X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;ds=sidebyside;f=ipc%2Fipc_sysctl.c;h=7d3704750efc1fd7ef9010acc20fcf2b76e14a28;hb=8d65af789f3e2cf4cfbdbf71a0f7a61ebcd41d38;hp=79e24e878c1eae6d2dc1247f72dec8de71ce2108;hpb=a08b4be74ca4199838cbb03d90906a0fd70d3b3c;p=safe%2Fjmp%2Flinux-2.6 diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c index 79e24e8..7d37047 100644 --- a/ipc/ipc_sysctl.c +++ b/ipc/ipc_sysctl.c @@ -14,6 +14,9 @@ #include #include #include +#include +#include +#include "util.h" static void *get_ipc(ctl_table *table) { @@ -23,36 +26,112 @@ static void *get_ipc(ctl_table *table) return which; } -#ifdef CONFIG_PROC_FS -static int proc_ipc_dointvec(ctl_table *table, int write, struct file *filp, +#ifdef CONFIG_PROC_SYSCTL +static int proc_ipc_dointvec(ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { struct ctl_table ipc_table; memcpy(&ipc_table, table, sizeof(ipc_table)); ipc_table.data = get_ipc(table); - return proc_dointvec(&ipc_table, write, filp, buffer, lenp, ppos); + return proc_dointvec(&ipc_table, write, buffer, lenp, ppos); +} + +static int proc_ipc_callback_dointvec(ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + struct ctl_table ipc_table; + size_t lenp_bef = *lenp; + int rc; + + memcpy(&ipc_table, table, sizeof(ipc_table)); + ipc_table.data = get_ipc(table); + + rc = proc_dointvec(&ipc_table, write, buffer, lenp, ppos); + + if (write && !rc && lenp_bef == *lenp) + /* + * Tunable has successfully been changed by hand. Disable its + * automatic adjustment. This simply requires unregistering + * the notifiers that trigger recalculation. + */ + unregister_ipcns_notifier(current->nsproxy->ipc_ns); + + return rc; } static int proc_ipc_doulongvec_minmax(ctl_table *table, int write, - struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos) + void __user *buffer, size_t *lenp, loff_t *ppos) { struct ctl_table ipc_table; memcpy(&ipc_table, table, sizeof(ipc_table)); ipc_table.data = get_ipc(table); - return proc_doulongvec_minmax(&ipc_table, write, filp, buffer, + return proc_doulongvec_minmax(&ipc_table, write, buffer, lenp, ppos); } +/* + * Routine that is called when the file "auto_msgmni" has successfully been + * written. + * Two values are allowed: + * 0: unregister msgmni's callback routine from the ipc namespace notifier + * chain. This means that msgmni won't be recomputed anymore upon memory + * add/remove or ipc namespace creation/removal. + * 1: register back the callback routine. + */ +static void ipc_auto_callback(int val) +{ + if (!val) + unregister_ipcns_notifier(current->nsproxy->ipc_ns); + else { + /* + * Re-enable automatic recomputing only if not already + * enabled. + */ + recompute_msgmni(current->nsproxy->ipc_ns); + cond_register_ipcns_notifier(current->nsproxy->ipc_ns); + } +} + +static int proc_ipcauto_dointvec_minmax(ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + struct ctl_table ipc_table; + size_t lenp_bef = *lenp; + int oldval; + int rc; + + memcpy(&ipc_table, table, sizeof(ipc_table)); + ipc_table.data = get_ipc(table); + oldval = *((int *)(ipc_table.data)); + + rc = proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos); + + if (write && !rc && lenp_bef == *lenp) { + int newval = *((int *)(ipc_table.data)); + /* + * The file "auto_msgmni" has correctly been set. + * React by (un)registering the corresponding tunable, if the + * value has changed. + */ + if (newval != oldval) + ipc_auto_callback(newval); + } + + return rc; +} + #else #define proc_ipc_doulongvec_minmax NULL #define proc_ipc_dointvec NULL +#define proc_ipc_callback_dointvec NULL +#define proc_ipcauto_dointvec_minmax NULL #endif #ifdef CONFIG_SYSCTL_SYSCALL /* The generic sysctl ipc data routine. */ -static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen, +static int sysctl_ipc_data(ctl_table *table, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen) { @@ -89,10 +168,31 @@ static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen, } return 1; } + +static int sysctl_ipc_registered_data(ctl_table *table, + void __user *oldval, size_t __user *oldlenp, + void __user *newval, size_t newlen) +{ + int rc; + + rc = sysctl_ipc_data(table, oldval, oldlenp, newval, newlen); + + if (newval && newlen && rc > 0) + /* + * Tunable has successfully been changed from userland + */ + unregister_ipcns_notifier(current->nsproxy->ipc_ns); + + return rc; +} #else #define sysctl_ipc_data NULL +#define sysctl_ipc_registered_data NULL #endif +static int zero; +static int one = 1; + static struct ctl_table ipc_kern_table[] = { { .ctl_name = KERN_SHMMAX, @@ -136,8 +236,8 @@ static struct ctl_table ipc_kern_table[] = { .data = &init_ipc_ns.msg_ctlmni, .maxlen = sizeof (init_ipc_ns.msg_ctlmni), .mode = 0644, - .proc_handler = proc_ipc_dointvec, - .strategy = sysctl_ipc_data, + .proc_handler = proc_ipc_callback_dointvec, + .strategy = sysctl_ipc_registered_data, }, { .ctl_name = KERN_MSGMNB, @@ -157,6 +257,16 @@ static struct ctl_table ipc_kern_table[] = { .proc_handler = proc_ipc_dointvec, .strategy = sysctl_ipc_data, }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "auto_msgmni", + .data = &init_ipc_ns.auto_msgmni, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_ipcauto_dointvec_minmax, + .extra1 = &zero, + .extra2 = &one, + }, {} };