@@ -1391,8 +1391,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. In ZONED mode, 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)
@@ -1333,6 +1333,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;
@@ -1340,14 +1343,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 in ZONED mode */
+ 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) {
@@ -210,4 +210,20 @@ 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