[LTP] [PATCH v2 2/2] syscalls/ioctl_loop05: Using LOOP_CONFIGURE to set direct io
Yang Xu
xuyang2018.jy@cn.fujitsu.com
Thu Jul 30 09:28:58 CEST 2020
Hi Martijn
CC block kernel guys
I have a question when using loop_configure ioctl to set direct io flag.
In ltp testcase ioctl_loop05, I modify this case as the follow (Using
loop_configure ioctl to set direct io mode with different
logical_block_size). But sometimes I met a problem that loop_configure
ioctl succeed but the flag doesn't take effect.
the test (need to merge this patch[1] and remove sleep)
ioctl_loop05.c:132: INFO: Using LOOP_SET_DIRECT_IO with offset less than
logical_block_size
ioctl_loop05.c:84: PASS: In non dio mode, lo_flags doesn't have
LO_FLAGS_DIRECT_IO flag
ioctl_loop05.c:86: PASS: /sys/block/loop0/loop/dio = 0
ioctl_loop05.c:106: PASS: set direct io failed as expected: EINVAL (22)
ioctl_loop05.c:132: INFO: Using LOOP_CONFIGURE without setting lo_offset
or sizelimit
ioctl_loop05.c:80: PASS: In dio mode, lo_flags has LO_FLAGS_DIRECT_IO flag
ioctl_loop05.c:86: PASS: /sys/block/loop0/loop/dio = 1
ioctl_loop05.c:132: INFO: Using LOOP_CONFIGURE With offset equal to
logical_block_size
ioctl_loop05.c:80: PASS: In dio mode, lo_flags has LO_FLAGS_DIRECT_IO flag
ioctl_loop05.c:86: PASS: /sys/block/loop0/loop/dio = 1
ioctl_loop05.c:132: INFO: Using LOOP_CONFIGURE witg offset less than
logical_block_size
ioctl_loop05.c:80: FAIL: In non dio mode, lo_flags has
LO_FLAGS_DIRECT_IO flag
ioctl_loop05.c:86: FAIL: /sys/block/loop0/loop/dio != 0 got 1
Summary:
passed 17
failed 2
skipped 0
warnings 0
dmesg
[75103.201861] loop_set_status: loop0 () has still dirty pages (nrpages=3)
[75103.321850] blk_update_request: I/O error, dev loop0, sector 2047 op
0x0:(READ) flags 0x80700 phys_seg 1 prio class 0
[75103.337105] blk_update_request: I/O error, dev loop0, sector 2047 op
0x0:(READ) flags 0x0 phys_seg 1 prio class 0
[75103.337816] Buffer I/O error on dev loop0, logical block 255, async
page read
It seems that the last blk_update_request has not completed but the
subquent blk request (loop_configure ioctl with non zero size or logic
block size triggers) has started.So kernel has this warning.Is it right?
Is it a expected behaviour?
[1]https://patchwork.ozlabs.org/project/ltp/patch/1595556357-29932-2-git-send-email-xuyang2018.jy@cn.fujitsu.com/
Best Regards
Yang Xu
> Since kernel commit 3448914e8cc5("loop: Add LOOP_CONFIGURE ioctl"),
> it can explicitly request direct I/O mode by setting LO_FLAGS_DIRECT_IO
> in loop_config.info.lo_flags.
>
> Signed-off-by: Yang Xu <xuyang2018.jy@cn.fujitsu.com>
> ---
> .../kernel/syscalls/ioctl/ioctl_loop05.c | 154 +++++++++++++-----
> 1 file changed, 117 insertions(+), 37 deletions(-)
>
> diff --git a/testcases/kernel/syscalls/ioctl/ioctl_loop05.c b/testcases/kernel/syscalls/ioctl/ioctl_loop05.c
> index e3c14faab..6abb27998 100644
> --- a/testcases/kernel/syscalls/ioctl/ioctl_loop05.c
> +++ b/testcases/kernel/syscalls/ioctl/ioctl_loop05.c
> @@ -19,6 +19,9 @@
> * enabled but falls back to buffered I/O later on. This is the case at least
> * for Btrfs. Because of that the test passes both with failure as well as
> * success with non-zero offset.
> + *
> + * Also use LOOP_CONFIGURE to test this by setting LO_FLAGS_DIRECT_IO
> + * in loop_config.info.lo_flags.
> */
>
> #include <stdio.h>
> @@ -32,8 +35,36 @@
> #define DIO_MESSAGE "In dio mode"
> #define NON_DIO_MESSAGE "In non dio mode"
>
> -static char dev_path[1024], sys_loop_diopath[1024], backing_file_path[1024];;
> +static char dev_path[1024], sys_loop_diopath[1024], backing_file_path[1024];
> static int dev_num, dev_fd, block_devfd, attach_flag, logical_block_size;
> +static int file_fd, loop_configure_sup = 1;
> +static struct loop_config loopconfig;
> +static struct loop_info loopinfo;
> +
> +static struct tcase {
> + int multi; /*logical_block_size / 2 as unit */
> + int dio_value;
> + int ioctl_flag;
> + char *message;
> +} tcases[] = {
> + {0, 1, LOOP_SET_DIRECT_IO,
> + "Using LOOP_SET_DIRET_IO without setting lo_offset or sizelimit"},
> +
> + {2, 1, LOOP_SET_DIRECT_IO,
> + "Using LOOP_SET_DIRECT_IO With offset equal to logical_block_size"},
> +
> + {1, 0, LOOP_SET_DIRECT_IO,
> + "Using LOOP_SET_DIRECT_IO with offset less than logical_block_size"},
> +
> + {0, 1, LOOP_CONFIGURE,
> + "Using LOOP_CONFIGURE without setting lo_offset or sizelimit"},
> +
> + {2, 1, LOOP_CONFIGURE,
> + "Using LOOP_CONFIGURE With offset equal to logical_block_size"},
> +
> + {1, 0, LOOP_CONFIGURE,
> + "Using LOOP_CONFIGURE witg offset less than logical_block_size"},
> +};
>
> static void check_dio_value(int flag)
> {
> @@ -42,61 +73,94 @@ static void check_dio_value(int flag)
> memset(&loopinfoget, 0, sizeof(loopinfoget));
>
> SAFE_IOCTL(dev_fd, LOOP_GET_STATUS, &loopinfoget);
> - tst_res(TINFO, "%s", flag ? DIO_MESSAGE : NON_DIO_MESSAGE);
>
> if (loopinfoget.lo_flags & LO_FLAGS_DIRECT_IO)
> - tst_res(flag ? TPASS : TFAIL, "lo_flags has LO_FLAGS_DIRECT_IO flag");
> + tst_res(flag ? TPASS : TFAIL,
> + "%s, lo_flags has LO_FLAGS_DIRECT_IO flag",
> + flag ? DIO_MESSAGE : NON_DIO_MESSAGE);
> else
> - tst_res(flag ? TFAIL : TPASS, "lo_flags doesn't have LO_FLAGS_DIRECT_IO flag");
> + tst_res(flag ? TFAIL : TPASS,
> + "%s, lo_flags doesn't have LO_FLAGS_DIRECT_IO flag",
> + flag ? DIO_MESSAGE : NON_DIO_MESSAGE);
>
> TST_ASSERT_INT(sys_loop_diopath, flag);
> }
>
> -static void verify_ioctl_loop(void)
> +static void verify_ioctl_loop(unsigned int n)
> {
> - struct loop_info loopinfo;
> -
> - memset(&loopinfo, 0, sizeof(loopinfo));
> - TST_RETRY_FUNC(ioctl(dev_fd, LOOP_SET_STATUS, &loopinfo), TST_RETVAL_EQ0);
> + if (tcases[n].ioctl_flag == LOOP_SET_DIRECT_IO) {
> + TST_RETRY_FUNC(ioctl(dev_fd, LOOP_SET_STATUS, &loopinfo), TST_RETVAL_EQ0);
> +
> + TEST(ioctl(dev_fd, LOOP_SET_DIRECT_IO, 1));
> + if (TST_RET == 0) {
> + if (tcases[n].dio_value)
> + tst_res(TPASS, "set direct io succeeded");
> + else
> + tst_res(TPASS, "set direct io succeeded, offset is ignored");
> + check_dio_value(1);
> + SAFE_IOCTL(dev_fd, LOOP_SET_DIRECT_IO, 0);
> + return;
> + }
> + if (TST_ERR == EINVAL && !tcases[n].dio_value)
> + tst_res(TPASS | TTERRNO,
> + "set direct io failed as expected");
> + else
> + tst_res(TFAIL | TTERRNO, "set direct io failed");
> + return;
> + }
> + /*
> + * When we call loop_configure ioctl successfully and detach it,
> + * the subquent loop_configure without non-zero lo_offset or
> + * sizelimit may trigger the blk_update_request I/O error.
> + * To avoid this, sleep 1s to ensure last blk_update_request has
> + * completed.
> + */
> + sleep(1);
> + /*
> + * loop_cofigure calls loop_update_dio() function, it will ignore
> + * the result of setting dio. It is different from loop_set_dio.
> + */
> + TST_RETRY_FUNC(ioctl(dev_fd, LOOP_CONFIGURE, &loopconfig), TST_RETVAL_EQ0);
> + check_dio_value(tcases[n].dio_value);
> + TST_RETRY_FUNC(ioctl(dev_fd, LOOP_CLR_FD, 0), TST_RETVAL_EQ0);
> +}
>
> - tst_res(TINFO, "Without setting lo_offset or sizelimit");
> - SAFE_IOCTL(dev_fd, LOOP_SET_DIRECT_IO, 1);
> - check_dio_value(1);
> +static void run(unsigned int n)
> +{
> + struct tcase *tc = &tcases[n];
>
> - SAFE_IOCTL(dev_fd, LOOP_SET_DIRECT_IO, 0);
> - check_dio_value(0);
> + tst_res(TINFO, "%s", tc->message);
>
> - tst_res(TINFO, "With offset equal to logical_block_size");
> - loopinfo.lo_offset = logical_block_size;
> - TST_RETRY_FUNC(ioctl(dev_fd, LOOP_SET_STATUS, &loopinfo), TST_RETVAL_EQ0);
> - TEST(ioctl(dev_fd, LOOP_SET_DIRECT_IO, 1));
> - if (TST_RET == 0) {
> - tst_res(TPASS, "LOOP_SET_DIRECT_IO succeeded");
> - check_dio_value(1);
> + if (tc->ioctl_flag == LOOP_SET_DIRECT_IO) {
> + if (!attach_flag) {
> + tst_attach_device(dev_path, "test.img");
> + attach_flag = 1;
> + }
> SAFE_IOCTL(dev_fd, LOOP_SET_DIRECT_IO, 0);
> - } else {
> - tst_res(TFAIL | TTERRNO, "LOOP_SET_DIRECT_IO failed");
> + check_dio_value(0);
> + loopinfo.lo_offset = logical_block_size * tc->multi / 2;
> + verify_ioctl_loop(n);
> + return;
> }
> -
> - tst_res(TINFO, "With nonzero offset less than logical_block_size");
> - loopinfo.lo_offset = logical_block_size / 2;
> - TST_RETRY_FUNC(ioctl(dev_fd, LOOP_SET_STATUS, &loopinfo), TST_RETVAL_EQ0);
> -
> - TEST(ioctl(dev_fd, LOOP_SET_DIRECT_IO, 1));
> - if (TST_RET == 0) {
> - tst_res(TPASS, "LOOP_SET_DIRECT_IO succeeded, offset is ignored");
> - SAFE_IOCTL(dev_fd, LOOP_SET_DIRECT_IO, 0);
> + if (tc->ioctl_flag == LOOP_CONFIGURE && !loop_configure_sup) {
> + tst_res(TCONF, "LOOP_CONFIGURE ioctl not supported");
> return;
> }
> - if (TST_ERR == EINVAL)
> - tst_res(TPASS | TTERRNO, "LOOP_SET_DIRECT_IO failed as expected");
> - else
> - tst_res(TFAIL | TTERRNO, "LOOP_SET_DIRECT_IO failed expected EINVAL got");
> + if (attach_flag) {
> + SAFE_CLOSE(dev_fd);
> + tst_detach_device(dev_path);
> + attach_flag = 0;
> + }
> + if (dev_fd < 0)
> + dev_fd = SAFE_OPEN(dev_path, O_RDWR);
> + loopconfig.info.lo_offset = logical_block_size * tc->multi / 2;
> + verify_ioctl_loop(n);
> }
>
> static void setup(void)
> {
> char bd_path[100];
> + int ret;
>
> if (tst_fs_type(".") == TST_TMPFS_MAGIC)
> tst_brk(TCONF, "tmpfd doesn't support O_DIRECT flag");
> @@ -128,8 +192,21 @@ static void setup(void)
> SAFE_IOCTL(block_devfd, BLKSSZGET, &logical_block_size);
> tst_res(TINFO, "backing dev(%s) logical_block_size is %d", bd_path, logical_block_size);
> SAFE_CLOSE(block_devfd);
> +
> if (logical_block_size > 512)
> TST_RETRY_FUNC(ioctl(dev_fd, LOOP_SET_BLOCK_SIZE, logical_block_size), TST_RETVAL_EQ0);
> +
> + file_fd = SAFE_OPEN("test.img", O_RDWR);
> + loopconfig.fd = -1;
> + ret = ioctl(dev_fd, LOOP_CONFIGURE, &loopconfig);
> + if (ret && errno != EBADF) {
> + tst_res(TINFO | TERRNO, "LOOP_CONFIGURE is not supported");
> + loop_configure_sup = 0;
> + return;
> + }
> + loopconfig.block_size = logical_block_size;
> + loopconfig.fd = file_fd;
> + loopconfig.info.lo_flags = LO_FLAGS_DIRECT_IO;
> }
>
> static void cleanup(void)
> @@ -138,6 +215,8 @@ static void cleanup(void)
> SAFE_CLOSE(dev_fd);
> if (block_devfd > 0)
> SAFE_CLOSE(block_devfd);
> + if (file_fd > 0)
> + SAFE_CLOSE(file_fd);
> if (attach_flag)
> tst_detach_device(dev_path);
> }
> @@ -145,7 +224,8 @@ static void cleanup(void)
> static struct tst_test test = {
> .setup = setup,
> .cleanup = cleanup,
> - .test_all = verify_ioctl_loop,
> + .test = run,
> + .tcnt = ARRAY_SIZE(tcases),
> .needs_root = 1,
> .needs_tmpdir = 1,
> .needs_drivers = (const char *const []) {
>
More information about the ltp
mailing list