]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 7 Mar 2021 14:14:51 +0000 (15:14 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 7 Mar 2021 14:14:51 +0000 (15:14 +0100)
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

queue-4.14/btrfs-fix-raid6-qstripe-kmap.patch [new file with mode: 0644]
queue-4.14/btrfs-raid56-simplify-tracking-of-q-stripe-presence.patch [new file with mode: 0644]
queue-4.14/pm-runtime-update-device-status-before-letting-suppliers-suspend.patch [new file with mode: 0644]

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 (file)
index 0000000..1dd00c8
--- /dev/null
@@ -0,0 +1,94 @@
+From d70cef0d46729808dc53f145372c02b145c92604 Mon Sep 17 00:00:00 2001
+From: Ira Weiny <ira.weiny@intel.com>
+Date: Wed, 27 Jan 2021 22:15:03 -0800
+Subject: btrfs: fix raid6 qstripe kmap
+
+From: Ira Weiny <ira.weiny@intel.com>
+
+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 <ira.weiny@intel.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..0984313
--- /dev/null
@@ -0,0 +1,126 @@
+From c17af96554a8a8777cbb0fd53b8497250e548b43 Mon Sep 17 00:00:00 2001
+From: David Sterba <dsterba@suse.com>
+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 <dsterba@suse.com>
+
+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 <johannes.thumshirn@wdc.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..b56774c
--- /dev/null
@@ -0,0 +1,122 @@
+From 44cc89f764646b2f1f2ea5d1a08b230131707851 Mon Sep 17 00:00:00 2001
+From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
+Date: Thu, 25 Feb 2021 19:23:27 +0100
+Subject: PM: runtime: Update device status before letting suppliers suspend
+
+From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+
+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 <zhangqing@rock-chips.com>
+Diagnosed-by: Ulf Hansson <ulf.hansson@linaro.org>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Tested-by: Elaine Zhang <zhangiqng@rock-chips.com>
+Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
+Cc: 4.10+ <stable@vger.kernel.org> # 4.10+
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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);
+       }