usb: gadget: Fix synchronization issue between f_audio_source

Race is happening when both audio_pcm_close() and audio_send()
executes in parallel.
When the PCM session is closed, the substream attribute of the
audio_dev structure is set to NULL in audio_pcm_close().
As there is no synchronization protection for the audio_dev subtream
attributes in audio_send(), it is causing NULL pointer dereference.
Hence fixing the issue by adding proper synchronization protection
for the audio_dev subtream attributes in audio_send().

CRs-Fixed: 613498
Change-Id: Id9ab0d4e347b8bb2f551f9033829e541bdcaf0e8
Signed-off-by: ChandanaKishori Chiluveru <cchilu@codeaurora.org>
Signed-off-by: Tarun Gupta <tarung@codeaurora.org>
This commit is contained in:
ChandanaKishori Chiluveru 2014-03-11 17:09:50 +05:30 committed by Gerrit - the friendly Code Review server
parent c5685ec0f3
commit a510e932e4

View file

@ -369,15 +369,22 @@ static void audio_send(struct audio_dev *audio)
s64 msecs; s64 msecs;
s64 frames; s64 frames;
ktime_t now; ktime_t now;
unsigned long flags;
spin_lock_irqsave(&audio->lock, flags);
/* audio->substream will be null if we have been closed */ /* audio->substream will be null if we have been closed */
if (!audio->substream) if (!audio->substream) {
spin_unlock_irqrestore(&audio->lock, flags);
return; return;
}
/* audio->buffer_pos will be null if we have been stopped */ /* audio->buffer_pos will be null if we have been stopped */
if (!audio->buffer_pos) if (!audio->buffer_pos) {
spin_unlock_irqrestore(&audio->lock, flags);
return; return;
}
runtime = audio->substream->runtime; runtime = audio->substream->runtime;
spin_unlock_irqrestore(&audio->lock, flags);
/* compute number of frames to send */ /* compute number of frames to send */
now = ktime_get(); now = ktime_get();
@ -400,8 +407,21 @@ static void audio_send(struct audio_dev *audio)
while (frames > 0) { while (frames > 0) {
req = audio_req_get(audio); req = audio_req_get(audio);
if (!req) spin_lock_irqsave(&audio->lock, flags);
/* audio->substream will be null if we have been closed */
if (!audio->substream) {
spin_unlock_irqrestore(&audio->lock, flags);
return;
}
/* audio->buffer_pos will be null if we have been stopped */
if (!audio->buffer_pos) {
spin_unlock_irqrestore(&audio->lock, flags);
return;
}
if (!req) {
spin_unlock_irqrestore(&audio->lock, flags);
break; break;
}
length = frames_to_bytes(runtime, frames); length = frames_to_bytes(runtime, frames);
if (length > IN_EP_MAX_PACKET_SIZE) if (length > IN_EP_MAX_PACKET_SIZE)
@ -427,6 +447,7 @@ static void audio_send(struct audio_dev *audio)
} }
req->length = length; req->length = length;
spin_unlock_irqrestore(&audio->lock, flags);
ret = usb_ep_queue(audio->in_ep, req, GFP_ATOMIC); ret = usb_ep_queue(audio->in_ep, req, GFP_ATOMIC);
if (ret < 0) { if (ret < 0) {
pr_err("usb_ep_queue failed ret: %d\n", ret); pr_err("usb_ep_queue failed ret: %d\n", ret);