Take fs_struct handling to new file (fs/fs_struct.c)
Pure code move; two new helper functions for nfsd and daemonize (unshare_fs_struct() and daemonize_fs_struct() resp.; for now - the same code as used to be in callers). unshare_fs_struct() exported (for nfsd, as copy_fs_struct()/exit_fs() used to be), copy_fs_struct() and exit_fs() don't need exports anymore. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
		
							parent
							
								
									f8ef3ed2be
								
							
						
					
					
						commit
						3e93cd6718
					
				| @ -11,7 +11,7 @@ obj-y :=	open.o read_write.o file_table.o super.o \ | ||||
| 		attr.o bad_inode.o file.o filesystems.o namespace.o \
 | ||||
| 		seq_file.o xattr.o libfs.o fs-writeback.o \
 | ||||
| 		pnode.o drop_caches.o splice.o sync.o utimes.o \
 | ||||
| 		stack.o | ||||
| 		stack.o fs_struct.o | ||||
| 
 | ||||
| ifeq ($(CONFIG_BLOCK),y) | ||||
| obj-y +=	buffer.o bio.o block_dev.o direct-io.o mpage.o ioprio.o | ||||
|  | ||||
							
								
								
									
										141
									
								
								fs/fs_struct.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								fs/fs_struct.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,141 @@ | ||||
| #include <linux/module.h> | ||||
| #include <linux/sched.h> | ||||
| #include <linux/fs.h> | ||||
| #include <linux/path.h> | ||||
| #include <linux/slab.h> | ||||
| 
 | ||||
| /*
 | ||||
|  * Replace the fs->{rootmnt,root} with {mnt,dentry}. Put the old values. | ||||
|  * It can block. | ||||
|  */ | ||||
| void set_fs_root(struct fs_struct *fs, struct path *path) | ||||
| { | ||||
| 	struct path old_root; | ||||
| 
 | ||||
| 	write_lock(&fs->lock); | ||||
| 	old_root = fs->root; | ||||
| 	fs->root = *path; | ||||
| 	path_get(path); | ||||
| 	write_unlock(&fs->lock); | ||||
| 	if (old_root.dentry) | ||||
| 		path_put(&old_root); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Replace the fs->{pwdmnt,pwd} with {mnt,dentry}. Put the old values. | ||||
|  * It can block. | ||||
|  */ | ||||
| void set_fs_pwd(struct fs_struct *fs, struct path *path) | ||||
| { | ||||
| 	struct path old_pwd; | ||||
| 
 | ||||
| 	write_lock(&fs->lock); | ||||
| 	old_pwd = fs->pwd; | ||||
| 	fs->pwd = *path; | ||||
| 	path_get(path); | ||||
| 	write_unlock(&fs->lock); | ||||
| 
 | ||||
| 	if (old_pwd.dentry) | ||||
| 		path_put(&old_pwd); | ||||
| } | ||||
| 
 | ||||
| void chroot_fs_refs(struct path *old_root, struct path *new_root) | ||||
| { | ||||
| 	struct task_struct *g, *p; | ||||
| 	struct fs_struct *fs; | ||||
| 	int count = 0; | ||||
| 
 | ||||
| 	read_lock(&tasklist_lock); | ||||
| 	do_each_thread(g, p) { | ||||
| 		task_lock(p); | ||||
| 		fs = p->fs; | ||||
| 		if (fs) { | ||||
| 			write_lock(&fs->lock); | ||||
| 			if (fs->root.dentry == old_root->dentry | ||||
| 			    && fs->root.mnt == old_root->mnt) { | ||||
| 				path_get(new_root); | ||||
| 				fs->root = *new_root; | ||||
| 				count++; | ||||
| 			} | ||||
| 			if (fs->pwd.dentry == old_root->dentry | ||||
| 			    && fs->pwd.mnt == old_root->mnt) { | ||||
| 				path_get(new_root); | ||||
| 				fs->pwd = *new_root; | ||||
| 				count++; | ||||
| 			} | ||||
| 			write_unlock(&fs->lock); | ||||
| 		} | ||||
| 		task_unlock(p); | ||||
| 	} while_each_thread(g, p); | ||||
| 	read_unlock(&tasklist_lock); | ||||
| 	while (count--) | ||||
| 		path_put(old_root); | ||||
| } | ||||
| 
 | ||||
| void put_fs_struct(struct fs_struct *fs) | ||||
| { | ||||
| 	/* No need to hold fs->lock if we are killing it */ | ||||
| 	if (atomic_dec_and_test(&fs->count)) { | ||||
| 		path_put(&fs->root); | ||||
| 		path_put(&fs->pwd); | ||||
| 		kmem_cache_free(fs_cachep, fs); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void exit_fs(struct task_struct *tsk) | ||||
| { | ||||
| 	struct fs_struct * fs = tsk->fs; | ||||
| 
 | ||||
| 	if (fs) { | ||||
| 		task_lock(tsk); | ||||
| 		tsk->fs = NULL; | ||||
| 		task_unlock(tsk); | ||||
| 		put_fs_struct(fs); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| struct fs_struct *copy_fs_struct(struct fs_struct *old) | ||||
| { | ||||
| 	struct fs_struct *fs = kmem_cache_alloc(fs_cachep, GFP_KERNEL); | ||||
| 	/* We don't need to lock fs - think why ;-) */ | ||||
| 	if (fs) { | ||||
| 		atomic_set(&fs->count, 1); | ||||
| 		rwlock_init(&fs->lock); | ||||
| 		fs->umask = old->umask; | ||||
| 		read_lock(&old->lock); | ||||
| 		fs->root = old->root; | ||||
| 		path_get(&old->root); | ||||
| 		fs->pwd = old->pwd; | ||||
| 		path_get(&old->pwd); | ||||
| 		read_unlock(&old->lock); | ||||
| 	} | ||||
| 	return fs; | ||||
| } | ||||
| 
 | ||||
| int unshare_fs_struct(void) | ||||
| { | ||||
| 	struct fs_struct *fsp = copy_fs_struct(current->fs); | ||||
| 	if (!fsp) | ||||
| 		return -ENOMEM; | ||||
| 	exit_fs(current); | ||||
| 	current->fs = fsp; | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(unshare_fs_struct); | ||||
| 
 | ||||
| /* to be mentioned only in INIT_TASK */ | ||||
| struct fs_struct init_fs = { | ||||
| 	.count		= ATOMIC_INIT(1), | ||||
| 	.lock		= __RW_LOCK_UNLOCKED(init_fs.lock), | ||||
| 	.umask		= 0022, | ||||
| }; | ||||
| 
 | ||||
| void daemonize_fs_struct(void) | ||||
| { | ||||
| 	struct fs_struct *fs; | ||||
| 
 | ||||
| 	exit_fs(current);	/* current->fs->count--; */ | ||||
| 	fs = &init_fs; | ||||
| 	current->fs = fs; | ||||
| 	atomic_inc(&fs->count); | ||||
| } | ||||
| @ -11,6 +11,7 @@ | ||||
| 
 | ||||
| struct super_block; | ||||
| struct linux_binprm; | ||||
| struct path; | ||||
| 
 | ||||
| /*
 | ||||
|  * block_dev.c | ||||
| @ -60,3 +61,8 @@ extern void umount_tree(struct vfsmount *, int, struct list_head *); | ||||
| extern struct vfsmount *copy_tree(struct vfsmount *, struct dentry *, int); | ||||
| 
 | ||||
| extern void __init mnt_init(void); | ||||
| 
 | ||||
| /*
 | ||||
|  * fs_struct.c | ||||
|  */ | ||||
| extern void chroot_fs_refs(struct path *, struct path *); | ||||
|  | ||||
| @ -2897,10 +2897,3 @@ EXPORT_SYMBOL(vfs_symlink); | ||||
| EXPORT_SYMBOL(vfs_unlink); | ||||
| EXPORT_SYMBOL(dentry_unhash); | ||||
| EXPORT_SYMBOL(generic_readlink); | ||||
| 
 | ||||
| /* to be mentioned only in INIT_TASK */ | ||||
| struct fs_struct init_fs = { | ||||
| 	.count		= ATOMIC_INIT(1), | ||||
| 	.lock		= __RW_LOCK_UNLOCKED(init_fs.lock), | ||||
| 	.umask		= 0022, | ||||
| }; | ||||
|  | ||||
| @ -2092,74 +2092,6 @@ out1: | ||||
| 	return retval; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Replace the fs->{rootmnt,root} with {mnt,dentry}. Put the old values. | ||||
|  * It can block. Requires the big lock held. | ||||
|  */ | ||||
| void set_fs_root(struct fs_struct *fs, struct path *path) | ||||
| { | ||||
| 	struct path old_root; | ||||
| 
 | ||||
| 	write_lock(&fs->lock); | ||||
| 	old_root = fs->root; | ||||
| 	fs->root = *path; | ||||
| 	path_get(path); | ||||
| 	write_unlock(&fs->lock); | ||||
| 	if (old_root.dentry) | ||||
| 		path_put(&old_root); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Replace the fs->{pwdmnt,pwd} with {mnt,dentry}. Put the old values. | ||||
|  * It can block. Requires the big lock held. | ||||
|  */ | ||||
| void set_fs_pwd(struct fs_struct *fs, struct path *path) | ||||
| { | ||||
| 	struct path old_pwd; | ||||
| 
 | ||||
| 	write_lock(&fs->lock); | ||||
| 	old_pwd = fs->pwd; | ||||
| 	fs->pwd = *path; | ||||
| 	path_get(path); | ||||
| 	write_unlock(&fs->lock); | ||||
| 
 | ||||
| 	if (old_pwd.dentry) | ||||
| 		path_put(&old_pwd); | ||||
| } | ||||
| 
 | ||||
| static void chroot_fs_refs(struct path *old_root, struct path *new_root) | ||||
| { | ||||
| 	struct task_struct *g, *p; | ||||
| 	struct fs_struct *fs; | ||||
| 	int count = 0; | ||||
| 
 | ||||
| 	read_lock(&tasklist_lock); | ||||
| 	do_each_thread(g, p) { | ||||
| 		task_lock(p); | ||||
| 		fs = p->fs; | ||||
| 		if (fs) { | ||||
| 			write_lock(&fs->lock); | ||||
| 			if (fs->root.dentry == old_root->dentry | ||||
| 			    && fs->root.mnt == old_root->mnt) { | ||||
| 				path_get(new_root); | ||||
| 				fs->root = *new_root; | ||||
| 				count++; | ||||
| 			} | ||||
| 			if (fs->pwd.dentry == old_root->dentry | ||||
| 			    && fs->pwd.mnt == old_root->mnt) { | ||||
| 				path_get(new_root); | ||||
| 				fs->pwd = *new_root; | ||||
| 				count++; | ||||
| 			} | ||||
| 			write_unlock(&fs->lock); | ||||
| 		} | ||||
| 		task_unlock(p); | ||||
| 	} while_each_thread(g, p); | ||||
| 	read_unlock(&tasklist_lock); | ||||
| 	while (count--) | ||||
| 		path_put(old_root); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * pivot_root Semantics: | ||||
|  * Moves the root file system of the current process to the directory put_old, | ||||
|  | ||||
| @ -404,7 +404,6 @@ static int | ||||
| nfsd(void *vrqstp) | ||||
| { | ||||
| 	struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp; | ||||
| 	struct fs_struct *fsp; | ||||
| 	int err, preverr = 0; | ||||
| 
 | ||||
| 	/* Lock module and set up kernel thread */ | ||||
| @ -413,13 +412,11 @@ nfsd(void *vrqstp) | ||||
| 	/* At this point, the thread shares current->fs
 | ||||
| 	 * with the init process. We need to create files with a | ||||
| 	 * umask of 0 instead of init's umask. */ | ||||
| 	fsp = copy_fs_struct(current->fs); | ||||
| 	if (!fsp) { | ||||
| 	if (unshare_fs_struct() < 0) { | ||||
| 		printk("Unable to start nfsd thread: out of memory\n"); | ||||
| 		goto out; | ||||
| 	} | ||||
| 	exit_fs(current); | ||||
| 	current->fs = fsp; | ||||
| 
 | ||||
| 	current->fs->umask = 0; | ||||
| 
 | ||||
| 	/*
 | ||||
|  | ||||
| @ -20,5 +20,7 @@ extern void set_fs_root(struct fs_struct *, struct path *); | ||||
| extern void set_fs_pwd(struct fs_struct *, struct path *); | ||||
| extern struct fs_struct *copy_fs_struct(struct fs_struct *); | ||||
| extern void put_fs_struct(struct fs_struct *); | ||||
| extern void daemonize_fs_struct(void); | ||||
| extern int unshare_fs_struct(void); | ||||
| 
 | ||||
| #endif /* _LINUX_FS_STRUCT_H */ | ||||
|  | ||||
| @ -429,7 +429,6 @@ EXPORT_SYMBOL(disallow_signal); | ||||
| void daemonize(const char *name, ...) | ||||
| { | ||||
| 	va_list args; | ||||
| 	struct fs_struct *fs; | ||||
| 	sigset_t blocked; | ||||
| 
 | ||||
| 	va_start(args, name); | ||||
| @ -462,11 +461,7 @@ void daemonize(const char *name, ...) | ||||
| 
 | ||||
| 	/* Become as one with the init task */ | ||||
| 
 | ||||
| 	exit_fs(current);	/* current->fs->count--; */ | ||||
| 	fs = init_task.fs; | ||||
| 	current->fs = fs; | ||||
| 	atomic_inc(&fs->count); | ||||
| 
 | ||||
| 	daemonize_fs_struct(); | ||||
| 	exit_files(current); | ||||
| 	current->files = init_task.files; | ||||
| 	atomic_inc(¤t->files->count); | ||||
| @ -565,30 +560,6 @@ void exit_files(struct task_struct *tsk) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void put_fs_struct(struct fs_struct *fs) | ||||
| { | ||||
| 	/* No need to hold fs->lock if we are killing it */ | ||||
| 	if (atomic_dec_and_test(&fs->count)) { | ||||
| 		path_put(&fs->root); | ||||
| 		path_put(&fs->pwd); | ||||
| 		kmem_cache_free(fs_cachep, fs); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void exit_fs(struct task_struct *tsk) | ||||
| { | ||||
| 	struct fs_struct * fs = tsk->fs; | ||||
| 
 | ||||
| 	if (fs) { | ||||
| 		task_lock(tsk); | ||||
| 		tsk->fs = NULL; | ||||
| 		task_unlock(tsk); | ||||
| 		put_fs_struct(fs); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| EXPORT_SYMBOL_GPL(exit_fs); | ||||
| 
 | ||||
| #ifdef CONFIG_MM_OWNER | ||||
| /*
 | ||||
|  * Task p is exiting and it owned mm, lets find a new owner for it | ||||
|  | ||||
| @ -681,38 +681,13 @@ fail_nomem: | ||||
| 	return retval; | ||||
| } | ||||
| 
 | ||||
| static struct fs_struct *__copy_fs_struct(struct fs_struct *old) | ||||
| { | ||||
| 	struct fs_struct *fs = kmem_cache_alloc(fs_cachep, GFP_KERNEL); | ||||
| 	/* We don't need to lock fs - think why ;-) */ | ||||
| 	if (fs) { | ||||
| 		atomic_set(&fs->count, 1); | ||||
| 		rwlock_init(&fs->lock); | ||||
| 		fs->umask = old->umask; | ||||
| 		read_lock(&old->lock); | ||||
| 		fs->root = old->root; | ||||
| 		path_get(&old->root); | ||||
| 		fs->pwd = old->pwd; | ||||
| 		path_get(&old->pwd); | ||||
| 		read_unlock(&old->lock); | ||||
| 	} | ||||
| 	return fs; | ||||
| } | ||||
| 
 | ||||
| struct fs_struct *copy_fs_struct(struct fs_struct *old) | ||||
| { | ||||
| 	return __copy_fs_struct(old); | ||||
| } | ||||
| 
 | ||||
| EXPORT_SYMBOL_GPL(copy_fs_struct); | ||||
| 
 | ||||
| static int copy_fs(unsigned long clone_flags, struct task_struct *tsk) | ||||
| { | ||||
| 	if (clone_flags & CLONE_FS) { | ||||
| 		atomic_inc(¤t->fs->count); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	tsk->fs = __copy_fs_struct(current->fs); | ||||
| 	tsk->fs = copy_fs_struct(current->fs); | ||||
| 	if (!tsk->fs) | ||||
| 		return -ENOMEM; | ||||
| 	return 0; | ||||
| @ -1545,7 +1520,7 @@ static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp) | ||||
| 
 | ||||
| 	if ((unshare_flags & CLONE_FS) && | ||||
| 	    (fs && atomic_read(&fs->count) > 1)) { | ||||
| 		*new_fsp = __copy_fs_struct(current->fs); | ||||
| 		*new_fsp = copy_fs_struct(current->fs); | ||||
| 		if (!*new_fsp) | ||||
| 			return -ENOMEM; | ||||
| 	} | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user