diff options
| author | Dave Airlie <airlied@redhat.com> | 2018-03-28 14:30:41 +1000 |
|---|---|---|
| committer | Dave Airlie <airlied@redhat.com> | 2018-03-28 14:30:41 +1000 |
| commit | 2b4f44eec2be2688511c2b617d0e1b4f94c45ba4 (patch) | |
| tree | 533c03602f4ae6d6404db6fa56c88e6f83e1bebe /fs/dcache.c | |
| parent | 33d009cd889490838c5db9b9339856c9e3d3facc (diff) | |
| parent | 3eb2ce825ea1ad89d20f7a3b5780df850e4be274 (diff) | |
Backmerge tag 'v4.16-rc7' into drm-next
Linux 4.16-rc7
This was requested by Daniel, and things were getting
a bit hard to reconcile, most of the conflicts were
trivial though.
Diffstat (limited to 'fs/dcache.c')
| -rw-r--r-- | fs/dcache.c | 21 |
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: spin_unlock(&parent->d_lock); goto again; } - rcu_read_unlock(); - if (parent != dentry) + if (parent != dentry) { spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); - else + if (unlikely(dentry->d_lockref.count < 0)) { + spin_unlock(&parent->d_lock); + parent = NULL; + } + } else { parent = NULL; + } + rcu_read_unlock(); return parent; } @@ -2474,7 +2479,7 @@ struct dentry *d_alloc_parallel(struct dentry *parent, retry: rcu_read_lock(); - seq = smp_load_acquire(&parent->d_inode->i_dir_seq) & ~1; + seq = smp_load_acquire(&parent->d_inode->i_dir_seq); r_seq = read_seqbegin(&rename_lock); dentry = __d_lookup_rcu(parent, name, &d_seq); if (unlikely(dentry)) { @@ -2495,8 +2500,14 @@ retry: rcu_read_unlock(); goto retry; } + + if (unlikely(seq & 1)) { + rcu_read_unlock(); + goto retry; + } + hlist_bl_lock(b); - if (unlikely(parent->d_inode->i_dir_seq != seq)) { + if (unlikely(READ_ONCE(parent->d_inode->i_dir_seq) != seq)) { hlist_bl_unlock(b); rcu_read_unlock(); goto retry; |
