X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fs390%2Fappldata%2Fappldata_base.c;h=01ae1964c938cd828379dc594087299309531725;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=2d7efbf4fffcaf5241d662a851fb31e7e35efca3;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c index 2d7efbf4f..01ae1964c 100644 --- a/arch/s390/appldata/appldata_base.c +++ b/arch/s390/appldata/appldata_base.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,8 @@ #include #include //#include +#include +#include #include "appldata.h" @@ -85,10 +88,11 @@ struct appldata_parameter_list { */ static const char appldata_proc_name[APPLDATA_PROC_NAME_LENGTH] = "appldata"; static int appldata_timer_handler(ctl_table *ctl, int write, struct file *filp, - void *buffer, size_t *lenp); + void __user *buffer, size_t *lenp, loff_t *ppos); static int appldata_interval_handler(ctl_table *ctl, int write, - struct file *filp, void *buffer, - size_t *lenp); + struct file *filp, + void __user *buffer, + size_t *lenp, loff_t *ppos); static struct ctl_table_header *appldata_sysctl_header; static struct ctl_table appldata_table[] = { @@ -123,12 +127,8 @@ static struct ctl_table appldata_dir_table[] = { */ DEFINE_PER_CPU(struct vtimer_list, appldata_timer); static atomic_t appldata_expire_count = ATOMIC_INIT(0); -static struct appldata_mod_vtimer_args { - struct vtimer_list *timer; - u64 expires; -} appldata_mod_vtimer_args; -static spinlock_t appldata_timer_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(appldata_timer_lock); static int appldata_interval = APPLDATA_CPU_INTERVAL; static int appldata_timer_active; @@ -140,7 +140,7 @@ static struct tasklet_struct appldata_tasklet_struct; /* * Ops list */ -static spinlock_t appldata_ops_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(appldata_ops_lock); static LIST_HEAD(appldata_ops_list); @@ -153,7 +153,7 @@ static LIST_HEAD(appldata_ops_list); static void appldata_timer_function(unsigned long data, struct pt_regs *regs) { P_DEBUG(" -= Timer =-\n"); - P_DEBUG("CPU: %i, expire: %i\n", smp_processor_id(), + P_DEBUG("CPU: %i, expire_count: %i\n", smp_processor_id(), atomic_read(&appldata_expire_count)); if (atomic_dec_and_test(&appldata_expire_count)) { atomic_set(&appldata_expire_count, num_online_cpus()); @@ -186,16 +186,6 @@ static void appldata_tasklet_function(unsigned long data) spin_unlock(&appldata_ops_lock); } -/* - * appldata_mod_vtimer_wrap() - * - * wrapper function for mod_virt_timer(), because smp_call_function_on() - * accepts only one parameter. - */ -static void appldata_mod_vtimer_wrap(struct appldata_mod_vtimer_args *args) { - mod_virt_timer(args->timer, args->expires); -} - /* * appldata_diag() * @@ -245,6 +235,79 @@ static int appldata_diag(char record_nr, u16 function, unsigned long buffer, /****************************** /proc stuff **********************************/ + +/* + * appldata_mod_vtimer_wrap() + * + * wrapper function for mod_virt_timer(), because smp_call_function_on() + * accepts only one parameter. + */ +static void __appldata_mod_vtimer_wrap(void *p) { + struct { + struct vtimer_list *timer; + u64 expires; + } *args = p; + mod_virt_timer(args->timer, args->expires); +} + +#define APPLDATA_ADD_TIMER 0 +#define APPLDATA_DEL_TIMER 1 +#define APPLDATA_MOD_TIMER 2 + +/* + * __appldata_vtimer_setup() + * + * Add, delete or modify virtual timers on all online cpus. + * The caller needs to get the appldata_timer_lock spinlock. + */ +static void +__appldata_vtimer_setup(int cmd) +{ + u64 per_cpu_interval; + int i; + + switch (cmd) { + case APPLDATA_ADD_TIMER: + if (appldata_timer_active) + break; + per_cpu_interval = (u64) (appldata_interval*1000 / + num_online_cpus()) * TOD_MICRO; + for_each_online_cpu(i) { + per_cpu(appldata_timer, i).expires = per_cpu_interval; + smp_call_function_on(add_virt_timer_periodic, + &per_cpu(appldata_timer, i), + 0, 1, i); + } + appldata_timer_active = 1; + P_INFO("Monitoring timer started.\n"); + break; + case APPLDATA_DEL_TIMER: + for_each_online_cpu(i) + del_virt_timer(&per_cpu(appldata_timer, i)); + if (!appldata_timer_active) + break; + appldata_timer_active = 0; + atomic_set(&appldata_expire_count, num_online_cpus()); + P_INFO("Monitoring timer stopped.\n"); + break; + case APPLDATA_MOD_TIMER: + per_cpu_interval = (u64) (appldata_interval*1000 / + num_online_cpus()) * TOD_MICRO; + if (!appldata_timer_active) + break; + for_each_online_cpu(i) { + struct { + struct vtimer_list *timer; + u64 expires; + } args; + args.timer = &per_cpu(appldata_timer, i); + args.expires = per_cpu_interval; + smp_call_function_on(__appldata_mod_vtimer_wrap, + &args, 0, 1, i); + } + } +} + /* * appldata_timer_handler() * @@ -252,13 +315,12 @@ static int appldata_diag(char record_nr, u16 function, unsigned long buffer, */ static int appldata_timer_handler(ctl_table *ctl, int write, struct file *filp, - void *buffer, size_t *lenp) + void __user *buffer, size_t *lenp, loff_t *ppos) { - int len, i; + int len; char buf[2]; - u64 per_cpu_interval; - if (!*lenp || filp->f_pos) { + if (!*lenp || *ppos) { *lenp = 0; return 0; } @@ -270,34 +332,18 @@ appldata_timer_handler(ctl_table *ctl, int write, struct file *filp, return -EFAULT; goto out; } - per_cpu_interval = (u64) (appldata_interval*1000 / - num_online_cpus()) * TOD_MICRO; len = *lenp; if (copy_from_user(buf, buffer, len > sizeof(buf) ? sizeof(buf) : len)) return -EFAULT; spin_lock(&appldata_timer_lock); - per_cpu_interval = (u64) (appldata_interval*1000 / - num_online_cpus()) * TOD_MICRO; - if ((buf[0] == '1') && (!appldata_timer_active)) { - for (i = 0; i < num_online_cpus(); i++) { - per_cpu(appldata_timer, i).expires = per_cpu_interval; - smp_call_function_on(add_virt_timer_periodic, - &per_cpu(appldata_timer, i), - 0, 1, i); - } - appldata_timer_active = 1; - P_INFO("Monitoring timer started.\n"); - } else if ((buf[0] == '0') && (appldata_timer_active)) { - for (i = 0; i < num_online_cpus(); i++) { - del_virt_timer(&per_cpu(appldata_timer, i)); - } - appldata_timer_active = 0; - P_INFO("Monitoring timer stopped.\n"); - } + if (buf[0] == '1') + __appldata_vtimer_setup(APPLDATA_ADD_TIMER); + else if (buf[0] == '0') + __appldata_vtimer_setup(APPLDATA_DEL_TIMER); spin_unlock(&appldata_timer_lock); out: *lenp = len; - filp->f_pos += len; + *ppos += len; return 0; } @@ -309,13 +355,12 @@ out: */ static int appldata_interval_handler(ctl_table *ctl, int write, struct file *filp, - void *buffer, size_t *lenp) + void __user *buffer, size_t *lenp, loff_t *ppos) { - int len, i, interval; + int len, interval; char buf[16]; - u64 per_cpu_interval; - if (!*lenp || filp->f_pos) { + if (!*lenp || *ppos) { *lenp = 0; return 0; } @@ -338,27 +383,15 @@ appldata_interval_handler(ctl_table *ctl, int write, struct file *filp, } spin_lock(&appldata_timer_lock); - per_cpu_interval = (u64) (interval*1000 / num_online_cpus()) * TOD_MICRO; appldata_interval = interval; - if (appldata_timer_active) { - for (i = 0; i < num_online_cpus(); i++) { - appldata_mod_vtimer_args.timer = - &per_cpu(appldata_timer, i); - appldata_mod_vtimer_args.expires = - per_cpu_interval; - smp_call_function_on( - (void *) appldata_mod_vtimer_wrap, - &appldata_mod_vtimer_args, - 0, 1, i); - } - } + __appldata_vtimer_setup(APPLDATA_MOD_TIMER); spin_unlock(&appldata_timer_lock); P_INFO("Monitoring CPU interval set to %u milliseconds.\n", interval); out: *lenp = len; - filp->f_pos += len; + *ppos += len; return 0; } @@ -370,7 +403,7 @@ out: */ static int appldata_generic_handler(ctl_table *ctl, int write, struct file *filp, - void *buffer, size_t *lenp) + void __user *buffer, size_t *lenp, loff_t *ppos) { struct appldata_ops *ops = NULL, *tmp_ops; int rc, len, found; @@ -396,7 +429,7 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp, } spin_unlock_bh(&appldata_ops_lock); - if (!*lenp || filp->f_pos) { + if (!*lenp || *ppos) { *lenp = 0; module_put(ops->owner); return 0; @@ -455,7 +488,7 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp, spin_unlock_bh(&appldata_ops_lock); out: *lenp = len; - filp->f_pos += len; + *ppos += len; module_put(ops->owner); return 0; } @@ -562,6 +595,56 @@ void appldata_unregister_ops(struct appldata_ops *ops) /******************************* init / exit *********************************/ + +static void +appldata_online_cpu(int cpu) +{ + init_virt_timer(&per_cpu(appldata_timer, cpu)); + per_cpu(appldata_timer, cpu).function = appldata_timer_function; + per_cpu(appldata_timer, cpu).data = (unsigned long) + &appldata_tasklet_struct; + atomic_inc(&appldata_expire_count); + spin_lock(&appldata_timer_lock); + __appldata_vtimer_setup(APPLDATA_MOD_TIMER); + spin_unlock(&appldata_timer_lock); +} + +static void +appldata_offline_cpu(int cpu) +{ + del_virt_timer(&per_cpu(appldata_timer, cpu)); + if (atomic_dec_and_test(&appldata_expire_count)) { + atomic_set(&appldata_expire_count, num_online_cpus()); + tasklet_schedule(&appldata_tasklet_struct); + } + spin_lock(&appldata_timer_lock); + __appldata_vtimer_setup(APPLDATA_MOD_TIMER); + spin_unlock(&appldata_timer_lock); +} + +static int +appldata_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + switch (action) { + case CPU_ONLINE: + appldata_online_cpu((long) hcpu); + break; +#ifdef CONFIG_HOTPLUG_CPU + case CPU_DEAD: + appldata_offline_cpu((long) hcpu); + break; +#endif + default: + break; + } + return NOTIFY_OK; +} + +static struct notifier_block __devinitdata appldata_nb = { + .notifier_call = appldata_cpu_notify, +}; + /* * appldata_init() * @@ -574,13 +657,11 @@ static int __init appldata_init(void) P_DEBUG("sizeof(parameter_list) = %lu\n", sizeof(struct appldata_parameter_list)); - for (i = 0; i < num_online_cpus(); i++) { - init_virt_timer(&per_cpu(appldata_timer, i)); - per_cpu(appldata_timer, i).function = appldata_timer_function; - per_cpu(appldata_timer, i).data = (unsigned long) - &appldata_tasklet_struct; - } - atomic_set(&appldata_expire_count, num_online_cpus()); + for_each_online_cpu(i) + appldata_online_cpu(i); + + /* Register cpu hotplug notifier */ + register_cpu_notifier(&appldata_nb); appldata_sysctl_header = register_sysctl_table(appldata_dir_table, 1); #ifdef MODULE @@ -621,9 +702,9 @@ static void __exit appldata_exit(void) } spin_unlock_bh(&appldata_ops_lock); - for (i = 0; i < num_online_cpus(); i++) { - del_virt_timer(&per_cpu(appldata_timer, i)); - } + for_each_online_cpu(i) + appldata_offline_cpu(i); + appldata_timer_active = 0; unregister_sysctl_table(appldata_sysctl_header);