aboutsummaryrefslogtreecommitdiffstats
path: root/net/unix
diff options
context:
space:
mode:
Diffstat (limited to 'net/unix')
-rw-r--r--net/unix/af_unix.c41
1 files changed, 33 insertions, 8 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index ef31b40ad550..955ec152cb71 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -326,9 +326,10 @@ found:
326 return s; 326 return s;
327} 327}
328 328
329static inline int unix_writable(struct sock *sk) 329static int unix_writable(const struct sock *sk)
330{ 330{
331 return (atomic_read(&sk->sk_wmem_alloc) << 2) <= sk->sk_sndbuf; 331 return sk->sk_state != TCP_LISTEN &&
332 (atomic_read(&sk->sk_wmem_alloc) << 2) <= sk->sk_sndbuf;
332} 333}
333 334
334static void unix_write_space(struct sock *sk) 335static void unix_write_space(struct sock *sk)
@@ -440,6 +441,7 @@ static void unix_release_sock(struct sock *sk, int embrion)
440 if (state == TCP_LISTEN) 441 if (state == TCP_LISTEN)
441 unix_release_sock(skb->sk, 1); 442 unix_release_sock(skb->sk, 1);
442 /* passed fds are erased in the kfree_skb hook */ 443 /* passed fds are erased in the kfree_skb hook */
444 UNIXCB(skb).consumed = skb->len;
443 kfree_skb(skb); 445 kfree_skb(skb);
444 } 446 }
445 447
@@ -1798,6 +1800,7 @@ alloc_skb:
1798 * this - does no harm 1800 * this - does no harm
1799 */ 1801 */
1800 consume_skb(newskb); 1802 consume_skb(newskb);
1803 newskb = NULL;
1801 } 1804 }
1802 1805
1803 if (skb_append_pagefrags(skb, page, offset, size)) { 1806 if (skb_append_pagefrags(skb, page, offset, size)) {
@@ -1810,8 +1813,11 @@ alloc_skb:
1810 skb->truesize += size; 1813 skb->truesize += size;
1811 atomic_add(size, &sk->sk_wmem_alloc); 1814 atomic_add(size, &sk->sk_wmem_alloc);
1812 1815
1813 if (newskb) 1816 if (newskb) {
1817 spin_lock(&other->sk_receive_queue.lock);
1814 __skb_queue_tail(&other->sk_receive_queue, newskb); 1818 __skb_queue_tail(&other->sk_receive_queue, newskb);
1819 spin_unlock(&other->sk_receive_queue.lock);
1820 }
1815 1821
1816 unix_state_unlock(other); 1822 unix_state_unlock(other);
1817 mutex_unlock(&unix_sk(other)->readlock); 1823 mutex_unlock(&unix_sk(other)->readlock);
@@ -2064,8 +2070,14 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state)
2064 goto out; 2070 goto out;
2065 } 2071 }
2066 2072
2073 if (flags & MSG_PEEK)
2074 skip = sk_peek_offset(sk, flags);
2075 else
2076 skip = 0;
2077
2067 do { 2078 do {
2068 int chunk; 2079 int chunk;
2080 bool drop_skb;
2069 struct sk_buff *skb, *last; 2081 struct sk_buff *skb, *last;
2070 2082
2071 unix_state_lock(sk); 2083 unix_state_lock(sk);
@@ -2112,7 +2124,6 @@ unlock:
2112 break; 2124 break;
2113 } 2125 }
2114 2126
2115 skip = sk_peek_offset(sk, flags);
2116 while (skip >= unix_skb_len(skb)) { 2127 while (skip >= unix_skb_len(skb)) {
2117 skip -= unix_skb_len(skb); 2128 skip -= unix_skb_len(skb);
2118 last = skb; 2129 last = skb;
@@ -2147,7 +2158,11 @@ unlock:
2147 } 2158 }
2148 2159
2149 chunk = min_t(unsigned int, unix_skb_len(skb) - skip, size); 2160 chunk = min_t(unsigned int, unix_skb_len(skb) - skip, size);
2161 skb_get(skb);
2150 chunk = state->recv_actor(skb, skip, chunk, state); 2162 chunk = state->recv_actor(skb, skip, chunk, state);
2163 drop_skb = !unix_skb_len(skb);
2164 /* skb is only safe to use if !drop_skb */
2165 consume_skb(skb);
2151 if (chunk < 0) { 2166 if (chunk < 0) {
2152 if (copied == 0) 2167 if (copied == 0)
2153 copied = -EFAULT; 2168 copied = -EFAULT;
@@ -2156,6 +2171,18 @@ unlock:
2156 copied += chunk; 2171 copied += chunk;
2157 size -= chunk; 2172 size -= chunk;
2158 2173
2174 if (drop_skb) {
2175 /* the skb was touched by a concurrent reader;
2176 * we should not expect anything from this skb
2177 * anymore and assume it invalid - we can be
2178 * sure it was dropped from the socket queue
2179 *
2180 * let's report a short read
2181 */
2182 err = 0;
2183 break;
2184 }
2185
2159 /* Mark read part of skb as used */ 2186 /* Mark read part of skb as used */
2160 if (!(flags & MSG_PEEK)) { 2187 if (!(flags & MSG_PEEK)) {
2161 UNIXCB(skb).consumed += chunk; 2188 UNIXCB(skb).consumed += chunk;
@@ -2179,14 +2206,12 @@ unlock:
2179 if (UNIXCB(skb).fp) 2206 if (UNIXCB(skb).fp)
2180 scm.fp = scm_fp_dup(UNIXCB(skb).fp); 2207 scm.fp = scm_fp_dup(UNIXCB(skb).fp);
2181 2208
2182 if (skip) { 2209 sk_peek_offset_fwd(sk, chunk);
2183 sk_peek_offset_fwd(sk, chunk);
2184 skip -= chunk;
2185 }
2186 2210
2187 if (UNIXCB(skb).fp) 2211 if (UNIXCB(skb).fp)
2188 break; 2212 break;
2189 2213
2214 skip = 0;
2190 last = skb; 2215 last = skb;
2191 last_len = skb->len; 2216 last_len = skb->len;
2192 unix_state_lock(sk); 2217 unix_state_lock(sk);