diff options
author | Nick Piggin <npiggin@kernel.dk> | 2011-01-05 20:01:21 +1100 |
---|---|---|
committer | Nick Piggin <npiggin@kernel.dk> | 2011-01-05 20:01:21 +1100 |
commit | d3a23e1678a5827c38ed8a465ad91d65e59fa911 (patch) | |
tree | 44363edff14c1796a634825f07decc2324d7e6e0 /fs/dcache.c | |
parent | 3c0eee3fe6a3a1c745379547c7e7c904aa64f6d5 (diff) |
Revert "fs: use RCU read side protection in d_validate"
This reverts commit 3825bdb7ed920845961f32f364454bee5f469abb.
You cannot dget() a dentry without having a reference, or holding
a lock that guarantees it remains valid.
Signed-off-by: Nick Piggin <npiggin@kernel.dk>
Diffstat (limited to 'fs/dcache.c')
-rw-r--r-- | fs/dcache.c | 31 |
1 files changed, 19 insertions, 12 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 23702a9d4e6d..cc2b93802179 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1491,26 +1491,33 @@ out: * This is used by ncpfs in its readdir implementation. * Zero is returned in the dentry is invalid. */ -int d_validate(struct dentry *dentry, struct dentry *parent) + +int d_validate(struct dentry *dentry, struct dentry *dparent) { - struct hlist_head *head = d_hash(parent, dentry->d_name.hash); - struct hlist_node *node; - struct dentry *d; + struct hlist_head *base; + struct hlist_node *lhp; /* Check whether the ptr might be valid at all.. */ if (!kmem_ptr_validate(dentry_cache, dentry)) - return 0; - if (dentry->d_parent != parent) - return 0; + goto out; - rcu_read_lock(); - hlist_for_each_entry_rcu(d, node, head, d_hash) { - if (d == dentry) { - dget(dentry); + if (dentry->d_parent != dparent) + goto out; + + spin_lock(&dcache_lock); + base = d_hash(dparent, dentry->d_name.hash); + hlist_for_each(lhp,base) { + /* hlist_for_each_entry_rcu() not required for d_hash list + * as it is parsed under dcache_lock + */ + if (dentry == hlist_entry(lhp, struct dentry, d_hash)) { + __dget_locked(dentry); + spin_unlock(&dcache_lock); return 1; } } - rcu_read_unlock(); + spin_unlock(&dcache_lock); +out: return 0; } EXPORT_SYMBOL(d_validate); |