Re: [PATCH v9] fsconfig04: Check FSCONFIG_SET_PATH

Andrea Cervesato via ltp <[email protected]>
Newsgroups gmane.linux.ltp
Message-ID <[email protected]>
Hi Wei,

> The fsconfig01.c does not test if FSCONFIG_SET_PATH has any effect;
> most of the calls there just set a dummy "sync" parameter. This test
> case aims to verify if the FSCONFIG_SET_PATH operation can be used
> to dynamically change the external journal device of an ext3 or ext4
> filesystem.
> 
> Closes: https://github.com/linux-test-project/ltp/issues/1169
> Signed-off-by: Wei Gao <wegao-IBi9RG/[email protected]>
> ---
> v8->v9:
> - Drop braces for single-statement inner branches
> 
>  runtest/syscalls                              |   1 +
>  testcases/kernel/syscalls/fsconfig/.gitignore |   1 +
>  .../kernel/syscalls/fsconfig/fsconfig04.c     | 180 ++++++++++++++++++
>  3 files changed, 182 insertions(+)
>  create mode 100644 testcases/kernel/syscalls/fsconfig/fsconfig04.c
> 
> diff --git a/runtest/syscalls b/runtest/syscalls
> index a021c79da..a7a9cf638 100644
> --- a/runtest/syscalls
> +++ b/runtest/syscalls
> @@ -422,6 +422,7 @@ fremovexattr02 fremovexattr02
>  fsconfig01 fsconfig01
>  fsconfig02 fsconfig02
>  fsconfig03 fsconfig03
> +fsconfig04 fsconfig04
>  
>  fsmount01 fsmount01
>  fsmount02 fsmount02
> diff --git a/testcases/kernel/syscalls/fsconfig/.gitignore b/testcases/kernel/syscalls/fsconfig/.gitignore
> index cfedae5f7..bd3754c34 100644
> --- a/testcases/kernel/syscalls/fsconfig/.gitignore
> +++ b/testcases/kernel/syscalls/fsconfig/.gitignore
> @@ -1,3 +1,4 @@
>  /fsconfig01
>  /fsconfig02
>  /fsconfig03
> +/fsconfig04
> diff --git a/testcases/kernel/syscalls/fsconfig/fsconfig04.c b/testcases/kernel/syscalls/fsconfig/fsconfig04.c
> new file mode 100644
> index 000000000..ce6c8fd01
> --- /dev/null
> +++ b/testcases/kernel/syscalls/fsconfig/fsconfig04.c
> @@ -0,0 +1,180 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2026 Wei Gao <wegao-IBi9RG/[email protected]>
> + */
> +
> +/*\
> + * This test aims to validate :manpage:`fsconfig(2)` with the
> + * FSCONFIG_SET_PATH operation in dynamically altering the external
> + * journal device of an ext3 or ext4 filesystem. Case acquires three
> + * loop devices (dev0, dev1, dev2), it formats dev1 and dev2 as
> + * external journal devices using the -O journal_dev option and assigns
> + * them the same UUID. Then formats dev0 (the main filesystem) multiple
> + * times, first associating it with dev1, then change to dev2, finally
> + * back to dev1 again as an external journal using the -J device= option.

This is not a description but the Description + Algorithm section. Please
split them so we understand what the test aims for + algorithm that is used.

> + *
> + * 2 Implementation notes in this case need mention:
> + *
> + * - To avoid "journal UUID does not match" error when switch external journal device
> + *   we have to assign same UUID to dev1/dev2
> + * - Before fsconfig test we have to format dev0 associating to dev1->dev2->dev1,
> + *   this will make sure both dev1/2's super block contain correct content. Otherwise
> + *   you will encounter error such as "EXT4-fs (loop0): External journal has more than
> + *   one user (unsupported) - 0" when switch external journal device using fsconfig.
> + */
> +
> +#include "tst_test.h"
> +#include "tst_safe_stdio.h"
> +#include "lapi/fsmount.h"
> +
> +#define MNTPOINT	"mntpoint"
> +#define LOOP_DEV_SIZE 10
> +#define UUID "d73c9e5e-97e4-4a9c-b17e-75a931b02660"
> +
> +static int fd = -1;
> +static char dev0[PATH_MAX];
> +static char dev1[PATH_MAX];
> +static char dev2[PATH_MAX];
> +
> +static void cleanup(void)
> +{
> +	if (fd != -1)
> +		SAFE_CLOSE(fd);
> +
> +	if (dev1[0])
> +		tst_detach_device(dev1);
> +
> +	if (dev2[0])
> +		tst_detach_device(dev2);
> +}
> +
> +static void setup(void)
> +{
> +	fsopen_supported_by_kernel();
> +
> +	strcpy(dev0, tst_device->dev);
> +
> +	if (tst_prealloc_file("dev1_file", 1024 * 1024, LOOP_DEV_SIZE))
> +		tst_brk(TBROK, "Failed to create dev1_file");
> +
> +	if (tst_find_free_loopdev(dev1, sizeof(dev1)) == -1)
> +		tst_brk(TBROK, "No free loop device found for dev1");
> +
> +	if (tst_attach_device(dev1, "dev1_file"))
> +		tst_brk(TBROK, "Failed to attach dev1_file to %s", dev1);
> +
> +	if (tst_prealloc_file("dev2_file", 1024 * 1024, LOOP_DEV_SIZE))
> +		tst_brk(TBROK, "Failed to create dev2_file");
> +
> +	if (tst_find_free_loopdev(dev2, sizeof(dev2)) == -1)
> +		tst_brk(TBROK, "No free loop device found for dev2");
> +
> +	if (tst_attach_device(dev2, "dev2_file"))
> +		tst_brk(TBROK, "Failed to attach dev2_file to %s", dev2);

This code is duplicated. We should create a helper that prealloc
and attach the device.

> +
> +	const char *const *mkfs_opts_set_UUID;
> +	const char *const *mkfs_opts_set_journal_dev1;
> +	const char *const *mkfs_opts_set_journal_dev2;
> +
> +	mkfs_opts_set_UUID = (const char *const []) {"-F", "-U", UUID,
> +		"-O", "journal_dev", NULL};
> +
> +	char device_option_dev1[PATH_MAX];
> +	char device_option_dev2[PATH_MAX];
> +
> +	snprintf(device_option_dev1, sizeof(device_option_dev1), "device=%s", dev1);
> +	snprintf(device_option_dev2, sizeof(device_option_dev2), "device=%s", dev2);
> +
> +	mkfs_opts_set_journal_dev1 = (const char *const []) {"-F", "-J",
> +		device_option_dev1, NULL};
> +
> +	mkfs_opts_set_journal_dev2 = (const char *const []) {"-F", "-J",
> +		device_option_dev2, NULL};
> +
> +	SAFE_MKFS(dev1, tst_device->fs_type, mkfs_opts_set_UUID, NULL);
> +	SAFE_MKFS(dev2, tst_device->fs_type, mkfs_opts_set_UUID, NULL);
> +	SAFE_MKFS(dev0, tst_device->fs_type, mkfs_opts_set_journal_dev1, NULL);
> +	SAFE_MKFS(dev0, tst_device->fs_type, mkfs_opts_set_journal_dev2, NULL);
> +	SAFE_MKFS(dev0, tst_device->fs_type, mkfs_opts_set_journal_dev1, NULL);
> +}
> +
> +static void run(void)
> +{
> +	TEST(fd = fsopen(tst_device->fs_type, 0));
> +	if (fd == -1)
> +		tst_brk(TBROK | TTERRNO, "fsopen() failed");
> +
> +	TEST(fsconfig(fd, FSCONFIG_SET_STRING, "source", dev0, 0));
> +	if (TST_RET == -1)
> +		tst_brk(TBROK | TTERRNO, "fsconfig(FSCONFIG_SET_STRING) failed");
> +
> +	TEST(fsconfig(fd, FSCONFIG_SET_PATH, "journal_path", dev2, 0));
> +	if (TST_RET == -1) {
> +		if (TST_ERR == EOPNOTSUPP)
> +			tst_res(TCONF, "fsconfig(FSCONFIG_SET_PATH) not supported");
> +		else
> +			tst_res(TFAIL | TTERRNO, "fsconfig(FSCONFIG_SET_PATH) failed");
> +		SAFE_CLOSE(fd);
> +		return;
> +	}
> +
> +	TEST(fsconfig(fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0));
> +	if (TST_RET == -1) {
> +		tst_res(TFAIL | TTERRNO, "fsconfig(FSCONFIG_CMD_CREATE) failed");
> +		SAFE_CLOSE(fd);
> +		return;
> +	}
> +
> +	char loop_name[NAME_MAX];
> +	char path[PATH_MAX];
> +	char device_str[NAME_MAX];
> +	unsigned int major, minor, device_num;
> +	unsigned int found = 0;
> +
> +	SAFE_SSCANF(dev2, "/dev/%s", loop_name);
> +
> +	snprintf(path, sizeof(path), "/sys/block/%s/dev", loop_name);
> +	SAFE_FILE_SCANF(path, "%u:%u", &major, &minor);
> +	device_num = (minor & 0xff) | (major << 8) | ((minor & ~0xff) << 12);
> +	snprintf(device_str, sizeof(device_str), "0x%04x", device_num);
> +
> +	char line[PATH_MAX];
> +	FILE *tune2fs;
> +
> +	snprintf(path, sizeof(path), "tune2fs -l %s 2>&1", dev0);
> +	tune2fs = SAFE_POPEN(path, "r");
> +
> +	while (fgets(line, PATH_MAX, tune2fs)) {
> +		if (*line && strstr(line, "Journal device:") && strstr(line, device_str)) {
> +			found = 1;
> +			break;
> +		}
> +	}
> +
> +	if (found == 1)
> +		tst_res(TPASS, "Device found in journal");
> +	else
> +		tst_res(TFAIL, "Device not found in journal");
> +
> +	pclose(tune2fs);
> +	SAFE_CLOSE(fd);
> +}
> +
> +static struct tst_test test = {
> +	.test_all = run,
> +	.setup = setup,
> +	.cleanup = cleanup,
> +	.needs_root = 1,
> +	.needs_tmpdir = 1,
> +	.format_device = 1,

we already format the device manually.

> +	.mntpoint = MNTPOINT,
> +	.needs_cmds = (struct tst_cmd []) {
> +		{.cmd = "tune2fs"},
> +		{}
> +	},
> +	.filesystems = (struct tst_fs []) {
> +		{.type = "ext3"},
> +		{.type = "ext4"},
> +		{}
> +	},
> +};
> -- 
> 2.54.0
> 

--
Andrea Cervesato
SUSE QE Automation Engineer Linux
andrea.cervesato-IBi9RG/[email protected]

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.