]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - fs/proc/base.c
procfs task exe symlink
[net-next-2.6.git] / fs / proc / base.c
index a04b3db7a296f8017913adbbbada28569241e587..b48ddb1199459530560a35cfeda4271cda3698b2 100644 (file)
@@ -604,6 +604,19 @@ static const struct file_operations proc_mounts_operations = {
        .poll           = mounts_poll,
 };
 
+static int mountinfo_open(struct inode *inode, struct file *file)
+{
+       return mounts_open_common(inode, file, &mountinfo_op);
+}
+
+static const struct file_operations proc_mountinfo_operations = {
+       .open           = mountinfo_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = mounts_release,
+       .poll           = mounts_poll,
+};
+
 static int mountstats_open(struct inode *inode, struct file *file)
 {
        return mounts_open_common(inode, file, &mountstats_op);
@@ -1168,6 +1181,81 @@ static const struct file_operations proc_pid_sched_operations = {
 
 #endif
 
+/*
+ * 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.
+ * Callers must hold down_write() on the mm's mmap_sem for these
+ */
+void added_exe_file_vma(struct mm_struct *mm)
+{
+       mm->num_exe_file_vmas++;
+}
+
+void removed_exe_file_vma(struct mm_struct *mm)
+{
+       mm->num_exe_file_vmas--;
+       if ((mm->num_exe_file_vmas == 0) && mm->exe_file){
+               fput(mm->exe_file);
+               mm->exe_file = NULL;
+       }
+
+}
+
+void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file)
+{
+       if (new_exe_file)
+               get_file(new_exe_file);
+       if (mm->exe_file)
+               fput(mm->exe_file);
+       mm->exe_file = new_exe_file;
+       mm->num_exe_file_vmas = 0;
+}
+
+struct file *get_mm_exe_file(struct mm_struct *mm)
+{
+       struct file *exe_file;
+
+       /* We need mmap_sem to protect against races with removal of
+        * VM_EXECUTABLE vmas */
+       down_read(&mm->mmap_sem);
+       exe_file = mm->exe_file;
+       if (exe_file)
+               get_file(exe_file);
+       up_read(&mm->mmap_sem);
+       return exe_file;
+}
+
+void dup_mm_exe_file(struct mm_struct *oldmm, struct mm_struct *newmm)
+{
+       /* It's safe to write the exe_file pointer without exe_file_lock because
+        * this is called during fork when the task is not yet in /proc */
+       newmm->exe_file = get_mm_exe_file(oldmm);
+}
+
+static int proc_exe_link(struct inode *inode, struct path *exe_path)
+{
+       struct task_struct *task;
+       struct mm_struct *mm;
+       struct file *exe_file;
+
+       task = get_proc_task(inode);
+       if (!task)
+               return -ENOENT;
+       mm = get_task_mm(task);
+       put_task_struct(task);
+       if (!mm)
+               return -ENOENT;
+       exe_file = get_mm_exe_file(mm);
+       mmput(mm);
+       if (exe_file) {
+               *exe_path = exe_file->f_path;
+               path_get(&exe_file->f_path);
+               fput(exe_file);
+               return 0;
+       } else
+               return -ENOENT;
+}
+
 static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
        struct inode *inode = dentry->d_inode;
@@ -2303,6 +2391,7 @@ static const struct pid_entry tgid_base_stuff[] = {
        LNK("root",       root),
        LNK("exe",        exe),
        REG("mounts",     S_IRUGO, mounts),
+       REG("mountinfo",  S_IRUGO, mountinfo),
        REG("mountstats", S_IRUSR, mountstats),
 #ifdef CONFIG_PROC_PAGE_MONITOR
        REG("clear_refs", S_IWUSR, clear_refs),
@@ -2635,6 +2724,7 @@ static const struct pid_entry tid_base_stuff[] = {
        LNK("root",      root),
        LNK("exe",       exe),
        REG("mounts",    S_IRUGO, mounts),
+       REG("mountinfo",  S_IRUGO, mountinfo),
 #ifdef CONFIG_PROC_PAGE_MONITOR
        REG("clear_refs", S_IWUSR, clear_refs),
        REG("smaps",     S_IRUGO, smaps),