From: Greg Kroah-Hartman Date: Tue, 1 Aug 2023 06:27:47 +0000 (+0200) Subject: 5.15-stable patches X-Git-Tag: v5.15.124~33 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=9d8bca5d4c00d3ad4d8b043c47999996d074b50b;p=thirdparty%2Fkernel%2Fstable-queue.git 5.15-stable patches 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 --- 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 index 00000000000..c5dc90cfcec --- /dev/null +++ b/queue-5.15/ceph-never-send-metrics-if-disable_send_metrics-is-set.patch @@ -0,0 +1,34 @@ +From 50164507f6b7b7ed85d8c3ac0266849fbd908db7 Mon Sep 17 00:00:00 2001 +From: Xiubo Li +Date: Thu, 20 Jul 2023 11:33:55 +0800 +Subject: ceph: never send metrics if disable_send_metrics is set + +From: Xiubo Li + +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 +Reviewed-by: Venky Shankar +Reviewed-by: Jeff Layton +Signed-off-by: Ilya Dryomov +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..702c16f8107 --- /dev/null +++ b/queue-5.15/dm-cache-policy-smq-ensure-io-doesn-t-prevent-cleaner-policy-progress.patch @@ -0,0 +1,106 @@ +From 1e4ab7b4c881cf26c1c72b3f56519e03475486fb Mon Sep 17 00:00:00 2001 +From: Joe Thornber +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 + +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 +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Cc: stable@vger.kernel.org +Signed-off-by: Joe Thornber +Signed-off-by: Mike Snitzer +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..b361571758c --- /dev/null +++ b/queue-5.15/rbd-harden-get_lock_owner_info-a-bit.patch @@ -0,0 +1,79 @@ +From 8ff2c64c9765446c3cef804fb99da04916603e27 Mon Sep 17 00:00:00 2001 +From: Ilya Dryomov +Date: Sat, 8 Jul 2023 16:16:59 +0200 +Subject: rbd: harden get_lock_owner_info() a bit + +From: Ilya Dryomov + +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 +Reviewed-by: Dongsheng Yang +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..45767ed049f --- /dev/null +++ b/queue-5.15/rbd-make-get_lock_owner_info-return-a-single-locker-or-null.patch @@ -0,0 +1,176 @@ +From f38cb9d9c2045dad16eead4a2e1aedfddd94603b Mon Sep 17 00:00:00 2001 +From: Ilya Dryomov +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 + +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 +Reviewed-by: Dongsheng Yang +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..11fee4a4601 --- /dev/null +++ b/queue-5.15/rbd-retrieve-and-check-lock-owner-twice-before-blocklisting.patch @@ -0,0 +1,99 @@ +From 588159009d5b7a09c3e5904cffddbe4a4e170301 Mon Sep 17 00:00:00 2001 +From: Ilya Dryomov +Date: Sat, 22 Jul 2023 20:28:08 +0200 +Subject: rbd: retrieve and check lock owner twice before blocklisting + +From: Ilya Dryomov + +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 +Reviewed-by: Dongsheng Yang +Signed-off-by: Greg Kroah-Hartman +--- + 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; + } diff --git a/queue-5.15/series b/queue-5.15/series index b2e8a05c432..c189ec3b2dd 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -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