[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