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:
Conrad Meyer 2020-11-17 19:51:47 +00:00
parent 46a5f8837d
commit de774e422e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=367773
9 changed files with 187 additions and 27 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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)
{

View File

@ -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_ */

View File

@ -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);

View File

@ -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 */

View File

@ -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 *);