diff options
-rw-r--r-- | convert.c | 391 | ||||
-rw-r--r-- | ctree.c | 125 | ||||
-rw-r--r-- | ctree.h | 32 | ||||
-rw-r--r-- | dir-item.c | 7 | ||||
-rw-r--r-- | disk-io.c | 158 | ||||
-rw-r--r-- | disk-io.h | 1 | ||||
-rw-r--r-- | extent-tree.c | 58 | ||||
-rw-r--r-- | file-item.c | 335 | ||||
-rw-r--r-- | mkfs.c | 2 | ||||
-rw-r--r-- | root-tree.c | 50 | ||||
-rw-r--r-- | utils.c | 1 | ||||
-rw-r--r-- | volumes.c | 26 |
12 files changed, 824 insertions, 362 deletions
@@ -41,7 +41,11 @@ #include <ext2fs/ext2_fs.h> #include <ext2fs/ext2fs.h> #include <ext2fs/ext2_ext_attr.h> + #define INO_OFFSET (BTRFS_FIRST_FREE_OBJECTID - EXT2_ROOT_INO) +#define STRIPE_LEN (64 * 1024) +#define EXT2_IMAGE_SUBVOL_OBJECTID BTRFS_FIRST_FREE_OBJECTID + /* * Open Ext2fs in readonly mode, read block allocation bitmap and * inode bitmap into memory. @@ -101,7 +105,7 @@ static int ext2_free_block(ext2_filsys fs, u64 block) static int cache_free_extents(struct btrfs_root *root, ext2_filsys ext2_fs) { - int ret = 0; + int i, ret = 0; blk_t block; u64 bytenr; u64 blocksize = ext2_fs->blocksize; @@ -113,10 +117,19 @@ static int cache_free_extents(struct btrfs_root *root, ext2_filsys ext2_fs) bytenr = block * blocksize; ret = set_extent_dirty(&root->fs_info->free_space_cache, bytenr, bytenr + blocksize - 1, 0); - if (ret) + BUG_ON(ret); + } + + for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) { + bytenr = btrfs_sb_offset(i); + bytenr &= ~((u64)STRIPE_LEN - 1); + if (bytenr >= blocksize * ext2_fs->super->s_blocks_count) break; + clear_extent_dirty(&root->fs_info->free_space_cache, bytenr, + bytenr + STRIPE_LEN - 1, 0); } - return ret; + + return 0; } static int custom_alloc_extent(struct btrfs_root *root, u64 num_bytes, @@ -172,10 +185,26 @@ fail: return -ENOSPC; } +static int intersect_with_sb(u64 bytenr, u64 num_bytes) +{ + int i; + u64 offset; + + for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) { + offset = btrfs_sb_offset(i); + offset &= ~((u64)STRIPE_LEN - 1); + + if (bytenr < offset + STRIPE_LEN && + bytenr + num_bytes > offset) + return 1; + } + return 0; +} + static int custom_free_extent(struct btrfs_root *root, u64 bytenr, u64 num_bytes) { - return 0; + return intersect_with_sb(bytenr, num_bytes); } struct btrfs_extent_ops extent_ops = { @@ -238,15 +267,17 @@ static int dir_iterate_proc(ext2_ino_t dir, int entry, ret = btrfs_insert_dir_item(idata->trans, idata->root, dirent->name, dirent->name_len, idata->objectid, &location, - filetype_conversion_table[file_type]); + filetype_conversion_table[file_type], + idata->index_cnt); if (ret) goto fail; ret = btrfs_insert_inode_ref(idata->trans, idata->root, dirent->name, dirent->name_len, objectid, idata->objectid, - idata->index_cnt++); + idata->index_cnt); if (ret) goto fail; + idata->index_cnt++; inode_size = btrfs_stack_inode_size(idata->inode) + dirent->name_len * 2; btrfs_set_stack_inode_size(idata->inode, inode_size); @@ -323,7 +354,7 @@ static int record_file_extent(struct btrfs_trans_handle *trans, struct btrfs_path path; struct btrfs_extent_item extent_item; u32 blocksize = root->sectorsize; - u64 nblocks; + u64 nbytes; u64 bytes_used; if (disk_bytenr == 0) { @@ -348,9 +379,11 @@ static int record_file_extent(struct btrfs_trans_handle *trans, blocksize, buffer); if (ret) break; - ret = btrfs_csum_file_block(trans, root, inode, - objectid, file_pos + offset, - buffer, blocksize); + ret = btrfs_csum_file_block(trans, + root->fs_info->csum_root, + disk_bytenr + num_bytes, + disk_bytenr + offset, + buffer, blocksize); if (ret) break; } @@ -375,10 +408,14 @@ static int record_file_extent(struct btrfs_trans_handle *trans, btrfs_set_file_extent_disk_num_bytes(leaf, fi, num_bytes); btrfs_set_file_extent_offset(leaf, fi, 0); btrfs_set_file_extent_num_bytes(leaf, fi, num_bytes); + btrfs_set_file_extent_ram_bytes(leaf, fi, num_bytes); + btrfs_set_file_extent_compression(leaf, fi, 0); + btrfs_set_file_extent_encryption(leaf, fi, 0); + btrfs_set_file_extent_other_encoding(leaf, fi, 0); btrfs_mark_buffer_dirty(leaf); - nblocks = btrfs_stack_inode_nblocks(inode) + num_bytes / 512; - btrfs_set_stack_inode_nblocks(inode, nblocks); + nbytes = btrfs_stack_inode_nbytes(inode) + num_bytes; + btrfs_set_stack_inode_nbytes(inode, nbytes); bytes_used = btrfs_root_used(&root->root_item); btrfs_set_root_used(&root->root_item, bytes_used + num_bytes); @@ -393,6 +430,10 @@ static int record_file_extent(struct btrfs_trans_handle *trans, bytes_used = btrfs_super_bytes_used(&info->super_copy); btrfs_set_super_bytes_used(&info->super_copy, bytes_used + num_bytes); + ret = btrfs_update_block_group(trans, root, disk_bytenr, + num_bytes, 1, 0); + if (ret) + goto fail; } else if (ret != -EEXIST) { goto fail; } @@ -400,7 +441,7 @@ static int record_file_extent(struct btrfs_trans_handle *trans, ret = btrfs_inc_extent_ref(trans, root, disk_bytenr, num_bytes, leaf->start, root->root_key.objectid, - trans->transid, objectid, file_pos); + trans->transid, objectid); if (ret) goto fail; ret = 0; @@ -440,13 +481,16 @@ static int block_iterate_proc(ext2_filsys ext2_fs, struct blk_iterate_data *idata) { int ret; + int sb_region; + int do_barrier; struct btrfs_root *root = idata->root; struct btrfs_trans_handle *trans = idata->trans; struct btrfs_block_group_cache *cache; - u64 bytenr; + u64 bytenr = disk_block * root->sectorsize; - BUG_ON(disk_block == 0); - if ((idata->num_blocks > 0 && disk_block >= idata->boundary) || + sb_region = intersect_with_sb(bytenr, root->sectorsize); + do_barrier = sb_region || disk_block >= idata->boundary; + if ((idata->num_blocks > 0 && do_barrier) || (file_block > idata->first_block + idata->num_blocks) || (disk_block != idata->disk_block + idata->num_blocks)) { if (idata->num_blocks > 0) { @@ -468,10 +512,14 @@ static int block_iterate_proc(ext2_filsys ext2_fs, goto fail; } - bytenr = disk_block * root->sectorsize; - cache = btrfs_lookup_block_group(root->fs_info, bytenr); - BUG_ON(!cache); - bytenr = cache->key.objectid + cache->key.offset; + if (sb_region) { + bytenr += STRIPE_LEN - 1; + bytenr &= ~((u64)STRIPE_LEN - 1); + } else { + cache = btrfs_lookup_block_group(root->fs_info, bytenr); + BUG_ON(!cache); + bytenr = cache->key.objectid + cache->key.offset; + } idata->first_block = file_block; idata->disk_block = disk_block; @@ -925,20 +973,18 @@ static inline dev_t new_decode_dev(u32 dev) } static int copy_inode_item(struct btrfs_inode_item *dst, - struct ext2_inode *src) + struct ext2_inode *src, u32 blocksize) { btrfs_set_stack_inode_generation(dst, 1); btrfs_set_stack_inode_size(dst, src->i_size); - btrfs_set_stack_inode_nblocks(dst, src->i_blocks); + btrfs_set_stack_inode_nbytes(dst, (u64)src->i_blocks * blocksize); btrfs_set_stack_inode_block_group(dst, 0); - btrfs_set_stack_inode_nblocks(dst, 0); btrfs_set_stack_inode_nlink(dst, src->i_links_count); btrfs_set_stack_inode_uid(dst, src->i_uid | (src->i_uid_high << 16)); btrfs_set_stack_inode_gid(dst, src->i_gid | (src->i_gid_high << 16)); btrfs_set_stack_inode_mode(dst, src->i_mode); btrfs_set_stack_inode_rdev(dst, 0); btrfs_set_stack_inode_flags(dst, 0); - btrfs_set_stack_inode_compat_flags(dst, 0); btrfs_set_stack_timespec_sec(&dst->atime, src->i_atime); btrfs_set_stack_timespec_nsec(&dst->atime, 0); btrfs_set_stack_timespec_sec(&dst->ctime, src->i_ctime); @@ -986,7 +1032,7 @@ static int copy_single_inode(struct btrfs_trans_handle *trans, if (ext2_inode->i_links_count == 0) return 0; - copy_inode_item(&btrfs_inode, ext2_inode); + copy_inode_item(&btrfs_inode, ext2_inode, ext2_fs->blocksize); if (!datacsum && S_ISREG(ext2_inode->i_mode)) { u32 flags = btrfs_stack_inode_flags(&btrfs_inode) | BTRFS_INODE_NODATASUM; @@ -1197,7 +1243,7 @@ static int create_ext2_image(struct btrfs_root *root, ext2_filsys ext2_fs, btrfs_set_stack_inode_generation(&btrfs_inode, 1); btrfs_set_stack_inode_size(&btrfs_inode, total_bytes); btrfs_set_stack_inode_nlink(&btrfs_inode, 1); - btrfs_set_stack_inode_nblocks(&btrfs_inode, 0); + btrfs_set_stack_inode_nbytes(&btrfs_inode, 0); btrfs_set_stack_inode_mode(&btrfs_inode, S_IFREG | 0400); btrfs_set_stack_inode_flags(&btrfs_inode, BTRFS_INODE_NODATASUM | BTRFS_INODE_READONLY); @@ -1330,12 +1376,13 @@ next: btrfs_set_key_type(&location, BTRFS_INODE_ITEM_KEY); ret = btrfs_insert_dir_item(trans, root, name, strlen(name), btrfs_root_dirid(&root->root_item), - &location, EXT2_FT_REG_FILE); + &location, EXT2_FT_REG_FILE, objectid); if (ret) goto fail; ret = btrfs_insert_inode_ref(trans, root, name, strlen(name), objectid, - btrfs_root_dirid(&root->root_item), 0); + btrfs_root_dirid(&root->root_item), + objectid); if (ret) goto fail; location.objectid = btrfs_root_dirid(&root->root_item); @@ -1358,68 +1405,81 @@ fail: return ret; } -struct btrfs_root *create_subvol(struct btrfs_root *root, const char *name) +struct btrfs_root *link_subvol(struct btrfs_root *root, const char *base, + u64 root_objectid) { - int ret; - u64 objectid; - struct btrfs_key location; - struct btrfs_root_item root_item; struct btrfs_trans_handle *trans; struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_root *tree_root = fs_info->tree_root; struct btrfs_root *new_root; - struct extent_buffer *tmp; + struct btrfs_path *path; + struct btrfs_key key; + u64 dirid = btrfs_root_dirid(&root->root_item); + u64 index = 2; + char buf[64]; + int i; + int ret; + + path = btrfs_alloc_path(); + BUG_ON(!path); + + key.objectid = dirid; + key.type = BTRFS_DIR_INDEX_KEY; + key.offset = (u64)-1; + + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); + BUG_ON(ret <= 0); + + if (path->slots[0] > 0) { + path->slots[0]--; + btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); + if (key.objectid == dirid && key.type == BTRFS_DIR_INDEX_KEY) + index = key.offset + 1; + } + btrfs_free_path(path); trans = btrfs_start_transaction(root, 1); BUG_ON(!trans); - objectid = btrfs_super_root_dir(&fs_info->super_copy); - ret = btrfs_find_free_objectid(trans, root, objectid, &objectid); - if (ret) - goto fail; - ret = btrfs_copy_root(trans, root, root->node, &tmp, objectid); - if (ret) - goto fail; - memcpy(&root_item, &root->root_item, sizeof(root_item)); - btrfs_set_root_bytenr(&root_item, tmp->start); - btrfs_set_root_level(&root_item, btrfs_header_level(tmp)); - free_extent_buffer(tmp); + key.objectid = root_objectid; + key.offset = (u64)-1; + key.type = BTRFS_ROOT_ITEM_KEY; - location.objectid = objectid; - location.offset = 1; - btrfs_set_key_type(&location, BTRFS_ROOT_ITEM_KEY); - ret = btrfs_insert_root(trans, root->fs_info->tree_root, - &location, &root_item); - if (ret) - goto fail; - location.offset = (u64)-1; - ret = btrfs_insert_dir_item(trans, tree_root, name, strlen(name), - btrfs_super_root_dir(&fs_info->super_copy), - &location, BTRFS_FT_DIR); - if (ret) - goto fail; - ret = btrfs_insert_inode_ref(trans, tree_root, name, strlen(name), - objectid, - btrfs_super_root_dir(&fs_info->super_copy), - 0); + strcpy(buf, base); + for (i = 0; i < 1024; i++) { + ret = btrfs_insert_dir_item(trans, root, buf, strlen(buf), + dirid, &key, BTRFS_FT_DIR, index); + if (ret != -EEXIST) + break; + sprintf(buf, "%s%d", base, i); + } if (ret) goto fail; + + /* add the backref first */ + ret = btrfs_add_root_ref(trans, tree_root, root_objectid, + BTRFS_ROOT_BACKREF_KEY, + root->root_key.objectid, + dirid, index, buf, strlen(buf)); + BUG_ON(ret); + + /* now add the forward ref */ + ret = btrfs_add_root_ref(trans, tree_root, root->root_key.objectid, + BTRFS_ROOT_REF_KEY, root_objectid, + dirid, index, buf, strlen(buf)); + ret = btrfs_commit_transaction(trans, root); BUG_ON(ret); - new_root = btrfs_read_fs_root(fs_info, &location); + + new_root = btrfs_read_fs_root(fs_info, &key); if (!new_root || IS_ERR(new_root)) goto fail; - trans = btrfs_start_transaction(new_root, 1); - BUG_ON(!trans); - ret = btrfs_make_root_dir(trans, new_root, BTRFS_FIRST_FREE_OBJECTID); - if (ret) - goto fail; - ret = btrfs_commit_transaction(trans, new_root); - BUG_ON(ret); + return new_root; fail: return NULL; } + /* * Fixup block accounting. The initial block accounting created by * make_block_groups isn't accuracy in this case. @@ -1572,7 +1632,7 @@ static int create_chunk_mapping(struct btrfs_trans_handle *trans, btrfs_set_stack_chunk_length(&chunk, cache->key.offset); btrfs_set_stack_chunk_owner(&chunk, extent_root->root_key.objectid); - btrfs_set_stack_chunk_stripe_len(&chunk, 64 * 1024); + btrfs_set_stack_chunk_stripe_len(&chunk, STRIPE_LEN); btrfs_set_stack_chunk_type(&chunk, cache->flags); btrfs_set_stack_chunk_io_align(&chunk, device->io_align); btrfs_set_stack_chunk_io_width(&chunk, device->io_width); @@ -1603,6 +1663,42 @@ err: return ret; } +static int create_subvol(struct btrfs_trans_handle *trans, + struct btrfs_root *root, u64 root_objectid) +{ + struct extent_buffer *tmp; + struct btrfs_root *new_root; + struct btrfs_key key; + struct btrfs_root_item root_item; + int ret; + + ret = btrfs_copy_root(trans, root, root->node, &tmp, + root_objectid); + BUG_ON(ret); + + memcpy(&root_item, &root->root_item, sizeof(root_item)); + btrfs_set_root_bytenr(&root_item, tmp->start); + btrfs_set_root_level(&root_item, btrfs_header_level(tmp)); + btrfs_set_root_generation(&root_item, trans->transid); + free_extent_buffer(tmp); + + key.objectid = root_objectid; + key.type = BTRFS_ROOT_ITEM_KEY; + key.offset = trans->transid; + ret = btrfs_insert_root(trans, root->fs_info->tree_root, + &key, &root_item); + + key.offset = (u64)-1; + new_root = btrfs_read_fs_root(root->fs_info, &key); + BUG_ON(!new_root || IS_ERR(new_root)); + + ret = btrfs_make_root_dir(trans, new_root, BTRFS_FIRST_FREE_OBJECTID); + BUG_ON(ret); + + btrfs_free_fs_root(root->fs_info, new_root); + return 0; +} + static int init_btrfs(struct btrfs_root *root) { int ret; @@ -1629,7 +1725,7 @@ static int init_btrfs(struct btrfs_root *root) location.offset = (u64)-1; ret = btrfs_insert_dir_item(trans, fs_info->tree_root, "default", 7, btrfs_super_root_dir(&fs_info->super_copy), - &location, BTRFS_FT_DIR); + &location, BTRFS_FT_DIR, 0); if (ret) goto err; ret = btrfs_insert_inode_ref(trans, fs_info->tree_root, "default", 7, @@ -1639,6 +1735,14 @@ static int init_btrfs(struct btrfs_root *root) goto err; btrfs_set_root_dirid(&fs_info->fs_root->root_item, BTRFS_FIRST_FREE_OBJECTID); + + /* subvol for ext2 image file */ + ret = create_subvol(trans, root, EXT2_IMAGE_SUBVOL_OBJECTID); + BUG_ON(ret); + /* subvol for data relocation */ + ret = create_subvol(trans, root, BTRFS_DATA_RELOC_TREE_OBJECTID); + BUG_ON(ret); + ret = btrfs_commit_transaction(trans, root); BUG_ON(ret); err: @@ -1670,7 +1774,7 @@ static int migrate_super_block(int fd, u64 old_bytenr, u32 sectorsize) BUG_ON(btrfs_super_bytenr(super) != old_bytenr); btrfs_set_super_bytenr(super, BTRFS_SUPER_INFO_OFFSET); - csum_tree_block(NULL, buf, 0); + csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0); ret = pwrite(fd, buf->data, sectorsize, BTRFS_SUPER_INFO_OFFSET); if (ret != sectorsize) goto fail; @@ -1754,7 +1858,7 @@ static int prepare_system_chunk(int fd, u64 sb_bytenr, u32 sectorsize) if (ret) goto fail; - csum_tree_block(NULL, buf, 0); + csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0); ret = pwrite(fd, buf->data, sectorsize, sb_bytenr); if (ret != sectorsize) goto fail; @@ -1770,7 +1874,7 @@ fail: static int relocate_one_reference(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 extent_start, u64 extent_size, - u64 objectid, u64 offset, + u64 objectid, struct btrfs_key *leaf_key, struct extent_io_tree *reloc_tree) { struct extent_buffer *leaf; @@ -1780,30 +1884,56 @@ static int relocate_one_reference(struct btrfs_trans_handle *trans, struct btrfs_inode_item inode; struct blk_iterate_data data; u64 bytenr; + u64 offset; u64 num_bytes; u64 cur_offset; u64 new_pos; - u64 nblocks; + u64 nbytes; u64 root_gen; u64 root_owner; u64 sector_end; + u32 nritems; u32 sectorsize = root->sectorsize; unsigned long ptr; + int found = 0; + int datacsum; int fd; int ret; + memcpy(&key, leaf_key, sizeof(key)); + if (key.objectid < objectid || + (key.objectid == objectid && + key.type < BTRFS_EXTENT_DATA_KEY)) { + key.objectid = objectid; + key.type = BTRFS_EXTENT_DATA_KEY; + key.offset = 0; + } btrfs_init_path(&path); - ret = btrfs_lookup_file_extent(trans, root, &path, - objectid, offset, -1); - if (ret) + ret = btrfs_search_slot(trans, root, &key, &path, -1, 1); + if (ret < 0) goto fail; leaf = path.nodes[0]; - fi = btrfs_item_ptr(leaf, path.slots[0], - struct btrfs_file_extent_item); - /* the extent may be referenced by old snapshot */ - if (extent_start != btrfs_file_extent_disk_bytenr(leaf, fi) || - extent_size != btrfs_file_extent_disk_num_bytes(leaf, fi)) { + nritems = btrfs_header_nritems(leaf); + while (1) { + if (path.slots[0] >= nritems) + break; + btrfs_item_key_to_cpu(leaf, &key, path.slots[0]); + if (key.objectid != objectid || + key.type != BTRFS_EXTENT_DATA_KEY) + break; + fi = btrfs_item_ptr(leaf, path.slots[0], + struct btrfs_file_extent_item); + if (extent_start == btrfs_file_extent_disk_bytenr(leaf, fi) && + extent_size == btrfs_file_extent_disk_num_bytes(leaf, fi)) { + offset = key.offset; + found = 1; + break; + } + path.slots[0]++; + } + + if (!found) { ret = 1; goto fail; } @@ -1817,9 +1947,9 @@ static int relocate_one_reference(struct btrfs_trans_handle *trans, if (ret) goto fail; - ret = btrfs_free_extent(trans, root, extent_start, extent_size, - leaf->start, root_owner, root_gen, objectid, - offset, 0); + ret = btrfs_free_extent(trans, root, + extent_start, extent_size, leaf->start, + root_owner, root_gen, objectid, 0); if (ret) goto fail; @@ -1838,8 +1968,9 @@ static int relocate_one_reference(struct btrfs_trans_handle *trans, btrfs_release_path(root, &path); BUG_ON(num_bytes & (sectorsize - 1)); - nblocks = btrfs_stack_inode_nblocks(&inode) - num_bytes / 512; - btrfs_set_stack_inode_nblocks(&inode, nblocks); + nbytes = btrfs_stack_inode_nbytes(&inode) - num_bytes; + btrfs_set_stack_inode_nbytes(&inode, nbytes); + datacsum = !(btrfs_stack_inode_flags(&inode) & BTRFS_INODE_NODATASUM); data = (struct blk_iterate_data) { .trans = trans, @@ -1850,7 +1981,7 @@ static int relocate_one_reference(struct btrfs_trans_handle *trans, .disk_block = 0, .num_blocks = 0, .boundary = (u64)-1, - .checksum = 0, + .checksum = datacsum, .errcode = 0, }; @@ -1926,25 +2057,46 @@ static int relocate_extents_range(struct btrfs_root *fs_root, { struct btrfs_fs_info *info = fs_root->fs_info; struct btrfs_root *extent_root = info->extent_root; - struct btrfs_root *cur_root; + struct btrfs_root *cur_root = NULL; struct btrfs_trans_handle *trans; struct btrfs_extent_ref *ref_item; struct extent_buffer *leaf; struct btrfs_key key; + struct btrfs_key leaf_key; struct btrfs_path path; struct extent_io_tree reloc_tree; u64 cur_byte; u64 num_bytes; u64 ref_root; u64 ref_owner; - u64 ref_offset; u64 num_refs; + u64 leaf_start; int pass = 0; int ret; int found; btrfs_init_path(&path); extent_io_tree_init(&reloc_tree); + + key.objectid = start_byte; + key.offset = 0; + key.type = BTRFS_EXTENT_ITEM_KEY; + ret = btrfs_search_slot(NULL, extent_root, &key, &path, 0, 0); + if (ret < 0) + goto fail; + if (ret > 0) { + ret = btrfs_previous_item(extent_root, &path, 0, + BTRFS_EXTENT_ITEM_KEY); + if (ret < 0) + goto fail; + if (ret == 0) { + leaf = path.nodes[0]; + btrfs_item_key_to_cpu(leaf, &key, path.slots[0]); + if (key.objectid + key.offset > start_byte) + start_byte = key.objectid; + } + } + btrfs_release_path(extent_root, &path); again: cur_root = (pass % 2 == 0) ? ext2_root : fs_root; num_refs = 0; @@ -2005,7 +2157,7 @@ next: struct btrfs_extent_ref); ref_root = btrfs_ref_root(leaf, ref_item); ref_owner = btrfs_ref_objectid(leaf, ref_item); - ref_offset = btrfs_ref_offset(leaf, ref_item); + leaf_start = key.offset; num_refs++; BUG_ON(ref_owner < BTRFS_FIRST_FREE_OBJECTID); @@ -2018,9 +2170,16 @@ next: if (!found) goto next; + leaf = read_tree_block(cur_root, leaf_start, + btrfs_level_size(cur_root, 0), 0); + BUG_ON(!leaf); + BUG_ON(btrfs_header_level(leaf) != 0); + btrfs_item_key_to_cpu(leaf, &leaf_key, 0); + free_extent_buffer(leaf); + ret = relocate_one_reference(trans, cur_root, cur_byte, num_bytes, ref_owner, - ref_offset, &reloc_tree); + &leaf_key, &reloc_tree); if (ret < 0) goto fail; @@ -2056,7 +2215,7 @@ static int cleanup_sys_chunk(struct btrfs_root *fs_root, struct btrfs_root *ext2_root) { struct btrfs_block_group_cache *cache; - int ret = 0; + int i, ret = 0; u64 offset = 0; u64 end_byte; @@ -2075,6 +2234,16 @@ static int cleanup_sys_chunk(struct btrfs_root *fs_root, } offset = end_byte; } + for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) { + offset = btrfs_sb_offset(i); + offset &= ~((u64)STRIPE_LEN - 1); + + ret = relocate_extents_range(fs_root, ext2_root, + offset, offset + STRIPE_LEN); + if (ret) + goto fail; + } + ret = 0; fail: return ret; } @@ -2234,7 +2403,7 @@ int do_convert(const char *devname, int datacsum, int packing, int noxattr) } root->fs_info->extent_ops = &extent_ops; /* recover block allocation bitmap */ - for (i = 0; i < 6; i++) { + for (i = 0; i < 7; i++) { blocks[i] /= blocksize; ext2_free_block(ext2_fs, blocks[i]); } @@ -2243,11 +2412,6 @@ int do_convert(const char *devname, int datacsum, int packing, int noxattr) fprintf(stderr, "unable to setup the root tree\n"); goto fail; } - ext2_root = create_subvol(root, "ext2_saved"); - if (!ext2_root) { - fprintf(stderr, "unable to create subvol\n"); - goto fail; - } printf("creating btrfs metadata.\n"); ret = copy_inodes(root, ext2_fs, datacsum, packing, noxattr); if (ret) { @@ -2255,6 +2419,11 @@ int do_convert(const char *devname, int datacsum, int packing, int noxattr) goto fail; } printf("creating ext2fs image file.\n"); + ext2_root = link_subvol(root, "ext2_saved", EXT2_IMAGE_SUBVOL_OBJECTID); + if (!ext2_root) { + fprintf(stderr, "unable to create subvol\n"); + goto fail; + } ret = create_ext2_image(ext2_root, ext2_fs, "image"); if (ret) { fprintf(stderr, "error during create_ext2_image %d\n", ret); @@ -2401,21 +2570,14 @@ int do_rollback(const char *devname, int force) } btrfs_init_path(&path); - name = "ext2_saved"; - root_dir = btrfs_super_root_dir(&root->fs_info->super_copy); - dir = btrfs_lookup_dir_item(NULL, root->fs_info->tree_root, &path, - root_dir, name, strlen(name), 0); - if (!dir || IS_ERR(dir)) { - fprintf(stderr, "unable to find subvol %s\n", name); - goto fail; - } - leaf = path.nodes[0]; - btrfs_dir_item_key_to_cpu(leaf, dir, &key); - btrfs_release_path(root->fs_info->tree_root, &path); + key.objectid = EXT2_IMAGE_SUBVOL_OBJECTID; + key.type = BTRFS_ROOT_ITEM_KEY; + key.offset = (u64)-1; ext2_root = btrfs_read_fs_root(root->fs_info, &key); if (!ext2_root || IS_ERR(ext2_root)) { - fprintf(stderr, "unable to open subvol %s\n", name); + fprintf(stderr, "unable to open subvol %llu\n", + key.objectid); goto fail; } @@ -2485,7 +2647,8 @@ int do_rollback(const char *devname, int force) cache2 = btrfs_lookup_block_group(root->fs_info, offset + num_bytes - 1); if (!cache1 || cache1 != cache2 || - !(cache1->flags & BTRFS_BLOCK_GROUP_SYSTEM)) + (!(cache1->flags & BTRFS_BLOCK_GROUP_SYSTEM) && + !intersect_with_sb(offset, num_bytes))) break; set_extent_bits(&io_tree, offset, offset + num_bytes - 1, @@ -1114,7 +1114,8 @@ again: if (ret && slot > 0) slot -= 1; p->slots[level] = slot; - if (ins_len > 0 && btrfs_header_nritems(b) >= + if ((p->search_for_split || ins_len > 0) && + btrfs_header_nritems(b) >= BTRFS_NODEPTRS_PER_BLOCK(root) - 3) { int sret = split_node(trans, root, p, level); BUG_ON(sret > 0); @@ -1949,11 +1950,11 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root int num_doubles = 0; struct btrfs_disk_key disk_key; - if (extend) + if (extend && data_size) space_needed = data_size; /* first try to make some room by pushing left and right */ - if (ins_key->type != BTRFS_DIR_ITEM_KEY) { + if (data_size && ins_key->type != BTRFS_DIR_ITEM_KEY) { wret = push_leaf_right(trans, root, path, data_size, 0); if (wret < 0) { return wret; @@ -2031,7 +2032,7 @@ again: } else { if (leaf_space_used(l, 0, mid + 1) + space_needed > BTRFS_LEAF_DATA_SIZE(root)) { - if (!extend && slot == 0) { + if (!extend && data_size && slot == 0) { btrfs_cpu_key_to_disk(&disk_key, ins_key); btrfs_set_header_nritems(right, 0); wret = insert_ptr(trans, root, path, @@ -2050,7 +2051,7 @@ again: ret = wret; } return ret; - } else if (extend && slot == 0) { + } else if ((extend || !data_size) && slot == 0) { mid = 1; } else { mid = slot; @@ -2117,6 +2118,120 @@ again: return ret; } +/* + * This function splits a single item into two items, + * giving 'new_key' to the new item and splitting the + * old one at split_offset (from the start of the item). + * + * The path may be released by this operation. After + * the split, the path is pointing to the old item. The + * new item is going to be in the same node as the old one. + * + * Note, the item being split must be smaller enough to live alone on + * a tree block with room for one extra struct btrfs_item + * + * This allows us to split the item in place, keeping a lock on the + * leaf the entire time. + */ +int btrfs_split_item(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + struct btrfs_path *path, + struct btrfs_key *new_key, + unsigned long split_offset) +{ + u32 item_size; + struct extent_buffer *leaf; + struct btrfs_key orig_key; + struct btrfs_item *item; + struct btrfs_item *new_item; + int ret = 0; + int slot; + u32 nritems; + u32 orig_offset; + struct btrfs_disk_key disk_key; + char *buf; + + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &orig_key, path->slots[0]); + if (btrfs_leaf_free_space(root, leaf) >= sizeof(struct btrfs_item)) + goto split; + + item_size = btrfs_item_size_nr(leaf, path->slots[0]); + btrfs_release_path(root, path); + + path->search_for_split = 1; + + ret = btrfs_search_slot(trans, root, &orig_key, path, 0, 1); + path->search_for_split = 0; + + /* if our item isn't there or got smaller, return now */ + if (ret != 0 || item_size != btrfs_item_size_nr(path->nodes[0], + path->slots[0])) { + return -EAGAIN; + } + + ret = split_leaf(trans, root, &orig_key, path, 0, 0); + BUG_ON(ret); + + BUG_ON(btrfs_leaf_free_space(root, leaf) < sizeof(struct btrfs_item)); + leaf = path->nodes[0]; + +split: + item = btrfs_item_nr(leaf, path->slots[0]); + orig_offset = btrfs_item_offset(leaf, item); + item_size = btrfs_item_size(leaf, item); + + + buf = kmalloc(item_size, GFP_NOFS); + read_extent_buffer(leaf, buf, btrfs_item_ptr_offset(leaf, + path->slots[0]), item_size); + slot = path->slots[0] + 1; + leaf = path->nodes[0]; + + nritems = btrfs_header_nritems(leaf); + + if (slot != nritems) { + /* shift the items */ + memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + 1), + btrfs_item_nr_offset(slot), + (nritems - slot) * sizeof(struct btrfs_item)); + + } + + btrfs_cpu_key_to_disk(&disk_key, new_key); + btrfs_set_item_key(leaf, &disk_key, slot); + + new_item = btrfs_item_nr(leaf, slot); + + btrfs_set_item_offset(leaf, new_item, orig_offset); + btrfs_set_item_size(leaf, new_item, item_size - split_offset); + + btrfs_set_item_offset(leaf, item, + orig_offset + item_size - split_offset); + btrfs_set_item_size(leaf, item, split_offset); + + btrfs_set_header_nritems(leaf, nritems + 1); + + /* write the data for the start of the original item */ + write_extent_buffer(leaf, buf, + btrfs_item_ptr_offset(leaf, path->slots[0]), + split_offset); + + /* write the data for the new item */ + write_extent_buffer(leaf, buf + split_offset, + btrfs_item_ptr_offset(leaf, slot), + item_size - split_offset); + btrfs_mark_buffer_dirty(leaf); + + ret = 0; + if (btrfs_leaf_free_space(root, leaf) < 0) { + btrfs_print_leaf(root, leaf); + BUG(); + } + kfree(buf); + return ret; +} + int btrfs_truncate_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, @@ -392,6 +392,12 @@ struct btrfs_path { int slots[BTRFS_MAX_LEVEL]; int reada; int lowest_level; + + /* + * set by btrfs_split_item, tells search_slot to keep all locks + * and to force calls to keep space in the nodes + */ + int search_for_split; }; /* @@ -642,8 +648,9 @@ struct btrfs_fs_info { struct btrfs_trans_handle *running_transaction; struct btrfs_super_block super_copy; - struct extent_buffer *sb_buffer; struct mutex fs_mutex; + + u64 super_bytenr; u64 total_pinned; struct btrfs_extent_ops *extent_ops; @@ -1582,6 +1589,11 @@ int btrfs_truncate_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u32 new_size, int from_end); +int btrfs_split_item(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + struct btrfs_path *path, + struct btrfs_key *new_key, + unsigned long split_offset); int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_key *key, struct btrfs_path *p, int ins_len, int cow); @@ -1629,6 +1641,11 @@ int btrfs_set_item_key_safe(struct btrfs_trans_handle *trans, struct btrfs_key *new_key); /* root-item.c */ +int btrfs_add_root_ref(struct btrfs_trans_handle *trans, + struct btrfs_root *tree_root, + u64 root_id, u8 type, u64 ref_id, + u64 dirid, u64 sequence, + const char *name, int name_len); int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_key *key); int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root @@ -1644,7 +1661,7 @@ int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid, /* dir-item.c */ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, const char *name, int name_len, u64 dir, - struct btrfs_key *location, u8 type); + struct btrfs_key *location, u8 type, u64 index); struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 dir, @@ -1698,6 +1715,8 @@ int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root struct btrfs_key *location, int mod); /* file-item.c */ +int btrfs_del_csums(struct btrfs_trans_handle *trans, + struct btrfs_root *root, u64 bytenr, u64 len); int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 objectid, u64 pos, u64 offset, @@ -1711,15 +1730,12 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, struct btrfs_path *path, u64 objectid, u64 bytenr, int mod); int btrfs_csum_file_block(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_inode_item *inode, - u64 objectid, u64 offset, - char *data, size_t len); + struct btrfs_root *root, u64 alloc_end, + u64 bytenr, char *data, size_t len); struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, - u64 objectid, u64 offset, - int cow); + u64 bytenr, int cow); int btrfs_csum_truncate(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 isize); @@ -107,7 +107,7 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans, int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, const char *name, int name_len, u64 dir, - struct btrfs_key *location, u8 type) + struct btrfs_key *location, u8 type, u64 index) { int ret = 0; int ret2 = 0; @@ -128,8 +128,6 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root name, name_len); if (IS_ERR(dir_item)) { ret = PTR_ERR(dir_item); - if (ret == -EEXIST) - goto second_insert; goto out; } @@ -144,7 +142,6 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root write_extent_buffer(leaf, name, name_ptr, name_len); btrfs_mark_buffer_dirty(leaf); -second_insert: /* FIXME, use some real flag for selecting the extra index */ if (root == root->fs_info->tree_root) { ret = 0; @@ -153,7 +150,7 @@ second_insert: btrfs_release_path(root, path); btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY); - key.offset = location->objectid; + key.offset = index; dir_item = insert_with_overflow(trans, root, path, &key, data_size, name, name_len); if (IS_ERR(dir_item)) { @@ -552,6 +552,7 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr, struct btrfs_root *extent_root = malloc(sizeof(struct btrfs_root)); struct btrfs_root *chunk_root = malloc(sizeof(struct btrfs_root)); struct btrfs_root *dev_root = malloc(sizeof(struct btrfs_root)); + struct btrfs_root *csum_root = malloc(sizeof(struct btrfs_root)); struct btrfs_fs_info *fs_info = malloc(sizeof(*fs_info)); int ret; struct btrfs_super_block *disk_super; @@ -580,6 +581,7 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr, fs_info->extent_root = extent_root; fs_info->chunk_root = chunk_root; fs_info->dev_root = dev_root; + fs_info->csum_root = csum_root; if (!writes) fs_info->readonly = 1; @@ -607,27 +609,17 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr, ret = btrfs_open_devices(fs_devices, O_RDONLY); BUG_ON(ret); - fs_info->sb_buffer = btrfs_find_create_tree_block(tree_root, sb_bytenr, - 4096); - BUG_ON(!fs_info->sb_buffer); - fs_info->sb_buffer->fd = fs_devices->latest_bdev; - fs_info->sb_buffer->dev_bytenr = sb_bytenr; - ret = read_extent_from_disk(fs_info->sb_buffer); - BUG_ON(ret); - btrfs_set_buffer_uptodate(fs_info->sb_buffer); - - read_extent_buffer(fs_info->sb_buffer, &fs_info->super_copy, 0, - sizeof(fs_info->super_copy)); - read_extent_buffer(fs_info->sb_buffer, fs_info->fsid, - (unsigned long)btrfs_super_fsid(fs_info->sb_buffer), - BTRFS_FSID_SIZE); - + fs_info->super_bytenr = sb_bytenr; disk_super = &fs_info->super_copy; - if (strncmp((char *)(&disk_super->magic), BTRFS_MAGIC, - sizeof(disk_super->magic))) { + ret = btrfs_read_dev_super(fs_devices->latest_bdev, + disk_super, sb_bytenr); + if (ret) { printk("No valid btrfs found\n"); BUG_ON(1); } + + memcpy(fs_info->fsid, &disk_super->fsid, BTRFS_FSID_SIZE); + nodesize = btrfs_super_nodesize(disk_super); leafsize = btrfs_super_leafsize(disk_super); sectorsize = btrfs_super_sectorsize(disk_super); @@ -637,8 +629,6 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr, tree_root->sectorsize = sectorsize; tree_root->stripesize = stripesize; - ret = btrfs_read_super_device(tree_root, fs_info->sb_buffer); - BUG_ON(ret); ret = btrfs_read_sys_array(tree_root); BUG_ON(ret); blocksize = btrfs_level_size(tree_root, @@ -682,6 +672,11 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr, dev_root->track_dirty = 1; ret = find_and_setup_root(tree_root, fs_info, + BTRFS_CSUM_TREE_OBJECTID, csum_root); + BUG_ON(ret); + csum_root->track_dirty = 1; + + ret = find_and_setup_root(tree_root, fs_info, BTRFS_FS_TREE_OBJECTID, root); BUG_ON(ret); root->ref_cows = 1; @@ -695,27 +690,83 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr, return root; } -int write_dev_supers(struct btrfs_root *root, struct extent_buffer *sb, +int btrfs_read_dev_super(int fd, struct btrfs_super_block *sb, u64 sb_bytenr) +{ + struct btrfs_super_block buf; + int i; + int ret; + u64 transid = 0; + u64 bytenr; + + if (sb_bytenr != BTRFS_SUPER_INFO_OFFSET) { + ret = pread64(fd, &buf, sizeof(buf), sb_bytenr); + if (ret < sizeof(buf)) + return -1; + + if (btrfs_super_bytenr(&buf) != sb_bytenr || + strncmp((char *)(&buf.magic), BTRFS_MAGIC, + sizeof(buf.magic))) + return -1; + + memcpy(sb, &buf, sizeof(*sb)); + return 0; + } + + for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) { + bytenr = btrfs_sb_offset(i); + ret = pread64(fd, &buf, sizeof(buf), bytenr); + if (ret < sizeof(buf)) + break; + + if (btrfs_super_bytenr(&buf) != bytenr || + strncmp((char *)(&buf.magic), BTRFS_MAGIC, + sizeof(buf.magic))) + continue; + + if (btrfs_super_generation(&buf) > transid) { + memcpy(sb, &buf, sizeof(*sb)); + transid = btrfs_super_generation(&buf); + } + } + + return transid > 0 ? 0 : -1; +} + +int write_dev_supers(struct btrfs_root *root, struct btrfs_super_block *sb, struct btrfs_device *device) { u64 bytenr; - u64 flags; + u32 crc; int i, ret; - sb->fd = device->fd; + if (root->fs_info->super_bytenr != BTRFS_SUPER_INFO_OFFSET) { + btrfs_set_super_bytenr(sb, root->fs_info->super_bytenr); + + crc = ~(u32)0; + crc = btrfs_csum_data(NULL, (char *)sb + BTRFS_CSUM_SIZE, crc, + BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE); + btrfs_csum_final(crc, (char *)&sb->csum[0]); + + ret = pwrite64(device->fd, sb, BTRFS_SUPER_INFO_SIZE, + root->fs_info->super_bytenr); + BUG_ON(ret != BTRFS_SUPER_INFO_SIZE); + return 0; + } + for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) { bytenr = btrfs_sb_offset(i); if (bytenr + BTRFS_SUPER_INFO_SIZE >= device->total_bytes) break; - btrfs_set_header_bytenr(sb, bytenr); - flags = btrfs_header_flags(sb); - btrfs_set_header_flags(sb, flags | BTRFS_HEADER_FLAG_WRITTEN); - csum_tree_block(root, sb, 0); + btrfs_set_super_bytenr(sb, bytenr); - sb->dev_bytenr = bytenr; - ret = write_extent_to_disk(sb); - BUG_ON(ret); + crc = ~(u32)0; + crc = btrfs_csum_data(NULL, (char *)sb + BTRFS_CSUM_SIZE, crc, + BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE); + btrfs_csum_final(crc, (char *)&sb->csum[0]); + + ret = pwrite64(device->fd, sb, BTRFS_SUPER_INFO_SIZE, bytenr); + BUG_ON(ret != BTRFS_SUPER_INFO_SIZE); } return 0; } @@ -725,32 +776,32 @@ int write_all_supers(struct btrfs_root *root) struct list_head *cur; struct list_head *head = &root->fs_info->fs_devices->devices; struct btrfs_device *dev; - struct extent_buffer *sb; + struct btrfs_super_block *sb; struct btrfs_dev_item *dev_item; int ret; + u64 flags; - sb = root->fs_info->sb_buffer; - dev_item = (struct btrfs_dev_item *)offsetof(struct btrfs_super_block, - dev_item); + sb = &root->fs_info->super_copy; + dev_item = &sb->dev_item; list_for_each(cur, head) { dev = list_entry(cur, struct btrfs_device, dev_list); if (!dev->writeable) continue; - btrfs_set_device_generation(sb, dev_item, 0); - btrfs_set_device_type(sb, dev_item, dev->type); - btrfs_set_device_id(sb, dev_item, dev->devid); - btrfs_set_device_total_bytes(sb, dev_item, dev->total_bytes); - btrfs_set_device_bytes_used(sb, dev_item, dev->bytes_used); - btrfs_set_device_io_align(sb, dev_item, dev->io_align); - btrfs_set_device_io_width(sb, dev_item, dev->io_width); - btrfs_set_device_sector_size(sb, dev_item, dev->sector_size); - write_extent_buffer(sb, dev->uuid, - (unsigned long)btrfs_device_uuid(dev_item), - BTRFS_UUID_SIZE); - write_extent_buffer(sb, dev->fs_devices->fsid, - (unsigned long)btrfs_device_fsid(dev_item), - BTRFS_UUID_SIZE); + btrfs_set_stack_device_generation(dev_item, 0); + btrfs_set_stack_device_type(dev_item, dev->type); + btrfs_set_stack_device_id(dev_item, dev->devid); + btrfs_set_stack_device_total_bytes(dev_item, dev->total_bytes); + btrfs_set_stack_device_bytes_used(dev_item, dev->bytes_used); + btrfs_set_stack_device_io_align(dev_item, dev->io_align); + btrfs_set_stack_device_io_width(dev_item, dev->io_width); + btrfs_set_stack_device_sector_size(dev_item, dev->sector_size); + memcpy(dev_item->uuid, dev->uuid, BTRFS_UUID_SIZE); + memcpy(dev_item->fsid, dev->fs_devices->fsid, BTRFS_UUID_SIZE); + + flags = btrfs_super_flags(sb); + btrfs_set_super_flags(sb, flags | BTRFS_HEADER_FLAG_WRITTEN); + ret = write_dev_supers(root, sb, dev); BUG_ON(ret); } @@ -779,9 +830,7 @@ int write_ctree_super(struct btrfs_trans_handle *trans, btrfs_header_level(chunk_root->node)); btrfs_set_super_chunk_root_generation(&root->fs_info->super_copy, btrfs_header_generation(chunk_root->node)); - write_extent_buffer(root->fs_info->sb_buffer, - &root->fs_info->super_copy, 0, - sizeof(root->fs_info->super_copy)); + ret = write_all_supers(root); if (ret) fprintf(stderr, "failed to write new super block err %d\n", ret); @@ -827,13 +876,13 @@ int close_ctree(struct btrfs_root *root) if (root->fs_info->tree_root->node) free_extent_buffer(root->fs_info->tree_root->node); free_extent_buffer(root->commit_root); - free_extent_buffer(root->fs_info->sb_buffer); - if (root->fs_info->chunk_root->node); + if (root->fs_info->chunk_root->node) free_extent_buffer(root->fs_info->chunk_root->node); - - if (root->fs_info->dev_root->node); + if (root->fs_info->dev_root->node) free_extent_buffer(root->fs_info->dev_root->node); + if (root->fs_info->csum_root->node) + free_extent_buffer(root->fs_info->csum_root->node); close_all_devices(root->fs_info); extent_io_tree_cleanup(&fs_info->extent_cache); @@ -848,6 +897,7 @@ int close_ctree(struct btrfs_root *root) free(fs_info->fs_root); free(fs_info->chunk_root); free(fs_info->dev_root); + free(fs_info->csum_root); free(fs_info); return 0; @@ -49,6 +49,7 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr, int close_ctree(struct btrfs_root *root); int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root *root); +int btrfs_read_dev_super(int fd, struct btrfs_super_block *sb, u64 sb_bytenr); int btrfs_map_bh_to_logical(struct btrfs_root *root, struct extent_buffer *bh, u64 logical); struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root, diff --git a/extent-tree.c b/extent-tree.c index b4ae95a9..5dc353a1 100644 --- a/extent-tree.c +++ b/extent-tree.c @@ -95,10 +95,8 @@ static int cache_block_group(struct btrfs_root *root, struct extent_buffer *leaf; struct extent_io_tree *free_space_cache; int slot; - u64 last = 0; + u64 last; u64 hole_size; - u64 first_free; - int found = 0; if (!block_group) return 0; @@ -114,22 +112,14 @@ static int cache_block_group(struct btrfs_root *root, return -ENOMEM; path->reada = 2; - first_free = block_group->key.objectid; - key.objectid = block_group->key.objectid; + last = max_t(u64, block_group->key.objectid, BTRFS_SUPER_INFO_OFFSET); + key.objectid = last; key.offset = 0; btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) - return ret; - ret = btrfs_previous_item(root, path, 0, BTRFS_EXTENT_ITEM_KEY); - if (ret < 0) - return ret; - if (ret == 0) { - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - if (key.objectid + key.offset > first_free) - first_free = key.objectid + key.offset; - } + goto err; + while(1) { leaf = path->nodes[0]; slot = path->slots[0]; @@ -153,10 +143,6 @@ static int cache_block_group(struct btrfs_root *root, } if (btrfs_key_type(&key) == BTRFS_EXTENT_ITEM_KEY) { - if (!found) { - last = first_free; - found = 1; - } if (key.objectid > last) { hole_size = key.objectid - last; set_extent_dirty(free_space_cache, last, @@ -169,8 +155,6 @@ next: path->slots[0]++; } - if (!found) - last = first_free; if (block_group->key.objectid + block_group->key.offset > last) { hole_size = block_group->key.objectid + @@ -1572,12 +1556,7 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root u64 super_used; u64 root_used; - if (pin) { - ret = pin_down_bytes(trans, root, bytenr, num_bytes, 0); - if (ret > 0) - mark_free = 1; - BUG_ON(ret < 0); - } + /* block accounting for super block */ super_used = btrfs_super_bytes_used(&info->super_copy); @@ -1593,8 +1572,25 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root if (ret) return ret; - if (ops && ops->free_extent) - ops->free_extent(root, bytenr, num_bytes); + if (ops && ops->free_extent) { + ret = ops->free_extent(root, bytenr, num_bytes); + if (ret > 0) { + pin = 0; + mark_free = 0; + } + } + + if (pin) { + ret = pin_down_bytes(trans, root, bytenr, num_bytes, 0); + if (ret > 0) + mark_free = 1; + BUG_ON(ret < 0); + } + + if (owner_objectid >= BTRFS_FIRST_FREE_OBJECTID) { + ret = btrfs_del_csums(trans, root, bytenr, num_bytes); + BUG_ON(ret); + } ret = update_block_group(trans, root, bytenr, num_bytes, 0, mark_free); @@ -2587,8 +2583,8 @@ int btrfs_make_block_groups(struct btrfs_trans_handle *trans, group_type = BTRFS_BLOCK_GROUP_SYSTEM; group_size /= 4; group_size &= ~(group_align - 1); - group_size = max_t(u64, group_size, 32 * 1024 * 1024); - group_size = min_t(u64, group_size, 128 * 1024 * 1024); + group_size = max_t(u64, group_size, 8 * 1024 * 1024); + group_size = min_t(u64, group_size, 32 * 1024 * 1024); } else { group_size &= ~(group_align - 1); if (total_data >= total_metadata * 2) { diff --git a/file-item.c b/file-item.c index a7400e24..562857c8 100644 --- a/file-item.c +++ b/file-item.c @@ -93,94 +93,23 @@ int btrfs_insert_inline_extent(struct btrfs_trans_handle *trans, key.offset = offset; btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY); - ret = btrfs_search_slot(trans, root, &key, path, 0, 1); - if (ret < 0) { + datasize = btrfs_file_extent_calc_inline_size(size); + ret = btrfs_insert_empty_item(trans, root, path, &key, datasize); + if (ret) { err = ret; goto fail; } - if (ret == 1) { - struct btrfs_key found_key; - if (path->slots[0] == 0) - goto insert; - - path->slots[0]--; - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); - - if (found_key.objectid != objectid) - goto insert; - - if (found_key.type != BTRFS_EXTENT_DATA_KEY) - goto insert; - ei = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - - if (btrfs_file_extent_type(leaf, ei) != - BTRFS_FILE_EXTENT_INLINE) { - goto insert; - } - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - ret = 0; - } - if (ret == 0) { - u32 found_size; - u64 found_end; + leaf = path->nodes[0]; + ei = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_file_extent_item); + btrfs_set_file_extent_generation(leaf, ei, trans->transid); + btrfs_set_file_extent_type(leaf, ei, BTRFS_FILE_EXTENT_INLINE); + btrfs_set_file_extent_ram_bytes(leaf, ei, size); + btrfs_set_file_extent_compression(leaf, ei, 0); + btrfs_set_file_extent_encryption(leaf, ei, 0); + btrfs_set_file_extent_other_encoding(leaf, ei, 0); - leaf = path->nodes[0]; - ei = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - - if (btrfs_file_extent_type(leaf, ei) != - BTRFS_FILE_EXTENT_INLINE) { - err = ret; - btrfs_print_leaf(root, leaf); - printk("found wasn't inline offset %llu inode %llu\n", - (unsigned long long)offset, - (unsigned long long)objectid); - goto fail; - } - found_size = btrfs_file_extent_inline_len(leaf, ei); - found_end = key.offset + found_size; - - if (found_end < offset + size) { - btrfs_release_path(root, path); - ret = btrfs_search_slot(trans, root, &key, path, - offset + size - found_end, 1); - BUG_ON(ret != 0); - - ret = btrfs_extend_item(trans, root, path, - offset + size - found_end); - if (ret) { - err = ret; - goto fail; - } - leaf = path->nodes[0]; - ei = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - } - if (found_end < offset) { - ptr = btrfs_file_extent_inline_start(ei) + found_size; - memset_extent_buffer(leaf, 0, ptr, offset - found_end); - } - } else { -insert: - btrfs_release_path(root, path); - datasize = offset + size - key.offset; - datasize = btrfs_file_extent_calc_inline_size(datasize); - ret = btrfs_insert_empty_item(trans, root, path, &key, - datasize); - if (ret) { - err = ret; - printk("got bad ret %d\n", ret); - goto fail; - } - leaf = path->nodes[0]; - ei = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - btrfs_set_file_extent_generation(leaf, ei, trans->transid); - btrfs_set_file_extent_type(leaf, ei, BTRFS_FILE_EXTENT_INLINE); - } ptr = btrfs_file_extent_inline_start(ei) + offset - key.offset; write_extent_buffer(leaf, buffer, ptr, size); btrfs_mark_buffer_dirty(leaf); @@ -192,7 +121,7 @@ fail: struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, - u64 objectid, u64 offset, int cow) + u64 bytenr, int cow) { int ret; struct btrfs_key file_key; @@ -200,13 +129,13 @@ struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans, struct btrfs_csum_item *item; struct extent_buffer *leaf; u64 csum_offset = 0; - int csums_in_item; u16 csum_size = btrfs_super_csum_size(&root->fs_info->super_copy); + int csums_in_item; - file_key.objectid = objectid; - file_key.offset = offset; - btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY); + file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; + file_key.offset = bytenr; + btrfs_set_key_type(&file_key, BTRFS_EXTENT_CSUM_KEY); ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow); if (ret < 0) goto fail; @@ -217,11 +146,10 @@ struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans, goto fail; path->slots[0]--; btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); - if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY || - found_key.objectid != objectid) { + if (btrfs_key_type(&found_key) != BTRFS_EXTENT_CSUM_KEY) goto fail; - } - csum_offset = (offset - found_key.offset) >> root->sectorsize; + + csum_offset = (bytenr - found_key.offset) / root->sectorsize; csums_in_item = btrfs_item_size_nr(leaf, path->slots[0]); csums_in_item /= csum_size; @@ -240,7 +168,6 @@ fail: return ERR_PTR(ret); } - int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 objectid, @@ -259,10 +186,8 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, } int btrfs_csum_file_block(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_inode_item *inode, - u64 objectid, u64 offset, - char *data, size_t len) + struct btrfs_root *root, u64 alloc_end, + u64 bytenr, char *data, size_t len) { int ret; struct btrfs_key file_key; @@ -282,11 +207,11 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans, path = btrfs_alloc_path(); BUG_ON(!path); - file_key.objectid = objectid; - file_key.offset = offset; - btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY); + file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; + file_key.offset = bytenr; + file_key.type = BTRFS_EXTENT_CSUM_KEY; - item = btrfs_lookup_csum(trans, root, path, objectid, offset, 1); + item = btrfs_lookup_csum(trans, root, path, bytenr, 1); if (!IS_ERR(item)) { leaf = path->nodes[0]; goto found; @@ -314,8 +239,8 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans, slot = 0; } btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot); - if (found_key.objectid != objectid || - found_key.type != BTRFS_CSUM_ITEM_KEY) { + if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || + found_key.type != BTRFS_EXTENT_CSUM_KEY) { found_next = 1; goto insert; } @@ -342,9 +267,9 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans, path->slots[0]--; leaf = path->nodes[0]; btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); - csum_offset = (offset - found_key.offset) / root->sectorsize; - if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY || - found_key.objectid != objectid || + csum_offset = (file_key.offset - found_key.offset) / root->sectorsize; + if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || + found_key.type != BTRFS_EXTENT_CSUM_KEY || csum_offset >= MAX_CSUM_ITEMS(root, csum_size)) { goto insert; } @@ -363,8 +288,8 @@ insert: btrfs_release_path(root, path); csum_offset = 0; if (found_next) { - u64 tmp = min(btrfs_stack_inode_size(inode), next_offset); - tmp -= offset & ~((u64)root->sectorsize -1); + u64 tmp = min(alloc_end, next_offset); + tmp -= file_key.offset; tmp /= root->sectorsize; tmp = max((u64)1, tmp); tmp = min(tmp, (u64)MAX_CSUM_ITEMS(root, csum_size)); @@ -390,9 +315,8 @@ found: csum_result = btrfs_csum_data(root, data, csum_result, len); btrfs_csum_final(csum_result, (char *)&csum_result); if (csum_result == 0) { - printk("csum result is 0 for inode %llu offset %llu\n", - (unsigned long long)objectid, - (unsigned long long)offset); + printk("csum result is 0 for block %llu\n", + (unsigned long long)bytenr); } write_extent_buffer(leaf, &csum_result, (unsigned long)item, @@ -404,28 +328,175 @@ fail: return ret; } -int btrfs_csum_truncate(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct btrfs_path *path, - u64 isize) +/* + * helper function for csum removal, this expects the + * key to describe the csum pointed to by the path, and it expects + * the csum to overlap the range [bytenr, len] + * + * The csum should not be entirely contained in the range and the + * range should not be entirely contained in the csum. + * + * This calls btrfs_truncate_item with the correct args based on the + * overlap, and fixes up the key as required. + */ +static noinline int truncate_one_csum(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + struct btrfs_path *path, + struct btrfs_key *key, + u64 bytenr, u64 len) +{ + struct extent_buffer *leaf; + u16 csum_size = + btrfs_super_csum_size(&root->fs_info->super_copy); + u64 csum_end; + u64 end_byte = bytenr + len; + u32 blocksize = root->sectorsize; + int ret; + + leaf = path->nodes[0]; + csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size; + csum_end *= root->sectorsize; + csum_end += key->offset; + + if (key->offset < bytenr && csum_end <= end_byte) { + /* + * [ bytenr - len ] + * [ ] + * [csum ] + * A simple truncate off the end of the item + */ + u32 new_size = (bytenr - key->offset) / blocksize; + new_size *= csum_size; + ret = btrfs_truncate_item(trans, root, path, new_size, 1); + BUG_ON(ret); + } else if (key->offset >= bytenr && csum_end > end_byte && + end_byte > key->offset) { + /* + * [ bytenr - len ] + * [ ] + * [csum ] + * we need to truncate from the beginning of the csum + */ + u32 new_size = (csum_end - end_byte) / blocksize; + new_size *= csum_size; + + ret = btrfs_truncate_item(trans, root, path, new_size, 0); + BUG_ON(ret); + + key->offset = end_byte; + ret = btrfs_set_item_key_safe(trans, root, path, key); + BUG_ON(ret); + } else { + BUG(); + } + return 0; +} + +/* + * deletes the csum items from the csum tree for a given + * range of bytes. + */ +int btrfs_del_csums(struct btrfs_trans_handle *trans, + struct btrfs_root *root, u64 bytenr, u64 len) { + struct btrfs_path *path; struct btrfs_key key; - struct extent_buffer *leaf = path->nodes[0]; - int slot = path->slots[0]; + u64 end_byte = bytenr + len; + u64 csum_end; + struct extent_buffer *leaf; int ret; - u32 new_item_size; - u64 new_item_span; - u64 blocks; - - btrfs_item_key_to_cpu(leaf, &key, slot); - if (isize <= key.offset) - return 0; - new_item_span = isize - key.offset; - blocks = (new_item_span + root->sectorsize - 1) / root->sectorsize; - new_item_size = blocks * - btrfs_super_csum_size(&root->fs_info->super_copy); - if (new_item_size >= btrfs_item_size_nr(leaf, slot)) - return 0; - ret = btrfs_truncate_item(trans, root, path, new_item_size, 1); - BUG_ON(ret); - return ret; + u16 csum_size = + btrfs_super_csum_size(&root->fs_info->super_copy); + int blocksize = root->sectorsize; + + root = root->fs_info->csum_root; + + path = btrfs_alloc_path(); + + while (1) { + key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; + key.offset = end_byte - 1; + key.type = BTRFS_EXTENT_CSUM_KEY; + + ret = btrfs_search_slot(trans, root, &key, path, -1, 1); + if (ret > 0) { + if (path->slots[0] == 0) + goto out; + path->slots[0]--; + } + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); + + if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || + key.type != BTRFS_EXTENT_CSUM_KEY) { + break; + } + + if (key.offset >= end_byte) + break; + + csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size; + csum_end *= blocksize; + csum_end += key.offset; + + /* this csum ends before we start, we're done */ + if (csum_end <= bytenr) + break; + + /* delete the entire item, it is inside our range */ + if (key.offset >= bytenr && csum_end <= end_byte) { + ret = btrfs_del_item(trans, root, path); + BUG_ON(ret); + } else if (key.offset < bytenr && csum_end > end_byte) { + unsigned long offset; + unsigned long shift_len; + unsigned long item_offset; + /* + * [ bytenr - len ] + * [csum ] + * + * Our bytes are in the middle of the csum, + * we need to split this item and insert a new one. + * + * But we can't drop the path because the + * csum could change, get removed, extended etc. + * + * The trick here is the max size of a csum item leaves + * enough room in the tree block for a single + * item header. So, we split the item in place, + * adding a new header pointing to the existing + * bytes. Then we loop around again and we have + * a nicely formed csum item that we can neatly + * truncate. + */ + offset = (bytenr - key.offset) / blocksize; + offset *= csum_size; + + shift_len = (len / blocksize) * csum_size; + + item_offset = btrfs_item_ptr_offset(leaf, + path->slots[0]); + + memset_extent_buffer(leaf, 0, item_offset + offset, + shift_len); + key.offset = bytenr; + + /* + * btrfs_split_item returns -EAGAIN when the + * item changed size or key + */ + ret = btrfs_split_item(trans, root, path, &key, offset); + BUG_ON(ret && ret != -EAGAIN); + + key.offset = end_byte - 1; + } else { + ret = truncate_one_csum(trans, root, path, + &key, bytenr, len); + BUG_ON(ret); + } + btrfs_release_path(root, path); + } +out: + btrfs_free_path(path); + return 0; } @@ -125,7 +125,7 @@ static int make_root_dir(struct btrfs_root *root) ret = btrfs_insert_dir_item(trans, root->fs_info->tree_root, "default", 7, btrfs_super_root_dir(&root->fs_info->super_copy), - &location, BTRFS_FT_DIR); + &location, BTRFS_FT_DIR, 0); if (ret) goto err; diff --git a/root-tree.c b/root-tree.c index 189f82d2..782472ca 100644 --- a/root-tree.c +++ b/root-tree.c @@ -201,3 +201,53 @@ out: btrfs_free_path(path); return ret; } + +/* + * add a btrfs_root_ref item. type is either BTRFS_ROOT_REF_KEY + * or BTRFS_ROOT_BACKREF_KEY. + * + * The dirid, sequence, name and name_len refer to the directory entry + * that is referencing the root. + * + * For a forward ref, the root_id is the id of the tree referencing + * the root and ref_id is the id of the subvol or snapshot. + * + * For a back ref the root_id is the id of the subvol or snapshot and + * ref_id is the id of the tree referencing it. + */ +int btrfs_add_root_ref(struct btrfs_trans_handle *trans, + struct btrfs_root *tree_root, + u64 root_id, u8 type, u64 ref_id, + u64 dirid, u64 sequence, + const char *name, int name_len) +{ + struct btrfs_key key; + int ret; + struct btrfs_path *path; + struct btrfs_root_ref *ref; + struct extent_buffer *leaf; + unsigned long ptr; + + + path = btrfs_alloc_path(); + + key.objectid = root_id; + key.type = type; + key.offset = ref_id; + + ret = btrfs_insert_empty_item(trans, tree_root, path, &key, + sizeof(*ref) + name_len); + BUG_ON(ret); + + leaf = path->nodes[0]; + ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_ref); + btrfs_set_root_ref_dirid(leaf, ref, dirid); + btrfs_set_root_ref_sequence(leaf, ref, sequence); + btrfs_set_root_ref_name_len(leaf, ref, name_len); + ptr = (unsigned long)(ref + 1); + write_extent_buffer(leaf, name, ptr, name_len); + btrfs_mark_buffer_dirty(leaf); + + btrfs_free_path(path); + return ret; +} @@ -491,6 +491,7 @@ int btrfs_add_to_fsid(struct btrfs_trans_handle *trans, printf("adding device %s id %llu\n", path, (unsigned long long)device->devid); + btrfs_set_super_bytenr(disk_super, BTRFS_SUPER_INFO_OFFSET); btrfs_set_stack_device_id(dev_item, device->devid); btrfs_set_stack_device_type(dev_item, device->type); btrfs_set_stack_device_io_align(dev_item, device->io_align); @@ -210,15 +210,10 @@ int btrfs_scan_one_device(int fd, const char *path, ret = -ENOMEM; goto error; } - ret = pread(fd, buf, 4096, super_offset); - if (ret != 4096) { - ret = -EIO; - goto error; - } disk_super = (struct btrfs_super_block *)buf; - if (strncmp((char *)(&disk_super->magic), BTRFS_MAGIC, - sizeof(disk_super->magic))) { - ret = -ENOENT; + ret = btrfs_read_dev_super(fd, disk_super, super_offset); + if (ret < 0) { + ret = -EIO; goto error_brelse; } devid = le64_to_cpu(disk_super->dev_item.devid); @@ -902,10 +897,10 @@ int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree, int i, j, nr = 0; ce = find_first_cache_extent(&map_tree->cache_tree, chunk_start); - BUG_ON(!ce || ce->start != chunk_start); + BUG_ON(!ce); map = container_of(ce, struct map_lookup, ce); - length = ce->size; + length = ce->size; if (map->type & BTRFS_BLOCK_GROUP_RAID10) length = ce->size / (map->num_stripes / map->sub_stripes); else if (map->type & BTRFS_BLOCK_GROUP_RAID0) @@ -929,7 +924,7 @@ int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree, } else if (map->type & BTRFS_BLOCK_GROUP_RAID0) { stripe_nr = stripe_nr * map->num_stripes + i; } - bytenr = chunk_start + stripe_nr * map->stripe_len; + bytenr = ce->start + stripe_nr * map->stripe_len; for (j = 0; j < nr; j++) { if (buf[j] == bytenr) break; @@ -1328,7 +1323,7 @@ int btrfs_read_super_device(struct btrfs_root *root, struct extent_buffer *buf) int btrfs_read_sys_array(struct btrfs_root *root) { struct btrfs_super_block *super_copy = &root->fs_info->super_copy; - struct extent_buffer *sb = root->fs_info->sb_buffer; + struct extent_buffer *sb; struct btrfs_disk_key *disk_key; struct btrfs_chunk *chunk; struct btrfs_key key; @@ -1340,6 +1335,12 @@ int btrfs_read_sys_array(struct btrfs_root *root) u32 cur; int ret; + sb = btrfs_find_create_tree_block(root, BTRFS_SUPER_INFO_OFFSET, + BTRFS_SUPER_INFO_SIZE); + if (!sb) + return -ENOMEM; + btrfs_set_buffer_uptodate(sb); + write_extent_buffer(sb, super_copy, 0, BTRFS_SUPER_INFO_SIZE); array_size = btrfs_super_sys_array_size(super_copy); /* @@ -1373,6 +1374,7 @@ int btrfs_read_sys_array(struct btrfs_root *root) sb_ptr += len; cur += len; } + free_extent_buffer(sb); return 0; } |