Commit dbfcc18f authored by Johannes Thumshirn's avatar Johannes Thumshirn Committed by David Sterba
Browse files

btrfs: zoned: prepare for allowing DUP on zoned



Allow for a block-group to be placed on more than one physical zone.

This is a preparation for allowing DUP profiles for meta-data on a zoned
file-system.

Signed-off-by: default avatarJohannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 4dcbb8ab
Loading
Loading
Loading
Loading
+16 −9
Original line number Original line Diff line number Diff line
@@ -1215,12 +1215,12 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
	struct btrfs_device *device;
	struct btrfs_device *device;
	u64 logical = cache->start;
	u64 logical = cache->start;
	u64 length = cache->length;
	u64 length = cache->length;
	u64 physical = 0;
	int ret;
	int ret;
	int i;
	int i;
	unsigned int nofs_flag;
	unsigned int nofs_flag;
	u64 *alloc_offsets = NULL;
	u64 *alloc_offsets = NULL;
	u64 *caps = NULL;
	u64 *caps = NULL;
	u64 *physical = NULL;
	unsigned long *active = NULL;
	unsigned long *active = NULL;
	u64 last_alloc = 0;
	u64 last_alloc = 0;
	u32 num_sequential = 0, num_conventional = 0;
	u32 num_sequential = 0, num_conventional = 0;
@@ -1264,6 +1264,12 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
		goto out;
		goto out;
	}
	}


	physical = kcalloc(map->num_stripes, sizeof(*physical), GFP_NOFS);
	if (!physical) {
		ret = -ENOMEM;
		goto out;
	}

	active = bitmap_zalloc(map->num_stripes, GFP_NOFS);
	active = bitmap_zalloc(map->num_stripes, GFP_NOFS);
	if (!active) {
	if (!active) {
		ret = -ENOMEM;
		ret = -ENOMEM;
@@ -1277,14 +1283,14 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
		int dev_replace_is_ongoing = 0;
		int dev_replace_is_ongoing = 0;


		device = map->stripes[i].dev;
		device = map->stripes[i].dev;
		physical = map->stripes[i].physical;
		physical[i] = map->stripes[i].physical;


		if (device->bdev == NULL) {
		if (device->bdev == NULL) {
			alloc_offsets[i] = WP_MISSING_DEV;
			alloc_offsets[i] = WP_MISSING_DEV;
			continue;
			continue;
		}
		}


		is_sequential = btrfs_dev_is_sequential(device, physical);
		is_sequential = btrfs_dev_is_sequential(device, physical[i]);
		if (is_sequential)
		if (is_sequential)
			num_sequential++;
			num_sequential++;
		else
		else
@@ -1299,21 +1305,21 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
		 * This zone will be used for allocation, so mark this zone
		 * This zone will be used for allocation, so mark this zone
		 * non-empty.
		 * non-empty.
		 */
		 */
		btrfs_dev_clear_zone_empty(device, physical);
		btrfs_dev_clear_zone_empty(device, physical[i]);


		down_read(&dev_replace->rwsem);
		down_read(&dev_replace->rwsem);
		dev_replace_is_ongoing = btrfs_dev_replace_is_ongoing(dev_replace);
		dev_replace_is_ongoing = btrfs_dev_replace_is_ongoing(dev_replace);
		if (dev_replace_is_ongoing && dev_replace->tgtdev != NULL)
		if (dev_replace_is_ongoing && dev_replace->tgtdev != NULL)
			btrfs_dev_clear_zone_empty(dev_replace->tgtdev, physical);
			btrfs_dev_clear_zone_empty(dev_replace->tgtdev, physical[i]);
		up_read(&dev_replace->rwsem);
		up_read(&dev_replace->rwsem);


		/*
		/*
		 * The group is mapped to a sequential zone. Get the zone write
		 * The group is mapped to a sequential zone. Get the zone write
		 * pointer to determine the allocation offset within the zone.
		 * pointer to determine the allocation offset within the zone.
		 */
		 */
		WARN_ON(!IS_ALIGNED(physical, fs_info->zone_size));
		WARN_ON(!IS_ALIGNED(physical[i], fs_info->zone_size));
		nofs_flag = memalloc_nofs_save();
		nofs_flag = memalloc_nofs_save();
		ret = btrfs_get_dev_zone(device, physical, &zone);
		ret = btrfs_get_dev_zone(device, physical[i], &zone);
		memalloc_nofs_restore(nofs_flag);
		memalloc_nofs_restore(nofs_flag);
		if (ret == -EIO || ret == -EOPNOTSUPP) {
		if (ret == -EIO || ret == -EOPNOTSUPP) {
			ret = 0;
			ret = 0;
@@ -1339,7 +1345,7 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
		case BLK_ZONE_COND_READONLY:
		case BLK_ZONE_COND_READONLY:
			btrfs_err(fs_info,
			btrfs_err(fs_info,
		"zoned: offline/readonly zone %llu on device %s (devid %llu)",
		"zoned: offline/readonly zone %llu on device %s (devid %llu)",
				  physical >> device->zone_info->zone_size_shift,
				  physical[i] >> device->zone_info->zone_size_shift,
				  rcu_str_deref(device->name), device->devid);
				  rcu_str_deref(device->name), device->devid);
			alloc_offsets[i] = WP_MISSING_DEV;
			alloc_offsets[i] = WP_MISSING_DEV;
			break;
			break;
@@ -1404,7 +1410,7 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
		if (alloc_offsets[0] == WP_MISSING_DEV) {
		if (alloc_offsets[0] == WP_MISSING_DEV) {
			btrfs_err(fs_info,
			btrfs_err(fs_info,
			"zoned: cannot recover write pointer for zone %llu",
			"zoned: cannot recover write pointer for zone %llu",
				physical);
				physical[0]);
			ret = -EIO;
			ret = -EIO;
			goto out;
			goto out;
		}
		}
@@ -1465,6 +1471,7 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
		cache->physical_map = NULL;
		cache->physical_map = NULL;
	}
	}
	bitmap_free(active);
	bitmap_free(active);
	kfree(physical);
	kfree(caps);
	kfree(caps);
	kfree(alloc_offsets);
	kfree(alloc_offsets);
	free_extent_map(em);
	free_extent_map(em);