summaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2019-05-08 09:01:24 -0400
committerTakashi Iwai <tiwai@suse.de>2019-05-08 09:31:24 -0400
commit7f84ff68be05ec7a5d2acf8fdc734fe5897af48f (patch)
treea420b1da64e5752da6dc74515867f29ddf75f12c /sound
parent534420c6ff87d3052540f1fd346e0adcff440819 (diff)
ALSA: line6: toneport: Fix broken usage of timer for delayed execution
The line6 toneport driver has code for some delayed initialization, and this hits the kernel Oops because mutex and other sleepable functions are used in the timer callback. Fix the abuse by a delayed work instead so that everything works gracefully. Reported-by: syzbot+a07d0142e74fdd595cfb@syzkaller.appspotmail.com Cc: <stable@vger.kernel.org> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r--sound/usb/line6/toneport.c16
1 files changed, 9 insertions, 7 deletions
diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c
index 19bee725de00..325b07b98b3c 100644
--- a/sound/usb/line6/toneport.c
+++ b/sound/usb/line6/toneport.c
@@ -54,8 +54,8 @@ struct usb_line6_toneport {
54 /* Firmware version (x 100) */ 54 /* Firmware version (x 100) */
55 u8 firmware_version; 55 u8 firmware_version;
56 56
57 /* Timer for delayed PCM startup */ 57 /* Work for delayed PCM startup */
58 struct timer_list timer; 58 struct delayed_work pcm_work;
59 59
60 /* Device type */ 60 /* Device type */
61 enum line6_device_type type; 61 enum line6_device_type type;
@@ -241,9 +241,10 @@ static int snd_toneport_source_put(struct snd_kcontrol *kcontrol,
241 return 1; 241 return 1;
242} 242}
243 243
244static void toneport_start_pcm(struct timer_list *t) 244static void toneport_start_pcm(struct work_struct *work)
245{ 245{
246 struct usb_line6_toneport *toneport = from_timer(toneport, t, timer); 246 struct usb_line6_toneport *toneport =
247 container_of(work, struct usb_line6_toneport, pcm_work.work);
247 struct usb_line6 *line6 = &toneport->line6; 248 struct usb_line6 *line6 = &toneport->line6;
248 249
249 line6_pcm_acquire(line6->line6pcm, LINE6_STREAM_MONITOR, true); 250 line6_pcm_acquire(line6->line6pcm, LINE6_STREAM_MONITOR, true);
@@ -393,7 +394,8 @@ static int toneport_setup(struct usb_line6_toneport *toneport)
393 if (toneport_has_led(toneport)) 394 if (toneport_has_led(toneport))
394 toneport_update_led(toneport); 395 toneport_update_led(toneport);
395 396
396 mod_timer(&toneport->timer, jiffies + TONEPORT_PCM_DELAY * HZ); 397 schedule_delayed_work(&toneport->pcm_work,
398 msecs_to_jiffies(TONEPORT_PCM_DELAY * 1000));
397 return 0; 399 return 0;
398} 400}
399 401
@@ -405,7 +407,7 @@ static void line6_toneport_disconnect(struct usb_line6 *line6)
405 struct usb_line6_toneport *toneport = 407 struct usb_line6_toneport *toneport =
406 (struct usb_line6_toneport *)line6; 408 (struct usb_line6_toneport *)line6;
407 409
408 del_timer_sync(&toneport->timer); 410 cancel_delayed_work_sync(&toneport->pcm_work);
409 411
410 if (toneport_has_led(toneport)) 412 if (toneport_has_led(toneport))
411 toneport_remove_leds(toneport); 413 toneport_remove_leds(toneport);
@@ -422,7 +424,7 @@ static int toneport_init(struct usb_line6 *line6,
422 struct usb_line6_toneport *toneport = (struct usb_line6_toneport *) line6; 424 struct usb_line6_toneport *toneport = (struct usb_line6_toneport *) line6;
423 425
424 toneport->type = id->driver_info; 426 toneport->type = id->driver_info;
425 timer_setup(&toneport->timer, toneport_start_pcm, 0); 427 INIT_DELAYED_WORK(&toneport->pcm_work, toneport_start_pcm);
426 428
427 line6->disconnect = line6_toneport_disconnect; 429 line6->disconnect = line6_toneport_disconnect;
428 430