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, 16 insertions, 5 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index 7c38f39958bc..8945e6cabd93 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -647,11 +647,16 @@ again:
647 spin_unlock(&parent->d_lock); 647 spin_unlock(&parent->d_lock);
648 goto again; 648 goto again;
649 } 649 }
650 rcu_read_unlock(); 650 if (parent != dentry) {
651 if (parent != dentry)
652 spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); 651 spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
653 else 652 if (unlikely(dentry->d_lockref.count < 0)) {
653 spin_unlock(&parent->d_lock);
654 parent = NULL;
655 }
656 } else {
654 parent = NULL; 657 parent = NULL;
658 }
659 rcu_read_unlock();
655 return parent; 660 return parent;
656} 661}
657 662
@@ -2474,7 +2479,7 @@ struct dentry *d_alloc_parallel(struct dentry *parent,
2474 2479
2475retry: 2480retry:
2476 rcu_read_lock(); 2481 rcu_read_lock();
2477 seq = smp_load_acquire(&parent->d_inode->i_dir_seq) & ~1; 2482 seq = smp_load_acquire(&parent->d_inode->i_dir_seq);
2478 r_seq = read_seqbegin(&rename_lock); 2483 r_seq = read_seqbegin(&rename_lock);
2479 dentry = __d_lookup_rcu(parent, name, &d_seq); 2484 dentry = __d_lookup_rcu(parent, name, &d_seq);
2480 if (unlikely(dentry)) { 2485 if (unlikely(dentry)) {
@@ -2495,8 +2500,14 @@ retry:
2495 rcu_read_unlock(); 2500 rcu_read_unlock();
2496 goto retry; 2501 goto retry;
2497 } 2502 }
2503
2504 if (unlikely(seq & 1)) {
2505 rcu_read_unlock();
2506 goto retry;
2507 }
2508
2498 hlist_bl_lock(b); 2509 hlist_bl_lock(b);
2499 if (unlikely(parent->d_inode->i_dir_seq != seq)) { 2510 if (unlikely(READ_ONCE(parent->d_inode->i_dir_seq) != seq)) {
2500 hlist_bl_unlock(b); 2511 hlist_bl_unlock(b);
2501 rcu_read_unlock(); 2512 rcu_read_unlock();
2502 goto retry; 2513 goto retry;