diff mbox series

[09/26] btrfs-progs: zoned: allow zoned filesystems on non-zoned block devices

Message ID 3ecdd9e85e977d87443a503a41fc349944687d6c.1619416549.git.naohiro.aota@wdc.com (mailing list archive)
State New, archived
Headers show
Series btrfs-progs: zoned: zoned block device support | expand

Commit Message

Naohiro Aota April 26, 2021, 6:27 a.m. UTC
Run a zoned filesystem on non-zoned devices. This is done by "slicing up"
the block device into static sized chunks and fake a conventional zone on
each of them. The emulated zone size is determined from the size of device
extent.

This is mainly aimed at testing of zoned filesystems, i.e. the zoned chunk
allocator, on regular block devices.

Currently, we always use EMULATED_ZONE_SIZE (= 256MB) for the emulated zone
size. In the future, this will be customized by mkfs option.

Signed-off-by: Naohiro Aota <naohiro.aota@wdc.com>
---
 kerncompat.h          |  1 +
 kernel-shared/zoned.c | 67 +++++++++++++++++++++++++++++++++++++++----
 2 files changed, 62 insertions(+), 6 deletions(-)

Comments

Johannes Thumshirn April 26, 2021, 1:43 p.m. UTC | #1
On 26/04/2021 08:28, Naohiro Aota wrote:
> +			}
>  		}
>  
> +
>  		if (!rep->nr_zones)
>  			break;

Nit: double newline

Otherwise
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
diff mbox series

Patch

diff --git a/kerncompat.h b/kerncompat.h
index a39b79cba767..b2983ed60c4a 100644
--- a/kerncompat.h
+++ b/kerncompat.h
@@ -166,6 +166,7 @@  typedef long long s64;
 typedef int s32;
 #endif
 
+typedef u64 sector_t;
 
 struct vma_shared { int prio_tree_node; };
 struct vm_area_struct {
diff --git a/kernel-shared/zoned.c b/kernel-shared/zoned.c
index 7b05fe6cc70f..ebaa2a81b2c8 100644
--- a/kernel-shared/zoned.c
+++ b/kernel-shared/zoned.c
@@ -14,6 +14,8 @@ 
 /* Maximum number of zones to report per ioctl(BLKREPORTZONE) call */
 #define BTRFS_REPORT_NR_ZONES   4096
 
+#define EMULATED_ZONE_SIZE SZ_256M
+
 static int btrfs_get_dev_zone_info(struct btrfs_device *device);
 
 enum btrfs_zoned_model zoned_model(const char *file)
@@ -51,6 +53,10 @@  u64 zone_size(const char *file)
 	char chunk[32];
 	int ret;
 
+	/* zoned emulation on regular device */
+	if (zoned_model(file) == ZONED_NONE)
+		return EMULATED_ZONE_SIZE;
+
 	ret = queue_param(file, "chunk_sectors", chunk, sizeof(chunk));
 	if (ret <= 0)
 		return 0;
@@ -71,6 +77,46 @@  u64 max_zone_append_size(const char *file)
 }
 
 #ifdef BTRFS_ZONED
+/*
+ * Emulate blkdev_report_zones() for a non-zoned device. It slices up the block
+ * device into static sized chunks and fake a conventional zone on each of
+ * them.
+ */
+static int emulate_report_zones(const char *file, int fd, u64 pos,
+				struct blk_zone *zones, unsigned int nr_zones)
+{
+	const sector_t zone_sectors = EMULATED_ZONE_SIZE >> SECTOR_SHIFT;
+	struct stat st;
+	sector_t bdev_size;
+	unsigned int i;
+	int ret;
+
+	ret = fstat(fd, &st);
+	if (ret < 0) {
+		error("unable to stat %s: %m", file);
+		return -EIO;
+	}
+
+	bdev_size = btrfs_device_size(fd, &st) >> SECTOR_SHIFT;
+
+	pos >>= SECTOR_SHIFT;
+	for (i = 0; i < nr_zones; i++) {
+		zones[i].start = i * zone_sectors + pos;
+		zones[i].len = zone_sectors;
+		zones[i].capacity = zone_sectors;
+		zones[i].wp = zones[i].start + zone_sectors;
+		zones[i].type = BLK_ZONE_TYPE_CONVENTIONAL;
+		zones[i].cond = BLK_ZONE_COND_NOT_WP;
+
+		if (zones[i].wp >= bdev_size) {
+			i++;
+			break;
+		}
+	}
+
+	return i;
+}
+
 static int report_zones(int fd, const char *file,
 			struct btrfs_zoned_device_info *zinfo)
 {
@@ -149,12 +195,23 @@  static int report_zones(int fd, const char *file,
 		rep->sector = sector;
 		rep->nr_zones = BTRFS_REPORT_NR_ZONES;
 
-		ret = ioctl(fd, BLKREPORTZONE, rep);
-		if (ret != 0) {
-			error("zoned: ioctl BLKREPORTZONE failed (%m)");
-			exit(1);
+		if (zinfo->model != ZONED_NONE) {
+			ret = ioctl(fd, BLKREPORTZONE, rep);
+			if (ret != 0) {
+				error("zoned: ioctl BLKREPORTZONE failed (%m)");
+				exit(1);
+			}
+		} else {
+			ret = emulate_report_zones(file, fd,
+						   sector << SECTOR_SHIFT,
+						   zone, BTRFS_REPORT_NR_ZONES);
+			if (ret < 0) {
+				error("zoned: failed to emulate BLKREPORTZONE");
+				exit(1);
+			}
 		}
 
+
 		if (!rep->nr_zones)
 			break;
 
@@ -231,8 +288,6 @@  int btrfs_get_zone_info(int fd, const char *file,
 
 	/* Check zone model */
 	model = zoned_model(file);
-	if (model == ZONED_NONE)
-		return 0;
 
 #ifdef BTRFS_ZONED
 	zinfo = calloc(1, sizeof(*zinfo));