From: Greg Kroah-Hartman Date: Tue, 3 Dec 2024 12:45:52 +0000 (+0100) Subject: 6.12-stable patches X-Git-Tag: v4.19.325~14 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=508657f1a4a932611a9b7b7f5a35256ad0ebde29;p=thirdparty%2Fkernel%2Fstable-queue.git 6.12-stable patches added patches: block-always-verify-unfreeze-lock-on-the-owner-task.patch block-don-t-verify-io-lock-for-freeze-unfreeze-in-elevator_init_mq.patch kvm-arm64-vgic-its-add-stronger-type-checking-to-the-its-entry-sizes.patch --- diff --git a/queue-6.12/block-always-verify-unfreeze-lock-on-the-owner-task.patch b/queue-6.12/block-always-verify-unfreeze-lock-on-the-owner-task.patch new file mode 100644 index 00000000000..f6f24ff229c --- /dev/null +++ b/queue-6.12/block-always-verify-unfreeze-lock-on-the-owner-task.patch @@ -0,0 +1,177 @@ +From 6a78699838a0ddeed3620ddf50c1521f1fe1e811 Mon Sep 17 00:00:00 2001 +From: Ming Lei +Date: Thu, 31 Oct 2024 21:37:19 +0800 +Subject: block: always verify unfreeze lock on the owner task + +From: Ming Lei + +commit 6a78699838a0ddeed3620ddf50c1521f1fe1e811 upstream. + +commit f1be1788a32e ("block: model freeze & enter queue as lock for +supporting lockdep") tries to apply lockdep for verifying freeze & +unfreeze. However, the verification is only done the outmost freeze and +unfreeze. This way is actually not correct because q->mq_freeze_depth +still may drop to zero on other task instead of the freeze owner task. + +Fix this issue by always verifying the last unfreeze lock on the owner +task context, and make sure both the outmost freeze & unfreeze are +verified in the current task. + +Fixes: f1be1788a32e ("block: model freeze & enter queue as lock for supporting lockdep") +Signed-off-by: Ming Lei +Link: https://lore.kernel.org/r/20241031133723.303835-4-ming.lei@redhat.com +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman +--- + block/blk-core.c | 2 - + block/blk-mq.c | 62 ++++++++++++++++++++++++++++++++++++++++++------- + block/blk.h | 3 +- + include/linux/blkdev.h | 4 +++ + 4 files changed, 61 insertions(+), 10 deletions(-) + +--- a/block/blk-core.c ++++ b/block/blk-core.c +@@ -287,7 +287,7 @@ bool blk_queue_start_drain(struct reques + * entering queue, so we call blk_freeze_queue_start() to + * prevent I/O from crossing blk_queue_enter(). + */ +- bool freeze = __blk_freeze_queue_start(q); ++ bool freeze = __blk_freeze_queue_start(q, current); + if (queue_is_mq(q)) + blk_mq_wake_waiters(q); + /* Make blk_queue_enter() reexamine the DYING flag. */ +--- a/block/blk-mq.c ++++ b/block/blk-mq.c +@@ -120,20 +120,66 @@ void blk_mq_in_flight_rw(struct request_ + inflight[1] = mi.inflight[1]; + } + +-bool __blk_freeze_queue_start(struct request_queue *q) ++#ifdef CONFIG_LOCKDEP ++static bool blk_freeze_set_owner(struct request_queue *q, ++ struct task_struct *owner) + { +- int freeze; ++ if (!owner) ++ return false; ++ ++ if (!q->mq_freeze_depth) { ++ q->mq_freeze_owner = owner; ++ q->mq_freeze_owner_depth = 1; ++ return true; ++ } ++ ++ if (owner == q->mq_freeze_owner) ++ q->mq_freeze_owner_depth += 1; ++ return false; ++} ++ ++/* verify the last unfreeze in owner context */ ++static bool blk_unfreeze_check_owner(struct request_queue *q) ++{ ++ if (!q->mq_freeze_owner) ++ return false; ++ if (q->mq_freeze_owner != current) ++ return false; ++ if (--q->mq_freeze_owner_depth == 0) { ++ q->mq_freeze_owner = NULL; ++ return true; ++ } ++ return false; ++} ++ ++#else ++ ++static bool blk_freeze_set_owner(struct request_queue *q, ++ struct task_struct *owner) ++{ ++ return false; ++} ++ ++static bool blk_unfreeze_check_owner(struct request_queue *q) ++{ ++ return false; ++} ++#endif ++ ++bool __blk_freeze_queue_start(struct request_queue *q, ++ struct task_struct *owner) ++{ ++ bool freeze; + + mutex_lock(&q->mq_freeze_lock); ++ freeze = blk_freeze_set_owner(q, owner); + if (++q->mq_freeze_depth == 1) { + percpu_ref_kill(&q->q_usage_counter); + mutex_unlock(&q->mq_freeze_lock); + if (queue_is_mq(q)) + blk_mq_run_hw_queues(q, false); +- freeze = true; + } else { + mutex_unlock(&q->mq_freeze_lock); +- freeze = false; + } + + return freeze; +@@ -141,7 +187,7 @@ bool __blk_freeze_queue_start(struct req + + void blk_freeze_queue_start(struct request_queue *q) + { +- if (__blk_freeze_queue_start(q)) ++ if (__blk_freeze_queue_start(q, current)) + blk_freeze_acquire_lock(q, false, false); + } + EXPORT_SYMBOL_GPL(blk_freeze_queue_start); +@@ -190,7 +236,7 @@ EXPORT_SYMBOL_GPL(blk_mq_freeze_queue); + + bool __blk_mq_unfreeze_queue(struct request_queue *q, bool force_atomic) + { +- int unfreeze = false; ++ bool unfreeze; + + mutex_lock(&q->mq_freeze_lock); + if (force_atomic) +@@ -200,8 +246,8 @@ bool __blk_mq_unfreeze_queue(struct requ + if (!q->mq_freeze_depth) { + percpu_ref_resurrect(&q->q_usage_counter); + wake_up_all(&q->mq_freeze_wq); +- unfreeze = true; + } ++ unfreeze = blk_unfreeze_check_owner(q); + mutex_unlock(&q->mq_freeze_lock); + + return unfreeze; +@@ -223,7 +269,7 @@ EXPORT_SYMBOL_GPL(blk_mq_unfreeze_queue) + */ + void blk_freeze_queue_start_non_owner(struct request_queue *q) + { +- __blk_freeze_queue_start(q); ++ __blk_freeze_queue_start(q, NULL); + } + EXPORT_SYMBOL_GPL(blk_freeze_queue_start_non_owner); + +--- a/block/blk.h ++++ b/block/blk.h +@@ -38,7 +38,8 @@ void blk_free_flush_queue(struct blk_flu + void blk_freeze_queue(struct request_queue *q); + bool __blk_mq_unfreeze_queue(struct request_queue *q, bool force_atomic); + bool blk_queue_start_drain(struct request_queue *q); +-bool __blk_freeze_queue_start(struct request_queue *q); ++bool __blk_freeze_queue_start(struct request_queue *q, ++ struct task_struct *owner); + int __bio_queue_enter(struct request_queue *q, struct bio *bio); + void submit_bio_noacct_nocheck(struct bio *bio); + void bio_await_chain(struct bio *bio); +--- a/include/linux/blkdev.h ++++ b/include/linux/blkdev.h +@@ -572,6 +572,10 @@ struct request_queue { + struct throtl_data *td; + #endif + struct rcu_head rcu_head; ++#ifdef CONFIG_LOCKDEP ++ struct task_struct *mq_freeze_owner; ++ int mq_freeze_owner_depth; ++#endif + wait_queue_head_t mq_freeze_wq; + /* + * Protect concurrent access to q_usage_counter by diff --git a/queue-6.12/block-don-t-verify-io-lock-for-freeze-unfreeze-in-elevator_init_mq.patch b/queue-6.12/block-don-t-verify-io-lock-for-freeze-unfreeze-in-elevator_init_mq.patch new file mode 100644 index 00000000000..25a33fdeaad --- /dev/null +++ b/queue-6.12/block-don-t-verify-io-lock-for-freeze-unfreeze-in-elevator_init_mq.patch @@ -0,0 +1,50 @@ +From 357e1b7f730bd85a383e7afa75a3caba329c5707 Mon Sep 17 00:00:00 2001 +From: Ming Lei +Date: Thu, 31 Oct 2024 21:37:20 +0800 +Subject: block: don't verify IO lock for freeze/unfreeze in elevator_init_mq() + +From: Ming Lei + +commit 357e1b7f730bd85a383e7afa75a3caba329c5707 upstream. + +elevator_init_mq() is only called at the entry of add_disk_fwnode() when +disk IO isn't allowed yet. + +So not verify io lock(q->io_lockdep_map) for freeze & unfreeze in +elevator_init_mq(). + +Reported-by: Marek Szyprowski +Reported-by: Lai Yi +Fixes: f1be1788a32e ("block: model freeze & enter queue as lock for supporting lockdep") +Signed-off-by: Ming Lei +Link: https://lore.kernel.org/r/20241031133723.303835-5-ming.lei@redhat.com +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman +--- + block/elevator.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +--- a/block/elevator.c ++++ b/block/elevator.c +@@ -598,13 +598,19 @@ void elevator_init_mq(struct request_que + * drain any dispatch activities originated from passthrough + * requests, then no need to quiesce queue which may add long boot + * latency, especially when lots of disks are involved. ++ * ++ * Disk isn't added yet, so verifying queue lock only manually. + */ +- blk_mq_freeze_queue(q); ++ blk_freeze_queue_start_non_owner(q); ++ blk_freeze_acquire_lock(q, true, false); ++ blk_mq_freeze_queue_wait(q); ++ + blk_mq_cancel_work_sync(q); + + err = blk_mq_init_sched(q, e); + +- blk_mq_unfreeze_queue(q); ++ blk_unfreeze_release_lock(q, true, false); ++ blk_mq_unfreeze_queue_non_owner(q); + + if (err) { + pr_warn("\"%s\" elevator initialization failed, " diff --git a/queue-6.12/kvm-arm64-vgic-its-add-stronger-type-checking-to-the-its-entry-sizes.patch b/queue-6.12/kvm-arm64-vgic-its-add-stronger-type-checking-to-the-its-entry-sizes.patch new file mode 100644 index 00000000000..69cd3bb9bc6 --- /dev/null +++ b/queue-6.12/kvm-arm64-vgic-its-add-stronger-type-checking-to-the-its-entry-sizes.patch @@ -0,0 +1,270 @@ +From 3b2c81d5feb250dfdcb0ef5825319f36c29f8336 Mon Sep 17 00:00:00 2001 +From: Marc Zyngier +Date: Sun, 17 Nov 2024 16:57:57 +0000 +Subject: KVM: arm64: vgic-its: Add stronger type-checking to the ITS entry sizes + +From: Marc Zyngier + +commit 3b2c81d5feb250dfdcb0ef5825319f36c29f8336 upstream. + +The ITS ABI infrastructure allows for some pretty lax code, where +the size of the data doesn't have to match the size of the entry, +potentially leading to a collection of interesting bugs. + +Commit 7fe28d7e68f9 ("KVM: arm64: vgic-its: Add a data length check +in vgic_its_save_*") added some checks, but starts by implicitly +casting all writes to a 64bit value, hiding some of the issues. + +Instead, introduce macros that will check the data type actually used +for dealing with the table entries. The macros are taking a symbolic +entry type that is used to fetch the size of the entry type for the +current ABI. This immediately catches a couple of low-impact gotchas +(zero values that are implicitly 32bit), easy enough to fix. + +Given that we currently only have a single ABI, hardcode a couple of +BUILD_BUG_ON()s that will fire if we use anything but a 64bit quantity, +and some (currently unreachable) fallback code that may become useful +one day. + +Signed-off-by: Marc Zyngier +Link: https://lore.kernel.org/r/20241117165757.247686-5-maz@kernel.org +Signed-off-by: Oliver Upton +Signed-off-by: Greg Kroah-Hartman +--- + arch/arm64/kvm/vgic/vgic-its.c | 69 +++++++++++++++++++++++++++++------------ + arch/arm64/kvm/vgic/vgic.h | 23 ------------- + 2 files changed, 50 insertions(+), 42 deletions(-) + +--- a/arch/arm64/kvm/vgic/vgic-its.c ++++ b/arch/arm64/kvm/vgic/vgic-its.c +@@ -31,6 +31,41 @@ static int vgic_its_commit_v0(struct vgi + static int update_lpi_config(struct kvm *kvm, struct vgic_irq *irq, + struct kvm_vcpu *filter_vcpu, bool needs_inv); + ++#define vgic_its_read_entry_lock(i, g, valp, t) \ ++ ({ \ ++ int __sz = vgic_its_get_abi(i)->t##_esz; \ ++ struct kvm *__k = (i)->dev->kvm; \ ++ int __ret; \ ++ \ ++ BUILD_BUG_ON(NR_ITS_ABIS == 1 && \ ++ sizeof(*(valp)) != ABI_0_ESZ); \ ++ if (NR_ITS_ABIS > 1 && \ ++ KVM_BUG_ON(__sz != sizeof(*(valp)), __k)) \ ++ __ret = -EINVAL; \ ++ else \ ++ __ret = kvm_read_guest_lock(__k, (g), \ ++ valp, __sz); \ ++ __ret; \ ++ }) ++ ++#define vgic_its_write_entry_lock(i, g, val, t) \ ++ ({ \ ++ int __sz = vgic_its_get_abi(i)->t##_esz; \ ++ struct kvm *__k = (i)->dev->kvm; \ ++ typeof(val) __v = (val); \ ++ int __ret; \ ++ \ ++ BUILD_BUG_ON(NR_ITS_ABIS == 1 && \ ++ sizeof(__v) != ABI_0_ESZ); \ ++ if (NR_ITS_ABIS > 1 && \ ++ KVM_BUG_ON(__sz != sizeof(__v), __k)) \ ++ __ret = -EINVAL; \ ++ else \ ++ __ret = vgic_write_guest_lock(__k, (g), \ ++ &__v, __sz); \ ++ __ret; \ ++ }) ++ + /* + * Creates a new (reference to a) struct vgic_irq for a given LPI. + * If this LPI is already mapped on another ITS, we increase its refcount +@@ -794,7 +829,7 @@ static int vgic_its_cmd_handle_discard(s + + its_free_ite(kvm, ite); + +- return vgic_its_write_entry_lock(its, gpa, 0, ite_esz); ++ return vgic_its_write_entry_lock(its, gpa, 0ULL, ite); + } + + return E_ITS_DISCARD_UNMAPPED_INTERRUPT; +@@ -1143,7 +1178,6 @@ static int vgic_its_cmd_handle_mapd(stru + bool valid = its_cmd_get_validbit(its_cmd); + u8 num_eventid_bits = its_cmd_get_size(its_cmd); + gpa_t itt_addr = its_cmd_get_ittaddr(its_cmd); +- int dte_esz = vgic_its_get_abi(its)->dte_esz; + struct its_device *device; + gpa_t gpa; + +@@ -1168,7 +1202,7 @@ static int vgic_its_cmd_handle_mapd(stru + * is an error, so we are done in any case. + */ + if (!valid) +- return vgic_its_write_entry_lock(its, gpa, 0, dte_esz); ++ return vgic_its_write_entry_lock(its, gpa, 0ULL, dte); + + device = vgic_its_alloc_device(its, device_id, itt_addr, + num_eventid_bits); +@@ -2090,7 +2124,7 @@ static int scan_its_table(struct vgic_it + * vgic_its_save_ite - Save an interrupt translation entry at @gpa + */ + static int vgic_its_save_ite(struct vgic_its *its, struct its_device *dev, +- struct its_ite *ite, gpa_t gpa, int ite_esz) ++ struct its_ite *ite, gpa_t gpa) + { + u32 next_offset; + u64 val; +@@ -2101,7 +2135,7 @@ static int vgic_its_save_ite(struct vgic + ite->collection->collection_id; + val = cpu_to_le64(val); + +- return vgic_its_write_entry_lock(its, gpa, val, ite_esz); ++ return vgic_its_write_entry_lock(its, gpa, val, ite); + } + + /** +@@ -2201,7 +2235,7 @@ static int vgic_its_save_itt(struct vgic + if (ite->irq->hw && !kvm_vgic_global_state.has_gicv4_1) + return -EACCES; + +- ret = vgic_its_save_ite(its, device, ite, gpa, ite_esz); ++ ret = vgic_its_save_ite(its, device, ite, gpa); + if (ret) + return ret; + } +@@ -2240,10 +2274,9 @@ static int vgic_its_restore_itt(struct v + * @its: ITS handle + * @dev: ITS device + * @ptr: GPA +- * @dte_esz: device table entry size + */ + static int vgic_its_save_dte(struct vgic_its *its, struct its_device *dev, +- gpa_t ptr, int dte_esz) ++ gpa_t ptr) + { + u64 val, itt_addr_field; + u32 next_offset; +@@ -2256,7 +2289,7 @@ static int vgic_its_save_dte(struct vgic + (dev->num_eventid_bits - 1)); + val = cpu_to_le64(val); + +- return vgic_its_write_entry_lock(its, ptr, val, dte_esz); ++ return vgic_its_write_entry_lock(its, ptr, val, dte); + } + + /** +@@ -2332,10 +2365,8 @@ static int vgic_its_device_cmp(void *pri + */ + static int vgic_its_save_device_tables(struct vgic_its *its) + { +- const struct vgic_its_abi *abi = vgic_its_get_abi(its); + u64 baser = its->baser_device_table; + struct its_device *dev; +- int dte_esz = abi->dte_esz; + + if (!(baser & GITS_BASER_VALID)) + return 0; +@@ -2354,7 +2385,7 @@ static int vgic_its_save_device_tables(s + if (ret) + return ret; + +- ret = vgic_its_save_dte(its, dev, eaddr, dte_esz); ++ ret = vgic_its_save_dte(its, dev, eaddr); + if (ret) + return ret; + } +@@ -2435,7 +2466,7 @@ static int vgic_its_restore_device_table + + static int vgic_its_save_cte(struct vgic_its *its, + struct its_collection *collection, +- gpa_t gpa, int esz) ++ gpa_t gpa) + { + u64 val; + +@@ -2444,7 +2475,7 @@ static int vgic_its_save_cte(struct vgic + collection->collection_id); + val = cpu_to_le64(val); + +- return vgic_its_write_entry_lock(its, gpa, val, esz); ++ return vgic_its_write_entry_lock(its, gpa, val, cte); + } + + /* +@@ -2452,7 +2483,7 @@ static int vgic_its_save_cte(struct vgic + * Return +1 on success, 0 if the entry was invalid (which should be + * interpreted as end-of-table), and a negative error value for generic errors. + */ +-static int vgic_its_restore_cte(struct vgic_its *its, gpa_t gpa, int esz) ++static int vgic_its_restore_cte(struct vgic_its *its, gpa_t gpa) + { + struct its_collection *collection; + struct kvm *kvm = its->dev->kvm; +@@ -2460,7 +2491,7 @@ static int vgic_its_restore_cte(struct v + u64 val; + int ret; + +- ret = vgic_its_read_entry_lock(its, gpa, &val, esz); ++ ret = vgic_its_read_entry_lock(its, gpa, &val, cte); + if (ret) + return ret; + val = le64_to_cpu(val); +@@ -2507,7 +2538,7 @@ static int vgic_its_save_collection_tabl + max_size = GITS_BASER_NR_PAGES(baser) * SZ_64K; + + list_for_each_entry(collection, &its->collection_list, coll_list) { +- ret = vgic_its_save_cte(its, collection, gpa, cte_esz); ++ ret = vgic_its_save_cte(its, collection, gpa); + if (ret) + return ret; + gpa += cte_esz; +@@ -2521,7 +2552,7 @@ static int vgic_its_save_collection_tabl + * table is not fully filled, add a last dummy element + * with valid bit unset + */ +- return vgic_its_write_entry_lock(its, gpa, 0, cte_esz); ++ return vgic_its_write_entry_lock(its, gpa, 0ULL, cte); + } + + /* +@@ -2546,7 +2577,7 @@ static int vgic_its_restore_collection_t + max_size = GITS_BASER_NR_PAGES(baser) * SZ_64K; + + while (read < max_size) { +- ret = vgic_its_restore_cte(its, gpa, cte_esz); ++ ret = vgic_its_restore_cte(its, gpa); + if (ret <= 0) + break; + gpa += cte_esz; +--- a/arch/arm64/kvm/vgic/vgic.h ++++ b/arch/arm64/kvm/vgic/vgic.h +@@ -146,29 +146,6 @@ static inline int vgic_write_guest_lock( + return ret; + } + +-static inline int vgic_its_read_entry_lock(struct vgic_its *its, gpa_t eaddr, +- u64 *eval, unsigned long esize) +-{ +- struct kvm *kvm = its->dev->kvm; +- +- if (KVM_BUG_ON(esize != sizeof(*eval), kvm)) +- return -EINVAL; +- +- return kvm_read_guest_lock(kvm, eaddr, eval, esize); +- +-} +- +-static inline int vgic_its_write_entry_lock(struct vgic_its *its, gpa_t eaddr, +- u64 eval, unsigned long esize) +-{ +- struct kvm *kvm = its->dev->kvm; +- +- if (KVM_BUG_ON(esize != sizeof(eval), kvm)) +- return -EINVAL; +- +- return vgic_write_guest_lock(kvm, eaddr, &eval, esize); +-} +- + /* + * This struct provides an intermediate representation of the fields contained + * in the GICH_VMCR and ICH_VMCR registers, such that code exporting the GIC diff --git a/queue-6.12/series b/queue-6.12/series index 58d08baf30e..52d7e8faef2 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -822,3 +822,6 @@ brd-decrease-the-number-of-allocated-pages-which-dis.patch sh-intc-fix-use-after-free-bug-in-register_intc_cont.patch tools-power-turbostat-fix-trailing-n-parsing.patch tools-power-turbostat-fix-child-s-argument-forwardin.patch +kvm-arm64-vgic-its-add-stronger-type-checking-to-the-its-entry-sizes.patch +block-always-verify-unfreeze-lock-on-the-owner-task.patch +block-don-t-verify-io-lock-for-freeze-unfreeze-in-elevator_init_mq.patch