7.0.10-rc1 review
Subsystems (6)
Greg Kroah-Hartman
maintainerPATCH 902/1146 drm/amdgpu/gmc: Fix AMDGPU_GART_PLACEMENT_LOW to not overlap with VRAM
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
[ Upstream commit 36d65da7570bf72ce28504fa9a81abfc728e6d96 ]
When the GART placement is set to AMDGPU_GART_PLACEMENT_LOW:
Make sure that GART does not overlap with VRAM when VRAM is configured to be in the low address space.
Solve this according to the following logic:
- When GART fits before VRAM, use zero address for GART
- Otherwise, put GART after the end of VRAM, aligned to 4 GiB
Previously, I had assumed this was not possible so it was OK to not handle it, but now we got a report from a user who has a board that is configured this way.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +4 -1
@@ -313,7 +313,10 @@ void amdgpu_gmc_gart_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc, mc->gart_start = max_mc_address - mc->gart_size +1 ;break ;case AMDGPU_GART_PLACEMENT_LOW : - mc->gart_start =0 ; +if (size_bf >= mc->gart_size) + mc->gart_start =0 ; +else + mc->gart_start =ALIGN (mc->fb_end, four_gb);break ;case AMDGPU_GART_PLACEMENT_BEST_FIT :default :
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 903/1146 drm/amd/pm: fix missing fine-grained dpm table flag on aldebaran
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yang Wang <[email protected]>
[ Upstream commit ccf8932ed8cf4fbfdcd4df2c6b524913691ee700 ]
Add the missing SMU_DPM_TABLE_FINE_GRAINED flag to aldebaran DPM table. This fixes the pp_dpm_sclk node issue caused by missing flag configuration.
--- drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +1 -0
@@ -425,6 +425,7 @@ static int aldebaran_set_default_dpm_table(struct smu_context *smu) dpm_table->dpm_levels[0 ].enabled = true; dpm_table->dpm_levels[1 ].value = pptable->GfxclkFmax; dpm_table->dpm_levels[1 ].enabled = true; + dpm_table->flags |=SMU_DPM_TABLE_FINE_GRAINED ; }else { dpm_table->count =1 ; dpm_table->dpm_levels[0 ].value = smu->smu_table.boot_values.gfxclk /100 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 904/1146 drm/amdgpu: fix AMDGPU_INFO_READ_MMR_REG
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian König <[email protected]>
[ Upstream commit 0ef196a208385b7d7da79f411c161b04e97283e2 ]
There were multiple issues in that code.
First of all the order between the reset semaphore and the mm_lock was wrong (e.g. copy_to_user) was called while holding the lock.
Then we allocated memory while holding the reset semaphore which is also a pretty big bug and can deadlock.
Then we used down_read_trylock() instead of waiting for the reset to finish.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 57 +++++++++++-------------- 1 file changed, 24 insertions(+), 33 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +24 -33
@@ -873,68 +873,59 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) ? -EFAULT :0 ; }case AMDGPU_INFO_READ_MMR_REG : { -int ret =0 ; -unsigned int n, alloc_size; -uint32_t *regs;unsigned int se_num = (info->read_mmr_reg.instance >>AMDGPU_INFO_MMR_SE_INDEX_SHIFT ) &AMDGPU_INFO_MMR_SE_INDEX_MASK ;unsigned int sh_num = (info->read_mmr_reg.instance >>AMDGPU_INFO_MMR_SH_INDEX_SHIFT ) &AMDGPU_INFO_MMR_SH_INDEX_MASK ; - -if (!down_read_trylock (&adev->reset_domain->sem)) -return -ENOENT ; +unsigned int alloc_size; +uint32_t *regs; +int ret;/* set full masks if the userspace set all bits * in the bitfields */ -if (se_num ==AMDGPU_INFO_MMR_SE_INDEX_MASK ) { +if (se_num ==AMDGPU_INFO_MMR_SE_INDEX_MASK ) se_num =0xffffffff ; - }else if (se_num >=AMDGPU_GFX_MAX_SE ) { - ret = -EINVAL ; - goto out; - } +else if (se_num >=AMDGPU_GFX_MAX_SE ) +return -EINVAL ; -if (sh_num ==AMDGPU_INFO_MMR_SH_INDEX_MASK ) { +if (sh_num ==AMDGPU_INFO_MMR_SH_INDEX_MASK ) sh_num =0xffffffff ; - }else if (sh_num >=AMDGPU_GFX_MAX_SH_PER_SE ) { - ret = -EINVAL ; - goto out; - } +else if (sh_num >=AMDGPU_GFX_MAX_SH_PER_SE ) +return -EINVAL ; -if (info->read_mmr_reg.count >128 ) { - ret = -EINVAL ; - goto out; - } +if (info->read_mmr_reg.count >128 ) +return -EINVAL ; - regs =kmalloc_array (info->read_mmr_reg.count,sizeof (*regs),GFP_KERNEL ); -if (!regs) { - ret = -ENOMEM ; - goto out; - } + regs =kmalloc_array (info->read_mmr_reg.count,sizeof (*regs), +GFP_KERNEL ); +if (!regs) +return -ENOMEM ; +down_read (&adev->reset_domain->sem); alloc_size = info->read_mmr_reg.count *sizeof (*regs); -amdgpu_gfx_off_ctrl (adev, false); + ret =0 ;for (i =0 ; i < info->read_mmr_reg.count; i++) {if (amdgpu_asic_read_register (adev, se_num, sh_num, info->read_mmr_reg.dword_offset + i, ®s[i])) {DRM_DEBUG_KMS ("unallowed offset %#x\n" , info->read_mmr_reg.dword_offset + i); -kfree (regs); -amdgpu_gfx_off_ctrl (adev, true); ret = -EFAULT ; - goto out; +break ; } }amdgpu_gfx_off_ctrl (adev, true); - n =copy_to_user (out, regs,min (size, alloc_size)); -kfree (regs); - ret = (n ? -EFAULT :0 ); -out:up_read (&adev->reset_domain->sem); + +if (!ret) { + ret =copy_to_user (out, regs,min (size, alloc_size)) + ? -EFAULT :0 ; + } +kfree (regs);return ret; }case AMDGPU_INFO_DEV_INFO : {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 905/1146 drm/amdgpu/uvd3.1: Dont validate the firmware when already validated
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
[ Upstream commit 13e4cf116dbf7a1fb8123a59bea2c098f30d3736 ]
UVD 3.1 firmware validation seems to always fail after attempting it when it had already been validated. (This works similarly with the VCE 1.0 as well.)
Don't attempt repeating the validation when it's already done.
This caused issues in situations when the system isn't able to suspend the GPU properly and so the GPU isn't actually powered down. Then amdgpu would fail when calling the IP block resume function.
--- drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +10 -0
@@ -242,6 +242,10 @@ static void uvd_v3_1_mc_resume(struct amdgpu_device *adev)uint64_t addr;uint32_t size; +/* When the keyselect is already set, don't perturb it. */ +if (RREG32 (mmUVD_FW_START)) +return ; +/* program the VCPU memory controller bits 0-27 */ addr = (adev->uvd.inst->gpu_addr +AMDGPU_UVD_FIRMWARE_OFFSET ) >>3 ; size =AMDGPU_UVD_FIRMWARE_SIZE (adev) >>3 ;
@@ -284,6 +288,12 @@ static int uvd_v3_1_fw_validate(struct amdgpu_device *adev)int i;uint32_t keysel = adev->uvd.keyselect; +if (RREG32 (mmUVD_FW_START) &UVD_FW_STATUS__PASS_MASK ) { +dev_dbg (adev->dev,"UVD keyselect already set: 0x%x (on CPU: 0x%x)\n" , +RREG32 (mmUVD_FW_START), adev->uvd.keyselect); +return 0 ; + } +WREG32 (mmUVD_FW_START, keysel);for (i =0 ; i <10 ; ++i) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 906/1146 drm/amdgpu/gfx6: Support harvested SI chips with disabled TCCs (v2)
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
[ Upstream commit fe2b84f9228e2a0903221a4d0d8c350b018e9c0c ]
This commit fixes amdgpu to work on the Radeon HD 7870 XT which has never worked with the Linux open source drivers before.
Some boards have "harvested" chips, meaning that some parts of the chip are disabled and fused, and it's sold for cheaper and under a different marketing name.
On a harvested chip, any of the following can be disabled:
- CUs (Compute Units)
- RBs (Render Backend, aka. ROP)
- Memory channels (ie. the chip has a lower bandwidth)
- TCCs (ie. less L2 cache)
Handle chips with harvested TCCs by patching the registers that configure how TCCs are mapped.
If some TCCs are disabled, we need to make sure that the disabled TCCs are not used, and the remaining TCCs are used optimally.
TCP_CHAN_STEER_LO/HI control which TCC is used by TCP channels. TCP_ADDR_CONFIG.NUM_TCC_BANKS controls how many channels are used.
Note that the TCC configuration is highly relevant to performance. Suboptimal configuration (eg. CHAN_STEER=0) can significantly reduce gaming performance.
For optimal performance:
- Rely on the CHAN_STEER from the golden registers table, only skip disabled TCCs but keep the mapping order.
- Limit NUM_TCC_BANKS to number of active TCCs to avoid thrashing, which performs better than using the same TCC twice.
v2:
- Also consider CGTS_USER_TCC_DISABLE for disabled TCCs.
--- drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 66 +++++++++++++++++++++++++++ 1 file changed, 66 insertions(+)
drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +66 -0
@@ -1571,6 +1571,71 @@ static void gfx_v6_0_setup_spi(struct amdgpu_device *adev)mutex_unlock (&adev->grbm_idx_mutex); } +/** +* gfx_v6_0_setup_tcc() - setup which TCCs are used +* +* @adev: amdgpu_device pointer +* +* Verify whether the current GPU has any TCCs disabled, +* which can happen when the GPU is harvested and some +* memory channels are disabled, reducing the memory bus width. +* For example, on the Radeon HD 7870 XT (Tahiti LE). +* +* If some TCCs are disabled, we need to make sure that +* the disabled TCCs are not used, and the remaining TCCs +* are used optimally. +* +* TCP_CHAN_STEER_LO/HI control which TCC is used by TCP channels. +* TCP_ADDR_CONFIG.NUM_TCC_BANKS controls how many channels are used. +* +* For optimal performance: +* - Rely on the CHAN_STEER from the golden registers table, +* only skip disabled TCCs but keep the mapping order. +* - Limit NUM_TCC_BANKS to number of active TCCs to avoid thrashing, +* which performs better than using the same TCC twice. +*/ +static void gfx_v6_0_setup_tcc (struct amdgpu_device *adev) +{ +u32 i, tcc, tcp_addr_config, num_active_tcc =0 ; +u64 chan_steer, patched_chan_steer =0 ; +const u32 num_max_tcc = adev->gfx.config.max_texture_channel_caches; +const u32 dis_tcc_mask = +amdgpu_gfx_create_bitmask (num_max_tcc) & + (REG_GET_FIELD (RREG32 (mmCGTS_TCC_DISABLE), +CGTS_TCC_DISABLE ,TCC_DISABLE ) | +REG_GET_FIELD (RREG32 (mmCGTS_USER_TCC_DISABLE), +CGTS_USER_TCC_DISABLE ,TCC_DISABLE )); + +/* When no TCC is disabled, the golden registers table already has optimal TCC setup */ +if (!dis_tcc_mask) +return ; + +/* Each 4-bit nibble contains the index of a TCC used by all TCPs */ + chan_steer =RREG32 (mmTCP_CHAN_STEER_LO) | ((u64 )RREG32 (mmTCP_CHAN_STEER_HI) <<32ull ); + +/* Patch the TCP to TCC mapping to skip disabled TCCs */ +for (i =0 ; i < num_max_tcc; ++i) { + tcc = (chan_steer >> (u64)(4 * i)) &0xf ; + +if (!((1 << tcc) & dis_tcc_mask)) { +/* Copy enabled TCC indices to the patched register value. */ + patched_chan_steer |= (u64 )tcc << (u64)(4 * num_active_tcc); + ++num_active_tcc; + } + } + +WARN_ON (num_active_tcc != num_max_tcc -hweight32 (dis_tcc_mask)); + +/* Patch number of TCCs used by TCPs */ + tcp_addr_config =REG_SET_FIELD (RREG32 (mmTCP_ADDR_CONFIG), +TCP_ADDR_CONFIG ,NUM_TCC_BANKS , + num_active_tcc -1 ); + +WREG32 (mmTCP_ADDR_CONFIG, tcp_addr_config); +WREG32 (mmTCP_CHAN_STEER_HI,upper_32_bits (patched_chan_steer)); +WREG32 (mmTCP_CHAN_STEER_LO,lower_32_bits (patched_chan_steer)); +} +static void gfx_v6_0_config_init (struct amdgpu_device *adev) { adev->gfx.config.double_offchip_lds_buf =0 ;
@@ -1729,6 +1794,7 @@ static void gfx_v6_0_constants_init(struct amdgpu_device *adev)gfx_v6_0_tiling_mode_table_init (adev);gfx_v6_0_setup_rb (adev); +gfx_v6_0_setup_tcc (adev);gfx_v6_0_setup_spi (adev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 907/1146 drm/amdgpu: Only send RMA CPER when threshold is exceeded
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kent Russell <[email protected]>
[ Upstream commit b56922fc37454633b831a2a04a1537616742977d ]
According to our documentation, the RMA should only occur when the threshold has been exceeded, not met.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +1 -1
@@ -1939,7 +1939,7 @@ void amdgpu_ras_check_bad_page_status(struct amdgpu_device *adev)if (!control || amdgpu_bad_page_threshold ==0 )return ; -if (control->ras_num_bad_pages >= ras->bad_page_cnt_threshold) { +if (control->ras_num_bad_pages > ras->bad_page_cnt_threshold) {if (amdgpu_dpm_send_rma_reason (adev))dev_warn (adev->dev,"Unable to send out-of-band RMA CPER" );else
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 908/1146 netfilter: xt_policy: fix strict mode inbound policy matching
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiexun Wang <[email protected]>
[ Upstream commit 4b2b4d7d4e203c92db8966b163edfacb1f0e1e29 ]
match_policy_in() walks sec_path entries from the last transform to the first one, but strict policy matching needs to consume info->pol[] in the same forward order as the rule layout.
Derive the strict-match policy position from the number of transforms already consumed so that multi-element inbound rules are matched consistently.
--- net/netfilter/xt_policy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/netfilter/xt_policy.c +1 -1
@@ -63,7 +63,7 @@ match_policy_in(const struct sk_buff *skb, const struct xt_policy_info *info,return 0 ;for (i = sp->len -1 ; i >=0 ; i--) { - pos = strict ? i - sp->len +1 :0 ; + pos = strict ? sp->len - i -1 :0 ;if (pos >= info->len)return 0 ; e = &info->pol[pos];
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 909/1146 netfilter: nf_conntrack_sip: dont use simple_strtoul
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit 8cf6809cddcbe301aedfc6b51bcd4944d45795f6 ]
Replace unsafe port parsing in epaddr_len(), ct_sip_parse_header_uri(), and ct_sip_parse_request() with a new sip_parse_port() helper that validates each digit against the buffer limit, eliminating the use of simple_strtoul() which assumes NUL-terminated strings.
The previous code dereferenced pointers without bounds checks after sip_parse_addr() and relied on simple_strtoul() on non-NUL-terminated skb data. A port that reaches the buffer limit without a trailing character is also rejected as malformed.
Also get rid of all simple_strtoul() usage in conntrack, prefer a stricter version instead. There are intentional changes:
- Bail out if number is > UINT_MAX and indicate a failure, same for too long sequences.
While we do accept 05535 as port 5535, we will not accept e.g. 'sip:10.0.0.1:005060'. While its syntactically valid under RFC 3261, we should restrict this to not waste cycles when presented with malformed packets with 64k '0' characters.
- Force base 10 in ct_sip_parse_numerical_param(). This is used to fetch 'expire=' and 'rports='; both are expected to use base-10.
- In nf_nat_sip.c, only accept the parsed value if its within the 1k-64k range.
- epaddr_len now returns 0 if the port is invalid, as it already does for invalid ip addresses. This is intentional. nf_conntrack_sip performs lots of guesswork to find the right parts of the message to parse. Being stricter could break existing setups. Connection tracking helpers are designed to allow traffic to pass, not to block it.
Based on an earlier patch from Jenny Guanni Qu <[email protected]>.
--- net/netfilter/nf_conntrack_sip.c | 152 ++++++++++++++++++++++++------- net/netfilter/nf_nat_sip.c | 1 + 2 files changed, 119 insertions(+), 34 deletions(-)
net/netfilter/nf_conntrack_sip.c +118 -34
@@ -181,6 +181,57 @@ static int sip_parse_addr(const struct nf_conn *ct, const char *cp,return 1 ; } +/* Parse optional port number after IP address. +* Returns false on malformed input, true otherwise. +* If port is non-NULL, stores parsed port in network byte order. +* If no port is present, sets *port to default SIP port. +*/ +static bool sip_parse_port (const char *dptr,const char **endp, +const char *limit,__be16 *port) +{ +unsigned int p =0 ; +int len =0 ; + +if (dptr >= limit) +return false; + +if (*dptr !=':' ) { +if (port) + *port =htons (SIP_PORT ); +if (endp) + *endp = dptr; +return true; + } + + dptr++;/* skip ':' */ + +while (dptr < limit &&isdigit (*dptr)) { + p = p *10 + (*dptr -'0' ); + dptr++; + len++; +if (len >5 )/* max "65535" */ +return false; + } + +if (len ==0 ) +return false; + +/* reached limit while parsing port */ +if (dptr >= limit) +return false; + +if (p <1024 || p >65535 ) +return false; + +if (port) + *port =htons (p); + +if (endp) + *endp = dptr; + +return true; +} +/* skip ip address. returns its length. */ static int epaddr_len (const struct nf_conn *ct,const char *dptr,const char *limit,int *shift)
@@ -193,11 +244,8 @@ static int epaddr_len(const struct nf_conn *ct, const char *dptr,return 0 ; } -/* Port number */ -if (*dptr ==':' ) { - dptr++; - dptr +=digits_len (ct, dptr, limit, shift); - } +if (!sip_parse_port (dptr, &dptr, limit,NULL )) +return 0 ;return dptr - aux; }
@@ -228,6 +276,51 @@ static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr,return epaddr_len (ct, dptr, limit, shift); } +/* simple_strtoul stops after first non-number character. +* But as we're not dealing with c-strings, we can't rely on +* hitting \r,\n,\0 etc. before moving past end of buffer. +* +* This is a variant of simple_strtoul, but doesn't require +* a c-string. +* +* If value exceeds UINT_MAX, 0 is returned. +*/ +static unsigned int sip_strtouint (const char *cp,unsigned int len,char **endp) +{ +const unsigned int max =sizeof ("4294967295" ); +unsigned int olen = len; +const char *s = cp; +u64 result =0 ; + +if (len > max) + len = max; + +while (olen >0 &&isdigit (*s)) { +unsigned int value; + +if (len ==0 ) + goto err; + + value = *s -'0' ; + result = result *10 + value; + +if (result >UINT_MAX ) + goto err; + s++; + len--; + olen--; + } + +if (endp) + *endp = (char *)s; + +return result; +err: +if (endp) + *endp = (char *)cp; +return 0 ; +} +/* Parse a SIP request line of the form: * * Request-Line = Method SP Request-URI SP SIP-Version CRLF
@@ -241,7 +334,6 @@ int ct_sip_parse_request(const struct nf_conn *ct, {const char *start = dptr, *limit = dptr + datalen, *end;unsigned int mlen; -unsigned int p;int shift =0 ;/* Skip method and following whitespace */
@@ -267,14 +359,8 @@ int ct_sip_parse_request(const struct nf_conn *ct,if (!sip_parse_addr (ct, dptr, &end, addr, limit, true))return -1 ; -if (end < limit && *end ==':' ) { - end++; - p =simple_strtoul (end, (char **)&end,10 ); -if (p <1024 || p >65535 ) -return -1 ; - *port =htons (p); - }else - *port =htons (SIP_PORT ); +if (!sip_parse_port (end, &end, limit, port)) +return -1 ;if (end == dptr)return 0 ;
@@ -509,7 +595,6 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, union nf_inet_addr *addr, __be16 *port) { const char *c, *limit = dptr + datalen; -unsigned int p;int ret; ret = ct_sip_walk_headers(ct, dptr, dataoff ? *dataoff : 0, datalen,
@@ -520,14 +605,8 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr,if (!sip_parse_addr (ct, dptr + *matchoff, &c, addr, limit, true))return -1 ; -if (*c ==':' ) { - c++; - p =simple_strtoul (c, (char **)&c,10 ); -if (p <1024 || p >65535 ) -return -1 ; - *port =htons (p); - }else - *port =htons (SIP_PORT ); +if (!sip_parse_port (c, &c, limit, port)) +return -1 ;if (dataoff) *dataoff = c - dptr;
@@ -609,7 +688,7 @@ int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr,return 0 ; start +=strlen (name); - *val =simple_strtoul (start, &end,0 ); + *val =sip_strtouint (start, limit - start, (char **)&end);if (start == end)return -1 ;if (matchoff && matchlen) {
@@ -1065,6 +1144,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff, mediaoff = sdpoff;for (i =0 ; i <ARRAY_SIZE (sdp_media_types); ) { +char *end; +if (ct_sip_get_sdp_header (ct, *dptr, mediaoff, *datalen,SDP_HDR_MEDIA ,SDP_HDR_UNSPEC , &mediaoff, &medialen) <=0 )
@@ -1080,8 +1161,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff, mediaoff += t->len; medialen -= t->len; - port =simple_strtoul (*dptr + mediaoff,NULL ,10 ); -if (port ==0 ) + port =sip_strtouint (*dptr + mediaoff, *datalen - mediaoff, (char **)&end); +if (port ==0 || *dptr + mediaoff == end)continue ;if (port <1024 || port >65535 ) {nf_ct_helper_log (skb, ct,"wrong port %u" , port);
@@ -1255,7 +1336,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff,*/ if (ct_sip_get_header (ct, *dptr,0 , *datalen,SIP_HDR_EXPIRES , &matchoff, &matchlen) >0 ) - expires =simple_strtoul (*dptr + matchoff,NULL ,10 ); + expires =sip_strtouint (*dptr + matchoff, *datalen - matchoff,NULL ); ret = ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, SIP_HDR_CONTACT, NULL,
@@ -1359,7 +1440,7 @@ static int process_register_response(struct sk_buff *skb, unsigned int protoff,if (ct_sip_get_header (ct, *dptr,0 , *datalen,SIP_HDR_EXPIRES , &matchoff, &matchlen) >0 ) - expires =simple_strtoul (*dptr + matchoff,NULL ,10 ); + expires =sip_strtouint (*dptr + matchoff, *datalen - matchoff,NULL );while (1 ) {unsigned int c_expires = expires;
@@ -1419,10 +1500,12 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff,struct nf_conn *ct =nf_ct_get (skb, &ctinfo);unsigned int matchoff, matchlen, matchend;unsigned int code, cseq, i; +char *end;if (*datalen <strlen ("SIP/2.0 200" ))return NF_ACCEPT ; - code =simple_strtoul (*dptr +strlen ("SIP/2.0 " ),NULL ,10 ); + code =sip_strtouint (*dptr +strlen ("SIP/2.0 " ), + *datalen -strlen ("SIP/2.0 " ),NULL );if (!code) {nf_ct_helper_log (skb, ct,"cannot get code" );return NF_DROP ;
@@ -1433,8 +1516,8 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff,nf_ct_helper_log (skb, ct,"cannot parse cseq" );return NF_DROP ; } - cseq =simple_strtoul (*dptr + matchoff,NULL ,10 ); -if (!cseq && *(*dptr + matchoff) !='0' ) { + cseq =sip_strtouint (*dptr + matchoff, *datalen - matchoff, (char **)&end); +if (*dptr + matchoff == end) {nf_ct_helper_log (skb, ct,"cannot get cseq" );return NF_DROP ; }
@@ -1483,6 +1566,7 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff,for (i =0 ; i <ARRAY_SIZE (sip_handlers); i++) {const struct sip_handler *handler; +char *end; handler = &sip_handlers[i];if (handler->request ==NULL )
@@ -1499,8 +1583,8 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff,nf_ct_helper_log (skb, ct,"cannot parse cseq" );return NF_DROP ; } - cseq =simple_strtoul (*dptr + matchoff,NULL ,10 ); -if (!cseq && *(*dptr + matchoff) !='0' ) { + cseq =sip_strtouint (*dptr + matchoff, *datalen - matchoff, (char **)&end); +if (*dptr + matchoff == end) {nf_ct_helper_log (skb, ct,"cannot get cseq" );return NF_DROP ; }
@@ -1576,7 +1660,7 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, &matchoff, &matchlen) <= 0)break ; - clen =simple_strtoul (dptr + matchoff, (char **)&end,10 ); + clen =sip_strtouint (dptr + matchoff, datalen - matchoff, (char **)&end);if (dptr + matchoff == end)break ;
net/netfilter/nf_nat_sip.c +1 -0
@@ -246,6 +246,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff,if (ct_sip_parse_numerical_param (ct, *dptr, matchend, *datalen,"rport=" , &poff, &plen, &n) >0 && + n >=1024 && n <=65535 &&htons (n) == ct->tuplehash[dir].tuple.dst.u.udp.port &&htons (n) != ct->tuplehash[!dir].tuple.src.u.udp.port) {__be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 910/1146 spi: rzv2h-rspi: Fix silent failure in clock setup error path
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: John Madieu <[email protected]>
[ Upstream commit 54900126ae0a2671f8790a7f95706b9ea95fac4e ]
rzv2h_rspi_setup_clock() is declared to return u32 but returns -EINVAL when no valid clock parameters are found. Cast to u32, -EINVAL becomes 0xffffffea, which is a non-zero value. The caller in rzv2h_rspi_prepare_message() guards against failure with:
rspi->freq = rzv2h_rspi_setup_clock(rspi, speed_hz); if (!rspi->freq) return -EINVAL;
Because 0xffffffea is non-zero, the check is bypassed and the controller proceeds to program SPBR/SPCMD with stale values, leading to an unknown bit rate.
Return 0 on the failed-search path, consistent with the existing clk_set_rate() failure path which already returns 0.
--- drivers/spi/spi-rzv2h-rspi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/spi/spi-rzv2h-rspi.c +1 -1
@@ -581,7 +581,7 @@ static u32 rzv2h_rspi_setup_clock(struct rzv2h_rspi_priv *rspi, u32 hz) RSPI_SPBR_SPR_MAX, &best_clock);if (!best_clock.clk_rate) -return -EINVAL ; +return 0 ; ret =clk_set_rate (best_clock.clk, best_clock.clk_rate);if (ret)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 911/1146 ASoC: amd: acp: Add DMI quirk for Valve Steam Deck OLED
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guilherme G. Piccoli <[email protected]>
[ Upstream commit b0f6f4ac7d5d04fe2adcdd63ed1cd1ad505b8958 ]
Commit 671dd2ffbd8b ("ASoC: amd: acp: Add new cpu dai and dailink creation for I2S BT instance") introduced a change that "broke" Steam Deck's audio probe, in the OLED
model, as observed in the following dmesg snippet:
[...]snd_sof_amd_vangogh 0000:04:00.5: Topology: ABI 3:26:0 Kernel ABI 3:23:1sof_mach nau8821-max: ASoC: physical link acp-bt-codec (id 2) not existsof_mach nau8821-max: ASoC: topology: could not load header: -22snd_sof_amd_vangogh 0000:04:00.5: tplg amd/sof-tplg/sof-vangogh-nau8821-max.tplg component load failed -22 snd_sof_amd_vangogh 0000:04:00.5: error: failed to load DSP topology -22 snd_sof_amd_vangogh 0000:04:00.5: ASoC error (-22): at snd_soc_component_probe() on 0000:04:00.5 sof_mach nau8821-max: ASoC: failed to instantiate card -22sof_mach nau8821-max: error -EINVAL: Failed to register card(sof-nau8821-max)sof_mach nau8821-max: probe with driver sof_mach failed with error -22
[...]
Notice the quotes in "broke": it's not really a bug in such commit, but instead a problem with a topology file from Steam Deck OLED. This was discussed to great extent in [1], and Cristian proposed a pretty simple and functional change that resolved the issue for the Deck's issue. That change, though, would break other devices, so it wasn't accepted upstream. And the proper suggested solution (fix the topology) was never implemented, so Valve's kernel (and anyone that wants to boot the mainline on Steam Deck OLED) is carrying that fix downstream.
So, we propose hereby a different approach: a DMI quirk, as many already present in the sound drivers, to address this issue solely on Steam Deck OLED, not breaking other devices and as a bonus, allowing simple patch up in case eventually the topology file gets fixed (we'd just need to check against any DMI info reflecting that or the topology/FW versions).
The motivation of such upstream quirk is related to users that want to test latest kernel trees on their devices and get no only non-working sound device, but seems some games (like Ori and the Blind Forest) can't properly work without a proper functional audio device. Example of such report can be seen at [2].
--- sound/soc/amd/acp/acp-legacy-mach.c | 2 +- sound/soc/amd/acp/acp-mach-common.c | 22 +++++++++++++++++++--- sound/soc/amd/acp/acp-mach.h | 4 ++++ sound/soc/amd/acp/acp-sof-mach.c | 2 +- 4 files changed, 25 insertions(+), 5 deletions(-)
sound/soc/amd/acp/acp-legacy-mach.c +1 -1
@@ -174,7 +174,7 @@ static int acp_asoc_probe(struct platform_device *pdev) acp_card_drvdata->acp_rev = mach->mach_params.subsystem_rev; dmi_id =dmi_first_match (acp_quirk_table); -if (dmi_id && dmi_id->driver_data) +if (dmi_id && dmi_id->driver_data == (void *)QUIRK_TDM_MODE_ENABLE ) acp_card_drvdata->tdm_mode = dmi_id->driver_data; ret =acp_legacy_dai_links_create (card);
sound/soc/amd/acp/acp-mach-common.c +19 -3
@@ -20,6 +20,7 @@#include <sound/soc.h> #include <linux/input.h> #include <linux/module.h> +#include <linux/dmi.h> #include "../../codecs/rt5682.h" #include "../../codecs/rt1019.h"
@@ -37,15 +38,21 @@#define NAU8821_FREQ_OUT 12288000#define MAX98388_CODEC_DAI "max98388-aif1" -#define TDM_MODE_ENABLE 1 -const struct dmi_system_id acp_quirk_table[] = { {/* Google skyrim proto-0 */ .matches = {DMI_EXACT_MATCH (DMI_PRODUCT_FAMILY ,"Google_Skyrim" ), }, - .driver_data = (void *)TDM_MODE_ENABLE , + .driver_data = (void *)QUIRK_TDM_MODE_ENABLE , + }, + { +/* Valve Steam Deck OLED */ + .matches = { +DMI_MATCH (DMI_SYS_VENDOR ,"Valve" ), +DMI_MATCH (DMI_PRODUCT_NAME ,"Galileo" ), + }, + .driver_data = (void *)QUIRK_REMAP_DMIC_BT , }, {} };
@@ -1401,6 +1408,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)struct snd_soc_dai_link *links;struct device *dev = card->dev;struct acp_card_drvdata *drv_data = card->drvdata; +const struct dmi_system_id *dmi_id =dmi_first_match (acp_quirk_table);int i =0 , num_links =0 ;if (drv_data->hs_cpu_id)
@@ -1572,6 +1580,9 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) links[i].codecs = &snd_soc_dummy_dlc; links[i].num_codecs =1 ; } + +if (dmi_id && dmi_id->driver_data == (void *)QUIRK_REMAP_DMIC_BT ) + links[i].id =DMIC_BE_ID ; i++; }
@@ -1587,6 +1598,11 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) links[i].capture_only =1 ; links[i].nonatomic = true; links[i].no_pcm =1 ; + +if (dmi_id && dmi_id->driver_data == (void *)QUIRK_REMAP_DMIC_BT ) { + links[i].id =BT_BE_ID ; +dev_dbg (dev,"quirk REMAP_DMIC_BT enabled\n" ); + } } card->dai_link = links;
sound/soc/amd/acp/acp-mach.h +4 -0
@@ -26,6 +26,10 @@#define acp_get_drvdata (card) ((struct acp_card_drvdata *)(card)->drvdata) +/* List of DMI quirks - check acp-mach-common.c for usage. */ +#define QUIRK_TDM_MODE_ENABLE 1 +#define QUIRK_REMAP_DMIC_BT 2 +enum be_id {HEADSET_BE_ID =0 ,AMP_BE_ID ,
sound/soc/amd/acp/acp-sof-mach.c +1 -1
@@ -110,7 +110,7 @@ static int acp_sof_probe(struct platform_device *pdev) acp_card_drvdata = card->drvdata; dmi_id =dmi_first_match (acp_quirk_table); -if (dmi_id && dmi_id->driver_data) +if (dmi_id && dmi_id->driver_data == (void *)QUIRK_TDM_MODE_ENABLE ) acp_card_drvdata->tdm_mode = dmi_id->driver_data; acp_card_drvdata->acp_rev = mach->mach_params.subsystem_rev;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 912/1146 ASoC: SOF: Intel: add an empty adr_link
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bard Liao <[email protected]>
[ Upstream commit 3c6f06a200796ae7b2b1065e8a6499b138e27a50 ]
An empty adr_link is expected to terminate the
for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) loop. Allocate link_num + 1 links to add an empty adr_link.
--- sound/soc/sof/intel/hda.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
sound/soc/sof/intel/hda.c +2 -1
@@ -1399,7 +1399,8 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev link_mask |=BIT (peripherals->array[i]->bus->link_id); link_num =hweight32 (link_mask); - links =devm_kcalloc (sdev->dev, link_num,sizeof (*links),GFP_KERNEL ); +/* An empty adr_link is needed to terminate the adr_link loop */ + links =devm_kcalloc (sdev->dev, link_num +1 ,sizeof (*links),GFP_KERNEL );if (!links)return NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 913/1146 spi: rockchip: Read ISR, not IMR, to detect cs-inactive IRQ
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: John Madieu <[email protected]>
[ Upstream commit b4683a239a409d65f88052f5630c748a8ba070cd ]
rockchip_spi_isr() decides whether the current interrupt was the cs-inactive event by reading IMR:
if (rs->cs_inactive && readl_relaxed(rs->regs + ROCKCHIP_SPI_IMR) & INT_CS_INACTIVE) ctlr->target_abort(ctlr);
IMR is the interrupt mask register: it tells which sources are enabled, not which one fired. In the PIO path, rockchip_spi_prepare_irq() enables both INT_RF_FULL and INT_CS_INACTIVE in IMR when rs->cs_inactive is true:
if (rs->cs_inactive) writel_relaxed(INT_RF_FULL | INT_CS_INACTIVE, rs->regs + ROCKCHIP_SPI_IMR);
so the IMR check is always true once cs_inactive is enabled, and every PIO interrupt - including normal RF_FULL completions - is dispatched to ctlr->target_abort(), aborting the transfer. The bug is reachable on ROCKCHIP_SPI_VER2_TYPE2 in target mode with a DMA-capable controller when the transfer is short enough to fall back to PIO (rockchip_spi_can_dma() returns false below fifo_len).
Read ISR (which is RISR masked by IMR) so the check actually reflects which interrupt fired, and parenthesise the expression for clarity while at it.
--- drivers/spi/spi-rockchip.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/spi/spi-rockchip.c +2 -1
@@ -357,7 +357,8 @@ static irqreturn_t rockchip_spi_isr(int irq, void *dev_id)struct rockchip_spi *rs =spi_controller_get_devdata (ctlr);/* When int_cs_inactive comes, spi target abort */ -if (rs->cs_inactive &&readl_relaxed (rs->regs +ROCKCHIP_SPI_IMR ) &INT_CS_INACTIVE ) { +if (rs->cs_inactive && + (readl_relaxed (rs->regs +ROCKCHIP_SPI_ISR ) &INT_CS_INACTIVE )) { ctlr->target_abort (ctlr);writel_relaxed (0 , rs->regs +ROCKCHIP_SPI_IMR );writel_relaxed (0xffffffff , rs->regs +ROCKCHIP_SPI_ICR );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 914/1146 ASoC: tas2764: Mark die temp register as volatile
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Calligeros <[email protected]>
[ Upstream commit 4cfb5971c2fbfac061c23fb4224a3a008199de81 ]
Reading the temperature register always returns the first value read from the chip due to regcache.
Mark TAS2764_TEMP as volatile to prevent returning stale, cached values when reading the die temp.
--- sound/soc/codecs/tas2764.c | 1 + 1 file changed, 1 insertion(+)
sound/soc/codecs/tas2764.c +1 -0
@@ -809,6 +809,7 @@ static bool tas2764_volatile_register(struct device *dev, unsigned int reg) {switch (reg) {case TAS2764_SW_RST : +case TAS2764_TEMP : case TAS2764_INT_LTCH0 ... TAS2764_INT_LTCH4:case TAS2764_INT_CLK_CFG :return true;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 915/1146 ASoC: tas2770: Fix order of operations for temperature calculation
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Calligeros <[email protected]>
[ Upstream commit c7ecb6a61908c2604dda6e42da66724d256de7b9 ]
The order of operations to derive the temperature from the temp register values was wrong, since 1000 / 16 is not an integer. This resulted in the calculated temperature value deviating from the value represented by the registers slightly, which was most obvious when the registers were zeroed (-92.265 *C vs the expected -93.000 *C).
Scale the reading before dividing the whole thing by 16 to correct this.
--- sound/soc/codecs/tas2770.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
sound/soc/codecs/tas2770.c +2 -2
@@ -549,7 +549,7 @@ static int tas2770_read_die_temp(struct tas2770_priv *tas2770, long *result)/* * As per datasheet: divide register by 16 and subtract 93 to get * degrees Celsius. hwmon requires millidegrees. Let's avoid rounding -* errors by subtracting 93 * 16 then multiplying by 1000 / 16. +* errors by subtracting 93 * 16 and scaling before dividing. * * NOTE: The ADC registers are initialised to 0 on reset. This means * that the temperature will read -93 *C until the chip is brought out
@@ -558,7 +558,7 @@ static int tas2770_read_die_temp(struct tas2770_priv *tas2770, long *result)* value read back from its registers will be the last value sampled * before entering software shutdown. */ - *result = (reading - (93 *16 )) * (1000 /16 ); + *result = (reading - (93 *16 )) *1000 /16 ;return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 916/1146 drm/sysfb: ofdrm: fix PCI device reference leaks
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuho Choi <[email protected]>
[ Upstream commit 4aa8110000b0d215deef8eed283565dd0c1def88 ]
display_get_pci_dev_of() gets a referenced PCI device via pci_get_device(). Drop that reference when pci_enable_device() fails and release it during the managed teardown path after pci_disable_device().
Without that, ofdrm leaks the pci_dev reference on both the error path and the normal cleanup path.
--- drivers/gpu/drm/sysfb/ofdrm.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/sysfb/ofdrm.c +2 -0
@@ -350,6 +350,7 @@ static void ofdrm_pci_release(void *data)struct pci_dev *pcidev = data;pci_disable_device (pcidev); +pci_dev_put (pcidev); }static int ofdrm_device_init_pci (struct ofdrm_device *odev)
@@ -375,6 +376,7 @@ static int ofdrm_device_init_pci(struct ofdrm_device *odev)if (ret) {drm_err (dev,"pci_enable_device(%s) failed: %d\n" ,dev_name (&pcidev->dev), ret); +pci_dev_put (pcidev);return ret; } ret =devm_add_action_or_reset (&pdev->dev, ofdrm_pci_release, pcidev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 917/1146 drm/color-mgmt: Typo s/R332/RGB332/
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Geert Uytterhoeven <[email protected]>
[ Upstream commit 9d5a2b8f6281f6090002517fb9272ea07038afe8 ]
Fix a typo of "RGB332" in kerneldoc for the drm_crtc_fill_palette_332() helper.
--- drivers/gpu/drm/drm_color_mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/drm_color_mgmt.c +1 -1
@@ -831,7 +831,7 @@ static void fill_palette_332(struct drm_crtc *crtc, u16 r, u16 g, u16 b, }/** -* drm_crtc_fill_palette_332 - Programs a default palette for R332-like formats +* drm_crtc_fill_palette_332 - Programs a default palette for RGB332-like formats * @crtc: The displaying CRTC * @set_palette: Callback for programming the hardware gamma LUT *
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 918/1146 arm64/scs: Fix potential sign extension issue of advance_loc4
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Guan <[email protected]>
[ Upstream commit 4023b7424ecd5d38cc75b650d6c1bf630ef8cb40 ]
The expression (*opcode++ << 24) and exp * code_alignment_factor may overflow signed int and becomes negative.
Fix this by casting each byte to u64 before shifting. Also fix the misaligned break statement while we are here.
Example of the result can be seen here:
It maybe not a real problem, but could be a issue in future.
--- arch/arm64/kernel/pi/patch-scs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/arm64/kernel/pi/patch-scs.c +2 -2
@@ -196,9 +196,9 @@ static int scs_handle_fde_frame(const struct eh_frame *frame, loc += *opcode++ * code_alignment_factor; loc += (*opcode++ <<8 ) * code_alignment_factor; loc += (*opcode++ <<16 ) * code_alignment_factor; - loc += (*opcode++ <<24 ) * code_alignment_factor; + loc += ((u64)*opcode++ <<24 ) * code_alignment_factor; size -=4 ; -break ; +break ;case DW_CFA_def_cfa:case DW_CFA_offset_extended:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 919/1146 spi: spi-mem: Add a packed command operation
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Miquel Raynal <[email protected]>
[ Upstream commit f79ee9e4b23244e77b28d176ce99a2d84d813ac5 ]
Instead of repeating the command opcode twice, some flash devices try to pack command and address bits. In this case, the second opcode byte being sent (LSB) is free to be used. The input data must be ANDed to only provide the relevant bits.
Stable-dep-of: 8d655748aba1 ("mtd: spinand: winbond: Set the packed page read flag to W35N02/04JW")
--- include/linux/spi/spi-mem.h | 8 ++++++++ 1 file changed, 8 insertions(+)
include/linux/spi/spi-mem.h +8 -0
@@ -28,6 +28,14 @@ .dtr = true, \ } +#define SPI_MEM_DTR_OP_PACKED_CMD (__opcode, __addr, __buswidth) \ + { \ + .nbytes = 2, \ + .opcode = __opcode << 8 | __addr, \ + .buswidth = __buswidth, \ + .dtr = true, \ + } +#define SPI_MEM_OP_ADDR (__nbytes, __val, __buswidth) \ { \ .nbytes = __nbytes, \
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 920/1146 mtd: spinand: Add support for packed read data ODTR commands
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Miquel Raynal <[email protected]>
[ Upstream commit 5e25407b68f460142539536e31fa20338db6146f ]
Some devices stuff address bits in the double byte opcode (in place of the repeated byte) in order to be able to increase the size of the devices, without adding extra address bytes.
Create a flag to identify those devices. When the flag is set, use the "packed" variant for the read data operation.
Stable-dep-of: 8d655748aba1 ("mtd: spinand: winbond: Set the packed page read flag to W35N02/04JW")
--- drivers/mtd/nand/spi/core.c | 24 +++++++++++++++++++++--- include/linux/mtd/spinand.h | 7 +++++++ 2 files changed, 28 insertions(+), 3 deletions(-)
drivers/mtd/nand/spi/core.c +21 -3
@@ -100,6 +100,17 @@ spinand_fill_page_read_op(struct spinand_device *spinand, u64 addr)return op; } +static struct spi_mem_op +spinand_fill_page_read_packed_op (struct spinand_device *spinand,u64 addr) +{ +struct spi_mem_op op = spinand->op_templates->page_read; + + op.cmd.opcode |= addr >>16 ; + op.addr.val = addr &0xFFFF ; + +return op; +} +struct spi_mem_op spinand_fill_prog_exec_op (struct spinand_device *spinand,u64 addr) {
@@ -453,7 +464,10 @@ static int spinand_load_page_op(struct spinand_device *spinand, {struct nand_device *nand =spinand_to_nand (spinand);unsigned int row =nanddev_pos_to_row (nand, &req->pos); -struct spi_mem_op op =SPINAND_OP (spinand, page_read, row); +bool packed = spinand->flags &SPINAND_ODTR_PACKED_PAGE_READ ; +struct spi_mem_op op = packed ? +SPINAND_OP (spinand, page_read_packed, row) : +SPINAND_OP (spinand, page_read, row);return spi_mem_exec_op (spinand->spimem, &op); }
@@ -1489,9 +1503,13 @@ static int spinand_init_odtr_instruction_set(struct spinand_device *spinand)if (!spi_mem_supports_op (spinand->spimem, &tmpl->blk_erase))return -EOPNOTSUPP ; - tmpl->page_read = (struct spi_mem_op )SPINAND_PAGE_READ_8D_8D_0_OP (0 ); -if (!spi_mem_supports_op (spinand->spimem, &tmpl->page_read)) +if (spinand->flags &SPINAND_ODTR_PACKED_PAGE_READ ) + tmpl->page_read = (struct spi_mem_op )SPINAND_PAGE_READ_PACKED_8D_8D_0_OP (0 ); +else + tmpl->page_read = (struct spi_mem_op )SPINAND_PAGE_READ_8D_8D_0_OP (0 ); +if (!spi_mem_supports_op (spinand->spimem, &tmpl->page_read)) {return -EOPNOTSUPP ; + } tmpl->prog_exec = (struct spi_mem_op )SPINAND_PROG_EXEC_8D_8D_0_OP (0 );if (!spi_mem_supports_op (spinand->spimem, &tmpl->prog_exec))
include/linux/mtd/spinand.h +7 -0
@@ -290,6 +290,12 @@ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) +#define SPINAND_PAGE_READ_PACKED_8D_8D_0_OP (addr) \ + SPI_MEM_OP(SPI_MEM_DTR_OP_PACKED_CMD(0x13, addr >> 16, 8), \ + SPI_MEM_DTR_OP_ADDR(2, addr & 0xffff, 8), \ + SPI_MEM_OP_NO_DUMMY, \ + SPI_MEM_OP_NO_DATA) +#define SPINAND_PAGE_READ_FROM_CACHE_8D_8D_8D_OP (addr, ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x9d, 8), \ SPI_MEM_DTR_OP_ADDR(2, addr, 8), \
@@ -482,6 +488,7 @@ struct spinand_ecc_info {#define SPINAND_HAS_PROG_PLANE_SELECT_BIT BIT(2)#define SPINAND_HAS_READ_PLANE_SELECT_BIT BIT(3)#define SPINAND_NO_RAW_ACCESS BIT(4) +#define SPINAND_ODTR_PACKED_PAGE_READ BIT(5)/** * struct spinand_ondie_ecc_conf - private SPI-NAND on-die ECC engine structure
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 921/1146 mtd: spinand: winbond: Set the packed page read flag to W35N02/04JW
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Miquel Raynal <[email protected]>
[ Upstream commit 8d655748aba1b603c54053a20322401dc1e5d782 ]
Both W35N02JW and W35N04JW diverge from W35N01JW when it comes to the "data read" operation in ODTR mode. In order to stuff more address bits (up to 18), the second command byte is replaced by the most significant address bits, keeping the number of address bytes to 2.
--- drivers/mtd/nand/spi/winbond.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/mtd/nand/spi/winbond.c +2 -2
@@ -518,7 +518,7 @@ static const struct spinand_info winbond_spinand_table[] = {SPINAND_INFO_OP_VARIANTS (&read_cache_octal_variants, &write_cache_octal_variants, &update_cache_octal_variants), -0 , +SPINAND_ODTR_PACKED_PAGE_READ ,SPINAND_INFO_VENDOR_OPS (&winbond_w35_ops),SPINAND_ECCINFO (&w35n01jw_ooblayout,NULL ), SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)),
@@ -529,7 +529,7 @@ static const struct spinand_info winbond_spinand_table[] = {SPINAND_INFO_OP_VARIANTS (&read_cache_octal_variants, &write_cache_octal_variants, &update_cache_octal_variants), -0 , +SPINAND_ODTR_PACKED_PAGE_READ ,SPINAND_INFO_VENDOR_OPS (&winbond_w35_ops),SPINAND_ECCINFO (&w35n01jw_ooblayout,NULL ), SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)),
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 922/1146 mtd: spinand: winbond: Fix ODTR write VCR on W35NxxJW
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Miquel Raynal <[email protected]>
[ Upstream commit 135ac3b84bcedae1860e7a9512d63166f42b736e ]
In most scenarios this variant is actually unused (VCR is written in SSDR mode), but we need to provide an octal variant. The address is 24 bits but is sent over 4 bytes MSB first. This means we need to shift the register address by one extra byte for the address to be correct.
I didn't catch this initially because the volatile register region is 256 bytes wide, so the write-then-read procedure did work with the small register addresses I was using at that time: 0 and 1.
--- drivers/mtd/nand/spi/winbond.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/mtd/nand/spi/winbond.c +1 -1
@@ -99,7 +99,7 @@ static SPINAND_OP_VARIANTS(update_cache_variants,#define SPINAND_WINBOND_WRITE_VCR_8D_8D_8D (reg, buf) \ SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x81, 8), \ - SPI_MEM_DTR_OP_ADDR(4, reg, 8), \ + SPI_MEM_DTR_OP_ADDR(4, reg << 8, 8), \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_DTR_OP_DATA_OUT(2, buf, 8))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 923/1146 ACPICA: Provide #defines for EINJV2 error types
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tony Luck <[email protected]>
[ Upstream commit 1f6008538384453eb4c13a3d7ff9e37ee8aee6b9 ]
EINJV2 defined new error types by moving the severity (correctable, uncorrectable non-fatal, uncorrectable fatal) out of the "type".
ACPI 6.5 introduced EINJV2 and defined a vendor defined error type using bit 31. This was dropped in ACPI 6.6.
Stable-dep-of: 0c00cfbcfcff ("ACPI: APEI: EINJ: Fix EINJV2 memory error injection")
--- include/acpi/actbl1.h | 6 ++++++ 1 file changed, 6 insertions(+)
include/acpi/actbl1.h +6 -0
@@ -1386,6 +1386,12 @@ enum acpi_einj_command_status {#define ACPI_EINJ_CXL_MEM_FATAL (1<<17)#define ACPI_EINJ_VENDOR_DEFINED (1<<31) +/* EINJV2 error types from EINJV2_GET_ERROR_TYPE (ACPI 6.6) */ + +#define ACPI_EINJV2_PROCESSOR (1) +#define ACPI_EINJV2_MEMORY (1<<1) +#define ACPI_EINJV2_PCIE (1<<2) +/******************************************************************************* * * ERST - Error Record Serialization Table (ACPI 4.0)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 924/1146 ACPI: APEI: EINJ: Fix EINJV2 memory error injection
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tony Luck <[email protected]>
[ Upstream commit 0c00cfbcfcffa7085e4f0c7fd7a4caada4e7a90f ]
Error types in EINJV2 use different bit positions for each flavor of injection from legacy EINJ.
Two issues:
1) The address sanity checks in einj_error_inject() were skipped for EINJV2 injections. Noted by sashiko[1]
2) __einj_error_trigger() failed to drop the entry of the target physical address from the list of resources that need to be requested.
Add a helper function that checks if an injection is to memory and use it to solve each of these issues.
Note that the old test in __einj_error_trigger() checked that param2 was not zero. This isn't needed because the sanity checks in einj_error_inject() reject memory injections with param2 == 0.
--- drivers/acpi/apei/einj-core.c | 45 +++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 20 deletions(-)
drivers/acpi/apei/einj-core.c +25 -20
@@ -401,8 +401,18 @@ static struct acpi_generic_address *einj_get_trigger_parameter_region(return NULL ; } + +static bool is_memory_injection (u32 type,u32 flags) +{ +if (flags &SETWA_FLAGS_EINJV2 ) +return !!(type &ACPI_EINJV2_MEMORY ); +if (type &ACPI5_VENDOR_BIT ) +return !!(vendor_flags &SETWA_FLAGS_MEM ); +return !!(type &MEM_ERROR_MASK ) || !!(flags &SETWA_FLAGS_MEM ); +} +/* Execute instructions in trigger error action table */ -static int __einj_error_trigger (u64 trigger_paddr,u32 type, +static int __einj_error_trigger (u64 trigger_paddr,u32 type,u32 flags,u64 param1,u64 param2) {struct acpi_einj_trigger trigger_tab;
@@ -480,7 +490,7 @@ static int __einj_error_trigger(u64 trigger_paddr, u32 type,* This will cause resource conflict with regular memory. So * remove it from trigger table resources. */ -if ((param_extension || acpi5) && (type &MEM_ERROR_MASK ) && param2) { +if ((param_extension || acpi5) &&is_memory_injection (type, flags)) {struct apei_resources addr_resources;apei_resources_init (&addr_resources);
@@ -660,7 +670,7 @@ static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,return rc; trigger_paddr =apei_exec_ctx_get_output (&ctx);if (notrigger ==0 ) { - rc =__einj_error_trigger (trigger_paddr, type, param1, param2); + rc =__einj_error_trigger (trigger_paddr, type, flags, param1, param2);if (rc)return rc; }
@@ -718,35 +728,30 @@ int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, u64 param3, SETWA_FLAGS_PCIE_SBDF | SETWA_FLAGS_EINJV2)))return -EINVAL ; +/* +* Injections targeting a CXL 1.0/1.1 port have to be injected +* via the einj_cxl_rch_error_inject() path as that does the proper +* validation of the given RCRB base (MMIO) address. +*/ +if (einj_is_cxl_error_type (type) && (flags &SETWA_FLAGS_MEM )) +return -EINVAL ; +/* check if type is a valid EINJv2 error type */ if (is_v2) {if (!(type & available_error_type_v2))return -EINVAL ; } -/* -* We need extra sanity checks for memory errors. -* Other types leap directly to injection. -*/ /* ensure param1/param2 existed */ if (!(param_extension || acpi5)) goto inject; -/* ensure injection is memory related */ -if (type &ACPI5_VENDOR_BIT ) { -if (vendor_flags !=SETWA_FLAGS_MEM ) - goto inject; - }else if (!(type &MEM_ERROR_MASK ) && !(flags &SETWA_FLAGS_MEM )) { - goto inject; - } -/* -* Injections targeting a CXL 1.0/1.1 port have to be injected -* via the einj_cxl_rch_error_inject() path as that does the proper -* validation of the given RCRB base (MMIO) address. +* We need extra sanity checks for memory errors. +* Other types leap directly to injection. */ -if (einj_is_cxl_error_type (type) && (flags &SETWA_FLAGS_MEM )) -return -EINVAL ; +if (!is_memory_injection (type, flags)) + goto inject;/* * Disallow crazy address masks that give BIOS leeway to pick
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 925/1146 cdrom, scsi: sr: propagate read-only status to block layer via set_disk_ro()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daan De Meyer <[email protected]>
[ Upstream commit 0898a817621a2f0cddca8122d9b974003fe5036d ]
The cdrom core never calls set_disk_ro() for a registered device, so BLKROGET on a CD-ROM device always returns 0 (writable), even when the drive has no write capabilities and writes will inevitably fail. This causes problems for userspace that relies on BLKROGET to determine whether a block device is read-only. For example, systemd's loop device setup uses BLKROGET to decide whether to create a loop device with LO_FLAGS_READ_ONLY. Without the read-only flag, writes pass through the loop device to the CD-ROM and fail with I/O errors. systemd-fsck similarly checks BLKROGET to decide whether to run fsck in no-repair mode (-n).
The write-capability bits in cdi->mask come from two different sources:CDC_DVD_RAM and CDC_CD_RW are populated by the driver from the MODE SENSE capabilities page (page 0x2A) before register_cdrom() is called, while CDC_MRW_W and CDC_RAM require the MMC GET CONFIGURATION command and were only probed by cdrom_open_write() at device open time. This meant that any attempt to compute the writable state from the full mask at probe time was incorrect, because the GET CONFIGURATION bits were still unset (and cdi->mask is initialized such that capabilities are assumed present).
Fix this by factoring the GET CONFIGURATION probing out of cdrom_open_write() into a new exported helper, cdrom_probe_write_features(), and having sr call it from sr_probe() right after get_capabilities() has populated the MODE SENSE bits. register_cdrom() then calls set_disk_ro() based on the full write-capability mask (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW) so the block layer reflects the drive's actual write support. The feature queries used (CDF_MRW and CDF_RWRT via GET CONFIGURATION with RT=00) report drive-level capabilities that are persistent across media, so a single probe before register_cdrom() is sufficient and the redundant probe at open time is dropped.
With set_disk_ro() now accurate, the long-vestigial cd->writeable flag in sr can go: get_capabilities() used to set cd->writeable based on the same four mask bits, but because CDC_MRW_W and CDC_RAM default to "capability present" in cdi->mask and aren't touched by MODE SENSE, the condition that gated cd->writeable was always true, making it unconditionally 1. Replace the corresponding gate in sr_init_command() with get_disk_ro(cd->disk), which turns a previously no-op check into a real one and also catches kernel-internal bio writers that bypass blkdev_write_iter()'s bdev_read_only() check.
The sd driver (SCSI disks) does not have this problem because it checks the MODE SENSE Write Protect bit and calls set_disk_ro() accordingly. The sr driver cannot use the same approach because the MMC specification does not define the WP bit in the MODE SENSE device-specific parameter byte for CD-ROM devices.
--- drivers/cdrom/cdrom.c | 73 ++++++++++++++++++++++++++++--------------- drivers/scsi/sr.c | 11 ++----- drivers/scsi/sr.h | 1 - include/linux/cdrom.h | 1 + 4 files changed, 51 insertions(+), 35 deletions(-)
drivers/cdrom/cdrom.c +48 -25
@@ -631,6 +631,16 @@ int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi)WARN_ON (!cdo->generic_packet); +/* +* Propagate the drive's write support to the block layer so BLKROGET +* reflects actual write capability. Drivers that use GET CONFIGURATION +* features (CDC_MRW_W, CDC_RAM) must have called +* cdrom_probe_write_features() before register_cdrom() so the mask is +* complete here. +*/ +set_disk_ro (disk, !CDROM_CAN (CDC_DVD_RAM |CDC_MRW_W |CDC_RAM | +CDC_CD_RW )); +cd_dbg (CD_REG_UNREG ,"drive \"/dev/%s\" registered\n" , cdi->name);mutex_lock (&cdrom_mutex);list_add (&cdi->list, &cdrom_list);
@@ -742,6 +752,44 @@ static int cdrom_is_random_writable(struct cdrom_device_info *cdi, int *write)return 0 ; } +/* +* Probe write-related MMC features via GET CONFIGURATION and update +* cdi->mask accordingly. Drivers that populate cdi->mask from the MODE SENSE +* capabilities page (e.g. sr) should call this after those MODE SENSE bits +* have been set but before register_cdrom(), so that the full set of +* write-capability bits is known by the time register_cdrom() decides on the +* initial read-only state of the disk. +*/ +void cdrom_probe_write_features (struct cdrom_device_info *cdi) +{ +int mrw, mrw_write, ram_write; + + mrw =0 ; +if (!cdrom_is_mrw (cdi, &mrw_write)) + mrw =1 ; + +if (CDROM_CAN (CDC_MO_DRIVE )) + ram_write =1 ; +else + (void )cdrom_is_random_writable (cdi, &ram_write); + +if (mrw) + cdi->mask &= ~CDC_MRW ; +else + cdi->mask |=CDC_MRW ; + +if (mrw_write) + cdi->mask &= ~CDC_MRW_W ; +else + cdi->mask |=CDC_MRW_W ; + +if (ram_write) + cdi->mask &= ~CDC_RAM ; +else + cdi->mask |=CDC_RAM ; +} +EXPORT_SYMBOL (cdrom_probe_write_features); +static int cdrom_media_erasable (struct cdrom_device_info *cdi) {disc_information di;
@@ -894,33 +942,8 @@ static int cdrom_is_dvd_rw(struct cdrom_device_info *cdi)*/ static int cdrom_open_write (struct cdrom_device_info *cdi) { -int mrw, mrw_write, ram_write;int ret =1 ; - mrw =0 ; -if (!cdrom_is_mrw (cdi, &mrw_write)) - mrw =1 ; - -if (CDROM_CAN (CDC_MO_DRIVE )) - ram_write =1 ; -else - (void )cdrom_is_random_writable (cdi, &ram_write); - -if (mrw) - cdi->mask &= ~CDC_MRW ; -else - cdi->mask |=CDC_MRW ; - -if (mrw_write) - cdi->mask &= ~CDC_MRW_W ; -else - cdi->mask |=CDC_MRW_W ; - -if (ram_write) - cdi->mask &= ~CDC_RAM ; -else - cdi->mask |=CDC_RAM ; -if (CDROM_CAN (CDC_MRW_W )) ret =cdrom_mrw_open_write (cdi);else if (CDROM_CAN (CDC_DVD_RAM ))
drivers/scsi/sr.c +2 -9
@@ -395,7 +395,7 @@ static blk_status_t sr_init_command(struct scsi_cmnd *SCpnt)switch (req_op (rq)) {case REQ_OP_WRITE : -if (!cd->writeable) +if (get_disk_ro (cd->disk)) goto out; SCpnt->cmnd[0 ] =WRITE_10 ; cd->cdi.media_written =1 ;
@@ -681,6 +681,7 @@ static int sr_probe(struct scsi_device *sdev) error = -ENOMEM ;if (get_capabilities (cd)) goto fail_minor; +cdrom_probe_write_features (&cd->cdi);sr_vendor_init (cd);set_capacity (disk, cd->capacity);
@@ -899,14 +900,6 @@ static int get_capabilities(struct scsi_cd *cd)/*else I don't think it can close its tray cd->cdi.mask |= CDC_CLOSE_TRAY; */ -/* -* if DVD-RAM, MRW-W or CD-RW, we are randomly writable -*/ -if ((cd->cdi.mask & (CDC_DVD_RAM |CDC_MRW_W |CDC_RAM |CDC_CD_RW )) != - (CDC_DVD_RAM |CDC_MRW_W |CDC_RAM |CDC_CD_RW )) { - cd->writeable =1 ; - } -kfree (buffer);return 0 ; }
drivers/scsi/sr.h +0 -1
@@ -35,7 +35,6 @@ typedef struct scsi_cd {struct scsi_device *device;unsigned int vendor;/* vendor code, see sr_vendor.c */ unsigned long ms_offset;/* for reading multisession-CD's */ - unsigned writeable : 1; unsigned use:1; /* is this device still supportable */ unsigned xa_flag:1; /* CD has XA sectors ? */ unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */
include/linux/cdrom.h +1 -0
@@ -108,6 +108,7 @@ int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev,extern unsigned int cdrom_check_events (struct cdrom_device_info *cdi,unsigned int clearing); +extern void cdrom_probe_write_features (struct cdrom_device_info *cdi);extern int register_cdrom (struct gendisk *disk,struct cdrom_device_info *cdi);extern void unregister_cdrom (struct cdrom_device_info *cdi);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 926/1146 spi: axiado: replace usleep_range() with udelay() in IRQ path
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Gu <[email protected]>
[ Upstream commit f5c6a272b699b9a0698535e1a56e683207e50030 ]
ax_spi_fill_tx_fifo() can be called from ax_spi_irq() which is a hard irq handler. Replace usleep_range(10, 10) with udelay(10) in atomic context.
--- drivers/spi/spi-axiado.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/spi/spi-axiado.c +1 -1
@@ -201,7 +201,7 @@ static void ax_spi_fill_tx_fifo(struct ax_spi *xspi)* then spi control did't work thoroughly, add one byte delay */ if (ax_spi_read (xspi,AX_SPI_IVR ) &AX_SPI_IVR_TFOV ) -usleep_range (10 ,10 ); +udelay (10 );if (xspi->tx_buf)ax_spi_write_b (xspi,AX_SPI_TXFIFO , *xspi->tx_buf++);else
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 927/1146 netdevsim: zero initialize struct iphdr in dummy sk_buff
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikola Z. Ivanov <[email protected]>
[ Upstream commit 35eaa6d8d6c2ee65e96f507add856e0eacf24591 ]
Syzbot reports a KMSAN uninit-value originating from nsim_dev_trap_skb_build, with the allocation also being performed in the same function.
Fix this by calling skb_put_zero instead of skb_put to guarantee zero initialization of the whole IP header.
--- drivers/net/netdevsim/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/netdevsim/dev.c +1 -1
@@ -829,7 +829,7 @@ static struct sk_buff *nsim_dev_trap_skb_build(void) skb->protocol =htons (ETH_P_IP );skb_set_network_header (skb, skb->len); - iph =skb_put (skb,sizeof (struct iphdr )); + iph =skb_put_zero (skb,sizeof (struct iphdr )); iph->protocol =IPPROTO_UDP ; iph->saddr =in_aton ("192.0.2.1" ); iph->daddr =in_aton ("198.51.100.1" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 928/1146 net/sched: netem: fix probability gaps in 4-state loss model
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephen Hemminger <[email protected]>
[ Upstream commit 732b463449fd0ef90acd13cda68eab1c91adb00c ]
The 4-state Markov chain in loss_4state() has gaps at the boundaries between transition probability ranges. The comparisons use:
if (rnd < a4) else if (a4 < rnd && rnd < a1 + a4)
When rnd equals a boundary value exactly, neither branch matches and no state transition occurs. The redundant lower-bound check (a4 < rnd) is already implied by being in the else branch.
Remove the unnecessary lower-bound comparisons so the ranges are contiguous and every random value produces a transition, matching the GI (General and Intuitive) loss model specification.
This bug goes back to original implementation of this model.
--- net/sched/sch_netem.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
net/sched/sch_netem.c +4 -4
@@ -227,10 +227,10 @@ static bool loss_4state(struct netem_sched_data *q)if (rnd < clg->a4) { clg->state =LOST_IN_GAP_PERIOD ;return true; - }else if (clg->a4 < rnd && rnd < clg->a1 + clg->a4) { + }else if (rnd < clg->a1 + clg->a4) { clg->state =LOST_IN_BURST_PERIOD ;return true; - }else if (clg->a1 + clg->a4 < rnd) { + }else { clg->state =TX_IN_GAP_PERIOD ; }
@@ -247,9 +247,9 @@ static bool loss_4state(struct netem_sched_data *q)case LOST_IN_BURST_PERIOD :if (rnd < clg->a3) clg->state =TX_IN_BURST_PERIOD ; -else if (clg->a3 < rnd && rnd < clg->a2 + clg->a3) { +else if (rnd < clg->a2 + clg->a3) { clg->state =TX_IN_GAP_PERIOD ; - }else if (clg->a2 + clg->a3 < rnd) { + }else { clg->state =LOST_IN_BURST_PERIOD ;return true; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 929/1146 net/sched: netem: fix queue limit check to include reordered packets
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephen Hemminger <[email protected]>
[ Upstream commit 4185701fcce6b426b6c3630b25330dddd9c47b0d ]
The queue limit check in netem_enqueue() uses q->t_len which only counts packets in the internal tfifo. Packets placed in sch->q by the reorder path (__qdisc_enqueue_head) are not counted, allowing the total queue occupancy to exceed sch->limit under reordering.
Include sch->q.qlen in the limit check.
--- net/sched/sch_netem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/sched/sch_netem.c +1 -1
@@ -524,7 +524,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch,1 <<get_random_u32_below (8 ); } -if (unlikely (q->t_len >= sch->limit)) { +if (unlikely (sch->q.qlen >= sch->limit)) {/* re-link segs, so that qdisc_drop_all() frees them all */ skb->next = segs;qdisc_drop_all (skb, sch, to_free);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 930/1146 net/sched: netem: only reseed PRNG when seed is explicitly provided
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephen Hemminger <[email protected]>
[ Upstream commit 986afaf809940577224a99c3a08d97a15eb37e93 ]
netem_change() unconditionally reseeds the PRNG on every tc change command. If TCA_NETEM_PRNG_SEED is not specified, a new random seed is generated, destroying reproducibility for users who set a deterministic seed on a previous change.
Move the initial random seed generation to netem_init() and only reseed in netem_change() when TCA_NETEM_PRNG_SEED is explicitly provided by the user.
--- net/sched/sch_netem.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
net/sched/sch_netem.c +6 -4
@@ -1112,11 +1112,10 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt,/* capping jitter to the range acceptable by tabledist() */ q->jitter =min_t (s64,abs (q->jitter),INT_MAX ); -if (tb[TCA_NETEM_PRNG_SEED ]) +if (tb[TCA_NETEM_PRNG_SEED ]) { q->prng.seed =nla_get_u64 (tb[TCA_NETEM_PRNG_SEED ]); -else - q->prng.seed =get_random_u64 (); -prandom_seed_state (&q->prng.prng_state, q->prng.seed); +prandom_seed_state (&q->prng.prng_state, q->prng.seed); + } unlock:sch_tree_unlock (sch);
@@ -1139,6 +1138,9 @@ static int netem_init(struct Qdisc *sch, struct nlattr *opt,return -EINVAL ; q->loss_model =CLG_RANDOM ; + q->prng.seed =get_random_u64 (); +prandom_seed_state (&q->prng.prng_state, q->prng.seed); + ret =netem_change (sch, opt, extack);if (ret)pr_info ("netem: change failed\n" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 931/1146 net/sched: netem: validate slot configuration
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephen Hemminger <[email protected]>
[ Upstream commit 01801c359a74737b9b1aa28568b60374d857241a ]
Reject slot configurations that have no defensible meaning:
- negative min_delay or max_delay
- min_delay greater than max_delay
- negative dist_delay or dist_jitter
- negative max_packets or max_bytes
Negative or out-of-order delays underflow in get_slot_next(), producing garbage intervals. Negative limits trip the per-slot accounting (packets_left/bytes_left <= 0) on the first packet of every slot, defeating the rate-limiting half of the slot feature.
Note that dist_jitter has been silently coerced to its absolute value by get_slot() since the feature was introduced; rejecting negatives here converts that silent coercion into -EINVAL. The abs() can be removed in a follow-up.
--- net/sched/sch_netem.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+)
net/sched/sch_netem.c +29 -0
@@ -827,6 +827,29 @@ static int get_dist_table(struct disttable **tbl, const struct nlattr *attr)return 0 ; } +static int validate_slot (const struct nlattr *attr,struct netlink_ext_ack *extack) +{ +const struct tc_netem_slot *c =nla_data (attr); + +if (c->min_delay <0 || c->max_delay <0 ) { +NL_SET_ERR_MSG_ATTR (extack, attr,"negative slot delay" ); +return -EINVAL ; + } +if (c->min_delay > c->max_delay) { +NL_SET_ERR_MSG_ATTR (extack, attr,"slot min delay greater than max delay" ); +return -EINVAL ; + } +if (c->dist_delay <0 || c->dist_jitter <0 ) { +NL_SET_ERR_MSG_ATTR (extack, attr,"negative dist delay" ); +return -EINVAL ; + } +if (c->max_packets <0 || c->max_bytes <0 ) { +NL_SET_ERR_MSG_ATTR (extack, attr,"negative slot limit" ); +return -EINVAL ; + } +return 0 ; +} +static void get_slot (struct netem_sched_data *q,const struct nlattr *attr) {const struct tc_netem_slot *c =nla_data (attr);
@@ -1040,6 +1063,12 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, goto table_free; } +if (tb[TCA_NETEM_SLOT ]) { + ret =validate_slot (tb[TCA_NETEM_SLOT ], extack); +if (ret) + goto table_free; + } +sch_tree_lock (sch);/* backup q->clg and q->loss_model */ old_clg = q->clg;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 932/1146 net/sched: netem: fix slot delay calculation overflow
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephen Hemminger <[email protected]>
[ Upstream commit 51e94e1e2fef351c74d69eb53666df808d26af95 ]
get_slot_next() computes a random delay between min_delay and max_delay using:
get_random_u32() * (max_delay - min_delay) >> 32
This overflows signed 64-bit arithmetic when the delay range exceeds approximately 2.1 seconds (2^31 nanoseconds), producing a negative result that effectively disables slot-based pacing. This is a realistic configuration for WAN emulation (e.g., slot 1s 5s).
Use mul_u64_u32_shr() which handles the widening multiply without overflow.
--- net/sched/sch_netem.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
net/sched/sch_netem.c +2 -3
@@ -659,9 +659,8 @@ static void get_slot_next(struct netem_sched_data *q, u64 now)if (!q->slot_dist) next_delay = q->slot_config.min_delay + - (get_random_u32 () * - (q->slot_config.max_delay - - q->slot_config.min_delay) >>32 ); +mul_u64_u32_shr (q->slot_config.max_delay - q->slot_config.min_delay, +get_random_u32 (),32 );else next_delay = tabledist(q->slot_config.dist_delay, (s32)(q->slot_config.dist_jitter),
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 933/1146 net/sched: netem: check for negative latency and jitter
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephen Hemminger <[email protected]>
[ Upstream commit 90be9fedb218ee95a1cf59050d1306fbfb0e8b87 ]
Reject requests with negative latency or jitter.
A negative value added to current timestamp (u64) wraps
to an enormous time_to_send, disabling dequeue.
The original UAPI used u32 for these values; the conversion to 64-bit time values via TCA_NETEM_LATENCY64 and TCA_NETEM_JITTER64 allowed signed values to reach the kernel without validation.
Jitter is already silently clamped by an abs() in netem_change(); that abs() can be removed in a follow-up once this rejection is in place.
--- net/sched/sch_netem.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
net/sched/sch_netem.c +22 -0
@@ -826,6 +826,16 @@ static int get_dist_table(struct disttable **tbl, const struct nlattr *attr)return 0 ; } +static int validate_time (const struct nlattr *attr,const char *name, +struct netlink_ext_ack *extack) +{ +if (nla_get_s64 (attr) <0 ) { +NL_SET_ERR_MSG_ATTR_FMT (extack, attr,"negative %s" , name); +return -EINVAL ; + } +return 0 ; +} +static int validate_slot (const struct nlattr *attr,struct netlink_ext_ack *extack) {const struct tc_netem_slot *c =nla_data (attr);
@@ -1068,6 +1078,18 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, goto table_free; } +if (tb[TCA_NETEM_LATENCY64 ]) { + ret =validate_time (tb[TCA_NETEM_LATENCY64 ],"latency" , extack); +if (ret) + goto table_free; + } + +if (tb[TCA_NETEM_JITTER64 ]) { + ret =validate_time (tb[TCA_NETEM_JITTER64 ],"jitter" , extack); +if (ret) + goto table_free; + } +sch_tree_lock (sch);/* backup q->clg and q->loss_model */ old_clg = q->clg;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 934/1146 net: airoha: fix BQL imbalance in TX path
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <[email protected]>
[ Upstream commit 2d9f5a118205da2683ffcec78b9347f1f01a820e ]
Fix a possible BQL imbalance in airoha_dev_xmit(), where inflight packets are accounted only for the AIROHA_NUM_TX_RING netdev TX queues. The queue index is computed as:
qid = skb_get_queue_mapping(skb) % ARRAY_SIZE(qdma->q_tx)
txq = netdev_get_tx_queue(dev, qid);However, airoha_qdma_tx_napi_poll() accounts completions across all netdev TX queues (num_tx_queues), leading to inconsistent BQL accounting.
Also reset all netdev TX queues in the ndo_stop callback.
--- drivers/net/ethernet/airoha/airoha_eth.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
drivers/net/ethernet/airoha/airoha_eth.c +3 -4
@@ -929,10 +929,9 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget) q->queued--;if (skb) { -u16 queue =skb_get_queue_mapping (skb);struct netdev_queue *txq; - txq =netdev_get_tx_queue (skb->dev, queue); + txq =skb_get_tx_queue (skb->dev, skb);netdev_tx_completed_queue (txq,1 , skb->len);dev_kfree_skb_any (skb); }
@@ -1735,7 +1734,7 @@ static int airoha_dev_stop(struct net_device *dev)if (err)return err; -for (i =0 ; i <ARRAY_SIZE (qdma->q_tx); i++) +for (i =0 ; i < dev->num_tx_queues; i++)netdev_tx_reset_subqueue (dev, i);if (atomic_dec_and_test (&qdma->users)) {
@@ -2037,7 +2036,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,spin_lock_bh (&q->lock); - txq =netdev_get_tx_queue (dev, qid); + txq =skb_get_tx_queue (dev, skb); nr_frags =1 +skb_shinfo (skb)->nr_frags;if (q->queued + nr_frags >= q->ndesc) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 935/1146 net: airoha: stop net_device TX queue before updating CPU index
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <[email protected]>
[ Upstream commit 3854de7b38be742cf7558476956d12414cb274f2 ]
Currently, airoha_eth driver updates the CPU index register prior of verifying whether the number of free descriptors has fallen below the threshold.
Move net_device TX queue length check before updating the TX CPU index in order to update TX CPU index even if there are more packets to be transmitted but the net_device TX queue is going to be stopped accounting the inflight packets.
--- drivers/net/ethernet/airoha/airoha_eth.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
drivers/net/ethernet/airoha/airoha_eth.c +4 -5
@@ -2092,17 +2092,16 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,skb_tx_timestamp (skb);netdev_tx_sent_queue (txq, skb->len); +if (q->ndesc - q->queued < q->free_thr) { +netif_tx_stop_queue (txq); + q->txq_stopped = true; + }if (netif_xmit_stopped (txq) || !netdev_xmit_more ())airoha_qdma_rmw (qdma,REG_TX_CPU_IDX (qid),TX_RING_CPU_IDX_MASK ,FIELD_PREP (TX_RING_CPU_IDX_MASK , index)); -if (q->ndesc - q->queued < q->free_thr) { -netif_tx_stop_queue (txq); - q->txq_stopped = true; - } -spin_unlock_bh (&q->lock);return NETDEV_TX_OK ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 936/1146 net: airoha: fix typo in function name
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhengping Zhang <[email protected]>
[ Upstream commit aebf15e8eb09b01e99f043e9f5d423798aac9d32 ]
Corrected the typo in the function name from
airhoa_is_lan_gdm_port to airoha_is_lan_gdm_port. This change ensures consistency in the API naming convention.
Stable-dep-of: e070aac63b42 ("net: airoha: Do not wake all netdev TX queues in airoha_qdma_wake_netdev_txqs()")
--- drivers/net/ethernet/airoha/airoha_eth.c | 2 +- drivers/net/ethernet/airoha/airoha_eth.h | 2 +- drivers/net/ethernet/airoha/airoha_ppe.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-)
drivers/net/ethernet/airoha/airoha_eth.c +1 -1
@@ -76,7 +76,7 @@ static void airoha_set_macaddr(struct airoha_gdm_port *port, const u8 *addr)struct airoha_eth *eth = port->qdma->eth;u32 val, reg; - reg =airhoa_is_lan_gdm_port (port) ?REG_FE_LAN_MAC_H + reg =airoha_is_lan_gdm_port (port) ?REG_FE_LAN_MAC_H :REG_FE_WAN_MAC_H ; val = (addr[0 ] <<16 ) | (addr[1 ] <<8 ) | addr[2 ];airoha_fe_wr (eth, reg, val);
drivers/net/ethernet/airoha/airoha_eth.h +1 -1
@@ -630,7 +630,7 @@ u32 airoha_rmw(void __iomem *base, u32 offset, u32 mask, u32 val);#define airoha_qdma_clear (qdma, offset, val) \ airoha_rmw((qdma)->regs, (offset), (val), 0) -static inline bool airhoa_is_lan_gdm_port (struct airoha_gdm_port *port) +static inline bool airoha_is_lan_gdm_port (struct airoha_gdm_port *port) {/* GDM1 port on EN7581 SoC is connected to the lan dsa switch. * GDM{2,3,4} can be used as wan port connected to an external
drivers/net/ethernet/airoha/airoha_ppe.c +1 -1
@@ -331,7 +331,7 @@ static int airoha_ppe_foe_entry_prepare(struct airoha_eth *eth,/* For downlink traffic consume SRAM memory for hw * forwarding descriptors queue. */ -if (airhoa_is_lan_gdm_port (port)) +if (airoha_is_lan_gdm_port (port)) val |=AIROHA_FOE_IB2_FAST_PATH ;if (dsa_port >=0 ) val |= FIELD_PREP(AIROHA_FOE_IB2_NBQ,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 937/1146 net: airoha: Do not wake all netdev TX queues in airoha_qdma_wake_netdev_txqs()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <[email protected]>
[ Upstream commit e070aac63b42bf81f4dc565f9f841ff47e6c992f ]
Do not wake every netdev TX queue across all ports sharing the QDMA running netif_tx_wake_all_queues routine in airoha_qdma_wake_netdev_txqs() but only the ones that are mapped the specific QDMA stopped hw TX queue. This patch can potentially avoid waking already stopped netdev TX queues that are mapped to a different QDMA hw TX queue.
Introduce airoha_qdma_get_txq utility routine.
--- drivers/net/ethernet/airoha/airoha_eth.c | 19 +++++++++++++++---- drivers/net/ethernet/airoha/airoha_eth.h | 5 +++++ 2 files changed, 20 insertions(+), 4 deletions(-)
drivers/net/ethernet/airoha/airoha_eth.c +15 -4
@@ -847,13 +847,24 @@ static void airoha_qdma_wake_netdev_txqs(struct airoha_queue *q) {struct airoha_qdma *qdma = q->qdma;struct airoha_eth *eth = qdma->eth; -int i; +int i, qid = q - &qdma->q_tx[0 ];for (i =0 ; i <ARRAY_SIZE (eth->ports); i++) {struct airoha_gdm_port *port = eth->ports[i]; +int j; + +if (!port) +continue ; -if (port && port->qdma == qdma) -netif_tx_wake_all_queues (port->dev); +if (port->qdma != qdma) +continue ; + +for (j =0 ; j < port->dev->num_tx_queues; j++) { +if (airoha_qdma_get_txq (qdma, j) != qid) +continue ; + +netif_wake_subqueue (port->dev, j); + } } q->txq_stopped = false; }
@@ -1999,7 +2010,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,u16 index;u8 fport; - qid =skb_get_queue_mapping (skb) %ARRAY_SIZE (qdma->q_tx); + qid =airoha_qdma_get_txq (qdma,skb_get_queue_mapping (skb)); tag =airoha_get_dsa_tag (skb, dev); msg0 = FIELD_PREP(QDMA_ETH_TXMSG_CHAN_MASK,
drivers/net/ethernet/airoha/airoha_eth.h +5 -0
@@ -630,6 +630,11 @@ u32 airoha_rmw(void __iomem *base, u32 offset, u32 mask, u32 val);#define airoha_qdma_clear (qdma, offset, val) \ airoha_rmw((qdma)->regs, (offset), (val), 0) +static inline u16 airoha_qdma_get_txq (struct airoha_qdma *qdma,u16 qid) +{ +return qid %ARRAY_SIZE (qdma->q_tx); +} +static inline bool airoha_is_lan_gdm_port (struct airoha_gdm_port *port) {/* GDM1 port on EN7581 SoC is connected to the lan dsa switch.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 938/1146 net: airoha: Do not read uninitialized fragment address in airoha_dev_xmit()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <[email protected]>
[ Upstream commit bde34e84edc8b5571fbde7e941e175a4293ee1eb ]
The transmit loop in airoha_dev_xmit() reads fragment address and length during its final iteration, when the loop index equals skb_shinfo(skb)->nr_frags, at which point the fragment data is uninitialized. While these values are never consumed, the read itself is unsafe and may trigger a page fault. Fix this by avoiding the fragment read on the last iteration.
Additionally, move the skb pointer from the first to the last used packet descriptor, so that airoha_qdma_tx_napi_poll() defers freeing the skb until the final descriptor is processed.
--- drivers/net/ethernet/airoha/airoha_eth.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
drivers/net/ethernet/airoha/airoha_eth.c +6 -3
@@ -2005,8 +2005,8 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,struct netdev_queue *txq;struct airoha_queue *q;LIST_HEAD (tx_list); +int i =0 , qid;void *data; -int i, qid;u16 index;u8 fport;
@@ -2065,7 +2065,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, list); index = e - q->entry; -for (i =0 ; i < nr_frags; i++) { +while (true) {struct airoha_qdma_desc *desc = &q->desc[index];skb_frag_t *frag = &skb_shinfo (skb)->frags[i];dma_addr_t addr;
@@ -2077,7 +2077,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, goto error_unmap;list_move_tail (&e->list, &tx_list); - e->skb = i ?NULL : skb; + e->skb = i == nr_frags -1 ? skb :NULL ; e->dma_addr = addr; e->dma_len = len;
@@ -2096,6 +2096,9 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,WRITE_ONCE (desc->msg1,cpu_to_le32 (msg1));WRITE_ONCE (desc->msg2,cpu_to_le32 (0xffff )); +if (++i == nr_frags) +break ; + data =skb_frag_address (frag); len =skb_frag_size (frag); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 939/1146 net/sched: sch_choke: annotate data-races in choke_dump_stats()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit d3aeb889dcbd78e95f500d383799a23d949796e0 ]
choke_dump_stats() only runs with RTNL held. It reads fields that can be changed in qdisc fast path. Add READ_ONCE()/WRITE_ONCE() annotations.
--- net/sched/sch_choke.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-)
net/sched/sch_choke.c +16 -10
@@ -229,7 +229,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch,/* Draw a packet at random from queue and compare flow */ if (choke_match_random (q, skb, &idx)) { - q->stats.matched++; +WRITE_ONCE (q->stats.matched, q->stats.matched +1 );choke_drop_by_idx (sch, idx, to_free); goto congestion_drop; }
@@ -241,11 +241,13 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch,qdisc_qstats_overlimit (sch);if (use_harddrop (q) || !use_ecn (q) || !INET_ECN_set_ce (skb)) { - q->stats.forced_drop++; +WRITE_ONCE (q->stats.forced_drop, + q->stats.forced_drop +1 ); goto congestion_drop; } - q->stats.forced_mark++; +WRITE_ONCE (q->stats.forced_mark, + q->stats.forced_mark +1 ); }else if (++q->vars.qcount) {if (red_mark_probability (p, &q->vars, q->vars.qavg)) { q->vars.qcount =0 ;
@@ -253,11 +255,13 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch,qdisc_qstats_overlimit (sch);if (!use_ecn (q) || !INET_ECN_set_ce (skb)) { - q->stats.prob_drop++; +WRITE_ONCE (q->stats.prob_drop, + q->stats.prob_drop +1 ); goto congestion_drop; } - q->stats.prob_mark++; +WRITE_ONCE (q->stats.prob_mark, + q->stats.prob_mark +1 ); } }else q->vars.qR =red_random (p);
@@ -272,7 +276,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch,return NET_XMIT_SUCCESS ; } - q->stats.pdrop++; +WRITE_ONCE (q->stats.pdrop, q->stats.pdrop +1 );return qdisc_drop (skb, sch, to_free); congestion_drop:
@@ -461,10 +465,12 @@ static int choke_dump_stats(struct Qdisc *sch, struct gnet_dump *d) {struct choke_sched_data *q =qdisc_priv (sch);struct tc_choke_xstats st = { - .early = q->stats.prob_drop + q->stats.forced_drop, - .marked = q->stats.prob_mark + q->stats.forced_mark, - .pdrop = q->stats.pdrop, - .matched = q->stats.matched, + .early =READ_ONCE (q->stats.prob_drop) + +READ_ONCE (q->stats.forced_drop), + .marked =READ_ONCE (q->stats.prob_mark) + +READ_ONCE (q->stats.forced_mark), + .pdrop =READ_ONCE (q->stats.pdrop), + .matched =READ_ONCE (q->stats.matched), };return gnet_stats_copy_app (d, &st,sizeof (st));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 940/1146 net/sched: sch_fq_pie: annotate data-races in fq_pie_dump_stats()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 59b145771c7982cfe9020d4e9e22da92d6b5ae31 ]
fq_codel_dump_stats() acquires the qdisc spinlock a bit too late.
Move this acquisition before we fill tc_fq_pie_xstats with live data.
Alternative would be to add READ_ONCE() and WRITE_ONCE() annotations, but the spinlock is needed anyway to scan q->new_flows and q->old_flows.
--- net/sched/sch_fq_pie.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-)
net/sched/sch_fq_pie.c +10 -9
@@ -509,18 +509,19 @@ static int fq_pie_dump(struct Qdisc *sch, struct sk_buff *skb)static int fq_pie_dump_stats (struct Qdisc *sch,struct gnet_dump *d) {struct fq_pie_sched_data *q =qdisc_priv (sch); -struct tc_fq_pie_xstats st = { - .packets_in = q->stats.packets_in, - .overlimit = q->stats.overlimit, - .overmemory = q->overmemory, - .dropped = q->stats.dropped, - .ecn_mark = q->stats.ecn_mark, - .new_flow_count = q->new_flow_count, - .memory_usage = q->memory_usage, - }; +struct tc_fq_pie_xstats st = {0 };struct list_head *pos;sch_tree_lock (sch); + + st.packets_in = q->stats.packets_in; + st.overlimit = q->stats.overlimit; + st.overmemory = q->overmemory; + st.dropped = q->stats.dropped; + st.ecn_mark = q->stats.ecn_mark; + st.new_flow_count = q->new_flow_count; + st.memory_usage = q->memory_usage; +list_for_each (pos, &q->new_flows) st.new_flows_len++;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 941/1146 vrf: Fix a potential NPD when removing a port from a VRF
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ido Schimmel <[email protected]>
[ Upstream commit 2674d603a9e6970463b2b9ebcf8e31e90beae169 ]
RCU readers that identified a net device as a VRF port using netif_is_l3_slave() assume that a subsequent call to netdev_master_upper_dev_get_rcu() will return a VRF device. They then continue to dereference its l3mdev operations.
This assumption is not always correct and can result in a NPD [1]. There is no RCU synchronization when removing a port from a VRF, so it is possible for an RCU reader to see a new master device (e.g., a bridge) that does not have l3mdev operations.
Fix by adding RCU synchronization after clearing the IFF_L3MDEV_SLAVE flag. Skip this synchronization when a net device is removed from a VRF as part of its deletion and when the VRF device itself is deleted. In the latter case an RCU grace period will pass by the time RTNL is released.
[1]
BUG: kernel NULL pointer dereference, address: 0000000000000000 [...] RIP: 0010:l3mdev_fib_table_rcu (net/l3mdev/l3mdev.c:181) [...] Call Trace: <TASK> l3mdev_fib_table_by_index (net/l3mdev/l3mdev.c:201 net/l3mdev/l3mdev.c:189) __inet_bind (net/ipv4/af_inet.c:499 (discriminator 3)) inet_bind_sk (net/ipv4/af_inet.c:469) __sys_bind (./include/linux/file.h:62 (discriminator 1) ./include/linux/file.h:83 (discriminator 1) net/socket.c:1951 (discriminator 1)) __x64_sys_bind (net/socket.c:1969 (discriminator 1) net/socket.c:1967 (discriminator 1) net/socket.c:1967 (discriminator 1)) do_syscall_64 (arch/x86/entry/syscall_64.c:63 (discriminator 1) arch/x86/entry/syscall_64.c:94 (discriminator 1))
entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130)
--- drivers/net/vrf.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-)
drivers/net/vrf.c +11 -4
@@ -1084,6 +1084,7 @@ static int do_vrf_add_slave(struct net_device *dev, struct net_device *port_dev, err: port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE ; +synchronize_net ();return ret; }
@@ -1103,10 +1104,16 @@ static int vrf_add_slave(struct net_device *dev, struct net_device *port_dev, }/* inverse of do_vrf_add_slave */ -static int do_vrf_del_slave (struct net_device *dev,struct net_device *port_dev) +static int do_vrf_del_slave (struct net_device *dev,struct net_device *port_dev, +bool needs_sync) {netdev_upper_dev_unlink (port_dev, dev); port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE ; +/* Make sure that concurrent RCU readers that identified the device +* as a VRF port see a VRF master or no master at all. +*/ +if (needs_sync) +synchronize_net ();cycle_netdev (port_dev,NULL );
@@ -1115,7 +1122,7 @@ static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev)static int vrf_del_slave (struct net_device *dev,struct net_device *port_dev) { -return do_vrf_del_slave (dev, port_dev); +return do_vrf_del_slave (dev, port_dev, true); }static void vrf_dev_uninit (struct net_device *dev)
@@ -1669,7 +1676,7 @@ static void vrf_dellink(struct net_device *dev, struct list_head *head)struct list_head *iter;netdev_for_each_lower_dev (dev, port_dev, iter) -vrf_del_slave (dev, port_dev); +do_vrf_del_slave (dev, port_dev, false);vrf_map_unregister_dev (dev);
@@ -1801,7 +1808,7 @@ static int vrf_device_event(struct notifier_block *unused, goto out; vrf_dev =netdev_master_upper_dev_get (dev); -vrf_del_slave (vrf_dev, dev); +do_vrf_del_slave (vrf_dev, dev, false); } out:return NOTIFY_DONE ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 942/1146 net: usb: rtl8150: fix use-after-free in rtl8150_start_xmit()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhan Jun <[email protected]>
[ Upstream commit 23f0e34c64acba15cad4d23e50f41f533da195fa ]
syzbot reported a KASAN slab-use-after-free read in rtl8150_start_xmit() when accessing skb->len for tx statistics after usb_submit_urb() has been called:
BUG: KASAN: slab-use-after-free in rtl8150_start_xmit+0x71f/0x760
drivers/net/usb/rtl8150.c:712
Read of size 4 at addr ffff88810eb7a930 by task kworker/0:4/5226The URB completion handler write_bulk_callback() frees the skb via dev_kfree_skb_irq(dev->tx_skb). The URB may complete on another CPU in softirq context before usb_submit_urb() returns in the submitter, so by the time the submitter reads skb->len the skb has already been queued to the per-CPU completion_queue and freed by net_tx_action():
CPU A (xmit) CPU B (USB completion softirq)
------------ ------------------------------
dev->tx_skb = skb;
usb_submit_urb() --+
|-------> write_bulk_callback()
| dev_kfree_skb_irq(dev->tx_skb)
| net_tx_action()
| napi_skb_cache_put() <-- free
netdev->stats.tx_bytes |
+= skb->len; <-- UAF readFix it by caching skb->len before submitting the URB and using the cached value when updating the tx_bytes counter.
The pre-existing tx_bytes semantics are preserved: the counter tracks the original frame length (skb->len), not the ETH_ZLEN/USB-alignment padded "count" value that is handed to the device. Changing that would be a user-visible accounting change and is out of scope for this UAF fix.
--- drivers/net/usb/rtl8150.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/net/usb/rtl8150.c +4 -1
@@ -683,6 +683,7 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev) {rtl8150_t *dev =netdev_priv (netdev); +unsigned int skb_len;int count, res;/* pad the frame and ensure terminating USB packet, datasheet 9.2.3 */
@@ -694,6 +695,8 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb,return NETDEV_TX_OK ; } + skb_len = skb->len; +netif_stop_queue (netdev); dev->tx_skb = skb; usb_fill_bulk_urb(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2),
@@ -709,7 +712,7 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, } }else { netdev->stats.tx_packets++; - netdev->stats.tx_bytes += skb->len; + netdev->stats.tx_bytes += skb_len;netif_trans_update (netdev); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 943/1146 net: usb: rtl8150: free skb on usb_submit_urb() failure in xmit
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Morduan Zang <[email protected]>
[ Upstream commit adbe2cdf75461891e50dbe11896ac78e9af1f874 ]
When rtl8150_start_xmit() fails to submit the tx URB, the URB is never handed to the USB core and write_bulk_callback() will not run. The driver returns NETDEV_TX_OK, which tells the networking stack that the skb has been consumed, but nothing actually frees the skb on this error path:
dev->tx_skb = skb;
...
if ((res = usb_submit_urb(dev->tx_urb, GFP_ATOMIC))) {
...
/* no kfree_skb here */
}
return NETDEV_TX_OK;This leaks the skb on every submit failure and also leaves dev->tx_skb pointing at memory that the driver itself may later free, which is fragile.
Free the skb with dev_kfree_skb_any() in the error path and clear dev->tx_skb so no stale pointer is left behind.
--- drivers/net/usb/rtl8150.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/net/usb/rtl8150.c +7 -0
@@ -710,6 +710,13 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, netdev->stats.tx_errors++;netif_start_queue (netdev); } +/* +* The URB was not submitted, so write_bulk_callback() will +* never run to free dev->tx_skb. Drop the skb here and +* clear tx_skb to avoid leaving a stale pointer. +*/ + dev->tx_skb =NULL ; +dev_kfree_skb_any (skb); }else { netdev->stats.tx_packets++; netdev->stats.tx_bytes += skb_len;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 944/1146 spi: amlogic-spisg: initialize completion before requesting IRQ
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Gu <[email protected]>
[ Upstream commit 8d0189c1ea98b56481eb809e3d1bdbf85557e819 ]
Move init_completion(&spisg->completion) to before devm_request_irq() to avoid a potential race condition where an interrupt could fire before the completion structure is initialized.
--- drivers/spi/spi-amlogic-spisg.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/spi/spi-amlogic-spisg.c +1 -2
@@ -794,6 +794,7 @@ static int aml_spisg_probe(struct platform_device *pdev)dma_set_max_seg_size (&pdev->dev,SPISG_BLOCK_MAX ); +init_completion (&spisg->completion); ret =devm_request_irq (&pdev->dev, irq, aml_spisg_irq,0 ,NULL , spisg);if (ret) {dev_err (&pdev->dev,"irq request failed\n" );
@@ -806,8 +807,6 @@ static int aml_spisg_probe(struct platform_device *pdev) goto out_clk; } -init_completion (&spisg->completion); -pm_runtime_put (&spisg->pdev->dev);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 945/1146 NFC: trf7970a: Ignore antenna noise when checking for RF field
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paul Geurts <[email protected]>
[ Upstream commit a9bc28aa4e64320668131349436a650bf42591a5 ]
The main channel Received Signal Strength Indicator (RSSI) measurement is used to determine whether an RF field is present or not. RSSI != 0 is interpreted as an RF Field is present. This does not take RF noise and measurement inaccuracy into account, and results in false positives in the field.
Define a noise level and make sure the RF field is only interpreted as present when the RSSI is above the noise level.
--- drivers/nfc/trf7970a.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/nfc/trf7970a.c +2 -1
@@ -317,6 +317,7 @@#define TRF7970A_RSSI_OSC_STATUS_RSSI_MASK (BIT(2) | BIT(1) | BIT(0))#define TRF7970A_RSSI_OSC_STATUS_RSSI_X_MASK (BIT(5) | BIT(4) | BIT(3))#define TRF7970A_RSSI_OSC_STATUS_RSSI_OSC_OK BIT(6) +#define TRF7970A_RSSI_OSC_STATUS_RSSI_NOISE_LEVEL 1#define TRF7970A_SPECIAL_FCN_REG1_COL_7_6 BIT(0)#define TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL BIT(1)
@@ -1300,7 +1301,7 @@ static int trf7970a_is_rf_field(struct trf7970a *trf, bool *is_rf_field)if (ret)return ret; -if (rssi &TRF7970A_RSSI_OSC_STATUS_RSSI_MASK ) +if ((rssi &TRF7970A_RSSI_OSC_STATUS_RSSI_MASK ) >TRF7970A_RSSI_OSC_STATUS_RSSI_NOISE_LEVEL ) *is_rf_field = true;else *is_rf_field = false;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 946/1146 net/sched: taprio: fix NULL pointer dereference in class dump
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
[ Upstream commit 3d07ca5c0fae311226f737963984bd94bb159a87 ]
When a TAPRIO child qdisc is deleted via RTM_DELQDISC, taprio_graft() is called with new == NULL and stores NULL into q->qdiscs[cl - 1]. Subsequent RTM_GETTCLASS dump operations walk all classes via taprio_walk() and call taprio_dump_class(), which calls taprio_leaf() returning the NULL pointer, then dereferences it to read child->handle, causing a kernel NULL pointer dereference.
The bug is reachable with namespace-scoped CAP_NET_ADMIN on any kernel with CONFIG_NET_SCH_TAPRIO enabled. On systems with unprivileged user namespaces enabled, an unprivileged local user can trigger a kernel panic by creating a taprio qdisc inside a new network namespace, grafting an explicit child qdisc, deleting it, and requesting a class dump. The RTM_GETTCLASS dump itself requires no capability.
Oops: general protection fault, probably for non-canonical address 0xdffffc0000000007: 0000 [#1] SMP KASAN NOPTI KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f] RIP: 0010:taprio_dump_class (net/sched/sch_taprio.c:2478) Call Trace: <TASK> tc_fill_tclass (net/sched/sch_api.c:1966) qdisc_class_dump (net/sched/sch_api.c:2326) taprio_walk (net/sched/sch_taprio.c:2514) tc_dump_tclass_qdisc (net/sched/sch_api.c:2352) tc_dump_tclass_root (net/sched/sch_api.c:2370) tc_dump_tclass (net/sched/sch_api.c:2431) rtnl_dumpit (net/core/rtnetlink.c:6864) netlink_dump (net/netlink/af_netlink.c:2325) rtnetlink_rcv_msg (net/core/rtnetlink.c:6959) netlink_rcv_skb (net/netlink/af_netlink.c:2550) </TASK>
Fix this by substituting &noop_qdisc when new is NULL in taprio_graft(), a common pattern used by other qdiscs (e.g., multiq_graft()) to ensure the q->qdiscs[] slots are never NULL. This makes control-plane dump paths safe without requiring individual NULL checks.
Since the data-plane paths (taprio_enqueue and taprio_dequeue_from_txq) previously had explicit NULL guards that would drop/skip the packet cleanly, update those checks to test for &noop_qdisc instead. Without this, packets would reach taprio_enqueue_one() which increments the root qdisc's qlen and backlog before calling the child's enqueue; noop_qdisc drops the packet but those counters are never rolled back, permanently inflating the root qdisc's statistics.
After this change *old can be a valid qdisc, NULL, or &noop_qdisc. Only call qdisc_put(*old) in the first case to avoid decreasing noop_qdisc's refcount, which was never increased.
--- net/sched/sch_taprio.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
net/sched/sch_taprio.c +8 -5
@@ -634,7 +634,7 @@ static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch, queue =skb_get_queue_mapping (skb); child = q->qdiscs[queue]; -if (unlikely (!child)) +if (unlikely (child == &noop_qdisc))return qdisc_drop (skb, sch, to_free);if (taprio_skb_exceeds_queue_max_sdu (sch, skb)) {
@@ -717,7 +717,7 @@ static struct sk_buff *taprio_dequeue_from_txq(struct Qdisc *sch, int txq,int len;u8 tc; -if (unlikely (!child)) +if (unlikely (child == &noop_qdisc))return NULL ;if (TXTIME_ASSIST_IS_ENABLED (q->flags))
@@ -2184,6 +2184,9 @@ static int taprio_graft(struct Qdisc *sch, unsigned long cl,if (!dev_queue)return -EINVAL ; +if (!new) + new = &noop_qdisc; +if (dev->flags &IFF_UP )dev_deactivate (dev);
@@ -2197,14 +2200,14 @@ static int taprio_graft(struct Qdisc *sch, unsigned long cl, *old = q->qdiscs[cl -1 ];if (FULL_OFFLOAD_IS_ENABLED (q->flags)) {WARN_ON_ONCE (dev_graft_qdisc (dev_queue, new) != *old); -if (new) +if (new != &noop_qdisc)qdisc_refcount_inc (new); -if (*old) +if (*old && *old != &noop_qdisc)qdisc_put (*old); } q->qdiscs[cl -1 ] = new; -if (new) +if (new != &noop_qdisc) new->flags |=TCQ_F_ONETXQUEUE |TCQ_F_NOPARENT ;if (dev->flags &IFF_UP )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 947/1146 net: phonet: do not BUG_ON() in pn_socket_autobind() on failed bind
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Morduan Zang <[email protected]>
[ Upstream commit 5b0c911bcdbd982f7748d11c0b39ec5808eae2de ]
syzbot reported a kernel BUG triggered from pn_socket_sendmsg() via pn_socket_autobind():
kernel BUG at net/phonet/socket.c:213!
RIP: 0010:pn_socket_autobind net/phonet/socket.c:213 [inline] RIP: 0010:pn_socket_sendmsg+0x240/0x250 net/phonet/socket.c:421 Call Trace: sock_sendmsg_nosec+0x112/0x150 net/socket.c:797 __sock_sendmsg net/socket.c:812 [inline] __sys_sendto+0x402/0x590 net/socket.c:2280 ...
pn_socket_autobind() calls pn_socket_bind() with port 0 and, on -EINVAL, assumes the socket was already bound and asserts that the port is non-zero:
err = pn_socket_bind(sock, ..., sizeof(struct sockaddr_pn));
if (err != -EINVAL)
return err;
BUG_ON(!pn_port(pn_sk(sock->sk)->sobject));
return 0; /* socket was already bound */However pn_socket_bind() also returns -EINVAL when sk->sk_state is not TCP_CLOSE, even when the socket has never been bound and pn_port() is still 0. In that case the BUG_ON() fires and panics the kernel from a user-triggerable path.
Treat the "bind returned -EINVAL but pn_port() is still 0" case as a regular error and propagate -EINVAL to the caller instead of crashing. Existing callers already translate a non-zero return from pn_socket_autobind() into -ENOBUFS/-EAGAIN, so returning -EINVAL here only changes behaviour from panic to a normal errno.
--- net/phonet/socket.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
net/phonet/socket.c +8 -2
@@ -208,9 +208,15 @@ static int pn_socket_autobind(struct socket *sock) sa.spn_family =AF_PHONET ; err =pn_socket_bind (sock, (struct sockaddr_unsized *)&sa,sizeof (struct sockaddr_pn )); -if (err != -EINVAL ) +/* +* pn_socket_bind() also returns -EINVAL when sk_state != TCP_CLOSE +* without a prior bind, so -EINVAL alone is not sufficient to infer +* that the socket was already bound. Only treat it as "already +* bound" when the port is non-zero; otherwise propagate the error +* instead of crashing the kernel. +*/ +if (err != -EINVAL ||unlikely (!pn_port (pn_sk (sock->sk)->sobject)))return err; -BUG_ON (!pn_port (pn_sk (sock->sk)->sobject));return 0 ;/* socket was already bound */ }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 948/1146 neigh: let neigh_xmit take skb ownership
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit 4438113be604ee67a7bf4f81da6e1cca41332ce4 ]
neigh_xmit always releases the skb, except when no neighbour table is found. But even the first added user of neigh_xmit (mpls) relied on neigh_xmit to release the skb (or queue it for tx).
sashiko reported:
If neigh_xmit() is called with an uninitialized neighbor table (for example, NEIGH_ND_TABLE when IPv6 is disabled), it returns -EAFNOSUPPORT and bypasses its internal out_kfree_skb error path. Because the return value of neigh_xmit() is ignored here, does this leak the SKB?
Assume full ownership and remove the last code path that doesn't xmit or free skb.
--- net/core/neighbour.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
net/core/neighbour.c +5 -5
@@ -3211,8 +3211,10 @@ int neigh_xmit(int index, struct net_device *dev,rcu_read_lock (); tbl =rcu_dereference (neigh_tables[index]); -if (!tbl) - goto out_unlock; +if (!tbl) { +rcu_read_unlock (); + goto out_kfree_skb; + }if (index ==NEIGH_ARP_TABLE ) {u32 key = *((u32 *)addr);
@@ -3228,7 +3230,6 @@ int neigh_xmit(int index, struct net_device *dev, goto out_kfree_skb; } err =READ_ONCE (neigh->output)(neigh, skb); -out_unlock:rcu_read_unlock (); }else if (index ==NEIGH_LINK_TABLE ) {
@@ -3238,11 +3239,10 @@ int neigh_xmit(int index, struct net_device *dev, goto out_kfree_skb; err =dev_queue_xmit (skb); } -out:return err; out_kfree_skb:kfree_skb (skb); - goto out; +return err; }EXPORT_SYMBOL (neigh_xmit);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 949/1146 tcp: make probe0 timer handle expired user timeout
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Altan Hacigumus <[email protected]>
[ Upstream commit 2b9f6f7065d4cfb65ba19126e0b35ac4544c3f3a ]
tcp_clamp_probe0_to_user_timeout() computes remaining time in jiffies using subtraction with an unsigned lvalue. If elapsed probing time exceeds the configured TCP_USER_TIMEOUT, the underflow yields a large value.
This ends up re-arming the probe timer for a full backoff interval instead of expiring immediately, delaying connection teardown beyond the configured timeout.
Fix this by preventing underflow so user-set timeout expiration is handled correctly without extending the probe timer.
--- net/ipv4/tcp_timer.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
net/ipv4/tcp_timer.c +3 -2
@@ -50,7 +50,8 @@ static u32 tcp_clamp_rto_to_user_timeout(const struct sock *sk)u32 tcp_clamp_probe0_to_user_timeout (const struct sock *sk,u32 when) {const struct inet_connection_sock *icsk =inet_csk (sk); -u32 remaining, user_timeout; +u32 user_timeout; +s32 remaining;s32 elapsed; user_timeout =READ_ONCE (icsk->icsk_user_timeout);
@@ -61,7 +62,7 @@ u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when)if (unlikely (elapsed <0 )) elapsed =0 ; remaining =msecs_to_jiffies (user_timeout) - elapsed; - remaining =max_t (u32, remaining,TCP_TIMEOUT_MIN ); + remaining =max_t (int, remaining,TCP_TIMEOUT_MIN );return min_t (u32, remaining, when); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 950/1146 netpoll: fix IPv6 local-address corruption
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit 3bc179bc7146c26c9dff75d2943d10528274e301 ]
netpoll_setup() decides whether to auto-populate the local source address by testing np->local_ip.ip, which only inspects the first 4 bytes of the union inet_addr storage.
For an IPv6 netpoll whose caller-supplied local address has a zero high-32 bits (::1, ::<suffix>, IPv4-mapped ::ffff:a.b.c.d, etc.), this misdetects the address as unset (which they are not, but the first 4 bytes are empty), calls netpoll_take_ipv6() and overwrites it with whatever matching link-local/global address the device happens to expose first.
Introduce a helper netpoll_local_ip_unset() that picks the correct family-aware test (ipv6_addr_any() for IPv6, !.ip for IPv4) and use it from netpoll_setup().
Reproducer is something like:
echo "::2" > local_ip
echo 1 > enabled
cat local_ip
# before this fix: 2001:db8::1 (caller-supplied ::2 was clobbered) # after this fix: ::2
--- net/core/netpoll.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-)
net/core/netpoll.c +18 -1
@@ -706,6 +706,23 @@ static int netpoll_take_ipv4(struct netpoll *np, struct net_device *ndev)return 0 ; } +/* +* Test whether the caller left np->local_ip unset, so that +* netpoll_setup() should auto-populate it from the egress device. +* +* np->local_ip is a union of __be32 (IPv4) and struct in6_addr (IPv6), +* so an IPv6 address whose first 4 bytes are zero (e.g. ::1, ::2, +* IPv4-mapped ::ffff:a.b.c.d) must not be tested via the IPv4 arm — +* doing so would misclassify a caller-supplied address as unset and +* silently overwrite it with whatever address the device exposes. +*/ +static bool netpoll_local_ip_unset (const struct netpoll *np) +{ +if (np->ipv6) +return ipv6_addr_any (&np->local_ip.in6); +return !np->local_ip.ip; +} +int netpoll_setup (struct netpoll *np) {struct net *net = current->nsproxy->net_ns;
@@ -750,7 +767,7 @@ int netpoll_setup(struct netpoll *np)rtnl_lock (); } -if (!np->local_ip.ip) { +if (netpoll_local_ip_unset (np)) {if (!np->ipv6) { err =netpoll_take_ipv4 (np, ndev);if (err)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 951/1146 ALSA: usb-audio: Fix potential leak of pd at parsing UAC3 streams
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <[email protected]>
[ Upstream commit c39f0bc03f84ba64c9144c95714df1dc36150f6d ]
At parsing UAC3 streams, we allocate a PD object at each time, and either assign or free it. But there is a case where the PD object may be leaked; namely, in __snd_usb_parse_audio_interface() loop, when an audioformat shares the same endpoint with others, it's put to a link and returns from snd_usb_add_audio_stream(), but the PD is forgotten afterwards. Overall, the treatment of PD object in the parser code is a bit flaky, and we should be more careful about the object ownership.
This patch tries to fix the above case and improve the code a bit. The pd object is now managed with the auto-cleanup in the loop, and the ownership is updated when the pd object gets assigned to the stream, which guarantees the release of the leftover object.
--- sound/usb/quirks.c | 2 +- sound/usb/stream.c | 58 ++++++++++++++++++---------------------------- sound/usb/stream.h | 3 ++- 3 files changed, 25 insertions(+), 38 deletions(-)
sound/usb/quirks.c +1 -1
@@ -122,7 +122,7 @@ static int add_audio_stream_from_fixed_fmt(struct snd_usb_audio *chip,snd_usb_audioformat_set_sync_ep (chip, fp); - err =snd_usb_add_audio_stream (chip, stream, fp); + err =snd_usb_add_audio_stream (chip, stream, fp,NULL );if (err <0 )return err;
sound/usb/stream.c +22 -36
129 lines not on this page · raw message
sound/usb/stream.h +2 -1
@@ -7,7 +7,8 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip,int snd_usb_add_audio_stream (struct snd_usb_audio *chip,int stream, -struct audioformat *fp); +struct audioformat *fp, +struct snd_usb_power_domain **pdptr);#endif /* __USBAUDIO_STREAM_H */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 952/1146 sched/fair: Fix wakeup_preempt_fair() vs delayed dequeue
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vincent Guittot <[email protected]>
[ Upstream commit ac8e69e693631689d74d8f1ebee6f84f737f797f ]
Similar to how pick_next_entity() must dequeue delayed entities, so too must wakeup_preempt_fair(). Any delayed task being found means it is eligible and hence past the 0-lag point, ready for removal.
Worse, by not removing delayed entities from consideration, it can skew the preemption decision, with the end result that a short slice wakeup will not result in a preemption.
tip/sched/core tip/sched/core +this patch
cyclictest slice (ms) (default)2.8 8 8
hackbench slice (ms) (default)2.8 20 20
Total Samples | 22559 22595 22683 Average (us) | 157 64( 59%) 59( 8%) Median (P50) (us) | 57 57( 0%) 58(- 2%) 90th Percentile (us) | 64 60( 6%) 60( 0%) 99th Percentile (us) | 2407 67( 97%) 67( 0%) 99.9th Percentile (us) | 3400 2288( 33%) 727( 68%) Maximum (us) | 5037 9252(-84%) 7461( 19%)
--- kernel/sched/fair.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-)
kernel/sched/fair.c +14 -13
@@ -1007,7 +1007,7 @@ static inline void cancel_protect_slice(struct sched_entity *se)* * Which allows tree pruning through eligibility. */ -static struct sched_entity *__pick_eevdf (struct cfs_rq *cfs_rq,bool protect) +static struct sched_entity *pick_eevdf (struct cfs_rq *cfs_rq,bool protect) {struct rb_node *node = cfs_rq->tasks_timeline.rb_root.rb_node;struct sched_entity *se =__pick_first_entity (cfs_rq);
@@ -1078,11 +1078,6 @@ static struct sched_entity *__pick_eevdf(struct cfs_rq *cfs_rq, bool protect)return best; } -static struct sched_entity *pick_eevdf (struct cfs_rq *cfs_rq) -{ -return __pick_eevdf (cfs_rq, true); -} -struct sched_entity *__pick_last_entity (struct cfs_rq *cfs_rq) {struct rb_node *last =rb_last (&cfs_rq->tasks_timeline.rb_root);
@@ -5540,11 +5535,11 @@ static int dequeue_entities(struct rq *rq, struct sched_entity *se, int flags);* 4) do not run the "skip" process, if something else is available */ static struct sched_entity * -pick_next_entity (struct rq *rq,struct cfs_rq *cfs_rq) +pick_next_entity (struct rq *rq,struct cfs_rq *cfs_rq,bool protect) {struct sched_entity *se; - se =pick_eevdf (cfs_rq); + se =pick_eevdf (cfs_rq, protect);if (se->sched_delayed) {dequeue_entities (rq, se,DEQUEUE_SLEEP |DEQUEUE_DELAYED );/*
@@ -8809,7 +8804,7 @@ static void wakeup_preempt_fair(struct rq *rq, struct task_struct *p, int wake_f {enum preempt_wakeup_action preempt_action =PREEMPT_WAKEUP_PICK ;struct task_struct *donor = rq->donor; -struct sched_entity *se = &donor->se, *pse = &p->se; +struct sched_entity *nse, *se = &donor->se, *pse = &p->se;struct cfs_rq *cfs_rq =task_cfs_rq (donor);int cse_is_idle, pse_is_idle;
@@ -8920,11 +8915,17 @@ static void wakeup_preempt_fair(struct rq *rq, struct task_struct *p, int wake_f } pick: + nse =pick_next_entity (rq, cfs_rq, preempt_action !=PREEMPT_WAKEUP_SHORT ); +/* If @p has become the most eligible task, force preemption */ +if (nse == pse) + goto preempt; +/* -* If @p has become the most eligible task, force preemption. +* Because p is enqueued, nse being null can only mean that we +* dequeued a delayed task. */ -if (__pick_eevdf (cfs_rq, preempt_action !=PREEMPT_WAKEUP_SHORT ) == pse) - goto preempt; +if (!nse) + goto pick;if (sched_feat (RUN_TO_PARITY ))update_protect_slice (cfs_rq, se);
@@ -8959,7 +8960,7 @@ static struct task_struct *pick_task_fair(struct rq *rq, struct rq_flags *rf) throttled |=check_cfs_rq_runtime (cfs_rq); - se =pick_next_entity (rq, cfs_rq); + se =pick_next_entity (rq, cfs_rq, true);if (!se) goto again; cfs_rq =group_cfs_rq (se);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 953/1146 sched/fair: Clear rel_deadline when initializing forked entities
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zicheng Qu <[email protected]>
[ Upstream commit 3da56dc063cd77b9c0b40add930767fab4e389f3 ]
A yield-triggered crash can happen when a newly forked sched_entity enters the fair class with se->rel_deadline unexpectedly set.
The failing sequence is:
1. A task is forked while se->rel_deadline is still set.
2. __sched_fork() initializes vruntime, vlag and other sched_entity state, but does not clear rel_deadline.
3. On the first enqueue, enqueue_entity() calls place_entity().
4. Because se->rel_deadline is set, place_entity() treats se->deadline as a relative deadline and converts it to an absolute deadline by adding the current vruntime.
5. However, the forked entity's deadline is not a valid inherited relative deadline for this new scheduling instance, so the conversion produces an abnormally large deadline.
6. If the task later calls sched_yield(), yield_task_fair() advances
se->vruntime to se->deadline.
7. The inflated vruntime is then used by the following enqueue path, where the vruntime-derived key can overflow when multiplied by the entity weight.
8. This corrupts cfs_rq->sum_w_vruntime, breaks EEVDF eligibility calculation, and can eventually make all entities appear ineligible. pick_next_entity() may then return NULL unexpectedly, leading to a later NULL dereference.
A captured trace shows the effect clearly. Before yield, the entity's vruntime was around:
9834017729983308
After yield_task_fair() executed:
se->vruntime = se->deadline
the vruntime jumped to:
19668035460670230
and the deadline was later advanced further to:
19668035463470230
This shows that the deadline had already become abnormally large before yield_task_fair() copied it into vruntime.
rel_deadline is only meaningful when se->deadline really carries a relative deadline that still needs to be placed against vruntime. A freshly forked sched_entity should not inherit or retain this state. Clear se->rel_deadline in __sched_fork(), together with the other sched_entity runtime state, so that the first enqueue does not interpret the new entity's deadline as a stale relative deadline.
--- kernel/sched/core.c | 1 + 1 file changed, 1 insertion(+)
kernel/sched/core.c +1 -0
@@ -4398,6 +4398,7 @@ static void __sched_fork(u64 clone_flags, struct task_struct *p) p->se.nr_migrations =0 ; p->se.vruntime =0 ; p->se.vlag =0 ; + p->se.rel_deadline =0 ;INIT_LIST_HEAD (&p->se.group_node);/* A delayed task cannot be in clone(). */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 954/1146 net: mctp i2c: check length before marking flow active
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: William A. Kennington III <[email protected]>
[ Upstream commit 4ca07b9239bd0478ae586632a2ed72be37ed8407 ]
Currently, mctp_i2c_get_tx_flow_state() is called before the packet length sanity check. This function marks a new flow as active in the MCTP core.
If the sanity check fails, mctp_i2c_xmit() returns early without calling mctp_i2c_lock_nest(). This results in a mismatched locking state: the flow is active, but the I2C bus lock was never acquired for it.
When the flow is later released, mctp_i2c_release_flow() will see the active state and queue an unlock marker. The TX thread will then decrement midev->i2c_lock_count from 0, causing it to underflow to -1.
This underflow permanently breaks the driver's locking logic, allowing future transmissions to occur without holding the I2C bus lock, leading to bus collisions and potential hardware hangs.
Move the mctp_i2c_get_tx_flow_state() call to after the length sanity check to ensure we only transition the flow state if we are actually going to proceed with the transmission and locking.
--- drivers/net/mctp/mctp-i2c.c | 4 ++-- net/sched/cls_flower.c | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-)
drivers/net/mctp/mctp-i2c.c +2 -2
@@ -496,8 +496,6 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb)u8 *pecp;int rc; - fs =mctp_i2c_get_tx_flow_state (midev, skb); - hdr = (void *)skb_mac_header (skb);/* Sanity check that packet contents matches skb length, * and can't exceed MCTP_I2C_BUFSZ
@@ -509,6 +507,8 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb)return ; } + fs =mctp_i2c_get_tx_flow_state (midev, skb); +if (skb_tailroom (skb) >=1 ) {/* Linear case with space, we can just append the PEC */ skb_put (skb,1 );
net/sched/cls_flower.c +3 -1
@@ -560,6 +560,7 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, struct netlink_ext_ack *extack) {struct cls_fl_head *head =fl_head_dereference (tp); +struct fl_flow_mask *mask; *last = false;
@@ -576,11 +577,12 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f,list_del_rcu (&f->list);spin_unlock (&tp->lock); - *last =fl_mask_put (head, f->mask); + mask = f->mask;if (!tc_skip_hw (f->flags))fl_hw_destroy_filter (tp, f, rtnl_held, extack);tcf_unbind_filter (tp, &f->res);__fl_put (f); + *last =fl_mask_put (head, mask);return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 955/1146 md/raid1,raid10: dont fail devices for invalid IO errors
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Keith Busch <[email protected]>
[ Upstream commit f7b24c7b41f23b5f9caa8b913afe79cd4c397d39 ]
BLK_STS_INVAL indicates the IO request itself was invalid, not that the device has failed. When raid1 treats this as a device error, it retries on alternate mirrors which fail the same way, eventually exceeding the read error threshold and removing the device from the array.
This happens when stacking configurations bypass bio_split_to_limits() in the IO path: dm-raid calls md_handle_request() directly without going through md_submit_bio(), skipping the alignment validation that would otherwise reject invalid bios early. The invalid bio reaches the lower block layers, which fail the bio with BLK_STS_INVAL, and raid1 wrongly interprets this as a device failure.
Add BLK_STS_INVAL to raid1_should_handle_error() so that invalid IO errors are propagated back to the caller rather than triggering device removal. This is consistent with the previous kernel behavior when alignment checks were done earlier in the direct-io path.
--- drivers/md/raid1-10.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/md/raid1-10.c +6 -1
@@ -293,8 +293,13 @@ static inline bool raid1_should_read_first(struct mddev *mddev,* bio with REQ_RAHEAD or REQ_NOWAIT can fail at anytime, before such IO is * submitted to the underlying disks, hence don't record badblocks or retry * in this case. +* +* BLK_STS_INVAL means the bio was not valid for the underlying device. This +* is a user error, not a device failure, so retrying or recording bad blocks +* would be wrong. */ static inline bool raid1_should_handle_error (struct bio *bio) { -return !(bio->bi_opf & (REQ_RAHEAD |REQ_NOWAIT )); +return !(bio->bi_opf & (REQ_RAHEAD |REQ_NOWAIT )) && + bio->bi_status !=BLK_STS_INVAL ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 956/1146 md: add fallback to correct bitmap_ops on version mismatch
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yu Kuai <[email protected]>
[ Upstream commit 09af773650024279a60348e7319d599e6571b15c ]
If default bitmap version and on-disk version doesn't match, and mdadm is not the latest version to set bitmap_type, set bitmap_ops based on the disk version.
Stable-dep-of: f2926a533d03 ("md/md-bitmap: add a none backend for bitmap grow")
--- drivers/md/md.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 110 insertions(+), 1 deletion(-)
drivers/md/md.c +110 -1
@@ -6465,15 +6465,124 @@ static void md_safemode_timeout(struct timer_list *t)static int start_dirty_degraded; +/* +* Read bitmap superblock and return the bitmap_id based on disk version. +* This is used as fallback when default bitmap version and on-disk version +* doesn't match, and mdadm is not the latest version to set bitmap_type. +*/ +static enum md_submodule_id md_bitmap_get_id_from_sb (struct mddev *mddev) +{ +struct md_rdev *rdev; +struct page *sb_page; +bitmap_super_t *sb; +enum md_submodule_id id =ID_BITMAP_NONE ; +sector_t sector; +u32 version; + +if (!mddev->bitmap_info.offset) +return ID_BITMAP_NONE ; + + sb_page =alloc_page (GFP_KERNEL ); +if (!sb_page) { +pr_warn ("md: %s: failed to allocate memory for bitmap\n" , +mdname (mddev)); +return ID_BITMAP_NONE ; + } + + sector = mddev->bitmap_info.offset; + +rdev_for_each (rdev, mddev) { +u32 iosize; + +if (!test_bit (In_sync, &rdev->flags) || +test_bit (Faulty, &rdev->flags) || +test_bit (Bitmap_sync, &rdev->flags)) +continue ; + + iosize =roundup (sizeof (bitmap_super_t), +bdev_logical_block_size (rdev->bdev)); +if (sync_page_io (rdev, sector, iosize, sb_page,REQ_OP_READ , + true)) + goto read_ok; + } +pr_warn ("md: %s: failed to read bitmap from any device\n" , +mdname (mddev)); + goto out; + +read_ok: + sb =kmap_local_page (sb_page); +if (sb->magic !=cpu_to_le32 (BITMAP_MAGIC )) { +pr_warn ("md: %s: invalid bitmap magic 0x%x\n" , +mdname (mddev),le32_to_cpu (sb->magic)); + goto out_unmap; + } + + version =le32_to_cpu (sb->version); +switch (version) { +case BITMAP_MAJOR_LO : +case BITMAP_MAJOR_HI : +case BITMAP_MAJOR_CLUSTERED : + id =ID_BITMAP ; +break ; +case BITMAP_MAJOR_LOCKLESS : + id =ID_LLBITMAP ; +break ; +default : +pr_warn ("md: %s: unknown bitmap version %u\n" , +mdname (mddev), version); +break ; + } + +out_unmap: +kunmap_local (sb); +out: +__free_page (sb_page); +return id; +} +static int md_bitmap_create (struct mddev *mddev) { +enum md_submodule_id orig_id = mddev->bitmap_id; +enum md_submodule_id sb_id; +int err; +if (mddev->bitmap_id ==ID_BITMAP_NONE )return -EINVAL ;if (!mddev_set_bitmap_ops (mddev))return -ENOENT ; -return mddev->bitmap_ops->create (mddev); + err = mddev->bitmap_ops->create (mddev); +if (!err) +return 0 ; + +/* +* Create failed, if default bitmap version and on-disk version +* doesn't match, and mdadm is not the latest version to set +* bitmap_type, set bitmap_ops based on the disk version. +*/ +mddev_clear_bitmap_ops (mddev); + + sb_id =md_bitmap_get_id_from_sb (mddev); +if (sb_id ==ID_BITMAP_NONE || sb_id == orig_id) +return err; + +pr_info ("md: %s: bitmap version mismatch, switching from %d to %d\n" , +mdname (mddev), orig_id, sb_id); + + mddev->bitmap_id = sb_id; +if (!mddev_set_bitmap_ops (mddev)) { + mddev->bitmap_id = orig_id; +return -ENOENT ; + } + + err = mddev->bitmap_ops->create (mddev); +if (err) { +mddev_clear_bitmap_ops (mddev); + mddev->bitmap_id = orig_id; + } + +return err; }static void md_bitmap_destroy (struct mddev *mddev)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 957/1146 md: factor bitmap creation away from sysfs handling
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yu Kuai <[email protected]>
[ Upstream commit 8776d342cf8fa0b98ca5e6fb2d956966fb5ca364 ]
Factor bitmap creation and destruction into helpers that do not touch bitmap sysfs registration.
This prepares the bitmap sysfs rework so callers such as the sysfs bitmap location path can create or destroy a bitmap backend without coupling that to sysfs group lifetime management.
Stable-dep-of: f2926a533d03 ("md/md-bitmap: add a none backend for bitmap grow")
--- drivers/md/md.c | 78 +++++++++++++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 29 deletions(-)
drivers/md/md.c +49 -29
@@ -688,7 +688,25 @@ static void active_io_release(struct percpu_ref *ref)static void no_op (struct percpu_ref *r) {} -static bool mddev_set_bitmap_ops (struct mddev *mddev) +static void md_bitmap_sysfs_add (struct mddev *mddev) +{ +if (sysfs_create_group (&mddev->kobj, mddev->bitmap_ops->group)) +pr_warn ("md: cannot register extra bitmap attributes for %s\n" , +mdname (mddev)); +else +/* +* Inform user with KOBJ_CHANGE about new bitmap +* attributes. +*/ +kobject_uevent (&mddev->kobj,KOBJ_CHANGE ); +} + +static void md_bitmap_sysfs_del (struct mddev *mddev) +{ +sysfs_remove_group (&mddev->kobj, mddev->bitmap_ops->group); +} + +static bool mddev_set_bitmap_ops_nosysfs (struct mddev *mddev) {struct bitmap_operations *old = mddev->bitmap_ops;struct md_submodule_head *head;
@@ -712,18 +730,6 @@ static bool mddev_set_bitmap_ops(struct mddev *mddev) mddev->bitmap_ops = (void *)head;xa_unlock (&md_submodule); - -if (!mddev_is_dm (mddev) && mddev->bitmap_ops->group) { -if (sysfs_create_group (&mddev->kobj, mddev->bitmap_ops->group)) -pr_warn ("md: cannot register extra bitmap attributes for %s\n" , -mdname (mddev)); -else -/* -* Inform user with KOBJ_CHANGE about new bitmap -* attributes. -*/ -kobject_uevent (&mddev->kobj,KOBJ_CHANGE ); - }return true; err:
@@ -731,15 +737,6 @@ static bool mddev_set_bitmap_ops(struct mddev *mddev)return false; } -static void mddev_clear_bitmap_ops (struct mddev *mddev) -{ -if (!mddev_is_dm (mddev) && mddev->bitmap_ops && - mddev->bitmap_ops->group) -sysfs_remove_group (&mddev->kobj, mddev->bitmap_ops->group); - - mddev->bitmap_ops =NULL ; -} -int mddev_init (struct mddev *mddev) {int err =0 ;
@@ -6540,7 +6537,7 @@ static enum md_submodule_id md_bitmap_get_id_from_sb(struct mddev *mddev)return id; } -static int md_bitmap_create (struct mddev *mddev) +static int md_bitmap_create_nosysfs (struct mddev *mddev) {enum md_submodule_id orig_id = mddev->bitmap_id;enum md_submodule_id sb_id;
@@ -6549,7 +6546,7 @@ static int md_bitmap_create(struct mddev *mddev)if (mddev->bitmap_id ==ID_BITMAP_NONE )return -EINVAL ; -if (!mddev_set_bitmap_ops (mddev)) +if (!mddev_set_bitmap_ops_nosysfs (mddev))return -ENOENT ; err = mddev->bitmap_ops->create (mddev);
@@ -6561,7 +6558,7 @@ static int md_bitmap_create(struct mddev *mddev)* doesn't match, and mdadm is not the latest version to set * bitmap_type, set bitmap_ops based on the disk version. */ -mddev_clear_bitmap_ops (mddev); + mddev->bitmap_ops =NULL ; sb_id =md_bitmap_get_id_from_sb (mddev);if (sb_id ==ID_BITMAP_NONE || sb_id == orig_id)
@@ -6571,27 +6568,50 @@ static int md_bitmap_create(struct mddev *mddev) mdname(mddev), orig_id, sb_id); mddev->bitmap_id = sb_id; -if (!mddev_set_bitmap_ops (mddev)) { +if (!mddev_set_bitmap_ops_nosysfs (mddev)) { mddev->bitmap_id = orig_id;return -ENOENT ; } err = mddev->bitmap_ops->create (mddev);if (err) { -mddev_clear_bitmap_ops (mddev); + mddev->bitmap_ops =NULL ; mddev->bitmap_id = orig_id; }return err; } -static void md_bitmap_destroy (struct mddev *mddev) +static int md_bitmap_create (struct mddev *mddev) +{ +int err; + + err =md_bitmap_create_nosysfs (mddev); +if (err) +return err; + +if (!mddev_is_dm (mddev) && mddev->bitmap_ops->group) +md_bitmap_sysfs_add (mddev); + +return 0 ; +} + +static void md_bitmap_destroy_nosysfs (struct mddev *mddev) {if (!md_bitmap_registered (mddev))return ; mddev->bitmap_ops->destroy (mddev); -mddev_clear_bitmap_ops (mddev); + mddev->bitmap_ops =NULL ; +} + +static void md_bitmap_destroy (struct mddev *mddev) +{ +if (!mddev_is_dm (mddev) && mddev->bitmap_ops && + mddev->bitmap_ops->group) +md_bitmap_sysfs_del (mddev); + +md_bitmap_destroy_nosysfs (mddev); }int md_run (struct mddev *mddev)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 958/1146 md/md-bitmap: split bitmap sysfs groups
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yu Kuai <[email protected]>
[ Upstream commit aba3d6d6cb55c6e1116d1215140559dd7ecdf9a9 ]
Split the classic bitmap sysfs files into a common bitmap group with the location attribute and a separate internal bitmap group for the remaining files.
At the same time, convert bitmap operations from a single sysfs group to a sysfs group array so backends can share part of their sysfs layout while adding backend-specific attributes separately.
Switch the bitmap sysfs helpers to use sysfs_update_groups() for the add and update path, and remove groups in reverse order so shared named groups are unmerged before the last group removes the directory.
Also make bitmap operation lookup depend only on the currently selected bitmap id matching the installed backend. This prepares the lookup path for a later registered none backend.
Stable-dep-of: f2926a533d03 ("md/md-bitmap: add a none backend for bitmap grow")
--- drivers/md/md-bitmap.c | 23 +++++++++++++++++++---- drivers/md/md-bitmap.h | 2 +- drivers/md/md-llbitmap.c | 7 ++++++- drivers/md/md.c | 21 ++++++++++++++------- 4 files changed, 40 insertions(+), 13 deletions(-)
drivers/md/md-bitmap.c +19 -4
@@ -2955,8 +2955,12 @@ static struct md_sysfs_entry max_backlog_used =__ATTR (max_backlog_used,S_IRUGO |S_IWUSR , behind_writes_used_show, behind_writes_used_reset); -static struct attribute *md_bitmap_attrs[] = { +static struct attribute *md_bitmap_common_attrs[] = { &bitmap_location.attr, +NULL +}; + +static struct attribute *md_bitmap_internal_attrs[] = { &bitmap_space.attr, &bitmap_timeout.attr, &bitmap_backlog.attr,
@@ -2967,9 +2971,20 @@ static struct attribute *md_bitmap_attrs[] = {NULL }; -static struct attribute_group md_bitmap_group = { +static struct attribute_group md_bitmap_common_group = { + .name ="bitmap" , + .attrs = md_bitmap_common_attrs, +}; + +static struct attribute_group md_bitmap_internal_group = { .name ="bitmap" , - .attrs = md_bitmap_attrs, + .attrs = md_bitmap_internal_attrs, +}; + +static const struct attribute_group *bitmap_groups[] = { + &md_bitmap_common_group, + &md_bitmap_internal_group, +NULL , };static struct bitmap_operations bitmap_ops = {
@@ -3013,7 +3028,7 @@ static struct bitmap_operations bitmap_ops = { .set_pages = bitmap_set_pages, .free = md_bitmap_free, - .group = &md_bitmap_group, + .groups = bitmap_groups, };int md_bitmap_init (void )
drivers/md/md-bitmap.h +1 -1
@@ -125,7 +125,7 @@ struct bitmap_operations {void (*set_pages)(void *data,unsigned long pages);void (*free)(void *data); -struct attribute_group *group; +const struct attribute_group **groups; };/* the bitmap API */
drivers/md/md-llbitmap.c +6 -1
@@ -1562,6 +1562,11 @@ static struct attribute_group md_llbitmap_group = { .attrs = md_llbitmap_attrs, }; +static const struct attribute_group *md_llbitmap_groups[] = { + &md_llbitmap_group, +NULL , +}; +static struct bitmap_operations llbitmap_ops = { .head = { .type =MD_BITMAP ,
@@ -1598,7 +1603,7 @@ static struct bitmap_operations llbitmap_ops = { .dirty_bits = llbitmap_dirty_bits, .write_all = llbitmap_write_all, - .group = &md_llbitmap_group, + .groups = md_llbitmap_groups, };int md_llbitmap_init (void )
drivers/md/md.c +14 -7
@@ -690,7 +690,7 @@ static void no_op(struct percpu_ref *r) {}static void md_bitmap_sysfs_add (struct mddev *mddev) { -if (sysfs_create_group (&mddev->kobj, mddev->bitmap_ops->group)) +if (sysfs_update_groups (&mddev->kobj, mddev->bitmap_ops->groups))pr_warn ("md: cannot register extra bitmap attributes for %s\n" ,mdname (mddev));else
@@ -703,16 +703,23 @@ static void md_bitmap_sysfs_add(struct mddev *mddev)static void md_bitmap_sysfs_del (struct mddev *mddev) { -sysfs_remove_group (&mddev->kobj, mddev->bitmap_ops->group); +int nr_groups =0 ; + +for (nr_groups =0 ; mddev->bitmap_ops->groups[nr_groups]; nr_groups++) + ; + +while (--nr_groups >=1 ) +sysfs_unmerge_group (&mddev->kobj, + mddev->bitmap_ops->groups[nr_groups]); +sysfs_remove_group (&mddev->kobj, mddev->bitmap_ops->groups[0 ]); }static bool mddev_set_bitmap_ops_nosysfs (struct mddev *mddev) { -struct bitmap_operations *old = mddev->bitmap_ops;struct md_submodule_head *head; -if (mddev->bitmap_id ==ID_BITMAP_NONE || - (old && old->head.id == mddev->bitmap_id)) +if (mddev->bitmap_ops && + mddev->bitmap_ops->head.id == mddev->bitmap_id)return true;xa_lock (&md_submodule);
@@ -6590,7 +6597,7 @@ static int md_bitmap_create(struct mddev *mddev)if (err)return err; -if (!mddev_is_dm (mddev) && mddev->bitmap_ops->group) +if (!mddev_is_dm (mddev) && mddev->bitmap_ops->groups)md_bitmap_sysfs_add (mddev);return 0 ;
@@ -6608,7 +6615,7 @@ static void md_bitmap_destroy_nosysfs(struct mddev *mddev)static void md_bitmap_destroy (struct mddev *mddev) {if (!mddev_is_dm (mddev) && mddev->bitmap_ops && - mddev->bitmap_ops->group) + mddev->bitmap_ops->groups)md_bitmap_sysfs_del (mddev);md_bitmap_destroy_nosysfs (mddev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 959/1146 md/md-bitmap: add a none backend for bitmap grow
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yu Kuai <[email protected]>
[ Upstream commit f2926a533d03fe70d753b512b713e06a2aa174af ]
Add a real none bitmap backend that exposes the common bitmap sysfs group and use it to keep bitmap/location available when an array has no bitmap.
Then switch the bitmap location sysfs path to move only between none and the classic bitmap backend, using the no-sysfs bitmap helpers while merging or unmerging the internal bitmap sysfs group.
This restores mdadm --grow bitmap addition through bitmap/location.
--- drivers/md/md-bitmap.c | 108 ++++++++++++++++++++++++++++++++++++++--- drivers/md/md.c | 42 +++++++++++++--- drivers/md/md.h | 3 ++ 3 files changed, 137 insertions(+), 16 deletions(-)
drivers/md/md-bitmap.c +100 -8
@@ -216,6 +216,7 @@ struct bitmap { };static struct workqueue_struct *md_bitmap_wq; +static struct attribute_group md_bitmap_internal_group;static int __bitmap_resize (struct bitmap *bitmap,sector_t blocks,int chunksize,bool init);
@@ -2580,6 +2581,30 @@ static int bitmap_resize(struct mddev *mddev, sector_t blocks, int chunksize)return __bitmap_resize (bitmap, blocks, chunksize, false); } +static bool bitmap_none_enabled (void *data,bool flush) +{ +return false; +} + +static int bitmap_none_create (struct mddev *mddev) +{ +return 0 ; +} + +static int bitmap_none_load (struct mddev *mddev) +{ +return 0 ; +} + +static void bitmap_none_destroy (struct mddev *mddev) +{ +} + +static int bitmap_none_get_stats (void *data,struct md_bitmap_stats *stats) +{ +return -ENOENT ; +} +static ssize_t location_show (struct mddev *mddev,char *page) {
@@ -2618,7 +2643,11 @@ location_store(struct mddev *mddev, const char *buf, size_t len) goto out; } -bitmap_destroy (mddev); +sysfs_unmerge_group (&mddev->kobj, &md_bitmap_internal_group); +md_bitmap_destroy_nosysfs (mddev); + mddev->bitmap_id =ID_BITMAP_NONE ; +if (!mddev_set_bitmap_ops_nosysfs (mddev)) + goto none_err; mddev->bitmap_info.offset =0 ;if (mddev->bitmap_info.file) {struct file *f = mddev->bitmap_info.file;
@@ -2654,16 +2683,25 @@ location_store(struct mddev *mddev, const char *buf, size_t len) } mddev->bitmap_info.offset = offset; - rv =bitmap_create (mddev); +md_bitmap_destroy_nosysfs (mddev); + mddev->bitmap_id =ID_BITMAP ; +if (!mddev_set_bitmap_ops_nosysfs (mddev)) + goto bitmap_err; + + rv =md_bitmap_create_nosysfs (mddev);if (rv) - goto out; + goto create_err; - rv =bitmap_load (mddev); + rv = mddev->bitmap_ops->load (mddev);if (rv) { mddev->bitmap_info.offset =0 ; -bitmap_destroy (mddev); - goto out; + goto load_err; } + + rv =sysfs_merge_group (&mddev->kobj, + &md_bitmap_internal_group); +if (rv) + goto merge_err; } }if (!mddev->external) {
@@ -2679,6 +2717,22 @@ location_store(struct mddev *mddev, const char *buf, size_t len)if (rv)return rv;return len; + +merge_err: + mddev->bitmap_info.offset =0 ; +load_err: +md_bitmap_destroy_nosysfs (mddev); +create_err: + mddev->bitmap_info.offset =0 ; + mddev->bitmap_id =ID_BITMAP_NONE ; +if (!mddev_set_bitmap_ops_nosysfs (mddev)) + rv = -ENOENT ; + goto out; +bitmap_err: + rv = -ENOENT ; +none_err: + mddev->bitmap_info.offset =0 ; + goto out; } static struct md_sysfs_entry bitmap_location =
@@ -2987,6 +3041,27 @@ static const struct attribute_group *bitmap_groups[] = { NULL, }; +static const struct attribute_group *bitmap_none_groups[] = { + &md_bitmap_common_group, +NULL , +}; + +static struct bitmap_operations bitmap_none_ops = { + .head = { + .type =MD_BITMAP , + .id =ID_BITMAP_NONE , + .name ="none" , + }, + + .enabled = bitmap_none_enabled, + .create = bitmap_none_create, + .load = bitmap_none_load, + .destroy = bitmap_none_destroy, + .get_stats = bitmap_none_get_stats, + + .groups = bitmap_none_groups, +}; +static struct bitmap_operations bitmap_ops = { .head = { .type =MD_BITMAP ,
@@ -3033,16 +3108,33 @@ static struct bitmap_operations bitmap_ops = {int md_bitmap_init (void ) { +int err; + md_bitmap_wq =alloc_workqueue ("md_bitmap" ,WQ_MEM_RECLAIM |WQ_UNBOUND ,0 );if (!md_bitmap_wq)return -ENOMEM ; -return register_md_submodule (&bitmap_ops.head); + err =register_md_submodule (&bitmap_none_ops.head); +if (err) + goto err_wq; + + err =register_md_submodule (&bitmap_ops.head); +if (err) + goto err_none; + +return 0 ; + +err_none: +unregister_md_submodule (&bitmap_none_ops.head); +err_wq: +destroy_workqueue (md_bitmap_wq); +return err; }void md_bitmap_exit (void ) { -destroy_workqueue (md_bitmap_wq);unregister_md_submodule (&bitmap_ops.head); +unregister_md_submodule (&bitmap_none_ops.head); +destroy_workqueue (md_bitmap_wq); }
drivers/md/md.c +34 -8
125 lines not on this page · raw message
drivers/md/md.h +3 -0
@@ -932,6 +932,9 @@ extern void md_allow_write(struct mddev *mddev);extern void md_wait_for_blocked_rdev (struct md_rdev *rdev,struct mddev *mddev);extern void md_set_array_sectors (struct mddev *mddev,sector_t array_sectors);extern int md_check_no_bitmap (struct mddev *mddev); +bool mddev_set_bitmap_ops_nosysfs (struct mddev *mddev); +int md_bitmap_create_nosysfs (struct mddev *mddev); +void md_bitmap_destroy_nosysfs (struct mddev *mddev);extern int md_integrity_register (struct mddev *mddev);extern int strict_strtoul_scaled (const char *cp,unsigned long *res,int scale);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 960/1146 s390/mm: Fix phys_to_folio() usage in do_secure_storage_access()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Heiko Carstens <[email protected]>
[ Upstream commit b95e0e792822bad8fc9eb33ea3a90005e29e75e9 ]
In case of a Secure-Storage-Access exception the effective aka virtual address which caused the exception is contained within the TEID.
do_secure_storage_access() incorrectly uses phys_to_folio() instead of virt_to_folio() to translate the virtual address to the corresponding folio.
Fix this by using virt_to_folio() instead of phys_to_folio().
--- arch/s390/mm/fault.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/s390/mm/fault.c +1 -1
@@ -438,7 +438,7 @@ void do_secure_storage_access(struct pt_regs *regs)panic ("Unexpected PGM 0x3d with TEID bit 61=0" ); }if (is_kernel_fault (regs)) { - folio =phys_to_folio (addr); + folio =virt_to_folio ((void *)addr);if (unlikely (!folio_try_get (folio)))return ; rc =uv_convert_from_secure (folio_to_phys (folio));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 961/1146 net: phy: dp83869: fix setting CLK_O_SEL field.
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Heiko Schocher <[email protected]>
[ Upstream commit 46f74a3f7d57d9cc0110b09cbc8163fa0a01afa2 ]
Table 7-121 in datasheet says we have to set register 0xc6 to value 0x10 before CLK_O_SEL can be modified. No more infos about this field found in datasheet. With this fix, setting of CLK_O_SEL field in IO_MUX_CFG register worked through dts property "ti,clk-output-sel" on a DP83869HMRGZR.
--- drivers/net/phy/dp83869.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
drivers/net/phy/dp83869.c +12 -1
@@ -31,6 +31,7 @@#define DP83869_RGMIICTL 0x0032#define DP83869_STRAP_STS1 0x006e#define DP83869_RGMIIDCTL 0x0086 +#define DP83869_ANA_PLL_PROG_PI 0x00c6#define DP83869_RXFCFG 0x0134#define DP83869_RXFPMD1 0x0136#define DP83869_RXFPMD2 0x0137
@@ -826,12 +827,22 @@ static int dp83869_config_init(struct phy_device *phydev)dp83869_config_port_mirroring (phydev);/* Clock output selection if muxing property is set */ -if (dp83869->clk_output_sel !=DP83869_CLK_O_SEL_REF_CLK ) +if (dp83869->clk_output_sel !=DP83869_CLK_O_SEL_REF_CLK ) { +/* +* Table 7-121 in datasheet says we have to set register 0xc6 +* to value 0x10 before CLK_O_SEL can be modified. +*/ + ret =phy_write_mmd (phydev,DP83869_DEVADDR , +DP83869_ANA_PLL_PROG_PI ,0x10 ); +if (ret) +return ret; + ret =phy_modify_mmd (phydev,DP83869_DEVADDR ,DP83869_IO_MUX_CFG ,DP83869_IO_MUX_CFG_CLK_O_SEL_MASK , dp83869->clk_output_sel <<DP83869_IO_MUX_CFG_CLK_O_SEL_SHIFT ); + }if (phy_interface_is_rgmii (phydev)) { ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_RGMIIDCTL,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 962/1146 drm/amd/display: properly handle family setting for early GC 11.5.4
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
[ Upstream commit 31bc64e87f5f3d9ccbb7e625d570cfd8f52c77fc ]
Early variants need an override.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c | 4 +--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 6 +++++- 2 files changed, 6 insertions(+), 4 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +1 -3
@@ -2986,10 +2986,8 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)case IP_VERSION (11 ,5 ,1 ):case IP_VERSION (11 ,5 ,2 ):case IP_VERSION (11 ,5 ,3 ): - adev->family =AMDGPU_FAMILY_GC_11_5_0 ; -break ;case IP_VERSION (11 ,5 ,4 ): - adev->family =AMDGPU_FAMILY_GC_11_5_4 ; + adev->family =AMDGPU_FAMILY_GC_11_5_0 ;break ;case IP_VERSION (12 ,0 ,0 ):case IP_VERSION (12 ,0 ,1 ):
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +5 -1
@@ -1891,7 +1891,11 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) goto error; } - init_data.asic_id.chip_family = adev->family; +/* special handling for early revisions of GC 11.5.4 */ +if (amdgpu_ip_version (adev,GC_HWIP ,0 ) ==IP_VERSION (11 ,5 ,4 )) + init_data.asic_id.chip_family =AMDGPU_FAMILY_GC_11_5_4 ; +else + init_data.asic_id.chip_family = adev->family; init_data.asic_id.pci_revision_id = adev->pdev->revision; init_data.asic_id.hw_internal_rev = adev->external_rev_id;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 963/1146 drm/amdgpu/vcn: set no_user_fence for VCN v2.0 enc/dec rings
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 8d80b293b41fcb5e9396db93e788b0f4ebcbafb7 ]
VCN encoder and decoder rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +2 -0
@@ -2113,6 +2113,7 @@ static const struct amd_ip_funcs vcn_v2_0_ip_funcs = {static const struct amdgpu_ring_funcs vcn_v2_0_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_DEC , .align_mask =0xf , + .no_user_fence = true, .secure_submission_supported = true, .get_rptr = vcn_v2_0_dec_ring_get_rptr, .get_wptr = vcn_v2_0_dec_ring_get_wptr,
@@ -2145,6 +2146,7 @@ static const struct amdgpu_ring_funcs vcn_v2_0_enc_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .get_rptr = vcn_v2_0_enc_ring_get_rptr, .get_wptr = vcn_v2_0_enc_ring_get_wptr, .set_wptr = vcn_v2_0_enc_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 964/1146 drm/amdgpu/vcn: set no_user_fence for VCN v2.5 enc/dec rings
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 4f317863a3ab212a027d8c8c3cc3af4e3fb95704 ]
VCN encoder and decoder rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c +2 -0
@@ -1778,6 +1778,7 @@ static void vcn_v2_5_dec_ring_set_wptr(struct amdgpu_ring *ring)static const struct amdgpu_ring_funcs vcn_v2_5_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_DEC , .align_mask =0xf , + .no_user_fence = true, .secure_submission_supported = true, .get_rptr = vcn_v2_5_dec_ring_get_rptr, .get_wptr = vcn_v2_5_dec_ring_get_wptr,
@@ -1879,6 +1880,7 @@ static const struct amdgpu_ring_funcs vcn_v2_5_enc_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .get_rptr = vcn_v2_5_enc_ring_get_rptr, .get_wptr = vcn_v2_5_enc_ring_get_wptr, .set_wptr = vcn_v2_5_enc_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 965/1146 drm/amdgpu/vcn: set no_user_fence for VCN v3.0 enc/dec rings
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit f1e5a6660d7cbf006079126d9babbf0ccf538c6b ]
VCN encoder and decoder rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +3 -0
@@ -1856,6 +1856,7 @@ static const struct amdgpu_ring_funcs vcn_v3_0_dec_sw_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_DEC, .align_mask = 0x3f, .nop = VCN_DEC_SW_CMD_NO_OP, + .no_user_fence = true, .secure_submission_supported = true, .get_rptr = vcn_v3_0_dec_ring_get_rptr, .get_wptr = vcn_v3_0_dec_ring_get_wptr,
@@ -2038,6 +2039,7 @@ static int vcn_v3_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p,static const struct amdgpu_ring_funcs vcn_v3_0_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_DEC , .align_mask =0xf , + .no_user_fence = true, .secure_submission_supported = true, .get_rptr = vcn_v3_0_dec_ring_get_rptr, .get_wptr = vcn_v3_0_dec_ring_get_wptr,
@@ -2140,6 +2142,7 @@ static const struct amdgpu_ring_funcs vcn_v3_0_enc_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .get_rptr = vcn_v3_0_enc_ring_get_rptr, .get_wptr = vcn_v3_0_enc_ring_get_wptr, .set_wptr = vcn_v3_0_enc_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 966/1146 drm/amdgpu/vcn: set no_user_fence for VCN v4.0 enc ring
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 51f694221047c84fa185be98210eb2c354ffb8c6 ]
VCN encoder and decoder rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +1 -0
@@ -1996,6 +1996,7 @@ static struct amdgpu_ring_funcs vcn_v4_0_unified_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .extra_bytes = sizeof(struct amdgpu_vcn_rb_metadata), .get_rptr = vcn_v4_0_unified_ring_get_rptr, .get_wptr = vcn_v4_0_unified_ring_get_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 967/1146 drm/amdgpu/vcn: set no_user_fence for VCN v4.0.3 enc ring
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 4532b52b34e4e4310386e6fdf6a643368599f522 ]
VCN encoder and decoder rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c +1 -0
@@ -1758,6 +1758,7 @@ static const struct amdgpu_ring_funcs vcn_v4_0_3_unified_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .get_rptr = vcn_v4_0_3_unified_ring_get_rptr, .get_wptr = vcn_v4_0_3_unified_ring_get_wptr, .set_wptr = vcn_v4_0_3_unified_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 968/1146 drm/amdgpu/vcn: set no_user_fence for VCN v4.0.5 enc ring
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 589a254bf3e88204c8402b9cbccd5e23a0af990f ]
VCN encoder and decoder rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c +1 -0
@@ -1483,6 +1483,7 @@ static struct amdgpu_ring_funcs vcn_v4_0_5_unified_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .get_rptr = vcn_v4_0_5_unified_ring_get_rptr, .get_wptr = vcn_v4_0_5_unified_ring_get_wptr, .set_wptr = vcn_v4_0_5_unified_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 969/1146 drm/amdgpu/vcn: set no_user_fence for VCN v5.0.0 enc ring
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 8cae0ce77de492d7c31c1532a2e80c0c6e7e58cb ]
VCN encoder and decoder rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c +1 -0
@@ -1207,6 +1207,7 @@ static const struct amdgpu_ring_funcs vcn_v5_0_0_unified_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .get_rptr = vcn_v5_0_0_unified_ring_get_rptr, .get_wptr = vcn_v5_0_0_unified_ring_get_wptr, .set_wptr = vcn_v5_0_0_unified_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 970/1146 drm/amdgpu/vcn: set no_user_fence for VCN v5.0.1 enc ring
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 8f4954722eab88e10c4ea0c0d3b1269c31421d3a ]
VCN encoder and decoder rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c +1 -0
@@ -1419,6 +1419,7 @@ static const struct amdgpu_ring_funcs vcn_v5_0_1_unified_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .get_rptr = vcn_v5_0_1_unified_ring_get_rptr, .get_wptr = vcn_v5_0_1_unified_ring_get_wptr, .set_wptr = vcn_v5_0_1_unified_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 971/1146 drm/amdgpu/jpeg: set no_user_fence for JPEG v2.0 ring
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit e5f612dc91650561fe2b5b76dd6d2898ec9ad480 ]
JPEG rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c +1 -0
@@ -802,6 +802,7 @@ static const struct amd_ip_funcs jpeg_v2_0_ip_funcs = {static const struct amdgpu_ring_funcs jpeg_v2_0_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .get_rptr = jpeg_v2_0_dec_ring_get_rptr, .get_wptr = jpeg_v2_0_dec_ring_get_wptr, .set_wptr = jpeg_v2_0_dec_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 972/1146 drm/amdgpu/jpeg: set no_user_fence for JPEG v2.5 ring
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 79405e774ede411c6b47ed41c651e40b92de64a2 ]
JPEG rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c +2 -0
@@ -693,6 +693,7 @@ static const struct amd_ip_funcs jpeg_v2_6_ip_funcs = {static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .get_rptr = jpeg_v2_5_dec_ring_get_rptr, .get_wptr = jpeg_v2_5_dec_ring_get_wptr, .set_wptr = jpeg_v2_5_dec_ring_set_wptr,
@@ -724,6 +725,7 @@ static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = {static const struct amdgpu_ring_funcs jpeg_v2_6_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .get_rptr = jpeg_v2_5_dec_ring_get_rptr, .get_wptr = jpeg_v2_5_dec_ring_get_wptr, .set_wptr = jpeg_v2_5_dec_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 973/1146 drm/amdgpu/jpeg: set no_user_fence for JPEG v3.0 ring
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit a2baf12eec41f246689e6a3f8619af1200031576 ]
JPEG rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c +1 -0
@@ -594,6 +594,7 @@ static const struct amd_ip_funcs jpeg_v3_0_ip_funcs = {static const struct amdgpu_ring_funcs jpeg_v3_0_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .get_rptr = jpeg_v3_0_dec_ring_get_rptr, .get_wptr = jpeg_v3_0_dec_ring_get_wptr, .set_wptr = jpeg_v3_0_dec_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 974/1146 drm/amdgpu/jpeg: set no_user_fence for JPEG v4.0 ring
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit e7e90b5839aeb8805ec83bb4da610b8dab8e184d ]
JPEG rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c +1 -0
@@ -759,6 +759,7 @@ static const struct amd_ip_funcs jpeg_v4_0_ip_funcs = {static const struct amdgpu_ring_funcs jpeg_v4_0_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .get_rptr = jpeg_v4_0_dec_ring_get_rptr, .get_wptr = jpeg_v4_0_dec_ring_get_wptr, .set_wptr = jpeg_v4_0_dec_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 975/1146 drm/amdgpu/jpeg: set no_user_fence for JPEG v4.0.3 ring
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 83e37c0987ca92f9e87789b46dd311dcf5a4a6c8 ]
JPEG rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c +1 -0
@@ -1219,6 +1219,7 @@ static const struct amd_ip_funcs jpeg_v4_0_3_ip_funcs = {static const struct amdgpu_ring_funcs jpeg_v4_0_3_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .get_rptr = jpeg_v4_0_3_dec_ring_get_rptr, .get_wptr = jpeg_v4_0_3_dec_ring_get_wptr, .set_wptr = jpeg_v4_0_3_dec_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 976/1146 drm/amdgpu/jpeg: set no_user_fence for JPEG v4.0.5 ring
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit b65b7f3f3c18f797f81a2af7c97e2079900ad6db ]
JPEG rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c +1 -0
@@ -804,6 +804,7 @@ static const struct amd_ip_funcs jpeg_v4_0_5_ip_funcs = {static const struct amdgpu_ring_funcs jpeg_v4_0_5_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .get_rptr = jpeg_v4_0_5_dec_ring_get_rptr, .get_wptr = jpeg_v4_0_5_dec_ring_get_wptr, .set_wptr = jpeg_v4_0_5_dec_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 977/1146 drm/amdgpu/jpeg: set no_user_fence for JPEG v5.0.0 ring
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit ea7c61c5f895e8f9ea0ffffa180498ef9c740152 ]
JPEG rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c +1 -0
@@ -680,6 +680,7 @@ static const struct amd_ip_funcs jpeg_v5_0_0_ip_funcs = {static const struct amdgpu_ring_funcs jpeg_v5_0_0_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .get_rptr = jpeg_v5_0_0_dec_ring_get_rptr, .get_wptr = jpeg_v5_0_0_dec_ring_get_wptr, .set_wptr = jpeg_v5_0_0_dec_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 978/1146 drm/amdgpu/jpeg: set no_user_fence for JPEG v5.0.1 ring
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 2f8e3da71a1b469b6e157aa3972f1448b3157840 ]
JPEG rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c +1 -0
@@ -884,6 +884,7 @@ static const struct amd_ip_funcs jpeg_v5_0_1_ip_funcs = {static const struct amdgpu_ring_funcs jpeg_v5_0_1_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .get_rptr = jpeg_v5_0_1_dec_ring_get_rptr, .get_wptr = jpeg_v5_0_1_dec_ring_get_wptr, .set_wptr = jpeg_v5_0_1_dec_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 979/1146 drm/amdgpu/jpeg: set no_user_fence for JPEG v5.3.0 ring
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 3b0ea2021351b6b813b34fac940957f1f4fad85b ]
JPEG rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v5_3_0.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/jpeg_v5_3_0.c +1 -0
@@ -661,6 +661,7 @@ static const struct amd_ip_funcs jpeg_v5_3_0_ip_funcs = {static const struct amdgpu_ring_funcs jpeg_v5_3_0_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .get_rptr = jpeg_v5_3_0_dec_ring_get_rptr, .get_wptr = jpeg_v5_3_0_dec_ring_get_wptr, .set_wptr = jpeg_v5_3_0_dec_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 980/1146 drm/amd/pm: Add fine grained flag to SMU v13.0.6
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lijo Lazar <[email protected]>
[ Upstream commit 47a5dfc8add4e60ff1ddc312f79998e70cbb0c09 ]
Gfx clock is fine grained on SMU v13.0.6/12 SOCs. Add the flag to report clock frequencies correctly.
--- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +1 -0
@@ -1122,6 +1122,7 @@ static int smu_v13_0_6_set_default_dpm_table(struct smu_context *smu)/* gfxclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.gfx_table; dpm_table->clk_type =SMU_GFXCLK ; + dpm_table->flags =SMU_DPM_TABLE_FINE_GRAINED ;if (smu_cmn_feature_is_enabled (smu,SMU_FEATURE_DPM_GFXCLK_BIT )) {/* In the case of gfxclk, only fine-grained dpm is honored. * Get min/max values from FW.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 981/1146 io_uring/napi: cap busy_poll_to 10 msec
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jens Axboe <[email protected]>
[ Upstream commit df8599ee18c0e5fe343ffe0b4c379636b8bb839a ]
Currently there's no cap on the maximum amount of time that napi is allowed to poll if no events are found, which can lead to kernel complaints on a task being stuck as there's no conditional rescheduling done within that loop.
Just cap it to 10 msec in total, that's already way above any kind of sane value that will reap any benefits, yet low enough that it's nowhere near being able to trigger preemption complaints.
--- io_uring/napi.c | 2 ++ 1 file changed, 2 insertions(+)
io_uring/napi.c +2 -0
@@ -276,6 +276,8 @@ static int io_napi_register_napi(struct io_ring_ctx *ctx,/* clean the napi list for new settings */ io_napi_free (ctx);WRITE_ONCE (ctx->napi_track_mode, napi->op_param); +/* cap NAPI at 10 msec of spin time */ + napi->busy_poll_to =min (10000 , napi->busy_poll_to);WRITE_ONCE (ctx->napi_busy_poll_dt, napi->busy_poll_to *NSEC_PER_USEC );WRITE_ONCE (ctx->napi_prefer_busy_poll, !!napi->prefer_busy_poll);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 982/1146 ASoC: cs35l56: Fix illegal writes to OTP_MEM registers
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Richard Fitzgerald <[email protected]>
[ Upstream commit be102efb832ef7e30e4cd4c2edf22bbf64ddf35a ]
Mark the OTP_MEM registers as volatile so that regcache_sync() will not attempt to write to them.
These registers hold a constant, and originally they were marked as readable non-volatile so that this value would be read into the regmap cache. The problem with this is regcache_sync() issues a write for any cached register that does not have a reg_default.
Though these registers are constants and writing them in normal use cannot change OTP, it is illegal for the host to write to them.
--- sound/soc/codecs/cs35l56-shared.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
sound/soc/codecs/cs35l56-shared.c +3 -4
@@ -108,8 +108,6 @@ int cs35l56_set_patch(struct cs35l56_base *cs35l56_base)EXPORT_SYMBOL_NS_GPL (cs35l56_set_patch,"SND_SOC_CS35L56_SHARED" );static const struct reg_default cs35l56_reg_defaults[] = { -/* no defaults for OTP_MEM - first read populates cache */ - {CS35L56_ASP1_ENABLES1 ,0x00000000 }, {CS35L56_ASP1_CONTROL1 ,0x00000028 }, {CS35L56_ASP1_CONTROL2 ,0x18180200 },
@@ -138,8 +136,6 @@ static const struct reg_default cs35l56_reg_defaults[] = { };static const struct reg_default cs35l63_reg_defaults[] = { -/* no defaults for OTP_MEM - first read populates cache */ - {CS35L56_ASP1_ENABLES1 ,0x00000000 }, {CS35L56_ASP1_CONTROL1 ,0x00000028 }, {CS35L56_ASP1_CONTROL2 ,0x18180200 },
@@ -282,6 +278,9 @@ static bool cs35l56_common_volatile_reg(unsigned int reg)case CS35L56_GLOBAL_ENABLES :/* owned by firmware */ case CS35L56_BLOCK_ENABLES :/* owned by firmware */ case CS35L56_BLOCK_ENABLES2 :/* owned by firmware */ +case CS35L56_OTP_MEM_53 : +case CS35L56_OTP_MEM_54 : +case CS35L56_OTP_MEM_55 : case CS35L56_SYNC_GPIO1_CFG ... CS35L56_ASP2_DIO_GPIO13_CFG:case CS35L56_UPDATE_REGS :case CS35L56_REFCLK_INPUT :/* owned by firmware */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 983/1146 net: psp: check for device unregister when creating assoc
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jakub Kicinski <[email protected]>
[ Upstream commit b89769f936a8fa9e66de72ddc1b71a9745a488e6 ]
psp_assoc_device_get_locked() obtains a psp_dev reference via psp_dev_get_for_sock() (which uses psp_dev_tryget() under RCU); it then acquires psd->lock and drops the reference. Before the lock is taken, psp_dev_unregister() can run to completion:
take psd->lock, clear out state, unlock, drop the registration reference.
The expectation is that the lock prevents device unregistration, but much like with netdevs special care has to be taken when "upgrading" a reference to a locked device. Add the missing check if device is still alive. psp_dev_is_registered() exists already but had no callers, which makes me wonder if I either forgot to add this or lost the check during refactoring...
--- net/psp/psp_nl.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
net/psp/psp_nl.c +7 -3
@@ -305,8 +305,13 @@ int psp_assoc_device_get_locked(const struct genl_split_ops *ops, psd =psp_dev_get_for_sock (socket->sk);if (psd) { - err =psp_dev_check_access (psd,genl_info_net (info)); -if (err) { +/* Extra care needed here, psp_dev_get_for_sock() only gives +* us access to struct psp_dev's memory, which is quite weak. +*/ +mutex_lock (&psd->lock); +if (!psp_dev_is_registered (psd) || +psp_dev_check_access (psd,genl_info_net (info))) { +mutex_unlock (&psd->lock);psp_dev_put (psd); psd =NULL ; }
@@ -319,7 +324,6 @@ int psp_assoc_device_get_locked(const struct genl_split_ops *ops, id = info->attrs[PSP_A_ASSOC_DEV_ID ];if (psd) { -mutex_lock (&psd->lock);if (id && psd->id !=nla_get_u32 (id)) {mutex_unlock (&psd->lock); NL_SET_ERR_MSG_ATTR(info->extack, id,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 984/1146 net: psp: require admin permission for dev-set and key-rotate
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jakub Kicinski <[email protected]>
[ Upstream commit b718342a7fbaa2dff5fefc31988c07af8c6cbc21 ]
The dev-set and key-rotate netlink operations modify shared device state (PSP version configuration and cryptographic key material, respectively) but do not require CAP_NET_ADMIN. The only access control is psp_dev_check_access() which merely verifies netns membership.
--- Documentation/netlink/specs/psp.yaml | 2 ++ net/psp/psp-nl-gen.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-)
Documentation/netlink/specs/psp.yaml +2 -0
@@ -188,6 +188,7 @@ operations: name: dev-set doc: Set the configuration of a PSP device. attribute-set: dev + flags: [admin-perm] do: request: attributes:
@@ -207,6 +208,7 @@ operations: name: key-rotate doc: Rotate the device key. attribute-set: dev + flags: [admin-perm] do: request: attributes:
net/psp/psp-nl-gen.c +2 -2
@@ -76,7 +76,7 @@ static const struct genl_split_ops psp_nl_ops[] = { .post_doit = psp_device_unlock, .policy = psp_dev_set_nl_policy, .maxattr = PSP_A_DEV_PSP_VERSIONS_ENA, - .flags = GENL_CMD_CAP_DO, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, }, { .cmd = PSP_CMD_KEY_ROTATE,
@@ -85,7 +85,7 @@ static const struct genl_split_ops psp_nl_ops[] = { .post_doit = psp_device_unlock, .policy = psp_key_rotate_nl_policy, .maxattr = PSP_A_DEV_ID, - .flags = GENL_CMD_CAP_DO, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, }, { .cmd = PSP_CMD_RX_ASSOC,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 985/1146 ASoC: codecs: ab8500: Fix casting of private data
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian A. Ehrhardt <[email protected]>
[ Upstream commit a201aef1a88b675e9eb8487e27d14e2eef3cef80 ]
ab8500_filter_controls[i].private_value is initialized using
.private_value = (unsigned long)&(struct filter_control)
{.count = xcount, .min = xmin, .max = xmax}thus it's a pointer to a struct filter_control casted to unsigned long.
So to get back that pointer .private_data must be cast back, not its address.
--- sound/soc/codecs/ab8500-codec.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
sound/soc/codecs/ab8500-codec.c +3 -3
@@ -2496,13 +2496,13 @@ static int ab8500_codec_probe(struct snd_soc_component *component)return status; } fc = (struct filter_control *) - &ab8500_filter_controls[AB8500_FILTER_ANC_FIR ].private_value; + ab8500_filter_controls[AB8500_FILTER_ANC_FIR ].private_value; drvdata->anc_fir_values = (long *)fc->value; fc = (struct filter_control *) - &ab8500_filter_controls[AB8500_FILTER_ANC_IIR ].private_value; + ab8500_filter_controls[AB8500_FILTER_ANC_IIR ].private_value; drvdata->anc_iir_values = (long *)fc->value; fc = (struct filter_control *) - &ab8500_filter_controls[AB8500_FILTER_SID_FIR ].private_value; + ab8500_filter_controls[AB8500_FILTER_SID_FIR ].private_value; drvdata->sid_fir_values = (long *)fc->value;snd_soc_dapm_disable_pin (dapm,"ANC Configure Input" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 986/1146 netfilter: skip recording stale or retransmitted INIT
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xin Long <[email protected]>
[ Upstream commit 576a5d2bad4814c881a829576b1261b9b8159d2b ]
An INIT whose init_tag matches the peer's vtag does not provide new state information. It indicates either:
- a stale INIT (after INIT-ACK has already been seen on the same side), or
- a retransmitted INIT (after INIT has already been recorded on the same side).
In both cases, the INIT must not update ct->proto.sctp.init[] state, since it does not advance the handshake tracking and may otherwise corrupt INIT/INIT-ACK validation logic.
Allow INIT processing only when the conntrack entry is newly created (SCTP_CONNTRACK_NONE), or when the init_tag differs from the stored peer vtag.
Note it skips the check for the ct with old_state SCTP_CONNTRACK_NONE in nf_conntrack_sctp_packet(), as it is just created in sctp_new() where it set ct->proto.sctp.vtag[IP_CT_DIR_REPLY] = ih->init_tag.
--- net/netfilter/nf_conntrack_proto_sctp.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
net/netfilter/nf_conntrack_proto_sctp.c +7 -3
@@ -466,9 +466,13 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct,if (!ih) goto out_unlock; -if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir]) - ct->proto.sctp.init[!dir] =0 ; - ct->proto.sctp.init[dir] =1 ; +/* Do not record INIT matching peer vtag (stale or retransmitted INIT). */ +if (old_state ==SCTP_CONNTRACK_NONE || + ct->proto.sctp.vtag[!dir] != ih->init_tag) { +if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir]) + ct->proto.sctp.init[!dir] =0 ; + ct->proto.sctp.init[dir] =1 ; + }pr_debug ("Setting vtag %x for dir %d\n" , ih->init_tag, !dir); ct->proto.sctp.vtag[!dir] = ih->init_tag;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 987/1146 sctp: discard stale INIT after handshake completion
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xin Long <[email protected]>
[ Upstream commit 8a92cb475ca90d84db769e4d4383e631ace0d6e5 ]
After an association reaches ESTABLISHED, the peer’s init_tag is already known from the handshake. Any subsequent INIT with the same init_tag is not a valid restart, but a delayed or duplicate INIT.
Drop such INIT chunks in sctp_sf_do_unexpected_init() instead of processing them as new association attempts.
--- net/sctp/sm_statefuns.c | 6 ++++++ 1 file changed, 6 insertions(+)
net/sctp/sm_statefuns.c +6 -0
@@ -1556,6 +1556,12 @@ static enum sctp_disposition sctp_sf_do_unexpected_init(/* Tag the variable length parameters. */ chunk->param_hdr.v =skb_pull (chunk->skb,sizeof (struct sctp_inithdr )); +if (asoc->state >=SCTP_STATE_ESTABLISHED ) { +/* Discard INIT matching peer vtag after handshake completion (stale INIT). */ +if (ntohl (chunk->subh.init_hdr->init_tag) == asoc->peer.i.init_tag) +return sctp_sf_pdiscard (net, ep, asoc, type, arg, commands); + } +/* Verify the INIT chunk before processing it. */ err_chunk =NULL ; if (!sctp_verify_init(net, ep, asoc, chunk->chunk_hdr->type,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 988/1146 bareudp: fix NULL pointer dereference in bareudp_fill_metadata_dst()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
[ Upstream commit aa6c6d9ee064aabfede4402fd1283424e649ca19 ]
bareudp_fill_metadata_dst() passes bareudp->sock to udp_tunnel6_dst_lookup() in the IPv6 path without a NULL check. The socket is only created in bareudp_open() and NULLed in bareudp_stop(), so calling this function while the device is down triggers a NULL dereference via sock->sk.
BUG: kernel NULL pointer dereference, address: 0000000000000018 RIP: 0010:udp_tunnel6_dst_lookup (net/ipv6/ip6_udp_tunnel.c:160) Call Trace: <TASK> bareudp_fill_metadata_dst (drivers/net/bareudp.c:532) do_execute_actions (net/openvswitch/actions.c:901) ovs_execute_actions (net/openvswitch/actions.c:1589) ovs_packet_cmd_execute (net/openvswitch/datapath.c:700) genl_family_rcv_msg_doit (net/netlink/genetlink.c:1114) genl_rcv_msg (net/netlink/genetlink.c:1209) netlink_rcv_skb (net/netlink/af_netlink.c:2550) </TASK>
Add a NULL check returning -ESHUTDOWN, consistent with the xmit paths in the same driver.
--- drivers/net/bareudp.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/bareudp.c +3 -0
@@ -529,6 +529,9 @@ static int bareudp_fill_metadata_dst(struct net_device *dev,struct in6_addr saddr;struct socket *sock =rcu_dereference (bareudp->sock); +if (!sock) +return -ESHUTDOWN ; + dst = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock, 0, &saddr, &info->key, sport, bareudp->port, info->key.tos,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 989/1146 net/sched: sch_cake: annotate data-races in cake_dump_stats() (I)
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 44967ac3785ebef6442377708925181d4a0eb1c8 ]
cake_dump_stats() runs without qdisc spinlock being held.
In this first patch, I add READ_ONCE()/WRITE_ONCE() annotations for the following fields:
- way_hits
- way_misses
- way_collisions
- sparse_flow_count
- decaying_flow_count
Other annotations are added in following patches, to ease code review.
--- net/sched/sch_cake.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-)
net/sched/sch_cake.c +21 -21
@@ -813,7 +813,7 @@ static u32 cake_hash(struct cake_tin_data *q, const struct sk_buff *skb, i++, k = (k + 1) % CAKE_SET_WAYS) {if (q->tags[outer_hash + k] == flow_hash) {if (i) - q->way_hits++; +WRITE_ONCE (q->way_hits, q->way_hits +1 );if (!q->flows[outer_hash + k].set) {/* need to increment host refcnts */
@@ -831,7 +831,7 @@ static u32 cake_hash(struct cake_tin_data *q, const struct sk_buff *skb,for (i =0 ; i <CAKE_SET_WAYS ; i++, k = (k +1 ) %CAKE_SET_WAYS ) {if (!q->flows[outer_hash + k].set) { - q->way_misses++; +WRITE_ONCE (q->way_misses, q->way_misses +1 ); allocate_src =cake_dsrc (flow_mode); allocate_dst =cake_ddst (flow_mode); goto found;
@@ -841,7 +841,7 @@ static u32 cake_hash(struct cake_tin_data *q, const struct sk_buff *skb,/* With no empty queues, default to the original * queue, accept the collision, update the host tags. */ - q->way_collisions++; +WRITE_ONCE (q->way_collisions, q->way_collisions +1 ); allocate_src =cake_dsrc (flow_mode); allocate_dst =cake_ddst (flow_mode);
@@ -1917,11 +1917,11 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,if (!flow->set) {list_add_tail (&flow->flowchain, &b->new_flows); }else { - b->decaying_flow_count--; +WRITE_ONCE (b->decaying_flow_count, b->decaying_flow_count -1 );list_move_tail (&flow->flowchain, &b->new_flows); } flow->set =CAKE_SET_SPARSE ; - b->sparse_flow_count++; +WRITE_ONCE (b->sparse_flow_count, b->sparse_flow_count +1 ); flow->deficit =cake_get_flow_quantum (b, flow, q->config->flow_mode); }else if (flow->set ==CAKE_SET_SPARSE_WAIT ) {
@@ -1929,7 +1929,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,* in the bulk rotation. */ flow->set =CAKE_SET_BULK ; - b->sparse_flow_count--; +WRITE_ONCE (b->sparse_flow_count, b->sparse_flow_count -1 ); b->bulk_flow_count++;cake_inc_srchost_bulk_flow_count (b, flow, q->config->flow_mode);
@@ -2149,7 +2149,7 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)*/ if (flow->set ==CAKE_SET_SPARSE ) {if (flow->head) { - b->sparse_flow_count--; +WRITE_ONCE (b->sparse_flow_count, b->sparse_flow_count -1 ); b->bulk_flow_count++;cake_inc_srchost_bulk_flow_count (b, flow, q->config->flow_mode);
@@ -2192,27 +2192,27 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)cake_dec_srchost_bulk_flow_count (b, flow, q->config->flow_mode);cake_dec_dsthost_bulk_flow_count (b, flow, q->config->flow_mode); - b->decaying_flow_count++; +WRITE_ONCE (b->decaying_flow_count, b->decaying_flow_count +1 ); }else if (flow->set ==CAKE_SET_SPARSE || flow->set ==CAKE_SET_SPARSE_WAIT ) { - b->sparse_flow_count--; - b->decaying_flow_count++; +WRITE_ONCE (b->sparse_flow_count, b->sparse_flow_count -1 ); +WRITE_ONCE (b->decaying_flow_count, b->decaying_flow_count +1 ); } flow->set =CAKE_SET_DECAYING ; }else {/* remove empty queue from the flowchain */ list_del_init (&flow->flowchain);if (flow->set ==CAKE_SET_SPARSE || - flow->set ==CAKE_SET_SPARSE_WAIT ) - b->sparse_flow_count--; -else if (flow->set ==CAKE_SET_BULK ) { + flow->set ==CAKE_SET_SPARSE_WAIT ) { +WRITE_ONCE (b->sparse_flow_count, b->sparse_flow_count -1 ); + }else if (flow->set ==CAKE_SET_BULK ) { b->bulk_flow_count--;cake_dec_srchost_bulk_flow_count (b, flow, q->config->flow_mode);cake_dec_dsthost_bulk_flow_count (b, flow, q->config->flow_mode); - }else - b->decaying_flow_count--; - + }else { +WRITE_ONCE (b->decaying_flow_count, b->decaying_flow_count -1 ); + } flow->set =CAKE_SET_NONE ; } goto begin;
@@ -3050,12 +3050,12 @@ static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d)PUT_TSTAT_U32 (BASE_DELAY_US ,ktime_to_us (ns_to_ktime (b->base_delay))); -PUT_TSTAT_U32 (WAY_INDIRECT_HITS , b->way_hits); -PUT_TSTAT_U32 (WAY_MISSES , b->way_misses); -PUT_TSTAT_U32 (WAY_COLLISIONS , b->way_collisions); +PUT_TSTAT_U32 (WAY_INDIRECT_HITS ,READ_ONCE (b->way_hits)); +PUT_TSTAT_U32 (WAY_MISSES ,READ_ONCE (b->way_misses)); +PUT_TSTAT_U32 (WAY_COLLISIONS ,READ_ONCE (b->way_collisions)); -PUT_TSTAT_U32 (SPARSE_FLOWS , b->sparse_flow_count + - b->decaying_flow_count); +PUT_TSTAT_U32 (SPARSE_FLOWS ,READ_ONCE (b->sparse_flow_count) + +READ_ONCE (b->decaying_flow_count));PUT_TSTAT_U32 (BULK_FLOWS , b->bulk_flow_count);PUT_TSTAT_U32 (UNRESPONSIVE_FLOWS , b->unresponsive_flow_count);PUT_TSTAT_U32 (MAX_SKBLEN , b->max_skblen);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 990/1146 net/sched: sch_cake: annotate data-races in cake_dump_stats() (II)
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 91a96427b93b9ba27413077b7e825d2fefbfa134 ]
cake_dump_stats() runs without qdisc spinlock being held.
In this second patch, I add READ_ONCE()/WRITE_ONCE() annotations for the following fields:
- bulk_flow_count
- unresponsive_flow_count
- max_skblen
- flow_quantum
Other annotations are added in following patches, to ease code review.
--- net/sched/sch_cake.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-)
net/sched/sch_cake.c +19 -15
@@ -1590,7 +1590,8 @@ static unsigned int cake_drop(struct Qdisc *sch, struct sk_buff **to_free) }if (cobalt_queue_full (&flow->cvars, &b->cparams, now)) - b->unresponsive_flow_count++; +WRITE_ONCE (b->unresponsive_flow_count, + b->unresponsive_flow_count +1 ); len =qdisc_pkt_len (skb); q->buffer_used -= skb->truesize;
@@ -1795,7 +1796,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, }if (unlikely (len > b->max_skblen)) - b->max_skblen = len; +WRITE_ONCE (b->max_skblen, len);if (qdisc_pkt_segs (skb) >1 && q->config->rate_flags &CAKE_FLAG_SPLIT_GSO ) {struct sk_buff *segs, *nskb;
@@ -1930,7 +1931,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,*/ flow->set =CAKE_SET_BULK ;WRITE_ONCE (b->sparse_flow_count, b->sparse_flow_count -1 ); - b->bulk_flow_count++; +WRITE_ONCE (b->bulk_flow_count, b->bulk_flow_count +1 );cake_inc_srchost_bulk_flow_count (b, flow, q->config->flow_mode);cake_inc_dsthost_bulk_flow_count (b, flow, q->config->flow_mode);
@@ -2150,7 +2151,7 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)if (flow->set ==CAKE_SET_SPARSE ) {if (flow->head) {WRITE_ONCE (b->sparse_flow_count, b->sparse_flow_count -1 ); - b->bulk_flow_count++; +WRITE_ONCE (b->bulk_flow_count, b->bulk_flow_count +1 );cake_inc_srchost_bulk_flow_count (b, flow, q->config->flow_mode);cake_inc_dsthost_bulk_flow_count (b, flow, q->config->flow_mode);
@@ -2177,7 +2178,8 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)if (!skb) {/* this queue was actually empty */ if (cobalt_queue_empty (&flow->cvars, &b->cparams, now)) - b->unresponsive_flow_count--; +WRITE_ONCE (b->unresponsive_flow_count, + b->unresponsive_flow_count -1 );if (flow->cvars.p_drop || flow->cvars.count ||ktime_before (now, flow->cvars.drop_next)) {
@@ -2187,7 +2189,7 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)list_move_tail (&flow->flowchain, &b->decaying_flows);if (flow->set ==CAKE_SET_BULK ) { - b->bulk_flow_count--; +WRITE_ONCE (b->bulk_flow_count, b->bulk_flow_count -1 );cake_dec_srchost_bulk_flow_count (b, flow, q->config->flow_mode);cake_dec_dsthost_bulk_flow_count (b, flow, q->config->flow_mode);
@@ -2206,7 +2208,7 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch) flow->set == CAKE_SET_SPARSE_WAIT) {WRITE_ONCE (b->sparse_flow_count, b->sparse_flow_count -1 ); } else if (flow->set == CAKE_SET_BULK) { - b->bulk_flow_count--; +WRITE_ONCE (b->bulk_flow_count, b->bulk_flow_count -1 );cake_dec_srchost_bulk_flow_count (b, flow, q->config->flow_mode);cake_dec_dsthost_bulk_flow_count (b, flow, q->config->flow_mode);
@@ -2329,9 +2331,9 @@ static void cake_set_rate(struct cake_tin_data *b, u64 rate, u32 mtu,u8 rate_shft =0 ;u64 rate_ns =0 ; - b->flow_quantum =1514 ;if (rate) { - b->flow_quantum =max (min (rate >>12 ,1514ULL ),300ULL ); +WRITE_ONCE (b->flow_quantum, +max (min (rate >>12 ,1514ULL ),300ULL )); rate_shft =34 ; rate_ns = ((u64 )NSEC_PER_SEC ) << rate_shft; rate_ns =div64_u64 (rate_ns,max (MIN_RATE , rate));
@@ -2339,8 +2341,10 @@ static void cake_set_rate(struct cake_tin_data *b, u64 rate, u32 mtu, rate_ns >>=1 ; rate_shft--; } - }/* else unlimited, ie. zero delay */ - + }else { +/* else unlimited, ie. zero delay */ +WRITE_ONCE (b->flow_quantum,1514 ); + } b->tin_rate_bps = rate; b->tin_rate_ns = rate_ns; b->tin_rate_shft = rate_shft;
@@ -3056,11 +3060,11 @@ static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d)PUT_TSTAT_U32 (SPARSE_FLOWS ,READ_ONCE (b->sparse_flow_count) +READ_ONCE (b->decaying_flow_count)); -PUT_TSTAT_U32 (BULK_FLOWS , b->bulk_flow_count); -PUT_TSTAT_U32 (UNRESPONSIVE_FLOWS , b->unresponsive_flow_count); -PUT_TSTAT_U32 (MAX_SKBLEN , b->max_skblen); +PUT_TSTAT_U32 (BULK_FLOWS ,READ_ONCE (b->bulk_flow_count)); +PUT_TSTAT_U32 (UNRESPONSIVE_FLOWS ,READ_ONCE (b->unresponsive_flow_count)); +PUT_TSTAT_U32 (MAX_SKBLEN ,READ_ONCE (b->max_skblen)); -PUT_TSTAT_U32 (FLOW_QUANTUM , b->flow_quantum); +PUT_TSTAT_U32 (FLOW_QUANTUM ,READ_ONCE (b->flow_quantum));nla_nest_end (d->skb, ts); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 991/1146 net/sched: sch_cake: annotate data-races in cake_dump_stats() (III)
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 276a98a434964088fccd4745db5b34d6e831e358 ]
cake_dump_stats() runs without qdisc spinlock being held.
In this third patch, I add READ_ONCE()/WRITE_ONCE() annotations for the following fields:
- packets
- tin_dropped
- tin_ecn_mark
- ack_drops
- peak_delay
- avge_delay
- base_delay
Other annotations are added in following patches, to ease code review.
--- net/sched/sch_cake.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-)
net/sched/sch_cake.c +20 -18
@@ -1600,7 +1600,7 @@ static unsigned int cake_drop(struct Qdisc *sch, struct sk_buff **to_free) sch->qstats.backlog -= len; flow->dropped++; - b->tin_dropped++; +WRITE_ONCE (b->tin_dropped, b->tin_dropped +1 );if (q->config->rate_flags &CAKE_FLAG_INGRESS )cake_advance_shaper (q, b, skb, now, true);
@@ -1820,7 +1820,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, numsegs++; slen += segs->len; q->buffer_used += segs->truesize; - b->packets++; +WRITE_ONCE (b->packets, b->packets +1 ); }/* stats */
@@ -1844,7 +1844,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, ack =cake_ack_filter (q, flow);if (ack) { - b->ack_drops++; +WRITE_ONCE (b->ack_drops, b->ack_drops +1 ); sch->qstats.drops++; ack_pkt_len =qdisc_pkt_len (ack); b->bytes += ack_pkt_len;
@@ -1860,7 +1860,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, }/* stats */ - b->packets++; +WRITE_ONCE (b->packets, b->packets +1 ); b->bytes += len - ack_pkt_len; b->backlogs[idx] += len - ack_pkt_len; b->tin_backlog += len - ack_pkt_len;
@@ -2236,7 +2236,7 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch) b->tin_deficit -= len; } flow->dropped++; - b->tin_dropped++; +WRITE_ONCE (b->tin_dropped, b->tin_dropped +1 );qdisc_tree_reduce_backlog (sch,1 ,qdisc_pkt_len (skb));qdisc_qstats_drop (sch);qdisc_dequeue_drop (sch, skb, reason);
@@ -2244,17 +2244,19 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch) goto retry; } - b->tin_ecn_mark += !!flow->cvars.ecn_marked; +WRITE_ONCE (b->tin_ecn_mark, b->tin_ecn_mark + !!flow->cvars.ecn_marked);qdisc_bstats_update (sch, skb);WRITE_ONCE (q->last_active, now);/* collect delay stats */ delay =ktime_to_ns (ktime_sub (now,cobalt_get_enqueue_time (skb))); - b->avge_delay =cake_ewma (b->avge_delay, delay,8 ); - b->peak_delay =cake_ewma (b->peak_delay, delay, - delay > b->peak_delay ?2 :8 ); - b->base_delay =cake_ewma (b->base_delay, delay, - delay < b->base_delay ?2 :8 ); +WRITE_ONCE (b->avge_delay,cake_ewma (b->avge_delay, delay,8 )); +WRITE_ONCE (b->peak_delay, +cake_ewma (b->peak_delay, delay, + delay > b->peak_delay ?2 :8 )); +WRITE_ONCE (b->base_delay, +cake_ewma (b->base_delay, delay, + delay < b->base_delay ?2 :8 )); len =cake_advance_shaper (q, b, skb, now, false); flow->deficit -= len;
@@ -3042,17 +3044,17 @@ static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d)PUT_TSTAT_U32 (INTERVAL_US ,ktime_to_us (ns_to_ktime (b->cparams.interval))); -PUT_TSTAT_U32 (SENT_PACKETS , b->packets); -PUT_TSTAT_U32 (DROPPED_PACKETS , b->tin_dropped); -PUT_TSTAT_U32 (ECN_MARKED_PACKETS , b->tin_ecn_mark); -PUT_TSTAT_U32 (ACKS_DROPPED_PACKETS , b->ack_drops); +PUT_TSTAT_U32 (SENT_PACKETS ,READ_ONCE (b->packets)); +PUT_TSTAT_U32 (DROPPED_PACKETS ,READ_ONCE (b->tin_dropped)); +PUT_TSTAT_U32 (ECN_MARKED_PACKETS ,READ_ONCE (b->tin_ecn_mark)); +PUT_TSTAT_U32 (ACKS_DROPPED_PACKETS ,READ_ONCE (b->ack_drops));PUT_TSTAT_U32 (PEAK_DELAY_US , -ktime_to_us (ns_to_ktime (b->peak_delay))); +ktime_to_us (ns_to_ktime (READ_ONCE (b->peak_delay))));PUT_TSTAT_U32 (AVG_DELAY_US , -ktime_to_us (ns_to_ktime (b->avge_delay))); +ktime_to_us (ns_to_ktime (READ_ONCE (b->avge_delay))));PUT_TSTAT_U32 (BASE_DELAY_US , -ktime_to_us (ns_to_ktime (b->base_delay))); +ktime_to_us (ns_to_ktime (READ_ONCE (b->base_delay))));PUT_TSTAT_U32 (WAY_INDIRECT_HITS ,READ_ONCE (b->way_hits));PUT_TSTAT_U32 (WAY_MISSES ,READ_ONCE (b->way_misses));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 992/1146 net/sched: sch_cake: annotate data-races in cake_dump_stats() (IV)
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 8fab48d87745a6ab1cec594b8d5865d9ae2db879 ]
cake_dump_stats() runs without qdisc spinlock being held.
In this fourth patch, I add READ_ONCE()/WRITE_ONCE() annotations for the following fields:
- avg_peak_bandwidth
- buffer_limit
- buffer_max_used
- avg_netoff
- max_netlen
- max_adjlen
- min_netlen
- min_adjlen
- active_queues
- tin_rate_bps
- bytes
- tin_backlog
Other annotations are added in following patch, to ease code review.
--- net/sched/sch_cake.c | 90 ++++++++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 44 deletions(-)
net/sched/sch_cake.c +46 -44
@@ -1379,9 +1379,9 @@ static u32 cake_calc_overhead(struct cake_sched_data *qd, u32 len, u32 off) len -= off;if (qd->max_netlen < len) - qd->max_netlen = len; +WRITE_ONCE (qd->max_netlen, len);if (qd->min_netlen > len) - qd->min_netlen = len; +WRITE_ONCE (qd->min_netlen, len); len += q->rate_overhead;
@@ -1401,9 +1401,9 @@ static u32 cake_calc_overhead(struct cake_sched_data *qd, u32 len, u32 off) }if (qd->max_adjlen < len) - qd->max_adjlen = len; +WRITE_ONCE (qd->max_adjlen, len);if (qd->min_adjlen > len) - qd->min_adjlen = len; +WRITE_ONCE (qd->min_adjlen, len);return len; }
@@ -1416,7 +1416,7 @@ static u32 cake_overhead(struct cake_sched_data *q, const struct sk_buff *skb)u16 segs =qdisc_pkt_segs (skb);u32 len =qdisc_pkt_len (skb); - q->avg_netoff =cake_ewma (q->avg_netoff, off <<16 ,8 ); +WRITE_ONCE (q->avg_netoff,cake_ewma (q->avg_netoff, off <<16 ,8 ));if (segs ==1 )return cake_calc_overhead (q, len, off);
@@ -1596,7 +1596,7 @@ static unsigned int cake_drop(struct Qdisc *sch, struct sk_buff **to_free) len =qdisc_pkt_len (skb); q->buffer_used -= skb->truesize; b->backlogs[idx] -= len; - b->tin_backlog -= len; +WRITE_ONCE (b->tin_backlog, b->tin_backlog - len); sch->qstats.backlog -= len; flow->dropped++;
@@ -1824,11 +1824,11 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, }/* stats */ - b->bytes += slen; b->backlogs[idx] += slen; - b->tin_backlog += slen; sch->qstats.backlog += slen; q->avg_window_bytes += slen; +WRITE_ONCE (b->bytes, b->bytes + slen); +WRITE_ONCE (b->tin_backlog, b->tin_backlog + slen);qdisc_tree_reduce_backlog (sch,1 -numsegs, len-slen);consume_skb (skb);
@@ -1847,7 +1847,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,WRITE_ONCE (b->ack_drops, b->ack_drops +1 ); sch->qstats.drops++; ack_pkt_len =qdisc_pkt_len (ack); - b->bytes += ack_pkt_len; +WRITE_ONCE (b->bytes, b->bytes + ack_pkt_len); q->buffer_used += skb->truesize - ack->truesize;if (q->config->rate_flags &CAKE_FLAG_INGRESS )cake_advance_shaper (q, b, ack, now, true);
@@ -1861,11 +1861,11 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,/* stats */ WRITE_ONCE (b->packets, b->packets +1 ); - b->bytes += len - ack_pkt_len; b->backlogs[idx] += len - ack_pkt_len; - b->tin_backlog += len - ack_pkt_len; sch->qstats.backlog += len - ack_pkt_len; q->avg_window_bytes += len - ack_pkt_len; +WRITE_ONCE (b->bytes, b->bytes + len - ack_pkt_len); +WRITE_ONCE (b->tin_backlog, b->tin_backlog + len - ack_pkt_len); }if (q->overflow_timeout)
@@ -1895,9 +1895,9 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,u64 b = q->avg_window_bytes * (u64 )NSEC_PER_SEC ; b =div64_u64 (b, window_interval); - q->avg_peak_bandwidth = -cake_ewma (q->avg_peak_bandwidth, b, - b > q->avg_peak_bandwidth ?2 :8 ); +WRITE_ONCE (q->avg_peak_bandwidth, +cake_ewma (q->avg_peak_bandwidth, b, + b > q->avg_peak_bandwidth ?2 :8 )); q->avg_window_bytes =0 ; q->avg_window_begin = now;
@@ -1938,7 +1938,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, }if (q->buffer_used > q->buffer_max_used) - q->buffer_max_used = q->buffer_used; +WRITE_ONCE (q->buffer_max_used, q->buffer_used);if (q->buffer_used <= q->buffer_limit)return NET_XMIT_SUCCESS ;
@@ -1978,7 +1978,7 @@ static struct sk_buff *cake_dequeue_one(struct Qdisc *sch) skb =dequeue_head (flow); len =qdisc_pkt_len (skb); b->backlogs[q->cur_flow] -= len; - b->tin_backlog -= len; +WRITE_ONCE (b->tin_backlog, b->tin_backlog - len); sch->qstats.backlog -= len; q->buffer_used -= skb->truesize; sch->q.qlen--;
@@ -2043,7 +2043,7 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)cake_configure_rates (sch, new_rate, true); q->last_checked_active = now; - q->active_queues = num_active_qs; +WRITE_ONCE (q->active_queues, num_active_qs); } begin:
@@ -2347,7 +2347,7 @@ static void cake_set_rate(struct cake_tin_data *b, u64 rate, u32 mtu,/* else unlimited, ie. zero delay */ WRITE_ONCE (b->flow_quantum,1514 ); } - b->tin_rate_bps = rate; +WRITE_ONCE (b->tin_rate_bps, rate); b->tin_rate_ns = rate_ns; b->tin_rate_shft = rate_shft;
@@ -2617,25 +2617,27 @@ static void cake_reconfigure(struct Qdisc *sch) {struct cake_sched_data *qd =qdisc_priv (sch);struct cake_sched_config *q = qd->config; +u32 buffer_limit;cake_configure_rates (sch, qd->config->rate_bps, false);if (q->buffer_config_limit) { - qd->buffer_limit = q->buffer_config_limit; + buffer_limit = q->buffer_config_limit; }else if (q->rate_bps) {u64 t = q->rate_bps * q->interval;do_div (t,USEC_PER_SEC /4 ); - qd->buffer_limit =max_t (u32, t,4U <<20 ); + buffer_limit =max_t (u32, t,4U <<20 ); }else { - qd->buffer_limit = ~0 ; + buffer_limit = ~0 ; } sch->flags &= ~TCQ_F_CAN_BYPASS ; - qd->buffer_limit =min (qd->buffer_limit, -max (sch->limit *psched_mtu (qdisc_dev (sch)), - q->buffer_config_limit)); +WRITE_ONCE (qd->buffer_limit, +min (buffer_limit, +max (sch->limit *psched_mtu (qdisc_dev (sch)), + q->buffer_config_limit))); } static int cake_config_change(struct cake_sched_config *q, struct nlattr *opt,
@@ -2780,10 +2782,10 @@ static int cake_change(struct Qdisc *sch, struct nlattr *opt,return ret;if (overhead_changed) { - qd->max_netlen =0 ; - qd->max_adjlen =0 ; - qd->min_netlen = ~0 ; - qd->min_adjlen = ~0 ; +WRITE_ONCE (qd->max_netlen,0 ); +WRITE_ONCE (qd->max_adjlen,0 ); +WRITE_ONCE (qd->min_netlen, ~0 ); +WRITE_ONCE (qd->min_adjlen, ~0 ); }if (qd->tins) {
@@ -3001,15 +3003,15 @@ static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d) goto nla_put_failure; \ }while (0 ) -PUT_STAT_U64 (CAPACITY_ESTIMATE64 , q->avg_peak_bandwidth); -PUT_STAT_U32 (MEMORY_LIMIT , q->buffer_limit); -PUT_STAT_U32 (MEMORY_USED , q->buffer_max_used); -PUT_STAT_U32 (AVG_NETOFF , ((q->avg_netoff +0x8000 ) >>16 )); -PUT_STAT_U32 (MAX_NETLEN , q->max_netlen); -PUT_STAT_U32 (MAX_ADJLEN , q->max_adjlen); -PUT_STAT_U32 (MIN_NETLEN , q->min_netlen); -PUT_STAT_U32 (MIN_ADJLEN , q->min_adjlen); -PUT_STAT_U32 (ACTIVE_QUEUES , q->active_queues); +PUT_STAT_U64 (CAPACITY_ESTIMATE64 ,READ_ONCE (q->avg_peak_bandwidth)); +PUT_STAT_U32 (MEMORY_LIMIT ,READ_ONCE (q->buffer_limit)); +PUT_STAT_U32 (MEMORY_USED ,READ_ONCE (q->buffer_max_used)); +PUT_STAT_U32 (AVG_NETOFF , ((READ_ONCE (q->avg_netoff) +0x8000 ) >>16 )); +PUT_STAT_U32 (MAX_NETLEN ,READ_ONCE (q->max_netlen)); +PUT_STAT_U32 (MAX_ADJLEN ,READ_ONCE (q->max_adjlen)); +PUT_STAT_U32 (MIN_NETLEN ,READ_ONCE (q->min_netlen)); +PUT_STAT_U32 (MIN_ADJLEN ,READ_ONCE (q->min_adjlen)); +PUT_STAT_U32 (ACTIVE_QUEUES ,READ_ONCE (q->active_queues));#undef PUT_STAT_U32#undef PUT_STAT_U64
@@ -3035,9 +3037,9 @@ static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d)if (!ts) goto nla_put_failure; -PUT_TSTAT_U64 (THRESHOLD_RATE64 , b->tin_rate_bps); -PUT_TSTAT_U64 (SENT_BYTES64 , b->bytes); -PUT_TSTAT_U32 (BACKLOG_BYTES , b->tin_backlog); +PUT_TSTAT_U64 (THRESHOLD_RATE64 ,READ_ONCE (b->tin_rate_bps)); +PUT_TSTAT_U64 (SENT_BYTES64 ,READ_ONCE (b->bytes)); +PUT_TSTAT_U32 (BACKLOG_BYTES ,READ_ONCE (b->tin_backlog));PUT_TSTAT_U32 (TARGET_US ,ktime_to_us (ns_to_ktime (b->cparams.target)));
@@ -3304,10 +3306,10 @@ static int cake_mq_change(struct Qdisc *sch, struct nlattr *opt,struct cake_sched_data *qd =qdisc_priv (chld);if (overhead_changed) { - qd->max_netlen =0 ; - qd->max_adjlen =0 ; - qd->min_netlen = ~0 ; - qd->min_adjlen = ~0 ; +WRITE_ONCE (qd->max_netlen,0 ); +WRITE_ONCE (qd->max_adjlen,0 ); +WRITE_ONCE (qd->min_netlen, ~0 ); +WRITE_ONCE (qd->min_adjlen, ~0 ); }if (qd->tins) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 993/1146 net/sched: sch_cake: annotate data-races in cake_dump_stats() (V)
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit a6c95b833dc17e84d16a8ac0f40fd0931616a52d ]
cake_dump_stats() runs without qdisc spinlock being held.
In this final patch, I add READ_ONCE()/WRITE_ONCE() annotations for cparams.target and cparams.interval.
--- net/sched/sch_cake.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
net/sched/sch_cake.c +7 -6
@@ -2356,10 +2356,11 @@ static void cake_set_rate(struct cake_tin_data *b, u64 rate, u32 mtu, byte_target_ns = (byte_target * rate_ns) >> rate_shft; - b->cparams.target =max ((byte_target_ns *3 ) /2 , target_ns); - b->cparams.interval =max (rtt_est_ns + - b->cparams.target - target_ns, - b->cparams.target *2 ); +WRITE_ONCE (b->cparams.target, +max ((byte_target_ns *3 ) /2 , target_ns)); +WRITE_ONCE (b->cparams.interval, +max (rtt_est_ns + b->cparams.target - target_ns, + b->cparams.target *2 )); b->cparams.mtu_time = byte_target_ns; b->cparams.p_inc =1 <<24 ;/* 1/256 */ b->cparams.p_dec =1 <<20 ;/* 1/4096 */
@@ -3042,9 +3043,9 @@ static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d)PUT_TSTAT_U32 (BACKLOG_BYTES ,READ_ONCE (b->tin_backlog));PUT_TSTAT_U32 (TARGET_US , -ktime_to_us (ns_to_ktime (b->cparams.target))); +ktime_to_us (ns_to_ktime (READ_ONCE (b->cparams.target))));PUT_TSTAT_U32 (INTERVAL_US , -ktime_to_us (ns_to_ktime (b->cparams.interval))); +ktime_to_us (ns_to_ktime (READ_ONCE (b->cparams.interval))));PUT_TSTAT_U32 (SENT_PACKETS ,READ_ONCE (b->packets));PUT_TSTAT_U32 (DROPPED_PACKETS ,READ_ONCE (b->tin_dropped));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 994/1146 netconsole: return count instead of strnlen(buf, count) from store callbacks
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit d62c6f2df5c0e1390b9a1f45b1b52689e3f234f0 ]
Several configfs store callbacks in netconsole end with:
ret = strnlen(buf, count);
This under-reports the number of bytes consumed when the input contains an embedded NUL within count, telling the VFS that fewer bytes were written than userspace actually handed in. A conformant partial-write loop would then retry the trailing bytes against a callback that has already accepted them.
Every other configfs driver in the tree returns count directly from its store callbacks once parsing has succeeded, including drivers/nvme/target/configfs.c, drivers/gpio/gpio-sim.c, drivers/most/configfs.c, drivers/block/null_blk/main.c, drivers/pci/endpoint/pci-ep-cfs.c, and the rest of the configfs users. netconsole was the outlier (along with drivers/infiniband/core/cma_configfs.c, which has the same latent issue).
Align netconsole with the rest of the configfs ecosystem: return count once the parser/validator has accepted the input. The numeric and boolean parsers (kstrtobool, kstrtou16, mac_pton, netpoll_parse_ip_addr) have already validated the meaningful prefix; any trailing bytes are padding and should simply be reported as consumed.
--- drivers/net/netconsole.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-)
drivers/net/netconsole.c +13 -13
@@ -752,7 +752,7 @@ static ssize_t enabled_store(struct config_item *item,unregister_netcons_consoles (); } - ret =strnlen (buf, count); + ret = count;/* Deferred cleanup */ netconsole_process_cleanups (); out_unlock:
@@ -781,7 +781,7 @@ static ssize_t release_store(struct config_item *item, const char *buf, nt->release = release; - ret =strnlen (buf, count); + ret = count; out_unlock:dynamic_netconsole_mutex_unlock ();return ret;
@@ -807,7 +807,7 @@ static ssize_t extended_store(struct config_item *item, const char *buf, goto out_unlock; nt->extended = extended; - ret =strnlen (buf, count); + ret = count; out_unlock:dynamic_netconsole_mutex_unlock ();return ret;
@@ -830,7 +830,7 @@ static ssize_t dev_name_store(struct config_item *item, const char *buf,trim_newline (nt->np.dev_name,IFNAMSIZ );dynamic_netconsole_mutex_unlock (); -return strnlen (buf, count); +return count; } static ssize_t local_port_store(struct config_item *item, const char *buf,
@@ -849,7 +849,7 @@ static ssize_t local_port_store(struct config_item *item, const char *buf, ret =kstrtou16 (buf,10 , &nt->np.local_port);if (ret <0 ) goto out_unlock; - ret =strnlen (buf, count); + ret = count; out_unlock:dynamic_netconsole_mutex_unlock ();return ret;
@@ -871,7 +871,7 @@ static ssize_t remote_port_store(struct config_item *item, ret =kstrtou16 (buf,10 , &nt->np.remote_port);if (ret <0 ) goto out_unlock; - ret =strnlen (buf, count); + ret = count; out_unlock:dynamic_netconsole_mutex_unlock ();return ret;
@@ -896,7 +896,7 @@ static ssize_t local_ip_store(struct config_item *item, const char *buf, goto out_unlock; nt->np.ipv6 = !!ipv6; - ret =strnlen (buf, count); + ret = count; out_unlock:dynamic_netconsole_mutex_unlock ();return ret;
@@ -921,7 +921,7 @@ static ssize_t remote_ip_store(struct config_item *item, const char *buf, goto out_unlock; nt->np.ipv6 = !!ipv6; - ret =strnlen (buf, count); + ret = count; out_unlock:dynamic_netconsole_mutex_unlock ();return ret;
@@ -957,7 +957,7 @@ static ssize_t remote_mac_store(struct config_item *item, const char *buf, goto out_unlock;memcpy (nt->np.remote_mac, remote_mac,ETH_ALEN ); - ret =strnlen (buf, count); + ret = count; out_unlock:dynamic_netconsole_mutex_unlock ();return ret;
@@ -1133,7 +1133,7 @@ static ssize_t sysdata_msgid_enabled_store(struct config_item *item,disable_sysdata_feature (nt,SYSDATA_MSGID ); unlock_ok: - ret =strnlen (buf, count); + ret = count;dynamic_netconsole_mutex_unlock ();mutex_unlock (&netconsole_subsys.su_mutex);return ret;
@@ -1162,7 +1162,7 @@ static ssize_t sysdata_release_enabled_store(struct config_item *item,disable_sysdata_feature (nt,SYSDATA_RELEASE ); unlock_ok: - ret =strnlen (buf, count); + ret = count;dynamic_netconsole_mutex_unlock ();mutex_unlock (&netconsole_subsys.su_mutex);return ret;
@@ -1191,7 +1191,7 @@ static ssize_t sysdata_taskname_enabled_store(struct config_item *item,disable_sysdata_feature (nt,SYSDATA_TASKNAME ); unlock_ok: - ret =strnlen (buf, count); + ret = count;dynamic_netconsole_mutex_unlock ();mutex_unlock (&netconsole_subsys.su_mutex);return ret;
@@ -1225,7 +1225,7 @@ static ssize_t sysdata_cpu_nr_enabled_store(struct config_item *item,disable_sysdata_feature (nt,SYSDATA_CPU_NR ); unlock_ok: - ret =strnlen (buf, count); + ret = count;dynamic_netconsole_mutex_unlock ();mutex_unlock (&netconsole_subsys.su_mutex);return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 995/1146 netconsole: avoid clobbering userdatum value on truncated write
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit e6dd94252b0fa7b4fcc00577c6898432c5d97a08 ]
userdatum_value_store() bounds count by MAX_EXTRADATA_VALUE_LEN (200) and then copies straight into udm->value, which is itself 200 bytes:
if (count > MAX_EXTRADATA_VALUE_LEN) return -EMSGSIZE; ... ret = strscpy(udm->value, buf, sizeof(udm->value)); if (ret < 0) goto out_unlock;
If userspace writes exactly MAX_EXTRADATA_VALUE_LEN bytes with no NUL within them, strscpy() copies 199 bytes plus a NUL into udm->value and returns -E2BIG. The function jumps to out_unlock and reports the error to userspace, but udm->value has already been overwritten with the truncated string and update_userdata() is skipped, so the corruption is not yet visible on the wire.
The next successful write to any userdatum entry under the same target calls update_userdata(), which packs udm->value into the active netconsole payload. From that point on, every netconsole message carries the silently truncated value, and userspace has no indication that a previous, error-returning write left state behind.
Tighten the entry check from "count > MAX_EXTRADATA_VALUE_LEN" to "count >= MAX_EXTRADATA_VALUE_LEN". With count strictly less than sizeof(udm->value), strscpy() can no longer return -E2BIG here, so the corrupting truncation path is removed entirely.
--- drivers/net/netconsole.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-)
drivers/net/netconsole.c +3 -5
@@ -1076,15 +1076,13 @@ static ssize_t userdatum_value_store(struct config_item *item, const char *buf,struct userdata *ud;ssize_t ret; -if (count >MAX_EXTRADATA_VALUE_LEN ) +if (count >=MAX_EXTRADATA_VALUE_LEN )return -EMSGSIZE ;mutex_lock (&netconsole_subsys.su_mutex);dynamic_netconsole_mutex_lock (); - - ret =strscpy (udm->value, buf,sizeof (udm->value)); -if (ret <0 ) - goto out_unlock; +/* count is bounded above, so strscpy() cannot truncate here */ +strscpy (udm->value, buf,sizeof (udm->value));trim_newline (udm->value,sizeof (udm->value)); ud =to_userdata (item->ci_parent);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 996/1146 netconsole: propagate device name truncation in dev_name_store()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit 92ceb7bff62c2606f664c204750eca0b85d44112 ]
dev_name_store() calls strscpy(nt->np.dev_name, buf, IFNAMSIZ) without checking the return value. If userspace writes an interface name longer than IFNAMSIZ - 1, strscpy() silently truncates and returns -E2BIG, but the function ignores it and reports a fully successful write back to userspace.
If a real interface happens to match the truncated name, netconsole will bind to the wrong device on the next enable, sending kernel logs and panic output to an unintended network segment with no indication to userspace that anything was rewritten.
Reject writes whose length cannot fit in nt->np.dev_name up front:
if (count >= IFNAMSIZ) return -ENAMETOOLONG;
This is not a big deal of a problem, but, it is still the correct approach.
--- drivers/net/netconsole.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/net/netconsole.c +7 -0
@@ -817,6 +817,13 @@ static ssize_t dev_name_store(struct config_item *item, const char *buf, size_t count) {struct netconsole_target *nt =to_target (item); +size_t len = count; + +/* Account for a trailing newline appended by tools like echo */ +if (len && buf[len -1 ] =='\n' ) + len--; +if (len >=IFNAMSIZ ) +return -ENAMETOOLONG ;dynamic_netconsole_mutex_lock ();if (nt->state ==STATE_ENABLED ) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 997/1146 netconsole: restore userdatum value on update_userdata() failure
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit 869cd6490fafe09c89a15d01610e8a03932d79f0 ]
userdatum_value_store() updates udm->value first and only then calls update_userdata() to rebuild the on-the-wire payload. If update_userdata() fails (e.g. -ENOMEM from kmalloc), the function returns the error to userspace, but udm->value already holds the new string while the live nt->userdata buffer still reflects the old one.
The next successful write to any sibling userdatum on the same target will call update_userdata() again, which walks every entry and packs the now-stale udm->value into the payload. The failed write is thus silently activated later, with no indication to userspace that the value it tried to set was rejected.
Snapshot the previous value before overwriting udm->value and restore it if update_userdata() fails so the visible state and the active payload stay consistent.
--- drivers/net/netconsole.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/net/netconsole.c +7 -1
@@ -1079,6 +1079,7 @@ static ssize_t userdatum_value_store(struct config_item *item, const char *buf, size_t count) {struct userdatum *udm =to_userdatum (item); +char old_value[MAX_EXTRADATA_VALUE_LEN ];struct netconsole_target *nt;struct userdata *ud;ssize_t ret;
@@ -1088,6 +1089,8 @@ static ssize_t userdatum_value_store(struct config_item *item, const char *buf,mutex_lock (&netconsole_subsys.su_mutex);dynamic_netconsole_mutex_lock (); +/* Snapshot for rollback if update_userdata() fails below */ +strscpy (old_value, udm->value,sizeof (old_value));/* count is bounded above, so strscpy() cannot truncate here */ strscpy (udm->value, buf,sizeof (udm->value));trim_newline (udm->value,sizeof (udm->value));
@@ -1095,8 +1098,11 @@ static ssize_t userdatum_value_store(struct config_item *item, const char *buf, ud =to_userdata (item->ci_parent); nt =userdata_to_target (ud); ret =update_userdata (nt); -if (ret <0 ) +if (ret <0 ) { +/* Restore the previous value so it matches the live payload */ +strscpy (udm->value, old_value,sizeof (udm->value)); goto out_unlock; + } ret = count; out_unlock:dynamic_netconsole_mutex_unlock ();
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 998/1146 ALSA: hda/conexant: Fix missing error check for jack detection
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: wangdicheng <[email protected]>
[ Upstream commit b0e2333a231107adedd38c6fcfe1adc6162716fc ]
In cx_probe(), the return value of snd_hda_jack_detect_enable_callback() is ignored. This function returns a pointer, and if it fails (e.g., due to memory allocation failure), it returns an error pointer which must be checked using IS_ERR().
If the registration fails, the driver continues to probe, but the jack detection callback will not be registered. This can lead to a kernel crash later when the driver attempts to handle jack events or accesses the uninitialized structure.
Check the return value using IS_ERR() and propagate the error via PTR_ERR() to the probe caller.
--- sound/hda/codecs/conexant.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
sound/hda/codecs/conexant.c +7 -1
@@ -1183,6 +1183,7 @@ static void add_cx5051_fake_mutes(struct hda_codec *codec)static int cx_probe (struct hda_codec *codec,const struct hda_device_id *id) {struct conexant_spec *spec; +struct hda_jack_callback *callback;int err;codec_info (codec,"%s: BIOS auto-probing.\n" , codec->core.chip_name);
@@ -1198,7 +1199,12 @@ static int cx_probe(struct hda_codec *codec, const struct hda_device_id *id)case 0x14f11f86 :case 0x14f11f87 : spec->is_cx11880_sn6140 = true; -snd_hda_jack_detect_enable_callback (codec,0x19 , cx_update_headset_mic_vref); + callback =snd_hda_jack_detect_enable_callback (codec,0x19 , + cx_update_headset_mic_vref); +if (IS_ERR (callback)) { + err =PTR_ERR (callback); + goto error; + }break ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 999/1146 ALSA: hda: cs35l56: Fix uninitialized value in cs35l56_hda_read_acpi()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Richard Fitzgerald <[email protected]>
[ Upstream commit 90df4957a3271adf391b3432cd76a40887cf3273 ]
Eliminate the uninitialized 'nval' in cs35l56_hda_read_acpi() if a system-specific quirk overrides processing of the dev-index property. The value is now stored in a new 'num_amps' member of struct cs35l56_hda so that the quirk handler can set the value.
The quirk for the Lenovo Yoga Book 9i GenX replaces the values from the dev-index property with hardcoded indexes. So cs35l56_hda_read_acpi() would then skip reading the property. But this left the 'nval' local variable uninitialized when it is later passed to cirrus_scodec_get_speaker_id().
--- sound/hda/codecs/side-codecs/cs35l56_hda.c | 12 +++++++----- sound/hda/codecs/side-codecs/cs35l56_hda.h | 1 + 2 files changed, 8 insertions(+), 5 deletions(-)
sound/hda/codecs/side-codecs/cs35l56_hda.c +7 -5
@@ -976,6 +976,7 @@ static int cs35l56_hda_system_resume(struct device *dev)static int cs35l56_hda_fixup_yoga9 (struct cs35l56_hda *cs35l56,int *bus_addr) {/* The cirrus,dev-index property has the wrong values */ + cs35l56->num_amps =2 ;switch (*bus_addr) {case 0x30 : cs35l56->index =1 ;
@@ -1025,7 +1026,6 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)char hid_string[8 ];struct acpi_device *adev;const char *property, *sub; -size_t nval;int i, ret;/*
@@ -1061,13 +1061,14 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id) ret = -EINVAL ; goto err; } - nval = ret; + cs35l56->num_amps = ret; - ret =device_property_read_u32_array (cs35l56->base.dev, property, values, nval); + ret =device_property_read_u32_array (cs35l56->base.dev, property, values, + cs35l56->num_amps);if (ret) goto err; -for (i =0 ; i < nval; i++) { +for (i =0 ; i < cs35l56->num_amps; i++) {if (values[i] == id) { cs35l56->index = i;break ;
@@ -1090,7 +1091,8 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)"Read ACPI _SUB failed(%ld): fallback to generic firmware\n" , PTR_ERR(sub)); }else { - ret =cirrus_scodec_get_speaker_id (cs35l56->base.dev, cs35l56->index, nval,-1 ); + ret =cirrus_scodec_get_speaker_id (cs35l56->base.dev, cs35l56->index, + cs35l56->num_amps,-1 );if (ret == -ENOENT ) { cs35l56->system_name = sub; }else if (ret >=0 ) {
sound/hda/codecs/side-codecs/cs35l56_hda.h +1 -0
@@ -26,6 +26,7 @@ struct cs35l56_hda {struct work_struct dsp_work;int index; +int num_amps;const char *system_name;const char *amp_name;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1000/1146 ALSA: hda/tas2781: Fix incorrect bit update for non-book-zero or book 0 pages >1
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shenghao Ding <[email protected]>
[ Upstream commit e052a1f7199260eda4d6ca08a59c3b98738f8491 ]
In TAS2781 SPI mode, when accessing non-book-zero or page numbers greater than 1 in book 0, an additional byte must be read. The first byte in such cases is a dummy byte and should be ignored.
--- sound/hda/codecs/side-codecs/tas2781_hda_spi.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
sound/hda/codecs/side-codecs/tas2781_hda_spi.c +11 -3
@@ -132,10 +132,18 @@ static int tasdevice_spi_dev_update_bits(struct tasdevice_priv *tas_priv,int ret, val;/* -* In our TAS2781 SPI mode, read/write was masked in last bit of -* address, it cause regmap_update_bits() not work as expected. +* In TAS2781 SPI mode, when accessing non-book-zero or page numbers +* greater than 1 in book 0, an additional byte must be read. The +* first byte in such cases is a dummy byte and should be ignored. */ - ret =tasdevice_dev_read (tas_priv, chn, reg, &val); +if ((TASDEVICE_BOOK_ID (reg) >0 ) || (TASDEVICE_PAGE_ID (reg) >1 )) { +unsigned char buf[2 ]; + + ret =tasdevice_dev_bulk_read (tas_priv, chn, reg, buf,2 ); + val = buf[1 ]; + }else { + ret =tasdevice_dev_read (tas_priv, chn, reg, &val); + }if (ret <0 ) {dev_err (tas_priv->dev,"%s, E=%d\n" , __func__, ret);return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1001/1146 futex: Prevent lockup in requeue-PI during signal/ timeout wakeup
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sebastian Andrzej Siewior <[email protected]>
[ Upstream commit bc7304f3ae20972d11db6e0b1b541c63feda5f05 ]
During wait-requeue-pi (task A) and requeue-PI (task B) the following race can happen:
Task A Task B
futex_wait_requeue_pi()
futex_setup_timer()
futex_do_wait()
futex_requeue()
CLASS(hb, hb1)(&key1);
CLASS(hb, hb2)(&key2);
*timeout*
futex_requeue_pi_wakeup_sync()
requeue_state = Q_REQUEUE_PI_IGNORE
*blocks on hb->lock*
futex_proxy_trylock_atomic()
futex_requeue_pi_prepare()
Q_REQUEUE_PI_IGNORE => -EAGAIN
double_unlock_hb(hb1, hb2)
*retry*Task B acquires both hb locks and attempts to acquire the PI-lock of the top most waiter (task B). Task A is leaving early due to a signal/ timeout and started removing itself from the queue. It updates its requeue_state but can not remove it from the list because this requires the hb lock which is owned by task B.
Usually task A is able to swoop the lock after task B unlocked it. However if task B is of higher priority then task A may not be able to wake up in time and acquire the lock before task B gets it again. Especially on a UP system where A is never scheduled.
As a result task A blocks on the lock and task B busy loops, trying to make progress but live locks the system instead. Tragic.
This can be fixed by removing the top most waiter from the list in this case. This allows task B to grab the next top waiter (if any) in the next iteration and make progress.
Remove the top most waiter if futex_requeue_pi_prepare() fails. Let the waiter conditionally remove itself from the list in handle_early_requeue_pi_wakeup().
--- kernel/futex/requeue.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
kernel/futex/requeue.c +9 -4
@@ -319,8 +319,11 @@ futex_proxy_trylock_atomic(u32 __user *pifutex, struct futex_hash_bucket *hb1,return -EINVAL ;/* Ensure that this does not race against an early wakeup */ -if (!futex_requeue_pi_prepare (top_waiter,NULL )) +if (!futex_requeue_pi_prepare (top_waiter,NULL )) { +plist_del (&top_waiter->list, &hb1->chain); +futex_hb_waiters_dec (hb1);return -EAGAIN ; + }/* * Try to take the lock for top_waiter and set the FUTEX_WAITERS bit
@@ -722,10 +725,12 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,/* * We were woken prior to requeue by a timeout or a signal. -* Unqueue the futex_q and determine which it was. +* Conditionally unqueue the futex_q and determine which it was. */ -plist_del (&q->list, &hb->chain); -futex_hb_waiters_dec (hb); +if (!plist_node_empty (&q->list)) { +plist_del (&q->list, &hb->chain); +futex_hb_waiters_dec (hb); + }/* Handle spurious wakeups gracefully */ ret = -EWOULDBLOCK ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1002/1146 drm/amd/display: Allow embedded connectors without DDC
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
[ Upstream commit 494941aa772dab79251543764db6cd14bd337e43 ]
On some laptops, the embedded panel may not have
a DDC (display data channel) available. On these,
the EDID may be hardcoded in ACPI or the VBIOS.
In this case, use GPIO_DDC_LINE_UNKNOWN and don't fail.
--- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c | 3 +++ drivers/gpu/drm/amd/display/dc/link/link_factory.c | 4 +++- 3 files changed, 7 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/display/dc/dc.h +1 -1
@@ -1638,7 +1638,7 @@ struct dc_scratch_space {struct dc_link_training_overrides preferred_training_settings;struct dp_audio_test_data audio_test_data; -uint8_t ddc_hw_inst; +enum gpio_ddc_line ddc_hw_inst;uint8_t hpd_src;
drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c +3 -0
@@ -646,6 +646,9 @@ enum gpio_result dal_ddc_change_mode(enum gpio_ddc_line dal_ddc_get_line (const struct ddc *ddc) { +if (!ddc) +return GPIO_DDC_LINE_UNKNOWN ; +return (enum gpio_ddc_line )dal_gpio_get_enum (ddc->pin_data); }
drivers/gpu/drm/amd/display/dc/link/link_factory.c +3 -1
@@ -549,7 +549,9 @@ static bool construct_phy(struct dc_link *link, goto ddc_create_fail; } -if (!link->ddc->ddc_pin) { +/* Embedded display connectors such as LVDS may not have DDC. */ +if (!link->ddc->ddc_pin && + !dc_is_embedded_signal (link->connector_signal)) {DC_ERROR ("Failed to get I2C info for connector!\n" ); goto ddc_create_fail; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1003/1146 drm/amd/display: Allow DCE link encoder without AUX registers
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
[ Upstream commit ac27e3f99035f132f23bc0409d0e57f11f054c70 ]
Allow constructing the DCE link encoder without DDC, which means the AUX registers array will be NULL.
This is necessary to support embedded connectors without DDC.
--- drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +3 -1
@@ -1071,7 +1071,9 @@ void dce110_link_encoder_hw_init(ASSERT (result ==BP_RESULT_OK ); } -aux_initialize (enc110); + +if (enc110->aux_regs) +aux_initialize (enc110);/* reinitialize HPD. * hpd_initialize() will pass DIG_FE id to HW context.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1004/1146 drm/amd/display: Allow constructing DCE6 link encoder without DDC
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
[ Upstream commit 880498a1943f865529819f778df3b9945ca57262 ]
When the DDC channel ID is set to CHANNEL_ID_UNKNOWN, pass NULL to the AUX regs array.
This is necessary to support embedded connectors without DDC.
--- drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c +2 -1
@@ -753,7 +753,8 @@ static struct link_encoder *dce60_link_encoder_create( enc_init_data, &link_enc_feature, &link_enc_regs[link_regs_id], - &link_enc_aux_regs[enc_init_data->channel -1 ], + enc_init_data->channel ==CHANNEL_ID_UNKNOWN ? +NULL : &link_enc_aux_regs[enc_init_data->channel -1 ], enc_init_data->hpd_source >=ARRAY_SIZE (link_enc_hpd_regs) ? NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]);return &enc110->base;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1005/1146 drm/amd/display: Allow constructing DCE8 link encoder without DDC
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
[ Upstream commit 60af4605ef35ecb7ad649a8534b83a2f7c69576d ]
When the DDC channel ID is set to CHANNEL_ID_UNKNOWN, pass NULL to the AUX regs array.
This is necessary to support embedded connectors without DDC.
--- drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c +2 -1
@@ -759,7 +759,8 @@ static struct link_encoder *dce80_link_encoder_create( enc_init_data, &link_enc_feature, &link_enc_regs[link_regs_id], - &link_enc_aux_regs[enc_init_data->channel -1 ], + enc_init_data->channel ==CHANNEL_ID_UNKNOWN ? +NULL : &link_enc_aux_regs[enc_init_data->channel -1 ], enc_init_data->hpd_source >=ARRAY_SIZE (link_enc_hpd_regs) ? NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]);return &enc110->base;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1006/1146 drm/amd/display: Read EDID from VBIOS embedded panel info
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
[ Upstream commit 9ea16f64189bf7b6ba50fc7f0325b3c1f836d105 ]
Some board manufacturers hardcode the EDID for the embedded panel in the VBIOS. This EDID should be used when the panel doesn't have a DDC.
For reference, see the legacy non-DC display code:amdgpu_atombios_encoder_get_lcd_info()
This is necessary to support embedded connectors without DDC.
--- .../gpu/drm/amd/display/dc/bios/bios_parser.c | 62 +++++++++++++++++++ .../display/include/grph_object_ctrl_defs.h | 4 ++ 2 files changed, 66 insertions(+)
drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +62 -0
@@ -1295,6 +1295,60 @@ static enum bp_result bios_parser_get_embedded_panel_info(return BP_RESULT_FAILURE ; } +static enum bp_result get_embedded_panel_extra_info ( +struct bios_parser *bp, +struct embedded_panel_info *info, +const uint32_t table_offset) +{ +uint8_t *record =bios_get_image (&bp->base, table_offset,1 ); +ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record; +ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record; + +while (*record !=ATOM_RECORD_END_TYPE ) { +switch (*record) { +case LCD_MODE_PATCH_RECORD_MODE_TYPE : + record +=sizeof (ATOM_PATCH_RECORD_MODE ); +break ; +case LCD_RTS_RECORD_TYPE : + record +=sizeof (ATOM_LCD_RTS_RECORD ); +break ; +case LCD_CAP_RECORD_TYPE : + record +=sizeof (ATOM_LCD_MODE_CONTROL_CAP ); +break ; +case LCD_FAKE_EDID_PATCH_RECORD_TYPE : + fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record; +if (fake_edid_record->ucFakeEDIDLength) { +if (fake_edid_record->ucFakeEDIDLength ==128 ) + info->fake_edid_size = + fake_edid_record->ucFakeEDIDLength; +else + info->fake_edid_size = + fake_edid_record->ucFakeEDIDLength *128 ; + + info->fake_edid = fake_edid_record->ucFakeEDIDString; + + record +=struct_size (fake_edid_record, + ucFakeEDIDString, + info->fake_edid_size); + }else { +/* empty fake edid record must be 3 bytes long */ + record +=sizeof (ATOM_FAKE_EDID_PATCH_RECORD ) +1 ; + } +break ; +case LCD_PANEL_RESOLUTION_RECORD_TYPE : + panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record; + info->panel_width_mm = panel_res_record->usHSize; + info->panel_height_mm = panel_res_record->usVSize; + record +=sizeof (ATOM_PANEL_RESOLUTION_PATCH_RECORD ); +break ; +default : +return BP_RESULT_BADBIOSTABLE ; + } + } + +return BP_RESULT_OK ; +} +static enum bp_result get_embedded_panel_info_v1_2 (struct bios_parser *bp,struct embedded_panel_info *info)
@@ -1411,6 +1465,10 @@ static enum bp_result get_embedded_panel_info_v1_2(if (ATOM_PANEL_MISC_API_ENABLED & lvds->ucLVDS_Misc) info->lcd_timing.misc_info.API_ENABLED = true; +if (lvds->usExtInfoTableOffset) +return get_embedded_panel_extra_info (bp, info, +le16_to_cpu (lvds->usExtInfoTableOffset) +DATA_TABLES (LCD_Info)); +return BP_RESULT_OK ; }
@@ -1536,6 +1594,10 @@ static enum bp_result get_embedded_panel_info_v1_3( (uint32_t ) (ATOM_PANEL_MISC_V13_GREY_LEVEL & lvds->ucLCD_Misc) >>ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT ; +if (lvds->usExtInfoTableOffset) +return get_embedded_panel_extra_info (bp, info, +le16_to_cpu (lvds->usExtInfoTableOffset) +DATA_TABLES (LCD_Info)); +return BP_RESULT_OK ; }
drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h +4 -0
@@ -153,6 +153,10 @@ struct embedded_panel_info {uint32_t drr_enabled;uint32_t min_drr_refresh_rate;bool realtek_eDPToLVDS; +uint16_t panel_width_mm; +uint16_t panel_height_mm; +uint16_t fake_edid_size; +const uint8_t *fake_edid; };struct dc_firmware_info {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1007/1146 drm/amd/display: Use EDID from VBIOS embedded panel info
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
[ Upstream commit 019155e2bd3e2cec425553195e9f9bc76bb0f848 ]
When an embedded panel has no DDC, read the EDID from the VBIOS embedded panel info and use that.
--- .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +44 -0
@@ -993,6 +993,45 @@ dm_helpers_read_acpi_edid(struct amdgpu_dm_connector *aconnector)return drm_edid_read_custom (connector, dm_helpers_probe_acpi_edid, connector); } +static const struct drm_edid * +dm_helpers_read_vbios_hardcoded_edid (struct dc_link *link,struct amdgpu_dm_connector *aconnector) +{ +struct dc_bios *bios = link->ctx->dc_bios; +struct embedded_panel_info info; +const struct drm_edid *edid; +enum bp_result r; + +if (!dc_is_embedded_signal (link->connector_signal) || + !bios->funcs->get_embedded_panel_info) +return NULL ; + +memset (&info,0 ,sizeof (info)); + r = bios->funcs->get_embedded_panel_info (bios, &info); + +if (r !=BP_RESULT_OK ) { +dm_error ("Error when reading embedded panel info: %u\n" , r); +return NULL ; + } + +if (!info.fake_edid || !info.fake_edid_size) { +dm_error ("Embedded panel info doesn't contain an EDID\n" ); +return NULL ; + } + + edid =drm_edid_alloc (info.fake_edid, info.fake_edid_size); + +if (!drm_edid_valid (edid)) { +dm_error ("EDID from embedded panel info is invalid\n" ); +drm_edid_free (edid); +return NULL ; + } + + aconnector->base.display_info.width_mm = info.panel_width_mm; + aconnector->base.display_info.height_mm = info.panel_height_mm; + +return edid; +} +void populate_hdmi_info_from_connector (struct drm_hdmi_info *hdmi,struct dc_edid_caps *edid_caps) { edid_caps->scdc_present = hdmi->scdc.supported;
@@ -1013,6 +1052,9 @@ enum dc_edid_status dm_helpers_read_local_edid(if (link->aux_mode) ddc = &aconnector->dm_dp_aux.aux.ddc; +else if (link->ddc_hw_inst ==GPIO_DDC_LINE_UNKNOWN && +dc_is_embedded_signal (link->connector_signal)) + ddc =NULL ;else ddc = &aconnector->i2c->base;
@@ -1023,6 +1065,8 @@ enum dc_edid_status dm_helpers_read_local_edid( drm_edid =dm_helpers_read_acpi_edid (aconnector);if (drm_edid)drm_info (connector->dev,"Using ACPI provided EDID for %s\n" , connector->name); +else if (!ddc) + drm_edid =dm_helpers_read_vbios_hardcoded_edid (link, aconnector);else drm_edid =drm_edid_read_ddc (connector, ddc);drm_edid_connector_update (connector, drm_edid);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1008/1146 drm/xe: Use XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET enum instead of magic number
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhanjun Dong <[email protected]>
[ Upstream commit a7f607610da721f77db358b09be8091e60bd8e89 ]
Replace the magic number 2 with the proper enum value XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET for better code readability and maintainability.
Stable-dep-of: a0fc362f0953 ("drm/xe: Drop registration of guc_submit_wedged_fini from xe_guc_submit_wedge()")
--- drivers/gpu/drm/xe/xe_guc_submit.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/gpu/drm/xe/xe_guc_submit.c +4 -3
@@ -1286,12 +1286,13 @@ void xe_guc_submit_wedge(struct xe_guc *guc)if (!guc->submission_state.initialized)return ; -if (xe->wedged.mode ==2 ) { +if (xe->wedged.mode ==XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET ) { err =devm_add_action_or_reset (guc_to_xe (guc)->drm.dev, guc_submit_wedged_fini, guc);if (err) { -xe_gt_err (gt,"Failed to register clean-up on wedged.mode=2; " -"Although device is wedged.\n" ); +xe_gt_err (gt,"Failed to register clean-up on wedged.mode=%s; " +"Although device is wedged.\n" , +xe_wedged_mode_to_string (XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET ));return ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1009/1146 drm/xe: Drop registration of guc_submit_wedged_fini from xe_guc_submit_wedge()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Brost <[email protected]>
[ Upstream commit a0fc362f095330f7b3f68ac0c55ef8da18290c87 ]
xe_guc_submit_wedge() runs in the DMA-fence signaling path, where GFP_KERNEL memory allocations are not permitted. However, registering guc_submit_wedged_fini via drmm_add_action_or_reset() triggers such an allocation.
Avoid this by moving the logic from guc_submit_wedged_fini() into guc_submit_fini(), where wedged exec queue references are dropped during normal teardown.
--- drivers/gpu/drm/xe/xe_guc_submit.c | 33 ++++++++---------------------- 1 file changed, 9 insertions(+), 24 deletions(-)
drivers/gpu/drm/xe/xe_guc_submit.c +9 -24
@@ -260,24 +260,12 @@ static void guc_submit_sw_fini(struct drm_device *drm, void *arg) }static void guc_submit_fini (void *arg) -{ -struct xe_guc *guc = arg; - -/* Forcefully kill any remaining exec queues */ -xe_guc_ct_stop (&guc->ct); -guc_submit_reset_prepare (guc); -xe_guc_softreset (guc); -xe_guc_submit_stop (guc); -xe_uc_fw_sanitize (&guc->fw); -xe_guc_submit_pause_abort (guc); -} - -static void guc_submit_wedged_fini (void *arg) {struct xe_guc *guc = arg;struct xe_exec_queue *q;unsigned long index; +/* Drop any wedged queue refs */ mutex_lock (&guc->submission_state.lock);xa_for_each (&guc->submission_state.exec_queue_lookup, index, q) {if (exec_queue_wedged (q)) {
@@ -287,6 +275,14 @@ static void guc_submit_wedged_fini(void *arg) } }mutex_unlock (&guc->submission_state.lock); + +/* Forcefully kill any remaining exec queues */ +xe_guc_ct_stop (&guc->ct); +guc_submit_reset_prepare (guc); +xe_guc_softreset (guc); +xe_guc_submit_stop (guc); +xe_uc_fw_sanitize (&guc->fw); +xe_guc_submit_pause_abort (guc); }static const struct xe_exec_queue_ops guc_exec_queue_ops;
@@ -1272,10 +1268,8 @@ static void disable_scheduling_deregister(struct xe_guc *guc,void xe_guc_submit_wedge (struct xe_guc *guc) {struct xe_device *xe =guc_to_xe (guc); -struct xe_gt *gt =guc_to_gt (guc);struct xe_exec_queue *q;unsigned long index; -int err;xe_gt_assert (guc_to_gt (guc),guc_to_xe (guc)->wedged.mode);
@@ -1287,15 +1281,6 @@ void xe_guc_submit_wedge(struct xe_guc *guc)return ;if (xe->wedged.mode ==XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET ) { - err =devm_add_action_or_reset (guc_to_xe (guc)->drm.dev, - guc_submit_wedged_fini, guc); -if (err) { -xe_gt_err (gt,"Failed to register clean-up on wedged.mode=%s; " -"Although device is wedged.\n" , -xe_wedged_mode_to_string (XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET )); -return ; - } -mutex_lock (&guc->submission_state.lock);xa_for_each (&guc->submission_state.exec_queue_lookup, index, q)if (xe_exec_queue_get_unless_zero (q))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1010/1146 drm/xe/debugfs: Correct printing of register whitelist ranges
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matt Roper <[email protected]>
[ Upstream commit 03f2499c51dffce611b065b2894406beb9f2ebe0 ]
The register-save-restore debugfs prints whitelist entries as offset ranges. E.g.,
REG[0x39319c-0x39319f]: allow read access
for a single dword-sized register. However the GENMASK value used to set the lower bits to '1' for the upper bound of the whitelist range incorrectly included one more bit than it should have, causing the whitelist ranges to sometimes appear twice as large as they really were. For example,
REG[0x6210-0x6217]: allow rw access
was also intended to be a single dword-sized register whitelist (with a range 0x6210-0x6213) but was printed incorrectly as a qword-sized range because one too many bits was flipped on. Similar 'off by one' logic was applied when printing 4-dword register ranges and 64-dword register ranges as well.
Correct the GENMASK logic to print these ranges in debugfs correctly. No impact outside of correcting the misleading debugfs output.
--- drivers/gpu/drm/xe/xe_reg_whitelist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/xe/xe_reg_whitelist.c +1 -1
@@ -218,7 +218,7 @@ void xe_reg_whitelist_print_entry(struct drm_printer *p, unsigned int indent, } range_start = reg ®_GENMASK (25 , range_bit); - range_end = range_start |REG_GENMASK (range_bit,0 ); + range_end = range_start |REG_GENMASK (range_bit -1 ,0 );switch (val &RING_FORCE_TO_NONPRIV_ACCESS_MASK ) {case RING_FORCE_TO_NONPRIV_ACCESS_RW :
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1011/1146 drm/xe: Fix potential NULL deref in xe_exec_queue_tlb_inval_last_fence_put_unlocked
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shuicheng Lin <[email protected]>
[ Upstream commit f8c4151d50b12923b67819ebf03c1c6782c984c1 ]
xe_exec_queue_tlb_inval_last_fence_put_unlocked() uses q->vm->xe as the first argument to xe_assert(). This function is called unconditionally from xe_exec_queue_destroy() for all queues, including kernel queues that have q->vm == NULL (e.g., queues created during GT init in xe_gt_record_default_lrcs() with vm=NULL).
While current compilers optimize away the q->vm->xe dereference (even in CONFIG_DRM_XE_DEBUG=y builds, the compiler pushes the dereference into the WARN branch that is only taken when the assert condition is false), the code is semantically incorrect and constitutes undefined behavior in the C abstract machine for the NULL pointer case.
Use gt_to_xe(q->gt) instead, which is always valid for any exec queue. This is consistent with how xe_exec_queue_destroy() itself obtains the xe_device pointer in its own xe_assert at the top of the function.
--- drivers/gpu/drm/xe/xe_exec_queue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/xe/xe_exec_queue.c +1 -1
@@ -1574,7 +1574,7 @@ void xe_exec_queue_tlb_inval_last_fence_put(struct xe_exec_queue *q,void xe_exec_queue_tlb_inval_last_fence_put_unlocked (struct xe_exec_queue *q,unsigned int type) { -xe_assert (q->vm->xe, type ==XE_EXEC_QUEUE_TLB_INVAL_MEDIA_GT || +xe_assert (gt_to_xe (q->gt), type ==XE_EXEC_QUEUE_TLB_INVAL_MEDIA_GT || type ==XE_EXEC_QUEUE_TLB_INVAL_PRIMARY_GT );dma_fence_put (q->tlb_inval[type].last_fence);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1012/1146 drm/xe: Fix error cleanup in xe_exec_queue_create_ioctl()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shuicheng Lin <[email protected]>
[ Upstream commit f3cc22d4df3ed58439ea7e21daa54c3608e03b78 ]
Two error handling issues exist in xe_exec_queue_create_ioctl():
1. When xe_hw_engine_group_add_exec_queue() fails, the error path jumps to put_exec_queue which skips xe_exec_queue_kill(). If the VM is in preempt fence mode, xe_vm_add_compute_exec_queue() has already added the queue to the VM's compute exec queue list. Skipping the kill leaves the queue on that list, leading to a dangling pointer after the queue is freed.
2. When xa_alloc() fails after xe_hw_engine_group_add_exec_queue() has succeeded, the error path does not call xe_hw_engine_group_del_exec_queue() to remove the queue from the hw engine group list. The queue is then freed while still linked into the hw engine group, causing a use-after-free.
Fix both by:
- Changing the xe_hw_engine_group_add_exec_queue() failure path to jump to kill_exec_queue so that xe_exec_queue_kill() properly removes the queue from the VM's compute list.
- Adding a del_hw_engine_group label before kill_exec_queue for the xa_alloc() failure path, which removes the queue from the hw engine group before proceeding with the rest of the cleanup.
--- drivers/gpu/drm/xe/xe_exec_queue.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/gpu/drm/xe/xe_exec_queue.c +5 -2
@@ -1227,7 +1227,7 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data,if (q->vm && q->hwe->hw_engine_group) { err =xe_hw_engine_group_add_exec_queue (q->hwe->hw_engine_group, q);if (err) - goto put_exec_queue; + goto kill_exec_queue; } }
@@ -1236,12 +1236,15 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data,/* user id alloc must always be last in ioctl to prevent UAF */ err =xa_alloc (&xef->exec_queue.xa, &id, q, xa_limit_32b,GFP_KERNEL );if (err) - goto kill_exec_queue; + goto del_hw_engine_group; args->exec_queue_id = id;return 0 ; +del_hw_engine_group: +if (q->vm && q->hwe && q->hwe->hw_engine_group) +xe_hw_engine_group_del_exec_queue (q->hwe->hw_engine_group, q); kill_exec_queue:xe_exec_queue_kill (q); delete_queue_group:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1013/1146 drm/xe/eustall: Fix drm_dev_put called before stream disable in close
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shuicheng Lin <[email protected]>
[ Upstream commit dc2d9842c67d883d3200ae33b9c3859dd9492408 ]
In xe_eu_stall_stream_close(), drm_dev_put() is called before the stream is disabled and its resources are freed. If this drops the last reference, the device structures could be freed while the subsequent cleanup code still accesses them, leading to a use-after-free.
Fix this by moving drm_dev_put() after all device accesses are complete. This matches the ordering in xe_oa_release().
--- drivers/gpu/drm/xe/xe_eu_stall.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/xe/xe_eu_stall.c +2 -2
@@ -869,14 +869,14 @@ static int xe_eu_stall_stream_close(struct inode *inode, struct file *file)struct xe_eu_stall_data_stream *stream = file->private_data;struct xe_gt *gt = stream->gt; -drm_dev_put (>->tile->xe->drm); -mutex_lock (>->eu_stall->stream_lock);xe_eu_stall_disable_locked (stream);xe_eu_stall_data_buf_destroy (stream);xe_eu_stall_stream_free (stream);mutex_unlock (>->eu_stall->stream_lock); +drm_dev_put (>->tile->xe->drm); +return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1014/1146 drm/xe/gsc: Fix BO leak on error in query_compatibility_version()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shuicheng Lin <[email protected]>
[ Upstream commit 3762d6c36549accea7068c4a175483fafdd03657 ]
When xe_gsc_read_out_header() fails, query_compatibility_version() returns directly instead of jumping to the out_bo label. This skips the xe_bo_unpin_map_no_vm() call, leaving the BO pinned and mapped with no remaining reference to free it.
Fix by using goto out_bo so the error path properly cleans up the BO, consistent with the other error handling in the same function.
--- drivers/gpu/drm/xe/xe_gsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/xe/xe_gsc.c +1 -1
@@ -166,7 +166,7 @@ static int query_compatibility_version(struct xe_gsc *gsc) &rd_offset);if (err) {xe_gt_err (gt,"HuC: invalid GSC reply for version query (err=%d)\n" , err); -return err; + goto out_bo; } compat->major =version_query_rd (xe, &bo->vmap, rd_offset, proj_major);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1015/1146 drm/xe/xelp: Fix Wa_18022495364
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tvrtko Ursulin <[email protected]>
[ Upstream commit 7fe6cae2f7fad2b5166b0fc096618629f9e2ebcb ]
It looks I mistyped CS_DEBUG_MODE2 as CS_DEBUG_MODE1 when adding the workaround. Fix it.
Stable-dep-of: 0df99689eb79 ("drm/xe/xelp: Fix Wa_18022495364")
--- drivers/gpu/drm/xe/xe_lrc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/xe/xe_lrc.c +1 -1
@@ -1202,7 +1202,7 @@ static ssize_t setup_invalidate_state_cache_wa(struct xe_lrc *lrc,if (xe_gt_WARN_ON (lrc->gt, max_len <3 ))return -ENOSPC ; - *cmd++ =MI_LOAD_REGISTER_IMM |MI_LRI_NUM_REGS (1 ); + *cmd++ =MI_LOAD_REGISTER_IMM |MI_LRI_LRM_CS_MMIO |MI_LRI_NUM_REGS (1 ); *cmd++ =CS_DEBUG_MODE2 (0 ).addr; *cmd++ =_MASKED_BIT_ENABLE (INSTRUCTION_STATE_CACHE_INVALIDATE );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1016/1146 net: airoha: Do not return err in ndo_stop() callback
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <[email protected]>
[ Upstream commit 4ca01292ea2f2363660610a65ba0285d7c3309ed ]
Always complete the airoha_dev_stop() routine regardless of the airoha_set_vip_for_gdm_port() return value, since errors from ndo_stop() are ignored by the networking stack and the interface is always considered down after the call.
--- drivers/net/ethernet/airoha/airoha_eth.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
drivers/net/ethernet/airoha/airoha_eth.c +2 -5
@@ -1738,13 +1738,10 @@ static int airoha_dev_stop(struct net_device *dev) {struct airoha_gdm_port *port =netdev_priv (dev);struct airoha_qdma *qdma = port->qdma; -int i, err; +int i;netif_tx_disable (dev); - err =airoha_set_vip_for_gdm_port (port, false); -if (err) -return err; - +airoha_set_vip_for_gdm_port (port, false);for (i =0 ; i < dev->num_tx_queues; i++)netdev_tx_reset_subqueue (dev, i);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1017/1146 bonding: print churn state via netlink
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hangbin Liu <[email protected]>
[ Upstream commit 4916f2e2f3fc9aef289fcd07949301e5c29094c2 ]
Currently, the churn state is printed only in sysfs. Add netlink support so users could get the state via netlink.
Stable-dep-of: c4f050ce06c5 ("bonding: 3ad: implement proper RCU rules for port->aggregator")
--- drivers/net/bonding/bond_netlink.c | 9 +++++++++ include/uapi/linux/if_link.h | 2 ++ 2 files changed, 11 insertions(+)
drivers/net/bonding/bond_netlink.c +9 -0
@@ -29,6 +29,8 @@ static size_t bond_get_slave_size(const struct net_device *bond_dev,nla_total_size (sizeof (u16)) +/* IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE */ nla_total_size (sizeof (s32)) +/* IFLA_BOND_SLAVE_PRIO */ nla_total_size (sizeof (u16)) +/* IFLA_BOND_SLAVE_ACTOR_PORT_PRIO */ +nla_total_size (sizeof (u8)) +/* IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE */ +nla_total_size (sizeof (u8)) +/* IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE */ 0 ; }
@@ -77,6 +79,13 @@ static int bond_fill_slave_info(struct sk_buff *skb, IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, ad_port->partner_oper.port_state)) goto nla_put_failure; + +if (nla_put_u8 (skb,IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE , + ad_port->sm_churn_actor_state)) + goto nla_put_failure; +if (nla_put_u8 (skb,IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE , + ad_port->sm_churn_partner_state)) + goto nla_put_failure; } if (nla_put_u16(skb, IFLA_BOND_SLAVE_ACTOR_PORT_PRIO,
include/uapi/linux/if_link.h +2 -0
@@ -1568,6 +1568,8 @@ enum {IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE ,IFLA_BOND_SLAVE_PRIO ,IFLA_BOND_SLAVE_ACTOR_PORT_PRIO , +IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE , +IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE , __IFLA_BOND_SLAVE_MAX, };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1018/1146 bonding: 3ad: implement proper RCU rules for port->aggregator
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit c4f050ce06c56cfb5993268af4a5cb66ed1cd04e ]
syzbot found a data-race in bond_3ad_get_active_agg_info / bond_3ad_state_machine_handler [1] which hints at lack of proper RCU implementation.
Add __rcu qualifier to port->aggregator, and add proper RCU API.
[1]
BUG: KCSAN: data-race in bond_3ad_get_active_agg_info / bond_3ad_state_machine_handler
write to 0xffff88813cf5c4b0 of 8 bytes by task 36 on cpu 0:
ad_port_selection_logic drivers/net/bonding/bond_3ad.c:1659 [inline] bond_3ad_state_machine_handler+0x9d5/0x2d60 drivers/net/bonding/bond_3ad.c:2569 process_one_work kernel/workqueue.c:3302 [inline] process_scheduled_works+0x4f0/0x9c0 kernel/workqueue.c:3385 worker_thread+0x58a/0x780 kernel/workqueue.c:3466 kthread+0x22a/0x280 kernel/kthread.c:436 ret_from_fork+0x146/0x330 arch/x86/kernel/process.c:158 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
read to 0xffff88813cf5c4b0 of 8 bytes by task 22063 on cpu 1:
__bond_3ad_get_active_agg_info drivers/net/bonding/bond_3ad.c:2858 [inline] bond_3ad_get_active_agg_info+0x8c/0x230 drivers/net/bonding/bond_3ad.c:2881 bond_fill_info+0xe0f/0x10f0 drivers/net/bonding/bond_netlink.c:853 rtnl_link_info_fill net/core/rtnetlink.c:906 [inline] rtnl_link_fill+0x1d7/0x4e0 net/core/rtnetlink.c:927 rtnl_fill_ifinfo+0xf8e/0x1380 net/core/rtnetlink.c:2168 rtmsg_ifinfo_build_skb+0x11c/0x1b0 net/core/rtnetlink.c:4453 rtmsg_ifinfo_event net/core/rtnetlink.c:4486 [inline] rtmsg_ifinfo+0x6d/0x110 net/core/rtnetlink.c:4495 __dev_notify_flags+0x76/0x390 net/core/dev.c:9790 netif_change_flags+0xac/0xd0 net/core/dev.c:9823 do_setlink+0x905/0x2950 net/core/rtnetlink.c:3180 rtnl_group_changelink net/core/rtnetlink.c:3813 [inline] __rtnl_newlink net/core/rtnetlink.c:3981 [inline] rtnl_newlink+0xf55/0x1400 net/core/rtnetlink.c:4109 rtnetlink_rcv_msg+0x64b/0x720 net/core/rtnetlink.c:6995 netlink_rcv_skb+0x123/0x220 net/netlink/af_netlink.c:2550 rtnetlink_rcv+0x1c/0x30 net/core/rtnetlink.c:7022 netlink_unicast_kernel net/netlink/af_netlink.c:1318 [inline] netlink_unicast+0x5a8/0x680 net/netlink/af_netlink.c:1344 netlink_sendmsg+0x5c8/0x6f0 net/netlink/af_netlink.c:1894 sock_sendmsg_nosec net/socket.c:787 [inline] __sock_sendmsg net/socket.c:802 [inline] ____sys_sendmsg+0x563/0x5b0 net/socket.c:2698 ___sys_sendmsg+0x195/0x1e0 net/socket.c:2752 __sys_sendmsg net/socket.c:2784 [inline] __do_sys_sendmsg net/socket.c:2789 [inline] __se_sys_sendmsg net/socket.c:2787 [inline] __x64_sys_sendmsg+0xd4/0x160 net/socket.c:2787 x64_sys_call+0x194c/0x3020 arch/x86/include/generated/asm/syscalls_64.h:47 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0x12c/0x3b0 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f
value changed: 0x0000000000000000 -> 0xffff88813cf5c400
Reported by Kernel Concurrency Sanitizer on:
CPU: 1 UID: 0 PID: 22063 Comm: syz.0.31122 Tainted: G W syzkaller #0 PREEMPT(full) Tainted: [W]=WARN Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 04/18/2026
--- drivers/net/bonding/bond_3ad.c | 109 ++++++++++++++----------- drivers/net/bonding/bond_main.c | 8 +- drivers/net/bonding/bond_netlink.c | 16 ++-- drivers/net/bonding/bond_procfs.c | 3 +- drivers/net/bonding/bond_sysfs_slave.c | 17 ++-- include/net/bond_3ad.h | 2 +- 6 files changed, 89 insertions(+), 66 deletions(-)
drivers/net/bonding/bond_3ad.c +60 -49
@@ -1029,6 +1029,7 @@ static void ad_cond_set_peer_notif(struct port *port)static void ad_mux_machine (struct port *port,bool *update_slave_arr) {struct bonding *bond =__get_bond_by_port (port); +struct aggregator *aggregator;mux_states_t last_state;/* keep current State Machine state to compare later if it was
@@ -1036,6 +1037,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)*/ last_state = port->sm_mux_state; + aggregator =rcu_dereference (port->aggregator);if (port->sm_vars &AD_PORT_BEGIN ) { port->sm_mux_state =AD_MUX_DETACHED ; }else {
@@ -1055,7 +1057,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)* cycle to update ready variable, we check * READY_N and update READY here */ -__set_agg_ports_ready (port->aggregator,__agg_ports_are_ready (port->aggregator)); +__set_agg_ports_ready (aggregator,__agg_ports_are_ready (aggregator)); port->sm_mux_state =AD_MUX_DETACHED ;break ; }
@@ -1070,7 +1072,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)* update ready variable, we check READY_N and update * READY here */ -__set_agg_ports_ready (port->aggregator,__agg_ports_are_ready (port->aggregator)); +__set_agg_ports_ready (aggregator,__agg_ports_are_ready (aggregator));/* if the wait_while_timer expired, and the port is * in READY state, move to ATTACHED state
@@ -1086,7 +1088,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)if ((port->sm_vars &AD_PORT_SELECTED ) && (port->partner_oper.port_state &LACP_STATE_SYNCHRONIZATION ) && !__check_agg_selection_timer (port)) { -if (port->aggregator->is_active) { +if (aggregator->is_active) {int state =AD_MUX_COLLECTING_DISTRIBUTING ;if (!bond->params.coupled_control)
@@ -1102,9 +1104,9 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)* cycle to update ready variable, we check * READY_N and update READY here */ -__set_agg_ports_ready (port->aggregator,__agg_ports_are_ready (port->aggregator)); +__set_agg_ports_ready (aggregator,__agg_ports_are_ready (aggregator)); port->sm_mux_state =AD_MUX_DETACHED ; - }else if (port->aggregator->is_active) { + }else if (aggregator->is_active) { port->actor_oper_port_state |=LACP_STATE_SYNCHRONIZATION ; }
@@ -1115,7 +1117,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)* sure that a collecting distributing * port in an active aggregator is enabled */ -if (port->aggregator->is_active && +if (aggregator->is_active && !__port_is_collecting_distributing (port)) {__enable_port (port); *update_slave_arr = true;
@@ -1134,7 +1136,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)*/ struct slave *slave = port->slave; -if (port->aggregator->is_active && +if (aggregator->is_active &&bond_is_slave_rx_disabled (slave)) {ad_enable_collecting (port); *update_slave_arr = true;
@@ -1154,8 +1156,8 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)* sure that a collecting distributing * port in an active aggregator is enabled */ -if (port->aggregator && - port->aggregator->is_active && +if (aggregator && + aggregator->is_active && !__port_is_collecting_distributing (port)) {__enable_port (port); *update_slave_arr = true;
@@ -1187,7 +1189,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) port->sm_mux_timer_counter =__ad_timer_to_ticks (AD_WAIT_WHILE_TIMER ,0 );break ;case AD_MUX_ATTACHED : -if (port->aggregator->is_active) +if (aggregator->is_active) port->actor_oper_port_state |=LACP_STATE_SYNCHRONIZATION ;else
@@ -1561,9 +1563,9 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) bond =__get_bond_by_port (port);/* if the port is connected to other aggregator, detach it */ -if (port->aggregator) { + temp_aggregator =rcu_dereference (port->aggregator); +if (temp_aggregator) {/* detach the port from its former aggregator */ - temp_aggregator = port->aggregator;for (curr_port = temp_aggregator->lag_ports; curr_port; last_port = curr_port, curr_port = curr_port->next_port_in_aggregator) {
@@ -1586,7 +1588,7 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)/* clear the port's relations to this * aggregator */ - port->aggregator =NULL ; +RCU_INIT_POINTER (port->aggregator,NULL ); port->next_port_in_aggregator =NULL ; port->actor_port_aggregator_identifier =0 ;
@@ -1609,7 +1611,7 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) port->slave->bond->dev->name, port->slave->dev->name, port->actor_port_number, - port->aggregator->aggregator_identifier); + temp_aggregator->aggregator_identifier); } }/* search on all aggregators for a suitable aggregator for this port */
@@ -1633,15 +1635,15 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) ) ) {/* attach to the founded aggregator */ - port->aggregator = aggregator; +rcu_assign_pointer (port->aggregator, aggregator); port->actor_port_aggregator_identifier = - port->aggregator->aggregator_identifier; + aggregator->aggregator_identifier; port->next_port_in_aggregator = aggregator->lag_ports; - port->aggregator->num_of_ports++; + aggregator->num_of_ports++; aggregator->lag_ports = port;slave_dbg (bond->dev, slave->dev,"Port %d joined LAG %d (existing LAG)\n" , port->actor_port_number, - port->aggregator->aggregator_identifier); + aggregator->aggregator_identifier);/* mark this port as selected */ port->sm_vars |=AD_PORT_SELECTED ;
@@ -1656,39 +1658,40 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)if (!found) {if (free_aggregator) {/* assign port a new aggregator */ - port->aggregator = free_aggregator; port->actor_port_aggregator_identifier = - port->aggregator->aggregator_identifier; + free_aggregator->aggregator_identifier;/* update the new aggregator's parameters * if port was responsed from the end-user */ if (port->actor_oper_port_key &AD_DUPLEX_KEY_MASKS )/* if port is full duplex */ - port->aggregator->is_individual = false; + free_aggregator->is_individual = false;else - port->aggregator->is_individual = true; + free_aggregator->is_individual = true; - port->aggregator->actor_admin_aggregator_key = + free_aggregator->actor_admin_aggregator_key = port->actor_admin_port_key; - port->aggregator->actor_oper_aggregator_key = + free_aggregator->actor_oper_aggregator_key = port->actor_oper_port_key; - port->aggregator->partner_system = + free_aggregator->partner_system = port->partner_oper.system; - port->aggregator->partner_system_priority = + free_aggregator->partner_system_priority = port->partner_oper.system_priority; - port->aggregator->partner_oper_aggregator_key = port->partner_oper.key; - port->aggregator->receive_state =1 ; - port->aggregator->transmit_state =1 ; - port->aggregator->lag_ports = port; - port->aggregator->num_of_ports++; + free_aggregator->partner_oper_aggregator_key = port->partner_oper.key; + free_aggregator->receive_state =1 ; + free_aggregator->transmit_state =1 ; + free_aggregator->lag_ports = port; + free_aggregator->num_of_ports++; + +rcu_assign_pointer (port->aggregator, free_aggregator);/* mark this port as selected */ port->sm_vars |=AD_PORT_SELECTED ;slave_dbg (bond->dev, port->slave->dev,"Port %d joined LAG %d (new LAG)\n" , port->actor_port_number, - port->aggregator->aggregator_identifier); + free_aggregator->aggregator_identifier); }else { slave_err(bond->dev, port->slave->dev, "Port %d did not find a suitable aggregator\n",
@@ -1700,13 +1703,12 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)* in all aggregator's ports, else set ready=FALSE in all * aggregator's ports */ -__set_agg_ports_ready (port->aggregator, -__agg_ports_are_ready (port->aggregator)); + aggregator =rcu_dereference (port->aggregator); +__set_agg_ports_ready (aggregator,__agg_ports_are_ready (aggregator)); - aggregator =__get_first_agg (port); -ad_agg_selection_logic (aggregator, update_slave_arr); +ad_agg_selection_logic (__get_first_agg (port), update_slave_arr); -if (!port->aggregator->is_active) +if (!aggregator->is_active) port->actor_oper_port_state &= ~LACP_STATE_SYNCHRONIZATION ; }
@@ -2075,13 +2077,15 @@ static void ad_initialize_port(struct port *port, const struct bond_params *bond*/ static void ad_enable_collecting (struct port *port) { -if (port->aggregator->is_active) { +struct aggregator *aggregator =rcu_dereference (port->aggregator); + +if (aggregator->is_active) {struct slave *slave = port->slave;slave_dbg (slave->bond->dev, slave->dev,"Enabling collecting on port %d (LAG %d)\n" , port->actor_port_number, - port->aggregator->aggregator_identifier); + aggregator->aggregator_identifier);__enable_collecting_port (port); } }
@@ -2093,11 +2097,13 @@ static void ad_enable_collecting(struct port *port)*/ static void ad_disable_distributing (struct port *port,bool *update_slave_arr) { -if (port->aggregator &&__agg_has_partner (port->aggregator)) { +struct aggregator *aggregator =rcu_dereference (port->aggregator); + +if (aggregator &&__agg_has_partner (aggregator)) {slave_dbg (port->slave->bond->dev, port->slave->dev,"Disabling distributing on port %d (LAG %d)\n" , port->actor_port_number, - port->aggregator->aggregator_identifier); + aggregator->aggregator_identifier);__disable_distributing_port (port);/* Slave array needs an update */ *update_slave_arr = true;
@@ -2114,11 +2120,13 @@ static void ad_disable_distributing(struct port *port, bool *update_slave_arr)static void ad_enable_collecting_distributing (struct port *port,bool *update_slave_arr) { -if (port->aggregator->is_active) { +struct aggregator *aggregator =rcu_dereference (port->aggregator); + +if (aggregator->is_active) {slave_dbg (port->slave->bond->dev, port->slave->dev,"Enabling port %d (LAG %d)\n" , port->actor_port_number, - port->aggregator->aggregator_identifier); + aggregator->aggregator_identifier);__enable_port (port);/* Slave array needs update */ *update_slave_arr = true;
@@ -2135,11 +2143,13 @@ static void ad_enable_collecting_distributing(struct port *port,static void ad_disable_collecting_distributing (struct port *port,bool *update_slave_arr) { -if (port->aggregator &&__agg_has_partner (port->aggregator)) { +struct aggregator *aggregator =rcu_dereference (port->aggregator); + +if (aggregator &&__agg_has_partner (aggregator)) {slave_dbg (port->slave->bond->dev, port->slave->dev,"Disabling port %d (LAG %d)\n" , port->actor_port_number, - port->aggregator->aggregator_identifier); + aggregator->aggregator_identifier);__disable_port (port);/* Slave array needs an update */ *update_slave_arr = true;
@@ -2379,7 +2389,7 @@ void bond_3ad_unbind_slave(struct slave *slave)*/ for (temp_port = aggregator->lag_ports; temp_port; temp_port = temp_port->next_port_in_aggregator) { - temp_port->aggregator = new_aggregator; +rcu_assign_pointer (temp_port->aggregator, new_aggregator); temp_port->actor_port_aggregator_identifier = new_aggregator->aggregator_identifier; }
@@ -2848,15 +2858,16 @@ int bond_3ad_set_carrier(struct bonding *bond)int __bond_3ad_get_active_agg_info (struct bonding *bond,struct ad_info *ad_info) { -struct aggregator *aggregator =NULL ; +struct aggregator *aggregator =NULL , *tmp;struct list_head *iter;struct slave *slave;struct port *port;bond_for_each_slave_rcu (bond, slave, iter) { port = &(SLAVE_AD_INFO (slave)->port); -if (port->aggregator && port->aggregator->is_active) { - aggregator = port->aggregator; + tmp =rcu_dereference (port->aggregator); +if (tmp && tmp->is_active) { + aggregator = tmp;break ; } }
drivers/net/bonding/bond_main.c +5 -3
@@ -1435,7 +1435,7 @@ static void bond_poll_controller(struct net_device *bond_dev)if (BOND_MODE (bond) ==BOND_MODE_8023AD ) {struct aggregator *agg = -SLAVE_AD_INFO (slave)->port.aggregator; +rcu_dereference (SLAVE_AD_INFO (slave)->port.aggregator);if (agg && agg->aggregator_identifier != ad_info.aggregator_id)
@@ -5181,15 +5181,16 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave)spin_unlock_bh (&bond->mode_lock); agg_id = ad_info.aggregator_id; } +rcu_read_lock ();bond_for_each_slave (bond, slave, iter) {if (skipslave == slave)continue ; all_slaves->arr[all_slaves->count++] = slave;if (BOND_MODE (bond) ==BOND_MODE_8023AD ) { -struct aggregator *agg; +const struct aggregator *agg; - agg =SLAVE_AD_INFO (slave)->port.aggregator; + agg =rcu_dereference (SLAVE_AD_INFO (slave)->port.aggregator);if (!agg || agg->aggregator_identifier != agg_id)continue ; }
@@ -5201,6 +5202,7 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave) usable_slaves->arr[usable_slaves->count++] = slave; } +rcu_read_unlock ();bond_set_slave_arr (bond, usable_slaves, all_slaves);return ret;
drivers/net/bonding/bond_netlink.c +10 -6
@@ -66,27 +66,29 @@ static int bond_fill_slave_info(struct sk_buff *skb,const struct port *ad_port; ad_port = &SLAVE_AD_INFO (slave)->port; - agg =SLAVE_AD_INFO (slave)->port.aggregator; +rcu_read_lock (); + agg =rcu_dereference (SLAVE_AD_INFO (slave)->port.aggregator);if (agg) {if (nla_put_u16 (skb,IFLA_BOND_SLAVE_AD_AGGREGATOR_ID , agg->aggregator_identifier)) - goto nla_put_failure; + goto nla_put_failure_rcu;if (nla_put_u8 (skb,IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE , ad_port->actor_oper_port_state)) - goto nla_put_failure; + goto nla_put_failure_rcu;if (nla_put_u16 (skb,IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE , ad_port->partner_oper.port_state)) - goto nla_put_failure; + goto nla_put_failure_rcu;if (nla_put_u8 (skb,IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE , ad_port->sm_churn_actor_state)) - goto nla_put_failure; + goto nla_put_failure_rcu;if (nla_put_u8 (skb,IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE , ad_port->sm_churn_partner_state)) - goto nla_put_failure; + goto nla_put_failure_rcu; } +rcu_read_unlock ();if (nla_put_u16 (skb,IFLA_BOND_SLAVE_ACTOR_PORT_PRIO ,SLAVE_AD_INFO (slave)->port_priority))
@@ -95,6 +97,8 @@ static int bond_fill_slave_info(struct sk_buff *skb,return 0 ; +nla_put_failure_rcu: +rcu_read_unlock (); nla_put_failure:return -EMSGSIZE ; }
drivers/net/bonding/bond_procfs.c +2 -1
@@ -187,6 +187,7 @@ static void bond_info_show_master(struct seq_file *seq) } } +/* Note: runs under rcu_read_lock() */ static void bond_info_show_slave (struct seq_file *seq,const struct slave *slave) {
@@ -213,7 +214,7 @@ static void bond_info_show_slave(struct seq_file *seq,if (BOND_MODE (bond) ==BOND_MODE_8023AD ) {const struct port *port = &SLAVE_AD_INFO (slave)->port; -const struct aggregator *agg = port->aggregator; +const struct aggregator *agg =rcu_dereference (port->aggregator);if (agg) { seq_printf(seq, "Aggregator ID: %d\n",
drivers/net/bonding/bond_sysfs_slave.c +11 -6
@@ -62,10 +62,15 @@ static ssize_t ad_aggregator_id_show(struct slave *slave, char *buf)const struct aggregator *agg;if (BOND_MODE (slave->bond) ==BOND_MODE_8023AD ) { - agg =SLAVE_AD_INFO (slave)->port.aggregator; -if (agg) -return sysfs_emit (buf,"%d\n" , - agg->aggregator_identifier); +rcu_read_lock (); + agg =rcu_dereference (SLAVE_AD_INFO (slave)->port.aggregator); +if (agg) { +ssize_t res =sysfs_emit (buf,"%d\n" , + agg->aggregator_identifier); +rcu_read_unlock (); +return res; + } +rcu_read_unlock (); }return sysfs_emit (buf,"N/A\n" );
@@ -78,7 +83,7 @@ static ssize_t ad_actor_oper_port_state_show(struct slave *slave, char *buf)if (BOND_MODE (slave->bond) ==BOND_MODE_8023AD ) { ad_port = &SLAVE_AD_INFO (slave)->port; -if (ad_port->aggregator) +if (rcu_access_pointer (ad_port->aggregator))return sysfs_emit (buf,"%u\n" , ad_port->actor_oper_port_state); }
@@ -93,7 +98,7 @@ static ssize_t ad_partner_oper_port_state_show(struct slave *slave, char *buf)if (BOND_MODE (slave->bond) ==BOND_MODE_8023AD ) { ad_port = &SLAVE_AD_INFO (slave)->port; -if (ad_port->aggregator) +if (rcu_access_pointer (ad_port->aggregator))return sysfs_emit (buf,"%u\n" , ad_port->partner_oper.port_state); }
include/net/bond_3ad.h +1 -1
@@ -243,7 +243,7 @@ typedef struct port {churn_state_t sm_churn_actor_state;churn_state_t sm_churn_partner_state;struct slave *slave;/* pointer to the bond slave that this port belongs to */ -struct aggregator *aggregator;/* pointer to an aggregator that this port related to */ +struct aggregator __rcu *aggregator;/* pointer to an aggregator that this port related to */ struct port *next_port_in_aggregator;/* Next port on the linked list of the parent aggregator */ u32 transaction_id;/* continuous number for identification of Marker PDU's; */ struct lacpdu lacpdu;/* the lacpdu that will be sent for this port */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1019/1146 page_pool: fix memory-provider leak in page_pool_create_percpu() error path
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hasan Basbunar <[email protected]>
[ Upstream commit 5ef343614db766acdc01c56d66e780a1b43c6ac6 ]
When page_pool_create_percpu() fails on page_pool_list(), it falls through to its err_uninit: label, which calls page_pool_uninit(). At that point page_pool_init() has already taken two references when the user requested PP_FLAG_ALLOW_UNREADABLE_NETMEM:
pool->mp_ops->init(pool) static_branch_inc(&page_pool_mem_providers);
Neither is undone by page_pool_uninit(); both are only undone by __page_pool_destroy() (success-side teardown). The error path therefore leaks the per-provider reference taken by mp_ops->init (io_zcrx_ifq->refs in the io_uring zcrx provider, the dmabuf binding refcount in the devmem provider) plus one increment of the page_pool_mem_providers static branch on every failure of xa_alloc_cyclic() inside page_pool_list().
The leaked io_zcrx_ifq->refs in turn pins everything io_zcrx_ifq_free() would release on cleanup: ifq->user (uid), ifq->mm_account (mmdrop), ifq->dev (device refcount), ifq->netdev_tracker (netdev refcount), and the rbuf region. The leaked static branch increment forces all subsequent page_pool_alloc_netmems() and page_pool_return_page() callers to take the slow mp_ops branch for the lifetime of the kernel.
Reachable via the io_uring zcrx path:
io_uring_register(IORING_REGISTER_ZCRX_IFQ) /* CAP_NET_ADMIN */ -> __io_uring_register -> io_register_zcrx -> zcrx_register_netdev -> netif_mp_open_rxq -> driver ndo_queue_mem_alloc -> page_pool_create_percpu -> page_pool_init succeeds (mp_ops->init runs, branch++) -> page_pool_list fails (xa_alloc_cyclic -ENOMEM) -> goto err_uninit <-- leak
The same shape applies to the devmem dmabuf provider via mp_dmabuf_devmem_init()/mp_dmabuf_devmem_destroy().
Restore the cleanup symmetry by moving the mp_ops->destroy() and static_branch_dec() calls out of __page_pool_destroy() and into page_pool_uninit(), so page_pool_uninit() is again the strict inverse of page_pool_init(). page_pool_uninit() has only two callers (the err_uninit: path and __page_pool_destroy()), so this preserves the single-call invariant on the success path while fixing the err path. The error path of page_pool_init() itself still skips the mp_ops cleanup correctly: mp_ops->init is the last action that takes a reference before page_pool_init() returns 0, so when it returns an error neither the refcount nor the static branch has been touched.
Triggering the bug requires xa_alloc_cyclic() to fail with -ENOMEM, which under normal GFP_KERNEL retry behaviour is rare. It is deterministic under CONFIG_FAULT_INJECTION with fail_page_alloc / xa fault injection, or under sustained memory pressure. The leak is silent: there is no warning, and the released kernel build continues running with a permanently-incremented static branch.
--- net/core/page_pool.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
net/core/page_pool.c +5 -5
@@ -327,6 +327,11 @@ static void page_pool_uninit(struct page_pool *pool)if (!pool->system)free_percpu (pool->recycle_stats);#endif + +if (pool->mp_ops) { + pool->mp_ops->destroy (pool); +static_branch_dec (&page_pool_mem_providers); + } }/**
@@ -1126,11 +1131,6 @@ static void __page_pool_destroy(struct page_pool *pool)page_pool_unlist (pool);page_pool_uninit (pool); -if (pool->mp_ops) { - pool->mp_ops->destroy (pool); -static_branch_dec (&page_pool_mem_providers); - } -kfree (pool); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1020/1146 iavf: rename IAVF_VLAN_IS_NEW to IAVF_VLAN_ADDING
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Oros <[email protected]>
[ Upstream commit 70d62b669f1f9080a25278fc90b64309f4ae8959 ]
Rename the IAVF_VLAN_IS_NEW state to IAVF_VLAN_ADDING to better describe what the state represents: an ADD request has been sent to the PF and is waiting for a response.
This is a pure rename with no behavioral change, preparing for a cleanup of the VLAN filter state machine.
Stable-dep-of: f2ce65b9b917 ("iavf: stop removing VLAN filters from PF on interface down")
--- drivers/net/ethernet/intel/iavf/iavf.h | 2 +- drivers/net/ethernet/intel/iavf/iavf_virtchnl.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-)
drivers/net/ethernet/intel/iavf/iavf.h +1 -1
@@ -158,7 +158,7 @@ struct iavf_vlan {enum iavf_vlan_state_t {IAVF_VLAN_INVALID ,IAVF_VLAN_ADD ,/* filter needs to be added */ -IAVF_VLAN_IS_NEW ,/* filter is new, wait for PF answer */ +IAVF_VLAN_ADDING ,/* ADD sent to PF, waiting for response */ IAVF_VLAN_ACTIVE ,/* filter is accepted by PF */ IAVF_VLAN_DISABLE ,/* filter needs to be deleted by PF, then marked INACTIVE */ IAVF_VLAN_INACTIVE ,/* filter is inactive, we are in IFF_DOWN */
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +4 -4
@@ -746,7 +746,7 @@ static void iavf_vlan_add_reject(struct iavf_adapter *adapter)spin_lock_bh (&adapter->mac_vlan_list_lock);list_for_each_entry_safe (f, ftmp, &adapter->vlan_filter_list, list) { -if (f->state ==IAVF_VLAN_IS_NEW ) { +if (f->state ==IAVF_VLAN_ADDING ) {list_del (&f->list);kfree (f); adapter->num_vlan_filters--;
@@ -812,7 +812,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter)if (f->state ==IAVF_VLAN_ADD ) { vvfl->vlan_id[i] = f->vlan.vid; i++; - f->state =IAVF_VLAN_IS_NEW ; + f->state =IAVF_VLAN_ADDING ;if (i == count)break ; }
@@ -874,7 +874,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter) vlan->tpid = f->vlan.tpid; i++; - f->state =IAVF_VLAN_IS_NEW ; + f->state =IAVF_VLAN_ADDING ; } }
@@ -2910,7 +2910,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,spin_lock_bh (&adapter->mac_vlan_list_lock);list_for_each_entry (f, &adapter->vlan_filter_list, list) { -if (f->state ==IAVF_VLAN_IS_NEW ) +if (f->state ==IAVF_VLAN_ADDING ) f->state =IAVF_VLAN_ACTIVE ; }spin_unlock_bh (&adapter->mac_vlan_list_lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1021/1146 iavf: stop removing VLAN filters from PF on interface down
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Oros <[email protected]>
[ Upstream commit f2ce65b9b917474a1a6ce68d357e15fac2aca0f2 ]
When a VF goes down, the driver currently sends DEL_VLAN to the PF for every VLAN filter (ACTIVE -> DISABLE -> send DEL -> INACTIVE), then re-adds them all on UP (INACTIVE -> ADD -> send ADD -> ADDING -> ACTIVE). This round-trip is unnecessary because:
1. The PF disables the VF's queues via VIRTCHNL_OP_DISABLE_QUEUES, which already prevents all RX/TX traffic regardless of VLAN filter state.
2. The VLAN filters remaining in PF HW while the VF is down is harmless - packets matching those filters have nowhere to go with queues disabled.
3. The DEL+ADD cycle during down/up creates race windows where the VLAN filter list is incomplete. With spoofcheck enabled, the PF enables TX VLAN filtering on the first non-zero VLAN add, blocking traffic for any VLANs not yet re-added.
Remove the entire DISABLE/INACTIVE state machinery:
- Remove IAVF_VLAN_DISABLE and IAVF_VLAN_INACTIVE enum values
- Remove iavf_restore_filters() and its call from iavf_open()
- Remove VLAN filter handling from iavf_clear_mac_vlan_filters(), rename it to iavf_clear_mac_filters()
- Remove DEL_VLAN_FILTER scheduling from iavf_down()
- Remove all DISABLE/INACTIVE handling from iavf_del_vlans()
VLAN filters now stay ACTIVE across down/up cycles. Only explicit user removal (ndo_vlan_rx_kill_vid) or PF/VF reset triggers VLAN filter deletion/re-addition.
--- drivers/net/ethernet/intel/iavf/iavf.h | 6 +-- drivers/net/ethernet/intel/iavf/iavf_main.c | 39 ++----------------- .../net/ethernet/intel/iavf/iavf_virtchnl.c | 33 +++------------- 3 files changed, 12 insertions(+), 66 deletions(-)
drivers/net/ethernet/intel/iavf/iavf.h +2 -4
@@ -159,10 +159,8 @@ enum iavf_vlan_state_t {IAVF_VLAN_INVALID ,IAVF_VLAN_ADD ,/* filter needs to be added */ IAVF_VLAN_ADDING ,/* ADD sent to PF, waiting for response */ -IAVF_VLAN_ACTIVE ,/* filter is accepted by PF */ -IAVF_VLAN_DISABLE ,/* filter needs to be deleted by PF, then marked INACTIVE */ -IAVF_VLAN_INACTIVE ,/* filter is inactive, we are in IFF_DOWN */ - IAVF_VLAN_REMOVE, /* filter needs to be removed from list */ +IAVF_VLAN_ACTIVE ,/* PF confirmed, filter is in HW */ + IAVF_VLAN_REMOVE, /* filter queued for DEL from PF */ }; struct iavf_vlan_filter {
drivers/net/ethernet/intel/iavf/iavf_main.c +4 -35
@@ -801,27 +801,6 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan)spin_unlock_bh (&adapter->mac_vlan_list_lock); } -/** -* iavf_restore_filters -* @adapter: board private structure -* -* Restore existing non MAC filters when VF netdev comes back up -**/ -static void iavf_restore_filters (struct iavf_adapter *adapter) -{ -struct iavf_vlan_filter *f; - -/* re-add all VLAN filters */ -spin_lock_bh (&adapter->mac_vlan_list_lock); - -list_for_each_entry (f, &adapter->vlan_filter_list, list) { -if (f->state ==IAVF_VLAN_INACTIVE ) - f->state =IAVF_VLAN_ADD ; - } - -spin_unlock_bh (&adapter->mac_vlan_list_lock); - adapter->aq_required |=IAVF_FLAG_AQ_ADD_VLAN_FILTER ; -}/** * iavf_get_num_vlans_added - get number of VLANs added
@@ -1240,13 +1219,12 @@ static void iavf_up_complete(struct iavf_adapter *adapter) }/** -* iavf_clear_mac_vlan_filters - Remove mac and vlan filters not sent to PF -* yet and mark other to be removed. +* iavf_clear_mac_filters - Remove MAC filters not sent to PF yet and mark +* others to be removed. * @adapter: board private structure **/ -static void iavf_clear_mac_vlan_filters (struct iavf_adapter *adapter) +static void iavf_clear_mac_filters (struct iavf_adapter *adapter) { -struct iavf_vlan_filter *vlf, *vlftmp;struct iavf_mac_filter *f, *ftmp;spin_lock_bh (&adapter->mac_vlan_list_lock);
@@ -1265,11 +1243,6 @@ static void iavf_clear_mac_vlan_filters(struct iavf_adapter *adapter) } } -/* disable all VLAN filters */ -list_for_each_entry_safe (vlf, vlftmp, &adapter->vlan_filter_list, - list) - vlf->state =IAVF_VLAN_DISABLE ; -spin_unlock_bh (&adapter->mac_vlan_list_lock); }
@@ -1365,7 +1338,7 @@ void iavf_down(struct iavf_adapter *adapter)iavf_napi_disable_all (adapter);iavf_irq_disable (adapter); -iavf_clear_mac_vlan_filters (adapter); +iavf_clear_mac_filters (adapter);iavf_clear_cloud_filters (adapter);iavf_clear_fdir_filters (adapter);iavf_clear_adv_rss_conf (adapter);
@@ -1382,8 +1355,6 @@ void iavf_down(struct iavf_adapter *adapter)*/ if (!list_empty (&adapter->mac_filter_list)) adapter->aq_required |=IAVF_FLAG_AQ_DEL_MAC_FILTER ; -if (!list_empty (&adapter->vlan_filter_list)) - adapter->aq_required |=IAVF_FLAG_AQ_DEL_VLAN_FILTER ;if (!list_empty (&adapter->cloud_filter_list)) adapter->aq_required |=IAVF_FLAG_AQ_DEL_CLOUD_FILTER ;if (!list_empty (&adapter->fdir_list_head))
@@ -4488,8 +4459,6 @@ static int iavf_open(struct net_device *netdev)iavf_add_filter (adapter, adapter->hw.mac.addr);spin_unlock_bh (&adapter->mac_vlan_list_lock); -/* Restore filters that were removed with IFF_DOWN */ -iavf_restore_filters (adapter);iavf_restore_fdir_filters (adapter);iavf_configure (adapter);
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +6 -27
@@ -911,22 +911,12 @@ void iavf_del_vlans(struct iavf_adapter *adapter)spin_lock_bh (&adapter->mac_vlan_list_lock);list_for_each_entry_safe (f, ftmp, &adapter->vlan_filter_list, list) { -/* since VLAN capabilities are not allowed, we dont want to send -* a VLAN delete request because it will most likely fail and -* create unnecessary errors/noise, so just free the VLAN -* filters marked for removal to enable bailing out before -* sending a virtchnl message -*/ if (f->state ==IAVF_VLAN_REMOVE && !VLAN_FILTERING_ALLOWED (adapter)) {list_del (&f->list);kfree (f); adapter->num_vlan_filters--; - }else if (f->state ==IAVF_VLAN_DISABLE && - !VLAN_FILTERING_ALLOWED (adapter)) { - f->state =IAVF_VLAN_INACTIVE ; - }else if (f->state ==IAVF_VLAN_REMOVE || - f->state ==IAVF_VLAN_DISABLE ) { + }else if (f->state ==IAVF_VLAN_REMOVE ) { count++; } }
@@ -959,13 +949,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) vvfl->vsi_id = adapter->vsi_res->vsi_id; vvfl->num_elements = count;list_for_each_entry_safe (f, ftmp, &adapter->vlan_filter_list, list) { -if (f->state ==IAVF_VLAN_DISABLE ) { - vvfl->vlan_id[i] = f->vlan.vid; - f->state =IAVF_VLAN_INACTIVE ; - i++; -if (i == count) -break ; - }else if (f->state ==IAVF_VLAN_REMOVE ) { +if (f->state ==IAVF_VLAN_REMOVE ) { vvfl->vlan_id[i] = f->vlan.vid;list_del (&f->list);kfree (f);
@@ -1007,8 +991,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) vvfl_v2->vport_id = adapter->vsi_res->vsi_id; vvfl_v2->num_elements = count;list_for_each_entry_safe (f, ftmp, &adapter->vlan_filter_list, list) { -if (f->state ==IAVF_VLAN_DISABLE || - f->state ==IAVF_VLAN_REMOVE ) { +if (f->state ==IAVF_VLAN_REMOVE ) {struct virtchnl_vlan_supported_caps *filtering_support = &adapter->vlan_v2_caps.filtering.filtering_support;struct virtchnl_vlan *vlan;
@@ -1022,13 +1005,9 @@ void iavf_del_vlans(struct iavf_adapter *adapter) vlan->tci = f->vlan.vid; vlan->tpid = f->vlan.tpid; -if (f->state ==IAVF_VLAN_DISABLE ) { - f->state =IAVF_VLAN_INACTIVE ; - }else { -list_del (&f->list); -kfree (f); - adapter->num_vlan_filters--; - } +list_del (&f->list); +kfree (f); + adapter->num_vlan_filters--; i++;if (i == count)break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1022/1146 iavf: wait for PF confirmation before removing VLAN filters
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Oros <[email protected]>
[ Upstream commit bbcbe4ed70dea948849549af7edf44bd42bbd695 ]
The VLAN filter DELETE path was asymmetric with the ADD path: ADD waits for PF confirmation (ADD -> ADDING -> ACTIVE), but DELETE immediately frees the filter struct after sending the DEL message without waiting for the PF response.
This is problematic because:
- If the PF rejects the DEL, the filter remains in HW but the driver has already freed the tracking structure, losing sync.
- Race conditions between DEL pending and other operations (add, reset) cannot be properly resolved if the filter struct is already gone.
Add IAVF_VLAN_REMOVING state to make the DELETE path symmetric:
REMOVE -> REMOVING (send DEL) -> PF confirms -> kfree
-> PF rejects -> ACTIVE
In iavf_del_vlans(), transition filters from REMOVE to REMOVING instead of immediately freeing them. The new DEL completion handler in iavf_virtchnl_completion() frees filters on success or reverts them to ACTIVE on error.
Update iavf_add_vlan() to handle the REMOVING state: if a DEL is pending and the user re-adds the same VLAN, queue it for ADD so it gets re-programmed after the PF processes the DEL.
The !VLAN_FILTERING_ALLOWED early-exit path still frees filters directly since no PF message is sent in that case.
Also update iavf_del_vlan() to skip filters already in REMOVING
state: DEL has been sent to PF and the completion handler will free the filter when PF confirms. Without this guard, the sequence DEL(pending) -> user-del -> second DEL could cause the PF to return an error for the second DEL (filter already gone), causing the completion handler to incorrectly revert a deleted filter back to ACTIVE.
--- drivers/net/ethernet/intel/iavf/iavf.h | 1 + drivers/net/ethernet/intel/iavf/iavf_main.c | 13 ++++--- .../net/ethernet/intel/iavf/iavf_virtchnl.c | 37 +++++++++++++------ 3 files changed, 34 insertions(+), 17 deletions(-)
drivers/net/ethernet/intel/iavf/iavf.h +1 -0
@@ -161,6 +161,7 @@ enum iavf_vlan_state_t {IAVF_VLAN_ADDING ,/* ADD sent to PF, waiting for response */ IAVF_VLAN_ACTIVE ,/* PF confirmed, filter is in HW */ IAVF_VLAN_REMOVE ,/* filter queued for DEL from PF */ + IAVF_VLAN_REMOVING, /* DEL sent to PF, waiting for response */ }; struct iavf_vlan_filter {
drivers/net/ethernet/intel/iavf/iavf_main.c +8 -5
@@ -757,10 +757,10 @@ iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter, adapter->num_vlan_filters++;iavf_schedule_aq_request (adapter,IAVF_FLAG_AQ_ADD_VLAN_FILTER ); }else if (f->state ==IAVF_VLAN_REMOVE ) { -/* Re-add the filter since we cannot tell whether the -* pending delete has already been processed by the PF. -* A duplicate add is harmless. -*/ +/* DEL not yet sent to PF, cancel it */ + f->state =IAVF_VLAN_ACTIVE ; + }else if (f->state ==IAVF_VLAN_REMOVING ) { +/* DEL already sent to PF, re-add after completion */ f->state =IAVF_VLAN_ADD ;iavf_schedule_aq_request (adapter,IAVF_FLAG_AQ_ADD_VLAN_FILTER );
@@ -791,11 +791,14 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan)list_del (&f->list);kfree (f); adapter->num_vlan_filters--; - }else { + }else if (f->state !=IAVF_VLAN_REMOVING ) { f->state =IAVF_VLAN_REMOVE ;iavf_schedule_aq_request (adapter,IAVF_FLAG_AQ_DEL_VLAN_FILTER ); } +/* If REMOVING, DEL is already sent to PF; completion +* handler will free the filter when PF confirms. +*/ }spin_unlock_bh (&adapter->mac_vlan_list_lock);
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +25 -12
@@ -948,12 +948,10 @@ void iavf_del_vlans(struct iavf_adapter *adapter) vvfl->vsi_id = adapter->vsi_res->vsi_id; vvfl->num_elements = count; -list_for_each_entry_safe (f, ftmp, &adapter->vlan_filter_list, list) { +list_for_each_entry (f, &adapter->vlan_filter_list, list) {if (f->state ==IAVF_VLAN_REMOVE ) { vvfl->vlan_id[i] = f->vlan.vid; -list_del (&f->list); -kfree (f); - adapter->num_vlan_filters--; + f->state =IAVF_VLAN_REMOVING ; i++;if (i == count)break ;
@@ -990,7 +988,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) vvfl_v2->vport_id = adapter->vsi_res->vsi_id; vvfl_v2->num_elements = count; -list_for_each_entry_safe (f, ftmp, &adapter->vlan_filter_list, list) { +list_for_each_entry (f, &adapter->vlan_filter_list, list) {if (f->state ==IAVF_VLAN_REMOVE ) {struct virtchnl_vlan_supported_caps *filtering_support = &adapter->vlan_v2_caps.filtering.filtering_support;
@@ -1005,9 +1003,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) vlan->tci = f->vlan.vid; vlan->tpid = f->vlan.tpid; -list_del (&f->list); -kfree (f); - adapter->num_vlan_filters--; + f->state =IAVF_VLAN_REMOVING ; i++;if (i == count)break ;
@@ -2370,10 +2366,6 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,ether_addr_copy (adapter->hw.mac.addr, netdev->dev_addr);wake_up (&adapter->vc_waitqueue);break ; -case VIRTCHNL_OP_DEL_VLAN : -dev_err (&adapter->pdev->dev,"Failed to delete VLAN filter, error %s\n" , -iavf_stat_str (&adapter->hw, v_retval)); -break ;case VIRTCHNL_OP_DEL_ETH_ADDR :dev_err (&adapter->pdev->dev,"Failed to delete MAC filter, error %s\n" ,iavf_stat_str (&adapter->hw, v_retval));
@@ -2895,6 +2887,27 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,spin_unlock_bh (&adapter->mac_vlan_list_lock); }break ; +case VIRTCHNL_OP_DEL_VLAN : +case VIRTCHNL_OP_DEL_VLAN_V2 : { +struct iavf_vlan_filter *f, *ftmp; + +spin_lock_bh (&adapter->mac_vlan_list_lock); +list_for_each_entry_safe (f, ftmp, &adapter->vlan_filter_list, + list) { +if (f->state ==IAVF_VLAN_REMOVING ) { +if (v_retval) { +/* PF rejected DEL, keep filter */ + f->state =IAVF_VLAN_ACTIVE ; + }else { +list_del (&f->list); +kfree (f); + adapter->num_vlan_filters--; + } + } + } +spin_unlock_bh (&adapter->mac_vlan_list_lock); + } +break ;case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING :/* PF enabled vlan strip on this VF. * Update netdev->features if needed to be in sync with ethtool.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1023/1146 iavf: add VIRTCHNL_OP_ADD_VLAN to success completion handler
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Oros <[email protected]>
[ Upstream commit 34d33313b52eeac3a97ad2e3176d523ec70d9283 ]
The V1 ADD_VLAN opcode had no success handler; filters sent via V1 stayed in ADDING state permanently. Add a fallthrough case so V1 filters also transition ADDING -> ACTIVE on PF confirmation.
Critically, add an if (v_retval) break guard: the error switch in iavf_virtchnl_completion() does NOT return after handling errors, it falls through to the success switch. Without this guard, a PF-rejected ADD would incorrectly mark ADDING filters as ACTIVE, creating a driver/HW mismatch where the driver believes the filter is installed but the PF never accepted it.
For V2, this is harmless: iavf_vlan_add_reject() in the error block already kfree'd all ADDING filters, so the success handler finds nothing to transition.
--- drivers/net/ethernet/intel/iavf/iavf_virtchnl.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +4 -0
@@ -2876,9 +2876,13 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,spin_unlock_bh (&adapter->adv_rss_lock); }break ; +case VIRTCHNL_OP_ADD_VLAN :case VIRTCHNL_OP_ADD_VLAN_V2 : {struct iavf_vlan_filter *f; +if (v_retval) +break ; +spin_lock_bh (&adapter->mac_vlan_list_lock);list_for_each_entry (f, &adapter->vlan_filter_list, list) {if (f->state ==IAVF_VLAN_ADDING )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1024/1146 ice: fix NULL pointer dereference in ice_reset_all_vfs()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Oros <[email protected]>
[ Upstream commit 54ef02487914c24170c7e1c061e45212dc55365e ]
ice_reset_all_vfs() ignores the return value of ice_vf_rebuild_vsi(). When the VSI rebuild fails (e.g. during NVM firmware update via nvmupdate64e), ice_vsi_rebuild() tears down the VSI on its error path, leaving txq_map and rxq_map as NULL. The subsequent unconditional call to ice_vf_post_vsi_rebuild() leads to a NULL pointer dereference in ice_ena_vf_q_mappings() when it accesses vsi->txq_map[0].
The single-VF reset path in ice_reset_vf() already handles this correctly by checking the return value of ice_vf_reconfig_vsi() and skipping ice_vf_post_vsi_rebuild() on failure.
Apply the same pattern to ice_reset_all_vfs(): check the return value of ice_vf_rebuild_vsi() and skip ice_vf_post_vsi_rebuild() and ice_eswitch_attach_vf() on failure. The VF is left safely disabled (ICE_VF_STATE_INIT not set, VFGEN_RSTAT not set to VFACTIVE) and can be recovered via a VFLR triggered by a PCI reset of the VF (sysfs reset or driver rebind).
Note that this patch does not prevent the VF VSI rebuild from failing during NVM update — the underlying cause is firmware being in a transitional state while the EMP reset is processed, which can cause Admin Queue commands (ice_add_vsi, ice_cfg_vsi_lan) to fail. This patch only prevents the subsequent NULL pointer dereference that crashes the kernel when the rebuild does fail.
crash> bt
PID: 50795 TASK: ff34c9ee708dc680 CPU: 1 COMMAND: "kworker/u512:5"
#0 [ff72159bcfe5bb50] machine_kexec at ffffffffaa8850ee
#1 [ff72159bcfe5bba8] __crash_kexec at ffffffffaaa15fba
#2 [ff72159bcfe5bc68] crash_kexec at ffffffffaaa16540
#3 [ff72159bcfe5bc70] oops_end at ffffffffaa837eda
#4 [ff72159bcfe5bc90] page_fault_oops at ffffffffaa893997
#5 [ff72159bcfe5bce8] exc_page_fault at ffffffffab528595
#6 [ff72159bcfe5bd10] asm_exc_page_fault at ffffffffab600bb2
[exception RIP: ice_ena_vf_q_mappings+0x79]
RIP: ffffffffc0a85b29 RSP: ff72159bcfe5bdc8 RFLAGS: 00010206
RAX: 00000000000f0000 RBX: ff34c9efc9c00000 RCX: 0000000000000000
RDX: 0000000000000000 RSI: 0000000000000010 RDI: ff34c9efc9c00000
RBP: ff34c9efc27d4828 R8: 0000000000000093 R9: 0000000000000040
R10: ff34c9efc27d4828 R11: 0000000000000040 R12: 0000000000100000
R13: 0000000000000010 R14: R15:
ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018
#7 [ff72159bcfe5bdf8] ice_sriov_post_vsi_rebuild at ffffffffc0a85e2e [ice]
#8 [ff72159bcfe5be08] ice_reset_all_vfs at ffffffffc0a920b4 [ice]
#9 [ff72159bcfe5be48] ice_service_task at ffffffffc0a31519 [ice]
#10 [ff72159bcfe5be88] process_one_work at ffffffffaa93dca4
#11 [ff72159bcfe5bec8] worker_thread at ffffffffaa93e9de
#12 [ff72159bcfe5bf18] kthread at ffffffffaa946663
#13 [ff72159bcfe5bf50] ret_from_fork at ffffffffaa8086b9 The panic occurs attempting to dereference the NULL pointer in RDX at ice_sriov.c:294, which loads vsi->txq_map (offset 0x4b8 in ice_vsi).
The faulting VSI is an allocated slab object but not fully initialized after a failed ice_vsi_rebuild():
crash> struct ice_vsi 0xff34c9efc27d4828
netdev = 0x0,
rx_rings = 0x0,
tx_rings = 0x0,
q_vectors = 0x0,
txq_map = 0x0,
rxq_map = 0x0,
alloc_txq = 0x10,
num_txq = 0x10,
alloc_rxq = 0x10,
num_rxq = 0x10,The nvmupdate64e process was performing NVM firmware update:
crash> bt 0xff34c9edd1a30000
PID: 49858 TASK: ff34c9edd1a30000 CPU: 1 COMMAND: "nvmupdate64e"
#0 [ff72159bcd617618] __schedule at ffffffffab5333f8
#4 [ff72159bcd617750] ice_sq_send_cmd at ffffffffc0a35347 [ice] #5 [ff72159bcd6177a8] ice_sq_send_cmd_retry at ffffffffc0a35b47 [ice] #6 [ff72159bcd617810] ice_aq_send_cmd at ffffffffc0a38018 [ice] #7 [ff72159bcd617848] ice_aq_read_nvm at ffffffffc0a40254 [ice] #8 [ff72159bcd6178b8] ice_read_flat_nvm at ffffffffc0a4034c [ice] #9 [ff72159bcd617918] ice_devlink_nvm_snapshot at ffffffffc0a6ffa5 [ice]
dmesg:
ice 0000:13:00.0: firmware recommends not updating fw.mgmt, as it
may result in a downgrade. continuing anyways
ice 0000:13:00.1: ice_init_nvm failed -5
ice 0000:13:00.1: Rebuild failed, unload and reload driver
--- drivers/net/ethernet/intel/ice/ice_vf_lib.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/net/ethernet/intel/ice/ice_vf_lib.c +6 -1
@@ -804,7 +804,12 @@ void ice_reset_all_vfs(struct ice_pf *pf)ice_vf_ctrl_invalidate_vsi (vf);ice_vf_pre_vsi_rebuild (vf); -ice_vf_rebuild_vsi (vf); +if (ice_vf_rebuild_vsi (vf)) { +dev_err (dev,"VF %u VSI rebuild failed, leaving VF disabled\n" , + vf->vf_id); +mutex_unlock (&vf->cfg_lock); +continue ; + }ice_vf_post_vsi_rebuild (vf);ice_eswitch_attach_vf (pf, vf);
Signature · 1 line
2.53.0