Merge branch 'linux-next' of git://git.infradead.org/ubifs-2.6
[pandora-kernel.git] / fs / ubifs / gc.c
index 918d158..151f108 100644 (file)
@@ -125,10 +125,16 @@ int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
        struct ubifs_scan_node *sa, *sb;
 
        cond_resched();
+       if (a == b)
+               return 0;
+
        sa = list_entry(a, struct ubifs_scan_node, list);
        sb = list_entry(b, struct ubifs_scan_node, list);
+
        ubifs_assert(key_type(c, &sa->key) == UBIFS_DATA_KEY);
        ubifs_assert(key_type(c, &sb->key) == UBIFS_DATA_KEY);
+       ubifs_assert(sa->type == UBIFS_DATA_NODE);
+       ubifs_assert(sb->type == UBIFS_DATA_NODE);
 
        inuma = key_inum(c, &sa->key);
        inumb = key_inum(c, &sb->key);
@@ -157,28 +163,40 @@ int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
  */
 int nondata_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
 {
-       int typea, typeb;
        ino_t inuma, inumb;
        struct ubifs_info *c = priv;
        struct ubifs_scan_node *sa, *sb;
 
        cond_resched();
+       if (a == b)
+               return 0;
+
        sa = list_entry(a, struct ubifs_scan_node, list);
        sb = list_entry(b, struct ubifs_scan_node, list);
-       typea = key_type(c, &sa->key);
-       typeb = key_type(c, &sb->key);
-       ubifs_assert(typea != UBIFS_DATA_KEY && typeb != UBIFS_DATA_KEY);
+
+       ubifs_assert(key_type(c, &sa->key) != UBIFS_DATA_KEY &&
+                    key_type(c, &sb->key) != UBIFS_DATA_KEY);
+       ubifs_assert(sa->type != UBIFS_DATA_NODE &&
+                    sb->type != UBIFS_DATA_NODE);
 
        /* Inodes go before directory entries */
-       if (typea == UBIFS_INO_KEY) {
-               if (typeb == UBIFS_INO_KEY)
+       if (sa->type == UBIFS_INO_NODE) {
+               if (sb->type == UBIFS_INO_NODE)
                        return sb->len - sa->len;
                return -1;
        }
-       if (typeb == UBIFS_INO_KEY)
+       if (sb->type == UBIFS_INO_NODE)
                return 1;
 
-       ubifs_assert(typea == UBIFS_DENT_KEY && typeb == UBIFS_DENT_KEY);
+       ubifs_assert(key_type(c, &sa->key) == UBIFS_DENT_KEY ||
+                    key_type(c, &sa->key) == UBIFS_XENT_KEY);
+       ubifs_assert(key_type(c, &sb->key) == UBIFS_DENT_KEY ||
+                    key_type(c, &sb->key) == UBIFS_XENT_KEY);
+       ubifs_assert(sa->type == UBIFS_DENT_NODE ||
+                    sa->type == UBIFS_XENT_NODE);
+       ubifs_assert(sb->type == UBIFS_DENT_NODE ||
+                    sb->type == UBIFS_XENT_NODE);
+
        inuma = key_inum(c, &sa->key);
        inumb = key_inum(c, &sb->key);
 
@@ -224,17 +242,33 @@ int nondata_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
 static int sort_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
                      struct list_head *nondata, int *min)
 {
+       int err;
        struct ubifs_scan_node *snod, *tmp;
 
        *min = INT_MAX;
 
        /* Separate data nodes and non-data nodes */
        list_for_each_entry_safe(snod, tmp, &sleb->nodes, list) {
-               int err;
+               ubifs_assert(snod->type == UBIFS_INO_NODE  ||
+                            snod->type == UBIFS_DATA_NODE ||
+                            snod->type == UBIFS_DENT_NODE ||
+                            snod->type == UBIFS_XENT_NODE ||
+                            snod->type == UBIFS_TRUN_NODE);
+
+               if (snod->type != UBIFS_INO_NODE  &&
+                   snod->type != UBIFS_DATA_NODE &&
+                   snod->type != UBIFS_DENT_NODE &&
+                   snod->type != UBIFS_XENT_NODE) {
+                       /* Probably truncation node, zap it */
+                       list_del(&snod->list);
+                       kfree(snod);
+                       continue;
+               }
 
-               ubifs_assert(snod->type != UBIFS_IDX_NODE);
-               ubifs_assert(snod->type != UBIFS_REF_NODE);
-               ubifs_assert(snod->type != UBIFS_CS_NODE);
+               ubifs_assert(key_type(c, &snod->key) == UBIFS_DATA_KEY ||
+                            key_type(c, &snod->key) == UBIFS_INO_KEY  ||
+                            key_type(c, &snod->key) == UBIFS_DENT_KEY ||
+                            key_type(c, &snod->key) == UBIFS_XENT_KEY);
 
                err = ubifs_tnc_has_node(c, &snod->key, 0, sleb->lnum,
                                         snod->offs, 0);
@@ -258,6 +292,13 @@ static int sort_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
        /* Sort data and non-data nodes */
        list_sort(c, &sleb->nodes, &data_nodes_cmp);
        list_sort(c, nondata, &nondata_nodes_cmp);
+
+       err = dbg_check_data_nodes_order(c, &sleb->nodes);
+       if (err)
+               return err;
+       err = dbg_check_nondata_nodes_order(c, nondata);
+       if (err)
+               return err;
        return 0;
 }
 
@@ -575,13 +616,14 @@ int ubifs_garbage_collect(struct ubifs_info *c, int anyway)
        struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf;
 
        ubifs_assert_cmt_locked(c);
+       ubifs_assert(!c->ro_media && !c->ro_mount);
 
        if (ubifs_gc_should_commit(c))
                return -EAGAIN;
 
        mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead);
 
-       if (c->ro_media) {
+       if (c->ro_error) {
                ret = -EROFS;
                goto out_unlock;
        }
@@ -677,14 +719,12 @@ int ubifs_garbage_collect(struct ubifs_info *c, int anyway)
 
                ret = ubifs_garbage_collect_leb(c, &lp);
                if (ret < 0) {
-                       if (ret == -EAGAIN || ret == -ENOSPC) {
+                       if (ret == -EAGAIN) {
                                /*
-                                * These codes are not errors, so we have to
-                                * return the LEB to lprops. But if the
-                                * 'ubifs_return_leb()' function fails, its
-                                * failure code is propagated to the caller
-                                * instead of the original '-EAGAIN' or
-                                * '-ENOSPC'.
+                                * This is not error, so we have to return the
+                                * LEB to lprops. But if 'ubifs_return_leb()'
+                                * fails, its failure code is propagated to the
+                                * caller instead of the original '-EAGAIN'.
                                 */
                                err = ubifs_return_leb(c, lp.lnum);
                                if (err)
@@ -774,8 +814,8 @@ out_unlock:
 out:
        ubifs_assert(ret < 0);
        ubifs_assert(ret != -ENOSPC && ret != -EAGAIN);
-       ubifs_ro_mode(c, ret);
        ubifs_wbuf_sync_nolock(wbuf);
+       ubifs_ro_mode(c, ret);
        mutex_unlock(&wbuf->io_mutex);
        ubifs_return_leb(c, lp.lnum);
        return ret;