git: 6c324fb645e6 - stable/13 - linux(4): Add a dedicated statat() implementation
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 29 Jun 2023 08:20:26 UTC
The branch stable/13 has been updated by dchagin: URL: https://cgit.FreeBSD.org/src/commit/?id=6c324fb645e64e0090e16a5846eafdeb723f4105 commit 6c324fb645e64e0090e16a5846eafdeb723f4105 Author: Dmitry Chagin <dchagin@FreeBSD.org> AuthorDate: 2023-04-28 08:55:04 +0000 Commit: Dmitry Chagin <dchagin@FreeBSD.org> CommitDate: 2023-06-29 08:15:45 +0000 linux(4): Add a dedicated statat() implementation Get rid of calling Linux stat translation hook and specific to Linux handling of non-vnode dirfd from kern_statat(), Reviewed by: kib, mjg Differential revision: https://reviews.freebsd.org/D35474 (cherry picked from commit cb858340dcbf214cc4c4d78dbb741620d7b3a252) --- sys/compat/cloudabi/cloudabi_file.c | 2 +- sys/compat/freebsd32/freebsd32_misc.c | 13 ++++++------- sys/compat/linux/linux_file.c | 8 ++++---- sys/compat/linux/linux_stats.c | 34 ++++++++++++++++++++++++++++++++-- sys/kern/vfs_mountroot.c | 2 +- sys/kern/vfs_syscalls.c | 34 +++++++++++----------------------- sys/sys/syscallsubr.h | 4 ++-- 7 files changed, 57 insertions(+), 40 deletions(-) diff --git a/sys/compat/cloudabi/cloudabi_file.c b/sys/compat/cloudabi/cloudabi_file.c index 83987b79aa0c..1a1def879977 100644 --- a/sys/compat/cloudabi/cloudabi_file.c +++ b/sys/compat/cloudabi/cloudabi_file.c @@ -659,7 +659,7 @@ cloudabi_sys_file_stat_get(struct thread *td, error = kern_statat(td, (uap->fd.flags & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0 ? 0 : - AT_SYMLINK_NOFOLLOW, uap->fd.fd, path, UIO_SYSSPACE, &sb, NULL); + AT_SYMLINK_NOFOLLOW, uap->fd.fd, path, UIO_SYSSPACE, &sb); cloudabi_freestr(path); if (error != 0) return (error); diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c index 70eece0311f4..9fd24a91080f 100644 --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -2251,8 +2251,7 @@ ofreebsd32_stat(struct thread *td, struct ofreebsd32_stat_args *uap) struct ostat32 sb32; int error; - error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, - &sb, NULL); + error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, &sb); if (error) return (error); copy_ostat(&sb, &sb32); @@ -2301,7 +2300,7 @@ freebsd32_fstatat(struct thread *td, struct freebsd32_fstatat_args *uap) int error; error = kern_statat(td, uap->flag, uap->fd, uap->path, UIO_USERSPACE, - &ub, NULL); + &ub); if (error) return (error); copy_stat(&ub, &ub32); @@ -2318,7 +2317,7 @@ ofreebsd32_lstat(struct thread *td, struct ofreebsd32_lstat_args *uap) int error; error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path, - UIO_USERSPACE, &sb, NULL); + UIO_USERSPACE, &sb); if (error) return (error); copy_ostat(&sb, &sb32); @@ -2437,7 +2436,7 @@ freebsd11_freebsd32_stat(struct thread *td, int error; error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, - &sb, NULL); + &sb); if (error != 0) return (error); error = freebsd11_cvtstat32(&sb, &sb32); @@ -2472,7 +2471,7 @@ freebsd11_freebsd32_fstatat(struct thread *td, int error; error = kern_statat(td, uap->flag, uap->fd, uap->path, UIO_USERSPACE, - &sb, NULL); + &sb); if (error != 0) return (error); error = freebsd11_cvtstat32(&sb, &sb32); @@ -2490,7 +2489,7 @@ freebsd11_freebsd32_lstat(struct thread *td, int error; error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path, - UIO_USERSPACE, &sb, NULL); + UIO_USERSPACE, &sb); if (error != 0) return (error); error = freebsd11_cvtstat32(&sb, &sb32); diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c index db4b1151bc60..249318a2e619 100644 --- a/sys/compat/linux/linux_file.c +++ b/sys/compat/linux/linux_file.c @@ -732,7 +732,7 @@ linux_unlink(struct thread *td, struct linux_unlink_args *args) if (error == EPERM) { /* Introduce POSIX noncompliant behaviour of Linux */ if (kern_statat(td, 0, AT_FDCWD, args->path, - UIO_USERSPACE, &st, NULL) == 0) { + UIO_USERSPACE, &st) == 0) { if (S_ISDIR(st.st_mode)) error = EISDIR; } @@ -742,8 +742,8 @@ linux_unlink(struct thread *td, struct linux_unlink_args *args) error = kern_funlinkat(td, AT_FDCWD, path, FD_NONE, UIO_SYSSPACE, 0, 0); if (error == EPERM) { /* Introduce POSIX noncompliant behaviour of Linux */ - if (kern_statat(td, 0, AT_FDCWD, path, UIO_SYSSPACE, &st, - NULL) == 0) { + if (kern_statat(td, 0, AT_FDCWD, path, UIO_SYSSPACE, + &st) == 0) { if (S_ISDIR(st.st_mode)) error = EISDIR; } @@ -769,7 +769,7 @@ linux_unlinkat_impl(struct thread *td, enum uio_seg pathseg, const char *path, if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) { /* Introduce POSIX noncompliant behaviour of Linux */ if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path, - pathseg, &st, NULL) == 0 && S_ISDIR(st.st_mode)) + pathseg, &st) == 0 && S_ISDIR(st.st_mode)) error = EISDIR; } return (error); diff --git a/sys/compat/linux/linux_stats.c b/sys/compat/linux/linux_stats.c index 58c378d6bc08..934fc6e5e740 100644 --- a/sys/compat/linux/linux_stats.c +++ b/sys/compat/linux/linux_stats.c @@ -29,17 +29,23 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include "opt_ktrace.h" + #include <sys/param.h> #include <sys/capsicum.h> #include <sys/dirent.h> #include <sys/lock.h> #include <sys/malloc.h> #include <sys/mutex.h> +#include <sys/namei.h> #include <sys/proc.h> #include <sys/stat.h> #include <sys/syscallsubr.h> #include <sys/tty.h> #include <sys/vnode.h> +#ifdef KTRACE +#include <sys/ktrace.h> +#endif #ifdef COMPAT_LINUX32 #include <machine/../linux32/linux.h> @@ -57,9 +63,33 @@ static int linux_kern_statat(struct thread *td, int flag, int fd, const char *path, enum uio_seg pathseg, struct stat *sbp) { + struct nameidata nd; + int error; + + if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH | + AT_EMPTY_PATH)) != 0) + return (EINVAL); + + NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_RESOLVE_BENEATH | + AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH) | LOCKSHARED | LOCKLEAF | + AUDITVNODE1, pathseg, path, fd, &cap_fstat_rights, td); - return (kern_statat(td, flag, fd, path, pathseg, sbp, - translate_vnhook_major_minor)); + if ((error = namei(&nd)) != 0) { + if (error == ENOTDIR && + (nd.ni_resflags & NIRES_EMPTYPATH) != 0) + error = kern_fstat(td, fd, sbp); + return (error); + } + error = VOP_STAT(nd.ni_vp, sbp, td->td_ucred, NOCRED, td); + if (error == 0) + translate_vnhook_major_minor(nd.ni_vp, sbp); + NDFREE_PNBUF(&nd); + vput(nd.ni_vp); +#ifdef KTRACE + if (KTRPOINT(td, KTR_STRUCT)) + ktrstat_error(sbp, error); +#endif + return (error); } #ifdef LINUX_LEGACY_SYSCALLS diff --git a/sys/kern/vfs_mountroot.c b/sys/kern/vfs_mountroot.c index 1886d3b7aca3..8a4b67836206 100644 --- a/sys/kern/vfs_mountroot.c +++ b/sys/kern/vfs_mountroot.c @@ -595,7 +595,7 @@ parse_dir_md(char **conf) free(tok, M_TEMP); /* Get file status. */ - error = kern_statat(td, 0, AT_FDCWD, path, UIO_SYSSPACE, &sb, NULL); + error = kern_statat(td, 0, AT_FDCWD, path, UIO_SYSSPACE, &sb); if (error) goto out; diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 3b3947b2ccb7..89f45e898d8e 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -109,7 +109,7 @@ static int kern_readlink_vp(struct vnode *vp, char *buf, enum uio_seg bufseg, static int kern_linkat_vp(struct thread *td, struct vnode *vp, int fd, const char *path, enum uio_seg segflag); -static uint64_t +uint64_t at2cnpflags(u_int at_flags, u_int mask) { u_int64_t res; @@ -2187,8 +2187,7 @@ ostat(struct thread *td, struct ostat_args *uap) struct ostat osb; int error; - error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, - &sb, NULL); + error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, &sb); if (error != 0) return (error); cvtstat(&sb, &osb); @@ -2212,7 +2211,7 @@ olstat(struct thread *td, struct olstat_args *uap) int error; error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path, - UIO_USERSPACE, &sb, NULL); + UIO_USERSPACE, &sb); if (error != 0) return (error); cvtstat(&sb, &osb); @@ -2330,8 +2329,7 @@ freebsd11_stat(struct thread *td, struct freebsd11_stat_args* uap) struct freebsd11_stat osb; int error; - error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, - &sb, NULL); + error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, &sb); if (error != 0) return (error); error = freebsd11_cvtstat(&sb, &osb); @@ -2348,7 +2346,7 @@ freebsd11_lstat(struct thread *td, struct freebsd11_lstat_args* uap) int error; error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path, - UIO_USERSPACE, &sb, NULL); + UIO_USERSPACE, &sb); if (error != 0) return (error); error = freebsd11_cvtstat(&sb, &osb); @@ -2385,7 +2383,7 @@ freebsd11_fstatat(struct thread *td, struct freebsd11_fstatat_args* uap) int error; error = kern_statat(td, uap->flag, uap->fd, uap->path, - UIO_USERSPACE, &sb, NULL); + UIO_USERSPACE, &sb); if (error != 0) return (error); error = freebsd11_cvtstat(&sb, &osb); @@ -2413,7 +2411,7 @@ sys_fstatat(struct thread *td, struct fstatat_args *uap) int error; error = kern_statat(td, uap->flag, uap->fd, uap->path, - UIO_USERSPACE, &sb, NULL); + UIO_USERSPACE, &sb); if (error == 0) error = copyout(&sb, uap->buf, sizeof (sb)); return (error); @@ -2421,8 +2419,7 @@ sys_fstatat(struct thread *td, struct fstatat_args *uap) int kern_statat(struct thread *td, int flag, int fd, const char *path, - enum uio_seg pathseg, struct stat *sbp, - void (*hook)(struct vnode *vp, struct stat *sbp)) + enum uio_seg pathseg, struct stat *sbp) { struct nameidata nd; int error; @@ -2435,17 +2432,9 @@ kern_statat(struct thread *td, int flag, int fd, const char *path, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH) | LOCKSHARED | LOCKLEAF | AUDITVNODE1, pathseg, path, fd, &cap_fstat_rights, td); - if ((error = namei(&nd)) != 0) { - if (error == ENOTDIR && - (nd.ni_resflags & NIRES_EMPTYPATH) != 0) - error = kern_fstat(td, fd, sbp); + if ((error = namei(&nd)) != 0) return (error); - } error = VOP_STAT(nd.ni_vp, sbp, td->td_ucred, NOCRED, td); - if (error == 0) { - if (__predict_false(hook != NULL)) - hook(nd.ni_vp, sbp); - } NDFREE_NOTHING(&nd); vput(nd.ni_vp); #ifdef __STAT_TIME_T_EXT @@ -2501,8 +2490,7 @@ freebsd11_nstat(struct thread *td, struct freebsd11_nstat_args *uap) struct nstat nsb; int error; - error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, - &sb, NULL); + error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, &sb); if (error != 0) return (error); freebsd11_cvtnstat(&sb, &nsb); @@ -2526,7 +2514,7 @@ freebsd11_nlstat(struct thread *td, struct freebsd11_nlstat_args *uap) int error; error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path, - UIO_USERSPACE, &sb, NULL); + UIO_USERSPACE, &sb); if (error != 0) return (error); freebsd11_cvtnstat(&sb, &nsb); diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h index ae17a10d01da..fb7bbe58a63a 100644 --- a/sys/sys/syscallsubr.h +++ b/sys/sys/syscallsubr.h @@ -80,6 +80,7 @@ struct mmap_req { mmap_check_fp_fn mr_check_fp_fn; }; +uint64_t at2cnpflags(u_int at_flags, u_int mask); int kern___getcwd(struct thread *td, char *buf, enum uio_seg bufseg, size_t buflen, size_t path_max); int kern_accept(struct thread *td, int s, struct sockaddr **name, @@ -312,8 +313,7 @@ int kern_sigqueue(struct thread *td, pid_t pid, int signum, union sigval *value); int kern_socket(struct thread *td, int domain, int type, int protocol); int kern_statat(struct thread *td, int flag, int fd, const char *path, - enum uio_seg pathseg, struct stat *sbp, - void (*hook)(struct vnode *vp, struct stat *sbp)); + enum uio_seg pathseg, struct stat *sbp); int kern_specialfd(struct thread *td, int type, void *arg); int kern_statfs(struct thread *td, const char *path, enum uio_seg pathseg, struct statfs *buf);