2 * Copyright (C) 2020 Western Digital Corporation or its affiliates.
4 * This file is released under the GPL.
11 #include <sys/ioctl.h>
19 #include "oslib/asprintf.h"
22 #include "zbd_types.h"
24 #include <linux/blkzoned.h>
27 * If the uapi headers installed on the system lacks zone capacity support,
28 * use our local versions. If the installed headers are recent enough to
29 * support zone capacity, do not redefine any structs.
31 #ifndef CONFIG_HAVE_REP_CAPACITY
32 #define BLK_ZONE_REP_CAPACITY (1 << 0)
35 __u64 start; /* Zone start sector */
36 __u64 len; /* Zone length in number of sectors */
37 __u64 wp; /* Zone write pointer position */
38 __u8 type; /* Zone type */
39 __u8 cond; /* Zone condition */
40 __u8 non_seq; /* Non-sequential write resources active */
41 __u8 reset; /* Reset write pointer recommended */
43 __u64 capacity; /* Zone capacity in number of sectors */
46 #define blk_zone blk_zone_v2
48 struct blk_zone_report_v2 {
52 struct blk_zone zones[0];
54 #define blk_zone_report blk_zone_report_v2
55 #endif /* CONFIG_HAVE_REP_CAPACITY */
58 * Read up to 255 characters from the first line of a file. Strip the trailing
61 static char *read_file(const char *path)
63 char line[256], *p = line;
66 f = fopen(path, "rb");
69 if (!fgets(line, sizeof(line), f))
77 int blkzoned_get_zoned_model(struct thread_data *td, struct fio_file *f,
78 enum zbd_zoned_model *model)
80 const char *file_name = f->file_name;
81 char *zoned_attr_path = NULL;
82 char *model_str = NULL;
84 char *sys_devno_path = NULL;
85 char *part_attr_path = NULL;
86 char *part_str = NULL;
87 char sys_path[PATH_MAX];
91 if (f->filetype != FIO_TYPE_BLOCK) {
98 if (stat(file_name, &statbuf) < 0)
101 if (asprintf(&sys_devno_path, "/sys/dev/block/%d:%d",
102 major(statbuf.st_rdev), minor(statbuf.st_rdev)) < 0)
105 sz = readlink(sys_devno_path, sys_path, sizeof(sys_path) - 1);
111 * If the device is a partition device, cut the device name in the
112 * canonical sysfs path to obtain the sysfs path of the holder device.
113 * e.g.: /sys/devices/.../sda/sda1 -> /sys/devices/.../sda
115 if (asprintf(&part_attr_path, "/sys/dev/block/%s/partition",
118 part_str = read_file(part_attr_path);
119 if (part_str && *part_str == '1') {
120 delim = strrchr(sys_path, '/');
126 if (asprintf(&zoned_attr_path,
127 "/sys/dev/block/%s/queue/zoned", sys_path) < 0)
130 model_str = read_file(zoned_attr_path);
133 dprint(FD_ZBD, "%s: zbd model string: %s\n", file_name, model_str);
134 if (strcmp(model_str, "host-aware") == 0)
135 *model = ZBD_HOST_AWARE;
136 else if (strcmp(model_str, "host-managed") == 0)
137 *model = ZBD_HOST_MANAGED;
140 free(zoned_attr_path);
142 free(part_attr_path);
143 free(sys_devno_path);
147 static uint64_t zone_capacity(struct blk_zone_report *hdr,
148 struct blk_zone *blkz)
150 if (hdr->flags & BLK_ZONE_REP_CAPACITY)
151 return blkz->capacity << 9;
152 return blkz->len << 9;
155 int blkzoned_report_zones(struct thread_data *td, struct fio_file *f,
156 uint64_t offset, struct zbd_zone *zones,
157 unsigned int nr_zones)
159 struct blk_zone_report *hdr = NULL;
160 struct blk_zone *blkz;
165 fd = open(f->file_name, O_RDONLY | O_LARGEFILE);
169 hdr = calloc(1, sizeof(struct blk_zone_report) +
170 nr_zones * sizeof(struct blk_zone));
176 hdr->nr_zones = nr_zones;
177 hdr->sector = offset >> 9;
178 ret = ioctl(fd, BLKREPORTZONE, hdr);
184 nr_zones = hdr->nr_zones;
185 blkz = (void *) hdr + sizeof(*hdr);
187 for (i = 0; i < nr_zones; i++, z++, blkz++) {
188 z->start = blkz->start << 9;
189 z->wp = blkz->wp << 9;
190 z->len = blkz->len << 9;
191 z->capacity = zone_capacity(hdr, blkz);
193 switch (blkz->type) {
194 case BLK_ZONE_TYPE_CONVENTIONAL:
195 z->type = ZBD_ZONE_TYPE_CNV;
197 case BLK_ZONE_TYPE_SEQWRITE_REQ:
198 z->type = ZBD_ZONE_TYPE_SWR;
200 case BLK_ZONE_TYPE_SEQWRITE_PREF:
201 z->type = ZBD_ZONE_TYPE_SWP;
204 td_verror(td, errno, "invalid zone type");
205 log_err("%s: invalid type for zone at sector %llu.\n",
206 f->file_name, (unsigned long long)offset >> 9);
211 switch (blkz->cond) {
212 case BLK_ZONE_COND_NOT_WP:
213 z->cond = ZBD_ZONE_COND_NOT_WP;
215 case BLK_ZONE_COND_EMPTY:
216 z->cond = ZBD_ZONE_COND_EMPTY;
218 case BLK_ZONE_COND_IMP_OPEN:
219 z->cond = ZBD_ZONE_COND_IMP_OPEN;
221 case BLK_ZONE_COND_EXP_OPEN:
222 z->cond = ZBD_ZONE_COND_EXP_OPEN;
224 case BLK_ZONE_COND_CLOSED:
225 z->cond = ZBD_ZONE_COND_CLOSED;
227 case BLK_ZONE_COND_FULL:
228 z->cond = ZBD_ZONE_COND_FULL;
230 case BLK_ZONE_COND_READONLY:
231 case BLK_ZONE_COND_OFFLINE:
233 /* Treat all these conditions as offline (don't use!) */
234 z->cond = ZBD_ZONE_COND_OFFLINE;
247 int blkzoned_reset_wp(struct thread_data *td, struct fio_file *f,
248 uint64_t offset, uint64_t length)
250 struct blk_zone_range zr = {
251 .sector = offset >> 9,
252 .nr_sectors = length >> 9,
256 /* If the file is not yet opened, open it for this function. */
259 fd = open(f->file_name, O_RDWR | O_LARGEFILE);
264 if (ioctl(fd, BLKRESETZONE, &zr) < 0)