From: Greg Kroah-Hartman Date: Sun, 15 Dec 2024 08:41:20 +0000 (+0100) Subject: 6.1-stable patches X-Git-Tag: v5.4.288~63 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=bba1810daf31183267d2ed0c1da6df5a47dff5ea;p=thirdparty%2Fkernel%2Fstable-queue.git 6.1-stable patches added patches: drm-i915-fix-memory-leak-by-correcting-cache-object-name-in-error-handler.patch usb-dwc3-xilinx-make-sure-pipe-clock-is-deselected-in-usb2-only-mode.patch usb-ehci-hcd-fix-call-balance-of-clocks-handling-routines.patch usb-gadget-u_serial-fix-the-issue-that-gs_start_io-crashed-due-to-accessing-null-pointer.patch usb-typec-anx7411-fix-fwnode_handle-reference-leak.patch usb-typec-anx7411-fix-of-node-reference-leaks-in-anx7411_typec_switch_probe.patch xfs-don-t-drop-errno-values-when-we-fail-to-ficlone-the-entire-range.patch xfs-update-btree-keys-correctly-when-_insrec-splits-an-inode-root-block.patch --- diff --git a/queue-6.1/drm-i915-fix-memory-leak-by-correcting-cache-object-name-in-error-handler.patch b/queue-6.1/drm-i915-fix-memory-leak-by-correcting-cache-object-name-in-error-handler.patch new file mode 100644 index 00000000000..cda1da5658e --- /dev/null +++ b/queue-6.1/drm-i915-fix-memory-leak-by-correcting-cache-object-name-in-error-handler.patch @@ -0,0 +1,36 @@ +From 2828e5808bcd5aae7fdcd169cac1efa2701fa2dd Mon Sep 17 00:00:00 2001 +From: Jiasheng Jiang +Date: Wed, 27 Nov 2024 20:10:42 +0000 +Subject: drm/i915: Fix memory leak by correcting cache object name in error handler + +From: Jiasheng Jiang + +commit 2828e5808bcd5aae7fdcd169cac1efa2701fa2dd upstream. + +Replace "slab_priorities" with "slab_dependencies" in the error handler +to avoid memory leak. + +Fixes: 32eb6bcfdda9 ("drm/i915: Make request allocation caches global") +Cc: # v5.2+ +Signed-off-by: Jiasheng Jiang +Reviewed-by: Nirmoy Das +Reviewed-by: Andi Shyti +Signed-off-by: Andi Shyti +Link: https://patchwork.freedesktop.org/patch/msgid/20241127201042.29620-1-jiashengjiangcool@gmail.com +(cherry picked from commit 9bc5e7dc694d3112bbf0fa4c46ef0fa0f114937a) +Signed-off-by: Tvrtko Ursulin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/i915/i915_scheduler.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpu/drm/i915/i915_scheduler.c ++++ b/drivers/gpu/drm/i915/i915_scheduler.c +@@ -506,6 +506,6 @@ int __init i915_scheduler_module_init(vo + return 0; + + err_priorities: +- kmem_cache_destroy(slab_priorities); ++ kmem_cache_destroy(slab_dependencies); + return -ENOMEM; + } diff --git a/queue-6.1/series b/queue-6.1/series index b8266210f5d..7c0c191f5a7 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -9,3 +9,11 @@ ata-sata_highbank-fix-of-node-reference-leak-in-highbank_initialize_phys.patch usb-dwc2-fix-hcd-resume.patch usb-dwc2-hcd-fix-getportstatus-setportfeature.patch usb-dwc2-fix-hcd-port-connection-race.patch +usb-ehci-hcd-fix-call-balance-of-clocks-handling-routines.patch +usb-typec-anx7411-fix-fwnode_handle-reference-leak.patch +usb-typec-anx7411-fix-of-node-reference-leaks-in-anx7411_typec_switch_probe.patch +usb-gadget-u_serial-fix-the-issue-that-gs_start_io-crashed-due-to-accessing-null-pointer.patch +usb-dwc3-xilinx-make-sure-pipe-clock-is-deselected-in-usb2-only-mode.patch +drm-i915-fix-memory-leak-by-correcting-cache-object-name-in-error-handler.patch +xfs-update-btree-keys-correctly-when-_insrec-splits-an-inode-root-block.patch +xfs-don-t-drop-errno-values-when-we-fail-to-ficlone-the-entire-range.patch diff --git a/queue-6.1/usb-dwc3-xilinx-make-sure-pipe-clock-is-deselected-in-usb2-only-mode.patch b/queue-6.1/usb-dwc3-xilinx-make-sure-pipe-clock-is-deselected-in-usb2-only-mode.patch new file mode 100644 index 00000000000..c136eab3af4 --- /dev/null +++ b/queue-6.1/usb-dwc3-xilinx-make-sure-pipe-clock-is-deselected-in-usb2-only-mode.patch @@ -0,0 +1,44 @@ +From a48f744bef9ee74814a9eccb030b02223e48c76c Mon Sep 17 00:00:00 2001 +From: Neal Frager +Date: Mon, 2 Dec 2024 23:41:51 +0530 +Subject: usb: dwc3: xilinx: make sure pipe clock is deselected in usb2 only mode + +From: Neal Frager + +commit a48f744bef9ee74814a9eccb030b02223e48c76c upstream. + +When the USB3 PHY is not defined in the Linux device tree, there could +still be a case where there is a USB3 PHY active on the board and enabled +by the first stage bootloader. If serdes clock is being used then the USB +will fail to enumerate devices in 2.0 only mode. + +To solve this, make sure that the PIPE clock is deselected whenever the +USB3 PHY is not defined and guarantees that the USB2 only mode will work +in all cases. + +Fixes: 9678f3361afc ("usb: dwc3: xilinx: Skip resets and USB3 register settings for USB2.0 mode") +Cc: stable@vger.kernel.org +Signed-off-by: Neal Frager +Signed-off-by: Radhey Shyam Pandey +Acked-by: Peter Korsgaard +Link: https://lore.kernel.org/r/1733163111-1414816-1-git-send-email-radhey.shyam.pandey@amd.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/dwc3/dwc3-xilinx.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/drivers/usb/dwc3/dwc3-xilinx.c ++++ b/drivers/usb/dwc3/dwc3-xilinx.c +@@ -122,8 +122,11 @@ static int dwc3_xlnx_init_zynqmp(struct + * in use but the usb3-phy entry is missing from the device tree. + * Therefore, skip these operations in this case. + */ +- if (!priv_data->usb3_phy) ++ if (!priv_data->usb3_phy) { ++ /* Deselect the PIPE Clock Select bit in FPD PIPE Clock register */ ++ writel(PIPE_CLK_DESELECT, priv_data->regs + XLNX_USB_FPD_PIPE_CLK); + goto skip_usb3_phy; ++ } + + crst = devm_reset_control_get_exclusive(dev, "usb_crst"); + if (IS_ERR(crst)) { diff --git a/queue-6.1/usb-ehci-hcd-fix-call-balance-of-clocks-handling-routines.patch b/queue-6.1/usb-ehci-hcd-fix-call-balance-of-clocks-handling-routines.patch new file mode 100644 index 00000000000..e529108c6ff --- /dev/null +++ b/queue-6.1/usb-ehci-hcd-fix-call-balance-of-clocks-handling-routines.patch @@ -0,0 +1,52 @@ +From 97264eaaba0122a5b7e8ddd7bf4ff3ac57c2b170 Mon Sep 17 00:00:00 2001 +From: Vitalii Mordan +Date: Thu, 21 Nov 2024 14:47:00 +0300 +Subject: usb: ehci-hcd: fix call balance of clocks handling routines + +From: Vitalii Mordan + +commit 97264eaaba0122a5b7e8ddd7bf4ff3ac57c2b170 upstream. + +If the clocks priv->iclk and priv->fclk were not enabled in ehci_hcd_sh_probe, +they should not be disabled in any path. + +Conversely, if they was enabled in ehci_hcd_sh_probe, they must be disabled +in all error paths to ensure proper cleanup. + +Found by Linux Verification Center (linuxtesting.org) with Klever. + +Fixes: 63c845522263 ("usb: ehci-hcd: Add support for SuperH EHCI.") +Cc: stable@vger.kernel.org # ff30bd6a6618: sh: clk: Fix clk_enable() to return 0 on NULL clk +Signed-off-by: Vitalii Mordan +Reviewed-by: Alan Stern +Link: https://lore.kernel.org/r/20241121114700.2100520-1-mordan@ispras.ru +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/host/ehci-sh.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +--- a/drivers/usb/host/ehci-sh.c ++++ b/drivers/usb/host/ehci-sh.c +@@ -120,8 +120,12 @@ static int ehci_hcd_sh_probe(struct plat + if (IS_ERR(priv->iclk)) + priv->iclk = NULL; + +- clk_enable(priv->fclk); +- clk_enable(priv->iclk); ++ ret = clk_enable(priv->fclk); ++ if (ret) ++ goto fail_request_resource; ++ ret = clk_enable(priv->iclk); ++ if (ret) ++ goto fail_iclk; + + ret = usb_add_hcd(hcd, irq, IRQF_SHARED); + if (ret != 0) { +@@ -137,6 +141,7 @@ static int ehci_hcd_sh_probe(struct plat + + fail_add_hcd: + clk_disable(priv->iclk); ++fail_iclk: + clk_disable(priv->fclk); + + fail_request_resource: diff --git a/queue-6.1/usb-gadget-u_serial-fix-the-issue-that-gs_start_io-crashed-due-to-accessing-null-pointer.patch b/queue-6.1/usb-gadget-u_serial-fix-the-issue-that-gs_start_io-crashed-due-to-accessing-null-pointer.patch new file mode 100644 index 00000000000..8932a8e1b7d --- /dev/null +++ b/queue-6.1/usb-gadget-u_serial-fix-the-issue-that-gs_start_io-crashed-due-to-accessing-null-pointer.patch @@ -0,0 +1,81 @@ +From 4cfbca86f6a8b801f3254e0e3c8f2b1d2d64be2b Mon Sep 17 00:00:00 2001 +From: Lianqin Hu +Date: Tue, 3 Dec 2024 12:14:16 +0000 +Subject: usb: gadget: u_serial: Fix the issue that gs_start_io crashed due to accessing null pointer + +From: Lianqin Hu + +commit 4cfbca86f6a8b801f3254e0e3c8f2b1d2d64be2b upstream. + +Considering that in some extreme cases, +when u_serial driver is accessed by multiple threads, +Thread A is executing the open operation and calling the gs_open, +Thread B is executing the disconnect operation and calling the +gserial_disconnect function,The port->port_usb pointer will be set to NULL. + +E.g. + Thread A Thread B + gs_open() gadget_unbind_driver() + gs_start_io() composite_disconnect() + gs_start_rx() gserial_disconnect() + ... ... + spin_unlock(&port->port_lock) + status = usb_ep_queue() spin_lock(&port->port_lock) + spin_lock(&port->port_lock) port->port_usb = NULL + gs_free_requests(port->port_usb->in) spin_unlock(&port->port_lock) + Crash + +This causes thread A to access a null pointer (port->port_usb is null) +when calling the gs_free_requests function, causing a crash. + +If port_usb is NULL, the release request will be skipped as it +will be done by gserial_disconnect. + +So add a null pointer check to gs_start_io before attempting +to access the value of the pointer port->port_usb. + +Call trace: + gs_start_io+0x164/0x25c + gs_open+0x108/0x13c + tty_open+0x314/0x638 + chrdev_open+0x1b8/0x258 + do_dentry_open+0x2c4/0x700 + vfs_open+0x2c/0x3c + path_openat+0xa64/0xc60 + do_filp_open+0xb8/0x164 + do_sys_openat2+0x84/0xf0 + __arm64_sys_openat+0x70/0x9c + invoke_syscall+0x58/0x114 + el0_svc_common+0x80/0xe0 + do_el0_svc+0x1c/0x28 + el0_svc+0x38/0x68 + +Fixes: c1dca562be8a ("usb gadget: split out serial core") +Cc: stable@vger.kernel.org +Suggested-by: Prashanth K +Signed-off-by: Lianqin Hu +Acked-by: Prashanth K +Link: https://lore.kernel.org/r/TYUPR06MB62178DC3473F9E1A537DCD02D2362@TYUPR06MB6217.apcprd06.prod.outlook.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/gadget/function/u_serial.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +--- a/drivers/usb/gadget/function/u_serial.c ++++ b/drivers/usb/gadget/function/u_serial.c +@@ -570,9 +570,12 @@ static int gs_start_io(struct gs_port *p + * we didn't in gs_start_tx() */ + tty_wakeup(port->port.tty); + } else { +- gs_free_requests(ep, head, &port->read_allocated); +- gs_free_requests(port->port_usb->in, &port->write_pool, +- &port->write_allocated); ++ /* Free reqs only if we are still connected */ ++ if (port->port_usb) { ++ gs_free_requests(ep, head, &port->read_allocated); ++ gs_free_requests(port->port_usb->in, &port->write_pool, ++ &port->write_allocated); ++ } + status = -EIO; + } + diff --git a/queue-6.1/usb-typec-anx7411-fix-fwnode_handle-reference-leak.patch b/queue-6.1/usb-typec-anx7411-fix-fwnode_handle-reference-leak.patch new file mode 100644 index 00000000000..a3bff3ceac1 --- /dev/null +++ b/queue-6.1/usb-typec-anx7411-fix-fwnode_handle-reference-leak.patch @@ -0,0 +1,155 @@ +From 645d56e4cc74e953284809d096532c1955918a28 Mon Sep 17 00:00:00 2001 +From: Joe Hattori +Date: Thu, 21 Nov 2024 11:34:29 +0900 +Subject: usb: typec: anx7411: fix fwnode_handle reference leak + +From: Joe Hattori + +commit 645d56e4cc74e953284809d096532c1955918a28 upstream. + +An fwnode_handle and usb_role_switch are obtained with an incremented +refcount in anx7411_typec_port_probe(), however the refcounts are not +decremented in the error path. The fwnode_handle is also not decremented +in the .remove() function. Therefore, call fwnode_handle_put() and +usb_role_switch_put() accordingly. + +Fixes: fe6d8a9c8e64 ("usb: typec: anx7411: Add Analogix PD ANX7411 support") +Cc: stable@vger.kernel.org +Signed-off-by: Joe Hattori +Reviewed-by: Heikki Krogerus +Link: https://lore.kernel.org/r/20241121023429.962848-1-joe@pf.is.s.u-tokyo.ac.jp +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/typec/anx7411.c | 47 +++++++++++++++++++++++++++----------------- + 1 file changed, 29 insertions(+), 18 deletions(-) + +--- a/drivers/usb/typec/anx7411.c ++++ b/drivers/usb/typec/anx7411.c +@@ -1020,6 +1020,16 @@ static void anx7411_port_unregister_altm + } + } + ++static void anx7411_port_unregister(struct typec_params *typecp) ++{ ++ fwnode_handle_put(typecp->caps.fwnode); ++ anx7411_port_unregister_altmodes(typecp->port_amode); ++ if (typecp->port) ++ typec_unregister_port(typecp->port); ++ if (typecp->role_sw) ++ usb_role_switch_put(typecp->role_sw); ++} ++ + static int anx7411_usb_mux_set(struct typec_mux_dev *mux, + struct typec_mux_state *state) + { +@@ -1153,34 +1163,34 @@ static int anx7411_typec_port_probe(stru + ret = fwnode_property_read_string(fwnode, "power-role", &buf); + if (ret) { + dev_err(dev, "power-role not found: %d\n", ret); +- return ret; ++ goto put_fwnode; + } + + ret = typec_find_port_power_role(buf); + if (ret < 0) +- return ret; ++ goto put_fwnode; + cap->type = ret; + + ret = fwnode_property_read_string(fwnode, "data-role", &buf); + if (ret) { + dev_err(dev, "data-role not found: %d\n", ret); +- return ret; ++ goto put_fwnode; + } + + ret = typec_find_port_data_role(buf); + if (ret < 0) +- return ret; ++ goto put_fwnode; + cap->data = ret; + + ret = fwnode_property_read_string(fwnode, "try-power-role", &buf); + if (ret) { + dev_err(dev, "try-power-role not found: %d\n", ret); +- return ret; ++ goto put_fwnode; + } + + ret = typec_find_power_role(buf); + if (ret < 0) +- return ret; ++ goto put_fwnode; + cap->prefer_role = ret; + + /* Get source pdos */ +@@ -1192,7 +1202,7 @@ static int anx7411_typec_port_probe(stru + typecp->src_pdo_nr); + if (ret < 0) { + dev_err(dev, "source cap validate failed: %d\n", ret); +- return -EINVAL; ++ goto put_fwnode; + } + + typecp->caps_flags |= HAS_SOURCE_CAP; +@@ -1206,7 +1216,7 @@ static int anx7411_typec_port_probe(stru + typecp->sink_pdo_nr); + if (ret < 0) { + dev_err(dev, "sink cap validate failed: %d\n", ret); +- return -EINVAL; ++ goto put_fwnode; + } + + for (i = 0; i < typecp->sink_pdo_nr; i++) { +@@ -1250,13 +1260,21 @@ static int anx7411_typec_port_probe(stru + ret = PTR_ERR(ctx->typec.port); + ctx->typec.port = NULL; + dev_err(dev, "Failed to register type c port %d\n", ret); +- return ret; ++ goto put_usb_role_switch; + } + + typec_port_register_altmodes(ctx->typec.port, NULL, ctx, + ctx->typec.port_amode, + MAX_ALTMODE); + return 0; ++ ++put_usb_role_switch: ++ if (ctx->typec.role_sw) ++ usb_role_switch_put(ctx->typec.role_sw); ++put_fwnode: ++ fwnode_handle_put(fwnode); ++ ++ return ret; + } + + static int anx7411_typec_check_connection(struct anx7411_data *ctx) +@@ -1528,8 +1546,7 @@ free_wq: + destroy_workqueue(plat->workqueue); + + free_typec_port: +- typec_unregister_port(plat->typec.port); +- anx7411_port_unregister_altmodes(plat->typec.port_amode); ++ anx7411_port_unregister(&plat->typec); + + free_typec_switch: + anx7411_unregister_switch(plat); +@@ -1554,17 +1571,11 @@ static void anx7411_i2c_remove(struct i2 + if (plat->spi_client) + i2c_unregister_device(plat->spi_client); + +- if (plat->typec.role_sw) +- usb_role_switch_put(plat->typec.role_sw); +- + anx7411_unregister_mux(plat); + + anx7411_unregister_switch(plat); + +- if (plat->typec.port) +- typec_unregister_port(plat->typec.port); +- +- anx7411_port_unregister_altmodes(plat->typec.port_amode); ++ anx7411_port_unregister(&plat->typec); + } + + static const struct i2c_device_id anx7411_id[] = { diff --git a/queue-6.1/usb-typec-anx7411-fix-of-node-reference-leaks-in-anx7411_typec_switch_probe.patch b/queue-6.1/usb-typec-anx7411-fix-of-node-reference-leaks-in-anx7411_typec_switch_probe.patch new file mode 100644 index 00000000000..cea453fb308 --- /dev/null +++ b/queue-6.1/usb-typec-anx7411-fix-of-node-reference-leaks-in-anx7411_typec_switch_probe.patch @@ -0,0 +1,90 @@ +From ef42b906df5c57d0719b69419df9dfd25f25c161 Mon Sep 17 00:00:00 2001 +From: Joe Hattori +Date: Tue, 26 Nov 2024 10:49:09 +0900 +Subject: usb: typec: anx7411: fix OF node reference leaks in anx7411_typec_switch_probe() + +From: Joe Hattori + +commit ef42b906df5c57d0719b69419df9dfd25f25c161 upstream. + +The refcounts of the OF nodes obtained by of_get_child_by_name() calls +in anx7411_typec_switch_probe() are not decremented. Replace them with +device_get_named_child_node() calls and store the return values to the +newly created fwnode_handle fields in anx7411_data, and call +fwnode_handle_put() on them in the error path and in the unregister +functions. + +Fixes: e45d7337dc0e ("usb: typec: anx7411: Use of_get_child_by_name() instead of of_find_node_by_name()") +Cc: stable@vger.kernel.org +Signed-off-by: Joe Hattori +Reviewed-by: Heikki Krogerus +Link: https://lore.kernel.org/r/20241126014909.3687917-1-joe@pf.is.s.u-tokyo.ac.jp +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/typec/anx7411.c | 19 ++++++++++++------- + 1 file changed, 12 insertions(+), 7 deletions(-) + +--- a/drivers/usb/typec/anx7411.c ++++ b/drivers/usb/typec/anx7411.c +@@ -289,6 +289,8 @@ struct anx7411_data { + struct power_supply *psy; + struct power_supply_desc psy_desc; + struct device *dev; ++ struct fwnode_handle *switch_node; ++ struct fwnode_handle *mux_node; + }; + + static u8 snk_identity[] = { +@@ -1098,6 +1100,7 @@ static void anx7411_unregister_mux(struc + if (ctx->typec.typec_mux) { + typec_mux_unregister(ctx->typec.typec_mux); + ctx->typec.typec_mux = NULL; ++ fwnode_handle_put(ctx->mux_node); + } + } + +@@ -1106,6 +1109,7 @@ static void anx7411_unregister_switch(st + if (ctx->typec.typec_switch) { + typec_switch_unregister(ctx->typec.typec_switch); + ctx->typec.typec_switch = NULL; ++ fwnode_handle_put(ctx->switch_node); + } + } + +@@ -1113,28 +1117,29 @@ static int anx7411_typec_switch_probe(st + struct device *dev) + { + int ret; +- struct device_node *node; + +- node = of_get_child_by_name(dev->of_node, "orientation_switch"); +- if (!node) ++ ctx->switch_node = device_get_named_child_node(dev, "orientation_switch"); ++ if (!ctx->switch_node) + return 0; + +- ret = anx7411_register_switch(ctx, dev, &node->fwnode); ++ ret = anx7411_register_switch(ctx, dev, ctx->switch_node); + if (ret) { + dev_err(dev, "failed register switch"); ++ fwnode_handle_put(ctx->switch_node); + return ret; + } + +- node = of_get_child_by_name(dev->of_node, "mode_switch"); +- if (!node) { ++ ctx->mux_node = device_get_named_child_node(dev, "mode_switch"); ++ if (!ctx->mux_node) { + dev_err(dev, "no typec mux exist"); + ret = -ENODEV; + goto unregister_switch; + } + +- ret = anx7411_register_mux(ctx, dev, &node->fwnode); ++ ret = anx7411_register_mux(ctx, dev, ctx->mux_node); + if (ret) { + dev_err(dev, "failed register mode switch"); ++ fwnode_handle_put(ctx->mux_node); + ret = -ENODEV; + goto unregister_switch; + } diff --git a/queue-6.1/xfs-don-t-drop-errno-values-when-we-fail-to-ficlone-the-entire-range.patch b/queue-6.1/xfs-don-t-drop-errno-values-when-we-fail-to-ficlone-the-entire-range.patch new file mode 100644 index 00000000000..e49a934a485 --- /dev/null +++ b/queue-6.1/xfs-don-t-drop-errno-values-when-we-fail-to-ficlone-the-entire-range.patch @@ -0,0 +1,61 @@ +From 7ce31f20a0771d71779c3b0ec9cdf474cc3c8e9a Mon Sep 17 00:00:00 2001 +From: "Darrick J. Wong" +Date: Mon, 2 Dec 2024 10:57:27 -0800 +Subject: xfs: don't drop errno values when we fail to ficlone the entire range + +From: Darrick J. Wong + +commit 7ce31f20a0771d71779c3b0ec9cdf474cc3c8e9a upstream. + +Way back when we first implemented FICLONE for XFS, life was simple -- +either the the entire remapping completed, or something happened and we +had to return an errno explaining what happened. Neither of those +ioctls support returning partial results, so it's all or nothing. + +Then things got complicated when copy_file_range came along, because it +actually can return the number of bytes copied, so commit 3f68c1f562f1e4 +tried to make it so that we could return a partial result if the +REMAP_FILE_CAN_SHORTEN flag is set. This is also how FIDEDUPERANGE can +indicate that the kernel performed a partial deduplication. + +Unfortunately, the logic is wrong if an error stops the remapping and +CAN_SHORTEN is not set. Because those callers cannot return partial +results, it is an error for ->remap_file_range to return a positive +quantity that is less than the @len passed in. Implementations really +should be returning a negative errno in this case, because that's what +btrfs (which introduced FICLONE{,RANGE}) did. + +Therefore, ->remap_range implementations cannot silently drop an errno +that they might have when the number of bytes remapped is less than the +number of bytes requested and CAN_SHORTEN is not set. + +Found by running generic/562 on a 64k fsblock filesystem and wondering +why it reported corrupt files. + +Cc: # v4.20 +Fixes: 3fc9f5e409319e ("xfs: remove xfs_reflink_remap_range") +Really-Fixes: 3f68c1f562f1e4 ("xfs: support returning partial reflink results") +Signed-off-by: "Darrick J. Wong" +Reviewed-by: Christoph Hellwig +Signed-off-by: Greg Kroah-Hartman +--- + fs/xfs/xfs_file.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/fs/xfs/xfs_file.c ++++ b/fs/xfs/xfs_file.c +@@ -1161,6 +1161,14 @@ out_unlock: + xfs_iunlock2_io_mmap(src, dest); + if (ret) + trace_xfs_reflink_remap_range_error(dest, ret, _RET_IP_); ++ /* ++ * If the caller did not set CAN_SHORTEN, then it is not prepared to ++ * handle partial results -- either the whole remap succeeds, or we ++ * must say why it did not. In this case, any error should be returned ++ * to the caller. ++ */ ++ if (ret && remapped < len && !(remap_flags & REMAP_FILE_CAN_SHORTEN)) ++ return ret; + return remapped > 0 ? remapped : ret; + } + diff --git a/queue-6.1/xfs-update-btree-keys-correctly-when-_insrec-splits-an-inode-root-block.patch b/queue-6.1/xfs-update-btree-keys-correctly-when-_insrec-splits-an-inode-root-block.patch new file mode 100644 index 00000000000..3f81cc21c17 --- /dev/null +++ b/queue-6.1/xfs-update-btree-keys-correctly-when-_insrec-splits-an-inode-root-block.patch @@ -0,0 +1,79 @@ +From 6d7b4bc1c3e00b1a25b7a05141a64337b4629337 Mon Sep 17 00:00:00 2001 +From: "Darrick J. Wong" +Date: Mon, 2 Dec 2024 10:57:31 -0800 +Subject: xfs: update btree keys correctly when _insrec splits an inode root block + +From: Darrick J. Wong + +commit 6d7b4bc1c3e00b1a25b7a05141a64337b4629337 upstream. + +In commit 2c813ad66a72, I partially fixed a bug wherein xfs_btree_insrec +would erroneously try to update the parent's key for a block that had +been split if we decided to insert the new record into the new block. +The solution was to detect this situation and update the in-core key +value that we pass up to the caller so that the caller will (eventually) +add the new block to the parent level of the tree with the correct key. + +However, I missed a subtlety about the way inode-rooted btrees work. If +the full block was a maximally sized inode root block, we'll solve that +fullness by moving the root block's records to a new block, resizing the +root block, and updating the root to point to the new block. We don't +pass a pointer to the new block to the caller because that work has +already been done. The new record will /always/ land in the new block, +so in this case we need to use xfs_btree_update_keys to update the keys. + +This bug can theoretically manifest itself in the very rare case that we +split a bmbt root block and the new record lands in the very first slot +of the new block, though I've never managed to trigger it in practice. +However, it is very easy to reproduce by running generic/522 with the +realtime rmapbt patchset if rtinherit=1. + +Cc: # v4.8 +Fixes: 2c813ad66a7218 ("xfs: support btrees with overlapping intervals for keys") +Signed-off-by: "Darrick J. Wong" +Reviewed-by: Christoph Hellwig +Signed-off-by: Greg Kroah-Hartman +--- + fs/xfs/libxfs/xfs_btree.c | 29 +++++++++++++++++++++++------ + 1 file changed, 23 insertions(+), 6 deletions(-) + +--- a/fs/xfs/libxfs/xfs_btree.c ++++ b/fs/xfs/libxfs/xfs_btree.c +@@ -3430,14 +3430,31 @@ xfs_btree_insrec( + xfs_btree_log_block(cur, bp, XFS_BB_NUMRECS); + + /* +- * If we just inserted into a new tree block, we have to +- * recalculate nkey here because nkey is out of date. ++ * Update btree keys to reflect the newly added record or keyptr. ++ * There are three cases here to be aware of. Normally, all we have to ++ * do is walk towards the root, updating keys as necessary. + * +- * Otherwise we're just updating an existing block (having shoved +- * some records into the new tree block), so use the regular key +- * update mechanism. ++ * If the caller had us target a full block for the insertion, we dealt ++ * with that by calling the _make_block_unfull function. If the ++ * "make unfull" function splits the block, it'll hand us back the key ++ * and pointer of the new block. We haven't yet added the new block to ++ * the next level up, so if we decide to add the new record to the new ++ * block (bp->b_bn != old_bn), we have to update the caller's pointer ++ * so that the caller adds the new block with the correct key. ++ * ++ * However, there is a third possibility-- if the selected block is the ++ * root block of an inode-rooted btree and cannot be expanded further, ++ * the "make unfull" function moves the root block contents to a new ++ * block and updates the root block to point to the new block. In this ++ * case, no block pointer is passed back because the block has already ++ * been added to the btree. In this case, we need to use the regular ++ * key update function, just like the first case. This is critical for ++ * overlapping btrees, because the high key must be updated to reflect ++ * the entire tree, not just the subtree accessible through the first ++ * child of the root (which is now two levels down from the root). + */ +- if (bp && xfs_buf_daddr(bp) != old_bn) { ++ if (!xfs_btree_ptr_is_null(cur, &nptr) && ++ bp && xfs_buf_daddr(bp) != old_bn) { + xfs_btree_get_keys(cur, block, lkey); + } else if (xfs_btree_needs_key_update(cur, optr)) { + error = xfs_btree_update_keys(cur, level);