]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.5-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 27 Sep 2012 18:24:57 +0000 (11:24 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 27 Sep 2012 18:24:57 +0000 (11:24 -0700)
added patches:
fix-a-dead-loop-in-async_synchronize_full.patch
libata-prevent-interface-errors-with-seagate-freeagent-goflex.patch
media-lirc_sir-make-device-registration-work.patch
rds-set-correct-msg_namelen.patch
sched-fix-race-in-task_group.patch

queue-3.5/fix-a-dead-loop-in-async_synchronize_full.patch [new file with mode: 0644]
queue-3.5/libata-prevent-interface-errors-with-seagate-freeagent-goflex.patch [new file with mode: 0644]
queue-3.5/media-lirc_sir-make-device-registration-work.patch [new file with mode: 0644]
queue-3.5/rds-set-correct-msg_namelen.patch [new file with mode: 0644]
queue-3.5/sched-fix-race-in-task_group.patch [new file with mode: 0644]
queue-3.5/series

diff --git a/queue-3.5/fix-a-dead-loop-in-async_synchronize_full.patch b/queue-3.5/fix-a-dead-loop-in-async_synchronize_full.patch
new file mode 100644 (file)
index 0000000..369265b
--- /dev/null
@@ -0,0 +1,89 @@
+From akpm@linux-foundation.org  Thu Sep 27 10:42:06 2012
+From: Li Zhong <zhong@linux.vnet.ibm.com>
+Date: Tue, 24 Jul 2012 15:02:49 -0700
+Subject: Fix a dead loop in async_synchronize_full()
+
+From: Li Zhong <zhong@linux.vnet.ibm.com>
+
+[Fixed upstream by commits 2955b47d2c1983998a8c5915cb96884e67f7cb53 and
+a4683487f90bfe3049686fc5c566bdc1ad03ace6 from Dan Williams, but they are much
+more intrusive than this tiny fix, according to Andrew - gregkh]
+
+This patch tries to fix a dead loop in  async_synchronize_full(), which
+could be seen when preemption is disabled on a single cpu machine. 
+
+void async_synchronize_full(void)
+{
+        do {
+                async_synchronize_cookie(next_cookie);
+        } while (!list_empty(&async_running) || !
+list_empty(&async_pending));
+}
+
+async_synchronize_cookie() calls async_synchronize_cookie_domain() with
+&async_running as the default domain to synchronize. 
+
+However, there might be some works in the async_pending list from other
+domains. On a single cpu system, without preemption, there is no chance
+for the other works to finish, so async_synchronize_full() enters a dead
+loop. 
+
+It seems async_synchronize_full() wants to synchronize all entries in
+all running lists(domains), so maybe we could just check the entry_count
+to know whether all works are finished. 
+
+Currently, async_synchronize_cookie_domain() expects a non-NULL running
+list ( if NULL, there would be NULL pointer dereference ), so maybe a
+NULL pointer could be used as an indication for the functions to
+synchronize all works in all domains. 
+
+Reported-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
+Signed-off-by: Li Zhong <zhong@linux.vnet.ibm.com>
+Tested-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
+Tested-by: Christian Kujau <lists@nerdbynature.de>
+Cc: Andrew Morton <akpm@linux-foundation.org>
+Cc: Dan Williams <dan.j.williams@gmail.com>
+Cc: Christian Kujau <lists@nerdbynature.de>
+Cc: Andrew Morton <akpm@linux-foundation.org>
+Cc: Cong Wang <xiyou.wangcong@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/async.c |   13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+--- a/kernel/async.c
++++ b/kernel/async.c
+@@ -86,6 +86,13 @@ static async_cookie_t  __lowest_in_progr
+ {
+       struct async_entry *entry;
++      if (!running) { /* just check the entry count */
++              if (atomic_read(&entry_count))
++                      return 0; /* smaller than any cookie */
++              else
++                      return next_cookie;
++      }
++
+       if (!list_empty(running)) {
+               entry = list_first_entry(running,
+                       struct async_entry, list);
+@@ -236,9 +243,7 @@ EXPORT_SYMBOL_GPL(async_schedule_domain)
+  */
+ void async_synchronize_full(void)
+ {
+-      do {
+-              async_synchronize_cookie(next_cookie);
+-      } while (!list_empty(&async_running) || !list_empty(&async_pending));
++      async_synchronize_cookie_domain(next_cookie, NULL);
+ }
+ EXPORT_SYMBOL_GPL(async_synchronize_full);
+@@ -258,7 +263,7 @@ EXPORT_SYMBOL_GPL(async_synchronize_full
+ /**
+  * async_synchronize_cookie_domain - synchronize asynchronous function calls within a certain domain with cookie checkpointing
+  * @cookie: async_cookie_t to use as checkpoint
+- * @running: running list to synchronize on
++ * @running: running list to synchronize on, NULL indicates all lists
+  *
+  * This function waits until all asynchronous function calls for the
+  * synchronization domain specified by the running list @list submitted
diff --git a/queue-3.5/libata-prevent-interface-errors-with-seagate-freeagent-goflex.patch b/queue-3.5/libata-prevent-interface-errors-with-seagate-freeagent-goflex.patch
new file mode 100644 (file)
index 0000000..808e2d6
--- /dev/null
@@ -0,0 +1,36 @@
+From c531077f40abc9f2129c4c83a30b3f8d6ce1c0e7 Mon Sep 17 00:00:00 2001
+From: Daniel J Blueman <daniel@quora.org>
+Date: Mon, 23 Jul 2012 12:22:37 +0800
+Subject: libata: Prevent interface errors with Seagate FreeAgent GoFlex
+
+From: Daniel J Blueman <daniel@quora.org>
+
+commit c531077f40abc9f2129c4c83a30b3f8d6ce1c0e7 upstream.
+
+When using my Seagate FreeAgent GoFlex eSATAp external disk enclosure,
+interface errors are always seen until 1.5Gbps is negotiated [1]. This
+occurs using any disk in the enclosure, and when the disk is connected
+directly with a generic passive eSATAp cable, we see stable 3Gbps
+operation as expected.
+
+Blacklist 3Gbps mode to avoid dataloss and the ~30s delay bus reset
+and renegotiation incurs.
+
+Signed-off-by: Daniel J Blueman <daniel@quora.org>
+Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/ata/libata-core.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/ata/libata-core.c
++++ b/drivers/ata/libata-core.c
+@@ -4126,6 +4126,7 @@ static const struct ata_blacklist_entry
+       /* Devices which aren't very happy with higher link speeds */
+       { "WD My Book",                 NULL,   ATA_HORKAGE_1_5_GBPS, },
++      { "Seagate FreeAgent GoFlex",   NULL,   ATA_HORKAGE_1_5_GBPS, },
+       /*
+        * Devices which choke on SETXFER.  Applies only if both the
diff --git a/queue-3.5/media-lirc_sir-make-device-registration-work.patch b/queue-3.5/media-lirc_sir-make-device-registration-work.patch
new file mode 100644 (file)
index 0000000..551650f
--- /dev/null
@@ -0,0 +1,129 @@
+From 4b71ca6bce8fab3d08c61bf330e781f957934ae1 Mon Sep 17 00:00:00 2001
+From: Jarod Wilson <jarod@redhat.com>
+Date: Mon, 4 Jun 2012 13:05:24 -0300
+Subject: media: lirc_sir: make device registration work
+
+From: Jarod Wilson <jarod@redhat.com>
+
+commit 4b71ca6bce8fab3d08c61bf330e781f957934ae1 upstream.
+
+For one, the driver device pointer needs to be filled in, or the lirc core
+will refuse to load the driver. And we really need to wire up all the
+platform_device bits. This has been tested via the lirc sourceforge tree
+and verified to work, been sitting there for months, finally getting
+around to sending it. :\
+
+Signed-off-by: Jarod Wilson <jarod@redhat.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
+CC: Josh Boyer <jwboyer@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/staging/media/lirc/lirc_sir.c |   60 ++++++++++++++++++++++++++++++++--
+ 1 file changed, 58 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/media/lirc/lirc_sir.c
++++ b/drivers/staging/media/lirc/lirc_sir.c
+@@ -52,6 +52,7 @@
+ #include <linux/io.h>
+ #include <asm/irq.h>
+ #include <linux/fcntl.h>
++#include <linux/platform_device.h>
+ #ifdef LIRC_ON_SA1100
+ #include <asm/hardware.h>
+ #ifdef CONFIG_SA1100_COLLIE
+@@ -487,9 +488,11 @@ static struct lirc_driver driver = {
+       .owner          = THIS_MODULE,
+ };
++static struct platform_device *lirc_sir_dev;
+ static int init_chrdev(void)
+ {
++      driver.dev = &lirc_sir_dev->dev;
+       driver.minor = lirc_register_driver(&driver);
+       if (driver.minor < 0) {
+               printk(KERN_ERR LIRC_DRIVER_NAME ": init_chrdev() failed.\n");
+@@ -1215,20 +1218,71 @@ static int init_lirc_sir(void)
+       return 0;
+ }
++static int __devinit lirc_sir_probe(struct platform_device *dev)
++{
++      return 0;
++}
++
++static int __devexit lirc_sir_remove(struct platform_device *dev)
++{
++      return 0;
++}
++
++static struct platform_driver lirc_sir_driver = {
++      .probe          = lirc_sir_probe,
++      .remove         = __devexit_p(lirc_sir_remove),
++      .driver         = {
++              .name   = "lirc_sir",
++              .owner  = THIS_MODULE,
++      },
++};
+ static int __init lirc_sir_init(void)
+ {
+       int retval;
++      retval = platform_driver_register(&lirc_sir_driver);
++      if (retval) {
++              printk(KERN_ERR LIRC_DRIVER_NAME ": Platform driver register "
++                     "failed!\n");
++              return -ENODEV;
++      }
++
++      lirc_sir_dev = platform_device_alloc("lirc_dev", 0);
++      if (!lirc_sir_dev) {
++              printk(KERN_ERR LIRC_DRIVER_NAME ": Platform device alloc "
++                     "failed!\n");
++              retval = -ENOMEM;
++              goto pdev_alloc_fail;
++      }
++
++      retval = platform_device_add(lirc_sir_dev);
++      if (retval) {
++              printk(KERN_ERR LIRC_DRIVER_NAME ": Platform device add "
++                     "failed!\n");
++              retval = -ENODEV;
++              goto pdev_add_fail;
++      }
++
+       retval = init_chrdev();
+       if (retval < 0)
+-              return retval;
++              goto fail;
++
+       retval = init_lirc_sir();
+       if (retval) {
+               drop_chrdev();
+-              return retval;
++              goto fail;
+       }
++
+       return 0;
++
++fail:
++      platform_device_del(lirc_sir_dev);
++pdev_add_fail:
++      platform_device_put(lirc_sir_dev);
++pdev_alloc_fail:
++      platform_driver_unregister(&lirc_sir_driver);
++      return retval;
+ }
+ static void __exit lirc_sir_exit(void)
+@@ -1236,6 +1290,8 @@ static void __exit lirc_sir_exit(void)
+       drop_hardware();
+       drop_chrdev();
+       drop_port();
++      platform_device_unregister(lirc_sir_dev);
++      platform_driver_unregister(&lirc_sir_driver);
+       printk(KERN_INFO LIRC_DRIVER_NAME ": Uninstalled.\n");
+ }
diff --git a/queue-3.5/rds-set-correct-msg_namelen.patch b/queue-3.5/rds-set-correct-msg_namelen.patch
new file mode 100644 (file)
index 0000000..6688b59
--- /dev/null
@@ -0,0 +1,220 @@
+From 06b6a1cf6e776426766298d055bb3991957d90a7 Mon Sep 17 00:00:00 2001
+From: Weiping Pan <wpan@redhat.com>
+Date: Mon, 23 Jul 2012 10:37:48 +0800
+Subject: rds: set correct msg_namelen
+
+From: Weiping Pan <wpan@redhat.com>
+
+commit 06b6a1cf6e776426766298d055bb3991957d90a7 upstream.
+
+Jay Fenlason (fenlason@redhat.com) found a bug,
+that recvfrom() on an RDS socket can return the contents of random kernel
+memory to userspace if it was called with a address length larger than
+sizeof(struct sockaddr_in).
+rds_recvmsg() also fails to set the addr_len paramater properly before
+returning, but that's just a bug.
+There are also a number of cases wher recvfrom() can return an entirely bogus
+address. Anything in rds_recvmsg() that returns a non-negative value but does
+not go through the "sin = (struct sockaddr_in *)msg->msg_name;" code path
+at the end of the while(1) loop will return up to 128 bytes of kernel memory
+to userspace.
+
+And I write two test programs to reproduce this bug, you will see that in
+rds_server, fromAddr will be overwritten and the following sock_fd will be
+destroyed.
+Yes, it is the programmer's fault to set msg_namelen incorrectly, but it is
+better to make the kernel copy the real length of address to user space in
+such case.
+
+How to run the test programs ?
+I test them on 32bit x86 system, 3.5.0-rc7.
+
+1 compile
+gcc -o rds_client rds_client.c
+gcc -o rds_server rds_server.c
+
+2 run ./rds_server on one console
+
+3 run ./rds_client on another console
+
+4 you will see something like:
+server is waiting to receive data...
+old socket fd=3
+server received data from client:data from client
+msg.msg_namelen=32
+new socket fd=-1067277685
+sendmsg()
+: Bad file descriptor
+
+/***************** rds_client.c ********************/
+
+int main(void)
+{
+       int sock_fd;
+       struct sockaddr_in serverAddr;
+       struct sockaddr_in toAddr;
+       char recvBuffer[128] = "data from client";
+       struct msghdr msg;
+       struct iovec iov;
+
+       sock_fd = socket(AF_RDS, SOCK_SEQPACKET, 0);
+       if (sock_fd < 0) {
+               perror("create socket error\n");
+               exit(1);
+       }
+
+       memset(&serverAddr, 0, sizeof(serverAddr));
+       serverAddr.sin_family = AF_INET;
+       serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
+       serverAddr.sin_port = htons(4001);
+
+       if (bind(sock_fd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
+               perror("bind() error\n");
+               close(sock_fd);
+               exit(1);
+       }
+
+       memset(&toAddr, 0, sizeof(toAddr));
+       toAddr.sin_family = AF_INET;
+       toAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
+       toAddr.sin_port = htons(4000);
+       msg.msg_name = &toAddr;
+       msg.msg_namelen = sizeof(toAddr);
+       msg.msg_iov = &iov;
+       msg.msg_iovlen = 1;
+       msg.msg_iov->iov_base = recvBuffer;
+       msg.msg_iov->iov_len = strlen(recvBuffer) + 1;
+       msg.msg_control = 0;
+       msg.msg_controllen = 0;
+       msg.msg_flags = 0;
+
+       if (sendmsg(sock_fd, &msg, 0) == -1) {
+               perror("sendto() error\n");
+               close(sock_fd);
+               exit(1);
+       }
+
+       printf("client send data:%s\n", recvBuffer);
+
+       memset(recvBuffer, '\0', 128);
+
+       msg.msg_name = &toAddr;
+       msg.msg_namelen = sizeof(toAddr);
+       msg.msg_iov = &iov;
+       msg.msg_iovlen = 1;
+       msg.msg_iov->iov_base = recvBuffer;
+       msg.msg_iov->iov_len = 128;
+       msg.msg_control = 0;
+       msg.msg_controllen = 0;
+       msg.msg_flags = 0;
+       if (recvmsg(sock_fd, &msg, 0) == -1) {
+               perror("recvmsg() error\n");
+               close(sock_fd);
+               exit(1);
+       }
+
+       printf("receive data from server:%s\n", recvBuffer);
+
+       close(sock_fd);
+
+       return 0;
+}
+
+/***************** rds_server.c ********************/
+
+int main(void)
+{
+       struct sockaddr_in fromAddr;
+       int sock_fd;
+       struct sockaddr_in serverAddr;
+       unsigned int addrLen;
+       char recvBuffer[128];
+       struct msghdr msg;
+       struct iovec iov;
+
+       sock_fd = socket(AF_RDS, SOCK_SEQPACKET, 0);
+       if(sock_fd < 0) {
+               perror("create socket error\n");
+               exit(0);
+       }
+
+       memset(&serverAddr, 0, sizeof(serverAddr));
+       serverAddr.sin_family = AF_INET;
+       serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
+       serverAddr.sin_port = htons(4000);
+       if (bind(sock_fd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
+               perror("bind error\n");
+               close(sock_fd);
+               exit(1);
+       }
+
+       printf("server is waiting to receive data...\n");
+       msg.msg_name = &fromAddr;
+
+       /*
+        * I add 16 to sizeof(fromAddr), ie 32,
+        * and pay attention to the definition of fromAddr,
+        * recvmsg() will overwrite sock_fd,
+        * since kernel will copy 32 bytes to userspace.
+        *
+        * If you just use sizeof(fromAddr), it works fine.
+        * */
+       msg.msg_namelen = sizeof(fromAddr) + 16;
+       /* msg.msg_namelen = sizeof(fromAddr); */
+       msg.msg_iov = &iov;
+       msg.msg_iovlen = 1;
+       msg.msg_iov->iov_base = recvBuffer;
+       msg.msg_iov->iov_len = 128;
+       msg.msg_control = 0;
+       msg.msg_controllen = 0;
+       msg.msg_flags = 0;
+
+       while (1) {
+               printf("old socket fd=%d\n", sock_fd);
+               if (recvmsg(sock_fd, &msg, 0) == -1) {
+                       perror("recvmsg() error\n");
+                       close(sock_fd);
+                       exit(1);
+               }
+               printf("server received data from client:%s\n", recvBuffer);
+               printf("msg.msg_namelen=%d\n", msg.msg_namelen);
+               printf("new socket fd=%d\n", sock_fd);
+               strcat(recvBuffer, "--data from server");
+               if (sendmsg(sock_fd, &msg, 0) == -1) {
+                       perror("sendmsg()\n");
+                       close(sock_fd);
+                       exit(1);
+               }
+       }
+
+       close(sock_fd);
+       return 0;
+}
+
+Signed-off-by: Weiping Pan <wpan@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/rds/recv.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/net/rds/recv.c
++++ b/net/rds/recv.c
+@@ -410,6 +410,8 @@ int rds_recvmsg(struct kiocb *iocb, stru
+       rdsdebug("size %zu flags 0x%x timeo %ld\n", size, msg_flags, timeo);
++      msg->msg_namelen = 0;
++
+       if (msg_flags & MSG_OOB)
+               goto out;
+@@ -485,6 +487,7 @@ int rds_recvmsg(struct kiocb *iocb, stru
+                       sin->sin_port = inc->i_hdr.h_sport;
+                       sin->sin_addr.s_addr = inc->i_saddr;
+                       memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
++                      msg->msg_namelen = sizeof(*sin);
+               }
+               break;
+       }
diff --git a/queue-3.5/sched-fix-race-in-task_group.patch b/queue-3.5/sched-fix-race-in-task_group.patch
new file mode 100644 (file)
index 0000000..6259541
--- /dev/null
@@ -0,0 +1,152 @@
+From 8323f26ce3425460769605a6aece7a174edaa7d1 Mon Sep 17 00:00:00 2001
+From: Peter Zijlstra <peterz@infradead.org>
+Date: Fri, 22 Jun 2012 13:36:05 +0200
+Subject: sched: Fix race in task_group()
+
+From: Peter Zijlstra <peterz@infradead.org>
+
+commit 8323f26ce3425460769605a6aece7a174edaa7d1 upstream.
+
+Stefan reported a crash on a kernel before a3e5d1091c1 ("sched:
+Don't call task_group() too many times in set_task_rq()"), he
+found the reason to be that the multiple task_group()
+invocations in set_task_rq() returned different values.
+
+Looking at all that I found a lack of serialization and plain
+wrong comments.
+
+The below tries to fix it using an extra pointer which is
+updated under the appropriate scheduler locks. Its not pretty,
+but I can't really see another way given how all the cgroup
+stuff works.
+
+Reported-and-tested-by: Stefan Bader <stefan.bader@canonical.com>
+Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
+Link: http://lkml.kernel.org/r/1340364965.18025.71.camel@twins
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ include/linux/init_task.h |   12 +++++++++++-
+ include/linux/sched.h     |    5 ++++-
+ kernel/sched/core.c       |    9 ++++++++-
+ kernel/sched/sched.h      |   23 ++++++++++-------------
+ 4 files changed, 33 insertions(+), 16 deletions(-)
+
+--- a/include/linux/init_task.h
++++ b/include/linux/init_task.h
+@@ -123,8 +123,17 @@ extern struct group_info init_groups;
+ extern struct cred init_cred;
++extern struct task_group root_task_group;
++
++#ifdef CONFIG_CGROUP_SCHED
++# define INIT_CGROUP_SCHED(tsk)                                               \
++      .sched_task_group = &root_task_group,
++#else
++# define INIT_CGROUP_SCHED(tsk)
++#endif
++
+ #ifdef CONFIG_PERF_EVENTS
+-# define INIT_PERF_EVENTS(tsk)                                        \
++# define INIT_PERF_EVENTS(tsk)                                                \
+       .perf_event_mutex =                                             \
+                __MUTEX_INITIALIZER(tsk.perf_event_mutex),             \
+       .perf_event_list = LIST_HEAD_INIT(tsk.perf_event_list),
+@@ -161,6 +170,7 @@ extern struct cred init_cred;
+       },                                                              \
+       .tasks          = LIST_HEAD_INIT(tsk.tasks),                    \
+       INIT_PUSHABLE_TASKS(tsk)                                        \
++      INIT_CGROUP_SCHED(tsk)                                          \
+       .ptraced        = LIST_HEAD_INIT(tsk.ptraced),                  \
+       .ptrace_entry   = LIST_HEAD_INIT(tsk.ptrace_entry),             \
+       .real_parent    = &tsk,                                         \
+--- a/include/linux/sched.h
++++ b/include/linux/sched.h
+@@ -1244,6 +1244,9 @@ struct task_struct {
+       const struct sched_class *sched_class;
+       struct sched_entity se;
+       struct sched_rt_entity rt;
++#ifdef CONFIG_CGROUP_SCHED
++      struct task_group *sched_task_group;
++#endif
+ #ifdef CONFIG_PREEMPT_NOTIFIERS
+       /* list of struct preempt_notifier: */
+@@ -2723,7 +2726,7 @@ extern int sched_group_set_rt_period(str
+ extern long sched_group_rt_period(struct task_group *tg);
+ extern int sched_rt_can_attach(struct task_group *tg, struct task_struct *tsk);
+ #endif
+-#endif
++#endif /* CONFIG_CGROUP_SCHED */
+ extern int task_can_switch_user(struct user_struct *up,
+                                       struct task_struct *tsk);
+--- a/kernel/sched/core.c
++++ b/kernel/sched/core.c
+@@ -1096,7 +1096,7 @@ void set_task_cpu(struct task_struct *p,
+        * a task's CPU. ->pi_lock for waking tasks, rq->lock for runnable tasks.
+        *
+        * sched_move_task() holds both and thus holding either pins the cgroup,
+-       * see set_task_rq().
++       * see task_group().
+        *
+        * Furthermore, all task_rq users should acquire both locks, see
+        * task_rq_lock().
+@@ -7596,6 +7596,7 @@ void sched_destroy_group(struct task_gro
+  */
+ void sched_move_task(struct task_struct *tsk)
+ {
++      struct task_group *tg;
+       int on_rq, running;
+       unsigned long flags;
+       struct rq *rq;
+@@ -7610,6 +7611,12 @@ void sched_move_task(struct task_struct
+       if (unlikely(running))
+               tsk->sched_class->put_prev_task(rq, tsk);
++      tg = container_of(task_subsys_state_check(tsk, cpu_cgroup_subsys_id,
++                              lockdep_is_held(&tsk->sighand->siglock)),
++                        struct task_group, css);
++      tg = autogroup_task_group(tsk, tg);
++      tsk->sched_task_group = tg;
++
+ #ifdef CONFIG_FAIR_GROUP_SCHED
+       if (tsk->sched_class->task_move_group)
+               tsk->sched_class->task_move_group(tsk, on_rq);
+--- a/kernel/sched/sched.h
++++ b/kernel/sched/sched.h
+@@ -538,22 +538,19 @@ extern int group_balance_cpu(struct sche
+ /*
+  * Return the group to which this tasks belongs.
+  *
+- * We use task_subsys_state_check() and extend the RCU verification with
+- * pi->lock and rq->lock because cpu_cgroup_attach() holds those locks for each
+- * task it moves into the cgroup. Therefore by holding either of those locks,
+- * we pin the task to the current cgroup.
++ * We cannot use task_subsys_state() and friends because the cgroup
++ * subsystem changes that value before the cgroup_subsys::attach() method
++ * is called, therefore we cannot pin it and might observe the wrong value.
++ *
++ * The same is true for autogroup's p->signal->autogroup->tg, the autogroup
++ * core changes this before calling sched_move_task().
++ *
++ * Instead we use a 'copy' which is updated from sched_move_task() while
++ * holding both task_struct::pi_lock and rq::lock.
+  */
+ static inline struct task_group *task_group(struct task_struct *p)
+ {
+-      struct task_group *tg;
+-      struct cgroup_subsys_state *css;
+-
+-      css = task_subsys_state_check(p, cpu_cgroup_subsys_id,
+-                      lockdep_is_held(&p->pi_lock) ||
+-                      lockdep_is_held(&task_rq(p)->lock));
+-      tg = container_of(css, struct task_group, css);
+-
+-      return autogroup_task_group(p, tg);
++      return p->sched_task_group;
+ }
+ /* Change a task's cfs_rq and parent entity if it moves across CPUs/groups */
index 195650d814797eda9de31aec7fb681582c2ddc3a..1be46961985bfab14a52a2d8a8e1317d26e5da14 100644 (file)
@@ -222,3 +222,8 @@ bluetooth-add-support-for-apple-vendor-specific-devices.patch
 bluetooth-fix-use-after-free-bug-in-smp.patch
 bluetooth-change-signature-of-smp_conn_security.patch
 bluetooth-fix-sending-a-hci-authorization-request-over-le-links.patch
+fix-a-dead-loop-in-async_synchronize_full.patch
+rds-set-correct-msg_namelen.patch
+libata-prevent-interface-errors-with-seagate-freeagent-goflex.patch
+sched-fix-race-in-task_group.patch
+media-lirc_sir-make-device-registration-work.patch