]>
Commit | Line | Data |
---|---|---|
903eef9e GKH |
1 | From tiwai@suse.de Wed Nov 7 15:57:25 2012 |
2 | From: tiwai@suse.de | |
3 | Date: Wed, 7 Nov 2012 12:39:53 +0100 | |
4 | Subject: ALSA: usb-audio: Use rwsem for disconnect protection | |
5 | To: stable@vger.kernel.org | |
6 | ||
7 | From: Takashi Iwai <tiwai@suse.de> | |
8 | ||
9 | commit 34f3c89fda4fba9fe689db22253ca8db2f5e6386 upstream. | |
10 | ||
11 | Replace mutex with rwsem for codec->shutdown protection so that | |
12 | concurrent accesses are allowed. | |
13 | ||
14 | Also add the protection to snd_usb_autosuspend() and | |
15 | snd_usb_autoresume(), too. | |
16 | ||
17 | Reported-by: Matthieu CASTET <matthieu.castet@parrot.com> | |
18 | Signed-off-by: Takashi Iwai <tiwai@suse.de> | |
19 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
20 | --- | |
21 | sound/usb/card.c | 12 ++++++++---- | |
22 | sound/usb/mixer.c | 12 ++++++------ | |
23 | sound/usb/pcm.c | 12 ++++++------ | |
24 | sound/usb/usbaudio.h | 2 +- | |
25 | 4 files changed, 21 insertions(+), 17 deletions(-) | |
26 | ||
27 | --- a/sound/usb/card.c | |
28 | +++ b/sound/usb/card.c | |
29 | @@ -339,7 +339,7 @@ static int snd_usb_audio_create(struct u | |
30 | } | |
31 | ||
32 | mutex_init(&chip->mutex); | |
33 | - mutex_init(&chip->shutdown_mutex); | |
34 | + init_rwsem(&chip->shutdown_rwsem); | |
35 | chip->index = idx; | |
36 | chip->dev = dev; | |
37 | chip->card = card; | |
38 | @@ -560,7 +560,7 @@ static void snd_usb_audio_disconnect(str | |
39 | ||
40 | card = chip->card; | |
41 | mutex_lock(®ister_mutex); | |
42 | - mutex_lock(&chip->shutdown_mutex); | |
43 | + down_write(&chip->shutdown_rwsem); | |
44 | chip->shutdown = 1; | |
45 | chip->num_interfaces--; | |
46 | if (chip->num_interfaces <= 0) { | |
47 | @@ -582,11 +582,11 @@ static void snd_usb_audio_disconnect(str | |
48 | snd_usb_mixer_disconnect(p); | |
49 | } | |
50 | usb_chip[chip->index] = NULL; | |
51 | - mutex_unlock(&chip->shutdown_mutex); | |
52 | + up_write(&chip->shutdown_rwsem); | |
53 | mutex_unlock(®ister_mutex); | |
54 | snd_card_free_when_closed(card); | |
55 | } else { | |
56 | - mutex_unlock(&chip->shutdown_mutex); | |
57 | + up_write(&chip->shutdown_rwsem); | |
58 | mutex_unlock(®ister_mutex); | |
59 | } | |
60 | } | |
61 | @@ -618,16 +618,20 @@ int snd_usb_autoresume(struct snd_usb_au | |
62 | { | |
63 | int err = -ENODEV; | |
64 | ||
65 | + down_read(&chip->shutdown_rwsem); | |
66 | if (!chip->shutdown && !chip->probing) | |
67 | err = usb_autopm_get_interface(chip->pm_intf); | |
68 | + up_read(&chip->shutdown_rwsem); | |
69 | ||
70 | return err; | |
71 | } | |
72 | ||
73 | void snd_usb_autosuspend(struct snd_usb_audio *chip) | |
74 | { | |
75 | + down_read(&chip->shutdown_rwsem); | |
76 | if (!chip->shutdown && !chip->probing) | |
77 | usb_autopm_put_interface(chip->pm_intf); | |
78 | + up_read(&chip->shutdown_rwsem); | |
79 | } | |
80 | ||
81 | static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) | |
82 | --- a/sound/usb/mixer.c | |
83 | +++ b/sound/usb/mixer.c | |
84 | @@ -292,7 +292,7 @@ static int get_ctl_value_v1(struct usb_m | |
85 | err = snd_usb_autoresume(cval->mixer->chip); | |
86 | if (err < 0) | |
87 | return -EIO; | |
88 | - mutex_lock(&chip->shutdown_mutex); | |
89 | + down_read(&chip->shutdown_rwsem); | |
90 | while (timeout-- > 0) { | |
91 | if (chip->shutdown) | |
92 | break; | |
93 | @@ -310,7 +310,7 @@ static int get_ctl_value_v1(struct usb_m | |
94 | err = -EINVAL; | |
95 | ||
96 | out: | |
97 | - mutex_unlock(&chip->shutdown_mutex); | |
98 | + up_read(&chip->shutdown_rwsem); | |
99 | snd_usb_autosuspend(cval->mixer->chip); | |
100 | return err; | |
101 | } | |
102 | @@ -337,7 +337,7 @@ static int get_ctl_value_v2(struct usb_m | |
103 | if (ret) | |
104 | goto error; | |
105 | ||
106 | - mutex_lock(&chip->shutdown_mutex); | |
107 | + down_read(&chip->shutdown_rwsem); | |
108 | if (chip->shutdown) | |
109 | ret = -ENODEV; | |
110 | else { | |
111 | @@ -346,7 +346,7 @@ static int get_ctl_value_v2(struct usb_m | |
112 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, | |
113 | validx, idx, buf, size); | |
114 | } | |
115 | - mutex_unlock(&chip->shutdown_mutex); | |
116 | + up_read(&chip->shutdown_rwsem); | |
117 | snd_usb_autosuspend(chip); | |
118 | ||
119 | if (ret < 0) { | |
120 | @@ -453,7 +453,7 @@ int snd_usb_mixer_set_ctl_value(struct u | |
121 | err = snd_usb_autoresume(chip); | |
122 | if (err < 0) | |
123 | return -EIO; | |
124 | - mutex_lock(&chip->shutdown_mutex); | |
125 | + down_read(&chip->shutdown_rwsem); | |
126 | while (timeout-- > 0) { | |
127 | if (chip->shutdown) | |
128 | break; | |
129 | @@ -471,7 +471,7 @@ int snd_usb_mixer_set_ctl_value(struct u | |
130 | err = -EINVAL; | |
131 | ||
132 | out: | |
133 | - mutex_unlock(&chip->shutdown_mutex); | |
134 | + up_read(&chip->shutdown_rwsem); | |
135 | snd_usb_autosuspend(chip); | |
136 | return err; | |
137 | } | |
138 | --- a/sound/usb/pcm.c | |
139 | +++ b/sound/usb/pcm.c | |
140 | @@ -474,7 +474,7 @@ static int snd_usb_hw_params(struct snd_ | |
141 | subs->period_bytes != params_period_bytes(hw_params) || | |
142 | subs->cur_rate != rate; | |
143 | ||
144 | - mutex_lock(&subs->stream->chip->shutdown_mutex); | |
145 | + down_read(&subs->stream->chip->shutdown_rwsem); | |
146 | if (subs->stream->chip->shutdown) { | |
147 | ret = -ENODEV; | |
148 | goto unlock; | |
149 | @@ -512,7 +512,7 @@ static int snd_usb_hw_params(struct snd_ | |
150 | } | |
151 | ||
152 | unlock: | |
153 | - mutex_unlock(&subs->stream->chip->shutdown_mutex); | |
154 | + up_read(&subs->stream->chip->shutdown_rwsem); | |
155 | return ret; | |
156 | } | |
157 | ||
158 | @@ -528,12 +528,12 @@ static int snd_usb_hw_free(struct snd_pc | |
159 | subs->cur_audiofmt = NULL; | |
160 | subs->cur_rate = 0; | |
161 | subs->period_bytes = 0; | |
162 | - mutex_lock(&subs->stream->chip->shutdown_mutex); | |
163 | + down_read(&subs->stream->chip->shutdown_rwsem); | |
164 | if (!subs->stream->chip->shutdown) { | |
165 | stop_endpoints(subs, 0, 1, 1); | |
166 | deactivate_endpoints(subs); | |
167 | } | |
168 | - mutex_unlock(&subs->stream->chip->shutdown_mutex); | |
169 | + up_read(&subs->stream->chip->shutdown_rwsem); | |
170 | return snd_pcm_lib_free_vmalloc_buffer(substream); | |
171 | } | |
172 | ||
173 | @@ -553,7 +553,7 @@ static int snd_usb_pcm_prepare(struct sn | |
174 | return -ENXIO; | |
175 | } | |
176 | ||
177 | - mutex_lock(&subs->stream->chip->shutdown_mutex); | |
178 | + down_read(&subs->stream->chip->shutdown_rwsem); | |
179 | if (subs->stream->chip->shutdown) { | |
180 | ret = -ENODEV; | |
181 | goto unlock; | |
182 | @@ -582,7 +582,7 @@ static int snd_usb_pcm_prepare(struct sn | |
183 | ret = start_endpoints(subs, 1); | |
184 | ||
185 | unlock: | |
186 | - mutex_unlock(&subs->stream->chip->shutdown_mutex); | |
187 | + up_read(&subs->stream->chip->shutdown_rwsem); | |
188 | return ret; | |
189 | } | |
190 | ||
191 | --- a/sound/usb/usbaudio.h | |
192 | +++ b/sound/usb/usbaudio.h | |
193 | @@ -37,7 +37,7 @@ struct snd_usb_audio { | |
194 | struct usb_interface *pm_intf; | |
195 | u32 usb_id; | |
196 | struct mutex mutex; | |
197 | - struct mutex shutdown_mutex; | |
198 | + struct rw_semaphore shutdown_rwsem; | |
199 | unsigned int shutdown:1; | |
200 | unsigned int probing:1; | |
201 | unsigned int autosuspended:1; |