pnfs: Add barrier to prevent lgopen using LAYOUTGET during recall
authorFred Isaman <fred.isaman@gmail.com>
Wed, 5 Oct 2016 13:37:12 +0000 (09:37 -0400)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Thu, 31 May 2018 19:03:11 +0000 (15:03 -0400)
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 <fred.isaman@gmail.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
fs/nfs/callback_proc.c
fs/nfs/pnfs.c
include/linux/nfs_fs_sb.h
include/linux/nfs_xdr.h

index a50d781..d561161 100644 (file)
@@ -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);
index 3dfe9fa..a29fdea 100644 (file)
@@ -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);
 }
index 2c18d61..74ae3e1 100644 (file)
@@ -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 */
index bc235e5..09dc14a 100644 (file)
@@ -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;
 };