From: Greg Kroah-Hartman Date: Tue, 15 Oct 2013 23:53:06 +0000 (-0700) Subject: 3.10-stable patches X-Git-Tag: v3.10.17~9 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8781ae5efe54a82de30018c7f79ab8b8148acbb2;p=thirdparty%2Fkernel%2Fstable-queue.git 3.10-stable patches 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 --- 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 index 00000000000..c45adafa82f --- /dev/null +++ b/queue-3.10/ipc-drop-ipcctl_pre_down.patch @@ -0,0 +1,83 @@ +From 3b1c4ad37741e53804ffe0a30dd01e08b2ab6241 Mon Sep 17 00:00:00 2001 +From: Davidlohr Bueso +Date: Wed, 11 Sep 2013 14:26:17 -0700 +Subject: ipc: drop ipcctl_pre_down + +From: Davidlohr Bueso + +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 +Tested-by: Sedat Dilek +Cc: Rik van Riel +Cc: Manfred Spraul +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Cc: Mike Galbraith +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..e25d34ebb77 --- /dev/null +++ b/queue-3.10/ipc-msg.c-fix-lost-wakeup-in-msgsnd.patch @@ -0,0 +1,91 @@ +From bebcb928c820d0ee83aca4b192adc195e43e66a2 Mon Sep 17 00:00:00 2001 +From: Manfred Spraul +Date: Tue, 3 Sep 2013 16:00:08 +0200 +Subject: ipc/msg.c: Fix lost wakeup in msgsnd(). + +From: Manfred Spraul + +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 +Acked-by: Rik van Riel +Signed-off-by: Manfred Spraul +Signed-off-by: Linus Torvalds +Cc: Mike Galbraith +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..3c97a702d85 --- /dev/null +++ b/queue-3.10/ipc-shm-cleanup-do_shmat-pasta.patch @@ -0,0 +1,85 @@ +From f42569b1388b1408b574a5e93a23a663647d4181 Mon Sep 17 00:00:00 2001 +From: Davidlohr Bueso +Date: Wed, 11 Sep 2013 14:26:22 -0700 +Subject: ipc,shm: cleanup do_shmat pasta + +From: Davidlohr Bueso + +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 +Tested-by: Sedat Dilek +Cc: Rik van Riel +Cc: Manfred Spraul +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Cc: Mike Galbraith +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..e1b7b9c4566 --- /dev/null +++ b/queue-3.10/ipc-shm-introduce-lockless-functions-to-obtain-the-ipc-object.patch @@ -0,0 +1,81 @@ +From 8b8d52ac382b17a19906b930cd69e2edb0aca8ba Mon Sep 17 00:00:00 2001 +From: Davidlohr Bueso +Date: Wed, 11 Sep 2013 14:26:15 -0700 +Subject: ipc,shm: introduce lockless functions to obtain the ipc object + +From: Davidlohr Bueso + +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 +Tested-by: Sedat Dilek +Cc: Rik van Riel +Cc: Manfred Spraul +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Cc: Mike Galbraith +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..276550fc5b5 --- /dev/null +++ b/queue-3.10/ipc-shm-introduce-shmctl_nolock.patch @@ -0,0 +1,118 @@ +From 68eccc1dc345539d589ae78ee43b835c1a06a134 Mon Sep 17 00:00:00 2001 +From: Davidlohr Bueso +Date: Wed, 11 Sep 2013 14:26:18 -0700 +Subject: ipc,shm: introduce shmctl_nolock + +From: Davidlohr Bueso + +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 +Tested-by: Sedat Dilek +Cc: Rik van Riel +Cc: Manfred Spraul +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Cc: Mike Galbraith +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..4bcaf0be2d6 --- /dev/null +++ b/queue-3.10/ipc-shm-make-shmctl_nolock-lockless.patch @@ -0,0 +1,86 @@ +From c97cb9ccab8c85428ec21eff690642ad2ce1fa8a Mon Sep 17 00:00:00 2001 +From: Davidlohr Bueso +Date: Wed, 11 Sep 2013 14:26:20 -0700 +Subject: ipc,shm: make shmctl_nolock lockless + +From: Davidlohr Bueso + +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 +Tested-by: Sedat Dilek +Cc: Rik van Riel +Cc: Manfred Spraul +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Cc: Mike Galbraith +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..66c50c47039 --- /dev/null +++ b/queue-3.10/ipc-shm-shorten-critical-region-for-shmat.patch @@ -0,0 +1,77 @@ +From c2c737a0461e61a34676bd0bd1bc1a70a1b4e396 Mon Sep 17 00:00:00 2001 +From: Davidlohr Bueso +Date: Wed, 11 Sep 2013 14:26:23 -0700 +Subject: ipc,shm: shorten critical region for shmat + +From: Davidlohr Bueso + +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 +Tested-by: Sedat Dilek +Cc: Rik van Riel +Cc: Manfred Spraul +Signed-off-by: Sasha Levin +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Cc: Mike Galbraith +Signed-off-by: Greg Kroah-Hartman + +--- + 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 ++ * ++ * Better ipc lock (kern_ipc_perm.lock) handling ++ * Davidlohr Bueso , June 2013. + */ + + #include +@@ -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 index 00000000000..579a76c9384 --- /dev/null +++ b/queue-3.10/ipc-shm-shorten-critical-region-for-shmctl.patch @@ -0,0 +1,135 @@ +From 2caacaa82a51b78fc0c800e206473874094287ed Mon Sep 17 00:00:00 2001 +From: Davidlohr Bueso +Date: Wed, 11 Sep 2013 14:26:21 -0700 +Subject: ipc,shm: shorten critical region for shmctl + +From: Davidlohr Bueso + +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 +Tested-by: Sedat Dilek +Cc: Rik van Riel +Cc: Manfred Spraul +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Cc: Mike Galbraith +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..2270c6b7af2 --- /dev/null +++ b/queue-3.10/ipc-shm-shorten-critical-region-in-shmctl_down.patch @@ -0,0 +1,68 @@ +From 79ccf0f8c8e04e8b9eda6645ba0f63b0915a3075 Mon Sep 17 00:00:00 2001 +From: Davidlohr Bueso +Date: Wed, 11 Sep 2013 14:26:16 -0700 +Subject: ipc,shm: shorten critical region in shmctl_down + +From: Davidlohr Bueso + +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 +Tested-by: Sedat Dilek +Cc: Rik van Riel +Cc: Manfred Spraul +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Cc: Mike Galbraith +Signed-off-by: Greg Kroah-Hartman + +--- + 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: diff --git a/queue-3.10/series b/queue-3.10/series index 74a2f032320..ea7b1d22c26 100644 --- a/queue-3.10/series +++ b/queue-3.10/series @@ -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