diff options
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/base.c | 70 | ||||
-rw-r--r-- | fs/proc/generic.c | 11 | ||||
-rw-r--r-- | fs/proc/kcore.c | 17 | ||||
-rw-r--r-- | fs/proc/proc_devtree.c | 1 | ||||
-rw-r--r-- | fs/proc/root.c | 29 |
5 files changed, 77 insertions, 51 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index 2e83c6a4e..d513987d8 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -22,6 +22,7 @@ #include <linux/stat.h> #include <linux/init.h> #include <linux/file.h> +#include <linux/string.h> /* * For hysterical raisins we keep the same inumbers as in the old procfs. @@ -651,6 +652,11 @@ static int pid_fd_revalidate(struct dentry * dentry, int flags) return 0; } +/* + * Exceptional case: normally we are not allowed to unhash a busy + * directory. In this case, however, we can do it - no aliasing problems + * due to the way we treat inodes. + */ static int pid_base_revalidate(struct dentry * dentry, int flags) { if (dentry->d_inode->u.proc_i.task->p_pptr) @@ -659,9 +665,9 @@ static int pid_base_revalidate(struct dentry * dentry, int flags) return 0; } -static void pid_delete_dentry(struct dentry * dentry) +static int pid_delete_dentry(struct dentry * dentry) { - d_drop(dentry); + return 1; } static struct dentry_operations pid_fd_dentry_operations = @@ -861,6 +867,28 @@ static struct inode_operations proc_base_inode_operations = { lookup: proc_base_lookup, }; +/* + * /proc/self: + */ +static int proc_self_readlink(struct dentry *dentry, char *buffer, int buflen) +{ + char tmp[30]; + sprintf(tmp, "%d", current->pid); + return vfs_readlink(dentry,buffer,buflen,tmp); +} + +static int proc_self_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + char tmp[30]; + sprintf(tmp, "%d", current->pid); + return vfs_follow_link(nd,tmp); +} + +static struct inode_operations proc_self_inode_operations = { + readlink: proc_self_readlink, + follow_link: proc_self_follow_link, +}; + struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry) { unsigned int pid, c; @@ -872,6 +900,23 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry) pid = 0; name = dentry->d_name.name; len = dentry->d_name.len; + if (len == 4 && !memcmp(name, "self", 4)) { + inode = get_empty_inode(); + if (!inode) + return ERR_PTR(-ENOMEM); + inode->i_sb = dir->i_sb; + inode->i_dev = dir->i_sb->s_dev; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->i_ino = fake_ino(0, PROC_PID_INO); + inode->u.proc_i.file = NULL; + inode->u.proc_i.task = NULL; + inode->i_mode = S_IFLNK|S_IRWXUGO; + inode->i_uid = inode->i_gid = 0; + inode->i_size = 64; + inode->i_op = &proc_self_inode_operations; + d_add(dentry, inode); + return NULL; + } while (len-- > 0) { c = *name - '0'; name++; @@ -916,7 +961,8 @@ void proc_pid_delete_inode(struct inode *inode) { if (inode->u.proc_i.file) fput(inode->u.proc_i.file); - free_task_struct(inode->u.proc_i.task); + if (inode->u.proc_i.task) + free_task_struct(inode->u.proc_i.task); } #define PROC_NUMBUF 10 @@ -932,7 +978,7 @@ static int get_pid_list(int index, unsigned int *pids) struct task_struct *p; int nr_pids = 0; - index -= FIRST_PROCESS_ENTRY; + index--; read_lock(&tasklist_lock); for_each_task(p) { int pid = p->pid; @@ -953,9 +999,17 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) { unsigned int pid_array[PROC_MAXPIDS]; char buf[PROC_NUMBUF]; - unsigned int nr = filp->f_pos; + unsigned int nr = filp->f_pos - FIRST_PROCESS_ENTRY; unsigned int nr_pids, i; + if (!nr) { + ino_t ino = fake_ino(0,PROC_PID_INO); + if (filldir(dirent, "self", 4, filp->f_pos, ino) < 0) + return 0; + filp->f_pos++; + nr++; + } + nr_pids = get_pid_list(nr, pid_array); for (i = 0; i < nr_pids; i++) { @@ -963,11 +1017,7 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) ino_t ino = fake_ino(pid,PROC_PID_INO); unsigned long j = PROC_NUMBUF; - do { - j--; - buf[j] = '0' + (pid % 10); - pid /= 10; - } while (pid); + do buf[--j] = '0' + (pid % 10); while (pid/=10); if (filldir(dirent, buf+j, PROC_NUMBUF-j, filp->f_pos, ino) < 0) break; diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 31e43fab9..1585657a2 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -140,9 +140,13 @@ proc_file_lseek(struct file * file, loff_t offset, int orig) { switch (orig) { case 0: + if (offset < 0) + return -EINVAL; file->f_pos = offset; return(file->f_pos); case 1: + if (offset + file->f_pos < 0) + return -EINVAL; file->f_pos += offset; return(file->f_pos); case 2: @@ -218,10 +222,9 @@ static struct inode_operations proc_link_inode_operations = { * smarter: we could keep a "volatile" flag in the * inode to indicate which ones to keep. */ -static void -proc_delete_dentry(struct dentry * dentry) +static int proc_delete_dentry(struct dentry * dentry) { - d_drop(dentry); + return 1; } static struct dentry_operations proc_dentry_operations = @@ -340,7 +343,7 @@ static struct inode_operations proc_dir_inode_operations = { lookup: proc_lookup, }; -int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp) +static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp) { int i; diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c index 13ec76b02..01db469da 100644 --- a/fs/proc/kcore.c +++ b/fs/proc/kcore.c @@ -315,13 +315,12 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t size_t elf_buflen; int num_vma; - /* XXX we need to somehow lock vmlist between here - * and after elf_kcore_store_hdr() returns. - * For now assume that num_vma does not change (TA) - */ + read_lock(&vmlist_lock); proc_root_kcore->size = size = get_kcore_size(&num_vma, &elf_buflen); - if (buflen == 0 || *fpos >= size) + if (buflen == 0 || *fpos >= size) { + read_unlock(&vmlist_lock); return 0; + } /* trim buflen to not go beyond EOF */ if (buflen > size - *fpos) @@ -335,10 +334,13 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t if (buflen < tsz) tsz = buflen; elf_buf = kmalloc(elf_buflen, GFP_ATOMIC); - if (!elf_buf) + if (!elf_buf) { + read_unlock(&vmlist_lock); return -ENOMEM; + } memset(elf_buf, 0, elf_buflen); elf_kcore_store_hdr(elf_buf, num_vma, elf_buflen); + read_unlock(&vmlist_lock); if (copy_to_user(buffer, elf_buf + *fpos, tsz)) { kfree(elf_buf); return -EFAULT; @@ -352,7 +354,8 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t /* leave now if filled buffer already */ if (buflen == 0) return acc; - } + } else + read_unlock(&vmlist_lock); /* where page 0 not mapped, write zeros into buffer */ #if defined (__i386__) || defined (__mc68000__) diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c index 88d41c3c2..c64166f78 100644 --- a/fs/proc/proc_devtree.c +++ b/fs/proc/proc_devtree.c @@ -112,7 +112,6 @@ static void add_node(struct device_node *np, struct proc_dir_entry *de) al = proc_symlink(at, de, ent->name); if (al == 0) break; - proc_register(de, al); *lastp = al; lastp = &al->next; } diff --git a/fs/proc/root.c b/fs/proc/root.c index 8088d064d..075a5843d 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -22,38 +22,9 @@ struct proc_dir_entry *proc_net, *proc_bus, *proc_root_fs, *proc_root_driver; struct proc_dir_entry *proc_sys_root; #endif -/* - * /proc/self: - */ -static int proc_self_readlink(struct dentry *dentry, char *buffer, int buflen) -{ - char tmp[30]; - sprintf(tmp, "%d", current->pid); - return vfs_readlink(dentry,buffer,buflen,tmp); -} - -static int proc_self_follow_link(struct dentry *dentry, struct nameidata *nd) -{ - char tmp[30]; - sprintf(tmp, "%d", current->pid); - return vfs_follow_link(nd,tmp); -} - -static struct inode_operations proc_self_inode_operations = { - readlink: proc_self_readlink, - follow_link: proc_self_follow_link -}; - -static struct proc_dir_entry proc_root_self = { - 0, 4, "self", - S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, 1, 0, 0, - 64, &proc_self_inode_operations, -}; - void __init proc_root_init(void) { proc_misc_init(); - proc_register(&proc_root, &proc_root_self); proc_net = proc_mkdir("net", 0); #ifdef CONFIG_SYSVIPC proc_mkdir("sysvipc", 0); |