]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 15 Oct 2013 23:53:06 +0000 (16:53 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 15 Oct 2013 23:53:06 +0000 (16:53 -0700)
added patches:
ipc-drop-ipcctl_pre_down.patch
ipc-msg.c-fix-lost-wakeup-in-msgsnd.patch
ipc-shm-cleanup-do_shmat-pasta.patch
ipc-shm-introduce-lockless-functions-to-obtain-the-ipc-object.patch
ipc-shm-introduce-shmctl_nolock.patch
ipc-shm-make-shmctl_nolock-lockless.patch
ipc-shm-shorten-critical-region-for-shmat.patch
ipc-shm-shorten-critical-region-for-shmctl.patch
ipc-shm-shorten-critical-region-in-shmctl_down.patch

queue-3.10/ipc-drop-ipcctl_pre_down.patch [new file with mode: 0644]
queue-3.10/ipc-msg.c-fix-lost-wakeup-in-msgsnd.patch [new file with mode: 0644]
queue-3.10/ipc-shm-cleanup-do_shmat-pasta.patch [new file with mode: 0644]
queue-3.10/ipc-shm-introduce-lockless-functions-to-obtain-the-ipc-object.patch [new file with mode: 0644]
queue-3.10/ipc-shm-introduce-shmctl_nolock.patch [new file with mode: 0644]
queue-3.10/ipc-shm-make-shmctl_nolock-lockless.patch [new file with mode: 0644]
queue-3.10/ipc-shm-shorten-critical-region-for-shmat.patch [new file with mode: 0644]
queue-3.10/ipc-shm-shorten-critical-region-for-shmctl.patch [new file with mode: 0644]
queue-3.10/ipc-shm-shorten-critical-region-in-shmctl_down.patch [new file with mode: 0644]
queue-3.10/series

diff --git a/queue-3.10/ipc-drop-ipcctl_pre_down.patch b/queue-3.10/ipc-drop-ipcctl_pre_down.patch
new file mode 100644 (file)
index 0000000..c45adaf
--- /dev/null
@@ -0,0 +1,83 @@
+From 3b1c4ad37741e53804ffe0a30dd01e08b2ab6241 Mon Sep 17 00:00:00 2001
+From: Davidlohr Bueso <davidlohr.bueso@hp.com>
+Date: Wed, 11 Sep 2013 14:26:17 -0700
+Subject: ipc: drop ipcctl_pre_down
+
+From: Davidlohr Bueso <davidlohr.bueso@hp.com>
+
+commit 3b1c4ad37741e53804ffe0a30dd01e08b2ab6241 upstream.
+
+Now that sem, msgque and shm, through *_down(), all use the lockless
+variant of ipcctl_pre_down(), go ahead and delete it.
+
+[akpm@linux-foundation.org: fix function name in kerneldoc, cleanups]
+Signed-off-by: Davidlohr Bueso <davidlohr.bueso@hp.com>
+Tested-by: Sedat Dilek <sedat.dilek@gmail.com>
+Cc: Rik van Riel <riel@redhat.com>
+Cc: Manfred Spraul <manfred@colorfullife.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Mike Galbraith <efault@gmx.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ ipc/util.c |   24 ++++--------------------
+ ipc/util.h |    3 ---
+ 2 files changed, 4 insertions(+), 23 deletions(-)
+
+--- a/ipc/util.c
++++ b/ipc/util.c
+@@ -733,7 +733,7 @@ int ipc_update_perm(struct ipc64_perm *i
+ }
+ /**
+- * ipcctl_pre_down - retrieve an ipc and check permissions for some IPC_XXX cmd
++ * ipcctl_pre_down_nolock - retrieve an ipc and check permissions for some IPC_XXX cmd
+  * @ns:  the ipc namespace
+  * @ids:  the table of ids where to look for the ipc
+  * @id:   the id of the ipc to retrieve
+@@ -746,29 +746,13 @@ int ipc_update_perm(struct ipc64_perm *i
+  * It must be called without any lock held and
+  *  - retrieves the ipc with the given id in the given table.
+  *  - performs some audit and permission check, depending on the given cmd
+- *  - returns the ipc with the ipc lock held in case of success
+- *    or an err-code without any lock held otherwise.
++ *  - returns a pointer to the ipc object or otherwise, the corresponding error.
+  *
+  * Call holding the both the rw_mutex and the rcu read lock.
+  */
+-struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
+-                                    struct ipc_ids *ids, int id, int cmd,
+-                                    struct ipc64_perm *perm, int extra_perm)
+-{
+-      struct kern_ipc_perm *ipcp;
+-
+-      ipcp = ipcctl_pre_down_nolock(ns, ids, id, cmd, perm, extra_perm);
+-      if (IS_ERR(ipcp))
+-              goto out;
+-
+-      spin_lock(&ipcp->lock);
+-out:
+-      return ipcp;
+-}
+-
+ struct kern_ipc_perm *ipcctl_pre_down_nolock(struct ipc_namespace *ns,
+-                                           struct ipc_ids *ids, int id, int cmd,
+-                                           struct ipc64_perm *perm, int extra_perm)
++                                      struct ipc_ids *ids, int id, int cmd,
++                                      struct ipc64_perm *perm, int extra_perm)
+ {
+       kuid_t euid;
+       int err = -EPERM;
+--- a/ipc/util.h
++++ b/ipc/util.h
+@@ -131,9 +131,6 @@ int ipc_update_perm(struct ipc64_perm *i
+ struct kern_ipc_perm *ipcctl_pre_down_nolock(struct ipc_namespace *ns,
+                                            struct ipc_ids *ids, int id, int cmd,
+                                            struct ipc64_perm *perm, int extra_perm);
+-struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
+-                                    struct ipc_ids *ids, int id, int cmd,
+-                                    struct ipc64_perm *perm, int extra_perm);
+ #ifndef CONFIG_ARCH_WANT_IPC_PARSE_VERSION
+   /* On IA-64, we always use the "64-bit version" of the IPC structures.  */ 
diff --git a/queue-3.10/ipc-msg.c-fix-lost-wakeup-in-msgsnd.patch b/queue-3.10/ipc-msg.c-fix-lost-wakeup-in-msgsnd.patch
new file mode 100644 (file)
index 0000000..e25d34e
--- /dev/null
@@ -0,0 +1,91 @@
+From bebcb928c820d0ee83aca4b192adc195e43e66a2 Mon Sep 17 00:00:00 2001
+From: Manfred Spraul <manfred@colorfullife.com>
+Date: Tue, 3 Sep 2013 16:00:08 +0200
+Subject: ipc/msg.c: Fix lost wakeup in msgsnd().
+
+From: Manfred Spraul <manfred@colorfullife.com>
+
+commit bebcb928c820d0ee83aca4b192adc195e43e66a2 upstream.
+
+The check if the queue is full and adding current to the wait queue of
+pending msgsnd() operations (ss_add()) must be atomic.
+
+Otherwise:
+ - the thread that performs msgsnd() finds a full queue and decides to
+   sleep.
+ - the thread that performs msgrcv() first reads all messages from the
+   queue and then sleeps, because the queue is empty.
+ - the msgrcv() calls do not perform any wakeups, because the msgsnd()
+   task has not yet called ss_add().
+ - then the msgsnd()-thread first calls ss_add() and then sleeps.
+
+Net result: msgsnd() and msgrcv() both sleep forever.
+
+Observed with msgctl08 from ltp with a preemptible kernel.
+
+Fix: Call ipc_lock_object() before performing the check.
+
+The patch also moves security_msg_queue_msgsnd() under ipc_lock_object:
+ - msgctl(IPC_SET) explicitely mentions that it tries to expunge any
+   pending operations that are not allowed anymore with the new
+   permissions.  If security_msg_queue_msgsnd() is called without locks,
+   then there might be races.
+ - it makes the patch much simpler.
+
+Reported-and-tested-by: Vineet Gupta <Vineet.Gupta1@synopsys.com>
+Acked-by: Rik van Riel <riel@redhat.com>
+Signed-off-by: Manfred Spraul <manfred@colorfullife.com>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Mike Galbraith <efault@gmx.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ ipc/msg.c |   12 +++++-------
+ 1 file changed, 5 insertions(+), 7 deletions(-)
+
+--- a/ipc/msg.c
++++ b/ipc/msg.c
+@@ -680,16 +680,18 @@ long do_msgsnd(int msqid, long mtype, vo
+               goto out_unlock1;
+       }
++      ipc_lock_object(&msq->q_perm);
++
+       for (;;) {
+               struct msg_sender s;
+               err = -EACCES;
+               if (ipcperms(ns, &msq->q_perm, S_IWUGO))
+-                      goto out_unlock1;
++                      goto out_unlock0;
+               err = security_msg_queue_msgsnd(msq, msg, msgflg);
+               if (err)
+-                      goto out_unlock1;
++                      goto out_unlock0;
+               if (msgsz + msq->q_cbytes <= msq->q_qbytes &&
+                               1 + msq->q_qnum <= msq->q_qbytes) {
+@@ -699,10 +701,9 @@ long do_msgsnd(int msqid, long mtype, vo
+               /* queue full, wait: */
+               if (msgflg & IPC_NOWAIT) {
+                       err = -EAGAIN;
+-                      goto out_unlock1;
++                      goto out_unlock0;
+               }
+-              ipc_lock_object(&msq->q_perm);
+               ss_add(msq, &s);
+               if (!ipc_rcu_getref(msq)) {
+@@ -730,10 +731,7 @@ long do_msgsnd(int msqid, long mtype, vo
+                       goto out_unlock0;
+               }
+-              ipc_unlock_object(&msq->q_perm);
+       }
+-
+-      ipc_lock_object(&msq->q_perm);
+       msq->q_lspid = task_tgid_vnr(current);
+       msq->q_stime = get_seconds();
diff --git a/queue-3.10/ipc-shm-cleanup-do_shmat-pasta.patch b/queue-3.10/ipc-shm-cleanup-do_shmat-pasta.patch
new file mode 100644 (file)
index 0000000..3c97a70
--- /dev/null
@@ -0,0 +1,85 @@
+From f42569b1388b1408b574a5e93a23a663647d4181 Mon Sep 17 00:00:00 2001
+From: Davidlohr Bueso <davidlohr.bueso@hp.com>
+Date: Wed, 11 Sep 2013 14:26:22 -0700
+Subject: ipc,shm: cleanup do_shmat pasta
+
+From: Davidlohr Bueso <davidlohr.bueso@hp.com>
+
+commit f42569b1388b1408b574a5e93a23a663647d4181 upstream.
+
+Clean up some of the messy do_shmat() spaghetti code, getting rid of
+out_free and out_put_dentry labels.  This makes shortening the critical
+region of this function in the next patch a little easier to do and read.
+
+Signed-off-by: Davidlohr Bueso <davidlohr.bueso@hp.com>
+Tested-by: Sedat Dilek <sedat.dilek@gmail.com>
+Cc: Rik van Riel <riel@redhat.com>
+Cc: Manfred Spraul <manfred@colorfullife.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Mike Galbraith <efault@gmx.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ ipc/shm.c |   26 ++++++++++++--------------
+ 1 file changed, 12 insertions(+), 14 deletions(-)
+
+--- a/ipc/shm.c
++++ b/ipc/shm.c
+@@ -1108,16 +1108,21 @@ long do_shmat(int shmid, char __user *sh
+       err = -ENOMEM;
+       sfd = kzalloc(sizeof(*sfd), GFP_KERNEL);
+-      if (!sfd)
+-              goto out_put_dentry;
++      if (!sfd) {
++              path_put(&path);
++              goto out_nattch;
++      }
+       file = alloc_file(&path, f_mode,
+                         is_file_hugepages(shp->shm_file) ?
+                               &shm_file_operations_huge :
+                               &shm_file_operations);
+       err = PTR_ERR(file);
+-      if (IS_ERR(file))
+-              goto out_free;
++      if (IS_ERR(file)) {
++              kfree(sfd);
++              path_put(&path);
++              goto out_nattch;
++      }
+       file->private_data = sfd;
+       file->f_mapping = shp->shm_file->f_mapping;
+@@ -1143,7 +1148,7 @@ long do_shmat(int shmid, char __user *sh
+                   addr > current->mm->start_stack - size - PAGE_SIZE * 5)
+                       goto invalid;
+       }
+-              
++
+       addr = do_mmap_pgoff(file, addr, size, prot, flags, 0, &populate);
+       *raddr = addr;
+       err = 0;
+@@ -1167,19 +1172,12 @@ out_nattch:
+       else
+               shm_unlock(shp);
+       up_write(&shm_ids(ns).rw_mutex);
+-
+-out:
+       return err;
+ out_unlock:
+       shm_unlock(shp);
+-      goto out;
+-
+-out_free:
+-      kfree(sfd);
+-out_put_dentry:
+-      path_put(&path);
+-      goto out_nattch;
++out:
++      return err;
+ }
+ SYSCALL_DEFINE3(shmat, int, shmid, char __user *, shmaddr, int, shmflg)
diff --git a/queue-3.10/ipc-shm-introduce-lockless-functions-to-obtain-the-ipc-object.patch b/queue-3.10/ipc-shm-introduce-lockless-functions-to-obtain-the-ipc-object.patch
new file mode 100644 (file)
index 0000000..e1b7b9c
--- /dev/null
@@ -0,0 +1,81 @@
+From 8b8d52ac382b17a19906b930cd69e2edb0aca8ba Mon Sep 17 00:00:00 2001
+From: Davidlohr Bueso <davidlohr.bueso@hp.com>
+Date: Wed, 11 Sep 2013 14:26:15 -0700
+Subject: ipc,shm: introduce lockless functions to obtain the ipc object
+
+From: Davidlohr Bueso <davidlohr.bueso@hp.com>
+
+commit 8b8d52ac382b17a19906b930cd69e2edb0aca8ba upstream.
+
+This is the third and final patchset that deals with reducing the amount
+of contention we impose on the ipc lock (kern_ipc_perm.lock).  These
+changes mostly deal with shared memory, previous work has already been
+done for semaphores and message queues:
+
+  http://lkml.org/lkml/2013/3/20/546 (sems)
+  http://lkml.org/lkml/2013/5/15/584 (mqueues)
+
+With these patches applied, a custom shm microbenchmark stressing shmctl
+doing IPC_STAT with 4 threads a million times, reduces the execution
+time by 50%.  A similar run, this time with IPC_SET, reduces the
+execution time from 3 mins and 35 secs to 27 seconds.
+
+Patches 1-8: replaces blindly taking the ipc lock for a smarter
+combination of rcu and ipc_obtain_object, only acquiring the spinlock
+when updating.
+
+Patch 9: renames the ids rw_mutex to rwsem, which is what it already was.
+
+Patch 10: is a trivial mqueue leftover cleanup
+
+Patch 11: adds a brief lock scheme description, requested by Andrew.
+
+This patch:
+
+Add shm_obtain_object() and shm_obtain_object_check(), which will allow us
+to get the ipc object without acquiring the lock.  Just as with other
+forms of ipc, these functions are basically wrappers around
+ipc_obtain_object*().
+
+Signed-off-by: Davidlohr Bueso <davidlohr.bueso@hp.com>
+Tested-by: Sedat Dilek <sedat.dilek@gmail.com>
+Cc: Rik van Riel <riel@redhat.com>
+Cc: Manfred Spraul <manfred@colorfullife.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Mike Galbraith <efault@gmx.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ ipc/shm.c |   20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+--- a/ipc/shm.c
++++ b/ipc/shm.c
+@@ -124,6 +124,26 @@ void __init shm_init (void)
+                               IPC_SHM_IDS, sysvipc_shm_proc_show);
+ }
++static inline struct shmid_kernel *shm_obtain_object(struct ipc_namespace *ns, int id)
++{
++      struct kern_ipc_perm *ipcp = ipc_obtain_object(&shm_ids(ns), id);
++
++      if (IS_ERR(ipcp))
++              return ERR_CAST(ipcp);
++
++      return container_of(ipcp, struct shmid_kernel, shm_perm);
++}
++
++static inline struct shmid_kernel *shm_obtain_object_check(struct ipc_namespace *ns, int id)
++{
++      struct kern_ipc_perm *ipcp = ipc_obtain_object_check(&shm_ids(ns), id);
++
++      if (IS_ERR(ipcp))
++              return ERR_CAST(ipcp);
++
++      return container_of(ipcp, struct shmid_kernel, shm_perm);
++}
++
+ /*
+  * shm_lock_(check_) routines are called in the paths where the rw_mutex
+  * is not necessarily held.
diff --git a/queue-3.10/ipc-shm-introduce-shmctl_nolock.patch b/queue-3.10/ipc-shm-introduce-shmctl_nolock.patch
new file mode 100644 (file)
index 0000000..276550f
--- /dev/null
@@ -0,0 +1,118 @@
+From 68eccc1dc345539d589ae78ee43b835c1a06a134 Mon Sep 17 00:00:00 2001
+From: Davidlohr Bueso <davidlohr.bueso@hp.com>
+Date: Wed, 11 Sep 2013 14:26:18 -0700
+Subject: ipc,shm: introduce shmctl_nolock
+
+From: Davidlohr Bueso <davidlohr.bueso@hp.com>
+
+commit 68eccc1dc345539d589ae78ee43b835c1a06a134 upstream.
+
+Similar to semctl and msgctl, when calling msgctl, the *_INFO and *_STAT
+commands can be performed without acquiring the ipc object.
+
+Add a shmctl_nolock() function and move the logic of *_INFO and *_STAT out
+of msgctl().  Since we are just moving functionality, this change still
+takes the lock and it will be properly lockless in the next patch.
+
+Signed-off-by: Davidlohr Bueso <davidlohr.bueso@hp.com>
+Tested-by: Sedat Dilek <sedat.dilek@gmail.com>
+Cc: Rik van Riel <riel@redhat.com>
+Cc: Manfred Spraul <manfred@colorfullife.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Mike Galbraith <efault@gmx.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ ipc/shm.c |   57 +++++++++++++++++++++++++++++++++++++++------------------
+ 1 file changed, 39 insertions(+), 18 deletions(-)
+
+--- a/ipc/shm.c
++++ b/ipc/shm.c
+@@ -820,29 +820,24 @@ out_up:
+       return err;
+ }
+-SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
++static int shmctl_nolock(struct ipc_namespace *ns, int shmid,
++                       int cmd, int version, void __user *buf)
+ {
++      int err;
+       struct shmid_kernel *shp;
+-      int err, version;
+-      struct ipc_namespace *ns;
+-      if (cmd < 0 || shmid < 0) {
+-              err = -EINVAL;
+-              goto out;
++      /* preliminary security checks for *_INFO */
++      if (cmd == IPC_INFO || cmd == SHM_INFO) {
++              err = security_shm_shmctl(NULL, cmd);
++              if (err)
++                      return err;
+       }
+-      version = ipc_parse_version(&cmd);
+-      ns = current->nsproxy->ipc_ns;
+-
+-      switch (cmd) { /* replace with proc interface ? */
++      switch (cmd) {
+       case IPC_INFO:
+       {
+               struct shminfo64 shminfo;
+-              err = security_shm_shmctl(NULL, cmd);
+-              if (err)
+-                      return err;
+-
+               memset(&shminfo, 0, sizeof(shminfo));
+               shminfo.shmmni = shminfo.shmseg = ns->shm_ctlmni;
+               shminfo.shmmax = ns->shm_ctlmax;
+@@ -864,10 +859,6 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int,
+       {
+               struct shm_info shm_info;
+-              err = security_shm_shmctl(NULL, cmd);
+-              if (err)
+-                      return err;
+-
+               memset(&shm_info, 0, sizeof(shm_info));
+               down_read(&shm_ids(ns).rw_mutex);
+               shm_info.used_ids = shm_ids(ns).in_use;
+@@ -928,6 +919,36 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int,
+                       err = result;
+               goto out;
+       }
++      default:
++              return -EINVAL;
++      }
++
++out_unlock:
++      shm_unlock(shp);
++out:
++      return err;
++}
++
++SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
++{
++      struct shmid_kernel *shp;
++      int err, version;
++      struct ipc_namespace *ns;
++
++      if (cmd < 0 || shmid < 0) {
++              err = -EINVAL;
++              goto out;
++      }
++
++      version = ipc_parse_version(&cmd);
++      ns = current->nsproxy->ipc_ns;
++
++      switch (cmd) {
++      case IPC_INFO:
++      case SHM_INFO:
++      case SHM_STAT:
++      case IPC_STAT:
++              return shmctl_nolock(ns, shmid, cmd, version, buf);
+       case SHM_LOCK:
+       case SHM_UNLOCK:
+       {
diff --git a/queue-3.10/ipc-shm-make-shmctl_nolock-lockless.patch b/queue-3.10/ipc-shm-make-shmctl_nolock-lockless.patch
new file mode 100644 (file)
index 0000000..4bcaf0b
--- /dev/null
@@ -0,0 +1,86 @@
+From c97cb9ccab8c85428ec21eff690642ad2ce1fa8a Mon Sep 17 00:00:00 2001
+From: Davidlohr Bueso <davidlohr.bueso@hp.com>
+Date: Wed, 11 Sep 2013 14:26:20 -0700
+Subject: ipc,shm: make shmctl_nolock lockless
+
+From: Davidlohr Bueso <davidlohr.bueso@hp.com>
+
+commit c97cb9ccab8c85428ec21eff690642ad2ce1fa8a upstream.
+
+While the INFO cmd doesn't take the ipc lock, the STAT commands do acquire
+it unnecessarily.  We can do the permissions and security checks only
+holding the rcu lock.
+
+[akpm@linux-foundation.org: coding-style fixes]
+Signed-off-by: Davidlohr Bueso <davidlohr.bueso@hp.com>
+Tested-by: Sedat Dilek <sedat.dilek@gmail.com>
+Cc: Rik van Riel <riel@redhat.com>
+Cc: Manfred Spraul <manfred@colorfullife.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Mike Galbraith <efault@gmx.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ ipc/shm.c |   19 ++++++++++++-------
+ 1 file changed, 12 insertions(+), 7 deletions(-)
+
+--- a/ipc/shm.c
++++ b/ipc/shm.c
+@@ -882,27 +882,31 @@ static int shmctl_nolock(struct ipc_name
+               struct shmid64_ds tbuf;
+               int result;
++              rcu_read_lock();
+               if (cmd == SHM_STAT) {
+-                      shp = shm_lock(ns, shmid);
++                      shp = shm_obtain_object(ns, shmid);
+                       if (IS_ERR(shp)) {
+                               err = PTR_ERR(shp);
+-                              goto out;
++                              goto out_unlock;
+                       }
+                       result = shp->shm_perm.id;
+               } else {
+-                      shp = shm_lock_check(ns, shmid);
++                      shp = shm_obtain_object_check(ns, shmid);
+                       if (IS_ERR(shp)) {
+                               err = PTR_ERR(shp);
+-                              goto out;
++                              goto out_unlock;
+                       }
+                       result = 0;
+               }
++
+               err = -EACCES;
+               if (ipcperms(ns, &shp->shm_perm, S_IRUGO))
+                       goto out_unlock;
++
+               err = security_shm_shmctl(shp, cmd);
+               if (err)
+                       goto out_unlock;
++
+               memset(&tbuf, 0, sizeof(tbuf));
+               kernel_to_ipc64_perm(&shp->shm_perm, &tbuf.shm_perm);
+               tbuf.shm_segsz  = shp->shm_segsz;
+@@ -912,8 +916,9 @@ static int shmctl_nolock(struct ipc_name
+               tbuf.shm_cpid   = shp->shm_cprid;
+               tbuf.shm_lpid   = shp->shm_lprid;
+               tbuf.shm_nattch = shp->shm_nattch;
+-              shm_unlock(shp);
+-              if(copy_shmid_to_user (buf, &tbuf, version))
++              rcu_read_unlock();
++
++              if (copy_shmid_to_user(buf, &tbuf, version))
+                       err = -EFAULT;
+               else
+                       err = result;
+@@ -924,7 +929,7 @@ static int shmctl_nolock(struct ipc_name
+       }
+ out_unlock:
+-      shm_unlock(shp);
++      rcu_read_unlock();
+ out:
+       return err;
+ }
diff --git a/queue-3.10/ipc-shm-shorten-critical-region-for-shmat.patch b/queue-3.10/ipc-shm-shorten-critical-region-for-shmat.patch
new file mode 100644 (file)
index 0000000..66c50c4
--- /dev/null
@@ -0,0 +1,77 @@
+From c2c737a0461e61a34676bd0bd1bc1a70a1b4e396 Mon Sep 17 00:00:00 2001
+From: Davidlohr Bueso <davidlohr.bueso@hp.com>
+Date: Wed, 11 Sep 2013 14:26:23 -0700
+Subject: ipc,shm: shorten critical region for shmat
+
+From: Davidlohr Bueso <davidlohr.bueso@hp.com>
+
+commit c2c737a0461e61a34676bd0bd1bc1a70a1b4e396 upstream.
+
+Similar to other system calls, acquire the kern_ipc_perm lock after doing
+the initial permission and security checks.
+
+[sasha.levin@oracle.com: dont leave do_shmat with rcu lock held]
+Signed-off-by: Davidlohr Bueso <davidlohr.bueso@hp.com>
+Tested-by: Sedat Dilek <sedat.dilek@gmail.com>
+Cc: Rik van Riel <riel@redhat.com>
+Cc: Manfred Spraul <manfred@colorfullife.com>
+Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Mike Galbraith <efault@gmx.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ ipc/shm.c |   14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+--- a/ipc/shm.c
++++ b/ipc/shm.c
+@@ -19,6 +19,9 @@
+  * namespaces support
+  * OpenVZ, SWsoft Inc.
+  * Pavel Emelianov <xemul@openvz.org>
++ *
++ * Better ipc lock (kern_ipc_perm.lock) handling
++ * Davidlohr Bueso <davidlohr.bueso@hp.com>, June 2013.
+  */
+ #include <linux/slab.h>
+@@ -1086,10 +1089,11 @@ long do_shmat(int shmid, char __user *sh
+        * additional creator id...
+        */
+       ns = current->nsproxy->ipc_ns;
+-      shp = shm_lock_check(ns, shmid);
++      rcu_read_lock();
++      shp = shm_obtain_object_check(ns, shmid);
+       if (IS_ERR(shp)) {
+               err = PTR_ERR(shp);
+-              goto out;
++              goto out_unlock;
+       }
+       err = -EACCES;
+@@ -1100,11 +1104,13 @@ long do_shmat(int shmid, char __user *sh
+       if (err)
+               goto out_unlock;
++      ipc_lock_object(&shp->shm_perm);
+       path = shp->shm_file->f_path;
+       path_get(&path);
+       shp->shm_nattch++;
+       size = i_size_read(path.dentry->d_inode);
+-      shm_unlock(shp);
++      ipc_unlock_object(&shp->shm_perm);
++      rcu_read_unlock();
+       err = -ENOMEM;
+       sfd = kzalloc(sizeof(*sfd), GFP_KERNEL);
+@@ -1175,7 +1181,7 @@ out_nattch:
+       return err;
+ out_unlock:
+-      shm_unlock(shp);
++      rcu_read_unlock();
+ out:
+       return err;
+ }
diff --git a/queue-3.10/ipc-shm-shorten-critical-region-for-shmctl.patch b/queue-3.10/ipc-shm-shorten-critical-region-for-shmctl.patch
new file mode 100644 (file)
index 0000000..579a76c
--- /dev/null
@@ -0,0 +1,135 @@
+From 2caacaa82a51b78fc0c800e206473874094287ed Mon Sep 17 00:00:00 2001
+From: Davidlohr Bueso <davidlohr.bueso@hp.com>
+Date: Wed, 11 Sep 2013 14:26:21 -0700
+Subject: ipc,shm: shorten critical region for shmctl
+
+From: Davidlohr Bueso <davidlohr.bueso@hp.com>
+
+commit 2caacaa82a51b78fc0c800e206473874094287ed upstream.
+
+With the *_INFO, *_STAT, IPC_RMID and IPC_SET commands already optimized,
+deal with the remaining SHM_LOCK and SHM_UNLOCK commands.  Take the
+shm_perm lock after doing the initial auditing and security checks.  The
+rest of the logic remains unchanged.
+
+Signed-off-by: Davidlohr Bueso <davidlohr.bueso@hp.com>
+Tested-by: Sedat Dilek <sedat.dilek@gmail.com>
+Cc: Rik van Riel <riel@redhat.com>
+Cc: Manfred Spraul <manfred@colorfullife.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Mike Galbraith <efault@gmx.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ ipc/shm.c |   49 +++++++++++++++++++++++++------------------------
+ 1 file changed, 25 insertions(+), 24 deletions(-)
+
+--- a/ipc/shm.c
++++ b/ipc/shm.c
+@@ -940,10 +940,8 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int,
+       int err, version;
+       struct ipc_namespace *ns;
+-      if (cmd < 0 || shmid < 0) {
+-              err = -EINVAL;
+-              goto out;
+-      }
++      if (cmd < 0 || shmid < 0)
++              return -EINVAL;
+       version = ipc_parse_version(&cmd);
+       ns = current->nsproxy->ipc_ns;
+@@ -954,36 +952,40 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int,
+       case SHM_STAT:
+       case IPC_STAT:
+               return shmctl_nolock(ns, shmid, cmd, version, buf);
++      case IPC_RMID:
++      case IPC_SET:
++              return shmctl_down(ns, shmid, cmd, buf, version);
+       case SHM_LOCK:
+       case SHM_UNLOCK:
+       {
+               struct file *shm_file;
+-              shp = shm_lock_check(ns, shmid);
++              rcu_read_lock();
++              shp = shm_obtain_object_check(ns, shmid);
+               if (IS_ERR(shp)) {
+                       err = PTR_ERR(shp);
+-                      goto out;
++                      goto out_unlock1;
+               }
+               audit_ipc_obj(&(shp->shm_perm));
++              err = security_shm_shmctl(shp, cmd);
++              if (err)
++                      goto out_unlock1;
++              ipc_lock_object(&shp->shm_perm);
+               if (!ns_capable(ns->user_ns, CAP_IPC_LOCK)) {
+                       kuid_t euid = current_euid();
+                       err = -EPERM;
+                       if (!uid_eq(euid, shp->shm_perm.uid) &&
+                           !uid_eq(euid, shp->shm_perm.cuid))
+-                              goto out_unlock;
++                              goto out_unlock0;
+                       if (cmd == SHM_LOCK && !rlimit(RLIMIT_MEMLOCK))
+-                              goto out_unlock;
++                              goto out_unlock0;
+               }
+-              err = security_shm_shmctl(shp, cmd);
+-              if (err)
+-                      goto out_unlock;
+-
+               shm_file = shp->shm_file;
+               if (is_file_hugepages(shm_file))
+-                      goto out_unlock;
++                      goto out_unlock0;
+               if (cmd == SHM_LOCK) {
+                       struct user_struct *user = current_user();
+@@ -992,32 +994,31 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int,
+                               shp->shm_perm.mode |= SHM_LOCKED;
+                               shp->mlock_user = user;
+                       }
+-                      goto out_unlock;
++                      goto out_unlock0;
+               }
+               /* SHM_UNLOCK */
+               if (!(shp->shm_perm.mode & SHM_LOCKED))
+-                      goto out_unlock;
++                      goto out_unlock0;
+               shmem_lock(shm_file, 0, shp->mlock_user);
+               shp->shm_perm.mode &= ~SHM_LOCKED;
+               shp->mlock_user = NULL;
+               get_file(shm_file);
+-              shm_unlock(shp);
++              ipc_unlock_object(&shp->shm_perm);
++              rcu_read_unlock();
+               shmem_unlock_mapping(shm_file->f_mapping);
++
+               fput(shm_file);
+-              goto out;
+-      }
+-      case IPC_RMID:
+-      case IPC_SET:
+-              err = shmctl_down(ns, shmid, cmd, buf, version);
+               return err;
++      }
+       default:
+               return -EINVAL;
+       }
+-out_unlock:
+-      shm_unlock(shp);
+-out:
++out_unlock0:
++      ipc_unlock_object(&shp->shm_perm);
++out_unlock1:
++      rcu_read_unlock();
+       return err;
+ }
diff --git a/queue-3.10/ipc-shm-shorten-critical-region-in-shmctl_down.patch b/queue-3.10/ipc-shm-shorten-critical-region-in-shmctl_down.patch
new file mode 100644 (file)
index 0000000..2270c6b
--- /dev/null
@@ -0,0 +1,68 @@
+From 79ccf0f8c8e04e8b9eda6645ba0f63b0915a3075 Mon Sep 17 00:00:00 2001
+From: Davidlohr Bueso <davidlohr.bueso@hp.com>
+Date: Wed, 11 Sep 2013 14:26:16 -0700
+Subject: ipc,shm: shorten critical region in shmctl_down
+
+From: Davidlohr Bueso <davidlohr.bueso@hp.com>
+
+commit 79ccf0f8c8e04e8b9eda6645ba0f63b0915a3075 upstream.
+
+Instead of holding the ipc lock for the entire function, use the
+ipcctl_pre_down_nolock and only acquire the lock for specific commands:
+RMID and SET.
+
+Signed-off-by: Davidlohr Bueso <davidlohr.bueso@hp.com>
+Tested-by: Sedat Dilek <sedat.dilek@gmail.com>
+Cc: Rik van Riel <riel@redhat.com>
+Cc: Manfred Spraul <manfred@colorfullife.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Mike Galbraith <efault@gmx.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ ipc/shm.c |   10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+--- a/ipc/shm.c
++++ b/ipc/shm.c
+@@ -780,11 +780,10 @@ static int shmctl_down(struct ipc_namesp
+       down_write(&shm_ids(ns).rw_mutex);
+       rcu_read_lock();
+-      ipcp = ipcctl_pre_down(ns, &shm_ids(ns), shmid, cmd,
+-                             &shmid64.shm_perm, 0);
++      ipcp = ipcctl_pre_down_nolock(ns, &shm_ids(ns), shmid, cmd,
++                                    &shmid64.shm_perm, 0);
+       if (IS_ERR(ipcp)) {
+               err = PTR_ERR(ipcp);
+-              /* the ipc lock is not held upon failure */
+               goto out_unlock1;
+       }
+@@ -792,14 +791,16 @@ static int shmctl_down(struct ipc_namesp
+       err = security_shm_shmctl(shp, cmd);
+       if (err)
+-              goto out_unlock0;
++              goto out_unlock1;
+       switch (cmd) {
+       case IPC_RMID:
++              ipc_lock_object(&shp->shm_perm);
+               /* do_shm_rmid unlocks the ipc object and rcu */
+               do_shm_rmid(ns, ipcp);
+               goto out_up;
+       case IPC_SET:
++              ipc_lock_object(&shp->shm_perm);
+               err = ipc_update_perm(&shmid64.shm_perm, ipcp);
+               if (err)
+                       goto out_unlock0;
+@@ -807,6 +808,7 @@ static int shmctl_down(struct ipc_namesp
+               break;
+       default:
+               err = -EINVAL;
++              goto out_unlock1;
+       }
+ out_unlock0:
index 74a2f032320e01915c0874fd42b4aba79fab61a2..ea7b1d22c269b687abf5a7b13dc68d464fba50b5 100644 (file)
@@ -44,3 +44,12 @@ ipc-sem-separate-wait-for-zero-and-alter-tasks-into-seperate-queues.patch
 ipc-sem.c-always-use-only-one-queue-for-alter-operations.patch
 ipc-sem.c-replace-shared-sem_otime-with-per-semaphore-value.patch
 ipc-sem.c-rename-try_atomic_semop-to-perform_atomic_semop-docu-update.patch
+ipc-msg.c-fix-lost-wakeup-in-msgsnd.patch
+ipc-shm-introduce-lockless-functions-to-obtain-the-ipc-object.patch
+ipc-shm-shorten-critical-region-in-shmctl_down.patch
+ipc-drop-ipcctl_pre_down.patch
+ipc-shm-introduce-shmctl_nolock.patch
+ipc-shm-make-shmctl_nolock-lockless.patch
+ipc-shm-shorten-critical-region-for-shmctl.patch
+ipc-shm-cleanup-do_shmat-pasta.patch
+ipc-shm-shorten-critical-region-for-shmat.patch