* Warning: This patch is a prototype and is NOT tested. * Signed-off-by: Amit Gud --- --- kernel/sysctl.c.orig 2006-07-20 16:56:09.000000000 -0400 +++ kernel/sysctl.c 2006-07-20 19:33:18.000000000 -0400 @@ -133,6 +133,9 @@ extern int no_unaligned_warning; static int parse_table(int __user *, int, void __user *, size_t __user *, void __user *, size_t, ctl_table *, void **); +static void check_pending_values(ctl_table *); +static void store_pending_val(int, void *, size_t); +static void init_pending_value_table(); static int proc_doutsstring(ctl_table *table, int write, struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos); @@ -158,6 +161,23 @@ extern ctl_table inotify_table[]; int sysctl_legacy_va_layout; #endif +/* struct ctl_pending_values is used for temporarily storing data values + for the entries which are not found at the _sysctl(2) time. This is + useful for the modules which are required to use the values stored + in /etc/sysctl.conf. During regiter_sysctl_table() these ctl_names + are checked against the ctl_names that are being registered and + 'strategy' and 'proc_handler' is called if previous entry is found. */ +#define NR_TEMP_VALUES 32 /* temporary storage for the data for unmatched ctl_names */ + +struct ctl_pending_val_s { + int name; + void *data; + size_t len; +} ctl_pending_values[NR_TEMP_VALUES]; + +static int ctl_index = 0; +spinlock_t ctl_pending_lock = SPIN_LOCK_UNLOCKED; + /* /proc declarations: */ #ifdef CONFIG_PROC_FS @@ -1099,12 +1119,20 @@ static void start_unregistering(struct c list_del_init(&p->ctl_entry); } +static void init_pending_value_table() +{ + int i; + for(i = 0; i < NR_TEMP_VALUES; i++) + ctl_pending_values[i].name = 0; +} + void __init sysctl_init(void) { #ifdef CONFIG_PROC_FS register_proc_table(root_table, proc_sys_root, &root_table_header); init_irq_proc(); #endif + init_pending_value_table(); } int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, @@ -1186,6 +1214,20 @@ static inline int ctl_perm(ctl_table *ta return test_perm(table->mode, op); } +static void store_pending_val(int n, void *newval, size_t newlen) +{ + spin_lock(&ctl_pending_lock); + kfree(ctl_pending_values[ctl_index].data); + + ctl_pending_values[ctl_index].name = n; + ctl_pending_values[ctl_index].data = kmalloc(newlen, GFP_ATOMIC); + memcpy(ctl_pending_values[ctl_index].data, newval, newlen); + ctl_pending_values[ctl_index].len = newlen; + + ctl_index = (++ctl_index % NR_TEMP_VALUES); + spin_unlock(&ctl_pending_lock); +} + static int parse_table(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen, @@ -1222,9 +1264,26 @@ repeat: return error; } } + store_pending_val(n, newval, newlen); return -ENOTDIR; } +static void check_pending_values(ctl_table *table) +{ + int i; + spin_lock(&ctl_pending_lock); + for(i = 0; i < NR_TEMP_VALUES; i++) { + int error; + void *context = NULL; + error = parse_table(&ctl_pending_values[i].name, 1, 0, 0, ctl_pending_values[i].data, + ctl_pending_values[i].len, table, &context); + kfree(context); + if(!error) + ctl_pending_values[i].name = 0; + } + spin_unlock(&ctl_pending_lock); +} + /* Perform the actual read/write of a sysctl table entry. */ int do_sysctl_strategy (ctl_table *table, int __user *name, int nlen, @@ -1365,6 +1424,7 @@ struct ctl_table_header *register_sysctl #ifdef CONFIG_PROC_FS register_proc_table(table, proc_sys_root, tmp); #endif + check_pending_values(table); return tmp; }