diff options
Diffstat (limited to 'fs/ubifs/debug.c')
| -rw-r--r-- | fs/ubifs/debug.c | 265 |
1 files changed, 233 insertions, 32 deletions
diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index 510ffa0bbda4..792c5a16c182 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c | |||
| @@ -32,6 +32,8 @@ | |||
| 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> | ||
| 36 | #include <linux/math64.h> | ||
| 35 | 37 | ||
| 36 | #ifdef CONFIG_UBIFS_FS_DEBUG | 38 | #ifdef CONFIG_UBIFS_FS_DEBUG |
| 37 | 39 | ||
| @@ -596,7 +598,9 @@ void dbg_dump_budg(struct ubifs_info *c) | |||
| 596 | struct rb_node *rb; | 598 | struct rb_node *rb; |
| 597 | struct ubifs_bud *bud; | 599 | struct ubifs_bud *bud; |
| 598 | struct ubifs_gced_idx_leb *idx_gc; | 600 | struct ubifs_gced_idx_leb *idx_gc; |
| 601 | long long available, outstanding, free; | ||
| 599 | 602 | ||
| 603 | ubifs_assert(spin_is_locked(&c->space_lock)); | ||
| 600 | spin_lock(&dbg_lock); | 604 | spin_lock(&dbg_lock); |
| 601 | printk(KERN_DEBUG "(pid %d) Budgeting info: budg_data_growth %lld, " | 605 | printk(KERN_DEBUG "(pid %d) Budgeting info: budg_data_growth %lld, " |
| 602 | "budg_dd_growth %lld, budg_idx_growth %lld\n", current->pid, | 606 | "budg_dd_growth %lld, budg_idx_growth %lld\n", current->pid, |
| @@ -629,6 +633,17 @@ void dbg_dump_budg(struct ubifs_info *c) | |||
| 629 | printk(KERN_DEBUG "\tGC'ed idx LEB %d unmap %d\n", | 633 | printk(KERN_DEBUG "\tGC'ed idx LEB %d unmap %d\n", |
| 630 | idx_gc->lnum, idx_gc->unmap); | 634 | idx_gc->lnum, idx_gc->unmap); |
| 631 | printk(KERN_DEBUG "\tcommit state %d\n", c->cmt_state); | 635 | printk(KERN_DEBUG "\tcommit state %d\n", c->cmt_state); |
| 636 | |||
| 637 | /* Print budgeting predictions */ | ||
| 638 | available = ubifs_calc_available(c, c->min_idx_lebs); | ||
| 639 | outstanding = c->budg_data_growth + c->budg_dd_growth; | ||
| 640 | if (available > outstanding) | ||
| 641 | free = ubifs_reported_space(c, available - outstanding); | ||
| 642 | else | ||
| 643 | free = 0; | ||
| 644 | printk(KERN_DEBUG "Budgeting predictions:\n"); | ||
| 645 | printk(KERN_DEBUG "\tavailable: %lld, outstanding %lld, free %lld\n", | ||
| 646 | available, outstanding, free); | ||
| 632 | spin_unlock(&dbg_lock); | 647 | spin_unlock(&dbg_lock); |
| 633 | } | 648 | } |
| 634 | 649 | ||
| @@ -645,7 +660,8 @@ void dbg_dump_lprops(struct ubifs_info *c) | |||
| 645 | struct ubifs_lprops lp; | 660 | struct ubifs_lprops lp; |
| 646 | struct ubifs_lp_stats lst; | 661 | struct ubifs_lp_stats lst; |
| 647 | 662 | ||
| 648 | printk(KERN_DEBUG "(pid %d) Dumping LEB properties\n", current->pid); | 663 | printk(KERN_DEBUG "(pid %d) start dumping LEB properties\n", |
| 664 | current->pid); | ||
| 649 | ubifs_get_lp_stats(c, &lst); | 665 | ubifs_get_lp_stats(c, &lst); |
| 650 | dbg_dump_lstats(&lst); | 666 | dbg_dump_lstats(&lst); |
| 651 | 667 | ||
| @@ -656,6 +672,8 @@ void dbg_dump_lprops(struct ubifs_info *c) | |||
| 656 | 672 | ||
| 657 | dbg_dump_lprop(c, &lp); | 673 | dbg_dump_lprop(c, &lp); |
| 658 | } | 674 | } |
| 675 | printk(KERN_DEBUG "(pid %d) finish dumping LEB properties\n", | ||
| 676 | current->pid); | ||
| 659 | } | 677 | } |
| 660 | 678 | ||
| 661 | void dbg_dump_lpt_info(struct ubifs_info *c) | 679 | void dbg_dump_lpt_info(struct ubifs_info *c) |
| @@ -663,6 +681,7 @@ void dbg_dump_lpt_info(struct ubifs_info *c) | |||
| 663 | int i; | 681 | int i; |
| 664 | 682 | ||
| 665 | spin_lock(&dbg_lock); | 683 | spin_lock(&dbg_lock); |
| 684 | printk(KERN_DEBUG "(pid %d) dumping LPT information\n", current->pid); | ||
| 666 | printk(KERN_DEBUG "\tlpt_sz: %lld\n", c->lpt_sz); | 685 | printk(KERN_DEBUG "\tlpt_sz: %lld\n", c->lpt_sz); |
| 667 | printk(KERN_DEBUG "\tpnode_sz: %d\n", c->pnode_sz); | 686 | printk(KERN_DEBUG "\tpnode_sz: %d\n", c->pnode_sz); |
| 668 | printk(KERN_DEBUG "\tnnode_sz: %d\n", c->nnode_sz); | 687 | printk(KERN_DEBUG "\tnnode_sz: %d\n", c->nnode_sz); |
| @@ -684,7 +703,8 @@ void dbg_dump_lpt_info(struct ubifs_info *c) | |||
| 684 | printk(KERN_DEBUG "\tLPT root is at %d:%d\n", c->lpt_lnum, c->lpt_offs); | 703 | printk(KERN_DEBUG "\tLPT root is at %d:%d\n", c->lpt_lnum, c->lpt_offs); |
| 685 | printk(KERN_DEBUG "\tLPT head is at %d:%d\n", | 704 | printk(KERN_DEBUG "\tLPT head is at %d:%d\n", |
| 686 | c->nhead_lnum, c->nhead_offs); | 705 | c->nhead_lnum, c->nhead_offs); |
| 687 | printk(KERN_DEBUG "\tLPT ltab is at %d:%d\n", c->ltab_lnum, c->ltab_offs); | 706 | printk(KERN_DEBUG "\tLPT ltab is at %d:%d\n", |
| 707 | c->ltab_lnum, c->ltab_offs); | ||
| 688 | if (c->big_lpt) | 708 | if (c->big_lpt) |
| 689 | printk(KERN_DEBUG "\tLPT lsave is at %d:%d\n", | 709 | printk(KERN_DEBUG "\tLPT lsave is at %d:%d\n", |
| 690 | c->lsave_lnum, c->lsave_offs); | 710 | c->lsave_lnum, c->lsave_offs); |
| @@ -703,9 +723,9 @@ void dbg_dump_leb(const struct ubifs_info *c, int lnum) | |||
| 703 | if (dbg_failure_mode) | 723 | if (dbg_failure_mode) |
| 704 | return; | 724 | return; |
| 705 | 725 | ||
| 706 | printk(KERN_DEBUG "(pid %d) Dumping LEB %d\n", current->pid, lnum); | 726 | printk(KERN_DEBUG "(pid %d) start dumping LEB %d\n", |
| 707 | 727 | current->pid, lnum); | |
| 708 | sleb = ubifs_scan(c, lnum, 0, c->dbg_buf); | 728 | sleb = ubifs_scan(c, lnum, 0, c->dbg->buf); |
| 709 | if (IS_ERR(sleb)) { | 729 | if (IS_ERR(sleb)) { |
| 710 | ubifs_err("scan error %d", (int)PTR_ERR(sleb)); | 730 | ubifs_err("scan error %d", (int)PTR_ERR(sleb)); |
| 711 | return; | 731 | return; |
| @@ -721,6 +741,8 @@ void dbg_dump_leb(const struct ubifs_info *c, int lnum) | |||
| 721 | dbg_dump_node(c, snod->node); | 741 | dbg_dump_node(c, snod->node); |
| 722 | } | 742 | } |
| 723 | 743 | ||
| 744 | printk(KERN_DEBUG "(pid %d) finish dumping LEB %d\n", | ||
| 745 | current->pid, lnum); | ||
| 724 | ubifs_scan_destroy(sleb); | 746 | ubifs_scan_destroy(sleb); |
| 725 | return; | 747 | return; |
| 726 | } | 748 | } |
| @@ -768,7 +790,7 @@ void dbg_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat) | |||
| 768 | { | 790 | { |
| 769 | int i; | 791 | int i; |
| 770 | 792 | ||
| 771 | printk(KERN_DEBUG "(pid %d) Dumping heap cat %d (%d elements)\n", | 793 | printk(KERN_DEBUG "(pid %d) start dumping heap cat %d (%d elements)\n", |
| 772 | current->pid, cat, heap->cnt); | 794 | current->pid, cat, heap->cnt); |
| 773 | for (i = 0; i < heap->cnt; i++) { | 795 | for (i = 0; i < heap->cnt; i++) { |
| 774 | struct ubifs_lprops *lprops = heap->arr[i]; | 796 | struct ubifs_lprops *lprops = heap->arr[i]; |
| @@ -777,6 +799,7 @@ void dbg_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat) | |||
| 777 | "flags %d\n", i, lprops->lnum, lprops->hpos, | 799 | "flags %d\n", i, lprops->lnum, lprops->hpos, |
| 778 | lprops->free, lprops->dirty, lprops->flags); | 800 | lprops->free, lprops->dirty, lprops->flags); |
| 779 | } | 801 | } |
| 802 | printk(KERN_DEBUG "(pid %d) finish dumping heap\n", current->pid); | ||
| 780 | } | 803 | } |
| 781 | 804 | ||
| 782 | void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode, | 805 | void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode, |
| @@ -784,7 +807,7 @@ void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode, | |||
| 784 | { | 807 | { |
| 785 | int i; | 808 | int i; |
| 786 | 809 | ||
| 787 | printk(KERN_DEBUG "(pid %d) Dumping pnode:\n", current->pid); | 810 | printk(KERN_DEBUG "(pid %d) dumping pnode:\n", current->pid); |
| 788 | printk(KERN_DEBUG "\taddress %zx parent %zx cnext %zx\n", | 811 | printk(KERN_DEBUG "\taddress %zx parent %zx cnext %zx\n", |
| 789 | (size_t)pnode, (size_t)parent, (size_t)pnode->cnext); | 812 | (size_t)pnode, (size_t)parent, (size_t)pnode->cnext); |
| 790 | printk(KERN_DEBUG "\tflags %lu iip %d level %d num %d\n", | 813 | printk(KERN_DEBUG "\tflags %lu iip %d level %d num %d\n", |
| @@ -803,7 +826,7 @@ void dbg_dump_tnc(struct ubifs_info *c) | |||
| 803 | int level; | 826 | int level; |
| 804 | 827 | ||
| 805 | printk(KERN_DEBUG "\n"); | 828 | printk(KERN_DEBUG "\n"); |
| 806 | printk(KERN_DEBUG "(pid %d) Dumping the TNC tree\n", current->pid); | 829 | printk(KERN_DEBUG "(pid %d) start dumping TNC tree\n", current->pid); |
| 807 | znode = ubifs_tnc_levelorder_next(c->zroot.znode, NULL); | 830 | znode = ubifs_tnc_levelorder_next(c->zroot.znode, NULL); |
| 808 | level = znode->level; | 831 | level = znode->level; |
| 809 | printk(KERN_DEBUG "== Level %d ==\n", level); | 832 | printk(KERN_DEBUG "== Level %d ==\n", level); |
| @@ -815,8 +838,7 @@ void dbg_dump_tnc(struct ubifs_info *c) | |||
| 815 | dbg_dump_znode(c, znode); | 838 | dbg_dump_znode(c, znode); |
| 816 | znode = ubifs_tnc_levelorder_next(c->zroot.znode, znode); | 839 | znode = ubifs_tnc_levelorder_next(c->zroot.znode, znode); |
| 817 | } | 840 | } |
| 818 | 841 | printk(KERN_DEBUG "(pid %d) finish dumping TNC tree\n", current->pid); | |
| 819 | printk(KERN_DEBUG "\n"); | ||
| 820 | } | 842 | } |
| 821 | 843 | ||
| 822 | static int dump_znode(struct ubifs_info *c, struct ubifs_znode *znode, | 844 | static int dump_znode(struct ubifs_info *c, struct ubifs_znode *znode, |
| @@ -992,8 +1014,8 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1, | |||
| 992 | zbr1->offs, DBGKEY(&key)); | 1014 | zbr1->offs, DBGKEY(&key)); |
| 993 | dbg_err("but it should have key %s according to tnc", | 1015 | dbg_err("but it should have key %s according to tnc", |
| 994 | DBGKEY(&zbr1->key)); | 1016 | DBGKEY(&zbr1->key)); |
| 995 | dbg_dump_node(c, dent1); | 1017 | dbg_dump_node(c, dent1); |
| 996 | goto out_free; | 1018 | goto out_free; |
| 997 | } | 1019 | } |
| 998 | 1020 | ||
| 999 | key_read(c, &dent2->key, &key); | 1021 | key_read(c, &dent2->key, &key); |
| @@ -1002,8 +1024,8 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1, | |||
| 1002 | zbr1->offs, DBGKEY(&key)); | 1024 | zbr1->offs, DBGKEY(&key)); |
| 1003 | dbg_err("but it should have key %s according to tnc", | 1025 | dbg_err("but it should have key %s according to tnc", |
| 1004 | DBGKEY(&zbr2->key)); | 1026 | DBGKEY(&zbr2->key)); |
| 1005 | dbg_dump_node(c, dent2); | 1027 | dbg_dump_node(c, dent2); |
| 1006 | goto out_free; | 1028 | goto out_free; |
| 1007 | } | 1029 | } |
| 1008 | 1030 | ||
| 1009 | nlen1 = le16_to_cpu(dent1->nlen); | 1031 | nlen1 = le16_to_cpu(dent1->nlen); |
| @@ -1020,9 +1042,9 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1, | |||
| 1020 | dbg_err("bad order of colliding key %s", | 1042 | dbg_err("bad order of colliding key %s", |
| 1021 | DBGKEY(&key)); | 1043 | DBGKEY(&key)); |
| 1022 | 1044 | ||
| 1023 | dbg_msg("first node at %d:%d\n", zbr1->lnum, zbr1->offs); | 1045 | ubifs_msg("first node at %d:%d\n", zbr1->lnum, zbr1->offs); |
| 1024 | dbg_dump_node(c, dent1); | 1046 | dbg_dump_node(c, dent1); |
| 1025 | dbg_msg("second node at %d:%d\n", zbr2->lnum, zbr2->offs); | 1047 | ubifs_msg("second node at %d:%d\n", zbr2->lnum, zbr2->offs); |
| 1026 | dbg_dump_node(c, dent2); | 1048 | dbg_dump_node(c, dent2); |
| 1027 | 1049 | ||
| 1028 | out_free: | 1050 | out_free: |
| @@ -2097,13 +2119,13 @@ static int simple_rand(void) | |||
| 2097 | return (next >> 16) & 32767; | 2119 | return (next >> 16) & 32767; |
| 2098 | } | 2120 | } |
| 2099 | 2121 | ||
| 2100 | void dbg_failure_mode_registration(struct ubifs_info *c) | 2122 | static void failure_mode_init(struct ubifs_info *c) |
| 2101 | { | 2123 | { |
| 2102 | struct failure_mode_info *fmi; | 2124 | struct failure_mode_info *fmi; |
| 2103 | 2125 | ||
| 2104 | fmi = kmalloc(sizeof(struct failure_mode_info), GFP_NOFS); | 2126 | fmi = kmalloc(sizeof(struct failure_mode_info), GFP_NOFS); |
| 2105 | if (!fmi) { | 2127 | if (!fmi) { |
| 2106 | dbg_err("Failed to register failure mode - no memory"); | 2128 | ubifs_err("Failed to register failure mode - no memory"); |
| 2107 | return; | 2129 | return; |
| 2108 | } | 2130 | } |
| 2109 | fmi->c = c; | 2131 | fmi->c = c; |
| @@ -2112,7 +2134,7 @@ void dbg_failure_mode_registration(struct ubifs_info *c) | |||
| 2112 | spin_unlock(&fmi_lock); | 2134 | spin_unlock(&fmi_lock); |
| 2113 | } | 2135 | } |
| 2114 | 2136 | ||
| 2115 | void dbg_failure_mode_deregistration(struct ubifs_info *c) | 2137 | static void failure_mode_exit(struct ubifs_info *c) |
| 2116 | { | 2138 | { |
| 2117 | struct failure_mode_info *fmi, *tmp; | 2139 | struct failure_mode_info *fmi, *tmp; |
| 2118 | 2140 | ||
| @@ -2146,42 +2168,44 @@ static int in_failure_mode(struct ubi_volume_desc *desc) | |||
| 2146 | struct ubifs_info *c = dbg_find_info(desc); | 2168 | struct ubifs_info *c = dbg_find_info(desc); |
| 2147 | 2169 | ||
| 2148 | if (c && dbg_failure_mode) | 2170 | if (c && dbg_failure_mode) |
| 2149 | return c->failure_mode; | 2171 | return c->dbg->failure_mode; |
| 2150 | return 0; | 2172 | return 0; |
| 2151 | } | 2173 | } |
| 2152 | 2174 | ||
| 2153 | static int do_fail(struct ubi_volume_desc *desc, int lnum, int write) | 2175 | static int do_fail(struct ubi_volume_desc *desc, int lnum, int write) |
| 2154 | { | 2176 | { |
| 2155 | struct ubifs_info *c = dbg_find_info(desc); | 2177 | struct ubifs_info *c = dbg_find_info(desc); |
| 2178 | struct ubifs_debug_info *d; | ||
| 2156 | 2179 | ||
| 2157 | if (!c || !dbg_failure_mode) | 2180 | if (!c || !dbg_failure_mode) |
| 2158 | return 0; | 2181 | return 0; |
| 2159 | if (c->failure_mode) | 2182 | d = c->dbg; |
| 2183 | if (d->failure_mode) | ||
| 2160 | return 1; | 2184 | return 1; |
| 2161 | if (!c->fail_cnt) { | 2185 | if (!d->fail_cnt) { |
| 2162 | /* First call - decide delay to failure */ | 2186 | /* First call - decide delay to failure */ |
| 2163 | if (chance(1, 2)) { | 2187 | if (chance(1, 2)) { |
| 2164 | unsigned int delay = 1 << (simple_rand() >> 11); | 2188 | unsigned int delay = 1 << (simple_rand() >> 11); |
| 2165 | 2189 | ||
| 2166 | if (chance(1, 2)) { | 2190 | if (chance(1, 2)) { |
| 2167 | c->fail_delay = 1; | 2191 | d->fail_delay = 1; |
| 2168 | c->fail_timeout = jiffies + | 2192 | d->fail_timeout = jiffies + |
| 2169 | msecs_to_jiffies(delay); | 2193 | msecs_to_jiffies(delay); |
| 2170 | dbg_rcvry("failing after %ums", delay); | 2194 | dbg_rcvry("failing after %ums", delay); |
| 2171 | } else { | 2195 | } else { |
| 2172 | c->fail_delay = 2; | 2196 | d->fail_delay = 2; |
| 2173 | c->fail_cnt_max = delay; | 2197 | d->fail_cnt_max = delay; |
| 2174 | dbg_rcvry("failing after %u calls", delay); | 2198 | dbg_rcvry("failing after %u calls", delay); |
| 2175 | } | 2199 | } |
| 2176 | } | 2200 | } |
| 2177 | c->fail_cnt += 1; | 2201 | d->fail_cnt += 1; |
| 2178 | } | 2202 | } |
| 2179 | /* Determine if failure delay has expired */ | 2203 | /* Determine if failure delay has expired */ |
| 2180 | if (c->fail_delay == 1) { | 2204 | if (d->fail_delay == 1) { |
| 2181 | if (time_before(jiffies, c->fail_timeout)) | 2205 | if (time_before(jiffies, d->fail_timeout)) |
| 2182 | return 0; | 2206 | return 0; |
| 2183 | } else if (c->fail_delay == 2) | 2207 | } else if (d->fail_delay == 2) |
| 2184 | if (c->fail_cnt++ < c->fail_cnt_max) | 2208 | if (d->fail_cnt++ < d->fail_cnt_max) |
| 2185 | return 0; | 2209 | return 0; |
| 2186 | if (lnum == UBIFS_SB_LNUM) { | 2210 | if (lnum == UBIFS_SB_LNUM) { |
| 2187 | if (write) { | 2211 | if (write) { |
| @@ -2239,7 +2263,7 @@ static int do_fail(struct ubi_volume_desc *desc, int lnum, int write) | |||
| 2239 | dbg_rcvry("failing in bud LEB %d commit not running", lnum); | 2263 | dbg_rcvry("failing in bud LEB %d commit not running", lnum); |
| 2240 | } | 2264 | } |
| 2241 | ubifs_err("*** SETTING FAILURE MODE ON (LEB %d) ***", lnum); | 2265 | ubifs_err("*** SETTING FAILURE MODE ON (LEB %d) ***", lnum); |
| 2242 | c->failure_mode = 1; | 2266 | d->failure_mode = 1; |
| 2243 | dump_stack(); | 2267 | dump_stack(); |
| 2244 | return 1; | 2268 | return 1; |
| 2245 | } | 2269 | } |
| @@ -2344,4 +2368,181 @@ int dbg_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype) | |||
| 2344 | return 0; | 2368 | return 0; |
| 2345 | } | 2369 | } |
| 2346 | 2370 | ||
| 2371 | /** | ||
| 2372 | * ubifs_debugging_init - initialize UBIFS debugging. | ||
| 2373 | * @c: UBIFS file-system description object | ||
| 2374 | * | ||
| 2375 | * This function initializes debugging-related data for the file system. | ||
| 2376 | * Returns zero in case of success and a negative error code in case of | ||
| 2377 | * failure. | ||
| 2378 | */ | ||
| 2379 | int ubifs_debugging_init(struct ubifs_info *c) | ||
| 2380 | { | ||
| 2381 | c->dbg = kzalloc(sizeof(struct ubifs_debug_info), GFP_KERNEL); | ||
| 2382 | if (!c->dbg) | ||
| 2383 | return -ENOMEM; | ||
| 2384 | |||
| 2385 | c->dbg->buf = vmalloc(c->leb_size); | ||
| 2386 | if (!c->dbg->buf) | ||
| 2387 | goto out; | ||
| 2388 | |||
| 2389 | failure_mode_init(c); | ||
| 2390 | return 0; | ||
| 2391 | |||
| 2392 | out: | ||
| 2393 | kfree(c->dbg); | ||
| 2394 | return -ENOMEM; | ||
| 2395 | } | ||
| 2396 | |||
| 2397 | /** | ||
| 2398 | * ubifs_debugging_exit - free debugging data. | ||
| 2399 | * @c: UBIFS file-system description object | ||
| 2400 | */ | ||
| 2401 | void ubifs_debugging_exit(struct ubifs_info *c) | ||
| 2402 | { | ||
| 2403 | failure_mode_exit(c); | ||
| 2404 | vfree(c->dbg->buf); | ||
| 2405 | kfree(c->dbg); | ||
| 2406 | } | ||
| 2407 | |||
| 2408 | /* | ||
| 2409 | * Root directory for UBIFS stuff in debugfs. Contains sub-directories which | ||
| 2410 | * contain the stuff specific to particular file-system mounts. | ||
| 2411 | */ | ||
| 2412 | static struct dentry *debugfs_rootdir; | ||
| 2413 | |||
| 2414 | /** | ||
| 2415 | * dbg_debugfs_init - initialize debugfs file-system. | ||
| 2416 | * | ||
| 2417 | * UBIFS uses debugfs file-system to expose various debugging knobs to | ||
| 2418 | * user-space. This function creates "ubifs" directory in the debugfs | ||
| 2419 | * file-system. Returns zero in case of success and a negative error code in | ||
| 2420 | * case of failure. | ||
| 2421 | */ | ||
| 2422 | int dbg_debugfs_init(void) | ||
| 2423 | { | ||
| 2424 | debugfs_rootdir = debugfs_create_dir("ubifs", NULL); | ||
| 2425 | if (IS_ERR(debugfs_rootdir)) { | ||
| 2426 | int err = PTR_ERR(debugfs_rootdir); | ||
| 2427 | ubifs_err("cannot create \"ubifs\" debugfs directory, " | ||
| 2428 | "error %d\n", err); | ||
| 2429 | return err; | ||
| 2430 | } | ||
| 2431 | |||
| 2432 | return 0; | ||
| 2433 | } | ||
| 2434 | |||
| 2435 | /** | ||
| 2436 | * dbg_debugfs_exit - remove the "ubifs" directory from debugfs file-system. | ||
| 2437 | */ | ||
| 2438 | void dbg_debugfs_exit(void) | ||
| 2439 | { | ||
| 2440 | debugfs_remove(debugfs_rootdir); | ||
| 2441 | } | ||
| 2442 | |||
| 2443 | static int open_debugfs_file(struct inode *inode, struct file *file) | ||
| 2444 | { | ||
| 2445 | file->private_data = inode->i_private; | ||
| 2446 | return 0; | ||
| 2447 | } | ||
| 2448 | |||
| 2449 | static ssize_t write_debugfs_file(struct file *file, const char __user *buf, | ||
| 2450 | size_t count, loff_t *ppos) | ||
| 2451 | { | ||
| 2452 | struct ubifs_info *c = file->private_data; | ||
| 2453 | struct ubifs_debug_info *d = c->dbg; | ||
| 2454 | |||
| 2455 | if (file->f_path.dentry == d->dump_lprops) | ||
| 2456 | dbg_dump_lprops(c); | ||
| 2457 | else if (file->f_path.dentry == d->dump_budg) { | ||
| 2458 | spin_lock(&c->space_lock); | ||
| 2459 | dbg_dump_budg(c); | ||
| 2460 | spin_unlock(&c->space_lock); | ||
| 2461 | } else if (file->f_path.dentry == d->dump_tnc) { | ||
| 2462 | mutex_lock(&c->tnc_mutex); | ||
| 2463 | dbg_dump_tnc(c); | ||
| 2464 | mutex_unlock(&c->tnc_mutex); | ||
| 2465 | } else | ||
| 2466 | return -EINVAL; | ||
| 2467 | |||
| 2468 | *ppos += count; | ||
| 2469 | return count; | ||
| 2470 | } | ||
| 2471 | |||
| 2472 | static const struct file_operations debugfs_fops = { | ||
| 2473 | .open = open_debugfs_file, | ||
| 2474 | .write = write_debugfs_file, | ||
| 2475 | .owner = THIS_MODULE, | ||
| 2476 | }; | ||
| 2477 | |||
| 2478 | /** | ||
| 2479 | * dbg_debugfs_init_fs - initialize debugfs for UBIFS instance. | ||
| 2480 | * @c: UBIFS file-system description object | ||
| 2481 | * | ||
| 2482 | * This function creates all debugfs files for this instance of UBIFS. Returns | ||
| 2483 | * zero in case of success and a negative error code in case of failure. | ||
| 2484 | * | ||
| 2485 | * Note, the only reason we have not merged this function with the | ||
| 2486 | * 'ubifs_debugging_init()' function is because it is better to initialize | ||
| 2487 | * debugfs interfaces at the very end of the mount process, and remove them at | ||
| 2488 | * the very beginning of the mount process. | ||
| 2489 | */ | ||
| 2490 | int dbg_debugfs_init_fs(struct ubifs_info *c) | ||
| 2491 | { | ||
| 2492 | int err; | ||
| 2493 | const char *fname; | ||
| 2494 | struct dentry *dent; | ||
| 2495 | struct ubifs_debug_info *d = c->dbg; | ||
| 2496 | |||
| 2497 | sprintf(d->debugfs_dir_name, "ubi%d_%d", c->vi.ubi_num, c->vi.vol_id); | ||
| 2498 | d->debugfs_dir = debugfs_create_dir(d->debugfs_dir_name, | ||
| 2499 | debugfs_rootdir); | ||
| 2500 | if (IS_ERR(d->debugfs_dir)) { | ||
| 2501 | err = PTR_ERR(d->debugfs_dir); | ||
| 2502 | ubifs_err("cannot create \"%s\" debugfs directory, error %d\n", | ||
| 2503 | d->debugfs_dir_name, err); | ||
| 2504 | goto out; | ||
| 2505 | } | ||
| 2506 | |||
| 2507 | fname = "dump_lprops"; | ||
| 2508 | dent = debugfs_create_file(fname, S_IWUGO, d->debugfs_dir, c, | ||
| 2509 | &debugfs_fops); | ||
| 2510 | if (IS_ERR(dent)) | ||
| 2511 | goto out_remove; | ||
| 2512 | d->dump_lprops = dent; | ||
| 2513 | |||
| 2514 | fname = "dump_budg"; | ||
| 2515 | dent = debugfs_create_file(fname, S_IWUGO, d->debugfs_dir, c, | ||
| 2516 | &debugfs_fops); | ||
| 2517 | if (IS_ERR(dent)) | ||
| 2518 | goto out_remove; | ||
| 2519 | d->dump_budg = dent; | ||
| 2520 | |||
| 2521 | fname = "dump_tnc"; | ||
| 2522 | dent = debugfs_create_file(fname, S_IWUGO, d->debugfs_dir, c, | ||
| 2523 | &debugfs_fops); | ||
| 2524 | if (IS_ERR(dent)) | ||
| 2525 | goto out_remove; | ||
| 2526 | d->dump_tnc = dent; | ||
| 2527 | |||
| 2528 | return 0; | ||
| 2529 | |||
| 2530 | out_remove: | ||
| 2531 | err = PTR_ERR(dent); | ||
| 2532 | ubifs_err("cannot create \"%s\" debugfs directory, error %d\n", | ||
| 2533 | fname, err); | ||
| 2534 | debugfs_remove_recursive(d->debugfs_dir); | ||
| 2535 | out: | ||
| 2536 | return err; | ||
| 2537 | } | ||
| 2538 | |||
| 2539 | /** | ||
| 2540 | * dbg_debugfs_exit_fs - remove all debugfs files. | ||
| 2541 | * @c: UBIFS file-system description object | ||
| 2542 | */ | ||
| 2543 | void dbg_debugfs_exit_fs(struct ubifs_info *c) | ||
| 2544 | { | ||
| 2545 | debugfs_remove_recursive(c->dbg->debugfs_dir); | ||
| 2546 | } | ||
| 2547 | |||
| 2347 | #endif /* CONFIG_UBIFS_FS_DEBUG */ | 2548 | #endif /* CONFIG_UBIFS_FS_DEBUG */ |
