[PATCH 4.7 097/186] pNFS: Fix LAYOUTGET handling of NFS4ERR_BAD_STATEID and NFS4ERR_EXPIRED

From: Greg Kroah-Hartman
Date: Thu Aug 18 2016 - 10:34:32 EST


4.7-stable review patch. If anyone has any objections, please let me know.

------------------

From: Trond Myklebust <trond.myklebust@xxxxxxxxxxxxxxx>

commit f7db0b283868411dc6bc8a223fd032b211d2d91f upstream.

We want to recover the open stateid if there is no layout stateid
and/or the stateid argument matches an open stateid.
Otherwise throw out the existing layout and recover from scratch, as
the layout stateid is bad.

Fixes: 183d9e7b112aa ("pnfs: rework LAYOUTGET retry handling")
Signed-off-by: Trond Myklebust <trond.myklebust@xxxxxxxxxxxxxxx>
Reviewed-by: Jeff Layton <jlayton@xxxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>

---
fs/nfs/nfs4proc.c | 32 ++++++++++++++------------------
1 file changed, 14 insertions(+), 18 deletions(-)

--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -7872,6 +7872,7 @@ nfs4_layoutget_handle_exception(struct r
struct pnfs_layout_hdr *lo;
int nfs4err = task->tk_status;
int err, status = 0;
+ LIST_HEAD(head);

dprintk("--> %s tk_status => %d\n", __func__, -task->tk_status);

@@ -7916,30 +7917,25 @@ nfs4_layoutget_handle_exception(struct r
case -NFS4ERR_BAD_STATEID:
exception->timeout = 0;
spin_lock(&inode->i_lock);
- if (nfs4_stateid_match(&lgp->args.stateid,
+ lo = NFS_I(inode)->layout;
+ /* If the open stateid was bad, then recover it. */
+ if (!lo || test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags) ||
+ nfs4_stateid_match_other(&lgp->args.stateid,
&lgp->args.ctx->state->stateid)) {
spin_unlock(&inode->i_lock);
- /* If the open stateid was bad, then recover it. */
exception->state = lgp->args.ctx->state;
break;
}
- lo = NFS_I(inode)->layout;
- if (lo && !test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags) &&
- nfs4_stateid_match_other(&lgp->args.stateid, &lo->plh_stateid)) {
- LIST_HEAD(head);

- /*
- * Mark the bad layout state as invalid, then retry
- * with the current stateid.
- */
- set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
- pnfs_mark_matching_lsegs_invalid(lo, &head, NULL, 0);
- spin_unlock(&inode->i_lock);
- pnfs_free_lseg_list(&head);
- status = -EAGAIN;
- goto out;
- } else
- spin_unlock(&inode->i_lock);
+ /*
+ * Mark the bad layout state as invalid, then retry
+ */
+ set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
+ pnfs_mark_matching_lsegs_invalid(lo, &head, NULL, 0);
+ spin_unlock(&inode->i_lock);
+ pnfs_free_lseg_list(&head);
+ status = -EAGAIN;
+ goto out;
}

err = nfs4_handle_exception(server, nfs4err, exception);