diff --git a/fs/dcache.c b/fs/dcache.c index 4361940af3349c69a263af1d1e47d8d794afbca3..6c7ff1bbf19510f33f30f9c3a86e6852a24a23d2 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1682,6 +1682,18 @@ 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 @@ -1693,9 +1705,15 @@ 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; + dentry->d_flags |= DCACHE_RCUACCESS; spin_lock(&parent->d_lock); /* @@ -1706,7 +1724,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); @@ -1719,11 +1737,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_RCUACCESS | DCACHE_DENTRY_CURSOR; dentry->d_parent = dget(parent); } +out: return dentry; } diff --git a/fs/filescontrol.c b/fs/filescontrol.c index 5fba9c376dd5eb06d3b053147537b3be1c5b6601..fbaeacbe2de886cde67cdaa271fea70496313ac5 100644 --- a/fs/filescontrol.c +++ b/fs/filescontrol.c @@ -26,7 +26,7 @@ #include #include -#define FILES_MAX ULLONG_MAX +#define FILES_MAX D_COUNT_MAX #define FILES_MAX_STR "max" diff --git a/include/linux/fs.h b/include/linux/fs.h index 09d0646acf66fdc8abc5d616fd6cc92e2c9b7dfb..dfe4b0d98bdedc290c88d27efed8040b6bd816c4 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -42,6 +42,9 @@ #include #include +#define D_COUNT_MAX (INT_MAX / 2) + + struct backing_dev_info; struct bdi_writeback; struct bio;