From 2384c119d04b54e6e6c282a8693246c4e7d1347e Mon Sep 17 00:00:00 2001 From: "bk0121.shin" Date: Wed, 14 Jan 2015 20:35:57 +0900 Subject: [PATCH] [media] dvb-core: Fix frontend thread serialization dvb_frontend_thread's life cycle is controlled by dvb_frontend_start and dvb_frontend_release. But, if user opens frontend device before the thread exits completely, dvb_frontend_start doesn't create a new thread. When exit condition of thread that is jiffies is triggered by dvb_frontend_release, dvb_frontend_thread wakes up and checks exit condition without semaphore acquiring. In this case, if user context checks existence of thread(fepriv->thread), it is true, and exit flage has DVB_FE_NO_EXIT. Therefore, dvb_frontend_start doesn't make a new thread, previous old thread is going to terminate. To fix this problem, semaphore should preserve thread exit condition and checking it, which are dvb_frontend_is_exiting and fe->exit. Signed-off-by: bk0121.shin --- drivers/media/dvb-core/dvb_frontend.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 2cf3057..a8e8d44 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -620,14 +620,17 @@ restart: || freezing(current), fepriv->delay); + if (down_interruptible(&fepriv->sem)) + break; + if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) { /* got signal or quitting */ - if (!down_interruptible(&fepriv->sem)) - semheld = true; + semheld = true; fe->exit = DVB_FE_NORMAL_EXIT; break; } + up(&fepriv->sem); if (try_to_freeze()) goto restart; @@ -821,17 +824,22 @@ static int dvb_frontend_start(struct dvb_frontend *fe) dev_dbg(fe->dvb->device, "%s:\n", __func__); + if (down_interruptible(&fepriv->sem)) + return -EINTR; + if (fepriv->thread) { - if (fe->exit == DVB_FE_NO_EXIT) + if (fe->exit == DVB_FE_NO_EXIT) { + up(&fepriv->sem); return 0; - else + } else { dvb_frontend_stop (fe); + } } - if (signal_pending(current)) - return -EINTR; - if (down_interruptible (&fepriv->sem)) + if (signal_pending(current)) { + up(&fepriv->sem); return -EINTR; + } fepriv->state = FESTATE_IDLE; fe->exit = DVB_FE_NO_EXIT; -- 1.9.1