[PATCH] rtasd cleanup

Nathan Lynch ntl at pobox.com
Sun Feb 20 07:28:46 EST 2005


Make rtasd stop (ab)using lock_cpu_hotplug and the online map.  Use a
lazier method: let do_event_scan tell rtasd on which cpu the scan was
done; rtasd then clears that cpu in its allowed map and migrates.
This reduces boot time by one second per cpu when
CONFIG_HOTPLUG_CPU=y.  (Sleeping for one second on each cpu while
holding the cpucontrol semaphore is not very polite.)

Stop looking up the "event-scan" token everywhere and just stash it in
a file-static variable.

Move a bunch of startup code from rtasd to rtas_init so it winds up in
the init text section.

Replace kernel_thread/daemonize with kthread_create.

rtasd.c | 193 +++++++++++++++++++++++++++++---------------------------
1 files changed, 101 insertions(+), 92 deletions(-)

Signed-off-by: Nathan Lynch <ntl at pobox.com>

Index: linux-2.6.11-rc4-bk4/arch/ppc64/kernel/rtasd.c
===================================================================
--- linux-2.6.11-rc4-bk4.orig/arch/ppc64/kernel/rtasd.c	2005-02-16 21:29:36.000000000 +0000
+++ linux-2.6.11-rc4-bk4/arch/ppc64/kernel/rtasd.c	2005-02-17 03:09:30.000000000 +0000
@@ -18,7 +18,8 @@
 #include <linux/init.h>
 #include <linux/vmalloc.h>
 #include <linux/spinlock.h>
-#include <linux/cpu.h>
+#include <linux/cpumask.h>
+#include <linux/kthread.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -43,6 +44,7 @@
 static unsigned long rtas_log_size;
 
 static int surveillance_timeout = -1;
+static int rtas_event_scan = -1; /* "event-scan" token */
 static unsigned int rtas_event_scan_rate;
 static unsigned int rtas_error_log_max;
 static unsigned int rtas_error_log_buffer_max;
@@ -359,95 +361,100 @@
 static int get_eventscan_parms(void)
 {
 	struct device_node *node;
-	int *ip;
+	int *ip, err = -1;
 
 	node = of_find_node_by_path("/rtas");
+	if (!node)
+		goto out;
 
-	ip = (int *)get_property(node, "rtas-event-scan-rate", NULL);
-	if (ip == NULL) {
-		printk(KERN_ERR "rtasd: no rtas-event-scan-rate\n");
-		of_node_put(node);
-		return -1;
-	}
+	if (!(ip = (int *)get_property(node, "event-scan", NULL)))
+		goto out;
+	rtas_event_scan = *ip;
+
+	if (!(ip = (int *)get_property(node, "rtas-event-scan-rate", NULL)))
+		goto out;
 	rtas_event_scan_rate = *ip;
-	DEBUG("rtas-event-scan-rate %d\n", rtas_event_scan_rate);
 
 	/* Make room for the sequence number */
 	rtas_error_log_max = rtas_get_error_log_max();
 	rtas_error_log_buffer_max = rtas_error_log_max + sizeof(int);
 
+	err = 0;
+out:
 	of_node_put(node);
-
-	return 0;
+	return err;
 }
 
-static void do_event_scan(int event_scan)
+/**
+ * do_event_scan - execute an event scan and log any errors returned
+ *
+ * Returns the cpu on which the event scan was run.  This is so rtasd
+ * can remove that cpu from its allowed map to ensure that it gets to
+ * run on a different cpu next time.  Architecture docs recommend that
+ * event scans be done periodically from every cpu in the system.
+ */
+static int do_event_scan(void)
 {
-	int error;
-	do {
+	int cpu = NR_CPUS;
+
+	while (1) {
+		int error;
+
 		memset(logdata, 0, rtas_error_log_max);
-		error = rtas_call(event_scan, 4, 1, NULL,
+
+		/* Get the cpu only once */
+		if (cpu == NR_CPUS)
+			cpu = get_cpu();
+
+		error = rtas_call(rtas_event_scan, 4, 1, NULL,
 				  RTAS_EVENT_SCAN_ALL_EVENTS, 0,
 				  __pa(logdata), rtas_error_log_max);
-		if (error == -1) {
-			printk(KERN_ERR "event-scan failed\n");
-			break;
-		}
 
-		if (error == 0)
+		if (likely(error == 1))
+			 /* No errors found */
+			break;
+		else if (error == 0) {
+			/* Must log and scan again */
 			pSeries_log_error(logdata, ERR_TYPE_RTAS_LOG, 0);
-
-	} while(error == 0);
+			continue;
+		} else {
+			/* Hardware error? */
+			printk(KERN_ERR "event-scan failed (rc = %d)\n",
+			       error);
+			break;
+		}
+	}
+	put_cpu();
+	return cpu;
 }
 
-static int rtasd(void *unused)
+/**
+ * do_event_scan_all_cpus - do an RTAS event scan on every cpu
+ *
+ * @delay:	time to sleep between scans
+ *
+ * Run an event scan on every cpu the scheduler will allow; return
+ * when there aren't any good cpus left.
+ */
+static void do_event_scan_all_cpus(long delay)
 {
-	unsigned int err_type;
-	int cpu = 0;
-	int event_scan = rtas_token("event-scan");
-	int rc;
+	cpumask_t allowed = CPU_MASK_ALL;
 
-	daemonize("rtasd");
-
-	if (event_scan == RTAS_UNKNOWN_SERVICE || get_eventscan_parms() == -1)
-		goto error;
-
-	rtas_log_buf = vmalloc(rtas_error_log_buffer_max*LOG_NUMBER);
-	if (!rtas_log_buf) {
-		printk(KERN_ERR "rtasd: no memory\n");
-		goto error;
+	while (0 == set_cpus_allowed(current, allowed)) {
+		int cpu = do_event_scan();
+		DEBUG("rtasd: completed event scan on cpu %i\n", cpu);
+		cpu_clear(cpu, allowed);
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(delay);
 	}
+}
 
-	printk(KERN_ERR "RTAS daemon started\n");
-
-	DEBUG("will sleep for %d jiffies\n", (HZ*60/rtas_event_scan_rate) / 2);
-
-	/* See if we have any error stored in NVRAM */
-	memset(logdata, 0, rtas_error_log_max);
-
-	rc = nvram_read_error_log(logdata, rtas_error_log_max, &err_type);
-
-	/* We can use rtas_log_buf now */
-	no_logging = 0;
-
-	if (!rc) {
-		if (err_type != ERR_FLAG_ALREADY_LOGGED) {
-			pSeries_log_error(logdata, err_type | ERR_FLAG_BOOT, 0);
-		}
-	}
+static int rtasd(void *unused)
+{
+	printk(KERN_INFO "RTAS daemon started\n");
 
 	/* First pass. */
-	lock_cpu_hotplug();
-	for_each_online_cpu(cpu) {
-		DEBUG("scheduling on %d\n", cpu);
-		set_cpus_allowed(current, cpumask_of_cpu(cpu));
-		DEBUG("watchdog scheduled on cpu %d\n", smp_processor_id());
-
-		do_event_scan(event_scan);
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout(HZ);
-	}
-	unlock_cpu_hotplug();
+	do_event_scan_all_cpus(HZ);
 
 	if (surveillance_timeout != -1) {
 		DEBUG("enabling surveillance\n");
@@ -455,51 +462,53 @@
 		DEBUG("surveillance enabled\n");
 	}
 
-	lock_cpu_hotplug();
-	cpu = first_cpu(cpu_online_map);
-	for (;;) {
-		set_cpus_allowed(current, cpumask_of_cpu(cpu));
-		do_event_scan(event_scan);
-		set_cpus_allowed(current, CPU_MASK_ALL);
-
-		/* Drop hotplug lock, and sleep for a bit (at least
-		 * one second since some machines have problems if we
-		 * call event-scan too quickly). */
-		unlock_cpu_hotplug();
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout((HZ*60/rtas_event_scan_rate) / 2);
-		lock_cpu_hotplug();
-
-		cpu = next_cpu(cpu, cpu_online_map);
-		if (cpu == NR_CPUS)
-			cpu = first_cpu(cpu_online_map);
-	}
-
-error:
-	/* Should delete proc entries */
-	return -EINVAL;
+	while (1)
+		do_event_scan_all_cpus((HZ*60/rtas_event_scan_rate) / 2);
 }
 
 static int __init rtas_init(void)
 {
 	struct proc_dir_entry *entry;
+	struct task_struct *p;
+	unsigned int err_type;
+	int rc;
 
 	/* No RTAS, only warn if we are on a pSeries box  */
-	if (rtas_token("event-scan") == RTAS_UNKNOWN_SERVICE) {
+	if (get_eventscan_parms() == -1) {
 		if (systemcfg->platform & PLATFORM_PSERIES)
-			printk(KERN_ERR "rtasd: no event-scan on system\n");
+			printk(KERN_ERR "no RTAS event-scan on system\n");
+		return 1;
+	}
+
+	rtas_log_buf = vmalloc(rtas_error_log_buffer_max*LOG_NUMBER);
+	if (!rtas_log_buf) {
+		printk(KERN_ERR "%s: no memory\n", __FUNCTION__);
 		return 1;
 	}
 
+	/* See if we have any error stored in NVRAM */
+	memset(logdata, 0, rtas_error_log_max);
+
+	rc = nvram_read_error_log(logdata, rtas_error_log_max, &err_type);
+
+	/* We can use rtas_log_buf now */
+	no_logging = 0;
+
+	if (!rc && err_type != ERR_FLAG_ALREADY_LOGGED)
+		pSeries_log_error(logdata, err_type | ERR_FLAG_BOOT, 0);
+
 	entry = create_proc_entry("ppc64/rtas/error_log", S_IRUSR, NULL);
 	if (entry)
 		entry->proc_fops = &proc_rtas_log_operations;
 	else
 		printk(KERN_ERR "Failed to create error_log proc entry\n");
 
-	if (kernel_thread(rtasd, NULL, CLONE_FS) < 0)
-		printk(KERN_ERR "Failed to start RTAS daemon\n");
-
+	p = kthread_create(rtasd, NULL, "rtasd");
+	if (IS_ERR(p)) {
+		printk(KERN_ERR "%s: rtasd creation failed\n", __FUNCTION__);
+		return 1;
+	}
+	wake_up_process(p);
 	return 0;
 }
 



More information about the Linuxppc64-dev mailing list