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: Eric W. Biederman <ebiederm@xmission.com>
This commit is contained in:
Родитель
e54012cede
Коммит
9e3d47df35
|
@ -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)
|
||||||
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)
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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
|
||||||
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;
|
||||||
};
|
};
|
||||||
|
|
Загрузка…
Ссылка в новой задаче