dynamic sysctl registration (pre2.0).4

Tom Dyas (tdyas@eden.rutgers.edu)
Fri, 17 May 96 0:13:36 EDT


The following patch adds support in the sysctl system for dynamically
adding and removing sysctl entries from existing sysctl tables. It is
fundamental redesign of how sysctl's are stored. They are now stored
as linked lists much as the procfs directory entries are stored.

This support is needed because modules such as binfmt_java may want to
register sysctl's in existing tables. The current system does not
allow this at all. Also, it will allow local sysctl registrations in
the kernel. Just like we eventually want to cleanup ksym.c, cleaning
up sysctl.c and all those ugly extern kludges can now be done.

Some minor typos in include/asm-i386/unistd.h are corrected. Just some
extra underscores in the syscall number macros which prevented me from
using _syscall1 to make a sysctl syscall function the first time
around.

The patch is against pre2.0.4 (a.k.a. 1.99.4).

Tom

--- linux/kernel/sysctl.c- Wed May 15 19:40:09 1996
+++ linux/kernel/sysctl.c Thu May 16 22:25:43 1996
@@ -1,14 +1,22 @@
/*
- * sysctl.c: General linux system control interface
+ * linux/kernel/sysctl.c - general system control interface
*
* Begun 24 March 1995, Stephen Tweedie
* Added /proc support, Dec 1995
* Added bdflush entry and intvec min/max checking, 2/23/96, Tom Dyas.
* Added hooks for /proc/sys/net (minor, minor patch), 96/4/1, Mike Shaver.
* Added kernel/java-{interpreter,appletviewer}, 96/5/10, Mike Shaver.
+ *
+ * 5/16/96 Tom Dyas - Rewritten to support dynamic registration of
+ * sysctl entries in any sysctl "table". The old version made it
+ * impossible for a module to dynamically load its own sysctl's into
+ * the standard tables. Also, the kernel code should be able to
+ * register sysctl's locally which should prevent the massive amounts
+ * of extern declarations that litter this file.
*/

#include <linux/config.h>
+#include <linux/module.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/sysctl.h>
@@ -31,16 +39,8 @@
#include <linux/nfs_fs.h>
#endif

-static ctl_table root_table[];
-static struct ctl_table_header root_table_header =
- {root_table, DNODE_SINGLE(&root_table_header)};
-
static int parse_table(int *, int, void *, size_t *, void *, size_t,
- ctl_table *, void **);
-
-static ctl_table kern_table[];
-static ctl_table vm_table[];
-extern ctl_table net_table[];
+ sysctl_entry *, void **);

/* /proc declarations: */

@@ -89,86 +89,134 @@

extern struct proc_dir_entry proc_sys_root;

-static void register_proc_table(ctl_table *, struct proc_dir_entry *);
-static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
#endif

extern int bdf_prm[], bdflush_min[], bdflush_max[];

-static int do_securelevel_strategy (ctl_table *, int *, int, void *, size_t *,
+static int do_securelevel_strategy (sysctl_entry *, int *, int, void *, size_t *,
void *, size_t, void **);

extern char binfmt_java_interpreter[], binfmt_java_appletviewer[];

/* The default sysctl tables: */

-static ctl_table root_table[] = {
- {CTL_KERN, "kernel", NULL, 0, 0555, kern_table},
- {CTL_VM, "vm", NULL, 0, 0555, vm_table},
- {CTL_NET, "net", NULL, 0, 0555, net_table},
- {0}
-};
+sysctl_entry sysctl_root = {0, "root", NULL, 0, 0555};
+
+sysctl_entry sysctl_kern = {CTL_KERN, "kernel", NULL, 0, 0555};
+
+sysctl_entry sysctl_vm = {CTL_VM, "vm", NULL, 0, 0555};

-static ctl_table kern_table[] = {
- {KERN_OSTYPE, "ostype", system_utsname.sysname, 64,
- 0444, NULL, &proc_dostring, &sysctl_string},
- {KERN_OSRELEASE, "osrelease", system_utsname.release, 64,
- 0444, NULL, &proc_dostring, &sysctl_string},
- {KERN_VERSION, "version", system_utsname.version, 64,
- 0444, NULL, &proc_dostring, &sysctl_string},
- {KERN_NODENAME, "hostname", system_utsname.nodename, 64,
- 0644, NULL, &proc_dostring, &sysctl_string},
- {KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64,
- 0644, NULL, &proc_dostring, &sysctl_string},
- {KERN_NRINODE, "inode-nr", &nr_inodes, 2*sizeof(int),
- 0444, NULL, &proc_dointvec},
- {KERN_MAXINODE, "inode-max", &max_inodes, sizeof(int),
- 0644, NULL, &proc_dointvec},
- {KERN_NRFILE, "file-nr", &nr_files, sizeof(int),
- 0444, NULL, &proc_dointvec},
- {KERN_MAXFILE, "file-max", &max_files, sizeof(int),
- 0644, NULL, &proc_dointvec},
- {KERN_SECURELVL, "securelevel", &securelevel, sizeof(int),
- 0444, NULL, &proc_dointvec, (ctl_handler *)&do_securelevel_strategy},
- {KERN_PANIC, "panic", &panic_timeout, sizeof(int),
- 0644, NULL, &proc_dointvec},
+static void init_root_table(void)
+{
+ register_sysctl(&sysctl_root,&sysctl_kern);
+ register_sysctl(&sysctl_root,&sysctl_vm);
+}
+
+static void init_kern_table(void)
+{
+ register_sysctl(&sysctl_kern, &(sysctl_entry)
+ {KERN_OSTYPE, "ostype", system_utsname.sysname, 64,
+ 0444, &proc_dostring, &sysctl_string});
+ register_sysctl(&sysctl_kern, &(sysctl_entry)
+ {KERN_OSRELEASE, "osrelease", system_utsname.release, 64,
+ 0444, &proc_dostring, &sysctl_string});
+ register_sysctl(&sysctl_kern, &(sysctl_entry)
+ {KERN_VERSION, "version", system_utsname.version, 64,
+ 0444, &proc_dostring, &sysctl_string});
+ register_sysctl(&sysctl_kern, &(sysctl_entry)
+ {KERN_NODENAME, "hostname", system_utsname.nodename, 64,
+ 0644, &proc_dostring, &sysctl_string});
+ register_sysctl(&sysctl_kern, &(sysctl_entry)
+ {KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64,
+ 0644, &proc_dostring, &sysctl_string});
+ register_sysctl(&sysctl_kern, &(sysctl_entry)
+ {KERN_NRINODE, "inode-nr", &nr_inodes, 2*sizeof(int),
+ 0444, &proc_dointvec});
+ register_sysctl(&sysctl_kern, &(sysctl_entry)
+ {KERN_MAXINODE, "inode-max", &max_inodes, sizeof(int),
+ 0644, &proc_dointvec});
+ register_sysctl(&sysctl_kern, &(sysctl_entry)
+ {KERN_NRFILE, "file-nr", &nr_files, sizeof(int),
+ 0444, &proc_dointvec});
+ register_sysctl(&sysctl_kern, &(sysctl_entry)
+ {KERN_MAXFILE, "file-max", &max_files, sizeof(int),
+ 0644, &proc_dointvec});
+ register_sysctl(&sysctl_kern, &(sysctl_entry)
+ {KERN_SECURELVL, "securelevel", &securelevel, sizeof(int),
+ 0444, &proc_dointvec, (ctl_handler *)&do_securelevel_strategy});
+ register_sysctl(&sysctl_kern, &(sysctl_entry)
+ {KERN_PANIC, "panic", &panic_timeout, sizeof(int),
+ 0644, &proc_dointvec});
#ifdef CONFIG_BLK_DEV_INITRD
- {KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int),
- 0644, NULL, &proc_dointvec},
+ register_sysctl(&sysctl_kern, &(sysctl_entry)
+ {KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int),
+ 0644, &proc_dointvec});
#endif
#ifdef CONFIG_ROOT_NFS
- {KERN_NFSRNAME, "nfs-root-name", nfs_root_name, NFS_ROOT_NAME_LEN,
- 0644, NULL, &proc_dostring, &sysctl_string },
- {KERN_NFSRNAME, "nfs-root-addrs", nfs_root_addrs, NFS_ROOT_ADDRS_LEN,
- 0644, NULL, &proc_dostring, &sysctl_string },
+ register_sysctl(&sysctl_kern, &(sysctl_entry)
+ {KERN_NFSRNAME, "nfs-root-name", nfs_root_name, NFS_ROOT_NAME_LEN,
+ 0644, &proc_dostring, &sysctl_string });
+ register_sysctl(&sysctl_kern, &(sysctl_entry)
+ {KERN_NFSRNAME, "nfs-root-addrs", nfs_root_addrs, NFS_ROOT_ADDRS_LEN,
+ 0644, &proc_dostring, &sysctl_string });
#endif
#ifdef CONFIG_BINFMT_JAVA
- {KERN_JAVA_INTERPRETER, "java-interpreter", binfmt_java_interpreter,
- 64, 0644, NULL, &proc_dostring, &sysctl_string },
- {KERN_JAVA_APPLETVIEWER, "java-appletviewer", binfmt_java_appletviewer,
- 64, 0644, NULL, &proc_dostring, &sysctl_string },
+ register_sysctl(&sysctl_kern, &(sysctl_entry)
+ {KERN_JAVA_INTERPRETER, "java-interpreter", binfmt_java_interpreter,
+ 64, 0644, &proc_dostring, &sysctl_string });
+ register_sysctl(&sysctl_kern, &(sysctl_entry)
+ {KERN_JAVA_APPLETVIEWER, "java-appletviewer", binfmt_java_appletviewer,
+ 64, 0644, &proc_dostring, &sysctl_string });
#endif
- {0}
-};
+}

-static ctl_table vm_table[] = {
- {VM_SWAPCTL, "swapctl",
- &swap_control, sizeof(swap_control_t), 0600, NULL, &proc_dointvec},
- {VM_KSWAPD, "kswapd",
- &kswapd_ctl, sizeof(kswapd_ctl), 0600, NULL, &proc_dointvec},
- {VM_FREEPG, "freepages",
- &min_free_pages, 3*sizeof(int), 0600, NULL, &proc_dointvec},
- {VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0600, NULL,
- &proc_dointvec_minmax, &sysctl_intvec, NULL,
- &bdflush_min, &bdflush_max},
- {0}
+static void init_vm_table(void)
+{
+ register_sysctl(&sysctl_vm, &(sysctl_entry)
+ {VM_SWAPCTL, "swapctl",
+ &swap_control, sizeof(swap_control_t), 0600, &proc_dointvec});
+ register_sysctl(&sysctl_vm, &(sysctl_entry)
+ {VM_KSWAPD, "kswapd",
+ &kswapd_ctl, sizeof(kswapd_ctl), 0600, &proc_dointvec});
+ register_sysctl(&sysctl_vm, &(sysctl_entry)
+ {VM_FREEPG, "freepages",
+ &min_free_pages, 3*sizeof(int), 0600, &proc_dointvec});
+ register_sysctl(&sysctl_vm, &(sysctl_entry)
+ {VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0600,
+ &proc_dointvec_minmax, &sysctl_intvec,
+ &bdflush_min, &bdflush_max});
+}
+
+static struct symbol_table sysctl_syms = {
+#include <linux/symtab_begin.h>
+ /* registration and deregistration of sysctl entries. */
+ X(register_sysctl),
+ X(unregister_sysctl),
+
+ /* standard sysctl entries. */
+ X(sysctl_root),
+ X(sysctl_kern),
+ X(sysctl_vm),
+ X(sysctl_net),
+
+ /* Standard sysctl handlers (procfs and strategy). */
+#ifdef CONFIG_PROC_FS
+ X(proc_dostring),
+ X(proc_dointvec),
+ X(proc_dointvec_minmax),
+#endif CONFIG_PROC_FS
+ X(sysctl_string),
+ X(sysctl_intvec),
+#include <linux/symtab_end.h>
};

+/* Initialize the standard sysctl world. */
void sysctl_init(void)
{
-#ifdef CONFIG_PROC_FS
- register_proc_table(root_table, &proc_sys_root);
-#endif
+ register_symtab(&sysctl_syms);
+ init_root_table();
+ init_kern_table();
+ init_vm_table();
}


@@ -177,7 +225,6 @@
void *newval, size_t newlen)
{
int error;
- struct ctl_table_header *tmp;
void *context;

if (nlen == 0 || nlen >= CTL_MAXNAME)
@@ -197,17 +244,13 @@
error = verify_area(VERIFY_READ,newval,newlen);
if (error) return error;
}
- tmp = &root_table_header;
- do {
- context = 0;
- error = parse_table(name, nlen, oldval, oldlenp,
- newval, newlen, root_table, &context);
- if (context)
- kfree(context);
- if (error != -ENOTDIR)
- return error;
- tmp = tmp->DLIST_NEXT(ctl_entry);
- } while (tmp != &root_table_header);
+ context = 0;
+ error = parse_table(name, nlen, oldval, oldlenp,
+ newval, newlen, sysctl_root.child, &context);
+ if (context)
+ kfree(context);
+ if (error != -ENOTDIR)
+ return error;
return -ENOTDIR;
}

@@ -251,7 +294,7 @@
return 0;
return -EACCES;
}
-static inline int ctl_perm(ctl_table *table, int op)
+static inline int ctl_perm(sysctl_entry *table, int op)
{
return test_perm(table->mode, op);
}
@@ -259,14 +302,14 @@
static int parse_table(int *name, int nlen,
void *oldval, size_t *oldlenp,
void *newval, size_t newlen,
- ctl_table *table, void **context)
+ sysctl_entry *table, void **context)
{
int error;
repeat:
if (!nlen)
return -ENOTDIR;

- for ( ; table->ctl_name; table++) {
+ for ( ; table; table = table->next) {
if (get_user(name) == table->ctl_name ||
table->ctl_name == CTL_ANY) {
if (table->child) {
@@ -295,7 +338,7 @@
}

/* Perform the actual read/write of a sysctl table entry. */
-int do_sysctl_strategy (ctl_table *table,
+int do_sysctl_strategy (sysctl_entry *table,
int *name, int nlen,
void *oldval, size_t *oldlenp,
void *newval, size_t newlen, void **context)
@@ -343,7 +386,7 @@
* If the tests are successful, the actual change is done by
* do_sysctl_strategy
*/
-static int do_securelevel_strategy (ctl_table *table,
+static int do_securelevel_strategy (sysctl_entry *table,
int *name, int nlen,
void *oldval, size_t *oldlenp,
void *newval, size_t newlen, void **context)
@@ -360,30 +403,84 @@
return 0;
}

-struct ctl_table_header *register_sysctl_table(ctl_table * table,
- int insert_at_head)
+/* Register a new sysctl entry in the correct places. */
+int register_sysctl(sysctl_entry *table, sysctl_entry *entry)
{
- struct ctl_table_header *tmp;
- tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
- if (!tmp)
+ /* Multiple registrations of the same entry are forbidden. */
+ if (entry->parent)
+ return -EBUSY;
+
+ /* Link this entry into the parent sysctl table. */
+ entry->next = table->child;
+ entry->parent = table;
+ table->child = entry;
+
+#ifdef CONFIG_PROC_FS
+ /* We cannot do anything without a proc name. */
+ if (! entry->procname)
return 0;
- *tmp = ((struct ctl_table_header) {table, DNODE_NULL});
- if (insert_at_head)
- DLIST_INSERT_AFTER(&root_table_header, tmp, ctl_entry);
+
+ /* Setup the procfs directory entry for this sysctl entry. */
+ entry->de.namelen = strlen(entry->procname);
+ entry->de.name = entry->procname;
+ entry->de.mode = entry->mode;
+ entry->de.nlink = 1;
+ entry->de.uid = 0;
+ entry->de.gid = 0;
+ entry->de.size = 0;
+ entry->de.get_info = 0; /* For internal use if we want it */
+ entry->de.fill_inode = 0; /* To override struct inode fields */
+ entry->de.next = entry->de.subdir = 0;
+ entry->de.data = (void *) entry;
+ /* Is it a file? */
+ if (entry->proc_handler) {
+ entry->de.ops = &proc_sys_inode_operations;
+ entry->de.mode |= S_IFREG;
+ }
+ /* Otherwise it's a subdir */
+ else {
+ entry->de.ops = &proc_dir_inode_operations;
+ entry->de.nlink++;
+ entry->de.mode |= S_IFDIR;
+ }
+ if (table == &sysctl_root)
+ proc_register_dynamic(&proc_sys_root, &entry->de);
else
- DLIST_INSERT_BEFORE(&root_table_header, tmp, ctl_entry);
-#ifdef CONFIG_PROC_FS
- register_proc_table(table, &proc_sys_root);
-#endif
- return tmp;
+ proc_register_dynamic(&table->de, &entry->de);
+
+#endif /* CONFIG_PROC_FS */
+
+ return 0;
}

-void unregister_sysctl_table(struct ctl_table_header * table)
+/* Remove a sysctl entry from the correct places. */
+int unregister_sysctl(sysctl_entry *table, int ctl_name)
{
- DLIST_DELETE(table, ctl_entry);
+ sysctl_entry **entries = &table->child, *entry;
+
+ while ((entry = *entries) != NULL) {
+ if (entry->ctl_name == ctl_name) {
+ /* All child entries must be unregistered first. */
+ if (entry->child)
+ return -EBUSY;
+
+ /* Unlink this entry from the parent table. */
+ *entries = entry->next;
+ entry->next = entry->parent = NULL;
+
#ifdef CONFIG_PROC_FS
- unregister_proc_table(table->ctl_table, &proc_sys_root);
+ /* Remove this entry from the procfs. */
+ if (table == &sysctl_root)
+ proc_unregister(&proc_sys_root,entry->de.low_ino);
+ else
+ proc_unregister(&table->de,entry->de.low_ino);
#endif
+ return 0;
+ }
+ else
+ entries = &entry->next;
+ }
+ return -EINVAL;
}

/*
@@ -392,76 +489,12 @@

#ifdef CONFIG_PROC_FS

-/* Scan the sysctl entries in table and add them all into /proc */
-static void register_proc_table(ctl_table * table, struct proc_dir_entry *root)
-{
- struct proc_dir_entry *de;
-
- for (; table->ctl_name; table++) {
- /* Can't do anything without a proc name. */
- if (!table->procname)
- continue;
- /* Maybe we can't do anything with it... */
- if (!table->proc_handler &&
- !table->child)
- continue;
-
- de = kmalloc(sizeof(*de), GFP_KERNEL);
- if (!de) continue;
- de->namelen = strlen(table->procname);
- de->name = table->procname;
- de->mode = table->mode;
- de->nlink = 1;
- de->uid = 0;
- de->gid = 0;
- de->size = 0;
- de->get_info = 0; /* For internal use if we want it */
- de->fill_inode = 0; /* To override struct inode fields */
- de->next = de->subdir = 0;
- de->data = (void *) table;
- /* Is it a file? */
- if (table->proc_handler) {
- de->ops = &proc_sys_inode_operations;
- de->mode |= S_IFREG;
- }
- /* Otherwise it's a subdir */
- else {
- de->ops = &proc_dir_inode_operations;
- de->nlink++;
- de->mode |= S_IFDIR;
- }
- table->de = de;
- proc_register_dynamic(root, de);
- if (de->mode & S_IFDIR )
- register_proc_table(table->child, de);
- }
-}
-
-static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root)
-{
- struct proc_dir_entry *de;
- for (; table->ctl_name; table++) {
- if (!(de = table->de))
- continue;
- if (de->mode & S_IFDIR) {
- if (!table->child) {
- printk (KERN_ALERT "Help - malformed sysctl tree on free\n");
- continue;
- }
- unregister_proc_table(table->child, de);
- }
- proc_unregister(root, de->low_ino);
- kfree(de);
- }
-}
-
-
static int do_rw_proc(int write, struct inode * inode, struct file * file,
char * buf, int count)
{
int error, op;
struct proc_dir_entry *de;
- struct ctl_table *table;
+ struct sysctl_entry *table;
size_t res;

error = verify_area(write ? VERIFY_READ : VERIFY_WRITE, buf, count);
@@ -471,7 +504,7 @@
de = (struct proc_dir_entry*) inode->u.generic_ip;
if (!de || !de->data)
return -ENOTDIR;
- table = (struct ctl_table *) de->data;
+ table = (struct sysctl_entry *) de->data;
if (!table || !table->proc_handler)
return -ENOTDIR;
op = (write ? 002 : 004);
@@ -502,7 +535,7 @@
return test_perm(inode->i_mode, op);
}

-int proc_dostring(ctl_table *table, int write, struct file *filp,
+int proc_dostring(sysctl_entry *table, int write, struct file *filp,
void *buffer, size_t *lenp)
{
int len;
@@ -545,7 +578,7 @@
return 0;
}

-int proc_dointvec(ctl_table *table, int write, struct file *filp,
+int proc_dointvec(sysctl_entry *table, int write, struct file *filp,
void *buffer, size_t *lenp)
{
int *i, vleft, first=1, len, left, neg, val;
@@ -620,7 +653,7 @@
return 0;
}

-int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
+int proc_dointvec_minmax(sysctl_entry *table, int write, struct file *filp,
void *buffer, size_t *lenp)
{
int *i, *min, *max, vleft, first=1, len, left, neg, val;
@@ -704,19 +737,19 @@

#else /* CONFIG_PROC_FS */

-int proc_dostring(ctl_table *table, int write, struct file *filp,
+int proc_dostring(sysctl_entry *table, int write, struct file *filp,
void *buffer, size_t *lenp)
{
return -ENOSYS;
}

-int proc_dointvec(ctl_table *table, int write, struct file *filp,
+int proc_dointvec(sysctl_entry *table, int write, struct file *filp,
void *buffer, size_t *lenp)
{
return -ENOSYS;
}

-int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
+int proc_dointvec_minmax(sysctl_entry *table, int write, struct file *filp,
void *buffer, size_t *lenp)
{
return -ENOSYS;
@@ -730,7 +763,7 @@
*/

/* The generic string strategy routine: */
-int sysctl_string(ctl_table *table, int *name, int nlen,
+int sysctl_string(sysctl_entry *table, int *name, int nlen,
void *oldval, size_t *oldlenp,
void *newval, size_t newlen, void **context)
{
@@ -766,7 +799,7 @@
* are between the minimum and maximum values given in the arrays
* table->extra1 and table->extra2, respectively.
*/
-int sysctl_intvec(ctl_table *table, int *name, int nlen,
+int sysctl_intvec(sysctl_entry *table, int *name, int nlen,
void *oldval, size_t *oldlenp,
void *newval, size_t newlen, void **context)
{
--- linux/kernel/ksyms.c- Wed May 15 20:56:39 1996
+++ linux/kernel/ksyms.c Thu May 16 22:13:01 1996
@@ -40,7 +40,6 @@
#include <linux/random.h>
#include <linux/mount.h>
#include <linux/pagemap.h>
-#include <linux/sysctl.h>
#include <linux/hdreg.h>
#include <linux/skbuff.h>
#include <linux/genhd.h>
@@ -226,10 +225,6 @@
X(lookup_exec_domain),
X(register_exec_domain),
X(unregister_exec_domain),
-
- /* sysctl table registration */
- X(register_sysctl_table),
- X(unregister_sysctl_table),

/* interrupt handling */
X(request_irq),
--- linux/include/linux/sysctl.h- Wed May 15 19:50:10 1996
+++ linux/include/linux/sysctl.h Thu May 16 22:02:42 1996
@@ -1,14 +1,19 @@
/*
- * sysctl.h: General linux system control interface
+ * sysctl.h - general system control interface definitions
*
* Begun 24 March 1995, Stephen Tweedie
+ * Rewritten to support dynamic registration by Tom Dyas, May 16, 1996.
*/

-#include <linux/lists.h>
-
#ifndef _LINUX_SYSCTL_H
#define _LINUX_SYSCTL_H

+#include <linux/config.h>
+#include <linux/types.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif
+
#define CTL_MAXNAME 10

struct __sysctl_args {
@@ -59,8 +64,8 @@
#define KERN_REALROOTDEV 16 /* real root device to mount after initrd */
#define KERN_NFSRNAME 17 /* NFS root name */
#define KERN_NFSRADDRS 18 /* NFS root addresses */
-#define KERN_JAVA_INTERPRETER 19 /* path to Java(tm) interpreter */
-#define KERN_JAVA_APPLETVIEWER 20 /* path to Java(tm) appletviewer */
+#define KERN_JAVA_INTERPRETER 19 /* path to Java(tm) interpreter */
+#define KERN_JAVA_APPLETVIEWER 20 /* path to Java(tm) appletviewer */

/* CTL_VM names: */
#define VM_SWAPCTL 1 /* struct: Set vm swapping control */
@@ -109,30 +114,27 @@
#ifdef __KERNEL__

extern asmlinkage int sys_sysctl(struct __sysctl_args *);
-extern void init_sysctl(void);
+extern void sysctl_init(void);

-typedef struct ctl_table ctl_table;
+typedef struct sysctl_entry sysctl_entry;

-typedef int ctl_handler (ctl_table *table, int *name, int nlen,
+typedef int ctl_handler (sysctl_entry *table, int *name, int nlen,
void *oldval, size_t *oldlenp,
void *newval, size_t newlen,
void **context);

-typedef int proc_handler (ctl_table *ctl, int write, struct file * filp,
+typedef int proc_handler (sysctl_entry *ctl, int write, struct file * filp,
void *buffer, size_t *lenp);

-extern int proc_dostring(ctl_table *, int, struct file *,
- void *, size_t *);
-extern int proc_dointvec(ctl_table *, int, struct file *,
- void *, size_t *);
-extern int proc_dointvec_minmax(ctl_table *, int, struct file *,
- void *, size_t *);
+extern proc_handler proc_dostring;
+extern proc_handler proc_dointvec;
+extern proc_handler proc_dointvec_minmax;

extern int do_sysctl (int *name, int nlen,
void *oldval, size_t *oldlenp,
void *newval, size_t newlen);

-extern int do_sysctl_strategy (ctl_table *table,
+extern int do_sysctl_strategy (sysctl_entry *table,
int *name, int nlen,
void *oldval, size_t *oldlenp,
void *newval, size_t newlen, void ** context);
@@ -152,69 +154,78 @@


/*
- * Register a set of sysctl names by calling register_sysctl_table
- * with an initialised array of ctl_table's. An entry with zero
- * ctl_name terminates the table. table->de will be set up by the
- * registration and need not be initialised in advance.
+ * Register a sysctl entry by calling register_sysctl with a pointer
+ * to the initialized struct sysctl_entry and a pointer to the
+ * "table" to place the entry under. See how the standard sysctl entries
+ * are registered in the sysctl.c for the particulars.
*
- * sysctl names can be mirrored automatically under /proc/sys. The
- * procname supplied controls /proc naming.
+ * Sysctl entries can be mirrored automatically under /proc/sys. The
+ * sysctl_entry member "procname" controls /proc naming.
*
- * The table's mode will be honoured both for sys_sysctl(2) and
- * proc-fs access.
+ * The entry's mode will be honoured both for sys_sysctl(2) and
+ * proc-fs access. The mode is checked as if root were the owner
+ * and group of every sysctl_entry.
*
* Leaf nodes in the sysctl tree will be represented by a single file
* under /proc; non-leaf nodes will be represented by directories. A
* null procname disables /proc mirroring at this node.
*
* sysctl(2) can automatically manage read and write requests through
- * the sysctl table. The data and maxlen fields of the ctl_table
+ * the sysctl table. The data and maxlen fields of the sysctl_entry
* struct enable minimal validation of the values being written to be
* performed, and the mode field allows minimal authentication.
*
* More sophisticated management can be enabled by the provision of a
- * strategy routine with the table entry. This will be called before
+ * strategy routine with the sysctl entry. This will be called before
* any automatic read or write of the data is performed.
*
* The strategy routine may return:
- * <0: Error occurred (error is passed to user process)
- * 0: OK - proceed with automatic read or write.
- * >0: OK - read or write has been done by the strategy routine, so
- * return immediately.
+ * <0: Error occurred (error is passed to user process)
+ * 0: OK - proceed with automatic read or write.
+ * >0: OK - read or write has been done by the strategy routine, so
+ * return immediately.
*
* There must be a proc_handler routine for any terminal nodes
* mirrored under /proc/sys (non-terminals are handled by a built-in
- * directory handler). Several default handlers are available to
- * cover common cases.
+ * directory handler). Several default handlers are available to
+ * cover common cases. Again, read sysctl.c for more information.
*/

-/* A sysctl table is an array of struct ctl_table: */
-struct ctl_table
+/* A sysctl table is a linked list of struct sysctl_entry's. */
+struct sysctl_entry
{
+ /* Binary and textual identifiers. */
int ctl_name; /* Binary ID */
const char *procname; /* Text ID for /proc/sys, or zero */
+
+ /* Location and permissions of the data. */
void *data;
int maxlen;
mode_t mode;
- ctl_table *child;
+
+ /* Callbacks for proc filesystem and reading/writing. */
proc_handler *proc_handler; /* Callback for text formatting */
ctl_handler *strategy; /* Callback function for all r/w */
- struct proc_dir_entry *de; /* /proc control block */
void *extra1;
void *extra2;
-};

-/* struct ctl_table_header is used to maintain dynamic lists of
- ctl_table trees. */
-struct ctl_table_header
-{
- ctl_table *ctl_table;
- DLNODE(struct ctl_table_header) ctl_entry;
+ /* Links to other sysctl entries in the hierarchy and procfs.
+ * Let (un)register_sysctl deal with this stuff ...
+ */
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry de; /* /proc control block */
+#endif
+ sysctl_entry *parent, *next, *child;
};

-struct ctl_table_header * register_sysctl_table(ctl_table * table,
- int insert_at_head);
-void unregister_sysctl_table(struct ctl_table_header * table);
+int register_sysctl(sysctl_entry * table, sysctl_entry *entry);
+int unregister_sysctl(sysctl_entry *table, int ctl_name);
+
+/* Standard top-level sysctl entries. */
+extern sysctl_entry sysctl_root;
+extern sysctl_entry sysctl_kern;
+extern sysctl_entry sysctl_vm;
+extern sysctl_entry sysctl_net;

#else /* __KERNEL__ */

--- linux/include/asm-i386/unistd.h- Thu May 16 21:38:14 1996
+++ linux/include/asm-i386/unistd.h Thu May 16 21:38:36 1996
@@ -145,16 +145,16 @@
#define __NR_afs_syscall 137 /* Syscall for Andrew File System */
#define __NR_setfsuid 138
#define __NR_setfsgid 139
-#define __NR__llseek 140
+#define __NR_llseek 140
#define __NR_getdents 141
-#define __NR__newselect 142
+#define __NR_newselect 142
#define __NR_flock 143
#define __NR_msync 144
#define __NR_readv 145
#define __NR_writev 146
#define __NR_getsid 147
#define __NR_fdatasync 148
-#define __NR__sysctl 149
+#define __NR_sysctl 149
#define __NR_mlock 150
#define __NR_munlock 151
#define __NR_mlockall 152
--- linux/include/asm/unistd.h- Thu May 16 21:38:14 1996
+++ linux/include/asm/unistd.h Thu May 16 21:38:36 1996
@@ -145,16 +145,16 @@
#define __NR_afs_syscall 137 /* Syscall for Andrew File System */
#define __NR_setfsuid 138
#define __NR_setfsgid 139
-#define __NR__llseek 140
+#define __NR_llseek 140
#define __NR_getdents 141
-#define __NR__newselect 142
+#define __NR_newselect 142
#define __NR_flock 143
#define __NR_msync 144
#define __NR_readv 145
#define __NR_writev 146
#define __NR_getsid 147
#define __NR_fdatasync 148
-#define __NR__sysctl 149
+#define __NR_sysctl 149
#define __NR_mlock 150
#define __NR_munlock 151
#define __NR_mlockall 152
--- linux/net/unix/sysctl_net_unix.c- Thu May 16 22:32:21 1996
+++ linux/net/unix/sysctl_net_unix.c Thu May 16 22:33:06 1996
@@ -8,6 +8,4 @@
#include <linux/mm.h>
#include <linux/sysctl.h>

-ctl_table unix_table[] = {
- {0}
-};
+sysctl_entry sysctl_net_unix = { NET_UNIX, "unix", NULL, 0, 0555 };
--- linux/net/802/sysctl_net_802.c- Thu May 16 22:35:18 1996
+++ linux/net/802/sysctl_net_802.c Thu May 16 22:36:07 1996
@@ -8,6 +8,4 @@
#include <linux/mm.h>
#include <linux/sysctl.h>

-ctl_table e802_table[] = {
- {0}
-};
+sysctl_entry sysctl_net_802 = { NET_802, "802", NULL, 0, 0555 };
--- linux/net/appletalk/sysctl_net_atalk.c- Thu May 16 22:39:51 1996
+++ linux/net/appletalk/sysctl_net_atalk.c Thu May 16 22:40:27 1996
@@ -8,6 +8,4 @@
#include <linux/mm.h>
#include <linux/sysctl.h>

-ctl_table atalk_table[] = {
- {0}
-};
+sysctl_entry sysctl_net_atalk = { NET_ATALK, "appletalk", NULL, 0, 0555 };
--- linux/net/ax25/sysctl_net_ax25.c- Thu May 16 22:41:42 1996
+++ linux/net/ax25/sysctl_net_ax25.c Thu May 16 22:42:06 1996
@@ -8,6 +8,4 @@
#include <linux/mm.h>
#include <linux/sysctl.h>

-ctl_table ax25_table[] = {
- {0}
-};
+sysctl_entry sysctl_net_ax25 = { NET_AX25, "ax25", NULL, 0, 0555 };
--- linux/net/core/sysctl_net_core.c- Thu May 16 22:30:42 1996
+++ linux/net/core/sysctl_net_core.c Thu May 16 22:33:25 1996
@@ -8,6 +8,4 @@
#include <linux/mm.h>
#include <linux/sysctl.h>

-ctl_table core_table[] = {
- {0}
-};
+sysctl_entry sysctl_net_core = { NET_CORE, "core", NULL, 0, 0555 };
--- linux/net/ethernet/sysctl_net_ether.c- Thu May 16 22:36:22 1996
+++ linux/net/ethernet/sysctl_net_ether.c Thu May 16 22:37:12 1996
@@ -8,6 +8,4 @@
#include <linux/mm.h>
#include <linux/sysctl.h>

-ctl_table ether_table[] = {
- {0}
-};
+sysctl_entry sysctl_net_ethernet = { NET_ETHER, "ethernet", NULL, 0, 0555 };
--- linux/net/ipv4/sysctl_net_ipv4.c- Thu May 16 22:37:46 1996
+++ linux/net/ipv4/sysctl_net_ipv4.c Thu May 16 22:38:37 1996
@@ -8,6 +8,4 @@
#include <linux/mm.h>
#include <linux/sysctl.h>

-ctl_table ipv4_table[] = {
- {0}
-};
+sysctl_entry sysctl_net_ipv4 = { NET_IPV4, "ipv4", NULL, 0, 0555 };
--- linux/net/ipx/sysctl_net_ipx.c- Thu May 16 22:38:47 1996
+++ linux/net/ipx/sysctl_net_ipx.c Thu May 16 22:39:12 1996
@@ -8,6 +8,4 @@
#include <linux/mm.h>
#include <linux/sysctl.h>

-ctl_table ipx_table[] = {
- {0}
-};
+sysctl_entry sysctl_net_ipx = { NET_IPX, "ipx", NULL, 0, 0555 };
--- linux/net/netrom/sysctl_net_netrom.c- Thu May 16 22:40:38 1996
+++ linux/net/netrom/sysctl_net_netrom.c Thu May 16 22:41:07 1996
@@ -8,6 +8,4 @@
#include <linux/mm.h>
#include <linux/sysctl.h>

-ctl_table netrom_table[] = {
- {0}
-};
+sysctl_entry sysctl_net_netrom = { NET_NETROM, "netrom", NULL, 0, 0555 };
--- linux/net/sysctl_net.c- Thu May 16 22:27:04 1996
+++ linux/net/sysctl_net.c Thu May 16 22:43:45 1996
@@ -10,52 +10,55 @@
#include <linux/sysctl.h>

#ifdef CONFIG_INET
-extern ctl_table ipv4_table[];
+extern sysctl_entry sysctl_net_ipv4;
#endif

#ifdef CONFIG_IPX
-extern ctl_table ipx_table[];
+extern sysctl_entry sysctl_net_ipx;
#endif

#ifdef CONFIG_ATALK
-extern ctl_table atalk_table[];
+extern sysctl_entry sysctl_net_atalk;
#endif

#ifdef CONFIG_NETROM
-extern ctl_table netrom_table[];
+extern sysctl_entry sysctl_net_netrom;
#endif

#ifdef CONFIG_AX25
-extern ctl_table ax25_table[];
+extern sysctl_entry sysctl_net_ax25;
#endif

-extern ctl_table core_table[], unix_table[];
+extern sysctl_entry sysctl_net_core, sysctl_net_unix;

#ifdef CONFIG_NET
-extern ctl_table ether_table[], e802_table[];
+extern sysctl_entry sysctl_net_ethernet, sysctl_net_802;
#endif

-ctl_table net_table[] = {
- {NET_CORE, "core", NULL, 0, 0555, core_table},
- {NET_UNIX, "unix", NULL, 0, 0555, unix_table},
+sysctl_entry sysctl_net = { CTL_NET, "net", NULL, 0, 0555 };
+
+void register_net_sysctls(void)
+{
+ register_sysctl(&sysctl_root,&sysctl_net);
+ register_sysctl(&sysctl_net,&sysctl_net_core);
+ register_sysctl(&sysctl_net,&sysctl_net_unix);
#ifdef CONFIG_NET
- {NET_802, "802", NULL, 0, 0555, e802_table},
- {NET_ETHER, "ethernet", NULL, 0, 0555, ether_table},
+ register_sysctl(&sysctl_net,&sysctl_net_802);
+ register_sysctl(&sysctl_net,&sysctl_net_ethernet);
#endif
#ifdef CONFIG_INET
- {NET_IPV4, "ipv4", NULL, 0, 0555, ipv4_table},
+ register_sysctl(&sysctl_net,&sysctl_net_ipv4);
#endif
#ifdef CONFIG_IPX
- {NET_IPX, "ipx", NULL, 0, 0555, ipx_table},
+ register_sysctl(&sysctl_net,&sysctl_net_ipx);
#endif
#ifdef CONFIG_ATALK
- {NET_ATALK, "appletalk", NULL, 0, 0555, atalk_table},
+ register_sysctl(&sysctl_net,&sysctl_net_atalk);
#endif
#ifdef CONFIG_NETROM
- {NET_NETROM, "netrom", NULL, 0, 0555, netrom_table},
+ register_sysctl(&sysctl_net,&sysctl_net_netrom);
#endif
#ifdef CONFIG_AX25
- {NET_AX25, "ax25", NULL, 0, 0555, ax25_table},
+ register_sysctl(&sysctl_net,&sysctl_net_ax25);
#endif
- {0}
-};
+}
--- linux/net/socket.c- Thu May 16 22:43:55 1996
+++ linux/net/socket.c Thu May 16 22:44:47 1996
@@ -80,6 +80,8 @@
extern void export_net_symbols(void);
#endif

+extern void register_net_sysctls(void);
+
static int sock_lseek(struct inode *inode, struct file *file, off_t offset,
int whence);
static int sock_read(struct inode *inode, struct file *file, char *buf,
@@ -1441,6 +1443,7 @@
#if defined(CONFIG_MODULES) && defined(CONFIG_NET)
export_net_symbols();
#endif
+ register_net_sysctls();
}

int socket_get_info(char *buffer, char **start, off_t offset, int length)