btrfs: zoned: reset zones of unused block groups
authorNaohiro Aota <naohiro.aota@wdc.com>
Thu, 4 Feb 2021 10:21:56 +0000 (19:21 +0900)
committerDavid Sterba <dsterba@suse.com>
Tue, 9 Feb 2021 01:46:04 +0000 (02:46 +0100)
We must reset the zones of a deleted unused block group to rewind the
zones' write pointers to the zones' start.

To do this, we can use the DISCARD_SYNC code to do the reset when the
filesystem is running on zoned devices.

Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Reviewed-by: Anand Jain <anand.jain@oracle.com>
Signed-off-by: Naohiro Aota <naohiro.aota@wdc.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/block-group.c
fs/btrfs/extent-tree.c
fs/btrfs/zoned.h

index 63093cfb807efce1dd1ccdeeaa049da8a795cd1b..70a0c0f8f99f5ff96f33e5366e18090d1cc49acb 100644 (file)
@@ -1408,8 +1408,12 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
                if (!async_trim_enabled && btrfs_test_opt(fs_info, DISCARD_ASYNC))
                        goto flip_async;
 
-               /* DISCARD can flip during remount */
-               trimming = btrfs_test_opt(fs_info, DISCARD_SYNC);
+               /*
+                * DISCARD can flip during remount. On zoned filesystems, we
+                * need to reset sequential-required zones.
+                */
+               trimming = btrfs_test_opt(fs_info, DISCARD_SYNC) ||
+                               btrfs_is_zoned(fs_info);
 
                /* Implicit trim during transaction commit. */
                if (trimming)
index dddcb8513c774d1c81d2325f3495cff97a8f1d87..d976c56b3a56a97abd9fa84d18fa752ac22bd864 100644 (file)
@@ -1298,6 +1298,9 @@ int btrfs_discard_extent(struct btrfs_fs_info *fs_info, u64 bytenr,
 
                stripe = bbio->stripes;
                for (i = 0; i < bbio->num_stripes; i++, stripe++) {
+                       struct btrfs_device *dev = stripe->dev;
+                       u64 physical = stripe->physical;
+                       u64 length = stripe->length;
                        u64 bytes;
                        struct request_queue *req_q;
 
@@ -1305,14 +1308,18 @@ int btrfs_discard_extent(struct btrfs_fs_info *fs_info, u64 bytenr,
                                ASSERT(btrfs_test_opt(fs_info, DEGRADED));
                                continue;
                        }
+
                        req_q = bdev_get_queue(stripe->dev->bdev);
-                       if (!blk_queue_discard(req_q))
+                       /* Zone reset on zoned filesystems */
+                       if (btrfs_can_zone_reset(dev, physical, length))
+                               ret = btrfs_reset_device_zone(dev, physical,
+                                                             length, &bytes);
+                       else if (blk_queue_discard(req_q))
+                               ret = btrfs_issue_discard(dev->bdev, physical,
+                                                         length, &bytes);
+                       else
                                continue;
 
-                       ret = btrfs_issue_discard(stripe->dev->bdev,
-                                                 stripe->physical,
-                                                 stripe->length,
-                                                 &bytes);
                        if (!ret) {
                                discarded_bytes += bytes;
                        } else if (ret != -EOPNOTSUPP) {
index b250a578e38c4ef562585287fe987306b2519431..c105641a6ad34c5a45a64e500ffe50693f530eba 100644 (file)
@@ -209,4 +209,19 @@ static inline bool btrfs_check_super_location(struct btrfs_device *device, u64 p
        return device->zone_info == NULL || !btrfs_dev_is_sequential(device, pos);
 }
 
+static inline bool btrfs_can_zone_reset(struct btrfs_device *device,
+                                       u64 physical, u64 length)
+{
+       u64 zone_size;
+
+       if (!btrfs_dev_is_sequential(device, physical))
+               return false;
+
+       zone_size = device->zone_info->zone_size;
+       if (!IS_ALIGNED(physical, zone_size) || !IS_ALIGNED(length, zone_size))
+               return false;
+
+       return true;
+}
+
 #endif