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/xprtsock.c | |
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/xprtsock.c')
-rw-r--r-- | net/sunrpc/xprtsock.c | 10 |
1 files changed, 10 insertions, 0 deletions
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 | /** |