diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2007-02-14 03:34:12 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-14 11:10:00 -0500 |
commit | 77b14db502cb85a031fe8fde6c85d52f3e0acb63 (patch) | |
tree | 4201f6a4dfe1062d1dc00659c403d630401b87cc /kernel/sysctl.c | |
parent | 1ff007eb8e8c7c44e9a384a67d0fdd0fd06ba811 (diff) |
[PATCH] sysctl: reimplement the sysctl proc support
With this change the sysctl inodes can be cached and nothing needs to be done
when removing a sysctl table.
For a cost of 2K code we will save about 4K of static tables (when we remove
de from ctl_table) and 70K in proc_dir_entries that we will not allocate, or
about half that on a 32bit arch.
The speed feels about the same, even though we can now cache the sysctl
dentries :(
We get the core advantage that we don't need to have a 1 to 1 mapping between
ctl table entries and proc files. Making it possible to have /proc/sys vary
depending on the namespace you are in. The currently merged namespaces don't
have an issue here but the network namespace under /proc/sys/net needs to have
different directories depending on which network adapters are visible. By
simply being a cache different directories being visible depending on who you
are is trivial to implement.
[akpm@osdl.org: fix uninitialised var]
[akpm@osdl.org: fix ARM build]
[bunk@stusta.de: make things static]
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Cc: Russell King <rmk@arm.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/sysctl.c')
-rw-r--r-- | kernel/sysctl.c | 182 |
1 files changed, 0 insertions, 182 deletions
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 6bbac5ce75ed..b3ee791ad663 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
@@ -159,26 +159,6 @@ int sysctl_legacy_va_layout; | |||
159 | #endif | 159 | #endif |
160 | 160 | ||
161 | 161 | ||
162 | /* /proc declarations: */ | ||
163 | |||
164 | #ifdef CONFIG_PROC_SYSCTL | ||
165 | |||
166 | static ssize_t proc_readsys(struct file *, char __user *, size_t, loff_t *); | ||
167 | static ssize_t proc_writesys(struct file *, const char __user *, size_t, loff_t *); | ||
168 | static int proc_opensys(struct inode *, struct file *); | ||
169 | |||
170 | const struct file_operations proc_sys_file_operations = { | ||
171 | .open = proc_opensys, | ||
172 | .read = proc_readsys, | ||
173 | .write = proc_writesys, | ||
174 | }; | ||
175 | |||
176 | extern struct proc_dir_entry *proc_sys_root; | ||
177 | |||
178 | static void register_proc_table(ctl_table *, struct proc_dir_entry *, void *); | ||
179 | static void unregister_proc_table(ctl_table *, struct proc_dir_entry *); | ||
180 | #endif | ||
181 | |||
182 | /* The default sysctl tables: */ | 162 | /* The default sysctl tables: */ |
183 | 163 | ||
184 | static ctl_table root_table[] = { | 164 | static ctl_table root_table[] = { |
@@ -1106,13 +1086,6 @@ struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev) | |||
1106 | return NULL; | 1086 | return NULL; |
1107 | } | 1087 | } |
1108 | 1088 | ||
1109 | void __init sysctl_init(void) | ||
1110 | { | ||
1111 | #ifdef CONFIG_PROC_SYSCTL | ||
1112 | register_proc_table(root_table, proc_sys_root, &root_table_header); | ||
1113 | #endif | ||
1114 | } | ||
1115 | |||
1116 | #ifdef CONFIG_SYSCTL_SYSCALL | 1089 | #ifdef CONFIG_SYSCTL_SYSCALL |
1117 | int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, | 1090 | int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, |
1118 | void __user *newval, size_t newlen) | 1091 | void __user *newval, size_t newlen) |
@@ -1348,9 +1321,6 @@ struct ctl_table_header *register_sysctl_table(ctl_table * table) | |||
1348 | spin_lock(&sysctl_lock); | 1321 | spin_lock(&sysctl_lock); |
1349 | list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry); | 1322 | list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry); |
1350 | spin_unlock(&sysctl_lock); | 1323 | spin_unlock(&sysctl_lock); |
1351 | #ifdef CONFIG_PROC_SYSCTL | ||
1352 | register_proc_table(table, proc_sys_root, tmp); | ||
1353 | #endif | ||
1354 | return tmp; | 1324 | return tmp; |
1355 | } | 1325 | } |
1356 | 1326 | ||
@@ -1366,9 +1336,6 @@ void unregister_sysctl_table(struct ctl_table_header * header) | |||
1366 | might_sleep(); | 1336 | might_sleep(); |
1367 | spin_lock(&sysctl_lock); | 1337 | spin_lock(&sysctl_lock); |
1368 | start_unregistering(header); | 1338 | start_unregistering(header); |
1369 | #ifdef CONFIG_PROC_SYSCTL | ||
1370 | unregister_proc_table(header->ctl_table, proc_sys_root); | ||
1371 | #endif | ||
1372 | spin_unlock(&sysctl_lock); | 1339 | spin_unlock(&sysctl_lock); |
1373 | kfree(header); | 1340 | kfree(header); |
1374 | } | 1341 | } |
@@ -1392,155 +1359,6 @@ void unregister_sysctl_table(struct ctl_table_header * table) | |||
1392 | 1359 | ||
1393 | #ifdef CONFIG_PROC_SYSCTL | 1360 | #ifdef CONFIG_PROC_SYSCTL |
1394 | 1361 | ||
1395 | /* Scan the sysctl entries in table and add them all into /proc */ | ||
1396 | static void register_proc_table(ctl_table * table, struct proc_dir_entry *root, void *set) | ||
1397 | { | ||
1398 | struct proc_dir_entry *de; | ||
1399 | int len; | ||
1400 | mode_t mode; | ||
1401 | |||
1402 | for (; table->ctl_name || table->procname; table++) { | ||
1403 | /* Can't do anything without a proc name. */ | ||
1404 | if (!table->procname) | ||
1405 | continue; | ||
1406 | /* Maybe we can't do anything with it... */ | ||
1407 | if (!table->proc_handler && !table->child) { | ||
1408 | printk(KERN_WARNING "SYSCTL: Can't register %s\n", | ||
1409 | table->procname); | ||
1410 | continue; | ||
1411 | } | ||
1412 | |||
1413 | len = strlen(table->procname); | ||
1414 | mode = table->mode; | ||
1415 | |||
1416 | de = NULL; | ||
1417 | if (table->proc_handler) | ||
1418 | mode |= S_IFREG; | ||
1419 | else { | ||
1420 | mode |= S_IFDIR; | ||
1421 | for (de = root->subdir; de; de = de->next) { | ||
1422 | if (proc_match(len, table->procname, de)) | ||
1423 | break; | ||
1424 | } | ||
1425 | /* If the subdir exists already, de is non-NULL */ | ||
1426 | } | ||
1427 | |||
1428 | if (!de) { | ||
1429 | de = create_proc_entry(table->procname, mode, root); | ||
1430 | if (!de) | ||
1431 | continue; | ||
1432 | de->set = set; | ||
1433 | de->data = (void *) table; | ||
1434 | if (table->proc_handler) | ||
1435 | de->proc_fops = &proc_sys_file_operations; | ||
1436 | } | ||
1437 | table->de = de; | ||
1438 | if (de->mode & S_IFDIR) | ||
1439 | register_proc_table(table->child, de, set); | ||
1440 | } | ||
1441 | } | ||
1442 | |||
1443 | /* | ||
1444 | * Unregister a /proc sysctl table and any subdirectories. | ||
1445 | */ | ||
1446 | static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root) | ||
1447 | { | ||
1448 | struct proc_dir_entry *de; | ||
1449 | for (; table->ctl_name || table->procname; table++) { | ||
1450 | if (!(de = table->de)) | ||
1451 | continue; | ||
1452 | if (de->mode & S_IFDIR) { | ||
1453 | if (!table->child) { | ||
1454 | printk (KERN_ALERT "Help - malformed sysctl tree on free\n"); | ||
1455 | continue; | ||
1456 | } | ||
1457 | unregister_proc_table(table->child, de); | ||
1458 | |||
1459 | /* Don't unregister directories which still have entries.. */ | ||
1460 | if (de->subdir) | ||
1461 | continue; | ||
1462 | } | ||
1463 | |||
1464 | /* | ||
1465 | * In any case, mark the entry as goner; we'll keep it | ||
1466 | * around if it's busy, but we'll know to do nothing with | ||
1467 | * its fields. We are under sysctl_lock here. | ||
1468 | */ | ||
1469 | de->data = NULL; | ||
1470 | |||
1471 | /* Don't unregister proc entries that are still being used.. */ | ||
1472 | if (atomic_read(&de->count)) | ||
1473 | continue; | ||
1474 | |||
1475 | table->de = NULL; | ||
1476 | remove_proc_entry(table->procname, root); | ||
1477 | } | ||
1478 | } | ||
1479 | |||
1480 | static ssize_t do_rw_proc(int write, struct file * file, char __user * buf, | ||
1481 | size_t count, loff_t *ppos) | ||
1482 | { | ||
1483 | int op; | ||
1484 | struct proc_dir_entry *de = PDE(file->f_path.dentry->d_inode); | ||
1485 | struct ctl_table *table; | ||
1486 | size_t res; | ||
1487 | ssize_t error = -ENOTDIR; | ||
1488 | |||
1489 | spin_lock(&sysctl_lock); | ||
1490 | if (de && de->data && use_table(de->set)) { | ||
1491 | /* | ||
1492 | * at that point we know that sysctl was not unregistered | ||
1493 | * and won't be until we finish | ||
1494 | */ | ||
1495 | spin_unlock(&sysctl_lock); | ||
1496 | table = (struct ctl_table *) de->data; | ||
1497 | if (!table || !table->proc_handler) | ||
1498 | goto out; | ||
1499 | error = -EPERM; | ||
1500 | op = (write ? 002 : 004); | ||
1501 | if (sysctl_perm(table, op)) | ||
1502 | goto out; | ||
1503 | |||
1504 | /* careful: calling conventions are nasty here */ | ||
1505 | res = count; | ||
1506 | error = (*table->proc_handler)(table, write, file, | ||
1507 | buf, &res, ppos); | ||
1508 | if (!error) | ||
1509 | error = res; | ||
1510 | out: | ||
1511 | spin_lock(&sysctl_lock); | ||
1512 | unuse_table(de->set); | ||
1513 | } | ||
1514 | spin_unlock(&sysctl_lock); | ||
1515 | return error; | ||
1516 | } | ||
1517 | |||
1518 | static int proc_opensys(struct inode *inode, struct file *file) | ||
1519 | { | ||
1520 | if (file->f_mode & FMODE_WRITE) { | ||
1521 | /* | ||
1522 | * sysctl entries that are not writable, | ||
1523 | * are _NOT_ writable, capabilities or not. | ||
1524 | */ | ||
1525 | if (!(inode->i_mode & S_IWUSR)) | ||
1526 | return -EPERM; | ||
1527 | } | ||
1528 | |||
1529 | return 0; | ||
1530 | } | ||
1531 | |||
1532 | static ssize_t proc_readsys(struct file * file, char __user * buf, | ||
1533 | size_t count, loff_t *ppos) | ||
1534 | { | ||
1535 | return do_rw_proc(0, file, buf, count, ppos); | ||
1536 | } | ||
1537 | |||
1538 | static ssize_t proc_writesys(struct file * file, const char __user * buf, | ||
1539 | size_t count, loff_t *ppos) | ||
1540 | { | ||
1541 | return do_rw_proc(1, file, (char __user *) buf, count, ppos); | ||
1542 | } | ||
1543 | |||
1544 | static int _proc_do_string(void* data, int maxlen, int write, | 1362 | static int _proc_do_string(void* data, int maxlen, int write, |
1545 | struct file *filp, void __user *buffer, | 1363 | struct file *filp, void __user *buffer, |
1546 | size_t *lenp, loff_t *ppos) | 1364 | size_t *lenp, loff_t *ppos) |