From patchwork Sat Mar 20 04:24:49 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sean Bartell X-Patchwork-Id: 87070 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o2K4OpdX006341 for ; Sat, 20 Mar 2010 04:24:51 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751131Ab0CTEYu (ORCPT ); Sat, 20 Mar 2010 00:24:50 -0400 Received: from mail-gw0-f46.google.com ([74.125.83.46]:42683 "EHLO mail-gw0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751020Ab0CTEYt (ORCPT ); Sat, 20 Mar 2010 00:24:49 -0400 Received: by gwaa18 with SMTP id a18so128962gwa.19 for ; Fri, 19 Mar 2010 21:24:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:date:from:to:subject :message-id:mail-followup-to:mime-version:content-type :content-disposition:user-agent; bh=Him78u2ldt1VKZDB0jyrMpa5apUF3P+LY7SrCBl91ig=; b=aJrkYIKTEquyUsHGGcj0lJ89ZncApRBQcntDFNH2gsY15W+QZmYMn419OtleprMqEM SuDPsppGU5tYhoPBkjNCNGEvyQ2XqrT8x938sKi6dgmtwaNz7+x3eQ9HMdRnXxEhUwXl TJ10IS6uGN4bhSXjRCc8H4sdlKfpSC+ln48tY= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=date:from:to:subject:message-id:mail-followup-to:mime-version :content-type:content-disposition:user-agent; b=ARyj3xW8+l49bSL7InbFQZ0zuN5ockzCzPDJT2hLu1ieFLDnh3yG3tqu7Qtfcyn0cw SPSAELRT9QRnT2Z0aBK3T94+cWxCnWkpZSSEzzFQvH5fo0p1u++2XXr2SjqPWhV+8Rid IIVg5R14L5ICVPexgX4Ys5LxQHSoa1H+ozAl8= Received: by 10.101.66.3 with SMTP id t3mr9187385ank.171.1269059088510; Fri, 19 Mar 2010 21:24:48 -0700 (PDT) Received: from flcl.lan (cpe-065-190-001-228.nc.res.rr.com [65.190.1.228]) by mx.google.com with ESMTPS id 5sm679191yxg.28.2010.03.19.21.24.46 (version=TLSv1/SSLv3 cipher=RC4-MD5); Fri, 19 Mar 2010 21:24:47 -0700 (PDT) Date: Sat, 20 Mar 2010 00:24:49 -0400 From: Sean Bartell To: linux-btrfs@vger.kernel.org Subject: [PATCH 1/4] btrfs-convert: make more use of cache_free_extents Message-ID: <20100320042449.GA17083@flcl.lan> Mail-Followup-To: linux-btrfs@vger.kernel.org MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.20 (2009-06-14) Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Sat, 20 Mar 2010 04:24:52 +0000 (UTC) diff --git a/convert.c b/convert.c index d037c98..c48f8ba 100644 --- a/convert.c +++ b/convert.c @@ -95,29 +95,10 @@ static int close_ext2fs(ext2_filsys fs) return 0; } -static int ext2_alloc_block(ext2_filsys fs, u64 goal, u64 *block_ret) +static int ext2_cache_free_extents(ext2_filsys ext2_fs, + struct extent_io_tree *free_tree) { - blk_t block; - - if (!ext2fs_new_block(fs, goal, NULL, &block)) { - ext2fs_fast_mark_block_bitmap(fs->block_map, block); - *block_ret = block; - return 0; - } - return -ENOSPC; -} - -static int ext2_free_block(ext2_filsys fs, u64 block) -{ - BUG_ON(block != (blk_t)block); - ext2fs_fast_unmark_block_bitmap(fs->block_map, block); - return 0; -} - -static int cache_free_extents(struct btrfs_root *root, ext2_filsys ext2_fs) - -{ - int i, ret = 0; + int ret = 0; blk_t block; u64 bytenr; u64 blocksize = ext2_fs->blocksize; @@ -127,29 +108,68 @@ static int cache_free_extents(struct btrfs_root *root, ext2_filsys ext2_fs) if (ext2fs_fast_test_block_bitmap(ext2_fs->block_map, block)) continue; bytenr = block * blocksize; - ret = set_extent_dirty(&root->fs_info->free_space_cache, - bytenr, bytenr + blocksize - 1, 0); + ret = set_extent_dirty(free_tree, bytenr, + bytenr + blocksize - 1, 0); BUG_ON(ret); } + return 0; +} + +/* mark btrfs-reserved blocks as used */ +static void adjust_free_extents(ext2_filsys ext2_fs, + struct extent_io_tree *free_tree) +{ + int i; + u64 bytenr; + u64 blocksize = ext2_fs->blocksize; + + clear_extent_dirty(free_tree, 0, BTRFS_SUPER_INFO_OFFSET - 1, 0); + 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); + clear_extent_dirty(free_tree, bytenr, bytenr + STRIPE_LEN - 1, + 0); } +} - clear_extent_dirty(&root->fs_info->free_space_cache, - 0, BTRFS_SUPER_INFO_OFFSET - 1, 0); - +static int alloc_blocks(struct extent_io_tree *free_tree, + u64 *blocks, int num, u64 blocksize) +{ + u64 start; + u64 end; + u64 last = 0; + u64 mask = blocksize - 1; + int ret; + while(num) { + ret = find_first_extent_bit(free_tree, last, &start, &end, + EXTENT_DIRTY); + if (ret) + goto fail; + last = end + 1; + if (start & mask) + start = (start & mask) + blocksize; + if (last - start < blocksize) + continue; + *blocks++ = start; + num--; + last = start + blocksize; + clear_extent_dirty(free_tree, start, last - 1, 0); + } return 0; +fail: + fprintf(stderr, "not enough free space\n"); + return -ENOSPC; } static int custom_alloc_extent(struct btrfs_root *root, u64 num_bytes, u64 hint_byte, struct btrfs_key *ins) { + u64 blocksize = root->sectorsize; + u64 mask = blocksize - 1; u64 start; u64 end; u64 last = hint_byte; @@ -171,6 +191,8 @@ static int custom_alloc_extent(struct btrfs_root *root, u64 num_bytes, start = max(last, start); last = end + 1; + if (start & mask) + start = (start & mask) + blocksize; if (last - start < num_bytes) continue; @@ -1186,9 +1208,9 @@ static int create_image_file_range(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 objectid, struct btrfs_inode_item *inode, u64 start_byte, u64 end_byte, - ext2_filsys ext2_fs) + struct extent_io_tree *orig_free_tree) { - u32 blocksize = ext2_fs->blocksize; + u32 blocksize = root->sectorsize; u32 block = start_byte / blocksize; u32 last_block = (end_byte + blocksize - 1) / blocksize; int ret = 0; @@ -1205,7 +1227,8 @@ static int create_image_file_range(struct btrfs_trans_handle *trans, .errcode = 0, }; for (; start_byte < end_byte; block++, start_byte += blocksize) { - if (!ext2fs_fast_test_block_bitmap(ext2_fs->block_map, block)) + if (test_range_bit(orig_free_tree, start_byte, + start_byte + blocksize, EXTENT_DIRTY, 1)) continue; ret = block_iterate_proc(NULL, block, block, &data); if (ret & BLOCK_ABORT) { @@ -1234,8 +1257,8 @@ fail: /* * Create the ext2fs image file. */ -static int create_ext2_image(struct btrfs_root *root, ext2_filsys ext2_fs, - const char *name) +static int create_ext2_image(struct btrfs_root *root, const char *name, + struct extent_io_tree *orig_free_tree) { int ret; struct btrfs_key key; @@ -1348,7 +1371,7 @@ next: if (bytenr > last_byte) { ret = create_image_file_range(trans, root, objectid, &btrfs_inode, last_byte, - bytenr, ext2_fs); + bytenr, orig_free_tree); if (ret) goto fail; } @@ -1370,7 +1393,7 @@ next: if (total_bytes > last_byte) { ret = create_image_file_range(trans, root, objectid, &btrfs_inode, last_byte, - total_bytes, ext2_fs); + total_bytes, orig_free_tree); if (ret) goto fail; } @@ -2332,9 +2355,23 @@ err: return ret; } +static int copy_dirtiness(struct extent_io_tree *out, + struct extent_io_tree *in) +{ + int ret; + u64 start, end, last = 0; + while (!find_first_extent_bit(in, last, &start, &end, EXTENT_DIRTY)) { + ret = set_extent_dirty(out, start, end, 0); + if (ret) + return ret; + last = end + 1; + } + return 0; +} + int do_convert(const char *devname, int datacsum, int packing, int noxattr) { - int i, fd, ret; + int fd, ret; u32 blocksize; u64 blocks[7]; u64 total_bytes; @@ -2342,7 +2379,11 @@ int do_convert(const char *devname, int datacsum, int packing, int noxattr) ext2_filsys ext2_fs; struct btrfs_root *root; struct btrfs_root *ext2_root; + struct extent_io_tree free_tree; + struct extent_io_tree orig_free_tree; + extent_io_tree_init(&free_tree); + extent_io_tree_init(&orig_free_tree); ret = open_ext2fs(devname, &ext2_fs); if (ret) { fprintf(stderr, "unable to open the Ext2fs\n"); @@ -2359,13 +2400,23 @@ int do_convert(const char *devname, int datacsum, int packing, int noxattr) fprintf(stderr, "filetype feature is missing\n"); goto fail; } - for (i = 0; i < 7; i++) { - ret = ext2_alloc_block(ext2_fs, 0, blocks + i); - if (ret) { - fprintf(stderr, "not enough free space\n"); - goto fail; - } - blocks[i] *= blocksize; + ret = ext2_cache_free_extents(ext2_fs, &orig_free_tree); + if (ret) { + fprintf(stderr, "error during cache_free_extents %d\n", ret); + goto fail; + } + /* preserve first 64KiB, just in case */ + clear_extent_dirty(&orig_free_tree, 0, BTRFS_SUPER_INFO_OFFSET - 1, 0); + + ret = copy_dirtiness(&free_tree, &orig_free_tree); + if (ret) { + fprintf(stderr, "error during copy_dirtiness %d\n", ret); + goto fail; + } + adjust_free_extents(ext2_fs, &free_tree); + ret = alloc_blocks(&free_tree, blocks, 7, blocksize); + if (ret) { + goto fail; } super_bytenr = blocks[0]; fd = open(devname, O_RDWR); @@ -2391,17 +2442,9 @@ int do_convert(const char *devname, int datacsum, int packing, int noxattr) fprintf(stderr, "unable to open ctree\n"); goto fail; } - ret = cache_free_extents(root, ext2_fs); - if (ret) { - fprintf(stderr, "error during cache_free_extents %d\n", ret); - goto fail; - } + copy_dirtiness(&root->fs_info->free_space_cache, &free_tree); + extent_io_tree_cleanup(&free_tree); root->fs_info->extent_ops = &extent_ops; - /* recover block allocation bitmap */ - for (i = 0; i < 7; i++) { - blocks[i] /= blocksize; - ext2_free_block(ext2_fs, blocks[i]); - } ret = init_btrfs(root); if (ret) { fprintf(stderr, "unable to setup the root tree\n"); @@ -2419,11 +2462,12 @@ int do_convert(const char *devname, int datacsum, int packing, int noxattr) fprintf(stderr, "unable to create subvol\n"); goto fail; } - ret = create_ext2_image(ext2_root, ext2_fs, "image"); + ret = create_ext2_image(ext2_root, "image", &orig_free_tree); if (ret) { fprintf(stderr, "error during create_ext2_image %d\n", ret); goto fail; } + extent_io_tree_cleanup(&orig_free_tree); printf("cleaning up system chunk.\n"); ret = cleanup_sys_chunk(root, ext2_root); if (ret) {