ALSA: rawmidi: Work around false-positive mutex lockdep warning

When opening a legacy rawmidi device for a UMP, it may re-open an
existing rawmidi device for appending to a substream, leading to a
lockdep warning due to rmidi->open_mutex taken twice -- but the
rawmidi devices are completely individual, hence it's a
false-positive.

For avoiding the warning, modify the helper to open a rawmidi instance
with a proper locking subclass from the UMP legacy open.

Unfortunately, there is no good way to achieve it with guard(), so
reverted to the manual mutex calls again.

Reported-by: syzbot+d10d58fc99caa0489796@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/6a6a9634.57649fcc.360844.000b.GAE@google.com
Link: https://patch.msgid.link/20260806101352.1291581-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Takashi Iwai
2026-08-06 12:13:51 +02:00
parent 02442d5fe8
commit 9c04742e73
3 changed files with 24 additions and 11 deletions

View File

@@ -176,8 +176,9 @@ int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream);
/* main midi functions */
int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info);
int snd_rawmidi_kernel_open(struct snd_rawmidi *rmidi, int subdevice,
int mode, struct snd_rawmidi_file *rfile);
int snd_rawmidi_kernel_open_nested(struct snd_rawmidi *rmidi, int subdevice,
int mode, struct snd_rawmidi_file *rfile,
int depth);
int snd_rawmidi_kernel_release(struct snd_rawmidi_file *rfile);
int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream,
struct snd_rawmidi_params *params);
@@ -191,6 +192,15 @@ long snd_rawmidi_kernel_read(struct snd_rawmidi_substream *substream,
long snd_rawmidi_kernel_write(struct snd_rawmidi_substream *substream,
const unsigned char *buf, long count);
/* non-nested version */
static inline int snd_rawmidi_kernel_open(struct snd_rawmidi *rmidi,
int subdevice,
int mode,
struct snd_rawmidi_file *rfile)
{
return snd_rawmidi_kernel_open_nested(rmidi, subdevice, mode, rfile, 0);
}
/* set up the tied devices */
static inline void snd_rawmidi_tie_devices(struct snd_rawmidi *r1,
struct snd_rawmidi *r2)

View File

@@ -408,9 +408,10 @@ static int rawmidi_open_priv(struct snd_rawmidi *rmidi, int subdevice, int mode,
return 0;
}
/* called from sound/core/seq/seq_midi.c */
int snd_rawmidi_kernel_open(struct snd_rawmidi *rmidi, int subdevice,
int mode, struct snd_rawmidi_file *rfile)
/* called from sound/core/seq/seq_midi.c and sound/core/ump.c */
int snd_rawmidi_kernel_open_nested(struct snd_rawmidi *rmidi, int subdevice,
int mode, struct snd_rawmidi_file *rfile,
int depth)
{
int err;
@@ -419,13 +420,14 @@ int snd_rawmidi_kernel_open(struct snd_rawmidi *rmidi, int subdevice,
if (!try_module_get(rmidi->card->module))
return -ENXIO;
guard(mutex)(&rmidi->open_mutex);
mutex_lock_nested(&rmidi->open_mutex, depth);
err = rawmidi_open_priv(rmidi, subdevice, mode, rfile);
if (err < 0)
module_put(rmidi->card->module);
mutex_unlock(&rmidi->open_mutex);
return err;
}
EXPORT_SYMBOL(snd_rawmidi_kernel_open);
EXPORT_SYMBOL(snd_rawmidi_kernel_open_nested);
static int snd_rawmidi_open(struct inode *inode, struct file *file)
{

View File

@@ -1157,10 +1157,11 @@ static int snd_ump_legacy_open(struct snd_rawmidi_substream *substream)
return -ENODEV;
if (dir == SNDRV_RAWMIDI_STREAM_OUTPUT) {
if (!ump->legacy_out_opens) {
err = snd_rawmidi_kernel_open(&ump->core, 0,
SNDRV_RAWMIDI_LFLG_OUTPUT |
SNDRV_RAWMIDI_LFLG_APPEND,
&ump->legacy_out_rfile);
err = snd_rawmidi_kernel_open_nested(&ump->core, 0,
SNDRV_RAWMIDI_LFLG_OUTPUT |
SNDRV_RAWMIDI_LFLG_APPEND,
&ump->legacy_out_rfile,
SINGLE_DEPTH_NESTING);
if (err < 0)
return err;
}