Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 59866da

Browse files
committed
ALSA: usb-audio: Avoid autopm calls after disconnection
Add a similar protection against the disconnection race and the invalid use of usb instance after disconnection, as well as we've done for the USB audio PCM. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=51201 Reviewd-by: Clemens Ladisch <[email protected]> Tested-by: Clemens Ladisch <[email protected]> Cc: <[email protected]> Signed-off-by: Takashi Iwai <[email protected]>
1 parent 467b103 commit 59866da

File tree

1 file changed

+22
-1
lines changed

1 file changed

+22
-1
lines changed

sound/usb/midi.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ struct snd_usb_midi {
116116
struct list_head list;
117117
struct timer_list error_timer;
118118
spinlock_t disc_lock;
119+
struct rw_semaphore disc_rwsem;
119120
struct mutex mutex;
120121
u32 usb_id;
121122
int next_midi_device;
@@ -1038,6 +1039,12 @@ static void substream_open(struct snd_rawmidi_substream *substream, int open)
10381039
struct snd_usb_midi* umidi = substream->rmidi->private_data;
10391040
struct snd_kcontrol *ctl;
10401041

1042+
down_read(&umidi->disc_rwsem);
1043+
if (umidi->disconnected) {
1044+
up_read(&umidi->disc_rwsem);
1045+
return;
1046+
}
1047+
10411048
mutex_lock(&umidi->mutex);
10421049
if (open) {
10431050
if (umidi->opened++ == 0 && umidi->roland_load_ctl) {
@@ -1056,6 +1063,7 @@ static void substream_open(struct snd_rawmidi_substream *substream, int open)
10561063
}
10571064
}
10581065
mutex_unlock(&umidi->mutex);
1066+
up_read(&umidi->disc_rwsem);
10591067
}
10601068

10611069
static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
@@ -1076,8 +1084,15 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
10761084
snd_BUG();
10771085
return -ENXIO;
10781086
}
1087+
1088+
down_read(&umidi->disc_rwsem);
1089+
if (umidi->disconnected) {
1090+
up_read(&umidi->disc_rwsem);
1091+
return -ENODEV;
1092+
}
10791093
err = usb_autopm_get_interface(umidi->iface);
10801094
port->autopm_reference = err >= 0;
1095+
up_read(&umidi->disc_rwsem);
10811096
if (err < 0 && err != -EACCES)
10821097
return -EIO;
10831098
substream->runtime->private_data = port;
@@ -1092,8 +1107,10 @@ static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream)
10921107
struct usbmidi_out_port *port = substream->runtime->private_data;
10931108

10941109
substream_open(substream, 0);
1095-
if (port->autopm_reference)
1110+
down_read(&umidi->disc_rwsem);
1111+
if (!umidi->disconnected && port->autopm_reference)
10961112
usb_autopm_put_interface(umidi->iface);
1113+
up_read(&umidi->disc_rwsem);
10971114
return 0;
10981115
}
10991116

@@ -1403,9 +1420,12 @@ void snd_usbmidi_disconnect(struct list_head* p)
14031420
* a timer may submit an URB. To reliably break the cycle
14041421
* a flag under lock must be used
14051422
*/
1423+
down_write(&umidi->disc_rwsem);
14061424
spin_lock_irq(&umidi->disc_lock);
14071425
umidi->disconnected = 1;
14081426
spin_unlock_irq(&umidi->disc_lock);
1427+
up_write(&umidi->disc_rwsem);
1428+
14091429
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
14101430
struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i];
14111431
if (ep->out)
@@ -2117,6 +2137,7 @@ int snd_usbmidi_create(struct snd_card *card,
21172137
umidi->usb_protocol_ops = &snd_usbmidi_standard_ops;
21182138
init_timer(&umidi->error_timer);
21192139
spin_lock_init(&umidi->disc_lock);
2140+
init_rwsem(&umidi->disc_rwsem);
21202141
mutex_init(&umidi->mutex);
21212142
umidi->usb_id = USB_ID(le16_to_cpu(umidi->dev->descriptor.idVendor),
21222143
le16_to_cpu(umidi->dev->descriptor.idProduct));

0 commit comments

Comments
 (0)