From: Sasha Levin Date: Thu, 9 Jul 2026 01:03:59 +0000 (-0400) Subject: Fixes for all trees X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ecb3e8b8c1879f23b111ec947e7ca6f291019670;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for all trees Signed-off-by: Sasha Levin --- diff --git a/queue-5.10/kvm-replace-guest-triggerable-bug_on-in-ioeventfd-da.patch b/queue-5.10/kvm-replace-guest-triggerable-bug_on-in-ioeventfd-da.patch new file mode 100644 index 0000000000..78b2719576 --- /dev/null +++ b/queue-5.10/kvm-replace-guest-triggerable-bug_on-in-ioeventfd-da.patch @@ -0,0 +1,124 @@ +From 823df3ca5709f7df3e52ea5d035cd33d9d6e851a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Jul 2026 16:30:49 +0000 +Subject: KVM: Replace guest-triggerable BUG_ON() in ioeventfd datamatch with + get_unaligned() + +From: Sean Christopherson + +commit f1edbed787ba67988ed34e0132ca128b052b6ce8 upstream. + +Drop a BUG_ON() that has been reachable since it was first added, way back +in 2009, and instead use get_unaligned() to perform potentially-unaligned +accesses. + +For a given store, KVM x86's emulator tracks the entire value in the +destination operand, x86_emulate_ctxt.dst. If the destination is memory, +and the target splits multiple pages and/or is emulated MMIO, then KVM +handles each fragment independently. E.g. on a page split starting at page +offset 0xffc, KVM writes 4 bytes to the first page, then the remaining +bytes to the second page, using ctxt->dst as the source for both (with +appropriate offsets). + +If the destination splits a page *and* hits emulated MMIO on the second +page, then KVM will complete the write to the first page, then emulate the +MMIO access to the second page. If there is a datamatch-enabled ioeventfd +at offset 0 of the second page, then KVM will process the remainder of the +store as a potential ioeventfd signal. + +Putting it all together, if the guest emits a store that splits a page +starting at page offset N, and the second page has a datamatch-enabled +ioeventfd at offset 0, then KVM will check for datamatch using +&dst.valptr[N] as the source. Due to dst (and thus dst.valptr) being +32-byte aligned, if N is not aligned to @len, the BUG_ON() fires. + +E.g. with a 16-byte store at page offset 0xffc, to an ioeventfd of len 8, +all initial checks in ioeventfd_in_range() will succeed, and the BUG_ON() +fires due to @val being 4-byte aligned, but not 8-byte aligned. + + ------------[ cut here ]------------ + kernel BUG at arch/x86/kvm/../../../virt/kvm/eventfd.c:783! + Oops: invalid opcode: 0000 [#1] SMP + CPU: 0 UID: 1000 PID: 615 Comm: repro Not tainted 7.1.0-rc2-ff238429d1ea #365 PREEMPT + Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015 + RIP: 0010:ioeventfd_write+0x6c/0x70 [kvm] + Call Trace: + + __kvm_io_bus_write+0x85/0xb0 [kvm] + kvm_io_bus_write+0x53/0x80 [kvm] + vcpu_mmio_write+0x66/0xf0 [kvm] + emulator_read_write_onepage+0x12a/0x540 [kvm] + emulator_read_write+0x109/0x2b0 [kvm] + x86_emulate_insn+0x4f8/0xfb0 [kvm] + x86_emulate_instruction+0x181/0x790 [kvm] + kvm_mmu_page_fault+0x313/0x630 [kvm] + vmx_handle_exit+0x18a/0x590 [kvm_intel] + kvm_arch_vcpu_ioctl_run+0xc81/0x1c90 [kvm] + kvm_vcpu_ioctl+0x2d5/0x970 [kvm] + __x64_sys_ioctl+0x8a/0xd0 + do_syscall_64+0xb7/0x890 + entry_SYSCALL_64_after_hwframe+0x4b/0x53 + RIP: 0033:0x7f19c931a9bf + + Modules linked in: kvm_intel kvm irqbypass + ---[ end trace 0000000000000000 ]--- + +In a perfect world, the fix would be to simply delete the BUG_ON(), as KVM +x86 doesn't perform alignment checks on "normal" memory accesses at CPL0. +Sadly, C99 ruins all the fun; while the x86 architecture plays nice, +dereferencing an unaligned pointer directly is undefined behavior in C, +e.g. triggers splats when running with CONFIG_UBSAN_ALIGNMENT=y. + +Fixes: d34e6b175e61 ("KVM: add ioeventfd support") +Cc: stable@vger.kernel.org +Signed-off-by: Sean Christopherson +Message-ID: <20260612225241.678509-1-seanjc@google.com> +Signed-off-by: Paolo Bonzini +[ Use the old header instead ] +Signed-off-by: Darshit Shah +Signed-off-by: Sasha Levin +--- + virt/kvm/eventfd.c | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c +index 4702b71aad0831..ff0ef5f7246e93 100644 +--- a/virt/kvm/eventfd.c ++++ b/virt/kvm/eventfd.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -695,21 +696,18 @@ ioeventfd_in_range(struct _ioeventfd *p, gpa_t addr, int len, const void *val) + return true; + + /* otherwise, we have to actually compare the data */ +- +- BUG_ON(!IS_ALIGNED((unsigned long)val, len)); +- + switch (len) { + case 1: +- _val = *(u8 *)val; ++ _val = get_unaligned((u8 *)val); + break; + case 2: +- _val = *(u16 *)val; ++ _val = get_unaligned((u16 *)val); + break; + case 4: +- _val = *(u32 *)val; ++ _val = get_unaligned((u32 *)val); + break; + case 8: +- _val = *(u64 *)val; ++ _val = get_unaligned((u64 *)val); + break; + default: + return false; +-- +2.53.0 + diff --git a/queue-5.10/series b/queue-5.10/series index 3f554b8ae2..ff3722099f 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -6,3 +6,4 @@ clk-imx-add-check-for-kcalloc.patch nfsd-move-name-lookup-out-of-nfsd4_list_rec_dir.patch nfsd-change-nfs4_client_to_reclaim-to-allocate-data.patch mmc-renesas_sdhi-add-quirk-entry-for-rz-g2h-soc.patch +kvm-replace-guest-triggerable-bug_on-in-ioeventfd-da.patch diff --git a/queue-5.15/kvm-replace-guest-triggerable-bug_on-in-ioeventfd-da.patch b/queue-5.15/kvm-replace-guest-triggerable-bug_on-in-ioeventfd-da.patch new file mode 100644 index 0000000000..78bed8ad7e --- /dev/null +++ b/queue-5.15/kvm-replace-guest-triggerable-bug_on-in-ioeventfd-da.patch @@ -0,0 +1,124 @@ +From bf0a86d7e8cdb3abad62e7ce8bc99131a772e5ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Jul 2026 16:30:49 +0000 +Subject: KVM: Replace guest-triggerable BUG_ON() in ioeventfd datamatch with + get_unaligned() + +From: Sean Christopherson + +commit f1edbed787ba67988ed34e0132ca128b052b6ce8 upstream. + +Drop a BUG_ON() that has been reachable since it was first added, way back +in 2009, and instead use get_unaligned() to perform potentially-unaligned +accesses. + +For a given store, KVM x86's emulator tracks the entire value in the +destination operand, x86_emulate_ctxt.dst. If the destination is memory, +and the target splits multiple pages and/or is emulated MMIO, then KVM +handles each fragment independently. E.g. on a page split starting at page +offset 0xffc, KVM writes 4 bytes to the first page, then the remaining +bytes to the second page, using ctxt->dst as the source for both (with +appropriate offsets). + +If the destination splits a page *and* hits emulated MMIO on the second +page, then KVM will complete the write to the first page, then emulate the +MMIO access to the second page. If there is a datamatch-enabled ioeventfd +at offset 0 of the second page, then KVM will process the remainder of the +store as a potential ioeventfd signal. + +Putting it all together, if the guest emits a store that splits a page +starting at page offset N, and the second page has a datamatch-enabled +ioeventfd at offset 0, then KVM will check for datamatch using +&dst.valptr[N] as the source. Due to dst (and thus dst.valptr) being +32-byte aligned, if N is not aligned to @len, the BUG_ON() fires. + +E.g. with a 16-byte store at page offset 0xffc, to an ioeventfd of len 8, +all initial checks in ioeventfd_in_range() will succeed, and the BUG_ON() +fires due to @val being 4-byte aligned, but not 8-byte aligned. + + ------------[ cut here ]------------ + kernel BUG at arch/x86/kvm/../../../virt/kvm/eventfd.c:783! + Oops: invalid opcode: 0000 [#1] SMP + CPU: 0 UID: 1000 PID: 615 Comm: repro Not tainted 7.1.0-rc2-ff238429d1ea #365 PREEMPT + Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015 + RIP: 0010:ioeventfd_write+0x6c/0x70 [kvm] + Call Trace: + + __kvm_io_bus_write+0x85/0xb0 [kvm] + kvm_io_bus_write+0x53/0x80 [kvm] + vcpu_mmio_write+0x66/0xf0 [kvm] + emulator_read_write_onepage+0x12a/0x540 [kvm] + emulator_read_write+0x109/0x2b0 [kvm] + x86_emulate_insn+0x4f8/0xfb0 [kvm] + x86_emulate_instruction+0x181/0x790 [kvm] + kvm_mmu_page_fault+0x313/0x630 [kvm] + vmx_handle_exit+0x18a/0x590 [kvm_intel] + kvm_arch_vcpu_ioctl_run+0xc81/0x1c90 [kvm] + kvm_vcpu_ioctl+0x2d5/0x970 [kvm] + __x64_sys_ioctl+0x8a/0xd0 + do_syscall_64+0xb7/0x890 + entry_SYSCALL_64_after_hwframe+0x4b/0x53 + RIP: 0033:0x7f19c931a9bf + + Modules linked in: kvm_intel kvm irqbypass + ---[ end trace 0000000000000000 ]--- + +In a perfect world, the fix would be to simply delete the BUG_ON(), as KVM +x86 doesn't perform alignment checks on "normal" memory accesses at CPL0. +Sadly, C99 ruins all the fun; while the x86 architecture plays nice, +dereferencing an unaligned pointer directly is undefined behavior in C, +e.g. triggers splats when running with CONFIG_UBSAN_ALIGNMENT=y. + +Fixes: d34e6b175e61 ("KVM: add ioeventfd support") +Cc: stable@vger.kernel.org +Signed-off-by: Sean Christopherson +Message-ID: <20260612225241.678509-1-seanjc@google.com> +Signed-off-by: Paolo Bonzini +[ Use the old header instead ] +Signed-off-by: Darshit Shah +Signed-off-by: Sasha Levin +--- + virt/kvm/eventfd.c | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c +index c841f8bc8228a1..b78a82f6dbbbd0 100644 +--- a/virt/kvm/eventfd.c ++++ b/virt/kvm/eventfd.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -710,21 +711,18 @@ ioeventfd_in_range(struct _ioeventfd *p, gpa_t addr, int len, const void *val) + return true; + + /* otherwise, we have to actually compare the data */ +- +- BUG_ON(!IS_ALIGNED((unsigned long)val, len)); +- + switch (len) { + case 1: +- _val = *(u8 *)val; ++ _val = get_unaligned((u8 *)val); + break; + case 2: +- _val = *(u16 *)val; ++ _val = get_unaligned((u16 *)val); + break; + case 4: +- _val = *(u32 *)val; ++ _val = get_unaligned((u32 *)val); + break; + case 8: +- _val = *(u64 *)val; ++ _val = get_unaligned((u64 *)val); + break; + default: + return false; +-- +2.53.0 + diff --git a/queue-5.15/series b/queue-5.15/series index f06ab4c903..814ae5f944 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -13,3 +13,4 @@ slimbus-convert-to-platform-remove-callback-returnin.patch slimbus-qcom-ngd-ctrl-register-callbacks-after-creat.patch nfsd-move-name-lookup-out-of-nfsd4_list_rec_dir.patch nfsd-change-nfs4_client_to_reclaim-to-allocate-data.patch +kvm-replace-guest-triggerable-bug_on-in-ioeventfd-da.patch diff --git a/queue-6.1/bluetooth-iso-copy-base-if-service-data-matches-eir_.patch b/queue-6.1/bluetooth-iso-copy-base-if-service-data-matches-eir_.patch new file mode 100644 index 0000000000..835a3cc203 --- /dev/null +++ b/queue-6.1/bluetooth-iso-copy-base-if-service-data-matches-eir_.patch @@ -0,0 +1,73 @@ +From 760334e316510ab36f7f51fea448802f2d3a181a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 Sep 2023 11:02:08 +0300 +Subject: Bluetooth: ISO: Copy BASE if service data matches + EIR_BAA_SERVICE_UUID + +From: Claudia Draghicescu + +[ Upstream commit f4da3ee15de9944482382181329bb6d7335ca003 ] + +Copy the content of a Periodic Advertisement Report to BASE only if +the service UUID is Basic Audio Announcement Service UUID. + +Signed-off-by: Claudia Draghicescu +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/iso.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c +index 7ea3e633550eb1..aad4baec9ec163 100644 +--- a/net/bluetooth/iso.c ++++ b/net/bluetooth/iso.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include "eir.h" + + static const struct proto_ops iso_sock_ops; + +@@ -46,6 +47,7 @@ static void iso_sock_kill(struct sock *sk); + + #define EIR_SERVICE_DATA_LENGTH 4 + #define BASE_MAX_LENGTH (HCI_MAX_PER_AD_LENGTH - EIR_SERVICE_DATA_LENGTH) ++#define EIR_BAA_SERVICE_UUID 0x1851 + + struct iso_pinfo { + struct bt_sock bt; +@@ -1337,6 +1339,8 @@ static int iso_sock_getsockopt(struct socket *sock, int level, int optname, + len = min_t(unsigned int, len, base_len); + if (copy_to_user(optval, base, len)) + err = -EFAULT; ++ if (put_user(len, optlen)) ++ err = -EFAULT; + + break; + +@@ -1606,12 +1610,16 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags) + + ev3 = hci_recv_event_data(hdev, HCI_EV_LE_PER_ADV_REPORT); + if (ev3) { ++ size_t base_len = ev3->length; ++ u8 *base; ++ + sk = iso_get_sock_listen(&hdev->bdaddr, bdaddr, + iso_match_sync_handle_pa_report, ev3); +- +- if (sk) { +- memcpy(iso_pi(sk)->base, ev3->data, ev3->length); +- iso_pi(sk)->base_len = ev3->length; ++ base = eir_get_service_data(ev3->data, ev3->length, ++ EIR_BAA_SERVICE_UUID, &base_len); ++ if (base && sk && base_len <= sizeof(iso_pi(sk)->base)) { ++ memcpy(iso_pi(sk)->base, base, base_len); ++ iso_pi(sk)->base_len = base_len; + } + } else { + sk = iso_get_sock_listen(&hdev->bdaddr, BDADDR_ANY, NULL, NULL); +-- +2.53.0 + diff --git a/queue-6.1/kvm-replace-guest-triggerable-bug_on-in-ioeventfd-da.patch b/queue-6.1/kvm-replace-guest-triggerable-bug_on-in-ioeventfd-da.patch new file mode 100644 index 0000000000..328687676b --- /dev/null +++ b/queue-6.1/kvm-replace-guest-triggerable-bug_on-in-ioeventfd-da.patch @@ -0,0 +1,124 @@ +From 1ad697f3ce3dc78f308393febfedb650eb1a37a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Jul 2026 16:30:49 +0000 +Subject: KVM: Replace guest-triggerable BUG_ON() in ioeventfd datamatch with + get_unaligned() + +From: Sean Christopherson + +commit f1edbed787ba67988ed34e0132ca128b052b6ce8 upstream. + +Drop a BUG_ON() that has been reachable since it was first added, way back +in 2009, and instead use get_unaligned() to perform potentially-unaligned +accesses. + +For a given store, KVM x86's emulator tracks the entire value in the +destination operand, x86_emulate_ctxt.dst. If the destination is memory, +and the target splits multiple pages and/or is emulated MMIO, then KVM +handles each fragment independently. E.g. on a page split starting at page +offset 0xffc, KVM writes 4 bytes to the first page, then the remaining +bytes to the second page, using ctxt->dst as the source for both (with +appropriate offsets). + +If the destination splits a page *and* hits emulated MMIO on the second +page, then KVM will complete the write to the first page, then emulate the +MMIO access to the second page. If there is a datamatch-enabled ioeventfd +at offset 0 of the second page, then KVM will process the remainder of the +store as a potential ioeventfd signal. + +Putting it all together, if the guest emits a store that splits a page +starting at page offset N, and the second page has a datamatch-enabled +ioeventfd at offset 0, then KVM will check for datamatch using +&dst.valptr[N] as the source. Due to dst (and thus dst.valptr) being +32-byte aligned, if N is not aligned to @len, the BUG_ON() fires. + +E.g. with a 16-byte store at page offset 0xffc, to an ioeventfd of len 8, +all initial checks in ioeventfd_in_range() will succeed, and the BUG_ON() +fires due to @val being 4-byte aligned, but not 8-byte aligned. + + ------------[ cut here ]------------ + kernel BUG at arch/x86/kvm/../../../virt/kvm/eventfd.c:783! + Oops: invalid opcode: 0000 [#1] SMP + CPU: 0 UID: 1000 PID: 615 Comm: repro Not tainted 7.1.0-rc2-ff238429d1ea #365 PREEMPT + Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015 + RIP: 0010:ioeventfd_write+0x6c/0x70 [kvm] + Call Trace: + + __kvm_io_bus_write+0x85/0xb0 [kvm] + kvm_io_bus_write+0x53/0x80 [kvm] + vcpu_mmio_write+0x66/0xf0 [kvm] + emulator_read_write_onepage+0x12a/0x540 [kvm] + emulator_read_write+0x109/0x2b0 [kvm] + x86_emulate_insn+0x4f8/0xfb0 [kvm] + x86_emulate_instruction+0x181/0x790 [kvm] + kvm_mmu_page_fault+0x313/0x630 [kvm] + vmx_handle_exit+0x18a/0x590 [kvm_intel] + kvm_arch_vcpu_ioctl_run+0xc81/0x1c90 [kvm] + kvm_vcpu_ioctl+0x2d5/0x970 [kvm] + __x64_sys_ioctl+0x8a/0xd0 + do_syscall_64+0xb7/0x890 + entry_SYSCALL_64_after_hwframe+0x4b/0x53 + RIP: 0033:0x7f19c931a9bf + + Modules linked in: kvm_intel kvm irqbypass + ---[ end trace 0000000000000000 ]--- + +In a perfect world, the fix would be to simply delete the BUG_ON(), as KVM +x86 doesn't perform alignment checks on "normal" memory accesses at CPL0. +Sadly, C99 ruins all the fun; while the x86 architecture plays nice, +dereferencing an unaligned pointer directly is undefined behavior in C, +e.g. triggers splats when running with CONFIG_UBSAN_ALIGNMENT=y. + +Fixes: d34e6b175e61 ("KVM: add ioeventfd support") +Cc: stable@vger.kernel.org +Signed-off-by: Sean Christopherson +Message-ID: <20260612225241.678509-1-seanjc@google.com> +Signed-off-by: Paolo Bonzini +[ Use the old header instead ] +Signed-off-by: Darshit Shah +Signed-off-by: Sasha Levin +--- + virt/kvm/eventfd.c | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c +index c3340bdc754af4..cff637cfaed1e7 100644 +--- a/virt/kvm/eventfd.c ++++ b/virt/kvm/eventfd.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -724,21 +725,18 @@ ioeventfd_in_range(struct _ioeventfd *p, gpa_t addr, int len, const void *val) + return true; + + /* otherwise, we have to actually compare the data */ +- +- BUG_ON(!IS_ALIGNED((unsigned long)val, len)); +- + switch (len) { + case 1: +- _val = *(u8 *)val; ++ _val = get_unaligned((u8 *)val); + break; + case 2: +- _val = *(u16 *)val; ++ _val = get_unaligned((u16 *)val); + break; + case 4: +- _val = *(u32 *)val; ++ _val = get_unaligned((u32 *)val); + break; + case 8: +- _val = *(u64 *)val; ++ _val = get_unaligned((u64 *)val); + break; + default: + return false; +-- +2.53.0 + diff --git a/queue-6.1/series b/queue-6.1/series index b6324033a6..307a1612bc 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -13,3 +13,5 @@ slimbus-qcom-ngd-ctrl-register-callbacks-after-creat.patch nfsd-move-name-lookup-out-of-nfsd4_list_rec_dir.patch nfsd-change-nfs4_client_to_reclaim-to-allocate-data.patch mm-vmscan-flush-deferred-tlb-before-freeing-large-fo.patch +bluetooth-iso-copy-base-if-service-data-matches-eir_.patch +kvm-replace-guest-triggerable-bug_on-in-ioeventfd-da.patch diff --git a/queue-6.12/mm-khugepaged-write-all-dirty-file-folios-when-colla.patch b/queue-6.12/mm-khugepaged-write-all-dirty-file-folios-when-colla.patch new file mode 100644 index 0000000000..40e2c01201 --- /dev/null +++ b/queue-6.12/mm-khugepaged-write-all-dirty-file-folios-when-colla.patch @@ -0,0 +1,131 @@ +From 8439c2201190b71a9535a9242da40b0287c4b0bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Jul 2026 16:13:57 +0100 +Subject: mm/khugepaged: write all dirty file folios when collapsing + +From: Pedro Falcato + +[There is no upstream commit, as this code was removed by upstream + commit 044925f9b565 ("mm: fs: remove filemap_nr_thps*() functions and their users")] + +As-is, khugepaged and writable-file opening exclude each other. A file +cannot be open writeable and have THPs (because the filesystem is not aware +of them). khugepaged will never collapse file pages for files that are +opened writeable. On an open(O_RDWR/O_WRONLY), the page cache for that +particular file is dropped. This is fine because nothing could've been +dirtied. + +However, there is an edge-case: collapse_file() might not be able to +coexist with concurrent writers, but it can coexist with dirty folios +(from previous writers). Therefore, the following can happen: + +open(file, O_RDWR) +write(file) +close(file) +madvise(file_mapping, MADV_COLLAPSE, some non-dirty range) +open(file, O_RDWR) + nr_thps > 0 + truncate_inode_pages() + /* THPs are cleared out, but so are the dirty folios */ + +When this edge-case happens, there is data loss, as the dirty folios are +fully discarded. + +Fix it by fully writing back the page cache (and waiting) when collapsing +file THPs. Doing so provides the guarantee that no dirty folio will be +observed while there are active THPs. To fully ensure this is safe, the +invalidate_lock needs to be held while doing the writeout, so that +do_dentry_open()'s page cache truncation excludes this write-and-wait. + +As a side effect, move the nr_thps counter bumping outside the i_pages +lock. This is correct since the counter itself is an atomic_t and the +producer <-> consumer correctness is provided by a full memory barrier: +smp_mb() in collapse_file()/memory barrier implied by full ordering in +get_write_access() -> atomic_inc_unless_negative(). + +Cc: stable@vger.kernel.org +Cc: Alexander Viro +Cc: Christian Brauner +Cc: Jan Kara +Cc: Matthew Wilcox +Cc: Song Liu +Cc: Eric Hagberg +Cc: Zi Yan +Fixes: 99cb0dbd47a1 ("mm,thp: add read-only THP support for (non-shmem) FS") +Reported-by: Gregg Leventhal +Closes: https://lore.kernel.org/linux-mm/CAFN_u7H_0ECF3jixP=T=U7AH5=Q3wQNvJMo8an3VqUDMerQfUw@mail.gmail.com/ +Tested-by: Zi Yan +Tested-by: Lance Yang +Signed-off-by: Pedro Falcato +Acked-by: David Hildenbrand (Arm) +Reviewed-by: Matthew Wilcox (Oracle) +Signed-off-by: Sasha Levin +--- + mm/khugepaged.c | 39 +++++++++++++++++++++++++-------------- + 1 file changed, 25 insertions(+), 14 deletions(-) + +diff --git a/mm/khugepaged.c b/mm/khugepaged.c +index a97b20617869ae..95b49ca6b196cc 100644 +--- a/mm/khugepaged.c ++++ b/mm/khugepaged.c +@@ -2017,32 +2017,43 @@ static int collapse_file(struct mm_struct *mm, unsigned long addr, + goto xa_unlocked; + } + +- if (!is_shmem) { ++xa_locked: ++ xas_unlock_irq(&xas); ++xa_unlocked: ++ ++ /* ++ * If collapse is successful, flush must be done now before copying. ++ * If collapse is unsuccessful, does flush actually need to be done? ++ * Do it anyway, to clear the state. ++ */ ++ try_to_unmap_flush(); ++ ++ if (result == SCAN_SUCCEED && !is_shmem && !mapping_large_folio_support(mapping)) { ++ /* ++ * invalidate_lock as shared excludes against concurrent opens ++ * in do_dentry_open() truncating the page cache. This is ++ * particularly important if there are dirty folios in transit. ++ */ ++ filemap_invalidate_lock_shared(mapping); + filemap_nr_thps_inc(mapping); + /* + * Paired with the fence in do_dentry_open() -> get_write_access() + * to ensure i_writecount is up to date and the update to nr_thps + * is visible. Ensures the page cache will be truncated if the +- * file is opened writable. ++ * file is opened writable. If collapse looks to be successful, ++ * flush any dirty pages out the page cache. With the nr_thps ++ * incremented, there won't be any new writers (nor new dirties). + */ + smp_mb(); +- if (inode_is_open_for_write(mapping->host)) { ++ if (inode_is_open_for_write(mapping->host) || filemap_write_and_wait(mapping)) { + result = SCAN_FAIL; + filemap_nr_thps_dec(mapping); ++ filemap_invalidate_unlock_shared(mapping); ++ goto rollback; + } ++ filemap_invalidate_unlock_shared(mapping); + } + +-xa_locked: +- xas_unlock_irq(&xas); +-xa_unlocked: +- +- /* +- * If collapse is successful, flush must be done now before copying. +- * If collapse is unsuccessful, does flush actually need to be done? +- * Do it anyway, to clear the state. +- */ +- try_to_unmap_flush(); +- + if (result == SCAN_SUCCEED && nr_none && + !shmem_charge(mapping->host, nr_none)) + result = SCAN_FAIL; +-- +2.53.0 + diff --git a/queue-6.12/series b/queue-6.12/series index 95940c0b46..81dc342160 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -29,3 +29,4 @@ nfsd-change-nfs4_client_to_reclaim-to-allocate-data.patch bonding-fix-xfrm-offload-feature-setup-on-active-bac.patch block-add-a-store_limit-operations-for-sysfs-entries.patch block-fix-queue-freeze-vs-limits-lock-order-in-sysfs.patch +mm-khugepaged-write-all-dirty-file-folios-when-colla.patch diff --git a/queue-6.18/mm-khugepaged-write-all-dirty-file-folios-when-colla.patch b/queue-6.18/mm-khugepaged-write-all-dirty-file-folios-when-colla.patch new file mode 100644 index 0000000000..1a45be2aff --- /dev/null +++ b/queue-6.18/mm-khugepaged-write-all-dirty-file-folios-when-colla.patch @@ -0,0 +1,131 @@ +From 4895984580d507ad7bc4cad738012e5567cf9eae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Jul 2026 16:13:57 +0100 +Subject: mm/khugepaged: write all dirty file folios when collapsing + +From: Pedro Falcato + +[There is no upstream commit, as this code was removed by upstream + commit 044925f9b565 ("mm: fs: remove filemap_nr_thps*() functions and their users")] + +As-is, khugepaged and writable-file opening exclude each other. A file +cannot be open writeable and have THPs (because the filesystem is not aware +of them). khugepaged will never collapse file pages for files that are +opened writeable. On an open(O_RDWR/O_WRONLY), the page cache for that +particular file is dropped. This is fine because nothing could've been +dirtied. + +However, there is an edge-case: collapse_file() might not be able to +coexist with concurrent writers, but it can coexist with dirty folios +(from previous writers). Therefore, the following can happen: + +open(file, O_RDWR) +write(file) +close(file) +madvise(file_mapping, MADV_COLLAPSE, some non-dirty range) +open(file, O_RDWR) + nr_thps > 0 + truncate_inode_pages() + /* THPs are cleared out, but so are the dirty folios */ + +When this edge-case happens, there is data loss, as the dirty folios are +fully discarded. + +Fix it by fully writing back the page cache (and waiting) when collapsing +file THPs. Doing so provides the guarantee that no dirty folio will be +observed while there are active THPs. To fully ensure this is safe, the +invalidate_lock needs to be held while doing the writeout, so that +do_dentry_open()'s page cache truncation excludes this write-and-wait. + +As a side effect, move the nr_thps counter bumping outside the i_pages +lock. This is correct since the counter itself is an atomic_t and the +producer <-> consumer correctness is provided by a full memory barrier: +smp_mb() in collapse_file()/memory barrier implied by full ordering in +get_write_access() -> atomic_inc_unless_negative(). + +Cc: stable@vger.kernel.org +Cc: Alexander Viro +Cc: Christian Brauner +Cc: Jan Kara +Cc: Matthew Wilcox +Cc: Song Liu +Cc: Eric Hagberg +Cc: Zi Yan +Fixes: 99cb0dbd47a1 ("mm,thp: add read-only THP support for (non-shmem) FS") +Reported-by: Gregg Leventhal +Closes: https://lore.kernel.org/linux-mm/CAFN_u7H_0ECF3jixP=T=U7AH5=Q3wQNvJMo8an3VqUDMerQfUw@mail.gmail.com/ +Tested-by: Zi Yan +Tested-by: Lance Yang +Signed-off-by: Pedro Falcato +Acked-by: David Hildenbrand (Arm) +Reviewed-by: Matthew Wilcox (Oracle) +Signed-off-by: Sasha Levin +--- + mm/khugepaged.c | 39 +++++++++++++++++++++++++-------------- + 1 file changed, 25 insertions(+), 14 deletions(-) + +diff --git a/mm/khugepaged.c b/mm/khugepaged.c +index 3dcd884c844e8f..01a5d443ffc586 100644 +--- a/mm/khugepaged.c ++++ b/mm/khugepaged.c +@@ -2077,32 +2077,43 @@ static int collapse_file(struct mm_struct *mm, unsigned long addr, + goto xa_unlocked; + } + +- if (!is_shmem) { ++xa_locked: ++ xas_unlock_irq(&xas); ++xa_unlocked: ++ ++ /* ++ * If collapse is successful, flush must be done now before copying. ++ * If collapse is unsuccessful, does flush actually need to be done? ++ * Do it anyway, to clear the state. ++ */ ++ try_to_unmap_flush(); ++ ++ if (result == SCAN_SUCCEED && !is_shmem && !mapping_large_folio_support(mapping)) { ++ /* ++ * invalidate_lock as shared excludes against concurrent opens ++ * in do_dentry_open() truncating the page cache. This is ++ * particularly important if there are dirty folios in transit. ++ */ ++ filemap_invalidate_lock_shared(mapping); + filemap_nr_thps_inc(mapping); + /* + * Paired with the fence in do_dentry_open() -> get_write_access() + * to ensure i_writecount is up to date and the update to nr_thps + * is visible. Ensures the page cache will be truncated if the +- * file is opened writable. ++ * file is opened writable. If collapse looks to be successful, ++ * flush any dirty pages out the page cache. With the nr_thps ++ * incremented, there won't be any new writers (nor new dirties). + */ + smp_mb(); +- if (inode_is_open_for_write(mapping->host)) { ++ if (inode_is_open_for_write(mapping->host) || filemap_write_and_wait(mapping)) { + result = SCAN_FAIL; + filemap_nr_thps_dec(mapping); ++ filemap_invalidate_unlock_shared(mapping); ++ goto rollback; + } ++ filemap_invalidate_unlock_shared(mapping); + } + +-xa_locked: +- xas_unlock_irq(&xas); +-xa_unlocked: +- +- /* +- * If collapse is successful, flush must be done now before copying. +- * If collapse is unsuccessful, does flush actually need to be done? +- * Do it anyway, to clear the state. +- */ +- try_to_unmap_flush(); +- + if (result == SCAN_SUCCEED && nr_none && + !shmem_charge(mapping->host, nr_none)) + result = SCAN_FAIL; +-- +2.53.0 + diff --git a/queue-6.18/series b/queue-6.18/series index 30724b9331..e4d9370daa 100644 --- a/queue-6.18/series +++ b/queue-6.18/series @@ -21,3 +21,4 @@ fbdev-fbcon-fix-out-of-bounds-read-in-err_out-of-fbcon_do_set_font.patch net-sched-dualpi2-fix-gso-backlog-accounting.patch nfsd-move-name-lookup-out-of-nfsd4_list_rec_dir.patch nfsd-change-nfs4_client_to_reclaim-to-allocate-data.patch +mm-khugepaged-write-all-dirty-file-folios-when-colla.patch diff --git a/queue-6.6/bluetooth-iso-copy-base-if-service-data-matches-eir_.patch b/queue-6.6/bluetooth-iso-copy-base-if-service-data-matches-eir_.patch new file mode 100644 index 0000000000..731c871f6a --- /dev/null +++ b/queue-6.6/bluetooth-iso-copy-base-if-service-data-matches-eir_.patch @@ -0,0 +1,73 @@ +From 027c876133436cdfbd85132fb3c231730f408d50 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 Sep 2023 11:02:08 +0300 +Subject: Bluetooth: ISO: Copy BASE if service data matches + EIR_BAA_SERVICE_UUID + +From: Claudia Draghicescu + +[ Upstream commit f4da3ee15de9944482382181329bb6d7335ca003 ] + +Copy the content of a Periodic Advertisement Report to BASE only if +the service UUID is Basic Audio Announcement Service UUID. + +Signed-off-by: Claudia Draghicescu +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/iso.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c +index 011b2187bd8516..8843bd5c5812ba 100644 +--- a/net/bluetooth/iso.c ++++ b/net/bluetooth/iso.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include "eir.h" + + static const struct proto_ops iso_sock_ops; + +@@ -47,6 +48,7 @@ static void iso_sock_kill(struct sock *sk); + + #define EIR_SERVICE_DATA_LENGTH 4 + #define BASE_MAX_LENGTH (HCI_MAX_PER_AD_LENGTH - EIR_SERVICE_DATA_LENGTH) ++#define EIR_BAA_SERVICE_UUID 0x1851 + + /* iso_pinfo flags values */ + enum { +@@ -1587,6 +1589,8 @@ static int iso_sock_getsockopt(struct socket *sock, int level, int optname, + len = min_t(unsigned int, len, base_len); + if (copy_to_user(optval, base, len)) + err = -EFAULT; ++ if (put_user(len, optlen)) ++ err = -EFAULT; + + break; + +@@ -1928,12 +1932,16 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags) + + ev3 = hci_recv_event_data(hdev, HCI_EV_LE_PER_ADV_REPORT); + if (ev3) { ++ size_t base_len = ev3->length; ++ u8 *base; ++ + sk = iso_get_sock_listen(&hdev->bdaddr, bdaddr, + iso_match_sync_handle_pa_report, ev3); +- +- if (sk) { +- memcpy(iso_pi(sk)->base, ev3->data, ev3->length); +- iso_pi(sk)->base_len = ev3->length; ++ base = eir_get_service_data(ev3->data, ev3->length, ++ EIR_BAA_SERVICE_UUID, &base_len); ++ if (base && sk && base_len <= sizeof(iso_pi(sk)->base)) { ++ memcpy(iso_pi(sk)->base, base, base_len); ++ iso_pi(sk)->base_len = base_len; + } + } else { + sk = iso_get_sock_listen(&hdev->bdaddr, BDADDR_ANY, NULL, NULL); +-- +2.53.0 + diff --git a/queue-6.6/series b/queue-6.6/series index e9942e61d2..e25bd47091 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -56,3 +56,4 @@ xfs-recreate-work-items-when-recovering-intent-items.patch xfs-dump-the-recovered-xattri-log-item-if-corruption.patch xfs-use-xfs_defer_finish_one-to-finish-recovered-wor.patch xfs-move-iop_recover-to-xfs_defer_op_type.patch +bluetooth-iso-copy-base-if-service-data-matches-eir_.patch diff --git a/queue-7.1/mm-khugepaged-write-all-dirty-file-folios-when-colla.patch b/queue-7.1/mm-khugepaged-write-all-dirty-file-folios-when-colla.patch new file mode 100644 index 0000000000..c2a26dadc3 --- /dev/null +++ b/queue-7.1/mm-khugepaged-write-all-dirty-file-folios-when-colla.patch @@ -0,0 +1,131 @@ +From 824db361bda77a9e311cbe37492563dceb815d88 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Jul 2026 16:13:57 +0100 +Subject: mm/khugepaged: write all dirty file folios when collapsing + +From: Pedro Falcato + +[There is no upstream commit, as this code was removed by upstream + commit 044925f9b565 ("mm: fs: remove filemap_nr_thps*() functions and their users")] + +As-is, khugepaged and writable-file opening exclude each other. A file +cannot be open writeable and have THPs (because the filesystem is not aware +of them). khugepaged will never collapse file pages for files that are +opened writeable. On an open(O_RDWR/O_WRONLY), the page cache for that +particular file is dropped. This is fine because nothing could've been +dirtied. + +However, there is an edge-case: collapse_file() might not be able to +coexist with concurrent writers, but it can coexist with dirty folios +(from previous writers). Therefore, the following can happen: + +open(file, O_RDWR) +write(file) +close(file) +madvise(file_mapping, MADV_COLLAPSE, some non-dirty range) +open(file, O_RDWR) + nr_thps > 0 + truncate_inode_pages() + /* THPs are cleared out, but so are the dirty folios */ + +When this edge-case happens, there is data loss, as the dirty folios are +fully discarded. + +Fix it by fully writing back the page cache (and waiting) when collapsing +file THPs. Doing so provides the guarantee that no dirty folio will be +observed while there are active THPs. To fully ensure this is safe, the +invalidate_lock needs to be held while doing the writeout, so that +do_dentry_open()'s page cache truncation excludes this write-and-wait. + +As a side effect, move the nr_thps counter bumping outside the i_pages +lock. This is correct since the counter itself is an atomic_t and the +producer <-> consumer correctness is provided by a full memory barrier: +smp_mb() in collapse_file()/memory barrier implied by full ordering in +get_write_access() -> atomic_inc_unless_negative(). + +Cc: stable@vger.kernel.org +Cc: Alexander Viro +Cc: Christian Brauner +Cc: Jan Kara +Cc: Matthew Wilcox +Cc: Song Liu +Cc: Eric Hagberg +Cc: Zi Yan +Fixes: 99cb0dbd47a1 ("mm,thp: add read-only THP support for (non-shmem) FS") +Reported-by: Gregg Leventhal +Closes: https://lore.kernel.org/linux-mm/CAFN_u7H_0ECF3jixP=T=U7AH5=Q3wQNvJMo8an3VqUDMerQfUw@mail.gmail.com/ +Tested-by: Zi Yan +Tested-by: Lance Yang +Signed-off-by: Pedro Falcato +Acked-by: David Hildenbrand (Arm) +Reviewed-by: Matthew Wilcox (Oracle) +Signed-off-by: Sasha Levin +--- + mm/khugepaged.c | 39 +++++++++++++++++++++++++-------------- + 1 file changed, 25 insertions(+), 14 deletions(-) + +diff --git a/mm/khugepaged.c b/mm/khugepaged.c +index b8452dbdb043f8..d6e04041f5dc11 100644 +--- a/mm/khugepaged.c ++++ b/mm/khugepaged.c +@@ -2094,32 +2094,43 @@ static enum scan_result collapse_file(struct mm_struct *mm, unsigned long addr, + goto xa_unlocked; + } + +- if (!is_shmem) { ++xa_locked: ++ xas_unlock_irq(&xas); ++xa_unlocked: ++ ++ /* ++ * If collapse is successful, flush must be done now before copying. ++ * If collapse is unsuccessful, does flush actually need to be done? ++ * Do it anyway, to clear the state. ++ */ ++ try_to_unmap_flush(); ++ ++ if (result == SCAN_SUCCEED && !is_shmem && !mapping_large_folio_support(mapping)) { ++ /* ++ * invalidate_lock as shared excludes against concurrent opens ++ * in do_dentry_open() truncating the page cache. This is ++ * particularly important if there are dirty folios in transit. ++ */ ++ filemap_invalidate_lock_shared(mapping); + filemap_nr_thps_inc(mapping); + /* + * Paired with the fence in do_dentry_open() -> get_write_access() + * to ensure i_writecount is up to date and the update to nr_thps + * is visible. Ensures the page cache will be truncated if the +- * file is opened writable. ++ * file is opened writable. If collapse looks to be successful, ++ * flush any dirty pages out the page cache. With the nr_thps ++ * incremented, there won't be any new writers (nor new dirties). + */ + smp_mb(); +- if (inode_is_open_for_write(mapping->host)) { ++ if (inode_is_open_for_write(mapping->host) || filemap_write_and_wait(mapping)) { + result = SCAN_FAIL; + filemap_nr_thps_dec(mapping); ++ filemap_invalidate_unlock_shared(mapping); ++ goto rollback; + } ++ filemap_invalidate_unlock_shared(mapping); + } + +-xa_locked: +- xas_unlock_irq(&xas); +-xa_unlocked: +- +- /* +- * If collapse is successful, flush must be done now before copying. +- * If collapse is unsuccessful, does flush actually need to be done? +- * Do it anyway, to clear the state. +- */ +- try_to_unmap_flush(); +- + if (result == SCAN_SUCCEED && nr_none && + !shmem_charge(mapping->host, nr_none)) + result = SCAN_FAIL; +-- +2.53.0 + diff --git a/queue-7.1/series b/queue-7.1/series index f9cab6a5a1..f12a1c6c36 100644 --- a/queue-7.1/series +++ b/queue-7.1/series @@ -2,3 +2,4 @@ rust-str-use-the-kernel-vertical-imports-style.patch rust-str-clean-unused-import-for-rust-1.98.patch userfaultfd-gate-must_wait-writability-check-on-pte_.patch net-sched-dualpi2-fix-gso-backlog-accounting.patch +mm-khugepaged-write-all-dirty-file-folios-when-colla.patch