From bf07704355800ce7f76a3b3974706b479d39d0a0 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 27 Nov 2025 15:04:42 +0100 Subject: [PATCH] 5.4-stable patches added patches: ata-libata-scsi-fix-system-suspend-for-a-security-locked-drive.patch fs-proc-fix-uaf-in-proc_readdir_de.patch input-pegasus-notetaker-fix-potential-out-of-bounds-access.patch input-remove-third-argument-of-usb_maxpacket.patch mm-mempool-fix-poisoning-order-0-pages-with-highmem.patch mm-mempool-replace-kmap_atomic-with-kmap_local_page.patch mm-mprotect-delete-pmd_none_or_clear_bad_unless_trans_huge.patch mm-mprotect-use-long-for-page-accountings-and-retval.patch net-netpoll-fix-incorrect-refcount-handling-causing-incorrect-cleanup.patch net-qede-initialize-qede_ll_ops-with-designated-initializer.patch pmdomain-arm-scmi-fix-genpd-leak-on-provider-registration-failure.patch pmdomain-imx-fix-reference-count-leak-in-imx_gpc_remove.patch uio_hv_generic-set-event-for-all-channels-on-the-device.patch usb-deprecate-the-third-argument-of-usb_maxpacket.patch --- ...-suspend-for-a-security-locked-drive.patch | 82 ++++++ .../fs-proc-fix-uaf-in-proc_readdir_de.patch | 107 +++++++ ...r-fix-potential-out-of-bounds-access.patch | 58 ++++ ...move-third-argument-of-usb_maxpacket.patch | 106 +++++++ ...poisoning-order-0-pages-with-highmem.patch | 110 +++++++ ...ace-kmap_atomic-with-kmap_local_page.patch | 71 +++++ ..._none_or_clear_bad_unless_trans_huge.patch | 273 ++++++++++++++++++ ...long-for-page-accountings-and-retval.patch | 222 ++++++++++++++ ...t-handling-causing-incorrect-cleanup.patch | 85 ++++++ ...e_ll_ops-with-designated-initializer.patch | 43 +++ ...eak-on-provider-registration-failure.patch | 82 ++++++ ...ference-count-leak-in-imx_gpc_remove.patch | 38 +++ queue-5.4/series | 14 + ...event-for-all-channels-on-the-device.patch | 74 +++++ ...-the-third-argument-of-usb_maxpacket.patch | 85 ++++++ 15 files changed, 1450 insertions(+) create mode 100644 queue-5.4/ata-libata-scsi-fix-system-suspend-for-a-security-locked-drive.patch create mode 100644 queue-5.4/fs-proc-fix-uaf-in-proc_readdir_de.patch create mode 100644 queue-5.4/input-pegasus-notetaker-fix-potential-out-of-bounds-access.patch create mode 100644 queue-5.4/input-remove-third-argument-of-usb_maxpacket.patch create mode 100644 queue-5.4/mm-mempool-fix-poisoning-order-0-pages-with-highmem.patch create mode 100644 queue-5.4/mm-mempool-replace-kmap_atomic-with-kmap_local_page.patch create mode 100644 queue-5.4/mm-mprotect-delete-pmd_none_or_clear_bad_unless_trans_huge.patch create mode 100644 queue-5.4/mm-mprotect-use-long-for-page-accountings-and-retval.patch create mode 100644 queue-5.4/net-netpoll-fix-incorrect-refcount-handling-causing-incorrect-cleanup.patch create mode 100644 queue-5.4/net-qede-initialize-qede_ll_ops-with-designated-initializer.patch create mode 100644 queue-5.4/pmdomain-arm-scmi-fix-genpd-leak-on-provider-registration-failure.patch create mode 100644 queue-5.4/pmdomain-imx-fix-reference-count-leak-in-imx_gpc_remove.patch create mode 100644 queue-5.4/uio_hv_generic-set-event-for-all-channels-on-the-device.patch create mode 100644 queue-5.4/usb-deprecate-the-third-argument-of-usb_maxpacket.patch diff --git a/queue-5.4/ata-libata-scsi-fix-system-suspend-for-a-security-locked-drive.patch b/queue-5.4/ata-libata-scsi-fix-system-suspend-for-a-security-locked-drive.patch new file mode 100644 index 0000000000..ec55311e1e --- /dev/null +++ b/queue-5.4/ata-libata-scsi-fix-system-suspend-for-a-security-locked-drive.patch @@ -0,0 +1,82 @@ +From stable+bounces-196790-greg=kroah.com@vger.kernel.org Mon Nov 24 20:23:20 2025 +From: Sasha Levin +Date: Mon, 24 Nov 2025 14:20:34 -0500 +Subject: ata: libata-scsi: Fix system suspend for a security locked drive +To: stable@vger.kernel.org +Cc: Niklas Cassel , Ilia Baryshnikov , Hannes Reinecke , "Martin K. Petersen" , Damien Le Moal , Sasha Levin +Message-ID: <20251124192034.3511-1-sashal@kernel.org> + +From: Niklas Cassel + +[ Upstream commit b11890683380a36b8488229f818d5e76e8204587 ] + +Commit cf3fc037623c ("ata: libata-scsi: Fix ata_to_sense_error() status +handling") fixed ata_to_sense_error() to properly generate sense key +ABORTED COMMAND (without any additional sense code), instead of the +previous bogus sense key ILLEGAL REQUEST with the additional sense code +UNALIGNED WRITE COMMAND, for a failed command. + +However, this broke suspend for Security locked drives (drives that have +Security enabled, and have not been Security unlocked by boot firmware). + +The reason for this is that the SCSI disk driver, for the Synchronize +Cache command only, treats any sense data with sense key ILLEGAL REQUEST +as a successful command (regardless of ASC / ASCQ). + +After commit cf3fc037623c ("ata: libata-scsi: Fix ata_to_sense_error() +status handling") the code that treats any sense data with sense key +ILLEGAL REQUEST as a successful command is no longer applicable, so the +command fails, which causes the system suspend to be aborted: + + sd 1:0:0:0: PM: dpm_run_callback(): scsi_bus_suspend returns -5 + sd 1:0:0:0: PM: failed to suspend async: error -5 + PM: Some devices failed to suspend, or early wake event detected + +To make suspend work once again, for a Security locked device only, +return sense data LOGICAL UNIT ACCESS NOT AUTHORIZED, the actual sense +data which a real SCSI device would have returned if locked. +The SCSI disk driver treats this sense data as a successful command. + +Cc: stable@vger.kernel.org +Reported-by: Ilia Baryshnikov +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220704 +Fixes: cf3fc037623c ("ata: libata-scsi: Fix ata_to_sense_error() status handling") +Reviewed-by: Hannes Reinecke +Reviewed-by: Martin K. Petersen +Reviewed-by: Damien Le Moal +Signed-off-by: Niklas Cassel +[ Adjust context ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/ata/libata-scsi.c | 8 ++++++++ + include/linux/ata.h | 1 + + 2 files changed, 9 insertions(+) + +--- a/drivers/ata/libata-scsi.c ++++ b/drivers/ata/libata-scsi.c +@@ -1179,6 +1179,14 @@ static void ata_gen_ata_sense(struct ata + ata_scsi_set_sense(dev, cmd, NOT_READY, 0x04, 0x21); + return; + } ++ ++ if (ata_id_is_locked(dev->id)) { ++ /* Security locked */ ++ /* LOGICAL UNIT ACCESS NOT AUTHORIZED */ ++ ata_scsi_set_sense(dev, cmd, DATA_PROTECT, 0x74, 0x71); ++ return; ++ } ++ + /* Use ata_to_sense_error() to map status register bits + * onto sense key, asc & ascq. + */ +--- a/include/linux/ata.h ++++ b/include/linux/ata.h +@@ -557,6 +557,7 @@ struct ata_bmdma_prd { + #define ata_id_has_ncq(id) ((id)[ATA_ID_SATA_CAPABILITY] & (1 << 8)) + #define ata_id_queue_depth(id) (((id)[ATA_ID_QUEUE_DEPTH] & 0x1f) + 1) + #define ata_id_removable(id) ((id)[ATA_ID_CONFIG] & (1 << 7)) ++#define ata_id_is_locked(id) (((id)[ATA_ID_DLF] & 0x7) == 0x7) + #define ata_id_has_atapi_AN(id) \ + ((((id)[ATA_ID_SATA_CAPABILITY] != 0x0000) && \ + ((id)[ATA_ID_SATA_CAPABILITY] != 0xffff)) && \ diff --git a/queue-5.4/fs-proc-fix-uaf-in-proc_readdir_de.patch b/queue-5.4/fs-proc-fix-uaf-in-proc_readdir_de.patch new file mode 100644 index 0000000000..7bfe2e191e --- /dev/null +++ b/queue-5.4/fs-proc-fix-uaf-in-proc_readdir_de.patch @@ -0,0 +1,107 @@ +From stable+bounces-195420-greg=kroah.com@vger.kernel.org Thu Nov 20 21:24:25 2025 +From: Sasha Levin +Date: Thu, 20 Nov 2025 15:23:17 -0500 +Subject: fs/proc: fix uaf in proc_readdir_de() +To: stable@vger.kernel.org +Cc: Wei Yang , Al Viro , Christian Brauner , wangzijie , Alexey Dobriyan , Andrew Morton , Sasha Levin +Message-ID: <20251120202317.2307846-1-sashal@kernel.org> + +From: Wei Yang + +[ Upstream commit 895b4c0c79b092d732544011c3cecaf7322c36a1 ] + +Pde is erased from subdir rbtree through rb_erase(), but not set the node +to EMPTY, which may result in uaf access. We should use RB_CLEAR_NODE() +set the erased node to EMPTY, then pde_subdir_next() will return NULL to +avoid uaf access. + +We found an uaf issue while using stress-ng testing, need to run testcase +getdent and tun in the same time. The steps of the issue is as follows: + +1) use getdent to traverse dir /proc/pid/net/dev_snmp6/, and current + pde is tun3; + +2) in the [time windows] unregister netdevice tun3 and tun2, and erase + them from rbtree. erase tun3 first, and then erase tun2. the + pde(tun2) will be released to slab; + +3) continue to getdent process, then pde_subdir_next() will return + pde(tun2) which is released, it will case uaf access. + +CPU 0 | CPU 1 +------------------------------------------------------------------------- +traverse dir /proc/pid/net/dev_snmp6/ | unregister_netdevice(tun->dev) //tun3 tun2 +sys_getdents64() | + iterate_dir() | + proc_readdir() | + proc_readdir_de() | snmp6_unregister_dev() + pde_get(de); | proc_remove() + read_unlock(&proc_subdir_lock); | remove_proc_subtree() + | write_lock(&proc_subdir_lock); + [time window] | rb_erase(&root->subdir_node, &parent->subdir); + | write_unlock(&proc_subdir_lock); + read_lock(&proc_subdir_lock); | + next = pde_subdir_next(de); | + pde_put(de); | + de = next; //UAF | + +rbtree of dev_snmp6 + | + pde(tun3) + / \ + NULL pde(tun2) + +Link: https://lkml.kernel.org/r/20251025024233.158363-1-albin_yang@163.com +Signed-off-by: Wei Yang +Cc: Al Viro +Cc: Christian Brauner +Cc: wangzijie +Cc: Alexey Dobriyan +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/proc/generic.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +--- a/fs/proc/generic.c ++++ b/fs/proc/generic.c +@@ -671,6 +671,12 @@ void pde_put(struct proc_dir_entry *pde) + } + } + ++static void pde_erase(struct proc_dir_entry *pde, struct proc_dir_entry *parent) ++{ ++ rb_erase(&pde->subdir_node, &parent->subdir); ++ RB_CLEAR_NODE(&pde->subdir_node); ++} ++ + /* + * Remove a /proc entry and free it if it's not currently in use. + */ +@@ -689,7 +695,7 @@ void remove_proc_entry(const char *name, + + de = pde_subdir_find(parent, fn, len); + if (de) { +- rb_erase(&de->subdir_node, &parent->subdir); ++ pde_erase(de, parent); + if (S_ISDIR(de->mode)) { + parent->nlink--; + } +@@ -727,13 +733,13 @@ int remove_proc_subtree(const char *name + write_unlock(&proc_subdir_lock); + return -ENOENT; + } +- rb_erase(&root->subdir_node, &parent->subdir); ++ pde_erase(root, parent); + + de = root; + while (1) { + next = pde_subdir_first(de); + if (next) { +- rb_erase(&next->subdir_node, &de->subdir); ++ pde_erase(next, de); + de = next; + continue; + } diff --git a/queue-5.4/input-pegasus-notetaker-fix-potential-out-of-bounds-access.patch b/queue-5.4/input-pegasus-notetaker-fix-potential-out-of-bounds-access.patch new file mode 100644 index 0000000000..25e0eaa84b --- /dev/null +++ b/queue-5.4/input-pegasus-notetaker-fix-potential-out-of-bounds-access.patch @@ -0,0 +1,58 @@ +From stable+bounces-196793-greg=kroah.com@vger.kernel.org Mon Nov 24 20:23:16 2025 +From: Sasha Levin +Date: Mon, 24 Nov 2025 14:20:46 -0500 +Subject: Input: pegasus-notetaker - fix potential out-of-bounds access +To: stable@vger.kernel.org +Cc: Seungjin Bae , Dmitry Torokhov , Sasha Levin +Message-ID: <20251124192046.3812-3-sashal@kernel.org> + +From: Seungjin Bae + +[ Upstream commit 69aeb507312306f73495598a055293fa749d454e ] + +In the pegasus_notetaker driver, the pegasus_probe() function allocates +the URB transfer buffer using the wMaxPacketSize value from +the endpoint descriptor. An attacker can use a malicious USB descriptor +to force the allocation of a very small buffer. + +Subsequently, if the device sends an interrupt packet with a specific +pattern (e.g., where the first byte is 0x80 or 0x42), +the pegasus_parse_packet() function parses the packet without checking +the allocated buffer size. This leads to an out-of-bounds memory access. + +Fixes: 1afca2b66aac ("Input: add Pegasus Notetaker tablet driver") +Signed-off-by: Seungjin Bae +Link: https://lore.kernel.org/r/20251007214131.3737115-2-eeodqql09@gmail.com +Cc: stable@vger.kernel.org +Signed-off-by: Dmitry Torokhov +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/input/tablet/pegasus_notetaker.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/drivers/input/tablet/pegasus_notetaker.c ++++ b/drivers/input/tablet/pegasus_notetaker.c +@@ -63,6 +63,9 @@ + #define BUTTON_PRESSED 0xb5 + #define COMMAND_VERSION 0xa9 + ++/* 1 Status + 1 Color + 2 X + 2 Y = 6 bytes */ ++#define NOTETAKER_PACKET_SIZE 6 ++ + /* in xy data packet */ + #define BATTERY_NO_REPORT 0x40 + #define BATTERY_LOW 0x41 +@@ -297,6 +300,12 @@ static int pegasus_probe(struct usb_inte + + pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); + pegasus->data_len = usb_maxpacket(dev, pipe); ++ if (pegasus->data_len < NOTETAKER_PACKET_SIZE) { ++ dev_err(&intf->dev, "packet size is too small (%d)\n", ++ pegasus->data_len); ++ error = -EINVAL; ++ goto err_free_mem; ++ } + + pegasus->data = usb_alloc_coherent(dev, pegasus->data_len, GFP_KERNEL, + &pegasus->data_dma); diff --git a/queue-5.4/input-remove-third-argument-of-usb_maxpacket.patch b/queue-5.4/input-remove-third-argument-of-usb_maxpacket.patch new file mode 100644 index 0000000000..e54a8c32c5 --- /dev/null +++ b/queue-5.4/input-remove-third-argument-of-usb_maxpacket.patch @@ -0,0 +1,106 @@ +From sashal@kernel.org Mon Nov 24 20:20:55 2025 +From: Sasha Levin +Date: Mon, 24 Nov 2025 14:20:45 -0500 +Subject: Input: remove third argument of usb_maxpacket() +To: stable@vger.kernel.org +Cc: Vincent Mailhol , Ville Syrjala , Dmitry Torokhov , Henk Vergonet , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20251124192046.3812-2-sashal@kernel.org> + +From: Vincent Mailhol + +[ Upstream commit 948bf187694fc1f4c20cf972fa18b1a6fb3d7603 ] + +The third argument of usb_maxpacket(): in_out has been deprecated +because it could be derived from the second argument (e.g. using +usb_pipeout(pipe)). + +N.B. function usb_maxpacket() was made variadic to accommodate the +transition from the old prototype with three arguments to the new one +with only two arguments (so that no renaming is needed). The variadic +argument is to be removed once all users of usb_maxpacket() get +migrated. + +CC: Ville Syrjala +CC: Dmitry Torokhov +CC: Henk Vergonet +Signed-off-by: Vincent Mailhol +Link: https://lore.kernel.org/r/20220317035514.6378-4-mailhol.vincent@wanadoo.fr +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 69aeb5073123 ("Input: pegasus-notetaker - fix potential out-of-bounds access") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/input/misc/ati_remote2.c | 2 +- + drivers/input/misc/cm109.c | 2 +- + drivers/input/misc/powermate.c | 2 +- + drivers/input/misc/yealink.c | 2 +- + drivers/input/tablet/acecad.c | 2 +- + drivers/input/tablet/pegasus_notetaker.c | 2 +- + 6 files changed, 6 insertions(+), 6 deletions(-) + +--- a/drivers/input/misc/ati_remote2.c ++++ b/drivers/input/misc/ati_remote2.c +@@ -639,7 +639,7 @@ static int ati_remote2_urb_init(struct a + return -ENOMEM; + + pipe = usb_rcvintpipe(udev, ar2->ep[i]->bEndpointAddress); +- maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); ++ maxp = usb_maxpacket(udev, pipe); + maxp = maxp > 4 ? 4 : maxp; + + usb_fill_int_urb(ar2->urb[i], udev, pipe, ar2->buf[i], maxp, +--- a/drivers/input/misc/cm109.c ++++ b/drivers/input/misc/cm109.c +@@ -749,7 +749,7 @@ static int cm109_usb_probe(struct usb_in + + /* get a handle to the interrupt data pipe */ + pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress); +- ret = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); ++ ret = usb_maxpacket(udev, pipe); + if (ret != USB_PKT_LEN) + dev_err(&intf->dev, "invalid payload size %d, expected %d\n", + ret, USB_PKT_LEN); +--- a/drivers/input/misc/powermate.c ++++ b/drivers/input/misc/powermate.c +@@ -374,7 +374,7 @@ static int powermate_probe(struct usb_in + + /* get a handle to the interrupt data pipe */ + pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress); +- maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); ++ maxp = usb_maxpacket(udev, pipe); + + if (maxp < POWERMATE_PAYLOAD_SIZE_MIN || maxp > POWERMATE_PAYLOAD_SIZE_MAX) { + printk(KERN_WARNING "powermate: Expected payload of %d--%d bytes, found %d bytes!\n", +--- a/drivers/input/misc/yealink.c ++++ b/drivers/input/misc/yealink.c +@@ -905,7 +905,7 @@ static int usb_probe(struct usb_interfac + + /* get a handle to the interrupt data pipe */ + pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress); +- ret = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); ++ ret = usb_maxpacket(udev, pipe); + if (ret != USB_PKT_LEN) + dev_err(&intf->dev, "invalid payload size %d, expected %zd\n", + ret, USB_PKT_LEN); +--- a/drivers/input/tablet/acecad.c ++++ b/drivers/input/tablet/acecad.c +@@ -130,7 +130,7 @@ static int usb_acecad_probe(struct usb_i + return -ENODEV; + + pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); +- maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); ++ maxp = usb_maxpacket(dev, pipe); + + acecad = kzalloc(sizeof(struct usb_acecad), GFP_KERNEL); + input_dev = input_allocate_device(); +--- a/drivers/input/tablet/pegasus_notetaker.c ++++ b/drivers/input/tablet/pegasus_notetaker.c +@@ -296,7 +296,7 @@ static int pegasus_probe(struct usb_inte + pegasus->intf = intf; + + pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); +- pegasus->data_len = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); ++ pegasus->data_len = usb_maxpacket(dev, pipe); + + pegasus->data = usb_alloc_coherent(dev, pegasus->data_len, GFP_KERNEL, + &pegasus->data_dma); diff --git a/queue-5.4/mm-mempool-fix-poisoning-order-0-pages-with-highmem.patch b/queue-5.4/mm-mempool-fix-poisoning-order-0-pages-with-highmem.patch new file mode 100644 index 0000000000..0eb14147c5 --- /dev/null +++ b/queue-5.4/mm-mempool-fix-poisoning-order-0-pages-with-highmem.patch @@ -0,0 +1,110 @@ +From stable+bounces-196812-greg=kroah.com@vger.kernel.org Mon Nov 24 22:43:40 2025 +From: Sasha Levin +Date: Mon, 24 Nov 2025 16:43:34 -0500 +Subject: mm/mempool: fix poisoning order>0 pages with HIGHMEM +To: stable@vger.kernel.org +Cc: Vlastimil Babka , kernel test robot , Christoph Hellwig , Sasha Levin +Message-ID: <20251124214334.44494-2-sashal@kernel.org> + +From: Vlastimil Babka + +[ Upstream commit ec33b59542d96830e3c89845ff833cf7b25ef172 ] + +The kernel test has reported: + + BUG: unable to handle page fault for address: fffba000 + #PF: supervisor write access in kernel mode + #PF: error_code(0x0002) - not-present page + *pde = 03171067 *pte = 00000000 + Oops: Oops: 0002 [#1] + CPU: 0 UID: 0 PID: 1 Comm: swapper/0 Tainted: G T 6.18.0-rc2-00031-gec7f31b2a2d3 #1 NONE a1d066dfe789f54bc7645c7989957d2bdee593ca + Tainted: [T]=RANDSTRUCT + Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 + EIP: memset (arch/x86/include/asm/string_32.h:168 arch/x86/lib/memcpy_32.c:17) + Code: a5 8b 4d f4 83 e1 03 74 02 f3 a4 83 c4 04 5e 5f 5d 2e e9 73 41 01 00 90 90 90 3e 8d 74 26 00 55 89 e5 57 56 89 c6 89 d0 89 f7 aa 89 f0 5e 5f 5d 2e e9 53 41 01 00 cc cc cc 55 89 e5 53 57 56 + EAX: 0000006b EBX: 00000015 ECX: 001fefff EDX: 0000006b + ESI: fffb9000 EDI: fffba000 EBP: c611fbf0 ESP: c611fbe8 + DS: 007b ES: 007b FS: 0000 GS: 0000 SS: 0068 EFLAGS: 00010287 + CR0: 80050033 CR2: fffba000 CR3: 0316e000 CR4: 00040690 + Call Trace: + poison_element (mm/mempool.c:83 mm/mempool.c:102) + mempool_init_node (mm/mempool.c:142 mm/mempool.c:226) + mempool_init_noprof (mm/mempool.c:250 (discriminator 1)) + ? mempool_alloc_pages (mm/mempool.c:640) + bio_integrity_initfn (block/bio-integrity.c:483 (discriminator 8)) + ? mempool_alloc_pages (mm/mempool.c:640) + do_one_initcall (init/main.c:1283) + +Christoph found out this is due to the poisoning code not dealing +properly with CONFIG_HIGHMEM because only the first page is mapped but +then the whole potentially high-order page is accessed. + +We could give up on HIGHMEM here, but it's straightforward to fix this +with a loop that's mapping, poisoning or checking and unmapping +individual pages. + +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-lkp/202511111411.9ebfa1ba-lkp@intel.com +Analyzed-by: Christoph Hellwig +Fixes: bdfedb76f4f5 ("mm, mempool: poison elements backed by slab allocator") +Cc: stable@vger.kernel.org +Tested-by: kernel test robot +Reviewed-by: Christoph Hellwig +Link: https://patch.msgid.link/20251113-mempool-poison-v1-1-233b3ef984c3@suse.cz +Signed-off-by: Vlastimil Babka +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + mm/mempool.c | 32 ++++++++++++++++++++++++++------ + 1 file changed, 26 insertions(+), 6 deletions(-) + +--- a/mm/mempool.c ++++ b/mm/mempool.c +@@ -64,10 +64,20 @@ static void check_element(mempool_t *poo + /* Mempools backed by page allocator */ + if (pool->free == mempool_free_pages) { + int order = (int)(long)pool->pool_data; +- void *addr = kmap_local_page((struct page *)element); + +- __check_element(pool, addr, 1UL << (PAGE_SHIFT + order)); +- kunmap_local(addr); ++#ifdef CONFIG_HIGHMEM ++ for (int i = 0; i < (1 << order); i++) { ++ struct page *page = (struct page *)element; ++ void *addr = kmap_local_page(page + i); ++ ++ __check_element(pool, addr, PAGE_SIZE); ++ kunmap_local(addr); ++ } ++#else ++ void *addr = page_address((struct page *)element); ++ ++ __check_element(pool, addr, PAGE_SIZE << order); ++#endif + } + } + +@@ -88,10 +98,20 @@ static void poison_element(mempool_t *po + /* Mempools backed by page allocator */ + if (pool->alloc == mempool_alloc_pages) { + int order = (int)(long)pool->pool_data; +- void *addr = kmap_local_page((struct page *)element); + +- __poison_element(addr, 1UL << (PAGE_SHIFT + order)); +- kunmap_local(addr); ++#ifdef CONFIG_HIGHMEM ++ for (int i = 0; i < (1 << order); i++) { ++ struct page *page = (struct page *)element; ++ void *addr = kmap_local_page(page + i); ++ ++ __poison_element(addr, PAGE_SIZE); ++ kunmap_local(addr); ++ } ++#else ++ void *addr = page_address((struct page *)element); ++ ++ __poison_element(addr, PAGE_SIZE << order); ++#endif + } + } + #else /* CONFIG_DEBUG_SLAB || CONFIG_SLUB_DEBUG_ON */ diff --git a/queue-5.4/mm-mempool-replace-kmap_atomic-with-kmap_local_page.patch b/queue-5.4/mm-mempool-replace-kmap_atomic-with-kmap_local_page.patch new file mode 100644 index 0000000000..83aafbaaa6 --- /dev/null +++ b/queue-5.4/mm-mempool-replace-kmap_atomic-with-kmap_local_page.patch @@ -0,0 +1,71 @@ +From stable+bounces-196811-greg=kroah.com@vger.kernel.org Mon Nov 24 22:43:40 2025 +From: Sasha Levin +Date: Mon, 24 Nov 2025 16:43:33 -0500 +Subject: mm/mempool: replace kmap_atomic() with kmap_local_page() +To: stable@vger.kernel.org +Cc: "Fabio M. De Francesco" , Ira Weiny , Andrew Morton , Sasha Levin +Message-ID: <20251124214334.44494-1-sashal@kernel.org> + +From: "Fabio M. De Francesco" + +[ Upstream commit f2bcc99a5e901a13b754648d1dbab60f4adf9375 ] + +kmap_atomic() has been deprecated in favor of kmap_local_page(). + +Therefore, replace kmap_atomic() with kmap_local_page(). + +kmap_atomic() is implemented like a kmap_local_page() which also disables +page-faults and preemption (the latter only in !PREEMPT_RT kernels). The +kernel virtual addresses returned by these two API are only valid in the +context of the callers (i.e., they cannot be handed to other threads). + +With kmap_local_page() the mappings are per thread and CPU local like in +kmap_atomic(); however, they can handle page-faults and can be called from +any context (including interrupts). The tasks that call kmap_local_page() +can be preempted and, when they are scheduled to run again, the kernel +virtual addresses are restored and are still valid. + +The code blocks between the mappings and un-mappings don't rely on the +above-mentioned side effects of kmap_atomic(), so that mere replacements +of the old API with the new one is all that they require (i.e., there is +no need to explicitly call pagefault_disable() and/or preempt_disable()). + +Link: https://lkml.kernel.org/r/20231120142640.7077-1-fabio.maria.de.francesco@linux.intel.com +Signed-off-by: Fabio M. De Francesco +Cc: Ira Weiny +Signed-off-by: Andrew Morton +Stable-dep-of: ec33b59542d9 ("mm/mempool: fix poisoning order>0 pages with HIGHMEM") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + mm/mempool.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/mm/mempool.c ++++ b/mm/mempool.c +@@ -64,10 +64,10 @@ static void check_element(mempool_t *poo + /* Mempools backed by page allocator */ + if (pool->free == mempool_free_pages) { + int order = (int)(long)pool->pool_data; +- void *addr = kmap_atomic((struct page *)element); ++ void *addr = kmap_local_page((struct page *)element); + + __check_element(pool, addr, 1UL << (PAGE_SHIFT + order)); +- kunmap_atomic(addr); ++ kunmap_local(addr); + } + } + +@@ -88,10 +88,10 @@ static void poison_element(mempool_t *po + /* Mempools backed by page allocator */ + if (pool->alloc == mempool_alloc_pages) { + int order = (int)(long)pool->pool_data; +- void *addr = kmap_atomic((struct page *)element); ++ void *addr = kmap_local_page((struct page *)element); + + __poison_element(addr, 1UL << (PAGE_SHIFT + order)); +- kunmap_atomic(addr); ++ kunmap_local(addr); + } + } + #else /* CONFIG_DEBUG_SLAB || CONFIG_SLUB_DEBUG_ON */ diff --git a/queue-5.4/mm-mprotect-delete-pmd_none_or_clear_bad_unless_trans_huge.patch b/queue-5.4/mm-mprotect-delete-pmd_none_or_clear_bad_unless_trans_huge.patch new file mode 100644 index 0000000000..5a40aca401 --- /dev/null +++ b/queue-5.4/mm-mprotect-delete-pmd_none_or_clear_bad_unless_trans_huge.patch @@ -0,0 +1,273 @@ +From stable+bounces-196861-greg=kroah.com@vger.kernel.org Tue Nov 25 06:10:55 2025 +From: Harry Yoo +Date: Tue, 25 Nov 2025 14:09:26 +0900 +Subject: mm/mprotect: delete pmd_none_or_clear_bad_unless_trans_huge() +To: stable@vger.kernel.org +Cc: Liam.Howlett@oracle.com, akpm@linux-foundation.org, baohua@kernel.org, baolin.wang@linux.alibaba.com, david@kernel.org, dev.jain@arm.com, hughd@google.com, jane.chu@oracle.com, jannh@google.com, kas@kernel.org, lance.yang@linux.dev, linux-mm@kvack.org, lorenzo.stoakes@oracle.com, npache@redhat.com, pfalcato@suse.de, ryan.roberts@arm.com, vbabka@suse.cz, ziy@nvidia.com, "Alistair Popple" , "Anshuman Khandual" , "Axel Rasmussen" , "Christophe Leroy" , "Christoph Hellwig" , "David Hildenbrand" , "Huang, Ying" , "Ira Weiny" , "Jason Gunthorpe" , "Kirill A . Shutemov" , "Lorenzo Stoakes" , "Matthew Wilcox" , "Mel Gorman" , "Miaohe Lin" , "Mike Kravetz" , "Mike Rapoport" , "Minchan Kim" , "Naoya Horiguchi" , "Pavel Tatashin" , "Peter Xu" , "Peter Zijlstra" , "Qi Zheng" , "Ralph Campbell" , "SeongJae Park" , "Song Liu" , "Steven Price" , "Suren Baghdasaryan" , "Thomas Hellström" , "Will Deacon" , "Yang Shi" , "Yu Zhao" , "Zack Rusin" +Message-ID: <20251125050926.1100484-3-harry.yoo@oracle.com> + +From: Hugh Dickins + +commit 670ddd8cdcbd1d07a4571266ae3517f821728c3a upstream. + +change_pmd_range() had special pmd_none_or_clear_bad_unless_trans_huge(), +required to avoid "bad" choices when setting automatic NUMA hinting under +mmap_read_lock(); but most of that is already covered in pte_offset_map() +now. change_pmd_range() just wants a pmd_none() check before wasting time +on MMU notifiers, then checks on the read-once _pmd value to work out +what's needed for huge cases. If change_pte_range() returns -EAGAIN to +retry if pte_offset_map_lock() fails, nothing more special is needed. + +Link: https://lkml.kernel.org/r/725a42a9-91e9-c868-925-e3a5fd40bb4f@google.com +Signed-off-by: Hugh Dickins +Cc: Alistair Popple +Cc: Anshuman Khandual +Cc: Axel Rasmussen +Cc: Christophe Leroy +Cc: Christoph Hellwig +Cc: David Hildenbrand +Cc: "Huang, Ying" +Cc: Ira Weiny +Cc: Jason Gunthorpe +Cc: Kirill A. Shutemov +Cc: Lorenzo Stoakes +Cc: Matthew Wilcox +Cc: Mel Gorman +Cc: Miaohe Lin +Cc: Mike Kravetz +Cc: Mike Rapoport (IBM) +Cc: Minchan Kim +Cc: Naoya Horiguchi +Cc: Pavel Tatashin +Cc: Peter Xu +Cc: Peter Zijlstra +Cc: Qi Zheng +Cc: Ralph Campbell +Cc: Ryan Roberts +Cc: SeongJae Park +Cc: Song Liu +Cc: Steven Price +Cc: Suren Baghdasaryan +Cc: Thomas Hellström +Cc: Will Deacon +Cc: Yang Shi +Cc: Yu Zhao +Cc: Zack Rusin +Signed-off-by: Andrew Morton +[ Background: + + It was reported that a bad pmd is seen when automatic NUMA balancing + is marking page table entries as prot_numa: + + [2437548.196018] mm/pgtable-generic.c:50: bad pmd 00000000af22fc02(dffffffe71fbfe02) + [2437548.235022] Call Trace: + [2437548.238234] + [2437548.241060] dump_stack_lvl+0x46/0x61 + [2437548.245689] panic+0x106/0x2e5 + [2437548.249497] pmd_clear_bad+0x3c/0x3c + [2437548.253967] change_pmd_range.isra.0+0x34d/0x3a7 + [2437548.259537] change_p4d_range+0x156/0x20e + [2437548.264392] change_protection_range+0x116/0x1a9 + [2437548.269976] change_prot_numa+0x15/0x37 + [2437548.274774] task_numa_work+0x1b8/0x302 + [2437548.279512] task_work_run+0x62/0x95 + [2437548.283882] exit_to_user_mode_loop+0x1a4/0x1a9 + [2437548.289277] exit_to_user_mode_prepare+0xf4/0xfc + [2437548.294751] ? sysvec_apic_timer_interrupt+0x34/0x81 + [2437548.300677] irqentry_exit_to_user_mode+0x5/0x25 + [2437548.306153] asm_sysvec_apic_timer_interrupt+0x16/0x1b + + This is due to a race condition between change_prot_numa() and + THP migration because the kernel doesn't check is_swap_pmd() and + pmd_trans_huge() atomically: + + change_prot_numa() THP migration + ====================================================================== + - change_pmd_range() + -> is_swap_pmd() returns false, + meaning it's not a PMD migration + entry. + - do_huge_pmd_numa_page() + -> migrate_misplaced_page() sets + migration entries for the THP. + - change_pmd_range() + -> pmd_none_or_clear_bad_unless_trans_huge() + -> pmd_none() and pmd_trans_huge() returns false + - pmd_none_or_clear_bad_unless_trans_huge() + -> pmd_bad() returns true for the migration entry! + + The upstream commit 670ddd8cdcbd ("mm/mprotect: delete + pmd_none_or_clear_bad_unless_trans_huge()") closes this race condition + by checking is_swap_pmd() and pmd_trans_huge() atomically. + + Backporting note: + Unlike mainline, pte_offset_map_lock() does not check if the pmd + entry is a migration entry or a hugepage; acquires PTL unconditionally + instead of returning failure. Therefore, it is necessary to keep the + !is_swap_pmd() && !pmd_trans_huge() && !pmd_devmap() check before + acquiring the PTL. + + After acquiring it, open-code the mainline semantics of + pte_offset_map_lock() so that change_pte_range() fails if the pmd value + has changed (under the PTL). This requires adding one more parameter + (for passing pmd value that is read before calling the function) to + change_pte_range(). ] +Signed-off-by: Greg Kroah-Hartman +--- + mm/mprotect.c | 100 ++++++++++++++++++++++++---------------------------------- + 1 file changed, 42 insertions(+), 58 deletions(-) + +--- a/mm/mprotect.c ++++ b/mm/mprotect.c +@@ -36,29 +36,24 @@ + #include "internal.h" + + static long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd, +- unsigned long addr, unsigned long end, pgprot_t newprot, +- int dirty_accountable, int prot_numa) ++ pmd_t pmd_old, unsigned long addr, unsigned long end, ++ pgprot_t newprot, int dirty_accountable, int prot_numa) + { + pte_t *pte, oldpte; ++ pmd_t pmd_val; + spinlock_t *ptl; + long pages = 0; + int target_node = NUMA_NO_NODE; + +- /* +- * Can be called with only the mmap_sem for reading by +- * prot_numa so we must check the pmd isn't constantly +- * changing from under us from pmd_none to pmd_trans_huge +- * and/or the other way around. +- */ +- if (pmd_trans_unstable(pmd)) +- return 0; +- +- /* +- * The pmd points to a regular pte so the pmd can't change +- * from under us even if the mmap_sem is only hold for +- * reading. +- */ + pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); ++ /* Make sure pmd didn't change after acquiring ptl */ ++ pmd_val = pmd_read_atomic(pmd); ++ /* See pmd_none_or_trans_huge_or_clear_bad for info on barrier */ ++ barrier(); ++ if (!pmd_same(pmd_old, pmd_val)) { ++ pte_unmap_unlock(pte, ptl); ++ return -EAGAIN; ++ } + + /* Get target node for single threaded private VMAs */ + if (prot_numa && !(vma->vm_flags & VM_SHARED) && +@@ -161,31 +156,6 @@ static long change_pte_range(struct vm_a + return pages; + } + +-/* +- * Used when setting automatic NUMA hinting protection where it is +- * critical that a numa hinting PMD is not confused with a bad PMD. +- */ +-static inline int pmd_none_or_clear_bad_unless_trans_huge(pmd_t *pmd) +-{ +- pmd_t pmdval = pmd_read_atomic(pmd); +- +- /* See pmd_none_or_trans_huge_or_clear_bad for info on barrier */ +-#ifdef CONFIG_TRANSPARENT_HUGEPAGE +- barrier(); +-#endif +- +- if (pmd_none(pmdval)) +- return 1; +- if (pmd_trans_huge(pmdval)) +- return 0; +- if (unlikely(pmd_bad(pmdval))) { +- pmd_clear_bad(pmd); +- return 1; +- } +- +- return 0; +-} +- + static inline long change_pmd_range(struct vm_area_struct *vma, + pud_t *pud, unsigned long addr, unsigned long end, + pgprot_t newprot, int dirty_accountable, int prot_numa) +@@ -200,21 +170,33 @@ static inline long change_pmd_range(stru + + pmd = pmd_offset(pud, addr); + do { +- long this_pages; +- ++ long ret; ++ pmd_t _pmd; ++again: + next = pmd_addr_end(addr, end); ++ _pmd = pmd_read_atomic(pmd); ++ /* See pmd_none_or_trans_huge_or_clear_bad for info on barrier */ ++#ifdef CONFIG_TRANSPARENT_HUGEPAGE ++ barrier(); ++#endif + + /* + * Automatic NUMA balancing walks the tables with mmap_sem + * held for read. It's possible a parallel update to occur +- * between pmd_trans_huge() and a pmd_none_or_clear_bad() +- * check leading to a false positive and clearing. +- * Hence, it's necessary to atomically read the PMD value +- * for all the checks. ++ * between pmd_trans_huge(), is_swap_pmd(), and ++ * a pmd_none_or_clear_bad() check leading to a false positive ++ * and clearing. Hence, it's necessary to atomically read ++ * the PMD value for all the checks. + */ +- if (!is_swap_pmd(*pmd) && !pmd_devmap(*pmd) && +- pmd_none_or_clear_bad_unless_trans_huge(pmd)) +- goto next; ++ if (!is_swap_pmd(_pmd) && !pmd_devmap(_pmd) && !pmd_trans_huge(_pmd)) { ++ if (pmd_none(_pmd)) ++ goto next; ++ ++ if (pmd_bad(_pmd)) { ++ pmd_clear_bad(pmd); ++ goto next; ++ } ++ } + + /* invoke the mmu notifier if the pmd is populated */ + if (!range.start) { +@@ -224,15 +206,15 @@ static inline long change_pmd_range(stru + mmu_notifier_invalidate_range_start(&range); + } + +- if (is_swap_pmd(*pmd) || pmd_trans_huge(*pmd) || pmd_devmap(*pmd)) { ++ if (is_swap_pmd(_pmd) || pmd_trans_huge(_pmd) || pmd_devmap(_pmd)) { + if (next - addr != HPAGE_PMD_SIZE) { + __split_huge_pmd(vma, pmd, addr, false, NULL); + } else { +- int nr_ptes = change_huge_pmd(vma, pmd, addr, +- newprot, prot_numa); ++ ret = change_huge_pmd(vma, pmd, addr, newprot, ++ prot_numa); + +- if (nr_ptes) { +- if (nr_ptes == HPAGE_PMD_NR) { ++ if (ret) { ++ if (ret == HPAGE_PMD_NR) { + pages += HPAGE_PMD_NR; + nr_huge_updates++; + } +@@ -243,9 +225,11 @@ static inline long change_pmd_range(stru + } + /* fall through, the trans huge pmd just split */ + } +- this_pages = change_pte_range(vma, pmd, addr, next, newprot, +- dirty_accountable, prot_numa); +- pages += this_pages; ++ ret = change_pte_range(vma, pmd, _pmd, addr, next, ++ newprot, dirty_accountable, prot_numa); ++ if (ret < 0) ++ goto again; ++ pages += ret; + next: + cond_resched(); + } while (pmd++, addr = next, addr != end); diff --git a/queue-5.4/mm-mprotect-use-long-for-page-accountings-and-retval.patch b/queue-5.4/mm-mprotect-use-long-for-page-accountings-and-retval.patch new file mode 100644 index 0000000000..d79ccd1578 --- /dev/null +++ b/queue-5.4/mm-mprotect-use-long-for-page-accountings-and-retval.patch @@ -0,0 +1,222 @@ +From stable+bounces-196860-greg=kroah.com@vger.kernel.org Tue Nov 25 06:10:31 2025 +From: Harry Yoo +Date: Tue, 25 Nov 2025 14:09:25 +0900 +Subject: mm/mprotect: use long for page accountings and retval +To: stable@vger.kernel.org +Cc: Liam.Howlett@oracle.com, akpm@linux-foundation.org, baohua@kernel.org, baolin.wang@linux.alibaba.com, david@kernel.org, dev.jain@arm.com, hughd@google.com, jane.chu@oracle.com, jannh@google.com, kas@kernel.org, lance.yang@linux.dev, linux-mm@kvack.org, lorenzo.stoakes@oracle.com, npache@redhat.com, pfalcato@suse.de, ryan.roberts@arm.com, vbabka@suse.cz, ziy@nvidia.com, Peter Xu , Mike Kravetz , James Houghton , Andrea Arcangeli , Axel Rasmussen , David Hildenbrand , Muchun Song , Nadav Amit , Harry Yoo +Message-ID: <20251125050926.1100484-2-harry.yoo@oracle.com> + +From: Peter Xu + +commit a79390f5d6a78647fd70856bd42b22d994de0ba2 upstream. + +Switch to use type "long" for page accountings and retval across the whole +procedure of change_protection(). + +The change should have shrinked the possible maximum page number to be +half comparing to previous (ULONG_MAX / 2), but it shouldn't overflow on +any system either because the maximum possible pages touched by change +protection should be ULONG_MAX / PAGE_SIZE. + +Two reasons to switch from "unsigned long" to "long": + + 1. It suites better on count_vm_numa_events(), whose 2nd parameter takes + a long type. + + 2. It paves way for returning negative (error) values in the future. + +Currently the only caller that consumes this retval is change_prot_numa(), +where the unsigned long was converted to an int. Since at it, touching up +the numa code to also take a long, so it'll avoid any possible overflow +too during the int-size convertion. + +Link: https://lkml.kernel.org/r/20230104225207.1066932-3-peterx@redhat.com +Signed-off-by: Peter Xu +Acked-by: Mike Kravetz +Acked-by: James Houghton +Cc: Andrea Arcangeli +Cc: Axel Rasmussen +Cc: David Hildenbrand +Cc: Muchun Song +Cc: Nadav Amit +Signed-off-by: Andrew Morton +[ Adjust context ] +Signed-off-by: Harry Yoo +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/hugetlb.h | 4 ++-- + include/linux/mm.h | 2 +- + mm/hugetlb.c | 4 ++-- + mm/mempolicy.c | 2 +- + mm/mprotect.c | 26 +++++++++++++------------- + 5 files changed, 19 insertions(+), 19 deletions(-) + +--- a/include/linux/hugetlb.h ++++ b/include/linux/hugetlb.h +@@ -137,7 +137,7 @@ struct page *follow_huge_pgd(struct mm_s + + int pmd_huge(pmd_t pmd); + int pud_huge(pud_t pud); +-unsigned long hugetlb_change_protection(struct vm_area_struct *vma, ++long hugetlb_change_protection(struct vm_area_struct *vma, + unsigned long address, unsigned long end, pgprot_t newprot); + + bool is_hugetlb_entry_migration(pte_t pte); +@@ -195,7 +195,7 @@ static inline bool isolate_huge_page(str + #define putback_active_hugepage(p) do {} while (0) + #define move_hugetlb_state(old, new, reason) do {} while (0) + +-static inline unsigned long hugetlb_change_protection(struct vm_area_struct *vma, ++static inline long hugetlb_change_protection(struct vm_area_struct *vma, + unsigned long address, unsigned long end, pgprot_t newprot) + { + return 0; +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -1657,7 +1657,7 @@ extern unsigned long move_page_tables(st + unsigned long old_addr, struct vm_area_struct *new_vma, + unsigned long new_addr, unsigned long len, + bool need_rmap_locks); +-extern unsigned long change_protection(struct vm_area_struct *vma, unsigned long start, ++extern long change_protection(struct vm_area_struct *vma, unsigned long start, + unsigned long end, pgprot_t newprot, + int dirty_accountable, int prot_numa); + extern int mprotect_fixup(struct vm_area_struct *vma, +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -4635,7 +4635,7 @@ same_page: + #define flush_hugetlb_tlb_range(vma, addr, end) flush_tlb_range(vma, addr, end) + #endif + +-unsigned long hugetlb_change_protection(struct vm_area_struct *vma, ++long hugetlb_change_protection(struct vm_area_struct *vma, + unsigned long address, unsigned long end, pgprot_t newprot) + { + struct mm_struct *mm = vma->vm_mm; +@@ -4643,7 +4643,7 @@ unsigned long hugetlb_change_protection( + pte_t *ptep; + pte_t pte; + struct hstate *h = hstate_vma(vma); +- unsigned long pages = 0; ++ long pages = 0; + bool shared_pmd = false; + struct mmu_notifier_range range; + +--- a/mm/mempolicy.c ++++ b/mm/mempolicy.c +@@ -595,7 +595,7 @@ unlock: + unsigned long change_prot_numa(struct vm_area_struct *vma, + unsigned long addr, unsigned long end) + { +- int nr_updated; ++ long nr_updated; + + nr_updated = change_protection(vma, addr, end, PAGE_NONE, 0, 1); + if (nr_updated) +--- a/mm/mprotect.c ++++ b/mm/mprotect.c +@@ -35,13 +35,13 @@ + + #include "internal.h" + +-static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd, ++static long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd, + unsigned long addr, unsigned long end, pgprot_t newprot, + int dirty_accountable, int prot_numa) + { + pte_t *pte, oldpte; + spinlock_t *ptl; +- unsigned long pages = 0; ++ long pages = 0; + int target_node = NUMA_NO_NODE; + + /* +@@ -186,13 +186,13 @@ static inline int pmd_none_or_clear_bad_ + return 0; + } + +-static inline unsigned long change_pmd_range(struct vm_area_struct *vma, ++static inline long change_pmd_range(struct vm_area_struct *vma, + pud_t *pud, unsigned long addr, unsigned long end, + pgprot_t newprot, int dirty_accountable, int prot_numa) + { + pmd_t *pmd; + unsigned long next; +- unsigned long pages = 0; ++ long pages = 0; + unsigned long nr_huge_updates = 0; + struct mmu_notifier_range range; + +@@ -200,7 +200,7 @@ static inline unsigned long change_pmd_r + + pmd = pmd_offset(pud, addr); + do { +- unsigned long this_pages; ++ long this_pages; + + next = pmd_addr_end(addr, end); + +@@ -258,13 +258,13 @@ next: + return pages; + } + +-static inline unsigned long change_pud_range(struct vm_area_struct *vma, ++static inline long change_pud_range(struct vm_area_struct *vma, + p4d_t *p4d, unsigned long addr, unsigned long end, + pgprot_t newprot, int dirty_accountable, int prot_numa) + { + pud_t *pud; + unsigned long next; +- unsigned long pages = 0; ++ long pages = 0; + + pud = pud_offset(p4d, addr); + do { +@@ -278,13 +278,13 @@ static inline unsigned long change_pud_r + return pages; + } + +-static inline unsigned long change_p4d_range(struct vm_area_struct *vma, ++static inline long change_p4d_range(struct vm_area_struct *vma, + pgd_t *pgd, unsigned long addr, unsigned long end, + pgprot_t newprot, int dirty_accountable, int prot_numa) + { + p4d_t *p4d; + unsigned long next; +- unsigned long pages = 0; ++ long pages = 0; + + p4d = p4d_offset(pgd, addr); + do { +@@ -298,7 +298,7 @@ static inline unsigned long change_p4d_r + return pages; + } + +-static unsigned long change_protection_range(struct vm_area_struct *vma, ++static long change_protection_range(struct vm_area_struct *vma, + unsigned long addr, unsigned long end, pgprot_t newprot, + int dirty_accountable, int prot_numa) + { +@@ -306,7 +306,7 @@ static unsigned long change_protection_r + pgd_t *pgd; + unsigned long next; + unsigned long start = addr; +- unsigned long pages = 0; ++ long pages = 0; + + BUG_ON(addr >= end); + pgd = pgd_offset(mm, addr); +@@ -328,11 +328,11 @@ static unsigned long change_protection_r + return pages; + } + +-unsigned long change_protection(struct vm_area_struct *vma, unsigned long start, ++long change_protection(struct vm_area_struct *vma, unsigned long start, + unsigned long end, pgprot_t newprot, + int dirty_accountable, int prot_numa) + { +- unsigned long pages; ++ long pages; + + if (is_vm_hugetlb_page(vma)) + pages = hugetlb_change_protection(vma, start, end, newprot); diff --git a/queue-5.4/net-netpoll-fix-incorrect-refcount-handling-causing-incorrect-cleanup.patch b/queue-5.4/net-netpoll-fix-incorrect-refcount-handling-causing-incorrect-cleanup.patch new file mode 100644 index 0000000000..f2157cb8c8 --- /dev/null +++ b/queue-5.4/net-netpoll-fix-incorrect-refcount-handling-causing-incorrect-cleanup.patch @@ -0,0 +1,85 @@ +From stable+bounces-195446-greg=kroah.com@vger.kernel.org Fri Nov 21 03:09:38 2025 +From: Sasha Levin +Date: Thu, 20 Nov 2025 21:05:19 -0500 +Subject: net: netpoll: fix incorrect refcount handling causing incorrect cleanup +To: stable@vger.kernel.org +Cc: Breno Leitao , Jay Vosburgh , Simon Horman , Jakub Kicinski , Sasha Levin +Message-ID: <20251121020519.2340754-1-sashal@kernel.org> + +From: Breno Leitao + +[ Upstream commit 49c8d2c1f94cc2f4d1a108530d7ba52614b874c2 ] + +commit efa95b01da18 ("netpoll: fix use after free") incorrectly +ignored the refcount and prematurely set dev->npinfo to NULL during +netpoll cleanup, leading to improper behavior and memory leaks. + +Scenario causing lack of proper cleanup: + +1) A netpoll is associated with a NIC (e.g., eth0) and netdev->npinfo is + allocated, and refcnt = 1 + - Keep in mind that npinfo is shared among all netpoll instances. In + this case, there is just one. + +2) Another netpoll is also associated with the same NIC and + npinfo->refcnt += 1. + - Now dev->npinfo->refcnt = 2; + - There is just one npinfo associated to the netdev. + +3) When the first netpolls goes to clean up: + - The first cleanup succeeds and clears np->dev->npinfo, ignoring + refcnt. + - It basically calls `RCU_INIT_POINTER(np->dev->npinfo, NULL);` + - Set dev->npinfo = NULL, without proper cleanup + - No ->ndo_netpoll_cleanup() is either called + +4) Now the second target tries to clean up + - The second cleanup fails because np->dev->npinfo is already NULL. + * In this case, ops->ndo_netpoll_cleanup() was never called, and + the skb pool is not cleaned as well (for the second netpoll + instance) + - This leaks npinfo and skbpool skbs, which is clearly reported by + kmemleak. + +Revert commit efa95b01da18 ("netpoll: fix use after free") and adds +clarifying comments emphasizing that npinfo cleanup should only happen +once the refcount reaches zero, ensuring stable and correct netpoll +behavior. + +Cc: # 3.17.x +Cc: Jay Vosburgh +Fixes: efa95b01da18 ("netpoll: fix use after free") +Signed-off-by: Breno Leitao +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20251107-netconsole_torture-v10-1-749227b55f63@debian.org +Signed-off-by: Jakub Kicinski +[ Adjust context ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/core/netpoll.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/net/core/netpoll.c ++++ b/net/core/netpoll.c +@@ -858,6 +858,10 @@ void __netpoll_cleanup(struct netpoll *n + + synchronize_srcu(&netpoll_srcu); + ++ /* At this point, there is a single npinfo instance per netdevice, and ++ * its refcnt tracks how many netpoll structures are linked to it. We ++ * only perform npinfo cleanup when the refcnt decrements to zero. ++ */ + if (refcount_dec_and_test(&npinfo->refcnt)) { + const struct net_device_ops *ops; + +@@ -867,8 +871,7 @@ void __netpoll_cleanup(struct netpoll *n + + RCU_INIT_POINTER(np->dev->npinfo, NULL); + call_rcu(&npinfo->rcu, rcu_cleanup_netpoll_info); +- } else +- RCU_INIT_POINTER(np->dev->npinfo, NULL); ++ } + } + EXPORT_SYMBOL_GPL(__netpoll_cleanup); + diff --git a/queue-5.4/net-qede-initialize-qede_ll_ops-with-designated-initializer.patch b/queue-5.4/net-qede-initialize-qede_ll_ops-with-designated-initializer.patch new file mode 100644 index 0000000000..cf6390e21f --- /dev/null +++ b/queue-5.4/net-qede-initialize-qede_ll_ops-with-designated-initializer.patch @@ -0,0 +1,43 @@ +From 6b3ab7f2cbfaeb6580709cd8ef4d72cfd01bfde4 Mon Sep 17 00:00:00 2001 +From: Nathan Chancellor +Date: Wed, 7 May 2025 21:47:45 +0100 +Subject: net: qede: Initialize qede_ll_ops with designated initializer + +From: Nathan Chancellor + +commit 6b3ab7f2cbfaeb6580709cd8ef4d72cfd01bfde4 upstream. + +After a recent change [1] in clang's randstruct implementation to +randomize structures that only contain function pointers, there is an +error because qede_ll_ops get randomized but does not use a designated +initializer for the first member: + + drivers/net/ethernet/qlogic/qede/qede_main.c:206:2: error: a randomized struct can only be initialized with a designated initializer + 206 | { + | ^ + +Explicitly initialize the common member using a designated initializer +to fix the build. + +Cc: stable@vger.kernel.org +Fixes: 035f7f87b729 ("randstruct: Enable Clang support") +Link: https://github.com/llvm/llvm-project/commit/04364fb888eea6db9811510607bed4b200bcb082 [1] +Signed-off-by: Nathan Chancellor +Link: https://patch.msgid.link/20250507-qede-fix-clang-randstruct-v1-1-5ccc15626fba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/qlogic/qede/qede_main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/ethernet/qlogic/qede/qede_main.c ++++ b/drivers/net/ethernet/qlogic/qede/qede_main.c +@@ -216,7 +216,7 @@ static struct pci_driver qede_pci_driver + }; + + static struct qed_eth_cb_ops qede_ll_ops = { +- { ++ .common = { + #ifdef CONFIG_RFS_ACCEL + .arfs_filter_op = qede_arfs_filter_op, + #endif diff --git a/queue-5.4/pmdomain-arm-scmi-fix-genpd-leak-on-provider-registration-failure.patch b/queue-5.4/pmdomain-arm-scmi-fix-genpd-leak-on-provider-registration-failure.patch new file mode 100644 index 0000000000..83d074384e --- /dev/null +++ b/queue-5.4/pmdomain-arm-scmi-fix-genpd-leak-on-provider-registration-failure.patch @@ -0,0 +1,82 @@ +From stable+bounces-196542-greg=kroah.com@vger.kernel.org Fri Nov 21 18:16:12 2025 +From: Sasha Levin +Date: Fri, 21 Nov 2025 12:16:05 -0500 +Subject: pmdomain: arm: scmi: Fix genpd leak on provider registration failure +To: stable@vger.kernel.org +Cc: Sudeep Holla , Peng Fan , Ulf Hansson , Sasha Levin +Message-ID: <20251121171605.2611489-1-sashal@kernel.org> + +From: Sudeep Holla + +[ Upstream commit 7458f72cc28f9eb0de811effcb5376d0ec19094a ] + +If of_genpd_add_provider_onecell() fails during probe, the previously +created generic power domains are not removed, leading to a memory leak +and potential kernel crash later in genpd_debug_add(). + +Add proper error handling to unwind the initialized domains before +returning from probe to ensure all resources are correctly released on +failure. + +Example crash trace observed without this fix: + + | Unable to handle kernel paging request at virtual address fffffffffffffc70 + | CPU: 1 UID: 0 PID: 1 Comm: swapper/0 Not tainted 6.18.0-rc1 #405 PREEMPT + | Hardware name: ARM LTD ARM Juno Development Platform/ARM Juno Development Platform + | pstate: 00000005 (nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) + | pc : genpd_debug_add+0x2c/0x160 + | lr : genpd_debug_init+0x74/0x98 + | Call trace: + | genpd_debug_add+0x2c/0x160 (P) + | genpd_debug_init+0x74/0x98 + | do_one_initcall+0xd0/0x2d8 + | do_initcall_level+0xa0/0x140 + | do_initcalls+0x60/0xa8 + | do_basic_setup+0x28/0x40 + | kernel_init_freeable+0xe8/0x170 + | kernel_init+0x2c/0x140 + | ret_from_fork+0x10/0x20 + +Fixes: 898216c97ed2 ("firmware: arm_scmi: add device power domain support using genpd") +Signed-off-by: Sudeep Holla +Reviewed-by: Peng Fan +Cc: stable@vger.kernel.org +Signed-off-by: Ulf Hansson +[ drivers/pmdomain/arm/scmi_pm_domain.c -> drivers/firmware/arm_scmi/scmi_pm_domain.c ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/firmware/arm_scmi/scmi_pm_domain.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +--- a/drivers/firmware/arm_scmi/scmi_pm_domain.c ++++ b/drivers/firmware/arm_scmi/scmi_pm_domain.c +@@ -53,7 +53,7 @@ static int scmi_pd_power_off(struct gene + + static int scmi_pm_domain_probe(struct scmi_device *sdev) + { +- int num_domains, i; ++ int num_domains, i, ret; + struct device *dev = &sdev->dev; + struct device_node *np = dev->of_node; + struct scmi_pm_domain *scmi_pd; +@@ -106,9 +106,18 @@ static int scmi_pm_domain_probe(struct s + scmi_pd_data->domains = domains; + scmi_pd_data->num_domains = num_domains; + ++ ret = of_genpd_add_provider_onecell(np, scmi_pd_data); ++ if (ret) ++ goto err_rm_genpds; ++ + dev_set_drvdata(dev, scmi_pd_data); + +- return of_genpd_add_provider_onecell(np, scmi_pd_data); ++ return 0; ++err_rm_genpds: ++ for (i = num_domains - 1; i >= 0; i--) ++ pm_genpd_remove(domains[i]); ++ ++ return ret; + } + + static void scmi_pm_domain_remove(struct scmi_device *sdev) diff --git a/queue-5.4/pmdomain-imx-fix-reference-count-leak-in-imx_gpc_remove.patch b/queue-5.4/pmdomain-imx-fix-reference-count-leak-in-imx_gpc_remove.patch new file mode 100644 index 0000000000..7308aaced9 --- /dev/null +++ b/queue-5.4/pmdomain-imx-fix-reference-count-leak-in-imx_gpc_remove.patch @@ -0,0 +1,38 @@ +From stable+bounces-196541-greg=kroah.com@vger.kernel.org Fri Nov 21 18:19:52 2025 +From: Sasha Levin +Date: Fri, 21 Nov 2025 12:15:53 -0500 +Subject: pmdomain: imx: Fix reference count leak in imx_gpc_remove +To: stable@vger.kernel.org +Cc: Miaoqian Lin , Ulf Hansson , Sasha Levin +Message-ID: <20251121171553.2611263-1-sashal@kernel.org> + +From: Miaoqian Lin + +[ Upstream commit bbde14682eba21d86f5f3d6fe2d371b1f97f1e61 ] + +of_get_child_by_name() returns a node pointer with refcount incremented, we +should use of_node_put() on it when not needed anymore. Add the missing +of_node_put() to avoid refcount leak. + +Fixes: 721cabf6c660 ("soc: imx: move PGC handling to a new GPC driver") +Cc: stable@vger.kernel.org +Signed-off-by: Miaoqian Lin +Signed-off-by: Ulf Hansson +[ drivers/pmdomain/imx/gpc.c -> drivers/soc/imx/gpc.c ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/soc/imx/gpc.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/soc/imx/gpc.c ++++ b/drivers/soc/imx/gpc.c +@@ -540,6 +540,8 @@ static int imx_gpc_remove(struct platfor + return ret; + } + ++ of_node_put(pgc_node); ++ + return 0; + } + diff --git a/queue-5.4/series b/queue-5.4/series index f0f23b4d40..e5a6de846c 100644 --- a/queue-5.4/series +++ b/queue-5.4/series @@ -172,3 +172,17 @@ kconfig-nconf-initialize-the-default-locale-at-start.patch mm-page_alloc-fix-hash-table-order-logging-in-alloc_.patch alsa-usb-audio-fix-uac2-clock-source-at-terminal-par.patch net-ethernet-ti-netcp-standardize-knav_dma_open_chan.patch +uio_hv_generic-set-event-for-all-channels-on-the-device.patch +net-qede-initialize-qede_ll_ops-with-designated-initializer.patch +net-netpoll-fix-incorrect-refcount-handling-causing-incorrect-cleanup.patch +pmdomain-arm-scmi-fix-genpd-leak-on-provider-registration-failure.patch +pmdomain-imx-fix-reference-count-leak-in-imx_gpc_remove.patch +fs-proc-fix-uaf-in-proc_readdir_de.patch +ata-libata-scsi-fix-system-suspend-for-a-security-locked-drive.patch +usb-deprecate-the-third-argument-of-usb_maxpacket.patch +input-remove-third-argument-of-usb_maxpacket.patch +input-pegasus-notetaker-fix-potential-out-of-bounds-access.patch +mm-mempool-replace-kmap_atomic-with-kmap_local_page.patch +mm-mempool-fix-poisoning-order-0-pages-with-highmem.patch +mm-mprotect-use-long-for-page-accountings-and-retval.patch +mm-mprotect-delete-pmd_none_or_clear_bad_unless_trans_huge.patch diff --git a/queue-5.4/uio_hv_generic-set-event-for-all-channels-on-the-device.patch b/queue-5.4/uio_hv_generic-set-event-for-all-channels-on-the-device.patch new file mode 100644 index 0000000000..7152ae9abe --- /dev/null +++ b/queue-5.4/uio_hv_generic-set-event-for-all-channels-on-the-device.patch @@ -0,0 +1,74 @@ +From d062463edf1770427dc2d637df4088df4835aa47 Mon Sep 17 00:00:00 2001 +From: Long Li +Date: Mon, 10 Mar 2025 15:12:01 -0700 +Subject: uio_hv_generic: Set event for all channels on the device + +From: Long Li + +commit d062463edf1770427dc2d637df4088df4835aa47 upstream. + +Hyper-V may offer a non latency sensitive device with subchannels without +monitor bit enabled. The decision is entirely on the Hyper-V host not +configurable within guest. + +When a device has subchannels, also signal events for the subchannel +if its monitor bit is disabled. + +This patch also removes the memory barrier when monitor bit is enabled +as it is not necessary. The memory barrier is only needed between +setting up interrupt mask and calling vmbus_set_event() when monitor +bit is disabled. + +Signed-off-by: Long Li +Reviewed-by: Michael Kelley +Reviewed-by: Saurabh Sengar +Link: https://lore.kernel.org/r/1741644721-20389-1-git-send-email-longli@linuxonhyperv.com +Fixes: b15b7d2a1b09 ("uio_hv_generic: Let userspace take care of interrupt mask") +Closes: https://bugs.debian.org/1120602 +Signed-off-by: Naman Jain +Signed-off-by: Greg Kroah-Hartman +--- + drivers/uio/uio_hv_generic.c | 21 +++++++++++++++++---- + 1 file changed, 17 insertions(+), 4 deletions(-) + +--- a/drivers/uio/uio_hv_generic.c ++++ b/drivers/uio/uio_hv_generic.c +@@ -80,9 +80,15 @@ hv_uio_irqcontrol(struct uio_info *info, + { + struct hv_uio_private_data *pdata = info->priv; + struct hv_device *dev = pdata->device; ++ struct vmbus_channel *primary, *sc; + +- dev->channel->inbound.ring_buffer->interrupt_mask = !irq_state; +- virt_mb(); ++ primary = dev->channel; ++ primary->inbound.ring_buffer->interrupt_mask = !irq_state; ++ ++ mutex_lock(&vmbus_connection.channel_mutex); ++ list_for_each_entry(sc, &primary->sc_list, sc_list) ++ sc->inbound.ring_buffer->interrupt_mask = !irq_state; ++ mutex_unlock(&vmbus_connection.channel_mutex); + + return 0; + } +@@ -93,11 +99,18 @@ hv_uio_irqcontrol(struct uio_info *info, + static void hv_uio_channel_cb(void *context) + { + struct vmbus_channel *chan = context; +- struct hv_device *hv_dev = chan->device_obj; +- struct hv_uio_private_data *pdata = hv_get_drvdata(hv_dev); ++ struct hv_device *hv_dev; ++ struct hv_uio_private_data *pdata; + + virt_mb(); + ++ /* ++ * The callback may come from a subchannel, in which case look ++ * for the hv device in the primary channel ++ */ ++ hv_dev = chan->primary_channel ? ++ chan->primary_channel->device_obj : chan->device_obj; ++ pdata = hv_get_drvdata(hv_dev); + uio_event_notify(&pdata->info); + } + diff --git a/queue-5.4/usb-deprecate-the-third-argument-of-usb_maxpacket.patch b/queue-5.4/usb-deprecate-the-third-argument-of-usb_maxpacket.patch new file mode 100644 index 0000000000..70ad86a0d4 --- /dev/null +++ b/queue-5.4/usb-deprecate-the-third-argument-of-usb_maxpacket.patch @@ -0,0 +1,85 @@ +From sashal@kernel.org Mon Nov 24 20:20:59 2025 +From: Sasha Levin +Date: Mon, 24 Nov 2025 14:20:44 -0500 +Subject: usb: deprecate the third argument of usb_maxpacket() +To: stable@vger.kernel.org +Cc: Vincent Mailhol , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20251124192046.3812-1-sashal@kernel.org> + +From: Vincent Mailhol + +[ Upstream commit 0f08c2e7458e25c967d844170f8ad1aac3b57a02 ] + +This is a transitional patch with the ultimate goal of changing the +prototype of usb_maxpacket() from: +| static inline __u16 +| usb_maxpacket(struct usb_device *udev, int pipe, int is_out) + +into: +| static inline u16 usb_maxpacket(struct usb_device *udev, int pipe) + +The third argument of usb_maxpacket(): is_out gets removed because it +can be derived from its second argument: pipe using +usb_pipeout(pipe). Furthermore, in the current version, +ubs_pipeout(pipe) is called regardless in order to sanitize the is_out +parameter. + +In order to make a smooth change, we first deprecate the is_out +parameter by simply ignoring it (using a variadic function) and will +remove it later, once all the callers get updated. + +The body of the function is reworked accordingly and is_out is +replaced by usb_pipeout(pipe). The WARN_ON() calls become unnecessary +and get removed. + +Finally, the return type is changed from __u16 to u16 because this is +not a UAPI function. + +Signed-off-by: Vincent Mailhol +Link: https://lore.kernel.org/r/20220317035514.6378-2-mailhol.vincent@wanadoo.fr +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 69aeb5073123 ("Input: pegasus-notetaker - fix potential out-of-bounds access") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/usb.h | 16 +++++----------- + 1 file changed, 5 insertions(+), 11 deletions(-) + +--- a/include/linux/usb.h ++++ b/include/linux/usb.h +@@ -1964,21 +1964,17 @@ usb_pipe_endpoint(struct usb_device *dev + return eps[usb_pipeendpoint(pipe)]; + } + +-/*-------------------------------------------------------------------------*/ +- +-static inline __u16 +-usb_maxpacket(struct usb_device *udev, int pipe, int is_out) ++static inline u16 usb_maxpacket(struct usb_device *udev, int pipe, ++ /* int is_out deprecated */ ...) + { + struct usb_host_endpoint *ep; + unsigned epnum = usb_pipeendpoint(pipe); + +- if (is_out) { +- WARN_ON(usb_pipein(pipe)); ++ if (usb_pipeout(pipe)) + ep = udev->ep_out[epnum]; +- } else { +- WARN_ON(usb_pipeout(pipe)); ++ else + ep = udev->ep_in[epnum]; +- } ++ + if (!ep) + return 0; + +@@ -1986,8 +1982,6 @@ usb_maxpacket(struct usb_device *udev, i + return usb_endpoint_maxp(&ep->desc); + } + +-/* ----------------------------------------------------------------------- */ +- + /* translate USB error codes to codes user space understands */ + static inline int usb_translate_errors(int error_code) + { -- 2.47.3