lkml.org 
[lkml]   [2003]   [Jul]   [10]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[PATCH/RFC] Deprecate sysctl(2), add sysctl_name

Hi,

I know I am a bit late with this. But I hope it can be done for 2.6.

I want to deprecate the numerical sysctl interface for 2.6. The numerical
name space always a bad design and never particularly stable
(e.g. most distribution kernels assigned freely new numbers so you cannot
really rely on it). There are a lot of duplicated and moved sysctls
around now. It's not a stable ABI.

Also near all people just use /proc/sys to change sysctls. The
sysctl.h/sysctl.c file were always one of the number one
sources of rejections when merging different trees.
I don't see the point in having a hard to maintain numerical name space
for this when there is a perfectly good symbolic name space.

This patch deprecates sysctl(2) by adding a printk to it. There is one
important user of it - glibc checks kernel.version in the startup code -
which is still handled without message. This needs to be still handled,
but the hope is that there are no other users of the numerical interface.

With the deprecation it can be hopefully removed for 2.8 except for a small
stub to emulate kernel.version for old binaries.

If there are any real others users of the numerical namespace we will
soon know, but I consider it unlikely.

The primary interface is /proc/sys now. This was always the most widely
used way to change sysctl. However there were some objections that embedded
systems don't want to have /proc mounted due to memory usage. To offer
them an alternative I added a new sysctl_name(2) system call.
It has the same semantics as the existing sysctl(2), except that
it takes a string instead of a list of numbers to specify the
Unlike /proc sysctl_name has low memory overhead (no dentries, no inodes)
etc. Still it likely is only useful for embedded users, everybody else
should just use /proc/sys.

I hope in 2.7 the internal implementation can be replaced by something
based on ELF segments, so that the central sysctl.c file can go away
and declaring sysctls will be finally easy. There already is an replacement
for it (include/linux/moduleparam.h), but it seems to be not widely used
yet. It unfortunately is a bit bloated, which makes it not nice to use
for everything.

I also added an compat interface for 64bit architectures with 32bit
emulation.

Please consider adding,

-Andi


--- linux-2.5/include/linux/sysctl.h 2003-06-06 17:55:40.000000000 +0200
+++ linux-2.5-amd64/include/linux/sysctl.h 2003-07-09 23:15:45.000000000 +0200
@@ -6,16 +6,10 @@
****************************************************************
****************************************************************
**
- ** WARNING:
** The values in this file are exported to user space via
- ** the sysctl() binary interface. Do *NOT* change the
- ** numbering of any existing values here, and do not change
- ** any numbers within any one set of values. If you have
- ** to redefine an existing interface, use a new number for it.
- ** The kernel will then return ENOTDIR to any application using
- ** the old binary interface.
- **
- ** --sct
+ ** the sysctl() binary interface. However this interface
+ ** is unstable and deprecated and will be removed in the future.
+ ** For a stable interface use /proc/sys.
**
****************************************************************
****************************************************************
--- linux-2.5/kernel/sysctl.c 2003-07-04 23:52:20.000000000 +0200
+++ linux-2.5-amd64/kernel/sysctl.c 2003-07-11 03:25:18.000000000 +0200
@@ -35,6 +35,7 @@
#include <linux/writeback.h>
#include <linux/hugetlb.h>
#include <linux/security.h>
+#include <linux/compat.h>
#include <asm/uaccess.h>

#ifdef CONFIG_ROOT_NFS
@@ -106,6 +107,10 @@

static int parse_table(int __user *, int, void __user *, size_t __user *, void __user *, size_t,
ctl_table *, void **);
+static int parse_table_name(char *name,
+ void __user *oldval, size_t *oldlenp,
+ void __user *newval, size_t newlen,
+ ctl_table *table, void **context);
static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp);

@@ -823,7 +838,16 @@

if (copy_from_user(&tmp, args, sizeof(tmp)))
return -EFAULT;
-
+
+ if (tmp.nlen != 2 || tmp.name[0] != CTL_KERN ||
+ tmp.name[1] != KERN_VERSION) {
+ int i;
+ printk(KERN_INFO "%s: numerical sysctl ", current->comm);
+ for (i = 0; i < tmp.nlen; i++)
+ printk("%d ", tmp.name[i]);
+ printk("is obsolete.\n");
+ }
+
lock_kernel();
error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp,
tmp.newval, tmp.newlen);
@@ -831,6 +855,76 @@
return error;
}

+/*
+ * Symbolic name space access for sysctl.
+ * /proc/sys is the better interface really, this is just for people with
+ * not enough memory for /proc.
+ */
+asmlinkage long sys_sysctl_name(char __user *username,
+ void __user *oldval, unsigned long *oldlenp,
+ void __user *newval, unsigned long newlen)
+{
+ struct list_head *node;
+ char *name = getname(username);
+ int err = PTR_ERR(name);
+ if (IS_ERR(name))
+ return err;
+ lock_kernel();
+ node = &root_table_header.ctl_entry;
+ do {
+ struct ctl_table_header *tbl =
+ list_entry(node, struct ctl_table_header, ctl_entry);
+ void *context = NULL;
+ err = parse_table_name(name, oldval, oldlenp, newval, newlen,
+ tbl->ctl_table, &context);
+ if (context)
+ kfree(context);
+ if (err != -ENOTDIR)
+ break;
+ node = node->next;
+ } while (node != &root_table_header.ctl_entry);
+ unlock_kernel();
+ putname(name);
+ return err;
+}
+
+#ifdef CONFIG_COMPAT
+asmlinkage long compat_sysctl_name(char __user *username,
+ void __user *coldval, compat_size_t *coldlenp,
+ void __user *cnewval, unsigned long newlen)
+{
+ unsigned long oldlen;
+ char *name;
+ int err;
+ void *newval, *oldval;
+ mm_segment_t oldfs;
+
+ if (get_user(oldlen, coldlenp))
+ return -EFAULT;
+
+ oldval = compat_alloc_user_space(oldlen + newlen);
+ newval = oldval + oldlen;
+ if (copy_in_user(newval, cnewval, newlen))
+ return -EFAULT;
+
+ name = getname(username);
+ err = PTR_ERR(name);
+ if (IS_ERR(name))
+ return err;
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ err = sys_sysctl_name(name, oldval, &oldlen, newval, newlen);
+ set_fs(oldfs);
+ putname(name);
+ if (err)
+ return err;
+ if (copy_in_user(coldval, oldval, oldlen))
+ return -EFAULT;
+ return put_user(oldlen, coldlenp);
+}
+#endif
+
/*
* ctl_perm does NOT grant the superuser all rights automatically, because
* some sysctl variables are readonly even to root.
@@ -895,6 +989,42 @@
return -ENOTDIR;
}

+static int parse_table_name(char *name,
+ void __user *oldval, size_t __user *oldlenp,
+ void __user *newval, size_t __user newlen,
+ ctl_table *table, void **context)
+{
+ int error;
+ char *s;
+repeat:
+ s = strsep(&name, "./");
+ for ( ; table->procname; table++) {
+ if (strcmp(s, table->procname))
+ continue;
+ if (table->child) {
+ if (ctl_perm(table, 001))
+ return -EPERM;
+ if (table->strategy) {
+ /* We don't bother passing name down. None of the
+ existing strategy functions use it. */
+ error = table->strategy(
+ table, NULL, 0,
+ oldval, oldlenp,
+ newval, newlen, context);
+ if (error)
+ return error;
+ }
+ table = table->child;
+ goto repeat;
+ }
+ error = do_sysctl_strategy(table, NULL, 0,
+ oldval, oldlenp,
+ newval, newlen, context);
+ return error;
+ }
+ return -ENOTDIR;
+}
+
/* Perform the actual read/write of a sysctl table entry. */
int do_sysctl_strategy (ctl_table *table,
int __user *name, int nlen,
--- linux-2.5/include/asm-i386/unistd.h 2003-07-09 22:50:06.000000000 +0200
+++ linux-2.5-amd64/include/asm-i386/unistd.h 2003-07-10 13:10:05.000000000 +0200
@@ -276,8 +276,9 @@
#define __NR_statfs64 268
#define __NR_fstatfs64 269
#define __NR_tgkill 270
+#define __NR_sysctl_name 271

-#define NR_syscalls 271
+#define NR_syscalls 272

/* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */

--- linux-2.5/arch/i386/kernel/entry.S 2003-07-09 22:49:57.000000000 +0200
+++ linux-2.5-amd64/arch/i386/kernel/entry.S 2003-07-10 13:09:43.000000000 +0200
@@ -877,5 +877,6 @@
.long sys_statfs64
.long sys_fstatfs64
.long sys_tgkill
-
+ .long sys_sysctl_name
+
nr_syscalls=(.-sys_call_table)/4
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
\
 
 \ /
  Last update: 2005-03-22 13:46    [from the cache]
©2003-2011 Jasper Spaans