]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
NFSv4/pnfs: Allow layoutget to return EAGAIN for softerr mounts
authorTrond Myklebust <trond.myklebust@hammerspace.com>
Sat, 9 Sep 2023 23:16:53 +0000 (19:16 -0400)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Sun, 22 Oct 2023 23:47:56 +0000 (19:47 -0400)
If we're using the 'softerr' mount option, we may want to allow
layoutget to return EAGAIN to allow knfsd server threads to return a
JUKEBOX/DELAY error to the client instead of busy waiting.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
fs/nfs/nfs4proc.c
fs/nfs/pnfs.c
fs/nfs/pnfs.h
fs/nfs/write.c

index 6f64fe97e72f371f74010034a0b7f8e193fa0b86..734643b60c484980e1fd8ce1c55d81f8eedd499e 100644 (file)
@@ -9646,6 +9646,9 @@ nfs4_layoutget_handle_exception(struct rpc_task *task,
 
        nfs4_sequence_free_slot(&lgp->res.seq_res);
 
+       exception->state = NULL;
+       exception->stateid = NULL;
+
        switch (nfs4err) {
        case 0:
                goto out;
@@ -9741,7 +9744,8 @@ static const struct rpc_call_ops nfs4_layoutget_call_ops = {
 };
 
 struct pnfs_layout_segment *
-nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout)
+nfs4_proc_layoutget(struct nfs4_layoutget *lgp,
+                   struct nfs4_exception *exception)
 {
        struct inode *inode = lgp->args.inode;
        struct nfs_server *server = NFS_SERVER(inode);
@@ -9761,13 +9765,10 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout)
                         RPC_TASK_MOVEABLE,
        };
        struct pnfs_layout_segment *lseg = NULL;
-       struct nfs4_exception exception = {
-               .inode = inode,
-               .timeout = *timeout,
-       };
        int status = 0;
 
        nfs4_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0, 0);
+       exception->retry = 0;
 
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
@@ -9778,11 +9779,12 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout)
                goto out;
 
        if (task->tk_status < 0) {
-               status = nfs4_layoutget_handle_exception(task, lgp, &exception);
-               *timeout = exception.timeout;
+               exception->retry = 1;
+               status = nfs4_layoutget_handle_exception(task, lgp, exception);
        } else if (lgp->res.layoutp->len == 0) {
+               exception->retry = 1;
                status = -EAGAIN;
-               *timeout = nfs4_update_delay(&exception.timeout);
+               nfs4_update_delay(&exception->timeout);
        } else
                lseg = pnfs_layout_process(lgp);
 out:
index 84343aefbbd64cdf241fcf4e677ba50e991d9109..21a365357629c7531aeb8ec128cba116d41dc7dd 100644 (file)
@@ -1980,7 +1980,9 @@ pnfs_update_layout(struct inode *ino,
        struct pnfs_layout_segment *lseg = NULL;
        struct nfs4_layoutget *lgp;
        nfs4_stateid stateid;
-       long timeout = 0;
+       struct nfs4_exception exception = {
+               .inode = ino,
+       };
        unsigned long giveup = jiffies + (clp->cl_lease_time << 1);
        bool first;
 
@@ -2144,7 +2146,7 @@ lookup_again:
        lgp->lo = lo;
        pnfs_get_layout_hdr(lo);
 
-       lseg = nfs4_proc_layoutget(lgp, &timeout);
+       lseg = nfs4_proc_layoutget(lgp, &exception);
        trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg,
                                 PNFS_UPDATE_LAYOUT_SEND_LAYOUTGET);
        nfs_layoutget_end(lo);
@@ -2171,6 +2173,8 @@ lookup_again:
                        goto out_put_layout_hdr;
                }
                if (lseg) {
+                       if (!exception.retry)
+                               goto out_put_layout_hdr;
                        if (first)
                                pnfs_clear_first_layoutget(lo);
                        trace_pnfs_update_layout(ino, pos, count,
index d886c8226d8fecac631cf85dcfad283a4c5681e3..db57a85500ee70f07347f8de647ddca341f4b1ac 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/nfs_page.h>
 #include <linux/workqueue.h>
 
+struct nfs4_exception;
 struct nfs4_opendata;
 
 enum {
@@ -245,7 +246,9 @@ extern size_t max_response_pages(struct nfs_server *server);
 extern int nfs4_proc_getdeviceinfo(struct nfs_server *server,
                                   struct pnfs_device *dev,
                                   const struct cred *cred);
-extern struct pnfs_layout_segment* nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout);
+extern struct pnfs_layout_segment *
+nfs4_proc_layoutget(struct nfs4_layoutget *lgp,
+                   struct nfs4_exception *exception);
 extern int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp, bool sync);
 
 /* pnfs.c */
index 9d82d50ce0b12dc7063f021d4380582633ed419f..b664caea8b4e6704bc0b46e8388487999697b80b 100644 (file)
@@ -739,6 +739,8 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
                                        &pgio);
                pgio.pg_error = 0;
                nfs_pageio_complete(&pgio);
+               if (err == -EAGAIN && mntflags & NFS_MOUNT_SOFTERR)
+                       break;
        } while (err < 0 && !nfs_error_is_fatal(err));
        nfs_io_completion_put(ioc);