6.6.148-rc1 review
Greg Kroah-Hartman
maintainerPATCH 401/484 ASoC: mediatek: Use common mtk_afe_pcm_platform with common probe cb
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: AngeloGioacchino Del Regno <[email protected]>
[ Upstream commit 1d2a6b3b5189b6c3e51f29e050aa9b2337b774e8 ]
Since the mtk-afe-platform-driver generic mtk_afe_pcm_platform now has a common .probe() callback, there is no reason to keep duplicating this function over and over in the SoC specific AFE-PCM drivers: switch over to register with the common bits instead.
Note that MT8186 was left out of this because it is registering some extra sinegen controls in the AFE-PCM probe callback and needs extra cleanups to be able to use the common bits.
Stable-dep-of: e24d5dde56a5 ("ASoC: mediatek: mt8192: Check runtime resume during probe")
--- sound/soc/mediatek/mt6797/mt6797-afe-pcm.c | 14 +------------- sound/soc/mediatek/mt7986/mt7986-afe-pcm.c | 14 +------------- sound/soc/mediatek/mt8183/mt8183-afe-pcm.c | 14 +------------- sound/soc/mediatek/mt8188/mt8188-afe-pcm.c | 21 +-------------------- sound/soc/mediatek/mt8192/mt8192-afe-pcm.c | 25 ++----------------------- sound/soc/mediatek/mt8195/mt8195-afe-pcm.c | 21 +-------------------- 6 files changed, 7 insertions(+), 102 deletions(-)
sound/soc/mediatek/mt6797/mt6797-afe-pcm.c +1 -13
@@ -704,18 +704,6 @@ static int mt6797_afe_runtime_resume(strreturn 0 ; } -static int mt6797_afe_component_probe (struct snd_soc_component *component) -{ -return mtk_afe_add_sub_dai_control (component); -} - -static const struct snd_soc_component_driver mt6797_afe_component = { - .name =AFE_PCM_NAME , - .probe = mt6797_afe_component_probe, - .pointer = mtk_afe_pcm_pointer, - .pcm_construct = mtk_afe_pcm_new, -}; -static int mt6797_dai_memif_register (struct mtk_base_afe *afe) {struct mtk_base_afe_dai *dai;
@@ -852,7 +840,7 @@ static int mt6797_afe_pcm_dev_probe(strupm_runtime_get_sync (&pdev->dev);/* register component */ - ret =devm_snd_soc_register_component (dev, &mt6797_afe_component, + ret =devm_snd_soc_register_component (dev, &mtk_afe_pcm_platform,NULL ,0 );if (ret) {dev_warn (dev,"err_platform\n" );
sound/soc/mediatek/mt7986/mt7986-afe-pcm.c +1 -13
@@ -429,18 +429,6 @@ static int mt7986_afe_runtime_resume(strreturn 0 ; } -static int mt7986_afe_component_probe (struct snd_soc_component *component) -{ -return mtk_afe_add_sub_dai_control (component); -} - -static const struct snd_soc_component_driver mt7986_afe_component = { - .name =AFE_PCM_NAME , - .probe = mt7986_afe_component_probe, - .pointer = mtk_afe_pcm_pointer, - .pcm_construct = mtk_afe_pcm_new, -}; -static int mt7986_dai_memif_register (struct mtk_base_afe *afe) {struct mtk_base_afe_dai *dai;
@@ -573,7 +561,7 @@ static int mt7986_afe_pcm_dev_probe(stru/* register component */ ret =devm_snd_soc_register_component (&pdev->dev, - &mt7986_afe_component, + &mtk_afe_pcm_platform,NULL ,0 );if (ret)return dev_err_probe (dev, ret,"Cannot register AFE component\n" );
sound/soc/mediatek/mt8183/mt8183-afe-pcm.c +1 -13
@@ -1043,18 +1043,6 @@ skip_regmap:return 0 ; } -static int mt8183_afe_component_probe (struct snd_soc_component *component) -{ -return mtk_afe_add_sub_dai_control (component); -} - -static const struct snd_soc_component_driver mt8183_afe_component = { - .name =AFE_PCM_NAME , - .probe = mt8183_afe_component_probe, - .pointer = mtk_afe_pcm_pointer, - .pcm_construct = mtk_afe_pcm_new, -}; -static int mt8183_dai_memif_register (struct mtk_base_afe *afe) {struct mtk_base_afe_dai *dai;
@@ -1250,7 +1238,7 @@ static int mt8183_afe_pcm_dev_probe(stru/* register component */ ret =devm_snd_soc_register_component (&pdev->dev, - &mt8183_afe_component, + &mtk_afe_pcm_platform,NULL ,0 );if (ret) {dev_warn (dev,"err_platform\n" );
sound/soc/mediatek/mt8188/mt8188-afe-pcm.c +1 -20
@@ -3027,25 +3027,6 @@ skip_regmap:return 0 ; } -static int mt8188_afe_component_probe (struct snd_soc_component *component) -{ -struct mtk_base_afe *afe =snd_soc_component_get_drvdata (component); -int ret; - -snd_soc_component_init_regmap (component, afe->regmap); - - ret =mtk_afe_add_sub_dai_control (component); - -return ret; -} - -static const struct snd_soc_component_driver mt8188_afe_component = { - .name =AFE_PCM_NAME , - .pointer = mtk_afe_pcm_pointer, - .pcm_construct = mtk_afe_pcm_new, - .probe = mt8188_afe_component_probe, -}; -static int init_memif_priv_data (struct mtk_base_afe *afe) {struct mt8188_afe_private *afe_priv = afe->platform_priv;
@@ -3347,7 +3328,7 @@ static int mt8188_afe_pcm_dev_probe(stru }/* register component */ - ret =devm_snd_soc_register_component (dev, &mt8188_afe_component, + ret =devm_snd_soc_register_component (dev, &mtk_afe_pcm_platform, afe->dai_drivers, afe->num_dai_drivers);if (ret) {dev_warn (dev,"err_platform\n" );
sound/soc/mediatek/mt8192/mt8192-afe-pcm.c +2 -23
@@ -2126,22 +2126,6 @@ skip_regmap:return 0 ; } -static int mt8192_afe_component_probe (struct snd_soc_component *component) -{ -return mtk_afe_add_sub_dai_control (component); -} - -static const struct snd_soc_component_driver mt8192_afe_component = { - .name =AFE_PCM_NAME , - .probe = mt8192_afe_component_probe, - .pointer = mtk_afe_pcm_pointer, - .pcm_construct = mtk_afe_pcm_new, -}; - -static const struct snd_soc_component_driver mt8192_afe_pcm_component = { - .name ="mt8192-afe-pcm-dai" , -}; -static int mt8192_dai_memif_register (struct mtk_base_afe *afe) {struct mtk_base_afe_dai *dai;
@@ -2318,16 +2302,11 @@ static int mt8192_afe_pcm_dev_probe(stru/* register platform */ ret =devm_snd_soc_register_component (&pdev->dev, - &mt8192_afe_component,NULL ,0 ); -if (ret) -return dev_err_probe (dev, ret,"Couldn't register AFE component\n" ); - - ret =devm_snd_soc_register_component (&pdev->dev, - &mt8192_afe_pcm_component, + &mtk_afe_pcm_platform, afe->dai_drivers, afe->num_dai_drivers);if (ret) -return dev_err_probe (dev, ret,"Couldn't register AFE-PCM component\n" ); +return dev_err_probe (dev, ret,"Couldn't register AFE component\n" );return 0 ; }
sound/soc/mediatek/mt8195/mt8195-afe-pcm.c +1 -20
@@ -2944,25 +2944,6 @@ skip_regmap:return 0 ; } -static int mt8195_afe_component_probe (struct snd_soc_component *component) -{ -struct mtk_base_afe *afe =snd_soc_component_get_drvdata (component); -int ret =0 ; - -snd_soc_component_init_regmap (component, afe->regmap); - - ret =mtk_afe_add_sub_dai_control (component); - -return ret; -} - -static const struct snd_soc_component_driver mt8195_afe_component = { - .name =AFE_PCM_NAME , - .pointer = mtk_afe_pcm_pointer, - .pcm_construct = mtk_afe_pcm_new, - .probe = mt8195_afe_component_probe, -}; -static int init_memif_priv_data (struct mtk_base_afe *afe) {struct mt8195_afe_private *afe_priv = afe->platform_priv;
@@ -3164,7 +3145,7 @@ static int mt8195_afe_pcm_dev_probe(stru }/* register component */ - ret =devm_snd_soc_register_component (dev, &mt8195_afe_component, + ret =devm_snd_soc_register_component (dev, &mtk_afe_pcm_platform, afe->dai_drivers, afe->num_dai_drivers);if (ret) {dev_warn (dev,"err_platform\n" );
Greg Kroah-Hartman
maintainerPATCH 402/484 ASoC: mediatek: mt8192-afe-pcm: Simplify probe() with local dev variable
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tang Bin <[email protected]>
[ Upstream commit 01981565c764c554cc96e2d30a71c42975171416 ]
Simplify the function mt8192_afe_pcm_dev_probe() by using local 'dev' instead of '&pdev->dev'.
Stable-dep-of: e24d5dde56a5 ("ASoC: mediatek: mt8192: Check runtime resume during probe")
--- sound/soc/mediatek/mt8192/mt8192-afe-pcm.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-)
sound/soc/mediatek/mt8192/mt8192-afe-pcm.c +9 -10
@@ -2164,27 +2164,26 @@ static int mt8192_afe_pcm_dev_probe(stru {struct mtk_base_afe *afe;struct mt8192_afe_private *afe_priv; -struct device *dev; +struct device *dev = &pdev->dev;struct reset_control *rstc;int i, ret, irq_id; - ret =dma_set_mask_and_coherent (&pdev->dev,DMA_BIT_MASK (34 )); + ret =dma_set_mask_and_coherent (dev,DMA_BIT_MASK (34 ));if (ret)return ret; - afe =devm_kzalloc (&pdev->dev,sizeof (*afe),GFP_KERNEL ); + afe =devm_kzalloc (dev,sizeof (*afe),GFP_KERNEL );if (!afe)return -ENOMEM ;platform_set_drvdata (pdev, afe); - afe->platform_priv =devm_kzalloc (&pdev->dev,sizeof (*afe_priv), + afe->platform_priv =devm_kzalloc (dev,sizeof (*afe_priv),GFP_KERNEL );if (!afe->platform_priv)return -ENOMEM ; afe_priv = afe->platform_priv; - afe->dev = &pdev->dev; - dev = afe->dev; + afe->dev = dev; ret =of_reserved_mem_device_init (dev);if (ret) {
@@ -2212,7 +2211,7 @@ static int mt8192_afe_pcm_dev_probe(struif (ret)return dev_err_probe (dev, ret,"failed to trigger audio reset\n" ); - ret =devm_pm_runtime_enable (&pdev->dev); + ret =devm_pm_runtime_enable (dev);if (ret)return ret;
@@ -2228,13 +2227,13 @@ static int mt8192_afe_pcm_dev_probe(stru/* enable clock for regcache get default value from hw */ afe_priv->pm_runtime_bypass_reg_ctl = true; -pm_runtime_get_sync (&pdev->dev); +pm_runtime_get_sync (dev); ret =regmap_reinit_cache (afe->regmap, &mt8192_afe_regmap_config);if (ret)return dev_err_probe (dev, ret,"regmap_reinit_cache fail\n" ); -pm_runtime_put_sync (&pdev->dev); +pm_runtime_put_sync (dev); afe_priv->pm_runtime_bypass_reg_ctl = false;regcache_cache_only (afe->regmap, true);
@@ -2301,7 +2300,7 @@ static int mt8192_afe_pcm_dev_probe(stru afe->runtime_suspend = mt8192_afe_runtime_suspend;/* register platform */ - ret =devm_snd_soc_register_component (&pdev->dev, + ret =devm_snd_soc_register_component (dev, &mtk_afe_pcm_platform, afe->dai_drivers, afe->num_dai_drivers);
Greg Kroah-Hartman
maintainerPATCH 403/484 ASoC: mediatek: mt8192: Check runtime resume during probe
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cássio Gabriel <[email protected]>
[ Upstream commit e24d5dde56a50946020b134fa8448869093db76a ]
The MT8192 AFE probe enables runtime PM temporarily while reinitializing the regmap cache from hardware, but it uses pm_runtime_get_sync() without checking the return value. If runtime resume fails, probe keeps going without the device necessarily being accessible, and pm_runtime_get_sync() may leave the PM usage count incremented.
The regmap_reinit_cache() failure path also returns before dropping the temporary PM reference and before clearing pm_runtime_bypass_reg_ctl.
Use pm_runtime_resume_and_get() so resume failures do not leak a usage count, and clear the temporary bypass flag after dropping the probe PM reference on all regmap_reinit_cache() outcomes.
--- sound/soc/mediatek/mt8192/mt8192-afe-pcm.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
sound/soc/mediatek/mt8192/mt8192-afe-pcm.c +8 -4
@@ -2227,15 +2227,19 @@ static int mt8192_afe_pcm_dev_probe(stru/* enable clock for regcache get default value from hw */ afe_priv->pm_runtime_bypass_reg_ctl = true; -pm_runtime_get_sync (dev); + ret =pm_runtime_resume_and_get (dev); +if (ret) { + afe_priv->pm_runtime_bypass_reg_ctl = false; +return dev_err_probe (dev, ret,"failed to resume device\n" ); + } ret =regmap_reinit_cache (afe->regmap, &mt8192_afe_regmap_config); -if (ret) -return dev_err_probe (dev, ret,"regmap_reinit_cache fail\n" ); -pm_runtime_put_sync (dev); afe_priv->pm_runtime_bypass_reg_ctl = false; +if (ret) +return dev_err_probe (dev, ret,"regmap_reinit_cache fail\n" ); +regcache_cache_only (afe->regmap, true);regcache_mark_dirty (afe->regmap);
Greg Kroah-Hartman
maintainerPATCH 404/484 ASoC: mediatek: mt8183: Check runtime resume during probe
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cássio Gabriel <[email protected]>
[ Upstream commit f0334fbfd107682d0c95f3f71e25f6127038e2b9 ]
The MT8183 AFE probe uses pm_runtime_get_sync() before reading hardware defaults into the regmap cache, but does not check whether runtime resume failed. If regmap_reinit_cache() then fails, the temporary runtime PM usage count is also not released.
Use pm_runtime_resume_and_get() so resume failures abort probe without leaking a usage count, and release the temporary reference before handling the regmap cache result.
--- sound/soc/mediatek/mt8183/mt8183-afe-pcm.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
sound/soc/mediatek/mt8183/mt8183-afe-pcm.c +8 -4
@@ -1149,17 +1149,21 @@ static int mt8183_afe_pcm_dev_probe(stru/* enable clock for regcache get default value from hw */ afe_priv->pm_runtime_bypass_reg_ctl = true; -pm_runtime_get_sync (&pdev->dev); + ret =pm_runtime_resume_and_get (dev); +if (ret) { + afe_priv->pm_runtime_bypass_reg_ctl = false; + goto err_pm_disable; + } ret =regmap_reinit_cache (afe->regmap, &mt8183_afe_regmap_config); +pm_runtime_put_sync (dev); + afe_priv->pm_runtime_bypass_reg_ctl = false; +if (ret) {dev_err (dev,"regmap_reinit_cache fail, ret %d\n" , ret); goto err_pm_disable; } -pm_runtime_put_sync (&pdev->dev); - afe_priv->pm_runtime_bypass_reg_ctl = false; -regcache_cache_only (afe->regmap, true);regcache_mark_dirty (afe->regmap);
Greg Kroah-Hartman
maintainerPATCH 405/484 netfilter: nft_set_pipapo: use GFP_KERNEL for insertions
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit 5b651783d80b97167ecd27dc6a4408c694873902 ]
An earlier attempt changed this to GFP_KERNEL, but the get helper is also called for get requests from userspace, which uses rcu.
Let the caller pass in the kmalloc flags to allow insertions to schedule if needed.
Stable-dep-of: 47e65eff5069 ("netfilter: nft_set_pipapo: don't leak bad clone into future transaction")
--- net/netfilter/nft_set_pipapo.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-)
net/netfilter/nft_set_pipapo.c +10 -7
@@ -505,6 +505,7 @@ out:* @data: Key data to be matched against existing elements * @genmask: If set, check that element is active in given genmask * @tstamp: timestamp to check for expired elements +* @gfp: the type of memory to allocate (see kmalloc). * * This is essentially the same as the lookup function, except that it matches * key data against the uncommitted copy and doesn't use preallocated maps for
@@ -515,7 +516,7 @@ out:static struct nft_pipapo_elem *pipapo_get (const struct net *net,const struct nft_set *set,const u8 *data,u8 genmask, -u64 tstamp) +u64 tstamp,gfp_t gfp) {struct nft_pipapo_elem *ret =ERR_PTR (-ENOENT );struct nft_pipapo *priv =nft_set_priv (set);
@@ -528,13 +529,13 @@ static struct nft_pipapo_elem *pipapo_geif (m->bsize_max ==0 )return ret; - res_map =kmalloc_array (m->bsize_max,sizeof (*res_map),GFP_ATOMIC ); + res_map =kmalloc_array (m->bsize_max,sizeof (*res_map), gfp);if (!res_map) { ret =ERR_PTR (-ENOMEM ); goto out; } - fill_map =kcalloc (m->bsize_max,sizeof (*res_map),GFP_ATOMIC ); + fill_map =kcalloc (m->bsize_max,sizeof (*res_map), gfp);if (!fill_map) { ret =ERR_PTR (-ENOMEM ); goto out;
@@ -609,7 +610,7 @@ static void *nft_pipapo_get(const struct const struct nft_set_elem *elem, unsigned int flags) { return pipapo_get(net, set, (const u8 *)elem->key.val.data, - nft_genmask_cur(net), get_jiffies_64()); + nft_genmask_cur(net), get_jiffies_64(), GFP_ATOMIC); }
@@ -1246,7 +1247,7 @@ static int nft_pipapo_insert(const strucelse end = start; - dup =pipapo_get (net, set, start, genmask, tstamp); + dup =pipapo_get (net, set, start, genmask, tstamp,GFP_KERNEL );if (!IS_ERR (dup)) {/* Check if we already have the same exact entry */ const struct nft_data *dup_key, *dup_end;
@@ -1268,7 +1269,8 @@ static int nft_pipapo_insert(const strucif (PTR_ERR (dup) == -ENOENT ) {/* Look for partially overlapping entries */ - dup =pipapo_get (net, set, end,nft_genmask_next (net), tstamp); + dup =pipapo_get (net, set, end,nft_genmask_next (net), tstamp, +GFP_KERNEL ); }if (PTR_ERR (dup) != -ENOENT ) {
@@ -1869,7 +1871,8 @@ static void *pipapo_deactivate(const str {struct nft_pipapo_elem *e; - e =pipapo_get (net, set, data,nft_genmask_next (net),nft_net_tstamp (net)); + e =pipapo_get (net, set, data,nft_genmask_next (net), +nft_net_tstamp (net),GFP_KERNEL );if (IS_ERR (e))return NULL ;
Greg Kroah-Hartman
maintainerPATCH 406/484 netfilter: nft_set_pipapo: move prove_locking helper around
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit a590f4760922acaa2d2b55a88004a38eecdd6412 ]
Preparation patch, the helper will soon get called from insert function too.
Stable-dep-of: 47e65eff5069 ("netfilter: nft_set_pipapo: don't leak bad clone into future transaction")
--- net/netfilter/nft_set_pipapo.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-)
net/netfilter/nft_set_pipapo.c +11 -11
@@ -1217,6 +1217,17 @@ static int pipapo_realloc_scratch(structreturn 0 ; } +static bool nft_pipapo_transaction_mutex_held (const struct nft_set *set) +{ +#ifdef CONFIG_PROVE_LOCKING +const struct net *net =read_pnet (&set->net); + +return lockdep_is_held (&nft_pernet (net)->commit_mutex); +#else +return true; +#endif +} +/** * nft_pipapo_insert() - Validate and insert ranged elements * @net: Network namespace
@@ -1802,17 +1813,6 @@ static void nft_pipapo_commit(struct nftpipapo_gc_queue (set); } -static bool nft_pipapo_transaction_mutex_held (const struct nft_set *set) -{ -#ifdef CONFIG_PROVE_LOCKING -const struct net *net =read_pnet (&set->net); - -return lockdep_is_held (&nft_pernet (net)->commit_mutex); -#else -return true; -#endif -} -static void nft_pipapo_abort (const struct nft_set *set) {struct nft_pipapo *priv =nft_set_priv (set);
Greg Kroah-Hartman
maintainerPATCH 407/484 netfilter: nft_set_pipapo: make pipapo_clone helper return NULL
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit 80efd2997fb9343a0283cf3cac5524a4595c8ff4 ]
Currently it returns an error pointer, but the only possible failure is ENOMEM.
After a followup patch, we'd need to discard the errno code, i.e.
x = pipapo_clone()
if (IS_ERR(x))
return NULL
or make more changes to fix up callers to expect IS_ERR() code from set->ops->deactivate().
So simplify this and make it return ptr-or-null.
Stable-dep-of: 47e65eff5069 ("netfilter: nft_set_pipapo: don't leak bad clone into future transaction")
--- net/netfilter/nft_set_pipapo.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
net/netfilter/nft_set_pipapo.c +7 -7
@@ -1358,7 +1358,7 @@ static int nft_pipapo_insert(const struc* pipapo_clone() - Clone matching data to create new working copy * @old: Existing matching data * -* Return: copy of matching data passed as 'old', error pointer on failure +* Return: copy of matching data passed as 'old' or NULL. */ static struct nft_pipapo_match *pipapo_clone (struct nft_pipapo_match *old) {
@@ -1368,7 +1368,7 @@ static struct nft_pipapo_match *pipapo_c new =kmalloc (struct_size (new, f, old->field_count),GFP_KERNEL_ACCOUNT );if (!new) -return ERR_PTR (-ENOMEM ); +return NULL ; new->field_count = old->field_count; new->bsize_max = old->bsize_max;
@@ -1444,7 +1444,7 @@ out_scratch:free_percpu (new->scratch);kfree (new); -return ERR_PTR (-ENOMEM ); +return NULL ; }/**
@@ -1798,7 +1798,7 @@ static void nft_pipapo_commit(struct nftreturn ; new_clone =pipapo_clone (priv->clone); -if (IS_ERR (new_clone)) +if (!new_clone)return ; priv->dirty = false;
@@ -1824,7 +1824,7 @@ static void nft_pipapo_abort(const struc m =rcu_dereference_protected (priv->match,nft_pipapo_transaction_mutex_held (set)); new_clone =pipapo_clone (m); -if (IS_ERR (new_clone)) +if (!new_clone)return ; priv->dirty = false;
@@ -2265,8 +2265,8 @@ static int nft_pipapo_init(const struct/* Create an initial clone of matching data for next insertion */ priv->clone =pipapo_clone (m); -if (IS_ERR (priv->clone)) { - err =PTR_ERR (priv->clone); +if (!priv->clone) { + err = -ENOMEM ; goto out_free; }
Greg Kroah-Hartman
maintainerPATCH 408/484 netfilter: nft_set_pipapo: prepare walk function for on-demand clone
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit 6c108d9bee448a850b03e682836bfe91fca645cb ]
The existing code uses iter->type to figure out what data is needed, the live copy (READ) or clone (UPDATE).
Without pending updates, priv->clone and priv->match will point to different memory locations, but they have identical content.
Future patch will make priv->clone == NULL if there are no pending changes, in this case we must copy the live data for the UPDATE case.
Currently this would require GFP_ATOMIC allocation. Split the walk function in two parts: one that does the walk and one that decides which data is needed.
In the UPDATE case, callers hold the transaction mutex so we do not need the rcu read lock. This allows to use GFP_KERNEL allocation while cloning.
Stable-dep-of: 47e65eff5069 ("netfilter: nft_set_pipapo: don't leak bad clone into future transaction")
--- net/netfilter/nft_set_pipapo.c | 60 ++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 21 deletions(-)
net/netfilter/nft_set_pipapo.c +39 -21
@@ -2109,35 +2109,23 @@ static void nft_pipapo_remove(const stru }/** -* nft_pipapo_walk() - Walk over elements +* nft_pipapo_do_walk() - Walk over elements in m * @ctx: nftables API context * @set: nftables API set representation +* @m: matching data pointing to key mapping array * @iter: Iterator * * As elements are referenced in the mapping array for the last field, directly * scan that array: there's no need to follow rule mappings from the first -* field. +* field. @m is protected either by RCU read lock or by transaction mutex. */ -static void nft_pipapo_walk (const struct nft_ctx *ctx,struct nft_set *set, -struct nft_set_iter *iter) +static void nft_pipapo_do_walk (const struct nft_ctx *ctx,struct nft_set *set, +const struct nft_pipapo_match *m, +struct nft_set_iter *iter) { -struct nft_pipapo *priv =nft_set_priv (set); -const struct nft_pipapo_match *m;const struct nft_pipapo_field *f;int i, r; -WARN_ON_ONCE (iter->type !=NFT_ITER_READ && - iter->type !=NFT_ITER_UPDATE ); - -rcu_read_lock (); -if (iter->type ==NFT_ITER_READ ) - m =rcu_dereference (priv->match); -else - m = priv->clone; - -if (unlikely (!m)) - goto out; -for (i =0 , f = m->f; i < m->field_count -1 ; i++, f++) ;
@@ -2157,14 +2145,44 @@ static void nft_pipapo_walk(const struct iter->err = iter->fn (ctx, set, iter, &elem);if (iter->err <0 ) - goto out; +return ; cont: iter->count++; } +} -out: -rcu_read_unlock (); +/** +* nft_pipapo_walk() - Walk over elements +* @ctx: nftables API context +* @set: nftables API set representation +* @iter: Iterator +* +* Test if destructive action is needed or not, clone active backend if needed +* and call the real function to work on the data. +*/ +static void nft_pipapo_walk (const struct nft_ctx *ctx,struct nft_set *set, +struct nft_set_iter *iter) +{ +struct nft_pipapo *priv =nft_set_priv (set); +const struct nft_pipapo_match *m; + +switch (iter->type) { +case NFT_ITER_UPDATE : + m = priv->clone; +nft_pipapo_do_walk (ctx, set, m, iter); +break ; +case NFT_ITER_READ : +rcu_read_lock (); + m =rcu_dereference (priv->match); +nft_pipapo_do_walk (ctx, set, m, iter); +rcu_read_unlock (); +break ; +default : + iter->err = -EINVAL ; +WARN_ON_ONCE (1 ); +break ; + } }/**
Greg Kroah-Hartman
maintainerPATCH 409/484 netfilter: nft_set_pipapo: merge deactivate helper into caller
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit c5444786d0ea2417a5e2cee7bd67137fc8bad687 ]
Its the only remaining call site so there is no need for this to be separated anymore.
Stable-dep-of: 47e65eff5069 ("netfilter: nft_set_pipapo: don't leak bad clone into future transaction")
--- net/netfilter/nft_set_pipapo.c | 39 +++++++++------------------------------ 1 file changed, 9 insertions(+), 30 deletions(-)
net/netfilter/nft_set_pipapo.c +9 -30
@@ -1854,52 +1854,31 @@ static void nft_pipapo_activate(const st }/** -* pipapo_deactivate() - Check that element is in set, mark as inactive +* nft_pipapo_deactivate() - Search for element and make it inactive * @net: Network namespace * @set: nftables API set representation -* @data: Input key data -* @ext: nftables API extension pointer, used to check for end element -* -* This is a convenience function that can be called from both -* nft_pipapo_deactivate() and nft_pipapo_flush(), as they are in fact the same -* operation. +* @elem: nftables API element representation containing key data * * Return: deactivated element if found, NULL otherwise. */ -static void *pipapo_deactivate (const struct net *net,const struct nft_set *set, -const u8 *data,const struct nft_set_ext *ext) +static void *nft_pipapo_deactivate (const struct net *net, +const struct nft_set *set, +const struct nft_set_elem *elem) {struct nft_pipapo_elem *e; - e =pipapo_get (net, set, data,nft_genmask_next (net), -nft_net_tstamp (net),GFP_KERNEL ); + e =pipapo_get (net, set, (const u8 *)elem->key.val.data, +nft_genmask_next (net),nft_net_tstamp (net),GFP_KERNEL );if (IS_ERR (e))return NULL ;nft_set_elem_change_active (net, set, &e->ext); -return e; -} - -/** -* nft_pipapo_deactivate() - Call pipapo_deactivate() to make element inactive -* @net: Network namespace -* @set: nftables API set representation -* @elem: nftables API element representation containing key data -* -* Return: deactivated element if found, NULL otherwise. -*/ -static void *nft_pipapo_deactivate (const struct net *net, -const struct nft_set *set, -const struct nft_set_elem *elem) -{ -const struct nft_set_ext *ext =nft_set_elem_ext (set, elem->priv); - -return pipapo_deactivate (net, set, (const u8 *)elem->key.val.data, ext); +return &e->priv; }/** -* nft_pipapo_flush() - Call pipapo_deactivate() to make element inactive +* nft_pipapo_flush() - make element inactive * @net: Network namespace * @set: nftables API set representation * @elem: nftables API element representation containing key data
Greg Kroah-Hartman
maintainerPATCH 410/484 netfilter: nft_set_pipapo: prepare pipapo_get helper for on-demand clone
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit a238106703ab4ae1090b86eba128815b8626d8f1 ]
The helper uses priv->clone unconditionally which will fail once we do the clone conditionally on first insert or removal.
'nft get element' from userspace needs to use priv->match since this runs from rcu read side lock section.
Prepare for this by passing the match backend data as argument.
Stable-dep-of: 47e65eff5069 ("netfilter: nft_set_pipapo: don't leak bad clone into future transaction")
--- net/netfilter/nft_set_pipapo.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-)
net/netfilter/nft_set_pipapo.c +15 -10
@@ -502,6 +502,7 @@ out:* pipapo_get() - Get matching element reference given key data * @net: Network namespace * @set: nftables API set representation +* @m: storage containing active/existing elements * @data: Key data to be matched against existing elements * @genmask: If set, check that element is active in given genmask * @tstamp: timestamp to check for expired elements
@@ -515,17 +516,15 @@ out:*/ static struct nft_pipapo_elem *pipapo_get (const struct net *net,const struct nft_set *set, +const struct nft_pipapo_match *m,const u8 *data,u8 genmask,u64 tstamp,gfp_t gfp) {struct nft_pipapo_elem *ret =ERR_PTR (-ENOENT ); -struct nft_pipapo *priv =nft_set_priv (set);unsigned long *res_map, *fill_map =NULL ; -const struct nft_pipapo_match *m;const struct nft_pipapo_field *f;int i; - m = priv->clone;if (m->bsize_max ==0 )return ret;
@@ -609,7 +608,10 @@ out:static void *nft_pipapo_get (const struct net *net,const struct nft_set *set,const struct nft_set_elem *elem,unsigned int flags) { -return pipapo_get (net, set, (const u8 *)elem->key.val.data, +struct nft_pipapo *priv =nft_set_priv (set); +struct nft_pipapo_match *m =rcu_dereference (priv->match); + +return pipapo_get (net, set, m, (const u8 *)elem->key.val.data,nft_genmask_cur (net),get_jiffies_64 (),GFP_ATOMIC ); }
@@ -1258,7 +1260,7 @@ static int nft_pipapo_insert(const strucelse end = start; - dup =pipapo_get (net, set, start, genmask, tstamp,GFP_KERNEL ); + dup =pipapo_get (net, set, m, start, genmask, tstamp,GFP_KERNEL );if (!IS_ERR (dup)) {/* Check if we already have the same exact entry */ const struct nft_data *dup_key, *dup_end;
@@ -1280,7 +1282,7 @@ static int nft_pipapo_insert(const strucif (PTR_ERR (dup) == -ENOENT ) {/* Look for partially overlapping entries */ - dup =pipapo_get (net, set, end,nft_genmask_next (net), tstamp, + dup =pipapo_get (net, set, m, end,nft_genmask_next (net), tstamp,GFP_KERNEL ); }
@@ -1865,16 +1867,18 @@ static void *nft_pipapo_deactivate(constconst struct nft_set *set, const struct nft_set_elem *elem) { + const struct nft_pipapo *priv = nft_set_priv(set); +struct nft_pipapo_match *m = priv->clone;struct nft_pipapo_elem *e; - e =pipapo_get (net, set, (const u8 *)elem->key.val.data, + e =pipapo_get (net, set, m, (const u8 *)elem->key.val.data,nft_genmask_next (net),nft_net_tstamp (net),GFP_KERNEL );if (IS_ERR (e))return NULL ;nft_set_elem_change_active (net, set, &e->ext); -return &e->priv; +return e; }/**
@@ -1900,8 +1904,9 @@ static bool nft_pipapo_flush(const struc {struct nft_pipapo_elem *e = elem; -return pipapo_deactivate (net, set, (const u8 *)nft_set_ext_key (&e->ext), - &e->ext); +nft_set_elem_change_active (net, set, &e->ext); + +return true; }/**
Greg Kroah-Hartman
maintainerPATCH 411/484 netfilter: nft_set_pipapo: move cloning of match info to insert/removal path
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit 3f1d886cc7c3525d4dbeee24bfa9bb3fe0d48ddc ]
This set type keeps two copies of the sets' content,
priv->match (live version, used to match from packet path) priv->clone (work-in-progress version of the 'future' priv->match).
All additions and removals are done on priv->clone. When transaction completes, priv->clone becomes priv->match and a new clone is allocated for use by next transaction.
Problem is that the cloning requires GFP_KERNEL allocations but we cannot fail at either commit or abort time.
This patch defers the clone until we get an insertion or removal request. This allows us to handle OOM situations correctly.
This also allows to remove ->dirty in a followup change:
If ->clone exists, ->dirty is always true
If ->clone is NULL, ->dirty is always false, no elements were added or removed (except catchall elements which are external to the specific set backend).
Stable-dep-of: 47e65eff5069 ("netfilter: nft_set_pipapo: don't leak bad clone into future transaction")
--- net/netfilter/nft_set_pipapo.c | 70 ++++++++++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 21 deletions(-)
net/netfilter/nft_set_pipapo.c +49 -21
@@ -1230,6 +1230,29 @@ static bool nft_pipapo_transaction_mutex#endif } +static struct nft_pipapo_match *pipapo_clone (struct nft_pipapo_match *old); + +/** +* pipapo_maybe_clone() - Build clone for pending data changes, if not existing +* @set: nftables API set representation +* +* Return: newly created or existing clone, if any. NULL on allocation failure +*/ +static struct nft_pipapo_match *pipapo_maybe_clone (const struct nft_set *set) +{ +struct nft_pipapo *priv =nft_set_priv (set); +struct nft_pipapo_match *m; + +if (priv->clone) +return priv->clone; + + m =rcu_dereference_protected (priv->match, +nft_pipapo_transaction_mutex_held (set)); + priv->clone =pipapo_clone (m); + +return priv->clone; +} +/** * nft_pipapo_insert() - Validate and insert ranged elements * @net: Network namespace
@@ -1247,14 +1270,17 @@ static int nft_pipapo_insert(const strucunion nft_pipapo_map_bucket rulemap[NFT_PIPAPO_MAX_FIELDS ];const u8 *start = (const u8 *)elem->key.val.data, *end;struct nft_pipapo_elem *e = elem->priv, *dup; +struct nft_pipapo_match *m =pipapo_maybe_clone (set);struct nft_pipapo *priv =nft_set_priv (set); -struct nft_pipapo_match *m = priv->clone;u8 genmask =nft_genmask_next (net);u64 tstamp =nft_net_tstamp (net);struct nft_pipapo_field *f;const u8 *start_p, *end_p;int i, bsize_max, err =0 ; +if (!m) +return -ENOMEM ; +if (nft_set_ext_exists (ext,NFT_SET_EXT_KEY_END )) end = (const u8 *)nft_set_ext_key_end (ext)->data;else
@@ -1791,7 +1817,10 @@ static void pipapo_reclaim_match(structstatic void nft_pipapo_commit (struct nft_set *set) {struct nft_pipapo *priv =nft_set_priv (set); -struct nft_pipapo_match *new_clone, *old; +struct nft_pipapo_match *old; + +if (!priv->clone) +return ;if (time_after_eq (jiffies, priv->last_gc +nft_set_gc_interval (set)))pipapo_gc_scan (set, priv->clone);
@@ -1799,40 +1828,29 @@ static void nft_pipapo_commit(struct nftif (!priv->dirty)return ; - new_clone =pipapo_clone (priv->clone); -if (!new_clone) -return ; - + old =rcu_replace_pointer (priv->match, priv->clone, +nft_pipapo_transaction_mutex_held (set)); + priv->clone =NULL ; priv->dirty = false; - old =rcu_access_pointer (priv->match); -rcu_assign_pointer (priv->match, priv->clone);if (old)call_rcu (&old->rcu, pipapo_reclaim_match); - priv->clone = new_clone; -pipapo_gc_queue (set); }static void nft_pipapo_abort (const struct nft_set *set) {struct nft_pipapo *priv =nft_set_priv (set); -struct nft_pipapo_match *new_clone, *m;if (!priv->dirty)return ; - m =rcu_dereference_protected (priv->match,nft_pipapo_transaction_mutex_held (set)); - - new_clone =pipapo_clone (m); -if (!new_clone) +if (!priv->clone)return ; - priv->dirty = false; -pipapo_free_match (priv->clone); - priv->clone = new_clone; + priv->clone =NULL ; }/**
@@ -1867,10 +1885,15 @@ static void *nft_pipapo_deactivate(constconst struct nft_set *set, const struct nft_set_elem *elem) { - const struct nft_pipapo *priv = nft_set_priv(set); -struct nft_pipapo_match *m = priv->clone; + struct nft_pipapo_match *m = pipapo_maybe_clone(set);struct nft_pipapo_elem *e; +/* removal must occur on priv->clone, if we are low on memory +* we have no choice and must fail the removal request. +*/ +if (!m) +return NULL ; + e =pipapo_get (net, set, m, (const u8 *)elem->key.val.data,nft_genmask_next (net),nft_net_tstamp (net),GFP_KERNEL );if (IS_ERR (e))
@@ -2153,7 +2176,12 @@ static void nft_pipapo_walk(const structswitch (iter->type) {case NFT_ITER_UPDATE : - m = priv->clone; + m =pipapo_maybe_clone (set); +if (!m) { + iter->err = -ENOMEM ; +return ; + } +nft_pipapo_do_walk (ctx, set, m, iter);break ;case NFT_ITER_READ :
Greg Kroah-Hartman
maintainerPATCH 412/484 netfilter: nft_set_pipapo: dont leak bad clone into future transaction
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit 47e65eff50691f0a5b79d325e28d83ec1da43bcf ]
On memory allocation failure the cloned nft_pipapo_match can enter a bad state:
- some fields can have their lookup tables resized while others did not
- bits might have been toggled
- scratch map can be undersized which also means m->bsize_max can be lower than what is required
This means that the next insertion in the same batch can trigger out-of-bounds writes.
Furthermore, a failure in the first can result in the bad clone to leak into the next transaction because the abort callback is never executed in this case (the upper layer saw an error and no attempt to allocate a transactional request was made).
Record a state for the nft_pipapo_match structure:
- NEW (pristine clone)
- MOD (modified clone with good state)
- ERR (potentially bogus content)
Then make it so that deletes and insertions fail when the clone entered ERR state.
In case the very first insert attempt results in an error, free the clone right away.
--- net/netfilter/nft_set_pipapo.c | 34 +++++++++++++++++++++++++++++----- net/netfilter/nft_set_pipapo.h | 8 ++++++++ 2 files changed, 37 insertions(+), 5 deletions(-)
net/netfilter/nft_set_pipapo.c +29 -5
@@ -342,6 +342,8 @@#include "nft_set_pipapo_avx2.h" #include "nft_set_pipapo.h" +static void nft_pipapo_abort (const struct nft_set *set); +/** * pipapo_refill() - For each set bit, set bits from selected mapping table item * @map: Bitmap to be scanned for set bits
@@ -1278,7 +1280,7 @@ static int nft_pipapo_insert(const strucconst u8 *start_p, *end_p;int i, bsize_max, err =0 ; -if (!m) +if (!m || m->state ==NFT_PIPAPO_CLONE_ERR )return -ENOMEM ;if (nft_set_ext_exists (ext,NFT_SET_EXT_KEY_END ))
@@ -1351,8 +1353,10 @@ static int nft_pipapo_insert(const strucelse ret =pipapo_expand (f, start, end, f->groups * f->bb); -if (ret <0 ) -return ret; +if (ret <0 ) { + err = ret; + goto abort; + }if (f->bsize > bsize_max) bsize_max = f->bsize;
@@ -1368,7 +1372,7 @@ static int nft_pipapo_insert(const struc err =pipapo_realloc_scratch (m, bsize_max);if (err) -return err; + goto abort; m->bsize_max = bsize_max; }else {
@@ -1379,7 +1383,26 @@ static int nft_pipapo_insert(const strucpipapo_map (m, rulemap, e); + m->state =NFT_PIPAPO_CLONE_MOD ;return 0 ; +abort: +DEBUG_NET_WARN_ON_ONCE (m->state ==NFT_PIPAPO_CLONE_ERR ); + +/* Two rollback cases: +* 1) no previous changes. nft_pipapo_abort is not +* guaranteed to be invoked (there might be no further +* add/delete requests coming after this). +* +* 2) we had previous changes: there are transaction +* records pointing to this set. Leave the rollback to +* the transaction handling. +*/ +if (m->state ==NFT_PIPAPO_CLONE_NEW ) +nft_pipapo_abort (set);/* releases m */ +else + m->state =NFT_PIPAPO_CLONE_ERR ; + +return err; }/**
@@ -1455,6 +1478,7 @@ static struct nft_pipapo_match *pipapo_c dst++; } + new->state =NFT_PIPAPO_CLONE_NEW ;return new; out_mt:
@@ -1891,7 +1915,7 @@ static void *nft_pipapo_deactivate(const/* removal must occur on priv->clone, if we are low on memory * we have no choice and must fail the removal request. */ -if (!m) +if (!m || m->state ==NFT_PIPAPO_CLONE_ERR )return NULL ; e = pipapo_get(net, set, m, (const u8 *)elem->key.val.data,
net/netfilter/nft_set_pipapo.h +8 -0
@@ -142,9 +142,16 @@ struct nft_pipapo_scratch {unsigned long map[]; }; +enum nft_pipapo_clone_state { +NFT_PIPAPO_CLONE_NEW , +NFT_PIPAPO_CLONE_MOD , +NFT_PIPAPO_CLONE_ERR , +}; +/** * struct nft_pipapo_match - Data used for lookup and matching * @field_count Amount of fields in set +* @state: add/delete state; used from control plane * @scratch: Preallocated per-CPU maps for partial matching results * @bsize_max: Maximum lookup table bucket size of all fields, in longs * @rcu Matching data is swapped on commits
@@ -152,6 +159,7 @@ struct nft_pipapo_scratch {*/ struct nft_pipapo_match {int field_count; +enum nft_pipapo_clone_state state:8 ;struct nft_pipapo_scratch *__percpu *scratch;size_t bsize_max;struct rcu_head rcu;
Greg Kroah-Hartman
maintainerPATCH 413/484 lsm: infrastructure management of the sock security
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Casey Schaufler <[email protected]>
[ Upstream commit 2aff9d20d50ac45dd13a013ef5231f4fb8912356 ]
Move management of the sock->sk_security blob out of the individual security modules and into the security infrastructure. Instead of allocating the blobs from within the modules the modules tell the infrastructure how much space is required, and the space is allocated there.
Stable-dep-of: 56acfeb10019 ("selinux: avoid sk_socket dereference in selinux_sctp_bind_connect()")
--- include/linux/lsm_hooks.h | 1 security/apparmor/include/net.h | 6 ++ security/apparmor/lsm.c | 38 ++++-------------- security/apparmor/net.c | 2 security/security.c | 36 ++++++++++++++++- security/selinux/hooks.c | 80 +++++++++++++++++--------------------- security/selinux/include/objsec.h | 5 ++ security/selinux/netlabel.c | 23 +++++----- security/smack/smack.h | 5 ++ security/smack/smack_lsm.c | 70 +++++++++++++++------------------ security/smack/smack_netfilter.c | 4 - 11 files changed, 146 insertions(+), 124 deletions(-)
include/linux/lsm_hooks.h +1 -0
@@ -61,6 +61,7 @@ struct lsm_blob_sizes {int lbs_file;int lbs_backing_file;int lbs_inode; +int lbs_sock;int lbs_superblock;int lbs_ipc;int lbs_msg_msg;
security/apparmor/include/net.h +5 -1
@@ -51,8 +51,12 @@ struct aa_sk_ctx {struct aa_label *peer; }; -#define SK_CTX (X ) ((X)->sk_security)#define SOCK_ctx (X ) SOCK_INODE(X)->i_security +static inline struct aa_sk_ctx *aa_sock (const struct sock *sk) +{ +return sk->sk_security + apparmor_blob_sizes.lbs_sock; +} +#define DEFINE_AUDIT_NET (NAME ,OP ,SK ,F ,T ,P ) \ struct lsm_network_audit NAME ## _net = { .sk = (SK), \ .family = (F)}; \
security/apparmor/lsm.c +10 -28
@@ -851,32 +851,14 @@ static int apparmor_task_kill(struct tas }/** -* apparmor_sk_alloc_security - allocate and attach the sk_security field -*/ -static int apparmor_sk_alloc_security (struct sock *sk,int family,gfp_t flags) -{ -struct aa_sk_ctx *ctx; - - ctx =kzalloc (sizeof (*ctx), flags); -if (!ctx) -return -ENOMEM ; - -SK_CTX (sk) = ctx; - -return 0 ; -} - -/** * apparmor_sk_free_security - free the sk_security field */ static void apparmor_sk_free_security (struct sock *sk) { -struct aa_sk_ctx *ctx =SK_CTX (sk); +struct aa_sk_ctx *ctx =aa_sock (sk); -SK_CTX (sk) =NULL ;aa_put_label (ctx->label);aa_put_label (ctx->peer); -kfree (ctx); }/**
@@ -885,8 +867,8 @@ static void apparmor_sk_free_security(ststatic void apparmor_sk_clone_security (const struct sock *sk,struct sock *newsk) { -struct aa_sk_ctx *ctx =SK_CTX (sk); -struct aa_sk_ctx *new =SK_CTX (newsk); +struct aa_sk_ctx *ctx =aa_sock (sk); +struct aa_sk_ctx *new =aa_sock (newsk);if (new->label)aa_put_label (new->label);
@@ -940,7 +922,7 @@ static int apparmor_socket_post_create(s label =aa_get_current_label ();if (sock->sk) { -struct aa_sk_ctx *ctx =SK_CTX (sock->sk); +struct aa_sk_ctx *ctx =aa_sock (sock->sk);aa_put_label (ctx->label); ctx->label =aa_get_label (label);
@@ -1139,7 +1121,7 @@ static int apparmor_socket_shutdown(stru*/ static int apparmor_socket_sock_rcv_skb (struct sock *sk,struct sk_buff *skb) { -struct aa_sk_ctx *ctx =SK_CTX (sk); +struct aa_sk_ctx *ctx =aa_sock (sk);if (!skb->secmark)return 0 ;
@@ -1159,7 +1141,7 @@ static int apparmor_socket_sock_rcv_skb(static struct aa_label *sk_peer_label (struct sock *sk) { -struct aa_sk_ctx *ctx =SK_CTX (sk); +struct aa_sk_ctx *ctx =aa_sock (sk);if (ctx->peer)return ctx->peer;
@@ -1240,7 +1222,7 @@ static int apparmor_socket_getpeersec_dg*/ static void apparmor_sock_graft (struct sock *sk,struct socket *parent) { -struct aa_sk_ctx *ctx =SK_CTX (sk); +struct aa_sk_ctx *ctx =aa_sock (sk);if (!ctx->label) ctx->label =aa_get_current_label ();
@@ -1250,7 +1232,7 @@ static void apparmor_sock_graft(struct sstatic int apparmor_inet_conn_request (const struct sock *sk,struct sk_buff *skb,struct request_sock *req) { -struct aa_sk_ctx *ctx =SK_CTX (sk); +struct aa_sk_ctx *ctx =aa_sock (sk);if (!skb->secmark)return 0 ;
@@ -1267,6 +1249,7 @@ struct lsm_blob_sizes apparmor_blob_size .lbs_cred = sizeof(struct aa_label *), .lbs_file = sizeof(struct aa_file_ctx), .lbs_task = sizeof(struct aa_task_ctx), + .lbs_sock = sizeof(struct aa_sk_ctx), };static struct security_hook_list apparmor_hooks[]__ro_after_init = {
@@ -1305,7 +1288,6 @@ static struct security_hook_list apparmoLSM_HOOK_INIT (getprocattr, apparmor_getprocattr),LSM_HOOK_INIT (setprocattr, apparmor_setprocattr), -LSM_HOOK_INIT (sk_alloc_security, apparmor_sk_alloc_security),LSM_HOOK_INIT (sk_free_security, apparmor_sk_free_security), LSM_HOOK_INIT(sk_clone_security, apparmor_sk_clone_security),
@@ -1864,7 +1846,7 @@ static unsigned int apparmor_ip_postroutif (sk ==NULL )return NF_ACCEPT ; - ctx =SK_CTX (sk); + ctx =aa_sock (sk);if (!apparmor_secmark_check (ctx->label,OP_SENDMSG ,AA_MAY_SEND , skb->secmark, sk))return NF_ACCEPT ;
security/apparmor/net.c +1 -1
@@ -152,7 +152,7 @@ static int aa_label_sk_perm(const struct const char *op, u32 request, struct sock *sk) { - struct aa_sk_ctx *ctx = SK_CTX(sk); + struct aa_sk_ctx *ctx = aa_sock(sk);int error =0 ;AA_BUG (!label);
security/security.c +35 -1
@@ -30,6 +30,7 @@#include <linux/string.h> #include <linux/msg.h> #include <net/flow.h> +#include <net/sock.h> /* How many LSMs were built into the kernel? */ #define LSM_COUNT (__end_lsm_info - __start_lsm_info)
@@ -212,6 +213,7 @@ static void __init lsm_set_blob_sizes(stlsm_set_blob_size (&needed->lbs_inode, &blob_sizes.lbs_inode);lsm_set_blob_size (&needed->lbs_ipc, &blob_sizes.lbs_ipc);lsm_set_blob_size (&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg); +lsm_set_blob_size (&needed->lbs_sock, &blob_sizes.lbs_sock);lsm_set_blob_size (&needed->lbs_superblock, &blob_sizes.lbs_superblock);lsm_set_blob_size (&needed->lbs_task, &blob_sizes.lbs_task); lsm_set_blob_size(&needed->lbs_xattr_count,
@@ -381,6 +383,7 @@ static void __init ordered_lsm_init(voidinit_debug ("inode blob size = %d\n" , blob_sizes.lbs_inode);init_debug ("ipc blob size = %d\n" , blob_sizes.lbs_ipc);init_debug ("msg_msg blob size = %d\n" , blob_sizes.lbs_msg_msg); +init_debug ("sock blob size = %d\n" , blob_sizes.lbs_sock);init_debug ("superblock blob size = %d\n" , blob_sizes.lbs_superblock);init_debug ("task blob size = %d\n" , blob_sizes.lbs_task);init_debug ("xattr slots = %d\n" , blob_sizes.lbs_xattr_count);
@@ -4560,6 +4563,28 @@ int security_socket_getpeersec_dgram(strEXPORT_SYMBOL (security_socket_getpeersec_dgram);/** +* lsm_sock_alloc - allocate a composite sock blob +* @sock: the sock that needs a blob +* @priority: allocation mode +* +* Allocate the sock blob for all the modules +* +* Returns 0, or -ENOMEM if memory can't be allocated. +*/ +static int lsm_sock_alloc (struct sock *sock,gfp_t priority) +{ +if (blob_sizes.lbs_sock ==0 ) { + sock->sk_security =NULL ; +return 0 ; + } + + sock->sk_security =kzalloc (blob_sizes.lbs_sock, priority); +if (sock->sk_security ==NULL ) +return -ENOMEM ; +return 0 ; +} + +/** * security_sk_alloc() - Allocate and initialize a sock's LSM blob * @sk: sock * @family: protocol family
@@ -4572,7 +4597,14 @@ EXPORT_SYMBOL(security_socket_getpeersec*/ int security_sk_alloc (struct sock *sk,int family,gfp_t priority) { -return call_int_hook (sk_alloc_security,0 , sk, family, priority); +int rc =lsm_sock_alloc (sk, priority); + +if (unlikely (rc)) +return rc; + rc =call_int_hook (sk_alloc_security,0 , sk, family, priority); +if (unlikely (rc)) +security_sk_free (sk); +return rc; }/**
@@ -4584,6 +4616,8 @@ int security_sk_alloc(struct sock *sk, ivoid security_sk_free (struct sock *sk) {call_void_hook (sk_free_security, sk); +kfree (sk->sk_security); + sk->sk_security =NULL ; }/**
security/selinux/hooks.c +37 -43
265 lines not on this page · raw message
security/selinux/include/objsec.h +5 -0
@@ -205,4 +205,9 @@ static inline struct superblock_security return superblock->s_security + selinux_blob_sizes.lbs_superblock; } +static inline struct sk_security_struct *selinux_sock (const struct sock *sock) +{ +return sock->sk_security + selinux_blob_sizes.lbs_sock; +} +#endif /* _SELINUX_OBJSEC_H_ */
security/selinux/netlabel.c +12 -11
@@ -17,6 +17,7 @@#include <linux/gfp.h> #include <linux/ip.h> #include <linux/ipv6.h> +#include <linux/lsm_hooks.h> #include <net/sock.h> #include <net/netlabel.h> #include <net/ip.h>
@@ -68,7 +69,7 @@ static int selinux_netlbl_sidlookup_cachstatic struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr (struct sock *sk) {int rc; -struct sk_security_struct *sksec = sk->sk_security; +struct sk_security_struct *sksec =selinux_sock (sk);struct netlbl_lsm_secattr *secattr;if (sksec->nlbl_secattr !=NULL )
@@ -100,7 +101,7 @@ static struct netlbl_lsm_secattr *selinu const struct sock *sk, u32 sid) { -struct sk_security_struct *sksec = sk->sk_security; +struct sk_security_struct *sksec =selinux_sock (sk);struct netlbl_lsm_secattr *secattr = sksec->nlbl_secattr;if (secattr ==NULL )
@@ -240,7 +241,7 @@ int selinux_netlbl_skbuff_setsid(struct* being labeled by it's parent socket, if it is just exit */ sk =skb_to_full_sk (skb);if (sk !=NULL ) { -struct sk_security_struct *sksec = sk->sk_security; +struct sk_security_struct *sksec =selinux_sock (sk);if (sksec->nlbl_state !=NLBL_REQSKB )return 0 ;
@@ -277,7 +278,7 @@ int selinux_netlbl_sctp_assoc_request(st {int rc;struct netlbl_lsm_secattr secattr; -struct sk_security_struct *sksec = asoc->base.sk->sk_security; +struct sk_security_struct *sksec =selinux_sock (asoc->base.sk);struct sockaddr_in addr4;struct sockaddr_in6 addr6;
@@ -356,7 +357,7 @@ inet_conn_request_return:*/ void selinux_netlbl_inet_csk_clone (struct sock *sk,u16 family) { -struct sk_security_struct *sksec = sk->sk_security; +struct sk_security_struct *sksec =selinux_sock (sk);if (family ==PF_INET ) sksec->nlbl_state =NLBL_LABELED ;
@@ -374,8 +375,8 @@ void selinux_netlbl_inet_csk_clone(struc*/ void selinux_netlbl_sctp_sk_clone (struct sock *sk,struct sock *newsk) { -struct sk_security_struct *sksec = sk->sk_security; -struct sk_security_struct *newsksec = newsk->sk_security; +struct sk_security_struct *sksec =selinux_sock (sk); +struct sk_security_struct *newsksec =selinux_sock (newsk); newsksec->nlbl_state = sksec->nlbl_state; }
@@ -393,7 +394,7 @@ void selinux_netlbl_sctp_sk_clone(structint selinux_netlbl_socket_post_create (struct sock *sk,u16 family) {int rc; -struct sk_security_struct *sksec = sk->sk_security; +struct sk_security_struct *sksec =selinux_sock (sk);struct netlbl_lsm_secattr *secattr;if (family !=PF_INET && family !=PF_INET6 )
@@ -507,7 +508,7 @@ int selinux_netlbl_socket_setsockopt(str {int rc =0 ;struct sock *sk = sock->sk; -struct sk_security_struct *sksec = sk->sk_security; +struct sk_security_struct *sksec =selinux_sock (sk);struct netlbl_lsm_secattr secattr; if (selinux_netlbl_option(level, optname) &&
@@ -545,7 +546,7 @@ static int selinux_netlbl_socket_connect struct sockaddr *addr) {int rc; -struct sk_security_struct *sksec = sk->sk_security; +struct sk_security_struct *sksec =selinux_sock (sk);struct netlbl_lsm_secattr *secattr;/* connected sockets are allowed to disconnect when the address family
@@ -584,7 +585,7 @@ static int selinux_netlbl_socket_connectint selinux_netlbl_socket_connect_locked (struct sock *sk,struct sockaddr *addr) { -struct sk_security_struct *sksec = sk->sk_security; +struct sk_security_struct *sksec =selinux_sock (sk);if (sksec->nlbl_state !=NLBL_REQSKB && sksec->nlbl_state !=NLBL_CONNLABELED )
security/smack/smack.h +5 -0
@@ -361,6 +361,11 @@ static inline struct superblock_smack *sreturn superblock->s_security + smack_blob_sizes.lbs_superblock; } +static inline struct socket_smack *smack_sock (const struct sock *sock) +{ +return sock->sk_security + smack_blob_sizes.lbs_sock; +} +/* * Is the directory transmuting? */
security/smack/smack_lsm.c +33 -37
243 lines not on this page · raw message
security/smack/smack_netfilter.c +2 -2
@@ -26,8 +26,8 @@ static unsigned int smack_ip_output(voidstruct socket_smack *ssp;struct smack_known *skp; -if (sk && sk->sk_security) { - ssp = sk->sk_security; +if (sk) { + ssp =smack_sock (sk); skp = ssp->smk_out; skb->secmark = skp->smk_secid; }
Greg Kroah-Hartman
maintainerPATCH 414/484 selinux: avoid sk_socket dereference in selinux_sctp_bind_connect()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tristan Madani <[email protected]>
[ Upstream commit 56acfeb10019e200ab6787d01f8d7cbe0f01526f ]
selinux_sctp_bind_connect() dereferences sk->sk_socket to pass a struct socket * to selinux_socket_bind() and selinux_socket_connect_helper(). However, when the hook is invoked from the ASCONF softirq path (sctp_process_asconf), there is no file reference guaranteeing that sk->sk_socket is non-NULL. The setsockopt callers (bindx, connectx, set_primary, sendmsg connect) hold a file reference and are not affected.
Both selinux_socket_bind() and selinux_socket_connect_helper() immediately resolve sock->sk, never using the struct socket * for anything else. Refactor the inner logic into helpers that take a struct sock * directly so that selinux_sctp_bind_connect() never needs to touch sk->sk_socket at all.
--- security/selinux/hooks.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-)
security/selinux/hooks.c +10 -9
@@ -4777,9 +4777,8 @@ static int selinux_socket_socketpair(strNeed to determine whether we should perform a name_bind permission check between the socket and the port number. */ -static int selinux_socket_bind (struct socket *sock,struct sockaddr *address,int addrlen) +static int __selinux_socket_bind (struct sock *sk,struct sockaddr *address,int addrlen) { -struct sock *sk = sock->sk;struct sk_security_struct *sksec =selinux_sock (sk);u16 family;int err;
@@ -4913,13 +4912,17 @@ err_af:return -EAFNOSUPPORT ; } +static int selinux_socket_bind (struct socket *sock,struct sockaddr *address,int addrlen) +{ +return __selinux_socket_bind (sock->sk, address, addrlen); +} +/* This supports connect(2) and SCTP connect services such as sctp_connectx(3) * and sctp_sendmsg(3) as described in Documentation/security/SCTP.rst */ -static int selinux_socket_connect_helper (struct socket *sock, +static int selinux_socket_connect_helper (struct sock *sk,struct sockaddr *address,int addrlen) { -struct sock *sk = sock->sk;struct sk_security_struct *sksec =selinux_sock (sk);int err;
@@ -5012,7 +5015,7 @@ static int selinux_socket_connect(structint err;struct sock *sk = sock->sk; - err =selinux_socket_connect_helper (sock, address, addrlen); + err =selinux_socket_connect_helper (sk, address, addrlen);if (err)return err;
@@ -5512,13 +5515,11 @@ static int selinux_sctp_bind_connect(strint len, err =0 , walk_size =0 ;void *addr_buf;struct sockaddr *addr; -struct socket *sock;if (!selinux_policycap_extsockclass ())return 0 ;/* Process one or more addresses that may be IPv4 or IPv6 */ - sock = sk->sk_socket; addr_buf = address;while (walk_size < addrlen) {
@@ -5547,14 +5548,14 @@ static int selinux_sctp_bind_connect(strcase SCTP_PRIMARY_ADDR :case SCTP_SET_PEER_PRIMARY_ADDR :case SCTP_SOCKOPT_BINDX_ADD : - err =selinux_socket_bind (sock, addr, len); + err =__selinux_socket_bind (sk, addr, len);break ;/* Connect checks */ case SCTP_SOCKOPT_CONNECTX :case SCTP_PARAM_SET_PRIMARY :case SCTP_PARAM_ADD_IP :case SCTP_SENDMSG_CONNECT : - err =selinux_socket_connect_helper (sock, addr, len); + err =selinux_socket_connect_helper (sk, addr, len);if (err)return err;
Greg Kroah-Hartman
maintainerPATCH 415/484 netfilter: nf_conntrack_sip: remove net variable shadowing
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit 7970d6aaf710db166de98c5356a260089896fae5 ]
net is already set, derived from nf_conn.
I don't see how the device could be living in a different netns than the conntrack entry.
Remove the extra variable and re-use existing one.
Stable-dep-of: e5e24a365a5e ("netfilter: nf_conntrack_sip: validate skb_dst() before accessing it")
--- net/netfilter/nf_conntrack_sip.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
net/netfilter/nf_conntrack_sip.c +1 -2
@@ -948,9 +948,8 @@ static int set_expected_rtp_rtcp(struct saddr = &ct->tuplehash[!dir].tuple.src.u3; }else if (sip_external_media) {struct net_device *dev =skb_dst (skb)->dev; -struct net *net =dev_net (dev); -struct flowi fl;struct dst_entry *dst =NULL ; +struct flowi fl;memset (&fl,0 ,sizeof (fl));
Greg Kroah-Hartman
maintainerPATCH 416/484 netfilter: nf_conntrack_sip: validate skb_dst() before accessing it
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pablo Neira Ayuso <[email protected]>
[ Upstream commit e5e24a365a5e024efef63cc49abb345fbd4852c5 ]
tc ingress and openvswitch do not guarantee routing information to be available. These subsystems use the conntrack helper infrastructure, and the SIP helper relies on the skb_dst() to be present if sip_external_media is set to 1 (which is disabled by default as a module parameter).
This effectively disables the sip_external_media toggle for these subsystems without resulting in a crash.
--- net/netfilter/nf_conntrack_sip.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
net/netfilter/nf_conntrack_sip.c +5 -2
@@ -947,7 +947,6 @@ static int set_expected_rtp_rtcp(structreturn NF_ACCEPT ; saddr = &ct->tuplehash[!dir].tuple.src.u3; }else if (sip_external_media) { -struct net_device *dev =skb_dst (skb)->dev;struct dst_entry *dst =NULL ;struct flowi fl;
@@ -969,7 +968,11 @@ static int set_expected_rtp_rtcp(struct* through the same interface as the signalling peer. */ if (dst) { -bool external_media = (dst->dev == dev); +const struct dst_entry *this_dst =skb_dst (skb); +bool external_media = false; + +if (this_dst && dst->dev == this_dst->dev) + external_media = true;dst_release (dst);if (external_media)
Greg Kroah-Hartman
maintainerPATCH 417/484 netfilter: nf_tables: Remove unused nft_reduce_is_readonly()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yue Haibing <[email protected]>
[ Upstream commit bf6788742b8d6c73de441e088a71de7154f0d4aa ]
Since commit 9e539c5b6d9c ("netfilter: nf_tables: disable expression reduction infra") this is unused.
Stable-dep-of: d07955dd34ec ("netfilter: nft_fib: reject fib expression on the netdev egress hook")
--- include/net/netfilter/nf_tables.h | 5 ----- 1 file changed, 5 deletions(-)
include/net/netfilter/nf_tables.h +0 -5
@@ -1851,11 +1851,6 @@ static inline u64 nft_net_tstamp(const s#define __NFT_REDUCE_READONLY 1UL#define NFT_REDUCE_READONLY (void *)__NFT_REDUCE_READONLY -static inline bool nft_reduce_is_readonly (const struct nft_expr *expr) -{ -return expr->ops->reduce ==NFT_REDUCE_READONLY ; -} -void nft_reg_track_update (struct nft_regs_track *track,const struct nft_expr *expr,u8 dreg,u8 len);void nft_reg_track_cancel (struct nft_regs_track *track,u8 dreg,u8 len);
Greg Kroah-Hartman
maintainerPATCH 418/484 netfilter: nf_tables: remove register tracking infrastructure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit 6b94d081f81dd524626f7aab2b98a9de335edb72 ]
This facility was disabled in commit9e539c5b6d9c ("netfilter: nf_tables: disable expression reduction infra"), because not all nft_exprs guarantee they will update the destination
register: some may set NFT_BREAK instead to cancel evaluation of the rule.
This has been dead code ever since.
There are no plans to salvage this at this time, so remove this.
Stable-dep-of: d07955dd34ec ("netfilter: nft_fib: reject fib expression on the netdev egress hook")
--- include/net/netfilter/nf_tables.h | 32 --------- include/net/netfilter/nft_fib.h | 2 include/net/netfilter/nft_meta.h | 3 net/bridge/netfilter/nft_meta_bridge.c | 20 ----- net/bridge/netfilter/nft_reject_bridge.c | 1 net/ipv4/netfilter/nft_dup_ipv4.c | 1 net/ipv4/netfilter/nft_fib_ipv4.c | 2 net/ipv4/netfilter/nft_reject_ipv4.c | 1 net/ipv6/netfilter/nft_dup_ipv6.c | 1 net/ipv6/netfilter/nft_fib_ipv6.c | 2 net/ipv6/netfilter/nft_reject_ipv6.c | 1 net/netfilter/nf_tables_api.c | 67 ------------------- net/netfilter/nft_bitwise.c | 104 ------------------------------- net/netfilter/nft_byteorder.c | 11 --- net/netfilter/nft_cmp.c | 3 net/netfilter/nft_compat.c | 10 -- net/netfilter/nft_connlimit.c | 1 net/netfilter/nft_counter.c | 1 net/netfilter/nft_ct.c | 46 ------------- net/netfilter/nft_dup_netdev.c | 1 net/netfilter/nft_dynset.c | 1 net/netfilter/nft_exthdr.c | 34 ---------- net/netfilter/nft_fib.c | 42 ------------ net/netfilter/nft_fib_inet.c | 1 net/netfilter/nft_fib_netdev.c | 1 net/netfilter/nft_flow_offload.c | 1 net/netfilter/nft_fwd_netdev.c | 2 net/netfilter/nft_hash.c | 36 ---------- net/netfilter/nft_immediate.c | 12 --- net/netfilter/nft_last.c | 1 net/netfilter/nft_limit.c | 2 net/netfilter/nft_log.c | 1 net/netfilter/nft_lookup.c | 12 --- net/netfilter/nft_masq.c | 3 net/netfilter/nft_meta.c | 45 ------------- net/netfilter/nft_nat.c | 2 net/netfilter/nft_numgen.c | 22 ------ net/netfilter/nft_objref.c | 2 net/netfilter/nft_osf.c | 25 ------- net/netfilter/nft_payload.c | 47 -------------- net/netfilter/nft_queue.c | 2 net/netfilter/nft_quota.c | 1 net/netfilter/nft_range.c | 1 net/netfilter/nft_redir.c | 3 net/netfilter/nft_reject_inet.c | 1 net/netfilter/nft_reject_netdev.c | 1 net/netfilter/nft_rt.c | 1 net/netfilter/nft_socket.c | 26 ------- net/netfilter/nft_synproxy.c | 1 net/netfilter/nft_tproxy.c | 1 net/netfilter/nft_tunnel.c | 26 ------- net/netfilter/nft_xfrm.c | 27 -------- 52 files changed, 693 deletions(-)
include/net/netfilter/nf_tables.h +0 -32
@@ -123,17 +123,6 @@ struct nft_regs { }; }; -struct nft_regs_track { -struct { -const struct nft_expr *selector; -const struct nft_expr *bitwise; -u8 num_reg; - } regs[NFT_REG32_NUM ]; - -const struct nft_expr *cur; -const struct nft_expr *last; -}; -/* Store/load an u8, u16 or u64 integer to/from the u32 data register. * * Note, when using concatenations, register allocation happens at 32-bit
@@ -420,8 +409,6 @@ int nft_expr_clone(struct nft_expr *dst,void nft_expr_destroy (const struct nft_ctx *ctx,struct nft_expr *expr);int nft_expr_dump (struct sk_buff *skb,unsigned int attr,const struct nft_expr *expr,bool reset); -bool nft_expr_reduce_bitwise (struct nft_regs_track *track, -const struct nft_expr *expr);struct nft_set_ext ;
@@ -933,7 +920,6 @@ struct nft_offload_ctx;* @destroy_clone: destruction clone function * @dump: function to dump parameters * @validate: validate expression, called during loop detection -* @reduce: reduce expression * @gc: garbage collection expression * @offload: hardware offload expression * @offload_action: function to report true/false to allocate one slot or not in the flow
@@ -967,8 +953,6 @@ struct nft_expr_ops { bool reset);int (*validate)(const struct nft_ctx *ctx,const struct nft_expr *expr); -bool (*reduce)(struct nft_regs_track *track, -const struct nft_expr *expr);bool (*gc)(struct net *net,const struct nft_expr *expr); int (*offload)(struct nft_offload_ctx *ctx,
@@ -1848,20 +1832,4 @@ static inline u64 nft_net_tstamp(const s return nft_pernet(net)->tstamp; } -#define __NFT_REDUCE_READONLY 1UL -#define NFT_REDUCE_READONLY (void *)__NFT_REDUCE_READONLY - -void nft_reg_track_update (struct nft_regs_track *track, -const struct nft_expr *expr,u8 dreg,u8 len); -void nft_reg_track_cancel (struct nft_regs_track *track,u8 dreg,u8 len); -void __nft_reg_track_cancel (struct nft_regs_track *track,u8 dreg); - -static inline bool nft_reg_track_cmp (struct nft_regs_track *track, -const struct nft_expr *expr,u8 dreg) -{ -return track->regs[dreg].selector && - track->regs[dreg].selector->ops == expr->ops && - track->regs[dreg].num_reg ==0 ; -} -#endif /* _NET_NF_TABLES_H */
include/net/netfilter/nft_fib.h +0 -2
@@ -36,6 +36,4 @@ void nft_fib6_eval(const struct nft_exprvoid nft_fib_store_result (void *reg,const struct nft_fib *priv,const struct net_device *dev); -bool nft_fib_reduce (struct nft_regs_track *track, -const struct nft_expr *expr);#endif
include/net/netfilter/nft_meta.h +0 -3
@@ -43,9 +43,6 @@ void nft_meta_set_destroy(const struct nint nft_meta_set_validate (const struct nft_ctx *ctx,const struct nft_expr *expr); -bool nft_meta_get_reduce (struct nft_regs_track *track, -const struct nft_expr *expr); -struct nft_inner_tun_ctx ; void nft_meta_inner_eval(const struct nft_expr *expr, struct nft_regs *regs, const struct nft_pktinfo *pkt,
net/bridge/netfilter/nft_meta_bridge.c +0 -20
@@ -104,7 +104,6 @@ static const struct nft_expr_ops nft_met .eval = nft_meta_bridge_get_eval, .init = nft_meta_bridge_get_init, .dump = nft_meta_get_dump, - .reduce = nft_meta_get_reduce, }; static void nft_meta_bridge_set_eval(const struct nft_expr *expr,
@@ -151,24 +150,6 @@ static int nft_meta_bridge_set_init(consreturn 0 ; } -static bool nft_meta_bridge_set_reduce (struct nft_regs_track *track, -const struct nft_expr *expr) -{ -int i; - -for (i =0 ; i <NFT_REG32_NUM ; i++) { -if (!track->regs[i].selector) -continue ; - -if (track->regs[i].selector->ops != &nft_meta_bridge_get_ops) -continue ; - -__nft_reg_track_cancel (track, i); - } - -return false; -} -static int nft_meta_bridge_set_validate (const struct nft_ctx *ctx,const struct nft_expr *expr) {
@@ -193,7 +174,6 @@ static const struct nft_expr_ops nft_met .init = nft_meta_bridge_set_init, .destroy = nft_meta_set_destroy, .dump = nft_meta_set_dump, - .reduce = nft_meta_bridge_set_reduce, .validate = nft_meta_bridge_set_validate, };
net/bridge/netfilter/nft_reject_bridge.c +0 -1
@@ -184,7 +184,6 @@ static const struct nft_expr_ops nft_rej .init = nft_reject_init, .dump = nft_reject_dump, .validate = nft_reject_bridge_validate, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_reject_bridge_type__read_mostly = {
net/ipv4/netfilter/nft_dup_ipv4.c +0 -1
@@ -76,7 +76,6 @@ static const struct nft_expr_ops nft_dup .eval = nft_dup_ipv4_eval, .init = nft_dup_ipv4_init, .dump = nft_dup_ipv4_dump, - .reduce = NFT_REDUCE_READONLY, };static const struct nla_policy nft_dup_ipv4_policy[NFTA_DUP_MAX +1 ] = {
net/ipv4/netfilter/nft_fib_ipv4.c +0 -2
@@ -157,7 +157,6 @@ static const struct nft_expr_ops nft_fib .init = nft_fib_init, .dump = nft_fib_dump, .validate = nft_fib_validate, - .reduce = nft_fib_reduce, };static const struct nft_expr_ops nft_fib4_ops = {
@@ -167,7 +166,6 @@ static const struct nft_expr_ops nft_fib .init = nft_fib_init, .dump = nft_fib_dump, .validate = nft_fib_validate, - .reduce = nft_fib_reduce, }; static const struct nft_expr_ops *
net/ipv4/netfilter/nft_reject_ipv4.c +0 -1
@@ -45,7 +45,6 @@ static const struct nft_expr_ops nft_rej .init = nft_reject_init, .dump = nft_reject_dump, .validate = nft_reject_validate, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_reject_ipv4_type__read_mostly = {
net/ipv6/netfilter/nft_dup_ipv6.c +0 -1
@@ -74,7 +74,6 @@ static const struct nft_expr_ops nft_dup .eval = nft_dup_ipv6_eval, .init = nft_dup_ipv6_init, .dump = nft_dup_ipv6_dump, - .reduce = NFT_REDUCE_READONLY, };static const struct nla_policy nft_dup_ipv6_policy[NFTA_DUP_MAX +1 ] = {
net/ipv6/netfilter/nft_fib_ipv6.c +0 -2
@@ -226,7 +226,6 @@ static const struct nft_expr_ops nft_fib .init = nft_fib_init, .dump = nft_fib_dump, .validate = nft_fib_validate, - .reduce = nft_fib_reduce, };static const struct nft_expr_ops nft_fib6_ops = {
@@ -236,7 +235,6 @@ static const struct nft_expr_ops nft_fib .init = nft_fib_init, .dump = nft_fib_dump, .validate = nft_fib_validate, - .reduce = nft_fib_reduce, }; static const struct nft_expr_ops *
net/ipv6/netfilter/nft_reject_ipv6.c +0 -1
@@ -46,7 +46,6 @@ static const struct nft_expr_ops nft_rej .init = nft_reject_init, .dump = nft_reject_dump, .validate = nft_reject_validate, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_reject_ipv6_type__read_mostly = {
net/netfilter/nf_tables_api.c +0 -67
89 lines not on this page · raw message
net/netfilter/nft_bitwise.c +0 -104
131 lines not on this page · raw message
net/netfilter/nft_byteorder.c +0 -11
@@ -177,23 +177,12 @@ nla_put_failure:return -1 ; } -static bool nft_byteorder_reduce (struct nft_regs_track *track, -const struct nft_expr *expr) -{ -struct nft_byteorder *priv =nft_expr_priv (expr); - -nft_reg_track_cancel (track, priv->dreg, priv->len); - -return false; -} -static const struct nft_expr_ops nft_byteorder_ops = { .type = &nft_byteorder_type, .size =NFT_EXPR_SIZE (sizeof (struct nft_byteorder )), .eval = nft_byteorder_eval, .init = nft_byteorder_init, .dump = nft_byteorder_dump, - .reduce = nft_byteorder_reduce, };struct nft_expr_type nft_byteorder_type__read_mostly = {
net/netfilter/nft_cmp.c +0 -3
@@ -190,7 +190,6 @@ static const struct nft_expr_ops nft_cmp .eval = nft_cmp_eval, .init = nft_cmp_init, .dump = nft_cmp_dump, - .reduce = NFT_REDUCE_READONLY, .offload = nft_cmp_offload, };
@@ -282,7 +281,6 @@ const struct nft_expr_ops nft_cmp_fast_o .eval = NULL, /* inlined */ .init = nft_cmp_fast_init, .dump = nft_cmp_fast_dump, - .reduce = NFT_REDUCE_READONLY, .offload = nft_cmp_fast_offload, };
@@ -376,7 +374,6 @@ const struct nft_expr_ops nft_cmp16_fast .eval = NULL, /* inlined */ .init = nft_cmp16_fast_init, .dump = nft_cmp16_fast_dump, - .reduce = NFT_REDUCE_READONLY, .offload = nft_cmp16_fast_offload, };
net/netfilter/nft_compat.c +0 -10
@@ -794,14 +794,6 @@ static const struct nfnetlink_subsystemstatic struct nft_expr_type nft_match_type; -static bool nft_match_reduce (struct nft_regs_track *track, -const struct nft_expr *expr) -{ -const struct xt_match *match = expr->ops->data; - -return strcmp (match->name,"comment" ) ==0 ; -} -static const struct nft_expr_ops *nft_match_select_ops (const struct nft_ctx *ctx,const struct nlattr *const tb[])
@@ -844,7 +836,6 @@ nft_match_select_ops(const struct nft_ct ops->dump = nft_match_dump; ops->validate = nft_match_validate; ops->data = match; - ops->reduce = nft_match_reduce; matchsize =NFT_EXPR_SIZE (XT_ALIGN (match->matchsize));if (matchsize >NFT_MATCH_LARGE_THRESH ) {
@@ -933,7 +924,6 @@ nft_target_select_ops(const struct nft_c ops->destroy = nft_target_destroy; ops->dump = nft_target_dump; ops->data = target; - ops->reduce =NFT_REDUCE_READONLY ;if (family ==NFPROTO_BRIDGE ) { ops->eval = nft_target_eval_bridge;
net/netfilter/nft_connlimit.c +0 -1
@@ -247,7 +247,6 @@ static const struct nft_expr_ops nft_con .destroy_clone = nft_connlimit_destroy_clone, .dump = nft_connlimit_dump, .gc = nft_connlimit_gc, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_connlimit_type__read_mostly = {
net/netfilter/nft_counter.c +0 -1
@@ -301,7 +301,6 @@ static const struct nft_expr_ops nft_cou .destroy_clone = nft_counter_destroy, .dump = nft_counter_dump, .clone = nft_counter_clone, - .reduce = NFT_REDUCE_READONLY, .offload = nft_counter_offload, .offload_stats = nft_counter_offload_stats, };
net/netfilter/nft_ct.c +0 -46
84 lines not on this page · raw message
net/netfilter/nft_dup_netdev.c +0 -1
@@ -80,7 +80,6 @@ static const struct nft_expr_ops nft_dup .eval = nft_dup_netdev_eval, .init = nft_dup_netdev_init, .dump = nft_dup_netdev_dump, - .reduce = NFT_REDUCE_READONLY, .offload = nft_dup_netdev_offload, .offload_action = nft_dup_netdev_offload_action, };
net/netfilter/nft_dynset.c +0 -1
@@ -430,7 +430,6 @@ static const struct nft_expr_ops nft_dyn .activate = nft_dynset_activate, .deactivate = nft_dynset_deactivate, .dump = nft_dynset_dump, - .reduce = NFT_REDUCE_READONLY, };struct nft_expr_type nft_dynset_type__read_mostly = {
net/netfilter/nft_exthdr.c +0 -34
@@ -701,40 +701,12 @@ static int nft_exthdr_dump_strip(structreturn nft_exthdr_dump_common (skb, priv); } -static bool nft_exthdr_reduce (struct nft_regs_track *track, -const struct nft_expr *expr) -{ -const struct nft_exthdr *priv =nft_expr_priv (expr); -const struct nft_exthdr *exthdr; - -if (!nft_reg_track_cmp (track, expr, priv->dreg)) { -nft_reg_track_update (track, expr, priv->dreg, priv->len); -return false; - } - - exthdr =nft_expr_priv (track->regs[priv->dreg].selector); -if (priv->type != exthdr->type || - priv->op != exthdr->op || - priv->flags != exthdr->flags || - priv->offset != exthdr->offset || - priv->len != exthdr->len) { -nft_reg_track_update (track, expr, priv->dreg, priv->len); -return false; - } - -if (!track->regs[priv->dreg].bitwise) -return true; - -return nft_expr_reduce_bitwise (track, expr); -} -static const struct nft_expr_ops nft_exthdr_ipv6_ops = { .type = &nft_exthdr_type, .size =NFT_EXPR_SIZE (sizeof (struct nft_exthdr )), .eval = nft_exthdr_ipv6_eval, .init = nft_exthdr_init, .dump = nft_exthdr_dump, - .reduce = nft_exthdr_reduce, };static const struct nft_expr_ops nft_exthdr_ipv4_ops = {
@@ -743,7 +715,6 @@ static const struct nft_expr_ops nft_ext .eval = nft_exthdr_ipv4_eval, .init = nft_exthdr_ipv4_init, .dump = nft_exthdr_dump, - .reduce = nft_exthdr_reduce, };static const struct nft_expr_ops nft_exthdr_tcp_ops = {
@@ -752,7 +723,6 @@ static const struct nft_expr_ops nft_ext .eval = nft_exthdr_tcp_eval, .init = nft_exthdr_init, .dump = nft_exthdr_dump, - .reduce = nft_exthdr_reduce, };static const struct nft_expr_ops nft_exthdr_tcp_set_ops = {
@@ -761,7 +731,6 @@ static const struct nft_expr_ops nft_ext .eval = nft_exthdr_tcp_set_eval, .init = nft_exthdr_tcp_set_init, .dump = nft_exthdr_dump_set, - .reduce = NFT_REDUCE_READONLY, };static const struct nft_expr_ops nft_exthdr_tcp_strip_ops = {
@@ -770,7 +739,6 @@ static const struct nft_expr_ops nft_ext .eval = nft_exthdr_tcp_strip_eval, .init = nft_exthdr_tcp_strip_init, .dump = nft_exthdr_dump_strip, - .reduce = NFT_REDUCE_READONLY, };static const struct nft_expr_ops nft_exthdr_sctp_ops = {
@@ -779,7 +747,6 @@ static const struct nft_expr_ops nft_ext .eval = nft_exthdr_sctp_eval, .init = nft_exthdr_init, .dump = nft_exthdr_dump, - .reduce = nft_exthdr_reduce, };static const struct nft_expr_ops nft_exthdr_dccp_ops = {
@@ -788,7 +755,6 @@ static const struct nft_expr_ops nft_ext .eval = nft_exthdr_dccp_eval, .init = nft_exthdr_dccp_init, .dump = nft_exthdr_dump, - .reduce = nft_exthdr_reduce, }; static const struct nft_expr_ops *
net/netfilter/nft_fib.c +0 -42
47 lines not on this page · raw message
net/netfilter/nft_fib_inet.c +0 -1
@@ -49,7 +49,6 @@ static const struct nft_expr_ops nft_fib .init = nft_fib_init, .dump = nft_fib_dump, .validate = nft_fib_validate, - .reduce = nft_fib_reduce, };static struct nft_expr_type nft_fib_inet_type__read_mostly = {
net/netfilter/nft_fib_netdev.c +0 -1
@@ -58,7 +58,6 @@ static const struct nft_expr_ops nft_fib .init = nft_fib_init, .dump = nft_fib_dump, .validate = nft_fib_validate, - .reduce = nft_fib_reduce, };static struct nft_expr_type nft_fib_netdev_type__read_mostly = {
net/netfilter/nft_flow_offload.c +0 -1
@@ -481,7 +481,6 @@ static const struct nft_expr_ops nft_flo .destroy = nft_flow_offload_destroy, .validate = nft_flow_offload_validate, .dump = nft_flow_offload_dump, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_flow_offload_type__read_mostly = {
net/netfilter/nft_fwd_netdev.c +0 -2
@@ -228,7 +228,6 @@ static const struct nft_expr_ops nft_fwd .init = nft_fwd_neigh_init, .dump = nft_fwd_neigh_dump, .validate = nft_fwd_validate, - .reduce = NFT_REDUCE_READONLY, };static const struct nft_expr_ops nft_fwd_netdev_ops = {
@@ -238,7 +237,6 @@ static const struct nft_expr_ops nft_fwd .init = nft_fwd_netdev_init, .dump = nft_fwd_netdev_dump, .validate = nft_fwd_validate, - .reduce = NFT_REDUCE_READONLY, .offload = nft_fwd_netdev_offload, .offload_action = nft_fwd_netdev_offload_action, };
net/netfilter/nft_hash.c +0 -36
@@ -165,16 +165,6 @@ nla_put_failure:return -1 ; } -static bool nft_jhash_reduce (struct nft_regs_track *track, -const struct nft_expr *expr) -{ -const struct nft_jhash *priv =nft_expr_priv (expr); - -nft_reg_track_cancel (track, priv->dreg,sizeof (u32)); - -return false; -} -static int nft_symhash_dump (struct sk_buff *skb,const struct nft_expr *expr,bool reset) {
@@ -195,30 +185,6 @@ nla_put_failure:return -1 ; } -static bool nft_symhash_reduce (struct nft_regs_track *track, -const struct nft_expr *expr) -{ -struct nft_symhash *priv =nft_expr_priv (expr); -struct nft_symhash *symhash; - -if (!nft_reg_track_cmp (track, expr, priv->dreg)) { -nft_reg_track_update (track, expr, priv->dreg,sizeof (u32)); -return false; - } - - symhash =nft_expr_priv (track->regs[priv->dreg].selector); -if (priv->offset != symhash->offset || - priv->modulus != symhash->modulus) { -nft_reg_track_update (track, expr, priv->dreg,sizeof (u32)); -return false; - } - -if (!track->regs[priv->dreg].bitwise) -return true; - -return false; -} -static struct nft_expr_type nft_hash_type;static const struct nft_expr_ops nft_jhash_ops = { .type = &nft_hash_type,
@@ -226,7 +192,6 @@ static const struct nft_expr_ops nft_jha .eval = nft_jhash_eval, .init = nft_jhash_init, .dump = nft_jhash_dump, - .reduce = nft_jhash_reduce, };static const struct nft_expr_ops nft_symhash_ops = {
@@ -235,7 +200,6 @@ static const struct nft_expr_ops nft_sym .eval = nft_symhash_eval, .init = nft_symhash_init, .dump = nft_symhash_dump, - .reduce = nft_symhash_reduce, }; static const struct nft_expr_ops *
net/netfilter/nft_immediate.c +0 -12
@@ -320,17 +320,6 @@ static bool nft_immediate_offload_actionreturn false; } -static bool nft_immediate_reduce (struct nft_regs_track *track, -const struct nft_expr *expr) -{ -const struct nft_immediate_expr *priv =nft_expr_priv (expr); - -if (priv->dreg !=NFT_REG_VERDICT ) -nft_reg_track_cancel (track, priv->dreg, priv->dlen); - -return false; -} -static const struct nft_expr_ops nft_imm_ops = { .type = &nft_imm_type, .size =NFT_EXPR_SIZE (sizeof (struct nft_immediate_expr )),
@@ -341,7 +330,6 @@ static const struct nft_expr_ops nft_imm .destroy = nft_immediate_destroy, .dump = nft_immediate_dump, .validate = nft_immediate_validate, - .reduce = nft_immediate_reduce, .offload = nft_immediate_offload, .offload_action = nft_immediate_offload_action, };
net/netfilter/nft_last.c +0 -1
@@ -125,7 +125,6 @@ static const struct nft_expr_ops nft_las .destroy = nft_last_destroy, .clone = nft_last_clone, .dump = nft_last_dump, - .reduce = NFT_REDUCE_READONLY, };struct nft_expr_type nft_last_type__read_mostly = {
net/netfilter/nft_limit.c +0 -2
@@ -243,7 +243,6 @@ static const struct nft_expr_ops nft_lim .destroy = nft_limit_pkts_destroy, .clone = nft_limit_pkts_clone, .dump = nft_limit_pkts_dump, - .reduce = NFT_REDUCE_READONLY, }; static void nft_limit_bytes_eval(const struct nft_expr *expr,
@@ -299,7 +298,6 @@ static const struct nft_expr_ops nft_lim .dump = nft_limit_bytes_dump, .clone = nft_limit_bytes_clone, .destroy = nft_limit_bytes_destroy, - .reduce = NFT_REDUCE_READONLY, }; static const struct nft_expr_ops *
net/netfilter/nft_log.c +0 -1
@@ -235,7 +235,6 @@ static const struct nft_expr_ops nft_log .init = nft_log_init, .destroy = nft_log_destroy, .dump = nft_log_dump, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_log_type__read_mostly = {
net/netfilter/nft_lookup.c +0 -12
@@ -232,17 +232,6 @@ static int nft_lookup_validate(const strreturn 0 ; } -static bool nft_lookup_reduce (struct nft_regs_track *track, -const struct nft_expr *expr) -{ -const struct nft_lookup *priv =nft_expr_priv (expr); - -if (priv->set->flags &NFT_SET_MAP ) -nft_reg_track_cancel (track, priv->dreg, priv->set->dlen); - -return false; -} -static const struct nft_expr_ops nft_lookup_ops = { .type = &nft_lookup_type, .size =NFT_EXPR_SIZE (sizeof (struct nft_lookup )),
@@ -253,7 +242,6 @@ static const struct nft_expr_ops nft_loo .destroy = nft_lookup_destroy, .dump = nft_lookup_dump, .validate = nft_lookup_validate, - .reduce = nft_lookup_reduce, };struct nft_expr_type nft_lookup_type__read_mostly = {
net/netfilter/nft_masq.c +0 -3
@@ -143,7 +143,6 @@ static const struct nft_expr_ops nft_mas .destroy = nft_masq_ipv4_destroy, .dump = nft_masq_dump, .validate = nft_masq_validate, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_masq_ipv4_type__read_mostly = {
@@ -171,7 +170,6 @@ static const struct nft_expr_ops nft_mas .destroy = nft_masq_ipv6_destroy, .dump = nft_masq_dump, .validate = nft_masq_validate, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_masq_ipv6_type__read_mostly = {
@@ -213,7 +211,6 @@ static const struct nft_expr_ops nft_mas .destroy = nft_masq_inet_destroy, .dump = nft_masq_dump, .validate = nft_masq_validate, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_masq_inet_type__read_mostly = {
net/netfilter/nft_meta.c +0 -45
67 lines not on this page · raw message
net/netfilter/nft_nat.c +0 -2
@@ -320,7 +320,6 @@ static const struct nft_expr_ops nft_nat .destroy = nft_nat_destroy, .dump = nft_nat_dump, .validate = nft_nat_validate, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_nat_type__read_mostly = {
@@ -351,7 +350,6 @@ static const struct nft_expr_ops nft_nat .destroy = nft_nat_destroy, .dump = nft_nat_dump, .validate = nft_nat_validate, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_inet_nat_type__read_mostly = {
net/netfilter/nft_numgen.c +0 -22
@@ -84,16 +84,6 @@ err:return err; } -static bool nft_ng_inc_reduce (struct nft_regs_track *track, -const struct nft_expr *expr) -{ -const struct nft_ng_inc *priv =nft_expr_priv (expr); - -nft_reg_track_cancel (track, priv->dreg,NFT_REG32_SIZE ); - -return false; -} -static int nft_ng_dump (struct sk_buff *skb,enum nft_registers dreg,u32 modulus,enum nft_ng_types type,u32 offset) {
@@ -178,16 +168,6 @@ static int nft_ng_random_dump(struct sk_ priv->offset); } -static bool nft_ng_random_reduce (struct nft_regs_track *track, -const struct nft_expr *expr) -{ -const struct nft_ng_random *priv =nft_expr_priv (expr); - -nft_reg_track_cancel (track, priv->dreg,NFT_REG32_SIZE ); - -return false; -} -static struct nft_expr_type nft_ng_type;static const struct nft_expr_ops nft_ng_inc_ops = { .type = &nft_ng_type,
@@ -196,7 +176,6 @@ static const struct nft_expr_ops nft_ng_ .init = nft_ng_inc_init, .destroy = nft_ng_inc_destroy, .dump = nft_ng_inc_dump, - .reduce = nft_ng_inc_reduce, };static const struct nft_expr_ops nft_ng_random_ops = {
@@ -205,7 +184,6 @@ static const struct nft_expr_ops nft_ng_ .eval = nft_ng_random_eval, .init = nft_ng_random_init, .dump = nft_ng_random_dump, - .reduce = nft_ng_random_reduce, }; static const struct nft_expr_ops *
net/netfilter/nft_objref.c +0 -2
@@ -123,7 +123,6 @@ static const struct nft_expr_ops nft_obj .deactivate = nft_objref_deactivate, .dump = nft_objref_dump, .validate = nft_objref_validate, - .reduce = NFT_REDUCE_READONLY, };struct nft_objref_map {
@@ -246,7 +245,6 @@ static const struct nft_expr_ops nft_obj .destroy = nft_objref_map_destroy, .dump = nft_objref_map_dump, .validate = nft_objref_map_validate, - .reduce = NFT_REDUCE_READONLY, }; static const struct nft_expr_ops *
net/netfilter/nft_osf.c +0 -25
@@ -136,30 +136,6 @@ static int nft_osf_validate(const structreturn nft_chain_validate_hooks (ctx->chain, hooks); } -static bool nft_osf_reduce (struct nft_regs_track *track, -const struct nft_expr *expr) -{ -struct nft_osf *priv =nft_expr_priv (expr); -struct nft_osf *osf; - -if (!nft_reg_track_cmp (track, expr, priv->dreg)) { -nft_reg_track_update (track, expr, priv->dreg,NFT_OSF_MAXGENRELEN ); -return false; - } - - osf =nft_expr_priv (track->regs[priv->dreg].selector); -if (priv->flags != osf->flags || - priv->ttl != osf->ttl) { -nft_reg_track_update (track, expr, priv->dreg,NFT_OSF_MAXGENRELEN ); -return false; - } - -if (!track->regs[priv->dreg].bitwise) -return true; - -return false; -} -static struct nft_expr_type nft_osf_type;static const struct nft_expr_ops nft_osf_op = { .eval = nft_osf_eval,
@@ -168,7 +144,6 @@ static const struct nft_expr_ops nft_osf .dump = nft_osf_dump, .type = &nft_osf_type, .validate = nft_osf_validate, - .reduce = nft_osf_reduce, };static struct nft_expr_type nft_osf_type__read_mostly = {
net/netfilter/nft_payload.c +0 -47
77 lines not on this page · raw message
net/netfilter/nft_queue.c +0 -2
@@ -191,7 +191,6 @@ static const struct nft_expr_ops nft_que .init = nft_queue_init, .dump = nft_queue_dump, .validate = nft_queue_validate, - .reduce = NFT_REDUCE_READONLY, };static const struct nft_expr_ops nft_queue_sreg_ops = {
@@ -201,7 +200,6 @@ static const struct nft_expr_ops nft_que .init = nft_queue_sreg_init, .dump = nft_queue_sreg_dump, .validate = nft_queue_validate, - .reduce = NFT_REDUCE_READONLY, }; static const struct nft_expr_ops *
net/netfilter/nft_quota.c +0 -1
@@ -265,7 +265,6 @@ static const struct nft_expr_ops nft_quo .destroy = nft_quota_destroy, .clone = nft_quota_clone, .dump = nft_quota_dump, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_quota_type__read_mostly = {
net/netfilter/nft_range.c +0 -1
@@ -138,7 +138,6 @@ static const struct nft_expr_ops nft_ran .eval = nft_range_eval, .init = nft_range_init, .dump = nft_range_dump, - .reduce = NFT_REDUCE_READONLY, };struct nft_expr_type nft_range_type__read_mostly = {
net/netfilter/nft_redir.c +0 -3
@@ -146,7 +146,6 @@ static const struct nft_expr_ops nft_red .destroy = nft_redir_ipv4_destroy, .dump = nft_redir_dump, .validate = nft_redir_validate, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_redir_ipv4_type__read_mostly = {
@@ -174,7 +173,6 @@ static const struct nft_expr_ops nft_red .destroy = nft_redir_ipv6_destroy, .dump = nft_redir_dump, .validate = nft_redir_validate, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_redir_ipv6_type__read_mostly = {
@@ -203,7 +201,6 @@ static const struct nft_expr_ops nft_red .destroy = nft_redir_inet_destroy, .dump = nft_redir_dump, .validate = nft_redir_validate, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_redir_inet_type__read_mostly = {
net/netfilter/nft_reject_inet.c +0 -1
@@ -79,7 +79,6 @@ static const struct nft_expr_ops nft_rej .init = nft_reject_init, .dump = nft_reject_dump, .validate = nft_reject_inet_validate, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_reject_inet_type__read_mostly = {
net/netfilter/nft_reject_netdev.c +0 -1
@@ -158,7 +158,6 @@ static const struct nft_expr_ops nft_rej .init = nft_reject_init, .dump = nft_reject_dump, .validate = nft_reject_netdev_validate, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_reject_netdev_type__read_mostly = {
net/netfilter/nft_rt.c +0 -1
@@ -195,7 +195,6 @@ static const struct nft_expr_ops nft_rt_ .init = nft_rt_get_init, .dump = nft_rt_get_dump, .validate = nft_rt_validate, - .reduce = NFT_REDUCE_READONLY, };struct nft_expr_type nft_rt_type__read_mostly = {
net/netfilter/nft_socket.c +0 -26
@@ -249,31 +249,6 @@ static int nft_socket_dump(struct sk_bufreturn 0 ; } -static bool nft_socket_reduce (struct nft_regs_track *track, -const struct nft_expr *expr) -{ -const struct nft_socket *priv =nft_expr_priv (expr); -const struct nft_socket *socket; - -if (!nft_reg_track_cmp (track, expr, priv->dreg)) { -nft_reg_track_update (track, expr, priv->dreg, priv->len); -return false; - } - - socket =nft_expr_priv (track->regs[priv->dreg].selector); -if (priv->key != socket->key || - priv->dreg != socket->dreg || - priv->level != socket->level) { -nft_reg_track_update (track, expr, priv->dreg, priv->len); -return false; - } - -if (!track->regs[priv->dreg].bitwise) -return true; - -return nft_expr_reduce_bitwise (track, expr); -} -static int nft_socket_validate (const struct nft_ctx *ctx,const struct nft_expr *expr) {
@@ -296,7 +271,6 @@ static const struct nft_expr_ops nft_soc .init = nft_socket_init, .dump = nft_socket_dump, .validate = nft_socket_validate, - .reduce = nft_socket_reduce, };static struct nft_expr_type nft_socket_type__read_mostly = {
net/netfilter/nft_synproxy.c +0 -1
@@ -290,7 +290,6 @@ static const struct nft_expr_ops nft_syn .dump = nft_synproxy_dump, .type = &nft_synproxy_type, .validate = nft_synproxy_validate, - .reduce = NFT_REDUCE_READONLY, };static struct nft_expr_type nft_synproxy_type__read_mostly = {
net/netfilter/nft_tproxy.c +0 -1
@@ -331,7 +331,6 @@ static const struct nft_expr_ops nft_tpr .init = nft_tproxy_init, .destroy = nft_tproxy_destroy, .dump = nft_tproxy_dump, - .reduce = NFT_REDUCE_READONLY, .validate = nft_tproxy_validate, };
net/netfilter/nft_tunnel.c +0 -26
@@ -124,31 +124,6 @@ nla_put_failure:return -1 ; } -static bool nft_tunnel_get_reduce (struct nft_regs_track *track, -const struct nft_expr *expr) -{ -const struct nft_tunnel *priv =nft_expr_priv (expr); -const struct nft_tunnel *tunnel; - -if (!nft_reg_track_cmp (track, expr, priv->dreg)) { -nft_reg_track_update (track, expr, priv->dreg, priv->len); -return false; - } - - tunnel =nft_expr_priv (track->regs[priv->dreg].selector); -if (priv->key != tunnel->key || - priv->dreg != tunnel->dreg || - priv->mode != tunnel->mode) { -nft_reg_track_update (track, expr, priv->dreg, priv->len); -return false; - } - -if (!track->regs[priv->dreg].bitwise) -return true; - -return false; -} -static struct nft_expr_type nft_tunnel_type;static const struct nft_expr_ops nft_tunnel_get_ops = { .type = &nft_tunnel_type,
@@ -156,7 +131,6 @@ static const struct nft_expr_ops nft_tun .eval = nft_tunnel_get_eval, .init = nft_tunnel_get_init, .dump = nft_tunnel_get_dump, - .reduce = nft_tunnel_get_reduce, };static struct nft_expr_type nft_tunnel_type__read_mostly = {
net/netfilter/nft_xfrm.c +0 -27
@@ -258,32 +258,6 @@ static int nft_xfrm_validate(const strucreturn nft_chain_validate_hooks (ctx->chain, hooks); } -static bool nft_xfrm_reduce (struct nft_regs_track *track, -const struct nft_expr *expr) -{ -const struct nft_xfrm *priv =nft_expr_priv (expr); -const struct nft_xfrm *xfrm; - -if (!nft_reg_track_cmp (track, expr, priv->dreg)) { -nft_reg_track_update (track, expr, priv->dreg, priv->len); -return false; - } - - xfrm =nft_expr_priv (track->regs[priv->dreg].selector); -if (priv->key != xfrm->key || - priv->dreg != xfrm->dreg || - priv->dir != xfrm->dir || - priv->spnum != xfrm->spnum) { -nft_reg_track_update (track, expr, priv->dreg, priv->len); -return false; - } - -if (!track->regs[priv->dreg].bitwise) -return true; - -return nft_expr_reduce_bitwise (track, expr); -} -static struct nft_expr_type nft_xfrm_type;static const struct nft_expr_ops nft_xfrm_get_ops = { .type = &nft_xfrm_type,
@@ -292,7 +266,6 @@ static const struct nft_expr_ops nft_xfr .init = nft_xfrm_get_init, .dump = nft_xfrm_get_dump, .validate = nft_xfrm_validate, - .reduce = nft_xfrm_reduce, };static struct nft_expr_type nft_xfrm_type__read_mostly = {
Greg Kroah-Hartman
maintainerPATCH 419/484 netfilter: nft_fib: reject fib expression on the netdev egress hook
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Theodor Arsenij Larionov-Trichkine <[email protected]>
[ Upstream commit d07955dd34ecae17d35d8c7d0a273a3fba653a8c ]
A fib expression in a netdev egress base chain dereferences nft_in(pkt), NULL on the transmit path, causing a NULL pointer dereference at eval. nft_fib_validate() masks the hook with NF_INET_* values, but netdev hook numbers are a separate enum that aliases them (NF_NETDEV_EGRESS == NF_INET_LOCAL_IN), so an egress chain passes validation and then faults.
Add nft_fib_netdev_validate() that limits each result/flag to the netdev hook where the device it reads exists: the input-device cases (OIF, OIFNAME, ADDRTYPE with F_IIF) to ingress, the output-device case (ADDRTYPE with F_OIF) to egress, ADDRTYPE with no device flag to both. Also restrict nft_fib_validate() to NFPROTO_IPV4/IPV6/INET so its NF_INET_* masks are not applied to another family's hooks.
--- net/netfilter/nft_fib.c | 9 +++++++++ net/netfilter/nft_fib_netdev.c | 29 ++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-)
net/netfilter/nft_fib.c +9 -0
@@ -31,6 +31,15 @@ int nft_fib_validate(const struct nft_ctconst struct nft_fib *priv =nft_expr_priv (expr);unsigned int hooks; +switch (ctx->family) { +case NFPROTO_IPV4 : +case NFPROTO_IPV6 : +case NFPROTO_INET : +break ; +default : +return -EOPNOTSUPP ; + } +switch (priv->result) {case NFT_FIB_RESULT_OIF :case NFT_FIB_RESULT_OIFNAME :
net/netfilter/nft_fib_netdev.c +28 -1
@@ -50,6 +50,33 @@ static void nft_fib_netdev_eval(const st regs->verdict.code =NFT_BREAK ; } +static int nft_fib_netdev_validate (const struct nft_ctx *ctx, +const struct nft_expr *expr) +{ +const struct nft_fib *priv =nft_expr_priv (expr); +unsigned int hooks; + +switch (priv->result) { +case NFT_FIB_RESULT_OIF : +case NFT_FIB_RESULT_OIFNAME : + hooks = (1 <<NF_NETDEV_INGRESS ); +break ; +case NFT_FIB_RESULT_ADDRTYPE : +if (priv->flags &NFTA_FIB_F_IIF ) + hooks = (1 <<NF_NETDEV_INGRESS ); +else if (priv->flags &NFTA_FIB_F_OIF ) + hooks = (1 <<NF_NETDEV_EGRESS ); +else + hooks = (1 <<NF_NETDEV_INGRESS ) | + (1 <<NF_NETDEV_EGRESS ); +break ; +default : +return -EINVAL ; + } + +return nft_chain_validate_hooks (ctx->chain, hooks); +} +static struct nft_expr_type nft_fib_netdev_type;static const struct nft_expr_ops nft_fib_netdev_ops = { .type = &nft_fib_netdev_type,
@@ -57,7 +84,7 @@ static const struct nft_expr_ops nft_fib .eval = nft_fib_netdev_eval, .init = nft_fib_init, .dump = nft_fib_dump, - .validate = nft_fib_validate, + .validate = nft_fib_netdev_validate, };static struct nft_expr_type nft_fib_netdev_type__read_mostly = {
Greg Kroah-Hartman
maintainerPATCH 420/484 NFSD: pass nfsd_file to nfsd_iter_read()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mike Snitzer <[email protected]>
[ Upstream commit 803bc849f0039291f546ba0e2237faebeb5c073e ]
Prepare for nfsd_iter_read() to use the DIO alignment stored in nfsd_file by passing the nfsd_file to nfsd_iter_read() rather than just the file which is associaed with the nfsd_file.
This means nfsd4_encode_readv() now also needs the nfsd_file rather than the file. Instead of changing the file arg to be the nfsd_file, we discard the file arg as the nfsd_file (and indeed the file) is already available via the "read" argument.
Stable-dep-of: 18c1cc698861 ("SUNRPC: Return an error from xdr_buf_to_bvec() on overflow")
--- fs/nfsd/nfs4xdr.c | 8 ++++---- fs/nfsd/vfs.c | 7 ++++--- fs/nfsd/vfs.h | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-)
fs/nfsd/nfs4xdr.c +4 -4
@@ -4096,7 +4096,7 @@ out_err:static __be32 nfsd4_encode_readv (struct nfsd4_compoundres *resp,struct nfsd4_read *read, -struct file *file,unsigned long maxcount) +unsigned long maxcount) {struct xdr_stream *xdr = resp->xdr;unsigned int base = xdr->buf->page_len & ~PAGE_MASK ;
@@ -4107,7 +4107,7 @@ static __be32 nfsd4_encode_readv(structif (xdr_reserve_space_vec (xdr, maxcount) <0 )return nfserr_resource; - nfserr =nfsd_iter_read (resp->rqstp, read->rd_fhp, file, + nfserr =nfsd_iter_read (resp->rqstp, read->rd_fhp, read->rd_nf, read->rd_offset, &maxcount, base, &read->rd_eof); read->rd_length = maxcount;
@@ -4155,7 +4155,7 @@ nfsd4_encode_read(struct nfsd4_compoundrif (file->f_op->splice_read && splice_ok) nfserr =nfsd4_encode_splice_read (resp, read, file, maxcount);else - nfserr =nfsd4_encode_readv (resp, read, file, maxcount); + nfserr =nfsd4_encode_readv (resp, read, maxcount);if (nfserr) {xdr_truncate_encode (xdr, starting_len);return nfserr;
@@ -4906,7 +4906,7 @@ nfsd4_encode_read_plus_data(struct nfsd4if (file->f_op->splice_read && splice_ok) nfserr =nfsd4_encode_splice_read (resp, read, file, maxcount);else - nfserr =nfsd4_encode_readv (resp, read, file, maxcount); + nfserr =nfsd4_encode_readv (resp, read, maxcount);if (nfserr)return nfserr;
fs/nfsd/vfs.c +4 -3
@@ -1061,7 +1061,7 @@ __be32 nfsd_splice_read(struct svc_rqst* nfsd_iter_read - Perform a VFS read using an iterator * @rqstp: RPC transaction context * @fhp: file handle of file to be read -* @file: opened struct file of file to be read +* @nf: opened struct nfsd_file of file to be read * @offset: starting byte offset * @count: IN: requested number of bytes; OUT: number of bytes read * @base: offset in first page of read buffer
@@ -1074,9 +1074,10 @@ __be32 nfsd_splice_read(struct svc_rqst* returned. */ __be32 nfsd_iter_read (struct svc_rqst *rqstp,struct svc_fh *fhp, -struct file *file,loff_t offset,unsigned long *count, +struct nfsd_file *nf,loff_t offset,unsigned long *count,unsigned int base,u32 *eof) { +struct file *file = nf->nf_file;unsigned long v, total;struct iov_iter iter;loff_t ppos = offset;
@@ -1258,7 +1259,7 @@ __be32 nfsd_read(struct svc_rqst *rqstp,if (file->f_op->splice_read &&test_bit (RQ_SPLICE_OK , &rqstp->rq_flags)) err =nfsd_splice_read (rqstp, fhp, file, offset, count, eof);else - err =nfsd_iter_read (rqstp, fhp, file, offset, count,0 , eof); + err =nfsd_iter_read (rqstp, fhp, nf, offset, count,0 , eof);nfsd_file_put (nf);trace_nfsd_read_done (rqstp, fhp, offset, *count);
fs/nfsd/vfs.h +1 -1
@@ -120,7 +120,7 @@ __be32 nfsd_splice_read(struct svc_rqstunsigned long *count, u32 *eof);__be32 nfsd_iter_read (struct svc_rqst *rqstp,struct svc_fh *fhp, -struct file *file,loff_t offset, +struct nfsd_file *nf,loff_t offset,unsigned long *count,unsigned int base,u32 *eof); __be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
Greg Kroah-Hartman
maintainerPATCH 421/484 sunrpc: allocate a separate bvec array for socket sends
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Layton <[email protected]>
[ Upstream commit 6b3b697d65d46a0f640216a3f6c72856c159c567 ]
svc_tcp_sendmsg() calls xdr_buf_to_bvec() with the second slot of rq_bvec as the start, but doesn't reduce the array length by one, which could lead to an array overrun. Also, rq_bvec is always rq_maxpages in length, which can be too short in some cases, since the TCP record marker consumes a slot.
Fix both problems by adding a separate bvec array to the svc_sock that is specifically for sending. For TCP, make this array one slot longer than rq_maxpages, to account for the record marker. For UDP, only allocate as large an array as we need since it's limited to 64k of payload.
Stable-dep-of: 18c1cc698861 ("SUNRPC: Return an error from xdr_buf_to_bvec() on overflow")
--- include/linux/sunrpc/svcsock.h | 3 +++ net/sunrpc/svcsock.c | 37 ++++++++++++++++++++++++++++--------- 2 files changed, 31 insertions(+), 9 deletions(-)
include/linux/sunrpc/svcsock.h +3 -0
@@ -26,6 +26,9 @@ struct svc_sock {void (*sk_odata)(struct sock *);void (*sk_owspace)(struct sock *); +/* For sends (protected by xpt_mutex) */ +struct bio_vec *sk_bvec; +/* private TCP part */ /* On-the-wire fragment header: */ __be32 sk_marker;
net/sunrpc/svcsock.c +28 -9
@@ -68,6 +68,17 @@#define RPCDBG_FACILITY RPCDBG_SVCXPRT +/* +* For UDP: +* 1 for header page +* enough pages for RPCSVC_MAXPAYLOAD_UDP +* 1 in case payload is not aligned +* 1 for tail page +*/ +enum { +SUNRPC_MAX_UDP_SENDPAGES =1 +RPCSVC_MAXPAYLOAD_UDP /PAGE_SIZE +1 +1 +}; +/* To-do: to avoid tying up an nfsd thread while waiting for a * handshake request, the request could instead be deferred. */
@@ -750,15 +761,14 @@ static int svc_udp_sendto(struct svc_rqsif (svc_xprt_is_dead (xprt)) goto out_notconn; - count =xdr_buf_to_bvec (rqstp->rq_bvec, -ARRAY_SIZE (rqstp->rq_bvec), xdr); + count =xdr_buf_to_bvec (svsk->sk_bvec,SUNRPC_MAX_UDP_SENDPAGES , xdr); -iov_iter_bvec (&msg.msg_iter,ITER_SOURCE , rqstp->rq_bvec, +iov_iter_bvec (&msg.msg_iter,ITER_SOURCE , svsk->sk_bvec, count, rqstp->rq_res.len); err =sock_sendmsg (svsk->sk_sock, &msg);if (err == -ECONNREFUSED ) {/* ICMP error on earlier request. */ -iov_iter_bvec (&msg.msg_iter,ITER_SOURCE , rqstp->rq_bvec, +iov_iter_bvec (&msg.msg_iter,ITER_SOURCE , svsk->sk_bvec, count, rqstp->rq_res.len); err =sock_sendmsg (svsk->sk_sock, &msg); }
@@ -1257,19 +1267,19 @@ static int svc_tcp_sendmsg(struct svc_so *sentp =0 ;/* The stream record marker is copied into a temporary page -* fragment buffer so that it can be included in rq_bvec. +* fragment buffer so that it can be included in sk_bvec. */ buf =page_frag_alloc (&svsk->sk_frag_cache,sizeof (marker),GFP_KERNEL );if (!buf)return -ENOMEM ;memcpy (buf, &marker,sizeof (marker)); -bvec_set_virt (rqstp->rq_bvec, buf,sizeof (marker)); +bvec_set_virt (svsk->sk_bvec, buf,sizeof (marker)); - count =xdr_buf_to_bvec (rqstp->rq_bvec +1 , -ARRAY_SIZE (rqstp->rq_bvec) -1 , &rqstp->rq_res); + count =xdr_buf_to_bvec (svsk->sk_bvec +1 ,RPCSVC_MAXPAGES , + &rqstp->rq_res); -iov_iter_bvec (&msg.msg_iter,ITER_SOURCE , rqstp->rq_bvec, +iov_iter_bvec (&msg.msg_iter,ITER_SOURCE , svsk->sk_bvec,1 + count,sizeof (marker) + rqstp->rq_res.len); ret =sock_sendmsg (svsk->sk_sock, &msg);page_frag_free (buf);
@@ -1432,6 +1442,13 @@ static struct svc_sock *svc_setup_socketif (!svsk)return ERR_PTR (-ENOMEM ); + svsk->sk_bvec =kcalloc (RPCSVC_MAXPAGES +1 ,sizeof (*svsk->sk_bvec), +GFP_KERNEL ); +if (!svsk->sk_bvec) { +kfree (svsk); +return ERR_PTR (-ENOMEM ); + } + inet = sock->sk;if (pmap_register) {
@@ -1441,6 +1458,7 @@ static struct svc_sock *svc_setup_socket inet->sk_protocol, ntohs(inet_sk(inet)->inet_sport));if (err <0 ) { +kfree (svsk->sk_bvec);kfree (svsk);return ERR_PTR (err); }
@@ -1660,5 +1678,6 @@ static void svc_sock_free(struct svc_xprif (pfc->va)__page_frag_cache_drain (virt_to_head_page (pfc->va), pfc->pagecnt_bias); +kfree (svsk->sk_bvec);kfree (svsk); }
Greg Kroah-Hartman
maintainerPATCH 422/484 SUNRPC: Add helpers to convert xdr_buf byte ranges to scatterlists
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit e9be933959b581effd426f93b86654f5fbf0c574 ]
The crypto/krb5 library accepts data in scatterlist form, but the GSS-API layer presents RPC payloads as struct xdr_buf. Bridge that gap with a pair of helper functions:
xdr_buf_to_sg() - populate a caller-supplied scatterlist
array from a byte range
xdr_buf_to_sg_alloc() - populate a caller-supplied inline
scatterlist, chaining to a heap- allocated overflow for large payloads
The inline array (typically stack-allocated at eight entries) covers the common case of small RPCs with no heap allocation on the encrypt/decrypt path. Only buffers spanning many pages incur a kmalloc for the chained extension.
The segment-walking logic follows the same head, page array, tail traversal as xdr_process_buf(), but populates a scatterlist directly rather than invoking a per-segment callback. sg_next() traversal makes the walker safe for chained scatterlists. Once subsequent patches reroute all per-message crypto operations through crypto/krb5, xdr_process_buf() loses its last callers and is removed.
Stable-dep-of: 18c1cc698861 ("SUNRPC: Return an error from xdr_buf_to_bvec() on overflow")
--- include/linux/sunrpc/xdr.h | 15 +++ net/sunrpc/xdr.c | 199 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 214 insertions(+)
include/linux/sunrpc/xdr.h +15 -0
@@ -141,6 +141,21 @@ int xdr_alloc_bvec(struct xdr_buf *buf,void xdr_free_bvec (struct xdr_buf *buf);unsigned int xdr_buf_to_bvec (struct bio_vec *bvec,unsigned int bvec_size,const struct xdr_buf *xdr); +int xdr_buf_to_sg (const struct xdr_buf *buf,unsigned int offset, +unsigned int len,struct scatterlist *sg,unsigned int nsg); +int xdr_buf_to_sg_alloc (const struct xdr_buf *buf,unsigned int offset, +unsigned int len,struct scatterlist *sg_head, +unsigned int sg_head_nents, +struct scatterlist **sg_overflow,gfp_t gfp); + +/* +* Inline scatterlist entries for xdr_buf_to_sg_alloc(). Sized to cover the +* head kvec, tail kvec, and a few page fragments without any heap allocation. +*/ +enum { +XDR_BUF_TO_SG_NENTS =8 , +}; +static inline __be32 *xdr_encode_array (__be32 *p,const void *s,unsigned int len) {
net/sunrpc/xdr.c +199 -0
205 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 423/484 SUNRPC: Return an error from xdr_buf_to_bvec() on overflow
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 18c1cc69886192e33536498289d26dba6894e3d5 ]
xdr_buf_to_bvec() returns a slot count even when the caller's bvec budget is exhausted partway through the xdr_buf. Callers feed that count into iov_iter_bvec() and continue as if the conversion had succeeded, silently sending or writing fewer bytes than the data length declares. For an NFS WRITE the server reports the truncated transfer to the client as full success.
The overflow represents an internal invariant violation: a higher layer reserved a bvec budget too small for the xdr_buf it then asked the encoder to convert. That is a server-side fault, not a media I/O failure and not a malformed client argument.
Change xdr_buf_to_bvec() to return a signed int and have the overflow label return -ESERVERFAULT. Update the three callers to detect the negative return and fail the request: nfsd_vfs_write() folds the error into host_err, which nfserrno() translates to nfserr_serverfault for the WRITE reply; svc_udp_sendto() and svc_tcp_sendmsg() propagate the error out of the send path.
--- include/linux/sunrpc/xdr.h | 4 ++-- net/sunrpc/svcsock.c | 14 ++++++++++++-- net/sunrpc/xdr.c | 11 ++++++----- 3 files changed, 20 insertions(+), 9 deletions(-)
include/linux/sunrpc/xdr.h +2 -2
@@ -139,8 +139,8 @@ void xdr_terminate_string(const struct xsize_t xdr_buf_pagecount (const struct xdr_buf *buf);int xdr_alloc_bvec (struct xdr_buf *buf,gfp_t gfp);void xdr_free_bvec (struct xdr_buf *buf); -unsigned int xdr_buf_to_bvec (struct bio_vec *bvec,unsigned int bvec_size, -const struct xdr_buf *xdr); +int xdr_buf_to_bvec (struct bio_vec *bvec,unsigned int bvec_size, +const struct xdr_buf *xdr);int xdr_buf_to_sg (const struct xdr_buf *buf,unsigned int offset,unsigned int len,struct scatterlist *sg,unsigned int nsg); int xdr_buf_to_sg_alloc(const struct xdr_buf *buf, unsigned int offset,
net/sunrpc/svcsock.c +12 -2
@@ -748,7 +748,7 @@ static int svc_udp_sendto(struct svc_rqs .msg_flags = MSG_SPLICE_PAGES, .msg_controllen = sizeof(buffer), }; -unsigned int count; +int count;int err;svc_udp_release_ctxt (xprt, rqstp->rq_xprt_ctxt);
@@ -762,6 +762,10 @@ static int svc_udp_sendto(struct svc_rqs goto out_notconn; count =xdr_buf_to_bvec (svsk->sk_bvec,SUNRPC_MAX_UDP_SENDPAGES , xdr); +if (count <0 ) { + err = count; + goto out_trace; + }iov_iter_bvec (&msg.msg_iter,ITER_SOURCE , svsk->sk_bvec, count, rqstp->rq_res.len);
@@ -773,6 +777,7 @@ static int svc_udp_sendto(struct svc_rqs err =sock_sendmsg (svsk->sk_sock, &msg); } +out_trace:trace_svcsock_udp_send (xprt, err);mutex_unlock (&xprt->xpt_mutex);
@@ -1260,7 +1265,7 @@ static int svc_tcp_sendmsg(struct svc_sostruct msghdr msg = { .msg_flags =MSG_SPLICE_PAGES , }; -unsigned int count; +int count;void *buf;int ret;
@@ -1278,10 +1283,15 @@ static int svc_tcp_sendmsg(struct svc_so count =xdr_buf_to_bvec (svsk->sk_bvec +1 ,RPCSVC_MAXPAGES , &rqstp->rq_res); +if (count <0 ) { + ret = count; + goto out; + }iov_iter_bvec (&msg.msg_iter,ITER_SOURCE , svsk->sk_bvec,1 + count,sizeof (marker) + rqstp->rq_res.len); ret =sock_sendmsg (svsk->sk_sock, &msg); +out:page_frag_free (buf);if (ret <0 )return ret;
net/sunrpc/xdr.c +6 -5
@@ -167,13 +167,14 @@ xdr_free_bvec(struct xdr_buf *buf)/** * xdr_buf_to_bvec - Copy components of an xdr_buf into a bio_vec array * @bvec: bio_vec array to populate -* @bvec_size: element count of @bio_vec +* @bvec_size: element count of @bvec * @xdr: xdr_buf to be copied * -* Returns the number of entries consumed in @bvec. +* Returns the number of entries consumed in @bvec on success, or +* -ESERVERFAULT when @xdr does not fit within @bvec_size entries. */ -unsigned int xdr_buf_to_bvec (struct bio_vec *bvec,unsigned int bvec_size, -const struct xdr_buf *xdr) +int xdr_buf_to_bvec (struct bio_vec *bvec,unsigned int bvec_size, +const struct xdr_buf *xdr) {const struct kvec *head = xdr->head;const struct kvec *tail = xdr->tail;
@@ -215,7 +216,7 @@ unsigned int xdr_buf_to_bvec(struct bio_ bvec_overflow:pr_warn_once ("%s: bio_vec array overflow\n" , __func__); -return count; +return -ESERVERFAULT ; }/**
Greg Kroah-Hartman
maintainerPATCH 424/484 mm/mm_init: fix pageblock migratetype for ZONE_DEVICE compound pages
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Muchun Song <[email protected]>
[ Upstream commit 94405c6136839f7c462249c8b4b957bcb9527a9d ]
The memmap_init_zone_device() function only initializes the migratetype of the first pageblock of a compound page. If the compound page size exceeds pageblock_nr_pages (e.g., 1GB hugepages with 2MB pageblocks), subsequent pageblocks in the compound page remain uninitialized.
Move the migratetype initialization out of __init_zone_device_page() and into a separate pageblock_migratetype_init_range() function. This iterates over the entire PFN range of the memory, ensuring that all pageblocks are correctly initialized.
Also remove the stale confusing comment about MEMINIT_HOTPLUG above the migratetype setting since it is an obsolete relic from commit 966cf44f637e ("mm: defer ZONE_DEVICE page initialization to the point where we init pgmap") and no longer makes sense here.
--- mm/mm_init.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-)
mm/mm_init.c +19 -15
@@ -649,6 +649,20 @@ static inline void fixup_hashdist(void)static inline void fixup_hashdist (void ) {}#endif /* CONFIG_NUMA */ +#ifdef CONFIG_ZONE_DEVICE +static __meminit void pageblock_migratetype_init_range (unsigned long pfn, +unsigned long nr_pages,int migratetype) +{ +const unsigned long end = pfn + nr_pages; + +for (pfn =pageblock_align (pfn); pfn < end; pfn += pageblock_nr_pages) { +set_pageblock_migratetype (pfn_to_page (pfn), migratetype); +if (IS_ALIGNED (pfn,PAGES_PER_SECTION )) +cond_resched (); + } +} +#endif +#ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT static inline void pgdat_set_deferred_range (pg_data_t *pgdat) {
@@ -993,21 +1007,6 @@ static void __ref __init_zone_device_pag page->zone_device_data =NULL ;/* -* Mark the block movable so that blocks are reserved for -* movable at startup. This will force kernel allocations -* to reserve their blocks rather than leaking throughout -* the address space during boot when many long-lived -* kernel allocations are made. -* -* Please note that MEMINIT_HOTPLUG path doesn't clear memmap -* because this is done early in section_activate() -*/ -if (pageblock_aligned (pfn)) { -set_pageblock_migratetype (page,MIGRATE_MOVABLE ); -cond_resched (); - } - -/* * ZONE_DEVICE pages are released directly to the driver page allocator * which will set the page count to 1 when allocating the page. */
@@ -1098,6 +1097,9 @@ void __ref memmap_init_zone_device(struc__init_zone_device_page (page, pfn, zone_idx, nid, pgmap); +if (IS_ALIGNED (pfn,PAGES_PER_SECTION )) +cond_resched (); +if (pfns_per_compound ==1 )continue ;
@@ -1105,6 +1107,8 @@ void __ref memmap_init_zone_device(struc compound_nr_pages(pfn, altmap, pgmap)); } +pageblock_migratetype_init_range (start_pfn, nr_pages,MIGRATE_MOVABLE ); +pr_debug ("%s initialised %lu pages in %ums\n" , __func__, nr_pages,jiffies_to_msecs (jiffies - start)); }
Greg Kroah-Hartman
maintainerPATCH 425/484 mtd: maps: vmu-flash: fix fault in unaligned fixup
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Fuchs <[email protected]>
[ Upstream commit 79d1661502c6e4b6f626185cef72cf2fa78116e1 ]
Use kzalloc_obj() / kzalloc_objs() to allocate the memcard structs, instead of kmalloc_obj() / kmalloc_objs() to prevent access to uninitialized data.
Fixes runtime error: Fault in unaligned fixup: 0000 [#1] at mtd_get_fact_prot_info.
--- drivers/mtd/maps/vmu-flash.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-)
drivers/mtd/maps/vmu-flash.c +3 -5
@@ -610,7 +610,7 @@ static int vmu_connect(struct maple_devi basic_flash_data =be32_to_cpu (mdev->devinfo.function_data[c -1 ]); - card =kmalloc (sizeof (struct memcard ),GFP_KERNEL ); + card = kzalloc_obj(struct memcard);if (!card) { error = -ENOMEM ; goto fail_nomem;
@@ -628,15 +628,13 @@ static int vmu_connect(struct maple_devi* Not sure there are actually any multi-partition devices in the * real world, but the hardware supports them, so, so will we */ - card->parts =kmalloc_array (card->partitions,sizeof (struct vmupart ), -GFP_KERNEL ); + card->parts = kzalloc_objs(struct vmupart, card->partitions);if (!card->parts) { error = -ENOMEM ; goto fail_partitions; } - card->mtd =kmalloc_array (card->partitions,sizeof (struct mtd_info ), -GFP_KERNEL ); + card->mtd = kzalloc_objs(struct mtd_info, card->partitions);if (!card->mtd) { error = -ENOMEM ; goto fail_mtd_info;
Greg Kroah-Hartman
maintainerPATCH 426/484 mtd: rawnand: Add a helper for calculating a page index
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Miquel Raynal <[email protected]>
[ Upstream commit df9803bf5a91e3599f12b53c94722f2c4e144a86 ]
For LUN crossing boundaries, it is handy to know what is the index of the last page in a LUN. This helper will soon be reused. At the same time I rename page_per_lun to ppl in the calling function to clarify the lines.
Stable-dep-of: 8e4531667d71 ("mtd: rawnand: Pause continuous reads at block boundaries")
--- drivers/mtd/nand/raw/nand_base.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-)
drivers/mtd/nand/raw/nand_base.c +11 -5
@@ -1212,19 +1212,25 @@ static int nand_lp_exec_read_page_op(strreturn nand_exec_op (chip, &op); } +static unsigned int rawnand_last_page_of_lun (unsigned int pages_per_lun,unsigned int lun) +{ +/* lun is expected to be very small */ +return (lun * pages_per_lun) + pages_per_lun -1 ; +} +static void rawnand_cap_cont_reads (struct nand_chip *chip) {struct nand_memory_organization *memorg; -unsigned int pages_per_lun, first_lun, last_lun; +unsigned int ppl, first_lun, last_lun; memorg =nanddev_get_memorg (&chip->base); - pages_per_lun = memorg->pages_per_eraseblock * memorg->eraseblocks_per_lun; - first_lun = chip->cont_read.first_page / pages_per_lun; - last_lun = chip->cont_read.last_page / pages_per_lun; + ppl = memorg->pages_per_eraseblock * memorg->eraseblocks_per_lun; + first_lun = chip->cont_read.first_page / ppl; + last_lun = chip->cont_read.last_page / ppl;/* Prevent sequential cache reads across LUN boundaries */ if (first_lun != last_lun) - chip->cont_read.pause_page = first_lun * pages_per_lun + pages_per_lun -1 ; + chip->cont_read.pause_page =rawnand_last_page_of_lun (ppl, first_lun);else chip->cont_read.pause_page = chip->cont_read.last_page; }
Greg Kroah-Hartman
maintainerPATCH 427/484 mtd: rawnand: Ensure all continuous terms are always in sync
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Miquel Raynal <[email protected]>
[ Upstream commit 6fb075fca63c3486612986eeff84ed4179644038 ]
While crossing a LUN boundary, it is probably safer (and clearer) to keep all members of the continuous read structure aligned, including the pause page (which is the last page of the lun or the last page of the continuous read). Once these members properly in sync, we can use the rawnand_cap_cont_reads() helper everywhere to "prepare" the next continuous read if there is one.
Stable-dep-of: 8e4531667d71 ("mtd: rawnand: Pause continuous reads at block boundaries")
--- drivers/mtd/nand/raw/nand_base.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-)
drivers/mtd/nand/raw/nand_base.c +14 -9
@@ -1233,6 +1233,15 @@ static void rawnand_cap_cont_reads(struc chip->cont_read.pause_page =rawnand_last_page_of_lun (ppl, first_lun); else chip->cont_read.pause_page = chip->cont_read.last_page; + +if (chip->cont_read.first_page == chip->cont_read.pause_page) { + chip->cont_read.first_page++; + chip->cont_read.pause_page =min (chip->cont_read.last_page, +rawnand_last_page_of_lun (ppl, first_lun +1 )); + } + +if (chip->cont_read.first_page >= chip->cont_read.last_page) + chip->cont_read.ongoing = false; } static int nand_lp_exec_cont_read_page_op(struct nand_chip *chip, unsigned int page,
@@ -1299,12 +1308,11 @@ static int nand_lp_exec_cont_read_page_oif (!chip->cont_read.ongoing)return 0 ; -if (page == chip->cont_read.pause_page && - page != chip->cont_read.last_page) { - chip->cont_read.first_page = chip->cont_read.pause_page +1 ; -rawnand_cap_cont_reads (chip); - }else if (page == chip->cont_read.last_page) { +if (page == chip->cont_read.last_page) { chip->cont_read.ongoing = false; + }else if (page == chip->cont_read.pause_page) { + chip->cont_read.first_page++; +rawnand_cap_cont_reads (chip); }return 0 ;
@@ -3512,10 +3520,7 @@ static void rawnand_cont_read_skip_firstreturn ; chip->cont_read.first_page++; -if (chip->cont_read.first_page == chip->cont_read.pause_page) - chip->cont_read.first_page++; -if (chip->cont_read.first_page >= chip->cont_read.last_page) - chip->cont_read.ongoing = false; +rawnand_cap_cont_reads (chip); }/**
Greg Kroah-Hartman
maintainerPATCH 428/484 mtd: rawnand: Pause continuous reads at block boundaries
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Miquel Raynal <[email protected]>
[ Upstream commit 8e4531667d718e2e9b193928cf9b2497fa0d01ef ]
Some chips do not support sequential cached reads past block boundaries, like Winbond. In practice when using UBI, this should very rarely happen, but let's make sure it never happens.
--- drivers/mtd/nand/raw/nand_base.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-)
drivers/mtd/nand/raw/nand_base.c +12 -12
@@ -1212,32 +1212,32 @@ static int nand_lp_exec_read_page_op(strreturn nand_exec_op (chip, &op); } -static unsigned int rawnand_last_page_of_lun (unsigned int pages_per_lun,unsigned int lun) +static unsigned int rawnand_last_page_of_block (unsigned int ppb,unsigned int block) { -/* lun is expected to be very small */ -return (lun * pages_per_lun) + pages_per_lun -1 ; +/* block is expected to be very small */ +return (block * ppb) + ppb -1 ; }static void rawnand_cap_cont_reads (struct nand_chip *chip) {struct nand_memory_organization *memorg; -unsigned int ppl, first_lun, last_lun; +unsigned int ppb, first_block, last_block; memorg =nanddev_get_memorg (&chip->base); - ppl = memorg->pages_per_eraseblock * memorg->eraseblocks_per_lun; - first_lun = chip->cont_read.first_page / ppl; - last_lun = chip->cont_read.last_page / ppl; - -/* Prevent sequential cache reads across LUN boundaries */ -if (first_lun != last_lun) - chip->cont_read.pause_page =rawnand_last_page_of_lun (ppl, first_lun); + ppb = memorg->pages_per_eraseblock; + first_block = chip->cont_read.first_page / ppb; + last_block = chip->cont_read.last_page / ppb; + +/* Prevent sequential cache reads across block boundaries */ +if (first_block != last_block) + chip->cont_read.pause_page =rawnand_last_page_of_block (ppb, first_block);else chip->cont_read.pause_page = chip->cont_read.last_page;if (chip->cont_read.first_page == chip->cont_read.pause_page) { chip->cont_read.first_page++; chip->cont_read.pause_page =min (chip->cont_read.last_page, -rawnand_last_page_of_lun (ppl, first_lun +1 )); +rawnand_last_page_of_block (ppb, first_block +1 )); }if (chip->cont_read.first_page >= chip->cont_read.last_page)
Greg Kroah-Hartman
maintainerPATCH 429/484 taskstats: fill_stats_for_tgid: use for_each_thread()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Oleg Nesterov <[email protected]>
[ Upstream commit ed5378a387fd7c382497f2abcf4605e030b64044 ]
do/while_each_thread should be avoided when possible.
Plus I _think_ this change allows to avoid lock_task_sighand() but I am not sure, I forgot everything about taskstats. In any case, this code does not look right in that the same thread can be accounted twice:taskstats_exit() can account the exiting thread in signal->stats and drop ->siglock but this thread is still on the thread-group list, so lock_task_sighand() can't help.
Stable-dep-of: b3e4fbb04220 ("taskstats: retain dead thread stats in TGID queries")
--- kernel/taskstats.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
kernel/taskstats.c +2 -3
@@ -233,9 +233,8 @@ static int fill_stats_for_tgid(pid_t tgielse memset (stats,0 ,sizeof (*stats)); - tsk = first; start_time =ktime_get_ns (); - do { +for_each_thread (first, tsk) {if (tsk->exit_state)continue ;/*
@@ -258,7 +257,7 @@ static int fill_stats_for_tgid(pid_t tgi stats->nvcsw += tsk->nvcsw; stats->nivcsw += tsk->nivcsw; - }while_each_thread (first, tsk); + }unlock_task_sighand (first, &flags); rc =0 ;
Greg Kroah-Hartman
maintainerPATCH 430/484 taskstats: retain dead thread stats in TGID queries
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yiyang Chen <[email protected]>
[ Upstream commit b3e4fbb04220efc3bc022bcf31b5689d39c6b111 ]
Patch series "taskstats: fix TGID dead-thread stat retention", v3.
This series fixes a taskstats TGID aggregation bug where fields added in the TGID query path were not preserved after thread exit, and adds a kselftest covering the regression.
The first patch keeps the cached TGID aggregate used for dead threads in step with the fields already accumulated for live threads, and also fixes the final TGID exit notification emitted when group_dead is true.
The second patch adds a kselftest that verifies TGID CPU stats do not regress after a worker thread exits and has been reaped.
This patch (of 2):
fill_stats_for_tgid() builds TGID stats from two sources: the cached aggregate in signal->stats and a scan of the live threads in the group.
However, fill_tgid_exit() only accumulates delay accounting into signal->stats. This means that once a thread exits, TGID queries lose the fields that fill_stats_for_tgid() adds for live threads.
This gap was introduced incrementally by two earlier changes that extended fill_stats_for_tgid() but did not make the corresponding update to fill_tgid_exit():
- commit 8c733420bdd5 ("taskstats: add e/u/stime for TGID command") added ac_etime, ac_utime, and ac_stime to the TGID query path.
- commit b663a79c1915 ("taskstats: add context-switch counters") added nvcsw and nivcsw to the TGID query path.
As a result, those fields were accounted for live threads in TGID queries, but were dropped from the cached TGID aggregate after thread exit. The final TGID exit notification emitted when group_dead is true also copies that cached aggregate, so it loses the same fields.
Factor the per-task TGID accumulation into tgid_stats_add_task() and use it in both fill_stats_for_tgid() and fill_tgid_exit(). This keeps the cached aggregate used for dead threads aligned with the live-thread accumulation used by TGID queries.
--- kernel/taskstats.c | 62 ++++++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 29 deletions(-)
kernel/taskstats.c +33 -29
@@ -210,13 +210,39 @@ static int fill_stats_for_pid(pid_t pid,return 0 ; } +static void tgid_stats_add_task (struct taskstats *stats, +struct task_struct *tsk,u64 now_ns) +{ +u64 delta, utime, stime; + +/* +* Each accounting subsystem calls its functions here to +* accumulate its per-task stats for tsk, into the per-tgid structure +* +* per-task-foo(stats, tsk); +*/ +delayacct_add_tsk (stats, tsk); + +/* calculate task elapsed time in nsec */ + delta = now_ns - tsk->start_time; +/* Convert to micro seconds */ +do_div (delta,NSEC_PER_USEC ); + stats->ac_etime += delta; + +task_cputime (tsk, &utime, &stime); + stats->ac_utime +=div_u64 (utime,NSEC_PER_USEC ); + stats->ac_stime +=div_u64 (stime,NSEC_PER_USEC ); + + stats->nvcsw += tsk->nvcsw; + stats->nivcsw += tsk->nivcsw; +} +static int fill_stats_for_tgid (pid_t tgid,struct taskstats *stats) {struct task_struct *tsk, *first;unsigned long flags;int rc = -ESRCH ; -u64 delta, utime, stime; -u64 start_time; +u64 now_ns;/* * Add additional stats from live tasks except zombie thread group
@@ -233,30 +259,12 @@ static int fill_stats_for_tgid(pid_t tgielse memset (stats,0 ,sizeof (*stats)); - start_time =ktime_get_ns (); + now_ns =ktime_get_ns ();for_each_thread (first, tsk) {if (tsk->exit_state)continue ; -/* -* Accounting subsystem can call its functions here to -* fill in relevant parts of struct taskstsats as follows -* -* per-task-foo(stats, tsk); -*/ -delayacct_add_tsk (stats, tsk); - -/* calculate task elapsed time in nsec */ - delta = start_time - tsk->start_time; -/* Convert to micro seconds */ -do_div (delta,NSEC_PER_USEC ); - stats->ac_etime += delta; - -task_cputime (tsk, &utime, &stime); - stats->ac_utime +=div_u64 (utime,NSEC_PER_USEC ); - stats->ac_stime +=div_u64 (stime,NSEC_PER_USEC ); - stats->nvcsw += tsk->nvcsw; - stats->nivcsw += tsk->nivcsw; +tgid_stats_add_task (stats, tsk, now_ns); }unlock_task_sighand (first, &flags);
@@ -275,18 +283,14 @@ out:static void fill_tgid_exit (struct task_struct *tsk) {unsigned long flags; +u64 now_ns;spin_lock_irqsave (&tsk->sighand->siglock, flags);if (!tsk->signal->stats) goto ret; -/* -* Each accounting subsystem calls its functions here to -* accumalate its per-task stats for tsk, into the per-tgid structure -* -* per-task-foo(tsk->signal->stats, tsk); -*/ -delayacct_add_tsk (tsk->signal->stats, tsk); + now_ns =ktime_get_ns (); +tgid_stats_add_task (tsk->signal->stats, tsk, now_ns); ret:spin_unlock_irqrestore (&tsk->sighand->siglock, flags);return ;
Greg Kroah-Hartman
maintainerPATCH 431/484 dma: dw-edma: Fix build warning in dw_edma_pcie_probe()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abinash Singh <[email protected]>
[ Upstream commit 3df63fa8f2afd051848e37ef1b8299dee28d4f87 ]
The function dw_edma_pcie_probe() in dw-edma-pcie.c triggered a
frame size warning:
ld.lld:warning:
drivers/dma/dw-edma/dw-edma-pcie.c:162:0: stack frame size (1040) exceeds limit (1024) in function 'dw_edma_pcie_probe'
This patch reduces the stack usage by dynamically allocating the vsec_data structure using kmalloc(), rather than placing it on the stack. This eliminates the overflow warning and improves kernel robustness.
Stable-dep-of: 11d7cfe0c119 ("dmaengine: dw-edma-pcie: Reject devices without driver data")
--- drivers/dma/dw-edma/dw-edma-pcie.c | 62 +++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 29 deletions(-)
drivers/dma/dw-edma/dw-edma-pcie.c +33 -29
@@ -160,12 +160,16 @@ static int dw_edma_pcie_probe(struct pci const struct pci_device_id *pid) {struct dw_edma_pcie_data *pdata = (void *)pid->driver_data; -struct dw_edma_pcie_data vsec_data; + struct dw_edma_pcie_data *vsec_data __free(kfree) = NULL;struct device *dev = &pdev->dev;struct dw_edma_chip *chip;int err, nr_irqs;int i, mask; + vsec_data =kmalloc (sizeof (*vsec_data),GFP_KERNEL ); +if (!vsec_data) +return -ENOMEM ; +/* Enable PCI device */ err =pcim_enable_device (pdev);if (err) {
@@ -173,23 +177,23 @@ static int dw_edma_pcie_probe(struct pcireturn err; } -memcpy (&vsec_data, pdata,sizeof (struct dw_edma_pcie_data )); +memcpy (vsec_data, pdata,sizeof (struct dw_edma_pcie_data ));/* * Tries to find if exists a PCIe Vendor-Specific Extended Capability * for the DMA, if one exists, then reconfigures it. */ -dw_edma_pcie_get_vsec_dma_data (pdev, &vsec_data); +dw_edma_pcie_get_vsec_dma_data (pdev, vsec_data);/* Mapping PCI BAR regions */ - mask =BIT (vsec_data.rg.bar); -for (i =0 ; i < vsec_data.wr_ch_cnt; i++) { - mask |=BIT (vsec_data.ll_wr[i].bar); - mask |=BIT (vsec_data.dt_wr[i].bar); - } -for (i =0 ; i < vsec_data.rd_ch_cnt; i++) { - mask |=BIT (vsec_data.ll_rd[i].bar); - mask |=BIT (vsec_data.dt_rd[i].bar); + mask =BIT (vsec_data->rg.bar); +for (i =0 ; i < vsec_data->wr_ch_cnt; i++) { + mask |=BIT (vsec_data->ll_wr[i].bar); + mask |=BIT (vsec_data->dt_wr[i].bar); + } +for (i =0 ; i < vsec_data->rd_ch_cnt; i++) { + mask |=BIT (vsec_data->ll_rd[i].bar); + mask |=BIT (vsec_data->dt_rd[i].bar); } err =pcim_iomap_regions (pdev, mask,pci_name (pdev));if (err) {
@@ -212,7 +216,7 @@ static int dw_edma_pcie_probe(struct pcireturn -ENOMEM ;/* IRQs allocation */ - nr_irqs =pci_alloc_irq_vectors (pdev,1 , vsec_data.irqs, + nr_irqs =pci_alloc_irq_vectors (pdev,1 , vsec_data->irqs,PCI_IRQ_MSI |PCI_IRQ_MSIX );if (nr_irqs <1 ) { pci_err(pdev, "fail to alloc IRQ vector (number of IRQs=%u)\n",
@@ -223,22 +227,22 @@ static int dw_edma_pcie_probe(struct pci/* Data structure initialization */ chip->dev = dev; - chip->mf = vsec_data.mf; + chip->mf = vsec_data->mf; chip->nr_irqs = nr_irqs; chip->ops = &dw_edma_pcie_plat_ops; - chip->ll_wr_cnt = vsec_data.wr_ch_cnt; - chip->ll_rd_cnt = vsec_data.rd_ch_cnt; + chip->ll_wr_cnt = vsec_data->wr_ch_cnt; + chip->ll_rd_cnt = vsec_data->rd_ch_cnt; - chip->reg_base =pcim_iomap_table (pdev)[vsec_data.rg.bar]; + chip->reg_base =pcim_iomap_table (pdev)[vsec_data->rg.bar];if (!chip->reg_base)return -ENOMEM ;for (i =0 ; i < chip->ll_wr_cnt; i++) {struct dw_edma_region *ll_region = &chip->ll_region_wr[i];struct dw_edma_region *dt_region = &chip->dt_region_wr[i]; -struct dw_edma_block *ll_block = &vsec_data.ll_wr[i]; -struct dw_edma_block *dt_block = &vsec_data.dt_wr[i]; +struct dw_edma_block *ll_block = &vsec_data->ll_wr[i]; +struct dw_edma_block *dt_block = &vsec_data->dt_wr[i]; ll_region->vaddr.io =pcim_iomap_table (pdev)[ll_block->bar];if (!ll_region->vaddr.io)
@@ -262,8 +266,8 @@ static int dw_edma_pcie_probe(struct pcifor (i =0 ; i < chip->ll_rd_cnt; i++) {struct dw_edma_region *ll_region = &chip->ll_region_rd[i];struct dw_edma_region *dt_region = &chip->dt_region_rd[i]; -struct dw_edma_block *ll_block = &vsec_data.ll_rd[i]; -struct dw_edma_block *dt_block = &vsec_data.dt_rd[i]; +struct dw_edma_block *ll_block = &vsec_data->ll_rd[i]; +struct dw_edma_block *dt_block = &vsec_data->dt_rd[i]; ll_region->vaddr.io =pcim_iomap_table (pdev)[ll_block->bar];if (!ll_region->vaddr.io)
@@ -295,31 +299,31 @@ static int dw_edma_pcie_probe(struct pcipci_dbg (pdev,"Version:\tUnknown (0x%x)\n" , chip->mf);pci_dbg (pdev,"Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p)\n" , - vsec_data.rg.bar, vsec_data.rg.off, vsec_data.rg.sz, + vsec_data->rg.bar, vsec_data->rg.off, vsec_data->rg.sz, chip->reg_base);for (i =0 ; i < chip->ll_wr_cnt; i++) {pci_dbg (pdev,"L. List:\tWRITE CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n" , - i, vsec_data.ll_wr[i].bar, - vsec_data.ll_wr[i].off, chip->ll_region_wr[i].sz, + i, vsec_data->ll_wr[i].bar, + vsec_data->ll_wr[i].off, chip->ll_region_wr[i].sz, chip->ll_region_wr[i].vaddr.io, &chip->ll_region_wr[i].paddr);pci_dbg (pdev,"Data:\tWRITE CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n" , - i, vsec_data.dt_wr[i].bar, - vsec_data.dt_wr[i].off, chip->dt_region_wr[i].sz, + i, vsec_data->dt_wr[i].bar, + vsec_data->dt_wr[i].off, chip->dt_region_wr[i].sz, chip->dt_region_wr[i].vaddr.io, &chip->dt_region_wr[i].paddr); }for (i =0 ; i < chip->ll_rd_cnt; i++) {pci_dbg (pdev,"L. List:\tREAD CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n" , - i, vsec_data.ll_rd[i].bar, - vsec_data.ll_rd[i].off, chip->ll_region_rd[i].sz, + i, vsec_data->ll_rd[i].bar, + vsec_data->ll_rd[i].off, chip->ll_region_rd[i].sz, chip->ll_region_rd[i].vaddr.io, &chip->ll_region_rd[i].paddr);pci_dbg (pdev,"Data:\tREAD CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n" , - i, vsec_data.dt_rd[i].bar, - vsec_data.dt_rd[i].off, chip->dt_region_rd[i].sz, + i, vsec_data->dt_rd[i].bar, + vsec_data->dt_rd[i].off, chip->dt_region_rd[i].sz, chip->dt_region_rd[i].vaddr.io, &chip->dt_region_rd[i].paddr); }
Greg Kroah-Hartman
maintainerPATCH 432/484 dmaengine: dw-edma: Fix confusing cleanup.h syntax
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Krzysztof Kozlowski <[email protected]>
[ Upstream commit f9ef8dedee34e2d7828d5a6a0643cd969aaa8437 ]
Initializing automatic __free variables to NULL without need (e.g. branches with different allocations), followed by actual allocation is in contrary to explicit coding rules guiding cleanup.h:
"Given that the "__free(...) = NULL" pattern for variables defined at the top of the function poses this potential interdependency problem the recommendation is to always define and assign variables in one statement and not group variable definitions at the top of the function when __free() is used."
Code does not have a bug, but is less readable and uses discouraged coding practice, so fix that by moving declaration to the place of assignment.
Stable-dep-of: 11d7cfe0c119 ("dmaengine: dw-edma-pcie: Reject devices without driver data")
--- drivers/dma/dw-edma/dw-edma-pcie.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/dma/dw-edma/dw-edma-pcie.c +2 -2
@@ -160,13 +160,13 @@ static int dw_edma_pcie_probe(struct pci const struct pci_device_id *pid) {struct dw_edma_pcie_data *pdata = (void *)pid->driver_data; - struct dw_edma_pcie_data *vsec_data __free(kfree) = NULL;struct device *dev = &pdev->dev;struct dw_edma_chip *chip;int err, nr_irqs;int i, mask; - vsec_data =kmalloc (sizeof (*vsec_data),GFP_KERNEL ); + struct dw_edma_pcie_data *vsec_data __free(kfree) = +kmalloc (sizeof (*vsec_data),GFP_KERNEL );if (!vsec_data)return -ENOMEM ;
Greg Kroah-Hartman
maintainerPATCH 433/484 dmaengine: dw-edma-pcie: Reject devices without driver data
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <[email protected]>
[ Upstream commit 11d7cfe0c119691b2dafbb699bbca90258c678aa ]
dw_edma_pcie_probe() treats the PCI device ID driver_data as the template for the controller layout and copies it unconditionally. A device bound dynamically via sysfs can match the driver without that data, which leads to a NULL pointer dereference.
Reject such matches before enabling the device.
--- drivers/dma/dw-edma/dw-edma-pcie.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/dma/dw-edma/dw-edma-pcie.c +3 -0
@@ -165,6 +165,9 @@ static int dw_edma_pcie_probe(struct pciint err, nr_irqs;int i, mask; +if (!pdata) +return -ENODEV ; + struct dw_edma_pcie_data *vsec_data __free(kfree) =kmalloc (sizeof (*vsec_data),GFP_KERNEL );if (!vsec_data)
Greg Kroah-Hartman
maintainerPATCH 434/484 thunderbolt: Handle lane bonding of Gen 4 XDomain links properly
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gil Fine <[email protected]>
[ Upstream commit 36b6ad6ad0350554e611a8cb754ccd40857416a8 ]
Gen 4 links come up as bonded already so we are not supposed to initiate lane bonding on them. However, we should still update the port structures accordingly. Split these into their own functions to make it easier to follow.
Stable-dep-of: 2c5d2d3c3f70 ("thunderbolt: Prevent XDomain delayed work use-after-free on disconnect")
--- drivers/thunderbolt/tb.c | 2 - drivers/thunderbolt/xdomain.c | 49 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 3 deletions(-)
drivers/thunderbolt/tb.c +0 -2
@@ -539,8 +539,6 @@ static void tb_port_unconfigure_xdomain(usb4_port_unconfigure_xdomain (port); elsetb_lc_unconfigure_xdomain (port ); - -tb_port_enable (port->dual_link_port); }static void tb_scan_xdomain (struct tb_port *port)
drivers/thunderbolt/xdomain.c +48 -1
67 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 435/484 thunderbolt: Remove usage of the deprecated ida_simple_xx() API
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christophe JAILLET <[email protected]>
[ Upstream commit dec6a613574cd3dea799170b7aaa8fd76e22f176 ]
ida_alloc() and ida_free() should be preferred to the deprecated ida_simple_get() and ida_simple_remove().
Note that the upper limit of ida_simple_get() is exclusive, but the one of ida_alloc_range()/ida_alloc_max() is inclusive. So a -1 has been added when needed.
Stable-dep-of: 2c5d2d3c3f70 ("thunderbolt: Prevent XDomain delayed work use-after-free on disconnect")
--- drivers/thunderbolt/domain.c | 6 +++--- drivers/thunderbolt/nhi.c | 6 +++--- drivers/thunderbolt/nvm.c | 4 ++-- drivers/thunderbolt/switch.c | 6 +++--- drivers/thunderbolt/xdomain.c | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-)
drivers/thunderbolt/domain.c +3 -3
@@ -321,7 +321,7 @@ static void tb_domain_release(struct devtb_ctl_free (tb->ctl);destroy_workqueue (tb->wq); -ida_simple_remove (&tb_domain_ida, tb->index); +ida_free (&tb_domain_ida, tb->index);mutex_destroy (&tb->lock);kfree (tb); }
@@ -389,7 +389,7 @@ struct tb *tb_domain_alloc(struct tb_nhi tb->nhi = nhi;mutex_init (&tb->lock); - tb->index =ida_simple_get (&tb_domain_ida,0 ,0 ,GFP_KERNEL ); + tb->index =ida_alloc (&tb_domain_ida,GFP_KERNEL );if (tb->index <0 ) goto err_free;
@@ -413,7 +413,7 @@ struct tb *tb_domain_alloc(struct tb_nhi err_destroy_wq:destroy_workqueue (tb->wq); err_remove_ida: -ida_simple_remove (&tb_domain_ida, tb->index); +ida_free (&tb_domain_ida, tb->index); err_free:kfree (tb);
drivers/thunderbolt/nhi.c +3 -3
@@ -465,7 +465,7 @@ static int ring_request_msix(struct tb_rif (!nhi->pdev->msix_enabled)return 0 ; - ret =ida_simple_get (&nhi->msix_ida,0 ,MSIX_MAX_VECS ,GFP_KERNEL ); + ret =ida_alloc_max (&nhi->msix_ida,MSIX_MAX_VECS -1 ,GFP_KERNEL );if (ret <0 )return ret;
@@ -485,7 +485,7 @@ static int ring_request_msix(struct tb_rreturn 0 ; err_ida_remove: -ida_simple_remove (&nhi->msix_ida, ring->vector); +ida_free (&nhi->msix_ida, ring->vector);return ret; }
@@ -496,7 +496,7 @@ static void ring_release_msix(struct tb_return ;free_irq (ring->irq, ring); -ida_simple_remove (&ring->nhi->msix_ida, ring->vector); +ida_free (&ring->nhi->msix_ida, ring->vector); ring->vector =0 ; ring->irq =0 ; }
drivers/thunderbolt/nvm.c +2 -2
@@ -330,7 +330,7 @@ struct tb_nvm *tb_nvm_alloc(struct devicif (!nvm)return ERR_PTR (-ENOMEM ); - ret =ida_simple_get (&nvm_ida,0 ,0 ,GFP_KERNEL ); + ret =ida_alloc (&nvm_ida,GFP_KERNEL );if (ret <0 ) {kfree (nvm);return ERR_PTR (ret);
@@ -528,7 +528,7 @@ void tb_nvm_free(struct tb_nvm *nvm)nvmem_unregister (nvm->non_active);nvmem_unregister (nvm->active);vfree (nvm->buf); -ida_simple_remove (&nvm_ida, nvm->id); +ida_free (&nvm_ida, nvm->id); }kfree (nvm); }
drivers/thunderbolt/switch.c +3 -3
@@ -777,7 +777,7 @@ static int tb_port_alloc_hopid(struct tbif (max_hopid <0 || max_hopid > port_max_hopid) max_hopid = port_max_hopid; -return ida_simple_get (ida, min_hopid, max_hopid +1 ,GFP_KERNEL ); +return ida_alloc_range (ida, min_hopid, max_hopid,GFP_KERNEL ); }/**
@@ -815,7 +815,7 @@ int tb_port_alloc_out_hopid(struct tb_po*/ void tb_port_release_in_hopid (struct tb_port *port,int hopid) { -ida_simple_remove (&port->in_hopids, hopid); +ida_free (&port->in_hopids, hopid); }/**
@@ -825,7 +825,7 @@ void tb_port_release_in_hopid(struct tb_*/ void tb_port_release_out_hopid (struct tb_port *port,int hopid) { -ida_simple_remove (&port->out_hopids, hopid); +ida_free (&port->out_hopids, hopid); } static inline bool tb_switch_is_reachable(const struct tb_switch *parent,
drivers/thunderbolt/xdomain.c +2 -2
@@ -1005,7 +1005,7 @@ static void tb_service_release(struct destruct tb_xdomain *xd =tb_service_parent (svc);tb_service_debugfs_remove (svc); -ida_simple_remove (&xd->service_ids, svc->id); +ida_free (&xd->service_ids, svc->id);kfree (svc->key);kfree (svc); }
@@ -1107,7 +1107,7 @@ static void enumerate_services(struct tbbreak ; } - id =ida_simple_get (&xd->service_ids,0 ,0 ,GFP_KERNEL ); + id =ida_alloc (&xd->service_ids,GFP_KERNEL );if (id <0 ) {kfree (svc->key);kfree (svc);
Greg Kroah-Hartman
maintainerPATCH 436/484 thunderbolt: Update property.c function documentation
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alan Borzeszkowski <[email protected]>
[ Upstream commit d015642ad36d78e6eba12d8ab96cea6fd4602b49 ]
Make property.c function documentation compliant with current kernel-doc standards. No functional changes.
Stable-dep-of: 2c5d2d3c3f70 ("thunderbolt: Prevent XDomain delayed work use-after-free on disconnect")
--- drivers/thunderbolt/property.c | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-)
drivers/thunderbolt/property.c +28 -10
@@ -231,11 +231,13 @@ static struct tb_property_dir *__tb_prop* * This function parses the XDomain properties data block into format that * can be traversed using the helper functions provided by this module. -* Upon success returns the parsed directory. In case of error returns -* %NULL. The resulting &struct tb_property_dir needs to be released by +* +* The resulting &struct tb_property_dir needs to be released by * calling tb_property_free_dir() when not needed anymore. * * The @block is expected to be root directory. +* +* Return: Pointer to &struct tb_property_dir, %NULL in case of failure. */ struct tb_property_dir *tb_property_parse_dir (const u32 *block,size_t block_len)
@@ -258,6 +260,8 @@ struct tb_property_dir *tb_property_pars* * Creates new, empty property directory. If @uuid is %NULL then the * directory is assumed to be root directory. +* +* Return: Pointer to &struct tb_property_dir, %NULL in case of failure. */ struct tb_property_dir *tb_property_create_dir (const uuid_t *uuid) {
@@ -501,9 +505,11 @@ static ssize_t __tb_property_format_dir(* @block_len: Length of the property block * * This function formats the directory to the packed format that can be -* then send over the thunderbolt fabric to receiving host. Returns %0 in -* case of success and negative errno on faulure. Passing %NULL in @block -* returns number of entries the block takes. +* then sent over the thunderbolt fabric to receiving host. +* +* Passing %NULL in @block returns number of entries the block takes. +* +* Return: %0 on success, negative errno otherwise. */ ssize_t tb_property_format_dir (const struct tb_property_dir *dir,u32 *block,size_t block_len)
@@ -525,9 +531,9 @@ ssize_t tb_property_format_dir(const str* tb_property_copy_dir() - Take a deep copy of directory * @dir: Directory to copy * -* This function takes a deep copy of @dir and returns back the copy. In -* case of error returns %NULL. The resulting directory needs to be -* released by calling tb_property_free_dir(). +* The resulting directory needs to be released by calling tb_property_free_dir(). +* +* Return: Pointer to &struct tb_property_dir, %NULL in case of failure. */ struct tb_property_dir *tb_property_copy_dir (const struct tb_property_dir *dir) {
@@ -597,6 +603,8 @@ err_free:* @parent: Directory to add the property * @key: Key for the property * @value: Immediate value to store with the property +* +* Return: %0 on success, negative errno otherwise. */ int tb_property_add_immediate (struct tb_property_dir *parent,const char *key,u32 value)
@@ -626,6 +634,8 @@ EXPORT_SYMBOL_GPL(tb_property_add_immedi* @buflen: Number of bytes in the data buffer * * Function takes a copy of @buf and adds it to the directory. +* +* Return: %0 on success, negative errno otherwise. */ int tb_property_add_data (struct tb_property_dir *parent,const char *key,const void *buf,size_t buflen)
@@ -662,6 +672,8 @@ EXPORT_SYMBOL_GPL(tb_property_add_data);* @text: String to add * * Function takes a copy of @text and adds it to the directory. +* +* Return: %0 on success, negative errno otherwise. */ int tb_property_add_text (struct tb_property_dir *parent,const char *key,const char *text)
@@ -696,6 +708,8 @@ EXPORT_SYMBOL_GPL(tb_property_add_text);* @parent: Directory to add the property * @key: Key for the property * @dir: Directory to add +* +* Return: %0 on success, negative errno otherwise. */ int tb_property_add_dir (struct tb_property_dir *parent,const char *key,struct tb_property_dir *dir)
@@ -736,8 +750,10 @@ EXPORT_SYMBOL_GPL(tb_property_remove);* @key: Key to look for * @type: Type of the property * -* Finds and returns property from the given directory. Does not recurse -* into sub-directories. Returns %NULL if the property was not found. +* Finds and returns property from the given directory. Does not +* recurse into sub-directories. +* +* Return: Pointer to &struct tb_property, %NULL if the property was not found. */ struct tb_property *tb_property_find (struct tb_property_dir *dir,const char *key,enum tb_property_type type)
@@ -757,6 +773,8 @@ EXPORT_SYMBOL_GPL(tb_property_find);* tb_property_get_next() - Get next property from directory * @dir: Directory holding properties * @prev: Previous property in the directory (%NULL returns the first) +* +* Return: Pointer to &struct tb_property, %NULL if property was not found. */ struct tb_property *tb_property_get_next (struct tb_property_dir *dir,struct tb_property *prev)
Greg Kroah-Hartman
maintainerPATCH 437/484 thunderbolt: Keep XDomain reference during the lifetime of a service
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mika Westerberg <[email protected]>
[ Upstream commit 8b4060998637f06975fceee9b73845d8672d411e ]
This is needed because we release the service ID in tb_service_release() and the ID array is owned by the parent XDomain.
Stable-dep-of: 2c5d2d3c3f70 ("thunderbolt: Prevent XDomain delayed work use-after-free on disconnect")
--- drivers/thunderbolt/xdomain.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/thunderbolt/xdomain.c +2 -1
@@ -1008,6 +1008,7 @@ static void tb_service_release(struct deida_free (&xd->service_ids, svc->id);kfree (svc->key);kfree (svc); +tb_xdomain_put (xd); }struct device_type tb_service_type = {
@@ -1116,7 +1117,7 @@ static void enumerate_services(struct tb svc->id = id; svc->dev.bus = &tb_bus_type; svc->dev.type = &tb_service_type; - svc->dev.parent = &xd->dev; + svc->dev.parent =get_device (&xd->dev);dev_set_name (&svc->dev,"%s.%d" ,dev_name (&xd->dev), svc->id);tb_service_debugfs_init (svc);
Greg Kroah-Hartman
maintainerPATCH 438/484 thunderbolt: Remove service debugfs entries during unregister
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mika Westerberg <[email protected]>
[ Upstream commit 4d5fc3f4068568dfcb8cbe2852b4adc56394aa26 ]
We add them as part of the register path so to keep it symmetric remove them as part of the unregister path. This also removes them even if the service itself is not yet released (but is unregistered), thus allowing new register with the same service name to happen.
Stable-dep-of: 2c5d2d3c3f70 ("thunderbolt: Prevent XDomain delayed work use-after-free on disconnect")
--- drivers/thunderbolt/xdomain.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
drivers/thunderbolt/xdomain.c +11 -3
@@ -1004,7 +1004,6 @@ static void tb_service_release(struct de struct tb_service *svc = container_of(dev, struct tb_service, dev);struct tb_xdomain *xd =tb_service_parent (svc); -tb_service_debugfs_remove (svc);ida_free (&xd->service_ids, svc->id);kfree (svc->key);kfree (svc);
@@ -1019,6 +1018,14 @@ struct device_type tb_service_type = { };EXPORT_SYMBOL_GPL (tb_service_type); +static void __unregister_service (struct device *dev) +{ +struct tb_service *svc =tb_to_service (dev); + +tb_service_debugfs_remove (svc); +device_unregister (&svc->dev); +} +static int remove_missing_service (struct device *dev,void *data) {struct tb_xdomain *xd = data;
@@ -1030,7 +1037,7 @@ static int remove_missing_service(structif (!tb_property_find (xd->remote_properties, svc->key,TB_PROPERTY_TYPE_DIRECTORY )) -device_unregister (dev); +__unregister_service (dev);return 0 ; }
@@ -1123,6 +1130,7 @@ static void enumerate_services(struct tbtb_service_debugfs_init (svc);if (device_register (&svc->dev)) { +tb_service_debugfs_remove (svc);put_device (&svc->dev);break ; }
@@ -2048,7 +2056,7 @@ void tb_xdomain_add(struct tb_xdomain *xstatic int unregister_service (struct device *dev,void *data) { -device_unregister (dev); +__unregister_service (dev);return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 439/484 thunderbolt: Remove XDomain from the bus without holding tb->lock
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mika Westerberg <[email protected]>
[ Upstream commit a8937f35cf39c39c64325aa84d0463d866850857 ]
Currently we call device_unregister() for services and the XDomain itself with tb->lock held. This prevents the service drivers from calling any functions that may take it. For this reason separate removing the XDomain from the topology data structures (where we need the lock) from unregistering the device from the bus (where remove callbacks of the drivers are being called).
Stable-dep-of: 2c5d2d3c3f70 ("thunderbolt: Prevent XDomain delayed work use-after-free on disconnect")
--- drivers/thunderbolt/debugfs.c | 2 + drivers/thunderbolt/domain.c | 30 +++++++++++++++++++++ drivers/thunderbolt/icm.c | 5 +++ drivers/thunderbolt/switch.c | 14 +++++++++ drivers/thunderbolt/tb.c | 59 ++++++++++++++++++++---------------------- drivers/thunderbolt/tb.h | 2 + drivers/thunderbolt/xdomain.c | 53 +++++++++++++++++++++++-------------- 7 files changed, 115 insertions(+), 50 deletions(-)
drivers/thunderbolt/debugfs.c +2 -0
@@ -956,6 +956,8 @@ static void margining_port_remove(structif (!port->usb4)return ; +if (!port->usb4->margining) +return ;snprintf (dir_name,sizeof (dir_name),"port%d" , port->port); parent =debugfs_lookup (dir_name, port->sw->debugfs_dir);
drivers/thunderbolt/domain.c +30 -0
@@ -867,6 +867,36 @@ int tb_domain_disconnect_all_paths(strucreturn bus_for_each_dev (&tb_bus_type,NULL , tb, disconnect_xdomain); } +struct unregister_context { +const struct tb *tb; +int n; +}; + +static int unregister_unplugged_xdomain (struct device *dev,void *data) +{ +struct unregister_context *ctx = data; +struct tb_xdomain *xd; + + xd =tb_to_xdomain (dev); +if (xd && xd->tb == ctx->tb && xd->is_unplugged) { +tb_xdomain_unregister (xd); + ctx->n++; + } +return 0 ; +} + +int tb_domain_unregister_unplugged_xdomains (struct tb *tb) +{ +struct unregister_context ctx; + + ctx.tb =tb_domain_get (tb); + ctx.n =0 ; +bus_for_each_dev (&tb_bus_type,NULL , &ctx, unregister_unplugged_xdomain); +tb_domain_put (tb); + +return ctx.n; +} +int tb_domain_init (void ) {int ret;
drivers/thunderbolt/icm.c +5 -0
@@ -713,6 +713,7 @@ static void remove_xdomain(struct tb_xdo sw =tb_to_switch (xd->dev.parent);tb_port_at (xd->route, sw)->xdomain =NULL ; + xd->is_unplugged = true;tb_xdomain_remove (xd); }
@@ -1728,6 +1729,8 @@ static void icm_handle_notification(strukfree (n->pkg);kfree (n); + +tb_domain_unregister_unplugged_xdomains (tb); } static void icm_handle_event(struct tb *tb, enum tb_cfg_pkg_type type,
@@ -2078,6 +2081,8 @@ static void icm_rescan_work(struct work_if (tb->root_switch)icm_free_unplugged_children (tb->root_switch);mutex_unlock (&tb->lock); + +tb_domain_unregister_unplugged_xdomains (tb); }static void icm_complete (struct tb *tb)
drivers/thunderbolt/switch.c +14 -0
@@ -3556,6 +3556,20 @@ int tb_switch_resume(struct tb_switch *stb_port_warn (port,"lost during suspend, disconnecting\n" );tb_sw_set_unplugged (port->remote->sw); + }else if (port->xdomain) { +/* +* If the user replaced the XDomain with +* another router, this will succeed in +* which case we must remove the XDomain +* before adding the new router. +*/ + err =tb_cfg_get_upstream_port (sw->tb->ctl, + port->xdomain->route); +if (err >0 ) { +tb_port_warn (port, +"XDomain was disconnected\n" ); + port->xdomain->is_unplugged = true; + } } } }
drivers/thunderbolt/tb.c +29 -30
100 lines not on this page · raw message
drivers/thunderbolt/tb.h +2 -0
@@ -752,6 +752,7 @@ int tb_domain_disconnect_xdomain_paths(s int transmit_path, int transmit_ring, int receive_path, int receive_ring);int tb_domain_disconnect_all_paths (struct tb *tb); +int tb_domain_unregister_unplugged_xdomains (struct tb *tb);static inline struct tb *tb_domain_get (struct tb *tb) {
@@ -1200,6 +1201,7 @@ struct tb_xdomain *tb_xdomain_alloc(stru const uuid_t *remote_uuid);void tb_xdomain_add (struct tb_xdomain *xd);void tb_xdomain_remove (struct tb_xdomain *xd); +void tb_xdomain_unregister (struct tb_xdomain *xd);struct tb_xdomain *tb_xdomain_find_by_link_depth (struct tb *tb,u8 link,u8 depth);
drivers/thunderbolt/xdomain.c +33 -20
74 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 440/484 thunderbolt: Prevent XDomain delayed work use-after-free on disconnect
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
[ Upstream commit 2c5d2d3c3f70cde2565d7b279b544893a2035842 ]
tb_xdp_handle_request() runs on system_wq and queues xd->state_work via queue_delayed_work() in three request handlers:PROPERTIES_CHANGED_REQUEST, UUID_REQUEST (via start_handshake), and LINK_STATE_CHANGE_REQUEST. Similarly, update_xdomain() queues xd->properties_changed_work when local properties change.
Concurrently, tb_xdomain_remove() calls stop_handshake() which does cancel_delayed_work_sync() on both delayed works. Later, tb_xdomain_unregister() calls device_unregister() which eventually frees the xdomain. Since commit 559c1e1e0134 ("thunderbolt: Run tb_xdp_handle_request() in system workqueue") moved the request handler off tb->wq, the handler and the remove path are no longer serialized. If queue_delayed_work() executes after cancel_delayed_work_sync() but before the xdomain is freed, the delayed work fires on a freed object.
Add xd->removing that tb_xdomain_remove() sets under xd->lock before calling stop_handshake(). Each external queue site holds the same lock and checks removing before calling queue_delayed_work(). This provides the mutual exclusion needed:
either the queue site acquires the lock first and queues work that the subsequent cancel will see, or the remove path acquires the lock first and the queue site observes removing == true and skips the queue.
--- drivers/thunderbolt/xdomain.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-)
drivers/thunderbolt/xdomain.c +13 -13
@@ -905,6 +905,19 @@ void tb_unregister_service_driver(struct }EXPORT_SYMBOL_GPL (tb_unregister_service_driver); +static int update_xdomain (struct device *dev,void *data) +{ +struct tb_xdomain *xd; + + xd =tb_to_xdomain (dev); +if (xd) { +queue_delayed_work (xd->tb->wq, &xd->properties_changed_work, +msecs_to_jiffies (50 )); + } + +return 0 ; +} +static ssize_t key_show (struct device *dev,struct device_attribute *attr,char *buf) {
@@ -2475,19 +2488,6 @@ bool tb_xdomain_handle_request(struct tbreturn ret >0 ; } -static int update_xdomain (struct device *dev,void *data) -{ -struct tb_xdomain *xd; - - xd =tb_to_xdomain (dev); -if (xd) { -queue_delayed_work (xd->tb->wq, &xd->properties_changed_work, -msecs_to_jiffies (50 )); - } - -return 0 ; -} -static void update_all_xdomains (void ) {bus_for_each_dev (&tb_bus_type,NULL ,NULL , update_xdomain);
Greg Kroah-Hartman
maintainerPATCH 441/484 platform/x86: dell-smbios: Move request functions for reuse
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lyndon Sanche <[email protected]>
[ Upstream commit 33245680ae565aaa114d726bf407c8ff38e75e71 ]
Move the dell_send_request and dell_fill_request symbols into smbios-base so that they can be used in multiple modules.
Stable-dep-of: 6e9cab2247e5 ("platform/x86: dell-laptop: fix missing cleanups in init error path")
--- drivers/platform/x86/dell/dell-laptop.c | 23 ----------------------- drivers/platform/x86/dell/dell-smbios-base.c | 25 +++++++++++++++++++++++++ drivers/platform/x86/dell/dell-smbios.h | 5 +++++ 3 files changed, 30 insertions(+), 23 deletions(-)
drivers/platform/x86/dell/dell-laptop.c +0 -23
@@ -353,29 +353,6 @@ static const struct dmi_system_id dell_q { } }; -static void dell_fill_request (struct calling_interface_buffer *buffer, -u32 arg0,u32 arg1,u32 arg2,u32 arg3) -{ -memset (buffer,0 ,sizeof (struct calling_interface_buffer )); - buffer->input[0 ] = arg0; - buffer->input[1 ] = arg1; - buffer->input[2 ] = arg2; - buffer->input[3 ] = arg3; -} - -static int dell_send_request (struct calling_interface_buffer *buffer, -u16 class,u16 select) -{ -int ret; - - buffer->cmd_class = class; - buffer->cmd_select = select; - ret =dell_smbios_call (buffer); -if (ret !=0 ) -return ret; -return dell_smbios_error (buffer->output[0 ]); -} -/* * Derived from information in smbios-wireless-ctl: *
drivers/platform/x86/dell/dell-smbios-base.c +25 -0
@@ -320,6 +320,31 @@ out_smbios_call: }EXPORT_SYMBOL_GPL (dell_smbios_call); +void dell_fill_request (struct calling_interface_buffer *buffer, +u32 arg0,u32 arg1,u32 arg2,u32 arg3) +{ +memset (buffer,0 ,sizeof (struct calling_interface_buffer )); + buffer->input[0 ] = arg0; + buffer->input[1 ] = arg1; + buffer->input[2 ] = arg2; + buffer->input[3 ] = arg3; +} +EXPORT_SYMBOL_GPL (dell_fill_request); + +int dell_send_request (struct calling_interface_buffer *buffer, +u16 class,u16 select) +{ +int ret; + + buffer->cmd_class = class; + buffer->cmd_select = select; + ret =dell_smbios_call (buffer); +if (ret !=0 ) +return ret; +return dell_smbios_error (buffer->output[0 ]); +} +EXPORT_SYMBOL_GPL (dell_send_request); +struct calling_interface_token *dell_smbios_find_token (int tokenid) {int i;
drivers/platform/x86/dell/dell-smbios.h +5 -0
@@ -64,6 +64,11 @@ int dell_smbios_call_filter(struct devic struct calling_interface_buffer *buffer);int dell_smbios_call (struct calling_interface_buffer *buffer); +void dell_fill_request (struct calling_interface_buffer *buffer, +u32 arg0,u32 arg1,u32 arg2,u32 arg3); +int dell_send_request (struct calling_interface_buffer *buffer, +u16 class,u16 select); +struct calling_interface_token *dell_smbios_find_token (int tokenid);enum dell_laptop_notifier_actions {
Greg Kroah-Hartman
maintainerPATCH 442/484 platform/x86: dell-laptop: fix missing cleanups in init error path
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haoxiang Li <[email protected]>
[ Upstream commit 6e9cab2247e5b243ae2d907ce7c948a8a9c8d61a ]
dell_init() initializes several resources after dell_setup_rfkill(), including the optional touchpad LED, keyboard backlight LED, battery hook, debugfs directory and dell-laptop notifier.
If a later LED or backlight registration fails, the error path only tears down the battery hook and rfkill resources. This leaves the notifier, debugfs directory, keyboard backlight LED and optional touchpad LED registered after dell_init() returns an error.
Add the missing cleanup calls before tearing down rfkill.
--- drivers/platform/x86/dell/dell-laptop.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/platform/x86/dell/dell-laptop.c +5 -0
@@ -2295,6 +2295,11 @@ fail_backlight:if (mute_led_registered)led_classdev_unregister (&mute_led_cdev); fail_led: +dell_laptop_unregister_notifier (&dell_laptop_notifier); +debugfs_remove_recursive (dell_laptop_dir); +kbd_led_exit (); +if (quirks && quirks->touchpad_led) +touchpad_led_exit ();dell_cleanup_rfkill (); fail_rfkill:platform_device_del (platform_device);
Greg Kroah-Hartman
maintainerPATCH 443/484 i2c: imx: separate atomic, dma and non-dma use case
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stefan Eichenberger <[email protected]>
[ Upstream commit b460b15b3cc23ef3639cc51043bf8b2a70ca1878 ]
Separate the atomic, dma and non-dma use case as a preparation step for moving the non-dma use case to the isr to avoid rescheduling while a transfer is in progress.
Stable-dep-of: cb2fc3785769 ("i2c: imx: fix locked bus on SMBus block-read of 0 (atomic)")
--- drivers/i2c/busses/i2c-imx.c | 107 ++++++++++++++++++++++++++++--------------- 1 file changed, 70 insertions(+), 37 deletions(-)
drivers/i2c/busses/i2c-imx.c +70 -37
@@ -1011,6 +1011,43 @@ static int i2c_imx_dma_write(struct imx_return i2c_imx_acked (i2c_imx); } +static int i2c_imx_prepare_read (struct imx_i2c_struct *i2c_imx, +struct i2c_msg *msgs,bool atomic, +bool use_dma) +{ +int result; +unsigned int temp =0 ; + +/* write slave address */ +imx_i2c_write_reg (i2c_8bit_addr_from_msg (msgs), i2c_imx,IMX_I2C_I2DR ); + result =i2c_imx_trx_complete (i2c_imx, atomic); +if (result) +return result; + result =i2c_imx_acked (i2c_imx); +if (result) +return result; + +dev_dbg (&i2c_imx->adapter.dev,"<%s> setup bus\n" , __func__); + +/* setup bus to read data */ + temp =imx_i2c_read_reg (i2c_imx,IMX_I2C_I2CR ); + temp &= ~I2CR_MTX ; + +/* +* Reset the I2CR_TXAK flag initially for SMBus block read since the +* length is unknown +*/ +if (msgs->len -1 ) + temp &= ~I2CR_TXAK ; +if (use_dma) + temp |=I2CR_DMAEN ; + +imx_i2c_write_reg (temp, i2c_imx,IMX_I2C_I2CR ); +imx_i2c_read_reg (i2c_imx,IMX_I2C_I2DR );/* dummy read */ + +return 0 ; +} +static int i2c_imx_dma_read (struct imx_i2c_struct *i2c_imx,struct i2c_msg *msgs,bool is_lastmsg) {
@@ -1021,6 +1058,11 @@ static int i2c_imx_dma_read(struct imx_istruct imx_i2c_dma *dma = i2c_imx->dma;struct device *dev = &i2c_imx->adapter.dev; + result =i2c_imx_prepare_read (i2c_imx, msgs, false, true); +if (result) +return result; + +dev_dbg (&i2c_imx->adapter.dev,"<%s> read data\n" , __func__); dma->chan_using = dma->chan_rx; dma->dma_transfer_dir =DMA_DEV_TO_MEM ;
@@ -1131,50 +1173,24 @@ static int i2c_imx_write(struct imx_i2c_return 0 ; } +static int i2c_imx_atomic_write (struct imx_i2c_struct *i2c_imx,struct i2c_msg *msgs) +{ +return i2c_imx_write (i2c_imx, msgs, true); +} +static int i2c_imx_read (struct imx_i2c_struct *i2c_imx,struct i2c_msg *msgs,bool is_lastmsg,bool atomic) {int i, result;unsigned int temp;int block_data = msgs->flags &I2C_M_RECV_LEN ; -int use_dma = i2c_imx->dma && msgs->flags &I2C_M_DMA_SAFE && - msgs->len >=DMA_THRESHOLD && !block_data; - -dev_dbg (&i2c_imx->adapter.dev, -"<%s> write slave address: addr=0x%x\n" , - __func__,i2c_8bit_addr_from_msg (msgs)); -/* write slave address */ -imx_i2c_write_reg (i2c_8bit_addr_from_msg (msgs), i2c_imx,IMX_I2C_I2DR ); - result =i2c_imx_trx_complete (i2c_imx, atomic); -if (result) -return result; - result =i2c_imx_acked (i2c_imx); + result =i2c_imx_prepare_read (i2c_imx, msgs, atomic, false);if (result)return result; -dev_dbg (&i2c_imx->adapter.dev,"<%s> setup bus\n" , __func__); - -/* setup bus to read data */ - temp =imx_i2c_read_reg (i2c_imx,IMX_I2C_I2CR ); - temp &= ~I2CR_MTX ; - -/* -* Reset the I2CR_TXAK flag initially for SMBus block read since the -* length is unknown -*/ -if ((msgs->len -1 ) || block_data) - temp &= ~I2CR_TXAK ; -if (use_dma) - temp |=I2CR_DMAEN ; -imx_i2c_write_reg (temp, i2c_imx,IMX_I2C_I2CR ); -imx_i2c_read_reg (i2c_imx,IMX_I2C_I2DR );/* dummy read */ -dev_dbg (&i2c_imx->adapter.dev,"<%s> read data\n" , __func__); -if (use_dma) -return i2c_imx_dma_read (i2c_imx, msgs, is_lastmsg); -/* read data */ for (i =0 ; i < msgs->len; i++) {u8 len =0 ;
@@ -1241,6 +1257,12 @@ static int i2c_imx_read(struct imx_i2c_sreturn 0 ; } +static int i2c_imx_atomic_read (struct imx_i2c_struct *i2c_imx,struct i2c_msg *msgs, +bool is_lastmsg) +{ +return i2c_imx_read (i2c_imx, msgs, is_lastmsg, true); +} +static int i2c_imx_xfer_common (struct i2c_adapter *adapter,struct i2c_msg *msgs,int num,bool atomic) {
@@ -1248,6 +1270,7 @@ static int i2c_imx_xfer_common(struct i2int result;bool is_lastmsg = false;struct imx_i2c_struct *i2c_imx =i2c_get_adapdata (adapter); +int use_dma =0 ;/* Start I2C transfer */ result =i2c_imx_start (i2c_imx, atomic);
@@ -1300,15 +1323,25 @@ static int i2c_imx_xfer_common(struct i2 (temp &I2SR_SRW ?1 :0 ), (temp &I2SR_IIF ?1 :0 ), (temp & I2SR_RXAK ? 1 : 0));#endif + + use_dma = i2c_imx->dma && msgs[i].len >=DMA_THRESHOLD && + msgs[i].flags &I2C_M_DMA_SAFE ;if (msgs[i].flags &I2C_M_RD ) { - result =i2c_imx_read (i2c_imx, &msgs[i], is_lastmsg, atomic); +int block_data = msgs->flags &I2C_M_RECV_LEN ; + +if (atomic) + result =i2c_imx_atomic_read (i2c_imx, &msgs[i], is_lastmsg); +else if (use_dma && !block_data) + result =i2c_imx_dma_read (i2c_imx, &msgs[i], is_lastmsg); +else + result =i2c_imx_read (i2c_imx, &msgs[i], is_lastmsg, false); }else { -if (!atomic && - i2c_imx->dma && msgs[i].len >=DMA_THRESHOLD && - msgs[i].flags &I2C_M_DMA_SAFE ) +if (atomic) + result =i2c_imx_atomic_write (i2c_imx, &msgs[i]); +else if (use_dma) result =i2c_imx_dma_write (i2c_imx, &msgs[i]);else - result =i2c_imx_write (i2c_imx, &msgs[i], atomic); + result =i2c_imx_write (i2c_imx, &msgs[i], false); }if (result) goto fail0;
Greg Kroah-Hartman
maintainerPATCH 444/484 i2c: imx: fix locked bus on SMBus block-read of 0 (atomic)
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vincent Jardin <[email protected]>
[ Upstream commit cb2fc37857693b55909fb77dc2c87cfbc1cdc476 ]
SMBus 3.1 6.5.7 allows a Block Read byte count of 0, but the atomic (polling) path rejects it as -EPROTO. Worse, it returns without a NACK+STOP: the next receive cycle has already started, so the target keeps holding SDA and the bus stays stuck until a power cycle for this i2c controller.
Reading I2DR to obtain the count likewise arms the next byte on the count > I2C_SMBUS_BLOCK_MAX path, which also returned -EPROTO directly and left the bus held.
Handle both: NACK the in-flight dummy byte (TXAK) and extend msgs->len so the existing last-byte handling emits STOP; the dummy byte is discarded. A count of 0 is a valid empty block read; a count above I2C_SMBUS_BLOCK_MAX is still reported as -EPROTO, but only after the bus has been released.
The interrupt-driven path has the same flaw from a later commit and is fixed separately, as it carries a different Fixes: tag and stable range.
--- drivers/i2c/busses/i2c-imx.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-)
drivers/i2c/busses/i2c-imx.c +16 -3
@@ -1184,6 +1184,7 @@ static int i2c_imx_read(struct imx_i2c_sint i, result;unsigned int temp;int block_data = msgs->flags &I2C_M_RECV_LEN ; +int block_err =0 ; result =i2c_imx_prepare_read (i2c_imx, msgs, atomic, false);if (result)
@@ -1205,8 +1206,20 @@ static int i2c_imx_read(struct imx_i2c_s*/ if ((!i) && block_data) { len =imx_i2c_read_reg (i2c_imx,IMX_I2C_I2DR ); -if ((len ==0 ) || (len >I2C_SMBUS_BLOCK_MAX )) -return -EPROTO ; +if ((len ==0 ) || (len >I2C_SMBUS_BLOCK_MAX )) { +/* +* SMBus 3.1 6.5.7: support count byte of 0. +* I2C_SMBUS_BLOCK_MAX case should not hold the SDA either. +*/ +if (len >I2C_SMBUS_BLOCK_MAX ) + block_err = -EPROTO ; + temp =imx_i2c_read_reg (i2c_imx,IMX_I2C_I2CR ); + temp |=I2CR_TXAK ; +imx_i2c_write_reg (temp, i2c_imx,IMX_I2C_I2CR ); + msgs->buf[0 ] =0 ; + msgs->len =2 ; +continue ; + }dev_dbg (&i2c_imx->adapter.dev,"<%s> read length: 0x%X\n" , __func__, len);
@@ -1254,7 +1267,7 @@ static int i2c_imx_read(struct imx_i2c_s"<%s> read byte: B%d=0x%X\n" , __func__, i, msgs->buf[i]); } -return 0 ; +return block_err; } static int i2c_imx_atomic_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,
Greg Kroah-Hartman
maintainerPATCH 445/484 nfs: remove dead code for the old swap over NFS implementation
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christoph Hellwig <[email protected]>
[ Upstream commit 7e8e78a0ba00c88f0ded86de64bdddc82e06b196 ]
Remove the code testing folio_test_swapcache either explicitly or implicitly in pagemap.h headers, as is now handled using the direct I/O path and not the buffered I/O path that these helpers are located in.
Stable-dep-of: 27934d02cbeb ("NFS: Charge unstable writes by request size, not folio size")
--- fs/nfs/internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/nfs/internal.h +1 -1
@@ -791,7 +791,7 @@ static inline void nfs_folio_mark_unstab struct nfs_commit_info *cinfo) {if (folio && !cinfo->dreq) { -struct inode *inode =folio_file_mapping (folio)->host; +struct inode *inode = folio->mapping->host;long nr =folio_nr_pages (folio);/* This page is really still in write-back - just that the
Greg Kroah-Hartman
maintainerPATCH 446/484 NFS: Charge unstable writes by request size, not folio size
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Coddington <[email protected]>
[ Upstream commit 27934d02cbeb8a957dd11c985a579e58d30c5270 ]
nfs_folio_mark_unstable() and nfs_folio_clear_commit() charge and uncharge NR_WRITEBACK/WB_WRITEBACK by folio_nr_pages(folio) once per *request* added to or removed from a commit list. This is correct only when a folio has a single associated request. When pg_test splits a folio into N sub-folio requests (e.g. pNFS flexfiles striping with a stripe unit smaller than the folio size, or plain wsize-limited splitting), each of the N requests independently charges the whole folio's page count, inflating the accounting by a factor of N per folio. With large folios and small stripe units this reaches multiple orders of magnitude: a 2 MiB folio split into 512 4 KiB requests can charge up to 512x its real size, pushing global dirty+writeback accounting past the system's dirty threshold and forcing every buffered writer on the host into the hard-throttle path, including unrelated in-kernel NFS server threads sharing the box.
Charge each request only for the pages it actually covers.
--- fs/nfs/internal.h | 12 +++++++----- fs/nfs/pnfs_nfs.c | 2 +- fs/nfs/write.c | 14 ++++++++------ 3 files changed, 16 insertions(+), 12 deletions(-)
fs/nfs/internal.h +7 -5
@@ -784,17 +784,19 @@ void nfs_super_set_maxbytes(struct super }/* -* Record the page as unstable (an extra writeback period) and mark its -* inode as dirty. +* Record the request's range as unstable (an extra writeback period) and +* mark its inode as dirty. */ -static inline void nfs_folio_mark_unstable (struct folio *folio, +static inline void nfs_folio_mark_unstable (struct nfs_page *req,struct nfs_commit_info *cinfo) { +struct folio *folio =nfs_page_to_folio (req); +if (folio && !cinfo->dreq) {struct inode *inode = folio->mapping->host; -long nr =folio_nr_pages (folio); +long nr =DIV_ROUND_UP (req->wb_bytes,PAGE_SIZE ); -/* This page is really still in write-back - just that the +/* This range is really still in write-back - just that the * writeback is happening on the server now. */ node_stat_mod_folio (folio,NR_WRITEBACK , nr);
fs/nfs/pnfs_nfs.c +1 -1
@@ -1226,7 +1226,7 @@ pnfs_layout_mark_request_commit(struct nnfs_request_add_commit_list_locked (req, list, cinfo);mutex_unlock (&NFS_I (cinfo->inode)->commit_mutex); -nfs_folio_mark_unstable (nfs_page_to_folio (req), cinfo); +nfs_folio_mark_unstable (req, cinfo);return ; out_resched:mutex_unlock (&NFS_I (cinfo->inode)->commit_mutex);
fs/nfs/write.c +8 -6
@@ -933,7 +933,7 @@ nfs_request_add_commit_list(struct nfs_pmutex_lock (&NFS_I (cinfo->inode)->commit_mutex);nfs_request_add_commit_list_locked (req, &cinfo->mds->list, cinfo);mutex_unlock (&NFS_I (cinfo->inode)->commit_mutex); -nfs_folio_mark_unstable (nfs_page_to_folio (req), cinfo); +nfs_folio_mark_unstable (req, cinfo); }EXPORT_SYMBOL_GPL (nfs_request_add_commit_list);
@@ -992,10 +992,12 @@ nfs_mark_request_commit(struct nfs_pagenfs_request_add_commit_list (req, cinfo); } -static void nfs_folio_clear_commit (struct folio *folio) +static void nfs_folio_clear_commit (struct nfs_page *req) { +struct folio *folio =nfs_page_to_folio (req); +if (folio) { -long nr =folio_nr_pages (folio); +long nr =DIV_ROUND_UP (req->wb_bytes,PAGE_SIZE );node_stat_mod_folio (folio,NR_WRITEBACK , -nr); wb_stat_mod(&inode_to_bdi(folio_file_mapping(folio)->host)->wb,
@@ -1016,7 +1018,7 @@ static void nfs_clear_request_commit(strnfs_request_remove_commit_list (req, cinfo); }mutex_unlock (&NFS_I (inode)->commit_mutex); -nfs_folio_clear_commit (nfs_page_to_folio (req)); +nfs_folio_clear_commit (req); } }
@@ -1834,7 +1836,7 @@ void nfs_retry_commit(struct list_head * req =nfs_list_entry (page_list->next);nfs_list_remove_request (req);nfs_mark_request_commit (req, lseg, cinfo, ds_commit_idx); -nfs_folio_clear_commit (nfs_page_to_folio (req)); +nfs_folio_clear_commit (req);nfs_unlock_and_release_request (req); } }
@@ -1902,7 +1904,7 @@ static void nfs_commit_release_pages(str req =nfs_list_entry (data->pages.next);nfs_list_remove_request (req); folio =nfs_page_to_folio (req); -nfs_folio_clear_commit (folio); +nfs_folio_clear_commit (req); dprintk("NFS: commit (%s/%llu %d@%lld)", nfs_req_openctx(req)->dentry->d_sb->s_id,
Greg Kroah-Hartman
maintainerPATCH 447/484 ovl: use linked upper dentry in copy-up tmpfile
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Souvik Banerjee <[email protected]>
[ Upstream commit e348eecd4d8fa8d18a5157ff59f7be1dc59c5928 ]
ovl_copy_up_tmpfile() stores the disconnected O_TMPFILE dentry as the overlay's upper dentry reference via ovl_inode_update(). vfs_tmpfile() allocated this dentry via d_alloc(parentpath->dentry, &slash_name), so d_name is "/" and d_parent is c->workdir. Local upper filesystems (ext4, btrfs, xfs, ...) immediately rename it to "#<inum>" via d_mark_tmpfile() inside their ->tmpfile() op; FUSE and virtiofs do not, so both fields stay that way. Neither identifies the destination directory and filename where ovl_do_link() actually linked the file.
When the upper filesystem implements ->d_revalidate() (e.g. FUSE or virtiofs), ovl_revalidate_real() calls it with the dentry's parent inode and a snapshot of d_name. The server tries to look up "/" inside c->workdir, fails, and overlayfs reports -ESTALE.
This causes persistent ESTALE errors for any file that was copied up via the tmpfile path, breaking dpkg, apt, and other tools that do rename-over-existing on overlayfs with a FUSE/virtiofs upper.
Before commit 6b52243f633e ("ovl: fold copy-up helpers into callers"), the tmpfile copy-up path used a dedicated helper ovl_link_tmpfile() that captured the linked destination dentry returned by ovl_do_link():
err = ovl_do_link(temp, udir, upper);
...
if (!err)
*newdentry = dget(upper);and published it via ovl_inode_update(d_inode(c->dentry), newdentry). The fold inlined ovl_do_link() into ovl_copy_up_tmpfile() but dropped the dget(upper) capture, and rewrote the publish line as ovl_inode_update(d_inode(c->dentry), dget(temp)) — where temp is the disconnected O_TMPFILE dentry.
Fix by keeping a reference to the linked destination dentry after ovl_do_link() succeeds, and publishing that dentry at the existing ovl_inode_update() call site. The non-tmpfile/workdir path continues to publish the renamed temporary dentry.
Reproducer:
- Mount overlayfs with virtiofs (or a FUSE fs whose server advertises FUSE_TMPFILE) as upper
- Run: dpkg -i <any .deb>
- Observe: "error installing new file '...': Stale file handle"
--- fs/overlayfs/copy_up.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
fs/overlayfs/copy_up.c +10 -2
@@ -793,7 +793,7 @@ static int ovl_copy_up_tmpfile(struct ov {struct ovl_fs *ofs =OVL_FS (c->dentry->d_sb);struct inode *udir =d_inode (c->destdir); -struct dentry *temp, *upper; +struct dentry *temp, *upper, *newdentry =NULL ;struct file *tmpfile;struct ovl_cu_creds cc;int err;
@@ -826,6 +826,14 @@ static int ovl_copy_up_tmpfile(struct ov err =PTR_ERR (upper);if (!IS_ERR (upper)) { err =ovl_do_link (ofs, temp, udir, upper); +if (!err) { +/* +* Record the linked dentry -- not the disconnected +* O_TMPFILE dentry -- so that ->d_revalidate() on +* the upper fs sees the real parent/name. +*/ + newdentry =dget (upper); + }dput (upper); }inode_unlock (udir);
@@ -841,7 +849,7 @@ static int ovl_copy_up_tmpfile(struct ovif (!c->metacopy)ovl_set_upperdata (d_inode (c->dentry)); -ovl_inode_update (d_inode (c->dentry),dget (temp)); +ovl_inode_update (d_inode (c->dentry), newdentry); out_fput:fput (tmpfile);
Greg Kroah-Hartman
maintainerPATCH 448/484 dm-verity: avoid double increment of &use_bh_wq_enabled
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mikulas Patocka <[email protected]>
[ Upstream commit 72e9ec2fe32b00994f41719cf77423fca67d48b2 ]
verity_parse_opt_args is called twice, first with the only_modifier_opts, first with only_modifier_opts == true and then with only_modifier_opts == false. Thus, the static branch &use_bh_wq_enabled was incremented twice and the destructor verity_dtr would only decrement it once.
Fix tihs bug by only incrementing it on the first call, on the second call, when v->use_bh_wq is true, do nothing.
--- drivers/md/dm-verity-target.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/md/dm-verity-target.c +2 -0
@@ -1172,6 +1172,8 @@ static int verity_parse_opt_args(structcontinue ; }else if (!strcasecmp (arg_name,DM_VERITY_OPT_TASKLET_VERIFY )) { +if (v->use_tasklet) +continue ; v->use_tasklet = true;static_branch_inc (&use_tasklet_enabled);continue ;
Greg Kroah-Hartman
maintainerPATCH 449/484 dm-verity: make error counter atomic
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mikulas Patocka <[email protected]>
[ Upstream commit 8ec4d9c5a5cf4b61fc087f871465b1f79b393325 ]
The error counter "v->corrupted_errs" was not atomic, thus it could be subject to race conditions. The call to dm_audit_log_target("max-corrupted-errors") may be skipped due to the races.
--- drivers/md/dm-verity-target.c | 12 +++++++----- drivers/md/dm-verity.h | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-)
drivers/md/dm-verity-target.c +7 -5
@@ -227,14 +227,16 @@ static int verity_handle_err(struct dm_vchar *envp[] = { verity_env,NULL };const char *type_str ="" ;struct mapped_device *md =dm_table_get_md (v->ti->table); +int ce;/* Corruption should be visible in device status in all modes */ v->hash_failed = true; -if (v->corrupted_errs >=DM_VERITY_MAX_CORRUPTED_ERRS ) - goto out; - - v->corrupted_errs++; + ce =atomic_read (&v->corrupted_errs); +do { +if (ce >=DM_VERITY_MAX_CORRUPTED_ERRS ) + goto out; + }while (!atomic_try_cmpxchg (&v->corrupted_errs, &ce, ce +1 ));switch (type) {case DM_VERITY_BLOCK_TYPE_DATA :
@@ -250,7 +252,7 @@ static int verity_handle_err(struct dm_vDMERR_LIMIT ("%s: %s block %llu is corrupted" , v->data_dev->name, type_str, block); -if (v->corrupted_errs ==DM_VERITY_MAX_CORRUPTED_ERRS ) { +if (ce +1 ==DM_VERITY_MAX_CORRUPTED_ERRS ) {DMERR ("%s: reached maximum errors" , v->data_dev->name);dm_audit_log_target (DM_MSG_PREFIX ,"max-corrupted-errors" , v->ti,0 ); }
drivers/md/dm-verity.h +1 -1
@@ -58,7 +58,7 @@ struct dm_verity {unsigned int digest_size;/* digest size for the current hash algorithm */ unsigned int ahash_reqsize;/* the size of temporary space for crypto */ enum verity_mode mode;/* mode for handling verification errors */ -unsigned int corrupted_errs;/* Number of errors for corrupted blocks */ +atomic_t corrupted_errs;/* Number of errors for corrupted blocks */ struct workqueue_struct *verify_wq;
Greg Kroah-Hartman
maintainerPATCH 450/484 firmware_loader: introduce __free() cleanup hanler
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Torokhov <[email protected]>
[ Upstream commit 8dde8fa0cc3edce73c050b9882d06c1a575f6402 ]
Define cleanup handler using facilities from linux/cleanup.h to simplify error handling in code using firmware loader. This will allow writing code like this:
int driver_update_firmware(...)
{
const struct firmware *fw_entry __free(firmware) = NULL;
int error;
...
error = request_firmware(&fw_entry, fw_name, dev);
if (error) {
dev_err(dev, "failed to request firmware %s: %d",
fw_name, error);
return error;
}
error = check_firmware_valid(fw_entry);
if (error)
return error;
guard(mutex)(&instance->lock);
error = use_firmware(instance, fw);
if (error)
return error;
return 0;
}Stable-dep-of: d48795b5cd68 ("Input: ims-pcu - fix firmware leak in async update")
--- include/linux/firmware.h | 3 +++ 1 file changed, 3 insertions(+)
include/linux/firmware.h +3 -0
@@ -4,6 +4,7 @@#include <linux/types.h> #include <linux/compiler.h> +#include <linux/cleanup.h> #include <linux/gfp.h> #define FW_ACTION_NOUEVENT 0
@@ -196,4 +197,6 @@ static inline void firmware_upload_unregint firmware_request_cache (struct device *device,const char *name); +DEFINE_FREE(firmware, struct firmware *, release_firmware(_T)) +#endif
Greg Kroah-Hartman
maintainerPATCH 451/484 Input: ims-pcu - fix firmware leak in async update
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Torokhov <[email protected]>
[ Upstream commit d48795b5cd6828d36b707e8d62fc9e5c90e004ab ]
The firmware object was not being released if validation failed. Use __free(firmware) to ensure the firmware is always released.
--- drivers/input/misc/ims-pcu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
drivers/input/misc/ims-pcu.c +2 -3
@@ -964,9 +964,10 @@ out:return retval; } -static void ims_pcu_process_async_firmware (const struct firmware *fw, +static void ims_pcu_process_async_firmware (const struct firmware *_fw,void *context) { + const struct firmware *fw __free(firmware) = _fw;struct ims_pcu *pcu = context;int error;
@@ -987,8 +988,6 @@ static void ims_pcu_process_async_firmwaims_pcu_handle_firmware_update (pcu, fw);mutex_unlock (&pcu->cmd_mutex); -release_firmware (fw); - out:complete (&pcu->async_firmware_done); }
Greg Kroah-Hartman
maintainerPATCH 452/484 workqueue: Factor out init_cpu_worker_pool()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tejun Heo <[email protected]>
[ Upstream commit 2fcdb1b44491e08f5334a92c50e8f362e0d46f91 ]
Factor out init_cpu_worker_pool() from workqueue_init_early(). This is pure reorganization in preparation of BH workqueue support.
Stable-dep-of: 50fd6dd755c6 ("tracing/user_events: Fix use-after-free in user_event_mm_dup()")
--- kernel/workqueue.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-)
kernel/workqueue.c +18 -14
@@ -6609,6 +6609,22 @@ static void __init restrict_unbound_cpumcpumask_and (wq_unbound_cpumask, wq_unbound_cpumask, mask); } +static void __init init_cpu_worker_pool (struct worker_pool *pool,int cpu,int nice) +{ +BUG_ON (init_worker_pool (pool)); + pool->cpu = cpu; +cpumask_copy (pool->attrs->cpumask,cpumask_of (cpu)); +cpumask_copy (pool->attrs->__pod_cpumask,cpumask_of (cpu)); + pool->attrs->nice = nice; + pool->attrs->affn_strict = true; + pool->node =cpu_to_node (cpu); + +/* alloc pool ID */ +mutex_lock (&wq_pool_mutex); +BUG_ON (worker_pool_assign_id (pool)); +mutex_unlock (&wq_pool_mutex); +} +/** * workqueue_init_early - early init for workqueue subsystem *
@@ -6657,20 +6673,8 @@ void __init workqueue_init_early(void)struct worker_pool *pool; i =0 ; -for_each_cpu_worker_pool (pool, cpu) { -BUG_ON (init_worker_pool (pool)); - pool->cpu = cpu; -cpumask_copy (pool->attrs->cpumask,cpumask_of (cpu)); -cpumask_copy (pool->attrs->__pod_cpumask,cpumask_of (cpu)); - pool->attrs->nice = std_nice[i++]; - pool->attrs->affn_strict = true; - pool->node =cpu_to_node (cpu); - -/* alloc pool ID */ -mutex_lock (&wq_pool_mutex); -BUG_ON (worker_pool_assign_id (pool)); -mutex_unlock (&wq_pool_mutex); - } +for_each_cpu_worker_pool (pool, cpu) +init_cpu_worker_pool (pool, cpu, std_nice[i++]); }/* create default unbound and ordered wq attrs */
Greg Kroah-Hartman
maintainerPATCH 453/484 workqueue: Add system_percpu_wq and system_dfl_wq
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marco Crivellari <[email protected]>
[ Upstream commit 128ea9f6ccfb6960293ae4212f4f97165e42222d ]
Currently, if a user enqueue a work item using schedule_delayed_work() the used wq is "system_wq" (per-cpu wq) while queue_delayed_work() use WORK_CPU_UNBOUND (used when a cpu is not specified). The same applies to schedule_work() that is using system_wq and queue_work(), that makes use again of WORK_CPU_UNBOUND.
This lack of consistentcy cannot be addressed without refactoring the API.
system_wq is a per-CPU worqueue, yet nothing in its name tells about that CPU affinity constraint, which is very often not required by users. Make it clear by adding a system_percpu_wq.
system_unbound_wq should be the default workqueue so as not to enforce locality constraints for random work whenever it's not required.
Adding system_dfl_wq to encourage its use when unbound work should be used.
Stable-dep-of: 50fd6dd755c6 ("tracing/user_events: Fix use-after-free in user_event_mm_dup()")
--- include/linux/workqueue.h | 8 +++++--- kernel/workqueue.c | 14 ++++++++++---- 2 files changed, 15 insertions(+), 7 deletions(-)
include/linux/workqueue.h +5 -3
@@ -410,7 +410,7 @@ enum {/* * System-wide workqueues which are always present. * -* system_wq is the one used by schedule[_delayed]_work[_on](). +* system_percpu_wq is the one used by schedule[_delayed]_work[_on](). * Multi-CPU multi-threaded. There are users which expect relatively * short queue flush time. Don't queue works which can run for too * long.
@@ -421,7 +421,7 @@ enum {* system_long_wq is similar to system_wq but may host long running * works. Queue flushing might take relatively long. * -* system_unbound_wq is unbound workqueue. Workers are not bound to +* system_dfl_wq is unbound workqueue. Workers are not bound to * any specific CPU, not concurrency managed, and all queued works are * executed immediately as long as max_active limit is not reached and * resources are available.
@@ -435,10 +435,12 @@ enum {* system_power_efficient_wq is identical to system_wq if * 'wq_power_efficient' is disabled. See WQ_POWER_EFFICIENT for more info. */ -extern struct workqueue_struct *system_wq; +extern struct workqueue_struct *system_wq;/* use system_percpu_wq, this will be removed */ +extern struct workqueue_struct *system_percpu_wq;extern struct workqueue_struct *system_highpri_wq;extern struct workqueue_struct *system_long_wq;extern struct workqueue_struct *system_unbound_wq; +extern struct workqueue_struct *system_dfl_wq;extern struct workqueue_struct *system_freezable_wq;extern struct workqueue_struct *system_power_efficient_wq;extern struct workqueue_struct *system_freezable_power_efficient_wq;
kernel/workqueue.c +10 -4
@@ -425,12 +425,16 @@ static struct kthread_worker *pwq_releasstruct workqueue_struct *system_wq__read_mostly ;EXPORT_SYMBOL (system_wq); +struct workqueue_struct *system_percpu_wq__read_mostly ; +EXPORT_SYMBOL (system_percpu_wq);struct workqueue_struct *system_highpri_wq__read_mostly ;EXPORT_SYMBOL_GPL (system_highpri_wq);struct workqueue_struct *system_long_wq__read_mostly ;EXPORT_SYMBOL_GPL (system_long_wq);struct workqueue_struct *system_unbound_wq__read_mostly ;EXPORT_SYMBOL_GPL (system_unbound_wq); +struct workqueue_struct *system_dfl_wq__read_mostly ; +EXPORT_SYMBOL_GPL (system_dfl_wq);struct workqueue_struct *system_freezable_wq__read_mostly ;EXPORT_SYMBOL_GPL (system_freezable_wq);struct workqueue_struct *system_power_efficient_wq__read_mostly ;
@@ -6696,10 +6700,11 @@ void __init workqueue_init_early(void) } system_wq =alloc_workqueue ("events" ,0 ,0 ); + system_percpu_wq =alloc_workqueue ("events" ,0 ,0 ); system_highpri_wq =alloc_workqueue ("events_highpri" ,WQ_HIGHPRI ,0 ); system_long_wq =alloc_workqueue ("events_long" ,0 ,0 ); - system_unbound_wq =alloc_workqueue ("events_unbound" ,WQ_UNBOUND , -WQ_MAX_ACTIVE ); + system_unbound_wq =alloc_workqueue ("events_unbound" ,WQ_UNBOUND ,WQ_MAX_ACTIVE ); + system_dfl_wq =alloc_workqueue ("events_unbound" ,WQ_UNBOUND ,WQ_MAX_ACTIVE ); system_freezable_wq =alloc_workqueue ("events_freezable" ,WQ_FREEZABLE ,0 ); system_power_efficient_wq = alloc_workqueue("events_power_efficient",
@@ -6707,8 +6712,9 @@ void __init workqueue_init_early(void) system_freezable_power_efficient_wq =alloc_workqueue ("events_freezable_power_efficient" ,WQ_FREEZABLE |WQ_POWER_EFFICIENT ,0 ); -BUG_ON (!system_wq || !system_highpri_wq || !system_long_wq || - !system_unbound_wq || !system_freezable_wq || +BUG_ON (!system_wq || !system_percpu_wq || !system_highpri_wq || + !system_long_wq || !system_unbound_wq || !system_dfl_wq || + !system_freezable_wq || !system_power_efficient_wq || !system_freezable_power_efficient_wq); }
Greg Kroah-Hartman
maintainerPATCH 454/484 tracing/user_events: Fix use-after-free in user_event_mm_dup()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
[ Upstream commit 50fd6dd755c6e48a38af2fa4621167eea56829c2 ]
user_event_mm_dup() walks the parent mm's enabler list locklessly under rcu_read_lock() during fork() (from copy_process()); it does not take event_mutex:
rcu_read_lock(); list_for_each_entry_rcu(enabler, &old_mm->enablers, mm_enablers_link) enabler->event = user_event_get(orig->event);
user_event_enabler_destroy() removes an enabler from that list with list_del_rcu() and then, without waiting for a grace period, drops the enabler's user_event reference with user_event_put() and frees the enabler with kfree(). A reader that loaded the enabler before the list_del_rcu() can still be walking it, which leads to two use-after-frees:
- kfree(enabler) frees the enabler while that reader dereferences enabler->event.
- user_event_put() may drop the last reference to the user_event, which is then freed (via delayed_destroy_user_event() on a work queue), while the same reader does user_event_get(orig->event) on it.
Both are reachable by an unprivileged task that can open user_events_data:
one multithreaded process that registers an enabler and then concurrently unregisters it and calls fork() triggers the race. KASAN reports a slab-use-after-free in user_event_mm_dup() during clone(), with a "refcount_t: addition on 0" warning when the user_event is freed.
The enabler use-after-free was found first; the user_event one was reported by XIAO WU, and the earlier enabler-only fix did not address it.
Defer both the user_event_put() and the kfree(enabler) to a work item queued with queue_rcu_work(), so they run only after an RCU grace period, once all readers walking the enabler list have finished. The put must run in process context because user_event_put() takes event_mutex on the last reference, so a work queue is used rather than call_rcu(). The now-unlocked put lets the locked argument of user_event_enabler_destroy() be removed; all callers are updated.
--- kernel/trace/trace_events_user.c | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-)
kernel/trace/trace_events_user.c +32 -7
@@ -104,6 +104,9 @@ struct user_event_enabler {/* Track enable bit, flags, etc. Aligned for bitops. */ unsigned long values; + +/* Defer the event put and enabler free past an RCU grace period. */ +struct rcu_work put_rwork; };/* Bits 0-5 are for the bit to update upon enable/disable (0-63 allowed) */
@@ -378,17 +381,39 @@ error:return NULL ; }; -static void user_event_enabler_destroy (struct user_event_enabler *enabler, -bool locked) +static void delayed_user_event_enabler_put (struct work_struct *work) { -list_del_rcu (&enabler->mm_enablers_link); +struct user_event_enabler *enabler =container_of (to_rcu_work (work), + struct user_event_enabler, put_rwork);/* No longer tracking the event via the enabler */ -user_event_put (enabler->event, locked); +user_event_put (enabler->event, false); +/* Run from queue_rcu_work(), the RCU grace period has elapsed */ kfree (enabler); } +static void user_event_enabler_destroy (struct user_event_enabler *enabler) +{ +list_del_rcu (&enabler->mm_enablers_link); + +/* +* The enabler is removed from an RCU-traversed list +* (user_event_mm_dup() walks mm->enablers under rcu_read_lock() only), +* and readers there dereference enabler->event and take a new ref on +* it. Both the put of that event reference and the free of the enabler +* therefore have to wait for a grace period so no reader can be looking +* at the enabler or racing the last put of its event. +* +* The put itself must not run in RCU context: when it drops the last +* reference user_event_put() takes event_mutex, which cannot be taken +* from a softirq/RCU callback. Defer both to a work item scheduled +* after a grace period via queue_rcu_work(). +*/ +INIT_RCU_WORK (&enabler->put_rwork, delayed_user_event_enabler_put); +queue_rcu_work (system_percpu_wq, &enabler->put_rwork); +} +static int user_event_mm_fault_in (struct user_event_mm *mm,unsigned long uaddr,int attempt) {
@@ -446,7 +471,7 @@ static void user_event_enabler_fault_fix/* User asked for enabler to be removed during fault */ if (test_bit (ENABLE_VAL_FREEING_BIT ,ENABLE_BITOPS (enabler))) { -user_event_enabler_destroy (enabler, true); +user_event_enabler_destroy (enabler); goto out; }
@@ -746,7 +771,7 @@ static void user_event_mm_destroy(structstruct user_event_enabler *enabler, *next;list_for_each_entry_safe (enabler, next, &mm->enablers, mm_enablers_link) -user_event_enabler_destroy (enabler, false); +user_event_enabler_destroy (enabler);mmdrop (mm->mm);kfree (mm);
@@ -2579,7 +2604,7 @@ static long user_events_ioctl_unreg(unsi flags |= enabler->values &ENABLE_VAL_COMPAT_MASK ;if (!test_bit (ENABLE_VAL_FAULTING_BIT ,ENABLE_BITOPS (enabler))) -user_event_enabler_destroy (enabler, true); +user_event_enabler_destroy (enabler);/* Removed at least one */ ret =0 ;
Greg Kroah-Hartman
maintainerPATCH 455/484 wifi: libertas_tf: fix use-after-free in lbtf_free_adapter()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maoyi Xie <[email protected]>
[ Upstream commit aa6dcd5c8dd9ba1d7d0f60093bcda41c0d6d438d ]
lbtf_free_adapter() calls timer_delete(&priv->command_timer), which does not wait for a running command_timer_fn() callback. lbtf_free_adapter() runs on the teardown path right before ieee80211_free_hw() frees priv, both in lbtf_remove_card() and in the probe error path. command_timer is armed by mod_timer() in lbtf_cmd() whenever a firmware command is sent. command_timer_fn() dereferences priv. If a command times out as the device is removed, command_timer_fn() runs concurrently with teardown and dereferences priv after it has been freed.
This is the same use-after-free that commit 03cc8f90d053 ("wifi: libertas:
fix use-after-free in lbs_free_adapter()") fixed in the sibling libertas driver. The libertas_tf variant has the identical pattern and was left unchanged. Use timer_delete_sync() so any in-flight callback completes before priv is freed.
--- drivers/net/wireless/marvell/libertas_tf/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/marvell/libertas_tf/main.c +1 -1
@@ -174,7 +174,7 @@ static void lbtf_free_adapter(struct lbt {lbtf_deb_enter (LBTF_DEB_MAIN );lbtf_free_cmd_buffer (priv); -del_timer (&priv->command_timer); +timer_delete_sync (&priv->command_timer);lbtf_deb_leave (LBTF_DEB_MAIN ); }
Greg Kroah-Hartman
maintainerPATCH 456/484 mmc: vub300: fix use-after-free on disconnect
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
The vub300 driver maintains an explicit reference count for the controller and its driver data and the last reference can in theory be dropped after the driver has been unbound.
This specifically means that the controller allocation must not be device managed as that can lead to use-after-free.
Note that the lifetime is currently also incorrectly tied the parent USB device rather than interface, which can lead to memory leaks if the driver is unbound without its device being physically disconnected (e.g. on probe deferral).
Fix both issues by reverting to non-managed allocation of the controller.
--- drivers/mmc/host/vub300.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/mmc/host/vub300.c +6 -6
@@ -2279,7 +2279,7 @@ static int vub300_probe(struct usb_interdev_err (&vub300->udev->dev,"Could not find two sets of bulk-in/out endpoint pairs\n" ); retval = -EINVAL ; - goto error5; + goto err_free_host; } retval = usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
@@ -2288,14 +2288,14 @@ static int vub300_probe(struct usb_inter0x0000 ,0x0000 , &vub300->hc_info, sizeof(vub300->hc_info), 1000);if (retval <0 ) - goto error5; + goto err_free_host; retval =usb_control_msg (vub300->udev,usb_sndctrlpipe (vub300->udev,0 ),SET_ROM_WAIT_STATES ,USB_DIR_OUT |USB_TYPE_VENDOR |USB_RECIP_DEVICE , firmware_rom_wait_states,0x0000 ,NULL ,0 ,1000 );if (retval <0 ) - goto error5; + goto err_free_host; dev_info(&vub300->udev->dev, "operating_mode = %s %s %d MHz %s %d byte USB packets\n", (mmc->caps & MMC_CAP_SDIO_IRQ) ? "IRQs" : "POLL",
@@ -2310,7 +2310,7 @@ static int vub300_probe(struct usb_inter0x0000 ,0x0000 , &vub300->system_port_status, sizeof(vub300->system_port_status), 1000);if (retval <0 ) { - goto error5; + goto err_free_host; }else if (sizeof (vub300->system_port_status) == retval) { vub300->card_present = (0x0001 & vub300->system_port_status.port_flags) ?1 :0 ;
@@ -2318,7 +2318,7 @@ static int vub300_probe(struct usb_inter (0x0010 & vub300->system_port_status.port_flags) ?1 :0 ; }else { retval = -EINVAL ; - goto error5; + goto err_free_host; }usb_set_intfdata (interface, vub300);INIT_DELAYED_WORK (&vub300->pollwork, vub300_pollwork_thread);
@@ -2348,7 +2348,7 @@ static int vub300_probe(struct usb_interreturn 0 ; error6:del_timer_sync (&vub300->inactivity_timer); -error5: +err_free_host:mmc_free_host (mmc);/* * and hence also frees vub300
Re: [PATCH 6.6 456/484] mmc: vub300: fix use-after-free on disconnect
Hello,
The backport is wrong and not as is discribe in the title.
It just renames the goto and I don`t know what the backport fix not in the tree for 'git log v6.6.147 --grep="mmc: vub300: Use devm_mmc_alloc_host() helper"' not found it fixes for, so I see just drop the patch.
BRs
Wentao Guan
Greg KH
maintainerRe: [PATCH 6.6 456/484] mmc: vub300: fix use-after-free on disconnect
Quoted 6 lines · Wentao Guan
Hello,
The backport is wrong and not as is discribe in the title.
It just renames the goto and I don`t know what the backport fix not in the tree for 'git log v6.6.147 --grep="mmc: vub300: Usedevm_mmc_alloc_host()helper"' not found it fixes for, so I see just drop the patch.
Odd, yeah, let me go drop this one, good catch. something went wrong on my side... I'll also drop it from the other queues.
thanks,
greg k-h
Re: [PATCH 6.6 456/484] mmc: vub300: fix use-after-free on disconnect
Quoted 10 lines · Greg Kroah-Hartman
Quoted 6 lines · Wentao Guan
Hello,
The backport is wrong and not as is discribe in the title.
It just renames the goto and I don`t know what the backport fix not in the tree for 'git log v6.6.147 --grep="mmc: vub300: Usedevm_mmc_alloc_host()helper"' not found it fixes for, so I see just drop the patch.Odd, yeah, let me go drop this one, good catch. something went wrong on my side... I'll also drop it from the other queues.
Yeah, this fixes a commit in 6.17 so shouldn't be backported further than that (unless that commit somehow ended up being backported as a dependency somewhere...).
Johan
Greg KH
maintainerRe: [PATCH 6.6 456/484] mmc: vub300: fix use-after-free on disconnect
Quoted 9 lines · Johan Hovold
Quoted 8 lines · Greg Kroah-Hartman
Quoted 6 lines · Wentao Guan
Hello,
The backport is wrong and not as is discribe in the title.
It just renames the goto and I don`t know what the backport fix not in the tree for 'git log v6.6.147 --grep="mmc: vub300: Usedevm_mmc_alloc_host()helper"' not found it fixes for, so I see just drop the patch.
Quoted 6 lines
Quoted 2 lines
Odd, yeah, let me go drop this one, good catch. something went wrong on my side... I'll also drop it from the other queues.
Yeah, this fixes a commit in 6.17 so shouldn't be backported further than that (unless that commit somehow ended up being backported as a dependency somewhere...).
It was a dependency, but backported wrong so I just ripped them all out :)
Greg Kroah-Hartman
maintainerPATCH 457/484 mmc: vub300: rename probe error labels
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
Error labels should be named after what they do.
Rename the probe error labels.
--- drivers/mmc/host/vub300.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-)
drivers/mmc/host/vub300.c +11 -9
@@ -2114,19 +2114,19 @@ static int vub300_probe(struct usb_inter command_out_urb =usb_alloc_urb (0 ,GFP_KERNEL );if (!command_out_urb) { retval = -ENOMEM ; - goto error0; + goto err_put_udev; } command_res_urb =usb_alloc_urb (0 ,GFP_KERNEL );if (!command_res_urb) { retval = -ENOMEM ; - goto error1; + goto err_free_out_urb; }/* this also allocates memory for our VUB300 mmc host device */ mmc =mmc_alloc_host (sizeof (struct vub300_mmc_host ), &udev->dev);if (!mmc) { retval = -ENOMEM ;dev_err (&udev->dev,"not enough memory for the mmc_host\n" ); - goto error4; + goto err_free_res_urb; }/* MMC core transfer sizes tunable parameters */ mmc->caps =0 ;
@@ -2343,23 +2343,25 @@ static int vub300_probe(struct usb_inter interface_to_InterfaceNumber(interface)); retval =mmc_add_host (mmc);if (retval) - goto error6; + goto err_delete_timer;return 0 ; -error6: -del_timer_sync (&vub300->inactivity_timer); + +err_delete_timer: +timer_delete_sync (&vub300->inactivity_timer); err_free_host:mmc_free_host (mmc);/* * and hence also frees vub300 * which is contained at the end of struct mmc */ -error4: +err_free_res_urb:usb_free_urb (command_res_urb); -error1: +err_free_out_urb:usb_free_urb (command_out_urb); -error0: +err_put_udev:usb_put_dev (udev); +return retval; }
Greg Kroah-Hartman
maintainerPATCH 458/484 mmc: vub300: fix use-after-free on probe failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
The vub300 driver lifetime-manages its controller state using vub300->kref, with vub300_delete() freeing the mmc host when the last reference is dropped. The probe error path after the inactivity timer has been armed still bypasses that lifetime rule, however, and falls through to mmc_free_host() directly if mmc_add_host() fails.
The race window is between arming the inactivity timer and reaching the probe error unwind after mmc_add_host() fails:
probe thread timer/workqueue
------------ ---------------
kref_init(&vub300->kref) ref = 1
kref_get(&vub300->kref) ref = 2, timer ref
add_timer(inactivity_timer) fires after one second
|
| race window
|<---------------------------------------------------->
| mmc_add_host(mmc)
inactivity timer fires vub300_queue_dead_work()
kref_get() ref = 3
queue_work(deadwork)
mmc_add_host() fails
timer_delete_sync()
mmc_free_host(mmc)
frees vub300
deadwork runs
use-after-free
The inactivity timeout is one second, so this would require mmc_add_host() to both fail and take more than one second to do so. This is unlikely to happen in practice, but the error path is still wrong.
timer_delete_sync() only waits for the timer callback itself. It does not flush deadwork that the callback may already have queued. As a result, queued deadwork can still hold a kref while the probe error path directly frees the backing mmc host, including the vub300 storage.
Fix this by using the same lifetime mechanism as disconnect. Clear vub300->interface so that the timer callback and any queued deadwork return early and drop their references, then drop the initial probe reference and return without falling through to err_free_host.
--- drivers/mmc/host/vub300.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/mmc/host/vub300.c +7 -3
@@ -2343,12 +2343,16 @@ static int vub300_probe(struct usb_inter interface_to_InterfaceNumber(interface)); retval =mmc_add_host (mmc);if (retval) - goto err_delete_timer; + goto err_stop_io;return 0 ; -err_delete_timer: -timer_delete_sync (&vub300->inactivity_timer); +err_stop_io: + vub300->interface =NULL ; +kref_put (&vub300->kref, vub300_delete); + +return retval; + err_free_host:mmc_free_host (mmc);/*
Greg Kroah-Hartman
maintainerPATCH 459/484 locking/rt: Fix the incorrect RCU protection in rt_spin_unlock()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Gleixner <[email protected]>
[ Upstream commit 89038cc87d80c77e7aa6f42a64b2573b74af339f ]
rt_spin_unlock() releases the RCU protection before unlocking the lock. That opens the door for the following UAF scenario:
T1 T2
spin_lock(&p->lock); rcu_read_lock();
invalidate(p); p = rcu_dereference(ptr);
rcu_assign_pointer(ptr, NULL); if (!p) return;
spin_unlock(&p->lock); spin_lock(&p->lock)
lock(&lock->lock); rcu_read_lock(); kfree_rcu(p); rcu_read_unlock(); .... spin_unlock(&p->lock) rcu_read_unlock(); // Ends grace period rcu_do_batch() kfree(p); UAF -> rt_mutex_cmpxchg_release(&lock->lock...)
Regular spinlocks keep preemption disabled accross the unlock operation, which provides full RCU protection, but the RT substitution fails to resemble that. Same applies for the rwlock substitution.
Move the rcu_read_unlock() invocation past the unlock operations to match the non-RT semantics. This makes it asymmetric vs. rt_xxx_lock(), but that's harmless as the caller needs to hold RCU read lock across the lock operation. The migrate_enable() call stays before the unlock operation because there is no per CPU operation in the unlock path which would require migration to be kept disabled.
--- kernel/locking/spinlock_rt.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-)
kernel/locking/spinlock_rt.c +24 -3
@@ -77,10 +77,27 @@ void __sched rt_spin_unlock(spinlock_t * {spin_release (&lock->dep_map, _RET_IP_);migrate_enable (); -rcu_read_unlock ();if (unlikely (!rt_mutex_cmpxchg_release (&lock->lock, current,NULL )))rt_mutex_slowunlock (&lock->lock); + +/* +* This must be last to prevent the following UAF: +* +* T1 T2 +* spin_lock(&p->lock); rcu_read_lock(); +* invalidate(p); p = rcu_dereference(ptr); +* rcu_assign_pointer(ptr, NULL); if (!p) return; +* spin_unlock(&p->lock); spin_lock(&p->lock); +* kfree_rcu(p); rcu_read_unlock(); +* .... +* spin_unlock(&p->lock) +* rcu_read_unlock(); // Ends grace period +* rcu_do_batch() +* kfree(p); +* UAF -> rt_mutex_cmpxchg_release(&p->lock.lock...) +*/ +rcu_read_unlock (); }EXPORT_SYMBOL (rt_spin_unlock);
@@ -255,17 +272,21 @@ void __sched rt_read_unlock(rwlock_t *rw {rwlock_release (&rwlock->dep_map, _RET_IP_);migrate_enable (); -rcu_read_unlock ();rwbase_read_unlock (&rwlock->rwbase,TASK_RTLOCK_WAIT ); + +/* This must be last. See comment in rt_spin_unlock() */ +rcu_read_unlock (); }EXPORT_SYMBOL (rt_read_unlock); void __sched rt_write_unlock(rwlock_t *rwlock) {rwlock_release (&rwlock->dep_map, _RET_IP_); -rcu_read_unlock ();migrate_enable ();rwbase_write_unlock (&rwlock->rwbase); + +/* This must be last. See comment in rt_spin_unlock() */ +rcu_read_unlock (); }EXPORT_SYMBOL (rt_write_unlock);
Greg Kroah-Hartman
maintainerPATCH 460/484 net: mana: Validate the packet length reported by the NIC
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dexuan Cui <[email protected]>
[ Upstream commit 2e2a83b4998af4384e677d3b2ac08565274279bf ]
Validate the packet length reported in the RX CQE before passing it to skb processing. The CQE is supplied by the NIC device and should not be blindly trusted.
--- drivers/net/ethernet/microsoft/mana/mana_en.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
drivers/net/ethernet/microsoft/mana/mana_en.c +13 -0
@@ -1739,6 +1739,19 @@ static void mana_process_rx_cqe(struct m rxbuf_oob = &rxq->rx_oobs[curr];WARN_ON_ONCE (rxbuf_oob->wqe_inf.wqe_size_in_bu !=1 ); +if (unlikely (pktlen > rxq->datasize)) { +/* Increase it even if mana_rx_skb() isn't called. */ + rxq->rx_cq.work_done++; + + ++ndev->stats.rx_dropped; +netdev_warn_once (ndev, +"Dropped oversized RX packet: len=%u, datasize=%u\n" , + pktlen, rxq->datasize); + +/* Reuse the RX buffer since rxbuf_oob is unchanged. */ + goto drop; + } +mana_refill_rx_oob (dev, rxq, rxbuf_oob, &old_buf, &old_fp);/* Unsuccessful refill will have old_buf == NULL.
Greg Kroah-Hartman
maintainerPATCH 461/484 pinctrl: remove pinctrl_gpio_direction_output()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bartosz Golaszewski <[email protected]>
[ Upstream commit 45d2055b0067739253883dc541f37c86aad45c92 ]
There are no more users of pinctrl_gpio_direction_output() so remove it.
Stable-dep-of: d3e91a95b2b0 ("gpio: tegra: do not call pinctrl for GPIO direction")
--- drivers/gpio/gpio-mvebu.c | 4 ++-- drivers/gpio/gpio-pxa.c | 4 ++-- drivers/gpio/gpio-tegra.c | 4 ++-- drivers/gpio/gpio-vf610.c | 4 ++-- drivers/pinctrl/cirrus/pinctrl-cs42l43.c | 4 ++-- drivers/pinctrl/cirrus/pinctrl-lochnagar.c | 2 +- drivers/pinctrl/core.c | 14 ++++++++------ drivers/pinctrl/intel/pinctrl-cherryview.c | 4 ++-- drivers/pinctrl/intel/pinctrl-intel.c | 4 ++-- drivers/pinctrl/intel/pinctrl-lynxpoint.c | 4 ++-- drivers/pinctrl/mediatek/pinctrl-moore.c | 4 ++-- drivers/pinctrl/mediatek/pinctrl-mtk-common.c | 4 ++-- drivers/pinctrl/mediatek/pinctrl-paris.c | 4 ++-- drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c | 4 ++-- drivers/pinctrl/pinctrl-as3722.c | 4 ++-- drivers/pinctrl/pinctrl-axp209.c | 2 +- drivers/pinctrl/pinctrl-cy8c95x0.c | 4 ++-- drivers/pinctrl/pinctrl-ingenic.c | 11 ++++++++--- drivers/pinctrl/pinctrl-ocelot.c | 4 ++-- drivers/pinctrl/pinctrl-rk805.c | 4 ++-- drivers/pinctrl/pinctrl-st.c | 4 ++-- drivers/pinctrl/renesas/gpio.c | 4 ++-- drivers/pinctrl/stm32/pinctrl-stm32.c | 4 ++-- drivers/pinctrl/vt8500/pinctrl-wmt.c | 4 ++-- include/linux/pinctrl/consumer.h | 13 +++++++++---- 25 files changed, 67 insertions(+), 55 deletions(-)
drivers/gpio/gpio-mvebu.c +2 -2
@@ -345,7 +345,7 @@ static int mvebu_gpio_direction_input(st* Check with the pinctrl driver whether this pin is usable as * an input GPIO */ - ret =pinctrl_gpio_direction_input (chip->base + pin); + ret =pinctrl_gpio_direction_input (chip, pin);if (ret)return ret;
@@ -365,7 +365,7 @@ static int mvebu_gpio_direction_output(s* Check with the pinctrl driver whether this pin is usable as * an output GPIO */ - ret =pinctrl_gpio_direction_output (chip->base + pin); + ret =pinctrl_gpio_direction_output (chip, pin);if (ret)return ret;
drivers/gpio/gpio-pxa.c +2 -2
@@ -260,7 +260,7 @@ static int pxa_gpio_direction_input(struint ret;if (pxa_gpio_has_pinctrl ()) { - ret =pinctrl_gpio_direction_input (chip->base + offset); + ret =pinctrl_gpio_direction_input (chip, offset);if (ret)return ret; }
@@ -289,7 +289,7 @@ static int pxa_gpio_direction_output(strwritel_relaxed (mask, base + (value ?GPSR_OFFSET :GPCR_OFFSET ));if (pxa_gpio_has_pinctrl ()) { - ret =pinctrl_gpio_direction_output (chip->base + offset); + ret =pinctrl_gpio_direction_output (chip, offset);if (ret)return ret; }
drivers/gpio/gpio-tegra.c +2 -2
@@ -179,7 +179,7 @@ static int tegra_gpio_direction_input(sttegra_gpio_mask_write (tgi,GPIO_MSK_OE (tgi, offset), offset,0 );tegra_gpio_enable (tgi, offset); - ret =pinctrl_gpio_direction_input (chip->base + offset); + ret =pinctrl_gpio_direction_input (chip, offset);if (ret <0 ) dev_err(tgi->dev, "Failed to set pinctrl input direction of GPIO %d: %d",
@@ -199,7 +199,7 @@ static int tegra_gpio_direction_output(stegra_gpio_mask_write (tgi,GPIO_MSK_OE (tgi, offset), offset,1 );tegra_gpio_enable (tgi, offset); - ret =pinctrl_gpio_direction_output (chip->base + offset); + ret =pinctrl_gpio_direction_output (chip, offset);if (ret <0 ) dev_err(tgi->dev, "Failed to set pinctrl output direction of GPIO %d: %d",
drivers/gpio/gpio-vf610.c +2 -2
@@ -116,7 +116,7 @@ static int vf610_gpio_direction_input(stvf610_gpio_writel (val, port->gpio_base +GPIO_PDDR ); } -return pinctrl_gpio_direction_input (chip->base + gpio); +return pinctrl_gpio_direction_input (chip, gpio); } static int vf610_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
@@ -134,7 +134,7 @@ static int vf610_gpio_direction_output(svf610_gpio_writel (val, port->gpio_base +GPIO_PDDR ); } -return pinctrl_gpio_direction_output (chip->base + gpio); +return pinctrl_gpio_direction_output (chip, gpio); }static void vf610_gpio_irq_handler (struct irq_desc *desc)
drivers/pinctrl/cirrus/pinctrl-cs42l43.c +2 -2
@@ -508,7 +508,7 @@ static void cs42l43_gpio_set(struct gpiostatic int cs42l43_gpio_direction_in (struct gpio_chip *chip,unsigned int offset) { -return pinctrl_gpio_direction_input (chip->base + offset); +return pinctrl_gpio_direction_input (chip, offset); } static int cs42l43_gpio_direction_out(struct gpio_chip *chip,
@@ -516,7 +516,7 @@ static int cs42l43_gpio_direction_out(st {cs42l43_gpio_set (chip, offset, value); -return pinctrl_gpio_direction_output (chip->base + offset); +return pinctrl_gpio_direction_output (chip, offset); }static int cs42l43_gpio_add_pin_ranges (struct gpio_chip *chip)
drivers/pinctrl/cirrus/pinctrl-lochnagar.c +1 -1
@@ -1098,7 +1098,7 @@ static int lochnagar_gpio_direction_out( {lochnagar_gpio_set (chip, offset, value); -return pinctrl_gpio_direction_output (chip->base + offset); +return pinctrl_gpio_direction_output (chip, offset); }static int lochnagar_fill_func_groups (struct lochnagar_pin_priv *priv)
drivers/pinctrl/core.c +8 -6
@@ -874,29 +874,31 @@ static int pinctrl_gpio_direction(unsign/** * pinctrl_gpio_direction_input() - request a GPIO pin to go into input mode -* @gpio: the GPIO pin number from the GPIO subsystem number space +* @gc: GPIO chip structure from the GPIO subsystem +* @offset: hardware offset of the GPIO relative to the controller * * This function should *ONLY* be used from gpiolib-based GPIO drivers, * as part of their gpio_direction_input() semantics, platforms and individual * drivers shall *NOT* touch pin control GPIO calls. */ -int pinctrl_gpio_direction_input (unsigned gpio) +int pinctrl_gpio_direction_input (struct gpio_chip *gc,unsigned int offset) { -return pinctrl_gpio_direction (gpio, true); +return pinctrl_gpio_direction (gc->base + offset, true); }EXPORT_SYMBOL_GPL (pinctrl_gpio_direction_input);/** * pinctrl_gpio_direction_output() - request a GPIO pin to go into output mode -* @gpio: the GPIO pin number from the GPIO subsystem number space +* @gc: GPIO chip structure from the GPIO subsystem +* @offset: hardware offset of the GPIO relative to the controller * * This function should *ONLY* be used from gpiolib-based GPIO drivers, * as part of their gpio_direction_output() semantics, platforms and individual * drivers shall *NOT* touch pin control GPIO calls. */ -int pinctrl_gpio_direction_output (unsigned gpio) +int pinctrl_gpio_direction_output (struct gpio_chip *gc,unsigned int offset) { -return pinctrl_gpio_direction (gpio, false); +return pinctrl_gpio_direction (gc->base + offset, false); }EXPORT_SYMBOL_GPL (pinctrl_gpio_direction_output);
drivers/pinctrl/intel/pinctrl-cherryview.c +2 -2
@@ -1172,14 +1172,14 @@ static int chv_gpio_get_direction(structstatic int chv_gpio_direction_input (struct gpio_chip *chip,unsigned int offset) { -return pinctrl_gpio_direction_input (chip->base + offset); +return pinctrl_gpio_direction_input (chip, offset); }static int chv_gpio_direction_output (struct gpio_chip *chip,unsigned int offset,int value) {chv_gpio_set (chip, offset, value); -return pinctrl_gpio_direction_output (chip->base + offset); +return pinctrl_gpio_direction_output (chip, offset); }static const struct gpio_chip chv_gpio_chip = {
drivers/pinctrl/intel/pinctrl-intel.c +2 -2
@@ -1026,14 +1026,14 @@ static int intel_gpio_get_direction(strustatic int intel_gpio_direction_input (struct gpio_chip *chip,unsigned int offset) { -return pinctrl_gpio_direction_input (chip->base + offset); +return pinctrl_gpio_direction_input (chip, offset); }static int intel_gpio_direction_output (struct gpio_chip *chip,unsigned int offset,int value) {intel_gpio_set (chip, offset, value); -return pinctrl_gpio_direction_output (chip->base + offset); +return pinctrl_gpio_direction_output (chip, offset); }static const struct gpio_chip intel_gpio_chip = {
drivers/pinctrl/intel/pinctrl-lynxpoint.c +2 -2
@@ -545,7 +545,7 @@ static void lp_gpio_set(struct gpio_chipstatic int lp_gpio_direction_input (struct gpio_chip *chip,unsigned int offset) { -return pinctrl_gpio_direction_input (chip->base + offset); +return pinctrl_gpio_direction_input (chip, offset); } static int lp_gpio_direction_output(struct gpio_chip *chip, unsigned int offset,
@@ -553,7 +553,7 @@ static int lp_gpio_direction_output(stru {lp_gpio_set (chip, offset, value); -return pinctrl_gpio_direction_output (chip->base + offset); +return pinctrl_gpio_direction_output (chip, offset); }static int lp_gpio_get_direction (struct gpio_chip *chip,unsigned int offset)
drivers/pinctrl/mediatek/pinctrl-moore.c +2 -2
@@ -509,7 +509,7 @@ static void mtk_gpio_set(struct gpio_chistatic int mtk_gpio_direction_input (struct gpio_chip *chip,unsigned int gpio) { -return pinctrl_gpio_direction_input (chip->base + gpio); +return pinctrl_gpio_direction_input (chip, gpio); } static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio,
@@ -517,7 +517,7 @@ static int mtk_gpio_direction_output(str {mtk_gpio_set (chip, gpio, value); -return pinctrl_gpio_direction_output (chip->base + gpio); +return pinctrl_gpio_direction_output (chip, gpio); }static int mtk_gpio_to_irq (struct gpio_chip *chip,unsigned int offset)
drivers/pinctrl/mediatek/pinctrl-mtk-common.c +2 -2
@@ -811,14 +811,14 @@ static const struct pinmux_ops mtk_pmx_ostatic int mtk_gpio_direction_input (struct gpio_chip *chip,unsigned offset) { -return pinctrl_gpio_direction_input (chip->base + offset); +return pinctrl_gpio_direction_input (chip, offset); }static int mtk_gpio_direction_output (struct gpio_chip *chip,unsigned offset,int value) {mtk_gpio_set (chip, offset, value); -return pinctrl_gpio_direction_output (chip->base + offset); +return pinctrl_gpio_direction_output (chip, offset); }static int mtk_gpio_get_direction (struct gpio_chip *chip,unsigned offset)
drivers/pinctrl/mediatek/pinctrl-paris.c +2 -2
@@ -904,7 +904,7 @@ static int mtk_gpio_direction_input(struif (gpio >= hw->soc->npins)return -EINVAL ; -return pinctrl_gpio_direction_input (chip->base + gpio); +return pinctrl_gpio_direction_input (chip, gpio); } static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio,
@@ -917,7 +917,7 @@ static int mtk_gpio_direction_output(strmtk_gpio_set (chip, gpio, value); -return pinctrl_gpio_direction_output (chip->base + gpio); +return pinctrl_gpio_direction_output (chip, gpio); }static int mtk_gpio_to_irq (struct gpio_chip *chip,unsigned int offset)
drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c +2 -2
@@ -171,7 +171,7 @@ static int npcmgpio_direction_input(strustruct npcm7xx_gpio *bank =gpiochip_get_data (chip);int ret; - ret =pinctrl_gpio_direction_input (offset + chip->base); + ret =pinctrl_gpio_direction_input (chip, offset);if (ret)return ret;
@@ -188,7 +188,7 @@ static int npcmgpio_direction_output(strdev_dbg (chip->parent,"gpio_direction_output: offset%d = %x\n" , offset, value); - ret =pinctrl_gpio_direction_output (offset + chip->base); + ret =pinctrl_gpio_direction_output (chip, offset);if (ret)return ret;
drivers/pinctrl/pinctrl-as3722.c +2 -2
@@ -502,14 +502,14 @@ static void as3722_gpio_set(struct gpio_static int as3722_gpio_direction_input (struct gpio_chip *chip,unsigned offset) { -return pinctrl_gpio_direction_input (chip->base + offset); +return pinctrl_gpio_direction_input (chip, offset); }static int as3722_gpio_direction_output (struct gpio_chip *chip,unsigned offset,int value) {as3722_gpio_set (chip, offset, value); -return pinctrl_gpio_direction_output (chip->base + offset); +return pinctrl_gpio_direction_output (chip, offset); }static int as3722_gpio_to_irq (struct gpio_chip *chip,unsigned offset)
drivers/pinctrl/pinctrl-axp209.c +1 -1
@@ -126,7 +126,7 @@ static int axp20x_gpio_get_reg(unsignedstatic int axp20x_gpio_input (struct gpio_chip *chip,unsigned int offset) { -return pinctrl_gpio_direction_input (chip->base + offset); +return pinctrl_gpio_direction_input (chip, offset); }static int axp20x_gpio_get (struct gpio_chip *chip,unsigned int offset)
drivers/pinctrl/pinctrl-cy8c95x0.c +2 -2
@@ -557,7 +557,7 @@ out:static int cy8c95x0_gpio_direction_input (struct gpio_chip *gc,unsigned int off) { -return pinctrl_gpio_direction_input (gc->base + off); +return pinctrl_gpio_direction_input (gc, off); } static int cy8c95x0_gpio_direction_output(struct gpio_chip *gc,
@@ -574,7 +574,7 @@ static int cy8c95x0_gpio_direction_outpuif (ret)return ret; -return pinctrl_gpio_direction_output (gc->base + off); +return pinctrl_gpio_direction_output (gc, off); }static int cy8c95x0_gpio_get_value (struct gpio_chip *gc,unsigned int off)
drivers/pinctrl/pinctrl-ingenic.c +8 -3
@@ -133,6 +133,8 @@ struct ingenic_pinctrl {struct pinctrl_pin_desc *pdesc;const struct ingenic_chip_info *info; + +struct gpio_chip *gc; };struct ingenic_gpio_chip {
@@ -3561,14 +3563,14 @@ static int ingenic_gpio_get(struct gpio_static int ingenic_gpio_direction_input (struct gpio_chip *gc,unsigned int offset) { -return pinctrl_gpio_direction_input (gc->base + offset); +return pinctrl_gpio_direction_input (gc, offset); }static int ingenic_gpio_direction_output (struct gpio_chip *gc,unsigned int offset,int value) {ingenic_gpio_set (gc, offset, value); -return pinctrl_gpio_direction_output (gc->base + offset); +return pinctrl_gpio_direction_output (gc, offset); } static inline void ingenic_config_pin(struct ingenic_pinctrl *jzpc,
@@ -4052,7 +4054,8 @@ static int ingenic_pinconf_set(struct pibreak ;case PIN_CONFIG_OUTPUT : - ret =pinctrl_gpio_direction_output (pin); + ret =pinctrl_gpio_direction_output (jzpc->gc, + pin - jzpc->gc->base);if (ret)return ret;
@@ -4172,6 +4175,8 @@ static int __init ingenic_gpio_probe(strif (!jzgc)return -ENOMEM ; + jzpc->gc = &jzgc->gc; + jzgc->jzpc = jzpc; jzgc->reg_base = bank * jzpc->info->reg_offset;
drivers/pinctrl/pinctrl-ocelot.c +2 -2
@@ -1779,7 +1779,7 @@ static int ocelot_gpio_get_direction(strstatic int ocelot_gpio_direction_input (struct gpio_chip *chip,unsigned int offset) { -return pinctrl_gpio_direction_input (chip->base + offset); +return pinctrl_gpio_direction_input (chip, offset); } static int ocelot_gpio_direction_output(struct gpio_chip *chip,
@@ -1795,7 +1795,7 @@ static int ocelot_gpio_direction_output(regmap_write (info->map,REG (OCELOT_GPIO_OUT_CLR , info, offset), pin); -return pinctrl_gpio_direction_output (chip->base + offset); +return pinctrl_gpio_direction_output (chip, offset); }static const struct gpio_chip ocelot_gpiolib_chip = {
drivers/pinctrl/pinctrl-rk805.c +2 -2
@@ -289,14 +289,14 @@ static void rk805_gpio_set(struct gpio_cstatic int rk805_gpio_direction_input (struct gpio_chip *chip,unsigned int offset) { -return pinctrl_gpio_direction_input (chip->base + offset); +return pinctrl_gpio_direction_input (chip, offset); }static int rk805_gpio_direction_output (struct gpio_chip *chip,unsigned int offset,int value) {rk805_gpio_set (chip, offset, value); -return pinctrl_gpio_direction_output (chip->base + offset); +return pinctrl_gpio_direction_output (chip, offset); }static int rk805_gpio_get_direction (struct gpio_chip *chip,unsigned int offset)
drivers/pinctrl/pinctrl-st.c +2 -2
@@ -719,7 +719,7 @@ static void st_gpio_set(struct gpio_chipstatic int st_gpio_direction_input (struct gpio_chip *chip,unsigned offset) { -pinctrl_gpio_direction_input (chip->base + offset); +pinctrl_gpio_direction_input (chip, offset);return 0 ; }
@@ -730,7 +730,7 @@ static int st_gpio_direction_output(strustruct st_gpio_bank *bank =gpiochip_get_data (chip);__st_gpio_set (bank, offset, value); -pinctrl_gpio_direction_output (chip->base + offset); +pinctrl_gpio_direction_output (chip, offset);return 0 ; }
drivers/pinctrl/renesas/gpio.c +2 -2
@@ -164,7 +164,7 @@ static void gpio_pin_set_value(struct shstatic int gpio_pin_direction_input (struct gpio_chip *gc,unsigned offset) { -return pinctrl_gpio_direction_input (gc->base + offset); +return pinctrl_gpio_direction_input (gc, offset); } static int gpio_pin_direction_output(struct gpio_chip *gc, unsigned offset,
@@ -172,7 +172,7 @@ static int gpio_pin_direction_output(str {gpio_pin_set_value (gpiochip_get_data (gc), offset, value); -return pinctrl_gpio_direction_output (gc->base + offset); +return pinctrl_gpio_direction_output (gc, offset); }static int gpio_pin_get (struct gpio_chip *gc,unsigned offset)
drivers/pinctrl/stm32/pinctrl-stm32.c +2 -2
@@ -241,7 +241,7 @@ static void stm32_gpio_set(struct gpio_cstatic int stm32_gpio_direction_input (struct gpio_chip *chip,unsigned offset) { -return pinctrl_gpio_direction_input (chip->base + offset); +return pinctrl_gpio_direction_input (chip, offset); } static int stm32_gpio_direction_output(struct gpio_chip *chip,
@@ -250,7 +250,7 @@ static int stm32_gpio_direction_output(sstruct stm32_gpio_bank *bank =gpiochip_get_data (chip);__stm32_gpio_set (bank, offset, value); -pinctrl_gpio_direction_output (chip->base + offset); +pinctrl_gpio_direction_output (chip, offset);return 0 ; }
drivers/pinctrl/vt8500/pinctrl-wmt.c +2 -2
@@ -528,14 +528,14 @@ static void wmt_gpio_set_value(struct gpstatic int wmt_gpio_direction_input (struct gpio_chip *chip,unsigned offset) { -return pinctrl_gpio_direction_input (chip->base + offset); +return pinctrl_gpio_direction_input (chip, offset); }static int wmt_gpio_direction_output (struct gpio_chip *chip,unsigned offset,int value) {wmt_gpio_set_value (chip, offset, value); -return pinctrl_gpio_direction_output (chip->base + offset); +return pinctrl_gpio_direction_output (chip, offset); }static const struct gpio_chip wmt_gpio_chip = {
include/linux/pinctrl/consumer.h +9 -4
@@ -17,6 +17,7 @@#include <linux/pinctrl/pinctrl-state.h> struct device ; +struct gpio_chip ;/* This struct is private to the core and should be regarded as a cookie */ struct pinctrl ;
@@ -28,8 +29,10 @@ struct pinctrl_state;extern bool pinctrl_gpio_can_use_line (unsigned gpio);extern int pinctrl_gpio_request (unsigned gpio);extern void pinctrl_gpio_free (unsigned gpio); -extern int pinctrl_gpio_direction_input (unsigned gpio); -extern int pinctrl_gpio_direction_output (unsigned gpio); +extern int pinctrl_gpio_direction_input (struct gpio_chip *gc, +unsigned int offset); +extern int pinctrl_gpio_direction_output (struct gpio_chip *gc, +unsigned int offset);extern int pinctrl_gpio_set_config (unsigned gpio,unsigned long config);extern struct pinctrl *__must_check pinctrl_get (struct device *dev);
@@ -77,12 +80,14 @@ static inline void pinctrl_gpio_free(uns { } -static inline int pinctrl_gpio_direction_input (unsigned gpio) +static inline int +pinctrl_gpio_direction_input (struct gpio_chip *gc,unsigned int offset) {return 0 ; } -static inline int pinctrl_gpio_direction_output (unsigned gpio) +static inline int +pinctrl_gpio_direction_output (struct gpio_chip *gc,unsigned int offset) {return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 462/484 gpio: tegra: do not call pinctrl for GPIO direction
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Runyu Xiao <[email protected]>
[ Upstream commit d3e91a95b2b0fc6336dbf3ec90d831a1654d2720 ]
tegra_gpio_direction_input() and tegra_gpio_direction_output() already program the GPIO controller direction registers directly. The additional pinctrl_gpio_direction_input/output() calls do not add a Tegra pinctrl operation, because the Tegra pinmux ops provide GPIO request/free handling but no gpio_set_direction hook.
The extra call still enters the pinctrl core and takes pctldev->mutex. Shared GPIO users can call the direction path while holding their per-line spinlock, so this otherwise redundant pinctrl direction call can sleep in an atomic context.
This was found by our static analysis tool and then confirmed by manual review of tegra_gpio_probe(), the Tegra GPIO direction callbacks and the Tegra pinctrl ops. The reviewed path has a default non-sleeping struct gpio_chip while the direction callback still enters the pinctrl mutex path.
A directed runtime validation kept the same non-sleeping chip registration and drove:
gpio_shared_proxy_direction_output()
gpiod_direction_output_raw_commit()
tegra_gpio_direction_output()
pinctrl_gpio_direction_output()
Lockdep reported a sleep-in-atomic warning with the shared GPIO spinlock held and pinctrl_get_device_gpio_range() plus tegra_gpio_direction_output() on the stack.
Do not mark the whole chip as can_sleep to paper over this: can_sleep describes whether get()/set() may sleep, and Tegra value access is MMIO. Remove the redundant pinctrl direction calls and keep pinctrl involvement in the existing request/free path.
--- drivers/gpio/gpio-tegra.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-)
drivers/gpio/gpio-tegra.c +2 -16
@@ -174,18 +174,11 @@ static int tegra_gpio_direction_input(st unsigned int offset) {struct tegra_gpio_info *tgi =gpiochip_get_data (chip); -int ret;tegra_gpio_mask_write (tgi,GPIO_MSK_OE (tgi, offset), offset,0 );tegra_gpio_enable (tgi, offset); - ret =pinctrl_gpio_direction_input (chip, offset); -if (ret <0 ) -dev_err (tgi->dev, -"Failed to set pinctrl input direction of GPIO %d: %d" , - chip->base + offset, ret); - -return ret; +return 0 ; } static int tegra_gpio_direction_output(struct gpio_chip *chip,
@@ -193,19 +186,12 @@ static int tegra_gpio_direction_output(s int value) {struct tegra_gpio_info *tgi =gpiochip_get_data (chip); -int ret;tegra_gpio_set (chip, offset, value);tegra_gpio_mask_write (tgi,GPIO_MSK_OE (tgi, offset), offset,1 );tegra_gpio_enable (tgi, offset); - ret =pinctrl_gpio_direction_output (chip, offset); -if (ret <0 ) -dev_err (tgi->dev, -"Failed to set pinctrl output direction of GPIO %d: %d" , - chip->base + offset, ret); - -return ret; +return 0 ; } static int tegra_gpio_get_direction(struct gpio_chip *chip,
Greg Kroah-Hartman
maintainerPATCH 463/484 net: ip6_tunnel: require CAP_NET_ADMIN in the device netns for changelink
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maoyi Xie <[email protected]>
[ Upstream commit 2496fa0b7d180b3ad356b514e7ff93bb14e6140a ]
ip6_tnl_changelink() operates on at most two netns, dev_net(dev) and the tunnel link netns t->net. They differ once the device is created in or moved to a netns other than the one the request runs in. The rtnl changelink path checks CAP_NET_ADMIN only against dev_net(dev), so a caller privileged there but not in t->net can rewrite a tunnel that lives in t->net.
Gate ip6_tnl_changelink() on rtnl_dev_link_net_capable() at its top, before any attribute is parsed.
--- net/ipv6/ip6_tunnel.c | 3 +++ 1 file changed, 3 insertions(+)
net/ipv6/ip6_tunnel.c +3 -0
@@ -2055,6 +2055,9 @@ static int ip6_tnl_changelink(struct netstruct ip6_tnl_net *ip6n =net_generic (net, ip6_tnl_net_id);struct ip_tunnel_encap ipencap; +if (!rtnl_dev_link_net_capable (dev, net)) +return -EPERM ; +if (dev == ip6n->fb_tnl_dev)return -EINVAL ;
Greg Kroah-Hartman
maintainerPATCH 464/484 gpio: mt7621: avoid corruption of shared interrupt trigger state
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sergio Paracuellos <[email protected]>
[ Upstream commit 1781172526d1092323af443fa03f00e6de560401 ]
The bank-shared fields like 'rising' and 'falling' are modified using non-atomic read-modify-write operations. Since every gpio chip instance represents an entire bank of 32 pins, if 'mediatek_gpio_irq_type()' is called concurrently for different IRQs on the same bank a possible overwrite of each other's configuration is possible. Thus, protect this state with 'gpio_generic_lock_irqsave' lock in the same way it is handled in irp_chip 'mediatek_gpio_irq_mask()' and 'mediatek_gpio_irq_unmask()' callbacks.
--- drivers/gpio/gpio-mt7621.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpio/gpio-mt7621.c +2 -0
@@ -156,6 +156,8 @@ mediatek_gpio_irq_type(struct irq_data *int pin = d->hwirq;u32 mask =BIT (pin); +guard (spinlock_irqsave)(&rg->lock); +if (type ==IRQ_TYPE_PROBE ) {if ((rg->rising | rg->falling | rg->hlevel | rg->llevel) & mask)
Greg Kroah-Hartman
maintainerPATCH 465/484 octeontx2-af: cn10k: restrict VF LMTLINE sharing to its own PF
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Junrui Luo <[email protected]>
[ Upstream commit 8cdcf3d2caacdee7ddd363705fb4d93b0c1a0915 ]
rvu_mbox_handler_lmtst_tbl_setup() uses req->base_pcifunc as a direct index into the LMT map table to read another function's LMTLINE physical base address and copy it into the caller's own LMT map table entry. The mailbox dispatcher authenticates req->hdr.pcifunc from the IRQ source, but req->base_pcifunc is a separate payload field and is not sanitized.
Reject the request with -EPERM when a VF caller's base_pcifunc is not a valid function under its own PF. is_pf_func_valid() bounds the FUNC field to the PF's configured VF count, keeping the computed index inside the caller's own slot block.
--- drivers/net/ethernet/marvell/octeontx2/af/rvu.c | 2 +- drivers/net/ethernet/marvell/octeontx2/af/rvu.h | 1 + drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c | 9 +++++++++ 3 files changed, 11 insertions(+), 1 deletion(-)
drivers/net/ethernet/marvell/octeontx2/af/rvu.c +1 -1
@@ -440,7 +440,7 @@ struct rvu_pfvf *rvu_get_pfvf(struct rvureturn &rvu->pf[rvu_get_pf (pcifunc)]; } -static bool is_pf_func_valid (struct rvu *rvu,u16 pcifunc) +bool is_pf_func_valid (struct rvu *rvu,u16 pcifunc) {int pf, vf, nvfs;u64 cfg;
drivers/net/ethernet/marvell/octeontx2/af/rvu.h +1 -0
@@ -751,6 +751,7 @@ int rvu_get_pf(u16 pcifunc);struct rvu_pfvf *rvu_get_pfvf (struct rvu *rvu,int pcifunc);void rvu_get_pf_numvfs (struct rvu *rvu,int pf,int *numvfs,int *hwvf);bool is_block_implemented (struct rvu_hwinfo *hw,int blkaddr); +bool is_pf_func_valid (struct rvu *rvu,u16 pcifunc);bool is_pffunc_map_valid (struct rvu *rvu,u16 pcifunc,int blktype);int rvu_get_lf (struct rvu *rvu,struct rvu_block *block,u16 pcifunc,u16 slot);int rvu_lf_reset (struct rvu *rvu,struct rvu_block *block,int lf);
drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c +9 -0
@@ -178,6 +178,15 @@ int rvu_mbox_handler_lmtst_tbl_setup(str* pcifunc (will be the one who is calling this mailbox). */ if (req->base_pcifunc) { +/* A VF is untrusted and must not redirect its LMTLINE to +* another PF's region, so confine VF callers to their own PF. +*/ +if (is_vf (req->hdr.pcifunc) && + (!is_pf_func_valid (rvu, req->base_pcifunc) || +rvu_get_pf (req->hdr.pcifunc) != +rvu_get_pf (req->base_pcifunc))) +return -EPERM ; +/* Calculating the LMT table index equivalent to primary * pcifunc. */
Greg Kroah-Hartman
maintainerPATCH 466/484 bootconfig: do not put quotes on cmdline items unless necessary
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rasmus Villemoes <[email protected]>
[ Upstream commit 212f863fa8811c780abacc1d0404c573fdc0a2de ]
When trying to migrate to using bootconfig to embed the kernel's and PID1's command line with the kernel image itself, and so allowing changing that without modifying the bootloader, I noticed that /proc/cmdline changed from e.g.
console=ttymxc0,115200n8 cma=128M quiet -- --log-level=notice
to
console="ttymxc0,115200n8" cma="128M" quiet -- --log-level="notice"
The kernel parameters are parsed just fine, and the quotes are indeed stripped from the actual argv[] given to PID1. However, the quoting doesn't really serve any purpose and looks excessive, and might confuse some (naive) userspace tool trying to parse /proc/cmdline. So do not quote the value unless it contains whitespace.
Stable-dep-of: dec4d8118c17 ("bootconfig: fix NULL-pointer arithmetic in xbc_snprint_cmdline()")
--- init/main.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
init/main.c +9 -3
@@ -325,7 +325,7 @@ static int __init xbc_snprint_cmdline(ch {struct xbc_node *knode, *vnode;char *end = buf + size; -const char *val; +const char *val, *q;int ret;xbc_node_for_each_key_value (root, knode, val) {
@@ -343,8 +343,14 @@ static int __init xbc_snprint_cmdline(chcontinue ; }xbc_array_for_each_value (vnode, val) { - ret =snprintf (buf,rest (buf, end),"%s=\"%s\" " , - xbc_namebuf, val); +/* +* For prettier and more readable /proc/cmdline, only +* quote the value when necessary, i.e. when it contains +* whitespace. +*/ + q =strpbrk (val," \t\r\n" ) ?"\"" :"" ; + ret =snprintf (buf,rest (buf, end),"%s=%s%s%s " , + xbc_namebuf, q, val, q);if (ret <0 )return ret; buf += ret;
Greg Kroah-Hartman
maintainerPATCH 467/484 bootconfig: move xbc_snprint_cmdline() to lib/bootconfig.c
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit 5a643e4623238e14b03d75ca0d4eda0645720cee ]
Move xbc_snprint_cmdline() from init/main.c to lib/bootconfig.c so the function (and its xbc_namebuf scratch buffer) becomes part of the shared parser library. tools/bootconfig already compiles lib/bootconfig.c directly, which lets a follow-up patch reuse the same renderer in the userspace tool to convert a bootconfig file into a flat cmdline string at build time.
No functional change.
Stable-dep-of: dec4d8118c17 ("bootconfig: fix NULL-pointer arithmetic in xbc_snprint_cmdline()")
--- include/linux/bootconfig.h | 3 ++ init/main.c | 45 ------------------------------------ lib/bootconfig.c | 56 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 45 deletions(-)
include/linux/bootconfig.h +3 -0
@@ -264,6 +264,9 @@ static inline struct xbc_node * __init xint __init xbc_node_compose_key_after (struct xbc_node *root,struct xbc_node *node,char *buf,size_t size); +/* Render key/value pairs under @root as a flat cmdline string */ +int __init xbc_snprint_cmdline (char *buf,size_t size,struct xbc_node *root); +/** * xbc_node_compose_key() - Compose full key string of the XBC node * @node: An XBC node.
init/main.c +0 -45
51 lines not on this page · raw message
lib/bootconfig.c +56 -0
62 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 468/484 bootconfig: fix NULL-pointer arithmetic in xbc_snprint_cmdline()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit dec4d8118c179b3d12bca7e609054c6011c4f2ce ]
xbc_snprint_cmdline() is meant to be called twice: first with buf=NULL, size=0 to probe the rendered length, then with a real buffer to fill it (the standard snprintf() two-pass pattern). The probe call makes the function compute "buf + size" (NULL + 0) and, on every iteration, advance "buf += ret" from that NULL base and pass the result back into snprintf().
Pointer arithmetic on a NULL pointer is undefined behavior. It is harmless in the in-kernel callers today, but the follow-up patches run this same code in the userspace tools/bootconfig parser at kernel build time, where host UBSan / FORTIFY_SOURCE abort the build.
Track a running written length (size_t) instead of mutating @buf, and only form "buf + len" when @buf is non-NULL. snprintf(NULL, 0, ...) is itself well defined and returns the would-be length, so the two-pass "probe then fill" usage returns identical byte counts.
--- lib/bootconfig.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-)
lib/bootconfig.c +16 -7
@@ -426,10 +426,18 @@ static char xbc_namebuf[XBC_KEYLEN_MAX]int __init xbc_snprint_cmdline (char *buf,size_t size,struct xbc_node *root) {struct xbc_node *knode, *vnode; -char *end = buf + size;const char *val, *q; +size_t len =0 ;int ret; +/* +* Track the running written length rather than advancing @buf, so we +* never form "buf + size" or "buf += ret" while @buf is NULL (the +* size-probe call passes buf=NULL, size=0). NULL pointer arithmetic +* is undefined behavior and trips host UBSan / FORTIFY_SOURCE when +* this renderer runs at kernel build time. snprintf(NULL, 0, ...) +* itself is well defined and returns the would-be length. +*/ xbc_node_for_each_key_value (root, knode, val) { ret =xbc_node_compose_key_after (root, knode, xbc_namebuf,XBC_KEYLEN_MAX );
@@ -438,10 +446,11 @@ int __init xbc_snprint_cmdline(char *buf vnode =xbc_node_get_child (knode);if (!vnode) { - ret =snprintf (buf,rest (buf, end),"%s " , xbc_namebuf); + ret =snprintf (buf ? buf + len :NULL ,rest (len, size), +"%s " , xbc_namebuf);if (ret <0 )return ret; - buf += ret; + len += ret;continue ; }xbc_array_for_each_value (vnode, val) {
@@ -451,15 +460,15 @@ int __init xbc_snprint_cmdline(char *buf* whitespace. */ q =strpbrk (val," \t\r\n" ) ?"\"" :"" ; - ret =snprintf (buf,rest (buf, end),"%s=%s%s%s " , - xbc_namebuf, q, val, q); + ret =snprintf (buf ? buf + len :NULL ,rest (len, size), +"%s=%s%s%s " , xbc_namebuf, q, val, q);if (ret <0 )return ret; - buf += ret; + len += ret; } } -return buf - (end - size); +return len; }#undef rest
Greg Kroah-Hartman
maintainerPATCH 469/484 ipmi: fix refcount leak in i_ipmi_request()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Liang <[email protected]>
[ Upstream commit a3f3859cecacb64f18fd446271ece9a3b3f2d4de ]
When a caller provides a supplied_recv message to i_ipmi_request(), the function increments the user's nr_msgs reference count. If an error occurs later, the out_err cleanup path only frees the recv_msg if the function allocated it itself (i.e., !supplied_recv). In the supplied_recv case the cleanup is skipped, leaving the reference count elevated. The caller ipmi_request_supply_msgs() does not release the supplied_recv on error, so the reference is permanently leaked.
Fix this by explicitly reverting the reference count operations when a supplied recv_msg with a valid user pointer is present in the error
path: decrement nr_msgs and drop the user's kref.
Message-ID: <[email protected]>
--- drivers/char/ipmi/ipmi_msghandler.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/char/ipmi/ipmi_msghandler.c +8 -0
@@ -2331,6 +2331,10 @@ static int i_ipmi_request(struct ipmi_usif (smi_msg ==NULL ) {if (!supplied_recv)ipmi_free_recv_msg (recv_msg); +else if (recv_msg->user) { +atomic_dec (&recv_msg->user->nr_msgs); +kref_put (&recv_msg->user->refcount, free_user); + }return -ENOMEM ; } }
@@ -2373,6 +2377,10 @@ out_err:ipmi_free_smi_msg (smi_msg);if (!supplied_recv)ipmi_free_recv_msg (recv_msg); +else if (recv_msg->user) { +atomic_dec (&recv_msg->user->nr_msgs); +kref_put (&recv_msg->user->refcount, free_user); + } }else {dev_dbg (intf->si_dev,"Send: %*ph\n" , smi_msg->data_size, smi_msg->data);
Greg Kroah-Hartman
maintainerPATCH 470/484 octeontx2-pf: fix SQB pointer leak on init failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dawei Feng <[email protected]>
[ Upstream commit 62e7df6d042aeebd5efb581074e28865c04477be ]
otx2_init_hw_resources() initializes SQ aura and pool resources before several later setup steps. On failure, err_free_sq_ptrs only frees SQB pages, leaving the per-SQ sqb_ptrs arrays behind.
Use otx2_free_sq_res() for the SQ unwind path and let it free sqb_ptrs even when sq->sqe has not been allocated yet.
The bug was first flagged by an experimental analysis tool we are developing for kernel memory-management bugs while analyzing v6.13-rc1. The tool is still under development and is not yet publicly available. Manual inspection confirms that the bug is still present in v7.1.1.
An x86_64 allyesconfig build showed no new warnings. As we do not have an OcteonTX2 PF device and the corresponding AF mailbox setup to test with, no runtime testing was able to be performed.
--- drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-)
drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +8 -9
@@ -1442,13 +1442,13 @@ static void otx2_free_sq_res(struct otx2otx2_sq_free_sqbs (pf);for (qidx =0 ; qidx <otx2_get_total_tx_queues (pf); qidx++) { sq = &qset->sq[qidx]; -/* Skip freeing Qos queues if they are not initialized */ -if (!sq->sqe) -continue ; -qmem_free (pf->dev, sq->sqe); -qmem_free (pf->dev, sq->tso_hdrs); -qmem_free (pf->dev, sq->timestamps); -kfree (sq->sg); +/* sq->sqe is not initialized for unused QoS queues */ +if (sq->sqe) { +qmem_free (pf->dev, sq->sqe); +qmem_free (pf->dev, sq->tso_hdrs); +qmem_free (pf->dev, sq->timestamps); +kfree (sq->sg); + }kfree (sq->sqb_ptrs); } }
@@ -1574,13 +1574,12 @@ static int otx2_init_hw_resources(structreturn err; err_free_nix_queues: -otx2_free_sq_res (pf);otx2_free_cq_res (pf);otx2_ctx_disable (mbox,NIX_AQ_CTYPE_RQ , false); err_free_txsch:otx2_txschq_stop (pf); err_free_sq_ptrs: -otx2_sq_free_sqbs (pf); +otx2_free_sq_res (pf); err_free_rq_ptrs:otx2_free_aura_ptr (pf,AURA_NIX_RQ );otx2_ctx_disable (mbox,NPA_AQ_CTYPE_POOL , true);
Greg Kroah-Hartman
maintainerPATCH 471/484 ata: libata-core: Reject an invalid concurrent positioning ranges count
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
[ Upstream commit 533a0b940f901c15e5cbbd4b5d66e871c209e8ce ]
ata_dev_config_cpr() takes the number of range descriptors from buf[0] of the concurrent positioning ranges log (up to 255), which the device reports independently of the log size in the GPL directory. The count is then walked at a fixed 32-byte stride in two places with no bound: the log read here, and the INQUIRY VPD page B9h emitter, which writes one descriptor per range into the fixed 2048-byte ata_scsi_rbuf. A device reporting a count larger than its own log overflows the read buffer (up to 7704 bytes past a 512-byte slab), and a count above 62 overflows the response buffer on the emit side.
Bound the count once, on probe, against both the log the device returned and the number of descriptors the VPD B9h response buffer can hold (ATA_DEV_MAX_CPR, derived from the rbuf size). Reject an out-of-range count with a warning; this keeps the emitter in bounds with no separate change there.
--- drivers/ata/libata-core.c | 18 ++++++++++++++++++ drivers/ata/libata-scsi.c | 2 -- drivers/ata/libata.h | 9 +++++++++ 3 files changed, 27 insertions(+), 2 deletions(-)
drivers/ata/libata-core.c +18 -0
@@ -2794,6 +2794,24 @@ static void ata_dev_config_cpr(struct atif (!nr_cpr) goto out; +/* +* The device reports the number of CPR descriptors independently of the +* log size, and that count is also used to emit VPD page B9h into the +* fixed-size rbuf. Reject a count larger than what that buffer can hold +* (ATA_DEV_MAX_CPR) or larger than the log the device actually returned. +*/ +if (nr_cpr >ATA_DEV_MAX_CPR ) { +ata_dev_warn (dev, +"Too many concurrent positioning ranges\n" ); + goto out; + } + +if (buf_len <64 + (size_t )nr_cpr *32 ) { +ata_dev_warn (dev, +"Invalid number of concurrent positioning ranges\n" ); + goto out; + } + cpr_log =kzalloc (struct_size (cpr_log, cpr, nr_cpr),GFP_KERNEL );if (!cpr_log) goto out;
drivers/ata/libata-scsi.c +0 -2
@@ -37,8 +37,6 @@#include "libata.h" #include "libata-transport.h" -#define ATA_SCSI_RBUF_SIZE 2048 -static DEFINE_SPINLOCK (ata_scsi_rbuf_lock);static u8 ata_scsi_rbuf[ATA_SCSI_RBUF_SIZE ];
drivers/ata/libata.h +9 -0
@@ -111,6 +111,15 @@ static inline void ata_acpi_bind_dev(str#endif /* libata-scsi.c */ +#define ATA_SCSI_RBUF_SIZE 2048 + +/* +* Maximum number of concurrent positioning ranges (CPR) supported. The ACS +* specifications allow up to 255, but we limit this to the number of CPR +* descriptors that fit in the rbuf buffer used to emit VPD page B9h. +*/ +#define ATA_DEV_MAX_CPR min(255, ((ATA_SCSI_RBUF_SIZE - 64) / 32)) +extern struct ata_device *ata_scsi_find_dev (struct ata_port *ap,const struct scsi_device *scsidev); extern int ata_scsi_add_hosts(struct ata_host *host,
Greg Kroah-Hartman
maintainerPATCH 472/484 net: macb: drop in-flight Tx SKBs on close
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Théo Lebrun <[email protected]>
[ Upstream commit 27f575836cfebbf872dec020428742b10650a955 ]
The MACB driver has since forever leaked the outgoing SKBs that have not yet been marked as completed. They live in queue->tx_skb which gets freed without remorse nor checking.
macb_free_consistent() gets called in a few codepaths, but only close will trigger the added expressions. In macb_open() and macb_alloc_consistent() failure cases, queues' tx_skb just got allocated and are empty.
--- drivers/net/ethernet/cadence/macb_main.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-)
drivers/net/ethernet/cadence/macb_main.c +20 -2
@@ -2582,8 +2582,26 @@ static void macb_free_consistent(struct bp->macbgem_ops.mog_free_rx_buffers (bp);for (q =0 , queue = bp->queues; q < bp->num_queues; ++q, ++queue) { -kfree (queue->tx_skb); - queue->tx_skb =NULL ; +if (queue->tx_skb) { +unsigned int dropped =0 , tail; + +for (tail = queue->tx_tail; tail != queue->tx_head; + tail++) { +if (macb_tx_skb (queue, tail)->skb) + dropped++; +macb_tx_unmap (bp,macb_tx_skb (queue, tail),0 ); + } + + queue->stats.tx_dropped += dropped; + bp->dev->stats.tx_dropped += dropped; + +kfree (queue->tx_skb); + queue->tx_skb =NULL ; + } + + queue->tx_head =0 ; + queue->tx_tail =0 ; +if (queue->tx_ring) { size =TX_RING_BYTES (bp) + bp->tx_bd_rd_prefetch; dma_free_coherent(&bp->pdev->dev, size,
Greg Kroah-Hartman
maintainerPATCH 473/484 net: ipa: fix SMEM state handle leaks in SMP2P init
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haoxiang Li <[email protected]>
[ Upstream commit 96ca1e658ae459276292bd6d971ab5d8c7e0379a ]
ipa_smp2p_init() acquires two Qualcomm SMEM state handles with qcom_smem_state_get(). However, neither the init error paths nor ipa_smp2p_exit() release them.
Release both handles with qcom_smem_state_put() in the init error paths and in ipa_smp2p_exit().
--- drivers/net/ipa/ipa_smp2p.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-)
drivers/net/ipa/ipa_smp2p.c +22 -8
@@ -233,19 +233,27 @@ int ipa_smp2p_init(struct ipa *ipa, bool &valid_bit);if (IS_ERR (valid_state))return PTR_ERR (valid_state); -if (valid_bit >=32 )/* BITS_PER_U32 */ -return -EINVAL ; +if (valid_bit >=32 ) {/* BITS_PER_U32 */ + ret = -EINVAL ; + goto err_valid_state_put; + } enabled_state =qcom_smem_state_get (dev,"ipa-clock-enabled" , &enabled_bit); -if (IS_ERR (enabled_state)) -return PTR_ERR (enabled_state); -if (enabled_bit >=32 )/* BITS_PER_U32 */ -return -EINVAL ; +if (IS_ERR (enabled_state)) { + ret =PTR_ERR (enabled_state); + goto err_valid_state_put; + } +if (enabled_bit >=32 ) {/* BITS_PER_U32 */ + ret = -EINVAL ; + goto err_enabled_state_put; + } smp2p =kzalloc (sizeof (*smp2p),GFP_KERNEL ); -if (!smp2p) -return -ENOMEM ; +if (!smp2p) { + ret = -ENOMEM ; + goto err_enabled_state_put; + } smp2p->ipa = ipa;
@@ -290,6 +298,10 @@ err_null_smp2p: ipa->smp2p =NULL ;mutex_destroy (&smp2p->mutex);kfree (smp2p); +err_enabled_state_put: +qcom_smem_state_put (enabled_state); +err_valid_state_put: +qcom_smem_state_put (valid_state);return ret; }
@@ -306,6 +318,8 @@ void ipa_smp2p_exit(struct ipa *ipa)ipa_smp2p_power_release (ipa); ipa->smp2p =NULL ;mutex_destroy (&smp2p->mutex); +qcom_smem_state_put (smp2p->enabled_state); +qcom_smem_state_put (smp2p->valid_state);kfree (smp2p); }
Greg Kroah-Hartman
maintainerPATCH 474/484 fs/resctrl: Fix double-add of pseudo-locked regions RMID to free list
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Reinette Chatre <[email protected]>
[ Upstream commit b9f089723aee892efc77c349ae47a6b452b293c4 ]
A pseudo-locked group's RMID is freed when it is created. On unmount rmdir_all_sub() unconditionally frees all RMID of all groups, resulting in a double-free of the pseudo-locked group's RMID. The consequence of this is that the original free results in the pseudo-locked group's RMID being added to the rmid_free_lru linked list and the second free then attempts to add the same RMID entry to the rmid_free_lru again.
Do not double-free a pseudo-locked group's RMID.
--- arch/x86/kernel/cpu/resctrl/rdtgroup.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
arch/x86/kernel/cpu/resctrl/rdtgroup.c +7 -5
@@ -2744,10 +2744,6 @@ static void rmdir_all_sub(void)if (rdtgrp == &rdtgroup_default)continue ; -if (rdtgrp->mode ==RDT_MODE_PSEUDO_LOCKSETUP || - rdtgrp->mode ==RDT_MODE_PSEUDO_LOCKED ) -rdtgroup_pseudo_lock_remove (rdtgrp); -/* * Give any CPUs back to the default group. We cannot copy * cpu_online_mask because a CPU might have executed the
@@ -2756,7 +2752,13 @@ static void rmdir_all_sub(void)cpumask_or (&rdtgroup_default.cpu_mask, &rdtgroup_default.cpu_mask, &rdtgrp->cpu_mask); -free_rmid (rdtgrp->mon.rmid); +if (rdtgrp->mode ==RDT_MODE_PSEUDO_LOCKSETUP || + rdtgrp->mode ==RDT_MODE_PSEUDO_LOCKED ) { +rdtgroup_pseudo_lock_remove (rdtgrp); + }else { +/* Pseudo-locked group's RMID is freed during setup. */ +free_rmid (rdtgrp->mon.rmid); + }kernfs_remove (rdtgrp->kn);list_del (&rdtgrp->rdtgroup_list);
Greg Kroah-Hartman
maintainerPATCH 475/484 KVM: Introduce vcpu->wants_to_run
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Matlack <[email protected]>
[ Upstream commit a6816314af5749cd88944bfdceb270c627cdf348 ]
Introduce vcpu->wants_to_run to indicate when a vCPU is in its core run loop, i.e. when the vCPU is running the KVM_RUN ioctl and immediate_exit was not set.
Replace all references to vcpu->run->immediate_exit with !vcpu->wants_to_run to avoid TOCTOU races with userspace. For example, a malicious userspace could invoked KVM_RUN with immediate_exit=true and then after KVM reads it to set wants_to_run=false, flip it to false. This would result in the vCPU running in KVM_RUN with wants_to_run=false. This wouldn't cause any real bugs today but is a dangerous landmine.
Stable-dep-of: e800decd9c0a ("KVM: x86: Only reset TSC Deadline Timer in apic_timer_expired on KVM_RUN")
--- arch/arm64/kvm/arm.c | 2 +- arch/mips/kvm/mips.c | 2 +- arch/powerpc/kvm/powerpc.c | 2 +- arch/riscv/kvm/vcpu.c | 2 +- arch/s390/kvm/kvm-s390.c | 2 +- arch/x86/kvm/x86.c | 4 ++-- include/linux/kvm_host.h | 1 + virt/kvm/kvm_main.c | 3 +++ 8 files changed, 11 insertions(+), 7 deletions(-)
arch/arm64/kvm/arm.c +1 -1
@@ -915,7 +915,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vvcpu_load (vcpu); -if (run->immediate_exit) { +if (!vcpu->wants_to_run) { ret = -EINTR ; goto out; }
arch/mips/kvm/mips.c +1 -1
@@ -436,7 +436,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_v vcpu->mmio_needed =0 ; } -if (vcpu->run->immediate_exit) +if (!vcpu->wants_to_run) goto out;lose_fpu (1 );
arch/powerpc/kvm/powerpc.c +1 -1
@@ -1858,7 +1858,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vkvm_sigset_activate (vcpu); -if (run->immediate_exit) +if (!vcpu->wants_to_run) r = -EINTR ;else r =kvmppc_vcpu_run (vcpu);
arch/riscv/kvm/vcpu.c +1 -1
@@ -704,7 +704,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vreturn ret; } -if (run->immediate_exit) { +if (!vcpu->wants_to_run) {kvm_vcpu_srcu_read_unlock (vcpu);return -EINTR ; }
arch/s390/kvm/kvm-s390.c +1 -1
@@ -5048,7 +5048,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vif (vcpu->kvm->arch.pv.dumping)return -EINVAL ; -if (kvm_run->immediate_exit) +if (!vcpu->wants_to_run)return -EINTR ; if (kvm_run->kvm_valid_regs & ~KVM_SYNC_S390_VALID_FIELDS ||
arch/x86/kvm/x86.c +2 -2
@@ -11224,7 +11224,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vkvm_vcpu_srcu_read_lock (vcpu);if (unlikely (vcpu->arch.mp_state ==KVM_MP_STATE_UNINITIALIZED )) { -if (kvm_run->immediate_exit) { +if (!vcpu->wants_to_run) { r = -EINTR ; goto out; }
@@ -11302,7 +11302,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vWARN_ON_ONCE (vcpu->mmio_needed); } -if (kvm_run->immediate_exit) { +if (!vcpu->wants_to_run) { r = -EINTR ; goto out; }
include/linux/kvm_host.h +1 -0
@@ -378,6 +378,7 @@ struct kvm_vcpu { bool dy_eligible; } spin_loop;#endif +bool wants_to_run;bool preempted;bool ready;struct kvm_vcpu_arch arch;
virt/kvm/kvm_main.c +3 -0
@@ -4160,7 +4160,10 @@ static long kvm_vcpu_ioctl(struct file *synchronize_rcu ();put_pid (oldpid); } + vcpu->wants_to_run = !READ_ONCE (vcpu->run->immediate_exit); r =kvm_arch_vcpu_ioctl_run (vcpu); + vcpu->wants_to_run = false; +trace_kvm_userspace_exit (vcpu->run->exit_reason, r);break ; }
Greg Kroah-Hartman
maintainerPATCH 476/484 KVM: x86: Only reset TSC Deadline Timer in apic_timer_expired on KVM_RUN
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Venkatesh Srinivas <[email protected]>
[ Upstream commit e800decd9c0ac4349bcd8f8f9b29fd21fe93165e ]
On Intel platforms with a VMX preemption timer and APICv, if a VMM calls KVM_GET_LAPIC before KVM_GET_MSRS to save the vCPU state, it is possible to lose a pending timer interrupt.
If the thread running these ioctls is migrated to another core after calling KVM_GET_LAPIC but before KVM_GET_MSRS and the guest is using their LAPIC timer in TSC-deadline mode, not only does the save LAPIC state not carry the pending interrupt, the TSCDEADLINE MSR will be zeroed.
After migration across CPUs, KVM_GET_MSRS calls vcpu_load, posting the interrupt and clearing the MSR:vcpu_load() ->
kvm_arch_vcpu_load() ->
kvm_lapic_restart_hv_timer() ->
start_hv_timer() ->
apic_timer_expired() ->
kvm_apic_inject_pending_timer_irqs()
. post interrupt into the LAPIC state
. clear IA32_TSCDEADLINEThe saved LAPIC state will be missing the pending interrupt and the saved MSR will be zero. Oops.
Fix by only posting an interrupt when we're attempting to enter the guest (vcpu->wants_to_run == true), not for vcpu_load from other paths.
Message-ID: <[email protected]>
--- arch/x86/kvm/lapic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/kvm/lapic.c +1 -1
@@ -1912,7 +1912,7 @@ static void apic_timer_expired(struct kvif (apic_lvtt_tscdeadline (apic) || ktimer->hv_timer_in_use) ktimer->expired_tscdeadline = ktimer->tscdeadline; -if (!from_timer_fn && apic->apicv_active) { +if (!from_timer_fn && apic->apicv_active && vcpu->wants_to_run) {WARN_ON (kvm_get_running_vcpu () != vcpu);kvm_apic_inject_pending_timer_irqs (apic);return ;
Greg Kroah-Hartman
maintainerPATCH 477/484 coredump: fix pidfs file refcount leak in umh_coredump_setup
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qian Zuo <[email protected]>
The backport of upstream commit b5325b2a270f introduced a reference count leak for pidfs_file.
In the upstream implementation, pidfs_file is declared with __free(fput), which automatically drops the initial file reference when leaving the scope. During the backport, the code was rewritten to manage the file pointer manually, but after a successful replace_fd(), pidfs_file was simply cleared without dropping the initial reference.
As a result, the pidfs file keeps an extra reference and is never released after the usermode helper exits, leaving associated objects, such as struct pid, permanently allocated and triggering kmemleak reports.
Fix this by explicitly calling fput(pidfs_file) after replace_fd().
--- fs/coredump.c | 1 + 1 file changed, 1 insertion(+)
fs/coredump.c +1 -0
@@ -560,6 +560,7 @@ static int umh_coredump_setup(struct subif (err <0 ) goto out_fail; +fput (pidfs_file); pidfs_file =NULL ; }
Greg Kroah-Hartman
maintainerPATCH 478/484 mm/damon/core: validate ranges in damon_set_regions()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: SJ Park <[email protected]>
commit 1292c0ecb1caefb8ca064a3639d5673991e8810c upstream.
DAMON core logic assumes zero length regions don't exist. However, a few DAMON API callers including DAMON_SYSFS, DAMON_RECLAIM and DAMON_LRU_SORT allow users to set empty monitoring target regions. This could result in WARN_ONCE() on CONFIG_DAMON_DEBUG_SANITY enabled kernel, and divide-by-zero from damon_merge_two_regions().
For example, the WANR_ONCE() can be triggered like below.
# grep DAMON_DEBUG_SANITY /boot/config-$(uname -r)
# CONFIG_DAMON_DEBUG_SANITY=y
# damo start
# cd /sys/kernel/mm/damon/admin/kdamonds/0
# echo 0 > contexts/0/targets/0/regions/0/start
# echo 0 > contexts/0/targets/0/regions/0/end
# echo commit > state
# dmesg
[....]
[ 73.705780] ------------[ cut here ]------------
[ 73.707552] start 0 >= end 0
[ 73.708452] WARNING: mm/damon/core.c:359 at damon_new_region+0x6e/0x80, CPU#1: kdamond.0/758
[...]All DAMON API callers eventually use damon_set_regions() to setup the regions. Add the validation logic in the function.
--- mm/damon/core.c | 6 ++++++ 1 file changed, 6 insertions(+)
mm/damon/core.c +6 -0
@@ -212,6 +212,12 @@ int damon_set_regions(struct damon_targeunsigned int i;int err; +for (i =0 ; i < nr_ranges; i++) { +if (ALIGN_DOWN (ranges[i].start,DAMON_MIN_REGION ) >= +ALIGN (ranges[i].end,DAMON_MIN_REGION )) +return -EINVAL ; + } +/* Remove regions which are not in the new ranges */ damon_for_each_region_safe (r, next, t) {for (i =0 ; i < nr_ranges; i++) {
Greg Kroah-Hartman
maintainerPATCH 479/484 mm/damon/core: disallow overlapping input ranges for damon_set_regions()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: SJ Park <[email protected]>
commit 954157679ec34661c2e87e7eb796104a797c32db upstream.
damon_set_regions() assumes the input ranges are sorted by the address and don't overlap each other. Hence the assumption was initially to be explicitly validated. But commit 97d482f4592f ("mm/damon/sysfs: reuse damon_set_regions() for regions setting") has mistakenly removed the validation.
This can make DAMON behave in unexpected ways. At the best, the monitoring results snapshot will just look weird since there will be overlapping regions. DAMOS will also work weirdly, applying the same action multiple times for overlapping regions, and make DAMOS quota weird. More seriously, depending on the setup and regions updates sequence, negative size regions can be made. It will trigger WARN_ONCE() if the kernel is built with CONFIG_DAMON_DEBUG_SANITY=y. Depending on the monitoring results, the negative size region can further trigger division by zero in damon_merge_two_regions().
Note that some of the consequences including the WARN_ONCE() and the divide by zero depend on commits that were introduced after the root cause commit 97d482f4592f ("mm/damon/sysfs: reuse damon_set_regions() for regions setting").
Fix the problems by checking the assumption and returning an error if the input ranges don't meet the assumption.
The issue was discovered [1] by Sashiko.
--- mm/damon/core.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
mm/damon/core.c +9 -2
@@ -210,12 +210,19 @@ int damon_set_regions(struct damon_targe {struct damon_region *r, *next;unsigned int i; +unsigned long last_end;int err;for (i =0 ; i < nr_ranges; i++) { -if (ALIGN_DOWN (ranges[i].start,DAMON_MIN_REGION ) >= -ALIGN (ranges[i].end,DAMON_MIN_REGION )) +unsigned long start, end; + + start =ALIGN_DOWN (ranges[i].start,DAMON_MIN_REGION ); + end =ALIGN (ranges[i].end,DAMON_MIN_REGION ); +if (start >= end) +return -EINVAL ; +if (i >0 && last_end > start)return -EINVAL ; + last_end = end; }/* Remove regions which are not in the new ranges */
Greg Kroah-Hartman
maintainerPATCH 480/484 ASoC: mediatek: mt8195: Add platform entry for ETDM1_OUT_BE dai link
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chen-Yu Tsai <[email protected]>
commit 282a4482e198e03781c152c88aac8aa382ef9a55 upstream.
Commit e70b8dd26711 ("ASoC: mediatek: mt8195: Remove afe-dai component and rework codec link") removed the codec entry for the ETDM1_OUT_BE dai link entirely instead of replacing it with COMP_EMPTY(). This worked by accident as the remaining COMP_EMPTY() platform entry became the codec entry, and the platform entry became completely empty, effectively the same as COMP_DUMMY() since snd_soc_fill_dummy_dai() doesn't do anything for platform entries.
This causes a KASAN out-of-bounds warning in mtk_soundcard_common_probe() in sound/soc/mediatek/common/mtk-soundcard-driver.c:
for_each_card_prelinks(card, i, dai_link) {
if (adsp_node && !strncmp(dai_link->name, "AFE_SOF", strlen("AFE_SOF")))
dai_link->platforms->of_node = adsp_node;
else if (!dai_link->platforms->name && !dai_link->platforms->of_node)
dai_link->platforms->of_node = platform_node;
}where the code expects the platforms array to have space for at least one entry.
Add an COMP_EMPTY() entry so that dai_link->platforms has space.
--- sound/soc/mediatek/mt8195/mt8195-mt6359.c | 1 + 1 file changed, 1 insertion(+)
sound/soc/mediatek/mt8195/mt8195-mt6359.c +1 -0
@@ -939,6 +939,7 @@ SND_SOC_DAILINK_DEFS(ETDM2_IN_BE,SND_SOC_DAILINK_DEFS (ETDM1_OUT_BE ,DAILINK_COMP_ARRAY (COMP_CPU ("ETDM1_OUT" )), +DAILINK_COMP_ARRAY (COMP_EMPTY ()),DAILINK_COMP_ARRAY (COMP_EMPTY ())); SND_SOC_DAILINK_DEFS(ETDM2_OUT_BE,
Greg Kroah-Hartman
maintainerPATCH 481/484 ASoC: mediatek: mt8195: Set ETDM1/2 IN/OUT to COMP_DUMMY()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Julien Massot <[email protected]>
commit 7af317f7faaab09d5a78f24605057d11f5955115 upstream.
ETDM2_IN_BE and ETDM1_OUT_BE are defined as COMP_EMPTY(), in the case the codec dai_name will be null.
Avoid a crash if the device tree is not assigning a codec to these links.
[ 1.179936] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000 [ 1.181065] Mem abort info: [ 1.181420] ESR = 0x0000000096000004 [ 1.181892] EC = 0x25: DABT (current EL), IL = 32 bits [ 1.182576] SET = 0, FnV = 0 [ 1.182964] EA = 0, S1PTW = 0 [ 1.183367] FSC = 0x04: level 0 translation fault [ 1.183983] Data abort info: [ 1.184406] ISV = 0, ISS = 0x00000004, ISS2 = 0x00000000 [ 1.185097] CM = 0, WnR = 0, TnD = 0, TagAccess = 0 [ 1.185766] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 [ 1.186439] [0000000000000000] user address but active_mm is swapper [ 1.187239] Internal error: Oops: 0000000096000004 [#1] PREEMPT SMP [ 1.188029] Modules linked in: [ 1.188420] CPU: 7 UID: 0 PID: 70 Comm: kworker/u32:1 Not tainted 6.14.0-rc4-next-20250226+ #85 [ 1.189515] Hardware name: Radxa NIO 12L (DT) [ 1.190065] Workqueue: events_unbound deferred_probe_work_func [ 1.190808] pstate: 40400009 (nZcv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 1.191683] pc : __pi_strcmp+0x24/0x140 [ 1.192170] lr : mt8195_mt6359_soc_card_probe+0x224/0x7b0 [ 1.192854] sp : ffff800083473970 [ 1.193271] x29: ffff800083473a10 x28: 0000000000001008 x27: 0000000000000002 [ 1.194168] x26: ffff800082408960 x25: ffff800082417db0 x24: ffff800082417d88 [ 1.195065] x23: 000000000000001e x22: ffff800082dbf480 x21: ffff800082dc07b8 [ 1.195961] x20: 0000000000000000 x19: 0000000000000013 x18: 00000000ffffffff [ 1.196858] x17: 000000040044ffff x16: 005000f2b5503510 x15: 0000000000000006 [ 1.197755] x14: ffff800082407af0 x13: 6e6f69737265766e x12: 692d6b636f6c6374 [ 1.198651] x11: 0000000000000002 x10: ffff80008240b920 x9 : 0000000000000018 [ 1.199547] x8 : 0101010101010101 x7 : 0000000000000000 x6 : 0000000000000000 [ 1.200443] x5 : 0000000000000000 x4 : 8080808080000000 x3 : 303933383978616d [ 1.201339] x2 : 0000000000000000 x1 : ffff80008240b920 x0 : 0000000000000000 [ 1.202236] Call trace: [ 1.202545] __pi_strcmp+0x24/0x140 (P) [ 1.203029] mtk_soundcard_common_probe+0x3bc/0x5b8 [ 1.203644] platform_probe+0x70/0xe8 [ 1.204106] really_probe+0xc8/0x3a0 [ 1.204556] __driver_probe_device+0x84/0x160 [ 1.205104] driver_probe_device+0x44/0x130 [ 1.205630] __device_attach_driver+0xc4/0x170 [ 1.206189] bus_for_each_drv+0x8c/0xf8 [ 1.206672] __device_attach+0xa8/0x1c8 [ 1.207155] device_initial_probe+0x1c/0x30 [ 1.207681] bus_probe_device+0xb0/0xc0 [ 1.208165] deferred_probe_work_func+0xa4/0x100 [ 1.208747] process_one_work+0x158/0x3e0 [ 1.209254] worker_thread+0x2c4/0x3e8 [ 1.209727] kthread+0x134/0x1f0 [ 1.210136] ret_from_fork+0x10/0x20 [ 1.210589] Code: 54000401 b50002c6 d503201f f86a6803 (f8408402) [ 1.211355] ---[ end trace 0000000000000000 ]---
--- sound/soc/mediatek/mt8195/mt8195-mt6359.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
sound/soc/mediatek/mt8195/mt8195-mt6359.c +2 -2
@@ -934,12 +934,12 @@ SND_SOC_DAILINK_DEFS(ETDM1_IN_BE,SND_SOC_DAILINK_DEFS (ETDM2_IN_BE ,DAILINK_COMP_ARRAY (COMP_CPU ("ETDM2_IN" )), -DAILINK_COMP_ARRAY (COMP_EMPTY ()), +DAILINK_COMP_ARRAY (COMP_DUMMY ()),DAILINK_COMP_ARRAY (COMP_EMPTY ()));SND_SOC_DAILINK_DEFS (ETDM1_OUT_BE ,DAILINK_COMP_ARRAY (COMP_CPU ("ETDM1_OUT" )), -DAILINK_COMP_ARRAY (COMP_EMPTY ()), +DAILINK_COMP_ARRAY (COMP_DUMMY ()),DAILINK_COMP_ARRAY (COMP_EMPTY ())); SND_SOC_DAILINK_DEFS(ETDM2_OUT_BE,
Greg Kroah-Hartman
maintainerPATCH 482/484 udmabuf: Ensure to perform cache synchronisation in begin_cpu_udmabuf()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Robert Mader <[email protected]>
commit 1d0e25c1ddf2063c499264fb2ba0fa6a3e4f8a00 upstream.
The message of commit 504e2b4ab97a ("dma-buf/udmabuf: skip redundant cpu sync to fix cacheline EEXIST warning") says:
Quoted 4 lines
The CPU sync at map/unmap time is also redundant for udmabuf:
begin_cpu_udmabuf()andend_cpu_udmabuf()already perform explicit cache synchronization via dma_sync_sgtable_for_cpu/device() when CPU access is requested through the dma-buf interface.
This, however, does not apply to the first time begin_cpu_udmabuf() is called on an udmabuf, in which case the implementation previously relied on get_sg_table() to perform the cache synchronisation.
Ensure to call dma_sync_sgtable_for_cpu() in that case as well.
--- drivers/dma-buf/udmabuf.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
drivers/dma-buf/udmabuf.c +5 -4
@@ -155,21 +155,22 @@ static int begin_cpu_udmabuf(struct dma_ {struct udmabuf *ubuf = buf->priv;struct device *dev = ubuf->device->this_device; -int ret =0 ;if (!ubuf->sg) { ubuf->sg =get_sg_table (dev, buf, direction);if (IS_ERR (ubuf->sg)) { +int ret; + ret =PTR_ERR (ubuf->sg); ubuf->sg =NULL ; +return ret; }else { ubuf->sg_dir = direction; } - }else { -dma_sync_sgtable_for_cpu (dev, ubuf->sg, direction); } -return ret; +dma_sync_sgtable_for_cpu (dev, ubuf->sg, direction); +return 0 ; } static int end_cpu_udmabuf(struct dma_buf *buf,
Greg Kroah-Hartman
maintainerPATCH 483/484 rxrpc: Disable IRQ, not BH, to take the lock for ->attend_link
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
commit d920270a6dbf756384b125ce39c17666a7c0c9f4 upstream.
Use spin_lock_irq(), not spin_lock_bh() to take the lock when accessing the ->attend_link() to stop a delay in the I/O thread due to an interrupt being taken in the app thread whilst that holds the lock and vice versa.
--- net/rxrpc/io_thread.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
net/rxrpc/io_thread.c +4 -4
@@ -423,9 +423,9 @@ int rxrpc_io_thread(void *data) struct rxrpc_connection, attend_link);if (conn) { -spin_lock_bh (&local->lock); +spin_lock_irq (&local->lock);list_del_init (&conn->attend_link); -spin_unlock_bh (&local->lock); +spin_unlock_irq (&local->lock);rxrpc_input_conn_event (conn,NULL );rxrpc_put_connection (conn, rxrpc_conn_put_poke);
@@ -440,9 +440,9 @@ int rxrpc_io_thread(void *data)if ((call =list_first_entry_or_null (&local->call_attend_q, struct rxrpc_call, attend_link))) { -spin_lock_bh (&local->lock); +spin_lock_irq (&local->lock);list_del_init (&call->attend_link); -spin_unlock_bh (&local->lock); +spin_unlock_irq (&local->lock);trace_rxrpc_call_poked (call);rxrpc_input_call_event (call,NULL );
Greg Kroah-Hartman
maintainerPATCH 484/484 KVM: SVM: Bump asid_generation on CPU online to avoid ASID collision after hotplug
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikunj A Dadhania <[email protected]>
commit 25f744ffa0c8e799e06250ce2e618367b166b0d4 upstream.
If a vCPU stays scheduled out (or blocked) while the last pCPU it ran on goes through a hotplug cycle (online->offline->online), and the vCPU then resumes execution on the same pCPU, then it is possible for it to run with an ASID that has now been assigned to a different vCPU, resulting in stale TLB translations being used.
svm_enable_virtualization_cpu() resets asid_generation to 1 and sets next_asid to max_asid + 1 on every CPU online event, including hotplug cycles. Because next_asid starts beyond the pool boundary, the first call to new_asid() after an online event always wraps the pool, incrementing asid_generation to 2 and assigning ASIDs starting from min_asid.
Consider two vCPUs from different VMs, vCPU-A pinned to CPU-X holding asid_generation=2 and ASID=N from before the hotplug event:
1. CPU-X goes offline and back online: asid_generation resets to 1, next_asid = max_asid + 1.
2. One or more vCPUs migrate to CPU-X and call new_asid(), wrapping the pool and consuming ASIDs starting from min_asid. Eventually vCPU-B from a different VM is assigned asid_generation=2, ASID=N — the same ASID that vCPU-A held before the hotplug.
3. vCPU-A enters pre_svm_run() on CPU-X: current_vmcb->cpu is unchanged so the migration branch is skipped. Its saved asid_generation=2 matches sd->asid_generation=2, so the generation check silently passes and vCPU-A continues running with ASID=N — the same ASID just freshly assigned to vCPU-B.
Both vCPUs from different VMs now run on CPU-X with the same ASID, causing them to share NPT TLB entries and producing stale translations.
The collision manifests as a KVM internal error (Suberror: 1, emulation failure). The NPT page fault reports a faulting GPA far outside the VM's physical memory range — a sign of stale TLB translations being used. KVM falls back to instruction emulation, which fails on FPU/XSave instructions (XRSTOR, STMXCSR) that the emulator does not implement.
Fix this by incrementing asid_generation instead of resetting it to 1 in svm_enable_virtualization_cpu(). On module load, asid_generation starts at 0 (memset) and the increment produces 1, identical to the old behaviour. On subsequent hotplug cycles the generation advances beyond any value a vCPU previously observed on this CPU, so the generation check in pre_svm_run() reliably forces new_asid() on every vCPU after every hotplug cycle.
Message-ID: <[email protected]>
--- arch/x86/kvm/svm/svm.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
arch/x86/kvm/svm/svm.c +6 -1
@@ -637,7 +637,12 @@ static int svm_hardware_enable(void)return -EBUSY ; sd =per_cpu_ptr (&svm_data, me); - sd->asid_generation =1 ; +/* +* Bump the current asid_generation value to ensure any vCPU that +* previously ran on this CPU sees a stale generation and is forced +* to acquire a new ASID, preventing a latent ASID collision. +*/ + sd->asid_generation++; sd->max_asid =cpuid_ebx (SVM_CPUID_FUNC ) -1 ; sd->next_asid = sd->max_asid +1 ; sd->min_asid = max_sev_asid +1 ;
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.6.148 release. There are 484 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat, 01 Aug 2026 14:13:41 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 8 lines
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.6.148-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-6.6.y
and the diffstat can be found below.thanks,
greg k-h
On ARCH_BRCMSTB using 32-bit and 64-bit ARM kernels, build tested on BMIPS_GENERIC:
Signature · 1 line
Florian
Am 30.07.2026 um 16:08 schrieb Greg Kroah-Hartman:
Quoted 4 lines
This is the start of the stable review cycle for the 6.6.148 release. There are 484 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Builds, boots and works on my 2-socket Ivy Bridge Xeon E5-2697 v2 server. No dmesg oddities or regressions found.
Beste Grüße,
Peter Schneider
Signature · 8 lines
Climb the mountain not to plant your flag, but to embrace the challenge, enjoy the air and behold the view. Climb it so you can see the world, not so the world can see you. -- David McCullough Jr. OpenPGP: 0xA3828BD796CCE11A8CADE8866E3A92C92C3FF244 Download: https://www.peters-netzplatz.de/download/pschneider1968_pub.asc https://keys.mailvelope.com/pks/lookup?op=get&[email protected] https://keys.mailvelope.com/pks/lookup?op=get&[email protected]
Quoted 8 lines · On Thu, 30 Jul 2026 16:08:17 +0200 Greg Kroah-Hartman…
This is the start of the stable review cycle for the 6.6.148 release. There are 484 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat, 01 Aug 2026 14:13:41 +0000. Anything received after that time might be too late.
Boot-tested under QEMU for Rust x86_64:
Thanks!
Cheers,
Miguel
# Librecast Test Results
020/020 [ OK ] liblcrq
010/010 [ OK ] libmld
120/120 [ OK ] liblibrecast
CPU/kernel: Linux auntie 6.6.148-rc1-g7f195ac3d444 #1 SMP PREEMPT_DYNAMIC Thu Jul 30 20:00:35 -00 2026 x86_64 AMD Ryzen 9 9950X 16-Core Processor AuthenticAMD GNU/Linux
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.6.148 release. There are 484 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat, 01 Aug 2026 14:13:41 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 9 lines
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.6.148-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-6.6.y
and the diffstat can be found below.thanks,
greg k-h
Compiled and booted on my test system. No dmesg regressions.
thanks,
-- Shuah
Hi!
Quoted 4 lines
This is the start of the stable review cycle for the 6.6.148 release. There are 484 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
CIP testing did not find any problems here:
https://gitlab.com/cip-project/cip-testing/linux-stable-rc-ci/-/tree/linux-6.6.y
Best regards,
Pavel
Hello,
Build tested in our x86,arm64,loongarch,riscv config successfully without error.
Best Regards
Wentao Guan
Log:
Linux version 6.6.148-rc1-arm64-desktop-hwe-g7f195ac3d444 (guanwentao@uos-PC) (aarch64-linux-gnu-gcc-12 (Deepin 12.3.0-17deepin8) 12.3.0, GNU ld (GNU Binutils for Deepin) 2.41) # SMP PREEMPT Linux version 6.6.148-rc1-arm64-desktop-hwe-g7f195ac3d444 (guanwentao@uos-PC) (aarch64-linux-gnu-gcc-12 (Deepin 12.3.0-17deepin8) 12.3.0, GNU ld (GNU Binutils for Deepin) 2.41) #2 SMP PREEMPT Fri Jul 31 11:50:50 CST 2026 Linux version 6.6.148-rc1-loong64-desktop-hwe-g7f195ac3d444 (guanwentao@uos-PC) (loongarch64-linux-gnu-gcc-12 (Deepin 12.3.0-17deepin8) 12.3.0, GNU ld (GNU Binutils for Deepin) 2.41) # SMP PREEMPT Linux version 6.6.148-rc1-loong64-desktop-hwe-g7f195ac3d444 (guanwentao@uos-PC) (loongarch64-linux-gnu-gcc-12 (Deepin 12.3.0-17deepin8) 12.3.0, GNU ld (GNU Binutils for Deepin) 2.41) #3 SMP PREEMPT Fri Jul 31 12:08:17 CST 2026 Linux version 6.6.148-rc1-riscv64-desktop-hwe+ (guanwentao@uos-PC) (riscv64-linux-gnu-gcc-12 (Deepin 12.3.0-17deepin8) 12.3.0, GNU ld (GNU Binutils for Deepin) 2.41) # SMP
Linux version 6.6.148-rc1-riscv64-desktop-hwe+ (guanwentao@uos-PC) (riscv64-linux-gnu-gcc-12 (Deepin 12.3.0-17deepin8) 12.3.0, GNU ld (GNU Binutils for Deepin) 2.41) #4 SMP Fri Jul 31 12:24:40 CST 2026 Linux version 6.6.148-rc1-amd64-desktop-hwe-g7f195ac3d444 (guanwentao@uos-PC) (gcc (Deepin 12.3.0-17deepin15) 12.3.0, GNU ld (GNU Binutils for Deepin) 2.41) # SMP PREEMPT_DYNAMIC
Linux version 6.6.148-rc1-amd64-desktop-hwe-g7f195ac3d444 (guanwentao@uos-PC) (gcc (Deepin 12.3.0-17deepin15) 12.3.0, GNU ld (GNU Binutils for Deepin) 2.41) #1 SMP PREEMPT_DYNAMIC Fri Jul 31 11:32:42 CST 2026
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.6.148 release. There are 484 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat, 01 Aug 2026 14:13:41 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 8 lines
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.6.148-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-6.6.y
and the diffstat can be found below.thanks,
greg k-h
I didn't notice earlier, but we now seem to have a mirrored version of the build problem described for 6.6.145-rc2 ([1]) earlier:
from: https://github.com/linux-ia64/linux-stable-rc/actions/runs/30608172560/job/91087240301#step:8:3099
```
drivers/cpufreq/ia64-acpi-cpufreq.c:327:27: error: initialization of 'int (*)(struct cpufreq_policy *)' from incompatible pointer type 'void (*)(struct cpufreq_policy *)' [-Wincompatible-pointer-types]
327 | .exit = acpi_cpufreq_cpu_exit,
| ^~~~~~~~~~~~~~~~~~~~~
drivers/cpufreq/ia64-acpi-cpufreq.c:327:27: note: (near initialization for 'acpi_cpufreq_driver.exit')
make[6]: *** [scripts/Makefile.build:243: drivers/cpufreq/ia64-acpi-cpufreq.o] Error 1
make[5]: *** [scripts/Makefile.build:480: drivers/cpufreq] Error 2
make[5]: *** Waiting for unfinished jobs....
```[1]: https://lore.kernel.org/stable/[email protected]/
Looking into the released 6.6.145 ([2]) the patch "cpufreq: Make cpufreq_driver->exit() return void" ([3]) that created the original problem for the ia64 buld in 6.6.145-rc1 and -rc2 was gone in the released 6.6.145.
Hence the patch which replays that change also for ia64 needs to go now, too.
Short of an upstream commit for this patch, I can only point you to the patch in:
* linux-stable-rc:
* stable:
* stable-queue:
..., you decide what you prefer. HTH.
Cheers,
Frank
P.S.
Would the patch from us have been dropped automatically with [3] if ours had contained a Fixes: b4b1ddc9dfe997a5f492fa3a36487f8e7a5de30d ("cpufreq: Make cpufreq_driver->exit() return void") tag maybe?
Greg Kroah-Hartman
maintainerQuoted 56 lines · Frank Scheiner
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.6.148 release. There are 484 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat, 01 Aug 2026 14:13:41 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 8 lines
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.6.148-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-6.6.y
and the diffstat can be found below.thanks,
greg k-h
I didn't notice earlier, but we now seem to have a mirrored version of the build problem described for 6.6.145-rc2 ([1]) earlier:
from: https://github.com/linux-ia64/linux-stable-rc/actions/runs/30608172560/job/91087240301#step:8:3099
``` drivers/cpufreq/ia64-acpi-cpufreq.c:327:27: error: initialization of 'int (*)(struct cpufreq_policy *)' from incompatible pointer type 'void (*)(struct cpufreq_policy *)' [-Wincompatible-pointer-types] 327 | .exit = acpi_cpufreq_cpu_exit, | ^~~~~~~~~~~~~~~~~~~~~ drivers/cpufreq/ia64-acpi-cpufreq.c:327:27: note: (near initialization for 'acpi_cpufreq_driver.exit') make[6]: *** [scripts/Makefile.build:243: drivers/cpufreq/ia64-acpi-cpufreq.o] Error 1 make[5]: *** [scripts/Makefile.build:480: drivers/cpufreq] Error 2 make[5]: *** Waiting for unfinished jobs.... ```[1]: https://lore.kernel.org/stable/[email protected]/
Looking into the released 6.6.145 ([2]) the patch "cpufreq: Make
cpufreq_driver->exit()return void" ([3]) that created the original problem for the ia64 buld in 6.6.145-rc1 and -rc2 was gone in the released 6.6.145.Hence the patch which replays that change also for ia64 needs to go now, too.
Short of an upstream commit for this patch, I can only point you to the patch in:
* linux-stable-rc:
* stable:
Quoted 7 lines
* stable-queue:
..., you decide what you prefer. HTH.
Ugh. This is what happens when we are trying to deal with stable stuff that is not upstream, we almost always get it wrong.
Can you send me a revert patch for this, so we can fix your build? ANd going forward, I think we're just going to have to stick to the "it has to be usptream" stuff, and if you wish to keep this arch alive outside of upstream, the api/build/whatever fallout will have to be on you, as we just can't handle it here, sorry.
thanks,
greg k-h
Quoted 5 lines · Greg Kroah-Hartman
[...]
Ugh. This is what happens when we are trying to deal with stable stuff that is not upstream, we almost always get it wrong.Can you send me a revert patch for this, so we can fix your build?
Locally I use [1] for now, also attached, based on linux-6.6.y at aa0e49877a2e61e9f4ca10e039727a34f59e9964, tag: v6.6.148.
Quoted 5 lines
ANd
going forward, I think we're just going to have to stick to the "it has to be usptream" stuff, and if you wish to keep this arch alive outside of upstream, the api/build/whatever fallout will have to be on you, as we just can't handle it here, sorry.
I kind of understand the issue here. But if it's impossible to maintain all architectures in an LTS kernel that were present during its first release, the LTS somewhat loses its meaning IMHO - unless this never covered all architectures present in a release. But then I also don't understand:
"The ia64 architecture gets its well-earned retirement as planned,
now that there is one last (mostly) working release that will be maintained as an LTS kernel."
...from [2].
But I also wonder: if a mainline patch that should go into a stable kernel branch but won't work as is, it needs to be backported somewhow, or?
Which is IMHO exactly the situation we have here: A mainline patch ([3]) from a Linux version (6.11) after an arch removal "failed" to modify all relevant files in a stable Linux version (6.6) before that arch removal. Hence that mainline patch requires modifications.
I assume there must have been already cases where a mainline patch was desired, but didn't fit as is and so required modifications. If that case is supported, it should also work for the few stable Linux branches that still have support for ia64 included (linux-5.10.y, linux-5.15.y, linux-6.1.y and linux-6.6.y)), no?
****
But if you can't handle that case, sure, we can do it on our own. Though again I think there is not much of a difference to cases where a mainline patch breaks some still supported arch, device driver, whatever in a stable branch and people like to have both working: they cannot fix it in mainline.
Cheers,
Frank
From 7d213dde115b77ee5759ffffcdcd4a5026464d49 Mon Sep 17 00:00:00 2001
From: Frank Scheiner <[email protected]>
Date: Tue, 4 Aug 2026 15:48:08 +0200
Subject: [PATCH] Revert "ia64: Make acpi_cpufreq_cpu_exit return void"
Commit b4b1ddc9dfe9 ("cpufreq: Make cpufreq_driver->exit() return void") was part of v6.6.145-rc1. But as it was derived from a later Linux version w/o support for ia64 it didn't touch all relevant parts in linux-6.6.y. Which now required an extra fix to build correctly for ia64. But b4b1ddc9dfe9 was then not part of the release v6.6.145. So the extra fix can go now, too.
This reverts commit bb51b626b5a8ef349b11876572540f19ad4d5030.
--- drivers/cpufreq/ia64-acpi-cpufreq.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/cpufreq/ia64-acpi-cpufreq.c +3 -1
@@ -302,7 +302,7 @@ acpi_cpufreq_cpu_init ( } -static void +static int acpi_cpufreq_cpu_exit (struct cpufreq_policy *policy) {
@@ -316,6 +316,8 @@ acpi_cpufreq_cpu_exit (kfree (policy->freq_table);kfree (data); } + +return (0 ); }
Signature · 1 line
2.25.1
Quoted 4 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.6.148 release. There are 484 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.6.148 release. There are 484 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat, 01 Aug 2026 14:13:41 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 8 lines
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.6.148-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-6.6.y
and the diffstat can be found below.thanks,
greg k-h
Built and booted successfully on RISC-V RV64 (HiFive Unmatched).