From b762450e84e20a179ee5993b065caaad99a65fbf Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 27 Jun 2006 02:53:26 -0700 Subject: [PATCH] zlib inflate: fix function definitions Fix function definitions to be ANSI-compliant: lib/zlib_inflate/inffast.c:68:1: warning: non-ANSI definition of function 'inflate_fast' lib/zlib_inflate/inftrees.c:33:1: warning: non-ANSI definition of function 'zlib_inflate_table' Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/zlib_inflate/inffast.c | 6 +++--- lib/zlib_inflate/inftrees.c | 9 ++------- 2 files changed, 5 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/zlib_inflate/inffast.c b/lib/zlib_inflate/inffast.c index 02a16eacb72d..d84560c076d8 100644 --- a/lib/zlib_inflate/inffast.c +++ b/lib/zlib_inflate/inffast.c @@ -63,10 +63,10 @@ bytes, which is the maximum length that can be coded. inflate_fast() requires strm->avail_out >= 258 for each loop to avoid checking for output space. + + - @start: inflate()'s starting value for strm->avail_out */ -void inflate_fast(strm, start) -z_streamp strm; -unsigned start; /* inflate()'s starting value for strm->avail_out */ +void inflate_fast(z_streamp strm, unsigned start) { struct inflate_state *state; unsigned char *in; /* local strm->next_in */ diff --git a/lib/zlib_inflate/inftrees.c b/lib/zlib_inflate/inftrees.c index da665fbb16aa..3fe6ce5b53e5 100644 --- a/lib/zlib_inflate/inftrees.c +++ b/lib/zlib_inflate/inftrees.c @@ -20,13 +20,8 @@ table index bits. It will differ if the request is greater than the longest code or if it is less than the shortest code. */ -int zlib_inflate_table(type, lens, codes, table, bits, work) -codetype type; -unsigned short *lens; -unsigned codes; -code **table; -unsigned *bits; -unsigned short *work; +int zlib_inflate_table(codetype type, unsigned short *lens, unsigned codes, + code **table, unsigned *bits, unsigned short *work) { unsigned len; /* a code's length in bits */ unsigned sym; /* index of code symbols */ -- cgit v1.2.3 From 77ba89c5cf28d5d98a3cae17f67a3e42b102cc25 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Tue, 27 Jun 2006 02:54:51 -0700 Subject: [PATCH] pi-futex: add plist implementation Add the priority-sorted list (plist) implementation. Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner Signed-off-by: Arjan van de Ven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/plist.h | 247 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/Kconfig | 6 ++ lib/Makefile | 1 + lib/plist.c | 118 ++++++++++++++++++++++++ 4 files changed, 372 insertions(+) create mode 100644 include/linux/plist.h create mode 100644 lib/plist.c (limited to 'lib') diff --git a/include/linux/plist.h b/include/linux/plist.h new file mode 100644 index 000000000000..3404faef542c --- /dev/null +++ b/include/linux/plist.h @@ -0,0 +1,247 @@ +/* + * Descending-priority-sorted double-linked list + * + * (C) 2002-2003 Intel Corp + * Inaky Perez-Gonzalez . + * + * 2001-2005 (c) MontaVista Software, Inc. + * Daniel Walker + * + * (C) 2005 Thomas Gleixner + * + * Simplifications of the original code by + * Oleg Nesterov + * + * Licensed under the FSF's GNU Public License v2 or later. + * + * Based on simple lists (include/linux/list.h). + * + * This is a priority-sorted list of nodes; each node has a + * priority from INT_MIN (highest) to INT_MAX (lowest). + * + * Addition is O(K), removal is O(1), change of priority of a node is + * O(K) and K is the number of RT priority levels used in the system. + * (1 <= K <= 99) + * + * This list is really a list of lists: + * + * - The tier 1 list is the prio_list, different priority nodes. + * + * - The tier 2 list is the node_list, serialized nodes. + * + * Simple ASCII art explanation: + * + * |HEAD | + * | | + * |prio_list.prev|<------------------------------------| + * |prio_list.next|<->|pl|<->|pl|<--------------->|pl|<-| + * |10 | |10| |21| |21| |21| |40| (prio) + * | | | | | | | | | | | | + * | | | | | | | | | | | | + * |node_list.next|<->|nl|<->|nl|<->|nl|<->|nl|<->|nl|<-| + * |node_list.prev|<------------------------------------| + * + * The nodes on the prio_list list are sorted by priority to simplify + * the insertion of new nodes. There are no nodes with duplicate + * priorites on the list. + * + * The nodes on the node_list is ordered by priority and can contain + * entries which have the same priority. Those entries are ordered + * FIFO + * + * Addition means: look for the prio_list node in the prio_list + * for the priority of the node and insert it before the node_list + * entry of the next prio_list node. If it is the first node of + * that priority, add it to the prio_list in the right position and + * insert it into the serialized node_list list + * + * Removal means remove it from the node_list and remove it from + * the prio_list if the node_list list_head is non empty. In case + * of removal from the prio_list it must be checked whether other + * entries of the same priority are on the list or not. If there + * is another entry of the same priority then this entry has to + * replace the removed entry on the prio_list. If the entry which + * is removed is the only entry of this priority then a simple + * remove from both list is sufficient. + * + * INT_MIN is the highest priority, 0 is the medium highest, INT_MAX + * is lowest priority. + * + * No locking is done, up to the caller. + * + */ +#ifndef _LINUX_PLIST_H_ +#define _LINUX_PLIST_H_ + +#include +#include + +struct plist_head { + struct list_head prio_list; + struct list_head node_list; +#ifdef CONFIG_DEBUG_PI_LIST + spinlock_t *lock; +#endif +}; + +struct plist_node { + int prio; + struct plist_head plist; +}; + +#ifdef CONFIG_DEBUG_PI_LIST +# define PLIST_HEAD_LOCK_INIT(_lock) .lock = _lock +#else +# define PLIST_HEAD_LOCK_INIT(_lock) +#endif + +/** + * #PLIST_HEAD_INIT - static struct plist_head initializer + * + * @head: struct plist_head variable name + */ +#define PLIST_HEAD_INIT(head, _lock) \ +{ \ + .prio_list = LIST_HEAD_INIT((head).prio_list), \ + .node_list = LIST_HEAD_INIT((head).node_list), \ + PLIST_HEAD_LOCK_INIT(&(_lock)) \ +} + +/** + * #PLIST_NODE_INIT - static struct plist_node initializer + * + * @node: struct plist_node variable name + * @__prio: initial node priority + */ +#define PLIST_NODE_INIT(node, __prio) \ +{ \ + .prio = (__prio), \ + .plist = PLIST_HEAD_INIT((node).plist, NULL), \ +} + +/** + * plist_head_init - dynamic struct plist_head initializer + * + * @head: &struct plist_head pointer + */ +static inline void +plist_head_init(struct plist_head *head, spinlock_t *lock) +{ + INIT_LIST_HEAD(&head->prio_list); + INIT_LIST_HEAD(&head->node_list); +#ifdef CONFIG_DEBUG_PI_LIST + head->lock = lock; +#endif +} + +/** + * plist_node_init - Dynamic struct plist_node initializer + * + * @node: &struct plist_node pointer + * @prio: initial node priority + */ +static inline void plist_node_init(struct plist_node *node, int prio) +{ + node->prio = prio; + plist_head_init(&node->plist, NULL); +} + +extern void plist_add(struct plist_node *node, struct plist_head *head); +extern void plist_del(struct plist_node *node, struct plist_head *head); + +/** + * plist_for_each - iterate over the plist + * + * @pos1: the type * to use as a loop counter. + * @head: the head for your list. + */ +#define plist_for_each(pos, head) \ + list_for_each_entry(pos, &(head)->node_list, plist.node_list) + +/** + * plist_for_each_entry_safe - iterate over a plist of given type safe + * against removal of list entry + * + * @pos1: the type * to use as a loop counter. + * @n1: another type * to use as temporary storage + * @head: the head for your list. + */ +#define plist_for_each_safe(pos, n, head) \ + list_for_each_entry_safe(pos, n, &(head)->node_list, plist.node_list) + +/** + * plist_for_each_entry - iterate over list of given type + * + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define plist_for_each_entry(pos, head, mem) \ + list_for_each_entry(pos, &(head)->node_list, mem.plist.node_list) + +/** + * plist_for_each_entry_safe - iterate over list of given type safe against + * removal of list entry + * + * @pos: the type * to use as a loop counter. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @m: the name of the list_struct within the struct. + */ +#define plist_for_each_entry_safe(pos, n, head, m) \ + list_for_each_entry_safe(pos, n, &(head)->node_list, m.plist.node_list) + +/** + * plist_head_empty - return !0 if a plist_head is empty + * + * @head: &struct plist_head pointer + */ +static inline int plist_head_empty(const struct plist_head *head) +{ + return list_empty(&head->node_list); +} + +/** + * plist_node_empty - return !0 if plist_node is not on a list + * + * @node: &struct plist_node pointer + */ +static inline int plist_node_empty(const struct plist_node *node) +{ + return plist_head_empty(&node->plist); +} + +/* All functions below assume the plist_head is not empty. */ + +/** + * plist_first_entry - get the struct for the first entry + * + * @ptr: the &struct plist_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#ifdef CONFIG_DEBUG_PI_LIST +# define plist_first_entry(head, type, member) \ +({ \ + WARN_ON(plist_head_empty(head)); \ + container_of(plist_first(head), type, member); \ +}) +#else +# define plist_first_entry(head, type, member) \ + container_of(plist_first(head), type, member) +#endif + +/** + * plist_first - return the first node (and thus, highest priority) + * + * @head: the &struct plist_head pointer + * + * Assumes the plist is _not_ empty. + */ +static inline struct plist_node* plist_first(const struct plist_head *head) +{ + return list_entry(head->node_list.next, + struct plist_node, plist.node_list); +} + +#endif diff --git a/lib/Kconfig b/lib/Kconfig index 3de93357f5ab..f6299342b882 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -86,4 +86,10 @@ config TEXTSEARCH_BM config TEXTSEARCH_FSM tristate +# +# plist support is select#ed if needed +# +config PLIST + boolean + endmenu diff --git a/lib/Makefile b/lib/Makefile index 79358ad1f113..10c13c9d7824 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -25,6 +25,7 @@ lib-$(CONFIG_SEMAPHORE_SLEEPERS) += semaphore-sleepers.o lib-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o lib-$(CONFIG_GENERIC_HWEIGHT) += hweight.o obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o +obj-$(CONFIG_PLIST) += plist.o obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o ifneq ($(CONFIG_HAVE_DEC_LOCK),y) diff --git a/lib/plist.c b/lib/plist.c new file mode 100644 index 000000000000..3074a02272f3 --- /dev/null +++ b/lib/plist.c @@ -0,0 +1,118 @@ +/* + * lib/plist.c + * + * Descending-priority-sorted double-linked list + * + * (C) 2002-2003 Intel Corp + * Inaky Perez-Gonzalez . + * + * 2001-2005 (c) MontaVista Software, Inc. + * Daniel Walker + * + * (C) 2005 Thomas Gleixner + * + * Simplifications of the original code by + * Oleg Nesterov + * + * Licensed under the FSF's GNU Public License v2 or later. + * + * Based on simple lists (include/linux/list.h). + * + * This file contains the add / del functions which are considered to + * be too large to inline. See include/linux/plist.h for further + * information. + */ + +#include +#include + +#ifdef CONFIG_DEBUG_PI_LIST + +static void plist_check_prev_next(struct list_head *t, struct list_head *p, + struct list_head *n) +{ + if (n->prev != p || p->next != n) { + printk("top: %p, n: %p, p: %p\n", t, t->next, t->prev); + printk("prev: %p, n: %p, p: %p\n", p, p->next, p->prev); + printk("next: %p, n: %p, p: %p\n", n, n->next, n->prev); + WARN_ON(1); + } +} + +static void plist_check_list(struct list_head *top) +{ + struct list_head *prev = top, *next = top->next; + + plist_check_prev_next(top, prev, next); + while (next != top) { + prev = next; + next = prev->next; + plist_check_prev_next(top, prev, next); + } +} + +static void plist_check_head(struct plist_head *head) +{ + WARN_ON(!head->lock); + if (head->lock) + WARN_ON_SMP(!spin_is_locked(head->lock)); + plist_check_list(&head->prio_list); + plist_check_list(&head->node_list); +} + +#else +# define plist_check_head(h) do { } while (0) +#endif + +/** + * plist_add - add @node to @head + * + * @node: &struct plist_node pointer + * @head: &struct plist_head pointer + */ +void plist_add(struct plist_node *node, struct plist_head *head) +{ + struct plist_node *iter; + + plist_check_head(head); + WARN_ON(!plist_node_empty(node)); + + list_for_each_entry(iter, &head->prio_list, plist.prio_list) { + if (node->prio < iter->prio) + goto lt_prio; + else if (node->prio == iter->prio) { + iter = list_entry(iter->plist.prio_list.next, + struct plist_node, plist.prio_list); + goto eq_prio; + } + } + +lt_prio: + list_add_tail(&node->plist.prio_list, &iter->plist.prio_list); +eq_prio: + list_add_tail(&node->plist.node_list, &iter->plist.node_list); + + plist_check_head(head); +} + +/** + * plist_del - Remove a @node from plist. + * + * @node: &struct plist_node pointer - entry to be removed + * @head: &struct plist_head pointer - list head + */ +void plist_del(struct plist_node *node, struct plist_head *head) +{ + plist_check_head(head); + + if (!list_empty(&node->plist.prio_list)) { + struct plist_node *next = plist_first(&node->plist); + + list_move_tail(&next->plist.prio_list, &node->plist.prio_list); + list_del_init(&node->plist.prio_list); + } + + list_del_init(&node->plist.node_list); + + plist_check_head(head); +} -- cgit v1.2.3 From e7eebaf6a81b956c989f184ee4b27277c88f8afe Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Tue, 27 Jun 2006 02:54:55 -0700 Subject: [PATCH] pi-futex: rt mutex debug Runtime debugging functionality for rt-mutexes. Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner Signed-off-by: Arjan van de Ven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mm.h | 1 + include/linux/rtmutex.h | 15 +- kernel/Makefile | 1 + kernel/exit.c | 1 + kernel/rtmutex-debug.c | 513 ++++++++++++++++++++++++++++++++++++++++++++++++ kernel/rtmutex-debug.h | 37 ++++ lib/Kconfig.debug | 13 ++ mm/slab.c | 1 + 8 files changed, 581 insertions(+), 1 deletion(-) create mode 100644 kernel/rtmutex-debug.c create mode 100644 kernel/rtmutex-debug.h (limited to 'lib') diff --git a/include/linux/mm.h b/include/linux/mm.h index 0ac255720f34..c41a1299b8cf 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1034,6 +1034,7 @@ static inline void debug_check_no_locks_freed(const void *from, unsigned long len) { mutex_debug_check_no_locks_freed(from, len); + rt_mutex_debug_check_no_locks_freed(from, len); } #ifndef CONFIG_DEBUG_PAGEALLOC diff --git a/include/linux/rtmutex.h b/include/linux/rtmutex.h index 12309c916c68..fa4a3b82ba70 100644 --- a/include/linux/rtmutex.h +++ b/include/linux/rtmutex.h @@ -40,6 +40,19 @@ struct rt_mutex { struct rt_mutex_waiter; struct hrtimer_sleeper; +#ifdef CONFIG_DEBUG_RT_MUTEXES + extern int rt_mutex_debug_check_no_locks_freed(const void *from, + unsigned long len); + extern void rt_mutex_debug_check_no_locks_held(struct task_struct *task); +#else + static inline int rt_mutex_debug_check_no_locks_freed(const void *from, + unsigned long len) + { + return 0; + } +# define rt_mutex_debug_check_no_locks_held(task) do { } while (0) +#endif + #ifdef CONFIG_DEBUG_RT_MUTEXES # define __DEBUG_RT_MUTEX_INITIALIZER(mutexname) \ , .name = #mutexname, .file = __FILE__, .line = __LINE__ @@ -48,7 +61,7 @@ struct hrtimer_sleeper; #else # define __DEBUG_RT_MUTEX_INITIALIZER(mutexname) # define rt_mutex_init(mutex) __rt_mutex_init(mutex, NULL) -# define rt_mutex_debug_task_free(t) do { } while (0) +# define rt_mutex_debug_task_free(t) do { } while (0) #endif #define __RT_MUTEX_INITIALIZER(mutexname) \ diff --git a/kernel/Makefile b/kernel/Makefile index 21df9a338ff0..f9c92d34cde5 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -17,6 +17,7 @@ ifeq ($(CONFIG_COMPAT),y) obj-$(CONFIG_FUTEX) += futex_compat.o endif obj-$(CONFIG_RT_MUTEXES) += rtmutex.o +obj-$(CONFIG_DEBUG_RT_MUTEXES) += rtmutex-debug.o obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o obj-$(CONFIG_SMP) += cpu.o spinlock.o obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o diff --git a/kernel/exit.c b/kernel/exit.c index 304ef637be6c..3e8a0282e9a5 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -929,6 +929,7 @@ fastcall NORET_TYPE void do_exit(long code) * If DEBUG_MUTEXES is on, make sure we are holding no locks: */ mutex_debug_check_no_locks_held(tsk); + rt_mutex_debug_check_no_locks_held(tsk); if (tsk->io_context) exit_io_context(); diff --git a/kernel/rtmutex-debug.c b/kernel/rtmutex-debug.c new file mode 100644 index 000000000000..4aa8a2c9f453 --- /dev/null +++ b/kernel/rtmutex-debug.c @@ -0,0 +1,513 @@ +/* + * RT-Mutexes: blocking mutual exclusion locks with PI support + * + * started by Ingo Molnar and Thomas Gleixner: + * + * Copyright (C) 2004-2006 Red Hat, Inc., Ingo Molnar + * Copyright (C) 2006 Timesys Corp., Thomas Gleixner + * + * This code is based on the rt.c implementation in the preempt-rt tree. + * Portions of said code are + * + * Copyright (C) 2004 LynuxWorks, Inc., Igor Manyilov, Bill Huey + * Copyright (C) 2006 Esben Nielsen + * Copyright (C) 2006 Kihon Technologies Inc., + * Steven Rostedt + * + * See rt.c in preempt-rt for proper credits and further information + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rtmutex_common.h" + +#ifdef CONFIG_DEBUG_RT_MUTEXES +# include "rtmutex-debug.h" +#else +# include "rtmutex.h" +#endif + +# define TRACE_WARN_ON(x) WARN_ON(x) +# define TRACE_BUG_ON(x) BUG_ON(x) + +# define TRACE_OFF() \ +do { \ + if (rt_trace_on) { \ + rt_trace_on = 0; \ + console_verbose(); \ + if (spin_is_locked(¤t->pi_lock)) \ + spin_unlock(¤t->pi_lock); \ + if (spin_is_locked(¤t->held_list_lock)) \ + spin_unlock(¤t->held_list_lock); \ + } \ +} while (0) + +# define TRACE_OFF_NOLOCK() \ +do { \ + if (rt_trace_on) { \ + rt_trace_on = 0; \ + console_verbose(); \ + } \ +} while (0) + +# define TRACE_BUG_LOCKED() \ +do { \ + TRACE_OFF(); \ + BUG(); \ +} while (0) + +# define TRACE_WARN_ON_LOCKED(c) \ +do { \ + if (unlikely(c)) { \ + TRACE_OFF(); \ + WARN_ON(1); \ + } \ +} while (0) + +# define TRACE_BUG_ON_LOCKED(c) \ +do { \ + if (unlikely(c)) \ + TRACE_BUG_LOCKED(); \ +} while (0) + +#ifdef CONFIG_SMP +# define SMP_TRACE_BUG_ON_LOCKED(c) TRACE_BUG_ON_LOCKED(c) +#else +# define SMP_TRACE_BUG_ON_LOCKED(c) do { } while (0) +#endif + +/* + * deadlock detection flag. We turn it off when we detect + * the first problem because we dont want to recurse back + * into the tracing code when doing error printk or + * executing a BUG(): + */ +int rt_trace_on = 1; + +void deadlock_trace_off(void) +{ + rt_trace_on = 0; +} + +static void printk_task(task_t *p) +{ + if (p) + printk("%16s:%5d [%p, %3d]", p->comm, p->pid, p, p->prio); + else + printk(""); +} + +static void printk_task_short(task_t *p) +{ + if (p) + printk("%s/%d [%p, %3d]", p->comm, p->pid, p, p->prio); + else + printk(""); +} + +static void printk_lock(struct rt_mutex *lock, int print_owner) +{ + if (lock->name) + printk(" [%p] {%s}\n", + lock, lock->name); + else + printk(" [%p] {%s:%d}\n", + lock, lock->file, lock->line); + + if (print_owner && rt_mutex_owner(lock)) { + printk(".. ->owner: %p\n", lock->owner); + printk(".. held by: "); + printk_task(rt_mutex_owner(lock)); + printk("\n"); + } + if (rt_mutex_owner(lock)) { + printk("... acquired at: "); + print_symbol("%s\n", lock->acquire_ip); + } +} + +static void printk_waiter(struct rt_mutex_waiter *w) +{ + printk("-------------------------\n"); + printk("| waiter struct %p:\n", w); + printk("| w->list_entry: [DP:%p/%p|SP:%p/%p|PRI:%d]\n", + w->list_entry.plist.prio_list.prev, w->list_entry.plist.prio_list.next, + w->list_entry.plist.node_list.prev, w->list_entry.plist.node_list.next, + w->list_entry.prio); + printk("| w->pi_list_entry: [DP:%p/%p|SP:%p/%p|PRI:%d]\n", + w->pi_list_entry.plist.prio_list.prev, w->pi_list_entry.plist.prio_list.next, + w->pi_list_entry.plist.node_list.prev, w->pi_list_entry.plist.node_list.next, + w->pi_list_entry.prio); + printk("\n| lock:\n"); + printk_lock(w->lock, 1); + printk("| w->ti->task:\n"); + printk_task(w->task); + printk("| blocked at: "); + print_symbol("%s\n", w->ip); + printk("-------------------------\n"); +} + +static void show_task_locks(task_t *p) +{ + switch (p->state) { + case TASK_RUNNING: printk("R"); break; + case TASK_INTERRUPTIBLE: printk("S"); break; + case TASK_UNINTERRUPTIBLE: printk("D"); break; + case TASK_STOPPED: printk("T"); break; + case EXIT_ZOMBIE: printk("Z"); break; + case EXIT_DEAD: printk("X"); break; + default: printk("?"); break; + } + printk_task(p); + if (p->pi_blocked_on) { + struct rt_mutex *lock = p->pi_blocked_on->lock; + + printk(" blocked on:"); + printk_lock(lock, 1); + } else + printk(" (not blocked)\n"); +} + +void rt_mutex_show_held_locks(task_t *task, int verbose) +{ + struct list_head *curr, *cursor = NULL; + struct rt_mutex *lock; + task_t *t; + unsigned long flags; + int count = 0; + + if (!rt_trace_on) + return; + + if (verbose) { + printk("------------------------------\n"); + printk("| showing all locks held by: | ("); + printk_task_short(task); + printk("):\n"); + printk("------------------------------\n"); + } + +next: + spin_lock_irqsave(&task->held_list_lock, flags); + list_for_each(curr, &task->held_list_head) { + if (cursor && curr != cursor) + continue; + lock = list_entry(curr, struct rt_mutex, held_list_entry); + t = rt_mutex_owner(lock); + WARN_ON(t != task); + count++; + cursor = curr->next; + spin_unlock_irqrestore(&task->held_list_lock, flags); + + printk("\n#%03d: ", count); + printk_lock(lock, 0); + goto next; + } + spin_unlock_irqrestore(&task->held_list_lock, flags); + + printk("\n"); +} + +void rt_mutex_show_all_locks(void) +{ + task_t *g, *p; + int count = 10; + int unlock = 1; + + printk("\n"); + printk("----------------------\n"); + printk("| showing all tasks: |\n"); + printk("----------------------\n"); + + /* + * Here we try to get the tasklist_lock as hard as possible, + * if not successful after 2 seconds we ignore it (but keep + * trying). This is to enable a debug printout even if a + * tasklist_lock-holding task deadlocks or crashes. + */ +retry: + if (!read_trylock(&tasklist_lock)) { + if (count == 10) + printk("hm, tasklist_lock locked, retrying... "); + if (count) { + count--; + printk(" #%d", 10-count); + mdelay(200); + goto retry; + } + printk(" ignoring it.\n"); + unlock = 0; + } + if (count != 10) + printk(" locked it.\n"); + + do_each_thread(g, p) { + show_task_locks(p); + if (!unlock) + if (read_trylock(&tasklist_lock)) + unlock = 1; + } while_each_thread(g, p); + + printk("\n"); + + printk("-----------------------------------------\n"); + printk("| showing all locks held in the system: |\n"); + printk("-----------------------------------------\n"); + + do_each_thread(g, p) { + rt_mutex_show_held_locks(p, 0); + if (!unlock) + if (read_trylock(&tasklist_lock)) + unlock = 1; + } while_each_thread(g, p); + + + printk("=============================================\n\n"); + + if (unlock) + read_unlock(&tasklist_lock); +} + +void rt_mutex_debug_check_no_locks_held(task_t *task) +{ + struct rt_mutex_waiter *w; + struct list_head *curr; + struct rt_mutex *lock; + + if (!rt_trace_on) + return; + if (!rt_prio(task->normal_prio) && rt_prio(task->prio)) { + printk("BUG: PI priority boost leaked!\n"); + printk_task(task); + printk("\n"); + } + if (list_empty(&task->held_list_head)) + return; + + spin_lock(&task->pi_lock); + plist_for_each_entry(w, &task->pi_waiters, pi_list_entry) { + TRACE_OFF(); + + printk("hm, PI interest held at exit time? Task:\n"); + printk_task(task); + printk_waiter(w); + return; + } + spin_unlock(&task->pi_lock); + + list_for_each(curr, &task->held_list_head) { + lock = list_entry(curr, struct rt_mutex, held_list_entry); + + printk("BUG: %s/%d, lock held at task exit time!\n", + task->comm, task->pid); + printk_lock(lock, 1); + if (rt_mutex_owner(lock) != task) + printk("exiting task is not even the owner??\n"); + } +} + +int rt_mutex_debug_check_no_locks_freed(const void *from, unsigned long len) +{ + const void *to = from + len; + struct list_head *curr; + struct rt_mutex *lock; + unsigned long flags; + void *lock_addr; + + if (!rt_trace_on) + return 0; + + spin_lock_irqsave(¤t->held_list_lock, flags); + list_for_each(curr, ¤t->held_list_head) { + lock = list_entry(curr, struct rt_mutex, held_list_entry); + lock_addr = lock; + if (lock_addr < from || lock_addr >= to) + continue; + TRACE_OFF(); + + printk("BUG: %s/%d, active lock [%p(%p-%p)] freed!\n", + current->comm, current->pid, lock, from, to); + dump_stack(); + printk_lock(lock, 1); + if (rt_mutex_owner(lock) != current) + printk("freeing task is not even the owner??\n"); + return 1; + } + spin_unlock_irqrestore(¤t->held_list_lock, flags); + + return 0; +} + +void rt_mutex_debug_task_free(struct task_struct *task) +{ + WARN_ON(!plist_head_empty(&task->pi_waiters)); + WARN_ON(task->pi_blocked_on); +} + +/* + * We fill out the fields in the waiter to store the information about + * the deadlock. We print when we return. act_waiter can be NULL in + * case of a remove waiter operation. + */ +void debug_rt_mutex_deadlock(int detect, struct rt_mutex_waiter *act_waiter, + struct rt_mutex *lock) +{ + struct task_struct *task; + + if (!rt_trace_on || detect || !act_waiter) + return; + + task = rt_mutex_owner(act_waiter->lock); + if (task && task != current) { + act_waiter->deadlock_task_pid = task->pid; + act_waiter->deadlock_lock = lock; + } +} + +void debug_rt_mutex_print_deadlock(struct rt_mutex_waiter *waiter) +{ + struct task_struct *task; + + if (!waiter->deadlock_lock || !rt_trace_on) + return; + + task = find_task_by_pid(waiter->deadlock_task_pid); + if (!task) + return; + + TRACE_OFF_NOLOCK(); + + printk("\n============================================\n"); + printk( "[ BUG: circular locking deadlock detected! ]\n"); + printk( "--------------------------------------------\n"); + printk("%s/%d is deadlocking current task %s/%d\n\n", + task->comm, task->pid, current->comm, current->pid); + + printk("\n1) %s/%d is trying to acquire this lock:\n", + current->comm, current->pid); + printk_lock(waiter->lock, 1); + + printk("... trying at: "); + print_symbol("%s\n", waiter->ip); + + printk("\n2) %s/%d is blocked on this lock:\n", task->comm, task->pid); + printk_lock(waiter->deadlock_lock, 1); + + rt_mutex_show_held_locks(current, 1); + rt_mutex_show_held_locks(task, 1); + + printk("\n%s/%d's [blocked] stackdump:\n\n", task->comm, task->pid); + show_stack(task, NULL); + printk("\n%s/%d's [current] stackdump:\n\n", + current->comm, current->pid); + dump_stack(); + rt_mutex_show_all_locks(); + printk("[ turning off deadlock detection." + "Please report this trace. ]\n\n"); + local_irq_disable(); +} + +void debug_rt_mutex_lock(struct rt_mutex *lock __IP_DECL__) +{ + unsigned long flags; + + if (rt_trace_on) { + TRACE_WARN_ON_LOCKED(!list_empty(&lock->held_list_entry)); + + spin_lock_irqsave(¤t->held_list_lock, flags); + list_add_tail(&lock->held_list_entry, ¤t->held_list_head); + spin_unlock_irqrestore(¤t->held_list_lock, flags); + + lock->acquire_ip = ip; + } +} + +void debug_rt_mutex_unlock(struct rt_mutex *lock) +{ + unsigned long flags; + + if (rt_trace_on) { + TRACE_WARN_ON_LOCKED(rt_mutex_owner(lock) != current); + TRACE_WARN_ON_LOCKED(list_empty(&lock->held_list_entry)); + + spin_lock_irqsave(¤t->held_list_lock, flags); + list_del_init(&lock->held_list_entry); + spin_unlock_irqrestore(¤t->held_list_lock, flags); + } +} + +void debug_rt_mutex_proxy_lock(struct rt_mutex *lock, + struct task_struct *powner __IP_DECL__) +{ + unsigned long flags; + + if (rt_trace_on) { + TRACE_WARN_ON_LOCKED(!list_empty(&lock->held_list_entry)); + + spin_lock_irqsave(&powner->held_list_lock, flags); + list_add_tail(&lock->held_list_entry, &powner->held_list_head); + spin_unlock_irqrestore(&powner->held_list_lock, flags); + + lock->acquire_ip = ip; + } +} + +void debug_rt_mutex_proxy_unlock(struct rt_mutex *lock) +{ + unsigned long flags; + + if (rt_trace_on) { + struct task_struct *owner = rt_mutex_owner(lock); + + TRACE_WARN_ON_LOCKED(!owner); + TRACE_WARN_ON_LOCKED(list_empty(&lock->held_list_entry)); + + spin_lock_irqsave(&owner->held_list_lock, flags); + list_del_init(&lock->held_list_entry); + spin_unlock_irqrestore(&owner->held_list_lock, flags); + } +} + +void debug_rt_mutex_init_waiter(struct rt_mutex_waiter *waiter) +{ + memset(waiter, 0x11, sizeof(*waiter)); + plist_node_init(&waiter->list_entry, MAX_PRIO); + plist_node_init(&waiter->pi_list_entry, MAX_PRIO); +} + +void debug_rt_mutex_free_waiter(struct rt_mutex_waiter *waiter) +{ + TRACE_WARN_ON(!plist_node_empty(&waiter->list_entry)); + TRACE_WARN_ON(!plist_node_empty(&waiter->pi_list_entry)); + TRACE_WARN_ON(waiter->task); + memset(waiter, 0x22, sizeof(*waiter)); +} + +void debug_rt_mutex_init(struct rt_mutex *lock, const char *name) +{ + void *addr = lock; + + if (rt_trace_on) { + rt_mutex_debug_check_no_locks_freed(addr, + sizeof(struct rt_mutex)); + INIT_LIST_HEAD(&lock->held_list_entry); + lock->name = name; + } +} + +void rt_mutex_deadlock_account_lock(struct rt_mutex *lock, task_t *task) +{ +} + +void rt_mutex_deadlock_account_unlock(struct task_struct *task) +{ +} + diff --git a/kernel/rtmutex-debug.h b/kernel/rtmutex-debug.h new file mode 100644 index 000000000000..7612fbc62d70 --- /dev/null +++ b/kernel/rtmutex-debug.h @@ -0,0 +1,37 @@ +/* + * RT-Mutexes: blocking mutual exclusion locks with PI support + * + * started by Ingo Molnar and Thomas Gleixner: + * + * Copyright (C) 2004-2006 Red Hat, Inc., Ingo Molnar + * Copyright (C) 2006, Timesys Corp., Thomas Gleixner + * + * This file contains macros used solely by rtmutex.c. Debug version. + */ + +#define __IP_DECL__ , unsigned long ip +#define __IP__ , ip +#define __RET_IP__ , (unsigned long)__builtin_return_address(0) + +extern void +rt_mutex_deadlock_account_lock(struct rt_mutex *lock, struct task_struct *task); +extern void rt_mutex_deadlock_account_unlock(struct task_struct *task); +extern void debug_rt_mutex_init_waiter(struct rt_mutex_waiter *waiter); +extern void debug_rt_mutex_free_waiter(struct rt_mutex_waiter *waiter); +extern void debug_rt_mutex_init(struct rt_mutex *lock, const char *name); +extern void debug_rt_mutex_lock(struct rt_mutex *lock __IP_DECL__); +extern void debug_rt_mutex_unlock(struct rt_mutex *lock); +extern void debug_rt_mutex_proxy_lock(struct rt_mutex *lock, + struct task_struct *powner __IP_DECL__); +extern void debug_rt_mutex_proxy_unlock(struct rt_mutex *lock); +extern void debug_rt_mutex_deadlock(int detect, struct rt_mutex_waiter *waiter, + struct rt_mutex *lock); +extern void debug_rt_mutex_print_deadlock(struct rt_mutex_waiter *waiter); +# define debug_rt_mutex_reset_waiter(w) \ + do { (w)->deadlock_lock = NULL; } while (0) + +static inline int debug_rt_mutex_detect_deadlock(struct rt_mutex_waiter *waiter, + int detect) +{ + return (waiter != NULL); +} diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 8bab0102ac73..06d3ea1133c9 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -107,6 +107,19 @@ config DEBUG_MUTEXES This allows mutex semantics violations and mutex related deadlocks (lockups) to be detected and reported automatically. +config DEBUG_RT_MUTEXES + bool "RT Mutex debugging, deadlock detection" + default y + depends on DEBUG_KERNEL && RT_MUTEXES + help + This allows rt mutex semantics violations and rt mutex related + deadlocks (lockups) to be detected and reported automatically. + +config DEBUG_PI_LIST + bool + default y + depends on DEBUG_RT_MUTEXES + config DEBUG_SPINLOCK bool "Spinlock debugging" depends on DEBUG_KERNEL diff --git a/mm/slab.c b/mm/slab.c index f378d027c684..233e39d14caf 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -107,6 +107,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3 From 61a87122869b6340a63b6f9f84097d3688604b90 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 27 Jun 2006 02:54:56 -0700 Subject: [PATCH] pi-futex: rt mutex tester RT-mutex tester: scriptable tester for rt mutexes, which allows userspace scripting of mutex unit-tests (and dynamic tests as well), using the actual rt-mutex implementation of the kernel. [akpm@osdl.org: fixlet] Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sched.h | 1 + kernel/Makefile | 1 + kernel/rtmutex-tester.c | 436 +++++++++++++++++++++++++++ kernel/rtmutex.c | 3 +- kernel/rtmutex_common.h | 22 ++ lib/Kconfig.debug | 7 + scripts/rt-tester/check-all.sh | 21 ++ scripts/rt-tester/rt-tester.py | 222 ++++++++++++++ scripts/rt-tester/t2-l1-2rt-sameprio.tst | 101 +++++++ scripts/rt-tester/t2-l1-pi.tst | 84 ++++++ scripts/rt-tester/t2-l1-signal.tst | 79 +++++ scripts/rt-tester/t2-l2-2rt-deadlock.tst | 91 ++++++ scripts/rt-tester/t3-l1-pi-1rt.tst | 95 ++++++ scripts/rt-tester/t3-l1-pi-2rt.tst | 96 ++++++ scripts/rt-tester/t3-l1-pi-3rt.tst | 95 ++++++ scripts/rt-tester/t3-l1-pi-signal.tst | 101 +++++++ scripts/rt-tester/t3-l1-pi-steal.tst | 99 ++++++ scripts/rt-tester/t3-l2-pi.tst | 95 ++++++ scripts/rt-tester/t4-l2-pi-deboost.tst | 127 ++++++++ scripts/rt-tester/t5-l4-pi-boost-deboost.tst | 148 +++++++++ 20 files changed, 1923 insertions(+), 1 deletion(-) create mode 100644 kernel/rtmutex-tester.c create mode 100644 scripts/rt-tester/check-all.sh create mode 100644 scripts/rt-tester/rt-tester.py create mode 100644 scripts/rt-tester/t2-l1-2rt-sameprio.tst create mode 100644 scripts/rt-tester/t2-l1-pi.tst create mode 100644 scripts/rt-tester/t2-l1-signal.tst create mode 100644 scripts/rt-tester/t2-l2-2rt-deadlock.tst create mode 100644 scripts/rt-tester/t3-l1-pi-1rt.tst create mode 100644 scripts/rt-tester/t3-l1-pi-2rt.tst create mode 100644 scripts/rt-tester/t3-l1-pi-3rt.tst create mode 100644 scripts/rt-tester/t3-l1-pi-signal.tst create mode 100644 scripts/rt-tester/t3-l1-pi-steal.tst create mode 100644 scripts/rt-tester/t3-l2-pi.tst create mode 100644 scripts/rt-tester/t4-l2-pi-deboost.tst create mode 100644 scripts/rt-tester/t5-l4-pi-boost-deboost.tst (limited to 'lib') diff --git a/include/linux/sched.h b/include/linux/sched.h index 6ea23c9af413..edadd13cf53f 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -982,6 +982,7 @@ static inline void put_task_struct(struct task_struct *t) #define PF_SPREAD_PAGE 0x01000000 /* Spread page cache over cpuset */ #define PF_SPREAD_SLAB 0x02000000 /* Spread some slab caches over cpuset */ #define PF_MEMPOLICY 0x10000000 /* Non-default NUMA mempolicy */ +#define PF_MUTEX_TESTER 0x20000000 /* Thread belongs to the rt mutex tester */ /* * Only the _current_ task can read/write to tsk->flags, but other diff --git a/kernel/Makefile b/kernel/Makefile index f9c92d34cde5..82fb182f6f61 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_FUTEX) += futex_compat.o endif obj-$(CONFIG_RT_MUTEXES) += rtmutex.o obj-$(CONFIG_DEBUG_RT_MUTEXES) += rtmutex-debug.o +obj-$(CONFIG_RT_MUTEX_TESTER) += rtmutex-tester.o obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o obj-$(CONFIG_SMP) += cpu.o spinlock.o obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o diff --git a/kernel/rtmutex-tester.c b/kernel/rtmutex-tester.c new file mode 100644 index 000000000000..fe211ba3a5b5 --- /dev/null +++ b/kernel/rtmutex-tester.c @@ -0,0 +1,436 @@ +/* + * RT-Mutex-tester: scriptable tester for rt mutexes + * + * started by Thomas Gleixner: + * + * Copyright (C) 2006, Timesys Corp., Thomas Gleixner + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rtmutex.h" + +#define MAX_RT_TEST_THREADS 8 +#define MAX_RT_TEST_MUTEXES 8 + +static spinlock_t rttest_lock; +static atomic_t rttest_event; + +struct test_thread_data { + int opcode; + int opdata; + int mutexes[MAX_RT_TEST_MUTEXES]; + int bkl; + int event; + struct sys_device sysdev; +}; + +static struct test_thread_data thread_data[MAX_RT_TEST_THREADS]; +static task_t *threads[MAX_RT_TEST_THREADS]; +static struct rt_mutex mutexes[MAX_RT_TEST_MUTEXES]; + +enum test_opcodes { + RTTEST_NOP = 0, + RTTEST_SCHEDOT, /* 1 Sched other, data = nice */ + RTTEST_SCHEDRT, /* 2 Sched fifo, data = prio */ + RTTEST_LOCK, /* 3 Lock uninterruptible, data = lockindex */ + RTTEST_LOCKNOWAIT, /* 4 Lock uninterruptible no wait in wakeup, data = lockindex */ + RTTEST_LOCKINT, /* 5 Lock interruptible, data = lockindex */ + RTTEST_LOCKINTNOWAIT, /* 6 Lock interruptible no wait in wakeup, data = lockindex */ + RTTEST_LOCKCONT, /* 7 Continue locking after the wakeup delay */ + RTTEST_UNLOCK, /* 8 Unlock, data = lockindex */ + RTTEST_LOCKBKL, /* 9 Lock BKL */ + RTTEST_UNLOCKBKL, /* 10 Unlock BKL */ + RTTEST_SIGNAL, /* 11 Signal other test thread, data = thread id */ + RTTEST_RESETEVENT = 98, /* 98 Reset event counter */ + RTTEST_RESET = 99, /* 99 Reset all pending operations */ +}; + +static int handle_op(struct test_thread_data *td, int lockwakeup) +{ + struct sched_param schedpar; + int i, id, ret = -EINVAL; + + switch(td->opcode) { + + case RTTEST_NOP: + return 0; + + case RTTEST_SCHEDOT: + schedpar.sched_priority = 0; + ret = sched_setscheduler(current, SCHED_NORMAL, &schedpar); + if (!ret) + set_user_nice(current, 0); + return ret; + + case RTTEST_SCHEDRT: + schedpar.sched_priority = td->opdata; + return sched_setscheduler(current, SCHED_FIFO, &schedpar); + + case RTTEST_LOCKCONT: + td->mutexes[td->opdata] = 1; + td->event = atomic_add_return(1, &rttest_event); + return 0; + + case RTTEST_RESET: + for (i = 0; i < MAX_RT_TEST_MUTEXES; i++) { + if (td->mutexes[i] == 4) { + rt_mutex_unlock(&mutexes[i]); + td->mutexes[i] = 0; + } + } + + if (!lockwakeup && td->bkl == 4) { + unlock_kernel(); + td->bkl = 0; + } + return 0; + + case RTTEST_RESETEVENT: + atomic_set(&rttest_event, 0); + return 0; + + default: + if (lockwakeup) + return ret; + } + + switch(td->opcode) { + + case RTTEST_LOCK: + case RTTEST_LOCKNOWAIT: + id = td->opdata; + if (id < 0 || id >= MAX_RT_TEST_MUTEXES) + return ret; + + td->mutexes[id] = 1; + td->event = atomic_add_return(1, &rttest_event); + rt_mutex_lock(&mutexes[id]); + td->event = atomic_add_return(1, &rttest_event); + td->mutexes[id] = 4; + return 0; + + case RTTEST_LOCKINT: + case RTTEST_LOCKINTNOWAIT: + id = td->opdata; + if (id < 0 || id >= MAX_RT_TEST_MUTEXES) + return ret; + + td->mutexes[id] = 1; + td->event = atomic_add_return(1, &rttest_event); + ret = rt_mutex_lock_interruptible(&mutexes[id], 0); + td->event = atomic_add_return(1, &rttest_event); + td->mutexes[id] = ret ? 0 : 4; + return ret ? -EINTR : 0; + + case RTTEST_UNLOCK: + id = td->opdata; + if (id < 0 || id >= MAX_RT_TEST_MUTEXES || td->mutexes[id] != 4) + return ret; + + td->event = atomic_add_return(1, &rttest_event); + rt_mutex_unlock(&mutexes[id]); + td->event = atomic_add_return(1, &rttest_event); + td->mutexes[id] = 0; + return 0; + + case RTTEST_LOCKBKL: + if (td->bkl) + return 0; + td->bkl = 1; + lock_kernel(); + td->bkl = 4; + return 0; + + case RTTEST_UNLOCKBKL: + if (td->bkl != 4) + break; + unlock_kernel(); + td->bkl = 0; + return 0; + + default: + break; + } + return ret; +} + +/* + * Schedule replacement for rtsem_down(). Only called for threads with + * PF_MUTEX_TESTER set. + * + * This allows us to have finegrained control over the event flow. + * + */ +void schedule_rt_mutex_test(struct rt_mutex *mutex) +{ + int tid, op, dat; + struct test_thread_data *td; + + /* We have to lookup the task */ + for (tid = 0; tid < MAX_RT_TEST_THREADS; tid++) { + if (threads[tid] == current) + break; + } + + BUG_ON(tid == MAX_RT_TEST_THREADS); + + td = &thread_data[tid]; + + op = td->opcode; + dat = td->opdata; + + switch (op) { + case RTTEST_LOCK: + case RTTEST_LOCKINT: + case RTTEST_LOCKNOWAIT: + case RTTEST_LOCKINTNOWAIT: + if (mutex != &mutexes[dat]) + break; + + if (td->mutexes[dat] != 1) + break; + + td->mutexes[dat] = 2; + td->event = atomic_add_return(1, &rttest_event); + break; + + case RTTEST_LOCKBKL: + default: + break; + } + + schedule(); + + + switch (op) { + case RTTEST_LOCK: + case RTTEST_LOCKINT: + if (mutex != &mutexes[dat]) + return; + + if (td->mutexes[dat] != 2) + return; + + td->mutexes[dat] = 3; + td->event = atomic_add_return(1, &rttest_event); + break; + + case RTTEST_LOCKNOWAIT: + case RTTEST_LOCKINTNOWAIT: + if (mutex != &mutexes[dat]) + return; + + if (td->mutexes[dat] != 2) + return; + + td->mutexes[dat] = 1; + td->event = atomic_add_return(1, &rttest_event); + return; + + case RTTEST_LOCKBKL: + return; + default: + return; + } + + td->opcode = 0; + + for (;;) { + set_current_state(TASK_INTERRUPTIBLE); + + if (td->opcode > 0) { + int ret; + + set_current_state(TASK_RUNNING); + ret = handle_op(td, 1); + set_current_state(TASK_INTERRUPTIBLE); + if (td->opcode == RTTEST_LOCKCONT) + break; + td->opcode = ret; + } + + /* Wait for the next command to be executed */ + schedule(); + } + + /* Restore previous command and data */ + td->opcode = op; + td->opdata = dat; +} + +static int test_func(void *data) +{ + struct test_thread_data *td = data; + int ret; + + current->flags |= PF_MUTEX_TESTER; + allow_signal(SIGHUP); + + for(;;) { + + set_current_state(TASK_INTERRUPTIBLE); + + if (td->opcode > 0) { + set_current_state(TASK_RUNNING); + ret = handle_op(td, 0); + set_current_state(TASK_INTERRUPTIBLE); + td->opcode = ret; + } + + /* Wait for the next command to be executed */ + schedule(); + + if (signal_pending(current)) + flush_signals(current); + + if(kthread_should_stop()) + break; + } + return 0; +} + +/** + * sysfs_test_command - interface for test commands + * @dev: thread reference + * @buf: command for actual step + * @count: length of buffer + * + * command syntax: + * + * opcode:data + */ +static ssize_t sysfs_test_command(struct sys_device *dev, const char *buf, + size_t count) +{ + struct test_thread_data *td; + char cmdbuf[32]; + int op, dat, tid; + + td = container_of(dev, struct test_thread_data, sysdev); + tid = td->sysdev.id; + + /* strings from sysfs write are not 0 terminated! */ + if (count >= sizeof(cmdbuf)) + return -EINVAL; + + /* strip of \n: */ + if (buf[count-1] == '\n') + count--; + if (count < 1) + return -EINVAL; + + memcpy(cmdbuf, buf, count); + cmdbuf[count] = 0; + + if (sscanf(cmdbuf, "%d:%d", &op, &dat) != 2) + return -EINVAL; + + switch (op) { + case RTTEST_SIGNAL: + send_sig(SIGHUP, threads[tid], 0); + break; + + default: + if (td->opcode > 0) + return -EBUSY; + td->opdata = dat; + td->opcode = op; + wake_up_process(threads[tid]); + } + + return count; +} + +/** + * sysfs_test_status - sysfs interface for rt tester + * @dev: thread to query + * @buf: char buffer to be filled with thread status info + */ +static ssize_t sysfs_test_status(struct sys_device *dev, char *buf) +{ + struct test_thread_data *td; + char *curr = buf; + task_t *tsk; + int i; + + td = container_of(dev, struct test_thread_data, sysdev); + tsk = threads[td->sysdev.id]; + + spin_lock(&rttest_lock); + + curr += sprintf(curr, + "O: %4d, E:%8d, S: 0x%08lx, P: %4d, N: %4d, B: %p, K: %d, M:", + td->opcode, td->event, tsk->state, + (MAX_RT_PRIO - 1) - tsk->prio, + (MAX_RT_PRIO - 1) - tsk->normal_prio, + tsk->pi_blocked_on, td->bkl); + + for (i = MAX_RT_TEST_MUTEXES - 1; i >=0 ; i--) + curr += sprintf(curr, "%d", td->mutexes[i]); + + spin_unlock(&rttest_lock); + + curr += sprintf(curr, ", T: %p, R: %p\n", tsk, + mutexes[td->sysdev.id].owner); + + return curr - buf; +} + +static SYSDEV_ATTR(status, 0600, sysfs_test_status, NULL); +static SYSDEV_ATTR(command, 0600, NULL, sysfs_test_command); + +static struct sysdev_class rttest_sysclass = { + set_kset_name("rttest"), +}; + +static int init_test_thread(int id) +{ + thread_data[id].sysdev.cls = &rttest_sysclass; + thread_data[id].sysdev.id = id; + + threads[id] = kthread_run(test_func, &thread_data[id], "rt-test-%d", id); + if (IS_ERR(threads[id])) + return PTR_ERR(threads[id]); + + return sysdev_register(&thread_data[id].sysdev); +} + +static int init_rttest(void) +{ + int ret, i; + + spin_lock_init(&rttest_lock); + + for (i = 0; i < MAX_RT_TEST_MUTEXES; i++) + rt_mutex_init(&mutexes[i]); + + ret = sysdev_class_register(&rttest_sysclass); + if (ret) + return ret; + + for (i = 0; i < MAX_RT_TEST_THREADS; i++) { + ret = init_test_thread(i); + if (ret) + break; + ret = sysdev_create_file(&thread_data[i].sysdev, &attr_status); + if (ret) + break; + ret = sysdev_create_file(&thread_data[i].sysdev, &attr_command); + if (ret) + break; + } + + printk("Initializing RT-Tester: %s\n", ret ? "Failed" : "OK" ); + + return ret; +} + +device_initcall(init_rttest); diff --git a/kernel/rtmutex.c b/kernel/rtmutex.c index 937a474fae94..39c8ca0cf526 100644 --- a/kernel/rtmutex.c +++ b/kernel/rtmutex.c @@ -640,7 +640,8 @@ rt_mutex_slowlock(struct rt_mutex *lock, int state, debug_rt_mutex_print_deadlock(&waiter); - schedule(); + if (waiter.task) + schedule_rt_mutex(lock); spin_lock(&lock->wait_lock); set_current_state(state); diff --git a/kernel/rtmutex_common.h b/kernel/rtmutex_common.h index 50eed60eb085..e068024eeffc 100644 --- a/kernel/rtmutex_common.h +++ b/kernel/rtmutex_common.h @@ -14,6 +14,28 @@ #include +/* + * The rtmutex in kernel tester is independent of rtmutex debugging. We + * call schedule_rt_mutex_test() instead of schedule() for the tasks which + * belong to the tester. That way we can delay the wakeup path of those + * threads to provoke lock stealing and testing of complex boosting scenarios. + */ +#ifdef CONFIG_RT_MUTEX_TESTER + +extern void schedule_rt_mutex_test(struct rt_mutex *lock); + +#define schedule_rt_mutex(_lock) \ + do { \ + if (!(current->flags & PF_MUTEX_TESTER)) \ + schedule(); \ + else \ + schedule_rt_mutex_test(_lock); \ + } while (0) + +#else +# define schedule_rt_mutex(_lock) schedule() +#endif + /* * This is the control structure for tasks blocked on a rt_mutex, * which is allocated on the kernel stack on of the blocked task. diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 06d3ea1133c9..6afe0af0a19b 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -120,6 +120,13 @@ config DEBUG_PI_LIST default y depends on DEBUG_RT_MUTEXES +config RT_MUTEX_TESTER + bool "Built-in scriptable tester for rt-mutexes" + depends on RT_MUTEXES + default n + help + This option enables a rt-mutex tester. + config DEBUG_SPINLOCK bool "Spinlock debugging" depends on DEBUG_KERNEL diff --git a/scripts/rt-tester/check-all.sh b/scripts/rt-tester/check-all.sh new file mode 100644 index 000000000000..ac45c3e65a35 --- /dev/null +++ b/scripts/rt-tester/check-all.sh @@ -0,0 +1,21 @@ + + +function testit () +{ + printf "%-30s: " $1 + ./rt-tester.py $1 | grep Pass +} + +testit t2-l1-2rt-sameprio.tst +testit t2-l1-pi.tst +testit t2-l1-signal.tst +#testit t2-l2-2rt-deadlock.tst +testit t3-l1-pi-1rt.tst +testit t3-l1-pi-2rt.tst +testit t3-l1-pi-3rt.tst +testit t3-l1-pi-signal.tst +testit t3-l1-pi-steal.tst +testit t3-l2-pi.tst +testit t4-l2-pi-deboost.tst +testit t5-l4-pi-boost-deboost.tst + diff --git a/scripts/rt-tester/rt-tester.py b/scripts/rt-tester/rt-tester.py new file mode 100644 index 000000000000..4c79660793cf --- /dev/null +++ b/scripts/rt-tester/rt-tester.py @@ -0,0 +1,222 @@ +#!/usr/bin/env python +# +# rt-mutex tester +# +# (C) 2006 Thomas Gleixner +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +import os +import sys +import getopt +import shutil +import string + +# Globals +quiet = 0 +test = 0 +comments = 0 + +sysfsprefix = "/sys/devices/system/rttest/rttest" +statusfile = "/status" +commandfile = "/command" + +# Command opcodes +cmd_opcodes = { + "schedother" : "1", + "schedfifo" : "2", + "lock" : "3", + "locknowait" : "4", + "lockint" : "5", + "lockintnowait" : "6", + "lockcont" : "7", + "unlock" : "8", + "lockbkl" : "9", + "unlockbkl" : "10", + "signal" : "11", + "resetevent" : "98", + "reset" : "99", + } + +test_opcodes = { + "prioeq" : ["P" , "eq" , None], + "priolt" : ["P" , "lt" , None], + "priogt" : ["P" , "gt" , None], + "nprioeq" : ["N" , "eq" , None], + "npriolt" : ["N" , "lt" , None], + "npriogt" : ["N" , "gt" , None], + "unlocked" : ["M" , "eq" , 0], + "trylock" : ["M" , "eq" , 1], + "blocked" : ["M" , "eq" , 2], + "blockedwake" : ["M" , "eq" , 3], + "locked" : ["M" , "eq" , 4], + "opcodeeq" : ["O" , "eq" , None], + "opcodelt" : ["O" , "lt" , None], + "opcodegt" : ["O" , "gt" , None], + "eventeq" : ["E" , "eq" , None], + "eventlt" : ["E" , "lt" , None], + "eventgt" : ["E" , "gt" , None], + } + +# Print usage information +def usage(): + print "rt-tester.py <-c -h -q -t> " + print " -c display comments after first command" + print " -h help" + print " -q quiet mode" + print " -t test mode (syntax check)" + print " testfile: read test specification from testfile" + print " otherwise from stdin" + return + +# Print progress when not in quiet mode +def progress(str): + if not quiet: + print str + +# Analyse a status value +def analyse(val, top, arg): + + intval = int(val) + + if top[0] == "M": + intval = intval / (10 ** int(arg)) + intval = intval % 10 + argval = top[2] + elif top[0] == "O": + argval = int(cmd_opcodes.get(arg, arg)) + else: + argval = int(arg) + + # progress("%d %s %d" %(intval, top[1], argval)) + + if top[1] == "eq" and intval == argval: + return 1 + if top[1] == "lt" and intval < argval: + return 1 + if top[1] == "gt" and intval > argval: + return 1 + return 0 + +# Parse the commandline +try: + (options, arguments) = getopt.getopt(sys.argv[1:],'chqt') +except getopt.GetoptError, ex: + usage() + sys.exit(1) + +# Parse commandline options +for option, value in options: + if option == "-c": + comments = 1 + elif option == "-q": + quiet = 1 + elif option == "-t": + test = 1 + elif option == '-h': + usage() + sys.exit(0) + +# Select the input source +if arguments: + try: + fd = open(arguments[0]) + except Exception,ex: + sys.stderr.write("File not found %s\n" %(arguments[0])) + sys.exit(1) +else: + fd = sys.stdin + +linenr = 0 + +# Read the test patterns +while 1: + + linenr = linenr + 1 + line = fd.readline() + if not len(line): + break + + line = line.strip() + parts = line.split(":") + + if not parts or len(parts) < 1: + continue + + if len(parts[0]) == 0: + continue + + if parts[0].startswith("#"): + if comments > 1: + progress(line) + continue + + if comments == 1: + comments = 2 + + progress(line) + + cmd = parts[0].strip().lower() + opc = parts[1].strip().lower() + tid = parts[2].strip() + dat = parts[3].strip() + + try: + # Test or wait for a status value + if cmd == "t" or cmd == "w": + testop = test_opcodes[opc] + + fname = "%s%s%s" %(sysfsprefix, tid, statusfile) + if test: + print fname + continue + + while 1: + query = 1 + fsta = open(fname, 'r') + status = fsta.readline().strip() + fsta.close() + stat = status.split(",") + for s in stat: + s = s.strip() + if s.startswith(testop[0]): + # Seperate status value + val = s[2:].strip() + query = analyse(val, testop, dat) + break + if query or cmd == "t": + break + + progress(" " + status) + + if not query: + sys.stderr.write("Test failed in line %d\n" %(linenr)) + sys.exit(1) + + # Issue a command to the tester + elif cmd == "c": + cmdnr = cmd_opcodes[opc] + # Build command string and sys filename + cmdstr = "%s:%s" %(cmdnr, dat) + fname = "%s%s%s" %(sysfsprefix, tid, commandfile) + if test: + print fname + continue + fcmd = open(fname, 'w') + fcmd.write(cmdstr) + fcmd.close() + + except Exception,ex: + sys.stderr.write(str(ex)) + sys.stderr.write("\nSyntax error in line %d\n" %(linenr)) + if not test: + fd.close() + sys.exit(1) + +# Normal exit pass +print "Pass" +sys.exit(0) + + diff --git a/scripts/rt-tester/t2-l1-2rt-sameprio.tst b/scripts/rt-tester/t2-l1-2rt-sameprio.tst new file mode 100644 index 000000000000..a2b6f2aae755 --- /dev/null +++ b/scripts/rt-tester/t2-l1-2rt-sameprio.tst @@ -0,0 +1,101 @@ +# +# RT-Mutex test +# +# Op: C(ommand)/T(est)/W(ait) +# | opcode +# | | threadid: 0-7 +# | | | opcode argument +# | | | | +# C: lock: 0: 0 +# +# Commands +# +# opcode opcode argument +# schedother nice value +# schedfifo priority +# lock lock nr (0-7) +# locknowait lock nr (0-7) +# lockint lock nr (0-7) +# lockintnowait lock nr (0-7) +# lockcont lock nr (0-7) +# unlock lock nr (0-7) +# lockbkl lock nr (0-7) +# unlockbkl lock nr (0-7) +# signal 0 +# reset 0 +# resetevent 0 +# +# Tests / Wait +# +# opcode opcode argument +# +# prioeq priority +# priolt priority +# priogt priority +# nprioeq normal priority +# npriolt normal priority +# npriogt normal priority +# locked lock nr (0-7) +# blocked lock nr (0-7) +# blockedwake lock nr (0-7) +# unlocked lock nr (0-7) +# lockedbkl dont care +# blockedbkl dont care +# unlockedbkl dont care +# opcodeeq command opcode or number +# opcodelt number +# opcodegt number +# eventeq number +# eventgt number +# eventlt number + +# +# 2 threads 1 lock +# +C: resetevent: 0: 0 +W: opcodeeq: 0: 0 + +# Set schedulers +C: schedfifo: 0: 80 +W: opcodeeq: 0: 0 +C: schedfifo: 1: 80 +W: opcodeeq: 1: 0 + +# T0 lock L0 +C: locknowait: 0: 0 +C: locknowait: 1: 0 +W: locked: 0: 0 +W: blocked: 1: 0 +T: prioeq: 0: 80 + +# T0 unlock L0 +C: unlock: 0: 0 +W: locked: 1: 0 + +# Verify T0 +W: unlocked: 0: 0 +T: prioeq: 0: 80 + +# Unlock +C: unlock: 1: 0 +W: unlocked: 1: 0 + +# T1,T0 lock L0 +C: locknowait: 1: 0 +C: locknowait: 0: 0 +W: locked: 1: 0 +W: blocked: 0: 0 +T: prioeq: 1: 80 + +# T1 unlock L0 +C: unlock: 1: 0 +W: locked: 0: 0 + +# Verify T1 +W: unlocked: 1: 0 +T: prioeq: 1: 80 + +# Unlock and exit +C: unlock: 0: 0 +W: unlocked: 0: 0 + diff --git a/scripts/rt-tester/t2-l1-pi.tst b/scripts/rt-tester/t2-l1-pi.tst new file mode 100644 index 000000000000..aa4c8940acd6 --- /dev/null +++ b/scripts/rt-tester/t2-l1-pi.tst @@ -0,0 +1,84 @@ +# +# RT-Mutex test +# +# Op: C(ommand)/T(est)/W(ait) +# | opcode +# | | threadid: 0-7 +# | | | opcode argument +# | | | | +# C: lock: 0: 0 +# +# Commands +# +# opcode opcode argument +# schedother nice value +# schedfifo priority +# lock lock nr (0-7) +# locknowait lock nr (0-7) +# lockint lock nr (0-7) +# lockintnowait lock nr (0-7) +# lockcont lock nr (0-7) +# unlock lock nr (0-7) +# lockbkl lock nr (0-7) +# unlockbkl lock nr (0-7) +# signal 0 +# reset 0 +# resetevent 0 +# +# Tests / Wait +# +# opcode opcode argument +# +# prioeq priority +# priolt priority +# priogt priority +# nprioeq normal priority +# npriolt normal priority +# npriogt normal priority +# locked lock nr (0-7) +# blocked lock nr (0-7) +# blockedwake lock nr (0-7) +# unlocked lock nr (0-7) +# lockedbkl dont care +# blockedbkl dont care +# unlockedbkl dont care +# opcodeeq command opcode or number +# opcodelt number +# opcodegt number +# eventeq number +# eventgt number +# eventlt number + +# +# 2 threads 1 lock with priority inversion +# +C: resetevent: 0: 0 +W: opcodeeq: 0: 0 + +# Set schedulers +C: schedother: 0: 0 +W: opcodeeq: 0: 0 +C: schedfifo: 1: 80 +W: opcodeeq: 1: 0 + +# T0 lock L0 +C: locknowait: 0: 0 +W: locked: 0: 0 + +# T1 lock L0 +C: locknowait: 1: 0 +W: blocked: 1: 0 +T: prioeq: 0: 80 + +# T0 unlock L0 +C: unlock: 0: 0 +W: locked: 1: 0 + +# Verify T1 +W: unlocked: 0: 0 +T: priolt: 0: 1 + +# Unlock and exit +C: unlock: 1: 0 +W: unlocked: 1: 0 + diff --git a/scripts/rt-tester/t2-l1-signal.tst b/scripts/rt-tester/t2-l1-signal.tst new file mode 100644 index 000000000000..c47ba06af209 --- /dev/null +++ b/scripts/rt-tester/t2-l1-signal.tst @@ -0,0 +1,79 @@ +# +# RT-Mutex test +# +# Op: C(ommand)/T(est)/W(ait) +# | opcode +# | | threadid: 0-7 +# | | | opcode argument +# | | | | +# C: lock: 0: 0 +# +# Commands +# +# opcode opcode argument +# schedother nice value +# schedfifo priority +# lock lock nr (0-7) +# locknowait lock nr (0-7) +# lockint lock nr (0-7) +# lockintnowait lock nr (0-7) +# lockcont lock nr (0-7) +# unlock lock nr (0-7) +# lockbkl lock nr (0-7) +# unlockbkl lock nr (0-7) +# signal 0 +# reset 0 +# resetevent 0 +# +# Tests / Wait +# +# opcode opcode argument +# +# prioeq priority +# priolt priority +# priogt priority +# nprioeq normal priority +# npriolt normal priority +# npriogt normal priority +# locked lock nr (0-7) +# blocked lock nr (0-7) +# blockedwake lock nr (0-7) +# unlocked lock nr (0-7) +# lockedbkl dont care +# blockedbkl dont care +# unlockedbkl dont care +# opcodeeq command opcode or number +# opcodelt number +# opcodegt number +# eventeq number +# eventgt number +# eventlt number + +# +# 2 threads 1 lock with priority inversion +# +C: resetevent: 0: 0 +W: opcodeeq: 0: 0 + +# Set schedulers +C: schedother: 0: 0 +W: opcodeeq: 0: 0 +C: schedother: 1: 0 +W: opcodeeq: 1: 0 + +# T0 lock L0 +C: locknowait: 0: 0 +W: locked: 0: 0 + +# T1 lock L0 +C: lockintnowait: 1: 0 +W: blocked: 1: 0 + +# Interrupt T1 +C: signal: 1: 0 +W: unlocked: 1: 0 +T: opcodeeq: 1: -4 + +# Unlock and exit +C: unlock: 0: 0 +W: unlocked: 0: 0 diff --git a/scripts/rt-tester/t2-l2-2rt-deadlock.tst b/scripts/rt-tester/t2-l2-2rt-deadlock.tst new file mode 100644 index 000000000000..0cee476b206e --- /dev/null +++ b/scripts/rt-tester/t2-l2-2rt-deadlock.tst @@ -0,0 +1,91 @@ +# +# RT-Mutex test +# +# Op: C(ommand)/T(est)/W(ait) +# | opcode +# | | threadid: 0-7 +# | | | opcode argument +# | | | | +# C: lock: 0: 0 +# +# Commands +# +# opcode opcode argument +# schedother nice value +# schedfifo priority +# lock lock nr (0-7) +# locknowait lock nr (0-7) +# lockint lock nr (0-7) +# lockintnowait lock nr (0-7) +# lockcont lock nr (0-7) +# unlock lock nr (0-7) +# lockbkl lock nr (0-7) +# unlockbkl lock nr (0-7) +# signal 0 +# reset 0 +# resetevent 0 +# +# Tests / Wait +# +# opcode opcode argument +# +# prioeq priority +# priolt priority +# priogt priority +# nprioeq normal priority +# npriolt normal priority +# npriogt normal priority +# locked lock nr (0-7) +# blocked lock nr (0-7) +# blockedwake lock nr (0-7) +# unlocked lock nr (0-7) +# lockedbkl dont care +# blockedbkl dont care +# unlockedbkl dont care +# opcodeeq command opcode or number +# opcodelt number +# opcodegt number +# eventeq number +# eventgt number +# eventlt number + +# +# 2 threads 2 lock +# +C: resetevent: 0: 0 +W: opcodeeq: 0: 0 + +# Set schedulers +C: schedfifo: 0: 80 +W: opcodeeq: 0: 0 +C: schedfifo: 1: 80 +W: opcodeeq: 1: 0 + +# T0 lock L0 +C: locknowait: 0: 0 +W: locked: 0: 0 + +# T1 lock L1 +C: locknowait: 1: 1 +W: locked: 1: 1 + +# T0 lock L1 +C: lockintnowait: 0: 1 +W: blocked: 0: 1 + +# T1 lock L0 +C: lockintnowait: 1: 0 +W: blocked: 1: 0 + +# Make deadlock go away +C: signal: 1: 0 +W: unlocked: 1: 0 +C: signal: 0: 0 +W: unlocked: 0: 1 + +# Unlock and exit +C: unlock: 0: 0 +W: unlocked: 0: 0 +C: unlock: 1: 1 +W: unlocked: 1: 1 + diff --git a/scripts/rt-tester/t3-l1-pi-1rt.tst b/scripts/rt-tester/t3-l1-pi-1rt.tst new file mode 100644 index 000000000000..a5eaf7ed5d54 --- /dev/null +++ b/scripts/rt-tester/t3-l1-pi-1rt.tst @@ -0,0 +1,95 @@ +# +# rt-mutex test +# +# Op: C(ommand)/T(est)/W(ait) +# | opcode +# | | threadid: 0-7 +# | | | opcode argument +# | | | | +# C: lock: 0: 0 +# +# Commands +# +# opcode opcode argument +# schedother nice value +# schedfifo priority +# lock lock nr (0-7) +# locknowait lock nr (0-7) +# lockint lock nr (0-7) +# lockintnowait lock nr (0-7) +# lockcont lock nr (0-7) +# unlock lock nr (0-7) +# lockbkl lock nr (0-7) +# unlockbkl lock nr (0-7) +# signal thread to signal (0-7) +# reset 0 +# resetevent 0 +# +# Tests / Wait +# +# opcode opcode argument +# +# prioeq priority +# priolt priority +# priogt priority +# nprioeq normal priority +# npriolt normal priority +# npriogt normal priority +# locked lock nr (0-7) +# blocked lock nr (0-7) +# blockedwake lock nr (0-7) +# unlocked lock nr (0-7) +# lockedbkl dont care +# blockedbkl dont care +# unlockedbkl dont care +# opcodeeq command opcode or number +# opcodelt number +# opcodegt number +# eventeq number +# eventgt number +# eventlt number + +# +# 3 threads 1 lock PI +# +C: resetevent: 0: 0 +W: opcodeeq: 0: 0 + +# Set schedulers +C: schedother: 0: 0 +W: opcodeeq: 0: 0 +C: schedother: 1: 0 +W: opcodeeq: 1: 0 +C: schedfifo: 2: 82 +W: opcodeeq: 2: 0 + +# T0 lock L0 +C: locknowait: 0: 0 +W: locked: 0: 0 + +# T1 lock L0 +C: locknowait: 1: 0 +W: blocked: 1: 0 +T: priolt: 0: 1 + +# T2 lock L0 +C: locknowait: 2: 0 +W: blocked: 2: 0 +T: prioeq: 0: 82 + +# T0 unlock L0 +C: unlock: 0: 0 + +# Wait until T2 got the lock +W: locked: 2: 0 +W: unlocked: 0: 0 +T: priolt: 0: 1 + +# T2 unlock L0 +C: unlock: 2: 0 + +W: unlocked: 2: 0 +W: locked: 1: 0 + +C: unlock: 1: 0 +W: unlocked: 1: 0 diff --git a/scripts/rt-tester/t3-l1-pi-2rt.tst b/scripts/rt-tester/t3-l1-pi-2rt.tst new file mode 100644 index 000000000000..c622391a8afe --- /dev/null +++ b/scripts/rt-tester/t3-l1-pi-2rt.tst @@ -0,0 +1,96 @@ +# +# rt-mutex test +# +# Op: C(ommand)/T(est)/W(ait) +# | opcode +# | | threadid: 0-7 +# | | | opcode argument +# | | | | +# C: lock: 0: 0 +# +# Commands +# +# opcode opcode argument +# schedother nice value +# schedfifo priority +# lock lock nr (0-7) +# locknowait lock nr (0-7) +# lockint lock nr (0-7) +# lockintnowait lock nr (0-7) +# lockcont lock nr (0-7) +# unlock lock nr (0-7) +# lockbkl lock nr (0-7) +# unlockbkl lock nr (0-7) +# signal thread to signal (0-7) +# reset 0 +# resetevent 0 +# +# Tests / Wait +# +# opcode opcode argument +# +# prioeq priority +# priolt priority +# priogt priority +# nprioeq normal priority +# npriolt normal priority +# npriogt normal priority +# locked lock nr (0-7) +# blocked lock nr (0-7) +# blockedwake lock nr (0-7) +# unlocked lock nr (0-7) +# lockedbkl dont care +# blockedbkl dont care +# unlockedbkl dont care +# opcodeeq command opcode or number +# opcodelt number +# opcodegt number +# eventeq number +# eventgt number +# eventlt number + +# +# 3 threads 1 lock PI +# +C: resetevent: 0: 0 +W: opcodeeq: 0: 0 + +# Set schedulers +C: schedother: 0: 0 +W: opcodeeq: 0: 0 +C: schedfifo: 1: 81 +W: opcodeeq: 1: 0 +C: schedfifo: 2: 82 +W: opcodeeq: 2: 0 + +# T0 lock L0 +C: locknowait: 0: 0 +W: locked: 0: 0 + +# T1 lock L0 +C: locknowait: 1: 0 +W: blocked: 1: 0 +T: prioeq: 0: 81 + +# T2 lock L0 +C: locknowait: 2: 0 +W: blocked: 2: 0 +T: prioeq: 0: 82 +T: prioeq: 1: 81 + +# T0 unlock L0 +C: unlock: 0: 0 + +# Wait until T2 got the lock +W: locked: 2: 0 +W: unlocked: 0: 0 +T: priolt: 0: 1 + +# T2 unlock L0 +C: unlock: 2: 0 + +W: unlocked: 2: 0 +W: locked: 1: 0 + +C: unlock: 1: 0 +W: unlocked: 1: 0 diff --git a/scripts/rt-tester/t3-l1-pi-3rt.tst b/scripts/rt-tester/t3-l1-pi-3rt.tst new file mode 100644 index 000000000000..b5057fb13e09 --- /dev/null +++ b/scripts/rt-tester/t3-l1-pi-3rt.tst @@ -0,0 +1,95 @@ +# +# rt-mutex test +# +# Op: C(ommand)/T(est)/W(ait) +# | opcode +# | | threadid: 0-7 +# | | | opcode argument +# | | | | +# C: lock: 0: 0 +# +# Commands +# +# opcode opcode argument +# schedother nice value +# schedfifo priority +# lock lock nr (0-7) +# locknowait lock nr (0-7) +# lockint lock nr (0-7) +# lockintnowait lock nr (0-7) +# lockcont lock nr (0-7) +# unlock lock nr (0-7) +# lockbkl lock nr (0-7) +# unlockbkl lock nr (0-7) +# signal thread to signal (0-7) +# reset 0 +# resetevent 0 +# +# Tests / Wait +# +# opcode opcode argument +# +# prioeq priority +# priolt priority +# priogt priority +# nprioeq normal priority +# npriolt normal priority +# npriogt normal priority +# locked lock nr (0-7) +# blocked lock nr (0-7) +# blockedwake lock nr (0-7) +# unlocked lock nr (0-7) +# lockedbkl dont care +# blockedbkl dont care +# unlockedbkl dont care +# opcodeeq command opcode or number +# opcodelt number +# opcodegt number +# eventeq number +# eventgt number +# eventlt number + +# +# 3 threads 1 lock PI +# +C: resetevent: 0: 0 +W: opcodeeq: 0: 0 + +# Set schedulers +C: schedfifo: 0: 80 +W: opcodeeq: 0: 0 +C: schedfifo: 1: 81 +W: opcodeeq: 1: 0 +C: schedfifo: 2: 82 +W: opcodeeq: 2: 0 + +# T0 lock L0 +C: locknowait: 0: 0 +W: locked: 0: 0 + +# T1 lock L0 +C: locknowait: 1: 0 +W: blocked: 1: 0 +T: prioeq: 0: 81 + +# T2 lock L0 +C: locknowait: 2: 0 +W: blocked: 2: 0 +T: prioeq: 0: 82 + +# T0 unlock L0 +C: unlock: 0: 0 + +# Wait until T2 got the lock +W: locked: 2: 0 +W: unlocked: 0: 0 +T: prioeq: 0: 80 + +# T2 unlock L0 +C: unlock: 2: 0 + +W: locked: 1: 0 +W: unlocked: 2: 0 + +C: unlock: 1: 0 +W: unlocked: 1: 0 diff --git a/scripts/rt-tester/t3-l1-pi-signal.tst b/scripts/rt-tester/t3-l1-pi-signal.tst new file mode 100644 index 000000000000..3e427daa33ff --- /dev/null +++ b/scripts/rt-tester/t3-l1-pi-signal.tst @@ -0,0 +1,101 @@ +# +# rt-mutex test +# +# Op: C(ommand)/T(est)/W(ait) +# | opcode +# | | threadid: 0-7 +# | | | opcode argument +# | | | | +# C: lock: 0: 0 +# +# Commands +# +# opcode opcode argument +# schedother nice value +# schedfifo priority +# lock lock nr (0-7) +# locknowait lock nr (0-7) +# lockint lock nr (0-7) +# lockintnowait lock nr (0-7) +# lockcont lock nr (0-7) +# unlock lock nr (0-7) +# lockbkl lock nr (0-7) +# unlockbkl lock nr (0-7) +# signal thread to signal (0-7) +# reset 0 +# resetevent 0 +# +# Tests / Wait +# +# opcode opcode argument +# +# prioeq priority +# priolt priority +# priogt priority +# nprioeq normal priority +# npriolt normal priority +# npriogt normal priority +# locked lock nr (0-7) +# blocked lock nr (0-7) +# blockedwake lock nr (0-7) +# unlocked lock nr (0-7) +# lockedbkl dont care +# blockedbkl dont care +# unlockedbkl dont care +# opcodeeq command opcode or number +# opcodelt number +# opcodegt number +# eventeq number +# eventgt number +# eventlt number + +# Reset event counter +C: resetevent: 0: 0 +W: opcodeeq: 0: 0 + +# Set priorities +C: schedother: 0: 0 +W: opcodeeq: 0: 0 +C: schedfifo: 1: 80 +W: opcodeeq: 1: 0 +C: schedfifo: 2: 81 +W: opcodeeq: 2: 0 + +# T0 lock L0 +C: lock: 0: 0 +W: locked: 0: 0 + +# T1 lock L0, no wait in the wakeup path +C: locknowait: 1: 0 +W: blocked: 1: 0 +T: prioeq: 0: 80 +T: prioeq: 1: 80 + +# T2 lock L0 interruptible, no wait in the wakeup path +C: lockintnowait: 2: 0 +W: blocked: 2: 0 +T: prioeq: 0: 81 +T: prioeq: 1: 80 + +# Interrupt T2 +C: signal: 2: 2 +W: unlocked: 2: 0 +T: prioeq: 1: 80 +T: prioeq: 0: 80 + +T: locked: 0: 0 +T: blocked: 1: 0 + +# T0 unlock L0 +C: unlock: 0: 0 + +# Wait until T1 has locked L0 and exit +W: locked: 1: 0 +W: unlocked: 0: 0 +T: priolt: 0: 1 + +C: unlock: 1: 0 +W: unlocked: 1: 0 + + + diff --git a/scripts/rt-tester/t3-l1-pi-steal.tst b/scripts/rt-tester/t3-l1-pi-steal.tst new file mode 100644 index 000000000000..72c24a9e4be4 --- /dev/null +++ b/scripts/rt-tester/t3-l1-pi-steal.tst @@ -0,0 +1,99 @@ +# +# rt-mutex test +# +# Op: C(ommand)/T(est)/W(ait) +# | opcode +# | | threadid: 0-7 +# | | | opcode argument +# | | | | +# C: lock: 0: 0 +# +# Commands +# +# opcode opcode argument +# schedother nice value +# schedfifo priority +# lock lock nr (0-7) +# locknowait lock nr (0-7) +# lockint lock nr (0-7) +# lockintnowait lock nr (0-7) +# lockcont lock nr (0-7) +# unlock lock nr (0-7) +# lockbkl lock nr (0-7) +# unlockbkl lock nr (0-7) +# signal thread to signal (0-7) +# reset 0 +# resetevent 0 +# +# Tests / Wait +# +# opcode opcode argument +# +# prioeq priority +# priolt priority +# priogt priority +# nprioeq normal priority +# npriolt normal priority +# npriogt normal priority +# locked lock nr (0-7) +# blocked lock nr (0-7) +# blockedwake lock nr (0-7) +# unlocked lock nr (0-7) +# lockedbkl dont care +# blockedbkl dont care +# unlockedbkl dont care +# opcodeeq command opcode or number +# opcodelt number +# opcodegt number +# eventeq number +# eventgt number +# eventlt number + +# +# 3 threads 1 lock PI steal pending ownership +# +C: resetevent: 0: 0 +W: opcodeeq: 0: 0 + +# Set schedulers +C: schedother: 0: 0 +W: opcodeeq: 0: 0 +C: schedfifo: 1: 80 +W: opcodeeq: 1: 0 +C: schedfifo: 2: 81 +W: opcodeeq: 2: 0 + +# T0 lock L0 +C: lock: 0: 0 +W: locked: 0: 0 + +# T1 lock L0 +C: lock: 1: 0 +W: blocked: 1: 0 +T: prioeq: 0: 80 + +# T0 unlock L0 +C: unlock: 0: 0 + +# Wait until T1 is in the wakeup loop +W: blockedwake: 1: 0 +T: priolt: 0: 1 + +# T2 lock L0 +C: lock: 2: 0 +# T1 leave wakeup loop +C: lockcont: 1: 0 + +# T2 must have the lock and T1 must be blocked +W: locked: 2: 0 +W: blocked: 1: 0 + +# T2 unlock L0 +C: unlock: 2: 0 + +# Wait until T1 is in the wakeup loop and let it run +W: blockedwake: 1: 0 +C: lockcont: 1: 0 +W: locked: 1: 0 +C: unlock: 1: 0 +W: unlocked: 1: 0 diff --git a/scripts/rt-tester/t3-l2-pi.tst b/scripts/rt-tester/t3-l2-pi.tst new file mode 100644 index 000000000000..2ba0dced48fa --- /dev/null +++ b/scripts/rt-tester/t3-l2-pi.tst @@ -0,0 +1,95 @@ +# +# rt-mutex test +# +# Op: C(ommand)/T(est)/W(ait) +# | opcode +# | | threadid: 0-7 +# | | | opcode argument +# | | | | +# C: lock: 0: 0 +# +# Commands +# +# opcode opcode argument +# schedother nice value +# schedfifo priority +# lock lock nr (0-7) +# locknowait lock nr (0-7) +# lockint lock nr (0-7) +# lockintnowait lock nr (0-7) +# lockcont lock nr (0-7) +# unlock lock nr (0-7) +# lockbkl lock nr (0-7) +# unlockbkl lock nr (0-7) +# signal thread to signal (0-7) +# reset 0 +# resetevent 0 +# +# Tests / Wait +# +# opcode opcode argument +# +# prioeq priority +# priolt priority +# priogt priority +# nprioeq normal priority +# npriolt normal priority +# npriogt normal priority +# locked lock nr (0-7) +# blocked lock nr (0-7) +# blockedwake lock nr (0-7) +# unlocked lock nr (0-7) +# lockedbkl dont care +# blockedbkl dont care +# unlockedbkl dont care +# opcodeeq command opcode or number +# opcodelt number +# opcodegt number +# eventeq number +# eventgt number +# eventlt number + +# +# 3 threads 2 lock PI +# +C: resetevent: 0: 0 +W: opcodeeq: 0: 0 + +# Set schedulers +C: schedother: 0: 0 +W: opcodeeq: 0: 0 +C: schedother: 1: 0 +W: opcodeeq: 1: 0 +C: schedfifo: 2: 82 +W: opcodeeq: 2: 0 + +# T0 lock L0 +C: locknowait: 0: 0 +W: locked: 0: 0 + +# T1 lock L0 +C: locknowait: 1: 0 +W: blocked: 1: 0 +T: priolt: 0: 1 + +# T2 lock L0 +C: locknowait: 2: 0 +W: blocked: 2: 0 +T: prioeq: 0: 82 + +# T0 unlock L0 +C: unlock: 0: 0 + +# Wait until T2 got the lock +W: locked: 2: 0 +W: unlocked: 0: 0 +T: priolt: 0: 1 + +# T2 unlock L0 +C: unlock: 2: 0 + +W: unlocked: 2: 0 +W: locked: 1: 0 + +C: unlock: 1: 0 +W: unlocked: 1: 0 diff --git a/scripts/rt-tester/t4-l2-pi-deboost.tst b/scripts/rt-tester/t4-l2-pi-deboost.tst new file mode 100644 index 000000000000..01f1a80fa02a --- /dev/null +++ b/scripts/rt-tester/t4-l2-pi-deboost.tst @@ -0,0 +1,127 @@ +# +# rt-mutex test +# +# Op: C(ommand)/T(est)/W(ait) +# | opcode +# | | threadid: 0-7 +# | | | opcode argument +# | | | | +# C: lock: 0: 0 +# +# Commands +# +# opcode opcode argument +# schedother nice value +# schedfifo priority +# lock lock nr (0-7) +# locknowait lock nr (0-7) +# lockint lock nr (0-7) +# lockintnowait lock nr (0-7) +# lockcont lock nr (0-7) +# unlock lock nr (0-7) +# lockbkl lock nr (0-7) +# unlockbkl lock nr (0-7) +# signal thread to signal (0-7) +# reset 0 +# resetevent 0 +# +# Tests / Wait +# +# opcode opcode argument +# +# prioeq priority +# priolt priority +# priogt priority +# nprioeq normal priority +# npriolt normal priority +# npriogt normal priority +# locked lock nr (0-7) +# blocked lock nr (0-7) +# blockedwake lock nr (0-7) +# unlocked lock nr (0-7) +# lockedbkl dont care +# blockedbkl dont care +# unlockedbkl dont care +# opcodeeq command opcode or number +# opcodelt number +# opcodegt number +# eventeq number +# eventgt number +# eventlt number + +# +# 4 threads 2 lock PI +# +C: resetevent: 0: 0 +W: opcodeeq: 0: 0 + +# Set schedulers +C: schedother: 0: 0 +W: opcodeeq: 0: 0 +C: schedother: 1: 0 +W: opcodeeq: 1: 0 +C: schedfifo: 2: 82 +W: opcodeeq: 2: 0 +C: schedfifo: 3: 83 +W: opcodeeq: 3: 0 + +# T0 lock L0 +C: locknowait: 0: 0 +W: locked: 0: 0 + +# T1 lock L1 +C: locknowait: 1: 1 +W: locked: 1: 1 + +# T3 lock L0 +C: lockintnowait: 3: 0 +W: blocked: 3: 0 +T: prioeq: 0: 83 + +# T0 lock L1 +C: lock: 0: 1 +W: blocked: 0: 1 +T: prioeq: 1: 83 + +# T1 unlock L1 +C: unlock: 1: 1 + +# Wait until T0 is in the wakeup code +W: blockedwake: 0: 1 + +# Verify that T1 is unboosted +W: unlocked: 1: 1 +T: priolt: 1: 1 + +# T2 lock L1 (T0 is boosted and pending owner !) +C: locknowait: 2: 1 +W: blocked: 2: 1 +T: prioeq: 0: 83 + +# Interrupt T3 and wait until T3 returned +C: signal: 3: 0 +W: unlocked: 3: 0 + +# Verify prio of T0 (still pending owner, +# but T2 is enqueued due to the previous boost by T3 +T: prioeq: 0: 82 + +# Let T0 continue +C: lockcont: 0: 1 +W: locked: 0: 1 + +# Unlock L1 and let T2 get L1 +C: unlock: 0: 1 +W: locked: 2: 1 + +# Verify that T0 is unboosted +W: unlocked: 0: 1 +T: priolt: 0: 1 + +# Unlock everything and exit +C: unlock: 2: 1 +W: unlocked: 2: 1 + +C: unlock: 0: 0 +W: unlocked: 0: 0 + diff --git a/scripts/rt-tester/t5-l4-pi-boost-deboost.tst b/scripts/rt-tester/t5-l4-pi-boost-deboost.tst new file mode 100644 index 000000000000..efa0788c1189 --- /dev/null +++ b/scripts/rt-tester/t5-l4-pi-boost-deboost.tst @@ -0,0 +1,148 @@ +# +# rt-mutex test +# +# Op: C(ommand)/T(est)/W(ait) +# | opcode +# | | threadid: 0-7 +# | | | opcode argument +# | | | | +# C: lock: 0: 0 +# +# Commands +# +# opcode opcode argument +# schedother nice value +# schedfifo priority +# lock lock nr (0-7) +# locknowait lock nr (0-7) +# lockint lock nr (0-7) +# lockintnowait lock nr (0-7) +# lockcont lock nr (0-7) +# unlock lock nr (0-7) +# lockbkl lock nr (0-7) +# unlockbkl lock nr (0-7) +# signal thread to signal (0-7) +# reset 0 +# resetevent 0 +# +# Tests / Wait +# +# opcode opcode argument +# +# prioeq priority +# priolt priority +# priogt priority +# nprioeq normal priority +# npriolt normal priority +# npriogt normal priority +# locked lock nr (0-7) +# blocked lock nr (0-7) +# blockedwake lock nr (0-7) +# unlocked lock nr (0-7) +# lockedbkl dont care +# blockedbkl dont care +# unlockedbkl dont care +# opcodeeq command opcode or number +# opcodelt number +# opcodegt number +# eventeq number +# eventgt number +# eventlt number + +# +# 5 threads 4 lock PI +# +C: resetevent: 0: 0 +W: opcodeeq: 0: 0 + +# Set schedulers +C: schedother: 0: 0 +W: opcodeeq: 0: 0 +C: schedfifo: 1: 81 +W: opcodeeq: 1: 0 +C: schedfifo: 2: 82 +W: opcodeeq: 2: 0 +C: schedfifo: 3: 83 +W: opcodeeq: 3: 0 +C: schedfifo: 4: 84 +W: opcodeeq: 4: 0 + +# T0 lock L0 +C: locknowait: 0: 0 +W: locked: 0: 0 + +# T1 lock L1 +C: locknowait: 1: 1 +W: locked: 1: 1 + +# T1 lock L0 +C: lockintnowait: 1: 0 +W: blocked: 1: 0 +T: prioeq: 0: 81 + +# T2 lock L2 +C: locknowait: 2: 2 +W: locked: 2: 2 + +# T2 lock L1 +C: lockintnowait: 2: 1 +W: blocked: 2: 1 +T: prioeq: 0: 82 +T: prioeq: 1: 82 + +# T3 lock L3 +C: locknowait: 3: 3 +W: locked: 3: 3 + +# T3 lock L2 +C: lockintnowait: 3: 2 +W: blocked: 3: 2 +T: prioeq: 0: 83 +T: prioeq: 1: 83 +T: prioeq: 2: 83 + +# T4 lock L3 +C: lockintnowait: 4: 3 +W: blocked: 4: 3 +T: prioeq: 0: 84 +T: prioeq: 1: 84 +T: prioeq: 2: 84 +T: prioeq: 3: 84 + +# Signal T4 +C: signal: 4: 0 +W: unlocked: 4: 3 +T: prioeq: 0: 83 +T: prioeq: 1: 83 +T: prioeq: 2: 83 +T: prioeq: 3: 83 + +# Signal T3 +C: signal: 3: 0 +W: unlocked: 3: 2 +T: prioeq: 0: 82 +T: prioeq: 1: 82 +T: prioeq: 2: 82 + +# Signal T2 +C: signal: 2: 0 +W: unlocked: 2: 1 +T: prioeq: 0: 81 +T: prioeq: 1: 81 + +# Signal T1 +C: signal: 1: 0 +W: unlocked: 1: 0 +T: priolt: 0: 1 + +# Unlock and exit +C: unlock: 3: 3 +C: unlock: 2: 2 +C: unlock: 1: 1 +C: unlock: 0: 0 + +W: unlocked: 3: 3 +W: unlocked: 2: 2 +W: unlocked: 1: 1 +W: unlocked: 0: 0 + -- cgit v1.2.3 From a1583d3e83cae1c58870602efc6328c34b644c01 Mon Sep 17 00:00:00 2001 From: Roman Zippel Date: Tue, 27 Jun 2006 02:55:00 -0700 Subject: [PATCH] fix rt-mutex defaults and dependencies Fix defaults and dependencies. Signed-off-by: Roman Zippel Cc: Thomas Gleixner Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/Kconfig.debug | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 6afe0af0a19b..5330911ebd30 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -109,7 +109,6 @@ config DEBUG_MUTEXES config DEBUG_RT_MUTEXES bool "RT Mutex debugging, deadlock detection" - default y depends on DEBUG_KERNEL && RT_MUTEXES help This allows rt mutex semantics violations and rt mutex related @@ -122,8 +121,7 @@ config DEBUG_PI_LIST config RT_MUTEX_TESTER bool "Built-in scriptable tester for rt-mutexes" - depends on RT_MUTEXES - default n + depends on DEBUG_KERNEL && RT_MUTEXES help This option enables a rt-mutex tester. -- cgit v1.2.3 From f71d20e961474dde77e6558396efb93d6ac80a4b Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Wed, 28 Jun 2006 04:26:45 -0700 Subject: [PATCH] Add EXPORT_UNUSED_SYMBOL and EXPORT_UNUSED_SYMBOL_GPL Temporarily add EXPORT_UNUSED_SYMBOL and EXPORT_UNUSED_SYMBOL_GPL. These will be used as a transition measure for symbols that aren't used in the kernel and are on the way out. When a module uses such a symbol, a warning is printk'd at modprobe time. The main reason for removing unused exports is size: eacho export takes roughly between 100 and 150 bytes of kernel space in the binary. This patch gives users the option to immediately get this size gain via a config option. Signed-off-by: Arjan van de Ven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/feature-removal-schedule.txt | 10 ++++ include/asm-generic/vmlinux.lds.h | 28 +++++++++++ include/linux/module.h | 20 ++++++++ kernel/module.c | 78 +++++++++++++++++++++++++++++- lib/Kconfig.debug | 16 ++++++ 5 files changed, 150 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 027285d0c26c..033ac91da07a 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -177,6 +177,16 @@ Who: Jean Delvare --------------------------- +What: Unused EXPORT_SYMBOL/EXPORT_SYMBOL_GPL exports + (temporary transition config option provided until then) + The transition config option will also be removed at the same time. +When: before 2.6.19 +Why: Unused symbols are both increasing the size of the kernel binary + and are often a sign of "wrong API" +Who: Arjan van de Ven + +--------------------------- + What: remove EXPORT_SYMBOL(tasklist_lock) When: August 2006 Files: kernel/fork.c diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 9d11550b4818..db5a3732f106 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -58,6 +58,20 @@ VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .; \ } \ \ + /* Kernel symbol table: Normal unused symbols */ \ + __ksymtab_unused : AT(ADDR(__ksymtab_unused) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ksymtab_unused) = .; \ + *(__ksymtab_unused) \ + VMLINUX_SYMBOL(__stop___ksymtab_unused) = .; \ + } \ + \ + /* Kernel symbol table: GPL-only unused symbols */ \ + __ksymtab_unused_gpl : AT(ADDR(__ksymtab_unused_gpl) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ksymtab_unused_gpl) = .; \ + *(__ksymtab_unused_gpl) \ + VMLINUX_SYMBOL(__stop___ksymtab_unused_gpl) = .; \ + } \ + \ /* Kernel symbol table: GPL-future-only symbols */ \ __ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .; \ @@ -79,6 +93,20 @@ VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .; \ } \ \ + /* Kernel symbol table: Normal unused symbols */ \ + __kcrctab_unused : AT(ADDR(__kcrctab_unused) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___kcrctab_unused) = .; \ + *(__kcrctab_unused) \ + VMLINUX_SYMBOL(__stop___kcrctab_unused) = .; \ + } \ + \ + /* Kernel symbol table: GPL-only unused symbols */ \ + __kcrctab_unused_gpl : AT(ADDR(__kcrctab_unused_gpl) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___kcrctab_unused_gpl) = .; \ + *(__kcrctab_unused_gpl) \ + VMLINUX_SYMBOL(__stop___kcrctab_unused_gpl) = .; \ + } \ + \ /* Kernel symbol table: GPL-future-only symbols */ \ __kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .; \ diff --git a/include/linux/module.h b/include/linux/module.h index 9ebbb74b7b72..9e9dc7c24d95 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -203,6 +203,15 @@ void *__symbol_get_gpl(const char *symbol); #define EXPORT_SYMBOL_GPL_FUTURE(sym) \ __EXPORT_SYMBOL(sym, "_gpl_future") + +#ifdef CONFIG_UNUSED_SYMBOLS +#define EXPORT_UNUSED_SYMBOL(sym) __EXPORT_SYMBOL(sym, "_unused") +#define EXPORT_UNUSED_SYMBOL_GPL(sym) __EXPORT_SYMBOL(sym, "_unused_gpl") +#else +#define EXPORT_UNUSED_SYMBOL(sym) +#define EXPORT_UNUSED_SYMBOL_GPL(sym) +#endif + #endif struct module_ref @@ -261,6 +270,15 @@ struct module unsigned int num_gpl_syms; const unsigned long *gpl_crcs; + /* unused exported symbols. */ + const struct kernel_symbol *unused_syms; + unsigned int num_unused_syms; + const unsigned long *unused_crcs; + /* GPL-only, unused exported symbols. */ + const struct kernel_symbol *unused_gpl_syms; + unsigned int num_unused_gpl_syms; + const unsigned long *unused_gpl_crcs; + /* symbols that will be GPL-only in the near future. */ const struct kernel_symbol *gpl_future_syms; unsigned int num_gpl_future_syms; @@ -456,6 +474,8 @@ void module_remove_driver(struct device_driver *); #define EXPORT_SYMBOL(sym) #define EXPORT_SYMBOL_GPL(sym) #define EXPORT_SYMBOL_GPL_FUTURE(sym) +#define EXPORT_UNUSED_SYMBOL(sym) +#define EXPORT_UNUSED_SYMBOL_GPL(sym) /* Given an address, look for it in the exception tables. */ static inline const struct exception_table_entry * diff --git a/kernel/module.c b/kernel/module.c index 10e5b872adf6..03b738172a8c 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -1,4 +1,4 @@ -/* Rewritten by Rusty Russell, on the backs of many others... +/* Copyright (C) 2002 Richard Henderson Copyright (C) 2001 Rusty Russell, 2002 Rusty Russell IBM. @@ -122,9 +122,17 @@ extern const struct kernel_symbol __start___ksymtab_gpl[]; extern const struct kernel_symbol __stop___ksymtab_gpl[]; extern const struct kernel_symbol __start___ksymtab_gpl_future[]; extern const struct kernel_symbol __stop___ksymtab_gpl_future[]; +extern const struct kernel_symbol __start___ksymtab_unused[]; +extern const struct kernel_symbol __stop___ksymtab_unused[]; +extern const struct kernel_symbol __start___ksymtab_unused_gpl[]; +extern const struct kernel_symbol __stop___ksymtab_unused_gpl[]; +extern const struct kernel_symbol __start___ksymtab_gpl_future[]; +extern const struct kernel_symbol __stop___ksymtab_gpl_future[]; extern const unsigned long __start___kcrctab[]; extern const unsigned long __start___kcrctab_gpl[]; extern const unsigned long __start___kcrctab_gpl_future[]; +extern const unsigned long __start___kcrctab_unused[]; +extern const unsigned long __start___kcrctab_unused_gpl[]; #ifndef CONFIG_MODVERSIONS #define symversion(base, idx) NULL @@ -144,6 +152,17 @@ static const struct kernel_symbol *lookup_symbol(const char *name, return NULL; } +static void printk_unused_warning(const char *name) +{ + printk(KERN_WARNING "Symbol %s is marked as UNUSED, " + "however this module is using it.\n", name); + printk(KERN_WARNING "This symbol will go away in the future.\n"); + printk(KERN_WARNING "Please evalute if this is the right api to use, " + "and if it really is, submit a report the linux kernel " + "mailinglist together with submitting your code for " + "inclusion.\n"); +} + /* Find a symbol, return value, crc and module which owns it */ static unsigned long __find_symbol(const char *name, struct module **owner, @@ -186,6 +205,25 @@ static unsigned long __find_symbol(const char *name, return ks->value; } + ks = lookup_symbol(name, __start___ksymtab_unused, + __stop___ksymtab_unused); + if (ks) { + printk_unused_warning(name); + *crc = symversion(__start___kcrctab_unused, + (ks - __start___ksymtab_unused)); + return ks->value; + } + + if (gplok) + ks = lookup_symbol(name, __start___ksymtab_unused_gpl, + __stop___ksymtab_unused_gpl); + if (ks) { + printk_unused_warning(name); + *crc = symversion(__start___kcrctab_unused_gpl, + (ks - __start___ksymtab_unused_gpl)); + return ks->value; + } + /* Now try modules. */ list_for_each_entry(mod, &modules, list) { *owner = mod; @@ -204,6 +242,23 @@ static unsigned long __find_symbol(const char *name, return ks->value; } } + ks = lookup_symbol(name, mod->unused_syms, mod->unused_syms + mod->num_unused_syms); + if (ks) { + printk_unused_warning(name); + *crc = symversion(mod->unused_crcs, (ks - mod->unused_syms)); + return ks->value; + } + + if (gplok) { + ks = lookup_symbol(name, mod->unused_gpl_syms, + mod->unused_gpl_syms + mod->num_unused_gpl_syms); + if (ks) { + printk_unused_warning(name); + *crc = symversion(mod->unused_gpl_crcs, + (ks - mod->unused_gpl_syms)); + return ks->value; + } + } ks = lookup_symbol(name, mod->gpl_future_syms, (mod->gpl_future_syms + mod->num_gpl_future_syms)); @@ -1407,6 +1462,8 @@ static struct module *load_module(void __user *umod, exportindex, modindex, obsparmindex, infoindex, gplindex, crcindex, gplcrcindex, versindex, pcpuindex, gplfutureindex, gplfuturecrcindex, unwindex = 0; + unsigned int unusedindex, unusedcrcindex, unusedgplindex, + unusedgplcrcindex; struct module *mod; long err = 0; void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ @@ -1487,9 +1544,13 @@ static struct module *load_module(void __user *umod, exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab"); gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl"); gplfutureindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl_future"); + unusedindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_unused"); + unusedgplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_unused_gpl"); crcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab"); gplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl"); gplfuturecrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl_future"); + unusedcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_unused"); + unusedgplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_unused_gpl"); setupindex = find_sec(hdr, sechdrs, secstrings, "__param"); exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table"); obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm"); @@ -1638,14 +1699,27 @@ static struct module *load_module(void __user *umod, mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr; mod->num_gpl_future_syms = sechdrs[gplfutureindex].sh_size / sizeof(*mod->gpl_future_syms); + mod->num_unused_syms = sechdrs[unusedindex].sh_size / + sizeof(*mod->unused_syms); + mod->num_unused_gpl_syms = sechdrs[unusedgplindex].sh_size / + sizeof(*mod->unused_gpl_syms); mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr; if (gplfuturecrcindex) mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr; + mod->unused_syms = (void *)sechdrs[unusedindex].sh_addr; + if (unusedcrcindex) + mod->unused_crcs = (void *)sechdrs[unusedcrcindex].sh_addr; + mod->unused_gpl_syms = (void *)sechdrs[unusedgplindex].sh_addr; + if (unusedgplcrcindex) + mod->unused_crcs = (void *)sechdrs[unusedgplcrcindex].sh_addr; + #ifdef CONFIG_MODVERSIONS if ((mod->num_syms && !crcindex) || (mod->num_gpl_syms && !gplcrcindex) || - (mod->num_gpl_future_syms && !gplfuturecrcindex)) { + (mod->num_gpl_future_syms && !gplfuturecrcindex) || + (mod->num_unused_syms && !unusedcrcindex) || + (mod->num_unused_gpl_syms && !unusedgplcrcindex)) { printk(KERN_WARNING "%s: No versions for exported symbols." " Tainting kernel.\n", mod->name); add_taint(TAINT_FORCED_MODULE); diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 5330911ebd30..e4fcbd12cf6e 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -23,6 +23,22 @@ config MAGIC_SYSRQ keys are documented in . Don't say Y unless you really know what this hack does. +config UNUSED_SYMBOLS + bool "Enable unused/obsolete exported symbols" + default y if X86 + help + Unused but exported symbols make the kernel needlessly bigger. For + that reason most of these unused exports will soon be removed. This + option is provided temporarily to provide a transition period in case + some external kernel module needs one of these symbols anyway. If you + encounter such a case in your module, consider if you are actually + using the right API. (rationale: since nobody in the kernel is using + this in a module, there is a pretty good chance it's actually the + wrong interface to use). If you really need the symbol, please send a + mail to the linux kernel mailing list mentioning the symbol and why + you really need it, and what the merge plan to the mainline kernel for + your module is. + config DEBUG_KERNEL bool "Kernel debugging" help -- cgit v1.2.3 From 0a6047eef1c465c38aacfbdab193161b3f0cd144 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 28 Jun 2006 17:09:34 -0700 Subject: Fix vsnprintf off-by-one bug The recent vsnprintf() fix introduced an off-by-one, and it's now possible to overrun the target buffer by one byte. The "end" pointer points to past the end of the buffer, so if we have to truncate the result, it needs to be done though "end[-1]". [ This is just an alternate and simpler patch to one proposed by Andrew and Jeremy, who actually noticed the problem ] Acked-by: Andrew Morton Acked-by: Jeremy Fitzhardinge Signed-off-by: Linus Torvalds --- lib/vsprintf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 797428afd111..bed7229378f2 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -489,7 +489,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) if (str < end) *str = '\0'; else - *end = '\0'; + end[-1] = '\0'; } /* the trailing null byte doesn't count towards the total */ return str-buf; -- cgit v1.2.3