diff options
author | Jeff Layton <jlayton@redhat.com> | 2012-07-23 13:58:51 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-07-30 18:55:59 -0400 |
commit | 5cf02d09b50b1ee1c2d536c9cf64af5a7d433f56 (patch) | |
tree | 7851ae064cdde3cd1eb2c0ef068bfecf24f53571 /net/sunrpc | |
parent | 506026c3ec270e18402f0c9d33fee37482c23861 (diff) |
nfs: skip commit in releasepage if we're freeing memory for fs-related reasons
We've had some reports of a deadlock where rpciod ends up with a stack
trace like this:
PID: 2507 TASK: ffff88103691ab40 CPU: 14 COMMAND: "rpciod/14"
#0 [ffff8810343bf2f0] schedule at ffffffff814dabd9
#1 [ffff8810343bf3b8] nfs_wait_bit_killable at ffffffffa038fc04 [nfs]
#2 [ffff8810343bf3c8] __wait_on_bit at ffffffff814dbc2f
#3 [ffff8810343bf418] out_of_line_wait_on_bit at ffffffff814dbcd8
#4 [ffff8810343bf488] nfs_commit_inode at ffffffffa039e0c1 [nfs]
#5 [ffff8810343bf4f8] nfs_release_page at ffffffffa038bef6 [nfs]
#6 [ffff8810343bf528] try_to_release_page at ffffffff8110c670
#7 [ffff8810343bf538] shrink_page_list.clone.0 at ffffffff81126271
#8 [ffff8810343bf668] shrink_inactive_list at ffffffff81126638
#9 [ffff8810343bf818] shrink_zone at ffffffff8112788f
#10 [ffff8810343bf8c8] do_try_to_free_pages at ffffffff81127b1e
#11 [ffff8810343bf958] try_to_free_pages at ffffffff8112812f
#12 [ffff8810343bfa08] __alloc_pages_nodemask at ffffffff8111fdad
#13 [ffff8810343bfb28] kmem_getpages at ffffffff81159942
#14 [ffff8810343bfb58] fallback_alloc at ffffffff8115a55a
#15 [ffff8810343bfbd8] ____cache_alloc_node at ffffffff8115a2d9
#16 [ffff8810343bfc38] kmem_cache_alloc at ffffffff8115b09b
#17 [ffff8810343bfc78] sk_prot_alloc at ffffffff81411808
#18 [ffff8810343bfcb8] sk_alloc at ffffffff8141197c
#19 [ffff8810343bfce8] inet_create at ffffffff81483ba6
#20 [ffff8810343bfd38] __sock_create at ffffffff8140b4a7
#21 [ffff8810343bfd98] xs_create_sock at ffffffffa01f649b [sunrpc]
#22 [ffff8810343bfdd8] xs_tcp_setup_socket at ffffffffa01f6965 [sunrpc]
#23 [ffff8810343bfe38] worker_thread at ffffffff810887d0
#24 [ffff8810343bfee8] kthread at ffffffff8108dd96
#25 [ffff8810343bff48] kernel_thread at ffffffff8100c1ca
rpciod is trying to allocate memory for a new socket to talk to the
server. The VM ends up calling ->releasepage to get more memory, and it
tries to do a blocking commit. That commit can't succeed however without
a connected socket, so we deadlock.
Fix this by setting PF_FSTRANS on the workqueue task prior to doing the
socket allocation, and having nfs_release_page check for that flag when
deciding whether to do a commit call. Also, set PF_FSTRANS
unconditionally in rpc_async_schedule since that function can also do
allocations sometimes.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Cc: stable@vger.kernel.org
Diffstat (limited to 'net/sunrpc')
-rw-r--r-- | net/sunrpc/sched.c | 2 | ||||
-rw-r--r-- | net/sunrpc/xprtrdma/transport.c | 3 | ||||
-rw-r--r-- | net/sunrpc/xprtsock.c | 10 |
3 files changed, 14 insertions, 1 deletions
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index ada1e2c33aa4..1f19aa15f89b 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c | |||
@@ -791,7 +791,9 @@ void rpc_execute(struct rpc_task *task) | |||
791 | 791 | ||
792 | static void rpc_async_schedule(struct work_struct *work) | 792 | static void rpc_async_schedule(struct work_struct *work) |
793 | { | 793 | { |
794 | current->flags |= PF_FSTRANS; | ||
794 | __rpc_execute(container_of(work, struct rpc_task, u.tk_work)); | 795 | __rpc_execute(container_of(work, struct rpc_task, u.tk_work)); |
796 | current->flags &= ~PF_FSTRANS; | ||
795 | } | 797 | } |
796 | 798 | ||
797 | /** | 799 | /** |
diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c index b446e100286f..06cdbff79e4a 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c | |||
@@ -200,6 +200,7 @@ xprt_rdma_connect_worker(struct work_struct *work) | |||
200 | int rc = 0; | 200 | int rc = 0; |
201 | 201 | ||
202 | if (!xprt->shutdown) { | 202 | if (!xprt->shutdown) { |
203 | current->flags |= PF_FSTRANS; | ||
203 | xprt_clear_connected(xprt); | 204 | xprt_clear_connected(xprt); |
204 | 205 | ||
205 | dprintk("RPC: %s: %sconnect\n", __func__, | 206 | dprintk("RPC: %s: %sconnect\n", __func__, |
@@ -212,10 +213,10 @@ xprt_rdma_connect_worker(struct work_struct *work) | |||
212 | 213 | ||
213 | out: | 214 | out: |
214 | xprt_wake_pending_tasks(xprt, rc); | 215 | xprt_wake_pending_tasks(xprt, rc); |
215 | |||
216 | out_clear: | 216 | out_clear: |
217 | dprintk("RPC: %s: exit\n", __func__); | 217 | dprintk("RPC: %s: exit\n", __func__); |
218 | xprt_clear_connecting(xprt); | 218 | xprt_clear_connecting(xprt); |
219 | current->flags &= ~PF_FSTRANS; | ||
219 | } | 220 | } |
220 | 221 | ||
221 | /* | 222 | /* |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 890b03f8d877..b88c6bf657ba 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
@@ -1895,6 +1895,8 @@ static void xs_local_setup_socket(struct work_struct *work) | |||
1895 | if (xprt->shutdown) | 1895 | if (xprt->shutdown) |
1896 | goto out; | 1896 | goto out; |
1897 | 1897 | ||
1898 | current->flags |= PF_FSTRANS; | ||
1899 | |||
1898 | clear_bit(XPRT_CONNECTION_ABORT, &xprt->state); | 1900 | clear_bit(XPRT_CONNECTION_ABORT, &xprt->state); |
1899 | status = __sock_create(xprt->xprt_net, AF_LOCAL, | 1901 | status = __sock_create(xprt->xprt_net, AF_LOCAL, |
1900 | SOCK_STREAM, 0, &sock, 1); | 1902 | SOCK_STREAM, 0, &sock, 1); |
@@ -1928,6 +1930,7 @@ static void xs_local_setup_socket(struct work_struct *work) | |||
1928 | out: | 1930 | out: |
1929 | xprt_clear_connecting(xprt); | 1931 | xprt_clear_connecting(xprt); |
1930 | xprt_wake_pending_tasks(xprt, status); | 1932 | xprt_wake_pending_tasks(xprt, status); |
1933 | current->flags &= ~PF_FSTRANS; | ||
1931 | } | 1934 | } |
1932 | 1935 | ||
1933 | static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) | 1936 | static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) |
@@ -1970,6 +1973,8 @@ static void xs_udp_setup_socket(struct work_struct *work) | |||
1970 | if (xprt->shutdown) | 1973 | if (xprt->shutdown) |
1971 | goto out; | 1974 | goto out; |
1972 | 1975 | ||
1976 | current->flags |= PF_FSTRANS; | ||
1977 | |||
1973 | /* Start by resetting any existing state */ | 1978 | /* Start by resetting any existing state */ |
1974 | xs_reset_transport(transport); | 1979 | xs_reset_transport(transport); |
1975 | sock = xs_create_sock(xprt, transport, | 1980 | sock = xs_create_sock(xprt, transport, |
@@ -1988,6 +1993,7 @@ static void xs_udp_setup_socket(struct work_struct *work) | |||
1988 | out: | 1993 | out: |
1989 | xprt_clear_connecting(xprt); | 1994 | xprt_clear_connecting(xprt); |
1990 | xprt_wake_pending_tasks(xprt, status); | 1995 | xprt_wake_pending_tasks(xprt, status); |
1996 | current->flags &= ~PF_FSTRANS; | ||
1991 | } | 1997 | } |
1992 | 1998 | ||
1993 | /* | 1999 | /* |
@@ -2113,6 +2119,8 @@ static void xs_tcp_setup_socket(struct work_struct *work) | |||
2113 | if (xprt->shutdown) | 2119 | if (xprt->shutdown) |
2114 | goto out; | 2120 | goto out; |
2115 | 2121 | ||
2122 | current->flags |= PF_FSTRANS; | ||
2123 | |||
2116 | if (!sock) { | 2124 | if (!sock) { |
2117 | clear_bit(XPRT_CONNECTION_ABORT, &xprt->state); | 2125 | clear_bit(XPRT_CONNECTION_ABORT, &xprt->state); |
2118 | sock = xs_create_sock(xprt, transport, | 2126 | sock = xs_create_sock(xprt, transport, |
@@ -2162,6 +2170,7 @@ static void xs_tcp_setup_socket(struct work_struct *work) | |||
2162 | case -EINPROGRESS: | 2170 | case -EINPROGRESS: |
2163 | case -EALREADY: | 2171 | case -EALREADY: |
2164 | xprt_clear_connecting(xprt); | 2172 | xprt_clear_connecting(xprt); |
2173 | current->flags &= ~PF_FSTRANS; | ||
2165 | return; | 2174 | return; |
2166 | case -EINVAL: | 2175 | case -EINVAL: |
2167 | /* Happens, for instance, if the user specified a link | 2176 | /* Happens, for instance, if the user specified a link |
@@ -2174,6 +2183,7 @@ out_eagain: | |||
2174 | out: | 2183 | out: |
2175 | xprt_clear_connecting(xprt); | 2184 | xprt_clear_connecting(xprt); |
2176 | xprt_wake_pending_tasks(xprt, status); | 2185 | xprt_wake_pending_tasks(xprt, status); |
2186 | current->flags &= ~PF_FSTRANS; | ||
2177 | } | 2187 | } |
2178 | 2188 | ||
2179 | /** | 2189 | /** |