pNFS: Fix LAYOUTGET handling of NFS4ERR_BAD_STATEID and NFS4ERR_EXPIRED
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: 183d9e7b11
("pnfs: rework LAYOUTGET retry handling")
Cc: stable@vger.kernel.org # 4.7
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
This commit is contained in:
parent
66b53f3258
commit
f7db0b2838
@ -7886,6 +7886,7 @@ nfs4_layoutget_handle_exception(struct rpc_task *task,
|
|||||||
struct pnfs_layout_hdr *lo;
|
struct pnfs_layout_hdr *lo;
|
||||||
int nfs4err = task->tk_status;
|
int nfs4err = task->tk_status;
|
||||||
int err, status = 0;
|
int err, status = 0;
|
||||||
|
LIST_HEAD(head);
|
||||||
|
|
||||||
dprintk("--> %s tk_status => %d\n", __func__, -task->tk_status);
|
dprintk("--> %s tk_status => %d\n", __func__, -task->tk_status);
|
||||||
|
|
||||||
@ -7930,30 +7931,25 @@ nfs4_layoutget_handle_exception(struct rpc_task *task,
|
|||||||
case -NFS4ERR_BAD_STATEID:
|
case -NFS4ERR_BAD_STATEID:
|
||||||
exception->timeout = 0;
|
exception->timeout = 0;
|
||||||
spin_lock(&inode->i_lock);
|
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)) {
|
&lgp->args.ctx->state->stateid)) {
|
||||||
spin_unlock(&inode->i_lock);
|
spin_unlock(&inode->i_lock);
|
||||||
/* If the open stateid was bad, then recover it. */
|
|
||||||
exception->state = lgp->args.ctx->state;
|
exception->state = lgp->args.ctx->state;
|
||||||
break;
|
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
|
* Mark the bad layout state as invalid, then retry
|
||||||
* with the current stateid.
|
*/
|
||||||
*/
|
set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
|
||||||
set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
|
pnfs_mark_matching_lsegs_invalid(lo, &head, NULL, 0);
|
||||||
pnfs_mark_matching_lsegs_invalid(lo, &head, NULL, 0);
|
spin_unlock(&inode->i_lock);
|
||||||
spin_unlock(&inode->i_lock);
|
pnfs_free_lseg_list(&head);
|
||||||
pnfs_free_lseg_list(&head);
|
status = -EAGAIN;
|
||||||
status = -EAGAIN;
|
goto out;
|
||||||
goto out;
|
|
||||||
} else
|
|
||||||
spin_unlock(&inode->i_lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = nfs4_handle_exception(server, nfs4err, exception);
|
err = nfs4_handle_exception(server, nfs4err, exception);
|
||||||
|
Loading…
Reference in New Issue
Block a user