diff options
author | Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> | 2011-01-29 08:13:26 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2011-03-15 02:21:37 -0400 |
commit | 990d6c2d7aee921e3bce22b2d6a750fd552262be (patch) | |
tree | af273c4bfbfd0342d39d05d5a017382eb32a7538 | |
parent | f52e0c11305aa09ed56cad97ffc8f0cdc3d78b5d (diff) |
vfs: Add name to file handle conversion support
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 <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/Kconfig | 2 | ||||
-rw-r--r-- | fs/Makefile | 2 | ||||
-rw-r--r-- | fs/fhandle.c | 107 | ||||
-rw-r--r-- | include/linux/exportfs.h | 3 | ||||
-rw-r--r-- | include/linux/fs.h | 7 | ||||
-rw-r--r-- | include/linux/syscalls.h | 5 | ||||
-rw-r--r-- | init/Kconfig | 12 | ||||
-rw-r--r-- | kernel/sys_ni.c | 3 |
8 files changed, 139 insertions, 2 deletions
diff --git a/fs/Kconfig b/fs/Kconfig index 3db9caa57edc..7cb53aafac1e 100644 --- a/fs/Kconfig +++ b/fs/Kconfig | |||
@@ -47,7 +47,7 @@ config FS_POSIX_ACL | |||
47 | def_bool n | 47 | def_bool n |
48 | 48 | ||
49 | config EXPORTFS | 49 | config EXPORTFS |
50 | tristate | 50 | bool |
51 | 51 | ||
52 | config FILE_LOCKING | 52 | config FILE_LOCKING |
53 | bool "Enable POSIX file locking API" if EXPERT | 53 | bool "Enable POSIX file locking API" if EXPERT |
diff --git a/fs/Makefile b/fs/Makefile index a7f7cef0c0c8..ba01202844c5 100644 --- a/fs/Makefile +++ b/fs/Makefile | |||
@@ -48,6 +48,8 @@ obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o | |||
48 | obj-$(CONFIG_NFS_COMMON) += nfs_common/ | 48 | obj-$(CONFIG_NFS_COMMON) += nfs_common/ |
49 | obj-$(CONFIG_GENERIC_ACL) += generic_acl.o | 49 | obj-$(CONFIG_GENERIC_ACL) += generic_acl.o |
50 | 50 | ||
51 | obj-$(CONFIG_FHANDLE) += fhandle.o | ||
52 | |||
51 | obj-y += quota/ | 53 | obj-y += quota/ |
52 | 54 | ||
53 | obj-$(CONFIG_PROC_FS) += proc/ | 55 | obj-$(CONFIG_PROC_FS) += proc/ |
diff --git a/fs/fhandle.c b/fs/fhandle.c new file mode 100644 index 000000000000..9f79e743a840 --- /dev/null +++ b/fs/fhandle.c | |||
@@ -0,0 +1,107 @@ | |||
1 | #include <linux/syscalls.h> | ||
2 | #include <linux/slab.h> | ||
3 | #include <linux/fs.h> | ||
4 | #include <linux/file.h> | ||
5 | #include <linux/mount.h> | ||
6 | #include <linux/namei.h> | ||
7 | #include <linux/exportfs.h> | ||
8 | #include <asm/uaccess.h> | ||
9 | #include "internal.h" | ||
10 | |||
11 | static long do_sys_name_to_handle(struct path *path, | ||
12 | struct file_handle __user *ufh, | ||
13 | int __user *mnt_id) | ||
14 | { | ||
15 | long retval; | ||
16 | struct file_handle f_handle; | ||
17 | int handle_dwords, handle_bytes; | ||
18 | struct file_handle *handle = NULL; | ||
19 | |||
20 | /* | ||
21 | * We need t make sure wether the file system | ||
22 | * support decoding of the file handle | ||
23 | */ | ||
24 | if (!path->mnt->mnt_sb->s_export_op || | ||
25 | !path->mnt->mnt_sb->s_export_op->fh_to_dentry) | ||
26 | return -EOPNOTSUPP; | ||
27 | |||
28 | if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle))) | ||
29 | return -EFAULT; | ||
30 | |||
31 | if (f_handle.handle_bytes > MAX_HANDLE_SZ) | ||
32 | return -EINVAL; | ||
33 | |||
34 | handle = kmalloc(sizeof(struct file_handle) + f_handle.handle_bytes, | ||
35 | GFP_KERNEL); | ||
36 | if (!handle) | ||
37 | return -ENOMEM; | ||
38 | |||
39 | /* convert handle size to multiple of sizeof(u32) */ | ||
40 | handle_dwords = f_handle.handle_bytes >> 2; | ||
41 | |||
42 | /* we ask for a non connected handle */ | ||
43 | retval = exportfs_encode_fh(path->dentry, | ||
44 | (struct fid *)handle->f_handle, | ||
45 | &handle_dwords, 0); | ||
46 | handle->handle_type = retval; | ||
47 | /* convert handle size to bytes */ | ||
48 | handle_bytes = handle_dwords * sizeof(u32); | ||
49 | handle->handle_bytes = handle_bytes; | ||
50 | if ((handle->handle_bytes > f_handle.handle_bytes) || | ||
51 | (retval == 255) || (retval == -ENOSPC)) { | ||
52 | /* As per old exportfs_encode_fh documentation | ||
53 | * we could return ENOSPC to indicate overflow | ||
54 | * But file system returned 255 always. So handle | ||
55 | * both the values | ||
56 | */ | ||
57 | /* | ||
58 | * set the handle size to zero so we copy only | ||
59 | * non variable part of the file_handle | ||
60 | */ | ||
61 | handle_bytes = 0; | ||
62 | retval = -EOVERFLOW; | ||
63 | } else | ||
64 | retval = 0; | ||
65 | /* copy the mount id */ | ||
66 | if (copy_to_user(mnt_id, &path->mnt->mnt_id, sizeof(*mnt_id)) || | ||
67 | copy_to_user(ufh, handle, | ||
68 | sizeof(struct file_handle) + handle_bytes)) | ||
69 | retval = -EFAULT; | ||
70 | kfree(handle); | ||
71 | return retval; | ||
72 | } | ||
73 | |||
74 | /** | ||
75 | * sys_name_to_handle_at: convert name to handle | ||
76 | * @dfd: directory relative to which name is interpreted if not absolute | ||
77 | * @name: name that should be converted to handle. | ||
78 | * @handle: resulting file handle | ||
79 | * @mnt_id: mount id of the file system containing the file | ||
80 | * @flag: flag value to indicate whether to follow symlink or not | ||
81 | * | ||
82 | * @handle->handle_size indicate the space available to store the | ||
83 | * variable part of the file handle in bytes. If there is not | ||
84 | * enough space, the field is updated to return the minimum | ||
85 | * value required. | ||
86 | */ | ||
87 | SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name, | ||
88 | struct file_handle __user *, handle, int __user *, mnt_id, | ||
89 | int, flag) | ||
90 | { | ||
91 | struct path path; | ||
92 | int lookup_flags; | ||
93 | int err; | ||
94 | |||
95 | if ((flag & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0) | ||
96 | return -EINVAL; | ||
97 | |||
98 | lookup_flags = (flag & AT_SYMLINK_FOLLOW) ? LOOKUP_FOLLOW : 0; | ||
99 | if (flag & AT_EMPTY_PATH) | ||
100 | lookup_flags |= LOOKUP_EMPTY; | ||
101 | err = user_path_at(dfd, name, lookup_flags, &path); | ||
102 | if (!err) { | ||
103 | err = do_sys_name_to_handle(&path, handle, mnt_id); | ||
104 | path_put(&path); | ||
105 | } | ||
106 | return err; | ||
107 | } | ||
diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h index 65afdfd31b7b..33a42f24b275 100644 --- a/include/linux/exportfs.h +++ b/include/linux/exportfs.h | |||
@@ -8,6 +8,9 @@ struct inode; | |||
8 | struct super_block; | 8 | struct super_block; |
9 | struct vfsmount; | 9 | struct vfsmount; |
10 | 10 | ||
11 | /* limit the handle size to NFSv4 handle size now */ | ||
12 | #define MAX_HANDLE_SZ 128 | ||
13 | |||
11 | /* | 14 | /* |
12 | * The fileid_type identifies how the file within the filesystem is encoded. | 15 | * The fileid_type identifies how the file within the filesystem is encoded. |
13 | * In theory this is freely set and parsed by the filesystem, but we try to | 16 | * In theory this is freely set and parsed by the filesystem, but we try to |
diff --git a/include/linux/fs.h b/include/linux/fs.h index b7178b05cf3a..3f64630c0e10 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -978,6 +978,13 @@ struct file { | |||
978 | #endif | 978 | #endif |
979 | }; | 979 | }; |
980 | 980 | ||
981 | struct file_handle { | ||
982 | __u32 handle_bytes; | ||
983 | int handle_type; | ||
984 | /* file identifier */ | ||
985 | unsigned char f_handle[0]; | ||
986 | }; | ||
987 | |||
981 | #define get_file(x) atomic_long_inc(&(x)->f_count) | 988 | #define get_file(x) atomic_long_inc(&(x)->f_count) |
982 | #define fput_atomic(x) atomic_long_add_unless(&(x)->f_count, -1, 1) | 989 | #define fput_atomic(x) atomic_long_add_unless(&(x)->f_count, -1, 1) |
983 | #define file_count(x) atomic_long_read(&(x)->f_count) | 990 | #define file_count(x) atomic_long_read(&(x)->f_count) |
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 98664db1be47..970112613fb4 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h | |||
@@ -62,6 +62,7 @@ struct robust_list_head; | |||
62 | struct getcpu_cache; | 62 | struct getcpu_cache; |
63 | struct old_linux_dirent; | 63 | struct old_linux_dirent; |
64 | struct perf_event_attr; | 64 | struct perf_event_attr; |
65 | struct file_handle; | ||
65 | 66 | ||
66 | #include <linux/types.h> | 67 | #include <linux/types.h> |
67 | #include <linux/aio_abi.h> | 68 | #include <linux/aio_abi.h> |
@@ -832,5 +833,7 @@ asmlinkage long sys_mmap_pgoff(unsigned long addr, unsigned long len, | |||
832 | unsigned long prot, unsigned long flags, | 833 | unsigned long prot, unsigned long flags, |
833 | unsigned long fd, unsigned long pgoff); | 834 | unsigned long fd, unsigned long pgoff); |
834 | asmlinkage long sys_old_mmap(struct mmap_arg_struct __user *arg); | 835 | asmlinkage long sys_old_mmap(struct mmap_arg_struct __user *arg); |
835 | 836 | asmlinkage long sys_name_to_handle_at(int dfd, const char __user *name, | |
837 | struct file_handle __user *handle, | ||
838 | int __user *mnt_id, int flag); | ||
836 | #endif | 839 | #endif |
diff --git a/init/Kconfig b/init/Kconfig index be788c0957d4..e72fa17fe559 100644 --- a/init/Kconfig +++ b/init/Kconfig | |||
@@ -287,6 +287,18 @@ config BSD_PROCESS_ACCT_V3 | |||
287 | for processing it. A preliminary version of these tools is available | 287 | for processing it. A preliminary version of these tools is available |
288 | at <http://www.gnu.org/software/acct/>. | 288 | at <http://www.gnu.org/software/acct/>. |
289 | 289 | ||
290 | config FHANDLE | ||
291 | bool "open by fhandle syscalls" | ||
292 | select EXPORTFS | ||
293 | help | ||
294 | If you say Y here, a user level program will be able to map | ||
295 | file names to handle and then later use the handle for | ||
296 | different file system operations. This is useful in implementing | ||
297 | userspace file servers, which now track files using handles instead | ||
298 | of names. The handle would remain the same even if file names | ||
299 | get renamed. Enables open_by_handle_at(2) and name_to_handle_at(2) | ||
300 | syscalls. | ||
301 | |||
290 | config TASKSTATS | 302 | config TASKSTATS |
291 | bool "Export task/process statistics through netlink (EXPERIMENTAL)" | 303 | bool "Export task/process statistics through netlink (EXPERIMENTAL)" |
292 | depends on NET | 304 | depends on NET |
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index c782fe9924c7..4e013439ac28 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c | |||
@@ -186,3 +186,6 @@ cond_syscall(sys_perf_event_open); | |||
186 | /* fanotify! */ | 186 | /* fanotify! */ |
187 | cond_syscall(sys_fanotify_init); | 187 | cond_syscall(sys_fanotify_init); |
188 | cond_syscall(sys_fanotify_mark); | 188 | cond_syscall(sys_fanotify_mark); |
189 | |||
190 | /* open by handle */ | ||
191 | cond_syscall(sys_name_to_handle_at); | ||