btrfs: zoned: allow DUP on meta-data block groups
authorJohannes Thumshirn <johannes.thumshirn@wdc.com>
Wed, 26 Jan 2022 13:46:23 +0000 (05:46 -0800)
committerDavid Sterba <dsterba@suse.com>
Mon, 14 Mar 2022 12:13:49 +0000 (13:13 +0100)
Allow creating or reading block-groups on a zoned device with DUP as a
meta-data profile.

This works because we're using the zoned_meta_io_lock and REQ_OP_WRITE
operations for meta-data on zoned btrfs, so all writes to meta-data zones
are aligned to the zone's write-pointer.

Upon loading of the block-group, it is ensured both zones do have the same
zone capacity and write-pointer offsets, so no extra machinery is needed
to keep the write-pointers in sync for the meta-data zones. If this
prerequisite is not met, loading of the block-group is refused.

Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/zoned.c

index 4f6f7afaa5a2270b1f108cbe96d3bc0d95d9bfa9..3aad1970ee4308726008c487d218c4fac8f73422 100644 (file)
@@ -1419,6 +1419,42 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
                cache->zone_is_active = test_bit(0, active);
                break;
        case BTRFS_BLOCK_GROUP_DUP:
+               if (map->type & BTRFS_BLOCK_GROUP_DATA) {
+                       btrfs_err(fs_info, "zoned: profile DUP not yet supported on data bg");
+                       ret = -EINVAL;
+                       goto out;
+               }
+               if (alloc_offsets[0] == WP_MISSING_DEV) {
+                       btrfs_err(fs_info,
+                       "zoned: cannot recover write pointer for zone %llu",
+                               physical[0]);
+                       ret = -EIO;
+                       goto out;
+               }
+               if (alloc_offsets[1] == WP_MISSING_DEV) {
+                       btrfs_err(fs_info,
+                       "zoned: cannot recover write pointer for zone %llu",
+                               physical[1]);
+                       ret = -EIO;
+                       goto out;
+               }
+               if (alloc_offsets[0] != alloc_offsets[1]) {
+                       btrfs_err(fs_info,
+                       "zoned: write pointer offset mismatch of zones in DUP profile");
+                       ret = -EIO;
+                       goto out;
+               }
+               if (test_bit(0, active) != test_bit(1, active)) {
+                       if (!btrfs_zone_activate(cache)) {
+                               ret = -EIO;
+                               goto out;
+                       }
+               } else {
+                       cache->zone_is_active = test_bit(0, active);
+               }
+               cache->alloc_offset = alloc_offsets[0];
+               cache->zone_capacity = min(caps[0], caps[1]);
+               break;
        case BTRFS_BLOCK_GROUP_RAID1:
        case BTRFS_BLOCK_GROUP_RAID0:
        case BTRFS_BLOCK_GROUP_RAID10: