diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2016-07-14 15:14:02 -0400 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2016-07-19 16:23:23 -0400 |
commit | f7db0b283868411dc6bc8a223fd032b211d2d91f (patch) | |
tree | cf7a2f7e1aee50843669d5c8548c1879b0725430 | |
parent | 66b53f325876703b7ab815c482cd104609f8772c (diff) |
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: 183d9e7b112aa ("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>
-rw-r--r-- | fs/nfs/nfs4proc.c | 34 |
1 files changed, 15 insertions, 19 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index ee8efe0a5202..a1a3b4c9a563 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -7886,6 +7886,7 @@ nfs4_layoutget_handle_exception(struct rpc_task *task, | |||
7886 | struct pnfs_layout_hdr *lo; | 7886 | struct pnfs_layout_hdr *lo; |
7887 | int nfs4err = task->tk_status; | 7887 | int nfs4err = task->tk_status; |
7888 | int err, status = 0; | 7888 | int err, status = 0; |
7889 | LIST_HEAD(head); | ||
7889 | 7890 | ||
7890 | dprintk("--> %s tk_status => %d\n", __func__, -task->tk_status); | 7891 | dprintk("--> %s tk_status => %d\n", __func__, -task->tk_status); |
7891 | 7892 | ||
@@ -7930,30 +7931,25 @@ nfs4_layoutget_handle_exception(struct rpc_task *task, | |||
7930 | case -NFS4ERR_BAD_STATEID: | 7931 | case -NFS4ERR_BAD_STATEID: |
7931 | exception->timeout = 0; | 7932 | exception->timeout = 0; |
7932 | spin_lock(&inode->i_lock); | 7933 | spin_lock(&inode->i_lock); |
7933 | if (nfs4_stateid_match(&lgp->args.stateid, | 7934 | lo = NFS_I(inode)->layout; |
7935 | /* If the open stateid was bad, then recover it. */ | ||
7936 | if (!lo || test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags) || | ||
7937 | nfs4_stateid_match_other(&lgp->args.stateid, | ||
7934 | &lgp->args.ctx->state->stateid)) { | 7938 | &lgp->args.ctx->state->stateid)) { |
7935 | spin_unlock(&inode->i_lock); | 7939 | spin_unlock(&inode->i_lock); |
7936 | /* If the open stateid was bad, then recover it. */ | ||
7937 | exception->state = lgp->args.ctx->state; | 7940 | exception->state = lgp->args.ctx->state; |
7938 | break; | 7941 | break; |
7939 | } | 7942 | } |
7940 | lo = NFS_I(inode)->layout; | 7943 | |
7941 | if (lo && !test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags) && | 7944 | /* |
7942 | nfs4_stateid_match_other(&lgp->args.stateid, &lo->plh_stateid)) { | 7945 | * Mark the bad layout state as invalid, then retry |
7943 | LIST_HEAD(head); | 7946 | */ |
7944 | 7947 | set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags); | |
7945 | /* | 7948 | pnfs_mark_matching_lsegs_invalid(lo, &head, NULL, 0); |
7946 | * Mark the bad layout state as invalid, then retry | 7949 | spin_unlock(&inode->i_lock); |
7947 | * with the current stateid. | 7950 | pnfs_free_lseg_list(&head); |
7948 | */ | 7951 | status = -EAGAIN; |
7949 | set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags); | 7952 | goto out; |
7950 | pnfs_mark_matching_lsegs_invalid(lo, &head, NULL, 0); | ||
7951 | spin_unlock(&inode->i_lock); | ||
7952 | pnfs_free_lseg_list(&head); | ||
7953 | status = -EAGAIN; | ||
7954 | goto out; | ||
7955 | } else | ||
7956 | spin_unlock(&inode->i_lock); | ||
7957 | } | 7953 | } |
7958 | 7954 | ||
7959 | err = nfs4_handle_exception(server, nfs4err, exception); | 7955 | err = nfs4_handle_exception(server, nfs4err, exception); |