| From foo@baz Sun May 27 17:33:37 CEST 2018 |
| From: NeilBrown <neilb@suse.com> |
| Date: Wed, 13 Dec 2017 09:57:09 +1100 |
| Subject: NFSv4: always set NFS_LOCK_LOST when a lock is lost. |
| |
| From: NeilBrown <neilb@suse.com> |
| |
| [ Upstream commit dce2630c7da73b0634686bca557cc8945cc450c8 ] |
| |
| There are 2 comments in the NFSv4 code which suggest that |
| SIGLOST should possibly be sent to a process. In these |
| cases a lock has been lost. |
| The current practice is to set NFS_LOCK_LOST so that |
| read/write returns EIO when a lock is lost. |
| So change these comments to code when sets NFS_LOCK_LOST. |
| |
| One case is when lock recovery after apparent server restart |
| fails with NFS4ERR_DENIED, NFS4ERR_RECLAIM_BAD, or |
| NFS4ERRO_RECLAIM_CONFLICT. The other case is when a lock |
| attempt as part of lease recovery fails with NFS4ERR_DENIED. |
| |
| In an ideal world, these should not happen. However I have |
| a packet trace showing an NFSv4.1 session getting |
| NFS4ERR_BADSESSION after an extended network parition. The |
| NFSv4.1 client treats this like server reboot until/unless |
| it get NFS4ERR_NO_GRACE, in which case it switches over to |
| "nograce" recovery mode. In this network trace, the client |
| attempts to recover a lock and the server (incorrectly) |
| reports NFS4ERR_DENIED rather than NFS4ERR_NO_GRACE. This |
| leads to the ineffective comment and the client then |
| continues to write using the OPEN stateid. |
| |
| Signed-off-by: NeilBrown <neilb@suse.com> |
| Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com> |
| Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| fs/nfs/nfs4proc.c | 12 ++++++++---- |
| fs/nfs/nfs4state.c | 5 ++++- |
| 2 files changed, 12 insertions(+), 5 deletions(-) |
| |
| --- a/fs/nfs/nfs4proc.c |
| +++ b/fs/nfs/nfs4proc.c |
| @@ -1934,7 +1934,7 @@ static int nfs4_open_reclaim(struct nfs4 |
| return ret; |
| } |
| |
| -static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct nfs4_state *state, const nfs4_stateid *stateid, int err) |
| +static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct nfs4_state *state, const nfs4_stateid *stateid, struct file_lock *fl, int err) |
| { |
| switch (err) { |
| default: |
| @@ -1981,7 +1981,11 @@ static int nfs4_handle_delegation_recall |
| return -EAGAIN; |
| case -ENOMEM: |
| case -NFS4ERR_DENIED: |
| - /* kill_proc(fl->fl_pid, SIGLOST, 1); */ |
| + if (fl) { |
| + struct nfs4_lock_state *lsp = fl->fl_u.nfs4_fl.owner; |
| + if (lsp) |
| + set_bit(NFS_LOCK_LOST, &lsp->ls_flags); |
| + } |
| return 0; |
| } |
| return err; |
| @@ -2017,7 +2021,7 @@ int nfs4_open_delegation_recall(struct n |
| err = nfs4_open_recover_helper(opendata, FMODE_READ); |
| } |
| nfs4_opendata_put(opendata); |
| - return nfs4_handle_delegation_recall_error(server, state, stateid, err); |
| + return nfs4_handle_delegation_recall_error(server, state, stateid, NULL, err); |
| } |
| |
| static void nfs4_open_confirm_prepare(struct rpc_task *task, void *calldata) |
| @@ -6499,7 +6503,7 @@ int nfs4_lock_delegation_recall(struct f |
| if (err != 0) |
| return err; |
| err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW); |
| - return nfs4_handle_delegation_recall_error(server, state, stateid, err); |
| + return nfs4_handle_delegation_recall_error(server, state, stateid, fl, err); |
| } |
| |
| struct nfs_release_lockowner_data { |
| --- a/fs/nfs/nfs4state.c |
| +++ b/fs/nfs/nfs4state.c |
| @@ -1429,6 +1429,7 @@ static int nfs4_reclaim_locks(struct nfs |
| struct inode *inode = state->inode; |
| struct nfs_inode *nfsi = NFS_I(inode); |
| struct file_lock *fl; |
| + struct nfs4_lock_state *lsp; |
| int status = 0; |
| struct file_lock_context *flctx = inode->i_flctx; |
| struct list_head *list; |
| @@ -1469,7 +1470,9 @@ restart: |
| case -NFS4ERR_DENIED: |
| case -NFS4ERR_RECLAIM_BAD: |
| case -NFS4ERR_RECLAIM_CONFLICT: |
| - /* kill_proc(fl->fl_pid, SIGLOST, 1); */ |
| + lsp = fl->fl_u.nfs4_fl.owner; |
| + if (lsp) |
| + set_bit(NFS_LOCK_LOST, &lsp->ls_flags); |
| status = 0; |
| } |
| spin_lock(&flctx->flc_lock); |