aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dcache.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/dcache.c')
-rw-r--r--fs/dcache.c21
1 files changed, 12 insertions, 9 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index b4d2e28eef5b..a8f89765d602 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -446,24 +446,27 @@ struct dentry *dget_parent(struct dentry *dentry)
446 struct dentry *ret; 446 struct dentry *ret;
447 447
448repeat: 448repeat:
449 spin_lock(&dentry->d_lock); 449 /*
450 * Don't need rcu_dereference because we re-check it was correct under
451 * the lock.
452 */
453 rcu_read_lock();
450 ret = dentry->d_parent; 454 ret = dentry->d_parent;
451 if (!ret) 455 if (!ret) {
452 goto out; 456 rcu_read_unlock();
453 if (dentry == ret) {
454 ret->d_count++;
455 goto out; 457 goto out;
456 } 458 }
457 if (!spin_trylock(&ret->d_lock)) { 459 spin_lock(&ret->d_lock);
458 spin_unlock(&dentry->d_lock); 460 if (unlikely(ret != dentry->d_parent)) {
459 cpu_relax(); 461 spin_unlock(&ret->d_lock);
462 rcu_read_unlock();
460 goto repeat; 463 goto repeat;
461 } 464 }
465 rcu_read_unlock();
462 BUG_ON(!ret->d_count); 466 BUG_ON(!ret->d_count);
463 ret->d_count++; 467 ret->d_count++;
464 spin_unlock(&ret->d_lock); 468 spin_unlock(&ret->d_lock);
465out: 469out:
466 spin_unlock(&dentry->d_lock);
467 return ret; 470 return ret;
468} 471}
469EXPORT_SYMBOL(dget_parent); 472EXPORT_SYMBOL(dget_parent);