aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Kconfig.debug11
-rw-r--r--lib/dma-debug.c1
-rw-r--r--lib/dynamic_debug.c98
-rw-r--r--lib/idr.c13
-rw-r--r--lib/kobject.c39
5 files changed, 130 insertions, 32 deletions
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 21ac830..69a3266 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -353,7 +353,7 @@ config SLUB_DEBUG_ON
config SLUB_STATS
default n
bool "Enable SLUB performance statistics"
- depends on SLUB && SLUB_DEBUG && SYSFS
+ depends on SLUB && SYSFS
help
SLUB statistics are useful to debug SLUBs allocation behavior in
order find ways to optimize the allocator. This should never be
@@ -461,6 +461,15 @@ config DEBUG_MUTEXES
This feature allows mutex semantics violations to be detected and
reported.
+config BKL
+ bool "Big Kernel Lock" if (SMP || PREEMPT)
+ default y
+ help
+ This is the traditional lock that is used in old code instead
+ of proper locking. All drivers that use the BKL should depend
+ on this symbol.
+ Say Y here unless you are working on removing the BKL.
+
config DEBUG_LOCK_ALLOC
bool "Lock debugging: detect incorrect freeing of live locks"
depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT
diff --git a/lib/dma-debug.c b/lib/dma-debug.c
index 01e6427..4bfb047 100644
--- a/lib/dma-debug.c
+++ b/lib/dma-debug.c
@@ -590,6 +590,7 @@ out_unlock:
static const struct file_operations filter_fops = {
.read = filter_read,
.write = filter_write,
+ .llseek = default_llseek,
};
static int dma_debug_fs_init(void)
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 7bd6df7..3094318 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -393,6 +393,40 @@ static int ddebug_parse_flags(const char *str, unsigned int *flagsp,
return 0;
}
+static int ddebug_exec_query(char *query_string)
+{
+ unsigned int flags = 0, mask = 0;
+ struct ddebug_query query;
+#define MAXWORDS 9
+ int nwords;
+ char *words[MAXWORDS];
+
+ nwords = ddebug_tokenize(query_string, words, MAXWORDS);
+ if (nwords <= 0)
+ return -EINVAL;
+ if (ddebug_parse_query(words, nwords-1, &query))
+ return -EINVAL;
+ if (ddebug_parse_flags(words[nwords-1], &flags, &mask))
+ return -EINVAL;
+
+ /* actually go and implement the change */
+ ddebug_change(&query, flags, mask);
+ return 0;
+}
+
+static __initdata char ddebug_setup_string[1024];
+static __init int ddebug_setup_query(char *str)
+{
+ if (strlen(str) >= 1024) {
+ pr_warning("ddebug boot param string too large\n");
+ return 0;
+ }
+ strcpy(ddebug_setup_string, str);
+ return 1;
+}
+
+__setup("ddebug_query=", ddebug_setup_query);
+
/*
* File_ops->write method for <debugfs>/dynamic_debug/conrol. Gathers the
* command text from userspace, parses and executes it.
@@ -400,12 +434,8 @@ static int ddebug_parse_flags(const char *str, unsigned int *flagsp,
static ssize_t ddebug_proc_write(struct file *file, const char __user *ubuf,
size_t len, loff_t *offp)
{
- unsigned int flags = 0, mask = 0;
- struct ddebug_query query;
-#define MAXWORDS 9
- int nwords;
- char *words[MAXWORDS];
char tmpbuf[256];
+ int ret;
if (len == 0)
return 0;
@@ -419,16 +449,9 @@ static ssize_t ddebug_proc_write(struct file *file, const char __user *ubuf,
printk(KERN_INFO "%s: read %d bytes from userspace\n",
__func__, (int)len);
- nwords = ddebug_tokenize(tmpbuf, words, MAXWORDS);
- if (nwords <= 0)
- return -EINVAL;
- if (ddebug_parse_query(words, nwords-1, &query))
- return -EINVAL;
- if (ddebug_parse_flags(words[nwords-1], &flags, &mask))
- return -EINVAL;
-
- /* actually go and implement the change */
- ddebug_change(&query, flags, mask);
+ ret = ddebug_exec_query(tmpbuf);
+ if (ret)
+ return ret;
*offp += len;
return len;
@@ -689,13 +712,14 @@ static void ddebug_remove_all_tables(void)
mutex_unlock(&ddebug_lock);
}
-static int __init dynamic_debug_init(void)
+static __initdata int ddebug_init_success;
+
+static int __init dynamic_debug_init_debugfs(void)
{
struct dentry *dir, *file;
- struct _ddebug *iter, *iter_start;
- const char *modname = NULL;
- int ret = 0;
- int n = 0;
+
+ if (!ddebug_init_success)
+ return -ENODEV;
dir = debugfs_create_dir("dynamic_debug", NULL);
if (!dir)
@@ -706,6 +730,16 @@ static int __init dynamic_debug_init(void)
debugfs_remove(dir);
return -ENOMEM;
}
+ return 0;
+}
+
+static int __init dynamic_debug_init(void)
+{
+ struct _ddebug *iter, *iter_start;
+ const char *modname = NULL;
+ int ret = 0;
+ int n = 0;
+
if (__start___verbose != __stop___verbose) {
iter = __start___verbose;
modname = iter->modname;
@@ -723,12 +757,26 @@ static int __init dynamic_debug_init(void)
}
ret = ddebug_add_module(iter_start, n, modname);
}
+
+ /* ddebug_query boot param got passed -> set it up */
+ if (ddebug_setup_string[0] != '\0') {
+ ret = ddebug_exec_query(ddebug_setup_string);
+ if (ret)
+ pr_warning("Invalid ddebug boot param %s",
+ ddebug_setup_string);
+ else
+ pr_info("ddebug initialized with string %s",
+ ddebug_setup_string);
+ }
+
out_free:
- if (ret) {
+ if (ret)
ddebug_remove_all_tables();
- debugfs_remove(dir);
- debugfs_remove(file);
- }
+ else
+ ddebug_init_success = 1;
return 0;
}
-module_init(dynamic_debug_init);
+/* Allow early initialization for boot messages via boot param */
+arch_initcall(dynamic_debug_init);
+/* Debugfs setup must be done later */
+module_init(dynamic_debug_init_debugfs);
diff --git a/lib/idr.c b/lib/idr.c
index 7f1a4f0..5e0966b 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -284,7 +284,7 @@ static int idr_get_new_above_int(struct idr *idp, void *ptr, int starting_id)
* idr_get_new_above - allocate new idr entry above or equal to a start id
* @idp: idr handle
* @ptr: pointer you want associated with the id
- * @start_id: id to start search at
+ * @starting_id: id to start search at
* @id: pointer to the allocated handle
*
* This is the allocate id function. It should be called with any
@@ -479,7 +479,7 @@ EXPORT_SYMBOL(idr_remove_all);
/**
* idr_destroy - release all cached layers within an idr tree
- * idp: idr handle
+ * @idp: idr handle
*/
void idr_destroy(struct idr *idp)
{
@@ -586,10 +586,11 @@ EXPORT_SYMBOL(idr_for_each);
/**
* idr_get_next - lookup next object of id to given id.
* @idp: idr handle
- * @id: pointer to lookup key
+ * @nextidp: pointer to lookup key
*
* Returns pointer to registered object with id, which is next number to
- * given id.
+ * given id. After being looked up, *@nextidp will be updated for the next
+ * iteration.
*/
void *idr_get_next(struct idr *idp, int *nextidp)
@@ -758,7 +759,7 @@ EXPORT_SYMBOL(ida_pre_get);
/**
* ida_get_new_above - allocate new ID above or equal to a start id
* @ida: ida handle
- * @staring_id: id to start search at
+ * @starting_id: id to start search at
* @p_id: pointer to the allocated handle
*
* Allocate new ID above or equal to @ida. It should be called with
@@ -912,7 +913,7 @@ EXPORT_SYMBOL(ida_remove);
/**
* ida_destroy - release all cached layers within an ida tree
- * ida: ida handle
+ * @ida: ida handle
*/
void ida_destroy(struct ida *ida)
{
diff --git a/lib/kobject.c b/lib/kobject.c
index f07c572..82dc34c 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -746,17 +746,56 @@ void kset_unregister(struct kset *k)
*/
struct kobject *kset_find_obj(struct kset *kset, const char *name)
{
+ return kset_find_obj_hinted(kset, name, NULL);
+}
+
+/**
+ * kset_find_obj_hinted - search for object in kset given a predecessor hint.
+ * @kset: kset we're looking in.
+ * @name: object's name.
+ * @hint: hint to possible object's predecessor.
+ *
+ * Check the hint's next object and if it is a match return it directly,
+ * otherwise, fall back to the behavior of kset_find_obj(). Either way
+ * a reference for the returned object is held and the reference on the
+ * hinted object is released.
+ */
+struct kobject *kset_find_obj_hinted(struct kset *kset, const char *name,
+ struct kobject *hint)
+{
struct kobject *k;
struct kobject *ret = NULL;
spin_lock(&kset->list_lock);
+
+ if (!hint)
+ goto slow_search;
+
+ /* end of list detection */
+ if (hint->entry.next == kset->list.next)
+ goto slow_search;
+
+ k = container_of(hint->entry.next, struct kobject, entry);
+ if (!kobject_name(k) || strcmp(kobject_name(k), name))
+ goto slow_search;
+
+ ret = kobject_get(k);
+ goto unlock_exit;
+
+slow_search:
list_for_each_entry(k, &kset->list, entry) {
if (kobject_name(k) && !strcmp(kobject_name(k), name)) {
ret = kobject_get(k);
break;
}
}
+
+unlock_exit:
spin_unlock(&kset->list_lock);
+
+ if (hint)
+ kobject_put(hint);
+
return ret;
}