serial: PL011: clear pending interrupts
[linux-flexiantxendom0.git] / ipc / msg.c
index be8449d..7385de2 100644 (file)
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -23,7 +23,6 @@
  */
 
 #include <linux/capability.h>
-#include <linux/slab.h>
 #include <linux/msg.h>
 #include <linux/spinlock.h>
 #include <linux/init.h>
@@ -84,7 +83,7 @@ static int sysvipc_msg_proc_show(struct seq_file *s, void *it);
  * Also take into account the number of nsproxies created so far.
  * This should be done staying within the (MSGMNI , IPCMNI/nr_ipc_ns) range.
  */
-static void recompute_msgmni(struct ipc_namespace *ns)
+void recompute_msgmni(struct ipc_namespace *ns)
 {
        struct sysinfo i;
        unsigned long allowed;
@@ -98,20 +97,15 @@ static void recompute_msgmni(struct ipc_namespace *ns)
 
        if (allowed < MSGMNI) {
                ns->msg_ctlmni = MSGMNI;
-               goto out_callback;
+               return;
        }
 
        if (allowed > IPCMNI / nb_ns) {
                ns->msg_ctlmni = IPCMNI / nb_ns;
-               goto out_callback;
+               return;
        }
 
        ns->msg_ctlmni = allowed;
-
-out_callback:
-
-       printk(KERN_INFO "msgmni has been set to %d for ipc namespace %p\n",
-               ns->msg_ctlmni, ns);
 }
 
 void msg_init_ns(struct ipc_namespace *ns)
@@ -130,33 +124,23 @@ void msg_init_ns(struct ipc_namespace *ns)
 void msg_exit_ns(struct ipc_namespace *ns)
 {
        free_ipcs(ns, &msg_ids(ns), freeque);
+       idr_destroy(&ns->ids[IPC_MSG_IDS].ipcs_idr);
 }
 #endif
 
 void __init msg_init(void)
 {
        msg_init_ns(&init_ipc_ns);
+
+       printk(KERN_INFO "msgmni has been set to %d\n",
+               init_ipc_ns.msg_ctlmni);
+
        ipc_init_proc_interface("sysvipc/msg",
                                "       key      msqid perms      cbytes       qnum lspid lrpid   uid   gid  cuid  cgid      stime      rtime      ctime\n",
                                IPC_MSG_IDS, sysvipc_msg_proc_show);
 }
 
 /*
- * This routine is called in the paths where the rw_mutex is held to protect
- * access to the idr tree.
- */
-static inline struct msg_queue *msg_lock_check_down(struct ipc_namespace *ns,
-                                               int id)
-{
-       struct kern_ipc_perm *ipcp = ipc_lock_check_down(&msg_ids(ns), id);
-
-       if (IS_ERR(ipcp))
-               return (struct msg_queue *)ipcp;
-
-       return container_of(ipcp, struct msg_queue, q_perm);
-}
-
-/*
  * msg_lock_(check_) routines are called in the paths where the rw_mutex
  * is not held.
  */
@@ -325,7 +309,7 @@ static inline int msg_security(struct kern_ipc_perm *ipcp, int msgflg)
        return security_msg_queue_associate(msq, msgflg);
 }
 
-asmlinkage long sys_msgget(key_t key, int msgflg)
+SYSCALL_DEFINE2(msgget, key_t, key, int, msgflg)
 {
        struct ipc_namespace *ns;
        struct ipc_ops msg_ops;
@@ -388,31 +372,14 @@ copy_msqid_to_user(void __user *buf, struct msqid64_ds *in, int version)
        }
 }
 
-struct msq_setbuf {
-       unsigned long   qbytes;
-       uid_t           uid;
-       gid_t           gid;
-       mode_t          mode;
-};
-
 static inline unsigned long
-copy_msqid_from_user(struct msq_setbuf *out, void __user *buf, int version)
+copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version)
 {
        switch(version) {
        case IPC_64:
-       {
-               struct msqid64_ds tbuf;
-
-               if (copy_from_user(&tbuf, buf, sizeof(tbuf)))
+               if (copy_from_user(out, buf, sizeof(*out)))
                        return -EFAULT;
-
-               out->qbytes             = tbuf.msg_qbytes;
-               out->uid                = tbuf.msg_perm.uid;
-               out->gid                = tbuf.msg_perm.gid;
-               out->mode               = tbuf.msg_perm.mode;
-
                return 0;
-       }
        case IPC_OLD:
        {
                struct msqid_ds tbuf_old;
@@ -420,14 +387,14 @@ copy_msqid_from_user(struct msq_setbuf *out, void __user *buf, int version)
                if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))
                        return -EFAULT;
 
-               out->uid                = tbuf_old.msg_perm.uid;
-               out->gid                = tbuf_old.msg_perm.gid;
-               out->mode               = tbuf_old.msg_perm.mode;
+               out->msg_perm.uid       = tbuf_old.msg_perm.uid;
+               out->msg_perm.gid       = tbuf_old.msg_perm.gid;
+               out->msg_perm.mode      = tbuf_old.msg_perm.mode;
 
                if (tbuf_old.msg_qbytes == 0)
-                       out->qbytes     = tbuf_old.msg_lqbytes;
+                       out->msg_qbytes = tbuf_old.msg_lqbytes;
                else
-                       out->qbytes     = tbuf_old.msg_qbytes;
+                       out->msg_qbytes = tbuf_old.msg_qbytes;
 
                return 0;
        }
@@ -436,10 +403,71 @@ copy_msqid_from_user(struct msq_setbuf *out, void __user *buf, int version)
        }
 }
 
-asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
+/*
+ * This function handles some msgctl commands which require the rw_mutex
+ * to be held in write mode.
+ * NOTE: no locks must be held, the rw_mutex is taken inside this function.
+ */
+static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
+                      struct msqid_ds __user *buf, int version)
 {
        struct kern_ipc_perm *ipcp;
-       struct msq_setbuf uninitialized_var(setbuf);
+       struct msqid64_ds uninitialized_var(msqid64);
+       struct msg_queue *msq;
+       int err;
+
+       if (cmd == IPC_SET) {
+               if (copy_msqid_from_user(&msqid64, buf, version))
+                       return -EFAULT;
+       }
+
+       ipcp = ipcctl_pre_down(ns, &msg_ids(ns), msqid, cmd,
+                              &msqid64.msg_perm, msqid64.msg_qbytes);
+       if (IS_ERR(ipcp))
+               return PTR_ERR(ipcp);
+
+       msq = container_of(ipcp, struct msg_queue, q_perm);
+
+       err = security_msg_queue_msgctl(msq, cmd);
+       if (err)
+               goto out_unlock;
+
+       switch (cmd) {
+       case IPC_RMID:
+               freeque(ns, ipcp);
+               goto out_up;
+       case IPC_SET:
+               if (msqid64.msg_qbytes > ns->msg_ctlmnb &&
+                   !capable(CAP_SYS_RESOURCE)) {
+                       err = -EPERM;
+                       goto out_unlock;
+               }
+
+               msq->q_qbytes = msqid64.msg_qbytes;
+
+               ipc_update_perm(&msqid64.msg_perm, ipcp);
+               msq->q_ctime = get_seconds();
+               /* sleeping receivers might be excluded by
+                * stricter permissions.
+                */
+               expunge_all(msq, -EAGAIN);
+               /* sleeping senders might be able to send
+                * due to a larger queue size.
+                */
+               ss_wakeup(&msq->q_senders, 0);
+               break;
+       default:
+               err = -EINVAL;
+       }
+out_unlock:
+       msg_unlock(msq);
+out_up:
+       up_write(&msg_ids(ns).rw_mutex);
+       return err;
+}
+
+SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf)
+{
        struct msg_queue *msq;
        int err, version;
        struct ipc_namespace *ns;
@@ -511,7 +539,7 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
                        success_return = 0;
                }
                err = -EACCES;
-               if (ipcperms(&msq->q_perm, S_IRUGO))
+               if (ipcperms(ns, &msq->q_perm, S_IRUGO))
                        goto out_unlock;
 
                err = security_msg_queue_msgctl(msq, cmd);
@@ -535,82 +563,13 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
                return success_return;
        }
        case IPC_SET:
-               if (!buf)
-                       return -EFAULT;
-               if (copy_msqid_from_user(&setbuf, buf, version))
-                       return -EFAULT;
-               break;
        case IPC_RMID:
-               break;
+               err = msgctl_down(ns, msqid, cmd, buf, version);
+               return err;
        default:
                return  -EINVAL;
        }
 
-       down_write(&msg_ids(ns).rw_mutex);
-       msq = msg_lock_check_down(ns, msqid);
-       if (IS_ERR(msq)) {
-               err = PTR_ERR(msq);
-               goto out_up;
-       }
-
-       ipcp = &msq->q_perm;
-
-       err = audit_ipc_obj(ipcp);
-       if (err)
-               goto out_unlock_up;
-       if (cmd == IPC_SET) {
-               err = audit_ipc_set_perm(setbuf.qbytes, setbuf.uid, setbuf.gid,
-                                        setbuf.mode);
-               if (err)
-                       goto out_unlock_up;
-       }
-
-       err = -EPERM;
-       if (current->euid != ipcp->cuid &&
-           current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN))
-               /* We _could_ check for CAP_CHOWN above, but we don't */
-               goto out_unlock_up;
-
-       err = security_msg_queue_msgctl(msq, cmd);
-       if (err)
-               goto out_unlock_up;
-
-       switch (cmd) {
-       case IPC_SET:
-       {
-               err = -EPERM;
-               if (setbuf.qbytes > ns->msg_ctlmnb && !capable(CAP_SYS_RESOURCE))
-                       goto out_unlock_up;
-
-               msq->q_qbytes = setbuf.qbytes;
-
-               ipcp->uid = setbuf.uid;
-               ipcp->gid = setbuf.gid;
-               ipcp->mode = (ipcp->mode & ~S_IRWXUGO) |
-                            (S_IRWXUGO & setbuf.mode);
-               msq->q_ctime = get_seconds();
-               /* sleeping receivers might be excluded by
-                * stricter permissions.
-                */
-               expunge_all(msq, -EAGAIN);
-               /* sleeping senders might be able to send
-                * due to a larger queue size.
-                */
-               ss_wakeup(&msq->q_senders, 0);
-               msg_unlock(msq);
-               break;
-       }
-       case IPC_RMID:
-               freeque(ns, &msq->q_perm);
-               break;
-       }
-       err = 0;
-out_up:
-       up_write(&msg_ids(ns).rw_mutex);
-       return err;
-out_unlock_up:
-       msg_unlock(msq);
-       goto out_up;
 out_unlock:
        msg_unlock(msq);
        return err;
@@ -705,7 +664,7 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
                struct msg_sender s;
 
                err = -EACCES;
-               if (ipcperms(&msq->q_perm, S_IWUGO))
+               if (ipcperms(ns, &msq->q_perm, S_IWUGO))
                        goto out_unlock_free;
 
                err = security_msg_queue_msgsnd(msq, msg, msgflg);
@@ -745,7 +704,7 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
        msq->q_stime = get_seconds();
 
        if (!pipelined_send(msq, msg)) {
-               /* noone is waiting for this message, enqueue it */
+               /* no one is waiting for this message, enqueue it */
                list_add_tail(&msg->m_list, &msq->q_messages);
                msq->q_cbytes += msgsz;
                msq->q_qnum++;
@@ -764,8 +723,8 @@ out_free:
        return err;
 }
 
-asmlinkage long
-sys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg)
+SYSCALL_DEFINE4(msgsnd, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz,
+               int, msgflg)
 {
        long mtype;
 
@@ -815,7 +774,7 @@ long do_msgrcv(int msqid, long *pmtype, void __user *mtext,
                struct list_head *tmp;
 
                msg = ERR_PTR(-EACCES);
-               if (ipcperms(&msq->q_perm, S_IRUGO))
+               if (ipcperms(ns, &msq->q_perm, S_IRUGO))
                        goto out_unlock;
 
                msg = ERR_PTR(-EAGAIN);
@@ -883,7 +842,7 @@ long do_msgrcv(int msqid, long *pmtype, void __user *mtext,
                 * Disable preemption.  We don't hold a reference to the queue
                 * and getting a reference would defeat the idea of a lockless
                 * operation, thus the code relies on rcu to guarantee the
-                * existance of msq:
+                * existence of msq:
                 * Prior to destruction, expunge_all(-EIRDM) changes r_msg.
                 * Thus if r_msg is -EAGAIN, then the queue not yet destroyed.
                 * rcu_read_lock() prevents preemption between reading r_msg
@@ -945,8 +904,8 @@ out_unlock:
        return msgsz;
 }
 
-asmlinkage long sys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz,
-                          long msgtyp, int msgflg)
+SYSCALL_DEFINE5(msgrcv, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz,
+               long, msgtyp, int, msgflg)
 {
        long err, mtype;