diff options
author | Dave Jones <davej@redhat.com> | 2006-04-18 17:19:55 -0500 |
---|---|---|
committer | Dave Jones <davej@redhat.com> | 2006-04-18 17:19:55 -0500 |
commit | f1f76afd71e0f17af9a35fcb649f4bab53304a4d (patch) | |
tree | a56257b13a0eda4a9b7e950c3b85adad16341b80 /fs/proc | |
parent | 530515a06f90c0831732709efee4a99497bd2b7c (diff) | |
parent | 385910f2b275a636238f70844f1b6da9fda6f2da (diff) |
Merge ../linus
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/base.c | 13 | ||||
-rw-r--r-- | fs/proc/proc_devtree.c | 103 | ||||
-rw-r--r-- | fs/proc/proc_misc.c | 163 | ||||
-rw-r--r-- | fs/proc/vmcore.c | 4 |
4 files changed, 126 insertions, 157 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index 8f1f49ceebe..a3a3eecef68 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -534,12 +534,15 @@ static int proc_oom_score(struct task_struct *task, char *buffer) /* If the process being read is separated by chroot from the reading process, * don't let the reader access the threads. + * + * note: this does dput(root) and mntput(vfsmnt) on exit. */ static int proc_check_chroot(struct dentry *root, struct vfsmount *vfsmnt) { struct dentry *de, *base; struct vfsmount *our_vfsmnt, *mnt; int res = 0; + read_lock(¤t->fs->lock); our_vfsmnt = mntget(current->fs->rootmnt); base = dget(current->fs->root); @@ -549,11 +552,11 @@ static int proc_check_chroot(struct dentry *root, struct vfsmount *vfsmnt) de = root; mnt = vfsmnt; - while (vfsmnt != our_vfsmnt) { - if (vfsmnt == vfsmnt->mnt_parent) + while (mnt != our_vfsmnt) { + if (mnt == mnt->mnt_parent) goto out; - de = vfsmnt->mnt_mountpoint; - vfsmnt = vfsmnt->mnt_parent; + de = mnt->mnt_mountpoint; + mnt = mnt->mnt_parent; } if (!is_subdir(de, base)) @@ -564,7 +567,7 @@ exit: dput(base); mntput(our_vfsmnt); dput(root); - mntput(mnt); + mntput(vfsmnt); return res; out: spin_unlock(&vfsmount_lock); diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c index 596b4b4f1cc..abdf068bc27 100644 --- a/fs/proc/proc_devtree.c +++ b/fs/proc/proc_devtree.c @@ -52,7 +52,8 @@ static int property_read_proc(char *page, char **start, off_t off, * Add a property to a node */ static struct proc_dir_entry * -__proc_device_tree_add_prop(struct proc_dir_entry *de, struct property *pp) +__proc_device_tree_add_prop(struct proc_dir_entry *de, struct property *pp, + const char *name) { struct proc_dir_entry *ent; @@ -60,14 +61,14 @@ __proc_device_tree_add_prop(struct proc_dir_entry *de, struct property *pp) * Unfortunately proc_register puts each new entry * at the beginning of the list. So we rearrange them. */ - ent = create_proc_read_entry(pp->name, - strncmp(pp->name, "security-", 9) + ent = create_proc_read_entry(name, + strncmp(name, "security-", 9) ? S_IRUGO : S_IRUSR, de, property_read_proc, pp); if (ent == NULL) return NULL; - if (!strncmp(pp->name, "security-", 9)) + if (!strncmp(name, "security-", 9)) ent->size = 0; /* don't leak number of password chars */ else ent->size = pp->length; @@ -78,7 +79,7 @@ __proc_device_tree_add_prop(struct proc_dir_entry *de, struct property *pp) void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop) { - __proc_device_tree_add_prop(pde, prop); + __proc_device_tree_add_prop(pde, prop, prop->name); } void proc_device_tree_remove_prop(struct proc_dir_entry *pde, @@ -106,6 +107,69 @@ void proc_device_tree_update_prop(struct proc_dir_entry *pde, } /* + * Various dodgy firmware might give us nodes and/or properties with + * conflicting names. That's generally ok, except for exporting via /proc, + * so munge names here to ensure they're unique. + */ + +static int duplicate_name(struct proc_dir_entry *de, const char *name) +{ + struct proc_dir_entry *ent; + int found = 0; + + spin_lock(&proc_subdir_lock); + + for (ent = de->subdir; ent != NULL; ent = ent->next) { + if (strcmp(ent->name, name) == 0) { + found = 1; + break; + } + } + + spin_unlock(&proc_subdir_lock); + + return found; +} + +static const char *fixup_name(struct device_node *np, struct proc_dir_entry *de, + const char *name) +{ + char *fixed_name; + int fixup_len = strlen(name) + 2 + 1; /* name + #x + \0 */ + int i = 1, size; + +realloc: + fixed_name = kmalloc(fixup_len, GFP_KERNEL); + if (fixed_name == NULL) { + printk(KERN_ERR "device-tree: Out of memory trying to fixup " + "name \"%s\"\n", name); + return name; + } + +retry: + size = snprintf(fixed_name, fixup_len, "%s#%d", name, i); + size++; /* account for NULL */ + + if (size > fixup_len) { + /* We ran out of space, free and reallocate. */ + kfree(fixed_name); + fixup_len = size; + goto realloc; + } + + if (duplicate_name(de, fixed_name)) { + /* Multiple duplicates. Retry with a different offset. */ + i++; + goto retry; + } + + printk(KERN_WARNING "device-tree: Duplicate name in %s, " + "renamed to \"%s\"\n", np->full_name, fixed_name); + + return fixed_name; +} + +/* * Process a node, adding entries for its children and its properties. */ void proc_device_tree_add_node(struct device_node *np, @@ -118,37 +182,30 @@ void proc_device_tree_add_node(struct device_node *np, set_node_proc_entry(np, de); for (child = NULL; (child = of_get_next_child(np, child));) { + /* Use everything after the last slash, or the full name */ p = strrchr(child->full_name, '/'); if (!p) p = child->full_name; else ++p; + + if (duplicate_name(de, p)) + p = fixup_name(np, de, p); + ent = proc_mkdir(p, de); if (ent == 0) break; proc_device_tree_add_node(child, ent); } of_node_put(child); + for (pp = np->properties; pp != 0; pp = pp->next) { - /* - * Yet another Apple device-tree bogosity: on some machines, - * they have properties & nodes with the same name. Those - * properties are quite unimportant for us though, thus we - * simply "skip" them here, but we do have to check. - */ - spin_lock(&proc_subdir_lock); - for (ent = de->subdir; ent != NULL; ent = ent->next) - if (!strcmp(ent->name, pp->name)) - break; - spin_unlock(&proc_subdir_lock); - if (ent != NULL) { - printk(KERN_WARNING "device-tree: property \"%s\" name" - " conflicts with node in %s\n", pp->name, - np->full_name); - continue; - } + p = pp->name; + + if (duplicate_name(de, p)) + p = fixup_name(np, de, p); - ent = __proc_device_tree_add_prop(de, pp); + ent = __proc_device_tree_add_prop(de, pp, p); if (ent == 0) break; } diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index ef5a3323f4b..5c10ea15742 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -249,144 +249,60 @@ static int cpuinfo_open(struct inode *inode, struct file *file) return seq_open(file, &cpuinfo_op); } -enum devinfo_states { - CHR_HDR, - CHR_LIST, - BLK_HDR, - BLK_LIST, - DEVINFO_DONE -}; - -struct devinfo_state { - void *chrdev; - void *blkdev; - unsigned int num_records; - unsigned int cur_record; - enum devinfo_states state; +static struct file_operations proc_cpuinfo_operations = { + .open = cpuinfo_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, }; -static void *devinfo_start(struct seq_file *f, loff_t *pos) +static int devinfo_show(struct seq_file *f, void *v) { - struct devinfo_state *info = f->private; + int i = *(loff_t *) v; - if (*pos) { - if ((info) && (*pos <= info->num_records)) - return info; - return NULL; + if (i < CHRDEV_MAJOR_HASH_SIZE) { + if (i == 0) + seq_printf(f, "Character devices:\n"); + chrdev_show(f, i); + } else { + i -= CHRDEV_MAJOR_HASH_SIZE; + if (i == 0) + seq_printf(f, "\nBlock devices:\n"); + blkdev_show(f, i); } - info = kmalloc(sizeof(*info), GFP_KERNEL); - f->private = info; - info->chrdev = acquire_chrdev_list(); - info->blkdev = acquire_blkdev_list(); - info->state = CHR_HDR; - info->num_records = count_chrdev_list(); - info->num_records += count_blkdev_list(); - info->num_records += 2; /* Character and Block headers */ - *pos = 1; - info->cur_record = *pos; - return info; + return 0; } -static void *devinfo_next(struct seq_file *f, void *v, loff_t *pos) +static void *devinfo_start(struct seq_file *f, loff_t *pos) { - int idummy; - char *ndummy; - struct devinfo_state *info = f->private; - - switch (info->state) { - case CHR_HDR: - info->state = CHR_LIST; - (*pos)++; - /*fallthrough*/ - case CHR_LIST: - if (get_chrdev_info(info->chrdev,&idummy,&ndummy)) { - /* - * The character dev list is complete - */ - info->state = BLK_HDR; - } else { - info->chrdev = get_next_chrdev(info->chrdev); - } - (*pos)++; - break; - case BLK_HDR: - info->state = BLK_LIST; - (*pos)++; - /*fallthrough*/ - case BLK_LIST: - if (get_blkdev_info(info->blkdev,&idummy,&ndummy)) { - /* - * The block dev list is complete - */ - info->state = DEVINFO_DONE; - } else { - info->blkdev = get_next_blkdev(info->blkdev); - } - (*pos)++; - break; - case DEVINFO_DONE: - (*pos)++; - info->cur_record = *pos; - info = NULL; - break; - default: - break; - } - if (info) - info->cur_record = *pos; - return info; + if (*pos < (BLKDEV_MAJOR_HASH_SIZE + CHRDEV_MAJOR_HASH_SIZE)) + return pos; + return NULL; } -static void devinfo_stop(struct seq_file *f, void *v) +static void *devinfo_next(struct seq_file *f, void *v, loff_t *pos) { - struct devinfo_state *info = f->private; - - if (info) { - release_chrdev_list(info->chrdev); - release_blkdev_list(info->blkdev); - f->private = NULL; - kfree(info); - } + (*pos)++; + if (*pos >= (BLKDEV_MAJOR_HASH_SIZE + CHRDEV_MAJOR_HASH_SIZE)) + return NULL; + return pos; } -static int devinfo_show(struct seq_file *f, void *arg) -{ - int major; - char *name; - struct devinfo_state *info = f->private; - - switch(info->state) { - case CHR_HDR: - seq_printf(f,"Character devices:\n"); - /* fallthrough */ - case CHR_LIST: - if (!get_chrdev_info(info->chrdev,&major,&name)) - seq_printf(f,"%3d %s\n",major,name); - break; - case BLK_HDR: - seq_printf(f,"\nBlock devices:\n"); - /* fallthrough */ - case BLK_LIST: - if (!get_blkdev_info(info->blkdev,&major,&name)) - seq_printf(f,"%3d %s\n",major,name); - break; - default: - break; - } - - return 0; +static void devinfo_stop(struct seq_file *f, void *v) +{ + /* Nothing to do */ } -static struct seq_operations devinfo_op = { - .start = devinfo_start, - .next = devinfo_next, - .stop = devinfo_stop, - .show = devinfo_show, +static struct seq_operations devinfo_ops = { + .start = devinfo_start, + .next = devinfo_next, + .stop = devinfo_stop, + .show = devinfo_show }; -static int devinfo_open(struct inode *inode, struct file *file) +static int devinfo_open(struct inode *inode, struct file *filp) { - return seq_open(file, &devinfo_op); + return seq_open(filp, &devinfo_ops); } static struct file_operations proc_devinfo_operations = { @@ -396,13 +312,6 @@ static struct file_operations proc_devinfo_operations = { .release = seq_release, }; -static struct file_operations proc_cpuinfo_operations = { - .open = cpuinfo_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - extern struct seq_operations vmstat_op; static int vmstat_open(struct inode *inode, struct file *file) { diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c index 7efa73d44c9..20d4b2237fc 100644 --- a/fs/proc/vmcore.c +++ b/fs/proc/vmcore.c @@ -103,8 +103,8 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos) { ssize_t acc = 0, tmp; - size_t tsz, nr_bytes; - u64 start; + size_t tsz; + u64 start, nr_bytes; struct vmcore *curr_m = NULL; if (buflen == 0 || *fpos >= vmcore_size) |