|
84 | 84 | /* Forward declarations for internal helper functions. */ |
85 | 85 | static int sctp_writeable(struct sock *sk); |
86 | 86 | static void sctp_wfree(struct sk_buff *skb); |
87 | | -static int sctp_wait_for_sndbuf(struct sctp_association *, long *timeo_p, |
88 | | - size_t msg_len); |
| 87 | +static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, |
| 88 | + size_t msg_len, struct sock **orig_sk); |
89 | 89 | static int sctp_wait_for_packet(struct sock *sk, int *err, long *timeo_p); |
90 | 90 | static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p); |
91 | 91 | static int sctp_wait_for_accept(struct sock *sk, long timeo); |
@@ -1970,7 +1970,8 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len) |
1970 | 1970 |
|
1971 | 1971 | timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); |
1972 | 1972 | if (!sctp_wspace(asoc)) { |
1973 | | - err = sctp_wait_for_sndbuf(asoc, &timeo, msg_len); |
| 1973 | + /* sk can be changed by peel off when waiting for buf. */ |
| 1974 | + err = sctp_wait_for_sndbuf(asoc, &timeo, msg_len, &sk); |
1974 | 1975 | if (err) { |
1975 | 1976 | if (err == -ESRCH) { |
1976 | 1977 | /* asoc is already dead. */ |
@@ -5021,12 +5022,6 @@ int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp) |
5021 | 5022 | if (!asoc) |
5022 | 5023 | return -EINVAL; |
5023 | 5024 |
|
5024 | | - /* If there is a thread waiting on more sndbuf space for |
5025 | | - * sending on this asoc, it cannot be peeled. |
5026 | | - */ |
5027 | | - if (waitqueue_active(&asoc->wait)) |
5028 | | - return -EBUSY; |
5029 | | - |
5030 | 5025 | /* An association cannot be branched off from an already peeled-off |
5031 | 5026 | * socket, nor is this supported for tcp style sockets. |
5032 | 5027 | */ |
@@ -7995,7 +7990,7 @@ void sctp_sock_rfree(struct sk_buff *skb) |
7995 | 7990 |
|
7996 | 7991 | /* Helper function to wait for space in the sndbuf. */ |
7997 | 7992 | static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, |
7998 | | - size_t msg_len) |
| 7993 | + size_t msg_len, struct sock **orig_sk) |
7999 | 7994 | { |
8000 | 7995 | struct sock *sk = asoc->base.sk; |
8001 | 7996 | int err = 0; |
@@ -8029,11 +8024,17 @@ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, |
8029 | 8024 | release_sock(sk); |
8030 | 8025 | current_timeo = schedule_timeout(current_timeo); |
8031 | 8026 | lock_sock(sk); |
| 8027 | + if (sk != asoc->base.sk) { |
| 8028 | + release_sock(sk); |
| 8029 | + sk = asoc->base.sk; |
| 8030 | + lock_sock(sk); |
| 8031 | + } |
8032 | 8032 |
|
8033 | 8033 | *timeo_p = current_timeo; |
8034 | 8034 | } |
8035 | 8035 |
|
8036 | 8036 | out: |
| 8037 | + *orig_sk = sk; |
8037 | 8038 | finish_wait(&asoc->wait, &wait); |
8038 | 8039 |
|
8039 | 8040 | /* Release the association's refcnt. */ |
|
0 commit comments