diff options
| author | ChandanaKishori Chiluveru <cchilu@codeaurora.org> | 2014-03-11 17:09:50 +0530 |
|---|---|---|
| committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2017-05-26 03:29:37 -0700 |
| commit | a510e932e4f77fa5f5d01c4223c3d2fb2f3a88c7 (patch) | |
| tree | 183af8a4189d8bf03eb1c404889e2825b26aafd6 | |
| parent | c5685ec0f3941352bad2535c8612058563ff064a (diff) | |
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>
| -rw-r--r-- | drivers/usb/gadget/function/f_audio_source.c | 27 |
1 files 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); |
