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.c148
1 files changed, 80 insertions, 68 deletions
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index f93502915988..b335acb43be2 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
@@ -168,19 +141,10 @@ static void ddebug_change(const struct ddebug_query *query,
168 else if (!dp->flags) 141 else if (!dp->flags)
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 dp->enabled = 1;
173 (1LL << dp->primary_hash); 146 else
174 dynamic_debug_enabled2 |= 147 dp->enabled = 0;
175 (1LL << dp->secondary_hash);
176 } else {
177 if (disabled_hash(dp->primary_hash, true))
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 }
184 if (verbose) 148 if (verbose)
185 printk(KERN_INFO 149 printk(KERN_INFO
186 "ddebug: changed %s:%d [%s]%s %s\n", 150 "ddebug: changed %s:%d [%s]%s %s\n",
@@ -428,6 +392,40 @@ static int ddebug_parse_flags(const char *str, unsigned int *flagsp,
428 return 0; 392 return 0;
429} 393}
430 394
395static int ddebug_exec_query(char *query_string)
396{
397 unsigned int flags = 0, mask = 0;
398 struct ddebug_query query;
399#define MAXWORDS 9
400 int nwords;
401 char *words[MAXWORDS];
402
403 nwords = ddebug_tokenize(query_string, words, MAXWORDS);
404 if (nwords <= 0)
405 return -EINVAL;
406 if (ddebug_parse_query(words, nwords-1, &query))
407 return -EINVAL;
408 if (ddebug_parse_flags(words[nwords-1], &flags, &mask))
409 return -EINVAL;
410
411 /* actually go and implement the change */
412 ddebug_change(&query, flags, mask);
413 return 0;
414}
415
416static __initdata char ddebug_setup_string[1024];
417static __init int ddebug_setup_query(char *str)
418{
419 if (strlen(str) >= 1024) {
420 pr_warning("ddebug boot param string too large\n");
421 return 0;
422 }
423 strcpy(ddebug_setup_string, str);
424 return 1;
425}
426
427__setup("ddebug_query=", ddebug_setup_query);
428
431/* 429/*
432 * File_ops->write method for <debugfs>/dynamic_debug/conrol. Gathers the 430 * File_ops->write method for <debugfs>/dynamic_debug/conrol. Gathers the
433 * command text from userspace, parses and executes it. 431 * command text from userspace, parses and executes it.
@@ -435,12 +433,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, 433static ssize_t ddebug_proc_write(struct file *file, const char __user *ubuf,
436 size_t len, loff_t *offp) 434 size_t len, loff_t *offp)
437{ 435{
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]; 436 char tmpbuf[256];
437 int ret;
444 438
445 if (len == 0) 439 if (len == 0)
446 return 0; 440 return 0;
@@ -454,16 +448,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", 448 printk(KERN_INFO "%s: read %d bytes from userspace\n",
455 __func__, (int)len); 449 __func__, (int)len);
456 450
457 nwords = ddebug_tokenize(tmpbuf, words, MAXWORDS); 451 ret = ddebug_exec_query(tmpbuf);
458 if (nwords < 0) 452 if (ret)
459 return -EINVAL; 453 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 454
468 *offp += len; 455 *offp += len;
469 return len; 456 return len;
@@ -691,7 +678,7 @@ static void ddebug_table_free(struct ddebug_table *dt)
691 * Called in response to a module being unloaded. Removes 678 * Called in response to a module being unloaded. Removes
692 * any ddebug_table's which point at the module. 679 * any ddebug_table's which point at the module.
693 */ 680 */
694int ddebug_remove_module(char *mod_name) 681int ddebug_remove_module(const char *mod_name)
695{ 682{
696 struct ddebug_table *dt, *nextdt; 683 struct ddebug_table *dt, *nextdt;
697 int ret = -ENOENT; 684 int ret = -ENOENT;
@@ -724,13 +711,14 @@ static void ddebug_remove_all_tables(void)
724 mutex_unlock(&ddebug_lock); 711 mutex_unlock(&ddebug_lock);
725} 712}
726 713
727static int __init dynamic_debug_init(void) 714static __initdata int ddebug_init_success;
715
716static int __init dynamic_debug_init_debugfs(void)
728{ 717{
729 struct dentry *dir, *file; 718 struct dentry *dir, *file;
730 struct _ddebug *iter, *iter_start; 719
731 const char *modname = NULL; 720 if (!ddebug_init_success)
732 int ret = 0; 721 return -ENODEV;
733 int n = 0;
734 722
735 dir = debugfs_create_dir("dynamic_debug", NULL); 723 dir = debugfs_create_dir("dynamic_debug", NULL);
736 if (!dir) 724 if (!dir)
@@ -741,6 +729,16 @@ static int __init dynamic_debug_init(void)
741 debugfs_remove(dir); 729 debugfs_remove(dir);
742 return -ENOMEM; 730 return -ENOMEM;
743 } 731 }
732 return 0;
733}
734
735static int __init dynamic_debug_init(void)
736{
737 struct _ddebug *iter, *iter_start;
738 const char *modname = NULL;
739 int ret = 0;
740 int n = 0;
741
744 if (__start___verbose != __stop___verbose) { 742 if (__start___verbose != __stop___verbose) {
745 iter = __start___verbose; 743 iter = __start___verbose;
746 modname = iter->modname; 744 modname = iter->modname;
@@ -758,12 +756,26 @@ static int __init dynamic_debug_init(void)
758 } 756 }
759 ret = ddebug_add_module(iter_start, n, modname); 757 ret = ddebug_add_module(iter_start, n, modname);
760 } 758 }
759
760 /* ddebug_query boot param got passed -> set it up */
761 if (ddebug_setup_string[0] != '\0') {
762 ret = ddebug_exec_query(ddebug_setup_string);
763 if (ret)
764 pr_warning("Invalid ddebug boot param %s",
765 ddebug_setup_string);
766 else
767 pr_info("ddebug initialized with string %s",
768 ddebug_setup_string);
769 }
770
761out_free: 771out_free:
762 if (ret) { 772 if (ret)
763 ddebug_remove_all_tables(); 773 ddebug_remove_all_tables();
764 debugfs_remove(dir); 774 else
765 debugfs_remove(file); 775 ddebug_init_success = 1;
766 }
767 return 0; 776 return 0;
768} 777}
769module_init(dynamic_debug_init); 778/* Allow early initialization for boot messages via boot param */
779arch_initcall(dynamic_debug_init);
780/* Debugfs setup must be done later */
781module_init(dynamic_debug_init_debugfs);