]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.15-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 1 Aug 2023 06:27:47 +0000 (08:27 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 1 Aug 2023 06:27:47 +0000 (08:27 +0200)
added patches:
ceph-never-send-metrics-if-disable_send_metrics-is-set.patch
dm-cache-policy-smq-ensure-io-doesn-t-prevent-cleaner-policy-progress.patch
rbd-harden-get_lock_owner_info-a-bit.patch
rbd-make-get_lock_owner_info-return-a-single-locker-or-null.patch
rbd-retrieve-and-check-lock-owner-twice-before-blocklisting.patch

queue-5.15/ceph-never-send-metrics-if-disable_send_metrics-is-set.patch [new file with mode: 0644]
queue-5.15/dm-cache-policy-smq-ensure-io-doesn-t-prevent-cleaner-policy-progress.patch [new file with mode: 0644]
queue-5.15/rbd-harden-get_lock_owner_info-a-bit.patch [new file with mode: 0644]
queue-5.15/rbd-make-get_lock_owner_info-return-a-single-locker-or-null.patch [new file with mode: 0644]
queue-5.15/rbd-retrieve-and-check-lock-owner-twice-before-blocklisting.patch [new file with mode: 0644]
queue-5.15/series

diff --git a/queue-5.15/ceph-never-send-metrics-if-disable_send_metrics-is-set.patch b/queue-5.15/ceph-never-send-metrics-if-disable_send_metrics-is-set.patch
new file mode 100644 (file)
index 0000000..c5dc90c
--- /dev/null
@@ -0,0 +1,34 @@
+From 50164507f6b7b7ed85d8c3ac0266849fbd908db7 Mon Sep 17 00:00:00 2001
+From: Xiubo Li <xiubli@redhat.com>
+Date: Thu, 20 Jul 2023 11:33:55 +0800
+Subject: ceph: never send metrics if disable_send_metrics is set
+
+From: Xiubo Li <xiubli@redhat.com>
+
+commit 50164507f6b7b7ed85d8c3ac0266849fbd908db7 upstream.
+
+Even the 'disable_send_metrics' is true so when the session is
+being opened it will always trigger to send the metric for the
+first time.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Xiubo Li <xiubli@redhat.com>
+Reviewed-by: Venky Shankar <vshankar@redhat.com>
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ceph/metric.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/fs/ceph/metric.c
++++ b/fs/ceph/metric.c
+@@ -202,7 +202,7 @@ static void metric_delayed_work(struct w
+       struct ceph_mds_client *mdsc =
+               container_of(m, struct ceph_mds_client, metric);
+-      if (mdsc->stopping)
++      if (mdsc->stopping || disable_send_metrics)
+               return;
+       if (!m->session || !check_session_state(m->session)) {
diff --git a/queue-5.15/dm-cache-policy-smq-ensure-io-doesn-t-prevent-cleaner-policy-progress.patch b/queue-5.15/dm-cache-policy-smq-ensure-io-doesn-t-prevent-cleaner-policy-progress.patch
new file mode 100644 (file)
index 0000000..702c16f
--- /dev/null
@@ -0,0 +1,106 @@
+From 1e4ab7b4c881cf26c1c72b3f56519e03475486fb Mon Sep 17 00:00:00 2001
+From: Joe Thornber <ejt@redhat.com>
+Date: Tue, 25 Jul 2023 11:44:41 -0400
+Subject: dm cache policy smq: ensure IO doesn't prevent cleaner policy progress
+
+From: Joe Thornber <ejt@redhat.com>
+
+commit 1e4ab7b4c881cf26c1c72b3f56519e03475486fb upstream.
+
+When using the cleaner policy to decommission the cache, there is
+never any writeback started from the cache as it is constantly delayed
+due to normal I/O keeping the device busy. Meaning @idle=false was
+always being passed to clean_target_met()
+
+Fix this by adding a specific 'cleaner' flag that is set when the
+cleaner policy is configured. This flag serves to always allow the
+cleaner's writeback work to be queued until the cache is
+decommissioned (even if the cache isn't idle).
+
+Reported-by: David Jeffery <djeffery@redhat.com>
+Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2")
+Cc: stable@vger.kernel.org
+Signed-off-by: Joe Thornber <ejt@redhat.com>
+Signed-off-by: Mike Snitzer <snitzer@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/md/dm-cache-policy-smq.c |   28 ++++++++++++++++++----------
+ 1 file changed, 18 insertions(+), 10 deletions(-)
+
+--- a/drivers/md/dm-cache-policy-smq.c
++++ b/drivers/md/dm-cache-policy-smq.c
+@@ -854,7 +854,13 @@ struct smq_policy {
+       struct background_tracker *bg_work;
+-      bool migrations_allowed;
++      bool migrations_allowed:1;
++
++      /*
++       * If this is set the policy will try and clean the whole cache
++       * even if the device is not idle.
++       */
++      bool cleaner:1;
+ };
+ /*----------------------------------------------------------------*/
+@@ -1133,7 +1139,7 @@ static bool clean_target_met(struct smq_
+        * Cache entries may not be populated.  So we cannot rely on the
+        * size of the clean queue.
+        */
+-      if (idle) {
++      if (idle || mq->cleaner) {
+               /*
+                * We'd like to clean everything.
+                */
+@@ -1716,11 +1722,9 @@ static void calc_hotspot_params(sector_t
+               *hotspot_block_size /= 2u;
+ }
+-static struct dm_cache_policy *__smq_create(dm_cblock_t cache_size,
+-                                          sector_t origin_size,
+-                                          sector_t cache_block_size,
+-                                          bool mimic_mq,
+-                                          bool migrations_allowed)
++static struct dm_cache_policy *
++__smq_create(dm_cblock_t cache_size, sector_t origin_size, sector_t cache_block_size,
++           bool mimic_mq, bool migrations_allowed, bool cleaner)
+ {
+       unsigned i;
+       unsigned nr_sentinels_per_queue = 2u * NR_CACHE_LEVELS;
+@@ -1807,6 +1811,7 @@ static struct dm_cache_policy *__smq_cre
+               goto bad_btracker;
+       mq->migrations_allowed = migrations_allowed;
++      mq->cleaner = cleaner;
+       return &mq->policy;
+@@ -1830,21 +1835,24 @@ static struct dm_cache_policy *smq_creat
+                                         sector_t origin_size,
+                                         sector_t cache_block_size)
+ {
+-      return __smq_create(cache_size, origin_size, cache_block_size, false, true);
++      return __smq_create(cache_size, origin_size, cache_block_size,
++                          false, true, false);
+ }
+ static struct dm_cache_policy *mq_create(dm_cblock_t cache_size,
+                                        sector_t origin_size,
+                                        sector_t cache_block_size)
+ {
+-      return __smq_create(cache_size, origin_size, cache_block_size, true, true);
++      return __smq_create(cache_size, origin_size, cache_block_size,
++                          true, true, false);
+ }
+ static struct dm_cache_policy *cleaner_create(dm_cblock_t cache_size,
+                                             sector_t origin_size,
+                                             sector_t cache_block_size)
+ {
+-      return __smq_create(cache_size, origin_size, cache_block_size, false, false);
++      return __smq_create(cache_size, origin_size, cache_block_size,
++                          false, false, true);
+ }
+ /*----------------------------------------------------------------*/
diff --git a/queue-5.15/rbd-harden-get_lock_owner_info-a-bit.patch b/queue-5.15/rbd-harden-get_lock_owner_info-a-bit.patch
new file mode 100644 (file)
index 0000000..b361571
--- /dev/null
@@ -0,0 +1,79 @@
+From 8ff2c64c9765446c3cef804fb99da04916603e27 Mon Sep 17 00:00:00 2001
+From: Ilya Dryomov <idryomov@gmail.com>
+Date: Sat, 8 Jul 2023 16:16:59 +0200
+Subject: rbd: harden get_lock_owner_info() a bit
+
+From: Ilya Dryomov <idryomov@gmail.com>
+
+commit 8ff2c64c9765446c3cef804fb99da04916603e27 upstream.
+
+- we want the exclusive lock type, so test for it directly
+- use sscanf() to actually parse the lock cookie and avoid admitting
+  invalid handles
+- bail if locker has a blank address
+
+Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
+Reviewed-by: Dongsheng Yang <dongsheng.yang@easystack.cn>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/block/rbd.c  |   21 +++++++++++++++------
+ net/ceph/messenger.c |    1 +
+ 2 files changed, 16 insertions(+), 6 deletions(-)
+
+--- a/drivers/block/rbd.c
++++ b/drivers/block/rbd.c
+@@ -3864,10 +3864,9 @@ static struct ceph_locker *get_lock_owne
+       u32 num_lockers;
+       u8 lock_type;
+       char *lock_tag;
++      u64 handle;
+       int ret;
+-      dout("%s rbd_dev %p\n", __func__, rbd_dev);
+-
+       ret = ceph_cls_lock_info(osdc, &rbd_dev->header_oid,
+                                &rbd_dev->header_oloc, RBD_LOCK_NAME,
+                                &lock_type, &lock_tag, &lockers, &num_lockers);
+@@ -3888,18 +3887,28 @@ static struct ceph_locker *get_lock_owne
+               goto err_busy;
+       }
+-      if (lock_type == CEPH_CLS_LOCK_SHARED) {
+-              rbd_warn(rbd_dev, "shared lock type detected");
++      if (lock_type != CEPH_CLS_LOCK_EXCLUSIVE) {
++              rbd_warn(rbd_dev, "incompatible lock type detected");
+               goto err_busy;
+       }
+       WARN_ON(num_lockers != 1);
+-      if (strncmp(lockers[0].id.cookie, RBD_LOCK_COOKIE_PREFIX,
+-                  strlen(RBD_LOCK_COOKIE_PREFIX))) {
++      ret = sscanf(lockers[0].id.cookie, RBD_LOCK_COOKIE_PREFIX " %llu",
++                   &handle);
++      if (ret != 1) {
+               rbd_warn(rbd_dev, "locked by external mechanism, cookie %s",
+                        lockers[0].id.cookie);
+               goto err_busy;
+       }
++      if (ceph_addr_is_blank(&lockers[0].info.addr)) {
++              rbd_warn(rbd_dev, "locker has a blank address");
++              goto err_busy;
++      }
++
++      dout("%s rbd_dev %p got locker %s%llu@%pISpc/%u handle %llu\n",
++           __func__, rbd_dev, ENTITY_NAME(lockers[0].id.name),
++           &lockers[0].info.addr.in_addr,
++           le32_to_cpu(lockers[0].info.addr.nonce), handle);
+ out:
+       kfree(lock_tag);
+--- a/net/ceph/messenger.c
++++ b/net/ceph/messenger.c
+@@ -1144,6 +1144,7 @@ bool ceph_addr_is_blank(const struct cep
+               return true;
+       }
+ }
++EXPORT_SYMBOL(ceph_addr_is_blank);
+ int ceph_addr_port(const struct ceph_entity_addr *addr)
+ {
diff --git a/queue-5.15/rbd-make-get_lock_owner_info-return-a-single-locker-or-null.patch b/queue-5.15/rbd-make-get_lock_owner_info-return-a-single-locker-or-null.patch
new file mode 100644 (file)
index 0000000..45767ed
--- /dev/null
@@ -0,0 +1,176 @@
+From f38cb9d9c2045dad16eead4a2e1aedfddd94603b Mon Sep 17 00:00:00 2001
+From: Ilya Dryomov <idryomov@gmail.com>
+Date: Fri, 30 Jun 2023 13:52:13 +0200
+Subject: rbd: make get_lock_owner_info() return a single locker or NULL
+
+From: Ilya Dryomov <idryomov@gmail.com>
+
+commit f38cb9d9c2045dad16eead4a2e1aedfddd94603b upstream.
+
+Make the "num_lockers can be only 0 or 1" assumption explicit and
+simplify the API by getting rid of output parameters in preparation
+for calling get_lock_owner_info() twice before blocklisting.
+
+Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
+Reviewed-by: Dongsheng Yang <dongsheng.yang@easystack.cn>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/block/rbd.c |   84 +++++++++++++++++++++++++++++++---------------------
+ 1 file changed, 51 insertions(+), 33 deletions(-)
+
+--- a/drivers/block/rbd.c
++++ b/drivers/block/rbd.c
+@@ -3851,10 +3851,17 @@ static void wake_lock_waiters(struct rbd
+       list_splice_tail_init(&rbd_dev->acquiring_list, &rbd_dev->running_list);
+ }
+-static int get_lock_owner_info(struct rbd_device *rbd_dev,
+-                             struct ceph_locker **lockers, u32 *num_lockers)
++static void free_locker(struct ceph_locker *locker)
++{
++      if (locker)
++              ceph_free_lockers(locker, 1);
++}
++
++static struct ceph_locker *get_lock_owner_info(struct rbd_device *rbd_dev)
+ {
+       struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
++      struct ceph_locker *lockers;
++      u32 num_lockers;
+       u8 lock_type;
+       char *lock_tag;
+       int ret;
+@@ -3863,39 +3870,45 @@ static int get_lock_owner_info(struct rb
+       ret = ceph_cls_lock_info(osdc, &rbd_dev->header_oid,
+                                &rbd_dev->header_oloc, RBD_LOCK_NAME,
+-                               &lock_type, &lock_tag, lockers, num_lockers);
+-      if (ret)
+-              return ret;
++                               &lock_type, &lock_tag, &lockers, &num_lockers);
++      if (ret) {
++              rbd_warn(rbd_dev, "failed to retrieve lockers: %d", ret);
++              return ERR_PTR(ret);
++      }
+-      if (*num_lockers == 0) {
++      if (num_lockers == 0) {
+               dout("%s rbd_dev %p no lockers detected\n", __func__, rbd_dev);
++              lockers = NULL;
+               goto out;
+       }
+       if (strcmp(lock_tag, RBD_LOCK_TAG)) {
+               rbd_warn(rbd_dev, "locked by external mechanism, tag %s",
+                        lock_tag);
+-              ret = -EBUSY;
+-              goto out;
++              goto err_busy;
+       }
+       if (lock_type == CEPH_CLS_LOCK_SHARED) {
+               rbd_warn(rbd_dev, "shared lock type detected");
+-              ret = -EBUSY;
+-              goto out;
++              goto err_busy;
+       }
+-      if (strncmp((*lockers)[0].id.cookie, RBD_LOCK_COOKIE_PREFIX,
++      WARN_ON(num_lockers != 1);
++      if (strncmp(lockers[0].id.cookie, RBD_LOCK_COOKIE_PREFIX,
+                   strlen(RBD_LOCK_COOKIE_PREFIX))) {
+               rbd_warn(rbd_dev, "locked by external mechanism, cookie %s",
+-                       (*lockers)[0].id.cookie);
+-              ret = -EBUSY;
+-              goto out;
++                       lockers[0].id.cookie);
++              goto err_busy;
+       }
+ out:
+       kfree(lock_tag);
+-      return ret;
++      return lockers;
++
++err_busy:
++      kfree(lock_tag);
++      ceph_free_lockers(lockers, num_lockers);
++      return ERR_PTR(-EBUSY);
+ }
+ static int find_watcher(struct rbd_device *rbd_dev,
+@@ -3949,51 +3962,56 @@ out:
+ static int rbd_try_lock(struct rbd_device *rbd_dev)
+ {
+       struct ceph_client *client = rbd_dev->rbd_client->client;
+-      struct ceph_locker *lockers;
+-      u32 num_lockers;
++      struct ceph_locker *locker;
+       int ret;
+       for (;;) {
++              locker = NULL;
++
+               ret = rbd_lock(rbd_dev);
+               if (ret != -EBUSY)
+-                      return ret;
++                      goto out;
+               /* determine if the current lock holder is still alive */
+-              ret = get_lock_owner_info(rbd_dev, &lockers, &num_lockers);
+-              if (ret)
+-                      return ret;
+-
+-              if (num_lockers == 0)
++              locker = get_lock_owner_info(rbd_dev);
++              if (IS_ERR(locker)) {
++                      ret = PTR_ERR(locker);
++                      locker = NULL;
++                      goto out;
++              }
++              if (!locker)
+                       goto again;
+-              ret = find_watcher(rbd_dev, lockers);
++              ret = find_watcher(rbd_dev, locker);
+               if (ret)
+                       goto out; /* request lock or error */
+               rbd_warn(rbd_dev, "breaking header lock owned by %s%llu",
+-                       ENTITY_NAME(lockers[0].id.name));
++                       ENTITY_NAME(locker->id.name));
+               ret = ceph_monc_blocklist_add(&client->monc,
+-                                            &lockers[0].info.addr);
++                                            &locker->info.addr);
+               if (ret) {
+-                      rbd_warn(rbd_dev, "blocklist of %s%llu failed: %d",
+-                               ENTITY_NAME(lockers[0].id.name), ret);
++                      rbd_warn(rbd_dev, "failed to blocklist %s%llu: %d",
++                               ENTITY_NAME(locker->id.name), ret);
+                       goto out;
+               }
+               ret = ceph_cls_break_lock(&client->osdc, &rbd_dev->header_oid,
+                                         &rbd_dev->header_oloc, RBD_LOCK_NAME,
+-                                        lockers[0].id.cookie,
+-                                        &lockers[0].id.name);
+-              if (ret && ret != -ENOENT)
++                                        locker->id.cookie, &locker->id.name);
++              if (ret && ret != -ENOENT) {
++                      rbd_warn(rbd_dev, "failed to break header lock: %d",
++                               ret);
+                       goto out;
++              }
+ again:
+-              ceph_free_lockers(lockers, num_lockers);
++              free_locker(locker);
+       }
+ out:
+-      ceph_free_lockers(lockers, num_lockers);
++      free_locker(locker);
+       return ret;
+ }
diff --git a/queue-5.15/rbd-retrieve-and-check-lock-owner-twice-before-blocklisting.patch b/queue-5.15/rbd-retrieve-and-check-lock-owner-twice-before-blocklisting.patch
new file mode 100644 (file)
index 0000000..11fee4a
--- /dev/null
@@ -0,0 +1,99 @@
+From 588159009d5b7a09c3e5904cffddbe4a4e170301 Mon Sep 17 00:00:00 2001
+From: Ilya Dryomov <idryomov@gmail.com>
+Date: Sat, 22 Jul 2023 20:28:08 +0200
+Subject: rbd: retrieve and check lock owner twice before blocklisting
+
+From: Ilya Dryomov <idryomov@gmail.com>
+
+commit 588159009d5b7a09c3e5904cffddbe4a4e170301 upstream.
+
+An attempt to acquire exclusive lock can race with the current lock
+owner closing the image:
+
+1. lock is held by client123, rbd_lock() returns -EBUSY
+2. get_lock_owner_info() returns client123 instance details
+3. client123 closes the image, lock is released
+4. find_watcher() returns 0 as there is no matching watcher anymore
+5. client123 instance gets erroneously blocklisted
+
+Particularly impacted is mirror snapshot scheduler in snapshot-based
+mirroring since it happens to open and close images a lot (images are
+opened only for as long as it takes to take the next mirror snapshot,
+the same client instance is used for all images).
+
+To reduce the potential for erroneous blocklisting, retrieve the lock
+owner again after find_watcher() returns 0.  If it's still there, make
+sure it matches the previously detected lock owner.
+
+Cc: stable@vger.kernel.org # f38cb9d9c204: rbd: make get_lock_owner_info() return a single locker or NULL
+Cc: stable@vger.kernel.org # 8ff2c64c9765: rbd: harden get_lock_owner_info() a bit
+Cc: stable@vger.kernel.org
+Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
+Reviewed-by: Dongsheng Yang <dongsheng.yang@easystack.cn>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/block/rbd.c |   25 +++++++++++++++++++++++--
+ 1 file changed, 23 insertions(+), 2 deletions(-)
+
+--- a/drivers/block/rbd.c
++++ b/drivers/block/rbd.c
+@@ -3851,6 +3851,15 @@ static void wake_lock_waiters(struct rbd
+       list_splice_tail_init(&rbd_dev->acquiring_list, &rbd_dev->running_list);
+ }
++static bool locker_equal(const struct ceph_locker *lhs,
++                       const struct ceph_locker *rhs)
++{
++      return lhs->id.name.type == rhs->id.name.type &&
++             lhs->id.name.num == rhs->id.name.num &&
++             !strcmp(lhs->id.cookie, rhs->id.cookie) &&
++             ceph_addr_equal_no_type(&lhs->info.addr, &rhs->info.addr);
++}
++
+ static void free_locker(struct ceph_locker *locker)
+ {
+       if (locker)
+@@ -3971,11 +3980,11 @@ out:
+ static int rbd_try_lock(struct rbd_device *rbd_dev)
+ {
+       struct ceph_client *client = rbd_dev->rbd_client->client;
+-      struct ceph_locker *locker;
++      struct ceph_locker *locker, *refreshed_locker;
+       int ret;
+       for (;;) {
+-              locker = NULL;
++              locker = refreshed_locker = NULL;
+               ret = rbd_lock(rbd_dev);
+               if (ret != -EBUSY)
+@@ -3995,6 +4004,16 @@ static int rbd_try_lock(struct rbd_devic
+               if (ret)
+                       goto out; /* request lock or error */
++              refreshed_locker = get_lock_owner_info(rbd_dev);
++              if (IS_ERR(refreshed_locker)) {
++                      ret = PTR_ERR(refreshed_locker);
++                      refreshed_locker = NULL;
++                      goto out;
++              }
++              if (!refreshed_locker ||
++                  !locker_equal(locker, refreshed_locker))
++                      goto again;
++
+               rbd_warn(rbd_dev, "breaking header lock owned by %s%llu",
+                        ENTITY_NAME(locker->id.name));
+@@ -4016,10 +4035,12 @@ static int rbd_try_lock(struct rbd_devic
+               }
+ again:
++              free_locker(refreshed_locker);
+               free_locker(locker);
+       }
+ out:
++      free_locker(refreshed_locker);
+       free_locker(locker);
+       return ret;
+ }
index b2e8a05c432ae848a8c0c8fd5f82a4c3576ac662..c189ec3b2ddd826632cb2410f4da3f877aab6b5c 100644 (file)
@@ -140,3 +140,8 @@ kvm-x86-disallow-kvm_set_sregs-2-if-incoming-cr0-is-.patch
 virtio-net-fix-race-between-set-queues-and-probe.patch
 s390-dasd-fix-hanging-device-after-quiesce-resume.patch
 asoc-wm8904-fill-the-cache-for-wm8904_adc_test_0-register.patch
+ceph-never-send-metrics-if-disable_send_metrics-is-set.patch
+dm-cache-policy-smq-ensure-io-doesn-t-prevent-cleaner-policy-progress.patch
+rbd-make-get_lock_owner_info-return-a-single-locker-or-null.patch
+rbd-harden-get_lock_owner_info-a-bit.patch
+rbd-retrieve-and-check-lock-owner-twice-before-blocklisting.patch