6.1.191-rc1 review
Subsystems (12)
Greg Kroah-Hartman
maintainerPATCH 628/1887 fork: defer linking file vma until vma is fully initialized
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Miaohe Lin <[email protected]>
[ Upstream commit 35e351780fa9d8240dd6f7e4f245f9ea37e96c19 ]
Thorvald reported a WARNING [1]. And the root cause is below race:
CPU 1 CPU 2
fork hugetlbfs_fallocate
dup_mmap hugetlbfs_punch_hole
i_mmap_lock_write(mapping);
vma_interval_tree_insert_after -- Child vma is visible through i_mmap tree. i_mmap_unlock_write(mapping);
hugetlb_dup_vma_private -- Clear vma_lock outside i_mmap_rwsem!
i_mmap_lock_write(mapping); hugetlb_vmdelete_list vma_interval_tree_foreach hugetlb_vma_trylock_write -- Vma_lock is cleared. tmp->vm_ops->open -- Alloc new vma_lock outside i_mmap_rwsem! hugetlb_vma_unlock_write -- Vma_lock is assigned!!! i_mmap_unlock_write(mapping);
hugetlb_dup_vma_private() and hugetlb_vm_op_open() are called outside i_mmap_rwsem lock while vma lock can be used in the same time. Fix this by deferring linking file vma until vma is fully initialized. Those vmas should be initialized first before they can be used.
--- kernel/fork.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-)
kernel/fork.c +18 -17
@@ -669,6 +669,24 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm, }else if (anon_vma_fork (tmp, mpnt)) goto fail_nomem_anon_vma_fork; tmp->vm_flags &= ~(VM_LOCKED |VM_LOCKONFAULT ); +/* +* Copy/update hugetlb private vma information. +*/ +if (is_vm_hugetlb_page (tmp)) +hugetlb_dup_vma_private (tmp); + +/* Link the vma into the MT */ + mas.index = tmp->vm_start; + mas.last = tmp->vm_end -1 ; +mas_store (&mas, tmp); +if (mas_is_err (&mas)) + goto fail_nomem_mas_store; + + mm->map_count++; + +if (tmp->vm_ops && tmp->vm_ops->open) + tmp->vm_ops->open (tmp); + file = tmp->vm_file;if (file) {struct address_space *mapping = file->f_mapping;
@@ -685,26 +703,9 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm,i_mmap_unlock_write (mapping); } -/* -* Copy/update hugetlb private vma information. -*/ -if (is_vm_hugetlb_page (tmp)) -hugetlb_dup_vma_private (tmp); - -/* Link the vma into the MT */ - mas.index = tmp->vm_start; - mas.last = tmp->vm_end -1 ; -mas_store (&mas, tmp); -if (mas_is_err (&mas)) - goto fail_nomem_mas_store; - - mm->map_count++;if (!(tmp->vm_flags &VM_WIPEONFORK )) retval =copy_page_range (tmp, mpnt); -if (tmp->vm_ops && tmp->vm_ops->open) - tmp->vm_ops->open (tmp); -if (retval) goto loop_out; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 629/1887 sched/deadline: Fix task_struct reference leak
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wander Lairson Costa <[email protected]>
[ Upstream commit b58652db66c910c2245f5bee7deca41c12d707b9 ]
During the execution of the following stress test with linux-rt:
stress-ng --cyclic 30 --timeout 30 --minimize --quiet
kmemleak frequently reported a memory leak concerning the task_struct:
unreferenced object 0xffff8881305b8000 (size 16136):
comm "stress-ng", pid 614, jiffies 4294883961 (age 286.412s) object hex dump (first 32 bytes):
02 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .@..............
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
debug hex dump (first 16 bytes):
53 09 00 00 00 00 00 00 00 00 00 00 00 00 00 00 S...............
backtrace:
[<00000000046b6790>] dup_task_struct+0x30/0x540
[<00000000c5ca0f0b>] copy_process+0x3d9/0x50e0
[<00000000ced59777>] kernel_clone+0xb0/0x770
[<00000000a50befdc>] __do_sys_clone+0xb6/0xf0
[<000000001dbf2008>] do_syscall_64+0x5d/0xf0
[<00000000552900ff>] entry_SYSCALL_64_after_hwframe+0x6e/0x76The issue occurs in start_dl_timer(), which increments the task_struct reference count and sets a timer. The timer callback, dl_task_timer, is supposed to decrement the reference count upon expiration. However, if enqueue_task_dl() is called before the timer expires and cancels it, the reference count is not decremented, leading to the leak.
This patch fixes the reference leak by ensuring the task_struct reference count is properly decremented when the timer is canceled.
--- kernel/sched/deadline.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
kernel/sched/deadline.c +5 -1
@@ -1689,8 +1689,12 @@ static void enqueue_task_dl(struct rq *rq, struct task_struct *p, int flags)* The replenish timer needs to be canceled. No * problem if it fires concurrently: boosted threads * are ignored in dl_task_timer(). +* +* If the timer callback was running (hrtimer_try_to_cancel == -1), +* it will eventually call put_task_struct(). */ -hrtimer_try_to_cancel (&p->dl.dl_timer); +if (hrtimer_try_to_cancel (&p->dl.dl_timer) ==1 ) +put_task_struct (p); p->dl.dl_throttled =0 ; } }else if (!dl_prio (p->normal_prio)) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 630/1887 f2fs: fix to shrink read extent node in batches
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chao Yu <[email protected]>
[ Upstream commit 3fc5d5a182f6a1f8bd4dc775feb54c369dd2c343 ]
We use rwlock to protect core structure data of extent tree during its shrink, however, if there is a huge number of extent nodes in extent tree, during shrink of extent tree, it may hold rwlock for a very long time, which may trigger kernel hang issue.
This patch fixes to shrink read extent node in batches, so that, critical region of the rwlock can be shrunk to avoid its extreme long time hold.
--- fs/f2fs/extent_cache.c | 67 ++++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 28 deletions(-)
fs/f2fs/extent_cache.c +39 -28
@@ -403,21 +403,22 @@ static struct extent_tree *__grab_extent_tree(struct inode *inode, }static unsigned int __free_extent_tree (struct f2fs_sb_info *sbi, -struct extent_tree *et) +struct extent_tree *et,unsigned int nr_shrink) {struct rb_node *node, *next;struct extent_node *en; -unsigned int count =atomic_read (&et->node_cnt); +unsigned int count; node =rb_first_cached (&et->root); -while (node) { + +for (count =0 ; node && count < nr_shrink; count++) { next =rb_next (node); en = rb_entry(node, struct extent_node, rb_node);__release_extent_node (sbi, et, en); node = next; } -return count -atomic_read (&et->node_cnt); +return count; } static void __drop_largest_extent(struct extent_tree *et,
@@ -611,6 +612,28 @@ static struct extent_node *__insert_extent_tree(struct f2fs_sb_info *sbi,return en; } +static unsigned int __destroy_extent_node (struct inode *inode, +enum extent_type type) +{ +struct f2fs_sb_info *sbi =F2FS_I_SB (inode); +struct extent_tree *et =F2FS_I (inode)->extent_tree[type]; +unsigned int nr_shrink =READ_EXTENT_CACHE_SHRINK_NUMBER ; +unsigned int node_cnt =0 ; + +if (!et || !atomic_read (&et->node_cnt)) +return 0 ; + +while (atomic_read (&et->node_cnt)) { +write_lock (&et->lock); + node_cnt +=__free_extent_tree (sbi, et, nr_shrink); +write_unlock (&et->lock); + } + +f2fs_bug_on (sbi,atomic_read (&et->node_cnt)); + +return node_cnt; +} +static void __update_extent_tree_range (struct inode *inode,struct extent_info *tei,enum extent_type type) {
@@ -740,9 +763,6 @@ static void __update_extent_tree_range(struct inode *inode, } } -if (is_inode_flag_set (inode,FI_NO_EXTENT )) -__free_extent_tree (sbi, et); -if (et->largest_updated) { et->largest_updated = false; updated = true;
@@ -750,6 +770,9 @@ static void __update_extent_tree_range(struct inode *inode,write_unlock (&et->lock); +if (is_inode_flag_set (inode,FI_NO_EXTENT )) +__destroy_extent_node (inode,EX_READ ); +if (updated)f2fs_mark_inode_dirty_sync (inode, true); }
@@ -835,10 +858,14 @@ static unsigned int __shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrinklist_for_each_entry_safe (et, next, &eti->zombie_list, list) {if (atomic_read (&et->node_cnt)) {write_lock (&et->lock); - node_cnt +=__free_extent_tree (sbi, et); + node_cnt +=__free_extent_tree (sbi, et, + nr_shrink - node_cnt - tree_cnt);write_unlock (&et->lock); } -f2fs_bug_on (sbi,atomic_read (&et->node_cnt)); + +if (atomic_read (&et->node_cnt)) + goto unlock_out; +list_del_init (&et->list);radix_tree_delete (&eti->extent_tree_root, et->ino);kmem_cache_free (extent_tree_slab, et);
@@ -929,23 +956,6 @@ unsigned int f2fs_shrink_read_extent_tree(struct f2fs_sb_info *sbi, int nr_shrinreturn __shrink_extent_tree (sbi, nr_shrink,EX_READ ); } -static unsigned int __destroy_extent_node (struct inode *inode, -enum extent_type type) -{ -struct f2fs_sb_info *sbi =F2FS_I_SB (inode); -struct extent_tree *et =F2FS_I (inode)->extent_tree[type]; -unsigned int node_cnt =0 ; - -if (!et || !atomic_read (&et->node_cnt)) -return 0 ; - -write_lock (&et->lock); - node_cnt =__free_extent_tree (sbi, et); -write_unlock (&et->lock); - -return node_cnt; -} -void f2fs_destroy_extent_node (struct inode *inode) {__destroy_extent_node (inode,EX_READ );
@@ -953,7 +963,6 @@ void f2fs_destroy_extent_node(struct inode *inode)static void __drop_extent_tree (struct inode *inode,enum extent_type type) { -struct f2fs_sb_info *sbi =F2FS_I_SB (inode);struct extent_tree *et =F2FS_I (inode)->extent_tree[type];bool updated = false;
@@ -961,7 +970,6 @@ static void __drop_extent_tree(struct inode *inode, enum extent_type type)return ;write_lock (&et->lock); -__free_extent_tree (sbi, et);if (type ==EX_READ ) {set_inode_flag (inode,FI_NO_EXTENT );if (et->largest.len) {
@@ -970,6 +978,9 @@ static void __drop_extent_tree(struct inode *inode, enum extent_type type) } }write_unlock (&et->lock); + +__destroy_extent_node (inode, type); +if (updated)f2fs_mark_inode_dirty_sync (inode, true); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 631/1887 drm/amdgpu: fix double free err_addr pointer warnings
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bob Zhou <[email protected]>
[ Upstream commit 506c245f3f1cd989cb89811a7f06e04ff8813a0d ]
In amdgpu_umc_bad_page_polling_timeout, the amdgpu_umc_handle_bad_pages will be run many times so that double free err_addr in some special case. So set the err_addr to NULL to avoid the warnings.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c +1 -0
@@ -109,6 +109,7 @@ static int amdgpu_umc_do_page_retirement(struct amdgpu_device *adev, }kfree (err_data->err_addr); + err_data->err_addr =NULL ;return AMDGPU_RAS_SUCCESS ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 632/1887 leds: an30259a: Use devm_mutex_init() for mutex initialization
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: George Stark <[email protected]>
[ Upstream commit c382e2e3eccb6b7ca8c7aff5092c1668428e7de6 ]
In this driver LEDs are registered using devm_led_classdev_register() so they are automatically unregistered after module's remove() is done. led_classdev_unregister() calls module's led_set_brightness() to turn off the LEDs and that callback uses mutex which was destroyed already in module's remove() so use devm API instead.
--- drivers/leds/leds-an30259a.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-)
drivers/leds/leds-an30259a.c +4 -10
@@ -296,7 +296,10 @@ static int an30259a_probe(struct i2c_client *client)if (err <0 )return err; -mutex_init (&chip->mutex); + err =devm_mutex_init (&client->dev, &chip->mutex); +if (err) +return err; + chip->client = client;i2c_set_clientdata (client, chip);
@@ -330,17 +333,9 @@ static int an30259a_probe(struct i2c_client *client)return 0 ; exit: -mutex_destroy (&chip->mutex);return err; } -static void an30259a_remove (struct i2c_client *client) -{ -struct an30259a *chip =i2c_get_clientdata (client); - -mutex_destroy (&chip->mutex); -} -static const struct of_device_id an30259a_match_table[] = { { .compatible ="panasonic,an30259a" , }, {/* sentinel */ },
@@ -360,7 +355,6 @@ static struct i2c_driver an30259a_driver = { .of_match_table = of_match_ptr(an30259a_match_table), }, .probe_new = an30259a_probe, - .remove = an30259a_remove, .id_table = an30259a_id, };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 633/1887 ice: Fix improper extts handling
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Milena Olech <[email protected]>
[ Upstream commit 00d3b4f54582d4e4a02cda5886bb336eeab268cc ]
Extts events are disabled and enabled by the application ts2phc. However, in case where the driver is removed when the application is running, a specific extts event remains enabled and can cause a kernel crash.
As a side effect, when the driver is reloaded and application is started again, remaining extts event for the channel from a previous run will keep firing and the message "extts on unexpected channel" might be printed to the user.
To avoid that, extts events shall be disabled when PTP is released.
--- drivers/net/ethernet/intel/ice/ice_ptp.c | 66 +++++++++++++++++------- drivers/net/ethernet/intel/ice/ice_ptp.h | 8 +++ 2 files changed, 56 insertions(+), 18 deletions(-)
drivers/net/ethernet/intel/ice/ice_ptp.c +48 -18
@@ -1513,27 +1513,24 @@ void ice_ptp_extts_event(struct ice_pf *pf)/** * ice_ptp_cfg_extts - Configure EXTTS pin and channel * @pf: Board private structure -* @ena: true to enable; false to disable * @chan: GPIO channel (0-3) -* @gpio_pin: GPIO pin -* @extts_flags: request flags from the ptp_extts_request.flags +* @config: desired EXTTS configuration. +* @store: If set to true, the values will be stored +* +* Configure an external timestamp event on the requested channel. */ -static int -ice_ptp_cfg_extts (struct ice_pf *pf,bool ena,unsigned int chan,u32 gpio_pin, -unsigned int extts_flags) +static void ice_ptp_cfg_extts (struct ice_pf *pf,unsigned int chan, +struct ice_extts_channel *config,bool store) {u32 func, aux_reg, gpio_reg, irq_reg;struct ice_hw *hw = &pf->hw;u8 tmr_idx; -if (chan > (unsigned int )pf->ptp.info.n_ext_ts) -return -EINVAL ; - tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; irq_reg =rd32 (hw,PFINT_OICR_ENA ); -if (ena) { +if (config->ena) {/* Enable the interrupt */ irq_reg |=PFINT_OICR_TSYN_EVNT_M ; aux_reg =GLTSYN_AUX_IN_0_INT_ENA_M ;
@@ -1542,9 +1539,9 @@ ice_ptp_cfg_extts(struct ice_pf *pf, bool ena, unsigned int chan, u32 gpio_pin,#define GLTSYN_AUX_IN_0_EVNTLVL_FALLING_EDGE BIT(1)/* set event level to requested edge */ -if (extts_flags &PTP_FALLING_EDGE ) +if (config->flags &PTP_FALLING_EDGE ) aux_reg |=GLTSYN_AUX_IN_0_EVNTLVL_FALLING_EDGE ; -if (extts_flags &PTP_RISING_EDGE ) +if (config->flags &PTP_RISING_EDGE ) aux_reg |=GLTSYN_AUX_IN_0_EVNTLVL_RISING_EDGE ;/* Write GPIO CTL reg.
@@ -1566,9 +1563,30 @@ ice_ptp_cfg_extts(struct ice_pf *pf, bool ena, unsigned int chan, u32 gpio_pin,wr32 (hw,PFINT_OICR_ENA , irq_reg);wr32 (hw,GLTSYN_AUX_IN (chan, tmr_idx), aux_reg); -wr32 (hw,GLGEN_GPIO_CTL (gpio_pin), gpio_reg); +wr32 (hw,GLGEN_GPIO_CTL (config->gpio_pin), gpio_reg); -return 0 ; +if (store) +memcpy (&pf->ptp.extts_channels[chan], config,sizeof (*config)); +} + +/** +* ice_ptp_disable_all_extts - Disable all EXTTS channels +* @pf: Board private structure +*/ +static void ice_ptp_disable_all_extts (struct ice_pf *pf) +{ +struct ice_extts_channel extts_cfg = {}; +int i; + +for (i =0 ; i < pf->ptp.info.n_ext_ts; i++) { +if (pf->ptp.extts_channels[i].ena) { + extts_cfg.gpio_pin = pf->ptp.extts_channels[i].gpio_pin; + extts_cfg.ena = false; +ice_ptp_cfg_extts (pf, i, &extts_cfg, false); + } + } + +synchronize_irq (pf->msix_entries[pf->oicr_idx].vector); }/**
@@ -1725,7 +1743,6 @@ ice_ptp_gpio_enable_e810(struct ptp_clock_info *info, struct ptp_clock_request *rq, int on) {struct ice_pf *pf =ptp_info_to_pf (info); -struct ice_perout_channel clk_cfg = {0 };bool sma_pres = false;unsigned int chan;u32 gpio_pin;
@@ -1736,6 +1753,9 @@ ice_ptp_gpio_enable_e810(struct ptp_clock_info *info,switch (rq->type) {case PTP_CLK_REQ_PEROUT : + { +struct ice_perout_channel clk_cfg = {}; + chan = rq->perout.index;if (sma_pres) {if (chan == ice_pin_desc_e810t[SMA1 ].chan)
@@ -1763,7 +1783,11 @@ ice_ptp_gpio_enable_e810(struct ptp_clock_info *info, err =ice_ptp_cfg_clkout (pf, chan, &clk_cfg, true);break ; + }case PTP_CLK_REQ_EXTTS : + { +struct ice_extts_channel extts_cfg = {}; + chan = rq->extts.index;if (sma_pres) {if (chan < ice_pin_desc_e810t[SMA2 ].chan)
@@ -1779,9 +1803,13 @@ ice_ptp_gpio_enable_e810(struct ptp_clock_info *info, gpio_pin = chan; } - err =ice_ptp_cfg_extts (pf, !!on, chan, gpio_pin, - rq->extts.flags); -break ; + extts_cfg.flags = rq->extts.flags; + extts_cfg.gpio_pin = gpio_pin; + extts_cfg.ena = !!on; + +ice_ptp_cfg_extts (pf, chan, &extts_cfg, true); +return 0 ; + }default :return -EOPNOTSUPP ; }
@@ -2711,6 +2739,8 @@ void ice_ptp_release(struct ice_pf *pf)clear_bit (ICE_FLAG_PTP , pf->flags); +ice_ptp_disable_all_extts (pf); +kthread_cancel_delayed_work_sync (&pf->ptp.work);ice_ptp_port_phy_stop (&pf->ptp.port);
drivers/net/ethernet/intel/ice/ice_ptp.h +8 -0
@@ -33,6 +33,12 @@ struct ice_perout_channel {u64 start_time; }; +struct ice_extts_channel { +bool ena; +u32 gpio_pin; +u32 flags; +}; +/* The ice hardware captures Tx hardware timestamps in the PHY. The timestamp * is stored in a buffer of registers. Depending on the specific hardware, * this buffer might be shared across multiple PHY ports.
@@ -165,6 +171,7 @@ struct ice_ptp_port {* @ext_ts_irq: the external timestamp IRQ in use * @kworker: kwork thread for handling periodic work * @perout_channels: periodic output data +* @extts_channels: channels for external timestamps * @info: structure defining PTP hardware capabilities * @clock: pointer to registered PTP clock device * @tstamp_config: hardware timestamping configuration
@@ -185,6 +192,7 @@ struct ice_ptp {u8 ext_ts_irq;struct kthread_worker *kworker;struct ice_perout_channel perout_channels[GLTSYN_TGT_H_IDX_MAX ]; +struct ice_extts_channel extts_channels[GLTSYN_TGT_H_IDX_MAX ];struct ptp_clock_info info;struct ptp_clock *clock;struct hwtstamp_config tstamp_config;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 634/1887 s390/pkey: Wipe copies of protected- and secure-keys
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Holger Dengler <[email protected]>
[ Upstream commit f2ebdadd85af4f4d0cae1e5d009c70eccc78c207 ]
Although the clear-key of neither protected- nor secure-keys is accessible, this key material should only be visible to the calling process. So wipe all copies of protected- or secure-keys from stack, even in case of an error.
--- drivers/s390/crypto/pkey_api.c | 80 ++++++++++++++++------------------ 1 file changed, 37 insertions(+), 43 deletions(-)
drivers/s390/crypto/pkey_api.c +37 -43
@@ -1173,10 +1173,9 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, rc =cca_genseckey (kgs.cardnr, kgs.domain, kgs.keytype, kgs.seckey.seckey);DEBUG_DBG ("%s cca_genseckey()=%d\n" , __func__, rc); -if (rc) -break ; -if (copy_to_user (ugs, &kgs,sizeof (kgs))) -return -EFAULT ; +if (!rc &©_to_user (ugs, &kgs,sizeof (kgs))) + rc = -EFAULT ; +memzero_explicit (&kgs,sizeof (kgs));break ; }case PKEY_CLR2SECK : {
@@ -1205,10 +1204,9 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, ksp.seckey.seckey, ksp.protkey.protkey, &ksp.protkey.len, &ksp.protkey.type);DEBUG_DBG ("%s cca_sec2protkey()=%d\n" , __func__, rc); -if (rc) -break ; -if (copy_to_user (usp, &ksp,sizeof (ksp))) -return -EFAULT ; +if (!rc &©_to_user (usp, &ksp,sizeof (ksp))) + rc = -EFAULT ; +memzero_explicit (&ksp,sizeof (ksp));break ; }case PKEY_CLR2PROTK : {
@@ -1250,10 +1248,9 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,return -EFAULT ; rc =pkey_skey2pkey (ksp.seckey.seckey, &ksp.protkey);DEBUG_DBG ("%s pkey_skey2pkey()=%d\n" , __func__, rc); -if (rc) -break ; -if (copy_to_user (usp, &ksp,sizeof (ksp))) -return -EFAULT ; +if (!rc &©_to_user (usp, &ksp,sizeof (ksp))) + rc = -EFAULT ; +memzero_explicit (&ksp,sizeof (ksp));break ; }case PKEY_VERIFYKEY : {
@@ -1265,10 +1262,9 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, rc =pkey_verifykey (&kvk.seckey, &kvk.cardnr, &kvk.domain, &kvk.keysize, &kvk.attributes);DEBUG_DBG ("%s pkey_verifykey()=%d\n" , __func__, rc); -if (rc) -break ; -if (copy_to_user (uvk, &kvk,sizeof (kvk))) -return -EFAULT ; +if (!rc &©_to_user (uvk, &kvk,sizeof (kvk))) + rc = -EFAULT ; +memzero_explicit (&kvk,sizeof (kvk));break ; }case PKEY_GENPROTK : {
@@ -1279,10 +1275,9 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,return -EFAULT ; rc =pkey_genprotkey (kgp.keytype, &kgp.protkey);DEBUG_DBG ("%s pkey_genprotkey()=%d\n" , __func__, rc); -if (rc) -break ; -if (copy_to_user (ugp, &kgp,sizeof (kgp))) -return -EFAULT ; +if (!rc &©_to_user (ugp, &kgp,sizeof (kgp))) + rc = -EFAULT ; +memzero_explicit (&kgp,sizeof (kgp));break ; }case PKEY_VERIFYPROTK : {
@@ -1293,6 +1288,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,return -EFAULT ; rc =pkey_verifyprotkey (&kvp.protkey);DEBUG_DBG ("%s pkey_verifyprotkey()=%d\n" , __func__, rc); +memzero_explicit (&kvp,sizeof (kvp));break ; }case PKEY_KBLOB2PROTK : {
@@ -1309,10 +1305,9 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,DEBUG_DBG ("%s pkey_keyblob2pkey()=%d\n" , __func__, rc);memzero_explicit (kkey, ktp.keylen);kfree (kkey); -if (rc) -break ; -if (copy_to_user (utp, &ktp,sizeof (ktp))) -return -EFAULT ; +if (!rc &©_to_user (utp, &ktp,sizeof (ktp))) + rc = -EFAULT ; +memzero_explicit (&ktp,sizeof (ktp));break ; }case PKEY_GENSECK2 : {
@@ -1338,23 +1333,23 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,DEBUG_DBG ("%s pkey_genseckey2()=%d\n" , __func__, rc);kfree (apqns);if (rc) { -kfree (kkey); +kfree_sensitive (kkey);break ; }if (kgs.key) {if (kgs.keylen < klen) { -kfree (kkey); +kfree_sensitive (kkey);return -EINVAL ; }if (copy_to_user (kgs.key, kkey, klen)) { -kfree (kkey); +kfree_sensitive (kkey);return -EFAULT ; } } kgs.keylen = klen;if (copy_to_user (ugs, &kgs,sizeof (kgs))) rc = -EFAULT ; -kfree (kkey); +kfree_sensitive (kkey);break ; }case PKEY_CLR2SECK2 : {
@@ -1380,16 +1375,16 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,DEBUG_DBG ("%s pkey_clr2seckey2()=%d\n" , __func__, rc);kfree (apqns);if (rc) { -kfree (kkey); +kfree_sensitive (kkey);break ; }if (kcs.key) {if (kcs.keylen < klen) { -kfree (kkey); +kfree_sensitive (kkey);return -EINVAL ; }if (copy_to_user (kcs.key, kkey, klen)) { -kfree (kkey); +kfree_sensitive (kkey);return -EFAULT ; } }
@@ -1397,7 +1392,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,if (copy_to_user (ucs, &kcs,sizeof (kcs))) rc = -EFAULT ;memzero_explicit (&kcs,sizeof (kcs)); -kfree (kkey); +kfree_sensitive (kkey);break ; }case PKEY_VERIFYKEY2 : {
@@ -1414,7 +1409,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, &kvk.cardnr, &kvk.domain, &kvk.type, &kvk.size, &kvk.flags);DEBUG_DBG ("%s pkey_verifykey2()=%d\n" , __func__, rc); -kfree (kkey); +kfree_sensitive (kkey);if (rc)break ;if (copy_to_user (uvk, &kvk,sizeof (kvk)))
@@ -1443,10 +1438,9 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,kfree (apqns);memzero_explicit (kkey, ktp.keylen);kfree (kkey); -if (rc) -break ; -if (copy_to_user (utp, &ktp,sizeof (ktp))) -return -EFAULT ; +if (!rc &©_to_user (utp, &ktp,sizeof (ktp))) + rc = -EFAULT ; +memzero_explicit (&ktp,sizeof (ktp));break ; }case PKEY_APQNS4K : {
@@ -1474,7 +1468,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, rc =pkey_apqns4key (kkey, kak.keylen, kak.flags, apqns, &nr_apqns);DEBUG_DBG ("%s pkey_apqns4key()=%d\n" , __func__, rc); -kfree (kkey); +kfree_sensitive (kkey);if (rc && rc != -ENOSPC ) {kfree (apqns);break ;
@@ -1560,7 +1554,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, protkey =kmalloc (protkeylen,GFP_KERNEL );if (!protkey) {kfree (apqns); -kfree (kkey); +kfree_sensitive (kkey);return -ENOMEM ; } rc = pkey_keyblob2pkey3(apqns, ktp.apqn_entries, kkey,
@@ -1571,20 +1565,20 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,memzero_explicit (kkey, ktp.keylen);kfree (kkey);if (rc) { -kfree (protkey); +kfree_sensitive (protkey);break ; }if (ktp.pkey && ktp.pkeylen) {if (protkeylen > ktp.pkeylen) { -kfree (protkey); +kfree_sensitive (protkey);return -EINVAL ; }if (copy_to_user (ktp.pkey, protkey, protkeylen)) { -kfree (protkey); +kfree_sensitive (protkey);return -EFAULT ; } } -kfree (protkey); +kfree_sensitive (protkey); ktp.pkeylen = protkeylen;if (copy_to_user (utp, &ktp,sizeof (ktp)))return -EFAULT ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 635/1887 s390/pkey: Wipe copies of clear-key structures on failure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Holger Dengler <[email protected]>
[ Upstream commit d65d76a44ffe74c73298ada25b0f578680576073 ]
Wipe all sensitive data from stack for all IOCTLs, which convert a clear-key into a protected- or secure-key.
--- drivers/s390/crypto/pkey_api.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-)
drivers/s390/crypto/pkey_api.c +9 -7
@@ -1187,9 +1187,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, rc =cca_clr2seckey (kcs.cardnr, kcs.domain, kcs.keytype, kcs.clrkey.clrkey, kcs.seckey.seckey);DEBUG_DBG ("%s cca_clr2seckey()=%d\n" , __func__, rc); -if (rc) -break ; -if (copy_to_user (ucs, &kcs,sizeof (kcs))) +if (!rc &©_to_user (ucs, &kcs,sizeof (kcs))) rc = -EFAULT ;memzero_explicit (&kcs,sizeof (kcs));break ;
@@ -1218,9 +1216,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, rc =pkey_clr2protkey (kcp.keytype, &kcp.clrkey, &kcp.protkey);DEBUG_DBG ("%s pkey_clr2protkey()=%d\n" , __func__, rc); -if (rc) -break ; -if (copy_to_user (ucp, &kcp,sizeof (kcp))) +if (!rc &©_to_user (ucp, &kcp,sizeof (kcp))) rc = -EFAULT ;memzero_explicit (&kcp,sizeof (kcp));break ;
@@ -1362,11 +1358,14 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,if (copy_from_user (&kcs, ucs,sizeof (kcs)))return -EFAULT ; apqns =_copy_apqns_from_user (kcs.apqns, kcs.apqn_entries); -if (IS_ERR (apqns)) +if (IS_ERR (apqns)) { +memzero_explicit (&kcs,sizeof (kcs));return PTR_ERR (apqns); + } kkey =kzalloc (klen,GFP_KERNEL );if (!kkey) {kfree (apqns); +memzero_explicit (&kcs,sizeof (kcs));return -ENOMEM ; } rc = pkey_clr2seckey2(apqns, kcs.apqn_entries,
@@ -1376,15 +1375,18 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,kfree (apqns);if (rc) {kfree_sensitive (kkey); +memzero_explicit (&kcs,sizeof (kcs));break ; }if (kcs.key) {if (kcs.keylen < klen) {kfree_sensitive (kkey); +memzero_explicit (&kcs,sizeof (kcs));return -EINVAL ; }if (copy_to_user (kcs.key, kkey, klen)) {kfree_sensitive (kkey); +memzero_explicit (&kcs,sizeof (kcs));return -EFAULT ; } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 636/1887 s390/pkey: Use kfree_sensitive() to fix Coccinelle warnings
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jules Irenge <[email protected]>
[ Upstream commit 22e6824622e8a8889df0f8fc4ed5aea0e702a694 ]
Replace memzero_explicit() and kfree() with kfree_sensitive() to fix warnings reported by Coccinelle:
WARNING opportunity for kfree_sensitive/kvfree_sensitive (line 1506) WARNING opportunity for kfree_sensitive/kvfree_sensitive (line 1643) WARNING opportunity for kfree_sensitive/kvfree_sensitive (line 1770)
--- drivers/s390/crypto/pkey_api.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-)
drivers/s390/crypto/pkey_api.c +3 -6
@@ -1299,8 +1299,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,return PTR_ERR (kkey); rc =pkey_keyblob2pkey (kkey, ktp.keylen, &ktp.protkey);DEBUG_DBG ("%s pkey_keyblob2pkey()=%d\n" , __func__, rc); -memzero_explicit (kkey, ktp.keylen); -kfree (kkey); +kfree_sensitive (kkey);if (!rc &©_to_user (utp, &ktp,sizeof (ktp))) rc = -EFAULT ;memzero_explicit (&ktp,sizeof (ktp));
@@ -1438,8 +1437,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, kkey, ktp.keylen, &ktp.protkey);DEBUG_DBG ("%s pkey_keyblob2pkey2()=%d\n" , __func__, rc);kfree (apqns); -memzero_explicit (kkey, ktp.keylen); -kfree (kkey); +kfree_sensitive (kkey);if (!rc &©_to_user (utp, &ktp,sizeof (ktp))) rc = -EFAULT ;memzero_explicit (&ktp,sizeof (ktp));
@@ -1564,8 +1562,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, protkey, &protkeylen);DEBUG_DBG ("%s pkey_keyblob2pkey3()=%d\n" , __func__, rc);kfree (apqns); -memzero_explicit (kkey, ktp.keylen); -kfree (kkey); +kfree_sensitive (kkey);if (rc) {kfree_sensitive (protkey);break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 637/1887 filemap: add helper mapping_max_folio_size()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Yang <[email protected]>
[ Upstream commit 79c137454815ba5554caa8eeb4ad5c94e96e45ce ]
Add mapping_max_folio_size() to get the maximum folio size for this pagecache mapping.
Stable-dep-of: 099d90642a71 ("mm/filemap: make MAX_PAGECACHE_ORDER acceptable to xarray")
--- include/linux/pagemap.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)
include/linux/pagemap.h +21 -0
@@ -325,6 +325,19 @@ static inline void mapping_set_gfp_mask(struct address_space *m, gfp_t mask) m->gfp_mask = mask; } +/* +* There are some parts of the kernel which assume that PMD entries +* are exactly HPAGE_PMD_ORDER. Those should be fixed, but until then, +* limit the maximum allocation order to PMD size. I'm not aware of any +* assumptions about maximum order if THP are disabled, but 8 seems like +* a good order (that's 1MB if you're using 4kB pages) +*/ +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +#define MAX_PAGECACHE_ORDER HPAGE_PMD_ORDER +#else +#define MAX_PAGECACHE_ORDER 8 +#endif +/** * mapping_set_large_folios() - Indicate the file supports large folios. * @mapping: The file.
@@ -351,6 +364,14 @@ static inline bool mapping_large_folio_support(struct address_space *mapping)test_bit (AS_LARGE_FOLIO_SUPPORT , &mapping->flags); } +/* Return the maximum folio size for this pagecache mapping, in bytes. */ +static inline size_t mapping_max_folio_size (struct address_space *mapping) +{ +if (mapping_large_folio_support (mapping)) +return PAGE_SIZE <<MAX_PAGECACHE_ORDER ; +return PAGE_SIZE ; +} +static inline int filemap_nr_thps (struct address_space *mapping) {#ifdef CONFIG_READ_ONLY_THP_FOR_FS
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 638/1887 mm/filemap: make MAX_PAGECACHE_ORDER acceptable to xarray
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gavin Shan <[email protected]>
[ Upstream commit 099d90642a711caae377f53309abfe27e8724a8b ]
Patch series "mm/filemap: Limit page cache size to that supported by xarray", v2.
Currently, xarray can't support arbitrary page cache size. More details can be found from the WARN_ON() statement in xas_split_alloc(). In our test whose code is attached below, we hit the WARN_ON() on ARM64 system where the base page size is 64KB and huge page size is 512MB. The issue was reported long time ago and some discussions on it can be found here [1].
[1] https://www.spinics.net/lists/linux-xfs/msg75404.html
In order to fix the issue, we need to adjust MAX_PAGECACHE_ORDER to one supported by xarray and avoid PMD-sized page cache if needed. The code changes are suggested by David Hildenbrand.
PATCH[1] adjusts MAX_PAGECACHE_ORDER to that supported by xarray PATCH[2-3] avoids PMD-sized page cache in the synchronous readahead path PATCH[4] avoids PMD-sized page cache for shmem files if needed
Test program
============
# cat test.c #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <fcntl.h> #include <errno.h> #include <sys/syscall.h> #include <sys/mman.h>
#define TEST_XFS_FILENAME "/tmp/data"
#define TEST_SHMEM_FILENAME "/dev/shm/data"
#define TEST_MEM_SIZE 0x20000000
int main(int argc, char **argv)
{
const char *filename;
int fd = 0;
void *buf = (void *)-1, *p;
int pgsize = getpagesize();
int ret;
if (pgsize != 0x10000) {
fprintf(stderr, "64KB base page size is required\n");
return -EPERM;
}
system("echo force > /sys/kernel/mm/transparent_hugepage/shmem_enabled");
system("rm -fr /tmp/data");
system("rm -fr /dev/shm/data");
system("echo 1 > /proc/sys/vm/drop_caches");
/* Open xfs or shmem file */
filename = TEST_XFS_FILENAME;
if (argc > 1 && !strcmp(argv[1], "shmem"))
filename = TEST_SHMEM_FILENAME;
fd = open(filename, O_CREAT | O_RDWR | O_TRUNC);
if (fd < 0) {
fprintf(stderr, "Unable to open <%s>\n", filename);
return -EIO;
}
/* Extend file size */
ret = ftruncate(fd, TEST_MEM_SIZE);
if (ret) {
fprintf(stderr, "Error %d to ftruncate()\n", ret);
goto cleanup;
}
/* Create VMA */
buf = mmap(NULL, TEST_MEM_SIZE,
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (buf == (void *)-1) {
fprintf(stderr, "Unable to mmap <%s>\n", filename);
goto cleanup;
}
fprintf(stdout, "mapped buffer at 0x%p\n", buf);
ret = madvise(buf, TEST_MEM_SIZE, MADV_HUGEPAGE);
if (ret) {
fprintf(stderr, "Unable to madvise(MADV_HUGEPAGE)\n");
goto cleanup;
}
/* Populate VMA */
ret = madvise(buf, TEST_MEM_SIZE, MADV_POPULATE_WRITE);
if (ret) {
fprintf(stderr, "Error %d to madvise(MADV_POPULATE_WRITE)\n", ret);
goto cleanup;
}
/* Punch the file to enforce xarray split */
ret = fallocate(fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
TEST_MEM_SIZE - pgsize, pgsize);
if (ret)
fprintf(stderr, "Error %d to fallocate()\n", ret);cleanup:
if (buf != (void *)-1) munmap(buf, TEST_MEM_SIZE); if (fd > 0) close(fd); return 0; }
# gcc test.c -o test # cat /proc/1/smaps | grep KernelPageSize | head -n 1 KernelPageSize: 64 kB # ./test shmem : ------------[ cut here ]------------ WARNING: CPU: 17 PID: 5253 at lib/xarray.c:1025 xas_split_alloc+0xf8/0x128 Modules linked in: nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib \ nft_reject_inet nf_reject_ipv4 nf_reject_ipv6 nft_reject nft_ct \ nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 \ ip_set nf_tables rfkill nfnetlink vfat fat virtio_balloon \ drm fuse xfs libcrc32c crct10dif_ce ghash_ce sha2_ce sha256_arm64 \ virtio_net sha1_ce net_failover failover virtio_console virtio_blk \ dimlib virtio_mmio CPU: 17 PID: 5253 Comm: test Kdump: loaded Tainted: G W 6.10.0-rc5-gavin+ #12 Hardware name: QEMU KVM Virtual Machine, BIOS edk2-20240524-1.el9 05/24/2024 pstate: 83400005 (Nzcv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--) pc : xas_split_alloc+0xf8/0x128 lr : split_huge_page_to_list_to_order+0x1c4/0x720 sp : ffff80008a92f5b0 x29: ffff80008a92f5b0 x28: ffff80008a92f610 x27: ffff80008a92f728 x26: 0000000000000cc0 x25: 000000000000000d x24: ffff0000cf00c858 x23: ffff80008a92f610 x22: ffffffdfc0600000 x21: 0000000000000000 x20: 0000000000000000 x19: ffffffdfc0600000 x18: 0000000000000000 x17: 0000000000000000 x16: 0000018000000000 x15: 3374004000000000 x14: 0000e00000000000 x13: 0000000000002000 x12: 0000000000000020 x11: 3374000000000000 x10: 3374e1c0ffff6000 x9 : ffffb463a84c681c x8 : 0000000000000003 x7 : 0000000000000000 x6 : ffff00011c976ce0 x5 : ffffb463aa47e378 x4 : 0000000000000000 x3 : 0000000000000cc0 x2 : 000000000000000d x1 : 000000000000000c x0 : 0000000000000000 Call trace: xas_split_alloc+0xf8/0x128 split_huge_page_to_list_to_order+0x1c4/0x720 truncate_inode_partial_folio+0xdc/0x160 shmem_undo_range+0x2bc/0x6a8 shmem_fallocate+0x134/0x430 vfs_fallocate+0x124/0x2e8 ksys_fallocate+0x4c/0xa0 __arm64_sys_fallocate+0x24/0x38 invoke_syscall.constprop.0+0x7c/0xd8 do_el0_svc+0xb4/0xd0 el0_svc+0x44/0x1d8 el0t_64_sync_handler+0x134/0x150 el0t_64_sync+0x17c/0x180
This patch (of 4):
The largest page cache order can be HPAGE_PMD_ORDER (13) on ARM64 with 64KB base page size. The xarray entry with this order can't be split as the following error messages indicate.
------------[ cut here ]------------ WARNING: CPU: 35 PID: 7484 at lib/xarray.c:1025 xas_split_alloc+0xf8/0x128 Modules linked in: nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib \ nft_reject_inet nf_reject_ipv4 nf_reject_ipv6 nft_reject nft_ct \ nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 \ ip_set rfkill nf_tables nfnetlink vfat fat virtio_balloon drm \ fuse xfs libcrc32c crct10dif_ce ghash_ce sha2_ce sha256_arm64 \ sha1_ce virtio_net net_failover virtio_console virtio_blk failover \ dimlib virtio_mmio CPU: 35 PID: 7484 Comm: test Kdump: loaded Tainted: G W 6.10.0-rc5-gavin+ #9 Hardware name: QEMU KVM Virtual Machine, BIOS edk2-20240524-1.el9 05/24/2024 pstate: 83400005 (Nzcv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--) pc : xas_split_alloc+0xf8/0x128 lr : split_huge_page_to_list_to_order+0x1c4/0x720
sp : ffff800087a4f6c0
x29: ffff800087a4f6c0 x28: ffff800087a4f720 x27: 000000001fffffff
x26: 0000000000000c40 x25: 000000000000000d x24: ffff00010625b858
x23: ffff800087a4f720 x22: ffffffdfc0780000 x21: 0000000000000000
x20: 0000000000000000 x19: ffffffdfc0780000 x18: 000000001ff40000
x17: 00000000ffffffff x16: 0000018000000000 x15: 51ec004000000000
x14: 0000e00000000000 x13: 0000000000002000 x12: 0000000000000020
x11: 51ec000000000000 x10: 51ece1c0ffff8000 x9 : ffffbeb961a44d28 x8 : 0000000000000003 x7 : ffffffdfc0456420 x6 : ffff0000e1aa6eb8 x5 : 20bf08b4fe778fca x4 : ffffffdfc0456420 x3 : 0000000000000c40 x2 : 000000000000000d x1 : 000000000000000c x0 : 0000000000000000
Call trace: xas_split_alloc+0xf8/0x128 split_huge_page_to_list_to_order+0x1c4/0x720 truncate_inode_partial_folio+0xdc/0x160 truncate_inode_pages_range+0x1b4/0x4a8 truncate_pagecache_range+0x84/0xa0 xfs_flush_unmap_range+0x70/0x90 [xfs] xfs_file_fallocate+0xfc/0x4d8 [xfs] vfs_fallocate+0x124/0x2e8 ksys_fallocate+0x4c/0xa0 __arm64_sys_fallocate+0x24/0x38 invoke_syscall.constprop.0+0x7c/0xd8 do_el0_svc+0xb4/0xd0 el0_svc+0x44/0x1d8 el0t_64_sync_handler+0x134/0x150 el0t_64_sync+0x17c/0x180
Fix it by decreasing MAX_PAGECACHE_ORDER to the largest supported order by xarray. For this specific case, MAX_PAGECACHE_ORDER is dropped from 13 to 11 when CONFIG_BASE_SMALL is disabled.
--- include/linux/pagemap.h | 11 +++++++++-- mm/readahead.c | 13 ------------- 2 files changed, 9 insertions(+), 15 deletions(-)
include/linux/pagemap.h +9 -2
@@ -333,11 +333,18 @@ static inline void mapping_set_gfp_mask(struct address_space *m, gfp_t mask)* a good order (that's 1MB if you're using 4kB pages) */ #ifdef CONFIG_TRANSPARENT_HUGEPAGE -#define MAX_PAGECACHE_ORDER HPAGE_PMD_ORDER +#define PREFERRED_MAX_PAGECACHE_ORDER HPAGE_PMD_ORDER#else -#define MAX_PAGECACHE_ORDER 8 +#define PREFERRED_MAX_PAGECACHE_ORDER 8#endif +/* +* xas_split_alloc() does not support arbitrary orders. This implies no +* 512MB THP on ARM64 with 64KB base page size. +*/ +#define MAX_XAS_ORDER (XA_CHUNK_SHIFT * 2 - 1) +#define MAX_PAGECACHE_ORDER min(MAX_XAS_ORDER, PREFERRED_MAX_PAGECACHE_ORDER) +/** * mapping_set_large_folios() - Indicate the file supports large folios. * @mapping: The file.
mm/readahead.c +0 -13
@@ -462,19 +462,6 @@ static int try_context_readahead(struct address_space *mapping,return 1 ; } -/* -* There are some parts of the kernel which assume that PMD entries -* are exactly HPAGE_PMD_ORDER. Those should be fixed, but until then, -* limit the maximum allocation order to PMD size. I'm not aware of any -* assumptions about maximum order if THP are disabled, but 8 seems like -* a good order (that's 1MB if you're using 4kB pages) -*/ -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -#define MAX_PAGECACHE_ORDER HPAGE_PMD_ORDER -#else -#define MAX_PAGECACHE_ORDER 8 -#endif -static inline int ra_alloc_folio (struct readahead_control *ractl,pgoff_t index,pgoff_t mark,unsigned int order,gfp_t gfp) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 639/1887 spi: microchip-core: ensure TX and RX FIFOs are empty at start of a transfer
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steve Wilkins <[email protected]>
[ Upstream commit 9cf71eb0faef4bff01df4264841b8465382d7927 ]
While transmitting with rx_len == 0, the RX FIFO is not going to be emptied in the interrupt handler. A subsequent transfer could then read crap from the previous transfer out of the RX FIFO into the start RX buffer. The core provides a register that will empty the RX and TX FIFOs, so do that before each transfer.
--- drivers/spi/spi-microchip-core.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/spi/spi-microchip-core.c +4 -0
@@ -91,6 +91,8 @@#define REG_CONTROL2 (0x28)#define REG_COMMAND (0x2c)#define COMMAND_CLRFRAMECNT BIT(4) +#define COMMAND_TXFIFORST BIT(3) +#define COMMAND_RXFIFORST BIT(2)#define REG_PKTSIZE (0x30)#define REG_CMD_SIZE (0x34)#define REG_HWSTATUS (0x38)
@@ -489,6 +491,8 @@ static int mchp_corespi_transfer_one(struct spi_controller *host,mchp_corespi_set_xfer_size (spi, (spi->tx_len >FIFO_DEPTH ) ?FIFO_DEPTH : spi->tx_len); +mchp_corespi_write (spi,REG_COMMAND ,COMMAND_RXFIFORST |COMMAND_TXFIFORST ); +while (spi->tx_len)mchp_corespi_write_fifo (spi);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 640/1887 PCI: endpoint: pci-epf-test: Make use of cached epc_features in pci_epf_test_core_init()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <[email protected]>
[ Upstream commit 5a5095a8bd1bd349cce1c879e5e44407a34dda8a ]
Instead of getting the epc_features from pci_epc_get_features() API, use the cached pci_epf_test::epc_features value to avoid the NULL check. Since the NULL check is already performed in pci_epf_test_bind(), having one more check in pci_epf_test_core_init() is redundant and it is not possible to hit the NULL pointer dereference.
Also with commit a01e7214bef9 ("PCI: endpoint: Remove "core_init_notifier" flag"), 'epc_features' got dereferenced without the NULL check, leading to the following false positive Smatch warning:
drivers/pci/endpoint/functions/pci-epf-test.c:784 pci_epf_test_core_init() error: we previously assumed 'epc_features' could be null (see line 747)
Thus, remove the redundant NULL check and also use the epc_features::
{msix_capable/msi_capable} flags directly to avoid local variables.
--- drivers/pci/endpoint/functions/pci-epf-test.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-)
drivers/pci/endpoint/functions/pci-epf-test.c +3 -11
@@ -782,19 +782,11 @@ static int pci_epf_test_core_init(struct pci_epf *epf) {struct pci_epf_test *epf_test =epf_get_drvdata (epf);struct pci_epf_header *header = epf->header; -const struct pci_epc_features *epc_features; +const struct pci_epc_features *epc_features = epf_test->epc_features;struct pci_epc *epc = epf->epc;struct device *dev = &epf->dev; -bool msix_capable = false; -bool msi_capable = true;int ret; - epc_features =pci_epc_get_features (epc, epf->func_no, epf->vfunc_no); -if (epc_features) { - msix_capable = epc_features->msix_capable; - msi_capable = epc_features->msi_capable; - } -if (epf->vfunc_no <=1 ) { ret =pci_epc_write_header (epc, epf->func_no, epf->vfunc_no, header);if (ret) {
@@ -807,7 +799,7 @@ static int pci_epf_test_core_init(struct pci_epf *epf)if (ret)return ret; -if (msi_capable) { +if (epc_features->msi_capable) { ret =pci_epc_set_msi (epc, epf->func_no, epf->vfunc_no, epf->msi_interrupts);if (ret) {
@@ -816,7 +808,7 @@ static int pci_epf_test_core_init(struct pci_epf *epf) } } -if (msix_capable) { +if (epc_features->msix_capable) { ret = pci_epc_set_msix(epc, epf->func_no, epf->vfunc_no, epf->msix_interrupts, epf_test->test_reg_bar,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 641/1887 soc: qcom: icc-bwmon: Fix refcount imbalance seen during bwmon_remove
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sibi Sankar <[email protected]>
[ Upstream commit 24086640ab39396eb1a92d1cb1cd2f31b2677c52 ]
The following warning is seen during bwmon_remove due to refcount imbalance, fix this by releasing the OPPs after use.
Logs:
WARNING: at drivers/opp/core.c:1640 _opp_table_kref_release+0x150/0x158 Hardware name: Qualcomm Technologies, Inc. X1E80100 CRD (DT) ... Call trace: _opp_table_kref_release+0x150/0x158 dev_pm_opp_remove_table+0x100/0x1b4 devm_pm_opp_of_table_release+0x10/0x1c devm_action_release+0x14/0x20 devres_release_all+0xa4/0x104 device_unbind_cleanup+0x18/0x60 device_release_driver_internal+0x1ec/0x228 driver_detach+0x50/0x98 bus_remove_driver+0x6c/0xbc driver_unregister+0x30/0x60 platform_driver_unregister+0x14/0x20 bwmon_driver_exit+0x18/0x524 [icc_bwmon] __arm64_sys_delete_module+0x184/0x264 invoke_syscall+0x48/0x118 el0_svc_common.constprop.0+0xc8/0xe8 do_el0_svc+0x20/0x2c el0_svc+0x34/0xdc el0t_64_sync_handler+0x13c/0x158 el0t_64_sync+0x190/0x194
--[ end trace 0000000000000000 ]---
--- drivers/soc/qcom/icc-bwmon.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/soc/qcom/icc-bwmon.c +2 -0
@@ -604,11 +604,13 @@ static int bwmon_probe(struct platform_device *pdev) opp =dev_pm_opp_find_bw_floor (dev, &bwmon->max_bw_kbps,0 );if (IS_ERR (opp))return dev_err_probe (dev,PTR_ERR (opp),"failed to find max peak bandwidth\n" ); +dev_pm_opp_put (opp); bwmon->min_bw_kbps =0 ; opp =dev_pm_opp_find_bw_ceil (dev, &bwmon->min_bw_kbps,0 );if (IS_ERR (opp))return dev_err_probe (dev,PTR_ERR (opp),"failed to find min peak bandwidth\n" ); +dev_pm_opp_put (opp); bwmon->dev = dev;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 642/1887 drm/amd/display: Fix null pointer deref in dcn20_resource.c
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aurabindo Pillai <[email protected]>
[ Upstream commit ecbf60782662f0a388493685b85a645a0ba1613c ]
Fixes a hang thats triggered when MPV is run on a DCN401 dGPU:
mpv --hwdec=vaapi --vo=gpu --hwdec-codecs=all
and then enabling fullscreen playback (double click on the video)
The following calltrace will be seen:
[ 181.843989] BUG: kernel NULL pointer dereference, address: 0000000000000000 [ 181.843997] #PF: supervisor instruction fetch in kernel mode [ 181.844003] #PF: error_code(0x0010) - not-present page [ 181.844009] PGD 0 P4D 0 [ 181.844020] Oops: 0010 [#1] PREEMPT SMP NOPTI [ 181.844028] CPU: 6 PID: 1892 Comm: gnome-shell Tainted: G W OE 6.5.0-41-generic #41~22.04.2-Ubuntu [ 181.844038] Hardware name: System manufacturer System Product Name/CROSSHAIR VI HERO, BIOS 6302 10/23/2018 [ 181.844044] RIP: 0010:0x0 [ 181.844079] Code: Unable to access opcode bytes at 0xffffffffffffffd6. [ 181.844084] RSP: 0018:ffffb593c2b8f7b0 EFLAGS: 00010246 [ 181.844093] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000004 [ 181.844099] RDX: ffffb593c2b8f804 RSI: ffffb593c2b8f7e0 RDI: ffff9e3c8e758400 [ 181.844105] RBP: ffffb593c2b8f7b8 R08: ffffb593c2b8f9c8 R09: ffffb593c2b8f96c [ 181.844110] R10: 0000000000000000 R11: 0000000000000000 R12: ffffb593c2b8f9c8 [ 181.844115] R13: 0000000000000001 R14: ffff9e3c88000000 R15: 0000000000000005 [ 181.844121] FS: 00007c6e323bb5c0(0000) GS:ffff9e3f85f80000(0000) knlGS:0000000000000000 [ 181.844128] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 181.844134] CR2: ffffffffffffffd6 CR3: 0000000140fbe000 CR4: 00000000003506e0 [ 181.844141] Call Trace: [ 181.844146] <TASK> [ 181.844153] ? show_regs+0x6d/0x80 [ 181.844167] ? __die+0x24/0x80 [ 181.844179] ? page_fault_oops+0x99/0x1b0 [ 181.844192] ? do_user_addr_fault+0x31d/0x6b0 [ 181.844204] ? exc_page_fault+0x83/0x1b0 [ 181.844216] ? asm_exc_page_fault+0x27/0x30 [ 181.844237] dcn20_get_dcc_compression_cap+0x23/0x30 [amdgpu] [ 181.845115] amdgpu_dm_plane_validate_dcc.constprop.0+0xe5/0x180 [amdgpu] [ 181.845985] amdgpu_dm_plane_fill_plane_buffer_attributes+0x300/0x580 [amdgpu] [ 181.846848] fill_dc_plane_info_and_addr+0x258/0x350 [amdgpu] [ 181.847734] fill_dc_plane_attributes+0x162/0x350 [amdgpu] [ 181.848748] dm_update_plane_state.constprop.0+0x4e3/0x6b0 [amdgpu] [ 181.849791] ? dm_update_plane_state.constprop.0+0x4e3/0x6b0 [amdgpu] [ 181.850840] amdgpu_dm_atomic_check+0xdfe/0x1760 [amdgpu]
--- drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c +5 -4
@@ -2173,10 +2173,11 @@ bool dcn20_get_dcc_compression_cap(const struct dc *dc, const struct dc_dcc_surface_param *input, struct dc_surface_dcc_cap *output) { - return dc->res_pool->hubbub->funcs->get_dcc_compression_cap( - dc->res_pool->hubbub, -input , -output ); + if (dc->res_pool->hubbub->funcs->get_dcc_compression_cap) + return dc->res_pool->hubbub->funcs->get_dcc_compression_cap( + dc->res_pool->hubbub, input, output); + +return false; }static void dcn20_destroy_resource_pool (struct resource_pool **pool)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 643/1887 nvme: apple: fix device reference counting
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Keith Busch <[email protected]>
[ Upstream commit b9ecbfa45516182cd062fecd286db7907ba84210 ]
Drivers must call nvme_uninit_ctrl after a successful nvme_init_ctrl. Split the allocation side out to make the error handling boundary easier to navigate. The apple driver had been doing this wrong, leaking the controller device memory on a tagset failure.
--- drivers/nvme/host/apple.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-)
drivers/nvme/host/apple.c +23 -6
@@ -1387,7 +1387,7 @@ static void devm_apple_nvme_mempool_destroy(void *data)mempool_destroy (data); } -static int apple_nvme_probe (struct platform_device *pdev) +static struct apple_nvme *apple_nvme_alloc (struct platform_device *pdev) {struct device *dev = &pdev->dev;struct apple_nvme *anv;
@@ -1395,7 +1395,7 @@ static int apple_nvme_probe(struct platform_device *pdev) anv =devm_kzalloc (dev,sizeof (*anv),GFP_KERNEL );if (!anv) -return -ENOMEM ; +return ERR_PTR (-ENOMEM ); anv->dev =get_device (dev); anv->adminq.is_adminq = true;
@@ -1515,10 +1515,26 @@ static int apple_nvme_probe(struct platform_device *pdev) goto put_dev; } +return anv; +put_dev: +put_device (anv->dev); +return ERR_PTR (ret); +} + +static int apple_nvme_probe (struct platform_device *pdev) +{ +struct apple_nvme *anv; +int ret; + + anv =apple_nvme_alloc (pdev); +if (IS_ERR (anv)) +return PTR_ERR (anv); + anv->ctrl.admin_q =blk_mq_init_queue (&anv->admin_tagset);if (IS_ERR (anv->ctrl.admin_q)) { ret = -ENOMEM ; - goto put_dev; + anv->ctrl.admin_q =NULL ; + goto out_uninit_ctrl; }if (!blk_get_queue (anv->ctrl.admin_q)) {
@@ -1527,7 +1543,7 @@ static int apple_nvme_probe(struct platform_device *pdev)blk_put_queue (anv->ctrl.admin_q); anv->ctrl.admin_q =NULL ; ret = -ENODEV ; - goto put_dev; + goto out_uninit_ctrl; }nvme_reset_ctrl (&anv->ctrl);
@@ -1535,8 +1551,9 @@ static int apple_nvme_probe(struct platform_device *pdev)return 0 ; -put_dev: -put_device (anv->dev); +out_uninit_ctrl: +nvme_uninit_ctrl (&anv->ctrl); +nvme_put_ctrl (&anv->ctrl);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 644/1887 f2fs: fix to cover read extent cache access with lock
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chao Yu <[email protected]>
[ Upstream commit d7409b05a64f212735f0d33f5f1602051a886eab ]
syzbot reports a f2fs bug as below:
BUG: KASAN: slab-use-after-free in sanity_check_extent_cache+0x370/0x410 fs/f2fs/extent_cache.c:46 Read of size 4 at addr ffff8880739ab220 by task syz-executor200/5097 CPU: 0 PID: 5097 Comm: syz-executor200 Not tainted 6.9.0-rc6-syzkaller #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 03/27/2024 Call Trace: <TASK> __dump_stack lib/dump_stack.c:88 [inline] dump_stack_lvl+0x241/0x360 lib/dump_stack.c:114 print_address_description mm/kasan/report.c:377 [inline] print_report+0x169/0x550 mm/kasan/report.c:488 kasan_report+0x143/0x180 mm/kasan/report.c:601 sanity_check_extent_cache+0x370/0x410 fs/f2fs/extent_cache.c:46 do_read_inode fs/f2fs/inode.c:509 [inline] f2fs_iget+0x33e1/0x46e0 fs/f2fs/inode.c:560 f2fs_nfs_get_inode+0x74/0x100 fs/f2fs/super.c:3237 generic_fh_to_dentry+0x9f/0xf0 fs/libfs.c:1413 exportfs_decode_fh_raw+0x152/0x5f0 fs/exportfs/expfs.c:444 exportfs_decode_fh+0x3c/0x80 fs/exportfs/expfs.c:584 do_handle_to_path fs/fhandle.c:155 [inline] handle_to_path fs/fhandle.c:210 [inline] do_handle_open+0x495/0x650 fs/fhandle.c:226 do_syscall_x64 arch/x86/entry/common.c:52 [inline] do_syscall_64+0xf5/0x240 arch/x86/entry/common.c:83 entry_SYSCALL_64_after_hwframe+0x77/0x7f
We missed to cover sanity_check_extent_cache() w/ extent cache lock, so, below race case may happen, result in use after free issue.
- f2fs_iget
- do_read_inode
- f2fs_init_read_extent_tree
: add largest extent entry in to cache
- shrink
- f2fs_shrink_read_extent_tree
- __shrink_extent_tree
- __detach_extent_node : drop largest extent entry
- sanity_check_extent_cache
: access et->largest w/o lock
let's refactor sanity_check_extent_cache() to avoid extent cache access and call it before f2fs_init_read_extent_tree() to fix this issue.
--- fs/f2fs/extent_cache.c | 44 ++++++++++++++++++++---------------------- fs/f2fs/f2fs.h | 2 +- fs/f2fs/inode.c | 8 ++++---- 3 files changed, 26 insertions(+), 28 deletions(-)
fs/f2fs/extent_cache.c +21 -23
@@ -15,26 +15,24 @@#include "node.h" #include <trace/events/f2fs.h> -bool sanity_check_extent_cache (struct inode *inode) +bool sanity_check_extent_cache (struct inode *inode,struct page *ipage) {struct f2fs_sb_info *sbi =F2FS_I_SB (inode); -struct f2fs_inode_info *fi =F2FS_I (inode); -struct extent_info *ei; +struct f2fs_extent *i_ext = &F2FS_INODE (ipage)->i_ext; +struct extent_info ei; -if (!fi->extent_tree[EX_READ ]) -return true; +get_read_extent_info (&ei, i_ext); - ei = &fi->extent_tree[EX_READ ]->largest; +if (!ei.len) +return true; -if (ei->len && - (!f2fs_is_valid_blkaddr (sbi, ei->blk, -DATA_GENERIC_ENHANCE ) || - !f2fs_is_valid_blkaddr (sbi, ei->blk + ei->len -1 , -DATA_GENERIC_ENHANCE ))) { +if (!f2fs_is_valid_blkaddr (sbi, ei.blk,DATA_GENERIC_ENHANCE ) || + !f2fs_is_valid_blkaddr (sbi, ei.blk + ei.len -1 , +DATA_GENERIC_ENHANCE )) {set_sbi_flag (sbi,SBI_NEED_FSCK );f2fs_warn (sbi,"%s: inode (ino=%lx) extent info [%u, %u, %u] is incorrect, run fsck to fix" , __func__, inode->i_ino, - ei->blk, ei->fofs, ei->len); + ei.blk, ei.fofs, ei.len);return false; }return true;
@@ -442,24 +440,22 @@ void f2fs_init_read_extent_tree(struct inode *inode, struct page *ipage)if (!__may_extent_tree (inode,EX_READ )) {/* drop largest read extent */ -if (i_ext && i_ext->len) { +if (i_ext->len) {f2fs_wait_on_page_writeback (ipage,NODE , true, true); i_ext->len =0 ;set_page_dirty (ipage); } - goto out; +set_inode_flag (inode,FI_NO_EXTENT ); +return ; } et =__grab_extent_tree (inode,EX_READ ); -if (!i_ext || !i_ext->len) - goto out; -get_read_extent_info (&ei, i_ext);write_lock (&et->lock); -if (atomic_read (&et->node_cnt)) - goto unlock_out; +if (atomic_read (&et->node_cnt) || !ei.len) + goto skip; en =__attach_extent_node (sbi, et, &ei,NULL , &et->root.rb_root.rb_node, true);
@@ -471,11 +467,13 @@ void f2fs_init_read_extent_tree(struct inode *inode, struct page *ipage)list_add_tail (&en->list, &eti->extent_list);spin_unlock (&eti->extent_lock); } -unlock_out: +skip: +/* Let's drop, if checkpoint got corrupted. */ +if (f2fs_cp_error (sbi)) { + et->largest.len =0 ; + et->largest_updated = true; + }write_unlock (&et->lock); -out: -if (!F2FS_I (inode)->extent_tree[EX_READ ]) -set_inode_flag (inode,FI_NO_EXTENT ); }void f2fs_init_extent_tree (struct inode *inode)
fs/f2fs/f2fs.h +1 -1
@@ -4164,7 +4164,7 @@ void f2fs_leave_shrinker(struct f2fs_sb_info *sbi);/* * extent_cache.c */ -bool sanity_check_extent_cache (struct inode *inode); +bool sanity_check_extent_cache (struct inode *inode,struct page *ipage);struct rb_entry *f2fs_lookup_rb_tree (struct rb_root_cached *root,struct rb_entry *cached_re,unsigned int ofs); struct rb_node **f2fs_lookup_rb_tree_for_insert(struct f2fs_sb_info *sbi,
fs/f2fs/inode.c +4 -4
@@ -455,15 +455,15 @@ static int do_read_inode(struct inode *inode)init_idisk_time (inode); -/* Need all the flag bits */ -f2fs_init_read_extent_tree (inode, node_page); - -if (!sanity_check_extent_cache (inode)) { +if (!sanity_check_extent_cache (inode, node_page)) {f2fs_put_page (node_page,1 );f2fs_handle_error (sbi,ERROR_CORRUPTED_INODE );return -EFSCORRUPTED ; } +/* Need all the flag bits */ +f2fs_init_read_extent_tree (inode, node_page); +f2fs_put_page (node_page,1 );stat_inc_inline_xattr (inode);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 645/1887 f2fs: fix to do sanity check on F2FS_INLINE_DATA flag in inode during GC
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chao Yu <[email protected]>
[ Upstream commit fc01008c92f40015aeeced94750855a7111b6929 ]
syzbot reports a f2fs bug as below:
------------[ cut here ]------------ kernel BUG at fs/f2fs/inline.c:258! CPU: 1 PID: 34 Comm: kworker/u8:2 Not tainted 6.9.0-rc6-syzkaller-00012-g9e4bc4bcae01 #0 RIP: 0010:f2fs_write_inline_data+0x781/0x790 fs/f2fs/inline.c:258 Call Trace: f2fs_write_single_data_page+0xb65/0x1d60 fs/f2fs/data.c:2834 f2fs_write_cache_pages fs/f2fs/data.c:3133 [inline] __f2fs_write_data_pages fs/f2fs/data.c:3288 [inline] f2fs_write_data_pages+0x1efe/0x3a90 fs/f2fs/data.c:3315 do_writepages+0x35b/0x870 mm/page-writeback.c:2612 __writeback_single_inode+0x165/0x10b0 fs/fs-writeback.c:1650 writeback_sb_inodes+0x905/0x1260 fs/fs-writeback.c:1941 wb_writeback+0x457/0xce0 fs/fs-writeback.c:2117 wb_do_writeback fs/fs-writeback.c:2264 [inline] wb_workfn+0x410/0x1090 fs/fs-writeback.c:2304 process_one_work kernel/workqueue.c:3254 [inline] process_scheduled_works+0xa12/0x17c0 kernel/workqueue.c:3335 worker_thread+0x86d/0xd70 kernel/workqueue.c:3416 kthread+0x2f2/0x390 kernel/kthread.c:388 ret_from_fork+0x4d/0x80 arch/x86/kernel/process.c:147 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:244
The root cause is: inline_data inode can be fuzzed, so that there may be valid blkaddr in its direct node, once f2fs triggers background GC to migrate the block, it will hit f2fs_bug_on() during dirty page writeback.
Let's add sanity check on F2FS_INLINE_DATA flag in inode during GC, so that, it can forbid migrating inline_data inode's data block for fixing.
--- fs/f2fs/gc.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
fs/f2fs/gc.c +10 -0
@@ -1567,6 +1567,16 @@ static int gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,continue ; } +if (f2fs_has_inline_data (inode)) { +set_sbi_flag (sbi,SBI_NEED_FSCK ); +f2fs_err (sbi, +"inode %lx has both inline_data flag and " +"data block, nid=%u, ofs_in_node=%u" , + inode->i_ino, dni.nid, ofs_in_node); +iput (inode); +continue ; + } + err =f2fs_gc_pinned_control (inode, gc_type, segno);if (err == -EAGAIN ) {iput (inode);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 646/1887 btrfs: do not BUG_ON() when freeing tree block after error
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Filipe Manana <[email protected]>
[ Upstream commit bb3868033a4cccff7be57e9145f2117cbdc91c11 ]
When freeing a tree block, at btrfs_free_tree_block(), if we fail to create a delayed reference we don't deal with the error and just do a BUG_ON(). The error most likely to happen is -ENOMEM, and we have a comment mentioning that only -ENOMEM can happen, but that is not true, because in case qgroups are enabled any error returned from btrfs_qgroup_trace_extent_post() (can be -EUCLEAN or anything returned from btrfs_search_slot() for example) can be propagated back to btrfs_free_tree_block().
So stop doing a BUG_ON() and return the error to the callers and make them abort the transaction to prevent leaking space. Syzbot was triggering this, likely due to memory allocation failure injection.
--- fs/btrfs/ctree.c | 65 ++++++++++++++++++++++++++++---------- fs/btrfs/ctree.h | 8 ++--- fs/btrfs/extent-tree.c | 22 +++++++------ fs/btrfs/free-space-tree.c | 10 ++++-- fs/btrfs/ioctl.c | 6 +++- fs/btrfs/qgroup.c | 6 ++-- 6 files changed, 82 insertions(+), 35 deletions(-)
fs/btrfs/ctree.c +49 -16
@@ -502,10 +502,16 @@ int btrfs_force_cow_block(struct btrfs_trans_handle *trans,atomic_inc (&cow->refs);rcu_assign_pointer (root->node, cow); -btrfs_free_tree_block (trans,btrfs_root_id (root), buf, - parent_start, last_ref); + ret =btrfs_free_tree_block (trans,btrfs_root_id (root), buf, + parent_start, last_ref);free_extent_buffer (buf);add_root_to_dirty_list (root); +if (ret <0 ) { +btrfs_tree_unlock (cow); +free_extent_buffer (cow); +btrfs_abort_transaction (trans, ret); +return ret; + } }else {WARN_ON (trans->transid !=btrfs_header_generation (parent)); btrfs_tree_mod_log_insert_key(parent, parent_slot,
@@ -524,8 +530,14 @@ int btrfs_force_cow_block(struct btrfs_trans_handle *trans,return ret; } } -btrfs_free_tree_block (trans,btrfs_root_id (root), buf, - parent_start, last_ref); + ret =btrfs_free_tree_block (trans,btrfs_root_id (root), buf, + parent_start, last_ref); +if (ret <0 ) { +btrfs_tree_unlock (cow); +free_extent_buffer (cow); +btrfs_abort_transaction (trans, ret); +return ret; + } }trace_btrfs_cow_block (root, buf, cow);
@@ -999,9 +1011,13 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,free_extent_buffer (mid);root_sub_used (root, mid->len); -btrfs_free_tree_block (trans,btrfs_root_id (root), mid,0 ,1 ); + ret =btrfs_free_tree_block (trans,btrfs_root_id (root), mid,0 ,1 );/* once for the root ptr */ free_extent_buffer_stale (mid); +if (ret <0 ) { +btrfs_abort_transaction (trans, ret); + goto enospc; + }return 0 ; } if (btrfs_header_nritems(mid) >
@@ -1058,10 +1074,14 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,btrfs_tree_unlock (right);del_ptr (root, path, level +1 , pslot +1 );root_sub_used (root, right->len); -btrfs_free_tree_block (trans,btrfs_root_id (root), right, -0 ,1 ); + ret =btrfs_free_tree_block (trans,btrfs_root_id (root), + right,0 ,1 );free_extent_buffer_stale (right); right =NULL ; +if (ret <0 ) { +btrfs_abort_transaction (trans, ret); + goto enospc; + } }else {struct btrfs_disk_key right_key;btrfs_node_key (right, &right_key,0 );
@@ -1107,9 +1127,15 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,btrfs_tree_unlock (mid);del_ptr (root, path, level +1 , pslot);root_sub_used (root, mid->len); -btrfs_free_tree_block (trans,btrfs_root_id (root), mid,0 ,1 ); + ret =btrfs_free_tree_block (trans,btrfs_root_id (root), mid,0 ,1 );free_extent_buffer_stale (mid); mid =NULL ; +if (ret <0 ) { + path->locks[level] =0 ; + path->nodes[level] =NULL ; +btrfs_abort_transaction (trans, ret); + goto enospc; + } }else {/* update the parent key to reflect our changes */ struct btrfs_disk_key mid_key;
@@ -4314,11 +4340,13 @@ static void del_ptr(struct btrfs_root *root, struct btrfs_path *path,* The path must have already been setup for deleting the leaf, including * all the proper balancing. path->nodes[1] must be locked. */ -static noinline void btrfs_del_leaf(struct btrfs_trans_handle *trans, -struct btrfs_root *root, -struct btrfs_path *path, -struct extent_buffer *leaf) +static noinline int btrfs_del_leaf(struct btrfs_trans_handle *trans, +struct btrfs_root *root, +struct btrfs_path *path, +struct extent_buffer *leaf) { +int ret; +WARN_ON (btrfs_header_generation (leaf) != trans->transid);del_ptr (root, path,1 , path->slots[1 ]);
@@ -4331,8 +4359,12 @@ static noinline void btrfs_del_leaf(struct btrfs_trans_handle *trans,root_sub_used (root, leaf->len);atomic_inc (&leaf->refs); -btrfs_free_tree_block (trans,btrfs_root_id (root), leaf,0 ,1 ); + ret =btrfs_free_tree_block (trans,btrfs_root_id (root), leaf,0 ,1 );free_extent_buffer_stale (leaf); +if (ret <0 ) +btrfs_abort_transaction (trans, ret); + +return ret; }/* * delete the item at the leaf level in path. If that empties
@@ -4387,7 +4419,9 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,btrfs_set_header_level (leaf,0 ); }else {btrfs_clean_tree_block (leaf); -btrfs_del_leaf (trans, root, path, leaf); + ret =btrfs_del_leaf (trans, root, path, leaf); +if (ret <0 ) +return ret; } }else {int used =leaf_space_used (leaf,0 , nritems);
@@ -4448,9 +4482,8 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,if (btrfs_header_nritems (leaf) ==0 ) { path->slots[1 ] = slot; -btrfs_del_leaf (trans, root, path, leaf); + ret =btrfs_del_leaf (trans, root, path, leaf);free_extent_buffer (leaf); - ret =0 ; }else {/* if we're still in the path, make sure * we're dirty. Otherwise, one of the
fs/btrfs/ctree.h +4 -4
@@ -2888,10 +2888,10 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans, int level, u64 hint, u64 empty_size, enum btrfs_lock_nesting nest); -void btrfs_free_tree_block (struct btrfs_trans_handle *trans, -u64 root_id, -struct extent_buffer *buf, -u64 parent,int last_ref); +int btrfs_free_tree_block (struct btrfs_trans_handle *trans, +u64 root_id, +struct extent_buffer *buf, +u64 parent,int last_ref); int btrfs_alloc_reserved_file_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 owner, u64 offset, u64 ram_bytes,
fs/btrfs/extent-tree.c +13 -9
@@ -3280,10 +3280,10 @@ static noinline int check_ref_cleanup(struct btrfs_trans_handle *trans,return 0 ; } -void btrfs_free_tree_block (struct btrfs_trans_handle *trans, -u64 root_id, -struct extent_buffer *buf, -u64 parent,int last_ref) +int btrfs_free_tree_block (struct btrfs_trans_handle *trans, +u64 root_id, +struct extent_buffer *buf, +u64 parent,int last_ref) {struct btrfs_fs_info *fs_info = trans->fs_info;struct btrfs_ref generic_ref = {0 };
@@ -3297,7 +3297,8 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,if (root_id !=BTRFS_TREE_LOG_OBJECTID ) {btrfs_ref_tree_mod (fs_info, &generic_ref); ret =btrfs_add_delayed_tree_ref (trans, &generic_ref,NULL ); -BUG_ON (ret);/* -ENOMEM */ +if (ret <0 ) +return ret; }if (last_ref &&btrfs_header_generation (buf) == trans->transid) {
@@ -3361,6 +3362,7 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,*/ clear_bit (EXTENT_BUFFER_CORRUPT , &buf->bflags); } +return 0 ; }/* Can return -ENOMEM */
@@ -5533,7 +5535,7 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans, struct walk_control *wc) {struct btrfs_fs_info *fs_info = root->fs_info; -int ret; +int ret =0 ;int level = wc->level;struct extent_buffer *eb = path->nodes[level];u64 parent =0 ;
@@ -5628,12 +5630,14 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans, goto owner_mismatch; } -btrfs_free_tree_block (trans,btrfs_root_id (root), eb, parent, - wc->refs[level] ==1 ); + ret =btrfs_free_tree_block (trans,btrfs_root_id (root), eb, parent, + wc->refs[level] ==1 ); +if (ret <0 ) +btrfs_abort_transaction (trans, ret); out: wc->refs[level] =0 ; wc->flags[level] =0 ; -return 0 ; +return ret; owner_mismatch: btrfs_err_rl(fs_info, "unexpected tree owner, have %llu expect %llu",
fs/btrfs/free-space-tree.c +7 -3
@@ -1292,10 +1292,14 @@ int btrfs_delete_free_space_tree(struct btrfs_fs_info *fs_info)btrfs_tree_lock (free_space_root->node);btrfs_clean_tree_block (free_space_root->node);btrfs_tree_unlock (free_space_root->node); -btrfs_free_tree_block (trans,btrfs_root_id (free_space_root), - free_space_root->node,0 ,1 ); - + ret =btrfs_free_tree_block (trans,btrfs_root_id (free_space_root), + free_space_root->node,0 ,1 );btrfs_put_root (free_space_root); +if (ret <0 ) { +btrfs_abort_transaction (trans, ret); +btrfs_end_transaction (trans); +return ret; + }return btrfs_commit_transaction (trans);
fs/btrfs/ioctl.c +5 -1
@@ -696,6 +696,8 @@ static noinline int create_subvol(struct user_namespace *mnt_userns, ret =btrfs_insert_root (trans, fs_info->tree_root, &key, root_item);if (ret) { +int ret2; +/* * Since we don't abort the transaction in this case, free the * tree block so that we don't leak space and leave the
@@ -706,7 +708,9 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,btrfs_tree_lock (leaf);btrfs_clean_tree_block (leaf);btrfs_tree_unlock (leaf); -btrfs_free_tree_block (trans, objectid, leaf,0 ,1 ); + ret2 =btrfs_free_tree_block (trans, objectid, leaf,0 ,1 ); +if (ret2 <0 ) +btrfs_abort_transaction (trans, ret2);free_extent_buffer (leaf); goto out; }
fs/btrfs/qgroup.c +4 -2
@@ -1325,9 +1325,11 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info)btrfs_tree_lock (quota_root->node);btrfs_clean_tree_block (quota_root->node);btrfs_tree_unlock (quota_root->node); -btrfs_free_tree_block (trans,btrfs_root_id (quota_root), - quota_root->node,0 ,1 ); + ret =btrfs_free_tree_block (trans,btrfs_root_id (quota_root), + quota_root->node,0 ,1 ); +if (ret <0 ) +btrfs_abort_transaction (trans, ret); out:btrfs_put_root (quota_root);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 647/1887 pktgen: use cpus_read_lock() in pg_net_init()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 979b581e4c69257acab1af415ddad6b2d78a2fa5 ]
I have seen the WARN_ON(smp_processor_id() != cpu) firing in pktgen_thread_worker() during tests.
We must use cpus_read_lock()/cpus_read_unlock() around the for_each_online_cpu(cpu) loop.
While we are at it use WARN_ON_ONCE() to avoid a possible syslog flood.
--- net/core/pktgen.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
net/core/pktgen.c +4 -1
@@ -114,6 +114,7 @@#include <linux/sys.h> #include <linux/types.h> +#include <linux/cpu.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h>
@@ -3615,7 +3616,7 @@ static int pktgen_thread_worker(void *arg)struct pktgen_dev *pkt_dev =NULL ;int cpu = t->cpu; -WARN_ON (smp_processor_id () != cpu); +WARN_ON_ONCE (smp_processor_id () != cpu);init_waitqueue_head (&t->queue);complete (&t->start_done);
@@ -3951,6 +3952,7 @@ static int __net_init pg_net_init(struct net *net) goto remove; } +cpus_read_lock ();for_each_online_cpu (cpu) {int err;
@@ -3959,6 +3961,7 @@ static int __net_init pg_net_init(struct net *net)pr_warn ("Cannot create thread for cpu %d (%d)\n" , cpu, err); } +cpus_read_unlock ();if (list_empty (&pn->pktgen_threads)) {pr_err ("Initialization failed for all threads\n" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 648/1887 drm/amd/display: Check index for aux_rd_interval before using
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Hung <[email protected]>
[ Upstream commit 9ba2ea6337b4f159aecb177555a6a81da92d302e ]
aux_rd_interval has size of 7 and should be checked.
This fixes 3 OVERRUN and 1 INTEGER_OVERFLOW issues reported by Coverity.
--- drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +2 -2
@@ -1676,10 +1676,10 @@ static enum dc_status configure_lttpr_mode_non_transparent(/* Driver does not need to train the first hop. Skip DPCD read and clear * AUX_RD_INTERVAL for DPTX-to-DPIA hop. */ -if (link->ep_type ==DISPLAY_ENDPOINT_USB4_DPIA ) +if (link->ep_type ==DISPLAY_ENDPOINT_USB4_DPIA && repeater_cnt >0 && repeater_cnt <MAX_REPEATER_CNT ) link->dpcd_caps.lttpr_caps.aux_rd_interval[--repeater_cnt] =0 ; -for (repeater_id = repeater_cnt; repeater_id >0 ; repeater_id--) { +for (repeater_id = repeater_cnt; repeater_id >0 && repeater_id <MAX_REPEATER_CNT ; repeater_id--) { aux_interval_address =DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1 + ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE ) * (repeater_id -1 )); core_link_read_dpcd(
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 649/1887 drm/amd/display: Ensure array index tg_inst wont be -1
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Hung <[email protected]>
[ Upstream commit 687fe329f18ab0ab0496b20ed2cb003d4879d931 ]
[WHY & HOW]tg_inst will be a negative if timing_generator_count equals 0, which should be checked before used.
This fixes 2 OVERRUN issues reported by Coverity.
--- drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/amd/display/dc/core/dc_resource.c +1 -1
@@ -2115,7 +2115,7 @@ static int acquire_first_free_pipe( pipe_ctx->plane_res.mpcc_inst = pool->dpps[i]->inst; pipe_ctx->pipe_idx = i; -if (i >= pool->timing_generator_count) { +if (i >= pool->timing_generator_count && pool->timing_generator_count !=0 ) {int tg_inst = pool->timing_generator_count -1 ; pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst];
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 650/1887 ice: protect XDP configuration with a mutex
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Larysa Zaremba <[email protected]>
[ Upstream commit 2504b8405768a57a71e660dbfd5abd59f679a03f ]
The main threat to data consistency in ice_xdp() is a possible asynchronous PF reset. It can be triggered by a user or by TX timeout handler.
XDP setup and PF reset code access the same resources in the following sections:
* ice_vsi_close() in ice_prepare_for_reset() - already rtnl-locked
* ice_vsi_rebuild() for the PF VSI - not protected
* ice_vsi_open() - already rtnl-locked
With an unfortunate timing, such accesses can result in a crash such as the one below:
[ +1.999878] ice 0000:b1:00.0: Registered XDP mem model MEM_TYPE_XSK_BUFF_POOL on Rx ring 14
[ +2.002992] ice 0000:b1:00.0: Registered XDP mem model MEM_TYPE_XSK_BUFF_POOL on Rx ring 18
[Mar15 18:17] ice 0000:b1:00.0 ens801f0np0: NETDEV WATCHDOG: CPU: 38: transmit queue 14 timed out 80692736 ms [ +0.000093] ice 0000:b1:00.0 ens801f0np0: tx_timeout: VSI_num: 6, Q 14, NTC: 0x0, HW_HEAD: 0x0, NTU: 0x0, INT: 0x4000001 [ +0.000012] ice 0000:b1:00.0 ens801f0np0: tx_timeout recovery level 1, txqueue 14
[ +0.394718] ice 0000:b1:00.0: PTP reset successful
[ +0.006184] BUG: kernel NULL pointer dereference, address: 0000000000000098
[ +0.000045] #PF: supervisor read access in kernel mode
[ +0.000023] #PF: error_code(0x0000) - not-present page
[ +0.000023] PGD 0 P4D 0
[ +0.000018] Oops: 0000 [#1] PREEMPT SMP NOPTI
[ +0.000023] CPU: 38 PID: 7540 Comm: kworker/38:1 Not tainted 6.8.0-rc7 #1
[ +0.000031] Hardware name: Intel Corporation S2600WFT/S2600WFT, BIOS SE5C620.86B.02.01.0014.082620210524 08/26/2021 [ +0.000036] Workqueue: ice ice_service_task [ice]
[ +0.000183] RIP: 0010:ice_clean_tx_ring+0xa/0xd0 [ice]
[...]
[ +0.000013] Call Trace:
[ +0.000016] <TASK>
[ +0.000014] ? __die+0x1f/0x70
[ +0.000029] ? page_fault_oops+0x171/0x4f0
[ +0.000029] ? schedule+0x3b/0xd0
[ +0.000027] ? exc_page_fault+0x7b/0x180
[ +0.000022] ? asm_exc_page_fault+0x22/0x30
[ +0.000031] ? ice_clean_tx_ring+0xa/0xd0 [ice]
[ +0.000194] ice_free_tx_ring+0xe/0x60 [ice]
[ +0.000186] ice_destroy_xdp_rings+0x157/0x310 [ice]
[ +0.000151] ice_vsi_decfg+0x53/0xe0 [ice]
[ +0.000180] ice_vsi_rebuild+0x239/0x540 [ice]
[ +0.000186] ice_vsi_rebuild_by_type+0x76/0x180 [ice]
[ +0.000145] ice_rebuild+0x18c/0x840 [ice]
[ +0.000145] ? delay_tsc+0x4a/0xc0
[ +0.000022] ? delay_tsc+0x92/0xc0
[ +0.000020] ice_do_reset+0x140/0x180 [ice]
[ +0.000886] ice_service_task+0x404/0x1030 [ice]
[ +0.000824] process_one_work+0x171/0x340
[ +0.000685] worker_thread+0x277/0x3a0
[ +0.000675] ? preempt_count_add+0x6a/0xa0
[ +0.000677] ? _raw_spin_lock_irqsave+0x23/0x50
[ +0.000679] ? __pfx_worker_thread+0x10/0x10
[ +0.000653] kthread+0xf0/0x120
[ +0.000635] ? __pfx_kthread+0x10/0x10
[ +0.000616] ret_from_fork+0x2d/0x50
[ +0.000612] ? __pfx_kthread+0x10/0x10
[ +0.000604] ret_from_fork_asm+0x1b/0x30
[ +0.000604] </TASK>
The previous way of handling this through returning -EBUSY is not viable, particularly when destroying AF_XDP socket, because the kernel proceeds with removal anyway.
There is plenty of code between those calls and there is no need to create a large critical section that covers all of them, same as there is no need to protect ice_vsi_rebuild() with rtnl_lock().
Add xdp_state_lock mutex to protect ice_vsi_rebuild() and ice_xdp().
Leaving unprotected sections in between would result in two states that have to be considered:
1. when the VSI is closed, but not yet rebuild
2. when VSI is already rebuild, but not yet open
The latter case is actually already handled through !netif_running() case, we just need to adjust flag checking a little. The former one is not as trivial, because between ice_vsi_close() and ice_vsi_rebuild(), a lot of hardware interaction happens, this can make adding/deleting rings exit with an error. Luckily, VSI rebuild is pending and can apply new configuration for us in a managed fashion.
Therefore, add an additional VSI state flag ICE_VSI_REBUILD_PENDING to indicate that ice_xdp() can just hot-swap the program.
Also, as ice_vsi_rebuild() flow is touched in this patch, make it more consistent by deconfiguring VSI when coalesce allocation fails.
--- drivers/net/ethernet/intel/ice/ice.h | 2 ++ drivers/net/ethernet/intel/ice/ice_lib.c | 18 ++++++++++++++++-- drivers/net/ethernet/intel/ice/ice_main.c | 20 +++++++++++++++----- drivers/net/ethernet/intel/ice/ice_xsk.c | 3 ++- 4 files changed, 35 insertions(+), 8 deletions(-)
drivers/net/ethernet/intel/ice/ice.h +2 -0
@@ -302,6 +302,7 @@ enum ice_vsi_state {ICE_VSI_UMAC_FLTR_CHANGED ,ICE_VSI_MMAC_FLTR_CHANGED ,ICE_VSI_PROMISC_CHANGED , +ICE_VSI_REBUILD_PENDING , ICE_VSI_STATE_NBITS /* must be last */ };
@@ -390,6 +391,7 @@ struct ice_vsi {struct ice_tx_ring **xdp_rings;/* XDP ring array */ u16 num_xdp_txq;/* Used XDP queues */ u8 xdp_mapping_mode;/* ICE_MAP_MODE_[CONTIG|SCATTER] */ +struct mutex xdp_state_lock;struct net_device **target_netdevs;
drivers/net/ethernet/intel/ice/ice_lib.c +16 -2
@@ -365,6 +365,7 @@ int ice_vsi_clear(struct ice_vsi *vsi) pf->next_vsi = vsi->idx;ice_vsi_free_arrays (vsi); +mutex_destroy (&vsi->xdp_state_lock);mutex_unlock (&pf->sw_mutex);devm_kfree (dev, vsi);
@@ -540,6 +541,8 @@ ice_vsi_alloc(struct ice_pf *pf, enum ice_vsi_type vsi_type,if (vsi->type ==ICE_VSI_CTRL && vf) vf->ctrl_vsi_idx = vsi->idx; + +mutex_init (&vsi->xdp_state_lock); goto unlock_pf; err_rings:
@@ -3204,10 +3207,14 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, bool init_vsi)ice_vsi_init_vlan_ops (vsi); +mutex_lock (&vsi->xdp_state_lock); + coalesce =kcalloc (vsi->num_q_vectors,sizeof (struct ice_coalesce_stored ),GFP_KERNEL ); -if (!coalesce) +if (!coalesce) { +mutex_unlock (&vsi->xdp_state_lock);return -ENOMEM ; + } prev_num_q_vectors =ice_vsi_rebuild_get_coalesce (vsi, coalesce);
@@ -3230,7 +3237,7 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, bool init_vsi) vsi->base_vector =0 ; } -if (ice_is_xdp_ena_vsi (vsi)) +if (vsi->xdp_rings)/* return value check can be skipped here, it always returns * 0 if reset is in progress */
@@ -3358,24 +3365,31 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, bool init_vsi) ret = -EIO ; goto err_vectors; }else { +mutex_unlock (&vsi->xdp_state_lock);return ice_schedule_reset (pf,ICE_RESET_PFR ); } }ice_vsi_rebuild_set_coalesce (vsi, coalesce, prev_num_q_vectors); +clear_bit (ICE_VSI_REBUILD_PENDING , vsi->state);kfree (coalesce); +mutex_unlock (&vsi->xdp_state_lock);return 0 ; err_vectors:ice_vsi_free_q_vectors (vsi); err_rings: +mutex_unlock (&vsi->xdp_state_lock);if (vsi->netdev) { vsi->current_netdev_flags =0 ;unregister_netdev (vsi->netdev);free_netdev (vsi->netdev); vsi->netdev =NULL ; } + goto err_clear; err_vsi: +mutex_unlock (&vsi->xdp_state_lock); +err_clear:ice_vsi_clear (vsi);set_bit (ICE_RESET_FAILED , pf->state);kfree (coalesce);
drivers/net/ethernet/intel/ice/ice_main.c +15 -5
@@ -620,6 +620,7 @@ ice_prepare_for_reset(struct ice_pf *pf, enum ice_reset_req reset_type)/* clear SW filtering DB */ ice_clear_hw_tbls (hw);/* disable the VSIs and their queues that are not already DOWN */ +set_bit (ICE_VSI_REBUILD_PENDING ,ice_get_main_vsi (pf)->state);ice_pf_dis_all_vsi (pf, false);if (test_bit (ICE_FLAG_PTP_SUPPORTED , pf->flags))
@@ -2770,6 +2771,7 @@ int ice_prepare_xdp_rings(struct ice_vsi *vsi, struct bpf_prog *prog)mutex_unlock (&pf->avail_q_mutex);devm_kfree (dev, vsi->xdp_rings); + vsi->xdp_rings =NULL ;return -ENOMEM ; }
@@ -2919,7 +2921,8 @@ ice_xdp_setup_prog(struct ice_vsi *vsi, struct bpf_prog *prog, }/* hot swap progs and avoid toggling link */ -if (ice_is_xdp_ena_vsi (vsi) == !!prog) { +if (ice_is_xdp_ena_vsi (vsi) == !!prog || +test_bit (ICE_VSI_REBUILD_PENDING , vsi->state)) {ice_vsi_assign_bpf_prog (vsi, prog);return 0 ; }
@@ -2991,21 +2994,28 @@ static int ice_xdp(struct net_device *dev, struct netdev_bpf *xdp) {struct ice_netdev_priv *np =netdev_priv (dev);struct ice_vsi *vsi = np->vsi; +int ret;if (vsi->type !=ICE_VSI_PF ) {NL_SET_ERR_MSG_MOD (xdp->extack,"XDP can be loaded only on PF VSI" );return -EINVAL ; } +mutex_lock (&vsi->xdp_state_lock); +switch (xdp->command) {case XDP_SETUP_PROG : -return ice_xdp_setup_prog (vsi, xdp->prog, xdp->extack); + ret =ice_xdp_setup_prog (vsi, xdp->prog, xdp->extack); +break ;case XDP_SETUP_XSK_POOL : -return ice_xsk_pool_setup (vsi, xdp->xsk.pool, - xdp->xsk.queue_id); + ret =ice_xsk_pool_setup (vsi, xdp->xsk.pool, xdp->xsk.queue_id); +break ;default : -return -EINVAL ; + ret = -EINVAL ; } + +mutex_unlock (&vsi->xdp_state_lock); +return ret; }/**
drivers/net/ethernet/intel/ice/ice_xsk.c +2 -1
@@ -388,7 +388,8 @@ int ice_xsk_pool_setup(struct ice_vsi *vsi, struct xsk_buff_pool *pool, u16 qid) goto failure; } - if_running =netif_running (vsi->netdev) &&ice_is_xdp_ena_vsi (vsi); + if_running = !test_bit (ICE_VSI_DOWN , vsi->state) && +ice_is_xdp_ena_vsi (vsi);if (if_running) {struct ice_rx_ring *rx_ring = vsi->rx_rings[qid];
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 651/1887 userfaultfd: fix checks for huge PMDs
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jann Horn <[email protected]>
[ Upstream commit 71c186efc1b2cf1aeabfeff3b9bd5ac4c5ac14d8 ]
Patch series "userfaultfd: fix races around pmd_trans_huge() check", v2.
The pmd_trans_huge() code in mfill_atomic() is wrong in three different ways depending on kernel version:
1. The pmd_trans_huge() check is racy and can lead to a BUG_ON() (if you hit the right two race windows) - I've tested this in a kernel build with some extra mdelay() calls. See the commit message for a description of the race scenario.
On older kernels (before 6.5), I think the same bug can even theoretically lead to accessing transhuge page contents as a page table if you hit the right 5 narrow race windows (I haven't tested this case).
2. As pointed out by Qi Zheng, pmd_trans_huge() is not sufficient for detecting PMDs that don't point to page tables.
On older kernels (before 6.5), you'd just have to win a single fairly wide race to hit this.
I've tested this on 6.1 stable by racing migration (with a mdelay() patched into try_to_migrate()) against UFFDIO_ZEROPAGE - on my x86 VM, that causes a kernel oops in ptlock_ptr().
3. On newer kernels (>=6.5), for shmem mappings, khugepaged is allowed to yank page tables out from under us (though I haven't tested that), so I think the BUG_ON() checks in mfill_atomic() are just wrong.
I decided to write two separate fixes for these (one fix for bugs 1+2, one fix for bug 3), so that the first fix can be backported to kernels affected by bugs 1+2.
This patch (of 2):
This fixes two issues.
I discovered that the following race can occur:
mfill_atomic other thread
============ ============
<zap PMD>
pmdp_get_lockless() [reads none pmd]
<bail if trans_huge>
<if none:>
<pagefault creates transhuge zeropage>
__pte_alloc [no-op]
<zap PMD>
<bail if pmd_trans_huge(*dst_pmd)> BUG_ON(pmd_none(*dst_pmd))
I have experimentally verified this in a kernel with extra mdelay() calls; the BUG_ON(pmd_none(*dst_pmd)) triggers.
On kernels newer than commit 0d940a9b270b ("mm/pgtable: allow pte_offset_map[_lock]() to fail"), this can't lead to anything worse than a BUG_ON(), since the page table access helpers are actually designed to deal with page tables concurrently disappearing; but on older kernels (<=6.4), I think we could probably theoretically race past the two BUG_ON() checks and end up treating a hugepage as a page table.
The second issue is that, as Qi Zheng pointed out, there are other types of huge PMDs that pmd_trans_huge() can't catch: devmap PMDs and swap PMDs (in particular, migration PMDs).
On <=6.4, this is worse than the first issue: If mfill_atomic() runs on a PMD that contains a migration entry (which just requires winning a single, fairly wide race), it will pass the PMD to pte_offset_map_lock(), which assumes that the PMD points to a page table.
Breakage follows: First, the kernel tries to take the PTE lock (which will crash or maybe worse if there is no "struct page" for the address bits in the migration entry PMD - I think at least on X86 there usually is no corresponding "struct page" thanks to the PTE inversion mitigation, amd64 looks different).
If that didn't crash, the kernel would next try to write a PTE into what it wrongly thinks is a page table.
As part of fixing these issues, get rid of the check for pmd_trans_huge() before __pte_alloc() - that's redundant, we're going to have to check for that after the __pte_alloc() anyway.
Backport note: pmdp_get_lockless() is pmd_read_atomic() in older kernels.
--- mm/userfaultfd.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-)
mm/userfaultfd.c +12 -10
@@ -642,21 +642,23 @@ static __always_inline ssize_t __mcopy_atomic(struct mm_struct *dst_mm, } dst_pmdval =pmd_read_atomic (dst_pmd); -/* -* If the dst_pmd is mapped as THP don't -* override it and just be strict. -*/ -if (unlikely (pmd_trans_huge (dst_pmdval))) { - err = -EEXIST ; -break ; - }if (unlikely (pmd_none (dst_pmdval)) &&unlikely (__pte_alloc (dst_mm, dst_pmd))) { err = -ENOMEM ;break ; } -/* If an huge pmd materialized from under us fail */ -if (unlikely (pmd_trans_huge (*dst_pmd))) { + dst_pmdval =pmd_read_atomic (dst_pmd); +/* +* If the dst_pmd is THP don't override it and just be strict. +* (This includes the case where the PMD used to be THP and +* changed back to none after __pte_alloc().) +*/ +if (unlikely (!pmd_present (dst_pmdval) ||pmd_trans_huge (dst_pmdval) || +pmd_devmap (dst_pmdval))) { + err = -EEXIST ; +break ; + } +if (unlikely (pmd_bad (dst_pmdval))) { err = -EFAULT ;break ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 652/1887 drm/amd/display: Use kcalloc() instead of kzalloc()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lenko Donchev <[email protected]>
[ Upstream commit f634ee1737e7b856bd4c3f040af867007d1cb7b8 ]
We are trying to get rid of all multiplications from allocation functions to prevent integer overflows. Here the multiplication is obviously safe, but using kcalloc() is more appropriate and improves readability. This patch has no effect on runtime behavior.
Stable-dep-of: 5524fa301ba6 ("drm/amd/display: Add missing NULL pointer check within dpcd_extend_address_range")
--- drivers/gpu/drm/amd/display/dc/core/dc_link_dpcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/amd/display/dc/core/dc_link_dpcd.c +1 -1
@@ -161,7 +161,7 @@ static void dpcd_extend_address_range(if (new_addr_range.start != in_address || new_addr_range.end != end_address) { *out_address = new_addr_range.start; *out_size =ADDRESS_RANGE_SIZE (new_addr_range.start, new_addr_range.end); - *out_data =kzalloc (*out_size *sizeof (**out_data),GFP_KERNEL ); + *out_data =kcalloc (*out_size,sizeof (**out_data),GFP_KERNEL ); } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 653/1887 drm/amd/display: Add missing NULL pointer check within dpcd_extend_address_range
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hersen Wu <[email protected]>
[ Upstream commit 5524fa301ba649f8cf00848f91468e0ba7e4f24c ]
[Why & How]
ASSERT if return NULL from kcalloc.
--- drivers/gpu/drm/amd/display/dc/core/dc_link_dpcd.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/display/dc/core/dc_link_dpcd.c +1 -0
@@ -162,6 +162,7 @@ static void dpcd_extend_address_range( *out_address = new_addr_range.start; *out_size =ADDRESS_RANGE_SIZE (new_addr_range.start, new_addr_range.end); *out_data =kcalloc (*out_size,sizeof (**out_data),GFP_KERNEL ); +ASSERT (*out_data); } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 654/1887 drm/amd/display: Fix index may exceed array range within fpu_update_bw_bounding_box
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hersen Wu <[email protected]>
[ Upstream commit 188fd1616ec43033cedbe343b6579e9921e2d898 ]
[Why]
Coverity reports OVERRUN warning. soc.num_states could be 40. But array range of bw_params->clk_table.entries is 8.
[How]
Assert if soc.num_states greater than 8.
--- drivers/gpu/drm/amd/display/dc/dml/dcn302/dcn302_fpu.c | 10 ++++++++++ drivers/gpu/drm/amd/display/dc/dml/dcn303/dcn303_fpu.c | 10 ++++++++++ drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c | 10 ++++++++++ drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c | 10 ++++++++++ 4 files changed, 40 insertions(+)
drivers/gpu/drm/amd/display/dc/dml/dcn302/dcn302_fpu.c +10 -0
@@ -304,6 +304,16 @@ void dcn302_fpu_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_p dram_speed_mts[num_states++] = bw_params->clk_table.entries[j++].memclk_mhz *16 ; } +/* bw_params->clk_table.entries[MAX_NUM_DPM_LVL]. +* MAX_NUM_DPM_LVL is 8. +* dcn3_02_soc.clock_limits[DC__VOLTAGE_STATES]. +* DC__VOLTAGE_STATES is 40. +*/ +if (num_states >MAX_NUM_DPM_LVL ) { +ASSERT (0 ); +return ; + } + dcn3_02_soc.num_states = num_states;for (i =0 ; i < dcn3_02_soc.num_states; i++) { dcn3_02_soc.clock_limits[i].state = i;
drivers/gpu/drm/amd/display/dc/dml/dcn303/dcn303_fpu.c +10 -0
@@ -299,6 +299,16 @@ void dcn303_fpu_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_p dram_speed_mts[num_states++] = bw_params->clk_table.entries[j++].memclk_mhz *16 ; } +/* bw_params->clk_table.entries[MAX_NUM_DPM_LVL]. +* MAX_NUM_DPM_LVL is 8. +* dcn3_02_soc.clock_limits[DC__VOLTAGE_STATES]. +* DC__VOLTAGE_STATES is 40. +*/ +if (num_states >MAX_NUM_DPM_LVL ) { +ASSERT (0 ); +return ; + } + dcn3_03_soc.num_states = num_states;for (i =0 ; i < dcn3_03_soc.num_states; i++) { dcn3_03_soc.clock_limits[i].state = i;
drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c +10 -0
@@ -2508,6 +2508,16 @@ void dcn32_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_pa dram_speed_mts[num_states++] = bw_params->clk_table.entries[j++].memclk_mhz *16 ; } +/* bw_params->clk_table.entries[MAX_NUM_DPM_LVL]. +* MAX_NUM_DPM_LVL is 8. +* dcn3_02_soc.clock_limits[DC__VOLTAGE_STATES]. +* DC__VOLTAGE_STATES is 40. +*/ +if (num_states >MAX_NUM_DPM_LVL ) { +ASSERT (0 ); +return ; + } + dcn3_2_soc.num_states = num_states;for (i =0 ; i < dcn3_2_soc.num_states; i++) { dcn3_2_soc.clock_limits[i].state = i;
drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c +10 -0
@@ -652,6 +652,16 @@ void dcn321_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_p dram_speed_mts[num_states++] = bw_params->clk_table.entries[j++].memclk_mhz *16 ; } +/* bw_params->clk_table.entries[MAX_NUM_DPM_LVL]. +* MAX_NUM_DPM_LVL is 8. +* dcn3_02_soc.clock_limits[DC__VOLTAGE_STATES]. +* DC__VOLTAGE_STATES is 40. +*/ +if (num_states >MAX_NUM_DPM_LVL ) { +ASSERT (0 ); +return ; + } + dcn3_21_soc.num_states = num_states;for (i =0 ; i < dcn3_21_soc.num_states; i++) { dcn3_21_soc.clock_limits[i].state = i;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 655/1887 wifi: mt76: mt7921: fix NULL pointer access in mt7921_ipv6_addr_change
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bert Karwatzki <[email protected]>
[ Upstream commit 479ffee68d59c599f8aed8fa2dcc8e13e7bd13c3 ]
When disabling wifi mt7921_ipv6_addr_change() is called as a notifier. At this point mvif->phy is already NULL so we cannot use it here.
--- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/mt7921/main.c +1 -1
@@ -1436,7 +1436,7 @@ static void mt7921_ipv6_addr_change(struct ieee80211_hw *hw, struct inet6_dev *idev) {struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; -struct mt7921_dev *dev = mvif->phy->dev; +struct mt7921_dev *dev =mt7921_hw_dev (hw);struct inet6_ifaddr *ifa;struct in6_addr ns_addrs[IEEE80211_BSS_ARP_ADDR_LIST_LEN ];struct sk_buff *skb;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 656/1887 pinmux: Use sequential access to access desc->pinmux data
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mukesh Ojha <[email protected]>
[ Upstream commit 5a3e85c3c397c781393ea5fb2f45b1f60f8a4e6e ]
When two client of the same gpio call pinctrl_select_state() for the same functionality, we are seeing NULL pointer issue while accessing desc->mux_owner.
Let's say two processes A, B executing in pin_request() for the same pin and process A updates the desc->mux_usecount but not yet updated the desc->mux_owner while process B see the desc->mux_usecount which got updated by A path and further executes strcmp and while accessing desc->mux_owner it crashes with NULL pointer.
Serialize the access to mux related setting with a mutex lock.
cpu0 (process A) cpu1(process B)
pinctrl_select_state() { pinctrl_select_state() {
pin_request() { pin_request() {
...
....
} else {
desc->mux_usecount++;
desc->mux_usecount && strcmp(desc->mux_owner, owner)) {
if (desc->mux_usecount > 1)
return 0;
desc->mux_owner = owner;} }
--- drivers/pinctrl/core.c | 3 + drivers/pinctrl/core.h | 1 + drivers/pinctrl/pinmux.c | 173 ++++++++++++++++++++++----------------- 3 files changed, 100 insertions(+), 77 deletions(-)
drivers/pinctrl/core.c +3 -0
@@ -221,6 +221,9 @@ static int pinctrl_register_one_pin(struct pinctrl_dev *pctldev,/* Set owner */ pindesc->pctldev = pctldev; +#ifdef CONFIG_PINMUX +mutex_init (&pindesc->mux_lock); +#endif /* Copy basic pin info */ if (pin->name) {
drivers/pinctrl/core.h +1 -0
@@ -167,6 +167,7 @@ struct pin_desc {const char *mux_owner;const struct pinctrl_setting_mux *mux_setting;const char *gpio_owner; +struct mutex mux_lock;#endif };
drivers/pinctrl/pinmux.c +96 -77
245 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 657/1887 crypto: stm32/cryp - call finalize with bh disabled
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maxime Méré <[email protected]>
[ Upstream commit 56ddb9aa3b324c2d9645b5a7343e46010cf3f6ce ]
The finalize operation in interrupt mode produce a produces a spinlock recursion warning. The reason is the fact that BH must be disabled during this process.
--- drivers/crypto/stm32/stm32-cryp.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/crypto/stm32/stm32-cryp.c +6 -2
@@ -4,6 +4,7 @@* Author: Fabien Dessenne <[email protected]> */ +#include <linux/bottom_half.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/interrupt.h>
@@ -249,7 +250,7 @@ static inline int stm32_cryp_wait_output(struct stm32_cryp *cryp) {u32 status; -return readl_relaxed_poll_timeout (cryp->regs +CRYP_SR , status, +return readl_relaxed_poll_timeout_atomic (cryp->regs +CRYP_SR , status, status &SR_OFNE ,10 ,100000 ); }
@@ -1538,8 +1539,11 @@ static irqreturn_t stm32_cryp_irq_thread(int irq, void *arg) it_mask &= ~IMSCR_OUT ;stm32_cryp_write (cryp,CRYP_IMSCR , it_mask); -if (!cryp->payload_in && !cryp->header_in && !cryp->payload_out) +if (!cryp->payload_in && !cryp->header_in && !cryp->payload_out) { +local_bh_disable ();stm32_cryp_finish_req (cryp,0 ); +local_bh_enable (); + }return IRQ_HANDLED ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 658/1887 drm/amd/display: Refactor ABM feature
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leon Huang <[email protected]>
[ Upstream commit b8fe56375f78835db47565d91ea9d21767fe3c08 ]
[Why]
Refactor ABM feature and implement inbox command for DMUB.
[How]
Implement the ioctl to send inbox command to DMUB.
Stable-dep-of: d6b54900c564 ("drm/amd/display: Avoid overflow from uint32_t to uint8_t")
--- drivers/gpu/drm/amd/display/dc/dce/Makefile | 2 +- drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c | 264 +++++++--------- .../gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c | 286 ++++++++++++++++++ .../gpu/drm/amd/display/dc/dce/dmub_abm_lcd.h | 46 +++ drivers/gpu/drm/amd/display/dc/inc/hw/abm.h | 6 + 5 files changed, 442 insertions(+), 162 deletions(-) create mode 100644 drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c create mode 100644 drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.h
drivers/gpu/drm/amd/display/dc/dce/Makefile +1 -1
@@ -29,7 +29,7 @@ DCE = dce_audio.o dce_stream_encoder.o dce_link_encoder.o dce_hwseq.o \ dce_mem_input.o dce_clock_source.o dce_scl_filters.o dce_transform.o \ dce_opp.o dce_dmcu.o dce_abm.o dce_ipp.o dce_aux.o \ -dce_i2c.o dce_i2c_hw.o dce_i2c_sw.o dmub_psr.o dmub_abm.o dce_panel_cntl.o \ +dce_i2c.o dce_i2c_hw.o dce_i2c_sw.o dmub_psr.o dmub_abm.o dmub_abm_lcd.o dce_panel_cntl.o \ dmub_hw_lock_mgr.o dmub_outbox.o AMD_DAL_DCE = $(addprefix $(AMDDALPATH)/dc/dce/,$(DCE))
drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c +103 -161
331 lines not on this page · raw message
drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c new file +286 -0
286 lines not on this page · raw message
drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.h new file +46 -0
46 lines not on this page · raw message
drivers/gpu/drm/amd/display/dc/inc/hw/abm.h +6 -0
@@ -55,6 +55,12 @@ struct abm_funcs {unsigned int bytes, unsigned int inst);bool (*set_abm_pause)(struct abm *abm,bool pause,unsigned int panel_inst,unsigned int otg_inst); +bool (*set_pipe_ex)(struct abm *abm, +unsigned int otg_inst, +unsigned int option, +unsigned int panel_inst); +bool (*set_abm_event)(struct abm *abm,unsigned int full_screen,unsigned int video_mode, + unsigned int hdr_mode, unsigned int panel_inst); };#endif
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 659/1887 drm/amd/display: Avoid overflow from uint32_t to uint8_t
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Hung <[email protected]>
[ Upstream commit d6b54900c564e35989cf6813e4071504fa0a90e0 ]
[WHAT & HOW]
dmub_rb_cmd's ramping_boundary has size of uint8_t and it is assigned 0xFFFF. Fix it by changing it to uint8_t with value of 0xFF.
This fixes 2 INTEGER_OVERFLOW issues reported by Coverity.
--- drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c | 2 +- drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hwseq.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c +1 -1
@@ -242,7 +242,7 @@ bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, uint32_t option, uint {union dmub_rb_cmd cmd;struct dc_context *dc = abm->ctx; -uint32_t ramping_boundary =0xFFFF ; +uint8_t ramping_boundary =0xFF ;memset (&cmd,0 ,sizeof (cmd)); cmd.abm_set_pipe.header.type =DMUB_CMD__ABM ;
drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hwseq.c +1 -1
@@ -141,7 +141,7 @@ static bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, uint32_t optio {union dmub_rb_cmd cmd;struct dc_context *dc = abm->ctx; -uint32_t ramping_boundary =0xFFFF ; +uint8_t ramping_boundary =0xFF ;memset (&cmd,0 ,sizeof (cmd)); cmd.abm_set_pipe.header.type =DMUB_CMD__ABM ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 660/1887 spi: hisi-kunpeng: Convert to platform remove callback returning void
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uwe Kleine-König <[email protected]>
[ Upstream commit e77ccdfe0145211b5a20ab62950894aea881bbb3 ]
The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void.
Trivially convert this driver from always returning zero in the remove callback to the void returning variant.
Stable-dep-of: 5127c42c77de ("spi: hisi-kunpeng: Add verification for the max_frequency provided by the firmware")
--- drivers/spi/spi-hisi-kunpeng.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
drivers/spi/spi-hisi-kunpeng.c +2 -4
@@ -531,15 +531,13 @@ static int hisi_spi_probe(struct platform_device *pdev)return 0 ; } -static int hisi_spi_remove (struct platform_device *pdev) +static void hisi_spi_remove (struct platform_device *pdev) {struct spi_controller *master =platform_get_drvdata (pdev);struct hisi_spi *hs =spi_controller_get_devdata (master);debugfs_remove_recursive (hs->debugfs);spi_unregister_controller (master); - -return 0 ; }static const struct acpi_device_id hisi_spi_acpi_match[] = {
@@ -550,7 +548,7 @@ MODULE_DEVICE_TABLE(acpi, hisi_spi_acpi_match);static struct platform_driver hisi_spi_driver = { .probe = hisi_spi_probe, - .remove = hisi_spi_remove, + .remove_new = hisi_spi_remove, .driver = { .name ="hisi-kunpeng-spi" , .acpi_match_table = hisi_spi_acpi_match,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 661/1887 spi: hisi-kunpeng: switch to use modern name
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yang Yingliang <[email protected]>
[ Upstream commit 9f5890466e93a7392c618e50de53cdd3a0dd1fd5 ]
Change legacy name master to modern name host.
No functional changed.
Stable-dep-of: 5127c42c77de ("spi: hisi-kunpeng: Add verification for the max_frequency provided by the firmware")
--- drivers/spi/spi-hisi-kunpeng.c | 84 +++++++++++++++++----------------- 1 file changed, 42 insertions(+), 42 deletions(-)
drivers/spi/spi-hisi-kunpeng.c +42 -42
@@ -162,10 +162,10 @@ static int hisi_spi_debugfs_init(struct hisi_spi *hs) {char name[32 ]; -struct spi_controller *master; +struct spi_controller *host; - master = container_of(hs->dev, struct spi_controller, dev); -snprintf (name,32 ,"hisi_spi%d" , master->bus_num); + host = container_of(hs->dev, struct spi_controller, dev); +snprintf (name,32 ,"hisi_spi%d" , host->bus_num); hs->debugfs =debugfs_create_dir (name,NULL );if (!hs->debugfs)return -ENOMEM ;
@@ -299,18 +299,18 @@ static void __hisi_calc_div_reg(struct hisi_chip_data *chip) chip->div_post = (chip->clk_div / chip->div_pre) -1 ; } -static u32 hisi_calc_effective_speed (struct spi_controller *master, +static u32 hisi_calc_effective_speed (struct spi_controller *host,struct hisi_chip_data *chip,u32 speed_hz) {u32 effective_speed;/* Note clock divider doesn't support odd numbers */ - chip->clk_div =DIV_ROUND_UP (master->max_speed_hz, speed_hz) +1 ; + chip->clk_div =DIV_ROUND_UP (host->max_speed_hz, speed_hz) +1 ; chip->clk_div &=0xfffe ;if (chip->clk_div >CLK_DIV_MAX ) chip->clk_div =CLK_DIV_MAX ; - effective_speed = master->max_speed_hz / chip->clk_div; + effective_speed = host->max_speed_hz / chip->clk_div;if (chip->speed_hz != effective_speed) {__hisi_calc_div_reg (chip); chip->speed_hz = effective_speed;
@@ -344,20 +344,20 @@ static void hisi_spi_hw_init(struct hisi_spi *hs)static irqreturn_t hisi_spi_irq (int irq,void *dev_id) { -struct spi_controller *master = dev_id; -struct hisi_spi *hs =spi_controller_get_devdata (master); +struct spi_controller *host = dev_id; +struct hisi_spi *hs =spi_controller_get_devdata (host);u32 irq_status =readl (hs->regs +HISI_SPI_ISR ) &ISR_MASK ;if (!irq_status)return IRQ_NONE ; -if (!master->cur_msg) +if (!host->cur_msg)return IRQ_HANDLED ;/* Error handling */ if (irq_status &ISR_RXOF ) {dev_err (hs->dev,"interrupt_transfer: fifo overflow\n" ); - master->cur_msg->status = -EIO ; + host->cur_msg->status = -EIO ; goto finalize_transfer; }
@@ -377,20 +377,20 @@ static irqreturn_t hisi_spi_irq(int irq, void *dev_id) finalize_transfer:hisi_spi_disable (hs); -spi_finalize_current_transfer (master); +spi_finalize_current_transfer (host);return IRQ_HANDLED ; } -static int hisi_spi_transfer_one (struct spi_controller *master, +static int hisi_spi_transfer_one (struct spi_controller *host,struct spi_device *spi,struct spi_transfer *transfer) { -struct hisi_spi *hs =spi_controller_get_devdata (master); +struct hisi_spi *hs =spi_controller_get_devdata (host);struct hisi_chip_data *chip =spi_get_ctldata (spi);u32 cr = chip->cr;/* Update per transfer options for speed and bpw */ transfer->effective_speed_hz = -hisi_calc_effective_speed (master, chip, transfer->speed_hz); +hisi_calc_effective_speed (host, chip, transfer->speed_hz); cr |=FIELD_PREP (CR_DIV_PRE_MASK , chip->div_pre); cr |=FIELD_PREP (CR_DIV_POST_MASK , chip->div_post); cr |=FIELD_PREP (CR_BPW_MASK , transfer->bits_per_word -1 );
@@ -417,10 +417,10 @@ static int hisi_spi_transfer_one(struct spi_controller *master,return 1 ; } -static void hisi_spi_handle_err (struct spi_controller *master, +static void hisi_spi_handle_err (struct spi_controller *host,struct spi_message *msg) { -struct hisi_spi *hs =spi_controller_get_devdata (master); +struct hisi_spi *hs =spi_controller_get_devdata (host);hisi_spi_disable (hs);
@@ -460,7 +460,7 @@ static void hisi_spi_cleanup(struct spi_device *spi)static int hisi_spi_probe (struct platform_device *pdev) {struct device *dev = &pdev->dev; -struct spi_controller *master; +struct spi_controller *host;struct hisi_spi *hs;int ret, irq;
@@ -468,13 +468,13 @@ static int hisi_spi_probe(struct platform_device *pdev)if (irq <0 )return irq; - master =devm_spi_alloc_master (dev,sizeof (*hs)); -if (!master) + host =devm_spi_alloc_host (dev,sizeof (*hs)); +if (!host)return -ENOMEM ; -platform_set_drvdata (pdev, master); +platform_set_drvdata (pdev, host); - hs =spi_controller_get_devdata (master); + hs =spi_controller_get_devdata (host); hs->dev = dev; hs->irq = irq;
@@ -482,9 +482,9 @@ static int hisi_spi_probe(struct platform_device *pdev)if (IS_ERR (hs->regs))return PTR_ERR (hs->regs); -/* Specify maximum SPI clocking speed (master only) by firmware */ +/* Specify maximum SPI clocking speed (host only) by firmware */ ret =device_property_read_u32 (dev,"spi-max-frequency" , - &master->max_speed_hz); + &host->max_speed_hz);if (ret) {dev_err (dev,"failed to get max SPI clocking speed, ret=%d\n" , ret);
@@ -492,32 +492,32 @@ static int hisi_spi_probe(struct platform_device *pdev) } ret =device_property_read_u16 (dev,"num-cs" , - &master->num_chipselect); + &host->num_chipselect);if (ret) - master->num_chipselect =DEFAULT_NUM_CS ; - - master->use_gpio_descriptors = true; - master->mode_bits =SPI_CPOL |SPI_CPHA |SPI_CS_HIGH |SPI_LOOP ; - master->bits_per_word_mask =SPI_BPW_RANGE_MASK (4 ,32 ); - master->bus_num = pdev->id; - master->setup = hisi_spi_setup; - master->cleanup = hisi_spi_cleanup; - master->transfer_one = hisi_spi_transfer_one; - master->handle_err = hisi_spi_handle_err; - master->dev.fwnode = dev->fwnode; + host->num_chipselect =DEFAULT_NUM_CS ; + + host->use_gpio_descriptors = true; + host->mode_bits =SPI_CPOL |SPI_CPHA |SPI_CS_HIGH |SPI_LOOP ; + host->bits_per_word_mask =SPI_BPW_RANGE_MASK (4 ,32 ); + host->bus_num = pdev->id; + host->setup = hisi_spi_setup; + host->cleanup = hisi_spi_cleanup; + host->transfer_one = hisi_spi_transfer_one; + host->handle_err = hisi_spi_handle_err; + host->dev.fwnode = dev->fwnode;hisi_spi_hw_init (hs); ret =devm_request_irq (dev, hs->irq, hisi_spi_irq,0 ,dev_name (dev), - master); + host);if (ret <0 ) {dev_err (dev,"failed to get IRQ=%d, ret=%d\n" , hs->irq, ret);return ret; } - ret =spi_register_controller (master); + ret =spi_register_controller (host);if (ret) { -dev_err (dev,"failed to register spi master, ret=%d\n" , ret); +dev_err (dev,"failed to register spi host, ret=%d\n" , ret);return ret; }
@@ -526,18 +526,18 @@ static int hisi_spi_probe(struct platform_device *pdev)dev_info (dev,"hw version:0x%x max-freq:%u kHz\n" ,readl (hs->regs +HISI_SPI_VERSION ), - master->max_speed_hz /1000 ); + host->max_speed_hz /1000 );return 0 ; }static void hisi_spi_remove (struct platform_device *pdev) { -struct spi_controller *master =platform_get_drvdata (pdev); -struct hisi_spi *hs =spi_controller_get_devdata (master); +struct spi_controller *host =platform_get_drvdata (pdev); +struct hisi_spi *hs =spi_controller_get_devdata (host);debugfs_remove_recursive (hs->debugfs); -spi_unregister_controller (master); +spi_unregister_controller (host); }static const struct acpi_device_id hisi_spi_acpi_match[] = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 662/1887 spi: hisi-kunpeng: Add verification for the max_frequency provided by the firmware
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Devyn Liu <[email protected]>
[ Upstream commit 5127c42c77de18651aa9e8e0a3ced190103b449c ]
If the value of max_speed_hz is 0, it may cause a division by zero error in hisi_calc_effective_speed().
The value of max_speed_hz is provided by firmware.
Firmware is generally considered as a trusted domain. However, as division by zero errors can cause system failure, for defense measure, the value of max_speed is validated here. So 0 is regarded as invalid and an error code is returned.
--- drivers/spi/spi-hisi-kunpeng.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/spi/spi-hisi-kunpeng.c +3 -0
@@ -491,6 +491,9 @@ static int hisi_spi_probe(struct platform_device *pdev)return -EINVAL ; } +if (host->max_speed_hz ==0 ) +return dev_err_probe (dev, -EINVAL ,"spi-max-frequency can't be 0\n" ); + ret =device_property_read_u16 (dev,"num-cs" , &host->num_chipselect);if (ret)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 663/1887 media: mediatek: vcodec: Fix H264 stateless decoder smatch warning
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yunfei Dong <[email protected]>
[ Upstream commit 7878d3a385efab560dce793b595447867fb163f2 ]
Fix a smatch static checker warning on vdec_h264_req_if.c. Which leads to a kernel crash when fb is NULL.
--- .../platform/mediatek/vcodec/vdec/vdec_h264_req_if.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_if.c +7 -2
@@ -352,11 +352,16 @@ static int vdec_h264_slice_decode(void *h_vdec, struct mtk_vcodec_mem *bs,return vpu_dec_reset (vpu); fb = inst->ctx->dev->vdec_pdata->get_cap_buffer (inst->ctx); +if (!fb) { +mtk_vcodec_err (inst,"fb buffer is NULL" ); +return -ENOMEM ; + } + src_buf_info = container_of(bs, struct mtk_video_dec_buf, bs_buffer); dst_buf_info = container_of(fb, struct mtk_video_dec_buf, frame_buffer); - y_fb_dma = fb ? (u64 )fb->base_y.dma_addr :0 ; - c_fb_dma = fb ? (u64 )fb->base_c.dma_addr :0 ; + y_fb_dma = fb->base_y.dma_addr; + c_fb_dma = fb->base_c.dma_addr;mtk_vcodec_debug (inst,"+ [%d] FB y_dma=%llx c_dma=%llx va=%p" , inst->num_nalu, y_fb_dma, c_fb_dma, fb);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 664/1887 bpf: Prevent tailcall infinite loop caused by freplace
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leon Hwang <[email protected]>
[ Upstream commit d6083f040d5d8f8d748462c77e90547097df936e ]
There is a potential infinite loop issue that can occur when using a combination of tail calls and freplace.
In an upcoming selftest, the attach target for entry_freplace of tailcall_freplace.c is subprog_tc of tc_bpf2bpf.c, while the tail call in entry_freplace leads to entry_tc. This results in an infinite loop:
entry_tc -> subprog_tc -> entry_freplace --tailcall-> entry_tc.
The problem arises because the tail_call_cnt in entry_freplace resets to zero each time entry_freplace is executed, causing the tail call mechanism to never terminate, eventually leading to a kernel panic.
To fix this issue, the solution is twofold:
1. Prevent updating a program extended by an freplace program to a prog_array map.
2. Prevent extending a program that is already part of a prog_array map with an freplace program.
This ensures that:
* If a program or its subprogram has been extended by an freplace program, it can no longer be updated to a prog_array map.
* If a program has been added to a prog_array map, neither it nor its subprograms can be extended by an freplace program.
Moreover, an extension program should not be tailcalled. As such, return -EINVAL if the program has a type of BPF_PROG_TYPE_EXT when adding it to a prog_array map.
Additionally, fix a minor code style issue by replacing eight spaces with a tab for proper formatting.
--- include/linux/bpf.h | 17 +++++++++++---- kernel/bpf/arraymap.c | 26 +++++++++++++++++++++-- kernel/bpf/core.c | 1 + kernel/bpf/syscall.c | 7 +++--- kernel/bpf/trampoline.c | 47 ++++++++++++++++++++++++++++++++++------- 5 files changed, 81 insertions(+), 17 deletions(-)
include/linux/bpf.h +13 -4
@@ -1014,8 +1014,12 @@ static __always_inline __nocfi unsigned int bpf_dispatcher_nop_func( }#ifdef CONFIG_BPF_JIT -int bpf_trampoline_link_prog (struct bpf_tramp_link *link,struct bpf_trampoline *tr); -int bpf_trampoline_unlink_prog (struct bpf_tramp_link *link,struct bpf_trampoline *tr); +int bpf_trampoline_link_prog (struct bpf_tramp_link *link, +struct bpf_trampoline *tr, +struct bpf_prog *tgt_prog); +int bpf_trampoline_unlink_prog (struct bpf_tramp_link *link, +struct bpf_trampoline *tr, +struct bpf_prog *tgt_prog);struct bpf_trampoline *bpf_trampoline_get (u64 key,struct bpf_attach_target_info *tgt_info);void bpf_trampoline_put (struct bpf_trampoline *tr);
@@ -1096,12 +1100,14 @@ void bpf_jit_uncharge_modmem(u32 size);bool bpf_prog_has_trampoline (const struct bpf_prog *prog);#else static inline int bpf_trampoline_link_prog (struct bpf_tramp_link *link, -struct bpf_trampoline *tr) +struct bpf_trampoline *tr, +struct bpf_prog *tgt_prog) {return -ENOTSUPP ; }static inline int bpf_trampoline_unlink_prog (struct bpf_tramp_link *link, -struct bpf_trampoline *tr) +struct bpf_trampoline *tr, +struct bpf_prog *tgt_prog) {return -ENOTSUPP ; }
@@ -1198,6 +1204,9 @@ struct bpf_prog_aux {bool sleepable;bool tail_call_reachable;bool xdp_has_frags; +bool is_extended;/* true if extended by freplace program */ +u64 prog_array_member_cnt;/* counts how many times as member of prog_array */ +struct mutex ext_mutex;/* mutex for is_extended and prog_array_member_cnt */ /* BTF_KIND_FUNC_PROTO for valid attach_btf_id */ const struct btf_type *attach_func_proto;/* function name for valid attach_btf_id */
kernel/bpf/arraymap.c +24 -2
@@ -889,22 +889,44 @@ static void *prog_fd_array_get_ptr(struct bpf_map *map, struct file *map_file, int fd) {struct bpf_prog *prog =bpf_prog_get (fd); +bool is_extended;if (IS_ERR (prog))return prog; -if (!bpf_prog_map_compatible (map, prog)) { +if (prog->type ==BPF_PROG_TYPE_EXT || + !bpf_prog_map_compatible (map, prog)) {bpf_prog_put (prog);return ERR_PTR (-EINVAL ); } +mutex_lock (&prog->aux->ext_mutex); + is_extended = prog->aux->is_extended; +if (!is_extended) + prog->aux->prog_array_member_cnt++; +mutex_unlock (&prog->aux->ext_mutex); +if (is_extended) { +/* Extended prog can not be tail callee. It's to prevent a +* potential infinite loop like: +* tail callee prog entry -> tail callee prog subprog -> +* freplace prog entry --tailcall-> tail callee prog entry. +*/ +bpf_prog_put (prog); +return ERR_PTR (-EBUSY ); + } +return prog; }static void prog_fd_array_put_ptr (struct bpf_map *map,void *ptr,bool need_defer) { +struct bpf_prog *prog = ptr; + +mutex_lock (&prog->aux->ext_mutex); + prog->aux->prog_array_member_cnt--; +mutex_unlock (&prog->aux->ext_mutex);/* bpf_prog is freed after one RCU or tasks trace grace period */ -bpf_prog_put (ptr); +bpf_prog_put (prog); }static u32 prog_fd_array_sys_lookup_elem (void *ptr)
kernel/bpf/core.c +1 -0
@@ -117,6 +117,7 @@ struct bpf_prog *bpf_prog_alloc_no_stats(unsigned int size, gfp_t gfp_extra_flagINIT_LIST_HEAD_RCU (&fp->aux->ksym.lnode);mutex_init (&fp->aux->used_maps_mutex); +mutex_init (&fp->aux->ext_mutex);mutex_init (&fp->aux->dst_mutex);return fp;
kernel/bpf/syscall.c +4 -3
@@ -2980,7 +2980,8 @@ static void bpf_tracing_link_release(struct bpf_link *link) container_of(link, struct bpf_tracing_link, link.link);WARN_ON_ONCE (bpf_trampoline_unlink_prog (&tr_link->link, - tr_link->trampoline)); + tr_link->trampoline, + tr_link->tgt_prog));bpf_trampoline_put (tr_link->trampoline);
@@ -3108,7 +3109,7 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog,* in prog->aux * * - if prog->aux->dst_trampoline is NULL, the program has already been -* attached to a target and its initial target was cleared (below) +* attached to a target and its initial target was cleared (below) * * - if tgt_prog != NULL, the caller specified tgt_prog_fd + * target_btf_id using the link_create API.
@@ -3178,7 +3179,7 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog,if (err) goto out_unlock; - err =bpf_trampoline_link_prog (&link->link, tr); + err =bpf_trampoline_link_prog (&link->link, tr, tgt_prog);if (err) {bpf_link_cleanup (&link_primer); link =NULL ;
kernel/bpf/trampoline.c +39 -8
101 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 665/1887 nvme-rdma: unquiesce admin_q before destroy it
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chunguang.xu <[email protected]>
[ Upstream commit 5858b687559809f05393af745cbadf06dee61295 ]
Kernel will hang on destroy admin_q while we create ctrl failed, such as following calltrace:
PID: 23644 TASK: ff2d52b40f439fc0 CPU: 2 COMMAND: "nvme"
#0 [ff61d23de260fb78] __schedule at ffffffff8323bc15
#1 [ff61d23de260fc08] schedule at ffffffff8323c014
#2 [ff61d23de260fc28] blk_mq_freeze_queue_wait at ffffffff82a3dba1 #3 [ff61d23de260fc78] blk_freeze_queue at ffffffff82a4113a #4 [ff61d23de260fc90] blk_cleanup_queue at ffffffff82a33006 #5 [ff61d23de260fcb0] nvme_rdma_destroy_admin_queue at ffffffffc12686ce #6 [ff61d23de260fcc8] nvme_rdma_setup_ctrl at ffffffffc1268ced #7 [ff61d23de260fd28] nvme_rdma_create_ctrl at ffffffffc126919b #8 [ff61d23de260fd68] nvmf_dev_write at ffffffffc024f362
#9 [ff61d23de260fe38] vfs_write at ffffffff827d5f25
RIP: 00007fda7891d574 RSP: 00007ffe2ef06958 RFLAGS: 00000202
RAX: ffffffffffffffda RBX: 000055e8122a4d90 RCX: 00007fda7891d574
RDX: 000000000000012b RSI: 000055e8122a4d90 RDI: 0000000000000004
RBP: 00007ffe2ef079c0 R8: 000000000000012b R9: 000055e8122a4d90
R10: 0000000000000000 R11: 0000000000000202 R12: 0000000000000004
R13: 000055e8122923c0 R14: 000000000000012b R15: 00007fda78a54500
ORIG_RAX: 0000000000000001 CS: 0033 SS: 002bThis due to we have quiesced admi_q before cancel requests, but forgot to unquiesce before destroy it, as a result we fail to drain the pending requests, and hang on blk_mq_freeze_queue_wait() forever. Here try to reuse nvme_rdma_teardown_admin_queue() to fix this issue and simplify the code.
--- drivers/nvme/host/rdma.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-)
drivers/nvme/host/rdma.c +1 -7
@@ -1120,13 +1120,7 @@ static int nvme_rdma_setup_ctrl(struct nvme_rdma_ctrl *ctrl, bool new)nvme_rdma_free_io_queues (ctrl); } destroy_admin: -nvme_stop_admin_queue (&ctrl->ctrl); -blk_sync_queue (ctrl->ctrl.admin_q); -nvme_rdma_stop_queue (&ctrl->queues[0 ]); -nvme_cancel_admin_tagset (&ctrl->ctrl); -if (new) -nvme_remove_admin_tag_set (&ctrl->ctrl); -nvme_rdma_destroy_admin_queue (ctrl); +nvme_rdma_teardown_admin_queue (ctrl, new);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 666/1887 drm/amd/display: Check null pointer before try to access it
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rodrigo Siqueira <[email protected]>
[ Upstream commit 1b686053c06ffb9f4524b288110cf2a831ff7a25 ]
[why & how]
Change the order of the pipe_ctx->plane_state check to ensure that plane_state is not null before accessing it.
--- drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +5 -5
@@ -1696,13 +1696,13 @@ static void dcn20_program_pipe(if (pipe_ctx->update_flags.raw || pipe_ctx->plane_state->update_flags.raw || pipe_ctx->stream->update_flags.raw)dcn20_update_dchubp_dpp (dc, pipe_ctx, context); -if (pipe_ctx->update_flags.bits.enable - || pipe_ctx->plane_state->update_flags.bits.hdr_mult) +if ((pipe_ctx->plane_state && pipe_ctx->plane_state->update_flags.bits.hdr_mult) || + pipe_ctx->update_flags.bits.enable) hws->funcs.set_hdr_multiplier (pipe_ctx); -if (pipe_ctx->update_flags.bits.enable || - pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || - pipe_ctx->plane_state->update_flags.bits.gamma_change) +if ((pipe_ctx->plane_state && pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change) || + (pipe_ctx->plane_state && pipe_ctx->plane_state->update_flags.bits.gamma_change) || + pipe_ctx->update_flags.bits.enable) hws->funcs.set_input_transfer_func (dc, pipe_ctx, pipe_ctx->plane_state);/* dcn10_translate_regamma_to_hw_format takes 750us to finish
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 667/1887 drm/amd/display: Add null check for pipe_ctx->plane_state in dcn20_program_pipe
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Srinivasan Shanmugam <[email protected]>
[ Upstream commit 8e4ed3cf1642df0c4456443d865cff61a9598aa8 ]
This commit addresses a null pointer dereference issue in the dcn20_program_pipe function. The issue could occur when pipe_ctx->plane_state is null.
The fix adds a check to ensure pipe_ctx->plane_state is not null before accessing. This prevents a null pointer dereference.
Reported by smatch:drivers/gpu/drm/amd/amdgpu/../display/dc/hwss/dcn20/dcn20_hwseq.c:1925 dcn20_program_pipe() error: we previously assumed 'pipe_ctx->plane_state' could be null (see line 1877)
--- drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +3 -1
@@ -1693,7 +1693,9 @@ static void dcn20_program_pipe( dc->res_pool->hubbub->funcs->program_det_size ( dc->res_pool->hubbub, pipe_ctx->plane_res.hubp->inst, pipe_ctx->det_buffer_size_kb); -if (pipe_ctx->update_flags.raw || pipe_ctx->plane_state->update_flags.raw || pipe_ctx->stream->update_flags.raw) +if (pipe_ctx->update_flags.raw || + (pipe_ctx->plane_state && pipe_ctx->plane_state->update_flags.raw) || + pipe_ctx->stream->update_flags.raw)dcn20_update_dchubp_dpp (dc, pipe_ctx, context); if ((pipe_ctx->plane_state && pipe_ctx->plane_state->update_flags.bits.hdr_mult) ||
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 668/1887 drm/amd/display: Add null check for head_pipe in dcn32_acquire_idle_pipe_for_head_pipe_in_layer
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Srinivasan Shanmugam <[email protected]>
[ Upstream commit ac2140449184a26eac99585b7f69814bd3ba8f2d ]
This commit addresses a potential null pointer dereference issue in the dcn32_acquire_idle_pipe_for_head_pipe_in_layer function. The issue could occur when head_pipe is null.
The fix adds a check to ensure head_pipe is not null before asserting it. If head_pipe is null, the function returns NULL to prevent a potential null pointer dereference.
Reported by smatch:drivers/gpu/drm/amd/amdgpu/../display/dc/resource/dcn32/dcn32_resource.c:2690 dcn32_acquire_idle_pipe_for_head_pipe_in_layer() error: we previously assumed 'head_pipe' could be null (see line 2681)
--- drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c +3 -1
@@ -2563,8 +2563,10 @@ struct pipe_ctx *dcn32_acquire_idle_pipe_for_head_pipe_in_layer(struct resource_context *old_ctx = &stream->ctx->dc->current_state->res_ctx;int head_index; -if (!head_pipe) +if (!head_pipe) {ASSERT (0 ); +return NULL ; + }/* * Modified from dcn20_acquire_idle_pipe_for_layer
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 669/1887 drm/amd/display: Add null check for head_pipe in dcn201_acquire_free_pipe_for_layer
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Srinivasan Shanmugam <[email protected]>
[ Upstream commit f22f4754aaa47d8c59f166ba3042182859e5dff7 ]
This commit addresses a potential null pointer dereference issue in the dcn201_acquire_free_pipe_for_layer function. The issue could occur when head_pipe is null.
The fix adds a check to ensure head_pipe is not null before asserting it. If head_pipe is null, the function returns NULL to prevent a potential null pointer dereference.
Reported by smatch:drivers/gpu/drm/amd/amdgpu/../display/dc/resource/dcn201/dcn201_resource.c:1016 dcn201_acquire_free_pipe_for_layer() error: we previously assumed 'head_pipe' could be null (see line 1010)
--- drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c +3 -1
@@ -1009,8 +1009,10 @@ static struct pipe_ctx *dcn201_acquire_idle_pipe_for_layer(struct pipe_ctx *head_pipe =resource_get_head_pipe_for_stream (res_ctx, stream);struct pipe_ctx *idle_pipe =find_idle_secondary_pipe (res_ctx, pool, head_pipe); -if (!head_pipe) +if (!head_pipe) {ASSERT (0 ); +return NULL ; + }if (!idle_pipe)return NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 670/1887 drm/amd/display: Check null pointers before multiple uses
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Hung <[email protected]>
[ Upstream commit fdd5ecbbff751c3b9061d8ebb08e5c96119915b4 ]
[WHAT & HOW]
Poniters, such as stream_enc and dc->bw_vbios, are null checked previously in the same function, so Coverity warns "implies that stream_enc and dc->bw_vbios might be null". They are used multiple times in the subsequent code and need to be checked.
This fixes 10 FORWARD_NULL issues reported by Coverity.
--- drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 5 ++++- drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c | 5 ++++- drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c | 3 +++ drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c | 3 +++ drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.c | 5 ++++- 5 files changed, 18 insertions(+), 3 deletions(-)
drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +4 -1
@@ -6187,8 +6187,11 @@ bool dc_link_dp_set_test_pattern(break ; } +if (!pipe_ctx->stream) +return false; +if (pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_enable) { -if (pipe_ctx->stream &&should_use_dmub_lock (pipe_ctx->stream->link)) { +if (should_use_dmub_lock (pipe_ctx->stream->link)) {union dmub_hw_lock_flags hw_locks = {0 };struct dmub_hw_lock_inst_flags inst_flags = {0 };
drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +4 -1
@@ -1065,7 +1065,10 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc)struct dm_pp_clock_levels clks = {0 };int memory_type_multiplier =MEMORY_TYPE_MULTIPLIER_CZ ; -if (dc->bw_vbios && dc->bw_vbios->memory_type == bw_def_hbm) +if (!dc->bw_vbios) +return ; + +if (dc->bw_vbios->memory_type == bw_def_hbm) memory_type_multiplier =MEMORY_TYPE_HBM ;/*do system clock TODO PPLIB: after PPLIB implement,
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +3 -0
@@ -2139,6 +2139,9 @@ bool dcn20_wait_for_blank_complete( {int counter; +if (!opp) +return false; +for (counter =0 ; counter <1000 ; counter++) {if (opp->funcs->dpg_is_blanked (opp))break ;
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c +3 -0
@@ -1664,6 +1664,9 @@ static void dcn32_enable_phantom_plane(struct dc *dc,else phantom_plane =dc_create_plane_state (dc); +if (!phantom_plane) +break ; +memcpy (&phantom_plane->address, &curr_pipe->plane_state->address,sizeof (phantom_plane->address));memcpy (&phantom_plane->scaling_quality, &curr_pipe->plane_state->scaling_quality,sizeof (phantom_plane->scaling_quality));
drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.c +4 -1
@@ -56,7 +56,10 @@ void reset_dio_stream_encoder(struct pipe_ctx *pipe_ctx)struct link_encoder *link_enc =link_enc_cfg_get_link_enc (pipe_ctx->stream->link);struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc; -if (stream_enc && stream_enc->funcs->disable_fifo) +if (!stream_enc) +return ; + +if (stream_enc->funcs->disable_fifo) stream_enc->funcs->disable_fifo (stream_enc); link_enc->funcs->connect_dig_be_to_fe(
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 671/1887 drm/amd/display: Check null pointers before used
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Hung <[email protected]>
[ Upstream commit be1fb44389ca3038ad2430dac4234669bc177ee3 ]
[WHAT & HOW]
Poniters, such as dc->clk_mgr, are null checked previously in the same function, so Coverity warns "implies that "dc->clk_mgr" might be null". As a result, these pointers need to be checked when used again.
This fixes 10 FORWARD_NULL issues reported by Coverity.
--- .../gpu/drm/amd/display/dc/clk_mgr/dce110/dce110_clk_mgr.c | 2 +- drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 2 +- drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c | 5 +++-- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c | 3 ++- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 4 ++-- drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c | 3 ++- drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c | 4 ++-- 7 files changed, 13 insertions(+), 10 deletions(-)
drivers/gpu/drm/amd/display/dc/clk_mgr/dce110/dce110_clk_mgr.c +1 -1
@@ -218,7 +218,7 @@ void dce11_pplib_apply_display_requirements(* , then change minimum memory clock based on real-time bandwidth * limitation. */ - if ((dc->ctx->asic_id.chip_family == FAMILY_AI) && + if (dc->bw_vbios && (dc->ctx->asic_id.chip_family == FAMILY_AI) && ASICREV_IS_VEGA20_P(dc->ctx->asic_id.hw_internal_rev) && (context->stream_count >= 2)) { pp_display_cfg->min_memory_clock_khz = max(pp_display_cfg->min_memory_clock_khz, (uint32_t) div64_s64(
drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +1 -1
@@ -3330,7 +3330,7 @@ bool dp_verify_link_cap_with_retries(memset (&link->verified_link_cap,0 ,sizeof (struct dc_link_settings )); -if (!dc_link_detect_sink (link, &type) || type == dc_connection_none) { +if (link->link_enc && (!dc_link_detect_sink (link, &type) || type == dc_connection_none)) { link->verified_link_cap = fail_safe_link_settings;break ; } else if (dp_verify_link_cap(link, known_limit_link_setting,
drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +3 -2
@@ -963,7 +963,7 @@ void dce110_edp_backlight_control( {struct dc_context *ctx = link->ctx;struct bp_transmitter_control cntl = {0 }; -uint8_t panel_instance; +uint8_t panel_instance =0 ;unsigned int pre_T11_delay =OLED_PRE_T11_DELAY ;unsigned int post_T7_delay =OLED_POST_T7_DELAY ;
@@ -1016,7 +1016,8 @@ void dce110_edp_backlight_control(*/ /* dc_service_sleep_in_milliseconds(50); */ /*edp 1.2*/ - panel_instance = link->panel_cntl->inst; +if (link->panel_cntl) + panel_instance = link->panel_cntl->inst;if (cntl.action ==TRANSMITTER_CONTROL_BACKLIGHT_ON ) {if (!link->dc->config.edp_no_power_sequencing)
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c +2 -1
@@ -749,7 +749,8 @@ bool hubp1_is_flip_pending(struct hubp *hubp)if (flip_pending)return true; -if (earliest_inuse_address.grph.addr.quad_part != hubp->request_address.grph.addr.quad_part) +if (hubp && + earliest_inuse_address.grph.addr.quad_part != hubp->request_address.grph.addr.quad_part)return true;return false;
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +2 -2
@@ -1490,7 +1490,7 @@ void dcn10_init_hw(struct dc *dc) dc->clk_mgr->funcs->init_clocks (dc->clk_mgr);/* Align bw context with hw config when system resume. */ -if (dc->clk_mgr->clks.dispclk_khz !=0 && dc->clk_mgr->clks.dppclk_khz !=0 ) { +if (dc->clk_mgr && dc->clk_mgr->clks.dispclk_khz !=0 && dc->clk_mgr->clks.dppclk_khz !=0 ) { dc->current_state->bw_ctx.bw.dcn.clk.dispclk_khz = dc->clk_mgr->clks.dispclk_khz; dc->current_state->bw_ctx.bw.dcn.clk.dppclk_khz = dc->clk_mgr->clks.dppclk_khz; }
@@ -1630,7 +1630,7 @@ void dcn10_init_hw(struct dc *dc)REG_UPDATE (DCFCLK_CNTL ,DCFCLK_GATE_DIS ,0 ); } -if (dc->clk_mgr->funcs->notify_wm_ranges) +if (dc->clk_mgr && dc->clk_mgr->funcs->notify_wm_ranges) dc->clk_mgr->funcs->notify_wm_ranges (dc->clk_mgr); }
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c +2 -1
@@ -925,7 +925,8 @@ bool hubp2_is_flip_pending(struct hubp *hubp)if (flip_pending)return true; -if (earliest_inuse_address.grph.addr.quad_part != hubp->request_address.grph.addr.quad_part) +if (hubp && + earliest_inuse_address.grph.addr.quad_part != hubp->request_address.grph.addr.quad_part)return true;return false;
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c +2 -2
@@ -281,10 +281,10 @@ void dcn31_init_hw(struct dc *dc)if (!dcb->funcs->is_accelerated_mode (dcb) && dc->res_pool->hubbub->funcs->init_watermarks) dc->res_pool->hubbub->funcs->init_watermarks (dc->res_pool->hubbub); -if (dc->clk_mgr->funcs->notify_wm_ranges) +if (dc->clk_mgr && dc->clk_mgr->funcs->notify_wm_ranges) dc->clk_mgr->funcs->notify_wm_ranges (dc->clk_mgr); -if (dc->clk_mgr->funcs->set_hard_max_memclk && !dc->clk_mgr->dc_mode_softmax_enabled) +if (dc->clk_mgr && dc->clk_mgr->funcs->set_hard_max_memclk && !dc->clk_mgr->dc_mode_softmax_enabled) dc->clk_mgr->funcs->set_hard_max_memclk (dc->clk_mgr);if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 672/1887 drm/amd/display: Check null pointers before using them
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Hung <[email protected]>
[ Upstream commit 1ff12bcd7deaeed25efb5120433c6a45dd5504a8 ]
[WHAT & HOW]
These pointers are null checked previously in the same function, indicating they might be null as reported by Coverity. As a result, they need to be checked when used again.
This fixes 3 FORWARD_NULL issue reported by Coverity.
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +4 -3
@@ -8628,9 +8628,10 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)DRM_INFO ("[HDCP_DM] hdcp_update_display enable_encryption = %x\n" , enable_encryption); -hdcp_update_display ( - adev->dm.hdcp_workqueue, aconnector->dc_link->link_index, aconnector, - new_con_state->hdcp_content_type, enable_encryption); +if (aconnector->dc_link) +hdcp_update_display ( + adev->dm.hdcp_workqueue, aconnector->dc_link->link_index, aconnector, + new_con_state->hdcp_content_type, enable_encryption); } }#endif
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 673/1887 drm/amd/display: Pass non-null to dcn20_validate_apply_pipe_split_flags
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Hung <[email protected]>
[ Upstream commit 5559598742fb4538e4c51c48ef70563c49c2af23 ]
[WHAT & HOW]
"dcn20_validate_apply_pipe_split_flags" dereferences merge, and thus it cannot be a null pointer. Let's pass a valid pointer to avoid null dereference.
This fixes 2 FORWARD_NULL issues reported by Coverity.
--- drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c | 3 ++- drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c +2 -1
@@ -2021,6 +2021,7 @@ bool dcn20_fast_validate_bw( {bool out = false;int split[MAX_PIPES ] = {0 }; +bool merge[MAX_PIPES ] = { false };int pipe_cnt, i, pipe_idx, vlevel;ASSERT (pipes);
@@ -2045,7 +2046,7 @@ bool dcn20_fast_validate_bw(if (vlevel > context->bw_ctx.dml.soc.num_states) goto validate_fail; - vlevel =dcn20_validate_apply_pipe_split_flags (dc, context, vlevel, split,NULL ); + vlevel =dcn20_validate_apply_pipe_split_flags (dc, context, vlevel, split, merge);/*initialize pipe_just_split_from to invalid idx*/ for (i =0 ; i <MAX_PIPES ; i++)
drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c +2 -1
@@ -818,6 +818,7 @@ bool dcn21_fast_validate_bw(struct dc *dc, {bool out = false;int split[MAX_PIPES ] = {0 }; +bool merge[MAX_PIPES ] = { false };int pipe_cnt, i, pipe_idx, vlevel;ASSERT (pipes);
@@ -860,7 +861,7 @@ bool dcn21_fast_validate_bw(struct dc *dc, goto validate_fail; } - vlevel =dcn20_validate_apply_pipe_split_flags (dc, context, vlevel, split,NULL ); + vlevel =dcn20_validate_apply_pipe_split_flags (dc, context, vlevel, split, merge);for (i =0 , pipe_idx =0 ; i < dc->res_pool->pipe_count; i++) {struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 674/1887 l2tp: prevent possible tunnel refcount underflow
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Chapman <[email protected]>
[ Upstream commit 24256415d18695b46da06c93135f5b51c548b950 ]
When a session is created, it sets a backpointer to its tunnel. When the session refcount drops to 0, l2tp_session_free drops the tunnel refcount if session->tunnel is non-NULL. However, session->tunnel is set in l2tp_session_create, before the tunnel refcount is incremented by l2tp_session_register, which leaves a small window where session->tunnel is non-NULL when the tunnel refcount hasn't been bumped.
Moving the assignment to l2tp_session_register is trivial but l2tp_session_create calls l2tp_session_set_header_len which uses session->tunnel to get the tunnel's encap. Add an encap arg to l2tp_session_set_header_len to avoid using session->tunnel.
If l2tpv3 sessions have colliding IDs, it is possible for l2tp_v3_session_get to race with l2tp_session_register and fetch a session which doesn't yet have session->tunnel set. Add a check for this case.
--- net/l2tp/l2tp_core.c | 16 ++++++++++------ net/l2tp/l2tp_core.h | 3 ++- net/l2tp/l2tp_netlink.c | 4 +++- net/l2tp/l2tp_ppp.c | 3 ++- 4 files changed, 17 insertions(+), 9 deletions(-)
net/l2tp/l2tp_core.c +10 -6
@@ -380,11 +380,13 @@ int l2tp_session_register(struct l2tp_session *session, }l2tp_tunnel_inc_refcount (tunnel); +WRITE_ONCE (session->tunnel, tunnel);hlist_add_head_rcu (&session->global_hlist, g_head);spin_unlock_bh (&pn->l2tp_session_hlist_lock); }else {l2tp_tunnel_inc_refcount (tunnel); +WRITE_ONCE (session->tunnel, tunnel); }hlist_add_head_rcu (&session->hlist, head);
@@ -698,7 +700,8 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,if (!session->lns_mode && !session->send_seq) {trace_session_seqnum_lns_enable (session); session->send_seq =1 ; -l2tp_session_set_header_len (session, tunnel->version); +l2tp_session_set_header_len (session, tunnel->version, + tunnel->encap); } }else {/* No sequence numbers.
@@ -719,7 +722,8 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,if (!session->lns_mode && session->send_seq) {trace_session_seqnum_lns_disable (session); session->send_seq =0 ; -l2tp_session_set_header_len (session, tunnel->version); +l2tp_session_set_header_len (session, tunnel->version, + tunnel->encap); }else if (session->send_seq) {pr_debug_ratelimited ("%s: recv data has no seq numbers when required. Discarding.\n" , session->name);
@@ -1579,7 +1583,8 @@ EXPORT_SYMBOL_GPL(l2tp_session_delete);/* We come here whenever a session's send_seq, cookie_len or * l2specific_type parameters are set. */ -void l2tp_session_set_header_len (struct l2tp_session *session,int version) +void l2tp_session_set_header_len (struct l2tp_session *session,int version, +enum l2tp_encap_type encap) {if (version ==L2TP_HDR_VER_2 ) { session->hdr_len =6 ;
@@ -1588,7 +1593,7 @@ void l2tp_session_set_header_len(struct l2tp_session *session, int version) }else { session->hdr_len =4 + session->cookie_len; session->hdr_len +=l2tp_get_l2specific_len (session); -if (session->tunnel->encap ==L2TP_ENCAPTYPE_UDP ) +if (encap ==L2TP_ENCAPTYPE_UDP ) session->hdr_len +=4 ; } }
@@ -1602,7 +1607,6 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn session =kzalloc (sizeof (*session) + priv_size,GFP_KERNEL );if (session) { session->magic =L2TP_SESSION_MAGIC ; - session->tunnel = tunnel; session->session_id = session_id; session->peer_session_id = peer_session_id;
@@ -1638,7 +1642,7 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnmemcpy (&session->peer_cookie[0 ], &cfg->peer_cookie[0 ], cfg->peer_cookie_len); } -l2tp_session_set_header_len (session, tunnel->version); +l2tp_session_set_header_len (session, tunnel->version, tunnel->encap);refcount_set (&session->ref_count,1 );
net/l2tp/l2tp_core.h +2 -1
@@ -261,7 +261,8 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,int l2tp_udp_encap_recv (struct sock *sk,struct sk_buff *skb);/* Transmit path helpers for sending packets over the tunnel socket. */ -void l2tp_session_set_header_len (struct l2tp_session *session,int version); +void l2tp_session_set_header_len (struct l2tp_session *session,int version, +enum l2tp_encap_type encap);int l2tp_xmit_skb (struct l2tp_session *session,struct sk_buff *skb);/* Pseudowire management.
net/l2tp/l2tp_netlink.c +3 -1
@@ -690,8 +690,10 @@ static int l2tp_nl_cmd_session_modify(struct sk_buff *skb, struct genl_info *inf session->recv_seq =nla_get_u8 (info->attrs[L2TP_ATTR_RECV_SEQ ]);if (info->attrs[L2TP_ATTR_SEND_SEQ ]) { +struct l2tp_tunnel *tunnel = session->tunnel; + session->send_seq =nla_get_u8 (info->attrs[L2TP_ATTR_SEND_SEQ ]); -l2tp_session_set_header_len (session, session->tunnel->version); +l2tp_session_set_header_len (session, tunnel->version, tunnel->encap); }if (info->attrs[L2TP_ATTR_LNS_MODE ])
net/l2tp/l2tp_ppp.c +2 -1
@@ -1194,7 +1194,8 @@ static int pppol2tp_session_setsockopt(struct sock *sk, po->chan.hdrlen = val ?PPPOL2TP_L2TP_HDR_SIZE_SEQ :PPPOL2TP_L2TP_HDR_SIZE_NOSEQ ; } -l2tp_session_set_header_len (session, session->tunnel->version); +l2tp_session_set_header_len (session, session->tunnel->version, + session->tunnel->encap);break ;case PPPOL2TP_SO_LNSMODE :
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 675/1887 net/ncsi: Disable the ncsi work before freeing the associated structure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eddie James <[email protected]>
[ Upstream commit a0ffa68c70b367358b2672cdab6fa5bc4c40de2c ]
The work function can run after the ncsi device is freed, resulting in use-after-free bugs or kernel panic.
--- net/ncsi/ncsi-manage.c | 2 ++ 1 file changed, 2 insertions(+)
net/ncsi/ncsi-manage.c +2 -0
@@ -1967,6 +1967,8 @@ void ncsi_unregister_dev(struct ncsi_dev *nd)list_del_rcu (&ndp->node);spin_unlock_irqrestore (&ncsi_dev_lock, flags); +cancel_work_sync (&ndp->work); +kfree (ndp); }EXPORT_SYMBOL_GPL (ncsi_unregister_dev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 676/1887 drm/amd/display: Implement bounds check for stream encoder creation in DCN401
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Srinivasan Shanmugam <[email protected]>
[ Upstream commit bdf606810210e8e07a0cdf1af3c467291363b295 ]
'stream_enc_regs' array is an array of dcn10_stream_enc_registers structures. The array is initialized with four elements, corresponding to the four calls to stream_enc_regs() in the array initializer. This means that valid indices for this array are 0, 1, 2, and 3.
The error message 'stream_enc_regs' 4 <= 5 below, is indicating that there is an attempt to access this array with an index of 5, which is out of bounds. This could lead to undefined behavior
Here, eng_id is used as an index to access the stream_enc_regs array. If eng_id is 5, this would result in an out-of-bounds access on the stream_enc_regs array.
Thus fixing Buffer overflow error in dcn401_stream_encoder_create
Found by smatch:drivers/gpu/drm/amd/amdgpu/../display/dc/resource/dcn401/dcn401_resource.c:1209 dcn401_stream_encoder_create() error: buffer overflow 'stream_enc_regs' 4 <= 5
--- drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c +1 -1
@@ -1208,7 +1208,7 @@ static struct stream_encoder *dcn321_stream_encoder_create( vpg =dcn321_vpg_create (ctx, vpg_inst); afmt =dcn321_afmt_create (ctx, afmt_inst); -if (!enc1 || !vpg || !afmt) { +if (!enc1 || !vpg || !afmt || eng_id >=ARRAY_SIZE (stream_enc_regs)) {kfree (enc1);kfree (vpg);kfree (afmt);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 677/1887 cpufreq: amd-pstate: add check for cpufreq_cpu_gets return value
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anastasia Belova <[email protected]>
[ Upstream commit 5493f9714e4cdaf0ee7cec15899a231400cb1a9f ]
cpufreq_cpu_get may return NULL. To avoid NULL-dereference check it and return in case of error.
Found by Linux Verification Center (linuxtesting.org) with SVACE.
--- drivers/cpufreq/amd-pstate.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/cpufreq/amd-pstate.c +6 -1
@@ -309,9 +309,14 @@ static void amd_pstate_adjust_perf(unsigned int cpu,unsigned long max_perf, min_perf, des_perf, cap_perf, lowest_nonlinear_perf, max_freq;struct cpufreq_policy *policy =cpufreq_cpu_get (cpu); -struct amd_cpudata *cpudata = policy->driver_data; +struct amd_cpudata *cpudata;unsigned int target_freq; +if (!policy) +return ; + + cpudata = policy->driver_data; + cap_perf =READ_ONCE (cpudata->highest_perf); lowest_nonlinear_perf =READ_ONCE (cpudata->lowest_nonlinear_perf); max_freq =READ_ONCE (cpudata->max_freq);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 678/1887 nvme-pci: fix race condition between reset and nvme_dev_disable()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maurizio Lombardi <[email protected]>
[ Upstream commit 26bc0a81f64ce00fc4342c38eeb2eddaad084dd2 ]
nvme_dev_disable() modifies the dev->online_queues field, therefore nvme_pci_update_nr_queues() should avoid racing against it, otherwise we could end up passing invalid values to blk_mq_update_nr_hw_queues().
WARNING: CPU: 39 PID: 61303 at drivers/pci/msi/api.c:347
pci_irq_get_affinity+0x187/0x210
Workqueue: nvme-reset-wq nvme_reset_work [nvme]
RIP: 0010:pci_irq_get_affinity+0x187/0x210
Call Trace:
<TASK>
? blk_mq_pci_map_queues+0x87/0x3c0
? pci_irq_get_affinity+0x187/0x210
blk_mq_pci_map_queues+0x87/0x3c0
nvme_pci_map_queues+0x189/0x460 [nvme]
blk_mq_update_nr_hw_queues+0x2a/0x40
nvme_reset_work+0x1be/0x2a0 [nvme]Fix the bug by locking the shutdown_lock mutex before using dev->online_queues. Give up if nvme_dev_disable() is running or if it has been executed already.
--- drivers/nvme/host/pci.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-)
drivers/nvme/host/pci.c +15 -3
@@ -2620,11 +2620,23 @@ static void nvme_pci_alloc_tag_set(struct nvme_dev *dev) dev->ctrl.tagset = set; } -static void nvme_pci_update_nr_queues (struct nvme_dev *dev) +static bool nvme_pci_update_nr_queues (struct nvme_dev *dev) { +/* Give up if we are racing with nvme_dev_disable() */ +if (!mutex_trylock (&dev->shutdown_lock)) +return false; + +/* Check if nvme_dev_disable() has been executed already */ +if (!dev->online_queues) { +mutex_unlock (&dev->shutdown_lock); +return false; + } +blk_mq_update_nr_hw_queues (&dev->tagset, dev->online_queues -1 );/* free previously allocated queues that are no longer usable */ nvme_free_queues (dev, dev->online_queues); +mutex_unlock (&dev->shutdown_lock); +return true; }static int nvme_pci_enable (struct nvme_dev *dev)
@@ -2986,8 +2998,8 @@ static void nvme_reset_work(struct work_struct *work)nvme_wait_freeze (&dev->ctrl);if (!dev->ctrl.tagset)nvme_pci_alloc_tag_set (dev); -else -nvme_pci_update_nr_queues (dev); +else if (!nvme_pci_update_nr_queues (dev)) + goto out;nvme_dbbuf_set (dev);nvme_unfreeze (&dev->ctrl); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 679/1887 cxl/port: Fix use-after-free, permit out-of-order decoder shutdown
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dan Williams <[email protected]>
[ Upstream commit 101c268bd2f37e965a5468353e62d154db38838e ]
In support of investigating an initialization failure report [1], cxl_test was updated to register mock memory-devices after the mock root-port/bus device had been registered. That led to cxl_test crashing with a use-after-free bug with the following signature:
cxl_port_attach_region: cxl region3: cxl_host_bridge.0:port3 decoder3.0 add: mem0:decoder7.0 @ 0 next: cxl_switch_uport.0 nr_eps: 1 nr_targets: 1
cxl_port_attach_region: cxl region3: cxl_host_bridge.0:port3 decoder3.0 add: mem4:decoder14.0 @ 1 next: cxl_switch_uport.0 nr_eps: 2 nr_targets: 1
cxl_port_setup_targets: cxl region3: cxl_switch_uport.0:port6 target[0] = cxl_switch_dport.0 for mem0:decoder7.0 @ 0
1) cxl_port_setup_targets: cxl region3: cxl_switch_uport.0:port6 target[1] = cxl_switch_dport.4 for mem4:decoder14.0 @ 1 [..]
cxld_unregister: cxl decoder14.0:
cxl_region_decode_reset: cxl_region region3:
mock_decoder_reset: cxl_port port3: decoder3.0 reset
2) mock_decoder_reset: cxl_port port3: decoder3.0: out of order reset, expected decoder3.1
cxl_endpoint_decoder_release: cxl decoder14.0:
[..]
cxld_unregister: cxl decoder7.0:
3) cxl_region_decode_reset: cxl_region region3:
Oops: general protection fault, probably for non-canonical address 0x6b6b6b6b6b6b6bc3: 0000 [#1] PREEMPT SMP PTI
[..]
RIP: 0010:to_cxl_port+0x8/0x60 [cxl_core]
[..]
Call Trace:
<TASK>
cxl_region_decode_reset+0x69/0x190 [cxl_core]
cxl_region_detach+0xe8/0x210 [cxl_core]
cxl_decoder_kill_region+0x27/0x40 [cxl_core]
cxld_unregister+0x5d/0x60 [cxl_core]At 1) a region has been established with 2 endpoint decoders (7.0 and 14.0). Those endpoints share a common switch-decoder in the topology (3.0). At teardown, 2), decoder14.0 is the first to be removed and hits the "out of order reset case" in the switch decoder. The effect though is that region3 cleanup is aborted leaving it in-tact and referencing decoder14.0. At 3) the second attempt to teardown region3 trips over the stale decoder14.0 object which has long since been deleted.
The fix here is to recognize that the CXL specification places no mandate on in-order shutdown of switch-decoders, the driver enforces in-order allocation, and hardware enforces in-order commit. So, rather than fail and leave objects dangling, always remove them.
In support of making cxl_region_decode_reset() always succeed, cxl_region_invalidate_memregion() failures are turned into warnings. Crashing the kernel is ok there since system integrity is at risk if caches cannot be managed around physical address mutation events like CXL region destruction.
A new device_for_each_child_reverse_from() is added to cleanup port->commit_end after all dependent decoders have been disabled. In other words if decoders are allocated 0->1->2 and disabled 1->2->0 then port->commit_end only decrements from 2 after 2 has been disabled, and it decrements all the way to zero since 1 was disabled previously.
--- drivers/base/core.c | 35 ++++++++++++++++++++++++++ drivers/cxl/core/hdm.c | 48 ++++++++++++++++++++++++++++++------ drivers/cxl/core/region.c | 29 ++++++---------------- drivers/cxl/cxl.h | 3 ++- include/linux/device.h | 3 +++ tools/testing/cxl/test/cxl.c | 14 ++++------- 6 files changed, 93 insertions(+), 39 deletions(-)
drivers/base/core.c +35 -0
@@ -4076,6 +4076,41 @@ int device_for_each_child_reverse(struct device *parent, void *data, }EXPORT_SYMBOL_GPL (device_for_each_child_reverse); +/** +* device_for_each_child_reverse_from - device child iterator in reversed order. +* @parent: parent struct device. +* @from: optional starting point in child list +* @fn: function to be called for each device. +* @data: data for the callback. +* +* Iterate over @parent's child devices, starting at @from, and call @fn +* for each, passing it @data. This helper is identical to +* device_for_each_child_reverse() when @from is NULL. +* +* @fn is checked each iteration. If it returns anything other than 0, +* iteration stop and that value is returned to the caller of +* device_for_each_child_reverse_from(); +*/ +int device_for_each_child_reverse_from (struct device *parent, +struct device *from,const void *data, +int (*fn)(struct device *,const void *)) +{ +struct klist_iter i; +struct device *child; +int error =0 ; + +if (!parent->p) +return 0 ; + +klist_iter_init_node (&parent->p->klist_children, &i, + (from ? &from->p->knode_parent :NULL )); +while ((child =prev_device (&i)) && !error) + error =fn (child, data); +klist_iter_exit (&i); +return error; +} +EXPORT_SYMBOL_GPL (device_for_each_child_reverse_from); +/** * device_find_child - device iterator for locating a particular device. * @parent: parent struct device
drivers/cxl/core/hdm.c +40 -8
71 lines not on this page · raw message
drivers/cxl/core/region.c +8 -21
@@ -121,7 +121,7 @@ static struct cxl_region_ref *cxl_rr_load(struct cxl_port *port,return xa_load (&port->regions, (unsigned long )cxlr); } -static int cxl_region_decode_reset (struct cxl_region *cxlr,int count) +static void cxl_region_decode_reset (struct cxl_region *cxlr,int count) {struct cxl_region_params *p = &cxlr->params;int i;
@@ -131,7 +131,6 @@ static int cxl_region_decode_reset(struct cxl_region *cxlr, int count)struct cxl_memdev *cxlmd =cxled_to_memdev (cxled);struct cxl_port *iter =cxled_to_port (cxled);struct cxl_ep *ep; -int rc =0 ;while (!is_cxl_root (to_cxl_port (iter->dev.parent))) iter =to_cxl_port (iter->dev.parent);
@@ -144,17 +143,11 @@ static int cxl_region_decode_reset(struct cxl_region *cxlr, int count) cxl_rr =cxl_rr_load (iter, cxlr); cxld = cxl_rr->decoder;if (cxld->reset) - rc = cxld->reset (cxld); -if (rc) -return rc; + cxld->reset (cxld); } - rc = cxled->cxld.reset (&cxled->cxld); -if (rc) -return rc; + cxled->cxld.reset (&cxled->cxld); } - -return 0 ; }static int cxl_region_decode_commit (struct cxl_region *cxlr)
@@ -244,8 +237,10 @@ static ssize_t commit_store(struct device *dev, struct device_attribute *attr,* The lock was dropped, so need to revalidate that the reset is * still pending. */ -if (p->state ==CXL_CONFIG_RESET_PENDING ) - rc =cxl_region_decode_reset (cxlr, p->interleave_ways); +if (p->state ==CXL_CONFIG_RESET_PENDING ) { +cxl_region_decode_reset (cxlr, p->interleave_ways); + p->state =CXL_CONFIG_ACTIVE ; + } }if (rc)
@@ -253,8 +248,6 @@ static ssize_t commit_store(struct device *dev, struct device_attribute *attr,if (commit) p->state =CXL_CONFIG_COMMIT ; -else if (p->state ==CXL_CONFIG_RESET_PENDING ) - p->state =CXL_CONFIG_ACTIVE ; out:up_write (&cxl_region_rwsem);
@@ -1393,13 +1386,7 @@ static int cxl_region_detach(struct cxl_endpoint_decoder *cxled)get_device (&cxlr->dev);if (p->state >CXL_CONFIG_ACTIVE ) { -/* -* TODO: tear down all impacted regions if a device is -* removed out of order -*/ - rc =cxl_region_decode_reset (cxlr, p->interleave_ways); -if (rc) - goto out; +cxl_region_decode_reset (cxlr, p->interleave_ways); p->state =CXL_CONFIG_ACTIVE ; }
drivers/cxl/cxl.h +2 -1
@@ -273,7 +273,7 @@ struct cxl_decoder {struct cxl_region *region;unsigned long flags;int (*commit)(struct cxl_decoder *cxld); -int (*reset)(struct cxl_decoder *cxld); +void (*reset)(struct cxl_decoder *cxld); };/*
@@ -555,6 +555,7 @@ static inline bool is_cxl_root(struct cxl_port *port)bool is_cxl_port (struct device *dev);struct cxl_port *to_cxl_port (struct device *dev); +void cxl_port_commit_reap (struct cxl_decoder *cxld);struct pci_bus ;int devm_cxl_register_pci_bus (struct device *host,struct device *uport,struct pci_bus *bus);
include/linux/device.h +3 -0
@@ -957,6 +957,9 @@ int device_for_each_child(struct device *dev, void *data, int (*fn)(struct device *dev, void *data));int device_for_each_child_reverse (struct device *dev,void *data,int (*fn)(struct device *dev,void *data)); +int device_for_each_child_reverse_from (struct device *parent, +struct device *from,const void *data, +int (*fn)(struct device *,const void *));struct device *device_find_child (struct device *dev,void *data,int (*match)(struct device *dev,void *data)); struct device *device_find_child_by_name(struct device *parent,
tools/testing/cxl/test/cxl.c +5 -9
@@ -533,26 +533,22 @@ static int mock_decoder_commit(struct cxl_decoder *cxld)return 0 ; } -static int mock_decoder_reset (struct cxl_decoder *cxld) +static void mock_decoder_reset (struct cxl_decoder *cxld) {struct cxl_port *port =to_cxl_port (cxld->dev.parent);int id = cxld->id;if ((cxld->flags &CXL_DECODER_F_ENABLE ) ==0 ) -return 0 ; +return ;dev_dbg (&port->dev,"%s reset\n" ,dev_name (&cxld->dev)); -if (port->commit_end != id) { +if (port->commit_end == id) +cxl_port_commit_reap (cxld); +else dev_dbg (&port->dev,"%s: out of order reset, expected decoder%d.%d\n" ,dev_name (&cxld->dev), port->id, port->commit_end); -return -EBUSY ; - } - - port->commit_end--; cxld->flags &= ~CXL_DECODER_F_ENABLE ; - -return 0 ; }static void default_mock_decoder (struct cxl_decoder *cxld)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 680/1887 ksmbd: check outstanding simultaneous SMB operations
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit 0a77d947f599b1f39065015bec99390d0c0022ee ]
If Client send simultaneous SMB operations to ksmbd, It exhausts too much memory through the "ksmbd_work_cache”. It will cause OOM issue. ksmbd has a credit mechanism but it can't handle this problem. This patch add the check if it exceeds max credits to prevent this problem by assuming that one smb request consumes at least one credit.
--- fs/smb/server/connection.c | 1 + fs/smb/server/connection.h | 1 + fs/smb/server/server.c | 16 ++++++++++------ fs/smb/server/smb_common.c | 10 +++++++--- fs/smb/server/smb_common.h | 2 +- 5 files changed, 20 insertions(+), 10 deletions(-)
fs/smb/server/connection.c +1 -0
@@ -115,6 +115,7 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)atomic_set (&conn->req_running,0 );atomic_set (&conn->r_count,0 );atomic_set (&conn->refcnt,1 ); +atomic_set (&conn->mux_smb_requests,0 ); conn->total_credits =1 ; conn->outstanding_credits =0 ;
fs/smb/server/connection.h +1 -0
@@ -113,6 +113,7 @@ struct ksmbd_conn {__le16 signing_algorithm;bool binding;atomic_t refcnt; +atomic_t mux_smb_requests; };struct ksmbd_conn_ops {
fs/smb/server/server.c +10 -6
@@ -290,6 +290,7 @@ static void handle_ksmbd_work(struct work_struct *wk)ksmbd_conn_try_dequeue_request (work);ksmbd_free_work_struct (work); +atomic_dec (&conn->mux_smb_requests);/* * Checking waitqueue to dropping pending requests on * disconnection. waitqueue_active is safe because it
@@ -311,6 +312,15 @@ static int queue_ksmbd_work(struct ksmbd_conn *conn)struct ksmbd_work *work;int err; + err =ksmbd_init_smb_server (conn); +if (err) +return 0 ; + +if (atomic_inc_return (&conn->mux_smb_requests) >= conn->vals->max_credits) { +atomic_dec_return (&conn->mux_smb_requests); +return -ENOSPC ; + } + work =ksmbd_alloc_work_struct ();if (!work) {pr_err ("allocation for work failed\n" );
@@ -321,12 +331,6 @@ static int queue_ksmbd_work(struct ksmbd_conn *conn) work->request_buf = conn->request_buf; conn->request_buf =NULL ; - err =ksmbd_init_smb_server (work); -if (err) { -ksmbd_free_work_struct (work); -return 0 ; - } -ksmbd_conn_enqueue_request (work);atomic_inc (&conn->r_count);/* update activity on connection */
fs/smb/server/smb_common.c +7 -3
@@ -388,6 +388,10 @@ static struct smb_version_ops smb1_server_ops = { .set_rsp_status = set_smb1_rsp_status, }; +static struct smb_version_values smb1_server_values = { + .max_credits =SMB2_MAX_CREDITS , +}; +static int smb1_negotiate (struct ksmbd_work *work) {return ksmbd_smb_negotiate_common (work,SMB_COM_NEGOTIATE );
@@ -399,18 +403,18 @@ static struct smb_version_cmds smb1_server_cmds[1] = {static int init_smb1_server (struct ksmbd_conn *conn) { + conn->vals = &smb1_server_values; conn->ops = &smb1_server_ops; conn->cmds = smb1_server_cmds; conn->max_cmds =ARRAY_SIZE (smb1_server_cmds);return 0 ; } -int ksmbd_init_smb_server (struct ksmbd_work *work) +int ksmbd_init_smb_server (struct ksmbd_conn *conn) { -struct ksmbd_conn *conn = work->conn;__le32 proto; - proto = *(__le32 *)((struct smb_hdr *)work->request_buf)->Protocol; + proto = *(__le32 *)((struct smb_hdr *)conn->request_buf)->Protocol;if (conn->need_neg == false) {if (proto ==SMB1_PROTO_NUMBER )return -EINVAL ;
fs/smb/server/smb_common.h +1 -1
@@ -391,7 +391,7 @@ bool ksmbd_smb_request(struct ksmbd_conn *conn);int ksmbd_lookup_dialect_by_id (__le16 *cli_dialects,__le16 dialects_count); -int ksmbd_init_smb_server (struct ksmbd_work *work); +int ksmbd_init_smb_server (struct ksmbd_conn *conn);struct ksmbd_kstat ; int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 681/1887 drm/msm/gem: prevent integer overflow in msm_ioctl_gem_submit()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dan Carpenter <[email protected]>
[ Upstream commit 3a47f4b439beb98e955d501c609dfd12b7836d61 ]
The "submit->cmd[i].size" and "submit->cmd[i].offset" variables are u32 values that come from the user via the submit_lookup_cmds() function. This addition could lead to an integer wrapping bug so use size_add() to prevent that.
Patchwork: https://patchwork.freedesktop.org/patch/624696/
--- drivers/gpu/drm/msm/msm_gem_submit.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/gpu/drm/msm/msm_gem_submit.c +1 -2
@@ -856,8 +856,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, goto out;if (!submit->cmd[i].size || - ((submit->cmd[i].size + submit->cmd[i].offset) > - msm_obj->base.size /4 )) { + (size_add (submit->cmd[i].size, submit->cmd[i].offset) > msm_obj->base.size /4 )) {DRM_ERROR ("invalid cmdstream size: %u\n" , submit->cmd[i].size *4 ); ret = -EINVAL ; goto out;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 682/1887 firmware: arm_scmi: Simplify chan_available transport operation
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cristian Marussi <[email protected]>
[ Upstream commit 7a75b7afd8ff7b891e60b2fc9622148e6d1e010a ]
SCMI transport operation .chan_available determines in a transport specific way if an SCMI channel is still available and to be configured. Such information is derived by analyzing bits of device node in a transport specific way, all it needs is a device node to operate up on, not necessarily a full blown device.
Simplify the helper to receive in input a reference to a device_node instead of a device carrying a pointer to such device_node.
Stable-dep-of: 295416091e44 ("firmware: arm_scmi: Fix slab-use-after-free in scmi_bus_notifier()")
--- drivers/firmware/arm_scmi/common.h | 2 +- drivers/firmware/arm_scmi/driver.c | 2 +- drivers/firmware/arm_scmi/mailbox.c | 4 ++-- drivers/firmware/arm_scmi/optee.c | 4 ++-- drivers/firmware/arm_scmi/smc.c | 4 ++-- drivers/firmware/arm_scmi/virtio.c | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-)
drivers/firmware/arm_scmi/common.h +1 -1
@@ -153,7 +153,7 @@ struct scmi_chan_info {*/ struct scmi_transport_ops {int (*link_supplier)(struct device *dev); -bool (*chan_available)(struct device *dev,int idx); +bool (*chan_available)(struct device_node *of_node,int idx);int (*chan_setup)(struct scmi_chan_info *cinfo,struct device *dev,bool tx);int (*chan_free)(int id,void *p,void *data);
drivers/firmware/arm_scmi/driver.c +1 -1
@@ -2047,7 +2047,7 @@ static int scmi_chan_setup(struct scmi_info *info, struct device *dev,if (cinfo)return 0 ; -if (!info->desc->ops->chan_available (dev, idx)) { +if (!info->desc->ops->chan_available (dev->of_node, idx)) { cinfo =idr_find (idr,SCMI_PROTOCOL_BASE );if (unlikely (!cinfo))/* Possible only if platform has no Rx */ return -EINVAL ;
drivers/firmware/arm_scmi/mailbox.c +2 -2
@@ -60,9 +60,9 @@ static void rx_callback(struct mbox_client *cl, void *m)scmi_rx_callback (smbox->cinfo,shmem_read_header (smbox->shmem),NULL ); } -static bool mailbox_chan_available (struct device *dev,int idx) +static bool mailbox_chan_available (struct device_node *of_node,int idx) { -return !of_parse_phandle_with_args (dev->of_node,"mboxes" , +return !of_parse_phandle_with_args (of_node,"mboxes" ,"#mbox-cells" , idx,NULL ); }
drivers/firmware/arm_scmi/optee.c +2 -2
@@ -328,11 +328,11 @@ static int scmi_optee_link_supplier(struct device *dev)return 0 ; } -static bool scmi_optee_chan_available (struct device *dev,int idx) +static bool scmi_optee_chan_available (struct device_node *of_node,int idx) {u32 channel_id; -return !of_property_read_u32_index (dev->of_node,"linaro,optee-channel-id" , +return !of_property_read_u32_index (of_node,"linaro,optee-channel-id" , idx, &channel_id); }
drivers/firmware/arm_scmi/smc.c +2 -2
@@ -54,9 +54,9 @@ static irqreturn_t smc_msg_done_isr(int irq, void *data)return IRQ_HANDLED ; } -static bool smc_chan_available (struct device *dev,int idx) +static bool smc_chan_available (struct device_node *of_node,int idx) { -struct device_node *np =of_parse_phandle (dev->of_node,"shmem" ,0 ); +struct device_node *np =of_parse_phandle (of_node,"shmem" ,0 );if (!np)return false;
drivers/firmware/arm_scmi/virtio.c +1 -1
@@ -385,7 +385,7 @@ static int virtio_link_supplier(struct device *dev)return 0 ; } -static bool virtio_chan_available (struct device *dev,int idx) +static bool virtio_chan_available (struct device_node *of_node,int idx) {struct scmi_vio_channel *channels, *vioch =NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 683/1887 firmware: arm_scmi: Use dedicated devices to initialize channels
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cristian Marussi <[email protected]>
[ Upstream commit 05a2801d8b90c1b5159618d4bd3a3c65d60f3ff1 ]
Refactor channels initialization to use dedicated transport devices instead of using devices borrowed from the SCMI drivers.
Initialize all channels, as described in the device tree, upfront during SCMI core stack probe phase and free all of them, including the underlying devices, when the SCMI core is removed.
Stable-dep-of: 295416091e44 ("firmware: arm_scmi: Fix slab-use-after-free in scmi_bus_notifier()")
--- drivers/firmware/arm_scmi/common.h | 1 - drivers/firmware/arm_scmi/driver.c | 158 ++++++++++++++++++++-------- drivers/firmware/arm_scmi/mailbox.c | 2 - drivers/firmware/arm_scmi/optee.c | 2 - drivers/firmware/arm_scmi/smc.c | 2 - drivers/firmware/arm_scmi/virtio.c | 2 - 6 files changed, 116 insertions(+), 51 deletions(-)
drivers/firmware/arm_scmi/common.h +0 -1
@@ -229,7 +229,6 @@ extern const struct scmi_desc scmi_optee_desc;#endif void scmi_rx_callback (struct scmi_chan_info *cinfo,u32 msg_hdr,void *priv); -void scmi_free_channel (struct scmi_chan_info *cinfo,struct idr *idr,int id);/* shmem related declarations */ struct scmi_shared_mem ;
drivers/firmware/arm_scmi/driver.c +116 -42
248 lines not on this page · raw message
drivers/firmware/arm_scmi/mailbox.c +0 -2
@@ -173,8 +173,6 @@ static int mailbox_chan_free(int id, void *p, void *data) smbox->cinfo =NULL ; } -scmi_free_channel (cinfo, data, id); -return 0 ; }
drivers/firmware/arm_scmi/optee.c +0 -2
@@ -488,8 +488,6 @@ static int scmi_optee_chan_free(int id, void *p, void *data) cinfo->transport_info =NULL ; channel->cinfo =NULL ; -scmi_free_channel (cinfo, data, id); -return 0 ; }
drivers/firmware/arm_scmi/smc.c +0 -2
@@ -185,8 +185,6 @@ static int smc_chan_free(int id, void *p, void *data) cinfo->transport_info =NULL ; scmi_info->cinfo =NULL ; -scmi_free_channel (cinfo, data, id); -return 0 ; }
drivers/firmware/arm_scmi/virtio.c +0 -2
@@ -489,8 +489,6 @@ static int virtio_chan_free(int id, void *p, void *data)virtio_break_device (vioch->vqueue->vdev);scmi_vio_channel_cleanup_sync (vioch); -scmi_free_channel (cinfo, data, id); -return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 684/1887 firmware: arm_scmi: Move protocol registration helpers
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cristian Marussi <[email protected]>
[ Upstream commit 9115c20ac1ee9e92a3e751e352db818b7f95746a ]
Move protocol registration helpers and logic out of bus.c compilation unit into driver.c.
No functional change.
Stable-dep-of: 295416091e44 ("firmware: arm_scmi: Fix slab-use-after-free in scmi_bus_notifier()")
--- drivers/firmware/arm_scmi/bus.c | 68 ------------------------------ drivers/firmware/arm_scmi/common.h | 3 -- drivers/firmware/arm_scmi/driver.c | 67 +++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 71 deletions(-)
drivers/firmware/arm_scmi/bus.c +0 -68
@@ -16,8 +16,6 @@#include "common.h" static DEFINE_IDA (scmi_bus_id); -static DEFINE_IDR (scmi_protocols); -static DEFINE_SPINLOCK (protocol_lock);static const struct scmi_device_id *scmi_dev_match_id (struct scmi_device *scmi_dev,struct scmi_driver *scmi_drv)
@@ -79,30 +77,6 @@ struct scmi_device *scmi_child_dev_find(struct device *parent,return to_scmi_dev (dev); } -const struct scmi_protocol *scmi_protocol_get (int protocol_id) -{ -const struct scmi_protocol *proto; - - proto =idr_find (&scmi_protocols, protocol_id); -if (!proto || !try_module_get (proto->owner)) { -pr_warn ("SCMI Protocol 0x%x not found!\n" , protocol_id); -return NULL ; - } - -pr_debug ("Found SCMI Protocol 0x%x\n" , protocol_id); - -return proto; -} - -void scmi_protocol_put (int protocol_id) -{ -const struct scmi_protocol *proto; - - proto =idr_find (&scmi_protocols, protocol_id); -if (proto) -module_put (proto->owner); -} -static int scmi_dev_probe (struct device *dev) {struct scmi_driver *scmi_drv =to_scmi_driver (dev->driver);
@@ -235,48 +209,6 @@ void scmi_set_handle(struct scmi_device *scmi_dev)scmi_device_link_add (&scmi_dev->dev, scmi_dev->handle->dev); } -int scmi_protocol_register (const struct scmi_protocol *proto) -{ -int ret; - -if (!proto) { -pr_err ("invalid protocol\n" ); -return -EINVAL ; - } - -if (!proto->instance_init) { -pr_err ("missing init for protocol 0x%x\n" , proto->id); -return -EINVAL ; - } - -spin_lock (&protocol_lock); - ret =idr_alloc (&scmi_protocols, (void *)proto, - proto->id, proto->id +1 ,GFP_ATOMIC ); -spin_unlock (&protocol_lock); -if (ret != proto->id) { -pr_err ("unable to allocate SCMI idr slot for 0x%x - err %d\n" , - proto->id, ret); -return ret; - } - -pr_debug ("Registered SCMI Protocol 0x%x\n" , proto->id); - -return 0 ; -} -EXPORT_SYMBOL_GPL (scmi_protocol_register); - -void scmi_protocol_unregister (const struct scmi_protocol *proto) -{ -spin_lock (&protocol_lock); -idr_remove (&scmi_protocols, proto->id); -spin_unlock (&protocol_lock); - -pr_debug ("Unregistered SCMI Protocol 0x%x\n" , proto->id); - -return ; -} -EXPORT_SYMBOL_GPL (scmi_protocol_unregister); -static int __scmi_devices_unregister (struct device *dev,void *data) {struct scmi_device *scmi_dev =to_scmi_dev (dev);
drivers/firmware/arm_scmi/common.h +0 -3
@@ -106,9 +106,6 @@ void scmi_setup_protocol_implemented(const struct scmi_protocol_handle *ph,int __init scmi_bus_init (void ); void __exit scmi_bus_exit(void); -const struct scmi_protocol *scmi_protocol_get (int protocol_id); -void scmi_protocol_put (int protocol_id); -int scmi_protocol_acquire (const struct scmi_handle *handle,u8 protocol_id);void scmi_protocol_release (const struct scmi_handle *handle,u8 protocol_id);
drivers/firmware/arm_scmi/driver.c +67 -0
79 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 685/1887 firmware: arm_scmi: Add common notifier helpers
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cristian Marussi <[email protected]>
[ Upstream commit 53b8c25df7082edd78a3fc63e359abee0f28fa70 ]
Add a pair of notifier chains and generic empty notifier callbacks. Currently they are still unused but they will be used to act properly on device request and creation events.
Stable-dep-of: 295416091e44 ("firmware: arm_scmi: Fix slab-use-after-free in scmi_bus_notifier()")
--- drivers/firmware/arm_scmi/bus.c | 6 ++- drivers/firmware/arm_scmi/common.h | 5 ++ drivers/firmware/arm_scmi/driver.c | 83 +++++++++++++++++++++++++++++- 3 files changed, 92 insertions(+), 2 deletions(-)
drivers/firmware/arm_scmi/bus.c +5 -1
@@ -15,6 +15,9 @@#include "common.h" +BLOCKING_NOTIFIER_HEAD (scmi_requested_devices_nh); +EXPORT_SYMBOL_GPL (scmi_requested_devices_nh); +static DEFINE_IDA (scmi_bus_id); static const struct scmi_device_id *
@@ -97,12 +100,13 @@ static void scmi_dev_remove(struct device *dev) scmi_drv->remove (scmi_dev); } -static struct bus_type scmi_bus_type = { +struct bus_type scmi_bus_type = { .name ="scmi_protocol" , .match = scmi_dev_match, .probe = scmi_dev_probe, .remove = scmi_dev_remove, }; +EXPORT_SYMBOL_GPL (scmi_bus_type);int scmi_driver_register (struct scmi_driver *driver,struct module *owner,const char *mod_name)
drivers/firmware/arm_scmi/common.h +5 -0
@@ -105,6 +105,11 @@ void scmi_setup_protocol_implemented(const struct scmi_protocol_handle *ph,int __init scmi_bus_init (void ); void __exit scmi_bus_exit(void); +extern struct bus_type scmi_bus_type; + +#define SCMI_BUS_NOTIFY_DEVICE_REQUEST 0 +#define SCMI_BUS_NOTIFY_DEVICE_UNREQUEST 1 +extern struct blocking_notifier_head scmi_requested_devices_nh;int scmi_protocol_acquire (const struct scmi_handle *handle,u8 protocol_id);void scmi_protocol_release (const struct scmi_handle *handle,u8 protocol_id);
drivers/firmware/arm_scmi/driver.c +82 -1
131 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 686/1887 firmware: arm_scmi: Refactor protocol device creation
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cristian Marussi <[email protected]>
[ Upstream commit d3cd7c525fd2ecce3a6c963f314969a54783d211 ]
Move protocol device request helpers from driver.c compilation unit to bus.c, so reducing the cross interactions between driver.c and bus.c.
Get rid of old protocol device creation process as a whole from driver.c and remove also stale SCMI system power unicity checks.
While at that make such helpers call into scmi_requested_devices_nh notification chain.
Stable-dep-of: 295416091e44 ("firmware: arm_scmi: Fix slab-use-after-free in scmi_bus_notifier()")
--- drivers/firmware/arm_scmi/bus.c | 157 ++++++++++++++- drivers/firmware/arm_scmi/common.h | 2 - drivers/firmware/arm_scmi/driver.c | 296 ----------------------------- 3 files changed, 156 insertions(+), 299 deletions(-)
drivers/firmware/arm_scmi/bus.c +156 -1
@@ -9,6 +9,7 @@#include <linux/types.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/device.h>
@@ -20,6 +21,160 @@ EXPORT_SYMBOL_GPL(scmi_requested_devices_nh);static DEFINE_IDA (scmi_bus_id); +static DEFINE_IDR (scmi_requested_devices); +/* Protect access to scmi_requested_devices */ +static DEFINE_MUTEX (scmi_requested_devices_mtx); + +struct scmi_requested_dev { +const struct scmi_device_id *id_table; +struct list_head node; +}; + +/** +* scmi_protocol_device_request - Helper to request a device +* +* @id_table: A protocol/name pair descriptor for the device to be created. +* +* This helper let an SCMI driver request specific devices identified by the +* @id_table to be created for each active SCMI instance. +* +* The requested device name MUST NOT be already existent for any protocol; +* at first the freshly requested @id_table is annotated in the IDR table +* @scmi_requested_devices and then the requested device is advertised to any +* registered party via the @scmi_requested_devices_nh notification chain. +* +* Return: 0 on Success +*/ +static int scmi_protocol_device_request (const struct scmi_device_id *id_table) +{ +int ret =0 ; +unsigned int id =0 ; +struct list_head *head, *phead =NULL ; +struct scmi_requested_dev *rdev; + +pr_debug ("Requesting SCMI device (%s) for protocol %x\n" , + id_table->name, id_table->protocol_id); + +/* +* Search for the matching protocol rdev list and then search +* of any existent equally named device...fails if any duplicate found. +*/ +mutex_lock (&scmi_requested_devices_mtx); +idr_for_each_entry (&scmi_requested_devices, head, id) { +if (!phead) { +/* A list found registered in the IDR is never empty */ + rdev = list_first_entry(head, struct scmi_requested_dev, + node); +if (rdev->id_table->protocol_id == + id_table->protocol_id) + phead = head; + } +list_for_each_entry (rdev, head, node) { +if (!strcmp (rdev->id_table->name, id_table->name)) { +pr_err ("Ignoring duplicate request [%d] %s\n" , + rdev->id_table->protocol_id, + rdev->id_table->name); + ret = -EINVAL ; + goto out; + } + } + } + +/* +* No duplicate found for requested id_table, so let's create a new +* requested device entry for this new valid request. +*/ + rdev =kzalloc (sizeof (*rdev),GFP_KERNEL ); +if (!rdev) { + ret = -ENOMEM ; + goto out; + } + rdev->id_table = id_table; + +/* +* Append the new requested device table descriptor to the head of the +* related protocol list, eventually creating such head if not already +* there. +*/ +if (!phead) { + phead =kzalloc (sizeof (*phead),GFP_KERNEL ); +if (!phead) { +kfree (rdev); + ret = -ENOMEM ; + goto out; + } +INIT_LIST_HEAD (phead); + + ret =idr_alloc (&scmi_requested_devices, (void *)phead, + id_table->protocol_id, + id_table->protocol_id +1 ,GFP_KERNEL ); +if (ret != id_table->protocol_id) { +pr_err ("Failed to save SCMI device - ret:%d\n" , ret); +kfree (rdev); +kfree (phead); + ret = -EINVAL ; + goto out; + } + ret =0 ; + } +list_add (&rdev->node, phead); + +out: +mutex_unlock (&scmi_requested_devices_mtx); + +if (!ret) +blocking_notifier_call_chain (&scmi_requested_devices_nh, +SCMI_BUS_NOTIFY_DEVICE_REQUEST , + (void *)rdev->id_table); + +return ret; +} + +/** +* scmi_protocol_device_unrequest - Helper to unrequest a device +* +* @id_table: A protocol/name pair descriptor for the device to be unrequested. +* +* The unrequested device, described by the provided id_table, is at first +* removed from the IDR @scmi_requested_devices and then the removal is +* advertised to any registered party via the @scmi_requested_devices_nh +* notification chain. +*/ +static void scmi_protocol_device_unrequest (const struct scmi_device_id *id_table) +{ +struct list_head *phead; + +pr_debug ("Unrequesting SCMI device (%s) for protocol %x\n" , + id_table->name, id_table->protocol_id); + +mutex_lock (&scmi_requested_devices_mtx); + phead =idr_find (&scmi_requested_devices, id_table->protocol_id); +if (phead) { +struct scmi_requested_dev *victim, *tmp; + +list_for_each_entry_safe (victim, tmp, phead, node) { +if (!strcmp (victim->id_table->name, id_table->name)) { +list_del (&victim->node); + +mutex_unlock (&scmi_requested_devices_mtx); +blocking_notifier_call_chain (&scmi_requested_devices_nh, +SCMI_BUS_NOTIFY_DEVICE_UNREQUEST , + (void *)victim->id_table); +kfree (victim); +mutex_lock (&scmi_requested_devices_mtx); +break ; + } + } + +if (list_empty (phead)) { +idr_remove (&scmi_requested_devices, + id_table->protocol_id); +kfree (phead); + } + } +mutex_unlock (&scmi_requested_devices_mtx); +} +static const struct scmi_device_id *scmi_dev_match_id (struct scmi_device *scmi_dev,struct scmi_driver *scmi_drv) {
@@ -127,7 +282,7 @@ int scmi_driver_register(struct scmi_driver *driver, struct module *owner, retval =driver_register (&driver->driver);if (!retval) -pr_debug ("registered new scmi driver %s\n" , driver->name); +pr_debug ("Registered new scmi driver %s\n" , driver->name);return retval; }
drivers/firmware/arm_scmi/common.h +0 -2
@@ -172,8 +172,6 @@ struct scmi_transport_ops {bool (*poll_done)(struct scmi_chan_info *cinfo,struct scmi_xfer *xfer); }; -int scmi_protocol_device_request (const struct scmi_device_id *id_table); -void scmi_protocol_device_unrequest (const struct scmi_device_id *id_table);struct scmi_device *scmi_child_dev_find (struct device *parent,int prot_id,const char *name);
drivers/firmware/arm_scmi/driver.c +0 -296
314 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 687/1887 firmware: arm_scmi: Move handle get/set helpers
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cristian Marussi <[email protected]>
[ Upstream commit 971fc0665f1361f23251e4d85fac4aed1b683505 ]
Move handle get/set helpers definitions into driver.c and invoke them through the bus notifier helper.
Stable-dep-of: 295416091e44 ("firmware: arm_scmi: Fix slab-use-after-free in scmi_bus_notifier()")
--- drivers/firmware/arm_scmi/bus.c | 17 --------------- drivers/firmware/arm_scmi/common.h | 4 ---- drivers/firmware/arm_scmi/driver.c | 35 +++++++++++++++++++++--------- 3 files changed, 25 insertions(+), 31 deletions(-)
drivers/firmware/arm_scmi/bus.c +0 -17
@@ -347,27 +347,10 @@ scmi_device_create(struct device_node *np, struct device *parent, int protocol,void scmi_device_destroy (struct scmi_device *scmi_dev) {kfree_const (scmi_dev->name); -scmi_handle_put (scmi_dev->handle);ida_free (&scmi_bus_id, scmi_dev->id);device_unregister (&scmi_dev->dev); } -void scmi_device_link_add (struct device *consumer,struct device *supplier) -{ -struct device_link *link; - - link =device_link_add (consumer, supplier,DL_FLAG_AUTOREMOVE_CONSUMER ); - -WARN_ON (!link); -} - -void scmi_set_handle (struct scmi_device *scmi_dev) -{ - scmi_dev->handle =scmi_handle_get (&scmi_dev->dev); -if (scmi_dev->handle) -scmi_device_link_add (&scmi_dev->dev, scmi_dev->handle->dev); -} -static int __scmi_devices_unregister (struct device *dev,void *data) {struct scmi_device *scmi_dev =to_scmi_dev (dev);
drivers/firmware/arm_scmi/common.h +0 -4
@@ -96,10 +96,6 @@ static inline void unpack_scmi_header(u32 msg_hdr, struct scmi_msg_hdr *hdr)struct scmi_revision_info *scmi_revision_area_get (const struct scmi_protocol_handle *ph); -int scmi_handle_put (const struct scmi_handle *handle); -void scmi_device_link_add (struct device *consumer,struct device *supplier); -struct scmi_handle *scmi_handle_get (struct device *dev); -void scmi_set_handle (struct scmi_device *scmi_dev);void scmi_setup_protocol_implemented (const struct scmi_protocol_handle *ph,u8 *prot_imp);
drivers/firmware/arm_scmi/driver.c +25 -10
@@ -1934,13 +1934,6 @@ static bool scmi_is_transport_atomic(const struct scmi_handle *handle,return ret; } -static inline -struct scmi_handle *scmi_handle_get_from_info_unlocked (struct scmi_info *info) -{ - info->users++; -return &info->handle; -} -/** * scmi_handle_get() - Get the SCMI handle for a device *
@@ -1952,7 +1945,7 @@ struct scmi_handle *scmi_handle_get_from_info_unlocked(struct scmi_info *info)* * Return: pointer to handle if successful, NULL on error */ -struct scmi_handle *scmi_handle_get (struct device *dev) +static struct scmi_handle *scmi_handle_get (struct device *dev) {struct list_head *p;struct scmi_info *info;
@@ -1962,7 +1955,8 @@ struct scmi_handle *scmi_handle_get(struct device *dev)list_for_each (p, &scmi_list) { info = list_entry(p, struct scmi_info, node);if (dev->parent == info->dev) { - handle =scmi_handle_get_from_info_unlocked (info); + info->users++; + handle = &info->handle;break ; } }
@@ -1983,7 +1977,7 @@ struct scmi_handle *scmi_handle_get(struct device *dev)* Return: 0 is successfully released * if null was passed, it returns -EINVAL; */ -int scmi_handle_put (const struct scmi_handle *handle) +static int scmi_handle_put (const struct scmi_handle *handle) {struct scmi_info *info;
@@ -1999,6 +1993,23 @@ int scmi_handle_put(const struct scmi_handle *handle)return 0 ; } +static void scmi_device_link_add (struct device *consumer, +struct device *supplier) +{ +struct device_link *link; + + link =device_link_add (consumer, supplier,DL_FLAG_AUTOREMOVE_CONSUMER ); + +WARN_ON (!link); +} + +static void scmi_set_handle (struct scmi_device *scmi_dev) +{ + scmi_dev->handle =scmi_handle_get (&scmi_dev->dev); +if (scmi_dev->handle) +scmi_device_link_add (&scmi_dev->dev, scmi_dev->handle->dev); +} +static int __scmi_xfer_info_init (struct scmi_info *sinfo,struct scmi_xfers_info *info) {
@@ -2278,8 +2289,12 @@ static int scmi_bus_notifier(struct notifier_block *nb,switch (action) {case BUS_NOTIFY_BIND_DRIVER : +/* setup handle now as the transport is ready */ +scmi_set_handle (sdev);break ;case BUS_NOTIFY_UNBOUND_DRIVER : +scmi_handle_put (sdev->handle); + sdev->handle =NULL ;break ;default :return NOTIFY_DONE ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 688/1887 firmware: arm_scmi: Refactor device create/destroy helpers
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cristian Marussi <[email protected]>
[ Upstream commit 2c3e674465e73e2f7eb52c39dc5c5e97e78e68ea ]
Refactor SCMI device create/destroy helpers: it is now possible to ask for the creation of all the currently requested devices for a whole protocol, not only for the creation of a single well-defined device.
While at that, re-instate uniqueness checks on the creation of SCMI SystemPower devices.
Stable-dep-of: 295416091e44 ("firmware: arm_scmi: Fix slab-use-after-free in scmi_bus_notifier()")
--- drivers/firmware/arm_scmi/bus.c | 141 ++++++++++++++++++++++++++--- drivers/firmware/arm_scmi/common.h | 8 +- drivers/firmware/arm_scmi/driver.c | 9 +- include/linux/scmi_protocol.h | 5 - 4 files changed, 141 insertions(+), 22 deletions(-)
drivers/firmware/arm_scmi/bus.c +130 -11
@@ -7,6 +7,7 @@#define pr_fmt (fmt) KBUILD_MODNAME ": " fmt +#include <linux/atomic.h> #include <linux/types.h> #include <linux/module.h> #include <linux/of.h>
@@ -30,6 +31,9 @@ struct scmi_requested_dev {struct list_head node; }; +/* Track globally the creation of SCMI SystemPower related devices */ +static atomic_t scmi_syspower_registered =ATOMIC_INIT (0 ); +/** * scmi_protocol_device_request - Helper to request a device *
@@ -213,11 +217,11 @@ static int scmi_match_by_id_table(struct device *dev, void *data)struct scmi_device_id *id_table = data;return sdev->protocol_id == id_table->protocol_id && - !strcmp (sdev->name, id_table->name); + (id_table->name && !strcmp (sdev->name, id_table->name)); } -struct scmi_device *scmi_child_dev_find (struct device *parent, -int prot_id,const char *name) +static struct scmi_device *scmi_child_dev_find (struct device *parent, +int prot_id,const char *name) {struct scmi_device_id id_table;struct device *dev;
@@ -300,13 +304,53 @@ static void scmi_device_release(struct device *dev)kfree (to_scmi_dev (dev)); } -struct scmi_device * -scmi_device_create (struct device_node *np,struct device *parent,int protocol, -const char *name) +static void __scmi_device_destroy (struct scmi_device *scmi_dev) +{ +pr_debug ("(%s) Destroying SCMI device '%s' for protocol 0x%x (%s)\n" , +of_node_full_name (scmi_dev->dev.parent->of_node), +dev_name (&scmi_dev->dev), scmi_dev->protocol_id, + scmi_dev->name); + +if (scmi_dev->protocol_id ==SCMI_PROTOCOL_SYSTEM ) +atomic_set (&scmi_syspower_registered,0 ); + +kfree_const (scmi_dev->name); +ida_free (&scmi_bus_id, scmi_dev->id); +device_unregister (&scmi_dev->dev); +} + +static struct scmi_device * +__scmi_device_create (struct device_node *np,struct device *parent, +int protocol,const char *name) {int id, retval;struct scmi_device *scmi_dev; +/* +* If the same protocol/name device already exist under the same parent +* (i.e. SCMI instance) just return the existent device. +* This avoids any race between the SCMI driver, creating devices for +* each DT defined protocol at probe time, and the concurrent +* registration of SCMI drivers. +*/ + scmi_dev =scmi_child_dev_find (parent, protocol, name); +if (scmi_dev) +return scmi_dev; + +/* +* Ignore any possible subsequent failures while creating the device +* since we are doomed anyway at that point; not using a mutex which +* spans across this whole function to keep things simple and to avoid +* to serialize all the __scmi_device_create calls across possibly +* different SCMI server instances (parent) +*/ +if (protocol ==SCMI_PROTOCOL_SYSTEM && +atomic_cmpxchg (&scmi_syspower_registered,0 ,1 )) { +dev_warn (parent, +"SCMI SystemPower protocol device must be unique !\n" ); +return NULL ; + } + scmi_dev =kzalloc (sizeof (*scmi_dev),GFP_KERNEL );if (!scmi_dev)return NULL ;
@@ -336,6 +380,10 @@ scmi_device_create(struct device_node *np, struct device *parent, int protocol,if (retval) goto put_dev; +pr_debug ("(%s) Created SCMI device '%s' for protocol 0x%x (%s)\n" , +of_node_full_name (parent->of_node), +dev_name (&scmi_dev->dev), protocol, name); +return scmi_dev; put_dev:kfree_const (scmi_dev->name);
@@ -344,18 +392,85 @@ scmi_device_create(struct device_node *np, struct device *parent, int protocol,return NULL ; } -void scmi_device_destroy (struct scmi_device *scmi_dev) +/** +* scmi_device_create - A method to create one or more SCMI devices +* +* @np: A reference to the device node to use for the new device(s) +* @parent: The parent device to use identifying a specific SCMI instance +* @protocol: The SCMI protocol to be associated with this device +* @name: The requested-name of the device to be created; this is optional +* and if no @name is provided, all the devices currently known to +* be requested on the SCMI bus for @protocol will be created. +* +* This method can be invoked to create a single well-defined device (like +* a transport device or a device requested by an SCMI driver loaded after +* the core SCMI stack has been probed), or to create all the devices currently +* known to have been requested by the loaded SCMI drivers for a specific +* protocol (typically during SCMI core protocol enumeration at probe time). +* +* Return: The created device (or one of them if @name was NOT provided and +* multiple devices were created) or NULL if no device was created; +* note that NULL indicates an error ONLY in case a specific @name +* was provided: when @name param was not provided, a number of devices +* could have been potentially created for a whole protocol, unless no +* device was found to have been requested for that specific protocol. +*/ +struct scmi_device *scmi_device_create (struct device_node *np, +struct device *parent,int protocol, +const char *name) { -kfree_const (scmi_dev->name); -ida_free (&scmi_bus_id, scmi_dev->id); -device_unregister (&scmi_dev->dev); +struct list_head *phead; +struct scmi_requested_dev *rdev; +struct scmi_device *scmi_dev =NULL ; + +if (name) +return __scmi_device_create (np, parent, protocol, name); + +mutex_lock (&scmi_requested_devices_mtx); + phead =idr_find (&scmi_requested_devices, protocol); +/* Nothing to do. */ +if (!phead) { +mutex_unlock (&scmi_requested_devices_mtx); +return scmi_dev; + } + +/* Walk the list of requested devices for protocol and create them */ +list_for_each_entry (rdev, phead, node) { +struct scmi_device *sdev; + + sdev =__scmi_device_create (np, parent, + rdev->id_table->protocol_id, + rdev->id_table->name); +/* Report errors and carry on... */ +if (sdev) + scmi_dev = sdev; +else +pr_err ("(%s) Failed to create device for protocol 0x%x (%s)\n" , +of_node_full_name (parent->of_node), + rdev->id_table->protocol_id, + rdev->id_table->name); + } +mutex_unlock (&scmi_requested_devices_mtx); + +return scmi_dev; } +EXPORT_SYMBOL_GPL (scmi_device_create); + +void scmi_device_destroy (struct device *parent,int protocol,const char *name) +{ +struct scmi_device *scmi_dev; + + scmi_dev =scmi_child_dev_find (parent, protocol, name); +if (scmi_dev) +__scmi_device_destroy (scmi_dev); +} +EXPORT_SYMBOL_GPL (scmi_device_destroy);static int __scmi_devices_unregister (struct device *dev,void *data) {struct scmi_device *scmi_dev =to_scmi_dev (dev); -scmi_device_destroy (scmi_dev); +__scmi_device_destroy (scmi_dev);return 0 ; }
@@ -377,6 +492,10 @@ int __init scmi_bus_init(void) void __exit scmi_bus_exit(void) { +/* +* Destroy all remaining devices: just in case the drivers were +* manually unbound and at first and then the modules unloaded. +*/ scmi_devices_unregister ();bus_unregister (&scmi_bus_type);ida_destroy (&scmi_bus_id);
drivers/firmware/arm_scmi/common.h +5 -3
@@ -107,6 +107,11 @@ extern struct bus_type scmi_bus_type;#define SCMI_BUS_NOTIFY_DEVICE_UNREQUEST 1extern struct blocking_notifier_head scmi_requested_devices_nh; +struct scmi_device *scmi_device_create (struct device_node *np, +struct device *parent,int protocol, +const char *name); +void scmi_device_destroy (struct device *parent,int protocol,const char *name); +int scmi_protocol_acquire (const struct scmi_handle *handle,u8 protocol_id);void scmi_protocol_release (const struct scmi_handle *handle,u8 protocol_id);
@@ -168,9 +173,6 @@ struct scmi_transport_ops {bool (*poll_done)(struct scmi_chan_info *cinfo,struct scmi_xfer *xfer); }; -struct scmi_device *scmi_child_dev_find (struct device *parent, -int prot_id,const char *name); -/** * struct scmi_desc - Description of SoC integration *
drivers/firmware/arm_scmi/driver.c +6 -3
@@ -2135,6 +2135,8 @@ static int scmi_chan_setup(struct scmi_info *info, struct device_node *of_node,/* Create a uniquely named, dedicated transport device for this chan */ tdev =scmi_device_create (of_node, info->dev, prot_id, name);if (!tdev) { +dev_err (info->dev, +"failed to create transport device (%s)\n" , name);devm_kfree (info->dev, cinfo);return -EINVAL ; }
@@ -2144,7 +2146,7 @@ static int scmi_chan_setup(struct scmi_info *info, struct device_node *of_node, ret = info->desc->ops->chan_setup (cinfo, info->dev, tx);if (ret) {of_node_put (of_node); -scmi_device_destroy (tdev); +scmi_device_destroy (info->dev, prot_id, name);devm_kfree (info->dev, cinfo);return ret; }
@@ -2167,7 +2169,7 @@ static int scmi_chan_setup(struct scmi_info *info, struct device_node *of_node,/* Destroy channel and device only if created by this call. */ if (tdev) {of_node_put (of_node); -scmi_device_destroy (tdev); +scmi_device_destroy (info->dev, prot_id, name);devm_kfree (info->dev, cinfo); }return ret;
@@ -2246,10 +2248,11 @@ static int scmi_chan_destroy(int id, void *p, void *idr)struct scmi_chan_info *cinfo = p;if (cinfo->dev) { +struct scmi_info *info =handle_to_scmi_info (cinfo->handle);struct scmi_device *sdev =to_scmi_dev (cinfo->dev);of_node_put (cinfo->dev->of_node); -scmi_device_destroy (sdev); +scmi_device_destroy (info->dev, id, sdev->name); cinfo->dev =NULL ; }
include/linux/scmi_protocol.h +0 -5
@@ -804,11 +804,6 @@ struct scmi_device {#define to_scmi_dev (d) container_of(d, struct scmi_device, dev) -struct scmi_device * -scmi_device_create (struct device_node *np,struct device *parent,int protocol, -const char *name); -void scmi_device_destroy (struct scmi_device *scmi_dev); -struct scmi_device_id {u8 protocol_id;const char *name;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 689/1887 firmware: arm_scmi: Fix slab-use-after-free in scmi_bus_notifier()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xinqi Zhang <[email protected]>
[ Upstream commit 295416091e44806760ccf753aeafdafc0ae268f3 ]
The scmi_dev->name is released prematurely in __scmi_device_destroy(), which causes slab-use-after-free when accessing scmi_dev->name in scmi_bus_notifier(). So move the release of scmi_dev->name to scmi_device_release() to avoid slab-use-after-free.
| BUG: KASAN: slab-use-after-free in strncmp+0xe4/0xec | Read of size 1 at addr ffffff80a482bcc0 by task swapper/0/1 | | CPU: 1 PID: 1 Comm: swapper/0 Not tainted 6.6.38-debug #1 | Hardware name: Qualcomm Technologies, Inc. SA8775P Ride (DT) | Call trace: | dump_backtrace+0x94/0x114 | show_stack+0x18/0x24 | dump_stack_lvl+0x48/0x60 | print_report+0xf4/0x5b0 | kasan_report+0xa4/0xec | __asan_report_load1_noabort+0x20/0x2c | strncmp+0xe4/0xec | scmi_bus_notifier+0x5c/0x54c | notifier_call_chain+0xb4/0x31c | blocking_notifier_call_chain+0x68/0x9c | bus_notify+0x54/0x78 | device_del+0x1bc/0x840 | device_unregister+0x20/0xb4 | __scmi_device_destroy+0xac/0x280 | scmi_device_destroy+0x94/0xd0 | scmi_chan_setup+0x524/0x750 | scmi_probe+0x7fc/0x1508 | platform_probe+0xc4/0x19c | really_probe+0x32c/0x99c | __driver_probe_device+0x15c/0x3c4 | driver_probe_device+0x5c/0x170 | __driver_attach+0x1c8/0x440 | bus_for_each_dev+0xf4/0x178 | driver_attach+0x3c/0x58 | bus_add_driver+0x234/0x4d4 | driver_register+0xf4/0x3c0 | __platform_driver_register+0x60/0x88 | scmi_driver_init+0xb0/0x104 | do_one_initcall+0xb4/0x664 | kernel_init_freeable+0x3c8/0x894 | kernel_init+0x24/0x1e8 | ret_from_fork+0x10/0x20 | | Allocated by task 1: | kasan_save_stack+0x2c/0x54 | kasan_set_track+0x2c/0x40 | kasan_save_alloc_info+0x24/0x34 | __kasan_kmalloc+0xa0/0xb8 | __kmalloc_node_track_caller+0x6c/0x104 | kstrdup+0x48/0x84 | kstrdup_const+0x34/0x40 | __scmi_device_create.part.0+0x8c/0x408 | scmi_device_create+0x104/0x370 | scmi_chan_setup+0x2a0/0x750 | scmi_probe+0x7fc/0x1508 | platform_probe+0xc4/0x19c | really_probe+0x32c/0x99c | __driver_probe_device+0x15c/0x3c4 | driver_probe_device+0x5c/0x170 | __driver_attach+0x1c8/0x440 | bus_for_each_dev+0xf4/0x178 | driver_attach+0x3c/0x58 | bus_add_driver+0x234/0x4d4 | driver_register+0xf4/0x3c0 | __platform_driver_register+0x60/0x88 | scmi_driver_init+0xb0/0x104 | do_one_initcall+0xb4/0x664 | kernel_init_freeable+0x3c8/0x894 | kernel_init+0x24/0x1e8 | ret_from_fork+0x10/0x20 | | Freed by task 1: | kasan_save_stack+0x2c/0x54 | kasan_set_track+0x2c/0x40 | kasan_save_free_info+0x38/0x5c | __kasan_slab_free+0xe8/0x164 | __kmem_cache_free+0x11c/0x230 | kfree+0x70/0x130 | kfree_const+0x20/0x40 | __scmi_device_destroy+0x70/0x280 | scmi_device_destroy+0x94/0xd0 | scmi_chan_setup+0x524/0x750 | scmi_probe+0x7fc/0x1508 | platform_probe+0xc4/0x19c | really_probe+0x32c/0x99c | __driver_probe_device+0x15c/0x3c4 | driver_probe_device+0x5c/0x170 | __driver_attach+0x1c8/0x440 | bus_for_each_dev+0xf4/0x178 | driver_attach+0x3c/0x58 | bus_add_driver+0x234/0x4d4 | driver_register+0xf4/0x3c0 | __platform_driver_register+0x60/0x88 | scmi_driver_init+0xb0/0x104 | do_one_initcall+0xb4/0x664 | kernel_init_freeable+0x3c8/0x894 | kernel_init+0x24/0x1e8 | ret_from_fork+0x10/0x20
Message-Id: <20241016-fix-arm-scmi-slab-use-after-free-v2-1-1783685ef90d@quicinc.com>
--- drivers/firmware/arm_scmi/bus.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/firmware/arm_scmi/bus.c +4 -3
@@ -301,7 +301,10 @@ EXPORT_SYMBOL_GPL(scmi_driver_unregister);static void scmi_device_release (struct device *dev) { -kfree (to_scmi_dev (dev)); +struct scmi_device *scmi_dev =to_scmi_dev (dev); + +kfree_const (scmi_dev->name); +kfree (scmi_dev); }static void __scmi_device_destroy (struct scmi_device *scmi_dev)
@@ -314,7 +317,6 @@ static void __scmi_device_destroy(struct scmi_device *scmi_dev)if (scmi_dev->protocol_id ==SCMI_PROTOCOL_SYSTEM )atomic_set (&scmi_syspower_registered,0 ); -kfree_const (scmi_dev->name);ida_free (&scmi_bus_id, scmi_dev->id);device_unregister (&scmi_dev->dev); }
@@ -386,7 +388,6 @@ __scmi_device_create(struct device_node *np, struct device *parent,return scmi_dev; put_dev: -kfree_const (scmi_dev->name);put_device (&scmi_dev->dev);ida_free (&scmi_bus_id, id);return NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 690/1887 afs: Fix lock recursion
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
[ Upstream commit 610a79ffea02102899a1373fe226d949944a7ed6 ]
afs_wake_up_async_call() can incur lock recursion. The problem is that it is called from AF_RXRPC whilst holding the ->notify_lock, but it tries to take a ref on the afs_call struct in order to pass it to a work queue - but if the afs_call is already queued, we then have an extraneous ref that must be put... calling afs_put_call() may call back down into AF_RXRPC through rxrpc_kernel_shutdown_call(), however, which might try taking the ->notify_lock again.
This case isn't very common, however, so defer it to a workqueue. The oops looks something like:
BUG: spinlock recursion on CPU#0, krxrpcio/7001/1646 lock: 0xffff888141399b30, .magic: dead4ead, .owner: krxrpcio/7001/1646, .owner_cpu: 0 CPU: 0 UID: 0 PID: 1646 Comm: krxrpcio/7001 Not tainted 6.12.0-rc2-build3+ #4351 Hardware name: ASUS All Series/H97-PLUS, BIOS 2306 10/09/2014 Call Trace: <TASK> dump_stack_lvl+0x47/0x70 do_raw_spin_lock+0x3c/0x90 rxrpc_kernel_shutdown_call+0x83/0xb0 afs_put_call+0xd7/0x180 rxrpc_notify_socket+0xa0/0x190 rxrpc_input_split_jumbo+0x198/0x1d0 rxrpc_input_data+0x14b/0x1e0 ? rxrpc_input_call_packet+0xc2/0x1f0 rxrpc_input_call_event+0xad/0x6b0 rxrpc_input_packet_on_conn+0x1e1/0x210 rxrpc_input_packet+0x3f2/0x4d0 rxrpc_io_thread+0x243/0x410 ? __pfx_rxrpc_io_thread+0x10/0x10 kthread+0xcf/0xe0 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x24/0x40 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 </TASK>
--- fs/afs/internal.h | 2 ++ fs/afs/rxrpc.c | 79 ++++++++++++++++++++++++++++++++++------------- 2 files changed, 59 insertions(+), 22 deletions(-)
fs/afs/internal.h +2 -0
@@ -99,6 +99,7 @@ struct afs_call {wait_queue_head_t waitq;/* processes awaiting completion */ struct work_struct async_work;/* async I/O processor */ struct work_struct work;/* actual work processor */ +struct work_struct free_work;/* Deferred free processor */ struct rxrpc_call *rxcall;/* RxRPC call handle */ struct key *key;/* security for this call */ struct afs_net *net;/* The network namespace */
@@ -1283,6 +1284,7 @@ extern int __net_init afs_open_socket(struct afs_net *); extern void __net_exit afs_close_socket(struct afs_net *);extern void afs_charge_preallocation (struct work_struct *);extern void afs_put_call (struct afs_call *); +void afs_deferred_put_call (struct afs_call *call);extern void afs_make_call (struct afs_addr_cursor *,struct afs_call *,gfp_t );extern long afs_wait_for_call_to_complete (struct afs_call *,struct afs_addr_cursor *); extern struct afs_call *afs_alloc_flat_call(struct afs_net *,
fs/afs/rxrpc.c +57 -22
119 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 691/1887 bpf: Add sk_is_inet and IS_ICSK check in tls_sw_has_ctx_tx/rx
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zijian Zhang <[email protected]>
[ Upstream commit 44d0469f79bd3d0b3433732877358df7dc6b17b1 ]
As the introduction of the support for vsock and unix sockets in sockmap, tls_sw_has_ctx_tx/rx cannot presume the socket passed in must be IS_ICSK. vsock and af_unix sockets have vsock_sock and unix_sock instead of inet_connection_sock. For these sockets, tls_get_ctx may return an invalid pointer and cause page fault in function tls_sw_ctx_rx.
BUG: unable to handle page fault for address: 0000000000040030 Workqueue: vsock-loopback vsock_loopback_work RIP: 0010:sk_psock_strp_data_ready+0x23/0x60 Call Trace: ? __die+0x81/0xc3 ? no_context+0x194/0x350 ? do_page_fault+0x30/0x110 ? async_page_fault+0x3e/0x50 ? sk_psock_strp_data_ready+0x23/0x60 virtio_transport_recv_pkt+0x750/0x800 ? update_load_avg+0x7e/0x620 vsock_loopback_work+0xd0/0x100 process_one_work+0x1a7/0x360 worker_thread+0x30/0x390 ? create_worker+0x1a0/0x1a0 kthread+0x112/0x130 ? __kthread_cancel_work+0x40/0x40 ret_from_fork+0x1f/0x40
v2:
- Add IS_ICSK check
v3:
- Update the commits in Fixes
--- include/net/tls.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
include/net/tls.h +10 -2
@@ -405,8 +405,12 @@ tls_offload_ctx_tx(const struct tls_context *tls_ctx)static inline bool tls_sw_has_ctx_tx (const struct sock *sk) { -struct tls_context *ctx =tls_get_ctx (sk); +struct tls_context *ctx; + +if (!sk_is_inet (sk) || !inet_sk (sk)->is_icsk) +return false; + ctx =tls_get_ctx (sk);if (!ctx)return false;return !!tls_sw_ctx_tx (ctx);
@@ -414,8 +418,12 @@ static inline bool tls_sw_has_ctx_tx(const struct sock *sk)static inline bool tls_sw_has_ctx_rx (const struct sock *sk) { -struct tls_context *ctx =tls_get_ctx (sk); +struct tls_context *ctx; + +if (!sk_is_inet (sk) || !inet_sk (sk)->is_icsk) +return false; + ctx =tls_get_ctx (sk);if (!ctx)return false;return !!tls_sw_ctx_rx (ctx);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 692/1887 RDMA/siw: Add sendpage_ok() check to disable MSG_SPLICE_PAGES
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Showrya M N <[email protected]>
[ Upstream commit 4e1e3dd88a4cedd5ccc1a3fc3d71e03b70a7a791 ]
While running ISER over SIW, the initiator machine encounters a warning from skb_splice_from_iter() indicating that a slab page is being used in send_page. To address this, it is better to add a sendpage_ok() check within the driver itself, and if it returns 0, then MSG_SPLICE_PAGES flag should be disabled before entering the network stack.
A similar issue has been discussed for NVMe in this thread:
https://lore.kernel.org/all/[email protected]/
WARNING: CPU: 0 PID: 5342 at net/core/skbuff.c:7140 skb_splice_from_iter+0x173/0x320 Call Trace: tcp_sendmsg_locked+0x368/0xe40 siw_tx_hdt+0x695/0xa40 [siw] siw_qp_sq_process+0x102/0xb00 [siw] siw_sq_resume+0x39/0x110 [siw] siw_run_sq+0x74/0x160 [siw] kthread+0xd2/0x100 ret_from_fork+0x34/0x40 ret_from_fork_asm+0x1a/0x30
--- drivers/infiniband/sw/siw/siw_qp_tx.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/infiniband/sw/siw/siw_qp_tx.c +2 -0
@@ -338,6 +338,8 @@ static int siw_tcp_sendpages(struct socket *s, struct page **page, int offset, msg.msg_flags &= ~MSG_MORE ;tcp_rate_check_app_limited (sk); +if (!sendpage_ok (page[i])) + msg.msg_flags &= ~MSG_SPLICE_PAGES ;bvec_set_page (&bvec, page[i], bytes, offset);iov_iter_bvec (&msg.msg_iter,ITER_SOURCE , &bvec,1 , bytes);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 693/1887 smb: client: Fix use-after-free of network namespace.
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <[email protected]>
[ Upstream commit ef7134c7fc48e1441b398e55a862232868a6f0a7 ]
Recently, we got a customer report that CIFS triggers oops while reconnecting to a server. [0]
The workload runs on Kubernetes, and some pods mount CIFS servers in non-root network namespaces. The problem rarely happened, but it was always while the pod was dying.
The root cause is wrong reference counting for network namespace.
CIFS uses kernel sockets, which do not hold refcnt of the netns that the socket belongs to. That means CIFS must ensure the socket is always freed before its netns; otherwise, use-after-free happens.
The repro steps are roughly:
1. mount CIFS in a non-root netns
2. drop packets from the netns
3. destroy the netns
4. unmount CIFS
We can reproduce the issue quickly with the script [1] below and see the splat [2] if CONFIG_NET_NS_REFCNT_TRACKER is enabled.
When the socket is TCP, it is hard to guarantee the netns lifetime without holding refcnt due to async timers.
Let's hold netns refcnt for each socket as done for SMC in commit 9744d2bf1976 ("smc: Fix use-after-free in tcp_write_timer_handler().").
Note that we need to move put_net() from cifs_put_tcp_session() to clean_demultiplex_info(); otherwise, __sock_create() still could touch a freed netns while cifsd tries to reconnect from cifs_demultiplex_thread().
Also, maybe_get_net() cannot be put just before __sock_create() because the code is not under RCU and there is a small chance that the same address happened to be reallocated to another netns.
[0]:
CIFS: VFS: \\XXXXXXXXXXX has not responded in 15 seconds. Reconnecting...
CIFS: Serverclose failed 4 times, giving up
Unable to handle kernel paging request at virtual address 14de99e461f84a07
Mem abort info:
ESR = 0x0000000096000004
EC = 0x25: DABT (current EL), IL = 32 bits
SET = 0, FnV = 0
EA = 0, S1PTW = 0
FSC = 0x04: level 0 translation fault
Data abort info:
ISV = 0, ISS = 0x00000004
CM = 0, WnR = 0
[14de99e461f84a07] address between user and kernel address ranges
Internal error: Oops: 0000000096000004 [#1] SMP Modules linked in: cls_bpf sch_ingress nls_utf8 cifs cifs_arc4 cifs_md4 dns_resolver tcp_diag inet_diag veth xt_state xt_connmark nf_conntrack_netlink xt_nat xt_statistic xt_MASQUERADE xt_mark xt_addrtype ipt_REJECT nf_reject_ipv4 nft_chain_nat nf_nat xt_conntrack nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 xt_comment nft_compat nf_tables nfnetlink overlay nls_ascii nls_cp437 sunrpc vfat fat aes_ce_blk aes_ce_cipher ghash_ce sm4_ce_cipher sm4 sm3_ce sm3 sha3_ce sha512_ce sha512_arm64 sha1_ce ena button sch_fq_codel loop fuse configfs dmi_sysfs sha2_ce sha256_arm64 dm_mirror dm_region_hash dm_log dm_mod dax efivarfs CPU: 5 PID: 2690970 Comm: cifsd Not tainted 6.1.103-109.184.amzn2023.aarch64 #1 Hardware name: Amazon EC2 r7g.4xlarge/, BIOS 1.0 11/1/2018 pstate: 00400005 (nzcv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : fib_rules_lookup+0x44/0x238 lr : __fib_lookup+0x64/0xbc
sp : ffff8000265db790
x29: ffff8000265db790 x28: 0000000000000000 x27: 000000000000bd01
x26: 0000000000000000 x25: ffff000b4baf8000 x24: ffff00047b5e4580
x23: ffff8000265db7e0 x22: 0000000000000000 x21: ffff00047b5e4500
x20: ffff0010e3f694f8 x19: 14de99e461f849f7 x18: 0000000000000000
x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000
x14: 0000000000000000 x13: 0000000000000000 x12: 3f92800abd010002
x11: 0000000000000001 x10: ffff0010e3f69420 x9 : ffff800008a6f294 x8 : 0000000000000000 x7 : 0000000000000006 x6 : 0000000000000000 x5 : 0000000000000001 x4 : ffff001924354280 x3 : ffff8000265db7e0 x2 : 0000000000000000 x1 : ffff0010e3f694f8 x0 : ffff00047b5e4500
Call trace: fib_rules_lookup+0x44/0x238 __fib_lookup+0x64/0xbc ip_route_output_key_hash_rcu+0x2c4/0x398 ip_route_output_key_hash+0x60/0x8c tcp_v4_connect+0x290/0x488 __inet_stream_connect+0x108/0x3d0 inet_stream_connect+0x50/0x78 kernel_connect+0x6c/0xac generic_ip_connect+0x10c/0x6c8 [cifs] __reconnect_target_unlocked+0xa0/0x214 [cifs] reconnect_dfs_server+0x144/0x460 [cifs] cifs_reconnect+0x88/0x148 [cifs] cifs_readv_from_socket+0x230/0x430 [cifs] cifs_read_from_socket+0x74/0xa8 [cifs] cifs_demultiplex_thread+0xf8/0x704 [cifs] kthread+0xd0/0xd4 Code: aa0003f8 f8480f13 eb18027f 540006c0 (b9401264)
[1]:
CIFS_CRED="/root/cred.cifs" CIFS_USER="Administrator"
CIFS_PASS="Password"
CIFS_IP="X.X.X.X" CIFS_PATH="//${CIFS_IP}/Users/Administrator/Desktop/CIFS_TEST" CIFS_MNT="/mnt/smb"
DEV="enp0s3"
cat <<EOF > ${CIFS_CRED}
username=${CIFS_USER}
password=${CIFS_PASS}
domain=EXAMPLE.COM
EOF
unshare -n bash -c "
mkdir -p ${CIFS_MNT}
ip netns attach root 1
ip link add eth0 type veth peer veth0 netns root
ip link set eth0 up
ip -n root link set veth0 up
ip addr add 192.168.0.2/24 dev eth0
ip -n root addr add 192.168.0.1/24 dev veth0
ip route add default via 192.168.0.1 dev eth0
ip netns exec root sysctl net.ipv4.ip_forward=1
ip netns exec root iptables -t nat -A POSTROUTING -s 192.168.0.2 -o ${DEV} -j MASQUERADE
mount -t cifs ${CIFS_PATH} ${CIFS_MNT} -o vers=3.0,sec=ntlmssp,credentials=${CIFS_CRED},rsize=65536,wsize=65536,cache=none,echo_interval=1 touch ${CIFS_MNT}/a.txt
ip netns exec root iptables -t nat -D POSTROUTING -s 192.168.0.2 -o ${DEV} -j MASQUERADE
"
umount ${CIFS_MNT}
[2]:ref_tracker: net notrefcnt@000000004bbc008d has 1/1 users at
sk_alloc (./include/net/net_namespace.h:339 net/core/sock.c:2227)
inet_create (net/ipv4/af_inet.c:326 net/ipv4/af_inet.c:252)
__sock_create (net/socket.c:1576)
generic_ip_connect (fs/smb/client/connect.c:3075)
cifs_get_tcp_session.part.0 (fs/smb/client/connect.c:3160 fs/smb/client/connect.c:1798)
cifs_mount_get_session (fs/smb/client/trace.h:959 fs/smb/client/connect.c:3366)
dfs_mount_share (fs/smb/client/dfs.c:63 fs/smb/client/dfs.c:285)
cifs_mount (fs/smb/client/connect.c:3622)
cifs_smb3_do_mount (fs/smb/client/cifsfs.c:949)
smb3_get_tree (fs/smb/client/fs_context.c:784 fs/smb/client/fs_context.c:802 fs/smb/client/fs_context.c:794)
vfs_get_tree (fs/super.c:1800)
path_mount (fs/namespace.c:3508 fs/namespace.c:3834)
__x64_sys_mount (fs/namespace.c:3848 fs/namespace.c:4057 fs/namespace.c:4034 fs/namespace.c:4034)
do_syscall_64 (arch/x86/entry/common.c:52 arch/x86/entry/common.c:83)
entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130)--- fs/smb/client/connect.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
fs/smb/client/connect.c +10 -3
@@ -1083,6 +1083,7 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server)*/ } +put_net (cifs_net_ns (server));#ifdef CONFIG_CIFS_DFS_UPCALL kfree (server->origin_fullpath);kfree (server->leaf_fullpath);
@@ -1677,8 +1678,6 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)/* srv_count can never go negative */ WARN_ON (server->srv_count <0 ); -put_net (cifs_net_ns (server)); -list_del_init (&server->tcp_ses_list);spin_unlock (&cifs_tcp_ses_lock);
@@ -3079,7 +3078,10 @@ generic_ip_connect(struct TCP_Server_Info *server) }if (socket ==NULL ) { - rc =__sock_create (cifs_net_ns (server), sfamily,SOCK_STREAM , +struct net *net =cifs_net_ns (server); +struct sock *sk; + + rc =__sock_create (net, sfamily,SOCK_STREAM ,IPPROTO_TCP , &socket,1 );if (rc <0 ) {cifs_server_dbg (VFS ,"Error %d creating socket\n" , rc);
@@ -3087,6 +3089,11 @@ generic_ip_connect(struct TCP_Server_Info *server)return rc; } + sk = socket->sk; + sk->sk_net_refcnt =1 ; +get_net_track (net, &sk->ns_tracker,GFP_KERNEL ); +sock_inuse_add (net,1 ); +/* BB other socket options to set KEEPALIVE, NODELAY? */ cifs_dbg (FYI ,"Socket created\n" ); server->ssocket = socket;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 694/1887 pmdomain: imx93-blk-ctrl: correct remove path
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peng Fan <[email protected]>
[ Upstream commit f7c7c5aa556378a2c8da72c1f7f238b6648f95fb ]
The check condition should be 'i < bc->onecell_data.num_domains', not 'bc->onecell_data.num_domains' which will make the look never finish and cause kernel panic.
Also disable runtime to address
"imx93-blk-ctrl 4ac10000.system-controller: Unbalanced pm_runtime_enable!"
Message-ID: <[email protected]>
--- drivers/soc/imx/imx93-blk-ctrl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/soc/imx/imx93-blk-ctrl.c +3 -1
@@ -298,7 +298,9 @@ static int imx93_blk_ctrl_remove(struct platform_device *pdev)of_genpd_del_provider (pdev->dev.of_node); -for (i =0 ; bc->onecell_data.num_domains; i++) { +pm_runtime_disable (&pdev->dev); + +for (i =0 ; i < bc->onecell_data.num_domains; i++) {struct imx93_blk_ctrl_domain *domain = &bc->domains[i];pm_genpd_remove (&domain->genpd);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 695/1887 exfat: fix out-of-bounds access of directory entries
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuezhang Mo <[email protected]>
[ Upstream commit 184fa506e392eb78364d9283c961217ff2c0617b ]
In the case of the directory size is greater than or equal to the cluster size, if start_clu becomes an EOF cluster(an invalid cluster) due to file system corruption, then the directory entry where ei->hint_femp.eidx hint is outside the directory, resulting in an out-of-bounds access, which may cause further file system corruption.
This commit adds a check for start_clu, if it is an invalid cluster, the file or directory will be treated as empty.
--- fs/exfat/namei.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
fs/exfat/namei.c +9 -4
@@ -656,14 +656,19 @@ static int exfat_find(struct inode *dir, struct qstr *qname, info->type =exfat_get_entry_type (ep); info->attr =le16_to_cpu (ep->dentry.file.attr); info->size =le64_to_cpu (ep2->dentry.stream.valid_size); + + info->start_clu =le32_to_cpu (ep2->dentry.stream.start_clu); +if (!is_valid_cluster (sbi, info->start_clu) && info->size) { +exfat_warn (sb,"start_clu is invalid cluster(0x%x)" , + info->start_clu); + info->size =0 ; + } +if (info->size ==0 ) { info->flags =ALLOC_NO_FAT_CHAIN ; info->start_clu =EXFAT_EOF_CLUSTER ; - }else { + }else info->flags = ep2->dentry.stream.flags; - info->start_clu = -le32_to_cpu (ep2->dentry.stream.start_clu); - } exfat_get_entry_time(sbi, &info->crtime, ep->dentry.file.create_tz,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 696/1887 sunrpc: fix one UAF issue caused by sunrpc kernel tcp socket
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Liu Jian <[email protected]>
[ Upstream commit 3f23f96528e8fcf8619895c4c916c52653892ec1 ]
BUG: KASAN: slab-use-after-free in tcp_write_timer_handler+0x156/0x3e0 Read of size 1 at addr ffff888111f322cd by task swapper/0/0 CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted 6.12.0-rc4-dirty #7 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 Call Trace: <IRQ> dump_stack_lvl+0x68/0xa0 print_address_description.constprop.0+0x2c/0x3d0 print_report+0xb4/0x270 kasan_report+0xbd/0xf0 tcp_write_timer_handler+0x156/0x3e0 tcp_write_timer+0x66/0x170 call_timer_fn+0xfb/0x1d0 __run_timers+0x3f8/0x480 run_timer_softirq+0x9b/0x100 handle_softirqs+0x153/0x390 __irq_exit_rcu+0x103/0x120 irq_exit_rcu+0xe/0x20 sysvec_apic_timer_interrupt+0x76/0x90 </IRQ> <TASK> asm_sysvec_apic_timer_interrupt+0x1a/0x20 RIP: 0010:default_idle+0xf/0x20 Code: 4c 01 c7 4c 29 c2 e9 72 ff ff ff 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 66 90 0f 00 2d 33 f8 25 00 fb f4 <fa> c3 cc cc cc cc 66 66 2e 0f 1f 84 00 00 00 00 00 90 90 90 90 90 RSP: 0018:ffffffffa2007e28 EFLAGS: 00000242 RAX: 00000000000f3b31 RBX: 1ffffffff4400fc7 RCX: ffffffffa09c3196 RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffffffff9f00590f RBP: 0000000000000000 R08: 0000000000000001 R09: ffffed102360835d R10: ffff88811b041aeb R11: 0000000000000001 R12: 0000000000000000 R13: ffffffffa202d7c0 R14: 0000000000000000 R15: 00000000000147d0 default_idle_call+0x6b/0xa0 cpuidle_idle_call+0x1af/0x1f0 do_idle+0xbc/0x130 cpu_startup_entry+0x33/0x40 rest_init+0x11f/0x210 start_kernel+0x39a/0x420 x86_64_start_reservations+0x18/0x30 x86_64_start_kernel+0x97/0xa0 common_startup_64+0x13e/0x141 </TASK> Allocated by task 595: kasan_save_stack+0x24/0x50 kasan_save_track+0x14/0x30 __kasan_slab_alloc+0x87/0x90 kmem_cache_alloc_noprof+0x12b/0x3f0 copy_net_ns+0x94/0x380 create_new_namespaces+0x24c/0x500 unshare_nsproxy_namespaces+0x75/0xf0 ksys_unshare+0x24e/0x4f0 __x64_sys_unshare+0x1f/0x30 do_syscall_64+0x70/0x180 entry_SYSCALL_64_after_hwframe+0x76/0x7e Freed by task 100: kasan_save_stack+0x24/0x50 kasan_save_track+0x14/0x30 kasan_save_free_info+0x3b/0x60 __kasan_slab_free+0x54/0x70 kmem_cache_free+0x156/0x5d0 cleanup_net+0x5d3/0x670 process_one_work+0x776/0xa90 worker_thread+0x2e2/0x560 kthread+0x1a8/0x1f0 ret_from_fork+0x34/0x60 ret_from_fork_asm+0x1a/0x30
Reproduction script:
mkdir -p /mnt/nfsshare
mkdir -p /mnt/nfs/netns_1
mkfs.ext4 /dev/sdb
mount /dev/sdb /mnt/nfsshare
systemctl restart nfs-server
chmod 777 /mnt/nfsshare
exportfs -i -o rw,no_root_squash *:/mnt/nfsshare
ip netns add netns_1
ip link add name veth_1_peer type veth peer veth_1 ifconfig veth_1_peer 11.11.0.254 up
ip link set veth_1 netns netns_1
ip netns exec netns_1 ifconfig veth_1 11.11.0.1
ip netns exec netns_1 /root/iptables -A OUTPUT -d 11.11.0.254 -p tcp \
--tcp-flags FIN FIN -j DROP
(note: In my environment, a DESTROY_CLIENTID operation is always sent
immediately, breaking the nfs tcp connection.)
ip netns exec netns_1 timeout -s 9 300 mount -t nfs -o proto=tcp,vers=4.1 \ 11.11.0.254:/mnt/nfsshare /mnt/nfs/netns_1
ip netns del netns_1
The reason here is that the tcp socket in netns_1 (nfs side) has been shutdown and closed (done in xs_destroy), but the FIN message (with ack) is discarded, and the nfsd side keeps sending retransmission messages. As a result, when the tcp sock in netns_1 processes the received message, it sends the message (FIN message) in the sending queue, and the tcp timer is re-established. When the network namespace is deleted, the net structure accessed by tcp's timer handler function causes problems.
To fix this problem, let's hold netns refcnt for the tcp kernel socket as done in other modules. This is an ugly hack which can easily be backported to earlier kernels. A proper fix which cleans up the interfaces will follow, but may not be so easy to backport.
--- net/sunrpc/svcsock.c | 3 +++ net/sunrpc/xprtsock.c | 6 ++++++ 2 files changed, 9 insertions(+)
net/sunrpc/svcsock.c +3 -0
@@ -1457,6 +1457,9 @@ static struct svc_xprt *svc_create_socket(struct svc_serv *serv, newlen = error;if (protocol ==IPPROTO_TCP ) { + sock->sk->sk_net_refcnt =1 ; +get_net_track (net, &sock->sk->ns_tracker,GFP_KERNEL ); +sock_inuse_add (net,1 );if ((error =kernel_listen (sock,64 )) <0 ) goto bummer; }
net/sunrpc/xprtsock.c +6 -0
@@ -1855,6 +1855,12 @@ static struct socket *xs_create_sock(struct rpc_xprt *xprt, goto out; } +if (protocol ==IPPROTO_TCP ) { + sock->sk->sk_net_refcnt =1 ; +get_net_track (xprt->xprt_net, &sock->sk->ns_tracker,GFP_KERNEL ); +sock_inuse_add (xprt->xprt_net,1 ); + } + filp =sock_alloc_file (sock,O_NONBLOCK ,NULL );if (IS_ERR (filp))return ERR_CAST (filp);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 697/1887 smb: Dont leak cfid when reconnect races with open_cached_dir
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paul Aurich <[email protected]>
[ Upstream commit 7afb86733685c64c604d32faf00fa4a1f22c2ab1 ]
open_cached_dir() may either race with the tcon reconnection even before compound_send_recv() or directly trigger a reconnection via SMB2_open_init() or SMB_query_info_init().
The reconnection process invokes invalidate_all_cached_dirs() via cifs_mark_open_files_invalid(), which removes all cfids from the cfids->entries list but doesn't drop a ref if has_lease isn't true. This results in the currently-being-constructed cfid not being on the list, but still having a refcount of 2. It leaks if returned from open_cached_dir().
Fix this by setting cfid->has_lease when the ref is actually taken; the cfid will not be used by other threads until it has a valid time.
Addresses these kmemleaks:
unreferenced object 0xffff8881090c4000 (size 1024):
comm "bash", pid 1860, jiffies 4295126592 hex dump (first 32 bytes):
00 01 00 00 00 00 ad de 22 01 00 00 00 00 ad de ........".......
00 ca 45 22 81 88 ff ff f8 dc 4f 04 81 88 ff ff ..E"......O.....
backtrace (crc 6f58c20f):
[<ffffffff8b895a1e>] __kmalloc_cache_noprof+0x2be/0x350
[<ffffffff8bda06e3>] open_cached_dir+0x993/0x1fb0
[<ffffffff8bdaa750>] cifs_readdir+0x15a0/0x1d50
[<ffffffff8b9a853f>] iterate_dir+0x28f/0x4b0
[<ffffffff8b9a9aed>] __x64_sys_getdents64+0xfd/0x200
[<ffffffff8cf6da05>] do_syscall_64+0x95/0x1a0
[<ffffffff8d00012f>] entry_SYSCALL_64_after_hwframe+0x76/0x7eunreferenced object 0xffff8881044fdcf8 (size 8):
comm "bash", pid 1860, jiffies 4295126592
hex dump (first 8 bytes):
00 cc cc cc cc cc cc cc ........
backtrace (crc 10c106a9):
[<ffffffff8b89a3d3>] __kmalloc_node_track_caller_noprof+0x363/0x480
[<ffffffff8b7d7256>] kstrdup+0x36/0x60
[<ffffffff8bda0700>] open_cached_dir+0x9b0/0x1fb0
[<ffffffff8bdaa750>] cifs_readdir+0x15a0/0x1d50
[<ffffffff8b9a853f>] iterate_dir+0x28f/0x4b0
[<ffffffff8b9a9aed>] __x64_sys_getdents64+0xfd/0x200
[<ffffffff8cf6da05>] do_syscall_64+0x95/0x1a0
[<ffffffff8d00012f>] entry_SYSCALL_64_after_hwframe+0x76/0x7eAnd addresses these BUG splats when unmounting the SMB filesystem:
BUG: Dentry ffff888140590ba0{i=1000000000080,n=/} still in use (2) [unmount of cifs cifs]
WARNING: CPU: 3 PID: 3433 at fs/dcache.c:1536 umount_check+0xd0/0x100
Modules linked in:
CPU: 3 UID: 0 PID: 3433 Comm: bash Not tainted 6.12.0-rc4-g850925a8133c-dirty #49
Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 11/12/2020
RIP: 0010:umount_check+0xd0/0x100
Code: 8d 7c 24 40 e8 31 5a f4 ff 49 8b 54 24 40 41 56 49 89 e9 45 89 e8 48 89 d9 41 57 48 89 de 48 c7 c7 80 e7 db ac e8 f0 72 9a ff <0f> 0b 58 31 c0 5a 5b 5d 41 5c 41 5d 41 5e 41 5f e9 2b e5 5d 01 41
RSP: 0018:ffff88811cc27978 EFLAGS: 00010286
RAX: 0000000000000000 RBX: ffff888140590ba0 RCX: ffffffffaaf20bae
RDX: dffffc0000000000 RSI: 0000000000000008 RDI: ffff8881f6fb6f40
RBP: ffff8881462ec000 R08: 0000000000000001 R09: ffffed1023984ee3
R10: ffff88811cc2771f R11: 00000000016cfcc0 R12: ffff888134383e08
R13: 0000000000000002 R14: ffff8881462ec668 R15: ffffffffaceab4c0
FS: 00007f23bfa98740(0000) GS:ffff8881f6f80000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000556de4a6f808 CR3: 0000000123c80000 CR4: 0000000000350ef0
Call Trace:
<TASK>
d_walk+0x6a/0x530
shrink_dcache_for_umount+0x6a/0x200
generic_shutdown_super+0x52/0x2a0
kill_anon_super+0x22/0x40
cifs_kill_sb+0x159/0x1e0
deactivate_locked_super+0x66/0xe0
cleanup_mnt+0x140/0x210
task_work_run+0xfb/0x170
syscall_exit_to_user_mode+0x29f/0x2b0
do_syscall_64+0xa1/0x1a0
entry_SYSCALL_64_after_hwframe+0x76/0x7e
RIP: 0033:0x7f23bfb93ae7
Code: ff ff ff ff c3 66 0f 1f 44 00 00 48 8b 0d 11 93 0d 00 f7 d8 64 89 01 b8 ff ff ff ff eb bf 0f 1f 44 00 00 b8 50 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d e9 92 0d 00 f7 d8 64 89 01 48
RSP: 002b:00007ffee9138598 EFLAGS: 00000246 ORIG_RAX: 0000000000000050
RAX: 0000000000000000 RBX: 0000558f1803e9a0 RCX: 00007f23bfb93ae7
RDX: 0000000000000000 RSI: 0000000000000004 RDI: 0000558f1803e9a0
RBP: 0000558f1803e600 R08: 0000000000000007 R09: 0000558f17fab610
R10: d91d5ec34ab757b0 R11: 0000000000000246 R12: 0000000000000001
R13: 0000000000000000 R14: 0000000000000015 R15: 0000000000000000
</TASK>
irq event stamp: 1163486
hardirqs last enabled at (1163485): [<ffffffffac98d344>] _raw_spin_unlock_irqrestore+0x34/0x60
hardirqs last disabled at (1163486): [<ffffffffac97dcfc>] __schedule+0xc7c/0x19a0
softirqs last enabled at (1163482): [<ffffffffab79a3ee>] __smb_send_rqst+0x3de/0x990
softirqs last disabled at (1163480): [<ffffffffac2314f1>] release_sock+0x21/0xf0
---[ end trace 0000000000000000 ]---VFS: Busy inodes after unmount of cifs (cifs)
------------[ cut here ]------------ kernel BUG at fs/super.c:661! Oops: invalid opcode: 0000 [#1] PREEMPT SMP KASAN NOPTI CPU: 1 UID: 0 PID: 3433 Comm: bash Tainted: G W 6.12.0-rc4-g850925a8133c-dirty #49 Tainted: [W]=WARN Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 11/12/2020 RIP: 0010:generic_shutdown_super+0x290/0x2a0 Code: e8 15 7c f7 ff 48 8b 5d 28 48 89 df e8 09 7c f7 ff 48 8b 0b 48 89 ee 48 8d 95 68 06 00 00 48 c7 c7 80 7f db ac e8 00 69 af ff <0f> 0b 66 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 00 90 90 90 90 90 90 RSP: 0018:ffff88811cc27a50 EFLAGS: 00010246 RAX: 000000000000003e RBX: ffffffffae994420 RCX: 0000000000000027 RDX: 0000000000000000 RSI: ffffffffab06180e RDI: ffff8881f6eb18c8 RBP: ffff8881462ec000 R08: 0000000000000001 R09: ffffed103edd6319 R10: ffff8881f6eb18cb R11: 00000000016d3158 R12: ffff8881462ec9c0 R13: ffff8881462ec050 R14: 0000000000000001 R15: 0000000000000000 FS: 00007f23bfa98740(0000) GS:ffff8881f6e80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f8364005d68 CR3: 0000000123c80000 CR4: 0000000000350ef0 Call Trace: <TASK> kill_anon_super+0x22/0x40 cifs_kill_sb+0x159/0x1e0 deactivate_locked_super+0x66/0xe0 cleanup_mnt+0x140/0x210 task_work_run+0xfb/0x170 syscall_exit_to_user_mode+0x29f/0x2b0 do_syscall_64+0xa1/0x1a0 entry_SYSCALL_64_after_hwframe+0x76/0x7e RIP: 0033:0x7f23bfb93ae7 </TASK> Modules linked in: ---[ end trace 0000000000000000 ]--- RIP: 0010:generic_shutdown_super+0x290/0x2a0 Code: e8 15 7c f7 ff 48 8b 5d 28 48 89 df e8 09 7c f7 ff 48 8b 0b 48 89 ee 48 8d 95 68 06 00 00 48 c7 c7 80 7f db ac e8 00 69 af ff <0f> 0b 66 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 00 90 90 90 90 90 90 RSP: 0018:ffff88811cc27a50 EFLAGS: 00010246 RAX: 000000000000003e RBX: ffffffffae994420 RCX: 0000000000000027 RDX: 0000000000000000 RSI: ffffffffab06180e RDI: ffff8881f6eb18c8 RBP: ffff8881462ec000 R08: 0000000000000001 R09: ffffed103edd6319 R10: ffff8881f6eb18cb R11: 00000000016d3158 R12: ffff8881462ec9c0 R13: ffff8881462ec050 R14: 0000000000000001 R15: 0000000000000000 FS: 00007f23bfa98740(0000) GS:ffff8881f6e80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f8364005d68 CR3: 0000000123c80000 CR4: 0000000000350ef0
This reproduces eventually with an SMB mount and two shells running these loops concurrently
- while true; do
cd ~; sleep 1;
for i in {1..3}; do cd /mnt/test/subdir;
echo $PWD; sleep 1; cd ..; echo $PWD; sleep 1;
done;
echo ...;
done
- while true; do
iptables -F OUTPUT; mount -t cifs -a;
for _ in {0..2}; do ls /mnt/test/subdir/ | wc -l; done;
iptables -I OUTPUT -p tcp --dport 445 -j DROP;
sleep 10
echo "unmounting"; umount -l -t cifs -a; echo "done unmounting";
sleep 20
echo "recovering"; iptables -F OUTPUT;
sleep 10;done
--- fs/smb/client/cached_dir.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-)
fs/smb/client/cached_dir.c +14 -13
@@ -57,6 +57,16 @@ static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids,list_add (&cfid->entry, &cfids->entries); cfid->on_list = true;kref_get (&cfid->refcount); +/* +* Set @cfid->has_lease to true during construction so that the lease +* reference can be put in cached_dir_lease_break() due to a potential +* lease break right after the request is sent or while @cfid is still +* being cached, or if a reconnection is triggered during construction. +* Concurrent processes won't be to use it yet due to @cfid->time being +* zero. +*/ + cfid->has_lease = true; +spin_unlock (&cfids->cfid_list_lock);return cfid; }
@@ -168,11 +178,11 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,return -ENOENT ; }/* -* At this point we either have a lease already and we can just -* return it. If not we are guaranteed to be the only thread accessing -* this cfid. +* Return cached fid if it is valid (has a lease and has a time). +* Otherwise, it is either a new entry or laundromat worker removed it +* from @cfids->entries. Caller will put last reference if the latter. */ -if (cfid->has_lease) { +if (cfid->has_lease && cfid->time) { *ret_cfid = cfid;kfree (utf16_path);return 0 ;
@@ -263,15 +273,6 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,smb2_set_related (&rqst[1 ]); -/* -* Set @cfid->has_lease to true before sending out compounded request so -* its lease reference can be put in cached_dir_lease_break() due to a -* potential lease break right after the request is sent or while @cfid -* is still being cached. Concurrent processes won't be to use it yet -* due to @cfid->time being zero. -*/ - cfid->has_lease = true; - rc =compound_send_recv (xid, ses, server, flags,2 , rqst, resp_buftype, rsp_iov);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 698/1887 smb: client: stop flooding dmesg in smb2_calc_signature()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paulo Alcantara <[email protected]>
[ Upstream commit a13ca780afab350f37f8be9eda2bf79d1aed9bdd ]
When having several mounts that share same credential and the client couldn't re-establish an SMB session due to an expired kerberos ticket or rotated password, smb2_calc_signature() will end up flooding dmesg when not finding SMB sessions to calculate signatures.
Stable-dep-of: 343d7fe6df9e ("smb: client: fix use-after-free of signing key")
--- fs/smb/client/smb2transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/smb/client/smb2transport.c +1 -1
@@ -242,7 +242,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, ses =smb2_find_smb_ses (server,le64_to_cpu (shdr->SessionId));if (unlikely (!ses)) { -cifs_server_dbg (VFS ,"%s: Could not find session\n" , __func__); +cifs_server_dbg (FYI ,"%s: Could not find session\n" , __func__);return -ENOENT ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 699/1887 smb: client: fix use-after-free of signing key
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paulo Alcantara <[email protected]>
[ Upstream commit 343d7fe6df9e247671440a932b6a73af4fa86d95 ]
Customers have reported use-after-free in @ses->auth_key.response with SMB2.1 + sign mounts which occurs due to following race:
task A task Bcifs_mount()
dfs_mount_share()
get_session()
cifs_mount_get_session() cifs_send_recv()
cifs_get_smb_ses() compound_send_recv()
cifs_setup_session() smb2_setup_request()
kfree_sensitive() smb2_calc_signature()
crypto_shash_setkey() *UAF*
Fix this by ensuring that we have a valid @ses->auth_key.response by checking whether @ses->ses_status is SES_GOOD or SES_EXITING with @ses->ses_lock held. After commit 24a9799aa8ef ("smb: client: fix UAF in smb2_reconnect_server()"), we made sure to call ->logoff() only when @ses was known to be good (e.g. valid ->auth_key.response), so it's safe to access signing key when @ses->ses_status == SES_EXITING.
--- fs/smb/client/smb2proto.h | 2 -- fs/smb/client/smb2transport.c | 56 +++++++++++++++++++++++++---------- 2 files changed, 40 insertions(+), 18 deletions(-)
fs/smb/client/smb2proto.h +0 -2
@@ -37,8 +37,6 @@ extern struct mid_q_entry *smb2_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst);extern struct mid_q_entry *smb2_setup_async_request (struct TCP_Server_Info *server,struct smb_rqst *rqst); -extern struct cifs_ses *smb2_find_smb_ses (struct TCP_Server_Info *server, -__u64 ses_id);extern struct cifs_tcon *smb2_find_smb_tcon (struct TCP_Server_Info *server,__u64 ses_id,__u32 tid); extern int smb2_calc_signature(struct smb_rqst *rqst,
fs/smb/client/smb2transport.c +40 -16
100 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 700/1887 io_uring: check for overflows in io_pin_pages
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pavel Begunkov <[email protected]>
[ Upstream commit 0c0a4eae26ac78379d0c1db053de168a8febc6c9 ]
WARNING: CPU: 0 PID: 5834 at io_uring/memmap.c:144 io_pin_pages+0x149/0x180 io_uring/memmap.c:144 CPU: 0 UID: 0 PID: 5834 Comm: syz-executor825 Not tainted 6.12.0-next-20241118-syzkaller #0 Call Trace: <TASK> __io_uaddr_map+0xfb/0x2d0 io_uring/memmap.c:183 io_rings_map io_uring/io_uring.c:2611 [inline] io_allocate_scq_urings+0x1c0/0x650 io_uring/io_uring.c:3470 io_uring_create+0x5b5/0xc00 io_uring/io_uring.c:3692 io_uring_setup io_uring/io_uring.c:3781 [inline] ... </TASK>
io_pin_pages()'s uaddr parameter came directly from the user and can be garbage. Don't just add size to it as it can overflow.
--- io_uring/rsrc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
io_uring/rsrc.c +6 -1
@@ -983,7 +983,12 @@ struct page **io_pin_pages(unsigned long ubuf, unsigned long len, int *npages)struct page **pages =NULL ;int i, pret, ret = -ENOMEM ; - end = (ubuf + len +PAGE_SIZE -1 ) >>PAGE_SHIFT ; +if (check_add_overflow (ubuf, len, &end)) +return ERR_PTR (-EOVERFLOW ); +if (check_add_overflow (end,PAGE_SIZE -1 , &end)) +return ERR_PTR (-EOVERFLOW ); + + end = end >>PAGE_SHIFT ; start = ubuf >>PAGE_SHIFT ; nr_pages = end - start;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 701/1887 KVM: arm64: Get rid of userspace_irqchip_in_use
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Raghavendra Rao Ananta <[email protected]>
[ Upstream commit 38d7aacca09230fdb98a34194fec2af597e8e20d ]
Improper use of userspace_irqchip_in_use led to syzbot hitting the following WARN_ON() in kvm_timer_update_irq():
WARNING: CPU: 0 PID: 3281 at arch/arm64/kvm/arch_timer.c:459 kvm_timer_update_irq+0x21c/0x394 Call trace: kvm_timer_update_irq+0x21c/0x394 arch/arm64/kvm/arch_timer.c:459 kvm_timer_vcpu_reset+0x158/0x684 arch/arm64/kvm/arch_timer.c:968 kvm_reset_vcpu+0x3b4/0x560 arch/arm64/kvm/reset.c:264 kvm_vcpu_set_target arch/arm64/kvm/arm.c:1553 [inline] kvm_arch_vcpu_ioctl_vcpu_init arch/arm64/kvm/arm.c:1573 [inline] kvm_arch_vcpu_ioctl+0x112c/0x1b3c arch/arm64/kvm/arm.c:1695 kvm_vcpu_ioctl+0x4ec/0xf74 virt/kvm/kvm_main.c:4658 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:907 [inline] __se_sys_ioctl fs/ioctl.c:893 [inline] __arm64_sys_ioctl+0x108/0x184 fs/ioctl.c:893 __invoke_syscall arch/arm64/kernel/syscall.c:35 [inline] invoke_syscall+0x78/0x1b8 arch/arm64/kernel/syscall.c:49 el0_svc_common+0xe8/0x1b0 arch/arm64/kernel/syscall.c:132 do_el0_svc+0x40/0x50 arch/arm64/kernel/syscall.c:151 el0_svc+0x54/0x14c arch/arm64/kernel/entry-common.c:712 el0t_64_sync_handler+0x84/0xfc arch/arm64/kernel/entry-common.c:730 el0t_64_sync+0x190/0x194 arch/arm64/kernel/entry.S:598
The following sequence led to the scenario:
- Userspace creates a VM and a vCPU.
- The vCPU is initialized with KVM_ARM_VCPU_PMU_V3 during KVM_ARM_VCPU_INIT.
- Without any other setup, such as vGIC or vPMU, userspace issues KVM_RUN on the vCPU. Since the vPMU is requested, but not setup, kvm_arm_pmu_v3_enable() fails in kvm_arch_vcpu_run_pid_change(). As a result, KVM_RUN returns after enabling the timer, but before incrementing 'userspace_irqchip_in_use':
kvm_arch_vcpu_run_pid_change()
ret = kvm_arm_pmu_v3_enable()
if (!vcpu->arch.pmu.created)
return -EINVAL;
if (ret)
return ret;
[...]
if (!irqchip_in_kernel(kvm))
static_branch_inc(&userspace_irqchip_in_use);
- Userspace ignores the error and issues KVM_ARM_VCPU_INIT again.
Since the timer is already enabled, control moves through the
following flow, ultimately hitting the WARN_ON():
kvm_timer_vcpu_reset()
if (timer->enabled)
kvm_timer_update_irq()
if (!userspace_irqchip())
ret = kvm_vgic_inject_irq()
ret = vgic_lazy_init()
if (unlikely(!vgic_initialized(kvm)))
if (kvm->arch.vgic.vgic_model !=
KVM_DEV_TYPE_ARM_VGIC_V2)
return -EBUSY;
WARN_ON(ret);Theoretically, since userspace_irqchip_in_use's functionality can be simply replaced by '!irqchip_in_kernel()', get rid of the static key to avoid the mismanagement, which also helps with the syzbot issue.
--- arch/arm64/include/asm/kvm_host.h | 2 -- arch/arm64/kvm/arch_timer.c | 3 +-- arch/arm64/kvm/arm.c | 18 +++--------------- 3 files changed, 4 insertions(+), 19 deletions(-)
arch/arm64/include/asm/kvm_host.h +0 -2
@@ -64,8 +64,6 @@ enum kvm_mode { };enum kvm_mode kvm_get_mode (void ); -DECLARE_STATIC_KEY_FALSE (userspace_irqchip_in_use); -extern unsigned int kvm_sve_max_vl;extern unsigned int kvm_host_sve_max_vl;int kvm_arm_init_sve (void );
arch/arm64/kvm/arch_timer.c +1 -2
@@ -161,8 +161,7 @@ static void get_timer_map(struct kvm_vcpu *vcpu, struct timer_map *map)static inline bool userspace_irqchip (struct kvm *kvm) { -return static_branch_unlikely (&userspace_irqchip_in_use) && -unlikely (!irqchip_in_kernel (kvm)); +return unlikely (!irqchip_in_kernel (kvm)); }static void soft_timer_start (struct hrtimer *hrt,u64 ns)
arch/arm64/kvm/arm.c +3 -15
@@ -56,7 +56,6 @@ DECLARE_KVM_NVHE_PER_CPU(struct kvm_nvhe_init_params, kvm_init_params);static bool vgic_present; static DEFINE_PER_CPU(unsigned char, kvm_arm_hardware_enabled); -DEFINE_STATIC_KEY_FALSE (userspace_irqchip_in_use);int kvm_arch_vcpu_should_kick (struct kvm_vcpu *vcpu) {
@@ -384,9 +383,6 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)void kvm_arch_vcpu_destroy (struct kvm_vcpu *vcpu) { -if (vcpu_has_run_once (vcpu) &&unlikely (!irqchip_in_kernel (vcpu->kvm))) -static_branch_dec (&userspace_irqchip_in_use); -kvm_mmu_free_memory_cache (&vcpu->arch.mmu_page_cache);kvm_timer_vcpu_terminate (vcpu);kvm_pmu_vcpu_destroy (vcpu);
@@ -609,14 +605,6 @@ int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)if (ret)return ret; -if (!irqchip_in_kernel (kvm)) { -/* -* Tell the rest of the code that there are userspace irqchip -* VMs in the wild. -*/ -static_branch_inc (&userspace_irqchip_in_use); - } -/* * Initialize traps for protected VMs. * NOTE: Move to run in EL2 directly, rather than via a hypercall, once
@@ -829,7 +817,7 @@ static bool kvm_vcpu_exit_request(struct kvm_vcpu *vcpu, int *ret)* state gets updated in kvm_timer_update_run and * kvm_pmu_update_run below). */ -if (static_branch_unlikely (&userspace_irqchip_in_use)) { +if (unlikely (!irqchip_in_kernel (vcpu->kvm))) {if (kvm_timer_should_notify_user (vcpu) ||kvm_pmu_should_notify_user (vcpu)) { *ret = -EINTR ;
@@ -948,7 +936,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) vcpu->mode =OUTSIDE_GUEST_MODE ;isb ();/* Ensure work in x_flush_hwstate is committed */ kvm_pmu_sync_hwstate (vcpu); -if (static_branch_unlikely (&userspace_irqchip_in_use)) +if (unlikely (!irqchip_in_kernel (vcpu->kvm)))kvm_timer_sync_user (vcpu);kvm_vgic_sync_hwstate (vcpu);local_irq_enable ();
@@ -994,7 +982,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)* we don't want vtimer interrupts to race with syncing the * timer virtual interrupt state. */ -if (static_branch_unlikely (&userspace_irqchip_in_use)) +if (unlikely (!irqchip_in_kernel (vcpu->kvm)))kvm_timer_sync_user (vcpu);kvm_arch_vcpu_ctxsync_fp (vcpu);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 702/1887 nfsd: release svc_expkey/svc_export with rcu_work
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yang Erkun <[email protected]>
[ Upstream commit f8c989a0c89a75d30f899a7cabdc14d72522bb8d ]
The last reference for cache_head can be reduced to zero in c_show and e_show(using rcu_read_lock and rcu_read_unlock). Consequently, svc_export_put and expkey_put will be invoked, leading to two issues:
1. The svc_export_put will directly free ex_uuid. However, e_show/c_show will access ex_uuid after cache_put, which can trigger a use-after-free issue, shown below.
==================================================================
BUG: KASAN: slab-use-after-free in svc_export_show+0x362/0x430 [nfsd]
Read of size 1 at addr ff11000010fdc120 by task cat/870
CPU: 1 UID: 0 PID: 870 Comm: cat Not tainted 6.12.0-rc3+ #1
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS
1.16.1-2.fc37 04/01/2014
Call Trace:
<TASK>
dump_stack_lvl+0x53/0x70
print_address_description.constprop.0+0x2c/0x3a0
print_report+0xb9/0x280
kasan_report+0xae/0xe0
svc_export_show+0x362/0x430 [nfsd]
c_show+0x161/0x390 [sunrpc]
seq_read_iter+0x589/0x770
seq_read+0x1e5/0x270
proc_reg_read+0xe1/0x140
vfs_read+0x125/0x530
ksys_read+0xc1/0x160
do_syscall_64+0x5f/0x170
entry_SYSCALL_64_after_hwframe+0x76/0x7e
Allocated by task 830:
kasan_save_stack+0x20/0x40
kasan_save_track+0x14/0x30
__kasan_kmalloc+0x8f/0xa0
__kmalloc_node_track_caller_noprof+0x1bc/0x400
kmemdup_noprof+0x22/0x50
svc_export_parse+0x8a9/0xb80 [nfsd]
cache_do_downcall+0x71/0xa0 [sunrpc]
cache_write_procfs+0x8e/0xd0 [sunrpc]
proc_reg_write+0xe1/0x140
vfs_write+0x1a5/0x6d0
ksys_write+0xc1/0x160
do_syscall_64+0x5f/0x170
entry_SYSCALL_64_after_hwframe+0x76/0x7e
Freed by task 868:
kasan_save_stack+0x20/0x40
kasan_save_track+0x14/0x30
kasan_save_free_info+0x3b/0x60
__kasan_slab_free+0x37/0x50
kfree+0xf3/0x3e0
svc_export_put+0x87/0xb0 [nfsd]
cache_purge+0x17f/0x1f0 [sunrpc]
nfsd_destroy_serv+0x226/0x2d0 [nfsd]
nfsd_svc+0x125/0x1e0 [nfsd]
write_threads+0x16a/0x2a0 [nfsd]
nfsctl_transaction_write+0x74/0xa0 [nfsd]
vfs_write+0x1a5/0x6d0
ksys_write+0xc1/0x160
do_syscall_64+0x5f/0x170
entry_SYSCALL_64_after_hwframe+0x76/0x7e2. We cannot sleep while using rcu_read_lock/rcu_read_unlock. However, svc_export_put/expkey_put will call path_put, which subsequently triggers a sleeping operation due to the following dput.
=============================
WARNING: suspicious RCU usage
5.10.0-dirty #141 Not tainted
-----------------------------
...
Call Trace: dump_stack+0x9a/0xd0 ___might_sleep+0x231/0x240 dput+0x39/0x600 path_put+0x1b/0x30 svc_export_put+0x17/0x80 e_show+0x1c9/0x200 seq_read_iter+0x63f/0x7c0 seq_read+0x226/0x2d0 vfs_read+0x113/0x2c0 ksys_read+0xc9/0x170 do_syscall_64+0x33/0x40 entry_SYSCALL_64_after_hwframe+0x67/0xd1
Fix these issues by using rcu_work to help release svc_expkey/svc_export. This approach allows for an asynchronous context to invoke path_put and also facilitates the freeing of uuid/exp/key after an RCU grace period.
--- fs/nfsd/export.c | 31 +++++++++++++++++++++++++------ fs/nfsd/export.h | 4 ++-- 2 files changed, 27 insertions(+), 8 deletions(-)
fs/nfsd/export.c +25 -6
@@ -40,15 +40,24 @@#define EXPKEY_HASHMAX (1 << EXPKEY_HASHBITS)#define EXPKEY_HASHMASK (EXPKEY_HASHMAX -1) -static void expkey_put (struct kref *ref) +static void expkey_put_work (struct work_struct *work) { - struct svc_expkey *key = container_of(ref, struct svc_expkey, h.ref); +struct svc_expkey *key = + container_of(to_rcu_work(work), struct svc_expkey, ek_rcu_work);if (test_bit (CACHE_VALID , &key->h.flags) && !test_bit (CACHE_NEGATIVE , &key->h.flags))path_put (&key->ek_path);auth_domain_put (key->ek_client); -kfree_rcu (key, ek_rcu); +kfree (key); +} + +static void expkey_put (struct kref *ref) +{ + struct svc_expkey *key = container_of(ref, struct svc_expkey, h.ref); + +INIT_RCU_WORK (&key->ek_rcu_work, expkey_put_work); +queue_rcu_work (system_wq, &key->ek_rcu_work); }static int expkey_upcall (struct cache_detail *cd,struct cache_head *h)
@@ -351,16 +360,26 @@ static void export_stats_destroy(struct export_stats *stats) EXP_STATS_COUNTERS_NUM); } -static void svc_export_put (struct kref *ref) +static void svc_export_put_work (struct work_struct *work) { - struct svc_export *exp = container_of(ref, struct svc_export, h.ref); +struct svc_export *exp = + container_of(to_rcu_work(work), struct svc_export, ex_rcu_work); +path_put (&exp->ex_path);auth_domain_put (exp->ex_client);nfsd4_fslocs_free (&exp->ex_fslocs);export_stats_destroy (exp->ex_stats);kfree (exp->ex_stats);kfree (exp->ex_uuid); -kfree_rcu (exp, ex_rcu); +kfree (exp); +} + +static void svc_export_put (struct kref *ref) +{ + struct svc_export *exp = container_of(ref, struct svc_export, h.ref); + +INIT_RCU_WORK (&exp->ex_rcu_work, svc_export_put_work); +queue_rcu_work (system_wq, &exp->ex_rcu_work); }static int svc_export_upcall (struct cache_detail *cd,struct cache_head *h)
fs/nfsd/export.h +2 -2
@@ -75,7 +75,7 @@ struct svc_export {u32 ex_layout_types;struct nfsd4_deviceid_map *ex_devid_map;struct cache_detail *cd; -struct rcu_head ex_rcu; +struct rcu_work ex_rcu_work;struct export_stats *ex_stats; };
@@ -91,7 +91,7 @@ struct svc_expkey {u32 ek_fsid[6 ];struct path ek_path; -struct rcu_head ek_rcu; +struct rcu_work ek_rcu_work; };#define EX_ISSYNC (exp) (!((exp)->ex_flags & NFSEXP_ASYNC))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 703/1887 RDMA/mlx5: Move events notifier registration to be after device registration
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Patrisious Haddad <[email protected]>
[ Upstream commit ede132a5cf559f3ab35a4c28bac4f4a6c20334d8 ]
Move pkey change work initialization and cleanup from device resources stage to notifier stage, since this is the stage which handles this work events.
Fix a race between the device deregistration and pkey change work by moving MLX5_IB_STAGE_DEVICE_NOTIFIER to be after MLX5_IB_STAGE_IB_REG in order to ensure that the notifier is deregistered before the device during cleanup. Which ensures there are no works that are being executed after the device has already unregistered which can cause the panic below.
BUG: kernel NULL pointer dereference, address: 0000000000000000 PGD 0 P4D 0 Oops: 0000 [#1] PREEMPT SMP PTI CPU: 1 PID: 630071 Comm: kworker/1:2 Kdump: loaded Tainted: G W OE --------- --- 5.14.0-162.6.1.el9_1.x86_64 #1 Hardware name: Microsoft Corporation Virtual Machine/Virtual Machine, BIOS 090008 02/27/2023 Workqueue: events pkey_change_handler [mlx5_ib] RIP: 0010:setup_qp+0x38/0x1f0 [mlx5_ib] Code: ee 41 54 45 31 e4 55 89 f5 53 48 89 fb 48 83 ec 20 8b 77 08 65 48 8b 04 25 28 00 00 00 48 89 44 24 18 48 8b 07 48 8d 4c 24 16 <4c> 8b 38 49 8b 87 80 0b 00 00 4c 89 ff 48 8b 80 08 05 00 00 8b 40 RSP: 0018:ffffbcc54068be20 EFLAGS: 00010282 RAX: 0000000000000000 RBX: ffff954054494128 RCX: ffffbcc54068be36 RDX: ffff954004934000 RSI: 0000000000000001 RDI: ffff954054494128 RBP: 0000000000000023 R08: ffff954001be2c20 R09: 0000000000000001 R10: ffff954001be2c20 R11: ffff9540260133c0 R12: 0000000000000000 R13: 0000000000000023 R14: 0000000000000000 R15: ffff9540ffcb0905 FS: 0000000000000000(0000) GS:ffff9540ffc80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000000 CR3: 000000010625c001 CR4: 00000000003706e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: mlx5_ib_gsi_pkey_change+0x20/0x40 [mlx5_ib] process_one_work+0x1e8/0x3c0 worker_thread+0x50/0x3b0 ? rescuer_thread+0x380/0x380 kthread+0x149/0x170 ? set_kthread_struct+0x50/0x50 ret_from_fork+0x22/0x30 Modules linked in: rdma_ucm(OE) rdma_cm(OE) iw_cm(OE) ib_ipoib(OE) ib_cm(OE) ib_umad(OE) mlx5_ib(OE) mlx5_fwctl(OE) fwctl(OE) ib_uverbs(OE) mlx5_core(OE) mlxdevm(OE) ib_core(OE) mlx_compat(OE) psample mlxfw(OE) tls knem(OE) netconsole nfsv3 nfs_acl nfs lockd grace fscache netfs qrtr rfkill sunrpc intel_rapl_msr intel_rapl_common rapl hv_balloon hv_utils i2c_piix4 pcspkr joydev fuse ext4 mbcache jbd2 sr_mod sd_mod cdrom t10_pi sg ata_generic pci_hyperv pci_hyperv_intf hyperv_drm drm_shmem_helper drm_kms_helper hv_storvsc syscopyarea hv_netvsc sysfillrect sysimgblt hid_hyperv fb_sys_fops scsi_transport_fc hyperv_keyboard drm ata_piix crct10dif_pclmul crc32_pclmul crc32c_intel libata ghash_clmulni_intel hv_vmbus serio_raw [last unloaded: ib_core] CR2: 0000000000000000 ---[ end trace f6f8be4eae12f7bc ]---
--- drivers/infiniband/hw/mlx5/main.c | 40 +++++++++++++--------------- drivers/infiniband/hw/mlx5/mlx5_ib.h | 2 +- 2 files changed, 20 insertions(+), 22 deletions(-)
drivers/infiniband/hw/mlx5/main.c +19 -21
@@ -2802,7 +2802,6 @@ static int mlx5_ib_dev_res_init(struct mlx5_ib_dev *dev)struct ib_srq_init_attr attr;struct ib_device *ibdev;struct ib_cq_init_attr cq_attr = {.cqe =1 }; -int port;int ret =0 ; ibdev = &dev->ib_dev;
@@ -2851,10 +2850,6 @@ static int mlx5_ib_dev_res_init(struct mlx5_ib_dev *dev) goto error6; } -for (port =0 ; port <ARRAY_SIZE (devr->ports); ++port) -INIT_WORK (&devr->ports[port].pkey_change_work, - pkey_change_handler); -return 0 ; error6:
@@ -2873,16 +2868,6 @@ static int mlx5_ib_dev_res_init(struct mlx5_ib_dev *dev)static void mlx5_ib_dev_res_cleanup (struct mlx5_ib_dev *dev) {struct mlx5_ib_resources *devr = &dev->devr; -int port; - -/* -* Make sure no change P_Key work items are still executing. -* -* At this stage, the mlx5_ib_event should be unregistered -* and it ensures that no new works are added. -*/ -for (port =0 ; port <ARRAY_SIZE (devr->ports); ++port) -cancel_work_sync (&devr->ports[port].pkey_change_work);ib_destroy_srq (devr->s1);ib_destroy_srq (devr->s0);
@@ -4089,6 +4074,13 @@ static void mlx5_ib_stage_delay_drop_cleanup(struct mlx5_ib_dev *dev)static int mlx5_ib_stage_dev_notifier_init (struct mlx5_ib_dev *dev) { +struct mlx5_ib_resources *devr = &dev->devr; +int port; + +for (port =0 ; port <ARRAY_SIZE (devr->ports); ++port) +INIT_WORK (&devr->ports[port].pkey_change_work, + pkey_change_handler); + dev->mdev_events.notifier_call = mlx5_ib_event;mlx5_notifier_register (dev->mdev, &dev->mdev_events);return 0 ;
@@ -4096,7 +4088,13 @@ static int mlx5_ib_stage_dev_notifier_init(struct mlx5_ib_dev *dev)static void mlx5_ib_stage_dev_notifier_cleanup (struct mlx5_ib_dev *dev) { +struct mlx5_ib_resources *devr = &dev->devr; +int port; +mlx5_notifier_unregister (dev->mdev, &dev->mdev_events); + +for (port =0 ; port <ARRAY_SIZE (devr->ports); ++port) +cancel_work_sync (&devr->ports[port].pkey_change_work); } void __mlx5_ib_remove(struct mlx5_ib_dev *dev,
@@ -4170,9 +4168,6 @@ static const struct mlx5_ib_profile pf_profile = {STAGE_CREATE (MLX5_IB_STAGE_DEVICE_RESOURCES , mlx5_ib_dev_res_init, mlx5_ib_dev_res_cleanup), -STAGE_CREATE (MLX5_IB_STAGE_DEVICE_NOTIFIER , - mlx5_ib_stage_dev_notifier_init, - mlx5_ib_stage_dev_notifier_cleanup),STAGE_CREATE (MLX5_IB_STAGE_ODP , mlx5_ib_odp_init_one, mlx5_ib_odp_cleanup_one),
@@ -4197,6 +4192,9 @@ static const struct mlx5_ib_profile pf_profile = {STAGE_CREATE (MLX5_IB_STAGE_IB_REG , mlx5_ib_stage_ib_reg_init, mlx5_ib_stage_ib_reg_cleanup), +STAGE_CREATE (MLX5_IB_STAGE_DEVICE_NOTIFIER , + mlx5_ib_stage_dev_notifier_init, + mlx5_ib_stage_dev_notifier_cleanup),STAGE_CREATE (MLX5_IB_STAGE_POST_IB_REG_UMR , mlx5_ib_stage_post_ib_reg_umr_init, NULL),
@@ -4233,9 +4231,6 @@ const struct mlx5_ib_profile raw_eth_profile = {STAGE_CREATE (MLX5_IB_STAGE_DEVICE_RESOURCES , mlx5_ib_dev_res_init, mlx5_ib_dev_res_cleanup), -STAGE_CREATE (MLX5_IB_STAGE_DEVICE_NOTIFIER , - mlx5_ib_stage_dev_notifier_init, - mlx5_ib_stage_dev_notifier_cleanup),STAGE_CREATE (MLX5_IB_STAGE_COUNTERS , mlx5_ib_counters_init, mlx5_ib_counters_cleanup),
@@ -4257,6 +4252,9 @@ const struct mlx5_ib_profile raw_eth_profile = {STAGE_CREATE (MLX5_IB_STAGE_IB_REG , mlx5_ib_stage_ib_reg_init, mlx5_ib_stage_ib_reg_cleanup), +STAGE_CREATE (MLX5_IB_STAGE_DEVICE_NOTIFIER , + mlx5_ib_stage_dev_notifier_init, + mlx5_ib_stage_dev_notifier_cleanup),STAGE_CREATE (MLX5_IB_STAGE_POST_IB_REG_UMR , mlx5_ib_stage_post_ib_reg_umr_init, NULL),
drivers/infiniband/hw/mlx5/mlx5_ib.h +1 -1
@@ -927,7 +927,6 @@ enum mlx5_ib_stages {MLX5_IB_STAGE_QP ,MLX5_IB_STAGE_SRQ ,MLX5_IB_STAGE_DEVICE_RESOURCES , -MLX5_IB_STAGE_DEVICE_NOTIFIER ,MLX5_IB_STAGE_ODP ,MLX5_IB_STAGE_COUNTERS , MLX5_IB_STAGE_CONG_DEBUGFS,
@@ -936,6 +935,7 @@ enum mlx5_ib_stages {MLX5_IB_STAGE_PRE_IB_REG_UMR ,MLX5_IB_STAGE_WHITELIST_UID ,MLX5_IB_STAGE_IB_REG , +MLX5_IB_STAGE_DEVICE_NOTIFIER ,MLX5_IB_STAGE_POST_IB_REG_UMR ,MLX5_IB_STAGE_DELAY_DROP , MLX5_IB_STAGE_RESTRACK,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 704/1887 netfilter: IDLETIMER: Fix for possible ABBA deadlock
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Phil Sutter <[email protected]>
[ Upstream commit f36b01994d68ffc253c8296e2228dfe6e6431c03 ]
Deletion of the last rule referencing a given idletimer may happen at the same time as a read of its file in sysfs:
| ======================================================
| WARNING: possible circular locking dependency detected
| 6.12.0-rc7-01692-g5e9a28f41134-dirty #594 Not tainted
| ------------------------------------------------------
| iptables/3303 is trying to acquire lock:
| ffff8881057e04b8 (kn->active#48){++++}-{0:0}, at: __kernfs_remove+0x20
|
| but task is already holding lock:
| ffffffffa0249068 (list_mutex){+.+.}-{3:3}, at: idletimer_tg_destroy_v]
|
| which lock already depends on the new lock.A simple reproducer is:
| #!/bin/bash | | while true; do | iptables -A INPUT -i foo -j IDLETIMER --timeout 10 --label "testme" | iptables -D INPUT -i foo -j IDLETIMER --timeout 10 --label "testme" | done & | while true; do | cat /sys/class/xt_idletimer/timers/testme >/dev/null | done
Avoid this by freeing list_mutex right after deleting the element from the list, then continuing with the teardown.
--- net/netfilter/xt_IDLETIMER.c | 52 +++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 24 deletions(-)
net/netfilter/xt_IDLETIMER.c +28 -24
@@ -415,21 +415,23 @@ static void idletimer_tg_destroy(const struct xt_tgdtor_param *par)mutex_lock (&list_mutex); -if (--info->timer->refcnt ==0 ) { -pr_debug ("deleting timer %s\n" , info->label); - -list_del (&info->timer->entry); -del_timer_sync (&info->timer->timer); -cancel_work_sync (&info->timer->work); -sysfs_remove_file (idletimer_tg_kobj, &info->timer->attr.attr); -kfree (info->timer->attr.attr.name); -kfree (info->timer); - }else { +if (--info->timer->refcnt >0 ) {pr_debug ("decreased refcnt of timer %s to %u\n" , info->label, info->timer->refcnt); +mutex_unlock (&list_mutex); +return ; } +pr_debug ("deleting timer %s\n" , info->label); + +list_del (&info->timer->entry);mutex_unlock (&list_mutex); + +del_timer_sync (&info->timer->timer); +cancel_work_sync (&info->timer->work); +sysfs_remove_file (idletimer_tg_kobj, &info->timer->attr.attr); +kfree (info->timer->attr.attr.name); +kfree (info->timer); }static void idletimer_tg_destroy_v1 (const struct xt_tgdtor_param *par)
@@ -440,25 +442,27 @@ static void idletimer_tg_destroy_v1(const struct xt_tgdtor_param *par)mutex_lock (&list_mutex); -if (--info->timer->refcnt ==0 ) { -pr_debug ("deleting timer %s\n" , info->label); - -list_del (&info->timer->entry); -if (info->timer->timer_type &XT_IDLETIMER_ALARM ) { -alarm_cancel (&info->timer->alarm); - }else { -del_timer_sync (&info->timer->timer); - } -cancel_work_sync (&info->timer->work); -sysfs_remove_file (idletimer_tg_kobj, &info->timer->attr.attr); -kfree (info->timer->attr.attr.name); -kfree (info->timer); - }else { +if (--info->timer->refcnt >0 ) {pr_debug ("decreased refcnt of timer %s to %u\n" , info->label, info->timer->refcnt); +mutex_unlock (&list_mutex); +return ; } +pr_debug ("deleting timer %s\n" , info->label); + +list_del (&info->timer->entry);mutex_unlock (&list_mutex); + +if (info->timer->timer_type &XT_IDLETIMER_ALARM ) { +alarm_cancel (&info->timer->alarm); + }else { +del_timer_sync (&info->timer->timer); + } +cancel_work_sync (&info->timer->work); +sysfs_remove_file (idletimer_tg_kobj, &info->timer->attr.attr); +kfree (info->timer->attr.attr.name); +kfree (info->timer); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 705/1887 drm: zynqmp_kms: Unplug DRM device before removal
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Anderson <[email protected]>
[ Upstream commit 2e07c88914fc5289c21820b1aa94f058feb38197 ]
Prevent userspace accesses to the DRM device from causing use-after-frees by unplugging the device before we remove it. This causes any further userspace accesses to result in an error without further calls into this driver's internals.
--- drivers/gpu/drm/xlnx/zynqmp_dpsub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/xlnx/zynqmp_dpsub.c +1 -1
@@ -253,7 +253,7 @@ static int zynqmp_dpsub_remove(struct platform_device *pdev)struct zynqmp_dpsub *dpsub =platform_get_drvdata (pdev);struct drm_device *drm = &dpsub->drm; -drm_dev_unregister (drm); +drm_dev_unplug (drm);drm_atomic_helper_shutdown (drm);drm_kms_helper_poll_fini (drm);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 706/1887 f2fs: fix to drop all discards after creating snapshot on lvm device
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chao Yu <[email protected]>
[ Upstream commit bc8aeb04fd80cb8cfae3058445c84410fd0beb5e ]
Piergiorgio reported a bug in bugzilla as below:
------------[ cut here ]------------ WARNING: CPU: 2 PID: 969 at fs/f2fs/segment.c:1330 RIP: 0010:__submit_discard_cmd+0x27d/0x400 [f2fs] Call Trace: __issue_discard_cmd+0x1ca/0x350 [f2fs] issue_discard_thread+0x191/0x480 [f2fs] kthread+0xcf/0x100 ret_from_fork+0x31/0x50 ret_from_fork_asm+0x1a/0x30
w/ below testcase, it can reproduce this bug quickly:
- pvcreate /dev/vdb
- vgcreate myvg1 /dev/vdb
- lvcreate -L 1024m -n mylv1 myvg1
- mount /dev/myvg1/mylv1 /mnt/f2fs
- dd if=/dev/zero of=/mnt/f2fs/file bs=1M count=20
- sync
- rm /mnt/f2fs/file
- sync
- lvcreate -L 1024m -s -n mylv1-snapshot /dev/myvg1/mylv1
- umount /mnt/f2fs
The root cause is: it will update discard_max_bytes of mounted lvm device to zero after creating snapshot on this lvm device, then, __submit_discard_cmd() will pass parameter @nr_sects w/ zero value to __blkdev_issue_discard(), it returns a NULL bio pointer, result in panic.
This patch changes as below for fixing:
1. Let's drop all remained discards in f2fs_unfreeze() if snapshot of lvm device is created.
2. Checking discard_max_bytes before submitting discard during __submit_discard_cmd().
--- fs/f2fs/segment.c | 9 +++++++++ fs/f2fs/super.c | 12 ++++++++++++ 2 files changed, 21 insertions(+)
fs/f2fs/segment.c +9 -0
@@ -1125,6 +1125,15 @@ static int __submit_discard_cmd(struct f2fs_sb_info *sbi,if (is_sbi_flag_set (sbi,SBI_NEED_FSCK ))return 0 ; +/* +* stop issuing discard for any of below cases: +* 1. device is conventional zone, but it doesn't support discard. +* 2. device is regulare device, after snapshot it doesn't support +* discard. +*/ +if (!bdev_max_discard_sectors (bdev)) +return -EOPNOTSUPP ; +trace_f2fs_issue_discard (bdev, dc->start, dc->len); lstart = dc->lstart;
fs/f2fs/super.c +12 -0
@@ -1742,6 +1742,18 @@ static int f2fs_freeze(struct super_block *sb)static int f2fs_unfreeze (struct super_block *sb) { +struct f2fs_sb_info *sbi =F2FS_SB (sb); + +/* +* It will update discard_max_bytes of mounted lvm device to zero +* after creating snapshot on this lvm device, let's drop all +* remained discards. +* We don't need to disable real-time discard because discard_max_bytes +* will recover after removal of snapshot. +*/ +if (test_opt (sbi,DISCARD ) && !f2fs_hw_support_discard (sbi)) +f2fs_issue_discard_timeout (sbi, false); +clear_sbi_flag (F2FS_SB (sb),SBI_IS_FREEZING );return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 707/1887 mm/slub: Avoid list corruption when removing a slab from the full list
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: yuan.gao <[email protected]>
[ Upstream commit dbc16915279a548a204154368da23d402c141c81 ]
Boot with slub_debug=UFPZ.
If allocated object failed in alloc_consistency_checks, all objects of the slab will be marked as used, and then the slab will be removed from the partial list.
When an object belonging to the slab got freed later, the remove_full() function is called. Because the slab is neither on the partial list nor on the full list, it eventually lead to a list corruption (actually a list poison being detected).
So we need to mark and isolate the slab page with metadata corruption, do not put it back in circulation.
Because the debug caches avoid all the fastpaths, reusing the frozen bit to mark slab page with metadata corruption seems to be fine.
[ 4277.385669] list_del corruption, ffffea00044b3e50->next is LIST_POISON1 (dead000000000100) [ 4277.387023] ------------[ cut here ]------------ [ 4277.387880] kernel BUG at lib/list_debug.c:56! [ 4277.388680] invalid opcode: 0000 [#1] PREEMPT SMP PTI [ 4277.389562] CPU: 5 PID: 90 Comm: kworker/5:1 Kdump: loaded Tainted: G OE 6.6.1-1 #1 [ 4277.392113] Workqueue: xfs-inodegc/vda1 xfs_inodegc_worker [xfs] [ 4277.393551] RIP: 0010:__list_del_entry_valid_or_report+0x7b/0xc0 [ 4277.394518] Code: 48 91 82 e8 37 f9 9a ff 0f 0b 48 89 fe 48 c7 c7 28 49 91 82 e8 26 f9 9a ff 0f 0b 48 89 fe 48 c7 c7 58 49 91 [ 4277.397292] RSP: 0018:ffffc90000333b38 EFLAGS: 00010082 [ 4277.398202] RAX: 000000000000004e RBX: ffffea00044b3e50 RCX: 0000000000000000 [ 4277.399340] RDX: 0000000000000002 RSI: ffffffff828f8715 RDI: 00000000ffffffff [ 4277.400545] RBP: ffffea00044b3e40 R08: 0000000000000000 R09: ffffc900003339f0 [ 4277.401710] R10: 0000000000000003 R11: ffffffff82d44088 R12: ffff888112cf9910 [ 4277.402887] R13: 0000000000000001 R14: 0000000000000001 R15: ffff8881000424c0 [ 4277.404049] FS: 0000000000000000(0000) GS:ffff88842fd40000(0000) knlGS:0000000000000000 [ 4277.405357] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 4277.406389] CR2: 00007f2ad0b24000 CR3: 0000000102a3a006 CR4: 00000000007706e0 [ 4277.407589] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 4277.408780] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 4277.410000] PKRU: 55555554 [ 4277.410645] Call Trace: [ 4277.411234] <TASK> [ 4277.411777] ? die+0x32/0x80 [ 4277.412439] ? do_trap+0xd6/0x100 [ 4277.413150] ? __list_del_entry_valid_or_report+0x7b/0xc0 [ 4277.414158] ? do_error_trap+0x6a/0x90 [ 4277.414948] ? __list_del_entry_valid_or_report+0x7b/0xc0 [ 4277.415915] ? exc_invalid_op+0x4c/0x60 [ 4277.416710] ? __list_del_entry_valid_or_report+0x7b/0xc0 [ 4277.417675] ? asm_exc_invalid_op+0x16/0x20 [ 4277.418482] ? __list_del_entry_valid_or_report+0x7b/0xc0 [ 4277.419466] ? __list_del_entry_valid_or_report+0x7b/0xc0 [ 4277.420410] free_to_partial_list+0x515/0x5e0 [ 4277.421242] ? xfs_iext_remove+0x41a/0xa10 [xfs] [ 4277.422298] xfs_iext_remove+0x41a/0xa10 [xfs] [ 4277.423316] ? xfs_inodegc_worker+0xb4/0x1a0 [xfs] [ 4277.424383] xfs_bmap_del_extent_delay+0x4fe/0x7d0 [xfs] [ 4277.425490] __xfs_bunmapi+0x50d/0x840 [xfs] [ 4277.426445] xfs_itruncate_extents_flags+0x13a/0x490 [xfs] [ 4277.427553] xfs_inactive_truncate+0xa3/0x120 [xfs] [ 4277.428567] xfs_inactive+0x22d/0x290 [xfs] [ 4277.429500] xfs_inodegc_worker+0xb4/0x1a0 [xfs] [ 4277.430479] process_one_work+0x171/0x340 [ 4277.431227] worker_thread+0x277/0x390 [ 4277.431962] ? __pfx_worker_thread+0x10/0x10 [ 4277.432752] kthread+0xf0/0x120 [ 4277.433382] ? __pfx_kthread+0x10/0x10 [ 4277.434134] ret_from_fork+0x2d/0x50 [ 4277.434837] ? __pfx_kthread+0x10/0x10 [ 4277.435566] ret_from_fork_asm+0x1b/0x30 [ 4277.436280] </TASK>
--- mm/slab.h | 5 +++++ mm/slub.c | 9 ++++++++- 2 files changed, 13 insertions(+), 1 deletion(-)
mm/slab.h +5 -0
@@ -40,6 +40,11 @@ struct slab {struct {unsigned inuse:16 ;unsigned objects:15 ; +/* +* If slab debugging is enabled then the +* frozen bit can be reused to indicate +* that the slab was corrupted +*/ unsigned frozen:1 ; }; };
mm/slub.c +8 -1
@@ -1196,6 +1196,11 @@ static int check_slab(struct kmem_cache *s, struct slab *slab) slab->inuse, slab->objects);return 0 ; } +if (slab->frozen) { +slab_err (s, slab,"Slab disabled since SLUB metadata consistency check failed" ); +return 0 ; + } +/* Slab_pad_check fixes things up after itself */ slab_pad_check (s, slab);return 1 ;
@@ -1392,6 +1397,7 @@ static noinline bool alloc_debug_processing(struct kmem_cache *s,slab_fix (s,"Marking all objects used" ); slab->inuse = slab->objects; slab->freelist =NULL ; + slab->frozen =1 ;/* mark consistency-failed slab as frozen */ }return false; }
@@ -2088,7 +2094,8 @@ static void *alloc_single_from_partial(struct kmem_cache *s, slab->inuse++;if (!alloc_debug_processing (s, slab, object, orig_size)) { -remove_partial (n, slab); +if (folio_test_slab (slab_folio (slab))) +remove_partial (n, slab);return NULL ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 708/1887 sched/deadline: Fix warning in migrate_enable for boosted tasks
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wander Lairson Costa <[email protected]>
[ Upstream commit 0664e2c311b9fa43b33e3e81429cd0c2d7f9c638 ]
When running the following command:
while true; do
stress-ng --cyclic 30 --timeout 30s --minimize --quiet
done
a warning is eventually triggered:
WARNING: CPU: 43 PID: 2848 at kernel/sched/deadline.c:794 setup_new_dl_entity+0x13e/0x180 ... Call Trace: <TASK> ? show_trace_log_lvl+0x1c4/0x2df ? enqueue_dl_entity+0x631/0x6e0 ? setup_new_dl_entity+0x13e/0x180 ? __warn+0x7e/0xd0 ? report_bug+0x11a/0x1a0 ? handle_bug+0x3c/0x70 ? exc_invalid_op+0x14/0x70 ? asm_exc_invalid_op+0x16/0x20 enqueue_dl_entity+0x631/0x6e0 enqueue_task_dl+0x7d/0x120 __do_set_cpus_allowed+0xe3/0x280 __set_cpus_allowed_ptr_locked+0x140/0x1d0 __set_cpus_allowed_ptr+0x54/0xa0 migrate_enable+0x7e/0x150 rt_spin_unlock+0x1c/0x90 group_send_sig_info+0xf7/0x1a0 ? kill_pid_info+0x1f/0x1d0 kill_pid_info+0x78/0x1d0 kill_proc_info+0x5b/0x110 __x64_sys_kill+0x93/0xc0 do_syscall_64+0x5c/0xf0 entry_SYSCALL_64_after_hwframe+0x6e/0x76 RIP: 0033:0x7f0dab31f92b
This warning occurs because set_cpus_allowed dequeues and enqueues tasks with the ENQUEUE_RESTORE flag set. If the task is boosted, the warning is triggered. A boosted task already had its parameters set by rt_mutex_setprio, and a new call to setup_new_dl_entity is unnecessary, hence the WARN_ON call.
Check if we are requeueing a boosted task and avoid calling setup_new_dl_entity if that's the case.
--- kernel/sched/deadline.c | 1 + 1 file changed, 1 insertion(+)
kernel/sched/deadline.c +1 -0
@@ -1656,6 +1656,7 @@ enqueue_dl_entity(struct sched_dl_entity *dl_se, int flags) }else if (flags &ENQUEUE_REPLENISH ) {replenish_dl_entity (dl_se); }else if ((flags &ENQUEUE_RESTORE ) && + !is_dl_boosted (dl_se) &&dl_time_before (dl_se->deadline,rq_clock (rq_of_dl_rq (dl_rq_of_se (dl_se))))) {setup_new_dl_entity (dl_se);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 709/1887 scsi: hisi_sas: Move slot variable definition in hisi_sas_abort_task()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xingui Yang <[email protected]>
[ Upstream commit 4b329abc91800d23941ac773e69b322a13981ecb ]
Each branch currently defines a slot variable independently, and it is neater to move it to the function head.
Stable-dep-of: 9f564f15f884 ("scsi: hisi_sas: Create all dump files during debugfs initialization")
--- drivers/scsi/hisi_sas/hisi_sas_main.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-)
drivers/scsi/hisi_sas/hisi_sas_main.c +3 -5
@@ -1574,6 +1574,7 @@ static int hisi_sas_abort_task(struct sas_task *task)struct hisi_sas_internal_abort_data internal_abort_data = { false };struct domain_device *device = task->dev;struct hisi_sas_device *sas_dev = device->lldd_dev; +struct hisi_sas_slot *slot = task->lldd_task;struct hisi_hba *hisi_hba;struct device *dev;int rc =TMF_RESP_FUNC_FAILED ;
@@ -1587,7 +1588,6 @@ static int hisi_sas_abort_task(struct sas_task *task)spin_lock_irqsave (&task->task_state_lock, flags);if (task->task_state_flags &SAS_TASK_STATE_DONE ) { -struct hisi_sas_slot *slot = task->lldd_task;struct hisi_sas_cq *cq;if (slot) {
@@ -1605,8 +1605,7 @@ static int hisi_sas_abort_task(struct sas_task *task) task->task_state_flags |=SAS_TASK_STATE_ABORTED ;spin_unlock_irqrestore (&task->task_state_lock, flags); -if (task->lldd_task && task->task_proto &SAS_PROTOCOL_SSP ) { -struct hisi_sas_slot *slot = task->lldd_task; +if (slot && task->task_proto &SAS_PROTOCOL_SSP ) {u16 tag = slot->idx;int rc2;
@@ -1640,9 +1639,8 @@ static int hisi_sas_abort_task(struct sas_task *task)hisi_sas_dereg_device (hisi_hba, device); rc =hisi_sas_softreset_ata_disk (device); } - }else if (task->lldd_task && task->task_proto &SAS_PROTOCOL_SMP ) { + }else if (slot && task->task_proto &SAS_PROTOCOL_SMP ) {/* SMP */ -struct hisi_sas_slot *slot = task->lldd_task;u32 tag = slot->idx;struct hisi_sas_cq *cq = &hisi_hba->cq[slot->dlvry_queue];
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 710/1887 scsi: hisi_sas: Add SATA_DISK_ERR bit handling for v3 hw
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xingui Yang <[email protected]>
[ Upstream commit 930d97dabdd56681aef752a35475f0212a171741 ]
When CQ header dw3 SATA_DISK_ERR is set it means this SATA disk is in error state and the current IPTT is invalid. An invalid IPTT does not correspond to any slot.
In this scenario, new I/Os that delivered to disk will be rejected by the controller and all I/Os remaining in the disk should be aborted, which we add here with the sas_ata_device_link_abort() call.
In hisi_sas_abort_task() we don't want to issue a soft reset as it may cause info to be lost in the target disk for the ATA EH autopsy. In this case, just release resources - the disk won't return other I/Os normally after NCQ Error, so this is safe.
Stable-dep-of: 9f564f15f884 ("scsi: hisi_sas: Create all dump files during debugfs initialization")
--- drivers/scsi/hisi_sas/hisi_sas.h | 1 + drivers/scsi/hisi_sas/hisi_sas_main.c | 18 +++++++++- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 48 ++++++++++++++++++++++++-- 3 files changed, 64 insertions(+), 3 deletions(-)
drivers/scsi/hisi_sas/hisi_sas.h +1 -0
@@ -104,6 +104,7 @@ enum {enum dev_status {HISI_SAS_DEV_INIT ,HISI_SAS_DEV_NORMAL , +HISI_SAS_DEV_NCQ_ERR , };enum {
drivers/scsi/hisi_sas/hisi_sas_main.c +17 -1
@@ -1631,13 +1631,26 @@ static int hisi_sas_abort_task(struct sas_task *task) }else if (task->task_proto &SAS_PROTOCOL_SATA || task->task_proto &SAS_PROTOCOL_STP ) {if (task->dev->dev_type ==SAS_SATA_DEV ) { +struct ata_queued_cmd *qc = task->uldd_task; + rc =hisi_sas_internal_task_abort_dev (sas_dev, false);if (rc <0 ) {dev_err (dev,"abort task: internal abort failed\n" ); goto out; }hisi_sas_dereg_device (hisi_hba, device); - rc =hisi_sas_softreset_ata_disk (device); + +/* +* If an ATA internal command times out in ATA EH, it +* need to execute soft reset, so check the scsicmd +*/ +if ((sas_dev->dev_status ==HISI_SAS_DEV_NCQ_ERR ) && + qc && qc->scsicmd) { +hisi_sas_do_release_task (hisi_hba, task, slot); + rc =TMF_RESP_FUNC_COMPLETE ; + }else { + rc =hisi_sas_softreset_ata_disk (device); + } } }else if (slot && task->task_proto &SAS_PROTOCOL_SMP ) {/* SMP */
@@ -1756,6 +1769,9 @@ static int hisi_sas_I_T_nexus_reset(struct domain_device *device)struct device *dev = hisi_hba->dev;int rc; +if (sas_dev->dev_status ==HISI_SAS_DEV_NCQ_ERR ) + sas_dev->dev_status =HISI_SAS_DEV_NORMAL ; + rc =hisi_sas_internal_task_abort_dev (sas_dev, false);if (rc <0 ) {dev_err (dev,"I_T nexus reset: internal abort (%d)\n" , rc);
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +46 -2
80 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 711/1887 scsi: hisi_sas: Add function complete_v3_hw()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Chen <[email protected]>
[ Upstream commit 538a60468966f47c53071d06db27bb78c2aaa81d ]
Put the work of processing cq slots in a separate function, complete_v3_hw(), which can then be used by cq_thread_v3_hw() and other functions when adding poll support.
[ Keep the cond_resched() call at the end of cq_thread_v3_hw() after the
split. Also pass need_lock to the hisi_sas_do_release_task() call added by the SATA_DISK_ERR dependency, which this tree's function requires. ]
Stable-dep-of: 9f564f15f884 ("scsi: hisi_sas: Create all dump files during debugfs initialization")
--- drivers/scsi/hisi_sas/hisi_sas_main.c | 2 +- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-)
drivers/scsi/hisi_sas/hisi_sas_main.c +1 -1
@@ -1646,7 +1646,7 @@ static int hisi_sas_abort_task(struct sas_task *task)*/ if ((sas_dev->dev_status ==HISI_SAS_DEV_NCQ_ERR ) && qc && qc->scsicmd) { -hisi_sas_do_release_task (hisi_hba, task, slot); +hisi_sas_do_release_task (hisi_hba, task, slot, true); rc =TMF_RESP_FUNC_COMPLETE ; }else { rc =hisi_sas_softreset_ata_disk (device);
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +12 -5
@@ -2407,15 +2407,14 @@ static void slot_complete_v3_hw(struct hisi_hba *hisi_hba, task->task_done (task); } -static irqreturn_t cq_thread_v3_hw (int irq_no,void *p) +static void complete_v3_hw (struct hisi_sas_cq *cq) { -struct hisi_sas_cq *cq = p; -struct hisi_hba *hisi_hba = cq->hisi_hba; -struct hisi_sas_slot *slot;struct hisi_sas_complete_v3_hdr *complete_queue; -u32 rd_point = cq->rd_point, wr_point; +struct hisi_hba *hisi_hba = cq->hisi_hba; +u32 rd_point, wr_point;int queue = cq->id; + rd_point = cq->rd_point; complete_queue = hisi_hba->complete_hdr[queue]; wr_point = hisi_sas_read32(hisi_hba, COMPL_Q_0_WR_PTR +
@@ -2424,6 +2423,7 @@ static irqreturn_t cq_thread_v3_hw(int irq_no, void *p)while (rd_point != wr_point) {struct hisi_sas_complete_v3_hdr *complete_hdr;struct device *dev = hisi_hba->dev; +struct hisi_sas_slot *slot;u32 dw0, dw1, dw3;int iptt;
@@ -2466,6 +2466,13 @@ static irqreturn_t cq_thread_v3_hw(int irq_no, void *p)/* update rd_point */ cq->rd_point = rd_point;hisi_sas_write32 (hisi_hba,COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point); +} + +static irqreturn_t cq_thread_v3_hw (int irq_no,void *p) +{ +struct hisi_sas_cq *cq = p; + +complete_v3_hw (cq);cond_resched ();return IRQ_HANDLED ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 712/1887 scsi: hisi_sas: Directly call register snapshot instead of using workqueue
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yihang Li <[email protected]>
[ Upstream commit 2ff07b5c6fe9173e7a7de3b23f300d71ad4d8fde ]
Currently, register information dump is performed via workqueue, regardless of the trigger mode (automatic or manual). There is a delay in dumping register through workqueue, the exact register information at trigger time cannot be obtained.
Call register snapshot directly instead of through a workqueue.
Stable-dep-of: 9f564f15f884 ("scsi: hisi_sas: Create all dump files during debugfs initialization")
--- drivers/scsi/hisi_sas/hisi_sas.h | 1 - drivers/scsi/hisi_sas/hisi_sas_main.c | 7 +++++-- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 14 +++----------- 3 files changed, 8 insertions(+), 14 deletions(-)
drivers/scsi/hisi_sas/hisi_sas.h +0 -1
@@ -450,7 +450,6 @@ struct hisi_hba {const struct hisi_sas_hw *hw;/* Low level hw interface */ unsigned long sata_dev_bitmap[BITS_TO_LONGS (HISI_SAS_MAX_DEVICES )];struct work_struct rst_work; -struct work_struct debugfs_work;u32 phy_state;u32 intr_coal_ticks;/* Time of interrupt coalesce in us */ u32 intr_coal_count;/* Interrupt count to coalesce */
drivers/scsi/hisi_sas/hisi_sas_main.c +5 -2
@@ -1907,8 +1907,11 @@ static bool hisi_sas_internal_abort_timeout(struct sas_task *task,struct hisi_hba *hisi_hba =dev_to_hisi_hba (device);struct hisi_sas_internal_abort_data *timeout = data; -if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct[0 ].itct) -queue_work (hisi_hba->wq, &hisi_hba->debugfs_work); +if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct[0 ].itct) { +down (&hisi_hba->sem); + hisi_hba->hw->debugfs_snapshot_regs (hisi_hba); +up (&hisi_hba->sem); + }if (task->task_state_flags &SAS_TASK_STATE_DONE ) { pr_err("Internal abort: timeout %016llx\n",
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +3 -11
@@ -554,7 +554,6 @@ static int prot_mask;module_param (prot_mask, int,0444 );MODULE_PARM_DESC (prot_mask," host protection capabilities mask, def=0x0 " ); -static void debugfs_work_handler_v3_hw (struct work_struct *work);static void debugfs_snapshot_regs_v3_hw (struct hisi_hba *hisi_hba);static u32 hisi_sas_read32 (struct hisi_hba *hisi_hba,u32 off)
@@ -3311,7 +3310,6 @@ hisi_sas_shost_alloc_pci(struct pci_dev *pdev) hisi_hba =shost_priv (shost);INIT_WORK (&hisi_hba->rst_work, hisi_sas_rst_work_handler); -INIT_WORK (&hisi_hba->debugfs_work, debugfs_work_handler_v3_hw); hisi_hba->hw = &hisi_sas_v3_hw; hisi_hba->pci_dev = pdev; hisi_hba->dev = dev;
@@ -3826,7 +3824,9 @@ static ssize_t debugfs_trigger_dump_v3_hw_write(struct file *file,if (buf[0 ] !='1' )return -EFAULT ; -queue_work (hisi_hba->wq, &hisi_hba->debugfs_work); +down (&hisi_hba->sem); +debugfs_snapshot_regs_v3_hw (hisi_hba); +up (&hisi_hba->sem);return count; }
@@ -4577,14 +4577,6 @@ static void debugfs_fifo_init_v3_hw(struct hisi_hba *hisi_hba) } } -static void debugfs_work_handler_v3_hw (struct work_struct *work) -{ -struct hisi_hba *hisi_hba = - container_of(work, struct hisi_hba, debugfs_work); - -debugfs_snapshot_regs_v3_hw (hisi_hba); -} -static void debugfs_release_v3_hw (struct hisi_hba *hisi_hba,int dump_index) {struct device *dev = hisi_hba->dev;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 713/1887 scsi: hisi_sas: Allocate DFX memory during dump trigger
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yihang Li <[email protected]>
[ Upstream commit 63f0733d07ce60252e885602b39571ade0441015 ]
Currently, if CONFIG_SCSI_HISI_SAS_DEBUGFS_DEFAULT_ENABLE is enabled, the memory space used by DFX is allocated during device initialization, which occupies a large number of memory resources. The memory usage before and after the driver is loaded is as follows:
Memory usage before the driver is loaded:
$ free -m
total used free shared buff/cache available
Mem: 867352 2578 864037 11 735 861681
Swap: 4095 0 4095Memory usage after the driver which include 4 HBAs is loaded:
$ insmod hisi_sas_v3_hw.ko
$ free -m
total used free shared buff/cache available
Mem: 867352 4760 861848 11 743 859495
Swap: 4095 0 4095The driver with 4 HBAs connected will allocate about 110 MB of memory without enabling debugfs.
Therefore, to avoid wasting memory resources, DFX memory is allocated during dump triggering. The dump may fail due to memory allocation failure. After this change, each dump costs about 10 MB of memory, and each dump lasts about 100 ms.
Stable-dep-of: 9f564f15f884 ("scsi: hisi_sas: Create all dump files during debugfs initialization")
--- drivers/scsi/hisi_sas/hisi_sas.h | 2 +- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 113 +++++++++++++------------ 2 files changed, 62 insertions(+), 53 deletions(-)
drivers/scsi/hisi_sas/hisi_sas.h +1 -1
@@ -342,7 +342,7 @@ struct hisi_sas_hw { u8 reg_index, u8 reg_count, u8 *write_data);void (*wait_cmds_complete_timeout)(struct hisi_hba *hisi_hba,int delay_ms,int timeout_ms); -void (*debugfs_snapshot_regs)(struct hisi_hba *hisi_hba); +int (*debugfs_snapshot_regs)(struct hisi_hba *hisi_hba);int complete_hdr_size;struct scsi_host_template *sht; };
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +61 -52
182 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 714/1887 scsi: hisi_sas: Create all dump files during debugfs initialization
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yihang Li <[email protected]>
[ Upstream commit 9f564f15f88490b484e02442dc4c4b11640ea172 ]
For the current debugfs of hisi_sas, after user triggers dump, the driver allocate memory space to save the register information and create debugfs files to display the saved information. In this process, the debugfs files created after each dump.
Therefore, when the dump is triggered while the driver is unbind, the following hang occurs:
[67840.853907] Unable to handle kernel NULL pointer dereference at virtual address 00000000000000a0 [67840.862947] Mem abort info: [67840.865855] ESR = 0x0000000096000004 [67840.869713] EC = 0x25: DABT (current EL), IL = 32 bits [67840.875125] SET = 0, FnV = 0 [67840.878291] EA = 0, S1PTW = 0 [67840.881545] FSC = 0x04: level 0 translation fault [67840.886528] Data abort info: [67840.889524] ISV = 0, ISS = 0x00000004, ISS2 = 0x00000000 [67840.895117] CM = 0, WnR = 0, TnD = 0, TagAccess = 0 [67840.900284] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 [67840.905709] user pgtable: 4k pages, 48-bit VAs, pgdp=0000002803a1f000 [67840.912263] [00000000000000a0] pgd=0000000000000000, p4d=0000000000000000 [67840.919177] Internal error: Oops: 0000000096000004 [#1] PREEMPT SMP [67840.996435] pstate: 80400009 (Nzcv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) [67841.003628] pc : down_write+0x30/0x98 [67841.007546] lr : start_creating.part.0+0x60/0x198 [67841.012495] sp : ffff8000b979ba20 [67841.016046] x29: ffff8000b979ba20 x28: 0000000000000010 x27: 0000000000024b40 [67841.023412] x26: 0000000000000012 x25: ffff20202b355ae8 x24: ffff20202b35a8c8 [67841.030779] x23: ffffa36877928208 x22: ffffa368b4972240 x21: ffff8000b979bb18 [67841.038147] x20: ffff00281dc1e3c0 x19: fffffffffffffffe x18: 0000000000000020 [67841.045515] x17: 0000000000000000 x16: ffffa368b128a530 x15: ffffffffffffffff [67841.052888] x14: ffff8000b979bc18 x13: ffffffffffffffff x12: ffff8000b979bb18 [67841.060263] x11: 0000000000000000 x10: 0000000000000000 x9 : ffffa368b1289b18 [67841.067640] x8 : 0000000000000012 x7 : 0000000000000000 x6 : 00000000000003a9 [67841.075014] x5 : 0000000000000000 x4 : ffff002818c5cb00 x3 : 0000000000000001 [67841.082388] x2 : 0000000000000000 x1 : ffff002818c5cb00 x0 : 00000000000000a0 [67841.089759] Call trace: [67841.092456] down_write+0x30/0x98 [67841.096017] start_creating.part.0+0x60/0x198 [67841.100613] debugfs_create_dir+0x48/0x1f8 [67841.104950] debugfs_create_files_v3_hw+0x88/0x348 [hisi_sas_v3_hw] [67841.111447] debugfs_snapshot_regs_v3_hw+0x708/0x798 [hisi_sas_v3_hw] [67841.118111] debugfs_trigger_dump_v3_hw_write+0x9c/0x120 [hisi_sas_v3_hw] [67841.125115] full_proxy_write+0x68/0xc8 [67841.129175] vfs_write+0xd8/0x3f0 [67841.132708] ksys_write+0x70/0x108 [67841.136317] __arm64_sys_write+0x24/0x38 [67841.140440] invoke_syscall+0x50/0x128 [67841.144385] el0_svc_common.constprop.0+0xc8/0xf0 [67841.149273] do_el0_svc+0x24/0x38 [67841.152773] el0_svc+0x38/0xd8 [67841.156009] el0t_64_sync_handler+0xc0/0xc8 [67841.160361] el0t_64_sync+0x1a4/0x1a8 [67841.164189] Code: b9000882 d2800002 d2800023 f9800011 (c85ffc05) [67841.170443] ---[ end trace 0000000000000000 ]---
To fix this issue, create all directories and files during debugfs initialization. In this way, the driver only needs to allocate memory space to save information each time the user triggers dumping.
--- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 79 ++++++++++++++++++++------ 1 file changed, 61 insertions(+), 18 deletions(-)
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +61 -18
@@ -3467,6 +3467,11 @@ debugfs_to_reg_name_v3_hw(int off, int base_off,return NULL ; } +static bool debugfs_dump_is_generated_v3_hw (void *p) +{ +return p ? true : false; +} +static void debugfs_print_reg_v3_hw (u32 *regs_val,struct seq_file *s,const struct hisi_sas_debugfs_reg *reg) {
@@ -3492,6 +3497,9 @@ static int debugfs_global_v3_hw_show(struct seq_file *s, void *p) {struct hisi_sas_debugfs_regs *global = s->private; +if (!debugfs_dump_is_generated_v3_hw (global->data)) +return -EPERM ; +debugfs_print_reg_v3_hw (global->data, s, &debugfs_global_reg);
@@ -3503,6 +3511,9 @@ static int debugfs_axi_v3_hw_show(struct seq_file *s, void *p) {struct hisi_sas_debugfs_regs *axi = s->private; +if (!debugfs_dump_is_generated_v3_hw (axi->data)) +return -EPERM ; +debugfs_print_reg_v3_hw (axi->data, s, &debugfs_axi_reg);
@@ -3514,6 +3525,9 @@ static int debugfs_ras_v3_hw_show(struct seq_file *s, void *p) {struct hisi_sas_debugfs_regs *ras = s->private; +if (!debugfs_dump_is_generated_v3_hw (ras->data)) +return -EPERM ; +debugfs_print_reg_v3_hw (ras->data, s, &debugfs_ras_reg);
@@ -3526,6 +3540,9 @@ static int debugfs_port_v3_hw_show(struct seq_file *s, void *p)struct hisi_sas_debugfs_port *port = s->private;const struct hisi_sas_debugfs_reg *reg_port = &debugfs_port_reg; +if (!debugfs_dump_is_generated_v3_hw (port->data)) +return -EPERM ; +debugfs_print_reg_v3_hw (port->data, s, reg_port);return 0 ;
@@ -3581,6 +3598,9 @@ static int debugfs_cq_v3_hw_show(struct seq_file *s, void *p)struct hisi_sas_debugfs_cq *debugfs_cq = s->private;int slot; +if (!debugfs_dump_is_generated_v3_hw (debugfs_cq->complete_hdr)) +return -EPERM ; +for (slot =0 ; slot <HISI_SAS_QUEUE_SLOTS ; slot++)debugfs_cq_show_slot_v3_hw (s, slot, debugfs_cq);
@@ -3602,8 +3622,12 @@ static void debugfs_dq_show_slot_v3_hw(struct seq_file *s, int slot,static int debugfs_dq_v3_hw_show (struct seq_file *s,void *p) { +struct hisi_sas_debugfs_dq *debugfs_dq = s->private;int slot; +if (!debugfs_dump_is_generated_v3_hw (debugfs_dq->hdr)) +return -EPERM ; +for (slot =0 ; slot <HISI_SAS_QUEUE_SLOTS ; slot++)debugfs_dq_show_slot_v3_hw (s, slot, s->private);
@@ -3617,6 +3641,9 @@ static int debugfs_iost_v3_hw_show(struct seq_file *s, void *p)struct hisi_sas_iost *iost = debugfs_iost->iost;int i, max_command_entries =HISI_SAS_MAX_COMMANDS ; +if (!debugfs_dump_is_generated_v3_hw (iost)) +return -EPERM ; +for (i =0 ; i < max_command_entries; i++, iost++) {__le64 *data = &iost->qw0;
@@ -3636,6 +3663,9 @@ static int debugfs_iost_cache_v3_hw_show(struct seq_file *s, void *p)int i, tab_idx;__le64 *iost; +if (!debugfs_dump_is_generated_v3_hw (iost_cache)) +return -EPERM ; +for (i =0 ; i <HISI_SAS_IOST_ITCT_CACHE_NUM ; i++, iost_cache++) {/* * Data struct of IOST cache:
@@ -3659,6 +3689,9 @@ static int debugfs_itct_v3_hw_show(struct seq_file *s, void *p)struct hisi_sas_debugfs_itct *debugfs_itct = s->private;struct hisi_sas_itct *itct = debugfs_itct->itct; +if (!debugfs_dump_is_generated_v3_hw (itct)) +return -EPERM ; +for (i =0 ; i <HISI_SAS_MAX_ITCT_ENTRIES ; i++, itct++) {__le64 *data = &itct->qw0;
@@ -3678,6 +3711,9 @@ static int debugfs_itct_cache_v3_hw_show(struct seq_file *s, void *p)int i, tab_idx;__le64 *itct; +if (!debugfs_dump_is_generated_v3_hw (itct_cache)) +return -EPERM ; +for (i =0 ; i <HISI_SAS_IOST_ITCT_CACHE_NUM ; i++, itct_cache++) {/* * Data struct of ITCT cache:
@@ -3695,10 +3731,9 @@ static int debugfs_itct_cache_v3_hw_show(struct seq_file *s, void *p) }DEFINE_SHOW_ATTRIBUTE (debugfs_itct_cache_v3_hw); -static void debugfs_create_files_v3_hw (struct hisi_hba *hisi_hba) +static void debugfs_create_files_v3_hw (struct hisi_hba *hisi_hba,int index) {u64 *debugfs_timestamp; -int dump_index = hisi_hba->debugfs_dump_index;struct dentry *dump_dentry;struct dentry *dentry;char name[256 ];
@@ -3706,17 +3741,17 @@ static void debugfs_create_files_v3_hw(struct hisi_hba *hisi_hba)int c;int d; -snprintf (name,256 ,"%d" , dump_index); +snprintf (name,256 ,"%d" , index); dump_dentry =debugfs_create_dir (name, hisi_hba->debugfs_dump_dentry); - debugfs_timestamp = &hisi_hba->debugfs_timestamp[dump_index]; + debugfs_timestamp = &hisi_hba->debugfs_timestamp[index];debugfs_create_u64 ("timestamp" ,0400 , dump_dentry, debugfs_timestamp);debugfs_create_file ("global" ,0400 , dump_dentry, - &hisi_hba->debugfs_regs[dump_index][DEBUGFS_GLOBAL ], + &hisi_hba->debugfs_regs[index][DEBUGFS_GLOBAL ], &debugfs_global_v3_hw_fops);/* Create port dir and files */
@@ -3725,7 +3760,7 @@ static void debugfs_create_files_v3_hw(struct hisi_hba *hisi_hba)snprintf (name,256 ,"%d" , p);debugfs_create_file (name,0400 , dentry, - &hisi_hba->debugfs_port_reg[dump_index][p], + &hisi_hba->debugfs_port_reg[index][p], &debugfs_port_v3_hw_fops); }
@@ -3735,7 +3770,7 @@ static void debugfs_create_files_v3_hw(struct hisi_hba *hisi_hba)snprintf (name,256 ,"%d" , c);debugfs_create_file (name,0400 , dentry, - &hisi_hba->debugfs_cq[dump_index][c], + &hisi_hba->debugfs_cq[index][c], &debugfs_cq_v3_hw_fops); }
@@ -3745,32 +3780,32 @@ static void debugfs_create_files_v3_hw(struct hisi_hba *hisi_hba)snprintf (name,256 ,"%d" , d);debugfs_create_file (name,0400 , dentry, - &hisi_hba->debugfs_dq[dump_index][d], + &hisi_hba->debugfs_dq[index][d], &debugfs_dq_v3_hw_fops); }debugfs_create_file ("iost" ,0400 , dump_dentry, - &hisi_hba->debugfs_iost[dump_index], + &hisi_hba->debugfs_iost[index], &debugfs_iost_v3_hw_fops);debugfs_create_file ("iost_cache" ,0400 , dump_dentry, - &hisi_hba->debugfs_iost_cache[dump_index], + &hisi_hba->debugfs_iost_cache[index], &debugfs_iost_cache_v3_hw_fops);debugfs_create_file ("itct" ,0400 , dump_dentry, - &hisi_hba->debugfs_itct[dump_index], + &hisi_hba->debugfs_itct[index], &debugfs_itct_v3_hw_fops);debugfs_create_file ("itct_cache" ,0400 , dump_dentry, - &hisi_hba->debugfs_itct_cache[dump_index], + &hisi_hba->debugfs_itct_cache[index], &debugfs_itct_cache_v3_hw_fops);debugfs_create_file ("axi" ,0400 , dump_dentry, - &hisi_hba->debugfs_regs[dump_index][DEBUGFS_AXI ], + &hisi_hba->debugfs_regs[index][DEBUGFS_AXI ], &debugfs_axi_v3_hw_fops);debugfs_create_file ("ras" ,0400 , dump_dentry, - &hisi_hba->debugfs_regs[dump_index][DEBUGFS_RAS ], + &hisi_hba->debugfs_regs[index][DEBUGFS_RAS ], &debugfs_ras_v3_hw_fops); }
@@ -4706,8 +4741,6 @@ static int debugfs_snapshot_regs_v3_hw(struct hisi_hba *hisi_hba)debugfs_snapshot_itct_reg_v3_hw (hisi_hba);debugfs_snapshot_iost_reg_v3_hw (hisi_hba); -debugfs_create_files_v3_hw (hisi_hba); -debugfs_snapshot_restore_v3_hw (hisi_hba); hisi_hba->debugfs_dump_index++;
@@ -4791,6 +4824,17 @@ static void debugfs_bist_init_v3_hw(struct hisi_hba *hisi_hba) hisi_hba->debugfs_bist_linkrate =SAS_LINK_RATE_1_5_GBPS ; } +static void debugfs_dump_init_v3_hw (struct hisi_hba *hisi_hba) +{ +int i; + + hisi_hba->debugfs_dump_dentry = +debugfs_create_dir ("dump" , hisi_hba->debugfs_dir); + +for (i =0 ; i < hisi_sas_debugfs_dump_count; i++) +debugfs_create_files_v3_hw (hisi_hba, i); +} +static void debugfs_exit_v3_hw (struct hisi_hba *hisi_hba) {debugfs_remove_recursive (hisi_hba->debugfs_dir);
@@ -4811,8 +4855,7 @@ static void debugfs_init_v3_hw(struct hisi_hba *hisi_hba)/* create bist structures */ debugfs_bist_init_v3_hw (hisi_hba); - hisi_hba->debugfs_dump_dentry = -debugfs_create_dir ("dump" , hisi_hba->debugfs_dir); +debugfs_dump_init_v3_hw (hisi_hba);debugfs_phy_down_cnt_init_v3_hw (hisi_hba);debugfs_fifo_init_v3_hw (hisi_hba);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 715/1887 bpf: Call free_htab_elem() after htab_unlock_bucket()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hou Tao <[email protected]>
[ Upstream commit b9e9ed90b10c82a4e9d4d70a2890f06bfcdd3b78 ]
For htab of maps, when the map is removed from the htab, it may hold the last reference of the map. bpf_map_fd_put_ptr() will invoke bpf_map_free_id() to free the id of the removed map element. However, bpf_map_fd_put_ptr() is invoked while holding a bucket lock (raw_spin_lock_t), and bpf_map_free_id() attempts to acquire map_idr_lock (spinlock_t), triggering the following lockdep warning:
=============================
[ BUG: Invalid wait context ]
6.11.0-rc4+ #49 Not tainted
-----------------------------
test_maps/4881 is trying to lock:
ffffffff84884578 (map_idr_lock){+...}-{3:3}, at: bpf_map_free_id.part.0+0x21/0x70 other info that might help us debug this:
context-{5:5}
2 locks held by test_maps/4881:
#0: ffffffff846caf60 (rcu_read_lock){....}-{1:3}, at: bpf_fd_htab_map_update_elem+0xf9/0x270 #1: ffff888149ced148 (&htab->lockdep_key#2){....}-{2:2}, at: htab_map_update_elem+0x178/0xa80
stack backtrace: CPU: 0 UID: 0 PID: 4881 Comm: test_maps Not tainted 6.11.0-rc4+ #49 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), ... Call Trace: <TASK> dump_stack_lvl+0x6e/0xb0 dump_stack+0x10/0x20 __lock_acquire+0x73e/0x36c0 lock_acquire+0x182/0x450 _raw_spin_lock_irqsave+0x43/0x70 bpf_map_free_id.part.0+0x21/0x70 bpf_map_put+0xcf/0x110 bpf_map_fd_put_ptr+0x9a/0xb0 free_htab_elem+0x69/0xe0 htab_map_update_elem+0x50f/0xa80 bpf_fd_htab_map_update_elem+0x131/0x270 htab_map_update_elem+0x50f/0xa80 bpf_fd_htab_map_update_elem+0x131/0x270 bpf_map_update_value+0x266/0x380 __sys_bpf+0x21bb/0x36b0 __x64_sys_bpf+0x45/0x60 x64_sys_call+0x1b2a/0x20d0 do_syscall_64+0x5d/0x100 entry_SYSCALL_64_after_hwframe+0x76/0x7e
One way to fix the lockdep warning is using raw_spinlock_t for map_idr_lock as well. However, bpf_map_alloc_id() invokes idr_alloc_cyclic() after acquiring map_idr_lock, it will trigger a similar lockdep warning because the slab's lock (s->cpu_slab->lock) is still a spinlock.
Instead of changing map_idr_lock's type, fix the issue by invoking htab_put_fd_value() after htab_unlock_bucket(). However, only deferring the invocation of htab_put_fd_value() is not enough, because the old map pointers in htab of maps can not be saved during batched deletion. Therefore, also defer the invocation of free_htab_elem(), so these to-be-freed elements could be linked together similar to lru map.
There are four callers for ->map_fd_put_ptr:
(1) alloc_htab_elem() (through htab_put_fd_value())
It invokes ->map_fd_put_ptr() under a raw_spinlock_t. The invocation of htab_put_fd_value() can not simply move after htab_unlock_bucket(), because the old element has already been stashed in htab->extra_elems. It may be reused immediately after htab_unlock_bucket() and the invocation of htab_put_fd_value() after htab_unlock_bucket() may release the newly-added element incorrectly. Therefore, saving the map pointer of the old element for htab of maps before unlocking the bucket and releasing the map_ptr after unlock. Beside the map pointer in the old element, should do the same thing for the special fields in the old element as well.
(2) free_htab_elem() (through htab_put_fd_value())
Its caller includes __htab_map_lookup_and_delete_elem(), htab_map_delete_elem() and __htab_map_lookup_and_delete_batch().
For htab_map_delete_elem(), simply invoke free_htab_elem() after htab_unlock_bucket(). For __htab_map_lookup_and_delete_batch(), just like lru map, linking the to-be-freed element into node_to_free list and invoking free_htab_elem() for these element after unlock. It is safe to reuse batch_flink as the link for node_to_free, because these elements have been removed from the hash llist.
Because htab of maps doesn't support lookup_and_delete operation, __htab_map_lookup_and_delete_elem() doesn't have the problem, so kept it as is.
(3) fd_htab_map_free()
It invokes ->map_fd_put_ptr without raw_spinlock_t.
(4) bpf_fd_htab_map_update_elem()
It invokes ->map_fd_put_ptr without raw_spinlock_t.
After moving free_htab_elem() outside htab bucket lock scope, using pcpu_freelist_push() instead of __pcpu_freelist_push() to disable the irq before freeing elements, and protecting the invocations of bpf_mem_cache_free() with migrate_{disable|enable} pair.
--- kernel/bpf/hashtab.c | 55 ++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 17 deletions(-)
kernel/bpf/hashtab.c +38 -17
@@ -873,10 +873,12 @@ static int htab_map_get_next_key(struct bpf_map *map, void *key, void *next_key)static void htab_elem_free (struct bpf_htab *htab,struct htab_elem *l) { +migrate_disable ();if (htab->map.map_type ==BPF_MAP_TYPE_PERCPU_HASH )bpf_mem_cache_free (&htab->pcpu_ma, l->ptr_to_pptr);check_and_free_fields (htab, l);bpf_mem_cache_free (&htab->ma, l); +migrate_enable (); }static void htab_put_fd_value (struct bpf_htab *htab,struct htab_elem *l)
@@ -921,7 +923,7 @@ static void free_htab_elem(struct bpf_htab *htab, struct htab_elem *l)if (htab_is_prealloc (htab)) {check_and_free_fields (htab, l); -__pcpu_freelist_push (&htab->freelist, &l->fnode); +pcpu_freelist_push (&htab->freelist, &l->fnode); }else {dec_elem_count (htab);htab_elem_free (htab, l);
@@ -994,7 +996,6 @@ static struct htab_elem *alloc_htab_elem(struct bpf_htab *htab, void *key,*/ pl_new =this_cpu_ptr (htab->extra_elems); l_new = *pl_new; -htab_put_fd_value (htab, old_elem); *pl_new = old_elem; }else {struct pcpu_freelist_node *l;
@@ -1079,6 +1080,7 @@ static int htab_map_update_elem(struct bpf_map *map, void *key, void *value,struct htab_elem *l_new =NULL , *l_old;struct hlist_nulls_head *head;unsigned long flags; +void *old_map_ptr;struct bucket *b;u32 key_size, hash;int ret;
@@ -1156,12 +1158,27 @@ static int htab_map_update_elem(struct bpf_map *map, void *key, void *value,hlist_nulls_add_head_rcu (&l_new->hash_node, head);if (l_old) {hlist_nulls_del_rcu (&l_old->hash_node); + +/* l_old has already been stashed in htab->extra_elems, free +* its special fields before it is available for reuse. Also +* save the old map pointer in htab of maps before unlock +* and release it after unlock. +*/ + old_map_ptr =NULL ; +if (htab_is_prealloc (htab)) { +if (map->ops->map_fd_put_ptr) + old_map_ptr =fd_htab_map_get_ptr (map, l_old); +check_and_free_fields (htab, l_old); + } + } +htab_unlock_bucket (htab, b, hash, flags); +if (l_old) { +if (old_map_ptr) + map->ops->map_fd_put_ptr (map, old_map_ptr, true);if (!htab_is_prealloc (htab))free_htab_elem (htab, l_old); -else -check_and_free_fields (htab, l_old); } - ret =0 ; +return 0 ; err:htab_unlock_bucket (htab, b, hash, flags);return ret;
@@ -1398,15 +1415,15 @@ static int htab_map_delete_elem(struct bpf_map *map, void *key)return ret; l =lookup_elem_raw (head, hash, key, key_size); - -if (l) { +if (l)hlist_nulls_del_rcu (&l->hash_node); -free_htab_elem (htab, l); - }else { +else ret = -ENOENT ; - }htab_unlock_bucket (htab, b, hash, flags); + +if (l) +free_htab_elem (htab, l);return ret; }
@@ -1824,13 +1841,14 @@ __htab_map_lookup_and_delete_batch(struct bpf_map *map,* may cause deadlock. See comments in function * prealloc_lru_pop(). Let us do bpf_lru_push_free() * after releasing the bucket lock. +* +* For htab of maps, htab_put_fd_value() in +* free_htab_elem() may acquire a spinlock with bucket +* lock being held and it violates the lock rule, so +* invoke free_htab_elem() after unlock as well. */ -if (is_lru_map) { - l->batch_flink = node_to_free; - node_to_free = l; - }else { -free_htab_elem (htab, l); - } + l->batch_flink = node_to_free; + node_to_free = l; } dst_key += key_size; dst_val += value_size;
@@ -1842,7 +1860,10 @@ __htab_map_lookup_and_delete_batch(struct bpf_map *map,while (node_to_free) { l = node_to_free; node_to_free = node_to_free->batch_flink; -htab_lru_push_free (htab, l); +if (is_lru_map) +htab_lru_push_free (htab, l); +else +free_htab_elem (htab, l); } next_batch:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 716/1887 mm/mempolicy: fix migrate_to_node() assuming there is at least one VMA in a MM
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Hildenbrand <[email protected]>
[ Upstream commit 091c1dd2d4df6edd1beebe0e5863d4034ade9572 ]
We currently assume that there is at least one VMA in a MM, which isn't true.
So we might end up having find_vma() return NULL, to then de-reference NULL. So properly handle find_vma() returning NULL.
This fixes the report:
Oops: general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN PTI KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] CPU: 1 UID: 0 PID: 6021 Comm: syz-executor284 Not tainted 6.12.0-rc7-syzkaller-00187-gf868cd251776 #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/30/2024 RIP: 0010:migrate_to_node mm/mempolicy.c:1090 [inline] RIP: 0010:do_migrate_pages+0x403/0x6f0 mm/mempolicy.c:1194 Code: ... RSP: 0018:ffffc9000375fd08 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffffc9000375fd78 RCX: 0000000000000000 RDX: ffff88807e171300 RSI: dffffc0000000000 RDI: ffff88803390c044 RBP: ffff88807e171428 R08: 0000000000000014 R09: fffffbfff2039ef1 R10: ffffffff901cf78f R11: 0000000000000000 R12: 0000000000000003 R13: ffffc9000375fe90 R14: ffffc9000375fe98 R15: ffffc9000375fdf8 FS: 00005555919e1380(0000) GS:ffff8880b8700000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00005555919e1ca8 CR3: 000000007f12a000 CR4: 00000000003526f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: <TASK> kernel_migrate_pages+0x5b2/0x750 mm/mempolicy.c:1709 __do_sys_migrate_pages mm/mempolicy.c:1727 [inline] __se_sys_migrate_pages mm/mempolicy.c:1723 [inline] __x64_sys_migrate_pages+0x96/0x100 mm/mempolicy.c:1723 do_syscall_x64 arch/x86/entry/common.c:52 [inline] do_syscall_64+0xcd/0x250 arch/x86/entry/common.c:83 entry_SYSCALL_64_after_hwframe+0x77/0x7f
--- mm/mempolicy.c | 2 ++ 1 file changed, 2 insertions(+)
mm/mempolicy.c +2 -0
@@ -1068,6 +1068,8 @@ static int migrate_to_node(struct mm_struct *mm, int source, int dest,* space range and MPOL_MF_DISCONTIG_OK, this call can not fail. */ vma =find_vma (mm,0 ); +if (unlikely (!vma)) +return 0 ;VM_BUG_ON (!(flags & (MPOL_MF_MOVE |MPOL_MF_MOVE_ALL )));queue_pages_range (mm, vma->vm_start, mm->task_size, &nmask, flags |MPOL_MF_DISCONTIG_OK , &pagelist);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 717/1887 net/smc: initialize close_work early to avoid warning
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wen Gu <[email protected]>
[ Upstream commit 0541db8ee32c09463a72d0987382b3a3336b0043 ]
We encountered a warning that close_work was canceled before initialization.
WARNING: CPU: 7 PID: 111103 at kernel/workqueue.c:3047 __flush_work+0x19e/0x1b0 Workqueue: events smc_lgr_terminate_work [smc] RIP: 0010:__flush_work+0x19e/0x1b0 Call Trace: ? __wake_up_common+0x7a/0x190 ? work_busy+0x80/0x80 __cancel_work_timer+0xe3/0x160 smc_close_cancel_work+0x1a/0x70 [smc] smc_close_active_abort+0x207/0x360 [smc] __smc_lgr_terminate.part.38+0xc8/0x180 [smc] process_one_work+0x19e/0x340 worker_thread+0x30/0x370 ? process_one_work+0x340/0x340 kthread+0x117/0x130 ? __kthread_cancel_work+0x50/0x50 ret_from_fork+0x22/0x30
This is because when smc_close_cancel_work is triggered, e.g. the RDMA driver is rmmod and the LGR is terminated, the conn->close_work is flushed before initialization, resulting in WARN_ON(!work->func).
__smc_lgr_terminate | smc_connect_{rdma|ism}
-------------------------------------------------------------
| smc_conn_create | \- smc_lgr_register_conn
for conn in lgr->conns_all |
\- smc_conn_kill |
\- smc_close_active_abort |
\- smc_close_cancel_work |
\- cancel_work_sync |
\- __flush_work |
(close_work) |
| smc_close_init
| \- INIT_WORK(&close_work)So fix this by initializing close_work before establishing the connection.
--- net/smc/af_smc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
net/smc/af_smc.c +1 -3
@@ -406,6 +406,7 @@ static struct sock *smc_sock_alloc(struct net *net, struct socket *sock,sk_refcnt_debug_inc (sk);mutex_init (&smc->clcsock_release_lock);smc_init_saved_callbacks (smc); +smc_close_init (smc);return sk; }
@@ -1277,7 +1278,6 @@ static int smc_connect_rdma(struct smc_sock *smc, goto connect_abort; } -smc_close_init (smc);smc_rx_init (smc);if (ini->first_contact_local) {
@@ -1397,7 +1397,6 @@ static int smc_connect_ism(struct smc_sock *smc, }smc_conn_save_peer_info (smc, aclc); -smc_close_init (smc);smc_rx_init (smc);smc_tx_init (smc);
@@ -2430,7 +2429,6 @@ static void smc_listen_work(struct work_struct *work) goto out_decl;mutex_lock (&smc_server_lgr_pending); -smc_close_init (new_smc);smc_rx_init (new_smc);smc_tx_init (new_smc);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 718/1887 f2fs: fix to do sanity check on node blkaddr in truncate_node()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chao Yu <[email protected]>
[ Upstream commit 6babe00ccd34fc65b78ef8b99754e32b4385f23d ]
syzbot reports a f2fs bug as below:
------------[ cut here ]------------ kernel BUG at fs/f2fs/segment.c:2534! RIP: 0010:f2fs_invalidate_blocks+0x35f/0x370 fs/f2fs/segment.c:2534 Call Trace: truncate_node+0x1ae/0x8c0 fs/f2fs/node.c:909 f2fs_remove_inode_page+0x5c2/0x870 fs/f2fs/node.c:1288 f2fs_evict_inode+0x879/0x15c0 fs/f2fs/inode.c:856 evict+0x4e8/0x9b0 fs/inode.c:723 f2fs_handle_failed_inode+0x271/0x2e0 fs/f2fs/inode.c:986 f2fs_create+0x357/0x530 fs/f2fs/namei.c:394 lookup_open fs/namei.c:3595 [inline] open_last_lookups fs/namei.c:3694 [inline] path_openat+0x1c03/0x3590 fs/namei.c:3930 do_filp_open+0x235/0x490 fs/namei.c:3960 do_sys_openat2+0x13e/0x1d0 fs/open.c:1415 do_sys_open fs/open.c:1430 [inline] __do_sys_openat fs/open.c:1446 [inline] __se_sys_openat fs/open.c:1441 [inline] __x64_sys_openat+0x247/0x2a0 fs/open.c:1441 do_syscall_x64 arch/x86/entry/common.c:52 [inline] do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0010:f2fs_invalidate_blocks+0x35f/0x370 fs/f2fs/segment.c:2534
The root cause is: on a fuzzed image, blkaddr in nat entry may be corrupted, then it will cause system panic when using it in f2fs_invalidate_blocks(), to avoid this, let's add sanity check on nat blkaddr in truncate_node().
--- fs/f2fs/node.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
fs/f2fs/node.c +10 -0
@@ -918,6 +918,16 @@ static int truncate_node(struct dnode_of_data *dn)if (err)return err; +if (ni.blk_addr !=NEW_ADDR && + !f2fs_is_valid_blkaddr (sbi, ni.blk_addr,DATA_GENERIC_ENHANCE )) { +f2fs_err (sbi, +"nat entry is corrupted, run fsck to fix it, ino:%u, " +"nid:%u, blkaddr:%u" , ni.ino, ni.nid, ni.blk_addr); +set_sbi_flag (sbi,SBI_NEED_FSCK ); +f2fs_handle_error (sbi,ERROR_INCONSISTENT_NAT ); +return -EFSCORRUPTED ; + } +/* Deallocate node address */ f2fs_invalidate_blocks (sbi, ni.blk_addr);dec_valid_node_count (sbi, dn->inode, dn->nid == dn->inode->i_ino);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 719/1887 udmabuf: fix memory leak on last export_udmabuf() error path
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jann Horn <[email protected]>
[ Upstream commit f49856f525acd5bef52ae28b7da2e001bbe7439e ]
In export_udmabuf(), if dma_buf_fd() fails because the FD table is full, a dma_buf owning the udmabuf has already been created; but the error handling in udmabuf_create() will tear down the udmabuf without doing anything about the containing dma_buf.
This leaves a dma_buf in memory that contains a dangling pointer; though that doesn't seem to lead to anything bad except a memory leak.
Fix it by moving the dma_buf_fd() call out of export_udmabuf() so that we can give it different error handling.
Note that the shape of this code changed a lot in commit 5e72b2b41a21 ("udmabuf: convert udmabuf driver to use folios"); but the memory leak seems to have existed since the introduction of udmabuf.
--- drivers/dma-buf/udmabuf.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
drivers/dma-buf/udmabuf.c +10 -1
@@ -289,7 +289,16 @@ static long udmabuf_create(struct miscdevice *device, flags =0 ;if (head->flags &UDMABUF_FLAGS_CLOEXEC ) flags |=O_CLOEXEC ; -return dma_buf_fd (buf, flags); + +/* +* Ownership of ubuf is held by the dmabuf from here. +* If the following dma_buf_fd() fails, dma_buf_put() cleans up both the +* dmabuf and the ubuf (through udmabuf_ops.release). +*/ + ret =dma_buf_fd (buf, flags); +if (ret <0 ) +dma_buf_put (buf); +return ret; err:while (pgbuf >0 )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 720/1887 smb: Initialize cfid->tcon before performing network ops
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paul Aurich <[email protected]>
[ Upstream commit c353ee4fb119a2582d0e011f66a76a38f5cf984d ]
Avoid leaking a tcon ref when a lease break races with opening the cached directory. Processing the leak break might take a reference to the tcon in cached_dir_lease_break() and then fail to release the ref in cached_dir_offload_close, since cfid->tcon is still NULL.
--- fs/smb/client/cached_dir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/smb/client/cached_dir.c +1 -1
@@ -211,6 +211,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, } } cfid->dentry = dentry; + cfid->tcon = tcon;/* * We do not hold the lock for the open because in case
@@ -284,7 +285,6 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, } goto oshr_free; } - cfid->tcon = tcon; cfid->is_open = true;spin_lock (&cfids->cfid_list_lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 721/1887 vfio/mlx5: Fix an unwind issue in mlx5vf_add_migration_pages()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yishai Hadas <[email protected]>
[ Upstream commit 22e87bf3f77c18f5982c19ffe2732ef0c7a25f16 ]
Fix an unwind issue in mlx5vf_add_migration_pages().
If a set of pages is allocated but fails to be added to the SG table, they need to be freed to prevent a memory leak.
Any pages successfully added to the SG table will be freed as part of mlx5vf_free_data_buffer().
--- drivers/vfio/pci/mlx5/main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/vfio/pci/mlx5/main.c +5 -1
@@ -71,6 +71,7 @@ static int mlx5vf_add_migration_pages(struct mlx5_vf_migration_file *migf,unsigned long filled;unsigned int to_fill;int ret; +int i; to_fill = min_t(unsigned int, npages, PAGE_SIZE / sizeof(*page_list)); page_list =kvzalloc (to_fill *sizeof (*page_list),GFP_KERNEL );
@@ -90,7 +91,7 @@ static int mlx5vf_add_migration_pages(struct mlx5_vf_migration_file *migf, GFP_KERNEL);if (ret) - goto err; + goto err_append; migf->allocated_length += filled *PAGE_SIZE ;/* clean input for another bulk allocation */ memset (page_list,0 , filled *sizeof (*page_list));
@@ -101,6 +102,9 @@ static int mlx5vf_add_migration_pages(struct mlx5_vf_migration_file *migf,kvfree (page_list);return 0 ; +err_append: +for (i = filled -1 ; i >=0 ; i--) +__free_page (page_list[i]); err:kvfree (page_list);return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 722/1887 scsi: mpi3mr: Fix corrupt config pages PHY state is switched in sysfs
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ranjan Kumar <[email protected]>
[ Upstream commit 711201a8b8334a397440ac0b859df0054e174bc9 ]
The driver, through the SAS transport, exposes a sysfs interface to enable/disable PHYs in a controller/expander setup. When multiple PHYs are disabled and enabled in rapid succession, the persistent and current config pages related to SAS IO unit/SAS Expander pages could get corrupted.
Use separate memory for each config request.
--- drivers/scsi/mpi3mr/mpi3mr.h | 9 ---- drivers/scsi/mpi3mr/mpi3mr_fw.c | 81 ++++++--------------------------- 2 files changed, 13 insertions(+), 77 deletions(-)
drivers/scsi/mpi3mr/mpi3mr.h +0 -9
@@ -130,8 +130,6 @@ extern atomic64_t event_counter;#define MPI3MR_WATCHDOG_INTERVAL 1000/* in milli seconds */ -#define MPI3MR_DEFAULT_CFG_PAGE_SZ 1024/* in bytes */ -#define MPI3MR_RESET_TOPOLOGY_SETTLE_TIME 10#define MPI3MR_SCMD_TIMEOUT (60 * HZ)
@@ -1013,9 +1011,6 @@ struct scmd_priv {* @io_throttle_low: I/O size to stop throttle in 512b blocks * @num_io_throttle_group: Maximum number of throttle groups * @throttle_groups: Pointer to throttle group info structures -* @cfg_page: Default memory for configuration pages -* @cfg_page_dma: Configuration page DMA address -* @cfg_page_sz: Default configuration page memory size * @sas_transport_enabled: SAS transport enabled or not * @scsi_device_channel: Channel ID for SCSI devices * @transport_cmds: Command tracker for SAS transport commands
@@ -1198,10 +1193,6 @@ struct mpi3mr_ioc {u16 num_io_throttle_group;struct mpi3mr_throttle_group_info *throttle_groups; -void *cfg_page; -dma_addr_t cfg_page_dma; -u16 cfg_page_sz; -u8 sas_transport_enabled;u8 scsi_device_channel;struct mpi3mr_drv_cmd transport_cmds;
drivers/scsi/mpi3mr/mpi3mr_fw.c +13 -68
111 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 723/1887 workqueue: Do not warn when cancelling WQ_MEM_RECLAIM work from !WQ_MEM_RECLAIM worker
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tvrtko Ursulin <[email protected]>
[ Upstream commit de35994ecd2dd6148ab5a6c5050a1670a04dec77 ]
After commit746ae46c1113 ("drm/sched: Mark scheduler work queues with WQ_MEM_RECLAIM") amdgpu started seeing the following warning:
[ ] workqueue: WQ_MEM_RECLAIM sdma0:drm_sched_run_job_work [gpu_sched] is flushing !WQ_MEM_RECLAIM events:amdgpu_device_delay_enable_gfx_off [amdgpu]
...
[ ] Workqueue: sdma0 drm_sched_run_job_work [gpu_sched]
...
[ ] Call Trace:
[ ] <TASK>
...
[ ] ? check_flush_dependency+0xf5/0x110
...
[ ] cancel_delayed_work_sync+0x6e/0x80 [ ] amdgpu_gfx_off_ctrl+0xab/0x140 [amdgpu] [ ] amdgpu_ring_alloc+0x40/0x50 [amdgpu] [ ] amdgpu_ib_schedule+0xf4/0x810 [amdgpu] [ ] ? drm_sched_run_job_work+0x22c/0x430 [gpu_sched] [ ] amdgpu_job_run+0xaa/0x1f0 [amdgpu] [ ] drm_sched_run_job_work+0x257/0x430 [gpu_sched] [ ] process_one_work+0x217/0x720
...
[ ] </TASK>
The intent of the verifcation done in check_flush_depedency is to ensure forward progress during memory reclaim, by flagging cases when either a memory reclaim process, or a memory reclaim work item is flushed from a context not marked as memory reclaim safe.
This is correct when flushing, but when called from the cancel(_delayed)_work_sync() paths it is a false positive because work is either already running, or will not be running at all. Therefore cancelling it is safe and we can relax the warning criteria by letting the helper know of the calling context.
References: 746ae46c1113 ("drm/sched: Mark scheduler work queues with WQ_MEM_RECLAIM")
--- kernel/workqueue.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-)
kernel/workqueue.c +13 -9
@@ -2607,23 +2607,27 @@ static int rescuer_thread(void *__rescuer)* check_flush_dependency - check for flush dependency sanity * @target_wq: workqueue being flushed * @target_work: work item being flushed (NULL for workqueue flushes) +* @from_cancel: are we called from the work cancel path * * %current is trying to flush the whole @target_wq or @target_work on it. -* If @target_wq doesn't have %WQ_MEM_RECLAIM, verify that %current is not -* reclaiming memory or running on a workqueue which doesn't have -* %WQ_MEM_RECLAIM as that can break forward-progress guarantee leading to -* a deadlock. +* If this is not the cancel path (which implies work being flushed is either +* already running, or will not be at all), check if @target_wq doesn't have +* %WQ_MEM_RECLAIM and verify that %current is not reclaiming memory or running +* on a workqueue which doesn't have %WQ_MEM_RECLAIM as that can break forward- +* progress guarantee leading to a deadlock. */ static void check_flush_dependency (struct workqueue_struct *target_wq, -struct work_struct *target_work) +struct work_struct *target_work, +bool from_cancel) { -work_func_t target_func = target_work ? target_work->func :NULL ; +work_func_t target_func;struct worker *worker; -if (target_wq->flags &WQ_MEM_RECLAIM ) +if (from_cancel || target_wq->flags &WQ_MEM_RECLAIM )return ; worker =current_wq_worker (); + target_func = target_work ? target_work->func :NULL ; WARN_ONCE(current->flags & PF_MEMALLOC, "workqueue: PF_MEMALLOC task %d(%s) is flushing !WQ_MEM_RECLAIM %s:%ps",
@@ -2857,7 +2861,7 @@ void __flush_workqueue(struct workqueue_struct *wq)list_add_tail (&this_flusher.list, &wq->flusher_overflow); } -check_flush_dependency (wq,NULL ); +check_flush_dependency (wq,NULL , false);mutex_unlock (&wq->mutex);
@@ -3032,7 +3036,7 @@ static bool start_flush_work(struct work_struct *work, struct wq_barrier *barr, pwq = worker->current_pwq; } -check_flush_dependency (pwq->wq, work); +check_flush_dependency (pwq->wq, work, from_cancel);insert_wq_barrier (pwq, barr, work, worker);raw_spin_unlock_irq (&pool->lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 724/1887 udp: Deal with race between UDP socket address change and rehash
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stefano Brivio <[email protected]>
[ Upstream commit a502ea6fa94b1f7be72a24bcf9e3f5f6b7e6e90c ]
If a UDP socket changes its local address while it's receiving datagrams, as a result of connect(), there is a period during which a lookup operation might fail to find it, after the address is changed but before the secondary hash (port and address) and the four-tuple hash (local and remote ports and addresses) are updated.
Secondary hash chains were introduced by commit 30fff9231fad ("udp:bind() optimisation") and, as a result, a rehash operation became needed to make a bound socket reachable again after a connect().
This operation was introduced by commit 719f835853a9 ("udp: add rehash on connect()") which isn't however a complete fix: the socket will be found once the rehashing completes, but not while it's pending.
This is noticeable with a socat(1) server in UDP4-LISTEN mode, and a client sending datagrams to it. After the server receives the first datagram (cf. _xioopen_ipdgram_listen()), it issues a connect() to the address of the sender, in order to set up a directed flow.
Now, if the client, running on a different CPU thread, happens to send a (subsequent) datagram while the server's socket changes its address, but is not rehashed yet, this will result in a failed lookup and a port unreachable error delivered to the client, as apparent from the following reproducer:
LEN=$(($(cat /proc/sys/net/core/wmem_default) / 4))
dd if=/dev/urandom bs=1 count=${LEN} of=tmp.in
while :; do
taskset -c 1 socat UDP4-LISTEN:1337,null-eof OPEN:tmp.out,create,trunc &
sleep 0.1 || sleep 1
taskset -c 2 socat OPEN:tmp.in UDP4:localhost:1337,shut-null
wait
donewhere the client will eventually get ECONNREFUSED on a write() (typically the second or third one of a given iteration):
2024/11/13 21:28:23 socat[46901] E write(6, 0x556db2e3c000, 8192): Connection refused
This issue was first observed as a seldom failure in Podman's tests checking UDP functionality while using pasta(1) to connect the container's network namespace, which leads us to a reproducer with the lookup error resulting in an ICMP packet on a tap device:
LOCAL_ADDR="$(ip -j -4 addr show|jq -rM '.[] | .addr_info[0] | select(.scope == "global").local')"
while :; do
./pasta --config-net -p pasta.pcap -u 1337 socat UDP4-LISTEN:1337,null-eof OPEN:tmp.out,create,trunc &
sleep 0.2 || sleep 1
socat OPEN:tmp.in UDP4:${LOCAL_ADDR}:1337,shut-null
wait
cmp tmp.in tmp.out
doneOnce this fails:
tmp.in tmp.out differ: char 8193, line 29
we can finally have a look at what's going on:
$ tshark -r pasta.pcap
1 0.000000 :: ? ff02::16 ICMPv6 110 Multicast Listener Report Message v2
2 0.168690 88.198.0.161 ? 88.198.0.164 UDP 8234 60260 ? 1337 Len=8192
3 0.168767 88.198.0.161 ? 88.198.0.164 UDP 8234 60260 ? 1337 Len=8192
4 0.168806 88.198.0.161 ? 88.198.0.164 UDP 8234 60260 ? 1337 Len=8192
5 0.168827 c6:47:05:8d:dc:04 ? Broadcast ARP 42 Who has 88.198.0.161? Tell 88.198.0.164
6 0.168851 9a:55:9a:55:9a:55 ? c6:47:05:8d:dc:04 ARP 42 88.198.0.161 is at 9a:55:9a:55:9a:55
7 0.168875 88.198.0.161 ? 88.198.0.164 UDP 8234 60260 ? 1337 Len=8192
8 0.168896 88.198.0.164 ? 88.198.0.161 ICMP 590 Destination unreachable (Port unreachable)
9 0.168926 88.198.0.161 ? 88.198.0.164 UDP 8234 60260 ? 1337 Len=8192
10 0.168959 88.198.0.161 ? 88.198.0.164 UDP 8234 60260 ? 1337 Len=8192
11 0.168989 88.198.0.161 ? 88.198.0.164 UDP 4138 60260 ? 1337 Len=4096
12 0.169010 88.198.0.161 ? 88.198.0.164 UDP 42 60260 ? 1337 Len=0On the third datagram received, the network namespace of the container initiates an ARP lookup to deliver the ICMP message.
In another variant of this reproducer, starting the client with:
strace -f pasta --config-net -u 1337 socat UDP4-LISTEN:1337,null-eof OPEN:tmp.out,create,trunc 2>strace.log &
and connecting to the socat server using a loopback address:
socat OPEN:tmp.in UDP4:localhost:1337,shut-null
we can more clearly observe a sendmmsg() call failing after the first datagram is delivered:
[pid 278012] connect(173, 0x7fff96c95fc0, 16) = 0
[...]
[pid 278012] recvmmsg(173, 0x7fff96c96020, 1024, MSG_DONTWAIT, NULL) = -1 EAGAIN (Resource temporarily unavailable) [pid 278012] sendmmsg(173, 0x561c5ad0a720, 1, MSG_NOSIGNAL) = 1
[...]
[pid 278012] sendmmsg(173, 0x561c5ad0a720, 1, MSG_NOSIGNAL) = -1 ECONNREFUSED (Connection refused)
and, somewhat confusingly, after a connect() on the same socket succeeded.
Until commit 4cdeeee9252a ("net: udp: prefer listeners bound to an address"), the race between receive address change and lookup didn't actually cause visible issues, because, once the lookup based on the secondary hash chain failed, we would still attempt a lookup based on the primary hash (destination port only), and find the socket with the outdated secondary hash.
That change, however, dropped port-only lookups altogether, as side effect, making the race visible.
To fix this, while avoiding the need to make address changes and rehash atomic against lookups, reintroduce primary hash lookups as fallback, if lookups based on four-tuple and secondary hashes fail.
To this end, introduce a simplified lookup implementation, which doesn't take care of SO_REUSEPORT groups: if we have one, there are multiple sockets that would match the four-tuple or secondary hash, meaning that we can't run into this race at all.
v2:
- instead of synchronising lookup operations against address change plus rehash, reintroduce a simplified version of the original primary hash lookup as fallback
v1:
- fix build with CONFIG_IPV6=n: add ifdef around sk_v6_rcv_saddr usage (Kuniyuki Iwashima)
- directly use sk_rcv_saddr for IPv4 receive addresses instead of fetching inet_rcv_saddr (Kuniyuki Iwashima)
- move inet_update_saddr() to inet_hashtables.h and use that to set IPv4/IPv6 addresses as suitable (Kuniyuki Iwashima)
- rebase onto net-next, update commit message accordingly
--- net/ipv4/udp.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++ net/ipv6/udp.c | 50 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+)
net/ipv4/udp.c +56 -0
@@ -414,6 +414,49 @@ u32 udp_ehashfn(const struct net *net, const __be32 laddr, const __u16 lport, udp_ehash_secret + net_hash_mix(net)); } +/** +* udp4_lib_lookup1() - Simplified lookup using primary hash (destination port) +* @net: Network namespace +* @saddr: Source address, network order +* @sport: Source port, network order +* @daddr: Destination address, network order +* @hnum: Destination port, host order +* @dif: Destination interface index +* @sdif: Destination bridge port index, if relevant +* @udptable: Set of UDP hash tables +* +* Simplified lookup to be used as fallback if no sockets are found due to a +* potential race between (receive) address change, and lookup happening before +* the rehash operation. This function ignores SO_REUSEPORT groups while scoring +* result sockets, because if we have one, we don't need the fallback at all. +* +* Called under rcu_read_lock(). +* +* Return: socket with highest matching score if any, NULL if none +*/ +static struct sock *udp4_lib_lookup1 (struct net *net, +__be32 saddr,__be16 sport, +__be32 daddr,unsigned int hnum, +int dif,int sdif, +const struct udp_table *udptable) +{ +unsigned int slot =udp_hashfn (net, hnum, udptable->mask); +struct udp_hslot *hslot = &udptable->hash[slot]; +struct sock *sk, *result =NULL ; +int score, badness =0 ; + +sk_for_each_rcu (sk, &hslot->head) { + score =compute_score (sk, net, + saddr, sport, daddr, hnum, dif, sdif); +if (score > badness) { + result = sk; + badness = score; + } + } + +return result; +} +/* called with rcu_read_lock() */ static struct sock *udp4_lib_lookup2(struct net *net, __be32 saddr, __be16 sport,
@@ -541,6 +584,19 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, result =udp4_lib_lookup2 (net, saddr, sport,htonl (INADDR_ANY ), hnum, dif, sdif, hslot2, skb); +if (!IS_ERR_OR_NULL (result)) + goto done; + +/* Primary hash (destination port) lookup as fallback for this race: +* 1. __ip4_datagram_connect() sets sk_rcv_saddr +* 2. lookup (this function): new sk_rcv_saddr, hashes not updated yet +* 3. rehash operation updating _secondary and four-tuple_ hashes +* The primary hash doesn't need an update after 1., so, thanks to this +* further step, 1. and 3. don't need to be atomic against the lookup. +*/ + result =udp4_lib_lookup1 (net, saddr, sport, daddr, hnum, dif, sdif, + udptable); + done:if (IS_ERR (result))return NULL ;
net/ipv6/udp.c +50 -0
62 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 725/1887 btrfs: do proper folio cleanup when cow_file_range() failed
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo <[email protected]>
[ Upstream commit 06f364284794f149d2abc167c11d556cf20c954b ]
[BUG]
When testing with COW fixup marked as BUG_ON() (this is involved with the new pin_user_pages*() change, which should not result new out-of-band dirty pages), I hit a crash triggered by the BUG_ON() from hitting COW fixup path.
This BUG_ON() happens just after a failed btrfs_run_delalloc_range():
BTRFS error (device dm-2): failed to run delalloc range, root 348 ino 405 folio 65536 submit_bitmap 6-15 start 90112 len 106496: -28
------------[ cut here ]------------ kernel BUG at fs/btrfs/extent_io.c:1444! Internal error: Oops - BUG: 00000000f2000800 [#1] SMP CPU: 0 UID: 0 PID: 434621 Comm: kworker/u24:8 Tainted: G OE 6.12.0-rc7-custom+ #86 Hardware name: QEMU KVM Virtual Machine, BIOS unknown 2/2/2022 Workqueue: events_unbound btrfs_async_reclaim_data_space [btrfs] pc : extent_writepage_io+0x2d4/0x308 [btrfs] lr : extent_writepage_io+0x2d4/0x308 [btrfs] Call trace: extent_writepage_io+0x2d4/0x308 [btrfs] extent_writepage+0x218/0x330 [btrfs] extent_write_cache_pages+0x1d4/0x4b0 [btrfs] btrfs_writepages+0x94/0x150 [btrfs] do_writepages+0x74/0x190 filemap_fdatawrite_wbc+0x88/0xc8 start_delalloc_inodes+0x180/0x3b0 [btrfs] btrfs_start_delalloc_roots+0x174/0x280 [btrfs] shrink_delalloc+0x114/0x280 [btrfs] flush_space+0x250/0x2f8 [btrfs] btrfs_async_reclaim_data_space+0x180/0x228 [btrfs] process_one_work+0x164/0x408 worker_thread+0x25c/0x388 kthread+0x100/0x118 ret_from_fork+0x10/0x20 Code: aa1403e1 9402f3ef aa1403e0 9402f36f (d4210000) ---[ end trace 0000000000000000 ]---
[CAUSE]
That failure is mostly from cow_file_range(), where we can hit -ENOSPC.
Although the -ENOSPC is already a bug related to our space reservation code, let's just focus on the error handling.
For example, we have the following dirty range [0, 64K) of an inode, with 4K sector size and 4K page size:
0 16K 32K 48K 64K |///////////////////////////////////////| |#######################################|
Where |///| means page are still dirty, and |###| means the extent io tree has EXTENT_DELALLOC flag.
- Enter extent_writepage() for page 0
- Enter btrfs_run_delalloc_range() for range [0, 64K)
- Enter cow_file_range() for range [0, 64K)
- Function btrfs_reserve_extent() only reserved one 16K extent So we created extent map and ordered extent for range [0, 16K)
0 16K 32K 48K 64K |////////|//////////////////////////////| |<- OE ->|##############################|
And range [0, 16K) has its delalloc flag cleared.
But since we haven't yet submit any bio, involved 4 pages are still dirty.
- Function btrfs_reserve_extent() returns with -ENOSPC Now we have to run error cleanup, which will clear all EXTENT_DELALLOC* flags and clear the dirty flags for the remaining ranges:
0 16K 32K 48K 64K |////////| | | | |
Note that range [0, 16K) still has its pages dirty.
- Some time later, writeback is triggered again for the range [0, 16K) since the page range still has dirty flags.
- btrfs_run_delalloc_range() will do nothing because there is no EXTENT_DELALLOC flag.
- extent_writepage_io() finds page 0 has no ordered flag Which falls into the COW fixup path, triggering the BUG_ON().
Unfortunately this error handling bug dates back to the introduction of btrfs. Thankfully with the abuse of COW fixup, at least it won't crash the kernel.
[FIX]
Instead of immediately unlocking the extent and folios, we keep the extent and folios locked until either erroring out or the whole delalloc range finished.
When the whole delalloc range finished without error, we just unlock the whole range with PAGE_SET_ORDERED (and PAGE_UNLOCK for !keep_locked cases), with EXTENT_DELALLOC and EXTENT_LOCKED cleared.
And the involved folios will be properly submitted, with their dirty flags cleared during submission.
For the error path, it will be a little more complex:
- The range with ordered extent allocated (range (1))
We only clear the EXTENT_DELALLOC and EXTENT_LOCKED, as the remaining flags are cleaned up by btrfs_mark_ordered_io_finished()->btrfs_finish_one_ordered().
For folios we finish the IO (clear dirty, start writeback and immediately finish the writeback) and unlock the folios.
- The range with reserved extent but no ordered extent (range(2))
- The range we never touched (range(3))
For both range (2) and range(3) the behavior is not changed.
Now even if cow_file_range() failed halfway with some successfully reserved extents/ordered extents, we will keep all folios clean, so there will be no future writeback triggered on them.
--- fs/btrfs/inode.c | 63 ++++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 29 deletions(-)
fs/btrfs/inode.c +34 -29
@@ -1265,6 +1265,17 @@ static noinline int cow_file_range(struct btrfs_inode *inode, alloc_hint =get_extent_allocation_hint (inode, start, num_bytes); +/* +* We're not doing compressed IO, don't unlock the first page (which +* the caller expects to stay locked), don't clear any dirty bits and +* don't set any writeback bits. +* +* Do set the Ordered (Private2) bit so we know this page was properly +* setup for writepage. +*/ + page_ops = unlock ?PAGE_UNLOCK :0 ; + page_ops |=PAGE_SET_ORDERED ; +/* * Relocation relies on the relocated extents to have exactly the same * size as the original extents. Normally writeback for relocation data
@@ -1335,21 +1346,6 @@ static noinline int cow_file_range(struct btrfs_inode *inode,btrfs_dec_block_group_reservations (fs_info, ins.objectid); -/* -* We're not doing compressed IO, don't unlock the first page -* (which the caller expects to stay locked), don't clear any -* dirty bits and don't set any writeback bits -* -* Do set the Ordered (Private2) bit so we know this page was -* properly setup for writepage. -*/ - page_ops = unlock ?PAGE_UNLOCK :0 ; - page_ops |=PAGE_SET_ORDERED ; - -extent_clear_unlock_delalloc (inode, start, start + ram_size -1 , - locked_page, -EXTENT_LOCKED |EXTENT_DELALLOC , - page_ops);if (num_bytes < cur_alloc_size) num_bytes =0 ;else
@@ -1366,6 +1362,8 @@ static noinline int cow_file_range(struct btrfs_inode *inode,if (ret) goto out_unlock; } +extent_clear_unlock_delalloc (inode, orig_start, end, locked_page, +EXTENT_LOCKED |EXTENT_DELALLOC , page_ops); out:return ret;
@@ -1380,10 +1378,15 @@ static noinline int cow_file_range(struct btrfs_inode *inode,* caller to write out the successfully allocated region and retry. */ if (done_offset && ret == -EAGAIN ) { -if (orig_start < start) +if (orig_start < start) { +extent_clear_unlock_delalloc (inode, orig_start, start -1 , + locked_page, +EXTENT_LOCKED |EXTENT_DELALLOC , + page_ops); *done_offset = start -1 ; -else + }else { *done_offset = start; + }return ret; }else if (ret == -EAGAIN ) {/* Convert to -ENOSPC since the caller cannot retry. */
@@ -1399,29 +1402,31 @@ static noinline int cow_file_range(struct btrfs_inode *inode,* We process each region below. */ - clear_bits =EXTENT_LOCKED |EXTENT_DELALLOC |EXTENT_DELALLOC_NEW | -EXTENT_DEFRAG |EXTENT_CLEAR_META_RESV ; - page_ops =PAGE_UNLOCK |PAGE_START_WRITEBACK |PAGE_END_WRITEBACK ; -/* * For the range (1). We have already instantiated the ordered extents * for this region. They are cleaned up by * btrfs_cleanup_ordered_extents() in e.g, -* btrfs_run_delalloc_range(). EXTENT_LOCKED | EXTENT_DELALLOC are -* already cleared in the above loop. And, EXTENT_DELALLOC_NEW | -* EXTENT_DEFRAG | EXTENT_CLEAR_META_RESV are handled by the cleanup -* function. +* btrfs_run_delalloc_range(). +* EXTENT_DELALLOC_NEW | EXTENT_DEFRAG | EXTENT_CLEAR_META_RESV +* are also handled by the cleanup function. * -* However, in case of unlock == 0, we still need to unlock the pages -* (except @locked_page) to ensure all the pages are unlocked. +* So here we only clear EXTENT_LOCKED and EXTENT_DELALLOC flag, and +* finish the writeback of the involved folios, which will be never submitted. */ -if (!unlock && orig_start < start) { +if (orig_start < start) { + clear_bits =EXTENT_LOCKED |EXTENT_DELALLOC ; + page_ops =PAGE_UNLOCK |PAGE_START_WRITEBACK |PAGE_END_WRITEBACK ; +if (!locked_page)mapping_set_error (inode->vfs_inode.i_mapping, ret);extent_clear_unlock_delalloc (inode, orig_start, start -1 , - locked_page,0 , page_ops); + locked_page, clear_bits, page_ops); } + clear_bits =EXTENT_LOCKED |EXTENT_DELALLOC |EXTENT_DELALLOC_NEW | +EXTENT_DEFRAG |EXTENT_CLEAR_META_RESV ; + page_ops =PAGE_UNLOCK |PAGE_START_WRITEBACK |PAGE_END_WRITEBACK ; +/* * For the range (2). If we reserved an extent for our delalloc range * (or a subrange) and failed to create the respective ordered extent,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 726/1887 xfrm: state: fix out-of-bounds read during lookup
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit e952837f3ddb0ff726d5b582aa1aad9aa38d024d ]
lookup and resize can run in parallel.
The xfrm_state_hash_generation seqlock ensures a retry, but the hash functions can observe a hmask value that is too large for the new hlist array.
rehash does:
rcu_assign_pointer(net->xfrm.state_bydst, ndst) [..] net->xfrm.state_hmask = nhashmask;
While state lookup does:
h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, encap_family); hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h, bydst) {
This is only safe in case the update to state_bydst is larger than net->xfrm.xfrm_state_hmask (or if the lookup function gets serialized via state spinlock again).
Fix this by prefetching state_hmask and the associated pointers. The xfrm_state_hash_generation seqlock retry will ensure that the pointer and the hmask will be consistent.
The existing helpers, like xfrm_dst_hash(), are now unsafe for RCU side, add lockdep assertions to document that they are only safe for insert side.
xfrm_state_lookup_byaddr() uses the spinlock rather than RCU. AFAICS this is an oversight from back when state lookup was converted to RCU, this lock should be replaced with RCU in a future patch.
--- net/xfrm/xfrm_state.c | 77 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 62 insertions(+), 15 deletions(-)
net/xfrm/xfrm_state.c +62 -15
@@ -34,6 +34,8 @@#define xfrm_state_deref_prot (table, net) \ rcu_dereference_protected((table), lockdep_is_held(&(net)->xfrm.xfrm_state_lock)) +#define xfrm_state_deref_check (table, net) \ + rcu_dereference_check((table), lockdep_is_held(&(net)->xfrm.xfrm_state_lock))static void xfrm_state_gc_task (struct work_struct *work);
@@ -61,6 +63,8 @@ static inline unsigned int xfrm_dst_hash(struct net *net, u32 reqid, unsigned short family) { +lockdep_assert_held (&net->xfrm.xfrm_state_lock); +return __xfrm_dst_hash (daddr, saddr, reqid, family, net->xfrm.state_hmask); }
@@ -69,6 +73,8 @@ static inline unsigned int xfrm_src_hash(struct net *net,const xfrm_address_t *saddr, unsigned short family) { + lockdep_assert_held(&net->xfrm.xfrm_state_lock); +return __xfrm_src_hash (daddr, saddr, family, net->xfrm.state_hmask); }
@@ -76,11 +82,15 @@ static inline unsigned int xfrm_spi_hash(struct net *net, const xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family) { + lockdep_assert_held(&net->xfrm.xfrm_state_lock); +return __xfrm_spi_hash (daddr, spi, proto, family, net->xfrm.state_hmask); }static unsigned int xfrm_seq_hash (struct net *net,u32 seq) { +lockdep_assert_held (&net->xfrm.xfrm_state_lock); +return __xfrm_seq_hash (seq, net->xfrm.state_hmask); }
@@ -944,15 +954,37 @@ xfrm_init_tempstate(struct xfrm_state *x, const struct flowi *fl, x->props.family = tmpl->encap_family; } -static struct xfrm_state *__xfrm_state_lookup (struct net *net,u32 mark, +struct xfrm_hash_state_ptrs { +const struct hlist_head *bydst; +const struct hlist_head *bysrc; +const struct hlist_head *byspi; +unsigned int hmask; +}; + +static void xfrm_hash_ptrs_get (const struct net *net,struct xfrm_hash_state_ptrs *ptrs) +{ +unsigned int sequence; + +do { + sequence =read_seqcount_begin (&net->xfrm.xfrm_state_hash_generation); + + ptrs->bydst =xfrm_state_deref_check (net->xfrm.state_bydst, net); + ptrs->bysrc =xfrm_state_deref_check (net->xfrm.state_bysrc, net); + ptrs->byspi =xfrm_state_deref_check (net->xfrm.state_byspi, net); + ptrs->hmask = net->xfrm.state_hmask; + }while (read_seqcount_retry (&net->xfrm.xfrm_state_hash_generation, sequence)); +} + +static struct xfrm_state *__xfrm_state_lookup (const struct xfrm_hash_state_ptrs *state_ptrs, +u32 mark,const xfrm_address_t *daddr,__be32 spi,u8 proto,unsigned short family) { -unsigned int h =xfrm_spi_hash (net, daddr, spi, proto, family); +unsigned int h =__xfrm_spi_hash (daddr, spi, proto, family, state_ptrs->hmask);struct xfrm_state *x; -hlist_for_each_entry_rcu (x, net->xfrm.state_byspi + h, byspi) { +hlist_for_each_entry_rcu (x, state_ptrs->byspi + h, byspi) { if (x->props.family != family || x->id.spi != spi || x->id.proto != proto ||
@@ -969,15 +1001,16 @@ static struct xfrm_state *__xfrm_state_lookup(struct net *net, u32 mark,return NULL ; } -static struct xfrm_state *__xfrm_state_lookup_byaddr (struct net *net,u32 mark, +static struct xfrm_state *__xfrm_state_lookup_byaddr (const struct xfrm_hash_state_ptrs *state_ptrs, +u32 mark,const xfrm_address_t *daddr,const xfrm_address_t *saddr,u8 proto,unsigned short family) { -unsigned int h =xfrm_src_hash (net, daddr, saddr, family); +unsigned int h =__xfrm_src_hash (daddr, saddr, family, state_ptrs->hmask);struct xfrm_state *x; -hlist_for_each_entry_rcu (x, net->xfrm.state_bysrc + h, bysrc) { +hlist_for_each_entry_rcu (x, state_ptrs->bysrc + h, bysrc) { if (x->props.family != family || x->id.proto != proto || !xfrm_addr_equal(&x->id.daddr, daddr, family) ||
@@ -997,14 +1030,17 @@ static struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, u32 mark,static inline struct xfrm_state *__xfrm_state_locate (struct xfrm_state *x,int use_spi,int family) { +struct xfrm_hash_state_ptrs state_ptrs;struct net *net =xs_net (x);u32 mark = x->mark.v & x->mark.m; +xfrm_hash_ptrs_get (net, &state_ptrs); +if (use_spi) -return __xfrm_state_lookup (net, mark, &x->id.daddr, +return __xfrm_state_lookup (&state_ptrs, mark, &x->id.daddr, x->id.spi, x->id.proto, family);else -return __xfrm_state_lookup_byaddr (net, mark, +return __xfrm_state_lookup_byaddr (&state_ptrs, mark, &x->id.daddr, &x->props.saddr, x->id.proto, family);
@@ -1067,6 +1103,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr, unsigned short family, u32 if_id) {static xfrm_address_t saddr_wildcard = { }; +struct xfrm_hash_state_ptrs state_ptrs;struct net *net =xp_net (pol);unsigned int h, h_wildcard;struct xfrm_state *x, *x0, *to_put;
@@ -1083,8 +1120,10 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr, sequence =read_seqcount_begin (&net->xfrm.xfrm_state_hash_generation);rcu_read_lock (); - h =xfrm_dst_hash (net, daddr, saddr, tmpl->reqid, encap_family); -hlist_for_each_entry_rcu (x, net->xfrm.state_bydst + h, bydst) { +xfrm_hash_ptrs_get (net, &state_ptrs); + + h =__xfrm_dst_hash (daddr, saddr, tmpl->reqid, encap_family, state_ptrs.hmask); +hlist_for_each_entry_rcu (x, state_ptrs.bydst + h, bydst) { if (x->props.family == encap_family && x->props.reqid == tmpl->reqid && (mark & x->mark.m) == x->mark.v &&
@@ -1100,8 +1139,9 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,if (best || acquire_in_progress) goto found; - h_wildcard =xfrm_dst_hash (net, daddr, &saddr_wildcard, tmpl->reqid, encap_family); -hlist_for_each_entry_rcu (x, net->xfrm.state_bydst + h_wildcard, bydst) { + h_wildcard =__xfrm_dst_hash (daddr, &saddr_wildcard, tmpl->reqid, + encap_family, state_ptrs.hmask); +hlist_for_each_entry_rcu (x, state_ptrs.bydst + h_wildcard, bydst) { if (x->props.family == encap_family && x->props.reqid == tmpl->reqid && (mark & x->mark.m) == x->mark.v &&
@@ -1119,7 +1159,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr, x = best;if (!x && !error && !acquire_in_progress) {if (tmpl->id.spi && - (x0 =__xfrm_state_lookup (net, mark, daddr, tmpl->id.spi, + (x0 =__xfrm_state_lookup (&state_ptrs, mark, daddr, tmpl->id.spi, tmpl->id.proto, encap_family)) !=NULL ) { to_put = x0; error = -EEXIST ;
@@ -1807,10 +1847,13 @@ struct xfrm_state * xfrm_state_lookup(struct net *net, u32 mark, const xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family) { + struct xfrm_hash_state_ptrs state_ptrs;struct xfrm_state *x;rcu_read_lock (); - x =__xfrm_state_lookup (net, mark, daddr, spi, proto, family); +xfrm_hash_ptrs_get (net, &state_ptrs); + + x =__xfrm_state_lookup (&state_ptrs, mark, daddr, spi, proto, family);rcu_read_unlock ();return x; }
@@ -1821,10 +1864,14 @@ xfrm_state_lookup_byaddr(struct net *net, u32 mark, const xfrm_address_t *daddr, const xfrm_address_t *saddr, u8 proto, unsigned short family) { + struct xfrm_hash_state_ptrs state_ptrs;struct xfrm_state *x;spin_lock_bh (&net->xfrm.xfrm_state_lock); - x =__xfrm_state_lookup_byaddr (net, mark, daddr, saddr, proto, family); + +xfrm_hash_ptrs_get (net, &state_ptrs); + + x =__xfrm_state_lookup_byaddr (&state_ptrs, mark, daddr, saddr, proto, family);spin_unlock_bh (&net->xfrm.xfrm_state_lock);return x; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 727/1887 powerpc/pseries/iommu: IOMMU incorrectly marks MMIO range in DDW
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gaurav Batra <[email protected]>
[ Upstream commit 8f70caad82e9c088ed93b4fea48d941ab6441886 ]
Power Hypervisor can possibily allocate MMIO window intersecting with Dynamic DMA Window (DDW) range, which is over 32-bit addressing.
These MMIO pages needs to be marked as reserved so that IOMMU doesn't map DMA buffers in this range.
The current code is not marking these pages correctly which is resulting in LPAR to OOPS while booting. The stack is at below
BUG: Unable to handle kernel data access on read at 0xc00800005cd40000 Faulting instruction address: 0xc00000000005cdac Oops: Kernel access of bad area, sig: 11 [#1] LE PAGE_SIZE=64K MMU=Hash SMP NR_CPUS=2048 NUMA pSeries Modules linked in: af_packet rfkill ibmveth(X) lpfc(+) nvmet_fc nvmet nvme_keyring crct10dif_vpmsum nvme_fc nvme_fabrics nvme_core be2net(+) nvme_auth rtc_generic nfsd auth_rpcgss nfs_acl lockd grace sunrpc fuse configfs ip_tables x_tables xfs libcrc32c dm_service_time ibmvfc(X) scsi_transport_fc vmx_crypto gf128mul crc32c_vpmsum dm_mirror dm_region_hash dm_log dm_multipath dm_mod sd_mod scsi_dh_emc scsi_dh_rdac scsi_dh_alua t10_pi crc64_rocksoft_generic crc64_rocksoft sg crc64 scsi_mod Supported: Yes, External CPU: 8 PID: 241 Comm: kworker/8:1 Kdump: loaded Not tainted 6.4.0-150600.23.14-default #1 SLE15-SP6 b44ee71c81261b9e4bab5e0cde1f2ed891d5359b Hardware name: IBM,9080-M9S POWER9 (raw) 0x4e2103 0xf000005 of:IBM,FW950.B0 (VH950_149) hv:phyp pSeries Workqueue: events work_for_cpu_fn NIP: c00000000005cdac LR: c00000000005e830 CTR: 0000000000000000 REGS: c00001400c9ff770 TRAP: 0300 Not tainted (6.4.0-150600.23.14-default) MSR: 800000000280b033 <SF,VEC,VSX,EE,FP,ME,IR,DR,RI,LE> CR: 24228448 XER: 00000001 CFAR: c00000000005cdd4 DAR: c00800005cd40000 DSISR: 40000000 IRQMASK: 0
GPR00: c00000000005e830 c00001400c9ffa10 c000000001987d00 c00001400c4fe800
GPR04: 0000080000000000 0000000000000001 0000000004000000 0000000000800000
GPR08: 0000000004000000 0000000000000001 c00800005cd40000 ffffffffffffffff
GPR12: 0000000084228882 c00000000a4c4f00 0000000000000010 0000080000000000
GPR16: c00001400c4fe800 0000000004000000 0800000000000000 c00000006088b800
GPR20: c00001401a7be980 c00001400eff3800 c000000002a2da68 000000000000002b
GPR24: c0000000026793a8 c000000002679368 000000000000002a c0000000026793c8
GPR28: 000008007effffff 0000080000000000 0000000000800000 c00001400c4fe800 NIP [c00000000005cdac] iommu_table_reserve_pages+0xac/0x100
LR [c00000000005e830] iommu_init_table+0x80/0x1e0
Call Trace: [c00001400c9ffa10] [c00000000005e810] iommu_init_table+0x60/0x1e0 (unreliable) [c00001400c9ffa90] [c00000000010356c] iommu_bypass_supported_pSeriesLP+0x9cc/0xe40 [c00001400c9ffc30] [c00000000005c300] dma_iommu_dma_supported+0xf0/0x230 [c00001400c9ffcb0] [c00000000024b0c4] dma_supported+0x44/0x90 [c00001400c9ffcd0] [c00000000024b14c] dma_set_mask+0x3c/0x80 [c00001400c9ffd00] [c0080000555b715c] be_probe+0xc4/0xb90 [be2net] [c00001400c9ffdc0] [c000000000986f3c] local_pci_probe+0x6c/0x110 [c00001400c9ffe40] [c000000000188f28] work_for_cpu_fn+0x38/0x60 [c00001400c9ffe70] [c00000000018e454] process_one_work+0x314/0x620 [c00001400c9fff10] [c00000000018f280] worker_thread+0x2b0/0x620 [c00001400c9fff90] [c00000000019bb18] kthread+0x148/0x150 [c00001400c9fffe0] [c00000000000ded8] start_kernel_thread+0x14/0x18
There are 2 issues in the code
1. The index is "int" while the address is "unsigned long". This results in negative value when setting the bitmap.
2. The DMA offset is page shifted but the MMIO range is used as-is (64-bit address). MMIO address needs to be page shifted as well.
--- arch/powerpc/kernel/iommu.c | 2 +- arch/powerpc/platforms/pseries/iommu.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-)
arch/powerpc/kernel/iommu.c +1 -1
@@ -685,7 +685,7 @@ static void iommu_table_clear(struct iommu_table *tbl)static void iommu_table_reserve_pages (struct iommu_table *tbl,unsigned long res_start,unsigned long res_end) { -int i; +unsigned long i;WARN_ON_ONCE (res_end < res_start);/*
arch/powerpc/platforms/pseries/iommu.c +2 -1
@@ -1510,7 +1510,8 @@ static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn)iommu_table_setparms_common (newtbl, pci->phb->bus->number, create.liobn, win_addr,1UL << len, page_shift,NULL , &iommu_table_lpar_multi_ops); -iommu_init_table (newtbl, pci->phb->node, start, end); +iommu_init_table (newtbl, pci->phb->node, + start >> page_shift, end >> page_shift); pci->table_group->tables[1 ] = newtbl;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 728/1887 PCI: dwc: ep: Prevent changing BAR size/flags in pci_epc_set_bar()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Niklas Cassel <[email protected]>
[ Upstream commit 3708acbd5f169ebafe1faa519cb28adc56295546 ]
In commit 4284c88fff0e ("PCI: designware-ep: Allow pci_epc_set_bar() update inbound map address") set_bar() was modified to support dynamically changing the backing physical address of a BAR that was already configured.
This means that set_bar() can be called twice, without ever calling clear_bar() (as calling clear_bar() would clear the BAR's PCI address assigned by the host).
This can only be done if the new BAR size/flags does not differ from the existing BAR configuration. Add these missing checks.
If we allow set_bar() to set e.g. a new BAR size that differs from the existing BAR size, the new address translation range will be smaller than the BAR size already determined by the host, which would mean that a read past the new BAR size would pass the iATU untranslated, which could allow the host to read memory not belonging to the new struct pci_epf_bar.
While at it, add comments which clarifies the support for dynamically changing the physical address of a BAR. (Which was also missing.)
--- drivers/pci/controller/dwc/pcie-designware-ep.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
drivers/pci/controller/dwc/pcie-designware-ep.c +17 -0
@@ -247,6 +247,23 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, func_offset =dw_pcie_ep_func_select (ep, func_no); +/* +* Certain EPF drivers dynamically change the physical address of a BAR +* (i.e. they call set_bar() twice, without ever calling clear_bar(), as +* calling clear_bar() would clear the BAR's PCI address assigned by the +* host). +*/ +if (ep->epf_bar[bar]) { +/* +* We can only dynamically change a BAR if the new BAR size and +* BAR flags do not differ from the existing configuration. +*/ +if (ep->epf_bar[bar]->barno != bar || + ep->epf_bar[bar]->size != size || + ep->epf_bar[bar]->flags != flags) +return -EINVAL ; + } + reg =PCI_BASE_ADDRESS_0 + (4 * bar) + func_offset;if (!(flags &PCI_BASE_ADDRESS_SPACE ))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 729/1887 ASoC: SOF: Intel: hda-dai: Ensure DAI widget is valid during params
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bard Liao <[email protected]>
[ Upstream commit 569922b82ca660f8b24e705f6cf674e6b1f99cc7 ]
Each cpu DAI should associate with a widget. However, the topology might not create the right number of DAI widgets for aggregated amps. And it will cause NULL pointer deference.
Check that the DAI widget associated with the CPU DAI is valid to prevent NULL pointer deference due to missing DAI widgets in topologies with aggregated amps.
--- sound/soc/sof/intel/hda.c | 5 +++++ 1 file changed, 5 insertions(+)
sound/soc/sof/intel/hda.c +5 -0
@@ -128,6 +128,11 @@ static int sdw_params_stream(struct device *dev,struct snd_soc_dapm_widget *w; w =snd_soc_dai_get_widget (d, params_data->stream); +if (!w) { +dev_err (dev,"%s widget not found, check amp link num in the topology\n" , + d->name); +return -EINVAL ; + } data.dai_index = (params_data->link_id <<8 ) | d->id; data.dai_data = params_data->alh_stream_id;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 730/1887 rds: sysctl: rds_tcp_{rcv,snd}buf: avoid using current->nsproxy
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthieu Baerts (NGI0) <[email protected]>
[ Upstream commit 7f5611cbc4871c7fb1ad36c2e5a9edad63dca95c ]
As mentioned in a previous commit of this series, using the 'net' structure via 'current' is not recommended for different reasons:
- Inconsistency: getting info from the reader's/writer's netns vs only from the opener's netns.
- current->nsproxy can be NULL in some cases, resulting in an 'Oops' (null-ptr-deref), e.g. when the current task is exiting, as spotted by syzbot [1] using acct(2).
The per-netns structure can be obtained from the table->data using container_of(), then the 'net' one can be retrieved from the listen socket (if available).
--- net/rds/tcp.c | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-)
net/rds/tcp.c +32 -7
@@ -53,8 +53,10 @@ static atomic_t rds_tcp_unloading = ATOMIC_INIT(0);static struct kmem_cache *rds_tcp_conn_slab; -static int rds_tcp_skbuf_handler (struct ctl_table *ctl,int write, -void *buffer,size_t *lenp,loff_t *fpos); +static int rds_tcp_sndbuf_handler (struct ctl_table *ctl,int write, +void *buffer,size_t *lenp,loff_t *fpos); +static int rds_tcp_rcvbuf_handler (struct ctl_table *ctl,int write, +void *buffer,size_t *lenp,loff_t *fpos);static int rds_tcp_min_sndbuf =SOCK_MIN_SNDBUF ;static int rds_tcp_min_rcvbuf =SOCK_MIN_RCVBUF ;
@@ -66,7 +68,7 @@ static struct ctl_table rds_tcp_sysctl_table[] = {/* data is per-net pointer */ .maxlen = sizeof(int), .mode = 0644, - .proc_handler = rds_tcp_skbuf_handler, + .proc_handler = rds_tcp_sndbuf_handler, .extra1 = &rds_tcp_min_sndbuf, },#define RDS_TCP_RCVBUF 1
@@ -75,7 +77,7 @@ static struct ctl_table rds_tcp_sysctl_table[] = {/* data is per-net pointer */ .maxlen = sizeof(int), .mode = 0644, - .proc_handler = rds_tcp_skbuf_handler, + .proc_handler = rds_tcp_rcvbuf_handler, .extra1 = &rds_tcp_min_rcvbuf, }, { }
@@ -752,10 +754,10 @@ static void rds_tcp_sysctl_reset(struct net *net)spin_unlock_irq (&rds_tcp_conn_lock); } -static int rds_tcp_skbuf_handler (struct ctl_table *ctl,int write, +static int rds_tcp_skbuf_handler (struct rds_tcp_net *rtn, +struct ctl_table *ctl,int write,void *buffer,size_t *lenp,loff_t *fpos) { -struct net *net = current->nsproxy->net_ns;int err; err =proc_dointvec_minmax (ctl, write, buffer, lenp, fpos);
@@ -764,11 +766,34 @@ static int rds_tcp_skbuf_handler(struct ctl_table *ctl, int write, *(int *)(ctl->extra1));return err; } -if (write) + +if (write && rtn->rds_tcp_listen_sock && rtn->rds_tcp_listen_sock->sk) { +struct net *net =sock_net (rtn->rds_tcp_listen_sock->sk); +rds_tcp_sysctl_reset (net); + } +return 0 ; } +static int rds_tcp_sndbuf_handler (struct ctl_table *ctl,int write, +void *buffer,size_t *lenp,loff_t *fpos) +{ + struct rds_tcp_net *rtn = container_of(ctl->data, struct rds_tcp_net, + sndbuf_size); + +return rds_tcp_skbuf_handler (rtn, ctl, write, buffer, lenp, fpos); +} + +static int rds_tcp_rcvbuf_handler (struct ctl_table *ctl,int write, +void *buffer,size_t *lenp,loff_t *fpos) +{ + struct rds_tcp_net *rtn = container_of(ctl->data, struct rds_tcp_net, + rcvbuf_size); + +return rds_tcp_skbuf_handler (rtn, ctl, write, buffer, lenp, fpos); +} +static void rds_tcp_exit (void ) {rds_tcp_set_unloading ();
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 731/1887 smb: client: fix double free of TCP_Server_Info::hostname
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paulo Alcantara <[email protected]>
[ Upstream commit fa2f9906a7b333ba757a7dbae0713d8a5396186e ]
When shutting down the server in cifs_put_tcp_session(), cifsd thread might be reconnecting to multiple DFS targets before it realizes it should exit the loop, so @server->hostname can't be freed as long as cifsd thread isn't done. Otherwise the following can happen:
RIP: 0010:__slab_free+0x223/0x3c0 Code: 5e 41 5f c3 cc cc cc cc 4c 89 de 4c 89 cf 44 89 44 24 08 4c 89 1c 24 e8 fb cf 8e 00 44 8b 44 24 08 4c 8b 1c 24 e9 5f fe ff ff <0f> 0b 41 f7 45 08 00 0d 21 00 0f 85 2d ff ff ff e9 1f ff ff ff 80 RSP: 0018:ffffb26180dbfd08 EFLAGS: 00010246 RAX: ffff8ea34728e510 RBX: ffff8ea34728e500 RCX: 0000000000800068 RDX: 0000000000800068 RSI: 0000000000000000 RDI: ffff8ea340042400 RBP: ffffe112041ca380 R08: 0000000000000001 R09: 0000000000000000 R10: 6170732e31303000 R11: 70726f632e786563 R12: ffff8ea34728e500 R13: ffff8ea340042400 R14: ffff8ea34728e500 R15: 0000000000800068 FS: 0000000000000000(0000) GS:ffff8ea66fd80000(0000) 000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007ffc25376080 CR3: 000000012a2ba001 CR4: PKRU: 55555554 Call Trace: <TASK> ? show_trace_log_lvl+0x1c4/0x2df ? show_trace_log_lvl+0x1c4/0x2df ? __reconnect_target_unlocked+0x3e/0x160 [cifs] ? __die_body.cold+0x8/0xd ? die+0x2b/0x50 ? do_trap+0xce/0x120 ? __slab_free+0x223/0x3c0 ? do_error_trap+0x65/0x80 ? __slab_free+0x223/0x3c0 ? exc_invalid_op+0x4e/0x70 ? __slab_free+0x223/0x3c0 ? asm_exc_invalid_op+0x16/0x20 ? __slab_free+0x223/0x3c0 ? extract_hostname+0x5c/0xa0 [cifs] ? extract_hostname+0x5c/0xa0 [cifs] ? __kmalloc+0x4b/0x140 __reconnect_target_unlocked+0x3e/0x160 [cifs] reconnect_dfs_server+0x145/0x430 [cifs] cifs_handle_standard+0x1ad/0x1d0 [cifs] cifs_demultiplex_thread+0x592/0x730 [cifs] ? __pfx_cifs_demultiplex_thread+0x10/0x10 [cifs] kthread+0xdd/0x100 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x29/0x50 </TASK>
--- fs/smb/client/connect.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
fs/smb/client/connect.c +1 -2
@@ -1088,6 +1088,7 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server)kfree (server->origin_fullpath);kfree (server->leaf_fullpath);#endif +kfree (server->hostname);kfree (server); length =atomic_dec_return (&tcpSesAllocCount);
@@ -1708,8 +1709,6 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)kfree_sensitive (server->session_key.response); server->session_key.response =NULL ; server->session_key.len =0 ; -kfree (server->hostname); - server->hostname =NULL ; task =xchg (&server->tsk,NULL );if (task)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 732/1887 mm: clear uffd-wp PTE/PMD state on mremap()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ryan Roberts <[email protected]>
[ Upstream commit 0cef0bb836e3cfe00f08f9606c72abd72fe78ca3 ]
When mremap()ing a memory region previously registered with userfaultfd as write-protected but without UFFD_FEATURE_EVENT_REMAP, an inconsistency in flag clearing leads to a mismatch between the vma flags (which have uffd-wp cleared) and the pte/pmd flags (which do not have uffd-wp cleared). This mismatch causes a subsequent mprotect(PROT_WRITE) to trigger a warning in page_table_check_pte_flags() due to setting the pte to writable while uffd-wp is still set.
Fix this by always explicitly clearing the uffd-wp pte/pmd flags on any such mremap() so that the values are consistent with the existing clearing of VM_UFFD_WP. Be careful to clear the logical flag regardless of its physical form; a PTE bit, a swap PTE bit, or a PTE marker. Cover PTE, huge PMD and hugetlb paths.
--- fs/userfaultfd.c | 7 +++++++ include/linux/userfaultfd_k.h | 7 +++++++ mm/huge_memory.c | 12 ++++++++++++ mm/hugetlb.c | 14 +++++++++++++- mm/mremap.c | 32 +++++++++++++++++++++++++++++++- 5 files changed, 70 insertions(+), 2 deletions(-)
fs/userfaultfd.c +7 -0
@@ -108,6 +108,13 @@ static bool userfaultfd_is_initialized(struct userfaultfd_ctx *ctx)return ctx->features &UFFD_FEATURE_INITIALIZED ; } +bool vma_has_uffd_without_event_remap (struct vm_area_struct *vma) +{ +struct userfaultfd_ctx *uffd_ctx = vma->vm_userfaultfd_ctx.ctx; + +return uffd_ctx && (uffd_ctx->features &UFFD_FEATURE_EVENT_REMAP ) ==0 ; +} +static void userfaultfd_set_vm_flags (struct vm_area_struct *vma,vm_flags_t flags) {
include/linux/userfaultfd_k.h +7 -0
@@ -162,6 +162,8 @@ static inline bool vma_can_userfault(struct vm_area_struct *vma,vma_is_shmem (vma); } +bool vma_has_uffd_without_event_remap (struct vm_area_struct *vma); +extern int dup_userfaultfd (struct vm_area_struct *,struct list_head *);extern void dup_userfaultfd_complete (struct list_head *);
@@ -274,6 +276,11 @@ static inline bool uffd_disable_fault_around(struct vm_area_struct *vma) return false; } +static inline bool vma_has_uffd_without_event_remap (struct vm_area_struct *vma) +{ +return false; +} +#endif /* CONFIG_USERFAULTFD */ static inline bool pte_marker_entry_uffd_wp (swp_entry_t entry)
mm/huge_memory.c +12 -0
@@ -1736,6 +1736,16 @@ static pmd_t move_soft_dirty_pmd(pmd_t pmd)return pmd; } +static pmd_t clear_uffd_wp_pmd (pmd_t pmd) +{ +if (pmd_present (pmd)) + pmd =pmd_clear_uffd_wp (pmd); +else if (is_swap_pmd (pmd)) + pmd =pmd_swp_clear_uffd_wp (pmd); + +return pmd; +} +bool move_huge_pmd (struct vm_area_struct *vma,unsigned long old_addr,unsigned long new_addr,pmd_t *old_pmd,pmd_t *new_pmd) {
@@ -1773,6 +1783,8 @@ bool move_huge_pmd(struct vm_area_struct *vma, unsigned long old_addr,pgtable_trans_huge_deposit (mm, new_pmd, pgtable); } pmd =move_soft_dirty_pmd (pmd); +if (vma_has_uffd_without_event_remap (vma)) + pmd =clear_uffd_wp_pmd (pmd);set_pmd_at (mm, new_addr, new_pmd, pmd);if (force_flush)flush_pmd_tlb_range (vma, old_addr, old_addr +PMD_SIZE );
mm/hugetlb.c +13 -1
@@ -5208,6 +5208,7 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,static void move_huge_pte (struct vm_area_struct *vma,unsigned long old_addr,unsigned long new_addr,pte_t *src_pte,pte_t *dst_pte) { +bool need_clear_uffd_wp =vma_has_uffd_without_event_remap (vma);struct hstate *h =hstate_vma (vma);struct mm_struct *mm = vma->vm_mm;spinlock_t *src_ptl, *dst_ptl;
@@ -5224,7 +5225,18 @@ static void move_huge_pte(struct vm_area_struct *vma, unsigned long old_addr,spin_lock_nested (src_ptl,SINGLE_DEPTH_NESTING ); pte =huge_ptep_get_and_clear (mm, old_addr, src_pte); -set_huge_pte_at (mm, new_addr, dst_pte, pte); + +if (need_clear_uffd_wp &&pte_marker_uffd_wp (pte)) +huge_pte_clear (mm, new_addr, dst_pte,huge_page_size (h)); +else { +if (need_clear_uffd_wp) { +if (pte_present (pte)) + pte =huge_pte_clear_uffd_wp (pte); +else if (is_swap_pte (pte)) + pte =pte_swp_clear_uffd_wp (pte); + } +set_huge_pte_at (mm, new_addr, dst_pte, pte); + }if (src_ptl != dst_ptl)spin_unlock (src_ptl);
mm/mremap.c +31 -1
@@ -138,6 +138,7 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd, struct vm_area_struct *new_vma, pmd_t *new_pmd, unsigned long new_addr, bool need_rmap_locks) { + bool need_clear_uffd_wp = vma_has_uffd_without_event_remap(vma);struct mm_struct *mm = vma->vm_mm;pte_t *old_pte, *new_pte, pte;spinlock_t *old_ptl, *new_ptl;
@@ -198,7 +199,18 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd, force_flush = true; pte =move_pte (pte, new_vma->vm_page_prot, old_addr, new_addr); pte =move_soft_dirty_pte (pte); -set_pte_at (mm, new_addr, new_pte, pte); + +if (need_clear_uffd_wp &&pte_marker_uffd_wp (pte)) +pte_clear (mm, new_addr, new_pte); +else { +if (need_clear_uffd_wp) { +if (pte_present (pte)) + pte =pte_clear_uffd_wp (pte); +else if (is_swap_pte (pte)) + pte =pte_swp_clear_uffd_wp (pte); + } +set_pte_at (mm, new_addr, new_pte, pte); + } }arch_leave_lazy_mmu_mode ();
@@ -257,6 +269,15 @@ static bool move_normal_pmd(struct vm_area_struct *vma, unsigned long old_addr,if (WARN_ON_ONCE (!pmd_none (*new_pmd)))return false; +/* If this pmd belongs to a uffd vma with remap events disabled, we need +* to ensure that the uffd-wp state is cleared from all pgtables. This +* means recursing into lower page tables in move_page_tables(), and we +* can reuse the existing code if we simply treat the entry as "not +* moved". +*/ +if (vma_has_uffd_without_event_remap (vma)) +return false; +/* * We don't have to worry about the ordering of src and dst * ptlocks because exclusive mmap_lock prevents deadlock.
@@ -306,6 +327,15 @@ static bool move_normal_pud(struct vm_area_struct *vma, unsigned long old_addr,if (WARN_ON_ONCE (!pud_none (*new_pud)))return false; +/* If this pud belongs to a uffd vma with remap events disabled, we need +* to ensure that the uffd-wp state is cleared from all pgtables. This +* means recursing into lower page tables in move_page_tables(), and we +* can reuse the existing code if we simply treat the entry as "not +* moved". +*/ +if (vma_has_uffd_without_event_remap (vma)) +return false; +/* * We don't have to worry about the ordering of src and dst * ptlocks because exclusive mmap_lock prevents deadlock.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 733/1887 RDMA/mlx5: Fix implicit ODP use after free
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Patrisious Haddad <[email protected]>
[ Upstream commit d3d930411ce390e532470194296658a960887773 ]
Prevent double queueing of implicit ODP mr destroy work by using __xa_cmpxchg() to make sure this is the only time we are destroying this specific mr.
Without this change, we could try to invalidate this mr twice, which in turn could result in queuing a MR work destroy twice, and eventually the second work could execute after the MR was freed due to the first work, causing a user after free and trace below.
refcount_t: underflow; use-after-free.
WARNING: CPU: 2 PID: 12178 at lib/refcount.c:28 refcount_warn_saturate+0x12b/0x130
Modules linked in: bonding ib_ipoib vfio_pci ip_gre geneve nf_tables ip6_gre gre ip6_tunnel tunnel6 ipip tunnel4 ib_umad rdma_ucm mlx5_vfio_pci vfio_pci_core vfio_iommu_type1 mlx5_ib vfio ib_uverbs mlx5_core iptable_raw openvswitch nsh rpcrdma ib_iser libiscsi scsi_transport_iscsi rdma_cm iw_cm ib_cm ib_core xt_conntrack xt_MASQUERADE nf_conntrack_netlink nfnetlink xt_addrtype iptable_nat nf_nat br_netfilter rpcsec_gss_krb5 auth_rpcgss oid_registry overlay zram zsmalloc fuse [last unloaded: ib_uverbs]
CPU: 2 PID: 12178 Comm: kworker/u20:5 Not tainted 6.5.0-rc1_net_next_mlx5_58c644e #1
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.13.0-0-gf21b5a4aeb02-prebuilt.qemu.org 04/01/2014
Workqueue: events_unbound free_implicit_child_mr_work [mlx5_ib]
RIP: 0010:refcount_warn_saturate+0x12b/0x130
Code: 48 c7 c7 38 95 2a 82 c6 05 bc c6 fe 00 01 e8 0c 66 aa ff 0f 0b 5b c3 48 c7 c7 e0 94 2a 82 c6 05 a7 c6 fe 00 01 e8 f5 65 aa ff <0f> 0b 5b c3 90 8b 07 3d 00 00 00 c0 74 12 83 f8 01 74 13 8d 50 ff
RSP: 0018:ffff8881008e3e40 EFLAGS: 00010286
RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000027
RDX: ffff88852c91b5c8 RSI: 0000000000000001 RDI: ffff88852c91b5c0
RBP: ffff8881dacd4e00 R08: 00000000ffffffff R09: 0000000000000019
R10: 000000000000072e R11: 0000000063666572 R12: ffff88812bfd9e00
R13: ffff8881c792d200 R14: ffff88810011c005 R15: ffff8881002099c0
FS: 0000000000000000(0000) GS:ffff88852c900000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f5694b5e000 CR3: 00000001153f6003 CR4: 0000000000370ea0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
Call Trace:
<TASK>
? refcount_warn_saturate+0x12b/0x130
free_implicit_child_mr_work+0x180/0x1b0 [mlx5_ib]
process_one_work+0x1cc/0x3c0
worker_thread+0x218/0x3c0
kthread+0xc6/0xf0
ret_from_fork+0x1f/0x30
</TASK>--- drivers/infiniband/hw/mlx5/odp.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
drivers/infiniband/hw/mlx5/odp.c +15 -1
@@ -213,10 +213,24 @@ static void destroy_unused_implicit_child_mr(struct mlx5_ib_mr *mr)unsigned long idx =ib_umem_start (odp) >>MLX5_IMR_MTT_SHIFT ;struct mlx5_ib_mr *imr = mr->parent; +/* +* If userspace is racing freeing the parent implicit ODP MR then we can +* loose the race with parent destruction. In this case +* mlx5_ib_free_odp_mr() will free everything in the implicit_children +* xarray so NOP is fine. This child MR cannot be destroyed here because +* we are under its umem_mutex. +*/ if (!refcount_inc_not_zero (&imr->mmkey.usecount))return ; -xa_erase (&imr->implicit_children, idx); +xa_lock (&imr->implicit_children); +if (__xa_cmpxchg (&imr->implicit_children, idx, mr,NULL ,GFP_KERNEL ) != + mr) { +xa_unlock (&imr->implicit_children); +return ; + } + +xa_unlock (&imr->implicit_children);/* Freeing a MR is a sleeping operation, so bounce to a work queue */ INIT_WORK (&mr->odp_destroy.work, free_implicit_child_mr_work);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 734/1887 scsi: mpi3mr: Fix possible crash when setting up bsg fails
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guixin Liu <[email protected]>
[ Upstream commit 295006f6e8c17212d3098811166e29627d19e05c ]
If bsg_setup_queue() fails, the bsg_queue is assigned a non-NULL value. Consequently, in mpi3mr_bsg_exit(), the condition "if(!mrioc->bsg_queue)" will not be satisfied, preventing execution from entering bsg_remove_queue(), which could lead to the following crash:
BUG: kernel NULL pointer dereference, address: 000000000000041c Call Trace: <TASK> mpi3mr_bsg_exit+0x1f/0x50 [mpi3mr] mpi3mr_remove+0x6f/0x340 [mpi3mr] pci_device_remove+0x3f/0xb0 device_release_driver_internal+0x19d/0x220 unbind_store+0xa4/0xb0 kernfs_fop_write_iter+0x11f/0x200 vfs_write+0x1fc/0x3e0 ksys_write+0x67/0xe0 do_syscall_64+0x38/0x80 entry_SYSCALL_64_after_hwframe+0x78/0xe2
--- drivers/scsi/mpi3mr/mpi3mr_app.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
drivers/scsi/mpi3mr/mpi3mr_app.c +7 -4
@@ -1531,6 +1531,7 @@ void mpi3mr_bsg_init(struct mpi3mr_ioc *mrioc) {struct device *bsg_dev = &mrioc->bsg_dev;struct device *parent = &mrioc->shost->shost_gendev; +struct request_queue *q;device_initialize (bsg_dev);
@@ -1546,9 +1547,9 @@ void mpi3mr_bsg_init(struct mpi3mr_ioc *mrioc)return ; } - mrioc->bsg_queue =bsg_setup_queue (bsg_dev,dev_name (bsg_dev), + q =bsg_setup_queue (bsg_dev,dev_name (bsg_dev), mpi3mr_bsg_request,NULL ,0 ); -if (IS_ERR (mrioc->bsg_queue)) { +if (IS_ERR (q)) {ioc_err (mrioc,"%s: bsg registration failed\n" ,dev_name (bsg_dev));device_del (bsg_dev);
@@ -1556,8 +1557,10 @@ void mpi3mr_bsg_init(struct mpi3mr_ioc *mrioc)return ; } -blk_queue_max_segments (mrioc->bsg_queue,MPI3MR_MAX_APP_XFER_SEGMENTS ); -blk_queue_max_hw_sectors (mrioc->bsg_queue,MPI3MR_MAX_APP_XFER_SECTORS ); + mrioc->bsg_queue = q; + +blk_queue_max_segments (q,MPI3MR_MAX_APP_XFER_SEGMENTS ); +blk_queue_max_hw_sectors (q,MPI3MR_MAX_APP_XFER_SECTORS );return ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 735/1887 wifi: rtw89: fix race between cancel_hw_scan and hw_scan completion
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ping-Ke Shih <[email protected]>
[ Upstream commit ba4bb0402c60e945c4c396c51f0acac3c3e3ea5c ]
The rtwdev->scanning flag isn't protected by mutex originally, so cancel_hw_scan can pass the condition, but suddenly hw_scan completion unset the flag and calls ieee80211_scan_completed() that will free local->hw_scan_req. Then, cancel_hw_scan raises null-ptr-deref and use-after-free. Fix it by moving the check condition to where protected by mutex.
KASAN: null-ptr-deref in range [0x0000000000000088-0x000000000000008f] CPU: 2 PID: 6922 Comm: kworker/2:2 Tainted: G OE Hardware name: LENOVO 2356AD1/2356AD1, BIOS G7ETB6WW (2.76 ) 09/10/2019 Workqueue: events cfg80211_conn_work [cfg80211] RIP: 0010:rtw89_fw_h2c_scan_offload_be+0xc33/0x13c3 [rtw89_core] Code: 00 45 89 6c 24 1c 0f 85 23 01 00 00 48 8b 85 20 ff ff ff 48 8d RSP: 0018:ffff88811fd9f068 EFLAGS: 00010206 RAX: dffffc0000000000 RBX: ffff88811fd9f258 RCX: 0000000000000001 RDX: 0000000000000011 RSI: 0000000000000001 RDI: 0000000000000089 RBP: ffff88811fd9f170 R08: 0000000000000000 R09: 0000000000000000 R10: ffff88811fd9f108 R11: 0000000000000000 R12: ffff88810e47f960 R13: 0000000000000000 R14: 000000000000ffff R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffff8881d6f00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007531dfca55b0 CR3: 00000001be296004 CR4: 00000000001706e0 Call Trace: <TASK> ? show_regs+0x61/0x73 ? __die_body+0x20/0x73 ? die_addr+0x4f/0x7b ? exc_general_protection+0x191/0x1db ? asm_exc_general_protection+0x27/0x30 ? rtw89_fw_h2c_scan_offload_be+0xc33/0x13c3 [rtw89_core] ? rtw89_fw_h2c_scan_offload_be+0x458/0x13c3 [rtw89_core] ? __pfx_rtw89_fw_h2c_scan_offload_be+0x10/0x10 [rtw89_core] ? do_raw_spin_lock+0x75/0xdb ? __pfx_do_raw_spin_lock+0x10/0x10 rtw89_hw_scan_offload+0xb5e/0xbf7 [rtw89_core] ? _raw_spin_unlock+0xe/0x24 ? __mutex_lock.constprop.0+0x40c/0x471 ? __pfx_rtw89_hw_scan_offload+0x10/0x10 [rtw89_core] ? __mutex_lock_slowpath+0x13/0x1f ? mutex_lock+0xa2/0xdc ? __pfx_mutex_lock+0x10/0x10 rtw89_hw_scan_abort+0x58/0xb7 [rtw89_core] rtw89_ops_cancel_hw_scan+0x120/0x13b [rtw89_core] ieee80211_scan_cancel+0x468/0x4d0 [mac80211] ieee80211_prep_connection+0x858/0x899 [mac80211] ieee80211_mgd_auth+0xbea/0xdde [mac80211] ? __pfx_ieee80211_mgd_auth+0x10/0x10 [mac80211] ? cfg80211_find_elem+0x15/0x29 [cfg80211] ? is_bss+0x1b7/0x1d7 [cfg80211] ieee80211_auth+0x18/0x27 [mac80211] cfg80211_mlme_auth+0x3bb/0x3e7 [cfg80211] cfg80211_conn_do_work+0x410/0xb81 [cfg80211] ? __pfx_cfg80211_conn_do_work+0x10/0x10 [cfg80211] ? __kasan_check_read+0x11/0x1f ? psi_group_change+0x8bc/0x944 ? __kasan_check_write+0x14/0x22 ? mutex_lock+0x8e/0xdc ? __pfx_mutex_lock+0x10/0x10 ? __pfx___radix_tree_lookup+0x10/0x10 cfg80211_conn_work+0x245/0x34d [cfg80211] ? __pfx_cfg80211_conn_work+0x10/0x10 [cfg80211] ? update_cfs_rq_load_avg+0x3bc/0x3d7 ? sched_clock_noinstr+0x9/0x1a ? sched_clock+0x10/0x24 ? sched_clock_cpu+0x7e/0x42e ? newidle_balance+0x796/0x937 ? __pfx_sched_clock_cpu+0x10/0x10 ? __pfx_newidle_balance+0x10/0x10 ? __kasan_check_read+0x11/0x1f ? psi_group_change+0x8bc/0x944 ? _raw_spin_unlock+0xe/0x24 ? raw_spin_rq_unlock+0x47/0x54 ? raw_spin_rq_unlock_irq+0x9/0x1f ? finish_task_switch.isra.0+0x347/0x586 ? __schedule+0x27bf/0x2892 ? mutex_unlock+0x80/0xd0 ? do_raw_spin_lock+0x75/0xdb ? __pfx___schedule+0x10/0x10 process_scheduled_works+0x58c/0x821 worker_thread+0x4c7/0x586 ? __kasan_check_read+0x11/0x1f kthread+0x285/0x294 ? __pfx_worker_thread+0x10/0x10 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x29/0x6f ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1b/0x30 </TASK>
--- drivers/net/wireless/realtek/rtw89/mac80211.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/net/wireless/realtek/rtw89/mac80211.c +5 -2
@@ -808,11 +808,14 @@ static void rtw89_ops_cancel_hw_scan(struct ieee80211_hw *hw,if (!RTW89_CHK_FW_FEATURE (SCAN_OFFLOAD , &rtwdev->fw))return ; +mutex_lock (&rtwdev->mutex); +if (!rtwdev->scanning) -return ; + goto out; -mutex_lock (&rtwdev->mutex);rtw89_hw_scan_abort (rtwdev, vif); + +out:mutex_unlock (&rtwdev->mutex); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 736/1887 RDMA/mlx5: Fix a race for an ODP MR which leads to CQE with error
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yishai Hadas <[email protected]>
[ Upstream commit abb604a1a9c87255c7a6f3b784410a9707baf467 ]
This patch addresses a race condition for an ODP MR that can result in a CQE with an error on the UMR QP.
During the __mlx5_ib_dereg_mr() flow, the following sequence of calls occurs:
mlx5_revoke_mr()
mlx5r_umr_revoke_mr()
mlx5r_umr_post_send_wait()
At this point, the lkey is freed from the hardware's perspective.
However, concurrently, mlx5_ib_invalidate_range() might be triggered by another task attempting to invalidate a range for the same freed lkey.
This task will:
- Acquire the umem_odp->umem_mutex lock.
- Call mlx5r_umr_update_xlt() on the UMR QP.
- Since the lkey has already been freed, this can lead to a CQE error, causing the UMR QP to enter an error state [1].
To resolve this race condition, the umem_odp->umem_mutex lock is now also acquired as part of the mlx5_revoke_mr() scope. Upon successful revoke, we set umem_odp->private which points to that MR to NULL, preventing any further invalidation attempts on its lkey.
[1] From dmesg:
infiniband rocep8s0f0: dump_cqe:277:(pid 0): WC error: 6, Message: memory bind operation error
cqe_dump: 00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
cqe_dump: 00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
cqe_dump: 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
cqe_dump: 00000030: 00 00 00 00 08 00 78 06 25 00 11 b9 00 0e dd d2
WARNING: CPU: 15 PID: 1506 at drivers/infiniband/hw/mlx5/umr.c:394 mlx5r_umr_post_send_wait+0x15a/0x2b0 [mlx5_ib] Modules linked in: ip6table_mangle ip6table_natip6table_filter ip6_tables iptable_mangle xt_conntrack xt_MASQUERADE nf_conntrack_netlink nfnetlink xt_addrtype iptable_nat nf_nat br_netfilter rpcsec_gss_krb5 auth_rpcgss oid_registry overlay rpcrdma rdma_ucm ib_iser libiscsi scsi_transport_iscsi rdma_cm iw_cm ib_umad ib_ipoib ib_cm mlx5_ib ib_uverbs ib_core fuse mlx5_core CPU: 15 UID: 0 PID: 1506 Comm: ibv_rc_pingpong Not tainted 6.12.0-rc7+ #1626 Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.13.0-0-gf21b5a4aeb02-prebuilt.qemu.org 04/01/2014 RIP: 0010:mlx5r_umr_post_send_wait+0x15a/0x2b0 [mlx5_ib] [..] Call Trace: <TASK> mlx5r_umr_update_xlt+0x23c/0x3e0 [mlx5_ib] mlx5_ib_invalidate_range+0x2e1/0x330 [mlx5_ib] __mmu_notifier_invalidate_range_start+0x1e1/0x240 zap_page_range_single+0xf1/0x1a0 madvise_vma_behavior+0x677/0x6e0 do_madvise+0x1a2/0x4b0 __x64_sys_madvise+0x25/0x30 do_syscall_64+0x6b/0x140 entry_SYSCALL_64_after_hwframe+0x76/0x7e
--- drivers/infiniband/hw/mlx5/mr.c | 31 +++++++++++++++++++++++++------ drivers/infiniband/hw/mlx5/odp.c | 2 ++ 2 files changed, 27 insertions(+), 6 deletions(-)
drivers/infiniband/hw/mlx5/mr.c +25 -6
@@ -1587,6 +1587,8 @@ int mlx5_ib_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata) {struct mlx5_ib_mr *mr =to_mmr (ibmr);struct mlx5_ib_dev *dev =to_mdev (ibmr->device); +bool is_odp =is_odp_mr (mr); +bool odp_locked = is_odp;int rc;/*
@@ -1628,25 +1630,42 @@ int mlx5_ib_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata) }/* Stop DMA */ +if (odp_locked) +mutex_lock (&to_ib_umem_odp (mr->umem)->umem_mutex); +if (mr->mmkey.cache_ent) {xa_lock_irq (&mr->mmkey.cache_ent->mkeys); mr->mmkey.cache_ent->in_use--;xa_unlock_irq (&mr->mmkey.cache_ent->mkeys); -if (mlx5r_umr_revoke_mr (mr) || -push_mkey (mr->mmkey.cache_ent, false, -xa_mk_value (mr->mmkey.key))) +if (mlx5r_umr_revoke_mr (mr)) { mr->mmkey.cache_ent =NULL ; + }else { +if (odp_locked) { +to_ib_umem_odp (mr->umem)->private =NULL ; +mutex_unlock (&to_ib_umem_odp (mr->umem)->umem_mutex); + odp_locked = false; + } +if (push_mkey (mr->mmkey.cache_ent, false, +xa_mk_value (mr->mmkey.key))) + mr->mmkey.cache_ent =NULL ; + } }if (!mr->mmkey.cache_ent) { rc =destroy_mkey (to_mdev (mr->ibmr.device), mr); -if (rc) +if (rc) { +if (odp_locked) +mutex_unlock (&to_ib_umem_odp (mr->umem)->umem_mutex);return rc; + } } -if (mr->umem) { -bool is_odp =is_odp_mr (mr); +if (odp_locked) { +to_ib_umem_odp (mr->umem)->private =NULL ; +mutex_unlock (&to_ib_umem_odp (mr->umem)->umem_mutex); + } +if (mr->umem) {if (!is_odp)atomic_sub (ib_umem_num_pages (mr->umem), &dev->mdev->priv.reg_pages);
drivers/infiniband/hw/mlx5/odp.c +2 -0
@@ -265,6 +265,8 @@ static bool mlx5_ib_invalidate_range(struct mmu_interval_notifier *mni,if (!umem_odp->npages) goto out; mr = umem_odp->private; +if (!mr) + goto out; start =max_t (u64,ib_umem_start (umem_odp), range->start); end =min_t (u64,ib_umem_end (umem_odp), range->end);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 737/1887 net: ipv6: fix dst ref loops in rpl, seg6 and ioam6 lwtunnels
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jakub Kicinski <[email protected]>
[ Upstream commit 92191dd1073088753821b862b791dcc83e558e07 ]
Some lwtunnels have a dst cache for post-transformation dst. If the packet destination did not change we may end up recording a reference to the lwtunnel in its own cache, and the lwtunnel state will never be freed.
Discovered by the ioam6.sh test, kmemleak was recently fixed to catch per-cpu memory leaks. I'm not sure if rpl and seg6 can actually hit this, but in principle I don't see why not.
--- net/ipv6/ioam6_iptunnel.c | 9 ++++++--- net/ipv6/rpl_iptunnel.c | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-)
net/ipv6/ioam6_iptunnel.c +6 -3
@@ -365,9 +365,12 @@ static int ioam6_output(struct net *net, struct sock *sk, struct sk_buff *skb) goto drop; } -local_bh_disable (); -dst_cache_set_ip6 (&ilwt->cache, dst, &fl6.saddr); -local_bh_enable (); +/* cache only if we don't create a dst reference loop */ +if (skb_dst (skb)->lwtstate != dst->lwtstate) { +local_bh_disable (); +dst_cache_set_ip6 (&ilwt->cache, dst, &fl6.saddr); +local_bh_enable (); + } }skb_dst_drop (skb);
net/ipv6/rpl_iptunnel.c +6 -3
@@ -236,9 +236,12 @@ static int rpl_output(struct net *net, struct sock *sk, struct sk_buff *skb) goto drop; } -local_bh_disable (); -dst_cache_set_ip6 (&rlwt->cache, dst, &fl6.saddr); -local_bh_enable (); +/* cache only if we don't create a dst reference loop */ +if (orig_dst->lwtstate != dst->lwtstate) { +local_bh_disable (); +dst_cache_set_ip6 (&rlwt->cache, dst, &fl6.saddr); +local_bh_enable (); + } err =skb_cow_head (skb,LL_RESERVED_SPACE (dst->dev));if (unlikely (err))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 738/1887 net: ravb: Fix missing rtnl lock in suspend/resume path
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kory Maincent <[email protected]>
[ Upstream commit 2c2ebb2b49573e5f8726112ad06b1dffc3c9ea03 ]
Fix the suspend/resume path by ensuring the rtnl lock is held where required. Calls to ravb_open, ravb_close and wol operations must be performed under the rtnl lock to prevent conflicts with ongoing ndo operations.
Without this fix, the following warning is triggered:
[ 39.032969] ============================= [ 39.032983] WARNING: suspicious RCU usage [ 39.033019] ----------------------------- [ 39.033033] drivers/net/phy/phy_device.c:2004 suspicious rcu_dereference_protected() usage! ... [ 39.033597] stack backtrace: [ 39.033613] CPU: 0 UID: 0 PID: 174 Comm: python3 Not tainted 6.13.0-rc7-next-20250116-arm64-renesas-00002-g35245dfdc62c #7 [ 39.033623] Hardware name: Renesas SMARC EVK version 2 based on r9a08g045s33 (DT) [ 39.033628] Call trace: [ 39.033633] show_stack+0x14/0x1c (C) [ 39.033652] dump_stack_lvl+0xb4/0xc4 [ 39.033664] dump_stack+0x14/0x1c [ 39.033671] lockdep_rcu_suspicious+0x16c/0x22c [ 39.033682] phy_detach+0x160/0x190 [ 39.033694] phy_disconnect+0x40/0x54 [ 39.033703] ravb_close+0x6c/0x1cc [ 39.033714] ravb_suspend+0x48/0x120 [ 39.033721] dpm_run_callback+0x4c/0x14c [ 39.033731] device_suspend+0x11c/0x4dc [ 39.033740] dpm_suspend+0xdc/0x214 [ 39.033748] dpm_suspend_start+0x48/0x60 [ 39.033758] suspend_devices_and_enter+0x124/0x574 [ 39.033769] pm_suspend+0x1ac/0x274 [ 39.033778] state_store+0x88/0x124 [ 39.033788] kobj_attr_store+0x14/0x24 [ 39.033798] sysfs_kf_write+0x48/0x6c [ 39.033808] kernfs_fop_write_iter+0x118/0x1a8 [ 39.033817] vfs_write+0x27c/0x378 [ 39.033825] ksys_write+0x64/0xf4 [ 39.033833] __arm64_sys_write+0x18/0x20 [ 39.033841] invoke_syscall+0x44/0x104 [ 39.033852] el0_svc_common.constprop.0+0xb4/0xd4 [ 39.033862] do_el0_svc+0x18/0x20 [ 39.033870] el0_svc+0x3c/0xf0 [ 39.033880] el0t_64_sync_handler+0xc0/0xc4 [ 39.033888] el0t_64_sync+0x154/0x158 [ 39.041274] ravb 11c30000.ethernet eth0: Link is Down
--- drivers/net/ethernet/renesas/ravb_main.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/net/ethernet/renesas/ravb_main.c +7 -1
@@ -3028,10 +3028,12 @@ static int __maybe_unused ravb_suspend(struct device *dev)netif_device_detach (ndev); +rtnl_lock ();if (priv->wol_enabled) ret =ravb_wol_setup (ndev);else ret =ravb_close (ndev); +rtnl_unlock ();if (priv->info->ccc_gac)ravb_ptp_stop (ndev);
@@ -3083,12 +3085,16 @@ static int __maybe_unused ravb_resume(struct device *dev)ravb_ptp_init (ndev, priv->pdev);if (netif_running (ndev)) { +rtnl_lock ();if (priv->wol_enabled) { ret =ravb_wol_restore (ndev); -if (ret) +if (ret) { +rtnl_unlock ();return ret; + } } ret =ravb_open (ndev); +rtnl_unlock ();if (ret <0 )return ret;ravb_set_rx_mode (ndev);
Signature · 1 line
2.53.0