From a510e932e4f77fa5f5d01c4223c3d2fb2f3a88c7 Mon Sep 17 00:00:00 2001 From: ChandanaKishori Chiluveru Date: Tue, 11 Mar 2014 17:09:50 +0530 Subject: [PATCH] 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 Signed-off-by: Tarun Gupta --- drivers/usb/gadget/function/f_audio_source.c | 27 +++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/function/f_audio_source.c b/drivers/usb/gadget/function/f_audio_source.c index 51ab794ef6f9..ab7441fcf66f 100644 --- a/drivers/usb/gadget/function/f_audio_source.c +++ b/drivers/usb/gadget/function/f_audio_source.c @@ -369,15 +369,22 @@ static void audio_send(struct audio_dev *audio) s64 msecs; s64 frames; ktime_t now; + unsigned long flags; + spin_lock_irqsave(&audio->lock, flags); /* audio->substream will be null if we have been closed */ - if (!audio->substream) + 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) + if (!audio->buffer_pos) { + spin_unlock_irqrestore(&audio->lock, flags); return; + } runtime = audio->substream->runtime; + spin_unlock_irqrestore(&audio->lock, flags); /* compute number of frames to send */ now = ktime_get(); @@ -400,8 +407,21 @@ static void audio_send(struct audio_dev *audio) while (frames > 0) { 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; + } length = frames_to_bytes(runtime, frames); if (length > IN_EP_MAX_PACKET_SIZE) @@ -427,6 +447,7 @@ static void audio_send(struct audio_dev *audio) } req->length = length; + spin_unlock_irqrestore(&audio->lock, flags); ret = usb_ep_queue(audio->in_ep, req, GFP_ATOMIC); if (ret < 0) { pr_err("usb_ep_queue failed ret: %d\n", ret);