]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.11-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 15 Oct 2013 23:32:00 +0000 (16:32 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 15 Oct 2013 23:32:00 +0000 (16:32 -0700)
added patches:
ipc-drop-ipcctl_pre_down.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.11/ipc-drop-ipcctl_pre_down.patch [new file with mode: 0644]
queue-3.11/ipc-shm-cleanup-do_shmat-pasta.patch [new file with mode: 0644]
queue-3.11/ipc-shm-introduce-lockless-functions-to-obtain-the-ipc-object.patch [new file with mode: 0644]
queue-3.11/ipc-shm-introduce-shmctl_nolock.patch [new file with mode: 0644]
queue-3.11/ipc-shm-make-shmctl_nolock-lockless.patch [new file with mode: 0644]
queue-3.11/ipc-shm-shorten-critical-region-for-shmat.patch [new file with mode: 0644]
queue-3.11/ipc-shm-shorten-critical-region-for-shmctl.patch [new file with mode: 0644]
queue-3.11/ipc-shm-shorten-critical-region-in-shmctl_down.patch [new file with mode: 0644]
queue-3.11/series

diff --git a/queue-3.11/ipc-drop-ipcctl_pre_down.patch b/queue-3.11/ipc-drop-ipcctl_pre_down.patch
new file mode 100644 (file)
index 0000000..4491ded
--- /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
+@@ -725,7 +725,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
+@@ -738,29 +738,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
+@@ -139,9 +139,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.11/ipc-shm-cleanup-do_shmat-pasta.patch b/queue-3.11/ipc-shm-cleanup-do_shmat-pasta.patch
new file mode 100644 (file)
index 0000000..807f8d2
--- /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
+@@ -1115,16 +1115,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;
+@@ -1150,7 +1155,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;
+@@ -1174,19 +1179,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.11/ipc-shm-introduce-lockless-functions-to-obtain-the-ipc-object.patch b/queue-3.11/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.11/ipc-shm-introduce-shmctl_nolock.patch b/queue-3.11/ipc-shm-introduce-shmctl_nolock.patch
new file mode 100644 (file)
index 0000000..0f402b3
--- /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
+@@ -827,29 +827,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;
+@@ -871,10 +866,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;
+@@ -935,6 +926,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.11/ipc-shm-make-shmctl_nolock-lockless.patch b/queue-3.11/ipc-shm-make-shmctl_nolock-lockless.patch
new file mode 100644 (file)
index 0000000..587f936
--- /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
+@@ -889,27 +889,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;
+@@ -919,8 +923,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;
+@@ -931,7 +936,7 @@ static int shmctl_nolock(struct ipc_name
+       }
+ out_unlock:
+-      shm_unlock(shp);
++      rcu_read_unlock();
+ out:
+       return err;
+ }
diff --git a/queue-3.11/ipc-shm-shorten-critical-region-for-shmat.patch b/queue-3.11/ipc-shm-shorten-critical-region-for-shmat.patch
new file mode 100644 (file)
index 0000000..d1bc774
--- /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>
+@@ -1093,10 +1096,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;
+@@ -1107,11 +1111,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);
+@@ -1182,7 +1188,7 @@ out_nattch:
+       return err;
+ out_unlock:
+-      shm_unlock(shp);
++      rcu_read_unlock();
+ out:
+       return err;
+ }
diff --git a/queue-3.11/ipc-shm-shorten-critical-region-for-shmctl.patch b/queue-3.11/ipc-shm-shorten-critical-region-for-shmctl.patch
new file mode 100644 (file)
index 0000000..6a5a734
--- /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
+@@ -947,10 +947,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;
+@@ -961,36 +959,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();
+@@ -999,32 +1001,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.11/ipc-shm-shorten-critical-region-in-shmctl_down.patch b/queue-3.11/ipc-shm-shorten-critical-region-in-shmctl_down.patch
new file mode 100644 (file)
index 0000000..a2cb60b
--- /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
+@@ -787,11 +787,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;
+       }
+@@ -799,14 +798,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;
+@@ -814,6 +815,7 @@ static int shmctl_down(struct ipc_namesp
+               break;
+       default:
+               err = -EINVAL;
++              goto out_unlock1;
+       }
+ out_unlock0:
index 56c3201fe74b74e17b19cbf13f29dde4fe6d3eaa..4b1e035ee5b6a66e8f76aa12c28ebbd844aedca0 100644 (file)
@@ -29,3 +29,11 @@ drm-radeon-dpm-off-by-one-in-si_set_mc_special_registers.patch
 drm-radeon-forever-loop-on-error-in-radeon_do_test_moves.patch
 drm-radeon-fix-typo-in-cp-dma-register-headers.patch
 drm-radeon-fix-hw-contexts-for-sumo2-asics.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