On Mon, Mar 12, 2018 at 09:17:42PM +0000, Al Viro wrote: > On Mon, Mar 05, 2018 at 01:37:43PM +0000, Roman Gushchin wrote: > > diff --git a/fs/dcache.c b/fs/dcache.c > > index 5c7df1df81ff..a0312d73f575 100644 > > --- a/fs/dcache.c > > +++ b/fs/dcache.c > > @@ -273,8 +273,16 @@ static void __d_free(struct rcu_head *head) > > static void __d_free_external(struct rcu_head *head) > > { > > struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu); > > - kfree(external_name(dentry)); > > - kmem_cache_free(dentry_cache, dentry); > > + struct external_name *name = external_name(dentry); > > + unsigned long bytes; > > + > > + bytes = dentry->d_name.len + offsetof(struct external_name, name[1]); > > + mod_node_page_state(page_pgdat(virt_to_page(name)), > > + NR_INDIRECTLY_RECLAIMABLE_BYTES, > > + -kmalloc_size(kmalloc_index(bytes))); > > + > > + kfree(name); > > + kmem_cache_free(dentry_cache, dentry); > > } > > That can't be right - external names can be freed in release_dentry_name_snapshot() > and copy_name() as well. When do you want kfree_rcu() paths accounted for, BTW? > At the point where we are freeing them, or where we are scheduling their freeing? Ah, I see... I think, it's better to account them when we're actually freeing, otherwise we will have strange path: (indirectly) reclaimable -> unreclaimable -> free Do you agree? Although it shouldn't be that important in practice. Thank you! -- >From ad9d6c627c2b9315de1967c40a1f4fa68705cf9e Mon Sep 17 00:00:00 2001 From: Roman Gushchin <guro@xxxxxx> Date: Mon, 12 Mar 2018 22:24:28 +0000 Subject: [PATCH] dcache: fix indirectly reclaimable memory accounting Signed-off-by: Roman Gushchin <guro@xxxxxx> --- fs/dcache.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index 98826efe22a0..19bc7495a6c4 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -266,6 +266,19 @@ static void __d_free(struct rcu_head *head) kmem_cache_free(dentry_cache, dentry); } +static void __d_free_external_name(struct rcu_head *head) +{ + struct external_name *name; + + name = container_of(head, struct external_name, u.head); + + mod_node_page_state(page_pgdat(virt_to_page(name)), + NR_INDIRECTLY_RECLAIMABLE_BYTES, + -ksize(name)); + + kfree(name); +} + static void __d_free_external(struct rcu_head *head) { struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu); @@ -307,7 +320,7 @@ void release_dentry_name_snapshot(struct name_snapshot *name) struct external_name *p; p = container_of(name->name, struct external_name, name[0]); if (unlikely(atomic_dec_and_test(&p->u.count))) - kfree_rcu(p, u.head); + call_rcu(&p->u.head, __d_free_external_name); } } EXPORT_SYMBOL(release_dentry_name_snapshot); @@ -2769,7 +2782,7 @@ static void copy_name(struct dentry *dentry, struct dentry *target) dentry->d_name.hash_len = target->d_name.hash_len; } if (old_name && likely(atomic_dec_and_test(&old_name->u.count))) - kfree_rcu(old_name, u.head); + call_rcu(&old_name->u.head, __d_free_external_name); } static void dentry_lock_for_move(struct dentry *dentry, struct dentry *target) -- 2.14.3