NFS/SUNRPC: Remove other deadlock-avoidance mechanisms in nfs_release_page()
Now that nfs_release_page() doesn't block indefinitely, other deadlock avoidance mechanisms aren't needed. - it doesn't hurt for kswapd to block occasionally. If it doesn't want to block it would clear __GFP_WAIT. The current_is_kswapd() was only added to avoid deadlocks and we have a new approach for that. - memory allocation in the SUNRPC layer can very rarely try to ->releasepage() a page it is trying to handle. The deadlock is removed as nfs_release_page() doesn't block indefinitely. So we don't need to set PF_FSTRANS for sunrpc network operations any more. Signed-off-by: NeilBrown <neilb@suse.de> Acked-by: Jeff Layton <jlayton@primarydata.com> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
This commit is contained in:
Родитель
353db79662
Коммит
1aff525629
|
@ -476,20 +476,18 @@ static int nfs_release_page(struct page *page, gfp_t gfp)
|
||||||
dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page);
|
dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page);
|
||||||
|
|
||||||
/* Always try to initiate a 'commit' if relevant, but only
|
/* Always try to initiate a 'commit' if relevant, but only
|
||||||
* wait for it if __GFP_WAIT is set and the calling process is
|
* wait for it if __GFP_WAIT is set. Even then, only wait 1
|
||||||
* allowed to block. Even then, only wait 1 second and only
|
* second and only if the 'bdi' is not congested.
|
||||||
* if the 'bdi' is not congested.
|
|
||||||
* Waiting indefinitely can cause deadlocks when the NFS
|
* Waiting indefinitely can cause deadlocks when the NFS
|
||||||
* server is on this machine, and there is no particular need
|
* server is on this machine, when a new TCP connection is
|
||||||
* to wait extensively here. A short wait has the benefit
|
* needed and in other rare cases. There is no particular
|
||||||
* that someone else can worry about the freezer.
|
* need to wait extensively here. A short wait has the
|
||||||
|
* benefit that someone else can worry about the freezer.
|
||||||
*/
|
*/
|
||||||
if (mapping) {
|
if (mapping) {
|
||||||
struct nfs_server *nfss = NFS_SERVER(mapping->host);
|
struct nfs_server *nfss = NFS_SERVER(mapping->host);
|
||||||
nfs_commit_inode(mapping->host, 0);
|
nfs_commit_inode(mapping->host, 0);
|
||||||
if ((gfp & __GFP_WAIT) &&
|
if ((gfp & __GFP_WAIT) &&
|
||||||
!current_is_kswapd() &&
|
|
||||||
!(current->flags & PF_FSTRANS) &&
|
|
||||||
!bdi_write_congested(&nfss->backing_dev_info)) {
|
!bdi_write_congested(&nfss->backing_dev_info)) {
|
||||||
wait_on_page_bit_killable_timeout(page, PG_private,
|
wait_on_page_bit_killable_timeout(page, PG_private,
|
||||||
HZ);
|
HZ);
|
||||||
|
|
|
@ -821,9 +821,7 @@ void rpc_execute(struct rpc_task *task)
|
||||||
|
|
||||||
static void rpc_async_schedule(struct work_struct *work)
|
static void rpc_async_schedule(struct work_struct *work)
|
||||||
{
|
{
|
||||||
current->flags |= PF_FSTRANS;
|
|
||||||
__rpc_execute(container_of(work, struct rpc_task, u.tk_work));
|
__rpc_execute(container_of(work, struct rpc_task, u.tk_work));
|
||||||
current->flags &= ~PF_FSTRANS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -205,7 +205,6 @@ xprt_rdma_connect_worker(struct work_struct *work)
|
||||||
struct rpc_xprt *xprt = &r_xprt->xprt;
|
struct rpc_xprt *xprt = &r_xprt->xprt;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
current->flags |= PF_FSTRANS;
|
|
||||||
xprt_clear_connected(xprt);
|
xprt_clear_connected(xprt);
|
||||||
|
|
||||||
dprintk("RPC: %s: %sconnect\n", __func__,
|
dprintk("RPC: %s: %sconnect\n", __func__,
|
||||||
|
@ -216,7 +215,6 @@ xprt_rdma_connect_worker(struct work_struct *work)
|
||||||
|
|
||||||
dprintk("RPC: %s: exit\n", __func__);
|
dprintk("RPC: %s: exit\n", __func__);
|
||||||
xprt_clear_connecting(xprt);
|
xprt_clear_connecting(xprt);
|
||||||
current->flags &= ~PF_FSTRANS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1954,8 +1954,6 @@ static int xs_local_setup_socket(struct sock_xprt *transport)
|
||||||
struct socket *sock;
|
struct socket *sock;
|
||||||
int status = -EIO;
|
int status = -EIO;
|
||||||
|
|
||||||
current->flags |= PF_FSTRANS;
|
|
||||||
|
|
||||||
clear_bit(XPRT_CONNECTION_ABORT, &xprt->state);
|
clear_bit(XPRT_CONNECTION_ABORT, &xprt->state);
|
||||||
status = __sock_create(xprt->xprt_net, AF_LOCAL,
|
status = __sock_create(xprt->xprt_net, AF_LOCAL,
|
||||||
SOCK_STREAM, 0, &sock, 1);
|
SOCK_STREAM, 0, &sock, 1);
|
||||||
|
@ -1995,7 +1993,6 @@ static int xs_local_setup_socket(struct sock_xprt *transport)
|
||||||
out:
|
out:
|
||||||
xprt_clear_connecting(xprt);
|
xprt_clear_connecting(xprt);
|
||||||
xprt_wake_pending_tasks(xprt, status);
|
xprt_wake_pending_tasks(xprt, status);
|
||||||
current->flags &= ~PF_FSTRANS;
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2098,8 +2095,6 @@ static void xs_udp_setup_socket(struct work_struct *work)
|
||||||
struct socket *sock = transport->sock;
|
struct socket *sock = transport->sock;
|
||||||
int status = -EIO;
|
int status = -EIO;
|
||||||
|
|
||||||
current->flags |= PF_FSTRANS;
|
|
||||||
|
|
||||||
/* Start by resetting any existing state */
|
/* Start by resetting any existing state */
|
||||||
xs_reset_transport(transport);
|
xs_reset_transport(transport);
|
||||||
sock = xs_create_sock(xprt, transport,
|
sock = xs_create_sock(xprt, transport,
|
||||||
|
@ -2119,7 +2114,6 @@ static void xs_udp_setup_socket(struct work_struct *work)
|
||||||
out:
|
out:
|
||||||
xprt_clear_connecting(xprt);
|
xprt_clear_connecting(xprt);
|
||||||
xprt_wake_pending_tasks(xprt, status);
|
xprt_wake_pending_tasks(xprt, status);
|
||||||
current->flags &= ~PF_FSTRANS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2256,8 +2250,6 @@ static void xs_tcp_setup_socket(struct work_struct *work)
|
||||||
struct rpc_xprt *xprt = &transport->xprt;
|
struct rpc_xprt *xprt = &transport->xprt;
|
||||||
int status = -EIO;
|
int status = -EIO;
|
||||||
|
|
||||||
current->flags |= PF_FSTRANS;
|
|
||||||
|
|
||||||
if (!sock) {
|
if (!sock) {
|
||||||
clear_bit(XPRT_CONNECTION_ABORT, &xprt->state);
|
clear_bit(XPRT_CONNECTION_ABORT, &xprt->state);
|
||||||
sock = xs_create_sock(xprt, transport,
|
sock = xs_create_sock(xprt, transport,
|
||||||
|
@ -2305,7 +2297,6 @@ static void xs_tcp_setup_socket(struct work_struct *work)
|
||||||
case -EINPROGRESS:
|
case -EINPROGRESS:
|
||||||
case -EALREADY:
|
case -EALREADY:
|
||||||
xprt_clear_connecting(xprt);
|
xprt_clear_connecting(xprt);
|
||||||
current->flags &= ~PF_FSTRANS;
|
|
||||||
return;
|
return;
|
||||||
case -EINVAL:
|
case -EINVAL:
|
||||||
/* Happens, for instance, if the user specified a link
|
/* Happens, for instance, if the user specified a link
|
||||||
|
@ -2323,7 +2314,6 @@ out_eagain:
|
||||||
out:
|
out:
|
||||||
xprt_clear_connecting(xprt);
|
xprt_clear_connecting(xprt);
|
||||||
xprt_wake_pending_tasks(xprt, status);
|
xprt_wake_pending_tasks(xprt, status);
|
||||||
current->flags &= ~PF_FSTRANS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Загрузка…
Ссылка в новой задаче