tests/ext4: Ensure resizes with sparse_super2 are handled correctly
v2 cover tests/ext4: Ensure resizes with sparse_super2 are handled correctly
As detailed in the patch [1], kernel currently does not support resizes with sparse_super2 enabled. Before the above patch, if we used the EXT4_IOC_RESIZE_FS ioctl directly, wiht sparse_super2 enabled, the kernel used to still try the resize and ultimatley leave the fs in an inconsistent state. This also led to corruption and kernel BUGs.
This patchset adds a test for ext4 to ensure that the kernel handles resizes with sparse_super2 correctly, and returns -EOPNOTSUPP.
Summary:
Patch 1: Fix the src/ext4_resize.c script to return accurate error
codes.
Patch 2: Add the ext4 test for checking resize functionality
Changes since v1 [2]
* In patch 2, don't iterate if the expected errno is returned
* Code cleanup and additional comments for clarity (also see extra note in patch 2)
* No changes in patch 1
[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b1489186cc8391e0c1e342f9fbc3eedf6b944c61
[2] https://lore.kernel.org/fstests/[email protected]/
Ojaswin Mujoo (2):
src/ext4_resize.c: Refactor code and ensure accurate errno is returned
ext4: Test to ensure resize with sparse_super2 is handled correctly
src/ext4_resize.c | 46 +++++++++++++------ tests/ext4/056 | 108 +++++++++++++++++++++++++++++++++++++++++++++ tests/ext4/056.out | 2 + 3 files changed, 142 insertions(+), 14 deletions(-) create mode 100755 tests/ext4/056 create mode 100644 tests/ext4/056.out
Signature · 1 line
2.27.0
PATCH v2 1/2 src/ext4_resize.c: Refactor code and ensure accurate errno is returned
The current implementation of ext4_resize returned 1 whenever there was an error. Modify this to return the correct error code. This is important for tests that rely on correct error reporting, by the kernel, for ext4 resize functionality.
Additionaly, perform some code cleanup.
--- src/ext4_resize.c | 46 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-)
src/ext4_resize.c +32 -14
@@ -10,6 +10,7 @@#include <unistd.h> #include <stdint.h> #include <stdlib.h> +#include <string.h> #include <sys/ioctl.h> #include <sys/mount.h>
@@ -19,33 +20,50 @@ typedef unsigned long long __u64;#define EXT4_IOC_RESIZE_FS _IOW('f', 16, __u64)#endif +#define pr_error (fmt, ...) do { \ + fprintf (stderr, "ext4_resize.c: " fmt, ##__VA_ARGS__); \ +} while (0) + +static void usage (void ) +{ +fprintf (stdout,"\nUsage: ext4_resize [mnt_path] [new_size(blocks)]\n" ); +} +int main (int argc,char **argv) {__u64 new_size;int error, fd; -char *tmp =NULL ; +char *mnt_dir =NULL , *tmp =NULL ;if (argc !=3 ) { -fputs ("insufficient arguments\n" , stderr); -return 1 ; - } - fd =open (argv[1 ],O_RDONLY ); -if (!fd) { -perror (argv[1 ]); -return 1 ; + error =EINVAL ; +pr_error ("insufficient arguments\n" ); +usage (); +return error; } + mnt_dir = argv[1 ]; + errno =0 ; new_size =strtoull (argv[2 ], &tmp,10 );if ((errno) || (*tmp !='\0' )) { -fprintf (stderr,"%s: invalid new size\n" , argv[0 ]); -return 1 ; + error = errno; +pr_error ("invalid new size\n" ); +return error; + } + + fd =open (mnt_dir,O_RDONLY ); +if (fd <0 ) { + error = errno; +pr_error ("open() failed with error: %s\n" ,strerror (error)); +return error; } - error =ioctl (fd,EXT4_IOC_RESIZE_FS , &new_size); -if (error <0 ) { -perror ("EXT4_IOC_RESIZE_FS" ); -return 1 ; +if (ioctl (fd,EXT4_IOC_RESIZE_FS , &new_size) <0 ) { + error = errno; +pr_error ("EXT4_IOC_RESIZE_FS ioctl() failed with error: %s\n" ,strerror (error)); +return error; } +return 0 ; }
Signature · 1 line
2.27.0
PATCH v2 2/2 ext4: Test to ensure resize with sparse_super2 is handled correctly
In reply to Ojaswin MujooKernel currently doesn't support resize of EXT4 mounted
with sparse_super2 option enabled. Earlier, it used to leave the resize incomplete and the fs would be left in an inconsistent state, however commit b1489186cc83[1] fixed this to avoid the fs corruption by clearly returning -EOPNOTSUPP.
Test to ensure that kernel handles resizing with sparse_super2 correctly. Run resize for multiple iterations because this sometimes leads to kernel crash due to fs corruption, which we want to detect.
Related commit in mainline:
[1] commit b1489186cc8391e0c1e342f9fbc3eedf6b944c61
ext4: add check to prevent attempting to resize an fs with sparse_super2
---
I would like to add a few comments on the approach followed in this test:
1. So although we check the return codes of the resize operation for proper logging, the test is only considered to be passed if fsck passes after the resize. This is because resizing a patched kernel always keeps the fs consistent whereas resizing on unpatched kernel always corrupts the fs.
2. I've noticed that running mkfs + resize multiple times on unpatched kernel sometimes results in KASAN reporting use-after-free. Hence, if we detect the kernel is unpatched (doesn't return EOPNOTSUPP on resize) we continue iterating to capture this. In this case, we don't run fsck in each iteration but run it only after all iterations are complete because _check_scratch_fs exits the test if it fails.
3. In case we detect patched kernel, we stop iterating, and run fsck to confirm success
tests/ext4/056 | 108 +++++++++++++++++++++++++++++++++++++++++++++ tests/ext4/056.out | 2 + 2 files changed, 110 insertions(+) create mode 100755 tests/ext4/056 create mode 100644 tests/ext4/056.out
tests/ext4/056 new file +108 -0
@@ -0,0 +1,108 @@ +#! /bin/bash +# SPDX-License-Identifier: GPL-2.0 +# Copyright (c) 2022 IBM. All Rights Reserved. +# +# We don't currently support resize of EXT4 filesystems mounted +# with sparse_super2 option enabled. Earlier, kernel used to leave the resize +# incomplete and the fs would be left into an incomplete state, however commit +# b1489186cc83[1] fixed this to avoid the fs corruption by clearly returning +# -ENOTSUPP. +# +# This test ensures that kernel handles resizing with sparse_super2 correctly +# +# Related commit in mainline: +# +# [1] commit b1489186cc8391e0c1e342f9fbc3eedf6b944c61 +# ext4: add check to prevent attempting to resize an fs with sparse_super2 +# + +. ./common/preamble +_begin_fstest auto ioctl resize quick + +# real QA test starts here + +INITIAL_FS_SIZE=1G +RESIZED_FS_SIZE=$((2*1024*1024*1024)) # 2G +ONLINE_RESIZE_BLOCK_LIMIT=$((256*1024*1024)) + +STOP_ITER=255 # Arbitrary return code + +_supported_fs ext4 +_require_scratch_size $(($RESIZED_FS_SIZE/1024)) +_require_test_program "ext4_resize" + +log() +{ + echo "$seq: $*" >> $seqres.full 2>&1 +} + +do_resize() +{ + _mkfs_dev -E resize=$ONLINE_RESIZE_BLOCK_LIMIT -O sparse_super2 \ + $SCRATCH_DEV $INITIAL_FS_SIZE >> $seqres.full 2>&1 \ + || _fail "$MKFS_PROG failed. Exiting" + + _scratch_mount || _fail "Failed to mount scratch partition. Exiting" + + local BS=$(_get_block_size $SCRATCH_MNT) + local REQUIRED_BLOCKS=$(($RESIZED_FS_SIZE/$BS)) + + local RESIZE_RET + local EOPNOTSUPP=95 + + log "Resizing FS" + $here/src/ext4_resize $SCRATCH_MNT $REQUIRED_BLOCKS >> $seqres.full 2>&1 + RESIZE_RET=$? + + # Test appears to be successful. Stop iterating and confirm if FS is + # consistent. + if [ $RESIZE_RET = $EOPNOTSUPP ] + then + log "Resize operation not supported with sparse_super2" + log "Threw expected error $RESIZE_RET (EOPNOTSUPP)" + return $STOP_ITER + fi + + # Test appears to be unsuccessful. Most probably, the fs is corrupt, + # iterate a few more times to further stress test this. + log "Something is wrong. Output of resize = $RESIZE_RET. \ + Expected $EOPNOTSUPP (EOPNOTSUPP)" + + # unmount after ioctl sometimes fails with "device busy" so add a small + # delay + sleep 0.2 + _scratch_unmount >> $seqres.full 2>&1 \ + || _fail "$UMOUNT_PROG failed. Exiting" +} + +run_test() +{ + local FSCK_RET + local ITERS=8 + local RET=0 + + for i in $(seq 1 $ITERS) + do + log "----------- Iteration: $i ------------" + do_resize + RET=$? + + [ "$RET" = "$STOP_ITER" ] && break + done + + log "-------- Iterations Complete ---------" + log "Checking if FS is in consistent state" + _check_scratch_fs + FSCK_RET=$? + + [ "$FSCK_RET" -ne "0" ] && \ + echo "fs corrupt. Check $seqres.full for more details" + + return $FSCK_RET +} + +echo "Silence is golden" +run_test +status=$? + +exit
tests/ext4/056.out new file +2 -0
@@ -0,0 +1,2 @@ +QA output created by 056 +Silence is golden
Signature · 1 line
2.27.0
Re: [PATCH v2 2/2] ext4: Test to ensure resize with sparse_super2 is handled correctly
Quoted 135 lines · Ojaswin Mujoo
Kernel currently doesn't support resize of EXT4 mounted
withsparse_super2option enabled. Earlier, it used to leave the resize incomplete and the fs would be left in an inconsistent state, however commit b1489186cc83[1] fixed this to avoid the fs corruption by clearly returning-EOPNOTSUPP.Test to ensure that kernel handles resizing with
sparse_super2correctly. Run resize for multiple iterations because this sometimes leads to kernel crash due to fs corruption, which we want to detect.Related commit in mainline:
[1] commit
b1489186cc8391e0c1e342f9fbc3eedf6b944c61ext4: add check to prevent attempting to resize an fs with
sparse_super2Signed-off-by Ojaswin Mujoo <[email protected]>---
I would like to add a few comments on the approach followed in this test:
1. So although we check the return codes of the resize operation for proper logging, the test is only considered to be passed if fsck passes after the resize. This is because resizing a patched kernel always keeps the fs consistent whereas resizing on unpatched kernel always corrupts the fs.
2. I've noticed that running mkfs + resize multiple times on unpatched kernel sometimes results in KASAN reporting use-after-free. Hence, if we detect the kernel is unpatched (doesn't return EOPNOTSUPP on resize) we continue iterating to capture this. In this case, we don't run fsck in each iteration but run it only after all iterations are complete because
_check_scratch_fsexits the test if it fails.3. In case we detect patched kernel, we stop iterating, and run fsck to confirm success
tests/ext4/056 | 108 +++++++++++++++++++++++++++++++++++++++++++++ tests/ext4/056.out | 2 + 2 files changed, 110 insertions(+) create mode 100755 tests/ext4/056 create mode 100644 tests/ext4/056.outtests/ext4/056 new file +85
-0@@ -0,0 +1,108 @@ +#! /bin/bash +# SPDX-License-Identifier: GPL-2.0 +# Copyright (c) 2022 IBM. All Rights Reserved. +# +# We don't currently support resize of EXT4 filesystems mounted +# with sparse_super2 option enabled. Earlier, kernel used to leave the resize +# incomplete and the fs would be left into an incomplete state, however commit +# b1489186cc83[1] fixed this to avoid the fs corruption by clearly returning +# -ENOTSUPP. +# +# This test ensures that kernel handles resizing with sparse_super2 correctly +# +# Related commit in mainline: +# +# [1] commit b1489186cc8391e0c1e342f9fbc3eedf6b944c61 +# ext4: add check to prevent attempting to resize an fs with sparse_super2 +# + +. ./common/preamble +_begin_fstest auto ioctl resize quick + +# real QA test starts here + +INITIAL_FS_SIZE=1G +RESIZED_FS_SIZE=$((2*1024*1024*1024)) # 2G +ONLINE_RESIZE_BLOCK_LIMIT=$((256*1024*1024)) + +STOP_ITER=255 # Arbitrary return code + +_supported_fs ext4 +_require_scratch_size $(($RESIZED_FS_SIZE/1024)) +_require_test_program "ext4_resize" + +log() +{ + echo "$seq: $*" >> $seqres.full 2>&1 +} + +do_resize() +{ + _mkfs_dev -E resize=$ONLINE_RESIZE_BLOCK_LIMIT -O sparse_super2 \ + $SCRATCH_DEV $INITIAL_FS_SIZE >> $seqres.full 2>&1 \ + || _fail "$MKFS_PROG failed. Exiting" + + _scratch_mount || _fail "Failed to mount scratch partition. Exiting" + + local BS=$(_get_block_size $SCRATCH_MNT) + local REQUIRED_BLOCKS=$(($RESIZED_FS_SIZE/$BS)) + + local RESIZE_RET + local EOPNOTSUPP=95 + + log "Resizing FS" + $here/src/ext4_resize $SCRATCH_MNT $REQUIRED_BLOCKS >> $seqres.full 2>&1 + RESIZE_RET=$? + + # Test appears to be successful. Stop iterating and confirm if FS is + # consistent. + if [ $RESIZE_RET = $EOPNOTSUPP ] + then + log "Resize operation not supported with sparse_super2" + log "Threw expected error $RESIZE_RET (EOPNOTSUPP)" + return $STOP_ITER + fi + + # Test appears to be unsuccessful. Most probably, the fs is corrupt, + # iterate a few more times to further stress test this. + log "Something is wrong. Output of resize = $RESIZE_RET. \ + Expected $EOPNOTSUPP (EOPNOTSUPP)" + + # unmount after ioctl sometimes fails with "device busy" so add a small + # delay + sleep 0.2 + _scratch_unmount >> $seqres.full 2>&1 \ + || _fail "$UMOUNT_PROG failed. Exiting" +} + +run_test() +{ + local FSCK_RET + local ITERS=8 + local RET=0 + + for i in $(seq 1 $ITERS) + do
tests/ext4/056 line 95
Quoted 10 lines
tests/ext4/056 new file +10
-0+ log "----------- Iteration: $i ------------" + do_resize + RET=$? + + [ "$RET" = "$STOP_ITER" ] && break + done + + log "-------- Iterations Complete ---------" + log "Checking if FS is in consistent state" + _check_scratch_fs
_check_scratch_fs will exit the test on failure and print error message, which will break the golden image, so there's no need to check fsck ret.
tests/ext4/056 line 101
Quoted 6 lines
tests/ext4/056 new file +6
-0+ FSCK_RET=$? + + [ "$FSCK_RET" -ne "0" ] && \ + echo "fs corrupt. Check $seqres.full for more details" + + return $FSCK_RET
So I removed above hunk on commit.
Thanks for the test! And my apology to the HUGE delay on review..
Thanks,
Eryu
Quoted 17 lines
tests/ext4/056 new file +7
-0+} + +echo "Silence is golden" +run_test +status=$? + +exittests/ext4/056.out new file +2
-0@@ -0,0 +1,2 @@ +QA output created by 056 +Silence is goldenSignature · 1 line
2.27.0
Re: [PATCH v2 2/2] ext4: Test to ensure resize with sparse_super2 is handled correctly
Quoted 159 lines · Eryu Guan
Quoted 135 lines · Ojaswin Mujoo
Kernel currently doesn't support resize of EXT4 mounted
withsparse_super2option enabled. Earlier, it used to leave the resize incomplete and the fs would be left in an inconsistent state, however commit b1489186cc83[1] fixed this to avoid the fs corruption by clearly returning-EOPNOTSUPP.Test to ensure that kernel handles resizing with
sparse_super2correctly. Run resize for multiple iterations because this sometimes leads to kernel crash due to fs corruption, which we want to detect.Related commit in mainline:
[1] commit
b1489186cc8391e0c1e342f9fbc3eedf6b944c61ext4: add check to prevent attempting to resize an fs with
sparse_super2Signed-off-by Ojaswin Mujoo <[email protected]>---
I would like to add a few comments on the approach followed in this test:
1. So although we check the return codes of the resize operation for proper logging, the test is only considered to be passed if fsck passes after the resize. This is because resizing a patched kernel always keeps the fs consistent whereas resizing on unpatched kernel always corrupts the fs.
2. I've noticed that running mkfs + resize multiple times on unpatched kernel sometimes results in KASAN reporting use-after-free. Hence, if we detect the kernel is unpatched (doesn't return EOPNOTSUPP on resize) we continue iterating to capture this. In this case, we don't run fsck in each iteration but run it only after all iterations are complete because
_check_scratch_fsexits the test if it fails.3. In case we detect patched kernel, we stop iterating, and run fsck to confirm success
tests/ext4/056 | 108 +++++++++++++++++++++++++++++++++++++++++++++ tests/ext4/056.out | 2 + 2 files changed, 110 insertions(+) create mode 100755 tests/ext4/056 create mode 100644 tests/ext4/056.outtests/ext4/056 new file +85
-0@@ -0,0 +1,108 @@ +#! /bin/bash +# SPDX-License-Identifier: GPL-2.0 +# Copyright (c) 2022 IBM. All Rights Reserved. +# +# We don't currently support resize of EXT4 filesystems mounted +# with sparse_super2 option enabled. Earlier, kernel used to leave the resize +# incomplete and the fs would be left into an incomplete state, however commit +# b1489186cc83[1] fixed this to avoid the fs corruption by clearly returning +# -ENOTSUPP. +# +# This test ensures that kernel handles resizing with sparse_super2 correctly +# +# Related commit in mainline: +# +# [1] commit b1489186cc8391e0c1e342f9fbc3eedf6b944c61 +# ext4: add check to prevent attempting to resize an fs with sparse_super2 +# + +. ./common/preamble +_begin_fstest auto ioctl resize quick + +# real QA test starts here + +INITIAL_FS_SIZE=1G +RESIZED_FS_SIZE=$((2*1024*1024*1024)) # 2G +ONLINE_RESIZE_BLOCK_LIMIT=$((256*1024*1024)) + +STOP_ITER=255 # Arbitrary return code + +_supported_fs ext4 +_require_scratch_size $(($RESIZED_FS_SIZE/1024)) +_require_test_program "ext4_resize" + +log() +{ + echo "$seq: $*" >> $seqres.full 2>&1 +} + +do_resize() +{ + _mkfs_dev -E resize=$ONLINE_RESIZE_BLOCK_LIMIT -O sparse_super2 \ + $SCRATCH_DEV $INITIAL_FS_SIZE >> $seqres.full 2>&1 \ + || _fail "$MKFS_PROG failed. Exiting" + + _scratch_mount || _fail "Failed to mount scratch partition. Exiting" + + local BS=$(_get_block_size $SCRATCH_MNT) + local REQUIRED_BLOCKS=$(($RESIZED_FS_SIZE/$BS)) + + local RESIZE_RET + local EOPNOTSUPP=95 + + log "Resizing FS" + $here/src/ext4_resize $SCRATCH_MNT $REQUIRED_BLOCKS >> $seqres.full 2>&1 + RESIZE_RET=$? + + # Test appears to be successful. Stop iterating and confirm if FS is + # consistent. + if [ $RESIZE_RET = $EOPNOTSUPP ] + then + log "Resize operation not supported with sparse_super2" + log "Threw expected error $RESIZE_RET (EOPNOTSUPP)" + return $STOP_ITER + fi + + # Test appears to be unsuccessful. Most probably, the fs is corrupt, + # iterate a few more times to further stress test this. + log "Something is wrong. Output of resize = $RESIZE_RET. \ + Expected $EOPNOTSUPP (EOPNOTSUPP)" + + # unmount after ioctl sometimes fails with "device busy" so add a small + # delay + sleep 0.2 + _scratch_unmount >> $seqres.full 2>&1 \ + || _fail "$UMOUNT_PROG failed. Exiting" +} + +run_test() +{ + local FSCK_RET + local ITERS=8 + local RET=0 + + for i in $(seq 1 $ITERS) + dotests/ext4/056 line 95
Quoted 10 lines
tests/ext4/056 new file +10
-0+ log "----------- Iteration: $i ------------" + do_resize + RET=$? + + [ "$RET" = "$STOP_ITER" ] && break + done + + log "-------- Iterations Complete ---------" + log "Checking if FS is in consistent state" + _check_scratch_fs
_check_scratch_fswill exit the test on failure and print error message, which will break the golden image, so there's no need to check fsck ret.tests/ext4/056 line 101
Quoted 6 lines
tests/ext4/056 new file +6
-0+ FSCK_RET=$? + + [ "$FSCK_RET" -ne "0" ] && \ + echo "fs corrupt. Check $seqres.full for more details" + + return $FSCK_RETSo I removed above hunk on commit.
Quoted 1 line
Thanks for the test! And my apology to the HUGE delay on review..
No worries Eryu, thanks a lot for the review :)
Regards,
Ojaswin
Quoted 21 lines
Thanks,
EryuQuoted 17 lines
tests/ext4/056 new file +7
-0+} + +echo "Silence is golden" +run_test +status=$? + +exittests/ext4/056.out new file +2
-0@@ -0,0 +1,2 @@ +QA output created by 056 +Silence is goldenSignature · 1 line
2.27.0
Greetings,
Just a gentle reminder to kindly let me know if any changes are needed in this patchset.
Thank you,
Ojaswin
Quoted 39 lines · Ojaswin Mujoo
As detailed in the patch [1], kernel currently does not support resizes with
sparse_super2enabled. Before the above patch, if we used theEXT4_IOC_RESIZE_FSioctl directly, wihtsparse_super2enabled, the kernel used to still try the resize and ultimatley leave the fs in an inconsistent state. This also led to corruption and kernel BUGs.This patchset adds a test for ext4 to ensure that the kernel handles resizes with
sparse_super2correctly, and returns-EOPNOTSUPP.Summary:
Patch 1: Fix the
src/ext4_resize.cscript to return accurate error
codes.
Patch 2: Add the ext4 test for checking resize functionalityChanges since v1 [2]
* In patch 2, don't iterate if the expected errno is returned
* Code cleanup and additional comments for clarity (also see extra note in patch 2)
* No changes in patch 1[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b1489186cc8391e0c1e342f9fbc3eedf6b944c61
[2] https://lore.kernel.org/fstests/[email protected]/Ojaswin Mujoo (2):
src/ext4_resize.c: Refactor code and ensure accurate errno is returned
ext4: Test to ensure resize withsparse_super2is handled correctlysrc/ext4_resize.c | 46 +++++++++++++------ tests/ext4/056 | 108 +++++++++++++++++++++++++++++++++++++++++++++ tests/ext4/056.out | 2 + 3 files changed, 142 insertions(+), 14 deletions(-) create mode 100755 tests/ext4/056 create mode 100644 tests/ext4/056.outSignature · 1 line
2.27.0