NFS: Ensure O_DIRECT reports an error if the bytes read/written is 0 [Linux 4.19.70]

This Linux kernel change "NFS: Ensure O_DIRECT reports an error if the bytes read/written is 0" is included in the Linux 4.19.70 release. This change is authored by Trond Myklebust <trond.myklebust [at] hammerspace.com> on Mon Aug 12 18:04:36 2019 -0400. The commit for this change in Linux stable tree is 4f4be79 (patch) which is from upstream commit eb2c50d. 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 eb2c50d.

NFS: Ensure O_DIRECT reports an error if the bytes read/written is 0

[ Upstream commit eb2c50da9e256dbbb3ff27694440e4c1900cfef8 ]

If the attempt to resend the I/O results in no bytes being read/written,
we must ensure that we report the error.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Fixes: 0a00b77b331a ("nfs: mirroring support for direct io")
Cc: stable@vger.kernel.org # v3.20+
Signed-off-by: Sasha Levin <sashal@kernel.org>

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

 fs/nfs/direct.c   | 27 ++++++++++++++++++---------
 fs/nfs/pagelist.c |  1 +
 2 files changed, 19 insertions(+), 9 deletions(-)

diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 0fd811a..f516ace 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -400,15 +400,21 @@ static void nfs_direct_read_completion(struct nfs_pgio_header *hdr)
    unsigned long bytes = 0;
    struct nfs_direct_req *dreq = hdr->dreq;

-   if (test_bit(NFS_IOHDR_REDO, &hdr->flags))
-       goto out_put;
-
    spin_lock(&dreq->lock);
-   if (test_bit(NFS_IOHDR_ERROR, &hdr->flags) && (hdr->good_bytes == 0))
+   if (test_bit(NFS_IOHDR_ERROR, &hdr->flags))
        dreq->error = hdr->error;
-   else
+
+   if (test_bit(NFS_IOHDR_REDO, &hdr->flags)) {
+       spin_unlock(&dreq->lock);
+       goto out_put;
+   }
+
+   if (hdr->good_bytes != 0)
        nfs_direct_good_bytes(dreq, hdr);

+   if (test_bit(NFS_IOHDR_EOF, &hdr->flags))
+       dreq->error = 0;
+
    spin_unlock(&dreq->lock);

    while (!list_empty(&hdr->pages)) {
@@ -774,16 +780,19 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr)
    bool request_commit = false;
    struct nfs_page *req = nfs_list_entry(hdr->pages.next);

-   if (test_bit(NFS_IOHDR_REDO, &hdr->flags))
-       goto out_put;
-
    nfs_init_cinfo_from_dreq(&cinfo, dreq);

    spin_lock(&dreq->lock);

    if (test_bit(NFS_IOHDR_ERROR, &hdr->flags))
        dreq->error = hdr->error;
-   if (dreq->error == 0) {
+
+   if (test_bit(NFS_IOHDR_REDO, &hdr->flags)) {
+       spin_unlock(&dreq->lock);
+       goto out_put;
+   }
+
+   if (hdr->good_bytes != 0) {
        nfs_direct_good_bytes(dreq, hdr);
        if (nfs_write_need_commit(hdr)) {
            if (dreq->flags == NFS_ODIRECT_RESCHED_WRITES)
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index 7f0b940..d23ea74 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -1248,6 +1248,7 @@ int nfs_pageio_resend(struct nfs_pageio_descriptor *desc,
    if (!list_empty(&pages)) {
        int err = desc->pg_error < 0 ? desc->pg_error : -EIO;
        hdr->completion_ops->error_cleanup(&pages, err);
+       nfs_set_pgio_error(hdr, err, hdr->io_start);
        return err;
    }
    return 0;

Leave a Reply

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