diff --git a/fs/dcache.c b/fs/dcache.c index 25ac74d30bff3b39e6763c4717cee2b403d80139..7cdd8bbedd1c5e52da743952b05da9790340f331 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 4a40823c3c6784f19bc98911cd1557736eafba7a..4f6b15e960ec5be062fd5d115a2362cdeadd41df 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -47,6 +47,9 @@ #include #include +#define D_COUNT_MAX (INT_MAX / 2) + + struct backing_dev_info; struct bdi_writeback; struct bio;