LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
From: "Eric W. Biederman" <ebiederm@xmission.com>
To: "<Andrew Morton" <akpm@osdl.org>
Cc: <linux-kernel@vger.kernel.org>, <containers@lists.osdl.org>,
<netdev@vger.kernel.org>,
xfs-masters@oss.sgi.com, xfs@oss.sgi.com,
linux-scsi@vger.kernel.org, James.Bottomley@SteelEye.com,
minyard@acm.org, openipmi-developer@lists.sourceforge.net,
<tony.luck@intel.com>,
linux-mips@linux-mips.org, ralf@linux-mips.org,
schwidefsky@de.ibm.com, heiko.carstens@de.ibm.com,
linux390@de.ibm.com, linux-390@vm.marist.edu, paulus@samba.org,
linuxppc-dev@ozlabs.org, lethal@linux-sh.org,
linuxsh-shmedia-dev@lists.sourceforge.net, <ak@suse.de>,
vojtech@suse.cz, clemens@ladisch.de, a.zummo@towertech.it,
rtc-linux@googlegroups.com, linux-parport@lists.infradead.org,
andrea@suse.de, tim@cyberelk.net, philb@gnu.org,
aharkes@cs.cmu.edu, coda@cs.cmu.edu,
codalist@TELEMANN.coda.cs.cmu.edu, aia21@cantab.net,
linux-ntfs-dev@lists.sourceforge.net, mark.fasheh@oracle.com,
kurt.hackel@oracle.com,
"Eric W. Biederman" <ebiederm@xmission.com>
Subject: [PATCH 58/59] sysctl: Reimplement the sysctl proc support
Date: Tue, 16 Jan 2007 09:40:03 -0700 [thread overview]
Message-ID: <11689657073389-git-send-email-ebiederm@xmission.com> (raw)
In-Reply-To: <m1ac0jc4no.fsf@ebiederm.dsl.xmission.com>
From: Eric W. Biederman <ebiederm@xmission.com> - unquoted
With this change the sysctl inodes can be cached and
nothing needs to be done when removing a sysctl table.
For a costk of 2K code we will save about 4K of static tables
(when we remove de from ctl_table) and 70K in proc_dir_entries
that we will not allocate, or about half that on a 32bit arch.
The speed feels about the same, even though we can now cache
the sysctl dentries :(
We get the core advantage that we don't need to have a
1 to 1 mapping between ctl table entries and proc files.
Making it possible to have /proc/sys vary depending on
the namespace you are in. The currently merged namespaces
don't have an issue here but the network namespace under
/proc/sys/net needs to have different directories depending
on which network adapters are visible. By simply being
a cache different directories being visible depending
on who you are is trivial to implement.
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
---
fs/proc/Makefile | 2 +-
fs/proc/inode.c | 1 +
fs/proc/internal.h | 2 +
fs/proc/proc_sysctl.c | 477 +++++++++++++++++++++++++++++++++++++++++++++++++
fs/proc/root.c | 10 +-
init/main.c | 4 -
kernel/sysctl.c | 182 -------------------
7 files changed, 484 insertions(+), 194 deletions(-)
diff --git a/fs/proc/Makefile b/fs/proc/Makefile
index f6c7762..a6b3a8f 100644
--- a/fs/proc/Makefile
+++ b/fs/proc/Makefile
@@ -8,7 +8,7 @@ proc-y := nommu.o task_nommu.o
proc-$(CONFIG_MMU) := mmu.o task_mmu.o
proc-y += inode.o root.o base.o generic.o array.o \
- proc_tty.o proc_misc.o
+ proc_tty.o proc_misc.o proc_sysctl.o
proc-$(CONFIG_PROC_KCORE) += kcore.o
proc-$(CONFIG_PROC_VMCORE) += vmcore.o
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index e26945b..0ea8265 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -161,6 +161,7 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino,
if (!inode)
goto out_ino;
+ PROC_I(inode)->fd = 0;
PROC_I(inode)->pde = de;
if (de) {
if (de->mode) {
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 987c773..3c9a305 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -11,6 +11,8 @@
#include <linux/proc_fs.h>
+extern int proc_sys_init(void);
+
struct vmalloc_info {
unsigned long used;
unsigned long largest_chunk;
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
new file mode 100644
index 0000000..08a2e66
--- /dev/null
+++ b/fs/proc/proc_sysctl.c
@@ -0,0 +1,477 @@
+/*
+ * /proc/sys support
+ */
+
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+#include <linux/security.h>
+#include "internal.h"
+
+static struct dentry_operations proc_sys_dentry_operations;
+static const struct file_operations proc_sys_file_operations;
+static struct inode_operations proc_sys_inode_operations;
+
+static void proc_sys_refresh_inode(struct inode *inode, struct ctl_table *table)
+{
+ /* Refresh the cached information bits in the inode */
+ if (table) {
+ inode->i_uid = 0;
+ inode->i_gid = 0;
+ inode->i_mode = table->mode;
+ if (table->proc_handler) {
+ inode->i_mode |= S_IFREG;
+ inode->i_nlink = 1;
+ } else {
+ inode->i_mode |= S_IFDIR;
+ inode->i_nlink = 0; /* It is too hard to figure out */
+ }
+ }
+}
+
+static struct inode *proc_sys_make_inode(struct inode *dir, struct ctl_table *table)
+{
+ struct inode *inode;
+ struct proc_inode *dir_ei, *ei;
+ int depth;
+
+ inode = new_inode(dir->i_sb);
+ if (!inode)
+ goto out;
+
+ /* A directory is always one deeper than it's parent */
+ dir_ei = PROC_I(dir);
+ depth = dir_ei->fd + 1;
+
+ ei = PROC_I(inode);
+ ei->fd = depth;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_op = &proc_sys_inode_operations;
+ inode->i_fop = &proc_sys_file_operations;
+ proc_sys_refresh_inode(inode, table);
+out:
+ return inode;
+}
+
+static struct dentry *proc_sys_ancestor(struct dentry *dentry, int depth)
+{
+ for (;;) {
+ struct proc_inode *ei;
+
+ ei = PROC_I(dentry->d_inode);
+ if (ei->fd == depth)
+ break; /* found */
+
+ dentry = dentry->d_parent;
+ }
+ return dentry;
+}
+
+static struct ctl_table *proc_sys_lookup_table_one(struct ctl_table *table,
+ struct qstr *name)
+{
+ int len;
+ for ( ; table->ctl_name || table->procname; table++) {
+
+ if (!table->procname)
+ continue;
+
+ len = strlen(table->procname);
+ if (len != name->len)
+ continue;
+
+ if (memcmp(table->procname, name->name, len) != 0)
+ continue;
+
+ /* I have a match */
+ return table;
+ }
+ return NULL;
+}
+
+static struct ctl_table *proc_sys_lookup_table(struct dentry *dentry,
+ struct ctl_table *table)
+{
+ struct dentry *ancestor;
+ struct proc_inode *ei;
+ int depth, i;
+
+ ei = PROC_I(dentry->d_inode);
+ depth = ei->fd;
+
+ if (depth == 0)
+ return table;
+
+ for (i = 1; table && (i <= depth); i++) {
+ ancestor = proc_sys_ancestor(dentry, i);
+ table = proc_sys_lookup_table_one(table, &ancestor->d_name);
+ if (table)
+ table = table->child;
+ }
+ return table;
+
+}
+static struct ctl_table *proc_sys_lookup_entry(struct dentry *dparent,
+ struct qstr *name,
+ struct ctl_table *table)
+{
+ table = proc_sys_lookup_table(dparent, table);
+ if (table)
+ table = proc_sys_lookup_table_one(table, name);
+ return table;
+}
+
+static struct ctl_table *do_proc_sys_lookup(struct dentry *parent,
+ struct qstr *name,
+ struct ctl_table_header **ptr)
+{
+ struct ctl_table_header *head;
+ struct ctl_table *table;
+
+ for (head = sysctl_head_next(NULL); head; head = sysctl_head_next(head)) {
+ table = proc_sys_lookup_entry(parent, name, head->ctl_table);
+ if (table)
+ break;
+ }
+ *ptr = head;
+ return table;
+}
+
+static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry,
+ struct nameidata *nd)
+{
+ struct ctl_table_header *head;
+ struct inode *inode;
+ struct dentry *err;
+ struct ctl_table *table;
+
+ err = ERR_PTR(-ENOENT);
+ table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head);
+ if (!table)
+ goto out;
+
+ err = ERR_PTR(-ENOMEM);
+ inode = proc_sys_make_inode(dir, table);
+ if (!inode)
+ goto out;
+
+ err = NULL;
+ dentry->d_op = &proc_sys_dentry_operations;
+ d_add(dentry, inode);
+
+out:
+ sysctl_head_finish(head);
+ return err;
+}
+
+static ssize_t proc_sys_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct dentry *dentry = filp->f_dentry;
+ struct ctl_table_header *head;
+ struct ctl_table *table;
+ ssize_t error, res;
+
+ table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head);
+ /* Has the sysctl entry disappeared on us? */
+ error = -ENOENT;
+ if (!table)
+ goto out;
+
+ /* Has the sysctl entry been replaced by a directory? */
+ error = -EISDIR;
+ if (!table->proc_handler)
+ goto out;
+
+ /*
+ * At this point we know that the sysctl was not unregistered
+ * and won't be until we finish.
+ */
+ error = -EPERM;
+ if (sysctl_perm(table, MAY_READ))
+ goto out;
+
+ /* careful: calling conventions are nasty here */
+ res = count;
+ error = table->proc_handler(table, 0, filp, buf, &res, ppos);
+ if (!error)
+ error = res;
+out:
+ sysctl_head_finish(head);
+
+ return error;
+}
+
+static ssize_t proc_sys_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct dentry *dentry = filp->f_dentry;
+ struct ctl_table_header *head;
+ struct ctl_table *table;
+ ssize_t error, res;
+
+ table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head);
+ /* Has the sysctl entry disappeared on us? */
+ error = -ENOENT;
+ if (!table)
+ goto out;
+
+ /* Has the sysctl entry been replaced by a directory? */
+ error = -EISDIR;
+ if (!table->proc_handler)
+ goto out;
+
+ /*
+ * At this point we know that the sysctl was not unregistered
+ * and won't be until we finish.
+ */
+ error = -EPERM;
+ if (sysctl_perm(table, MAY_WRITE))
+ goto out;
+
+ /* careful: calling conventions are nasty here */
+ res = count;
+ error = table->proc_handler(table, 1, filp, buf, &res, ppos);
+ if (!error)
+ error = res;
+out:
+ sysctl_head_finish(head);
+
+ return error;
+}
+
+
+static int proc_sys_fill_cache(struct file *filp, void *dirent,
+ filldir_t filldir, struct ctl_table *table)
+{
+ struct ctl_table_header *head;
+ struct ctl_table *child_table = NULL;
+ struct dentry *child, *dir = filp->f_path.dentry;
+ struct inode *inode;
+ struct qstr qname;
+ ino_t ino = 0;
+ unsigned type = DT_UNKNOWN;
+ int ret;
+
+ qname.name = table->procname;
+ qname.len = strlen(table->procname);
+ qname.hash = full_name_hash(qname.name, qname.len);
+
+ /* Suppress duplicates.
+ * Only fill a directory entry if it is the value that
+ * an ordinary lookup of that name returns. Hide all
+ * others.
+ *
+ * If we ever cache this translation in the dcache
+ * I should do a dcache lookup first. But for now
+ * it is just simpler not to.
+ */
+ ret = 0;
+ child_table = do_proc_sys_lookup(dir, &qname, &head);
+ sysctl_head_finish(head);
+ if (child_table != table)
+ return 0;
+
+ child = d_lookup(dir, &qname);
+ if (!child) {
+ struct dentry *new;
+ new = d_alloc(dir, &qname);
+ if (new) {
+ inode = proc_sys_make_inode(dir->d_inode, table);
+ if (!inode)
+ child = ERR_PTR(-ENOMEM);
+ else {
+ new->d_op = &proc_sys_dentry_operations;
+ d_add(new, inode);
+ }
+ if (child)
+ dput(new);
+ else
+ child = new;
+ }
+ }
+ if (!child || IS_ERR(child) || !child->d_inode)
+ goto end_instantiate;
+ inode = child->d_inode;
+ if (inode) {
+ ino = inode->i_ino;
+ type = inode->i_mode >> 12;
+ }
+ dput(child);
+end_instantiate:
+ if (!ino)
+ ino= find_inode_number(dir, &qname);
+ if (!ino)
+ ino = 1;
+ return filldir(dirent, qname.name, qname.len, filp->f_pos, ino, type);
+}
+
+static int proc_sys_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+ struct dentry *dentry = filp->f_dentry;
+ struct inode *inode = dentry->d_inode;
+ struct ctl_table_header *head = NULL;
+ struct ctl_table *table;
+ unsigned long pos;
+ int ret;
+
+ ret = -ENOTDIR;
+ if (!S_ISDIR(inode->i_mode))
+ goto out;
+
+ ret = 0;
+ switch(filp->f_pos) {
+ case 0:
+ if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino, DT_DIR) < 0)
+ goto out;
+ filp->f_pos++;
+ /* fall through */
+ case 1:
+ if (filldir(dirent, "..", 2, filp->f_pos, parent_ino(dentry), DT_DIR) < 0)
+ goto out;
+ filp->f_pos++;
+ /* fall through */
+ default:
+ pos = 2;
+ break;
+ }
+
+ /* - Find each instance of the directory
+ * - Read all entries in each instance
+ * - Before returning an entry to user space lookup the entry
+ * by name and if I find a different entry don't return
+ * this one because it means it is a buried dup.
+ * For sysctl this should only happen for directory entries.
+ */
+ for (head = sysctl_head_next(NULL); head; head = sysctl_head_next(head)) {
+ table = proc_sys_lookup_table(dentry, head->ctl_table);
+
+ if (!table)
+ continue;
+
+ for (; table->ctl_name || table->procname; table++, pos++) {
+ /* Can't do anything without a proc name */
+ if (!table->procname)
+ continue;
+
+ if (pos < filp->f_pos)
+ continue;
+
+ if (proc_sys_fill_cache(filp, dirent, filldir, table) < 0)
+ goto out;
+ filp->f_pos = pos + 1;
+ }
+ }
+ ret = 1;
+out:
+ sysctl_head_finish(head);
+ return ret;
+}
+
+static int proc_sys_permission(struct inode *inode, int mask, struct nameidata *nd)
+{
+ /*
+ * sysctl entries that are not writeable,
+ * are _NOT_ writeable, capabilities or not.
+ */
+ struct ctl_table_header *head;
+ struct ctl_table *table;
+ struct dentry *dentry;
+ int mode;
+ int depth;
+ int error;
+
+ head = NULL;
+ depth = PROC_I(inode)->fd;
+
+ /* First check the cached permissions, in case we don't have
+ * enough information to lookup the sysctl table entry.
+ */
+ error = -EACCES;
+ mode = inode->i_mode;
+
+ if (current->euid == 0)
+ mode >>= 6;
+ else if (in_group_p(0))
+ mode >>= 3;
+
+ if ((mode & mask & (MAY_READ|MAY_WRITE|MAY_EXEC)) == mask)
+ error = 0;
+
+ /* If we can't get a sysctl table entry the permission
+ * checks on the cached mode will have to be enough.
+ */
+ if (!nd || !depth)
+ goto out;
+
+ dentry = nd->dentry;
+ table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head);
+
+ /* If the entry does not exist deny permission */
+ error = -EACCES;
+ if (!table)
+ goto out;
+
+ /* Use the permissions on the sysctl table entry */
+ error = sysctl_perm(table, mask);
+out:
+ sysctl_head_finish(head);
+ return error;
+}
+
+static int proc_sys_setattr(struct dentry *dentry, struct iattr *attr)
+{
+ struct inode *inode = dentry->d_inode;
+ int error;
+
+ if (attr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
+ return -EPERM;
+
+ error = inode_change_ok(inode, attr);
+ if (!error) {
+ error = security_inode_setattr(dentry, attr);
+ if (!error)
+ error = inode_setattr(inode, attr);
+ }
+
+ return error;
+}
+
+/* I'm lazy and don't distinguish between files and directories,
+ * until access time.
+ */
+static const struct file_operations proc_sys_file_operations = {
+ .read = proc_sys_read,
+ .write = proc_sys_write,
+ .readdir = proc_sys_readdir,
+};
+
+static struct inode_operations proc_sys_inode_operations = {
+ .lookup = proc_sys_lookup,
+ .permission = proc_sys_permission,
+ .setattr = proc_sys_setattr,
+};
+
+static int proc_sys_revalidate(struct dentry *dentry, struct nameidata *nd)
+{
+ struct ctl_table_header *head;
+ struct ctl_table *table;
+ table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head);
+ proc_sys_refresh_inode(dentry->d_inode, table);
+ sysctl_head_finish(head);
+ return !!table;
+}
+
+static struct dentry_operations proc_sys_dentry_operations = {
+ .d_revalidate = proc_sys_revalidate,
+};
+
+struct proc_dir_entry *proc_sys_root;
+
+int proc_sys_init(void)
+{
+ proc_sys_root = proc_mkdir("sys", NULL);
+ proc_sys_root->proc_iops = &proc_sys_inode_operations;
+ proc_sys_root->proc_fops = &proc_sys_file_operations;
+ proc_sys_root->nlink = 0;
+ return 0;
+}
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 8059e92..4d42406 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -23,10 +23,6 @@
struct proc_dir_entry *proc_net, *proc_net_stat, *proc_bus, *proc_root_fs, *proc_root_driver;
-#ifdef CONFIG_SYSCTL
-struct proc_dir_entry *proc_sys_root;
-#endif
-
static int proc_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
@@ -71,9 +67,6 @@ void __init proc_root_init(void)
#ifdef CONFIG_SYSVIPC
proc_mkdir("sysvipc", NULL);
#endif
-#ifdef CONFIG_SYSCTL
- proc_sys_root = proc_mkdir("sys", NULL);
-#endif
proc_root_fs = proc_mkdir("fs", NULL);
proc_root_driver = proc_mkdir("driver", NULL);
proc_mkdir("fs/nfsd", NULL); /* somewhere for the nfsd filesystem to be mounted */
@@ -86,6 +79,9 @@ void __init proc_root_init(void)
proc_device_tree_init();
#endif
proc_bus = proc_mkdir("bus", NULL);
+#ifdef CONFIG_SYSCTL
+ proc_sys_init();
+#endif
}
static int proc_root_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat
diff --git a/init/main.c b/init/main.c
index 8af5c6e..7926e5d 100644
--- a/init/main.c
+++ b/init/main.c
@@ -86,7 +86,6 @@ extern void init_IRQ(void);
extern void fork_init(unsigned long);
extern void mca_init(void);
extern void sbus_init(void);
-extern void sysctl_init(void);
extern void signals_init(void);
extern void pidhash_init(void);
extern void pidmap_init(void);
@@ -688,9 +687,6 @@ static void __init do_basic_setup(void)
usermodehelper_init();
driver_init();
-#ifdef CONFIG_SYSCTL
- sysctl_init();
-#endif
#ifdef CONFIG_PROC_FS
init_irq_proc();
#endif
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index ec5e4a1..4b45bdb 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -159,26 +159,6 @@ int sysctl_legacy_va_layout;
-/* /proc declarations: */
-
-#ifdef CONFIG_PROC_SYSCTL
-
-static ssize_t proc_readsys(struct file *, char __user *, size_t, loff_t *);
-static ssize_t proc_writesys(struct file *, const char __user *, size_t, loff_t *);
-static int proc_opensys(struct inode *, struct file *);
-
-const struct file_operations proc_sys_file_operations = {
- .open = proc_opensys,
- .read = proc_readsys,
- .write = proc_writesys,
-};
-
-extern struct proc_dir_entry *proc_sys_root;
-
-static void register_proc_table(ctl_table *, struct proc_dir_entry *, void *);
-static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
-#endif
-
/* The default sysctl tables: */
static ctl_table root_table[] = {
@@ -1102,13 +1082,6 @@ struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev)
return NULL;
}
-void __init sysctl_init(void)
-{
-#ifdef CONFIG_PROC_SYSCTL
- register_proc_table(root_table, proc_sys_root, &root_table_header);
-#endif
-}
-
#ifdef CONFIG_SYSCTL_SYSCALL
int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
@@ -1345,9 +1318,6 @@ struct ctl_table_header *register_sysctl_table(ctl_table * table)
spin_lock(&sysctl_lock);
list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry);
spin_unlock(&sysctl_lock);
-#ifdef CONFIG_PROC_SYSCTL
- register_proc_table(table, proc_sys_root, tmp);
-#endif
return tmp;
}
@@ -1363,9 +1333,6 @@ void unregister_sysctl_table(struct ctl_table_header * header)
might_sleep();
spin_lock(&sysctl_lock);
start_unregistering(header);
-#ifdef CONFIG_PROC_SYSCTL
- unregister_proc_table(header->ctl_table, proc_sys_root);
-#endif
spin_unlock(&sysctl_lock);
kfree(header);
}
@@ -1389,155 +1356,6 @@ void unregister_sysctl_table(struct ctl_table_header * table)
#ifdef CONFIG_PROC_SYSCTL
-/* 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, void *set)
-{
- struct proc_dir_entry *de;
- int len;
- mode_t mode;
-
- for (; table->ctl_name || table->procname; 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) {
- printk(KERN_WARNING "SYSCTL: Can't register %s\n",
- table->procname);
- continue;
- }
-
- len = strlen(table->procname);
- mode = table->mode;
-
- de = NULL;
- if (table->proc_handler)
- mode |= S_IFREG;
- else {
- mode |= S_IFDIR;
- for (de = root->subdir; de; de = de->next) {
- if (proc_match(len, table->procname, de))
- break;
- }
- /* If the subdir exists already, de is non-NULL */
- }
-
- if (!de) {
- de = create_proc_entry(table->procname, mode, root);
- if (!de)
- continue;
- de->set = set;
- de->data = (void *) table;
- if (table->proc_handler)
- de->proc_fops = &proc_sys_file_operations;
- }
- table->de = de;
- if (de->mode & S_IFDIR)
- register_proc_table(table->child, de, set);
- }
-}
-
-/*
- * Unregister a /proc sysctl table and any subdirectories.
- */
-static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root)
-{
- struct proc_dir_entry *de;
- for (; table->ctl_name || table->procname; 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);
-
- /* Don't unregister directories which still have entries.. */
- if (de->subdir)
- continue;
- }
-
- /*
- * In any case, mark the entry as goner; we'll keep it
- * around if it's busy, but we'll know to do nothing with
- * its fields. We are under sysctl_lock here.
- */
- de->data = NULL;
-
- /* Don't unregister proc entries that are still being used.. */
- if (atomic_read(&de->count))
- continue;
-
- table->de = NULL;
- remove_proc_entry(table->procname, root);
- }
-}
-
-static ssize_t do_rw_proc(int write, struct file * file, char __user * buf,
- size_t count, loff_t *ppos)
-{
- int op;
- struct proc_dir_entry *de = PDE(file->f_path.dentry->d_inode);
- struct ctl_table *table;
- size_t res;
- ssize_t error = -ENOTDIR;
-
- spin_lock(&sysctl_lock);
- if (de && de->data && use_table(de->set)) {
- /*
- * at that point we know that sysctl was not unregistered
- * and won't be until we finish
- */
- spin_unlock(&sysctl_lock);
- table = (struct ctl_table *) de->data;
- if (!table || !table->proc_handler)
- goto out;
- error = -EPERM;
- op = (write ? 002 : 004);
- if (sysctl_perm(table, op))
- goto out;
-
- /* careful: calling conventions are nasty here */
- res = count;
- error = (*table->proc_handler)(table, write, file,
- buf, &res, ppos);
- if (!error)
- error = res;
- out:
- spin_lock(&sysctl_lock);
- unuse_table(de->set);
- }
- spin_unlock(&sysctl_lock);
- return error;
-}
-
-static int proc_opensys(struct inode *inode, struct file *file)
-{
- if (file->f_mode & FMODE_WRITE) {
- /*
- * sysctl entries that are not writable,
- * are _NOT_ writable, capabilities or not.
- */
- if (!(inode->i_mode & S_IWUSR))
- return -EPERM;
- }
-
- return 0;
-}
-
-static ssize_t proc_readsys(struct file * file, char __user * buf,
- size_t count, loff_t *ppos)
-{
- return do_rw_proc(0, file, buf, count, ppos);
-}
-
-static ssize_t proc_writesys(struct file * file, const char __user * buf,
- size_t count, loff_t *ppos)
-{
- return do_rw_proc(1, file, (char __user *) buf, count, ppos);
-}
-
static int _proc_do_string(void* data, int maxlen, int write,
struct file *filp, void __user *buffer,
size_t *lenp, loff_t *ppos)
--
1.4.4.1.g278f
next prev parent reply other threads:[~2007-01-16 16:59 UTC|newest]
Thread overview: 104+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-01-16 16:33 [PATCH 0/59] Cleanup sysctl Eric W. Biederman
2007-01-16 16:39 ` [PATCH 1/59] sysctl x25: Remove unnecessary insert_at_head from register_sysctl_table Eric W. Biederman
2007-01-16 16:39 ` [PATCH 2/59] sysctl: Move CTL_SUNRPC to sysctl.h where it belongs Eric W. Biederman
2007-01-16 16:39 ` [PATCH 3/59] sysctl: sunrpc Remove unnecessary insert_at_head flag Eric W. Biederman
2007-01-16 16:39 ` [PATCH 4/59] sysctl: sunrpc Don't unnecessarily set ctl_table->de Eric W. Biederman
2007-01-16 16:39 ` [PATCH 5/59] sysctl: rose remove unnecessary insert_at_head flag Eric W. Biederman
2007-01-16 17:36 ` Ralf Baechle
2007-01-16 16:39 ` [PATCH 6/59] sysctl: netrom " Eric W. Biederman
2007-01-16 16:39 ` [PATCH 7/59] sysctl: llc " Eric W. Biederman
2007-01-16 16:39 ` [PATCH 8/59] sysctl: ipx " Eric W. Biederman
2007-01-16 16:39 ` [PATCH 9/59] sysctl: decnet " Eric W. Biederman
2007-01-16 16:39 ` [PATCH 10/59] sysctl: dccp " Eric W. Biederman
2007-01-16 16:39 ` [PATCH 11/59] sysctl: ax25 " Eric W. Biederman
2007-01-16 16:39 ` [PATCH 12/59] sysctl: atalk " Eric W. Biederman
2007-01-16 16:39 ` [PATCH 13/59] sysctl: xfs " Eric W. Biederman
2007-01-16 16:39 ` [PATCH 14/59] sysctl: C99 convert xfs ctl_tables Eric W. Biederman
2007-01-16 18:16 ` Alexey Dobriyan
2007-01-16 18:37 ` Eric W. Biederman
2007-01-16 18:45 ` [PATCH] sysctl: fixes for my C99 converion " Eric W. Biederman
2007-01-17 17:01 ` [PATCH 14/59] sysctl: C99 convert " Kirill Korotaev
2007-01-17 17:37 ` [xfs-masters] " Eric Sandeen
2007-01-16 16:39 ` [PATCH 15/59] sysctl: scsi remove unnecessary insert_at_head flag Eric W. Biederman
2007-01-16 16:39 ` [PATCH 16/59] sysctl: md Remove " Eric W. Biederman
2007-01-16 16:39 ` [PATCH 17/59] sysctl: mac_hid remove " Eric W. Biederman
2007-01-16 16:39 ` [PATCH 18/59] sysctl: ipmi " Eric W. Biederman
2007-01-17 3:14 ` Benjamin Herrenschmidt
2007-01-16 16:39 ` [PATCH 19/59] sysctl: cdrom " Eric W. Biederman
2007-01-16 16:39 ` [PATCH 20/59] sysctl: cdrom Don't set de->owner Eric W. Biederman
2007-01-16 18:19 ` James Bottomley
2007-01-16 16:39 ` [PATCH 21/59] sysctl: Move CTL_PM into sysctl.h where it belongs Eric W. Biederman
2007-01-16 16:39 ` [PATCH 22/59] sysctl: frv pm remove unnecessary insert_at_head flag Eric W. Biederman
2007-01-16 16:39 ` [PATCH 23/59] sysctl: Move CTL_FRV into sysctl.h where it belongs Eric W. Biederman
2007-01-16 16:39 ` [PATCH 24/59] sysctl: frv remove unnecessary insert_at_head flag Eric W. Biederman
2007-01-16 16:39 ` [PATCH 25/59] sysctl: C99 convert arch/frv/kernel/pm.c Eric W. Biederman
2007-01-17 17:14 ` Kirill Korotaev
2007-01-22 22:21 ` Herbert Poetzl
2007-01-24 9:00 ` David Howells
2007-01-16 16:39 ` [PATCH 26/59] sysctl: C99 convert arch/frv/kernel/sysctl.c Eric W. Biederman
2007-01-16 16:39 ` [PATCH 27/59] sysctl: sn Remove sysctl ABI BREAKAGE Eric W. Biederman
2007-01-16 16:39 ` [PATCH 28/59] sysctl: C99 Convert arch/ia64/sn/kernel/xpc_main.c Eric W. Biederman
2007-01-16 16:39 ` [PATCH 29/59] sysctl: C99 convert arch/ia64/kernel/perfmon and remove ABI breakage Eric W. Biederman
2007-01-16 16:39 ` [PATCH 30/59] sysctl: mips/au1000 Remove sys_sysctl support Eric W. Biederman
2007-01-16 16:39 ` [PATCH 31/59] sysctl: C99 convert the ctl_tables in arch/mips/au1000/common/power.c Eric W. Biederman
2007-01-16 22:20 ` Ingo Oeser
2007-01-16 16:39 ` [PATCH 32/59] sysctl: C99 convert arch/mips/lasat/sysctl.c and remove ABI breakage Eric W. Biederman
2007-01-16 16:39 ` [PATCH 33/59] sysctl: s390 move sysctl definitions to sysctl.h Eric W. Biederman
2007-01-17 17:23 ` Kirill Korotaev
2007-01-16 16:39 ` [PATCH 34/59] sysctl: s390 Remove unnecessary use of insert_at_head Eric W. Biederman
2007-01-16 16:39 ` [PATCH 35/59] sysctl: C99 convert ctl_tables in arch/powerpc/kernel/idle.c Eric W. Biederman
2007-01-17 3:16 ` Benjamin Herrenschmidt
2007-01-16 16:39 ` [PATCH 36/59] sysctl: C99 convert ctl_tables entries in arch/ppc/kernel/ppc_htab.c Eric W. Biederman
2007-01-17 3:16 ` Benjamin Herrenschmidt
2007-01-16 16:39 ` [PATCH 37/59] sysctl: C99 convert arch/sh64/kernel/traps.c and remove ABI breakage Eric W. Biederman
2007-01-16 22:07 ` Paul Mundt
2007-01-16 16:39 ` [PATCH 38/59] sysctl: x86_64 Remove unnecessary use of insert_at_head Eric W. Biederman
2007-01-16 16:39 ` [PATCH 39/59] sysctl: C99 convert ctl_tables in arch/x86_64/ia32/ia32_binfmt.c Eric W. Biederman
2007-01-16 16:39 ` [PATCH 40/59] sysctl: C99 convert ctl_tables in arch/x86_64/kernel/vsyscall.c Eric W. Biederman
2007-01-16 16:39 ` [PATCH 41/59] sysctl: C99 convert ctl_tables in arch/x86_64/mm/init.c Eric W. Biederman
2007-01-16 16:39 ` [PATCH 42/59] sysctl: Remove sys_sysctl support from the hpet timer driver Eric W. Biederman
2007-01-17 7:54 ` Clemens Ladisch
2007-01-16 16:39 ` [PATCH 43/59] sysctl: Remove sys_sysctl support from drivers/char/rtc.c Eric W. Biederman
2007-01-16 16:39 ` [PATCH 44/59] sysctl: Register the sysctl number used by the arlan driver Eric W. Biederman
2007-01-16 16:39 ` [PATCH 45/59] sysctl: C99 convert ctl_tables in drivers/parport/procfs.c Eric W. Biederman
2007-01-16 22:15 ` Ingo Oeser
2007-01-16 23:00 ` Eric W. Biederman
2007-01-16 16:39 ` [PATCH 46/59] sysctl: C99 convert coda ctl_tables and remove binary sysctls Eric W. Biederman
2007-01-16 16:39 ` [PATCH 47/59] sysctl: C99 convert ctl_tables in NTFS and remove sys_sysctl support Eric W. Biederman
2007-01-16 16:39 ` [PATCH 48/59] sysctl: Register the ocfs2 sysctl numbers Eric W. Biederman
2007-01-16 20:37 ` Mark Fasheh
2007-01-16 16:39 ` [PATCH 49/59] sysctl: Move init_irq_proc into init/main where it belongs Eric W. Biederman
2007-01-27 10:51 ` Andrew Morton
2007-01-16 16:39 ` [PATCH 50/59] sysctl: Move utsname sysctls to their own file Eric W. Biederman
2007-01-17 17:41 ` Kirill Korotaev
2007-01-17 19:31 ` Eric W. Biederman
2007-01-22 22:24 ` Herbert Poetzl
2007-01-16 16:39 ` [PATCH 51/59] sysctl: Move SYSV IPC " Eric W. Biederman
2007-01-17 17:44 ` Kirill Korotaev
2007-01-16 16:39 ` [PATCH 52/59] sysctl: Create sys/fs/binfmt_misc as an ordinary sysctl entry Eric W. Biederman
2007-01-16 16:39 ` [PATCH 53/59] sysctl: Remove support for CTL_ANY Eric W. Biederman
2007-01-16 16:39 ` [PATCH 54/59] sysctl: Remove support for directory strategy routines Eric W. Biederman
2007-01-16 16:40 ` [PATCH 55/59] sysctl: Remove insert_at_head from register_sysctl Eric W. Biederman
2007-01-16 16:40 ` [PATCH 56/59] sysctl: factor out sysctl_head_next from do_sysctl Eric W. Biederman
2007-01-16 16:40 ` [PATCH 57/59] sysctl: allow sysctl_perm to be called from outside of sysctl.c Eric W. Biederman
2007-01-16 16:40 ` Eric W. Biederman [this message]
2007-03-14 10:38 ` [PATCH 58/59] sysctl: Reimplement the sysctl proc support Ingo Molnar
2007-03-14 10:48 ` Alexey Dobriyan
2007-03-14 12:24 ` Ingo Molnar
2007-03-14 13:34 ` Eric W. Biederman
2007-03-14 13:46 ` Ingo Molnar
2007-03-14 15:44 ` Michal Schmidt
2007-01-16 16:40 ` [PATCH 59/59] sysctl: Remove the proc_dir_entry member for the sysctl tables Eric W. Biederman
2007-01-16 16:53 ` [PATCH 0/59] Cleanup sysctl H. Peter Anvin
2007-01-16 18:12 ` Eric W. Biederman
2007-01-16 18:35 ` H. Peter Anvin
2007-01-16 18:54 ` Eric W. Biederman
2007-01-16 18:58 ` H. Peter Anvin
2007-01-16 19:03 ` Eric W. Biederman
2007-01-16 19:15 ` H. Peter Anvin
2007-01-16 19:30 ` Eric W. Biederman
2007-01-16 20:02 ` David Howells
2007-01-17 4:21 ` Andi Kleen
2007-01-17 12:10 ` Martin Schwidefsky
2007-01-17 18:10 ` Kirill Korotaev
2007-01-17 19:02 ` Eric W. Biederman
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=11689657073389-git-send-email-ebiederm@xmission.com \
--to=ebiederm@xmission.com \
--cc=James.Bottomley@SteelEye.com \
--cc=a.zummo@towertech.it \
--cc=aharkes@cs.cmu.edu \
--cc=aia21@cantab.net \
--cc=ak@suse.de \
--cc=akpm@osdl.org \
--cc=andrea@suse.de \
--cc=clemens@ladisch.de \
--cc=coda@cs.cmu.edu \
--cc=codalist@TELEMANN.coda.cs.cmu.edu \
--cc=containers@lists.osdl.org \
--cc=heiko.carstens@de.ibm.com \
--cc=kurt.hackel@oracle.com \
--cc=lethal@linux-sh.org \
--cc=linux-390@vm.marist.edu \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mips@linux-mips.org \
--cc=linux-ntfs-dev@lists.sourceforge.net \
--cc=linux-parport@lists.infradead.org \
--cc=linux-scsi@vger.kernel.org \
--cc=linux390@de.ibm.com \
--cc=linuxppc-dev@ozlabs.org \
--cc=linuxsh-shmedia-dev@lists.sourceforge.net \
--cc=mark.fasheh@oracle.com \
--cc=minyard@acm.org \
--cc=netdev@vger.kernel.org \
--cc=openipmi-developer@lists.sourceforge.net \
--cc=paulus@samba.org \
--cc=philb@gnu.org \
--cc=ralf@linux-mips.org \
--cc=rtc-linux@googlegroups.com \
--cc=schwidefsky@de.ibm.com \
--cc=tim@cyberelk.net \
--cc=tony.luck@intel.com \
--cc=vojtech@suse.cz \
--cc=xfs-masters@oss.sgi.com \
--cc=xfs@oss.sgi.com \
--subject='Re: [PATCH 58/59] sysctl: Reimplement the sysctl proc support' \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).