forked from mirrors/linux
		
	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>
This commit is contained in:
		
							parent
							
								
									f52e0c1130
								
							
						
					
					
						commit
						990d6c2d7a
					
				
					 8 changed files with 139 additions and 2 deletions
				
			
		| 
						 | 
					@ -47,7 +47,7 @@ config FS_POSIX_ACL
 | 
				
			||||||
	def_bool n
 | 
						def_bool n
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config EXPORTFS
 | 
					config EXPORTFS
 | 
				
			||||||
	tristate
 | 
						bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config FILE_LOCKING
 | 
					config FILE_LOCKING
 | 
				
			||||||
	bool "Enable POSIX file locking API" if EXPERT
 | 
						bool "Enable POSIX file locking API" if EXPERT
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -48,6 +48,8 @@ obj-$(CONFIG_FS_POSIX_ACL)	+= posix_acl.o xattr_acl.o
 | 
				
			||||||
obj-$(CONFIG_NFS_COMMON)	+= nfs_common/
 | 
					obj-$(CONFIG_NFS_COMMON)	+= nfs_common/
 | 
				
			||||||
obj-$(CONFIG_GENERIC_ACL)	+= generic_acl.o
 | 
					obj-$(CONFIG_GENERIC_ACL)	+= generic_acl.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					obj-$(CONFIG_FHANDLE)		+= fhandle.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
obj-y				+= quota/
 | 
					obj-y				+= quota/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
obj-$(CONFIG_PROC_FS)		+= proc/
 | 
					obj-$(CONFIG_PROC_FS)		+= proc/
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										107
									
								
								fs/fhandle.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								fs/fhandle.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,9 @@ struct inode;
 | 
				
			||||||
struct super_block;
 | 
					struct super_block;
 | 
				
			||||||
struct vfsmount;
 | 
					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.
 | 
					 * 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
 | 
					 * In theory this is freely set and parsed by the filesystem, but we try to
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -978,6 +978,13 @@ struct file {
 | 
				
			||||||
#endif
 | 
					#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 get_file(x)	atomic_long_inc(&(x)->f_count)
 | 
				
			||||||
#define fput_atomic(x)	atomic_long_add_unless(&(x)->f_count, -1, 1)
 | 
					#define fput_atomic(x)	atomic_long_add_unless(&(x)->f_count, -1, 1)
 | 
				
			||||||
#define file_count(x)	atomic_long_read(&(x)->f_count)
 | 
					#define file_count(x)	atomic_long_read(&(x)->f_count)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -62,6 +62,7 @@ struct robust_list_head;
 | 
				
			||||||
struct getcpu_cache;
 | 
					struct getcpu_cache;
 | 
				
			||||||
struct old_linux_dirent;
 | 
					struct old_linux_dirent;
 | 
				
			||||||
struct perf_event_attr;
 | 
					struct perf_event_attr;
 | 
				
			||||||
 | 
					struct file_handle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/types.h>
 | 
					#include <linux/types.h>
 | 
				
			||||||
#include <linux/aio_abi.h>
 | 
					#include <linux/aio_abi.h>
 | 
				
			||||||
| 
						 | 
					@ -832,5 +833,7 @@ asmlinkage long sys_mmap_pgoff(unsigned long addr, unsigned long len,
 | 
				
			||||||
			unsigned long prot, unsigned long flags,
 | 
								unsigned long prot, unsigned long flags,
 | 
				
			||||||
			unsigned long fd, unsigned long pgoff);
 | 
								unsigned long fd, unsigned long pgoff);
 | 
				
			||||||
asmlinkage long sys_old_mmap(struct mmap_arg_struct __user *arg);
 | 
					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
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										12
									
								
								init/Kconfig
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								init/Kconfig
									
									
									
									
									
								
							| 
						 | 
					@ -287,6 +287,18 @@ config BSD_PROCESS_ACCT_V3
 | 
				
			||||||
	  for processing it. A preliminary version of these tools is available
 | 
						  for processing it. A preliminary version of these tools is available
 | 
				
			||||||
	  at <http://www.gnu.org/software/acct/>.
 | 
						  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
 | 
					config TASKSTATS
 | 
				
			||||||
	bool "Export task/process statistics through netlink (EXPERIMENTAL)"
 | 
						bool "Export task/process statistics through netlink (EXPERIMENTAL)"
 | 
				
			||||||
	depends on NET
 | 
						depends on NET
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -186,3 +186,6 @@ cond_syscall(sys_perf_event_open);
 | 
				
			||||||
/* fanotify! */
 | 
					/* fanotify! */
 | 
				
			||||||
cond_syscall(sys_fanotify_init);
 | 
					cond_syscall(sys_fanotify_init);
 | 
				
			||||||
cond_syscall(sys_fanotify_mark);
 | 
					cond_syscall(sys_fanotify_mark);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* open by handle */
 | 
				
			||||||
 | 
					cond_syscall(sys_name_to_handle_at);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue