--- /dev/null
+From 5a69e3d0a1b0f07e58c353560cfcb1ea20a6f040 Mon Sep 17 00:00:00 2001
+From: Hridesh MG <hridesh699@gmail.com>
+Date: Thu, 5 Dec 2024 22:48:42 +0530
+Subject: ALSA: hda/realtek: Fix headset mic on Acer Nitro 5
+
+From: Hridesh MG <hridesh699@gmail.com>
+
+commit 5a69e3d0a1b0f07e58c353560cfcb1ea20a6f040 upstream.
+
+Add a PCI quirk to enable microphone input on the headphone jack on
+the Acer Nitro 5 AN515-58 laptop.
+
+Signed-off-by: Hridesh MG <hridesh699@gmail.com>
+Cc: <stable@vger.kernel.org>
+Link: https://patch.msgid.link/20241205171843.7787-1-hridesh699@gmail.com
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ sound/pci/hda/patch_realtek.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -10127,6 +10127,7 @@ static const struct hda_quirk alc269_fix
+ SND_PCI_QUIRK(0x1025, 0x1430, "Acer TravelMate B311R-31", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1025, 0x1466, "Acer Aspire A515-56", ALC255_FIXUP_ACER_HEADPHONE_AND_MIC),
+ SND_PCI_QUIRK(0x1025, 0x1534, "Acer Predator PH315-54", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
++ SND_PCI_QUIRK(0x1025, 0x159c, "Acer Nitro 5 AN515-58", ALC2XX_FIXUP_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1025, 0x169a, "Acer Swift SFG16", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED),
+ SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
+ SND_PCI_QUIRK(0x1028, 0x053c, "Dell Latitude E5430", ALC292_FIXUP_DELL_E7X),
--- /dev/null
+From 82fdcf9b518b205da040046fbe7747fb3fd18657 Mon Sep 17 00:00:00 2001
+From: Jaakko Salo <jaakkos@gmail.com>
+Date: Fri, 6 Dec 2024 18:44:48 +0200
+Subject: ALSA: usb-audio: Add implicit feedback quirk for Yamaha THR5
+
+From: Jaakko Salo <jaakkos@gmail.com>
+
+commit 82fdcf9b518b205da040046fbe7747fb3fd18657 upstream.
+
+Use implicit feedback from the capture endpoint to fix popping
+sounds during playback.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=219567
+Signed-off-by: Jaakko Salo <jaakkos@gmail.com>
+Cc: <stable@vger.kernel.org>
+Link: https://patch.msgid.link/20241206164448.8136-1-jaakkos@gmail.com
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ sound/usb/quirks.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/sound/usb/quirks.c
++++ b/sound/usb/quirks.c
+@@ -2179,6 +2179,8 @@ static const struct usb_audio_quirk_flag
+ QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIC_RES_384),
+ DEVICE_FLG(0x046d, 0x09a4, /* Logitech QuickCam E 3500 */
+ QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_IGNORE_CTL_ERROR),
++ DEVICE_FLG(0x0499, 0x1506, /* Yamaha THR5 */
++ QUIRK_FLAG_GENERIC_IMPLICIT_FB),
+ DEVICE_FLG(0x0499, 0x1509, /* Steinberg UR22 */
+ QUIRK_FLAG_GENERIC_IMPLICIT_FB),
+ DEVICE_FLG(0x0499, 0x3108, /* Yamaha YIT-W12TX */
--- /dev/null
+From 86e6ca55b83c575ab0f2e105cf08f98e58d3d7af Mon Sep 17 00:00:00 2001
+From: Tejun Heo <tj@kernel.org>
+Date: Fri, 6 Dec 2024 07:59:51 -1000
+Subject: blk-cgroup: Fix UAF in blkcg_unpin_online()
+
+From: Tejun Heo <tj@kernel.org>
+
+commit 86e6ca55b83c575ab0f2e105cf08f98e58d3d7af upstream.
+
+blkcg_unpin_online() walks up the blkcg hierarchy putting the online pin. To
+walk up, it uses blkcg_parent(blkcg) but it was calling that after
+blkcg_destroy_blkgs(blkcg) which could free the blkcg, leading to the
+following UAF:
+
+ ==================================================================
+ BUG: KASAN: slab-use-after-free in blkcg_unpin_online+0x15a/0x270
+ Read of size 8 at addr ffff8881057678c0 by task kworker/9:1/117
+
+ CPU: 9 UID: 0 PID: 117 Comm: kworker/9:1 Not tainted 6.13.0-rc1-work-00182-gb8f52214c61a-dirty #48
+ Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS unknown 02/02/2022
+ Workqueue: cgwb_release cgwb_release_workfn
+ Call Trace:
+ <TASK>
+ dump_stack_lvl+0x27/0x80
+ print_report+0x151/0x710
+ kasan_report+0xc0/0x100
+ blkcg_unpin_online+0x15a/0x270
+ cgwb_release_workfn+0x194/0x480
+ process_scheduled_works+0x71b/0xe20
+ worker_thread+0x82a/0xbd0
+ kthread+0x242/0x2c0
+ ret_from_fork+0x33/0x70
+ ret_from_fork_asm+0x1a/0x30
+ </TASK>
+ ...
+ Freed by task 1944:
+ kasan_save_track+0x2b/0x70
+ kasan_save_free_info+0x3c/0x50
+ __kasan_slab_free+0x33/0x50
+ kfree+0x10c/0x330
+ css_free_rwork_fn+0xe6/0xb30
+ process_scheduled_works+0x71b/0xe20
+ worker_thread+0x82a/0xbd0
+ kthread+0x242/0x2c0
+ ret_from_fork+0x33/0x70
+ ret_from_fork_asm+0x1a/0x30
+
+Note that the UAF is not easy to trigger as the free path is indirected
+behind a couple RCU grace periods and a work item execution. I could only
+trigger it with artifical msleep() injected in blkcg_unpin_online().
+
+Fix it by reading the parent pointer before destroying the blkcg's blkg's.
+
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Reported-by: Abagail ren <renzezhongucas@gmail.com>
+Suggested-by: Linus Torvalds <torvalds@linuxfoundation.org>
+Fixes: 4308a434e5e0 ("blkcg: don't offline parent blkcg first")
+Cc: stable@vger.kernel.org # v5.7+
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ block/blk-cgroup.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/block/blk-cgroup.c
++++ b/block/blk-cgroup.c
+@@ -1324,10 +1324,14 @@ void blkcg_unpin_online(struct cgroup_su
+ struct blkcg *blkcg = css_to_blkcg(blkcg_css);
+
+ do {
++ struct blkcg *parent;
++
+ if (!refcount_dec_and_test(&blkcg->online_pin))
+ break;
++
++ parent = blkcg_parent(blkcg);
+ blkcg_destroy_blkgs(blkcg);
+- blkcg = blkcg_parent(blkcg);
++ blkcg = parent;
+ } while (blkcg);
+ }
+
--- /dev/null
+From 5eb3317aa5a2ffe4574ab1a12cf9bc9447ca26c0 Mon Sep 17 00:00:00 2001
+From: Damien Le Moal <dlemoal@kernel.org>
+Date: Mon, 9 Dec 2024 21:23:55 +0900
+Subject: block: Ignore REQ_NOWAIT for zone reset and zone finish operations
+
+From: Damien Le Moal <dlemoal@kernel.org>
+
+commit 5eb3317aa5a2ffe4574ab1a12cf9bc9447ca26c0 upstream.
+
+There are currently any issuer of REQ_OP_ZONE_RESET and
+REQ_OP_ZONE_FINISH operations that set REQ_NOWAIT. However, as we cannot
+handle this flag correctly due to the potential request allocation
+failure that may happen in blk_mq_submit_bio() after blk_zone_plug_bio()
+has handled the zone write plug write pointer updates for the targeted
+zones, modify blk_zone_wplug_handle_reset_or_finish() to warn if this
+flag is set and ignore it.
+
+Fixes: dd291d77cc90 ("block: Introduce zone write plugging")
+Cc: stable@vger.kernel.org
+Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
+Link: https://lore.kernel.org/r/20241209122357.47838-3-dlemoal@kernel.org
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ block/blk-zoned.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/block/blk-zoned.c
++++ b/block/blk-zoned.c
+@@ -704,6 +704,15 @@ static bool blk_zone_wplug_handle_reset_
+ }
+
+ /*
++ * No-wait reset or finish BIOs do not make much sense as the callers
++ * issue these as blocking operations in most cases. To avoid issues
++ * the BIO execution potentially failing with BLK_STS_AGAIN, warn about
++ * REQ_NOWAIT being set and ignore that flag.
++ */
++ if (WARN_ON_ONCE(bio->bi_opf & REQ_NOWAIT))
++ bio->bi_opf &= ~REQ_NOWAIT;
++
++ /*
+ * If we have a zone write plug, set its write pointer offset to 0
+ * (reset case) or to the zone size (finish case). This will abort all
+ * BIOs plugged for the target zone. It is fine as resetting or
--- /dev/null
+From fe0418eb9bd69a19a948b297c8de815e05f3cde1 Mon Sep 17 00:00:00 2001
+From: Damien Le Moal <dlemoal@kernel.org>
+Date: Mon, 9 Dec 2024 21:23:57 +0900
+Subject: block: Prevent potential deadlocks in zone write plug error recovery
+
+From: Damien Le Moal <dlemoal@kernel.org>
+
+commit fe0418eb9bd69a19a948b297c8de815e05f3cde1 upstream.
+
+Zone write plugging for handling writes to zones of a zoned block
+device always execute a zone report whenever a write BIO to a zone
+fails. The intent of this is to ensure that the tracking of a zone write
+pointer is always correct to ensure that the alignment to a zone write
+pointer of write BIOs can be checked on submission and that we can
+always correctly emulate zone append operations using regular write
+BIOs.
+
+However, this error recovery scheme introduces a potential deadlock if a
+device queue freeze is initiated while BIOs are still plugged in a zone
+write plug and one of these write operation fails. In such case, the
+disk zone write plug error recovery work is scheduled and executes a
+report zone. This in turn can result in a request allocation in the
+underlying driver to issue the report zones command to the device. But
+with the device queue freeze already started, this allocation will
+block, preventing the report zone execution and the continuation of the
+processing of the plugged BIOs. As plugged BIOs hold a queue usage
+reference, the queue freeze itself will never complete, resulting in a
+deadlock.
+
+Avoid this problem by completely removing from the zone write plugging
+code the use of report zones operations after a failed write operation,
+instead relying on the device user to either execute a report zones,
+reset the zone, finish the zone, or give up writing to the device (which
+is a fairly common pattern for file systems which degrade to read-only
+after write failures). This is not an unreasonnable requirement as all
+well-behaved applications, FSes and device mapper already use report
+zones to recover from write errors whenever possible by comparing the
+current position of a zone write pointer with what their assumption
+about the position is.
+
+The changes to remove the automatic error recovery are as follows:
+ - Completely remove the error recovery work and its associated
+ resources (zone write plug list head, disk error list, and disk
+ zone_wplugs_work work struct). This also removes the functions
+ disk_zone_wplug_set_error() and disk_zone_wplug_clear_error().
+
+ - Change the BLK_ZONE_WPLUG_ERROR zone write plug flag into
+ BLK_ZONE_WPLUG_NEED_WP_UPDATE. This new flag is set for a zone write
+ plug whenever a write opration targetting the zone of the zone write
+ plug fails. This flag indicates that the zone write pointer offset is
+ not reliable and that it must be updated when the next report zone,
+ reset zone, finish zone or disk revalidation is executed.
+
+ - Modify blk_zone_write_plug_bio_endio() to set the
+ BLK_ZONE_WPLUG_NEED_WP_UPDATE flag for the target zone of a failed
+ write BIO.
+
+ - Modify the function disk_zone_wplug_set_wp_offset() to clear this
+ new flag, thus implementing recovery of a correct write pointer
+ offset with the reset (all) zone and finish zone operations.
+
+ - Modify blkdev_report_zones() to always use the disk_report_zones_cb()
+ callback so that disk_zone_wplug_sync_wp_offset() can be called for
+ any zone marked with the BLK_ZONE_WPLUG_NEED_WP_UPDATE flag.
+ This implements recovery of a correct write pointer offset for zone
+ write plugs marked with BLK_ZONE_WPLUG_NEED_WP_UPDATE and within
+ the range of the report zones operation executed by the user.
+
+ - Modify blk_revalidate_seq_zone() to call
+ disk_zone_wplug_sync_wp_offset() for all sequential write required
+ zones when a zoned block device is revalidated, thus always resolving
+ any inconsistency between the write pointer offset of zone write
+ plugs and the actual write pointer position of sequential zones.
+
+Fixes: dd291d77cc90 ("block: Introduce zone write plugging")
+Cc: stable@vger.kernel.org
+Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
+Link: https://lore.kernel.org/r/20241209122357.47838-5-dlemoal@kernel.org
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ block/blk-zoned.c | 308 +++++++++----------------------------------------
+ include/linux/blkdev.h | 2
+ 2 files changed, 61 insertions(+), 249 deletions(-)
+
+--- a/block/blk-zoned.c
++++ b/block/blk-zoned.c
+@@ -41,7 +41,6 @@ static const char *const zone_cond_name[
+ /*
+ * Per-zone write plug.
+ * @node: hlist_node structure for managing the plug using a hash table.
+- * @link: To list the plug in the zone write plug error list of the disk.
+ * @ref: Zone write plug reference counter. A zone write plug reference is
+ * always at least 1 when the plug is hashed in the disk plug hash table.
+ * The reference is incremented whenever a new BIO needing plugging is
+@@ -63,7 +62,6 @@ static const char *const zone_cond_name[
+ */
+ struct blk_zone_wplug {
+ struct hlist_node node;
+- struct list_head link;
+ refcount_t ref;
+ spinlock_t lock;
+ unsigned int flags;
+@@ -80,8 +78,8 @@ struct blk_zone_wplug {
+ * - BLK_ZONE_WPLUG_PLUGGED: Indicates that the zone write plug is plugged,
+ * that is, that write BIOs are being throttled due to a write BIO already
+ * being executed or the zone write plug bio list is not empty.
+- * - BLK_ZONE_WPLUG_ERROR: Indicates that a write error happened which will be
+- * recovered with a report zone to update the zone write pointer offset.
++ * - BLK_ZONE_WPLUG_NEED_WP_UPDATE: Indicates that we lost track of a zone
++ * write pointer offset and need to update it.
+ * - BLK_ZONE_WPLUG_UNHASHED: Indicates that the zone write plug was removed
+ * from the disk hash table and that the initial reference to the zone
+ * write plug set when the plug was first added to the hash table has been
+@@ -91,11 +89,9 @@ struct blk_zone_wplug {
+ * freed once all remaining references from BIOs or functions are dropped.
+ */
+ #define BLK_ZONE_WPLUG_PLUGGED (1U << 0)
+-#define BLK_ZONE_WPLUG_ERROR (1U << 1)
++#define BLK_ZONE_WPLUG_NEED_WP_UPDATE (1U << 1)
+ #define BLK_ZONE_WPLUG_UNHASHED (1U << 2)
+
+-#define BLK_ZONE_WPLUG_BUSY (BLK_ZONE_WPLUG_PLUGGED | BLK_ZONE_WPLUG_ERROR)
+-
+ /**
+ * blk_zone_cond_str - Return string XXX in BLK_ZONE_COND_XXX.
+ * @zone_cond: BLK_ZONE_COND_XXX.
+@@ -163,6 +159,11 @@ int blkdev_report_zones(struct block_dev
+ {
+ struct gendisk *disk = bdev->bd_disk;
+ sector_t capacity = get_capacity(disk);
++ struct disk_report_zones_cb_args args = {
++ .disk = disk,
++ .user_cb = cb,
++ .user_data = data,
++ };
+
+ if (!bdev_is_zoned(bdev) || WARN_ON_ONCE(!disk->fops->report_zones))
+ return -EOPNOTSUPP;
+@@ -170,7 +171,8 @@ int blkdev_report_zones(struct block_dev
+ if (!nr_zones || sector >= capacity)
+ return 0;
+
+- return disk->fops->report_zones(disk, sector, nr_zones, cb, data);
++ return disk->fops->report_zones(disk, sector, nr_zones,
++ disk_report_zones_cb, &args);
+ }
+ EXPORT_SYMBOL_GPL(blkdev_report_zones);
+
+@@ -464,7 +466,7 @@ static inline void disk_put_zone_wplug(s
+ {
+ if (refcount_dec_and_test(&zwplug->ref)) {
+ WARN_ON_ONCE(!bio_list_empty(&zwplug->bio_list));
+- WARN_ON_ONCE(!list_empty(&zwplug->link));
++ WARN_ON_ONCE(zwplug->flags & BLK_ZONE_WPLUG_PLUGGED);
+ WARN_ON_ONCE(!(zwplug->flags & BLK_ZONE_WPLUG_UNHASHED));
+
+ call_rcu(&zwplug->rcu_head, disk_free_zone_wplug_rcu);
+@@ -478,8 +480,8 @@ static inline bool disk_should_remove_zo
+ if (zwplug->flags & BLK_ZONE_WPLUG_UNHASHED)
+ return false;
+
+- /* If the zone write plug is still busy, it cannot be removed. */
+- if (zwplug->flags & BLK_ZONE_WPLUG_BUSY)
++ /* If the zone write plug is still plugged, it cannot be removed. */
++ if (zwplug->flags & BLK_ZONE_WPLUG_PLUGGED)
+ return false;
+
+ /*
+@@ -562,7 +564,6 @@ again:
+ return NULL;
+
+ INIT_HLIST_NODE(&zwplug->node);
+- INIT_LIST_HEAD(&zwplug->link);
+ refcount_set(&zwplug->ref, 2);
+ spin_lock_init(&zwplug->lock);
+ zwplug->flags = 0;
+@@ -611,124 +612,29 @@ static void disk_zone_wplug_abort(struct
+ }
+
+ /*
+- * Abort (fail) all plugged BIOs of a zone write plug that are not aligned
+- * with the assumed write pointer location of the zone when the BIO will
+- * be unplugged.
+- */
+-static void disk_zone_wplug_abort_unaligned(struct gendisk *disk,
+- struct blk_zone_wplug *zwplug)
+-{
+- unsigned int wp_offset = zwplug->wp_offset;
+- struct bio_list bl = BIO_EMPTY_LIST;
+- struct bio *bio;
+-
+- while ((bio = bio_list_pop(&zwplug->bio_list))) {
+- if (disk_zone_is_full(disk, zwplug->zone_no, wp_offset) ||
+- (bio_op(bio) != REQ_OP_ZONE_APPEND &&
+- bio_offset_from_zone_start(bio) != wp_offset)) {
+- blk_zone_wplug_bio_io_error(zwplug, bio);
+- continue;
+- }
+-
+- wp_offset += bio_sectors(bio);
+- bio_list_add(&bl, bio);
+- }
+-
+- bio_list_merge(&zwplug->bio_list, &bl);
+-}
+-
+-static inline void disk_zone_wplug_set_error(struct gendisk *disk,
+- struct blk_zone_wplug *zwplug)
+-{
+- unsigned long flags;
+-
+- if (zwplug->flags & BLK_ZONE_WPLUG_ERROR)
+- return;
+-
+- /*
+- * At this point, we already have a reference on the zone write plug.
+- * However, since we are going to add the plug to the disk zone write
+- * plugs work list, increase its reference count. This reference will
+- * be dropped in disk_zone_wplugs_work() once the error state is
+- * handled, or in disk_zone_wplug_clear_error() if the zone is reset or
+- * finished.
+- */
+- zwplug->flags |= BLK_ZONE_WPLUG_ERROR;
+- refcount_inc(&zwplug->ref);
+-
+- spin_lock_irqsave(&disk->zone_wplugs_lock, flags);
+- list_add_tail(&zwplug->link, &disk->zone_wplugs_err_list);
+- spin_unlock_irqrestore(&disk->zone_wplugs_lock, flags);
+-}
+-
+-static inline void disk_zone_wplug_clear_error(struct gendisk *disk,
+- struct blk_zone_wplug *zwplug)
+-{
+- unsigned long flags;
+-
+- if (!(zwplug->flags & BLK_ZONE_WPLUG_ERROR))
+- return;
+-
+- /*
+- * We are racing with the error handling work which drops the reference
+- * on the zone write plug after handling the error state. So remove the
+- * plug from the error list and drop its reference count only if the
+- * error handling has not yet started, that is, if the zone write plug
+- * is still listed.
+- */
+- spin_lock_irqsave(&disk->zone_wplugs_lock, flags);
+- if (!list_empty(&zwplug->link)) {
+- list_del_init(&zwplug->link);
+- zwplug->flags &= ~BLK_ZONE_WPLUG_ERROR;
+- disk_put_zone_wplug(zwplug);
+- }
+- spin_unlock_irqrestore(&disk->zone_wplugs_lock, flags);
+-}
+-
+-/*
+- * Set a zone write plug write pointer offset to either 0 (zone reset case)
+- * or to the zone size (zone finish case). This aborts all plugged BIOs, which
+- * is fine to do as doing a zone reset or zone finish while writes are in-flight
+- * is a mistake from the user which will most likely cause all plugged BIOs to
+- * fail anyway.
++ * Set a zone write plug write pointer offset to the specified value.
++ * This aborts all plugged BIOs, which is fine as this function is called for
++ * a zone reset operation, a zone finish operation or if the zone needs a wp
++ * update from a report zone after a write error.
+ */
+ static void disk_zone_wplug_set_wp_offset(struct gendisk *disk,
+ struct blk_zone_wplug *zwplug,
+ unsigned int wp_offset)
+ {
+- unsigned long flags;
+-
+- spin_lock_irqsave(&zwplug->lock, flags);
+-
+- /*
+- * Make sure that a BIO completion or another zone reset or finish
+- * operation has not already removed the plug from the hash table.
+- */
+- if (zwplug->flags & BLK_ZONE_WPLUG_UNHASHED) {
+- spin_unlock_irqrestore(&zwplug->lock, flags);
+- return;
+- }
++ lockdep_assert_held(&zwplug->lock);
+
+ /* Update the zone write pointer and abort all plugged BIOs. */
++ zwplug->flags &= ~BLK_ZONE_WPLUG_NEED_WP_UPDATE;
+ zwplug->wp_offset = wp_offset;
+ disk_zone_wplug_abort(zwplug);
+
+ /*
+- * Updating the write pointer offset puts back the zone
+- * in a good state. So clear the error flag and decrement the
+- * error count if we were in error state.
+- */
+- disk_zone_wplug_clear_error(disk, zwplug);
+-
+- /*
+ * The zone write plug now has no BIO plugged: remove it from the
+ * hash table so that it cannot be seen. The plug will be freed
+ * when the last reference is dropped.
+ */
+ if (disk_should_remove_zone_wplug(disk, zwplug))
+ disk_remove_zone_wplug(disk, zwplug);
+-
+- spin_unlock_irqrestore(&zwplug->lock, flags);
+ }
+
+ static unsigned int blk_zone_wp_offset(struct blk_zone *zone)
+@@ -765,7 +671,7 @@ static void disk_zone_wplug_sync_wp_offs
+ return;
+
+ spin_lock_irqsave(&zwplug->lock, flags);
+- if (zwplug->flags & BLK_ZONE_WPLUG_ERROR)
++ if (zwplug->flags & BLK_ZONE_WPLUG_NEED_WP_UPDATE)
+ disk_zone_wplug_set_wp_offset(disk, zwplug,
+ blk_zone_wp_offset(zone));
+ spin_unlock_irqrestore(&zwplug->lock, flags);
+@@ -789,6 +695,7 @@ static bool blk_zone_wplug_handle_reset_
+ struct gendisk *disk = bio->bi_bdev->bd_disk;
+ sector_t sector = bio->bi_iter.bi_sector;
+ struct blk_zone_wplug *zwplug;
++ unsigned long flags;
+
+ /* Conventional zones cannot be reset nor finished. */
+ if (disk_zone_is_conv(disk, sector)) {
+@@ -805,7 +712,9 @@ static bool blk_zone_wplug_handle_reset_
+ */
+ zwplug = disk_get_zone_wplug(disk, sector);
+ if (zwplug) {
++ spin_lock_irqsave(&zwplug->lock, flags);
+ disk_zone_wplug_set_wp_offset(disk, zwplug, wp_offset);
++ spin_unlock_irqrestore(&zwplug->lock, flags);
+ disk_put_zone_wplug(zwplug);
+ }
+
+@@ -816,6 +725,7 @@ static bool blk_zone_wplug_handle_reset_
+ {
+ struct gendisk *disk = bio->bi_bdev->bd_disk;
+ struct blk_zone_wplug *zwplug;
++ unsigned long flags;
+ sector_t sector;
+
+ /*
+@@ -827,7 +737,9 @@ static bool blk_zone_wplug_handle_reset_
+ sector += disk->queue->limits.chunk_sectors) {
+ zwplug = disk_get_zone_wplug(disk, sector);
+ if (zwplug) {
++ spin_lock_irqsave(&zwplug->lock, flags);
+ disk_zone_wplug_set_wp_offset(disk, zwplug, 0);
++ spin_unlock_irqrestore(&zwplug->lock, flags);
+ disk_put_zone_wplug(zwplug);
+ }
+ }
+@@ -1010,12 +922,22 @@ static bool blk_zone_wplug_prepare_bio(s
+ struct gendisk *disk = bio->bi_bdev->bd_disk;
+
+ /*
++ * If we lost track of the zone write pointer due to a write error,
++ * the user must either execute a report zones, reset the zone or finish
++ * the to recover a reliable write pointer position. Fail BIOs if the
++ * user did not do that as we cannot handle emulated zone append
++ * otherwise.
++ */
++ if (zwplug->flags & BLK_ZONE_WPLUG_NEED_WP_UPDATE)
++ return false;
++
++ /*
+ * Check that the user is not attempting to write to a full zone.
+ * We know such BIO will fail, and that would potentially overflow our
+ * write pointer offset beyond the end of the zone.
+ */
+ if (disk_zone_wplug_is_full(disk, zwplug))
+- goto err;
++ return false;
+
+ if (bio_op(bio) == REQ_OP_ZONE_APPEND) {
+ /*
+@@ -1034,24 +956,18 @@ static bool blk_zone_wplug_prepare_bio(s
+ bio_set_flag(bio, BIO_EMULATES_ZONE_APPEND);
+ } else {
+ /*
+- * Check for non-sequential writes early because we avoid a
+- * whole lot of error handling trouble if we don't send it off
+- * to the driver.
++ * Check for non-sequential writes early as we know that BIOs
++ * with a start sector not unaligned to the zone write pointer
++ * will fail.
+ */
+ if (bio_offset_from_zone_start(bio) != zwplug->wp_offset)
+- goto err;
++ return false;
+ }
+
+ /* Advance the zone write pointer offset. */
+ zwplug->wp_offset += bio_sectors(bio);
+
+ return true;
+-
+-err:
+- /* We detected an invalid write BIO: schedule error recovery. */
+- disk_zone_wplug_set_error(disk, zwplug);
+- kblockd_schedule_work(&disk->zone_wplugs_work);
+- return false;
+ }
+
+ static bool blk_zone_wplug_handle_write(struct bio *bio, unsigned int nr_segs)
+@@ -1101,20 +1017,20 @@ static bool blk_zone_wplug_handle_write(
+ bio_set_flag(bio, BIO_ZONE_WRITE_PLUGGING);
+
+ /*
+- * If the zone is already plugged or has a pending error, add the BIO
+- * to the plug BIO list. Do the same for REQ_NOWAIT BIOs to ensure that
+- * we will not see a BLK_STS_AGAIN failure if we let the BIO execute.
++ * If the zone is already plugged, add the BIO to the plug BIO list.
++ * Do the same for REQ_NOWAIT BIOs to ensure that we will not see a
++ * BLK_STS_AGAIN failure if we let the BIO execute.
+ * Otherwise, plug and let the BIO execute.
+ */
+- if (zwplug->flags & BLK_ZONE_WPLUG_BUSY || (bio->bi_opf & REQ_NOWAIT))
++ if ((zwplug->flags & BLK_ZONE_WPLUG_PLUGGED) ||
++ (bio->bi_opf & REQ_NOWAIT))
+ goto plug;
+
+- /*
+- * If an error is detected when preparing the BIO, add it to the BIO
+- * list so that error recovery can deal with it.
+- */
+- if (!blk_zone_wplug_prepare_bio(zwplug, bio))
+- goto plug;
++ if (!blk_zone_wplug_prepare_bio(zwplug, bio)) {
++ spin_unlock_irqrestore(&zwplug->lock, flags);
++ bio_io_error(bio);
++ return true;
++ }
+
+ zwplug->flags |= BLK_ZONE_WPLUG_PLUGGED;
+
+@@ -1214,16 +1130,6 @@ static void disk_zone_wplug_unplug_bio(s
+
+ spin_lock_irqsave(&zwplug->lock, flags);
+
+- /*
+- * If we had an error, schedule error recovery. The recovery work
+- * will restart submission of plugged BIOs.
+- */
+- if (zwplug->flags & BLK_ZONE_WPLUG_ERROR) {
+- spin_unlock_irqrestore(&zwplug->lock, flags);
+- kblockd_schedule_work(&disk->zone_wplugs_work);
+- return;
+- }
+-
+ /* Schedule submission of the next plugged BIO if we have one. */
+ if (!bio_list_empty(&zwplug->bio_list)) {
+ disk_zone_wplug_schedule_bio_work(disk, zwplug);
+@@ -1266,12 +1172,13 @@ void blk_zone_write_plug_bio_endio(struc
+ }
+
+ /*
+- * If the BIO failed, mark the plug as having an error to trigger
+- * recovery.
++ * If the BIO failed, abort all plugged BIOs and mark the plug as
++ * needing a write pointer update.
+ */
+ if (bio->bi_status != BLK_STS_OK) {
+ spin_lock_irqsave(&zwplug->lock, flags);
+- disk_zone_wplug_set_error(disk, zwplug);
++ disk_zone_wplug_abort(zwplug);
++ zwplug->flags |= BLK_ZONE_WPLUG_NEED_WP_UPDATE;
+ spin_unlock_irqrestore(&zwplug->lock, flags);
+ }
+
+@@ -1327,6 +1234,7 @@ static void blk_zone_wplug_bio_work(stru
+ */
+ spin_lock_irqsave(&zwplug->lock, flags);
+
++again:
+ bio = bio_list_pop(&zwplug->bio_list);
+ if (!bio) {
+ zwplug->flags &= ~BLK_ZONE_WPLUG_PLUGGED;
+@@ -1335,10 +1243,8 @@ static void blk_zone_wplug_bio_work(stru
+ }
+
+ if (!blk_zone_wplug_prepare_bio(zwplug, bio)) {
+- /* Error recovery will decide what to do with the BIO. */
+- bio_list_add_head(&zwplug->bio_list, bio);
+- spin_unlock_irqrestore(&zwplug->lock, flags);
+- goto put_zwplug;
++ blk_zone_wplug_bio_io_error(zwplug, bio);
++ goto again;
+ }
+
+ spin_unlock_irqrestore(&zwplug->lock, flags);
+@@ -1360,97 +1266,6 @@ put_zwplug:
+ disk_put_zone_wplug(zwplug);
+ }
+
+-static int blk_zone_wplug_report_zone_cb(struct blk_zone *zone,
+- unsigned int idx, void *data)
+-{
+- struct blk_zone *zonep = data;
+-
+- *zonep = *zone;
+- return 0;
+-}
+-
+-static void disk_zone_wplug_handle_error(struct gendisk *disk,
+- struct blk_zone_wplug *zwplug)
+-{
+- sector_t zone_start_sector =
+- bdev_zone_sectors(disk->part0) * zwplug->zone_no;
+- unsigned int noio_flag;
+- struct blk_zone zone;
+- unsigned long flags;
+- int ret;
+-
+- /* Get the current zone information from the device. */
+- noio_flag = memalloc_noio_save();
+- ret = disk->fops->report_zones(disk, zone_start_sector, 1,
+- blk_zone_wplug_report_zone_cb, &zone);
+- memalloc_noio_restore(noio_flag);
+-
+- spin_lock_irqsave(&zwplug->lock, flags);
+-
+- /*
+- * A zone reset or finish may have cleared the error already. In such
+- * case, do nothing as the report zones may have seen the "old" write
+- * pointer value before the reset/finish operation completed.
+- */
+- if (!(zwplug->flags & BLK_ZONE_WPLUG_ERROR))
+- goto unlock;
+-
+- zwplug->flags &= ~BLK_ZONE_WPLUG_ERROR;
+-
+- if (ret != 1) {
+- /*
+- * We failed to get the zone information, meaning that something
+- * is likely really wrong with the device. Abort all remaining
+- * plugged BIOs as otherwise we could endup waiting forever on
+- * plugged BIOs to complete if there is a queue freeze on-going.
+- */
+- disk_zone_wplug_abort(zwplug);
+- goto unplug;
+- }
+-
+- /* Update the zone write pointer offset. */
+- zwplug->wp_offset = blk_zone_wp_offset(&zone);
+- disk_zone_wplug_abort_unaligned(disk, zwplug);
+-
+- /* Restart BIO submission if we still have any BIO left. */
+- if (!bio_list_empty(&zwplug->bio_list)) {
+- disk_zone_wplug_schedule_bio_work(disk, zwplug);
+- goto unlock;
+- }
+-
+-unplug:
+- zwplug->flags &= ~BLK_ZONE_WPLUG_PLUGGED;
+- if (disk_should_remove_zone_wplug(disk, zwplug))
+- disk_remove_zone_wplug(disk, zwplug);
+-
+-unlock:
+- spin_unlock_irqrestore(&zwplug->lock, flags);
+-}
+-
+-static void disk_zone_wplugs_work(struct work_struct *work)
+-{
+- struct gendisk *disk =
+- container_of(work, struct gendisk, zone_wplugs_work);
+- struct blk_zone_wplug *zwplug;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&disk->zone_wplugs_lock, flags);
+-
+- while (!list_empty(&disk->zone_wplugs_err_list)) {
+- zwplug = list_first_entry(&disk->zone_wplugs_err_list,
+- struct blk_zone_wplug, link);
+- list_del_init(&zwplug->link);
+- spin_unlock_irqrestore(&disk->zone_wplugs_lock, flags);
+-
+- disk_zone_wplug_handle_error(disk, zwplug);
+- disk_put_zone_wplug(zwplug);
+-
+- spin_lock_irqsave(&disk->zone_wplugs_lock, flags);
+- }
+-
+- spin_unlock_irqrestore(&disk->zone_wplugs_lock, flags);
+-}
+-
+ static inline unsigned int disk_zone_wplugs_hash_size(struct gendisk *disk)
+ {
+ return 1U << disk->zone_wplugs_hash_bits;
+@@ -1459,8 +1274,6 @@ static inline unsigned int disk_zone_wpl
+ void disk_init_zone_resources(struct gendisk *disk)
+ {
+ spin_lock_init(&disk->zone_wplugs_lock);
+- INIT_LIST_HEAD(&disk->zone_wplugs_err_list);
+- INIT_WORK(&disk->zone_wplugs_work, disk_zone_wplugs_work);
+ }
+
+ /*
+@@ -1559,8 +1372,6 @@ void disk_free_zone_resources(struct gen
+ if (!disk->zone_wplugs_pool)
+ return;
+
+- cancel_work_sync(&disk->zone_wplugs_work);
+-
+ if (disk->zone_wplugs_wq) {
+ destroy_workqueue(disk->zone_wplugs_wq);
+ disk->zone_wplugs_wq = NULL;
+@@ -1757,6 +1568,8 @@ static int blk_revalidate_seq_zone(struc
+ if (!disk->zone_wplugs_hash)
+ return 0;
+
++ disk_zone_wplug_sync_wp_offset(disk, zone);
++
+ wp_offset = blk_zone_wp_offset(zone);
+ if (!wp_offset || wp_offset >= zone->capacity)
+ return 0;
+@@ -1893,6 +1706,7 @@ int blk_revalidate_disk_zones(struct gen
+ memalloc_noio_restore(noio_flag);
+ return ret;
+ }
++
+ ret = disk->fops->report_zones(disk, 0, UINT_MAX,
+ blk_revalidate_zone_cb, &args);
+ if (!ret) {
+--- a/include/linux/blkdev.h
++++ b/include/linux/blkdev.h
+@@ -200,8 +200,6 @@ struct gendisk {
+ spinlock_t zone_wplugs_lock;
+ struct mempool_s *zone_wplugs_pool;
+ struct hlist_head *zone_wplugs_hash;
+- struct list_head zone_wplugs_err_list;
+- struct work_struct zone_wplugs_work;
+ struct workqueue_struct *zone_wplugs_wq;
+ #endif /* CONFIG_BLK_DEV_ZONED */
+
--- /dev/null
+From 4122fef16b172f7c1838fcf74340268c86ed96db Mon Sep 17 00:00:00 2001
+From: Damien Le Moal <dlemoal@kernel.org>
+Date: Thu, 7 Nov 2024 15:54:38 +0900
+Subject: block: Switch to using refcount_t for zone write plugs
+
+From: Damien Le Moal <dlemoal@kernel.org>
+
+commit 4122fef16b172f7c1838fcf74340268c86ed96db upstream.
+
+Replace the raw atomic_t reference counting of zone write plugs with a
+refcount_t. No functional changes.
+
+Reported-by: kernel test robot <lkp@intel.com>
+Closes: https://lore.kernel.org/oe-kbuild-all/202411050650.ilIZa8S7-lkp@intel.com/
+Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Link: https://lore.kernel.org/r/20241107065438.236348-1-dlemoal@kernel.org
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ block/blk-zoned.c | 20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+--- a/block/blk-zoned.c
++++ b/block/blk-zoned.c
+@@ -18,7 +18,7 @@
+ #include <linux/vmalloc.h>
+ #include <linux/sched/mm.h>
+ #include <linux/spinlock.h>
+-#include <linux/atomic.h>
++#include <linux/refcount.h>
+ #include <linux/mempool.h>
+
+ #include "blk.h"
+@@ -64,7 +64,7 @@ static const char *const zone_cond_name[
+ struct blk_zone_wplug {
+ struct hlist_node node;
+ struct list_head link;
+- atomic_t ref;
++ refcount_t ref;
+ spinlock_t lock;
+ unsigned int flags;
+ unsigned int zone_no;
+@@ -417,7 +417,7 @@ static struct blk_zone_wplug *disk_get_z
+
+ hlist_for_each_entry_rcu(zwplug, &disk->zone_wplugs_hash[idx], node) {
+ if (zwplug->zone_no == zno &&
+- atomic_inc_not_zero(&zwplug->ref)) {
++ refcount_inc_not_zero(&zwplug->ref)) {
+ rcu_read_unlock();
+ return zwplug;
+ }
+@@ -438,7 +438,7 @@ static void disk_free_zone_wplug_rcu(str
+
+ static inline void disk_put_zone_wplug(struct blk_zone_wplug *zwplug)
+ {
+- if (atomic_dec_and_test(&zwplug->ref)) {
++ if (refcount_dec_and_test(&zwplug->ref)) {
+ WARN_ON_ONCE(!bio_list_empty(&zwplug->bio_list));
+ WARN_ON_ONCE(!list_empty(&zwplug->link));
+ WARN_ON_ONCE(!(zwplug->flags & BLK_ZONE_WPLUG_UNHASHED));
+@@ -469,7 +469,7 @@ static inline bool disk_should_remove_zo
+ * taken when the plug was allocated and another reference taken by the
+ * caller context).
+ */
+- if (atomic_read(&zwplug->ref) > 2)
++ if (refcount_read(&zwplug->ref) > 2)
+ return false;
+
+ /* We can remove zone write plugs for zones that are empty or full. */
+@@ -539,7 +539,7 @@ again:
+
+ INIT_HLIST_NODE(&zwplug->node);
+ INIT_LIST_HEAD(&zwplug->link);
+- atomic_set(&zwplug->ref, 2);
++ refcount_set(&zwplug->ref, 2);
+ spin_lock_init(&zwplug->lock);
+ zwplug->flags = 0;
+ zwplug->zone_no = zno;
+@@ -630,7 +630,7 @@ static inline void disk_zone_wplug_set_e
+ * finished.
+ */
+ zwplug->flags |= BLK_ZONE_WPLUG_ERROR;
+- atomic_inc(&zwplug->ref);
++ refcount_inc(&zwplug->ref);
+
+ spin_lock_irqsave(&disk->zone_wplugs_lock, flags);
+ list_add_tail(&zwplug->link, &disk->zone_wplugs_err_list);
+@@ -1105,7 +1105,7 @@ static void disk_zone_wplug_schedule_bio
+ * reference we take here.
+ */
+ WARN_ON_ONCE(!(zwplug->flags & BLK_ZONE_WPLUG_PLUGGED));
+- atomic_inc(&zwplug->ref);
++ refcount_inc(&zwplug->ref);
+ queue_work(disk->zone_wplugs_wq, &zwplug->bio_work);
+ }
+
+@@ -1450,7 +1450,7 @@ static void disk_destroy_zone_wplugs_has
+ while (!hlist_empty(&disk->zone_wplugs_hash[i])) {
+ zwplug = hlist_entry(disk->zone_wplugs_hash[i].first,
+ struct blk_zone_wplug, node);
+- atomic_inc(&zwplug->ref);
++ refcount_inc(&zwplug->ref);
+ disk_remove_zone_wplug(disk, zwplug);
+ disk_put_zone_wplug(zwplug);
+ }
+@@ -1876,7 +1876,7 @@ int queue_zone_wplugs_show(void *data, s
+ spin_lock_irqsave(&zwplug->lock, flags);
+ zwp_zone_no = zwplug->zone_no;
+ zwp_flags = zwplug->flags;
+- zwp_ref = atomic_read(&zwplug->ref);
++ zwp_ref = refcount_read(&zwplug->ref);
+ zwp_wp_offset = zwplug->wp_offset;
+ zwp_bio_list_size = bio_list_size(&zwplug->bio_list);
+ spin_unlock_irqrestore(&zwplug->lock, flags);
--- /dev/null
+From cae005670887cb07ceafc25bb32e221e56286488 Mon Sep 17 00:00:00 2001
+From: Damien Le Moal <dlemoal@kernel.org>
+Date: Mon, 9 Dec 2024 21:23:54 +0900
+Subject: block: Use a zone write plug BIO work for REQ_NOWAIT BIOs
+
+From: Damien Le Moal <dlemoal@kernel.org>
+
+commit cae005670887cb07ceafc25bb32e221e56286488 upstream.
+
+For zoned block devices, a write BIO issued to a zone that has no
+on-going writes will be prepared for execution and allowed to execute
+immediately by blk_zone_wplug_handle_write() (called from
+blk_zone_plug_bio()). However, if this BIO specifies REQ_NOWAIT, the
+allocation of a request for its execution in blk_mq_submit_bio() may
+fail after blk_zone_plug_bio() completed, marking the target zone of the
+BIO as plugged. When this BIO is retried later on, it will be blocked as
+the zone write plug of the target zone is in a plugged state without any
+on-going write operation (completion of write operations trigger
+unplugging of the next write BIOs for a zone). This leads to a BIO that
+is stuck in a zone write plug and never completes, which results in
+various issues such as hung tasks.
+
+Avoid this problem by always executing REQ_NOWAIT write BIOs using the
+BIO work of a zone write plug. This ensure that we never block the BIO
+issuer and can thus safely ignore the REQ_NOWAIT flag when executing the
+BIO from the zone write plug BIO work.
+
+Since such BIO may be the first write BIO issued to a zone with no
+on-going write, modify disk_zone_wplug_add_bio() to schedule the zone
+write plug BIO work if the write plug is not already marked with the
+BLK_ZONE_WPLUG_PLUGGED flag. This scheduling is otherwise not necessary
+as the completion of the on-going write for the zone will schedule the
+execution of the next plugged BIOs.
+
+blk_zone_wplug_handle_write() is also fixed to better handle zone write
+plug allocation failures for REQ_NOWAIT BIOs by failing a write BIO
+using bio_wouldblock_error() instead of bio_io_error().
+
+Reported-by: Bart Van Assche <bvanassche@acm.org>
+Fixes: dd291d77cc90 ("block: Introduce zone write plugging")
+Cc: stable@vger.kernel.org
+Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
+Link: https://lore.kernel.org/r/20241209122357.47838-2-dlemoal@kernel.org
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ block/blk-zoned.c | 62 ++++++++++++++++++++++++++++++++++++------------------
+ 1 file changed, 42 insertions(+), 20 deletions(-)
+
+--- a/block/blk-zoned.c
++++ b/block/blk-zoned.c
+@@ -759,9 +759,25 @@ static bool blk_zone_wplug_handle_reset_
+ return false;
+ }
+
+-static inline void blk_zone_wplug_add_bio(struct blk_zone_wplug *zwplug,
+- struct bio *bio, unsigned int nr_segs)
++static void disk_zone_wplug_schedule_bio_work(struct gendisk *disk,
++ struct blk_zone_wplug *zwplug)
++{
++ /*
++ * Take a reference on the zone write plug and schedule the submission
++ * of the next plugged BIO. blk_zone_wplug_bio_work() will release the
++ * reference we take here.
++ */
++ WARN_ON_ONCE(!(zwplug->flags & BLK_ZONE_WPLUG_PLUGGED));
++ refcount_inc(&zwplug->ref);
++ queue_work(disk->zone_wplugs_wq, &zwplug->bio_work);
++}
++
++static inline void disk_zone_wplug_add_bio(struct gendisk *disk,
++ struct blk_zone_wplug *zwplug,
++ struct bio *bio, unsigned int nr_segs)
+ {
++ bool schedule_bio_work = false;
++
+ /*
+ * Grab an extra reference on the BIO request queue usage counter.
+ * This reference will be reused to submit a request for the BIO for
+@@ -778,6 +794,16 @@ static inline void blk_zone_wplug_add_bi
+ bio_clear_polled(bio);
+
+ /*
++ * REQ_NOWAIT BIOs are always handled using the zone write plug BIO
++ * work, which can block. So clear the REQ_NOWAIT flag and schedule the
++ * work if this is the first BIO we are plugging.
++ */
++ if (bio->bi_opf & REQ_NOWAIT) {
++ schedule_bio_work = !(zwplug->flags & BLK_ZONE_WPLUG_PLUGGED);
++ bio->bi_opf &= ~REQ_NOWAIT;
++ }
++
++ /*
+ * Reuse the poll cookie field to store the number of segments when
+ * split to the hardware limits.
+ */
+@@ -790,6 +816,11 @@ static inline void blk_zone_wplug_add_bi
+ * at the tail of the list to preserve the sequential write order.
+ */
+ bio_list_add(&zwplug->bio_list, bio);
++
++ zwplug->flags |= BLK_ZONE_WPLUG_PLUGGED;
++
++ if (schedule_bio_work)
++ disk_zone_wplug_schedule_bio_work(disk, zwplug);
+ }
+
+ /*
+@@ -983,7 +1014,10 @@ static bool blk_zone_wplug_handle_write(
+
+ zwplug = disk_get_and_lock_zone_wplug(disk, sector, gfp_mask, &flags);
+ if (!zwplug) {
+- bio_io_error(bio);
++ if (bio->bi_opf & REQ_NOWAIT)
++ bio_wouldblock_error(bio);
++ else
++ bio_io_error(bio);
+ return true;
+ }
+
+@@ -992,9 +1026,11 @@ static bool blk_zone_wplug_handle_write(
+
+ /*
+ * If the zone is already plugged or has a pending error, add the BIO
+- * to the plug BIO list. Otherwise, plug and let the BIO execute.
++ * to the plug BIO list. Do the same for REQ_NOWAIT BIOs to ensure that
++ * we will not see a BLK_STS_AGAIN failure if we let the BIO execute.
++ * Otherwise, plug and let the BIO execute.
+ */
+- if (zwplug->flags & BLK_ZONE_WPLUG_BUSY)
++ if (zwplug->flags & BLK_ZONE_WPLUG_BUSY || (bio->bi_opf & REQ_NOWAIT))
+ goto plug;
+
+ /*
+@@ -1011,8 +1047,7 @@ static bool blk_zone_wplug_handle_write(
+ return false;
+
+ plug:
+- zwplug->flags |= BLK_ZONE_WPLUG_PLUGGED;
+- blk_zone_wplug_add_bio(zwplug, bio, nr_segs);
++ disk_zone_wplug_add_bio(disk, zwplug, bio, nr_segs);
+
+ spin_unlock_irqrestore(&zwplug->lock, flags);
+
+@@ -1096,19 +1131,6 @@ bool blk_zone_plug_bio(struct bio *bio,
+ }
+ EXPORT_SYMBOL_GPL(blk_zone_plug_bio);
+
+-static void disk_zone_wplug_schedule_bio_work(struct gendisk *disk,
+- struct blk_zone_wplug *zwplug)
+-{
+- /*
+- * Take a reference on the zone write plug and schedule the submission
+- * of the next plugged BIO. blk_zone_wplug_bio_work() will release the
+- * reference we take here.
+- */
+- WARN_ON_ONCE(!(zwplug->flags & BLK_ZONE_WPLUG_PLUGGED));
+- refcount_inc(&zwplug->ref);
+- queue_work(disk->zone_wplugs_wq, &zwplug->bio_work);
+-}
+-
+ static void disk_zone_wplug_unplug_bio(struct gendisk *disk,
+ struct blk_zone_wplug *zwplug)
+ {
--- /dev/null
+From ef1b808e3b7c98612feceedf985c2fbbeb28f956 Mon Sep 17 00:00:00 2001
+From: Jann Horn <jannh@google.com>
+Date: Tue, 10 Dec 2024 17:32:13 +0100
+Subject: bpf: Fix UAF via mismatching bpf_prog/attachment RCU flavors
+
+From: Jann Horn <jannh@google.com>
+
+commit ef1b808e3b7c98612feceedf985c2fbbeb28f956 upstream.
+
+Uprobes always use bpf_prog_run_array_uprobe() under tasks-trace-RCU
+protection. But it is possible to attach a non-sleepable BPF program to a
+uprobe, and non-sleepable BPF programs are freed via normal RCU (see
+__bpf_prog_put_noref()). This leads to UAF of the bpf_prog because a normal
+RCU grace period does not imply a tasks-trace-RCU grace period.
+
+Fix it by explicitly waiting for a tasks-trace-RCU grace period after
+removing the attachment of a bpf_prog to a perf_event.
+
+Fixes: 8c7dcb84e3b7 ("bpf: implement sleepable uprobes by chaining gps")
+Suggested-by: Andrii Nakryiko <andrii@kernel.org>
+Suggested-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Jann Horn <jannh@google.com>
+Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/bpf/20241210-bpf-fix-actual-uprobe-uaf-v1-1-19439849dd44@google.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/trace/bpf_trace.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/kernel/trace/bpf_trace.c
++++ b/kernel/trace/bpf_trace.c
+@@ -2223,6 +2223,13 @@ void perf_event_detach_bpf_prog(struct p
+ bpf_prog_array_free_sleepable(old_array);
+ }
+
++ /*
++ * It could be that the bpf_prog is not sleepable (and will be freed
++ * via normal RCU), but is called from a point that supports sleepable
++ * programs and uses tasks-trace-RCU.
++ */
++ synchronize_rcu_tasks_trace();
++
+ bpf_prog_put(event->prog);
+ event->prog = NULL;
+
--- /dev/null
+From 2eb75f86d52565367211c51334d15fe672633085 Mon Sep 17 00:00:00 2001
+From: Christian Marangi <ansuelsmth@gmail.com>
+Date: Sat, 16 Nov 2024 11:56:53 +0100
+Subject: clk: en7523: Fix wrong BUS clock for EN7581
+
+From: Christian Marangi <ansuelsmth@gmail.com>
+
+commit 2eb75f86d52565367211c51334d15fe672633085 upstream.
+
+The Documentation for EN7581 had a typo and still referenced the EN7523
+BUS base source frequency. This was in conflict with a different page in
+the Documentration that state that the BUS runs at 300MHz (600MHz source
+with divisor set to 2) and the actual watchdog that tick at half the BUS
+clock (150MHz). This was verified with the watchdog by timing the
+seconds that the system takes to reboot (due too watchdog) and by
+operating on different values of the BUS divisor.
+
+The correct values for source of BUS clock are 600MHz and 540MHz.
+
+This was also confirmed by Airoha.
+
+Cc: stable@vger.kernel.org
+Fixes: 66bc47326ce2 ("clk: en7523: Add EN7581 support")
+Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
+Link: https://lore.kernel.org/r/20241116105710.19748-1-ansuelsmth@gmail.com
+Acked-by: Lorenzo Bianconi <lorenzo@kernel.org>
+Signed-off-by: Stephen Boyd <sboyd@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/clk/clk-en7523.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/clk/clk-en7523.c
++++ b/drivers/clk/clk-en7523.c
+@@ -92,6 +92,7 @@ static const u32 slic_base[] = { 1000000
+ static const u32 npu_base[] = { 333000000, 400000000, 500000000 };
+ /* EN7581 */
+ static const u32 emi7581_base[] = { 540000000, 480000000, 400000000, 300000000 };
++static const u32 bus7581_base[] = { 600000000, 540000000 };
+ static const u32 npu7581_base[] = { 800000000, 750000000, 720000000, 600000000 };
+ static const u32 crypto_base[] = { 540000000, 480000000 };
+
+@@ -227,8 +228,8 @@ static const struct en_clk_desc en7581_b
+ .base_reg = REG_BUS_CLK_DIV_SEL,
+ .base_bits = 1,
+ .base_shift = 8,
+- .base_values = bus_base,
+- .n_base_values = ARRAY_SIZE(bus_base),
++ .base_values = bus7581_base,
++ .n_base_values = ARRAY_SIZE(bus7581_base),
+
+ .div_bits = 3,
+ .div_shift = 0,
--- /dev/null
+From cd26cd65476711e2c69e0a049c0eeef4b743f5ac Mon Sep 17 00:00:00 2001
+From: Chenghai Huang <huangchenghai2@huawei.com>
+Date: Sat, 30 Nov 2024 16:01:31 +0800
+Subject: crypto: hisilicon/debugfs - fix the struct pointer incorrectly offset problem
+
+From: Chenghai Huang <huangchenghai2@huawei.com>
+
+commit cd26cd65476711e2c69e0a049c0eeef4b743f5ac upstream.
+
+Offset based on (id * size) is wrong for sqc and cqc.
+(*sqc/*cqc + 1) can already offset sizeof(struct(Xqc)) length.
+
+Fixes: 15f112f9cef5 ("crypto: hisilicon/debugfs - mask the unnecessary info from the dump")
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Chenghai Huang <huangchenghai2@huawei.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/crypto/hisilicon/debugfs.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/crypto/hisilicon/debugfs.c b/drivers/crypto/hisilicon/debugfs.c
+index 1b9b7bccdeff..45e130b901eb 100644
+--- a/drivers/crypto/hisilicon/debugfs.c
++++ b/drivers/crypto/hisilicon/debugfs.c
+@@ -192,7 +192,7 @@ static int qm_sqc_dump(struct hisi_qm *qm, char *s, char *name)
+
+ down_read(&qm->qps_lock);
+ if (qm->sqc) {
+- memcpy(&sqc, qm->sqc + qp_id * sizeof(struct qm_sqc), sizeof(struct qm_sqc));
++ memcpy(&sqc, qm->sqc + qp_id, sizeof(struct qm_sqc));
+ sqc.base_h = cpu_to_le32(QM_XQC_ADDR_MASK);
+ sqc.base_l = cpu_to_le32(QM_XQC_ADDR_MASK);
+ dump_show(qm, &sqc, sizeof(struct qm_sqc), "SOFT SQC");
+@@ -229,7 +229,7 @@ static int qm_cqc_dump(struct hisi_qm *qm, char *s, char *name)
+
+ down_read(&qm->qps_lock);
+ if (qm->cqc) {
+- memcpy(&cqc, qm->cqc + qp_id * sizeof(struct qm_cqc), sizeof(struct qm_cqc));
++ memcpy(&cqc, qm->cqc + qp_id, sizeof(struct qm_cqc));
+ cqc.base_h = cpu_to_le32(QM_XQC_ADDR_MASK);
+ cqc.base_l = cpu_to_le32(QM_XQC_ADDR_MASK);
+ dump_show(qm, &cqc, sizeof(struct qm_cqc), "SOFT CQC");
+--
+2.47.1
+
--- /dev/null
+From b76b840fd93374240b59825f1ab8e2f5c9907acb Mon Sep 17 00:00:00 2001
+From: Damien Le Moal <dlemoal@kernel.org>
+Date: Mon, 9 Dec 2024 21:23:56 +0900
+Subject: dm: Fix dm-zoned-reclaim zone write pointer alignment
+
+From: Damien Le Moal <dlemoal@kernel.org>
+
+commit b76b840fd93374240b59825f1ab8e2f5c9907acb upstream.
+
+The zone reclaim processing of the dm-zoned device mapper uses
+blkdev_issue_zeroout() to align the write pointer of a zone being used
+for reclaiming another zone, to write the valid data blocks from the
+zone being reclaimed at the same position relative to the zone start in
+the reclaim target zone.
+
+The first call to blkdev_issue_zeroout() will try to use hardware
+offload using a REQ_OP_WRITE_ZEROES operation if the device reports a
+non-zero max_write_zeroes_sectors queue limit. If this operation fails
+because of the lack of hardware support, blkdev_issue_zeroout() falls
+back to using a regular write operation with the zero-page as buffer.
+Currently, such REQ_OP_WRITE_ZEROES failure is automatically handled by
+the block layer zone write plugging code which will execute a report
+zones operation to ensure that the write pointer of the target zone of
+the failed operation has not changed and to "rewind" the zone write
+pointer offset of the target zone as it was advanced when the write zero
+operation was submitted. So the REQ_OP_WRITE_ZEROES failure does not
+cause any issue and blkdev_issue_zeroout() works as expected.
+
+However, since the automatic recovery of zone write pointers by the zone
+write plugging code can potentially cause deadlocks with queue freeze
+operations, a different recovery must be implemented in preparation for
+the removal of zone write plugging report zones based recovery.
+
+Do this by introducing the new function blk_zone_issue_zeroout(). This
+function first calls blkdev_issue_zeroout() with the flag
+BLKDEV_ZERO_NOFALLBACK to intercept failures on the first execution
+which attempt to use the device hardware offload with the
+REQ_OP_WRITE_ZEROES operation. If this attempt fails, a report zone
+operation is issued to restore the zone write pointer offset of the
+target zone to the correct position and blkdev_issue_zeroout() is called
+again without the BLKDEV_ZERO_NOFALLBACK flag. The report zones
+operation performing this recovery is implemented using the helper
+function disk_zone_sync_wp_offset() which calls the gendisk report_zones
+file operation with the callback disk_report_zones_cb(). This callback
+updates the target write pointer offset of the target zone using the new
+function disk_zone_wplug_sync_wp_offset().
+
+dmz_reclaim_align_wp() is modified to change its call to
+blkdev_issue_zeroout() to a call to blk_zone_issue_zeroout() without any
+other change needed as the two functions are functionnally equivalent.
+
+Fixes: dd291d77cc90 ("block: Introduce zone write plugging")
+Cc: stable@vger.kernel.org
+Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Acked-by: Mike Snitzer <snitzer@kernel.org>
+Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
+Link: https://lore.kernel.org/r/20241209122357.47838-4-dlemoal@kernel.org
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ block/blk-zoned.c | 141 +++++++++++++++++++++++++++++++++++-------
+ drivers/md/dm-zoned-reclaim.c | 6 -
+ include/linux/blkdev.h | 3
+ 3 files changed, 124 insertions(+), 26 deletions(-)
+
+--- a/block/blk-zoned.c
++++ b/block/blk-zoned.c
+@@ -115,6 +115,30 @@ const char *blk_zone_cond_str(enum blk_z
+ }
+ EXPORT_SYMBOL_GPL(blk_zone_cond_str);
+
++struct disk_report_zones_cb_args {
++ struct gendisk *disk;
++ report_zones_cb user_cb;
++ void *user_data;
++};
++
++static void disk_zone_wplug_sync_wp_offset(struct gendisk *disk,
++ struct blk_zone *zone);
++
++static int disk_report_zones_cb(struct blk_zone *zone, unsigned int idx,
++ void *data)
++{
++ struct disk_report_zones_cb_args *args = data;
++ struct gendisk *disk = args->disk;
++
++ if (disk->zone_wplugs_hash)
++ disk_zone_wplug_sync_wp_offset(disk, zone);
++
++ if (!args->user_cb)
++ return 0;
++
++ return args->user_cb(zone, idx, args->user_data);
++}
++
+ /**
+ * blkdev_report_zones - Get zones information
+ * @bdev: Target block device
+@@ -707,6 +731,58 @@ static void disk_zone_wplug_set_wp_offse
+ spin_unlock_irqrestore(&zwplug->lock, flags);
+ }
+
++static unsigned int blk_zone_wp_offset(struct blk_zone *zone)
++{
++ switch (zone->cond) {
++ case BLK_ZONE_COND_IMP_OPEN:
++ case BLK_ZONE_COND_EXP_OPEN:
++ case BLK_ZONE_COND_CLOSED:
++ return zone->wp - zone->start;
++ case BLK_ZONE_COND_FULL:
++ return zone->len;
++ case BLK_ZONE_COND_EMPTY:
++ return 0;
++ case BLK_ZONE_COND_NOT_WP:
++ case BLK_ZONE_COND_OFFLINE:
++ case BLK_ZONE_COND_READONLY:
++ default:
++ /*
++ * Conventional, offline and read-only zones do not have a valid
++ * write pointer.
++ */
++ return UINT_MAX;
++ }
++}
++
++static void disk_zone_wplug_sync_wp_offset(struct gendisk *disk,
++ struct blk_zone *zone)
++{
++ struct blk_zone_wplug *zwplug;
++ unsigned long flags;
++
++ zwplug = disk_get_zone_wplug(disk, zone->start);
++ if (!zwplug)
++ return;
++
++ spin_lock_irqsave(&zwplug->lock, flags);
++ if (zwplug->flags & BLK_ZONE_WPLUG_ERROR)
++ disk_zone_wplug_set_wp_offset(disk, zwplug,
++ blk_zone_wp_offset(zone));
++ spin_unlock_irqrestore(&zwplug->lock, flags);
++
++ disk_put_zone_wplug(zwplug);
++}
++
++static int disk_zone_sync_wp_offset(struct gendisk *disk, sector_t sector)
++{
++ struct disk_report_zones_cb_args args = {
++ .disk = disk,
++ };
++
++ return disk->fops->report_zones(disk, sector, 1,
++ disk_report_zones_cb, &args);
++}
++
+ static bool blk_zone_wplug_handle_reset_or_finish(struct bio *bio,
+ unsigned int wp_offset)
+ {
+@@ -1284,29 +1360,6 @@ put_zwplug:
+ disk_put_zone_wplug(zwplug);
+ }
+
+-static unsigned int blk_zone_wp_offset(struct blk_zone *zone)
+-{
+- switch (zone->cond) {
+- case BLK_ZONE_COND_IMP_OPEN:
+- case BLK_ZONE_COND_EXP_OPEN:
+- case BLK_ZONE_COND_CLOSED:
+- return zone->wp - zone->start;
+- case BLK_ZONE_COND_FULL:
+- return zone->len;
+- case BLK_ZONE_COND_EMPTY:
+- return 0;
+- case BLK_ZONE_COND_NOT_WP:
+- case BLK_ZONE_COND_OFFLINE:
+- case BLK_ZONE_COND_READONLY:
+- default:
+- /*
+- * Conventional, offline and read-only zones do not have a valid
+- * write pointer.
+- */
+- return UINT_MAX;
+- }
+-}
+-
+ static int blk_zone_wplug_report_zone_cb(struct blk_zone *zone,
+ unsigned int idx, void *data)
+ {
+@@ -1876,6 +1929,48 @@ int blk_revalidate_disk_zones(struct gen
+ }
+ EXPORT_SYMBOL_GPL(blk_revalidate_disk_zones);
+
++/**
++ * blk_zone_issue_zeroout - zero-fill a block range in a zone
++ * @bdev: blockdev to write
++ * @sector: start sector
++ * @nr_sects: number of sectors to write
++ * @gfp_mask: memory allocation flags (for bio_alloc)
++ *
++ * Description:
++ * Zero-fill a block range in a zone (@sector must be equal to the zone write
++ * pointer), handling potential errors due to the (initially unknown) lack of
++ * hardware offload (See blkdev_issue_zeroout()).
++ */
++int blk_zone_issue_zeroout(struct block_device *bdev, sector_t sector,
++ sector_t nr_sects, gfp_t gfp_mask)
++{
++ int ret;
++
++ if (WARN_ON_ONCE(!bdev_is_zoned(bdev)))
++ return -EIO;
++
++ ret = blkdev_issue_zeroout(bdev, sector, nr_sects, gfp_mask,
++ BLKDEV_ZERO_NOFALLBACK);
++ if (ret != -EOPNOTSUPP)
++ return ret;
++
++ /*
++ * The failed call to blkdev_issue_zeroout() advanced the zone write
++ * pointer. Undo this using a report zone to update the zone write
++ * pointer to the correct current value.
++ */
++ ret = disk_zone_sync_wp_offset(bdev->bd_disk, sector);
++ if (ret != 1)
++ return ret < 0 ? ret : -EIO;
++
++ /*
++ * Retry without BLKDEV_ZERO_NOFALLBACK to force the fallback to a
++ * regular write with zero-pages.
++ */
++ return blkdev_issue_zeroout(bdev, sector, nr_sects, gfp_mask, 0);
++}
++EXPORT_SYMBOL_GPL(blk_zone_issue_zeroout);
++
+ #ifdef CONFIG_BLK_DEBUG_FS
+
+ int queue_zone_wplugs_show(void *data, struct seq_file *m)
+--- a/drivers/md/dm-zoned-reclaim.c
++++ b/drivers/md/dm-zoned-reclaim.c
+@@ -76,9 +76,9 @@ static int dmz_reclaim_align_wp(struct d
+ * pointer and the requested position.
+ */
+ nr_blocks = block - wp_block;
+- ret = blkdev_issue_zeroout(dev->bdev,
+- dmz_start_sect(zmd, zone) + dmz_blk2sect(wp_block),
+- dmz_blk2sect(nr_blocks), GFP_NOIO, 0);
++ ret = blk_zone_issue_zeroout(dev->bdev,
++ dmz_start_sect(zmd, zone) + dmz_blk2sect(wp_block),
++ dmz_blk2sect(nr_blocks), GFP_NOIO);
+ if (ret) {
+ dmz_dev_err(dev,
+ "Align zone %u wp %llu to %llu (wp+%u) blocks failed %d",
+--- a/include/linux/blkdev.h
++++ b/include/linux/blkdev.h
+@@ -1386,6 +1386,9 @@ static inline bool bdev_is_zone_start(st
+ return bdev_offset_from_zone_start(bdev, sector) == 0;
+ }
+
++int blk_zone_issue_zeroout(struct block_device *bdev, sector_t sector,
++ sector_t nr_sects, gfp_t gfp_mask);
++
+ static inline int queue_dma_alignment(const struct request_queue *q)
+ {
+ return q->limits.dma_alignment;
--- /dev/null
+From 4011b351b1b5a953aaa7c6b3915f908b3cc1be96 Mon Sep 17 00:00:00 2001
+From: Miguel Ojeda <ojeda@kernel.org>
+Date: Tue, 26 Nov 2024 00:33:32 +0100
+Subject: drm/panic: remove spurious empty line to clean warning
+
+From: Miguel Ojeda <ojeda@kernel.org>
+
+commit 4011b351b1b5a953aaa7c6b3915f908b3cc1be96 upstream.
+
+Clippy in the upcoming Rust 1.83.0 spots a spurious empty line since the
+`clippy::empty_line_after_doc_comments` warning is now enabled by default
+given it is part of the `suspicious` group [1]:
+
+ error: empty line after doc comment
+ --> drivers/gpu/drm/drm_panic_qr.rs:931:1
+ |
+ 931 | / /// They must remain valid for the duration of the function call.
+ 932 | |
+ | |_
+ 933 | #[no_mangle]
+ 934 | / pub unsafe extern "C" fn drm_panic_qr_generate(
+ 935 | | url: *const i8,
+ 936 | | data: *mut u8,
+ 937 | | data_len: usize,
+ ... |
+ 940 | | tmp_size: usize,
+ 941 | | ) -> u8 {
+ | |_______- the comment documents this function
+ |
+ = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#empty_line_after_doc_comments
+ = note: `-D clippy::empty-line-after-doc-comments` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::empty_line_after_doc_comments)]`
+ = help: if the empty line is unintentional remove it
+
+Thus remove the empty line.
+
+Cc: stable@vger.kernel.org
+Fixes: cb5164ac43d0 ("drm/panic: Add a QR code panic screen")
+Link: https://github.com/rust-lang/rust-clippy/pull/13091 [1]
+Reviewed-by: Jocelyn Falempe <jfalempe@redhat.com>
+Link: https://lore.kernel.org/r/20241125233332.697497-1-ojeda@kernel.org
+Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/drm_panic_qr.rs | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/drm_panic_qr.rs b/drivers/gpu/drm/drm_panic_qr.rs
+index 09500cddc009..ef2d490965ba 100644
+--- a/drivers/gpu/drm/drm_panic_qr.rs
++++ b/drivers/gpu/drm/drm_panic_qr.rs
+@@ -929,7 +929,6 @@ impl QrImage<'_> {
+ /// * `tmp` must be valid for reading and writing for `tmp_size` bytes.
+ ///
+ /// They must remain valid for the duration of the function call.
+-
+ #[no_mangle]
+ pub unsafe extern "C" fn drm_panic_qr_generate(
+ url: *const i8,
+--
+2.47.1
+
--- /dev/null
+From c0ec4890d6454980c53c3cc164140115c4a671f2 Mon Sep 17 00:00:00 2001
+From: Alan Borzeszkowski <alan.borzeszkowski@linux.intel.com>
+Date: Wed, 4 Dec 2024 09:04:14 +0200
+Subject: gpio: graniterapids: Check if GPIO line can be used for IRQs
+
+From: Alan Borzeszkowski <alan.borzeszkowski@linux.intel.com>
+
+commit c0ec4890d6454980c53c3cc164140115c4a671f2 upstream.
+
+GPIO line can only be used as interrupt if its INTSEL register is
+programmed by the BIOS.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Alan Borzeszkowski <alan.borzeszkowski@linux.intel.com>
+Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Acked-by: Andy Shevchenko <andy@kernel.org>
+Link: https://lore.kernel.org/r/20241204070415.1034449-7-mika.westerberg@linux.intel.com
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpio/gpio-graniterapids.c | 15 ++++++++++++---
+ 1 file changed, 12 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpio/gpio-graniterapids.c b/drivers/gpio/gpio-graniterapids.c
+index b12abe77299c..3a972d460fe2 100644
+--- a/drivers/gpio/gpio-graniterapids.c
++++ b/drivers/gpio/gpio-graniterapids.c
+@@ -39,6 +39,7 @@
+
+ #define GNR_CFG_DW_HOSTSW_MODE BIT(27)
+ #define GNR_CFG_DW_RX_MASK GENMASK(23, 22)
++#define GNR_CFG_DW_INTSEL_MASK GENMASK(21, 14)
+ #define GNR_CFG_DW_RX_DISABLE FIELD_PREP(GNR_CFG_DW_RX_MASK, 2)
+ #define GNR_CFG_DW_RX_EDGE FIELD_PREP(GNR_CFG_DW_RX_MASK, 1)
+ #define GNR_CFG_DW_RX_LEVEL FIELD_PREP(GNR_CFG_DW_RX_MASK, 0)
+@@ -227,10 +228,18 @@ static void gnr_gpio_irq_unmask(struct irq_data *d)
+ static int gnr_gpio_irq_set_type(struct irq_data *d, unsigned int type)
+ {
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+- irq_hw_number_t pin = irqd_to_hwirq(d);
+- u32 mask = GNR_CFG_DW_RX_MASK;
++ struct gnr_gpio *priv = gpiochip_get_data(gc);
++ irq_hw_number_t hwirq = irqd_to_hwirq(d);
++ u32 reg;
+ u32 set;
+
++ /* Allow interrupts only if Interrupt Select field is non-zero */
++ reg = readl(gnr_gpio_get_padcfg_addr(priv, hwirq));
++ if (!(reg & GNR_CFG_DW_INTSEL_MASK)) {
++ dev_dbg(gc->parent, "GPIO %lu cannot be used as IRQ", hwirq);
++ return -EPERM;
++ }
++
+ /* Falling edge and level low triggers not supported by the GPIO controller */
+ switch (type) {
+ case IRQ_TYPE_NONE:
+@@ -248,7 +257,7 @@ static int gnr_gpio_irq_set_type(struct irq_data *d, unsigned int type)
+ return -EINVAL;
+ }
+
+- return gnr_gpio_configure_line(gc, pin, mask, set);
++ return gnr_gpio_configure_line(gc, hwirq, GNR_CFG_DW_RX_MASK, set);
+ }
+
+ static const struct irq_chip gnr_gpio_irq_chip = {
+--
+2.47.1
+
--- /dev/null
+From 0588504d28dedde6789aec17a6ece6fa8e477725 Mon Sep 17 00:00:00 2001
+From: Alan Borzeszkowski <alan.borzeszkowski@linux.intel.com>
+Date: Wed, 4 Dec 2024 09:04:13 +0200
+Subject: gpio: graniterapids: Determine if GPIO pad can be used by driver
+
+From: Alan Borzeszkowski <alan.borzeszkowski@linux.intel.com>
+
+commit 0588504d28dedde6789aec17a6ece6fa8e477725 upstream.
+
+Add check of HOSTSW_MODE bit to determine if GPIO pad can be used by the
+driver.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Alan Borzeszkowski <alan.borzeszkowski@linux.intel.com>
+Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Acked-by: Andy Shevchenko <andy@kernel.org>
+Link: https://lore.kernel.org/r/20241204070415.1034449-6-mika.westerberg@linux.intel.com
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpio/gpio-graniterapids.c | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+--- a/drivers/gpio/gpio-graniterapids.c
++++ b/drivers/gpio/gpio-graniterapids.c
+@@ -37,6 +37,7 @@
+ #define GNR_GPI_STATUS_OFFSET 0x14
+ #define GNR_GPI_ENABLE_OFFSET 0x24
+
++#define GNR_CFG_DW_HOSTSW_MODE BIT(27)
+ #define GNR_CFG_DW_RX_MASK GENMASK(23, 22)
+ #define GNR_CFG_DW_RX_DISABLE FIELD_PREP(GNR_CFG_DW_RX_MASK, 2)
+ #define GNR_CFG_DW_RX_EDGE FIELD_PREP(GNR_CFG_DW_RX_MASK, 1)
+@@ -90,6 +91,20 @@ static int gnr_gpio_configure_line(struc
+ return 0;
+ }
+
++static int gnr_gpio_request(struct gpio_chip *gc, unsigned int gpio)
++{
++ struct gnr_gpio *priv = gpiochip_get_data(gc);
++ u32 dw;
++
++ dw = readl(gnr_gpio_get_padcfg_addr(priv, gpio));
++ if (!(dw & GNR_CFG_DW_HOSTSW_MODE)) {
++ dev_warn(gc->parent, "GPIO %u is not owned by host", gpio);
++ return -EBUSY;
++ }
++
++ return 0;
++}
++
+ static int gnr_gpio_get(struct gpio_chip *gc, unsigned int gpio)
+ {
+ const struct gnr_gpio *priv = gpiochip_get_data(gc);
+@@ -141,6 +156,7 @@ static int gnr_gpio_direction_output(str
+
+ static const struct gpio_chip gnr_gpio_chip = {
+ .owner = THIS_MODULE,
++ .request = gnr_gpio_request,
+ .get = gnr_gpio_get,
+ .set = gnr_gpio_set,
+ .get_direction = gnr_gpio_get_direction,
--- /dev/null
+From 0bb18e34abdde7bf58fca8542e2dcf621924ea19 Mon Sep 17 00:00:00 2001
+From: Alan Borzeszkowski <alan.borzeszkowski@linux.intel.com>
+Date: Wed, 4 Dec 2024 09:04:15 +0200
+Subject: gpio: graniterapids: Fix GPIO Ack functionality
+
+From: Alan Borzeszkowski <alan.borzeszkowski@linux.intel.com>
+
+commit 0bb18e34abdde7bf58fca8542e2dcf621924ea19 upstream.
+
+Interrupt status (GPI_IS) register is cleared by writing 1 to it, not 0.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Alan Borzeszkowski <alan.borzeszkowski@linux.intel.com>
+Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Acked-by: Andy Shevchenko <andy@kernel.org>
+Link: https://lore.kernel.org/r/20241204070415.1034449-8-mika.westerberg@linux.intel.com
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpio/gpio-graniterapids.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/gpio/gpio-graniterapids.c
++++ b/drivers/gpio/gpio-graniterapids.c
+@@ -166,7 +166,7 @@ static void gnr_gpio_irq_ack(struct irq_
+ guard(raw_spinlock_irqsave)(&priv->lock);
+
+ reg = readl(addr);
+- reg &= ~BIT(bit_idx);
++ reg |= BIT(bit_idx);
+ writel(reg, addr);
+ }
+
--- /dev/null
+From 7382d2f0e802077c36495e325da8d253a15fb441 Mon Sep 17 00:00:00 2001
+From: Alan Borzeszkowski <alan.borzeszkowski@linux.intel.com>
+Date: Wed, 4 Dec 2024 09:04:10 +0200
+Subject: gpio: graniterapids: Fix incorrect BAR assignment
+
+From: Alan Borzeszkowski <alan.borzeszkowski@linux.intel.com>
+
+commit 7382d2f0e802077c36495e325da8d253a15fb441 upstream.
+
+Base Address of vGPIO MMIO register is provided directly by the BIOS
+instead of using offsets. Update address assignment to reflect this
+change in driver.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Alan Borzeszkowski <alan.borzeszkowski@linux.intel.com>
+Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Acked-by: Andy Shevchenko <andy@kernel.org>
+Link: https://lore.kernel.org/r/20241204070415.1034449-3-mika.westerberg@linux.intel.com
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpio/gpio-graniterapids.c | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+--- a/drivers/gpio/gpio-graniterapids.c
++++ b/drivers/gpio/gpio-graniterapids.c
+@@ -32,7 +32,7 @@
+ #define GNR_PINS_PER_REG 32
+ #define GNR_NUM_REGS DIV_ROUND_UP(GNR_NUM_PINS, GNR_PINS_PER_REG)
+
+-#define GNR_CFG_BAR 0x00
++#define GNR_CFG_PADBAR 0x00
+ #define GNR_CFG_LOCK_OFFSET 0x04
+ #define GNR_GPI_STATUS_OFFSET 0x20
+ #define GNR_GPI_ENABLE_OFFSET 0x24
+@@ -50,6 +50,7 @@
+ * struct gnr_gpio - Intel Granite Rapids-D vGPIO driver state
+ * @gc: GPIO controller interface
+ * @reg_base: base address of the GPIO registers
++ * @pad_base: base address of the vGPIO pad configuration registers
+ * @ro_bitmap: bitmap of read-only pins
+ * @lock: guard the registers
+ * @pad_backup: backup of the register state for suspend
+@@ -57,6 +58,7 @@
+ struct gnr_gpio {
+ struct gpio_chip gc;
+ void __iomem *reg_base;
++ void __iomem *pad_base;
+ DECLARE_BITMAP(ro_bitmap, GNR_NUM_PINS);
+ raw_spinlock_t lock;
+ u32 pad_backup[];
+@@ -65,7 +67,7 @@ struct gnr_gpio {
+ static void __iomem *gnr_gpio_get_padcfg_addr(const struct gnr_gpio *priv,
+ unsigned int gpio)
+ {
+- return priv->reg_base + gpio * sizeof(u32);
++ return priv->pad_base + gpio * sizeof(u32);
+ }
+
+ static int gnr_gpio_configure_line(struct gpio_chip *gc, unsigned int gpio,
+@@ -292,6 +294,7 @@ static int gnr_gpio_probe(struct platfor
+ struct gnr_gpio *priv;
+ void __iomem *regs;
+ int irq, ret;
++ u32 offset;
+
+ priv = devm_kzalloc(dev, struct_size(priv, pad_backup, num_backup_pins), GFP_KERNEL);
+ if (!priv)
+@@ -303,6 +306,10 @@ static int gnr_gpio_probe(struct platfor
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
++ priv->reg_base = regs;
++ offset = readl(priv->reg_base + GNR_CFG_PADBAR);
++ priv->pad_base = priv->reg_base + offset;
++
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+@@ -312,8 +319,6 @@ static int gnr_gpio_probe(struct platfor
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to request interrupt\n");
+
+- priv->reg_base = regs + readl(regs + GNR_CFG_BAR);
+-
+ gnr_gpio_init_pin_ro_bits(dev, priv->reg_base + GNR_CFG_LOCK_OFFSET,
+ priv->ro_bitmap);
+
--- /dev/null
+From 0fe329b55231cca489f9bed1db0e778d077fdaf9 Mon Sep 17 00:00:00 2001
+From: Shankar Bandal <shankar.bandal@intel.com>
+Date: Wed, 4 Dec 2024 09:04:11 +0200
+Subject: gpio: graniterapids: Fix invalid GPI_IS register offset
+
+From: Shankar Bandal <shankar.bandal@intel.com>
+
+commit 0fe329b55231cca489f9bed1db0e778d077fdaf9 upstream.
+
+Update GPI Interrupt Status register offset to correct value.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Shankar Bandal <shankar.bandal@intel.com>
+Signed-off-by: Alan Borzeszkowski <alan.borzeszkowski@linux.intel.com>
+Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Acked-by: Andy Shevchenko <andy@kernel.org>
+Link: https://lore.kernel.org/r/20241204070415.1034449-4-mika.westerberg@linux.intel.com
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpio/gpio-graniterapids.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/gpio/gpio-graniterapids.c b/drivers/gpio/gpio-graniterapids.c
+index d2b542b536b6..be907784ccdb 100644
+--- a/drivers/gpio/gpio-graniterapids.c
++++ b/drivers/gpio/gpio-graniterapids.c
+@@ -34,7 +34,7 @@
+
+ #define GNR_CFG_PADBAR 0x00
+ #define GNR_CFG_LOCK_OFFSET 0x04
+-#define GNR_GPI_STATUS_OFFSET 0x20
++#define GNR_GPI_STATUS_OFFSET 0x14
+ #define GNR_GPI_ENABLE_OFFSET 0x24
+
+ #define GNR_CFG_DW_RX_MASK GENMASK(25, 22)
+--
+2.47.1
+
--- /dev/null
+From 15636b00a055474033426b94b6372728b2163a1e Mon Sep 17 00:00:00 2001
+From: Shankar Bandal <shankar.bandal@intel.com>
+Date: Wed, 4 Dec 2024 09:04:12 +0200
+Subject: gpio: graniterapids: Fix invalid RXEVCFG register bitmask
+
+From: Shankar Bandal <shankar.bandal@intel.com>
+
+commit 15636b00a055474033426b94b6372728b2163a1e upstream.
+
+Correct RX Level/Edge Configuration register (RXEVCFG) bitmask.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Shankar Bandal <shankar.bandal@intel.com>
+Signed-off-by: Alan Borzeszkowski <alan.borzeszkowski@linux.intel.com>
+Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Acked-by: Andy Shevchenko <andy@kernel.org>
+Link: https://lore.kernel.org/r/20241204070415.1034449-5-mika.westerberg@linux.intel.com
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpio/gpio-graniterapids.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/gpio/gpio-graniterapids.c b/drivers/gpio/gpio-graniterapids.c
+index be907784ccdb..ec2931a65723 100644
+--- a/drivers/gpio/gpio-graniterapids.c
++++ b/drivers/gpio/gpio-graniterapids.c
+@@ -37,7 +37,7 @@
+ #define GNR_GPI_STATUS_OFFSET 0x14
+ #define GNR_GPI_ENABLE_OFFSET 0x24
+
+-#define GNR_CFG_DW_RX_MASK GENMASK(25, 22)
++#define GNR_CFG_DW_RX_MASK GENMASK(23, 22)
+ #define GNR_CFG_DW_RX_DISABLE FIELD_PREP(GNR_CFG_DW_RX_MASK, 2)
+ #define GNR_CFG_DW_RX_EDGE FIELD_PREP(GNR_CFG_DW_RX_MASK, 1)
+ #define GNR_CFG_DW_RX_LEVEL FIELD_PREP(GNR_CFG_DW_RX_MASK, 0)
+--
+2.47.1
+
--- /dev/null
+From eb9640fd1ce666610b77f5997596e9570a36378f Mon Sep 17 00:00:00 2001
+From: Alan Borzeszkowski <alan.borzeszkowski@linux.intel.com>
+Date: Wed, 4 Dec 2024 09:04:09 +0200
+Subject: gpio: graniterapids: Fix vGPIO driver crash
+
+From: Alan Borzeszkowski <alan.borzeszkowski@linux.intel.com>
+
+commit eb9640fd1ce666610b77f5997596e9570a36378f upstream.
+
+Move setting irq_chip.name from probe() function to the initialization
+of "irq_chip" struct in order to fix vGPIO driver crash during bootup.
+
+Crash was caused by unauthorized modification of irq_chip.name field
+where irq_chip struct was initialized as const.
+
+This behavior is a consequence of suboptimal implementation of
+gpio_irq_chip_set_chip(), which should be changed to avoid
+casting away const qualifier.
+
+Crash log:
+BUG: unable to handle page fault for address: ffffffffc0ba81c0
+/#PF: supervisor write access in kernel mode
+/#PF: error_code(0x0003) - permissions violation
+CPU: 33 UID: 0 PID: 1075 Comm: systemd-udevd Not tainted 6.12.0-rc6-00077-g2e1b3cc9d7f7 #1
+Hardware name: Intel Corporation Kaseyville RP/Kaseyville RP, BIOS KVLDCRB1.PGS.0026.D73.2410081258 10/08/2024
+RIP: 0010:gnr_gpio_probe+0x171/0x220 [gpio_graniterapids]
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Alan Borzeszkowski <alan.borzeszkowski@linux.intel.com>
+Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Acked-by: Andy Shevchenko <andy@kernel.org>
+Link: https://lore.kernel.org/r/20241204070415.1034449-2-mika.westerberg@linux.intel.com
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpio/gpio-graniterapids.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/gpio/gpio-graniterapids.c
++++ b/drivers/gpio/gpio-graniterapids.c
+@@ -234,6 +234,7 @@ static int gnr_gpio_irq_set_type(struct
+ }
+
+ static const struct irq_chip gnr_gpio_irq_chip = {
++ .name = "gpio-graniterapids",
+ .irq_ack = gnr_gpio_irq_ack,
+ .irq_mask = gnr_gpio_irq_mask,
+ .irq_unmask = gnr_gpio_irq_unmask,
+@@ -324,7 +325,6 @@ static int gnr_gpio_probe(struct platfor
+
+ girq = &priv->gc.irq;
+ gpio_irq_chip_set_chip(girq, &gnr_gpio_irq_chip);
+- girq->chip->name = dev_name(dev);
+ girq->parent_handler = NULL;
+ girq->num_parents = 0;
+ girq->parents = NULL;
--- /dev/null
+From 3396995f9fb6bcbe0004a68118a22f98bab6e2b9 Mon Sep 17 00:00:00 2001
+From: Haoyu Li <lihaoyu499@gmail.com>
+Date: Tue, 3 Dec 2024 22:14:51 +0800
+Subject: gpio: ljca: Initialize num before accessing item in ljca_gpio_config
+
+From: Haoyu Li <lihaoyu499@gmail.com>
+
+commit 3396995f9fb6bcbe0004a68118a22f98bab6e2b9 upstream.
+
+With the new __counted_by annocation in ljca_gpio_packet, the "num"
+struct member must be set before accessing the "item" array. Failing to
+do so will trigger a runtime warning when enabling CONFIG_UBSAN_BOUNDS
+and CONFIG_FORTIFY_SOURCE.
+
+Fixes: 1034cc423f1b ("gpio: update Intel LJCA USB GPIO driver")
+Cc: stable@vger.kernel.org
+Signed-off-by: Haoyu Li <lihaoyu499@gmail.com>
+Link: https://lore.kernel.org/stable/20241203141451.342316-1-lihaoyu499%40gmail.com
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpio/gpio-ljca.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/gpio/gpio-ljca.c b/drivers/gpio/gpio-ljca.c
+index d67b912d884d..c6c31e6146c7 100644
+--- a/drivers/gpio/gpio-ljca.c
++++ b/drivers/gpio/gpio-ljca.c
+@@ -82,9 +82,9 @@ static int ljca_gpio_config(struct ljca_gpio_dev *ljca_gpio, u8 gpio_id,
+ int ret;
+
+ mutex_lock(&ljca_gpio->trans_lock);
++ packet->num = 1;
+ packet->item[0].index = gpio_id;
+ packet->item[0].value = config | ljca_gpio->connect_mode[gpio_id];
+- packet->num = 1;
+
+ ret = ljca_transfer(ljca_gpio->ljca, LJCA_GPIO_CONFIG, (u8 *)packet,
+ struct_size(packet, item, packet->num), NULL, 0);
+--
+2.47.1
+
--- /dev/null
+From b95629435b84b9ecc0c765995204a4d8a913ed52 Mon Sep 17 00:00:00 2001
+From: Namjae Jeon <linkinjeon@kernel.org>
+Date: Thu, 5 Dec 2024 21:38:47 +0900
+Subject: ksmbd: fix racy issue from session lookup and expire
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+commit b95629435b84b9ecc0c765995204a4d8a913ed52 upstream.
+
+Increment the session reference count within the lock for lookup to avoid
+racy issue with session expire.
+
+Cc: stable@vger.kernel.org
+Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-25737
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/smb/server/auth.c | 2 ++
+ fs/smb/server/mgmt/user_session.c | 6 +++++-
+ fs/smb/server/server.c | 4 ++--
+ fs/smb/server/smb2pdu.c | 27 ++++++++++++++-------------
+ 4 files changed, 23 insertions(+), 16 deletions(-)
+
+--- a/fs/smb/server/auth.c
++++ b/fs/smb/server/auth.c
+@@ -1016,6 +1016,8 @@ static int ksmbd_get_encryption_key(stru
+
+ ses_enc_key = enc ? sess->smb3encryptionkey :
+ sess->smb3decryptionkey;
++ if (enc)
++ ksmbd_user_session_get(sess);
+ memcpy(key, ses_enc_key, SMB3_ENC_DEC_KEY_SIZE);
+
+ return 0;
+--- a/fs/smb/server/mgmt/user_session.c
++++ b/fs/smb/server/mgmt/user_session.c
+@@ -263,8 +263,10 @@ struct ksmbd_session *ksmbd_session_look
+
+ down_read(&conn->session_lock);
+ sess = xa_load(&conn->sessions, id);
+- if (sess)
++ if (sess) {
+ sess->last_active = jiffies;
++ ksmbd_user_session_get(sess);
++ }
+ up_read(&conn->session_lock);
+ return sess;
+ }
+@@ -275,6 +277,8 @@ struct ksmbd_session *ksmbd_session_look
+
+ down_read(&sessions_table_lock);
+ sess = __session_lookup(id);
++ if (sess)
++ ksmbd_user_session_get(sess);
+ up_read(&sessions_table_lock);
+
+ return sess;
+--- a/fs/smb/server/server.c
++++ b/fs/smb/server/server.c
+@@ -241,14 +241,14 @@ send:
+ if (work->tcon)
+ ksmbd_tree_connect_put(work->tcon);
+ smb3_preauth_hash_rsp(work);
+- if (work->sess)
+- ksmbd_user_session_put(work->sess);
+ if (work->sess && work->sess->enc && work->encrypted &&
+ conn->ops->encrypt_resp) {
+ rc = conn->ops->encrypt_resp(work);
+ if (rc < 0)
+ conn->ops->set_rsp_status(work, STATUS_DATA_ERROR);
+ }
++ if (work->sess)
++ ksmbd_user_session_put(work->sess);
+
+ ksmbd_conn_write(work);
+ }
+--- a/fs/smb/server/smb2pdu.c
++++ b/fs/smb/server/smb2pdu.c
+@@ -67,8 +67,10 @@ static inline bool check_session_id(stru
+ return false;
+
+ sess = ksmbd_session_lookup_all(conn, id);
+- if (sess)
++ if (sess) {
++ ksmbd_user_session_put(sess);
+ return true;
++ }
+ pr_err("Invalid user session id: %llu\n", id);
+ return false;
+ }
+@@ -605,10 +607,8 @@ int smb2_check_user_session(struct ksmbd
+
+ /* Check for validity of user session */
+ work->sess = ksmbd_session_lookup_all(conn, sess_id);
+- if (work->sess) {
+- ksmbd_user_session_get(work->sess);
++ if (work->sess)
+ return 1;
+- }
+ ksmbd_debug(SMB, "Invalid user session, Uid %llu\n", sess_id);
+ return -ENOENT;
+ }
+@@ -1701,29 +1701,35 @@ int smb2_sess_setup(struct ksmbd_work *w
+
+ if (conn->dialect != sess->dialect) {
+ rc = -EINVAL;
++ ksmbd_user_session_put(sess);
+ goto out_err;
+ }
+
+ if (!(req->hdr.Flags & SMB2_FLAGS_SIGNED)) {
+ rc = -EINVAL;
++ ksmbd_user_session_put(sess);
+ goto out_err;
+ }
+
+ if (strncmp(conn->ClientGUID, sess->ClientGUID,
+ SMB2_CLIENT_GUID_SIZE)) {
+ rc = -ENOENT;
++ ksmbd_user_session_put(sess);
+ goto out_err;
+ }
+
+ if (sess->state == SMB2_SESSION_IN_PROGRESS) {
+ rc = -EACCES;
++ ksmbd_user_session_put(sess);
+ goto out_err;
+ }
+
+ if (sess->state == SMB2_SESSION_EXPIRED) {
+ rc = -EFAULT;
++ ksmbd_user_session_put(sess);
+ goto out_err;
+ }
++ ksmbd_user_session_put(sess);
+
+ if (ksmbd_conn_need_reconnect(conn)) {
+ rc = -EFAULT;
+@@ -1731,7 +1737,8 @@ int smb2_sess_setup(struct ksmbd_work *w
+ goto out_err;
+ }
+
+- if (ksmbd_session_lookup(conn, sess_id)) {
++ sess = ksmbd_session_lookup(conn, sess_id);
++ if (!sess) {
+ rc = -EACCES;
+ goto out_err;
+ }
+@@ -1742,7 +1749,6 @@ int smb2_sess_setup(struct ksmbd_work *w
+ }
+
+ conn->binding = true;
+- ksmbd_user_session_get(sess);
+ } else if ((conn->dialect < SMB30_PROT_ID ||
+ server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) &&
+ (req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) {
+@@ -1769,7 +1775,6 @@ int smb2_sess_setup(struct ksmbd_work *w
+ }
+
+ conn->binding = false;
+- ksmbd_user_session_get(sess);
+ }
+ work->sess = sess;
+
+@@ -2195,9 +2200,9 @@ err_out:
+ int smb2_session_logoff(struct ksmbd_work *work)
+ {
+ struct ksmbd_conn *conn = work->conn;
++ struct ksmbd_session *sess = work->sess;
+ struct smb2_logoff_req *req;
+ struct smb2_logoff_rsp *rsp;
+- struct ksmbd_session *sess;
+ u64 sess_id;
+ int err;
+
+@@ -2219,11 +2224,6 @@ int smb2_session_logoff(struct ksmbd_wor
+ ksmbd_close_session_fds(work);
+ ksmbd_conn_wait_idle(conn);
+
+- /*
+- * Re-lookup session to validate if session is deleted
+- * while waiting request complete
+- */
+- sess = ksmbd_session_lookup_all(conn, sess_id);
+ if (ksmbd_tree_conn_session_logoff(sess)) {
+ ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId);
+ rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;
+@@ -8962,6 +8962,7 @@ int smb3_decrypt_req(struct ksmbd_work *
+ le64_to_cpu(tr_hdr->SessionId));
+ return -ECONNABORTED;
+ }
++ ksmbd_user_session_put(sess);
+
+ iov[0].iov_base = buf;
+ iov[0].iov_len = sizeof(struct smb2_transform_hdr) + 4;
--- /dev/null
+From b7ffecbe198e2dfc44abf92ceb90f46150f7527a Mon Sep 17 00:00:00 2001
+From: Shakeel Butt <shakeel.butt@linux.dev>
+Date: Mon, 9 Dec 2024 20:06:57 -0800
+Subject: memcg: slub: fix SUnreclaim for post charged objects
+
+From: Shakeel Butt <shakeel.butt@linux.dev>
+
+commit b7ffecbe198e2dfc44abf92ceb90f46150f7527a upstream.
+
+Large kmalloc directly allocates from the page allocator and then use
+lruvec_stat_mod_folio() to increment the unreclaimable slab stats for
+global and memcg. However when post memcg charging of slab objects was
+added in commit 9028cdeb38e1 ("memcg: add charging of already allocated
+slab objects"), it missed to correctly handle the unreclaimable slab
+stats for memcg.
+
+One user visisble effect of that bug is that the node level
+unreclaimable slab stat will work correctly but the memcg level stat can
+underflow as kernel correctly handles the free path but the charge path
+missed to increment the memcg level unreclaimable slab stat. Let's fix
+by correctly handle in the post charge code path.
+
+Fixes: 9028cdeb38e1 ("memcg: add charging of already allocated slab objects")
+Signed-off-by: Shakeel Butt <shakeel.butt@linux.dev>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ mm/slub.c | 21 ++++++++++++++++++---
+ 1 file changed, 18 insertions(+), 3 deletions(-)
+
+--- a/mm/slub.c
++++ b/mm/slub.c
+@@ -2199,9 +2199,24 @@ bool memcg_slab_post_charge(void *p, gfp
+
+ folio = virt_to_folio(p);
+ if (!folio_test_slab(folio)) {
+- return folio_memcg_kmem(folio) ||
+- (__memcg_kmem_charge_page(folio_page(folio, 0), flags,
+- folio_order(folio)) == 0);
++ int size;
++
++ if (folio_memcg_kmem(folio))
++ return true;
++
++ if (__memcg_kmem_charge_page(folio_page(folio, 0), flags,
++ folio_order(folio)))
++ return false;
++
++ /*
++ * This folio has already been accounted in the global stats but
++ * not in the memcg stats. So, subtract from the global and use
++ * the interface which adds to both global and memcg stats.
++ */
++ size = folio_size(folio);
++ node_stat_mod_folio(folio, NR_SLAB_UNRECLAIMABLE_B, -size);
++ lruvec_stat_mod_folio(folio, NR_SLAB_UNRECLAIMABLE_B, size);
++ return true;
+ }
+
+ slab = folio_slab(folio);
--- /dev/null
+From 246dfe3dc199246bd64635163115f2691623fc53 Mon Sep 17 00:00:00 2001
+From: Kuan-Wei Chiu <visitorckw@gmail.com>
+Date: Mon, 9 Dec 2024 21:42:26 +0800
+Subject: perf ftrace: Fix undefined behavior in cmp_profile_data()
+
+From: Kuan-Wei Chiu <visitorckw@gmail.com>
+
+commit 246dfe3dc199246bd64635163115f2691623fc53 upstream.
+
+The comparison function cmp_profile_data() violates the C standard's
+requirements for qsort() comparison functions, which mandate symmetry
+and transitivity:
+
+* Symmetry: If x < y, then y > x.
+* Transitivity: If x < y and y < z, then x < z.
+
+When v1 and v2 are equal, the function incorrectly returns 1, breaking
+symmetry and transitivity. This causes undefined behavior, which can
+lead to memory corruption in certain versions of glibc [1].
+
+Fix the issue by returning 0 when v1 and v2 are equal, ensuring
+compliance with the C standard and preventing undefined behavior.
+
+Link: https://www.qualys.com/2024/01/30/qsort.txt [1]
+Fixes: 0f223813edd0 ("perf ftrace: Add 'profile' command")
+Fixes: 74ae366c37b7 ("perf ftrace profile: Add -s/--sort option")
+Cc: stable@vger.kernel.org
+Signed-off-by: Kuan-Wei Chiu <visitorckw@gmail.com>
+Reviewed-by: Namhyung Kim <namhyung@kernel.org>
+Reviewed-by: Arnaldo Carvalho de Melo <acme@redhat.com>
+Cc: jserv@ccns.ncku.edu.tw
+Cc: chuang@cs.nycu.edu.tw
+Link: https://lore.kernel.org/r/20241209134226.1939163-1-visitorckw@gmail.com
+Signed-off-by: Namhyung Kim <namhyung@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ tools/perf/builtin-ftrace.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c
+index 272d3c70810e..a56cf8b0a7d4 100644
+--- a/tools/perf/builtin-ftrace.c
++++ b/tools/perf/builtin-ftrace.c
+@@ -1151,8 +1151,9 @@ static int cmp_profile_data(const void *a, const void *b)
+
+ if (v1 > v2)
+ return -1;
+- else
++ if (v1 < v2)
+ return 1;
++ return 0;
+ }
+
+ static void print_profile_result(struct perf_ftrace *ftrace)
+--
+2.47.1
+
--- /dev/null
+From 9f3de72a0c37005f897d69e4bdd59c25b8898447 Mon Sep 17 00:00:00 2001
+From: Kan Liang <kan.liang@linux.intel.com>
+Date: Tue, 19 Nov 2024 05:55:01 -0800
+Subject: perf/x86/intel/ds: Unconditionally drain PEBS DS when changing PEBS_DATA_CFG
+
+From: Kan Liang <kan.liang@linux.intel.com>
+
+commit 9f3de72a0c37005f897d69e4bdd59c25b8898447 upstream.
+
+The PEBS kernel warnings can still be observed with the below case.
+
+when the below commands are running in parallel for a while.
+
+ while true;
+ do
+ perf record --no-buildid -a --intr-regs=AX \
+ -e cpu/event=0xd0,umask=0x81/pp \
+ -c 10003 -o /dev/null ./triad;
+ done &
+
+ while true;
+ do
+ perf record -e 'cpu/mem-loads,ldlat=3/uP' -W -d -- ./dtlb
+ done
+
+The commit b752ea0c28e3 ("perf/x86/intel/ds: Flush PEBS DS when changing
+PEBS_DATA_CFG") intends to flush the entire PEBS buffer before the
+hardware is reprogrammed. However, it fails in the above case.
+
+The first perf command utilizes the large PEBS, while the second perf
+command only utilizes a single PEBS. When the second perf event is
+added, only the n_pebs++. The intel_pmu_pebs_enable() is invoked after
+intel_pmu_pebs_add(). So the cpuc->n_pebs == cpuc->n_large_pebs check in
+the intel_pmu_drain_large_pebs() fails. The PEBS DS is not flushed.
+The new PEBS event should not be taken into account when flushing the
+existing PEBS DS.
+
+The check is unnecessary here. Before the hardware is reprogrammed, all
+the stale records must be drained unconditionally.
+
+For single PEBS or PEBS-vi-pt, the DS must be empty. The drain_pebs()
+can handle the empty case. There is no harm to unconditionally drain the
+PEBS DS.
+
+Fixes: b752ea0c28e3 ("perf/x86/intel/ds: Flush PEBS DS when changing PEBS_DATA_CFG")
+Signed-off-by: Kan Liang <kan.liang@linux.intel.com>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/r/20241119135504.1463839-2-kan.liang@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/events/intel/ds.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/x86/events/intel/ds.c
++++ b/arch/x86/events/intel/ds.c
+@@ -1468,7 +1468,7 @@ void intel_pmu_pebs_enable(struct perf_e
+ * hence we need to drain when changing said
+ * size.
+ */
+- intel_pmu_drain_large_pebs(cpuc);
++ intel_pmu_drain_pebs_buffer();
+ adaptive_pebs_record_size_update();
+ wrmsrl(MSR_PEBS_DATA_CFG, pebs_data_cfg);
+ cpuc->active_pebs_data_cfg = pebs_data_cfg;
--- /dev/null
+From b3431a8bb336cece8adc452437befa7d4534b2fd Mon Sep 17 00:00:00 2001
+From: Alexandre Ghiti <alexghiti@rivosinc.com>
+Date: Mon, 9 Dec 2024 08:41:25 +0100
+Subject: riscv: Fix IPIs usage in kfence_protect_page()
+
+From: Alexandre Ghiti <alexghiti@rivosinc.com>
+
+commit b3431a8bb336cece8adc452437befa7d4534b2fd upstream.
+
+flush_tlb_kernel_range() may use IPIs to flush the TLBs of all the
+cores, which triggers the following warning when the irqs are disabled:
+
+[ 3.455330] WARNING: CPU: 1 PID: 0 at kernel/smp.c:815 smp_call_function_many_cond+0x452/0x520
+[ 3.456647] Modules linked in:
+[ 3.457218] CPU: 1 UID: 0 PID: 0 Comm: swapper/1 Not tainted 6.12.0-rc7-00010-g91d3de7240b8 #1
+[ 3.457416] Hardware name: QEMU QEMU Virtual Machine, BIOS
+[ 3.457633] epc : smp_call_function_many_cond+0x452/0x520
+[ 3.457736] ra : on_each_cpu_cond_mask+0x1e/0x30
+[ 3.457786] epc : ffffffff800b669a ra : ffffffff800b67c2 sp : ff2000000000bb50
+[ 3.457824] gp : ffffffff815212b8 tp : ff6000008014f080 t0 : 000000000000003f
+[ 3.457859] t1 : ffffffff815221e0 t2 : 000000000000000f s0 : ff2000000000bc10
+[ 3.457920] s1 : 0000000000000040 a0 : ffffffff815221e0 a1 : 0000000000000001
+[ 3.457953] a2 : 0000000000010000 a3 : 0000000000000003 a4 : 0000000000000000
+[ 3.458006] a5 : 0000000000000000 a6 : ffffffffffffffff a7 : 0000000000000000
+[ 3.458042] s2 : ffffffff815223be s3 : 00fffffffffff000 s4 : ff600001ffe38fc0
+[ 3.458076] s5 : ff600001ff950d00 s6 : 0000000200000120 s7 : 0000000000000001
+[ 3.458109] s8 : 0000000000000001 s9 : ff60000080841ef0 s10: 0000000000000001
+[ 3.458141] s11: ffffffff81524812 t3 : 0000000000000001 t4 : ff60000080092bc0
+[ 3.458172] t5 : 0000000000000000 t6 : ff200000000236d0
+[ 3.458203] status: 0000000200000100 badaddr: ffffffff800b669a cause: 0000000000000003
+[ 3.458373] [<ffffffff800b669a>] smp_call_function_many_cond+0x452/0x520
+[ 3.458593] [<ffffffff800b67c2>] on_each_cpu_cond_mask+0x1e/0x30
+[ 3.458625] [<ffffffff8000e4ca>] __flush_tlb_range+0x118/0x1ca
+[ 3.458656] [<ffffffff8000e6b2>] flush_tlb_kernel_range+0x1e/0x26
+[ 3.458683] [<ffffffff801ea56a>] kfence_protect+0xc0/0xce
+[ 3.458717] [<ffffffff801e9456>] kfence_guarded_free+0xc6/0x1c0
+[ 3.458742] [<ffffffff801e9d6c>] __kfence_free+0x62/0xc6
+[ 3.458764] [<ffffffff801c57d8>] kfree+0x106/0x32c
+[ 3.458786] [<ffffffff80588cf2>] detach_buf_split+0x188/0x1a8
+[ 3.458816] [<ffffffff8058708c>] virtqueue_get_buf_ctx+0xb6/0x1f6
+[ 3.458839] [<ffffffff805871da>] virtqueue_get_buf+0xe/0x16
+[ 3.458880] [<ffffffff80613d6a>] virtblk_done+0x5c/0xe2
+[ 3.458908] [<ffffffff8058766e>] vring_interrupt+0x6a/0x74
+[ 3.458930] [<ffffffff800747d8>] __handle_irq_event_percpu+0x7c/0xe2
+[ 3.458956] [<ffffffff800748f0>] handle_irq_event+0x3c/0x86
+[ 3.458978] [<ffffffff800786cc>] handle_simple_irq+0x9e/0xbe
+[ 3.459004] [<ffffffff80073934>] generic_handle_domain_irq+0x1c/0x2a
+[ 3.459027] [<ffffffff804bf87c>] imsic_handle_irq+0xba/0x120
+[ 3.459056] [<ffffffff80073934>] generic_handle_domain_irq+0x1c/0x2a
+[ 3.459080] [<ffffffff804bdb76>] riscv_intc_aia_irq+0x24/0x34
+[ 3.459103] [<ffffffff809d0452>] handle_riscv_irq+0x2e/0x4c
+[ 3.459133] [<ffffffff809d923e>] call_on_irq_stack+0x32/0x40
+
+So only flush the local TLB and let the lazy kfence page fault handling
+deal with the faults which could happen when a core has an old protected
+pte version cached in its TLB. That leads to potential inaccuracies which
+can be tolerated when using kfence.
+
+Fixes: 47513f243b45 ("riscv: Enable KFENCE for riscv64")
+Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com>
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/r/20241209074125.52322-1-alexghiti@rivosinc.com
+Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/riscv/include/asm/kfence.h | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/arch/riscv/include/asm/kfence.h
++++ b/arch/riscv/include/asm/kfence.h
+@@ -22,7 +22,9 @@ static inline bool kfence_protect_page(u
+ else
+ set_pte(pte, __pte(pte_val(ptep_get(pte)) | _PAGE_PRESENT));
+
+- flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
++ preempt_disable();
++ local_flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
++ preempt_enable();
+
+ return true;
+ }
--- /dev/null
+From c796e187201242992d6d292bfeff41aadfdf3f29 Mon Sep 17 00:00:00 2001
+From: Alexandre Ghiti <alexghiti@rivosinc.com>
+Date: Mon, 9 Dec 2024 08:45:08 +0100
+Subject: riscv: Fix wrong usage of __pa() on a fixmap address
+
+From: Alexandre Ghiti <alexghiti@rivosinc.com>
+
+commit c796e187201242992d6d292bfeff41aadfdf3f29 upstream.
+
+riscv uses fixmap addresses to map the dtb so we can't use __pa() which
+is reserved for linear mapping addresses.
+
+Fixes: b2473a359763 ("of/fdt: add dt_phys arg to early_init_dt_scan and early_init_dt_verify")
+Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com>
+Link: https://lore.kernel.org/r/20241209074508.53037-1-alexghiti@rivosinc.com
+Cc: stable@vger.kernel.org
+Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/riscv/kernel/setup.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/riscv/kernel/setup.c
++++ b/arch/riscv/kernel/setup.c
+@@ -227,7 +227,7 @@ static void __init init_resources(void)
+ static void __init parse_dtb(void)
+ {
+ /* Early scan of device tree from init memory */
+- if (early_init_dt_scan(dtb_early_va, __pa(dtb_early_va))) {
++ if (early_init_dt_scan(dtb_early_va, dtb_early_pa)) {
+ const char *name = of_flat_dt_get_machine_name();
+
+ if (name) {
--- /dev/null
+From 21f1b85c8912262adf51707e63614a114425eb10 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= <bjorn@rivosinc.com>
+Date: Wed, 20 Nov 2024 14:12:02 +0100
+Subject: riscv: mm: Do not call pmd dtor on vmemmap page table teardown
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Björn Töpel <bjorn@rivosinc.com>
+
+commit 21f1b85c8912262adf51707e63614a114425eb10 upstream.
+
+The vmemmap's, which is used for RV64 with SPARSEMEM_VMEMMAP, page
+tables are populated using pmd (page middle directory) hugetables.
+However, the pmd allocation is not using the generic mechanism used by
+the VMA code (e.g. pmd_alloc()), or the RISC-V specific
+create_pgd_mapping()/alloc_pmd_late(). Instead, the vmemmap page table
+code allocates a page, and calls vmemmap_set_pmd(). This results in
+that the pmd ctor is *not* called, nor would it make sense to do so.
+
+Now, when tearing down a vmemmap page table pmd, the cleanup code
+would unconditionally, and incorrectly call the pmd dtor, which
+results in a crash (best case).
+
+This issue was found when running the HMM selftests:
+
+ | tools/testing/selftests/mm# ./test_hmm.sh smoke
+ | ... # when unloading the test_hmm.ko module
+ | page: refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x10915b
+ | flags: 0x1000000000000000(node=0|zone=1)
+ | raw: 1000000000000000 0000000000000000 dead000000000122 0000000000000000
+ | raw: 0000000000000000 0000000000000000 00000001ffffffff 0000000000000000
+ | page dumped because: VM_BUG_ON_PAGE(ptdesc->pmd_huge_pte)
+ | ------------[ cut here ]------------
+ | kernel BUG at include/linux/mm.h:3080!
+ | Kernel BUG [#1]
+ | Modules linked in: test_hmm(-) sch_fq_codel fuse drm drm_panel_orientation_quirks backlight dm_mod
+ | CPU: 1 UID: 0 PID: 514 Comm: modprobe Tainted: G W 6.12.0-00982-gf2a4f1682d07 #2
+ | Tainted: [W]=WARN
+ | Hardware name: riscv-virtio qemu/qemu, BIOS 2024.10 10/01/2024
+ | epc : remove_pgd_mapping+0xbec/0x1070
+ | ra : remove_pgd_mapping+0xbec/0x1070
+ | epc : ffffffff80010a68 ra : ffffffff80010a68 sp : ff20000000a73940
+ | gp : ffffffff827b2d88 tp : ff6000008785da40 t0 : ffffffff80fbce04
+ | t1 : 0720072007200720 t2 : 706d756420656761 s0 : ff20000000a73a50
+ | s1 : ff6000008915cff8 a0 : 0000000000000039 a1 : 0000000000000008
+ | a2 : ff600003fff0de20 a3 : 0000000000000000 a4 : 0000000000000000
+ | a5 : 0000000000000000 a6 : c0000000ffffefff a7 : ffffffff824469b8
+ | s2 : ff1c0000022456c0 s3 : ff1ffffffdbfffff s4 : ff6000008915c000
+ | s5 : ff6000008915c000 s6 : ff6000008915c000 s7 : ff1ffffffdc00000
+ | s8 : 0000000000000001 s9 : ff1ffffffdc00000 s10: ffffffff819a31f0
+ | s11: ffffffffffffffff t3 : ffffffff8000c950 t4 : ff60000080244f00
+ | t5 : ff60000080244000 t6 : ff20000000a73708
+ | status: 0000000200000120 badaddr: ffffffff80010a68 cause: 0000000000000003
+ | [<ffffffff80010a68>] remove_pgd_mapping+0xbec/0x1070
+ | [<ffffffff80fd238e>] vmemmap_free+0x14/0x1e
+ | [<ffffffff8032e698>] section_deactivate+0x220/0x452
+ | [<ffffffff8032ef7e>] sparse_remove_section+0x4a/0x58
+ | [<ffffffff802f8700>] __remove_pages+0x7e/0xba
+ | [<ffffffff803760d8>] memunmap_pages+0x2bc/0x3fe
+ | [<ffffffff02a3ca28>] dmirror_device_remove_chunks+0x2ea/0x518 [test_hmm]
+ | [<ffffffff02a3e026>] hmm_dmirror_exit+0x3e/0x1018 [test_hmm]
+ | [<ffffffff80102c14>] __riscv_sys_delete_module+0x15a/0x2a6
+ | [<ffffffff80fd020c>] do_trap_ecall_u+0x1f2/0x266
+ | [<ffffffff80fde0a2>] _new_vmalloc_restore_context_a0+0xc6/0xd2
+ | Code: bf51 7597 0184 8593 76a5 854a 4097 0029 80e7 2c00 (9002) 7597
+ | ---[ end trace 0000000000000000 ]---
+ | Kernel panic - not syncing: Fatal exception in interrupt
+
+Add a check to avoid calling the pmd dtor, if the calling context is
+vmemmap_free().
+
+Fixes: c75a74f4ba19 ("riscv: mm: Add memory hotplugging support")
+Signed-off-by: Björn Töpel <bjorn@rivosinc.com>
+Reviewed-by: Alexandre Ghiti <alexghiti@rivosinc.com>
+Link: https://lore.kernel.org/r/20241120131203.1859787-1-bjorn@kernel.org
+Cc: stable@vger.kernel.org
+Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/riscv/mm/init.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
+index 0e8c20adcd98..fc53ce748c80 100644
+--- a/arch/riscv/mm/init.c
++++ b/arch/riscv/mm/init.c
+@@ -1566,7 +1566,7 @@ static void __meminit free_pte_table(pte_t *pte_start, pmd_t *pmd)
+ pmd_clear(pmd);
+ }
+
+-static void __meminit free_pmd_table(pmd_t *pmd_start, pud_t *pud)
++static void __meminit free_pmd_table(pmd_t *pmd_start, pud_t *pud, bool is_vmemmap)
+ {
+ struct page *page = pud_page(*pud);
+ struct ptdesc *ptdesc = page_ptdesc(page);
+@@ -1579,7 +1579,8 @@ static void __meminit free_pmd_table(pmd_t *pmd_start, pud_t *pud)
+ return;
+ }
+
+- pagetable_pmd_dtor(ptdesc);
++ if (!is_vmemmap)
++ pagetable_pmd_dtor(ptdesc);
+ if (PageReserved(page))
+ free_reserved_page(page);
+ else
+@@ -1703,7 +1704,7 @@ static void __meminit remove_pud_mapping(pud_t *pud_base, unsigned long addr, un
+ remove_pmd_mapping(pmd_base, addr, next, is_vmemmap, altmap);
+
+ if (pgtable_l4_enabled)
+- free_pmd_table(pmd_base, pudp);
++ free_pmd_table(pmd_base, pudp, is_vmemmap);
+ }
+ }
+
+--
+2.47.1
+
--- /dev/null
+From 22368fe1f9bbf39db2b5b52859589883273e80ce Mon Sep 17 00:00:00 2001
+From: Juri Lelli <juri.lelli@redhat.com>
+Date: Wed, 27 Nov 2024 07:37:40 +0100
+Subject: sched/deadline: Fix replenish_dl_new_period dl_server condition
+
+From: Juri Lelli <juri.lelli@redhat.com>
+
+commit 22368fe1f9bbf39db2b5b52859589883273e80ce upstream.
+
+The condition in replenish_dl_new_period() that checks if a reservation
+(dl_server) is deferred and is not handling a starvation case is
+obviously wrong.
+
+Fix it.
+
+Fixes: a110a81c52a9 ("sched/deadline: Deferrable dl server")
+Signed-off-by: Juri Lelli <juri.lelli@redhat.com>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Cc: stable@vger.kernel.org
+Link: https://lkml.kernel.org/r/20241127063740.8278-1-juri.lelli@redhat.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/sched/deadline.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
+index d9d5a702f1a6..206691d35b7d 100644
+--- a/kernel/sched/deadline.c
++++ b/kernel/sched/deadline.c
+@@ -781,7 +781,7 @@ static inline void replenish_dl_new_period(struct sched_dl_entity *dl_se,
+ * If it is a deferred reservation, and the server
+ * is not handling an starvation case, defer it.
+ */
+- if (dl_se->dl_defer & !dl_se->dl_defer_running) {
++ if (dl_se->dl_defer && !dl_se->dl_defer_running) {
+ dl_se->dl_throttled = 1;
+ dl_se->dl_defer_armed = 1;
+ }
+--
+2.47.1
+
--- /dev/null
+From 7cc0e0a43a91052477c2921f924a37d9c3891f0c Mon Sep 17 00:00:00 2001
+From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
+Date: Mon, 25 Nov 2024 13:58:56 +0200
+Subject: serial: sh-sci: Check if TX data was written to device in .tx_empty()
+
+From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
+
+commit 7cc0e0a43a91052477c2921f924a37d9c3891f0c upstream.
+
+On the Renesas RZ/G3S, when doing suspend to RAM, the uart_suspend_port()
+is called. The uart_suspend_port() calls 3 times the
+struct uart_port::ops::tx_empty() before shutting down the port.
+
+According to the documentation, the struct uart_port::ops::tx_empty()
+API tests whether the transmitter FIFO and shifter for the port is
+empty.
+
+The Renesas RZ/G3S SCIFA IP reports the number of data units stored in the
+transmit FIFO through the FDR (FIFO Data Count Register). The data units
+in the FIFOs are written in the shift register and transmitted from there.
+The TEND bit in the Serial Status Register reports if the data was
+transmitted from the shift register.
+
+In the previous code, in the tx_empty() API implemented by the sh-sci
+driver, it is considered that the TX is empty if the hardware reports the
+TEND bit set and the number of data units in the FIFO is zero.
+
+According to the HW manual, the TEND bit has the following meaning:
+
+0: Transmission is in the waiting state or in progress.
+1: Transmission is completed.
+
+It has been noticed that when opening the serial device w/o using it and
+then switch to a power saving mode, the tx_empty() call in the
+uart_port_suspend() function fails, leading to the "Unable to drain
+transmitter" message being printed on the console. This is because the
+TEND=0 if nothing has been transmitted and the FIFOs are empty. As the
+TEND=0 has double meaning (waiting state, in progress) we can't
+determined the scenario described above.
+
+Add a software workaround for this. This sets a variable if any data has
+been sent on the serial console (when using PIO) or if the DMA callback has
+been called (meaning something has been transmitted). In the tx_empty()
+API the status of the DMA transaction is also checked and if it is
+completed or in progress the code falls back in checking the hardware
+registers instead of relying on the software variable.
+
+Fixes: 73a19e4c0301 ("serial: sh-sci: Add DMA support.")
+Cc: stable@vger.kernel.org
+Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
+Link: https://lore.kernel.org/r/20241125115856.513642-1-claudiu.beznea.uj@bp.renesas.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/sh-sci.c | 29 +++++++++++++++++++++++++++++
+ 1 file changed, 29 insertions(+)
+
+--- a/drivers/tty/serial/sh-sci.c
++++ b/drivers/tty/serial/sh-sci.c
+@@ -157,6 +157,7 @@ struct sci_port {
+
+ bool has_rtscts;
+ bool autorts;
++ bool tx_occurred;
+ };
+
+ #define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS
+@@ -850,6 +851,7 @@ static void sci_transmit_chars(struct ua
+ {
+ struct tty_port *tport = &port->state->port;
+ unsigned int stopped = uart_tx_stopped(port);
++ struct sci_port *s = to_sci_port(port);
+ unsigned short status;
+ unsigned short ctrl;
+ int count;
+@@ -885,6 +887,7 @@ static void sci_transmit_chars(struct ua
+ }
+
+ sci_serial_out(port, SCxTDR, c);
++ s->tx_occurred = true;
+
+ port->icount.tx++;
+ } while (--count > 0);
+@@ -1241,6 +1244,8 @@ static void sci_dma_tx_complete(void *ar
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+
++ s->tx_occurred = true;
++
+ if (!kfifo_is_empty(&tport->xmit_fifo)) {
+ s->cookie_tx = 0;
+ schedule_work(&s->work_tx);
+@@ -1731,6 +1736,19 @@ static void sci_flush_buffer(struct uart
+ s->cookie_tx = -EINVAL;
+ }
+ }
++
++static void sci_dma_check_tx_occurred(struct sci_port *s)
++{
++ struct dma_tx_state state;
++ enum dma_status status;
++
++ if (!s->chan_tx)
++ return;
++
++ status = dmaengine_tx_status(s->chan_tx, s->cookie_tx, &state);
++ if (status == DMA_COMPLETE || status == DMA_IN_PROGRESS)
++ s->tx_occurred = true;
++}
+ #else /* !CONFIG_SERIAL_SH_SCI_DMA */
+ static inline void sci_request_dma(struct uart_port *port)
+ {
+@@ -1740,6 +1758,10 @@ static inline void sci_free_dma(struct u
+ {
+ }
+
++static void sci_dma_check_tx_occurred(struct sci_port *s)
++{
++}
++
+ #define sci_flush_buffer NULL
+ #endif /* !CONFIG_SERIAL_SH_SCI_DMA */
+
+@@ -2076,6 +2098,12 @@ static unsigned int sci_tx_empty(struct
+ {
+ unsigned short status = sci_serial_in(port, SCxSR);
+ unsigned short in_tx_fifo = sci_txfill(port);
++ struct sci_port *s = to_sci_port(port);
++
++ sci_dma_check_tx_occurred(s);
++
++ if (!s->tx_occurred)
++ return TIOCSER_TEMT;
+
+ return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0;
+ }
+@@ -2247,6 +2275,7 @@ static int sci_startup(struct uart_port
+
+ dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
+
++ s->tx_occurred = false;
+ sci_request_dma(port);
+
+ ret = sci_request_irq(s);
--- /dev/null
+usb-misc-onboard_usb_dev-skip-suspend-resume-sequence-for-usb5744-smbus-support.patch
+serial-sh-sci-check-if-tx-data-was-written-to-device-in-.tx_empty.patch
+bpf-fix-uaf-via-mismatching-bpf_prog-attachment-rcu-flavors.patch
+sched-deadline-fix-replenish_dl_new_period-dl_server-condition.patch
+perf-x86-intel-ds-unconditionally-drain-pebs-ds-when-changing-pebs_data_cfg.patch
+clk-en7523-fix-wrong-bus-clock-for-en7581.patch
+ksmbd-fix-racy-issue-from-session-lookup-and-expire.patch
+splice-do-not-checksum-af_unix-sockets.patch
+tcp-check-space-before-adding-mptcp-syn-options.patch
+perf-ftrace-fix-undefined-behavior-in-cmp_profile_data.patch
+virtio_net-correct-netdev_tx_reset_queue-invocation-point.patch
+virtio_ring-add-a-func-argument-recycle_done-to-virtqueue_resize.patch
+virtio_net-ensure-netdev_tx_reset_queue-is-called-on-tx-ring-resize.patch
+riscv-mm-do-not-call-pmd-dtor-on-vmemmap-page-table-teardown.patch
+riscv-fix-wrong-usage-of-__pa-on-a-fixmap-address.patch
+blk-cgroup-fix-uaf-in-blkcg_unpin_online.patch
+block-switch-to-using-refcount_t-for-zone-write-plugs.patch
+block-use-a-zone-write-plug-bio-work-for-req_nowait-bios.patch
+dm-fix-dm-zoned-reclaim-zone-write-pointer-alignment.patch
+block-prevent-potential-deadlocks-in-zone-write-plug-error-recovery.patch
+gpio-graniterapids-fix-gpio-ack-functionality.patch
+memcg-slub-fix-sunreclaim-for-post-charged-objects.patch
+spi-rockchip-fix-pm-runtime-count-on-no-op-cs.patch
+gpio-ljca-initialize-num-before-accessing-item-in-ljca_gpio_config.patch
+alsa-usb-audio-add-implicit-feedback-quirk-for-yamaha-thr5.patch
+alsa-hda-realtek-fix-headset-mic-on-acer-nitro-5.patch
+riscv-fix-ipis-usage-in-kfence_protect_page.patch
+crypto-hisilicon-debugfs-fix-the-struct-pointer-incorrectly-offset-problem.patch
+drm-panic-remove-spurious-empty-line-to-clean-warning.patch
+usb-host-max3421-hcd-correctly-abort-a-usb-request.patch
+block-ignore-req_nowait-for-zone-reset-and-zone-finish-operations.patch
+gpio-graniterapids-fix-vgpio-driver-crash.patch
+gpio-graniterapids-fix-incorrect-bar-assignment.patch
+gpio-graniterapids-fix-invalid-gpi_is-register-offset.patch
+gpio-graniterapids-fix-invalid-rxevcfg-register-bitmask.patch
+gpio-graniterapids-determine-if-gpio-pad-can-be-used-by-driver.patch
+gpio-graniterapids-check-if-gpio-line-can-be-used-for-irqs.patch
+usb-core-hcd-only-check-primary-hcd-skip_phy_initialization.patch
--- /dev/null
+From 0bb394067a792e7119abc9e0b7158ef19381f456 Mon Sep 17 00:00:00 2001
+From: Christian Loehle <christian.loehle@arm.com>
+Date: Fri, 6 Dec 2024 19:50:55 +0000
+Subject: spi: rockchip: Fix PM runtime count on no-op cs
+
+From: Christian Loehle <christian.loehle@arm.com>
+
+commit 0bb394067a792e7119abc9e0b7158ef19381f456 upstream.
+
+The early bail out that caused an out-of-bounds write was removed with
+commit 5c018e378f91 ("spi: spi-rockchip: Fix out of bounds array
+access")
+Unfortunately that caused the PM runtime count to be unbalanced and
+underflowed on the first call. To fix that reintroduce a no-op check
+by reading the register directly.
+
+Cc: stable@vger.kernel.org
+Fixes: 5c018e378f91 ("spi: spi-rockchip: Fix out of bounds array access")
+Signed-off-by: Christian Loehle <christian.loehle@arm.com>
+Link: https://patch.msgid.link/1f2b3af4-2b7a-4ac8-ab95-c80120ebf44c@arm.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/spi/spi-rockchip.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+--- a/drivers/spi/spi-rockchip.c
++++ b/drivers/spi/spi-rockchip.c
+@@ -241,6 +241,20 @@ static void rockchip_spi_set_cs(struct s
+ struct spi_controller *ctlr = spi->controller;
+ struct rockchip_spi *rs = spi_controller_get_devdata(ctlr);
+ bool cs_asserted = spi->mode & SPI_CS_HIGH ? enable : !enable;
++ bool cs_actual;
++
++ /*
++ * SPI subsystem tries to avoid no-op calls that would break the PM
++ * refcount below. It can't however for the first time it is used.
++ * To detect this case we read it here and bail out early for no-ops.
++ */
++ if (spi_get_csgpiod(spi, 0))
++ cs_actual = !!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SER) & 1);
++ else
++ cs_actual = !!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SER) &
++ BIT(spi_get_chipselect(spi, 0)));
++ if (unlikely(cs_actual == cs_asserted))
++ return;
+
+ if (cs_asserted) {
+ /* Keep things powered as long as CS is asserted */
--- /dev/null
+From 6bd8614fc2d076fc21b7488c9f279853960964e2 Mon Sep 17 00:00:00 2001
+From: Frederik Deweerdt <deweerdt.lkml@gmail.com>
+Date: Mon, 9 Dec 2024 21:06:48 -0800
+Subject: splice: do not checksum AF_UNIX sockets
+
+From: Frederik Deweerdt <deweerdt.lkml@gmail.com>
+
+commit 6bd8614fc2d076fc21b7488c9f279853960964e2 upstream.
+
+When `skb_splice_from_iter` was introduced, it inadvertently added
+checksumming for AF_UNIX sockets. This resulted in significant
+slowdowns, for example when using sendfile over unix sockets.
+
+Using the test code in [1] in my test setup (2G single core qemu),
+the client receives a 1000M file in:
+- without the patch: 1482ms (+/- 36ms)
+- with the patch: 652.5ms (+/- 22.9ms)
+
+This commit addresses the issue by marking checksumming as unnecessary in
+`unix_stream_sendmsg`
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Frederik Deweerdt <deweerdt.lkml@gmail.com>
+Fixes: 2e910b95329c ("net: Add a function to splice pages into an skbuff for MSG_SPLICE_PAGES")
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Reviewed-by: Joe Damato <jdamato@fastly.com>
+Link: https://patch.msgid.link/Z1fMaHkRf8cfubuE@xiberoa
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/unix/af_unix.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/net/unix/af_unix.c
++++ b/net/unix/af_unix.c
+@@ -2313,6 +2313,7 @@ static int unix_stream_sendmsg(struct so
+ fds_sent = true;
+
+ if (unlikely(msg->msg_flags & MSG_SPLICE_PAGES)) {
++ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ err = skb_splice_from_iter(skb, &msg->msg_iter, size,
+ sk->sk_allocation);
+ if (err < 0) {
--- /dev/null
+From 06d64ab46f19ac12f59a1d2aa8cd196b2e4edb5b Mon Sep 17 00:00:00 2001
+From: MoYuanhao <moyuanhao3676@163.com>
+Date: Mon, 9 Dec 2024 13:28:14 +0100
+Subject: tcp: check space before adding MPTCP SYN options
+
+From: MoYuanhao <moyuanhao3676@163.com>
+
+commit 06d64ab46f19ac12f59a1d2aa8cd196b2e4edb5b upstream.
+
+Ensure there is enough space before adding MPTCP options in
+tcp_syn_options().
+
+Without this check, 'remaining' could underflow, and causes issues. If
+there is not enough space, MPTCP should not be used.
+
+Signed-off-by: MoYuanhao <moyuanhao3676@163.com>
+Fixes: cec37a6e41aa ("mptcp: Handle MP_CAPABLE options for outgoing connections")
+Cc: stable@vger.kernel.org
+Acked-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+[ Matt: Add Fixes, cc Stable, update Description ]
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20241209-net-mptcp-check-space-syn-v1-1-2da992bb6f74@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/ipv4/tcp_output.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/net/ipv4/tcp_output.c
++++ b/net/ipv4/tcp_output.c
+@@ -883,8 +883,10 @@ static unsigned int tcp_syn_options(stru
+ unsigned int size;
+
+ if (mptcp_syn_options(sk, skb, &size, &opts->mptcp)) {
+- opts->options |= OPTION_MPTCP;
+- remaining -= size;
++ if (remaining >= size) {
++ opts->options |= OPTION_MPTCP;
++ remaining -= size;
++ }
+ }
+ }
+
--- /dev/null
+From d2ec94fbc431cc77ed53d4480bdc856669c2b5aa Mon Sep 17 00:00:00 2001
+From: Xu Yang <xu.yang_2@nxp.com>
+Date: Tue, 5 Nov 2024 17:01:20 +0800
+Subject: usb: core: hcd: only check primary hcd skip_phy_initialization
+
+From: Xu Yang <xu.yang_2@nxp.com>
+
+commit d2ec94fbc431cc77ed53d4480bdc856669c2b5aa upstream.
+
+Before commit 53a2d95df836 ("usb: core: add phy notify connect and
+disconnect"), phy initialization will be skipped even when shared hcd
+doesn't set skip_phy_initialization flag. However, the situation is
+changed after the commit. The hcd.c will initialize phy when add shared
+hcd. This behavior is unexpected for some platforms which will handle phy
+initialization by themselves. To avoid the issue, this will only check
+skip_phy_initialization flag of primary hcd since shared hcd normally
+follow primary hcd setting.
+
+Fixes: 53a2d95df836 ("usb: core: add phy notify connect and disconnect")
+Cc: stable@vger.kernel.org
+Signed-off-by: Xu Yang <xu.yang_2@nxp.com>
+Link: https://lore.kernel.org/r/20241105090120.2438366-1-xu.yang_2@nxp.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/core/hcd.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/core/hcd.c
++++ b/drivers/usb/core/hcd.c
+@@ -2794,8 +2794,14 @@ int usb_add_hcd(struct usb_hcd *hcd,
+ int retval;
+ struct usb_device *rhdev;
+ struct usb_hcd *shared_hcd;
++ int skip_phy_initialization;
+
+- if (!hcd->skip_phy_initialization) {
++ if (usb_hcd_is_primary_hcd(hcd))
++ skip_phy_initialization = hcd->skip_phy_initialization;
++ else
++ skip_phy_initialization = hcd->primary_hcd->skip_phy_initialization;
++
++ if (!skip_phy_initialization) {
+ if (usb_hcd_is_primary_hcd(hcd)) {
+ hcd->phy_roothub = usb_phy_roothub_alloc(hcd->self.sysdev);
+ if (IS_ERR(hcd->phy_roothub))
--- /dev/null
+From 0d2ada05227881f3d0722ca2364e3f7a860a301f Mon Sep 17 00:00:00 2001
+From: Mark Tomlinson <mark.tomlinson@alliedtelesis.co.nz>
+Date: Mon, 25 Nov 2024 11:14:30 +1300
+Subject: usb: host: max3421-hcd: Correctly abort a USB request.
+
+From: Mark Tomlinson <mark.tomlinson@alliedtelesis.co.nz>
+
+commit 0d2ada05227881f3d0722ca2364e3f7a860a301f upstream.
+
+If the current USB request was aborted, the spi thread would not respond
+to any further requests. This is because the "curr_urb" pointer would
+not become NULL, so no further requests would be taken off the queue.
+The solution here is to set the "urb_done" flag, as this will cause the
+correct handling of the URB. Also clear interrupts that should only be
+expected if an URB is in progress.
+
+Fixes: 2d53139f3162 ("Add support for using a MAX3421E chip as a host driver.")
+Cc: stable <stable@kernel.org>
+Signed-off-by: Mark Tomlinson <mark.tomlinson@alliedtelesis.co.nz>
+Link: https://lore.kernel.org/r/20241124221430.1106080-1-mark.tomlinson@alliedtelesis.co.nz
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/host/max3421-hcd.c | 16 +++++++++++-----
+ 1 file changed, 11 insertions(+), 5 deletions(-)
+
+--- a/drivers/usb/host/max3421-hcd.c
++++ b/drivers/usb/host/max3421-hcd.c
+@@ -779,11 +779,17 @@ max3421_check_unlink(struct usb_hcd *hcd
+ retval = 1;
+ dev_dbg(&spi->dev, "%s: URB %p unlinked=%d",
+ __func__, urb, urb->unlinked);
+- usb_hcd_unlink_urb_from_ep(hcd, urb);
+- spin_unlock_irqrestore(&max3421_hcd->lock,
+- flags);
+- usb_hcd_giveback_urb(hcd, urb, 0);
+- spin_lock_irqsave(&max3421_hcd->lock, flags);
++ if (urb == max3421_hcd->curr_urb) {
++ max3421_hcd->urb_done = 1;
++ max3421_hcd->hien &= ~(BIT(MAX3421_HI_HXFRDN_BIT) |
++ BIT(MAX3421_HI_RCVDAV_BIT));
++ } else {
++ usb_hcd_unlink_urb_from_ep(hcd, urb);
++ spin_unlock_irqrestore(&max3421_hcd->lock,
++ flags);
++ usb_hcd_giveback_urb(hcd, urb, 0);
++ spin_lock_irqsave(&max3421_hcd->lock, flags);
++ }
+ }
+ }
+ }
--- /dev/null
+From ce15d6b3d5c3c6f78290066be0f0a4fd89cdeb5b Mon Sep 17 00:00:00 2001
+From: Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
+Date: Tue, 3 Dec 2024 00:18:22 +0530
+Subject: usb: misc: onboard_usb_dev: skip suspend/resume sequence for USB5744 SMBus support
+
+From: Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
+
+commit ce15d6b3d5c3c6f78290066be0f0a4fd89cdeb5b upstream.
+
+USB5744 SMBus initialization is done once in probe() and doing it in resume
+is not supported so avoid going into suspend and reset the HUB.
+
+There is a sysfs property 'always_powered_in_suspend' to implement this
+feature but since default state should be set to a working configuration
+so override this property value.
+
+It fixes the suspend/resume testcase on Kria KR260 Robotics Starter Kit.
+
+Fixes: 6782311d04df ("usb: misc: onboard_usb_dev: add Microchip usb5744 SMBus programming support")
+Cc: stable@vger.kernel.org
+Signed-off-by: Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
+Link: https://lore.kernel.org/r/1733165302-1694891-1-git-send-email-radhey.shyam.pandey@amd.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/misc/onboard_usb_dev.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/usb/misc/onboard_usb_dev.c b/drivers/usb/misc/onboard_usb_dev.c
+index 36b11127280f..75ac3c6aa92d 100644
+--- a/drivers/usb/misc/onboard_usb_dev.c
++++ b/drivers/usb/misc/onboard_usb_dev.c
+@@ -407,8 +407,10 @@ static int onboard_dev_probe(struct platform_device *pdev)
+ }
+
+ if (of_device_is_compatible(pdev->dev.of_node, "usb424,2744") ||
+- of_device_is_compatible(pdev->dev.of_node, "usb424,5744"))
++ of_device_is_compatible(pdev->dev.of_node, "usb424,5744")) {
+ err = onboard_dev_5744_i2c_init(client);
++ onboard_dev->always_powered_in_suspend = true;
++ }
+
+ put_device(&client->dev);
+ if (err < 0)
+--
+2.47.1
+
--- /dev/null
+From 3ddccbefebdbe0c4c72a248676e4d39ac66a8e26 Mon Sep 17 00:00:00 2001
+From: Koichiro Den <koichiro.den@canonical.com>
+Date: Fri, 6 Dec 2024 10:10:42 +0900
+Subject: virtio_net: correct netdev_tx_reset_queue() invocation point
+
+From: Koichiro Den <koichiro.den@canonical.com>
+
+commit 3ddccbefebdbe0c4c72a248676e4d39ac66a8e26 upstream.
+
+When virtnet_close is followed by virtnet_open, some TX completions can
+possibly remain unconsumed, until they are finally processed during the
+first NAPI poll after the netdev_tx_reset_queue(), resulting in a crash
+[1]. Commit b96ed2c97c79 ("virtio_net: move netdev_tx_reset_queue() call
+before RX napi enable") was not sufficient to eliminate all BQL crash
+cases for virtio-net.
+
+This issue can be reproduced with the latest net-next master by running:
+`while :; do ip l set DEV down; ip l set DEV up; done` under heavy network
+TX load from inside the machine.
+
+netdev_tx_reset_queue() can actually be dropped from virtnet_open path;
+the device is not stopped in any case. For BQL core part, it's just like
+traffic nearly ceases to exist for some period. For stall detector added
+to BQL, even if virtnet_close could somehow lead to some TX completions
+delayed for long, followed by virtnet_open, we can just take it as stall
+as mentioned in commit 6025b9135f7a ("net: dqs: add NIC stall detector
+based on BQL"). Note also that users can still reset stall_max via sysfs.
+
+So, drop netdev_tx_reset_queue() from virtnet_enable_queue_pair(). This
+eliminates the BQL crashes. As a result, netdev_tx_reset_queue() is now
+explicitly required in freeze/restore path. This patch adds it to
+immediately after free_unused_bufs(), following the rule of thumb:
+netdev_tx_reset_queue() should follow any SKB freeing not followed by
+netdev_tx_completed_queue(). This seems the most consistent and
+streamlined approach, and now netdev_tx_reset_queue() runs whenever
+free_unused_bufs() is done.
+
+[1]:
+------------[ cut here ]------------
+kernel BUG at lib/dynamic_queue_limits.c:99!
+Oops: invalid opcode: 0000 [#1] PREEMPT SMP NOPTI
+CPU: 7 UID: 0 PID: 1598 Comm: ip Tainted: G N 6.12.0net-next_main+ #2
+Tainted: [N]=TEST
+Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), \
+BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014
+RIP: 0010:dql_completed+0x26b/0x290
+Code: b7 c2 49 89 e9 44 89 da 89 c6 4c 89 d7 e8 ed 17 47 00 58 65 ff 0d
+4d 27 90 7e 0f 85 fd fe ff ff e8 ea 53 8d ff e9 f3 fe ff ff <0f> 0b 01
+d2 44 89 d1 29 d1 ba 00 00 00 00 0f 48 ca e9 28 ff ff ff
+RSP: 0018:ffffc900002b0d08 EFLAGS: 00010297
+RAX: 0000000000000000 RBX: ffff888102398c80 RCX: 0000000080190009
+RDX: 0000000000000000 RSI: 000000000000006a RDI: 0000000000000000
+RBP: ffff888102398c00 R08: 0000000000000000 R09: 0000000000000000
+R10: 00000000000000ca R11: 0000000000015681 R12: 0000000000000001
+R13: ffffc900002b0d68 R14: ffff88811115e000 R15: ffff8881107aca40
+FS: 00007f41ded69500(0000) GS:ffff888667dc0000(0000)
+knlGS:0000000000000000
+CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+CR2: 0000556ccc2dc1a0 CR3: 0000000104fd8003 CR4: 0000000000772ef0
+PKRU: 55555554
+Call Trace:
+ <IRQ>
+ ? die+0x32/0x80
+ ? do_trap+0xd9/0x100
+ ? dql_completed+0x26b/0x290
+ ? dql_completed+0x26b/0x290
+ ? do_error_trap+0x6d/0xb0
+ ? dql_completed+0x26b/0x290
+ ? exc_invalid_op+0x4c/0x60
+ ? dql_completed+0x26b/0x290
+ ? asm_exc_invalid_op+0x16/0x20
+ ? dql_completed+0x26b/0x290
+ __free_old_xmit+0xff/0x170 [virtio_net]
+ free_old_xmit+0x54/0xc0 [virtio_net]
+ virtnet_poll+0xf4/0xe30 [virtio_net]
+ ? __update_load_avg_cfs_rq+0x264/0x2d0
+ ? update_curr+0x35/0x260
+ ? reweight_entity+0x1be/0x260
+ __napi_poll.constprop.0+0x28/0x1c0
+ net_rx_action+0x329/0x420
+ ? enqueue_hrtimer+0x35/0x90
+ ? trace_hardirqs_on+0x1d/0x80
+ ? kvm_sched_clock_read+0xd/0x20
+ ? sched_clock+0xc/0x30
+ ? kvm_sched_clock_read+0xd/0x20
+ ? sched_clock+0xc/0x30
+ ? sched_clock_cpu+0xd/0x1a0
+ handle_softirqs+0x138/0x3e0
+ do_softirq.part.0+0x89/0xc0
+ </IRQ>
+ <TASK>
+ __local_bh_enable_ip+0xa7/0xb0
+ virtnet_open+0xc8/0x310 [virtio_net]
+ __dev_open+0xfa/0x1b0
+ __dev_change_flags+0x1de/0x250
+ dev_change_flags+0x22/0x60
+ do_setlink.isra.0+0x2df/0x10b0
+ ? rtnetlink_rcv_msg+0x34f/0x3f0
+ ? netlink_rcv_skb+0x54/0x100
+ ? netlink_unicast+0x23e/0x390
+ ? netlink_sendmsg+0x21e/0x490
+ ? ____sys_sendmsg+0x31b/0x350
+ ? avc_has_perm_noaudit+0x67/0xf0
+ ? cred_has_capability.isra.0+0x75/0x110
+ ? __nla_validate_parse+0x5f/0xee0
+ ? __pfx___probestub_irq_enable+0x3/0x10
+ ? __create_object+0x5e/0x90
+ ? security_capable+0x3b/0x70
+ rtnl_newlink+0x784/0xaf0
+ ? avc_has_perm_noaudit+0x67/0xf0
+ ? cred_has_capability.isra.0+0x75/0x110
+ ? stack_depot_save_flags+0x24/0x6d0
+ ? __pfx_rtnl_newlink+0x10/0x10
+ rtnetlink_rcv_msg+0x34f/0x3f0
+ ? do_syscall_64+0x6c/0x180
+ ? entry_SYSCALL_64_after_hwframe+0x76/0x7e
+ ? __pfx_rtnetlink_rcv_msg+0x10/0x10
+ netlink_rcv_skb+0x54/0x100
+ netlink_unicast+0x23e/0x390
+ netlink_sendmsg+0x21e/0x490
+ ____sys_sendmsg+0x31b/0x350
+ ? copy_msghdr_from_user+0x6d/0xa0
+ ___sys_sendmsg+0x86/0xd0
+ ? __pte_offset_map+0x17/0x160
+ ? preempt_count_add+0x69/0xa0
+ ? __call_rcu_common.constprop.0+0x147/0x610
+ ? preempt_count_add+0x69/0xa0
+ ? preempt_count_add+0x69/0xa0
+ ? _raw_spin_trylock+0x13/0x60
+ ? trace_hardirqs_on+0x1d/0x80
+ __sys_sendmsg+0x66/0xc0
+ do_syscall_64+0x6c/0x180
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+RIP: 0033:0x7f41defe5b34
+Code: 15 e1 12 0f 00 f7 d8 64 89 02 b8 ff ff ff ff eb bf 0f 1f 44 00 00
+f3 0f 1e fa 80 3d 35 95 0f 00 00 74 13 b8 2e 00 00 00 0f 05 <48> 3d 00
+f0 ff ff 77 4c c3 0f 1f 00 55 48 89 e5 48 83 ec 20 89 55
+RSP: 002b:00007ffe5336ecc8 EFLAGS: 00000202 ORIG_RAX: 000000000000002e
+RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 00007f41defe5b34
+RDX: 0000000000000000 RSI: 00007ffe5336ed30 RDI: 0000000000000003
+RBP: 00007ffe5336eda0 R08: 0000000000000010 R09: 0000000000000001
+R10: 00007ffe5336f6f9 R11: 0000000000000202 R12: 0000000000000003
+R13: 0000000067452259 R14: 0000556ccc28b040 R15: 0000000000000000
+ </TASK>
+[...]
+
+Fixes: c8bd1f7f3e61 ("virtio_net: add support for Byte Queue Limits")
+Cc: <stable@vger.kernel.org> # v6.11+
+Signed-off-by: Koichiro Den <koichiro.den@canonical.com>
+Acked-by: Jason Wang <jasowang@redhat.com>
+Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
+[ pabeni: trimmed possibly troublesome separator ]
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/virtio_net.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/virtio_net.c
++++ b/drivers/net/virtio_net.c
+@@ -2898,7 +2898,6 @@ static int virtnet_enable_queue_pair(str
+ if (err < 0)
+ goto err_xdp_reg_mem_model;
+
+- netdev_tx_reset_queue(netdev_get_tx_queue(vi->dev, qp_index));
+ virtnet_napi_enable(vi->rq[qp_index].vq, &vi->rq[qp_index].napi);
+ virtnet_napi_tx_enable(vi, vi->sq[qp_index].vq, &vi->sq[qp_index].napi);
+
+@@ -6728,11 +6727,20 @@ free:
+
+ static void remove_vq_common(struct virtnet_info *vi)
+ {
++ int i;
++
+ virtio_reset_device(vi->vdev);
+
+ /* Free unused buffers in both send and recv, if any. */
+ free_unused_bufs(vi);
+
++ /*
++ * Rule of thumb is netdev_tx_reset_queue() should follow any
++ * skb freeing not followed by netdev_tx_completed_queue()
++ */
++ for (i = 0; i < vi->max_queue_pairs; i++)
++ netdev_tx_reset_queue(netdev_get_tx_queue(vi->dev, i));
++
+ free_receive_bufs(vi);
+
+ free_receive_page_frags(vi);
--- /dev/null
+From 1480f0f61b675567ca5d0943d6ef2e39172dcafd Mon Sep 17 00:00:00 2001
+From: Koichiro Den <koichiro.den@canonical.com>
+Date: Fri, 6 Dec 2024 10:10:45 +0900
+Subject: virtio_net: ensure netdev_tx_reset_queue is called on tx ring resize
+
+From: Koichiro Den <koichiro.den@canonical.com>
+
+commit 1480f0f61b675567ca5d0943d6ef2e39172dcafd upstream.
+
+virtnet_tx_resize() flushes remaining tx skbs, requiring DQL counters to
+be reset when flushing has actually occurred. Add
+virtnet_sq_free_unused_buf_done() as a callback for virtqueue_reset() to
+handle this.
+
+Fixes: c8bd1f7f3e61 ("virtio_net: add support for Byte Queue Limits")
+Cc: <stable@vger.kernel.org> # v6.11+
+Signed-off-by: Koichiro Den <koichiro.den@canonical.com>
+Acked-by: Jason Wang <jasowang@redhat.com>
+Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/virtio_net.c | 12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/virtio_net.c
++++ b/drivers/net/virtio_net.c
+@@ -502,6 +502,7 @@ struct virtio_net_common_hdr {
+ };
+
+ static void virtnet_sq_free_unused_buf(struct virtqueue *vq, void *buf);
++static void virtnet_sq_free_unused_buf_done(struct virtqueue *vq);
+ static int virtnet_xdp_handler(struct bpf_prog *xdp_prog, struct xdp_buff *xdp,
+ struct net_device *dev,
+ unsigned int *xdp_xmit,
+@@ -3228,7 +3229,8 @@ static int virtnet_tx_resize(struct virt
+
+ virtnet_tx_pause(vi, sq);
+
+- err = virtqueue_resize(sq->vq, ring_num, virtnet_sq_free_unused_buf, NULL);
++ err = virtqueue_resize(sq->vq, ring_num, virtnet_sq_free_unused_buf,
++ virtnet_sq_free_unused_buf_done);
+ if (err)
+ netdev_err(vi->dev, "resize tx fail: tx queue index: %d err: %d\n", qindex, err);
+
+@@ -5996,6 +5998,14 @@ static void virtnet_sq_free_unused_buf(s
+ xdp_return_frame(ptr_to_xdp(buf));
+ }
+
++static void virtnet_sq_free_unused_buf_done(struct virtqueue *vq)
++{
++ struct virtnet_info *vi = vq->vdev->priv;
++ int i = vq2txq(vq);
++
++ netdev_tx_reset_queue(netdev_get_tx_queue(vi->dev, i));
++}
++
+ static void free_unused_bufs(struct virtnet_info *vi)
+ {
+ void *buf;
--- /dev/null
+From 8d6712c892019b9b9dc5c7039edd3c9d770b510b Mon Sep 17 00:00:00 2001
+From: Koichiro Den <koichiro.den@canonical.com>
+Date: Fri, 6 Dec 2024 10:10:44 +0900
+Subject: virtio_ring: add a func argument 'recycle_done' to virtqueue_resize()
+
+From: Koichiro Den <koichiro.den@canonical.com>
+
+commit 8d6712c892019b9b9dc5c7039edd3c9d770b510b upstream.
+
+When virtqueue_resize() has actually recycled all unused buffers,
+additional work may be required in some cases. Relying solely on its
+return status is fragile, so introduce a new function argument
+'recycle_done', which is invoked when the recycle really occurs.
+
+Cc: <stable@vger.kernel.org> # v6.11+
+Signed-off-by: Koichiro Den <koichiro.den@canonical.com>
+Acked-by: Jason Wang <jasowang@redhat.com>
+Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/virtio_net.c | 4 ++--
+ drivers/virtio/virtio_ring.c | 6 +++++-
+ include/linux/virtio.h | 3 ++-
+ 3 files changed, 9 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/virtio_net.c
++++ b/drivers/net/virtio_net.c
+@@ -3165,7 +3165,7 @@ static int virtnet_rx_resize(struct virt
+
+ virtnet_rx_pause(vi, rq);
+
+- err = virtqueue_resize(rq->vq, ring_num, virtnet_rq_unmap_free_buf);
++ err = virtqueue_resize(rq->vq, ring_num, virtnet_rq_unmap_free_buf, NULL);
+ if (err)
+ netdev_err(vi->dev, "resize rx fail: rx queue index: %d err: %d\n", qindex, err);
+
+@@ -3228,7 +3228,7 @@ static int virtnet_tx_resize(struct virt
+
+ virtnet_tx_pause(vi, sq);
+
+- err = virtqueue_resize(sq->vq, ring_num, virtnet_sq_free_unused_buf);
++ err = virtqueue_resize(sq->vq, ring_num, virtnet_sq_free_unused_buf, NULL);
+ if (err)
+ netdev_err(vi->dev, "resize tx fail: tx queue index: %d err: %d\n", qindex, err);
+
+--- a/drivers/virtio/virtio_ring.c
++++ b/drivers/virtio/virtio_ring.c
+@@ -2716,6 +2716,7 @@ EXPORT_SYMBOL_GPL(vring_create_virtqueue
+ * @_vq: the struct virtqueue we're talking about.
+ * @num: new ring num
+ * @recycle: callback to recycle unused buffers
++ * @recycle_done: callback to be invoked when recycle for all unused buffers done
+ *
+ * When it is really necessary to create a new vring, it will set the current vq
+ * into the reset state. Then call the passed callback to recycle the buffer
+@@ -2736,7 +2737,8 @@ EXPORT_SYMBOL_GPL(vring_create_virtqueue
+ *
+ */
+ int virtqueue_resize(struct virtqueue *_vq, u32 num,
+- void (*recycle)(struct virtqueue *vq, void *buf))
++ void (*recycle)(struct virtqueue *vq, void *buf),
++ void (*recycle_done)(struct virtqueue *vq))
+ {
+ struct vring_virtqueue *vq = to_vvq(_vq);
+ int err;
+@@ -2753,6 +2755,8 @@ int virtqueue_resize(struct virtqueue *_
+ err = virtqueue_disable_and_recycle(_vq, recycle);
+ if (err)
+ return err;
++ if (recycle_done)
++ recycle_done(_vq);
+
+ if (vq->packed_ring)
+ err = virtqueue_resize_packed(_vq, num);
+--- a/include/linux/virtio.h
++++ b/include/linux/virtio.h
+@@ -100,7 +100,8 @@ dma_addr_t virtqueue_get_avail_addr(cons
+ dma_addr_t virtqueue_get_used_addr(const struct virtqueue *vq);
+
+ int virtqueue_resize(struct virtqueue *vq, u32 num,
+- void (*recycle)(struct virtqueue *vq, void *buf));
++ void (*recycle)(struct virtqueue *vq, void *buf),
++ void (*recycle_done)(struct virtqueue *vq));
+ int virtqueue_reset(struct virtqueue *vq,
+ void (*recycle)(struct virtqueue *vq, void *buf));
+