From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from cn.fujitsu.com ([59.151.112.132]:29187 "EHLO heian.cn.fujitsu.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1750939AbdBTG1H (ORCPT ); Mon, 20 Feb 2017 01:27:07 -0500 Subject: Re: [PATCH 3/7] Btrfs: introduce a function to get extra mirror from replace To: Liu Bo , References: <1487381301-865-1-git-send-email-bo.li.liu@oracle.com> <1487381301-865-4-git-send-email-bo.li.liu@oracle.com> CC: David Sterba From: Qu Wenruo Message-ID: <7ed1bfd8-d50e-14a0-bc2e-e0c83e98db60@cn.fujitsu.com> Date: Mon, 20 Feb 2017 14:26:58 +0800 MIME-Version: 1.0 In-Reply-To: <1487381301-865-4-git-send-email-bo.li.liu@oracle.com> Content-Type: text/plain; charset="utf-8"; format=flowed Sender: linux-btrfs-owner@vger.kernel.org List-ID: At 02/18/2017 09:28 AM, Liu Bo wrote: > As the part of getting extra mirror in __btrfs_map_block is > self-independent, this puts it into a separate function. > > Signed-off-by: Liu Bo Looks good to me. Reviewed-by: Qu Wenruo Thanks, Qu > --- > fs/btrfs/volumes.c | 161 +++++++++++++++++++++++++++++------------------------ > 1 file changed, 89 insertions(+), 72 deletions(-) > > diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c > index 96228f3..f62efc7 100644 > --- a/fs/btrfs/volumes.c > +++ b/fs/btrfs/volumes.c > @@ -140,6 +140,11 @@ static int btrfs_relocate_sys_chunks(struct btrfs_fs_info *fs_info); > static void __btrfs_reset_dev_stats(struct btrfs_device *dev); > static void btrfs_dev_stat_print_on_error(struct btrfs_device *dev); > static void btrfs_dev_stat_print_on_load(struct btrfs_device *device); > +static int __btrfs_map_block(struct btrfs_fs_info *fs_info, > + enum btrfs_map_op op, > + u64 logical, u64 *length, > + struct btrfs_bio **bbio_ret, > + int mirror_num, int need_raid_map); > > DEFINE_MUTEX(uuid_mutex); > static LIST_HEAD(fs_uuids); > @@ -5463,6 +5468,83 @@ static int __btrfs_map_block_for_discard(struct btrfs_fs_info *fs_info, > return ret; > } > > +/* > + * In dev-replace case, for repair case (that's the only case where the mirror > + * is selected explicitly when calling btrfs_map_block), blocks left of the > + * left cursor can also be read from the target drive. > + * > + * For REQ_GET_READ_MIRRORS, the target drive is added as the last one to the > + * array of stripes. > + * For READ, it also needs to be supported using the same mirror number. > + * > + * If the requested block is not left of the left cursor, EIO is returned. This > + * can happen because btrfs_num_copies() returns one more in the dev-replace > + * case. > + */ > +static int get_extra_mirror_from_replace(struct btrfs_fs_info *fs_info, > + u64 logical, u64 length, > + u64 srcdev_devid, int *mirror_num, > + u64 *physical) > +{ > + struct btrfs_bio *bbio = NULL; > + int num_stripes; > + int index_srcdev = 0; > + int found = 0; > + u64 physical_of_found = 0; > + int i; > + int ret = 0; > + > + ret = __btrfs_map_block(fs_info, BTRFS_MAP_GET_READ_MIRRORS, > + logical, &length, &bbio, 0, 0); > + if (ret) { > + ASSERT(bbio == NULL); > + return ret; > + } > + > + num_stripes = bbio->num_stripes; > + if (*mirror_num > num_stripes) { > + /* > + * BTRFS_MAP_GET_READ_MIRRORS does not contain this mirror, > + * that means that the requested area is not left of the left > + * cursor > + */ > + btrfs_put_bbio(bbio); > + return -EIO; > + } > + > + /* > + * process the rest of the function using the mirror_num of the source > + * drive. Therefore look it up first. At the end, patch the device > + * pointer to the one of the target drive. > + */ > + for (i = 0; i < num_stripes; i++) { > + if (bbio->stripes[i].dev->devid != srcdev_devid) > + continue; > + > + /* > + * In case of DUP, in order to keep it simple, only add the > + * mirror with the lowest physical address > + */ > + if (found && > + physical_of_found <= bbio->stripes[i].physical) > + continue; > + > + index_srcdev = i; > + found = 1; > + physical_of_found = bbio->stripes[i].physical; > + } > + > + btrfs_put_bbio(bbio); > + > + ASSERT(found); > + if (!found) > + return -EIO; > + > + *mirror_num = index_srcdev + 1; > + *physical = physical_of_found; > + return ret; > +} > + > static int __btrfs_map_block(struct btrfs_fs_info *fs_info, > enum btrfs_map_op op, > u64 logical, u64 *length, > @@ -5567,79 +5649,14 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, > if (dev_replace_is_ongoing && mirror_num == map->num_stripes + 1 && > op != BTRFS_MAP_WRITE && op != BTRFS_MAP_GET_READ_MIRRORS && > dev_replace->tgtdev != NULL) { > - /* > - * in dev-replace case, for repair case (that's the only > - * case where the mirror is selected explicitly when > - * calling btrfs_map_block), blocks left of the left cursor > - * can also be read from the target drive. > - * For REQ_GET_READ_MIRRORS, the target drive is added as > - * the last one to the array of stripes. For READ, it also > - * needs to be supported using the same mirror number. > - * If the requested block is not left of the left cursor, > - * EIO is returned. This can happen because btrfs_num_copies() > - * returns one more in the dev-replace case. > - */ > - u64 tmp_length = *length; > - struct btrfs_bio *tmp_bbio = NULL; > - int tmp_num_stripes; > - u64 srcdev_devid = dev_replace->srcdev->devid; > - int index_srcdev = 0; > - int found = 0; > - u64 physical_of_found = 0; > - > - ret = __btrfs_map_block(fs_info, BTRFS_MAP_GET_READ_MIRRORS, > - logical, &tmp_length, &tmp_bbio, 0, 0); > - if (ret) { > - WARN_ON(tmp_bbio != NULL); > - goto out; > - } > - > - tmp_num_stripes = tmp_bbio->num_stripes; > - if (mirror_num > tmp_num_stripes) { > - /* > - * BTRFS_MAP_GET_READ_MIRRORS does not contain this > - * mirror, that means that the requested area > - * is not left of the left cursor > - */ > - ret = -EIO; > - btrfs_put_bbio(tmp_bbio); > - goto out; > - } > - > - /* > - * process the rest of the function using the mirror_num > - * of the source drive. Therefore look it up first. > - * At the end, patch the device pointer to the one of the > - * target drive. > - */ > - for (i = 0; i < tmp_num_stripes; i++) { > - if (tmp_bbio->stripes[i].dev->devid != srcdev_devid) > - continue; > - > - /* > - * In case of DUP, in order to keep it simple, only add > - * the mirror with the lowest physical address > - */ > - if (found && > - physical_of_found <= tmp_bbio->stripes[i].physical) > - continue; > - > - index_srcdev = i; > - found = 1; > - physical_of_found = tmp_bbio->stripes[i].physical; > - } > - > - btrfs_put_bbio(tmp_bbio); > - > - if (!found) { > - WARN_ON(1); > - ret = -EIO; > + ret = get_extra_mirror_from_replace(fs_info, logical, *length, > + dev_replace->srcdev->devid, > + &mirror_num, > + &physical_to_patch_in_first_stripe); > + if (ret) > goto out; > - } > - > - mirror_num = index_srcdev + 1; > - patch_the_first_stripe_for_dev_replace = 1; > - physical_to_patch_in_first_stripe = physical_of_found; > + else > + patch_the_first_stripe_for_dev_replace = 1; > } else if (mirror_num > map->num_stripes) { > mirror_num = 0; > } >