Merge branch 'linux-next' of git://git.infradead.org/ubifs-2.6
[pandora-kernel.git] / fs / ubifs / debug.c
index c2a68ba..0bee4db 100644 (file)
@@ -2239,6 +2239,162 @@ out_free:
        return err;
 }
 
+/**
+ * dbg_check_data_nodes_order - check that list of data nodes is sorted.
+ * @c: UBIFS file-system description object
+ * @head: the list of nodes ('struct ubifs_scan_node' objects)
+ *
+ * This function returns zero if the list of data nodes is sorted correctly,
+ * and %-EINVAL if not.
+ */
+int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head)
+{
+       struct list_head *cur;
+       struct ubifs_scan_node *sa, *sb;
+
+       if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
+               return 0;
+
+       for (cur = head->next; cur->next != head; cur = cur->next) {
+               ino_t inuma, inumb;
+               uint32_t blka, blkb;
+
+               cond_resched();
+               sa = container_of(cur, struct ubifs_scan_node, list);
+               sb = container_of(cur->next, struct ubifs_scan_node, list);
+
+               if (sa->type != UBIFS_DATA_NODE) {
+                       ubifs_err("bad node type %d", sa->type);
+                       dbg_dump_node(c, sa->node);
+                       return -EINVAL;
+               }
+               if (sb->type != UBIFS_DATA_NODE) {
+                       ubifs_err("bad node type %d", sb->type);
+                       dbg_dump_node(c, sb->node);
+                       return -EINVAL;
+               }
+
+               inuma = key_inum(c, &sa->key);
+               inumb = key_inum(c, &sb->key);
+
+               if (inuma < inumb)
+                       continue;
+               if (inuma > inumb) {
+                       ubifs_err("larger inum %lu goes before inum %lu",
+                                 (unsigned long)inuma, (unsigned long)inumb);
+                       goto error_dump;
+               }
+
+               blka = key_block(c, &sa->key);
+               blkb = key_block(c, &sb->key);
+
+               if (blka > blkb) {
+                       ubifs_err("larger block %u goes before %u", blka, blkb);
+                       goto error_dump;
+               }
+               if (blka == blkb) {
+                       ubifs_err("two data nodes for the same block");
+                       goto error_dump;
+               }
+       }
+
+       return 0;
+
+error_dump:
+       dbg_dump_node(c, sa->node);
+       dbg_dump_node(c, sb->node);
+       return -EINVAL;
+}
+
+/**
+ * dbg_check_nondata_nodes_order - check that list of data nodes is sorted.
+ * @c: UBIFS file-system description object
+ * @head: the list of nodes ('struct ubifs_scan_node' objects)
+ *
+ * This function returns zero if the list of non-data nodes is sorted correctly,
+ * and %-EINVAL if not.
+ */
+int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head)
+{
+       struct list_head *cur;
+       struct ubifs_scan_node *sa, *sb;
+
+       if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
+               return 0;
+
+       for (cur = head->next; cur->next != head; cur = cur->next) {
+               ino_t inuma, inumb;
+               uint32_t hasha, hashb;
+
+               cond_resched();
+               sa = container_of(cur, struct ubifs_scan_node, list);
+               sb = container_of(cur->next, struct ubifs_scan_node, list);
+
+               if (sa->type != UBIFS_INO_NODE && sa->type != UBIFS_DENT_NODE &&
+                   sa->type != UBIFS_XENT_NODE) {
+                       ubifs_err("bad node type %d", sa->type);
+                       dbg_dump_node(c, sa->node);
+                       return -EINVAL;
+               }
+               if (sa->type != UBIFS_INO_NODE && sa->type != UBIFS_DENT_NODE &&
+                   sa->type != UBIFS_XENT_NODE) {
+                       ubifs_err("bad node type %d", sb->type);
+                       dbg_dump_node(c, sb->node);
+                       return -EINVAL;
+               }
+
+               if (sa->type != UBIFS_INO_NODE && sb->type == UBIFS_INO_NODE) {
+                       ubifs_err("non-inode node goes before inode node");
+                       goto error_dump;
+               }
+
+               if (sa->type == UBIFS_INO_NODE && sb->type != UBIFS_INO_NODE)
+                       continue;
+
+               if (sa->type == UBIFS_INO_NODE && sb->type == UBIFS_INO_NODE) {
+                       /* Inode nodes are sorted in descending size order */
+                       if (sa->len < sb->len) {
+                               ubifs_err("smaller inode node goes first");
+                               goto error_dump;
+                       }
+                       continue;
+               }
+
+               /*
+                * This is either a dentry or xentry, which should be sorted in
+                * ascending (parent ino, hash) order.
+                */
+               inuma = key_inum(c, &sa->key);
+               inumb = key_inum(c, &sb->key);
+
+               if (inuma < inumb)
+                       continue;
+               if (inuma > inumb) {
+                       ubifs_err("larger inum %lu goes before inum %lu",
+                                 (unsigned long)inuma, (unsigned long)inumb);
+                       goto error_dump;
+               }
+
+               hasha = key_block(c, &sa->key);
+               hashb = key_block(c, &sb->key);
+
+               if (hasha > hashb) {
+                       ubifs_err("larger hash %u goes before %u", hasha, hashb);
+                       goto error_dump;
+               }
+       }
+
+       return 0;
+
+error_dump:
+       ubifs_msg("dumping first node");
+       dbg_dump_node(c, sa->node);
+       ubifs_msg("dumping second node");
+       dbg_dump_node(c, sb->node);
+       return -EINVAL;
+       return 0;
+}
+
 static int invocation_cnt;
 
 int dbg_force_in_the_gaps(void)
@@ -2625,6 +2781,7 @@ static const struct file_operations dfs_fops = {
        .open = open_debugfs_file,
        .write = write_debugfs_file,
        .owner = THIS_MODULE,
+       .llseek = default_llseek,
 };
 
 /**