summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorRoman Gushchin <guro@fb.com>2018-04-10 19:27:44 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-04-11 13:28:29 -0400
commitf1782c9bc547754f4bd3043fe8cfda53db85f13f (patch)
treed5b25e08831e52c5a5d665fdd3b837a653dab21b /fs
parent034ebf65c3c21d85b963d39f992258a64a85e3a9 (diff)
dcache: account external names as indirectly reclaimable memory
I received a report about suspicious growth of unreclaimable slabs on some machines. I've found that it happens on machines with low memory pressure, and these unreclaimable slabs are external names attached to dentries. External names are allocated using generic kmalloc() function, so they are accounted as unreclaimable. But they are held by dentries, which are reclaimable, and they will be reclaimed under the memory pressure. In particular, this breaks MemAvailable calculation, as it doesn't take unreclaimable slabs into account. This leads to a silly situation, when a machine is almost idle, has no memory pressure and therefore has a big dentry cache. And the resulting MemAvailable is too low to start a new workload. To address the issue, the NR_INDIRECTLY_RECLAIMABLE_BYTES counter is used to track the amount of memory, consumed by external names. The counter is increased in the dentry allocation path, if an external name structure is allocated; and it's decreased in the dentry freeing path. To reproduce the problem I've used the following Python script: import os for iter in range (0, 10000000): try: name = ("/some_long_name_%d" % iter) + "_" * 220 os.stat(name) except Exception: pass Without this patch: $ cat /proc/meminfo | grep MemAvailable MemAvailable: 7811688 kB $ python indirect.py $ cat /proc/meminfo | grep MemAvailable MemAvailable: 2753052 kB With the patch: $ cat /proc/meminfo | grep MemAvailable MemAvailable: 7809516 kB $ python indirect.py $ cat /proc/meminfo | grep MemAvailable MemAvailable: 7749144 kB [guro@fb.com: fix indirectly reclaimable memory accounting for CONFIG_SLOB] Link: http://lkml.kernel.org/r/20180312194140.19517-1-guro@fb.com [guro@fb.com: fix indirectly reclaimable memory accounting] Link: http://lkml.kernel.org/r/20180313125701.7955-1-guro@fb.com Link: http://lkml.kernel.org/r/20180305133743.12746-5-guro@fb.com Signed-off-by: Roman Gushchin <guro@fb.com> Reviewed-by: Andrew Morton <akpm@linux-foundation.org> Cc: Alexander Viro <viro@zeniv.linux.org.uk> Cc: Michal Hocko <mhocko@suse.com> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Mel Gorman <mgorman@techsingularity.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/dcache.c39
1 files changed, 30 insertions, 9 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index 593079176123..915816e90049 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -257,11 +257,25 @@ static void __d_free(struct rcu_head *head)
257 kmem_cache_free(dentry_cache, dentry); 257 kmem_cache_free(dentry_cache, dentry);
258} 258}
259 259
260static void __d_free_external_name(struct rcu_head *head)
261{
262 struct external_name *name = container_of(head, struct external_name,
263 u.head);
264
265 mod_node_page_state(page_pgdat(virt_to_page(name)),
266 NR_INDIRECTLY_RECLAIMABLE_BYTES,
267 -ksize(name));
268
269 kfree(name);
270}
271
260static void __d_free_external(struct rcu_head *head) 272static void __d_free_external(struct rcu_head *head)
261{ 273{
262 struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu); 274 struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu);
263 kfree(external_name(dentry)); 275
264 kmem_cache_free(dentry_cache, dentry); 276 __d_free_external_name(&external_name(dentry)->u.head);
277
278 kmem_cache_free(dentry_cache, dentry);
265} 279}
266 280
267static inline int dname_external(const struct dentry *dentry) 281static inline int dname_external(const struct dentry *dentry)
@@ -291,7 +305,7 @@ void release_dentry_name_snapshot(struct name_snapshot *name)
291 struct external_name *p; 305 struct external_name *p;
292 p = container_of(name->name, struct external_name, name[0]); 306 p = container_of(name->name, struct external_name, name[0]);
293 if (unlikely(atomic_dec_and_test(&p->u.count))) 307 if (unlikely(atomic_dec_and_test(&p->u.count)))
294 kfree_rcu(p, u.head); 308 call_rcu(&p->u.head, __d_free_external_name);
295 } 309 }
296} 310}
297EXPORT_SYMBOL(release_dentry_name_snapshot); 311EXPORT_SYMBOL(release_dentry_name_snapshot);
@@ -1617,6 +1631,7 @@ EXPORT_SYMBOL(d_invalidate);
1617 1631
1618struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name) 1632struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
1619{ 1633{
1634 struct external_name *ext = NULL;
1620 struct dentry *dentry; 1635 struct dentry *dentry;
1621 char *dname; 1636 char *dname;
1622 int err; 1637 int err;
@@ -1637,14 +1652,14 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
1637 dname = dentry->d_iname; 1652 dname = dentry->d_iname;
1638 } else if (name->len > DNAME_INLINE_LEN-1) { 1653 } else if (name->len > DNAME_INLINE_LEN-1) {
1639 size_t size = offsetof(struct external_name, name[1]); 1654 size_t size = offsetof(struct external_name, name[1]);
1640 struct external_name *p = kmalloc(size + name->len, 1655
1641 GFP_KERNEL_ACCOUNT); 1656 ext = kmalloc(size + name->len, GFP_KERNEL_ACCOUNT);
1642 if (!p) { 1657 if (!ext) {
1643 kmem_cache_free(dentry_cache, dentry); 1658 kmem_cache_free(dentry_cache, dentry);
1644 return NULL; 1659 return NULL;
1645 } 1660 }
1646 atomic_set(&p->u.count, 1); 1661 atomic_set(&ext->u.count, 1);
1647 dname = p->name; 1662 dname = ext->name;
1648 } else { 1663 } else {
1649 dname = dentry->d_iname; 1664 dname = dentry->d_iname;
1650 } 1665 }
@@ -1683,6 +1698,12 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
1683 } 1698 }
1684 } 1699 }
1685 1700
1701 if (unlikely(ext)) {
1702 pg_data_t *pgdat = page_pgdat(virt_to_page(ext));
1703 mod_node_page_state(pgdat, NR_INDIRECTLY_RECLAIMABLE_BYTES,
1704 ksize(ext));
1705 }
1706
1686 this_cpu_inc(nr_dentry); 1707 this_cpu_inc(nr_dentry);
1687 1708
1688 return dentry; 1709 return dentry;
@@ -2770,7 +2791,7 @@ static void copy_name(struct dentry *dentry, struct dentry *target)
2770 dentry->d_name.hash_len = target->d_name.hash_len; 2791 dentry->d_name.hash_len = target->d_name.hash_len;
2771 } 2792 }
2772 if (old_name && likely(atomic_dec_and_test(&old_name->u.count))) 2793 if (old_name && likely(atomic_dec_and_test(&old_name->u.count)))
2773 kfree_rcu(old_name, u.head); 2794 call_rcu(&old_name->u.head, __d_free_external_name);
2774} 2795}
2775 2796
2776/* 2797/*