[LTP] [PATCH] syscalls/statx13: Add basic test for STATX_WRITE_ATOMIC on regular file

gpathak gpathak@suse.de
Fri Sep 18 13:04:02 CEST 2026


On 2026-09-17 14:19, Petr Vorel wrote:
> Hi Gaurav,
> 
> nit: this is a second version of the patch, it'd help to distinguish 
> them if you
> generate it with git format-patch -v2. It's also mentioned (as "-v 2") 
> in our
> tutorial:
> 
> https://linux-test-project.readthedocs.io/en/latest/developers/test_case_tutorial.html
> 
> (Tutorial is slightly outdated both code and instructions but still 
> more or less
> valid. It should be structured and improved but I still recommend you 
> to read it
> to get various ideas not covered elsewhere).
> 
> Also this second patch failed to build in CI. Could you please enable 
> CI in your
> LTP fork and push the branch before sending? You 1) get results quicker 
> 2) saves
> our time to look on something which is broken.
> 
>> This patch adds a new test to validate these atomic write limit 
>> fields.
>> The test ensures the filesystem correctly advertises the 
>> STATX_ATTR_WRITE_ATOMIC
>> attribute when queried on a file opened with O_DIRECT. It also 
>> verifies that the
>> reported optimized maximum is logically consistent by falling within 
>> the
>> absolute minimum and maximum boundaries. Furthermore, it checks that 
>> all
>> reported atomic write unit sizes are valid powers of two, adhering to 
>> the strict
>> requirements of the kernel block layer.
> 
>> If the underlying storage hardware or filesystem lacks atomic write
>> support, the test gracefully skips with TCONF.
> 
>> Fixes: #1224
> 
>> Signed-off-by: Gaurav Pathak <gaurav.pathak@suse.com>
>> ---
>>  configure.ac                               |   2 +-
>>  testcases/kernel/syscalls/statx/.gitignore |   1 +
>>  testcases/kernel/syscalls/statx/statx13.c  | 130 
>> +++++++++++++++++++++
>>  3 files changed, 132 insertions(+), 1 deletion(-)
> 
> Please go over agent reports (it asked for runtest/syscalls already in 
> the first patch).
> ...
>> index 000000000..ea42a102c
>> --- /dev/null
>> +++ b/testcases/kernel/syscalls/statx/statx13.c
>> @@ -0,0 +1,130 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +/*
>> + * Copyright (c) 2026 SUSE LLC <gaurav.pathak@suse.com>
>> + */
>> +
>> +/*\
>> + * This test validates the STATX_WRITE_ATOMIC feature (introduced in 
>> Linux 6.13).
>> + * It ensures that supported filesystems (xfs as of now) correctly 
>> report their
> git grep generic_atomic_write_valid (functions mentioned at [1] which 
> was
> mentioned in the "block atomic writes" feature [2]) mentions also ext4. 
> And you
> also test both xfs and ext4, you should either update filesystem list 
> in docs or
> not mention filesystems at all.
> 
> [1] 
> https://lore.kernel.org/linux-xfs/20240607143919.2622319-1-john.g.garry@oracle.com/T/#t
> [2] 
> https://lore.kernel.org/lkml/20240620125359.2684798-1-john.g.garry@oracle.com/
> 
>> + * atomic write limits to user space when queried via statx().
>> + *
>> + * The test performs the following validations:
> nit: there needs to be a blank line otherwise list will not be 
> formatted
> 
> => we should teach agent to recognise it
> 
>> + * - Creates a test file using O_DIRECT (a prerequisite for atomic 
>> writes).
>> + * - Calls statx() with the STATX_WRITE_ATOMIC mask to retrieve the 
>> limits.
>> + * - Verifies that stx_atomic_write_unit_min, 
>> stx_atomic_write_unit_max, and
>> + *    stx_atomic_write_unit_max_opt are logically consistent (e.g., 
>> max_opt is
> And this extra space before stx_atomic_write_unit_max_opt make is 
> formatted as
> bold (see later doc build)
> 
>> + *    within the min and max bounds).
>> + * - Ensures all reported atomic write unit sizes are valid powers of 
>> two.
>> + */
>> +
>> +#define _GNU_SOURCE
>> +#include <sys/param.h>
>> +#include "tst_test.h"
>> +
>> +#define MNTPOINT "mnt_point"
>> +#define TESTFILE MNTPOINT"/testfile"
> 
> nit style check complains, you'll find it with:
> $ make check-statx13
> ...
> CHECK testcases/kernel/syscalls/statx/statx13.c
> statx13.c:25: CHECK: Concatenated strings should use spaces between 
> elements
> 
> 
>> +#define MODE 0644
>> +
>> +#define WRITE_SIZE 4096
>> +#define ALIGNMENT  4096
>> +
>> +static int file_fd = -1;
>> +
>> +static void verify_statx(void)
>> +{
>> +	struct statx buff;
>> +
>> +	TST_EXP_PASS_SILENT(statx(AT_FDCWD, TESTFILE, 0, STATX_BASIC_STATS | 
>> STATX_WRITE_ATOMIC, &buff),
>> +			"statx(AT_FDCWD, %s, 0, STATX_WRITE_ATOMIC, &buf)", TESTFILE);
>> +
>> +	if (!(buff.stx_attributes & STATX_ATTR_WRITE_ATOMIC)) {
>> +		tst_res(TCONF, "Filesystem does not support STATX_WRITE_ATOMIC");
>> +		return;
> 
> This is enough (without following return).
> 		tst_brk(TCONF, "Filesystem does not support STATX_WRITE_ATOMIC");
>> +	}
>> +
>> +	if (buff.stx_atomic_write_unit_min > 0 &&
>> +			__builtin_popcount(buff.stx_atomic_write_unit_min) == 1)
>> +		tst_res(TPASS, "stx_atomic_write_unit_min(%u) is power of 2",
>> +				buff.stx_atomic_write_unit_min);
>> +	else
>> +		tst_res(TFAIL, "stx_atomic_write_unit_min(%u) is not a power of 2",
>> +				buff.stx_atomic_write_unit_min);
>> +
>> +	if (buff.stx_atomic_write_unit_max > 0 &&
>> +			__builtin_popcount(buff.stx_atomic_write_unit_max) == 1)
>> +		tst_res(TPASS, "stx_atomic_write_unit_max(%u) is power of 2",
>> +				buff.stx_atomic_write_unit_max);
>> +	else
>> +		tst_res(TFAIL, "stx_atomic_write_unit_max(%u) is not a power of 2",
>> +				buff.stx_atomic_write_unit_max);
>> +
>> +#ifdef HAVE_STRUCT_STATX_STX_ATOMIC_WRITE_UNIT_MAX_OPT
>> +	if (buff.stx_atomic_write_unit_max_opt == 0) {
>> +		tst_res(TINFO, "stx_atomic_write_unit_max_opt is 0 (no optimized 
>> max reported)");
> Shouldn't this be TPASS?
> 
>> +	} else {
>> +		if (buff.stx_atomic_write_unit_max_opt > 
>> buff.stx_atomic_write_unit_max)
>> +			tst_res(TFAIL, "stx_atomic_write_unit_max_opt (%u) exceeds max 
>> (%u)",
>> +					buff.stx_atomic_write_unit_max_opt,
>> +					buff.stx_atomic_write_unit_max);
>> +
>> +		else if (buff.stx_atomic_write_unit_max_opt < 
>> buff.stx_atomic_write_unit_min)
>> +			tst_res(TFAIL, "stx_atomic_write_unit_max_opt (%u) is less than 
>> min (%u)",
>> +					buff.stx_atomic_write_unit_max_opt,
>> +					buff.stx_atomic_write_unit_min);
>> +		else
>> +			tst_res(TPASS, "stx_atomic_write_unit_max_opt (%u) is within valid 
>> range [%u, %u]",
>> +					buff.stx_atomic_write_unit_max_opt,
>> +					buff.stx_atomic_write_unit_min,
>> +					buff.stx_atomic_write_unit_max);
>> +
>> +		if (__builtin_popcount(buff.stx_atomic_write_unit_max_opt) != 1)
>> +			tst_res(TFAIL, "stx_atomic_write_unit_max_opt (%u) is not a power 
>> of 2",
>> +					buff.stx_atomic_write_unit_max_opt);
>> +	}
>> +#else
>> +	tst_res(TCONF, "stx_atomic_write_unit_max_opt is not defined in 
>> struct statx");
>> +#endif
>> +}
>> +
>> +static void setup(void)
>> +{
>> +	char *data_buff = SAFE_MEMALIGN(ALIGNMENT, WRITE_SIZE);
>> +
>> +	if (strcmp(tst_device->fs_type, "xfs") && 
>> strcmp(tst_device->fs_type, "ext4"))
>> +		tst_brk(TCONF, "This test only supports ext4 and xfs");
> FYI .filesystems member in struct tst_test test select filesystems, you 
> don't
> need to check here. Please remove it.
> 
> => we should teach agent to detect this.
> 
>> +
>> +	umask(0);
>> +	memset(data_buff, '@', WRITE_SIZE);
>> +
>> +	file_fd =  SAFE_OPEN(TESTFILE, O_RDWR | O_CREAT | O_DIRECT, MODE);
>> +	SAFE_WRITE(SAFE_WRITE_ALL, file_fd, data_buff, WRITE_SIZE);
>> +}
>> +
>> +static void cleanup(void)
>> +{
>> +	if (file_fd > -1)
>> +		SAFE_CLOSE(file_fd);
>> +}
>> +
>> +static struct tst_test test = {
>> +	.test_all = verify_statx,
>> +	.setup = setup,
>> +	.cleanup = cleanup,
>> +	.min_kver = "6.13",
>> +	.needs_root = 1,
>> +	.needs_device = 1,
>> +	.needs_tmpdir = 1,
> nit: Some tags aren't needed and will be later deleted. You can see it:
> 
> $ cd metadata/; make
> /home/pvorel/install/src/ltp.git/metadata/parse.sh > ltp.json
> testcases/kernel/syscalls/statx/statx13.c: useless tag: needs_device
> testcases/kernel/syscalls/statx/statx13.c: useless tag: needs_tmpdir
> 
> Or you could see it at doc build (but that usually requires python 
> virtualenv
> and it's slower, OTOH you can check how the doc will look like)
> 
> $ cd doc; make setup && make
> => see the docs in thml file:
> doc/html/users/test_catalog.html#statx13
> 
>> +	.mntpoint = MNTPOINT,
>> +	.mount_device = 1,
>> +	.filesystems = (struct tst_fs[]) {
>> +		{
>> +			.type = "xfs",
>> +			.mkfs_opts = (const char *const []){"-f", "-bsize=16K", NULL},
>> +		},
>> +		{
>> +			.type = "ext4",
>> +			.mkfs_opts = (const char *const []){"-O", "bigalloc", "-b", 
>> "4096", "-C", "65536", NULL},
> BTW my 7.2.0-4.g080d79d-default still TCONF on ext4. Maybe wrong 
> params?
>> +		},
>> +		{}
>> +	},
>> +};

Hello Petr,
Thanks a lot for reviewing the patch and providing useful pointers.
I am able to fix almost all of the issues reviewed by you and reported 
by automation agent.

>>> +			.type = "ext4",
>>> +			.mkfs_opts = (const char *const []){"-O", "bigalloc", "-b", 
>>> "4096", "-C", "65536", NULL},
>> BTW my 7.2.0-4.g080d79d-default still TCONF on ext4. Maybe wrong 
>> params?

However, for ext4 filesystem case, I used scsi_debug kernel module to 
emulate the behavior of allowing 16K write operation using O_DIRECT flag 
which is bigger than the PAGESIZE of 4096. On my system and some other 
machines on which I ran this test, ext4 is not allowing me to cross 
PAGESIZE boundary, maybe because the kernel running on those machines is 
compiled with 4K PAGESIZE. I believe this is also the same in your case. 
Maybe we need to test this on a kernel having PAGESIZE greater than 
4096.


More information about the ltp mailing list