From c49b5209f99abe082d3d4cd94f0ad924baea34ed Mon Sep 17 00:00:00 2001 From: Fred Isaman Date: Wed, 5 Oct 2016 09:37:12 -0400 Subject: [PATCH] pnfs: Add barrier to prevent lgopen using LAYOUTGET during recall Since the LAYOUTGET on OPEN can be sent without prior inode information, existing methods to prevent LAYOUTGET from being sent while processing CB_LAYOUTRECALL don't work. Track if a recall occurred while LAYOUTGET was being sent, and if so ignore the results. Signed-off-by: Fred Isaman Signed-off-by: Trond Myklebust --- fs/nfs/callback_proc.c | 2 ++ fs/nfs/pnfs.c | 8 +++++++- include/linux/nfs_fs_sb.h | 1 + include/linux/nfs_xdr.h | 1 + 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index a50d7813e3ea..d561161b7c3e 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -322,6 +322,8 @@ static u32 initiate_bulk_draining(struct nfs_client *clp, static u32 do_callback_layoutrecall(struct nfs_client *clp, struct cb_layoutrecallargs *args) { + write_seqcount_begin(&clp->cl_callback_count); + write_seqcount_end(&clp->cl_callback_count); if (args->cbl_recall_type == RETURN_FILE) return initiate_file_draining(clp, args); return initiate_bulk_draining(clp, args); diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 3dfe9fa264a5..a29fdea2db91 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -1017,6 +1017,7 @@ pnfs_alloc_init_layoutget_args(struct inode *ino, nfs4_stateid_copy(&lgp->args.stateid, stateid); lgp->gfp_flags = gfp_flags; lgp->cred = get_rpccred(ctx->cred); + lgp->callback_count = raw_seqcount_begin(&server->nfs_client->cl_callback_count); return lgp; } @@ -2101,6 +2102,7 @@ void pnfs_parse_lgopen(struct inode *ino, struct nfs4_layoutget *lgp, { struct pnfs_layout_hdr *lo; struct pnfs_layout_segment *lseg; + struct nfs_server *srv = NFS_SERVER(ino); u32 iomode; if (!lgp) @@ -2116,7 +2118,7 @@ void pnfs_parse_lgopen(struct inode *ino, struct nfs4_layoutget *lgp, /* FIXME - Any error not listed above permanently * halts lgopen attempts. */ - NFS_SERVER(ino)->caps &= ~NFS_CAP_LGOPEN; + srv->caps &= ~NFS_CAP_LGOPEN; } return; } @@ -2129,6 +2131,9 @@ void pnfs_parse_lgopen(struct inode *ino, struct nfs4_layoutget *lgp, lo = NFS_I(lgp->args.inode)->layout; pnfs_get_layout_hdr(lo); + if (read_seqcount_retry(&srv->nfs_client->cl_callback_count, + lgp->callback_count)) + goto out; lseg = pnfs_layout_process(lgp); atomic_dec(&lo->plh_outstanding); if (IS_ERR(lseg)) { @@ -2139,6 +2144,7 @@ void pnfs_parse_lgopen(struct inode *ino, struct nfs4_layoutget *lgp, pnfs_layout_clear_fail_bit(lo, pnfs_iomode_to_fail_bit(iomode)); pnfs_put_lseg(lseg); } +out: pnfs_clear_first_layoutget(lo); pnfs_put_layout_hdr(lo); } diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 2c18d618604e..74ae3e1d19a0 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -28,6 +28,7 @@ struct nfs41_impl_id; struct nfs_client { refcount_t cl_count; atomic_t cl_mds_count; + seqcount_t cl_callback_count; int cl_cons_state; /* current construction state (-ve: init error) */ #define NFS_CS_READY 0 /* ready to be used */ #define NFS_CS_INITING 1 /* busy initialising */ diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index bc235e50415f..09dc14ac5804 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -271,6 +271,7 @@ struct nfs4_layoutget { struct nfs4_layoutget_args args; struct nfs4_layoutget_res res; struct rpc_cred *cred; + unsigned callback_count; gfp_t gfp_flags; }; -- 2.30.2