sysctl: Factor out sysctl_data.
There as been no easy way to wrap the default sysctl strategy routine except for returning 0. Which is not always what we want. The few instances I have seen that want different behaviour have written their own version of sysctl_data. While not too hard it is unnecessary code and has the potential for extra bugs. So to make these situations easier and make that part of sysctl more symetric I have factord sysctl_data out of do_sysctl_strategy and exported as a function everyone can use. Further having sysctl_data be an explicit function makes checking for badly formed sysctl tables much easier. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Cc: Alexey Dobriyan <adobriyan@sw.ru> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
d8217f076b
commit
49a0c45833
|
@ -972,6 +972,7 @@ extern int do_sysctl_strategy (struct ctl_table *table,
|
|||
void __user *oldval, size_t __user *oldlenp,
|
||||
void __user *newval, size_t newlen);
|
||||
|
||||
extern ctl_handler sysctl_data;
|
||||
extern ctl_handler sysctl_string;
|
||||
extern ctl_handler sysctl_intvec;
|
||||
extern ctl_handler sysctl_jiffies;
|
||||
|
|
|
@ -1443,7 +1443,6 @@ int do_sysctl_strategy (struct ctl_table *table,
|
|||
void __user *newval, size_t newlen)
|
||||
{
|
||||
int op = 0, rc;
|
||||
size_t len;
|
||||
|
||||
if (oldval)
|
||||
op |= 004;
|
||||
|
@ -1464,25 +1463,10 @@ int do_sysctl_strategy (struct ctl_table *table,
|
|||
/* If there is no strategy routine, or if the strategy returns
|
||||
* zero, proceed with automatic r/w */
|
||||
if (table->data && table->maxlen) {
|
||||
if (oldval && oldlenp) {
|
||||
if (get_user(len, oldlenp))
|
||||
return -EFAULT;
|
||||
if (len) {
|
||||
if (len > table->maxlen)
|
||||
len = table->maxlen;
|
||||
if(copy_to_user(oldval, table->data, len))
|
||||
return -EFAULT;
|
||||
if(put_user(len, oldlenp))
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
if (newval && newlen) {
|
||||
len = newlen;
|
||||
if (len > table->maxlen)
|
||||
len = table->maxlen;
|
||||
if(copy_from_user(table->data, newval, len))
|
||||
return -EFAULT;
|
||||
}
|
||||
rc = sysctl_data(table, name, nlen, oldval, oldlenp,
|
||||
newval, newlen);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -2381,6 +2365,40 @@ int proc_doulongvec_ms_jiffies_minmax(struct ctl_table *table, int write,
|
|||
* General sysctl support routines
|
||||
*/
|
||||
|
||||
/* The generic sysctl data routine (used if no strategy routine supplied) */
|
||||
int sysctl_data(struct ctl_table *table, int __user *name, int nlen,
|
||||
void __user *oldval, size_t __user *oldlenp,
|
||||
void __user *newval, size_t newlen)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
/* Get out of I don't have a variable */
|
||||
if (!table->data || !table->maxlen)
|
||||
return -ENOTDIR;
|
||||
|
||||
if (oldval && oldlenp) {
|
||||
if (get_user(len, oldlenp))
|
||||
return -EFAULT;
|
||||
if (len) {
|
||||
if (len > table->maxlen)
|
||||
len = table->maxlen;
|
||||
if (copy_to_user(oldval, table->data, len))
|
||||
return -EFAULT;
|
||||
if (put_user(len, oldlenp))
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
if (newval && newlen) {
|
||||
if (newlen > table->maxlen)
|
||||
newlen = table->maxlen;
|
||||
|
||||
if (copy_from_user(table->data, newval, newlen))
|
||||
return -EFAULT;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* The generic string strategy routine: */
|
||||
int sysctl_string(struct ctl_table *table, int __user *name, int nlen,
|
||||
void __user *oldval, size_t __user *oldlenp,
|
||||
|
@ -2569,6 +2587,13 @@ out:
|
|||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int sysctl_data(struct ctl_table *table, int __user *name, int nlen,
|
||||
void __user *oldval, size_t __user *oldlenp,
|
||||
void __user *newval, size_t newlen)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int sysctl_string(struct ctl_table *table, int __user *name, int nlen,
|
||||
void __user *oldval, size_t __user *oldlenp,
|
||||
void __user *newval, size_t newlen)
|
||||
|
@ -2616,4 +2641,5 @@ EXPORT_SYMBOL(sysctl_intvec);
|
|||
EXPORT_SYMBOL(sysctl_jiffies);
|
||||
EXPORT_SYMBOL(sysctl_ms_jiffies);
|
||||
EXPORT_SYMBOL(sysctl_string);
|
||||
EXPORT_SYMBOL(sysctl_data);
|
||||
EXPORT_SYMBOL(unregister_sysctl_table);
|
||||
|
|
Loading…
Reference in New Issue