[LTP] [PATCH v3] Testing statx syscall

Cyril Hrubis chrubis@suse.cz
Wed Jul 25 14:38:51 CEST 2018


Hi!
> --- /dev/null
> +++ b/include/lapi/sys_statx.h
> @@ -0,0 +1,269 @@
> +// SPDX-License-Identifier: GPL-2.0 or later
> +/*
> + * Referred from linux kernel -github/torvalds/linux
> + * Copyright (c) Zilogic Systems Pvt. Ltd., 2018
> + * Email: code@zilogic.com
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +#ifndef STATX_H
> +#define STATX_H
> +
> +#include <stdint.h>
> +#include "lapi/syscalls.h"
> +
> +/*
> + * Timestamp structure for the timestamps in struct statx.
> + *
> + * tv_sec holds the number of seconds before (negative) or after (positive)
> + * 00:00:00 1st January 1970 UTC.
> + *
> + * tv_nsec holds a number of nanoseconds (0..999,999,999) after the tv_sec time.
> + *
> + * __reserved is held in case we need a yet finer resolution.
> + */
> +struct statx_timestamp {
> +	int64_t 	tv_sec;
> +	uint32_t	tv_nsec;
> +	int32_t __reserved;
> +};
> +
> +/*
> + * Structures for the extended file attribute retrieval system call
> + * (statx()).
> + *
> + * The caller passes a mask of what they're specifically interested in as a
> + * parameter to statx().  What statx() actually got will be indicated in
> + * st_mask upon return.
> + *
> + * For each bit in the mask argument:
> + *
> + * - if the datum is not supported:
> + *
> + *   - the bit will be cleared, and
> + *
> + *   - the datum will be set to an appropriate fabricated value if one is
> + *     available (eg. CIFS can take a default uid and gid), otherwise
> + *
> + *   - the field will be cleared;
> + *
> + * - otherwise, if explicitly requested:
> + *
> + *   - the datum will be synchronised to the server if AT_STATX_FORCE_SYNC is
> + *     set or if the datum is considered out of date, and
> + *
> + *   - the field will be filled in and the bit will be set;
> + *
> + * - otherwise, if not requested, but available in approximate form without any
> + *   effort, it will be filled in anyway, and the bit will be set upon return
> + *   (it might not be up to date, however, and no attempt will be made to
> + *   synchronise the internal state first);
> + *
> + * - otherwise the field and the bit will be cleared before returning.
> + *
> + * Items in STATX_BASIC_STATS may be marked unavailable on return, but they
> + * will have values installed for compatibility purposes so that stat() and
> + * co. can be emulated in userspace.
> + */
> +struct statx {
> +	/* 0x00 */
> +	uint32_t	stx_mask;
> +	uint32_t	stx_blksize;
> +	uint64_t	stx_attributes;
> +	/* 0x10 */
> +	uint32_t	stx_nlink;
> +	uint32_t	stx_uid;
> +	uint32_t	stx_gid;
> +	uint16_t	stx_mode;
> +	uint16_t	__spare0[1];
> +	/* 0x20 */
> +	uint64_t	stx_ino;
> +	uint64_t	stx_size;
> +	uint64_t	stx_blocks;
> +	uint64_t	stx_attributes_mask;
> +	/* 0x40 */
> +	const struct statx_timestamp	stx_atime;
> +	const struct statx_timestamp	stx_btime;
> +	const struct statx_timestamp	stx_ctime;
> +	const struct statx_timestamp	stx_mtime;
> +	/* 0x80 */
> +	uint32_t	stx_rdev_major;
> +	uint32_t	stx_rdev_minor;
> +	uint32_t	stx_dev_major;
> +	uint32_t	stx_dev_minor;
> +	/* 0x90 */
> +	uint64_t	__spare2[14];
> +	/* 0x100 */
> +};
> +
> +#if !defined(HAVE_STATX)
> +
> +# ifdef __TEST_H__
> +#  define TST_SYSCALL_WRAPPER ltp_syscall
> +# else
> +#  define TST_SYSCALL_WRAPPER tst_syscall
> +# endif /* __TEST_H__ */

Since we are adding only new library testcases we can avoid this and use
tst_syscall() in the statx() wrapper directly.

> +/*
> + * sys_statx: wrapper function of statx
> + *
> + * Returns: It returns status of statx syscall
> + */
> +static inline int sys_statx(int dirfd, const char *pathname, unsigned int flags,
> +			    unsigned int mask, struct statx *statxbuf)

And since we check for the statx, we can call this function just statx()
so that the tests will pick up the system function definition if it's
available.

> +{
> +	return TST_SYSCALL_WRAPPER(__NR_statx, dirfd, pathname, flags, mask, statxbuf);
> +}
> +#endif
> +
> +/*
> + * Flags to be stx_mask
> + *
> + * Query request/result mask for statx() and struct statx::stx_mask.
> + *
> + * These bits should be set in the mask argument of statx() to request
> + * particular items when calling statx().
> + */
> +#ifndef STATX_TYPE
> +# define STATX_TYPE		0x00000001U
> +#endif
> +
> +#ifndef STATX_MODE
> +# define STATX_MODE		0x00000002U
> +#endif
> +
> +#ifndef STATX_NLINK
> +# define STATX_NLINK		0x00000004U
> +#endif
> +
> +#ifndef STATX_UID
> +# define STATX_UID		0x00000008U
> +#endif
> +
> +#ifndef STATX_GID
> +# define STATX_GID		0x00000010U
> +#endif
> +
> +#ifndef STATX_ATIME
> +# define STATX_ATIME		0x00000020U
> +#endif
> +
> +#ifndef STATX_MTIME
> +# define STATX_MTIME		0x00000040U
> +#endif
> +
> +#ifndef STATX_CTIME
> +# define STATX_CTIME		0x00000080U
> +#endif
> +
> +#ifndef STATX_INO
> +# define STATX_INO		0x00000100U
> +#endif
> +
> +#ifndef STATX_SIZE
> +# define STATX_SIZE		0x00000200U
> +#endif
> +
> +#ifndef STATX_BLOCKS
> +# define STATX_BLOCKS		0x00000400U
> +#endif
> +
> +#ifndef STATX_BASIC_STATS
> +# define STATX_BASIC_STATS	0x000007ffU
> +#endif
> +
> +#ifndef STATX_BTIME
> +# define STATX_BTIME		0x00000800U
> +#endif
> +
> +#ifndef STATX_ALL
> +# define STATX_ALL		0x00000fffU
> +#endif
> +
> +#ifndef STATX__RESERVED
> +# define STATX__RESERVED	0x80000000U
> +#endif
> +
> +/*
> + * Attributes to be found in stx_attributes and masked in stx_attributes_mask.
> + *
> + * These give information about the features or the state of a file that might
> + * be of use to ordinary userspace programs such as GUIs or ls rather than
> + * specialised tools.
> + *
> + * Note that the flags marked [I] correspond to generic FS_IOC_FLAGS
> + * semantically.  Where possible, the numerical value is picked to correspond
> + * also.
> + */
> +#ifndef STATX_ATTR_COMPRESSED
> +# define STATX_ATTR_COMPRESSED	0x00000004
> +#endif
> +
> +#ifndef STATX_ATTR_IMMUTABLE
> +# define STATX_ATTR_IMMUTABLE	0x00000010
> +#endif
> +
> +#ifndef STATX_ATTR_APPEND
> +# define STATX_ATTR_APPEND	0x00000020
> +#endif
> +
> +#ifndef STATX_ATTR_NODUMP
> +# define STATX_ATTR_NODUMP	0x00000040
> +#endif
> +
> +#ifndef STATX_ATTR_ENCRYPTED
> +# define STATX_ATTR_ENCRYPTED	0x00000800
> +#endif
> +
> +#ifndef STATX_ATTR_AUTOMOUNT
> +# define STATX_ATTR_AUTOMOUNT	0x00001000
> +#endif
> +
> +#ifndef AT_SYMLINK_NOFOLLOW
> +# define AT_SYMLINK_NOFOLLOW	0x100
> +#endif
> +
> +#ifndef AT_REMOVEDIR
> +# define AT_REMOVEDIR		0x200
> +#endif
> +
> +#ifndef AT_SYMLINK_FOLLOW
> +# define AT_SYMLINK_FOLLOW	0x400
> +#endif
> +
> +#ifndef AT_NO_AUTOMOUNT
> +# define AT_NO_AUTOMOUNT	0x800
> +#endif
> +
> +#ifndef AT_EMPTY_PATH
> +# define AT_EMPTY_PATH		0x1000
> +#endif
> +
> +#ifndef AT_STATX_SYNC_TYPE
> +# define AT_STATX_SYNC_TYPE	0x6000
> +#endif
> +
> +#ifndef AT_STATX_SYNC_AS_STAT
> +# define AT_STATX_SYNC_AS_STAT	0x0000
> +#endif
> +
> +#ifndef AT_STATX_FORCE_SYNC
> +# define AT_STATX_FORCE_SYNC	0x2000
> +#endif
> +
> +#ifndef AT_STATX_DONT_SYNC
> +# define AT_STATX_DONT_SYNC	0x4000
> +#endif
> +
> +#endif
> diff --git a/include/lapi/syscalls/arm.in b/include/lapi/syscalls/arm.in
> index 71a4b713d..784b64004 100644
> --- a/include/lapi/syscalls/arm.in
> +++ b/include/lapi/syscalls/arm.in
> @@ -341,3 +341,4 @@ renameat2 (__NR_SYSCALL_BASE+382)
>  getrandom (__NR_SYSCALL_BASE+384)
>  memfd_create (__NR_SYSCALL_BASE+385)
>  copy_file_range (__NR_SYSCALL_BASE+391)
> +statx (__NR_SYSCALL+397)
> diff --git a/include/lapi/syscalls/i386.in b/include/lapi/syscalls/i386.in
> index 0f9601472..453ac3e4e 100644
> --- a/include/lapi/syscalls/i386.in
> +++ b/include/lapi/syscalls/i386.in
> @@ -341,3 +341,4 @@ renameat2 354
>  getrandom 355
>  memfd_create 356
>  copy_file_range 377
> +statx 383
> diff --git a/include/lapi/syscalls/powerpc.in b/include/lapi/syscalls/powerpc.in
> index 11ddca34e..10fb238bf 100644
> --- a/include/lapi/syscalls/powerpc.in
> +++ b/include/lapi/syscalls/powerpc.in
> @@ -348,3 +348,4 @@ renameat2 357
>  getrandom 359
>  memfd_create 360
>  copy_file_range 379
> +statx 383
> diff --git a/include/lapi/syscalls/powerpc64.in b/include/lapi/syscalls/powerpc64.in
> index 11ddca34e..10fb238bf 100644
> --- a/include/lapi/syscalls/powerpc64.in
> +++ b/include/lapi/syscalls/powerpc64.in
> @@ -348,3 +348,4 @@ renameat2 357
>  getrandom 359
>  memfd_create 360
>  copy_file_range 379
> +statx 383
> diff --git a/include/lapi/syscalls/s390.in b/include/lapi/syscalls/s390.in
> index 98c861f36..486205030 100644
> --- a/include/lapi/syscalls/s390.in
> +++ b/include/lapi/syscalls/s390.in
> @@ -332,3 +332,4 @@ renameat2 347
>  getrandom 349
>  memfd_create 350
>  copy_file_range 375
> +statx 379
> \ No newline at end of file
> diff --git a/include/lapi/syscalls/sparc.in b/include/lapi/syscalls/sparc.in
> index 296d694a8..bbab51b72 100644
> --- a/include/lapi/syscalls/sparc.in
> +++ b/include/lapi/syscalls/sparc.in
> @@ -337,3 +337,4 @@ renameat2 345
>  getrandom 347
>  memfd_create 348
>  copy_file_range 357
> +statx 360
> diff --git a/include/lapi/syscalls/sparc64.in b/include/lapi/syscalls/sparc64.in
> index 169347a6a..ebff38265 100644
> --- a/include/lapi/syscalls/sparc64.in
> +++ b/include/lapi/syscalls/sparc64.in
> @@ -313,3 +313,4 @@ renameat2 345
>  getrandom 347
>  memfd_create 348
>  copy_file_range 357
> +statx 360
> diff --git a/include/lapi/syscalls/x86_64.in b/include/lapi/syscalls/x86_64.in
> index 89db79404..11a7b74ca 100644
> --- a/include/lapi/syscalls/x86_64.in
> +++ b/include/lapi/syscalls/x86_64.in
> @@ -308,3 +308,4 @@ renameat2 316
>  getrandom 318
>  memfd_create 319
>  copy_file_range 326
> +statx 332
> diff --git a/m4/ltp-statx.m4 b/m4/ltp-statx.m4
> new file mode 100644
> index 000000000..52823b5ed
> --- /dev/null
> +++ b/m4/ltp-statx.m4
> @@ -0,0 +1,25 @@
> +dnl
> +dnl Copyright (c) Linux Test Project, 2014
> +dnl
> +dnl This program is free software;  you can redistribute it and/or modify
> +dnl it under the terms of the GNU General Public License as published by
> +dnl the Free Software Foundation; either version 2 of the License, or
> +dnl (at your option) any later version.
> +dnl
> +dnl This program is distributed in the hope that it will be useful,
> +dnl but WITHOUT ANY WARRANTY;  without even the implied warranty of
> +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
> +dnl the GNU General Public License for more details.
> +dnl
> +dnl You should have received a copy of the GNU General Public License
> +dnl along with this program;  if not, write to the Free Software
> +dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> +dnl
> +
> +dnl
> +dnl LTP_CHECK_STATX
> +dnl ----------------------------
> +dnl
> +AC_DEFUN([LTP_CHECK_STATX],[
> +AC_CHECK_FUNCS(statx,,)
> +])
> diff --git a/runtest/syscalls b/runtest/syscalls
> index dc72484cb..bc84c0df7 100644
> --- a/runtest/syscalls
> +++ b/runtest/syscalls
> @@ -1277,6 +1277,15 @@ statfs03_64 statfs03_64
>  statvfs01 statvfs01
>  statvfs02 statvfs02
>  
> +statx01 statx01
> +statx01_64 statx01_64
> +statx02 statx02
> +statx02_64 statx02_64
> +statx03 statx03
> +statx03_64 statx03_64
> +statx04 statx04
> +statx04_64 statx04_64
> +
>  stime01 stime01
>  stime02 stime02
>  
> diff --git a/testcases/kernel/syscalls/statx/.gitignore b/testcases/kernel/syscalls/statx/.gitignore
> new file mode 100644
> index 000000000..474871dd1
> --- /dev/null
> +++ b/testcases/kernel/syscalls/statx/.gitignore
> @@ -0,0 +1,8 @@
> +/statx01
> +/statx01_64
> +/statx02
> +/statx02_64
> +/statx03
> +/statx03_64
> +/statx04
> +/statx04_64
> diff --git a/testcases/kernel/syscalls/statx/Makefile b/testcases/kernel/syscalls/statx/Makefile
> new file mode 100644
> index 000000000..bf1201019
> --- /dev/null
> +++ b/testcases/kernel/syscalls/statx/Makefile
> @@ -0,0 +1,26 @@
> +#
> +#  Copyright (c) International Business Machines  Corp., 2001
> +#
> +#  This program is free software;  you can redistribute it and/or modify
> +#  it under the terms of the GNU General Public License as published by
> +#  the Free Software Foundation; either version 2 of the License, or
> +#  (at your option) any later version.
> +#
> +#  This program is distributed in the hope that it will be useful,
> +#  but WITHOUT ANY WARRANTY;  without even the implied warranty of
> +#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
> +#  the GNU General Public License for more details.
> +#
> +#  You should have received a copy of the GNU General Public License
> +#  along with this program;  if not, write to the Free Software
> +#  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
> +#
> +
> +top_srcdir		?= ../../../..
> +
> +include $(top_srcdir)/include/mk/testcases.mk
> +include $(abs_srcdir)/../utils/newer_64.mk
> +
> +%_64: CPPFLAGS += -D_FILE_OFFSET_BITS=64
> +
> +include $(top_srcdir)/include/mk/generic_leaf_target.mk
> diff --git a/testcases/kernel/syscalls/statx/statx01.c b/testcases/kernel/syscalls/statx/statx01.c
> new file mode 100644
> index 000000000..ef8aabc7e
> --- /dev/null
> +++ b/testcases/kernel/syscalls/statx/statx01.c
> @@ -0,0 +1,200 @@
> +// SPDX-License-Identifier: GPL-2.0 or later
> +/*
> + * Copyright (c) Zilogic Systems Pvt. Ltd., 2018
> + * Email: code@zilogic.com
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +/*
> + * Test statx
> + *
> + * This code tests the functionality of statx system call.
> + *
> + * TESTCASE 1:
> + * The metadata for normal file are tested against predefined values:
> + * 1) gid
> + * 2) uid
> + * 3) mode
> + * 4) blocks
> + * 5) size
> + *
> + * A file is created and metadata values are set with
> + * predefined values.
> + * Then the values obtained using statx is checked against
> + * the predefined values.
> + *
> + * TESTCASE 2:
> + * The metadata for device file are tested against predefined values:
> + * 1) MAJOR number
> + * 2) MINOR number
> + *
> + * A device file is created seperately using mknod(must be a root user).
> + * The major number and minor number are set while creation.
> + * Major and minor numbers obtained using statx is checked against
> + * predefined values.
> + * Minimum kernel version required is 4.11.
> + */
> +#include <stdio.h>
> +#include <string.h>
> +#include <pwd.h>
> +#include <sys/types.h>
> +#include <sys/sysmacros.h>
> +#include "tst_test.h"
> +#include "tst_safe_macros.h"
> +#include "lapi/sys_statx.h"
> +#include <unistd.h>
> +
> +#define TESTFILE "test_file"
> +#define DEVICEFILE "blk_dev"
> +#define MODE 0644
> +
> +static int file_fd;
> +#define SIZE 256
> +#define MAJOR 8
> +#define MINOR 1
> +
> +static void test_normal_file(void)
> +{
> +	struct statx buff;
> +	uint32_t blocks;
> +
> +	TEST(sys_statx(AT_FDCWD, TESTFILE, 0, 0, &buff));
> +	if (TEST_RETURN == 0)
> +		tst_res(TPASS,
> +			"statx(AT_FDCWD, %s, 0, 0, &buff) passed", TESTFILE);
> +	else
> +		tst_res(TFAIL|TTERRNO,
> +			"statx(AT_FDCWD, %s, 0, 0, &buff) failed", TESTFILE);

This is a minor but we should return from the function here in a case
that statx have failed.

> +	if (geteuid() == buff.stx_uid)
> +		tst_res(TPASS,
> +			"stx_uid(%u) obtained is correct", buff.stx_uid);
> +	else
> +		tst_res(TFAIL|TTERRNO,
> +			"stx_uid(%u) obtained is different from euid(%u)",
> +			buff.stx_uid, geteuid());
> +
> +	if (getegid() == buff.stx_gid)
> +		tst_res(TPASS,
> +			"stx_gid(%u) obtained is correct", buff.stx_gid);
> +	else
> +		tst_res(TFAIL|TTERRNO,
                                ^
				I does not make sense to print the
				TEST_ERRNO here, it only makes sense to be called
				right after we called the TEST(statx(...)).
> +			"stx_gid(%u) obtained is different from egid(%u)",
> +			buff.stx_gid, getegid());
> +
> +	if (buff.stx_size == SIZE)
> +		tst_res(TPASS,
> +			"stx_size(%llu) obtained is correct", buff.stx_size);
> +	else
> +		tst_res(TFAIL|TTERRNO,
> +			"stx_size(%llu) obtained is different from expected(%u)",
> +			buff.stx_size, SIZE);
> +
> +	if ((buff.stx_mode & ~(S_IFMT)) == MODE)
> +		tst_res(TPASS,
> +			"stx_mode(%u) obtained is correct", buff.stx_mode);
> +	else
> +		tst_res(TFAIL|TTERRNO,
> +			"stx_mode(%u) obtained is different from expected(%u)",
> +			buff.stx_mode, MODE);
> +
> +	blocks = (((SIZE + buff.stx_blksize - 1) / buff.stx_blksize)
> +		  * (buff.stx_blksize / 512));
> +	
> +	if (blocks == buff.stx_blocks)
> +		tst_res(TPASS,
> +			"stx_blocks(%llu) obtained is correct",
> +			buff.stx_blocks);
> +	else
> +		tst_res(TFAIL|TTERRNO,
> +			"stx_blocks(%llu) obtained is different from expected(%u)",
> +			buff.stx_blocks, blocks);

And the same for the rest of these checks.

> +}
> +
> +static void test_device_file(void)
> +{
> +	struct statx buff;
> +
> +	TEST(sys_statx(AT_FDCWD, DEVICEFILE, 0, 0, &buff));
> +	if (TEST_RETURN == 0)
> +		tst_res(TPASS,
> +			"statx(AT_FDCWD, %s, 0, 0, &buff) passed", DEVICEFILE);
                                                            ^
							    The TPASS
							    flag will
							    already
							    print that
							    the test has
							    passed, we
							    can avoid
							    it here.
> +	else
> +		tst_res(TFAIL|TTERRNO,
> +			"statx(AT_FDCWD, %s, 0, 0, &buff) failed", DEVICEFILE);
                                                            ^
							    Same here
							    the TFAIL
							    flag will
							    cover that.
> +
> +	if (buff.stx_rdev_major == MAJOR)
> +		tst_res(TPASS,
> +			"stx_rdev_major(%u) obtained is correct",
> +			buff.stx_rdev_major);
> +	else
> +		tst_res(TFAIL|TTERRNO,
> +			"stx_rdev_major(%u) obtained is different from expected(%u)",
> +			buff.stx_rdev_major, MAJOR);
> +
> +	if (buff.stx_rdev_minor == MINOR)
> +		tst_res(TPASS,
> +			"stx_rdev_minor(%u) obtained is correct",
> +			buff.stx_rdev_minor);
> +	else
> +		tst_res(TFAIL|TTERRNO,
> +			"stx_rdev_minor(%u) obtained is different from expected(%u)",
> +			buff.stx_rdev_minor, MINOR);
> +}
> +
> +
> +struct tcase {
> +	void (*tfunc)(void);
> +} tcases[] = {
> +	{&test_normal_file},
> +	{&test_device_file}
> +};
> +
> +static void run(unsigned int i)
> +{
> +	struct tcase *t;
> +
> +	t = &tcases[i];
> +	t->tfunc();
> +}
> +
> +static void setup(void)
> +{
> +	char data_buff[SIZE];
> +
> +	memset(data_buff, '@', sizeof(data_buff));
> +
> +	file_fd =  SAFE_OPEN(TESTFILE, O_RDWR|O_CREAT, MODE);
> +	SAFE_WRITE(0, file_fd, data_buff, sizeof(data_buff));
> +
> +	SAFE_MKNOD(DEVICEFILE, S_IFBLK | 0777, makedev(MAJOR, MINOR));
> +}
> +
> +static void cleanup(void)
> +{
> +	if (file_fd > 0)
> +		SAFE_CLOSE(file_fd);
> +}
> +
> +static struct tst_test test = {
> +	.test = run,
> +	.tcnt = ARRAY_SIZE(tcases),
> +	.setup = setup,
> +	.cleanup = cleanup,
> +	.min_kver = "4.11",
> +	.needs_root = 1,
> +	.needs_tmpdir = 1,
> +};
> diff --git a/testcases/kernel/syscalls/statx/statx02.c b/testcases/kernel/syscalls/statx/statx02.c
> new file mode 100644
> index 000000000..6b819c079
> --- /dev/null
> +++ b/testcases/kernel/syscalls/statx/statx02.c
> @@ -0,0 +1,144 @@
> +// SPDX-License-Identifier: GPL-2.0 or later
> +/*
> + * Copyright (c) Zilogic Systems Pvt. Ltd., 2018
> + * Email: code@zilogic.com
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +/*
> + * Test statx
> + *
> + * This code tests the following flags:
> + * 1) AT_EMPTY_PATH
> + * 2) AT_SYMLINK_NOFOLLOW
> + *
> + * A test file and a link for it is created.
> + *
> + * To check empty path flag, test file fd alone is passed.
> + * Predefined size of testfile is checked against obtained value.
> + *
> + * To check symlink no follow flag, the linkname is statxed.
> + * To ensure that link is not dereferenced, obtained inode is compared
> + * with test file inode.
> + * Minimum kernel version required is 4.11.
> + */
> +
> +#include <stdio.h>
> +#include <string.h>
> +#include <pwd.h>
> +#include "tst_test.h"
> +#include "tst_safe_macros.h"
> +#include "lapi/sys_statx.h"
> +
> +#define TESTFILE "test_temp"
> +#define LINK_FILE "test_temp_ln"
> +#define MODE 0644
> +#define SIZE 14
> +
> +static int file_fd;
> +
> +static void test_empty_path(void)
> +{
> +	struct statx buf;
> +
> +	TEST(sys_statx(file_fd, "", AT_EMPTY_PATH, 0, &buf));
> +	if (TEST_RETURN == 0)
> +		tst_res(TPASS,
> +			"statx(file_fd, \" \", AT_EMPTY_PATH, 0, &buf): passed");
                                                                         ^
									 Here
									 as
									 well
> +	else
> +		tst_res(TFAIL|TTERRNO,
> +			"statx(file_fd, \" \", AT_EMPTY_PATH, 0, &buff): failed");
                                                                           ^
									   And
									   here
									   as
									   well
									   and
									   in
									   a
									   couple
									   of
									   other
									   places
> +
> +	if (buf.stx_size == SIZE)
> +		tst_res(TPASS,
> +			"stx_size(%llu) obtained is correct", buf.stx_size);
> +	else
> +		tst_res(TFAIL|TTERRNO,
> +			"stx_size(%llu) obtained is not same as expected(%u)",
> +			buf.stx_size, SIZE);
> +
> +}
> +
> +static void test_sym_link(void)
> +{
> +	struct statx fbuf;
> +	struct statx lbuf;
> +
> +	TEST(sys_statx(AT_FDCWD, TESTFILE, 0, 0, &fbuf));
> +
> +	if (TEST_RETURN == 0)
> +		tst_res(TPASS,
> +			"statx(AT_FDCWD, %s, 0, 0, &fbuf) passed", TESTFILE);
> +	else
> +		tst_res(TFAIL|TTERRNO,
> +			"statx(AT_FDCWD, %s, 0, 0, &fbuf) failed", TESTFILE);
> +
> +	TEST(sys_statx(AT_FDCWD, LINK_FILE, AT_SYMLINK_NOFOLLOW, 0, &lbuf));
> +
> +	if (TEST_RETURN == 0)
> +		tst_res(TPASS,
> +			"statx(AT_FDCWD, %s, AT_SYMLINK_NOFOLLOW, 0,&lbuf): passed",
> +			LINK_FILE);
> +	else
> +		tst_res(TFAIL|TTERRNO,
> +			"statx(AT_FDCWD, %s, AT_SYMLINK_NOFOLLOW, 0,&lbuf): failed",
> +			LINK_FILE);
> +
> +	if (fbuf.stx_ino != lbuf.stx_ino)
> +		tst_res(TPASS, "Statx symlink flag worked as expected");
> +	else
> +		tst_res(TFAIL|TTERRNO,
> +			"Statx symlink flag failed to work as expected");
> +}
> +
> +struct tcase {
> +	void (*tfunc)(void);
> +} tcases[] = {
> +	{&test_empty_path},
> +	{&test_sym_link}
> +};
> +
> +static void run(unsigned int i)
> +{
> +	struct tcase *t;
> +
> +	t = &tcases[i];
> +	t->tfunc();
> +}
> +
> +static void setup(void)
> +{
> +	char data_buf[SIZE] = "LinusTorvalds";
> +
> +	file_fd = SAFE_OPEN(TESTFILE, O_RDWR | O_CREAT, MODE);
> +	SAFE_WRITE(0, file_fd, data_buf, sizeof(data_buf));
> +
> +	SAFE_SYMLINK(TESTFILE, LINK_FILE);
> +}
> +
> +static void cleanup(void)
> +{
> +	if (file_fd > 0)
> +		SAFE_CLOSE(file_fd);
> +}
> +
> +static struct tst_test test = {
> +	.test = run,
> +	.tcnt = ARRAY_SIZE(tcases),
> +	.setup = setup,
> +	.cleanup = cleanup,
> +	.min_kver = "4.11",
> +	.needs_tmpdir = 1,
> +};
> diff --git a/testcases/kernel/syscalls/statx/statx03.c b/testcases/kernel/syscalls/statx/statx03.c
> new file mode 100644
> index 000000000..e88778201
> --- /dev/null
> +++ b/testcases/kernel/syscalls/statx/statx03.c
> @@ -0,0 +1,127 @@
> +// SPDX-License-Identifier: GPL-2.0 or later
> +/*
> + * Copyright (c) Zilogic Systems Pvt. Ltd., 2018
> + * Email: code@zilogic.com
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +/*
> + * Test statx
> + *
> + * This code tests if expected error values are returned for specific cases by
> + * statx.
> + * The error cases are simulated and the return value is checked against
> + * expected error number value.
> + * The following error values are tested:
> + * 1) EBADF - Bad file descriptor
> + * 2) EFAULT - Bad address
> + * 3) EINVAL - Invalid argument
> + * 4) ENOENT - No such file or directory
> + * 5) ENOTDIR - Not a directory
> + * 6) ENAMETOOLONG - Filename too long
> + *
> + * Error scenario is simulated for each listed flag by passing
> + * respective arguments.
> + * The obtained error flag is checked against the expected
> + * flag value for that scenario.
> + *
> + * Minimum Kernel version required is 4.11.
> + */
> +#include <stdio.h>
> +#include <string.h>
> +#include <pwd.h>
> +#include "tst_test.h"
> +#include "tst_safe_macros.h"
> +#include "lapi/sys_statx.h"
> +
> +#define TESTFILE "test_file"
> +#define MODE 0644
> +
> +static int tst_file_fd;
> +static char long_pathname[257];
> +
> +static const struct test_case {
> +	uint32_t dfd;
> +	char *filename;
> +	uint32_t flag;
> +	uint32_t mask;
> +	int32_t errnum;
> +} tcases[] = {
> +	{.dfd = -1, .filename = TESTFILE, .flag = 0,
> +	 .mask = 0, .errnum = EBADF},
> +
> +	{.dfd = AT_FDCWD, .filename = NULL, .flag = 0,
                             ^
			     We should use tst_get_bad_add() to get an
			     address that causes EFAULT, some
			     architectures do have a mapping at NULL
			     address.
> +	 .mask = 0, .errnum = EFAULT},
> +
> +	{.dfd = AT_FDCWD, .filename = TESTFILE, .flag = -1,
> +	 .mask = 0, .errnum = EINVAL},
> +
> +	{.dfd = AT_FDCWD, .filename = TESTFILE, .flag = 0,
> +	 .mask = -1, .errnum = EINVAL},
> +
> +	{.dfd = AT_FDCWD, .filename = "", .flag = 0,
> +	 .mask = 0, .errnum = ENOENT},
> +
> +	{.dfd = 1, .filename = TESTFILE, .flag = 0,
> +	 .mask = 0, .errnum = ENOTDIR},
> +
> +	{.dfd = AT_FDCWD, .filename = long_pathname, .flag = 0,
> +	 .mask = 0, .errnum = ENAMETOOLONG},
> +};
> +
> +static void run_test(unsigned int i)
> +{
> +	struct statx buf;
> +	const struct test_case *tc = &tcases[i];
> +
> +	TEST(sys_statx(tc->dfd, tc->filename, tc->flag,
> +		       tc->mask, &buf));
> +
> +	if (TEST_RETURN != -1) {
> +		tst_res(TFAIL, "statx() returned with %ld", TEST_RETURN);
> +		return;
> +	}
> +
> +	if (tc->errnum == TEST_ERRNO) {
> +		tst_res(TPASS | TTERRNO, "statx() failed with");
> +		return;
> +	}
> +
> +	tst_res(TFAIL | TTERRNO,
> +		"statx() should fail with %s", tst_strerrno(tc->errnum));
> +}
> +
> +static void setup(void)
> +{
> +	tst_file_fd = SAFE_OPEN(TESTFILE, O_RDWR | O_CREAT, MODE);
> +
> +	memset(long_pathname, '@', sizeof(long_pathname));
> +	long_pathname[sizeof(long_pathname) - 1] = 0;
> +}
> +
> +static void cleanup(void)
> +{
> +	if (tst_file_fd > 0)
> +		SAFE_CLOSE(tst_file_fd);
> +}
> +
> +static struct tst_test test = {
> +	.tcnt = ARRAY_SIZE(tcases),
> +	.test = run_test,
> +	.setup = setup,
> +	.cleanup = cleanup,
> +	.min_kver = "4.11",
> +	.needs_tmpdir = 1,
> +};
> diff --git a/testcases/kernel/syscalls/statx/statx04.c b/testcases/kernel/syscalls/statx/statx04.c
> new file mode 100644
> index 000000000..24eb3273b
> --- /dev/null
> +++ b/testcases/kernel/syscalls/statx/statx04.c
> @@ -0,0 +1,221 @@
> +// SPDX-License-Identifier: GPL-2.0 or later
> +/*
> + * Copyright (c) Zilogic Systems Pvt. Ltd., 2018
> + * Email: code@zilogic.com
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +/*
> + * Test statx
> + *
> + * This code tests the functionality of statx system call.
> + * This code tests if the attributes field of statx received expected value.
> + * File set with following flags by using SAFE_IOCTL and e4crypt:
> + * 1) STATX_ATTR_COMPRESSED - The file is compressed by the filesystem.
> + * 2) STATX_ATTR_IMMUTABLE - The file cannot be modified.
> + * 3) STATX_ATTR_APPEND - The file can only be opened in append mode for writing.
> + * 4) STATX_ATTR_NODUMP - File is not a candidate for backup when a backup program
> + *                        such as dump(8) is run.
> + * 5) STATX_ATTR_ENCRYPTED - A key is required for the file to be encrypted by
> + *                          the filesystem.
> + *
> + * A test directory is created with flags added to it.
> + *
> + * SAFE_IOCTL() is used to modify the atttributes of the directory such as
> + * compressed, append, nodump and immutable.
> + *
> + * e4crypt is used to set the encrypt flag.
> + *
> + * Two directory are tested.
> + * First directory has all flags set.
> + * Second directory has no flags set.
> + * 
> + * Minimum kernel version required is 4.11.
> + */
> +
> +#include "tst_test.h"
> +#include "lapi/sys_statx.h"
> +
> +#define	FS_IOC_GETFLAGS	_IOR('f', 1, long)
> +#define	FS_IOC_SETFLAGS	_IOW('f', 2, long)
> +
> +#define	FS_COMPR_FL        0x00000004 /* Compress file */
> +#define FS_IMMUTABLE_FL	   0x00000010 /* Immutable file */
> +#define FS_APPEND_FL	   0x00000020 /* writes to file may only append */
> +#define FS_NODUMP_FL	   0x00000040 /* do not dump file */

These flags should go to a lapi header as well, probably lapi/fs.h.

> +#define TESTDIR_FLAGGED "mnt_point/test_dir1"
> +#define TESTDIR_UNFLAGGED "mnt_point/test_dir2"
> +#define MOUNT_POINT "mnt_point"
> +
> +static void test_flagged(void)
> +{
> +	struct statx buf;
> +
> +	TEST(sys_statx(AT_FDCWD, TESTDIR_FLAGGED, 0, 0, &buf));
> +	if (TEST_RETURN == 0)
> +		tst_res(TPASS,
> +			"sys_statx(AT_FDCWD, %s, 0, 0, &buf): passed", TESTDIR_FLAGGED);
> +	else
> +		tst_res(TFAIL | TTERRNO,
> +			"sys_statx(AT_FDCWD, %s, 0, 0, &buf): failed", TESTDIR_FLAGGED);
> +
> +	if (buf.stx_attributes & STATX_ATTR_COMPRESSED)
> +		tst_res(TPASS, "STATX_ATTR_COMPRESSED flag is set");
> +	else
> +		tst_res(TFAIL | TTERRNO,
> +			"STATX_ATTR_COMPRESSED flag is not set");
> +
> +	if (buf.stx_attributes & STATX_ATTR_APPEND)
> +		tst_res(TPASS, "STATX_ATTR_APPEND flag is set");
> +	else
> +		tst_res(TFAIL | TTERRNO,
> +			"STATX_ATTR_APPEND flag is not set");
> +
> +	if (buf.stx_attributes & STATX_ATTR_IMMUTABLE)
> +		tst_res(TPASS, "STATX_ATTR_IMMUTABLE flag is set");
> +	else
> +		tst_res(TFAIL | TTERRNO,
> +			"STATX_ATTR_IMMUTABLE flag is not set");
> +
> +	if (buf.stx_attributes & STATX_ATTR_NODUMP)
> +		tst_res(TPASS, "STATX_ATTR_NODUMP flag is set");
> +	else
> +		tst_res(TFAIL | TTERRNO,
> +			"STATX_ATTR_NODUMP flag is not set");
> +
> +	if (buf.stx_attributes & STATX_ATTR_ENCRYPTED)
> +		tst_res(TPASS, "STATX_ATTR_ENCRYPTED flag is set");
> +	else
> +		tst_res(TFAIL | TTERRNO,
> +			"STATX_ATTR_ENCRYPTED flag is not set");
> +}
> +
> +static void test_unflagged(void)
> +{
> +	struct statx buf;
> +
> +	TEST(sys_statx(AT_FDCWD, TESTDIR_UNFLAGGED, 0, 0, &buf));
> +	if (TEST_RETURN == 0)
> +		tst_res(TPASS,
> +			"sys_statx(AT_FDCWD, %s, 0, 0, &buf): passed", TESTDIR_UNFLAGGED);
> +	else
> +		tst_res(TFAIL | TTERRNO,
> +			"sys_statx(AT_FDCWD, %s, 0, 0, &buf): failed", TESTDIR_UNFLAGGED);
> +
> +	if ((buf.stx_attributes & STATX_ATTR_COMPRESSED) == 0)
> +		tst_res(TPASS, "STATX_ATTR_COMPRESSED flag is not set");
> +	else
> +		tst_res(TFAIL | TTERRNO,
> +			"STATX_ATTR_COMPRESSED flag is set");
> +
> +	if ((buf.stx_attributes & STATX_ATTR_APPEND) == 0)
> +		tst_res(TPASS, "STATX_ATTR_APPEND flag is not set");
> +	else
> +		tst_res(TFAIL | TTERRNO,
> +			"STATX_ATTR_APPEND flag is set");
> +
> +	if ((buf.stx_attributes & STATX_ATTR_IMMUTABLE) == 0)
> +		tst_res(TPASS, "STATX_ATTR_IMMUTABLE flag is not set");
> +	else
> +		tst_res(TFAIL | TTERRNO,
> +			"STATX_ATTR_IMMUTABLE flag is set");
> +
> +	if ((buf.stx_attributes & STATX_ATTR_NODUMP) == 0)
> +		tst_res(TPASS, "STATX_ATTR_NODUMP flag is not set");
> +	else
> +		tst_res(TFAIL | TTERRNO,
> +			"STATX_ATTR_NODUMP flag is set");
> +
> +	if ((buf.stx_attributes & STATX_ATTR_ENCRYPTED) == 0)
> +		tst_res(TPASS, "STATX_ATTR_ENCRYPTED flag is not set");
> +	else
> +		tst_res(TFAIL | TTERRNO,
> +			"STATX_ATTR_ENCRYPTED flag is set");
> +}
> +
> +struct test_cases {
> +	void (*tfunc)(void);
> +} tcases[] = {
> +	{&test_flagged},
> +	{&test_unflagged},
> +};
> +
> +static void run(unsigned int i)
> +{
> +	struct test_cases *tc = &tcases[i];
> +
> +	tc->tfunc();
> +}
> +
> +static void caid_flags_setup(void)
> +{
> +	int fd;
> +	int attr;
> +
> +	fd = SAFE_OPEN(TESTDIR_FLAGGED, O_RDONLY | O_DIRECTORY);
> +
> +	SAFE_IOCTL(fd, FS_IOC_GETFLAGS, &attr);
> +
> +	attr |= FS_COMPR_FL | FS_APPEND_FL | FS_IMMUTABLE_FL | FS_NODUMP_FL;
> +
> +	SAFE_IOCTL(fd, FS_IOC_SETFLAGS, &attr);
> +
> +	SAFE_CLOSE(fd);
> +}
> +
> +static void encrypt_flag_setup(void)
> +{
> +	const char *dev = dev = tst_device->dev;
                         ^
			 This code does not make much sense, typo?

> +	const char * const mkfs_opts[] = {"-O encrypt", NULL};
> +
> +	SAFE_MKDIR(MOUNT_POINT, 0777);
> +
> +	SAFE_MKFS(dev, "ext4", mkfs_opts, NULL);
> +	SAFE_MOUNT(dev, MOUNT_POINT, "ext4", 0, NULL);
> +
> +	SAFE_MKDIR(TESTDIR_FLAGGED, 0777);
> +	SAFE_MKDIR(TESTDIR_UNFLAGGED, 0777);
> +	
     ^
     Trailing whitespace, you can check for formatting errors like this
     one with the linux kernel checkpatch.pl script.

> +	TEST(tst_system("echo qwery | e4crypt add_key "TESTDIR_FLAGGED));
> +	if (TEST_RETURN == 0)
> +		tst_res(TINFO, "Encryption flag is added to %s", TESTDIR_FLAGGED);
> +	else
> +		tst_res(TINFO | TERRNO,
> +			"Encryption flag is failed add to %s", TESTDIR_FLAGGED);

        We should handle the case when e4crypt is not installed on the
	machine, i.e. check for 'command-not-found' exit value here and
	set a flag that would produce TCONF instead of TFAIL in the
	check for encrypted flag in the test_flagged() functio.n

> +}
> +
> +static void setup(void)
> +{
> +	encrypt_flag_setup();
> +	caid_flags_setup();
> +}
> +
> +static void cleanup(void)
> +{
> +	SAFE_UMOUNT(MOUNT_POINT);
> +}
> +
> +static struct tst_test test = {
> +	.test = run,
> +	.tcnt = ARRAY_SIZE(tcases),
> +	.setup = setup,
> +	.cleanup = cleanup,
> +	.min_kver = "4.11",
> +	.needs_root = 1,
> +	.needs_device = 1,
> +	.dev_fs_type = "ext4",
> +	.dev_min_size = 512,
> +};
> -- 
> 2.11.0
> 
> 
> -- 
> Mailing list info: https://lists.linux.it/listinfo/ltp

-- 
Cyril Hrubis
chrubis@suse.cz


More information about the ltp mailing list