All of lore.kernel.org
 help / color / mirror / Atom feed
From: Gautham R Shenoy <ego@in.ibm.com>
To: rusty@rustcorp.com.au, torvalds@osdl.org, akpm@osdl.org
Cc: linux-kernel@vger.kernel.org, arjan@intel.linux.com,
	davej@redhat.com, mingo@elte.hu, vatsa@in.ibm.com,
	dipankar@in.ibm.com, ashok.raj@intel.com
Subject: [RFC][PATCH 3/4] (Refcount + Waitqueue) implementation for cpu_hotplug "locking"
Date: Thu, 24 Aug 2006 16:02:33 +0530	[thread overview]
Message-ID: <20060824103233.GD2395@in.ibm.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 165 bytes --]


-- 
Gautham R Shenoy
Linux Technology Center
IBM India.
"Freedom comes with a price tag of responsibility, which is still a bargain,
because Freedom is priceless!"

[-- Attachment #2: 3of4.patch --]
[-- Type: text/plain, Size: 8201 bytes --]

This patch provides the (Refcount + Workqueue) implementation for
cpu_hotplug "locking". It is analogous to a unfair rwsem.

Signed-off-by : Gautham R Shenoy <ego@in.ibm.com>

Index: current/kernel/cpu.c
===================================================================
--- current.orig/kernel/cpu.c	2006-08-06 23:50:11.000000000 +0530
+++ current/kernel/cpu.c	2006-08-24 15:00:04.000000000 +0530
@@ -14,50 +14,172 @@
 #include <linux/kthread.h>
 #include <linux/stop_machine.h>
 #include <linux/mutex.h>
-
-/* This protects CPUs going up and down... */
-static DEFINE_MUTEX(cpu_add_remove_lock);
-static DEFINE_MUTEX(cpu_bitmask_lock);
+#include <asm/percpu.h>
+#include <linux/cpumask.h>
+#include <linux/types.h>
+#include <linux/wait.h>
 
 static __cpuinitdata BLOCKING_NOTIFIER_HEAD(cpu_chain);
 
+/************************************************************************
+ *			A FEW CONTEXT SPECIFIC DEFINITIONS		*
+ * ---------------------------------------------------------------------*
+ * - reader : task which tries to *prevent* a cpu hotplug event.	*
+ *									*
+ * - writer : task which tries to *perform* a cpu hotplug event		*
+ *									*
+ * - write-operation: cpu hotplug operation.				*
+ *									*
+ ************************************************************************/
+
+ /***********************************************************************
+ *			THE PROTOCOL					*
+ *----------------------------------------------------------------------*
+ *- Analogous to RWSEM, only not so fair.				*
+ *									*
+ *- Readers assume control iff:						*
+ *	a) No other reader has a reference and no writer is writing.	*
+ *	OR								*
+ *	b) Atleast one reader has a reference.				*
+ *									*
+ *- In any other case, the reader is blocked.				*
+ *									*
+ *- Writer gets to perform a write iff:					*
+ *	*No* reader has a reference and no writer is writing.		*
+ *									*
+ *- In any other case, the writer is blocked.				*
+ *									*
+ *- Writer, on completion would preferable wake up other waiting	*
+ *  writers over the waiting readers.					*
+ *									*
+ *- The *last* writer wakes up all the waiting readers.			*
+ *									*
+ ************************************************************************/
+
+/************************************************************************
+				USEFUL FLAGS
+*************************************************************************/
+/* System has no writers 	*/
+#define NO_WRITERS		0
+
+/* Some writer is waiting */
+#define WRITER_WAITING		1
+
+/* A Writer is performing cpu hotplug*/
+#define CPU_HOTPLUG_ONGOING	2
+
+/*************************************************************************
+		 ( REFCOUNT + WAITQUEUE ) VARIABLES
+**************************************************************************/
+
+static struct {
+	int reader_count; /* Refcount for the Readers*/
+	int status; /* Status of hotplug operation(none,waiting,ongoing) */
+	spinlock_t lock; /* Serializes access to this struct */
+} cpu_hotplug __cacheline_aligned_in_smp =
+		{0, NO_WRITERS, SPIN_LOCK_UNLOCKED};
+
+/* Waitqueues for readers and writers */
+static __cacheline_aligned_in_smp DECLARE_WAIT_QUEUE_HEAD(read_queue);
+static __cacheline_aligned_in_smp DECLARE_WAIT_QUEUE_HEAD(write_queue);
+
+/********************************************************************
+	MAIN CPU_HOTPLUG (ENABLE/ DISABLE/ BEGIN/ DONE) CODE
+*********************************************************************/
 #ifdef CONFIG_HOTPLUG_CPU
 
-/* Crappy recursive lock-takers in cpufreq! Complain loudly about idiots */
-static struct task_struct *recursive;
-static int recursive_depth;
-
+/** lock_cpu_hotplug : Blocks iff
+	- Hotplug operation is underway.
+*/
 void lock_cpu_hotplug(void)
 {
-	struct task_struct *tsk = current;
-
-	if (tsk == recursive) {
-		static int warnings = 10;
-		if (warnings) {
-			printk(KERN_ERR "Lukewarm IQ detected in hotplug locking\n");
-			WARN_ON(1);
-			warnings--;
-		}
-		recursive_depth++;
+	DECLARE_WAITQUEUE(wait, current);
+	spin_lock(&cpu_hotplug.lock);
+	cpu_hotplug.reader_count++;
+	if (cpu_hotplug.status != CPU_HOTPLUG_ONGOING) {
+		spin_unlock(&cpu_hotplug.lock);
 		return;
 	}
-	mutex_lock(&cpu_bitmask_lock);
-	recursive = tsk;
+	add_wait_queue_exclusive(&read_queue, &wait);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	spin_unlock(&cpu_hotplug.lock);
+	schedule();
+	remove_wait_queue(&read_queue, &wait);
 }
 EXPORT_SYMBOL_GPL(lock_cpu_hotplug);
 
+/** unlock_cpu_hotplug:
+	- Decrements the reader_count.
+	- If no readers are holding reference AND there is a writer
+	waiting, we set the flag to HOTPLUG_ONGOING and wake up
+	one of the waiting writer.
+*/
 void unlock_cpu_hotplug(void)
 {
-	WARN_ON(recursive != current);
-	if (recursive_depth) {
-		recursive_depth--;
-		return;
+	spin_lock(&cpu_hotplug.lock);
+	/* This should not happen, but in case it does... */
+	WARN_ON(!cpu_hotplug.reader_count);
+
+	cpu_hotplug.reader_count--;
+	if (!(cpu_hotplug.reader_count) && \
+			(cpu_hotplug.status == WRITER_WAITING)) {
+		cpu_hotplug.status = CPU_HOTPLUG_ONGOING;
+		wake_up(&write_queue);
 	}
-	mutex_unlock(&cpu_bitmask_lock);
-	recursive = NULL;
+	spin_unlock(&cpu_hotplug.lock);
 }
 EXPORT_SYMBOL_GPL(unlock_cpu_hotplug);
 
+/** cpu_hotplug_begin : Blocks unless
+	No reader has the reference
+	AND
+	Hotplug operation is not ongoing.
+*/
+static void cpu_hotplug_begin(int interruptible)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	spin_lock(&cpu_hotplug.lock);
+	if (!cpu_hotplug.reader_count && \
+			(cpu_hotplug.status != CPU_HOTPLUG_ONGOING)) {
+		cpu_hotplug.status = CPU_HOTPLUG_ONGOING;
+		spin_unlock(&cpu_hotplug.lock);
+		return;
+	}
+	if (cpu_hotplug.status != CPU_HOTPLUG_ONGOING)
+		cpu_hotplug.status = WRITER_WAITING;
+	add_wait_queue_exclusive(&write_queue, &wait);
+	if (interruptible)
+		set_current_state(TASK_INTERRUPTIBLE);
+	else
+		set_current_state(TASK_UNINTERRUPTIBLE);
+	spin_unlock(&cpu_hotplug.lock);
+	schedule();
+	remove_wait_queue(&write_queue, &wait);
+}
+
+/** cpu_hotplug_done : Performs either one of the following:
+	- Wake up the next writer,if any.
+	- reset flag to zero
+	 and wake up all the waiting readers, if any.
+*/
+void cpu_hotplug_done(void)
+{
+	spin_lock(&cpu_hotplug.lock);
+
+	if (!list_empty(&write_queue.task_list))
+		/* Another cpu writer! */
+		wake_up(&write_queue);
+	else {
+		/* This is the last writer. Remove the flag */
+		cpu_hotplug.status = NO_WRITERS;
+
+		if (cpu_hotplug.reader_count)
+			wake_up_all(&read_queue); /* All rise! */
+	}
+
+	spin_unlock(&cpu_hotplug.lock);
+}
+
 #endif	/* CONFIG_HOTPLUG_CPU */
 
 /* Need to know about CPUs going up/down? */
@@ -114,7 +236,7 @@ int cpu_down(unsigned int cpu)
 	struct task_struct *p;
 	cpumask_t old_allowed, tmp;
 
-	mutex_lock(&cpu_add_remove_lock);
+	cpu_hotplug_begin(1);
 	if (num_online_cpus() == 1) {
 		err = -EBUSY;
 		goto out;
@@ -140,9 +262,7 @@ int cpu_down(unsigned int cpu)
 	cpu_clear(cpu, tmp);
 	set_cpus_allowed(current, tmp);
 
-	mutex_lock(&cpu_bitmask_lock);
 	p = __stop_machine_run(take_cpu_down, NULL, cpu);
-	mutex_unlock(&cpu_bitmask_lock);
 
 	if (IS_ERR(p)) {
 		/* CPU didn't die: tell everyone.  Can't complain. */
@@ -180,7 +300,7 @@ out_thread:
 out_allowed:
 	set_cpus_allowed(current, old_allowed);
 out:
-	mutex_unlock(&cpu_add_remove_lock);
+	cpu_hotplug_done();
 	return err;
 }
 #endif /*CONFIG_HOTPLUG_CPU*/
@@ -190,7 +310,7 @@ int __devinit cpu_up(unsigned int cpu)
 	int ret;
 	void *hcpu = (void *)(long)cpu;
 
-	mutex_lock(&cpu_add_remove_lock);
+	cpu_hotplug_begin(1);
 	if (cpu_online(cpu) || !cpu_present(cpu)) {
 		ret = -EINVAL;
 		goto out;
@@ -205,21 +325,18 @@ int __devinit cpu_up(unsigned int cpu)
 	}
 
 	/* Arch-specific enabling code. */
-	mutex_lock(&cpu_bitmask_lock);
 	ret = __cpu_up(cpu);
-	mutex_unlock(&cpu_bitmask_lock);
 	if (ret != 0)
 		goto out_notify;
 	BUG_ON(!cpu_online(cpu));
 
 	/* Now call notifier in preparation. */
 	blocking_notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu);
-
 out_notify:
 	if (ret != 0)
 		blocking_notifier_call_chain(&cpu_chain,
 				CPU_UP_CANCELED, hcpu);
 out:
-	mutex_unlock(&cpu_add_remove_lock);
+	cpu_hotplug_done();
 	return ret;
 }

             reply	other threads:[~2006-08-24 10:31 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-08-24 10:32 Gautham R Shenoy [this message]
2006-08-24 11:14 ` [RFC][PATCH 3/4] (Refcount + Waitqueue) implementation for cpu_hotplug "locking" Ingo Molnar
2006-08-24 12:28   ` Gautham R Shenoy
2006-08-24 12:25     ` Ingo Molnar
2006-08-24 12:58       ` Srivatsa Vaddagiri
2006-08-25  6:04         ` Gautham R Shenoy
2006-08-25  6:19           ` Nick Piggin
2006-08-25  6:29             ` Srivatsa Vaddagiri

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=20060824103233.GD2395@in.ibm.com \
    --to=ego@in.ibm.com \
    --cc=akpm@osdl.org \
    --cc=arjan@intel.linux.com \
    --cc=ashok.raj@intel.com \
    --cc=davej@redhat.com \
    --cc=dipankar@in.ibm.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@elte.hu \
    --cc=rusty@rustcorp.com.au \
    --cc=torvalds@osdl.org \
    --cc=vatsa@in.ibm.com \
    /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.