]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.0-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 24 Jul 2012 20:31:48 +0000 (13:31 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 24 Jul 2012 20:31:48 +0000 (13:31 -0700)
added patches:
dm-raid1-fix-crash-with-mirror-recovery-and-discard.patch
mips-properly-align-the-.data..init_task-section.patch
ubifs-fix-a-bug-in-empty-space-fix-up.patch

queue-3.0/dm-raid1-fix-crash-with-mirror-recovery-and-discard.patch [new file with mode: 0644]
queue-3.0/mips-properly-align-the-.data..init_task-section.patch [new file with mode: 0644]
queue-3.0/series
queue-3.0/ubifs-fix-a-bug-in-empty-space-fix-up.patch [new file with mode: 0644]

diff --git a/queue-3.0/dm-raid1-fix-crash-with-mirror-recovery-and-discard.patch b/queue-3.0/dm-raid1-fix-crash-with-mirror-recovery-and-discard.patch
new file mode 100644 (file)
index 0000000..8e490d3
--- /dev/null
@@ -0,0 +1,110 @@
+From 751f188dd5ab95b3f2b5f2f467c38aae5a2877eb Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Fri, 20 Jul 2012 14:25:03 +0100
+Subject: dm raid1: fix crash with mirror recovery and discard
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+commit 751f188dd5ab95b3f2b5f2f467c38aae5a2877eb upstream.
+
+This patch fixes a crash when a discard request is sent during mirror
+recovery.
+
+Firstly, some background.  Generally, the following sequence happens during
+mirror synchronization:
+- function do_recovery is called
+- do_recovery calls dm_rh_recovery_prepare
+- dm_rh_recovery_prepare uses a semaphore to limit the number
+  simultaneously recovered regions (by default the semaphore value is 1,
+  so only one region at a time is recovered)
+- dm_rh_recovery_prepare calls __rh_recovery_prepare,
+  __rh_recovery_prepare asks the log driver for the next region to
+  recover. Then, it sets the region state to DM_RH_RECOVERING. If there
+  are no pending I/Os on this region, the region is added to
+  quiesced_regions list. If there are pending I/Os, the region is not
+  added to any list. It is added to the quiesced_regions list later (by
+  dm_rh_dec function) when all I/Os finish.
+- when the region is on quiesced_regions list, there are no I/Os in
+  flight on this region. The region is popped from the list in
+  dm_rh_recovery_start function. Then, a kcopyd job is started in the
+  recover function.
+- when the kcopyd job finishes, recovery_complete is called. It calls
+  dm_rh_recovery_end. dm_rh_recovery_end adds the region to
+  recovered_regions or failed_recovered_regions list (depending on
+  whether the copy operation was successful or not).
+
+The above mechanism assumes that if the region is in DM_RH_RECOVERING
+state, no new I/Os are started on this region. When I/O is started,
+dm_rh_inc_pending is called, which increases reg->pending count. When
+I/O is finished, dm_rh_dec is called. It decreases reg->pending count.
+If the count is zero and the region was in DM_RH_RECOVERING state,
+dm_rh_dec adds it to the quiesced_regions list.
+
+Consequently, if we call dm_rh_inc_pending/dm_rh_dec while the region is
+in DM_RH_RECOVERING state, it could be added to quiesced_regions list
+multiple times or it could be added to this list when kcopyd is copying
+data (it is assumed that the region is not on any list while kcopyd does
+its jobs). This results in memory corruption and crash.
+
+There already exist bypasses for REQ_FLUSH requests: REQ_FLUSH requests
+do not belong to any region, so they are always added to the sync list
+in do_writes. dm_rh_inc_pending does not increase count for REQ_FLUSH
+requests. In mirror_end_io, dm_rh_dec is never called for REQ_FLUSH
+requests. These bypasses avoid the crash possibility described above.
+
+These bypasses were improperly implemented for REQ_DISCARD when
+the mirror target gained discard support in commit
+5fc2ffeabb9ee0fc0e71ff16b49f34f0ed3d05b4 (dm raid1: support discard).
+
+In do_writes, REQ_DISCARD requests is always added to the sync queue and
+immediately dispatched (even if the region is in DM_RH_RECOVERING).  However,
+dm_rh_inc and dm_rh_dec is called for REQ_DISCARD resusts.  So it violates the
+rule that no I/Os are started on DM_RH_RECOVERING regions, and causes the list
+corruption described above.
+
+This patch changes it so that REQ_DISCARD requests follow the same path
+as REQ_FLUSH. This avoids the crash.
+
+Reference: https://bugzilla.redhat.com/837607
+
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Alasdair G Kergon <agk@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/md/dm-raid1.c       |    2 +-
+ drivers/md/dm-region-hash.c |    5 ++++-
+ 2 files changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/md/dm-raid1.c
++++ b/drivers/md/dm-raid1.c
+@@ -1210,7 +1210,7 @@ static int mirror_end_io(struct dm_targe
+        * We need to dec pending if this was a write.
+        */
+       if (rw == WRITE) {
+-              if (!(bio->bi_rw & REQ_FLUSH))
++              if (!(bio->bi_rw & (REQ_FLUSH | REQ_DISCARD)))
+                       dm_rh_dec(ms->rh, map_context->ll);
+               return error;
+       }
+--- a/drivers/md/dm-region-hash.c
++++ b/drivers/md/dm-region-hash.c
+@@ -404,6 +404,9 @@ void dm_rh_mark_nosync(struct dm_region_
+               return;
+       }
++      if (bio->bi_rw & REQ_DISCARD)
++              return;
++
+       /* We must inform the log that the sync count has changed. */
+       log->type->set_region_sync(log, region, 0);
+@@ -524,7 +527,7 @@ void dm_rh_inc_pending(struct dm_region_
+       struct bio *bio;
+       for (bio = bios->head; bio; bio = bio->bi_next) {
+-              if (bio->bi_rw & REQ_FLUSH)
++              if (bio->bi_rw & (REQ_FLUSH | REQ_DISCARD))
+                       continue;
+               rh_inc(rh, dm_rh_bio_to_region(rh, bio));
+       }
diff --git a/queue-3.0/mips-properly-align-the-.data..init_task-section.patch b/queue-3.0/mips-properly-align-the-.data..init_task-section.patch
new file mode 100644 (file)
index 0000000..17cb138
--- /dev/null
@@ -0,0 +1,66 @@
+From 7b1c0d26a8e272787f0f9fcc5f3e8531df3b3409 Mon Sep 17 00:00:00 2001
+From: David Daney <david.daney@cavium.com>
+Date: Thu, 19 Jul 2012 09:11:14 +0200
+Subject: MIPS: Properly align the .data..init_task section.
+
+From: David Daney <david.daney@cavium.com>
+
+commit 7b1c0d26a8e272787f0f9fcc5f3e8531df3b3409 upstream.
+
+Improper alignment can lead to unbootable systems and/or random
+crashes.
+
+[ralf@linux-mips.org: This is a lond standing bug since
+6eb10bc9e2deab06630261cd05c4cb1e9a60e980 (kernel.org) rsp.
+c422a10917f75fd19fa7fe070aaaa23e384dae6f (lmo) [MIPS: Clean up linker script
+using new linker script macros.] so dates back to 2.6.32.]
+
+Signed-off-by: David Daney <david.daney@cavium.com>
+Cc: linux-mips@linux-mips.org
+Patchwork: https://patchwork.linux-mips.org/patch/3881/
+Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/mips/include/asm/thread_info.h |    4 ++--
+ arch/mips/kernel/vmlinux.lds.S      |    3 ++-
+ 2 files changed, 4 insertions(+), 3 deletions(-)
+
+--- a/arch/mips/include/asm/thread_info.h
++++ b/arch/mips/include/asm/thread_info.h
+@@ -60,6 +60,8 @@ struct thread_info {
+ register struct thread_info *__current_thread_info __asm__("$28");
+ #define current_thread_info()  __current_thread_info
++#endif /* !__ASSEMBLY__ */
++
+ /* thread information allocation */
+ #if defined(CONFIG_PAGE_SIZE_4KB) && defined(CONFIG_32BIT)
+ #define THREAD_SIZE_ORDER (1)
+@@ -97,8 +99,6 @@ register struct thread_info *__current_t
+ #define free_thread_info(info) kfree(info)
+-#endif /* !__ASSEMBLY__ */
+-
+ #define PREEMPT_ACTIVE                0x10000000
+ /*
+--- a/arch/mips/kernel/vmlinux.lds.S
++++ b/arch/mips/kernel/vmlinux.lds.S
+@@ -1,5 +1,6 @@
+ #include <asm/asm-offsets.h>
+ #include <asm/page.h>
++#include <asm/thread_info.h>
+ #include <asm-generic/vmlinux.lds.h>
+ #undef mips
+@@ -73,7 +74,7 @@ SECTIONS
+       .data : {       /* Data */
+               . = . + DATAOFFSET;             /* for CONFIG_MAPPED_KERNEL */
+-              INIT_TASK_DATA(PAGE_SIZE)
++              INIT_TASK_DATA(THREAD_SIZE)
+               NOSAVE_DATA
+               CACHELINE_ALIGNED_DATA(1 << CONFIG_MIPS_L1_CACHE_SHIFT)
+               READ_MOSTLY_DATA(1 << CONFIG_MIPS_L1_CACHE_SHIFT)
index bf76a2ef4ef97b47c645638d72c4970d2362ef24..a143a4ae63461d8672490fceb4b3126afe81f624 100644 (file)
@@ -1,3 +1,6 @@
 cifs-always-update-the-inode-cache-with-the-results-from-a-find_.patch
 ntp-fix-sta_ins-del-clearing-bug.patch
 mm-fix-lost-kswapd-wakeup-in-kswapd_stop.patch
+mips-properly-align-the-.data..init_task-section.patch
+ubifs-fix-a-bug-in-empty-space-fix-up.patch
+dm-raid1-fix-crash-with-mirror-recovery-and-discard.patch
diff --git a/queue-3.0/ubifs-fix-a-bug-in-empty-space-fix-up.patch b/queue-3.0/ubifs-fix-a-bug-in-empty-space-fix-up.patch
new file mode 100644 (file)
index 0000000..68a2748
--- /dev/null
@@ -0,0 +1,65 @@
+From c6727932cfdb13501108b16c38463c09d5ec7a74 Mon Sep 17 00:00:00 2001
+From: Artem Bityutskiy <Artem.Bityutskiy@linux.intel.com>
+Date: Sat, 14 Jul 2012 14:33:09 +0300
+Subject: UBIFS: fix a bug in empty space fix-up
+
+From: Artem Bityutskiy <Artem.Bityutskiy@linux.intel.com>
+
+commit c6727932cfdb13501108b16c38463c09d5ec7a74 upstream.
+
+UBIFS has a feature called "empty space fix-up" which is a quirk to work-around
+limitations of dumb flasher programs. Namely, of those flashers that are unable
+to skip NAND pages full of 0xFFs while flashing, resulting in empty space at
+the end of half-filled eraseblocks to be unusable for UBIFS. This feature is
+relatively new (introduced in v3.0).
+
+The fix-up routine (fixup_free_space()) is executed only once at the very first
+mount if the superblock has the 'space_fixup' flag set (can be done with -F
+option of mkfs.ubifs). It basically reads all the UBIFS data and metadata and
+writes it back to the same LEB. The routine assumes the image is pristine and
+does not have anything in the journal.
+
+There was a bug in 'fixup_free_space()' where it fixed up the log incorrectly.
+All but one LEB of the log of a pristine file-system are empty. And one
+contains just a commit start node. And 'fixup_free_space()' just unmapped this
+LEB, which resulted in wiping the commit start node. As a result, some users
+were unable to mount the file-system next time with the following symptom:
+
+UBIFS error (pid 1): replay_log_leb: first log node at LEB 3:0 is not CS node
+UBIFS error (pid 1): replay_log_leb: log error detected while replaying the log at LEB 3:0
+
+The root-cause of this bug was that 'fixup_free_space()' wrongly assumed
+that the beginning of empty space in the log head (c->lhead_offs) was known
+on mount. However, it is not the case - it was always 0. UBIFS does not store
+in it the master node and finds out by scanning the log on every mount.
+
+The fix is simple - just pass commit start node size instead of 0 to
+'fixup_leb()'.
+
+Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@linux.intel.com>
+Reported-by: Iwo Mergler <Iwo.Mergler@netcommwireless.com>
+Tested-by: Iwo Mergler <Iwo.Mergler@netcommwireless.com>
+Reported-by: James Nute <newten82@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/ubifs/sb.c |    8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+--- a/fs/ubifs/sb.c
++++ b/fs/ubifs/sb.c
+@@ -715,8 +715,12 @@ static int fixup_free_space(struct ubifs
+               lnum = ubifs_next_log_lnum(c, lnum);
+       }
+-      /* Fixup the current log head */
+-      err = fixup_leb(c, c->lhead_lnum, c->lhead_offs);
++      /*
++       * Fixup the log head which contains the only a CS node at the
++       * beginning.
++       */
++      err = fixup_leb(c, c->lhead_lnum,
++                      ALIGN(UBIFS_CS_NODE_SZ, c->min_io_size));
+       if (err)
+               goto out;