diff options
Diffstat (limited to 'net')
| -rw-r--r-- | net/atm/pppoatm.c | 21 |
1 files changed, 19 insertions, 2 deletions
diff --git a/net/atm/pppoatm.c b/net/atm/pppoatm.c index 9fcda8c85e9a..8c93267ce969 100644 --- a/net/atm/pppoatm.c +++ b/net/atm/pppoatm.c | |||
| @@ -113,7 +113,17 @@ static void pppoatm_release_cb(struct atm_vcc *atmvcc) | |||
| 113 | { | 113 | { |
| 114 | struct pppoatm_vcc *pvcc = atmvcc_to_pvcc(atmvcc); | 114 | struct pppoatm_vcc *pvcc = atmvcc_to_pvcc(atmvcc); |
| 115 | 115 | ||
| 116 | tasklet_schedule(&pvcc->wakeup_tasklet); | 116 | /* |
| 117 | * As in pppoatm_pop(), it's safe to clear the BLOCKED bit here because | ||
| 118 | * the wakeup *can't* race with pppoatm_send(). They both hold the PPP | ||
| 119 | * channel's ->downl lock. And the potential race with *setting* it, | ||
| 120 | * which leads to the double-check dance in pppoatm_may_send(), doesn't | ||
| 121 | * exist here. In the sock_owned_by_user() case in pppoatm_send(), we | ||
| 122 | * set the BLOCKED bit while the socket is still locked. We know that | ||
| 123 | * ->release_cb() can't be called until that's done. | ||
| 124 | */ | ||
| 125 | if (test_and_clear_bit(BLOCKED, &pvcc->blocked)) | ||
| 126 | tasklet_schedule(&pvcc->wakeup_tasklet); | ||
| 117 | if (pvcc->old_release_cb) | 127 | if (pvcc->old_release_cb) |
| 118 | pvcc->old_release_cb(atmvcc); | 128 | pvcc->old_release_cb(atmvcc); |
| 119 | } | 129 | } |
| @@ -292,8 +302,15 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb) | |||
| 292 | 302 | ||
| 293 | vcc = ATM_SKB(skb)->vcc; | 303 | vcc = ATM_SKB(skb)->vcc; |
| 294 | bh_lock_sock(sk_atm(vcc)); | 304 | bh_lock_sock(sk_atm(vcc)); |
| 295 | if (sock_owned_by_user(sk_atm(vcc))) | 305 | if (sock_owned_by_user(sk_atm(vcc))) { |
| 306 | /* | ||
| 307 | * Needs to happen (and be flushed, hence test_and_) before we unlock | ||
| 308 | * the socket. It needs to be seen by the time our ->release_cb gets | ||
| 309 | * called. | ||
| 310 | */ | ||
| 311 | test_and_set_bit(BLOCKED, &pvcc->blocked); | ||
| 296 | goto nospace; | 312 | goto nospace; |
| 313 | } | ||
| 297 | if (test_bit(ATM_VF_RELEASED, &vcc->flags) || | 314 | if (test_bit(ATM_VF_RELEASED, &vcc->flags) || |
| 298 | test_bit(ATM_VF_CLOSE, &vcc->flags) || | 315 | test_bit(ATM_VF_CLOSE, &vcc->flags) || |
| 299 | !test_bit(ATM_VF_READY, &vcc->flags)) { | 316 | !test_bit(ATM_VF_READY, &vcc->flags)) { |
