[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