All of lore.kernel.org
 help / color / mirror / Atom feed
From: Michel Lespinasse <walken@google.com>
To: Ingo Molnar <mingo@elte.hu>,
	Peter Zijlstra <peterz@infradead.org>,
	Thomas Gleixner <tglx@linutronix.de>
Cc: LKML <linux-kernel@vger.kernel.org>, Robert Love <rml@tech9.net>,
	Andrew Morton <akpm@linux-foundation.org>,
	Andreas Herrmann <andreas.herrmann3@amd.com>
Subject: Stronger CONFIG_DEBUG_SPINLOCK_SLEEP without CONFIG_PREEMPT
Date: Mon, 24 May 2010 16:51:12 -0700	[thread overview]
Message-ID: <20100524235112.GA30453@google.com> (raw)

CONFIG_DEBUG_SPINLOCK_SLEEP without CONFIG_PREEMPT
    
When CONFIG_DEBUG_SPINLOCK_SLEEP is enabled, I think it would make sense
to have preempt_disable() increment the preempt count in order to be able
to display debug messages if someone attempts to sleep from within a
critical region.

This change defines PREEMPT_LOCK_OFFSET to be the value by which
preempt_disable() increment the preempt count - 1 if CONFIG_PREEMPT and/or
CONFIG_DEBUG_SPINLOCK_SLEEP are set, and 0 otherwise.

If CONFIG_PREEMPT is not set, preempt_disable() should add
PREEMPT_LOCK_OFFSET to the preempt count but it is allowed to skip
the optimization barriers since we are not, in the non-preempt case,
worried about the preempt count value being tested from within
interrupt handlers.

Signed-off-by: Michel Lespinasse <walken@google.com>

diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h
index d5b3876..4902dd8 100644
--- a/include/linux/hardirq.h
+++ b/include/linux/hardirq.h
@@ -2,7 +2,7 @@
 #define LINUX_HARDIRQ_H
 
 #include <linux/preempt.h>
-#ifdef CONFIG_PREEMPT
+#if PREEMPT_LOCK_OFFSET
 #include <linux/smp_lock.h>
 #endif
 #include <linux/lockdep.h>
@@ -92,12 +92,10 @@
  */
 #define in_nmi()	(preempt_count() & NMI_MASK)
 
-#if defined(CONFIG_PREEMPT)
+#if PREEMPT_LOCK_OFFSET
 # define PREEMPT_INATOMIC_BASE kernel_locked()
-# define PREEMPT_CHECK_OFFSET 1
 #else
 # define PREEMPT_INATOMIC_BASE 0
-# define PREEMPT_CHECK_OFFSET 0
 #endif
 
 /*
@@ -114,16 +112,16 @@
  * (used by the scheduler, *after* releasing the kernel lock)
  */
 #define in_atomic_preempt_off() \
-		((preempt_count() & ~PREEMPT_ACTIVE) != PREEMPT_CHECK_OFFSET)
+		((preempt_count() & ~PREEMPT_ACTIVE) != PREEMPT_LOCK_OFFSET)
 
 #ifdef CONFIG_PREEMPT
 # define preemptible()	(preempt_count() == 0 && !irqs_disabled())
-# define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
 #else
 # define preemptible()	0
-# define IRQ_EXIT_OFFSET HARDIRQ_OFFSET
 #endif
 
+#define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET - PREEMPT_LOCK_OFFSET)
+
 #if defined(CONFIG_SMP) || defined(CONFIG_GENERIC_HARDIRQS)
 extern void synchronize_irq(unsigned int irq);
 #else
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 3c62ed4..07e9a51 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -133,9 +133,7 @@ static inline int page_cache_get_speculative(struct page *page)
 	VM_BUG_ON(in_interrupt());
 
 #if !defined(CONFIG_SMP) && defined(CONFIG_TREE_RCU)
-# ifdef CONFIG_PREEMPT
-	VM_BUG_ON(!in_atomic());
-# endif
+	VM_BUG_ON(PREEMPT_LOCK_OFFSET && !in_atomic());
 	/*
 	 * Preempt must be disabled here - we rely on rcu_read_lock doing
 	 * this for us.
@@ -171,9 +169,7 @@ static inline int page_cache_add_speculative(struct page *page, int count)
 	VM_BUG_ON(in_interrupt());
 
 #if !defined(CONFIG_SMP) && defined(CONFIG_TREE_RCU)
-# ifdef CONFIG_PREEMPT
-	VM_BUG_ON(!in_atomic());
-# endif
+	VM_BUG_ON(PREEMPT_LOCK_OFFSET && !in_atomic());
 	VM_BUG_ON(page_count(page) == 0);
 	atomic_add(count, &page->_count);
 
diff --git a/include/linux/preempt.h b/include/linux/preempt.h
index 0f82cb0..1cbfda1 100644
--- a/include/linux/preempt.h
+++ b/include/linux/preempt.h
@@ -18,6 +18,12 @@
 # define sub_preempt_count(val)	do { preempt_count() -= (val); } while (0)
 #endif
 
+#if defined(CONFIG_PREEMPT) || defined(CONFIG_DEBUG_SPINLOCK_SLEEP)
+# define PREEMPT_LOCK_OFFSET 1
+#else
+# define PREEMPT_LOCK_OFFSET 0
+#endif
+
 #define inc_preempt_count() add_preempt_count(1)
 #define dec_preempt_count() sub_preempt_count(1)
 
@@ -27,72 +33,65 @@
 
 asmlinkage void preempt_schedule(void);
 
+#define preempt_check_resched() \
+do { \
+	if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \
+		preempt_schedule(); \
+} while (0)
+
+#define preempt_barrier() \
+do { \
+	barrier(); \
+} while (0)
+
+#else
+
+#define preempt_check_resched()		do { } while (0)
+#define preempt_barrier()		do { } while (0)
+
+#endif
+
 #define preempt_disable() \
 do { \
-	inc_preempt_count(); \
-	barrier(); \
+	add_preempt_count(PREEMPT_LOCK_OFFSET); \
+	preempt_barrier(); \
 } while (0)
 
 #define preempt_enable_no_resched() \
 do { \
-	barrier(); \
-	dec_preempt_count(); \
-} while (0)
-
-#define preempt_check_resched() \
-do { \
-	if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \
-		preempt_schedule(); \
+	preempt_barrier(); \
+	sub_preempt_count(PREEMPT_LOCK_OFFSET); \
 } while (0)
 
 #define preempt_enable() \
 do { \
 	preempt_enable_no_resched(); \
-	barrier(); \
+	preempt_barrier(); \
 	preempt_check_resched(); \
 } while (0)
 
 /* For debugging and tracer internals only! */
-#define add_preempt_count_notrace(val)			\
-	do { preempt_count() += (val); } while (0)
-#define sub_preempt_count_notrace(val)			\
-	do { preempt_count() -= (val); } while (0)
-#define inc_preempt_count_notrace() add_preempt_count_notrace(1)
-#define dec_preempt_count_notrace() sub_preempt_count_notrace(1)
 
 #define preempt_disable_notrace() \
 do { \
-	inc_preempt_count_notrace(); \
-	barrier(); \
+	preempt_count() += PREEMPT_LOCK_OFFSET; \
+	preempt_barrier(); \
 } while (0)
 
 #define preempt_enable_no_resched_notrace() \
 do { \
-	barrier(); \
-	dec_preempt_count_notrace(); \
+	preempt_barrier(); \
+	preempt_count() -= PREEMPT_LOCK_OFFSET; \
 } while (0)
 
 /* preempt_check_resched is OK to trace */
 #define preempt_enable_notrace() \
 do { \
 	preempt_enable_no_resched_notrace(); \
-	barrier(); \
+	preempt_barrier(); \
 	preempt_check_resched(); \
 } while (0)
 
-#else
-
-#define preempt_disable()		do { } while (0)
-#define preempt_enable_no_resched()	do { } while (0)
-#define preempt_enable()		do { } while (0)
-#define preempt_check_resched()		do { } while (0)
-
-#define preempt_disable_notrace()		do { } while (0)
-#define preempt_enable_no_resched_notrace()	do { } while (0)
-#define preempt_enable_notrace()		do { } while (0)
-
-#endif
-
 #ifdef CONFIG_PREEMPT_NOTIFIERS
 
 struct preempt_notifier;
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 2b7b81d..df119c1 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -2354,12 +2354,6 @@ extern int _cond_resched(void);
 
 extern int __cond_resched_lock(spinlock_t *lock);
 
-#ifdef CONFIG_PREEMPT
-#define PREEMPT_LOCK_OFFSET	PREEMPT_OFFSET
-#else
-#define PREEMPT_LOCK_OFFSET	0
-#endif
-
 #define cond_resched_lock(lock) ({				\
 	__might_sleep(__FILE__, __LINE__, PREEMPT_LOCK_OFFSET);	\
 	__cond_resched_lock(lock);				\
diff --git a/kernel/sched.c b/kernel/sched.c
index 3c2a54f..61dd981 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -2641,9 +2641,9 @@ void sched_fork(struct task_struct *p, int clone_flags)
 #if defined(CONFIG_SMP) && defined(__ARCH_WANT_UNLOCKED_CTXSW)
 	p->oncpu = 0;
 #endif
-#ifdef CONFIG_PREEMPT
+#if PREEMPT_LOCK_OFFSET
 	/* Want to start with kernel preemption disabled. */
-	task_thread_info(p)->preempt_count = 1;
+	task_thread_info(p)->preempt_count = PREEMPT_LOCK_OFFSET;
 #endif
 	plist_node_init(&p->pushable_tasks, MAX_PRIO);
 
@@ -5266,11 +5266,8 @@ void __cpuinit init_idle(struct task_struct *idle, int cpu)
 	raw_spin_unlock_irqrestore(&rq->lock, flags);
 
 	/* Set the preempt count _outside_ the spinlocks! */
-#if defined(CONFIG_PREEMPT)
-	task_thread_info(idle)->preempt_count = (idle->lock_depth >= 0);
-#else
-	task_thread_info(idle)->preempt_count = 0;
-#endif
+	task_thread_info(idle)->preempt_count =
+		(idle->lock_depth >= 0) ? PREEMPT_LOCK_OFFSET : 0;
 	/*
 	 * The idle tasks have their own, simple scheduling class:
 	 */
diff --git a/lib/kernel_lock.c b/lib/kernel_lock.c
index b135d04..106826d 100644
--- a/lib/kernel_lock.c
+++ b/lib/kernel_lock.c
@@ -96,6 +96,7 @@ static inline void __lock_kernel(void)
  */
 static inline void __lock_kernel(void)
 {
+	preempt_disable();
 	do_raw_spin_lock(&kernel_flag);
 }
 #endif


-- 
Michel "Walken" Lespinasse
A program is never fully debugged until the last user dies.

                 reply	other threads:[~2010-05-24 23:51 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20100524235112.GA30453@google.com \
    --to=walken@google.com \
    --cc=akpm@linux-foundation.org \
    --cc=andreas.herrmann3@amd.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@elte.hu \
    --cc=peterz@infradead.org \
    --cc=rml@tech9.net \
    --cc=tglx@linutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.