btrfs-progs: zoned: introduce max_zone_append_size

The zone append write command has a maximum IO size restriction it
accepts. This is because a zone append write command cannot be split, as
we ask the device to place the data into a specific target zone and the
device responds with the actual written location of the data.

Introduce max_zone_append_size to zone_info and fs_info to track the
value, so we can limit all I/O to a zoned block device that we want to
write using the zone append command to the device's limits.

Zone append command is mandatory for zoned btrfs. So, reject a device
with max_zone_append_size == 0.

Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Naohiro Aota <naohiro.aota@wdc.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Naohiro Aota 2021-04-26 15:27:23 +09:00 committed by David Sterba
parent 7e520022ff
commit 3c0f83e541
3 changed files with 32 additions and 0 deletions

View File

@ -1222,6 +1222,9 @@ struct btrfs_fs_info {
u64 zone_size; u64 zone_size;
u64 zoned; u64 zoned;
}; };
/* Max size to emit ZONE_APPEND write command */
u64 max_zone_append_size;
}; };
static inline bool btrfs_is_zoned(const struct btrfs_fs_info *fs_info) static inline bool btrfs_is_zoned(const struct btrfs_fs_info *fs_info)

View File

@ -58,6 +58,18 @@ u64 zone_size(const char *file)
return strtoull((const char *)chunk, NULL, 10) << SECTOR_SHIFT; return strtoull((const char *)chunk, NULL, 10) << SECTOR_SHIFT;
} }
u64 max_zone_append_size(const char *file)
{
char chunk[32];
int ret;
ret = queue_param(file, "zone_append_max_bytes", chunk, sizeof(chunk));
if (ret <= 0)
return 0;
return strtoull((const char *)chunk, NULL, 10);
}
#ifdef BTRFS_ZONED #ifdef BTRFS_ZONED
static int report_zones(int fd, const char *file, static int report_zones(int fd, const char *file,
struct btrfs_zoned_device_info *zinfo) struct btrfs_zoned_device_info *zinfo)
@ -101,9 +113,18 @@ static int report_zones(int fd, const char *file,
/* Allocate the zone information array */ /* Allocate the zone information array */
zinfo->zone_size = zone_bytes; zinfo->zone_size = zone_bytes;
zinfo->max_zone_append_size = max_zone_append_size(file);
zinfo->nr_zones = device_size / zone_bytes; zinfo->nr_zones = device_size / zone_bytes;
if (device_size & (zone_bytes - 1)) if (device_size & (zone_bytes - 1))
zinfo->nr_zones++; zinfo->nr_zones++;
if (zoned_model(file) != ZONED_NONE &&
zinfo->max_zone_append_size == 0) {
error(
"zoned: device %s does not support ZONE_APPEND command", file);
exit(1);
}
zinfo->zones = calloc(zinfo->nr_zones, sizeof(struct blk_zone)); zinfo->zones = calloc(zinfo->nr_zones, sizeof(struct blk_zone));
if (!zinfo->zones) { if (!zinfo->zones) {
error("zoned: no memory for zone information"); error("zoned: no memory for zone information");
@ -246,6 +267,7 @@ int btrfs_check_zoned_mode(struct btrfs_fs_info *fs_info)
u64 zoned_devices = 0; u64 zoned_devices = 0;
u64 nr_devices = 0; u64 nr_devices = 0;
u64 zone_size = 0; u64 zone_size = 0;
u64 max_zone_append_size = 0;
const bool incompat_zoned = btrfs_fs_incompat(fs_info, ZONED); const bool incompat_zoned = btrfs_fs_incompat(fs_info, ZONED);
int ret = 0; int ret = 0;
@ -280,6 +302,11 @@ int btrfs_check_zoned_mode(struct btrfs_fs_info *fs_info)
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
if (!max_zone_append_size ||
(zone_info->max_zone_append_size &&
zone_info->max_zone_append_size < max_zone_append_size))
max_zone_append_size =
zone_info->max_zone_append_size;
} }
nr_devices++; nr_devices++;
} }
@ -319,6 +346,7 @@ int btrfs_check_zoned_mode(struct btrfs_fs_info *fs_info)
} }
fs_info->zone_size = zone_size; fs_info->zone_size = zone_size;
fs_info->max_zone_append_size = max_zone_append_size;
out: out:
return ret; return ret;

View File

@ -31,6 +31,7 @@ enum btrfs_zoned_model {
struct btrfs_zoned_device_info { struct btrfs_zoned_device_info {
enum btrfs_zoned_model model; enum btrfs_zoned_model model;
u64 zone_size; u64 zone_size;
u64 max_zone_append_size;
u32 nr_zones; u32 nr_zones;
struct blk_zone *zones; struct blk_zone *zones;
}; };