summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2014-08-21 20:09:22 +0400
committerTrond Myklebust <trond.myklebust@primarydata.com>2014-09-10 23:47:01 +0400
commit47abadefad213bb7de9592d2e09a8bd282ddc3de (patch)
tree654dab2b331441f3a823a33ad1912578459f6cd9
parentdefb8460881cbf0a5890bc7a63b42c0cfbed721d (diff)
downloadlinux-47abadefad213bb7de9592d2e09a8bd282ddc3de.tar.xz
pnfs: avoid using stale stateids after layoutreturn
After we issued a layoutreturn operations the may free the layout stateid and will thus cause bad stateid error when the client uses it again. We currently try to avoid this case by chosing the open stateid if not lsegs are present for this inode. But various places can hold refererence on lsegs and thus cause the list not to be empty shortly after a layout return. Add an explicit flag to mark the current layout stateid invalid and force usage of the openstateid after we did a full file layoutreturn. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
-rw-r--r--fs/nfs/pnfs.c7
-rw-r--r--fs/nfs/pnfs.h1
2 files changed, 7 insertions, 1 deletions
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index ff7fabe33529..57b5728e0b8e 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -738,7 +738,8 @@ pnfs_choose_layoutget_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo,
status = -EAGAIN;
} else if (!nfs4_valid_open_stateid(open_state)) {
status = -EBADF;
- } else if (list_empty(&lo->plh_segs)) {
+ } else if (list_empty(&lo->plh_segs) ||
+ test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags)) {
int seq;
do {
@@ -860,6 +861,8 @@ _pnfs_return_layout(struct inode *ino)
dprintk("NFS: %s no layout segments to return\n", __func__);
goto out;
}
+
+ set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
lo->plh_block_lgets++;
spin_unlock(&ino->i_lock);
pnfs_free_lseg_list(&tmp_list);
@@ -1380,6 +1383,8 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
lo->plh_barrier = be32_to_cpu(res->stateid.seqid);
}
+ clear_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
+
pnfs_get_lseg(lseg);
pnfs_layout_insert_lseg(lo, lseg);
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h
index 79c63114ce77..1dd8a5e96c9f 100644
--- a/fs/nfs/pnfs.h
+++ b/fs/nfs/pnfs.h
@@ -65,6 +65,7 @@ enum {
NFS_LAYOUT_BULK_RECALL, /* bulk recall affecting layout */
NFS_LAYOUT_ROC, /* some lseg had roc bit set */
NFS_LAYOUT_RETURN, /* Return this layout ASAP */
+ NFS_LAYOUT_INVALID_STID, /* layout stateid id is invalid */
};
enum layoutdriver_policy_flags {