fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / fs / proc / task_nommu.c
index 126db97..fcc5caf 100644 (file)
@@ -1,7 +1,9 @@
 
 #include <linux/mm.h>
 #include <linux/file.h>
+#include <linux/mount.h>
 #include <linux/seq_file.h>
+#include "internal.h"
 
 /*
  * Logic: we've got two memory sums for each process, "shared", and
  */
 char *task_mem(struct mm_struct *mm, char *buffer)
 {
+       struct vm_list_struct *vml;
        unsigned long bytes = 0, sbytes = 0, slack = 0;
-       struct mm_tblock_struct *tblock;
         
        down_read(&mm->mmap_sem);
-       for (tblock = &mm->context.tblock; tblock; tblock = tblock->next) {
-               if (!tblock->rblock)
+       for (vml = mm->context.vmlist; vml; vml = vml->next) {
+               if (!vml->vma)
                        continue;
-               bytes += kobjsize(tblock);
+
+               bytes += kobjsize(vml);
                if (atomic_read(&mm->mm_count) > 1 ||
-                   tblock->rblock->refcount > 1) {
-                       sbytes += kobjsize(tblock->rblock->kblock);
-                       sbytes += kobjsize(tblock->rblock);
+                   atomic_read(&vml->vma->vm_usage) > 1
+                   ) {
+                       sbytes += kobjsize((void *) vml->vma->vm_start);
+                       sbytes += kobjsize(vml->vma);
                } else {
-                       bytes += kobjsize(tblock->rblock->kblock);
-                       bytes += kobjsize(tblock->rblock);
-                       slack += kobjsize(tblock->rblock->kblock) -
-                                       tblock->rblock->size;
+                       bytes += kobjsize((void *) vml->vma->vm_start);
+                       bytes += kobjsize(vml->vma);
+                       slack += kobjsize((void *) vml->vma->vm_start) -
+                               (vml->vma->vm_end - vml->vma->vm_start);
                }
        }
 
@@ -65,61 +69,161 @@ char *task_mem(struct mm_struct *mm, char *buffer)
 
 unsigned long task_vsize(struct mm_struct *mm)
 {
-       struct mm_tblock_struct *tbp;
+       struct vm_list_struct *tbp;
        unsigned long vsize = 0;
 
-       for (tbp = &mm->context.tblock; tbp; tbp = tbp->next) {
-               if (tbp->rblock)
-                       vsize += kobjsize(tbp->rblock->kblock);
+       down_read(&mm->mmap_sem);
+       for (tbp = mm->context.vmlist; tbp; tbp = tbp->next) {
+               if (tbp->vma)
+                       vsize += kobjsize((void *) tbp->vma->vm_start);
        }
-
+       up_read(&mm->mmap_sem);
        return vsize;
 }
 
 int task_statm(struct mm_struct *mm, int *shared, int *text,
               int *data, int *resident)
 {
-       struct mm_tblock_struct *tbp;
+       struct vm_list_struct *tbp;
        int size = kobjsize(mm);
-       
-       for (tbp = &mm->context.tblock; tbp; tbp = tbp->next) {
-               if (tbp->next)
-                       size += kobjsize(tbp->next);
-               if (tbp->rblock) {
-                       size += kobjsize(tbp->rblock);
-                       size += kobjsize(tbp->rblock->kblock);
+
+       down_read(&mm->mmap_sem);
+       for (tbp = mm->context.vmlist; tbp; tbp = tbp->next) {
+               size += kobjsize(tbp);
+               if (tbp->vma) {
+                       size += kobjsize(tbp->vma);
+                       size += kobjsize((void *) tbp->vma->vm_start);
                }
        }
 
        size += (*text = mm->end_code - mm->start_code);
        size += (*data = mm->start_stack - mm->start_data);
-
+       up_read(&mm->mmap_sem);
        *resident = size;
        return size;
 }
 
+int proc_exe_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
+{
+       struct vm_list_struct *vml;
+       struct vm_area_struct *vma;
+       struct task_struct *task = get_proc_task(inode);
+       struct mm_struct *mm = get_task_mm(task);
+       int result = -ENOENT;
+
+       if (!mm)
+               goto out;
+       down_read(&mm->mmap_sem);
+
+       vml = mm->context.vmlist;
+       vma = NULL;
+       while (vml) {
+               if ((vml->vma->vm_flags & VM_EXECUTABLE) && vml->vma->vm_file) {
+                       vma = vml->vma;
+                       break;
+               }
+               vml = vml->next;
+       }
+
+       if (vma) {
+               *mnt = mntget(vma->vm_file->f_path.mnt);
+               *dentry = dget(vma->vm_file->f_path.dentry);
+               result = 0;
+       }
+
+       up_read(&mm->mmap_sem);
+       mmput(mm);
+out:
+       return result;
+}
+
 /*
- * Albert D. Cahalan suggested to fake entries for the traditional
- * sections here.  This might be worth investigating.
+ * display mapping lines for a particular process's /proc/pid/maps
  */
-static int show_map(struct seq_file *m, void *v)
+static int show_map(struct seq_file *m, void *_vml)
 {
-       return 0;
+       struct vm_list_struct *vml = _vml;
+       return nommu_vma_show(m, vml->vma);
 }
+
 static void *m_start(struct seq_file *m, loff_t *pos)
 {
+       struct proc_maps_private *priv = m->private;
+       struct vm_list_struct *vml;
+       struct mm_struct *mm;
+       loff_t n = *pos;
+
+       /* pin the task and mm whilst we play with them */
+       priv->task = get_pid_task(priv->pid, PIDTYPE_PID);
+       if (!priv->task)
+               return NULL;
+
+       mm = get_task_mm(priv->task);
+       if (!mm) {
+               put_task_struct(priv->task);
+               priv->task = NULL;
+               return NULL;
+       }
+
+       down_read(&mm->mmap_sem);
+
+       /* start from the Nth VMA */
+       for (vml = mm->context.vmlist; vml; vml = vml->next)
+               if (n-- == 0)
+                       return vml;
        return NULL;
 }
-static void m_stop(struct seq_file *m, void *v)
+
+static void m_stop(struct seq_file *m, void *_vml)
 {
+       struct proc_maps_private *priv = m->private;
+
+       if (priv->task) {
+               struct mm_struct *mm = priv->task->mm;
+               up_read(&mm->mmap_sem);
+               mmput(mm);
+               put_task_struct(priv->task);
+       }
 }
-static void *m_next(struct seq_file *m, void *v, loff_t *pos)
+
+static void *m_next(struct seq_file *m, void *_vml, loff_t *pos)
 {
-       return NULL;
+       struct vm_list_struct *vml = _vml;
+
+       (*pos)++;
+       return vml ? vml->next : NULL;
 }
-struct seq_operations proc_pid_maps_op = {
+
+static struct seq_operations proc_pid_maps_ops = {
        .start  = m_start,
        .next   = m_next,
        .stop   = m_stop,
        .show   = show_map
 };
+
+static int maps_open(struct inode *inode, struct file *file)
+{
+       struct proc_maps_private *priv;
+       int ret = -ENOMEM;
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (priv) {
+               priv->pid = proc_pid(inode);
+               ret = seq_open(file, &proc_pid_maps_ops);
+               if (!ret) {
+                       struct seq_file *m = file->private_data;
+                       m->private = priv;
+               } else {
+                       kfree(priv);
+               }
+       }
+       return ret;
+}
+
+struct file_operations proc_maps_operations = {
+       .open           = maps_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release_private,
+};
+