[v2 078/115] sysctl: alloc ctl_table_header with kmem_cache

From: Lucian Adrian Grijincu
Date: Sun May 08 2011 - 18:47:52 EST


Because now ctl_table_header objects are allocated with a fixed size
buffer (sizeof(struct ctl_table_header)) we can do the allocations
with kmem_cache.

Also, by making sure that the objects that are returned to the cache
are in a sane state we don't waste time reinitializing every field
after kmem_cache_alloc. We only initialize fields that were not left
with a sane value before returning an object to the cache.

Signed-off-by: Lucian Adrian Grijincu <lucian.grijincu@xxxxxxxxx>
---
kernel/sysctl.c | 48 +++++++++++++++++++++++++++++++++++++++---------
1 files changed, 39 insertions(+), 9 deletions(-)

diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index d777e89..c207c19 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -198,6 +198,9 @@ static int sysrq_sysctl_handler(ctl_table *table, int write,

#endif

+/* cache for ctl_table_header objects */
+static struct kmem_cache *sysctl_header_cachep;
+
/* uses default ops */
static const struct ctl_table_group_ops root_table_group_ops = { };

@@ -1553,7 +1556,9 @@ void sysctl_proc_inode_get(struct ctl_table_header *head)

static void free_head(struct rcu_head *rcu)
{
- kfree(container_of(rcu, struct ctl_table_header, rcu));
+ struct ctl_table_header *header;
+ header = container_of(rcu, struct ctl_table_header, rcu);
+ kmem_cache_free(sysctl_header_cachep, header);
}

void sysctl_proc_inode_put(struct ctl_table_header *head)
@@ -1664,6 +1669,8 @@ int sysctl_perm(struct ctl_table_group *group, struct ctl_table *table, int op)
return test_perm(mode, op);
}

+static void sysctl_header_ctor(void *data);
+
__init int sysctl_init(void)
{
struct ctl_table_header *kern_header, *vm_header, *fs_header,
@@ -1672,6 +1679,12 @@ __init int sysctl_init(void)
struct ctl_table_header *binfmt_misc_header;
#endif

+ sysctl_header_cachep = kmem_cache_create("sysctl_header_cachep",
+ sizeof(struct ctl_table_header),
+ 0, 0, &sysctl_header_ctor);
+ if (!sysctl_header_cachep)
+ goto fail_alloc_cachep;
+
kern_header = register_sysctl_paths(kern_path, kern_table);
if (kern_header == NULL)
goto fail_register_kern;
@@ -1715,6 +1728,8 @@ fail_register_fs:
fail_register_vm:
unregister_sysctl_table(kern_header);
fail_register_kern:
+ kmem_cache_destroy(sysctl_header_cachep);
+fail_alloc_cachep:
return -ENOMEM;
}

@@ -1735,19 +1750,34 @@ static int ctl_path_items(const struct ctl_path *path)
return n;
}

+static void sysctl_header_ctor(void *data)
+{
+ struct ctl_table_header *h = data;
+
+ h->ctl_use_refs = 0;
+ h->ctl_procfs_refs = 0;
+ h->ctl_header_refs = 0;
+
+ INIT_LIST_HEAD(&h->ctl_entry);
+ INIT_LIST_HEAD(&h->ctl_subdirs);
+ INIT_LIST_HEAD(&h->ctl_tables);
+}

static struct ctl_table_header *alloc_sysctl_header(struct ctl_table_group *group)
{
struct ctl_table_header *h;

- h = kzalloc(sizeof(*h), GFP_KERNEL);
+ h = kmem_cache_alloc(sysctl_header_cachep, GFP_KERNEL);
if (!h)
return NULL;

+ /* - all _refs members are zero before freeing
+ * - all list_head members point to themselves (empty lists) */
+
+ h->ctl_table_arg = NULL;
+ h->unregistering = NULL;
h->ctl_group = group;
- INIT_LIST_HEAD(&h->ctl_entry);
- INIT_LIST_HEAD(&h->ctl_subdirs);
- INIT_LIST_HEAD(&h->ctl_tables);
+
return h;
}

@@ -1905,12 +1935,12 @@ static struct ctl_table_header *sysctl_mkdirs(struct ctl_table_header *parent,
parent = mkdir_netns_corresp(parent, group, &__netns_corresp);

if (__netns_corresp)
- kfree(__netns_corresp);
+ kmem_cache_free(sysctl_header_cachep, __netns_corresp);

/* free unused pre-allocated entries */
for (i = 0; i < nr_dirs; i++)
if (dirs[i])
- kfree(dirs[i]);
+ kmem_cache_free(sysctl_header_cachep, dirs[i]);

return parent;

@@ -1918,7 +1948,7 @@ err_alloc_coresp:
i = nr_dirs;
err_alloc_dir:
for (i--; i >= 0; i--)
- kfree(dirs[i]);
+ kmem_cache_free(sysctl_header_cachep, dirs[i]);
return NULL;

}
@@ -1991,7 +2021,7 @@ struct ctl_table_header *__register_sysctl_paths(struct ctl_table_group *group,

header->parent = sysctl_mkdirs(&root_table_header, group, path, nr_dirs);
if (!header->parent) {
- kfree(header);
+ kmem_cache_free(sysctl_header_cachep, header);
return NULL;
}

--
1.7.5.134.g1c08b

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/