diff --git a/fs/dcache.c b/fs/dcache.c index ea0485861d9377311a858359ab1183a1bae4e042..185d71a1c05bd40f54c9c04c69784b766f57717a 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1774,6 +1774,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 @@ -1785,9 +1797,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 @@ -1797,7 +1815,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); @@ -1810,11 +1828,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/fs/filescontrol.c b/fs/filescontrol.c index 4ad500f4002579d9c83ffaaaf4ef01679bfea667..fdd557a246be1541494f9cfa38c3b2e243180132 100644 --- a/fs/filescontrol.c +++ b/fs/filescontrol.c @@ -27,7 +27,7 @@ #include #include -#define FILES_MAX ULONG_MAX +#define FILES_MAX D_COUNT_MAX #define FILES_MAX_STR "max" static bool no_acct; diff --git a/include/linux/fs.h b/include/linux/fs.h index 8f6704a3f596c6b1fadd6eb7cc56dceba5cd415a..243a0987ca2ba908883b72c91bde5d41531b65e7 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -44,6 +44,9 @@ #include #include +#define D_COUNT_MAX (INT_MAX / 2) + + struct backing_dev_info; struct bdi_writeback; struct bio;