Merge branch 'linux-next' of git://git.infradead.org/ubifs-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 2 Jan 2009 23:57:47 +0000 (15:57 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 2 Jan 2009 23:57:47 +0000 (15:57 -0800)
* 'linux-next' of git://git.infradead.org/ubifs-2.6: (33 commits)
  UBIFS: add more useful debugging prints
  UBIFS: print debugging messages properly
  UBIFS: fix numerous spelling mistakes
  UBIFS: allow mounting when short of space
  UBIFS: fix writing uncompressed files
  UBIFS: fix checkpatch.pl warnings
  UBIFS: fix sparse warnings
  UBIFS: simplify make_free_space
  UBIFS: do not lie about used blocks
  UBIFS: restore budg_uncommitted_idx
  UBIFS: always commit on unmount
  UBIFS: use ubi_sync
  UBIFS: always commit in sync_fs
  UBIFS: fix file-system synchronization
  UBIFS: fix constants initialization
  UBIFS: avoid unnecessary calculations
  UBIFS: re-calculate min_idx_size after the commit
  UBIFS: use nicer 64-bit math
  UBIFS: fix available blocks count
  UBIFS: various comment improvements and fixes
  ...

21 files changed:
Documentation/filesystems/ubifs.txt
fs/ubifs/budget.c
fs/ubifs/commit.c
fs/ubifs/compress.c
fs/ubifs/debug.c
fs/ubifs/debug.h
fs/ubifs/file.c
fs/ubifs/ioctl.c
fs/ubifs/journal.c
fs/ubifs/key.h
fs/ubifs/lprops.c
fs/ubifs/lpt.c
fs/ubifs/lpt_commit.c
fs/ubifs/orphan.c
fs/ubifs/replay.c
fs/ubifs/sb.c
fs/ubifs/super.c
fs/ubifs/tnc.c
fs/ubifs/tnc_commit.c
fs/ubifs/ubifs-media.h
fs/ubifs/ubifs.h

index dd84ea3c10daf00cf78a2361dce9f8b691095e4d..84da2a4ba25ab698b8788e03d33d1678f86eba22 100644 (file)
@@ -95,6 +95,9 @@ no_chk_data_crc               skip checking of CRCs on data nodes in order to
                        of this option is that corruption of the contents
                        of a file can go unnoticed.
 chk_data_crc (*)       do not skip checking CRCs on data nodes
+compr=none              override default compressor and set it to "none"
+compr=lzo               override default compressor and set it to "lzo"
+compr=zlib              override default compressor and set it to "zlib"
 
 
 Quick usage instructions
index 4a18f084cc427a7df83214055d9efa023a549444..0e5e54d829243afba459b97a72a303aad6654e00 100644 (file)
 
 #include "ubifs.h"
 #include <linux/writeback.h>
-#include <asm/div64.h>
+#include <linux/math64.h>
 
 /*
  * When pessimistic budget calculations say that there is no enough space,
  * UBIFS starts writing back dirty inodes and pages, doing garbage collection,
- * or committing. The below constants define maximum number of times UBIFS
+ * or committing. The below constant defines maximum number of times UBIFS
  * repeats the operations.
  */
-#define MAX_SHRINK_RETRIES 8
-#define MAX_GC_RETRIES     4
-#define MAX_CMT_RETRIES    2
-#define MAX_NOSPC_RETRIES  1
+#define MAX_MKSPC_RETRIES 3
 
 /*
  * The below constant defines amount of dirty pages which should be written
  */
 #define NR_TO_WRITE 16
 
-/**
- * struct retries_info - information about re-tries while making free space.
- * @prev_liability: previous liability
- * @shrink_cnt: how many times the liability was shrinked
- * @shrink_retries: count of liability shrink re-tries (increased when
- *                  liability does not shrink)
- * @try_gc: GC should be tried first
- * @gc_retries: how many times GC was run
- * @cmt_retries: how many times commit has been done
- * @nospc_retries: how many times GC returned %-ENOSPC
- *
- * Since we consider budgeting to be the fast-path, and this structure has to
- * be allocated on stack and zeroed out, we make it smaller using bit-fields.
- */
-struct retries_info {
-       long long prev_liability;
-       unsigned int shrink_cnt;
-       unsigned int shrink_retries:5;
-       unsigned int try_gc:1;
-       unsigned int gc_retries:4;
-       unsigned int cmt_retries:3;
-       unsigned int nospc_retries:1;
-};
-
 /**
  * shrink_liability - write-back some dirty pages/inodes.
  * @c: UBIFS file-system description object
@@ -146,10 +119,26 @@ static int run_gc(struct ubifs_info *c)
        return 0;
 }
 
+/**
+ * get_liability - calculate current liability.
+ * @c: UBIFS file-system description object
+ *
+ * This function calculates and returns current UBIFS liability, i.e. the
+ * amount of bytes UBIFS has "promised" to write to the media.
+ */
+static long long get_liability(struct ubifs_info *c)
+{
+       long long liab;
+
+       spin_lock(&c->space_lock);
+       liab = c->budg_idx_growth + c->budg_data_growth + c->budg_dd_growth;
+       spin_unlock(&c->space_lock);
+       return liab;
+}
+
 /**
  * make_free_space - make more free space on the file-system.
  * @c: UBIFS file-system description object
- * @ri: information about previous invocations of this function
  *
  * This function is called when an operation cannot be budgeted because there
  * is supposedly no free space. But in most cases there is some free space:
@@ -165,87 +154,42 @@ static int run_gc(struct ubifs_info *c)
  * Returns %-ENOSPC if it couldn't do more free space, and other negative error
  * codes on failures.
  */
-static int make_free_space(struct ubifs_info *c, struct retries_info *ri)
+static int make_free_space(struct ubifs_info *c)
 {
-       int err;
-
-       /*
-        * If we have some dirty pages and inodes (liability), try to write
-        * them back unless this was tried too many times without effect
-        * already.
-        */
-       if (ri->shrink_retries < MAX_SHRINK_RETRIES && !ri->try_gc) {
-               long long liability;
-
-               spin_lock(&c->space_lock);
-               liability = c->budg_idx_growth + c->budg_data_growth +
-                           c->budg_dd_growth;
-               spin_unlock(&c->space_lock);
+       int err, retries = 0;
+       long long liab1, liab2;
 
-               if (ri->prev_liability >= liability) {
-                       /* Liability does not shrink, next time try GC then */
-                       ri->shrink_retries += 1;
-                       if (ri->gc_retries < MAX_GC_RETRIES)
-                               ri->try_gc = 1;
-                       dbg_budg("liability did not shrink: retries %d of %d",
-                                ri->shrink_retries, MAX_SHRINK_RETRIES);
-               }
+       do {
+               liab1 = get_liability(c);
+               /*
+                * We probably have some dirty pages or inodes (liability), try
+                * to write them back.
+                */
+               dbg_budg("liability %lld, run write-back", liab1);
+               shrink_liability(c, NR_TO_WRITE);
 
-               dbg_budg("force write-back (count %d)", ri->shrink_cnt);
-               shrink_liability(c, NR_TO_WRITE + ri->shrink_cnt);
+               liab2 = get_liability(c);
+               if (liab2 < liab1)
+                       return -EAGAIN;
 
-               ri->prev_liability = liability;
-               ri->shrink_cnt += 1;
-               return -EAGAIN;
-       }
+               dbg_budg("new liability %lld (not shrinked)", liab2);
 
-       /*
-        * Try to run garbage collector unless it was already tried too many
-        * times.
-        */
-       if (ri->gc_retries < MAX_GC_RETRIES) {
-               ri->gc_retries += 1;
-               dbg_budg("run GC, retries %d of %d",
-                        ri->gc_retries, MAX_GC_RETRIES);
-
-               ri->try_gc = 0;
+               /* Liability did not shrink again, try GC */
+               dbg_budg("Run GC");
                err = run_gc(c);
                if (!err)
                        return -EAGAIN;
 
-               if (err == -EAGAIN) {
-                       dbg_budg("GC asked to commit");
-                       err = ubifs_run_commit(c);
-                       if (err)
-                               return err;
-                       return -EAGAIN;
-               }
-
-               if (err != -ENOSPC)
-                       return err;
-
-               /*
-                * GC could not make any progress. If this is the first time,
-                * then it makes sense to try to commit, because it might make
-                * some dirty space.
-                */
-               dbg_budg("GC returned -ENOSPC, retries %d",
-                        ri->nospc_retries);
-               if (ri->nospc_retries >= MAX_NOSPC_RETRIES)
+               if (err != -EAGAIN && err != -ENOSPC)
+                       /* Some real error happened */
                        return err;
-               ri->nospc_retries += 1;
-       }
 
-       /* Neither GC nor write-back helped, try to commit */
-       if (ri->cmt_retries < MAX_CMT_RETRIES) {
-               ri->cmt_retries += 1;
-               dbg_budg("run commit, retries %d of %d",
-                        ri->cmt_retries, MAX_CMT_RETRIES);
+               dbg_budg("Run commit (retries %d)", retries);
                err = ubifs_run_commit(c);
                if (err)
                        return err;
-               return -EAGAIN;
-       }
+       } while (retries++ < MAX_MKSPC_RETRIES);
+
        return -ENOSPC;
 }
 
@@ -258,8 +202,8 @@ static int make_free_space(struct ubifs_info *c, struct retries_info *ri)
  */
 int ubifs_calc_min_idx_lebs(struct ubifs_info *c)
 {
-       int ret;
-       uint64_t idx_size;
+       int idx_lebs, eff_leb_size = c->leb_size - c->max_idx_node_sz;
+       long long idx_size;
 
        idx_size = c->old_idx_sz + c->budg_idx_growth + c->budg_uncommitted_idx;
 
@@ -271,23 +215,16 @@ int ubifs_calc_min_idx_lebs(struct ubifs_info *c)
         * pair, nor similarly the two variables for the new index size, so we
         * have to do this costly 64-bit division on fast-path.
         */
-       if (do_div(idx_size, c->leb_size - c->max_idx_node_sz))
-               ret = idx_size + 1;
-       else
-               ret = idx_size;
+       idx_size += eff_leb_size - 1;
+       idx_lebs = div_u64(idx_size, eff_leb_size);
        /*
         * The index head is not available for the in-the-gaps method, so add an
         * extra LEB to compensate.
         */
-       ret += 1;
-       /*
-        * At present the index needs at least 2 LEBs: one for the index head
-        * and one for in-the-gaps method (which currently does not cater for
-        * the index head and so excludes it from consideration).
-        */
-       if (ret < 2)
-               ret = 2;
-       return ret;
+       idx_lebs += 1;
+       if (idx_lebs < MIN_INDEX_LEBS)
+               idx_lebs = MIN_INDEX_LEBS;
+       return idx_lebs;
 }
 
 /**
@@ -530,8 +467,7 @@ static int calc_dd_growth(const struct ubifs_info *c,
 int ubifs_budget_space(struct ubifs_info *c, struct ubifs_budget_req *req)
 {
        int uninitialized_var(cmt_retries), uninitialized_var(wb_retries);
-       int err, idx_growth, data_growth, dd_growth;
-       struct retries_info ri;
+       int err, idx_growth, data_growth, dd_growth, retried = 0;
 
        ubifs_assert(req->new_page <= 1);
        ubifs_assert(req->dirtied_page <= 1);
@@ -549,7 +485,6 @@ int ubifs_budget_space(struct ubifs_info *c, struct ubifs_budget_req *req)
        if (!data_growth && !dd_growth)
                return 0;
        idx_growth = calc_idx_growth(c, req);
-       memset(&ri, 0, sizeof(struct retries_info));
 
 again:
        spin_lock(&c->space_lock);
@@ -587,12 +522,17 @@ again:
                return err;
        }
 
-       err = make_free_space(c, &ri);
+       err = make_free_space(c);
+       cond_resched();
        if (err == -EAGAIN) {
                dbg_budg("try again");
-               cond_resched();
                goto again;
        } else if (err == -ENOSPC) {
+               if (!retried) {
+                       retried = 1;
+                       dbg_budg("-ENOSPC, but anyway try once again");
+                       goto again;
+               }
                dbg_budg("FS is full, -ENOSPC");
                c->nospace = 1;
                if (can_use_rp(c) || c->rp_size == 0)
@@ -712,9 +652,9 @@ void ubifs_release_dirty_inode_budget(struct ubifs_info *c,
  * user-space. User-space application tend to expect that if the file-system
  * (e.g., via the 'statfs()' call) reports that it has N bytes available, they
  * are able to write a file of size N. UBIFS attaches node headers to each data
- * node and it has to write indexind nodes as well. This introduces additional
- * overhead, and UBIFS it has to report sligtly less free space to meet the
- * above expectetion.
+ * node and it has to write indexing nodes as well. This introduces additional
+ * overhead, and UBIFS has to report slightly less free space to meet the above
+ * expectations.
  *
  * This function assumes free space is made up of uncompressed data nodes and
  * full index nodes (one per data node, tripled because we always allow enough
@@ -723,7 +663,7 @@ void ubifs_release_dirty_inode_budget(struct ubifs_info *c,
  * Note, the calculation is pessimistic, which means that most of the time
  * UBIFS reports less space than it actually has.
  */
-long long ubifs_reported_space(const struct ubifs_info *c, uint64_t free)
+long long ubifs_reported_space(const struct ubifs_info *c, long long free)
 {
        int divisor, factor, f;
 
@@ -737,7 +677,7 @@ long long ubifs_reported_space(const struct ubifs_info *c, uint64_t free)
         * of data nodes, f - fanout. Because effective UBIFS fanout is twice
         * as less than maximum fanout, we assume that each data node
         * introduces 3 * @c->max_idx_node_sz / (@c->fanout/2 - 1) bytes.
-        * Note, the multiplier 3 is because UBIFS reseves thrice as more space
+        * Note, the multiplier 3 is because UBIFS reserves thrice as more space
         * for the index.
         */
        f = c->fanout > 3 ? c->fanout >> 1 : 2;
@@ -745,8 +685,7 @@ long long ubifs_reported_space(const struct ubifs_info *c, uint64_t free)
        divisor = UBIFS_MAX_DATA_NODE_SZ;
        divisor += (c->max_idx_node_sz * 3) / (f - 1);
        free *= factor;
-       do_div(free, divisor);
-       return free;
+       return div_u64(free, divisor);
 }
 
 /**
@@ -756,10 +695,10 @@ long long ubifs_reported_space(const struct ubifs_info *c, uint64_t free)
  * This function calculates amount of free space to report to user-space.
  *
  * Because UBIFS may introduce substantial overhead (the index, node headers,
- * alighment, wastage at the end of eraseblocks, etc), it cannot report real
+ * alignment, wastage at the end of eraseblocks, etc), it cannot report real
  * amount of free flash space it has (well, because not all dirty space is
- * reclamable, UBIFS does not actually know the real amount). If UBIFS did so,
- * it would bread user expectetion about what free space is. Users seem to
+ * reclaimable, UBIFS does not actually know the real amount). If UBIFS did so,
+ * it would bread user expectations about what free space is. Users seem to
  * accustomed to assume that if the file-system reports N bytes of free space,
  * they would be able to fit a file of N bytes to the FS. This almost works for
  * traditional file-systems, because they have way less overhead than UBIFS.
@@ -771,18 +710,9 @@ long long ubifs_get_free_space(struct ubifs_info *c)
        long long available, outstanding, free;
 
        spin_lock(&c->space_lock);
-       min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+       min_idx_lebs = c->min_idx_lebs;
+       ubifs_assert(min_idx_lebs == ubifs_calc_min_idx_lebs(c));
        outstanding = c->budg_data_growth + c->budg_dd_growth;
-
-       /*
-        * Force the amount available to the total size reported if the used
-        * space is zero.
-        */
-       if (c->lst.total_used <= UBIFS_INO_NODE_SZ && !outstanding) {
-               spin_unlock(&c->space_lock);
-               return (long long)c->block_cnt << UBIFS_BLOCK_SHIFT;
-       }
-
        available = ubifs_calc_available(c, min_idx_lebs);
 
        /*
index b49884c8c10e823cbe484e9d5c1fadddf16b5008..f3a7945527fb694b9902143763deebc15231b3aa 100644 (file)
@@ -470,12 +470,12 @@ int dbg_old_index_check_init(struct ubifs_info *c, struct ubifs_zbranch *zroot)
 {
        struct ubifs_idx_node *idx;
        int lnum, offs, len, err = 0;
+       struct ubifs_debug_info *d = c->dbg;
 
-       c->old_zroot = *zroot;
-
-       lnum = c->old_zroot.lnum;
-       offs = c->old_zroot.offs;
-       len = c->old_zroot.len;
+       d->old_zroot = *zroot;
+       lnum = d->old_zroot.lnum;
+       offs = d->old_zroot.offs;
+       len = d->old_zroot.len;
 
        idx = kmalloc(c->max_idx_node_sz, GFP_NOFS);
        if (!idx)
@@ -485,8 +485,8 @@ int dbg_old_index_check_init(struct ubifs_info *c, struct ubifs_zbranch *zroot)
        if (err)
                goto out;
 
-       c->old_zroot_level = le16_to_cpu(idx->level);
-       c->old_zroot_sqnum = le64_to_cpu(idx->ch.sqnum);
+       d->old_zroot_level = le16_to_cpu(idx->level);
+       d->old_zroot_sqnum = le64_to_cpu(idx->ch.sqnum);
 out:
        kfree(idx);
        return err;
@@ -509,6 +509,7 @@ int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot)
 {
        int lnum, offs, len, err = 0, uninitialized_var(last_level), child_cnt;
        int first = 1, iip;
+       struct ubifs_debug_info *d = c->dbg;
        union ubifs_key lower_key, upper_key, l_key, u_key;
        unsigned long long uninitialized_var(last_sqnum);
        struct ubifs_idx_node *idx;
@@ -525,9 +526,9 @@ int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot)
             UBIFS_IDX_NODE_SZ;
 
        /* Start at the old zroot */
-       lnum = c->old_zroot.lnum;
-       offs = c->old_zroot.offs;
-       len = c->old_zroot.len;
+       lnum = d->old_zroot.lnum;
+       offs = d->old_zroot.offs;
+       len = d->old_zroot.len;
        iip = 0;
 
        /*
@@ -560,11 +561,11 @@ int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot)
                if (first) {
                        first = 0;
                        /* Check root level and sqnum */
-                       if (le16_to_cpu(idx->level) != c->old_zroot_level) {
+                       if (le16_to_cpu(idx->level) != d->old_zroot_level) {
                                err = 2;
                                goto out_dump;
                        }
-                       if (le64_to_cpu(idx->ch.sqnum) != c->old_zroot_sqnum) {
+                       if (le64_to_cpu(idx->ch.sqnum) != d->old_zroot_sqnum) {
                                err = 3;
                                goto out_dump;
                        }
index a0ada596b17c4a5d9180b515e5fd7e524b72a642..11e4132f314acfcabc610cf97f4c4dd9e52b768d 100644 (file)
@@ -33,7 +33,7 @@
 /* Fake description object for the "none" compressor */
 static struct ubifs_compressor none_compr = {
        .compr_type = UBIFS_COMPR_NONE,
-       .name = "no compression",
+       .name = "none",
        .capi_name = "",
 };
 
@@ -43,13 +43,13 @@ static DEFINE_MUTEX(lzo_mutex);
 static struct ubifs_compressor lzo_compr = {
        .compr_type = UBIFS_COMPR_LZO,
        .comp_mutex = &lzo_mutex,
-       .name = "LZO",
+       .name = "lzo",
        .capi_name = "lzo",
 };
 #else
 static struct ubifs_compressor lzo_compr = {
        .compr_type = UBIFS_COMPR_LZO,
-       .name = "LZO",
+       .name = "lzo",
 };
 #endif
 
@@ -108,7 +108,7 @@ void ubifs_compress(const void *in_buf, int in_len, void *out_buf, int *out_len,
        if (compr->comp_mutex)
                mutex_lock(compr->comp_mutex);
        err = crypto_comp_compress(compr->cc, in_buf, in_len, out_buf,
-                                  out_len);
+                                  (unsigned int *)out_len);
        if (compr->comp_mutex)
                mutex_unlock(compr->comp_mutex);
        if (unlikely(err)) {
@@ -119,10 +119,10 @@ void ubifs_compress(const void *in_buf, int in_len, void *out_buf, int *out_len,
        }
 
        /*
-        * Presently, we just require that compression results in less data,
-        * rather than any defined minimum compression ratio or amount.
+        * If the data compressed only slightly, it is better to leave it
+        * uncompressed to improve read speed.
         */
-       if (ALIGN(*out_len, 8) >= ALIGN(in_len, 8))
+       if (in_len - *out_len < UBIFS_MIN_COMPRESS_DIFF)
                goto no_compr;
 
        return;
@@ -172,7 +172,7 @@ int ubifs_decompress(const void *in_buf, int in_len, void *out_buf,
        if (compr->decomp_mutex)
                mutex_lock(compr->decomp_mutex);
        err = crypto_comp_decompress(compr->cc, in_buf, in_len, out_buf,
-                                    out_len);
+                                    (unsigned int *)out_len);
        if (compr->decomp_mutex)
                mutex_unlock(compr->decomp_mutex);
        if (err)
@@ -244,7 +244,7 @@ out_lzo:
 /**
  * ubifs_compressors_exit - de-initialize UBIFS compressors.
  */
-void __exit ubifs_compressors_exit(void)
+void ubifs_compressors_exit(void)
 {
        compr_exit(&lzo_compr);
        compr_exit(&zlib_compr);
index 510ffa0bbda4658559cf682a01145d4ff7f9231e..792c5a16c182e6b4f501e85041c7144e444370e8 100644 (file)
@@ -32,6 +32,8 @@
 #include "ubifs.h"
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/debugfs.h>
+#include <linux/math64.h>
 
 #ifdef CONFIG_UBIFS_FS_DEBUG
 
@@ -596,7 +598,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,
@@ -629,6 +633,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);
 }
 
@@ -645,7 +660,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);
 
@@ -656,6 +672,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)
@@ -663,6 +681,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);
@@ -684,7 +703,8 @@ void dbg_dump_lpt_info(struct ubifs_info *c)
        printk(KERN_DEBUG "\tLPT root is at %d:%d\n", c->lpt_lnum, c->lpt_offs);
        printk(KERN_DEBUG "\tLPT head is at %d:%d\n",
               c->nhead_lnum, c->nhead_offs);
-       printk(KERN_DEBUG "\tLPT ltab is at %d:%d\n", c->ltab_lnum, c->ltab_offs);
+       printk(KERN_DEBUG "\tLPT ltab is at %d:%d\n",
+              c->ltab_lnum, c->ltab_offs);
        if (c->big_lpt)
                printk(KERN_DEBUG "\tLPT lsave is at %d:%d\n",
                       c->lsave_lnum, c->lsave_offs);
@@ -703,9 +723,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;
@@ -721,6 +741,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;
 }
@@ -768,7 +790,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];
@@ -777,6 +799,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,
@@ -784,7 +807,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",
@@ -803,7 +826,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);
@@ -815,8 +838,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,
@@ -992,8 +1014,8 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
                        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;
+               dbg_dump_node(c, dent1);
+               goto out_free;
        }
 
        key_read(c, &dent2->key, &key);
@@ -1002,8 +1024,8 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
                        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;
+               dbg_dump_node(c, dent2);
+               goto out_free;
        }
 
        nlen1 = le16_to_cpu(dent1->nlen);
@@ -1020,9 +1042,9 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
                dbg_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:
@@ -2097,13 +2119,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;
@@ -2112,7 +2134,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;
 
@@ -2146,42 +2168,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) {
@@ -2239,7 +2263,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;
 }
@@ -2344,4 +2368,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 */
index 33d6b95071e4589f94c17530d0d14320920c47af..9820d6999f7e0b2704325713cba2150a7c4b0cef 100644 (file)
 
 #ifdef CONFIG_UBIFS_FS_DEBUG
 
-#define UBIFS_DBG(op) op
+/**
+ * ubifs_debug_info - per-FS debugging information.
+ * @buf: a buffer of LEB size, used for various purposes
+ * @old_zroot: old index root - used by 'dbg_check_old_index()'
+ * @old_zroot_level: old index root level - used by 'dbg_check_old_index()'
+ * @old_zroot_sqnum: old index root sqnum - used by 'dbg_check_old_index()'
+ * @failure_mode: failure mode for recovery testing
+ * @fail_delay: 0=>don't delay, 1=>delay a time, 2=>delay a number of calls
+ * @fail_timeout: time in jiffies when delay of failure mode expires
+ * @fail_cnt: current number of calls to failure mode I/O functions
+ * @fail_cnt_max: number of calls by which to delay failure mode
+ * @chk_lpt_sz: used by LPT tree size checker
+ * @chk_lpt_sz2: used by LPT tree size checker
+ * @chk_lpt_wastage: used by LPT tree size checker
+ * @chk_lpt_lebs: used by LPT tree size checker
+ * @new_nhead_offs: used by LPT tree size checker
+ * @new_ihead_lnum: used by debugging to check ihead_lnum
+ * @new_ihead_offs: used by debugging to check ihead_offs
+ *
+ * debugfs_dir_name: name of debugfs directory containing this file-system's
+ *                   files
+ * debugfs_dir: direntry object of the file-system debugfs directory
+ * dump_lprops: "dump lprops" debugfs knob
+ * dump_budg: "dump budgeting information" debugfs knob
+ * dump_tnc: "dump TNC" debugfs knob
+ */
+struct ubifs_debug_info {
+       void *buf;
+       struct ubifs_zbranch old_zroot;
+       int old_zroot_level;
+       unsigned long long old_zroot_sqnum;
+       int failure_mode;
+       int fail_delay;
+       unsigned long fail_timeout;
+       unsigned int fail_cnt;
+       unsigned int fail_cnt_max;
+       long long chk_lpt_sz;
+       long long chk_lpt_sz2;
+       long long chk_lpt_wastage;
+       int chk_lpt_lebs;
+       int new_nhead_offs;
+       int new_ihead_lnum;
+       int new_ihead_offs;
+
+       char debugfs_dir_name[100];
+       struct dentry *debugfs_dir;
+       struct dentry *dump_lprops;
+       struct dentry *dump_budg;
+       struct dentry *dump_tnc;
+};
 
 #define ubifs_assert(expr) do {                                                \
        if (unlikely(!(expr))) {                                               \
@@ -211,14 +260,18 @@ extern unsigned int ubifs_msg_flags;
 extern unsigned int ubifs_chk_flags;
 extern unsigned int ubifs_tst_flags;
 
-/* Dump functions */
+int ubifs_debugging_init(struct ubifs_info *c);
+void ubifs_debugging_exit(struct ubifs_info *c);
 
+/* Dump functions */
 const char *dbg_ntype(int type);
 const char *dbg_cstate(int cmt_state);
 const char *dbg_get_key_dump(const struct ubifs_info *c,
                             const union ubifs_key *key);
 void dbg_dump_inode(const struct ubifs_info *c, const struct inode *inode);
 void dbg_dump_node(const struct ubifs_info *c, const void *node);
+void dbg_dump_lpt_node(const struct ubifs_info *c, void *node, int lnum,
+                      int offs);
 void dbg_dump_budget_req(const struct ubifs_budget_req *req);
 void dbg_dump_lstats(const struct ubifs_lp_stats *lst);
 void dbg_dump_budg(struct ubifs_info *c);
@@ -233,9 +286,9 @@ void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
                    struct ubifs_nnode *parent, int iip);
 void dbg_dump_tnc(struct ubifs_info *c);
 void dbg_dump_index(struct ubifs_info *c);
+void dbg_dump_lpt_lebs(const struct ubifs_info *c);
 
 /* Checking helper functions */
-
 typedef int (*dbg_leaf_callback)(struct ubifs_info *c,
                                 struct ubifs_zbranch *zbr, void *priv);
 typedef int (*dbg_znode_callback)(struct ubifs_info *c,
@@ -274,9 +327,6 @@ int dbg_force_in_the_gaps(void);
 
 #define dbg_failure_mode (ubifs_tst_flags & UBIFS_TST_RCVRY)
 
-void dbg_failure_mode_registration(struct ubifs_info *c);
-void dbg_failure_mode_deregistration(struct ubifs_info *c);
-
 #ifndef UBIFS_DBG_PRESERVE_UBI
 
 #define ubi_leb_read   dbg_leb_read
@@ -318,9 +368,13 @@ static inline int dbg_change(struct ubi_volume_desc *desc, int lnum,
        return dbg_leb_change(desc, lnum, buf, len, UBI_UNKNOWN);
 }
 
-#else /* !CONFIG_UBIFS_FS_DEBUG */
+/* Debugfs-related stuff */
+int dbg_debugfs_init(void);
+void dbg_debugfs_exit(void);
+int dbg_debugfs_init_fs(struct ubifs_info *c);
+void dbg_debugfs_exit_fs(struct ubifs_info *c);
 
-#define UBIFS_DBG(op)
+#else /* !CONFIG_UBIFS_FS_DEBUG */
 
 /* Use "if (0)" to make compiler check arguments even if debugging is off */
 #define ubifs_assert(expr)  do {                                               \
@@ -360,23 +414,28 @@ static inline int dbg_change(struct ubi_volume_desc *desc, int lnum,
 #define DBGKEY(key)  ((char *)(key))
 #define DBGKEY1(key) ((char *)(key))
 
-#define dbg_ntype(type)                       ""
-#define dbg_cstate(cmt_state)                 ""
-#define dbg_get_key_dump(c, key)              ({})
-#define dbg_dump_inode(c, inode)              ({})
-#define dbg_dump_node(c, node)                ({})
-#define dbg_dump_budget_req(req)              ({})
-#define dbg_dump_lstats(lst)                  ({})
-#define dbg_dump_budg(c)                      ({})
-#define dbg_dump_lprop(c, lp)                 ({})
-#define dbg_dump_lprops(c)                    ({})
-#define dbg_dump_lpt_info(c)                  ({})
-#define dbg_dump_leb(c, lnum)                 ({})
-#define dbg_dump_znode(c, znode)              ({})
-#define dbg_dump_heap(c, heap, cat)           ({})
-#define dbg_dump_pnode(c, pnode, parent, iip) ({})
-#define dbg_dump_tnc(c)                       ({})
-#define dbg_dump_index(c)                     ({})
+#define ubifs_debugging_init(c)                0
+#define ubifs_debugging_exit(c)                ({})
+
+#define dbg_ntype(type)                        ""
+#define dbg_cstate(cmt_state)                  ""
+#define dbg_get_key_dump(c, key)               ({})
+#define dbg_dump_inode(c, inode)               ({})
+#define dbg_dump_node(c, node)                 ({})
+#define dbg_dump_lpt_node(c, node, lnum, offs) ({})
+#define dbg_dump_budget_req(req)               ({})
+#define dbg_dump_lstats(lst)                   ({})
+#define dbg_dump_budg(c)                       ({})
+#define dbg_dump_lprop(c, lp)                  ({})
+#define dbg_dump_lprops(c)                     ({})
+#define dbg_dump_lpt_info(c)                   ({})
+#define dbg_dump_leb(c, lnum)                  ({})
+#define dbg_dump_znode(c, znode)               ({})
+#define dbg_dump_heap(c, heap, cat)            ({})
+#define dbg_dump_pnode(c, pnode, parent, iip)  ({})
+#define dbg_dump_tnc(c)                        ({})
+#define dbg_dump_index(c)                      ({})
+#define dbg_dump_lpt_lebs(c)                   ({})
 
 #define dbg_walk_index(c, leaf_cb, znode_cb, priv) 0
 #define dbg_old_index_check_init(c, zroot)         0
@@ -396,9 +455,11 @@ static inline int dbg_change(struct ubi_volume_desc *desc, int lnum,
 #define dbg_force_in_the_gaps_enabled              0
 #define dbg_force_in_the_gaps()                    0
 #define dbg_failure_mode                           0
-#define dbg_failure_mode_registration(c)           ({})
-#define dbg_failure_mode_deregistration(c)         ({})
 
-#endif /* !CONFIG_UBIFS_FS_DEBUG */
+#define dbg_debugfs_init()                         0
+#define dbg_debugfs_exit()
+#define dbg_debugfs_init_fs(c)                     0
+#define dbg_debugfs_exit_fs(c)                     0
 
+#endif /* !CONFIG_UBIFS_FS_DEBUG */
 #endif /* !__UBIFS_DEBUG_H__ */
index 2624411d9758d11023c938418f8a6a7938066ff5..fe82d2464d463f0eed8939400964524d04592971 100644 (file)
@@ -72,8 +72,8 @@ static int read_block(struct inode *inode, void *addr, unsigned int block,
                return err;
        }
 
-       ubifs_assert(le64_to_cpu(dn->ch.sqnum) > ubifs_inode(inode)->creat_sqnum);
-
+       ubifs_assert(le64_to_cpu(dn->ch.sqnum) >
+                    ubifs_inode(inode)->creat_sqnum);
        len = le32_to_cpu(dn->size);
        if (len <= 0 || len > UBIFS_BLOCK_SIZE)
                goto dump;
@@ -254,7 +254,7 @@ static int write_begin_slow(struct address_space *mapping,
        }
 
        if (!PageUptodate(page)) {
-               if (!(pos & PAGE_CACHE_MASK) && len == PAGE_CACHE_SIZE)
+               if (!(pos & ~PAGE_CACHE_MASK) && len == PAGE_CACHE_SIZE)
                        SetPageChecked(page);
                else {
                        err = do_readpage(page);
@@ -444,7 +444,7 @@ static int ubifs_write_begin(struct file *file, struct address_space *mapping,
 
        if (!PageUptodate(page)) {
                /* The page is not loaded from the flash */
-               if (!(pos & PAGE_CACHE_MASK) && len == PAGE_CACHE_SIZE)
+               if (!(pos & ~PAGE_CACHE_MASK) && len == PAGE_CACHE_SIZE)
                        /*
                         * We change whole page so no need to load it. But we
                         * have to set the @PG_checked flag to make the further
index 5e82cffe969503594101c9f5e418d3d77ce6064c..6db7a6be6c9732a8a14cecc8ea60683522493442 100644 (file)
@@ -154,6 +154,7 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case FS_IOC_GETFLAGS:
                flags = ubifs2ioctl(ubifs_inode(inode)->flags);
 
+               dbg_gen("get flags: %#x, i_flags %#x", flags, inode->i_flags);
                return put_user(flags, (int __user *) arg);
 
        case FS_IOC_SETFLAGS: {
@@ -176,6 +177,7 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                err = mnt_want_write(file->f_path.mnt);
                if (err)
                        return err;
+               dbg_gen("set flags: %#x, i_flags %#x", flags, inode->i_flags);
                err = setflags(inode, flags);
                mnt_drop_write(file->f_path.mnt);
                return err;
index f91b745908ea595ac94bd25b86368d5515149be0..10ae25b7d1dbe4e4ed84c8d6f4d835a3cd40f37c 100644 (file)
@@ -704,7 +704,7 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
        data->size = cpu_to_le32(len);
        zero_data_node_unused(data);
 
-       if (!(ui->flags && UBIFS_COMPR_FL))
+       if (!(ui->flags & UBIFS_COMPR_FL))
                /* Compression is disabled for this inode */
                compr_type = UBIFS_COMPR_NONE;
        else
@@ -1220,7 +1220,7 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
        data_key_init(c, &key, inum, blk);
 
        bit = old_size & (UBIFS_BLOCK_SIZE - 1);
-       blk = (old_size >> UBIFS_BLOCK_SHIFT) - (bit ? 0: 1);
+       blk = (old_size >> UBIFS_BLOCK_SHIFT) - (bit ? 0 : 1);
        data_key_init(c, &to_key, inum, blk);
 
        err = ubifs_tnc_remove_range(c, &key, &to_key);
index 3f1f16bc25c99ba1e019c940030c1fa48b7217fa..efb3430a2581c4b723cafc6f846ed7b5841ed933 100644 (file)
 #ifndef __UBIFS_KEY_H__
 #define __UBIFS_KEY_H__
 
+/**
+ * key_mask_hash - mask a valid hash value.
+ * @val: value to be masked
+ *
+ * We use hash values as offset in directories, so values %0 and %1 are
+ * reserved for "." and "..". %2 is reserved for "end of readdir" marker. This
+ * function makes sure the reserved values are not used.
+ */
+static inline uint32_t key_mask_hash(uint32_t hash)
+{
+       hash &= UBIFS_S_KEY_HASH_MASK;
+       if (unlikely(hash <= 2))
+               hash += 3;
+       return hash;
+}
+
 /**
  * key_r5_hash - R5 hash function (borrowed from reiserfs).
  * @s: direntry name
@@ -54,16 +70,7 @@ static inline uint32_t key_r5_hash(const char *s, int len)
                str++;
        }
 
-       a &= UBIFS_S_KEY_HASH_MASK;
-
-       /*
-        * We use hash values as offset in directories, so values %0 and %1 are
-        * reserved for "." and "..". %2 is reserved for "end of readdir"
-        * marker.
-        */
-       if (unlikely(a >= 0 && a <= 2))
-               a += 3;
-       return a;
+       return key_mask_hash(a);
 }
 
 /**
@@ -77,10 +84,7 @@ static inline uint32_t key_test_hash(const char *str, int len)
 
        len = min_t(uint32_t, len, 4);
        memcpy(&a, str, len);
-       a &= UBIFS_S_KEY_HASH_MASK;
-       if (unlikely(a >= 0 && a <= 2))
-               a += 3;
-       return a;
+       return key_mask_hash(a);
 }
 
 /**
index f27176e9b70d7208074e0825065f3a79618f9940..dfd2bcece27a865de970f3d4333468c5ebb5db66 100644 (file)
@@ -520,13 +520,13 @@ static int is_lprops_dirty(struct ubifs_info *c, struct ubifs_lprops *lprops)
  * @flags: new flags
  * @idx_gc_cnt: change to the count of idx_gc list
  *
- * This function changes LEB properties. This function does not change a LEB
- * property (@free, @dirty or @flag) if the value passed is %LPROPS_NC.
+ * This function changes LEB properties (@free, @dirty or @flag). However, the
+ * property which has the %LPROPS_NC value is not changed. Returns a pointer to
+ * the updated LEB properties on success and a negative error code on failure.
  *
- * This function returns a pointer to the updated LEB properties on success
- * and a negative error code on failure. N.B. the LEB properties may have had to
- * be copied (due to COW) and consequently the pointer returned may not be the
- * same as the pointer passed.
+ * Note, the LEB properties may have had to be copied (due to COW) and
+ * consequently the pointer returned may not be the same as the pointer
+ * passed.
  */
 const struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c,
                                           const struct ubifs_lprops *lp,
@@ -1088,7 +1088,7 @@ static int scan_check_cb(struct ubifs_info *c,
                }
        }
 
-       sleb = ubifs_scan(c, lnum, 0, c->dbg_buf);
+       sleb = ubifs_scan(c, lnum, 0, c->dbg->buf);
        if (IS_ERR(sleb)) {
                /*
                 * After an unclean unmount, empty and freeable LEBs
index db8bd0e518b21151c5d6f11eff7d40bac62fc9ff..b2792e84d2452fd37e27991b42c1ab5754044de4 100644 (file)
  * can be written into a single eraseblock. In that case, garbage collection
  * consists of just writing the whole table, which therefore makes all other
  * eraseblocks reusable. In the case of the big model, dirty eraseblocks are
- * selected for garbage collection, which consists are marking the nodes in
+ * selected for garbage collection, which consists of marking the clean nodes in
  * that LEB as dirty, and then only the dirty nodes are written out. Also, in
  * the case of the big model, a table of LEB numbers is saved so that the entire
  * LPT does not to be scanned looking for empty eraseblocks when UBIFS is first
  * mounted.
  */
 
-#include <linux/crc16.h>
 #include "ubifs.h"
+#include <linux/crc16.h>
+#include <linux/math64.h>
 
 /**
  * do_calc_lpt_geom - calculate sizes for the LPT area.
@@ -135,15 +136,13 @@ static void do_calc_lpt_geom(struct ubifs_info *c)
 int ubifs_calc_lpt_geom(struct ubifs_info *c)
 {
        int lebs_needed;
-       uint64_t sz;
+       long long sz;
 
        do_calc_lpt_geom(c);
 
        /* Verify that lpt_lebs is big enough */
        sz = c->lpt_sz * 2; /* Must have at least 2 times the size */
-       sz += c->leb_size - 1;
-       do_div(sz, c->leb_size);
-       lebs_needed = sz;
+       lebs_needed = div_u64(sz + c->leb_size - 1, c->leb_size);
        if (lebs_needed > c->lpt_lebs) {
                ubifs_err("too few LPT LEBs");
                return -EINVAL;
@@ -156,7 +155,6 @@ int ubifs_calc_lpt_geom(struct ubifs_info *c)
        }
 
        c->check_lpt_free = c->big_lpt;
-
        return 0;
 }
 
@@ -176,7 +174,7 @@ static int calc_dflt_lpt_geom(struct ubifs_info *c, int *main_lebs,
                              int *big_lpt)
 {
        int i, lebs_needed;
-       uint64_t sz;
+       long long sz;
 
        /* Start by assuming the minimum number of LPT LEBs */
        c->lpt_lebs = UBIFS_MIN_LPT_LEBS;
@@ -203,9 +201,7 @@ static int calc_dflt_lpt_geom(struct ubifs_info *c, int *main_lebs,
        /* Now check there are enough LPT LEBs */
        for (i = 0; i < 64 ; i++) {
                sz = c->lpt_sz * 4; /* Allow 4 times the size */
-               sz += c->leb_size - 1;
-               do_div(sz, c->leb_size);
-               lebs_needed = sz;
+               lebs_needed = div_u64(sz + c->leb_size - 1, c->leb_size);
                if (lebs_needed > c->lpt_lebs) {
                        /* Not enough LPT LEBs so try again with more */
                        c->lpt_lebs = lebs_needed;
@@ -558,7 +554,7 @@ static int calc_nnode_num(int row, int col)
  * This function calculates and returns the nnode number based on the parent's
  * nnode number and the index in parent.
  */
-static int calc_nnode_num_from_parent(struct ubifs_info *c,
+static int calc_nnode_num_from_parent(const struct ubifs_info *c,
                                      struct ubifs_nnode *parent, int iip)
 {
        int num, shft;
@@ -583,7 +579,7 @@ static int calc_nnode_num_from_parent(struct ubifs_info *c,
  * This function calculates and returns the pnode number based on the parent's
  * nnode number and the index in parent.
  */
-static int calc_pnode_num_from_parent(struct ubifs_info *c,
+static int calc_pnode_num_from_parent(const struct ubifs_info *c,
                                      struct ubifs_nnode *parent, int iip)
 {
        int i, n = c->lpt_hght - 1, pnum = parent->num, num = 0;
@@ -966,7 +962,7 @@ static int check_lpt_type(uint8_t **addr, int *pos, int type)
  *
  * This function returns %0 on success and a negative error code on failure.
  */
-static int unpack_pnode(struct ubifs_info *c, void *buf,
+static int unpack_pnode(const struct ubifs_info *c, void *buf,
                        struct ubifs_pnode *pnode)
 {
        uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
@@ -996,15 +992,15 @@ static int unpack_pnode(struct ubifs_info *c, void *buf,
 }
 
 /**
- * unpack_nnode - unpack a nnode.
+ * ubifs_unpack_nnode - unpack a nnode.
  * @c: UBIFS file-system description object
  * @buf: buffer containing packed nnode to unpack
  * @nnode: nnode structure to fill
  *
  * This function returns %0 on success and a negative error code on failure.
  */
-static int unpack_nnode(struct ubifs_info *c, void *buf,
-                       struct ubifs_nnode *nnode)
+int ubifs_unpack_nnode(const struct ubifs_info *c, void *buf,
+                      struct ubifs_nnode *nnode)
 {
        uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
        int i, pos = 0, err;
@@ -1036,7 +1032,7 @@ static int unpack_nnode(struct ubifs_info *c, void *buf,
  *
  * This function returns %0 on success and a negative error code on failure.
  */
-static int unpack_ltab(struct ubifs_info *c, void *buf)
+static int unpack_ltab(const struct ubifs_info *c, void *buf)
 {
        uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
        int i, pos = 0, err;
@@ -1068,7 +1064,7 @@ static int unpack_ltab(struct ubifs_info *c, void *buf)
  *
  * This function returns %0 on success and a negative error code on failure.
  */
-static int unpack_lsave(struct ubifs_info *c, void *buf)
+static int unpack_lsave(const struct ubifs_info *c, void *buf)
 {
        uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
        int i, pos = 0, err;
@@ -1096,7 +1092,7 @@ static int unpack_lsave(struct ubifs_info *c, void *buf)
  *
  * This function returns %0 on success and a negative error code on failure.
  */
-static int validate_nnode(struct ubifs_info *c, struct ubifs_nnode *nnode,
+static int validate_nnode(const struct ubifs_info *c, struct ubifs_nnode *nnode,
                          struct ubifs_nnode *parent, int iip)
 {
        int i, lvl, max_offs;
@@ -1140,7 +1136,7 @@ static int validate_nnode(struct ubifs_info *c, struct ubifs_nnode *nnode,
  *
  * This function returns %0 on success and a negative error code on failure.
  */
-static int validate_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
+static int validate_pnode(const struct ubifs_info *c, struct ubifs_pnode *pnode,
                          struct ubifs_nnode *parent, int iip)
 {
        int i;
@@ -1174,7 +1170,8 @@ static int validate_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
  * This function calculates the LEB numbers for the LEB properties it contains
  * based on the pnode number.
  */
-static void set_pnode_lnum(struct ubifs_info *c, struct ubifs_pnode *pnode)
+static void set_pnode_lnum(const struct ubifs_info *c,
+                          struct ubifs_pnode *pnode)
 {
        int i, lnum;
 
@@ -1227,7 +1224,7 @@ int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
                err = ubi_read(c->ubi, lnum, buf, offs, c->nnode_sz);
                if (err)
                        goto out;
-               err = unpack_nnode(c, buf, nnode);
+               err = ubifs_unpack_nnode(c, buf, nnode);
                if (err)
                        goto out;
        }
@@ -1816,7 +1813,7 @@ static struct ubifs_nnode *scan_get_nnode(struct ubifs_info *c,
                               c->nnode_sz);
                if (err)
                        return ERR_PTR(err);
-               err = unpack_nnode(c, buf, nnode);
+               err = ubifs_unpack_nnode(c, buf, nnode);
                if (err)
                        return ERR_PTR(err);
        }
index a41434b427854e66527775ca3e6fdfcb89a332bd..96ca957071754067f7aeddf5dcecc2b0a2b12116 100644 (file)
@@ -320,6 +320,8 @@ no_space:
        dbg_err("LPT out of space at LEB %d:%d needing %d, done_ltab %d, "
                "done_lsave %d", lnum, offs, len, done_ltab, done_lsave);
        dbg_dump_lpt_info(c);
+       dbg_dump_lpt_lebs(c);
+       dump_stack();
        return err;
 }
 
@@ -546,8 +548,10 @@ static int write_cnodes(struct ubifs_info *c)
 no_space:
        ubifs_err("LPT out of space mismatch");
        dbg_err("LPT out of space mismatch at LEB %d:%d needing %d, done_ltab "
-               "%d, done_lsave %d", lnum, offs, len, done_ltab, done_lsave);
+               "%d, done_lsave %d", lnum, offs, len, done_ltab, done_lsave);
        dbg_dump_lpt_info(c);
+       dbg_dump_lpt_lebs(c);
+       dump_stack();
        return err;
 }
 
@@ -749,7 +753,7 @@ static void lpt_tgc_start(struct ubifs_info *c)
  * LPT trivial garbage collection is where a LPT LEB contains only dirty and
  * free space and so may be reused as soon as the next commit is completed.
  * This function is called after the commit is completed (master node has been
- * written) and unmaps LPT LEBs that were marked for trivial GC.
+ * written) and un-maps LPT LEBs that were marked for trivial GC.
  */
 static int lpt_tgc_end(struct ubifs_info *c)
 {
@@ -1025,7 +1029,7 @@ static int make_node_dirty(struct ubifs_info *c, int node_type, int node_num,
  * @c: UBIFS file-system description object
  * @node_type: LPT node type
  */
-static int get_lpt_node_len(struct ubifs_info *c, int node_type)
+static int get_lpt_node_len(const struct ubifs_info *c, int node_type)
 {
        switch (node_type) {
        case UBIFS_LPT_NNODE:
@@ -1046,7 +1050,7 @@ static int get_lpt_node_len(struct ubifs_info *c, int node_type)
  * @buf: buffer
  * @len: length of buffer
  */
-static int get_pad_len(struct ubifs_info *c, uint8_t *buf, int len)
+static int get_pad_len(const struct ubifs_info *c, uint8_t *buf, int len)
 {
        int offs, pad_len;
 
@@ -1063,7 +1067,8 @@ static int get_pad_len(struct ubifs_info *c, uint8_t *buf, int len)
  * @buf: buffer
  * @node_num: node number is returned here
  */
-static int get_lpt_node_type(struct ubifs_info *c, uint8_t *buf, int *node_num)
+static int get_lpt_node_type(const struct ubifs_info *c, uint8_t *buf,
+                            int *node_num)
 {
        uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
        int pos = 0, node_type;
@@ -1081,7 +1086,7 @@ static int get_lpt_node_type(struct ubifs_info *c, uint8_t *buf, int *node_num)
  *
  * This function returns %1 if the buffer contains a node or %0 if it does not.
  */
-static int is_a_node(struct ubifs_info *c, uint8_t *buf, int len)
+static int is_a_node(const struct ubifs_info *c, uint8_t *buf, int len)
 {
        uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
        int pos = 0, node_type, node_len;
@@ -1105,7 +1110,6 @@ static int is_a_node(struct ubifs_info *c, uint8_t *buf, int len)
        return 1;
 }
 
-
 /**
  * lpt_gc_lnum - garbage collect a LPT LEB.
  * @c: UBIFS file-system description object
@@ -1463,7 +1467,7 @@ void ubifs_lpt_free(struct ubifs_info *c, int wr_only)
 #ifdef CONFIG_UBIFS_FS_DEBUG
 
 /**
- * dbg_is_all_ff - determine if a buffer contains only 0xff bytes.
+ * dbg_is_all_ff - determine if a buffer contains only 0xFF bytes.
  * @buf: buffer
  * @len: buffer length
  */
@@ -1488,7 +1492,7 @@ static int dbg_is_nnode_dirty(struct ubifs_info *c, int lnum, int offs)
        struct ubifs_nnode *nnode;
        int hght;
 
-       /* Entire tree is in memory so first_nnode / next_nnode are ok */
+       /* Entire tree is in memory so first_nnode / next_nnode are OK */
        nnode = first_nnode(c, &hght);
        for (; nnode; nnode = next_nnode(c, nnode, &hght)) {
                struct ubifs_nbranch *branch;
@@ -1602,7 +1606,10 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)
 {
        int err, len = c->leb_size, dirty = 0, node_type, node_num, node_len;
        int ret;
-       void *buf = c->dbg_buf;
+       void *buf = c->dbg->buf;
+
+       if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
+               return 0;
 
        dbg_lp("LEB %d", lnum);
        err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
@@ -1704,6 +1711,9 @@ int dbg_chk_lpt_free_spc(struct ubifs_info *c)
        long long free = 0;
        int i;
 
+       if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
+               return 0;
+
        for (i = 0; i < c->lpt_lebs; i++) {
                if (c->ltab[i].tgc || c->ltab[i].cmt)
                        continue;
@@ -1716,6 +1726,8 @@ int dbg_chk_lpt_free_spc(struct ubifs_info *c)
                dbg_err("LPT space error: free %lld lpt_sz %lld",
                        free, c->lpt_sz);
                dbg_dump_lpt_info(c);
+               dbg_dump_lpt_lebs(c);
+               dump_stack();
                return -EINVAL;
        }
        return 0;
@@ -1731,15 +1743,19 @@ int dbg_chk_lpt_free_spc(struct ubifs_info *c)
  */
 int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)
 {
+       struct ubifs_debug_info *d = c->dbg;
        long long chk_lpt_sz, lpt_sz;
        int err = 0;
 
+       if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
+               return 0;
+
        switch (action) {
        case 0:
-               c->chk_lpt_sz = 0;
-               c->chk_lpt_sz2 = 0;
-               c->chk_lpt_lebs = 0;
-               c->chk_lpt_wastage = 0;
+               d->chk_lpt_sz = 0;
+               d->chk_lpt_sz2 = 0;
+               d->chk_lpt_lebs = 0;
+               d->chk_lpt_wastage = 0;
                if (c->dirty_pn_cnt > c->pnode_cnt) {
                        dbg_err("dirty pnodes %d exceed max %d",
                                c->dirty_pn_cnt, c->pnode_cnt);
@@ -1752,35 +1768,35 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)
                }
                return err;
        case 1:
-               c->chk_lpt_sz += len;
+               d->chk_lpt_sz += len;
                return 0;
        case 2:
-               c->chk_lpt_sz += len;
-               c->chk_lpt_wastage += len;
-               c->chk_lpt_lebs += 1;
+               d->chk_lpt_sz += len;
+               d->chk_lpt_wastage += len;
+               d->chk_lpt_lebs += 1;
                return 0;
        case 3:
                chk_lpt_sz = c->leb_size;
-               chk_lpt_sz *= c->chk_lpt_lebs;
+               chk_lpt_sz *= d->chk_lpt_lebs;
                chk_lpt_sz += len - c->nhead_offs;
-               if (c->chk_lpt_sz != chk_lpt_sz) {
+               if (d->chk_lpt_sz != chk_lpt_sz) {
                        dbg_err("LPT wrote %lld but space used was %lld",
-                               c->chk_lpt_sz, chk_lpt_sz);
+                               d->chk_lpt_sz, chk_lpt_sz);
                        err = -EINVAL;
                }
-               if (c->chk_lpt_sz > c->lpt_sz) {
+               if (d->chk_lpt_sz > c->lpt_sz) {
                        dbg_err("LPT wrote %lld but lpt_sz is %lld",
-                               c->chk_lpt_sz, c->lpt_sz);
+                               d->chk_lpt_sz, c->lpt_sz);
                        err = -EINVAL;
                }
-               if (c->chk_lpt_sz2 && c->chk_lpt_sz != c->chk_lpt_sz2) {
+               if (d->chk_lpt_sz2 && d->chk_lpt_sz != d->chk_lpt_sz2) {
                        dbg_err("LPT layout size %lld but wrote %lld",
-                               c->chk_lpt_sz, c->chk_lpt_sz2);
+                               d->chk_lpt_sz, d->chk_lpt_sz2);
                        err = -EINVAL;
                }
-               if (c->chk_lpt_sz2 && c->new_nhead_offs != len) {
+               if (d->chk_lpt_sz2 && d->new_nhead_offs != len) {
                        dbg_err("LPT new nhead offs: expected %d was %d",
-                               c->new_nhead_offs, len);
+                               d->new_nhead_offs, len);
                        err = -EINVAL;
                }
                lpt_sz = (long long)c->pnode_cnt * c->pnode_sz;
@@ -1788,26 +1804,146 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)
                lpt_sz += c->ltab_sz;
                if (c->big_lpt)
                        lpt_sz += c->lsave_sz;
-               if (c->chk_lpt_sz - c->chk_lpt_wastage > lpt_sz) {
+               if (d->chk_lpt_sz - d->chk_lpt_wastage > lpt_sz) {
                        dbg_err("LPT chk_lpt_sz %lld + waste %lld exceeds %lld",
-                               c->chk_lpt_sz, c->chk_lpt_wastage, lpt_sz);
+                               d->chk_lpt_sz, d->chk_lpt_wastage, lpt_sz);
                        err = -EINVAL;
                }
-               if (err)
+               if (err) {
                        dbg_dump_lpt_info(c);
-               c->chk_lpt_sz2 = c->chk_lpt_sz;
-               c->chk_lpt_sz = 0;
-               c->chk_lpt_wastage = 0;
-               c->chk_lpt_lebs = 0;
-               c->new_nhead_offs = len;
+                       dbg_dump_lpt_lebs(c);
+                       dump_stack();
+               }
+               d->chk_lpt_sz2 = d->chk_lpt_sz;
+               d->chk_lpt_sz = 0;
+               d->chk_lpt_wastage = 0;
+               d->chk_lpt_lebs = 0;
+               d->new_nhead_offs = len;
                return err;
        case 4:
-               c->chk_lpt_sz += len;
-               c->chk_lpt_wastage += len;
+               d->chk_lpt_sz += len;
+               d->chk_lpt_wastage += len;
                return 0;
        default:
                return -EINVAL;
        }
 }
 
+/**
+ * dbg_dump_lpt_leb - dump an LPT LEB.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number to dump
+ *
+ * This function dumps an LEB from LPT area. Nodes in this area are very
+ * different to nodes in the main area (e.g., they do not have common headers,
+ * they do not have 8-byte alignments, etc), so we have a separate function to
+ * dump LPT area LEBs. Note, LPT has to be locked by the caller.
+ */
+static void dump_lpt_leb(const struct ubifs_info *c, int lnum)
+{
+       int err, len = c->leb_size, node_type, node_num, node_len, offs;
+       void *buf = c->dbg->buf;
+
+       printk(KERN_DEBUG "(pid %d) start dumping LEB %d\n",
+              current->pid, lnum);
+       err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
+       if (err) {
+               ubifs_err("cannot read LEB %d, error %d", lnum, err);
+               return;
+       }
+       while (1) {
+               offs = c->leb_size - len;
+               if (!is_a_node(c, buf, len)) {
+                       int pad_len;
+
+                       pad_len = get_pad_len(c, buf, len);
+                       if (pad_len) {
+                               printk(KERN_DEBUG "LEB %d:%d, pad %d bytes\n",
+                                      lnum, offs, pad_len);
+                               buf += pad_len;
+                               len -= pad_len;
+                               continue;
+                       }
+                       if (len)
+                               printk(KERN_DEBUG "LEB %d:%d, free %d bytes\n",
+                                      lnum, offs, len);
+                       break;
+               }
+
+               node_type = get_lpt_node_type(c, buf, &node_num);
+               switch (node_type) {
+               case UBIFS_LPT_PNODE:
+               {
+                       node_len = c->pnode_sz;
+                       if (c->big_lpt)
+                               printk(KERN_DEBUG "LEB %d:%d, pnode num %d\n",
+                                      lnum, offs, node_num);
+                       else
+                               printk(KERN_DEBUG "LEB %d:%d, pnode\n",
+                                      lnum, offs);
+                       break;
+               }
+               case UBIFS_LPT_NNODE:
+               {
+                       int i;
+                       struct ubifs_nnode nnode;
+
+                       node_len = c->nnode_sz;
+                       if (c->big_lpt)
+                               printk(KERN_DEBUG "LEB %d:%d, nnode num %d, ",
+                                      lnum, offs, node_num);
+                       else
+                               printk(KERN_DEBUG "LEB %d:%d, nnode, ",
+                                      lnum, offs);
+                       err = ubifs_unpack_nnode(c, buf, &nnode);
+                       for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+                               printk("%d:%d", nnode.nbranch[i].lnum,
+                                      nnode.nbranch[i].offs);
+                               if (i != UBIFS_LPT_FANOUT - 1)
+                                       printk(", ");
+                       }
+                       printk("\n");
+                       break;
+               }
+               case UBIFS_LPT_LTAB:
+                       node_len = c->ltab_sz;
+                       printk(KERN_DEBUG "LEB %d:%d, ltab\n",
+                              lnum, offs);
+                       break;
+               case UBIFS_LPT_LSAVE:
+                       node_len = c->lsave_sz;
+                       printk(KERN_DEBUG "LEB %d:%d, lsave len\n", lnum, offs);
+                       break;
+               default:
+                       ubifs_err("LPT node type %d not recognized", node_type);
+                       return;
+               }
+
+               buf += node_len;
+               len -= node_len;
+       }
+
+       printk(KERN_DEBUG "(pid %d) finish dumping LEB %d\n",
+              current->pid, lnum);
+}
+
+/**
+ * dbg_dump_lpt_lebs - dump LPT lebs.
+ * @c: UBIFS file-system description object
+ *
+ * This function dumps all LPT LEBs. The caller has to make sure the LPT is
+ * locked.
+ */
+void dbg_dump_lpt_lebs(const struct ubifs_info *c)
+{
+       int i;
+
+       printk(KERN_DEBUG "(pid %d) start dumping all LPT LEBs\n",
+              current->pid);
+       for (i = 0; i < c->lpt_lebs; i++)
+               dump_lpt_leb(c, i + c->lpt_first);
+       printk(KERN_DEBUG "(pid %d) finish dumping all LPT LEBs\n",
+              current->pid);
+}
+
 #endif /* CONFIG_UBIFS_FS_DEBUG */
index 9bd5a43d4526c8d7a55d0ae2a1fb4fa37a3fd922..9e6f403f170e4425641c5db8b833db9f63c3ce7b 100644 (file)
@@ -899,7 +899,7 @@ static int dbg_scan_orphans(struct ubifs_info *c, struct check_info *ci)
        for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) {
                struct ubifs_scan_leb *sleb;
 
-               sleb = ubifs_scan(c, lnum, 0, c->dbg_buf);
+               sleb = ubifs_scan(c, lnum, 0, c->dbg->buf);
                if (IS_ERR(sleb)) {
                        err = PTR_ERR(sleb);
                        break;
index 21f7d047c306be4cc3761deed76ea0de2ff8ea3f..ce42a7b0ca5a3113b92495ed67a2970a36292a49 100644 (file)
@@ -144,7 +144,7 @@ static int set_bud_lprops(struct ubifs_info *c, struct replay_entry *r)
                /*
                 * If the replay order was perfect the dirty space would now be
                 * zero. The order is not perfect because the the journal heads
-                * race with eachother. This is not a problem but is does mean
+                * race with each other. This is not a problem but is does mean
                 * that the dirty space may temporarily exceed c->leb_size
                 * during the replay.
                 */
@@ -656,7 +656,7 @@ out_dump:
  * @dirty: amount of dirty space from padding and deletion nodes
  *
  * This function inserts a reference node to the replay tree and returns zero
- * in case of success ort a negative error code in case of failure.
+ * in case of success or a negative error code in case of failure.
  */
 static int insert_ref_node(struct ubifs_info *c, int lnum, int offs,
                           unsigned long long sqnum, int free, int dirty)
@@ -883,7 +883,7 @@ static int replay_log_leb(struct ubifs_info *c, int lnum, int offs, void *sbuf)
                 * This means that we reached end of log and now
                 * look to the older log data, which was already
                 * committed but the eraseblock was not erased (UBIFS
-                * only unmaps it). So this basically means we have to
+                * only un-maps it). So this basically means we have to
                 * exit with "end of log" code.
                 */
                err = 1;
@@ -1062,6 +1062,15 @@ int ubifs_replay_journal(struct ubifs_info *c)
        if (err)
                goto out;
 
+       /*
+        * UBIFS budgeting calculations use @c->budg_uncommitted_idx variable
+        * to roughly estimate index growth. Things like @c->min_idx_lebs
+        * depend on it. This means we have to initialize it to make sure
+        * budgeting works properly.
+        */
+       c->budg_uncommitted_idx = atomic_long_read(&c->dirty_zn_cnt);
+       c->budg_uncommitted_idx *= c->max_idx_node_sz;
+
        ubifs_assert(c->bud_bytes <= c->max_bud_bytes || c->need_recovery);
        dbg_mnt("finished, log head LEB %d:%d, max_sqnum %llu, "
                "highest_inum %lu", c->lhead_lnum, c->lhead_offs, c->max_sqnum,
index 0f392351dc5a57232c776ccf7577c7d759d5da85..e070c643d1bb180b0099c7674f9703d4be0870ce 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "ubifs.h"
 #include <linux/random.h>
+#include <linux/math64.h>
 
 /*
  * Default journal size in logical eraseblocks as a percent of total
@@ -80,7 +81,7 @@ static int create_default_filesystem(struct ubifs_info *c)
        int err, tmp, jnl_lebs, log_lebs, max_buds, main_lebs, main_first;
        int lpt_lebs, lpt_first, orph_lebs, big_lpt, ino_waste, sup_flags = 0;
        int min_leb_cnt = UBIFS_MIN_LEB_CNT;
-       uint64_t tmp64, main_bytes;
+       long long tmp64, main_bytes;
        __le64 tmp_le64;
 
        /* Some functions called from here depend on the @c->key_len filed */
@@ -160,7 +161,7 @@ static int create_default_filesystem(struct ubifs_info *c)
        if (!sup)
                return -ENOMEM;
 
-       tmp64 = (uint64_t)max_buds * c->leb_size;
+       tmp64 = (long long)max_buds * c->leb_size;
        if (big_lpt)
                sup_flags |= UBIFS_FLG_BIGLPT;
 
@@ -179,14 +180,16 @@ static int create_default_filesystem(struct ubifs_info *c)
        sup->fanout        = cpu_to_le32(DEFAULT_FANOUT);
        sup->lsave_cnt     = cpu_to_le32(c->lsave_cnt);
        sup->fmt_version   = cpu_to_le32(UBIFS_FORMAT_VERSION);
-       sup->default_compr = cpu_to_le16(UBIFS_COMPR_LZO);
        sup->time_gran     = cpu_to_le32(DEFAULT_TIME_GRAN);
+       if (c->mount_opts.override_compr)
+               sup->default_compr = cpu_to_le16(c->mount_opts.compr_type);
+       else
+               sup->default_compr = cpu_to_le16(UBIFS_COMPR_LZO);
 
        generate_random_uuid(sup->uuid);
 
-       main_bytes = (uint64_t)main_lebs * c->leb_size;
-       tmp64 = main_bytes * DEFAULT_RP_PERCENT;
-       do_div(tmp64, 100);
+       main_bytes = (long long)main_lebs * c->leb_size;
+       tmp64 = div_u64(main_bytes * DEFAULT_RP_PERCENT, 100);
        if (tmp64 > DEFAULT_MAX_RP_SIZE)
                tmp64 = DEFAULT_MAX_RP_SIZE;
        sup->rp_size = cpu_to_le64(tmp64);
@@ -582,16 +585,15 @@ int ubifs_read_superblock(struct ubifs_info *c)
        c->jhead_cnt     = le32_to_cpu(sup->jhead_cnt) + NONDATA_JHEADS_CNT;
        c->fanout        = le32_to_cpu(sup->fanout);
        c->lsave_cnt     = le32_to_cpu(sup->lsave_cnt);
-       c->default_compr = le16_to_cpu(sup->default_compr);
        c->rp_size       = le64_to_cpu(sup->rp_size);
        c->rp_uid        = le32_to_cpu(sup->rp_uid);
        c->rp_gid        = le32_to_cpu(sup->rp_gid);
        sup_flags        = le32_to_cpu(sup->flags);
+       if (!c->mount_opts.override_compr)
+               c->default_compr = le16_to_cpu(sup->default_compr);
 
        c->vfs_sb->s_time_gran = le32_to_cpu(sup->time_gran);
-
        memcpy(&c->uuid, &sup->uuid, 16);
-
        c->big_lpt = !!(sup_flags & UBIFS_FLG_BIGLPT);
 
        /* Automatically increase file system size to the maximum size */
index d80b2aef42b661001b2c87ac645f9a8ac29fbfd7..0d7564b95f8e2572ff47e661e7616fce7354a440 100644 (file)
@@ -34,6 +34,8 @@
 #include <linux/parser.h>
 #include <linux/seq_file.h>
 #include <linux/mount.h>
+#include <linux/math64.h>
+#include <linux/writeback.h>
 #include "ubifs.h"
 
 /*
@@ -417,39 +419,54 @@ static int ubifs_show_options(struct seq_file *s, struct vfsmount *mnt)
        else if (c->mount_opts.chk_data_crc == 1)
                seq_printf(s, ",no_chk_data_crc");
 
+       if (c->mount_opts.override_compr) {
+               seq_printf(s, ",compr=");
+               seq_printf(s, ubifs_compr_name(c->mount_opts.compr_type));
+       }
+
        return 0;
 }
 
 static int ubifs_sync_fs(struct super_block *sb, int wait)
 {
+       int i, err;
        struct ubifs_info *c = sb->s_fs_info;
-       int i, ret = 0, err;
-       long long bud_bytes;
-
-       if (c->jheads) {
-               for (i = 0; i < c->jhead_cnt; i++) {
-                       err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
-                       if (err && !ret)
-                               ret = err;
-               }
+       struct writeback_control wbc = {
+               .sync_mode   = wait ? WB_SYNC_ALL : WB_SYNC_HOLD,
+               .range_start = 0,
+               .range_end   = LLONG_MAX,
+               .nr_to_write = LONG_MAX,
+       };
+
+       if (sb->s_flags & MS_RDONLY)
+               return 0;
 
-               /* Commit the journal unless it has too little data */
-               spin_lock(&c->buds_lock);
-               bud_bytes = c->bud_bytes;
-               spin_unlock(&c->buds_lock);
-               if (bud_bytes > c->leb_size) {
-                       err = ubifs_run_commit(c);
-                       if (err)
-                               return err;
-               }
+       /*
+        * Synchronize write buffers, because 'ubifs_run_commit()' does not
+        * do this if it waits for an already running commit.
+        */
+       for (i = 0; i < c->jhead_cnt; i++) {
+               err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
+               if (err)
+                       return err;
        }
 
        /*
-        * We ought to call sync for c->ubi but it does not have one. If it had
-        * it would in turn call mtd->sync, however mtd operations are
-        * synchronous anyway, so we don't lose any sleep here.
+        * VFS calls '->sync_fs()' before synchronizing all dirty inodes and
+        * pages, so synchronize them first, then commit the journal. Strictly
+        * speaking, it is not necessary to commit the journal here,
+        * synchronizing write-buffers would be enough. But committing makes
+        * UBIFS free space predictions much more accurate, so we want to let
+        * the user be able to get more accurate results of 'statfs()' after
+        * they synchronize the file system.
         */
-       return ret;
+       generic_sync_sb_inodes(sb, &wbc);
+
+       err = ubifs_run_commit(c);
+       if (err)
+               return err;
+
+       return ubi_sync(c->vi.ubi_num);
 }
 
 /**
@@ -596,7 +613,7 @@ static int bud_wbuf_callback(struct ubifs_info *c, int lnum, int free, int pad)
 }
 
 /*
- * init_constants_late - initialize UBIFS constants.
+ * init_constants_sb - initialize UBIFS constants.
  * @c: UBIFS file-system description object
  *
  * This is a helper function which initializes various UBIFS constants after
@@ -604,10 +621,10 @@ static int bud_wbuf_callback(struct ubifs_info *c, int lnum, int free, int pad)
  * makes sure they are all right. Returns zero in case of success and a
  * negative error code in case of failure.
  */
-static int init_constants_late(struct ubifs_info *c)
+static int init_constants_sb(struct ubifs_info *c)
 {
        int tmp, err;
-       uint64_t tmp64;
+       long long tmp64;
 
        c->main_bytes = (long long)c->main_lebs * c->leb_size;
        c->max_znode_sz = sizeof(struct ubifs_znode) +
@@ -634,9 +651,8 @@ static int init_constants_late(struct ubifs_info *c)
         * Make sure that the log is large enough to fit reference nodes for
         * all buds plus one reserved LEB.
         */
-       tmp64 = c->max_bud_bytes;
-       tmp = do_div(tmp64, c->leb_size);
-       c->max_bud_cnt = tmp64 + !!tmp;
+       tmp64 = c->max_bud_bytes + c->leb_size - 1;
+       c->max_bud_cnt = div_u64(tmp64, c->leb_size);
        tmp = (c->ref_node_alsz * c->max_bud_cnt + c->leb_size - 1);
        tmp /= c->leb_size;
        tmp += 1;
@@ -672,7 +688,7 @@ static int init_constants_late(struct ubifs_info *c)
         * Consequently, if the journal is too small, UBIFS will treat it as
         * always full.
         */
-       tmp64 = (uint64_t)(c->jhead_cnt + 1) * c->leb_size + 1;
+       tmp64 = (long long)(c->jhead_cnt + 1) * c->leb_size + 1;
        if (c->bg_bud_bytes < tmp64)
                c->bg_bud_bytes = tmp64;
        if (c->max_bud_bytes < tmp64 + c->leb_size)
@@ -682,6 +698,21 @@ static int init_constants_late(struct ubifs_info *c)
        if (err)
                return err;
 
+       return 0;
+}
+
+/*
+ * init_constants_master - initialize UBIFS constants.
+ * @c: UBIFS file-system description object
+ *
+ * This is a helper function which initializes various UBIFS constants after
+ * the master node has been read. It also checks various UBIFS parameters and
+ * makes sure they are all right.
+ */
+static void init_constants_master(struct ubifs_info *c)
+{
+       long long tmp64;
+
        c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
 
        /*
@@ -690,14 +721,13 @@ static int init_constants_late(struct ubifs_info *c)
         * necessary to report something for the 'statfs()' call.
         *
         * Subtract the LEB reserved for GC, the LEB which is reserved for
-        * deletions, and assume only one journal head is available.
+        * deletions, minimum LEBs for the index, and assume only one journal
+        * head is available.
         */
-       tmp64 = c->main_lebs - 2 - c->jhead_cnt + 1;
-       tmp64 *= (uint64_t)c->leb_size - c->leb_overhead;
+       tmp64 = c->main_lebs - 1 - 1 - MIN_INDEX_LEBS - c->jhead_cnt + 1;
+       tmp64 *= (long long)c->leb_size - c->leb_overhead;
        tmp64 = ubifs_reported_space(c, tmp64);
        c->block_cnt = tmp64 >> UBIFS_BLOCK_SHIFT;
-
-       return 0;
 }
 
 /**
@@ -878,6 +908,7 @@ static int check_volume_empty(struct ubifs_info *c)
  * Opt_no_bulk_read: disable bulk-reads
  * Opt_chk_data_crc: check CRCs when reading data nodes
  * Opt_no_chk_data_crc: do not check CRCs when reading data nodes
+ * Opt_override_compr: override default compressor
  * Opt_err: just end of array marker
  */
 enum {
@@ -887,6 +918,7 @@ enum {
        Opt_no_bulk_read,
        Opt_chk_data_crc,
        Opt_no_chk_data_crc,
+       Opt_override_compr,
        Opt_err,
 };
 
@@ -897,6 +929,7 @@ static const match_table_t tokens = {
        {Opt_no_bulk_read, "no_bulk_read"},
        {Opt_chk_data_crc, "chk_data_crc"},
        {Opt_no_chk_data_crc, "no_chk_data_crc"},
+       {Opt_override_compr, "compr=%s"},
        {Opt_err, NULL},
 };
 
@@ -950,6 +983,28 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options,
                        c->mount_opts.chk_data_crc = 1;
                        c->no_chk_data_crc = 1;
                        break;
+               case Opt_override_compr:
+               {
+                       char *name = match_strdup(&args[0]);
+
+                       if (!name)
+                               return -ENOMEM;
+                       if (!strcmp(name, "none"))
+                               c->mount_opts.compr_type = UBIFS_COMPR_NONE;
+                       else if (!strcmp(name, "lzo"))
+                               c->mount_opts.compr_type = UBIFS_COMPR_LZO;
+                       else if (!strcmp(name, "zlib"))
+                               c->mount_opts.compr_type = UBIFS_COMPR_ZLIB;
+                       else {
+                               ubifs_err("unknown compressor \"%s\"", name);
+                               kfree(name);
+                               return -EINVAL;
+                       }
+                       kfree(name);
+                       c->mount_opts.override_compr = 1;
+                       c->default_compr = c->mount_opts.compr_type;
+                       break;
+               }
                default:
                        ubifs_err("unrecognized mount option \"%s\" "
                                  "or missing value", p);
@@ -1018,6 +1073,30 @@ again:
        }
 }
 
+/**
+ * check_free_space - check if there is enough free space to mount.
+ * @c: UBIFS file-system description object
+ *
+ * This function makes sure UBIFS has enough free space to be mounted in
+ * read/write mode. UBIFS must always have some free space to allow deletions.
+ */
+static int check_free_space(struct ubifs_info *c)
+{
+       ubifs_assert(c->dark_wm > 0);
+       if (c->lst.total_free + c->lst.total_dirty < c->dark_wm) {
+               ubifs_err("insufficient free space to mount in read/write mode");
+               dbg_dump_budg(c);
+               dbg_dump_lprops(c);
+               /*
+                * We return %-EINVAL instead of %-ENOSPC because it seems to
+                * be the closest error code mentioned in the mount function
+                * documentation.
+                */
+               return -EINVAL;
+       }
+       return 0;
+}
+
 /**
  * mount_ubifs - mount UBIFS file-system.
  * @c: UBIFS file-system description object
@@ -1039,11 +1118,9 @@ static int mount_ubifs(struct ubifs_info *c)
        if (err)
                return err;
 
-#ifdef CONFIG_UBIFS_FS_DEBUG
-       c->dbg_buf = vmalloc(c->leb_size);
-       if (!c->dbg_buf)
-               return -ENOMEM;
-#endif
+       err = ubifs_debugging_init(c);
+       if (err)
+               return err;
 
        err = check_volume_empty(c);
        if (err)
@@ -1100,27 +1177,25 @@ static int mount_ubifs(struct ubifs_info *c)
                goto out_free;
 
        /*
-        * Make sure the compressor which is set as the default on in the
-        * superblock was actually compiled in.
+        * Make sure the compressor which is set as default in the superblock
+        * or overridden by mount options is actually compiled in.
         */
        if (!ubifs_compr_present(c->default_compr)) {
-               ubifs_warn("'%s' compressor is set by superblock, but not "
-                          "compiled in", ubifs_compr_name(c->default_compr));
-               c->default_compr = UBIFS_COMPR_NONE;
+               ubifs_err("'compressor \"%s\" is not compiled in",
+                         ubifs_compr_name(c->default_compr));
+               goto out_free;
        }
 
-       dbg_failure_mode_registration(c);
-
-       err = init_constants_late(c);
+       err = init_constants_sb(c);
        if (err)
-               goto out_dereg;
+               goto out_free;
 
        sz = ALIGN(c->max_idx_node_sz, c->min_io_size);
        sz = ALIGN(sz + c->max_idx_node_sz, c->min_io_size);
        c->cbuf = kmalloc(sz, GFP_NOFS);
        if (!c->cbuf) {
                err = -ENOMEM;
-               goto out_dereg;
+               goto out_free;
        }
 
        sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num, c->vi.vol_id);
@@ -1145,6 +1220,8 @@ static int mount_ubifs(struct ubifs_info *c)
        if (err)
                goto out_master;
 
+       init_constants_master(c);
+
        if ((c->mst_node->flags & cpu_to_le32(UBIFS_MST_DIRTY)) != 0) {
                ubifs_msg("recovery needed");
                c->need_recovery = 1;
@@ -1183,12 +1260,9 @@ static int mount_ubifs(struct ubifs_info *c)
        if (!mounted_read_only) {
                int lnum;
 
-               /* Check for enough free space */
-               if (ubifs_calc_available(c, c->min_idx_lebs) <= 0) {
-                       ubifs_err("insufficient available space");
-                       err = -EINVAL;
+               err = check_free_space(c);
+               if (err)
                        goto out_orphans;
-               }
 
                /* Check for enough log space */
                lnum = c->lhead_lnum + 1;
@@ -1232,6 +1306,10 @@ static int mount_ubifs(struct ubifs_info *c)
                }
        }
 
+       err = dbg_debugfs_init_fs(c);
+       if (err)
+               goto out_infos;
+
        err = dbg_check_filesystem(c);
        if (err)
                goto out_infos;
@@ -1283,8 +1361,20 @@ static int mount_ubifs(struct ubifs_info *c)
        dbg_msg("tree fanout:         %d", c->fanout);
        dbg_msg("reserved GC LEB:     %d", c->gc_lnum);
        dbg_msg("first main LEB:      %d", c->main_first);
+       dbg_msg("max. znode size      %d", c->max_znode_sz);
+       dbg_msg("max. index node size %d", c->max_idx_node_sz);
+       dbg_msg("node sizes:          data %zu, inode %zu, dentry %zu",
+               UBIFS_DATA_NODE_SZ, UBIFS_INO_NODE_SZ, UBIFS_DENT_NODE_SZ);
+       dbg_msg("node sizes:          trun %zu, sb %zu, master %zu",
+               UBIFS_TRUN_NODE_SZ, UBIFS_SB_NODE_SZ, UBIFS_MST_NODE_SZ);
+       dbg_msg("node sizes:          ref %zu, cmt. start %zu, orph %zu",
+               UBIFS_REF_NODE_SZ, UBIFS_CS_NODE_SZ, UBIFS_ORPH_NODE_SZ);
+       dbg_msg("max. node sizes:     data %zu, inode %zu dentry %zu",
+               UBIFS_MAX_DATA_NODE_SZ, UBIFS_MAX_INO_NODE_SZ,
+               UBIFS_MAX_DENT_NODE_SZ);
        dbg_msg("dead watermark:      %d", c->dead_wm);
        dbg_msg("dark watermark:      %d", c->dark_wm);
+       dbg_msg("LEB overhead:        %d", c->leb_overhead);
        x = (long long)c->main_lebs * c->dark_wm;
        dbg_msg("max. dark space:     %lld (%lld KiB, %lld MiB)",
                x, x >> 10, x >> 20);
@@ -1320,14 +1410,12 @@ out_wbufs:
        free_wbufs(c);
 out_cbuf:
        kfree(c->cbuf);
-out_dereg:
-       dbg_failure_mode_deregistration(c);
 out_free:
        kfree(c->bu.buf);
        vfree(c->ileb_buf);
        vfree(c->sbuf);
        kfree(c->bottom_up_buf);
-       UBIFS_DBG(vfree(c->dbg_buf));
+       ubifs_debugging_exit(c);
        return err;
 }
 
@@ -1345,6 +1433,7 @@ static void ubifs_umount(struct ubifs_info *c)
        dbg_gen("un-mounting UBI device %d, volume %d", c->vi.ubi_num,
                c->vi.vol_id);
 
+       dbg_debugfs_exit_fs(c);
        spin_lock(&ubifs_infos_lock);
        list_del(&c->infos_list);
        spin_unlock(&ubifs_infos_lock);
@@ -1364,8 +1453,7 @@ static void ubifs_umount(struct ubifs_info *c)
        vfree(c->ileb_buf);
        vfree(c->sbuf);
        kfree(c->bottom_up_buf);
-       UBIFS_DBG(vfree(c->dbg_buf));
-       dbg_failure_mode_deregistration(c);
+       ubifs_debugging_exit(c);
 }
 
 /**
@@ -1387,12 +1475,9 @@ static int ubifs_remount_rw(struct ubifs_info *c)
        c->remounting_rw = 1;
        c->always_chk_crc = 1;
 
-       /* Check for enough free space */
-       if (ubifs_calc_available(c, c->min_idx_lebs) <= 0) {
-               ubifs_err("insufficient available space");
-               err = -EINVAL;
+       err = check_free_space(c);
+       if (err)
                goto out;
-       }
 
        if (c->old_leb_cnt != c->leb_cnt) {
                struct ubifs_sb_node *sup;
@@ -1515,20 +1600,24 @@ out:
  * @c: UBIFS file-system description object
  *
  * This function is called during un-mounting and re-mounting, and it commits
- * the journal unless the "fast unmount" mode is enabled. It also avoids
- * committing the journal if it contains too few data.
+ * the journal unless the "fast unmount" mode is enabled.
  */
 static void commit_on_unmount(struct ubifs_info *c)
 {
-       if (!c->fast_unmount) {
-               long long bud_bytes;
+       struct super_block *sb = c->vfs_sb;
+       long long bud_bytes;
 
-               spin_lock(&c->buds_lock);
-               bud_bytes = c->bud_bytes;
-               spin_unlock(&c->buds_lock);
-               if (bud_bytes > c->leb_size)
-                       ubifs_run_commit(c);
-       }
+       /*
+        * This function is called before the background thread is stopped, so
+        * we may race with ongoing commit, which means we have to take
+        * @c->bud_lock to access @c->bud_bytes.
+        */
+       spin_lock(&c->buds_lock);
+       bud_bytes = c->bud_bytes;
+       spin_unlock(&c->buds_lock);
+
+       if (!c->fast_unmount && !(sb->s_flags & MS_RDONLY) && bud_bytes)
+               ubifs_run_commit(c);
 }
 
 /**
@@ -1849,7 +1938,6 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
                goto out_iput;
 
        mutex_unlock(&c->umount_mutex);
-
        return 0;
 
 out_iput:
@@ -1955,7 +2043,7 @@ static void ubifs_kill_sb(struct super_block *sb)
         * We do 'commit_on_unmount()' here instead of 'ubifs_put_super()'
         * in order to be outside BKL.
         */
-       if (sb->s_root && !(sb->s_flags & MS_RDONLY))
+       if (sb->s_root)
                commit_on_unmount(c);
        /* The un-mount routine is actually done in put_super() */
        generic_shutdown_super(sb);
@@ -2020,6 +2108,14 @@ static int __init ubifs_init(void)
        BUILD_BUG_ON(UBIFS_INO_NODE_SZ != 160);
        BUILD_BUG_ON(UBIFS_REF_NODE_SZ != 64);
 
+       /*
+        * We use 2 bit wide bit-fields to store compression type, which should
+        * be amended if more compressors are added. The bit-fields are:
+        * @compr_type in 'struct ubifs_inode', @default_compr in
+        * 'struct ubifs_info' and @compr_type in 'struct ubifs_mount_opts'.
+        */
+       BUILD_BUG_ON(UBIFS_COMPR_TYPES_CNT > 4);
+
        /*
         * We require that PAGE_CACHE_SIZE is greater-than-or-equal-to
         * UBIFS_BLOCK_SIZE. It is assumed that both are powers of 2.
@@ -2048,12 +2144,18 @@ static int __init ubifs_init(void)
        register_shrinker(&ubifs_shrinker_info);
 
        err = ubifs_compressors_init();
+       if (err)
+               goto out_shrinker;
+
+       err = dbg_debugfs_init();
        if (err)
                goto out_compr;
 
        return 0;
 
 out_compr:
+       ubifs_compressors_exit();
+out_shrinker:
        unregister_shrinker(&ubifs_shrinker_info);
        kmem_cache_destroy(ubifs_inode_slab);
 out_reg:
@@ -2068,6 +2170,7 @@ static void __exit ubifs_exit(void)
        ubifs_assert(list_empty(&ubifs_infos));
        ubifs_assert(atomic_long_read(&ubifs_clean_zn_cnt) == 0);
 
+       dbg_debugfs_exit();
        ubifs_compressors_exit();
        unregister_shrinker(&ubifs_shrinker_info);
        kmem_cache_destroy(ubifs_inode_slab);
index 6eef5344a145ec845ee17791567ea41ad4db2fa9..f7e36f5455275e3e125b551b49b32448dd6f9188 100644 (file)
@@ -2245,12 +2245,11 @@ int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key,
                        if (found) {
                                /* Ensure the znode is dirtied */
                                if (znode->cnext || !ubifs_zn_dirty(znode)) {
-                                           znode = dirty_cow_bottom_up(c,
-                                                                       znode);
-                                           if (IS_ERR(znode)) {
-                                                   err = PTR_ERR(znode);
-                                                   goto out_unlock;
-                                           }
+                                       znode = dirty_cow_bottom_up(c, znode);
+                                       if (IS_ERR(znode)) {
+                                               err = PTR_ERR(znode);
+                                               goto out_unlock;
+                                       }
                                }
                                zbr = &znode->zbranch[n];
                                lnc_free(zbr);
@@ -2317,11 +2316,11 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
 
                /* Ensure the znode is dirtied */
                if (znode->cnext || !ubifs_zn_dirty(znode)) {
-                           znode = dirty_cow_bottom_up(c, znode);
-                           if (IS_ERR(znode)) {
-                                   err = PTR_ERR(znode);
-                                   goto out_unlock;
-                           }
+                       znode = dirty_cow_bottom_up(c, znode);
+                       if (IS_ERR(znode)) {
+                               err = PTR_ERR(znode);
+                               goto out_unlock;
+                       }
                }
 
                if (found == 1) {
@@ -2627,11 +2626,11 @@ int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key,
 
                /* Ensure the znode is dirtied */
                if (znode->cnext || !ubifs_zn_dirty(znode)) {
-                           znode = dirty_cow_bottom_up(c, znode);
-                           if (IS_ERR(znode)) {
-                                   err = PTR_ERR(znode);
-                                   goto out_unlock;
-                           }
+                       znode = dirty_cow_bottom_up(c, znode);
+                       if (IS_ERR(znode)) {
+                               err = PTR_ERR(znode);
+                               goto out_unlock;
+                       }
                }
 
                /* Remove all keys in range except the first */
index 8ac76b1c2d552eb5d8c94e765e2e4a1a2f747358..fde8d127c768d11c6b16087f4a2a6437b729c1d1 100644 (file)
@@ -553,8 +553,8 @@ static int layout_in_empty_space(struct ubifs_info *c)
        }
 
 #ifdef CONFIG_UBIFS_FS_DEBUG
-       c->new_ihead_lnum = lnum;
-       c->new_ihead_offs = buf_offs;
+       c->dbg->new_ihead_lnum = lnum;
+       c->dbg->new_ihead_offs = buf_offs;
 #endif
 
        return 0;
@@ -802,8 +802,10 @@ int ubifs_tnc_start_commit(struct ubifs_info *c, struct ubifs_zbranch *zroot)
         * budgeting subsystem to assume the index is already committed,
         * even though it is not.
         */
+       ubifs_assert(c->min_idx_lebs == ubifs_calc_min_idx_lebs(c));
        c->old_idx_sz = c->calc_idx_sz;
        c->budg_uncommitted_idx = 0;
+       c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
        spin_unlock(&c->space_lock);
        mutex_unlock(&c->tnc_mutex);
 
@@ -1002,7 +1004,8 @@ static int write_index(struct ubifs_info *c)
        }
 
 #ifdef CONFIG_UBIFS_FS_DEBUG
-       if (lnum != c->new_ihead_lnum || buf_offs != c->new_ihead_offs) {
+       if (lnum != c->dbg->new_ihead_lnum ||
+           buf_offs != c->dbg->new_ihead_offs) {
                ubifs_err("inconsistent ihead");
                return -EINVAL;
        }
index 0b378042a3a28dd18737f6211e29dafbe7c5410b..b25fc36cf72f1fa70889dc3749f892e604673e75 100644 (file)
  */
 #define UBIFS_MIN_COMPR_LEN 128
 
+/*
+ * If compressed data length is less than %UBIFS_MIN_COMPRESS_DIFF bytes
+ * shorter than uncompressed data length, UBIFS preferes to leave this data
+ * node uncompress, because it'll be read faster.
+ */
+#define UBIFS_MIN_COMPRESS_DIFF 64
+
 /* Root inode number */
 #define UBIFS_ROOT_INO 1
 
index 46b172560a064eb7b4d541359aa9b02e7dd39380..fc2a4cc66d03c75429a14de807c4fcf8d48a7cce 100644 (file)
 #define SQNUM_WARN_WATERMARK 0xFFFFFFFF00000000ULL
 #define SQNUM_WATERMARK      0xFFFFFFFFFF000000ULL
 
+/*
+ * Minimum amount of LEBs reserved for the index. At present the index needs at
+ * least 2 LEBs: one for the index head and one for in-the-gaps method (which
+ * currently does not cater for the index head and so excludes it from
+ * consideration).
+ */
+#define MIN_INDEX_LEBS 2
+
 /* Minimum amount of data UBIFS writes to the flash */
 #define MIN_WRITE_SZ (UBIFS_DATA_NODE_SZ + 8)
 
@@ -386,12 +394,12 @@ struct ubifs_inode {
        unsigned int dirty:1;
        unsigned int xattr:1;
        unsigned int bulk_read:1;
+       unsigned int compr_type:2;
        struct mutex ui_mutex;
        spinlock_t ui_lock;
        loff_t synced_i_size;
        loff_t ui_size;
        int flags;
-       int compr_type;
        pgoff_t last_page_read;
        pgoff_t read_in_a_row;
        int data_len;
@@ -419,7 +427,7 @@ struct ubifs_unclean_leb {
  *
  * LPROPS_UNCAT: not categorized
  * LPROPS_DIRTY: dirty > 0, not index
- * LPROPS_DIRTY_IDX: dirty + free > UBIFS_CH_SZ and index
+ * LPROPS_DIRTY_IDX: dirty + free > @c->min_idx_node_sze and index
  * LPROPS_FREE: free > 0, not empty, not index
  * LPROPS_HEAP_CNT: number of heaps used for storing categorized LEBs
  * LPROPS_EMPTY: LEB is empty, not taken
@@ -473,8 +481,8 @@ struct ubifs_lprops {
 struct ubifs_lpt_lprops {
        int free;
        int dirty;
-       unsigned tgc : 1;
-       unsigned cmt : 1;
+       unsigned tgc:1;
+       unsigned cmt:1;
 };
 
 /**
@@ -482,24 +490,26 @@ struct ubifs_lpt_lprops {
  * @empty_lebs: number of empty LEBs
  * @taken_empty_lebs: number of taken LEBs
  * @idx_lebs: number of indexing LEBs
- * @total_free: total free space in bytes
- * @total_dirty: total dirty space in bytes
- * @total_used: total used space in bytes (includes only data LEBs)
- * @total_dead: total dead space in bytes (includes only data LEBs)
- * @total_dark: total dark space in bytes (includes only data LEBs)
+ * @total_free: total free space in bytes (includes all LEBs)
+ * @total_dirty: total dirty space in bytes (includes all LEBs)
+ * @total_used: total used space in bytes (does not include index LEBs)
+ * @total_dead: total dead space in bytes (does not include index LEBs)
+ * @total_dark: total dark space in bytes (does not include index LEBs)
+ *
+ * The @taken_empty_lebs field counts the LEBs that are in the transient state
+ * of having been "taken" for use but not yet written to. @taken_empty_lebs is
+ * needed to account correctly for @gc_lnum, otherwise @empty_lebs could be
+ * used by itself (in which case 'unused_lebs' would be a better name). In the
+ * case of @gc_lnum, it is "taken" at mount time or whenever a LEB is retained
+ * by GC, but unlike other empty LEBs that are "taken", it may not be written
+ * straight away (i.e. before the next commit start or unmount), so either
+ * @gc_lnum must be specially accounted for, or the current approach followed
+ * i.e. count it under @taken_empty_lebs.
  *
- * N.B. total_dirty and total_used are different to other total_* fields,
- * because they account _all_ LEBs, not just data LEBs.
+ * @empty_lebs includes @taken_empty_lebs.
  *
- * 'taken_empty_lebs' counts the LEBs that are in the transient state of having
- * been 'taken' for use but not yet written to. 'taken_empty_lebs' is needed
- * to account correctly for gc_lnum, otherwise 'empty_lebs' could be used
- * by itself (in which case 'unused_lebs' would be a better name). In the case
- * of gc_lnum, it is 'taken' at mount time or whenever a LEB is retained by GC,
- * but unlike other empty LEBs that are 'taken', it may not be written straight
- * away (i.e. before the next commit start or unmount), so either gc_lnum must
- * be specially accounted for, or the current approach followed i.e. count it
- * under 'taken_empty_lebs'.
+ * @total_used, @total_dead and @total_dark fields do not account indexing
+ * LEBs.
  */
 struct ubifs_lp_stats {
        int empty_lebs;
@@ -893,15 +903,25 @@ struct ubifs_orphan {
 /**
  * struct ubifs_mount_opts - UBIFS-specific mount options information.
  * @unmount_mode: selected unmount mode (%0 default, %1 normal, %2 fast)
- * @bulk_read: enable bulk-reads
- * @chk_data_crc: check CRCs when reading data nodes
+ * @bulk_read: enable/disable bulk-reads (%0 default, %1 disabe, %2 enable)
+ * @chk_data_crc: enable/disable CRC data checking when reading data nodes
+ *                (%0 default, %1 disabe, %2 enable)
+ * @override_compr: override default compressor (%0 - do not override and use
+ *                  superblock compressor, %1 - override and use compressor
+ *                  specified in @compr_type)
+ * @compr_type: compressor type to override the superblock compressor with
+ *              (%UBIFS_COMPR_NONE, etc)
  */
 struct ubifs_mount_opts {
        unsigned int unmount_mode:2;
        unsigned int bulk_read:2;
        unsigned int chk_data_crc:2;
+       unsigned int override_compr:1;
+       unsigned int compr_type:2;
 };
 
+struct ubifs_debug_info;
+
 /**
  * struct ubifs_info - UBIFS file-system description data structure
  * (per-superblock).
@@ -946,6 +966,7 @@ struct ubifs_mount_opts {
  * @no_chk_data_crc: do not check CRCs when reading data nodes (except during
  *                   recovery)
  * @bulk_read: enable bulk-reads
+ * @default_compr: default compression algorithm (%UBIFS_COMPR_LZO, etc)
  *
  * @tnc_mutex: protects the Tree Node Cache (TNC), @zroot, @cnext, @enext, and
  *             @calc_idx_sz
@@ -963,8 +984,6 @@ struct ubifs_mount_opts {
  * @ileb_nxt: next pre-allocated index LEBs
  * @old_idx: tree of index nodes obsoleted since the last commit start
  * @bottom_up_buf: a buffer which is used by 'dirty_cow_bottom_up()' in tnc.c
- * @new_ihead_lnum: used by debugging to check ihead_lnum
- * @new_ihead_offs: used by debugging to check ihead_offs
  *
  * @mst_node: master node
  * @mst_offs: offset of valid master node
@@ -986,7 +1005,6 @@ struct ubifs_mount_opts {
  * @main_lebs: count of LEBs in the main area
  * @main_first: first LEB of the main area
  * @main_bytes: main area size in bytes
- * @default_compr: default compression algorithm (%UBIFS_COMPR_LZO, etc)
  *
  * @key_hash_type: type of the key hash
  * @key_hash: direntry key hash function
@@ -1149,15 +1167,7 @@ struct ubifs_mount_opts {
  * @always_chk_crc: always check CRCs (while mounting and remounting rw)
  * @mount_opts: UBIFS-specific mount options
  *
- * @dbg_buf: a buffer of LEB size used for debugging purposes
- * @old_zroot: old index root - used by 'dbg_check_old_index()'
- * @old_zroot_level: old index root level - used by 'dbg_check_old_index()'
- * @old_zroot_sqnum: old index root sqnum - used by 'dbg_check_old_index()'
- * @failure_mode: failure mode for recovery testing
- * @fail_delay: 0=>don't delay, 1=>delay a time, 2=>delay a number of calls
- * @fail_timeout: time in jiffies when delay of failure mode expires
- * @fail_cnt: current number of calls to failure mode I/O functions
- * @fail_cnt_max: number of calls by which to delay failure mode
+ * @dbg: debugging-related information
  */
 struct ubifs_info {
        struct super_block *vfs_sb;
@@ -1196,6 +1206,7 @@ struct ubifs_info {
        unsigned int big_lpt:1;
        unsigned int no_chk_data_crc:1;
        unsigned int bulk_read:1;
+       unsigned int default_compr:2;
 
        struct mutex tnc_mutex;
        struct ubifs_zbranch zroot;
@@ -1212,10 +1223,6 @@ struct ubifs_info {
        int ileb_nxt;
        struct rb_root old_idx;
        int *bottom_up_buf;
-#ifdef CONFIG_UBIFS_FS_DEBUG
-       int new_ihead_lnum;
-       int new_ihead_offs;
-#endif
 
        struct ubifs_mst_node *mst_node;
        int mst_offs;
@@ -1237,7 +1244,6 @@ struct ubifs_info {
        int main_lebs;
        int main_first;
        long long main_bytes;
-       int default_compr;
 
        uint8_t key_hash_type;
        uint32_t (*key_hash)(const char *str, int len);
@@ -1315,8 +1321,8 @@ struct ubifs_info {
        void *sbuf;
        struct list_head idx_gc;
        int idx_gc_cnt;
-       volatile int gc_seq;
-       volatile int gced_lnum;
+       int gc_seq;
+       int gced_lnum;
 
        struct list_head infos_list;
        struct mutex umount_mutex;
@@ -1391,21 +1397,7 @@ struct ubifs_info {
        struct ubifs_mount_opts mount_opts;
 
 #ifdef CONFIG_UBIFS_FS_DEBUG
-       void *dbg_buf;
-       struct ubifs_zbranch old_zroot;
-       int old_zroot_level;
-       unsigned long long old_zroot_sqnum;
-       int failure_mode;
-       int fail_delay;
-       unsigned long fail_timeout;
-       unsigned int fail_cnt;
-       unsigned int fail_cnt_max;
-       long long chk_lpt_sz;
-       long long chk_lpt_sz2;
-       long long chk_lpt_wastage;
-       int chk_lpt_lebs;
-       int new_nhead_lnum;
-       int new_nhead_offs;
+       struct ubifs_debug_info *dbg;
 #endif
 };
 
@@ -1505,7 +1497,7 @@ void ubifs_cancel_ino_op(struct ubifs_info *c, struct inode *inode,
 long long ubifs_get_free_space(struct ubifs_info *c);
 int ubifs_calc_min_idx_lebs(struct ubifs_info *c);
 void ubifs_convert_page_budget(struct ubifs_info *c);
-long long ubifs_reported_space(const struct ubifs_info *c, uint64_t free);
+long long ubifs_reported_space(const struct ubifs_info *c, long long free);
 long long ubifs_calc_available(const struct ubifs_info *c, int min_idx_lebs);
 
 /* find.c */
@@ -1639,6 +1631,9 @@ void ubifs_add_lpt_dirt(struct ubifs_info *c, int lnum, int dirty);
 void ubifs_add_nnode_dirt(struct ubifs_info *c, struct ubifs_nnode *nnode);
 uint32_t ubifs_unpack_bits(uint8_t **addr, int *pos, int nrbits);
 struct ubifs_nnode *ubifs_first_nnode(struct ubifs_info *c, int *hght);
+/* Needed only in debugging code in lpt_commit.c */
+int ubifs_unpack_nnode(const struct ubifs_info *c, void *buf,
+                      struct ubifs_nnode *nnode);
 
 /* lpt_commit.c */
 int ubifs_lpt_start_commit(struct ubifs_info *c);
@@ -1714,7 +1709,7 @@ long ubifs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 
 /* compressor.c */
 int __init ubifs_compressors_init(void);
-void __exit ubifs_compressors_exit(void);
+void ubifs_compressors_exit(void);
 void ubifs_compress(const void *in_buf, int in_len, void *out_buf, int *out_len,
                    int *compr_type);
 int ubifs_decompress(const void *buf, int len, void *out, int *out_len,