diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-13 20:14:13 -0800 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-13 20:14:13 -0800 | 
| commit | db9effe99adc67c53e6aedadadd2aa9a02342e48 (patch) | |
| tree | efe7ebfe951972568189ef2548130f0abd515210 /fs/namei.c | |
| parent | 9c4bc1c2befbbdce4b9fd526e67a7a2ea143ffa2 (diff) | |
| parent | f20877d94a74557b7c28b4ed8920d834c31e0ea5 (diff) | |
| download | linux-db9effe99adc67c53e6aedadadd2aa9a02342e48.tar.bz2 | |
Merge branch 'vfs-scale-working' of git://git.kernel.org/pub/scm/linux/kernel/git/npiggin/linux-npiggin
* 'vfs-scale-working' of git://git.kernel.org/pub/scm/linux/kernel/git/npiggin/linux-npiggin:
  fs: fix do_last error case when need_reval_dot
  nfs: add missing rcu-walk check
  fs: hlist UP debug fixup
  fs: fix dropping of rcu-walk from force_reval_path
  fs: force_reval_path drop rcu-walk before d_invalidate
  fs: small rcu-walk documentation fixes
Fixed up trivial conflicts in Documentation/filesystems/porting
Diffstat (limited to 'fs/namei.c')
| -rw-r--r-- | fs/namei.c | 28 | 
1 files changed, 24 insertions, 4 deletions
| diff --git a/fs/namei.c b/fs/namei.c index 0b14f6910fc6..86643302079e 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -479,6 +479,14 @@ static int nameidata_dentry_drop_rcu(struct nameidata *nd, struct dentry *dentry  	struct fs_struct *fs = current->fs;  	struct dentry *parent = nd->path.dentry; +	/* +	 * It can be possible to revalidate the dentry that we started +	 * the path walk with. force_reval_path may also revalidate the +	 * dentry already committed to the nameidata. +	 */ +	if (unlikely(parent == dentry)) +		return nameidata_drop_rcu(nd); +  	BUG_ON(!(nd->flags & LOOKUP_RCU));  	if (nd->root.mnt) {  		spin_lock(&fs->lock); @@ -583,6 +591,13 @@ void release_open_intent(struct nameidata *nd)  		fput(nd->intent.open.file);  } +/* + * Call d_revalidate and handle filesystems that request rcu-walk + * to be dropped. This may be called and return in rcu-walk mode, + * regardless of success or error. If -ECHILD is returned, the caller + * must return -ECHILD back up the path walk stack so path walk may + * be restarted in ref-walk mode. + */  static int d_revalidate(struct dentry *dentry, struct nameidata *nd)  {  	int status; @@ -673,6 +688,9 @@ force_reval_path(struct path *path, struct nameidata *nd)  		return 0;  	if (!status) { +		/* Don't d_invalidate in rcu-walk mode */ +		if (nameidata_drop_rcu(nd)) +			return -ECHILD;  		d_invalidate(dentry);  		status = -ESTALE;  	} @@ -2105,11 +2123,13 @@ static struct file *do_last(struct nameidata *nd, struct path *path,  		dir = nd->path.dentry;  	case LAST_DOT:  		if (need_reval_dot(dir)) { -			error = d_revalidate(nd->path.dentry, nd); -			if (!error) -				error = -ESTALE; -			if (error < 0) +			int status = d_revalidate(nd->path.dentry, nd); +			if (!status) +				status = -ESTALE; +			if (status < 0) { +				error = status;  				goto exit; +			}  		}  		/* fallthrough */  	case LAST_ROOT: |