Skip to content

Commit

Permalink
ALSA: line6: toneport: Fix broken usage of timer for delayed execution
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Takashi Iwai committed May 8, 2019
1 parent 534420c commit 7f84ff6
Showing 1 changed file with 9 additions and 7 deletions.
16 changes: 9 additions & 7 deletions sound/usb/line6/toneport.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ struct usb_line6_toneport {
/* Firmware version (x 100) */
u8 firmware_version;

/* Timer for delayed PCM startup */
struct timer_list timer;
/* Work for delayed PCM startup */
struct delayed_work pcm_work;

/* Device type */
enum line6_device_type type;
Expand Down Expand Up @@ -241,9 +241,10 @@ static int snd_toneport_source_put(struct snd_kcontrol *kcontrol,
return 1;
}

static void toneport_start_pcm(struct timer_list *t)
static void toneport_start_pcm(struct work_struct *work)
{
struct usb_line6_toneport *toneport = from_timer(toneport, t, timer);
struct usb_line6_toneport *toneport =
container_of(work, struct usb_line6_toneport, pcm_work.work);
struct usb_line6 *line6 = &toneport->line6;

line6_pcm_acquire(line6->line6pcm, LINE6_STREAM_MONITOR, true);
Expand Down Expand Up @@ -393,7 +394,8 @@ static int toneport_setup(struct usb_line6_toneport *toneport)
if (toneport_has_led(toneport))
toneport_update_led(toneport);

mod_timer(&toneport->timer, jiffies + TONEPORT_PCM_DELAY * HZ);
schedule_delayed_work(&toneport->pcm_work,
msecs_to_jiffies(TONEPORT_PCM_DELAY * 1000));
return 0;
}

Expand All @@ -405,7 +407,7 @@ static void line6_toneport_disconnect(struct usb_line6 *line6)
struct usb_line6_toneport *toneport =
(struct usb_line6_toneport *)line6;

del_timer_sync(&toneport->timer);
cancel_delayed_work_sync(&toneport->pcm_work);

if (toneport_has_led(toneport))
toneport_remove_leds(toneport);
Expand All @@ -422,7 +424,7 @@ static int toneport_init(struct usb_line6 *line6,
struct usb_line6_toneport *toneport = (struct usb_line6_toneport *) line6;

toneport->type = id->driver_info;
timer_setup(&toneport->timer, toneport_start_pcm, 0);
INIT_DELAYED_WORK(&toneport->pcm_work, toneport_start_pcm);

line6->disconnect = line6_toneport_disconnect;

Expand Down

0 comments on commit 7f84ff6

Please sign in to comment.