diff options
-rw-r--r-- | drivers/staging/smbfs/cache.c | 4 | ||||
-rw-r--r-- | drivers/usb/core/inode.c | 8 | ||||
-rw-r--r-- | fs/autofs4/autofs_i.h | 11 | ||||
-rw-r--r-- | fs/autofs4/expire.c | 127 | ||||
-rw-r--r-- | fs/autofs4/root.c | 18 | ||||
-rw-r--r-- | fs/ceph/dir.c | 6 | ||||
-rw-r--r-- | fs/ceph/inode.c | 8 | ||||
-rw-r--r-- | fs/coda/cache.c | 2 | ||||
-rw-r--r-- | fs/dcache.c | 248 | ||||
-rw-r--r-- | fs/libfs.c | 24 | ||||
-rw-r--r-- | fs/ncpfs/dir.c | 3 | ||||
-rw-r--r-- | fs/ncpfs/ncplib_kernel.h | 4 | ||||
-rw-r--r-- | fs/notify/fsnotify.c | 4 | ||||
-rw-r--r-- | include/linux/dcache.h | 1 | ||||
-rw-r--r-- | kernel/cgroup.c | 19 | ||||
-rw-r--r-- | security/selinux/selinuxfs.c | 12 |
16 files changed, 339 insertions, 160 deletions
diff --git a/drivers/staging/smbfs/cache.c b/drivers/staging/smbfs/cache.c index 0beded260b00..920434b6c071 100644 --- a/drivers/staging/smbfs/cache.c +++ b/drivers/staging/smbfs/cache.c | |||
@@ -63,6 +63,7 @@ smb_invalidate_dircache_entries(struct dentry *parent) | |||
63 | struct dentry *dentry; | 63 | struct dentry *dentry; |
64 | 64 | ||
65 | spin_lock(&dcache_lock); | 65 | spin_lock(&dcache_lock); |
66 | spin_lock(&parent->d_lock); | ||
66 | next = parent->d_subdirs.next; | 67 | next = parent->d_subdirs.next; |
67 | while (next != &parent->d_subdirs) { | 68 | while (next != &parent->d_subdirs) { |
68 | dentry = list_entry(next, struct dentry, d_u.d_child); | 69 | dentry = list_entry(next, struct dentry, d_u.d_child); |
@@ -70,6 +71,7 @@ smb_invalidate_dircache_entries(struct dentry *parent) | |||
70 | smb_age_dentry(server, dentry); | 71 | smb_age_dentry(server, dentry); |
71 | next = next->next; | 72 | next = next->next; |
72 | } | 73 | } |
74 | spin_unlock(&parent->d_lock); | ||
73 | spin_unlock(&dcache_lock); | 75 | spin_unlock(&dcache_lock); |
74 | } | 76 | } |
75 | 77 | ||
@@ -97,6 +99,7 @@ smb_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos) | |||
97 | 99 | ||
98 | /* If a pointer is invalid, we search the dentry. */ | 100 | /* If a pointer is invalid, we search the dentry. */ |
99 | spin_lock(&dcache_lock); | 101 | spin_lock(&dcache_lock); |
102 | spin_lock(&parent->d_lock); | ||
100 | next = parent->d_subdirs.next; | 103 | next = parent->d_subdirs.next; |
101 | while (next != &parent->d_subdirs) { | 104 | while (next != &parent->d_subdirs) { |
102 | dent = list_entry(next, struct dentry, d_u.d_child); | 105 | dent = list_entry(next, struct dentry, d_u.d_child); |
@@ -111,6 +114,7 @@ smb_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos) | |||
111 | } | 114 | } |
112 | dent = NULL; | 115 | dent = NULL; |
113 | out_unlock: | 116 | out_unlock: |
117 | spin_unlock(&parent->d_lock); | ||
114 | spin_unlock(&dcache_lock); | 118 | spin_unlock(&dcache_lock); |
115 | return dent; | 119 | return dent; |
116 | } | 120 | } |
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index e3ab4437ea96..89a0e8366585 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c | |||
@@ -344,18 +344,20 @@ static int usbfs_empty (struct dentry *dentry) | |||
344 | struct list_head *list; | 344 | struct list_head *list; |
345 | 345 | ||
346 | spin_lock(&dcache_lock); | 346 | spin_lock(&dcache_lock); |
347 | 347 | spin_lock(&dentry->d_lock); | |
348 | list_for_each(list, &dentry->d_subdirs) { | 348 | list_for_each(list, &dentry->d_subdirs) { |
349 | struct dentry *de = list_entry(list, struct dentry, d_u.d_child); | 349 | struct dentry *de = list_entry(list, struct dentry, d_u.d_child); |
350 | spin_lock(&de->d_lock); | 350 | |
351 | spin_lock_nested(&de->d_lock, DENTRY_D_LOCK_NESTED); | ||
351 | if (usbfs_positive(de)) { | 352 | if (usbfs_positive(de)) { |
352 | spin_unlock(&de->d_lock); | 353 | spin_unlock(&de->d_lock); |
354 | spin_unlock(&dentry->d_lock); | ||
353 | spin_unlock(&dcache_lock); | 355 | spin_unlock(&dcache_lock); |
354 | return 0; | 356 | return 0; |
355 | } | 357 | } |
356 | spin_unlock(&de->d_lock); | 358 | spin_unlock(&de->d_lock); |
357 | } | 359 | } |
358 | 360 | spin_unlock(&dentry->d_lock); | |
359 | spin_unlock(&dcache_lock); | 361 | spin_unlock(&dcache_lock); |
360 | return 1; | 362 | return 1; |
361 | } | 363 | } |
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index 3912dcf047e5..9d2ae9b30d9f 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h | |||
@@ -254,6 +254,17 @@ static inline int simple_positive(struct dentry *dentry) | |||
254 | return dentry->d_inode && !d_unhashed(dentry); | 254 | return dentry->d_inode && !d_unhashed(dentry); |
255 | } | 255 | } |
256 | 256 | ||
257 | static inline void __autofs4_add_expiring(struct dentry *dentry) | ||
258 | { | ||
259 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | ||
260 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | ||
261 | if (ino) { | ||
262 | if (list_empty(&ino->expiring)) | ||
263 | list_add(&ino->expiring, &sbi->expiring_list); | ||
264 | } | ||
265 | return; | ||
266 | } | ||
267 | |||
257 | static inline void autofs4_add_expiring(struct dentry *dentry) | 268 | static inline void autofs4_add_expiring(struct dentry *dentry) |
258 | { | 269 | { |
259 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | 270 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); |
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index ee6402050f13..968c1434af62 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c | |||
@@ -91,24 +91,64 @@ done: | |||
91 | } | 91 | } |
92 | 92 | ||
93 | /* | 93 | /* |
94 | * Calculate next entry in top down tree traversal. | 94 | * Calculate and dget next entry in top down tree traversal. |
95 | * From next_mnt in namespace.c - elegant. | ||
96 | */ | 95 | */ |
97 | static struct dentry *next_dentry(struct dentry *p, struct dentry *root) | 96 | static struct dentry *get_next_positive_dentry(struct dentry *prev, |
97 | struct dentry *root) | ||
98 | { | 98 | { |
99 | struct list_head *next = p->d_subdirs.next; | 99 | struct list_head *next; |
100 | struct dentry *p, *ret; | ||
101 | |||
102 | if (prev == NULL) | ||
103 | return dget(prev); | ||
100 | 104 | ||
105 | spin_lock(&dcache_lock); | ||
106 | relock: | ||
107 | p = prev; | ||
108 | spin_lock(&p->d_lock); | ||
109 | again: | ||
110 | next = p->d_subdirs.next; | ||
101 | if (next == &p->d_subdirs) { | 111 | if (next == &p->d_subdirs) { |
102 | while (1) { | 112 | while (1) { |
103 | if (p == root) | 113 | struct dentry *parent; |
114 | |||
115 | if (p == root) { | ||
116 | spin_unlock(&p->d_lock); | ||
117 | spin_unlock(&dcache_lock); | ||
118 | dput(prev); | ||
104 | return NULL; | 119 | return NULL; |
120 | } | ||
121 | |||
122 | parent = p->d_parent; | ||
123 | if (!spin_trylock(&parent->d_lock)) { | ||
124 | spin_unlock(&p->d_lock); | ||
125 | cpu_relax(); | ||
126 | goto relock; | ||
127 | } | ||
128 | spin_unlock(&p->d_lock); | ||
105 | next = p->d_u.d_child.next; | 129 | next = p->d_u.d_child.next; |
106 | if (next != &p->d_parent->d_subdirs) | 130 | p = parent; |
131 | if (next != &parent->d_subdirs) | ||
107 | break; | 132 | break; |
108 | p = p->d_parent; | ||
109 | } | 133 | } |
110 | } | 134 | } |
111 | return list_entry(next, struct dentry, d_u.d_child); | 135 | ret = list_entry(next, struct dentry, d_u.d_child); |
136 | |||
137 | spin_lock_nested(&ret->d_lock, DENTRY_D_LOCK_NESTED); | ||
138 | /* Negative dentry - try next */ | ||
139 | if (!simple_positive(ret)) { | ||
140 | spin_unlock(&ret->d_lock); | ||
141 | p = ret; | ||
142 | goto again; | ||
143 | } | ||
144 | dget_dlock(ret); | ||
145 | spin_unlock(&ret->d_lock); | ||
146 | spin_unlock(&p->d_lock); | ||
147 | spin_unlock(&dcache_lock); | ||
148 | |||
149 | dput(prev); | ||
150 | |||
151 | return ret; | ||
112 | } | 152 | } |
113 | 153 | ||
114 | /* | 154 | /* |
@@ -158,22 +198,11 @@ static int autofs4_tree_busy(struct vfsmount *mnt, | |||
158 | if (!simple_positive(top)) | 198 | if (!simple_positive(top)) |
159 | return 1; | 199 | return 1; |
160 | 200 | ||
161 | spin_lock(&dcache_lock); | 201 | p = NULL; |
162 | for (p = top; p; p = next_dentry(p, top)) { | 202 | while ((p = get_next_positive_dentry(p, top))) { |
163 | spin_lock(&p->d_lock); | ||
164 | /* Negative dentry - give up */ | ||
165 | if (!simple_positive(p)) { | ||
166 | spin_unlock(&p->d_lock); | ||
167 | continue; | ||
168 | } | ||
169 | |||
170 | DPRINTK("dentry %p %.*s", | 203 | DPRINTK("dentry %p %.*s", |
171 | p, (int) p->d_name.len, p->d_name.name); | 204 | p, (int) p->d_name.len, p->d_name.name); |
172 | 205 | ||
173 | p = dget_dlock(p); | ||
174 | spin_unlock(&p->d_lock); | ||
175 | spin_unlock(&dcache_lock); | ||
176 | |||
177 | /* | 206 | /* |
178 | * Is someone visiting anywhere in the subtree ? | 207 | * Is someone visiting anywhere in the subtree ? |
179 | * If there's no mount we need to check the usage | 208 | * If there's no mount we need to check the usage |
@@ -208,10 +237,7 @@ static int autofs4_tree_busy(struct vfsmount *mnt, | |||
208 | return 1; | 237 | return 1; |
209 | } | 238 | } |
210 | } | 239 | } |
211 | dput(p); | ||
212 | spin_lock(&dcache_lock); | ||
213 | } | 240 | } |
214 | spin_unlock(&dcache_lock); | ||
215 | 241 | ||
216 | /* Timeout of a tree mount is ultimately determined by its top dentry */ | 242 | /* Timeout of a tree mount is ultimately determined by its top dentry */ |
217 | if (!autofs4_can_expire(top, timeout, do_now)) | 243 | if (!autofs4_can_expire(top, timeout, do_now)) |
@@ -230,36 +256,21 @@ static struct dentry *autofs4_check_leaves(struct vfsmount *mnt, | |||
230 | DPRINTK("parent %p %.*s", | 256 | DPRINTK("parent %p %.*s", |
231 | parent, (int)parent->d_name.len, parent->d_name.name); | 257 | parent, (int)parent->d_name.len, parent->d_name.name); |
232 | 258 | ||
233 | spin_lock(&dcache_lock); | 259 | p = NULL; |
234 | for (p = parent; p; p = next_dentry(p, parent)) { | 260 | while ((p = get_next_positive_dentry(p, parent))) { |
235 | spin_lock(&p->d_lock); | ||
236 | /* Negative dentry - give up */ | ||
237 | if (!simple_positive(p)) { | ||
238 | spin_unlock(&p->d_lock); | ||
239 | continue; | ||
240 | } | ||
241 | |||
242 | DPRINTK("dentry %p %.*s", | 261 | DPRINTK("dentry %p %.*s", |
243 | p, (int) p->d_name.len, p->d_name.name); | 262 | p, (int) p->d_name.len, p->d_name.name); |
244 | 263 | ||
245 | p = dget_dlock(p); | ||
246 | spin_unlock(&p->d_lock); | ||
247 | spin_unlock(&dcache_lock); | ||
248 | |||
249 | if (d_mountpoint(p)) { | 264 | if (d_mountpoint(p)) { |
250 | /* Can we umount this guy */ | 265 | /* Can we umount this guy */ |
251 | if (autofs4_mount_busy(mnt, p)) | 266 | if (autofs4_mount_busy(mnt, p)) |
252 | goto cont; | 267 | continue; |
253 | 268 | ||
254 | /* Can we expire this guy */ | 269 | /* Can we expire this guy */ |
255 | if (autofs4_can_expire(p, timeout, do_now)) | 270 | if (autofs4_can_expire(p, timeout, do_now)) |
256 | return p; | 271 | return p; |
257 | } | 272 | } |
258 | cont: | ||
259 | dput(p); | ||
260 | spin_lock(&dcache_lock); | ||
261 | } | 273 | } |
262 | spin_unlock(&dcache_lock); | ||
263 | return NULL; | 274 | return NULL; |
264 | } | 275 | } |
265 | 276 | ||
@@ -310,8 +321,8 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
310 | { | 321 | { |
311 | unsigned long timeout; | 322 | unsigned long timeout; |
312 | struct dentry *root = sb->s_root; | 323 | struct dentry *root = sb->s_root; |
324 | struct dentry *dentry; | ||
313 | struct dentry *expired = NULL; | 325 | struct dentry *expired = NULL; |
314 | struct list_head *next; | ||
315 | int do_now = how & AUTOFS_EXP_IMMEDIATE; | 326 | int do_now = how & AUTOFS_EXP_IMMEDIATE; |
316 | int exp_leaves = how & AUTOFS_EXP_LEAVES; | 327 | int exp_leaves = how & AUTOFS_EXP_LEAVES; |
317 | struct autofs_info *ino; | 328 | struct autofs_info *ino; |
@@ -323,26 +334,8 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
323 | now = jiffies; | 334 | now = jiffies; |
324 | timeout = sbi->exp_timeout; | 335 | timeout = sbi->exp_timeout; |
325 | 336 | ||
326 | spin_lock(&dcache_lock); | 337 | dentry = NULL; |
327 | next = root->d_subdirs.next; | 338 | while ((dentry = get_next_positive_dentry(dentry, root))) { |
328 | |||
329 | /* On exit from the loop expire is set to a dgot dentry | ||
330 | * to expire or it's NULL */ | ||
331 | while ( next != &root->d_subdirs ) { | ||
332 | struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child); | ||
333 | |||
334 | /* Negative dentry - give up */ | ||
335 | spin_lock(&dentry->d_lock); | ||
336 | if (!simple_positive(dentry)) { | ||
337 | next = next->next; | ||
338 | spin_unlock(&dentry->d_lock); | ||
339 | continue; | ||
340 | } | ||
341 | |||
342 | dentry = dget_dlock(dentry); | ||
343 | spin_unlock(&dentry->d_lock); | ||
344 | spin_unlock(&dcache_lock); | ||
345 | |||
346 | spin_lock(&sbi->fs_lock); | 339 | spin_lock(&sbi->fs_lock); |
347 | ino = autofs4_dentry_ino(dentry); | 340 | ino = autofs4_dentry_ino(dentry); |
348 | 341 | ||
@@ -405,11 +398,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
405 | } | 398 | } |
406 | next: | 399 | next: |
407 | spin_unlock(&sbi->fs_lock); | 400 | spin_unlock(&sbi->fs_lock); |
408 | dput(dentry); | ||
409 | spin_lock(&dcache_lock); | ||
410 | next = next->next; | ||
411 | } | 401 | } |
412 | spin_unlock(&dcache_lock); | ||
413 | return NULL; | 402 | return NULL; |
414 | 403 | ||
415 | found: | 404 | found: |
@@ -420,7 +409,11 @@ found: | |||
420 | init_completion(&ino->expire_complete); | 409 | init_completion(&ino->expire_complete); |
421 | spin_unlock(&sbi->fs_lock); | 410 | spin_unlock(&sbi->fs_lock); |
422 | spin_lock(&dcache_lock); | 411 | spin_lock(&dcache_lock); |
412 | spin_lock(&expired->d_parent->d_lock); | ||
413 | spin_lock_nested(&expired->d_lock, DENTRY_D_LOCK_NESTED); | ||
423 | list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child); | 414 | list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child); |
415 | spin_unlock(&expired->d_lock); | ||
416 | spin_unlock(&expired->d_parent->d_lock); | ||
424 | spin_unlock(&dcache_lock); | 417 | spin_unlock(&dcache_lock); |
425 | return expired; | 418 | return expired; |
426 | } | 419 | } |
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 7922509b5b2b..7a9ed6b88291 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c | |||
@@ -143,10 +143,13 @@ static int autofs4_dir_open(struct inode *inode, struct file *file) | |||
143 | * it. | 143 | * it. |
144 | */ | 144 | */ |
145 | spin_lock(&dcache_lock); | 145 | spin_lock(&dcache_lock); |
146 | spin_lock(&dentry->d_lock); | ||
146 | if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { | 147 | if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { |
148 | spin_unlock(&dentry->d_lock); | ||
147 | spin_unlock(&dcache_lock); | 149 | spin_unlock(&dcache_lock); |
148 | return -ENOENT; | 150 | return -ENOENT; |
149 | } | 151 | } |
152 | spin_unlock(&dentry->d_lock); | ||
150 | spin_unlock(&dcache_lock); | 153 | spin_unlock(&dcache_lock); |
151 | 154 | ||
152 | out: | 155 | out: |
@@ -253,7 +256,9 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
253 | lookup_type = autofs4_need_mount(nd->flags); | 256 | lookup_type = autofs4_need_mount(nd->flags); |
254 | spin_lock(&sbi->fs_lock); | 257 | spin_lock(&sbi->fs_lock); |
255 | spin_lock(&dcache_lock); | 258 | spin_lock(&dcache_lock); |
259 | spin_lock(&dentry->d_lock); | ||
256 | if (!(lookup_type || ino->flags & AUTOFS_INF_PENDING)) { | 260 | if (!(lookup_type || ino->flags & AUTOFS_INF_PENDING)) { |
261 | spin_unlock(&dentry->d_lock); | ||
257 | spin_unlock(&dcache_lock); | 262 | spin_unlock(&dcache_lock); |
258 | spin_unlock(&sbi->fs_lock); | 263 | spin_unlock(&sbi->fs_lock); |
259 | goto follow; | 264 | goto follow; |
@@ -266,6 +271,7 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
266 | */ | 271 | */ |
267 | if (ino->flags & AUTOFS_INF_PENDING || | 272 | if (ino->flags & AUTOFS_INF_PENDING || |
268 | (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs))) { | 273 | (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs))) { |
274 | spin_unlock(&dentry->d_lock); | ||
269 | spin_unlock(&dcache_lock); | 275 | spin_unlock(&dcache_lock); |
270 | spin_unlock(&sbi->fs_lock); | 276 | spin_unlock(&sbi->fs_lock); |
271 | 277 | ||
@@ -275,6 +281,7 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
275 | 281 | ||
276 | goto follow; | 282 | goto follow; |
277 | } | 283 | } |
284 | spin_unlock(&dentry->d_lock); | ||
278 | spin_unlock(&dcache_lock); | 285 | spin_unlock(&dcache_lock); |
279 | spin_unlock(&sbi->fs_lock); | 286 | spin_unlock(&sbi->fs_lock); |
280 | follow: | 287 | follow: |
@@ -347,10 +354,12 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
347 | 354 | ||
348 | /* Check for a non-mountpoint directory with no contents */ | 355 | /* Check for a non-mountpoint directory with no contents */ |
349 | spin_lock(&dcache_lock); | 356 | spin_lock(&dcache_lock); |
357 | spin_lock(&dentry->d_lock); | ||
350 | if (S_ISDIR(dentry->d_inode->i_mode) && | 358 | if (S_ISDIR(dentry->d_inode->i_mode) && |
351 | !d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { | 359 | !d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { |
352 | DPRINTK("dentry=%p %.*s, emptydir", | 360 | DPRINTK("dentry=%p %.*s, emptydir", |
353 | dentry, dentry->d_name.len, dentry->d_name.name); | 361 | dentry, dentry->d_name.len, dentry->d_name.name); |
362 | spin_unlock(&dentry->d_lock); | ||
354 | spin_unlock(&dcache_lock); | 363 | spin_unlock(&dcache_lock); |
355 | 364 | ||
356 | /* The daemon never causes a mount to trigger */ | 365 | /* The daemon never causes a mount to trigger */ |
@@ -367,6 +376,7 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
367 | 376 | ||
368 | return status; | 377 | return status; |
369 | } | 378 | } |
379 | spin_unlock(&dentry->d_lock); | ||
370 | spin_unlock(&dcache_lock); | 380 | spin_unlock(&dcache_lock); |
371 | 381 | ||
372 | return 1; | 382 | return 1; |
@@ -776,12 +786,16 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) | |||
776 | return -EACCES; | 786 | return -EACCES; |
777 | 787 | ||
778 | spin_lock(&dcache_lock); | 788 | spin_lock(&dcache_lock); |
789 | spin_lock(&sbi->lookup_lock); | ||
790 | spin_lock(&dentry->d_lock); | ||
779 | if (!list_empty(&dentry->d_subdirs)) { | 791 | if (!list_empty(&dentry->d_subdirs)) { |
792 | spin_unlock(&dentry->d_lock); | ||
793 | spin_unlock(&sbi->lookup_lock); | ||
780 | spin_unlock(&dcache_lock); | 794 | spin_unlock(&dcache_lock); |
781 | return -ENOTEMPTY; | 795 | return -ENOTEMPTY; |
782 | } | 796 | } |
783 | autofs4_add_expiring(dentry); | 797 | __autofs4_add_expiring(dentry); |
784 | spin_lock(&dentry->d_lock); | 798 | spin_unlock(&sbi->lookup_lock); |
785 | __d_drop(dentry); | 799 | __d_drop(dentry); |
786 | spin_unlock(&dentry->d_lock); | 800 | spin_unlock(&dentry->d_lock); |
787 | spin_unlock(&dcache_lock); | 801 | spin_unlock(&dcache_lock); |
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 571f270dca0f..2c924e8d85fe 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c | |||
@@ -113,6 +113,7 @@ static int __dcache_readdir(struct file *filp, | |||
113 | last); | 113 | last); |
114 | 114 | ||
115 | spin_lock(&dcache_lock); | 115 | spin_lock(&dcache_lock); |
116 | spin_lock(&parent->d_lock); | ||
116 | 117 | ||
117 | /* start at beginning? */ | 118 | /* start at beginning? */ |
118 | if (filp->f_pos == 2 || last == NULL || | 119 | if (filp->f_pos == 2 || last == NULL || |
@@ -136,7 +137,7 @@ more: | |||
136 | fi->at_end = 1; | 137 | fi->at_end = 1; |
137 | goto out_unlock; | 138 | goto out_unlock; |
138 | } | 139 | } |
139 | spin_lock(&dentry->d_lock); | 140 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); |
140 | if (!d_unhashed(dentry) && dentry->d_inode && | 141 | if (!d_unhashed(dentry) && dentry->d_inode && |
141 | ceph_snap(dentry->d_inode) != CEPH_SNAPDIR && | 142 | ceph_snap(dentry->d_inode) != CEPH_SNAPDIR && |
142 | ceph_ino(dentry->d_inode) != CEPH_INO_CEPH && | 143 | ceph_ino(dentry->d_inode) != CEPH_INO_CEPH && |
@@ -154,6 +155,7 @@ more: | |||
154 | 155 | ||
155 | dget_dlock(dentry); | 156 | dget_dlock(dentry); |
156 | spin_unlock(&dentry->d_lock); | 157 | spin_unlock(&dentry->d_lock); |
158 | spin_unlock(&parent->d_lock); | ||
157 | spin_unlock(&dcache_lock); | 159 | spin_unlock(&dcache_lock); |
158 | 160 | ||
159 | dout(" %llu (%llu) dentry %p %.*s %p\n", di->offset, filp->f_pos, | 161 | dout(" %llu (%llu) dentry %p %.*s %p\n", di->offset, filp->f_pos, |
@@ -188,10 +190,12 @@ more: | |||
188 | } | 190 | } |
189 | 191 | ||
190 | spin_lock(&dcache_lock); | 192 | spin_lock(&dcache_lock); |
193 | spin_lock(&parent->d_lock); | ||
191 | p = p->prev; /* advance to next dentry */ | 194 | p = p->prev; /* advance to next dentry */ |
192 | goto more; | 195 | goto more; |
193 | 196 | ||
194 | out_unlock: | 197 | out_unlock: |
198 | spin_unlock(&parent->d_lock); | ||
195 | spin_unlock(&dcache_lock); | 199 | spin_unlock(&dcache_lock); |
196 | out: | 200 | out: |
197 | if (last) | 201 | if (last) |
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index bb68c799074d..2c6944473366 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c | |||
@@ -842,11 +842,13 @@ static void ceph_set_dentry_offset(struct dentry *dn) | |||
842 | spin_unlock(&inode->i_lock); | 842 | spin_unlock(&inode->i_lock); |
843 | 843 | ||
844 | spin_lock(&dcache_lock); | 844 | spin_lock(&dcache_lock); |
845 | spin_lock(&dn->d_lock); | 845 | spin_lock(&dir->d_lock); |
846 | spin_lock_nested(&dn->d_lock, DENTRY_D_LOCK_NESTED); | ||
846 | list_move(&dn->d_u.d_child, &dir->d_subdirs); | 847 | list_move(&dn->d_u.d_child, &dir->d_subdirs); |
847 | dout("set_dentry_offset %p %lld (%p %p)\n", dn, di->offset, | 848 | dout("set_dentry_offset %p %lld (%p %p)\n", dn, di->offset, |
848 | dn->d_u.d_child.prev, dn->d_u.d_child.next); | 849 | dn->d_u.d_child.prev, dn->d_u.d_child.next); |
849 | spin_unlock(&dn->d_lock); | 850 | spin_unlock(&dn->d_lock); |
851 | spin_unlock(&dir->d_lock); | ||
850 | spin_unlock(&dcache_lock); | 852 | spin_unlock(&dcache_lock); |
851 | } | 853 | } |
852 | 854 | ||
@@ -1232,9 +1234,11 @@ retry_lookup: | |||
1232 | } else { | 1234 | } else { |
1233 | /* reorder parent's d_subdirs */ | 1235 | /* reorder parent's d_subdirs */ |
1234 | spin_lock(&dcache_lock); | 1236 | spin_lock(&dcache_lock); |
1235 | spin_lock(&dn->d_lock); | 1237 | spin_lock(&parent->d_lock); |
1238 | spin_lock_nested(&dn->d_lock, DENTRY_D_LOCK_NESTED); | ||
1236 | list_move(&dn->d_u.d_child, &parent->d_subdirs); | 1239 | list_move(&dn->d_u.d_child, &parent->d_subdirs); |
1237 | spin_unlock(&dn->d_lock); | 1240 | spin_unlock(&dn->d_lock); |
1241 | spin_unlock(&parent->d_lock); | ||
1238 | spin_unlock(&dcache_lock); | 1242 | spin_unlock(&dcache_lock); |
1239 | } | 1243 | } |
1240 | 1244 | ||
diff --git a/fs/coda/cache.c b/fs/coda/cache.c index 9060f08e70cf..859393fca2b7 100644 --- a/fs/coda/cache.c +++ b/fs/coda/cache.c | |||
@@ -94,6 +94,7 @@ static void coda_flag_children(struct dentry *parent, int flag) | |||
94 | struct dentry *de; | 94 | struct dentry *de; |
95 | 95 | ||
96 | spin_lock(&dcache_lock); | 96 | spin_lock(&dcache_lock); |
97 | spin_lock(&parent->d_lock); | ||
97 | list_for_each(child, &parent->d_subdirs) | 98 | list_for_each(child, &parent->d_subdirs) |
98 | { | 99 | { |
99 | de = list_entry(child, struct dentry, d_u.d_child); | 100 | de = list_entry(child, struct dentry, d_u.d_child); |
@@ -102,6 +103,7 @@ static void coda_flag_children(struct dentry *parent, int flag) | |||
102 | continue; | 103 | continue; |
103 | coda_flag_inode(de->d_inode, flag); | 104 | coda_flag_inode(de->d_inode, flag); |
104 | } | 105 | } |
106 | spin_unlock(&parent->d_lock); | ||
105 | spin_unlock(&dcache_lock); | 107 | spin_unlock(&dcache_lock); |
106 | return; | 108 | return; |
107 | } | 109 | } |
diff --git a/fs/dcache.c b/fs/dcache.c index ee127f9ab274..a661247a20d5 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -47,6 +47,8 @@ | |||
47 | * - d_lru | 47 | * - d_lru |
48 | * - d_count | 48 | * - d_count |
49 | * - d_unhashed() | 49 | * - d_unhashed() |
50 | * - d_parent and d_subdirs | ||
51 | * - childrens' d_child and d_parent | ||
50 | * | 52 | * |
51 | * Ordering: | 53 | * Ordering: |
52 | * dcache_lock | 54 | * dcache_lock |
@@ -223,24 +225,22 @@ static void dentry_lru_move_tail(struct dentry *dentry) | |||
223 | * | 225 | * |
224 | * If this is the root of the dentry tree, return NULL. | 226 | * If this is the root of the dentry tree, return NULL. |
225 | * | 227 | * |
226 | * dcache_lock and d_lock must be held by caller, are dropped by d_kill. | 228 | * dcache_lock and d_lock and d_parent->d_lock must be held by caller, and |
229 | * are dropped by d_kill. | ||
227 | */ | 230 | */ |
228 | static struct dentry *d_kill(struct dentry *dentry) | 231 | static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent) |
229 | __releases(dentry->d_lock) | 232 | __releases(dentry->d_lock) |
233 | __releases(parent->d_lock) | ||
230 | __releases(dcache_lock) | 234 | __releases(dcache_lock) |
231 | { | 235 | { |
232 | struct dentry *parent; | ||
233 | |||
234 | list_del(&dentry->d_u.d_child); | 236 | list_del(&dentry->d_u.d_child); |
237 | if (parent) | ||
238 | spin_unlock(&parent->d_lock); | ||
235 | dentry_iput(dentry); | 239 | dentry_iput(dentry); |
236 | /* | 240 | /* |
237 | * dentry_iput drops the locks, at which point nobody (except | 241 | * dentry_iput drops the locks, at which point nobody (except |
238 | * transient RCU lookups) can reach this dentry. | 242 | * transient RCU lookups) can reach this dentry. |
239 | */ | 243 | */ |
240 | if (IS_ROOT(dentry)) | ||
241 | parent = NULL; | ||
242 | else | ||
243 | parent = dentry->d_parent; | ||
244 | d_free(dentry); | 244 | d_free(dentry); |
245 | return parent; | 245 | return parent; |
246 | } | 246 | } |
@@ -312,6 +312,7 @@ EXPORT_SYMBOL(d_drop); | |||
312 | 312 | ||
313 | void dput(struct dentry *dentry) | 313 | void dput(struct dentry *dentry) |
314 | { | 314 | { |
315 | struct dentry *parent; | ||
315 | if (!dentry) | 316 | if (!dentry) |
316 | return; | 317 | return; |
317 | 318 | ||
@@ -319,6 +320,10 @@ repeat: | |||
319 | if (dentry->d_count == 1) | 320 | if (dentry->d_count == 1) |
320 | might_sleep(); | 321 | might_sleep(); |
321 | spin_lock(&dentry->d_lock); | 322 | spin_lock(&dentry->d_lock); |
323 | if (IS_ROOT(dentry)) | ||
324 | parent = NULL; | ||
325 | else | ||
326 | parent = dentry->d_parent; | ||
322 | if (dentry->d_count == 1) { | 327 | if (dentry->d_count == 1) { |
323 | if (!spin_trylock(&dcache_lock)) { | 328 | if (!spin_trylock(&dcache_lock)) { |
324 | /* | 329 | /* |
@@ -330,10 +335,17 @@ repeat: | |||
330 | spin_unlock(&dentry->d_lock); | 335 | spin_unlock(&dentry->d_lock); |
331 | goto repeat; | 336 | goto repeat; |
332 | } | 337 | } |
338 | if (parent && !spin_trylock(&parent->d_lock)) { | ||
339 | spin_unlock(&dentry->d_lock); | ||
340 | spin_unlock(&dcache_lock); | ||
341 | goto repeat; | ||
342 | } | ||
333 | } | 343 | } |
334 | dentry->d_count--; | 344 | dentry->d_count--; |
335 | if (dentry->d_count) { | 345 | if (dentry->d_count) { |
336 | spin_unlock(&dentry->d_lock); | 346 | spin_unlock(&dentry->d_lock); |
347 | if (parent) | ||
348 | spin_unlock(&parent->d_lock); | ||
337 | spin_unlock(&dcache_lock); | 349 | spin_unlock(&dcache_lock); |
338 | return; | 350 | return; |
339 | } | 351 | } |
@@ -355,6 +367,8 @@ repeat: | |||
355 | dentry_lru_add(dentry); | 367 | dentry_lru_add(dentry); |
356 | 368 | ||
357 | spin_unlock(&dentry->d_lock); | 369 | spin_unlock(&dentry->d_lock); |
370 | if (parent) | ||
371 | spin_unlock(&parent->d_lock); | ||
358 | spin_unlock(&dcache_lock); | 372 | spin_unlock(&dcache_lock); |
359 | return; | 373 | return; |
360 | 374 | ||
@@ -363,7 +377,7 @@ unhash_it: | |||
363 | kill_it: | 377 | kill_it: |
364 | /* if dentry was on the d_lru list delete it from there */ | 378 | /* if dentry was on the d_lru list delete it from there */ |
365 | dentry_lru_del(dentry); | 379 | dentry_lru_del(dentry); |
366 | dentry = d_kill(dentry); | 380 | dentry = d_kill(dentry, parent); |
367 | if (dentry) | 381 | if (dentry) |
368 | goto repeat; | 382 | goto repeat; |
369 | } | 383 | } |
@@ -584,12 +598,13 @@ EXPORT_SYMBOL(d_prune_aliases); | |||
584 | * quadratic behavior of shrink_dcache_parent(), but is also expected | 598 | * quadratic behavior of shrink_dcache_parent(), but is also expected |
585 | * to be beneficial in reducing dentry cache fragmentation. | 599 | * to be beneficial in reducing dentry cache fragmentation. |
586 | */ | 600 | */ |
587 | static void prune_one_dentry(struct dentry * dentry) | 601 | static void prune_one_dentry(struct dentry *dentry, struct dentry *parent) |
588 | __releases(dentry->d_lock) | 602 | __releases(dentry->d_lock) |
603 | __releases(parent->d_lock) | ||
589 | __releases(dcache_lock) | 604 | __releases(dcache_lock) |
590 | { | 605 | { |
591 | __d_drop(dentry); | 606 | __d_drop(dentry); |
592 | dentry = d_kill(dentry); | 607 | dentry = d_kill(dentry, parent); |
593 | 608 | ||
594 | /* | 609 | /* |
595 | * Prune ancestors. Locking is simpler than in dput(), | 610 | * Prune ancestors. Locking is simpler than in dput(), |
@@ -597,9 +612,20 @@ static void prune_one_dentry(struct dentry * dentry) | |||
597 | */ | 612 | */ |
598 | while (dentry) { | 613 | while (dentry) { |
599 | spin_lock(&dcache_lock); | 614 | spin_lock(&dcache_lock); |
615 | again: | ||
600 | spin_lock(&dentry->d_lock); | 616 | spin_lock(&dentry->d_lock); |
617 | if (IS_ROOT(dentry)) | ||
618 | parent = NULL; | ||
619 | else | ||
620 | parent = dentry->d_parent; | ||
621 | if (parent && !spin_trylock(&parent->d_lock)) { | ||
622 | spin_unlock(&dentry->d_lock); | ||
623 | goto again; | ||
624 | } | ||
601 | dentry->d_count--; | 625 | dentry->d_count--; |
602 | if (dentry->d_count) { | 626 | if (dentry->d_count) { |
627 | if (parent) | ||
628 | spin_unlock(&parent->d_lock); | ||
603 | spin_unlock(&dentry->d_lock); | 629 | spin_unlock(&dentry->d_lock); |
604 | spin_unlock(&dcache_lock); | 630 | spin_unlock(&dcache_lock); |
605 | return; | 631 | return; |
@@ -607,7 +633,7 @@ static void prune_one_dentry(struct dentry * dentry) | |||
607 | 633 | ||
608 | dentry_lru_del(dentry); | 634 | dentry_lru_del(dentry); |
609 | __d_drop(dentry); | 635 | __d_drop(dentry); |
610 | dentry = d_kill(dentry); | 636 | dentry = d_kill(dentry, parent); |
611 | } | 637 | } |
612 | } | 638 | } |
613 | 639 | ||
@@ -616,29 +642,40 @@ static void shrink_dentry_list(struct list_head *list) | |||
616 | struct dentry *dentry; | 642 | struct dentry *dentry; |
617 | 643 | ||
618 | while (!list_empty(list)) { | 644 | while (!list_empty(list)) { |
645 | struct dentry *parent; | ||
646 | |||
619 | dentry = list_entry(list->prev, struct dentry, d_lru); | 647 | dentry = list_entry(list->prev, struct dentry, d_lru); |
620 | 648 | ||
621 | if (!spin_trylock(&dentry->d_lock)) { | 649 | if (!spin_trylock(&dentry->d_lock)) { |
650 | relock: | ||
622 | spin_unlock(&dcache_lru_lock); | 651 | spin_unlock(&dcache_lru_lock); |
623 | cpu_relax(); | 652 | cpu_relax(); |
624 | spin_lock(&dcache_lru_lock); | 653 | spin_lock(&dcache_lru_lock); |
625 | continue; | 654 | continue; |
626 | } | 655 | } |
627 | 656 | ||
628 | __dentry_lru_del(dentry); | ||
629 | |||
630 | /* | 657 | /* |
631 | * We found an inuse dentry which was not removed from | 658 | * We found an inuse dentry which was not removed from |
632 | * the LRU because of laziness during lookup. Do not free | 659 | * the LRU because of laziness during lookup. Do not free |
633 | * it - just keep it off the LRU list. | 660 | * it - just keep it off the LRU list. |
634 | */ | 661 | */ |
635 | if (dentry->d_count) { | 662 | if (dentry->d_count) { |
663 | __dentry_lru_del(dentry); | ||
636 | spin_unlock(&dentry->d_lock); | 664 | spin_unlock(&dentry->d_lock); |
637 | continue; | 665 | continue; |
638 | } | 666 | } |
667 | if (IS_ROOT(dentry)) | ||
668 | parent = NULL; | ||
669 | else | ||
670 | parent = dentry->d_parent; | ||
671 | if (parent && !spin_trylock(&parent->d_lock)) { | ||
672 | spin_unlock(&dentry->d_lock); | ||
673 | goto relock; | ||
674 | } | ||
675 | __dentry_lru_del(dentry); | ||
639 | spin_unlock(&dcache_lru_lock); | 676 | spin_unlock(&dcache_lru_lock); |
640 | 677 | ||
641 | prune_one_dentry(dentry); | 678 | prune_one_dentry(dentry, parent); |
642 | /* dcache_lock and dentry->d_lock dropped */ | 679 | /* dcache_lock and dentry->d_lock dropped */ |
643 | spin_lock(&dcache_lock); | 680 | spin_lock(&dcache_lock); |
644 | spin_lock(&dcache_lru_lock); | 681 | spin_lock(&dcache_lru_lock); |
@@ -833,14 +870,16 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) | |||
833 | /* this is a branch with children - detach all of them | 870 | /* this is a branch with children - detach all of them |
834 | * from the system in one go */ | 871 | * from the system in one go */ |
835 | spin_lock(&dcache_lock); | 872 | spin_lock(&dcache_lock); |
873 | spin_lock(&dentry->d_lock); | ||
836 | list_for_each_entry(loop, &dentry->d_subdirs, | 874 | list_for_each_entry(loop, &dentry->d_subdirs, |
837 | d_u.d_child) { | 875 | d_u.d_child) { |
838 | spin_lock(&loop->d_lock); | 876 | spin_lock_nested(&loop->d_lock, |
877 | DENTRY_D_LOCK_NESTED); | ||
839 | dentry_lru_del(loop); | 878 | dentry_lru_del(loop); |
840 | __d_drop(loop); | 879 | __d_drop(loop); |
841 | spin_unlock(&loop->d_lock); | 880 | spin_unlock(&loop->d_lock); |
842 | cond_resched_lock(&dcache_lock); | ||
843 | } | 881 | } |
882 | spin_unlock(&dentry->d_lock); | ||
844 | spin_unlock(&dcache_lock); | 883 | spin_unlock(&dcache_lock); |
845 | 884 | ||
846 | /* move to the first child */ | 885 | /* move to the first child */ |
@@ -868,16 +907,17 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) | |||
868 | BUG(); | 907 | BUG(); |
869 | } | 908 | } |
870 | 909 | ||
871 | if (IS_ROOT(dentry)) | 910 | if (IS_ROOT(dentry)) { |
872 | parent = NULL; | 911 | parent = NULL; |
873 | else { | 912 | list_del(&dentry->d_u.d_child); |
913 | } else { | ||
874 | parent = dentry->d_parent; | 914 | parent = dentry->d_parent; |
875 | spin_lock(&parent->d_lock); | 915 | spin_lock(&parent->d_lock); |
876 | parent->d_count--; | 916 | parent->d_count--; |
917 | list_del(&dentry->d_u.d_child); | ||
877 | spin_unlock(&parent->d_lock); | 918 | spin_unlock(&parent->d_lock); |
878 | } | 919 | } |
879 | 920 | ||
880 | list_del(&dentry->d_u.d_child); | ||
881 | detached++; | 921 | detached++; |
882 | 922 | ||
883 | inode = dentry->d_inode; | 923 | inode = dentry->d_inode; |
@@ -958,6 +998,7 @@ int have_submounts(struct dentry *parent) | |||
958 | spin_lock(&dcache_lock); | 998 | spin_lock(&dcache_lock); |
959 | if (d_mountpoint(parent)) | 999 | if (d_mountpoint(parent)) |
960 | goto positive; | 1000 | goto positive; |
1001 | spin_lock(&this_parent->d_lock); | ||
961 | repeat: | 1002 | repeat: |
962 | next = this_parent->d_subdirs.next; | 1003 | next = this_parent->d_subdirs.next; |
963 | resume: | 1004 | resume: |
@@ -965,22 +1006,34 @@ resume: | |||
965 | struct list_head *tmp = next; | 1006 | struct list_head *tmp = next; |
966 | struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); | 1007 | struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); |
967 | next = tmp->next; | 1008 | next = tmp->next; |
1009 | |||
1010 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); | ||
968 | /* Have we found a mount point ? */ | 1011 | /* Have we found a mount point ? */ |
969 | if (d_mountpoint(dentry)) | 1012 | if (d_mountpoint(dentry)) { |
1013 | spin_unlock(&dentry->d_lock); | ||
1014 | spin_unlock(&this_parent->d_lock); | ||
970 | goto positive; | 1015 | goto positive; |
1016 | } | ||
971 | if (!list_empty(&dentry->d_subdirs)) { | 1017 | if (!list_empty(&dentry->d_subdirs)) { |
1018 | spin_unlock(&this_parent->d_lock); | ||
1019 | spin_release(&dentry->d_lock.dep_map, 1, _RET_IP_); | ||
972 | this_parent = dentry; | 1020 | this_parent = dentry; |
1021 | spin_acquire(&this_parent->d_lock.dep_map, 0, 1, _RET_IP_); | ||
973 | goto repeat; | 1022 | goto repeat; |
974 | } | 1023 | } |
1024 | spin_unlock(&dentry->d_lock); | ||
975 | } | 1025 | } |
976 | /* | 1026 | /* |
977 | * All done at this level ... ascend and resume the search. | 1027 | * All done at this level ... ascend and resume the search. |
978 | */ | 1028 | */ |
979 | if (this_parent != parent) { | 1029 | if (this_parent != parent) { |
980 | next = this_parent->d_u.d_child.next; | 1030 | next = this_parent->d_u.d_child.next; |
1031 | spin_unlock(&this_parent->d_lock); | ||
981 | this_parent = this_parent->d_parent; | 1032 | this_parent = this_parent->d_parent; |
1033 | spin_lock(&this_parent->d_lock); | ||
982 | goto resume; | 1034 | goto resume; |
983 | } | 1035 | } |
1036 | spin_unlock(&this_parent->d_lock); | ||
984 | spin_unlock(&dcache_lock); | 1037 | spin_unlock(&dcache_lock); |
985 | return 0; /* No mount points found in tree */ | 1038 | return 0; /* No mount points found in tree */ |
986 | positive: | 1039 | positive: |
@@ -1010,6 +1063,7 @@ static int select_parent(struct dentry * parent) | |||
1010 | int found = 0; | 1063 | int found = 0; |
1011 | 1064 | ||
1012 | spin_lock(&dcache_lock); | 1065 | spin_lock(&dcache_lock); |
1066 | spin_lock(&this_parent->d_lock); | ||
1013 | repeat: | 1067 | repeat: |
1014 | next = this_parent->d_subdirs.next; | 1068 | next = this_parent->d_subdirs.next; |
1015 | resume: | 1069 | resume: |
@@ -1017,8 +1071,9 @@ resume: | |||
1017 | struct list_head *tmp = next; | 1071 | struct list_head *tmp = next; |
1018 | struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); | 1072 | struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); |
1019 | next = tmp->next; | 1073 | next = tmp->next; |
1074 | BUG_ON(this_parent == dentry); | ||
1020 | 1075 | ||
1021 | spin_lock(&dentry->d_lock); | 1076 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); |
1022 | 1077 | ||
1023 | /* | 1078 | /* |
1024 | * move only zero ref count dentries to the end | 1079 | * move only zero ref count dentries to the end |
@@ -1031,33 +1086,44 @@ resume: | |||
1031 | dentry_lru_del(dentry); | 1086 | dentry_lru_del(dentry); |
1032 | } | 1087 | } |
1033 | 1088 | ||
1034 | spin_unlock(&dentry->d_lock); | ||
1035 | |||
1036 | /* | 1089 | /* |
1037 | * We can return to the caller if we have found some (this | 1090 | * We can return to the caller if we have found some (this |
1038 | * ensures forward progress). We'll be coming back to find | 1091 | * ensures forward progress). We'll be coming back to find |
1039 | * the rest. | 1092 | * the rest. |
1040 | */ | 1093 | */ |
1041 | if (found && need_resched()) | 1094 | if (found && need_resched()) { |
1095 | spin_unlock(&dentry->d_lock); | ||
1042 | goto out; | 1096 | goto out; |
1097 | } | ||
1043 | 1098 | ||
1044 | /* | 1099 | /* |
1045 | * Descend a level if the d_subdirs list is non-empty. | 1100 | * Descend a level if the d_subdirs list is non-empty. |
1046 | */ | 1101 | */ |
1047 | if (!list_empty(&dentry->d_subdirs)) { | 1102 | if (!list_empty(&dentry->d_subdirs)) { |
1103 | spin_unlock(&this_parent->d_lock); | ||
1104 | spin_release(&dentry->d_lock.dep_map, 1, _RET_IP_); | ||
1048 | this_parent = dentry; | 1105 | this_parent = dentry; |
1106 | spin_acquire(&this_parent->d_lock.dep_map, 0, 1, _RET_IP_); | ||
1049 | goto repeat; | 1107 | goto repeat; |
1050 | } | 1108 | } |
1109 | |||
1110 | spin_unlock(&dentry->d_lock); | ||
1051 | } | 1111 | } |
1052 | /* | 1112 | /* |
1053 | * All done at this level ... ascend and resume the search. | 1113 | * All done at this level ... ascend and resume the search. |
1054 | */ | 1114 | */ |
1055 | if (this_parent != parent) { | 1115 | if (this_parent != parent) { |
1116 | struct dentry *tmp; | ||
1056 | next = this_parent->d_u.d_child.next; | 1117 | next = this_parent->d_u.d_child.next; |
1057 | this_parent = this_parent->d_parent; | 1118 | tmp = this_parent->d_parent; |
1119 | spin_unlock(&this_parent->d_lock); | ||
1120 | BUG_ON(tmp == this_parent); | ||
1121 | this_parent = tmp; | ||
1122 | spin_lock(&this_parent->d_lock); | ||
1058 | goto resume; | 1123 | goto resume; |
1059 | } | 1124 | } |
1060 | out: | 1125 | out: |
1126 | spin_unlock(&this_parent->d_lock); | ||
1061 | spin_unlock(&dcache_lock); | 1127 | spin_unlock(&dcache_lock); |
1062 | return found; | 1128 | return found; |
1063 | } | 1129 | } |
@@ -1155,18 +1221,19 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) | |||
1155 | INIT_LIST_HEAD(&dentry->d_lru); | 1221 | INIT_LIST_HEAD(&dentry->d_lru); |
1156 | INIT_LIST_HEAD(&dentry->d_subdirs); | 1222 | INIT_LIST_HEAD(&dentry->d_subdirs); |
1157 | INIT_LIST_HEAD(&dentry->d_alias); | 1223 | INIT_LIST_HEAD(&dentry->d_alias); |
1224 | INIT_LIST_HEAD(&dentry->d_u.d_child); | ||
1158 | 1225 | ||
1159 | if (parent) { | 1226 | if (parent) { |
1160 | dentry->d_parent = dget(parent); | 1227 | spin_lock(&dcache_lock); |
1228 | spin_lock(&parent->d_lock); | ||
1229 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); | ||
1230 | dentry->d_parent = dget_dlock(parent); | ||
1161 | dentry->d_sb = parent->d_sb; | 1231 | dentry->d_sb = parent->d_sb; |
1162 | } else { | ||
1163 | INIT_LIST_HEAD(&dentry->d_u.d_child); | ||
1164 | } | ||
1165 | |||
1166 | spin_lock(&dcache_lock); | ||
1167 | if (parent) | ||
1168 | list_add(&dentry->d_u.d_child, &parent->d_subdirs); | 1232 | list_add(&dentry->d_u.d_child, &parent->d_subdirs); |
1169 | spin_unlock(&dcache_lock); | 1233 | spin_unlock(&dentry->d_lock); |
1234 | spin_unlock(&parent->d_lock); | ||
1235 | spin_unlock(&dcache_lock); | ||
1236 | } | ||
1170 | 1237 | ||
1171 | this_cpu_inc(nr_dentry); | 1238 | this_cpu_inc(nr_dentry); |
1172 | 1239 | ||
@@ -1684,13 +1751,18 @@ int d_validate(struct dentry *dentry, struct dentry *dparent) | |||
1684 | struct dentry *child; | 1751 | struct dentry *child; |
1685 | 1752 | ||
1686 | spin_lock(&dcache_lock); | 1753 | spin_lock(&dcache_lock); |
1754 | spin_lock(&dparent->d_lock); | ||
1687 | list_for_each_entry(child, &dparent->d_subdirs, d_u.d_child) { | 1755 | list_for_each_entry(child, &dparent->d_subdirs, d_u.d_child) { |
1688 | if (dentry == child) { | 1756 | if (dentry == child) { |
1689 | __dget_locked(dentry); | 1757 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); |
1758 | __dget_locked_dlock(dentry); | ||
1759 | spin_unlock(&dentry->d_lock); | ||
1760 | spin_unlock(&dparent->d_lock); | ||
1690 | spin_unlock(&dcache_lock); | 1761 | spin_unlock(&dcache_lock); |
1691 | return 1; | 1762 | return 1; |
1692 | } | 1763 | } |
1693 | } | 1764 | } |
1765 | spin_unlock(&dparent->d_lock); | ||
1694 | spin_unlock(&dcache_lock); | 1766 | spin_unlock(&dcache_lock); |
1695 | 1767 | ||
1696 | return 0; | 1768 | return 0; |
@@ -1802,17 +1874,6 @@ void dentry_update_name_case(struct dentry *dentry, struct qstr *name) | |||
1802 | } | 1874 | } |
1803 | EXPORT_SYMBOL(dentry_update_name_case); | 1875 | EXPORT_SYMBOL(dentry_update_name_case); |
1804 | 1876 | ||
1805 | /* | ||
1806 | * When switching names, the actual string doesn't strictly have to | ||
1807 | * be preserved in the target - because we're dropping the target | ||
1808 | * anyway. As such, we can just do a simple memcpy() to copy over | ||
1809 | * the new name before we switch. | ||
1810 | * | ||
1811 | * Note that we have to be a lot more careful about getting the hash | ||
1812 | * switched - we have to switch the hash value properly even if it | ||
1813 | * then no longer matches the actual (corrupted) string of the target. | ||
1814 | * The hash value has to match the hash queue that the dentry is on.. | ||
1815 | */ | ||
1816 | static void switch_names(struct dentry *dentry, struct dentry *target) | 1877 | static void switch_names(struct dentry *dentry, struct dentry *target) |
1817 | { | 1878 | { |
1818 | if (dname_external(target)) { | 1879 | if (dname_external(target)) { |
@@ -1854,18 +1915,53 @@ static void switch_names(struct dentry *dentry, struct dentry *target) | |||
1854 | swap(dentry->d_name.len, target->d_name.len); | 1915 | swap(dentry->d_name.len, target->d_name.len); |
1855 | } | 1916 | } |
1856 | 1917 | ||
1918 | static void dentry_lock_for_move(struct dentry *dentry, struct dentry *target) | ||
1919 | { | ||
1920 | /* | ||
1921 | * XXXX: do we really need to take target->d_lock? | ||
1922 | */ | ||
1923 | if (IS_ROOT(dentry) || dentry->d_parent == target->d_parent) | ||
1924 | spin_lock(&target->d_parent->d_lock); | ||
1925 | else { | ||
1926 | if (d_ancestor(dentry->d_parent, target->d_parent)) { | ||
1927 | spin_lock(&dentry->d_parent->d_lock); | ||
1928 | spin_lock_nested(&target->d_parent->d_lock, | ||
1929 | DENTRY_D_LOCK_NESTED); | ||
1930 | } else { | ||
1931 | spin_lock(&target->d_parent->d_lock); | ||
1932 | spin_lock_nested(&dentry->d_parent->d_lock, | ||
1933 | DENTRY_D_LOCK_NESTED); | ||
1934 | } | ||
1935 | } | ||
1936 | if (target < dentry) { | ||
1937 | spin_lock_nested(&target->d_lock, 2); | ||
1938 | spin_lock_nested(&dentry->d_lock, 3); | ||
1939 | } else { | ||
1940 | spin_lock_nested(&dentry->d_lock, 2); | ||
1941 | spin_lock_nested(&target->d_lock, 3); | ||
1942 | } | ||
1943 | } | ||
1944 | |||
1945 | static void dentry_unlock_parents_for_move(struct dentry *dentry, | ||
1946 | struct dentry *target) | ||
1947 | { | ||
1948 | if (target->d_parent != dentry->d_parent) | ||
1949 | spin_unlock(&dentry->d_parent->d_lock); | ||
1950 | if (target->d_parent != target) | ||
1951 | spin_unlock(&target->d_parent->d_lock); | ||
1952 | } | ||
1953 | |||
1857 | /* | 1954 | /* |
1858 | * We cannibalize "target" when moving dentry on top of it, | 1955 | * When switching names, the actual string doesn't strictly have to |
1859 | * because it's going to be thrown away anyway. We could be more | 1956 | * be preserved in the target - because we're dropping the target |
1860 | * polite about it, though. | 1957 | * anyway. As such, we can just do a simple memcpy() to copy over |
1861 | * | 1958 | * the new name before we switch. |
1862 | * This forceful removal will result in ugly /proc output if | 1959 | * |
1863 | * somebody holds a file open that got deleted due to a rename. | 1960 | * Note that we have to be a lot more careful about getting the hash |
1864 | * We could be nicer about the deleted file, and let it show | 1961 | * switched - we have to switch the hash value properly even if it |
1865 | * up under the name it had before it was deleted rather than | 1962 | * then no longer matches the actual (corrupted) string of the target. |
1866 | * under the original name of the file that was moved on top of it. | 1963 | * The hash value has to match the hash queue that the dentry is on.. |
1867 | */ | 1964 | */ |
1868 | |||
1869 | /* | 1965 | /* |
1870 | * d_move_locked - move a dentry | 1966 | * d_move_locked - move a dentry |
1871 | * @dentry: entry to move | 1967 | * @dentry: entry to move |
@@ -1879,20 +1975,12 @@ static void d_move_locked(struct dentry * dentry, struct dentry * target) | |||
1879 | if (!dentry->d_inode) | 1975 | if (!dentry->d_inode) |
1880 | printk(KERN_WARNING "VFS: moving negative dcache entry\n"); | 1976 | printk(KERN_WARNING "VFS: moving negative dcache entry\n"); |
1881 | 1977 | ||
1978 | BUG_ON(d_ancestor(dentry, target)); | ||
1979 | BUG_ON(d_ancestor(target, dentry)); | ||
1980 | |||
1882 | write_seqlock(&rename_lock); | 1981 | write_seqlock(&rename_lock); |
1883 | /* | 1982 | |
1884 | * XXXX: do we really need to take target->d_lock? | 1983 | dentry_lock_for_move(dentry, target); |
1885 | */ | ||
1886 | if (d_ancestor(dentry, target)) { | ||
1887 | spin_lock(&dentry->d_lock); | ||
1888 | spin_lock_nested(&target->d_lock, DENTRY_D_LOCK_NESTED); | ||
1889 | } else if (d_ancestor(target, dentry) || target < dentry) { | ||
1890 | spin_lock(&target->d_lock); | ||
1891 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); | ||
1892 | } else { | ||
1893 | spin_lock(&dentry->d_lock); | ||
1894 | spin_lock_nested(&target->d_lock, DENTRY_D_LOCK_NESTED); | ||
1895 | } | ||
1896 | 1984 | ||
1897 | /* Move the dentry to the target hash queue, if on different bucket */ | 1985 | /* Move the dentry to the target hash queue, if on different bucket */ |
1898 | spin_lock(&dcache_hash_lock); | 1986 | spin_lock(&dcache_hash_lock); |
@@ -1924,6 +2012,8 @@ static void d_move_locked(struct dentry * dentry, struct dentry * target) | |||
1924 | } | 2012 | } |
1925 | 2013 | ||
1926 | list_add(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs); | 2014 | list_add(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs); |
2015 | |||
2016 | dentry_unlock_parents_for_move(dentry, target); | ||
1927 | spin_unlock(&target->d_lock); | 2017 | spin_unlock(&target->d_lock); |
1928 | fsnotify_d_move(dentry); | 2018 | fsnotify_d_move(dentry); |
1929 | spin_unlock(&dentry->d_lock); | 2019 | spin_unlock(&dentry->d_lock); |
@@ -2013,17 +2103,20 @@ out_err: | |||
2013 | /* | 2103 | /* |
2014 | * Prepare an anonymous dentry for life in the superblock's dentry tree as a | 2104 | * Prepare an anonymous dentry for life in the superblock's dentry tree as a |
2015 | * named dentry in place of the dentry to be replaced. | 2105 | * named dentry in place of the dentry to be replaced. |
2106 | * returns with anon->d_lock held! | ||
2016 | */ | 2107 | */ |
2017 | static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon) | 2108 | static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon) |
2018 | { | 2109 | { |
2019 | struct dentry *dparent, *aparent; | 2110 | struct dentry *dparent, *aparent; |
2020 | 2111 | ||
2021 | switch_names(dentry, anon); | 2112 | dentry_lock_for_move(anon, dentry); |
2022 | swap(dentry->d_name.hash, anon->d_name.hash); | ||
2023 | 2113 | ||
2024 | dparent = dentry->d_parent; | 2114 | dparent = dentry->d_parent; |
2025 | aparent = anon->d_parent; | 2115 | aparent = anon->d_parent; |
2026 | 2116 | ||
2117 | switch_names(dentry, anon); | ||
2118 | swap(dentry->d_name.hash, anon->d_name.hash); | ||
2119 | |||
2027 | dentry->d_parent = (aparent == anon) ? dentry : aparent; | 2120 | dentry->d_parent = (aparent == anon) ? dentry : aparent; |
2028 | list_del(&dentry->d_u.d_child); | 2121 | list_del(&dentry->d_u.d_child); |
2029 | if (!IS_ROOT(dentry)) | 2122 | if (!IS_ROOT(dentry)) |
@@ -2038,6 +2131,10 @@ static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon) | |||
2038 | else | 2131 | else |
2039 | INIT_LIST_HEAD(&anon->d_u.d_child); | 2132 | INIT_LIST_HEAD(&anon->d_u.d_child); |
2040 | 2133 | ||
2134 | dentry_unlock_parents_for_move(anon, dentry); | ||
2135 | spin_unlock(&dentry->d_lock); | ||
2136 | |||
2137 | /* anon->d_lock still locked, returns locked */ | ||
2041 | anon->d_flags &= ~DCACHE_DISCONNECTED; | 2138 | anon->d_flags &= ~DCACHE_DISCONNECTED; |
2042 | } | 2139 | } |
2043 | 2140 | ||
@@ -2073,7 +2170,6 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) | |||
2073 | /* Is this an anonymous mountpoint that we could splice | 2170 | /* Is this an anonymous mountpoint that we could splice |
2074 | * into our tree? */ | 2171 | * into our tree? */ |
2075 | if (IS_ROOT(alias)) { | 2172 | if (IS_ROOT(alias)) { |
2076 | spin_lock(&alias->d_lock); | ||
2077 | __d_materialise_dentry(dentry, alias); | 2173 | __d_materialise_dentry(dentry, alias); |
2078 | __d_drop(alias); | 2174 | __d_drop(alias); |
2079 | goto found; | 2175 | goto found; |
@@ -2558,6 +2654,7 @@ void d_genocide(struct dentry *root) | |||
2558 | struct list_head *next; | 2654 | struct list_head *next; |
2559 | 2655 | ||
2560 | spin_lock(&dcache_lock); | 2656 | spin_lock(&dcache_lock); |
2657 | spin_lock(&this_parent->d_lock); | ||
2561 | repeat: | 2658 | repeat: |
2562 | next = this_parent->d_subdirs.next; | 2659 | next = this_parent->d_subdirs.next; |
2563 | resume: | 2660 | resume: |
@@ -2571,8 +2668,10 @@ resume: | |||
2571 | continue; | 2668 | continue; |
2572 | } | 2669 | } |
2573 | if (!list_empty(&dentry->d_subdirs)) { | 2670 | if (!list_empty(&dentry->d_subdirs)) { |
2574 | spin_unlock(&dentry->d_lock); | 2671 | spin_unlock(&this_parent->d_lock); |
2672 | spin_release(&dentry->d_lock.dep_map, 1, _RET_IP_); | ||
2575 | this_parent = dentry; | 2673 | this_parent = dentry; |
2674 | spin_acquire(&this_parent->d_lock.dep_map, 0, 1, _RET_IP_); | ||
2576 | goto repeat; | 2675 | goto repeat; |
2577 | } | 2676 | } |
2578 | dentry->d_count--; | 2677 | dentry->d_count--; |
@@ -2580,12 +2679,13 @@ resume: | |||
2580 | } | 2679 | } |
2581 | if (this_parent != root) { | 2680 | if (this_parent != root) { |
2582 | next = this_parent->d_u.d_child.next; | 2681 | next = this_parent->d_u.d_child.next; |
2583 | spin_lock(&this_parent->d_lock); | ||
2584 | this_parent->d_count--; | 2682 | this_parent->d_count--; |
2585 | spin_unlock(&this_parent->d_lock); | 2683 | spin_unlock(&this_parent->d_lock); |
2586 | this_parent = this_parent->d_parent; | 2684 | this_parent = this_parent->d_parent; |
2685 | spin_lock(&this_parent->d_lock); | ||
2587 | goto resume; | 2686 | goto resume; |
2588 | } | 2687 | } |
2688 | spin_unlock(&this_parent->d_lock); | ||
2589 | spin_unlock(&dcache_lock); | 2689 | spin_unlock(&dcache_lock); |
2590 | } | 2690 | } |
2591 | 2691 | ||
diff --git a/fs/libfs.c b/fs/libfs.c index 433e7139c23a..cc4794914b52 100644 --- a/fs/libfs.c +++ b/fs/libfs.c | |||
@@ -81,7 +81,8 @@ int dcache_dir_close(struct inode *inode, struct file *file) | |||
81 | 81 | ||
82 | loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin) | 82 | loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin) |
83 | { | 83 | { |
84 | mutex_lock(&file->f_path.dentry->d_inode->i_mutex); | 84 | struct dentry *dentry = file->f_path.dentry; |
85 | mutex_lock(&dentry->d_inode->i_mutex); | ||
85 | switch (origin) { | 86 | switch (origin) { |
86 | case 1: | 87 | case 1: |
87 | offset += file->f_pos; | 88 | offset += file->f_pos; |
@@ -89,7 +90,7 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin) | |||
89 | if (offset >= 0) | 90 | if (offset >= 0) |
90 | break; | 91 | break; |
91 | default: | 92 | default: |
92 | mutex_unlock(&file->f_path.dentry->d_inode->i_mutex); | 93 | mutex_unlock(&dentry->d_inode->i_mutex); |
93 | return -EINVAL; | 94 | return -EINVAL; |
94 | } | 95 | } |
95 | if (offset != file->f_pos) { | 96 | if (offset != file->f_pos) { |
@@ -100,22 +101,25 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin) | |||
100 | loff_t n = file->f_pos - 2; | 101 | loff_t n = file->f_pos - 2; |
101 | 102 | ||
102 | spin_lock(&dcache_lock); | 103 | spin_lock(&dcache_lock); |
104 | spin_lock(&dentry->d_lock); | ||
105 | /* d_lock not required for cursor */ | ||
103 | list_del(&cursor->d_u.d_child); | 106 | list_del(&cursor->d_u.d_child); |
104 | p = file->f_path.dentry->d_subdirs.next; | 107 | p = dentry->d_subdirs.next; |
105 | while (n && p != &file->f_path.dentry->d_subdirs) { | 108 | while (n && p != &dentry->d_subdirs) { |
106 | struct dentry *next; | 109 | struct dentry *next; |
107 | next = list_entry(p, struct dentry, d_u.d_child); | 110 | next = list_entry(p, struct dentry, d_u.d_child); |
108 | spin_lock(&next->d_lock); | 111 | spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED); |
109 | if (simple_positive(next)) | 112 | if (simple_positive(next)) |
110 | n--; | 113 | n--; |
111 | spin_unlock(&next->d_lock); | 114 | spin_unlock(&next->d_lock); |
112 | p = p->next; | 115 | p = p->next; |
113 | } | 116 | } |
114 | list_add_tail(&cursor->d_u.d_child, p); | 117 | list_add_tail(&cursor->d_u.d_child, p); |
118 | spin_unlock(&dentry->d_lock); | ||
115 | spin_unlock(&dcache_lock); | 119 | spin_unlock(&dcache_lock); |
116 | } | 120 | } |
117 | } | 121 | } |
118 | mutex_unlock(&file->f_path.dentry->d_inode->i_mutex); | 122 | mutex_unlock(&dentry->d_inode->i_mutex); |
119 | return offset; | 123 | return offset; |
120 | } | 124 | } |
121 | 125 | ||
@@ -156,6 +160,7 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
156 | /* fallthrough */ | 160 | /* fallthrough */ |
157 | default: | 161 | default: |
158 | spin_lock(&dcache_lock); | 162 | spin_lock(&dcache_lock); |
163 | spin_lock(&dentry->d_lock); | ||
159 | if (filp->f_pos == 2) | 164 | if (filp->f_pos == 2) |
160 | list_move(q, &dentry->d_subdirs); | 165 | list_move(q, &dentry->d_subdirs); |
161 | 166 | ||
@@ -169,6 +174,7 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
169 | } | 174 | } |
170 | 175 | ||
171 | spin_unlock(&next->d_lock); | 176 | spin_unlock(&next->d_lock); |
177 | spin_unlock(&dentry->d_lock); | ||
172 | spin_unlock(&dcache_lock); | 178 | spin_unlock(&dcache_lock); |
173 | if (filldir(dirent, next->d_name.name, | 179 | if (filldir(dirent, next->d_name.name, |
174 | next->d_name.len, filp->f_pos, | 180 | next->d_name.len, filp->f_pos, |
@@ -176,11 +182,15 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
176 | dt_type(next->d_inode)) < 0) | 182 | dt_type(next->d_inode)) < 0) |
177 | return 0; | 183 | return 0; |
178 | spin_lock(&dcache_lock); | 184 | spin_lock(&dcache_lock); |
185 | spin_lock(&dentry->d_lock); | ||
186 | spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED); | ||
179 | /* next is still alive */ | 187 | /* next is still alive */ |
180 | list_move(q, p); | 188 | list_move(q, p); |
189 | spin_unlock(&next->d_lock); | ||
181 | p = q; | 190 | p = q; |
182 | filp->f_pos++; | 191 | filp->f_pos++; |
183 | } | 192 | } |
193 | spin_unlock(&dentry->d_lock); | ||
184 | spin_unlock(&dcache_lock); | 194 | spin_unlock(&dcache_lock); |
185 | } | 195 | } |
186 | return 0; | 196 | return 0; |
@@ -276,6 +286,7 @@ int simple_empty(struct dentry *dentry) | |||
276 | int ret = 0; | 286 | int ret = 0; |
277 | 287 | ||
278 | spin_lock(&dcache_lock); | 288 | spin_lock(&dcache_lock); |
289 | spin_lock(&dentry->d_lock); | ||
279 | list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) { | 290 | list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) { |
280 | spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED); | 291 | spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED); |
281 | if (simple_positive(child)) { | 292 | if (simple_positive(child)) { |
@@ -286,6 +297,7 @@ int simple_empty(struct dentry *dentry) | |||
286 | } | 297 | } |
287 | ret = 1; | 298 | ret = 1; |
288 | out: | 299 | out: |
300 | spin_unlock(&dentry->d_lock); | ||
289 | spin_unlock(&dcache_lock); | 301 | spin_unlock(&dcache_lock); |
290 | return ret; | 302 | return ret; |
291 | } | 303 | } |
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index bbbf7922f422..102278ed38bd 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c | |||
@@ -392,6 +392,7 @@ ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos) | |||
392 | 392 | ||
393 | /* If a pointer is invalid, we search the dentry. */ | 393 | /* If a pointer is invalid, we search the dentry. */ |
394 | spin_lock(&dcache_lock); | 394 | spin_lock(&dcache_lock); |
395 | spin_lock(&parent->d_lock); | ||
395 | next = parent->d_subdirs.next; | 396 | next = parent->d_subdirs.next; |
396 | while (next != &parent->d_subdirs) { | 397 | while (next != &parent->d_subdirs) { |
397 | dent = list_entry(next, struct dentry, d_u.d_child); | 398 | dent = list_entry(next, struct dentry, d_u.d_child); |
@@ -400,11 +401,13 @@ ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos) | |||
400 | dget_locked(dent); | 401 | dget_locked(dent); |
401 | else | 402 | else |
402 | dent = NULL; | 403 | dent = NULL; |
404 | spin_unlock(&parent->d_lock); | ||
403 | spin_unlock(&dcache_lock); | 405 | spin_unlock(&dcache_lock); |
404 | goto out; | 406 | goto out; |
405 | } | 407 | } |
406 | next = next->next; | 408 | next = next->next; |
407 | } | 409 | } |
410 | spin_unlock(&parent->d_lock); | ||
408 | spin_unlock(&dcache_lock); | 411 | spin_unlock(&dcache_lock); |
409 | return NULL; | 412 | return NULL; |
410 | 413 | ||
diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h index 244d1b73fda7..c4b718ff9a6b 100644 --- a/fs/ncpfs/ncplib_kernel.h +++ b/fs/ncpfs/ncplib_kernel.h | |||
@@ -194,6 +194,7 @@ ncp_renew_dentries(struct dentry *parent) | |||
194 | struct dentry *dentry; | 194 | struct dentry *dentry; |
195 | 195 | ||
196 | spin_lock(&dcache_lock); | 196 | spin_lock(&dcache_lock); |
197 | spin_lock(&parent->d_lock); | ||
197 | next = parent->d_subdirs.next; | 198 | next = parent->d_subdirs.next; |
198 | while (next != &parent->d_subdirs) { | 199 | while (next != &parent->d_subdirs) { |
199 | dentry = list_entry(next, struct dentry, d_u.d_child); | 200 | dentry = list_entry(next, struct dentry, d_u.d_child); |
@@ -205,6 +206,7 @@ ncp_renew_dentries(struct dentry *parent) | |||
205 | 206 | ||
206 | next = next->next; | 207 | next = next->next; |
207 | } | 208 | } |
209 | spin_unlock(&parent->d_lock); | ||
208 | spin_unlock(&dcache_lock); | 210 | spin_unlock(&dcache_lock); |
209 | } | 211 | } |
210 | 212 | ||
@@ -216,6 +218,7 @@ ncp_invalidate_dircache_entries(struct dentry *parent) | |||
216 | struct dentry *dentry; | 218 | struct dentry *dentry; |
217 | 219 | ||
218 | spin_lock(&dcache_lock); | 220 | spin_lock(&dcache_lock); |
221 | spin_lock(&parent->d_lock); | ||
219 | next = parent->d_subdirs.next; | 222 | next = parent->d_subdirs.next; |
220 | while (next != &parent->d_subdirs) { | 223 | while (next != &parent->d_subdirs) { |
221 | dentry = list_entry(next, struct dentry, d_u.d_child); | 224 | dentry = list_entry(next, struct dentry, d_u.d_child); |
@@ -223,6 +226,7 @@ ncp_invalidate_dircache_entries(struct dentry *parent) | |||
223 | ncp_age_dentry(server, dentry); | 226 | ncp_age_dentry(server, dentry); |
224 | next = next->next; | 227 | next = next->next; |
225 | } | 228 | } |
229 | spin_unlock(&parent->d_lock); | ||
226 | spin_unlock(&dcache_lock); | 230 | spin_unlock(&dcache_lock); |
227 | } | 231 | } |
228 | 232 | ||
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 20dc218707ca..aa4f25e803f6 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c | |||
@@ -68,17 +68,19 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode) | |||
68 | /* run all of the children of the original inode and fix their | 68 | /* run all of the children of the original inode and fix their |
69 | * d_flags to indicate parental interest (their parent is the | 69 | * d_flags to indicate parental interest (their parent is the |
70 | * original inode) */ | 70 | * original inode) */ |
71 | spin_lock(&alias->d_lock); | ||
71 | list_for_each_entry(child, &alias->d_subdirs, d_u.d_child) { | 72 | list_for_each_entry(child, &alias->d_subdirs, d_u.d_child) { |
72 | if (!child->d_inode) | 73 | if (!child->d_inode) |
73 | continue; | 74 | continue; |
74 | 75 | ||
75 | spin_lock(&child->d_lock); | 76 | spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED); |
76 | if (watched) | 77 | if (watched) |
77 | child->d_flags |= DCACHE_FSNOTIFY_PARENT_WATCHED; | 78 | child->d_flags |= DCACHE_FSNOTIFY_PARENT_WATCHED; |
78 | else | 79 | else |
79 | child->d_flags &= ~DCACHE_FSNOTIFY_PARENT_WATCHED; | 80 | child->d_flags &= ~DCACHE_FSNOTIFY_PARENT_WATCHED; |
80 | spin_unlock(&child->d_lock); | 81 | spin_unlock(&child->d_lock); |
81 | } | 82 | } |
83 | spin_unlock(&alias->d_lock); | ||
82 | } | 84 | } |
83 | spin_unlock(&dcache_lock); | 85 | spin_unlock(&dcache_lock); |
84 | } | 86 | } |
diff --git a/include/linux/dcache.h b/include/linux/dcache.h index b0ade2d46805..ddf4f55624f7 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h | |||
@@ -305,6 +305,7 @@ static inline struct dentry *dget_dlock(struct dentry *dentry) | |||
305 | } | 305 | } |
306 | return dentry; | 306 | return dentry; |
307 | } | 307 | } |
308 | |||
308 | static inline struct dentry *dget(struct dentry *dentry) | 309 | static inline struct dentry *dget(struct dentry *dentry) |
309 | { | 310 | { |
310 | if (dentry) { | 311 | if (dentry) { |
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index eb7af39350c6..7b4705b51d4a 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -877,23 +877,31 @@ static void cgroup_clear_directory(struct dentry *dentry) | |||
877 | 877 | ||
878 | BUG_ON(!mutex_is_locked(&dentry->d_inode->i_mutex)); | 878 | BUG_ON(!mutex_is_locked(&dentry->d_inode->i_mutex)); |
879 | spin_lock(&dcache_lock); | 879 | spin_lock(&dcache_lock); |
880 | spin_lock(&dentry->d_lock); | ||
880 | node = dentry->d_subdirs.next; | 881 | node = dentry->d_subdirs.next; |
881 | while (node != &dentry->d_subdirs) { | 882 | while (node != &dentry->d_subdirs) { |
882 | struct dentry *d = list_entry(node, struct dentry, d_u.d_child); | 883 | struct dentry *d = list_entry(node, struct dentry, d_u.d_child); |
884 | |||
885 | spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED); | ||
883 | list_del_init(node); | 886 | list_del_init(node); |
884 | if (d->d_inode) { | 887 | if (d->d_inode) { |
885 | /* This should never be called on a cgroup | 888 | /* This should never be called on a cgroup |
886 | * directory with child cgroups */ | 889 | * directory with child cgroups */ |
887 | BUG_ON(d->d_inode->i_mode & S_IFDIR); | 890 | BUG_ON(d->d_inode->i_mode & S_IFDIR); |
888 | d = dget_locked(d); | 891 | dget_locked_dlock(d); |
892 | spin_unlock(&d->d_lock); | ||
893 | spin_unlock(&dentry->d_lock); | ||
889 | spin_unlock(&dcache_lock); | 894 | spin_unlock(&dcache_lock); |
890 | d_delete(d); | 895 | d_delete(d); |
891 | simple_unlink(dentry->d_inode, d); | 896 | simple_unlink(dentry->d_inode, d); |
892 | dput(d); | 897 | dput(d); |
893 | spin_lock(&dcache_lock); | 898 | spin_lock(&dcache_lock); |
894 | } | 899 | spin_lock(&dentry->d_lock); |
900 | } else | ||
901 | spin_unlock(&d->d_lock); | ||
895 | node = dentry->d_subdirs.next; | 902 | node = dentry->d_subdirs.next; |
896 | } | 903 | } |
904 | spin_unlock(&dentry->d_lock); | ||
897 | spin_unlock(&dcache_lock); | 905 | spin_unlock(&dcache_lock); |
898 | } | 906 | } |
899 | 907 | ||
@@ -902,10 +910,17 @@ static void cgroup_clear_directory(struct dentry *dentry) | |||
902 | */ | 910 | */ |
903 | static void cgroup_d_remove_dir(struct dentry *dentry) | 911 | static void cgroup_d_remove_dir(struct dentry *dentry) |
904 | { | 912 | { |
913 | struct dentry *parent; | ||
914 | |||
905 | cgroup_clear_directory(dentry); | 915 | cgroup_clear_directory(dentry); |
906 | 916 | ||
907 | spin_lock(&dcache_lock); | 917 | spin_lock(&dcache_lock); |
918 | parent = dentry->d_parent; | ||
919 | spin_lock(&parent->d_lock); | ||
920 | spin_lock(&dentry->d_lock); | ||
908 | list_del_init(&dentry->d_u.d_child); | 921 | list_del_init(&dentry->d_u.d_child); |
922 | spin_unlock(&dentry->d_lock); | ||
923 | spin_unlock(&parent->d_lock); | ||
909 | spin_unlock(&dcache_lock); | 924 | spin_unlock(&dcache_lock); |
910 | remove_dir(dentry); | 925 | remove_dir(dentry); |
911 | } | 926 | } |
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 073fd5b0a53a..017ec096446e 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
@@ -1146,22 +1146,30 @@ static void sel_remove_entries(struct dentry *de) | |||
1146 | struct list_head *node; | 1146 | struct list_head *node; |
1147 | 1147 | ||
1148 | spin_lock(&dcache_lock); | 1148 | spin_lock(&dcache_lock); |
1149 | spin_lock(&de->d_lock); | ||
1149 | node = de->d_subdirs.next; | 1150 | node = de->d_subdirs.next; |
1150 | while (node != &de->d_subdirs) { | 1151 | while (node != &de->d_subdirs) { |
1151 | struct dentry *d = list_entry(node, struct dentry, d_u.d_child); | 1152 | struct dentry *d = list_entry(node, struct dentry, d_u.d_child); |
1153 | |||
1154 | spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED); | ||
1152 | list_del_init(node); | 1155 | list_del_init(node); |
1153 | 1156 | ||
1154 | if (d->d_inode) { | 1157 | if (d->d_inode) { |
1155 | d = dget_locked(d); | 1158 | dget_locked_dlock(d); |
1159 | spin_unlock(&de->d_lock); | ||
1160 | spin_unlock(&d->d_lock); | ||
1156 | spin_unlock(&dcache_lock); | 1161 | spin_unlock(&dcache_lock); |
1157 | d_delete(d); | 1162 | d_delete(d); |
1158 | simple_unlink(de->d_inode, d); | 1163 | simple_unlink(de->d_inode, d); |
1159 | dput(d); | 1164 | dput(d); |
1160 | spin_lock(&dcache_lock); | 1165 | spin_lock(&dcache_lock); |
1161 | } | 1166 | spin_lock(&de->d_lock); |
1167 | } else | ||
1168 | spin_unlock(&d->d_lock); | ||
1162 | node = de->d_subdirs.next; | 1169 | node = de->d_subdirs.next; |
1163 | } | 1170 | } |
1164 | 1171 | ||
1172 | spin_unlock(&de->d_lock); | ||
1165 | spin_unlock(&dcache_lock); | 1173 | spin_unlock(&dcache_lock); |
1166 | } | 1174 | } |
1167 | 1175 | ||