UBIFS: fix available blocks count
[linux-2.6-block.git] / fs / ubifs / debug.c
index 7186400750e775ad18bd2e9975a373ecb7803e62..6ecb01a99d146cc813dc3f190202ebebd6300349 100644 (file)
@@ -32,6 +32,7 @@
 #include "ubifs.h"
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/debugfs.h>
 
 #ifdef CONFIG_UBIFS_FS_DEBUG
 
@@ -101,21 +102,24 @@ static void sprintf_key(const struct ubifs_info *c, const union ubifs_key *key,
        if (c->key_fmt == UBIFS_SIMPLE_KEY_FMT) {
                switch (type) {
                case UBIFS_INO_KEY:
-                       sprintf(p, "(%lu, %s)", key_inum(c, key),
+                       sprintf(p, "(%lu, %s)", (unsigned long)key_inum(c, key),
                               get_key_type(type));
                        break;
                case UBIFS_DENT_KEY:
                case UBIFS_XENT_KEY:
-                       sprintf(p, "(%lu, %s, %#08x)", key_inum(c, key),
+                       sprintf(p, "(%lu, %s, %#08x)",
+                               (unsigned long)key_inum(c, key),
                                get_key_type(type), key_hash(c, key));
                        break;
                case UBIFS_DATA_KEY:
-                       sprintf(p, "(%lu, %s, %u)", key_inum(c, key),
+                       sprintf(p, "(%lu, %s, %u)",
+                               (unsigned long)key_inum(c, key),
                                get_key_type(type), key_block(c, key));
                        break;
                case UBIFS_TRUN_KEY:
                        sprintf(p, "(%lu, %s)",
-                               key_inum(c, key), get_key_type(type));
+                               (unsigned long)key_inum(c, key),
+                               get_key_type(type));
                        break;
                default:
                        sprintf(p, "(bad key type: %#08x, %#08x)",
@@ -364,8 +368,8 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
                       le32_to_cpu(mst->ihead_lnum));
                printk(KERN_DEBUG "\tihead_offs     %u\n",
                       le32_to_cpu(mst->ihead_offs));
-               printk(KERN_DEBUG "\tindex_size     %u\n",
-                      le32_to_cpu(mst->index_size));
+               printk(KERN_DEBUG "\tindex_size     %llu\n",
+                      (unsigned long long)le64_to_cpu(mst->index_size));
                printk(KERN_DEBUG "\tlpt_lnum       %u\n",
                       le32_to_cpu(mst->lpt_lnum));
                printk(KERN_DEBUG "\tlpt_offs       %u\n",
@@ -593,7 +597,9 @@ void dbg_dump_budg(struct ubifs_info *c)
        struct rb_node *rb;
        struct ubifs_bud *bud;
        struct ubifs_gced_idx_leb *idx_gc;
+       long long available, outstanding, free;
 
+       ubifs_assert(spin_is_locked(&c->space_lock));
        spin_lock(&dbg_lock);
        printk(KERN_DEBUG "(pid %d) Budgeting info: budg_data_growth %lld, "
               "budg_dd_growth %lld, budg_idx_growth %lld\n", current->pid,
@@ -626,6 +632,17 @@ void dbg_dump_budg(struct ubifs_info *c)
                printk(KERN_DEBUG "\tGC'ed idx LEB %d unmap %d\n",
                       idx_gc->lnum, idx_gc->unmap);
        printk(KERN_DEBUG "\tcommit state %d\n", c->cmt_state);
+
+       /* Print budgeting predictions */
+       available = ubifs_calc_available(c, c->min_idx_lebs);
+       outstanding = c->budg_data_growth + c->budg_dd_growth;
+       if (available > outstanding)
+               free = ubifs_reported_space(c, available - outstanding);
+       else
+               free = 0;
+       printk(KERN_DEBUG "Budgeting predictions:\n");
+       printk(KERN_DEBUG "\tavailable: %lld, outstanding %lld, free %lld\n",
+              available, outstanding, free);
        spin_unlock(&dbg_lock);
 }
 
@@ -642,7 +659,8 @@ void dbg_dump_lprops(struct ubifs_info *c)
        struct ubifs_lprops lp;
        struct ubifs_lp_stats lst;
 
-       printk(KERN_DEBUG "(pid %d) Dumping LEB properties\n", current->pid);
+       printk(KERN_DEBUG "(pid %d) start dumping LEB properties\n",
+              current->pid);
        ubifs_get_lp_stats(c, &lst);
        dbg_dump_lstats(&lst);
 
@@ -653,6 +671,8 @@ void dbg_dump_lprops(struct ubifs_info *c)
 
                dbg_dump_lprop(c, &lp);
        }
+       printk(KERN_DEBUG "(pid %d) finish dumping LEB properties\n",
+              current->pid);
 }
 
 void dbg_dump_lpt_info(struct ubifs_info *c)
@@ -660,6 +680,7 @@ void dbg_dump_lpt_info(struct ubifs_info *c)
        int i;
 
        spin_lock(&dbg_lock);
+       printk(KERN_DEBUG "(pid %d) dumping LPT information\n", current->pid);
        printk(KERN_DEBUG "\tlpt_sz:        %lld\n", c->lpt_sz);
        printk(KERN_DEBUG "\tpnode_sz:      %d\n", c->pnode_sz);
        printk(KERN_DEBUG "\tnnode_sz:      %d\n", c->nnode_sz);
@@ -700,9 +721,9 @@ void dbg_dump_leb(const struct ubifs_info *c, int lnum)
        if (dbg_failure_mode)
                return;
 
-       printk(KERN_DEBUG "(pid %d) Dumping LEB %d\n", current->pid, lnum);
-
-       sleb = ubifs_scan(c, lnum, 0, c->dbg_buf);
+       printk(KERN_DEBUG "(pid %d) start dumping LEB %d\n",
+              current->pid, lnum);
+       sleb = ubifs_scan(c, lnum, 0, c->dbg->buf);
        if (IS_ERR(sleb)) {
                ubifs_err("scan error %d", (int)PTR_ERR(sleb));
                return;
@@ -718,6 +739,8 @@ void dbg_dump_leb(const struct ubifs_info *c, int lnum)
                dbg_dump_node(c, snod->node);
        }
 
+       printk(KERN_DEBUG "(pid %d) finish dumping LEB %d\n",
+              current->pid, lnum);
        ubifs_scan_destroy(sleb);
        return;
 }
@@ -765,7 +788,7 @@ void dbg_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat)
 {
        int i;
 
-       printk(KERN_DEBUG "(pid %d) Dumping heap cat %d (%d elements)\n",
+       printk(KERN_DEBUG "(pid %d) start dumping heap cat %d (%d elements)\n",
               current->pid, cat, heap->cnt);
        for (i = 0; i < heap->cnt; i++) {
                struct ubifs_lprops *lprops = heap->arr[i];
@@ -774,6 +797,7 @@ void dbg_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat)
                       "flags %d\n", i, lprops->lnum, lprops->hpos,
                       lprops->free, lprops->dirty, lprops->flags);
        }
+       printk(KERN_DEBUG "(pid %d) finish dumping heap\n", current->pid);
 }
 
 void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
@@ -781,7 +805,7 @@ void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
 {
        int i;
 
-       printk(KERN_DEBUG "(pid %d) Dumping pnode:\n", current->pid);
+       printk(KERN_DEBUG "(pid %d) dumping pnode:\n", current->pid);
        printk(KERN_DEBUG "\taddress %zx parent %zx cnext %zx\n",
               (size_t)pnode, (size_t)parent, (size_t)pnode->cnext);
        printk(KERN_DEBUG "\tflags %lu iip %d level %d num %d\n",
@@ -800,7 +824,7 @@ void dbg_dump_tnc(struct ubifs_info *c)
        int level;
 
        printk(KERN_DEBUG "\n");
-       printk(KERN_DEBUG "(pid %d) Dumping the TNC tree\n", current->pid);
+       printk(KERN_DEBUG "(pid %d) start dumping TNC tree\n", current->pid);
        znode = ubifs_tnc_levelorder_next(c->zroot.znode, NULL);
        level = znode->level;
        printk(KERN_DEBUG "== Level %d ==\n", level);
@@ -812,8 +836,7 @@ void dbg_dump_tnc(struct ubifs_info *c)
                dbg_dump_znode(c, znode);
                znode = ubifs_tnc_levelorder_next(c->zroot.znode, znode);
        }
-
-       printk(KERN_DEBUG "\n");
+       printk(KERN_DEBUG "(pid %d) finish dumping TNC tree\n", current->pid);
 }
 
 static int dump_znode(struct ubifs_info *c, struct ubifs_znode *znode,
@@ -985,22 +1008,22 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
        err = 1;
        key_read(c, &dent1->key, &key);
        if (keys_cmp(c, &zbr1->key, &key)) {
-               dbg_err("1st entry at %d:%d has key %s", zbr1->lnum,
-                       zbr1->offs, DBGKEY(&key));
-               dbg_err("but it should have key %s according to tnc",
-                       DBGKEY(&zbr1->key));
-                       dbg_dump_node(c, dent1);
-                       goto out_free;
+               ubifs_err("1st entry at %d:%d has key %s", zbr1->lnum,
+                         zbr1->offs, DBGKEY(&key));
+               ubifs_err("but it should have key %s according to tnc",
+                         DBGKEY(&zbr1->key));
+               dbg_dump_node(c, dent1);
+               goto out_free;
        }
 
        key_read(c, &dent2->key, &key);
        if (keys_cmp(c, &zbr2->key, &key)) {
-               dbg_err("2nd entry at %d:%d has key %s", zbr1->lnum,
-                       zbr1->offs, DBGKEY(&key));
-               dbg_err("but it should have key %s according to tnc",
-                       DBGKEY(&zbr2->key));
-                       dbg_dump_node(c, dent2);
-                       goto out_free;
+               ubifs_err("2nd entry at %d:%d has key %s", zbr1->lnum,
+                         zbr1->offs, DBGKEY(&key));
+               ubifs_err("but it should have key %s according to tnc",
+                         DBGKEY(&zbr2->key));
+               dbg_dump_node(c, dent2);
+               goto out_free;
        }
 
        nlen1 = le16_to_cpu(dent1->nlen);
@@ -1012,14 +1035,14 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
                goto out_free;
        }
        if (cmp == 0 && nlen1 == nlen2)
-               dbg_err("2 xent/dent nodes with the same name");
+               ubifs_err("2 xent/dent nodes with the same name");
        else
-               dbg_err("bad order of colliding key %s",
+               ubifs_err("bad order of colliding key %s",
                        DBGKEY(&key));
 
-       dbg_msg("first node at %d:%d\n", zbr1->lnum, zbr1->offs);
+       ubifs_msg("first node at %d:%d\n", zbr1->lnum, zbr1->offs);
        dbg_dump_node(c, dent1);
-       dbg_msg("second node at %d:%d\n", zbr2->lnum, zbr2->offs);
+       ubifs_msg("second node at %d:%d\n", zbr2->lnum, zbr2->offs);
        dbg_dump_node(c, dent2);
 
 out_free:
@@ -1589,7 +1612,7 @@ static struct fsck_inode *add_inode(struct ubifs_info *c,
 
        if (inum > c->highest_inum) {
                ubifs_err("too high inode number, max. is %lu",
-                         c->highest_inum);
+                         (unsigned long)c->highest_inum);
                return ERR_PTR(-EINVAL);
        }
 
@@ -1668,16 +1691,18 @@ static struct fsck_inode *read_add_inode(struct ubifs_info *c,
        ino_key_init(c, &key, inum);
        err = ubifs_lookup_level0(c, &key, &znode, &n);
        if (!err) {
-               ubifs_err("inode %lu not found in index", inum);
+               ubifs_err("inode %lu not found in index", (unsigned long)inum);
                return ERR_PTR(-ENOENT);
        } else if (err < 0) {
-               ubifs_err("error %d while looking up inode %lu", err, inum);
+               ubifs_err("error %d while looking up inode %lu",
+                         err, (unsigned long)inum);
                return ERR_PTR(err);
        }
 
        zbr = &znode->zbranch[n];
        if (zbr->len < UBIFS_INO_NODE_SZ) {
-               ubifs_err("bad node %lu node length %d", inum, zbr->len);
+               ubifs_err("bad node %lu node length %d",
+                         (unsigned long)inum, zbr->len);
                return ERR_PTR(-EINVAL);
        }
 
@@ -1697,7 +1722,7 @@ static struct fsck_inode *read_add_inode(struct ubifs_info *c,
        kfree(ino);
        if (IS_ERR(fscki)) {
                ubifs_err("error %ld while adding inode %lu node",
-                         PTR_ERR(fscki), inum);
+                         PTR_ERR(fscki), (unsigned long)inum);
                return fscki;
        }
 
@@ -1786,7 +1811,8 @@ static int check_leaf(struct ubifs_info *c, struct ubifs_zbranch *zbr,
                if (IS_ERR(fscki)) {
                        err = PTR_ERR(fscki);
                        ubifs_err("error %d while processing data node and "
-                                 "trying to find inode node %lu", err, inum);
+                                 "trying to find inode node %lu",
+                                 err, (unsigned long)inum);
                        goto out_dump;
                }
 
@@ -1819,7 +1845,8 @@ static int check_leaf(struct ubifs_info *c, struct ubifs_zbranch *zbr,
                if (IS_ERR(fscki)) {
                        err = PTR_ERR(fscki);
                        ubifs_err("error %d while processing entry node and "
-                                 "trying to find inode node %lu", err, inum);
+                                 "trying to find inode node %lu",
+                                 err, (unsigned long)inum);
                        goto out_dump;
                }
 
@@ -1832,7 +1859,7 @@ static int check_leaf(struct ubifs_info *c, struct ubifs_zbranch *zbr,
                        err = PTR_ERR(fscki);
                        ubifs_err("error %d while processing entry node and "
                                  "trying to find parent inode node %lu",
-                                 err, inum);
+                                 err, (unsigned long)inum);
                        goto out_dump;
                }
 
@@ -1923,7 +1950,8 @@ static int check_inodes(struct ubifs_info *c, struct fsck_data *fsckd)
                            fscki->references != 1) {
                                ubifs_err("directory inode %lu has %d "
                                          "direntries which refer it, but "
-                                         "should be 1", fscki->inum,
+                                         "should be 1",
+                                         (unsigned long)fscki->inum,
                                          fscki->references);
                                goto out_dump;
                        }
@@ -1931,27 +1959,29 @@ static int check_inodes(struct ubifs_info *c, struct fsck_data *fsckd)
                            fscki->references != 0) {
                                ubifs_err("root inode %lu has non-zero (%d) "
                                          "direntries which refer it",
-                                         fscki->inum, fscki->references);
+                                         (unsigned long)fscki->inum,
+                                         fscki->references);
                                goto out_dump;
                        }
                        if (fscki->calc_sz != fscki->size) {
                                ubifs_err("directory inode %lu size is %lld, "
                                          "but calculated size is %lld",
-                                         fscki->inum, fscki->size,
-                                         fscki->calc_sz);
+                                         (unsigned long)fscki->inum,
+                                         fscki->size, fscki->calc_sz);
                                goto out_dump;
                        }
                        if (fscki->calc_cnt != fscki->nlink) {
                                ubifs_err("directory inode %lu nlink is %d, "
                                          "but calculated nlink is %d",
-                                         fscki->inum, fscki->nlink,
-                                         fscki->calc_cnt);
+                                         (unsigned long)fscki->inum,
+                                         fscki->nlink, fscki->calc_cnt);
                                goto out_dump;
                        }
                } else {
                        if (fscki->references != fscki->nlink) {
                                ubifs_err("inode %lu nlink is %d, but "
-                                         "calculated nlink is %d", fscki->inum,
+                                         "calculated nlink is %d",
+                                         (unsigned long)fscki->inum,
                                          fscki->nlink, fscki->references);
                                goto out_dump;
                        }
@@ -1959,20 +1989,21 @@ static int check_inodes(struct ubifs_info *c, struct fsck_data *fsckd)
                if (fscki->xattr_sz != fscki->calc_xsz) {
                        ubifs_err("inode %lu has xattr size %u, but "
                                  "calculated size is %lld",
-                                 fscki->inum, fscki->xattr_sz,
+                                 (unsigned long)fscki->inum, fscki->xattr_sz,
                                  fscki->calc_xsz);
                        goto out_dump;
                }
                if (fscki->xattr_cnt != fscki->calc_xcnt) {
                        ubifs_err("inode %lu has %u xattrs, but "
-                                 "calculated count is %lld", fscki->inum,
+                                 "calculated count is %lld",
+                                 (unsigned long)fscki->inum,
                                  fscki->xattr_cnt, fscki->calc_xcnt);
                        goto out_dump;
                }
                if (fscki->xattr_nms != fscki->calc_xnms) {
                        ubifs_err("inode %lu has xattr names' size %u, but "
                                  "calculated names' size is %lld",
-                                 fscki->inum, fscki->xattr_nms,
+                                 (unsigned long)fscki->inum, fscki->xattr_nms,
                                  fscki->calc_xnms);
                        goto out_dump;
                }
@@ -1985,11 +2016,12 @@ out_dump:
        ino_key_init(c, &key, fscki->inum);
        err = ubifs_lookup_level0(c, &key, &znode, &n);
        if (!err) {
-               ubifs_err("inode %lu not found in index", fscki->inum);
+               ubifs_err("inode %lu not found in index",
+                         (unsigned long)fscki->inum);
                return -ENOENT;
        } else if (err < 0) {
                ubifs_err("error %d while looking up inode %lu",
-                         err, fscki->inum);
+                         err, (unsigned long)fscki->inum);
                return err;
        }
 
@@ -2007,7 +2039,7 @@ out_dump:
        }
 
        ubifs_msg("dump of the inode %lu sitting in LEB %d:%d",
-                 fscki->inum, zbr->lnum, zbr->offs);
+                 (unsigned long)fscki->inum, zbr->lnum, zbr->offs);
        dbg_dump_node(c, ino);
        kfree(ino);
        return -EINVAL;
@@ -2085,13 +2117,13 @@ static int simple_rand(void)
        return (next >> 16) & 32767;
 }
 
-void dbg_failure_mode_registration(struct ubifs_info *c)
+static void failure_mode_init(struct ubifs_info *c)
 {
        struct failure_mode_info *fmi;
 
        fmi = kmalloc(sizeof(struct failure_mode_info), GFP_NOFS);
        if (!fmi) {
-               dbg_err("Failed to register failure mode - no memory");
+               ubifs_err("Failed to register failure mode - no memory");
                return;
        }
        fmi->c = c;
@@ -2100,7 +2132,7 @@ void dbg_failure_mode_registration(struct ubifs_info *c)
        spin_unlock(&fmi_lock);
 }
 
-void dbg_failure_mode_deregistration(struct ubifs_info *c)
+static void failure_mode_exit(struct ubifs_info *c)
 {
        struct failure_mode_info *fmi, *tmp;
 
@@ -2134,42 +2166,44 @@ static int in_failure_mode(struct ubi_volume_desc *desc)
        struct ubifs_info *c = dbg_find_info(desc);
 
        if (c && dbg_failure_mode)
-               return c->failure_mode;
+               return c->dbg->failure_mode;
        return 0;
 }
 
 static int do_fail(struct ubi_volume_desc *desc, int lnum, int write)
 {
        struct ubifs_info *c = dbg_find_info(desc);
+       struct ubifs_debug_info *d;
 
        if (!c || !dbg_failure_mode)
                return 0;
-       if (c->failure_mode)
+       d = c->dbg;
+       if (d->failure_mode)
                return 1;
-       if (!c->fail_cnt) {
+       if (!d->fail_cnt) {
                /* First call - decide delay to failure */
                if (chance(1, 2)) {
                        unsigned int delay = 1 << (simple_rand() >> 11);
 
                        if (chance(1, 2)) {
-                               c->fail_delay = 1;
-                               c->fail_timeout = jiffies +
+                               d->fail_delay = 1;
+                               d->fail_timeout = jiffies +
                                                  msecs_to_jiffies(delay);
                                dbg_rcvry("failing after %ums", delay);
                        } else {
-                               c->fail_delay = 2;
-                               c->fail_cnt_max = delay;
+                               d->fail_delay = 2;
+                               d->fail_cnt_max = delay;
                                dbg_rcvry("failing after %u calls", delay);
                        }
                }
-               c->fail_cnt += 1;
+               d->fail_cnt += 1;
        }
        /* Determine if failure delay has expired */
-       if (c->fail_delay == 1) {
-               if (time_before(jiffies, c->fail_timeout))
+       if (d->fail_delay == 1) {
+               if (time_before(jiffies, d->fail_timeout))
                        return 0;
-       } else if (c->fail_delay == 2)
-               if (c->fail_cnt++ < c->fail_cnt_max)
+       } else if (d->fail_delay == 2)
+               if (d->fail_cnt++ < d->fail_cnt_max)
                        return 0;
        if (lnum == UBIFS_SB_LNUM) {
                if (write) {
@@ -2227,7 +2261,7 @@ static int do_fail(struct ubi_volume_desc *desc, int lnum, int write)
                dbg_rcvry("failing in bud LEB %d commit not running", lnum);
        }
        ubifs_err("*** SETTING FAILURE MODE ON (LEB %d) ***", lnum);
-       c->failure_mode = 1;
+       d->failure_mode = 1;
        dump_stack();
        return 1;
 }
@@ -2332,4 +2366,181 @@ int dbg_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype)
        return 0;
 }
 
+/**
+ * ubifs_debugging_init - initialize UBIFS debugging.
+ * @c: UBIFS file-system description object
+ *
+ * This function initializes debugging-related data for the file system.
+ * Returns zero in case of success and a negative error code in case of
+ * failure.
+ */
+int ubifs_debugging_init(struct ubifs_info *c)
+{
+       c->dbg = kzalloc(sizeof(struct ubifs_debug_info), GFP_KERNEL);
+       if (!c->dbg)
+               return -ENOMEM;
+
+       c->dbg->buf = vmalloc(c->leb_size);
+       if (!c->dbg->buf)
+               goto out;
+
+       failure_mode_init(c);
+       return 0;
+
+out:
+       kfree(c->dbg);
+       return -ENOMEM;
+}
+
+/**
+ * ubifs_debugging_exit - free debugging data.
+ * @c: UBIFS file-system description object
+ */
+void ubifs_debugging_exit(struct ubifs_info *c)
+{
+       failure_mode_exit(c);
+       vfree(c->dbg->buf);
+       kfree(c->dbg);
+}
+
+/*
+ * Root directory for UBIFS stuff in debugfs. Contains sub-directories which
+ * contain the stuff specific to particular file-system mounts.
+ */
+static struct dentry *debugfs_rootdir;
+
+/**
+ * dbg_debugfs_init - initialize debugfs file-system.
+ *
+ * UBIFS uses debugfs file-system to expose various debugging knobs to
+ * user-space. This function creates "ubifs" directory in the debugfs
+ * file-system. Returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+int dbg_debugfs_init(void)
+{
+       debugfs_rootdir = debugfs_create_dir("ubifs", NULL);
+       if (IS_ERR(debugfs_rootdir)) {
+               int err = PTR_ERR(debugfs_rootdir);
+               ubifs_err("cannot create \"ubifs\" debugfs directory, "
+                         "error %d\n", err);
+               return err;
+       }
+
+       return 0;
+}
+
+/**
+ * dbg_debugfs_exit - remove the "ubifs" directory from debugfs file-system.
+ */
+void dbg_debugfs_exit(void)
+{
+       debugfs_remove(debugfs_rootdir);
+}
+
+static int open_debugfs_file(struct inode *inode, struct file *file)
+{
+       file->private_data = inode->i_private;
+       return 0;
+}
+
+static ssize_t write_debugfs_file(struct file *file, const char __user *buf,
+                                 size_t count, loff_t *ppos)
+{
+       struct ubifs_info *c = file->private_data;
+       struct ubifs_debug_info *d = c->dbg;
+
+       if (file->f_path.dentry == d->dump_lprops)
+               dbg_dump_lprops(c);
+       else if (file->f_path.dentry == d->dump_budg) {
+               spin_lock(&c->space_lock);
+               dbg_dump_budg(c);
+               spin_unlock(&c->space_lock);
+       } else if (file->f_path.dentry == d->dump_tnc) {
+               mutex_lock(&c->tnc_mutex);
+               dbg_dump_tnc(c);
+               mutex_unlock(&c->tnc_mutex);
+       } else
+               return -EINVAL;
+
+       *ppos += count;
+       return count;
+}
+
+static const struct file_operations debugfs_fops = {
+       .open = open_debugfs_file,
+       .write = write_debugfs_file,
+       .owner = THIS_MODULE,
+};
+
+/**
+ * dbg_debugfs_init_fs - initialize debugfs for UBIFS instance.
+ * @c: UBIFS file-system description object
+ *
+ * This function creates all debugfs files for this instance of UBIFS. Returns
+ * zero in case of success and a negative error code in case of failure.
+ *
+ * Note, the only reason we have not merged this function with the
+ * 'ubifs_debugging_init()' function is because it is better to initialize
+ * debugfs interfaces at the very end of the mount process, and remove them at
+ * the very beginning of the mount process.
+ */
+int dbg_debugfs_init_fs(struct ubifs_info *c)
+{
+       int err;
+       const char *fname;
+       struct dentry *dent;
+       struct ubifs_debug_info *d = c->dbg;
+
+       sprintf(d->debugfs_dir_name, "ubi%d_%d", c->vi.ubi_num, c->vi.vol_id);
+       d->debugfs_dir = debugfs_create_dir(d->debugfs_dir_name,
+                                             debugfs_rootdir);
+       if (IS_ERR(d->debugfs_dir)) {
+               err = PTR_ERR(d->debugfs_dir);
+               ubifs_err("cannot create \"%s\" debugfs directory, error %d\n",
+                         d->debugfs_dir_name, err);
+               goto out;
+       }
+
+       fname = "dump_lprops";
+       dent = debugfs_create_file(fname, S_IWUGO, d->debugfs_dir, c,
+                                  &debugfs_fops);
+       if (IS_ERR(dent))
+               goto out_remove;
+       d->dump_lprops = dent;
+
+       fname = "dump_budg";
+       dent = debugfs_create_file(fname, S_IWUGO, d->debugfs_dir, c,
+                                  &debugfs_fops);
+       if (IS_ERR(dent))
+               goto out_remove;
+       d->dump_budg = dent;
+
+       fname = "dump_tnc";
+       dent = debugfs_create_file(fname, S_IWUGO, d->debugfs_dir, c,
+                                  &debugfs_fops);
+       if (IS_ERR(dent))
+               goto out_remove;
+       d->dump_tnc = dent;
+
+       return 0;
+
+out_remove:
+       err = PTR_ERR(dent);
+       ubifs_err("cannot create \"%s\" debugfs directory, error %d\n",
+                 fname, err);
+       debugfs_remove_recursive(d->debugfs_dir);
+out:
+       return err;
+}
+
+/**
+ * dbg_debugfs_exit_fs - remove all debugfs files.
+ * @c: UBIFS file-system description object
+ */
+void dbg_debugfs_exit_fs(struct ubifs_info *c)
+{
+       debugfs_remove_recursive(c->dbg->debugfs_dir);
+}
+
 #endif /* CONFIG_UBIFS_FS_DEBUG */