Commit 59866da9e4ae54819e3c4e0a8f426bdb0c2ef993

Authored by Takashi Iwai
1 parent 467b103505

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 <clemens@ladisch.de>
Tested-by: Clemens Ladisch <clemens@ladisch.de>
Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>

Showing 1 changed file with 22 additions and 1 deletions Side-by-side Diff

... ... @@ -116,6 +116,7 @@
116 116 struct list_head list;
117 117 struct timer_list error_timer;
118 118 spinlock_t disc_lock;
  119 + struct rw_semaphore disc_rwsem;
119 120 struct mutex mutex;
120 121 u32 usb_id;
121 122 int next_midi_device;
... ... @@ -1038,6 +1039,12 @@
1038 1039 struct snd_usb_midi* umidi = substream->rmidi->private_data;
1039 1040 struct snd_kcontrol *ctl;
1040 1041  
  1042 + down_read(&umidi->disc_rwsem);
  1043 + if (umidi->disconnected) {
  1044 + up_read(&umidi->disc_rwsem);
  1045 + return;
  1046 + }
  1047 +
1041 1048 mutex_lock(&umidi->mutex);
1042 1049 if (open) {
1043 1050 if (umidi->opened++ == 0 && umidi->roland_load_ctl) {
... ... @@ -1056,6 +1063,7 @@
1056 1063 }
1057 1064 }
1058 1065 mutex_unlock(&umidi->mutex);
  1066 + up_read(&umidi->disc_rwsem);
1059 1067 }
1060 1068  
1061 1069 static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
1062 1070  
... ... @@ -1076,8 +1084,15 @@
1076 1084 snd_BUG();
1077 1085 return -ENXIO;
1078 1086 }
  1087 +
  1088 + down_read(&umidi->disc_rwsem);
  1089 + if (umidi->disconnected) {
  1090 + up_read(&umidi->disc_rwsem);
  1091 + return -ENODEV;
  1092 + }
1079 1093 err = usb_autopm_get_interface(umidi->iface);
1080 1094 port->autopm_reference = err >= 0;
  1095 + up_read(&umidi->disc_rwsem);
1081 1096 if (err < 0 && err != -EACCES)
1082 1097 return -EIO;
1083 1098 substream->runtime->private_data = port;
1084 1099  
... ... @@ -1092,8 +1107,10 @@
1092 1107 struct usbmidi_out_port *port = substream->runtime->private_data;
1093 1108  
1094 1109 substream_open(substream, 0);
1095   - if (port->autopm_reference)
  1110 + down_read(&umidi->disc_rwsem);
  1111 + if (!umidi->disconnected && port->autopm_reference)
1096 1112 usb_autopm_put_interface(umidi->iface);
  1113 + up_read(&umidi->disc_rwsem);
1097 1114 return 0;
1098 1115 }
1099 1116  
1100 1117  
... ... @@ -1403,9 +1420,12 @@
1403 1420 * a timer may submit an URB. To reliably break the cycle
1404 1421 * a flag under lock must be used
1405 1422 */
  1423 + down_write(&umidi->disc_rwsem);
1406 1424 spin_lock_irq(&umidi->disc_lock);
1407 1425 umidi->disconnected = 1;
1408 1426 spin_unlock_irq(&umidi->disc_lock);
  1427 + up_write(&umidi->disc_rwsem);
  1428 +
1409 1429 for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
1410 1430 struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i];
1411 1431 if (ep->out)
... ... @@ -2117,6 +2137,7 @@
2117 2137 umidi->usb_protocol_ops = &snd_usbmidi_standard_ops;
2118 2138 init_timer(&umidi->error_timer);
2119 2139 spin_lock_init(&umidi->disc_lock);
  2140 + init_rwsem(&umidi->disc_rwsem);
2120 2141 mutex_init(&umidi->mutex);
2121 2142 umidi->usb_id = USB_ID(le16_to_cpu(umidi->dev->descriptor.idVendor),
2122 2143 le16_to_cpu(umidi->dev->descriptor.idProduct));