From: Ingo Molnar , john stultz clocksource_lock is used in softirq-context via e.g. timeofday_periodic_hook() -> get_next_clocksource(), but the lock is not acquired in a softirq-safe manner - which could lead to deadlocks. Signed-off-by: Ingo Molnar Cc: john stultz Signed-off-by: Andrew Morton --- kernel/time/clocksource.c | 44 ++++++++++++++++++++++-------------- 1 files changed, 27 insertions(+), 17 deletions(-) diff -puN kernel/time/clocksource.c~time-clocksource-infrastructure-fix-clocksource_lock-deadlock kernel/time/clocksource.c --- devel/kernel/time/clocksource.c~time-clocksource-infrastructure-fix-clocksource_lock-deadlock 2006-01-31 20:19:28.000000000 -0800 +++ devel-akpm/kernel/time/clocksource.c 2006-01-31 20:19:28.000000000 -0800 @@ -56,12 +56,14 @@ static char override_name[32]; */ struct clocksource *get_next_clocksource(void) { - spin_lock(&clocksource_lock); + unsigned long flags; + + spin_lock_irqsave(&clocksource_lock, flags); if (next_clocksource) { curr_clocksource = next_clocksource; next_clocksource = NULL; } - spin_unlock(&clocksource_lock); + spin_unlock_irqrestore(&clocksource_lock, flags); return curr_clocksource; } @@ -70,6 +72,10 @@ struct clocksource *get_next_clocksource * select_clocksource - Finds the best registered clocksource. * * Private function. Must hold clocksource_lock when called. + * + * Looks through the list of registered clocksources, returning + * the one with the highest rating value. If there is a clocksource + * name that matches the override string, return that clocksource. */ static struct clocksource *select_clocksource(void) { @@ -127,18 +133,20 @@ static int is_registered_source(struct c */ void register_clocksource(struct clocksource *c) { - spin_lock(&clocksource_lock); + unsigned long flags; + spin_lock_irqsave(&clocksource_lock, flags); /* check if clocksource is already registered */ if (is_registered_source(c)) { - printk("register_clocksource: Cannot register %s. Already registered!", + printk("register_clocksource(%s): already registered!", c->name); } else { - list_add(&c->list, &clocksource_list); - /* select next clocksource */ + /* register it */ + list_add(&c->list, &clocksource_list); + /* scan the registered clocksources, and pick the best one */ next_clocksource = select_clocksource(); } - spin_unlock(&clocksource_lock); + spin_unlock_irqrestore(&clocksource_lock, flags); } EXPORT_SYMBOL(register_clocksource); @@ -152,9 +160,11 @@ EXPORT_SYMBOL(register_clocksource); */ void reselect_clocksource(void) { - spin_lock(&clocksource_lock); + unsigned long flags; + + spin_lock_irqsave(&clocksource_lock, flags); next_clocksource = select_clocksource(); - spin_unlock(&clocksource_lock); + spin_unlock_irqrestore(&clocksource_lock, flags); } /** @@ -169,9 +179,9 @@ sysfs_show_current_clocksources(struct s { char *curr = buf; - spin_lock(&clocksource_lock); + spin_lock_irq(&clocksource_lock); curr += sprintf(curr, "%s ", curr_clocksource->name); - spin_unlock(&clocksource_lock); + spin_unlock_irq(&clocksource_lock); curr += sprintf(curr, "\n"); @@ -200,7 +210,7 @@ static ssize_t sysfs_override_clocksourc if (count < 1) return -EINVAL; - spin_lock(&clocksource_lock); + spin_lock_irq(&clocksource_lock); /* copy the name given: */ memcpy(override_name, buf, count); @@ -209,7 +219,7 @@ static ssize_t sysfs_override_clocksourc /* try to select it: */ next_clocksource = select_clocksource(); - spin_unlock(&clocksource_lock); + spin_unlock_irq(&clocksource_lock); return count; } @@ -227,14 +237,14 @@ sysfs_show_available_clocksources(struct struct list_head *tmp; char *curr = buf; - spin_lock(&clocksource_lock); + spin_lock_irq(&clocksource_lock); list_for_each(tmp, &clocksource_list) { struct clocksource *src; src = list_entry(tmp, struct clocksource, list); curr += sprintf(curr, "%s ", src->name); } - spin_unlock(&clocksource_lock); + spin_unlock_irq(&clocksource_lock); curr += sprintf(curr, "\n"); @@ -287,10 +297,10 @@ device_initcall(init_clocksource_sysfs); */ static int __init boot_override_clocksource(char* str) { - spin_lock(&clocksource_lock); + spin_lock_irq(&clocksource_lock); if (str) strlcpy(override_name, str, sizeof(override_name)); - spin_unlock(&clocksource_lock); + spin_unlock_irq(&clocksource_lock); return 1; } _