diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Kconfig.debug | 23 | ||||
-rw-r--r-- | lib/bust_spinlocks.c | 2 | ||||
-rw-r--r-- | lib/dynamic_printk.c | 58 | ||||
-rw-r--r-- | lib/fault-inject.c | 1 | ||||
-rw-r--r-- | lib/klist.c | 43 | ||||
-rw-r--r-- | lib/kobject_uevent.c | 8 | ||||
-rw-r--r-- | lib/percpu_counter.c | 18 | ||||
-rw-r--r-- | lib/prio_heap.c | 2 | ||||
-rw-r--r-- | lib/proportions.c | 2 | ||||
-rw-r--r-- | lib/radix-tree.c | 13 | ||||
-rw-r--r-- | lib/rbtree.c | 12 | ||||
-rw-r--r-- | lib/sort.c | 30 | ||||
-rw-r--r-- | lib/swiotlb.c | 2 | ||||
-rw-r--r-- | lib/vsprintf.c | 4 |
14 files changed, 139 insertions, 79 deletions
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 2e75478..4c9ae60 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -512,6 +512,13 @@ config DEBUG_VIRTUAL If unsure, say N. +config DEBUG_NOMMU_REGIONS + bool "Debug the global anon/private NOMMU mapping region tree" + depends on DEBUG_KERNEL && !MMU + help + This option causes the global tree of anonymous and private mapping + regions to be regularly checked for invalid topology. + config DEBUG_WRITECOUNT bool "Debug filesystem writers count" depends on DEBUG_KERNEL @@ -566,14 +573,14 @@ config DEBUG_NOTIFIERS config FRAME_POINTER bool "Compile the kernel with frame pointers" depends on DEBUG_KERNEL && \ - (X86 || CRIS || M68K || M68KNOMMU || FRV || UML || S390 || \ - AVR32 || SUPERH || BLACKFIN || MN10300) - default y if DEBUG_INFO && UML - help - If you say Y here the resulting kernel image will be slightly larger - and slower, but it might give very useful debugging information on - some architectures or if you use external debuggers. - If you don't debug the kernel, you can say N. + (CRIS || M68K || M68KNOMMU || FRV || UML || S390 || \ + AVR32 || SUPERH || BLACKFIN || MN10300) || \ + ARCH_WANT_FRAME_POINTERS + default y if (DEBUG_INFO && UML) || ARCH_WANT_FRAME_POINTERS + help + If you say Y here the resulting kernel image will be slightly + larger and slower, but it gives very useful debugging information + in case of kernel bugs. (precise oopses/stacktraces/warnings) config BOOT_PRINTK_DELAY bool "Delay each boot printk message by N milliseconds" diff --git a/lib/bust_spinlocks.c b/lib/bust_spinlocks.c index 486da62..9681d54 100644 --- a/lib/bust_spinlocks.c +++ b/lib/bust_spinlocks.c @@ -12,6 +12,7 @@ #include <linux/tty.h> #include <linux/wait.h> #include <linux/vt_kern.h> +#include <linux/console.h> void __attribute__((weak)) bust_spinlocks(int yes) @@ -22,6 +23,7 @@ void __attribute__((weak)) bust_spinlocks(int yes) #ifdef CONFIG_VT unblank_screen(); #endif + console_unblank(); if (--oops_in_progress == 0) wake_up_klogd(); } diff --git a/lib/dynamic_printk.c b/lib/dynamic_printk.c index 8e30295..165a197 100644 --- a/lib/dynamic_printk.c +++ b/lib/dynamic_printk.c @@ -277,40 +277,34 @@ static ssize_t pr_debug_write(struct file *file, const char __user *buf, dynamic_enabled = DYNAMIC_ENABLED_NONE; } err = 0; - } else { - if (elem) { - if (value && (elem->enable == 0)) { - dynamic_printk_enabled |= - (1LL << elem->hash1); - dynamic_printk_enabled2 |= - (1LL << elem->hash2); - elem->enable = 1; - num_enabled++; - dynamic_enabled = DYNAMIC_ENABLED_SOME; - err = 0; - printk(KERN_DEBUG - "debugging enabled for module %s\n", - elem->name); - } else if (!value && (elem->enable == 1)) { - elem->enable = 0; - num_enabled--; - if (disabled_hash(elem->hash1, true)) - dynamic_printk_enabled &= + } else if (elem) { + if (value && (elem->enable == 0)) { + dynamic_printk_enabled |= (1LL << elem->hash1); + dynamic_printk_enabled2 |= (1LL << elem->hash2); + elem->enable = 1; + num_enabled++; + dynamic_enabled = DYNAMIC_ENABLED_SOME; + err = 0; + printk(KERN_DEBUG + "debugging enabled for module %s\n", + elem->name); + } else if (!value && (elem->enable == 1)) { + elem->enable = 0; + num_enabled--; + if (disabled_hash(elem->hash1, true)) + dynamic_printk_enabled &= ~(1LL << elem->hash1); - if (disabled_hash(elem->hash2, false)) - dynamic_printk_enabled2 &= + if (disabled_hash(elem->hash2, false)) + dynamic_printk_enabled2 &= ~(1LL << elem->hash2); - if (num_enabled) - dynamic_enabled = - DYNAMIC_ENABLED_SOME; - else - dynamic_enabled = - DYNAMIC_ENABLED_NONE; - err = 0; - printk(KERN_DEBUG - "debugging disabled for module " - "%s\n", elem->name); - } + if (num_enabled) + dynamic_enabled = DYNAMIC_ENABLED_SOME; + else + dynamic_enabled = DYNAMIC_ENABLED_NONE; + err = 0; + printk(KERN_DEBUG + "debugging disabled for module %s\n", + elem->name); } } } diff --git a/lib/fault-inject.c b/lib/fault-inject.c index a50a311..f97af55b 100644 --- a/lib/fault-inject.c +++ b/lib/fault-inject.c @@ -6,7 +6,6 @@ #include <linux/fs.h> #include <linux/module.h> #include <linux/interrupt.h> -#include <linux/unwind.h> #include <linux/stacktrace.h> #include <linux/kallsyms.h> #include <linux/fault-inject.h> diff --git a/lib/klist.c b/lib/klist.c index bbdd301..573d606 100644 --- a/lib/klist.c +++ b/lib/klist.c @@ -36,6 +36,7 @@ #include <linux/klist.h> #include <linux/module.h> +#include <linux/sched.h> /* * Use the lowest bit of n_klist to mark deleted nodes and exclude @@ -108,7 +109,6 @@ static void add_tail(struct klist *k, struct klist_node *n) static void klist_node_init(struct klist *k, struct klist_node *n) { INIT_LIST_HEAD(&n->n_node); - init_completion(&n->n_removed); kref_init(&n->n_ref); knode_set_klist(n, k); if (k->get) @@ -171,13 +171,34 @@ void klist_add_before(struct klist_node *n, struct klist_node *pos) } EXPORT_SYMBOL_GPL(klist_add_before); +struct klist_waiter { + struct list_head list; + struct klist_node *node; + struct task_struct *process; + int woken; +}; + +static DEFINE_SPINLOCK(klist_remove_lock); +static LIST_HEAD(klist_remove_waiters); + static void klist_release(struct kref *kref) { + struct klist_waiter *waiter, *tmp; struct klist_node *n = container_of(kref, struct klist_node, n_ref); WARN_ON(!knode_dead(n)); list_del(&n->n_node); - complete(&n->n_removed); + spin_lock(&klist_remove_lock); + list_for_each_entry_safe(waiter, tmp, &klist_remove_waiters, list) { + if (waiter->node != n) + continue; + + waiter->woken = 1; + mb(); + wake_up_process(waiter->process); + list_del(&waiter->list); + } + spin_unlock(&klist_remove_lock); knode_set_klist(n, NULL); } @@ -217,8 +238,24 @@ EXPORT_SYMBOL_GPL(klist_del); */ void klist_remove(struct klist_node *n) { + struct klist_waiter waiter; + + waiter.node = n; + waiter.process = current; + waiter.woken = 0; + spin_lock(&klist_remove_lock); + list_add(&waiter.list, &klist_remove_waiters); + spin_unlock(&klist_remove_lock); + klist_del(n); - wait_for_completion(&n->n_removed); + + for (;;) { + set_current_state(TASK_UNINTERRUPTIBLE); + if (waiter.woken) + break; + schedule(); + } + __set_current_state(TASK_RUNNING); } EXPORT_SYMBOL_GPL(klist_remove); diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 3f91472..318328dd 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -165,7 +165,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, /* keys passed in from the caller */ if (envp_ext) { for (i = 0; envp_ext[i]; i++) { - retval = add_uevent_var(env, envp_ext[i]); + retval = add_uevent_var(env, "%s", envp_ext[i]); if (retval) goto exit; } @@ -225,8 +225,10 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, } NETLINK_CB(skb).dst_group = 1; - netlink_broadcast(uevent_sock, skb, 0, 1, GFP_KERNEL); - } + retval = netlink_broadcast(uevent_sock, skb, 0, 1, + GFP_KERNEL); + } else + retval = -ENOMEM; } #endif diff --git a/lib/percpu_counter.c b/lib/percpu_counter.c index 4bb0ed3..aeaa6d7 100644 --- a/lib/percpu_counter.c +++ b/lib/percpu_counter.c @@ -9,10 +9,8 @@ #include <linux/cpu.h> #include <linux/module.h> -#ifdef CONFIG_HOTPLUG_CPU static LIST_HEAD(percpu_counters); static DEFINE_MUTEX(percpu_counters_lock); -#endif void percpu_counter_set(struct percpu_counter *fbc, s64 amount) { @@ -101,13 +99,24 @@ void percpu_counter_destroy(struct percpu_counter *fbc) } EXPORT_SYMBOL(percpu_counter_destroy); -#ifdef CONFIG_HOTPLUG_CPU +int percpu_counter_batch __read_mostly = 32; +EXPORT_SYMBOL(percpu_counter_batch); + +static void compute_batch_value(void) +{ + int nr = num_online_cpus(); + + percpu_counter_batch = max(32, nr*2); +} + static int __cpuinit percpu_counter_hotcpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu) { +#ifdef CONFIG_HOTPLUG_CPU unsigned int cpu; struct percpu_counter *fbc; + compute_batch_value(); if (action != CPU_DEAD) return NOTIFY_OK; @@ -124,13 +133,14 @@ static int __cpuinit percpu_counter_hotcpu_callback(struct notifier_block *nb, spin_unlock_irqrestore(&fbc->lock, flags); } mutex_unlock(&percpu_counters_lock); +#endif return NOTIFY_OK; } static int __init percpu_counter_startup(void) { + compute_batch_value(); hotcpu_notifier(percpu_counter_hotcpu_callback, 0); return 0; } module_init(percpu_counter_startup); -#endif diff --git a/lib/prio_heap.c b/lib/prio_heap.c index 471944a..a7af6f8 100644 --- a/lib/prio_heap.c +++ b/lib/prio_heap.c @@ -31,7 +31,7 @@ void *heap_insert(struct ptr_heap *heap, void *p) if (heap->size < heap->max) { /* Heap insertion */ - int pos = heap->size++; + pos = heap->size++; while (pos > 0 && heap->gt(p, ptrs[(pos-1)/2])) { ptrs[pos] = ptrs[(pos-1)/2]; pos = (pos-1)/2; diff --git a/lib/proportions.c b/lib/proportions.c index 7367f2b..d50746a 100644 --- a/lib/proportions.c +++ b/lib/proportions.c @@ -147,6 +147,7 @@ out: * this is used to track the active references. */ static struct prop_global *prop_get_global(struct prop_descriptor *pd) +__acquires(RCU) { int index; @@ -160,6 +161,7 @@ static struct prop_global *prop_get_global(struct prop_descriptor *pd) } static void prop_put_global(struct prop_descriptor *pd, struct prop_global *pg) +__releases(RCU) { rcu_read_unlock(); } diff --git a/lib/radix-tree.c b/lib/radix-tree.c index be86b32..4bb42a0 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c @@ -81,7 +81,7 @@ struct radix_tree_preload { int nr; struct radix_tree_node *nodes[RADIX_TREE_MAX_PATH]; }; -DEFINE_PER_CPU(struct radix_tree_preload, radix_tree_preloads) = { 0, }; +static DEFINE_PER_CPU(struct radix_tree_preload, radix_tree_preloads) = { 0, }; static inline gfp_t root_gfp_mask(struct radix_tree_root *root) { @@ -640,13 +640,14 @@ EXPORT_SYMBOL(radix_tree_tag_get); * * Returns: the index of the hole if found, otherwise returns an index * outside of the set specified (in which case 'return - index >= max_scan' - * will be true). + * will be true). In rare cases of index wrap-around, 0 will be returned. * * radix_tree_next_hole may be called under rcu_read_lock. However, like - * radix_tree_gang_lookup, this will not atomically search a snapshot of the - * tree at a single point in time. For example, if a hole is created at index - * 5, then subsequently a hole is created at index 10, radix_tree_next_hole - * covering both indexes may return 10 if called under rcu_read_lock. + * radix_tree_gang_lookup, this will not atomically search a snapshot of + * the tree at a single point in time. For example, if a hole is created + * at index 5, then subsequently a hole is created at index 10, + * radix_tree_next_hole covering both indexes may return 10 if called + * under rcu_read_lock. */ unsigned long radix_tree_next_hole(struct radix_tree_root *root, unsigned long index, unsigned long max_scan) diff --git a/lib/rbtree.c b/lib/rbtree.c index 48499c2..9956b996 100644 --- a/lib/rbtree.c +++ b/lib/rbtree.c @@ -292,7 +292,7 @@ EXPORT_SYMBOL(rb_erase); /* * This function returns the first node (in sort order) of the tree. */ -struct rb_node *rb_first(struct rb_root *root) +struct rb_node *rb_first(const struct rb_root *root) { struct rb_node *n; @@ -305,7 +305,7 @@ struct rb_node *rb_first(struct rb_root *root) } EXPORT_SYMBOL(rb_first); -struct rb_node *rb_last(struct rb_root *root) +struct rb_node *rb_last(const struct rb_root *root) { struct rb_node *n; @@ -318,7 +318,7 @@ struct rb_node *rb_last(struct rb_root *root) } EXPORT_SYMBOL(rb_last); -struct rb_node *rb_next(struct rb_node *node) +struct rb_node *rb_next(const struct rb_node *node) { struct rb_node *parent; @@ -331,7 +331,7 @@ struct rb_node *rb_next(struct rb_node *node) node = node->rb_right; while (node->rb_left) node=node->rb_left; - return node; + return (struct rb_node *)node; } /* No right-hand children. Everything down and left is @@ -347,7 +347,7 @@ struct rb_node *rb_next(struct rb_node *node) } EXPORT_SYMBOL(rb_next); -struct rb_node *rb_prev(struct rb_node *node) +struct rb_node *rb_prev(const struct rb_node *node) { struct rb_node *parent; @@ -360,7 +360,7 @@ struct rb_node *rb_prev(struct rb_node *node) node = node->rb_left; while (node->rb_right) node=node->rb_right; - return node; + return (struct rb_node *)node; } /* No left-hand children. Go up till we find an ancestor which @@ -32,11 +32,11 @@ static void generic_swap(void *a, void *b, int size) * @base: pointer to data to sort * @num: number of elements * @size: size of each element - * @cmp: pointer to comparison function - * @swap: pointer to swap function or NULL + * @cmp_func: pointer to comparison function + * @swap_func: pointer to swap function or NULL * * This function does a heapsort on the given array. You may provide a - * swap function optimized to your element type. + * swap_func function optimized to your element type. * * Sorting time is O(n log n) both on average and worst-case. While * qsort is about 20% faster on average, it suffers from exploitable @@ -45,37 +45,39 @@ static void generic_swap(void *a, void *b, int size) */ void sort(void *base, size_t num, size_t size, - int (*cmp)(const void *, const void *), - void (*swap)(void *, void *, int size)) + int (*cmp_func)(const void *, const void *), + void (*swap_func)(void *, void *, int size)) { /* pre-scale counters for performance */ int i = (num/2 - 1) * size, n = num * size, c, r; - if (!swap) - swap = (size == 4 ? u32_swap : generic_swap); + if (!swap_func) + swap_func = (size == 4 ? u32_swap : generic_swap); /* heapify */ for ( ; i >= 0; i -= size) { for (r = i; r * 2 + size < n; r = c) { c = r * 2 + size; - if (c < n - size && cmp(base + c, base + c + size) < 0) + if (c < n - size && + cmp_func(base + c, base + c + size) < 0) c += size; - if (cmp(base + r, base + c) >= 0) + if (cmp_func(base + r, base + c) >= 0) break; - swap(base + r, base + c, size); + swap_func(base + r, base + c, size); } } /* sort */ for (i = n - size; i > 0; i -= size) { - swap(base, base + i, size); + swap_func(base, base + i, size); for (r = 0; r * 2 + size < i; r = c) { c = r * 2 + size; - if (c < i - size && cmp(base + c, base + c + size) < 0) + if (c < i - size && + cmp_func(base + c, base + c + size) < 0) c += size; - if (cmp(base + r, base + c) >= 0) + if (cmp_func(base + r, base + c) >= 0) break; - swap(base + r, base + c, size); + swap_func(base + r, base + c, size); } } } diff --git a/lib/swiotlb.c b/lib/swiotlb.c index ec7922b..30fe65e 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c @@ -619,7 +619,7 @@ swiotlb_full(struct device *dev, size_t size, int dir, int do_panic) * the damage, or panic when the transfer is too big. */ printk(KERN_ERR "DMA: Out of SW-IOMMU space for %zu bytes at " - "device %s\n", size, dev ? dev->bus_id : "?"); + "device %s\n", size, dev ? dev_name(dev) : "?"); if (size > io_tlb_overflow && do_panic) { if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 98d63227..0fbd012 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -170,6 +170,8 @@ int strict_strtoul(const char *cp, unsigned int base, unsigned long *res) return -EINVAL; val = simple_strtoul(cp, &tail, base); + if (tail == cp) + return -EINVAL; if ((*tail == '\0') || ((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) { *res = val; @@ -241,6 +243,8 @@ int strict_strtoull(const char *cp, unsigned int base, unsigned long long *res) return -EINVAL; val = simple_strtoull(cp, &tail, base); + if (tail == cp) + return -EINVAL; if ((*tail == '\0') || ((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) { *res = val; |