Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at ddb4cbfc53aa0913ee8da059fcbf628d14f40f63 420 lines 9.8 kB view raw
1/* 2 * lib/dynamic_printk.c 3 * 4 * make pr_debug()/dev_dbg() calls runtime configurable based upon their 5 * their source module. 6 * 7 * Copyright (C) 2008 Red Hat, Inc., Jason Baron <jbaron@redhat.com> 8 */ 9 10#include <linux/kernel.h> 11#include <linux/module.h> 12#include <linux/uaccess.h> 13#include <linux/seq_file.h> 14#include <linux/debugfs.h> 15#include <linux/fs.h> 16 17extern struct mod_debug __start___verbose[]; 18extern struct mod_debug __stop___verbose[]; 19 20struct debug_name { 21 struct hlist_node hlist; 22 struct hlist_node hlist2; 23 int hash1; 24 int hash2; 25 char *name; 26 int enable; 27 int type; 28}; 29 30static int nr_entries; 31static int num_enabled; 32int dynamic_enabled = DYNAMIC_ENABLED_NONE; 33static struct hlist_head module_table[DEBUG_HASH_TABLE_SIZE] = 34 { [0 ... DEBUG_HASH_TABLE_SIZE-1] = HLIST_HEAD_INIT }; 35static struct hlist_head module_table2[DEBUG_HASH_TABLE_SIZE] = 36 { [0 ... DEBUG_HASH_TABLE_SIZE-1] = HLIST_HEAD_INIT }; 37static DECLARE_MUTEX(debug_list_mutex); 38 39/* dynamic_printk_enabled, and dynamic_printk_enabled2 are bitmasks in which 40 * bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They 41 * use independent hash functions, to reduce the chance of false positives. 42 */ 43long long dynamic_printk_enabled; 44EXPORT_SYMBOL_GPL(dynamic_printk_enabled); 45long long dynamic_printk_enabled2; 46EXPORT_SYMBOL_GPL(dynamic_printk_enabled2); 47 48/* returns the debug module pointer. */ 49static struct debug_name *find_debug_module(char *module_name) 50{ 51 int i; 52 struct hlist_head *head; 53 struct hlist_node *node; 54 struct debug_name *element; 55 56 element = NULL; 57 for (i = 0; i < DEBUG_HASH_TABLE_SIZE; i++) { 58 head = &module_table[i]; 59 hlist_for_each_entry_rcu(element, node, head, hlist) 60 if (!strcmp(element->name, module_name)) 61 return element; 62 } 63 return NULL; 64} 65 66/* returns the debug module pointer. */ 67static struct debug_name *find_debug_module_hash(char *module_name, int hash) 68{ 69 struct hlist_head *head; 70 struct hlist_node *node; 71 struct debug_name *element; 72 73 element = NULL; 74 head = &module_table[hash]; 75 hlist_for_each_entry_rcu(element, node, head, hlist) 76 if (!strcmp(element->name, module_name)) 77 return element; 78 return NULL; 79} 80 81/* caller must hold mutex*/ 82static int __add_debug_module(char *mod_name, int hash, int hash2) 83{ 84 struct debug_name *new; 85 char *module_name; 86 int ret = 0; 87 88 if (find_debug_module(mod_name)) { 89 ret = -EINVAL; 90 goto out; 91 } 92 module_name = kmalloc(strlen(mod_name) + 1, GFP_KERNEL); 93 if (!module_name) { 94 ret = -ENOMEM; 95 goto out; 96 } 97 module_name = strcpy(module_name, mod_name); 98 module_name[strlen(mod_name)] = '\0'; 99 new = kzalloc(sizeof(struct debug_name), GFP_KERNEL); 100 if (!new) { 101 kfree(module_name); 102 ret = -ENOMEM; 103 goto out; 104 } 105 INIT_HLIST_NODE(&new->hlist); 106 INIT_HLIST_NODE(&new->hlist2); 107 new->name = module_name; 108 new->hash1 = hash; 109 new->hash2 = hash2; 110 hlist_add_head_rcu(&new->hlist, &module_table[hash]); 111 hlist_add_head_rcu(&new->hlist2, &module_table2[hash2]); 112 nr_entries++; 113out: 114 return ret; 115} 116 117int unregister_dynamic_debug_module(char *mod_name) 118{ 119 struct debug_name *element; 120 int ret = 0; 121 122 down(&debug_list_mutex); 123 element = find_debug_module(mod_name); 124 if (!element) { 125 ret = -EINVAL; 126 goto out; 127 } 128 hlist_del_rcu(&element->hlist); 129 hlist_del_rcu(&element->hlist2); 130 synchronize_rcu(); 131 kfree(element->name); 132 if (element->enable) 133 num_enabled--; 134 kfree(element); 135 nr_entries--; 136out: 137 up(&debug_list_mutex); 138 return 0; 139} 140EXPORT_SYMBOL_GPL(unregister_dynamic_debug_module); 141 142int register_dynamic_debug_module(char *mod_name, int type, char *share_name, 143 char *flags, int hash, int hash2) 144{ 145 struct debug_name *elem; 146 int ret = 0; 147 148 down(&debug_list_mutex); 149 elem = find_debug_module(mod_name); 150 if (!elem) { 151 if (__add_debug_module(mod_name, hash, hash2)) 152 goto out; 153 elem = find_debug_module(mod_name); 154 if (dynamic_enabled == DYNAMIC_ENABLED_ALL && 155 !strcmp(mod_name, share_name)) { 156 elem->enable = true; 157 num_enabled++; 158 } 159 } 160 elem->type |= type; 161out: 162 up(&debug_list_mutex); 163 return ret; 164} 165EXPORT_SYMBOL_GPL(register_dynamic_debug_module); 166 167int __dynamic_dbg_enabled_helper(char *mod_name, int type, int value, int hash) 168{ 169 struct debug_name *elem; 170 int ret = 0; 171 172 if (dynamic_enabled == DYNAMIC_ENABLED_ALL) 173 return 1; 174 rcu_read_lock(); 175 elem = find_debug_module_hash(mod_name, hash); 176 if (elem && elem->enable) 177 ret = 1; 178 rcu_read_unlock(); 179 return ret; 180} 181EXPORT_SYMBOL_GPL(__dynamic_dbg_enabled_helper); 182 183static void set_all(bool enable) 184{ 185 struct debug_name *e; 186 struct hlist_node *node; 187 int i; 188 long long enable_mask; 189 190 for (i = 0; i < DEBUG_HASH_TABLE_SIZE; i++) { 191 if (module_table[i].first != NULL) { 192 hlist_for_each_entry(e, node, &module_table[i], hlist) { 193 e->enable = enable; 194 } 195 } 196 } 197 if (enable) 198 enable_mask = ULLONG_MAX; 199 else 200 enable_mask = 0; 201 dynamic_printk_enabled = enable_mask; 202 dynamic_printk_enabled2 = enable_mask; 203} 204 205static int disabled_hash(int i, bool first_table) 206{ 207 struct debug_name *e; 208 struct hlist_node *node; 209 210 if (first_table) { 211 hlist_for_each_entry(e, node, &module_table[i], hlist) { 212 if (e->enable) 213 return 0; 214 } 215 } else { 216 hlist_for_each_entry(e, node, &module_table2[i], hlist2) { 217 if (e->enable) 218 return 0; 219 } 220 } 221 return 1; 222} 223 224static ssize_t pr_debug_write(struct file *file, const char __user *buf, 225 size_t length, loff_t *ppos) 226{ 227 char *buffer, *s, *value_str, *setting_str; 228 int err, value; 229 struct debug_name *elem = NULL; 230 int all = 0; 231 232 if (length > PAGE_SIZE || length < 0) 233 return -EINVAL; 234 235 buffer = (char *)__get_free_page(GFP_KERNEL); 236 if (!buffer) 237 return -ENOMEM; 238 239 err = -EFAULT; 240 if (copy_from_user(buffer, buf, length)) 241 goto out; 242 243 err = -EINVAL; 244 if (length < PAGE_SIZE) 245 buffer[length] = '\0'; 246 else if (buffer[PAGE_SIZE-1]) 247 goto out; 248 249 err = -EINVAL; 250 down(&debug_list_mutex); 251 252 if (strncmp("set", buffer, 3)) 253 goto out_up; 254 s = buffer + 3; 255 setting_str = strsep(&s, "="); 256 if (s == NULL) 257 goto out_up; 258 setting_str = strstrip(setting_str); 259 value_str = strsep(&s, " "); 260 if (s == NULL) 261 goto out_up; 262 s = strstrip(s); 263 if (!strncmp(s, "all", 3)) 264 all = 1; 265 else 266 elem = find_debug_module(s); 267 if (!strncmp(setting_str, "enable", 6)) { 268 value = !!simple_strtol(value_str, NULL, 10); 269 if (all) { 270 if (value) { 271 set_all(true); 272 num_enabled = nr_entries; 273 dynamic_enabled = DYNAMIC_ENABLED_ALL; 274 } else { 275 set_all(false); 276 num_enabled = 0; 277 dynamic_enabled = DYNAMIC_ENABLED_NONE; 278 } 279 err = 0; 280 } else { 281 if (elem) { 282 if (value && (elem->enable == 0)) { 283 dynamic_printk_enabled |= 284 (1LL << elem->hash1); 285 dynamic_printk_enabled2 |= 286 (1LL << elem->hash2); 287 elem->enable = 1; 288 num_enabled++; 289 dynamic_enabled = DYNAMIC_ENABLED_SOME; 290 err = 0; 291 printk(KERN_DEBUG 292 "debugging enabled for module %s", 293 elem->name); 294 } else if (!value && (elem->enable == 1)) { 295 elem->enable = 0; 296 num_enabled--; 297 if (disabled_hash(elem->hash1, true)) 298 dynamic_printk_enabled &= 299 ~(1LL << elem->hash1); 300 if (disabled_hash(elem->hash2, false)) 301 dynamic_printk_enabled2 &= 302 ~(1LL << elem->hash2); 303 if (num_enabled) 304 dynamic_enabled = 305 DYNAMIC_ENABLED_SOME; 306 else 307 dynamic_enabled = 308 DYNAMIC_ENABLED_NONE; 309 err = 0; 310 printk(KERN_DEBUG 311 "debugging disabled for module " 312 "%s", elem->name); 313 } 314 } 315 } 316 } 317 if (!err) 318 err = length; 319out_up: 320 up(&debug_list_mutex); 321out: 322 free_page((unsigned long)buffer); 323 return err; 324} 325 326static void *pr_debug_seq_start(struct seq_file *f, loff_t *pos) 327{ 328 return (*pos < DEBUG_HASH_TABLE_SIZE) ? pos : NULL; 329} 330 331static void *pr_debug_seq_next(struct seq_file *s, void *v, loff_t *pos) 332{ 333 (*pos)++; 334 if (*pos >= DEBUG_HASH_TABLE_SIZE) 335 return NULL; 336 return pos; 337} 338 339static void pr_debug_seq_stop(struct seq_file *s, void *v) 340{ 341 /* Nothing to do */ 342} 343 344static int pr_debug_seq_show(struct seq_file *s, void *v) 345{ 346 struct hlist_head *head; 347 struct hlist_node *node; 348 struct debug_name *elem; 349 unsigned int i = *(loff_t *) v; 350 351 rcu_read_lock(); 352 head = &module_table[i]; 353 hlist_for_each_entry_rcu(elem, node, head, hlist) { 354 seq_printf(s, "%s enabled=%d", elem->name, elem->enable); 355 seq_printf(s, "\n"); 356 } 357 rcu_read_unlock(); 358 return 0; 359} 360 361static struct seq_operations pr_debug_seq_ops = { 362 .start = pr_debug_seq_start, 363 .next = pr_debug_seq_next, 364 .stop = pr_debug_seq_stop, 365 .show = pr_debug_seq_show 366}; 367 368static int pr_debug_open(struct inode *inode, struct file *filp) 369{ 370 return seq_open(filp, &pr_debug_seq_ops); 371} 372 373static const struct file_operations pr_debug_operations = { 374 .open = pr_debug_open, 375 .read = seq_read, 376 .write = pr_debug_write, 377 .llseek = seq_lseek, 378 .release = seq_release, 379}; 380 381static int __init dynamic_printk_init(void) 382{ 383 struct dentry *dir, *file; 384 struct mod_debug *iter; 385 unsigned long value; 386 387 dir = debugfs_create_dir("dynamic_printk", NULL); 388 if (!dir) 389 return -ENOMEM; 390 file = debugfs_create_file("modules", 0644, dir, NULL, 391 &pr_debug_operations); 392 if (!file) { 393 debugfs_remove(dir); 394 return -ENOMEM; 395 } 396 for (value = (unsigned long)__start___verbose; 397 value < (unsigned long)__stop___verbose; 398 value += sizeof(struct mod_debug)) { 399 iter = (struct mod_debug *)value; 400 register_dynamic_debug_module(iter->modname, 401 iter->type, 402 iter->logical_modname, 403 iter->flag_names, iter->hash, iter->hash2); 404 } 405 if (dynamic_enabled == DYNAMIC_ENABLED_ALL) 406 set_all(true); 407 return 0; 408} 409module_init(dynamic_printk_init); 410/* may want to move this earlier so we can get traces as early as possible */ 411 412static int __init dynamic_printk_setup(char *str) 413{ 414 if (str) 415 return -ENOENT; 416 dynamic_enabled = DYNAMIC_ENABLED_ALL; 417 return 0; 418} 419/* Use early_param(), so we can get debug output as early as possible */ 420early_param("dynamic_printk", dynamic_printk_setup);