diff options
author | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2008-10-23 04:49:28 -0400 |
---|---|---|
committer | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2008-12-03 06:14:33 -0500 |
commit | 552ff3179d1e93a3e982357544c059f3e9a5516e (patch) | |
tree | fb53c9ab1b19e1c98fc0a316859413723e34d186 | |
parent | 17c2f9f85c896b48a5d74a9155d99ec5b241a0e6 (diff) |
UBIFS: add debugfs support
We need to have a possibility to see various UBIFS variables
and ask UBIFS to dump various information. Debugfs is what
we need.
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
-rw-r--r-- | fs/ubifs/debug.c | 173 | ||||
-rw-r--r-- | fs/ubifs/debug.h | 27 | ||||
-rw-r--r-- | fs/ubifs/super.c | 12 | ||||
-rw-r--r-- | fs/ubifs/ubifs.h | 1 |
4 files changed, 193 insertions, 20 deletions
diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index 0332a856a082..56842772c804 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include "ubifs.h" | 32 | #include "ubifs.h" |
33 | #include <linux/module.h> | 33 | #include <linux/module.h> |
34 | #include <linux/moduleparam.h> | 34 | #include <linux/moduleparam.h> |
35 | #include <linux/debugfs.h> | ||
35 | 36 | ||
36 | #ifdef CONFIG_UBIFS_FS_DEBUG | 37 | #ifdef CONFIG_UBIFS_FS_DEBUG |
37 | 38 | ||
@@ -988,22 +989,20 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1, | |||
988 | err = 1; | 989 | err = 1; |
989 | key_read(c, &dent1->key, &key); | 990 | key_read(c, &dent1->key, &key); |
990 | if (keys_cmp(c, &zbr1->key, &key)) { | 991 | if (keys_cmp(c, &zbr1->key, &key)) { |
991 | dbg_err("1st entry at %d:%d has key %s", zbr1->lnum, | 992 | ubifs_err("1st entry at %d:%d has key %s", zbr1->lnum, |
992 | zbr1->offs, DBGKEY(&key)); | 993 | zbr1->offs, DBGKEY(&key)); |
993 | dbg_err("but it should have key %s according to tnc", | 994 | ubifs_err("but it should have key %s according to tnc", |
994 | DBGKEY(&zbr1->key)); | 995 | DBGKEY(&zbr1->key)); dbg_dump_node(c, dent1); |
995 | dbg_dump_node(c, dent1); | 996 | goto out_free; |
996 | goto out_free; | ||
997 | } | 997 | } |
998 | 998 | ||
999 | key_read(c, &dent2->key, &key); | 999 | key_read(c, &dent2->key, &key); |
1000 | if (keys_cmp(c, &zbr2->key, &key)) { | 1000 | if (keys_cmp(c, &zbr2->key, &key)) { |
1001 | dbg_err("2nd entry at %d:%d has key %s", zbr1->lnum, | 1001 | ubifs_err("2nd entry at %d:%d has key %s", zbr1->lnum, |
1002 | zbr1->offs, DBGKEY(&key)); | 1002 | zbr1->offs, DBGKEY(&key)); |
1003 | dbg_err("but it should have key %s according to tnc", | 1003 | ubifs_err("but it should have key %s according to tnc", |
1004 | DBGKEY(&zbr2->key)); | 1004 | DBGKEY(&zbr2->key)); dbg_dump_node(c, dent2); |
1005 | dbg_dump_node(c, dent2); | 1005 | goto out_free; |
1006 | goto out_free; | ||
1007 | } | 1006 | } |
1008 | 1007 | ||
1009 | nlen1 = le16_to_cpu(dent1->nlen); | 1008 | nlen1 = le16_to_cpu(dent1->nlen); |
@@ -1015,14 +1014,14 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1, | |||
1015 | goto out_free; | 1014 | goto out_free; |
1016 | } | 1015 | } |
1017 | if (cmp == 0 && nlen1 == nlen2) | 1016 | if (cmp == 0 && nlen1 == nlen2) |
1018 | dbg_err("2 xent/dent nodes with the same name"); | 1017 | ubifs_err("2 xent/dent nodes with the same name"); |
1019 | else | 1018 | else |
1020 | dbg_err("bad order of colliding key %s", | 1019 | ubifs_err("bad order of colliding key %s", |
1021 | DBGKEY(&key)); | 1020 | DBGKEY(&key)); |
1022 | 1021 | ||
1023 | dbg_msg("first node at %d:%d\n", zbr1->lnum, zbr1->offs); | 1022 | ubifs_msg("first node at %d:%d\n", zbr1->lnum, zbr1->offs); |
1024 | dbg_dump_node(c, dent1); | 1023 | dbg_dump_node(c, dent1); |
1025 | dbg_msg("second node at %d:%d\n", zbr2->lnum, zbr2->offs); | 1024 | ubifs_msg("second node at %d:%d\n", zbr2->lnum, zbr2->offs); |
1026 | dbg_dump_node(c, dent2); | 1025 | dbg_dump_node(c, dent2); |
1027 | 1026 | ||
1028 | out_free: | 1027 | out_free: |
@@ -2103,7 +2102,7 @@ static void failure_mode_init(struct ubifs_info *c) | |||
2103 | 2102 | ||
2104 | fmi = kmalloc(sizeof(struct failure_mode_info), GFP_NOFS); | 2103 | fmi = kmalloc(sizeof(struct failure_mode_info), GFP_NOFS); |
2105 | if (!fmi) { | 2104 | if (!fmi) { |
2106 | dbg_err("Failed to register failure mode - no memory"); | 2105 | ubifs_err("Failed to register failure mode - no memory"); |
2107 | return; | 2106 | return; |
2108 | } | 2107 | } |
2109 | fmi->c = c; | 2108 | fmi->c = c; |
@@ -2383,4 +2382,144 @@ void ubifs_debugging_exit(struct ubifs_info *c) | |||
2383 | kfree(c->dbg); | 2382 | kfree(c->dbg); |
2384 | } | 2383 | } |
2385 | 2384 | ||
2385 | /* | ||
2386 | * Root directory for UBIFS stuff in debugfs. Contains sub-directories which | ||
2387 | * contain the stuff specific to particular file-system mounts. | ||
2388 | */ | ||
2389 | static struct dentry *debugfs_rootdir; | ||
2390 | |||
2391 | /** | ||
2392 | * dbg_debugfs_init - initialize debugfs file-system. | ||
2393 | * | ||
2394 | * UBIFS uses debugfs file-system to expose various debugging knobs to | ||
2395 | * user-space. This function creates "ubifs" directory in the debugfs | ||
2396 | * file-system. Returns zero in case of success and a negative error code in | ||
2397 | * case of failure. | ||
2398 | */ | ||
2399 | int dbg_debugfs_init(void) | ||
2400 | { | ||
2401 | debugfs_rootdir = debugfs_create_dir("ubifs", NULL); | ||
2402 | if (IS_ERR(debugfs_rootdir)) { | ||
2403 | int err = PTR_ERR(debugfs_rootdir); | ||
2404 | ubifs_err("cannot create \"ubifs\" debugfs directory, " | ||
2405 | "error %d\n", err); | ||
2406 | return err; | ||
2407 | } | ||
2408 | |||
2409 | return 0; | ||
2410 | } | ||
2411 | |||
2412 | /** | ||
2413 | * dbg_debugfs_exit - remove the "ubifs" directory from debugfs file-system. | ||
2414 | */ | ||
2415 | void dbg_debugfs_exit(void) | ||
2416 | { | ||
2417 | debugfs_remove(debugfs_rootdir); | ||
2418 | } | ||
2419 | |||
2420 | static int open_debugfs_file(struct inode *inode, struct file *file) | ||
2421 | { | ||
2422 | file->private_data = inode->i_private; | ||
2423 | return 0; | ||
2424 | } | ||
2425 | |||
2426 | static ssize_t write_debugfs_file(struct file *file, const char __user *buf, | ||
2427 | size_t count, loff_t *ppos) | ||
2428 | { | ||
2429 | struct ubifs_info *c = file->private_data; | ||
2430 | struct ubifs_debug_info *d = c->dbg; | ||
2431 | |||
2432 | if (file->f_path.dentry == d->dump_lprops) | ||
2433 | dbg_dump_lprops(c); | ||
2434 | else if (file->f_path.dentry == d->dump_budg) { | ||
2435 | spin_lock(&c->space_lock); | ||
2436 | dbg_dump_budg(c); | ||
2437 | spin_unlock(&c->space_lock); | ||
2438 | } else if (file->f_path.dentry == d->dump_budg) { | ||
2439 | mutex_lock(&c->tnc_mutex); | ||
2440 | dbg_dump_tnc(c); | ||
2441 | mutex_unlock(&c->tnc_mutex); | ||
2442 | } else | ||
2443 | return -EINVAL; | ||
2444 | |||
2445 | *ppos += count; | ||
2446 | return count; | ||
2447 | } | ||
2448 | |||
2449 | static const struct file_operations debugfs_fops = { | ||
2450 | .open = open_debugfs_file, | ||
2451 | .write = write_debugfs_file, | ||
2452 | .owner = THIS_MODULE, | ||
2453 | }; | ||
2454 | |||
2455 | /** | ||
2456 | * dbg_debugfs_init_fs - initialize debugfs for UBIFS instance. | ||
2457 | * @c: UBIFS file-system description object | ||
2458 | * | ||
2459 | * This function creates all debugfs files for this instance of UBIFS. Returns | ||
2460 | * zero in case of success and a negative error code in case of failure. | ||
2461 | * | ||
2462 | * Note, the only reason we have not merged this function with the | ||
2463 | * 'ubifs_debugging_init()' function is because it is better to initialize | ||
2464 | * debugfs interfaces at the very end of the mount process, and remove them at | ||
2465 | * the very beginning of the mount process. | ||
2466 | */ | ||
2467 | int dbg_debugfs_init_fs(struct ubifs_info *c) | ||
2468 | { | ||
2469 | int err; | ||
2470 | const char *fname; | ||
2471 | struct dentry *dent; | ||
2472 | struct ubifs_debug_info *d = c->dbg; | ||
2473 | |||
2474 | sprintf(d->debugfs_dir_name, "ubi%d_%d", c->vi.ubi_num, c->vi.vol_id); | ||
2475 | d->debugfs_dir = debugfs_create_dir(d->debugfs_dir_name, | ||
2476 | debugfs_rootdir); | ||
2477 | if (IS_ERR(d->debugfs_dir)) { | ||
2478 | err = PTR_ERR(d->debugfs_dir); | ||
2479 | ubifs_err("cannot create \"%s\" debugfs directory, error %d\n", | ||
2480 | d->debugfs_dir_name, err); | ||
2481 | goto out; | ||
2482 | } | ||
2483 | |||
2484 | fname = "dump_lprops"; | ||
2485 | dent = debugfs_create_file(fname, S_IWUGO, d->debugfs_dir, c, | ||
2486 | &debugfs_fops); | ||
2487 | if (IS_ERR(dent)) | ||
2488 | goto out_remove; | ||
2489 | d->dump_lprops = dent; | ||
2490 | |||
2491 | fname = "dump_budg"; | ||
2492 | dent = debugfs_create_file(fname, S_IWUGO, d->debugfs_dir, c, | ||
2493 | &debugfs_fops); | ||
2494 | if (IS_ERR(dent)) | ||
2495 | goto out_remove; | ||
2496 | d->dump_budg = dent; | ||
2497 | |||
2498 | fname = "dump_tnc"; | ||
2499 | dent = debugfs_create_file(fname, S_IWUGO, d->debugfs_dir, c, | ||
2500 | &debugfs_fops); | ||
2501 | if (IS_ERR(dent)) | ||
2502 | goto out_remove; | ||
2503 | d->dump_tnc = dent; | ||
2504 | |||
2505 | return 0; | ||
2506 | |||
2507 | out_remove: | ||
2508 | err = PTR_ERR(dent); | ||
2509 | ubifs_err("cannot create \"%s\" debugfs directory, error %d\n", | ||
2510 | fname, err); | ||
2511 | debugfs_remove_recursive(d->debugfs_dir); | ||
2512 | out: | ||
2513 | return err; | ||
2514 | } | ||
2515 | |||
2516 | /** | ||
2517 | * dbg_debugfs_exit_fs - remove all debugfs files. | ||
2518 | * @c: UBIFS file-system description object | ||
2519 | */ | ||
2520 | void dbg_debugfs_exit_fs(struct ubifs_info *c) | ||
2521 | { | ||
2522 | debugfs_remove_recursive(c->dbg->debugfs_dir); | ||
2523 | } | ||
2524 | |||
2386 | #endif /* CONFIG_UBIFS_FS_DEBUG */ | 2525 | #endif /* CONFIG_UBIFS_FS_DEBUG */ |
diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h index d6ea1362d56a..a6b70f8aac9c 100644 --- a/fs/ubifs/debug.h +++ b/fs/ubifs/debug.h | |||
@@ -43,6 +43,13 @@ | |||
43 | * @new_nhead_offs: used by LPT tree size checker | 43 | * @new_nhead_offs: used by LPT tree size checker |
44 | * @new_ihead_lnum: used by debugging to check ihead_lnum | 44 | * @new_ihead_lnum: used by debugging to check ihead_lnum |
45 | * @new_ihead_offs: used by debugging to check ihead_offs | 45 | * @new_ihead_offs: used by debugging to check ihead_offs |
46 | * | ||
47 | * debugfs_dir_name: name of debugfs directory containing this file-system's | ||
48 | * files | ||
49 | * debugfs_dir: direntry object of the file-system debugfs directory | ||
50 | * dump_lprops: "dump lprops" debugfs knob | ||
51 | * dump_budg: "dump budgeting information" debugfs knob | ||
52 | * dump_tnc: "dump TNC" debugfs knob | ||
46 | */ | 53 | */ |
47 | struct ubifs_debug_info { | 54 | struct ubifs_debug_info { |
48 | void *buf; | 55 | void *buf; |
@@ -61,6 +68,12 @@ struct ubifs_debug_info { | |||
61 | int new_nhead_offs; | 68 | int new_nhead_offs; |
62 | int new_ihead_lnum; | 69 | int new_ihead_lnum; |
63 | int new_ihead_offs; | 70 | int new_ihead_offs; |
71 | |||
72 | char debugfs_dir_name[100]; | ||
73 | struct dentry *debugfs_dir; | ||
74 | struct dentry *dump_lprops; | ||
75 | struct dentry *dump_budg; | ||
76 | struct dentry *dump_tnc; | ||
64 | }; | 77 | }; |
65 | 78 | ||
66 | #define ubifs_assert(expr) do { \ | 79 | #define ubifs_assert(expr) do { \ |
@@ -251,7 +264,6 @@ int ubifs_debugging_init(struct ubifs_info *c); | |||
251 | void ubifs_debugging_exit(struct ubifs_info *c); | 264 | void ubifs_debugging_exit(struct ubifs_info *c); |
252 | 265 | ||
253 | /* Dump functions */ | 266 | /* Dump functions */ |
254 | |||
255 | const char *dbg_ntype(int type); | 267 | const char *dbg_ntype(int type); |
256 | const char *dbg_cstate(int cmt_state); | 268 | const char *dbg_cstate(int cmt_state); |
257 | const char *dbg_get_key_dump(const struct ubifs_info *c, | 269 | const char *dbg_get_key_dump(const struct ubifs_info *c, |
@@ -274,7 +286,6 @@ void dbg_dump_tnc(struct ubifs_info *c); | |||
274 | void dbg_dump_index(struct ubifs_info *c); | 286 | void dbg_dump_index(struct ubifs_info *c); |
275 | 287 | ||
276 | /* Checking helper functions */ | 288 | /* Checking helper functions */ |
277 | |||
278 | typedef int (*dbg_leaf_callback)(struct ubifs_info *c, | 289 | typedef int (*dbg_leaf_callback)(struct ubifs_info *c, |
279 | struct ubifs_zbranch *zbr, void *priv); | 290 | struct ubifs_zbranch *zbr, void *priv); |
280 | typedef int (*dbg_znode_callback)(struct ubifs_info *c, | 291 | typedef int (*dbg_znode_callback)(struct ubifs_info *c, |
@@ -354,6 +365,12 @@ static inline int dbg_change(struct ubi_volume_desc *desc, int lnum, | |||
354 | return dbg_leb_change(desc, lnum, buf, len, UBI_UNKNOWN); | 365 | return dbg_leb_change(desc, lnum, buf, len, UBI_UNKNOWN); |
355 | } | 366 | } |
356 | 367 | ||
368 | /* Debugfs-related stuff */ | ||
369 | int dbg_debugfs_init(void); | ||
370 | void dbg_debugfs_exit(void); | ||
371 | int dbg_debugfs_init_fs(struct ubifs_info *c); | ||
372 | void dbg_debugfs_exit_fs(struct ubifs_info *c); | ||
373 | |||
357 | #else /* !CONFIG_UBIFS_FS_DEBUG */ | 374 | #else /* !CONFIG_UBIFS_FS_DEBUG */ |
358 | 375 | ||
359 | /* Use "if (0)" to make compiler check arguments even if debugging is off */ | 376 | /* Use "if (0)" to make compiler check arguments even if debugging is off */ |
@@ -434,6 +451,10 @@ static inline int dbg_change(struct ubi_volume_desc *desc, int lnum, | |||
434 | #define dbg_force_in_the_gaps() 0 | 451 | #define dbg_force_in_the_gaps() 0 |
435 | #define dbg_failure_mode 0 | 452 | #define dbg_failure_mode 0 |
436 | 453 | ||
437 | #endif /* !CONFIG_UBIFS_FS_DEBUG */ | 454 | #define dbg_debugfs_init() 0 |
455 | #define dbg_debugfs_exit() | ||
456 | #define dbg_debugfs_init_fs(c) 0 | ||
457 | #define dbg_debugfs_exit_fs(c) 0 | ||
438 | 458 | ||
459 | #endif /* !CONFIG_UBIFS_FS_DEBUG */ | ||
439 | #endif /* !__UBIFS_DEBUG_H__ */ | 460 | #endif /* !__UBIFS_DEBUG_H__ */ |
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index ad44822059c7..2dbaa4fc2cbb 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c | |||
@@ -1258,6 +1258,10 @@ static int mount_ubifs(struct ubifs_info *c) | |||
1258 | } | 1258 | } |
1259 | } | 1259 | } |
1260 | 1260 | ||
1261 | err = dbg_debugfs_init_fs(c); | ||
1262 | if (err) | ||
1263 | goto out_infos; | ||
1264 | |||
1261 | err = dbg_check_filesystem(c); | 1265 | err = dbg_check_filesystem(c); |
1262 | if (err) | 1266 | if (err) |
1263 | goto out_infos; | 1267 | goto out_infos; |
@@ -1369,6 +1373,7 @@ static void ubifs_umount(struct ubifs_info *c) | |||
1369 | dbg_gen("un-mounting UBI device %d, volume %d", c->vi.ubi_num, | 1373 | dbg_gen("un-mounting UBI device %d, volume %d", c->vi.ubi_num, |
1370 | c->vi.vol_id); | 1374 | c->vi.vol_id); |
1371 | 1375 | ||
1376 | dbg_debugfs_exit_fs(c); | ||
1372 | spin_lock(&ubifs_infos_lock); | 1377 | spin_lock(&ubifs_infos_lock); |
1373 | list_del(&c->infos_list); | 1378 | list_del(&c->infos_list); |
1374 | spin_unlock(&ubifs_infos_lock); | 1379 | spin_unlock(&ubifs_infos_lock); |
@@ -2079,11 +2084,17 @@ static int __init ubifs_init(void) | |||
2079 | 2084 | ||
2080 | err = ubifs_compressors_init(); | 2085 | err = ubifs_compressors_init(); |
2081 | if (err) | 2086 | if (err) |
2087 | goto out_shrinker; | ||
2088 | |||
2089 | err = dbg_debugfs_init(); | ||
2090 | if (err) | ||
2082 | goto out_compr; | 2091 | goto out_compr; |
2083 | 2092 | ||
2084 | return 0; | 2093 | return 0; |
2085 | 2094 | ||
2086 | out_compr: | 2095 | out_compr: |
2096 | ubifs_compressors_exit(); | ||
2097 | out_shrinker: | ||
2087 | unregister_shrinker(&ubifs_shrinker_info); | 2098 | unregister_shrinker(&ubifs_shrinker_info); |
2088 | kmem_cache_destroy(ubifs_inode_slab); | 2099 | kmem_cache_destroy(ubifs_inode_slab); |
2089 | out_reg: | 2100 | out_reg: |
@@ -2098,6 +2109,7 @@ static void __exit ubifs_exit(void) | |||
2098 | ubifs_assert(list_empty(&ubifs_infos)); | 2109 | ubifs_assert(list_empty(&ubifs_infos)); |
2099 | ubifs_assert(atomic_long_read(&ubifs_clean_zn_cnt) == 0); | 2110 | ubifs_assert(atomic_long_read(&ubifs_clean_zn_cnt) == 0); |
2100 | 2111 | ||
2112 | dbg_debugfs_exit(); | ||
2101 | ubifs_compressors_exit(); | 2113 | ubifs_compressors_exit(); |
2102 | unregister_shrinker(&ubifs_shrinker_info); | 2114 | unregister_shrinker(&ubifs_shrinker_info); |
2103 | kmem_cache_destroy(ubifs_inode_slab); | 2115 | kmem_cache_destroy(ubifs_inode_slab); |
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index 7e090a5e2bf6..4cf28e85de78 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h | |||
@@ -1158,6 +1158,7 @@ struct ubifs_debug_info; | |||
1158 | * @mount_opts: UBIFS-specific mount options | 1158 | * @mount_opts: UBIFS-specific mount options |
1159 | * | 1159 | * |
1160 | * @dbg: debugging-related information | 1160 | * @dbg: debugging-related information |
1161 | * @dfs: debugfs support-related information | ||
1161 | */ | 1162 | */ |
1162 | struct ubifs_info { | 1163 | struct ubifs_info { |
1163 | struct super_block *vfs_sb; | 1164 | struct super_block *vfs_sb; |