aboutsummaryrefslogtreecommitdiffstats
path: root/fs/libfs.c
diff options
context:
space:
mode:
authorNick Piggin <npiggin@kernel.dk>2011-01-07 01:49:33 -0500
committerNick Piggin <npiggin@kernel.dk>2011-01-07 01:50:21 -0500
commitda5029563a0a026c64821b09e8e7b4fd81d3fe1b (patch)
tree5d5618e0cb382390073377b1be7d0aa76879ac54 /fs/libfs.c
parentb7ab39f631f505edc2bbdb86620d5493f995c9da (diff)
fs: dcache scale d_unhashed
Protect d_unhashed(dentry) condition with d_lock. This means keeping DCACHE_UNHASHED bit in synch with hash manipulations. Signed-off-by: Nick Piggin <npiggin@kernel.dk>
Diffstat (limited to 'fs/libfs.c')
-rw-r--r--fs/libfs.c29
1 files changed, 20 insertions, 9 deletions
diff --git a/fs/libfs.c b/fs/libfs.c
index b9d25d83e228..433e7139c23a 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -16,6 +16,11 @@
16 16
17#include <asm/uaccess.h> 17#include <asm/uaccess.h>
18 18
19static inline int simple_positive(struct dentry *dentry)
20{
21 return dentry->d_inode && !d_unhashed(dentry);
22}
23
19int simple_getattr(struct vfsmount *mnt, struct dentry *dentry, 24int simple_getattr(struct vfsmount *mnt, struct dentry *dentry,
20 struct kstat *stat) 25 struct kstat *stat)
21{ 26{
@@ -100,8 +105,10 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin)
100 while (n && p != &file->f_path.dentry->d_subdirs) { 105 while (n && p != &file->f_path.dentry->d_subdirs) {
101 struct dentry *next; 106 struct dentry *next;
102 next = list_entry(p, struct dentry, d_u.d_child); 107 next = list_entry(p, struct dentry, d_u.d_child);
103 if (!d_unhashed(next) && next->d_inode) 108 spin_lock(&next->d_lock);
109 if (simple_positive(next))
104 n--; 110 n--;
111 spin_unlock(&next->d_lock);
105 p = p->next; 112 p = p->next;
106 } 113 }
107 list_add_tail(&cursor->d_u.d_child, p); 114 list_add_tail(&cursor->d_u.d_child, p);
@@ -155,9 +162,13 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)
155 for (p=q->next; p != &dentry->d_subdirs; p=p->next) { 162 for (p=q->next; p != &dentry->d_subdirs; p=p->next) {
156 struct dentry *next; 163 struct dentry *next;
157 next = list_entry(p, struct dentry, d_u.d_child); 164 next = list_entry(p, struct dentry, d_u.d_child);
158 if (d_unhashed(next) || !next->d_inode) 165 spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED);
166 if (!simple_positive(next)) {
167 spin_unlock(&next->d_lock);
159 continue; 168 continue;
169 }
160 170
171 spin_unlock(&next->d_lock);
161 spin_unlock(&dcache_lock); 172 spin_unlock(&dcache_lock);
162 if (filldir(dirent, next->d_name.name, 173 if (filldir(dirent, next->d_name.name,
163 next->d_name.len, filp->f_pos, 174 next->d_name.len, filp->f_pos,
@@ -259,20 +270,20 @@ int simple_link(struct dentry *old_dentry, struct inode *dir, struct dentry *den
259 return 0; 270 return 0;
260} 271}
261 272
262static inline int simple_positive(struct dentry *dentry)
263{
264 return dentry->d_inode && !d_unhashed(dentry);
265}
266
267int simple_empty(struct dentry *dentry) 273int simple_empty(struct dentry *dentry)
268{ 274{
269 struct dentry *child; 275 struct dentry *child;
270 int ret = 0; 276 int ret = 0;
271 277
272 spin_lock(&dcache_lock); 278 spin_lock(&dcache_lock);
273 list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) 279 list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) {
274 if (simple_positive(child)) 280 spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED);
281 if (simple_positive(child)) {
282 spin_unlock(&child->d_lock);
275 goto out; 283 goto out;
284 }
285 spin_unlock(&child->d_lock);
286 }
276 ret = 1; 287 ret = 1;
277out: 288out:
278 spin_unlock(&dcache_lock); 289 spin_unlock(&dcache_lock);