]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - ipc/msg.c
[PATCH] mark struct file_operations const 2
[linux-2.6.git] / ipc / msg.c
index 2b4fccf8ea55a9a2babc5f92b36fcdf6a1dd5a7d..a388824740e7e9c1e770dde9d3082609c0e8f017 100644 (file)
--- a/ipc/msg.c
+++ b/ipc/msg.c
  *
  * 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>
 #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)
 {