aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fhandle.c
diff options
context:
space:
mode:
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>2011-01-29 08:13:26 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2011-03-15 02:21:37 -0400
commit990d6c2d7aee921e3bce22b2d6a750fd552262be (patch)
treeaf273c4bfbfd0342d39d05d5a017382eb32a7538 /fs/fhandle.c
parentf52e0c11305aa09ed56cad97ffc8f0cdc3d78b5d (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>
Diffstat (limited to 'fs/fhandle.c')
-rw-r--r--fs/fhandle.c107
1 files changed, 107 insertions, 0 deletions
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
11static 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 */
87SYSCALL_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}