提交 7ba5d5d0 编写于 作者: Y yangerkun 提交者: Xie XiuQi

fs/dcache.c: avoid softlock since too many negative dentry

euler inclusion
category: bugfix
bugzilla: 15743
CVE: NA
---------------------------

Parallel thread to add negative dentry under root dir. Sometimes later,
'systemctl daemon-reload' will report softlockup since
__fsnotify_update_child_dentry_flags need update all child under root
dentry without distinguish does it active or not. It will waste so long
time with catching d_lock of root dentry. And other thread try to
spin_lock d_lock will run overtime.

Limit negative dentry under dir can avoid this.
Signed-off-by: Nyangerkun <yangerkun@huawei.com>
Reviewed-by: NMiao Xie <miaoxie@huawei.com>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
上级 3cd16d87
......@@ -316,12 +316,20 @@ static inline void __d_set_inode_and_type(struct dentry *dentry,
unsigned type_flags)
{
unsigned flags;
struct dentry *parent;
parent = dentry->d_parent;
if ((dentry->d_flags & DCACHE_NEGATIVE_ACCOUNT) && parent) {
WARN_ON(!inode);
atomic_dec(&parent->d_neg_dnum);
}
dentry->d_inode = inode;
/* paired with smp_rmb() in lookup_fast() */
smp_wmb();
flags = READ_ONCE(dentry->d_flags);
flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU);
flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU |
DCACHE_NEGATIVE_ACCOUNT);
flags |= type_flags;
WRITE_ONCE(dentry->d_flags, flags);
}
......@@ -338,6 +346,7 @@ static inline void __d_clear_type_and_inode(struct dentry *dentry)
static void dentry_free(struct dentry *dentry)
{
WARN_ON(!hlist_unhashed(&dentry->d_u.d_alias));
WARN_ON(dentry->d_flags & DCACHE_NEGATIVE_ACCOUNT);
if (unlikely(dname_external(dentry))) {
struct external_name *p = external_name(dentry);
if (likely(atomic_dec_and_test(&p->u.count))) {
......@@ -562,8 +571,14 @@ static void __dentry_kill(struct dentry *dentry)
/* if it was on the hash then remove it */
__d_drop(dentry);
dentry_unlist(dentry, parent);
if (parent)
if (parent) {
if (dentry->d_flags & DCACHE_NEGATIVE_ACCOUNT) {
atomic_dec(&parent->d_neg_dnum);
dentry->d_flags &= ~DCACHE_NEGATIVE_ACCOUNT;
}
spin_unlock(&parent->d_lock);
}
if (dentry->d_inode)
dentry_unlink_inode(dentry);
else
......@@ -623,6 +638,8 @@ static inline struct dentry *lock_parent(struct dentry *dentry)
static inline bool retain_dentry(struct dentry *dentry)
{
struct dentry *parent;
WARN_ON(d_in_lookup(dentry));
/* Unreachable? Get rid of it */
......@@ -636,6 +653,28 @@ static inline bool retain_dentry(struct dentry *dentry)
if (dentry->d_op->d_delete(dentry))
return false;
}
if (unlikely(!dentry->d_parent))
goto noparent;
parent = dentry->d_parent;
/* Return false if it's negative */
WARN_ON((atomic_read(&parent->d_neg_dnum) < 0));
if (!dentry->d_inode) {
if (!(dentry->d_flags & DCACHE_NEGATIVE_ACCOUNT)) {
unsigned flags = READ_ONCE(dentry->d_flags);
flags |= DCACHE_NEGATIVE_ACCOUNT;
WRITE_ONCE(dentry->d_flags, flags);
atomic_inc(&parent->d_neg_dnum);
}
}
if (!dentry->d_inode &&
atomic_read(&parent->d_neg_dnum) >= NEG_DENTRY_LIMIT)
return false;
noparent:
/* retain; LRU fodder */
dentry->d_lockref.count--;
if (unlikely(!(dentry->d_flags & DCACHE_LRU_LIST)))
......@@ -1651,6 +1690,7 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
seqcount_init(&dentry->d_seq);
dentry->d_inode = NULL;
dentry->d_parent = dentry;
atomic_set(&dentry->d_neg_dnum, 0);
dentry->d_sb = sb;
dentry->d_op = NULL;
dentry->d_fsdata = NULL;
......
......@@ -84,6 +84,7 @@ extern struct dentry_stat_t dentry_stat;
# endif
#endif
#define NEG_DENTRY_LIMIT 16384
#define d_lock d_lockref.lock
struct dentry {
......@@ -119,6 +120,8 @@ struct dentry {
struct rcu_head d_rcu;
} d_u;
/* negative dentry under this dentry, if it's dir */
atomic_t d_neg_dnum;
KABI_RESERVE(1)
KABI_RESERVE(2)
} __randomize_layout;
......@@ -225,6 +228,7 @@ struct dentry_operations {
#define DCACHE_PAR_LOOKUP 0x10000000 /* being looked up (with parent locked shared) */
#define DCACHE_DENTRY_CURSOR 0x20000000
#define DCACHE_NEGATIVE_ACCOUNT 0x40000000
extern seqlock_t rename_lock;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册