From: yangerkun yangerkun@huawei.com
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I8JDP6?from=project-issue
---------------------------
We use lockref for dentry reference without notice that so many negative dentry under one dir can lead to overflow of lockref. This can lead to system crash if we do this under root dir.
Since there is not a perfect solution, we just limit max number of dentry count up to INT_MAX / 2. Also, it will cost a lot of time from INT_MAX / 2 to INT_MAX, so we no need to do this under protection of dentry lock.
Also, we limit the FILES_MAX to INT_MAX / 2, since a lot open for same file can lead to overflow too.
Changelog: v1->v2: add a function to do check / add a Macro to mean INT_MAX / 2
Signed-off-by: yangerkun yangerkun@huawei.com Reviewed-by: Miao Xie miaoxie@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com
Conflicts: fs/dcache.c Reviewed-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com Signed-off-by: Zizhi Wo wozizhi@huawei.com --- fs/dcache.c | 32 ++++++++++++++++++++++++++++---- include/linux/fs.h | 3 +++ 2 files changed, 31 insertions(+), 4 deletions(-)
diff --git a/fs/dcache.c b/fs/dcache.c index 25ac74d30bff..7cdd8bbedd1c 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1834,6 +1834,18 @@ static struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name) return dentry; }
+static inline bool d_forbid_overflow(struct dentry *dentry) +{ + if (unlikely(d_count(dentry) >= D_COUNT_MAX)) { + shrink_dcache_parent(dentry); + + if (d_count(dentry) >= D_COUNT_MAX) + return false; + } + + return true; +} + /** * d_alloc - allocate a dcache entry * @parent: parent of entry to allocate @@ -1845,9 +1857,15 @@ static struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name) */ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) { - struct dentry *dentry = __d_alloc(parent->d_sb, name); + struct dentry *dentry = NULL; + + if (unlikely(!d_forbid_overflow(parent))) + goto out; + + dentry = __d_alloc(parent->d_sb, name); if (!dentry) - return NULL; + goto out; + spin_lock(&parent->d_lock); /* * don't need child lock because it is not subject @@ -1857,7 +1875,7 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) dentry->d_parent = parent; list_add(&dentry->d_child, &parent->d_subdirs); spin_unlock(&parent->d_lock); - +out: return dentry; } EXPORT_SYMBOL(d_alloc); @@ -1870,11 +1888,17 @@ EXPORT_SYMBOL(d_alloc_anon);
struct dentry *d_alloc_cursor(struct dentry * parent) { - struct dentry *dentry = d_alloc_anon(parent->d_sb); + struct dentry *dentry = NULL; + + if (unlikely(!d_forbid_overflow(parent))) + goto out; + + dentry = d_alloc_anon(parent->d_sb); if (dentry) { dentry->d_flags |= DCACHE_DENTRY_CURSOR; dentry->d_parent = dget(parent); } +out: return dentry; }
diff --git a/include/linux/fs.h b/include/linux/fs.h index 4a40823c3c67..4f6b15e960ec 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -47,6 +47,9 @@ #include <asm/byteorder.h> #include <uapi/linux/fs.h>
+#define D_COUNT_MAX (INT_MAX / 2) + + struct backing_dev_info; struct bdi_writeback; struct bio;
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://gitee.com/openeuler/kernel/pulls/2986 邮件列表地址:https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/V...
FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://gitee.com/openeuler/kernel/pulls/2986 Mailing list address: https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/V...