]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
pppoatm: optimise PPP channel wakeups after sock_owned_by_user()
authorDavid Woodhouse <David.Woodhouse@intel.com>
Wed, 28 Nov 2012 10:15:05 +0000 (10:15 +0000)
committerDavid Woodhouse <David.Woodhouse@intel.com>
Sun, 2 Dec 2012 00:05:20 +0000 (00:05 +0000)
We don't need to schedule the wakeup tasklet on *every* unlock; only if we
actually blocked the channel in the first place.

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Acked-by: Krzysztof Mazur <krzysiek@podlesie.net>
net/atm/pppoatm.c

index 9fcda8c85e9a1342e310fcfb6e67cd7919413311..8c93267ce96910a48f9eb9e5bb8e295470656edf 100644 (file)
@@ -113,7 +113,17 @@ static void pppoatm_release_cb(struct atm_vcc *atmvcc)
 {
        struct pppoatm_vcc *pvcc = atmvcc_to_pvcc(atmvcc);
 
-       tasklet_schedule(&pvcc->wakeup_tasklet);
+       /*
+        * As in pppoatm_pop(), it's safe to clear the BLOCKED bit here because
+        * the wakeup *can't* race with pppoatm_send(). They both hold the PPP
+        * channel's ->downl lock. And the potential race with *setting* it,
+        * which leads to the double-check dance in pppoatm_may_send(), doesn't
+        * exist here. In the sock_owned_by_user() case in pppoatm_send(), we
+        * set the BLOCKED bit while the socket is still locked. We know that
+        * ->release_cb() can't be called until that's done.
+        */
+       if (test_and_clear_bit(BLOCKED, &pvcc->blocked))
+               tasklet_schedule(&pvcc->wakeup_tasklet);
        if (pvcc->old_release_cb)
                pvcc->old_release_cb(atmvcc);
 }
@@ -292,8 +302,15 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
 
        vcc = ATM_SKB(skb)->vcc;
        bh_lock_sock(sk_atm(vcc));
-       if (sock_owned_by_user(sk_atm(vcc)))
+       if (sock_owned_by_user(sk_atm(vcc))) {
+               /*
+                * Needs to happen (and be flushed, hence test_and_) before we unlock
+                * the socket. It needs to be seen by the time our ->release_cb gets
+                * called.
+                */
+               test_and_set_bit(BLOCKED, &pvcc->blocked);
                goto nospace;
+       }
        if (test_bit(ATM_VF_RELEASED, &vcc->flags) ||
            test_bit(ATM_VF_CLOSE, &vcc->flags) ||
            !test_bit(ATM_VF_READY, &vcc->flags)) {