From ec7b85da52360cf6f144c00a8a65e6e903863db5 Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Tue, 26 Jul 2016 14:00:01 +0800 Subject: btrfs-progs: check: introduce function to check inode_extref Introduce a new function check_inode_extref() to check INODE_EXTREF, and call find_dir_item() to find the related DIR_ITEM/DIR_INDEX. Signed-off-by: Lu Fengqi Signed-off-by: Qu Wenruo Signed-off-by: David Sterba --- cmds-check.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) (limited to 'cmds-check.c') diff --git a/cmds-check.c b/cmds-check.c index 8f1a2871..ffb4da1a 100644 --- a/cmds-check.c +++ b/cmds-check.c @@ -4041,6 +4041,84 @@ next: return err; } +/* + * Traverse the given INODE_EXTREF and call find_dir_item() to find related + * DIR_ITEM/DIR_INDEX. + * + * @root: the root of the fs/file tree + * @ref_key: the key of the INODE_EXTREF + * @refs: the count of INODE_EXTREF + * @mode: the st_mode of INODE_ITEM + * + * Return 0 if no error occurred. + */ +static int check_inode_extref(struct btrfs_root *root, + struct btrfs_key *ref_key, + struct extent_buffer *node, int slot, u64 *refs, + int mode) +{ + struct btrfs_key key; + struct btrfs_inode_extref *extref; + char namebuf[BTRFS_NAME_LEN] = {0}; + u32 total; + u32 cur = 0; + u32 len; + u32 name_len; + u64 index; + u64 parent; + int ret; + int err = 0; + + extref = btrfs_item_ptr(node, slot, struct btrfs_inode_extref); + total = btrfs_item_size_nr(node, slot); + +next: + /* update inode ref count */ + (*refs)++; + name_len = btrfs_inode_extref_name_len(node, extref); + index = btrfs_inode_extref_index(node, extref); + parent = btrfs_inode_extref_parent(node, extref); + if (name_len <= BTRFS_NAME_LEN) { + len = name_len; + } else { + len = BTRFS_NAME_LEN; + warning("root %llu INODE_EXTREF[%llu %llu] name too long", + root->objectid, ref_key->objectid, ref_key->offset); + } + read_extent_buffer(node, namebuf, (unsigned long)(extref + 1), len); + + /* Check root dir ref name */ + if (index == 0 && strncmp(namebuf, "..", name_len)) { + error("root %llu INODE_EXTREF[%llu %llu] ROOT_DIR name shouldn't be %s", + root->objectid, ref_key->objectid, ref_key->offset, + namebuf); + err |= ROOT_DIR_ERROR; + } + + /* find related dir_index */ + key.objectid = parent; + key.type = BTRFS_DIR_INDEX_KEY; + key.offset = index; + ret = find_dir_item(root, ref_key, &key, index, namebuf, len, mode); + err |= ret; + + /* find related dir_item */ + key.objectid = parent; + key.type = BTRFS_DIR_ITEM_KEY; + key.offset = btrfs_name_hash(namebuf, len); + ret = find_dir_item(root, ref_key, &key, index, namebuf, len, mode); + err |= ret; + + len = sizeof(*extref) + name_len; + extref = (struct btrfs_inode_extref *)((char *)extref + len); + cur += len; + + if (cur < total) + goto next; + + return err; +} + static int all_backpointers_checked(struct extent_record *rec, int print_errs) { struct list_head *cur = rec->backrefs.next; -- cgit v1.2.3