6.18.53-rc1 review
Subsystems (6)
Greg Kroah-Hartman
maintainerPATCH 1153/1250 i2c: smbus: reject oversized block transfers in the common path
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
commit 3051cd060fa496df42954291fa2306ed2eab4ecc upstream.
The SMBus block transfer length data->block[0] is validated in i2c_smbus_xfer_emulated() but that check runs too late for tracepoints and is skipped entirely when the adapter provides a native smbus_xfer implementation. This allows user-controlled oversized block lengths to reach tracepoint memcpy calls and driver callbacks unchecked.
Add an early validation in __i2c_smbus_xfer() that rejects block transfers whose caller-supplied length is zero or exceeds I2C_SMBUS_BLOCK_MAX before any tracepoint fires or driver callback runs. data->block[0] is filled in by the device on SMBus block reads, so the check is scoped to operations where the length is actually supplied by the caller. This is consistent with the existing -EINVAL convention in the emulated path and protects all downstream consumers at once: the smbus_write tracepoint, all native smbus_xfer driver implementations, and the emulated path.
Two distinct bugs are fixed by this change:
Bug 1: smbus_write tracepoint OOB (include/trace/events/smbus.h)
trace_smbus_write() fires before any validation and copies data->block[0]+1 bytes into a 34-byte event buffer. With block[0]=0xfe the tracepoint copies 255 bytes, overflowing by 221.
BUG: KASAN: stack-out-of-bounds in trace_event_raw_event_smbus_write+0x27c/0x530 Read of size 255 at addr ffff88800d98fcf8 by task poc_smbus/91 Call Trace: <TASK> __asan_memcpy+0x23/0x80 trace_event_raw_event_smbus_write+0x27c/0x530 __i2c_smbus_xfer+0x43a/0xa40 i2c_smbus_xfer+0x19e/0x340 i2cdev_ioctl_smbus+0x38f/0x7f0 i2cdev_ioctl+0x35e/0x680 __x64_sys_ioctl+0x147/0x1e0 do_syscall_64+0xcf/0x15a0 entry_SYSCALL_64_after_hwframe+0x76/0x7e </TASK>
Bug 2: i2c-stub I2C_SMBUS_I2C_BLOCK_DATA OOB (drivers/i2c/i2c-stub.c)
stub_xfer() implements .smbus_xfer directly and only clamps block[0] against 256-command, not I2C_SMBUS_BLOCK_MAX. With block[0]=0xff and command=0 the loop accesses block[1+i] for i up to 254, far past the 34-byte union.
UBSAN: array-index-out-of-bounds in drivers/i2c/i2c-stub.c:223:44 index 34 is out of range for type '__u8 [34]' Call Trace: <TASK> __ubsan_handle_out_of_bounds+0xd7/0x120 stub_xfer+0x1971/0x198f [i2c_stub] __i2c_smbus_xfer+0x306/0xa40 i2c_smbus_xfer+0x19e/0x340 i2cdev_ioctl_smbus+0x38f/0x7f0 i2cdev_ioctl+0x35e/0x680 __x64_sys_ioctl+0x147/0x1e0 do_syscall_64+0xcf/0x15a0 entry_SYSCALL_64_after_hwframe+0x76/0x7e </TASK>
Both traces reproduced on v7.0-rc6+i2c/for-current with KASAN+UBSAN.
--- drivers/i2c/i2c-core-smbus.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
drivers/i2c/i2c-core-smbus.c +12 -0
@@ -566,6 +566,18 @@ s32 __i2c_smbus_xfer(struct i2c_adapterif (res)return res; +/* Reject invalid caller-supplied block lengths before any +* tracepoint or native smbus_xfer callback runs. +*/ +if (data && + (protocol ==I2C_SMBUS_I2C_BLOCK_DATA || + protocol ==I2C_SMBUS_BLOCK_PROC_CALL || + (protocol ==I2C_SMBUS_BLOCK_DATA && + read_write ==I2C_SMBUS_WRITE )) && + (data->block[0 ] ==0 || + data->block[0 ] >I2C_SMBUS_BLOCK_MAX )) +return -EINVAL ; +/* If enabled, the following two tracepoints are conditional on * read_write and protocol. */
Greg Kroah-Hartman
maintainerPATCH 1154/1250 net: appletalk: fix NULL pointer dereference in aarp_send_ddp()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
commit 9e7f36ab5b7bf68463faa5f7b926fea8f35597bb upstream.
aarp_send_ddp() calls atalk_find_dev_addr(dev) in the LocalTalk fast path without checking for NULL. When the device has no AppleTalk interface configured (dev->atalk_ptr == NULL), this leads to a NULL pointer dereference at the at->s_net access.
KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] RIP: 0010:aarp_send_ddp (net/appletalk/aarp.c:552 (discriminator 2)) Call Trace: <TASK> atalk_sendmsg (net/appletalk/ddp.c:1715) __sys_sendto (net/socket.c:2265 (discriminator 1)) __x64_sys_sendto (net/socket.c:2272) do_syscall_64 (arch/x86/entry/syscall_64.c:94) entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
Add a NULL check consistent with the other callers of atalk_find_dev_addr().
--- net/appletalk/aarp.c | 5 +++++ 1 file changed, 5 insertions(+)
net/appletalk/aarp.c +5 -0
@@ -542,6 +542,11 @@ int aarp_send_ddp(struct net_device *devstruct ddpehdr *ddp = (struct ddpehdr *)skb->data;int ft =2 ; +if (!at) { +kfree_skb (skb); +return NET_XMIT_DROP ; + } +/* * Compressible ? *
Greg Kroah-Hartman
maintainerPATCH 1155/1250 media: chips-media: wave5: Add timeout while stop_streaming
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jackson Lee <[email protected]>
[ Upstream commit 2ae7faed2e60d6d07d9efdd962d20dcb15330ced ]
When stop_streaming is called, an infinite loop may occur in some cases. Add a bounded poll of the queue status: loop until the queues drain, sleeping briefly between polls, and bail out once VPU_DEC_STOP_TIMEOUT elapses.
--- drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c | 12 ++++++------ drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h | 1 + 2 files changed, 7 insertions(+), 6 deletions(-)
drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c +6 -6
@@ -5,6 +5,7 @@* Copyright (C) 2021-2023 CHIPS&MEDIA INC */ +#include <linux/delay.h> #include <linux/pm_runtime.h> #include "wave5-helper.h"
@@ -1490,25 +1491,24 @@ static void wave5_vpu_dec_stop_streaming {struct vpu_instance *inst =vb2_get_drv_priv (q);struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; -bool check_cmd = TRUE; +unsigned long timeout;dev_dbg (inst->dev->dev,"%s: type: %u\n" , __func__, q->type);pm_runtime_resume_and_get (inst->dev->dev); -while (check_cmd) { + timeout = jiffies +msecs_to_jiffies (VPU_DEC_STOP_TIMEOUT ); +while (true) {struct queue_status_info q_status; -struct dec_output_info dec_output_info;wave5_vpu_dec_give_command (inst,DEC_GET_QUEUE_STATUS , &q_status);if (q_status.report_queue_count ==0 )break ; -if (wave5_vpu_wait_interrupt (inst,VPU_DEC_TIMEOUT ) <0 ) +if (time_after (jiffies, timeout))break ; -if (wave5_vpu_dec_get_output_info (inst, &dec_output_info)) -dev_dbg (inst->dev->dev,"there is no output info\n" ); +usleep_range (1000 ,2000 ); }v4l2_m2m_update_stop_streaming_state (m2m_ctx, q);
drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h +1 -0
@@ -59,6 +59,7 @@// application specific configuration #define VPU_ENC_TIMEOUT 60000#define VPU_DEC_TIMEOUT 60000 +#define VPU_DEC_STOP_TIMEOUT 300// for WAVE encoder #define USE_SRC_PRP_AXI 0
Greg Kroah-Hartman
maintainerPATCH 1156/1250 scsi: qla2xxx: Zero dport diagnostics buffer to avoid info leak
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
[ Upstream commit a152edab3854f01dd2daf3eaf8f32cbabdb3834e ]
qla2x00_do_dport_diagnostics() allocates the qla_dport_diag response buffer with kmalloc_obj() (non-zeroing) and, on success, copies the full sizeof(*dd) back to user space via sg_copy_from_buffer(). The inbound sg_copy_to_buffer() only fills as many bytes as the user request payload provides, and qla26xx_dport_diagnostics() zeroes only dd->buf. The options and unused[] fields are therefore copied out uninitialized, leaking kernel heap contents to user space.
Allocate with kzalloc_obj(), matching qla2x00_do_dport_diagnostics_v2().
--- drivers/scsi/qla2xxx/qla_bsg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/scsi/qla2xxx/qla_bsg.c +1 -1
@@ -2412,7 +2412,7 @@ qla2x00_do_dport_diagnostics(struct bsg_ !IS_QLA28XX(vha->hw))return -EPERM ; - dd =kmalloc (sizeof (*dd),GFP_KERNEL ); + dd =kzalloc (sizeof (*dd),GFP_KERNEL );if (!dd) {ql_log (ql_log_warn, vha,0x70db ,"Failed to allocate memory for dport.\n" );
Greg Kroah-Hartman
maintainerPATCH 1157/1250 media: iris: turn platform data into constants
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Baryshkov <[email protected]>
[ Upstream commit 7a02a8b98419c992faf8ab714cf4df7da99b2c46 ]
Make all struct iris_platform_data instances constant, they are not modified at runtime.
Stable-dep-of: f87d7eda07fc ("media: qcom: iris: fix runtime PM reference leaks")
--- drivers/media/platform/qcom/iris/iris_platform_common.h | 10 +++++----- drivers/media/platform/qcom/iris/iris_platform_gen2.c | 8 ++++---- drivers/media/platform/qcom/iris/iris_platform_sm8250.c | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-)
drivers/media/platform/qcom/iris/iris_platform_common.h +5 -5
@@ -41,11 +41,11 @@ enum pipe_type { PIPE_4 = 4, }; -extern struct iris_platform_data qcs8300_data; -extern struct iris_platform_data sm8250_data; -extern struct iris_platform_data sm8550_data; -extern struct iris_platform_data sm8650_data; -extern struct iris_platform_data sm8750_data; +extern const struct iris_platform_data qcs8300_data; +extern const struct iris_platform_data sm8250_data; +extern const struct iris_platform_data sm8550_data; +extern const struct iris_platform_data sm8650_data; +extern const struct iris_platform_data sm8750_data;enum platform_clk_type {IRIS_AXI_CLK ,/* AXI0 in case of platforms with multiple AXI clocks */
drivers/media/platform/qcom/iris/iris_platform_gen2.c +4 -4
@@ -737,7 +737,7 @@ static const u32 sm8550_enc_op_int_buf_t BUF_SCRATCH_2, }; -struct iris_platform_data sm8550_data = { +const struct iris_platform_data sm8550_data = { .get_instance = iris_hfi_gen2_get_instance, .init_hfi_command_ops = iris_hfi_gen2_command_ops_init, .init_hfi_response_ops = iris_hfi_gen2_response_ops_init,
@@ -827,7 +827,7 @@ struct iris_platform_data sm8550_data =* - controller_rst_tbl to sm8650_controller_reset_table * - fwname to "qcom/vpu/vpu33_p4.mbn" */ -struct iris_platform_data sm8650_data = { +const struct iris_platform_data sm8650_data = { .get_instance = iris_hfi_gen2_get_instance, .init_hfi_command_ops = iris_hfi_gen2_command_ops_init, .init_hfi_response_ops = iris_hfi_gen2_response_ops_init,
@@ -912,7 +912,7 @@ struct iris_platform_data sm8650_data = .enc_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_op_int_buf_tbl), }; -struct iris_platform_data sm8750_data = { +const struct iris_platform_data sm8750_data = { .get_instance = iris_hfi_gen2_get_instance, .init_hfi_command_ops = iris_hfi_gen2_command_ops_init, .init_hfi_response_ops = iris_hfi_gen2_response_ops_init,
@@ -1000,7 +1000,7 @@ struct iris_platform_data sm8750_data =* - inst_caps to platform_inst_cap_qcs8300 * - inst_fw_caps to inst_fw_cap_qcs8300 */ -struct iris_platform_data qcs8300_data = { +const struct iris_platform_data qcs8300_data = { .get_instance = iris_hfi_gen2_get_instance, .init_hfi_command_ops = iris_hfi_gen2_command_ops_init, .init_hfi_response_ops = iris_hfi_gen2_response_ops_init,
drivers/media/platform/qcom/iris/iris_platform_sm8250.c +1 -1
@@ -314,7 +314,7 @@ static const u32 sm8250_enc_ip_int_buf_t BUF_SCRATCH_2, }; -struct iris_platform_data sm8250_data = { +const struct iris_platform_data sm8250_data = { .get_instance = iris_hfi_gen1_get_instance, .init_hfi_command_ops = &iris_hfi_gen1_command_ops_init, .init_hfi_response_ops = iris_hfi_gen1_response_ops_init,
Greg Kroah-Hartman
maintainerPATCH 1158/1250 media: remove conditional return with no effect
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sang-Heon Jeon <[email protected]>
[ Upstream commit 9508676ad8562368bb1aa7d1991fbd50611ddacb ]
Both branches of the check return the same value, so the check has no effect. Remove it and return the value directly.
This is the result of running the Coccinelle script from scripts/coccinelle/misc/cond_return_no_effect.cocci.
Stable-dep-of: f87d7eda07fc ("media: qcom: iris: fix runtime PM reference leaks")
--- drivers/media/i2c/mt9p031.c | 6 +----- drivers/media/platform/microchip/microchip-sama7g5-isc.c | 7 +------ drivers/media/platform/qcom/iris/iris_resources.c | 6 +----- drivers/media/platform/qcom/venus/pm_helpers.c | 7 +------ drivers/media/platform/renesas/rcar-csi2.c | 6 +----- drivers/media/platform/samsung/s3c-camif/camif-core.c | 7 +------ drivers/media/usb/dvb-usb-v2/mxl111sf.c | 12 ++---------- drivers/media/usb/gspca/jl2005bcd.c | 7 +------ 8 files changed, 9 insertions(+), 49 deletions(-)
drivers/media/i2c/mt9p031.c +1 -5
@@ -453,11 +453,7 @@ static int mt9p031_set_params(struct mt9 ret =mt9p031_write (client,MT9P031_HORIZONTAL_BLANK , hblank -1 );if (ret <0 )return ret; - ret =mt9p031_write (client,MT9P031_VERTICAL_BLANK , vblank -1 ); -if (ret <0 ) -return ret; - -return ret; +return mt9p031_write (client,MT9P031_VERTICAL_BLANK , vblank -1 ); }static int mt9p031_s_stream (struct v4l2_subdev *subdev,int enable)
drivers/media/platform/microchip/microchip-sama7g5-isc.c +1 -6
@@ -598,13 +598,8 @@ static int __maybe_unused xisc_runtime_sstatic int __maybe_unused xisc_runtime_resume (struct device *dev) {struct isc_device *isc =dev_get_drvdata (dev); -int ret; - ret =clk_prepare_enable (isc->hclock); -if (ret) -return ret; - -return ret; +return clk_prepare_enable (isc->hclock); }static const struct dev_pm_ops microchip_xisc_dev_pm_ops = {
drivers/media/platform/qcom/iris/iris_resources.c +1 -5
@@ -66,11 +66,7 @@ int iris_enable_power_domains(struct iriif (ret)return ret; - ret =pm_runtime_get_sync (pd_dev); -if (ret <0 ) -return ret; - -return ret; +return pm_runtime_get_sync (pd_dev); }int iris_disable_power_domains (struct iris_core *core,struct device *pd_dev)
drivers/media/platform/qcom/venus/pm_helpers.c +1 -6
@@ -645,7 +645,6 @@ static int decide_core(struct venus_instunsigned long max_freq =ULONG_MAX ;struct device *dev = core->dev;struct dev_pm_opp *opp; -int ret =0 ;if (legacy_binding) {if (inst->session_type ==VIDC_SESSION_TYPE_DEC )
@@ -693,11 +692,7 @@ static int decide_core(struct venus_inst } done: - ret =hfi_session_set_property (inst, ptype, &cu); -if (ret) -return ret; - -return ret; +return hfi_session_set_property (inst, ptype, &cu); }static int acquire_core (struct venus_inst *inst)
drivers/media/platform/renesas/rcar-csi2.c +1 -5
@@ -2265,11 +2265,7 @@ static int rcsi2_init_phtw_v3u(struct rcreturn ret; } - ret =rcsi2_phtw_write_array (priv, step4,ARRAY_SIZE (step4)); -if (ret) -return ret; - -return ret; +return rcsi2_phtw_write_array (priv, step4,ARRAY_SIZE (step4)); }/* -----------------------------------------------------------------------------
drivers/media/platform/samsung/s3c-camif/camif-core.c +1 -6
@@ -302,7 +302,6 @@ static int camif_media_dev_init(struct cstruct media_device *md = &camif->media_dev;struct v4l2_device *v4l2_dev = &camif->v4l2_dev;unsigned int ip_rev = camif->variant->ip_revision; -int ret;memset (md,0 ,sizeof (*md)); snprintf(md->model, sizeof(md->model), "Samsung S3C%s CAMIF",
@@ -317,11 +316,7 @@ static int camif_media_dev_init(struct cmedia_device_init (md); - ret =v4l2_device_register (camif->dev, v4l2_dev); -if (ret <0 ) -return ret; - -return ret; +return v4l2_device_register (camif->dev, v4l2_dev); }static void camif_clk_put (struct camif_dev *camif)
drivers/media/usb/dvb-usb-v2/mxl111sf.c +2 -10
@@ -987,11 +987,7 @@ static int mxl111sf_frontend_attach_atscif (ret <0 )return ret; - ret =mxl111sf_lg2160_frontend_attach (adap,2 ); -if (ret <0 ) -return ret; - -return ret; +return mxl111sf_lg2160_frontend_attach (adap,2 ); }static int mxl111sf_frontend_attach_mercury (struct dvb_usb_adapter *adap)
@@ -1007,11 +1003,7 @@ static int mxl111sf_frontend_attach_mercif (ret <0 )return ret; - ret =mxl111sf_lg2161_ep6_frontend_attach (adap,2 ); -if (ret <0 ) -return ret; - -return ret; +return mxl111sf_lg2161_ep6_frontend_attach (adap,2 ); }static int mxl111sf_frontend_attach_mercury_mh (struct dvb_usb_adapter *adap)
drivers/media/usb/gspca/jl2005bcd.c +1 -6
@@ -148,17 +148,12 @@ static int jl2005c_start_new_frame(strucstatic int jl2005c_write_reg (struct gspca_dev *gspca_dev,unsigned char reg,unsigned char value) { -int retval;u8 instruction[2 ]; instruction[0 ] = reg; instruction[1 ] = value; - retval =jl2005c_write2 (gspca_dev, instruction); -if (retval <0 ) -return retval; - -return retval; +return jl2005c_write2 (gspca_dev, instruction); }static int jl2005c_get_firmware_id (struct gspca_dev *gspca_dev)
Greg Kroah-Hartman
maintainerPATCH 1159/1250 media: qcom: iris: fix runtime PM reference leaks
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hungyu Lin <[email protected]>
[ Upstream commit f87d7eda07fca21efe4b96169ae59007db46e60e ]
Use pm_runtime_resume_and_get() in iris_enable_power_domains() to avoid leaking a runtime PM usage count on failure.
Also ensure pm_runtime_put_sync() is always called in iris_disable_power_domains(), even when iris_opp_set_rate() fails, so runtime PM references remain balanced.
--- drivers/media/platform/qcom/iris/iris_resources.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
drivers/media/platform/qcom/iris/iris_resources.c +6 -5
@@ -66,20 +66,21 @@ int iris_enable_power_domains(struct iriif (ret)return ret; -return pm_runtime_get_sync (pd_dev); +return pm_runtime_resume_and_get (pd_dev); }int iris_disable_power_domains (struct iris_core *core,struct device *pd_dev) {int ret; +int pm_ret; ret =dev_pm_opp_set_rate (core->dev,0 ); -if (ret) -return ret; -pm_runtime_put_sync (pd_dev); + pm_ret =pm_runtime_put_sync (pd_dev); +if (!ret) + ret = pm_ret; -return 0 ; +return ret; }static struct clk *iris_get_clk_by_type (struct iris_core *core,enum platform_clk_type clk_type)
Greg Kroah-Hartman
maintainerPATCH 1160/1250 scsi: qla2xxx: Null out freed pointers in qla2x00_mem_alloc() error path
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
[ Upstream commit 6d90f0feb929f6c0f3010f9af4747c7230b75993 ]
When qla2x00_mem_alloc() fails, qla2x00_probe_one() jumps to probe_hw_failed and calls qla2x00_mem_free(). Several error labels in qla2x00_mem_alloc() freed adapter members (elsrej.c, purex_dma_pool, flt, sfp_data, loop_id_map, async_pd, sf_init_cb, ex_init_cb, npiv_info) but left the pointers dangling. qla2x00_mem_free() then freed them a second time. Worse, for the dma_pool members it issued dma_pool_free(ha->s_dma_pool, ...) after s_dma_pool had already been destroyed and set to NULL at fail_s_dma_pool, dereferencing a NULL pool.
Clear each freed pointer (and its DMA handle) in the error labels so the subsequent qla2x00_mem_free() skips them.
--- drivers/scsi/qla2xxx/qla_os.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
drivers/scsi/qla2xxx/qla_os.c +15 -0
@@ -4486,25 +4486,40 @@ qla2x00_mem_alloc(struct qla_hw_data *ha fail_lsrjt:dma_free_coherent (&ha->pdev->dev, ha->elsrej.size, ha->elsrej.c, ha->elsrej.cdma); + ha->elsrej.c =NULL ; + ha->elsrej.cdma =0 ; fail_elsrej:dma_pool_destroy (ha->purex_dma_pool); + ha->purex_dma_pool =NULL ; fail_flt:dma_free_coherent (&ha->pdev->dev,sizeof (struct qla_flt_header ) +FLT_REGIONS_SIZE , ha->flt, ha->flt_dma); + ha->flt =NULL ; + ha->flt_dma =0 ; fail_flt_buffer:dma_free_coherent (&ha->pdev->dev,SFP_DEV_SIZE , ha->sfp_data, ha->sfp_data_dma); + ha->sfp_data =NULL ; + ha->sfp_data_dma =0 ; fail_sfp_data:kfree (ha->loop_id_map); + ha->loop_id_map =NULL ; fail_loop_id_map:dma_pool_free (ha->s_dma_pool, ha->async_pd, ha->async_pd_dma); + ha->async_pd =NULL ; + ha->async_pd_dma =0 ; fail_async_pd:dma_pool_free (ha->s_dma_pool, ha->sf_init_cb, ha->sf_init_cb_dma); + ha->sf_init_cb =NULL ; + ha->sf_init_cb_dma =0 ; fail_sf_init_cb:dma_pool_free (ha->s_dma_pool, ha->ex_init_cb, ha->ex_init_cb_dma); + ha->ex_init_cb =NULL ; + ha->ex_init_cb_dma =0 ; fail_ex_init_cb:kfree (ha->npiv_info); + ha->npiv_info =NULL ; fail_npiv_info:dma_free_coherent (&ha->pdev->dev, ((*rsp)->length +1 ) *sizeof (response_t), (*rsp)->ring, (*rsp)->dma);
Greg Kroah-Hartman
maintainerPATCH 1161/1250 scsi: qla2xxx: Fix queue teardown NULL dma_free and bitmap locking
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
[ Upstream commit 34a40e0dff940ac5eba494a69b553ea571e24873 ]
qla25xx_free_req_que() and qla25xx_free_rsp_que() have two pre-existing bugs exposed on the error path of qla25xx_create_{req,rsp}_que():
1. When dma_alloc_coherent() fails during queue creation, the error path calls the free function with req->ring / rsp->ring still NULL (from kzalloc). The unconditional dma_free_coherent() with a NULL cpu_addr is undefined behavior and can panic.
2. The free functions clear req_qid_map / rsp_qid_map under vport_lock, but the create functions protect the same bitmaps with mq_lock. This provides no mutual exclusion. Additionally, the create error path clears the bit and releases mq_lock before calling the free function, creating a window where another thread can allocate the same que_id and have its ha->req_q_map entry clobbered by the subsequent lockless NULL assignment in the free function.
Fix by:
- Guarding dma_free_coherent() with a NULL check on the ring pointer.
- Using mq_lock (the lock held by all creators) in the free functions to atomically NULL the map entry and clear the bitmap bit.
- Removing the now-redundant clear_bit blocks from the create error paths since the free functions handle it atomically.
Backport adaptation for the stable tree: the 29xx IOCB size-selection helpers are absent, and queue creation still allocates fixed-size entries. Initialize the local req_entry_size and rsp_entry_size values with sizeof(request_t) and sizeof(response_t), respectively, so DMA freeing continues to match allocation without adding helper functions or 29xx support. Retain all NULL-ring guards, mq_lock protection, and removal of the premature bitmap clears.
Keep the response-ring cleanup layout used by upstream so target commit 19788a55cab61d78e33e0914a5a31d27843e8a4a applies unchanged.
Stable-dep-of: 19788a55cab6 ("scsi: qla2xxx: Fix use-after-free of qpair work on queue teardown")
--- drivers/scsi/qla2xxx/qla_mid.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-)
drivers/scsi/qla2xxx/qla_mid.c +15 -14
@@ -574,16 +574,19 @@ qla25xx_free_req_que(struct scsi_qla_hos {struct qla_hw_data *ha = vha->hw;uint16_t que_id = req->id; +size_t req_entry_size =sizeof (request_t); -dma_free_coherent (&ha->pdev->dev, (req->length +1 ) * -sizeof (request_t), req->ring, req->dma); +if (req->ring) +dma_free_coherent (&ha->pdev->dev, + (req->length +1 ) * req_entry_size, + req->ring, req->dma); req->ring =NULL ; req->dma =0 ;if (que_id) { +mutex_lock (&ha->mq_lock); ha->req_q_map[que_id] =NULL ; -mutex_lock (&ha->vport_lock);clear_bit (que_id, ha->req_qid_map); -mutex_unlock (&ha->vport_lock); +mutex_unlock (&ha->mq_lock); }kfree (req->outstanding_cmds);kfree (req);
@@ -594,6 +597,7 @@ qla25xx_free_rsp_que(struct scsi_qla_hos {struct qla_hw_data *ha = vha->hw;uint16_t que_id = rsp->id; +size_t rsp_entry_size =sizeof (response_t);if (rsp->msix && rsp->msix->have_irq) {free_irq (rsp->msix->vector, rsp->msix->handle);
@@ -601,15 +605,18 @@ qla25xx_free_rsp_que(struct scsi_qla_hos rsp->msix->in_use =0 ; rsp->msix->handle =NULL ; } -dma_free_coherent (&ha->pdev->dev, (rsp->length +1 ) * -sizeof (response_t), rsp->ring, rsp->dma); + +if (rsp->ring) +dma_free_coherent (&ha->pdev->dev, + (rsp->length +1 ) * rsp_entry_size, + rsp->ring, rsp->dma); rsp->ring =NULL ; rsp->dma =0 ;if (que_id) { +mutex_lock (&ha->mq_lock); ha->rsp_q_map[que_id] =NULL ; -mutex_lock (&ha->vport_lock);clear_bit (que_id, ha->rsp_qid_map); -mutex_unlock (&ha->vport_lock); +mutex_unlock (&ha->mq_lock); }kfree (rsp); }
@@ -794,9 +801,6 @@ qla25xx_create_req_que(struct qla_hw_datif (ret !=QLA_SUCCESS ) {ql_log (ql_log_fatal, base_vha,0x00df ,"%s failed.\n" , __func__); -mutex_lock (&ha->mq_lock); -clear_bit (que_id, ha->req_qid_map); -mutex_unlock (&ha->mq_lock); goto que_failed; } vha->flags.qpairs_req_created =1 ;
@@ -908,9 +912,6 @@ qla25xx_create_rsp_que(struct qla_hw_datif (ret !=QLA_SUCCESS ) {ql_log (ql_log_fatal, base_vha,0x00e7 ,"%s failed.\n" , __func__); -mutex_lock (&ha->mq_lock); -clear_bit (que_id, ha->rsp_qid_map); -mutex_unlock (&ha->mq_lock); goto que_failed; } vha->flags.qpairs_rsp_created =1 ;
Greg Kroah-Hartman
maintainerPATCH 1162/1250 scsi: qla2xxx: Fix use-after-free of qpair work on queue teardown
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
[ Upstream commit 19788a55cab61d78e33e0914a5a31d27843e8a4a ]
The response queue MSI-X handler qla2xxx_msix_rsp_q() schedules qla_do_work() via queue_work(ha->wq, &qpair->q_work). qla_do_work() dereferences the qpair (vha, rsp) and takes qpair->qp_lock.
During teardown, qla2xxx_delete_qpair() deletes the response queue, which calls free_irq() in qla25xx_free_rsp_que(), and then frees the queue and the qpair. free_irq() waits for running hardirq handlers but does not cancel work already placed on ha->wq. A still-pending q_work then runs qla_do_work() against the freed qpair and response queue, causing a use-after-free. This is especially likely during full adapter teardown, where destroy_workqueue(ha->wq) forces pending work to run after the queue pairs have been freed.
Flush the work item with cancel_work_sync() in qla25xx_free_rsp_que() after free_irq() has released the interrupt (so no new work can be queued) and before the response queue and qpair memory are freed (so the flushed handler still sees valid memory). Guard on rsp->qpair and ha->wq to match the INIT_WORK() condition and avoid operating on an uninitialized work_struct.
--- drivers/scsi/qla2xxx/qla_mid.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/scsi/qla2xxx/qla_mid.c +4 -0
@@ -606,6 +606,10 @@ qla25xx_free_rsp_que(struct scsi_qla_hos rsp->msix->handle =NULL ; } +/* Flush any queued response work before freeing the queue/qpair. */ +if (rsp->qpair && ha->wq) +cancel_work_sync (&rsp->qpair->q_work); +if (rsp->ring) dma_free_coherent(&ha->pdev->dev, (rsp->length + 1) * rsp_entry_size,
Greg Kroah-Hartman
maintainerPATCH 1163/1250 scsi: qla2xxx: Bound VP index against VP_CTRL IOCB bitmap size
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
[ Upstream commit 878613ecb5a36db26859c4fd83daf9283a334fa2 ]
The VP control IOCB selects its target virtual port by setting one bit in vp_idx_map, a fixed 16-byte (128-bit) array in both vp_ctrl_entry_24xx and vp_ctrl_entry_24xx_ext. qla25xx_ctrlvp_iocb() computes map = (vp_index - 1) / 8 and writes vce->vp_idx_map[map] without checking that map stays within the array.
max_npiv_vports is taken from firmware and only sanitized to a MIN_MULTI_ID_FABRIC-aligned boundary, so it can legitimately be 191 or 255, and qla24xx_control_vp() only rejects vp_index >= max_npiv_vports. A vp_index above 128 therefore yields map >= 16 and an out-of-bounds write of up to 16 bytes past vp_idx_map, corrupting the trailing IOCB fields (or the adjacent request-ring slot on the 64-byte layout).
Reject a vp_index that cannot be represented in the IOCB bitmap in qla24xx_control_vp(), and add a defensive ARRAY_SIZE() guard in qla25xx_ctrlvp_iocb() before the write. Adapters that report the usual 63 or 127 NPIV vports are unaffected.
--- drivers/scsi/qla2xxx/qla_iocb.c | 6 ++++++ drivers/scsi/qla2xxx/qla_mid.c | 8 ++++++++ 2 files changed, 14 insertions(+)
drivers/scsi/qla2xxx/qla_iocb.c +6 -0
@@ -3828,6 +3828,12 @@ qla25xx_ctrlvp_iocb(srb_t *sp, struct vp*/ map = (sp->u.iocb_cmd.u.ctrlvp.vp_index -1 ) /8 ; pos = (sp->u.iocb_cmd.u.ctrlvp.vp_index -1 ) &7 ; +if (map >=ARRAY_SIZE (vce->vp_idx_map)) { +ql_log (ql_log_warn, sp->vha,0x307c , +"ctrlvp: vp_index %u exceeds vp_idx_map capacity\n" , + sp->u.iocb_cmd.u.ctrlvp.vp_index); +return ; + } vce->vp_idx_map[map] |=1 << pos; }
drivers/scsi/qla2xxx/qla_mid.c +8 -0
@@ -962,6 +962,14 @@ int qla24xx_control_vp(scsi_qla_host_t *if (vp_index ==0 || vp_index >= ha->max_npiv_vports)return QLA_PARAMETER_ERROR ; +/* +* The VP_CTRL IOCB selects the target VP through a fixed 128-bit +* (16-byte) vp_idx_map bitmap, so vp_index must fit within it even +* if firmware advertises more NPIV vports. +*/ + if (vp_index > sizeof_field(struct vp_ctrl_entry_24xx, vp_idx_map) * 8) +return QLA_PARAMETER_ERROR ; +/* ref: INIT */ sp =qla2x00_get_sp (base_vha,NULL ,GFP_KERNEL );if (!sp)
Greg Kroah-Hartman
maintainerPATCH 1164/1250 scsi: qla2xxx: Fix 64G link speed reporting in get_data_rate
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
[ Upstream commit 52fba32317ee631faa878725b2f7cd5c08acacd3 ]
qla2x00_get_data_rate() skips updating ha->link_data_rate when the firmware returns mcp->mb[1] == 0x7. That value was a legacy sentinel from before 64G hardware existed, but PORT_SPEED_64GB is now defined as 0x07 and ha->link_data_rate is decoded with the PORT_SPEED_* encoding. On a 64G-capable adapter a genuine 64G link is therefore dropped, and the port speed is misreported (port_speed sysfs, fc_host speed, FDMI).
Only 28xx and 29xx support 64G, so accept 0x07 on those adapters while keeping the legacy filter for older ones. Also drop the duplicate copy of the check at the end of the success branch; it repeated the first assignment with no intervening change.
--- drivers/scsi/qla2xxx/qla_mbx.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/scsi/qla2xxx/qla_mbx.c +1 -3
@@ -5658,7 +5658,7 @@ qla2x00_get_data_rate(scsi_qla_host_t *vql_dbg (ql_dbg_mbx, vha,0x1107 ,"Failed=%x mb[0]=%x.\n" , rval, mcp->mb[0 ]); }else { -if (mcp->mb[1 ] !=0x7 ) +if (mcp->mb[1 ] !=0x7 ||IS_QLA28XX (ha)) ha->link_data_rate = mcp->mb[1 ];if (IS_QLA83XX (ha) ||IS_QLA27XX (ha) ||IS_QLA28XX (ha)) {
@@ -5669,8 +5669,6 @@ qla2x00_get_data_rate(scsi_qla_host_t *vql_dbg (ql_dbg_mbx + ql_dbg_verbose, vha,0x1108 ,"Done %s.\n" , __func__); -if (mcp->mb[1 ] !=0x7 ) - ha->link_data_rate = mcp->mb[1 ]; }return rval;
Greg Kroah-Hartman
maintainerPATCH 1165/1250 scsi: qla2xxx: Skip vport under deletion in report ID acquisition
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
[ Upstream commit 23582731afa35031c94fadb71a4f3b4afd094649 ]
qla24xx_report_id_acquisition() format-1 handling walks ha->vp_list under vport_slock, takes a vref_count on the matching vport and calls qla_update_host_map() to register its port id.
A vport teardown via qla24xx_vport_delete() sets VPORT_DELETE, then qla24xx_disable_vp() removes the vport from the host_map btree and zeroes vha->d_id (RESET_AL_PA). The vport is only unlinked from vp_list later, in qla24xx_deallocate_vp_id(), which clears vp_map[idx] (RESET_VP_IDX) but does not touch host_map. In the window in between, report ID acquisition can still find the vport on vp_list and call qla_update_host_map(); with d_id already zeroed it takes the btree_insert32() path and re-inserts the dying vport into host_map. Nothing cleans that entry afterwards, so once scsi_host_put() frees the vha a later host_map lookup dereferences freed memory.
Skip a vport that has VPORT_DELETE set before taking the reference, so it is neither re-registered nor scheduled for DPC re-registration. This mirrors the existing guard in qla2x00_alert_all_vps().
--- drivers/scsi/qla2xxx/qla_mbx.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/scsi/qla2xxx/qla_mbx.c +2 -0
@@ -4147,6 +4147,8 @@ qla24xx_report_id_acquisition(scsi_qla_hspin_lock_irqsave (&ha->vport_slock, flags);list_for_each_entry (vp, &ha->vp_list, list) {if (rptid_entry->vp_idx == vp->vp_idx) { +if (test_bit (VPORT_DELETE , &vp->dpc_flags)) +break ; found =1 ;atomic_inc (&vp->vref_count);break ;
Greg Kroah-Hartman
maintainerPATCH 1166/1250 scsi: qla2xxx: Use ring-slot helpers in __qla2x00_alloc_iocbs
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
[ Upstream commit 7e51b6d2d8f6b7f48d9cef1cf87471b55b12f6de ]
__qla2x00_alloc_iocbs() open-codes ring pointer selection and entry size based on IS_QLA29XX(ha): 29xx reaches the slot via ring_ext_ptr and zeroes REQUEST_ENTRY_SIZE_EXT bytes, while other adapters use ring_ptr with REQUEST_ENTRY_SIZE bytes.
Replace the two branches with the qla_req_ring_slot() and qla_req_entry_size() helpers, and initialise pkt at declaration. The IS_QLAFX00 register-mapped writes remain guarded because IS_QLAFX00 and IS_QLA29XX cannot be true simultaneously.
No functional change: the bytes written to the firmware-visible IOCB are identical.
Stable adaptation:
This tree has no QLA29xx support, extended request ring, or ring-slot helpers. Provide file-local macro helpers mapping to req->ring_ptr and REQUEST_ENTRY_SIZE, preserving the existing 64-byte ring behavior without adding functions or importing the unrelated QLA29xx support series.
Retain the helper calls and declaration initialization from this change. Use a multiline packet-preparation comment so commit 626e44f3d8a9 ("scsi: qla2xxx: Use memset_io() to clear QLAFX00 request ring slot") applies unchanged, including its leading context. That commit remains responsible for changing the FX00 clearing operation to memset_io().
Stable-dep-of: 626e44f3d8a9 ("scsi: qla2xxx: Use memset_io() to clear QLAFX00 request ring slot")
--- drivers/scsi/qla2xxx/qla_iocb.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
drivers/scsi/qla2xxx/qla_iocb.c +10 -5
@@ -11,6 +11,10 @@#include <scsi/scsi_tcq.h> +/* All adapters supported by this tree use the 64-byte request ring. */ +#define qla_req_ring_slot (ha, req) ((req)->ring_ptr) +#define qla_req_entry_size (ha) REQUEST_ENTRY_SIZE +static int qla_start_scsi_type6 (srb_t *sp);/** * qla2x00_get_cmd_direction() - Determine control_flag data direction.
@@ -2286,10 +2290,9 @@ __qla2x00_alloc_iocbs(struct qla_qpair *struct req_que *req = qpair->req;device_reg_t *reg =ISP_QUE_REG (ha, req->id);uint32_t handle; -request_t *pkt;uint16_t cnt, req_cnt; +request_t *pkt =NULL ; - pkt =NULL ; req_cnt =1 ; handle =0 ;
@@ -2343,10 +2346,12 @@ __qla2x00_alloc_iocbs(struct qla_qpair * sp->handle = handle; } -/* Prep packet */ +/* +* Prep the current request-ring slot. +*/ req->cnt -= req_cnt; - pkt = req->ring_ptr; -memset (pkt,0 ,REQUEST_ENTRY_SIZE ); + pkt =qla_req_ring_slot (ha, req); +memset (pkt,0 ,qla_req_entry_size (ha));if (IS_QLAFX00 (ha)) {wrt_reg_byte ((u8 __force __iomem *)&pkt->entry_count, req_cnt);wrt_reg_dword ((__le32 __force __iomem *)&pkt->handle, handle);
Greg Kroah-Hartman
maintainerPATCH 1167/1250 scsi: qla2xxx: Use memset_io() to clear QLAFX00 request ring slot
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
[ Upstream commit 626e44f3d8a924a97a3848a9fd45833947e081e9 ]
For QLAFX00 the request ring is ioremapped device I/O memory (ha->iobase + req_que_off), not DMA-coherent RAM, which is why the rest of the FX00 path accesses it through memcpy_toio() and the wrt_reg_* helpers. __qla2x00_alloc_iocbs() however zeroed the producer slot with a plain memset(). On architectures such as ARM64 a regular memset() may emit unaligned or block-zeroing instructions (e.g. DC ZVA) that are invalid on Device memory, leading to a synchronous external abort.
Use memset_io() to clear the slot for QLAFX00, matching the I/O accessors used elsewhere on this ring. Other adapters keep the plain memset() on their DMA-coherent rings. The zero-fill is retained for FX00 because its IOCB builders (e.g. qlafx00_fxdisc_iocb()) copy only part of the entry and rely on the unused tail being pre-zeroed.
--- drivers/scsi/qla2xxx/qla_iocb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/scsi/qla2xxx/qla_iocb.c +3 -1
@@ -2351,11 +2351,13 @@ __qla2x00_alloc_iocbs(struct qla_qpair **/ req->cnt -= req_cnt; pkt =qla_req_ring_slot (ha, req); -memset (pkt,0 ,qla_req_entry_size (ha));if (IS_QLAFX00 (ha)) { +memset_io ((void __iomem __force *)pkt,0 , +qla_req_entry_size (ha));wrt_reg_byte ((u8 __force __iomem *)&pkt->entry_count, req_cnt);wrt_reg_dword ((__le32 __force __iomem *)&pkt->handle, handle); }else { +memset (pkt,0 ,qla_req_entry_size (ha)); pkt->entry_count = req_cnt; pkt->handle = handle; }
Greg Kroah-Hartman
maintainerPATCH 1168/1250 scsi: qla2xxx: Fix soft lockup polling continuation IOCB signature
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
[ Upstream commit d7e3fa7d06bf7fcaac186d3c4d635caac166d36c ]
qla27xx_copy_multiple_pkt() and qla27xx_copy_fpin_pkt() poll rsp_q->ring_ptr->signature for RESPONSE_PROCESSED (0xDEADDEAD) to decide whether the next continuation IOCB has arrived, spinning on cpu_relax() without advancing the ring or decrementing the entry count while it has not. response_t::signature lives at byte offset 60, but a continuation IOCB (sts_cont_entry_t / struct sts_cont_entry_ext) carries raw FC frame payload at that offset (data[56..59]). A received frame whose payload bytes happen to equal 0xDEADDEAD is therefore misread as "not yet arrived", and the loop spins forever in interrupt/DPC context, causing a CPU soft lockup.
The poll is also unnecessary: callers of qla27xx_copy_multiple_pkt() (PT_LS4_UNSOL and the NVMe purls path) already gate on qla_chk_cont_iocb_avail(), which guarantees all entry_count IOCBs are present before copying begins. The sibling helper __qla_copy_purex_to_buffer() already drops the signature poll and relies on the entry_type == STATUS_CONT_TYPE guard instead.
Remove the signature busy-wait from both helpers, keeping the entry_type guard, and gate the FPIN path with qla_chk_cont_iocb_avail() so it defers and re-processes on the next interrupt once all continuation IOCBs have arrived, mirroring the ELS_AUTH_ELS and PT_LS4_UNSOL arms. With this the signature field is never read on a continuation IOCB, eliminating the payload-aliasing lockup.
--- drivers/scsi/qla2xxx/qla_isr.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-)
drivers/scsi/qla2xxx/qla_isr.c +16 -17
@@ -921,14 +921,6 @@ qla27xx_copy_multiple_pkt(struct scsi_ql do { while ((total_bytes > 0) && (entry_count_remaining > 0)) { - if (rsp_q->ring_ptr->signature == RESPONSE_PROCESSED) { - ql_dbg(ql_dbg_async, vha, 0x5084, - "Ran out of IOCBs, partial data 0x%x\n", - buffer_copy_offset); - cpu_relax(); - continue; - } - new_pkt = (sts_cont_entry_t *)rsp_q->ring_ptr; *pkt = new_pkt;
@@ -1205,14 +1197,6 @@ qla27xx_copy_fpin_pkt(struct scsi_qla_ho do { while ((total_bytes > 0) && (entry_count_remaining > 0)) { - if (rsp_q->ring_ptr->signature == RESPONSE_PROCESSED) { - ql_dbg(ql_dbg_async, vha, 0x5084, - "Ran out of IOCBs, partial data 0x%x\n", - buffer_copy_offset); - cpu_relax(); - continue; - } - new_pkt = (sts_cont_entry_t *)rsp_q->ring_ptr; *pkt = new_pkt;
@@ -4142,9 +4126,24 @@ process_err: "SCM not active for this port\n");break ; } +if (qla_chk_cont_iocb_avail (vha, rsp, + (response_t *)pkt, rsp_in)) { +/* +* ring_ptr and ring_index were +* pre-incremented above. Reset them +* back to current. Wait for next +* interrupt with all IOCBs to arrive +* and re-process. +*/ + rsp->ring_ptr = (response_t *)pkt; + rsp->ring_index = cur_ring_index; + +ql_dbg (ql_dbg_init, vha,0x5095 , +"Defer processing FPIN...\n" ); +return ; + } pure_item =qla27xx_copy_fpin_pkt (vha, (void **)&pkt, &rsp); -__update_rsp_in (is_shadow_hba, rsp, rsp_in);if (!pure_item)break ; qla24xx_queue_purex_item(vha, pure_item,
Greg Kroah-Hartman
maintainerPATCH 1169/1250 scsi: qla2xxx: Clamp max_npiv_vports to VP_CTRL bitmap capacity
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
[ Upstream commit 2ac6a829843cf3df522d19e091276109b94c4c7a ]
ha->max_npiv_vports is taken from firmware (mcp->mb[11]) and only constrained so that (max_npiv_vports + 1) is a multiple of MIN_MULTI_ID_FABRIC, which permits values of 63, 127, 191 and 255. NPIV vports are then allocated up to that count.
VP enable uses the VP_CONFIG IOCB, which addresses a vport through a plain vp_index byte, so a vp_index beyond 128 is enabled without issue. VP disable, however, uses the VP_CTRL IOCB, which selects target vports through the fixed 128-bit vp_idx_map bitmap. qla24xx_control_vp() rejects a vp_index past that bitmap and the IOCB builder cannot set a bit beyond 127, yet qla24xx_vport_delete() frees the local state regardless. A vport with vp_index > 128 can therefore be created and enabled but never disabled, leaving it permanently active in firmware: a resource leak.
Cap ha->max_npiv_vports at init to the vp_idx_map capacity so such vports are never created. This collapses 191/255 to 127 (still modulo-valid) and leaves the real-world 63/127 cases unaffected.
--- drivers/scsi/qla2xxx/qla_fw.h | 4 ++++ drivers/scsi/qla2xxx/qla_init.c | 13 +++++++++++++ drivers/scsi/qla2xxx/qla_mid.c | 8 ++++++++ 3 files changed, 25 insertions(+)
drivers/scsi/qla2xxx/qla_fw.h +4 -0
@@ -1442,6 +1442,10 @@ struct vp_ctrl_entry_24xx {uint8_t reserved_5[24 ]; }; +/* vp_idx_map is a 128-bit (16-byte) bitmap selecting target VPs. */ +#define VP_CTRL_IDX_MAP_BITS \ + (sizeof_field(struct vp_ctrl_entry_24xx, vp_idx_map) * 8) +/* * Modify Virtual Port Configuration IOCB */
drivers/scsi/qla2xxx/qla_init.c +13 -0
@@ -4408,6 +4408,19 @@ enable_82xx_npiv: MIN_MULTI_ID_FABRIC)) ha->max_npiv_vports =MIN_MULTI_ID_FABRIC -1 ; + +/* +* The VP_CTRL IOCB selects target VPs +* through the fixed vp_idx_map bitmap, +* so a vp_index beyond it can be enabled +* via VP_CONFIG but never disabled via +* VP_CTRL, leaking the VP. Cap the count +* to the bitmap capacity. +*/ +if (ha->max_npiv_vports >= +VP_CTRL_IDX_MAP_BITS ) + ha->max_npiv_vports = +VP_CTRL_IDX_MAP_BITS -1 ; }qla2x00_get_resource_cnts (vha);qla_init_iocb_limit (vha);
drivers/scsi/qla2xxx/qla_mid.c +8 -0
@@ -970,6 +970,14 @@ int qla24xx_control_vp(scsi_qla_host_t * if (vp_index > sizeof_field(struct vp_ctrl_entry_24xx, vp_idx_map) * 8)return QLA_PARAMETER_ERROR ; +/* +* The VP_CTRL IOCB selects the target VP through a fixed 128-bit +* (16-byte) vp_idx_map bitmap, so vp_index must fit within it even +* if firmware advertises more NPIV vports. +*/ +if (vp_index >VP_CTRL_IDX_MAP_BITS ) +return QLA_PARAMETER_ERROR ; +/* ref: INIT */ sp =qla2x00_get_sp (base_vha,NULL ,GFP_KERNEL );if (!sp)
Greg Kroah-Hartman
maintainerPATCH 1170/1250 scsi: qla2xxx: Unlink NVMe unsol ctx before freeing on LS reject error
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
[ Upstream commit e46160a5d4fa59bf4d5f3412b6b5cb79edb967dd ]
qla_nvme_xmt_ls_rsp() obtains uctx, which was linked into fcport->unsol_ctx_head by qla2xxx_process_purls_iocb() and is still linked when the NVMe transport calls back to transmit the LS response. On the error (out:) path the function frees uctx with kfree() but never removes it from the list. This leaves a freed node in fcport->unsol_ctx_head: the next list_add_tail() for that fcport writes through the freed node, and a subsequent list_del() can corrupt the list or panic.
Unlink uctx with list_del() before kfree() on the error path, matching the other free sites in qla_nvme_release_lsrsp_cmd_kref() and qla2xxx_process_purls_pkt(). qla2x00_rel_sp() in the failure path only returns the SRB to its pool and does not invoke sp->put_fn, so the out:
path is the sole free and uctx is always still linked there.
Stable-dep-of: 76da0c43c63e ("scsi: qla2xxx: Serialize NVMe unsol ctx list with a per-fcport lock")
--- drivers/scsi/qla2xxx/qla_nvme.c | 1 + 1 file changed, 1 insertion(+)
drivers/scsi/qla2xxx/qla_nvme.c +1 -0
@@ -446,6 +446,7 @@ out:qla_nvme_ls_reject_iocb (vha, ha->base_qpair, &a, true);spin_unlock_irqrestore (ha->base_qpair->qp_lock_ptr, flags); } +list_del (&uctx->elem);kfree (uctx);return rval; }
Greg Kroah-Hartman
maintainerPATCH 1171/1250 scsi: qla2xxx: Serialize NVMe unsol ctx list with a per-fcport lock
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
[ Upstream commit 76da0c43c63eb0496649e372ac64466364d0fe7d ]
The fcport->unsol_ctx_head list is modified from several contexts without a common lock. Entries are added in qla2xxx_process_purls_iocb() from the response queue ISR (under the qpair qp_lock), while they are removed from qla2xxx_process_purls_pkt() (DPC/purex worker), qla_nvme_xmt_ls_rsp() (NVMe-FC transport callback) and qla_nvme_release_lsrsp_cmd_kref() (SRB completion). The qpair qp_lock cannot serialize this per-fcport list since multiqueue adapters add entries through different qpairs, so a concurrent add and delete (or two concurrent deletes) can corrupt the list pointers.
Introduce a dedicated per-fcport spinlock, unsol_ctx_lock, initialized in qla2x00_alloc_fcport(), and take it around every list_add_tail()/list_del() on unsol_ctx_head. The add nests under the existing qp_lock; no delete path takes qp_lock, so the lock order is consistent and deadlock free.
--- drivers/scsi/qla2xxx/qla_def.h | 2 ++ drivers/scsi/qla2xxx/qla_init.c | 1 + drivers/scsi/qla2xxx/qla_nvme.c | 9 +++++++++ 3 files changed, 12 insertions(+)
drivers/scsi/qla2xxx/qla_def.h +2 -0
@@ -2570,6 +2570,8 @@ typedef struct fc_port {struct list_head list;struct scsi_qla_host *vha;struct list_head unsol_ctx_head; +/* Serializes unsol_ctx_head against ISR, DPC and NVMe transport. */ +spinlock_t unsol_ctx_lock; unsigned int conf_compl_supported:1; unsigned int deleted:2;
drivers/scsi/qla2xxx/qla_init.c +1 -0
@@ -5649,6 +5649,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vhINIT_LIST_HEAD (&fcport->gnl_entry);INIT_LIST_HEAD (&fcport->list);INIT_LIST_HEAD (&fcport->unsol_ctx_head); +spin_lock_init (&fcport->unsol_ctx_lock);INIT_LIST_HEAD (&fcport->sess_cmd_list);spin_lock_init (&fcport->sess_cmd_lock);
drivers/scsi/qla2xxx/qla_nvme.c +9 -0
@@ -257,7 +257,9 @@ static void qla_nvme_release_lsrsp_cmd_k fd_rsp = uctx->fd_rsp; +spin_lock_irqsave (&uctx->fcport->unsol_ctx_lock, flags);list_del (&uctx->elem); +spin_unlock_irqrestore (&uctx->fcport->unsol_ctx_lock, flags); fd_rsp->done (fd_rsp);kfree (uctx);
@@ -446,7 +448,9 @@ out:qla_nvme_ls_reject_iocb (vha, ha->base_qpair, &a, true);spin_unlock_irqrestore (ha->base_qpair->qp_lock_ptr, flags); } +spin_lock_irqsave (&uctx->fcport->unsol_ctx_lock, flags);list_del (&uctx->elem); +spin_unlock_irqrestore (&uctx->fcport->unsol_ctx_lock, flags);kfree (uctx);return rval; }
@@ -1216,7 +1220,9 @@ qla2xxx_process_purls_pkt(struct scsi_qlspin_unlock_irqrestore (vha->hw->base_qpair->qp_lock_ptr, flags); } +spin_lock_irqsave (&uctx->fcport->unsol_ctx_lock, flags);list_del (&uctx->elem); +spin_unlock_irqrestore (&uctx->fcport->unsol_ctx_lock, flags);kfree (uctx); } }
@@ -1258,6 +1264,7 @@ void qla2xxx_process_purls_iocb(void **pstruct purex_item *item;port_id_t d_id = {0 };port_id_t id = {0 }; +unsigned long flags;u8 *opcode;bool xmt_reject = false;
@@ -1323,7 +1330,9 @@ void qla2xxx_process_purls_iocb(void **p uctx->ox_id = p->ox_id; qla_rport->uctx = uctx;INIT_LIST_HEAD (&uctx->elem); +spin_lock_irqsave (&fcport->unsol_ctx_lock, flags);list_add_tail (&uctx->elem, &fcport->unsol_ctx_head); +spin_unlock_irqrestore (&fcport->unsol_ctx_lock, flags); item->purls_context = (void *)uctx; ql_dbg(ql_dbg_unsol, vha, 0x2121,
Greg Kroah-Hartman
maintainerPATCH 1172/1250 scsi: qla2xxx: Validate BSG request_len before reading vendor_cmd[]
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
[ Upstream commit 4cf38dd9465736141263ebb63375868311a0ec81 ]
The FC BSG transport allocates job->request via memdup_user() using the exact user-supplied request_len. For FC_BSG_HST_VENDOR, fc_bsg_host_dispatch() only guarantees request_len covers msgcode and vendor_id; it does not account for the vendor_cmd[] flexible array.
qla2xxx then reads the command selector vendor_cmd[0] and, in several sub-handlers, vendor_cmd[1]/[2] or structures overlaid on the vendor command area without verifying request_len. A caller holding CAP_SYS_RAWIO can submit a short request whose vendor_id matches the host, triggering out-of-bounds heap reads (KASAN-detectable, and able to mis-select a command or panic).
Add a central guard in qla2x00_process_vendor_specific() so the selector is always in bounds, restrict the early vendor_cmd[0] read in qla24xx_bsg_request() to sufficiently long vendor messages, and add request_len checks to the sub-handlers that read further:qla24xx_proc_fcp_prio_cfg_cmd(), qla2x00_process_loopback(), qla84xx_reset(), qla84xx_updatefw(), qla2x00_read_optrom(), qla2x00_update_optrom(), qlafx00_mgmt_cmd() and qla28xx_validate_flash_image().
--- drivers/scsi/qla2xxx/qla_bsg.c | 45 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-)
drivers/scsi/qla2xxx/qla_bsg.c +43 -2
@@ -158,6 +158,12 @@ qla24xx_proc_fcp_prio_cfg_cmd(struct bsg goto exit_fcp_prio_cfg; } +if (bsg_job->request_len < +sizeof (struct fc_bsg_request ) +2 *sizeof (uint32_t )) { + ret = -EINVAL ; + goto exit_fcp_prio_cfg; + } +/* Get the sub command */ oper = bsg_request->rqst_data.h_vendor.vendor_cmd[1 ];
@@ -756,6 +762,10 @@ qla2x00_process_loopback(struct bsg_jobreturn -EIO ; } +if (bsg_job->request_len < +sizeof (struct fc_bsg_request ) +3 *sizeof (uint32_t )) +return -EINVAL ; +memset (&elreq,0 ,sizeof (elreq)); elreq.req_sg_cnt = dma_map_sg(&ha->pdev->dev,
@@ -988,6 +998,10 @@ qla84xx_reset(struct bsg_job *bsg_job)return -EINVAL ; } +if (bsg_job->request_len < +sizeof (struct fc_bsg_request ) +2 *sizeof (uint32_t )) +return -EINVAL ; + flag = bsg_request->rqst_data.h_vendor.vendor_cmd[1 ]; rval =qla84xx_reset_chip (vha, flag ==A84_ISSUE_RESET_DIAG_FW );
@@ -1032,6 +1046,10 @@ qla84xx_updatefw(struct bsg_job *bsg_jobreturn -EINVAL ; } +if (bsg_job->request_len < +sizeof (struct fc_bsg_request ) +2 *sizeof (uint32_t )) +return -EINVAL ; + sg_cnt =dma_map_sg (&ha->pdev->dev, bsg_job->request_payload.sg_list, bsg_job->request_payload.sg_cnt,DMA_TO_DEVICE );if (!sg_cnt) {
@@ -1482,6 +1500,10 @@ qla2x00_read_optrom(struct bsg_job *bsg_struct qla_hw_data *ha = vha->hw;int rval =0 ; +if (bsg_job->request_len < +sizeof (struct fc_bsg_request ) +2 *sizeof (uint32_t )) +return -EINVAL ; +if (ha->flags.nic_core_reset_hdlr_active)return -EBUSY ;
@@ -1519,6 +1541,10 @@ qla2x00_update_optrom(struct bsg_job *bsstruct qla_hw_data *ha = vha->hw;int rval =0 ; +if (bsg_job->request_len < +sizeof (struct fc_bsg_request ) +2 *sizeof (uint32_t )) +return -EINVAL ; +mutex_lock (&ha->optrom_mutex); rval =qla2x00_optrom_setup (bsg_job, vha,1 );if (rval) {
@@ -2010,6 +2036,11 @@ qlafx00_mgmt_cmd(struct bsg_job *bsg_jobstruct fc_port *fcport;char *type ="FC_BSG_HST_FX_MGMT" ; +if (bsg_job->request_len < +sizeof (struct fc_bsg_request ) +sizeof (uint32_t ) + +sizeof (struct qla_mt_iocb_rqst_fx00 )) +return -EINVAL ; +/* Copy the IOCB specific information */ piocb_rqst = (struct qla_mt_iocb_rqst_fx00 *) &bsg_request->rqst_data.h_vendor.vendor_cmd[1 ];
@@ -2899,6 +2930,13 @@ qla2x00_process_vendor_specific(struct s {struct fc_bsg_request *bsg_request = bsg_job->request; +if (bsg_job->request_len < +sizeof (struct fc_bsg_request ) +sizeof (uint32_t )) { +ql_log (ql_log_warn, vha,0x7000 , +"BSG request too small for vendor cmd.\n" ); +return -EINVAL ; + } +ql_dbg (ql_dbg_edif, vha,0x911b ,"%s FC_BSG_HST_VENDOR cmd[0]=0x%x\n" , __func__, bsg_request->rqst_data.h_vendor.vendor_cmd[0 ]);
@@ -3024,8 +3062,11 @@ qla24xx_bsg_request(struct bsg_job *bsg_ }/* Disable port will bring down the chip, allow enable command */ -if (bsg_request->rqst_data.h_vendor.vendor_cmd[0 ] ==QL_VND_MANAGE_HOST_PORT || - bsg_request->rqst_data.h_vendor.vendor_cmd[0 ] ==QL_VND_GET_HOST_STATS ) +if (bsg_request->msgcode ==FC_BSG_HST_VENDOR && + bsg_job->request_len >= +sizeof (struct fc_bsg_request ) +sizeof (uint32_t ) && + (bsg_request->rqst_data.h_vendor.vendor_cmd[0 ] ==QL_VND_MANAGE_HOST_PORT || + bsg_request->rqst_data.h_vendor.vendor_cmd[0 ] ==QL_VND_GET_HOST_STATS )) goto skip_chip_chk;if (vha->hw->flags.port_isolated) {
Greg Kroah-Hartman
maintainerPATCH 1173/1250 f2fs: validate MOVE_RANGE destination size
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wenjie Qi <[email protected]>
[ Upstream commit e533889fc26aea0cd83c90327063f272061dd820 ]
F2FS_IOC_MOVE_RANGE checks the source range, but not the destination end before updating i_size. A source hole can expose this: __clone_blkaddrs() skips NULL_ADDR entries and returns success, so the caller can still extend the destination inode with unchecked pos_out + len.
Reject destination overflow and use inode_newsize_ok() before extending the destination inode.
--- fs/f2fs/file.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)
fs/f2fs/file.c +12 -4
@@ -3175,8 +3175,9 @@ static int f2fs_move_file_range(struct fstruct inode *src =file_inode (file_in);struct inode *dst =file_inode (file_out);struct f2fs_sb_info *sbi =F2FS_I_SB (src); -size_t olen = len, dst_max_i_size =0 ; -size_t dst_osize; +size_t olen = len; +loff_t dst_max_i_size =0 ; +loff_t dst_osize, dst_end;int ret; if (file_in->f_path.mnt != file_out->f_path.mnt ||
@@ -3234,8 +3235,15 @@ static int f2fs_move_file_range(struct f } dst_osize = dst->i_size; -if (pos_out + olen > dst->i_size) - dst_max_i_size = pos_out + olen; +if (olen >LLONG_MAX - pos_out) + goto out_unlock; + dst_end = pos_out + olen; +if (dst_end > dst->i_size) { + ret =inode_newsize_ok (dst, dst_end); +if (ret) + goto out_unlock; + dst_max_i_size = dst_end; + }/* verify the end result is block aligned */ if (!IS_ALIGNED(pos_in, F2FS_BLKSIZE) ||
Greg Kroah-Hartman
maintainerPATCH 1174/1250 f2fs: limit recovery filename logging to stored length
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wenjie Qi <[email protected]>
[ Upstream commit 01027b2fcb74dade59fb833b51023f6593b6a9a2 ]
F2FS stores recovery filenames as a length plus a fixed-size i_name buffer. The buffer is not NUL-terminated, but recover_inode() and recover_dentry() print it with %s.
For a 255-byte filename, recovery logging can read past i_name into the following raw inode fields.
Print the name with a precision bounded by i_namelen and F2FS_NAME_LEN.
--- fs/f2fs/recovery.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-)
fs/f2fs/recovery.c +22 -11
@@ -169,7 +169,8 @@ static int recover_dentry(struct inode *struct inode *dir, *einode;struct fsync_inode_entry *entry;int err =0 ; -char *name; +const char *name; +int name_len; entry =get_fsync_inode (dir_list, pino);if (!entry) {
@@ -228,12 +229,16 @@ retry: out_put:f2fs_folio_put (folio, false); out: -if (file_enc_name (inode)) +if (file_enc_name (inode)) { name ="<encrypted>" ; -else + name_len =sizeof ("<encrypted>" ) -1 ; + }else { name = raw_inode->i_name; -f2fs_notice (F2FS_I_SB (inode),"%s: ino = %x, name = %s, dir = %lx, err = %d" , - __func__,ino_of_node (ifolio), name, + name_len = min_t(unsigned int, le32_to_cpu(raw_inode->i_namelen), +F2FS_NAME_LEN ); + } +f2fs_notice (F2FS_I_SB (inode),"%s: ino = %x, name = %.*s, dir = %lx, err = %d" , + __func__,ino_of_node (ifolio), name_len, name,IS_ERR (dir) ?0 : dir->i_ino, err);return err; }
@@ -281,7 +286,8 @@ static int recover_inode(struct inode *i {struct f2fs_inode *raw =F2FS_INODE (folio);struct f2fs_inode_info *fi =F2FS_I (inode); -char *name; +const char *name; +int name_len;int err; inode->i_mode =le16_to_cpu (raw->i_mode);
@@ -330,13 +336,18 @@ static int recover_inode(struct inode *if2fs_mark_inode_dirty_sync (inode, true); -if (file_enc_name (inode)) +if (file_enc_name (inode)) { name ="<encrypted>" ; -else - name =F2FS_INODE (folio)->i_name; + name_len =sizeof ("<encrypted>" ) -1 ; + }else { + name = raw->i_name; + name_len = min_t(unsigned int, le32_to_cpu(raw->i_namelen), +F2FS_NAME_LEN ); + } -f2fs_notice (F2FS_I_SB (inode),"recover_inode: ino = %x, name = %s, inline = %x" , -ino_of_node (folio), name, raw->i_inline); +f2fs_notice (F2FS_I_SB (inode),"%s: ino = %x, name = %.*s, inline = %x" , + __func__,ino_of_node (folio), name_len, name, + raw->i_inline);return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 1175/1250 f2fs: embed f2fs_gc_kthread in f2fs_sb_info
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chao Yu <[email protected]>
[ Upstream commit 3d7bca9d583793bb7d0bac0d95a24ddd2e129eed ]
Instead of allocating f2fs_gc_kthread dynamically, embed it in f2fs_sb_info. This simplifies lifetime management and prepares for fixing race conditions during teardown.
- __sbi_store - remount|shutdown
- f2fs_stop_gc_thread
- access sbi->gc_thread
- sbi->gc_thread = NULL
- access sbi->gc_thread->f2fs_gc_task
--- fs/f2fs/debug.c | 4 ---- fs/f2fs/f2fs.h | 29 ++++++++++++++++++++++++++++- fs/f2fs/gc.c | 36 +++++++++++++++--------------------- fs/f2fs/gc.h | 29 ++--------------------------- fs/f2fs/segment.c | 9 ++++----- fs/f2fs/super.c | 4 ++-- fs/f2fs/sysfs.c | 18 +++++++++--------- 7 files changed, 60 insertions(+), 69 deletions(-)
fs/f2fs/debug.c +0 -4
@@ -351,10 +351,6 @@ static void update_mem_info(struct f2fs_ get_cache: si->cache_mem =0 ; -/* build gc */ -if (sbi->gc_thread) - si->cache_mem +=sizeof (struct f2fs_gc_kthread ); -/* build merge flush thread */ if (SM_I (sbi)->fcc_info) si->cache_mem +=sizeof (struct flush_cmd_control );
fs/f2fs/f2fs.h +28 -1
@@ -1683,6 +1683,33 @@ struct decompress_io_ctx {#define MAX_COMPRESS_LOG_SIZE 8#define MAX_COMPRESS_WINDOW_SIZE (log_size) ((PAGE_SIZE) << (log_size)) +struct f2fs_gc_kthread { +struct task_struct *f2fs_gc_task; +wait_queue_head_t gc_wait_queue_head; + +/* for gc sleep time */ +unsigned int urgent_sleep_time; +unsigned int min_sleep_time; +unsigned int max_sleep_time; +unsigned int no_gc_sleep_time; + +/* for changing gc mode */ +bool gc_wake; + +/* for GC_MERGE mount option */ +wait_queue_head_t fggc_wq;/* +* caller of f2fs_balance_fs() +* will wait on this wait queue. +*/ + +/* for gc control for zoned devices */ +unsigned int no_zoned_gc_percent; +unsigned int boost_zoned_gc_percent; +unsigned int valid_thresh_ratio; +unsigned int boost_gc_multiple; +unsigned int boost_gc_greedy; +}; +struct f2fs_sb_info {struct super_block *sb;/* pointer to VFS super block */ struct proc_dir_entry *s_proc;/* proc entry */
@@ -1818,7 +1845,7 @@ struct f2fs_sb_info {* semaphore for GC, avoid * race between GC and GC or CP */ -struct f2fs_gc_kthread *gc_thread;/* GC thread */ +struct f2fs_gc_kthread gc_thread;/* GC thread */ struct atgc_management am;/* atgc management */ unsigned int cur_victim_sec;/* current victim section num */ unsigned int gc_mode;/* current GC state */
fs/f2fs/gc.c +15 -21
@@ -31,9 +31,9 @@ static unsigned int count_bits(const unsstatic int gc_thread_func (void *data) {struct f2fs_sb_info *sbi = data; -struct f2fs_gc_kthread *gc_th = sbi->gc_thread; -wait_queue_head_t *wq = &sbi->gc_thread->gc_wait_queue_head; -wait_queue_head_t *fggc_wq = &sbi->gc_thread->fggc_wq; +struct f2fs_gc_kthread *gc_th = &sbi->gc_thread; +wait_queue_head_t *wq = &sbi->gc_thread.gc_wait_queue_head; +wait_queue_head_t *fggc_wq = &sbi->gc_thread.fggc_wq;unsigned int wait_ms;struct f2fs_gc_control gc_control = { .victim_segno =NULL_SEGNO ,
@@ -191,13 +191,9 @@ next:int f2fs_start_gc_thread (struct f2fs_sb_info *sbi) { -struct f2fs_gc_kthread *gc_th; +struct f2fs_gc_kthread *gc_th = &sbi->gc_thread;dev_t dev = sbi->sb->s_bdev->bd_dev; - gc_th =f2fs_kmalloc (sbi,sizeof (struct f2fs_gc_kthread ),GFP_KERNEL ); -if (!gc_th) -return -ENOMEM ; - gc_th->urgent_sleep_time =DEF_GC_THREAD_URGENT_SLEEP_TIME ; gc_th->valid_thresh_ratio =DEF_GC_THREAD_VALID_THRESH_RATIO ; gc_th->boost_gc_multiple =BOOST_GC_MULTIPLE ;
@@ -219,16 +215,14 @@ int f2fs_start_gc_thread(struct f2fs_sb_ gc_th->gc_wake = false; - sbi->gc_thread = gc_th; -init_waitqueue_head (&sbi->gc_thread->gc_wait_queue_head); -init_waitqueue_head (&sbi->gc_thread->fggc_wq); - sbi->gc_thread->f2fs_gc_task =kthread_run (gc_thread_func, sbi, +init_waitqueue_head (&gc_th->gc_wait_queue_head); +init_waitqueue_head (&gc_th->fggc_wq); + gc_th->f2fs_gc_task =kthread_run (gc_thread_func, sbi,"f2fs_gc-%u:%u" ,MAJOR (dev),MINOR (dev));if (IS_ERR (gc_th->f2fs_gc_task)) {int err =PTR_ERR (gc_th->f2fs_gc_task); -kfree (gc_th); - sbi->gc_thread =NULL ; + gc_th->f2fs_gc_task =NULL ;return err; }
@@ -237,14 +231,14 @@ int f2fs_start_gc_thread(struct f2fs_sb_void f2fs_stop_gc_thread (struct f2fs_sb_info *sbi) { -struct f2fs_gc_kthread *gc_th = sbi->gc_thread; +struct f2fs_gc_kthread *gc_th = &sbi->gc_thread; -if (!gc_th) +if (!gc_th->f2fs_gc_task)return ; +kthread_stop (gc_th->f2fs_gc_task); + gc_th->f2fs_gc_task =NULL ;wake_up_all (&gc_th->fggc_wq); -kfree (gc_th); - sbi->gc_thread =NULL ; }static int select_gc_type (struct f2fs_sb_info *sbi,int gc_type)
@@ -792,7 +786,7 @@ int f2fs_get_victim(struct f2fs_sb_infoif (one_time) { p.one_time_gc = one_time;if (has_enough_free_secs (sbi,0 ,NR_PERSISTENT_LOG )) - valid_thresh_ratio = sbi->gc_thread->valid_thresh_ratio; + valid_thresh_ratio = sbi->gc_thread.valid_thresh_ratio; } retry:
@@ -1794,9 +1788,9 @@ static int do_garbage_collect(struct f2fif (f2fs_sb_has_blkzoned (sbi) && !has_enough_free_blocks (sbi, - sbi->gc_thread->boost_zoned_gc_percent)) + sbi->gc_thread.boost_zoned_gc_percent)) window_granularity *= - sbi->gc_thread->boost_gc_multiple; + sbi->gc_thread.boost_gc_multiple; end_segno = start_segno + window_granularity; }
fs/f2fs/gc.h +2 -27
@@ -45,32 +45,7 @@#define NR_GC_CHECKPOINT_SECS (3)/* data/node/dentry sections */ -struct f2fs_gc_kthread { -struct task_struct *f2fs_gc_task; -wait_queue_head_t gc_wait_queue_head; - -/* for gc sleep time */ -unsigned int urgent_sleep_time; -unsigned int min_sleep_time; -unsigned int max_sleep_time; -unsigned int no_gc_sleep_time; - -/* for changing gc mode */ -bool gc_wake; - -/* for GC_MERGE mount option */ -wait_queue_head_t fggc_wq;/* -* caller of f2fs_balance_fs() -* will wait on this wait queue. -*/ - -/* for gc control for zoned devices */ -unsigned int no_zoned_gc_percent; -unsigned int boost_zoned_gc_percent; -unsigned int valid_thresh_ratio; -unsigned int boost_gc_multiple; -unsigned int boost_gc_greedy; -}; +struct gc_inode_list {struct list_head ilist;
@@ -197,6 +172,6 @@ static inline bool need_to_boost_gc(stru {if (f2fs_sb_has_blkzoned (sbi))return !has_enough_free_blocks (sbi, - sbi->gc_thread->boost_zoned_gc_percent); + sbi->gc_thread.boost_zoned_gc_percent);return has_enough_invalid_blocks (sbi); }
fs/f2fs/segment.c +4 -5
@@ -450,15 +450,14 @@ void f2fs_balance_fs(struct f2fs_sb_infof2fs_submit_merged_write (sbi,DATA );f2fs_submit_all_merged_ipu_writes (sbi); -if (test_opt (sbi,GC_MERGE ) && sbi->gc_thread && - sbi->gc_thread->f2fs_gc_task) { +if (test_opt (sbi,GC_MERGE ) && sbi->gc_thread.f2fs_gc_task) {DEFINE_WAIT (wait); -prepare_to_wait (&sbi->gc_thread->fggc_wq, &wait, +prepare_to_wait (&sbi->gc_thread.fggc_wq, &wait,TASK_UNINTERRUPTIBLE ); -wake_up (&sbi->gc_thread->gc_wait_queue_head); +wake_up (&sbi->gc_thread.gc_wait_queue_head);io_schedule (); -finish_wait (&sbi->gc_thread->fggc_wq, &wait); +finish_wait (&sbi->gc_thread.fggc_wq, &wait); }else {struct f2fs_gc_control gc_control = { .victim_segno =NULL_SEGNO ,
fs/f2fs/super.c +2 -2
@@ -2846,11 +2846,11 @@ static int __f2fs_remount(struct fs_contif ((flags &SB_RDONLY ) || (F2FS_OPTION (sbi).bggc_mode ==BGGC_MODE_OFF && !test_opt (sbi,GC_MERGE ))) { -if (sbi->gc_thread) { +if (sbi->gc_thread.f2fs_gc_task) {f2fs_stop_gc_thread (sbi); need_restart_gc = true; } - }else if (!sbi->gc_thread) { + }else if (!sbi->gc_thread.f2fs_gc_task) { err =f2fs_start_gc_thread (sbi);if (err) goto restore_opts;
fs/f2fs/sysfs.c +9 -9
@@ -74,7 +74,7 @@ static ssize_t f2fs_sbi_show(struct f2fsstatic unsigned char *__struct_ptr (struct f2fs_sb_info *sbi,int struct_type) {if (struct_type ==GC_THREAD ) -return (unsigned char *)sbi->gc_thread; +return (unsigned char *)&sbi->gc_thread;else if (struct_type ==SM_INFO )return (unsigned char *)SM_I (sbi);else if (struct_type ==DCC_INFO )
@@ -648,20 +648,20 @@ out: sbi->gc_mode =GC_NORMAL ; }else if (t ==1 ) { sbi->gc_mode =GC_URGENT_HIGH ; -if (sbi->gc_thread) { - sbi->gc_thread->gc_wake = true; +if (sbi->gc_thread.f2fs_gc_task) { + sbi->gc_thread.gc_wake = true;wake_up_interruptible_all ( - &sbi->gc_thread->gc_wait_queue_head); + &sbi->gc_thread.gc_wait_queue_head);wake_up_discard_thread (sbi, true); } }else if (t ==2 ) { sbi->gc_mode =GC_URGENT_LOW ; }else if (t ==3 ) { sbi->gc_mode =GC_URGENT_MID ; -if (sbi->gc_thread) { - sbi->gc_thread->gc_wake = true; +if (sbi->gc_thread.f2fs_gc_task) { + sbi->gc_thread.gc_wake = true;wake_up_interruptible_all ( - &sbi->gc_thread->gc_wait_queue_head); + &sbi->gc_thread.gc_wait_queue_head); } }else {return -EINVAL ;
@@ -918,14 +918,14 @@ out:if (!strcmp (a->attr.name,"gc_boost_gc_multiple" )) {if (t <1 || t >SEGS_PER_SEC (sbi))return -EINVAL ; - sbi->gc_thread->boost_gc_multiple = (unsigned int )t; + sbi->gc_thread.boost_gc_multiple = (unsigned int )t;return count; }if (!strcmp (a->attr.name,"gc_boost_gc_greedy" )) {if (t >GC_GREEDY )return -EINVAL ; - sbi->gc_thread->boost_gc_greedy = (unsigned int )t; + sbi->gc_thread.boost_gc_greedy = (unsigned int )t;return count; }
Greg Kroah-Hartman
maintainerPATCH 1176/1250 f2fs: fix to reclaim space in f2fs_allocate_pinning_section()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chao Yu <[email protected]>
[ Upstream commit fa487f56efba6344aef67d871688f0908fe08af3 ]
It needs to trigger checkpoint to free space reclaimed by f2fs_gc_range(), otherwise, fallocate() on pinfile will fail easily even there is slash space in conventional zone.
[Testcase]nullblk_create.sh 512 2 1024 1024
mkfs.f2fs /dev/nullb0 -f -m
mount /dev/nullb0 /mnt/f2fs/
touch /mnt/f2fs/pinfilef2fs_io pinfile set /mnt/f2fs/pinfile
mkdir /mnt/f2fs/dir/
for((i=0;i<3934;i++)) do { dd if=/dev/zero of=/mnt/f2fs/dir/$i bs=1M count=1;} done sync
for((i=0;i<3934;i+=2)) do { rm /mnt/f2fs/dir/$i;} done for((i=0;i<1950;i++)) do { rm /mnt/f2fs/dir/$i;} done
syncf2fs_io fallocate 0 0 $((1024*1024*1024)) /mnt/f2fs/pinfile
sync
stat /mnt/f2fs/pinfilef2fs_io fiemap 0 $((1024*1024*1024)) /mnt/f2fs/pinfile
[Before]
fallocate failed: Resource temporarily unavailable
File: /mnt/f2fs/pinfile
Size: 109051904 Blocks: 213208 IO Block: 4096 regular file
Device: 250,0 Inode: 4 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2026-08-12 20:04:02.264000000 +0800
Modify: 2026-08-12 20:04:26.784000000 +0800
Change: 2026-08-12 20:04:26.784000000 +0800
Birth: -
root@localhost:~#
root@localhost:~#
root@localhost:~#
root@localhost:~# f2fs_io fiemap 0 $((1024*1024*1024)) /mnt/f2fs/pinfile
Fiemap: offset = 0 len = 1073741824
logical addr. physical addr. length flags
0 0000000000000000 0000000002e00000 0000000000200000 00001000
1 0000000000200000 000000002dc00000 0000000000400000 00001000
2 0000000000600000 000000002e400000 0000000000600000 00001000
3 0000000000c00000 000000007a400000 0000000005c00000 00001001[After]
File: /mnt/f2fs/pinfile
Size: 1073741824 Blocks: 2099216 IO Block: 4096 regular file
Device: 250,0 Inode: 4 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2026-08-12 19:47:49.428000000 +0800
Modify: 2026-08-12 19:49:06.808000000 +0800
Change: 2026-08-12 19:49:06.808000000 +0800
Birth: -
Fiemap: offset = 0 len = 1073741824
logical addr. physical addr. length flags
0 0000000000000000 0000000002e00000 0000000000200000 00001000 1 0000000000200000 000000003aa00000 0000000000400000 00001000 2 0000000000600000 000000003b400000 0000000000200000 00001000 3 0000000000800000 000000007a200000 0000000005e00000 00001000 4 0000000006600000 0000000002800000 0000000000200000 00001000 5 0000000006800000 0000000003200000 0000000000400000 00001000 6 0000000006c00000 0000000003000000 0000000000200000 00001000 7 0000000006e00000 0000000003600000 0000000037200000 00001000 8 000000003e000000 000000003b200000 0000000000200000 00001000 9 000000003e200000 000000003a800000 0000000000200000 00001000 10 000000003e400000 000000003ae00000 0000000000400000 00001000 11 000000003e800000 000000003b600000 0000000001800000 00001001
--- fs/f2fs/segment.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
fs/f2fs/segment.c +6 -3
@@ -3387,10 +3387,13 @@ retry: err =f2fs_gc_range (sbi,0 , sbi->first_seq_zone_segno -1 , true,ZONED_PIN_SEC_REQUIRED_COUNT );f2fs_up_write (&sbi->gc_lock); - - gc_required = false; -if (!err) +if (err) +return err; + err =f2fs_sync_fs (sbi->sb,1 ); +if (!err) { + gc_required = false; goto retry; + } }return err;
Greg Kroah-Hartman
maintainerPATCH 1177/1250 f2fs: accurately adjust free_sections during free_segment_range
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daeho Jeong <[email protected]>
[ Upstream commit 8c963d1738fdca400082ff5f9d99e083de4f4e70 ]
In free_segment_range(), MAIN_SECS(sbi) is temporarily reduced by secs to restrict block allocation to the safe remaining main area while valid blocks in the truncated range are evacuated by GC.
However, FREE_I(sbi)->free_sections tracks the total number of free sections across the whole filesystem. If any sections within the truncated range were already free upon entering free_segment_range(), failing to deduct them from free_sections causes the filesystem to overestimate available free sections in the active, reduced main area. This leads to inconsistent free section accounting during GC data migration and can trigger unexpected allocation failures or assertion errors when space is tight.
Fix this by calculating the number of already-free sections in the truncated range, deducting them from free_sections upon entering free_segment_range(), and restoring them on exit.
--- fs/f2fs/gc.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-)
fs/f2fs/gc.c +14 -1
@@ -2165,8 +2165,9 @@ int f2fs_gc_range(struct f2fs_sb_info *sstatic int free_segment_range (struct f2fs_sb_info *sbi,unsigned int secs,bool dry_run) { -unsigned int next_inuse, start, end; +unsigned int secno, next_inuse, start, end, end_secno;struct cp_control cpc = {CP_RESIZE ,0 ,0 ,0 }; +unsigned int freed_secs =0 ;int gc_mode, gc_type;int err =0 ;int type;
@@ -2175,6 +2176,7 @@ static int free_segment_range(struct f2fMAIN_SECS (sbi) -= secs; start =MAIN_SECS (sbi) *SEGS_PER_SEC (sbi); end =MAIN_SEGS (sbi) -1 ; + end_secno =GET_SEC_FROM_SEG (sbi, end);mutex_lock (&DIRTY_I (sbi)->seglist_lock);for (gc_mode =0 ; gc_mode <MAX_GC_POLICY ; gc_mode++)
@@ -2186,6 +2188,14 @@ static int free_segment_range(struct f2f sbi->next_victim_seg[gc_type] =NULL_SEGNO ;mutex_unlock (&DIRTY_I (sbi)->seglist_lock); +spin_lock (&FREE_I (sbi)->segmap_lock); +for (secno =MAIN_SECS (sbi); secno <= end_secno; secno++) { +if (!test_bit (secno,FREE_I (sbi)->free_secmap)) + freed_secs++; + } +FREE_I (sbi)->free_sections -= freed_secs; +spin_unlock (&FREE_I (sbi)->segmap_lock); +/* Move out cursegs from the target range */ for (type =CURSEG_HOT_DATA ; type <NR_CURSEG_TYPE ; type++) { err =f2fs_allocate_segment_for_resize (sbi, type, start, end);
@@ -2210,6 +2220,9 @@ static int free_segment_range(struct f2ff2fs_bug_on (sbi,1 ); } out: +spin_lock (&FREE_I (sbi)->segmap_lock); +FREE_I (sbi)->free_sections += freed_secs; +spin_unlock (&FREE_I (sbi)->segmap_lock);MAIN_SECS (sbi) += secs;return err; }
Greg Kroah-Hartman
maintainerPATCH 1178/1250 fou: Fix use-after-free in fou_create()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xuanqiang Luo <[email protected]>
commit b14361aca6350ff7907b0e9903c7b94dc7d5d4a0 upstream.
fou_create() publishes struct fou through sk_user_data before adding the new FOU port to the per-netns list. If fou_add_to_port_list() fails, the error path frees fou while it is still reachable through sk_user_data. A concurrent receive can then dereference the freed object in fou_from_sock().
This ordering issue was previously noted in the linked discussion.
The failure is reachable when local port 0 is requested. Each socket binds to a different ephemeral port, but fou_cfg_cmp() compares the requested port 0 and reports -EALREADY once an entry already exists.
Release the tunnel socket before freeing fou so sk_user_data is cleared first, and defer reclamation with kfree_rcu() to protect concurrent RCU readers. This matches the lifetime handling in fou_release().
--- net/ipv4/fou_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/ipv4/fou_core.c +1 -1
@@ -632,9 +632,9 @@ static int fou_create(struct net *net, sreturn 0 ; error: -kfree (fou);if (sock)udp_tunnel_sock_release (sock); +kfree_rcu (fou, rcu);return err; }
Greg Kroah-Hartman
maintainerPATCH 1179/1250 Revert: "f2fs: check in-memory block bitmap"
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chao Yu <[email protected]>
[ Upstream commit a2b251259bf2bdf550893bac078e9ce0a10e76c9 ]
Commit 355e78913c0d ("f2fs: check in-memory block bitmap") added a mirror for valid block bitmap, it expects to detect in-memory corruption, however we never got any reports from the check points for almost decade, let's remove the code, it can help to save memories.
Stable-dep-of: 2b8704b6a8b2 ("f2fs: fix to reset all pinned status during fggc")
--- fs/f2fs/segment.c | 38 -------------------------------------- fs/f2fs/segment.h | 6 ------ 2 files changed, 44 deletions(-)
fs/f2fs/segment.c +0 -38
@@ -2458,9 +2458,6 @@ static int update_sit_entry_for_release( unsigned int segno, block_t blkaddr, unsigned int offset, int del) { bool exist; -#ifdef CONFIG_F2FS_CHECK_FS -bool mir_exist; -#endif int i;int del_count = -del;
@@ -2468,15 +2465,6 @@ static int update_sit_entry_for_release(for (i =0 ; i < del_count; i++) { exist =f2fs_test_and_clear_bit (offset + i, se->cur_valid_map); -#ifdef CONFIG_F2FS_CHECK_FS - mir_exist =f2fs_test_and_clear_bit (offset + i, - se->cur_valid_map_mir); -if (unlikely (exist != mir_exist)) { -f2fs_err (sbi,"Inconsistent error when clearing bitmap, blk:%u, old bit:%d" , - blkaddr + i, exist); -f2fs_bug_on (sbi,1 ); - } -#endif if (unlikely (!exist)) {f2fs_err (sbi,"Bitmap was wrongly cleared, blk:%u" , blkaddr + i);f2fs_bug_on (sbi,1 );
@@ -2517,20 +2505,8 @@ static int update_sit_entry_for_alloc(st unsigned int segno, block_t blkaddr, unsigned int offset, int del) { bool exist; -#ifdef CONFIG_F2FS_CHECK_FS -bool mir_exist; -#endif exist =f2fs_test_and_set_bit (offset, se->cur_valid_map); -#ifdef CONFIG_F2FS_CHECK_FS - mir_exist =f2fs_test_and_set_bit (offset, - se->cur_valid_map_mir); -if (unlikely (exist != mir_exist)) { -f2fs_err (sbi,"Inconsistent error when setting bitmap, blk:%u, old bit:%d" , - blkaddr, exist); -f2fs_bug_on (sbi,1 ); - } -#endif if (unlikely (exist)) {f2fs_err (sbi,"Bitmap was wrongly set, blk:%u" , blkaddr);f2fs_bug_on (sbi,1 );
@@ -4761,11 +4737,6 @@ void f2fs_flush_sit_entries(struct f2fs_int offset, sit_offset; se =get_seg_entry (sbi, segno); -#ifdef CONFIG_F2FS_CHECK_FS -if (memcmp (se->cur_valid_map, se->cur_valid_map_mir, -SIT_VBLOCK_MAP_SIZE )) -f2fs_bug_on (sbi,1 ); -#endif /* add discard candidates */ if (!(cpc->reason &CP_DISCARD )) {
@@ -4856,11 +4827,7 @@ static int build_sit_info(struct f2fs_sbif (!sit_i->dirty_sentries_bitmap)return -ENOMEM ; -#ifdef CONFIG_F2FS_CHECK_FS - bitmap_size =MAIN_SEGS (sbi) *SIT_VBLOCK_MAP_SIZE * (3 + discard_map); -#else bitmap_size =MAIN_SEGS (sbi) *SIT_VBLOCK_MAP_SIZE * (2 + discard_map); -#endif sit_i->bitmap =f2fs_kvzalloc (sbi, bitmap_size,GFP_KERNEL );if (!sit_i->bitmap)return -ENOMEM ;
@@ -4874,11 +4841,6 @@ static int build_sit_info(struct f2fs_sb sit_i->sentries[start].ckpt_valid_map = bitmap; bitmap +=SIT_VBLOCK_MAP_SIZE ; -#ifdef CONFIG_F2FS_CHECK_FS - sit_i->sentries[start].cur_valid_map_mir = bitmap; - bitmap +=SIT_VBLOCK_MAP_SIZE ; -#endif -if (discard_map) { sit_i->sentries[start].discard_map = bitmap; bitmap +=SIT_VBLOCK_MAP_SIZE ;
fs/f2fs/segment.h +0 -6
@@ -172,9 +172,6 @@ struct seg_entry { unsigned int ckpt_valid_blocks:10; /* # of valid blocks last cp */ unsigned int padding:6; /* padding */unsigned char *cur_valid_map;/* validity bitmap of blocks */ -#ifdef CONFIG_F2FS_CHECK_FS -unsigned char *cur_valid_map_mir;/* mirror of current valid bitmap */ -#endif /* * # of valid blocks and the validity bitmap stored in the last * checkpoint pack. This information is used by the SSR mode.
@@ -403,9 +400,6 @@ static inline void seg_info_from_raw_sit se->ckpt_valid_blocks =GET_SIT_VBLOCKS (rs);memcpy (se->cur_valid_map, rs->valid_map,SIT_VBLOCK_MAP_SIZE );memcpy (se->ckpt_valid_map, rs->valid_map,SIT_VBLOCK_MAP_SIZE ); -#ifdef CONFIG_F2FS_CHECK_FS -memcpy (se->cur_valid_map_mir, rs->valid_map,SIT_VBLOCK_MAP_SIZE ); -#endif se->type =GET_SIT_TYPE (rs); se->mtime =le64_to_cpu (rs->mtime); }
Greg Kroah-Hartman
maintainerPATCH 1180/1250 f2fs: reject setattr size changes on large folio files
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wenjie Qi <[email protected]>
[ Upstream commit 242d30bfc0a84b8b5de0a88821b53c9ad7fd31c4 ]
F2FS large folios are only enabled for immutable non-compressed files. Writable open and writable mmap reject such mappings, but truncate(2) through f2fs_setattr() misses the same guard.
If FS_IMMUTABLE_FL is cleared while the inode is still cached, the mapping can keep large-folio support and ATTR_SIZE can change i_size. Reject size changes in that state.
Stable-dep-of: 2b8704b6a8b2 ("f2fs: fix to reset all pinned status during fggc")
--- fs/f2fs/file.c | 2 ++ 1 file changed, 2 insertions(+)
fs/f2fs/file.c +2 -0
@@ -1136,6 +1136,8 @@ int f2fs_setattr(struct mnt_idmap *idmapreturn -EPERM ;if ((attr->ia_valid &ATTR_SIZE )) { +if (mapping_large_folio_support (inode->i_mapping)) +return -EOPNOTSUPP ;if (!f2fs_is_compress_backend_ready (inode) ||IS_DEVICE_ALIASING (inode))return -EOPNOTSUPP ;
Greg Kroah-Hartman
maintainerPATCH 1181/1250 drm/amdgpu: Fix missing unwind in amdgpu_ib_schedule() error path
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Srinivasan Shanmugam <[email protected]>
[ Upstream commit ba038065655c45728be346d0b174a6da08d8a5c5 ]
amdgpu_ib_schedule() returns early after calling amdgpu_ring_undo(). This skips the common free_fence cleanup path. Other error paths were already changed to use goto free_fence, but this one was missed.
Change the early return to goto free_fence so all error paths clean up the same way.
Fixes the below:drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c:232 amdgpu_ib_schedule()
warn: missing unwind goto?
drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
124 int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned int num_ibs,
125 struct amdgpu_ib *ibs, struct amdgpu_job *job,
126 struct dma_fence **f)
127 {
...
224
225 if (ring->funcs->insert_start)
226 ring->funcs->insert_start(ring);
227
228 if (job) {
229 r = amdgpu_vm_flush(ring, job, need_pipe_sync);
230 if (r) {
231 amdgpu_ring_undo(ring);--> 232 return r;
The patch changed the other error paths to goto free_fence but
this one was accidentally skipped.
233 }
234 }
235
236 amdgpu_ring_ib_begin(ring);
...
338
339 free_fence:
340 if (!job)
341 kfree(af);
342 return r;
343 }Stable-dep-of: 6760f5cb12d2 ("drm/amdgpu: avoid force-completing uninitialized UVD rings")
--- drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c +1 -1
@@ -222,7 +222,7 @@ int amdgpu_ib_schedule(struct amdgpu_rin r =amdgpu_vm_flush (ring, job, need_pipe_sync);if (r) {amdgpu_ring_undo (ring); -return r; + goto free_fence; } }
Greg Kroah-Hartman
maintainerPATCH 1182/1250 drm/amdgpu: add a helper to calculate ring distance
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
[ Upstream commit 08e7d6c3cee880bd3ec3eb14c478f9fa805b0bdc ]
Add a helper to calculate the distance in DWs between two wptrs.
Stable-dep-of: 6760f5cb12d2 ("drm/amdgpu: avoid force-completing uninitialized UVD rings")
--- drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h +12 -6
@@ -516,6 +516,17 @@ static inline void amdgpu_ring_write_mul ring->count_dw -= count_dw; } +static inline unsigned int amdgpu_ring_get_dw_distance (struct amdgpu_ring *ring, +u64 start_wptr,u64 end_wptr) +{ +unsigned int start = start_wptr & ring->buf_mask; +unsigned int end = end_wptr & ring->buf_mask; + +if (end < start) + end += ring->ring_size >>2 ; +return end - start; +} +/** * amdgpu_ring_patch_cond_exec - patch dw count of conditional execute * @ring: amdgpu_ring structure
@@ -526,18 +537,13 @@ static inline void amdgpu_ring_write_mulstatic inline void amdgpu_ring_patch_cond_exec (struct amdgpu_ring *ring,unsigned int offset) { -unsigned cur; -if (!ring->funcs->init_cond_exec)return ;WARN_ON (offset > ring->buf_mask);WARN_ON (ring->ring[offset] !=0 ); - cur = (ring->wptr -1 ) & ring->buf_mask; -if (cur < offset) - cur += ring->ring_size >>2 ; - ring->ring[offset] = cur - offset; + ring->ring[offset] =amdgpu_ring_get_dw_distance (ring, offset, ring->wptr -1 ); }int amdgpu_ring_test_helper (struct amdgpu_ring *ring);
Greg Kroah-Hartman
maintainerPATCH 1183/1250 drm/amdgpu: reorder IB schedule sequence
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
[ Upstream commit d3499de3b737f3f6a2058382f7bff641c74f52a4 ]
This reorders the IB schedule sequence to cleanly
separate the vm operation from the IB submission.
This makes the two independent so we can cleanly
associate each one with its respective fence.
v2: fixes for VCN
Stable-dep-of: 6760f5cb12d2 ("drm/amdgpu: avoid force-completing uninitialized UVD rings")
--- drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c | 22 +++++++++++----------- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 11 +++++++++++ 2 files changed, 22 insertions(+), 11 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c +11 -11
@@ -208,16 +208,6 @@ int amdgpu_ib_schedule(struct amdgpu_rindma_fence_put (tmp); } -if ((ib->flags &AMDGPU_IB_FLAG_EMIT_MEM_SYNC ) && ring->funcs->emit_mem_sync) - ring->funcs->emit_mem_sync (ring); - -if (ring->funcs->emit_wave_limit && - ring->hw_prio ==AMDGPU_GFX_PIPE_PRIO_HIGH ) - ring->funcs->emit_wave_limit (ring, true); - -if (ring->funcs->insert_start) - ring->funcs->insert_start (ring); -if (job) { r =amdgpu_vm_flush (ring, job, need_pipe_sync);if (r) {
@@ -228,6 +218,16 @@ int amdgpu_ib_schedule(struct amdgpu_rinamdgpu_ring_ib_begin (ring); +if (ring->funcs->insert_start) + ring->funcs->insert_start (ring); + +if ((ib->flags &AMDGPU_IB_FLAG_EMIT_MEM_SYNC ) && ring->funcs->emit_mem_sync) + ring->funcs->emit_mem_sync (ring); + +if (ring->funcs->emit_wave_limit && + ring->hw_prio ==AMDGPU_GFX_PIPE_PRIO_HIGH ) + ring->funcs->emit_wave_limit (ring, true); +if (ring->funcs->emit_gfx_shadow && adev->gfx.cp_gfx_shadow)amdgpu_ring_emit_gfx_shadow (ring, shadow_va, csa_va, gds_va, init_shadow, vmid);
@@ -312,6 +312,7 @@ int amdgpu_ib_schedule(struct amdgpu_rin ring->hw_prio == AMDGPU_GFX_PIPE_PRIO_HIGH) ring->funcs->emit_wave_limit(ring, false); +amdgpu_ring_ib_end (ring);/* Save the wptr associated with this fence. * This must be last for resets to work properly * as we need to save the wptr associated with this
@@ -320,7 +321,6 @@ int amdgpu_ib_schedule(struct amdgpu_rin*/ amdgpu_fence_save_wptr (*f); -amdgpu_ring_ib_end (ring);amdgpu_ring_commit (ring);return 0 ;
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +11 -0
@@ -814,6 +814,17 @@ int amdgpu_vm_flush(struct amdgpu_ring *return 0 ;amdgpu_ring_ib_begin (ring); + +/* There is no matching insert_end for this on purpose for the vm flush. +* The IB portion of the submission has both. Having multiple +* insert_start sequences is ok, but you can only have one insert_end +* per submission based on the way VCN FW works. For JPEG +* you can as many insert_start and insert_end sequences as you like as +* long as the rest of the packets come between start and end sequences. +*/ +if (ring->funcs->insert_start) + ring->funcs->insert_start (ring); +if (ring->funcs->init_cond_exec) patch =amdgpu_ring_init_cond_exec (ring, ring->cond_exe_gpu_addr);
Greg Kroah-Hartman
maintainerPATCH 1184/1250 drm/amdgpu: Make amdgpu_vm_flush() non-failing in submission path
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Srinivasan Shanmugam <[email protected]>
[ Upstream commit 37872d06f85f0349e7b1f0680aea77326f7c135e ]
amdgpu_vm_flush() is used during job submission and is not expected to fail. Convert it to return void and simplify the caller.
Initialize the COND_EXEC patch location to 0 so it is safe to call amdgpu_ring_patch_cond_exec() when init_cond_exec is not supported.
Stable-dep-of: 6760f5cb12d2 ("drm/amdgpu: avoid force-completing uninitialized UVD rings")
--- drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c | 9 ++------- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 10 +++------- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h | 2 +- 3 files changed, 6 insertions(+), 15 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c +2 -7
@@ -208,13 +208,8 @@ int amdgpu_ib_schedule(struct amdgpu_rindma_fence_put (tmp); } -if (job) { - r =amdgpu_vm_flush (ring, job, need_pipe_sync); -if (r) { -amdgpu_ring_undo (ring); - goto free_fence; - } - } +if (job) +amdgpu_vm_flush (ring, job, need_pipe_sync);amdgpu_ring_ib_begin (ring);
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +3 -7
@@ -760,12 +760,9 @@ bool amdgpu_vm_need_pipeline_sync(struct* @need_pipe_sync: is pipe sync needed * * Emit a VM flush when it is necessary. -* -* Returns: -* 0 on success, errno otherwise. */ -int amdgpu_vm_flush (struct amdgpu_ring *ring,struct amdgpu_job *job, -bool need_pipe_sync) +void amdgpu_vm_flush (struct amdgpu_ring *ring,struct amdgpu_job *job, +bool need_pipe_sync) {struct amdgpu_device *adev = ring->adev; struct amdgpu_isolation *isolation =
@@ -811,7 +808,7 @@ int amdgpu_vm_flush(struct amdgpu_ring *if (!vm_flush_needed && !gds_switch_needed && !need_pipe_sync && !cleaner_shader_needed) -return 0 ; +return ;amdgpu_ring_ib_begin (ring);
@@ -902,7 +899,6 @@ int amdgpu_vm_flush(struct amdgpu_ring * }amdgpu_ring_ib_end (ring); -return 0 ; }/**
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h +1 -1
@@ -516,7 +516,7 @@ int amdgpu_vm_validate(struct amdgpu_devstruct ww_acquire_ctx *ticket, int (*callback)(void *p, struct amdgpu_bo *bo), void *param); -int amdgpu_vm_flush (struct amdgpu_ring *ring,struct amdgpu_job *job,bool need_pipe_sync); +void amdgpu_vm_flush (struct amdgpu_ring *ring,struct amdgpu_job *job,bool need_pipe_sync);int amdgpu_vm_update_pdes (struct amdgpu_device *adev,struct amdgpu_vm *vm,bool immediate); int amdgpu_vm_clear_freed(struct amdgpu_device *adev,
Greg Kroah-Hartman
maintainerPATCH 1185/1250 drm/amdgpu: plumb timedout fence through to force completion
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
[ Upstream commit c184df870db1e328691ea0fbb7d0e59efd9d3f9f ]
When we do a full adapter reset, if we know the timedout fence mark the fence with -ETIME rather than -ECANCELED so it gets properly handled by userspace.
v2: rebase
Stable adaptation: retain the existing fence helper declarations and use &job->hw_fence.base because this branch embeds the hardware fence in the job. Preserve the existing job-fence clearing during full adapter reset. Drop the VCN 4.0.3 and 5.0.1 JPEG reset call-site updates because their helpers do not exist on this branch; no new functions are introduced. The two-argument UVD completion call provides the context required by 6760f5cb12d2 ("drm/amdgpu: avoid force-completing uninitialized UVD rings").
Also restore the fallible amdgpu_vm_flush() interface and its caller's ring rollback. The preceding dependency 014ab3140cf9 converted it to void, but this stable branch still allocates a fence in amdgpu_fence_emit() and can return -ENOMEM. That left a value-return in a void function and broke both x86 and arm64 builds. Keep the error propagation rather than silently continuing submission after a failed flush. The job embeds its hardware fence here, so the caller can return after ring rollback without an additional fence-free path.
[ sashal: Reduced backport -- upstream c184df870db1e touches 9 file(s), this
backport carries 10. Not backported here:
drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c
This note is generated from the file lists only; see the resolution record for the reasoning. ]
Stable-dep-of: 6760f5cb12d2 ("drm/amdgpu: avoid force-completing uninitialized UVD rings")
--- drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 6 +++++- drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c | 26 ++++++++++++++++++++++---- drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c | 9 +++++++-- drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h | 3 ++- drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c | 21 +++++++++++++-------- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 10 +++++++--- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h | 2 +- 10 files changed, 61 insertions(+), 24 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c +1 -1
@@ -1960,7 +1960,7 @@ static int amdgpu_debugfs_ib_preempt(voi/* swap out the old fences */ amdgpu_ib_preempt_fences_swap (ring, fences); -amdgpu_fence_driver_force_completion (ring); +amdgpu_fence_driver_force_completion (ring,NULL );/* resubmit unfinished jobs */ amdgpu_ib_preempt_job_recovery (&ring->sched);
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +5 -1
@@ -5890,6 +5890,7 @@ int amdgpu_device_pre_asic_reset(struct {int i, r =0 ;struct amdgpu_job *job =NULL ; +struct dma_fence *fence =NULL ;struct amdgpu_device *tmp_adev = reset_context->reset_req_dev;bool need_full_reset =test_bit (AMDGPU_NEED_FULL_RESET , &reset_context->flags);
@@ -5902,6 +5903,9 @@ int amdgpu_device_pre_asic_reset(structamdgpu_fence_driver_isr_toggle (adev, true); +if (job) + fence = &job->hw_fence.base; +/* block all schedulers and reset given job's ring */ for (i =0 ; i <AMDGPU_MAX_RINGS ; ++i) {struct amdgpu_ring *ring = adev->rings[i];
@@ -5915,7 +5919,7 @@ int amdgpu_device_pre_asic_reset(structamdgpu_fence_driver_clear_job_fences (ring);/* after all hw jobs are reset, hw fence is meaningless, so force_completion */ -amdgpu_fence_driver_force_completion (ring); +amdgpu_fence_driver_force_completion (ring, fence); }amdgpu_fence_driver_isr_toggle (adev, false);
drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +22 -4
@@ -582,7 +582,7 @@ void amdgpu_fence_driver_hw_fini(struct r = -ENODEV ;/* no need to trigger GPU reset as we are unloading */ if (r) -amdgpu_fence_driver_force_completion (ring); +amdgpu_fence_driver_force_completion (ring,NULL ); if (!drm_dev_is_unplugged(adev_to_drm(adev)) && ring->fence_drv.irq_src &&
@@ -727,16 +727,34 @@ void amdgpu_fence_driver_set_error(struc* amdgpu_fence_driver_force_completion - force signal latest fence of ring * * @ring: fence of the ring to signal +* @timedout_fence: fence of the timedout job * */ -void amdgpu_fence_driver_force_completion (struct amdgpu_ring *ring) +void amdgpu_fence_driver_force_completion (struct amdgpu_ring *ring, +struct dma_fence *timedout_fence) { -amdgpu_fence_driver_set_error (ring, -ECANCELED ); +struct amdgpu_fence_driver *drv = &ring->fence_drv; +unsigned long flags; + +spin_lock_irqsave (&drv->lock, flags); +for (unsigned int i =0 ; i <= drv->num_fences_mask; ++i) { +struct dma_fence *fence; + + fence =rcu_dereference_protected (drv->fences[i], +lockdep_is_held (&drv->lock)); +if (fence && !dma_fence_is_signaled_locked (fence)) { +if (fence == timedout_fence) +dma_fence_set_error (fence, -ETIME ); +else +dma_fence_set_error (fence, -ECANCELED ); + } + } +spin_unlock_irqrestore (&drv->lock, flags); +amdgpu_fence_write (ring, ring->fence_drv.sync_seq);amdgpu_fence_process (ring); } -/* * Kernel queue reset handling *
drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c +7 -2
@@ -208,8 +208,13 @@ int amdgpu_ib_schedule(struct amdgpu_rindma_fence_put (tmp); } -if (job) -amdgpu_vm_flush (ring, job, need_pipe_sync); +if (job) { + r =amdgpu_vm_flush (ring, job, need_pipe_sync); +if (r) { +amdgpu_ring_undo (ring); +return r; + } + }amdgpu_ring_ib_begin (ring);
drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h +2 -1
@@ -154,7 +154,8 @@ extern const struct drm_sched_backend_opvoid amdgpu_fence_driver_clear_job_fences (struct amdgpu_ring *ring);void amdgpu_fence_driver_set_error (struct amdgpu_ring *ring,int error); -void amdgpu_fence_driver_force_completion (struct amdgpu_ring *ring); +void amdgpu_fence_driver_force_completion (struct amdgpu_ring *ring, +struct dma_fence *timedout_fence);void amdgpu_fence_driver_guilty_force_completion (struct amdgpu_fence *af);void amdgpu_fence_save_wptr (struct dma_fence *fence);
drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c +2 -2
@@ -600,10 +600,10 @@ exit:* to be submitted to the queues after the reset is complete. */ if (!ret) { -amdgpu_fence_driver_force_completion (gfx_ring); +amdgpu_fence_driver_force_completion (gfx_ring,NULL );drm_sched_wqueue_start (&gfx_ring->sched);if (adev->sdma.has_page_queue) { -amdgpu_fence_driver_force_completion (page_ring); +amdgpu_fence_driver_force_completion (page_ring,NULL );drm_sched_wqueue_start (&page_ring->sched); } }
drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +1 -1
@@ -516,7 +516,7 @@ int amdgpu_uvd_resume(struct amdgpu_devi }memset_io (ptr,0 , size);/* to restore uvd fence seq */ -amdgpu_fence_driver_force_completion (&adev->uvd.inst[i].ring); +amdgpu_fence_driver_force_completion (&adev->uvd.inst[i].ring,NULL ); } }return 0 ;
drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c +13 -8
@@ -1480,15 +1480,16 @@ int vcn_set_powergating_state(struct amd/** * amdgpu_vcn_reset_engine - Reset a specific VCN engine -* @adev: Pointer to the AMDGPU device -* @instance_id: VCN engine instance to reset +* @ring: Pointer to the VCN ring +* @timedout_fence: fence that timed out * * Returns: 0 on success, or a negative error code on failure. */ -static int amdgpu_vcn_reset_engine (struct amdgpu_device *adev, -uint32_t instance_id) +static int amdgpu_vcn_reset_engine (struct amdgpu_ring *ring, +struct amdgpu_fence *timedout_fence) { -struct amdgpu_vcn_inst *vinst = &adev->vcn.inst[instance_id]; +struct amdgpu_device *adev = ring->adev; +struct amdgpu_vcn_inst *vinst = &adev->vcn.inst[ring->me];int r, i;mutex_lock (&vinst->engine_reset_mutex);
@@ -1512,9 +1513,13 @@ static int amdgpu_vcn_reset_engine(strucif (r) goto unlock; } -amdgpu_fence_driver_force_completion (&vinst->ring_dec); +amdgpu_fence_driver_force_completion (&vinst->ring_dec, + (&vinst->ring_dec == ring) ? + &timedout_fence->base :NULL );for (i =0 ; i < vinst->num_enc_rings; i++) -amdgpu_fence_driver_force_completion (&vinst->ring_enc[i]); +amdgpu_fence_driver_force_completion (&vinst->ring_enc[i], + (&vinst->ring_enc[i] == ring) ? + &timedout_fence->base :NULL );/* Restart the scheduler's work queue for the dec and enc rings * if they were stopped by this function. This allows new tasks
@@ -1550,7 +1555,7 @@ int amdgpu_vcn_ring_reset(struct amdgpu_if (adev->vcn.inst[ring->me].using_unified_queue)return -EINVAL ; -return amdgpu_vcn_reset_engine (adev, ring->me); +return amdgpu_vcn_reset_engine (ring, timedout_fence); } int amdgpu_vcn_reg_dump_init(struct amdgpu_device *adev,
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +7 -3
@@ -760,9 +760,12 @@ bool amdgpu_vm_need_pipeline_sync(struct* @need_pipe_sync: is pipe sync needed * * Emit a VM flush when it is necessary. +* +* Returns: +* 0 on success, errno otherwise. */ -void amdgpu_vm_flush (struct amdgpu_ring *ring,struct amdgpu_job *job, -bool need_pipe_sync) +int amdgpu_vm_flush (struct amdgpu_ring *ring,struct amdgpu_job *job, +bool need_pipe_sync) {struct amdgpu_device *adev = ring->adev; struct amdgpu_isolation *isolation =
@@ -808,7 +811,7 @@ void amdgpu_vm_flush(struct amdgpu_ringif (!vm_flush_needed && !gds_switch_needed && !need_pipe_sync && !cleaner_shader_needed) -return ; +return 0 ;amdgpu_ring_ib_begin (ring);
@@ -899,6 +902,7 @@ void amdgpu_vm_flush(struct amdgpu_ring }amdgpu_ring_ib_end (ring); +return 0 ; }/**
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h +1 -1
@@ -516,7 +516,7 @@ int amdgpu_vm_validate(struct amdgpu_devstruct ww_acquire_ctx *ticket, int (*callback)(void *p, struct amdgpu_bo *bo), void *param); -void amdgpu_vm_flush (struct amdgpu_ring *ring,struct amdgpu_job *job,bool need_pipe_sync); +int amdgpu_vm_flush (struct amdgpu_ring *ring,struct amdgpu_job *job,bool need_pipe_sync);int amdgpu_vm_update_pdes (struct amdgpu_device *adev,struct amdgpu_vm *vm,bool immediate); int amdgpu_vm_clear_freed(struct amdgpu_device *adev,
Greg Kroah-Hartman
maintainerPATCH 1186/1250 drm/amdgpu: avoid force-completing uninitialized UVD rings
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bob Zhou <[email protected]>
[ Upstream commit 6760f5cb12d2366ddd58a2d8637f7583d73f596b ]
uvd_v7_0_sw_init() does not initialize the UVD decode ring for an SR-IOV VF. However, amdgpu_uvd_resume() unconditionally force-completes the decode ring when restoring its fence sequence.
Skip fence completion when the fence driver is not initialized.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +2 -1
@@ -516,7 +516,8 @@ int amdgpu_uvd_resume(struct amdgpu_devi }memset_io (ptr,0 , size);/* to restore uvd fence seq */ -amdgpu_fence_driver_force_completion (&adev->uvd.inst[i].ring,NULL ); +if (adev->uvd.inst[i].ring.fence_drv.initialized) +amdgpu_fence_driver_force_completion (&adev->uvd.inst[i].ring,NULL ); } }return 0 ;
Greg Kroah-Hartman
maintainerPATCH 1187/1250 i2c: designware: Global register definitions
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Heikki Krogerus <[email protected]>
[ Upstream commit 874ef9a6f2fc45d3f6021842d92fa5420fa4c825 ]
Moving the register definitions to a global header file include/linux/designware_i2c.h. That removes the need to duplicate them in the adaptation layers for this driver outside of drivers/i2c/busses/. There is at least one of those in drivers/gpu/drm/xe/xe_i2c.c.
Backport notes for 6.18:
Move the register definitions already present in this tree to the shared header. Omit the surrounding register-access and FIFO-depth constants from 518edab3ad4f6, since that independent cleanup is absent here.
Prepare the existing Xe register-write callback for 244abef7f280 by including the shared definitions, providing I2C_REG(), and adding a pass-through DW_IC_SMBUS_INTR_MASK case. Keep the adapter driver's mask
unchanged: the newer SMBus alert handler from f43fa4b8522ba is absent. Include bitfield.h explicitly for the target's FIELD_MODIFY() use. This lets the target cherry-pick cleanly without importing the newer interrupt implementation or adding any functions to this dependency.
Stable-dep-of: 244abef7f280 ("drm/xe/i2c: Keep the i2c controller always enabled")
--- MAINTAINERS | 1 drivers/gpu/drm/xe/regs/xe_i2c_regs.h | 2 drivers/gpu/drm/xe/xe_i2c.c | 12 ++- drivers/i2c/busses/i2c-designware-common.c | 2 drivers/i2c/busses/i2c-designware-core.h | 85 ----------------------- drivers/i2c/busses/i2c-designware-master.c | 2 drivers/i2c/busses/i2c-designware-slave.c | 2 include/linux/designware_i2c.h | 107 +++++++++++++++++++++++++++++ 8 files changed, 129 insertions(+), 84 deletions(-) create mode 100644 include/linux/designware_i2c.h
MAINTAINERS +1 -0
@@ -24964,6 +24964,7 @@ R: Jan Dabros <[email protected]> L: [email protected] S: Supported F: drivers/i2c/busses/i2c-designware-* +F: include/linux/designware_i2c.h SYNOPSYS DESIGNWARE I2C DRIVER - AMDISP M: Nirujogi Pratap <[email protected]>
drivers/gpu/drm/xe/regs/xe_i2c_regs.h +2 -0
@@ -17,4 +17,6 @@#define I2C_CONFIG_CMD XE_REG(I2C_CONFIG_SPACE_OFFSET + PCI_COMMAND)#define I2C_CONFIG_PMCSR XE_REG(I2C_CONFIG_SPACE_OFFSET + 0x84) +#define I2C_REG (reg) XE_REG((reg) + I2C_MEM_SPACE_OFFSET) +#endif /* _XE_I2C_REGS_H_ */
drivers/gpu/drm/xe/xe_i2c.c +11 -1
@@ -6,6 +6,7 @@*/ #include <linux/array_size.h> +#include <linux/bitfield.h> #include <linux/container_of.h> #include <linux/device.h> #include <linux/err.h>
@@ -23,6 +24,8 @@#include <linux/types.h> #include <linux/workqueue.h> +#include <linux/designware_i2c.h> +#include "regs/xe_i2c_regs.h" #include "regs/xe_irq_regs.h"
@@ -230,8 +233,15 @@ static int xe_i2c_write(void *context, u {struct xe_i2c *i2c = context; -xe_mmio_write32 (i2c->mmio,XE_REG (reg +I2C_MEM_SPACE_OFFSET ), val); +switch (reg) { +case DW_IC_SMBUS_INTR_MASK : +/* Preserve the interrupt mask requested by the adapter driver. */ +break ; +default : +break ; + } +xe_mmio_write32 (i2c->mmio,I2C_REG (reg), val);return 0 ; }
drivers/i2c/busses/i2c-designware-common.c +2 -0
@@ -32,6 +32,8 @@#include <linux/types.h> #include <linux/units.h> +#include <linux/designware_i2c.h> +#include "i2c-designware-core.h" static const char *const abort_sources[] = {
drivers/i2c/busses/i2c-designware-core.h +2 -83
106 lines not on this page · raw message
drivers/i2c/busses/i2c-designware-master.c +2 -0
@@ -25,6 +25,8 @@#include <linux/regmap.h> #include <linux/reset.h> +#include <linux/designware_i2c.h> +#include "i2c-designware-core.h" #define AMD_TIMEOUT_MIN_US 25
drivers/i2c/busses/i2c-designware-slave.c +2 -0
@@ -19,6 +19,8 @@#include <linux/pm_runtime.h> #include <linux/regmap.h> +#include <linux/designware_i2c.h> +#include "i2c-designware-core.h" static void i2c_dw_configure_fifo_slave (struct dw_i2c_dev *dev)
include/linux/designware_i2c.h new file +107 -0
107 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 1188/1250 drm/xe/i2c: Keep the i2c controller always enabled
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Heikki Krogerus <[email protected]>
[ Upstream commit 244abef7f280a6a84297bfab5fd2e77147bc419a ]
Some platforms make an assumption that the i2c controller's enabled state indicates also the power state of the controller. This can create a problem when the controller is in disabled state, because the hardware may assume incorrectly that it is then also in low-power state.
To fix this, the controller is kept enabled by taking over the IC_ENABLE register. The controller has to be disabled when the configuration is updated and when the target address or the slave address are assigned, so disabling it when IC_CON, IC_TAR or IC_SAR registers are programmed, and then re-enabling it again.
--- drivers/gpu/drm/xe/xe_i2c.c | 49 +++++++++++++++++++++++++++++++++++++++++++- drivers/gpu/drm/xe/xe_i2c.h | 1 2 files changed, 49 insertions(+), 1 deletion(-)
drivers/gpu/drm/xe/xe_i2c.c +48 -1
@@ -8,6 +8,7 @@#include <linux/array_size.h> #include <linux/bitfield.h> #include <linux/container_of.h> +#include <linux/delay.h> #include <linux/device.h> #include <linux/err.h> #include <linux/i2c.h>
@@ -220,11 +221,40 @@ static void xe_i2c_remove_irq(struct xe_irq_domain_remove (i2c->irqdomain); } +/* See "Disabling DW_apb_i2c" in the DesignWare DW_abp_i2c databook. */ +static void xe_i2c_disable (struct xe_i2c *i2c) +{ +int timeout =100 ; +u32 status; + +xe_mmio_rmw32 (i2c->mmio,I2C_REG (DW_IC_ENABLE ),DW_IC_ENABLE_ENABLE ,0 ); + +do { + status =xe_mmio_read32 (i2c->mmio,I2C_REG (DW_IC_ENABLE_STATUS )); +if (!(status &DW_IC_ENABLE_ENABLE )) +return ; +/* Can't sleep here. */ +udelay (25 ); + }while (timeout--); + +dev_warn (i2c->drm_dev,"timeout in disabling i2c adapter\n" ); +} +static int xe_i2c_read (void *context,unsigned int reg,unsigned int *val) {struct xe_i2c *i2c = context; - *val =xe_mmio_read32 (i2c->mmio,XE_REG (reg +I2C_MEM_SPACE_OFFSET )); + *val =xe_mmio_read32 (i2c->mmio,I2C_REG (reg)); + +switch (reg) { +case DW_IC_ENABLE : +case DW_IC_ENABLE_STATUS : +FIELD_MODIFY (DW_IC_ENABLE_ENABLE , val, + i2c->ic_enable &DW_IC_ENABLE_ENABLE ); +break ; +default : +break ; + }return 0 ; }
@@ -234,6 +264,23 @@ static int xe_i2c_write(void *context, ustruct xe_i2c *i2c = context;switch (reg) { +case DW_IC_CON : +case DW_IC_TAR : +case DW_IC_SAR : +/* Disable the controller. */ +xe_i2c_disable (i2c); + +/* Write the register. */ +xe_mmio_write32 (i2c->mmio,I2C_REG (reg), val); + +/* Enable the controller. */ +xe_mmio_rmw32 (i2c->mmio,I2C_REG (DW_IC_ENABLE ),0 ,DW_IC_ENABLE_ENABLE ); +return 0 ; +case DW_IC_ENABLE : + i2c->ic_enable = val; +/* Other fields can be updated except the enable bit. */ + val |=DW_IC_ENABLE_ENABLE ; +break ;case DW_IC_SMBUS_INTR_MASK :/* Preserve the interrupt mask requested by the adapter driver. */ break ;
drivers/gpu/drm/xe/xe_i2c.h +1 -0
@@ -34,6 +34,7 @@ struct xe_i2c {struct platform_device *pdev;struct i2c_adapter *adapter;struct i2c_client *client[XE_I2C_MAX_CLIENTS ]; +unsigned int ic_enable;struct notifier_block bus_notifier;struct work_struct work;
Greg Kroah-Hartman
maintainerPATCH 1189/1250 drm/pagemap: dma-unmap pages before handling migration errors
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Brost <[email protected]>
[ Upstream commit 9e6372ec2a3990662ae0a67f56ac0aee19848d5b ]
drm_pagemap_migrate_unmap_pages() relies on the pages array to determine which pages require DMA unmapping. However, drm_pagemap_migration_unlock_put_pages() clears the array as part of its cleanup, leaving drm_pagemap_migrate_unmap_pages() with no valid page information if it is called afterward.
Call drm_pagemap_migrate_unmap_pages() before drm_pagemap_migration_unlock_put_pages() so the pages array remains valid during DMA unmapping.
--- drivers/gpu/drm/drm_pagemap.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/gpu/drm/drm_pagemap.c +5 -5
@@ -606,12 +606,12 @@ retry: goto err_finalize; err_finalize: +drm_pagemap_migrate_unmap_pages (devmem_allocation->dev, pagemap_addr, npages, +DMA_FROM_DEVICE );if (err)drm_pagemap_migration_unlock_put_pages (npages, dst);migrate_device_pages (src, dst, npages);migrate_device_finalize (src, dst, npages); -drm_pagemap_migrate_unmap_pages (devmem_allocation->dev, pagemap_addr, npages, -DMA_FROM_DEVICE ); err_free:kvfree (buf); err_out:
@@ -742,13 +742,13 @@ static int __drm_pagemap_migrate_to_ram( goto err_finalize; err_finalize: +if (dev) +drm_pagemap_migrate_unmap_pages (dev, pagemap_addr, npages, +DMA_FROM_DEVICE );if (err)drm_pagemap_migration_unlock_put_pages (npages, migrate.dst);migrate_vma_pages (&migrate);migrate_vma_finalize (&migrate); -if (dev) -drm_pagemap_migrate_unmap_pages (dev, pagemap_addr, npages, -DMA_FROM_DEVICE ); err_free:kvfree (buf); err_out:
Greg Kroah-Hartman
maintainerPATCH 1190/1250 ipmr: account multicast table and route memory
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zihan Xi <[email protected]>
[ Upstream commit b7ee18725f2292ab554aa96a101ae42d45f008bd ]
A netadmin in a user+net namespace can create many IPv4 and IPv6 multicast routing tables with MRT_TABLE and MRT6_TABLE. Each unseen id allocates an mr_table via the shared mr_table_alloc(), links it into the per-net list, and leaves it until netns teardown. Those objects were not charged to memcg, so the host unreclaimable slab grows with the table count.
Account mr_table allocations with GFP_KERNEL_ACCOUNT and mark the IPv4/IPv6 MFC caches SLAB_ACCOUNT. This matches the established handling of IP addresses, routes and alternate interface names.
Unresolved MFC entries are still allocated from softIRQ with GFP_ATOMIC and are not charged. They expire after 10 seconds and are bounded by the socket receive queue; see commit 0079ad8e8dc3 ("ipmr: remove hard code cache_resolve_queue_len limit").
--- net/ipv4/ipmr.c | 3 ++- net/ipv4/ipmr_base.c | 2 +- net/ipv6/ip6mr.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-)
net/ipv4/ipmr.c +2 -1
@@ -3325,7 +3325,8 @@ int __init ip_mr_init(void) {int err; - mrt_cachep =KMEM_CACHE (mfc_cache,SLAB_HWCACHE_ALIGN |SLAB_PANIC ); + mrt_cachep =KMEM_CACHE (mfc_cache, +SLAB_HWCACHE_ALIGN |SLAB_PANIC |SLAB_ACCOUNT ); err =register_pernet_subsys (&ipmr_net_ops);if (err)
net/ipv4/ipmr_base.c +1 -1
@@ -52,7 +52,7 @@ mr_table_alloc(struct net *net, u32 id,struct mr_table *mrt;int err; - mrt =kzalloc (sizeof (*mrt),GFP_KERNEL ); + mrt =kzalloc (sizeof (*mrt),GFP_KERNEL_ACCOUNT );if (!mrt)return ERR_PTR (-ENOMEM ); mrt->id = id;
net/ipv6/ip6mr.c +1 -1
@@ -1393,7 +1393,7 @@ int __init ip6_mr_init(void) {int err; - mrt_cachep =KMEM_CACHE (mfc6_cache,SLAB_HWCACHE_ALIGN ); + mrt_cachep =KMEM_CACHE (mfc6_cache,SLAB_HWCACHE_ALIGN |SLAB_ACCOUNT );if (!mrt_cachep)return -ENOMEM ;
Greg Kroah-Hartman
maintainerPATCH 1191/1250 configfs: unhash the dentry before dropping the item in rmdir
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vasileios Almpanis <[email protected]>
[ Upstream commit f06c2d26d1999d37e93299db0ecead04ca7d0b9f ]
configfs_get_config_item() treats a hashed dentry as proof that sd->s_element is a live config_item. configfs_rmdir() breaks that:simple_rmdir() leaves the dentry hashed, the last reference to the item is dropped right after, and the dentry is only unhashed by d_delete() once ->rmdir() has returned. configfs_symlink() resolves its target holding no lock on it, so get_target() can land in that window:
BUG: KASAN: slab-use-after-free in config_item_get+0x26/0x90 get_target fs/configfs/symlink.c:128 [inline] configfs_symlink+0x4ab/0x1030 fs/configfs/symlink.c:185
Unhash in configfs_remove_dir(), while the item is still guaranteed to be there. A reference obtained just before that stays harmless, as create_link() rechecks CONFIGFS_USET_DROPPING, already set by configfs_detach_prep(). Both configfs_unregister_subsystem() paths d_drop() after detaching, so this only makes rmdir match them.
--- fs/configfs/dir.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
fs/configfs/dir.c +11 -2
@@ -401,8 +401,17 @@ static void remove_dir(struct dentry * dconfigfs_remove_dirent (d); -if (d_really_is_positive (d)) -simple_rmdir (d_inode (parent),d); +if (d_really_is_positive (d)) { +if (!simple_rmdir (d_inode (parent), d)) +/* +* configfs_get_config_item() takes a hashed dentry as +* proof that ->s_element is still alive. Our caller +* is about to drop the last reference to the item and +* the VFS will not unhash until after we return, so +* unhash it here. +*/ +d_drop (d); + }pr_debug (" o %pd removing done (%d)\n" , d,d_count (d));
Greg Kroah-Hartman
maintainerPATCH 1192/1250 x86/mm/pat: Convert split_large_page() to use ptdescs
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Vishal Moola (Oracle)" <[email protected]>
[ Upstream commit e751303e0ad2e998f421d104193f6904df3516d1 ]
Use the ptdesc APIs for all page table allocation and free sites to allow their separate allocation from struct page in the future.
Update split_large_page() to allocate a ptdesc instead of allocating a page for use as a page table.
Stable-dep-of: 9e4a3ec3411b ("x86/mm/pat: Allocate split page tables as kernel page tables")
--- arch/x86/mm/pat/set_memory.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
arch/x86/mm/pat/set_memory.c +7 -6
@@ -1138,9 +1138,10 @@ set:static int __split_large_page (struct cpa_data *cpa,pte_t *kpte,unsigned long address, -struct page *base) +struct ptdesc *ptdesc) {unsigned long lpaddr, lpinc, ref_pfn, pfn, pfninc =1 ; +struct page *base =ptdesc_page (ptdesc);pte_t *pbase = (pte_t *)page_address (base);unsigned int i, level;pgprot_t ref_prot;
@@ -1245,18 +1246,18 @@ __split_large_page(struct cpa_data *cpa,static int split_large_page (struct cpa_data *cpa,pte_t *kpte,unsigned long address) { -struct page *base; +struct ptdesc *ptdesc;if (!debug_pagealloc_enabled ())spin_unlock (&cpa_lock); - base =alloc_pages (GFP_KERNEL ,0 ); + ptdesc =pagetable_alloc (GFP_KERNEL ,0 );if (!debug_pagealloc_enabled ())spin_lock (&cpa_lock); -if (!base) +if (!ptdesc)return -ENOMEM ; -if (__split_large_page (cpa, kpte, address, base)) -__free_page (base); +if (__split_large_page (cpa, kpte, address, ptdesc)) +pagetable_free (ptdesc);return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 1193/1250 x86/mm/pat: Dont gate cpa_lock on debug_pagealloc_enabled()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Mike Rapoport (Microsoft)" <[email protected]>
[ Upstream commit 5fce67641a3ed9a0782eaa228ddece526461a367 ]
The splitting and merging of kernel page table mappings between small and large is protected by cpa_lock. The merging is relatively new but the splitting is ancient.
The splitting has a locking optimization: since DEBUG_PAGEALLOC forces all mappings to 4k, there are no large pages to split. So the code that *might* cause a split can just skip the locking (and a few other things).
This is entertaining, but it adds complexity and makes for weird locking rules. Plus it's all for a debugging feature which makes the kernel super slow in the first place. Optimizing something which is already super slow and not used in production is not the best way to spend our complexity budget.
Stop gating cpa_lock on debug_pagealloc_enabled() to simplify the code and the locking rules.
[ dhansen: flesh out changelog ]
Stable-dep-of: 9e4a3ec3411b ("x86/mm/pat: Allocate split page tables as kernel page tables")
--- arch/x86/mm/pat/set_memory.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-)
arch/x86/mm/pat/set_memory.c +7 -12
@@ -63,10 +63,9 @@ enum cpa_warn {static const int cpa_warn_level =CPA_PROTECT ;/* -* Serialize cpa() (for !DEBUG_PAGEALLOC which uses large identity mappings) -* using cpa_lock. So that we don't allow any other cpu, with stale large tlb -* entries change the page attribute in parallel to some other cpu -* splitting a large page entry along with changing the attribute. +* Serialize cpa() using cpa_lock so that we don't allow any other cpu, with +* stale large tlb entries, to change the page attribute in parallel to some +* other cpu splitting a large page entry along with changing the attribute. */ static DEFINE_SPINLOCK (cpa_lock);
@@ -1248,11 +1247,9 @@ static int split_large_page(struct cpa_d {struct ptdesc *ptdesc; -if (!debug_pagealloc_enabled ()) -spin_unlock (&cpa_lock); +spin_unlock (&cpa_lock); ptdesc =pagetable_alloc (GFP_KERNEL ,0 ); -if (!debug_pagealloc_enabled ()) -spin_lock (&cpa_lock); +spin_lock (&cpa_lock);if (!ptdesc)return -ENOMEM ;
@@ -2024,11 +2021,9 @@ static int __change_page_attr_set_clr(stif (cpa->flags & (CPA_ARRAY |CPA_PAGES_ARRAY )) cpa->numpages =1 ; -if (!debug_pagealloc_enabled ()) -spin_lock (&cpa_lock); +spin_lock (&cpa_lock); ret =__change_page_attr (cpa, primary); -if (!debug_pagealloc_enabled ()) -spin_unlock (&cpa_lock); +spin_unlock (&cpa_lock);if (ret) goto out;
Greg Kroah-Hartman
maintainerPATCH 1194/1250 x86/mm/pat: Acquire init_mm read lock on attribute changes to avoid UAF
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Lorenzo Stoakes (ARM)" <[email protected]>
[ Upstream commit d5d8b8662e6e5a565b47a0388640e88402f23274 ]
A previous commit protected against races between ptdump and CPA collapse, however one still exists between attribute changes and collapse as reported by Denis V. Lunev (linked).
When an attribute change arises, a lockless page table walker obtains a PTE entry, which is later written to via set_pte_atomic():
...
-> change_page_attr_set_clr()
-> __change_page_attr_set_clr()
-> __change_page_attr()
-> _lookup_address_cpa() -> lookup_address_in_pgd_attr() -> [ lockless page table walker ]
-> set_pte_atomic()
There is nothing preventing a concurrent CPA collapse which can free the PTE that was retrieved here, resulting in a use-after-free.
With the mmap write lock taken on init_mm over CPA collapse, resolve this race by acquiring an mmap read lock on init_mm over __change_page_attr_set_clr().
This locks across the whole operation over which the walk and the PTE entry write occurs, solving the race.
It is safe to do this here, as no spinlocks are held upon entry to __change_page_attr_set_clr().
However, the lock must not be held over an allocation, as allocation can trigger reclaim and shrinkers may call into CPA recursively, making deadlocks possible (init_mm -> ... -> fs_reclaim -> init_mm).
A page table is allocated when a huge page needs to be split:
-> change_page_attr_set_clr()
-> __change_page_attr_set_clr()
-> __change_page_attr()
-> split_large_page()
[ pagetable_alloc() ]
-> __split_large_page()
Avoid deadlocks by dropping the mmap lock across pagetable_alloc() in split_large_page() and track whether this is needed by adding a new 'init_mm_read_locked' flag to struct cpa_data.
This is safe as __split_large_page() (called with locks re-established) revalidates that the page table entry is the same as it was prior to the locks being dropped and __change_page_attr() repeats the entire page table walk whenever a split occurs, so concurrent split and collapse are accounted for.
Concurrent ptdump is also safe as the lock is only dropped over page table allocation during which time the page table has not yet been modified.
The CPA_COLLAPSE flag is only set by set_memory_rox(), which exclusively operates upon vmalloc ranges, and on x86 only within the module mapping space.
This is important, because some callers directly invoke __change_page_attr_set_clr(), bypassing this lock. However, none of these operate within the module mapping space.
* cpa_process_alias() - a recursive helper called by
__change_page_attr_set_clr().
* __set_memory_enc_pgtable() - operates on the direct mapping and (via __vmbus_establish_gpadl()) the vmalloc mapping space.
* __set_pages_[n]p() - called by set_direct_map_[invalid, default, valid]_noflush(), __kernel_map_pages() - operates on the direct map.
* kernel_[un]map_pages_in_pgd() - operates on EFI ranges.
This work is based upon Denis V. Lunev's excellent analysis of the bug with gratitude.
[ dhansen: move to imperative voice in changelog ]
Stable-dep-of: 9e4a3ec3411b ("x86/mm/pat: Allocate split page tables as kernel page tables")
--- arch/x86/mm/pat/set_memory.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
arch/x86/mm/pat/set_memory.c +11 -2
@@ -50,7 +50,8 @@ struct cpa_data {unsigned int flags; unsigned int force_split : 1, force_static_prot : 1, - force_flush_all : 1; + force_flush_all : 1, + init_mm_read_locked : 1;struct page **pages; };
@@ -1248,7 +1249,11 @@ static int split_large_page(struct cpa_dstruct ptdesc *ptdesc;spin_unlock (&cpa_lock); +if (cpa->init_mm_read_locked) +mmap_read_unlock (&init_mm); ptdesc =pagetable_alloc (GFP_KERNEL ,0 ); +if (cpa->init_mm_read_locked) +mmap_read_lock (&init_mm);spin_lock (&cpa_lock);if (!ptdesc)return -ENOMEM ;
@@ -2105,7 +2110,11 @@ static int change_page_attr_set_clr(unsi cpa.curpage =0 ; cpa.force_split = force_split; - ret =__change_page_attr_set_clr (&cpa,1 ); +/* Avoid race with concurrent CPA collapse. */ + cpa.init_mm_read_locked = true; +scoped_guard (mmap_read_lock, &init_mm) + ret = __change_page_attr_set_clr(&cpa, 1); + cpa.init_mm_read_locked = false;/* * Check whether we really changed something:
Greg Kroah-Hartman
maintainerPATCH 1195/1250 x86/mm/pat: Allocate split page tables as kernel page tables
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Lorenzo Stoakes (ARM)" <[email protected]>
[ Upstream commit 9e4a3ec3411bb6bb59e3c1f29b75609f1e87aac4 ]
A PTE is allocated directly without going through the standard page table allocation routines (such as pte_alloc_one_kernel()) when the CPA code splits a large page (__split_large_page()).
This means the page table constructor is never called nor is the page table marked as a kernel page table.
The former results in the folio associated with the page table not being marked as a page table (__pagetable_ctor() is never called thus neither is __folio_set_pgtable()) nor are statistics updated to reflect it (lruvec_stat_add_folio() is never called).
The latter issue of failing to mark the page table as a kernel page table (ptdesc_set_kernel() is never called) is far more problematic.
Since commit:
5ba2f0a15564 ("mm: introduce deferred freeing for kernel page tables")
kernel page table freeing has been batched and since the subsequent commit:
e37d5a2d60a3 ("iommu/sva: invalidate stale IOTLB entries for kernel address space")
IOTLB cache entries for kernel page tables have been invalidated upon being freed.
Since split page tables are freed without this invalidation, the IOTLB can contain stale entries for them.
Resolve the issue by using the ordinary PTE allocation API at split time.
This results in these kernel page tables invoking a page table constructor, and thus requires a page table destructor.
Destructors are not always present, like for early allocated direct map page tables). Conditionally call pagetable_dtor_free() if the PG_table folio flag for the ptdesc is set, otherwise we free the page table via pagetable_free().
Regardless of which path is taken page tables marked as kernel page tables, which now includes split page tables, take the correct route through pagetable_free_kernel().
There is a user-visible side effect in that split page tables will appear in nr_page_table_pages in /proc/vmstat (as do other kernel page tables allocated after early boot), however this is a positive change.
This issue started being markedly problematic after commit:
5ba2f0a15564 ("mm: introduce deferred freeing for kernel page tables")
so choose this as the Fixes target.
[ dhansen: rephrase in imperative mood ]
--- arch/x86/mm/pat/set_memory.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-)
arch/x86/mm/pat/set_memory.c +16 -9
@@ -434,7 +434,15 @@ static void __cpa_collapse_large_pages(slist_for_each_entry_safe (ptdesc, tmp, &pgtables, pt_list) {list_del (&ptdesc->pt_list); -pagetable_free (ptdesc); +/* +* Only early alloc'd direct map should not be flagged PG_table +* here and those shouldn't be collapsed. However be abundantly +* cautious and handle the !PG_table case too. +*/ +if (PageTable ((ptdesc_page (ptdesc)))) +pagetable_dtor_free (ptdesc); +else +pagetable_free (ptdesc); }spin_unlock (&cpa_lock);
@@ -1138,11 +1146,10 @@ set:static int __split_large_page (struct cpa_data *cpa,pte_t *kpte,unsigned long address, -struct ptdesc *ptdesc) +pte_t *pbase) {unsigned long lpaddr, lpinc, ref_pfn, pfn, pfninc =1 ; -struct page *base =ptdesc_page (ptdesc); -pte_t *pbase = (pte_t *)page_address (base); +struct page *base =virt_to_page (pbase);unsigned int i, level;pgprot_t ref_prot;bool nx, rw;
@@ -1246,20 +1253,20 @@ __split_large_page(struct cpa_data *cpa,static int split_large_page (struct cpa_data *cpa,pte_t *kpte,unsigned long address) { -struct ptdesc *ptdesc; +pte_t *pte;spin_unlock (&cpa_lock);if (cpa->init_mm_read_locked)mmap_read_unlock (&init_mm); - ptdesc =pagetable_alloc (GFP_KERNEL ,0 ); + pte =pte_alloc_one_kernel (&init_mm);if (cpa->init_mm_read_locked)mmap_read_lock (&init_mm);spin_lock (&cpa_lock); -if (!ptdesc) +if (!pte)return -ENOMEM ; -if (__split_large_page (cpa, kpte, address, ptdesc)) -pagetable_free (ptdesc); +if (__split_large_page (cpa, kpte, address, pte)) +pte_free_kernel (&init_mm, pte);return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 1196/1250 init/main: read bootconfig header with get_unaligned_le32()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sun Jian <[email protected]>
[ Upstream commit 499f86de4f8c34e19a57daf2b6f0cba848e91994 ]
get_boot_config_from_initrd() scans up to 3 bytes before initrd_end to handle GRUB 4-byte alignment. As a result, the bootconfig header immediately preceding the magic may be unaligned.
Read the size and checksum fields with get_unaligned_le32() instead of casting to u32 * and using le32_to_cpu(), avoiding potential unaligned access and silencing sparse "cast to restricted __le32" warnings.
Sparse warnings (gcc + C=1):
init/main.c:292:16: warning: cast to restricted __le32 init/main.c:293:16: warning: cast to restricted __le32
No functional change intended.
Stable-dep-of: 7812d6dab069 ("bootconfig: Fix integer overflow in initrd size check")
--- init/main.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
init/main.c +5 -4
@@ -104,6 +104,7 @@#include <linux/pidfs.h> #include <linux/ptdump.h> #include <linux/time_namespace.h> +#include <linux/unaligned.h> #include <net/net_namespace.h> #include <asm/io.h>
@@ -269,7 +270,7 @@ static void * __init get_boot_config_fro {u32 size, csum;char *data; -u32 *hdr; +u8 *hdr;int i;if (!initrd_end)
@@ -288,9 +289,9 @@ static void * __init get_boot_config_froreturn NULL ; found: - hdr = (u32 *)(data -8 ); - size =le32_to_cpu (hdr[0 ]); - csum =le32_to_cpu (hdr[1 ]); + hdr = (u8 *)(data -8 ); + size =get_unaligned_le32 (hdr); + csum =get_unaligned_le32 (hdr +4 ); data = ((void *)hdr) - size;if ((unsigned long )data < initrd_start) {
Greg Kroah-Hartman
maintainerPATCH 1197/1250 bootconfig: Fix integer overflow in initrd size check
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Masami Hiramatsu (Google)" <[email protected]>
[ Upstream commit 7812d6dab0698001e50e8c2f901e17da3eb6f429 ]
Sashiko reported that in get_boot_config_from_initrd(), a crafted initrd with a huge bootconfig size (such as 0xFFFFFFFF) can cause the pointer arithmetic:
data = ((void *)hdr) - size;
to wrap around on 32-bit systems (or when pointer subtraction overflows). Because data wraps around, the subsequent bounds check:
if ((unsigned long)data < initrd_start)
evaluates to false, bypassing the check. The kernel then calls xbc_calc_checksum(data, size), which attempts to read 4GB of memory, hitting unmapped pages and triggering a fatal kernel page fault during early boot. Furthermore, on 64-bit systems with an initrd > 4.29 GB, an unbounded 32-bit size can similarly bypass the initrd_start check.
Fix this by:
1. Ensuring the initrd is at least large enough to contain the bootconfig footer and verifying hdr is within the initrd bounds.
2. Checking that size does not exceed XBC_DATA_MAX and does not exceed the available space between initrd_start and hdr before performing pointer subtraction.
--- init/main.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-)
init/main.c +15 -10
@@ -273,7 +273,8 @@ static void * __init get_boot_config_frou8 *hdr;int i; -if (!initrd_end) +if (!initrd_end || initrd_end < initrd_start || + initrd_end - initrd_start <BOOTCONFIG_MAGIC_LEN +8 )return NULL ; data = (char *)initrd_end -BOOTCONFIG_MAGIC_LEN ;
@@ -290,16 +291,26 @@ static void * __init get_boot_config_fro found: hdr = (u8 *)(data -8 ); +if ((unsigned long )hdr < initrd_start) +return NULL ; + size =get_unaligned_le32 (hdr); csum =get_unaligned_le32 (hdr +4 ); - data = ((void *)hdr) - size; -if ((unsigned long )data < initrd_start) { -pr_err ("bootconfig size %d is greater than initrd size %ld\n" , +if (size >XBC_DATA_MAX ) { +pr_err ("bootconfig size %u is greater than max size %d\n" , + size,XBC_DATA_MAX ); +return NULL ; + } + +if (size > ((unsigned long )hdr - initrd_start)) { +pr_err ("bootconfig size %u is greater than initrd size %lu\n" , size, initrd_end - initrd_start);return NULL ; } + data = ((void *)hdr) - size; +if (xbc_calc_checksum (data, size) != csum) {pr_err ("bootconfig checksum failed\n" );return NULL ;
@@ -402,12 +413,6 @@ static void __init setup_boot_config(voireturn ; } -if (size >=XBC_DATA_MAX ) { -pr_err ("bootconfig size %ld greater than max size %d\n" , - (long )size,XBC_DATA_MAX ); -return ; - } - ret =xbc_init (data, size, &msg, &pos);if (ret <0 ) {if (pos <0 )
Greg Kroah-Hartman
maintainerPATCH 1198/1250 genetlink: pin family module during policy dump
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: XingWang Xiang <[email protected]>
[ Upstream commit 6a1094c34d176827b2b173e163dcc964a13af93f ]
The generic netlink controller's policy dump keeps pointers to the target family's operation and policy tables in its callback state. A dump may be split across multiple skbs and remain pending after the initial request.
Netlink pins the module which owns the dump callback, but in this case that is the controller's owner rather than the target family's owner. The target family can consequently be unregistered and its module unloaded while a policy dump is pending. Advancing the dump then dereferences policy memory from the unloaded module.
Take a reference to the target family's module when the dump starts. Drop it from the error and done paths. This matches the lifetime for which the dump context retains the family and policy pointers.
--- net/netlink/genetlink.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-)
net/netlink/genetlink.c +16 -5
@@ -1514,6 +1514,7 @@ struct ctrl_dump_policy_ctx {struct netlink_policy_dump_state *state;const struct genl_family *rt;struct genl_op_iter *op_iter; +struct module *owner;u32 op;u16 fam_id; u8 dump_map:1,
@@ -1556,6 +1557,9 @@ static int ctrl_dumppolicy_start(structreturn -ENOENT ; ctx->rt = rt; + ctx->owner = rt->module; +if (!try_module_get (ctx->owner)) +return -ENOENT ;if (tb[CTRL_ATTR_OP ]) {struct genl_split_ops doit, dump;
@@ -1566,7 +1570,7 @@ static int ctrl_dumppolicy_start(struct err =genl_get_cmd_both (ctx->op, rt, &doit, &dump);if (err) {NL_SET_BAD_ATTR (cb->extack, tb[CTRL_ATTR_OP ]); -return err; + goto err_put_owner; }if (doit.policy) {
@@ -1584,16 +1588,20 @@ static int ctrl_dumppolicy_start(struct goto err_free_state; } -if (!ctx->state) -return -ENODATA ; +if (!ctx->state) { + err = -ENODATA ; + goto err_put_owner; + } ctx->dump_map =1 ;return 0 ; } ctx->op_iter =kmalloc (sizeof (*ctx->op_iter),GFP_KERNEL ); -if (!ctx->op_iter) -return -ENOMEM ; +if (!ctx->op_iter) { + err = -ENOMEM ; + goto err_put_owner; + }genl_op_iter_init (rt, ctx->op_iter); ctx->dump_map =genl_op_iter_next (ctx->op_iter);
@@ -1625,6 +1633,8 @@ err_free_state:netlink_policy_dump_free (ctx->state); err_free_op_iter:kfree (ctx->op_iter); +err_put_owner: +module_put (ctx->owner);return err; }
@@ -1761,6 +1771,7 @@ static int ctrl_dumppolicy_done(struct nkfree (ctx->op_iter);netlink_policy_dump_free (ctx->state); +module_put (ctx->owner);return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 1199/1250 io_uring/rw: end write accounting from ->ki_complete
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jens Axboe <[email protected]>
[ Upstream commit 796aa0547557e63338657ed1c487906f9fac4c73 ]
Commit b000145e9907 moved both the fsnotify calls and the write accounting out of the kiocb completion handler and into the io_req_rw_complete() task_work. However, only the fsnotify part actually needed to move as it may sleep. Ending the write accounting is just a percpu_up_read() on the superblock writers sem.
Deferring it is a problem, because it makes dropping SB_FREEZE_WRITE protection depend on the ring owner getting to running task_work. But the task may be blocked in freeze_super(), causing it to never get to that:
task io-wq worker
--------------------------------------------------------------
io_write()
io_kiocb_start_write() (takes sb_writers, hidden from
lockdep by __sb_writers_release)
write_iter() -> -EIOCBQUEUED
ioctl(FS_IOC_SHUTDOWN)
bdev_freeze()
freeze_super()
percpu_down_write() <- waits for the reader above
io_write()
kiocb_start_write()
percpu_down_read() <- queued
behind the writer
<bio completes>
io_complete_rw()
queues io_req_rw_complete() <- never runs, task is in D state
End the write from io_complete_rw() instead, and leave only the fsnotify calls in task_work.
--- io_uring/rw.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-)
io_uring/rw.c +13 -12
@@ -532,20 +532,15 @@ static void io_req_end_write(struct io_k } } -/* -* Trigger the notifications after having done some IO, and finish the write -* accounting, if any. -*/ -static void io_req_io_end (struct io_kiocb *req) +/* Trigger the notifications after having done some IO. */ +static void io_req_io_notify (struct io_kiocb *req) { struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw); -if (rw->kiocb.ki_flags &IOCB_WRITE ) { -io_req_end_write (req); +if (rw->kiocb.ki_flags &IOCB_WRITE )fsnotify_modify (req->file); - }else { +else fsnotify_access (req->file); - } }static void __io_complete_rw_common (struct io_kiocb *req,long res)
@@ -586,7 +581,7 @@ void io_req_rw_complete(struct io_tw_reqio_req_set_res (req,io_fixup_rw_res (req, res),0 ); } -io_req_io_end (req); +io_req_io_notify (req);if (req->flags & (REQ_F_BUFFER_SELECTED |REQ_F_BUFFER_RING )) req->cqe.flags |=io_put_kbuf (req, req->cqe.res,NULL );
@@ -600,6 +595,10 @@ static void io_complete_rw(struct kiocb struct io_rw *rw = container_of(kiocb, struct io_rw, kiocb);struct io_kiocb *req =cmd_to_io_kiocb (rw); +/* ring owner may block in freeze_super() before task_work runs */ +if (kiocb->ki_flags &IOCB_WRITE ) +io_req_end_write (req); +if (!kiocb->dio_complete || !(kiocb->ki_flags &IOCB_DIO_CALLER_COMP )) {__io_complete_rw_common (req, res);io_req_set_res (req,io_fixup_rw_res (req, res),0 );
@@ -675,10 +674,12 @@ static int kiocb_done(struct io_kiocb *r__io_complete_rw_common (req, ret);/* -* Safe to call io_end from here as we're inline +* Safe to notify from here as we're inline * from the submission path. */ -io_req_io_end (req); +if (rw->kiocb.ki_flags &IOCB_WRITE ) +io_req_end_write (req); +io_req_io_notify (req);if (sel) cflags =io_put_kbuf (req, ret, sel->buf_list);io_req_set_res (req, final_ret, cflags);
Greg Kroah-Hartman
maintainerPATCH 1200/1250 drm/amd/display: Rebuild InfoFrames on output color space changes
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Satyajit Roy <[email protected]>
[ Upstream commit 8cfd9e22eb5c04b15b82985ff913944f84673d4f ]
resource_build_info_frame() derives colorimetry and RGB quantization from stream->output_color_space. A Broadcast RGB-only atomic commit updates that field and reprograms the output CSC, but none of the InfoFrame update predicates include output_color_space. The sink can therefore retain the previous AVI InfoFrame range while the source starts transmitting a different pixel range.
Treat an output color space change as an InfoFrame change in update classification and in both stream programming paths.
Hardware testing on an HDMI 2.1 television confirmed that its automatic black-level selection follows Full to Limited and Limited to Full transitions in SDR, HDR, and HDR with VRR active, without a modeset or visible link blank.
--- drivers/gpu/drm/amd/display/dc/core/dc.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/display/dc/core/dc.c +1 -0
@@ -3602,6 +3602,7 @@ static void commit_planes_do_stream_upda dc->hwss.setup_periodic_interrupt (dc, pipe_ctx); if ((stream_update->hdr_static_metadata && !stream->use_dynamic_meta) || + stream_update->output_color_space || stream_update->vrr_infopacket || stream_update->vsc_infopacket || stream_update->vsp_infopacket ||
Greg Kroah-Hartman
maintainerPATCH 1201/1250 drm/xe: Flush LSC untyped L1 dataport cache after rcs/ccs batches
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Hellström <[email protected]>
[ Upstream commit f5fcf7e638b904397ec0f66d3ea6766ef0cfe25b ]
emit_render_cache_flush() sets PIPE_CONTROL0_HDC_PIPELINE_FLUSH to flush the L2/HDC data cache before fence signalling, but it never requests a flush of the LSC untyped L1 data cache via the 'Untyped Data-Port Cache Flush Enable' bit in PIPE_CONTROL DWord0[11].
Per the Bspec, in 3D pipeline mode HDC Pipeline Flush is documented to also flush/invalidate the untyped L1 cache, but only depending on how HDC_CHICKEN0[13:11] is programmed. Starting with MTL, this coupling between HDC Pipeline Flush and the untyped L1 cache flush no longer holds in practice, regardless of how HDC_CHICKEN0 is programmed, so relying on it is not safe on newer platforms such as BMG. Mesa's Vulkan driver (anv) has been assuming the kernel flushes both caches between submissions, and hit user-visible corruption in apps such as Llama.cpp because of this gap; it now works around it by flushing both caches again from userspace at the end of every command buffer.
Correctness between submissions on the same queue is userspace's responsibility and belongs in Mesa, not the kernel. However, for security we must ensure stale data can't leak through the untyped L1 dataport cache once memory is reclaimed or evicted, which requires the KMD to flush it before releasing memory for reuse.
Prior to MTL, HDC_CHICKEN0 could be programmed (as already done for DG2 via Wa_22010960976/Wa_14013347512) to reliably keep HDC Pipeline Flush coupled to the untyped L1 cache flush, so those platforms are unaffected. Mesa's own anv driver found that on MTL the HW disconnected the two independently of how HDC_CHICKEN0 is programmed, and could not bring the old behavior back even by writing the register by hand; see Mesa commit 7c2ff46a4fc3 ("anv: don't prevent L1 untyped cache flush in 3D mode"). The kernel can't reliably request the flush from the CS on MTL either, so restrict the new PIPE_CONTROL bit to GRAPHICS_VERx100 >= 2000 (Xe2 and later), where it can be relied on.
Explicitly set PIPE_CONTROL0_UNTYPED_DATAPORT_CACHE_FLUSH together with PIPE_CONTROL0_HDC_PIPELINE_FLUSH in emit_render_cache_flush() on Xe2 and later, so the L1 data cache is known clean before memory is released for reuse, without depending on undocumented platform-specific HDC_CHICKEN0 behavior.
Bspec: 56551
--- drivers/gpu/drm/xe/instructions/xe_gpu_commands.h | 1 + drivers/gpu/drm/xe/xe_ring_ops.c | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-)
drivers/gpu/drm/xe/instructions/xe_gpu_commands.h +1 -0
@@ -41,6 +41,7 @@#define GFX_OP_PIPE_CONTROL (len) ((0x3<<29)|(0x3<<27)|(0x2<<24)|((len)-2)) +#define PIPE_CONTROL0_UNTYPED_DATAPORT_CACHE_FLUSH BIT(11)/* gen12 */ #define PIPE_CONTROL0_L3_READ_ONLY_CACHE_INVALIDATE BIT(10)/* gen12 */ #define PIPE_CONTROL0_HDC_PIPELINE_FLUSH BIT(9)/* gen12 */
drivers/gpu/drm/xe/xe_ring_ops.c +14 -2
@@ -176,13 +176,25 @@ static int emit_store_imm_ppgtt_posted(ustatic int emit_render_cache_flush (struct xe_sched_job *job,u32 *dw,int i) {struct xe_gt *gt = job->q->gt; +struct xe_device *xe =gt_to_xe (gt);bool lacks_render = !(gt->info.engine_mask &XE_HW_ENGINE_RCS_MASK ); -u32 flags; +u32 flags0, flags;if (XE_GT_WA (gt,14016712196 )) i =emit_pipe_control (dw, i,0 ,PIPE_CONTROL_DEPTH_CACHE_FLUSH ,LRC_PPHWSP_FLUSH_INVAL_SCRATCH_ADDR ,0 ); + flags0 =PIPE_CONTROL0_HDC_PIPELINE_FLUSH ; +/* +* Prior to MTL, HDC Pipeline Flush reliably also flushes the LSC +* untyped L1 dataport cache, provided HDC_CHICKEN0 is programmed +* correctly. Starting with MTL that coupling no longer holds +* regardless of how HDC_CHICKEN0 is programmed, but explicitly +* requesting the flush via PIPE_CONTROL is itself only reliable +* from Xe2 onward, so only gate it in on Xe2+. +*/ +if (GRAPHICS_VERx100 (xe) >=2000 ) + flags0 |=PIPE_CONTROL0_UNTYPED_DATAPORT_CACHE_FLUSH ; flags = (PIPE_CONTROL_CS_STALL | PIPE_CONTROL_TILE_CACHE_FLUSH | PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH |
@@ -198,7 +210,7 @@ static int emit_render_cache_flush(strucelse if (job->q->class ==XE_ENGINE_CLASS_COMPUTE ) flags &= ~PIPE_CONTROL_3D_ENGINE_FLAGS ; -return emit_pipe_control (dw, i,PIPE_CONTROL0_HDC_PIPELINE_FLUSH , flags,0 ,0 ); +return emit_pipe_control (dw, i, flags0, flags,0 ,0 ); }static int emit_pipe_control_to_ring_end (struct xe_hw_engine *hwe,u32 *dw,int i)
Greg Kroah-Hartman
maintainerPATCH 1202/1250 drm/amd/display: Propagate HDMI RGB quantization selectability
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Satyajit Roy <[email protected]>
[ Upstream commit bdcd0411d7d186225a52458fd42bb70d54ca917a ]
DC uses dc_edid_caps.qs_bit when constructing the HDMI AVI InfoFrame quantization-range field. Although DRM parses the sink capability into drm_display_info, DM never copies it into the DC EDID capabilities. The field therefore remains zero and the AVI quantization range stays at its default value.
Copy rgb_quant_range_selectable for HDMI sinks and extend the existing EDID-capability KUnit test to cover it.
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +3 -0
@@ -156,6 +156,9 @@ enum dc_edid_status dm_helpers_parse_edi edid_caps->edid_hdmi = connector->display_info.is_hdmi; +if (edid_caps->edid_hdmi) + edid_caps->qs_bit = connector->display_info.rgb_quant_range_selectable; +apply_edid_quirks (link, edid_buf, edid_caps); sad_count =drm_edid_to_sad ((struct edid *) edid->raw_edid, &sads);
Greg Kroah-Hartman
maintainerPATCH 1203/1250 drm/amd/display: Honor Broadcast RGB for BT.2020 RGB output
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Satyajit Roy <[email protected]>
[ Upstream commit 7fca7acd60a228b62b4e9efa5f184738041e9564 ]
amdgpu_dm_get_output_color_space() applies the Broadcast RGB connector property to default RGB output, but always selects full-range output for BT.2020 RGB. Consequently, explicitly selecting Limited has no effect on the output CSC or AVI InfoFrame when HDR uses BT.2020 RGB.
Select COLOR_SPACE_2020_RGB_LIMITEDRANGE when the output encoding is RGB and Broadcast RGB is Limited. Keep Automatic and Full at full range, and leave YCbCr output unchanged.
Add KUnit coverage for limited-range RGB output through both BT.2020 connector colorspace values.
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +7 -3
@@ -6511,10 +6511,14 @@ get_output_color_space(const struct dc_cbreak ;case DRM_MODE_COLORIMETRY_BT2020_RGB :case DRM_MODE_COLORIMETRY_BT2020_YCC : -if (dc_crtc_timing->pixel_encoding ==PIXEL_ENCODING_RGB ) - color_space =COLOR_SPACE_2020_RGB_FULLRANGE ; -else +if (dc_crtc_timing->pixel_encoding ==PIXEL_ENCODING_RGB ) { +if (connector_state->hdmi.broadcast_rgb ==DRM_HDMI_BROADCAST_RGB_LIMITED ) + color_space =COLOR_SPACE_2020_RGB_LIMITEDRANGE ; +else + color_space =COLOR_SPACE_2020_RGB_FULLRANGE ; + }else { color_space =COLOR_SPACE_2020_YCBCR_LIMITED ; + }break ;case DRM_MODE_COLORIMETRY_DEFAULT :// ITU601 default :
Greg Kroah-Hartman
maintainerPATCH 1204/1250 drm/bridge: ti-sn65dsi83: Fix error handling in sn65dsi83_reset_work()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Esben Haabendal <[email protected]>
commit 4600b4d1a9ee730d03ddac5ce409cd2730ce8c0c upstream.
The error handling of sn65dsi83_reset_pipe() in sn65dsi83_reset_work() has seen a couple of changes that seems to cause a bit of confusion.
While sn65dsi83_reset_work() has implemented an early exit if sn65dsi83_reset_pipe() fails since it was added, when a commit from Maxime Ripard switched to use drm_bridge_helper_reset_crtc() [1] the sn65dsi83_reset_pipe() function would no longer return an error code, so the early exit was then a no-op, and even on sn65dsi83_reset_pipe() failure, enable_irq() has been called.
When drm_bridge_enter()/drm_bridge_exit() resource protection was added, the drm_bridge_exit() incidentally was always called, which is the correct approach. But only because the early exit in sn65dsi83_reset_pipe() was never hit because sn65dsi83_reset_pipe() always returns 0.
In order get back to a situation where enable_irq() is not called on sn65dsi83_reset_pipe() failure, which should help protect against irq storms, we need to reintroduce a non-zero return value from sn65dsi83_reset_pipe() on error, and fix sn65dsi83_reset_work() so that we always exit the DRM bridge critical section with drm_bridge_exit().
[1] commit e17fadff7ab9 ("drm/bridge: ti-sn65dsi83: Switch to drm_bridge_helper_reset_crtc")
[2] commit d2e8d1bc840b ("drm/bridge: ti-sn65dsi83: protect device resources on unplug")
--- drivers/gpu/drm/bridge/ti-sn65dsi83.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/bridge/ti-sn65dsi83.c +2 -1
@@ -399,7 +399,7 @@ retry:drm_modeset_drop_locks (&ctx);drm_modeset_acquire_fini (&ctx); -return 0 ; +return err; }static void sn65dsi83_reset_work (struct work_struct *ws)
@@ -413,6 +413,7 @@ static void sn65dsi83_reset_work(structdev_err (ctx->dev,"reset pipe failed %pe\n" ,ERR_PTR (ret));return ; } +if (ctx->irq)enable_irq (ctx->irq); }
Greg Kroah-Hartman
maintainerPATCH 1205/1250 xfs: initialise args->total for parent pointer updates
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Javier Tia <[email protected]>
commit 8e4ebb6afaa34bd2e8ce52da231003d24111c2d6 upstream.
xfs_parent_da_args_init() builds an xfs_da_args from a zeroed xfs_parent_args (kmem_cache_zalloc), leaving args->total == 0. xfs_da_grow_inode_int() treats that field as a running block reservation and subtracts from it; because it is an xfs_extlen_t (uint32_t), the first attr-fork growth wraps it to ~0U. That defeats the free-space check in xfs_alloc_space_available(), and when it coincides with an AG that has exactly zero available blocks the allocation is clamped to maxlen 0 and returns -ENOSPC, which xfs_defer_finish_noroll() escalates to a filesystem shutdown.
Set args->total the way the log recovery path does (xfs_attri_recover_work(), xfs_attr_item.c:706), in the add and replace paths that can grow the fork. Removals and lookups never grow it, so they leave the field alone, matching that switch.
[ Backported to 6.12.y and 6.18.y, whose fs/xfs/libxfs/xfs_parent.c are
byte-identical. These trees queue the operation with xfs_attr_defer_add() instead of calling xfs_attr_setname() and xfs_attr_replacename() directly, and spell the inode number child->i_ino rather than I_INO(child), so the upstream hunks do not apply as-is. The defect is unchanged: xfs_attr_defer_add() stores a pointer to this same xfs_da_args, and xfs_attr_finish_item() resets only args->trans, so the zeroed total still reaches xfs_da_grow_inode_int(). The assignment therefore goes in the same place, before the operation is queued. xfs_attr_calc_size() needs no new include: it is declared in xfs_attr.h, which xfs_parent.c already includes. ]
--- fs/xfs/libxfs/xfs_parent.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
fs/xfs/libxfs/xfs_parent.c +11 -2
@@ -193,7 +193,7 @@ xfs_parent_addname(const struct xfs_name *parent_name, struct xfs_inode *child) { - int error; + int error, local; error =xfs_parent_iread_extents (tp, child);if (error)
@@ -202,6 +202,11 @@ xfs_parent_addname(xfs_inode_to_parent_rec (&ppargs->rec, dp);xfs_parent_da_args_init (&ppargs->args, tp, &ppargs->rec, child, child->i_ino, parent_name); + +/* Growing the attr fork needs a real reservation in args->total. */ + ppargs->args.total =xfs_attr_calc_size (&ppargs->args, &local); +ASSERT (local); +xfs_attr_defer_add (&ppargs->args,XFS_ATTR_DEFER_SET );return 0 ; }
@@ -239,7 +244,7 @@ xfs_parent_replacename(const struct xfs_name *new_name, struct xfs_inode *child) { - int error; + int error, local; error =xfs_parent_iread_extents (tp, child);if (error)
@@ -249,6 +254,10 @@ xfs_parent_replacename(xfs_parent_da_args_init (&ppargs->args, tp, &ppargs->rec, child, child->i_ino, old_name); +/* Growing the attr fork needs a real reservation in args->total. */ + ppargs->args.total =xfs_attr_calc_size (&ppargs->args, &local); +ASSERT (local); +xfs_inode_to_parent_rec (&ppargs->new_rec, new_dp); ppargs->args.new_name = new_name->name; ppargs->args.new_namelen = new_name->len;
Greg Kroah-Hartman
maintainerPATCH 1206/1250 tracing: Remove get_trigger_ops() and add count_func() from trigger ops
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit bdafb4d4cb3bb18b29517eaae09fb49d25f854f0 ]
The struct event_command has a callback function called get_trigger_ops(). This callback returns the "trigger_ops" to use for the trigger. These ops define the trigger function, how to init the trigger, how to print the trigger and how to free it.
The only reason there's a callback function to get these ops is because some triggers have two types of operations. One is an "always on" operation, and the other is a "count down" operation. If a user passes in a parameter to say how many times the trigger should execute. For example:
echo stacktrace:5 > events/kmem/kmem_cache_alloc/trigger
It will trigger the stacktrace for the first 5 times the kmem_cache_alloc event is hit.
Instead of having two different trigger_ops since the only difference between them is the tigger itself (the print, init and free functions are all the same), just use a single ops that the event_command points to and add a function field to the trigger_ops to have a count_func.
When a trigger is added to an event, if there's a count attached to it and the trigger ops has the count_func field, the data allocated to represent this trigger will have a new flag set called COUNT.
Then when the trigger executes, it will check if the COUNT data flag is set, and if so, it will call the ops count_func(). If that returns false, it returns without executing the trigger.
This removes the need for duplicate event_trigger_ops structures.
Stable-dep-of: 6ede78d0563a ("tracing: Set the trace clock before registering the histogram trigger")
--- kernel/trace/trace.h | 26 ++- kernel/trace/trace_eprobe.c | 8 - kernel/trace/trace_events_hist.c | 60 -------- kernel/trace/trace_events_trigger.c | 257 ++++++++++++------------------------ 4 files changed, 116 insertions(+), 235 deletions(-)
kernel/trace/trace.h +18 -8
@@ -1758,6 +1758,7 @@ extern void clear_event_triggers(structenum {EVENT_TRIGGER_FL_PROBE =BIT (0 ), +EVENT_TRIGGER_FL_COUNT =BIT (1 ), };struct event_trigger_data {
@@ -1789,6 +1790,10 @@ struct enable_trigger_data {bool hist; }; +bool event_trigger_count (struct event_trigger_data *data, +struct trace_buffer *buffer,void *rec, +struct ring_buffer_event *event); +extern int event_enable_trigger_print (struct seq_file *m,struct event_trigger_data *data);extern void event_enable_trigger_free (struct event_trigger_data *data);
@@ -1876,6 +1881,11 @@ extern void event_file_put(struct trace_* registered the trigger (see struct event_command) along with * the trace record, rec. * +* @count_func: If defined and a numeric parameter is passed to the +* trigger, then this function will be called before @trigger +* is called. If this function returns false, then @trigger is not +* executed. +* * @init: An optional initialization function called for the trigger * when the trigger is registered (via the event_command reg() * function). This can be used to perform per-trigger
@@ -1903,6 +1913,10 @@ struct event_trigger_ops {struct trace_buffer *buffer, void *rec, struct ring_buffer_event *rbe); +bool (*count_func)(struct event_trigger_data *data, +struct trace_buffer *buffer, +void *rec, +struct ring_buffer_event *rbe);int (*init)(struct event_trigger_data *data);void (*free)(struct event_trigger_data *data); int (*print)(struct seq_file *m,
@@ -1929,6 +1943,9 @@ struct event_trigger_ops {* @name: The unique name that identifies the event command. This is * the name used when setting triggers via trigger files. * +* @trigger_ops: The event_trigger_ops implementation associated with +* the command. +* * @trigger_type: A unique id that identifies the event command * 'type'. This value has two purposes, the first to ensure that * only one trigger of the same type can be set at a given time
@@ -1980,17 +1997,11 @@ struct event_trigger_ops {* event command, filters set by the user for the command will be * ignored. This is usually implemented by the generic utility * function @set_trigger_filter() (see trace_event_triggers.c). -* -* @get_trigger_ops: The callback function invoked to retrieve the -* event_trigger_ops implementation associated with the command. -* This callback function allows a single event_command to -* support multiple trigger implementations via different sets of -* event_trigger_ops, depending on the value of the @param -* string. */ struct event_command {struct list_head list;char *name; +const struct event_trigger_ops *trigger_ops;enum event_trigger_type trigger_type;int flags; int (*parse)(struct event_command *cmd_ops,
@@ -2007,7 +2018,6 @@ struct event_command {int (*set_filter)(char *filter_str,struct event_trigger_data *data,struct trace_event_file *file); -const struct event_trigger_ops *(*get_trigger_ops)(char *cmd,char *param); };/**
kernel/trace/trace_eprobe.c +1 -7
@@ -514,21 +514,15 @@ static void eprobe_trigger_unreg_func(ch } -static const struct event_trigger_ops *eprobe_trigger_get_ops (char *cmd, -char *param) -{ -return &eprobe_trigger_ops; -} -static struct event_command event_trigger_cmd = { .name ="eprobe" , .trigger_type =ETT_EVENT_EPROBE , .flags =EVENT_CMD_FL_NEEDS_REC , + .trigger_ops = &eprobe_trigger_ops, .parse = eprobe_trigger_cmd_parse, .reg = eprobe_trigger_reg_func, .unreg = eprobe_trigger_unreg_func, .unreg_all =NULL , - .get_trigger_ops = eprobe_trigger_get_ops, .set_filter =NULL , };
kernel/trace/trace_events_hist.c +5 -55
115 lines not on this page · raw message
kernel/trace/trace_events_trigger.c +92 -165
476 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 1207/1250 tracing: Merge struct event_trigger_ops into struct event_command
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit b052d70f7c9c156409a70e65c10d83b5650e7e78 ]
Now that there's pretty much a one to one mapping between the struct event_trigger_ops and struct event_command, there's no reason to have two different structures. Merge the function pointers of event_trigger_ops into event_command.
There's one exception in trace_events_hist.c for the event_hist_trigger_named_ops. This has special logic for the init and free function pointers for "named histograms". In this case, allocate the cmd_ops of the event_trigger_data and set it to the proper init and free functions, which are used to initialize and free the event_trigger_data respectively. Have the free function and the init function (on failure) free the cmd_ops of the data element.
Stable-dep-of: 6ede78d0563a ("tracing: Set the trace clock before registering the histogram trigger")
--- kernel/trace/trace.h | 126 ++++++++++++++---------------------- kernel/trace/trace_eprobe.c | 13 +-- kernel/trace/trace_events_hist.c | 93 +++++++++++++------------- kernel/trace/trace_events_trigger.c | 121 +++++++++++++--------------------- 4 files changed, 151 insertions(+), 202 deletions(-)
kernel/trace/trace.h +51 -75
@@ -1765,7 +1765,6 @@ struct event_trigger_data {unsigned long count;int ref;int flags; -const struct event_trigger_ops *ops;struct event_command *cmd_ops;struct event_filter __rcu *filter;char *filter_str;
@@ -1857,73 +1856,6 @@ extern void event_file_get(struct trace_extern void event_file_put (struct trace_event_file *file);/** -* struct event_trigger_ops - callbacks for trace event triggers -* -* The methods in this structure provide per-event trigger hooks for -* various trigger operations. -* -* The @init and @free methods are used during trigger setup and -* teardown, typically called from an event_command's @parse() -* function implementation. -* -* The @print method is used to print the trigger spec. -* -* The @trigger method is the function that actually implements the -* trigger and is called in the context of the triggering event -* whenever that event occurs. -* -* All the methods below, except for @init() and @free(), must be -* implemented. -* -* @trigger: The trigger 'probe' function called when the triggering -* event occurs. The data passed into this callback is the data -* that was supplied to the event_command @reg() function that -* registered the trigger (see struct event_command) along with -* the trace record, rec. -* -* @count_func: If defined and a numeric parameter is passed to the -* trigger, then this function will be called before @trigger -* is called. If this function returns false, then @trigger is not -* executed. -* -* @init: An optional initialization function called for the trigger -* when the trigger is registered (via the event_command reg() -* function). This can be used to perform per-trigger -* initialization such as incrementing a per-trigger reference -* count, for instance. This is usually implemented by the -* generic utility function @event_trigger_init() (see -* trace_event_triggers.c). -* -* @free: An optional de-initialization function called for the -* trigger when the trigger is unregistered (via the -* event_command @reg() function). This can be used to perform -* per-trigger de-initialization such as decrementing a -* per-trigger reference count and freeing corresponding trigger -* data, for instance. This is usually implemented by the -* generic utility function @event_trigger_free() (see -* trace_event_triggers.c). -* -* @print: The callback function invoked to have the trigger print -* itself. This is usually implemented by a wrapper function -* that calls the generic utility function @event_trigger_print() -* (see trace_event_triggers.c). -*/ -struct event_trigger_ops { -void (*trigger)(struct event_trigger_data *data, -struct trace_buffer *buffer, -void *rec, -struct ring_buffer_event *rbe); -bool (*count_func)(struct event_trigger_data *data, -struct trace_buffer *buffer, -void *rec, -struct ring_buffer_event *rbe); -int (*init)(struct event_trigger_data *data); -void (*free)(struct event_trigger_data *data); -int (*print)(struct seq_file *m, -struct event_trigger_data *data); -}; - -/** * struct event_command - callbacks and data members for event commands * * Event commands are invoked by users by writing the command name
@@ -1943,9 +1875,6 @@ struct event_trigger_ops {* @name: The unique name that identifies the event command. This is * the name used when setting triggers via trigger files. * -* @trigger_ops: The event_trigger_ops implementation associated with -* the command. -* * @trigger_type: A unique id that identifies the event command * 'type'. This value has two purposes, the first to ensure that * only one trigger of the same type can be set at a given time
@@ -1975,7 +1904,7 @@ struct event_trigger_ops {* * @reg: Adds the trigger to the list of triggers associated with the * event, and enables the event trigger itself, after -* initializing it (via the event_trigger_ops @init() function). +* initializing it (via the event_command @init() function). * This is also where commands can use the @trigger_type value to * make the decision as to whether or not multiple instances of * the trigger should be allowed. This is usually implemented by
@@ -1984,7 +1913,7 @@ struct event_trigger_ops {* * @unreg: Removes the trigger from the list of triggers associated * with the event, and disables the event trigger itself, after -* initializing it (via the event_trigger_ops @free() function). +* initializing it (via the event_command @free() function). * This is usually implemented by the generic utility function * @unregister_trigger() (see trace_event_triggers.c). *
@@ -1997,11 +1926,46 @@ struct event_trigger_ops {* event command, filters set by the user for the command will be * ignored. This is usually implemented by the generic utility * function @set_trigger_filter() (see trace_event_triggers.c). +* +* All the methods below, except for @init() and @free(), must be +* implemented. +* +* @trigger: The trigger 'probe' function called when the triggering +* event occurs. The data passed into this callback is the data +* that was supplied to the event_command @reg() function that +* registered the trigger (see struct event_command) along with +* the trace record, rec. +* +* @count_func: If defined and a numeric parameter is passed to the +* trigger, then this function will be called before @trigger +* is called. If this function returns false, then @trigger is not +* executed. +* +* @init: An optional initialization function called for the trigger +* when the trigger is registered (via the event_command reg() +* function). This can be used to perform per-trigger +* initialization such as incrementing a per-trigger reference +* count, for instance. This is usually implemented by the +* generic utility function @event_trigger_init() (see +* trace_event_triggers.c). +* +* @free: An optional de-initialization function called for the +* trigger when the trigger is unregistered (via the +* event_command @reg() function). This can be used to perform +* per-trigger de-initialization such as decrementing a +* per-trigger reference count and freeing corresponding trigger +* data, for instance. This is usually implemented by the +* generic utility function @event_trigger_free() (see +* trace_event_triggers.c). +* +* @print: The callback function invoked to have the trigger print +* itself. This is usually implemented by a wrapper function +* that calls the generic utility function @event_trigger_print() +* (see trace_event_triggers.c). */ struct event_command {struct list_head list;char *name; -const struct event_trigger_ops *trigger_ops;enum event_trigger_type trigger_type;int flags; int (*parse)(struct event_command *cmd_ops,
@@ -2018,6 +1982,18 @@ struct event_command {int (*set_filter)(char *filter_str,struct event_trigger_data *data,struct trace_event_file *file); +void (*trigger)(struct event_trigger_data *data, +struct trace_buffer *buffer, +void *rec, +struct ring_buffer_event *rbe); +bool (*count_func)(struct event_trigger_data *data, +struct trace_buffer *buffer, +void *rec, +struct ring_buffer_event *rbe); +int (*init)(struct event_trigger_data *data); +void (*free)(struct event_trigger_data *data); +int (*print)(struct seq_file *m, +struct event_trigger_data *data); };/**
@@ -2038,7 +2014,7 @@ struct event_command {* either committed or discarded. At that point, if any commands * have deferred their triggers, those commands are finally * invoked following the close of the current event. In other -* words, if the event_trigger_ops @func() probe implementation +* words, if the event_command @func() probe implementation * itself logs to the trace buffer, this flag should be set, * otherwise it can be left unspecified. *
kernel/trace/trace_eprobe.c +4 -9
@@ -485,13 +485,6 @@ static void eprobe_trigger_func(struct e__eprobe_trace_func (edata, rec); } -static const struct event_trigger_ops eprobe_trigger_ops = { - .trigger = eprobe_trigger_func, - .print = eprobe_trigger_print, - .init = eprobe_trigger_init, - .free = eprobe_trigger_free, -}; - static int eprobe_trigger_cmd_parse(struct event_command *cmd_ops, struct trace_event_file *file, char *glob, char *cmd,
@@ -518,12 +511,15 @@ static struct event_command event_trigge .name = "eprobe", .trigger_type = ETT_EVENT_EPROBE, .flags = EVENT_CMD_FL_NEEDS_REC, - .trigger_ops = &eprobe_trigger_ops, .parse = eprobe_trigger_cmd_parse, .reg = eprobe_trigger_reg_func, .unreg = eprobe_trigger_unreg_func, .unreg_all = NULL, .set_filter = NULL, + .trigger = eprobe_trigger_func, + .print = eprobe_trigger_print, + .init = eprobe_trigger_init, + .free = eprobe_trigger_free, }; static struct event_trigger_data *
@@ -543,7 +539,6 @@ new_eprobe_trigger(struct trace_eprobe * trigger->flags =EVENT_TRIGGER_FL_PROBE ; trigger->count =-1 ; - trigger->ops = &eprobe_trigger_ops;/* * EVENT PROBE triggers are not registered as commands with
kernel/trace/trace_events_hist.c +48 -45
194 lines not on this page · raw message
kernel/trace/trace_events_trigger.c +48 -73
268 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 1208/1250 tracing: Set the trace clock before registering the histogram trigger
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Donggeun Yoo <[email protected]>
[ Upstream commit 6ede78d0563a2a3ae3e46f9c07cedb5d79645429 ]
hist_register_trigger() puts the trigger on the global named_triggers list in cmd_ops->init(), and only then sets the trace clock:
if (data->cmd_ops->init) {
ret = data->cmd_ops->init(data);
if (ret < 0)
goto out;
}
if (hist_data->enable_timestamps) {
ret = tracing_set_clock(file->tr, hist_data->attrs->clock);
if (ret) {
hist_err(tr, HIST_ERR_SET_CLOCK_FAIL, errpos(clock));
goto out;
}The clock string is not checked anywhere before that call, so a named trigger using common_timestamp with an unknown clock fails after it has already become findable. event_hist_trigger_parse() then frees it without taking it off the list, and the next lookup by name reads the freed object:
~# cd /sys/kernel/tracing/events/sched/sched_switch
~# echo 'hist:name=foo:keys=common_pid:ts=common_timestamp:clock=bogus' > trigger
bash: echo: write error: Invalid argument
~# echo 'hist:name=foo:keys=common_pid' > trigger
BUG: KASAN: slab-use-after-free in find_named_trigger+0xac/0xc0 Read of size 8 at addr ffff88800915d760 by task init/1 find_named_trigger+0xac/0xc0 hist_register_trigger+0xc1/0x900 event_hist_trigger_parse+0x3146/0x6af0 event_trigger_write+0xce/0x160 Freed by task 63: kfree+0x154/0x420 trigger_kthread_fn+0xfd/0x160
Set the clock before the trigger is registered, so that nothing which can fail runs after it is published, the way commit 6f86bdeab633 ("tracing: Fix bad hist from corrupting named_triggers list") moved the registration below the rest of the setup.
tracing_set_filter_buffering() is reference counted, so the init failure path has to drop the reference that the clock block now takes first.
--- kernel/trace/trace_events_hist.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)
kernel/trace/trace_events_hist.c +9 -6
@@ -6594,12 +6594,6 @@ static int hist_register_trigger(char *g data->cmd_ops = cmd_ops; } -if (data->cmd_ops->init) { - ret = data->cmd_ops->init (data); -if (ret <0 ) - goto out; - } -if (hist_data->enable_timestamps) {char *clock = hist_data->attrs->clock;
@@ -6612,6 +6606,15 @@ static int hist_register_trigger(char *gtracing_set_filter_buffering (file->tr, true); } +if (data->cmd_ops->init) { + ret = data->cmd_ops->init (data); +if (ret <0 ) { +if (hist_data->enable_timestamps) +tracing_set_filter_buffering (file->tr, false); + goto out; + } + } +if (named_data) {remove_hist_vars (hist_data);destroy_hist_data (hist_data);
Greg Kroah-Hartman
maintainerPATCH 1209/1250 tracing: Take the reference before publishing the named histogram trigger
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Donggeun Yoo <[email protected]>
[ Upstream commit 0fe23b8eaba0d3372c66b7b31204408da0715edc ]
event_hist_trigger_named_init() puts the trigger on the global named_triggers list and only then takes the reference on the trigger it shares its histogram with:
data->ref++;
save_named_trigger(data->named_data->name, data);
ret = event_hist_trigger_init(data->named_data);
if (ret < 0) {
kfree(data->cmd_ops);
data->cmd_ops = &trigger_hist_cmd;
}
return ret;event_hist_trigger_init() fails when alloc_hist_pad() cannot allocate, and nothing takes the trigger back off the list on the way out. event_hist_trigger_parse() frees it, and the next lookup by name reads the freed object:
BUG: KASAN: slab-use-after-free in find_named_trigger+0xac/0xc0 Read of size 8 at addr ffff888009346860 by task init/1 find_named_trigger+0xac/0xc0 hist_register_trigger+0xc1/0xa00 event_hist_trigger_parse+0x3146/0x6af0 event_trigger_write+0xce/0x160 Freed by task 67: kfree+0x154/0x420 trigger_kthread_fn+0xfd/0x160
Do the reference first and publish once it has succeeded, so that nothing which can fail runs after the trigger becomes findable.
--- kernel/trace/trace_events_hist.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
kernel/trace/trace_events_hist.c +6 -5
@@ -6355,17 +6355,18 @@ static int event_hist_trigger_named_init {int ret; - data->ref++; - -save_named_trigger (data->named_data->name, data); - ret =event_hist_trigger_init (data->named_data);if (ret <0 ) {kfree (data->cmd_ops); data->cmd_ops = &trigger_hist_cmd; +return ret; } -return ret; + data->ref++; + +save_named_trigger (data->named_data->name, data); + +return 0 ; }static void event_hist_trigger_named_free (struct event_trigger_data *data)
Greg Kroah-Hartman
maintainerPATCH 1210/1250 tracing: Undo the registration when enabling the histogram trigger fails
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Donggeun Yoo <[email protected]>
[ Upstream commit 92383cef66791a0c63a2f27755cadbdb2fbf270b ]
Commit 6f86bdeab633 ("tracing: Fix bad hist from corrupting named_triggers list") described how a trigger that is registered but not on file->triggers ends up freed while still on the global named_triggers list, and moved the registration down so that hist_trigger_enable() follows it immediately. One path still gets there. hist_trigger_enable() adds the trigger and takes it straight back out when the event cannot be enabled:
list_add_tail_rcu(&data->list, &file->triggers);
update_cond_flag(file);
if (trace_event_trigger_enable_disable(file, 1) < 0) {
list_del_rcu(&data->list);
update_cond_flag(file);
ret--;
}so the list walk in hist_unregister_trigger() matches nothing, test stays NULL, and the ->free() that would call del_named_trigger() is skipped. out_unreg falls through to out_free, which frees the trigger anyway:
BUG: KASAN: slab-use-after-free in find_named_trigger+0xac/0xc0 Read of size 8 at addr ffff8880091d3160 by task init/1 find_named_trigger+0xac/0xc0 hist_register_trigger+0xc1/0xa00 event_hist_trigger_parse+0x3146/0x6af0 event_trigger_write+0xce/0x160 Freed by task 69: kfree+0x154/0x420 trigger_kthread_fn+0xfd/0x160
Leave the trigger where hist_unregister_trigger() can find it and let that undo the registration, which is the only code that knows all of what cmd_ops->init() took: the named list entry, the hist_pad reference, the reference on the trigger a named histogram is shared with, and the copied cmd_ops. It also pairs the failed trace_event_trigger_enable_disable(), whose sm_ref and buffered event reference are otherwise left behind.
Since ->free() releases trigger_data and, for a trigger that does not share its histogram, hist_data with it, out_unreg can no longer fall through to out_free. For a trigger that does share, hist_register_trigger() has already destroyed the caller's hist_data, so the fall-through was reading freed memory there as well.
Move the enable_timestamps check in hist_unregister_trigger() above the ->free() call for the same reason: hist_data does not outlive it once the trigger being removed is the one that owns it.
--- kernel/trace/trace_events_hist.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-)
kernel/trace/trace_events_hist.c +10 -7
@@ -6633,11 +6633,12 @@ static int hist_trigger_enable(struct evupdate_cond_flag (file); -if (trace_event_trigger_enable_disable (file,1 ) <0 ) { -list_del_rcu (&data->list); -update_cond_flag (file); +/* +* On failure the caller undoes the registration, and +* hist_unregister_trigger() can only find the trigger here. +*/ +if (trace_event_trigger_enable_disable (file,1 ) <0 ) ret--; - }return ret; }
@@ -6715,13 +6716,13 @@ static void hist_unregister_trigger(char } } -if (test && test->cmd_ops->free) - test->cmd_ops->free (test); -if (hist_data->enable_timestamps) {if (!hist_data->remove || test)tracing_set_filter_buffering (file->tr, false); } + +if (test && test->cmd_ops->free) + test->cmd_ops->free (test); }static bool hist_file_check_refs (struct trace_event_file *file)
@@ -6926,6 +6927,8 @@ static int event_hist_trigger_parse(strureturn ret; out_unreg:event_trigger_unregister (cmd_ops, file, glob+1 , trigger_data); +/* The unregister frees trigger_data, skip out_free */ + goto out; out_free:event_trigger_reset_filter (cmd_ops, trigger_data);
Greg Kroah-Hartman
maintainerPATCH 1211/1250 EDAC/altera: Use ECC manager compatible to select A10/S10 IRQ layout
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rounak Das <[email protected]>
[ Upstream commit d4486fc3098e176cb4a29fee037216484761f9ca ]
The SDMMC ECC IRQ layout selection uses CONFIG_64BIT to distinguish between Arria10 and Stratix10 paths.
Detect the SoC once at probe via the device match table (.data) store it in struct altr_arria10_edac, and use it instead of CONFIG_64BIT.
This keeps the decision correct for every ECC child device (OCRAM, SD/MMC, etc.) and avoids any runtime compatible lookup.
Stable-dep-of: 9868f5c077df ("EDAC/altera: Use parent device for devres in altr_portb_setup()")
--- drivers/edac/altera_edac.c | 107 ++++++++++++++++++++++----------------------- drivers/edac/altera_edac.h | 1 2 files changed, 55 insertions(+), 53 deletions(-)
drivers/edac/altera_edac.c +54 -53
@@ -1507,6 +1507,7 @@ static int altr_portb_setup(struct altr_int edac_idx, rc;struct device_node *np;const struct edac_device_prv_data *prv = &a10_sdmmceccb_data; +bool is_s10 = device->edac->is_s10; rc =altr_check_ecc_deps (device);if (rc)
@@ -1548,15 +1549,14 @@ static int altr_portb_setup(struct altr_/* * Update the PortB IRQs - A10 has 4, S10 has 2, Index accordingly -* -* FIXME: Instead of ifdefs with different architectures the driver -* should properly use compatibles. */ -#ifdef CONFIG_64BIT - altdev->sb_irq =irq_of_parse_and_map (np,1 ); -#else - altdev->sb_irq =irq_of_parse_and_map (np,2 ); -#endif + +/* Using compatibles to determine the IRQ Index */ +if (is_s10) + altdev->sb_irq =irq_of_parse_and_map (np,1 ); +else + altdev->sb_irq =irq_of_parse_and_map (np,2 ); +if (!altdev->sb_irq) {edac_printk (KERN_ERR ,EDAC_DEVICE ,"Error PortB SBIRQ alloc\n" ); rc = -ENODEV ;
@@ -1570,29 +1570,28 @@ static int altr_portb_setup(struct altr_ goto err_release_group_1; } -#ifdef CONFIG_64BIT -/* Use IRQ to determine SError origin instead of assigning IRQ */ - rc =of_property_read_u32_index (np,"interrupts" ,1 , &altdev->db_irq); -if (rc) { -edac_printk (KERN_ERR ,EDAC_DEVICE , -"Error PortB DBIRQ alloc\n" ); - goto err_release_group_1; - } -#else - altdev->db_irq =irq_of_parse_and_map (np,3 ); -if (!altdev->db_irq) { -edac_printk (KERN_ERR ,EDAC_DEVICE ,"Error PortB DBIRQ alloc\n" ); - rc = -ENODEV ; - goto err_release_group_1; - } - rc =devm_request_irq (&altdev->ddev, altdev->db_irq, - prv->ecc_irq_handler,IRQF_TRIGGER_HIGH , - ecc_name, altdev); -if (rc) { -edac_printk (KERN_ERR ,EDAC_DEVICE ,"PortB DBERR IRQ error\n" ); - goto err_release_group_1; +if (is_s10) { +/* Use IRQ to determine SError origin instead of assigning IRQ */ + rc =of_property_read_u32_index (np,"interrupts" ,1 , &altdev->db_irq); +if (rc) { +edac_printk (KERN_ERR ,EDAC_DEVICE ,"Error PortB DBIRQ alloc\n" ); + goto err_release_group_1; + } + }else { + altdev->db_irq =irq_of_parse_and_map (np,3 ); +if (!altdev->db_irq) { +edac_printk (KERN_ERR ,EDAC_DEVICE ,"Error PortB DBIRQ alloc\n" ); + rc = -ENODEV ; + goto err_release_group_1; + } + rc =devm_request_irq (&altdev->ddev, altdev->db_irq, + prv->ecc_irq_handler,IRQF_TRIGGER_HIGH , + ecc_name, altdev); +if (rc) { +edac_printk (KERN_ERR ,EDAC_DEVICE ,"PortB DBERR IRQ error\n" ); + goto err_release_group_1; + } } -#endif rc =edac_device_add_device (dci);if (rc) {
@@ -1974,29 +1973,29 @@ static int altr_edac_a10_device_add(stru goto err_release_group1; } -#ifdef CONFIG_64BIT -/* Use IRQ to determine SError origin instead of assigning IRQ */ - rc =of_property_read_u32_index (np,"interrupts" ,0 , &altdev->db_irq); -if (rc) { -edac_printk (KERN_ERR ,EDAC_DEVICE , -"Unable to parse DB IRQ index\n" ); - goto err_release_group1; - } -#else - altdev->db_irq =irq_of_parse_and_map (np,1 ); -if (!altdev->db_irq) { -edac_printk (KERN_ERR ,EDAC_DEVICE ,"Error allocating DBIRQ\n" ); - rc = -ENODEV ; - goto err_release_group1; - } - rc =devm_request_irq (edac->dev, altdev->db_irq, prv->ecc_irq_handler, -IRQF_TRIGGER_HIGH , - ecc_name, altdev); -if (rc) { -edac_printk (KERN_ERR ,EDAC_DEVICE ,"No DBERR IRQ resource\n" ); - goto err_release_group1; +if (edac->is_s10) { +/* Use IRQ to determine SError origin instead of assigning IRQ */ + rc =of_property_read_u32_index (np,"interrupts" ,0 , &altdev->db_irq); +if (rc) { +edac_printk (KERN_ERR ,EDAC_DEVICE , +"Unable to parse DB IRQ index\n" ); + goto err_release_group1; + } + }else { + altdev->db_irq =irq_of_parse_and_map (np,1 ); +if (!altdev->db_irq) { +edac_printk (KERN_ERR ,EDAC_DEVICE ,"Error allocating DBIRQ\n" ); + rc = -ENODEV ; + goto err_release_group1; + } + rc =devm_request_irq (edac->dev, altdev->db_irq, prv->ecc_irq_handler, +IRQF_TRIGGER_HIGH , + ecc_name, altdev); +if (rc) { +edac_printk (KERN_ERR ,EDAC_DEVICE ,"No DBERR IRQ resource\n" ); + goto err_release_group1; + } } -#endif rc =edac_device_add_device (dci);if (rc) {
@@ -2122,6 +2121,8 @@ static int altr_edac_a10_probe(struct plplatform_set_drvdata (pdev, edac);INIT_LIST_HEAD (&edac->a10_ecc_devices); + edac->is_s10 = !!device_get_match_data (&pdev->dev); + edac->ecc_mgr_map =altr_sysmgr_regmap_lookup_by_phandle (pdev->dev.of_node,"altr,sysmgr-syscon" );
@@ -2207,7 +2208,7 @@ static int altr_edac_a10_probe(struct plstatic const struct of_device_id altr_edac_a10_of_match[] = { { .compatible ="altr,socfpga-a10-ecc-manager" }, - { .compatible ="altr,socfpga-s10-ecc-manager" }, + { .compatible ="altr,socfpga-s10-ecc-manager" , .data = (void *)1 }, {}, };MODULE_DEVICE_TABLE (of, altr_edac_a10_of_match);
drivers/edac/altera_edac.h +1 -0
@@ -395,6 +395,7 @@ struct altr_arria10_edac {struct irq_chip irq_chip;struct list_head a10_ecc_devices;struct notifier_block panic_notifier; + bool is_s10; };#endif /* #ifndef _ALTERA_EDAC_H */
Greg Kroah-Hartman
maintainerPATCH 1212/1250 EDAC/altera: Use parent device for devres in altr_portb_setup()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dinh Nguyen <[email protected]>
[ Upstream commit 9868f5c077dfe0b606331f2e782484f91a5789a5 ]
Anchor the devres group and the devm-managed IRQ requests in altr_portb_setup() to the actual parent device (device->edac->dev) instead of the embedded struct device inside the copied per-port altr_edac_device_dev.
This keeps devres_open_group(), devm_request_irq(), devres_remove_group() and devres_release_group() all referring to the same long-lived device so the group and the resources allocated inside it are torn down together.
--- drivers/edac/altera_edac.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/edac/altera_edac.c +5 -5
@@ -1534,7 +1534,7 @@ static int altr_portb_setup(struct altr_ altdev = dci->pvt_info; *altdev = *device; -if (!devres_open_group (&altdev->ddev, altr_portb_setup,GFP_KERNEL )) +if (!devres_open_group (device->edac->dev, altr_portb_setup,GFP_KERNEL ))return -ENOMEM ;/* Update PortB specific values */
@@ -1562,7 +1562,7 @@ static int altr_portb_setup(struct altr_ rc = -ENODEV ; goto err_release_group_1; } - rc =devm_request_irq (&altdev->ddev, altdev->sb_irq, + rc =devm_request_irq (device->edac->dev, altdev->sb_irq, prv->ecc_irq_handler,IRQF_TRIGGER_HIGH , ecc_name, altdev);if (rc) {
@@ -1584,7 +1584,7 @@ static int altr_portb_setup(struct altr_ rc = -ENODEV ; goto err_release_group_1; } - rc =devm_request_irq (&altdev->ddev, altdev->db_irq, + rc =devm_request_irq (device->edac->dev, altdev->db_irq, prv->ecc_irq_handler,IRQF_TRIGGER_HIGH , ecc_name, altdev);if (rc) {
@@ -1604,13 +1604,13 @@ static int altr_portb_setup(struct altr_list_add (&altdev->next, &altdev->edac->a10_ecc_devices); -devres_remove_group (&altdev->ddev, altr_portb_setup); +devres_remove_group (device->edac->dev, altr_portb_setup);return 0 ; err_release_group_1:edac_device_free_ctl_info (dci); -devres_release_group (&altdev->ddev, altr_portb_setup); +devres_release_group (device->edac->dev, altr_portb_setup);edac_printk (KERN_ERR ,EDAC_DEVICE ,"%s:Error setting up EDAC device: %d\n" , ecc_name, rc);return rc;
Greg Kroah-Hartman
maintainerPATCH 1213/1250 netfilter: cttimeout: detach dataplane timeout policy and repurpose refcount
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pablo Neira Ayuso <[email protected]>
[ Upstream commit 7d6a9cdb8d3a51d9cfe546a09a518ab3d2671549 ]
Add a refcount for struct nf_ct_timeout which is used by ct extension to set the custom ct timeout policy, this tells us that the ct timeout is being used by a conntrack entry. When the last conntrack entry drops the refcount on the ct timeout, the ct timeout is released.
Remove the refcount for control plane which controls if the ruleset refers to the timeout policy. After this update, it is possible to remove the ct timeout policy from nfnetlink_cttimeout immediately. This is for simplicity not to handle two refcounts on a single object.
Remove nf_queue_nf_hook_drop(): a packet sitting in nfqueue will just hold a reference to the nf_ct_timeout object until packet is reinjected, since this is part of the ct extension, this will be released by the time the conntrack is freed.
nf_ct_untimeout() is still called to clean up in a best effort basis:
the ct timeout on existing entries gets removed when the ct timeout goes away, but as long as the iptables ruleset still refers to the ct timeout through a template, new conntracks may keep attaching it and extend its lifetime until the rule is removed.
nf_ct_untimeout() is not called anymore from module removal path, this is unlikely to find timeouts give module refcount is bumped, and the new refcount already tracks the ct timeout policy use so it is released when unused.
Stable-dep-of: fec9b1de0d02 ("netfilter: cttimeout: prevent UAF during module unload")
--- include/net/netfilter/nf_conntrack_timeout.h | 27 ++++++ net/netfilter/nf_conntrack_core.c | 6 - net/netfilter/nf_conntrack_timeout.c | 27 +++++- net/netfilter/nfnetlink_cttimeout.c | 112 ++++++++++++--------------- net/netfilter/nft_ct.c | 7 - net/netfilter/xt_CT.c | 2 6 files changed, 107 insertions(+), 74 deletions(-)
include/net/netfilter/nf_conntrack_timeout.h +25 -2
@@ -12,6 +12,7 @@#define CTNL_TIMEOUT_NAME_MAX 32struct nf_ct_timeout { +refcount_t refcnt;__u16 l3num;const struct nf_conntrack_l4proto *l4proto;struct rcu_head rcu;
@@ -22,6 +23,22 @@ struct nf_conn_timeout {struct nf_ct_timeout __rcu *timeout; }; +static inline void nf_ct_timeout_put (const struct nf_conn *ct) +{ +#ifdef CONFIG_NF_CONNTRACK_TIMEOUT +struct nf_conn_timeout *timeout_ext; +struct nf_ct_timeout *timeout; + + timeout_ext =nf_ct_ext_find (ct,NF_CT_EXT_TIMEOUT ); +if (!timeout_ext) +return ; + + timeout =rcu_dereference (timeout_ext->timeout); +if (timeout &&refcount_dec_and_test (&timeout->refcnt)) +kfree_rcu (timeout, rcu); +#endif +} +static inline unsigned int *nf_ct_timeout_data (const struct nf_conn_timeout *t) {
@@ -56,8 +73,14 @@ struct nf_conn_timeout *nf_ct_timeout_ex#ifdef CONFIG_NF_CONNTRACK_TIMEOUT struct nf_conn_timeout *timeout_ext; +if (!timeout) +return NULL ; + timeout_ext =nf_ct_ext_add (ct,NF_CT_EXT_TIMEOUT , gfp); -if (timeout_ext ==NULL ) +if (!timeout_ext || timeout_ext->timeout) +return NULL ; + +if (!refcount_inc_not_zero (&timeout->refcnt))return NULL ;rcu_assign_pointer (timeout_ext->timeout, timeout);
@@ -75,7 +98,7 @@ static inline unsigned int *nf_ct_timeoustruct nf_conn_timeout *timeout_ext; timeout_ext =nf_ct_timeout_find (ct); -if (timeout_ext) +if (timeout_ext &&rcu_access_pointer (timeout_ext->timeout)) timeouts =nf_ct_timeout_data (timeout_ext);#endif return timeouts;
net/netfilter/nf_conntrack_core.c +4 -2
@@ -1690,16 +1690,18 @@ void nf_conntrack_free(struct nf_conn *c*/ WARN_ON (refcount_read (&ct->ct_general.use) !=0 ); +rcu_read_lock ();if (ct->status &IPS_SRC_NAT_DONE ) {const struct nf_nat_hook *nat_hook; -rcu_read_lock (); nat_hook =rcu_dereference (nf_nat_hook);if (nat_hook) nat_hook->remove_nat_bysrc (ct); -rcu_read_unlock (); } +nf_ct_timeout_put (ct); +rcu_read_unlock (); +kfree (ct->ext);kmem_cache_free (nf_conntrack_cachep, ct); cnet =nf_ct_pernet (net);
net/netfilter/nf_conntrack_timeout.c +24 -3
@@ -25,17 +25,32 @@const struct nf_ct_timeout_hooks __rcu *nf_ct_timeout_hook__read_mostly ;EXPORT_SYMBOL_GPL (nf_ct_timeout_hook); +/* nf_ct_iterate_cleanup() holds the conntrack lock. */ static int untimeout (struct nf_conn *ct,void *timeout) {struct nf_conn_timeout *timeout_ext =nf_ct_timeout_find (ct);if (timeout_ext) { -const struct nf_ct_timeout *t; +struct nf_ct_timeout *t; - t =rcu_access_pointer (timeout_ext->timeout); +rcu_read_lock (); + t =rcu_dereference (timeout_ext->timeout); +if (!t) { +rcu_read_unlock (); +return 0 ; + } -if (!timeout || t == timeout) +if (!timeout || t == timeout) {RCU_INIT_POINTER (timeout_ext->timeout,NULL ); + +/* No race with nf_conntrack_free() which is called +* only after the conntrack has been removed from +* the hashes. +*/ +if (refcount_dec_and_test (&t->refcnt)) +kfree_rcu (t, rcu); + } +rcu_read_unlock (); }/* We are not intended to delete this conntrack. */
@@ -70,6 +85,8 @@ int nf_ct_set_timeout(struct net *net, sconst char *errmsg =NULL ;int ret =0 ; +WARN_ON_ONCE (!nf_ct_is_template (ct)); +rcu_read_lock (); h =rcu_dereference (nf_ct_timeout_hook);if (!h) {
@@ -127,6 +144,8 @@ void nf_ct_destroy_timeout(struct nf_construct nf_conn_timeout *timeout_ext;const struct nf_ct_timeout_hooks *h; +WARN_ON_ONCE (!nf_ct_is_template (ct)); +rcu_read_lock (); h =rcu_dereference (nf_ct_timeout_hook);
@@ -139,6 +158,8 @@ void nf_ct_destroy_timeout(struct nf_conif (t) h->timeout_put (t);RCU_INIT_POINTER (timeout_ext->timeout,NULL ); +if (t &&refcount_dec_and_test (&t->refcnt)) +kfree_rcu (t, rcu); } }rcu_read_unlock ();
net/netfilter/nfnetlink_cttimeout.c +50 -62
219 lines not on this page · raw message
net/netfilter/nft_ct.c +3 -4
@@ -898,8 +898,6 @@ static void nft_ct_timeout_obj_eval(stru } } -rcu_assign_pointer (timeout->timeout, priv->timeout); -/* adjust the timeout as per 'new' state. ct is unconfirmed, * so the current timestamp must not be added. */
@@ -950,6 +948,7 @@ static int nft_ct_timeout_obj_init(const timeout->l3num = l3num; timeout->l4proto = l4proto; +refcount_set (&timeout->refcnt,1 ); ret =nf_ct_netns_get (ctx->net, ctx->family);if (ret <0 )
@@ -970,10 +969,10 @@ static void nft_ct_timeout_obj_destroy(cstruct nft_ct_timeout_obj *priv =nft_obj_data (obj);struct nf_ct_timeout *timeout = priv->timeout; -nf_queue_nf_hook_drop (ctx->net);nf_ct_untimeout (ctx->net, timeout);nf_ct_netns_put (ctx->net, ctx->family); -kfree_rcu (priv->timeout, rcu); +if (refcount_dec_and_test (&timeout->refcnt)) +kfree_rcu (priv->timeout, rcu); } static int nft_ct_timeout_obj_dump(struct sk_buff *skb,
net/netfilter/xt_CT.c +1 -1
@@ -284,7 +284,7 @@ static void xt_ct_tg_destroy(const strucstruct nf_conn_help *help;if (ct) { -if (info->helper[0 ] || info->timeout[0 ]) +if (info->helper[0 ])nf_queue_nf_hook_drop (par->net); help =nfct_help (ct);
Greg Kroah-Hartman
maintainerPATCH 1214/1250 netfilter: cttimeout: prevent UAF during module unload
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <[email protected]>
[ Upstream commit fec9b1de0d02de8dafa3cc344bcb91cf28660643 ]
nf_ct_set_timeout() protects the timeout hook dereference and policy lookup with rcu_read_lock(). cttimeout_exit(), however, unregisters the per-net operations before it clears the hook.
This allows the following interleaving:
CPU 0 CPU 1
cttimeout_exit() nf_ct_set_timeout()
unregister_pernet_subsys() rcu_read_lock()
kfree(pernet) h = nf_ct_timeout_hook
h->timeout_find_get()
nfct_timeout_pernet()
The hook still points to ctnl_timeout_find_get() when CPU 1 looks up the already freed per-net timeout list. KASAN reported:
BUG: KASAN: slab-use-after-free in ctnl_timeout_find_get Read of size 8 by task poc/90 Call Trace: ctnl_timeout_find_get+0x271/0x2a0 [nfnetlink_cttimeout] nf_ct_set_timeout+0x7b/0x3c0 xt_ct_tg_check+0x724/0xb20 xt_check_target+0x234/0xa90 do_ipt_set_ctl+0x570/0x1270 Allocated by task 89: __kmalloc_noprof+0x16e/0x460 ops_init+0x6d/0x420 register_pernet_operations+0x2f6/0x670 Freed by task 91: kfree+0x131/0x390 ops_undo_list+0x3d4/0x730 unregister_pernet_operations+0x232/0x490 unregister_pernet_subsys+0x1c/0x30 cttimeout_exit+0x52/0x970 [nfnetlink_cttimeout]
Clear the hook and wait for existing readers before unregistering the per-net operations. This blocks new policy lookups and ensures readers that observed the hook finish before the per-net storage is freed.
--- net/netfilter/nfnetlink_cttimeout.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/netfilter/nfnetlink_cttimeout.c +1 -1
@@ -654,9 +654,9 @@ static void __exit cttimeout_exit(void) {nfnetlink_subsys_unregister (&cttimeout_subsys); -unregister_pernet_subsys (&cttimeout_ops);RCU_INIT_POINTER (nf_ct_timeout_hook,NULL );synchronize_net (); +unregister_pernet_subsys (&cttimeout_ops); }module_init (cttimeout_init);
Greg Kroah-Hartman
maintainerPATCH 1215/1250 ns: add __ns_ref_read()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
[ Upstream commit 6b053576edb12c7739ea9c7c9900031361922631 ]
Implement ns_ref_read() the same way as ns_ref_{get,put}(). No point in making that any more special or different from the other helpers.
Stable-dep-of: cdd812d0683d ("exit: hold a reference to thread_pid across proc_flush_pid")
--- include/linux/ns_common.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
include/linux/ns_common.h +6 -1
@@ -156,7 +156,12 @@ static __always_inline __must_check boolreturn refcount_inc_not_zero (&ns->__ns_ref); } -#define ns_ref_read (__ns) refcount_read(&to_ns_common((__ns))->__ns_ref) +static __always_inline __must_check int __ns_ref_read(const struct ns_common *ns) +{ +return refcount_read (&ns->__ns_ref); +} + +#define ns_ref_read (__ns) __ns_ref_read(to_ns_common((__ns)))#define ns_ref_inc (__ns) refcount_inc(&to_ns_common((__ns))->__ns_ref)#define ns_ref_get (__ns) __ns_ref_get(to_ns_common((__ns)))#define ns_ref_put (__ns) __ns_ref_put(to_ns_common((__ns)))
Greg Kroah-Hartman
maintainerPATCH 1216/1250 ns: rename to exit_nsproxy_namespaces()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
[ Upstream commit 4b06b70c8244b442d58ae0fb59870cf31fdb422e ]
The current naming is very misleading as this really isn't exiting all of the task's namespaces. It is only exiting the namespaces that hang of off nsproxy. Reflect that in the name.
Stable-dep-of: cdd812d0683d ("exit: hold a reference to thread_pid across proc_flush_pid")
--- include/linux/nsproxy.h | 2 +- kernel/cgroup/cgroup.c | 6 +++--- kernel/exit.c | 2 +- kernel/fork.c | 2 +- kernel/nsproxy.c | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-)
include/linux/nsproxy.h +1 -1
@@ -93,7 +93,7 @@ static inline struct cred *nsset_cred(st*/ int copy_namespaces (u64 flags,struct task_struct *tsk); -void exit_task_namespaces (struct task_struct *tsk); +void exit_nsproxy_namespaces (struct task_struct *tsk);void switch_task_namespaces (struct task_struct *tsk,struct nsproxy *new);int exec_task_namespaces (void );void free_nsproxy (struct nsproxy *ns);
kernel/cgroup/cgroup.c +3 -3
@@ -1522,9 +1522,9 @@ static struct cgroup *current_cgns_cgrou }else {/* * NOTE: This function may be called from bpf_cgroup_from_id() -* on a task which has already passed exit_task_namespaces() and -* nsproxy == NULL. Fall back to cgrp_dfl_root which will make all -* cgroups visible for lookups. +* on a task which has already passed exit_nsproxy_namespaces() +* and nsproxy == NULL. Fall back to cgrp_dfl_root which will +* make all cgroups visible for lookups. */ return &cgrp_dfl_root.cgrp; }
kernel/exit.c +1 -1
@@ -973,7 +973,7 @@ void __noreturn do_exit(long code)exit_fs (tsk);if (group_dead)disassociate_ctty (1 ); -exit_task_namespaces (tsk); +exit_nsproxy_namespaces (tsk);exit_task_work (tsk);exit_thread (tsk);
kernel/fork.c +1 -1
@@ -2455,7 +2455,7 @@ bad_fork_cleanup_io:if (p->io_context)exit_io_context (p); bad_fork_cleanup_namespaces: -exit_task_namespaces (p); +exit_nsproxy_namespaces (p); bad_fork_cleanup_mm:if (p->mm) {mm_clear_owner (p->mm, p);
kernel/nsproxy.c +1 -1
@@ -241,7 +241,7 @@ void switch_task_namespaces(struct task_put_nsproxy (ns); } -void exit_task_namespaces (struct task_struct *p) +void exit_nsproxy_namespaces (struct task_struct *p) {switch_task_namespaces (p,NULL ); }
Greg Kroah-Hartman
maintainerPATCH 1217/1250 exit: hold a reference to thread_pid across proc_flush_pid
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daehyeon Ko <[email protected]>
[ Upstream commit cdd812d0683dee14ead02c9eded568685e61b23f ]
Commit 0a36bad01731 ("release_task: kill the no longer needed get/put_pid(thread_pid)") removed the reference around proc_flush_pid(). It assumed that free_pids(post.pids) at the end of release_task() would keep thread_pid alive until then.
That assumption is wrong. __change_pid() only records a detached PID in post.pids when pid_has_task() is false for every PIDTYPE. If another task still uses the exiting task's PID as its process group or session ID, __unhash_process() removes the exiting task's PIDTYPE_PID link but leaves the PID out of post.pids. release_task() therefore holds no reference to it after dropping tasklist_lock.
The other task can then remove the remaining PIDTYPE links. Its free_pids() call schedules delayed_put_pid(), and the RCU callback can free the PID before the first release_task() reaches proc_flush_pid().
An unprivileged reproducer races wait4(-1) against setsid() to trigger this ordering. Three of three fresh v7.2 KASAN boots reported:
BUG: KASAN: slab-use-after-free in
proc_invalidate_siblings_dcache+0x3e2/0x3f0
Read of size 8 by task h7_pid_reaper/1921
Call Trace:
proc_invalidate_siblings_dcache
release_task
wait_consider_task
__do_wait
do_wait
kernel_wait4
Freed by task 0:
kmem_cache_free
put_pid
delayed_put_pid
rcu_core
Last potentially related work creation:
__call_rcu_common
free_pids
ksys_setsidKASAN identified a 144-byte object from the pid cache and located the bad read 80 bytes into the freed object, matching pid->inodes. With an explicit reference, three of three fresh boots completed without a KASAN report. The concurrent RCU callback dropped its reference while proc_flush_pid() was protected, and the balancing put_pid() performed the final free afterward.
Take a reference before __unhash_process() clears p->thread_pid and release it after proc_flush_pid() completes.
A tested source reproducer is available privately on request. No controlled read or write, information leak, or privilege escalation is claimed. The mainline patch applies directly to v6.19.y and newer; v6.16.y through v6.18.y need a context-adjusted backport.
--- kernel/exit.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
kernel/exit.c +6 -3
@@ -264,8 +264,11 @@ repeat:pidfs_exit (p);cgroup_release (p); -/* Retrieve @thread_pid before __unhash_process() may set it to NULL. */ - thread_pid =task_pid (p); +/* +* Pin @thread_pid before __unhash_process() clears it. The last +* PIDTYPE detach can otherwise free it before proc_flush_pid(). +*/ + thread_pid =get_pid (task_pid (p));write_lock_irq (&tasklist_lock);ptrace_release_task (p);
@@ -294,8 +297,8 @@ repeat: }write_unlock_irq (&tasklist_lock); -/* @thread_pid can't go away until free_pids() below */ proc_flush_pid (thread_pid); +put_pid (thread_pid);add_device_randomness (&p->se.sum_exec_runtime,sizeof (p->se.sum_exec_runtime));free_pids (post.pids);
Greg Kroah-Hartman
maintainerPATCH 1218/1250 net: macb: Replace open-coded implementation with napi_schedule()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kevin Hao <[email protected]>
[ Upstream commit dc3bd465ea36af7fd6f9197c05353effc616145c ]
The driver currently duplicates the logic of napi_schedule() primarily to include additional debug information. However, these debug details are not essential for a specific driver and can be effectively obtained through existing tracepoints in the networking core, such as /sys/kernel/tracing/events/napi/napi_poll. Therefore, this patch replaces the open-coded implementation with napi_schedule() to simplify the driver's code.
Stable-dep-of: e1406330d70e ("net: macb: initialize PTP state before registering clock")
--- drivers/net/ethernet/cadence/macb_main.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-)
drivers/net/ethernet/cadence/macb_main.c +2 -8
@@ -2010,10 +2010,7 @@ static irqreturn_t macb_interrupt(int irif (bp->caps &MACB_CAPS_ISR_CLEAR_ON_WRITE )queue_writel (queue,ISR ,MACB_BIT (RCOMP )); -if (napi_schedule_prep (&queue->napi_rx)) { -netdev_vdbg (bp->dev,"scheduling RX softirq\n" ); -__napi_schedule (&queue->napi_rx); - } +napi_schedule (&queue->napi_rx); } if (status & (MACB_BIT(TCOMP) |
@@ -2028,10 +2025,7 @@ static irqreturn_t macb_interrupt(int irwmb ();// ensure softirq can see update } -if (napi_schedule_prep (&queue->napi_tx)) { -netdev_vdbg (bp->dev,"scheduling TX softirq\n" ); -__napi_schedule (&queue->napi_tx); - } +napi_schedule (&queue->napi_tx); }if (unlikely (status & (MACB_TX_ERR_FLAGS ))) {
Greg Kroah-Hartman
maintainerPATCH 1219/1250 net: macb: Use netif_napi_add_tx() instead of netif_napi_add() for TX NAPI
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kevin Hao <[email protected]>
[ Upstream commit c321b5676d0c41de9155c1966aa6af8b7ca35091 ]
The TX NAPI should be registered via netif_napi_add_tx() to avoid unnecessarily polluting the napi_hash table.
Stable-dep-of: e1406330d70e ("net: macb: initialize PTP state before registering clock")
--- drivers/net/ethernet/cadence/macb_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/cadence/macb_main.c +1 -1
@@ -4650,7 +4650,7 @@ static int macb_init(struct platform_dev queue->bp = bp;spin_lock_init (&queue->tx_ptr_lock);netif_napi_add (dev, &queue->napi_rx, macb_rx_poll); -netif_napi_add (dev, &queue->napi_tx, macb_tx_poll); +netif_napi_add_tx (dev, &queue->napi_tx, macb_tx_poll);if (hw_q) { queue->ISR =GEM_ISR (hw_q -1 ); queue->IER =GEM_IER (hw_q -1 );
Greg Kroah-Hartman
maintainerPATCH 1220/1250 net: macb: unify device pointer naming convention
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Théo Lebrun <[email protected]>
[ Upstream commit 07362f68e61d82ee53da0e9ae2c7f981c3538861 ]
Here are all device pointer variable permutations inside MACB:
struct device *dev;
struct net_device *dev;
struct net_device *ndev;
struct net_device *netdev;
struct pci_dev *pdev; // inside macb_pci.c
struct phy_device *phy;
struct phy_device *phydev;
struct platform_device *pdev;
struct platform_device *plat_dev; // inside macb_pci.c
Unify to this convention:
struct device *dev;
struct net_device *netdev;
struct pci_dev *pci;
struct phy_device *phydev;
struct platform_device *pdev;
Ensure nothing slipped through using ctags tooling:
⟩ ctags -o - --kinds-c='{local}{member}{parameter}' \
--fields='{typeref}' drivers/net/ethernet/cadence/* | \
awk -F"\t" '
$NF~/struct:.*(device|dev) / {print $NF, $1}' | \ sort -u
typeref:struct:device * dev
typeref:struct:in_device * idev // ignored
typeref:struct:net_device * netdev
typeref:struct:pci_dev * pci
typeref:struct:phy_device * phydev
typeref:struct:platform_device * pdev
Also fix some printk() calls to use __func__ instead of hardcoding. This silences some checkpatch.pl warnings and doesn't deserve a separate commit.
Backport note: retain only the dev-to-netdev rename in gem_ptp_init(). The target e1406330d70e ("net: macb: initialize PTP state before registering clock") needs this spelling in its ptp_clock_register() context; its macb_probe() hunk already applies to this stable tree. Drop the unrelated driver-wide renames and logging cleanup. In particular, do not import newer EEE, interrupt, DMA, queue, or probe changes absent from this branch. This limited rename changes no behavior and adds no functions.
[ sashal: Reduced backport -- upstream 07362f68e61d8 touches 4 file(s), this
backport carries 1. Not backported here:
drivers/net/ethernet/cadence/macb.h drivers/net/ethernet/cadence/macb_main.c drivers/net/ethernet/cadence/macb_pci.c
This note is generated from the file lists only; see the resolution record for the reasoning. ]
Stable-dep-of: e1406330d70e ("net: macb: initialize PTP state before registering clock")
--- drivers/net/ethernet/cadence/macb_ptp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/net/ethernet/cadence/macb_ptp.c +3 -3
@@ -322,9 +322,9 @@ void gem_ptp_txstamp(struct macb *bp, stskb_tstamp_tx (skb, &shhwtstamps); } -void gem_ptp_init (struct net_device *dev) +void gem_ptp_init (struct net_device *netdev) { -struct macb *bp =netdev_priv (dev); +struct macb *bp =netdev_priv (netdev); bp->ptp_clock_info = gem_ptp_caps_template;
@@ -332,7 +332,7 @@ void gem_ptp_init(struct net_device *dev bp->tsu_rate = bp->ptp_info->get_tsu_rate (bp); bp->ptp_clock_info.max_adj = bp->ptp_info->get_ptp_max_adj ();gem_ptp_init_timer (bp); - bp->ptp_clock =ptp_clock_register (&bp->ptp_clock_info, &dev->dev); + bp->ptp_clock =ptp_clock_register (&bp->ptp_clock_info, &netdev->dev);if (IS_ERR (bp->ptp_clock)) {pr_err ("ptp clock register failed: %ld\n" ,PTR_ERR (bp->ptp_clock));
Greg Kroah-Hartman
maintainerPATCH 1221/1250 net: macb: initialize PTP state before registering clock
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Runyu Xiao <[email protected]>
[ Upstream commit e1406330d70e56dd44fa6fbafc86e77e5c80c122 ]
gem_ptp_init() registers the PTP clock before initializing bp->tsu_clk_lock and the TSU hardware. Since ptp_clock_register() publishes the PTP character device, userspace may invoke PTP callbacks before the lock and hardware are ready.
In addition, gem_ptp_init() is called from both the interface open and resume paths. Reinitializing tsu_clk_lock there can reset the lock while timestamp processing is using it.
This race is theoretical and has not been observed in practice.
Initialize tsu_clk_lock once during probe and initialize the TSU before registering the PTP clock.
--- drivers/net/ethernet/cadence/macb_main.c | 1 + drivers/net/ethernet/cadence/macb_ptp.c | 5 +---- 2 files changed, 2 insertions(+), 4 deletions(-)
drivers/net/ethernet/cadence/macb_main.c +1 -0
@@ -5657,6 +5657,7 @@ static int macb_probe(struct platform_de }spin_lock_init (&bp->lock);spin_lock_init (&bp->stats_lock); +spin_lock_init (&bp->tsu_clk_lock);/* setup capabilities */ macb_configure_caps (bp, macb_config);
drivers/net/ethernet/cadence/macb_ptp.c +1 -4
@@ -332,6 +332,7 @@ void gem_ptp_init(struct net_device *net bp->tsu_rate = bp->ptp_info->get_tsu_rate (bp); bp->ptp_clock_info.max_adj = bp->ptp_info->get_ptp_max_adj ();gem_ptp_init_timer (bp); +gem_ptp_init_tsu (bp); bp->ptp_clock =ptp_clock_register (&bp->ptp_clock_info, &netdev->dev);if (IS_ERR (bp->ptp_clock)) { pr_err("ptp clock register failed: %ld\n",
@@ -343,10 +344,6 @@ void gem_ptp_init(struct net_device *netreturn ; } -spin_lock_init (&bp->tsu_clk_lock); - -gem_ptp_init_tsu (bp); -dev_info (&bp->pdev->dev,"%s ptp clock registered.\n" ,GEM_PTP_TIMER_NAME ); }
Greg Kroah-Hartman
maintainerPATCH 1222/1250 erofs: separate plain and compressed filesystems formally
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gao Xiang <[email protected]>
[ Upstream commit 7cef3c8341940febf75db6c25199cd83fb74d52f ]
The EROFS on-disk format uses a tiny, plain metadata design that prioritizes performance and minimizes complex inconsistencies against common writable disk filesystems (almost all serious metadata inconsistency cannot happen in well-designed immutable filesystems like EROFS). EROFS deliberately avoids artificial design flaws to eliminate serious security risks from untrusted remote sources by design, although human-made implementation bugs can still happen sometimes.
Currently, there is no strict check to prevent compressed inodes, especially LZ4-compressed inodes, from being read in plain filesystems.
Starting with erofs-utils 1.0 and Linux 5.3, LZ4_0PADDING sb feature is automatically enabled for LZ4-compressed EROFS images to support in-place decompression. Furthermore, since Linux 5.4 LTS is no longer supported, we no longer need to handle ancient LZ4-compressed EROFS images generated by erofs-utils prior to 1.0.
To formally distinguish different filesystem types for improved security:
- Use the presence of LZ4_0PADDING or a non-zero dsb->u1.lz4_max_distance as a marker for compressed filesystems containing LZ4-compressed inodes only;
- For other algorithms, use dsb->u1.available_compr_algs bitmap.
Note: LZ4_0PADDING has been supported since Linux 5.4 (the first formal kernel version), so exposing it via sysfs is no longer necessary and is now deprecated (but remain it for five more years until 2031):
dsb->u1 has been strictly non-zero for all EROFS images containing compressed inodes starting with erofs-utils v1.3 and it is actually a much better marker for compressed filesystems.
Backport dependency note for Linux 6.18:
Retain only the zero_padding sysfs feature removal and the corresponding feature-list documentation update. The documentation layout is required for target 839f075aabdf5c21048f9801b87c0b841dd3d064 ("erofs: add sysfs feature entry for xattr prefixes") to apply without modification, and the sysfs removal keeps that list consistent with the attributes exposed.
Drop the decompressor, inode, superblock, and internal-header changes. Those changes are unrelated to the target, and the decompressor hunks assume upstream's newer string-based error reporting instead of this stable branch's integer-return implementation. Leave the existing compression behavior intact; no functions are added by this dependency.
[ sashal: Reduced backport -- upstream 7cef3c8341940 touches 7 file(s), this
backport carries 2. Not backported here:
fs/erofs/decompressor.c
fs/erofs/erofs_fs.h
fs/erofs/inode.c
fs/erofs/internal.h
fs/erofs/super.c
This note is generated from the file lists only; see the resolution record for the reasoning. ]
Stable-dep-of: 839f075aabdf ("erofs: add sysfs feature entry for xattr prefixes")
--- Documentation/ABI/testing/sysfs-fs-erofs | 6 +++--- fs/erofs/sysfs.c | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-)
Documentation/ABI/testing/sysfs-fs-erofs +3 -3
@@ -3,9 +3,9 @@ Date: November 2021 Contact: "Huang Jianan" <[email protected]> Description: Shows all enabled kernel features. Supported features: - zero_padding, compr_cfgs, big_pcluster, chunked_file, - device_table, compr_head2, sb_chksum, ztailpacking, - dedupe, fragments, 48bit, metabox. + compr_cfgs, big_pcluster, chunked_file, device_table, + compr_head2, sb_chksum, ztailpacking, dedupe, fragments, + 48bit, metabox. What: /sys/fs/erofs/<disk>/sync_decompress Date: November 2021
fs/erofs/sysfs.c +0 -2
@@ -86,7 +86,6 @@ static struct attribute *erofs_attrs[] =ATTRIBUTE_GROUPS (erofs);/* Features this copy of erofs supports */ -EROFS_ATTR_FEATURE (zero_padding);EROFS_ATTR_FEATURE (compr_cfgs);EROFS_ATTR_FEATURE (big_pcluster);EROFS_ATTR_FEATURE (chunked_file);
@@ -100,7 +99,6 @@ EROFS_ATTR_FEATURE(48bit);EROFS_ATTR_FEATURE (metabox);static struct attribute *erofs_feat_attrs[] = { -ATTR_LIST (zero_padding),ATTR_LIST (compr_cfgs),ATTR_LIST (big_pcluster),ATTR_LIST (chunked_file),
Greg Kroah-Hartman
maintainerPATCH 1223/1250 erofs: add sysfs feature entry for xattr prefixes
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jingbo Xu <[email protected]>
[ Upstream commit 839f075aabdf5c21048f9801b87c0b841dd3d064 ]
Let /sys/fs/erofs/features/xattr_prefixes advertise that this kernel supports the EROFS_FEATURE_INCOMPAT_XATTR_PREFIXES on-disk format.
--- Documentation/ABI/testing/sysfs-fs-erofs | 2 +- fs/erofs/sysfs.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-)
Documentation/ABI/testing/sysfs-fs-erofs +1 -1
@@ -5,7 +5,7 @@ Description: Shows all enabled kernel fe Supported features: compr_cfgs, big_pcluster, chunked_file, device_table, compr_head2, sb_chksum, ztailpacking, dedupe, fragments, - 48bit, metabox. + xattr_prefixes, 48bit, metabox. What: /sys/fs/erofs/<disk>/sync_decompress Date: November 2021
fs/erofs/sysfs.c +2 -0
@@ -95,6 +95,7 @@ EROFS_ATTR_FEATURE(sb_chksum);EROFS_ATTR_FEATURE (ztailpacking);EROFS_ATTR_FEATURE (fragments);EROFS_ATTR_FEATURE (dedupe); +EROFS_ATTR_FEATURE (xattr_prefixes); EROFS_ATTR_FEATURE(48bit);EROFS_ATTR_FEATURE (metabox);
@@ -108,6 +109,7 @@ static struct attribute *erofs_feat_attrATTR_LIST (ztailpacking),ATTR_LIST (fragments),ATTR_LIST (dedupe), +ATTR_LIST (xattr_prefixes), ATTR_LIST(48bit),ATTR_LIST (metabox), NULL,
Greg Kroah-Hartman
maintainerPATCH 1224/1250 idpf: Fix kernel-doc descriptions to avoid warnings
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andy Shevchenko <[email protected]>
[ Upstream commit 7fe9c81aa24a2374b1a9a2160d44f4afbf8ab80d ]
In many functions the Return section is missing. Fix kernel-doc descriptions to address that and other warnings.
Before the change:
$ scripts/kernel-doc -none -Wreturn drivers/net/ethernet/intel/idpf/idpf_txrx.c 2>&1 | wc -l 85
Stable-dep-of: 7dd4c829bac2 ("idpf: disable DIM work before freeing q_vectors")
--- drivers/net/ethernet/intel/idpf/idpf_txrx.c | 94 +++++++++++++++++----------- 1 file changed, 58 insertions(+), 36 deletions(-)
drivers/net/ethernet/intel/idpf/idpf_txrx.c +58 -36
@@ -19,6 +19,8 @@ LIBETH_SQE_CHECK_PRIV(u32);* Make sure we don't exceed maximum scatter gather buffers for a single * packet. * TSO case has been handled earlier from idpf_features_check(). +* +* Return: %true if skb exceeds max descriptors per packet, %false otherwise. */ static bool idpf_chk_linearize(const struct sk_buff *skb, unsigned int max_bufs,
@@ -172,7 +174,7 @@ static void idpf_tx_desc_rel_all(struct* idpf_tx_buf_alloc_all - Allocate memory for all buffer resources * @tx_q: queue for which the buffers are allocated * -* Returns 0 on success, negative on failure +* Return: 0 on success, negative on failure */ static int idpf_tx_buf_alloc_all (struct idpf_tx_queue *tx_q) {
@@ -196,7 +198,7 @@ static int idpf_tx_buf_alloc_all(struct* @vport: vport to allocate resources for * @tx_q: the tx ring to set up * -* Returns 0 on success, negative on failure +* Return: 0 on success, negative on failure */ static int idpf_tx_desc_alloc (const struct idpf_vport *vport,struct idpf_tx_queue *tx_q)
@@ -297,7 +299,7 @@ static int idpf_compl_desc_alloc(const s* idpf_tx_desc_alloc_all - allocate all queues Tx resources * @vport: virtual port private structure * -* Returns 0 on success, negative on failure +* Return: 0 on success, negative on failure */ static int idpf_tx_desc_alloc_all (struct idpf_vport *vport) {
@@ -548,7 +550,7 @@ static void idpf_rx_buf_hw_update(struct* idpf_rx_hdr_buf_alloc_all - Allocate memory for header buffers * @bufq: ring to use * -* Returns 0 on success, negative on failure. +* Return: 0 on success, negative on failure. */ static int idpf_rx_hdr_buf_alloc_all (struct idpf_buf_queue *bufq) {
@@ -600,7 +602,7 @@ static void idpf_post_buf_refill(struct* @bufq: buffer queue to post to * @buf_id: buffer id to post * -* Returns false if buffer could not be allocated, true otherwise. +* Return: %false if buffer could not be allocated, %true otherwise. */ static bool idpf_rx_post_buf_desc (struct idpf_buf_queue *bufq,u16 buf_id) {
@@ -649,7 +651,7 @@ static bool idpf_rx_post_buf_desc(struct* @bufq: buffer queue to post working set to * @working_set: number of buffers to put in working set * -* Returns true if @working_set bufs were posted successfully, false otherwise. +* Return: %true if @working_set bufs were posted successfully, %false otherwise. */ static bool idpf_rx_post_init_bufs (struct idpf_buf_queue *bufq,u16 working_set)
@@ -718,7 +720,7 @@ static int idpf_rx_bufs_init_singleq(str* idpf_rx_buf_alloc_all - Allocate memory for all buffer resources * @rxbufq: queue for which the buffers are allocated * -* Returns 0 on success, negative on failure +* Return: 0 on success, negative on failure */ static int idpf_rx_buf_alloc_all (struct idpf_buf_queue *rxbufq) {
@@ -746,7 +748,7 @@ rx_buf_alloc_all_out:* @bufq: buffer queue to create page pool for * @type: type of Rx buffers to allocate * -* Returns 0 on success, negative on failure +* Return: 0 on success, negative on failure */ static int idpf_rx_bufs_init (struct idpf_buf_queue *bufq,enum libeth_fqe_type type)
@@ -781,7 +783,7 @@ static int idpf_rx_bufs_init(struct idpf* idpf_rx_bufs_init_all - Initialize all RX bufs * @vport: virtual port struct * -* Returns 0 on success, negative on failure +* Return: 0 on success, negative on failure */ int idpf_rx_bufs_init_all (struct idpf_vport *vport) {
@@ -836,7 +838,7 @@ int idpf_rx_bufs_init_all(struct idpf_vp* @vport: vport to allocate resources for * @rxq: Rx queue for which the resources are setup * -* Returns 0 on success, negative on failure +* Return: 0 on success, negative on failure */ static int idpf_rx_desc_alloc (const struct idpf_vport *vport,struct idpf_rx_queue *rxq)
@@ -898,7 +900,7 @@ static int idpf_bufq_desc_alloc(const st* idpf_rx_desc_alloc_all - allocate all RX queues resources * @vport: virtual port structure * -* Returns 0 on success, negative on failure +* Return: 0 on success, negative on failure */ static int idpf_rx_desc_alloc_all (struct idpf_vport *vport) {
@@ -1426,7 +1428,7 @@ void idpf_vport_queues_rel(struct idpf_v* dereference the queue from queue groups. This allows us to quickly pull a * txq based on a queue index. * -* Returns 0 on success, negative on failure +* Return: 0 on success, negative on failure */ static int idpf_vport_init_fast_path_txqs (struct idpf_vport *vport) {
@@ -1559,7 +1561,7 @@ void idpf_vport_calc_num_q_desc(struct i* @vport_msg: message to fill with data * @max_q: vport max queue info * -* Return 0 on success, error value on failure. +* Return: 0 on success, error value on failure. */ int idpf_vport_calc_total_qs(struct idpf_adapter *adapter, u16 vport_idx, struct virtchnl2_create_vport *vport_msg,
@@ -1694,7 +1696,7 @@ static void idpf_rxq_set_descids(const s* @vport: vport to allocate txq groups for * @num_txq: number of txqs to allocate for each group * -* Returns 0 on success, negative on failure +* Return: 0 on success, negative on failure */ static int idpf_txq_group_alloc (struct idpf_vport *vport,u16 num_txq) {
@@ -1786,7 +1788,7 @@ err_alloc:* @vport: vport to allocate rxq groups for * @num_rxq: number of rxqs to allocate for each group * -* Returns 0 on success, negative on failure +* Return: 0 on success, negative on failure */ static int idpf_rxq_group_alloc (struct idpf_vport *vport,u16 num_rxq) {
@@ -1915,7 +1917,7 @@ err_alloc:* idpf_vport_queue_grp_alloc_all - Allocate all queue groups/resources * @vport: vport with qgrps to allocate * -* Returns 0 on success, negative on failure +* Return: 0 on success, negative on failure */ static int idpf_vport_queue_grp_alloc_all (struct idpf_vport *vport) {
@@ -1944,8 +1946,9 @@ err_out:* idpf_vport_queues_alloc - Allocate memory for all queues * @vport: virtual port * -* Allocate memory for queues associated with a vport. Returns 0 on success, -* negative on failure. +* Allocate memory for queues associated with a vport. +* +* Return: 0 on success, negative on failure. */ int idpf_vport_queues_alloc (struct idpf_vport *vport) {
@@ -2172,7 +2175,7 @@ static void idpf_tx_handle_rs_completion* @budget: Used to determine if we are in netpoll * @cleaned: returns number of packets cleaned * -* Returns true if there's any budget left (e.g. the clean is finished) +* Return: %true if there's any budget left (e.g. the clean is finished) */ static bool idpf_tx_clean_complq (struct idpf_compl_queue *complq,int budget,int *cleaned)
@@ -2398,7 +2401,7 @@ void idpf_tx_splitq_build_flow_desc(unio }/** -* idpf_tx_splitq_has_room - check if enough Tx splitq resources are available +* idpf_txq_has_room - check if enough Tx splitq resources are available * @tx_q: the queue to be checked * @descs_needed: number of descriptors required for this packet * @bufs_needed: number of Tx buffers required for this packet
@@ -2529,6 +2532,8 @@ unsigned int idpf_tx_res_count_required(* idpf_tx_splitq_bump_ntu - adjust NTU and generation * @txq: the tx ring to wrap * @ntu: ring index to bump +* +* Return: the next ring index hopping to 0 when wraps around */ static unsigned int idpf_tx_splitq_bump_ntu (struct idpf_tx_queue *txq,u16 ntu) {
@@ -2797,7 +2802,7 @@ static void idpf_tx_splitq_map(struct id* @skb: pointer to skb * @off: pointer to struct that holds offload parameters * -* Returns error (negative) if TSO was requested but cannot be applied to the +* Return: error (negative) if TSO was requested but cannot be applied to the * given skb, 0 if TSO does not apply to the given skb, or 1 otherwise. */ int idpf_tso (struct sk_buff *skb,struct idpf_tx_offload_params *off)
@@ -2875,6 +2880,8 @@ int idpf_tso(struct sk_buff *skb, struct* * Since the TX buffer rings mimics the descriptor ring, update the tx buffer * ring entry to reflect that this index is a context descriptor +* +* Return: pointer to the next descriptor */ static union idpf_flex_tx_ctx_desc *idpf_tx_splitq_get_ctx_desc (struct idpf_tx_queue *txq)
@@ -2893,6 +2900,8 @@ idpf_tx_splitq_get_ctx_desc(struct idpf_* idpf_tx_drop_skb - free the SKB and bump tail if necessary * @tx_q: queue to send buffer on * @skb: pointer to skb +* +* Return: always NETDEV_TX_OK */ netdev_tx_t idpf_tx_drop_skb (struct idpf_tx_queue *tx_q,struct sk_buff *skb) {
@@ -2994,7 +3003,7 @@ static bool idpf_tx_splitq_need_re(struc* @skb: send buffer * @tx_q: queue to send buffer on * -* Returns NETDEV_TX_OK if sent, else an error code +* Return: NETDEV_TX_OK if sent, else an error code */ static netdev_tx_t idpf_tx_splitq_frame (struct sk_buff *skb,struct idpf_tx_queue *tx_q)
@@ -3117,7 +3126,7 @@ static netdev_tx_t idpf_tx_splitq_frame(* @skb: send buffer * @netdev: network interface device structure * -* Returns NETDEV_TX_OK if sent, else an error code +* Return: NETDEV_TX_OK if sent, else an error code */ netdev_tx_t idpf_tx_start (struct sk_buff *skb,struct net_device *netdev) {
@@ -3267,10 +3276,10 @@ idpf_rx_splitq_extract_csum_bits(const s* @rx_desc: Receive descriptor * @decoded: Decoded Rx packet type related fields * -* Return 0 on success and error code on failure -* * Populate the skb fields with the total number of RSC segments, RSC payload * length and packet type. +* +* Return: 0 on success and error code on failure */ static int idpf_rx_rsc(struct idpf_rx_queue *rxq, struct sk_buff *skb, const struct virtchnl2_rx_flex_desc_adv_nic_3 *rx_desc,
@@ -3372,6 +3381,8 @@ idpf_rx_hwtstamp(const struct idpf_rx_qu* This function checks the ring, descriptor, and packet information in * order to populate the hash, checksum, protocol, and * other fields within the skb. +* +* Return: 0 on success and error code on failure */ static int __idpf_rx_process_skb_fields(struct idpf_rx_queue *rxq, struct sk_buff *skb,
@@ -3466,6 +3477,7 @@ static u32 idpf_rx_hsplit_wa(const struc* @stat_err_field: field from descriptor to test bits in * @stat_err_bits: value to mask * +* Return: %true if any of given @stat_err_bits are set, %false otherwise. */ static bool idpf_rx_splitq_test_staterr (const u8 stat_err_field,const u8 stat_err_bits)
@@ -3477,8 +3489,8 @@ static bool idpf_rx_splitq_test_staterr(* idpf_rx_splitq_is_eop - process handling of EOP buffers * @rx_desc: Rx descriptor for current buffer * -* If the buffer is an EOP buffer, this function exits returning true, -* otherwise return false indicating that this is in fact a non-EOP buffer. +* Return: %true if the buffer is an EOP buffer, %false otherwise, indicating +* that this is in fact a non-EOP buffer. */ static bool idpf_rx_splitq_is_eop (struct virtchnl2_rx_flex_desc_adv_nic_3 *rx_desc) {
@@ -3497,7 +3509,7 @@ static bool idpf_rx_splitq_is_eop(struct* expensive overhead for IOMMU access this provides a means of avoiding * it by maintaining the mapping of the page to the system. * -* Returns amount of work completed +* Return: amount of work completed */ static int idpf_rx_splitq_clean (struct idpf_rx_queue *rxq,int budget) {
@@ -3627,7 +3639,7 @@ payload:* @buf_id: buffer ID * @buf_desc: Buffer queue descriptor * -* Return 0 on success and negative on failure. +* Return: 0 on success and negative on failure. */ static int idpf_rx_update_bufq_desc (struct idpf_buf_queue *bufq,u32 buf_id,struct virtchnl2_splitq_rx_buf_desc *buf_desc)
@@ -3754,6 +3766,7 @@ static void idpf_rx_clean_refillq_all(st* @irq: interrupt number * @data: pointer to a q_vector * +* Return: always IRQ_HANDLED */ static irqreturn_t idpf_vport_intr_clean_queues (int __always_unused irq,void *data)
@@ -3875,6 +3888,8 @@ static void idpf_vport_intr_dis_irq_all(/** * idpf_vport_intr_buildreg_itr - Enable default interrupt generation settings * @q_vector: pointer to q_vector +* +* Return: value to be written back to HW to enable interrupt generation */ static u32 idpf_vport_intr_buildreg_itr (struct idpf_q_vector *q_vector) {
@@ -4012,6 +4027,8 @@ void idpf_vport_intr_update_itr_ena_irq(/** * idpf_vport_intr_req_irq - get MSI-X vectors from the OS for the vport * @vport: main vport structure +* +* Return: 0 on success, negative on failure */ static int idpf_vport_intr_req_irq (struct idpf_vport *vport) {
@@ -4222,7 +4239,7 @@ static void idpf_vport_intr_napi_ena_all* @budget: Used to determine if we are in netpoll * @cleaned: returns number of packets cleaned * -* Returns false if clean is not complete else returns true +* Return: %false if clean is not complete else returns %true */ static bool idpf_tx_splitq_clean_all (struct idpf_q_vector *q_vec,int budget,int *cleaned)
@@ -4249,7 +4266,7 @@ static bool idpf_tx_splitq_clean_all(str* @budget: Used to determine if we are in netpoll * @cleaned: returns number of packets cleaned * -* Returns false if clean is not complete else returns true +* Return: %false if clean is not complete else returns %true */ static bool idpf_rx_splitq_clean_all (struct idpf_q_vector *q_vec,int budget,int *cleaned)
@@ -4292,6 +4309,8 @@ static bool idpf_rx_splitq_clean_all(str* idpf_vport_splitq_napi_poll - NAPI handler * @napi: struct from which you get q_vector * @budget: budget provided by stack +* +* Return: how many packets were cleaned */ static int idpf_vport_splitq_napi_poll (struct napi_struct *napi,int budget) {
@@ -4440,7 +4459,9 @@ static void idpf_vport_intr_map_vector_t* idpf_vport_intr_init_vec_idx - Initialize the vector indexes * @vport: virtual port * -* Initialize vector indexes with values returened over mailbox +* Initialize vector indexes with values returned over mailbox. +* +* Return: 0 on success, negative on failure */ static int idpf_vport_intr_init_vec_idx (struct idpf_vport *vport) {
@@ -4506,8 +4527,9 @@ static void idpf_vport_intr_napi_add_all* idpf_vport_intr_alloc - Allocate memory for interrupt vectors * @vport: virtual port * -* We allocate one q_vector per queue interrupt. If allocation fails we -* return -ENOMEM. +* Allocate one q_vector per queue interrupt. +* +* Return: 0 on success, if allocation fails we return -ENOMEM. */ int idpf_vport_intr_alloc (struct idpf_vport *vport) {
@@ -4594,7 +4616,7 @@ error:* idpf_vport_intr_init - Setup all vectors for the given vport * @vport: virtual port * -* Returns 0 on success or negative on failure +* Return: 0 on success or negative on failure */ int idpf_vport_intr_init (struct idpf_vport *vport) {
@@ -4633,7 +4655,7 @@ void idpf_vport_intr_ena(struct idpf_vpo* idpf_config_rss - Send virtchnl messages to configure RSS * @vport: virtual port * -* Return 0 on success, negative on failure +* Return: 0 on success, negative on failure */ int idpf_config_rss (struct idpf_vport *vport) {
Greg Kroah-Hartman
maintainerPATCH 1225/1250 idpf: introduce local idpf structure to store virtchnl queue chunks
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pavan Kumar Linga <[email protected]>
[ Upstream commit d83d80347dea37e568ca9abf969ee909859a5a7d ]
Queue ID and register info received from device Control Plane is stored locally in the same little endian format. As the queue chunks are retrieved in 3 functions, lexx_to_cpu conversions are done each time. Instead introduce a new idpf structure to store the received queue info. It also avoids conditional check to retrieve queue chunks.
With this change, there is no need to store the queue chunks in 'req_qs_chunks' field. So remove that.
Stable-dep-of: 7dd4c829bac2 ("idpf: disable DIM work before freeing q_vectors")
--- drivers/net/ethernet/intel/idpf/idpf.h | 31 ++++ drivers/net/ethernet/intel/idpf/idpf_lib.c | 43 ++++-- drivers/net/ethernet/intel/idpf/idpf_virtchnl.c | 170 ++++++++++++------------ drivers/net/ethernet/intel/idpf/idpf_virtchnl.h | 18 +- 4 files changed, 161 insertions(+), 101 deletions(-)
drivers/net/ethernet/intel/idpf/idpf.h +29 -2
@@ -550,10 +550,37 @@ struct idpf_vector_lifo { };/** +* struct idpf_queue_id_reg_chunk - individual queue ID and register chunk +* @qtail_reg_start: queue tail register offset +* @qtail_reg_spacing: queue tail register spacing +* @type: queue type of the queues in the chunk +* @start_queue_id: starting queue ID in the chunk +* @num_queues: number of queues in the chunk +*/ +struct idpf_queue_id_reg_chunk { +u64 qtail_reg_start; +u32 qtail_reg_spacing; +u32 type; +u32 start_queue_id; +u32 num_queues; +}; + +/** +* struct idpf_queue_id_reg_info - queue ID and register chunk info received +* over the mailbox +* @num_chunks: number of chunks +* @queue_chunks: array of chunks +*/ +struct idpf_queue_id_reg_info { +u16 num_chunks; +struct idpf_queue_id_reg_chunk *queue_chunks; +}; + +/** * struct idpf_vport_config - Vport configuration data * @user_config: see struct idpf_vport_user_config_data * @max_q: Maximum possible queues -* @req_qs_chunks: Queue chunk data for requested queues +* @qid_reg_info: Struct to store the queue ID and register info * @mac_filter_list_lock: Lock to protect mac filters * @flow_steer_list_lock: Lock to protect fsteer filters * @flags: See enum idpf_vport_config_flags
@@ -561,7 +588,7 @@ struct idpf_vector_lifo {struct idpf_vport_config {struct idpf_vport_user_config_data user_config;struct idpf_vport_max_q max_q; -struct virtchnl2_add_queues *req_qs_chunks; +struct idpf_queue_id_reg_info qid_reg_info;spinlock_t mac_filter_list_lock;spinlock_t flow_steer_list_lock; DECLARE_BITMAP(flags, IDPF_VPORT_CONFIG_FLAGS_NBITS);
drivers/net/ethernet/intel/idpf/idpf_lib.c +29 -14
131 lines not on this page · raw message
drivers/net/ethernet/intel/idpf/idpf_virtchnl.c +89 -81
311 lines not on this page · raw message
drivers/net/ethernet/intel/idpf/idpf_virtchnl.h +14 -4
@@ -93,6 +93,7 @@ struct idpf_netdev_priv;struct idpf_vec_regs ;struct idpf_vport ;struct idpf_vport_max_q ; +struct idpf_vport_config ;struct idpf_vport_user_config_data ; ssize_t idpf_vc_xn_exec(struct idpf_adapter *adapter,
@@ -104,8 +105,16 @@ void idpf_vc_core_deinit(struct idpf_adaint idpf_get_reg_intr_vecs (struct idpf_vport *vport,struct idpf_vec_regs *reg_vals); -int idpf_queue_reg_init (struct idpf_vport *vport); -int idpf_vport_queue_ids_init (struct idpf_vport *vport); +int idpf_queue_reg_init (struct idpf_vport *vport, +struct idpf_queue_id_reg_info *chunks); +int idpf_vport_queue_ids_init (struct idpf_vport *vport, +struct idpf_queue_id_reg_info *chunks); +static inline void +idpf_vport_deinit_queue_reg_chunks (struct idpf_vport_config *vport_cfg) +{ +kfree (vport_cfg->qid_reg_info.queue_chunks); + vport_cfg->qid_reg_info.queue_chunks =NULL ; +}bool idpf_vport_is_cap_ena (struct idpf_vport *vport,u16 flag);bool idpf_sideband_flow_type_ena (struct idpf_vport *vport,u32 flow_type);
@@ -144,7 +153,7 @@ int idpf_send_disable_queues_msg(structint idpf_send_config_queues_msg (struct idpf_vport *vport);int idpf_send_enable_queues_msg (struct idpf_vport *vport); -void idpf_vport_init (struct idpf_vport *vport,struct idpf_vport_max_q *max_q); +int idpf_vport_init (struct idpf_vport *vport,struct idpf_vport_max_q *max_q);u32 idpf_get_vport_id (struct idpf_vport *vport);int idpf_send_create_vport_msg (struct idpf_adapter *adapter,struct idpf_vport_max_q *max_q);
@@ -159,7 +168,8 @@ void idpf_vport_dealloc_max_qs(struct id struct idpf_vport_max_q *max_q);int idpf_send_add_queues_msg (const struct idpf_vport *vport,u16 num_tx_q,u16 num_complq,u16 num_rx_q,u16 num_rx_bufq); -int idpf_send_delete_queues_msg (struct idpf_vport *vport); +int idpf_send_delete_queues_msg (struct idpf_vport *vport, +struct idpf_queue_id_reg_info *chunks);int idpf_vport_alloc_vec_indexes (struct idpf_vport *vport); int idpf_get_vec_ids(struct idpf_adapter *adapter,
Greg Kroah-Hartman
maintainerPATCH 1226/1250 idpf: introduce idpf_q_vec_rsrc struct and move vector resources to it
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pavan Kumar Linga <[email protected]>
[ Upstream commit d1061502f353d5e1a8937181b84b722e75fabf11 ]
To group all the vector and queue resources, introduce idpf_q_vec_rsrc structure. This helps to reuse the same config path functions by other features. For example, PTP implementation can use the existing config infrastructure to configure secondary mailbox by passing its queue and vector info. It also helps to avoid any duplication of code.
Existing queue and vector resources are grouped as default resources. This patch moves vector info to the newly introduced structure. Following patch moves the queue resources.
While at it, declare the loop iterator for 'num_q_vectors' in loop and use the correct type.
Include idpf_q_vec_rsrc backpointer in idpf_alloc_queue_set along with vport.
Stable-dep-of: 7dd4c829bac2 ("idpf: disable DIM work before freeing q_vectors")
--- drivers/net/ethernet/intel/idpf/idpf.h | 39 ++-- drivers/net/ethernet/intel/idpf/idpf_dev.c | 16 + drivers/net/ethernet/intel/idpf/idpf_lib.c | 35 ++-- drivers/net/ethernet/intel/idpf/idpf_txrx.c | 199 ++++++++++++------------ drivers/net/ethernet/intel/idpf/idpf_txrx.h | 14 + drivers/net/ethernet/intel/idpf/idpf_vf_dev.c | 16 + drivers/net/ethernet/intel/idpf/idpf_virtchnl.c | 34 ++-- drivers/net/ethernet/intel/idpf/idpf_virtchnl.h | 8 8 files changed, 201 insertions(+), 160 deletions(-)
drivers/net/ethernet/intel/idpf/idpf.h +24 -15
@@ -8,6 +8,7 @@struct idpf_adapter ;struct idpf_vport ;struct idpf_vport_max_q ; +struct idpf_q_vec_rsrc ;#include <net/pkt_sched.h> #include <linux/aer.h>
@@ -201,7 +202,8 @@ struct idpf_vport_max_q {struct idpf_reg_ops {void (*ctlq_reg_init)(struct idpf_adapter *adapter,struct idpf_ctlq_create_info *cq); -int (*intr_reg_init)(struct idpf_vport *vport); +int (*intr_reg_init)(struct idpf_vport *vport, +struct idpf_q_vec_rsrc *rsrc);void (*mb_intr_reg_init)(struct idpf_adapter *adapter);void (*reset_reg_init)(struct idpf_adapter *adapter); void (*trigger_reset)(struct idpf_adapter *adapter,
@@ -288,7 +290,27 @@ struct idpf_fsteer_fltr { };/** +* struct idpf_q_vec_rsrc - handle for queue and vector resources +* @q_vectors: array of queue vectors +* @q_vector_idxs: starting index of queue vectors +* @num_q_vectors: number of IRQ vectors allocated +* @noirq_v_idx: ID of the NOIRQ vector +* @noirq_dyn_ctl_ena: value to write to the above to enable it +* @noirq_dyn_ctl: register to enable/disable the vector for NOIRQ queues +*/ +struct idpf_q_vec_rsrc { +struct idpf_q_vector *q_vectors; +u16 *q_vector_idxs; +u16 num_q_vectors; +u16 noirq_v_idx; +u32 noirq_dyn_ctl_ena; +void __iomem *noirq_dyn_ctl; + +}; + +/** * struct idpf_vport - Handle for netdevices and queue resources +* @dflt_qv_rsrc: contains default queue and vector resources * @num_txq: Number of allocated TX queues * @num_complq: Number of allocated completion queues * @txq_desc_count: TX queue descriptor count
@@ -325,12 +347,6 @@ struct idpf_fsteer_fltr {* @idx: Software index in adapter vports struct * @default_vport: Use this vport if one isn't specified * @base_rxd: True if the driver should use base descriptors instead of flex -* @num_q_vectors: Number of IRQ vectors allocated -* @q_vectors: Array of queue vectors -* @q_vector_idxs: Starting index of queue vectors -* @noirq_dyn_ctl: register to enable/disable the vector for NOIRQ queues -* @noirq_dyn_ctl_ena: value to write to the above to enable it -* @noirq_v_idx: ID of the NOIRQ vector * @max_mtu: device given max possible MTU * @default_mac_addr: device will give a default MAC to use * @rx_itr_profile: RX profiles for Dynamic Interrupt Moderation
@@ -343,6 +359,7 @@ struct idpf_fsteer_fltr {* @tstamp_stats: Tx timestamping statistics */ struct idpf_vport { +struct idpf_q_vec_rsrc dflt_qv_rsrc;u16 num_txq;u16 num_complq;u32 txq_desc_count;
@@ -380,14 +397,6 @@ struct idpf_vport {bool default_vport;bool base_rxd; -u16 num_q_vectors; -struct idpf_q_vector *q_vectors; -u16 *q_vector_idxs; - -void __iomem *noirq_dyn_ctl; -u32 noirq_dyn_ctl_ena; -u16 noirq_v_idx; -u16 max_mtu;u8 default_mac_addr[ETH_ALEN ];u16 rx_itr_profile[IDPF_DIM_PROFILE_SLOTS ];
drivers/net/ethernet/intel/idpf/idpf_dev.c +9 -7
@@ -70,11 +70,13 @@ static void idpf_mb_intr_reg_init(struct/** * idpf_intr_reg_init - Initialize interrupt registers * @vport: virtual port structure +* @rsrc: pointer to queue and vector resources */ -static int idpf_intr_reg_init (struct idpf_vport *vport) +static int idpf_intr_reg_init (struct idpf_vport *vport, +struct idpf_q_vec_rsrc *rsrc) {struct idpf_adapter *adapter = vport->adapter; -int num_vecs = vport->num_q_vectors; +u16 num_vecs = rsrc->num_q_vectors;struct idpf_vec_regs *reg_vals;int num_regs, i, err =0 ;u32 rx_itr, tx_itr, val;
@@ -93,8 +95,8 @@ static int idpf_intr_reg_init(struct idp }for (i =0 ; i < num_vecs; i++) { -struct idpf_q_vector *q_vector = &vport->q_vectors[i]; -u16 vec_id = vport->q_vector_idxs[i] -IDPF_MBX_Q_VEC ; +struct idpf_q_vector *q_vector = &rsrc->q_vectors[i]; +u16 vec_id = rsrc->q_vector_idxs[i] -IDPF_MBX_Q_VEC ;struct idpf_intr_reg *intr = &q_vector->intr_reg;u32 spacing;
@@ -123,12 +125,12 @@ static int idpf_intr_reg_init(struct idp/* Data vector for NOIRQ queues */ - val = reg_vals[vport->q_vector_idxs[i] -IDPF_MBX_Q_VEC ].dyn_ctl_reg; - vport->noirq_dyn_ctl =idpf_get_reg_addr (adapter, val); + val = reg_vals[rsrc->q_vector_idxs[i] -IDPF_MBX_Q_VEC ].dyn_ctl_reg; + rsrc->noirq_dyn_ctl =idpf_get_reg_addr (adapter, val); val =PF_GLINT_DYN_CTL_WB_ON_ITR_M |PF_GLINT_DYN_CTL_INTENA_MSK_M |FIELD_PREP (PF_GLINT_DYN_CTL_ITR_INDX_M ,IDPF_NO_ITR_UPDATE_IDX ); - vport->noirq_dyn_ctl_ena = val; + rsrc->noirq_dyn_ctl_ena = val; free_reg_vals:kfree (reg_vals);
drivers/net/ethernet/intel/idpf/idpf_lib.c +20 -15
@@ -975,6 +975,7 @@ static void idpf_remove_features(structstatic void idpf_vport_stop (struct idpf_vport *vport,bool rtnl) {struct idpf_netdev_priv *np =netdev_priv (vport->netdev); +struct idpf_q_vec_rsrc *rsrc = &vport->dflt_qv_rsrc;struct idpf_queue_id_reg_info *chunks;if (!test_bit (IDPF_VPORT_UP , np->state))
@@ -1002,10 +1003,10 @@ static void idpf_vport_stop(struct idpf_idpf_remove_features (vport); vport->link_up = false; -idpf_vport_intr_deinit (vport); +idpf_vport_intr_deinit (vport, rsrc);idpf_xdp_rxq_info_deinit_all (vport);idpf_vport_queues_rel (vport); -idpf_vport_intr_rel (vport); +idpf_vport_intr_rel (rsrc);clear_bit (IDPF_VPORT_UP , np->state);if (rtnl)
@@ -1068,6 +1069,7 @@ static void idpf_decfg_netdev(struct idp*/ static void idpf_vport_rel (struct idpf_vport *vport) { +struct idpf_q_vec_rsrc *rsrc = &vport->dflt_qv_rsrc;struct idpf_adapter *adapter = vport->adapter;struct idpf_vport_config *vport_config;struct idpf_vector_info vec_info;
@@ -1092,13 +1094,13 @@ static void idpf_vport_rel(struct idpf_v/* Release all the allocated vectors on the stack */ vec_info.num_req_vecs =0 ; - vec_info.num_curr_vecs = vport->num_q_vectors; + vec_info.num_curr_vecs = rsrc->num_q_vectors; vec_info.default_vport = vport->default_vport; -idpf_req_rel_vector_indexes (adapter, vport->q_vector_idxs, &vec_info); +idpf_req_rel_vector_indexes (adapter, rsrc->q_vector_idxs, &vec_info); -kfree (vport->q_vector_idxs); - vport->q_vector_idxs =NULL ; +kfree (rsrc->q_vector_idxs); + rsrc->q_vector_idxs =NULL ;idpf_vport_deinit_queue_reg_chunks (vport_config);
@@ -1226,6 +1228,7 @@ static struct idpf_vport *idpf_vport_all {struct idpf_rss_data *rss_data;u16 idx = adapter->next_vport; +struct idpf_q_vec_rsrc *rsrc;struct idpf_vport *vport;u16 num_max_q;int err;
@@ -1273,8 +1276,9 @@ static struct idpf_vport *idpf_vport_all vport->default_vport = adapter->num_alloc_vports <idpf_get_default_vports (adapter); - vport->q_vector_idxs =kcalloc (num_max_q,sizeof (u16),GFP_KERNEL ); -if (!vport->q_vector_idxs) + rsrc = &vport->dflt_qv_rsrc; + rsrc->q_vector_idxs =kcalloc (num_max_q,sizeof (u16),GFP_KERNEL ); +if (!rsrc->q_vector_idxs) goto free_vport; err =idpf_vport_init (vport, max_q);
@@ -1315,7 +1319,7 @@ free_rss_key: free_qreg_chunks:idpf_vport_deinit_queue_reg_chunks (adapter->vport_config[idx]); free_vector_idxs: -kfree (vport->q_vector_idxs); +kfree (rsrc->q_vector_idxs); free_vport:kfree (vport);
@@ -1489,6 +1493,7 @@ static void idpf_rx_init_buf_tail(structstatic int idpf_vport_open (struct idpf_vport *vport,bool rtnl) {struct idpf_netdev_priv *np =netdev_priv (vport->netdev); +struct idpf_q_vec_rsrc *rsrc = &vport->dflt_qv_rsrc;struct idpf_adapter *adapter = vport->adapter;struct idpf_vport_config *vport_config;struct idpf_queue_id_reg_info *chunks;
@@ -1503,7 +1508,7 @@ static int idpf_vport_open(struct idpf_v/* we do not allow interface up just yet */ netif_carrier_off (vport->netdev); - err =idpf_vport_intr_alloc (vport); + err =idpf_vport_intr_alloc (vport, rsrc);if (err) {dev_err (&adapter->pdev->dev,"Failed to allocate interrupts for vport %u: %d\n" , vport->vport_id, err);
@@ -1524,7 +1529,7 @@ static int idpf_vport_open(struct idpf_v goto queues_rel; } - err =idpf_vport_intr_init (vport); + err =idpf_vport_intr_init (vport, rsrc);if (err) {dev_err (&adapter->pdev->dev,"Failed to initialize interrupts for vport %u: %d\n" , vport->vport_id, err);
@@ -1555,7 +1560,7 @@ static int idpf_vport_open(struct idpf_v goto intr_deinit; } -idpf_vport_intr_ena (vport); +idpf_vport_intr_ena (vport, rsrc); err =idpf_send_config_queues_msg (vport);if (err) {
@@ -1616,11 +1621,11 @@ unmap_queue_vectors: rxq_deinit:idpf_xdp_rxq_info_deinit_all (vport); intr_deinit: -idpf_vport_intr_deinit (vport); +idpf_vport_intr_deinit (vport, rsrc); queues_rel:idpf_vport_queues_rel (vport); intr_rel: -idpf_vport_intr_rel (vport); +idpf_vport_intr_rel (rsrc); err_rtnl_unlock:if (rtnl)
@@ -2086,7 +2091,7 @@ int idpf_initiate_soft_reset(struct idpfmemcpy (vport, new_vport, offsetof(struct idpf_vport , link_up));if (reset_cause ==IDPF_SR_Q_CHANGE ) -idpf_vport_alloc_vec_indexes (vport); +idpf_vport_alloc_vec_indexes (vport, &vport->dflt_qv_rsrc); err =idpf_set_real_num_queues (vport);if (err)
drivers/net/ethernet/intel/idpf/idpf_txrx.c +104 -95
470 lines not on this page · raw message
drivers/net/ethernet/intel/idpf/idpf_txrx.h +9 -5
@@ -1080,12 +1080,16 @@ int idpf_vport_calc_total_qs(struct idpfvoid idpf_vport_calc_num_q_groups (struct idpf_vport *vport);int idpf_vport_queues_alloc (struct idpf_vport *vport);void idpf_vport_queues_rel (struct idpf_vport *vport); -void idpf_vport_intr_rel (struct idpf_vport *vport); -int idpf_vport_intr_alloc (struct idpf_vport *vport); +void idpf_vport_intr_rel (struct idpf_q_vec_rsrc *rsrc); +int idpf_vport_intr_alloc (struct idpf_vport *vport, +struct idpf_q_vec_rsrc *rsrc);void idpf_vport_intr_update_itr_ena_irq (struct idpf_q_vector *q_vector); -void idpf_vport_intr_deinit (struct idpf_vport *vport); -int idpf_vport_intr_init (struct idpf_vport *vport); -void idpf_vport_intr_ena (struct idpf_vport *vport); +void idpf_vport_intr_deinit (struct idpf_vport *vport, +struct idpf_q_vec_rsrc *rsrc); +int idpf_vport_intr_init (struct idpf_vport *vport, +struct idpf_q_vec_rsrc *rsrc); +void idpf_vport_intr_ena (struct idpf_vport *vport, +struct idpf_q_vec_rsrc *rsrc);void idpf_fill_dflt_rss_lut (struct idpf_vport *vport);int idpf_config_rss (struct idpf_vport *vport);int idpf_init_rss_lut (struct idpf_vport *vport);
drivers/net/ethernet/intel/idpf/idpf_vf_dev.c +9 -7
@@ -69,11 +69,13 @@ static void idpf_vf_mb_intr_reg_init(str/** * idpf_vf_intr_reg_init - Initialize interrupt registers * @vport: virtual port structure +* @rsrc: pointer to queue and vector resources */ -static int idpf_vf_intr_reg_init (struct idpf_vport *vport) +static int idpf_vf_intr_reg_init (struct idpf_vport *vport, +struct idpf_q_vec_rsrc *rsrc) {struct idpf_adapter *adapter = vport->adapter; -int num_vecs = vport->num_q_vectors; +u16 num_vecs = rsrc->num_q_vectors;struct idpf_vec_regs *reg_vals;int num_regs, i, err =0 ;u32 rx_itr, tx_itr, val;
@@ -92,8 +94,8 @@ static int idpf_vf_intr_reg_init(struct }for (i =0 ; i < num_vecs; i++) { -struct idpf_q_vector *q_vector = &vport->q_vectors[i]; -u16 vec_id = vport->q_vector_idxs[i] -IDPF_MBX_Q_VEC ; +struct idpf_q_vector *q_vector = &rsrc->q_vectors[i]; +u16 vec_id = rsrc->q_vector_idxs[i] -IDPF_MBX_Q_VEC ;struct idpf_intr_reg *intr = &q_vector->intr_reg;u32 spacing;
@@ -122,12 +124,12 @@ static int idpf_vf_intr_reg_init(struct/* Data vector for NOIRQ queues */ - val = reg_vals[vport->q_vector_idxs[i] -IDPF_MBX_Q_VEC ].dyn_ctl_reg; - vport->noirq_dyn_ctl =idpf_get_reg_addr (adapter, val); + val = reg_vals[rsrc->q_vector_idxs[i] -IDPF_MBX_Q_VEC ].dyn_ctl_reg; + rsrc->noirq_dyn_ctl =idpf_get_reg_addr (adapter, val); val =VF_INT_DYN_CTLN_WB_ON_ITR_M |VF_INT_DYN_CTLN_INTENA_MSK_M |FIELD_PREP (VF_INT_DYN_CTLN_ITR_INDX_M ,IDPF_NO_ITR_UPDATE_IDX ); - vport->noirq_dyn_ctl_ena = val; + rsrc->noirq_dyn_ctl_ena = val; free_reg_vals:kfree (reg_vals);
drivers/net/ethernet/intel/idpf/idpf_virtchnl.c +20 -14
@@ -732,7 +732,9 @@ struct idpf_chunked_msg_params {u32 vc_op; }; -struct idpf_queue_set *idpf_alloc_queue_set (struct idpf_vport *vport,u32 num) +struct idpf_queue_set *idpf_alloc_queue_set (struct idpf_vport *vport, +struct idpf_q_vec_rsrc *qv_rsrc, +u32 num) {struct idpf_queue_set *qp;
@@ -741,6 +743,7 @@ struct idpf_queue_set *idpf_alloc_queue_return NULL ; qp->vport = vport; + qp->qv_rsrc = qv_rsrc; qp->num = num;return qp;
@@ -847,7 +850,7 @@ static int idpf_wait_for_marker_event(st { struct idpf_queue_set *qs __free(kfree) = NULL; - qs =idpf_alloc_queue_set (vport, vport->num_txq); + qs =idpf_alloc_queue_set (vport, &vport->dflt_qv_rsrc, vport->num_txq);if (!qs)return -ENOMEM ;
@@ -1860,7 +1863,7 @@ static int idpf_send_config_tx_queues_msu32 totqs = vport->num_txq + vport->num_complq;u32 k =0 ; - qs =idpf_alloc_queue_set (vport, totqs); + qs =idpf_alloc_queue_set (vport, &vport->dflt_qv_rsrc, totqs);if (!qs)return -ENOMEM ;
@@ -2045,7 +2048,7 @@ static int idpf_send_config_rx_queues_msu32 totqs = vport->num_rxq + vport->num_bufq;u32 k =0 ; - qs =idpf_alloc_queue_set (vport, totqs); + qs =idpf_alloc_queue_set (vport, &vport->dflt_qv_rsrc, totqs);if (!qs)return -ENOMEM ;
@@ -2190,7 +2193,7 @@ static int idpf_send_ena_dis_queues_msg( num_txq = vport->num_txq + vport->num_complq; num_q = num_txq + vport->num_rxq + vport->num_bufq; - qs =idpf_alloc_queue_set (vport, num_q); + qs =idpf_alloc_queue_set (vport, &vport->dflt_qv_rsrc, num_q);if (!qs)return -ENOMEM ;
@@ -2328,7 +2331,7 @@ idpf_send_map_unmap_queue_set_vector_msg v_idx = vec->v_idx; itr_idx = vec->rx_itr_idx; }else { - v_idx = qs->vport->noirq_v_idx; + v_idx = qs->qv_rsrc->noirq_v_idx; itr_idx =VIRTCHNL2_ITR_IDX_0 ; }break ;
@@ -2348,7 +2351,7 @@ idpf_send_map_unmap_queue_set_vector_msg v_idx = vec->v_idx; itr_idx = vec->tx_itr_idx; }else { - v_idx = qs->vport->noirq_v_idx; + v_idx = qs->qv_rsrc->noirq_v_idx; itr_idx =VIRTCHNL2_ITR_IDX_1 ; }break ;
@@ -2378,7 +2381,7 @@ int idpf_send_map_unmap_queue_vector_msgu32 num_q = vport->num_txq + vport->num_rxq;u32 k =0 ; - qs =idpf_alloc_queue_set (vport, num_q); + qs =idpf_alloc_queue_set (vport, &vport->dflt_qv_rsrc, num_q);if (!qs)return -ENOMEM ;
@@ -3624,20 +3627,22 @@ void idpf_vc_core_deinit(struct idpf_ada/** * idpf_vport_alloc_vec_indexes - Get relative vector indexes * @vport: virtual port data struct +* @rsrc: pointer to queue and vector resources * * This function requests the vector information required for the vport and * stores the vector indexes received from the 'global vector distribution' * in the vport's queue vectors array. * -* Return 0 on success, error on failure +* Return: 0 on success, error on failure */ -int idpf_vport_alloc_vec_indexes (struct idpf_vport *vport) +int idpf_vport_alloc_vec_indexes (struct idpf_vport *vport, +struct idpf_q_vec_rsrc *rsrc) {struct idpf_vector_info vec_info;int num_alloc_vecs;u32 req; - vec_info.num_curr_vecs = vport->num_q_vectors; + vec_info.num_curr_vecs = rsrc->num_q_vectors;if (vec_info.num_curr_vecs) vec_info.num_curr_vecs +=IDPF_RESERVED_VECS ;
@@ -3650,7 +3655,7 @@ int idpf_vport_alloc_vec_indexes(struct vec_info.index = vport->idx; num_alloc_vecs =idpf_req_rel_vector_indexes (vport->adapter, - vport->q_vector_idxs, + rsrc->q_vector_idxs, &vec_info);if (num_alloc_vecs <=0 ) { dev_err(&vport->adapter->pdev->dev, "Vector distribution failed: %d\n",
@@ -3658,7 +3663,7 @@ int idpf_vport_alloc_vec_indexes(structreturn -EINVAL ; } - vport->num_q_vectors = num_alloc_vecs -IDPF_RESERVED_VECS ; + rsrc->num_q_vectors = num_alloc_vecs -IDPF_RESERVED_VECS ;return 0 ; }
@@ -3674,6 +3679,7 @@ int idpf_vport_alloc_vec_indexes(struct*/ int idpf_vport_init (struct idpf_vport *vport,struct idpf_vport_max_q *max_q) { +struct idpf_q_vec_rsrc *rsrc = &vport->dflt_qv_rsrc;struct idpf_adapter *adapter = vport->adapter;struct virtchnl2_create_vport *vport_msg;struct idpf_vport_config *vport_config;
@@ -3718,7 +3724,7 @@ int idpf_vport_init(struct idpf_vport *vidpf_vport_init_num_qs (vport, vport_msg);idpf_vport_calc_num_q_desc (vport);idpf_vport_calc_num_q_groups (vport); -idpf_vport_alloc_vec_indexes (vport); +idpf_vport_alloc_vec_indexes (vport, rsrc); vport->crc_enable = adapter->crc_enable;
drivers/net/ethernet/intel/idpf/idpf_virtchnl.h +6 -2
@@ -138,12 +138,15 @@ struct idpf_queue_ptr {struct idpf_queue_set {struct idpf_vport *vport; +struct idpf_q_vec_rsrc *qv_rsrc;u32 num; struct idpf_queue_ptr qs[] __counted_by(num); }; -struct idpf_queue_set *idpf_alloc_queue_set (struct idpf_vport *vport,u32 num); +struct idpf_queue_set *idpf_alloc_queue_set (struct idpf_vport *vport, +struct idpf_q_vec_rsrc *rsrc, +u32 num);int idpf_send_enable_queue_set_msg (const struct idpf_queue_set *qs);int idpf_send_disable_queue_set_msg (const struct idpf_queue_set *qs);
@@ -171,7 +174,8 @@ int idpf_send_add_queues_msg(const strucint idpf_send_delete_queues_msg (struct idpf_vport *vport,struct idpf_queue_id_reg_info *chunks); -int idpf_vport_alloc_vec_indexes (struct idpf_vport *vport); +int idpf_vport_alloc_vec_indexes (struct idpf_vport *vport, +struct idpf_q_vec_rsrc *rsrc);int idpf_get_vec_ids (struct idpf_adapter *adapter,u16 *vecids,int num_vecids,struct virtchnl2_vector_chunks *chunks);
Greg Kroah-Hartman
maintainerPATCH 1227/1250 idpf: disable DIM work before freeing q_vectors
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
[ Upstream commit 7dd4c829bac2916be98a3e34b41daaba7f42b4c4 ]
idpf never drains the Tx/Rx DIM works before freeing the memory they live in. tx_dim and rx_dim are embedded in struct idpf_q_vector, they are queued from the NAPI poll via net_dim(), and idpf_vport_intr_rel() ends with kfree(rsrc->q_vectors). Nothing in the driver cancels them.
idpf_tx_dim_work() and idpf_rx_dim_work() then run on freed memory:idpf_vport_intr_write_itr() writes the ITR register through q_vector->intr_reg.tx_itr / rx_itr, void __iomem pointers loaded out of the freed q_vector. No configuration is needed to get there -- IDPF_ITR_IS_DYNAMIC() is defined as (itr_mode) and idpf_vport_alloc() initialises both modes to IDPF_ITR_DYNAMIC.
Draining after idpf_vport_intr_napi_dis_all() is not enough on its own. idpf_net_dim() is called from inside the
"if (napi_complete_done(napi, work_done))" branch of the poll, and napi_complete_done() has already cleared NAPIF_STATE_SCHED by then. napi_disable_locked() waits only while (val & (NAPIF_STATE_SCHED | NAPIF_STATE_NPSVC)), so napi_disable() can return while the poll tail is still queueing the work, and a plain cancel_work_sync() would be re-armed behind the drain.
Use disable_work_sync(): schedule_work() on a work with a non-zero disable count is dropped by clear_pending_if_disabled() before __queue_work() is reached.
Move idpf_init_dim() to idpf_vport_intr_alloc() so the works are initialised on every path that can reach the drain -- the three "goto intr_deinit" sites between idpf_vport_intr_init() and idpf_vport_intr_ena() get there without the enable side having run. Nothing re-enables them: rsrc->q_vectors is freed on every exit from idpf_vport_open() and on every idpf_vport_stop(), so the count dies with the object.
It is a race, not a deterministic failure -- net_dim() only schedules once DIM_NEVENTS events have accumulated and the profile index changes. A KASAN ifup/ifdown loop under load is the way to see it.
--- drivers/net/ethernet/intel/idpf/idpf_txrx.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-)
drivers/net/ethernet/intel/idpf/idpf_txrx.c +23 -1
@@ -4137,6 +4137,26 @@ static void idpf_vport_intr_ena_irq_all( }/** +* idpf_vport_intr_dis_dim_all - Disable DIM work for all q_vectors +* @rsrc: pointer to queue and vector resources +* +* The DIM works are embedded in the q_vector array that +* idpf_vport_intr_rel() frees, and the poll arms them after +* napi_complete_done() has already cleared NAPI_STATE_SCHED. Disable +* rather than just cancel, so that a poll tail still running past +* napi_disable() cannot queue them again behind the drain. +*/ +static void idpf_vport_intr_dis_dim_all (struct idpf_q_vec_rsrc *rsrc) +{ +for (u16 v_idx =0 ; v_idx < rsrc->num_q_vectors; v_idx++) { +struct idpf_q_vector *q_vector = &rsrc->q_vectors[v_idx]; + +disable_work_sync (&q_vector->tx_dim.work); +disable_work_sync (&q_vector->rx_dim.work); + } +} + +/** * idpf_vport_intr_deinit - Release all vector associations for the vport * @vport: main vport structure * @rsrc: pointer to queue and vector resources
@@ -4146,6 +4166,7 @@ void idpf_vport_intr_deinit(struct idpf_ {idpf_vport_intr_dis_irq_all (rsrc);idpf_vport_intr_napi_dis_all (rsrc); +idpf_vport_intr_dis_dim_all (rsrc);idpf_vport_intr_napi_del_all (rsrc);idpf_vport_intr_rel_irq (vport, rsrc); }
@@ -4226,7 +4247,6 @@ static void idpf_vport_intr_napi_ena_allfor (u16 q_idx =0 ; q_idx < rsrc->num_q_vectors; q_idx++) {struct idpf_q_vector *q_vector = &rsrc->q_vectors[q_idx]; -idpf_init_dim (q_vector);napi_enable (&q_vector->napi); } }
@@ -4569,6 +4589,8 @@ int idpf_vport_intr_alloc(struct idpf_vp q_coal = &user_config->q_coalesce[v_idx]; q_vector->vport = vport; +idpf_init_dim (q_vector); + q_vector->tx_itr_value = q_coal->tx_coalesce_usecs; q_vector->tx_intr_mode = q_coal->tx_intr_mode; q_vector->tx_itr_idx =VIRTCHNL2_ITR_IDX_1 ;
Greg Kroah-Hartman
maintainerPATCH 1228/1250 landlock: Clarify documentation for the IOCTL access right
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Günther Noack <[email protected]>
[ Upstream commit 6abbb8703aeeb645a681ab6ad155e0b450413787 ]
Move the description of the LANDLOCK_ACCESS_FS_IOCTL_DEV access right together with the file access rights.
This group of access rights applies to files (in this case device files), and they can be added to file or directory inodes using landlock_add_rule(2). The check for that works the same for all file access rights, including LANDLOCK_ACCESS_FS_IOCTL_DEV.
Invoking ioctl(2) on directory FDs can not currently be restricted with Landlock. Having it grouped separately in the documentation is a remnant from earlier revisions of the LANDLOCK_ACCESS_FS_IOCTL_DEV patch set.
Stable-dep-of: 2c6dc7925382 ("landlock: Fix use-after-free of the source's parent directory")
--- include/uapi/linux/landlock.h | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-)
include/uapi/linux/landlock.h +17 -20
@@ -216,6 +216,23 @@ struct landlock_net_port_attr {* :manpage:`ftruncate(2)`, :manpage:`creat(2)`, or :manpage:`open(2)` with * ``O_TRUNC``. This access right is available since the third version of the * Landlock ABI. +* - %LANDLOCK_ACCESS_FS_IOCTL_DEV: Invoke :manpage:`ioctl(2)` commands on an opened +* character or block device. +* +* This access right applies to all `ioctl(2)` commands implemented by device +* drivers. However, the following common IOCTL commands continue to be +* invokable independent of the %LANDLOCK_ACCESS_FS_IOCTL_DEV right: +* +* * IOCTL commands targeting file descriptors (``FIOCLEX``, ``FIONCLEX``), +* * IOCTL commands targeting file descriptions (``FIONBIO``, ``FIOASYNC``), +* * IOCTL commands targeting file systems (``FIFREEZE``, ``FITHAW``, +* ``FIGETBSZ``, ``FS_IOC_GETFSUUID``, ``FS_IOC_GETFSSYSFSPATH``) +* * Some IOCTL commands which do not make sense when used with devices, but +* whose implementations are safe and return the right error codes +* (``FS_IOC_FIEMAP``, ``FICLONE``, ``FICLONERANGE``, ``FIDEDUPERANGE``) +* +* This access right is available since the fifth version of the Landlock +* ABI. * * Whether an opened file can be truncated with :manpage:`ftruncate(2)` or used * with `ioctl(2)` is determined during :manpage:`open(2)`, in the same way as
@@ -276,26 +293,6 @@ struct landlock_net_port_attr {* If multiple requirements are not met, the ``EACCES`` error code takes * precedence over ``EXDEV``. * -* The following access right applies both to files and directories: -* -* - %LANDLOCK_ACCESS_FS_IOCTL_DEV: Invoke :manpage:`ioctl(2)` commands on an opened -* character or block device. -* -* This access right applies to all `ioctl(2)` commands implemented by device -* drivers. However, the following common IOCTL commands continue to be -* invokable independent of the %LANDLOCK_ACCESS_FS_IOCTL_DEV right: -* -* * IOCTL commands targeting file descriptors (``FIOCLEX``, ``FIONCLEX``), -* * IOCTL commands targeting file descriptions (``FIONBIO``, ``FIOASYNC``), -* * IOCTL commands targeting file systems (``FIFREEZE``, ``FITHAW``, -* ``FIGETBSZ``, ``FS_IOC_GETFSUUID``, ``FS_IOC_GETFSSYSFSPATH``) -* * Some IOCTL commands which do not make sense when used with devices, but -* whose implementations are safe and return the right error codes -* (``FS_IOC_FIEMAP``, ``FICLONE``, ``FICLONERANGE``, ``FIDEDUPERANGE``) -* -* This access right is available since the fifth version of the Landlock -* ABI. -* * .. warning:: * * It is currently not possible to restrict some file-related actions
Greg Kroah-Hartman
maintainerPATCH 1229/1250 landlock: Add access_mask_subset() helper
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Günther Noack <[email protected]>
[ Upstream commit 45f2a2926b2187d1b08132d2728af50785b007a7 ]
This helper function checks whether an access_mask_t has a subset of the bits enabled than another one. This expresses the intent a bit smoother in the code and does not cost us anything when it gets inlined.
Stable-dep-of: 2c6dc7925382 ("landlock: Fix use-after-free of the source's parent directory")
--- security/landlock/access.h | 7 +++++++ security/landlock/fs.c | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-)
security/landlock/access.h +7 -0
@@ -97,4 +97,11 @@ landlock_upgrade_handled_access_masks(st return access_masks; } +/* Checks the subset relation between access masks. */ +static inline bool access_mask_subset (access_mask_t subset, +access_mask_t superset) +{ +return (subset | superset) == superset; +} +#endif /* _SECURITY_LANDLOCK_ACCESS_H */
security/landlock/fs.c +2 -2
@@ -332,7 +332,7 @@ int landlock_append_fs_rule(struct landl/* Files only get access rights that make sense. */ if (!d_is_dir (path->dentry) && - (access_rights |ACCESS_FILE ) !=ACCESS_FILE ) + !access_mask_subset (access_rights,ACCESS_FILE ))return -EINVAL ;if (WARN_ON_ONCE (ruleset->num_layers !=1 ))return -EINVAL ;
@@ -1717,7 +1717,7 @@ static int hook_file_open(struct file *c ARRAY_SIZE(layer_masks));#endif /* CONFIG_AUDIT */ -if ((open_access_request & allowed_access) == open_access_request) +if (access_mask_subset (open_access_request, allowed_access))return 0 ;/* Sets access to reflect the actual request. */
Greg Kroah-Hartman
maintainerPATCH 1230/1250 landlock: Transpose the layer masks data structure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Günther Noack <[email protected]>
[ Upstream commit 65b691f84dba54a446518c51b25d3d4f1739dec5 ]
The layer masks data structure tracks the requested but unfulfilled access rights during an operation's security check. It stores one bit for each combination of access right and layer index. If the bit is set, that access right is not granted (yet) in the given layer and we have to traverse the path further upwards to grant it.
Previously, the layer masks were stored as arrays mapping from access right indices to layer_mask_t. The layer_mask_t value then indicates all layers in which the given access right is still (tentatively) denied.
This patch introduces struct layer_access_masks instead: This struct contains an array with the access_mask_t of each (tentatively) denied access right in that layer.
The hypothesis of this patch is that this simplifies the code enough so that the resulting code will run faster:
* We can use bitwise operations in multiple places where we previously looped over bits individually with macros. (Should require less branch speculation and lends itself to better loop unrolling.)
* Code is ~75 lines smaller.
Other noteworthy changes:
* In no_more_access(), call a new helper function may_refer(), which only solves the asymmetric case. Previously, the code interleaved the checks for the two symmetric cases in RENAME_EXCHANGE. It feels that the code is clearer when renames without RENAME_EXCHANGE are more obviously the normal case.
Tradeoffs:
This change improves performance, at a slight size increase to the layer masks data structure.
This fixes the size of the data structure at 32 bytes for all types of access rights. (64, once we introduce a 17th filesystem access right).
For filesystem access rights, at the moment, the data structure has the same size as before, but once we introduce the 17th filesystem access right, it will double in size (from 32 to 64 bytes), as access_mask_t grows from 16 to 32 bit [1].
Stable backport notes:
Resolve the landlock_unmask_layers() comment conflict by keeping the per-layer access-mask implementation while preserving the stable tree's other ruleset changes.
Keep the forward and RENAME_EXCHANGE restriction checks inside the existing no_more_access() function instead of adding may_refer(). Both checks retain the per-layer subset comparison and file-only filtering. No new functions are introduced by this backport.
Remove the extra blank line before the combined parent-access success check in current_check_refer_path() to match the context required by 2c6dc792538260a8087ac5b22c31b3b8e47c85d6. The parent-dentry reference fix itself remains in that target commit.
Stable-dep-of: 2c6dc7925382 ("landlock: Fix use-after-free of the source's parent directory")
--- security/landlock/access.h | 28 ++- security/landlock/audit.c | 81 +++------- security/landlock/audit.h | 3 security/landlock/domain.c | 44 +++-- security/landlock/domain.h | 3 security/landlock/fs.c | 333 +++++++++++++++++++------------------------- security/landlock/net.c | 9 - security/landlock/ruleset.c | 93 ++++-------- security/landlock/ruleset.h | 6 9 files changed, 262 insertions(+), 338 deletions(-)
security/landlock/access.h +22 -6
@@ -61,14 +61,30 @@ union access_masks_all {static_assert (sizeof (typeof_member (union access_masks_all ,masks )) ==sizeof (typeof_member (union access_masks_all ,all ))); -typedef u16 layer_mask_t ; - -/* Makes sure all layers can be checked. */ -static_assert (BITS_PER_TYPE (layer_mask_t) >=LANDLOCK_MAX_NUM_LAYERS ); +/** +* struct layer_access_masks - A boolean matrix of layers and access rights +* +* This has a bit for each combination of layer numbers and access rights. +* During access checks, it is used to represent the access rights for each +* layer which still need to be fulfilled. When all bits are 0, the access +* request is considered to be fulfilled. +*/ +struct layer_access_masks { +/** +* @access: The unfulfilled access rights for each layer. +*/ +access_mask_t access[LANDLOCK_MAX_NUM_LAYERS ]; +};/* -* Tracks domains responsible of a denied access. This is required to avoid -* storing in each object the full layer_masks[] required by update_request(). +* Tracks domains responsible of a denied access. This avoids storing in each +* object the full matrix of per-layer unfulfilled access rights, which is +* required by update_request(). +* +* Each nibble represents the layer index of the newest layer which denied a +* certain access right. For file system access rights, the upper four bits are +* the index of the layer which denies LANDLOCK_ACCESS_FS_IOCTL_DEV and the +* lower nibble represents LANDLOCK_ACCESS_FS_TRUNCATE. */ typedef u8 deny_masks_t ;
security/landlock/audit.c +25 -56
134 lines not on this page · raw message
security/landlock/audit.h +1 -2
@@ -43,8 +43,7 @@ struct landlock_request {access_mask_t access;/* Required fields for requests with layer masks. */ -const layer_mask_t (*layer_masks)[]; -size_t layer_masks_size; +const struct layer_access_masks *layer_masks;/* Required fields for requests with deny masks. */ const access_mask_t all_existing_optional_access;
security/landlock/domain.c +24 -20
84 lines not on this page · raw message
security/landlock/domain.h +1 -2
@@ -119,8 +119,7 @@ struct landlock_hierarchy {deny_masks_t landlock_get_deny_masks (const access_mask_t all_existing_optional_access,const access_mask_t optional_access, -const layer_mask_t (*const layer_masks)[], -size_t layer_masks_size); +const struct layer_access_masks *const masks);int landlock_init_hierarchy_log (struct landlock_hierarchy *const hierarchy);
security/landlock/fs.c +146 -187
525 lines not on this page · raw message
security/landlock/net.c +5 -4
@@ -48,7 +48,7 @@ static int current_check_access_socket(s {unsigned short sock_family;__be16 port; -layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_NET ] = {}; +struct layer_access_masks layer_masks = {};const struct landlock_rule *rule;struct landlock_id id = { .type =LANDLOCK_KEY_NET_PORT ,
@@ -201,8 +201,10 @@ static int current_check_access_socket(s access_request =landlock_init_layer_masks (subject->domain, access_request, &layer_masks,LANDLOCK_KEY_NET_PORT ); -if (landlock_unmask_layers (rule, access_request, &layer_masks, -ARRAY_SIZE (layer_masks))) +if (!access_request) +return 0 ; + +if (landlock_unmask_layers (rule, &layer_masks))return 0 ; audit_net.family = address->sa_family;
@@ -214,7 +216,6 @@ static int current_check_access_socket(s .audit.u.net = &audit_net, .access = access_request, .layer_masks = &layer_masks, - .layer_masks_size = ARRAY_SIZE(layer_masks), });return -EACCES ; }
security/landlock/ruleset.c +36 -57
149 lines not on this page · raw message
security/landlock/ruleset.h +2 -4
@@ -302,14 +302,12 @@ landlock_get_scope_mask(const struct lan }bool landlock_unmask_layers (const struct landlock_rule *const rule, -const access_mask_t access_request, -layer_mask_t (*const layer_masks)[], -const size_t masks_array_size); +struct layer_access_masks *masks);access_mask_t landlock_init_layer_masks (const struct landlock_ruleset *const domain,const access_mask_t access_request, -layer_mask_t (*const layer_masks)[], +struct layer_access_masks *masks,const enum landlock_key_type key_type);#endif /* _SECURITY_LANDLOCK_RULESET_H */
Greg Kroah-Hartman
maintainerPATCH 1231/1250 landlock: Use mem_is_zero() in is_layer_masks_allowed()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Günther Noack <[email protected]>
[ Upstream commit 1c4fe87364782d1b058cc9d15fc8acef44bce033 ]
This is equivalent, but expresses the intent a bit clearer.
Stable-dep-of: 2c6dc7925382 ("landlock: Fix use-after-free of the source's parent directory")
--- security/landlock/fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
security/landlock/fs.c +1 -1
@@ -559,7 +559,7 @@ static void test_no_more_access(struct kstatic bool is_layer_masks_allowed (const struct layer_access_masks *masks) { -return !memchr_inv (&masks->access,0 ,sizeof (masks->access)); +return mem_is_zero (&masks->access,sizeof (masks->access)); }/*
Greg Kroah-Hartman
maintainerPATCH 1232/1250 landlock: Fix use-after-free of the sources parent directory
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Norbert Szetei <[email protected]>
[ Upstream commit 2c6dc792538260a8087ac5b22c31b3b8e47c85d6 ]
current_check_refer_path() reads old_dentry->d_parent without holding a reference nor a lock on it, and then dereferences it in collect_domain_accesses() and in the audit record.
A reference on a child does not pin its parent: __d_move() reassigns dentry->d_parent and drops the reference the child held on its former parent. hook_path_rename() is not affected because the rename path calls lock_rename() before the hook, so the source cannot be reparented under it. hook_path_link() has no such protection: filename_linkat() holds a reference on the source dentry but neither locks nor references its parent, so a concurrent rename(2) can reparent the source while security_path_link() runs, and the former parent can then be removed and freed while the hook walks it.
A process can trigger this after entering a Landlock domain that handles at least one filesystem access right. The process can then race a linkat(2) loop against rename(2) and rmdir(2):
BUG: KASAN: slab-use-after-free in collect_domain_accesses+0x278/0x290 Read of size 4 at addr ffff888160bd53f4 by task llrepro2/549 collect_domain_accesses+0x278/0x290 current_check_refer_path+0x952/0x1120 security_path_link+0x1be/0x320 filename_linkat+0x342/0x6d0 __x64_sys_linkat+0xfa/0x150 Freed by task 562: kmem_cache_free+0x139/0x4c0 i_callback+0x4b/0x80 rcu_core+0x7dc/0x10a0
Take a reference on the dentry selected as the source parent, using dget() for the common-mount-root case and dget_parent() otherwise. Release it after the hierarchy walk and synchronous audit logging.
--- security/landlock/fs.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
security/landlock/fs.c +12 -6
@@ -1196,11 +1196,12 @@ static int current_check_refer_path(stru/* * old_dentry may be the root of the common mount point and * !IS_ROOT(old_dentry) at the same time (e.g. with open_tree() and -* OPEN_TREE_CLONE). We do not need to call dget(old_parent) because -* we keep a reference to old_dentry. +* OPEN_TREE_CLONE). Pin the dentry used as old_parent in either case. +* Otherwise, dget_parent() safely fetches and pins the current parent +* against a concurrent rename(2). */ - old_parent = (old_dentry == mnt_dir.dentry) ? old_dentry : - old_dentry->d_parent; + old_parent = (old_dentry == mnt_dir.dentry) ?dget (old_dentry) : +dget_parent (old_dentry);/* new_dir->dentry is equal to new_dentry->d_parent */ allow_parent1 = collect_domain_accesses(subject->domain, mnt_dir.dentry,
@@ -1209,8 +1210,10 @@ static int current_check_refer_path(stru allow_parent2 =collect_domain_accesses (subject->domain, mnt_dir.dentry, new_dir->dentry, &layer_masks_parent2); -if (allow_parent1 && allow_parent2) +if (allow_parent1 && allow_parent2) { +dput (old_parent);return 0 ; + }/* * To be able to compare source and destination domain access rights,
@@ -1222,8 +1225,10 @@ static int current_check_refer_path(stru subject->domain, &mnt_dir, access_request_parent1, &layer_masks_parent1, &request1, old_dentry, access_request_parent2, &layer_masks_parent2, &request2, - exchange ? new_dentry : NULL)) + exchange ? new_dentry : NULL)) { +dput (old_parent);return 0 ; + }if (request1.access) { request1.audit.u.path.dentry = old_parent;
@@ -1233,6 +1238,7 @@ static int current_check_refer_path(stru request2.audit.u.path.dentry = new_dir->dentry;landlock_log_denial (subject, &request2); } +dput (old_parent);/* * This prioritizes EACCES over EXDEV for all actions, including
Greg Kroah-Hartman
maintainerPATCH 1233/1250 mptcp: pm: reset retrans_time when ADD_ADDR entry is reused
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Matthieu Baerts (NGI0)" <[email protected]>
[ Upstream commit f968190c0b42ea2004dc1426359a53ec365a7a37 ]
When an ADD_ADDR entry is reused, the timer is re-armed, because the goal is to re-announce an ADD_ADDR, and eventually retransmit it if needed.
In this case, the retransmission counter should be reset as well, so the re-announced address gets its retransmissions back instead of relying on what was left before, and possibly not being able to retransmit it.
--- net/mptcp/pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/mptcp/pm.c +1 -1
@@ -461,10 +461,10 @@ bool mptcp_pm_announced_alloc(struct mpt add_entry->addr = *addr; add_entry->sock = msk; - add_entry->retrans_times =0 ;timer_setup (&add_entry->add_timer, mptcp_pm_add_timer,0 ); reset_timer: + add_entry->retrans_times =0 ; add_entry->timer_done = false; timeout =mptcp_adjust_add_addr_timeout (msk);if (timeout)
Greg Kroah-Hartman
maintainerPATCH 1234/1250 fwctl/bnxt_en: Move common definitions to include/linux/bnxt/
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pavan Chebbi <[email protected]>
[ Upstream commit 7be18a1fa00eab5283b35c13e26c6b76fcaab9ce ]
We have common definitions that are now going to be used by more than one component outside of bnxt (bnxt_re and fwctl)
Move bnxt_ulp.h to include/linux/bnxt/ as ulp.h.
Stable-dep-of: 961e2a17c5e3 ("bnxt_en: Handle buffer allocation failure in bnxt_rx_ring_reset()")
--- drivers/infiniband/hw/bnxt_re/debugfs.c | 2 +- drivers/infiniband/hw/bnxt_re/main.c | 2 +- drivers/infiniband/hw/bnxt_re/qplib_fp.c | 2 +- drivers/infiniband/hw/bnxt_re/qplib_res.h | 2 +- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 2 +- drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c | 2 +- drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 2 +- drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c | 2 +- drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c | 2 +- .../broadcom/bnxt/bnxt_ulp.h => include/linux/bnxt/ulp.h | 0 drivers/infiniband/hw/bnxt_re/debugfs.c | 2 drivers/infiniband/hw/bnxt_re/main.c | 2 drivers/infiniband/hw/bnxt_re/qplib_fp.c | 2 drivers/infiniband/hw/bnxt_re/qplib_res.h | 2 drivers/net/ethernet/broadcom/bnxt/bnxt.c | 2 drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c | 2 drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 2 drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c | 2 drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c | 2 drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h | 129 ---------------------- include/linux/bnxt/ulp.h | 129 ++++++++++++++++++++++ 11 files changed, 138 insertions(+), 138 deletions(-) rename drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h => include/linux/bnxt/ulp.h (100%)
drivers/infiniband/hw/bnxt_re/debugfs.c +1 -1
@@ -10,8 +10,8 @@#include <linux/pci.h> #include <linux/seq_file.h> #include <rdma/ib_addr.h> +#include <linux/bnxt/ulp.h> -#include "bnxt_ulp.h" #include "roce_hsi.h" #include "qplib_res.h" #include "qplib_sp.h"
drivers/infiniband/hw/bnxt_re/main.c +1 -1
@@ -55,8 +55,8 @@#include <rdma/ib_umem.h> #include <rdma/ib_addr.h> #include <linux/hashtable.h> +#include <linux/bnxt/ulp.h> -#include "bnxt_ulp.h" #include "roce_hsi.h" #include "qplib_res.h" #include "qplib_sp.h"
drivers/infiniband/hw/bnxt_re/qplib_fp.c +1 -1
@@ -46,6 +46,7 @@#include <linux/delay.h> #include <linux/prefetch.h> #include <linux/if_ether.h> +#include <linux/bnxt/ulp.h> #include <rdma/ib_mad.h> #include "roce_hsi.h"
@@ -55,7 +56,6 @@#include "qplib_sp.h" #include "qplib_fp.h" #include <rdma/ib_addr.h> -#include "bnxt_ulp.h" #include "bnxt_re.h" #include "ib_verbs.h"
drivers/infiniband/hw/bnxt_re/qplib_res.h +1 -1
@@ -39,7 +39,7 @@#ifndef __BNXT_QPLIB_RES_H__#define __BNXT_QPLIB_RES_H__ -#include "bnxt_ulp.h" +#include <linux/bnxt/ulp.h> extern const struct bnxt_qplib_gid bnxt_qplib_gid_zero;
drivers/net/ethernet/broadcom/bnxt/bnxt.c +1 -1
@@ -59,10 +59,10 @@#include <net/netdev_rx_queue.h> #include <linux/pci-tph.h> #include <linux/bnxt/hsi.h> +#include <linux/bnxt/ulp.h> #include "bnxt.h" #include "bnxt_hwrm.h" -#include "bnxt_ulp.h" #include "bnxt_sriov.h" #include "bnxt_ethtool.h" #include "bnxt_dcb.h"
drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c +1 -1
@@ -13,12 +13,12 @@#include <net/devlink.h> #include <net/netdev_lock.h> #include <linux/bnxt/hsi.h> +#include <linux/bnxt/ulp.h> #include "bnxt.h" #include "bnxt_hwrm.h" #include "bnxt_vfr.h" #include "bnxt_devlink.h" #include "bnxt_ethtool.h" -#include "bnxt_ulp.h" #include "bnxt_ptp.h" #include "bnxt_coredump.h" #include "bnxt_nvm_defs.h"
drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +1 -1
@@ -27,9 +27,9 @@#include <net/netdev_queues.h> #include <net/netlink.h> #include <linux/bnxt/hsi.h> +#include <linux/bnxt/ulp.h> #include "bnxt.h" #include "bnxt_hwrm.h" -#include "bnxt_ulp.h" #include "bnxt_xdp.h" #include "bnxt_ptp.h" #include "bnxt_ethtool.h"
drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c +1 -1
@@ -17,9 +17,9 @@#include <linux/etherdevice.h> #include <net/dcbnl.h> #include <linux/bnxt/hsi.h> +#include <linux/bnxt/ulp.h> #include "bnxt.h" #include "bnxt_hwrm.h" -#include "bnxt_ulp.h" #include "bnxt_sriov.h" #include "bnxt_vfr.h" #include "bnxt_ethtool.h"
drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c +1 -1
@@ -22,10 +22,10 @@#include <linux/auxiliary_bus.h> #include <net/netdev_lock.h> #include <linux/bnxt/hsi.h> +#include <linux/bnxt/ulp.h> #include "bnxt.h" #include "bnxt_hwrm.h" -#include "bnxt_ulp.h" static DEFINE_IDA (bnxt_aux_dev_ids);
drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h deleted +0 -129
129 lines not on this page · raw message
include/linux/bnxt/ulp.h new file +129 -0
129 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 1235/1250 Reapply "bnxt_en: bring back rtnl_lock() in the bnxt_open() path"
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jakub Kicinski <[email protected]>
[ Upstream commit b6197b386677ae5268d4702e23849d9ad53051ad ]
This reverts commit 850d9248d2eac662f869c766a598c877690c74e5. This reapplies commit 325eb217e41f ("bnxt_en: bring back rtnl_lock() in the bnxt_open() path").
Breno reports a lockdep warning in bnxt. During FW reset the driver may end up calling netif_set_real_num_tx_queues() (if queue count changes), so calls to bnxt_open() still require rtnl_lock.
net/sched/sch_generic.c:1416 suspicious rcu_dereference_protected() usage!
dev_qdisc_change_real_num_tx+0x54/0xe0 netif_set_real_num_tx_queues+0x4ed/0xa80 __bnxt_open_nic+0x9cb/0x3490 bnxt_open+0x1cb/0x370 bnxt_fw_reset_task+0x80d/0x1e80 process_scheduled_works+0x9c1/0x13b0
The reverted commit was just an optimization / experiment so let's go back to taking the lock.
Stable adaptation for dependency of 961e2a17c5e3559b3f8654d2daabdd25a42e770a:
Keep this branch's two-argument bnxt_ulp_start() calls, including error notifications, and release RTNL before invoking them.
Reuse and rename the existing service-task lock/unlock helpers to add RTNL coverage without adding functions. Inline their original netdev-only operations in bnxt_fw_exception() and bnxt_fw_reset() so those paths keep their existing locking and BNXT_STATE_IN_SP_TASK ordering. The RX reset path then provides the bnxt_rtnl_unlock_sp() required by the target's buffer-allocation failure handling.
Stable-dep-of: 961e2a17c5e3 ("bnxt_en: Handle buffer allocation failure in bnxt_rx_ring_reset()")
--- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 44 +++++++++++++++++++----------- 1 file changed, 28 insertions(+), 16 deletions(-)
drivers/net/ethernet/broadcom/bnxt/bnxt.c +28 -16
@@ -14283,31 +14283,32 @@ bnxt_restart_timer:mod_timer (&bp->timer, jiffies + bp->current_interval); } -static void bnxt_lock_sp (struct bnxt *bp) +static void bnxt_rtnl_lock_sp (struct bnxt *bp) {/* We are called from bnxt_sp_task which has BNXT_STATE_IN_SP_TASK * set. If the device is being closed, bnxt_close() may be holding -* netdev instance lock and waiting for BNXT_STATE_IN_SP_TASK to clear. -* So we must clear BNXT_STATE_IN_SP_TASK before holding netdev -* instance lock. +* RTNL and the netdev instance lock while waiting for +* BNXT_STATE_IN_SP_TASK to clear. Clear it before taking either lock. */ clear_bit (BNXT_STATE_IN_SP_TASK , &bp->state); +rtnl_lock ();netdev_lock (bp->dev); } -static void bnxt_unlock_sp (struct bnxt *bp) +static void bnxt_rtnl_unlock_sp (struct bnxt *bp) {set_bit (BNXT_STATE_IN_SP_TASK , &bp->state);netdev_unlock (bp->dev); +rtnl_unlock (); }/* Only called from bnxt_sp_task() */ static void bnxt_reset (struct bnxt *bp,bool silent) { -bnxt_lock_sp (bp); +bnxt_rtnl_lock_sp (bp);if (test_bit (BNXT_STATE_OPEN , &bp->state))bnxt_reset_task (bp, silent); -bnxt_unlock_sp (bp); +bnxt_rtnl_unlock_sp (bp); }/* Only called from bnxt_sp_task() */
@@ -14315,9 +14316,9 @@ static void bnxt_rx_ring_reset(struct bn {int i; -bnxt_lock_sp (bp); +bnxt_rtnl_lock_sp (bp);if (!test_bit (BNXT_STATE_OPEN , &bp->state)) { -bnxt_unlock_sp (bp); +bnxt_rtnl_unlock_sp (bp);return ; }/* Disable and flush TPA before resetting the RX ring */
@@ -14356,7 +14357,7 @@ static void bnxt_rx_ring_reset(struct bn }if (bp->flags &BNXT_FLAG_TPA )bnxt_set_tpa (bp, true); -bnxt_unlock_sp (bp); +bnxt_rtnl_unlock_sp (bp); }static void bnxt_fw_fatal_close (struct bnxt *bp)
@@ -14455,9 +14456,11 @@ void bnxt_fw_exception(struct bnxt *bp)netdev_warn (bp->dev,"Detected firmware fatal condition, initiating reset\n" );set_bit (BNXT_STATE_FW_FATAL_COND , &bp->state);bnxt_ulp_stop (bp); -bnxt_lock_sp (bp); +clear_bit (BNXT_STATE_IN_SP_TASK , &bp->state); +netdev_lock (bp->dev);bnxt_force_fw_reset (bp); -bnxt_unlock_sp (bp); +set_bit (BNXT_STATE_IN_SP_TASK , &bp->state); +netdev_unlock (bp->dev); }/* Returns the number of registered VFs, or 1 if VF configuration is pending, or
@@ -14487,7 +14490,8 @@ static int bnxt_get_registered_vfs(strucvoid bnxt_fw_reset (struct bnxt *bp) {bnxt_ulp_stop (bp); -bnxt_lock_sp (bp); +clear_bit (BNXT_STATE_IN_SP_TASK , &bp->state); +netdev_lock (bp->dev);if (test_bit (BNXT_STATE_OPEN , &bp->state) && !test_bit (BNXT_STATE_IN_FW_RESET , &bp->state)) {struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
@@ -14533,7 +14537,8 @@ void bnxt_fw_reset(struct bnxt *bp)bnxt_queue_fw_reset_work (bp, tmo); } fw_reset_exit: -bnxt_unlock_sp (bp); +set_bit (BNXT_STATE_IN_SP_TASK , &bp->state); +netdev_unlock (bp->dev); }static void bnxt_chk_missed_irq (struct bnxt *bp)
@@ -15269,15 +15274,17 @@ static void bnxt_fw_reset_task(struct wo bp->fw_reset_state =BNXT_FW_RESET_STATE_OPENING ; fallthrough;case BNXT_FW_RESET_STATE_OPENING : -while (!netdev_trylock (bp->dev)) { +while (!rtnl_trylock ()) {bnxt_queue_fw_reset_work (bp,HZ /10 );return ; } +netdev_lock (bp->dev); rc =bnxt_open (bp->dev);if (rc) {netdev_err (bp->dev,"bnxt_open() failed during FW reset\n" );bnxt_fw_reset_abort (bp, rc);netdev_unlock (bp->dev); +rtnl_unlock (); goto ulp_start; }
@@ -15297,6 +15304,7 @@ static void bnxt_fw_reset_task(struct wobnxt_dl_health_fw_status_update (bp, true); }netdev_unlock (bp->dev); +rtnl_unlock ();bnxt_ulp_start (bp,0 );bnxt_reenable_sriov (bp);netdev_lock (bp->dev);
@@ -16292,7 +16300,7 @@ err_reset: rc);napi_enable_locked (&bnapi->napi);bnxt_db_nq_arm (bp, &cpr->cp_db, cpr->cp_raw_cons); -bnxt_reset_task (bp, true); +netif_close (dev);return rc; }
@@ -17120,6 +17128,7 @@ static int bnxt_resume(struct device *destruct bnxt *bp =netdev_priv (dev);int rc =0 ; +rtnl_lock ();netdev_lock (dev); rc =pci_enable_device (bp->pdev);if (rc) {
@@ -17164,6 +17173,7 @@ static int bnxt_resume(struct device *de resume_exit:netdev_unlock (bp->dev); +rtnl_unlock ();bnxt_ulp_start (bp, rc);if (!rc)bnxt_reenable_sriov (bp);
@@ -17329,6 +17339,7 @@ static void bnxt_io_resume(struct pci_deint err;netdev_info (bp->dev,"PCI Slot Resume\n" ); +rtnl_lock ();netdev_lock (netdev); err =bnxt_hwrm_func_qcaps (bp);
@@ -17346,6 +17357,7 @@ static void bnxt_io_resume(struct pci_denetif_device_attach (netdev);netdev_unlock (netdev); +rtnl_unlock ();bnxt_ulp_start (bp, err);if (!err)bnxt_reenable_sriov (bp);
Greg Kroah-Hartman
maintainerPATCH 1236/1250 bnxt_en: Handle buffer allocation failure in bnxt_rx_ring_reset()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joe Damato <[email protected]>
[ Upstream commit 961e2a17c5e3559b3f8654d2daabdd25a42e770a ]
bnxt_rx_ring_reset() frees the ring buffers and then reallocates them, ignoring the result.
bnxt_alloc_one_rx_ring() can fail in bnxt_alloc_one_tpa_info_data(), which returns -ENOMEM on the first failed allocation and leaves the remaining rxr->rx_tpa[] entries zeroed.
The error isn't propagated up, so the loop in bnxt_rx_ring_reset continues and at the end the code re-enables TPA with partially unallocated rx_tpa array.
This means that when the agg_id from hardware is mapped to a SW index in rxr->rx_tpa[], an uninitialized slot can be chosen which would hand a zero DMA address to the device.
Fix this by falling back to a global reset, which is what the existing code already does when other functions fail, but unlike the other failure cases this particular failure has to return because TPA can't be re-enabled since the allocation failed.
--- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/net/ethernet/broadcom/bnxt/bnxt.c +8 -1
@@ -14348,7 +14348,14 @@ static void bnxt_rx_ring_reset(struct bn rxr->rx_sw_agg_prod =0 ; rxr->rx_next_cons =0 ; rxr->bnapi->in_reset = false; -bnxt_alloc_one_rx_ring (bp, i); + rc =bnxt_alloc_one_rx_ring (bp, i); +if (rc) { +netdev_warn (bp->dev,"RX ring reset failed to allocate buffers, rc = %d, falling back to global reset\n" , + rc); +bnxt_reset_task (bp, true); +bnxt_rtnl_unlock_sp (bp); +return ; + } cpr = &rxr->bnapi->cp_ring; cpr->sw_stats->rx.rx_resets++;if (bp->flags &BNXT_FLAG_AGG_RINGS )
Greg Kroah-Hartman
maintainerPATCH 1237/1250 tcp: rename icsk_timeout() to tcp_timeout_expires()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 3a6e8fd0bf4042c572dc52e634878b9aca02970d ]
In preparation of sk->tcp_timeout_timer introduction, rename icsk_timeout() helper and change its argument to plain 'const struct sock *sk'.
Stable-dep-of: e2ab913f68c7 ("mptcp: do not reschedule the RTX timer for fallback sockets")
--- include/net/inet_connection_sock.h | 5 ++--- net/ipv4/inet_diag.c | 4 ++-- net/ipv4/tcp_ipv4.c | 4 ++-- net/ipv4/tcp_timer.c | 6 +++--- net/ipv6/tcp_ipv6.c | 4 ++-- net/mptcp/protocol.c | 2 +- 6 files changed, 12 insertions(+), 13 deletions(-)
include/net/inet_connection_sock.h +2 -3
@@ -186,10 +186,9 @@ static inline void inet_csk_delack_init(memset (&inet_csk (sk)->icsk_ack,0 ,sizeof (inet_csk (sk)->icsk_ack)); } -static inline unsigned long -icsk_timeout (const struct inet_connection_sock *icsk) +static inline unsigned long tcp_timeout_expires (const struct sock *sk) { -return READ_ONCE (icsk->icsk_retransmit_timer.expires); +return READ_ONCE (inet_csk (sk)->icsk_retransmit_timer.expires); } static inline unsigned long
net/ipv4/inet_diag.c +2 -2
@@ -287,12 +287,12 @@ int inet_sk_diag_fill(struct sock *sk, s r->idiag_timer =1 ; r->idiag_retrans =READ_ONCE (icsk->icsk_retransmits); r->idiag_expires = -jiffies_delta_to_msecs (icsk_timeout (icsk) - jiffies); +jiffies_delta_to_msecs (tcp_timeout_expires (sk) - jiffies); }else if (icsk_pending ==ICSK_TIME_PROBE0 ) { r->idiag_timer =4 ; r->idiag_retrans =READ_ONCE (icsk->icsk_probes_out); r->idiag_expires = -jiffies_delta_to_msecs (icsk_timeout (icsk) - jiffies); +jiffies_delta_to_msecs (tcp_timeout_expires (sk) - jiffies); }else if (timer_pending (&sk->sk_timer)) { r->idiag_timer =2 ; r->idiag_retrans =READ_ONCE (icsk->icsk_probes_out);
net/ipv4/tcp_ipv4.c +2 -2
@@ -2928,10 +2928,10 @@ static void get_tcp4_sock(struct sock *s icsk_pending == ICSK_TIME_REO_TIMEOUT || icsk_pending == ICSK_TIME_LOSS_PROBE) { timer_active =1 ; - timer_expires =icsk_timeout (icsk); + timer_expires =tcp_timeout_expires (sk); } else if (icsk_pending == ICSK_TIME_PROBE0) { timer_active =4 ; - timer_expires =icsk_timeout (icsk); + timer_expires =tcp_timeout_expires (sk); } else if (timer_pending(&sk->sk_timer)) { timer_active =2 ; timer_expires = sk->sk_timer.expires;
net/ipv4/tcp_timer.c +3 -3
@@ -513,7 +513,7 @@ static bool tcp_rtx_probe0_timed_out(con* and tp->rcv_tstamp might very well have been written recently. * rcv_delta can thus be negative. */ - rcv_delta =icsk_timeout (icsk) - tp->rcv_tstamp; + rcv_delta =tcp_timeout_expires (sk) - tp->rcv_tstamp;if (rcv_delta <= timeout)return false;
@@ -700,9 +700,9 @@ void tcp_write_timer_handler(struct sock !icsk->icsk_pending)return ; -if (time_after (icsk_timeout (icsk), jiffies)) { +if (time_after (tcp_timeout_expires (sk), jiffies)) {sk_reset_timer (sk, &icsk->icsk_retransmit_timer, -icsk_timeout (icsk)); +tcp_timeout_expires (sk));return ; }tcp_mstamp_refresh (tcp_sk (sk));
net/ipv6/tcp_ipv6.c +2 -2
@@ -2200,10 +2200,10 @@ static void get_tcp6_sock(struct seq_fil icsk_pending == ICSK_TIME_REO_TIMEOUT || icsk_pending == ICSK_TIME_LOSS_PROBE) { timer_active =1 ; - timer_expires =icsk_timeout (icsk); + timer_expires =tcp_timeout_expires (sp); } else if (icsk_pending == ICSK_TIME_PROBE0) { timer_active =4 ; - timer_expires =icsk_timeout (icsk); + timer_expires =tcp_timeout_expires (sp); } else if (timer_pending(&sp->sk_timer)) { timer_active =2 ; timer_expires = sp->sk_timer.expires;
net/mptcp/protocol.c +1 -1
@@ -533,7 +533,7 @@ static long mptcp_timeout_from_subflow(cconst struct sock *ssk =mptcp_subflow_tcp_sock (subflow);return inet_csk (ssk)->icsk_pending && !subflow->stale_count ? -icsk_timeout (inet_csk (ssk)) - jiffies :0 ; +tcp_timeout_expires (ssk) - jiffies :0 ; }static void mptcp_set_timeout (struct sock *sk)
Greg Kroah-Hartman
maintainerPATCH 1238/1250 tcp: introduce icsk->icsk_keepalive_timer
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 08dfe370239e53494453cee1e2ded2cdaa1efd12 ]
sk->sk_timer has been used for TCP keepalives.
Keepalive timers are not in fast path, we want to use sk->sk_timer storage for retransmit timers, for better cache locality.
Create icsk->icsk_keepalive_timer and change keepalive code to no longer use sk->sk_timer.
Added space is reclaimed in the following patch.
This includes changes to MPTCP, which was also using sk_timer.
Alias icsk->mptcp_tout_timer and icsk->icsk_keepalive_timer for inet_sk_diag_fill() sake.
Stable-dep-of: e2ab913f68c7 ("mptcp: do not reschedule the RTX timer for fallback sockets")
--- Documentation/networking/net_cachelines/inet_connection_sock.rst | 1 include/net/inet_connection_sock.h | 11 ++++++++-- net/ipv4/inet_connection_sock.c | 6 ++--- net/ipv4/inet_diag.c | 4 +-- net/ipv4/tcp_ipv4.c | 4 +-- net/ipv4/tcp_timer.c | 9 ++++---- net/ipv6/tcp_ipv6.c | 4 +-- net/mptcp/protocol.c | 10 +++++---- net/mptcp/protocol.h | 2 - tools/testing/selftests/bpf/progs/bpf_iter_tcp4.c | 4 +-- tools/testing/selftests/bpf/progs/bpf_iter_tcp6.c | 4 +-- 11 files changed, 35 insertions(+), 24 deletions(-)
Documentation/networking/net_cachelines/inet_connection_sock.rst +1 -0
@@ -14,6 +14,7 @@ struct inet_bind_bucket icsk struct inet_bind2_bucket icsk_bind2_hash read_mostly tcp_set_state,inet_put_port struct timer_list icsk_retransmit_timer read_write inet_csk_reset_xmit_timer,tcp_connect struct timer_list icsk_delack_timer read_mostly inet_csk_reset_xmit_timer,tcp_connect +struct timer_list icsk_keepalive_timer u32 icsk_rto read_write tcp_cwnd_validate,tcp_schedule_loss_probe,tcp_connect_init,tcp_connect,tcp_write_xmit,tcp_push_one u32 icsk_rto_min u32 icsk_rto_max read_mostly tcp_reset_xmit_timer
include/net/inet_connection_sock.h +9 -2
@@ -59,6 +59,9 @@ struct inet_connection_sock_af_ops {* @icsk_bind_hash: Bind node * @icsk_bind2_hash: Bind node in the bhash2 table * @icsk_retransmit_timer: Resend (no ack) +* @icsk_delack_timer: Delayed ACK timer +* @icsk_keepalive_timer: Keepalive timer +* @mptcp_tout_timer: mptcp timer * @icsk_rto: Retransmit timeout * @icsk_pmtu_cookie Last pmtu seen by socket * @icsk_ca_ops Pluggable congestion control hook
@@ -83,8 +86,12 @@ struct inet_connection_sock {struct request_sock_queue icsk_accept_queue;struct inet_bind_bucket *icsk_bind_hash;struct inet_bind2_bucket *icsk_bind2_hash; -struct timer_list icsk_retransmit_timer; -struct timer_list icsk_delack_timer; +struct timer_list icsk_retransmit_timer; +struct timer_list icsk_delack_timer; +union { +struct timer_list icsk_keepalive_timer; +struct timer_list mptcp_tout_timer; + };__u32 icsk_rto;__u32 icsk_rto_min;u32 icsk_rto_max;
net/ipv4/inet_connection_sock.c +3 -3
@@ -750,7 +750,7 @@ void inet_csk_init_xmit_timers(struct sotimer_setup (&icsk->icsk_retransmit_timer, retransmit_handler,0 );timer_setup (&icsk->icsk_delack_timer, delack_handler,0 ); -timer_setup (&sk->sk_timer, keepalive_handler,0 ); +timer_setup (&icsk->icsk_keepalive_timer, keepalive_handler,0 ); icsk->icsk_pending = icsk->icsk_ack.pending =0 ; }
@@ -763,7 +763,7 @@ void inet_csk_clear_xmit_timers(struct ssk_stop_timer (sk, &icsk->icsk_retransmit_timer);sk_stop_timer (sk, &icsk->icsk_delack_timer); -sk_stop_timer (sk, &sk->sk_timer); +sk_stop_timer (sk, &icsk->icsk_keepalive_timer); }void inet_csk_clear_xmit_timers_sync (struct sock *sk)
@@ -778,7 +778,7 @@ void inet_csk_clear_xmit_timers_sync(strsk_stop_timer_sync (sk, &icsk->icsk_retransmit_timer);sk_stop_timer_sync (sk, &icsk->icsk_delack_timer); -sk_stop_timer_sync (sk, &sk->sk_timer); +sk_stop_timer_sync (sk, &icsk->icsk_keepalive_timer); } struct dst_entry *inet_csk_route_req(const struct sock *sk,
net/ipv4/inet_diag.c +2 -2
@@ -293,11 +293,11 @@ int inet_sk_diag_fill(struct sock *sk, s r->idiag_retrans =READ_ONCE (icsk->icsk_probes_out); r->idiag_expires =jiffies_delta_to_msecs (tcp_timeout_expires (sk) - jiffies); - }else if (timer_pending (&sk->sk_timer)) { + }else if (timer_pending (&icsk->icsk_keepalive_timer)) { r->idiag_timer =2 ; r->idiag_retrans =READ_ONCE (icsk->icsk_probes_out); r->idiag_expires = -jiffies_delta_to_msecs (sk->sk_timer.expires - jiffies); +jiffies_delta_to_msecs (icsk->icsk_keepalive_timer.expires - jiffies); }if ((ext & (1 << (INET_DIAG_INFO -1 ))) && handler->idiag_info_size) {
net/ipv4/tcp_ipv4.c +2 -2
@@ -2932,9 +2932,9 @@ static void get_tcp4_sock(struct sock *s }else if (icsk_pending ==ICSK_TIME_PROBE0 ) { timer_active =4 ; timer_expires =tcp_timeout_expires (sk); - }else if (timer_pending (&sk->sk_timer)) { + }else if (timer_pending (&icsk->icsk_keepalive_timer)) { timer_active =2 ; - timer_expires = sk->sk_timer.expires; + timer_expires = icsk->icsk_keepalive_timer.expires; }else { timer_active =0 ; timer_expires = jiffies;
net/ipv4/tcp_timer.c +5 -4
@@ -759,12 +759,12 @@ EXPORT_IPV6_MOD(tcp_syn_ack_timeout);void tcp_reset_keepalive_timer (struct sock *sk,unsigned long len) { -sk_reset_timer (sk, &sk->sk_timer, jiffies + len); +sk_reset_timer (sk, &inet_csk (sk)->icsk_keepalive_timer, jiffies + len); }static void tcp_delete_keepalive_timer (struct sock *sk) { -sk_stop_timer (sk, &sk->sk_timer); +sk_stop_timer (sk, &inet_csk (sk)->icsk_keepalive_timer); }void tcp_set_keepalive (struct sock *sk,int val)
@@ -781,8 +781,9 @@ EXPORT_IPV6_MOD_GPL(tcp_set_keepalive);static void tcp_keepalive_timer (struct timer_list *t) { -struct sock *sk =timer_container_of (sk, t, sk_timer); -struct inet_connection_sock *icsk =inet_csk (sk); +struct inet_connection_sock *icsk = +timer_container_of (icsk, t, icsk_keepalive_timer); +struct sock *sk = &icsk->icsk_inet.sk;struct tcp_sock *tp =tcp_sk (sk);u32 elapsed;
net/ipv6/tcp_ipv6.c +2 -2
@@ -2204,9 +2204,9 @@ static void get_tcp6_sock(struct seq_fil }else if (icsk_pending ==ICSK_TIME_PROBE0 ) { timer_active =4 ; timer_expires =tcp_timeout_expires (sp); - }else if (timer_pending (&sp->sk_timer)) { + }else if (timer_pending (&icsk->icsk_keepalive_timer)) { timer_active =2 ; - timer_expires = sp->sk_timer.expires; + timer_expires = icsk->icsk_keepalive_timer.expires; }else { timer_active =0 ; timer_expires = jiffies;
net/mptcp/protocol.c +6 -4
@@ -2348,7 +2348,9 @@ static void mptcp_retransmit_timer(strucstatic void mptcp_tout_timer (struct timer_list *t) { -struct sock *sk =timer_container_of (sk, t, sk_timer); +struct inet_connection_sock *icsk = +timer_container_of (icsk, t, mptcp_tout_timer); +struct sock *sk = &icsk->icsk_inet.sk;mptcp_schedule_work (sk);sock_put (sk);
@@ -2804,7 +2806,7 @@ void mptcp_reset_tout_timer(struct mptcp*/ timeout =inet_csk (sk)->icsk_mtup.probe_timestamp ? close_timeout : fail_tout; -sk_reset_timer (sk, &sk->sk_timer, timeout); +sk_reset_timer (sk, &inet_csk (sk)->mptcp_tout_timer, timeout); }static void mptcp_mp_fail_no_response (struct mptcp_sock *msk)
@@ -2935,7 +2937,7 @@ static void __mptcp_init_sock(struct soc/* re-use the csk retrans timer for MPTCP-level retrans */ timer_setup (&msk->sk.icsk_retransmit_timer, mptcp_retransmit_timer,0 ); -timer_setup (&sk->sk_timer, mptcp_tout_timer,0 ); +timer_setup (&msk->sk.mptcp_tout_timer, mptcp_tout_timer,0 ); }static void mptcp_ca_reset (struct sock *sk)
@@ -3137,7 +3139,7 @@ static void __mptcp_destroy_sock(structmight_sleep ();mptcp_stop_rtx_timer (sk); -sk_stop_timer (sk, &sk->sk_timer); +sk_stop_timer (sk, &inet_csk (sk)->mptcp_tout_timer); msk->pm.status =0 ;mptcp_release_sched (msk);
net/mptcp/protocol.h +1 -1
@@ -880,7 +880,7 @@ static inline void mptcp_stop_tout_timerif (!inet_csk (sk)->icsk_mtup.probe_timestamp)return ; -sk_stop_timer (sk, &sk->sk_timer); +sk_stop_timer (sk, &inet_csk (sk)->mptcp_tout_timer);inet_csk (sk)->icsk_mtup.probe_timestamp =0 ; }
tools/testing/selftests/bpf/progs/bpf_iter_tcp4.c +2 -2
@@ -103,9 +103,9 @@ static int dump_tcp_sock(struct seq_file }else if (icsk->icsk_pending ==ICSK_TIME_PROBE0 ) { timer_active =4 ; timer_expires = icsk->icsk_retransmit_timer.expires; - }else if (timer_pending (&sp->sk_timer)) { + }else if (timer_pending (&icsk->icsk_keepalive_timer)) { timer_active =2 ; - timer_expires = sp->sk_timer.expires; + timer_expires = icsk->icsk_keepalive_timer.expires; }else { timer_active =0 ; timer_expires =bpf_jiffies64 ();
tools/testing/selftests/bpf/progs/bpf_iter_tcp6.c +2 -2
@@ -103,9 +103,9 @@ static int dump_tcp6_sock(struct seq_fil }else if (icsk->icsk_pending ==ICSK_TIME_PROBE0 ) { timer_active =4 ; timer_expires = icsk->icsk_retransmit_timer.expires; - }else if (timer_pending (&sp->sk_timer)) { + }else if (timer_pending (&icsk->icsk_keepalive_timer)) { timer_active =2 ; - timer_expires = sp->sk_timer.expires; + timer_expires = icsk->icsk_keepalive_timer.expires; }else { timer_active =0 ; timer_expires =bpf_jiffies64 ();
Greg Kroah-Hartman
maintainerPATCH 1239/1250 tcp: remove icsk->icsk_retransmit_timer
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 9a5e5334adc039fa652aa071ea95b18db0bc1f43 ]
Now sk->sk_timer is no longer used by TCP keepalive, we can use its storage for TCP and MPTCP retransmit timers for better cache locality.
Stable-dep-of: e2ab913f68c7 ("mptcp: do not reschedule the RTX timer for fallback sockets")
--- Documentation/networking/net_cachelines/inet_connection_sock.rst | 1 include/net/inet_connection_sock.h | 8 ++--- include/net/sock.h | 9 ++++-- net/ipv4/inet_connection_sock.c | 6 ++-- net/ipv4/tcp_timer.c | 8 ++--- net/mptcp/protocol.c | 15 +++------- tools/testing/selftests/bpf/progs/bpf_iter_tcp4.c | 4 +- tools/testing/selftests/bpf/progs/bpf_iter_tcp6.c | 4 +- 8 files changed, 25 insertions(+), 30 deletions(-)
Documentation/networking/net_cachelines/inet_connection_sock.rst +0 -1
@@ -12,7 +12,6 @@ struct inet_sock icsk struct request_sock_queue icsk_accept_queue struct inet_bind_bucket icsk_bind_hash read_mostly tcp_set_state struct inet_bind2_bucket icsk_bind2_hash read_mostly tcp_set_state,inet_put_port -struct timer_list icsk_retransmit_timer read_write inet_csk_reset_xmit_timer,tcp_connect struct timer_list icsk_delack_timer read_mostly inet_csk_reset_xmit_timer,tcp_connect struct timer_list icsk_keepalive_timer u32 icsk_rto read_write tcp_cwnd_validate,tcp_schedule_loss_probe,tcp_connect_init,tcp_connect,tcp_write_xmit,tcp_push_one
include/net/inet_connection_sock.h +3 -5
@@ -58,7 +58,6 @@ struct inet_connection_sock_af_ops {* @icsk_accept_queue: FIFO of established children * @icsk_bind_hash: Bind node * @icsk_bind2_hash: Bind node in the bhash2 table -* @icsk_retransmit_timer: Resend (no ack) * @icsk_delack_timer: Delayed ACK timer * @icsk_keepalive_timer: Keepalive timer * @mptcp_tout_timer: mptcp timer
@@ -86,7 +85,6 @@ struct inet_connection_sock {struct request_sock_queue icsk_accept_queue;struct inet_bind_bucket *icsk_bind_hash;struct inet_bind2_bucket *icsk_bind2_hash; -struct timer_list icsk_retransmit_timer;struct timer_list icsk_delack_timer;union {struct timer_list icsk_keepalive_timer;
@@ -195,7 +193,7 @@ static inline void inet_csk_delack_init(static inline unsigned long tcp_timeout_expires (const struct sock *sk) { -return READ_ONCE (inet_csk (sk)->icsk_retransmit_timer.expires); +return READ_ONCE (sk->tcp_retransmit_timer.expires); } static inline unsigned long
@@ -211,7 +209,7 @@ static inline void inet_csk_clear_xmit_tif (what ==ICSK_TIME_RETRANS || what ==ICSK_TIME_PROBE0 ) {smp_store_release (&icsk->icsk_pending,0 );#ifdef INET_CSK_CLEAR_TIMERS -sk_stop_timer (sk, &icsk->icsk_retransmit_timer); +sk_stop_timer (sk, &sk->tcp_retransmit_timer);#endif }else if (what ==ICSK_TIME_DACK ) {smp_store_release (&icsk->icsk_ack.pending,0 );
@@ -243,7 +241,7 @@ static inline void inet_csk_reset_xmit_tif (what ==ICSK_TIME_RETRANS || what ==ICSK_TIME_PROBE0 || what ==ICSK_TIME_LOSS_PROBE || what ==ICSK_TIME_REO_TIMEOUT ) {smp_store_release (&icsk->icsk_pending, what); -sk_reset_timer (sk, &icsk->icsk_retransmit_timer, when); +sk_reset_timer (sk, &sk->tcp_retransmit_timer, when); }else if (what ==ICSK_TIME_DACK ) {smp_store_release (&icsk->icsk_ack.pending, icsk->icsk_ack.pending |ICSK_ACK_TIMER );
include/net/sock.h +7 -2
@@ -303,6 +303,8 @@ struct sk_filter;* @sk_txrehash: enable TX hash rethink * @sk_filter: socket filtering instructions * @sk_timer: sock cleanup timer +* @tcp_retransmit_timer: tcp retransmit timer +* @mptcp_retransmit_timer: mptcp retransmit timer * @sk_stamp: time stamp of last packet received * @sk_stamp_seq: lock for accessing sk_stamp on 32 bit architectures only * @sk_tsflags: SO_TIMESTAMPING flags
@@ -480,8 +482,11 @@ struct sock {u32 sk_dst_pending_confirm;u32 sk_pacing_status;/* see enum sk_pacing */ struct page_frag sk_frag; -struct timer_list sk_timer; - +union { +struct timer_list sk_timer; +struct timer_list tcp_retransmit_timer; +struct timer_list mptcp_retransmit_timer; + };unsigned long sk_pacing_rate;/* bytes per second */ atomic_t sk_zckey;atomic_t sk_tskey;
net/ipv4/inet_connection_sock.c +3 -3
@@ -748,7 +748,7 @@ void inet_csk_init_xmit_timers(struct so {struct inet_connection_sock *icsk =inet_csk (sk); -timer_setup (&icsk->icsk_retransmit_timer, retransmit_handler,0 ); +timer_setup (&sk->tcp_retransmit_timer, retransmit_handler,0 );timer_setup (&icsk->icsk_delack_timer, delack_handler,0 );timer_setup (&icsk->icsk_keepalive_timer, keepalive_handler,0 ); icsk->icsk_pending = icsk->icsk_ack.pending =0 ;
@@ -761,7 +761,7 @@ void inet_csk_clear_xmit_timers(struct ssmp_store_release (&icsk->icsk_pending,0 );smp_store_release (&icsk->icsk_ack.pending,0 ); -sk_stop_timer (sk, &icsk->icsk_retransmit_timer); +sk_stop_timer (sk, &sk->tcp_retransmit_timer);sk_stop_timer (sk, &icsk->icsk_delack_timer);sk_stop_timer (sk, &icsk->icsk_keepalive_timer); }
@@ -776,7 +776,7 @@ void inet_csk_clear_xmit_timers_sync(strsmp_store_release (&icsk->icsk_pending,0 );smp_store_release (&icsk->icsk_ack.pending,0 ); -sk_stop_timer_sync (sk, &icsk->icsk_retransmit_timer); +sk_stop_timer_sync (sk, &sk->tcp_retransmit_timer);sk_stop_timer_sync (sk, &icsk->icsk_delack_timer);sk_stop_timer_sync (sk, &icsk->icsk_keepalive_timer); }
net/ipv4/tcp_timer.c +3 -5
@@ -701,7 +701,7 @@ void tcp_write_timer_handler(struct sockreturn ;if (time_after (tcp_timeout_expires (sk), jiffies)) { -sk_reset_timer (sk, &icsk->icsk_retransmit_timer, +sk_reset_timer (sk, &sk->tcp_retransmit_timer,tcp_timeout_expires (sk));return ; }
@@ -728,12 +728,10 @@ void tcp_write_timer_handler(struct sockstatic void tcp_write_timer (struct timer_list *t) { -struct inet_connection_sock *icsk = -timer_container_of (icsk, t, icsk_retransmit_timer); -struct sock *sk = &icsk->icsk_inet.sk; +struct sock *sk =timer_container_of (sk, t, tcp_retransmit_timer);/* Avoid locking the socket when there is no pending event. */ -if (!smp_load_acquire (&icsk->icsk_pending)) +if (!smp_load_acquire (&inet_csk (sk)->icsk_pending)) goto out;bh_lock_sock (sk);
net/mptcp/protocol.c +5 -10
@@ -425,9 +425,7 @@ static bool __mptcp_move_skb(struct sockstatic void mptcp_stop_rtx_timer (struct sock *sk) { -struct inet_connection_sock *icsk =inet_csk (sk); - -sk_stop_timer (sk, &icsk->icsk_retransmit_timer); +sk_stop_timer (sk, &sk->mptcp_retransmit_timer);mptcp_sk (sk)->timer_ival =0 ; }
@@ -936,12 +934,11 @@ static void __mptcp_flush_join_list(strustatic bool mptcp_rtx_timer_pending (struct sock *sk) { -return timer_pending (&inet_csk (sk)->icsk_retransmit_timer); +return timer_pending (&sk->mptcp_retransmit_timer); }static void mptcp_reset_rtx_timer (struct sock *sk) { -struct inet_connection_sock *icsk =inet_csk (sk);unsigned long tout;/* prevent rescheduling on close */
@@ -949,7 +946,7 @@ static void mptcp_reset_rtx_timer(structreturn ; tout =mptcp_sk (sk)->timer_ival; -sk_reset_timer (sk, &icsk->icsk_retransmit_timer, jiffies + tout); +sk_reset_timer (sk, &sk->mptcp_retransmit_timer, jiffies + tout); }bool mptcp_schedule_work (struct sock *sk)
@@ -2328,9 +2325,7 @@ out_err:static void mptcp_retransmit_timer (struct timer_list *t) { -struct inet_connection_sock *icsk =timer_container_of (icsk, t, - icsk_retransmit_timer); -struct sock *sk = &icsk->icsk_inet.sk; +struct sock *sk =timer_container_of (sk, t, mptcp_retransmit_timer);struct mptcp_sock *msk =mptcp_sk (sk);bh_lock_sock (sk);
@@ -2936,7 +2931,7 @@ static void __mptcp_init_sock(struct socspin_lock_init (&msk->fallback_lock);/* re-use the csk retrans timer for MPTCP-level retrans */ -timer_setup (&msk->sk.icsk_retransmit_timer, mptcp_retransmit_timer,0 ); +timer_setup (&sk->mptcp_retransmit_timer, mptcp_retransmit_timer,0 );timer_setup (&msk->sk.mptcp_tout_timer, mptcp_tout_timer,0 ); }
tools/testing/selftests/bpf/progs/bpf_iter_tcp4.c +2 -2
@@ -99,10 +99,10 @@ static int dump_tcp_sock(struct seq_file icsk->icsk_pending == ICSK_TIME_REO_TIMEOUT || icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) { timer_active =1 ; - timer_expires = icsk->icsk_retransmit_timer.expires; + timer_expires = sp->tcp_retransmit_timer.expires; } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) { timer_active =4 ; - timer_expires = icsk->icsk_retransmit_timer.expires; + timer_expires = sp->tcp_retransmit_timer.expires; } else if (timer_pending(&icsk->icsk_keepalive_timer)) { timer_active =2 ; timer_expires = icsk->icsk_keepalive_timer.expires;
tools/testing/selftests/bpf/progs/bpf_iter_tcp6.c +2 -2
@@ -99,10 +99,10 @@ static int dump_tcp6_sock(struct seq_fil icsk->icsk_pending == ICSK_TIME_REO_TIMEOUT || icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) { timer_active =1 ; - timer_expires = icsk->icsk_retransmit_timer.expires; + timer_expires = sp->tcp_retransmit_timer.expires; } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) { timer_active =4 ; - timer_expires = icsk->icsk_retransmit_timer.expires; + timer_expires = sp->tcp_retransmit_timer.expires; } else if (timer_pending(&icsk->icsk_keepalive_timer)) { timer_active =2 ; timer_expires = icsk->icsk_keepalive_timer.expires;
Greg Kroah-Hartman
maintainerPATCH 1240/1250 mptcp: do not reschedule the RTX timer for fallback sockets
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paolo Abeni <[email protected]>
[ Upstream commit e2ab913f68c7d11e2561b8a8ad0b87ffefcad667 ]
On fallback socket the retrans timer is a quite convoluted no-op, but currently nothing prevents the MPTCP core to keep rescheduling it.
Additionally gate RTX timer reset to the msk not being fallen back to TCP yet. To avoid adding multiple tests in fast-path, use a new flags bit for such condition.
The RTX enable bit is clear at close time and set before the msk could start retransmitting, with a couple of caveats:
- passive sockets inherit the bit from the listener msk; set the bit on such socket to avoid flipping it in the fast-path, even if the listener will obviously never retransmit.
- while fastopening (MPTFO), mptcp_sendmsg_fastopen still ends-up calling mptcp_connect via tcp_sendmsg_fastopen -> __inet_stream_connect(ssk->sk_socket), and the first subflow's sk_socket points to the msk one.
--- net/mptcp/protocol.c | 13 ++++++++++--- net/mptcp/protocol.h | 1 + 2 files changed, 11 insertions(+), 3 deletions(-)
net/mptcp/protocol.c +10 -3
@@ -93,6 +93,7 @@ bool __mptcp_try_fallback(struct mptcp_s msk->allow_subflows = false;set_bit (MPTCP_FALLBACK_DONE , &msk->flags); +clear_bit (MPTCP_RTX_ENABLED , &msk->flags);__MPTCP_INC_STATS (net, fb_mib);spin_unlock_bh (&msk->fallback_lock);return true;
@@ -939,13 +940,14 @@ static bool mptcp_rtx_timer_pending(strustatic void mptcp_reset_rtx_timer (struct sock *sk) { +struct mptcp_sock *msk =mptcp_sk (sk);unsigned long tout; -/* prevent rescheduling on close */ -if (unlikely (inet_sk_state_load (sk) ==TCP_CLOSE )) +/* Prevent rescheduling on close and in case of fallback. */ +if (!test_bit (MPTCP_RTX_ENABLED , &msk->flags))return ; - tout =mptcp_sk (sk)->timer_ival; + tout = msk->timer_ival;sk_reset_timer (sk, &sk->mptcp_retransmit_timer, jiffies + tout); }
@@ -3050,6 +3052,9 @@ void mptcp_set_state(struct sock *sk, in* transition from TCP_SYN_RECV to TCP_CLOSE_WAIT. */ break ; +case TCP_CLOSE : +clear_bit (MPTCP_RTX_ENABLED , &mptcp_sk (sk)->flags); + fallthrough;default :if (oldstate ==TCP_ESTABLISHED || oldstate ==TCP_CLOSE_WAIT )MPTCP_DEC_STATS (sock_net (sk),MPTCP_MIB_CURRESTAB );
@@ -3850,6 +3855,7 @@ static int mptcp_connect(struct sock *skif (IS_ERR (ssk))return PTR_ERR (ssk); +set_bit (MPTCP_RTX_ENABLED , &msk->flags);mptcp_set_state (sk,TCP_SYN_SENT ); subflow =mptcp_subflow_ctx (ssk);#ifdef CONFIG_TCP_MD5SIG
@@ -3997,6 +4003,7 @@ static int mptcp_listen(struct socket *s goto unlock; } +set_bit (MPTCP_RTX_ENABLED , &msk->flags);mptcp_set_state (sk,TCP_LISTEN );sock_set_flag (sk,SOCK_RCU_FREE );
net/mptcp/protocol.h +1 -0
@@ -116,6 +116,7 @@#define MPTCP_WORK_RTX 1#define MPTCP_FALLBACK_DONE 2#define MPTCP_WORK_CLOSE_SUBFLOW 3 +#define MPTCP_RTX_ENABLED 4/* MPTCP socket release cb flags */ #define MPTCP_PUSH_PENDING 1
Greg Kroah-Hartman
maintainerPATCH 1241/1250 mptcp: prevent race between disconnect() and rtx
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paolo Abeni <[email protected]>
[ Upstream commit 85c580b0d8590520ae00a15c29e9fb9c99427a3e ]
Sashiko noted that the two event can race, leading to inconsistent status. Prevent the race using the synchronous timer stop operation.
--- net/mptcp/protocol.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
net/mptcp/protocol.c +8 -2
@@ -3293,6 +3293,7 @@ static void mptcp_copy_inaddrs(struct sostatic int mptcp_disconnect (struct sock *sk,int flags) { +struct inet_connection_sock *icsk =inet_csk (sk);struct mptcp_sock *msk =mptcp_sk (sk);/* We are on the fastopen error path. We can't call straight into the
@@ -3305,8 +3306,13 @@ static int mptcp_disconnect(struct sockmptcp_check_listen_stop (sk);mptcp_set_state (sk,TCP_CLOSE ); -mptcp_stop_rtx_timer (sk); -mptcp_stop_tout_timer (sk); +/* The later subflow close can not kick again the tout timer, +* as the msk is already in closed status. +*/ + msk->timer_ival = icsk->icsk_rto_min; +sk_stop_timer_sync (sk, &sk->mptcp_retransmit_timer); + icsk->icsk_mtup.probe_timestamp =0 ; +sk_stop_timer_sync (sk, &icsk->mptcp_tout_timer);mptcp_pm_connection_closed (msk);
Greg Kroah-Hartman
maintainerPATCH 1242/1250 smb: client: refactor ACL setting control flow in id_mode_to_cifs_acl()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ralph Boehme <[email protected]>
[ Upstream commit a540a64c4801fe02e452ee37e961018106418260 ]
Refactor the control flow in id_mode_to_cifs_acl() to reduce nesting and prevent error code overwriting.
Instead of wrapping the call to ops->set_acl() in a conditional block, introduce early exits (goto id_mode_to_cifs_acl_exit) when build_sec_desc() fails or ops->set_acl is NULL. This ensures that any actual error returned by build_sec_desc() is not overwritten with -EOPNOTSUPP.
Stable-dep-of: d05045177a85 ("smb: client: fail DACL rewrite when the new DACL exceeds 64K")
--- fs/smb/client/cifsacl.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-)
fs/smb/client/cifsacl.c +10 -6
@@ -1799,14 +1799,18 @@ id_mode_to_cifs_acl(struct inode *inode,cifs_dbg (NOISY ,"build_sec_desc rc: %d\n" , rc); -if (ops->set_acl ==NULL ) - rc = -EOPNOTSUPP ; +if (rc !=0 ) + goto id_mode_to_cifs_acl_exit; -if (!rc) { -/* Set the security descriptor */ - rc = ops->set_acl (pnntsd, nsecdesclen, inode, path, aclflag); -cifs_dbg (NOISY ,"set_cifs_acl rc: %d\n" , rc); +if (ops->set_acl ==NULL ) { + rc = -EOPNOTSUPP ; + goto id_mode_to_cifs_acl_exit; } + +/* Set the security descriptor */ + rc = ops->set_acl (pnntsd, nsecdesclen, inode, path, aclflag); +cifs_dbg (NOISY ,"set_cifs_acl rc: %d\n" , rc); + id_mode_to_cifs_acl_exit:cifs_put_tlink (tlink);
Greg Kroah-Hartman
maintainerPATCH 1243/1250 smb/client: fix security flag calculation when setting security descriptors
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ralph Boehme <[email protected]>
[ Upstream commit 4939889c985da68936090cc013e58c28b7bff34f ]
In id_mode_to_cifs_acl(), aclflag was initialized to CIFS_ACL_DACL by default. This forced the client to request setting the DACL even when only an ownership (chown) or group (chgrp) change was being performed.
Let build_sec_desc() do the proper flag calculation by initializing aclflag to 0. build_sec_desc() sets the appropriate bits (CIFS_ACL_OWNER, CIFS_ACL_GROUP, or CIFS_ACL_DACL) depending on what actually changed. During ownership transfer, CIFS_ACL_DACL is only set if replace_sids_and_copy_aces() actually replaces the SIDs inside any of the DACL's ACEs.
If build_sec_desc() results in aclflag being 0 (meaning no changes were mapped), exit early to avoid sending an empty security descriptor update to the server.
Stable-dep-of: d05045177a85 ("smb: client: fail DACL rewrite when the new DACL exceeds 64K")
--- fs/smb/client/cifsacl.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-)
fs/smb/client/cifsacl.c +16 -6
@@ -1130,7 +1130,8 @@ set_size:static __u16 replace_sids_and_copy_aces (struct smb_acl *pdacl,struct smb_acl *pndacl,struct smb_sid *pownersid,struct smb_sid *pgrpsid, -struct smb_sid *pnownersid,struct smb_sid *pngrpsid) +struct smb_sid *pnownersid,struct smb_sid *pngrpsid, +int *aclflag) {int i;u16 size =0 ;
@@ -1154,12 +1155,15 @@ static __u16 replace_sids_and_copy_aces( pntace = (struct smb_ace *) (acl_base + size); pnntace = (struct smb_ace *) (nacl_base + nsize); -if (pnownersid &&compare_sids (&pntace->sid, pownersid) ==0 ) +if (pnownersid &&compare_sids (&pntace->sid, pownersid) ==0 ) { ace_size =cifs_copy_ace (pnntace, pntace, pnownersid); -else if (pngrpsid &&compare_sids (&pntace->sid, pgrpsid) ==0 ) + *aclflag |=CIFS_ACL_DACL ; + }else if (pngrpsid &&compare_sids (&pntace->sid, pgrpsid) ==0 ) { ace_size =cifs_copy_ace (pnntace, pntace, pngrpsid); -else + *aclflag |=CIFS_ACL_DACL ; + }else { ace_size =cifs_copy_ace (pnntace, pntace,NULL ); + } size +=le16_to_cpu (pntace->size); nsize += ace_size;
@@ -1481,7 +1485,8 @@ static int build_sec_desc(struct smb_nts/* Replace ACEs for old owner with new one */ size =replace_sids_and_copy_aces (dacl_ptr, ndacl_ptr, owner_sid_ptr, group_sid_ptr, - nowner_sid_ptr, ngroup_sid_ptr); + nowner_sid_ptr, ngroup_sid_ptr, + aclflag); ndacl_ptr->size =cpu_to_le16 (size); }
@@ -1696,7 +1701,7 @@ id_mode_to_cifs_acl(struct inode *inode, kuid_t uid, kgid_t gid) { int rc = 0; -int aclflag =CIFS_ACL_DACL ;/* default flag to set */ +int aclflag =0 ;__u32 secdesclen =0 ;__u32 nsecdesclen =0 ;__u32 dacloffset =0 ;
@@ -1802,6 +1807,11 @@ id_mode_to_cifs_acl(struct inode *inode,if (rc !=0 ) goto id_mode_to_cifs_acl_exit; +if (aclflag ==0 ) { +cifs_dbg (FYI ,"set_cifs_acl aclflag=0, no change mapped\n" ); + goto id_mode_to_cifs_acl_exit; + } +if (ops->set_acl ==NULL ) { rc = -EOPNOTSUPP ; goto id_mode_to_cifs_acl_exit;
Greg Kroah-Hartman
maintainerPATCH 1244/1250 smb: client: fail DACL rewrite when the new DACL exceeds 64K
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bjoern Doebel <[email protected]>
[ Upstream commit d05045177a855386bca5e1909e08d06290e6e3b3 ]
replace_sids_and_copy_aces() and set_chmod_dacl() accumulate the size of the DACL they build in a u16. That accumulator can wrap.
validate_dacl() caps num_aces at (dacl_size - sizeof(struct smb_acl)) / 20, i.e. 3276 for a maximally sized DACL, while each rewritten ACE can grow to sizeof(struct smb_ace) (76 bytes) once its SID is replaced with one carrying SID_MAX_SUB_AUTHORITIES sub-authorities. The worst case is therefore sizeof(struct smb_acl) + 3276 * 76 = 248984 bytes, far beyond what a u16 can hold. A wraparound is reached with 863 ACEs.
After the wraparound, ndacl_ptr->size becomes meaningless and the offset will point anywhere in the ACE array. As a result, we will see corruption of the DACL, which then gets sent to the server. This is not an out-of-bounds write as the allocation now covers the worst-case expansion, so writes will always go into the buffer.
Adjust the code to use a u32 internally and return -EOVERFLOW in the overflow case. The operation must be refused, because a DACL can only hold 2^16-1 bytes on the wire and larger DACLs cannot be represented.
set_chmod_dacl() carries the same pattern and is fixed the same way. It only wraps once the source DACL comes within roughly 380 bytes of the 64K ceiling, but the failure mode is identical.
--- fs/smb/client/cifsacl.c | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-)
fs/smb/client/cifsacl.c +26 -13
@@ -1023,13 +1023,13 @@ unsigned int setup_special_user_owner_ACstatic void populate_new_aces (char *nacl_base,struct smb_sid *pownersid,struct smb_sid *pgrpsid, -__u64 *pnmode,u16 *pnum_aces,u16 *pnsize, +__u64 *pnmode,u16 *pnum_aces,u32 *pnsize,bool modefromsid,bool posix) {__u64 nmode;u16 num_aces =0 ; -u16 nsize =0 ; +u32 nsize =0 ;__u64 user_mode;__u64 group_mode;__u64 other_mode;
@@ -1128,17 +1128,17 @@ set_size: *pnsize = nsize; } -static __u16 replace_sids_and_copy_aces (struct smb_acl *pdacl,struct smb_acl *pndacl, -struct smb_sid *pownersid,struct smb_sid *pgrpsid, -struct smb_sid *pnownersid,struct smb_sid *pngrpsid, -int *aclflag) +static int replace_sids_and_copy_aces (struct smb_acl *pdacl,struct smb_acl *pndacl, +struct smb_sid *pownersid,struct smb_sid *pgrpsid, +struct smb_sid *pnownersid,struct smb_sid *pngrpsid, +int *aclflag,u16 *pnsize) {int i;u16 size =0 ;struct smb_ace *pntace =NULL ;char *acl_base =NULL ;u16 src_num_aces =0 ; -u16 nsize =0 ; +u32 nsize =0 ;struct smb_ace *pnntace =NULL ;char *nacl_base =NULL ;u16 ace_size =0 ;
@@ -1167,9 +1167,12 @@ static __u16 replace_sids_and_copy_aces( size +=le16_to_cpu (pntace->size); nsize += ace_size; +if (nsize >U16_MAX ) +return -EOVERFLOW ; } -return nsize; + *pnsize = nsize; +return 0 ; } static int set_chmod_dacl(struct smb_acl *pdacl, struct smb_acl *pndacl,
@@ -1181,7 +1184,7 @@ static int set_chmod_dacl(struct smb_aclstruct smb_ace *pntace =NULL ;char *acl_base =NULL ;u16 src_num_aces =0 ; -u16 nsize =0 ; +u32 nsize =0 ;struct smb_ace *pnntace =NULL ;char *nacl_base =NULL ;u16 num_aces =0 ;
@@ -1232,6 +1235,8 @@ static int set_chmod_dacl(struct smb_acl nsize +=cifs_copy_ace (pnntace, pntace,NULL ); num_aces++; +if (nsize >U16_MAX ) +return -EOVERFLOW ; next_ace: size +=le16_to_cpu (pntace->size);
@@ -1248,6 +1253,10 @@ next_ace: } finalize_dacl: +/* The DACL size field is 16-bit on the wire, see MS-DTYP 2.4.5 */ +if (nsize >U16_MAX ) +return -EOVERFLOW ; + pndacl->num_aces =cpu_to_le16 (num_aces); pndacl->size =cpu_to_le16 (nsize);
@@ -1408,6 +1417,8 @@ static int build_sec_desc(struct smb_nts rc =set_chmod_dacl (dacl_ptr, ndacl_ptr, owner_sid_ptr, group_sid_ptr, pnmode, mode_from_sid, posix); +if (rc) +return rc; sidsoffset = ndacloffset +le16_to_cpu (ndacl_ptr->size);/* copy the non-dacl portion of secdesc */
@@ -1483,10 +1494,12 @@ static int build_sec_desc(struct smb_ntsif (dacloffset) {/* Replace ACEs for old owner with new one */ - size =replace_sids_and_copy_aces (dacl_ptr, ndacl_ptr, - owner_sid_ptr, group_sid_ptr, - nowner_sid_ptr, ngroup_sid_ptr, - aclflag); + rc =replace_sids_and_copy_aces (dacl_ptr, ndacl_ptr, + owner_sid_ptr, group_sid_ptr, + nowner_sid_ptr, ngroup_sid_ptr, + aclflag, &size); +if (rc) + goto chown_chgrp_exit; ndacl_ptr->size =cpu_to_le16 (size); }
Greg Kroah-Hartman
maintainerPATCH 1245/1250 smb: client: use atomic_t for mnt_cifs_flags
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paulo Alcantara <[email protected]>
[ Upstream commit 4fc3a433c13944ee5766ec5b9bf6f1eb4d29b880 ]
Use atomic_t for cifs_sb_info::mnt_cifs_flags as it's currently accessed locklessly and may be changed concurrently in mount/remount and reconnect paths.
[Backport to 6.18: retain the atomic mount-flag conversion while keeping this branch's existing function interfaces and locations. Implement cifs_sb_flags as a single-evaluation macro with the upstream unsigned return type; do not add functions or import the generic CIFS_SB helpers, inode-state changes, reconnect helpers, or oplock refactors.
Convert the existing readers, including the legacy cache macros, to the accessor. Use atomic bit operations at existing update sites, including reset_cifs_unix_caps in connect.c, and publish the remount flag snapshot with atomic_set. Keep smb3_update_mnt_flags returning void.
This supplies the accessor required by cd2b2b57921d (smb: client: fix WSL reparse point uid/gid override), whose patch applies without changes.]
[ sashal: Reduced backport -- upstream 4fc3a433c1394 touches 27 file(s), this
backport carries 25. Not backported here:
fs/smb/client/cifs_unicode.h
fs/smb/client/fs_context.h
This note is generated from the file lists only; see the resolution record for the reasoning. ]
Stable-dep-of: cd2b2b57921d ("smb: client: fix WSL reparse point uid/gid override")
--- fs/smb/client/cached_dir.c | 2 fs/smb/client/cifs_fs_sb.h | 8 ++- fs/smb/client/cifs_ioctl.h | 2 fs/smb/client/cifs_unicode.c | 4 - fs/smb/client/cifsacl.c | 6 +- fs/smb/client/cifsfs.c | 66 ++++++++++++------------- fs/smb/client/cifsglob.h | 10 ++- fs/smb/client/connect.c | 43 +++++++--------- fs/smb/client/dfs_cache.c | 2 fs/smb/client/dir.c | 16 +++--- fs/smb/client/file.c | 32 ++++++------ fs/smb/client/fs_context.c | 110 +++++++++++++++++++++---------------------- fs/smb/client/inode.c | 80 +++++++++++++++---------------- fs/smb/client/ioctl.c | 2 fs/smb/client/link.c | 4 - fs/smb/client/misc.c | 12 ++-- fs/smb/client/readdir.c | 16 +++--- fs/smb/client/reparse.c | 10 +-- fs/smb/client/reparse.h | 4 - fs/smb/client/smb1ops.c | 4 - fs/smb/client/smb2file.c | 2 fs/smb/client/smb2misc.c | 4 - fs/smb/client/smb2ops.c | 4 - fs/smb/client/smb2pdu.c | 4 - fs/smb/client/xattr.c | 6 +- 25 files changed, 230 insertions(+), 223 deletions(-)
fs/smb/client/cached_dir.c +1 -1
@@ -118,7 +118,7 @@ static const char *path_no_prefix(structif (!*path)return path; -if ((cifs_sb->mnt_cifs_flags &CIFS_MOUNT_USE_PREFIX_PATH ) && +if ((cifs_sb_flags (cifs_sb) &CIFS_MOUNT_USE_PREFIX_PATH ) && cifs_sb->prepath) { len =strlen (cifs_sb->prepath) +1 ;if (unlikely (len >strlen (path)))
fs/smb/client/cifs_fs_sb.h +7 -1
@@ -10,6 +10,7 @@#ifndef _CIFS_FS_SB_H#define _CIFS_FS_SB_H +#include <linux/atomic.h> #include <linux/backing-dev.h> #define CIFS_MOUNT_NO_PERM 1/* do not do client vfs_perm check */
@@ -55,7 +56,7 @@ struct cifs_sb_info {struct nls_table *local_nls;struct smb3_fs_context *ctx;atomic_t active; -unsigned int mnt_cifs_flags; +atomic_t mnt_cifs_flags;struct delayed_work prune_tlinks;struct rcu_head rcu;
@@ -72,4 +73,9 @@ struct cifs_sb_info {*/ struct dentry *root; }; + +/* Mount flags are accessed locklessly by mount/remount and reconnect paths. */ +#define cifs_sb_flags (cifs_sb) \ + ((unsigned int)atomic_read(&(cifs_sb)->mnt_cifs_flags)) +#endif /* _CIFS_FS_SB_H */
fs/smb/client/cifs_ioctl.h +1 -1
@@ -125,7 +125,7 @@ struct smb3_notify_info {static inline bool cifs_forced_shutdown (struct cifs_sb_info *sbi) { -if (CIFS_MOUNT_SHUTDOWN & sbi->mnt_cifs_flags) +if (CIFS_MOUNT_SHUTDOWN &cifs_sb_flags (sbi))return true;else return false;
fs/smb/client/cifs_unicode.c +2 -2
@@ -16,9 +16,9 @@ int cifs_remap(struct cifs_sb_info *cifs {int map_type; -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_MAP_SFM_CHR ) +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_MAP_SFM_CHR ) map_type =SFM_MAP_UNI_RSVD ; -else if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_MAP_SPECIAL_CHR ) +else if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_MAP_SPECIAL_CHR ) map_type =SFU_MAP_UNI_RSVD ;else map_type =NO_MAP_UNI_RSVD ;
fs/smb/client/cifsacl.c +3 -3
@@ -373,7 +373,7 @@ sid_to_id(struct cifs_sb_info *cifs_sb,return -EIO ; } -if ((cifs_sb->mnt_cifs_flags &CIFS_MOUNT_UID_FROM_ACL ) || +if ((cifs_sb_flags (cifs_sb) &CIFS_MOUNT_UID_FROM_ACL ) || (cifs_sb_master_tcon (cifs_sb)->posix_extensions)) {uint32_t unix_id;bool is_group;
@@ -1752,12 +1752,12 @@ id_mode_to_cifs_acl(struct inode *inode,return rc; } -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_MODE_FROM_SID ) +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_MODE_FROM_SID ) mode_from_sid = true;else mode_from_sid = false; -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_UID_FROM_ACL ) +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_UID_FROM_ACL ) id_from_sid = true;else id_from_sid = false;
fs/smb/client/cifsfs.c +33 -33
148 lines not on this page · raw message
fs/smb/client/cifsglob.h +7 -3
@@ -1540,9 +1540,13 @@ int cifs_file_set_size(const unsigned in#define CIFS_CACHE_RW_FLG (CIFS_CACHE_READ_FLG | CIFS_CACHE_WRITE_FLG)#define CIFS_CACHE_RHW_FLG (CIFS_CACHE_RW_FLG | CIFS_CACHE_HANDLE_FLG) -#define CIFS_CACHE_READ (cinode) ((cinode->oplock & CIFS_CACHE_READ_FLG) || (CIFS_SB(cinode->netfs.inode.i_sb)->mnt_cifs_flags & CIFS_MOUNT_RO_CACHE)) +#define CIFS_CACHE_READ (cinode) \ + (((cinode)->oplock & CIFS_CACHE_READ_FLG) || \ + (cifs_sb_flags(CIFS_SB((cinode)->netfs.inode.i_sb)) & CIFS_MOUNT_RO_CACHE))#define CIFS_CACHE_HANDLE (cinode) (cinode->oplock & CIFS_CACHE_HANDLE_FLG) -#define CIFS_CACHE_WRITE (cinode) ((cinode->oplock & CIFS_CACHE_WRITE_FLG) || (CIFS_SB(cinode->netfs.inode.i_sb)->mnt_cifs_flags & CIFS_MOUNT_RW_CACHE)) +#define CIFS_CACHE_WRITE (cinode) \ + (((cinode)->oplock & CIFS_CACHE_WRITE_FLG) || \ + (cifs_sb_flags(CIFS_SB((cinode)->netfs.inode.i_sb)) & CIFS_MOUNT_RW_CACHE))/* * One of these for each file inode
@@ -1605,7 +1609,7 @@ CIFS_FILE_SB(struct file *file)static inline char CIFS_DIR_SEP (const struct cifs_sb_info *cifs_sb) { -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_POSIX_PATHS ) +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_POSIX_PATHS )return '/' ;else return '\\' ;
fs/smb/client/connect.c +20 -23
133 lines not on this page · raw message
fs/smb/client/dfs_cache.c +1 -1
@@ -1352,7 +1352,7 @@ int dfs_cache_remount_fs(struct cifs_sb_* Force the use of prefix path to support failover on DFS paths that resolve to targets * that have different prefix paths. */ - cifs_sb->mnt_cifs_flags |=CIFS_MOUNT_USE_PREFIX_PATH ; +atomic_or (CIFS_MOUNT_USE_PREFIX_PATH , &cifs_sb->mnt_cifs_flags);refresh_tcon_referral (tcon, true);return 0 ;
fs/smb/client/dir.c +8 -8
@@ -97,7 +97,7 @@ char *__build_path_from_dentry_optional_else dfsplen =0 ; -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_USE_PREFIX_PATH ) +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_USE_PREFIX_PATH ) pplen = cifs_sb->prepath ?strlen (cifs_sb->prepath) +1 :0 ; s =dentry_path_raw (direntry, page,PATH_MAX );
@@ -124,7 +124,7 @@ char *__build_path_from_dentry_optional_if (dfsplen) { s -= dfsplen;memcpy (s, tree, dfsplen); -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_POSIX_PATHS ) { +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_POSIX_PATHS ) {int i;for (i =0 ; i < dfsplen; i++) {if (s[i] =='\\' )
@@ -161,7 +161,7 @@ check_name(struct dentry *direntry, stru le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength)))return -ENAMETOOLONG ; -if (!(cifs_sb->mnt_cifs_flags &CIFS_MOUNT_POSIX_PATHS )) { +if (!(cifs_sb_flags (cifs_sb) &CIFS_MOUNT_POSIX_PATHS )) {for (i =0 ; i < direntry->d_name.len; i++) {if (direntry->d_name.name[i] =='\\' ) {cifs_dbg (FYI ,"Invalid file name\n" );
@@ -376,7 +376,7 @@ retry_open: .device = 0, }; -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_SET_UID ) { +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_SET_UID ) { args.uid =current_fsuid ();if (inode->i_mode &S_ISGID ) args.gid = inode->i_gid;
@@ -413,9 +413,9 @@ cifs_create_get_file_info:if (server->ops->set_lease_key) server->ops->set_lease_key (newinode, fid);if ((*oplock &CIFS_CREATE_ACTION ) &&S_ISREG (newinode->i_mode)) { -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_DYNPERM ) +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_DYNPERM ) newinode->i_mode = mode; -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_SET_UID ) { +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_SET_UID ) { newinode->i_uid =current_fsuid ();if (inode->i_mode &S_ISGID ) newinode->i_gid = inode->i_gid;
@@ -539,8 +539,8 @@ cifs_atomic_open(struct inode *inode, st }if (file->f_flags &O_DIRECT && -CIFS_SB (inode->i_sb)->mnt_cifs_flags &CIFS_MOUNT_STRICT_IO ) { -if (CIFS_SB (inode->i_sb)->mnt_cifs_flags &CIFS_MOUNT_NO_BRL ) +cifs_sb_flags (CIFS_SB (inode->i_sb)) &CIFS_MOUNT_STRICT_IO ) { +if (cifs_sb_flags (CIFS_SB (inode->i_sb)) &CIFS_MOUNT_NO_BRL ) file->f_op = &cifs_file_direct_nobrl_ops;else file->f_op = &cifs_file_direct_ops;
fs/smb/client/file.c +16 -16
@@ -282,7 +282,7 @@ static int cifs_init_request(struct netf open_file = file->private_data; rreq->netfs_priv = file->private_data; req->cfile =cifsFileInfo_get (open_file); -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_RWPIDFORWARD ) +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_RWPIDFORWARD ) req->pid = req->cfile->pid; }else if (rreq->origin !=NETFS_WRITEBACK ) {WARN_ON_ONCE (1 );
@@ -896,7 +896,7 @@ void _cifsFileInfo_put(struct cifsFileIn* close because it may cause a error when we open this file * again and get at least level II oplock. */ -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_STRICT_IO ) +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_STRICT_IO )set_bit (CIFS_INO_INVALID_MAPPING , &cifsi->flags);cifs_set_oplock_level (cifsi,0 ); }
@@ -949,7 +949,7 @@ int cifs_file_flush(const unsigned int xstruct cifs_tcon *tcon;int rc; -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NOSSYNC ) +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NOSSYNC )return 0 ;if (cfile && (OPEN_FMODE (cfile->f_flags) &FMODE_WRITE )) {
@@ -1047,8 +1047,8 @@ int cifs_open(struct inode *inode, struc inode, file->f_flags, full_path);if (file->f_flags &O_DIRECT && - cifs_sb->mnt_cifs_flags &CIFS_MOUNT_STRICT_IO ) { -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NO_BRL ) +cifs_sb_flags (cifs_sb) &CIFS_MOUNT_STRICT_IO ) { +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NO_BRL ) file->f_op = &cifs_file_direct_nobrl_ops;else file->f_op = &cifs_file_direct_ops;
@@ -1212,7 +1212,7 @@ cifs_relock_file(struct cifsFileInfo *cf#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY if (cap_unix (tcon->ses) && (CIFS_UNIX_FCNTL_CAP &le64_to_cpu (tcon->fsUnixInfo.Capability)) && - ((cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NOPOSIXBRL ) ==0 )) + ((cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NOPOSIXBRL ) ==0 )) rc =cifs_push_posix_locks (cfile); else#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
@@ -2008,7 +2008,7 @@ cifs_push_locks(struct cifsFileInfo *cfi#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY if (cap_unix (tcon->ses) && (CIFS_UNIX_FCNTL_CAP &le64_to_cpu (tcon->fsUnixInfo.Capability)) && - ((cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NOPOSIXBRL ) ==0 )) + ((cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NOPOSIXBRL ) ==0 )) rc =cifs_push_posix_locks (cfile); else#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
@@ -2416,7 +2416,7 @@ int cifs_flock(struct file *file, int cmif (cap_unix (tcon->ses) && (CIFS_UNIX_FCNTL_CAP &le64_to_cpu (tcon->fsUnixInfo.Capability)) && - ((cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NOPOSIXBRL ) ==0 )) + ((cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NOPOSIXBRL ) ==0 )) posix_lck = true;if (!lock && !unlock) {
@@ -2466,7 +2466,7 @@ int cifs_lock(struct file *file, int cmdif (cap_unix (tcon->ses) && (CIFS_UNIX_FCNTL_CAP &le64_to_cpu (tcon->fsUnixInfo.Capability)) && - ((cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NOPOSIXBRL ) ==0 )) + ((cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NOPOSIXBRL ) ==0 )) posix_lck = true;/* * BB add code here to normalize offset and length to account for
@@ -2520,7 +2520,7 @@ struct cifsFileInfo *find_readable_file(struct cifs_sb_info *cifs_sb =CIFS_SB (cifs_inode->netfs.inode.i_sb);/* only filter by fsuid on multiuser mounts */ -if (!(cifs_sb->mnt_cifs_flags &CIFS_MOUNT_MULTIUSER )) +if (!(cifs_sb_flags (cifs_sb) &CIFS_MOUNT_MULTIUSER )) fsuid_only = false;spin_lock (&cifs_inode->open_file_lock);
@@ -2576,7 +2576,7 @@ cifs_get_writable_file(struct cifsInodeI cifs_sb =CIFS_SB (cifs_inode->netfs.inode.i_sb);/* only filter by fsuid on multiuser mounts */ -if (!(cifs_sb->mnt_cifs_flags &CIFS_MOUNT_MULTIUSER )) +if (!(cifs_sb_flags (cifs_sb) &CIFS_MOUNT_MULTIUSER )) fsuid_only = false;spin_lock (&cifs_inode->open_file_lock);
@@ -2785,7 +2785,7 @@ int cifs_fsync(struct file *file, loff_t file, datasync); tcon =tlink_tcon (smbfile->tlink); -if (!(cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NOSSYNC )) { +if (!(cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NOSSYNC )) { server = tcon->ses->server;if (server->ops->flush ==NULL ) { rc = -ENOSYS ;
@@ -2854,7 +2854,7 @@ cifs_writev(struct kiocb *iocb, struct iif (rc <=0 ) goto out; -if ((cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NOPOSIXBRL ) && +if ((cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NOPOSIXBRL ) && (cifs_find_lock_conflict (cfile, iocb->ki_pos,iov_iter_count (from), server->vals->exclusive_lock_type,0 ,NULL ,CIFS_WRITE_OP ))) {
@@ -2890,7 +2890,7 @@ cifs_strict_writev(struct kiocb *iocb, sif (CIFS_CACHE_WRITE (cinode)) {if (cap_unix (tcon->ses) && (CIFS_UNIX_FCNTL_CAP &le64_to_cpu (tcon->fsUnixInfo.Capability)) && - ((cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NOPOSIXBRL ) ==0 )) { + ((cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NOPOSIXBRL ) ==0 )) { written =netfs_file_write_iter (iocb, from); goto out; }
@@ -2995,7 +2995,7 @@ cifs_strict_readv(struct kiocb *iocb, stif (!CIFS_CACHE_READ (cinode))return netfs_unbuffered_read_iter (iocb, to); -if ((cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NOPOSIXBRL ) ==0 ) { +if ((cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NOPOSIXBRL ) ==0 ) {if (iocb->ki_flags &IOCB_DIRECT )return netfs_unbuffered_read_iter (iocb, to);return netfs_buffered_read_iter (iocb, to);
@@ -3117,7 +3117,7 @@ bool is_size_safe_to_change(struct cifsIstruct cifs_sb_info *cifs_sb; cifs_sb =CIFS_SB (cifsInode->netfs.inode.i_sb); -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_DIRECT_IO ) { +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_DIRECT_IO ) {/* since no page cache to corrupt on directio we can change size safely */ return true;
fs/smb/client/fs_context.c +55 -55
200 lines not on this page · raw message
fs/smb/client/inode.c +40 -40
268 lines not on this page · raw message
fs/smb/client/ioctl.c +1 -1
@@ -217,7 +217,7 @@ static int cifs_shutdown(struct super_bl*/ case CIFS_GOING_FLAGS_LOGFLUSH :case CIFS_GOING_FLAGS_NOLOGFLUSH : - sbi->mnt_cifs_flags |=CIFS_MOUNT_SHUTDOWN ; +atomic_or (CIFS_MOUNT_SHUTDOWN , &sbi->mnt_cifs_flags); goto shutdown_good;default : rc = -EINVAL ;
fs/smb/client/link.c +2 -2
@@ -593,14 +593,14 @@ cifs_symlink(struct mnt_idmap *idmap, stbreak ;case CIFS_SYMLINK_TYPE_MFSYMLINKS : -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_MF_SYMLINKS ) { +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_MF_SYMLINKS ) { rc =create_mf_symlink (xid, pTcon, cifs_sb, full_path, symname); }break ;case CIFS_SYMLINK_TYPE_SFU : -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_UNX_EMUL ) { +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_UNX_EMUL ) { rc =__cifs_sfu_make_node (xid, inode, direntry, pTcon, full_path,S_IFLNK ,0 , symname);
fs/smb/client/misc.c +6 -6
@@ -566,13 +566,13 @@ dump_smb(void *buf, int smb_buf_length)void cifs_autodisable_serverino (struct cifs_sb_info *cifs_sb) { -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_SERVER_INUM ) { +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_SERVER_INUM ) {struct cifs_tcon *tcon =NULL ;if (cifs_sb->master_tlink) tcon =cifs_sb_master_tcon (cifs_sb); - cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM ; +atomic_andnot (CIFS_MOUNT_SERVER_INUM , &cifs_sb->mnt_cifs_flags); cifs_sb->mnt_cifs_serverino_autodisabled = true;cifs_dbg (VFS ,"Autodisabling the use of server inode numbers on %s\n" , tcon ? tcon->tree_name :"new server" );
@@ -674,11 +674,11 @@ void cifs_done_oplock_break(struct cifsIbool backup_cred (struct cifs_sb_info *cifs_sb) { -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_CIFS_BACKUPUID ) { +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_CIFS_BACKUPUID ) {if (uid_eq (cifs_sb->ctx->backupuid,current_fsuid ()))return true; } -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_CIFS_BACKUPGID ) { +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_CIFS_BACKUPGID ) {if (in_group_p (cifs_sb->ctx->backupgid))return true; }
@@ -1306,7 +1306,7 @@ int cifs_update_super_prepath(struct cifconvert_delimiter (cifs_sb->prepath,CIFS_DIR_SEP (cifs_sb)); } - cifs_sb->mnt_cifs_flags |=CIFS_MOUNT_USE_PREFIX_PATH ; +atomic_or (CIFS_MOUNT_USE_PREFIX_PATH , &cifs_sb->mnt_cifs_flags);return 0 ; }
@@ -1335,7 +1335,7 @@ int cifs_inval_name_dfs_link_error(const* look up or tcon is not DFS. */ if (strlen (full_path) <2 || !cifs_sb || - (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NO_DFS ) || + (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NO_DFS ) || !is_tcon_dfs (tcon))return 0 ;
fs/smb/client/readdir.c +8 -8
@@ -122,7 +122,7 @@ retry:* want to clobber the existing one with the one that * the readdir code created. */ -if (!(cifs_sb->mnt_cifs_flags &CIFS_MOUNT_SERVER_INUM )) +if (!(cifs_sb_flags (cifs_sb) &CIFS_MOUNT_SERVER_INUM )) fattr->cf_uniqueid =CIFS_I (inode)->uniqueid;/*
@@ -216,11 +216,11 @@ out_reparse:* may look wrong since the inodes may not have timed out by the time * "ls" does a stat() call on them. */ -if ((cifs_sb->mnt_cifs_flags &CIFS_MOUNT_CIFS_ACL ) || - (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_MODE_FROM_SID )) +if ((cifs_sb_flags (cifs_sb) &CIFS_MOUNT_CIFS_ACL ) || + (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_MODE_FROM_SID )) fattr->cf_flags |=CIFS_FATTR_NEED_REVAL ; -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_UNX_EMUL && +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_UNX_EMUL && fattr->cf_cifsattrs &ATTR_SYSTEM ) {if (fattr->cf_eof ==0 ) { fattr->cf_mode &= ~S_IFMT ;
@@ -396,7 +396,7 @@ ffirst_retry:else if ((tcon->ses->capabilities & tcon->ses->server->vals->cap_nt_find) ==0 ) { cifsFile->srch_inf.info_level =SMB_FIND_FILE_INFO_STANDARD ; - }else if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_SERVER_INUM ) { + }else if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_SERVER_INUM ) { cifsFile->srch_inf.info_level =SMB_FIND_FILE_ID_FULL_DIR_INFO ; }else /* not srvinos - BB fixme add check for backlevel? */ { cifsFile->srch_inf.info_level =SMB_FIND_FILE_FULL_DIRECTORY_INFO ;
@@ -413,7 +413,7 @@ ffirst_retry:if (rc ==0 ) { cifsFile->invalidHandle = false; }else if ((rc == -EOPNOTSUPP ) && - (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_SERVER_INUM )) { + (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_SERVER_INUM )) {cifs_autodisable_serverino (cifs_sb); goto ffirst_retry; }
@@ -1025,14 +1025,14 @@ static int cifs_filldir(char *find_entrybreak ; } -if (de.ino && (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_SERVER_INUM )) { +if (de.ino && (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_SERVER_INUM )) { fattr.cf_uniqueid = de.ino; }else { fattr.cf_uniqueid =iunique (sb,ROOT_I );cifs_autodisable_serverino (cifs_sb); } -if ((cifs_sb->mnt_cifs_flags &CIFS_MOUNT_MF_SYMLINKS ) && +if ((cifs_sb_flags (cifs_sb) &CIFS_MOUNT_MF_SYMLINKS ) &&couldbe_mf_symlink (&fattr))/* * trying to get the type and mode can be slow,
fs/smb/client/reparse.c +5 -5
@@ -83,7 +83,7 @@ static int create_native_symlink(const u .symlink_target = symlink_target, }; -if (!(cifs_sb->mnt_cifs_flags &CIFS_MOUNT_POSIX_PATHS ) && +if (!(cifs_sb_flags (cifs_sb) &CIFS_MOUNT_POSIX_PATHS ) && symroot && symname[0 ] =='/' ) {/* * This is a request to create an absolute symlink on the server
@@ -164,7 +164,7 @@ static int create_native_symlink(const u* mask these characters in NT object prefix by '_' and then change * them back. */ -if (!(cifs_sb->mnt_cifs_flags &CIFS_MOUNT_POSIX_PATHS ) && symname[0 ] =='/' ) +if (!(cifs_sb_flags (cifs_sb) &CIFS_MOUNT_POSIX_PATHS ) && symname[0 ] =='/' ) sym[0 ] = sym[1 ] = sym[2 ] = sym[5 ] ='_' ; path =cifs_convert_path_to_utf16 (sym, cifs_sb);
@@ -173,7 +173,7 @@ static int create_native_symlink(const u goto out; } -if (!(cifs_sb->mnt_cifs_flags &CIFS_MOUNT_POSIX_PATHS ) && symname[0 ] =='/' ) { +if (!(cifs_sb_flags (cifs_sb) &CIFS_MOUNT_POSIX_PATHS ) && symname[0 ] =='/' ) { sym[0 ] ='\\' ; sym[1 ] = sym[2 ] ='?' ; sym[5 ] =':' ;
@@ -197,7 +197,7 @@ static int create_native_symlink(const u slen =2 *UniStrnlen ((wchar_t *)path,REPARSE_SYM_PATH_MAX ); poff =0 ; plen = slen; -if (!(cifs_sb->mnt_cifs_flags &CIFS_MOUNT_POSIX_PATHS ) && symname[0 ] =='/' ) { +if (!(cifs_sb_flags (cifs_sb) &CIFS_MOUNT_POSIX_PATHS ) && symname[0 ] =='/' ) {/* * For absolute NT symlinks skip leading "\\??\\" in PrintName as * PrintName is user visible location in DOS/Win32 format (not in NT format).
@@ -822,7 +822,7 @@ int smb2_parse_native_symlink(char **tar goto out; } -if (!(cifs_sb->mnt_cifs_flags &CIFS_MOUNT_POSIX_PATHS ) && +if (!(cifs_sb_flags (cifs_sb) &CIFS_MOUNT_POSIX_PATHS ) && symroot && !relative) {/* * This is an absolute symlink from the server which does not
fs/smb/client/reparse.h +2 -2
@@ -32,7 +32,7 @@ static inline kuid_t wsl_make_kuid(struc {u32 uid =le32_to_cpu (*(__le32 *)ptr); -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_OVERR_UID ) +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_OVERR_UID )return cifs_sb->ctx->linux_uid;return make_kuid (current_user_ns (), uid); }
@@ -42,7 +42,7 @@ static inline kgid_t wsl_make_kgid(struc {u32 gid =le32_to_cpu (*(__le32 *)ptr); -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_OVERR_GID ) +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_OVERR_GID )return cifs_sb->ctx->linux_gid;return make_kgid (current_user_ns (), gid); }
fs/smb/client/smb1ops.c +2 -2
@@ -1138,7 +1138,7 @@ cifs_make_node(unsigned int xid, struct .mtime = NO_CHANGE_64, .device = dev, }; -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_SET_UID ) { +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_SET_UID ) { args.uid =current_fsuid (); args.gid =current_fsgid (); }else {
@@ -1157,7 +1157,7 @@ cifs_make_node(unsigned int xid, structif (rc ==0 )d_instantiate (dentry, newinode);return rc; - }else if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_UNX_EMUL ) { + }else if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_UNX_EMUL ) {/* * Check if mounted with mount parm 'sfu' mount parm. * SFU emulation should work with all servers
fs/smb/client/smb2file.c +1 -1
@@ -93,7 +93,7 @@ int smb2_fix_symlink_target_type(char *** POSIX server does not distinguish between symlinks to file and * symlink directory. So nothing is needed to fix on the client side. */ -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_POSIX_PATHS ) +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_POSIX_PATHS )return 0 ;if (!*target)
fs/smb/client/smb2misc.c +2 -2
@@ -496,9 +496,9 @@ cifs_convert_path_to_utf16(const char *f__le16 *to;int map_type; -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_MAP_SFM_CHR ) +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_MAP_SFM_CHR ) map_type =SFM_MAP_UNI_RSVD ; -else if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_MAP_SPECIAL_CHR ) +else if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_MAP_SPECIAL_CHR ) map_type =SFU_MAP_UNI_RSVD ;else map_type =NO_MAP_UNI_RSVD ;
fs/smb/client/smb2ops.c +2 -2
@@ -1008,7 +1008,7 @@ smb2_is_path_accessible(const unsigned i rc = -EREMOTE ; }if (rc == -EREMOTE &&IS_ENABLED (CONFIG_CIFS_DFS_UPCALL ) && - (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NO_DFS )) + (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NO_DFS )) rc = -EOPNOTSUPP ; goto out; }
@@ -5563,7 +5563,7 @@ static int smb2_make_node(unsigned int x* supports block and char device, socket & fifo, * and was used by default in earlier versions of Windows */ -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_UNX_EMUL ) { +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_UNX_EMUL ) { rc =cifs_sfu_make_node (xid, inode, dentry, tcon, full_path, mode, dev); }else if (CIFS_REPARSE_SUPPORT (tcon)) {
fs/smb/client/smb2pdu.c +2 -2
@@ -3118,7 +3118,7 @@ SMB2_open_init(struct cifs_tcon *tcon, sbool set_mode;bool set_owner; -if ((oparms->cifs_sb->mnt_cifs_flags &CIFS_MOUNT_MODE_FROM_SID ) && +if ((cifs_sb_flags (oparms->cifs_sb) &CIFS_MOUNT_MODE_FROM_SID ) && (oparms->mode !=ACL_NO_MODE )) set_mode = true;else {
@@ -3126,7 +3126,7 @@ SMB2_open_init(struct cifs_tcon *tcon, s oparms->mode =ACL_NO_MODE ; } -if (oparms->cifs_sb->mnt_cifs_flags &CIFS_MOUNT_UID_FROM_ACL ) +if (cifs_sb_flags (oparms->cifs_sb) &CIFS_MOUNT_UID_FROM_ACL ) set_owner = true;else set_owner = false;
fs/smb/client/xattr.c +3 -3
@@ -150,7 +150,7 @@ static int cifs_xattr_set(const struct xbreak ; } -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NO_XATTR ) +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NO_XATTR ) goto out;if (pTcon->ses->server->ops->set_EA) {
@@ -310,7 +310,7 @@ static int cifs_xattr_get(const struct xbreak ; } -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NO_XATTR ) +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NO_XATTR ) goto out;if (pTcon->ses->server->ops->query_all_EAs)
@@ -399,7 +399,7 @@ ssize_t cifs_listxattr(struct dentry *diif (unlikely (cifs_forced_shutdown (cifs_sb)))return -EIO ; -if (cifs_sb->mnt_cifs_flags &CIFS_MOUNT_NO_XATTR ) +if (cifs_sb_flags (cifs_sb) &CIFS_MOUNT_NO_XATTR )return -EOPNOTSUPP ; tlink =cifs_sb_tlink (cifs_sb);
Greg Kroah-Hartman
maintainerPATCH 1246/1250 drm/ttm: Tidy usage of local variables a little bit
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tvrtko Ursulin <[email protected]>
[ Upstream commit c06da4b3573a2d3c906c185450d0b1059d02820e ]
At the moment the TTM code has a few places which exibit sub-optimal patterns regarding local variable usage:
* Having a local with some object cached but not always using it.
* Having a local for a single use object member access.
* Failed opportunities to use a local to cache a pointer.
Lets tidy this a little bit and apply some more consistency.
It is mostly for consistency and redability but I have also checked that there are not negative code generation effects. In fact there are more positives:
add/remove: 0/0 grow/shrink: 3/9 up/down: 12/-175 (-163)
Function old new delta ttm_pool_restore_and_alloc 415 423 +8 ttm_bo_vunmap 147 149 +2 ttm_bo_evict 521 523 +2 ttm_bo_vm_fault_reserved 972 970 -2 ttm_bo_vm_dummy_page 155 152 -3 ttm_bo_vm_fault 203 196 -7 ttm_bo_populate 158 150 -8 ttm_bo_move_memcpy 600 592 -8 ttm_bo_kmap 667 644 -23 ttm_bo_shrink 333 305 -28 ttm_bo_release 750 720 -30 ttm_bo_swapout_cb 691 625 -66
Total: Before=42717, After=42554, chg -0.38%
Stable-dep-of: 941ac10529b3 ("drm/ttm: Drop tt->restore after successful restore")
--- drivers/gpu/drm/ttm/ttm_bo.c | 62 +++++++++++++++++++------------------ drivers/gpu/drm/ttm/ttm_bo_util.c | 47 +++++++++++++--------------- drivers/gpu/drm/ttm/ttm_bo_vm.c | 12 ++----- drivers/gpu/drm/ttm/ttm_pool.c | 26 ++++++++------- drivers/gpu/drm/ttm/ttm_resource.c | 6 +-- 5 files changed, 77 insertions(+), 76 deletions(-)
drivers/gpu/drm/ttm/ttm_bo.c +32 -30
@@ -266,8 +266,8 @@ static void ttm_bo_release(struct kref * 30 * HZ); } -if (bo->bdev->funcs->release_notify) - bo->bdev->funcs->release_notify (bo); +if (bdev->funcs->release_notify) + bdev->funcs->release_notify (bo);drm_vma_offset_remove (bdev->vma_manager, &bo->base.vma_node);ttm_mem_io_free (bdev, bo->resource);
@@ -281,7 +281,7 @@ static void ttm_bo_release(struct kref *ttm_bo_flush_all_fences (bo); bo->deleted = true; -spin_lock (&bo->bdev->lru_lock); +spin_lock (&bdev->lru_lock);/* * Make pinned bos immediately available to
@@ -297,7 +297,7 @@ static void ttm_bo_release(struct kref * }kref_init (&bo->kref); -spin_unlock (&bo->bdev->lru_lock); +spin_unlock (&bdev->lru_lock);INIT_WORK (&bo->delayed_delete, ttm_bo_delayed_delete);
@@ -358,7 +358,6 @@ static int ttm_bo_bounce_temp_buffer(strstatic int ttm_bo_evict (struct ttm_buffer_object *bo,struct ttm_operation_ctx *ctx) { -struct ttm_device *bdev = bo->bdev;struct ttm_resource *evict_mem;struct ttm_placement placement;struct ttm_place hop;
@@ -369,7 +368,7 @@ static int ttm_bo_evict(struct ttm_buffedma_resv_assert_held (bo->base.resv); placement.num_placement =0 ; - bdev->funcs->evict_flags (bo, &placement); + bo->bdev->funcs->evict_flags (bo, &placement);if (!placement.num_placement) { ret =ttm_bo_wait_ctx (bo, ctx);
@@ -422,16 +421,16 @@ bool ttm_bo_eviction_valuable(struct ttm const struct ttm_place *place) {struct ttm_resource *res = bo->resource; -struct ttm_device *bdev = bo->bdev;dma_resv_assert_held (bo->base.resv); -if (bo->resource->mem_type ==TTM_PL_SYSTEM ) + +if (res->mem_type ==TTM_PL_SYSTEM )return true;/* Don't evict this BO if it's outside of the * requested placement range */ -return ttm_resource_intersects (bdev, res, place, bo->base.size); +return ttm_resource_intersects (bo->bdev, res, place, bo->base.size); }EXPORT_SYMBOL (ttm_bo_eviction_valuable);
@@ -1105,10 +1104,13 @@ struct ttm_bo_swapout_walk {static s64 ttm_bo_swapout_cb (struct ttm_lru_walk *walk,struct ttm_buffer_object *bo) { -struct ttm_place place = {.mem_type = bo->resource->mem_type}; +struct ttm_resource *res = bo->resource; +struct ttm_place place = { .mem_type = res->mem_type };struct ttm_bo_swapout_walk *swapout_walk =container_of (walk,typeof (*swapout_walk), walk);struct ttm_operation_ctx *ctx = walk->arg.ctx; +struct ttm_device *bdev = bo->bdev; +struct ttm_tt *tt = bo->ttm;s64 ret;/*
@@ -1117,20 +1119,19 @@ ttm_bo_swapout_cb(struct ttm_lru_walk *w* The driver may use the fact that we're moving from SYSTEM * as an indication that we're about to swap out. */ -if (bo->pin_count || !bo->bdev->funcs->eviction_valuable (bo, &place)) { +if (bo->pin_count || !bdev->funcs->eviction_valuable (bo, &place)) { ret = -EBUSY ; goto out; } -if (!bo->ttm || !ttm_tt_is_populated (bo->ttm) || - bo->ttm->page_flags &TTM_TT_FLAG_EXTERNAL || - bo->ttm->page_flags &TTM_TT_FLAG_SWAPPED ) { +if (!tt || !ttm_tt_is_populated (tt) || + tt->page_flags & (TTM_TT_FLAG_EXTERNAL |TTM_TT_FLAG_SWAPPED )) { ret = -EBUSY ; goto out; }if (bo->deleted) { -pgoff_t num_pages = bo->ttm->num_pages; +pgoff_t num_pages = tt->num_pages; ret =ttm_bo_wait_ctx (bo, ctx);if (ret)
@@ -1144,7 +1145,7 @@ ttm_bo_swapout_cb(struct ttm_lru_walk *w/* * Move to system cached */ -if (bo->resource->mem_type !=TTM_PL_SYSTEM ) { +if (res->mem_type !=TTM_PL_SYSTEM ) {struct ttm_resource *evict_mem;struct ttm_place hop;
@@ -1171,21 +1172,21 @@ ttm_bo_swapout_cb(struct ttm_lru_walk *w goto out;ttm_bo_unmap_virtual (bo); -if (bo->bdev->funcs->swap_notify) - bo->bdev->funcs->swap_notify (bo); +if (bdev->funcs->swap_notify) + bdev->funcs->swap_notify (bo); -if (ttm_tt_is_populated (bo->ttm)) { -spin_lock (&bo->bdev->lru_lock); -ttm_resource_del_bulk_move (bo->resource, bo); -spin_unlock (&bo->bdev->lru_lock); +if (ttm_tt_is_populated (tt)) { +spin_lock (&bdev->lru_lock); +ttm_resource_del_bulk_move (res, bo); +spin_unlock (&bdev->lru_lock); - ret =ttm_tt_swapout (bo->bdev, bo->ttm, swapout_walk->gfp_flags); + ret =ttm_tt_swapout (bdev, tt, swapout_walk->gfp_flags); -spin_lock (&bo->bdev->lru_lock); +spin_lock (&bdev->lru_lock);if (ret) -ttm_resource_add_bulk_move (bo->resource, bo); -ttm_resource_move_to_lru_tail (bo->resource); -spin_unlock (&bo->bdev->lru_lock); +ttm_resource_add_bulk_move (res, bo); +ttm_resource_move_to_lru_tail (res); +spin_unlock (&bdev->lru_lock); } out:
@@ -1258,6 +1259,7 @@ void ttm_bo_tt_destroy(struct ttm_bufferint ttm_bo_populate (struct ttm_buffer_object *bo,struct ttm_operation_ctx *ctx) { +struct ttm_device *bdev = bo->bdev;struct ttm_tt *tt = bo->ttm;bool swapped;int ret;
@@ -1268,16 +1270,16 @@ int ttm_bo_populate(struct ttm_buffer_obreturn 0 ; swapped =ttm_tt_is_swapped (tt); - ret =ttm_tt_populate (bo->bdev, tt, ctx); + ret =ttm_tt_populate (bdev, tt, ctx);if (ret)return ret;if (swapped && !ttm_tt_is_swapped (tt) && !bo->pin_count && bo->resource) { -spin_lock (&bo->bdev->lru_lock); +spin_lock (&bdev->lru_lock);ttm_resource_add_bulk_move (bo->resource, bo);ttm_resource_move_to_lru_tail (bo->resource); -spin_unlock (&bo->bdev->lru_lock); +spin_unlock (&bdev->lru_lock); }return 0 ;
drivers/gpu/drm/ttm/ttm_bo_util.c +23 -24
138 lines not on this page · raw message
drivers/gpu/drm/ttm/ttm_bo_vm.c +5 -7
@@ -186,7 +186,6 @@ vm_fault_t ttm_bo_vm_fault_reserved(stru {struct vm_area_struct *vma = vmf->vma;struct ttm_buffer_object *bo = vma->vm_private_data; -struct ttm_device *bdev = bo->bdev;unsigned long page_offset;unsigned long page_last;unsigned long pfn;
@@ -205,7 +204,7 @@ vm_fault_t ttm_bo_vm_fault_reserved(struif (unlikely (ret !=0 ))return ret; - err =ttm_mem_io_reserve (bdev, bo->resource); + err =ttm_mem_io_reserve (bo->bdev, bo->resource);if (unlikely (err !=0 ))return VM_FAULT_SIGBUS ;
@@ -293,7 +292,6 @@ vm_fault_t ttm_bo_vm_dummy_page(struct v {struct vm_area_struct *vma = vmf->vma;struct ttm_buffer_object *bo = vma->vm_private_data; -struct drm_device *ddev = bo->base.dev;vm_fault_t ret =VM_FAULT_NOPAGE ;unsigned long address;unsigned long pfn;
@@ -305,7 +303,8 @@ vm_fault_t ttm_bo_vm_dummy_page(struct vreturn VM_FAULT_OOM ;/* Set the page to be freed using drmm release action */ -if (drmm_add_action_or_reset (ddev, ttm_bo_release_dummy_page, page)) +if (drmm_add_action_or_reset (bo->base.dev, ttm_bo_release_dummy_page, + page))return VM_FAULT_OOM ; pfn =page_to_pfn (page);
@@ -322,10 +321,9 @@ EXPORT_SYMBOL(ttm_bo_vm_dummy_page);vm_fault_t ttm_bo_vm_fault (struct vm_fault *vmf) {struct vm_area_struct *vma = vmf->vma; -pgprot_t prot;struct ttm_buffer_object *bo = vma->vm_private_data; -struct drm_device *ddev = bo->base.dev;vm_fault_t ret; +pgprot_t prot;int idx; ret =ttm_bo_vm_reserve (bo, vmf);
@@ -333,7 +331,7 @@ vm_fault_t ttm_bo_vm_fault(struct vm_faureturn ret; prot = vma->vm_page_prot; -if (drm_dev_enter (ddev, &idx)) { +if (drm_dev_enter (bo->base.dev, &idx)) { ret =ttm_bo_vm_fault_reserved (vmf, prot,TTM_BO_VM_NUM_PREFAULT );drm_dev_exit (idx); }else {
drivers/gpu/drm/ttm/ttm_pool.c +14 -12
@@ -836,32 +836,34 @@ EXPORT_SYMBOL(ttm_pool_alloc);int ttm_pool_restore_and_alloc (struct ttm_pool *pool,struct ttm_tt *tt,const struct ttm_operation_ctx *ctx) { +struct ttm_pool_tt_restore *restore = tt->restore;struct ttm_pool_alloc_state alloc;if (WARN_ON (!ttm_tt_is_backed_up (tt)))return -EINVAL ; -if (!tt->restore) { +if (!restore) {gfp_t gfp =GFP_KERNEL | __GFP_NOWARN;ttm_pool_alloc_state_init (tt, &alloc);if (ctx->gfp_retry_mayfail) gfp |= __GFP_RETRY_MAYFAIL; - tt->restore =kzalloc (sizeof (*tt->restore), gfp); -if (!tt->restore) + restore =kzalloc (sizeof (*restore), gfp); +if (!restore)return -ENOMEM ; - tt->restore->snapshot_alloc = alloc; - tt->restore->pool = pool; - tt->restore->restored_pages =1 ; - }else { -struct ttm_pool_tt_restore *restore = tt->restore; -int ret; + restore->snapshot_alloc = alloc; + restore->pool = pool; + restore->restored_pages =1 ; + tt->restore = restore; + }else { alloc = restore->snapshot_alloc; -if (ttm_pool_restore_valid (tt->restore)) { - ret =ttm_pool_restore_commit (restore, tt->backup, ctx, &alloc); +if (ttm_pool_restore_valid (restore)) { +int ret =ttm_pool_restore_commit (restore, tt->backup, + ctx, &alloc); +if (ret)return ret; }
@@ -869,7 +871,7 @@ int ttm_pool_restore_and_alloc(struct ttreturn 0 ; } -return __ttm_pool_alloc (pool, tt, ctx, &alloc, tt->restore); +return __ttm_pool_alloc (pool, tt, ctx, &alloc, restore); }/**
drivers/gpu/drm/ttm/ttm_resource.c +3 -3
@@ -620,11 +620,11 @@ ttm_resource_cursor_check_bulk(struct tt struct ttm_lru_item *next_lru) {struct ttm_resource *next =ttm_lru_item_to_res (next_lru); -struct ttm_lru_bulk_move *bulk =NULL ; -struct ttm_buffer_object *bo = next->bo; +struct ttm_lru_bulk_move *bulk;lockdep_assert_held (&cursor->man->bdev->lru_lock); - bulk = bo->bulk_move; + + bulk = next->bo->bulk_move;if (cursor->bulk != bulk) {if (bulk) {
Greg Kroah-Hartman
maintainerPATCH 1247/1250 drm/ttm: Drop tt->restore after successful restore
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Brost <[email protected]>
[ Upstream commit 941ac10529b3be5965a88d432a161ab459672ba8 ]
ttm_pool_restore_and_alloc() can successfully complete the restore process via ttm_pool_restore_commit(), but tt->restore is not dropped afterward. As a result, subsequent backup/restore flows observe what appears to be a completed restore, while in reality shmem handles are still installed in tt->pages, leading to the stack trace below.
Fix this by freeing and dropping tt->restore in ttm_pool_restore_and_alloc() upon successful completion of the restore.
20545 [ 309.784531] RIP: 0010:sg_alloc_append_table_from_pages+0x38c/0x490
20547 [ 309.809570] RSP: 0018:ffffc9000623b838 EFLAGS: 00010206
20548 [ 309.814827] RAX: 0000000000001000 RBX: ffff88816e42a160 RCX: 0000000000000000 20549 [ 309.821986] RDX: 0000000000002000 RSI: 0000000000000003 RDI: 0000000000001000 20550 [ 309.829147] RBP: ffff88816e42a168 R08: 0000000000000002 R09: 000000007ffff000 20551 [ 309.836310] R10: ffffc9000623b928 R11: 0000000000000000 R12: 000000007ffff000 20552 [ 309.843471] R13: ffff88815ba5a100 R14: 0000000000000000 R15: 0000000000000001 20553 [ 309.850634] FS: 00007f9ff305e700(0000) GS:ffff888276c94000(0000) knlGS:0000000000000000 20554 [ 309.858749] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
20555 [ 309.864519] CR2: 00007f9fca701000 CR3: 00000001565e2005 CR4: 0000000008f70ef0 20556 [ 309.871678] PKRU: 55555558
20557 [ 309.874403] Call Trace:
20558 [ 309.876866] <TASK>
20559 [ 309.878988] sg_alloc_table_from_pages_segment+0x60/0x100
20560 [ 309.884415] ? ttm_resource_manager_usage+0x36/0x60 [ttm]
20561 [ 309.889845] ? xe_tt_map_sg+0x7d/0xd0 [xe]
20562 [ 309.894045] xe_tt_map_sg+0x7d/0xd0 [xe]
20563 [ 309.898037] xe_bo_move+0x927/0xaa0 [xe]
20564 [ 309.902029] ttm_bo_handle_move_mem+0xba/0x170 [ttm]
20565 [ 309.907022] ttm_bo_validate+0xbe/0x190 [ttm]
20566 [ 309.911405] xe_bo_validate+0x9a/0x120 [xe]
20567 [ 309.915663] xe_gpuvm_validate+0xd9/0x140 [xe]
20568 [ 309.920206] drm_gpuvm_validate+0x2f0/0x5b0 [drm_gpuvm]
20569 [ 309.925459] ? drm_exec_lock_obj+0x63/0x210 [drm_exec]
20570 [ 309.930627] xe_vm_validate_rebind+0x46/0xb0 [xe]
20571 [ 309.935428] xe_exec_fn+0x20/0x40 [xe]
20572 [ 309.939249] drm_gpuvm_exec_lock+0x78/0xc0 [drm_gpuvm]
20573 [ 309.944410] xe_validation_exec_lock+0x5a/0xa0 [xe]
20574 [ 309.949385] xe_exec_ioctl+0x806/0xc30 [xe]
20575 [ 309.953639] ? ttwu_queue_wakelist+0xd9/0xf0
20576 [ 309.957935] ? __pfx_xe_exec_fn+0x10/0x10 [xe]
20577 [ 309.962449] ? __wake_up_common+0x73/0xa0
20578 [ 309.966482] ? __pfx_xe_exec_ioctl+0x10/0x10 [xe]
20579 [ 309.971263] drm_ioctl_kernel+0xa3/0x100
20580 [ 309.975209] drm_ioctl+0x213/0x440
20581 [ 309.978637] ? __pfx_xe_exec_ioctl+0x10/0x10 [xe]
20582 [ 309.983415] xe_drm_ioctl+0x67/0xd0 [xe]
20583 [ 309.987408] __x64_sys_ioctl+0x7f/0xd0
--- drivers/gpu/drm/ttm/ttm_pool.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-)
drivers/gpu/drm/ttm/ttm_pool.c +12 -3
@@ -838,6 +838,7 @@ int ttm_pool_restore_and_alloc(struct tt {struct ttm_pool_tt_restore *restore = tt->restore;struct ttm_pool_alloc_state alloc; +int ret;if (WARN_ON (!ttm_tt_is_backed_up (tt)))return -EINVAL ;
@@ -861,14 +862,22 @@ int ttm_pool_restore_and_alloc(struct tt }else { alloc = restore->snapshot_alloc;if (ttm_pool_restore_valid (restore)) { -int ret =ttm_pool_restore_commit (restore, tt->backup, - ctx, &alloc); + ret =ttm_pool_restore_commit (restore, tt->backup, + ctx, &alloc);if (ret)return ret; } -if (!alloc.remaining_pages) +if (!alloc.remaining_pages) { + ret =ttm_pool_apply_caching (&alloc); +if (ret) +return ret; + +kfree (tt->restore); + tt->restore =NULL ; +return 0 ; + } }return __ttm_pool_alloc (pool, tt, ctx, &alloc, restore);
Greg Kroah-Hartman
maintainerPATCH 1248/1250 drm/ttm: Fix bo resource use-after-free
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thadeu Lima de Souza Cascardo <[email protected]>
commit 91d7e9df42598af28ca440b95b16a4e51a408771 upstream.
When allocating a lot of buffers and putting the TTM under memory pressure, during swapout, it might crash the system with the stack trace below.
It turns out that ttm_bo_swapout_cb might replace bo->resource when it moves it to system cached.
When commit c06da4b3573a ("drm/ttm: Tidy usage of local variables a little bit") used a local variable for bo->resource, it used the freed resource later in the function, leading to a UAF.
Move back to using bo->resource in all cases in that function instead of a local variable.
[ 604.814275] BUG: kernel NULL pointer dereference, address: 0000000000000000 [ 604.814284] #PF: supervisor read access in kernel mode [ 604.814288] #PF: error_code(0x0000) - not-present page [ 604.814291] PGD 0 P4D 0 [ 604.814296] Oops: Oops: 0000 [#1] SMP NOPTI [ 604.814303] CPU: 2 UID: 0 PID: 4408 Comm: vulkan Tainted: G W 7.0.0-rc2-00001-gc50a051e6aca #21 PREEMPT(full) aef6eb0c02036a7c8a5e62e0c84a30c2be90688d [ 604.814309] Tainted: [W]=WARN [ 604.814311] Hardware name: Valve Jupiter/Jupiter, BIOS F7A0133 08/05/2024 [ 604.814314] RIP: 0010:ttm_resource_move_to_lru_tail+0x100/0x160 [ttm] [ 604.814329] Code: 5b 5d e9 83 b4 1b cb 48 63 d2 48 c1 e0 04 48 8b 4e 40 48 8d 7e 40 48 8b ac d3 d8 00 00 00 48 89 c3 48 8d 54 05 68 48 8b 46 48 <48> 3b 38 0f 85 b3 3b 00 00 48 3b 79 08 0f 85 a9 3b 00 00 48 89 41 [ 604.814332] RSP: 0018:ffffcfe54e3d7578 EFLAGS: 00010256 [ 604.814336] RAX: 0000000000000000 RBX: 0000000000000000 RCX: ffff8cf09eced300 [ 604.814339] RDX: 0000000000000068 RSI: ffff8cf1d4c1fc00 RDI: ffff8cf1d4c1fc40 [ 604.814341] RBP: 0000000000000000 R08: ffff8cf09eced300 R09: 0000000000000000 [ 604.814344] R10: 0000000000000000 R11: 0000000000000016 R12: ffff8cf1d4c1fc00 [ 604.814346] R13: 0000000000000400 R14: ffff8cf096289c00 R15: ffff8cf084c8f688 [ 604.814349] FS: 00007f00531b7780(0000) GS:ffff8cf4217a0000(0000) knlGS:0000000000000000 [ 604.814352] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 604.814355] CR2: 0000000000000000 CR3: 000000018e3df000 CR4: 0000000000350ef0 [ 604.814358] Call Trace: [ 604.814362] <TASK> [ 604.814368] ttm_bo_swapout_cb+0x24c/0x280 [ttm a469cf7fcb6737fdcf3fb5cdbcc8b1ca41f3e302] [ 604.814380] ttm_lru_walk_for_evict+0xac/0x1d0 [ttm a469cf7fcb6737fdcf3fb5cdbcc8b1ca41f3e302] [ 604.814394] ttm_bo_swapout+0x5b/0x80 [ttm a469cf7fcb6737fdcf3fb5cdbcc8b1ca41f3e302] [ 604.814405] ttm_global_swapout+0x63/0x100 [ttm a469cf7fcb6737fdcf3fb5cdbcc8b1ca41f3e302] [ 604.814415] ttm_tt_populate+0x82/0x130 [ttm a469cf7fcb6737fdcf3fb5cdbcc8b1ca41f3e302] [ 604.814424] ttm_bo_populate+0x37/0xa0 [ttm a469cf7fcb6737fdcf3fb5cdbcc8b1ca41f3e302] [ 604.814433] ttm_bo_handle_move_mem+0x157/0x170 [ttm a469cf7fcb6737fdcf3fb5cdbcc8b1ca41f3e302] [ 604.814443] ttm_bo_validate+0xd9/0x180 [ttm a469cf7fcb6737fdcf3fb5cdbcc8b1ca41f3e302] [ 604.814453] ttm_bo_init_reserved+0xa0/0x1b0 [ttm a469cf7fcb6737fdcf3fb5cdbcc8b1ca41f3e302] [ 604.814461] ? srso_return_thunk+0x5/0x5f [ 604.814469] amdgpu_bo_create+0x1f5/0x500 [amdgpu 361516226706227f4403914dbfdd3f90996136ca] [ 604.814855] ? __pfx_amdgpu_bo_user_destroy+0x10/0x10 [amdgpu 361516226706227f4403914dbfdd3f90996136ca] [ 604.815182] amdgpu_bo_create_user+0x3d/0x70 [amdgpu 361516226706227f4403914dbfdd3f90996136ca] [ 604.815504] amdgpu_gem_create_ioctl+0x16c/0x3b0 [amdgpu 361516226706227f4403914dbfdd3f90996136ca] [ 604.815830] ? __pfx_amdgpu_bo_user_destroy+0x10/0x10 [amdgpu 361516226706227f4403914dbfdd3f90996136ca] [ 604.816155] ? __pfx_amdgpu_gem_create_ioctl+0x10/0x10 [amdgpu 361516226706227f4403914dbfdd3f90996136ca] [ 604.816478] drm_ioctl_kernel+0xae/0x100 [ 604.816486] drm_ioctl+0x283/0x510 [ 604.816491] ? __pfx_amdgpu_gem_create_ioctl+0x10/0x10 [amdgpu 361516226706227f4403914dbfdd3f90996136ca] [ 604.816819] amdgpu_drm_ioctl+0x4a/0x80 [amdgpu 361516226706227f4403914dbfdd3f90996136ca] [ 604.817135] __x64_sys_ioctl+0x96/0xe0 [ 604.817142] do_syscall_64+0x11b/0x7e0 [ 604.817148] ? srso_return_thunk+0x5/0x5f [ 604.817152] ? srso_return_thunk+0x5/0x5f [ 604.817156] ? walk_system_ram_range+0xb0/0x110 [ 604.817161] ? srso_return_thunk+0x5/0x5f [ 604.817165] ? __pte_offset_map+0x1b/0xb0 [ 604.817170] ? srso_return_thunk+0x5/0x5f [ 604.817174] ? pte_offset_map_lock+0x87/0xf0 [ 604.817179] ? srso_return_thunk+0x5/0x5f [ 604.817183] ? insert_pfn+0x9f/0x1f0 [ 604.817188] ? srso_return_thunk+0x5/0x5f [ 604.817192] ? vmf_insert_pfn_prot+0x97/0x190 [ 604.817197] ? srso_return_thunk+0x5/0x5f [ 604.817201] ? ttm_bo_vm_fault_reserved+0x1a6/0x3f0 [ttm a469cf7fcb6737fdcf3fb5cdbcc8b1ca41f3e302] [ 604.817213] ? srso_return_thunk+0x5/0x5f [ 604.817217] ? amdgpu_gem_fault+0xe2/0x100 [amdgpu 361516226706227f4403914dbfdd3f90996136ca] [ 604.817542] ? srso_return_thunk+0x5/0x5f [ 604.817546] ? __do_fault+0x33/0x180 [ 604.817550] ? srso_return_thunk+0x5/0x5f [ 604.817554] ? do_fault+0x178/0x610 [ 604.817559] ? srso_return_thunk+0x5/0x5f [ 604.817562] ? __handle_mm_fault+0x9be/0x1120 [ 604.817567] ? srso_return_thunk+0x5/0x5f [ 604.817574] ? srso_return_thunk+0x5/0x5f [ 604.817578] ? count_memcg_events+0xc4/0x160 [ 604.817583] ? srso_return_thunk+0x5/0x5f [ 604.817587] ? handle_mm_fault+0x1d7/0x2e0 [ 604.817593] ? srso_return_thunk+0x5/0x5f [ 604.817596] ? do_user_addr_fault+0x173/0x660 [ 604.817602] ? srso_return_thunk+0x5/0x5f [ 604.817607] entry_SYSCALL_64_after_hwframe+0x76/0x7e [ 604.817612] RIP: 0033:0x7f00532cef4d [ 604.817617] Code: 04 25 28 00 00 00 48 89 45 c8 31 c0 48 8d 45 10 c7 45 b0 10 00 00 00 48 89 45 b8 48 8d 45 d0 48 89 45 c0 b8 10 00 00 00 0f 05 <89> c2 3d 00 f0 ff ff 77 1a 48 8b 45 c8 64 48 2b 04 25 28 00 00 00 [ 604.817620] RSP: 002b:00007ffd69ab0650 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 [ 604.817624] RAX: ffffffffffffffda RBX: 00007ffd69ab07d0 RCX: 00007f00532cef4d [ 604.817627] RDX: 00007ffd69ab0700 RSI: 00000000c0206440 RDI: 0000000000000005 [ 604.817629] RBP: 00007ffd69ab06a0 R08: 00007f00533a0ac0 R09: 0000000000000000 [ 604.817632] R10: 00007ffd69ab07c0 R11: 0000000000000246 R12: 00007ffd69ab0700 [ 604.817634] R13: 00000000c0206440 R14: 0000000000000005 R15: 0000000000000243 [ 604.817642] </TASK>
--- drivers/gpu/drm/ttm/ttm_bo.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-)
drivers/gpu/drm/ttm/ttm_bo.c +5 -6
@@ -1104,8 +1104,7 @@ struct ttm_bo_swapout_walk {static s64 ttm_bo_swapout_cb (struct ttm_lru_walk *walk,struct ttm_buffer_object *bo) { -struct ttm_resource *res = bo->resource; -struct ttm_place place = { .mem_type = res->mem_type }; +struct ttm_place place = { .mem_type = bo->resource->mem_type };struct ttm_bo_swapout_walk *swapout_walk =container_of (walk,typeof (*swapout_walk), walk);struct ttm_operation_ctx *ctx = walk->arg.ctx;
@@ -1145,7 +1144,7 @@ ttm_bo_swapout_cb(struct ttm_lru_walk *w/* * Move to system cached */ -if (res->mem_type !=TTM_PL_SYSTEM ) { +if (bo->resource->mem_type !=TTM_PL_SYSTEM ) {struct ttm_resource *evict_mem;struct ttm_place hop;
@@ -1177,15 +1176,15 @@ ttm_bo_swapout_cb(struct ttm_lru_walk *wif (ttm_tt_is_populated (tt)) {spin_lock (&bdev->lru_lock); -ttm_resource_del_bulk_move (res, bo); +ttm_resource_del_bulk_move (bo->resource, bo);spin_unlock (&bdev->lru_lock); ret =ttm_tt_swapout (bdev, tt, swapout_walk->gfp_flags);spin_lock (&bdev->lru_lock);if (ret) -ttm_resource_add_bulk_move (res, bo); -ttm_resource_move_to_lru_tail (res); +ttm_resource_add_bulk_move (bo->resource, bo); +ttm_resource_move_to_lru_tail (bo->resource);spin_unlock (&bdev->lru_lock); }
Greg Kroah-Hartman
maintainerPATCH 1249/1250 misc: amd-sbi: Add null check for devm_kasprintf()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Griffin Kroah-Hartman <[email protected]>
commit 1bb5c324b872c2e71fa1b12a5f59615b994501da upstream.
Add two checks for devm_kasprintf() errors in create_misc_rmi_device(), returning -ENOMEM if the function failed.
--- drivers/misc/amd-sbi/rmi-core.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/misc/amd-sbi/rmi-core.c +4 -0
@@ -471,6 +471,8 @@ int create_misc_rmi_device(struct sbrmi_GFP_KERNEL ,"sbrmi-%x" , data->dev_static_addr); +if (!data->sbrmi_misc_dev.name) +return -ENOMEM ; data->sbrmi_misc_dev.minor =MISC_DYNAMIC_MINOR ; data->sbrmi_misc_dev.fops = &sbrmi_fops; data->sbrmi_misc_dev.parent = dev;
@@ -478,6 +480,8 @@ int create_misc_rmi_device(struct sbrmi_GFP_KERNEL ,"sbrmi-%x" , data->dev_static_addr); +if (!data->sbrmi_misc_dev.nodename) +return -ENOMEM ; data->sbrmi_misc_dev.mode =0600 ;return misc_register (&data->sbrmi_misc_dev);
Greg Kroah-Hartman
maintainerPATCH 1250/1250 x86/mm: Fix and document DEBUG_PAGEALLOC
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peter Zijlstra <[email protected]>
commit 7da514d819a0afb148634aac92b3d190f34947c3 upstream.
It turns out that commit 5fce67641a3e ("x86/mm/pat: Don't gate cpa_lock on debug_pagealloc_enabled()") was a little too quick to remove the debug_pagealloc exception for cpa_lock.
Notably __kernel_map_pages() is used by the page-allocator from any context the page-allocator itself is used, which violates the cpa_lock rules.
Re-instate the exception, except make it specific to the __kernel_map_pages() such that any other cpa() usage is still fully serialized by cpa_lock. Also note that since cpa() should not be used on memory that isn't allocated, the page-allocator locking and cpa are infact mutually exclusive and all cpa usage in fully serialized.
Add a comment explaining this and other 'funnies' surrounding DEBUG_PAGEALLOC, including how pgd_lock is not affected and the TLB trickery.
--- arch/x86/mm/pat/set_memory.c | 80 +++++++++++++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 22 deletions(-)
arch/x86/mm/pat/set_memory.c +58 -22
@@ -70,11 +70,12 @@ static const int cpa_warn_level = CPA_PR*/ static DEFINE_SPINLOCK (cpa_lock); -#define CPA_FLUSHTLB 1 -#define CPA_ARRAY 2 -#define CPA_PAGES_ARRAY 4 -#define CPA_NO_CHECK_ALIAS 8/* Do not search for aliases */ -#define CPA_COLLAPSE 16/* try to collapse large pages */ +#define CPA_FLUSHTLB 0x01 +#define CPA_ARRAY 0x02 +#define CPA_PAGES_ARRAY 0x04 +#define CPA_NO_CHECK_ALIAS 0x08/* Do not search for aliases */ +#define CPA_COLLAPSE 0x10/* try to collapse large pages */ +#define CPA_DEBUG_PAGEALLOC 0x20static inline pgprot_t cachemode2pgprot (enum page_cache_mode pcm) {
@@ -2014,6 +2015,7 @@ static int __change_page_attr_set_clr(st {unsigned long numpages = cpa->numpages;unsigned long rempages = numpages; +bool lock = true;int ret =0 ;/*
@@ -2023,6 +2025,29 @@ static int __change_page_attr_set_clr(st !cpa->force_split)return ret; +/* +* DEBUG_PAGEALLOC is special; it is called from any context the +* page-allocator is, which violates the normal cpa_lock locking +* rules. +* +* However, since it is part of the page-allocator, things are still +* properly serialized by the page-allocator locking and the fact that +* when a page is owned by the page-allocator, it isn't owned by +* anybody else. That is, you *SHOULD NOT* be calling cpa() on memory +* that isn't allocated. +* +* Additionally, DEBUG_PAGEALLOC ensures (per probe_page_size_mask()) +* that the kernel mapping is 4k pages, therefore there are no large +* pages to split/collapse. +* +* Furthermore, the page-allocator strictly manages pages that +* *exist*, avoiding pgd_lock. +* +* Therefore, it is safe to not take cpa_lock. +*/ +if (debug_pagealloc_enabled () && (cpa->flags &CPA_DEBUG_PAGEALLOC )) + lock = false; +while (rempages) {/* * Store the remaining nr of pages for the large page
@@ -2033,9 +2058,12 @@ static int __change_page_attr_set_clr(stif (cpa->flags & (CPA_ARRAY |CPA_PAGES_ARRAY )) cpa->numpages =1 ; -spin_lock (&cpa_lock); - ret =__change_page_attr (cpa, primary); -spin_unlock (&cpa_lock); +if (lock) { +guard (spinlock)(&cpa_lock); + ret =__change_page_attr (cpa, primary); + }else { + ret =__change_page_attr (cpa, primary); + }if (ret) goto out;
@@ -2631,7 +2659,7 @@ int set_pages_rw(struct page *page, intreturn set_memory_rw (addr, numpages); } -static int __set_pages_p (struct page *page,int numpages) +static int __set_pages_p (struct page *page,int numpages,unsigned int cpa_flags) {unsigned long tempaddr = (unsigned long )page_address (page);struct cpa_data cpa = { .vaddr = &tempaddr,
@@ -2639,7 +2667,7 @@ static int __set_pages_p(struct page *pa .numpages = numpages, .mask_set = __pgprot(_PAGE_PRESENT | _PAGE_RW), .mask_clr = __pgprot(0), - .flags = CPA_NO_CHECK_ALIAS }; + .flags = CPA_NO_CHECK_ALIAS | cpa_flags };/* * No alias checking needed for setting present flag. otherwise,
@@ -2650,7 +2678,7 @@ static int __set_pages_p(struct page *pareturn __change_page_attr_set_clr (&cpa,1 ); } -static int __set_pages_np (struct page *page,int numpages) +static int __set_pages_np (struct page *page,int numpages,unsigned int cpa_flags) {unsigned long tempaddr = (unsigned long )page_address (page);struct cpa_data cpa = { .vaddr = &tempaddr,
@@ -2658,7 +2686,7 @@ static int __set_pages_np(struct page *p .numpages = numpages, .mask_set = __pgprot(0), .mask_clr = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY), - .flags = CPA_NO_CHECK_ALIAS }; + .flags = CPA_NO_CHECK_ALIAS | cpa_flags };/* * No alias checking needed for setting not present flag. otherwise,
@@ -2671,20 +2699,20 @@ static int __set_pages_np(struct page *pint set_direct_map_invalid_noflush (struct page *page) { -return __set_pages_np (page,1 ); +return __set_pages_np (page,1 ,0 ); }int set_direct_map_default_noflush (struct page *page) { -return __set_pages_p (page,1 ); +return __set_pages_p (page,1 ,0 ); }int set_direct_map_valid_noflush (struct page *page,unsigned nr,bool valid) {if (valid) -return __set_pages_p (page, nr); +return __set_pages_p (page, nr,0 ); -return __set_pages_np (page, nr); +return __set_pages_np (page, nr,0 ); }#ifdef CONFIG_DEBUG_PAGEALLOC
@@ -2703,15 +2731,23 @@ void __kernel_map_pages(struct page *pag* and hence no memory allocations during large page split. */ if (enable) -__set_pages_p (page, numpages); +__set_pages_p (page, numpages,CPA_DEBUG_PAGEALLOC );else -__set_pages_np (page, numpages); +__set_pages_np (page, numpages,CPA_DEBUG_PAGEALLOC );/* -* We should perform an IPI and flush all tlbs, -* but that can deadlock->flush only current cpu. -* Preemption needs to be disabled around __flush_tlb_all() due to -* CR3 reload in __native_flush_tlb(). +* We should perform an IPI and flush all tlbs, but that can +* deadlock, settle for a local flush. +* +* Not doing a global TLB flush means that remote CPUs will retain +* stale TLB entries. In case of P->NP (on free) this means the remote +* CPUs will not take the faults, making the debug scheme less +* reliable. On the NP->P (on alloc) this means the remote CPUs can +* take a spurious fault. However spurious_kernel_fault() will observe +* *_present() and fix it up. +* +* Preemption needs to be disabled around __flush_tlb_all() due to CR3 +* reload in __native_flush_tlb(). */ preempt_disable ();__flush_tlb_all ();