diff options
author | Dave Jones <davej@redhat.com> | 2006-12-12 18:13:32 -0500 |
---|---|---|
committer | Dave Jones <davej@redhat.com> | 2006-12-12 18:13:32 -0500 |
commit | f0eef25339f92f7cd4aeea23d9ae97987a5a1e82 (patch) | |
tree | 2472e94d39f43a9580a6d2d5d92de0b749023263 /ipc | |
parent | 0cfea5dd98205f2fa318836da664a7d7df1afbc1 (diff) | |
parent | e1036502e5263851259d147771226161e5ccc85a (diff) |
Merge ../linus
Diffstat (limited to 'ipc')
-rw-r--r-- | ipc/compat.c | 23 | ||||
-rw-r--r-- | ipc/mqueue.c | 61 | ||||
-rw-r--r-- | ipc/msg.c | 204 | ||||
-rw-r--r-- | ipc/msgutil.c | 2 | ||||
-rw-r--r-- | ipc/sem.c | 210 | ||||
-rw-r--r-- | ipc/shm.c | 267 | ||||
-rw-r--r-- | ipc/util.c | 141 | ||||
-rw-r--r-- | ipc/util.h | 36 |
8 files changed, 649 insertions, 295 deletions
diff --git a/ipc/compat.c b/ipc/compat.c index 4d20cfd38f0..fa18141539f 100644 --- a/ipc/compat.c +++ b/ipc/compat.c @@ -115,7 +115,6 @@ struct compat_shm_info { extern int sem_ctls[]; #define sc_semopm (sem_ctls[2]) -#define MAXBUF (64*1024) static inline int compat_ipc_parse_version(int *cmd) { @@ -307,35 +306,30 @@ long compat_sys_semctl(int first, int second, int third, void __user *uptr) long compat_sys_msgsnd(int first, int second, int third, void __user *uptr) { - struct msgbuf __user *p; struct compat_msgbuf __user *up = uptr; long type; if (first < 0) return -EINVAL; - if (second < 0 || (second >= MAXBUF - sizeof(struct msgbuf))) + if (second < 0) return -EINVAL; - p = compat_alloc_user_space(second + sizeof(struct msgbuf)); - if (get_user(type, &up->mtype) || - put_user(type, &p->mtype) || - copy_in_user(p->mtext, up->mtext, second)) + if (get_user(type, &up->mtype)) return -EFAULT; - return sys_msgsnd(first, p, second, third); + return do_msgsnd(first, type, up->mtext, second, third); } long compat_sys_msgrcv(int first, int second, int msgtyp, int third, int version, void __user *uptr) { - struct msgbuf __user *p; struct compat_msgbuf __user *up; long type; int err; if (first < 0) return -EINVAL; - if (second < 0 || (second >= MAXBUF - sizeof(struct msgbuf))) + if (second < 0) return -EINVAL; if (!version) { @@ -349,14 +343,11 @@ long compat_sys_msgrcv(int first, int second, int msgtyp, int third, uptr = compat_ptr(ipck.msgp); msgtyp = ipck.msgtyp; } - p = compat_alloc_user_space(second + sizeof(struct msgbuf)); - err = sys_msgrcv(first, p, second, msgtyp, third); + up = uptr; + err = do_msgrcv(first, &type, up->mtext, second, msgtyp, third); if (err < 0) goto out; - up = uptr; - if (get_user(type, &p->mtype) || - put_user(type, &up->mtype) || - copy_in_user(up->mtext, p->mtext, err)) + if (put_user(type, &up->mtype)) err = -EFAULT; out: return err; diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 02e6f679897..02717f71d8d 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -2,7 +2,7 @@ * POSIX message queues filesystem for Linux. * * Copyright (C) 2003,2004 Krzysztof Benedyczak (golbi@mat.uni.torun.pl) - * Michal Wronski (Michal.Wronski@motorola.com) + * Michal Wronski (michal.wronski@gmail.com) * * Spinlocks: Mohamed Abbas (abbas.mohamed@intel.com) * Lockless receive & send, fd based notify: @@ -73,7 +73,7 @@ struct mqueue_inode_info { struct mq_attr attr; struct sigevent notify; - pid_t notify_owner; + struct pid* notify_owner; struct user_struct *user; /* user who created, for accounting */ struct sock *notify_sock; struct sk_buff *notify_cookie; @@ -90,7 +90,7 @@ static struct super_operations mqueue_super_ops; static void remove_notification(struct mqueue_inode_info *info); static spinlock_t mq_lock; -static kmem_cache_t *mqueue_inode_cachep; +static struct kmem_cache *mqueue_inode_cachep; static struct vfsmount *mqueue_mnt; static unsigned int queues_count; @@ -115,7 +115,6 @@ static struct inode *mqueue_get_inode(struct super_block *sb, int mode, inode->i_mode = mode; inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; - inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_mtime = inode->i_ctime = inode->i_atime = CURRENT_TIME; @@ -135,7 +134,7 @@ static struct inode *mqueue_get_inode(struct super_block *sb, int mode, INIT_LIST_HEAD(&info->e_wait_q[0].list); INIT_LIST_HEAD(&info->e_wait_q[1].list); info->messages = NULL; - info->notify_owner = 0; + info->notify_owner = NULL; info->qsize = 0; info->user = NULL; /* set when all is ok */ memset(&info->attr, 0, sizeof(info->attr)); @@ -169,7 +168,7 @@ static struct inode *mqueue_get_inode(struct super_block *sb, int mode, /* all is ok */ info->user = get_uid(u); } else if (S_ISDIR(mode)) { - inode->i_nlink++; + inc_nlink(inode); /* Some things misbehave if size == 0 on a directory */ inode->i_size = 2 * DIRENT_SIZE; inode->i_op = &mqueue_dir_inode_operations; @@ -212,7 +211,7 @@ static int mqueue_get_sb(struct file_system_type *fs_type, return get_sb_single(fs_type, flags, data, mqueue_fill_super, mnt); } -static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags) +static void init_once(void *foo, struct kmem_cache * cachep, unsigned long flags) { struct mqueue_inode_info *p = (struct mqueue_inode_info *) foo; @@ -225,7 +224,7 @@ static struct inode *mqueue_alloc_inode(struct super_block *sb) { struct mqueue_inode_info *ei; - ei = kmem_cache_alloc(mqueue_inode_cachep, SLAB_KERNEL); + ei = kmem_cache_alloc(mqueue_inode_cachep, GFP_KERNEL); if (!ei) return NULL; return &ei->vfs_inode; @@ -308,7 +307,7 @@ static int mqueue_unlink(struct inode *dir, struct dentry *dentry) dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME; dir->i_size -= DIRENT_SIZE; - inode->i_nlink--; + drop_nlink(inode); dput(dentry); return 0; } @@ -323,7 +322,7 @@ static int mqueue_unlink(struct inode *dir, struct dentry *dentry) static ssize_t mqueue_read_file(struct file *filp, char __user *u_data, size_t count, loff_t * off) { - struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode); + struct mqueue_inode_info *info = MQUEUE_I(filp->f_path.dentry->d_inode); char buffer[FILENT_SIZE]; size_t slen; loff_t o; @@ -339,7 +338,7 @@ static ssize_t mqueue_read_file(struct file *filp, char __user *u_data, (info->notify_owner && info->notify.sigev_notify == SIGEV_SIGNAL) ? info->notify.sigev_signo : 0, - info->notify_owner); + pid_nr(info->notify_owner)); spin_unlock(&info->lock); buffer[sizeof(buffer)-1] = '\0'; slen = strlen(buffer)+1; @@ -355,16 +354,16 @@ static ssize_t mqueue_read_file(struct file *filp, char __user *u_data, return -EFAULT; *off = o + count; - filp->f_dentry->d_inode->i_atime = filp->f_dentry->d_inode->i_ctime = CURRENT_TIME; + filp->f_path.dentry->d_inode->i_atime = filp->f_path.dentry->d_inode->i_ctime = CURRENT_TIME; return count; } static int mqueue_flush_file(struct file *filp, fl_owner_t id) { - struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode); + struct mqueue_inode_info *info = MQUEUE_I(filp->f_path.dentry->d_inode); spin_lock(&info->lock); - if (current->tgid == info->notify_owner) + if (task_tgid(current) == info->notify_owner) remove_notification(info); spin_unlock(&info->lock); @@ -373,7 +372,7 @@ static int mqueue_flush_file(struct file *filp, fl_owner_t id) static unsigned int mqueue_poll_file(struct file *filp, struct poll_table_struct *poll_tab) { - struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode); + struct mqueue_inode_info *info = MQUEUE_I(filp->f_path.dentry->d_inode); int retval = 0; poll_wait(filp, &info->wait_q, poll_tab); @@ -519,8 +518,8 @@ static void __do_notify(struct mqueue_inode_info *info) sig_i.si_pid = current->tgid; sig_i.si_uid = current->uid; - kill_proc_info(info->notify.sigev_signo, - &sig_i, info->notify_owner); + kill_pid_info(info->notify.sigev_signo, + &sig_i, info->notify_owner); break; case SIGEV_THREAD: set_cookie(info->notify_cookie, NOTIFY_WOKENUP); @@ -529,7 +528,8 @@ static void __do_notify(struct mqueue_inode_info *info) break; } /* after notification unregisters process */ - info->notify_owner = 0; + put_pid(info->notify_owner); + info->notify_owner = NULL; } wake_up(&info->wait_q); } @@ -567,12 +567,13 @@ static long prepare_timeout(const struct timespec __user *u_arg) static void remove_notification(struct mqueue_inode_info *info) { - if (info->notify_owner != 0 && + if (info->notify_owner != NULL && info->notify.sigev_notify == SIGEV_THREAD) { set_cookie(info->notify_cookie, NOTIFY_REMOVED); netlink_sendskb(info->notify_sock, info->notify_cookie, 0); } - info->notify_owner = 0; + put_pid(info->notify_owner); + info->notify_owner = NULL; } static int mq_attr_ok(struct mq_attr *attr) @@ -835,7 +836,7 @@ asmlinkage long sys_mq_timedsend(mqd_t mqdes, const char __user *u_msg_ptr, if (unlikely(!filp)) goto out; - inode = filp->f_dentry->d_inode; + inode = filp->f_path.dentry->d_inode; if (unlikely(filp->f_op != &mqueue_file_operations)) goto out_fput; info = MQUEUE_I(inode); @@ -918,7 +919,7 @@ asmlinkage ssize_t sys_mq_timedreceive(mqd_t mqdes, char __user *u_msg_ptr, if (unlikely(!filp)) goto out; - inode = filp->f_dentry->d_inode; + inode = filp->f_path.dentry->d_inode; if (unlikely(filp->f_op != &mqueue_file_operations)) goto out_fput; info = MQUEUE_I(inode); @@ -1055,7 +1056,7 @@ retry: if (!filp) goto out; - inode = filp->f_dentry->d_inode; + inode = filp->f_path.dentry->d_inode; if (unlikely(filp->f_op != &mqueue_file_operations)) goto out_fput; info = MQUEUE_I(inode); @@ -1063,11 +1064,11 @@ retry: ret = 0; spin_lock(&info->lock); if (u_notification == NULL) { - if (info->notify_owner == current->tgid) { + if (info->notify_owner == task_tgid(current)) { remove_notification(info); inode->i_atime = inode->i_ctime = CURRENT_TIME; } - } else if (info->notify_owner != 0) { + } else if (info->notify_owner != NULL) { ret = -EBUSY; } else { switch (notification.sigev_notify) { @@ -1087,7 +1088,8 @@ retry: info->notify.sigev_notify = SIGEV_SIGNAL; break; } - info->notify_owner = current->tgid; + + info->notify_owner = get_pid(task_tgid(current)); inode->i_atime = inode->i_ctime = CURRENT_TIME; } spin_unlock(&info->lock); @@ -1124,7 +1126,7 @@ asmlinkage long sys_mq_getsetattr(mqd_t mqdes, if (!filp) goto out; - inode = filp->f_dentry->d_inode; + inode = filp->f_path.dentry->d_inode; if (unlikely(filp->f_op != &mqueue_file_operations)) goto out_fput; info = MQUEUE_I(inode); @@ -1275,10 +1277,7 @@ out_filesystem: out_sysctl: if (mq_sysctl_table) unregister_sysctl_table(mq_sysctl_table); - if (kmem_cache_destroy(mqueue_inode_cachep)) { - printk(KERN_INFO - "mqueue_inode_cache: not all structures were freed\n"); - } + kmem_cache_destroy(mqueue_inode_cachep); return error; } diff --git a/ipc/msg.c b/ipc/msg.c index 2b4fccf8ea5..a388824740e 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -16,6 +16,10 @@ * * support for audit of ipc object properties and permission changes * Dustin Kirkland <dustin.kirkland@us.ibm.com> + * + * namespaces support + * OpenVZ, SWsoft Inc. + * Pavel Emelianov <xemul@openvz.org> */ #include <linux/capability.h> @@ -31,16 +35,12 @@ #include <linux/audit.h> #include <linux/seq_file.h> #include <linux/mutex.h> +#include <linux/nsproxy.h> #include <asm/current.h> #include <asm/uaccess.h> #include "util.h" -/* sysctl: */ -int msg_ctlmax = MSGMAX; -int msg_ctlmnb = MSGMNB; -int msg_ctlmni = MSGMNI; - /* * one msg_receiver structure for each sleeping receiver: */ @@ -52,7 +52,7 @@ struct msg_receiver { long r_msgtype; long r_maxsize; - volatile struct msg_msg *r_msg; + struct msg_msg *volatile r_msg; }; /* one msg_sender for each sleeping sender */ @@ -69,30 +69,76 @@ struct msg_sender { static atomic_t msg_bytes = ATOMIC_INIT(0); static atomic_t msg_hdrs = ATOMIC_INIT(0); -static struct ipc_ids msg_ids; +static struct ipc_ids init_msg_ids; -#define msg_lock(id) ((struct msg_queue *)ipc_lock(&msg_ids, id)) -#define msg_unlock(msq) ipc_unlock(&(msq)->q_perm) -#define msg_rmid(id) ((struct msg_queue *)ipc_rmid(&msg_ids, id)) -#define msg_checkid(msq, msgid) ipc_checkid(&msg_ids, &msq->q_perm, msgid) -#define msg_buildid(id, seq) ipc_buildid(&msg_ids, id, seq) +#define msg_ids(ns) (*((ns)->ids[IPC_MSG_IDS])) -static void freeque(struct msg_queue *msq, int id); -static int newque(key_t key, int msgflg); +#define msg_lock(ns, id) ((struct msg_queue*)ipc_lock(&msg_ids(ns), id)) +#define msg_unlock(msq) ipc_unlock(&(msq)->q_perm) +#define msg_rmid(ns, id) ((struct msg_queue*)ipc_rmid(&msg_ids(ns), id)) +#define msg_checkid(ns, msq, msgid) \ + ipc_checkid(&msg_ids(ns), &msq->q_perm, msgid) +#define msg_buildid(ns, id, seq) \ + ipc_buildid(&msg_ids(ns), id, seq) + +static void freeque (struct ipc_namespace *ns, struct msg_queue *msq, int id); +static int newque (struct ipc_namespace *ns, key_t key, int msgflg); #ifdef CONFIG_PROC_FS static int sysvipc_msg_proc_show(struct seq_file *s, void *it); #endif +static void __ipc_init __msg_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids) +{ + ns->ids[IPC_MSG_IDS] = ids; + ns->msg_ctlmax = MSGMAX; + ns->msg_ctlmnb = MSGMNB; + ns->msg_ctlmni = MSGMNI; + ipc_init_ids(ids, ns->msg_ctlmni); +} + +#ifdef CONFIG_IPC_NS +int msg_init_ns(struct ipc_namespace *ns) +{ + struct ipc_ids *ids; + + ids = kmalloc(sizeof(struct ipc_ids), GFP_KERNEL); + if (ids == NULL) + return -ENOMEM; + + __msg_init_ns(ns, ids); + return 0; +} + +void msg_exit_ns(struct ipc_namespace *ns) +{ + int i; + struct msg_queue *msq; + + mutex_lock(&msg_ids(ns).mutex); + for (i = 0; i <= msg_ids(ns).max_id; i++) { + msq = msg_lock(ns, i); + if (msq == NULL) + continue; + + freeque(ns, msq, i); + } + mutex_unlock(&msg_ids(ns).mutex); + + ipc_fini_ids(ns->ids[IPC_MSG_IDS]); + kfree(ns->ids[IPC_MSG_IDS]); + ns->ids[IPC_MSG_IDS] = NULL; +} +#endif + void __init msg_init(void) { - ipc_init_ids(&msg_ids, msg_ctlmni); + __msg_init_ns(&init_ipc_ns, &init_msg_ids); ipc_init_proc_interface("sysvipc/msg", " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n", - &msg_ids, - sysvipc_msg_proc_show); + IPC_MSG_IDS, sysvipc_msg_proc_show); } -static int newque(key_t key, int msgflg) +static int newque (struct ipc_namespace *ns, key_t key, int msgflg) { struct msg_queue *msq; int id, retval; @@ -111,18 +157,18 @@ static int newque(key_t key, int msgflg) return retval; } - id = ipc_addid(&msg_ids, &msq->q_perm, msg_ctlmni); + id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni); if (id == -1) { security_msg_queue_free(msq); ipc_rcu_putref(msq); return -ENOSPC; } - msq->q_id = msg_buildid(id, msq->q_perm.seq); + msq->q_id = msg_buildid(ns, id, msq->q_perm.seq); msq->q_stime = msq->q_rtime = 0; msq->q_ctime = get_seconds(); msq->q_cbytes = msq->q_qnum = 0; - msq->q_qbytes = msg_ctlmnb; + msq->q_qbytes = ns->msg_ctlmnb; msq->q_lspid = msq->q_lrpid = 0; INIT_LIST_HEAD(&msq->q_messages); INIT_LIST_HEAD(&msq->q_receivers); @@ -186,13 +232,13 @@ static void expunge_all(struct msg_queue *msq, int res) * msg_ids.mutex and the spinlock for this message queue is hold * before freeque() is called. msg_ids.mutex remains locked on exit. */ -static void freeque(struct msg_queue *msq, int id) +static void freeque(struct ipc_namespace *ns, struct msg_queue *msq, int id) { struct list_head *tmp; expunge_all(msq, -EIDRM); ss_wakeup(&msq->q_senders, 1); - msq = msg_rmid(id); + msq = msg_rmid(ns, id); msg_unlock(msq); tmp = msq->q_messages.next; @@ -212,24 +258,27 @@ asmlinkage long sys_msgget(key_t key, int msgflg) { struct msg_queue *msq; int id, ret = -EPERM; + struct ipc_namespace *ns; + + ns = current->nsproxy->ipc_ns; - mutex_lock(&msg_ids.mutex); + mutex_lock(&msg_ids(ns).mutex); if (key == IPC_PRIVATE) - ret = newque(key, msgflg); - else if ((id = ipc_findkey(&msg_ids, key)) == -1) { /* key not used */ + ret = newque(ns, key, msgflg); + else if ((id = ipc_findkey(&msg_ids(ns), key)) == -1) { /* key not used */ if (!(msgflg & IPC_CREAT)) ret = -ENOENT; else - ret = newque(key, msgflg); + ret = newque(ns, key, msgflg); } else if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) { ret = -EEXIST; } else { - msq = msg_lock(id); + msq = msg_lock(ns, id); BUG_ON(msq == NULL); if (ipcperms(&msq->q_perm, msgflg)) ret = -EACCES; else { - int qid = msg_buildid(id, msq->q_perm.seq); + int qid = msg_buildid(ns, id, msq->q_perm.seq); ret = security_msg_queue_associate(msq, msgflg); if (!ret) @@ -237,7 +286,7 @@ asmlinkage long sys_msgget(key_t key, int msgflg) } msg_unlock(msq); } - mutex_unlock(&msg_ids.mutex); + mutex_unlock(&msg_ids(ns).mutex); return ret; } @@ -341,11 +390,13 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf) struct msq_setbuf setbuf; struct msg_queue *msq; int err, version; + struct ipc_namespace *ns; if (msqid < 0 || cmd < 0) return -EINVAL; version = ipc_parse_version(&cmd); + ns = current->nsproxy->ipc_ns; switch (cmd) { case IPC_INFO: @@ -366,14 +417,14 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf) return err; memset(&msginfo, 0, sizeof(msginfo)); - msginfo.msgmni = msg_ctlmni; - msginfo.msgmax = msg_ctlmax; - msginfo.msgmnb = msg_ctlmnb; + msginfo.msgmni = ns->msg_ctlmni; + msginfo.msgmax = ns->msg_ctlmax; + msginfo.msgmnb = ns->msg_ctlmnb; msginfo.msgssz = MSGSSZ; msginfo.msgseg = MSGSEG; - mutex_lock(&msg_ids.mutex); + mutex_lock(&msg_ids(ns).mutex); if (cmd == MSG_INFO) { - msginfo.msgpool = msg_ids.in_use; + msginfo.msgpool = msg_ids(ns).in_use; msginfo.msgmap = atomic_read(&msg_hdrs); msginfo.msgtql = atomic_read(&msg_bytes); } else { @@ -381,8 +432,8 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf) msginfo.msgpool = MSGPOOL; msginfo.msgtql = MSGTQL; } - max_id = msg_ids.max_id; - mutex_unlock(&msg_ids.mutex); + max_id = msg_ids(ns).max_id; + mutex_unlock(&msg_ids(ns).mutex); if (copy_to_user(buf, &msginfo, sizeof(struct msginfo))) return -EFAULT; return (max_id < 0) ? 0 : max_id; @@ -395,20 +446,20 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf) if (!buf) return -EFAULT; - if (cmd == MSG_STAT && msqid >= msg_ids.entries->size) + if (cmd == MSG_STAT && msqid >= msg_ids(ns).entries->size) return -EINVAL; memset(&tbuf, 0, sizeof(tbuf)); - msq = msg_lock(msqid); + msq = msg_lock(ns, msqid); if (msq == NULL) return -EINVAL; if (cmd == MSG_STAT) { - success_return = msg_buildid(msqid, msq->q_perm.seq); + success_return = msg_buildid(ns, msqid, msq->q_perm.seq); } else { err = -EIDRM; - if (msg_checkid(msq, msqid)) + if (msg_checkid(ns, msq, msqid)) goto out_unlock; success_return = 0; } @@ -446,14 +497,14 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf) return -EINVAL; } - mutex_lock(&msg_ids.mutex); - msq = msg_lock(msqid); + mutex_lock(&msg_ids(ns).mutex); + msq = msg_lock(ns, msqid); err = -EINVAL; if (msq == NULL) goto out_up; err = -EIDRM; - if (msg_checkid(msq, msqid)) + if (msg_checkid(ns, msq, msqid)) goto out_unlock_up; ipcp = &msq->q_perm; @@ -481,7 +532,7 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf) case IPC_SET: { err = -EPERM; - if (setbuf.qbytes > msg_ctlmnb && !capable(CAP_SYS_RESOURCE)) + if (setbuf.qbytes > ns->msg_ctlmnb && !capable(CAP_SYS_RESOURCE)) goto out_unlock_up; msq->q_qbytes = setbuf.qbytes; @@ -503,12 +554,12 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf) break; } case IPC_RMID: - freeque(msq, msqid); + freeque(ns, msq, msqid); break; } err = 0; out_up: - mutex_unlock(&msg_ids.mutex); + mutex_unlock(&msg_ids(ns).mutex); return err; out_unlock_up: msg_unlock(msq); @@ -575,35 +626,35 @@ static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg) return 0; } -asmlinkage long -sys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg) +long do_msgsnd(int msqid, long mtype, void __user *mtext, + size_t msgsz, int msgflg) { struct msg_queue *msq; struct msg_msg *msg; - long mtype; int err; + struct ipc_namespace *ns; - if (msgsz > msg_ctlmax || (long) msgsz < 0 || msqid < 0) + ns = current->nsproxy->ipc_ns; + + if (msgsz > ns->msg_ctlmax || (long) msgsz < 0 || msqid < 0) return -EINVAL; - if (get_user(mtype, &msgp->mtype)) - return -EFAULT; if (mtype < 1) return -EINVAL; - msg = load_msg(msgp->mtext, msgsz); + msg = load_msg(mtext, msgsz); if (IS_ERR(msg)) return PTR_ERR(msg); msg->m_type = mtype; msg->m_ts = msgsz; - msq = msg_lock(msqid); + msq = msg_lock(ns, msqid); err = -EINVAL; if (msq == NULL) goto out_free; err= -EIDRM; - if (msg_checkid(msq, msqid)) + if (msg_checkid(ns, msq, msqid)) goto out_unlock_free; for (;;) { @@ -669,6 +720,16 @@ out_free: return err; } +asmlinkage long +sys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg) +{ + long mtype; + + if (get_user(mtype, &msgp->mtype)) + return -EFAULT; + return do_msgsnd(msqid, mtype, msgp->mtext, msgsz, msgflg); +} + static inline int convert_mode(long *msgtyp, int msgflg) { /* @@ -688,23 +749,25 @@ static inline int convert_mode(long *msgtyp, int msgflg) return SEARCH_EQUAL; } -asmlinkage long sys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz, - long msgtyp, int msgflg) +long do_msgrcv(int msqid, long *pmtype, void __user *mtext, + size_t msgsz, long msgtyp, int msgflg) { struct msg_queue *msq; struct msg_msg *msg; int mode; + struct ipc_namespace *ns; if (msqid < 0 || (long) msgsz < 0) return -EINVAL; mode = convert_mode(&msgtyp, msgflg); + ns = current->nsproxy->ipc_ns; - msq = msg_lock(msqid); + msq = msg_lock(ns, msqid); if (msq == NULL) return -EINVAL; msg = ERR_PTR(-EIDRM); - if (msg_checkid(msq, msqid)) + if (msg_checkid(ns, msq, msqid)) goto out_unlock; for (;;) { @@ -833,15 +896,30 @@ out_unlock: return PTR_ERR(msg); msgsz = (msgsz > msg->m_ts) ? msg->m_ts : msgsz; - if (put_user (msg->m_type, &msgp->mtype) || - store_msg(msgp->mtext, msg, msgsz)) { + *pmtype = msg->m_type; + if (store_msg(mtext, msg, msgsz)) msgsz = -EFAULT; - } + free_msg(msg); return msgsz; } +asmlinkage long sys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz, + long msgtyp, int msgflg) +{ + long err, mtype; + + err = do_msgrcv(msqid, &mtype, msgp->mtext, msgsz, msgtyp, msgflg); + if (err < 0) + goto out; + + if (put_user(mtype, &msgp->mtype)) + err = -EFAULT; +out: + return err; +} + #ifdef CONFIG_PROC_FS static int sysvipc_msg_proc_show(struct seq_file *s, void *it) { diff --git a/ipc/msgutil.c b/ipc/msgutil.c index 66cfb87646e..0992616eeed 100644 --- a/ipc/msgutil.c +++ b/ipc/msgutil.c @@ -1,5 +1,5 @@ /* - * linux/ipc/util.c + * linux/ipc/msgutil.c * Copyright (C) 1999, 2004 Manfred Spraul * * This file is released under GNU General Public Licence version 2 or diff --git a/ipc/sem.c b/ipc/sem.c index 6013c751156..d3e12efd55c 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -64,6 +64,10 @@ * * support for audit of ipc object properties and permission changes * Dustin Kirkland <dustin.kirkland@us.ibm.com> + * + * namespaces support + * OpenVZ, SWsoft Inc. + * Pavel Emelianov <xemul@openvz.org> */ #include <linux/slab.h> @@ -78,22 +82,25 @@ #include <linux/capability.h> #include <linux/seq_file.h> #include <linux/mutex.h> +#include <linux/nsproxy.h> #include <asm/uaccess.h> #include "util.h" +#define sem_ids(ns) (*((ns)->ids[IPC_SEM_IDS])) + +#define sem_lock(ns, id) ((struct sem_array*)ipc_lock(&sem_ids(ns), id)) +#define sem_unlock(sma) ipc_unlock(&(sma)->sem_perm) +#define sem_rmid(ns, id) ((struct sem_array*)ipc_rmid(&sem_ids(ns), id)) +#define sem_checkid(ns, sma, semid) \ + ipc_checkid(&sem_ids(ns),&sma->sem_perm,semid) +#define sem_buildid(ns, id, seq) \ + ipc_buildid(&sem_ids(ns), id, seq) -#define sem_lock(id) ((struct sem_array*)ipc_lock(&sem_ids,id)) -#define sem_unlock(sma) ipc_unlock(&(sma)->sem_perm) -#define sem_rmid(id) ((struct sem_array*)ipc_rmid(&sem_ids,id)) -#define sem_checkid(sma, semid) \ - ipc_checkid(&sem_ids,&sma->sem_perm,semid) -#define sem_buildid(id, seq) \ - ipc_buildid(&sem_ids, id, seq) -static struct ipc_ids sem_ids; +static struct ipc_ids init_sem_ids; -static int newary (key_t, int, int); -static void freeary (struct sem_array *sma, int id); +static int newary(struct ipc_namespace *, key_t, int, int); +static void freeary(struct ipc_namespace *ns, struct sem_array *sma, int id); #ifdef CONFIG_PROC_FS static int sysvipc_sem_proc_show(struct seq_file *s, void *it); #endif @@ -110,22 +117,62 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it); * */ -int sem_ctls[4] = {SEMMSL, SEMMNS, SEMOPM, SEMMNI}; -#define sc_semmsl (sem_ctls[0]) -#define sc_semmns (sem_ctls[1]) -#define sc_semopm (sem_ctls[2]) -#define sc_semmni (sem_ctls[3]) +#define sc_semmsl sem_ctls[0] +#define sc_semmns sem_ctls[1] +#define sc_semopm sem_ctls[2] +#define sc_semmni sem_ctls[3] -static int used_sems; +static void __ipc_init __sem_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids) +{ + ns->ids[IPC_SEM_IDS] = ids; + ns->sc_semmsl = SEMMSL; + ns->sc_semmns = SEMMNS; + ns->sc_semopm = SEMOPM; + ns->sc_semmni = SEMMNI; + ns->used_sems = 0; + ipc_init_ids(ids, ns->sc_semmni); +} + +#ifdef CONFIG_IPC_NS +int sem_init_ns(struct ipc_namespace *ns) +{ + struct ipc_ids *ids; + + ids = kmalloc(sizeof(struct ipc_ids), GFP_KERNEL); + if (ids == NULL) + return -ENOMEM; + + __sem_init_ns(ns, ids); + return 0; +} + +void sem_exit_ns(struct ipc_namespace *ns) +{ + int i; + struct sem_array *sma; + + mutex_lock(&sem_ids(ns).mutex); + for (i = 0; i <= sem_ids(ns).max_id; i++) { + sma = sem_lock(ns, i); + if (sma == NULL) + continue; + + freeary(ns, sma, i); + } + mutex_unlock(&sem_ids(ns).mutex); + + ipc_fini_ids(ns->ids[IPC_SEM_IDS]); + kfree(ns->ids[IPC_SEM_IDS]); + ns->ids[IPC_SEM_IDS] = NULL; +} +#endif void __init sem_init (void) { - used_sems = 0; - ipc_init_ids(&sem_ids,sc_semmni); + __sem_init_ns(&init_ipc_ns, &init_sem_ids); ipc_init_proc_interface("sysvipc/sem", " key semid perms nsems uid gid cuid cgid otime ctime\n", - &sem_ids, - sysvipc_sem_proc_show); + IPC_SEM_IDS, sysvipc_sem_proc_show); } /* @@ -162,7 +209,7 @@ void __init sem_init (void) */ #define IN_WAKEUP 1 -static int newary (key_t key, int nsems, int semflg) +static int newary (struct ipc_namespace *ns, key_t key, int nsems, int semflg) { int id; int retval; @@ -171,7 +218,7 @@ static int newary (key_t key, int nsems, int semflg) if (!nsems) return -EINVAL; - if (used_sems + nsems > sc_semmns) + if (ns->used_sems + nsems > ns->sc_semmns) return -ENOSPC; size = sizeof (*sma) + nsems * sizeof (struct sem); @@ -191,15 +238,15 @@ static int newary (key_t key, int nsems, int semflg) return retval; } - id = ipc_addid(&sem_ids, &sma->sem_perm, sc_semmni); + id = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni); if(id == -1) { security_sem_free(sma); ipc_rcu_putref(sma); return -ENOSPC; } - used_sems += nsems; + ns->used_sems += nsems; - sma->sem_id = sem_buildid(id, sma->sem_perm.seq); + sma->sem_id = sem_buildid(ns, id, sma->sem_perm.seq); sma->sem_base = (struct sem *) &sma[1]; /* sma->sem_pending = NULL; */ sma->sem_pending_last = &sma->sem_pending; @@ -215,29 +262,32 @@ asmlinkage long sys_semget (key_t key, int nsems, int semflg) { int id, err = -EINVAL; struct sem_array *sma; + struct ipc_namespace *ns; - if (nsems < 0 || nsems > sc_semmsl) + ns = current->nsproxy->ipc_ns; + + if (nsems < 0 || nsems > ns->sc_semmsl) return -EINVAL; - mutex_lock(&sem_ids.mutex); + mutex_lock(&sem_ids(ns).mutex); if (key == IPC_PRIVATE) { - err = newary(key, nsems, semflg); - } else if ((id = ipc_findkey(&sem_ids, key)) == -1) { /* key not used */ + err = newary(ns, key, nsems, semflg); + } else if ((id = ipc_findkey(&sem_ids(ns), key)) == -1) { /* key not used */ if (!(semflg & IPC_CREAT)) err = -ENOENT; else - err = newary(key, nsems, semflg); + err = newary(ns, key, nsems, semflg); } else if (semflg & IPC_CREAT && semflg & IPC_EXCL) { err = -EEXIST; } else { - sma = sem_lock(id); + sma = sem_lock(ns, id); BUG_ON(sma==NULL); if (nsems > sma->sem_nsems) err = -EINVAL; else if (ipcperms(&sma->sem_perm, semflg)) err = -EACCES; else { - int semid = sem_buildid(id, sma->sem_perm.seq); + int semid = sem_buildid(ns, id, sma->sem_perm.seq); err = security_sem_associate(sma, semflg); if (!err) err = semid; @@ -245,7 +295,7 @@ asmlinkage long sys_semget (key_t key, int nsems, int semflg) sem_unlock(sma); } - mutex_unlock(&sem_ids.mutex); + mutex_unlock(&sem_ids(ns).mutex); return err; } @@ -444,7 +494,7 @@ static int count_semzcnt (struct sem_array * sma, ushort semnum) * the spinlock for this semaphore set hold. sem_ids.mutex remains locked * on exit. */ -static void freeary (struct sem_array *sma, int id) +static void freeary (struct ipc_namespace *ns, struct sem_array *sma, int id) { struct sem_undo *un; struct sem_queue *q; @@ -472,10 +522,10 @@ static void freeary (struct sem_array *sma, int id) } /* Remove the semaphore set from the ID array*/ - sma = sem_rmid(id); + sma = sem_rmid(ns, id); sem_unlock(sma); - used_sems -= sma->sem_nsems; + ns->used_sems -= sma->sem_nsems; size = sizeof (*sma) + sma->sem_nsems * sizeof (struct sem); security_sem_free(sma); ipc_rcu_putref(sma); @@ -503,7 +553,8 @@ static unsigned long copy_semid_to_user(void __user *buf, struct semid64_ds *in, } } -static int semctl_nolock(int semid, int semnum, int cmd, int version, union semun arg) +static int semctl_nolock(struct ipc_namespace *ns, int semid, int semnum, + int cmd, int version, union semun arg) { int err = -EINVAL; struct sem_array *sma; @@ -520,24 +571,24 @@ static int semctl_nolock(int semid, int semnum, int cmd, int version, union semu return err; memset(&seminfo,0,sizeof(seminfo)); - seminfo.semmni = sc_semmni; - seminfo.semmns = sc_semmns; - seminfo.semmsl = sc_semmsl; - seminfo.semopm = sc_semopm; + seminfo.semmni = ns->sc_semmni; + seminfo.semmns = ns->sc_semmns; + seminfo.semmsl = ns->sc_semmsl; + seminfo.semopm = ns->sc_semopm; seminfo.semvmx = SEMVMX; seminfo.semmnu = SEMMNU; seminfo.semmap = SEMMAP; seminfo.semume = SEMUME; - mutex_lock(&sem_ids.mutex); + mutex_lock(&sem_ids(ns).mutex); if (cmd == SEM_INFO) { - seminfo.semusz = sem_ids.in_use; - seminfo.semaem = used_sems; + seminfo.semusz = sem_ids(ns).in_use; + seminfo.semaem = ns->used_sems; } else { seminfo.semusz = SEMUSZ; seminfo.semaem = SEMAEM; } - max_id = sem_ids.max_id; - mutex_unlock(&sem_ids.mutex); + max_id = sem_ids(ns).max_id; + mutex_unlock(&sem_ids(ns).mutex); if (copy_to_user (arg.__buf, &seminfo, sizeof(struct seminfo))) return -EFAULT; return (max_id < 0) ? 0: max_id; @@ -547,12 +598,12 @@ static int semctl_nolock(int semid, int semnum, int cmd, int version, union semu struct semid64_ds tbuf; int id; - if(semid >= sem_ids.entries->size) + if(semid >= sem_ids(ns).entries->size) return -EINVAL; memset(&tbuf,0,sizeof(tbuf)); - sma = sem_lock(semid); + sma = sem_lock(ns, semid); if(sma == NULL) return -EINVAL; @@ -564,7 +615,7 @@ static int semctl_nolock(int semid, int semnum, int cmd, int version, union semu if (err) goto out_unlock; - id = sem_buildid(semid, sma->sem_perm.seq); + id = sem_buildid(ns, semid, sma->sem_perm.seq); kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm); tbuf.sem_otime = sma->sem_otime; @@ -584,7 +635,8 @@ out_unlock: return err; } -static int semctl_main(int semid, int semnum, int cmd, int version, union semun arg) +static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, + int cmd, int version, union semun arg) { struct sem_array *sma; struct sem* curr; @@ -593,14 +645,14 @@ static int semctl_main(int semid, int semnum, int cmd, int version, union semun ushort* sem_io = fast_sem_io; int nsems; - sma = sem_lock(semid); + sma = sem_lock(ns, semid); if(sma==NULL) return -EINVAL; nsems = sma->sem_nsems; err=-EIDRM; - if (sem_checkid(sma,semid)) + if (sem_checkid(ns,sma,semid)) goto out_unlock; err = -EACCES; @@ -802,7 +854,8 @@ static inline unsigned long copy_semid_from_user(struct sem_setbuf *out, void __ } } -static int semctl_down(int semid, int semnum, int cmd, int version, union semun arg) +static int semctl_down(struct ipc_namespace *ns, int semid, int semnum, + int cmd, int version, union semun arg) { struct sem_array *sma; int err; @@ -813,11 +866,11 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun if(copy_semid_from_user (&setbuf, arg.buf, version)) return -EFAULT; } - sma = sem_lock(semid); + sma = sem_lock(ns, semid); if(sma==NULL) return -EINVAL; - if (sem_checkid(sma,semid)) { + if (sem_checkid(ns,sma,semid)) { err=-EIDRM; goto out_unlock; } @@ -844,7 +897,7 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun switch(cmd){ case IPC_RMID: - freeary(sma, semid); + freeary(ns, sma, semid); err = 0; break; case IPC_SET: @@ -872,17 +925,19 @@ asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg) { int err = -EINVAL; int version; + struct ipc_namespace *ns; if (semid < 0) return -EINVAL; version = ipc_parse_version(&cmd); + ns = current->nsproxy->ipc_ns; switch(cmd) { case IPC_INFO: case SEM_INFO: case SEM_STAT: - err = semctl_nolock(semid,semnum,cmd,version,arg); + err = semctl_nolock(ns,semid,semnum,cmd,version,arg); return err; case GETALL: case GETVAL: @@ -892,13 +947,13 @@ asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg) case IPC_STAT: case SETVAL: case SETALL: - err = semctl_main(semid,semnum,cmd,version,arg); + err = semctl_main(ns,semid,semnum,cmd,version,arg); return err; case IPC_RMID: case IPC_SET: - mutex_lock(&sem_ids.mutex); - err = semctl_down(semid,semnum,cmd,version,arg); - mutex_unlock(&sem_ids.mutex); + mutex_lock(&sem_ids(ns).mutex); + err = semctl_down(ns,semid,semnum,cmd,version,arg); + mutex_unlock(&sem_ids(ns).mutex); return err; default: return -EINVAL; @@ -949,15 +1004,12 @@ static inline void unlock_semundo(void) static inline int get_undo_list(struct sem_undo_list **undo_listp) { struct sem_undo_list *undo_list; - int size; undo_list = current->sysvsem.undo_list; if (!undo_list) { - size = sizeof(struct sem_undo_list); - undo_list = (struct sem_undo_list *) kmalloc(size, GFP_KERNEL); + undo_list = kzalloc(sizeof(*undo_list), GFP_KERNEL); if (undo_list == NULL) return -ENOMEM; - memset(undo_list, 0, size); spin_lock_init(&undo_list->lock); atomic_set(&undo_list->refcnt, 1); current->sysvsem.undo_list = undo_list; @@ -986,7 +1038,7 @@ static struct sem_undo *lookup_undo(struct sem_undo_list *ulp, int semid) return un; } -static struct sem_undo *find_undo(int semid) +static struct sem_undo *find_undo(struct ipc_namespace *ns, int semid) { struct sem_array *sma; struct sem_undo_list *ulp; @@ -1005,12 +1057,12 @@ static struct sem_undo *find_undo(int semid) goto out; /* no undo structure around - allocate one. */ - sma = sem_lock(semid); + sma = sem_lock(ns, semid); un = ERR_PTR(-EINVAL); if(sma==NULL) goto out; un = ERR_PTR(-EIDRM); - if (sem_checkid(sma,semid)) { + if (sem_checkid(ns,sma,semid)) { sem_unlock(sma); goto out; } @@ -1018,14 +1070,13 @@ static struct sem_undo *find_undo(int semid) ipc_rcu_getref(sma); sem_unlock(sma); - new = (struct sem_undo *) kmalloc(sizeof(struct sem_undo) + sizeof(short)*nsems, GFP_KERNEL); + new = kzalloc(sizeof(struct sem_undo) + sizeof(short)*nsems, GFP_KERNEL); if (!new) { ipc_lock_by_ptr(&sma->sem_perm); ipc_rcu_putref(sma); sem_unlock(sma); return ERR_PTR(-ENOMEM); } - memset(new, 0, sizeof(struct sem_undo) + sizeof(short)*nsems); new->semadj = (short *) &new[1]; new->semid = semid; @@ -1070,10 +1121,13 @@ asmlinkage long sys_semtimedop(int semid, struct sembuf __user *tsops, int undos = 0, alter = 0, max; struct sem_queue queue; unsigned long jiffies_left = 0; + struct ipc_namespace *ns; + + ns = current->nsproxy->ipc_ns; if (nsops < 1 || semid < 0) return -EINVAL; - if (nsops > sc_semopm) + if (nsops > ns->sc_semopm) return -E2BIG; if(nsops > SEMOPM_FAST) { sops = kmalloc(sizeof(*sops)*nsops,GFP_KERNEL); @@ -1109,7 +1163,7 @@ asmlinkage long sys_semtimedop(int semid, struct sembuf __user *tsops, retry_undos: if (undos) { - un = find_undo(semid); + un = find_undo(ns, semid); if (IS_ERR(un)) { error = PTR_ERR(un); goto out_free; @@ -1117,12 +1171,12 @@ retry_undos: } else un = NULL; - sma = sem_lock(semid); + sma = sem_lock(ns, semid); error=-EINVAL; if(sma==NULL) goto out_free; error = -EIDRM; - if (sem_checkid(sma,semid)) + if (sem_checkid(ns,sma,semid)) goto out_unlock_free; /* * semid identifies are not unique - find_undo may have @@ -1190,7 +1244,7 @@ retry_undos: goto out_free; } - sma = sem_lock(semid); + sma = sem_lock(ns, semid); if(sma==NULL) { BUG_ON(queue.prev != NULL); error = -EIDRM; @@ -1267,6 +1321,7 @@ void exit_sem(struct task_struct *tsk) { struct sem_undo_list *undo_list; struct sem_undo *u, **up; + struct ipc_namespace *ns; undo_list = tsk->sysvsem.undo_list; if (!undo_list) @@ -1275,6 +1330,7 @@ void exit_sem(struct task_struct *tsk) if (!atomic_dec_and_test(&undo_list->refcnt)) return; + ns = tsk->nsproxy->ipc_ns; /* There's no need to hold the semundo list lock, as current * is the last task exiting for this undo list. */ @@ -1288,14 +1344,14 @@ void exit_sem(struct task_struct *tsk) if(semid == -1) continue; - sma = sem_lock(semid); + sma = sem_lock(ns, semid); if (sma == NULL) continue; if (u->semid == -1) goto next_entry; - BUG_ON(sem_checkid(sma,u->semid)); + BUG_ON(sem_checkid(ns,sma,u->semid)); /* remove u from the sma->undo list */ for (unp = &sma->undo; (un = *unp); unp = &un->id_next) { diff --git a/ipc/shm.c b/ipc/shm.c index 940b0c9b13a..6d16bb6de7d 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -15,6 +15,10 @@ * * support for audit of ipc object properties and permission changes * Dustin Kirkland <dustin.kirkland@us.ibm.com> + * + * namespaces support + * OpenVZ, SWsoft Inc. + * Pavel Emelianov <xemul@openvz.org> */ #include <linux/slab.h> @@ -32,6 +36,7 @@ #include <linux/ptrace.h> #include <linux/seq_file.h> #include <linux/mutex.h> +#include <linux/nsproxy.h> #include <asm/uaccess.h> @@ -40,59 +45,116 @@ static struct file_operations shm_file_operations; static struct vm_operations_struct shm_vm_ops; -static struct ipc_ids shm_ids; +static struct ipc_ids init_shm_ids; + +#define shm_ids(ns) (*((ns)->ids[IPC_SHM_IDS])) -#define shm_lock(id) ((struct shmid_kernel*)ipc_lock(&shm_ids,id)) -#define shm_unlock(shp) ipc_unlock(&(shp)->shm_perm) -#define shm_get(id) ((struct shmid_kernel*)ipc_get(&shm_ids,id)) -#define shm_buildid(id, seq) \ - ipc_buildid(&shm_ids, id, seq) +#define shm_lock(ns, id) \ + ((struct shmid_kernel*)ipc_lock(&shm_ids(ns),id)) +#define shm_unlock(shp) \ + ipc_unlock(&(shp)->shm_perm) +#define shm_get(ns, id) \ + ((struct shmid_kernel*)ipc_get(&shm_ids(ns),id)) +#define shm_buildid(ns, id, seq) \ + ipc_buildid(&shm_ids(ns), id, seq) -static int newseg (key_t key, int shmflg, size_t size); +static int newseg (struct ipc_namespace *ns, key_t key, + int shmflg, size_t size); static void shm_open (struct vm_area_struct *shmd); static void shm_close (struct vm_area_struct *shmd); +static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp); #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; -int shm_ctlmni = SHMMNI; +static void __ipc_init __shm_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids) +{ + ns->ids[IPC_SHM_IDS] = ids; + ns->shm_ctlmax = SHMMAX; + ns->shm_ctlall = SHMALL; + ns->shm_ctlmni = SHMMNI; + ns->shm_tot = 0; + ipc_init_ids(ids, 1); +} + +static void do_shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *shp) +{ + if (shp->shm_nattch){ + shp->shm_perm.mode |= SHM_DEST; + /* Do not find it any more */ + shp->shm_perm.key = IPC_PRIVATE; + shm_unlock(shp); + } else + shm_destroy(ns, shp); +} + +#ifdef CONFIG_IPC_NS +int shm_init_ns(struct ipc_namespace *ns) +{ + struct ipc_ids *ids; + + ids = kmalloc(sizeof(struct ipc_ids), GFP_KERNEL); + if (ids == NULL) + return -ENOMEM; -static int shm_tot; /* total number of shared memory pages */ + __shm_init_ns(ns, ids); + return 0; +} + +void shm_exit_ns(struct ipc_namespace *ns) +{ + int i; + struct shmid_kernel *shp; + + mutex_lock(&shm_ids(ns).mutex); + for (i = 0; i <= shm_ids(ns).max_id; i++) { + shp = shm_lock(ns, i); + if (shp == NULL) + continue; + + do_shm_rmid(ns, shp); + } + mutex_unlock(&shm_ids(ns).mutex); + + ipc_fini_ids(ns->ids[IPC_SHM_IDS]); + kfree(ns->ids[IPC_SHM_IDS]); + ns->ids[IPC_SHM_IDS] = NULL; +} +#endif void __init shm_init (void) { - ipc_init_ids(&shm_ids, 1); + __shm_init_ns(&init_ipc_ns, &init_shm_ids); ipc_init_proc_interface("sysvipc/shm", " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime\n", - &shm_ids, - sysvipc_shm_proc_show); + IPC_SHM_IDS, sysvipc_shm_proc_show); } -static inline int shm_checkid(struct shmid_kernel *s, int id) +static inline int shm_checkid(struct ipc_namespace *ns, + struct shmid_kernel *s, int id) { - if (ipc_checkid(&shm_ids,&s->shm_perm,id)) + if (ipc_checkid(&shm_ids(ns), &s->shm_perm, id)) return -EIDRM; return 0; } -static inline struct shmid_kernel *shm_rmid(int id) +static inline struct shmid_kernel *shm_rmid(struct ipc_namespace *ns, int id) { - return (struct shmid_kernel *)ipc_rmid(&shm_ids,id); + return (struct shmid_kernel *)ipc_rmid(&shm_ids(ns), id); } -static inline int shm_addid(struct shmid_kernel *shp) +static inline int shm_addid(struct ipc_namespace *ns, struct shmid_kernel *shp) { - return ipc_addid(&shm_ids, &shp->shm_perm, shm_ctlmni); + return ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni); } -static inline void shm_inc (int id) { +static inline void shm_inc(struct ipc_namespace *ns, int id) +{ struct shmid_kernel *shp; - shp = shm_lock(id); + shp = shm_lock(ns, id); BUG_ON(!shp); shp->shm_atim = get_seconds(); shp->shm_lprid = current->tgid; @@ -100,10 +162,13 @@ static inline void shm_inc (int id) { shm_unlock(shp); } +#define shm_file_ns(file) (*((struct ipc_namespace **)&(file)->private_data)) + /* This is called by fork, once for every shm attach. */ -static void shm_open (struct vm_area_struct *shmd) +static void shm_open(struct vm_area_struct *shmd) { - shm_inc (shmd->vm_file->f_dentry->d_inode->i_ino); + shm_inc(shm_file_ns(shmd->vm_file), + shmd->vm_file->f_path.dentry->d_inode->i_ino); } /* @@ -114,15 +179,15 @@ static void shm_open (struct vm_area_struct *shmd) * It has to be called with shp and shm_ids.mutex locked, * but returns with shp unlocked and freed. */ -static void shm_destroy (struct shmid_kernel *shp) +static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp) { - shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT; - shm_rmid (shp->id); + ns->shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT; + shm_rmid(ns, shp->id); shm_unlock(shp); if (!is_file_hugepages(shp->shm_file)) shmem_lock(shp->shm_file, 0, shp->mlock_user); else - user_shm_unlock(shp->shm_file->f_dentry->d_inode->i_size, + user_shm_unlock(shp->shm_file->f_path.dentry->d_inode->i_size, shp->mlock_user); fput (shp->shm_file); security_shm_free(shp); @@ -138,22 +203,25 @@ static void shm_destroy (struct shmid_kernel *shp) static void shm_close (struct vm_area_struct *shmd) { struct file * file = shmd->vm_file; - int id = file->f_dentry->d_inode->i_ino; + int id = file->f_path.dentry->d_inode->i_ino; struct shmid_kernel *shp; + struct ipc_namespace *ns; - mutex_lock(&shm_ids.mutex); + ns = shm_file_ns(file); + + mutex_lock(&shm_ids(ns).mutex); /* remove from the list of attaches of the shm segment */ - shp = shm_lock(id); + shp = shm_lock(ns, id); BUG_ON(!shp); shp->shm_lprid = current->tgid; shp->shm_dtim = get_seconds(); shp->shm_nattch--; if(shp->shm_nattch == 0 && shp->shm_perm.mode & SHM_DEST) - shm_destroy (shp); + shm_destroy(ns, shp); else shm_unlock(shp); - mutex_unlock(&shm_ids.mutex); + mutex_unlock(&shm_ids(ns).mutex); } static int shm_mmap(struct file * file, struct vm_area_struct * vma) @@ -165,14 +233,25 @@ static int shm_mmap(struct file * file, struct vm_area_struct * vma) vma->vm_ops = &shm_vm_ops; if (!(vma->vm_flags & VM_WRITE)) vma->vm_flags &= ~VM_MAYWRITE; - shm_inc(file->f_dentry->d_inode->i_ino); + shm_inc(shm_file_ns(file), file->f_path.dentry->d_inode->i_ino); } return ret; } +static int shm_release(struct inode *ino, struct file *file) +{ + struct ipc_namespace *ns; + + ns = shm_file_ns(file); + put_ipc_ns(ns); + shm_file_ns(file) = NULL; + return 0; +} + static struct file_operations shm_file_operations = { - .mmap = shm_mmap, + .mmap = shm_mmap, + .release = shm_release, #ifndef CONFIG_MMU .get_unmapped_area = shmem_get_unmapped_area, #endif @@ -188,7 +267,7 @@ static struct vm_operations_struct shm_vm_ops = { #endif }; -static int newseg (key_t key, int shmflg, size_t size) +static int newseg (struct ipc_namespace *ns, key_t key, int shmflg, size_t size) { int error; struct shmid_kernel *shp; @@ -197,10 +276,10 @@ static int newseg (key_t key, int shmflg, size_t size) char name[13]; int id; - if (size < SHMMIN || size > shm_ctlmax) + if (size < SHMMIN || size > ns->shm_ctlmax) return -EINVAL; - if (shm_tot + numpages >= shm_ctlall) + if (ns->shm_tot + numpages >= ns->shm_ctlall) return -ENOSPC; shp = ipc_rcu_alloc(sizeof(*shp)); @@ -239,7 +318,7 @@ static int newseg (key_t key, int shmflg, size_t size) goto no_file; error = -ENOSPC; - id = shm_addid(shp); + id = shm_addid(ns, shp); if(id == -1) goto no_id; @@ -249,15 +328,17 @@ static int newseg (key_t key, int shmflg, size_t size) shp->shm_ctim = get_seconds(); shp->shm_segsz = size; shp->shm_nattch = 0; - shp->id = shm_buildid(id,shp->shm_perm.seq); + shp->id = shm_buildid(ns, id, shp->shm_perm.seq); shp->shm_file = file; - file->f_dentry->d_inode->i_ino = shp->id; + file->f_path.dentry->d_inode->i_ino = shp->id; + + shm_file_ns(file) = get_ipc_ns(ns); /* Hugetlb ops would have already been assigned. */ if (!(shmflg & SHM_HUGETLB)) file->f_op = &shm_file_operations; - shm_tot += numpages; + ns->shm_tot += numpages; shm_unlock(shp); return shp->id; @@ -273,33 +354,36 @@ asmlinkage long sys_shmget (key_t key, size_t size, int shmflg) { struct shmid_kernel *shp; int err, id = 0; + struct ipc_namespace *ns; + + ns = current->nsproxy->ipc_ns; - mutex_lock(&shm_ids.mutex); + mutex_lock(&shm_ids(ns).mutex); if (key == IPC_PRIVATE) { - err = newseg(key, shmflg, size); - } else if ((id = ipc_findkey(&shm_ids, key)) == -1) { + err = newseg(ns, key, shmflg, size); + } else if ((id = ipc_findkey(&shm_ids(ns), key)) == -1) { if (!(shmflg & IPC_CREAT)) err = -ENOENT; else - err = newseg(key, shmflg, size); + err = newseg(ns, key, shmflg, size); } else if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL)) { err = -EEXIST; } else { - shp = shm_lock(id); + shp = shm_lock(ns, id); BUG_ON(shp==NULL); if (shp->shm_segsz < size) err = -EINVAL; else if (ipcperms(&shp->shm_perm, shmflg)) err = -EACCES; else { - int shmid = shm_buildid(id, shp->shm_perm.seq); + int shmid = shm_buildid(ns, id, shp->shm_perm.seq); err = security_shm_associate(shp, shmflg); if (!err) err = shmid; } shm_unlock(shp); } - mutex_unlock(&shm_ids.mutex); + mutex_unlock(&shm_ids(ns).mutex); return err; } @@ -395,22 +479,23 @@ static inline unsigned long copy_shminfo_to_user(void __user *buf, struct shminf } } -static void shm_get_stat(unsigned long *rss, unsigned long *swp) +static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss, + unsigned long *swp) { int i; *rss = 0; *swp = 0; - for (i = 0; i <= shm_ids.max_id; i++) { + for (i = 0; i <= shm_ids(ns).max_id; i++) { struct shmid_kernel *shp; struct inode *inode; - shp = shm_get(i); + shp = shm_get(ns, i); if(!shp) continue; - inode = shp->shm_file->f_dentry->d_inode; + inode = shp->shm_file->f_path.dentry->d_inode; if (is_file_hugepages(shp->shm_file)) { struct address_space *mapping = inode->i_mapping; @@ -430,6 +515,7 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) struct shm_setbuf setbuf; struct shmid_kernel *shp; int err, version; + struct ipc_namespace *ns; if (cmd < 0 || shmid < 0) { err = -EINVAL; @@ -437,6 +523,7 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) } version = ipc_parse_version(&cmd); + ns = current->nsproxy->ipc_ns; switch (cmd) { /* replace with proc interface ? */ case IPC_INFO: @@ -448,15 +535,15 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) return err; memset(&shminfo,0,sizeof(shminfo)); - shminfo.shmmni = shminfo.shmseg = shm_ctlmni; - shminfo.shmmax = shm_ctlmax; - shminfo.shmall = shm_ctlall; + shminfo.shmmni = shminfo.shmseg = ns->shm_ctlmni; + shminfo.shmmax = ns->shm_ctlmax; + shminfo.shmall = ns->shm_ctlall; shminfo.shmmin = SHMMIN; if(copy_shminfo_to_user (buf, &shminfo, version)) return -EFAULT; /* reading a integer is always atomic */ - err= shm_ids.max_id; + err= shm_ids(ns).max_id; if(err<0) err = 0; goto out; @@ -470,14 +557,14 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) return err; memset(&shm_info,0,sizeof(shm_info)); - mutex_lock(&shm_ids.mutex); - shm_info.used_ids = shm_ids.in_use; - shm_get_stat (&shm_info.shm_rss, &shm_info.shm_swp); - shm_info.shm_tot = shm_tot; + mutex_lock(&shm_ids(ns).mutex); + shm_info.used_ids = shm_ids(ns).in_use; + shm_get_stat (ns, &shm_info.shm_rss, &shm_info.shm_swp); + shm_info.shm_tot = ns->shm_tot; shm_info.swap_attempts = 0; shm_info.swap_successes = 0; - err = shm_ids.max_id; - mutex_unlock(&shm_ids.mutex); + err = shm_ids(ns).max_id; + mutex_unlock(&shm_ids(ns).mutex); if(copy_to_user (buf, &shm_info, sizeof(shm_info))) { err = -EFAULT; goto out; @@ -492,17 +579,17 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) struct shmid64_ds tbuf; int result; memset(&tbuf, 0, sizeof(tbuf)); - shp = shm_lock(shmid); + shp = shm_lock(ns, shmid); if(shp==NULL) { err = -EINVAL; goto out; } else if(cmd==SHM_STAT) { err = -EINVAL; - if (shmid > shm_ids.max_id) + if (shmid > shm_ids(ns).max_id) goto out_unlock; - result = shm_buildid(shmid, shp->shm_perm.seq); + result = shm_buildid(ns, shmid, shp->shm_perm.seq); } else { - err = shm_checkid(shp,shmid); + err = shm_checkid(ns, shp,shmid); if(err) goto out_unlock; result = 0; @@ -534,12 +621,12 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) case SHM_LOCK: case SHM_UNLOCK: { - shp = shm_lock(shmid); + shp = shm_lock(ns, shmid); if(shp==NULL) { err = -EINVAL; goto out; } - err = shm_checkid(shp,shmid); + err = shm_checkid(ns, shp,shmid); if(err) goto out_unlock; @@ -590,12 +677,12 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) * Instead we set a destroyed flag, and then blow * the name away when the usage hits zero. */ - mutex_lock(&shm_ids.mutex); - shp = shm_lock(shmid); + mutex_lock(&shm_ids(ns).mutex); + shp = shm_lock(ns, shmid); err = -EINVAL; if (shp == NULL) goto out_up; - err = shm_checkid(shp, shmid); + err = shm_checkid(ns, shp, shmid); if(err) goto out_unlock_up; @@ -614,14 +701,8 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) if (err) goto out_unlock_up; - if (shp->shm_nattch){ - shp->shm_perm.mode |= SHM_DEST; - /* Do not find it any more */ - shp->shm_perm.key = IPC_PRIVATE; - shm_unlock(shp); - } else - shm_destroy (shp); - mutex_unlock(&shm_ids.mutex); + do_shm_rmid(ns, shp); + mutex_unlock(&shm_ids(ns).mutex); goto out; } @@ -631,12 +712,12 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) err = -EFAULT; goto out; } - mutex_lock(&shm_ids.mutex); - shp = shm_lock(shmid); + mutex_lock(&shm_ids(ns).mutex); + shp = shm_lock(ns, shmid); err=-EINVAL; if(shp==NULL) goto out_up; - err = shm_checkid(shp,shmid); + err = shm_checkid(ns, shp,shmid); if(err) goto out_unlock_up; err = audit_ipc_obj(&(shp->shm_perm)); @@ -673,7 +754,7 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) out_unlock_up: shm_unlock(shp); out_up: - mutex_unlock(&shm_ids.mutex); + mutex_unlock(&shm_ids(ns).mutex); goto out; out_unlock: shm_unlock(shp); @@ -699,6 +780,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr) unsigned long prot; int acc_mode; void *user_addr; + struct ipc_namespace *ns; if (shmid < 0) { err = -EINVAL; @@ -737,12 +819,13 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr) * We cannot rely on the fs check since SYSV IPC does have an * additional creator id... */ - shp = shm_lock(shmid); + ns = current->nsproxy->ipc_ns; + shp = shm_lock(ns, shmid); if(shp == NULL) { err = -EINVAL; goto out; } - err = shm_checkid(shp,shmid); + err = shm_checkid(ns, shp,shmid); if (err) { shm_unlock(shp); goto out; @@ -760,7 +843,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr) } file = shp->shm_file; - size = i_size_read(file->f_dentry->d_inode); + size = i_size_read(file->f_path.dentry->d_inode); shp->shm_nattch++; shm_unlock(shp); @@ -783,16 +866,16 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr) invalid: up_write(¤t->mm->mmap_sem); - mutex_lock(&shm_ids.mutex); - shp = shm_lock(shmid); + mutex_lock(&shm_ids(ns).mutex); + shp = shm_lock(ns, shmid); BUG_ON(!shp); shp->shm_nattch--; if(shp->shm_nattch == 0 && shp->shm_perm.mode & SHM_DEST) - shm_destroy (shp); + shm_destroy(ns, shp); else shm_unlock(shp); - mutex_unlock(&shm_ids.mutex); + mutex_unlock(&shm_ids(ns).mutex); *raddr = (unsigned long) user_addr; err = 0; @@ -865,7 +948,7 @@ asmlinkage long sys_shmdt(char __user *shmaddr) (vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) { - size = vma->vm_file->f_dentry->d_inode->i_size; + size = vma->vm_file->f_path.dentry->d_inode->i_size; do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start); /* * We discovered the size of the shm segment, so diff --git a/ipc/util.c b/ipc/util.c index 67b6d178db6..a9b7a227b8d 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -12,6 +12,9 @@ * Mingming Cao <cmm@us.ibm.com> * Mar 2006 - support for audit of ipc object properties * Dustin Kirkland <dustin.kirkland@us.ibm.com> + * Jun 2006 - namespaces ssupport + * OpenVZ, SWsoft Inc. + * Pavel Emelianov <xemul@openvz.org> */ #include <linux/mm.h> @@ -29,6 +32,7 @@ #include <linux/seq_file.h> #include <linux/proc_fs.h> #include <linux/audit.h> +#include <linux/nsproxy.h> #include <asm/unistd.h> @@ -37,10 +41,111 @@ struct ipc_proc_iface { const char *path; const char *header; - struct ipc_ids *ids; + int ids; int (*show)(struct seq_file *, void *); }; +struct ipc_namespace init_ipc_ns = { + .kref = { + .refcount = ATOMIC_INIT(2), + }, +}; + +#ifdef CONFIG_IPC_NS +static struct ipc_namespace *clone_ipc_ns(struct ipc_namespace *old_ns) +{ + int err; + struct ipc_namespace *ns; + + err = -ENOMEM; + ns = kmalloc(sizeof(struct ipc_namespace), GFP_KERNEL); + if (ns == NULL) + goto err_mem; + + err = sem_init_ns(ns); + if (err) + goto err_sem; + err = msg_init_ns(ns); + if (err) + goto err_msg; + err = shm_init_ns(ns); + if (err) + goto err_shm; + + kref_init(&ns->kref); + return ns; + +err_shm: + msg_exit_ns(ns); +err_msg: + sem_exit_ns(ns); +err_sem: + kfree(ns); +err_mem: + return ERR_PTR(err); +} + +int unshare_ipcs(unsigned long unshare_flags, struct ipc_namespace **new_ipc) +{ + struct ipc_namespace *new; + + if (unshare_flags & CLONE_NEWIPC) { + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + new = clone_ipc_ns(current->nsproxy->ipc_ns); + if (IS_ERR(new)) + return PTR_ERR(new); + + *new_ipc = new; + } + + return 0; +} + +int copy_ipcs(unsigned long flags, struct task_struct *tsk) +{ + struct ipc_namespace *old_ns = tsk->nsproxy->ipc_ns; + struct ipc_namespace *new_ns; + int err = 0; + + if (!old_ns) + return 0; + + get_ipc_ns(old_ns); + + if (!(flags & CLONE_NEWIPC)) + return 0; + + if (!capable(CAP_SYS_ADMIN)) { + err = -EPERM; + goto out; + } + + new_ns = clone_ipc_ns(old_ns); + if (!new_ns) { + err = -ENOMEM; + goto out; + } + + tsk->nsproxy->ipc_ns = new_ns; +out: + put_ipc_ns(old_ns); + return err; +} + +void free_ipc_ns(struct kref *kref) +{ + struct ipc_namespace *ns; + + ns = container_of(kref, struct ipc_namespace, kref); + sem_exit_ns(ns); + msg_exit_ns(ns); + shm_exit_ns(ns); + kfree(ns); +} +#endif + /** * ipc_init - initialise IPC subsystem * @@ -67,7 +172,7 @@ __initcall(ipc_init); * array itself. */ -void __init ipc_init_ids(struct ipc_ids* ids, int size) +void __ipc_init ipc_init_ids(struct ipc_ids* ids, int size) { int i; @@ -110,8 +215,7 @@ static struct file_operations sysvipc_proc_fops; * @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 *)) + int ids, int (*show)(struct seq_file *, void *)) { struct proc_dir_entry *pde; struct ipc_proc_iface *iface; @@ -197,7 +301,7 @@ static int grow_ary(struct ipc_ids* ids, int newsize) */ rcu_assign_pointer(ids->entries, new); - ipc_rcu_putref(old); + __ipc_fini_ids(ids, old); return newsize; } @@ -410,6 +514,11 @@ void ipc_rcu_getref(void *ptr) container_of(ptr, struct ipc_rcu_hdr, data)->refcount++; } +static void ipc_do_vfree(struct work_struct *work) +{ + vfree(container_of(work, struct ipc_rcu_sched, work)); +} + /** * ipc_schedule_free - free ipc + rcu space * @head: RCU callback structure for queued work @@ -424,7 +533,7 @@ static void ipc_schedule_free(struct rcu_head *head) struct ipc_rcu_sched *sched = container_of(&(grace->data[0]), struct ipc_rcu_sched, data[0]); - INIT_WORK(&sched->work, vfree, sched); + INIT_WORK(&sched->work, ipc_do_vfree); schedule_work(&sched->work); } @@ -635,6 +744,9 @@ static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos) struct ipc_proc_iface *iface = s->private; struct kern_ipc_perm *ipc = it; loff_t p; + struct ipc_ids *ids; + + ids = current->nsproxy->ipc_ns->ids[iface->ids]; /* If we had an ipc id locked before, unlock it */ if (ipc && ipc != SEQ_START_TOKEN) @@ -644,8 +756,8 @@ static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos) * 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; } @@ -664,12 +776,15 @@ static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos) struct ipc_proc_iface *iface = s->private; struct kern_ipc_perm *ipc; loff_t p; + struct ipc_ids *ids; + + ids = current->nsproxy->ipc_ns->ids[iface->ids]; /* * Take the lock - this will be released by the corresponding * call to stop(). */ - mutex_lock(&iface->ids->mutex); + mutex_lock(&ids->mutex); /* pos < 0 is invalid */ if (*pos < 0) @@ -680,8 +795,8 @@ static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos) 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; } @@ -693,13 +808,15 @@ static void sysvipc_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; /* If we had a locked segment, release it */ if (ipc && ipc != SEQ_START_TOKEN) ipc_unlock(ipc); + ids = current->nsproxy->ipc_ns->ids[iface->ids]; /* Release the lock we took in start() */ - mutex_unlock(&iface->ids->mutex); + mutex_unlock(&ids->mutex); } static int sysvipc_proc_show(struct seq_file *s, void *it) diff --git a/ipc/util.h b/ipc/util.h index 0181553d31d..e3aa2c5c97d 100644 --- a/ipc/util.h +++ b/ipc/util.h @@ -3,6 +3,8 @@ * Copyright (C) 1999 Christoph Rohland * * ipc helper functions (c) 1999 Manfred Spraul <manfred@colorfullife.com> + * namespaces support. 2006 OpenVZ, SWsoft Inc. + * Pavel Emelianov <xemul@openvz.org> */ #ifndef _IPC_UTIL_H @@ -15,6 +17,14 @@ void sem_init (void); void msg_init (void); void shm_init (void); +int sem_init_ns(struct ipc_namespace *ns); +int msg_init_ns(struct ipc_namespace *ns); +int shm_init_ns(struct ipc_namespace *ns); + +void sem_exit_ns(struct ipc_namespace *ns); +void msg_exit_ns(struct ipc_namespace *ns); +void shm_exit_ns(struct ipc_namespace *ns); + struct ipc_id_ary { int size; struct kern_ipc_perm *p[0]; @@ -31,15 +41,23 @@ struct ipc_ids { }; struct seq_file; -void __init ipc_init_ids(struct ipc_ids* ids, int size); +#ifdef CONFIG_IPC_NS +#define __ipc_init +#else +#define __ipc_init __init +#endif +void __ipc_init ipc_init_ids(struct ipc_ids *ids, int size); #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 *)); + int ids, int (*show)(struct seq_file *, void *)); #else #define ipc_init_proc_interface(path, header, ids, show) do {} while (0) #endif +#define IPC_SEM_IDS 0 +#define IPC_MSG_IDS 1 +#define IPC_SHM_IDS 2 + /* must be called with ids->mutex acquired.*/ int ipc_findkey(struct ipc_ids* ids, key_t key); int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size); @@ -65,6 +83,18 @@ void* ipc_rcu_alloc(int size); void ipc_rcu_getref(void *ptr); void ipc_rcu_putref(void *ptr); +static inline void __ipc_fini_ids(struct ipc_ids *ids, + struct ipc_id_ary *entries) +{ + if (entries != &ids->nullentry) + ipc_rcu_putref(entries); +} + +static inline void ipc_fini_ids(struct ipc_ids *ids) +{ + __ipc_fini_ids(ids, ids->entries); +} + struct kern_ipc_perm* ipc_get(struct ipc_ids* ids, int id); struct kern_ipc_perm* ipc_lock(struct ipc_ids* ids, int id); void ipc_lock_by_ptr(struct kern_ipc_perm *ipcp); |