]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
hid: jarvis: Fix rare case deadlock
authorXia Yang <xiay@nvidia.com>
Wed, 28 Jan 2015 02:17:20 +0000 (18:17 -0800)
committerXia Yang <xiay@nvidia.com>
Thu, 19 Mar 2015 22:47:12 +0000 (15:47 -0700)
snd_pcm_resume() turns out to hold the same lock
as snd_pcm_suspend() and causes the same deadlock
fixed previously, only in less chance.  There is no
easy way around this deadlock in kernel thus we do
a best effort prevent.  In the rare case it still
happens, we avoid abort the operation and let userspace
try again.

Bug 1599000

Change-Id: I09ca660a8d785dff76a3cf44e5b67c9ce5b147a9
Signed-off-by: Xia Yang <xiay@nvidia.com>
Reviewed-on: http://git-master/r/678118
(cherry picked from commit 6c7e1a772234df7ed757859f1f5840885de26625)
Reviewed-on: http://git-master/r/716503
GVS: Gerrit_Virtual_Submit
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
drivers/hid/hid-atv-jarvis.c

index a3f1b6f99fbfc68dbe9fa023ed920dd6023f5016..5d998a3bc70a6089ee040e4a64374fd8975de205 100644 (file)
@@ -885,10 +885,8 @@ static void snd_atvr_timer_start(struct snd_pcm_substream *substream)
 {
        struct snd_atvr *atvr_snd = snd_pcm_substream_chip(substream);
 
-       /*
-        * Wait previous timer callback to finish to ensure clean state.
-        */
-       del_timer_sync(&atvr_snd->decoding_timer);
+       if (try_to_del_timer_sync(&atvr_snd->decoding_timer) < 0)
+               return -EAGAIN;
 
        atvr_snd->timer_enabled = true;
        atvr_snd->previous_jiffies = jiffies;
@@ -922,8 +920,10 @@ static void snd_atvr_timer_stop(struct snd_pcm_substream *substream)
                 * We could temporarily give up the lock and relock later.
                 * However, that could break the original purpose of the lock.
                 * Thus we just try delete the timer but do not block.
-                * Instead, we ensure previous timer is finished in
-                * snd_atvr_timer_start() where the lock concerned is not held.
+                * Instead, we check if previous timer is finished in
+                * snd_atvr_timer_start() where timing has less stress.
+                * In the rare case it is still not finished, we return EAGAIN
+                * and let userspace try again later.
                 */
                ret = try_to_del_timer_sync(&atvr_snd->decoding_timer);
                if (ret < 0)