From: Greg Kroah-Hartman Date: Tue, 24 Jul 2012 20:31:48 +0000 (-0700) Subject: 3.0-stable patches X-Git-Tag: v3.4.7~15 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1f288d69e6ea2452f72cceff9cd57502d9358414;p=thirdparty%2Fkernel%2Fstable-queue.git 3.0-stable patches 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 --- 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 index 00000000000..8e490d31bd3 --- /dev/null +++ b/queue-3.0/dm-raid1-fix-crash-with-mirror-recovery-and-discard.patch @@ -0,0 +1,110 @@ +From 751f188dd5ab95b3f2b5f2f467c38aae5a2877eb Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Fri, 20 Jul 2012 14:25:03 +0100 +Subject: dm raid1: fix crash with mirror recovery and discard + +From: Mikulas Patocka + +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 +Signed-off-by: Alasdair G Kergon +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..17cb1384adf --- /dev/null +++ b/queue-3.0/mips-properly-align-the-.data..init_task-section.patch @@ -0,0 +1,66 @@ +From 7b1c0d26a8e272787f0f9fcc5f3e8531df3b3409 Mon Sep 17 00:00:00 2001 +From: David Daney +Date: Thu, 19 Jul 2012 09:11:14 +0200 +Subject: MIPS: Properly align the .data..init_task section. + +From: David Daney + +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 +Cc: linux-mips@linux-mips.org +Patchwork: https://patchwork.linux-mips.org/patch/3881/ +Signed-off-by: Ralf Baechle +Signed-off-by: Greg Kroah-Hartman + +--- + 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 + #include ++#include + #include + + #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) diff --git a/queue-3.0/series b/queue-3.0/series index bf76a2ef4ef..a143a4ae634 100644 --- a/queue-3.0/series +++ b/queue-3.0/series @@ -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 index 00000000000..68a27488c66 --- /dev/null +++ b/queue-3.0/ubifs-fix-a-bug-in-empty-space-fix-up.patch @@ -0,0 +1,65 @@ +From c6727932cfdb13501108b16c38463c09d5ec7a74 Mon Sep 17 00:00:00 2001 +From: Artem Bityutskiy +Date: Sat, 14 Jul 2012 14:33:09 +0300 +Subject: UBIFS: fix a bug in empty space fix-up + +From: Artem Bityutskiy + +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 +Reported-by: Iwo Mergler +Tested-by: Iwo Mergler +Reported-by: James Nute +Signed-off-by: Greg Kroah-Hartman + +--- + 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; +