static int iterate_inode_refs(u64 inum, struct btrfs_root *fs_root, struct btrfs_path *path, iterate_irefs_t *iterate, void *ctx) { int ret = 0; int slot; u32 cur; u32 len; u32 name_len; u64 parent = 0; int found = 0; struct extent_buffer *eb; struct btrfs_item *item; struct btrfs_inode_ref *iref; struct btrfs_key found_key; while (!ret) { ret = inode_ref_info(inum, parent ? parent+1 : 0, fs_root, path, &found_key); if (ret < 0) break; if (ret) { ret = found ? 0 : -ENOENT; break; } ++found; parent = found_key.offset; slot = path->slots[0]; eb = btrfs_clone_extent_buffer(path->nodes[0]); if (!eb) { ret = -ENOMEM; break; } extent_buffer_get(eb); btrfs_release_path(path); item = btrfs_item_nr(slot); iref = btrfs_item_ptr(eb, slot, struct btrfs_inode_ref); for (cur = 0; cur < btrfs_item_size(eb, item); cur += len) { name_len = btrfs_inode_ref_name_len(eb, iref); /* path must be released before calling iterate()! */ pr_debug("following ref at offset %u for inode %llu in " "tree %llu\n", cur, found_key.objectid, fs_root->objectid); ret = iterate(parent, name_len, (unsigned long)(iref + 1), eb, ctx); if (ret) break; len = sizeof(*iref) + name_len; iref = (struct btrfs_inode_ref *)((char *)iref + len); } free_extent_buffer(eb); } btrfs_release_path(path); return ret; }
static int commit_tree_roots(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info) { struct btrfs_root *root; struct list_head *next; struct extent_buffer *eb; int ret; if (fs_info->readonly) return 0; eb = fs_info->tree_root->node; extent_buffer_get(eb); ret = btrfs_cow_block(trans, fs_info->tree_root, eb, NULL, 0, &eb); free_extent_buffer(eb); if (ret) return ret; while(!list_empty(&fs_info->dirty_cowonly_roots)) { next = fs_info->dirty_cowonly_roots.next; list_del_init(next); root = list_entry(next, struct btrfs_root, dirty_list); update_cowonly_root(trans, root); free_extent_buffer(root->commit_root); root->commit_root = NULL; } return 0; }
struct btrfs_trans_handle* btrfs_start_transaction(struct btrfs_root *root, int num_blocks) { struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_trans_handle *h = kzalloc(sizeof(*h), GFP_NOFS); if (fs_info->transaction_aborted) return ERR_PTR(-EROFS); if (!h) return ERR_PTR(-ENOMEM); if (root->commit_root) { error("commit_root already set when starting transaction"); kfree(h); return ERR_PTR(-EINVAL); } if (fs_info->running_transaction) { error("attempt to start transaction over already running one"); kfree(h); return ERR_PTR(-EINVAL); } h->fs_info = fs_info; fs_info->running_transaction = h; fs_info->generation++; h->transid = fs_info->generation; h->blocks_reserved = num_blocks; h->reinit_extent_tree = false; root->last_trans = h->transid; root->commit_root = root->node; extent_buffer_get(root->node); return h; }
int commit_tree_roots(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info) { struct btrfs_root *root; struct list_head *next; struct extent_buffer *eb; int ret; if (fs_info->readonly) return 0; eb = fs_info->tree_root->node; extent_buffer_get(eb); ret = btrfs_cow_block(trans, fs_info->tree_root, eb, NULL, 0, &eb); free_extent_buffer(eb); if (ret) return ret; /* * If the above CoW is the first one to dirty the current tree_root, * delayed refs for it won't be run until after this function has * finished executing, meaning we won't process the extent tree root, * which will have been added to ->dirty_cowonly_roots. So run * delayed refs here as well. */ ret = btrfs_run_delayed_refs(trans, -1); if (ret) return ret; while(!list_empty(&fs_info->dirty_cowonly_roots)) { next = fs_info->dirty_cowonly_roots.next; list_del_init(next); root = list_entry(next, struct btrfs_root, dirty_list); ret = update_cowonly_root(trans, root); free_extent_buffer(root->commit_root); root->commit_root = NULL; if (ret < 0) return ret; } return 0; }
static int test_hole_first(u32 sectorsize, u32 nodesize) { struct btrfs_fs_info *fs_info = NULL; struct inode *inode = NULL; struct btrfs_root *root = NULL; struct extent_map *em = NULL; int ret = -ENOMEM; inode = btrfs_new_test_inode(); if (!inode) { test_msg("Couldn't allocate inode\n"); return ret; } BTRFS_I(inode)->location.type = BTRFS_INODE_ITEM_KEY; BTRFS_I(inode)->location.objectid = BTRFS_FIRST_FREE_OBJECTID; BTRFS_I(inode)->location.offset = 0; fs_info = btrfs_alloc_dummy_fs_info(); if (!fs_info) { test_msg("Couldn't allocate dummy fs info\n"); goto out; } root = btrfs_alloc_dummy_root(fs_info, sectorsize, nodesize); if (IS_ERR(root)) { test_msg("Couldn't allocate root\n"); goto out; } root->node = alloc_dummy_extent_buffer(NULL, nodesize, nodesize); if (!root->node) { test_msg("Couldn't allocate dummy buffer\n"); goto out; } extent_buffer_get(root->node); btrfs_set_header_nritems(root->node, 0); btrfs_set_header_level(root->node, 0); BTRFS_I(inode)->root = root; ret = -EINVAL; /* * Need a blank inode item here just so we don't confuse * btrfs_get_extent. */ insert_inode_item_key(root); insert_extent(root, sectorsize, sectorsize, sectorsize, 0, sectorsize, sectorsize, BTRFS_FILE_EXTENT_REG, 0, 1); em = btrfs_get_extent(inode, NULL, 0, 0, 2 * sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start != EXTENT_MAP_HOLE) { test_msg("Expected a hole, got %llu\n", em->block_start); goto out; } if (em->start != 0 || em->len != sectorsize) { test_msg("Unexpected extent wanted start 0 len %u, " "got start %llu len %llu\n", sectorsize, em->start, em->len); goto out; } if (em->flags != vacancy_only) { test_msg("Wrong flags, wanted %lu, have %lu\n", vacancy_only, em->flags); goto out; } free_extent_map(em); em = btrfs_get_extent(inode, NULL, 0, sectorsize, 2 * sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start != sectorsize) { test_msg("Expected a real extent, got %llu\n", em->block_start); goto out; } if (em->start != sectorsize || em->len != sectorsize) { test_msg("Unexpected extent wanted start %u len %u, " "got start %llu len %llu\n", sectorsize, sectorsize, em->start, em->len); goto out; } if (em->flags != 0) { test_msg("Unexpected flags set, wanted 0 got %lu\n", em->flags); goto out; } ret = 0; out: if (!IS_ERR(em)) free_extent_map(em); iput(inode); btrfs_free_dummy_root(root); btrfs_free_dummy_fs_info(fs_info); return ret; }
static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize) { struct btrfs_fs_info *fs_info = NULL; struct inode *inode = NULL; struct btrfs_root *root = NULL; struct extent_map *em = NULL; u64 orig_start; u64 disk_bytenr; u64 offset; int ret = -ENOMEM; inode = btrfs_new_test_inode(); if (!inode) { test_msg("Couldn't allocate inode\n"); return ret; } BTRFS_I(inode)->location.type = BTRFS_INODE_ITEM_KEY; BTRFS_I(inode)->location.objectid = BTRFS_FIRST_FREE_OBJECTID; BTRFS_I(inode)->location.offset = 0; fs_info = btrfs_alloc_dummy_fs_info(); if (!fs_info) { test_msg("Couldn't allocate dummy fs info\n"); goto out; } root = btrfs_alloc_dummy_root(fs_info, sectorsize, nodesize); if (IS_ERR(root)) { test_msg("Couldn't allocate root\n"); goto out; } root->node = alloc_dummy_extent_buffer(NULL, nodesize, nodesize); if (!root->node) { test_msg("Couldn't allocate dummy buffer\n"); goto out; } /* * We will just free a dummy node if it's ref count is 2 so we need an * extra ref so our searches don't accidentally release our page. */ extent_buffer_get(root->node); btrfs_set_header_nritems(root->node, 0); btrfs_set_header_level(root->node, 0); ret = -EINVAL; /* First with no extents */ BTRFS_I(inode)->root = root; em = btrfs_get_extent(inode, NULL, 0, 0, sectorsize, 0); if (IS_ERR(em)) { em = NULL; test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start != EXTENT_MAP_HOLE) { test_msg("Expected a hole, got %llu\n", em->block_start); goto out; } if (!test_bit(EXTENT_FLAG_VACANCY, &em->flags)) { test_msg("Vacancy flag wasn't set properly\n"); goto out; } free_extent_map(em); btrfs_drop_extent_cache(inode, 0, (u64)-1, 0); /* * All of the magic numbers are based on the mapping setup in * setup_file_extents, so if you change anything there you need to * update the comment and update the expected values below. */ setup_file_extents(root, sectorsize); em = btrfs_get_extent(inode, NULL, 0, 0, (u64)-1, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start != EXTENT_MAP_HOLE) { test_msg("Expected a hole, got %llu\n", em->block_start); goto out; } if (em->start != 0 || em->len != 5) { test_msg("Unexpected extent wanted start 0 len 5, got start " "%llu len %llu\n", em->start, em->len); goto out; } if (em->flags != 0) { test_msg("Unexpected flags set, want 0 have %lu\n", em->flags); goto out; } offset = em->start + em->len; free_extent_map(em); em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start != EXTENT_MAP_INLINE) { test_msg("Expected an inline, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != (sectorsize - 5)) { test_msg("Unexpected extent wanted start %llu len 1, got start " "%llu len %llu\n", offset, em->start, em->len); goto out; } if (em->flags != 0) { test_msg("Unexpected flags set, want 0 have %lu\n", em->flags); goto out; } /* * We don't test anything else for inline since it doesn't get set * unless we have a page for it to write into. Maybe we should change * this? */ offset = em->start + em->len; free_extent_map(em); em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start != EXTENT_MAP_HOLE) { test_msg("Expected a hole, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != 4) { test_msg("Unexpected extent wanted start %llu len 4, got start " "%llu len %llu\n", offset, em->start, em->len); goto out; } if (em->flags != 0) { test_msg("Unexpected flags set, want 0 have %lu\n", em->flags); goto out; } offset = em->start + em->len; free_extent_map(em); /* Regular extent */ em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start >= EXTENT_MAP_LAST_BYTE) { test_msg("Expected a real extent, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != sectorsize - 1) { test_msg("Unexpected extent wanted start %llu len 4095, got " "start %llu len %llu\n", offset, em->start, em->len); goto out; } if (em->flags != 0) { test_msg("Unexpected flags set, want 0 have %lu\n", em->flags); goto out; } if (em->orig_start != em->start) { test_msg("Wrong orig offset, want %llu, have %llu\n", em->start, em->orig_start); goto out; } offset = em->start + em->len; free_extent_map(em); /* The next 3 are split extents */ em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start >= EXTENT_MAP_LAST_BYTE) { test_msg("Expected a real extent, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != sectorsize) { test_msg("Unexpected extent start %llu len %u, " "got start %llu len %llu\n", offset, sectorsize, em->start, em->len); goto out; } if (em->flags != 0) { test_msg("Unexpected flags set, want 0 have %lu\n", em->flags); goto out; } if (em->orig_start != em->start) { test_msg("Wrong orig offset, want %llu, have %llu\n", em->start, em->orig_start); goto out; } disk_bytenr = em->block_start; orig_start = em->start; offset = em->start + em->len; free_extent_map(em); em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start != EXTENT_MAP_HOLE) { test_msg("Expected a hole, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != sectorsize) { test_msg("Unexpected extent wanted start %llu len %u, " "got start %llu len %llu\n", offset, sectorsize, em->start, em->len); goto out; } if (em->flags != 0) { test_msg("Unexpected flags set, want 0 have %lu\n", em->flags); goto out; } offset = em->start + em->len; free_extent_map(em); em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start >= EXTENT_MAP_LAST_BYTE) { test_msg("Expected a real extent, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != 2 * sectorsize) { test_msg("Unexpected extent wanted start %llu len %u, " "got start %llu len %llu\n", offset, 2 * sectorsize, em->start, em->len); goto out; } if (em->flags != 0) { test_msg("Unexpected flags set, want 0 have %lu\n", em->flags); goto out; } if (em->orig_start != orig_start) { test_msg("Wrong orig offset, want %llu, have %llu\n", orig_start, em->orig_start); goto out; } disk_bytenr += (em->start - orig_start); if (em->block_start != disk_bytenr) { test_msg("Wrong block start, want %llu, have %llu\n", disk_bytenr, em->block_start); goto out; } offset = em->start + em->len; free_extent_map(em); /* Prealloc extent */ em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start >= EXTENT_MAP_LAST_BYTE) { test_msg("Expected a real extent, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != sectorsize) { test_msg("Unexpected extent wanted start %llu len %u, " "got start %llu len %llu\n", offset, sectorsize, em->start, em->len); goto out; } if (em->flags != prealloc_only) { test_msg("Unexpected flags set, want %lu have %lu\n", prealloc_only, em->flags); goto out; } if (em->orig_start != em->start) { test_msg("Wrong orig offset, want %llu, have %llu\n", em->start, em->orig_start); goto out; } offset = em->start + em->len; free_extent_map(em); /* The next 3 are a half written prealloc extent */ em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start >= EXTENT_MAP_LAST_BYTE) { test_msg("Expected a real extent, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != sectorsize) { test_msg("Unexpected extent wanted start %llu len %u, " "got start %llu len %llu\n", offset, sectorsize, em->start, em->len); goto out; } if (em->flags != prealloc_only) { test_msg("Unexpected flags set, want %lu have %lu\n", prealloc_only, em->flags); goto out; } if (em->orig_start != em->start) { test_msg("Wrong orig offset, want %llu, have %llu\n", em->start, em->orig_start); goto out; } disk_bytenr = em->block_start; orig_start = em->start; offset = em->start + em->len; free_extent_map(em); em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start >= EXTENT_MAP_HOLE) { test_msg("Expected a real extent, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != sectorsize) { test_msg("Unexpected extent wanted start %llu len %u, " "got start %llu len %llu\n", offset, sectorsize, em->start, em->len); goto out; } if (em->flags != 0) { test_msg("Unexpected flags set, want 0 have %lu\n", em->flags); goto out; } if (em->orig_start != orig_start) { test_msg("Unexpected orig offset, wanted %llu, have %llu\n", orig_start, em->orig_start); goto out; } if (em->block_start != (disk_bytenr + (em->start - em->orig_start))) { test_msg("Unexpected block start, wanted %llu, have %llu\n", disk_bytenr + (em->start - em->orig_start), em->block_start); goto out; } offset = em->start + em->len; free_extent_map(em); em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start >= EXTENT_MAP_LAST_BYTE) { test_msg("Expected a real extent, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != 2 * sectorsize) { test_msg("Unexpected extent wanted start %llu len %u, " "got start %llu len %llu\n", offset, 2 * sectorsize, em->start, em->len); goto out; } if (em->flags != prealloc_only) { test_msg("Unexpected flags set, want %lu have %lu\n", prealloc_only, em->flags); goto out; } if (em->orig_start != orig_start) { test_msg("Wrong orig offset, want %llu, have %llu\n", orig_start, em->orig_start); goto out; } if (em->block_start != (disk_bytenr + (em->start - em->orig_start))) { test_msg("Unexpected block start, wanted %llu, have %llu\n", disk_bytenr + (em->start - em->orig_start), em->block_start); goto out; } offset = em->start + em->len; free_extent_map(em); /* Now for the compressed extent */ em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start >= EXTENT_MAP_LAST_BYTE) { test_msg("Expected a real extent, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != 2 * sectorsize) { test_msg("Unexpected extent wanted start %llu len %u," "got start %llu len %llu\n", offset, 2 * sectorsize, em->start, em->len); goto out; } if (em->flags != compressed_only) { test_msg("Unexpected flags set, want %lu have %lu\n", compressed_only, em->flags); goto out; } if (em->orig_start != em->start) { test_msg("Wrong orig offset, want %llu, have %llu\n", em->start, em->orig_start); goto out; } if (em->compress_type != BTRFS_COMPRESS_ZLIB) { test_msg("Unexpected compress type, wanted %d, got %d\n", BTRFS_COMPRESS_ZLIB, em->compress_type); goto out; } offset = em->start + em->len; free_extent_map(em); /* Split compressed extent */ em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start >= EXTENT_MAP_LAST_BYTE) { test_msg("Expected a real extent, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != sectorsize) { test_msg("Unexpected extent wanted start %llu len %u," "got start %llu len %llu\n", offset, sectorsize, em->start, em->len); goto out; } if (em->flags != compressed_only) { test_msg("Unexpected flags set, want %lu have %lu\n", compressed_only, em->flags); goto out; } if (em->orig_start != em->start) { test_msg("Wrong orig offset, want %llu, have %llu\n", em->start, em->orig_start); goto out; } if (em->compress_type != BTRFS_COMPRESS_ZLIB) { test_msg("Unexpected compress type, wanted %d, got %d\n", BTRFS_COMPRESS_ZLIB, em->compress_type); goto out; } disk_bytenr = em->block_start; orig_start = em->start; offset = em->start + em->len; free_extent_map(em); em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start >= EXTENT_MAP_LAST_BYTE) { test_msg("Expected a real extent, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != sectorsize) { test_msg("Unexpected extent wanted start %llu len %u, " "got start %llu len %llu\n", offset, sectorsize, em->start, em->len); goto out; } if (em->flags != 0) { test_msg("Unexpected flags set, want 0 have %lu\n", em->flags); goto out; } if (em->orig_start != em->start) { test_msg("Wrong orig offset, want %llu, have %llu\n", em->start, em->orig_start); goto out; } offset = em->start + em->len; free_extent_map(em); em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start != disk_bytenr) { test_msg("Block start does not match, want %llu got %llu\n", disk_bytenr, em->block_start); goto out; } if (em->start != offset || em->len != 2 * sectorsize) { test_msg("Unexpected extent wanted start %llu len %u, " "got start %llu len %llu\n", offset, 2 * sectorsize, em->start, em->len); goto out; } if (em->flags != compressed_only) { test_msg("Unexpected flags set, want %lu have %lu\n", compressed_only, em->flags); goto out; } if (em->orig_start != orig_start) { test_msg("Wrong orig offset, want %llu, have %llu\n", em->start, orig_start); goto out; } if (em->compress_type != BTRFS_COMPRESS_ZLIB) { test_msg("Unexpected compress type, wanted %d, got %d\n", BTRFS_COMPRESS_ZLIB, em->compress_type); goto out; } offset = em->start + em->len; free_extent_map(em); /* A hole between regular extents but no hole extent */ em = btrfs_get_extent(inode, NULL, 0, offset + 6, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start >= EXTENT_MAP_LAST_BYTE) { test_msg("Expected a real extent, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != sectorsize) { test_msg("Unexpected extent wanted start %llu len %u, " "got start %llu len %llu\n", offset, sectorsize, em->start, em->len); goto out; } if (em->flags != 0) { test_msg("Unexpected flags set, want 0 have %lu\n", em->flags); goto out; } if (em->orig_start != em->start) { test_msg("Wrong orig offset, want %llu, have %llu\n", em->start, em->orig_start); goto out; } offset = em->start + em->len; free_extent_map(em); em = btrfs_get_extent(inode, NULL, 0, offset, 4096 * 1024, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start != EXTENT_MAP_HOLE) { test_msg("Expected a hole extent, got %llu\n", em->block_start); goto out; } /* * Currently we just return a length that we requested rather than the * length of the actual hole, if this changes we'll have to change this * test. */ if (em->start != offset || em->len != 3 * sectorsize) { test_msg("Unexpected extent wanted start %llu len %u, " "got start %llu len %llu\n", offset, 3 * sectorsize, em->start, em->len); goto out; } if (em->flags != vacancy_only) { test_msg("Unexpected flags set, want %lu have %lu\n", vacancy_only, em->flags); goto out; } if (em->orig_start != em->start) { test_msg("Wrong orig offset, want %llu, have %llu\n", em->start, em->orig_start); goto out; } offset = em->start + em->len; free_extent_map(em); em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize, 0); if (IS_ERR(em)) { test_msg("Got an error when we shouldn't have\n"); goto out; } if (em->block_start >= EXTENT_MAP_LAST_BYTE) { test_msg("Expected a real extent, got %llu\n", em->block_start); goto out; } if (em->start != offset || em->len != sectorsize) { test_msg("Unexpected extent wanted start %llu len %u," "got start %llu len %llu\n", offset, sectorsize, em->start, em->len); goto out; } if (em->flags != 0) { test_msg("Unexpected flags set, want 0 have %lu\n", em->flags); goto out; } if (em->orig_start != em->start) { test_msg("Wrong orig offset, want %llu, have %llu\n", em->start, em->orig_start); goto out; } ret = 0; out: if (!IS_ERR(em)) free_extent_map(em); iput(inode); btrfs_free_dummy_root(root); btrfs_free_dummy_fs_info(fs_info); return ret; }
static int iterate_inode_extrefs(u64 inum, struct btrfs_root *fs_root, struct btrfs_path *path, iterate_irefs_t *iterate, void *ctx) { int ret; int slot; u64 offset = 0; u64 parent; int found = 0; struct extent_buffer *eb; struct btrfs_inode_extref *extref; struct extent_buffer *leaf; u32 item_size; u32 cur_offset; unsigned long ptr; while (1) { ret = btrfs_find_one_extref(fs_root, inum, offset, path, &extref, &offset); if (ret < 0) break; if (ret) { ret = found ? 0 : -ENOENT; break; } ++found; slot = path->slots[0]; eb = btrfs_clone_extent_buffer(path->nodes[0]); if (!eb) { ret = -ENOMEM; break; } extent_buffer_get(eb); btrfs_tree_read_lock(eb); btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK); btrfs_release_path(path); leaf = path->nodes[0]; item_size = btrfs_item_size_nr(leaf, slot); ptr = btrfs_item_ptr_offset(leaf, slot); cur_offset = 0; while (cur_offset < item_size) { u32 name_len; extref = (struct btrfs_inode_extref *)(ptr + cur_offset); parent = btrfs_inode_extref_parent(eb, extref); name_len = btrfs_inode_extref_name_len(eb, extref); ret = iterate(parent, name_len, (unsigned long)&extref->name, eb, ctx); if (ret) break; cur_offset += btrfs_inode_extref_name_len(leaf, extref); cur_offset += sizeof(*extref); } btrfs_tree_read_unlock_blocking(eb); free_extent_buffer(eb); offset++; } btrfs_release_path(path); return ret; }