diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-13 23:14:13 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-13 23:14:13 -0500 |
commit | db9effe99adc67c53e6aedadadd2aa9a02342e48 (patch) | |
tree | efe7ebfe951972568189ef2548130f0abd515210 /fs/namei.c | |
parent | 9c4bc1c2befbbdce4b9fd526e67a7a2ea143ffa2 (diff) | |
parent | f20877d94a74557b7c28b4ed8920d834c31e0ea5 (diff) |
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 | |||
479 | struct fs_struct *fs = current->fs; | 479 | struct fs_struct *fs = current->fs; |
480 | struct dentry *parent = nd->path.dentry; | 480 | struct dentry *parent = nd->path.dentry; |
481 | 481 | ||
482 | /* | ||
483 | * It can be possible to revalidate the dentry that we started | ||
484 | * the path walk with. force_reval_path may also revalidate the | ||
485 | * dentry already committed to the nameidata. | ||
486 | */ | ||
487 | if (unlikely(parent == dentry)) | ||
488 | return nameidata_drop_rcu(nd); | ||
489 | |||
482 | BUG_ON(!(nd->flags & LOOKUP_RCU)); | 490 | BUG_ON(!(nd->flags & LOOKUP_RCU)); |
483 | if (nd->root.mnt) { | 491 | if (nd->root.mnt) { |
484 | spin_lock(&fs->lock); | 492 | spin_lock(&fs->lock); |
@@ -583,6 +591,13 @@ void release_open_intent(struct nameidata *nd) | |||
583 | fput(nd->intent.open.file); | 591 | fput(nd->intent.open.file); |
584 | } | 592 | } |
585 | 593 | ||
594 | /* | ||
595 | * Call d_revalidate and handle filesystems that request rcu-walk | ||
596 | * to be dropped. This may be called and return in rcu-walk mode, | ||
597 | * regardless of success or error. If -ECHILD is returned, the caller | ||
598 | * must return -ECHILD back up the path walk stack so path walk may | ||
599 | * be restarted in ref-walk mode. | ||
600 | */ | ||
586 | static int d_revalidate(struct dentry *dentry, struct nameidata *nd) | 601 | static int d_revalidate(struct dentry *dentry, struct nameidata *nd) |
587 | { | 602 | { |
588 | int status; | 603 | int status; |
@@ -673,6 +688,9 @@ force_reval_path(struct path *path, struct nameidata *nd) | |||
673 | return 0; | 688 | return 0; |
674 | 689 | ||
675 | if (!status) { | 690 | if (!status) { |
691 | /* Don't d_invalidate in rcu-walk mode */ | ||
692 | if (nameidata_drop_rcu(nd)) | ||
693 | return -ECHILD; | ||
676 | d_invalidate(dentry); | 694 | d_invalidate(dentry); |
677 | status = -ESTALE; | 695 | status = -ESTALE; |
678 | } | 696 | } |
@@ -2105,11 +2123,13 @@ static struct file *do_last(struct nameidata *nd, struct path *path, | |||
2105 | dir = nd->path.dentry; | 2123 | dir = nd->path.dentry; |
2106 | case LAST_DOT: | 2124 | case LAST_DOT: |
2107 | if (need_reval_dot(dir)) { | 2125 | if (need_reval_dot(dir)) { |
2108 | error = d_revalidate(nd->path.dentry, nd); | 2126 | int status = d_revalidate(nd->path.dentry, nd); |
2109 | if (!error) | 2127 | if (!status) |
2110 | error = -ESTALE; | 2128 | status = -ESTALE; |
2111 | if (error < 0) | 2129 | if (status < 0) { |
2130 | error = status; | ||
2112 | goto exit; | 2131 | goto exit; |
2132 | } | ||
2113 | } | 2133 | } |
2114 | /* fallthrough */ | 2134 | /* fallthrough */ |
2115 | case LAST_ROOT: | 2135 | case LAST_ROOT: |