procfs: fix tid fdinfo
[safe/jmp/linux-2.6] / fs / proc / base.c
index 175db25..8418fcc 100644 (file)
@@ -81,6 +81,7 @@
 #include <linux/elf.h>
 #include <linux/pid_namespace.h>
 #include <linux/fs_struct.h>
+#include <linux/slab.h>
 #include "internal.h"
 
 /* NOTE:
@@ -442,12 +443,13 @@ static const struct file_operations proc_lstats_operations = {
 unsigned long badness(struct task_struct *p, unsigned long uptime);
 static int proc_oom_score(struct task_struct *task, char *buffer)
 {
-       unsigned long points;
+       unsigned long points = 0;
        struct timespec uptime;
 
        do_posix_clock_monotonic_gettime(&uptime);
        read_lock(&tasklist_lock);
-       points = badness(task, uptime.tv_sec);
+       if (pid_alive(task))
+               points = badness(task, uptime.tv_sec);
        read_unlock(&tasklist_lock);
        return sprintf(buffer, "%lu\n", points);
 }
@@ -458,7 +460,7 @@ struct limit_names {
 };
 
 static const struct limit_names lnames[RLIM_NLIMITS] = {
-       [RLIMIT_CPU] = {"Max cpu time", "ms"},
+       [RLIMIT_CPU] = {"Max cpu time", "seconds"},
        [RLIMIT_FSIZE] = {"Max file size", "bytes"},
        [RLIMIT_DATA] = {"Max data size", "bytes"},
        [RLIMIT_STACK] = {"Max stack size", "bytes"},
@@ -647,17 +649,11 @@ static int mounts_release(struct inode *inode, struct file *file)
 static unsigned mounts_poll(struct file *file, poll_table *wait)
 {
        struct proc_mounts *p = file->private_data;
-       struct mnt_namespace *ns = p->ns;
        unsigned res = POLLIN | POLLRDNORM;
 
-       poll_wait(file, &ns->poll, wait);
-
-       spin_lock(&vfsmount_lock);
-       if (p->event != ns->event) {
-               p->event = ns->event;
+       poll_wait(file, &p->ns->poll, wait);
+       if (mnt_had_events(p))
                res |= POLLERR | POLLPRI;
-       }
-       spin_unlock(&vfsmount_lock);
 
        return res;
 }
@@ -999,16 +995,17 @@ static ssize_t oom_adjust_read(struct file *file, char __user *buf,
        struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
        char buffer[PROC_NUMBUF];
        size_t len;
-       int oom_adjust;
+       int oom_adjust = OOM_DISABLE;
+       unsigned long flags;
 
        if (!task)
                return -ESRCH;
-       task_lock(task);
-       if (task->mm)
-               oom_adjust = task->mm->oom_adj;
-       else
-               oom_adjust = OOM_DISABLE;
-       task_unlock(task);
+
+       if (lock_task_sighand(task, &flags)) {
+               oom_adjust = task->signal->oom_adj;
+               unlock_task_sighand(task, &flags);
+       }
+
        put_task_struct(task);
 
        len = snprintf(buffer, sizeof(buffer), "%i\n", oom_adjust);
@@ -1020,40 +1017,44 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf,
                                size_t count, loff_t *ppos)
 {
        struct task_struct *task;
-       char buffer[PROC_NUMBUF], *end;
-       int oom_adjust;
+       char buffer[PROC_NUMBUF];
+       long oom_adjust;
+       unsigned long flags;
+       int err;
 
        memset(buffer, 0, sizeof(buffer));
        if (count > sizeof(buffer) - 1)
                count = sizeof(buffer) - 1;
        if (copy_from_user(buffer, buf, count))
                return -EFAULT;
-       oom_adjust = simple_strtol(buffer, &end, 0);
+
+       err = strict_strtol(strstrip(buffer), 0, &oom_adjust);
+       if (err)
+               return -EINVAL;
        if ((oom_adjust < OOM_ADJUST_MIN || oom_adjust > OOM_ADJUST_MAX) &&
             oom_adjust != OOM_DISABLE)
                return -EINVAL;
-       if (*end == '\n')
-               end++;
+
        task = get_proc_task(file->f_path.dentry->d_inode);
        if (!task)
                return -ESRCH;
-       task_lock(task);
-       if (!task->mm) {
-               task_unlock(task);
+       if (!lock_task_sighand(task, &flags)) {
                put_task_struct(task);
-               return -EINVAL;
+               return -ESRCH;
        }
-       if (oom_adjust < task->mm->oom_adj && !capable(CAP_SYS_RESOURCE)) {
-               task_unlock(task);
+
+       if (oom_adjust < task->signal->oom_adj && !capable(CAP_SYS_RESOURCE)) {
+               unlock_task_sighand(task, &flags);
                put_task_struct(task);
                return -EACCES;
        }
-       task->mm->oom_adj = oom_adjust;
-       task_unlock(task);
+
+       task->signal->oom_adj = oom_adjust;
+
+       unlock_task_sighand(task, &flags);
        put_task_struct(task);
-       if (end - buffer == 0)
-               return -EIO;
-       return end - buffer;
+
+       return count;
 }
 
 static const struct file_operations proc_oom_adjust_operations = {
@@ -1090,8 +1091,12 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf,
        if (!capable(CAP_AUDIT_CONTROL))
                return -EPERM;
 
-       if (current != pid_task(proc_pid(inode), PIDTYPE_PID))
+       rcu_read_lock();
+       if (current != pid_task(proc_pid(inode), PIDTYPE_PID)) {
+               rcu_read_unlock();
                return -EPERM;
+       }
+       rcu_read_unlock();
 
        if (count >= PAGE_SIZE)
                count = PAGE_SIZE - 1;
@@ -1182,17 +1187,16 @@ static ssize_t proc_fault_inject_write(struct file * file,
                count = sizeof(buffer) - 1;
        if (copy_from_user(buffer, buf, count))
                return -EFAULT;
-       make_it_fail = simple_strtol(buffer, &end, 0);
-       if (*end == '\n')
-               end++;
+       make_it_fail = simple_strtol(strstrip(buffer), &end, 0);
+       if (*end)
+               return -EINVAL;
        task = get_proc_task(file->f_dentry->d_inode);
        if (!task)
                return -ESRCH;
        task->make_it_fail = make_it_fail;
        put_task_struct(task);
-       if (end - buffer == 0)
-               return -EIO;
-       return end - buffer;
+
+       return count;
 }
 
 static const struct file_operations proc_fault_inject_operations = {
@@ -1261,6 +1265,72 @@ static const struct file_operations proc_pid_sched_operations = {
 
 #endif
 
+static ssize_t comm_write(struct file *file, const char __user *buf,
+                               size_t count, loff_t *offset)
+{
+       struct inode *inode = file->f_path.dentry->d_inode;
+       struct task_struct *p;
+       char buffer[TASK_COMM_LEN];
+
+       memset(buffer, 0, sizeof(buffer));
+       if (count > sizeof(buffer) - 1)
+               count = sizeof(buffer) - 1;
+       if (copy_from_user(buffer, buf, count))
+               return -EFAULT;
+
+       p = get_proc_task(inode);
+       if (!p)
+               return -ESRCH;
+
+       if (same_thread_group(current, p))
+               set_task_comm(p, buffer);
+       else
+               count = -EINVAL;
+
+       put_task_struct(p);
+
+       return count;
+}
+
+static int comm_show(struct seq_file *m, void *v)
+{
+       struct inode *inode = m->private;
+       struct task_struct *p;
+
+       p = get_proc_task(inode);
+       if (!p)
+               return -ESRCH;
+
+       task_lock(p);
+       seq_printf(m, "%s\n", p->comm);
+       task_unlock(p);
+
+       put_task_struct(p);
+
+       return 0;
+}
+
+static int comm_open(struct inode *inode, struct file *filp)
+{
+       int ret;
+
+       ret = single_open(filp, comm_show, NULL);
+       if (!ret) {
+               struct seq_file *m = filp->private_data;
+
+               m->private = inode;
+       }
+       return ret;
+}
+
+static const struct file_operations proc_pid_set_comm_operations = {
+       .open           = comm_open,
+       .read           = seq_read,
+       .write          = comm_write,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 /*
  * We added or removed a vma mapping the executable. The vmas are only mapped
  * during exec and are not mapped with the mmap system call.
@@ -1349,7 +1419,6 @@ static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
                goto out;
 
        error = PROC_I(inode)->op.proc_get_link(inode, &nd->path);
-       nd->last_type = LAST_BIND;
 out:
        return ERR_PTR(error);
 }
@@ -2196,7 +2265,7 @@ static const struct inode_operations proc_attr_dir_inode_operations = {
 
 #endif
 
-#if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE)
+#ifdef CONFIG_ELF_CORE
 static ssize_t proc_coredump_filter_read(struct file *file, char __user *buf,
                                         size_t count, loff_t *ppos)
 {
@@ -2300,16 +2369,30 @@ static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
        struct pid_namespace *ns = dentry->d_sb->s_fs_info;
        pid_t tgid = task_tgid_nr_ns(current, ns);
-       char tmp[PROC_NUMBUF];
-       if (!tgid)
-               return ERR_PTR(-ENOENT);
-       sprintf(tmp, "%d", task_tgid_nr_ns(current, ns));
-       return ERR_PTR(vfs_follow_link(nd,tmp));
+       char *name = ERR_PTR(-ENOENT);
+       if (tgid) {
+               name = __getname();
+               if (!name)
+                       name = ERR_PTR(-ENOMEM);
+               else
+                       sprintf(name, "%d", tgid);
+       }
+       nd_set_link(nd, name);
+       return NULL;
+}
+
+static void proc_self_put_link(struct dentry *dentry, struct nameidata *nd,
+                               void *cookie)
+{
+       char *s = nd_get_link(nd);
+       if (!IS_ERR(s))
+               __putname(s);
 }
 
 static const struct inode_operations proc_self_inode_operations = {
        .readlink       = proc_self_readlink,
        .follow_link    = proc_self_follow_link,
+       .put_link       = proc_self_put_link,
 };
 
 /*
@@ -2500,6 +2583,7 @@ static const struct pid_entry tgid_base_stuff[] = {
 #ifdef CONFIG_SCHED_DEBUG
        REG("sched",      S_IRUGO|S_IWUSR, proc_pid_sched_operations),
 #endif
+       REG("comm",      S_IRUGO|S_IWUSR, proc_pid_set_comm_operations),
 #ifdef CONFIG_HAVE_ARCH_TRACEHOOK
        INF("syscall",    S_IRUSR, proc_pid_syscall),
 #endif
@@ -2552,7 +2636,7 @@ static const struct pid_entry tgid_base_stuff[] = {
 #ifdef CONFIG_FAULT_INJECTION
        REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations),
 #endif
-#if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE)
+#ifdef CONFIG_ELF_CORE
        REG("coredump_filter", S_IRUGO|S_IWUSR, proc_coredump_filter_operations),
 #endif
 #ifdef CONFIG_TASK_IO_ACCOUNTING
@@ -2593,15 +2677,11 @@ static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid)
        name.len = snprintf(buf, sizeof(buf), "%d", pid);
        dentry = d_hash_and_lookup(mnt->mnt_root, &name);
        if (dentry) {
-               if (!(current->flags & PF_EXITING))
-                       shrink_dcache_parent(dentry);
+               shrink_dcache_parent(dentry);
                d_drop(dentry);
                dput(dentry);
        }
 
-       if (tgid == 0)
-               goto out;
-
        name.name = buf;
        name.len = snprintf(buf, sizeof(buf), "%d", tgid);
        leader = d_hash_and_lookup(mnt->mnt_root, &name);
@@ -2658,17 +2738,16 @@ out:
 void proc_flush_task(struct task_struct *task)
 {
        int i;
-       struct pid *pid, *tgid = NULL;
+       struct pid *pid, *tgid;
        struct upid *upid;
 
        pid = task_pid(task);
-       if (thread_group_leader(task))
-               tgid = task_tgid(task);
+       tgid = task_tgid(task);
 
        for (i = 0; i <= pid->level; i++) {
                upid = &pid->numbers[i];
                proc_flush_task_mnt(upid->ns->proc_mnt, upid->nr,
-                       tgid ? tgid->numbers[i].nr : 0);
+                                       tgid->numbers[i].nr);
        }
 
        upid = &pid->numbers[pid->level];
@@ -2830,7 +2909,7 @@ out_no_task:
  */
 static const struct pid_entry tid_base_stuff[] = {
        DIR("fd",        S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations),
-       DIR("fdinfo",    S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fd_operations),
+       DIR("fdinfo",    S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fdinfo_operations),
        REG("environ",   S_IRUSR, proc_environ_operations),
        INF("auxv",      S_IRUSR, proc_pid_auxv),
        ONE("status",    S_IRUGO, proc_pid_status),
@@ -2839,6 +2918,7 @@ static const struct pid_entry tid_base_stuff[] = {
 #ifdef CONFIG_SCHED_DEBUG
        REG("sched",     S_IRUGO|S_IWUSR, proc_pid_sched_operations),
 #endif
+       REG("comm",      S_IRUGO|S_IWUSR, proc_pid_set_comm_operations),
 #ifdef CONFIG_HAVE_ARCH_TRACEHOOK
        INF("syscall",   S_IRUSR, proc_pid_syscall),
 #endif