|
@@ -257,11 +257,25 @@ 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 = 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);
|
|
|
- kfree(external_name(dentry));
|
|
|
- kmem_cache_free(dentry_cache, dentry);
|
|
|
+
|
|
|
+ __d_free_external_name(&external_name(dentry)->u.head);
|
|
|
+
|
|
|
+ kmem_cache_free(dentry_cache, dentry);
|
|
|
}
|
|
|
|
|
|
static inline int dname_external(const struct dentry *dentry)
|
|
@@ -291,7 +305,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);
|
|
@@ -1617,6 +1631,7 @@ EXPORT_SYMBOL(d_invalidate);
|
|
|
|
|
|
struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
|
|
|
{
|
|
|
+ struct external_name *ext = NULL;
|
|
|
struct dentry *dentry;
|
|
|
char *dname;
|
|
|
int err;
|
|
@@ -1637,14 +1652,14 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
|
|
|
dname = dentry->d_iname;
|
|
|
} else if (name->len > DNAME_INLINE_LEN-1) {
|
|
|
size_t size = offsetof(struct external_name, name[1]);
|
|
|
- struct external_name *p = kmalloc(size + name->len,
|
|
|
- GFP_KERNEL_ACCOUNT);
|
|
|
- if (!p) {
|
|
|
+
|
|
|
+ ext = kmalloc(size + name->len, GFP_KERNEL_ACCOUNT);
|
|
|
+ if (!ext) {
|
|
|
kmem_cache_free(dentry_cache, dentry);
|
|
|
return NULL;
|
|
|
}
|
|
|
- atomic_set(&p->u.count, 1);
|
|
|
- dname = p->name;
|
|
|
+ atomic_set(&ext->u.count, 1);
|
|
|
+ dname = ext->name;
|
|
|
} else {
|
|
|
dname = dentry->d_iname;
|
|
|
}
|
|
@@ -1683,6 +1698,12 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if (unlikely(ext)) {
|
|
|
+ pg_data_t *pgdat = page_pgdat(virt_to_page(ext));
|
|
|
+ mod_node_page_state(pgdat, NR_INDIRECTLY_RECLAIMABLE_BYTES,
|
|
|
+ ksize(ext));
|
|
|
+ }
|
|
|
+
|
|
|
this_cpu_inc(nr_dentry);
|
|
|
|
|
|
return dentry;
|
|
@@ -2770,7 +2791,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);
|
|
|
}
|
|
|
|
|
|
/*
|