btrfs-progs: check: introduce function to find inode_ref
authorLu Fengqi <lufq.fnst@cn.fujitsu.com>
Mon, 25 Jul 2016 05:12:35 +0000 (13:12 +0800)
committerDavid Sterba <dsterba@suse.com>
Wed, 14 Dec 2016 14:06:33 +0000 (15:06 +0100)
Introduce a new function find_inode_ref() to find
INODE_REF/INODE_EXTREF for the given key, and check it with the
specified DIR_ITEM/DIR_INDEX match.

Signed-off-by: Lu Fengqi <lufq.fnst@cn.fujitsu.com>
Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
Signed-off-by: David Sterba <dsterba@suse.com>
cmds-check.c

index ffb4da1..e9a4d86 100644 (file)
@@ -3830,6 +3830,7 @@ out:
 #define ROOT_DIR_ERROR         (1<<1)  /* bad ROOT_DIR */
 #define DIR_ITEM_MISSING       (1<<2)  /* DIR_ITEM not found */
 #define DIR_ITEM_MISMATCH      (1<<3)  /* DIR_ITEM found but not match */
+#define INODE_REF_MISSING      (1<<4)  /* INODE_REF/INODE_EXTREF not found */
 
 /*
  * Find DIR_ITEM/DIR_INDEX for the given key and check it with the specified
@@ -4119,6 +4120,154 @@ next:
        return err;
 }
 
+/*
+ * Find INODE_REF/INODE_EXTREF for the given key and check it with the specified
+ * DIR_ITEM/DIR_INDEX match.
+ *
+ * @root:      the root of the fs/file tree
+ * @key:       the key of the INODE_REF/INODE_EXTREF
+ * @name:      the name in the INODE_REF/INODE_EXTREF
+ * @namelen:   the length of name in the INODE_REF/INODE_EXTREF
+ * @index:     the index in the INODE_REF/INODE_EXTREF, for DIR_ITEM set index
+ * to (u64)-1
+ * @ext_ref:   the EXTENDED_IREF feature
+ *
+ * Return 0 if no error occurred.
+ * Return >0 for error bitmap
+ */
+static int find_inode_ref(struct btrfs_root *root, struct btrfs_key *key,
+                         char *name, int namelen, u64 index,
+                         unsigned int ext_ref)
+{
+       struct btrfs_path path;
+       struct btrfs_inode_ref *ref;
+       struct btrfs_inode_extref *extref;
+       struct extent_buffer *node;
+       char ref_namebuf[BTRFS_NAME_LEN] = {0};
+       u32 total;
+       u32 cur = 0;
+       u32 len;
+       u32 ref_namelen;
+       u64 ref_index;
+       u64 parent;
+       u64 dir_id;
+       int slot;
+       int ret;
+
+       btrfs_init_path(&path);
+       ret = btrfs_search_slot(NULL, root, key, &path, 0, 0);
+       if (ret) {
+               ret = INODE_REF_MISSING;
+               goto extref;
+       }
+
+       node = path.nodes[0];
+       slot = path.slots[0];
+
+       ref = btrfs_item_ptr(node, slot, struct btrfs_inode_ref);
+       total = btrfs_item_size_nr(node, slot);
+
+       /* Iterate all entry of INODE_REF */
+       while (cur < total) {
+               ret = INODE_REF_MISSING;
+
+               ref_namelen = btrfs_inode_ref_name_len(node, ref);
+               ref_index = btrfs_inode_ref_index(node, ref);
+               if (index != (u64)-1 && index != ref_index)
+                       goto next_ref;
+
+               if (ref_namelen <= BTRFS_NAME_LEN) {
+                       len = ref_namelen;
+               } else {
+                       len = BTRFS_NAME_LEN;
+                       warning("root %llu INODE %s[%llu %llu] name too long",
+                               root->objectid,
+                               key->type == BTRFS_INODE_REF_KEY ?
+                                       "REF" : "EXTREF",
+                               key->objectid, key->offset);
+               }
+               read_extent_buffer(node, ref_namebuf, (unsigned long)(ref + 1),
+                                  len);
+
+               if (len != namelen || strncmp(ref_namebuf, name, len))
+                       goto next_ref;
+
+               ret = 0;
+               goto out;
+next_ref:
+               len = sizeof(*ref) + ref_namelen;
+               ref = (struct btrfs_inode_ref *)((char *)ref + len);
+               cur += len;
+       }
+
+extref:
+       /* Skip if not support EXTENDED_IREF feature */
+       if (!ext_ref)
+               goto out;
+
+       btrfs_release_path(&path);
+       btrfs_init_path(&path);
+
+       dir_id = key->offset;
+       key->type = BTRFS_INODE_EXTREF_KEY;
+       key->offset = btrfs_extref_hash(dir_id, name, namelen);
+
+       ret = btrfs_search_slot(NULL, root, key, &path, 0, 0);
+       if (ret) {
+               ret = INODE_REF_MISSING;
+               goto out;
+       }
+
+       node = path.nodes[0];
+       slot = path.slots[0];
+
+       extref = btrfs_item_ptr(node, slot, struct btrfs_inode_extref);
+       cur = 0;
+       total = btrfs_item_size_nr(node, slot);
+
+       /* Iterate all entry of INODE_EXTREF */
+       while (cur < total) {
+               ret = INODE_REF_MISSING;
+
+               ref_namelen = btrfs_inode_extref_name_len(node, extref);
+               ref_index = btrfs_inode_extref_index(node, extref);
+               parent = btrfs_inode_extref_parent(node, extref);
+               if (index != (u64)-1 && index != ref_index)
+                       goto next_extref;
+
+               if (parent != dir_id)
+                       goto next_extref;
+
+               if (ref_namelen <= BTRFS_NAME_LEN) {
+                       len = ref_namelen;
+               } else {
+                       len = BTRFS_NAME_LEN;
+                       warning("Warning: root %llu INODE %s[%llu %llu] name too long\n",
+                               root->objectid,
+                               key->type == BTRFS_INODE_REF_KEY ?
+                                       "REF" : "EXTREF",
+                               key->objectid, key->offset);
+               }
+               read_extent_buffer(node, ref_namebuf,
+                                  (unsigned long)(extref + 1), len);
+
+               if (len != namelen || strncmp(ref_namebuf, name, len))
+                       goto next_extref;
+
+               ret = 0;
+               goto out;
+
+next_extref:
+               len = sizeof(*extref) + ref_namelen;
+               extref = (struct btrfs_inode_extref *)((char *)extref + len);
+               cur += len;
+
+       }
+out:
+       btrfs_release_path(&path);
+       return ret;
+}
+
 static int all_backpointers_checked(struct extent_record *rec, int print_errs)
 {
        struct list_head *cur = rec->backrefs.next;