diff options
author | Nick Piggin <npiggin@kernel.dk> | 2011-01-07 01:49:32 -0500 |
---|---|---|
committer | Nick Piggin <npiggin@kernel.dk> | 2011-01-07 01:50:21 -0500 |
commit | b7ab39f631f505edc2bbdb86620d5493f995c9da (patch) | |
tree | 62be97ebc7fc69ceb601f23312d335ebb8038ee7 | |
parent | 2304450783dfde7b0b94ae234edd0dbffa865073 (diff) |
fs: dcache scale dentry refcount
Make d_count non-atomic and protect it with d_lock. This allows us to ensure a
0 refcount dentry remains 0 without dcache_lock. It is also fairly natural when
we start protecting many other dentry members with d_lock.
Signed-off-by: Nick Piggin <npiggin@kernel.dk>
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/inode.c | 2 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_fs.c | 2 | ||||
-rw-r--r-- | drivers/infiniband/hw/qib/qib_fs.c | 2 | ||||
-rw-r--r-- | fs/autofs4/expire.c | 8 | ||||
-rw-r--r-- | fs/autofs4/root.c | 6 | ||||
-rw-r--r-- | fs/ceph/dir.c | 4 | ||||
-rw-r--r-- | fs/ceph/inode.c | 4 | ||||
-rw-r--r-- | fs/ceph/mds_client.c | 2 | ||||
-rw-r--r-- | fs/coda/dir.c | 2 | ||||
-rw-r--r-- | fs/configfs/dir.c | 3 | ||||
-rw-r--r-- | fs/configfs/inode.c | 2 | ||||
-rw-r--r-- | fs/dcache.c | 106 | ||||
-rw-r--r-- | fs/ecryptfs/inode.c | 2 | ||||
-rw-r--r-- | fs/locks.c | 2 | ||||
-rw-r--r-- | fs/namei.c | 2 | ||||
-rw-r--r-- | fs/nfs/dir.c | 6 | ||||
-rw-r--r-- | fs/nfs/unlink.c | 2 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 5 | ||||
-rw-r--r-- | fs/nilfs2/super.c | 2 | ||||
-rw-r--r-- | include/linux/dcache.h | 29 | ||||
-rw-r--r-- | kernel/cgroup.c | 2 |
21 files changed, 126 insertions, 69 deletions
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 3532b92de98..29a406a7754 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c | |||
@@ -162,7 +162,7 @@ static void spufs_prune_dir(struct dentry *dir) | |||
162 | spin_lock(&dcache_lock); | 162 | spin_lock(&dcache_lock); |
163 | spin_lock(&dentry->d_lock); | 163 | spin_lock(&dentry->d_lock); |
164 | if (!(d_unhashed(dentry)) && dentry->d_inode) { | 164 | if (!(d_unhashed(dentry)) && dentry->d_inode) { |
165 | dget_locked(dentry); | 165 | dget_locked_dlock(dentry); |
166 | __d_drop(dentry); | 166 | __d_drop(dentry); |
167 | spin_unlock(&dentry->d_lock); | 167 | spin_unlock(&dentry->d_lock); |
168 | simple_unlink(dir->d_inode, dentry); | 168 | simple_unlink(dir->d_inode, dentry); |
diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c index 8c8afc716b9..18aee04a841 100644 --- a/drivers/infiniband/hw/ipath/ipath_fs.c +++ b/drivers/infiniband/hw/ipath/ipath_fs.c | |||
@@ -280,7 +280,7 @@ static int remove_file(struct dentry *parent, char *name) | |||
280 | spin_lock(&dcache_lock); | 280 | spin_lock(&dcache_lock); |
281 | spin_lock(&tmp->d_lock); | 281 | spin_lock(&tmp->d_lock); |
282 | if (!(d_unhashed(tmp) && tmp->d_inode)) { | 282 | if (!(d_unhashed(tmp) && tmp->d_inode)) { |
283 | dget_locked(tmp); | 283 | dget_locked_dlock(tmp); |
284 | __d_drop(tmp); | 284 | __d_drop(tmp); |
285 | spin_unlock(&tmp->d_lock); | 285 | spin_unlock(&tmp->d_lock); |
286 | spin_unlock(&dcache_lock); | 286 | spin_unlock(&dcache_lock); |
diff --git a/drivers/infiniband/hw/qib/qib_fs.c b/drivers/infiniband/hw/qib/qib_fs.c index f99bddc0171..fe4b242f009 100644 --- a/drivers/infiniband/hw/qib/qib_fs.c +++ b/drivers/infiniband/hw/qib/qib_fs.c | |||
@@ -456,7 +456,7 @@ static int remove_file(struct dentry *parent, char *name) | |||
456 | spin_lock(&dcache_lock); | 456 | spin_lock(&dcache_lock); |
457 | spin_lock(&tmp->d_lock); | 457 | spin_lock(&tmp->d_lock); |
458 | if (!(d_unhashed(tmp) && tmp->d_inode)) { | 458 | if (!(d_unhashed(tmp) && tmp->d_inode)) { |
459 | dget_locked(tmp); | 459 | dget_locked_dlock(tmp); |
460 | __d_drop(tmp); | 460 | __d_drop(tmp); |
461 | spin_unlock(&tmp->d_lock); | 461 | spin_unlock(&tmp->d_lock); |
462 | spin_unlock(&dcache_lock); | 462 | spin_unlock(&dcache_lock); |
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index a796c9417fb..413b5642e6c 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c | |||
@@ -198,7 +198,7 @@ static int autofs4_tree_busy(struct vfsmount *mnt, | |||
198 | else | 198 | else |
199 | ino_count++; | 199 | ino_count++; |
200 | 200 | ||
201 | if (atomic_read(&p->d_count) > ino_count) { | 201 | if (p->d_count > ino_count) { |
202 | top_ino->last_used = jiffies; | 202 | top_ino->last_used = jiffies; |
203 | dput(p); | 203 | dput(p); |
204 | return 1; | 204 | return 1; |
@@ -347,7 +347,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
347 | 347 | ||
348 | /* Path walk currently on this dentry? */ | 348 | /* Path walk currently on this dentry? */ |
349 | ino_count = atomic_read(&ino->count) + 2; | 349 | ino_count = atomic_read(&ino->count) + 2; |
350 | if (atomic_read(&dentry->d_count) > ino_count) | 350 | if (dentry->d_count > ino_count) |
351 | goto next; | 351 | goto next; |
352 | 352 | ||
353 | /* Can we umount this guy */ | 353 | /* Can we umount this guy */ |
@@ -369,7 +369,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
369 | if (!exp_leaves) { | 369 | if (!exp_leaves) { |
370 | /* Path walk currently on this dentry? */ | 370 | /* Path walk currently on this dentry? */ |
371 | ino_count = atomic_read(&ino->count) + 1; | 371 | ino_count = atomic_read(&ino->count) + 1; |
372 | if (atomic_read(&dentry->d_count) > ino_count) | 372 | if (dentry->d_count > ino_count) |
373 | goto next; | 373 | goto next; |
374 | 374 | ||
375 | if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) { | 375 | if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) { |
@@ -383,7 +383,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
383 | } else { | 383 | } else { |
384 | /* Path walk currently on this dentry? */ | 384 | /* Path walk currently on this dentry? */ |
385 | ino_count = atomic_read(&ino->count) + 1; | 385 | ino_count = atomic_read(&ino->count) + 1; |
386 | if (atomic_read(&dentry->d_count) > ino_count) | 386 | if (dentry->d_count > ino_count) |
387 | goto next; | 387 | goto next; |
388 | 388 | ||
389 | expired = autofs4_check_leaves(mnt, dentry, timeout, do_now); | 389 | expired = autofs4_check_leaves(mnt, dentry, timeout, do_now); |
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index d34896cfb19..7922509b5b2 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c | |||
@@ -436,7 +436,7 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry) | |||
436 | spin_lock(&active->d_lock); | 436 | spin_lock(&active->d_lock); |
437 | 437 | ||
438 | /* Already gone? */ | 438 | /* Already gone? */ |
439 | if (atomic_read(&active->d_count) == 0) | 439 | if (active->d_count == 0) |
440 | goto next; | 440 | goto next; |
441 | 441 | ||
442 | qstr = &active->d_name; | 442 | qstr = &active->d_name; |
@@ -452,7 +452,7 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry) | |||
452 | goto next; | 452 | goto next; |
453 | 453 | ||
454 | if (d_unhashed(active)) { | 454 | if (d_unhashed(active)) { |
455 | dget(active); | 455 | dget_dlock(active); |
456 | spin_unlock(&active->d_lock); | 456 | spin_unlock(&active->d_lock); |
457 | spin_unlock(&sbi->lookup_lock); | 457 | spin_unlock(&sbi->lookup_lock); |
458 | spin_unlock(&dcache_lock); | 458 | spin_unlock(&dcache_lock); |
@@ -507,7 +507,7 @@ static struct dentry *autofs4_lookup_expiring(struct dentry *dentry) | |||
507 | goto next; | 507 | goto next; |
508 | 508 | ||
509 | if (d_unhashed(expiring)) { | 509 | if (d_unhashed(expiring)) { |
510 | dget(expiring); | 510 | dget_dlock(expiring); |
511 | spin_unlock(&expiring->d_lock); | 511 | spin_unlock(&expiring->d_lock); |
512 | spin_unlock(&sbi->lookup_lock); | 512 | spin_unlock(&sbi->lookup_lock); |
513 | spin_unlock(&dcache_lock); | 513 | spin_unlock(&dcache_lock); |
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index d902948a90d..3ecf915a455 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c | |||
@@ -150,7 +150,9 @@ more: | |||
150 | di = ceph_dentry(dentry); | 150 | di = ceph_dentry(dentry); |
151 | } | 151 | } |
152 | 152 | ||
153 | atomic_inc(&dentry->d_count); | 153 | spin_lock(&dentry->d_lock); |
154 | dentry->d_count++; | ||
155 | spin_unlock(&dentry->d_lock); | ||
154 | spin_unlock(&dcache_lock); | 156 | spin_unlock(&dcache_lock); |
155 | 157 | ||
156 | dout(" %llu (%llu) dentry %p %.*s %p\n", di->offset, filp->f_pos, | 158 | dout(" %llu (%llu) dentry %p %.*s %p\n", di->offset, filp->f_pos, |
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index bf1286588f2..bb68c799074 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c | |||
@@ -879,8 +879,8 @@ static struct dentry *splice_dentry(struct dentry *dn, struct inode *in, | |||
879 | } else if (realdn) { | 879 | } else if (realdn) { |
880 | dout("dn %p (%d) spliced with %p (%d) " | 880 | dout("dn %p (%d) spliced with %p (%d) " |
881 | "inode %p ino %llx.%llx\n", | 881 | "inode %p ino %llx.%llx\n", |
882 | dn, atomic_read(&dn->d_count), | 882 | dn, dn->d_count, |
883 | realdn, atomic_read(&realdn->d_count), | 883 | realdn, realdn->d_count, |
884 | realdn->d_inode, ceph_vinop(realdn->d_inode)); | 884 | realdn->d_inode, ceph_vinop(realdn->d_inode)); |
885 | dput(dn); | 885 | dput(dn); |
886 | dn = realdn; | 886 | dn = realdn; |
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 38800eaa81d..a50fca1e03b 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c | |||
@@ -1486,7 +1486,7 @@ retry: | |||
1486 | *base = ceph_ino(temp->d_inode); | 1486 | *base = ceph_ino(temp->d_inode); |
1487 | *plen = len; | 1487 | *plen = len; |
1488 | dout("build_path on %p %d built %llx '%.*s'\n", | 1488 | dout("build_path on %p %d built %llx '%.*s'\n", |
1489 | dentry, atomic_read(&dentry->d_count), *base, len, path); | 1489 | dentry, dentry->d_count, *base, len, path); |
1490 | return path; | 1490 | return path; |
1491 | } | 1491 | } |
1492 | 1492 | ||
diff --git a/fs/coda/dir.c b/fs/coda/dir.c index 4cce3b07d9d..9e37e8bc9b8 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c | |||
@@ -559,7 +559,7 @@ static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd) | |||
559 | if (cii->c_flags & C_FLUSH) | 559 | if (cii->c_flags & C_FLUSH) |
560 | coda_flag_inode_children(inode, C_FLUSH); | 560 | coda_flag_inode_children(inode, C_FLUSH); |
561 | 561 | ||
562 | if (atomic_read(&de->d_count) > 1) | 562 | if (de->d_count > 1) |
563 | /* pretend it's valid, but don't change the flags */ | 563 | /* pretend it's valid, but don't change the flags */ |
564 | goto out; | 564 | goto out; |
565 | 565 | ||
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index 20024a9ef5a..e9acea440ff 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c | |||
@@ -394,8 +394,7 @@ static void remove_dir(struct dentry * d) | |||
394 | if (d->d_inode) | 394 | if (d->d_inode) |
395 | simple_rmdir(parent->d_inode,d); | 395 | simple_rmdir(parent->d_inode,d); |
396 | 396 | ||
397 | pr_debug(" o %s removing done (%d)\n",d->d_name.name, | 397 | pr_debug(" o %s removing done (%d)\n",d->d_name.name, d->d_count); |
398 | atomic_read(&d->d_count)); | ||
399 | 398 | ||
400 | dput(parent); | 399 | dput(parent); |
401 | } | 400 | } |
diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c index 253476d78ed..79b37765d8f 100644 --- a/fs/configfs/inode.c +++ b/fs/configfs/inode.c | |||
@@ -253,7 +253,7 @@ void configfs_drop_dentry(struct configfs_dirent * sd, struct dentry * parent) | |||
253 | spin_lock(&dcache_lock); | 253 | spin_lock(&dcache_lock); |
254 | spin_lock(&dentry->d_lock); | 254 | spin_lock(&dentry->d_lock); |
255 | if (!(d_unhashed(dentry) && dentry->d_inode)) { | 255 | if (!(d_unhashed(dentry) && dentry->d_inode)) { |
256 | dget_locked(dentry); | 256 | dget_locked_dlock(dentry); |
257 | __d_drop(dentry); | 257 | __d_drop(dentry); |
258 | spin_unlock(&dentry->d_lock); | 258 | spin_unlock(&dentry->d_lock); |
259 | spin_unlock(&dcache_lock); | 259 | spin_unlock(&dcache_lock); |
diff --git a/fs/dcache.c b/fs/dcache.c index 3d3c843c36e..81e91502b29 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -45,6 +45,7 @@ | |||
45 | * - d_flags | 45 | * - d_flags |
46 | * - d_name | 46 | * - d_name |
47 | * - d_lru | 47 | * - d_lru |
48 | * - d_count | ||
48 | * | 49 | * |
49 | * Ordering: | 50 | * Ordering: |
50 | * dcache_lock | 51 | * dcache_lock |
@@ -125,6 +126,7 @@ static void __d_free(struct rcu_head *head) | |||
125 | */ | 126 | */ |
126 | static void d_free(struct dentry *dentry) | 127 | static void d_free(struct dentry *dentry) |
127 | { | 128 | { |
129 | BUG_ON(dentry->d_count); | ||
128 | this_cpu_dec(nr_dentry); | 130 | this_cpu_dec(nr_dentry); |
129 | if (dentry->d_op && dentry->d_op->d_release) | 131 | if (dentry->d_op && dentry->d_op->d_release) |
130 | dentry->d_op->d_release(dentry); | 132 | dentry->d_op->d_release(dentry); |
@@ -222,8 +224,11 @@ static struct dentry *d_kill(struct dentry *dentry) | |||
222 | struct dentry *parent; | 224 | struct dentry *parent; |
223 | 225 | ||
224 | list_del(&dentry->d_u.d_child); | 226 | list_del(&dentry->d_u.d_child); |
225 | /*drops the locks, at that point nobody can reach this dentry */ | ||
226 | dentry_iput(dentry); | 227 | dentry_iput(dentry); |
228 | /* | ||
229 | * dentry_iput drops the locks, at which point nobody (except | ||
230 | * transient RCU lookups) can reach this dentry. | ||
231 | */ | ||
227 | if (IS_ROOT(dentry)) | 232 | if (IS_ROOT(dentry)) |
228 | parent = NULL; | 233 | parent = NULL; |
229 | else | 234 | else |
@@ -303,13 +308,23 @@ void dput(struct dentry *dentry) | |||
303 | return; | 308 | return; |
304 | 309 | ||
305 | repeat: | 310 | repeat: |
306 | if (atomic_read(&dentry->d_count) == 1) | 311 | if (dentry->d_count == 1) |
307 | might_sleep(); | 312 | might_sleep(); |
308 | if (!atomic_dec_and_lock(&dentry->d_count, &dcache_lock)) | ||
309 | return; | ||
310 | |||
311 | spin_lock(&dentry->d_lock); | 313 | spin_lock(&dentry->d_lock); |
312 | if (atomic_read(&dentry->d_count)) { | 314 | if (dentry->d_count == 1) { |
315 | if (!spin_trylock(&dcache_lock)) { | ||
316 | /* | ||
317 | * Something of a livelock possibility we could avoid | ||
318 | * by taking dcache_lock and trying again, but we | ||
319 | * want to reduce dcache_lock anyway so this will | ||
320 | * get improved. | ||
321 | */ | ||
322 | spin_unlock(&dentry->d_lock); | ||
323 | goto repeat; | ||
324 | } | ||
325 | } | ||
326 | dentry->d_count--; | ||
327 | if (dentry->d_count) { | ||
313 | spin_unlock(&dentry->d_lock); | 328 | spin_unlock(&dentry->d_lock); |
314 | spin_unlock(&dcache_lock); | 329 | spin_unlock(&dcache_lock); |
315 | return; | 330 | return; |
@@ -389,7 +404,7 @@ int d_invalidate(struct dentry * dentry) | |||
389 | * working directory or similar). | 404 | * working directory or similar). |
390 | */ | 405 | */ |
391 | spin_lock(&dentry->d_lock); | 406 | spin_lock(&dentry->d_lock); |
392 | if (atomic_read(&dentry->d_count) > 1) { | 407 | if (dentry->d_count > 1) { |
393 | if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) { | 408 | if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) { |
394 | spin_unlock(&dentry->d_lock); | 409 | spin_unlock(&dentry->d_lock); |
395 | spin_unlock(&dcache_lock); | 410 | spin_unlock(&dcache_lock); |
@@ -404,29 +419,61 @@ int d_invalidate(struct dentry * dentry) | |||
404 | } | 419 | } |
405 | EXPORT_SYMBOL(d_invalidate); | 420 | EXPORT_SYMBOL(d_invalidate); |
406 | 421 | ||
407 | /* This should be called _only_ with dcache_lock held */ | 422 | /* This must be called with dcache_lock and d_lock held */ |
408 | static inline struct dentry * __dget_locked_dlock(struct dentry *dentry) | 423 | static inline struct dentry * __dget_locked_dlock(struct dentry *dentry) |
409 | { | 424 | { |
410 | atomic_inc(&dentry->d_count); | 425 | dentry->d_count++; |
411 | dentry_lru_del(dentry); | 426 | dentry_lru_del(dentry); |
412 | return dentry; | 427 | return dentry; |
413 | } | 428 | } |
414 | 429 | ||
430 | /* This should be called _only_ with dcache_lock held */ | ||
415 | static inline struct dentry * __dget_locked(struct dentry *dentry) | 431 | static inline struct dentry * __dget_locked(struct dentry *dentry) |
416 | { | 432 | { |
417 | atomic_inc(&dentry->d_count); | ||
418 | spin_lock(&dentry->d_lock); | 433 | spin_lock(&dentry->d_lock); |
419 | dentry_lru_del(dentry); | 434 | __dget_locked_dlock(dentry); |
420 | spin_unlock(&dentry->d_lock); | 435 | spin_unlock(&dentry->d_lock); |
421 | return dentry; | 436 | return dentry; |
422 | } | 437 | } |
423 | 438 | ||
439 | struct dentry * dget_locked_dlock(struct dentry *dentry) | ||
440 | { | ||
441 | return __dget_locked_dlock(dentry); | ||
442 | } | ||
443 | |||
424 | struct dentry * dget_locked(struct dentry *dentry) | 444 | struct dentry * dget_locked(struct dentry *dentry) |
425 | { | 445 | { |
426 | return __dget_locked(dentry); | 446 | return __dget_locked(dentry); |
427 | } | 447 | } |
428 | EXPORT_SYMBOL(dget_locked); | 448 | EXPORT_SYMBOL(dget_locked); |
429 | 449 | ||
450 | struct dentry *dget_parent(struct dentry *dentry) | ||
451 | { | ||
452 | struct dentry *ret; | ||
453 | |||
454 | repeat: | ||
455 | spin_lock(&dentry->d_lock); | ||
456 | ret = dentry->d_parent; | ||
457 | if (!ret) | ||
458 | goto out; | ||
459 | if (dentry == ret) { | ||
460 | ret->d_count++; | ||
461 | goto out; | ||
462 | } | ||
463 | if (!spin_trylock(&ret->d_lock)) { | ||
464 | spin_unlock(&dentry->d_lock); | ||
465 | cpu_relax(); | ||
466 | goto repeat; | ||
467 | } | ||
468 | BUG_ON(!ret->d_count); | ||
469 | ret->d_count++; | ||
470 | spin_unlock(&ret->d_lock); | ||
471 | out: | ||
472 | spin_unlock(&dentry->d_lock); | ||
473 | return ret; | ||
474 | } | ||
475 | EXPORT_SYMBOL(dget_parent); | ||
476 | |||
430 | /** | 477 | /** |
431 | * d_find_alias - grab a hashed alias of inode | 478 | * d_find_alias - grab a hashed alias of inode |
432 | * @inode: inode in question | 479 | * @inode: inode in question |
@@ -495,7 +542,7 @@ restart: | |||
495 | spin_lock(&dcache_lock); | 542 | spin_lock(&dcache_lock); |
496 | list_for_each_entry(dentry, &inode->i_dentry, d_alias) { | 543 | list_for_each_entry(dentry, &inode->i_dentry, d_alias) { |
497 | spin_lock(&dentry->d_lock); | 544 | spin_lock(&dentry->d_lock); |
498 | if (!atomic_read(&dentry->d_count)) { | 545 | if (!dentry->d_count) { |
499 | __dget_locked_dlock(dentry); | 546 | __dget_locked_dlock(dentry); |
500 | __d_drop(dentry); | 547 | __d_drop(dentry); |
501 | spin_unlock(&dentry->d_lock); | 548 | spin_unlock(&dentry->d_lock); |
@@ -530,7 +577,10 @@ static void prune_one_dentry(struct dentry * dentry) | |||
530 | */ | 577 | */ |
531 | while (dentry) { | 578 | while (dentry) { |
532 | spin_lock(&dcache_lock); | 579 | spin_lock(&dcache_lock); |
533 | if (!atomic_dec_and_lock(&dentry->d_count, &dentry->d_lock)) { | 580 | spin_lock(&dentry->d_lock); |
581 | dentry->d_count--; | ||
582 | if (dentry->d_count) { | ||
583 | spin_unlock(&dentry->d_lock); | ||
534 | spin_unlock(&dcache_lock); | 584 | spin_unlock(&dcache_lock); |
535 | return; | 585 | return; |
536 | } | 586 | } |
@@ -562,7 +612,7 @@ static void shrink_dentry_list(struct list_head *list) | |||
562 | * the LRU because of laziness during lookup. Do not free | 612 | * the LRU because of laziness during lookup. Do not free |
563 | * it - just keep it off the LRU list. | 613 | * it - just keep it off the LRU list. |
564 | */ | 614 | */ |
565 | if (atomic_read(&dentry->d_count)) { | 615 | if (dentry->d_count) { |
566 | spin_unlock(&dentry->d_lock); | 616 | spin_unlock(&dentry->d_lock); |
567 | continue; | 617 | continue; |
568 | } | 618 | } |
@@ -783,7 +833,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) | |||
783 | do { | 833 | do { |
784 | struct inode *inode; | 834 | struct inode *inode; |
785 | 835 | ||
786 | if (atomic_read(&dentry->d_count) != 0) { | 836 | if (dentry->d_count != 0) { |
787 | printk(KERN_ERR | 837 | printk(KERN_ERR |
788 | "BUG: Dentry %p{i=%lx,n=%s}" | 838 | "BUG: Dentry %p{i=%lx,n=%s}" |
789 | " still in use (%d)" | 839 | " still in use (%d)" |
@@ -792,7 +842,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) | |||
792 | dentry->d_inode ? | 842 | dentry->d_inode ? |
793 | dentry->d_inode->i_ino : 0UL, | 843 | dentry->d_inode->i_ino : 0UL, |
794 | dentry->d_name.name, | 844 | dentry->d_name.name, |
795 | atomic_read(&dentry->d_count), | 845 | dentry->d_count, |
796 | dentry->d_sb->s_type->name, | 846 | dentry->d_sb->s_type->name, |
797 | dentry->d_sb->s_id); | 847 | dentry->d_sb->s_id); |
798 | BUG(); | 848 | BUG(); |
@@ -802,7 +852,9 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) | |||
802 | parent = NULL; | 852 | parent = NULL; |
803 | else { | 853 | else { |
804 | parent = dentry->d_parent; | 854 | parent = dentry->d_parent; |
805 | atomic_dec(&parent->d_count); | 855 | spin_lock(&parent->d_lock); |
856 | parent->d_count--; | ||
857 | spin_unlock(&parent->d_lock); | ||
806 | } | 858 | } |
807 | 859 | ||
808 | list_del(&dentry->d_u.d_child); | 860 | list_del(&dentry->d_u.d_child); |
@@ -853,7 +905,9 @@ void shrink_dcache_for_umount(struct super_block *sb) | |||
853 | 905 | ||
854 | dentry = sb->s_root; | 906 | dentry = sb->s_root; |
855 | sb->s_root = NULL; | 907 | sb->s_root = NULL; |
856 | atomic_dec(&dentry->d_count); | 908 | spin_lock(&dentry->d_lock); |
909 | dentry->d_count--; | ||
910 | spin_unlock(&dentry->d_lock); | ||
857 | shrink_dcache_for_umount_subtree(dentry); | 911 | shrink_dcache_for_umount_subtree(dentry); |
858 | 912 | ||
859 | while (!hlist_empty(&sb->s_anon)) { | 913 | while (!hlist_empty(&sb->s_anon)) { |
@@ -950,7 +1004,7 @@ resume: | |||
950 | * move only zero ref count dentries to the end | 1004 | * move only zero ref count dentries to the end |
951 | * of the unused list for prune_dcache | 1005 | * of the unused list for prune_dcache |
952 | */ | 1006 | */ |
953 | if (!atomic_read(&dentry->d_count)) { | 1007 | if (!dentry->d_count) { |
954 | dentry_lru_move_tail(dentry); | 1008 | dentry_lru_move_tail(dentry); |
955 | found++; | 1009 | found++; |
956 | } else { | 1010 | } else { |
@@ -1068,7 +1122,7 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) | |||
1068 | memcpy(dname, name->name, name->len); | 1122 | memcpy(dname, name->name, name->len); |
1069 | dname[name->len] = 0; | 1123 | dname[name->len] = 0; |
1070 | 1124 | ||
1071 | atomic_set(&dentry->d_count, 1); | 1125 | dentry->d_count = 1; |
1072 | dentry->d_flags = DCACHE_UNHASHED; | 1126 | dentry->d_flags = DCACHE_UNHASHED; |
1073 | spin_lock_init(&dentry->d_lock); | 1127 | spin_lock_init(&dentry->d_lock); |
1074 | dentry->d_inode = NULL; | 1128 | dentry->d_inode = NULL; |
@@ -1556,7 +1610,7 @@ struct dentry * __d_lookup(struct dentry * parent, struct qstr * name) | |||
1556 | goto next; | 1610 | goto next; |
1557 | } | 1611 | } |
1558 | 1612 | ||
1559 | atomic_inc(&dentry->d_count); | 1613 | dentry->d_count++; |
1560 | found = dentry; | 1614 | found = dentry; |
1561 | spin_unlock(&dentry->d_lock); | 1615 | spin_unlock(&dentry->d_lock); |
1562 | break; | 1616 | break; |
@@ -1653,7 +1707,7 @@ void d_delete(struct dentry * dentry) | |||
1653 | spin_lock(&dcache_lock); | 1707 | spin_lock(&dcache_lock); |
1654 | spin_lock(&dentry->d_lock); | 1708 | spin_lock(&dentry->d_lock); |
1655 | isdir = S_ISDIR(dentry->d_inode->i_mode); | 1709 | isdir = S_ISDIR(dentry->d_inode->i_mode); |
1656 | if (atomic_read(&dentry->d_count) == 1) { | 1710 | if (dentry->d_count == 1) { |
1657 | dentry->d_flags &= ~DCACHE_CANT_MOUNT; | 1711 | dentry->d_flags &= ~DCACHE_CANT_MOUNT; |
1658 | dentry_iput(dentry); | 1712 | dentry_iput(dentry); |
1659 | fsnotify_nameremove(dentry, isdir); | 1713 | fsnotify_nameremove(dentry, isdir); |
@@ -2494,11 +2548,15 @@ resume: | |||
2494 | this_parent = dentry; | 2548 | this_parent = dentry; |
2495 | goto repeat; | 2549 | goto repeat; |
2496 | } | 2550 | } |
2497 | atomic_dec(&dentry->d_count); | 2551 | spin_lock(&dentry->d_lock); |
2552 | dentry->d_count--; | ||
2553 | spin_unlock(&dentry->d_lock); | ||
2498 | } | 2554 | } |
2499 | if (this_parent != root) { | 2555 | if (this_parent != root) { |
2500 | next = this_parent->d_u.d_child.next; | 2556 | next = this_parent->d_u.d_child.next; |
2501 | atomic_dec(&this_parent->d_count); | 2557 | spin_lock(&this_parent->d_lock); |
2558 | this_parent->d_count--; | ||
2559 | spin_unlock(&this_parent->d_lock); | ||
2502 | this_parent = this_parent->d_parent; | 2560 | this_parent = this_parent->d_parent; |
2503 | goto resume; | 2561 | goto resume; |
2504 | } | 2562 | } |
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index a1ed7a7cb17..5e5c7ec1fc9 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c | |||
@@ -260,7 +260,7 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, | |||
260 | ecryptfs_dentry->d_parent)); | 260 | ecryptfs_dentry->d_parent)); |
261 | lower_inode = lower_dentry->d_inode; | 261 | lower_inode = lower_dentry->d_inode; |
262 | fsstack_copy_attr_atime(ecryptfs_dir_inode, lower_dir_dentry->d_inode); | 262 | fsstack_copy_attr_atime(ecryptfs_dir_inode, lower_dir_dentry->d_inode); |
263 | BUG_ON(!atomic_read(&lower_dentry->d_count)); | 263 | BUG_ON(!lower_dentry->d_count); |
264 | ecryptfs_set_dentry_private(ecryptfs_dentry, | 264 | ecryptfs_set_dentry_private(ecryptfs_dentry, |
265 | kmem_cache_alloc(ecryptfs_dentry_info_cache, | 265 | kmem_cache_alloc(ecryptfs_dentry_info_cache, |
266 | GFP_KERNEL)); | 266 | GFP_KERNEL)); |
diff --git a/fs/locks.c b/fs/locks.c index 8729347bcd1..08415b2a6d3 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -1389,7 +1389,7 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) | |||
1389 | if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) | 1389 | if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) |
1390 | goto out; | 1390 | goto out; |
1391 | if ((arg == F_WRLCK) | 1391 | if ((arg == F_WRLCK) |
1392 | && ((atomic_read(&dentry->d_count) > 1) | 1392 | && ((dentry->d_count > 1) |
1393 | || (atomic_read(&inode->i_count) > 1))) | 1393 | || (atomic_read(&inode->i_count) > 1))) |
1394 | goto out; | 1394 | goto out; |
1395 | } | 1395 | } |
diff --git a/fs/namei.c b/fs/namei.c index f3b5ca40465..cbfa5fb3107 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -2133,7 +2133,7 @@ void dentry_unhash(struct dentry *dentry) | |||
2133 | shrink_dcache_parent(dentry); | 2133 | shrink_dcache_parent(dentry); |
2134 | spin_lock(&dcache_lock); | 2134 | spin_lock(&dcache_lock); |
2135 | spin_lock(&dentry->d_lock); | 2135 | spin_lock(&dentry->d_lock); |
2136 | if (atomic_read(&dentry->d_count) == 2) | 2136 | if (dentry->d_count == 2) |
2137 | __d_drop(dentry); | 2137 | __d_drop(dentry); |
2138 | spin_unlock(&dentry->d_lock); | 2138 | spin_unlock(&dentry->d_lock); |
2139 | spin_unlock(&dcache_lock); | 2139 | spin_unlock(&dcache_lock); |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 9184c7c80f7..12de824edb5 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -1720,7 +1720,7 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry) | |||
1720 | 1720 | ||
1721 | spin_lock(&dcache_lock); | 1721 | spin_lock(&dcache_lock); |
1722 | spin_lock(&dentry->d_lock); | 1722 | spin_lock(&dentry->d_lock); |
1723 | if (atomic_read(&dentry->d_count) > 1) { | 1723 | if (dentry->d_count > 1) { |
1724 | spin_unlock(&dentry->d_lock); | 1724 | spin_unlock(&dentry->d_lock); |
1725 | spin_unlock(&dcache_lock); | 1725 | spin_unlock(&dcache_lock); |
1726 | /* Start asynchronous writeout of the inode */ | 1726 | /* Start asynchronous writeout of the inode */ |
@@ -1868,7 +1868,7 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1868 | dfprintk(VFS, "NFS: rename(%s/%s -> %s/%s, ct=%d)\n", | 1868 | dfprintk(VFS, "NFS: rename(%s/%s -> %s/%s, ct=%d)\n", |
1869 | old_dentry->d_parent->d_name.name, old_dentry->d_name.name, | 1869 | old_dentry->d_parent->d_name.name, old_dentry->d_name.name, |
1870 | new_dentry->d_parent->d_name.name, new_dentry->d_name.name, | 1870 | new_dentry->d_parent->d_name.name, new_dentry->d_name.name, |
1871 | atomic_read(&new_dentry->d_count)); | 1871 | new_dentry->d_count); |
1872 | 1872 | ||
1873 | /* | 1873 | /* |
1874 | * For non-directories, check whether the target is busy and if so, | 1874 | * For non-directories, check whether the target is busy and if so, |
@@ -1886,7 +1886,7 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1886 | rehash = new_dentry; | 1886 | rehash = new_dentry; |
1887 | } | 1887 | } |
1888 | 1888 | ||
1889 | if (atomic_read(&new_dentry->d_count) > 2) { | 1889 | if (new_dentry->d_count > 2) { |
1890 | int err; | 1890 | int err; |
1891 | 1891 | ||
1892 | /* copy the target dentry's name */ | 1892 | /* copy the target dentry's name */ |
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 7bdec853140..8fe9eb47a97 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c | |||
@@ -496,7 +496,7 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry) | |||
496 | 496 | ||
497 | dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n", | 497 | dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n", |
498 | dentry->d_parent->d_name.name, dentry->d_name.name, | 498 | dentry->d_parent->d_name.name, dentry->d_name.name, |
499 | atomic_read(&dentry->d_count)); | 499 | dentry->d_count); |
500 | nfs_inc_stats(dir, NFSIOS_SILLYRENAME); | 500 | nfs_inc_stats(dir, NFSIOS_SILLYRENAME); |
501 | 501 | ||
502 | /* | 502 | /* |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 184938fcff0..3a359023c9f 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -1756,8 +1756,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, | |||
1756 | goto out_dput_new; | 1756 | goto out_dput_new; |
1757 | 1757 | ||
1758 | if (svc_msnfs(ffhp) && | 1758 | if (svc_msnfs(ffhp) && |
1759 | ((atomic_read(&odentry->d_count) > 1) | 1759 | ((odentry->d_count > 1) || (ndentry->d_count > 1))) { |
1760 | || (atomic_read(&ndentry->d_count) > 1))) { | ||
1761 | host_err = -EPERM; | 1760 | host_err = -EPERM; |
1762 | goto out_dput_new; | 1761 | goto out_dput_new; |
1763 | } | 1762 | } |
@@ -1843,7 +1842,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
1843 | if (type != S_IFDIR) { /* It's UNLINK */ | 1842 | if (type != S_IFDIR) { /* It's UNLINK */ |
1844 | #ifdef MSNFS | 1843 | #ifdef MSNFS |
1845 | if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && | 1844 | if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && |
1846 | (atomic_read(&rdentry->d_count) > 1)) { | 1845 | (rdentry->d_count > 1)) { |
1847 | host_err = -EPERM; | 1846 | host_err = -EPERM; |
1848 | } else | 1847 | } else |
1849 | #endif | 1848 | #endif |
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index f804d41ec9d..d36fc7ee615 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c | |||
@@ -838,7 +838,7 @@ static int nilfs_attach_snapshot(struct super_block *s, __u64 cno, | |||
838 | 838 | ||
839 | static int nilfs_tree_was_touched(struct dentry *root_dentry) | 839 | static int nilfs_tree_was_touched(struct dentry *root_dentry) |
840 | { | 840 | { |
841 | return atomic_read(&root_dentry->d_count) > 1; | 841 | return root_dentry->d_count > 1; |
842 | } | 842 | } |
843 | 843 | ||
844 | /** | 844 | /** |
diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 2feb624b67f..b0ade2d4680 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h | |||
@@ -87,7 +87,7 @@ full_name_hash(const unsigned char *name, unsigned int len) | |||
87 | #endif | 87 | #endif |
88 | 88 | ||
89 | struct dentry { | 89 | struct dentry { |
90 | atomic_t d_count; | 90 | unsigned int d_count; /* protected by d_lock */ |
91 | unsigned int d_flags; /* protected by d_lock */ | 91 | unsigned int d_flags; /* protected by d_lock */ |
92 | spinlock_t d_lock; /* per dentry lock */ | 92 | spinlock_t d_lock; /* per dentry lock */ |
93 | int d_mounted; | 93 | int d_mounted; |
@@ -297,17 +297,28 @@ extern char *dentry_path(struct dentry *, char *, int); | |||
297 | * needs and they take necessary precautions) you should hold dcache_lock | 297 | * needs and they take necessary precautions) you should hold dcache_lock |
298 | * and call dget_locked() instead of dget(). | 298 | * and call dget_locked() instead of dget(). |
299 | */ | 299 | */ |
300 | 300 | static inline struct dentry *dget_dlock(struct dentry *dentry) | |
301 | { | ||
302 | if (dentry) { | ||
303 | BUG_ON(!dentry->d_count); | ||
304 | dentry->d_count++; | ||
305 | } | ||
306 | return dentry; | ||
307 | } | ||
301 | static inline struct dentry *dget(struct dentry *dentry) | 308 | static inline struct dentry *dget(struct dentry *dentry) |
302 | { | 309 | { |
303 | if (dentry) { | 310 | if (dentry) { |
304 | BUG_ON(!atomic_read(&dentry->d_count)); | 311 | spin_lock(&dentry->d_lock); |
305 | atomic_inc(&dentry->d_count); | 312 | dget_dlock(dentry); |
313 | spin_unlock(&dentry->d_lock); | ||
306 | } | 314 | } |
307 | return dentry; | 315 | return dentry; |
308 | } | 316 | } |
309 | 317 | ||
310 | extern struct dentry * dget_locked(struct dentry *); | 318 | extern struct dentry * dget_locked(struct dentry *); |
319 | extern struct dentry * dget_locked_dlock(struct dentry *); | ||
320 | |||
321 | extern struct dentry *dget_parent(struct dentry *dentry); | ||
311 | 322 | ||
312 | /** | 323 | /** |
313 | * d_unhashed - is dentry hashed | 324 | * d_unhashed - is dentry hashed |
@@ -338,16 +349,6 @@ static inline void dont_mount(struct dentry *dentry) | |||
338 | spin_unlock(&dentry->d_lock); | 349 | spin_unlock(&dentry->d_lock); |
339 | } | 350 | } |
340 | 351 | ||
341 | static inline struct dentry *dget_parent(struct dentry *dentry) | ||
342 | { | ||
343 | struct dentry *ret; | ||
344 | |||
345 | spin_lock(&dentry->d_lock); | ||
346 | ret = dget(dentry->d_parent); | ||
347 | spin_unlock(&dentry->d_lock); | ||
348 | return ret; | ||
349 | } | ||
350 | |||
351 | extern void dput(struct dentry *); | 352 | extern void dput(struct dentry *); |
352 | 353 | ||
353 | static inline int d_mountpoint(struct dentry *dentry) | 354 | static inline int d_mountpoint(struct dentry *dentry) |
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 746055b214d..eb7af39350c 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -3655,9 +3655,7 @@ again: | |||
3655 | list_del(&cgrp->sibling); | 3655 | list_del(&cgrp->sibling); |
3656 | cgroup_unlock_hierarchy(cgrp->root); | 3656 | cgroup_unlock_hierarchy(cgrp->root); |
3657 | 3657 | ||
3658 | spin_lock(&cgrp->dentry->d_lock); | ||
3659 | d = dget(cgrp->dentry); | 3658 | d = dget(cgrp->dentry); |
3660 | spin_unlock(&d->d_lock); | ||
3661 | 3659 | ||
3662 | cgroup_d_remove_dir(d); | 3660 | cgroup_d_remove_dir(d); |
3663 | dput(d); | 3661 | dput(d); |