diff options
| author | Nick Piggin <npiggin@kernel.dk> | 2011-01-07 17:49:21 +1100 | 
|---|---|---|
| committer | Nick Piggin <npiggin@kernel.dk> | 2011-01-07 17:50:17 +1100 | 
| commit | fbc8d4c04626e015b18cc61199f505920abb48f0 (patch) | |
| tree | 31cd59dd54966d225ae159f41308798b2d58b8a2 | |
| parent | 5adcee1d8d32d7f305f6f5aaefdbf8f35adca177 (diff) | |
config fs: avoid switching ->d_op on live dentry
Switching d_op on a live dentry is racy in general, so avoid it. In this case
it is a negative dentry, which is safer, but there are still concurrent ops
which may be called on d_op in that case (eg. d_revalidate). So in general
a filesystem may not do this. Fix configfs so as not to do this.
Signed-off-by: Nick Piggin <npiggin@kernel.dk>
| -rw-r--r-- | fs/configfs/dir.c | 17 | 
1 files changed, 9 insertions, 8 deletions
| diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index 0b502f80c69..57870696941 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c @@ -232,10 +232,8 @@ int configfs_make_dirent(struct configfs_dirent * parent_sd,  	sd->s_mode = mode;  	sd->s_dentry = dentry; -	if (dentry) { +	if (dentry)  		dentry->d_fsdata = configfs_get(sd); -		dentry->d_op = &configfs_dentry_ops; -	}  	return 0;  } @@ -278,7 +276,6 @@ static int create_dir(struct config_item * k, struct dentry * p,  		error = configfs_create(d, mode, init_dir);  		if (!error) {  			inc_nlink(p->d_inode); -			(d)->d_op = &configfs_dentry_ops;  		} else {  			struct configfs_dirent *sd = d->d_fsdata;  			if (sd) { @@ -371,9 +368,7 @@ int configfs_create_link(struct configfs_symlink *sl,  				   CONFIGFS_ITEM_LINK);  	if (!err) {  		err = configfs_create(dentry, mode, init_symlink); -		if (!err) -			dentry->d_op = &configfs_dentry_ops; -		else { +		if (err) {  			struct configfs_dirent *sd = dentry->d_fsdata;  			if (sd) {  				spin_lock(&configfs_dirent_lock); @@ -493,7 +488,11 @@ static struct dentry * configfs_lookup(struct inode *dir,  		 * If it doesn't exist and it isn't a NOT_PINNED item,  		 * it must be negative.  		 */ -		return simple_lookup(dir, dentry, nd); +		if (dentry->d_name.len > NAME_MAX) +			return ERR_PTR(-ENAMETOOLONG); +		dentry->d_op = &configfs_dentry_ops; +		d_add(dentry, NULL); +		return NULL;  	}  out: @@ -685,6 +684,7 @@ static int create_default_group(struct config_group *parent_group,  	ret = -ENOMEM;  	child = d_alloc(parent, &name);  	if (child) { +		child->d_op = &configfs_dentry_ops;  		d_add(child, NULL);  		ret = configfs_attach_group(&parent_group->cg_item, @@ -1682,6 +1682,7 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys)  	err = -ENOMEM;  	dentry = d_alloc(configfs_sb->s_root, &name);  	if (dentry) { +		dentry->d_op = &configfs_dentry_ops;  		d_add(dentry, NULL);  		err = configfs_attach_group(sd->s_element, &group->cg_item, | 
