From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751801AbaI3VE2 (ORCPT ); Tue, 30 Sep 2014 17:04:28 -0400 Received: from forward8l.mail.yandex.net ([84.201.143.141]:47026 "EHLO forward8l.mail.yandex.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750846AbaI3VE0 (ORCPT ); Tue, 30 Sep 2014 17:04:26 -0400 X-Yandex-Uniq: 0419ea50-2e6e-4ee1-8a01-da91abc61dd1 Authentication-Results: smtp12.mail.yandex.net; dkim=pass header.i=@yandex.ru Subject: [PATCH v2 1/3] sched/dl: Implement cancel_dl_timer() to use in switched_from_dl() From: Kirill Tkhai To: linux-kernel@vger.kernel.org Cc: Peter Zijlstra , Kirill Tkhai , Ingo Molnar , Juri Lelli Date: Wed, 01 Oct 2014 01:04:22 +0400 Message-ID: <20140930210412.5258.35299.stgit@localhost> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Kirill Tkhai hrtimer_try_to_cancel() may bring a suprise, its call may fail. raw_spin_lock(&rq->lock) ... dl_task_timer raw_spin_lock(&rq->lock) ... raw_spin_lock(&rq->lock) ... switched_from_dl() ... ... hrtimer_try_to_cancel() ... ... switched_to_fair() ... ... ... ... ... ... ... ... raw_spin_unlock(&rq->lock) ... (asquired) ... ... ... ... ... ... do_exit() ... ... schedule() ... ... raw_spin_lock(&rq->lock) ... raw_spin_unlock(&rq->lock) ... ... ... raw_spin_unlock(&rq->lock) ... raw_spin_lock(&rq->lock) ... ... (asquired) put_task_struct() ... ... free_task_struct() ... ... ... ... raw_spin_unlock(&rq->lock) ... (asquired) ... ... ... ... ... Surprise!!! ... So, let's implement 100% guaranteed way to cancel the timer and let's be sure we are safe even in very unlikely situations. We do not create any problem with rq unlocking, because it already may happed below in pull_dl_task(). No problem with deadline tasks balancing too. Signed-off-by: Kirill Tkhai --- kernel/sched/deadline.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c index abfaf3d..63f8b4a 100644 --- a/kernel/sched/deadline.c +++ b/kernel/sched/deadline.c @@ -555,11 +555,6 @@ void init_dl_task_timer(struct sched_dl_entity *dl_se) { struct hrtimer *timer = &dl_se->dl_timer; - if (hrtimer_active(timer)) { - hrtimer_try_to_cancel(timer); - return; - } - hrtimer_init(timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); timer->function = dl_task_timer; } @@ -1567,10 +1562,34 @@ void init_sched_dl_class(void) #endif /* CONFIG_SMP */ +/* + * Surely cancel task's dl_timer. May drop rq->lock. + */ +static void cancel_dl_timer(struct rq *rq, struct task_struct *p) +{ + struct hrtimer *dl_timer = &p->dl.dl_timer; + + /* Nobody will change task's class if pi_lock is held */ + lockdep_assert_held(&p->pi_lock); + + if (hrtimer_active(dl_timer)) { + int ret = hrtimer_try_to_cancel(dl_timer); + + if (unlikely(ret == -1)) { + /* + * Note, p may migrate OR new deadline tasks + * may appear in rq when we are unlocking it. + */ + raw_spin_unlock(&rq->lock); + hrtimer_cancel(dl_timer); + raw_spin_lock(&rq->lock); + } + } +} + static void switched_from_dl(struct rq *rq, struct task_struct *p) { - if (hrtimer_active(&p->dl.dl_timer) && !dl_policy(p->policy)) - hrtimer_try_to_cancel(&p->dl.dl_timer); + cancel_dl_timer(rq, p); __dl_clear_params(p);