diff options
| author | WANG Cong <xiyou.wangcong@gmail.com> | 2016-11-17 18:55:26 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2016-11-18 13:58:39 -0500 |
| commit | 06a77b07e3b44aea2b3c0e64de420ea2cfdcbaa9 (patch) | |
| tree | 35be97e54af45ef40e4b8a1aea158c8c0ebd352b /net/unix | |
| parent | 0e2d1af399a3674351a5d0b8da5ba5764e0973a4 (diff) | |
af_unix: conditionally use freezable blocking calls in read
Commit 2b15af6f95 ("af_unix: use freezable blocking calls in read")
converts schedule_timeout() to its freezable version, it was probably
correct at that time, but later, commit 2b514574f7e8
("net: af_unix: implement splice for stream af_unix sockets") breaks
the strong requirement for a freezable sleep, according to
commit 0f9548ca1091:
We shouldn't try_to_freeze if locks are held. Holding a lock can cause a
deadlock if the lock is later acquired in the suspend or hibernate path
(e.g. by dpm). Holding a lock can also cause a deadlock in the case of
cgroup_freezer if a lock is held inside a frozen cgroup that is later
acquired by a process outside that group.
The pipe_lock is still held at that point.
So use freezable version only for the recvmsg call path, avoid impact for
Android.
Fixes: 2b514574f7e8 ("net: af_unix: implement splice for stream af_unix sockets")
Reported-by: Dmitry Vyukov <dvyukov@google.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Colin Cross <ccross@android.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Cc: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/unix')
| -rw-r--r-- | net/unix/af_unix.c | 17 |
1 files changed, 11 insertions, 6 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 5d1c14a2f268..2358f2690ec5 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c | |||
| @@ -2199,7 +2199,8 @@ out: | |||
| 2199 | * Sleep until more data has arrived. But check for races.. | 2199 | * Sleep until more data has arrived. But check for races.. |
| 2200 | */ | 2200 | */ |
| 2201 | static long unix_stream_data_wait(struct sock *sk, long timeo, | 2201 | static long unix_stream_data_wait(struct sock *sk, long timeo, |
| 2202 | struct sk_buff *last, unsigned int last_len) | 2202 | struct sk_buff *last, unsigned int last_len, |
| 2203 | bool freezable) | ||
| 2203 | { | 2204 | { |
| 2204 | struct sk_buff *tail; | 2205 | struct sk_buff *tail; |
| 2205 | DEFINE_WAIT(wait); | 2206 | DEFINE_WAIT(wait); |
| @@ -2220,7 +2221,10 @@ static long unix_stream_data_wait(struct sock *sk, long timeo, | |||
| 2220 | 2221 | ||
| 2221 | sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk); | 2222 | sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk); |
| 2222 | unix_state_unlock(sk); | 2223 | unix_state_unlock(sk); |
| 2223 | timeo = freezable_schedule_timeout(timeo); | 2224 | if (freezable) |
| 2225 | timeo = freezable_schedule_timeout(timeo); | ||
| 2226 | else | ||
| 2227 | timeo = schedule_timeout(timeo); | ||
| 2224 | unix_state_lock(sk); | 2228 | unix_state_lock(sk); |
| 2225 | 2229 | ||
| 2226 | if (sock_flag(sk, SOCK_DEAD)) | 2230 | if (sock_flag(sk, SOCK_DEAD)) |
| @@ -2250,7 +2254,8 @@ struct unix_stream_read_state { | |||
| 2250 | unsigned int splice_flags; | 2254 | unsigned int splice_flags; |
| 2251 | }; | 2255 | }; |
| 2252 | 2256 | ||
| 2253 | static int unix_stream_read_generic(struct unix_stream_read_state *state) | 2257 | static int unix_stream_read_generic(struct unix_stream_read_state *state, |
| 2258 | bool freezable) | ||
| 2254 | { | 2259 | { |
| 2255 | struct scm_cookie scm; | 2260 | struct scm_cookie scm; |
| 2256 | struct socket *sock = state->socket; | 2261 | struct socket *sock = state->socket; |
| @@ -2330,7 +2335,7 @@ again: | |||
| 2330 | mutex_unlock(&u->iolock); | 2335 | mutex_unlock(&u->iolock); |
| 2331 | 2336 | ||
| 2332 | timeo = unix_stream_data_wait(sk, timeo, last, | 2337 | timeo = unix_stream_data_wait(sk, timeo, last, |
| 2333 | last_len); | 2338 | last_len, freezable); |
| 2334 | 2339 | ||
| 2335 | if (signal_pending(current)) { | 2340 | if (signal_pending(current)) { |
| 2336 | err = sock_intr_errno(timeo); | 2341 | err = sock_intr_errno(timeo); |
| @@ -2472,7 +2477,7 @@ static int unix_stream_recvmsg(struct socket *sock, struct msghdr *msg, | |||
| 2472 | .flags = flags | 2477 | .flags = flags |
| 2473 | }; | 2478 | }; |
| 2474 | 2479 | ||
| 2475 | return unix_stream_read_generic(&state); | 2480 | return unix_stream_read_generic(&state, true); |
| 2476 | } | 2481 | } |
| 2477 | 2482 | ||
| 2478 | static int unix_stream_splice_actor(struct sk_buff *skb, | 2483 | static int unix_stream_splice_actor(struct sk_buff *skb, |
| @@ -2503,7 +2508,7 @@ static ssize_t unix_stream_splice_read(struct socket *sock, loff_t *ppos, | |||
| 2503 | flags & SPLICE_F_NONBLOCK) | 2508 | flags & SPLICE_F_NONBLOCK) |
| 2504 | state.flags = MSG_DONTWAIT; | 2509 | state.flags = MSG_DONTWAIT; |
| 2505 | 2510 | ||
| 2506 | return unix_stream_read_generic(&state); | 2511 | return unix_stream_read_generic(&state, false); |
| 2507 | } | 2512 | } |
| 2508 | 2513 | ||
| 2509 | static int unix_shutdown(struct socket *sock, int mode) | 2514 | static int unix_shutdown(struct socket *sock, int mode) |
