From: Ashok Raj Changes proc entries for cpu hotplug to be created via the cpu hotplug notifier callbacks. Also fixed a bug in the removal code that did not remove proc entries as expected. --- 25-akpm/arch/ia64/kernel/palinfo.c | 134 ++++++++++++++++++++++++++++--------- 1 files changed, 104 insertions(+), 30 deletions(-) diff -puN arch/ia64/kernel/palinfo.c~ia64-cpuhotplug-palinfo arch/ia64/kernel/palinfo.c --- 25/arch/ia64/kernel/palinfo.c~ia64-cpuhotplug-palinfo Tue May 4 17:46:06 2004 +++ 25-akpm/arch/ia64/kernel/palinfo.c Tue May 4 17:46:06 2004 @@ -8,11 +8,14 @@ * * Copyright (C) 2000-2001, 2003 Hewlett-Packard Co * Stephane Eranian + * Copyright (C) 2004 Intel Corporation + * Ashok Raj * * 05/26/2000 S.Eranian initial release * 08/21/2000 S.Eranian updated to July 2000 PAL specs * 02/05/2001 S.Eranian fixed module support * 10/23/2001 S.Eranian updated pal_perf_mon_info bug fixes + * 03/24/2004 Ashok Raj updated to work with CPU Hotplug */ #include #include @@ -22,6 +25,9 @@ #include #include #include +#include +#include +#include #include #include @@ -768,13 +774,12 @@ static palinfo_entry_t palinfo_entries[] * does not do recursion of deletion * * Notes: - * - first +1 accounts for the cpuN entry - * - second +1 account for toplevel palinfo - * + * - +1 accounts for the cpuN directory entry in /proc/pal */ -#define NR_PALINFO_PROC_ENTRIES (NR_CPUS*(NR_PALINFO_ENTRIES+1)+1) +#define NR_PALINFO_PROC_ENTRIES (NR_CPUS*(NR_PALINFO_ENTRIES+1)) static struct proc_dir_entry *palinfo_proc_entries[NR_PALINFO_PROC_ENTRIES]; +static struct proc_dir_entry *palinfo_dir; /* * This data structure is used to pass which cpu,function is being requested @@ -888,47 +893,107 @@ palinfo_read_entry(char *page, char **st return len; } -static int __init -palinfo_init(void) +static void +create_palinfo_proc_entries(unsigned int cpu) { # define CPUSTR "cpu%d" pal_func_cpu_u_t f; - struct proc_dir_entry **pdir = palinfo_proc_entries; - struct proc_dir_entry *palinfo_dir, *cpu_dir; - int i, j; + struct proc_dir_entry **pdir; + struct proc_dir_entry *cpu_dir; + int j; char cpustr[sizeof(CPUSTR)]; - printk(KERN_INFO "PAL Information Facility v%s\n", PALINFO_VERSION); - - palinfo_dir = proc_mkdir("pal", NULL); /* * we keep track of created entries in a depth-first order for * cleanup purposes. Each entry is stored into palinfo_proc_entries */ - for (i=0; i < NR_CPUS; i++) { + sprintf(cpustr,CPUSTR, cpu); - if (!cpu_online(i)) continue; + cpu_dir = proc_mkdir(cpustr, palinfo_dir); - sprintf(cpustr,CPUSTR, i); + f.req_cpu = cpu; - cpu_dir = proc_mkdir(cpustr, palinfo_dir); + /* + * Compute the location to store per cpu entries + * We dont store the top level entry in this list, but + * remove it finally after removing all cpu entries. + */ + pdir = &palinfo_proc_entries[cpu*(NR_PALINFO_ENTRIES+1)]; + *pdir++ = cpu_dir; + for (j=0; j < NR_PALINFO_ENTRIES; j++) { + f.func_id = j; + *pdir = create_proc_read_entry( + palinfo_entries[j].name, 0, cpu_dir, + palinfo_read_entry, (void *)f.value); + if (*pdir) + (*pdir)->owner = THIS_MODULE; + pdir++; + } +} - f.req_cpu = i; +static void +remove_palinfo_proc_entries(unsigned int hcpu) +{ + int j; + struct proc_dir_entry *cpu_dir, **pdir; - for (j=0; j < NR_PALINFO_ENTRIES; j++) { - f.func_id = j; - *pdir = create_proc_read_entry( - palinfo_entries[j].name, 0, cpu_dir, - palinfo_read_entry, (void *)f.value); - if (*pdir) - (*pdir)->owner = THIS_MODULE; - pdir++; + pdir = &palinfo_proc_entries[hcpu*(NR_PALINFO_ENTRIES+1)]; + cpu_dir = *pdir; + *pdir++=NULL; + for (j=0; j < (NR_PALINFO_ENTRIES); j++) { + if ((*pdir)) { + remove_proc_entry ((*pdir)->name, cpu_dir); + *pdir ++= NULL; } - *pdir++ = cpu_dir; } - *pdir = palinfo_dir; + + if (cpu_dir) { + remove_proc_entry(cpu_dir->name, palinfo_dir); + } +} + +static int __devinit palinfo_cpu_callback(struct notifier_block *nfb, + unsigned long action, + void *hcpu) +{ + unsigned int hotcpu = (unsigned long)hcpu; + + switch (action) { + case CPU_ONLINE: + create_palinfo_proc_entries(hotcpu); + break; +#ifdef CONFIG_HOTPLUG_CPU + case CPU_DEAD: + remove_palinfo_proc_entries(hotcpu); + break; +#endif + } + return NOTIFY_OK; +} + +static struct notifier_block palinfo_cpu_notifier = +{ + .notifier_call = palinfo_cpu_callback, + .priority = 0, +}; + +static int __init +palinfo_init(void) +{ + int i = 0; + + printk(KERN_INFO "PAL Information Facility v%s\n", PALINFO_VERSION); + palinfo_dir = proc_mkdir("pal", NULL); + + /* Create palinfo dirs in /proc for all online cpus */ + for_each_online_cpu(i) { + create_palinfo_proc_entries(i); + } + + /* Register for future delivery via notify registration */ + register_cpu_notifier(&palinfo_cpu_notifier); return 0; } @@ -939,10 +1004,19 @@ palinfo_exit(void) int i = 0; /* remove all nodes: depth first pass. Could optimize this */ - for (i=0; i< NR_PALINFO_PROC_ENTRIES ; i++) { - if (palinfo_proc_entries[i]) - remove_proc_entry (palinfo_proc_entries[i]->name, NULL); + for_each_online_cpu(i) { + remove_palinfo_proc_entries(i); } + + /* + * Remove the top level entry finally + */ + remove_proc_entry(palinfo_dir->name, NULL); + + /* + * Unregister from cpu notifier callbacks + */ + unregister_cpu_notifier(&palinfo_cpu_notifier); } module_init(palinfo_init); _