Skip to contentSkip to conversation

schedule() in_atomic() fix

PATCH In review Robert Love 1 participant 3 messages Sep 18, 2002 1 message not in the archive

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 schedule() in_atomic() fix

Linus,

Attached patch fixes the scheduler in_atomic() problem with kernel preemption enabled (and is also working - when kernel preemption is on, it finds a couple issues during boot).

I hope this approach is to your liking.

Patch is against current BK, please apply.

Robert Love

kernel/sched.c +13 -4
diff -urN linux-2.5.36/kernel/sched.c linux/kernel/sched.c
@@ -940,9 +940,6 @@
 	struct list_head *queue;
 	int idx;
 
-	if (unlikely(in_atomic()))
-		BUG();
-
 #if CONFIG_DEBUG_HIGHMEM
 	check_highmem_ptes();
 #endif
@@ -950,8 +947,20 @@
 	preempt_disable();
 	prev = current;
 	rq = this_rq();
-
 	release_kernel_lock(prev);
+
+	/*
+	 * Test if we are atomic.  Since do_exit() needs to call into
+	 * schedule() atomically, we ignore that for now.  Otherwise,
+	 * whine if we are scheduling when we should not be.
+	 */
+	if (likely(current->state != TASK_ZOMBIE)) {
+		if (unlikely((preempt_count() & ~PREEMPT_ACTIVE) != 1)) {
+			printk(KERN_ERR "scheduling while non-atomic!\n");
+			dump_stack();
+		}
+	}
+
 	prev->sleep_timestamp = jiffies;
 	spin_lock_irq(&rq->lock);
 

A message that is not in the archive (sent off-list or not yet received): [email protected]

#2 lore raw
Quoted 5 lines · Andrew Morton
Quoted 2 lines · Robert Love

+ printk(KERN_ERR "scheduling while non-atomic!\n");

When did this become illegal? :-)

Ugh, reality is blurred... thanks.

Linus, this patch reduces the kernel by 4 bytes over the previous. Please, apply.

Robert Love

kernel/sched.c +13 -4
diff -urN linux-2.5.36/kernel/sched.c linux/kernel/sched.c
@@ -940,9 +940,6 @@
 	struct list_head *queue;
 	int idx;
 
-	if (unlikely(in_atomic()))
-		BUG();
-
 #if CONFIG_DEBUG_HIGHMEM
 	check_highmem_ptes();
 #endif
@@ -950,8 +947,20 @@
 	preempt_disable();
 	prev = current;
 	rq = this_rq();
-
 	release_kernel_lock(prev);
+
+	/*
+	 * Test if we are atomic.  Since do_exit() needs to call into
+	 * schedule() atomically, we ignore that for now.  Otherwise,
+	 * whine if we are scheduling when we should not be.
+	 */
+	if (likely(current->state != TASK_ZOMBIE)) {
+		if (unlikely((preempt_count() & ~PREEMPT_ACTIVE) != 1)) {
+			printk(KERN_ERR "scheduling while atomic!\n");
+			dump_stack();
+		}
+	}
+
 	prev->sleep_timestamp = jiffies;
 	spin_lock_irq(&rq->lock);
 
#3 lore raw
In reply to Robert Love
Quoted 3 lines · Robert Love

Attached patch fixes the scheduler in_atomic() problem with kernel preemption enabled (and is also working - when kernel preemption is on, it finds a couple issues during boot).

Attached version works with non-CONFIG_PREEMPT ...

Robert Love

kernel/sched.c +11 -2
diff -urN linux-2.5.36/kernel/sched.c linux/kernel/sched.c
@@ -940,8 +940,17 @@
 	struct list_head *queue;
 	int idx;
 
-	if (unlikely(in_atomic()))
-		BUG();
+	/*
+	 * Test if we are atomic.  Since do_exit() needs to call into
+	 * schedule() atomically, we ignore that for now.  Otherwise,
+	 * whine if we are scheduling when we should not be.
+	 */
+	if (likely(current->state != TASK_ZOMBIE)) {
+		if (unlikely(in_atomic())) {
+			printk(KERN_ERR "scheduling while atomic!\n");
+			dump_stack();
+		}
+	}
 
 #if CONFIG_DEBUG_HIGHMEM
 	check_highmem_ptes();