Introduce path_put()
[pandora-kernel.git] / fs / proc / base.c
index 7411bfb..c742be4 100644 (file)
  *     in /proc for a task before it execs a suid executable.
  */
 
-
-/* Worst case buffer size needed for holding an integer. */
-#define PROC_NUMBUF 13
-
 struct pid_entry {
        char *name;
        int len;
@@ -125,6 +121,10 @@ struct pid_entry {
        NOD(NAME, (S_IFREG|(MODE)),                     \
                NULL, &proc_info_file_operations,       \
                { .proc_read = &proc_##OTYPE } )
+#define ONE(NAME, MODE, OTYPE)                         \
+       NOD(NAME, (S_IFREG|(MODE)),                     \
+               NULL, &proc_single_file_operations,     \
+               { .proc_show = &proc_##OTYPE } )
 
 int maps_protect;
 EXPORT_SYMBOL(maps_protect);
@@ -199,7 +199,7 @@ static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vf
        (task == current || \
        (task->parent == current && \
        (task->ptrace & PT_PTRACED) && \
-        (task->state == TASK_STOPPED || task->state == TASK_TRACED) && \
+        (task_is_stopped_or_traced(task)) && \
         security_ptrace(current,task) == 0))
 
 struct mm_struct *mm_for_maps(struct task_struct *task)
@@ -310,6 +310,77 @@ static int proc_pid_schedstat(struct task_struct *task, char *buffer)
 }
 #endif
 
+#ifdef CONFIG_LATENCYTOP
+static int lstats_show_proc(struct seq_file *m, void *v)
+{
+       int i;
+       struct task_struct *task = m->private;
+       seq_puts(m, "Latency Top version : v0.1\n");
+
+       for (i = 0; i < 32; i++) {
+               if (task->latency_record[i].backtrace[0]) {
+                       int q;
+                       seq_printf(m, "%i %li %li ",
+                               task->latency_record[i].count,
+                               task->latency_record[i].time,
+                               task->latency_record[i].max);
+                       for (q = 0; q < LT_BACKTRACEDEPTH; q++) {
+                               char sym[KSYM_NAME_LEN];
+                               char *c;
+                               if (!task->latency_record[i].backtrace[q])
+                                       break;
+                               if (task->latency_record[i].backtrace[q] == ULONG_MAX)
+                                       break;
+                               sprint_symbol(sym, task->latency_record[i].backtrace[q]);
+                               c = strchr(sym, '+');
+                               if (c)
+                                       *c = 0;
+                               seq_printf(m, "%s ", sym);
+                       }
+                       seq_printf(m, "\n");
+               }
+
+       }
+       return 0;
+}
+
+static int lstats_open(struct inode *inode, struct file *file)
+{
+       int ret;
+       struct seq_file *m;
+       struct task_struct *task = get_proc_task(inode);
+
+       ret = single_open(file, lstats_show_proc, NULL);
+       if (!ret) {
+               m = file->private_data;
+               m->private = task;
+       }
+       return ret;
+}
+
+static ssize_t lstats_write(struct file *file, const char __user *buf,
+                           size_t count, loff_t *offs)
+{
+       struct seq_file *m;
+       struct task_struct *task;
+
+       m = file->private_data;
+       task = m->private;
+       clear_all_latency_tracing(task);
+
+       return count;
+}
+
+static const struct file_operations proc_lstats_operations = {
+       .open           = lstats_open,
+       .read           = seq_read,
+       .write          = lstats_write,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+#endif
+
 /* The badness from the OOM killer */
 unsigned long badness(struct task_struct *p, unsigned long uptime);
 static int proc_oom_score(struct task_struct *task, char *buffer)
@@ -435,7 +506,7 @@ static const struct inode_operations proc_def_inode_operations = {
        .setattr        = proc_setattr,
 };
 
-extern struct seq_operations mounts_op;
+extern const struct seq_operations mounts_op;
 struct proc_mounts {
        struct seq_file m;
        int event;
@@ -514,7 +585,7 @@ static const struct file_operations proc_mounts_operations = {
        .poll           = mounts_poll,
 };
 
-extern struct seq_operations mountstats_op;
+extern const struct seq_operations mountstats_op;
 static int mountstats_open(struct inode *inode, struct file *file)
 {
        int ret = seq_open(file, &mountstats_op);
@@ -591,6 +662,45 @@ static const struct file_operations proc_info_file_operations = {
        .read           = proc_info_read,
 };
 
+static int proc_single_show(struct seq_file *m, void *v)
+{
+       struct inode *inode = m->private;
+       struct pid_namespace *ns;
+       struct pid *pid;
+       struct task_struct *task;
+       int ret;
+
+       ns = inode->i_sb->s_fs_info;
+       pid = proc_pid(inode);
+       task = get_pid_task(pid, PIDTYPE_PID);
+       if (!task)
+               return -ESRCH;
+
+       ret = PROC_I(inode)->op.proc_show(m, ns, pid, task);
+
+       put_task_struct(task);
+       return ret;
+}
+
+static int proc_single_open(struct inode *inode, struct file *filp)
+{
+       int ret;
+       ret = single_open(filp, proc_single_show, NULL);
+       if (!ret) {
+               struct seq_file *m = filp->private_data;
+
+               m->private = inode;
+       }
+       return ret;
+}
+
+static const struct file_operations proc_single_file_operations = {
+       .open           = proc_single_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 static int mem_open(struct inode* inode, struct file* file)
 {
        file->private_data = (void*)((long)current->self_exec_id);
@@ -716,7 +826,7 @@ out_no_task:
 }
 #endif
 
-static loff_t mem_lseek(struct file * file, loff_t offset, int orig)
+loff_t mem_lseek(struct file *file, loff_t offset, int orig)
 {
        switch (orig) {
        case 0:
@@ -864,42 +974,6 @@ static const struct file_operations proc_oom_adjust_operations = {
        .write          = oom_adjust_write,
 };
 
-#ifdef CONFIG_MMU
-static ssize_t clear_refs_write(struct file *file, const char __user *buf,
-                               size_t count, loff_t *ppos)
-{
-       struct task_struct *task;
-       char buffer[PROC_NUMBUF], *end;
-       struct mm_struct *mm;
-
-       memset(buffer, 0, sizeof(buffer));
-       if (count > sizeof(buffer) - 1)
-               count = sizeof(buffer) - 1;
-       if (copy_from_user(buffer, buf, count))
-               return -EFAULT;
-       if (!simple_strtol(buffer, &end, 0))
-               return -EINVAL;
-       if (*end == '\n')
-               end++;
-       task = get_proc_task(file->f_path.dentry->d_inode);
-       if (!task)
-               return -ESRCH;
-       mm = get_task_mm(task);
-       if (mm) {
-               clear_refs_smap(mm);
-               mmput(mm);
-       }
-       put_task_struct(task);
-       if (end - buffer == 0)
-               return -EIO;
-       return end - buffer;
-}
-
-static struct file_operations proc_clear_refs_operations = {
-       .write          = clear_refs_write,
-};
-#endif
-
 #ifdef CONFIG_AUDITSYSCALL
 #define TMPBUFLEN 21
 static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
@@ -913,7 +987,7 @@ static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
        if (!task)
                return -ESRCH;
        length = scnprintf(tmpbuf, TMPBUFLEN, "%u",
-                               audit_get_loginuid(task->audit_context));
+                               audit_get_loginuid(task));
        put_task_struct(task);
        return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
 }
@@ -1020,6 +1094,7 @@ static const struct file_operations proc_fault_inject_operations = {
 };
 #endif
 
+
 #ifdef CONFIG_SCHED_DEBUG
 /*
  * Print out various scheduling related per-task fields:
@@ -1089,13 +1164,14 @@ static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
        int error = -EACCES;
 
        /* We don't need a base pointer in the /proc filesystem */
-       path_release(nd);
+       path_put(&nd->path);
 
        /* Are we allowed to snoop on the tasks file descriptors? */
        if (!proc_fd_access_allowed(inode))
                goto out;
 
-       error = PROC_I(inode)->op.proc_get_link(inode, &nd->dentry, &nd->mnt);
+       error = PROC_I(inode)->op.proc_get_link(inode, &nd->path.dentry,
+                                               &nd->path.mnt);
        nd->last_type = LAST_BIND;
 out:
        return ERR_PTR(error);
@@ -2026,15 +2102,23 @@ static const struct file_operations proc_coredump_filter_operations = {
 static int proc_self_readlink(struct dentry *dentry, char __user *buffer,
                              int buflen)
 {
+       struct pid_namespace *ns = dentry->d_sb->s_fs_info;
+       pid_t tgid = task_tgid_nr_ns(current, ns);
        char tmp[PROC_NUMBUF];
-       sprintf(tmp, "%d", task_tgid_vnr(current));
+       if (!tgid)
+               return -ENOENT;
+       sprintf(tmp, "%d", tgid);
        return vfs_readlink(dentry,buffer,buflen,tmp);
 }
 
 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];
-       sprintf(tmp, "%d", task_tgid_vnr(current));
+       if (!tgid)
+               return ERR_PTR(-ENOENT);
+       sprintf(tmp, "%d", task_tgid_nr_ns(current, ns));
        return ERR_PTR(vfs_follow_link(nd,tmp));
 }
 
@@ -2199,14 +2283,14 @@ static const struct pid_entry tgid_base_stuff[] = {
        DIR("fdinfo",     S_IRUSR|S_IXUSR, fdinfo),
        REG("environ",    S_IRUSR, environ),
        INF("auxv",       S_IRUSR, pid_auxv),
-       INF("status",     S_IRUGO, pid_status),
+       ONE("status",     S_IRUGO, pid_status),
        INF("limits",     S_IRUSR, pid_limits),
 #ifdef CONFIG_SCHED_DEBUG
        REG("sched",      S_IRUGO|S_IWUSR, pid_sched),
 #endif
        INF("cmdline",    S_IRUGO, pid_cmdline),
-       INF("stat",       S_IRUGO, tgid_stat),
-       INF("statm",      S_IRUGO, pid_statm),
+       ONE("stat",       S_IRUGO, tgid_stat),
+       ONE("statm",      S_IRUGO, pid_statm),
        REG("maps",       S_IRUGO, maps),
 #ifdef CONFIG_NUMA
        REG("numa_maps",  S_IRUGO, numa_maps),
@@ -2217,9 +2301,10 @@ static const struct pid_entry tgid_base_stuff[] = {
        LNK("exe",        exe),
        REG("mounts",     S_IRUGO, mounts),
        REG("mountstats", S_IRUSR, mountstats),
-#ifdef CONFIG_MMU
+#ifdef CONFIG_PROC_PAGE_MONITOR
        REG("clear_refs", S_IWUSR, clear_refs),
        REG("smaps",      S_IRUGO, smaps),
+       REG("pagemap",    S_IRUSR, pagemap),
 #endif
 #ifdef CONFIG_SECURITY
        DIR("attr",       S_IRUGO|S_IXUGO, attr_dir),
@@ -2230,6 +2315,9 @@ static const struct pid_entry tgid_base_stuff[] = {
 #ifdef CONFIG_SCHEDSTATS
        INF("schedstat",  S_IRUGO, pid_schedstat),
 #endif
+#ifdef CONFIG_LATENCYTOP
+       REG("latency",  S_IRUGO, lstats),
+#endif
 #ifdef CONFIG_PROC_PID_CPUSET
        REG("cpuset",     S_IRUGO, cpuset),
 #endif
@@ -2285,7 +2373,8 @@ 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) {
-               shrink_dcache_parent(dentry);
+               if (!(current->flags & PF_EXITING))
+                       shrink_dcache_parent(dentry);
                d_drop(dentry);
                dput(dentry);
        }
@@ -2525,14 +2614,14 @@ static const struct pid_entry tid_base_stuff[] = {
        DIR("fdinfo",    S_IRUSR|S_IXUSR, fdinfo),
        REG("environ",   S_IRUSR, environ),
        INF("auxv",      S_IRUSR, pid_auxv),
-       INF("status",    S_IRUGO, pid_status),
+       ONE("status",    S_IRUGO, pid_status),
        INF("limits",    S_IRUSR, pid_limits),
 #ifdef CONFIG_SCHED_DEBUG
        REG("sched",     S_IRUGO|S_IWUSR, pid_sched),
 #endif
        INF("cmdline",   S_IRUGO, pid_cmdline),
-       INF("stat",      S_IRUGO, tid_stat),
-       INF("statm",     S_IRUGO, pid_statm),
+       ONE("stat",      S_IRUGO, tid_stat),
+       ONE("statm",     S_IRUGO, pid_statm),
        REG("maps",      S_IRUGO, maps),
 #ifdef CONFIG_NUMA
        REG("numa_maps", S_IRUGO, numa_maps),
@@ -2542,9 +2631,10 @@ static const struct pid_entry tid_base_stuff[] = {
        LNK("root",      root),
        LNK("exe",       exe),
        REG("mounts",    S_IRUGO, mounts),
-#ifdef CONFIG_MMU
+#ifdef CONFIG_PROC_PAGE_MONITOR
        REG("clear_refs", S_IWUSR, clear_refs),
        REG("smaps",     S_IRUGO, smaps),
+       REG("pagemap",    S_IRUSR, pagemap),
 #endif
 #ifdef CONFIG_SECURITY
        DIR("attr",      S_IRUGO|S_IXUGO, attr_dir),
@@ -2555,6 +2645,9 @@ static const struct pid_entry tid_base_stuff[] = {
 #ifdef CONFIG_SCHEDSTATS
        INF("schedstat", S_IRUGO, pid_schedstat),
 #endif
+#ifdef CONFIG_LATENCYTOP
+       REG("latency",  S_IRUGO, lstats),
+#endif
 #ifdef CONFIG_PROC_PID_CPUSET
        REG("cpuset",    S_IRUGO, cpuset),
 #endif