]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.12-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 3 Dec 2024 12:45:52 +0000 (13:45 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 3 Dec 2024 12:45:52 +0000 (13:45 +0100)
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

queue-6.12/block-always-verify-unfreeze-lock-on-the-owner-task.patch [new file with mode: 0644]
queue-6.12/block-don-t-verify-io-lock-for-freeze-unfreeze-in-elevator_init_mq.patch [new file with mode: 0644]
queue-6.12/kvm-arm64-vgic-its-add-stronger-type-checking-to-the-its-entry-sizes.patch [new file with mode: 0644]
queue-6.12/series

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 (file)
index 0000000..f6f24ff
--- /dev/null
@@ -0,0 +1,177 @@
+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
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 (file)
index 0000000..25a33fd
--- /dev/null
@@ -0,0 +1,50 @@
+From 357e1b7f730bd85a383e7afa75a3caba329c5707 Mon Sep 17 00:00:00 2001
+From: Ming Lei <ming.lei@redhat.com>
+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 <ming.lei@redhat.com>
+
+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 <m.szyprowski@samsung.com>
+Reported-by: Lai Yi <yi1.lai@linux.intel.com>
+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-5-ming.lei@redhat.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..69cd3bb
--- /dev/null
@@ -0,0 +1,270 @@
+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
index 58d08baf30eaf8c4225fd38a6aa506827ff937dc..52d7e8faef273f6ca865dfb44b50d73843754d6a 100644 (file)
@@ -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