Whamcloud - gitweb
LU-17482 llite: short read could mess up next read offset 27/53827/3
authorBobi Jam <bobijam@whamcloud.com>
Fri, 26 Jan 2024 10:06:50 +0000 (18:06 +0800)
committerBobi Jam <bobijam@whamcloud.com>
Wed, 31 Jan 2024 05:33:49 +0000 (13:33 +0800)
When read reaches EOF, it could read data from stale pagecache, but
we need to restore the iocb->ki_pos so that next read could continue
from the correct offset.

Fixes: 4468f6c9d9 ("LU-16025 llite: adjust read count as file got truncated")
Signed-off-by: Bobi Jam <bobijam@whamcloud.com>
Change-Id: Ib8b62c41bf65f8efec82dda53fcfbdb68ad08b38

lustre/include/obd_support.h
lustre/llite/file.c
lustre/tests/multiop.c
lustre/tests/sanity.sh

index 465382d..52a6d02 100644 (file)
@@ -634,6 +634,7 @@ extern bool obd_enable_health_write;
 #define OBD_FAIL_LOV_COMP_MAGIC                            0x1426
 #define OBD_FAIL_LOV_COMP_PATTERN                  0x1427
 #define OBD_FAIL_LOV_INVALID_OSTIDX                0x1428
+#define OBD_FAIL_LLITE_READ_PAUSE                  0x1431
 
 #define OBD_FAIL_FID_INDIR     0x1501
 #define OBD_FAIL_FID_INLMA     0x1502
index dcc8a93..87f16fe 100644 (file)
@@ -2104,6 +2104,7 @@ static ssize_t ll_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
        struct lu_env *env;
        struct vvp_io_args *args;
        struct file *file = iocb->ki_filp;
+       loff_t orig_ki_pos = iocb->ki_pos;
        ssize_t result;
        ssize_t rc2;
        __u16 refcheck;
@@ -2132,6 +2133,8 @@ static ssize_t ll_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
        else if (result > 0)
                stale_data = true;
 
+       CFS_FAIL_TIMEOUT_ORSET(OBD_FAIL_LLITE_READ_PAUSE, CFS_FAIL_ONCE,
+                              cfs_fail_val);
        /**
         * Currently when PCC read failed, we do not fall back to the
         * normal read path, just return the error.
@@ -2172,6 +2175,7 @@ out:
                 * we've reached EOF before the read, the data read are cached
                 * stale data.
                 */
+               iocb->ki_pos = orig_ki_pos;
                iov_iter_truncate(to, 0);
                result = 0;
        }
index 48886ac..69da675 100644 (file)
@@ -638,6 +638,9 @@ int main(int argc, char **argv)
                        }
 
                        while (len > 0) {
+                               off_t start, off;
+
+                               start = lseek(fd, 0, SEEK_CUR);
                                rc = read(fd, buf_align, len);
                                if (rc == -1) {
                                        save_errno = errno;
@@ -645,8 +648,9 @@ int main(int argc, char **argv)
                                        exit(save_errno);
                                }
                                if (rc < len) {
-                                       fprintf(stderr, "short read: %lld/%u\n",
-                                               rc, len);
+                                       off = lseek(fd, 0, SEEK_CUR);
+                                       fprintf(stderr, "short read: %ld ->+ %u -> %ld %lld\n",
+                                               start, len, off, rc);
                                        if (rc == 0)
                                                break;
                                }
index be98d8a..aff231c 100755 (executable)
@@ -23666,7 +23666,7 @@ test_250() {
 }
 run_test 250 "Write above 16T limit"
 
-test_251() {
+test_251a() {
        $LFS setstripe -c -1 -S 1048576 $DIR/$tfile
 
        #define OBD_FAIL_LLITE_LOST_LAYOUT 0x1407
@@ -23681,7 +23681,29 @@ test_251() {
 
        rm -f $DIR/$tfile
 }
-run_test 251 "Handling short read and write correctly"
+run_test 251a "Handling short read and write correctly"
+
+test_251b() {
+       dd if=/dev/zero of=$DIR/$tfile bs=1k count=4 ||
+               error "write $tfile failed"
+
+       sleep 2 && echo 12345 >> $DIR/$tfile &
+
+       #define OBD_FAIL_LLITE_READ_PAUSE 0x1431
+       $LCTL set_param fail_loc=0x1431 fail_val=5
+       # seek to 4096, 2 seconds later, file size expand to 4102, and after
+       # 5 seconds, read 10 bytes, the short read should
+       # report:
+       #                start ->+ read_len -> offset_after_read read_count
+       #     short read: 4096 ->+ 10 -> 4096 0
+       # not:
+       #     short read: 4096 ->+ 10 -> 4102 0
+       local off=$($MULTIOP $DIR/$tfile oO_RDONLY:z4096r10c 2>&1 | \
+                       awk '/short read/ { print $7 }')
+       (( off == 4096 )) ||
+               error "short read should set offset at 4096, not $off"
+}
+run_test 251b "short read restore offset correctly"
 
 test_252() {
        remote_mds_nodsh && skip "remote MDS with nodsh"