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
This commit is contained in:
parent
80d8a4a003
commit
cb858340dc
@ -2284,8 +2284,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);
|
||||
@ -2334,7 +2333,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);
|
||||
@ -2351,7 +2350,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);
|
||||
@ -2469,8 +2468,7 @@ freebsd11_freebsd32_stat(struct thread *td,
|
||||
struct freebsd11_stat32 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 != 0)
|
||||
return (error);
|
||||
error = freebsd11_cvtstat32(&sb, &sb32);
|
||||
@ -2505,7 +2503,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);
|
||||
@ -2523,7 +2521,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);
|
||||
@ -2595,8 +2593,7 @@ freebsd11_freebsd32_nstat(struct thread *td,
|
||||
struct nstat32 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);
|
||||
error = freebsd11_cvtnstat32(&sb, &nsb);
|
||||
@ -2614,7 +2611,7 @@ freebsd11_freebsd32_nlstat(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_cvtnstat32(&sb, &nsb);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
return (kern_statat(td, flag, fd, path, pathseg, sbp,
|
||||
translate_vnhook_major_minor));
|
||||
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);
|
||||
|
||||
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);
|
||||
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
|
||||
|
@ -594,7 +594,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;
|
||||
|
||||
|
@ -110,7 +110,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)
|
||||
{
|
||||
uint64_t res;
|
||||
@ -2193,8 +2193,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);
|
||||
@ -2218,7 +2217,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);
|
||||
@ -2336,8 +2335,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);
|
||||
@ -2354,7 +2352,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);
|
||||
@ -2391,7 +2389,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);
|
||||
@ -2419,7 +2417,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);
|
||||
@ -2427,8 +2425,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;
|
||||
@ -2441,18 +2438,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);
|
||||
|
||||
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);
|
||||
if (__predict_false(hook != NULL)) {
|
||||
if (error == 0) {
|
||||
hook(nd.ni_vp, sbp);
|
||||
}
|
||||
}
|
||||
NDFREE_PNBUF(&nd);
|
||||
vput(nd.ni_vp);
|
||||
#ifdef __STAT_TIME_T_EXT
|
||||
@ -2515,8 +2503,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);
|
||||
error = freebsd11_cvtnstat(&sb, &nsb);
|
||||
@ -2542,7 +2529,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);
|
||||
error = freebsd11_cvtnstat(&sb, &nsb);
|
||||
|
@ -81,6 +81,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_abort2(struct thread *td, const char *why, int nargs,
|
||||
@ -319,8 +320,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);
|
||||
|
Loading…
Reference in New Issue
Block a user