linux(4): Implement name_to_handle_at(), open_by_handle_at()
They are similar to our getfhat(2) and fhopen(2) syscalls. Differential Revision: https://reviews.freebsd.org/D27111
This commit is contained in:
parent
46a5f8837d
commit
de774e422e
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=367773
@ -1792,10 +1792,20 @@
|
||||
}
|
||||
; Linux 2.6.39 (glibc 2.14):
|
||||
303 AUE_NULL STD {
|
||||
int linux_name_to_handle_at(void);
|
||||
int linux_name_to_handle_at(
|
||||
l_int dirfd,
|
||||
const char *name,
|
||||
struct l_file_handle *handle,
|
||||
l_int *mnt_id,
|
||||
l_int flags
|
||||
);
|
||||
}
|
||||
304 AUE_NULL STD {
|
||||
int linux_open_by_handle_at(void);
|
||||
int linux_open_by_handle_at(
|
||||
l_int mountdirfd,
|
||||
struct l_file_handle *handle,
|
||||
l_int flags
|
||||
);
|
||||
}
|
||||
305 AUE_NULL STD {
|
||||
int linux_clock_adjtime(void);
|
||||
|
@ -1916,10 +1916,20 @@
|
||||
}
|
||||
; Linux 2.6.39:
|
||||
341 AUE_NULL STD {
|
||||
int linux_name_to_handle_at(void);
|
||||
int linux_name_to_handle_at(
|
||||
l_int dirfd,
|
||||
const char *name,
|
||||
struct l_file_handle *handle,
|
||||
l_int *mnt_id,
|
||||
l_int flags
|
||||
);
|
||||
}
|
||||
342 AUE_NULL STD {
|
||||
int linux_open_by_handle_at(void);
|
||||
int linux_open_by_handle_at(
|
||||
l_int mountdirfd,
|
||||
struct l_file_handle *handle,
|
||||
l_int flags
|
||||
);
|
||||
}
|
||||
343 AUE_NULL STD {
|
||||
int linux_clock_adjtime(void);
|
||||
|
@ -1473,10 +1473,20 @@
|
||||
int linux_fanotify_mark(void);
|
||||
}
|
||||
264 AUE_NULL STD {
|
||||
int linux_name_to_handle_at(void);
|
||||
int linux_name_to_handle_at(
|
||||
l_int dirfd,
|
||||
const char *name,
|
||||
struct l_file_handle *handle,
|
||||
l_int *mnt_id,
|
||||
l_int flags
|
||||
);
|
||||
}
|
||||
265 AUE_NULL STD {
|
||||
int linux_open_by_handle_at(void);
|
||||
int linux_open_by_handle_at(
|
||||
l_int mountdirfd,
|
||||
struct l_file_handle *handle,
|
||||
l_int flags
|
||||
);
|
||||
}
|
||||
266 AUE_NULL STD {
|
||||
int linux_clock_adjtime(void);
|
||||
|
@ -101,8 +101,6 @@ DUMMY(perf_event_open);
|
||||
DUMMY(fanotify_init);
|
||||
DUMMY(fanotify_mark);
|
||||
/* Linux 2.6.39: */
|
||||
DUMMY(name_to_handle_at);
|
||||
DUMMY(open_by_handle_at);
|
||||
DUMMY(clock_adjtime);
|
||||
/* Linux 3.0: */
|
||||
DUMMY(setns);
|
||||
|
@ -121,13 +121,9 @@ linux_creat(struct thread *td, struct linux_creat_args *args)
|
||||
#endif
|
||||
|
||||
static int
|
||||
linux_common_open(struct thread *td, int dirfd, const char *path, int l_flags,
|
||||
int mode, enum uio_seg seg)
|
||||
linux_common_openflags(int l_flags)
|
||||
{
|
||||
struct proc *p = td->td_proc;
|
||||
struct file *fp;
|
||||
int fd;
|
||||
int bsd_flags, error;
|
||||
int bsd_flags;
|
||||
|
||||
bsd_flags = 0;
|
||||
switch (l_flags & LINUX_O_ACCMODE) {
|
||||
@ -167,7 +163,19 @@ linux_common_open(struct thread *td, int dirfd, const char *path, int l_flags,
|
||||
if (l_flags & LINUX_O_DIRECTORY)
|
||||
bsd_flags |= O_DIRECTORY;
|
||||
/* XXX LINUX_O_NOATIME: unable to be easily implemented. */
|
||||
return (bsd_flags);
|
||||
}
|
||||
|
||||
static int
|
||||
linux_common_open(struct thread *td, int dirfd, const char *path, int l_flags,
|
||||
int mode, enum uio_seg seg)
|
||||
{
|
||||
struct proc *p = td->td_proc;
|
||||
struct file *fp;
|
||||
int fd;
|
||||
int bsd_flags, error;
|
||||
|
||||
bsd_flags = linux_common_openflags(l_flags);
|
||||
error = kern_openat(td, dirfd, path, seg, bsd_flags, mode);
|
||||
if (error != 0) {
|
||||
if (error == EMLINK)
|
||||
@ -254,6 +262,102 @@ linux_open(struct thread *td, struct linux_open_args *args)
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
linux_name_to_handle_at(struct thread *td,
|
||||
struct linux_name_to_handle_at_args *args)
|
||||
{
|
||||
static const l_int valid_flags = (LINUX_AT_SYMLINK_FOLLOW |
|
||||
LINUX_AT_EMPTY_PATH);
|
||||
static const l_uint fh_size = sizeof(fhandle_t);
|
||||
|
||||
fhandle_t fh;
|
||||
l_uint fh_bytes;
|
||||
l_int mount_id;
|
||||
int error, fd, bsd_flags;
|
||||
|
||||
if (args->flags & ~valid_flags)
|
||||
return (EINVAL);
|
||||
if (args->flags & LINUX_AT_EMPTY_PATH)
|
||||
/* XXX: not supported yet */
|
||||
return (EOPNOTSUPP);
|
||||
|
||||
fd = args->dirfd;
|
||||
if (fd == LINUX_AT_FDCWD)
|
||||
fd = AT_FDCWD;
|
||||
|
||||
bsd_flags = 0;
|
||||
if (!(args->flags & LINUX_AT_SYMLINK_FOLLOW))
|
||||
bsd_flags |= AT_SYMLINK_NOFOLLOW;
|
||||
|
||||
if (!LUSECONVPATH(td)) {
|
||||
error = kern_getfhat(td, bsd_flags, fd, args->name,
|
||||
UIO_USERSPACE, &fh, UIO_SYSSPACE);
|
||||
} else {
|
||||
char *path;
|
||||
|
||||
LCONVPATH_AT(td, args->name, &path, 0, fd);
|
||||
error = kern_getfhat(td, bsd_flags, fd, path, UIO_SYSSPACE,
|
||||
&fh, UIO_SYSSPACE);
|
||||
LFREEPATH(path);
|
||||
}
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
/* Emit mount_id -- required before EOVERFLOW case. */
|
||||
mount_id = (fh.fh_fsid.val[0] ^ fh.fh_fsid.val[1]);
|
||||
error = copyout(&mount_id, args->mnt_id, sizeof(mount_id));
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
/* Check if there is room for handle. */
|
||||
error = copyin(&args->handle->handle_bytes, &fh_bytes,
|
||||
sizeof(fh_bytes));
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
if (fh_bytes < fh_size) {
|
||||
error = copyout(&fh_size, &args->handle->handle_bytes,
|
||||
sizeof(fh_size));
|
||||
if (error == 0)
|
||||
error = EOVERFLOW;
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* Emit handle. */
|
||||
mount_id = 0;
|
||||
/*
|
||||
* We don't use handle_type for anything yet, but initialize a known
|
||||
* value.
|
||||
*/
|
||||
error = copyout(&mount_id, &args->handle->handle_type,
|
||||
sizeof(mount_id));
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
error = copyout(&fh, &args->handle->f_handle,
|
||||
sizeof(fh));
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
linux_open_by_handle_at(struct thread *td,
|
||||
struct linux_open_by_handle_at_args *args)
|
||||
{
|
||||
l_uint fh_bytes;
|
||||
int bsd_flags, error;
|
||||
|
||||
error = copyin(&args->handle->handle_bytes, &fh_bytes,
|
||||
sizeof(fh_bytes));
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
if (fh_bytes < sizeof(fhandle_t))
|
||||
return (EINVAL);
|
||||
|
||||
bsd_flags = linux_common_openflags(args->flags);
|
||||
return (kern_fhopen(td, (void *)&args->handle->f_handle, bsd_flags));
|
||||
}
|
||||
|
||||
int
|
||||
linux_lseek(struct thread *td, struct linux_lseek_args *args)
|
||||
{
|
||||
|
@ -36,6 +36,7 @@
|
||||
#define LINUX_AT_EACCESS 0x200
|
||||
#define LINUX_AT_REMOVEDIR 0x200
|
||||
#define LINUX_AT_SYMLINK_FOLLOW 0x400
|
||||
#define LINUX_AT_EMPTY_PATH 0x1000
|
||||
|
||||
/*
|
||||
* posix_fadvise advice
|
||||
@ -174,4 +175,10 @@
|
||||
#define LINUX_HUGETLB_FLAG_ENCODE_2GB (31 << LINUX_HUGETLB_FLAG_ENCODE_SHIFT)
|
||||
#define LINUX_HUGETLB_FLAG_ENCODE_16GB (34U << LINUX_HUGETLB_FLAG_ENCODE_SHIFT)
|
||||
|
||||
struct l_file_handle {
|
||||
l_uint handle_bytes;
|
||||
l_int handle_type;
|
||||
unsigned char f_handle[0];
|
||||
};
|
||||
|
||||
#endif /* !_LINUX_FILE_H_ */
|
||||
|
@ -1934,10 +1934,20 @@
|
||||
}
|
||||
; Linux 2.6.39:
|
||||
341 AUE_NULL STD {
|
||||
int linux_name_to_handle_at(void);
|
||||
int linux_name_to_handle_at(
|
||||
l_int dirfd,
|
||||
const char *name,
|
||||
struct l_file_handle *handle,
|
||||
l_int *mnt_id,
|
||||
l_int flags
|
||||
);
|
||||
}
|
||||
342 AUE_NULL STD {
|
||||
int linux_open_by_handle_at(void);
|
||||
int linux_open_by_handle_at(
|
||||
l_int mountdirfd,
|
||||
struct l_file_handle *handle,
|
||||
l_int flags
|
||||
);
|
||||
}
|
||||
343 AUE_NULL STD {
|
||||
int linux_clock_adjtime(void);
|
||||
|
@ -105,8 +105,6 @@ static int vn_access(struct vnode *vp, int user_flags, struct ucred *cred,
|
||||
struct thread *td);
|
||||
static int kern_fhlinkat(struct thread *td, int fd, const char *path,
|
||||
enum uio_seg pathseg, fhandle_t *fhp);
|
||||
static int kern_getfhat(struct thread *td, int flags, int fd,
|
||||
const char *path, enum uio_seg pathseg, fhandle_t *fhp);
|
||||
static int kern_readlink_vp(struct vnode *vp, char *buf, enum uio_seg bufseg,
|
||||
size_t count, struct thread *td);
|
||||
static int kern_linkat_vp(struct thread *td, struct vnode *vp, int fd,
|
||||
@ -4315,7 +4313,7 @@ sys_lgetfh(struct thread *td, struct lgetfh_args *uap)
|
||||
{
|
||||
|
||||
return (kern_getfhat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->fname,
|
||||
UIO_USERSPACE, uap->fhp));
|
||||
UIO_USERSPACE, uap->fhp, UIO_USERSPACE));
|
||||
}
|
||||
|
||||
#ifndef _SYS_SYSPROTO_H_
|
||||
@ -4329,7 +4327,7 @@ sys_getfh(struct thread *td, struct getfh_args *uap)
|
||||
{
|
||||
|
||||
return (kern_getfhat(td, 0, AT_FDCWD, uap->fname, UIO_USERSPACE,
|
||||
uap->fhp));
|
||||
uap->fhp, UIO_USERSPACE));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -4355,12 +4353,12 @@ sys_getfhat(struct thread *td, struct getfhat_args *uap)
|
||||
AT_RESOLVE_BENEATH)) != 0)
|
||||
return (EINVAL);
|
||||
return (kern_getfhat(td, uap->flags, uap->fd, uap->path, UIO_USERSPACE,
|
||||
uap->fhp));
|
||||
uap->fhp, UIO_USERSPACE));
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
kern_getfhat(struct thread *td, int flags, int fd, const char *path,
|
||||
enum uio_seg pathseg, fhandle_t *fhp)
|
||||
enum uio_seg pathseg, fhandle_t *fhp, enum uio_seg fhseg)
|
||||
{
|
||||
struct nameidata nd;
|
||||
fhandle_t fh;
|
||||
@ -4382,8 +4380,12 @@ kern_getfhat(struct thread *td, int flags, int fd, const char *path,
|
||||
fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
|
||||
error = VOP_VPTOFH(vp, &fh.fh_fid);
|
||||
vput(vp);
|
||||
if (error == 0)
|
||||
error = copyout(&fh, fhp, sizeof (fh));
|
||||
if (error == 0) {
|
||||
if (fhseg == UIO_USERSPACE)
|
||||
error = copyout(&fh, fhp, sizeof (fh));
|
||||
else
|
||||
memcpy(fhp, &fh, sizeof(fh));
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -4492,6 +4494,12 @@ struct fhopen_args {
|
||||
#endif
|
||||
int
|
||||
sys_fhopen(struct thread *td, struct fhopen_args *uap)
|
||||
{
|
||||
return (kern_fhopen(td, uap->u_fhp, uap->flags));
|
||||
}
|
||||
|
||||
int
|
||||
kern_fhopen(struct thread *td, const struct fhandle *u_fhp, int flags)
|
||||
{
|
||||
struct mount *mp;
|
||||
struct vnode *vp;
|
||||
@ -4504,11 +4512,11 @@ sys_fhopen(struct thread *td, struct fhopen_args *uap)
|
||||
if (error != 0)
|
||||
return (error);
|
||||
indx = -1;
|
||||
fmode = FFLAGS(uap->flags);
|
||||
fmode = FFLAGS(flags);
|
||||
/* why not allow a non-read/write open for our lockd? */
|
||||
if (((fmode & (FREAD | FWRITE)) == 0) || (fmode & O_CREAT))
|
||||
return (EINVAL);
|
||||
error = copyin(uap->u_fhp, &fhp, sizeof(fhp));
|
||||
error = copyin(u_fhp, &fhp, sizeof(fhp));
|
||||
if (error != 0)
|
||||
return(error);
|
||||
/* find the mount point */
|
||||
|
@ -140,6 +140,7 @@ int kern_fchownat(struct thread *td, int fd, const char *path,
|
||||
enum uio_seg pathseg, int uid, int gid, int flag);
|
||||
int kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg);
|
||||
int kern_fcntl_freebsd(struct thread *td, int fd, int cmd, long arg);
|
||||
int kern_fhopen(struct thread *td, const struct fhandle *u_fhp, int flags);
|
||||
int kern_fhstat(struct thread *td, fhandle_t fh, struct stat *buf);
|
||||
int kern_fhstatfs(struct thread *td, fhandle_t fh, struct statfs *buf);
|
||||
int kern_fpathconf(struct thread *td, int fd, int name, long *valuep);
|
||||
@ -153,6 +154,8 @@ int kern_futimens(struct thread *td, int fd, struct timespec *tptr,
|
||||
enum uio_seg tptrseg);
|
||||
int kern_getdirentries(struct thread *td, int fd, char *buf, size_t count,
|
||||
off_t *basep, ssize_t *residp, enum uio_seg bufseg);
|
||||
int kern_getfhat(struct thread *td, int flags, int fd, const char *path,
|
||||
enum uio_seg pathseg, fhandle_t *fhp, enum uio_seg fhseg);
|
||||
int kern_getfsstat(struct thread *td, struct statfs **buf, size_t bufsize,
|
||||
size_t *countp, enum uio_seg bufseg, int mode);
|
||||
int kern_getitimer(struct thread *, u_int, struct itimerval *);
|
||||
|
Loading…
Reference in New Issue
Block a user