Patch "netfs, cifs: Fix handling of short DIO read" has been added to the 6.10-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    netfs, cifs: Fix handling of short DIO read

to the 6.10-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     netfs-cifs-fix-handling-of-short-dio-read.patch
and it can be found in the queue-6.10 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit ea31ee7c8b47104a5fb93bd23e0b322bf4a7e492
Author: David Howells <dhowells@xxxxxxxxxx>
Date:   Thu Aug 22 23:06:49 2024 +0100

    netfs, cifs: Fix handling of short DIO read
    
    [ Upstream commit 1da29f2c39b67b846b74205c81bf0ccd96d34727 ]
    
    Short DIO reads, particularly in relation to cifs, are not being handled
    correctly by cifs and netfslib.  This can be tested by doing a DIO read of
    a file where the size of read is larger than the size of the file.  When it
    crosses the EOF, it gets a short read and this gets retried, and in the
    case of cifs, the retry read fails, with the failure being translated to
    ENODATA.
    
    Fix this by the following means:
    
     (1) Add a flag, NETFS_SREQ_HIT_EOF, for the filesystem to set when it
         detects that the read did hit the EOF.
    
     (2) Make the netfslib read assessment stop processing subrequests when it
         encounters one with that flag set.
    
     (3) Return rreq->transferred, the accumulated contiguous amount read to
         that point, to userspace for a DIO read.
    
     (4) Make cifs set the flag and clear the error if the read RPC returned
         ENODATA.
    
     (5) Make cifs set the flag and clear the error if a short read occurred
         without error and the read-to file position is now at the remote inode
         size.
    
    Fixes: 69c3c023af25 ("cifs: Implement netfslib hooks")
    Signed-off-by: David Howells <dhowells@xxxxxxxxxx>
    cc: Steve French <sfrench@xxxxxxxxx>
    cc: Paulo Alcantara <pc@xxxxxxxxxxxxx>
    cc: Jeff Layton <jlayton@xxxxxxxxxx>
    cc: linux-cifs@xxxxxxxxxxxxxxx
    cc: netfs@xxxxxxxxxxxxxxx
    cc: linux-fsdevel@xxxxxxxxxxxxxxx
    Signed-off-by: Steve French <stfrench@xxxxxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/fs/netfs/io.c b/fs/netfs/io.c
index 2a5c22606fb1..c91e7b12bbf1 100644
--- a/fs/netfs/io.c
+++ b/fs/netfs/io.c
@@ -368,7 +368,8 @@ static void netfs_rreq_assess_dio(struct netfs_io_request *rreq)
 		if (subreq->error || subreq->transferred == 0)
 			break;
 		transferred += subreq->transferred;
-		if (subreq->transferred < subreq->len)
+		if (subreq->transferred < subreq->len ||
+		    test_bit(NETFS_SREQ_HIT_EOF, &subreq->flags))
 			break;
 	}
 
@@ -503,7 +504,8 @@ void netfs_subreq_terminated(struct netfs_io_subrequest *subreq,
 
 	subreq->error = 0;
 	subreq->transferred += transferred_or_error;
-	if (subreq->transferred < subreq->len)
+	if (subreq->transferred < subreq->len &&
+	    !test_bit(NETFS_SREQ_HIT_EOF, &subreq->flags))
 		goto incomplete;
 
 complete:
@@ -777,10 +779,13 @@ int netfs_begin_read(struct netfs_io_request *rreq, bool sync)
 			    TASK_UNINTERRUPTIBLE);
 
 		ret = rreq->error;
-		if (ret == 0 && rreq->submitted < rreq->len &&
-		    rreq->origin != NETFS_DIO_READ) {
-			trace_netfs_failure(rreq, NULL, ret, netfs_fail_short_read);
-			ret = -EIO;
+		if (ret == 0) {
+			if (rreq->origin == NETFS_DIO_READ) {
+				ret = rreq->transferred;
+			} else if (rreq->submitted < rreq->len) {
+				trace_netfs_failure(rreq, NULL, ret, netfs_fail_short_read);
+				ret = -EIO;
+			}
 		}
 	} else {
 		/* If we decrement nr_outstanding to 0, the ref belongs to us. */
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index 5f5f51bf9850..8e02e9f45e0e 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -4501,6 +4501,7 @@ static void
 smb2_readv_callback(struct mid_q_entry *mid)
 {
 	struct cifs_io_subrequest *rdata = mid->callback_data;
+	struct netfs_inode *ictx = netfs_inode(rdata->rreq->inode);
 	struct cifs_tcon *tcon = tlink_tcon(rdata->req->cfile->tlink);
 	struct TCP_Server_Info *server = rdata->server;
 	struct smb2_hdr *shdr =
@@ -4593,11 +4594,15 @@ smb2_readv_callback(struct mid_q_entry *mid)
 				     rdata->got_bytes);
 
 	if (rdata->result == -ENODATA) {
-		/* We may have got an EOF error because fallocate
-		 * failed to enlarge the file.
-		 */
-		if (rdata->subreq.start < rdata->subreq.rreq->i_size)
+		__set_bit(NETFS_SREQ_HIT_EOF, &rdata->subreq.flags);
+		rdata->result = 0;
+	} else {
+		if (rdata->got_bytes < rdata->actual_len &&
+		    rdata->subreq.start + rdata->subreq.transferred + rdata->got_bytes ==
+		    ictx->remote_i_size) {
+			__set_bit(NETFS_SREQ_HIT_EOF, &rdata->subreq.flags);
 			rdata->result = 0;
+		}
 	}
 	trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, rdata->credits.value,
 			      server->credits, server->in_flight,
diff --git a/include/linux/netfs.h b/include/linux/netfs.h
index 5d0288938cc2..d8892b1a2dd7 100644
--- a/include/linux/netfs.h
+++ b/include/linux/netfs.h
@@ -200,6 +200,7 @@ struct netfs_io_subrequest {
 #define NETFS_SREQ_NEED_RETRY		9	/* Set if the filesystem requests a retry */
 #define NETFS_SREQ_RETRYING		10	/* Set if we're retrying */
 #define NETFS_SREQ_FAILED		11	/* Set if the subreq failed unretryably */
+#define NETFS_SREQ_HIT_EOF		12	/* Set if we hit the EOF */
 };
 
 enum netfs_io_origin {




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux