From patchwork Sat Apr 30 14:23:58 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hugo Mills X-Patchwork-Id: 743642 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter2.kernel.org (8.14.4/8.14.3) with ESMTP id p3UEOOUH020003 for ; Sat, 30 Apr 2011 14:24:24 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755115Ab1D3OYS (ORCPT ); Sat, 30 Apr 2011 10:24:18 -0400 Received: from frost.carfax.org.uk ([212.13.194.111]:4418 "EHLO frost.carfax.org.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753677Ab1D3OYL (ORCPT ); Sat, 30 Apr 2011 10:24:11 -0400 Received: from ruthven.carfax.org.uk ([10.0.0.10]) by frost.carfax.org.uk with esmtp (Exim 4.69) (envelope-from ) id 1QGB5Y-0005h6-L4; Sat, 30 Apr 2011 14:24:08 +0000 Received: from [10.0.0.10] (helo=ruthven.carfax.org.uk) by ruthven.carfax.org.uk with esmtp (Exim 4.72) (envelope-from ) id 1QGB5Y-0007ay-D3; Sat, 30 Apr 2011 15:24:04 +0100 From: Hugo Mills To: Btrfs mailing list , Chris Mason , David Sterba Subject: [PATCH v6 3/8] btrfs: Factor out enumeration of chunks to a separate function Date: Sat, 30 Apr 2011 15:23:58 +0100 Message-Id: <1304173443-29159-4-git-send-email-hugo@carfax.org.uk> X-Mailer: git-send-email 1.7.2.5 In-Reply-To: <1304173443-29159-1-git-send-email-hugo@carfax.org.uk> References: <1304173443-29159-1-git-send-email-hugo@carfax.org.uk> X-frost.carfax.org.uk-Spam-Score: -0.0 (/) X-frost.carfax.org.uk-Spam-Report: Spam detection software, running on the system "spamd0.lon.bitfolk.com", has identified this incoming email as possible spam. The original message has been attached to this so you can view it (if it isn't spam) or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: The main balance function has two loops which are functionally identical in their looping mechanism, but which perform a different operation on the chunks they loop over. To avoid repeating code more than necessary, factor this loop out into a separate iterator function which takes a function parameter for the action to be performed. [...] Content analysis details: (-0.0 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 T_RP_MATCHES_RCVD Envelope sender domain matches handover relay domain 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.6 (demeter2.kernel.org [140.211.167.43]); Sat, 30 Apr 2011 14:24:24 +0000 (UTC) The main balance function has two loops which are functionally identical in their looping mechanism, but which perform a different operation on the chunks they loop over. To avoid repeating code more than necessary, factor this loop out into a separate iterator function which takes a function parameter for the action to be performed. Signed-off-by: Hugo Mills --- fs/btrfs/volumes.c | 174 +++++++++++++++++++++++++++++---------------------- 1 files changed, 99 insertions(+), 75 deletions(-) diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 07ff192..fabd006 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2020,6 +2020,97 @@ static u64 div_factor(u64 num, int factor) return num; } +/* Define a type, and two functions which can be used for the two + * phases of the balance operation: one for counting chunks, and one + * for actually moving them. */ +typedef void (*balance_iterator_function)(struct btrfs_root *, + struct btrfs_balance_info *, + struct btrfs_path *, + struct btrfs_key *); + +static void balance_count_chunks(struct btrfs_root *chunk_root, + struct btrfs_balance_info *bal_info, + struct btrfs_path *path, + struct btrfs_key *key) +{ + spin_lock(&chunk_root->fs_info->balance_info_lock); + bal_info->expected++; + spin_unlock(&chunk_root->fs_info->balance_info_lock); +} + +static void balance_move_chunks(struct btrfs_root *chunk_root, + struct btrfs_balance_info *bal_info, + struct btrfs_path *path, + struct btrfs_key *key) +{ + int ret; + + ret = btrfs_relocate_chunk(chunk_root, + chunk_root->root_key.objectid, + key->objectid, + key->offset); + BUG_ON(ret && ret != -ENOSPC); + spin_lock(&chunk_root->fs_info->balance_info_lock); + bal_info->completed++; + spin_unlock(&chunk_root->fs_info->balance_info_lock); + printk(KERN_INFO "btrfs: balance: %u/%u block groups completed\n", + bal_info->completed, bal_info->expected); +} + +/* Iterate through all chunks, performing some function on each one. */ +static int balance_iterate_chunks(struct btrfs_root *chunk_root, + struct btrfs_balance_info *bal_info, + balance_iterator_function iterator_fn) +{ + int ret = 0; + struct btrfs_path *path; + struct btrfs_key key; + struct btrfs_key found_key; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID; + key.offset = (u64)-1; + key.type = BTRFS_CHUNK_ITEM_KEY; + + while (!bal_info->cancel_pending) { + ret = btrfs_search_slot(NULL, chunk_root, &key, path, 0, 0); + if (ret < 0) + break; + /* + * this shouldn't happen, it means the last relocate + * failed + */ + if (ret == 0) + break; + + ret = btrfs_previous_item(chunk_root, path, 0, + BTRFS_CHUNK_ITEM_KEY); + if (ret) + break; + + btrfs_item_key_to_cpu(path->nodes[0], &found_key, + path->slots[0]); + if (found_key.objectid != key.objectid) + break; + + /* chunk zero is special */ + if (found_key.offset == 0) + break; + + /* Call the function to do the work for this chunk */ + btrfs_release_path(chunk_root, path); + iterator_fn(chunk_root, bal_info, path, &found_key); + + key.offset = found_key.offset - 1; + } + + btrfs_free_path(path); + return ret; +} + int btrfs_balance(struct btrfs_root *dev_root) { int ret; @@ -2027,11 +2118,8 @@ int btrfs_balance(struct btrfs_root *dev_root) struct btrfs_device *device; u64 old_size; u64 size_to_free; - struct btrfs_path *path; - struct btrfs_key key; struct btrfs_root *chunk_root = dev_root->fs_info->chunk_root; struct btrfs_trans_handle *trans; - struct btrfs_key found_key; struct btrfs_balance_info *bal_info; if (dev_root->fs_info->sb->s_flags & MS_RDONLY) @@ -2052,8 +2140,7 @@ int btrfs_balance(struct btrfs_root *dev_root) } spin_lock(&dev_root->fs_info->balance_info_lock); dev_root->fs_info->balance_info = bal_info; - bal_info->expected = -1; /* One less than actually counted, - because chunk 0 is special */ + bal_info->expected = 0; bal_info->completed = 0; bal_info->cancel_pending = 0; spin_unlock(&dev_root->fs_info->balance_info_lock); @@ -2082,86 +2169,23 @@ int btrfs_balance(struct btrfs_root *dev_root) } /* step two, count the chunks */ - path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; + ret = balance_iterate_chunks(chunk_root, bal_info, + balance_count_chunks); + if (ret) goto error; - } - - key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID; - key.offset = (u64)-1; - key.type = BTRFS_CHUNK_ITEM_KEY; - - ret = btrfs_search_slot(NULL, chunk_root, &key, path, 0, 0); - if (ret <= 0) { - printk(KERN_ERR "btrfs: Failed to find the last chunk.\n"); - BUG(); - } - - while (1) { - ret = btrfs_previous_item(chunk_root, path, 0, - BTRFS_CHUNK_ITEM_KEY); - if (ret) - break; - - spin_lock(&dev_root->fs_info->balance_info_lock); - bal_info->expected++; - spin_unlock(&dev_root->fs_info->balance_info_lock); - } - - btrfs_release_path(chunk_root, path); /* step three, relocate all the chunks */ - key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID; - key.offset = (u64)-1; - key.type = BTRFS_CHUNK_ITEM_KEY; - - while (!bal_info->cancel_pending) { - ret = btrfs_search_slot(NULL, chunk_root, &key, path, 0, 0); - if (ret < 0) - goto error; - - /* - * this shouldn't happen, it means the last relocate - * failed - */ - if (ret == 0) - break; - - ret = btrfs_previous_item(chunk_root, path, 0, - BTRFS_CHUNK_ITEM_KEY); - if (ret) - break; - - btrfs_item_key_to_cpu(path->nodes[0], &found_key, - path->slots[0]); - if (found_key.objectid != key.objectid) - break; - - /* chunk zero is special */ - if (found_key.offset == 0) - break; + ret = balance_iterate_chunks(chunk_root, bal_info, + balance_move_chunks); + if (ret) + goto error; - btrfs_release_path(chunk_root, path); - ret = btrfs_relocate_chunk(chunk_root, - chunk_root->root_key.objectid, - found_key.objectid, - found_key.offset); - BUG_ON(ret && ret != -ENOSPC); - key.offset = found_key.offset - 1; - spin_lock(&dev_root->fs_info->balance_info_lock); - bal_info->completed++; - spin_unlock(&dev_root->fs_info->balance_info_lock); - printk(KERN_INFO "btrfs: balance: %u/%u block groups completed\n", - bal_info->completed, bal_info->expected); - } ret = 0; if (bal_info->cancel_pending) { printk(KERN_INFO "btrfs: balance cancelled\n"); ret = -EINTR; } error: - btrfs_free_path(path); spin_lock(&dev_root->fs_info->balance_info_lock); kfree(dev_root->fs_info->balance_info); dev_root->fs_info->balance_info = NULL;