]>
Commit | Line | Data |
---|---|---|
731fa5a3 GKH |
1 | From 0b074ab7fc0d575247b9cc9f93bb7e007ca38840 Mon Sep 17 00:00:00 2001 |
2 | From: Takashi Iwai <tiwai@suse.de> | |
3 | Date: Tue, 28 May 2019 08:39:44 +0200 | |
4 | Subject: ALSA: line6: Assure canceling delayed work at disconnection | |
5 | ||
6 | From: Takashi Iwai <tiwai@suse.de> | |
7 | ||
8 | commit 0b074ab7fc0d575247b9cc9f93bb7e007ca38840 upstream. | |
9 | ||
10 | The current code performs the cancel of a delayed work at the late | |
11 | stage of disconnection procedure, which may lead to the access to the | |
12 | already cleared state. | |
13 | ||
14 | This patch assures to call cancel_delayed_work_sync() at the beginning | |
15 | of the disconnection procedure for avoiding that race. The delayed | |
16 | work object is now assigned in the common line6 object instead of its | |
17 | derivative, so that we can call cancel_delayed_work_sync(). | |
18 | ||
19 | Along with the change, the startup function is called via the new | |
20 | callback instead. This will make it easier to port other LINE6 | |
21 | drivers to use the delayed work for startup in later patches. | |
22 | ||
23 | Reported-by: syzbot+5255458d5e0a2b10bbb9@syzkaller.appspotmail.com | |
24 | Fixes: 7f84ff68be05 ("ALSA: line6: toneport: Fix broken usage of timer for delayed execution") | |
25 | Cc: <stable@vger.kernel.org> | |
26 | Signed-off-by: Takashi Iwai <tiwai@suse.de> | |
27 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
28 | ||
29 | --- | |
30 | sound/usb/line6/driver.c | 12 ++++++++++++ | |
31 | sound/usb/line6/driver.h | 4 ++++ | |
32 | sound/usb/line6/toneport.c | 15 +++------------ | |
33 | 3 files changed, 19 insertions(+), 12 deletions(-) | |
34 | ||
35 | --- a/sound/usb/line6/driver.c | |
36 | +++ b/sound/usb/line6/driver.c | |
37 | @@ -720,6 +720,15 @@ static int line6_init_cap_control(struct | |
38 | return 0; | |
39 | } | |
40 | ||
41 | +static void line6_startup_work(struct work_struct *work) | |
42 | +{ | |
43 | + struct usb_line6 *line6 = | |
44 | + container_of(work, struct usb_line6, startup_work.work); | |
45 | + | |
46 | + if (line6->startup) | |
47 | + line6->startup(line6); | |
48 | +} | |
49 | + | |
50 | /* | |
51 | Probe USB device. | |
52 | */ | |
53 | @@ -755,6 +764,7 @@ int line6_probe(struct usb_interface *in | |
54 | line6->properties = properties; | |
55 | line6->usbdev = usbdev; | |
56 | line6->ifcdev = &interface->dev; | |
57 | + INIT_DELAYED_WORK(&line6->startup_work, line6_startup_work); | |
58 | ||
59 | strcpy(card->id, properties->id); | |
60 | strcpy(card->driver, driver_name); | |
61 | @@ -825,6 +835,8 @@ void line6_disconnect(struct usb_interfa | |
62 | if (WARN_ON(usbdev != line6->usbdev)) | |
63 | return; | |
64 | ||
65 | + cancel_delayed_work(&line6->startup_work); | |
66 | + | |
67 | if (line6->urb_listen != NULL) | |
68 | line6_stop_listen(line6); | |
69 | ||
70 | --- a/sound/usb/line6/driver.h | |
71 | +++ b/sound/usb/line6/driver.h | |
72 | @@ -178,11 +178,15 @@ struct usb_line6 { | |
73 | fifo; | |
74 | } messages; | |
75 | ||
76 | + /* Work for delayed PCM startup */ | |
77 | + struct delayed_work startup_work; | |
78 | + | |
79 | /* If MIDI is supported, buffer_message contains the pre-processed data; | |
80 | * otherwise the data is only in urb_listen (buffer_incoming). | |
81 | */ | |
82 | void (*process_message)(struct usb_line6 *); | |
83 | void (*disconnect)(struct usb_line6 *line6); | |
84 | + void (*startup)(struct usb_line6 *line6); | |
85 | }; | |
86 | ||
87 | extern char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, | |
88 | --- a/sound/usb/line6/toneport.c | |
89 | +++ b/sound/usb/line6/toneport.c | |
90 | @@ -54,9 +54,6 @@ struct usb_line6_toneport { | |
91 | /* Firmware version (x 100) */ | |
92 | u8 firmware_version; | |
93 | ||
94 | - /* Work for delayed PCM startup */ | |
95 | - struct delayed_work pcm_work; | |
96 | - | |
97 | /* Device type */ | |
98 | enum line6_device_type type; | |
99 | ||
100 | @@ -241,12 +238,8 @@ static int snd_toneport_source_put(struc | |
101 | return 1; | |
102 | } | |
103 | ||
104 | -static void toneport_start_pcm(struct work_struct *work) | |
105 | +static void toneport_startup(struct usb_line6 *line6) | |
106 | { | |
107 | - struct usb_line6_toneport *toneport = | |
108 | - container_of(work, struct usb_line6_toneport, pcm_work.work); | |
109 | - struct usb_line6 *line6 = &toneport->line6; | |
110 | - | |
111 | line6_pcm_acquire(line6->line6pcm, LINE6_STREAM_MONITOR, true); | |
112 | } | |
113 | ||
114 | @@ -394,7 +387,7 @@ static int toneport_setup(struct usb_lin | |
115 | if (toneport_has_led(toneport)) | |
116 | toneport_update_led(toneport); | |
117 | ||
118 | - schedule_delayed_work(&toneport->pcm_work, | |
119 | + schedule_delayed_work(&toneport->line6.startup_work, | |
120 | msecs_to_jiffies(TONEPORT_PCM_DELAY * 1000)); | |
121 | return 0; | |
122 | } | |
123 | @@ -407,8 +400,6 @@ static void line6_toneport_disconnect(st | |
124 | struct usb_line6_toneport *toneport = | |
125 | (struct usb_line6_toneport *)line6; | |
126 | ||
127 | - cancel_delayed_work_sync(&toneport->pcm_work); | |
128 | - | |
129 | if (toneport_has_led(toneport)) | |
130 | toneport_remove_leds(toneport); | |
131 | } | |
132 | @@ -424,9 +415,9 @@ static int toneport_init(struct usb_line | |
133 | struct usb_line6_toneport *toneport = (struct usb_line6_toneport *) line6; | |
134 | ||
135 | toneport->type = id->driver_info; | |
136 | - INIT_DELAYED_WORK(&toneport->pcm_work, toneport_start_pcm); | |
137 | ||
138 | line6->disconnect = line6_toneport_disconnect; | |
139 | + line6->startup = toneport_startup; | |
140 | ||
141 | /* initialize PCM subsystem: */ | |
142 | err = line6_init_pcm(line6, &toneport_pcm_properties); |