Commit d23c2cc4 authored by Takashi Sakamoto's avatar Takashi Sakamoto Committed by Takashi Iwai

ALSA: fireworks/bebob/dice/oxfw: allow stream destructor after releasing runtime

Currently stream destructor in each driver has a problem to be called in
a context in which sound card object is released, because the destructors
call amdtp_stream_pcm_abort() and touch PCM runtime data.

The PCM runtime data is destroyed in application's context with
snd_pcm_close(), on the other hand PCM substream data is destroyed after
sound card object is released, in most case after all of ALSA character
devices are released. When PCM runtime is destroyed and PCM substream is
remained, amdtp_stream_pcm_abort() touches PCM runtime data and causes
Null-pointer-dereference.

This commit changes stream destructors and allows each driver to call
it after releasing runtime.
Signed-off-by: default avatarTakashi Sakamoto <o-takashi@sakamocchi.jp>
Cc: <stable@vger.kernel.org> # 3.19+
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent c6f224dc
...@@ -410,8 +410,6 @@ break_both_connections(struct snd_bebob *bebob) ...@@ -410,8 +410,6 @@ break_both_connections(struct snd_bebob *bebob)
static void static void
destroy_both_connections(struct snd_bebob *bebob) destroy_both_connections(struct snd_bebob *bebob)
{ {
break_both_connections(bebob);
cmp_connection_destroy(&bebob->in_conn); cmp_connection_destroy(&bebob->in_conn);
cmp_connection_destroy(&bebob->out_conn); cmp_connection_destroy(&bebob->out_conn);
} }
...@@ -712,16 +710,14 @@ void snd_bebob_stream_update_duplex(struct snd_bebob *bebob) ...@@ -712,16 +710,14 @@ void snd_bebob_stream_update_duplex(struct snd_bebob *bebob)
mutex_unlock(&bebob->mutex); mutex_unlock(&bebob->mutex);
} }
/*
* This function should be called before starting streams or after stopping
* streams.
*/
void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob) void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob)
{ {
mutex_lock(&bebob->mutex); mutex_lock(&bebob->mutex);
amdtp_stream_pcm_abort(&bebob->rx_stream);
amdtp_stream_pcm_abort(&bebob->tx_stream);
amdtp_stream_stop(&bebob->rx_stream);
amdtp_stream_stop(&bebob->tx_stream);
amdtp_stream_destroy(&bebob->rx_stream); amdtp_stream_destroy(&bebob->rx_stream);
amdtp_stream_destroy(&bebob->tx_stream); amdtp_stream_destroy(&bebob->tx_stream);
......
...@@ -311,14 +311,21 @@ static int init_stream(struct snd_dice *dice, struct amdtp_stream *stream) ...@@ -311,14 +311,21 @@ static int init_stream(struct snd_dice *dice, struct amdtp_stream *stream)
return err; return err;
} }
/*
* This function should be called before starting streams or after stopping
* streams.
*/
static void destroy_stream(struct snd_dice *dice, struct amdtp_stream *stream) static void destroy_stream(struct snd_dice *dice, struct amdtp_stream *stream)
{ {
amdtp_stream_destroy(stream); struct fw_iso_resources *resources;
if (stream == &dice->tx_stream) if (stream == &dice->tx_stream)
fw_iso_resources_destroy(&dice->tx_resources); resources = &dice->tx_resources;
else else
fw_iso_resources_destroy(&dice->rx_resources); resources = &dice->rx_resources;
amdtp_stream_destroy(stream);
fw_iso_resources_destroy(resources);
} }
int snd_dice_stream_init_duplex(struct snd_dice *dice) int snd_dice_stream_init_duplex(struct snd_dice *dice)
...@@ -332,6 +339,8 @@ int snd_dice_stream_init_duplex(struct snd_dice *dice) ...@@ -332,6 +339,8 @@ int snd_dice_stream_init_duplex(struct snd_dice *dice)
goto end; goto end;
err = init_stream(dice, &dice->rx_stream); err = init_stream(dice, &dice->rx_stream);
if (err < 0)
destroy_stream(dice, &dice->tx_stream);
end: end:
return err; return err;
} }
...@@ -340,10 +349,7 @@ void snd_dice_stream_destroy_duplex(struct snd_dice *dice) ...@@ -340,10 +349,7 @@ void snd_dice_stream_destroy_duplex(struct snd_dice *dice)
{ {
snd_dice_transaction_clear_enable(dice); snd_dice_transaction_clear_enable(dice);
stop_stream(dice, &dice->tx_stream);
destroy_stream(dice, &dice->tx_stream); destroy_stream(dice, &dice->tx_stream);
stop_stream(dice, &dice->rx_stream);
destroy_stream(dice, &dice->rx_stream); destroy_stream(dice, &dice->rx_stream);
dice->substreams_counter = 0; dice->substreams_counter = 0;
......
...@@ -100,17 +100,22 @@ start_stream(struct snd_efw *efw, struct amdtp_stream *stream, ...@@ -100,17 +100,22 @@ start_stream(struct snd_efw *efw, struct amdtp_stream *stream,
return err; return err;
} }
/*
* This function should be called before starting the stream or after stopping
* the streams.
*/
static void static void
destroy_stream(struct snd_efw *efw, struct amdtp_stream *stream) destroy_stream(struct snd_efw *efw, struct amdtp_stream *stream)
{ {
stop_stream(efw, stream); struct cmp_connection *conn;
amdtp_stream_destroy(stream);
if (stream == &efw->tx_stream) if (stream == &efw->tx_stream)
cmp_connection_destroy(&efw->out_conn); conn = &efw->out_conn;
else else
cmp_connection_destroy(&efw->in_conn); conn = &efw->in_conn;
amdtp_stream_destroy(stream);
cmp_connection_destroy(&efw->out_conn);
} }
static int static int
......
...@@ -337,6 +337,10 @@ void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw, ...@@ -337,6 +337,10 @@ void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw,
stop_stream(oxfw, stream); stop_stream(oxfw, stream);
} }
/*
* This function should be called before starting the stream or after stopping
* the streams.
*/
void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw, void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw,
struct amdtp_stream *stream) struct amdtp_stream *stream)
{ {
...@@ -347,8 +351,6 @@ void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw, ...@@ -347,8 +351,6 @@ void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw,
else else
conn = &oxfw->in_conn; conn = &oxfw->in_conn;
stop_stream(oxfw, stream);
amdtp_stream_destroy(stream); amdtp_stream_destroy(stream);
cmp_connection_destroy(conn); cmp_connection_destroy(conn);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment