diff options
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/Makefile | 2 | ||||
-rw-r--r-- | fs/proc/array.c | 2 | ||||
-rw-r--r-- | fs/proc/base.c | 56 | ||||
-rw-r--r-- | fs/proc/generic.c | 12 | ||||
-rw-r--r-- | fs/proc/inode.c | 3 | ||||
-rw-r--r-- | fs/proc/internal.h | 14 | ||||
-rw-r--r-- | fs/proc/nommu.c | 2 | ||||
-rw-r--r-- | fs/proc/proc_misc.c | 54 | ||||
-rw-r--r-- | fs/proc/proc_sysctl.c | 479 | ||||
-rw-r--r-- | fs/proc/proc_tty.c | 2 | ||||
-rw-r--r-- | fs/proc/root.c | 18 | ||||
-rw-r--r-- | fs/proc/task_mmu.c | 6 | ||||
-rw-r--r-- | fs/proc/task_nommu.c | 2 |
13 files changed, 565 insertions, 87 deletions
diff --git a/fs/proc/Makefile b/fs/proc/Makefile index f6c77627257..a6b3a8f878f 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/array.c b/fs/proc/array.c index 70e4fab117b..07c9cdbcdca 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -351,7 +351,7 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) struct signal_struct *sig = task->signal; if (sig->tty) { - tty_pgrp = sig->tty->pgrp; + tty_pgrp = pid_nr(sig->tty->pgrp); tty_nr = new_encode_dev(tty_devnum(sig->tty)); } diff --git a/fs/proc/base.c b/fs/proc/base.c index 1a979ea3b37..4f5745af8c1 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -93,8 +93,8 @@ struct pid_entry { int len; char *name; mode_t mode; - struct inode_operations *iop; - struct file_operations *fop; + const struct inode_operations *iop; + const struct file_operations *fop; union proc_op op; }; @@ -352,7 +352,7 @@ static int proc_setattr(struct dentry *dentry, struct iattr *attr) return error; } -static struct inode_operations proc_def_inode_operations = { +static const struct inode_operations proc_def_inode_operations = { .setattr = proc_setattr, }; @@ -424,7 +424,7 @@ static unsigned mounts_poll(struct file *file, poll_table *wait) return res; } -static struct file_operations proc_mounts_operations = { +static const struct file_operations proc_mounts_operations = { .open = mounts_open, .read = seq_read, .llseek = seq_lseek, @@ -462,7 +462,7 @@ static int mountstats_open(struct inode *inode, struct file *file) return ret; } -static struct file_operations proc_mountstats_operations = { +static const struct file_operations proc_mountstats_operations = { .open = mountstats_open, .read = seq_read, .llseek = seq_lseek, @@ -501,7 +501,7 @@ out_no_task: return length; } -static struct file_operations proc_info_file_operations = { +static const struct file_operations proc_info_file_operations = { .read = proc_info_read, }; @@ -646,7 +646,7 @@ static loff_t mem_lseek(struct file * file, loff_t offset, int orig) return file->f_pos; } -static struct file_operations proc_mem_operations = { +static const struct file_operations proc_mem_operations = { .llseek = mem_lseek, .read = mem_read, .write = mem_write, @@ -710,7 +710,7 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf, return end - buffer; } -static struct file_operations proc_oom_adjust_operations = { +static const struct file_operations proc_oom_adjust_operations = { .read = oom_adjust_read, .write = oom_adjust_write, }; @@ -777,7 +777,7 @@ out_free_page: return length; } -static struct file_operations proc_loginuid_operations = { +static const struct file_operations proc_loginuid_operations = { .read = proc_loginuid_read, .write = proc_loginuid_write, }; @@ -849,7 +849,7 @@ out_no_task: return result; } -static struct file_operations proc_seccomp_operations = { +static const struct file_operations proc_seccomp_operations = { .read = seccomp_read, .write = seccomp_write, }; @@ -908,7 +908,7 @@ static ssize_t proc_fault_inject_write(struct file * file, return end - buffer; } -static struct file_operations proc_fault_inject_operations = { +static const struct file_operations proc_fault_inject_operations = { .read = proc_fault_inject_read, .write = proc_fault_inject_write, }; @@ -980,7 +980,7 @@ out: return error; } -static struct inode_operations proc_pid_link_inode_operations = { +static const struct inode_operations proc_pid_link_inode_operations = { .readlink = proc_pid_readlink, .follow_link = proc_pid_follow_link, .setattr = proc_setattr, @@ -1408,7 +1408,7 @@ out_no_task: return retval; } -static struct file_operations proc_fd_operations = { +static const struct file_operations proc_fd_operations = { .read = generic_read_dir, .readdir = proc_readfd, }; @@ -1416,7 +1416,7 @@ static struct file_operations proc_fd_operations = { /* * proc directories can do almost nothing.. */ -static struct inode_operations proc_fd_inode_operations = { +static const struct inode_operations proc_fd_inode_operations = { .lookup = proc_lookupfd, .setattr = proc_setattr, }; @@ -1623,7 +1623,7 @@ out_no_task: return length; } -static struct file_operations proc_pid_attr_operations = { +static const struct file_operations proc_pid_attr_operations = { .read = proc_pid_attr_read, .write = proc_pid_attr_write, }; @@ -1644,7 +1644,7 @@ static int proc_attr_dir_readdir(struct file * filp, attr_dir_stuff,ARRAY_SIZE(attr_dir_stuff)); } -static struct file_operations proc_attr_dir_operations = { +static const struct file_operations proc_attr_dir_operations = { .read = generic_read_dir, .readdir = proc_attr_dir_readdir, }; @@ -1656,7 +1656,7 @@ static struct dentry *proc_attr_dir_lookup(struct inode *dir, attr_dir_stuff, ARRAY_SIZE(attr_dir_stuff)); } -static struct inode_operations proc_attr_dir_inode_operations = { +static const struct inode_operations proc_attr_dir_inode_operations = { .lookup = proc_attr_dir_lookup, .getattr = pid_getattr, .setattr = proc_setattr, @@ -1682,7 +1682,7 @@ static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd) return ERR_PTR(vfs_follow_link(nd,tmp)); } -static struct inode_operations proc_self_inode_operations = { +static const struct inode_operations proc_self_inode_operations = { .readlink = proc_self_readlink, .follow_link = proc_self_follow_link, }; @@ -1810,17 +1810,21 @@ static int proc_base_fill_cache(struct file *filp, void *dirent, filldir_t filld static int proc_pid_io_accounting(struct task_struct *task, char *buffer) { return sprintf(buffer, +#ifdef CONFIG_TASK_XACCT "rchar: %llu\n" "wchar: %llu\n" "syscr: %llu\n" "syscw: %llu\n" +#endif "read_bytes: %llu\n" "write_bytes: %llu\n" "cancelled_write_bytes: %llu\n", +#ifdef CONFIG_TASK_XACCT (unsigned long long)task->rchar, (unsigned long long)task->wchar, (unsigned long long)task->syscr, (unsigned long long)task->syscw, +#endif (unsigned long long)task->ioac.read_bytes, (unsigned long long)task->ioac.write_bytes, (unsigned long long)task->ioac.cancelled_write_bytes); @@ -1830,8 +1834,8 @@ static int proc_pid_io_accounting(struct task_struct *task, char *buffer) /* * Thread groups */ -static struct file_operations proc_task_operations; -static struct inode_operations proc_task_inode_operations; +static const struct file_operations proc_task_operations; +static const struct inode_operations proc_task_inode_operations; static struct pid_entry tgid_base_stuff[] = { DIR("task", S_IRUGO|S_IXUGO, task), @@ -1890,7 +1894,7 @@ static int proc_tgid_base_readdir(struct file * filp, tgid_base_stuff,ARRAY_SIZE(tgid_base_stuff)); } -static struct file_operations proc_tgid_base_operations = { +static const struct file_operations proc_tgid_base_operations = { .read = generic_read_dir, .readdir = proc_tgid_base_readdir, }; @@ -1900,7 +1904,7 @@ static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *de tgid_base_stuff, ARRAY_SIZE(tgid_base_stuff)); } -static struct inode_operations proc_tgid_base_inode_operations = { +static const struct inode_operations proc_tgid_base_inode_operations = { .lookup = proc_tgid_base_lookup, .getattr = pid_getattr, .setattr = proc_setattr, @@ -2173,12 +2177,12 @@ static struct dentry *proc_tid_base_lookup(struct inode *dir, struct dentry *den tid_base_stuff, ARRAY_SIZE(tid_base_stuff)); } -static struct file_operations proc_tid_base_operations = { +static const struct file_operations proc_tid_base_operations = { .read = generic_read_dir, .readdir = proc_tid_base_readdir, }; -static struct inode_operations proc_tid_base_inode_operations = { +static const struct inode_operations proc_tid_base_inode_operations = { .lookup = proc_tid_base_lookup, .getattr = pid_getattr, .setattr = proc_setattr, @@ -2404,13 +2408,13 @@ static int proc_task_getattr(struct vfsmount *mnt, struct dentry *dentry, struct return 0; } -static struct inode_operations proc_task_inode_operations = { +static const struct inode_operations proc_task_inode_operations = { .lookup = proc_task_lookup, .getattr = proc_task_getattr, .setattr = proc_setattr, }; -static struct file_operations proc_task_operations = { +static const struct file_operations proc_task_operations = { .read = generic_read_dir, .readdir = proc_task_readdir, }; diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 853cb877d5f..775fb21294d 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -32,14 +32,14 @@ static loff_t proc_file_lseek(struct file *, loff_t, int); DEFINE_SPINLOCK(proc_subdir_lock); -int proc_match(int len, const char *name, struct proc_dir_entry *de) +static int proc_match(int len, const char *name, struct proc_dir_entry *de) { if (de->namelen != len) return 0; return !memcmp(name, de->name, len); } -static struct file_operations proc_file_operations = { +static const struct file_operations proc_file_operations = { .llseek = proc_file_lseek, .read = proc_file_read, .write = proc_file_write, @@ -265,7 +265,7 @@ static int proc_getattr(struct vfsmount *mnt, struct dentry *dentry, return 0; } -static struct inode_operations proc_file_inode_operations = { +static const struct inode_operations proc_file_inode_operations = { .setattr = proc_notify_change, }; @@ -357,7 +357,7 @@ static void *proc_follow_link(struct dentry *dentry, struct nameidata *nd) return NULL; } -static struct inode_operations proc_link_inode_operations = { +static const struct inode_operations proc_link_inode_operations = { .readlink = generic_readlink, .follow_link = proc_follow_link, }; @@ -497,7 +497,7 @@ out: unlock_kernel(); * use the in-memory "struct proc_dir_entry" tree to parse * the /proc directory. */ -static struct file_operations proc_dir_operations = { +static const struct file_operations proc_dir_operations = { .read = generic_read_dir, .readdir = proc_readdir, }; @@ -505,7 +505,7 @@ static struct file_operations proc_dir_operations = { /* * proc directories can do almost nothing.. */ -static struct inode_operations proc_dir_inode_operations = { +static const struct inode_operations proc_dir_inode_operations = { .lookup = proc_lookup, .getattr = proc_getattr, .setattr = proc_notify_change, diff --git a/fs/proc/inode.c b/fs/proc/inode.c index e26945ba685..c372eb151a3 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -132,7 +132,7 @@ static int proc_remount(struct super_block *sb, int *flags, char *data) return 0; } -static struct super_operations proc_sops = { +static const struct super_operations proc_sops = { .alloc_inode = proc_alloc_inode, .destroy_inode = proc_destroy_inode, .read_inode = proc_read_inode, @@ -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 987c773dbb2..c932aa65e19 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; @@ -38,13 +40,13 @@ extern int proc_tgid_stat(struct task_struct *, char *); extern int proc_pid_status(struct task_struct *, char *); extern int proc_pid_statm(struct task_struct *, char *); -extern struct file_operations proc_maps_operations; -extern struct file_operations proc_numa_maps_operations; -extern struct file_operations proc_smaps_operations; +extern const struct file_operations proc_maps_operations; +extern const struct file_operations proc_numa_maps_operations; +extern const struct file_operations proc_smaps_operations; -extern struct file_operations proc_maps_operations; -extern struct file_operations proc_numa_maps_operations; -extern struct file_operations proc_smaps_operations; +extern const struct file_operations proc_maps_operations; +extern const struct file_operations proc_numa_maps_operations; +extern const struct file_operations proc_smaps_operations; void free_proc_entry(struct proc_dir_entry *de); diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c index 5ec67257e5f..22f789de390 100644 --- a/fs/proc/nommu.c +++ b/fs/proc/nommu.c @@ -128,7 +128,7 @@ static int proc_nommu_vma_list_open(struct inode *inode, struct file *file) return seq_open(file, &proc_nommu_vma_list_seqop); } -static struct file_operations proc_nommu_vma_list_operations = { +static const struct file_operations proc_nommu_vma_list_operations = { .open = proc_nommu_vma_list_open, .read = seq_read, .llseek = seq_lseek, diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index b37ce33f67e..e2c4c0a5c90 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -121,16 +121,11 @@ static int meminfo_read_proc(char *page, char **start, off_t off, { struct sysinfo i; int len; - unsigned long inactive; - unsigned long active; - unsigned long free; unsigned long committed; unsigned long allowed; struct vmalloc_info vmi; long cached; - get_zone_counts(&active, &inactive, &free); - /* * display in kilobytes. */ @@ -187,8 +182,8 @@ static int meminfo_read_proc(char *page, char **start, off_t off, K(i.bufferram), K(cached), K(total_swapcache_pages), - K(active), - K(inactive), + K(global_page_state(NR_ACTIVE)), + K(global_page_state(NR_INACTIVE)), #ifdef CONFIG_HIGHMEM K(i.totalhigh), K(i.freehigh), @@ -228,7 +223,7 @@ static int fragmentation_open(struct inode *inode, struct file *file) return seq_open(file, &fragmentation_op); } -static struct file_operations fragmentation_file_operations = { +static const struct file_operations fragmentation_file_operations = { .open = fragmentation_open, .read = seq_read, .llseek = seq_lseek, @@ -241,7 +236,7 @@ static int zoneinfo_open(struct inode *inode, struct file *file) return seq_open(file, &zoneinfo_op); } -static struct file_operations proc_zoneinfo_file_operations = { +static const struct file_operations proc_zoneinfo_file_operations = { .open = zoneinfo_open, .read = seq_read, .llseek = seq_lseek, @@ -266,7 +261,7 @@ static int cpuinfo_open(struct inode *inode, struct file *file) return seq_open(file, &cpuinfo_op); } -static struct file_operations proc_cpuinfo_operations = { +static const struct file_operations proc_cpuinfo_operations = { .open = cpuinfo_open, .read = seq_read, .llseek = seq_lseek, @@ -325,7 +320,7 @@ static int devinfo_open(struct inode *inode, struct file *filp) return seq_open(filp, &devinfo_ops); } -static struct file_operations proc_devinfo_operations = { +static const struct file_operations proc_devinfo_operations = { .open = devinfo_open, .read = seq_read, .llseek = seq_lseek, @@ -337,7 +332,7 @@ static int vmstat_open(struct inode *inode, struct file *file) { return seq_open(file, &vmstat_op); } -static struct file_operations proc_vmstat_file_operations = { +static const struct file_operations proc_vmstat_file_operations = { .open = vmstat_open, .read = seq_read, .llseek = seq_lseek, @@ -368,7 +363,7 @@ static int partitions_open(struct inode *inode, struct file *file) { return seq_open(file, &partitions_op); } -static struct file_operations proc_partitions_operations = { +static const struct file_operations proc_partitions_operations = { .open = partitions_open, .read = seq_read, .llseek = seq_lseek, @@ -380,7 +375,7 @@ static int diskstats_open(struct inode *inode, struct file *file) { return seq_open(file, &diskstats_op); } -static struct file_operations proc_diskstats_operations = { +static const struct file_operations proc_diskstats_operations = { .open = diskstats_open, .read = seq_read, .llseek = seq_lseek, @@ -394,7 +389,7 @@ static int modules_open(struct inode *inode, struct file *file) { return seq_open(file, &modules_op); } -static struct file_operations proc_modules_operations = { +static const struct file_operations proc_modules_operations = { .open = modules_open, .read = seq_read, .llseek = seq_lseek, @@ -409,7 +404,7 @@ static int slabinfo_open(struct inode *inode, struct file *file) { return seq_open(file, &slabinfo_op); } -static struct file_operations proc_slabinfo_operations = { +static const struct file_operations proc_slabinfo_operations = { .open = slabinfo_open, .read = seq_read, .write = slabinfo_write, @@ -443,7 +438,7 @@ static int slabstats_release(struct inode *inode, struct file *file) return seq_release(inode, file); } -static struct file_operations proc_slabstats_operations = { +static const struct file_operations proc_slabstats_operations = { .open = slabstats_open, .read = seq_read, .llseek = seq_lseek, @@ -556,7 +551,7 @@ static int stat_open(struct inode *inode, struct file *file) kfree(buf); return res; } -static struct file_operations proc_stat_operations = { +static const struct file_operations proc_stat_operations = { .open = stat_open, .read = seq_read, .llseek = seq_lseek, @@ -598,7 +593,7 @@ static int interrupts_open(struct inode *inode, struct file *filp) return seq_open(filp, &int_seq_ops); } -static struct file_operations proc_interrupts_operations = { +static const struct file_operations proc_interrupts_operations = { .open = interrupts_open, .read = seq_read, .llseek = seq_lseek, @@ -655,7 +650,7 @@ static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf, return count; } -static struct file_operations proc_sysrq_trigger_operations = { +static const struct file_operations proc_sysrq_trigger_operations = { .write = write_sysrq_trigger, }; #endif @@ -672,7 +667,6 @@ void create_seq_entry(char *name, mode_t mode, const struct file_operations *f) void __init proc_misc_init(void) { - struct proc_dir_entry *entry; static struct { char *name; int (*read_proc)(char*,char**,off_t,int,int*,void*); @@ -700,9 +694,12 @@ void __init proc_misc_init(void) /* And now for trickier ones */ #ifdef CONFIG_PRINTK - entry = create_proc_entry("kmsg", S_IRUSR, &proc_root); - if (entry) - entry->proc_fops = &proc_kmsg_operations; + { + struct proc_dir_entry *entry; + entry = create_proc_entry("kmsg", S_IRUSR, &proc_root); + if (entry) + entry->proc_fops = &proc_kmsg_operations; + } #endif create_seq_entry("devices", 0, &proc_devinfo_operations); create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations); @@ -743,8 +740,11 @@ void __init proc_misc_init(void) proc_vmcore->proc_fops = &proc_vmcore_operations; #endif #ifdef CONFIG_MAGIC_SYSRQ - entry = create_proc_entry("sysrq-trigger", S_IWUSR, NULL); - if (entry) - entry->proc_fops = &proc_sysrq_trigger_operations; + { + struct proc_dir_entry *entry; + entry = create_proc_entry("sysrq-trigger", S_IWUSR, NULL); + if (entry) + entry->proc_fops = &proc_sysrq_trigger_operations; + } #endif } diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c new file mode 100644 index 00000000000..20e8cbb3436 --- /dev/null +++ b/fs/proc/proc_sysctl.c @@ -0,0 +1,479 @@ +/* + * /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; + inode->i_flags |= S_PRIVATE; /* tell selinux to ignore this inode */ + 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 = NULL; + + 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, (char __user *)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; + /* Avoid a switch here: arm builds fail with missing __cmpdi2 */ + if (filp->f_pos == 0) { + if (filldir(dirent, ".", 1, filp->f_pos, + inode->i_ino, DT_DIR) < 0) + goto out; + filp->f_pos++; + } + if (filp->f_pos == 1) { + if (filldir(dirent, "..", 2, filp->f_pos, + parent_ino(dentry), DT_DIR) < 0) + goto out; + filp->f_pos++; + } + pos = 2; + + /* - 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, +}; + +static 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/proc_tty.c b/fs/proc/proc_tty.c index 15c4455b09e..c1bbfbeb035 100644 --- a/fs/proc/proc_tty.c +++ b/fs/proc/proc_tty.c @@ -138,7 +138,7 @@ static int tty_drivers_open(struct inode *inode, struct file *file) return seq_open(file, &tty_drivers_op); } -static struct file_operations proc_tty_drivers_operations = { +static const struct file_operations proc_tty_drivers_operations = { .open = tty_drivers_open, .read = seq_read, .llseek = seq_lseek, diff --git a/fs/proc/root.c b/fs/proc/root.c index 64d242b6dcf..5834a744c2a 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,13 +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 -#if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE) - proc_mkdir("sys/fs", NULL); - proc_mkdir("sys/fs/binfmt_misc", 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 */ @@ -90,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 @@ -136,7 +128,7 @@ static int proc_root_readdir(struct file * filp, * <pid> directories. Thus we don't use the generic * directory handling functions for that.. */ -static struct file_operations proc_root_operations = { +static const struct file_operations proc_root_operations = { .read = generic_read_dir, .readdir = proc_root_readdir, }; @@ -144,7 +136,7 @@ static struct file_operations proc_root_operations = { /* * proc root can do almost nothing.. */ -static struct inode_operations proc_root_inode_operations = { +static const struct inode_operations proc_root_inode_operations = { .lookup = proc_root_lookup, .getattr = proc_root_getattr, }; diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 55ade0d1562..7445980c802 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -434,7 +434,7 @@ static int maps_open(struct inode *inode, struct file *file) return do_maps_open(inode, file, &proc_pid_maps_op); } -struct file_operations proc_maps_operations = { +const struct file_operations proc_maps_operations = { .open = maps_open, .read = seq_read, .llseek = seq_lseek, @@ -456,7 +456,7 @@ static int numa_maps_open(struct inode *inode, struct file *file) return do_maps_open(inode, file, &proc_pid_numa_maps_op); } -struct file_operations proc_numa_maps_operations = { +const struct file_operations proc_numa_maps_operations = { .open = numa_maps_open, .read = seq_read, .llseek = seq_lseek, @@ -469,7 +469,7 @@ static int smaps_open(struct inode *inode, struct file *file) return do_maps_open(inode, file, &proc_pid_smaps_op); } -struct file_operations proc_smaps_operations = { +const struct file_operations proc_smaps_operations = { .open = smaps_open, .read = seq_read, .llseek = seq_lseek, diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c index fcc5caf93f5..7cddf6b8635 100644 --- a/fs/proc/task_nommu.c +++ b/fs/proc/task_nommu.c @@ -220,7 +220,7 @@ static int maps_open(struct inode *inode, struct file *file) return ret; } -struct file_operations proc_maps_operations = { +const struct file_operations proc_maps_operations = { .open = maps_open, .read = seq_read, .llseek = seq_lseek, |