diff options
Diffstat (limited to 'fs/proc/base.c')
-rw-r--r-- | fs/proc/base.c | 70 |
1 files changed, 60 insertions, 10 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; |