git: b630d64c3da1 - stable/13 - linux: implement statx(2)

From: Edward Tomasz Napierala <trasz_at_FreeBSD.org>
Date: Thu, 17 Feb 2022 15:53:49 UTC
The branch stable/13 has been updated by trasz:

URL: https://cgit.FreeBSD.org/src/commit/?id=b630d64c3da1f669859ae61300191be09a744577

commit b630d64c3da1f669859ae61300191be09a744577
Author:     Philippe Michaud-Boudreault <pitwuu@gmail.com>
AuthorDate: 2021-06-08 08:24:10 +0000
Commit:     Edward Tomasz Napierala <trasz@FreeBSD.org>
CommitDate: 2022-02-14 00:07:33 +0000

    linux: implement statx(2)
    
    PR:             252106
    Reviewed By:    dchagin
    Differential Revision:  https://reviews.freebsd.org/D30466
    
    (cherry picked from commit 2362ad457a01d56d87e74823599578ab37bdbfb9)
---
 sys/compat/linux/linux.h       | 42 ++++++++++++++++++++++++++
 sys/compat/linux/linux_dummy.c |  2 --
 sys/compat/linux/linux_stats.c | 67 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 109 insertions(+), 2 deletions(-)

diff --git a/sys/compat/linux/linux.h b/sys/compat/linux/linux.h
index 48217959951c..18eafa88a432 100644
--- a/sys/compat/linux/linux.h
+++ b/sys/compat/linux/linux.h
@@ -205,4 +205,46 @@ int linux_to_bsd_bits_(int value, struct bsd_to_linux_bitmap *bitmap,
 int bsd_to_linux_errno(int error);
 void linux_check_errtbl(void);
 
+#define STATX_BASIC_STATS		0x07ff
+#define STATX_BTIME			0x0800
+#define STATX_ALL			0x0fff
+
+#define STATX_ATTR_COMPRESSED		0x0004
+#define STATX_ATTR_IMMUTABLE		0x0010
+#define STATX_ATTR_APPEND		0x0020
+#define STATX_ATTR_NODUMP		0x0040
+#define STATX_ATTR_ENCRYPTED		0x0800
+#define STATX_ATTR_AUTOMOUNT		0x1000
+
+struct l_statx_timestamp {
+	int64_t tv_sec;
+	int32_t tv_nsec;
+	int32_t __spare0;
+};
+
+struct l_statx {
+	uint32_t stx_mask;
+	uint32_t stx_blksize;
+	uint64_t stx_attributes;
+	uint32_t stx_nlink;
+	uint32_t stx_uid;
+	uint32_t stx_gid;
+	uint16_t stx_mode;
+	uint16_t __spare0[1];
+	uint64_t stx_ino;
+	uint64_t stx_size;
+	uint64_t stx_blocks;
+	uint64_t stx_attributes_mask;
+	struct l_statx_timestamp stx_atime;
+	struct l_statx_timestamp stx_btime;
+	struct l_statx_timestamp stx_ctime;
+	struct l_statx_timestamp stx_mtime;
+	uint32_t stx_rdev_major;
+	uint32_t stx_rdev_minor;
+	uint32_t stx_dev_major;
+	uint32_t stx_dev_minor;
+	uint64_t stx_mnt_id;
+	uint64_t __spare2[13];
+};
+
 #endif /* _LINUX_MI_H_ */
diff --git a/sys/compat/linux/linux_dummy.c b/sys/compat/linux/linux_dummy.c
index fef09809822b..aa579d762c93 100644
--- a/sys/compat/linux/linux_dummy.c
+++ b/sys/compat/linux/linux_dummy.c
@@ -147,8 +147,6 @@ DUMMY(faccessat2);
 DUMMY(process_madvise);
 DUMMY(epoll_pwait2);
 DUMMY(mount_setattr);
-/* Linux 4.11: */
-DUMMY(statx);
 /* Linux 4.18: */
 DUMMY(io_pgetevents);
 DUMMY(rseq);
diff --git a/sys/compat/linux/linux_stats.c b/sys/compat/linux/linux_stats.c
index c88f6f53bdd7..4e6304500a8b 100644
--- a/sys/compat/linux/linux_stats.c
+++ b/sys/compat/linux/linux_stats.c
@@ -196,6 +196,40 @@ newstat_copyout(struct stat *buf, void *ubuf)
 	return (copyout(&tbuf, ubuf, sizeof(tbuf)));
 }
 
+static int
+statx_copyout(struct stat *buf, void *ubuf)
+{
+	struct l_statx tbuf;
+
+	bzero(&tbuf, sizeof(tbuf));
+	tbuf.stx_mask = STATX_ALL;
+	tbuf.stx_blksize = buf->st_blksize;
+	tbuf.stx_attributes = 0;
+	tbuf.stx_nlink = buf->st_nlink;
+	tbuf.stx_uid = buf->st_uid;
+	tbuf.stx_gid = buf->st_gid;
+	tbuf.stx_mode = buf->st_mode;
+	tbuf.stx_ino = buf->st_ino;
+	tbuf.stx_size = buf->st_size;
+	tbuf.stx_blocks = buf->st_blocks;
+
+	tbuf.stx_atime.tv_sec = buf->st_atim.tv_sec;
+	tbuf.stx_atime.tv_nsec = buf->st_atim.tv_nsec;
+	tbuf.stx_btime.tv_sec = buf->st_birthtim.tv_sec;
+	tbuf.stx_btime.tv_nsec = buf->st_birthtim.tv_nsec;
+	tbuf.stx_ctime.tv_sec = buf->st_ctim.tv_sec;
+	tbuf.stx_ctime.tv_nsec = buf->st_ctim.tv_nsec;
+	tbuf.stx_mtime.tv_sec = buf->st_mtim.tv_sec;
+	tbuf.stx_mtime.tv_nsec = buf->st_mtim.tv_nsec;
+
+	tbuf.stx_rdev_major = buf->st_rdev >> 8;
+	tbuf.stx_rdev_minor = buf->st_rdev & 0xff;
+	tbuf.stx_dev_major = buf->st_dev >> 8;
+	tbuf.stx_dev_minor = buf->st_dev & 0xff;
+
+	return (copyout(&tbuf, ubuf, sizeof(tbuf)));
+}
+
 #ifdef LINUX_LEGACY_SYSCALLS
 int
 linux_newstat(struct thread *td, struct linux_newstat_args *args)
@@ -730,3 +764,36 @@ linux_syncfs(struct thread *td, struct linux_syncfs_args *args)
 	vrele(vp);
 	return (error);
 }
+
+int
+linux_statx(struct thread *td, struct linux_statx_args *args)
+{
+	char *path;
+	int error, dirfd, flags;
+	struct stat buf;
+
+	if (args->flags & ~(LINUX_AT_SYMLINK_NOFOLLOW | LINUX_AT_EMPTY_PATH)) {
+		linux_msg(td, "statx unsupported flags 0x%x", args->flags);
+		return (EINVAL);
+	}
+
+	flags = (args->flags & LINUX_AT_SYMLINK_NOFOLLOW) ?
+	    AT_SYMLINK_NOFOLLOW : 0;
+	flags |= (args->flags & LINUX_AT_EMPTY_PATH) ?
+	    AT_EMPTY_PATH : 0;
+
+	dirfd = (args->dirfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dirfd;
+	if (!LUSECONVPATH(td)) {
+		error = linux_kern_statat(td, flags, dirfd, args->pathname,
+		    UIO_USERSPACE, &buf);
+	} else {
+		LCONVPATHEXIST_AT(td, args->pathname, &path, dirfd);
+		error = linux_kern_statat(td, flags, dirfd, path, UIO_SYSSPACE, &buf);
+		LFREEPATH(path);
+	}
+	if (error == 0)
+		error = statx_copyout(&buf, args->statxbuf);
+
+	return (error);
+}
+