NFSv4/flexfiles: Cancel I/O if the layout is recalled or revoked
authorTrond Myklebust <trond.myklebust@hammerspace.com>
Wed, 5 Oct 2022 19:57:38 +0000 (15:57 -0400)
committerAnna Schumaker <Anna.Schumaker@Netapp.com>
Thu, 6 Oct 2022 13:52:09 +0000 (09:52 -0400)
If the layout is recalled or revoked, we want to cancel I/O as quickly
as possible so that we can return the layout.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
fs/nfs/flexfilelayout/flexfilelayout.c
fs/nfs/pnfs.c
fs/nfs/pnfs.h

index 1443330..1ec79cc 100644 (file)
@@ -1379,6 +1379,11 @@ static int ff_layout_read_prepare_common(struct rpc_task *task,
                return -EIO;
        }
 
+       if (!pnfs_is_valid_lseg(hdr->lseg)) {
+               rpc_exit(task, -EAGAIN);
+               return -EAGAIN;
+       }
+
        ff_layout_read_record_layoutstats_start(task, hdr);
        return 0;
 }
@@ -1559,6 +1564,11 @@ static int ff_layout_write_prepare_common(struct rpc_task *task,
                return -EIO;
        }
 
+       if (!pnfs_is_valid_lseg(hdr->lseg)) {
+               rpc_exit(task, -EAGAIN);
+               return -EAGAIN;
+       }
+
        ff_layout_write_record_layoutstats_start(task, hdr);
        return 0;
 }
@@ -1651,15 +1661,23 @@ static void ff_layout_commit_record_layoutstats_done(struct rpc_task *task,
        set_bit(NFS_LSEG_LAYOUTRETURN, &cdata->lseg->pls_flags);
 }
 
-static void ff_layout_commit_prepare_common(struct rpc_task *task,
-               struct nfs_commit_data *cdata)
+static int ff_layout_commit_prepare_common(struct rpc_task *task,
+                                          struct nfs_commit_data *cdata)
 {
+       if (!pnfs_is_valid_lseg(cdata->lseg)) {
+               rpc_exit(task, -EAGAIN);
+               return -EAGAIN;
+       }
+
        ff_layout_commit_record_layoutstats_start(task, cdata);
+       return 0;
 }
 
 static void ff_layout_commit_prepare_v3(struct rpc_task *task, void *data)
 {
-       ff_layout_commit_prepare_common(task, data);
+       if (ff_layout_commit_prepare_common(task, data))
+               return;
+
        rpc_call_start(task);
 }
 
@@ -1955,6 +1973,65 @@ ff_layout_commit_pagelist(struct inode *inode, struct list_head *mds_pages,
                                            ff_layout_initiate_commit);
 }
 
+static bool ff_layout_match_rw(const struct rpc_task *task,
+                              const struct nfs_pgio_header *hdr,
+                              const struct pnfs_layout_segment *lseg)
+{
+       return hdr->lseg == lseg;
+}
+
+static bool ff_layout_match_commit(const struct rpc_task *task,
+                                  const struct nfs_commit_data *cdata,
+                                  const struct pnfs_layout_segment *lseg)
+{
+       return cdata->lseg == lseg;
+}
+
+static bool ff_layout_match_io(const struct rpc_task *task, const void *data)
+{
+       const struct rpc_call_ops *ops = task->tk_ops;
+
+       if (ops == &ff_layout_read_call_ops_v3 ||
+           ops == &ff_layout_read_call_ops_v4 ||
+           ops == &ff_layout_write_call_ops_v3 ||
+           ops == &ff_layout_write_call_ops_v4)
+               return ff_layout_match_rw(task, task->tk_calldata, data);
+       if (ops == &ff_layout_commit_call_ops_v3 ||
+           ops == &ff_layout_commit_call_ops_v4)
+               return ff_layout_match_commit(task, task->tk_calldata, data);
+       return false;
+}
+
+static void ff_layout_cancel_io(struct pnfs_layout_segment *lseg)
+{
+       struct nfs4_ff_layout_segment *flseg = FF_LAYOUT_LSEG(lseg);
+       struct nfs4_ff_layout_mirror *mirror;
+       struct nfs4_ff_layout_ds *mirror_ds;
+       struct nfs4_pnfs_ds *ds;
+       struct nfs_client *ds_clp;
+       struct rpc_clnt *clnt;
+       u32 idx;
+
+       for (idx = 0; idx < flseg->mirror_array_cnt; idx++) {
+               mirror = flseg->mirror_array[idx];
+               mirror_ds = mirror->mirror_ds;
+               if (!mirror_ds)
+                       continue;
+               ds = mirror->mirror_ds->ds;
+               if (!ds)
+                       continue;
+               ds_clp = ds->ds_clp;
+               if (!ds_clp)
+                       continue;
+               clnt = ds_clp->cl_rpcclient;
+               if (!clnt)
+                       continue;
+               if (!rpc_cancel_tasks(clnt, -EAGAIN, ff_layout_match_io, lseg))
+                       continue;
+               rpc_clnt_disconnect(clnt);
+       }
+}
+
 static struct pnfs_ds_commit_info *
 ff_layout_get_ds_info(struct inode *inode)
 {
@@ -2512,6 +2589,7 @@ static struct pnfs_layoutdriver_type flexfilelayout_type = {
        .prepare_layoutreturn   = ff_layout_prepare_layoutreturn,
        .sync                   = pnfs_nfs_generic_sync,
        .prepare_layoutstats    = ff_layout_prepare_layoutstats,
+       .cancel_io              = ff_layout_cancel_io,
 };
 
 static int __init nfs4flexfilelayout_init(void)
index 2613b7e..d41fc15 100644 (file)
@@ -710,6 +710,7 @@ pnfs_mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
                            u32 seq)
 {
        struct pnfs_layout_segment *lseg, *next;
+       struct nfs_server *server = NFS_SERVER(lo->plh_inode);
        int remaining = 0;
 
        dprintk("%s:Begin lo %p\n", __func__, lo);
@@ -722,8 +723,10 @@ pnfs_mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
                                "offset %llu length %llu\n", __func__,
                                lseg, lseg->pls_range.iomode, lseg->pls_seq,
                                lseg->pls_range.offset, lseg->pls_range.length);
-                       if (!mark_lseg_invalid(lseg, tmp_list))
-                               remaining++;
+                       if (mark_lseg_invalid(lseg, tmp_list))
+                               continue;
+                       remaining++;
+                       pnfs_lseg_cancel_io(server, lseg);
                }
        dprintk("%s:Return %i\n", __func__, remaining);
        return remaining;
@@ -2485,6 +2488,7 @@ pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo,
                                u32 seq)
 {
        struct pnfs_layout_segment *lseg, *next;
+       struct nfs_server *server = NFS_SERVER(lo->plh_inode);
        int remaining = 0;
 
        dprintk("%s:Begin lo %p\n", __func__, lo);
@@ -2507,6 +2511,7 @@ pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo,
                                continue;
                        remaining++;
                        set_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags);
+                       pnfs_lseg_cancel_io(server, lseg);
                }
 
        if (remaining) {
index f331f06..e3e6a41 100644 (file)
@@ -169,6 +169,8 @@ struct pnfs_layoutdriver_type {
        void (*cleanup_layoutcommit) (struct nfs4_layoutcommit_data *data);
        int (*prepare_layoutcommit) (struct nfs4_layoutcommit_args *args);
        int (*prepare_layoutstats) (struct nfs42_layoutstat_args *args);
+
+       void (*cancel_io)(struct pnfs_layout_segment *lseg);
 };
 
 struct pnfs_commit_ops {
@@ -685,6 +687,13 @@ pnfs_lseg_request_intersecting(struct pnfs_layout_segment *lseg, struct nfs_page
                                req_offset(req), req_last);
 }
 
+static inline void pnfs_lseg_cancel_io(struct nfs_server *server,
+                                      struct pnfs_layout_segment *lseg)
+{
+       if (server->pnfs_curr_ld->cancel_io)
+               server->pnfs_curr_ld->cancel_io(lseg);
+}
+
 extern unsigned int layoutstats_timer;
 
 #ifdef NFS_DEBUG