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:
parent
c5685ec0f3
commit
a510e932e4
1 changed files with 24 additions and 3 deletions
|
@ -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);
|
||||||
|
|
Loading…
Add table
Reference in a new issue