diff options
author | Bryan Schumaker <bjschuma@netapp.com> | 2012-11-12 16:55:38 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-11-20 23:34:54 -0500 |
commit | 6bdb5f213c4344324f600dde885f25768fbd14db (patch) | |
tree | 6823ca803d7b6b26c81118eb91b0e4e825c9a78f /fs/nfs | |
parent | f994c43d19a9116727d4c228d3f13db595bff562 (diff) |
NFS: Add sequence_priviliged_ops for nfs4_proc_sequence()
If I mount an NFS v4.1 server to a single client multiple times and then
run xfstests over each mountpoint I usually get the client into a state
where recovery deadlocks. The server informs the client of a
cb_path_down sequence error, the client then does a
bind_connection_to_session and checks the status of the lease.
I found that bind_connection_to_session sets the NFS4_SESSION_DRAINING
flag on the client, but this flag is never unset before
nfs4_check_lease() reaches nfs4_proc_sequence(). This causes the client
to deadlock, halting all NFS activity to the server. nfs4_proc_sequence()
is only called by the state manager, so I can change it to run in privileged
mode to bypass the NFS4_SESSION_DRAINING check and avoid the deadlock.
Signed-off-by: Bryan Schumaker <bjschuma@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Cc: stable@vger.kernel.org
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/nfs4proc.c | 21 |
1 files changed, 17 insertions, 4 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 6300cdd81101..a32d953b08de 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -6136,13 +6136,26 @@ static void nfs41_sequence_prepare(struct rpc_task *task, void *data) | |||
6136 | rpc_call_start(task); | 6136 | rpc_call_start(task); |
6137 | } | 6137 | } |
6138 | 6138 | ||
6139 | static void nfs41_sequence_prepare_privileged(struct rpc_task *task, void *data) | ||
6140 | { | ||
6141 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
6142 | nfs41_sequence_prepare(task, data); | ||
6143 | } | ||
6144 | |||
6139 | static const struct rpc_call_ops nfs41_sequence_ops = { | 6145 | static const struct rpc_call_ops nfs41_sequence_ops = { |
6140 | .rpc_call_done = nfs41_sequence_call_done, | 6146 | .rpc_call_done = nfs41_sequence_call_done, |
6141 | .rpc_call_prepare = nfs41_sequence_prepare, | 6147 | .rpc_call_prepare = nfs41_sequence_prepare, |
6142 | .rpc_release = nfs41_sequence_release, | 6148 | .rpc_release = nfs41_sequence_release, |
6143 | }; | 6149 | }; |
6144 | 6150 | ||
6145 | static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) | 6151 | static const struct rpc_call_ops nfs41_sequence_privileged_ops = { |
6152 | .rpc_call_done = nfs41_sequence_call_done, | ||
6153 | .rpc_call_prepare = nfs41_sequence_prepare_privileged, | ||
6154 | .rpc_release = nfs41_sequence_release, | ||
6155 | }; | ||
6156 | |||
6157 | static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred, | ||
6158 | const struct rpc_call_ops *seq_ops) | ||
6146 | { | 6159 | { |
6147 | struct nfs4_sequence_data *calldata; | 6160 | struct nfs4_sequence_data *calldata; |
6148 | struct rpc_message msg = { | 6161 | struct rpc_message msg = { |
@@ -6152,7 +6165,7 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_ | |||
6152 | struct rpc_task_setup task_setup_data = { | 6165 | struct rpc_task_setup task_setup_data = { |
6153 | .rpc_client = clp->cl_rpcclient, | 6166 | .rpc_client = clp->cl_rpcclient, |
6154 | .rpc_message = &msg, | 6167 | .rpc_message = &msg, |
6155 | .callback_ops = &nfs41_sequence_ops, | 6168 | .callback_ops = seq_ops, |
6156 | .flags = RPC_TASK_ASYNC | RPC_TASK_SOFT, | 6169 | .flags = RPC_TASK_ASYNC | RPC_TASK_SOFT, |
6157 | }; | 6170 | }; |
6158 | 6171 | ||
@@ -6179,7 +6192,7 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp, struct rpc_cred *cr | |||
6179 | 6192 | ||
6180 | if ((renew_flags & NFS4_RENEW_TIMEOUT) == 0) | 6193 | if ((renew_flags & NFS4_RENEW_TIMEOUT) == 0) |
6181 | return 0; | 6194 | return 0; |
6182 | task = _nfs41_proc_sequence(clp, cred); | 6195 | task = _nfs41_proc_sequence(clp, cred, &nfs41_sequence_ops); |
6183 | if (IS_ERR(task)) | 6196 | if (IS_ERR(task)) |
6184 | ret = PTR_ERR(task); | 6197 | ret = PTR_ERR(task); |
6185 | else | 6198 | else |
@@ -6193,7 +6206,7 @@ static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) | |||
6193 | struct rpc_task *task; | 6206 | struct rpc_task *task; |
6194 | int ret; | 6207 | int ret; |
6195 | 6208 | ||
6196 | task = _nfs41_proc_sequence(clp, cred); | 6209 | task = _nfs41_proc_sequence(clp, cred, &nfs41_sequence_privileged_ops); |
6197 | if (IS_ERR(task)) { | 6210 | if (IS_ERR(task)) { |
6198 | ret = PTR_ERR(task); | 6211 | ret = PTR_ERR(task); |
6199 | goto out; | 6212 | goto out; |