mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
media: dvb: mpq: Fix race-condition in mutex locking
mpq_dmx_decoder_fullness_wait was called either from dvb-demux or internally by the plug-in. In the first case mutex should be locked before checking the video buffer while in the second case it was called while the mutex was already locked. Due to this the function checked whether the mutex is already locked or not. This check it not atomic, if the function is called by dvb-demux while the mutex is un-locked, after this check it is possible to have a context-switch and the mutex gets locked by other API functions of the plug-in, which could lead to dead-lock or invalid states. Change-Id: I32ce4aa3ee7a93c1a8a4fda1d0f916e65eab11ce Signed-off-by: Hamad Kadmany <hkadmany@codeaurora.org>
This commit is contained in:
parent
b08b9f8d16
commit
870e84aea2
1 changed files with 64 additions and 34 deletions
|
@ -1975,7 +1975,15 @@ int mpq_dmx_decoder_fullness_init(struct dvb_demux_feed *feed)
|
|||
}
|
||||
EXPORT_SYMBOL(mpq_dmx_decoder_fullness_init);
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether the free space of decoder's output
|
||||
* buffer is larger than specific number of bytes.
|
||||
*
|
||||
* @sbuff: MPQ stream buffer used for decoder data.
|
||||
* @required_space: number of required free bytes in the buffer
|
||||
*
|
||||
* Return 1 if required free bytes are available, 0 otherwise.
|
||||
*/
|
||||
static inline int mpq_dmx_check_decoder_fullness(
|
||||
struct mpq_streambuffer *sbuff,
|
||||
size_t required_space)
|
||||
|
@ -1995,16 +2003,30 @@ static inline int mpq_dmx_check_decoder_fullness(
|
|||
return (free >= required_space);
|
||||
}
|
||||
|
||||
int mpq_dmx_decoder_fullness_wait(
|
||||
/**
|
||||
* Checks whether decoder's output buffer has free space
|
||||
* for specific number of bytes, if not, the function waits
|
||||
* until the amount of free-space is available.
|
||||
*
|
||||
* @feed: decoder's feed object
|
||||
* @required_space: number of required free bytes in the buffer
|
||||
* @lock_feed: indicates whether mutex should be held before
|
||||
* accessing the feed information. If the caller of this function
|
||||
* already holds a mutex then this should be set to 0 and 1 otherwise.
|
||||
*
|
||||
* Return 0 if required space is available and error code
|
||||
* in case waiting on buffer fullness was aborted.
|
||||
*/
|
||||
static int mpq_dmx_decoder_fullness_check(
|
||||
struct dvb_demux_feed *feed,
|
||||
size_t required_space)
|
||||
size_t required_space,
|
||||
int lock_feed)
|
||||
{
|
||||
struct mpq_demux *mpq_demux = feed->demux->priv;
|
||||
struct mpq_streambuffer *sbuff = NULL;
|
||||
struct mpq_video_feed_info *feed_data;
|
||||
struct mpq_feed *mpq_feed;
|
||||
int ret = 0;
|
||||
int was_locked;
|
||||
|
||||
if (!mpq_dmx_is_video_feed(feed)) {
|
||||
MPQ_DVB_DBG_PRINT("%s: Invalid feed type %d\n",
|
||||
|
@ -2013,11 +2035,13 @@ int mpq_dmx_decoder_fullness_wait(
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (mutex_is_locked(&mpq_demux->mutex)) {
|
||||
was_locked = 1;
|
||||
} else {
|
||||
if (lock_feed) {
|
||||
mutex_lock(&mpq_demux->mutex);
|
||||
was_locked = 0;
|
||||
} else if (!mutex_is_locked(&mpq_demux->mutex)) {
|
||||
MPQ_DVB_ERR_PRINT(
|
||||
"%s: Mutex should have been locked\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mpq_feed = feed->priv;
|
||||
|
@ -2025,7 +2049,7 @@ int mpq_dmx_decoder_fullness_wait(
|
|||
|
||||
sbuff = feed_data->video_buffer;
|
||||
if (sbuff == NULL) {
|
||||
if (!was_locked)
|
||||
if (lock_feed)
|
||||
mutex_unlock(&mpq_demux->mutex);
|
||||
MPQ_DVB_ERR_PRINT("%s: mpq_streambuffer object is NULL\n",
|
||||
__func__);
|
||||
|
@ -2060,22 +2084,29 @@ int mpq_dmx_decoder_fullness_wait(
|
|||
}
|
||||
|
||||
if (ret < 0) {
|
||||
if (!was_locked)
|
||||
if (lock_feed)
|
||||
mutex_unlock(&mpq_demux->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((feed_data->fullness_wait_cancel) ||
|
||||
(feed_data->video_buffer == NULL)) {
|
||||
if (!was_locked)
|
||||
if (lock_feed)
|
||||
mutex_unlock(&mpq_demux->mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!was_locked)
|
||||
if (lock_feed)
|
||||
mutex_unlock(&mpq_demux->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mpq_dmx_decoder_fullness_wait(
|
||||
struct dvb_demux_feed *feed,
|
||||
size_t required_space)
|
||||
{
|
||||
return mpq_dmx_decoder_fullness_check(feed, required_space, 1);
|
||||
}
|
||||
EXPORT_SYMBOL(mpq_dmx_decoder_fullness_wait);
|
||||
|
||||
int mpq_dmx_decoder_fullness_abort(struct dvb_demux_feed *feed)
|
||||
|
@ -3695,6 +3726,13 @@ static int mpq_sdmx_section_filtering(struct mpq_feed *mpq_feed,
|
|||
u8 tmp;
|
||||
int i;
|
||||
|
||||
if (!mutex_is_locked(&mpq_feed->mpq_demux->mutex)) {
|
||||
MPQ_DVB_ERR_PRINT(
|
||||
"%s: Mutex should have been locked\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) {
|
||||
tmp = DVB_RINGBUFFER_PEEK(&mpq_feed->sdmx_buf, i);
|
||||
xor = f->filter.filter_value[i] ^ tmp;
|
||||
|
@ -3709,20 +3747,12 @@ static int mpq_sdmx_section_filtering(struct mpq_feed *mpq_feed,
|
|||
return 0;
|
||||
|
||||
if (feed->demux->playback_mode == DMX_PB_MODE_PULL) {
|
||||
int was_locked;
|
||||
|
||||
if (mutex_is_locked(&mpq_feed->mpq_demux->mutex)) {
|
||||
mutex_unlock(&mpq_feed->mpq_demux->mutex);
|
||||
was_locked = 1;
|
||||
} else {
|
||||
was_locked = 0;
|
||||
}
|
||||
mutex_unlock(&mpq_feed->mpq_demux->mutex);
|
||||
|
||||
ret = feed->demux->buffer_ctrl.sec(&f->filter,
|
||||
header->payload_length);
|
||||
|
||||
if (was_locked)
|
||||
mutex_lock(&mpq_feed->mpq_demux->mutex);
|
||||
mutex_lock(&mpq_feed->mpq_demux->mutex);
|
||||
|
||||
if (ret) {
|
||||
MPQ_DVB_DBG_PRINT(
|
||||
|
@ -3757,7 +3787,13 @@ static int mpq_sdmx_check_ts_stall(struct mpq_demux *mpq_demux,
|
|||
{
|
||||
struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
|
||||
int ret;
|
||||
int was_locked;
|
||||
|
||||
if (!mutex_is_locked(&mpq_feed->mpq_demux->mutex)) {
|
||||
MPQ_DVB_ERR_PRINT(
|
||||
"%s: Mutex should have been locked\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* For PULL mode need to verify there is enough space for the dmxdev
|
||||
|
@ -3769,19 +3805,13 @@ static int mpq_sdmx_check_ts_stall(struct mpq_demux *mpq_demux,
|
|||
MPQ_DVB_DBG_PRINT("%s: Stalling for events and %d bytes\n",
|
||||
__func__, req);
|
||||
|
||||
if (mutex_is_locked(&mpq_demux->mutex)) {
|
||||
mutex_unlock(&mpq_demux->mutex);
|
||||
was_locked = 1;
|
||||
} else {
|
||||
was_locked = 0;
|
||||
}
|
||||
mutex_unlock(&mpq_demux->mutex);
|
||||
|
||||
ret = mpq_demux->demux.buffer_ctrl.ts(&feed->feed.ts, req);
|
||||
MPQ_DVB_DBG_PRINT("%s: stall result = %d\n",
|
||||
__func__, ret);
|
||||
|
||||
if (was_locked)
|
||||
mutex_lock(&mpq_demux->mutex);
|
||||
mutex_lock(&mpq_demux->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -3971,12 +4001,12 @@ static void mpq_sdmx_decoder_filter_results(struct mpq_demux *mpq_demux,
|
|||
(sts->error_indicators & SDMX_FILTER_ERR_D_LIN_BUFS_FULL)) {
|
||||
MPQ_DVB_DBG_PRINT("%s: Decoder stall...\n", __func__);
|
||||
|
||||
ret = mpq_dmx_decoder_fullness_wait(
|
||||
mpq_feed->dvb_demux_feed, 0);
|
||||
ret = mpq_dmx_decoder_fullness_check(
|
||||
mpq_feed->dvb_demux_feed, 0, 0);
|
||||
if (ret) {
|
||||
/* we reach here if demuxing was aborted */
|
||||
MPQ_DVB_DBG_PRINT(
|
||||
"%s: mpq_dmx_decoder_fullness_wait aborted\n",
|
||||
"%s: mpq_dmx_decoder_fullness_check aborted\n",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue