aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>2015-02-21 09:54:57 -0500
committerTakashi Iwai <tiwai@suse.de>2015-02-23 03:10:38 -0500
commit12ed719291a953d443921f9cdb0ffee41066c340 (patch)
tree92362d30da81381fd8fe004fc3ba553ceea754ea /sound
parent6426460e5d87810e042962281fe3c1e8fc256162 (diff)
ALSA: fireworks/bebob/dice/oxfw: add reference-counting for FireWire unit
Fireworks and Dice drivers try to touch instances of FireWire unit after sound card object is released, while references to the unit is decremented in .remove(). When unplugging during streaming, sound card object is released after .remove(), thus Fireworks and Dice drivers causes GPF or Null-pointer-dereferencing to application processes because an instance of FireWire unit was already released. This commit adds reference-counting for FireWire unit in drivers to allow them to touch an instance of FireWire unit after .remove(). In most case, any operations after .remove() may be failed safely. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Cc: <stable@vger.kernel.org> # 3.19+ Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r--sound/firewire/bebob/bebob.c12
-rw-r--r--sound/firewire/dice/dice.c11
-rw-r--r--sound/firewire/fireworks/fireworks.c12
-rw-r--r--sound/firewire/oxfw/oxfw.c11
4 files changed, 42 insertions, 4 deletions
diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c
index fc19c99654aa..b612599fb543 100644
--- a/sound/firewire/bebob/bebob.c
+++ b/sound/firewire/bebob/bebob.c
@@ -116,11 +116,19 @@ end:
116 return err; 116 return err;
117} 117}
118 118
119/*
120 * This module releases the FireWire unit data after all ALSA character devices
121 * are released by applications. This is for releasing stream data or finishing
122 * transactions safely. Thus at returning from .remove(), this module still keep
123 * references for the unit.
124 */
119static void 125static void
120bebob_card_free(struct snd_card *card) 126bebob_card_free(struct snd_card *card)
121{ 127{
122 struct snd_bebob *bebob = card->private_data; 128 struct snd_bebob *bebob = card->private_data;
123 129
130 fw_unit_put(bebob->unit);
131
124 if (bebob->card_index >= 0) { 132 if (bebob->card_index >= 0) {
125 mutex_lock(&devices_mutex); 133 mutex_lock(&devices_mutex);
126 clear_bit(bebob->card_index, devices_used); 134 clear_bit(bebob->card_index, devices_used);
@@ -205,7 +213,7 @@ bebob_probe(struct fw_unit *unit,
205 card->private_free = bebob_card_free; 213 card->private_free = bebob_card_free;
206 214
207 bebob->card = card; 215 bebob->card = card;
208 bebob->unit = unit; 216 bebob->unit = fw_unit_get(unit);
209 bebob->spec = spec; 217 bebob->spec = spec;
210 mutex_init(&bebob->mutex); 218 mutex_init(&bebob->mutex);
211 spin_lock_init(&bebob->lock); 219 spin_lock_init(&bebob->lock);
@@ -310,6 +318,8 @@ static void bebob_remove(struct fw_unit *unit)
310 318
311 snd_bebob_stream_destroy_duplex(bebob); 319 snd_bebob_stream_destroy_duplex(bebob);
312 snd_card_disconnect(bebob->card); 320 snd_card_disconnect(bebob->card);
321
322 /* No need to wait for releasing card object in this context. */
313 snd_card_free_when_closed(bebob->card); 323 snd_card_free_when_closed(bebob->card);
314} 324}
315 325
diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c
index 90d8f40ff727..797f0726fc74 100644
--- a/sound/firewire/dice/dice.c
+++ b/sound/firewire/dice/dice.c
@@ -226,11 +226,19 @@ static void dice_card_strings(struct snd_dice *dice)
226 strcpy(card->mixername, "DICE"); 226 strcpy(card->mixername, "DICE");
227} 227}
228 228
229/*
230 * This module releases the FireWire unit data after all ALSA character devices
231 * are released by applications. This is for releasing stream data or finishing
232 * transactions safely. Thus at returning from .remove(), this module still keep
233 * references for the unit.
234 */
229static void dice_card_free(struct snd_card *card) 235static void dice_card_free(struct snd_card *card)
230{ 236{
231 struct snd_dice *dice = card->private_data; 237 struct snd_dice *dice = card->private_data;
232 238
233 snd_dice_transaction_destroy(dice); 239 snd_dice_transaction_destroy(dice);
240 fw_unit_put(dice->unit);
241
234 mutex_destroy(&dice->mutex); 242 mutex_destroy(&dice->mutex);
235} 243}
236 244
@@ -251,7 +259,7 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
251 259
252 dice = card->private_data; 260 dice = card->private_data;
253 dice->card = card; 261 dice->card = card;
254 dice->unit = unit; 262 dice->unit = fw_unit_get(unit);
255 card->private_free = dice_card_free; 263 card->private_free = dice_card_free;
256 264
257 spin_lock_init(&dice->lock); 265 spin_lock_init(&dice->lock);
@@ -309,6 +317,7 @@ static void dice_remove(struct fw_unit *unit)
309 317
310 snd_dice_stream_destroy_duplex(dice); 318 snd_dice_stream_destroy_duplex(dice);
311 319
320 /* No need to wait for releasing card object in this context. */
312 snd_card_free_when_closed(dice->card); 321 snd_card_free_when_closed(dice->card);
313} 322}
314 323
diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c
index 3e2ed8e82cbc..1e33394d8a93 100644
--- a/sound/firewire/fireworks/fireworks.c
+++ b/sound/firewire/fireworks/fireworks.c
@@ -173,11 +173,19 @@ end:
173 return err; 173 return err;
174} 174}
175 175
176/*
177 * This module releases the FireWire unit data after all ALSA character devices
178 * are released by applications. This is for releasing stream data or finishing
179 * transactions safely. Thus at returning from .remove(), this module still keep
180 * references for the unit.
181 */
176static void 182static void
177efw_card_free(struct snd_card *card) 183efw_card_free(struct snd_card *card)
178{ 184{
179 struct snd_efw *efw = card->private_data; 185 struct snd_efw *efw = card->private_data;
180 186
187 fw_unit_put(efw->unit);
188
181 if (efw->card_index >= 0) { 189 if (efw->card_index >= 0) {
182 mutex_lock(&devices_mutex); 190 mutex_lock(&devices_mutex);
183 clear_bit(efw->card_index, devices_used); 191 clear_bit(efw->card_index, devices_used);
@@ -218,7 +226,7 @@ efw_probe(struct fw_unit *unit,
218 card->private_free = efw_card_free; 226 card->private_free = efw_card_free;
219 227
220 efw->card = card; 228 efw->card = card;
221 efw->unit = unit; 229 efw->unit = fw_unit_get(unit);
222 mutex_init(&efw->mutex); 230 mutex_init(&efw->mutex);
223 spin_lock_init(&efw->lock); 231 spin_lock_init(&efw->lock);
224 init_waitqueue_head(&efw->hwdep_wait); 232 init_waitqueue_head(&efw->hwdep_wait);
@@ -293,6 +301,8 @@ static void efw_remove(struct fw_unit *unit)
293 snd_efw_transaction_remove_instance(efw); 301 snd_efw_transaction_remove_instance(efw);
294 302
295 snd_card_disconnect(efw->card); 303 snd_card_disconnect(efw->card);
304
305 /* No need to wait for releasing card object in this context. */
296 snd_card_free_when_closed(efw->card); 306 snd_card_free_when_closed(efw->card);
297} 307}
298 308
diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c
index 60e5cad0531a..1607b26404c3 100644
--- a/sound/firewire/oxfw/oxfw.c
+++ b/sound/firewire/oxfw/oxfw.c
@@ -104,11 +104,19 @@ end:
104 return err; 104 return err;
105} 105}
106 106
107/*
108 * This module releases the FireWire unit data after all ALSA character devices
109 * are released by applications. This is for releasing stream data or finishing
110 * transactions safely. Thus at returning from .remove(), this module still keep
111 * references for the unit.
112 */
107static void oxfw_card_free(struct snd_card *card) 113static void oxfw_card_free(struct snd_card *card)
108{ 114{
109 struct snd_oxfw *oxfw = card->private_data; 115 struct snd_oxfw *oxfw = card->private_data;
110 unsigned int i; 116 unsigned int i;
111 117
118 fw_unit_put(oxfw->unit);
119
112 for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) { 120 for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
113 kfree(oxfw->tx_stream_formats[i]); 121 kfree(oxfw->tx_stream_formats[i]);
114 kfree(oxfw->rx_stream_formats[i]); 122 kfree(oxfw->rx_stream_formats[i]);
@@ -136,7 +144,7 @@ static int oxfw_probe(struct fw_unit *unit,
136 oxfw = card->private_data; 144 oxfw = card->private_data;
137 oxfw->card = card; 145 oxfw->card = card;
138 mutex_init(&oxfw->mutex); 146 mutex_init(&oxfw->mutex);
139 oxfw->unit = unit; 147 oxfw->unit = fw_unit_get(unit);
140 oxfw->device_info = (const struct device_info *)id->driver_data; 148 oxfw->device_info = (const struct device_info *)id->driver_data;
141 spin_lock_init(&oxfw->lock); 149 spin_lock_init(&oxfw->lock);
142 init_waitqueue_head(&oxfw->hwdep_wait); 150 init_waitqueue_head(&oxfw->hwdep_wait);
@@ -218,6 +226,7 @@ static void oxfw_remove(struct fw_unit *unit)
218 if (oxfw->has_output) 226 if (oxfw->has_output)
219 snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream); 227 snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream);
220 228
229 /* No need to wait for releasing card object in this context. */
221 snd_card_free_when_closed(oxfw->card); 230 snd_card_free_when_closed(oxfw->card);
222} 231}
223 232