Subject: [PATCH] Allow all pspaces to be visbile simultaneously in proc From: Eric W. Biederman Date: 1130027713 -0600 --- fs/proc/array.c | 36 +++++++------- fs/proc/base.c | 124 +++++++++++++++++++++++++++++++++++------------ fs/proc/internal.h | 15 ++++-- fs/proc/root.c | 63 +++++++++++++++++++----- include/linux/pid.h | 2 + include/linux/proc_fs.h | 10 +--- include/linux/pspace.h | 30 ++++++++--- 7 files changed, 196 insertions(+), 84 deletions(-) 869e7382a64e42052fc1203200f43da4a27b8a22 diff --git a/fs/proc/array.c b/fs/proc/array.c index d39c0a4..3224fc5 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -157,7 +157,7 @@ static inline const char * get_task_stat return *p; } -static inline char * task_state(struct task_struct *p, char *buffer) +static inline char * task_state(struct pspace *pspace, struct task_struct *p, char *buffer) { struct group_info *group_info; int g; @@ -165,10 +165,10 @@ static inline char * task_state(struct t struct fdtable *fdt = NULL; read_lock(&tasklist_lock); - tgid = pid_to_user(p->tgid); - pid = pid_to_user(p->pid); - ptgid = pid_alive(p) ? pid_to_user(p->group_leader->real_parent->tgid) : 0; - tppid = pid_alive(p) ? pid_to_user(p->parent->pid) : 0; + tgid = pspace_pid_to_user(pspace, p->tgid); + pid = pspace_pid_to_user(pspace, p->pid); + ptgid = pid_alive(p) ? pspace_pid_to_user(pspace, p->group_leader->real_parent->tgid) : 0; + tppid = pid_alive(p) ? pspace_pid_to_user(pspace, p->parent->pid) : 0; buffer += sprintf(buffer, "State:\t%s\n" "SleepAVG:\t%lu%%\n" @@ -297,13 +297,13 @@ static inline char *task_cap(struct task cap_t(p->cap_effective)); } -int proc_pid_status(struct task_struct *task, char * buffer) +int proc_pid_status(struct pspace *pspace, struct task_struct *task, char * buffer) { char * orig = buffer; struct mm_struct *mm = get_task_mm(task); buffer = task_name(task, buffer); - buffer = task_state(task, buffer); + buffer = task_state(pspace, task, buffer); if (mm) { buffer = task_mem(mm, buffer); @@ -318,7 +318,7 @@ int proc_pid_status(struct task_struct * return buffer - orig; } -static int do_task_stat(struct task_struct *task, char * buffer, int whole) +static int do_task_stat(struct pspace *pspace, struct task_struct *task, char * buffer, int whole) { unsigned long vsize, eip, esp, wchan = ~0UL; long priority, nice; @@ -374,11 +374,11 @@ static int do_task_stat(struct task_stru } if (task->signal) { if (task->signal->tty) { - tty_pgrp = pid_to_user(task->signal->tty->pgrp); + tty_pgrp = pspace_pid_to_user(pspace, task->signal->tty->pgrp); tty_nr = new_encode_dev(tty_devnum(task->signal->tty)); } - pgid = pid_to_user(process_group(task)); - sid = pid_to_user(task->signal->session); + pgid = pspace_pid_to_user(pspace, process_group(task)); + sid = pspace_pid_to_user(pspace, task->signal->session); cmin_flt = task->signal->cmin_flt; cmaj_flt = task->signal->cmaj_flt; cutime = task->signal->cutime; @@ -393,7 +393,7 @@ static int do_task_stat(struct task_stru it_real_value = task->signal->it_real_value; } ppid = pid_alive(task) ? - pid_to_user(task->group_leader->real_parent->tgid) : 0; + pspace_pid_to_user(pspace, task->group_leader->real_parent->tgid) : 0; read_unlock(&tasklist_lock); if (!whole || num_threads<2) @@ -420,7 +420,7 @@ static int do_task_stat(struct task_stru res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ %lu %lu %lu %lu %lu %ld %ld %ld %ld %d %ld %llu %lu %ld %lu %lu %lu %lu %lu \ %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu\n", - pid_to_user(task->pid), + pspace_pid_to_user(pspace, task->pid), tcomm, state, ppid, @@ -470,17 +470,17 @@ static int do_task_stat(struct task_stru return res; } -int proc_tid_stat(struct task_struct *task, char * buffer) +int proc_tid_stat(struct pspace *pspace, struct task_struct *task, char * buffer) { - return do_task_stat(task, buffer, 0); + return do_task_stat(pspace, task, buffer, 0); } -int proc_tgid_stat(struct task_struct *task, char * buffer) +int proc_tgid_stat(struct pspace *pspace, struct task_struct *task, char * buffer) { - return do_task_stat(task, buffer, 1); + return do_task_stat(pspace, task, buffer, 1); } -int proc_pid_statm(struct task_struct *task, char *buffer) +int proc_pid_statm(struct pspace *pspace, struct task_struct *task, char *buffer) { int size = 0, resident = 0, shared = 0, text = 0, lib = 0, data = 0; struct mm_struct *mm = get_task_mm(task); diff --git a/fs/proc/base.c b/fs/proc/base.c index fb5fef8..d56862d 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -79,6 +79,10 @@ * inumbers of the rest of procfs (currently those are in 0x0000--0xffff). * As soon as we'll get a separate superblock we will be able to forget * about magical ranges too. + * + * Note the inumbers used here are totally meaninless except as they + * give hints to user space. The code does not use the inode numbers + * except to return them to user space. */ #define fake_ino(pid,ino) (((pid)<<16)|(ino)) @@ -86,6 +90,7 @@ enum pid_directory_inos { PROC_TGID_INO = 2, PROC_TGID_TASK, + PROC_TGID_PSPACE, PROC_TGID_STATUS, PROC_TGID_MEM, #ifdef CONFIG_SECCOMP @@ -177,6 +182,7 @@ struct pid_entry { static struct pid_entry tgid_base_stuff[] = { E(PROC_TGID_TASK, "task", S_IFDIR|S_IRUGO|S_IXUGO), + E(PROC_TGID_PSPACE, "pspace", S_IFDIR|S_IRUGO|S_IXUGO), E(PROC_TGID_FD, "fd", S_IFDIR|S_IRUSR|S_IXUSR), E(PROC_TGID_ENVIRON, "environ", S_IFREG|S_IRUSR), E(PROC_TGID_AUXV, "auxv", S_IFREG|S_IRUSR), @@ -396,7 +402,7 @@ static int proc_task_root_link(struct in (task->state == TASK_STOPPED || task->state == TASK_TRACED) && \ security_ptrace(current,task) == 0)) -static int proc_pid_environ(struct task_struct *task, char * buffer) +static int proc_pid_environ(struct pspace *pspace, struct task_struct *task, char * buffer) { int res = 0; struct mm_struct *mm = get_task_mm(task); @@ -412,7 +418,7 @@ static int proc_pid_environ(struct task_ return res; } -static int proc_pid_cmdline(struct task_struct *task, char * buffer) +static int proc_pid_cmdline(struct pspace *pspace, struct task_struct *task, char * buffer) { int res = 0; unsigned int len; @@ -449,7 +455,7 @@ out: return res; } -static int proc_pid_auxv(struct task_struct *task, char *buffer) +static int proc_pid_auxv(struct pspace *pspace, struct task_struct *task, char *buffer) { int res = 0; struct mm_struct *mm = get_task_mm(task); @@ -473,7 +479,7 @@ static int proc_pid_auxv(struct task_str * Provides a wchan file via kallsyms in a proper one-value-per-file format. * Returns the resolved symbol. If that fails, simply return the address. */ -static int proc_pid_wchan(struct task_struct *task, char *buffer) +static int proc_pid_wchan(struct pspace *pspace, struct task_struct *task, char *buffer) { char *modname; const char *sym_name; @@ -504,7 +510,7 @@ static int proc_pid_schedstat(struct tas /* 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) +static int proc_oom_score(struct pspace *pspace, struct task_struct *task, char *buffer) { unsigned long points; struct timespec uptime; @@ -698,6 +704,7 @@ static ssize_t proc_info_read(struct fil struct inode * inode = file->f_dentry->d_inode; unsigned long page; ssize_t length; + struct pspace *pspace = proc_pspace(inode); struct task_struct *task = proc_task(inode); if (count > PROC_BLOCK_SIZE) @@ -705,7 +712,7 @@ static ssize_t proc_info_read(struct fil if (!(page = __get_free_page(GFP_KERNEL))) return -ENOMEM; - length = PROC_I(inode)->op.proc_read(task, (char*)page); + length = PROC_I(inode)->op.proc_read(pspace, task, (char*)page); if (length >= 0) length = simple_read_from_buffer(buf, count, ppos, (char *)page, length); @@ -1256,7 +1263,8 @@ static int task_dumpable(struct task_str } -static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task, int ino) +static struct inode *proc_pid_make_inode(struct super_block * sb, + struct pspace *pspace, struct task_struct *task, int ino) { struct inode * inode; struct proc_inode *ei; @@ -1271,15 +1279,17 @@ static struct inode *proc_pid_make_inode ei = PROC_I(inode); ei->task = NULL; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; - inode->i_ino = fake_ino(task->pid, ino); + inode->i_ino = fake_ino(task->pid - pspace->offset, ino); if (!pid_alive(task)) goto out_unlock; /* - * grab the reference to task. + * grab references to the task and pspace; */ + get_pspace(pspace); get_task_struct(task); + ei->pspace = pspace; ei->task = task; ei->type = ino; inode->i_uid = 0; @@ -1398,7 +1408,7 @@ static struct dentry_operations pid_base /* Lookups */ -unsigned proc_name_to_int(struct qstr *qstr) +static unsigned name_to_int(struct qstr *qstr) { const char *name = qstr->name; int len = qstr->len; @@ -1423,8 +1433,9 @@ out: /* SMP-safe */ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, struct nameidata *nd) { + struct pspace *pspace = proc_pspace(dir); struct task_struct *task = proc_task(dir); - unsigned fd = proc_name_to_int(&dentry->d_name); + unsigned fd = name_to_int(&dentry->d_name); struct file * file; struct files_struct * files; struct inode *inode; @@ -1435,7 +1446,7 @@ static struct dentry *proc_lookupfd(stru if (!pid_alive(task)) goto out; - inode = proc_pid_make_inode(dir->i_sb, task, PROC_TID_FD_DIR+fd); + inode = proc_pid_make_inode(dir->i_sb, pspace, task, PROC_TID_FD_DIR+fd); if (!inode) goto out; ei = PROC_I(inode); @@ -1469,6 +1480,34 @@ out: return ERR_PTR(-ENOENT); } +static void *proc_pspace_follow_link(struct vfsmount *mnt, struct dentry *parent, struct nameidata *nd) +{ + /* Follow the pseudo link to the per pspace root of the /proc + * filesystem + */ + struct task_struct *task = proc_task(nd->dentry->d_inode); + struct dentry *dentry; + dentry = get_pspace_root_dentry(parent->d_sb, task->pspace); + + if (!IS_ERR(dentry)) { + struct vfsmount *cover; + cover = alloc_vfsmnt(NULL); + cover->mnt_sb = dentry->d_sb; + cover->mnt_root = dget(dentry); + cover->mnt_mountpoint = parent; + cover->mnt_parent = mnt; + mntget(mnt); + mntput(nd->mnt); + nd->mnt = cover; + atomic_inc(&dentry->d_sb->s_active); + } + /* Forget nd->dentry */ + dput(nd->dentry); + nd->dentry = dentry; + + return NULL; +} + static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldir); static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd); @@ -1495,6 +1534,13 @@ static struct inode_operations proc_task .permission = proc_task_permission, }; +/* + * Magic pspace link/mount + */ +static struct inode_operations proc_pspace_inode_operations = { + .follow_link = proc_pspace_follow_link, +}; + #ifdef CONFIG_SECURITY static ssize_t proc_pid_attr_read(struct file * file, char __user * buf, size_t count, loff_t *ppos) @@ -1558,7 +1604,7 @@ static struct file_operations proc_tgid_ static struct inode_operations proc_tgid_attr_inode_operations; #endif -static int get_tid_list(int index, unsigned int *tids, struct inode *dir); +static int get_tid_list(struct pspace *pspace, int index, unsigned int *tids, struct inode *dir); /* SMP-safe */ static struct dentry *proc_pident_lookup(struct inode *dir, @@ -1567,6 +1613,7 @@ static struct dentry *proc_pident_lookup { struct inode *inode; int error; + struct pspace *pspace = proc_pspace(dir); struct task_struct *task = proc_task(dir); struct pid_entry *p; struct proc_inode *ei; @@ -1587,7 +1634,7 @@ static struct dentry *proc_pident_lookup goto out; error = -EINVAL; - inode = proc_pid_make_inode(dir->i_sb, task, p->type); + inode = proc_pid_make_inode(dir->i_sb, pspace, task, p->type); if (!inode) goto out; @@ -1599,10 +1646,14 @@ static struct dentry *proc_pident_lookup */ switch(p->type) { case PROC_TGID_TASK: - inode->i_nlink = 2 + get_tid_list(2, NULL, dir); + inode->i_nlink = 2 + get_tid_list(pspace, 2, NULL, dir); inode->i_op = &proc_task_inode_operations; inode->i_fop = &proc_task_operations; break; + case PROC_TGID_PSPACE: + inode->i_nlink = 2; + inode->i_op = &proc_pspace_inode_operations; + break; case PROC_TID_FD: case PROC_TGID_FD: inode->i_nlink = 2; @@ -1834,15 +1885,17 @@ static struct inode_operations proc_tid_ static int proc_self_readlink(struct dentry *dentry, char __user *buffer, int buflen) { + struct pspace *pspace = proc_pspace(dentry->d_parent->d_inode); char tmp[30]; - sprintf(tmp, "%d", pid_to_user(current->tgid)); + sprintf(tmp, "%d", pspace_pid_to_user(pspace, current->tgid)); return vfs_readlink(dentry,buffer,buflen,tmp); } static void *proc_self_follow_link(struct vfsmount *mnt, struct dentry *dentry, struct nameidata *nd) { + struct pspace *pspace = proc_pspace(nd->dentry->d_inode); char tmp[30]; - sprintf(tmp, "%d", pid_to_user(current->tgid)); + sprintf(tmp, "%d", pspace_pid_to_user(pspace, current->tgid)); return ERR_PTR(vfs_follow_link(nd,tmp)); } @@ -1908,13 +1961,16 @@ void proc_pid_flush(struct dentry *proc_ /* SMP-safe */ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd) { + struct pspace *pspace = proc_pspace(nd->dentry->d_inode); struct task_struct *task; struct inode *inode; struct proc_inode *ei; unsigned tgid; int died; - if (dentry->d_name.len == 4 && !memcmp(dentry->d_name.name,"self",4)) { + if (dentry->d_name.len == 4 && !memcmp(dentry->d_name.name,"self",4) && + (pspace == current->pspace)) + { inode = new_inode(dir->i_sb); if (!inode) return ERR_PTR(-ENOMEM); @@ -1929,10 +1985,10 @@ struct dentry *proc_pid_lookup(struct in d_add(dentry, inode); return NULL; } - tgid = proc_name_to_int(&dentry->d_name); + tgid = name_to_int(&dentry->d_name); if (tgid == ~0U) goto out; - tgid = pid_from_user(tgid); + tgid = pspace_pid_from_user(pspace, tgid); read_lock(&tasklist_lock); task = find_task_by_pid(tgid); @@ -1942,7 +1998,7 @@ struct dentry *proc_pid_lookup(struct in if (!task) goto out; - inode = proc_pid_make_inode(dir->i_sb, task, PROC_TGID_INO); + inode = proc_pid_make_inode(dir->i_sb, pspace, task, PROC_TGID_INO); if (!inode) { @@ -1984,15 +2040,16 @@ out: /* SMP-safe */ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd) { + struct pspace *pspace = proc_pspace(dir); struct task_struct *task; struct task_struct *leader = proc_task(dir); struct inode *inode; unsigned tid; - tid = proc_name_to_int(&dentry->d_name); + tid = name_to_int(&dentry->d_name); if (tid == ~0U) goto out; - tid = pid_from_user(tid); + tid = pspace_pid_from_user(pspace, tid); read_lock(&tasklist_lock); task = find_task_by_pid(tid); @@ -2004,7 +2061,7 @@ static struct dentry *proc_task_lookup(s if (leader->tgid != task->tgid) goto out_drop_task; - inode = proc_pid_make_inode(dir->i_sb, task, PROC_TID_INO); + inode = proc_pid_make_inode(dir->i_sb, pspace, task, PROC_TID_INO); if (!inode) @@ -2039,7 +2096,7 @@ out: * tasklist lock while doing this, and we must release it before * we actually do the filldir itself, so we use a temp buffer.. */ -static int get_tgid_list(int index, unsigned long version, unsigned int *tgids) +static int get_tgid_list(struct pspace *pspace, int index, unsigned long version, unsigned int *tgids) { struct task_struct *p; int nr_tgids = 0; @@ -2062,11 +2119,11 @@ static int get_tgid_list(int index, unsi int tgid = p->pid; if (!pid_alive(p)) continue; - if (!pid_visible(p->tgid)) + if (!pspace_pid_visible(pspace, p->tgid)) continue; if (--index >= 0) continue; - tgids[nr_tgids] = pid_to_user(tgid); + tgids[nr_tgids] = pspace_pid_to_user(pspace, tgid); nr_tgids++; if (nr_tgids >= PROC_MAXPIDS) break; @@ -2080,7 +2137,7 @@ static int get_tgid_list(int index, unsi * tasklist lock while doing this, and we must release it before * we actually do the filldir itself, so we use a temp buffer.. */ -static int get_tid_list(int index, unsigned int *tids, struct inode *dir) +static int get_tid_list(struct pspace *pspace, int index, unsigned int *tids, struct inode *dir) { struct task_struct *leader_task = proc_task(dir); struct task_struct *task = leader_task; @@ -2093,13 +2150,13 @@ static int get_tid_list(int index, unsig * unlinked task, which cannot be used to access the task-list * via next_thread(). */ - if (pid_alive(task) && pid_visible(task->pid)) do { + if (pid_alive(task) && pspace_pid_visible(pspace, task->pid)) do { int tid = task->pid; if (--index >= 0) continue; if (tids != NULL) - tids[nr_tids] = pid_to_user(tid); + tids[nr_tids] = pspace_pid_to_user(pspace, tid); nr_tids++; if (nr_tids >= PROC_MAXPIDS) break; @@ -2111,6 +2168,7 @@ static int get_tid_list(int index, unsig /* for the /proc/ directory itself, after non-process stuff has been done */ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) { + struct pspace *pspace = proc_pspace(filp->f_dentry->d_inode); unsigned int tgid_array[PROC_MAXPIDS]; char buf[PROC_NUMBUF]; unsigned int nr = filp->f_pos - FIRST_PROCESS_ENTRY; @@ -2131,7 +2189,7 @@ int proc_pid_readdir(struct file * filp, next_tgid = filp->f_version; filp->f_version = 0; for (;;) { - nr_tgids = get_tgid_list(nr, next_tgid, tgid_array); + nr_tgids = get_tgid_list(pspace, nr, next_tgid, tgid_array); if (!nr_tgids) { /* no more entries ! */ break; @@ -2147,6 +2205,7 @@ int proc_pid_readdir(struct file * filp, for (i=0;if_dentry->d_inode); unsigned int tid_array[PROC_MAXPIDS]; char buf[PROC_NUMBUF]; unsigned int nr_tids, i; @@ -2198,7 +2258,7 @@ static int proc_task_readdir(struct file /* fall through */ } - nr_tids = get_tid_list(pos, tid_array, inode); + nr_tids = get_tid_list(pspace, pos, tid_array, inode); inode->i_nlink = pos + nr_tids; for (i = 0; i < nr_tids; i++) { diff --git a/fs/proc/internal.h b/fs/proc/internal.h index fb6df85..f39dd98 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -32,11 +32,11 @@ do { \ extern void create_seq_entry(char *name, mode_t mode, struct file_operations *f); extern int proc_exe_link(struct inode *, struct dentry **, struct vfsmount **); -extern int proc_tid_stat(struct task_struct *, char *); -extern int proc_tgid_stat(struct task_struct *, char *); -extern int proc_pid_status(struct task_struct *, char *); -extern int proc_pid_statm(struct task_struct *, char *); -extern unsigned proc_name_to_int(struct qstr *qstr); +extern int proc_tid_stat(struct pspace *, struct task_struct *, char *); +extern int proc_tgid_stat(struct pspace *, struct task_struct *, char *); +extern int proc_pid_status(struct pspace *, struct task_struct *, char *); +extern int proc_pid_statm(struct pspace *,struct task_struct *, char *); +extern struct dentry *get_pspace_root_dentry(struct super_block *, struct pspace *); static inline struct task_struct *proc_task(struct inode *inode) { @@ -48,4 +48,9 @@ static inline int proc_type(struct inode return PROC_I(inode)->type; } +static inline struct pspace *proc_pspace(struct inode *inode) +{ + return PROC_I(inode)->pspace; +} + extern void free_proc_entry(struct proc_dir_entry *); diff --git a/fs/proc/root.c b/fs/proc/root.c index 9d28720..21735dd 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -22,6 +22,9 @@ #include #include "internal.h" +static struct file_operations pspace_root_operations; +static struct inode_operations pspace_root_inode_operations; + struct proc_dir_entry *proc_net, *proc_net_stat, *proc_bus, *proc_root_fs, *proc_root_driver; #ifdef CONFIG_SYSCTL @@ -83,11 +86,11 @@ void __init proc_root_init(void) proc_bus = proc_mkdir("bus", NULL); } -static void *proc_root_follow_link(struct vfsmount *mnt, struct dentry *parent, struct nameidata *nd) +struct dentry *get_pspace_root_dentry(struct super_block *sb, struct pspace *pspace) { - /* Follow the pseudo link to the per pspace root of the /proc - * filesystem + /* Find a pspace root of the /proc filesystem */ + struct dentry *parent = sb->s_root; struct inode *root = parent->d_inode; struct dentry *dentry; struct qstr str; @@ -99,24 +102,52 @@ static void *proc_root_follow_link(struc * additional vfsmount is added, which allows me to skip * the dentry name when building the d_path name. */ - str.name = (const unsigned char *)¤t->pspace; - str.len = sizeof(current->pspace); + str.name = (const unsigned char *)&pspace; + str.len = sizeof(pspace); str.hash = full_name_hash(str.name, str.len); /* See if I already have the pspace dentry and if not create it */ down(&root->i_sem); dentry = d_lookup(parent, &str); if (!dentry) { + struct inode *inode; dentry = d_alloc(parent, &str); if (dentry) { - dentry->d_fsdata = current->pspace; - d_add(dentry, root); - __iget(root); + inode = new_inode(parent->d_sb); + } + if (dentry && inode) { + struct proc_inode *ei = PROC_I(inode); + get_pspace(pspace); + ei->pspace = pspace; + ei->task = NULL; + ei->pde = PDE(root); + inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; + inode->i_uid = 0; + inode->i_gid = 0; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->i_nlink = 2; + inode->i_op = &pspace_root_inode_operations; + inode->i_fop = &pspace_root_operations; + inode->i_ino = PROC_ROOT_INO; + d_add(dentry, inode); } else { + dput(dentry); dentry = ERR_PTR(-ENOMEM); } } up(&root->i_sem); + return dentry; +} + + +static void *proc_root_follow_link(struct vfsmount *mnt, struct dentry *parent, struct nameidata *nd) +{ + /* Follow the pseudo link to the per pspace root of the /proc + * filesystem + */ + struct dentry *dentry; + dentry = get_pspace_root_dentry(parent->d_sb, current->pspace); + if (!IS_ERR(dentry)) { struct vfsmount *cover; cover = alloc_vfsmnt(NULL); @@ -138,13 +169,14 @@ static void *proc_root_follow_link(struc static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry, struct nameidata *nd) { + struct pspace *pspace = proc_pspace(nd->dentry->d_inode); /* * nr_processes is actually protected by the tasklist_lock; * however, it's conventional to do reads, especially for * reporting, without any locking whatsoever. */ if (dir->i_ino == PROC_ROOT_INO) /* check for safety... */ - dir->i_nlink = proc_root.nlink + current->pspace->nr_processes; + dir->i_nlink = proc_root.nlink + pspace->nr_processes; if (!proc_lookup(dir, dentry, nd)) { return NULL; @@ -180,7 +212,7 @@ static int proc_root_readdir(struct file * directories. Thus we don't use the generic * directory handling functions for that.. */ -static struct file_operations proc_root_operations = { +static struct file_operations pspace_root_operations = { .read = generic_read_dir, .readdir = proc_root_readdir, }; @@ -188,11 +220,15 @@ static struct file_operations proc_root_ /* * proc root can do almost nothing.. */ -static struct inode_operations proc_root_inode_operations = { +static struct inode_operations pspace_root_inode_operations = { .lookup = proc_root_lookup, -#if 1 +}; + +/* + * proc root can do almost nothing.. + */ +static struct inode_operations proc_root_inode_operations = { .follow_link = proc_root_follow_link, -#endif }; /* @@ -205,7 +241,6 @@ struct proc_dir_entry proc_root = { .mode = S_IFDIR | S_IRUGO | S_IXUGO, .nlink = 2, .proc_iops = &proc_root_inode_operations, - .proc_fops = &proc_root_operations, .parent = &proc_root, }; diff --git a/include/linux/pid.h b/include/linux/pid.h index fedeced..8a75e6c 100644 --- a/include/linux/pid.h +++ b/include/linux/pid.h @@ -4,9 +4,11 @@ enum pid_type { PIDTYPE_PID, + PIDTYPE_ALTPID, PIDTYPE_TGID, PIDTYPE_PGID, PIDTYPE_SID, + PIDTYPE_PSPACE, PIDTYPE_MAX }; diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 3f640ea..ef48ded 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -242,12 +242,14 @@ static inline void kclist_add(struct kco extern void kclist_add(struct kcore_list *, void *, size_t); #endif +struct pspace; struct proc_inode { + struct pspace *pspace; struct task_struct *task; int type; union { int (*proc_get_link)(struct inode *, struct dentry **, struct vfsmount **); - int (*proc_read)(struct task_struct *task, char *page); + int (*proc_read)(struct pspace *pspace, struct task_struct *task, char *page); } op; struct proc_dir_entry *pde; struct inode vfs_inode; @@ -263,12 +265,6 @@ static inline struct proc_dir_entry *PDE return PROC_I(inode)->pde; } -struct pspace; -static inline struct pspace *PROC_P(const struct dentry *dentry) -{ - return dentry->d_fsdata; -} - extern int proc_pspace_root_dentry(struct pspace *pspace); #endif /* _LINUX_PROC_FS_H */ diff --git a/include/linux/pspace.h b/include/linux/pspace.h index 6a05210..b6043bc 100644 --- a/include/linux/pspace.h +++ b/include/linux/pspace.h @@ -30,27 +30,41 @@ extern struct pspace init_pspace; #define INVALID_PID 0x7fffffff -static inline int pid_from_user(int pid) +static inline int pspace_pid_from_user(struct pspace *pspace, int pid) { - if (pid < current->pspace->max) - pid += current->pspace->offset; + if (pid < pspace->max) + pid += pspace->offset; else pid = INVALID_PID; return pid; } -static inline int pid_to_user(int pid) +static inline int pspace_pid_to_user(struct pspace *pspace, int pid) { - pid = pid - current->pspace->offset; - if ((pid <= 0) || (pid >= current->pspace->max)) + pid = pid - pspace->offset; + if ((pid <= 0) || (pid >= pspace->max)) pid = 0; return pid; } +static inline int pspace_pid_visible(struct pspace *pspace, int pid) +{ + return pspace_pid_to_user(pspace, pid) > 0; +} + +static inline int pid_from_user(int pid) +{ + return pspace_pid_from_user(current->pspace, pid); +} + +static inline int pid_to_user(int pid) +{ + return pspace_pid_to_user(current->pspace, pid); +} + static inline int pid_visible(int pid) { - pid = pid_to_user(pid); - return pid > 0; + return pspace_pid_visible(current->pspace, pid); } static inline void get_pspace(struct pspace *pspace) -- 1.0.GIT