diff options
author | Trond Myklebust <trond.myklebust@hammerspace.com> | 2018-06-15 15:58:45 -0400 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@hammerspace.com> | 2018-06-19 08:52:27 -0400 |
commit | 2dbf8dffbf35fd8f611083b9d9fe74fdccf912a3 (patch) | |
tree | 6117410c8eb22dd08dc0edb20fbea61a14a6bc16 | |
parent | d5681f59ee3d4a2e60b9234e94c163cbbf559d0a (diff) |
pNFS: Always free the session slot on error in nfs4_layoutget_handle_exception
Right now, we can call nfs_commit_inode() while holding the session slot,
which could lead to NFSv4 deadlocks. Ensure we only keep the slot if
the server returned a layout that we have to process.
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
-rw-r--r-- | fs/nfs/nfs4proc.c | 17 |
1 files changed, 10 insertions, 7 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index ed45090e4df6..2c8c2696415e 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -8650,6 +8650,8 @@ nfs4_layoutget_handle_exception(struct rpc_task *task, | |||
8650 | 8650 | ||
8651 | dprintk("--> %s tk_status => %d\n", __func__, -task->tk_status); | 8651 | dprintk("--> %s tk_status => %d\n", __func__, -task->tk_status); |
8652 | 8652 | ||
8653 | nfs4_sequence_free_slot(&lgp->res.seq_res); | ||
8654 | |||
8653 | switch (nfs4err) { | 8655 | switch (nfs4err) { |
8654 | case 0: | 8656 | case 0: |
8655 | goto out; | 8657 | goto out; |
@@ -8714,7 +8716,6 @@ nfs4_layoutget_handle_exception(struct rpc_task *task, | |||
8714 | goto out; | 8716 | goto out; |
8715 | } | 8717 | } |
8716 | 8718 | ||
8717 | nfs4_sequence_free_slot(&lgp->res.seq_res); | ||
8718 | err = nfs4_handle_exception(server, nfs4err, exception); | 8719 | err = nfs4_handle_exception(server, nfs4err, exception); |
8719 | if (!status) { | 8720 | if (!status) { |
8720 | if (exception->retry) | 8721 | if (exception->retry) |
@@ -8786,20 +8787,22 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout) | |||
8786 | if (IS_ERR(task)) | 8787 | if (IS_ERR(task)) |
8787 | return ERR_CAST(task); | 8788 | return ERR_CAST(task); |
8788 | status = rpc_wait_for_completion_task(task); | 8789 | status = rpc_wait_for_completion_task(task); |
8789 | if (status == 0) { | 8790 | if (status != 0) |
8791 | goto out; | ||
8792 | |||
8793 | /* if layoutp->len is 0, nfs4_layoutget_prepare called rpc_exit */ | ||
8794 | if (task->tk_status < 0 || lgp->res.layoutp->len == 0) { | ||
8790 | status = nfs4_layoutget_handle_exception(task, lgp, &exception); | 8795 | status = nfs4_layoutget_handle_exception(task, lgp, &exception); |
8791 | *timeout = exception.timeout; | 8796 | *timeout = exception.timeout; |
8792 | } | 8797 | } else |
8793 | 8798 | lseg = pnfs_layout_process(lgp); | |
8799 | out: | ||
8794 | trace_nfs4_layoutget(lgp->args.ctx, | 8800 | trace_nfs4_layoutget(lgp->args.ctx, |
8795 | &lgp->args.range, | 8801 | &lgp->args.range, |
8796 | &lgp->res.range, | 8802 | &lgp->res.range, |
8797 | &lgp->res.stateid, | 8803 | &lgp->res.stateid, |
8798 | status); | 8804 | status); |
8799 | 8805 | ||
8800 | /* if layoutp->len is 0, nfs4_layoutget_prepare called rpc_exit */ | ||
8801 | if (status == 0 && lgp->res.layoutp->len) | ||
8802 | lseg = pnfs_layout_process(lgp); | ||
8803 | rpc_put_task(task); | 8806 | rpc_put_task(task); |
8804 | dprintk("<-- %s status=%d\n", __func__, status); | 8807 | dprintk("<-- %s status=%d\n", __func__, status); |
8805 | if (status) | 8808 | if (status) |