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 v2.6.29-rc7 414 lines 9.7 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 ret; 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 if (elem) { 281 if (value && (elem->enable == 0)) { 282 dynamic_printk_enabled |= (1LL << elem->hash1); 283 dynamic_printk_enabled2 |= (1LL << elem->hash2); 284 elem->enable = 1; 285 num_enabled++; 286 dynamic_enabled = DYNAMIC_ENABLED_SOME; 287 err = 0; 288 printk(KERN_DEBUG 289 "debugging enabled for module %s\n", 290 elem->name); 291 } else if (!value && (elem->enable == 1)) { 292 elem->enable = 0; 293 num_enabled--; 294 if (disabled_hash(elem->hash1, true)) 295 dynamic_printk_enabled &= 296 ~(1LL << elem->hash1); 297 if (disabled_hash(elem->hash2, false)) 298 dynamic_printk_enabled2 &= 299 ~(1LL << elem->hash2); 300 if (num_enabled) 301 dynamic_enabled = DYNAMIC_ENABLED_SOME; 302 else 303 dynamic_enabled = DYNAMIC_ENABLED_NONE; 304 err = 0; 305 printk(KERN_DEBUG 306 "debugging disabled for module %s\n", 307 elem->name); 308 } 309 } 310 } 311 if (!err) 312 err = length; 313out_up: 314 up(&debug_list_mutex); 315out: 316 free_page((unsigned long)buffer); 317 return err; 318} 319 320static void *pr_debug_seq_start(struct seq_file *f, loff_t *pos) 321{ 322 return (*pos < DEBUG_HASH_TABLE_SIZE) ? pos : NULL; 323} 324 325static void *pr_debug_seq_next(struct seq_file *s, void *v, loff_t *pos) 326{ 327 (*pos)++; 328 if (*pos >= DEBUG_HASH_TABLE_SIZE) 329 return NULL; 330 return pos; 331} 332 333static void pr_debug_seq_stop(struct seq_file *s, void *v) 334{ 335 /* Nothing to do */ 336} 337 338static int pr_debug_seq_show(struct seq_file *s, void *v) 339{ 340 struct hlist_head *head; 341 struct hlist_node *node; 342 struct debug_name *elem; 343 unsigned int i = *(loff_t *) v; 344 345 rcu_read_lock(); 346 head = &module_table[i]; 347 hlist_for_each_entry_rcu(elem, node, head, hlist) { 348 seq_printf(s, "%s enabled=%d", elem->name, elem->enable); 349 seq_printf(s, "\n"); 350 } 351 rcu_read_unlock(); 352 return 0; 353} 354 355static struct seq_operations pr_debug_seq_ops = { 356 .start = pr_debug_seq_start, 357 .next = pr_debug_seq_next, 358 .stop = pr_debug_seq_stop, 359 .show = pr_debug_seq_show 360}; 361 362static int pr_debug_open(struct inode *inode, struct file *filp) 363{ 364 return seq_open(filp, &pr_debug_seq_ops); 365} 366 367static const struct file_operations pr_debug_operations = { 368 .open = pr_debug_open, 369 .read = seq_read, 370 .write = pr_debug_write, 371 .llseek = seq_lseek, 372 .release = seq_release, 373}; 374 375static int __init dynamic_printk_init(void) 376{ 377 struct dentry *dir, *file; 378 struct mod_debug *iter; 379 unsigned long value; 380 381 dir = debugfs_create_dir("dynamic_printk", NULL); 382 if (!dir) 383 return -ENOMEM; 384 file = debugfs_create_file("modules", 0644, dir, NULL, 385 &pr_debug_operations); 386 if (!file) { 387 debugfs_remove(dir); 388 return -ENOMEM; 389 } 390 for (value = (unsigned long)__start___verbose; 391 value < (unsigned long)__stop___verbose; 392 value += sizeof(struct mod_debug)) { 393 iter = (struct mod_debug *)value; 394 register_dynamic_debug_module(iter->modname, 395 iter->type, 396 iter->logical_modname, 397 iter->flag_names, iter->hash, iter->hash2); 398 } 399 if (dynamic_enabled == DYNAMIC_ENABLED_ALL) 400 set_all(true); 401 return 0; 402} 403module_init(dynamic_printk_init); 404/* may want to move this earlier so we can get traces as early as possible */ 405 406static int __init dynamic_printk_setup(char *str) 407{ 408 if (str) 409 return -ENOENT; 410 dynamic_enabled = DYNAMIC_ENABLED_ALL; 411 return 0; 412} 413/* Use early_param(), so we can get debug output as early as possible */ 414early_param("dynamic_printk", dynamic_printk_setup);