From 1f0b2a0dca6a3296791584770bb0062d1b969c51 Mon Sep 17 00:00:00 2001 From: Lai Siyao Date: Tue, 4 Aug 2020 02:21:58 +0800 Subject: [PATCH] LU-13909 llite: prune invalid dentries When file LOOKUP lock is canceled on client, mark its dentries invalid, and also prune them to avoid OOM, to achieve this, ll_invalidate_aliases() is renamed to ll_prune_aliases(), the latter calls d_prune_aliases() to prune unused invalid dentries. The same for negative dentries when parent UPDATE lock is canceled, rename ll_invalidate_negative_children() to ll_prune_negative_children(). Since now unused invalid dentries will always be pruned, it's not necessary to call __d_drop() in d_lustre_invalidate(). It's redundant to take i_lock before d_lustre_invalidate() in ll_inode_revalidate() because d_lustre_invalidate() takes d_lock, remove it. Signed-off-by: Lai Siyao Change-Id: Ib0ae57537e31ba9269e042b94bc5fbe7cb263a50 Reviewed-on: https://review.whamcloud.com/39685 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Andreas Dilger Reviewed-by: Oleg Drokin Reviewed-by: Yingjin Qian --- lustre/llite/dcache.c | 15 ++++++--------- lustre/llite/file.c | 7 ++----- lustre/llite/llite_internal.h | 22 ++++++---------------- lustre/llite/namei.c | 44 ++++++++++++++++++++++++++++++------------- 4 files changed, 45 insertions(+), 43 deletions(-) diff --git a/lustre/llite/dcache.c b/lustre/llite/dcache.c index a02055f..c299068 100644 --- a/lustre/llite/dcache.c +++ b/lustre/llite/dcache.c @@ -217,7 +217,8 @@ void ll_intent_release(struct lookup_intent *it) EXIT; } -void ll_invalidate_aliases(struct inode *inode) +/* mark aliases invalid and prune unused aliases */ +void ll_prune_aliases(struct inode *inode) { struct dentry *dentry; ENTRY; @@ -228,16 +229,12 @@ void ll_invalidate_aliases(struct inode *inode) PFID(ll_inode2fid(inode)), inode); spin_lock(&inode->i_lock); - hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) { - CDEBUG(D_DENTRY, - "dentry in drop %pd (%p) parent %p inode %p flags %d\n", - dentry, dentry, dentry->d_parent, - dentry->d_inode, dentry->d_flags); - - d_lustre_invalidate(dentry, 0); - } + hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) + d_lustre_invalidate(dentry); spin_unlock(&inode->i_lock); + d_prune_aliases(inode); + EXIT; } diff --git a/lustre/llite/file.c b/lustre/llite/file.c index bc0f5dd..9cb9d00 100644 --- a/lustre/llite/file.c +++ b/lustre/llite/file.c @@ -4778,11 +4778,8 @@ static int ll_inode_revalidate(struct dentry *dentry, enum ldlm_intent_flags op) * do_lookup() -> ll_revalidate_it(). We cannot use d_drop * here to preserve get_cwd functionality on 2.6. * Bug 10503 */ - if (!dentry->d_inode->i_nlink) { - spin_lock(&inode->i_lock); - d_lustre_invalidate(dentry, 0); - spin_unlock(&inode->i_lock); - } + if (!dentry->d_inode->i_nlink) + d_lustre_invalidate(dentry); ll_lookup_finish_locks(&oit, dentry); out: diff --git a/lustre/llite/llite_internal.h b/lustre/llite/llite_internal.h index 4363d09..130a6a7 100644 --- a/lustre/llite/llite_internal.h +++ b/lustre/llite/llite_internal.h @@ -1145,7 +1145,7 @@ int ll_d_init(struct dentry *de); extern const struct dentry_operations ll_d_ops; void ll_intent_drop_lock(struct lookup_intent *); void ll_intent_release(struct lookup_intent *); -void ll_invalidate_aliases(struct inode *); +void ll_prune_aliases(struct inode *inode); void ll_lookup_finish_locks(struct lookup_intent *it, struct dentry *dentry); int ll_revalidate_it_finish(struct ptlrpc_request *request, struct lookup_intent *it, struct dentry *de); @@ -1613,28 +1613,18 @@ static inline void __d_lustre_invalidate(struct dentry *dentry) /* * Mark dentry INVALID, if dentry refcount is zero (this is normally case for - * ll_md_blocking_ast), unhash this dentry, and let dcache to reclaim it later; - * else dput() of the last refcount will unhash this dentry and kill it. + * ll_md_blocking_ast), it will be pruned by ll_prune_aliases() and + * ll_prune_negative_children(); otherwise dput() of the last refcount will + * unhash this dentry and kill it. */ -static inline void d_lustre_invalidate(struct dentry *dentry, int nested) +static inline void d_lustre_invalidate(struct dentry *dentry) { CDEBUG(D_DENTRY, "invalidate dentry %pd (%p) parent %p inode %p refc %d\n", dentry, dentry, dentry->d_parent, dentry->d_inode, ll_d_count(dentry)); - spin_lock_nested(&dentry->d_lock, - nested ? DENTRY_D_LOCK_NESTED : DENTRY_D_LOCK_NORMAL); + spin_lock(&dentry->d_lock); __d_lustre_invalidate(dentry); - /* - * We should be careful about dentries created by d_obtain_alias(). - * These dentries are not put in the dentry tree, instead they are - * linked to sb->s_anon through dentry->d_hash. - * shrink_dcache_for_umount() shrinks the tree and sb->s_anon list. - * If we unhashed such a dentry, unmount would not be able to find - * it and busy inodes would be reported. - */ - if (ll_d_count(dentry) == 0 && !(dentry->d_flags & DCACHE_DISCONNECTED)) - __d_drop(dentry); spin_unlock(&dentry->d_lock); } diff --git a/lustre/llite/namei.c b/lustre/llite/namei.c index 9b9c4b8..ab6285c 100644 --- a/lustre/llite/namei.c +++ b/lustre/llite/namei.c @@ -155,26 +155,44 @@ struct inode *ll_iget(struct super_block *sb, ino_t hash, RETURN(inode); } -static void ll_invalidate_negative_children(struct inode *dir) +/* mark negative sub file dentries invalid and prune unused dentries */ +static void ll_prune_negative_children(struct inode *dir) { - struct dentry *dentry, *tmp_subdir; + struct dentry *dentry; + struct dentry *child; + ENTRY; + +restart: spin_lock(&dir->i_lock); hlist_for_each_entry(dentry, &dir->i_dentry, d_alias) { spin_lock(&dentry->d_lock); - if (!list_empty(&dentry->d_subdirs)) { - struct dentry *child; - - list_for_each_entry_safe(child, tmp_subdir, - &dentry->d_subdirs, - d_child) { - if (child->d_inode == NULL) - d_lustre_invalidate(child, 1); + list_for_each_entry(child, &dentry->d_subdirs, d_child) { + if (child->d_inode) + continue; + + spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED); + __d_lustre_invalidate(child); + if (!ll_d_count(child)) { + dget_dlock(child); + __d_drop(child); + spin_unlock(&child->d_lock); + spin_unlock(&dentry->d_lock); + spin_unlock(&dir->i_lock); + + CDEBUG(D_DENTRY, "prune negative dentry %pd\n", + child); + + dput(child); + goto restart; } + spin_unlock(&child->d_lock); } spin_unlock(&dentry->d_lock); } spin_unlock(&dir->i_lock); + + EXIT; } int ll_test_inode_by_fid(struct inode *inode, void *opaque) @@ -343,18 +361,18 @@ static void ll_lock_cancel_bits(struct ldlm_lock *lock, __u64 to_cancel) ll_test_inode_by_fid, (void *)&lli->lli_pfid); if (master_inode) { - ll_invalidate_negative_children(master_inode); + ll_prune_negative_children(master_inode); iput(master_inode); } } else { - ll_invalidate_negative_children(inode); + ll_prune_negative_children(inode); } } if ((bits & (MDS_INODELOCK_LOOKUP | MDS_INODELOCK_PERM)) && inode->i_sb->s_root != NULL && inode != inode->i_sb->s_root->d_inode) - ll_invalidate_aliases(inode); + ll_prune_aliases(inode); if (bits & (MDS_INODELOCK_LOOKUP | MDS_INODELOCK_PERM)) forget_all_cached_acls(inode); -- 1.8.3.1