Commit 9e3d47df authored by Eric W. Biederman's avatar Eric W. Biederman

sysctl: Make the header lists per directory.

Slightly enhance efficiency and clarity of the code by making the
header list per directory instead of per set.

Benchmark before:
    make-dummies 0 999 -> 0.63s
    rmmod dummy        -> 0.12s
    make-dummies 0 9999 -> 2m35s
    rmmod dummy         -> 18s

Benchmark after:
    make-dummies 0 999 -> 0.32s
    rmmod dummy        -> 0.12s
    make-dummies 0 9999 -> 1m17s
    rmmod dummy         -> 17s
Signed-off-by: default avatarEric W. Biederman <ebiederm@xmission.com>
parent e54012ce
...@@ -33,12 +33,12 @@ static struct ctl_table root_table[] = { ...@@ -33,12 +33,12 @@ static struct ctl_table root_table[] = {
{ } { }
}; };
static struct ctl_table_root sysctl_table_root = { static struct ctl_table_root sysctl_table_root = {
.default_set.list = LIST_HEAD_INIT(sysctl_table_root.default_set.dir.header.ctl_entry), .default_set.dir.list = LIST_HEAD_INIT(sysctl_table_root.default_set.dir.list),
.default_set.dir.header = { .default_set.dir.header = {
{{.count = 1, {{.count = 1,
.nreg = 1, .nreg = 1,
.ctl_table = root_table, .ctl_table = root_table,
.ctl_entry = LIST_HEAD_INIT(sysctl_table_root.default_set.list),}}, .ctl_entry = LIST_HEAD_INIT(sysctl_table_root.default_set.dir.header.ctl_entry),}},
.ctl_table_arg = root_table, .ctl_table_arg = root_table,
.root = &sysctl_table_root, .root = &sysctl_table_root,
.set = &sysctl_table_root.default_set, .set = &sysctl_table_root.default_set,
...@@ -79,15 +79,12 @@ static int namecmp(const char *name1, int len1, const char *name2, int len2) ...@@ -79,15 +79,12 @@ static int namecmp(const char *name1, int len1, const char *name2, int len2)
static struct ctl_table *find_entry(struct ctl_table_header **phead, static struct ctl_table *find_entry(struct ctl_table_header **phead,
struct ctl_dir *dir, const char *name, int namelen) struct ctl_dir *dir, const char *name, int namelen)
{ {
struct ctl_table_set *set = dir->header.set;
struct ctl_table_header *head; struct ctl_table_header *head;
struct ctl_table *entry; struct ctl_table *entry;
list_for_each_entry(head, &set->list, ctl_entry) { list_for_each_entry(head, &dir->list, ctl_entry) {
if (head->unregistering) if (head->unregistering)
continue; continue;
if (head->parent != dir)
continue;
for (entry = head->ctl_table; entry->procname; entry++) { for (entry = head->ctl_table; entry->procname; entry++) {
const char *procname = entry->procname; const char *procname = entry->procname;
if (namecmp(procname, strlen(procname), name, namelen) == 0) { if (namecmp(procname, strlen(procname), name, namelen) == 0) {
...@@ -133,7 +130,7 @@ static int insert_header(struct ctl_dir *dir, struct ctl_table_header *header) ...@@ -133,7 +130,7 @@ static int insert_header(struct ctl_dir *dir, struct ctl_table_header *header)
err = insert_links(header); err = insert_links(header);
if (err) if (err)
goto fail_links; goto fail_links;
list_add_tail(&header->ctl_entry, &header->set->list); list_add_tail(&header->ctl_entry, &header->parent->list);
return 0; return 0;
fail_links: fail_links:
header->parent = NULL; header->parent = NULL;
...@@ -247,14 +244,12 @@ static struct ctl_table *lookup_entry(struct ctl_table_header **phead, ...@@ -247,14 +244,12 @@ static struct ctl_table *lookup_entry(struct ctl_table_header **phead,
static struct ctl_table_header *next_usable_entry(struct ctl_dir *dir, static struct ctl_table_header *next_usable_entry(struct ctl_dir *dir,
struct list_head *tmp) struct list_head *tmp)
{ {
struct ctl_table_set *set = dir->header.set;
struct ctl_table_header *head; struct ctl_table_header *head;
for (tmp = tmp->next; tmp != &set->list; tmp = tmp->next) { for (tmp = tmp->next; tmp != &dir->list; tmp = tmp->next) {
head = list_entry(tmp, struct ctl_table_header, ctl_entry); head = list_entry(tmp, struct ctl_table_header, ctl_entry);
if (head->parent != dir || if (!head->ctl_table->procname ||
!head->ctl_table->procname ||
!use_table(head)) !use_table(head))
continue; continue;
...@@ -270,7 +265,7 @@ static void first_entry(struct ctl_dir *dir, ...@@ -270,7 +265,7 @@ static void first_entry(struct ctl_dir *dir,
struct ctl_table *entry = NULL; struct ctl_table *entry = NULL;
spin_lock(&sysctl_lock); spin_lock(&sysctl_lock);
head = next_usable_entry(dir, &dir->header.set->list); head = next_usable_entry(dir, &dir->list);
spin_unlock(&sysctl_lock); spin_unlock(&sysctl_lock);
if (head) if (head)
entry = head->ctl_table; entry = head->ctl_table;
...@@ -793,6 +788,7 @@ static struct ctl_dir *new_dir(struct ctl_table_set *set, ...@@ -793,6 +788,7 @@ static struct ctl_dir *new_dir(struct ctl_table_set *set,
new_name = (char *)(table + 2); new_name = (char *)(table + 2);
memcpy(new_name, name, namelen); memcpy(new_name, name, namelen);
new_name[namelen] = '\0'; new_name[namelen] = '\0';
INIT_LIST_HEAD(&new->list);
table[0].procname = new_name; table[0].procname = new_name;
table[0].mode = S_IFDIR|S_IRUGO|S_IXUGO; table[0].mode = S_IFDIR|S_IRUGO|S_IXUGO;
init_header(&new->header, set->dir.header.root, set, table); init_header(&new->header, set->dir.header.root, set, table);
...@@ -917,12 +913,10 @@ static int sysctl_check_table_dups(struct ctl_dir *dir, struct ctl_table *old, ...@@ -917,12 +913,10 @@ static int sysctl_check_table_dups(struct ctl_dir *dir, struct ctl_table *old,
static int sysctl_check_dups(struct ctl_dir *dir, struct ctl_table *table) static int sysctl_check_dups(struct ctl_dir *dir, struct ctl_table *table)
{ {
struct ctl_table_set *set;
struct ctl_table_header *head; struct ctl_table_header *head;
int error = 0; int error = 0;
set = dir->header.set; list_for_each_entry(head, &dir->list, ctl_entry) {
list_for_each_entry(head, &set->list, ctl_entry) {
if (head->unregistering) if (head->unregistering)
continue; continue;
if (head->parent != dir) if (head->parent != dir)
...@@ -1494,14 +1488,14 @@ void setup_sysctl_set(struct ctl_table_set *set, ...@@ -1494,14 +1488,14 @@ void setup_sysctl_set(struct ctl_table_set *set,
int (*is_seen)(struct ctl_table_set *)) int (*is_seen)(struct ctl_table_set *))
{ {
memset(set, sizeof(*set), 0); memset(set, sizeof(*set), 0);
INIT_LIST_HEAD(&set->list);
set->is_seen = is_seen; set->is_seen = is_seen;
INIT_LIST_HEAD(&set->dir.list);
init_header(&set->dir.header, root, set, root_table); init_header(&set->dir.header, root, set, root_table);
} }
void retire_sysctl_set(struct ctl_table_set *set) void retire_sysctl_set(struct ctl_table_set *set)
{ {
WARN_ON(!list_empty(&set->list)); WARN_ON(!list_empty(&set->dir.list));
} }
int __init proc_sys_init(void) int __init proc_sys_init(void)
......
...@@ -1047,10 +1047,10 @@ struct ctl_table_header ...@@ -1047,10 +1047,10 @@ struct ctl_table_header
struct ctl_dir { struct ctl_dir {
/* Header must be at the start of ctl_dir */ /* Header must be at the start of ctl_dir */
struct ctl_table_header header; struct ctl_table_header header;
struct list_head list;
}; };
struct ctl_table_set { struct ctl_table_set {
struct list_head list;
int (*is_seen)(struct ctl_table_set *); int (*is_seen)(struct ctl_table_set *);
struct ctl_dir dir; struct ctl_dir dir;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment