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 * Read up to 255 characters from the first line of a file. Strip the trailing
30 static char *read_file(const char *path)
32 char line[256], *p = line;
35 f = fopen(path, "rb");
38 if (!fgets(line, sizeof(line), f))
46 int blkzoned_get_zoned_model(struct thread_data *td, struct fio_file *f,
47 enum zbd_zoned_model *model)
49 const char *file_name = f->file_name;
50 char *zoned_attr_path = NULL;
51 char *model_str = NULL;
53 char *sys_devno_path = NULL;
54 char *part_attr_path = NULL;
55 char *part_str = NULL;
56 char sys_path[PATH_MAX];
60 if (f->filetype != FIO_TYPE_BLOCK) {
67 if (stat(file_name, &statbuf) < 0)
70 if (asprintf(&sys_devno_path, "/sys/dev/block/%d:%d",
71 major(statbuf.st_rdev), minor(statbuf.st_rdev)) < 0)
74 sz = readlink(sys_devno_path, sys_path, sizeof(sys_path) - 1);
80 * If the device is a partition device, cut the device name in the
81 * canonical sysfs path to obtain the sysfs path of the holder device.
82 * e.g.: /sys/devices/.../sda/sda1 -> /sys/devices/.../sda
84 if (asprintf(&part_attr_path, "/sys/dev/block/%s/partition",
87 part_str = read_file(part_attr_path);
88 if (part_str && *part_str == '1') {
89 delim = strrchr(sys_path, '/');
95 if (asprintf(&zoned_attr_path,
96 "/sys/dev/block/%s/queue/zoned", sys_path) < 0)
99 model_str = read_file(zoned_attr_path);
102 dprint(FD_ZBD, "%s: zbd model string: %s\n", file_name, model_str);
103 if (strcmp(model_str, "host-aware") == 0)
104 *model = ZBD_HOST_AWARE;
105 else if (strcmp(model_str, "host-managed") == 0)
106 *model = ZBD_HOST_MANAGED;
109 free(zoned_attr_path);
111 free(part_attr_path);
112 free(sys_devno_path);
116 int blkzoned_report_zones(struct thread_data *td, struct fio_file *f,
117 uint64_t offset, struct zbd_zone *zones,
118 unsigned int nr_zones)
120 struct blk_zone_report *hdr = NULL;
121 struct blk_zone *blkz;
126 fd = open(f->file_name, O_RDONLY | O_LARGEFILE);
130 hdr = calloc(1, sizeof(struct blk_zone_report) +
131 nr_zones * sizeof(struct blk_zone));
137 hdr->nr_zones = nr_zones;
138 hdr->sector = offset >> 9;
139 ret = ioctl(fd, BLKREPORTZONE, hdr);
145 nr_zones = hdr->nr_zones;
146 blkz = &hdr->zones[0];
148 for (i = 0; i < nr_zones; i++, z++, blkz++) {
149 z->start = blkz->start << 9;
150 z->wp = blkz->wp << 9;
151 z->len = blkz->len << 9;
153 switch (blkz->type) {
154 case BLK_ZONE_TYPE_CONVENTIONAL:
155 z->type = ZBD_ZONE_TYPE_CNV;
157 case BLK_ZONE_TYPE_SEQWRITE_REQ:
158 z->type = ZBD_ZONE_TYPE_SWR;
160 case BLK_ZONE_TYPE_SEQWRITE_PREF:
161 z->type = ZBD_ZONE_TYPE_SWP;
164 td_verror(td, errno, "invalid zone type");
165 log_err("%s: invalid type for zone at sector %llu.\n",
166 f->file_name, (unsigned long long)offset >> 9);
171 switch (blkz->cond) {
172 case BLK_ZONE_COND_NOT_WP:
173 z->cond = ZBD_ZONE_COND_NOT_WP;
175 case BLK_ZONE_COND_EMPTY:
176 z->cond = ZBD_ZONE_COND_EMPTY;
178 case BLK_ZONE_COND_IMP_OPEN:
179 z->cond = ZBD_ZONE_COND_IMP_OPEN;
181 case BLK_ZONE_COND_EXP_OPEN:
182 z->cond = ZBD_ZONE_COND_EXP_OPEN;
184 case BLK_ZONE_COND_CLOSED:
185 z->cond = ZBD_ZONE_COND_CLOSED;
187 case BLK_ZONE_COND_FULL:
188 z->cond = ZBD_ZONE_COND_FULL;
190 case BLK_ZONE_COND_READONLY:
191 case BLK_ZONE_COND_OFFLINE:
193 /* Treat all these conditions as offline (don't use!) */
194 z->cond = ZBD_ZONE_COND_OFFLINE;
207 int blkzoned_reset_wp(struct thread_data *td, struct fio_file *f,
208 uint64_t offset, uint64_t length)
210 struct blk_zone_range zr = {
211 .sector = offset >> 9,
212 .nr_sectors = length >> 9,
215 if (ioctl(f->fd, BLKRESETZONE, &zr) < 0)