Skip to content

Commit 076c3ee

Browse files
committed
sysctl: Rewrite proc_sys_lookup introducing find_entry and lookup_entry.
Replace the helpers that proc_sys_lookup uses with helpers that work in terms of an entire sysctl directory. This is worse for sysctl_lock hold times but it is much better for code clarity and the code cleanups to come. find_in_table is no longer needed so it is removed. find_entry a general helper to find entries in a directory is added. lookup_entry is a simple wrapper around find_entry that takes the sysctl_lock increases the use count if an entry is found and drops the sysctl_lock. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
1 parent a194558 commit 076c3ee

File tree

1 file changed

+76
-26
lines changed

1 file changed

+76
-26
lines changed

fs/proc/proc_sysctl.c

Lines changed: 76 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,55 @@ static struct ctl_table_root sysctl_table_root = {
4949

5050
static DEFINE_SPINLOCK(sysctl_lock);
5151

52+
static int namecmp(const char *name1, int len1, const char *name2, int len2)
53+
{
54+
int minlen;
55+
int cmp;
56+
57+
minlen = len1;
58+
if (minlen > len2)
59+
minlen = len2;
60+
61+
cmp = memcmp(name1, name2, minlen);
62+
if (cmp == 0)
63+
cmp = len1 - len2;
64+
return cmp;
65+
}
66+
67+
static struct ctl_table *find_entry(struct ctl_table_header **phead,
68+
struct ctl_table_set *set,
69+
struct ctl_table_header *dir_head, struct ctl_table *dir,
70+
const char *name, int namelen)
71+
{
72+
struct ctl_table_header *head;
73+
struct ctl_table *entry;
74+
75+
if (dir_head->set == set) {
76+
for (entry = dir; entry->procname; entry++) {
77+
const char *procname = entry->procname;
78+
if (namecmp(procname, strlen(procname), name, namelen) == 0) {
79+
*phead = dir_head;
80+
return entry;
81+
}
82+
}
83+
}
84+
85+
list_for_each_entry(head, &set->list, ctl_entry) {
86+
if (head->unregistering)
87+
continue;
88+
if (head->attached_to != dir)
89+
continue;
90+
for (entry = head->attached_by; entry->procname; entry++) {
91+
const char *procname = entry->procname;
92+
if (namecmp(procname, strlen(procname), name, namelen) == 0) {
93+
*phead = head;
94+
return entry;
95+
}
96+
}
97+
}
98+
return NULL;
99+
}
100+
52101
static void init_header(struct ctl_table_header *head,
53102
struct ctl_table_root *root, struct ctl_table_set *set,
54103
struct ctl_table *table)
@@ -168,6 +217,32 @@ lookup_header_list(struct ctl_table_root *root, struct nsproxy *namespaces)
168217
return &set->list;
169218
}
170219

220+
static struct ctl_table *lookup_entry(struct ctl_table_header **phead,
221+
struct ctl_table_header *dir_head,
222+
struct ctl_table *dir,
223+
const char *name, int namelen)
224+
{
225+
struct ctl_table_header *head;
226+
struct ctl_table *entry;
227+
struct ctl_table_root *root;
228+
struct ctl_table_set *set;
229+
230+
spin_lock(&sysctl_lock);
231+
root = &sysctl_table_root;
232+
do {
233+
set = lookup_header_set(root, current->nsproxy);
234+
entry = find_entry(&head, set, dir_head, dir, name, namelen);
235+
if (entry && use_table(head))
236+
*phead = head;
237+
else
238+
entry = NULL;
239+
root = list_entry(root->root_list.next,
240+
struct ctl_table_root, root_list);
241+
} while (!entry && root != &sysctl_table_root);
242+
spin_unlock(&sysctl_lock);
243+
return entry;
244+
}
245+
171246
static struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces,
172247
struct ctl_table_header *prev)
173248
{
@@ -284,21 +359,6 @@ static struct inode *proc_sys_make_inode(struct super_block *sb,
284359
return inode;
285360
}
286361

287-
static struct ctl_table *find_in_table(struct ctl_table *p, struct qstr *name)
288-
{
289-
for ( ; p->procname; p++) {
290-
if (strlen(p->procname) != name->len)
291-
continue;
292-
293-
if (memcmp(p->procname, name->name, name->len) != 0)
294-
continue;
295-
296-
/* I have a match */
297-
return p;
298-
}
299-
return NULL;
300-
}
301-
302362
static struct ctl_table_header *grab_header(struct inode *inode)
303363
{
304364
struct ctl_table_header *head = PROC_I(inode)->sysctl;
@@ -328,17 +388,7 @@ static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry,
328388

329389
table = table ? table->child : &head->ctl_table[1];
330390

331-
p = find_in_table(table, name);
332-
if (!p) {
333-
for (h = sysctl_head_next(NULL); h; h = sysctl_head_next(h)) {
334-
if (h->attached_to != table)
335-
continue;
336-
p = find_in_table(h->attached_by, name);
337-
if (p)
338-
break;
339-
}
340-
}
341-
391+
p = lookup_entry(&h, head, table, name->name, name->len);
342392
if (!p)
343393
goto out;
344394

0 commit comments

Comments
 (0)