There is a soft hang caused by a deadlock in d_alloc_parallel which waits up on lookups to finish for the dentries in the parent directory's hash_table. In case when d_add_ci is called from the fs layer's lookup functions, the dentry being looked up is already in the hash table (created before the fs lookup function gets called). We should not be processing the same dentry that is being looked up, hence, in case of case-insensitive filesystems we are making it a case-exact match to prevent this from happening. Signed-off-by: Shreeya Patel <shreeya.patel@xxxxxxxxxxxxx> --- fs/dcache.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index cf871a81f4fd..2a28ab64a165 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -2565,6 +2565,15 @@ static void d_wait_lookup(struct dentry *dentry) } } +static inline bool d_same_exact_name(const struct dentry *dentry, + const struct dentry *parent, + const struct qstr *name) +{ + if (dentry->d_name.len != name->len) + return false; + return dentry_cmp(dentry, name->name, name->len) == 0; +} + struct dentry *d_alloc_parallel(struct dentry *parent, const struct qstr *name, wait_queue_head_t *wq) @@ -2575,6 +2584,7 @@ struct dentry *d_alloc_parallel(struct dentry *parent, struct dentry *new = d_alloc(parent, name); struct dentry *dentry; unsigned seq, r_seq, d_seq; + int ci_dir = IS_CASEFOLDED(parent->d_inode); if (unlikely(!new)) return ERR_PTR(-ENOMEM); @@ -2626,8 +2636,14 @@ struct dentry *d_alloc_parallel(struct dentry *parent, continue; if (dentry->d_parent != parent) continue; - if (!d_same_name(dentry, parent, name)) - continue; + if (ci_dir) { + if (!d_same_exact_name(dentry, parent, name)) + continue; + } else { + if (!d_same_name(dentry, parent, name)) + continue; + } + hlist_bl_unlock(b); /* now we can try to grab a reference */ if (!lockref_get_not_dead(&dentry->d_lockref)) { -- 2.30.2