From: Ziyi Guo <[email protected]>

[ Upstream commit f514248727606b9087bc38a284ff686e0093abf1 ]

fsl_xcvr_activate_ctl() has
lockdep_assert_held(&card->snd_card->controls_rwsem),
but fsl_xcvr_mode_put() calls it without acquiring this lock.

Other callers of fsl_xcvr_activate_ctl() in fsl_xcvr_startup() and
fsl_xcvr_shutdown() properly acquire the lock with down_read()/up_read().

Add the missing down_read()/up_read() calls around fsl_xcvr_activate_ctl()
in fsl_xcvr_mode_put() to fix the lockdep assertion and prevent potential
race conditions when multiple userspace threads access the control.

Signed-off-by: Ziyi Guo <[email protected]>
Link: 
https://patch.msgid.link/[email protected]
Signed-off-by: Mark Brown <[email protected]>
Signed-off-by: Sasha Levin <[email protected]>
---

LLM Generated explanations, may be completely bogus:

Line 194 confirms the `lockdep_assert_held` — this will trigger a
lockdep warning when `fsl_xcvr_mode_put()` is called without the lock
held.

The function modifies `kctl->vd[0].access` (lines 205-207) and calls
`snd_ctl_notify` — without the lock, concurrent access could corrupt the
control's access flags, leading to undefined behavior.

### 3. Classification

- **Bug type**: Missing locking — race condition and lockdep assertion
  violation
- **Category**: Synchronization fix
- **This is NOT**: A feature, refactoring, or cleanup — it's purely
  adding missing synchronization

### 4. Scope and Risk Assessment

- **Lines changed**: +3 (down_read, up_read, blank line)
- **Files changed**: 1 (sound/soc/fsl/fsl_xcvr.c)
- **Risk**: Extremely low — the fix follows the exact same pattern as
  all other callers of the same function
- **Could it break anything?**: The lock is a read-lock (`down_read`),
  and `fsl_xcvr_mode_put()` is called from the ALSA control put path
  which should not hold this lock already (no deadlock risk). The other
  callers also use `down_read`, so there's no write-lock contention
  introduced.

### 5. User Impact

- **Who is affected**: Users of NXP i.MX SoCs with XCVR (audio
  transceiver) — this is used on i.MX 8MP and similar
- **Trigger**: Changing the audio mode via ALSA controls (e.g.,
  switching between SPDIF/ARC/eARC modes)
- **Symptom**: lockdep WARNING at minimum; potential data race on
  control access flags that could cause inconsistent state
- **Severity**: Medium — lockdep warnings are real bugs that indicate
  potential for corruption

### 6. Stability and Dependencies

- **Reviewed-by**: Accepted by Mark Brown (ASoC maintainer) — strong
  confidence signal
- **Dependencies**: None — this is a standalone fix. The
  `controls_rwsem` and `fsl_xcvr_activate_ctl()` function have been
  present for a long time
- **Backport difficulty**: Trivial — the patch is small and the
  surrounding code is stable

### 7. Summary

This is a textbook stable backport candidate:
- **Obviously correct**: Follows the exact same locking pattern as the 2
  other callers of the same function
- **Fixes a real bug**: Missing lock causes lockdep assertion and
  potential race condition
- **Small and contained**: 3 lines added in 1 file
- **No new features**: Pure bug fix
- **Low risk**: Read-lock addition following established pattern,
  accepted by subsystem maintainer

**YES**

 sound/soc/fsl/fsl_xcvr.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c
index 58db4906a01d5..51669e5fe8888 100644
--- a/sound/soc/fsl/fsl_xcvr.c
+++ b/sound/soc/fsl/fsl_xcvr.c
@@ -223,10 +223,13 @@ static int fsl_xcvr_mode_put(struct snd_kcontrol 
*kcontrol,
 
        xcvr->mode = snd_soc_enum_item_to_val(e, item[0]);
 
+       down_read(&card->snd_card->controls_rwsem);
        fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name,
                              (xcvr->mode == FSL_XCVR_MODE_ARC));
        fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name,
                              (xcvr->mode == FSL_XCVR_MODE_EARC));
+       up_read(&card->snd_card->controls_rwsem);
+
        /* Allow playback for SPDIF only */
        rtd = snd_soc_get_pcm_runtime(card, card->dai_link);
        rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count =
-- 
2.51.0


Reply via email to