NFSv4: always set NFS_LOCK_LOST when a lock is lost.
authorNeilBrown <neilb@suse.com>
Tue, 12 Dec 2017 22:57:09 +0000 (09:57 +1100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 26 Apr 2018 09:02:03 +0000 (11:02 +0200)
[ 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
fs/nfs/nfs4state.c

index 2241d52710f7b070cb0a083eace6de481e328d0f..ae8f43d270d6dc6a0ce76bce9f51ebb3208d7e46 100644 (file)
@@ -1885,7 +1885,7 @@ static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *sta
        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:
@@ -1932,7 +1932,11 @@ static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct
                        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;
@@ -1968,7 +1972,7 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx,
                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)
@@ -6595,7 +6599,7 @@ int nfs4_lock_delegation_recall(struct file_lock *fl, struct nfs4_state *state,
        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 {
index 0378e2257ca75f392f20bebe59ca935951d7a813..45873ed92057b329fe0b05450d97a3626fde49ff 100644 (file)
@@ -1447,6 +1447,7 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_
        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;
@@ -1487,7 +1488,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);