aboutsummaryrefslogtreecommitdiffstats
path: root/lib/dynamic_debug.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dynamic_debug.c')
-rw-r--r--lib/dynamic_debug.c143
1 files changed, 78 insertions, 65 deletions
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index f93502915988..3094318bfea7 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -25,19 +25,12 @@
25#include <linux/uaccess.h> 25#include <linux/uaccess.h>
26#include <linux/dynamic_debug.h> 26#include <linux/dynamic_debug.h>
27#include <linux/debugfs.h> 27#include <linux/debugfs.h>
28#include <linux/slab.h>
29#include <linux/jump_label.h>
28 30
29extern struct _ddebug __start___verbose[]; 31extern struct _ddebug __start___verbose[];
30extern struct _ddebug __stop___verbose[]; 32extern struct _ddebug __stop___verbose[];
31 33
32/* dynamic_debug_enabled, and dynamic_debug_enabled2 are bitmasks in which
33 * bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They
34 * use independent hash functions, to reduce the chance of false positives.
35 */
36long long dynamic_debug_enabled;
37EXPORT_SYMBOL_GPL(dynamic_debug_enabled);
38long long dynamic_debug_enabled2;
39EXPORT_SYMBOL_GPL(dynamic_debug_enabled2);
40
41struct ddebug_table { 34struct ddebug_table {
42 struct list_head link; 35 struct list_head link;
43 char *mod_name; 36 char *mod_name;
@@ -87,26 +80,6 @@ static char *ddebug_describe_flags(struct _ddebug *dp, char *buf,
87} 80}
88 81
89/* 82/*
90 * must be called with ddebug_lock held
91 */
92
93static int disabled_hash(char hash, bool first_table)
94{
95 struct ddebug_table *dt;
96 char table_hash_value;
97
98 list_for_each_entry(dt, &ddebug_tables, link) {
99 if (first_table)
100 table_hash_value = dt->ddebugs->primary_hash;
101 else
102 table_hash_value = dt->ddebugs->secondary_hash;
103 if (dt->num_enabled && (hash == table_hash_value))
104 return 0;
105 }
106 return 1;
107}
108
109/*
110 * Search the tables for _ddebug's which match the given 83 * Search the tables for _ddebug's which match the given
111 * `query' and apply the `flags' and `mask' to them. Tells 84 * `query' and apply the `flags' and `mask' to them. Tells
112 * the user which ddebug's were changed, or whether none 85 * the user which ddebug's were changed, or whether none
@@ -169,17 +142,9 @@ static void ddebug_change(const struct ddebug_query *query,
169 dt->num_enabled++; 142 dt->num_enabled++;
170 dp->flags = newflags; 143 dp->flags = newflags;
171 if (newflags) { 144 if (newflags) {
172 dynamic_debug_enabled |= 145 jump_label_enable(&dp->enabled);
173 (1LL << dp->primary_hash);
174 dynamic_debug_enabled2 |=
175 (1LL << dp->secondary_hash);
176 } else { 146 } else {
177 if (disabled_hash(dp->primary_hash, true)) 147 jump_label_disable(&dp->enabled);
178 dynamic_debug_enabled &=
179 ~(1LL << dp->primary_hash);
180 if (disabled_hash(dp->secondary_hash, false))
181 dynamic_debug_enabled2 &=
182 ~(1LL << dp->secondary_hash);
183 } 148 }
184 if (verbose) 149 if (verbose)
185 printk(KERN_INFO 150 printk(KERN_INFO
@@ -428,6 +393,40 @@ static int ddebug_parse_flags(const char *str, unsigned int *flagsp,
428 return 0; 393 return 0;
429} 394}
430 395
396static int ddebug_exec_query(char *query_string)
397{
398 unsigned int flags = 0, mask = 0;
399 struct ddebug_query query;
400#define MAXWORDS 9
401 int nwords;
402 char *words[MAXWORDS];
403
404 nwords = ddebug_tokenize(query_string, words, MAXWORDS);
405 if (nwords <= 0)
406 return -EINVAL;
407 if (ddebug_parse_query(words, nwords-1, &query))
408 return -EINVAL;
409 if (ddebug_parse_flags(words[nwords-1], &flags, &mask))
410 return -EINVAL;
411
412 /* actually go and implement the change */
413 ddebug_change(&query, flags, mask);
414 return 0;
415}
416
417static __initdata char ddebug_setup_string[1024];
418static __init int ddebug_setup_query(char *str)
419{
420 if (strlen(str) >= 1024) {
421 pr_warning("ddebug boot param string too large\n");
422 return 0;
423 }
424 strcpy(ddebug_setup_string, str);
425 return 1;
426}
427
428__setup("ddebug_query=", ddebug_setup_query);
429
431/* 430/*
432 * File_ops->write method for <debugfs>/dynamic_debug/conrol. Gathers the 431 * File_ops->write method for <debugfs>/dynamic_debug/conrol. Gathers the
433 * command text from userspace, parses and executes it. 432 * command text from userspace, parses and executes it.
@@ -435,12 +434,8 @@ static int ddebug_parse_flags(const char *str, unsigned int *flagsp,
435static ssize_t ddebug_proc_write(struct file *file, const char __user *ubuf, 434static ssize_t ddebug_proc_write(struct file *file, const char __user *ubuf,
436 size_t len, loff_t *offp) 435 size_t len, loff_t *offp)
437{ 436{
438 unsigned int flags = 0, mask = 0;
439 struct ddebug_query query;
440#define MAXWORDS 9
441 int nwords;
442 char *words[MAXWORDS];
443 char tmpbuf[256]; 437 char tmpbuf[256];
438 int ret;
444 439
445 if (len == 0) 440 if (len == 0)
446 return 0; 441 return 0;
@@ -454,16 +449,9 @@ static ssize_t ddebug_proc_write(struct file *file, const char __user *ubuf,
454 printk(KERN_INFO "%s: read %d bytes from userspace\n", 449 printk(KERN_INFO "%s: read %d bytes from userspace\n",
455 __func__, (int)len); 450 __func__, (int)len);
456 451
457 nwords = ddebug_tokenize(tmpbuf, words, MAXWORDS); 452 ret = ddebug_exec_query(tmpbuf);
458 if (nwords < 0) 453 if (ret)
459 return -EINVAL; 454 return ret;
460 if (ddebug_parse_query(words, nwords-1, &query))
461 return -EINVAL;
462 if (ddebug_parse_flags(words[nwords-1], &flags, &mask))
463 return -EINVAL;
464
465 /* actually go and implement the change */
466 ddebug_change(&query, flags, mask);
467 455
468 *offp += len; 456 *offp += len;
469 return len; 457 return len;
@@ -691,7 +679,7 @@ static void ddebug_table_free(struct ddebug_table *dt)
691 * Called in response to a module being unloaded. Removes 679 * Called in response to a module being unloaded. Removes
692 * any ddebug_table's which point at the module. 680 * any ddebug_table's which point at the module.
693 */ 681 */
694int ddebug_remove_module(char *mod_name) 682int ddebug_remove_module(const char *mod_name)
695{ 683{
696 struct ddebug_table *dt, *nextdt; 684 struct ddebug_table *dt, *nextdt;
697 int ret = -ENOENT; 685 int ret = -ENOENT;
@@ -724,13 +712,14 @@ static void ddebug_remove_all_tables(void)
724 mutex_unlock(&ddebug_lock); 712 mutex_unlock(&ddebug_lock);
725} 713}
726 714
727static int __init dynamic_debug_init(void) 715static __initdata int ddebug_init_success;
716
717static int __init dynamic_debug_init_debugfs(void)
728{ 718{
729 struct dentry *dir, *file; 719 struct dentry *dir, *file;
730 struct _ddebug *iter, *iter_start; 720
731 const char *modname = NULL; 721 if (!ddebug_init_success)
732 int ret = 0; 722 return -ENODEV;
733 int n = 0;
734 723
735 dir = debugfs_create_dir("dynamic_debug", NULL); 724 dir = debugfs_create_dir("dynamic_debug", NULL);
736 if (!dir) 725 if (!dir)
@@ -741,6 +730,16 @@ static int __init dynamic_debug_init(void)
741 debugfs_remove(dir); 730 debugfs_remove(dir);
742 return -ENOMEM; 731 return -ENOMEM;
743 } 732 }
733 return 0;
734}
735
736static int __init dynamic_debug_init(void)
737{
738 struct _ddebug *iter, *iter_start;
739 const char *modname = NULL;
740 int ret = 0;
741 int n = 0;
742
744 if (__start___verbose != __stop___verbose) { 743 if (__start___verbose != __stop___verbose) {
745 iter = __start___verbose; 744 iter = __start___verbose;
746 modname = iter->modname; 745 modname = iter->modname;
@@ -758,12 +757,26 @@ static int __init dynamic_debug_init(void)
758 } 757 }
759 ret = ddebug_add_module(iter_start, n, modname); 758 ret = ddebug_add_module(iter_start, n, modname);
760 } 759 }
760
761 /* ddebug_query boot param got passed -> set it up */
762 if (ddebug_setup_string[0] != '\0') {
763 ret = ddebug_exec_query(ddebug_setup_string);
764 if (ret)
765 pr_warning("Invalid ddebug boot param %s",
766 ddebug_setup_string);
767 else
768 pr_info("ddebug initialized with string %s",
769 ddebug_setup_string);
770 }
771
761out_free: 772out_free:
762 if (ret) { 773 if (ret)
763 ddebug_remove_all_tables(); 774 ddebug_remove_all_tables();
764 debugfs_remove(dir); 775 else
765 debugfs_remove(file); 776 ddebug_init_success = 1;
766 }
767 return 0; 777 return 0;
768} 778}
769module_init(dynamic_debug_init); 779/* Allow early initialization for boot messages via boot param */
780arch_initcall(dynamic_debug_init);
781/* Debugfs setup must be done later */
782module_init(dynamic_debug_init_debugfs);