NFS: Pass error information to the pgio error cleanup routine [Linux 4.19.70]

This Linux kernel change "NFS: Pass error information to the pgio error cleanup routine" is included in the Linux 4.19.70 release. This change is authored by Trond Myklebust <trond.myklebust [at] hammerspace.com> on Wed Feb 13 10:39:39 2019 -0500. The commit for this change in Linux stable tree is b5891b6 (patch) which is from upstream commit df3accb. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream df3accb.

NFS: Pass error information to the pgio error cleanup routine

[ Upstream commit df3accb849607a86278a37c35e6b313635ccc48b ]

Allow the caller to pass error information when cleaning up a failed
I/O request so that we can conditionally take action to cancel the
request altogether if the error turned out to be fatal.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>

There are 24 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 fs/nfs/direct.c         |  4 ++--
 fs/nfs/pagelist.c       |  5 +++--
 fs/nfs/read.c           |  2 +-
 fs/nfs/write.c          | 11 +++++++++--
 include/linux/nfs_xdr.h |  2 +-
 5 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 1377ee2..0fd811a 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -428,7 +428,7 @@ static void nfs_direct_read_completion(struct nfs_pgio_header *hdr)
    hdr->release(hdr);
 }

-static void nfs_read_sync_pgio_error(struct list_head *head)
+static void nfs_read_sync_pgio_error(struct list_head *head, int error)
 {
    struct nfs_page *req;

@@ -820,7 +820,7 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr)
    hdr->release(hdr);
 }

-static void nfs_write_sync_pgio_error(struct list_head *head)
+static void nfs_write_sync_pgio_error(struct list_head *head, int error)
 {
    struct nfs_page *req;

diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index 9cbd829..7f0b940 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -994,7 +994,7 @@ static void nfs_pageio_doio(struct nfs_pageio_descriptor *desc)
    LIST_HEAD(head);

    nfs_list_move_request(req, &head);
-   desc->pg_completion_ops->error_cleanup(&head);
+   desc->pg_completion_ops->error_cleanup(&head, desc->pg_error);
 }

 /**
@@ -1130,7 +1130,8 @@ static void nfs_pageio_error_cleanup(struct nfs_pageio_descriptor *desc)

    for (midx = 0; midx < desc->pg_mirror_count; midx++) {
        mirror = &desc->pg_mirrors[midx];
-       desc->pg_completion_ops->error_cleanup(&mirror->pg_list);
+       desc->pg_completion_ops->error_cleanup(&mirror->pg_list,
+               desc->pg_error);
    }
 }

diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 48d7277..09d5c28 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -205,7 +205,7 @@ static void nfs_initiate_read(struct nfs_pgio_header *hdr,
 }

 static void
-nfs_async_read_error(struct list_head *head)
+nfs_async_read_error(struct list_head *head, int error)
 {
    struct nfs_page *req;

diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 51d0b79..5ab9979 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -1394,20 +1394,27 @@ static void nfs_redirty_request(struct nfs_page *req)
    nfs_release_request(req);
 }

-static void nfs_async_write_error(struct list_head *head)
+static void nfs_async_write_error(struct list_head *head, int error)
 {
    struct nfs_page *req;

    while (!list_empty(head)) {
        req = nfs_list_entry(head->next);
        nfs_list_remove_request(req);
+       if (nfs_error_is_fatal(error)) {
+           nfs_context_set_write_error(req->wb_context, error);
+           if (nfs_error_is_fatal_on_server(error)) {
+               nfs_write_error_remove_page(req);
+               continue;
+           }
+       }
        nfs_redirty_request(req);
    }
 }

 static void nfs_async_write_reschedule_io(struct nfs_pgio_header *hdr)
 {
-   nfs_async_write_error(&hdr->pages);
+   nfs_async_write_error(&hdr->pages, 0);
    filemap_fdatawrite_range(hdr->inode->i_mapping, hdr->args.offset,
            hdr->args.offset + hdr->args.count - 1);
 }
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index bd1c889..cab24a1 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1539,7 +1539,7 @@ struct nfs_commit_data {
 };

 struct nfs_pgio_completion_ops {
-   void    (*error_cleanup)(struct list_head *head);
+   void    (*error_cleanup)(struct list_head *head, int);
    void    (*init_hdr)(struct nfs_pgio_header *hdr);
    void    (*completion)(struct nfs_pgio_header *hdr);
    void    (*reschedule_io)(struct nfs_pgio_header *hdr);

Leave a Reply

Your email address will not be published. Required fields are marked *