--- /dev/null
+From 6a78699838a0ddeed3620ddf50c1521f1fe1e811 Mon Sep 17 00:00:00 2001
+From: Ming Lei <ming.lei@redhat.com>
+Date: Thu, 31 Oct 2024 21:37:19 +0800
+Subject: block: always verify unfreeze lock on the owner task
+
+From: Ming Lei <ming.lei@redhat.com>
+
+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 <ming.lei@redhat.com>
+Link: https://lore.kernel.org/r/20241031133723.303835-4-ming.lei@redhat.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
--- /dev/null
+From 3b2c81d5feb250dfdcb0ef5825319f36c29f8336 Mon Sep 17 00:00:00 2001
+From: Marc Zyngier <maz@kernel.org>
+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 <maz@kernel.org>
+
+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 <maz@kernel.org>
+Link: https://lore.kernel.org/r/20241117165757.247686-5-maz@kernel.org
+Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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