The branch stable/13 has been updated by dchagin:

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

commit 6c324fb645e64e0090e16a5846eafdeb723f4105
Author:     Dmitry Chagin <[email protected]>
AuthorDate: 2023-04-28 08:55:04 +0000
Commit:     Dmitry Chagin <[email protected]>
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);

Reply via email to