]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/proc/base.c
Merge master.kernel.org:/home/rmk/linux-2.6-arm-smp
[linux-2.6-omap-h63xx.git] / fs / proc / base.c
index 491f2d9f89acd93fabb0d0067ee76f329bc14c2b..23db452ab428c9896a96aad29217100e67aeb78a 100644 (file)
  *  go into icache. We cache the reference to task_struct upon lookup too.
  *  Eventually it should become a filesystem in its own. We don't use the
  *  rest of procfs anymore.
+ *
+ *
+ *  Changelog:
+ *  17-Jan-2005
+ *  Allan Bezerra
+ *  Bruna Moreira <bruna.moreira@indt.org.br>
+ *  Edjard Mota <edjard.mota@indt.org.br>
+ *  Ilias Biris <ilias.biris@indt.org.br>
+ *  Mauricio Lin <mauricio.lin@indt.org.br>
+ *
+ *  Embedded Linux Lab - 10LE Instituto Nokia de Tecnologia - INdT
+ *
+ *  A new process specific entry (smaps) included in /proc. It shows the
+ *  size of rss for each memory area. The maps entry lacks information
+ *  about physical memory size (rss) for each mapped file, i.e.,
+ *  rss information for executables and library files.
+ *  This additional information is useful for any tools that need to know
+ *  about physical memory consumption for a process specific library.
+ *
+ *  Changelog:
+ *  21-Feb-2005
+ *  Embedded Linux Lab - 10LE Instituto Nokia de Tecnologia - INdT
+ *  Pud inclusion in the page table walking.
+ *
+ *  ChangeLog:
+ *  10-Mar-2005
+ *  10LE Instituto Nokia de Tecnologia - INdT:
+ *  A better way to walks through the page table as suggested by Hugh Dickins.
+ *
+ *  Simo Piiroinen <simo.piiroinen@nokia.com>:
+ *  Smaps information related to shared, private, clean and dirty pages.
+ *
+ *  Paul Mundt <paul.mundt@nokia.com>:
+ *  Overall revision about smaps.
  */
 
 #include <asm/uaccess.h>
@@ -28,6 +62,7 @@
 #include <linux/namespace.h>
 #include <linux/mm.h>
 #include <linux/smp_lock.h>
+#include <linux/rcupdate.h>
 #include <linux/kallsyms.h>
 #include <linux/mount.h>
 #include <linux/security.h>
@@ -65,8 +100,10 @@ enum pid_directory_inos {
        PROC_TGID_STAT,
        PROC_TGID_STATM,
        PROC_TGID_MAPS,
+       PROC_TGID_NUMA_MAPS,
        PROC_TGID_MOUNTS,
        PROC_TGID_WCHAN,
+       PROC_TGID_SMAPS,
 #ifdef CONFIG_SCHEDSTATS
        PROC_TGID_SCHEDSTAT,
 #endif
@@ -83,7 +120,6 @@ enum pid_directory_inos {
 #ifdef CONFIG_AUDITSYSCALL
        PROC_TGID_LOGINUID,
 #endif
-       PROC_TGID_FD_DIR,
        PROC_TGID_OOM_SCORE,
        PROC_TGID_OOM_ADJUST,
        PROC_TID_INO,
@@ -102,8 +138,10 @@ enum pid_directory_inos {
        PROC_TID_STAT,
        PROC_TID_STATM,
        PROC_TID_MAPS,
+       PROC_TID_NUMA_MAPS,
        PROC_TID_MOUNTS,
        PROC_TID_WCHAN,
+       PROC_TID_SMAPS,
 #ifdef CONFIG_SCHEDSTATS
        PROC_TID_SCHEDSTAT,
 #endif
@@ -120,9 +158,11 @@ enum pid_directory_inos {
 #ifdef CONFIG_AUDITSYSCALL
        PROC_TID_LOGINUID,
 #endif
-       PROC_TID_FD_DIR = 0x8000,       /* 0x8000-0xffff */
        PROC_TID_OOM_SCORE,
        PROC_TID_OOM_ADJUST,
+
+       /* Add new entries before this */
+       PROC_TID_FD_DIR = 0x8000,       /* 0x8000-0xffff */
 };
 
 struct pid_entry {
@@ -144,6 +184,9 @@ static struct pid_entry tgid_base_stuff[] = {
        E(PROC_TGID_STAT,      "stat",    S_IFREG|S_IRUGO),
        E(PROC_TGID_STATM,     "statm",   S_IFREG|S_IRUGO),
        E(PROC_TGID_MAPS,      "maps",    S_IFREG|S_IRUGO),
+#ifdef CONFIG_NUMA
+       E(PROC_TGID_NUMA_MAPS, "numa_maps", S_IFREG|S_IRUGO),
+#endif
        E(PROC_TGID_MEM,       "mem",     S_IFREG|S_IRUSR|S_IWUSR),
 #ifdef CONFIG_SECCOMP
        E(PROC_TGID_SECCOMP,   "seccomp", S_IFREG|S_IRUSR|S_IWUSR),
@@ -152,6 +195,7 @@ static struct pid_entry tgid_base_stuff[] = {
        E(PROC_TGID_ROOT,      "root",    S_IFLNK|S_IRWXUGO),
        E(PROC_TGID_EXE,       "exe",     S_IFLNK|S_IRWXUGO),
        E(PROC_TGID_MOUNTS,    "mounts",  S_IFREG|S_IRUGO),
+       E(PROC_TGID_SMAPS,     "smaps",   S_IFREG|S_IRUGO),
 #ifdef CONFIG_SECURITY
        E(PROC_TGID_ATTR,      "attr",    S_IFDIR|S_IRUGO|S_IXUGO),
 #endif
@@ -180,6 +224,9 @@ static struct pid_entry tid_base_stuff[] = {
        E(PROC_TID_STAT,       "stat",    S_IFREG|S_IRUGO),
        E(PROC_TID_STATM,      "statm",   S_IFREG|S_IRUGO),
        E(PROC_TID_MAPS,       "maps",    S_IFREG|S_IRUGO),
+#ifdef CONFIG_NUMA
+       E(PROC_TID_NUMA_MAPS,  "numa_maps",    S_IFREG|S_IRUGO),
+#endif
        E(PROC_TID_MEM,        "mem",     S_IFREG|S_IRUSR|S_IWUSR),
 #ifdef CONFIG_SECCOMP
        E(PROC_TID_SECCOMP,    "seccomp", S_IFREG|S_IRUSR|S_IWUSR),
@@ -188,6 +235,7 @@ static struct pid_entry tid_base_stuff[] = {
        E(PROC_TID_ROOT,       "root",    S_IFLNK|S_IRWXUGO),
        E(PROC_TID_EXE,        "exe",     S_IFLNK|S_IRWXUGO),
        E(PROC_TID_MOUNTS,     "mounts",  S_IFREG|S_IRUGO),
+       E(PROC_TID_SMAPS,      "smaps",   S_IFREG|S_IRUGO),
 #ifdef CONFIG_SECURITY
        E(PROC_TID_ATTR,       "attr",    S_IFDIR|S_IRUGO|S_IXUGO),
 #endif
@@ -236,30 +284,36 @@ static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsm
 
        files = get_files_struct(task);
        if (files) {
-               spin_lock(&files->file_lock);
+               rcu_read_lock();
                file = fcheck_files(files, fd);
                if (file) {
                        *mnt = mntget(file->f_vfsmnt);
                        *dentry = dget(file->f_dentry);
-                       spin_unlock(&files->file_lock);
+                       rcu_read_unlock();
                        put_files_struct(files);
                        return 0;
                }
-               spin_unlock(&files->file_lock);
+               rcu_read_unlock();
                put_files_struct(files);
        }
        return -ENOENT;
 }
 
-static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
+static struct fs_struct *get_fs_struct(struct task_struct *task)
 {
        struct fs_struct *fs;
-       int result = -ENOENT;
-       task_lock(proc_task(inode));
-       fs = proc_task(inode)->fs;
+       task_lock(task);
+       fs = task->fs;
        if(fs)
                atomic_inc(&fs->count);
-       task_unlock(proc_task(inode));
+       task_unlock(task);
+       return fs;
+}
+
+static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
+{
+       struct fs_struct *fs = get_fs_struct(proc_task(inode));
+       int result = -ENOENT;
        if (fs) {
                read_lock(&fs->lock);
                *mnt = mntget(fs->pwdmnt);
@@ -273,13 +327,8 @@ static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfs
 
 static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
 {
-       struct fs_struct *fs;
+       struct fs_struct *fs = get_fs_struct(proc_task(inode));
        int result = -ENOENT;
-       task_lock(proc_task(inode));
-       fs = proc_task(inode)->fs;
-       if(fs)
-               atomic_inc(&fs->count);
-       task_unlock(proc_task(inode));
        if (fs) {
                read_lock(&fs->lock);
                *mnt = mntget(fs->rootmnt);
@@ -298,33 +347,6 @@ static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vf
         (task->state == TASK_STOPPED || task->state == TASK_TRACED) && \
         security_ptrace(current,task) == 0))
 
-static int may_ptrace_attach(struct task_struct *task)
-{
-       int retval = 0;
-
-       task_lock(task);
-
-       if (!task->mm)
-               goto out;
-       if (((current->uid != task->euid) ||
-            (current->uid != task->suid) ||
-            (current->uid != task->uid) ||
-            (current->gid != task->egid) ||
-            (current->gid != task->sgid) ||
-            (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
-               goto out;
-       rmb();
-       if (task->mm->dumpable != 1 && !capable(CAP_SYS_PTRACE))
-               goto out;
-       if (security_ptrace(current, task))
-               goto out;
-
-       retval = 1;
-out:
-       task_unlock(task);
-       return retval;
-}
-
 static int proc_pid_environ(struct task_struct *task, char * buffer)
 {
        int res = 0;
@@ -334,7 +356,7 @@ static int proc_pid_environ(struct task_struct *task, char * buffer)
                if (len > PAGE_SIZE)
                        len = PAGE_SIZE;
                res = access_process_vm(task, mm->env_start, buffer, len, 0);
-               if (!may_ptrace_attach(task))
+               if (!ptrace_may_attach(task))
                        res = -ESRCH;
                mmput(mm);
        }
@@ -515,6 +537,46 @@ static struct file_operations proc_maps_operations = {
        .release        = seq_release,
 };
 
+#ifdef CONFIG_NUMA
+extern struct seq_operations proc_pid_numa_maps_op;
+static int numa_maps_open(struct inode *inode, struct file *file)
+{
+       struct task_struct *task = proc_task(inode);
+       int ret = seq_open(file, &proc_pid_numa_maps_op);
+       if (!ret) {
+               struct seq_file *m = file->private_data;
+               m->private = task;
+       }
+       return ret;
+}
+
+static struct file_operations proc_numa_maps_operations = {
+       .open           = numa_maps_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+#endif
+
+extern struct seq_operations proc_pid_smaps_op;
+static int smaps_open(struct inode *inode, struct file *file)
+{
+       struct task_struct *task = proc_task(inode);
+       int ret = seq_open(file, &proc_pid_smaps_op);
+       if (!ret) {
+               struct seq_file *m = file->private_data;
+               m->private = task;
+       }
+       return ret;
+}
+
+static struct file_operations proc_smaps_operations = {
+       .open           = smaps_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
 extern struct seq_operations mounts_op;
 static int mounts_open(struct inode *inode, struct file *file)
 {
@@ -597,7 +659,7 @@ static ssize_t mem_read(struct file * file, char __user * buf,
        int ret = -ESRCH;
        struct mm_struct *mm;
 
-       if (!MAY_PTRACE(task) || !may_ptrace_attach(task))
+       if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
                goto out;
 
        ret = -ENOMEM;
@@ -623,7 +685,7 @@ static ssize_t mem_read(struct file * file, char __user * buf,
 
                this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
                retval = access_process_vm(task, src, page, this_len, 0);
-               if (!retval || !MAY_PTRACE(task) || !may_ptrace_attach(task)) {
+               if (!retval || !MAY_PTRACE(task) || !ptrace_may_attach(task)) {
                        if (!ret)
                                ret = -EIO;
                        break;
@@ -661,7 +723,7 @@ static ssize_t mem_write(struct file * file, const char * buf,
        struct task_struct *task = proc_task(file->f_dentry->d_inode);
        unsigned long dst = *ppos;
 
-       if (!MAY_PTRACE(task) || !may_ptrace_attach(task))
+       if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
                return -ESRCH;
 
        page = (char *)__get_free_page(GFP_USER);
@@ -978,6 +1040,7 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
        int retval;
        char buf[NUMBUF];
        struct files_struct * files;
+       struct fdtable *fdt;
 
        retval = -ENOENT;
        if (!pid_alive(p))
@@ -1000,15 +1063,16 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
                        files = get_files_struct(p);
                        if (!files)
                                goto out;
-                       spin_lock(&files->file_lock);
+                       rcu_read_lock();
+                       fdt = files_fdtable(files);
                        for (fd = filp->f_pos-2;
-                            fd < files->max_fds;
+                            fd < fdt->max_fds;
                             fd++, filp->f_pos++) {
                                unsigned int i,j;
 
                                if (!fcheck_files(files, fd))
                                        continue;
-                               spin_unlock(&files->file_lock);
+                               rcu_read_unlock();
 
                                j = NUMBUF;
                                i = fd;
@@ -1020,12 +1084,12 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
 
                                ino = fake_ino(tid, PROC_TID_FD_DIR + fd);
                                if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino, DT_LNK) < 0) {
-                                       spin_lock(&files->file_lock);
+                                       rcu_read_lock();
                                        break;
                                }
-                               spin_lock(&files->file_lock);
+                               rcu_read_lock();
                        }
-                       spin_unlock(&files->file_lock);
+                       rcu_read_unlock();
                        put_files_struct(files);
        }
 out:
@@ -1200,9 +1264,9 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
 
        files = get_files_struct(task);
        if (files) {
-               spin_lock(&files->file_lock);
+               rcu_read_lock();
                if (fcheck_files(files, fd)) {
-                       spin_unlock(&files->file_lock);
+                       rcu_read_unlock();
                        put_files_struct(files);
                        if (task_dumpable(task)) {
                                inode->i_uid = task->euid;
@@ -1214,7 +1278,7 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
                        security_task_to_inode(task, inode);
                        return 1;
                }
-               spin_unlock(&files->file_lock);
+               rcu_read_unlock();
                put_files_struct(files);
        }
        d_drop(dentry);
@@ -1306,7 +1370,7 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
        if (!files)
                goto out_unlock;
        inode->i_mode = S_IFLNK;
-       spin_lock(&files->file_lock);
+       rcu_read_lock();
        file = fcheck_files(files, fd);
        if (!file)
                goto out_unlock2;
@@ -1314,7 +1378,7 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
                inode->i_mode |= S_IRUSR | S_IXUSR;
        if (file->f_mode & 2)
                inode->i_mode |= S_IWUSR | S_IXUSR;
-       spin_unlock(&files->file_lock);
+       rcu_read_unlock();
        put_files_struct(files);
        inode->i_op = &proc_pid_link_inode_operations;
        inode->i_size = 64;
@@ -1324,7 +1388,7 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
        return NULL;
 
 out_unlock2:
-       spin_unlock(&files->file_lock);
+       rcu_read_unlock();
        put_files_struct(files);
 out_unlock:
        iput(inode);
@@ -1524,6 +1588,12 @@ static struct dentry *proc_pident_lookup(struct inode *dir,
                case PROC_TGID_MAPS:
                        inode->i_fop = &proc_maps_operations;
                        break;
+#ifdef CONFIG_NUMA
+               case PROC_TID_NUMA_MAPS:
+               case PROC_TGID_NUMA_MAPS:
+                       inode->i_fop = &proc_numa_maps_operations;
+                       break;
+#endif
                case PROC_TID_MEM:
                case PROC_TGID_MEM:
                        inode->i_op = &proc_mem_inode_operations;
@@ -1539,6 +1609,10 @@ static struct dentry *proc_pident_lookup(struct inode *dir,
                case PROC_TGID_MOUNTS:
                        inode->i_fop = &proc_mounts_operations;
                        break;
+               case PROC_TID_SMAPS:
+               case PROC_TGID_SMAPS:
+                       inode->i_fop = &proc_smaps_operations;
+                       break;
 #ifdef CONFIG_SECURITY
                case PROC_TID_ATTR:
                        inode->i_nlink = 2;