Skip to content

Commit

Permalink
vfs: Add name to file handle conversion support
Browse files Browse the repository at this point in the history
The syscall also return mount id which can be used
to lookup file system specific information such as uuid
in /proc/<pid>/mountinfo

Signed-off-by: Aneesh Kumar K.V <[email protected]>
Signed-off-by: Al Viro <[email protected]>
  • Loading branch information
kvaneesh authored and Al Viro committed Mar 15, 2011
1 parent f52e0c1 commit 990d6c2
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 2 deletions.
2 changes: 1 addition & 1 deletion fs/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ config FS_POSIX_ACL
def_bool n

config EXPORTFS
tristate
bool

config FILE_LOCKING
bool "Enable POSIX file locking API" if EXPERT
Expand Down
2 changes: 2 additions & 0 deletions fs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o
obj-$(CONFIG_NFS_COMMON) += nfs_common/
obj-$(CONFIG_GENERIC_ACL) += generic_acl.o

obj-$(CONFIG_FHANDLE) += fhandle.o

obj-y += quota/

obj-$(CONFIG_PROC_FS) += proc/
Expand Down
107 changes: 107 additions & 0 deletions fs/fhandle.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#include <linux/syscalls.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/exportfs.h>
#include <asm/uaccess.h>
#include "internal.h"

static long do_sys_name_to_handle(struct path *path,
struct file_handle __user *ufh,
int __user *mnt_id)
{
long retval;
struct file_handle f_handle;
int handle_dwords, handle_bytes;
struct file_handle *handle = NULL;

/*
* We need t make sure wether the file system
* support decoding of the file handle
*/
if (!path->mnt->mnt_sb->s_export_op ||
!path->mnt->mnt_sb->s_export_op->fh_to_dentry)
return -EOPNOTSUPP;

if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle)))
return -EFAULT;

if (f_handle.handle_bytes > MAX_HANDLE_SZ)
return -EINVAL;

handle = kmalloc(sizeof(struct file_handle) + f_handle.handle_bytes,
GFP_KERNEL);
if (!handle)
return -ENOMEM;

/* convert handle size to multiple of sizeof(u32) */
handle_dwords = f_handle.handle_bytes >> 2;

/* we ask for a non connected handle */
retval = exportfs_encode_fh(path->dentry,
(struct fid *)handle->f_handle,
&handle_dwords, 0);
handle->handle_type = retval;
/* convert handle size to bytes */
handle_bytes = handle_dwords * sizeof(u32);
handle->handle_bytes = handle_bytes;
if ((handle->handle_bytes > f_handle.handle_bytes) ||
(retval == 255) || (retval == -ENOSPC)) {
/* As per old exportfs_encode_fh documentation
* we could return ENOSPC to indicate overflow
* But file system returned 255 always. So handle
* both the values
*/
/*
* set the handle size to zero so we copy only
* non variable part of the file_handle
*/
handle_bytes = 0;
retval = -EOVERFLOW;
} else
retval = 0;
/* copy the mount id */
if (copy_to_user(mnt_id, &path->mnt->mnt_id, sizeof(*mnt_id)) ||
copy_to_user(ufh, handle,
sizeof(struct file_handle) + handle_bytes))
retval = -EFAULT;
kfree(handle);
return retval;
}

/**
* sys_name_to_handle_at: convert name to handle
* @dfd: directory relative to which name is interpreted if not absolute
* @name: name that should be converted to handle.
* @handle: resulting file handle
* @mnt_id: mount id of the file system containing the file
* @flag: flag value to indicate whether to follow symlink or not
*
* @handle->handle_size indicate the space available to store the
* variable part of the file handle in bytes. If there is not
* enough space, the field is updated to return the minimum
* value required.
*/
SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name,
struct file_handle __user *, handle, int __user *, mnt_id,
int, flag)
{
struct path path;
int lookup_flags;
int err;

if ((flag & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0)
return -EINVAL;

lookup_flags = (flag & AT_SYMLINK_FOLLOW) ? LOOKUP_FOLLOW : 0;
if (flag & AT_EMPTY_PATH)
lookup_flags |= LOOKUP_EMPTY;
err = user_path_at(dfd, name, lookup_flags, &path);
if (!err) {
err = do_sys_name_to_handle(&path, handle, mnt_id);
path_put(&path);
}
return err;
}
3 changes: 3 additions & 0 deletions include/linux/exportfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ struct inode;
struct super_block;
struct vfsmount;

/* limit the handle size to NFSv4 handle size now */
#define MAX_HANDLE_SZ 128

/*
* The fileid_type identifies how the file within the filesystem is encoded.
* In theory this is freely set and parsed by the filesystem, but we try to
Expand Down
7 changes: 7 additions & 0 deletions include/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,13 @@ struct file {
#endif
};

struct file_handle {
__u32 handle_bytes;
int handle_type;
/* file identifier */
unsigned char f_handle[0];
};

#define get_file(x) atomic_long_inc(&(x)->f_count)
#define fput_atomic(x) atomic_long_add_unless(&(x)->f_count, -1, 1)
#define file_count(x) atomic_long_read(&(x)->f_count)
Expand Down
5 changes: 4 additions & 1 deletion include/linux/syscalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ struct robust_list_head;
struct getcpu_cache;
struct old_linux_dirent;
struct perf_event_attr;
struct file_handle;

#include <linux/types.h>
#include <linux/aio_abi.h>
Expand Down Expand Up @@ -832,5 +833,7 @@ asmlinkage long sys_mmap_pgoff(unsigned long addr, unsigned long len,
unsigned long prot, unsigned long flags,
unsigned long fd, unsigned long pgoff);
asmlinkage long sys_old_mmap(struct mmap_arg_struct __user *arg);

asmlinkage long sys_name_to_handle_at(int dfd, const char __user *name,
struct file_handle __user *handle,
int __user *mnt_id, int flag);
#endif
12 changes: 12 additions & 0 deletions init/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,18 @@ config BSD_PROCESS_ACCT_V3
for processing it. A preliminary version of these tools is available
at <http://www.gnu.org/software/acct/>.

config FHANDLE
bool "open by fhandle syscalls"
select EXPORTFS
help
If you say Y here, a user level program will be able to map
file names to handle and then later use the handle for
different file system operations. This is useful in implementing
userspace file servers, which now track files using handles instead
of names. The handle would remain the same even if file names
get renamed. Enables open_by_handle_at(2) and name_to_handle_at(2)
syscalls.

config TASKSTATS
bool "Export task/process statistics through netlink (EXPERIMENTAL)"
depends on NET
Expand Down
3 changes: 3 additions & 0 deletions kernel/sys_ni.c
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,6 @@ cond_syscall(sys_perf_event_open);
/* fanotify! */
cond_syscall(sys_fanotify_init);
cond_syscall(sys_fanotify_mark);

/* open by handle */
cond_syscall(sys_name_to_handle_at);

0 comments on commit 990d6c2

Please sign in to comment.