]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.1-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 19 Aug 2015 15:56:29 +0000 (08:56 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 19 Aug 2015 15:56:29 +0000 (08:56 -0700)
added patches:
clk-pxa-pxa3xx-fix-cken-register-access.patch
ipc-sem-fix-use-after-free-on-ipc_rmid-after-a-task-using-same-semaphore-set-exits.patch
ipc-sem.c-update-correct-memory-barriers.patch
mm-hwpoison-fix-fail-isolate-hugetlbfs-page-w-refcount-held.patch
mm-hwpoison-fix-page-refcount-of-unknown-non-lru-page.patch
rsi-fix-failure-to-load-firmware-after-memory-leak-fix-and-fix-the-leak.patch
xen-blkback-replace-work_pending-with-work_busy-in-purge_persistent_gnt.patch
xen-blkfront-don-t-add-indirect-pages-to-list-when.patch

queue-4.1/clk-pxa-pxa3xx-fix-cken-register-access.patch [new file with mode: 0644]
queue-4.1/ipc-sem-fix-use-after-free-on-ipc_rmid-after-a-task-using-same-semaphore-set-exits.patch [new file with mode: 0644]
queue-4.1/ipc-sem.c-update-correct-memory-barriers.patch [new file with mode: 0644]
queue-4.1/mm-hwpoison-fix-fail-isolate-hugetlbfs-page-w-refcount-held.patch [new file with mode: 0644]
queue-4.1/mm-hwpoison-fix-page-refcount-of-unknown-non-lru-page.patch [new file with mode: 0644]
queue-4.1/rsi-fix-failure-to-load-firmware-after-memory-leak-fix-and-fix-the-leak.patch [new file with mode: 0644]
queue-4.1/xen-blkback-replace-work_pending-with-work_busy-in-purge_persistent_gnt.patch [new file with mode: 0644]
queue-4.1/xen-blkfront-don-t-add-indirect-pages-to-list-when.patch [new file with mode: 0644]

diff --git a/queue-4.1/clk-pxa-pxa3xx-fix-cken-register-access.patch b/queue-4.1/clk-pxa-pxa3xx-fix-cken-register-access.patch
new file mode 100644 (file)
index 0000000..203cd5f
--- /dev/null
@@ -0,0 +1,38 @@
+From b93028c9af807b9474789e6aba34a6135b6cb708 Mon Sep 17 00:00:00 2001
+From: Robert Jarzmik <robert.jarzmik@free.fr>
+Date: Tue, 4 Aug 2015 08:21:33 +0200
+Subject: clk: pxa: pxa3xx: fix CKEN register access
+
+From: Robert Jarzmik <robert.jarzmik@free.fr>
+
+commit b93028c9af807b9474789e6aba34a6135b6cb708 upstream.
+
+Clocks 0 to 31 are on CKENA, and not CKENB. The clock register names
+were inadequately inverted. As a consequence, all clock operations were
+happening on CKENB, because almost all but 2 clocks are on CKENA.
+
+As the clocks were activated by the bootloader in the former tests, it
+escaped the testing that the wrong clock gate was manipulated. The error
+was revealed by changing the pxa3xx-nand driver to a module, where upon
+unloading, the wrong clock was disabled in CKENB.
+
+Fixes: 9bbb8a338fb2 ("clk: pxa: add pxa3xx clock driver")
+Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/clk/pxa/clk-pxa3xx.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/clk/pxa/clk-pxa3xx.c
++++ b/drivers/clk/pxa/clk-pxa3xx.c
+@@ -126,7 +126,7 @@ PARENTS(pxa3xx_ac97_bus) = { "ring_osc_6
+ PARENTS(pxa3xx_sbus) = { "ring_osc_60mhz", "system_bus" };
+ PARENTS(pxa3xx_smemcbus) = { "ring_osc_60mhz", "smemc" };
+-#define CKEN_AB(bit) ((CKEN_ ## bit > 31) ? &CKENA : &CKENB)
++#define CKEN_AB(bit) ((CKEN_ ## bit > 31) ? &CKENB : &CKENA)
+ #define PXA3XX_CKEN(dev_id, con_id, parents, mult_lp, div_lp, mult_hp,        \
+                   div_hp, bit, is_lp, flags)                          \
+       PXA_CKEN(dev_id, con_id, bit, parents, mult_lp, div_lp,         \
diff --git a/queue-4.1/ipc-sem-fix-use-after-free-on-ipc_rmid-after-a-task-using-same-semaphore-set-exits.patch b/queue-4.1/ipc-sem-fix-use-after-free-on-ipc_rmid-after-a-task-using-same-semaphore-set-exits.patch
new file mode 100644 (file)
index 0000000..22323f8
--- /dev/null
@@ -0,0 +1,254 @@
+From 602b8593d2b4138c10e922eeaafe306f6b51817b Mon Sep 17 00:00:00 2001
+From: "Herton R. Krzesinski" <herton@redhat.com>
+Date: Fri, 14 Aug 2015 15:35:02 -0700
+Subject: ipc,sem: fix use after free on IPC_RMID after a task using same semaphore set exits
+
+From: "Herton R. Krzesinski" <herton@redhat.com>
+
+commit 602b8593d2b4138c10e922eeaafe306f6b51817b upstream.
+
+The current semaphore code allows a potential use after free: in
+exit_sem we may free the task's sem_undo_list while there is still
+another task looping through the same semaphore set and cleaning the
+sem_undo list at freeary function (the task called IPC_RMID for the same
+semaphore set).
+
+For example, with a test program [1] running which keeps forking a lot
+of processes (which then do a semop call with SEM_UNDO flag), and with
+the parent right after removing the semaphore set with IPC_RMID, and a
+kernel built with CONFIG_SLAB, CONFIG_SLAB_DEBUG and
+CONFIG_DEBUG_SPINLOCK, you can easily see something like the following
+in the kernel log:
+
+   Slab corruption (Not tainted): kmalloc-64 start=ffff88003b45c1c0, len=64
+   000: 6b 6b 6b 6b 6b 6b 6b 6b 00 6b 6b 6b 6b 6b 6b 6b  kkkkkkkk.kkkkkkk
+   010: ff ff ff ff 6b 6b 6b 6b ff ff ff ff ff ff ff ff  ....kkkk........
+   Prev obj: start=ffff88003b45c180, len=64
+   000: 00 00 00 00 ad 4e ad de ff ff ff ff 5a 5a 5a 5a  .....N......ZZZZ
+   010: ff ff ff ff ff ff ff ff c0 fb 01 37 00 88 ff ff  ...........7....
+   Next obj: start=ffff88003b45c200, len=64
+   000: 00 00 00 00 ad 4e ad de ff ff ff ff 5a 5a 5a 5a  .....N......ZZZZ
+   010: ff ff ff ff ff ff ff ff 68 29 a7 3c 00 88 ff ff  ........h).<....
+   BUG: spinlock wrong CPU on CPU#2, test/18028
+   general protection fault: 0000 [#1] SMP
+   Modules linked in: 8021q mrp garp stp llc nf_conntrack_ipv4 nf_defrag_ipv4 ip6t_REJECT nf_reject_ipv6 nf_conntrack_ipv6 nf_defrag_ipv6 xt_state nf_conntrack ip6table_filter ip6_tables binfmt_misc ppdev input_leds joydev parport_pc parport floppy serio_raw virtio_balloon virtio_rng virtio_console virtio_net iosf_mbi crct10dif_pclmul crc32_pclmul ghash_clmulni_intel pcspkr qxl ttm drm_kms_helper drm snd_hda_codec_generic i2c_piix4 snd_hda_intel snd_hda_codec snd_hda_core snd_hwdep snd_seq snd_seq_device snd_pcm snd_timer snd soundcore crc32c_intel virtio_pci virtio_ring virtio pata_acpi ata_generic [last unloaded: speedstep_lib]
+   CPU: 2 PID: 18028 Comm: test Not tainted 4.2.0-rc5+ #1
+   Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.8.1-20150318_183358- 04/01/2014
+   RIP: spin_dump+0x53/0xc0
+   Call Trace:
+     spin_bug+0x30/0x40
+     do_raw_spin_unlock+0x71/0xa0
+     _raw_spin_unlock+0xe/0x10
+     freeary+0x82/0x2a0
+     ? _raw_spin_lock+0xe/0x10
+     semctl_down.clone.0+0xce/0x160
+     ? __do_page_fault+0x19a/0x430
+     ? __audit_syscall_entry+0xa8/0x100
+     SyS_semctl+0x236/0x2c0
+     ? syscall_trace_leave+0xde/0x130
+     entry_SYSCALL_64_fastpath+0x12/0x71
+   Code: 8b 80 88 03 00 00 48 8d 88 60 05 00 00 48 c7 c7 a0 2c a4 81 31 c0 65 8b 15 eb 40 f3 7e e8 08 31 68 00 4d 85 e4 44 8b 4b 08 74 5e <45> 8b 84 24 88 03 00 00 49 8d 8c 24 60 05 00 00 8b 53 04 48 89
+   RIP  [<ffffffff810d6053>] spin_dump+0x53/0xc0
+    RSP <ffff88003750fd68>
+   ---[ end trace 783ebb76612867a0 ]---
+   NMI watchdog: BUG: soft lockup - CPU#3 stuck for 22s! [test:18053]
+   Modules linked in: 8021q mrp garp stp llc nf_conntrack_ipv4 nf_defrag_ipv4 ip6t_REJECT nf_reject_ipv6 nf_conntrack_ipv6 nf_defrag_ipv6 xt_state nf_conntrack ip6table_filter ip6_tables binfmt_misc ppdev input_leds joydev parport_pc parport floppy serio_raw virtio_balloon virtio_rng virtio_console virtio_net iosf_mbi crct10dif_pclmul crc32_pclmul ghash_clmulni_intel pcspkr qxl ttm drm_kms_helper drm snd_hda_codec_generic i2c_piix4 snd_hda_intel snd_hda_codec snd_hda_core snd_hwdep snd_seq snd_seq_device snd_pcm snd_timer snd soundcore crc32c_intel virtio_pci virtio_ring virtio pata_acpi ata_generic [last unloaded: speedstep_lib]
+   CPU: 3 PID: 18053 Comm: test Tainted: G      D         4.2.0-rc5+ #1
+   Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.8.1-20150318_183358- 04/01/2014
+   RIP: native_read_tsc+0x0/0x20
+   Call Trace:
+     ? delay_tsc+0x40/0x70
+     __delay+0xf/0x20
+     do_raw_spin_lock+0x96/0x140
+     _raw_spin_lock+0xe/0x10
+     sem_lock_and_putref+0x11/0x70
+     SYSC_semtimedop+0x7bf/0x960
+     ? handle_mm_fault+0xbf6/0x1880
+     ? dequeue_task_fair+0x79/0x4a0
+     ? __do_page_fault+0x19a/0x430
+     ? kfree_debugcheck+0x16/0x40
+     ? __do_page_fault+0x19a/0x430
+     ? __audit_syscall_entry+0xa8/0x100
+     ? do_audit_syscall_entry+0x66/0x70
+     ? syscall_trace_enter_phase1+0x139/0x160
+     SyS_semtimedop+0xe/0x10
+     SyS_semop+0x10/0x20
+     entry_SYSCALL_64_fastpath+0x12/0x71
+   Code: 47 10 83 e8 01 85 c0 89 47 10 75 08 65 48 89 3d 1f 74 ff 7e c9 c3 0f 1f 44 00 00 55 48 89 e5 e8 87 17 04 00 66 90 c9 c3 0f 1f 00 <55> 48 89 e5 0f 31 89 c1 48 89 d0 48 c1 e0 20 89 c9 48 09 c8 c9
+   Kernel panic - not syncing: softlockup: hung tasks
+
+I wasn't able to trigger any badness on a recent kernel without the
+proper config debugs enabled, however I have softlockup reports on some
+kernel versions, in the semaphore code, which are similar as above (the
+scenario is seen on some servers running IBM DB2 which uses semaphore
+syscalls).
+
+The patch here fixes the race against freeary, by acquiring or waiting
+on the sem_undo_list lock as necessary (exit_sem can race with freeary,
+while freeary sets un->semid to -1 and removes the same sem_undo from
+list_proc or when it removes the last sem_undo).
+
+After the patch I'm unable to reproduce the problem using the test case
+[1].
+
+[1] Test case used below:
+
+    #include <stdio.h>
+    #include <sys/types.h>
+    #include <sys/ipc.h>
+    #include <sys/sem.h>
+    #include <sys/wait.h>
+    #include <stdlib.h>
+    #include <time.h>
+    #include <unistd.h>
+    #include <errno.h>
+
+    #define NSEM 1
+    #define NSET 5
+
+    int sid[NSET];
+
+    void thread()
+    {
+            struct sembuf op;
+            int s;
+            uid_t pid = getuid();
+
+            s = rand() % NSET;
+            op.sem_num = pid % NSEM;
+            op.sem_op = 1;
+            op.sem_flg = SEM_UNDO;
+
+            semop(sid[s], &op, 1);
+            exit(EXIT_SUCCESS);
+    }
+
+    void create_set()
+    {
+            int i, j;
+            pid_t p;
+            union {
+                    int val;
+                    struct semid_ds *buf;
+                    unsigned short int *array;
+                    struct seminfo *__buf;
+            } un;
+
+            /* Create and initialize semaphore set */
+            for (i = 0; i < NSET; i++) {
+                    sid[i] = semget(IPC_PRIVATE , NSEM, 0644 | IPC_CREAT);
+                    if (sid[i] < 0) {
+                            perror("semget");
+                            exit(EXIT_FAILURE);
+                    }
+            }
+            un.val = 0;
+            for (i = 0; i < NSET; i++) {
+                    for (j = 0; j < NSEM; j++) {
+                            if (semctl(sid[i], j, SETVAL, un) < 0)
+                                    perror("semctl");
+                    }
+            }
+
+            /* Launch threads that operate on semaphore set */
+            for (i = 0; i < NSEM * NSET * NSET; i++) {
+                    p = fork();
+                    if (p < 0)
+                            perror("fork");
+                    if (p == 0)
+                            thread();
+            }
+
+            /* Free semaphore set */
+            for (i = 0; i < NSET; i++) {
+                    if (semctl(sid[i], NSEM, IPC_RMID))
+                            perror("IPC_RMID");
+            }
+
+            /* Wait for forked processes to exit */
+            while (wait(NULL)) {
+                    if (errno == ECHILD)
+                            break;
+            };
+    }
+
+    int main(int argc, char **argv)
+    {
+            pid_t p;
+
+            srand(time(NULL));
+
+            while (1) {
+                    p = fork();
+                    if (p < 0) {
+                            perror("fork");
+                            exit(EXIT_FAILURE);
+                    }
+                    if (p == 0) {
+                            create_set();
+                            goto end;
+                    }
+
+                    /* Wait for forked processes to exit */
+                    while (wait(NULL)) {
+                            if (errno == ECHILD)
+                                    break;
+                    };
+            }
+    end:
+            return 0;
+    }
+
+[akpm@linux-foundation.org: use normal comment layout]
+Signed-off-by: Herton R. Krzesinski <herton@redhat.com>
+Acked-by: Manfred Spraul <manfred@colorfullife.com>
+Cc: Davidlohr Bueso <dave@stgolabs.net>
+Cc: Rafael Aquini <aquini@redhat.com>
+CC: Aristeu Rozanski <aris@redhat.com>
+Cc: David Jeffery <djeffery@redhat.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+
+---
+ ipc/sem.c |   23 +++++++++++++++++------
+ 1 file changed, 17 insertions(+), 6 deletions(-)
+
+--- a/ipc/sem.c
++++ b/ipc/sem.c
+@@ -2074,17 +2074,28 @@ void exit_sem(struct task_struct *tsk)
+               rcu_read_lock();
+               un = list_entry_rcu(ulp->list_proc.next,
+                                   struct sem_undo, list_proc);
+-              if (&un->list_proc == &ulp->list_proc)
+-                      semid = -1;
+-               else
+-                      semid = un->semid;
++              if (&un->list_proc == &ulp->list_proc) {
++                      /*
++                       * We must wait for freeary() before freeing this ulp,
++                       * in case we raced with last sem_undo. There is a small
++                       * possibility where we exit while freeary() didn't
++                       * finish unlocking sem_undo_list.
++                       */
++                      spin_unlock_wait(&ulp->lock);
++                      rcu_read_unlock();
++                      break;
++              }
++              spin_lock(&ulp->lock);
++              semid = un->semid;
++              spin_unlock(&ulp->lock);
++              /* exit_sem raced with IPC_RMID, nothing to do */
+               if (semid == -1) {
+                       rcu_read_unlock();
+-                      break;
++                      continue;
+               }
+-              sma = sem_obtain_object_check(tsk->nsproxy->ipc_ns, un->semid);
++              sma = sem_obtain_object_check(tsk->nsproxy->ipc_ns, semid);
+               /* exit_sem raced with IPC_RMID, nothing to do */
+               if (IS_ERR(sma)) {
+                       rcu_read_unlock();
diff --git a/queue-4.1/ipc-sem.c-update-correct-memory-barriers.patch b/queue-4.1/ipc-sem.c-update-correct-memory-barriers.patch
new file mode 100644 (file)
index 0000000..c5fbdbf
--- /dev/null
@@ -0,0 +1,86 @@
+From 3ed1f8a99d70ea1cd1508910eb107d0edcae5009 Mon Sep 17 00:00:00 2001
+From: Manfred Spraul <manfred@colorfullife.com>
+Date: Fri, 14 Aug 2015 15:35:10 -0700
+Subject: ipc/sem.c: update/correct memory barriers
+
+From: Manfred Spraul <manfred@colorfullife.com>
+
+commit 3ed1f8a99d70ea1cd1508910eb107d0edcae5009 upstream.
+
+sem_lock() did not properly pair memory barriers:
+
+!spin_is_locked() and spin_unlock_wait() are both only control barriers.
+The code needs an acquire barrier, otherwise the cpu might perform read
+operations before the lock test.
+
+As no primitive exists inside <include/spinlock.h> and since it seems
+noone wants another primitive, the code creates a local primitive within
+ipc/sem.c.
+
+With regards to -stable:
+
+The change of sem_wait_array() is a bugfix, the change to sem_lock() is a
+nop (just a preprocessor redefinition to improve the readability).  The
+bugfix is necessary for all kernels that use sem_wait_array() (i.e.:
+starting from 3.10).
+
+Signed-off-by: Manfred Spraul <manfred@colorfullife.com>
+Reported-by: Oleg Nesterov <oleg@redhat.com>
+Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Cc: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
+Cc: Kirill Tkhai <ktkhai@parallels.com>
+Cc: Ingo Molnar <mingo@redhat.com>
+Cc: Josh Poimboeuf <jpoimboe@redhat.com>
+Cc: Davidlohr Bueso <dave@stgolabs.net>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ ipc/sem.c |   18 ++++++++++++++----
+ 1 file changed, 14 insertions(+), 4 deletions(-)
+
+--- a/ipc/sem.c
++++ b/ipc/sem.c
+@@ -253,6 +253,16 @@ static void sem_rcu_free(struct rcu_head
+ }
+ /*
++ * spin_unlock_wait() and !spin_is_locked() are not memory barriers, they
++ * are only control barriers.
++ * The code must pair with spin_unlock(&sem->lock) or
++ * spin_unlock(&sem_perm.lock), thus just the control barrier is insufficient.
++ *
++ * smp_rmb() is sufficient, as writes cannot pass the control barrier.
++ */
++#define ipc_smp_acquire__after_spin_is_unlocked()     smp_rmb()
++
++/*
+  * Wait until all currently ongoing simple ops have completed.
+  * Caller must own sem_perm.lock.
+  * New simple ops cannot start, because simple ops first check
+@@ -275,6 +285,7 @@ static void sem_wait_array(struct sem_ar
+               sem = sma->sem_base + i;
+               spin_unlock_wait(&sem->lock);
+       }
++      ipc_smp_acquire__after_spin_is_unlocked();
+ }
+ /*
+@@ -327,13 +338,12 @@ static inline int sem_lock(struct sem_ar
+               /* Then check that the global lock is free */
+               if (!spin_is_locked(&sma->sem_perm.lock)) {
+                       /*
+-                       * The ipc object lock check must be visible on all
+-                       * cores before rechecking the complex count.  Otherwise
+-                       * we can race with  another thread that does:
++                       * We need a memory barrier with acquire semantics,
++                       * otherwise we can race with another thread that does:
+                        *      complex_count++;
+                        *      spin_unlock(sem_perm.lock);
+                        */
+-                      smp_rmb();
++                      ipc_smp_acquire__after_spin_is_unlocked();
+                       /*
+                        * Now repeat the test of complex_count:
diff --git a/queue-4.1/mm-hwpoison-fix-fail-isolate-hugetlbfs-page-w-refcount-held.patch b/queue-4.1/mm-hwpoison-fix-fail-isolate-hugetlbfs-page-w-refcount-held.patch
new file mode 100644 (file)
index 0000000..66962bb
--- /dev/null
@@ -0,0 +1,48 @@
+From 036138080a4376e5f3e5d0cca8ac99084c5cf06e Mon Sep 17 00:00:00 2001
+From: Wanpeng Li <wanpeng.li@hotmail.com>
+Date: Fri, 14 Aug 2015 15:34:59 -0700
+Subject: mm/hwpoison: fix fail isolate hugetlbfs page w/ refcount held
+
+From: Wanpeng Li <wanpeng.li@hotmail.com>
+
+commit 036138080a4376e5f3e5d0cca8ac99084c5cf06e upstream.
+
+Hugetlbfs pages will get a refcount in get_any_page() or
+madvise_hwpoison() if soft offlining through madvise.  The refcount which
+is held by the soft offline path should be released if we fail to isolate
+hugetlbfs pages.
+
+Fix it by reducing the refcount for both isolation success and failure.
+
+Signed-off-by: Wanpeng Li <wanpeng.li@hotmail.com>
+Acked-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ mm/memory-failure.c |   13 ++++++-------
+ 1 file changed, 6 insertions(+), 7 deletions(-)
+
+--- a/mm/memory-failure.c
++++ b/mm/memory-failure.c
+@@ -1589,13 +1589,12 @@ static int soft_offline_huge_page(struct
+       unlock_page(hpage);
+       ret = isolate_huge_page(hpage, &pagelist);
+-      if (ret) {
+-              /*
+-               * get_any_page() and isolate_huge_page() takes a refcount each,
+-               * so need to drop one here.
+-               */
+-              put_page(hpage);
+-      } else {
++      /*
++       * get_any_page() and isolate_huge_page() takes a refcount each,
++       * so need to drop one here.
++       */
++      put_page(hpage);
++      if (!ret) {
+               pr_info("soft offline: %#lx hugepage failed to isolate\n", pfn);
+               return -EBUSY;
+       }
diff --git a/queue-4.1/mm-hwpoison-fix-page-refcount-of-unknown-non-lru-page.patch b/queue-4.1/mm-hwpoison-fix-page-refcount-of-unknown-non-lru-page.patch
new file mode 100644 (file)
index 0000000..5179e96
--- /dev/null
@@ -0,0 +1,37 @@
+From 4f32be677b124a49459e2603321c7a5605ceb9f8 Mon Sep 17 00:00:00 2001
+From: Wanpeng Li <wanpeng.li@hotmail.com>
+Date: Fri, 14 Aug 2015 15:34:56 -0700
+Subject: mm/hwpoison: fix page refcount of unknown non LRU page
+
+From: Wanpeng Li <wanpeng.li@hotmail.com>
+
+commit 4f32be677b124a49459e2603321c7a5605ceb9f8 upstream.
+
+After trying to drain pages from pagevec/pageset, we try to get reference
+count of the page again, however, the reference count of the page is not
+reduced if the page is still not on LRU list.
+
+Fix it by adding the put_page() to drop the page reference which is from
+__get_any_page().
+
+Signed-off-by: Wanpeng Li <wanpeng.li@hotmail.com>
+Acked-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ mm/memory-failure.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/mm/memory-failure.c
++++ b/mm/memory-failure.c
+@@ -1558,6 +1558,8 @@ static int get_any_page(struct page *pag
+                */
+               ret = __get_any_page(page, pfn, 0);
+               if (!PageLRU(page)) {
++                      /* Drop page reference which is from __get_any_page() */
++                      put_page(page);
+                       pr_info("soft_offline: %#lx: unknown non LRU page type %lx\n",
+                               pfn, page->flags);
+                       return -EIO;
diff --git a/queue-4.1/rsi-fix-failure-to-load-firmware-after-memory-leak-fix-and-fix-the-leak.patch b/queue-4.1/rsi-fix-failure-to-load-firmware-after-memory-leak-fix-and-fix-the-leak.patch
new file mode 100644 (file)
index 0000000..a20f392
--- /dev/null
@@ -0,0 +1,88 @@
+From 5d5cd85ff441534a52f23f821d0a7c644d3b6cce Mon Sep 17 00:00:00 2001
+From: Mike Looijmans <mike.looijmans@topic.nl>
+Date: Tue, 28 Jul 2015 07:51:01 +0200
+Subject: rsi: Fix failure to load firmware after memory leak fix and fix the leak
+
+From: Mike Looijmans <mike.looijmans@topic.nl>
+
+commit 5d5cd85ff441534a52f23f821d0a7c644d3b6cce upstream.
+
+Fixes commit eae79b4f3e82 ("rsi: fix memory leak in rsi_load_ta_instructions()")
+which stopped the driver from functioning.
+
+Firmware data has been allocated using vmalloc(), resulting in memory
+that cannot be used for DMA. Hence the firmware was first copied to a
+buffer allocated with kmalloc() in the original code. This patch reverts
+the commit and only calls "kfree()" to release the buffer after sending
+the data. This fixes the memory leak without breaking the driver.
+
+Add a comment to the kmemdup() calls to explain why this is done, and abort
+if memory allocation fails.
+
+Tested on a Topic Miami-Florida board which contains the rsi SDIO chip.
+
+Also added the same kfree() call to the USB glue driver. This was not
+tested on actual hardware though, as I only have the SDIO version.
+
+Fixes: eae79b4f3e82 ("rsi: fix memory leak in rsi_load_ta_instructions()")
+Signed-off-by: Mike Looijmans <mike.looijmans@topic.nl>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/wireless/rsi/rsi_91x_sdio_ops.c |    8 +++++++-
+ drivers/net/wireless/rsi/rsi_91x_usb_ops.c  |    4 ++++
+ 2 files changed, 11 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
++++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
+@@ -172,6 +172,7 @@ static int rsi_load_ta_instructions(stru
+               (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+       u32 len;
+       u32 num_blocks;
++      const u8 *fw;
+       const struct firmware *fw_entry = NULL;
+       u32 block_size = dev->tx_blk_size;
+       int status = 0;
+@@ -200,6 +201,10 @@ static int rsi_load_ta_instructions(stru
+               return status;
+       }
++      /* Copy firmware into DMA-accessible memory */
++      fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);
++      if (!fw)
++              return -ENOMEM;
+       len = fw_entry->size;
+       if (len % 4)
+@@ -210,7 +215,8 @@ static int rsi_load_ta_instructions(stru
+       rsi_dbg(INIT_ZONE, "%s: Instruction size:%d\n", __func__, len);
+       rsi_dbg(INIT_ZONE, "%s: num blocks: %d\n", __func__, num_blocks);
+-      status = rsi_copy_to_card(common, fw_entry->data, len, num_blocks);
++      status = rsi_copy_to_card(common, fw, len, num_blocks);
++      kfree(fw);
+       release_firmware(fw_entry);
+       return status;
+ }
+--- a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c
++++ b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c
+@@ -146,7 +146,10 @@ static int rsi_load_ta_instructions(stru
+               return status;
+       }
++      /* Copy firmware into DMA-accessible memory */
+       fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);
++      if (!fw)
++              return -ENOMEM;
+       len = fw_entry->size;
+       if (len % 4)
+@@ -158,6 +161,7 @@ static int rsi_load_ta_instructions(stru
+       rsi_dbg(INIT_ZONE, "%s: num blocks: %d\n", __func__, num_blocks);
+       status = rsi_copy_to_card(common, fw, len, num_blocks);
++      kfree(fw);
+       release_firmware(fw_entry);
+       return status;
+ }
diff --git a/queue-4.1/xen-blkback-replace-work_pending-with-work_busy-in-purge_persistent_gnt.patch b/queue-4.1/xen-blkback-replace-work_pending-with-work_busy-in-purge_persistent_gnt.patch
new file mode 100644 (file)
index 0000000..770bcb0
--- /dev/null
@@ -0,0 +1,40 @@
+From 53bc7dc004fecf39e0ba70f2f8d120a1444315d3 Mon Sep 17 00:00:00 2001
+From: Bob Liu <bob.liu@oracle.com>
+Date: Wed, 22 Jul 2015 14:40:10 +0800
+Subject: xen-blkback: replace work_pending with work_busy in purge_persistent_gnt()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Bob Liu <bob.liu@oracle.com>
+
+commit 53bc7dc004fecf39e0ba70f2f8d120a1444315d3 upstream.
+
+The BUG_ON() in purge_persistent_gnt() will be triggered when previous purge
+work haven't finished.
+
+There is a work_pending() before this BUG_ON, but it doesn't account if the work
+is still currently running.
+
+Acked-by: Roger Pau MonnĂ© <roger.pau@citrix.com>
+Signed-off-by: Bob Liu <bob.liu@oracle.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/block/xen-blkback/blkback.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/block/xen-blkback/blkback.c
++++ b/drivers/block/xen-blkback/blkback.c
+@@ -362,8 +362,8 @@ static void purge_persistent_gnt(struct
+               return;
+       }
+-      if (work_pending(&blkif->persistent_purge_work)) {
+-              pr_alert_ratelimited("Scheduled work from previous purge is still pending, cannot purge list\n");
++      if (work_busy(&blkif->persistent_purge_work)) {
++              pr_alert_ratelimited("Scheduled work from previous purge is still busy, cannot purge list\n");
+               return;
+       }
diff --git a/queue-4.1/xen-blkfront-don-t-add-indirect-pages-to-list-when.patch b/queue-4.1/xen-blkfront-don-t-add-indirect-pages-to-list-when.patch
new file mode 100644 (file)
index 0000000..aeb4f07
--- /dev/null
@@ -0,0 +1,44 @@
+From 7b0767502b5db11cb1f0daef2d01f6d71b1192dc Mon Sep 17 00:00:00 2001
+From: Bob Liu <bob.liu@oracle.com>
+Date: Wed, 22 Jul 2015 14:40:09 +0800
+Subject: xen-blkfront: don't add indirect pages to list when
+ !feature_persistent
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Bob Liu <bob.liu@oracle.com>
+
+commit 7b0767502b5db11cb1f0daef2d01f6d71b1192dc upstream.
+
+We should consider info->feature_persistent when adding indirect page to list
+info->indirect_pages, else the BUG_ON() in blkif_free() would be triggered.
+
+When we are using persistent grants the indirect_pages list
+should always be empty because blkfront has pre-allocated enough
+persistent pages to fill all requests on the ring.
+
+Acked-by: Roger Pau MonnĂ© <roger.pau@citrix.com>
+Signed-off-by: Bob Liu <bob.liu@oracle.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/block/xen-blkfront.c |    6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/drivers/block/xen-blkfront.c
++++ b/drivers/block/xen-blkfront.c
+@@ -1118,8 +1118,10 @@ static void blkif_completion(struct blk_
+                                * Add the used indirect page back to the list of
+                                * available pages for indirect grefs.
+                                */
+-                              indirect_page = pfn_to_page(s->indirect_grants[i]->pfn);
+-                              list_add(&indirect_page->lru, &info->indirect_pages);
++                              if (!info->feature_persistent) {
++                                      indirect_page = pfn_to_page(s->indirect_grants[i]->pfn);
++                                      list_add(&indirect_page->lru, &info->indirect_pages);
++                              }
+                               s->indirect_grants[i]->gref = GRANT_INVALID_REF;
+                               list_add_tail(&s->indirect_grants[i]->node, &info->grants);
+                       }