From: Greg Kroah-Hartman Date: Sun, 7 Mar 2021 14:14:51 +0000 (+0100) Subject: 4.14-stable patches X-Git-Tag: v5.4.104~28 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4ac0745eb7cb5adbafeb7210b1e6d131b95380d6;p=thirdparty%2Fkernel%2Fstable-queue.git 4.14-stable patches added patches: btrfs-fix-raid6-qstripe-kmap.patch btrfs-raid56-simplify-tracking-of-q-stripe-presence.patch pm-runtime-update-device-status-before-letting-suppliers-suspend.patch --- diff --git a/queue-4.14/btrfs-fix-raid6-qstripe-kmap.patch b/queue-4.14/btrfs-fix-raid6-qstripe-kmap.patch new file mode 100644 index 00000000000..1dd00c82ef0 --- /dev/null +++ b/queue-4.14/btrfs-fix-raid6-qstripe-kmap.patch @@ -0,0 +1,94 @@ +From d70cef0d46729808dc53f145372c02b145c92604 Mon Sep 17 00:00:00 2001 +From: Ira Weiny +Date: Wed, 27 Jan 2021 22:15:03 -0800 +Subject: btrfs: fix raid6 qstripe kmap + +From: Ira Weiny + +commit d70cef0d46729808dc53f145372c02b145c92604 upstream. + +When a qstripe is required an extra page is allocated and mapped. There +were 3 problems: + +1) There is no corresponding call of kunmap() for the qstripe page. +2) There is no reason to map the qstripe page more than once if the + number of bits set in rbio->dbitmap is greater than one. +3) There is no reason to map the parity page and unmap it each time + through the loop. + +The page memory can continue to be reused with a single mapping on each +iteration by raid6_call.gen_syndrome() without remapping. So map the +page for the duration of the loop. + +Similarly, improve the algorithm by mapping the parity page just 1 time. + +Fixes: 5a6ac9eacb49 ("Btrfs, raid56: support parity scrub on raid56") +CC: stable@vger.kernel.org # 4.4.x: c17af96554a8: btrfs: raid56: simplify tracking of Q stripe presence +CC: stable@vger.kernel.org # 4.4.x +Signed-off-by: Ira Weiny +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Greg Kroah-Hartman +--- + fs/btrfs/raid56.c | 21 ++++++++++----------- + 1 file changed, 10 insertions(+), 11 deletions(-) + +--- a/fs/btrfs/raid56.c ++++ b/fs/btrfs/raid56.c +@@ -2360,16 +2360,21 @@ static noinline void finish_parity_scrub + SetPageUptodate(p_page); + + if (has_qstripe) { ++ /* RAID6, allocate and map temp space for the Q stripe */ + q_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM); + if (!q_page) { + __free_page(p_page); + goto cleanup; + } + SetPageUptodate(q_page); ++ pointers[rbio->real_stripes - 1] = kmap(q_page); + } + + atomic_set(&rbio->error, 0); + ++ /* Map the parity stripe just once */ ++ pointers[nr_data] = kmap(p_page); ++ + for_each_set_bit(pagenr, rbio->dbitmap, rbio->stripe_npages) { + struct page *p; + void *parity; +@@ -2379,16 +2384,8 @@ static noinline void finish_parity_scrub + pointers[stripe] = kmap(p); + } + +- /* then add the parity stripe */ +- pointers[stripe++] = kmap(p_page); +- + if (has_qstripe) { +- /* +- * raid6, add the qstripe and call the +- * library function to fill in our p/q +- */ +- pointers[stripe++] = kmap(q_page); +- ++ /* RAID6, call the library function to fill in our P/Q */ + raid6_call.gen_syndrome(rbio->real_stripes, PAGE_SIZE, + pointers); + } else { +@@ -2409,12 +2406,14 @@ static noinline void finish_parity_scrub + + for (stripe = 0; stripe < nr_data; stripe++) + kunmap(page_in_rbio(rbio, stripe, pagenr, 0)); +- kunmap(p_page); + } + ++ kunmap(p_page); + __free_page(p_page); +- if (q_page) ++ if (q_page) { ++ kunmap(q_page); + __free_page(q_page); ++ } + + writeback: + /* diff --git a/queue-4.14/btrfs-raid56-simplify-tracking-of-q-stripe-presence.patch b/queue-4.14/btrfs-raid56-simplify-tracking-of-q-stripe-presence.patch new file mode 100644 index 00000000000..0984313deb0 --- /dev/null +++ b/queue-4.14/btrfs-raid56-simplify-tracking-of-q-stripe-presence.patch @@ -0,0 +1,126 @@ +From c17af96554a8a8777cbb0fd53b8497250e548b43 Mon Sep 17 00:00:00 2001 +From: David Sterba +Date: Wed, 19 Feb 2020 15:17:20 +0100 +Subject: btrfs: raid56: simplify tracking of Q stripe presence +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: David Sterba + +commit c17af96554a8a8777cbb0fd53b8497250e548b43 upstream. + +There are temporary variables tracking the index of P and Q stripes, but +none of them is really used as such, merely for determining if the Q +stripe is present. This leads to compiler warnings with +-Wunused-but-set-variable and has been reported several times. + +fs/btrfs/raid56.c: In function ‘finish_rmw’: +fs/btrfs/raid56.c:1199:6: warning: variable ‘p_stripe’ set but not used [-Wunused-but-set-variable] + 1199 | int p_stripe = -1; + | ^~~~~~~~ +fs/btrfs/raid56.c: In function ‘finish_parity_scrub’: +fs/btrfs/raid56.c:2356:6: warning: variable ‘p_stripe’ set but not used [-Wunused-but-set-variable] + 2356 | int p_stripe = -1; + | ^~~~~~~~ + +Replace the two variables with one that has a clear meaning and also get +rid of the warnings. The logic that verifies that there are only 2 +valid cases is unchanged. + +Reviewed-by: Johannes Thumshirn +Signed-off-by: David Sterba +Signed-off-by: Greg Kroah-Hartman +--- + fs/btrfs/raid56.c | 37 +++++++++++++++---------------------- + 1 file changed, 15 insertions(+), 22 deletions(-) + +--- a/fs/btrfs/raid56.c ++++ b/fs/btrfs/raid56.c +@@ -1190,22 +1190,19 @@ static noinline void finish_rmw(struct b + int nr_data = rbio->nr_data; + int stripe; + int pagenr; +- int p_stripe = -1; +- int q_stripe = -1; ++ bool has_qstripe; + struct bio_list bio_list; + struct bio *bio; + int ret; + + bio_list_init(&bio_list); + +- if (rbio->real_stripes - rbio->nr_data == 1) { +- p_stripe = rbio->real_stripes - 1; +- } else if (rbio->real_stripes - rbio->nr_data == 2) { +- p_stripe = rbio->real_stripes - 2; +- q_stripe = rbio->real_stripes - 1; +- } else { ++ if (rbio->real_stripes - rbio->nr_data == 1) ++ has_qstripe = false; ++ else if (rbio->real_stripes - rbio->nr_data == 2) ++ has_qstripe = true; ++ else + BUG(); +- } + + /* at this point we either have a full stripe, + * or we've read the full stripe from the drive. +@@ -1249,7 +1246,7 @@ static noinline void finish_rmw(struct b + SetPageUptodate(p); + pointers[stripe++] = kmap(p); + +- if (q_stripe != -1) { ++ if (has_qstripe) { + + /* + * raid6, add the qstripe and call the +@@ -2325,8 +2322,7 @@ static noinline void finish_parity_scrub + int nr_data = rbio->nr_data; + int stripe; + int pagenr; +- int p_stripe = -1; +- int q_stripe = -1; ++ bool has_qstripe; + struct page *p_page = NULL; + struct page *q_page = NULL; + struct bio_list bio_list; +@@ -2336,14 +2332,12 @@ static noinline void finish_parity_scrub + + bio_list_init(&bio_list); + +- if (rbio->real_stripes - rbio->nr_data == 1) { +- p_stripe = rbio->real_stripes - 1; +- } else if (rbio->real_stripes - rbio->nr_data == 2) { +- p_stripe = rbio->real_stripes - 2; +- q_stripe = rbio->real_stripes - 1; +- } else { ++ if (rbio->real_stripes - rbio->nr_data == 1) ++ has_qstripe = false; ++ else if (rbio->real_stripes - rbio->nr_data == 2) ++ has_qstripe = true; ++ else + BUG(); +- } + + if (bbio->num_tgtdevs && bbio->tgtdev_map[rbio->scrubp]) { + is_replace = 1; +@@ -2365,7 +2359,7 @@ static noinline void finish_parity_scrub + goto cleanup; + SetPageUptodate(p_page); + +- if (q_stripe != -1) { ++ if (has_qstripe) { + q_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM); + if (!q_page) { + __free_page(p_page); +@@ -2388,8 +2382,7 @@ static noinline void finish_parity_scrub + /* then add the parity stripe */ + pointers[stripe++] = kmap(p_page); + +- if (q_stripe != -1) { +- ++ if (has_qstripe) { + /* + * raid6, add the qstripe and call the + * library function to fill in our p/q diff --git a/queue-4.14/pm-runtime-update-device-status-before-letting-suppliers-suspend.patch b/queue-4.14/pm-runtime-update-device-status-before-letting-suppliers-suspend.patch new file mode 100644 index 00000000000..b56774c10f3 --- /dev/null +++ b/queue-4.14/pm-runtime-update-device-status-before-letting-suppliers-suspend.patch @@ -0,0 +1,122 @@ +From 44cc89f764646b2f1f2ea5d1a08b230131707851 Mon Sep 17 00:00:00 2001 +From: "Rafael J. Wysocki" +Date: Thu, 25 Feb 2021 19:23:27 +0100 +Subject: PM: runtime: Update device status before letting suppliers suspend + +From: Rafael J. Wysocki + +commit 44cc89f764646b2f1f2ea5d1a08b230131707851 upstream. + +Because the PM-runtime status of the device is not updated in +__rpm_callback(), attempts to suspend the suppliers of the given +device triggered by rpm_put_suppliers() called by it may fail. + +Fix this by making __rpm_callback() update the device's status to +RPM_SUSPENDED before calling rpm_put_suppliers() if the current +status of the device is RPM_SUSPENDING and the callback just invoked +by it has returned 0 (success). + +While at it, modify the code in __rpm_callback() to always check +the device's PM-runtime status under its PM lock. + +Link: https://lore.kernel.org/linux-pm/CAPDyKFqm06KDw_p8WXsM4dijDbho4bb6T4k50UqqvR1_COsp8g@mail.gmail.com/ +Fixes: 21d5c57b3726 ("PM / runtime: Use device links") +Reported-by: Elaine Zhang +Diagnosed-by: Ulf Hansson +Signed-off-by: Rafael J. Wysocki +Tested-by: Elaine Zhang +Reviewed-by: Ulf Hansson +Cc: 4.10+ # 4.10+ +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Greg Kroah-Hartman +--- + drivers/base/power/runtime.c | 62 +++++++++++++++++++++++++------------------ + 1 file changed, 37 insertions(+), 25 deletions(-) + +--- a/drivers/base/power/runtime.c ++++ b/drivers/base/power/runtime.c +@@ -306,22 +306,22 @@ static void rpm_put_suppliers(struct dev + static int __rpm_callback(int (*cb)(struct device *), struct device *dev) + __releases(&dev->power.lock) __acquires(&dev->power.lock) + { +- int retval, idx; + bool use_links = dev->power.links_count > 0; ++ bool get = false; ++ int retval, idx; ++ bool put; + + if (dev->power.irq_safe) { + spin_unlock(&dev->power.lock); ++ } else if (!use_links) { ++ spin_unlock_irq(&dev->power.lock); + } else { ++ get = dev->power.runtime_status == RPM_RESUMING; ++ + spin_unlock_irq(&dev->power.lock); + +- /* +- * Resume suppliers if necessary. +- * +- * The device's runtime PM status cannot change until this +- * routine returns, so it is safe to read the status outside of +- * the lock. +- */ +- if (use_links && dev->power.runtime_status == RPM_RESUMING) { ++ /* Resume suppliers if necessary. */ ++ if (get) { + idx = device_links_read_lock(); + + retval = rpm_get_suppliers(dev); +@@ -336,24 +336,36 @@ static int __rpm_callback(int (*cb)(stru + + if (dev->power.irq_safe) { + spin_lock(&dev->power.lock); +- } else { +- /* +- * If the device is suspending and the callback has returned +- * success, drop the usage counters of the suppliers that have +- * been reference counted on its resume. +- * +- * Do that if resume fails too. +- */ +- if (use_links +- && ((dev->power.runtime_status == RPM_SUSPENDING && !retval) +- || (dev->power.runtime_status == RPM_RESUMING && retval))) { +- idx = device_links_read_lock(); ++ return retval; ++ } + +- fail: +- rpm_put_suppliers(dev); ++ spin_lock_irq(&dev->power.lock); + +- device_links_read_unlock(idx); +- } ++ if (!use_links) ++ return retval; ++ ++ /* ++ * If the device is suspending and the callback has returned success, ++ * drop the usage counters of the suppliers that have been reference ++ * counted on its resume. ++ * ++ * Do that if the resume fails too. ++ */ ++ put = dev->power.runtime_status == RPM_SUSPENDING && !retval; ++ if (put) ++ __update_runtime_status(dev, RPM_SUSPENDED); ++ else ++ put = get && retval; ++ ++ if (put) { ++ spin_unlock_irq(&dev->power.lock); ++ ++ idx = device_links_read_lock(); ++ ++fail: ++ rpm_put_suppliers(dev); ++ ++ device_links_read_unlock(idx); + + spin_lock_irq(&dev->power.lock); + }