diff options
Diffstat (limited to 'fs/fs_struct.c')
| -rw-r--r-- | fs/fs_struct.c | 74 | 
1 files changed, 34 insertions, 40 deletions
diff --git a/fs/fs_struct.c b/fs/fs_struct.c index ed45a9cf5f3..7dca743b2ce 100644 --- a/fs/fs_struct.c +++ b/fs/fs_struct.c @@ -1,22 +1,25 @@ -#include <linux/module.h> +#include <linux/export.h>  #include <linux/sched.h>  #include <linux/fs.h>  #include <linux/path.h>  #include <linux/slab.h>  #include <linux/fs_struct.h> +#include "internal.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) +void set_fs_root(struct fs_struct *fs, const struct path *path)  {  	struct path old_root; +	path_get(path);  	spin_lock(&fs->lock); +	write_seqcount_begin(&fs->seq);  	old_root = fs->root;  	fs->root = *path; -	path_get(path); +	write_seqcount_end(&fs->seq);  	spin_unlock(&fs->lock);  	if (old_root.dentry)  		path_put(&old_root); @@ -26,21 +29,31 @@ void set_fs_root(struct fs_struct *fs, struct path *path)   * 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) +void set_fs_pwd(struct fs_struct *fs, const struct path *path)  {  	struct path old_pwd; +	path_get(path);  	spin_lock(&fs->lock); +	write_seqcount_begin(&fs->seq);  	old_pwd = fs->pwd;  	fs->pwd = *path; -	path_get(path); +	write_seqcount_end(&fs->seq);  	spin_unlock(&fs->lock);  	if (old_pwd.dentry)  		path_put(&old_pwd);  } -void chroot_fs_refs(struct path *old_root, struct path *new_root) +static inline int replace_path(struct path *p, const struct path *old, const struct path *new) +{ +	if (likely(p->dentry != old->dentry || p->mnt != old->mnt)) +		return 0; +	*p = *new; +	return 1; +} + +void chroot_fs_refs(const struct path *old_root, const struct path *new_root)  {  	struct task_struct *g, *p;  	struct fs_struct *fs; @@ -51,18 +64,15 @@ void chroot_fs_refs(struct path *old_root, struct path *new_root)  		task_lock(p);  		fs = p->fs;  		if (fs) { +			int hits = 0;  			spin_lock(&fs->lock); -			if (fs->root.dentry == old_root->dentry -			    && fs->root.mnt == old_root->mnt) { -				path_get(new_root); -				fs->root = *new_root; +			write_seqcount_begin(&fs->seq); +			hits += replace_path(&fs->root, old_root, new_root); +			hits += replace_path(&fs->pwd, old_root, new_root); +			write_seqcount_end(&fs->seq); +			while (hits--) {  				count++; -			} -			if (fs->pwd.dentry == old_root->dentry -			    && fs->pwd.mnt == old_root->mnt) {  				path_get(new_root); -				fs->pwd = *new_root; -				count++;  			}  			spin_unlock(&fs->lock);  		} @@ -105,8 +115,15 @@ struct fs_struct *copy_fs_struct(struct fs_struct *old)  		fs->users = 1;  		fs->in_exec = 0;  		spin_lock_init(&fs->lock); +		seqcount_init(&fs->seq);  		fs->umask = old->umask; -		get_fs_root_and_pwd(old, &fs->root, &fs->pwd); + +		spin_lock(&old->lock); +		fs->root = old->root; +		path_get(&fs->root); +		fs->pwd = old->pwd; +		path_get(&fs->pwd); +		spin_unlock(&old->lock);  	}  	return fs;  } @@ -144,29 +161,6 @@ EXPORT_SYMBOL(current_umask);  struct fs_struct init_fs = {  	.users		= 1,  	.lock		= __SPIN_LOCK_UNLOCKED(init_fs.lock), +	.seq		= SEQCNT_ZERO(init_fs.seq),  	.umask		= 0022,  }; - -void daemonize_fs_struct(void) -{ -	struct fs_struct *fs = current->fs; - -	if (fs) { -		int kill; - -		task_lock(current); - -		spin_lock(&init_fs.lock); -		init_fs.users++; -		spin_unlock(&init_fs.lock); - -		spin_lock(&fs->lock); -		current->fs = &init_fs; -		kill = !--fs->users; -		spin_unlock(&fs->lock); - -		task_unlock(current); -		if (kill) -			free_fs_struct(fs); -	} -}  | 
