Subject: [PATCH] sysvipc namespace support in proc From: Eric W. Biederman Date: 1132737224 -0700 --- fs/proc/base.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/proc/root.c | 3 -- include/linux/ipc.h | 4 ++ ipc/msg.c | 40 ++++++++++++++------- ipc/sem.c | 37 +++++++++++++------ ipc/shm.c | 41 +++++++++++++++------- ipc/util.c | 97 ++++++++++----------------------------------------- ipc/util.h | 17 +++------ 8 files changed, 202 insertions(+), 130 deletions(-) 11f3a9ea8301542c1ac6ccad3d7300da84a6be65 diff --git a/fs/proc/base.c b/fs/proc/base.c index 7ad13ee..007bed3 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -71,6 +71,7 @@ #include #include #include +#include #include "internal.h" /* @@ -89,6 +90,9 @@ enum pid_directory_inos { PROC_SELF = 2, PROC_MOUNTS, +#ifdef CONFIG_SYSVIPC + PROC_SYSVIPC, +#endif PROC_SYMLINK_LAST, PROC_LOADAVG = PROC_SYMLINK_LAST, @@ -111,6 +115,9 @@ enum pid_directory_inos { PROC_TGID_MAPS, PROC_TGID_NUMA_MAPS, PROC_TGID_MOUNTS, +#ifdef CONFIG_SYSVIPC + PROC_TGID_SYSVIPC, +#endif PROC_TGID_WCHAN, PROC_TGID_SMAPS, #ifdef CONFIG_SCHEDSTATS @@ -150,6 +157,9 @@ enum pid_directory_inos { PROC_TID_MAPS, PROC_TID_NUMA_MAPS, PROC_TID_MOUNTS, +#ifdef CONFIG_SYSVIPC + PROC_TID_SYSVIPC, +#endif PROC_TID_WCHAN, PROC_TID_SMAPS, #ifdef CONFIG_SCHEDSTATS @@ -171,6 +181,11 @@ enum pid_directory_inos { PROC_TID_OOM_SCORE, PROC_TID_OOM_ADJUST, +#ifdef CONFIG_SYSVIPC + PROC_SYSVIPC_MSG, + PROC_SYSVIPC_SEM, + PROC_SYSVIPC_SHM, +#endif /* Add new entries before this */ PROC_TID_FD_DIR = 0x8000, /* 0x8000-0xffff */ }; @@ -187,6 +202,9 @@ struct pid_entry { static struct pid_entry proc_base_stuff[] = { E(PROC_SELF, "self", S_IFLNK|S_IRWXUGO), E(PROC_MOUNTS, "mounts", S_IFLNK|S_IRWXUGO), +#ifdef CONFIG_SYSVIPC + E(PROC_SYSVIPC, "sysvipc", S_IFLNK|S_IRWXUGO), +#endif E(PROC_LOADAVG, "loadavg", S_IFREG|S_IRUGO), {0,0,NULL,0} }; @@ -212,6 +230,9 @@ 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), +#ifdef CONFIG_SYSVIPC + E(PROC_TGID_SYSVIPC, "sysvipc", S_IFDIR|S_IRUGO|S_IXUGO), +#endif E(PROC_TGID_SMAPS, "smaps", S_IFREG|S_IRUGO), #ifdef CONFIG_SECURITY E(PROC_TGID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO), @@ -252,6 +273,9 @@ 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), +#ifdef CONFIG_SYSVIPC + E(PROC_TID_SYSVIPC, "sysvipc", S_IFDIR|S_IRUGO|S_IXUGO), +#endif E(PROC_TID_SMAPS, "smaps", S_IFREG|S_IRUGO), #ifdef CONFIG_SECURITY E(PROC_TID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO), @@ -295,6 +319,17 @@ static struct pid_entry tid_attr_stuff[] }; #endif +#ifdef CONFIG_SYSVIPC +static struct pid_entry proc_sysvipc_stuff[] = { + E(PROC_SYSVIPC_MSG, "msg", S_IFREG|S_IRUGO), + E(PROC_SYSVIPC_SEM, "sem", S_IFREG|S_IRUGO), + E(PROC_SYSVIPC_SHM, "shm", S_IFREG|S_IRUGO), + {0,0,NULL,0} +}; +static struct file_operations proc_sysvipc_operations; +static struct inode_operations proc_sysvipc_inode_operations; +#endif /* CONFIG_SYSVIPC */ + #undef E static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt) @@ -1138,6 +1173,20 @@ static struct inode_operations proc_moun .follow_link = proc_mounts_follow_link, }; +#ifdef CONFIG_SYSVIPC +static void *proc_sysvipc_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + static const char *sysvipc = "self/sysvipc"; + nd_set_link(nd, (char *)sysvipc); + return NULL; +} + +static struct inode_operations proc_sysvipc_link_inode_operations = { + .readlink = generic_readlink, + .follow_link = proc_sysvipc_follow_link, +}; +#endif /* CONFIG_SYSVIPC */ + #define LOAD_INT(x) ((x) >> FSHIFT) #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) @@ -1859,6 +1908,12 @@ static struct dentry *proc_pident_lookup inode->i_op = &proc_mounts_inode_operations; dentry->d_op = &self_dentry_operations; break; +#ifdef CONFIG_SYSVIPC + case PROC_SYSVIPC: + inode->i_op = &proc_sysvipc_link_inode_operations; + dentry->d_op = &self_dentry_operations; + break; +#endif /* CONFIG_SYSVIPC */ case PROC_LOADAVG: inode->i_fop = &proc_info_file_operations; ei->op.proc_read = proc_loadavg; @@ -1947,6 +2002,22 @@ static struct dentry *proc_pident_lookup case PROC_TGID_MOUNTS: inode->i_fop = &proc_mounts_operations; break; +#ifdef CONFIG_SYSVIPC + case PROC_TID_SYSVIPC: + case PROC_TGID_SYSVIPC: + inode->i_op = &proc_sysvipc_inode_operations; + inode->i_fop = &proc_sysvipc_operations; + break; + case PROC_SYSVIPC_MSG: + inode->i_fop = &proc_msg_fops; + break; + case PROC_SYSVIPC_SEM: + inode->i_fop = &proc_sem_fops; + break; + case PROC_SYSVIPC_SHM: + inode->i_fop = &proc_shm_fops; + break; +#endif /* CONFIG_SYSVIPC */ case PROC_TID_SMAPS: case PROC_TGID_SMAPS: inode->i_fop = &proc_smaps_operations; @@ -2119,6 +2190,28 @@ static struct inode_operations proc_tid_ }; #endif +#ifdef CONFIG_SYSVIPC +static int proc_sysvipc_readdir(struct file *filp, void *dirent, filldir_t filldir) +{ + return proc_pident_readdir(filp, dirent, filldir, + proc_sysvipc_stuff, ARRAY_SIZE(proc_sysvipc_stuff)); +} + +static struct file_operations proc_sysvipc_operations = { + .read = generic_read_dir, + .readdir = proc_sysvipc_readdir, +}; + +static struct dentry *proc_sysvipc_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) +{ + return proc_pident_lookup(dir, dentry, proc_sysvipc_stuff); +} + +static struct inode_operations proc_sysvipc_inode_operations = { + .lookup = proc_sysvipc_lookup, +}; +#endif /* CONFIG_SYSVIPC */ + /** * proc_pid_unhash - Unhash /proc/@pid entry from the dcache. * @p: task that should be flushed. diff --git a/fs/proc/root.c b/fs/proc/root.c index 87373d0..520661e 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -73,9 +73,6 @@ void __init proc_root_init(void) proc_net = proc_mkdir("net", NULL); proc_net_stat = proc_mkdir("net/stat", NULL); -#ifdef CONFIG_SYSVIPC - proc_mkdir("sysvipc", NULL); -#endif #ifdef CONFIG_SYSCTL proc_sys_root = proc_mkdir("sys", NULL); #endif diff --git a/include/linux/ipc.h b/include/linux/ipc.h index 0bf39fb..98b0b29 100644 --- a/include/linux/ipc.h +++ b/include/linux/ipc.h @@ -76,6 +76,10 @@ static inline int copy_sysvipc(int flags static inline void exit_sysvipc(struct task_struct *tsk) { } #endif +extern struct file_operations proc_msg_fops; +extern struct file_operations proc_sem_fops; +extern struct file_operations proc_shm_fops; + #endif /* __KERNEL__ */ #endif /* _LINUX_IPC_H */ diff --git a/ipc/msg.c b/ipc/msg.c index b9f1610..0b604d0 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -74,17 +74,6 @@ static atomic_t msg_hdrs = ATOMIC_INIT(0 static void freeque (struct msg_queue *msq, int id); static int newque (key_t key, int msgflg); static void msg_free(struct kern_ipc_perm *p); -#ifdef CONFIG_PROC_FS -static int sysvipc_msg_proc_show(struct seq_file *s, void *it); -#endif - -void __init msg_init (void) -{ - ipc_init_proc_interface("sysvipc/msg", - " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n", - &init_ipc_ns.msg_ids, - sysvipc_msg_proc_show); -} void msg_init_ipc(struct ipc_ns *ipc) { @@ -826,10 +815,14 @@ out_unlock: } #ifdef CONFIG_PROC_FS -static int sysvipc_msg_proc_show(struct seq_file *s, void *it) +static int msg_proc_show(struct seq_file *s, void *it) { struct msg_queue *msq = it; + if (it == SEQ_START_TOKEN) + return seq_puts(s, + " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n"); + return seq_printf(s, "%10d %10d %4o %10lu %10lu %5u %5u %5u %5u %5u %5u %10lu %10lu %10lu\n", msq->q_perm.key, @@ -847,4 +840,25 @@ static int sysvipc_msg_proc_show(struct msq->q_rtime, msq->q_ctime); } -#endif + +static struct seq_operations proc_msg_seqops = { + .start = ipc_proc_start, + .stop = ipc_proc_stop, + .next = ipc_proc_next, + .show = msg_proc_show, +}; + +static int msg_proc_open(struct inode *inode, struct file *file) +{ + struct task_struct *task = PROC_I(inode)->task; + return ipc_proc_open(inode, file, &proc_msg_seqops, &task->ipc->msg_ids); +} + +struct file_operations proc_msg_fops = { + .open = msg_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +#endif /* CONFIG_PROC_FS */ diff --git a/ipc/sem.c b/ipc/sem.c index 77a01e7..3b8ee83 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -90,9 +90,6 @@ static int newary (key_t, int, int); static void freeary (struct sem_array *sma, int id); static void sem_free (struct kern_ipc_perm *p); -#ifdef CONFIG_PROC_FS -static int sysvipc_sem_proc_show(struct seq_file *s, void *it); -#endif #define SEMMSL_FAST 256 /* 512 bytes on stack */ #define SEMOPM_FAST 64 /* ~ 372 bytes on stack */ @@ -114,14 +111,6 @@ int sem_ctls[4] = {SEMMSL, SEMMNS, SEMOP static int used_sems; -void __init sem_init (void) -{ - ipc_init_proc_interface("sysvipc/sem", - " key semid perms nsems uid gid cuid cgid otime ctime\n", - &init_ipc_ns.sem_ids, - sysvipc_sem_proc_show); -} - void sem_init_ipc(struct ipc_ns *ipc) { ipc_init_ids(&ipc->sem_ids, sc_semmni); @@ -1354,10 +1343,13 @@ next_entry: } #ifdef CONFIG_PROC_FS -static int sysvipc_sem_proc_show(struct seq_file *s, void *it) +static int sem_proc_show(struct seq_file *s, void *it) { struct sem_array *sma = it; + if (it == SEQ_START_TOKEN) + return seq_puts(s, + " key semid perms nsems uid gid cuid cgid otime ctime\n"); return seq_printf(s, "%10d %10d %4o %10lu %5u %5u %5u %5u %10lu %10lu\n", sma->sem_perm.key, @@ -1371,4 +1363,25 @@ static int sysvipc_sem_proc_show(struct sma->sem_otime, sma->sem_ctime); } + +static struct seq_operations proc_sem_seqops = { + .start = ipc_proc_start, + .stop = ipc_proc_stop, + .next = ipc_proc_next, + .show = sem_proc_show, +}; + +static int sem_proc_open(struct inode *inode, struct file *file) +{ + struct task_struct *task = PROC_I(inode)->task; + return ipc_proc_open(inode, file, &proc_sem_seqops, &task->ipc->sem_ids); +} + +struct file_operations proc_sem_fops = { + .open = sem_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + #endif diff --git a/ipc/shm.c b/ipc/shm.c index 1635715..e603218 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -30,6 +30,7 @@ #include #include #include +#include #include @@ -50,9 +51,6 @@ static int newseg (key_t key, int shmflg static void shm_open (struct vm_area_struct *shmd); static void shm_close (struct vm_area_struct *shmd); static void shm_free (struct kern_ipc_perm *p); -#ifdef CONFIG_PROC_FS -static int sysvipc_shm_proc_show(struct seq_file *s, void *it); -#endif size_t shm_ctlmax = SHMMAX; size_t shm_ctlall = SHMALL; @@ -60,14 +58,6 @@ int shm_ctlmni = SHMMNI; static int shm_tot; /* total number of shared memory pages */ -void __init shm_init (void) -{ - ipc_init_proc_interface("sysvipc/shm", - " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime\n", - &init_ipc_ns.shm_ids, - sysvipc_shm_proc_show); -} - void shm_init_ipc(struct ipc_ns *ipc) { ipc_init_ids(&ipc->shm_ids, 1); @@ -911,11 +901,15 @@ asmlinkage long sys_shmdt(char __user *s } #ifdef CONFIG_PROC_FS -static int sysvipc_shm_proc_show(struct seq_file *s, void *it) +static int shm_proc_show(struct seq_file *s, void *it) { struct shmid_kernel *shp = it; char *format; + if (it == SEQ_START_TOKEN) + return seq_puts(s, + " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime\n"); + #define SMALL_STRING "%10d %10d %4o %10u %5u %5u %5d %5u %5u %5u %5u %10lu %10lu %10lu\n" #define BIG_STRING "%10d %10d %4o %21u %5u %5u %5d %5u %5u %5u %5u %10lu %10lu %10lu\n" @@ -939,4 +933,25 @@ static int sysvipc_shm_proc_show(struct shp->shm_dtim, shp->shm_ctim); } -#endif + +static struct seq_operations proc_shm_seqops = { + .start = ipc_proc_start, + .stop = ipc_proc_stop, + .next = ipc_proc_next, + .show = shm_proc_show, +}; + +static int shm_proc_open(struct inode *inode, struct file *file) +{ + struct task_struct *task = PROC_I(inode)->task; + return ipc_proc_open(inode, file, &proc_shm_seqops, &task->ipc->shm_ids); +} + +struct file_operations proc_shm_fops = { + .open = shm_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +#endif /* CONFIG_PROC_FS */ diff --git a/ipc/util.c b/ipc/util.c index fd6761f..1a54abb 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -54,9 +54,6 @@ static int __init ipc_init(void) msg_init_ipc(&init_ipc_ns); sem_init_ipc(&init_ipc_ns); shm_init_ipc(&init_ipc_ns); - sem_init(); - msg_init(); - shm_init(); return 0; } __initcall(ipc_init); @@ -171,43 +168,6 @@ void put_sysvipc(struct ipc_ns *ipc) } } -#ifdef CONFIG_PROC_FS -static struct file_operations sysvipc_proc_fops; -/** - * ipc_init_proc_interface - Create a proc interface for sysipc types - * using a seq_file interface. - * @path: Path in procfs - * @header: Banner to be printed at the beginning of the file. - * @ids: ipc id table to iterate. - * @show: show routine. - */ -void __init ipc_init_proc_interface(const char *path, const char *header, - struct ipc_ids *ids, - int (*show)(struct seq_file *, void *)) -{ - struct proc_dir_entry *pde; - struct ipc_proc_iface *iface; - - iface = kmalloc(sizeof(*iface), GFP_KERNEL); - if (!iface) - return; - iface->path = path; - iface->header = header; - iface->ids = ids; - iface->show = show; - - pde = create_proc_entry(path, - S_IRUGO, /* world readable */ - NULL /* parent dir */); - if (pde) { - pde->data = iface; - pde->proc_fops = &sysvipc_proc_fops; - } else { - kfree(iface); - } -} -#endif - /** * ipc_findkey - find a key in an ipc identifier set * @ids: Identifier set @@ -702,9 +662,10 @@ int ipc_parse_version (int *cmd) #endif /* __ARCH_WANT_IPC_PARSE_VERSION */ #ifdef CONFIG_PROC_FS -static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos) +/* seq operations */ +void *ipc_proc_next(struct seq_file *s, void *it, loff_t *pos) { - struct ipc_proc_iface *iface = s->private; + struct ipc_ids *ids = s->private; struct kern_ipc_perm *ipc = it; loff_t p; @@ -716,8 +677,8 @@ static void *sysvipc_proc_next(struct se * p = *pos - 1 (because id 0 starts at position 1) * + 1 (because we increment the position by one) */ - for (p = *pos; p <= iface->ids->max_id; p++) { - if ((ipc = ipc_lock(iface->ids, p)) != NULL) { + for (p = *pos; p <= ids->max_id; p++) { + if ((ipc = ipc_lock(ids, p)) != NULL) { *pos = p + 1; return ipc; } @@ -731,9 +692,9 @@ static void *sysvipc_proc_next(struct se * File positions: pos 0 -> header, pos n -> ipc id + 1. * SeqFile iterator: iterator value locked shp or SEQ_TOKEN_START. */ -static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos) +void *ipc_proc_start(struct seq_file *s, loff_t *pos) { - struct ipc_proc_iface *iface = s->private; + struct ipc_ids *ids = s->private; struct kern_ipc_perm *ipc; loff_t p; @@ -741,7 +702,7 @@ static void *sysvipc_proc_start(struct s * Take the lock - this will be released by the corresponding * call to stop(). */ - down(&iface->ids->sem); + down(&ids->sem); /* pos < 0 is invalid */ if (*pos < 0) @@ -752,8 +713,8 @@ static void *sysvipc_proc_start(struct s return SEQ_START_TOKEN; /* Find the (pos-1)th ipc */ - for (p = *pos - 1; p <= iface->ids->max_id; p++) { - if ((ipc = ipc_lock(iface->ids, p)) != NULL) { + for (p = *pos - 1; p <= ids->max_id; p++) { + if ((ipc = ipc_lock(ids, p)) != NULL) { *pos = p + 1; return ipc; } @@ -761,52 +722,32 @@ static void *sysvipc_proc_start(struct s return NULL; } -static void sysvipc_proc_stop(struct seq_file *s, void *it) +void ipc_proc_stop(struct seq_file *s, void *it) { struct kern_ipc_perm *ipc = it; - struct ipc_proc_iface *iface = s->private; + struct ipc_ids * ids = s->private; /* If we had a locked segment, release it */ if (ipc && ipc != SEQ_START_TOKEN) ipc_unlock(ipc); /* Release the lock we took in start() */ - up(&iface->ids->sem); -} - -static int sysvipc_proc_show(struct seq_file *s, void *it) -{ - struct ipc_proc_iface *iface = s->private; - - if (it == SEQ_START_TOKEN) - return seq_puts(s, iface->header); - - return iface->show(s, it); + up(&ids->sem); } -static struct seq_operations sysvipc_proc_seqops = { - .start = sysvipc_proc_start, - .stop = sysvipc_proc_stop, - .next = sysvipc_proc_next, - .show = sysvipc_proc_show, -}; +/* file operations */ -static int sysvipc_proc_open(struct inode *inode, struct file *file) { +int ipc_proc_open(struct inode *inode, struct file *file, + struct seq_operations *ops, struct ipc_ids *ids) +{ int ret; struct seq_file *seq; - - ret = seq_open(file, &sysvipc_proc_seqops); + ret = seq_open(file, ops); if (!ret) { seq = file->private_data; - seq->private = PDE(inode)->data; + seq->private = ids; } return ret; } -static struct file_operations sysvipc_proc_fops = { - .open = sysvipc_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; #endif /* CONFIG_PROC_FS */ diff --git a/ipc/util.h b/ipc/util.h index 68e6495..5d32f50 100644 --- a/ipc/util.h +++ b/ipc/util.h @@ -11,10 +11,6 @@ #define USHRT_MAX 0xffff #define SEQ_MULTIPLIER (IPCMNI) -void sem_init (void); -void msg_init (void); -void shm_init (void); - struct ipc_id_ary { int size; struct kern_ipc_perm *p[0]; @@ -37,8 +33,6 @@ struct ipc_ns { struct ipc_ids shm_ids; }; -extern struct ipc_ns init_ipc_ns; - void msg_init_ipc(struct ipc_ns *ipc); void sem_init_ipc(struct ipc_ns *ipc); void shm_init_ipc(struct ipc_ns *ipc); @@ -57,12 +51,13 @@ extern void put_sysvipc(struct ipc_ns *i struct seq_file; void __init ipc_init_ids(struct ipc_ids* ids, int size); void ipc_free_ids(struct ipc_ids *ids, void (*ipc_free)(struct kern_ipc_perm *p)); + #ifdef CONFIG_PROC_FS -void __init ipc_init_proc_interface(const char *path, const char *header, - struct ipc_ids *ids, - int (*show)(struct seq_file *, void *)); -#else -#define ipc_init_proc_interface(path, header, ids, show) do {} while (0) +extern void *ipc_proc_next(struct seq_file *s, void *it, loff_t *pos); +extern void *ipc_proc_start(struct seq_file *s, loff_t *pos); +extern void ipc_proc_stop(struct seq_file *s, void *it); +extern int ipc_proc_open(struct inode *inode, struct file *file, + struct seq_operations *ops, struct ipc_ids *ids); #endif /* must be called with ids->sem acquired.*/ -- 1.0.GIT