Merge branch 'taras/nfs-upstream' of https://github.com/tarasglek/fio-1
[fio.git] / oslib / linux-blkzoned.c
CommitLineData
b7694961
DLM
1/*
2 * Copyright (C) 2020 Western Digital Corporation or its affiliates.
3 *
4 * This file is released under the GPL.
5 */
6#include <errno.h>
7#include <string.h>
8#include <stdlib.h>
9#include <dirent.h>
10#include <fcntl.h>
11#include <sys/ioctl.h>
12#include <sys/stat.h>
13#include <unistd.h>
14
15#include "file.h"
16#include "fio.h"
17#include "lib/pow2.h"
18#include "log.h"
19#include "oslib/asprintf.h"
20#include "smalloc.h"
21#include "verify.h"
22#include "zbd_types.h"
23
24#include <linux/blkzoned.h>
25
6ee607ba
NC
26/*
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.
30 */
31#ifndef CONFIG_HAVE_REP_CAPACITY
32#define BLK_ZONE_REP_CAPACITY (1 << 0)
33
34struct blk_zone_v2 {
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 */
42 __u8 resv[4];
43 __u64 capacity; /* Zone capacity in number of sectors */
44 __u8 reserved[24];
45};
46#define blk_zone blk_zone_v2
47
48struct blk_zone_report_v2 {
49 __u64 sector;
50 __u32 nr_zones;
51 __u32 flags;
52struct blk_zone zones[0];
53};
54#define blk_zone_report blk_zone_report_v2
55#endif /* CONFIG_HAVE_REP_CAPACITY */
56
b7694961
DLM
57/*
58 * Read up to 255 characters from the first line of a file. Strip the trailing
59 * newline.
60 */
61static char *read_file(const char *path)
62{
63 char line[256], *p = line;
64 FILE *f;
65
66 f = fopen(path, "rb");
67 if (!f)
68 return NULL;
69 if (!fgets(line, sizeof(line), f))
70 line[0] = '\0';
71 strsep(&p, "\n");
72 fclose(f);
73
74 return strdup(line);
75}
76
eaa45783
NC
77/*
78 * Get the value of a sysfs attribute for a block device.
79 *
80 * Returns NULL on failure.
81 * Returns a pointer to a string on success.
82 * The caller is responsible for freeing the memory.
83 */
84static char *blkzoned_get_sysfs_attr(const char *file_name, const char *attr)
b7694961 85{
eaa45783 86 char *attr_path = NULL;
b7694961
DLM
87 struct stat statbuf;
88 char *sys_devno_path = NULL;
89 char *part_attr_path = NULL;
90 char *part_str = NULL;
91 char sys_path[PATH_MAX];
92 ssize_t sz;
93 char *delim = NULL;
eaa45783 94 char *attr_str = NULL;
b7694961
DLM
95
96 if (stat(file_name, &statbuf) < 0)
97 goto out;
98
99 if (asprintf(&sys_devno_path, "/sys/dev/block/%d:%d",
100 major(statbuf.st_rdev), minor(statbuf.st_rdev)) < 0)
101 goto out;
102
103 sz = readlink(sys_devno_path, sys_path, sizeof(sys_path) - 1);
104 if (sz < 0)
105 goto out;
106 sys_path[sz] = '\0';
107
108 /*
109 * If the device is a partition device, cut the device name in the
110 * canonical sysfs path to obtain the sysfs path of the holder device.
111 * e.g.: /sys/devices/.../sda/sda1 -> /sys/devices/.../sda
112 */
113 if (asprintf(&part_attr_path, "/sys/dev/block/%s/partition",
114 sys_path) < 0)
115 goto out;
116 part_str = read_file(part_attr_path);
117 if (part_str && *part_str == '1') {
118 delim = strrchr(sys_path, '/');
119 if (!delim)
120 goto out;
121 *delim = '\0';
122 }
123
eaa45783
NC
124 if (asprintf(&attr_path,
125 "/sys/dev/block/%s/%s", sys_path, attr) < 0)
b7694961
DLM
126 goto out;
127
eaa45783
NC
128 attr_str = read_file(attr_path);
129out:
130 free(attr_path);
131 free(part_str);
132 free(part_attr_path);
133 free(sys_devno_path);
134
135 return attr_str;
136}
137
138int blkzoned_get_zoned_model(struct thread_data *td, struct fio_file *f,
139 enum zbd_zoned_model *model)
140{
141 char *model_str = NULL;
142
143 if (f->filetype != FIO_TYPE_BLOCK) {
144 *model = ZBD_IGNORE;
145 return 0;
146 }
147
148 *model = ZBD_NONE;
149
150 model_str = blkzoned_get_sysfs_attr(f->file_name, "queue/zoned");
b7694961 151 if (!model_str)
eaa45783
NC
152 return 0;
153
154 dprint(FD_ZBD, "%s: zbd model string: %s\n", f->file_name, model_str);
b7694961
DLM
155 if (strcmp(model_str, "host-aware") == 0)
156 *model = ZBD_HOST_AWARE;
157 else if (strcmp(model_str, "host-managed") == 0)
158 *model = ZBD_HOST_MANAGED;
eaa45783 159
b7694961 160 free(model_str);
eaa45783 161
b7694961
DLM
162 return 0;
163}
164
d2f442bc
NC
165int blkzoned_get_max_open_zones(struct thread_data *td, struct fio_file *f,
166 unsigned int *max_open_zones)
167{
168 char *max_open_str;
169
170 if (f->filetype != FIO_TYPE_BLOCK)
171 return -EIO;
172
173 max_open_str = blkzoned_get_sysfs_attr(f->file_name, "queue/max_open_zones");
174 if (!max_open_str)
175 return 0;
176
177 dprint(FD_ZBD, "%s: max open zones supported by device: %s\n",
178 f->file_name, max_open_str);
179 *max_open_zones = atoll(max_open_str);
180
181 free(max_open_str);
182
183 return 0;
184}
185
236d23a8
SK
186static uint64_t zone_capacity(struct blk_zone_report *hdr,
187 struct blk_zone *blkz)
188{
236d23a8
SK
189 if (hdr->flags & BLK_ZONE_REP_CAPACITY)
190 return blkz->capacity << 9;
236d23a8
SK
191 return blkz->len << 9;
192}
193
b7694961
DLM
194int blkzoned_report_zones(struct thread_data *td, struct fio_file *f,
195 uint64_t offset, struct zbd_zone *zones,
196 unsigned int nr_zones)
197{
198 struct blk_zone_report *hdr = NULL;
199 struct blk_zone *blkz;
200 struct zbd_zone *z;
201 unsigned int i;
202 int fd = -1, ret;
203
204 fd = open(f->file_name, O_RDONLY | O_LARGEFILE);
205 if (fd < 0)
206 return -errno;
207
208 hdr = calloc(1, sizeof(struct blk_zone_report) +
209 nr_zones * sizeof(struct blk_zone));
210 if (!hdr) {
211 ret = -ENOMEM;
212 goto out;
213 }
214
215 hdr->nr_zones = nr_zones;
216 hdr->sector = offset >> 9;
217 ret = ioctl(fd, BLKREPORTZONE, hdr);
218 if (ret) {
219 ret = -errno;
220 goto out;
221 }
222
223 nr_zones = hdr->nr_zones;
f8779edf 224 blkz = (void *) hdr + sizeof(*hdr);
b7694961
DLM
225 z = &zones[0];
226 for (i = 0; i < nr_zones; i++, z++, blkz++) {
227 z->start = blkz->start << 9;
228 z->wp = blkz->wp << 9;
229 z->len = blkz->len << 9;
236d23a8 230 z->capacity = zone_capacity(hdr, blkz);
b7694961
DLM
231
232 switch (blkz->type) {
233 case BLK_ZONE_TYPE_CONVENTIONAL:
234 z->type = ZBD_ZONE_TYPE_CNV;
235 break;
236 case BLK_ZONE_TYPE_SEQWRITE_REQ:
237 z->type = ZBD_ZONE_TYPE_SWR;
238 break;
239 case BLK_ZONE_TYPE_SEQWRITE_PREF:
240 z->type = ZBD_ZONE_TYPE_SWP;
241 break;
242 default:
243 td_verror(td, errno, "invalid zone type");
244 log_err("%s: invalid type for zone at sector %llu.\n",
245 f->file_name, (unsigned long long)offset >> 9);
246 ret = -EIO;
247 goto out;
248 }
249
250 switch (blkz->cond) {
251 case BLK_ZONE_COND_NOT_WP:
252 z->cond = ZBD_ZONE_COND_NOT_WP;
253 break;
254 case BLK_ZONE_COND_EMPTY:
255 z->cond = ZBD_ZONE_COND_EMPTY;
256 break;
257 case BLK_ZONE_COND_IMP_OPEN:
258 z->cond = ZBD_ZONE_COND_IMP_OPEN;
259 break;
260 case BLK_ZONE_COND_EXP_OPEN:
261 z->cond = ZBD_ZONE_COND_EXP_OPEN;
262 break;
263 case BLK_ZONE_COND_CLOSED:
264 z->cond = ZBD_ZONE_COND_CLOSED;
265 break;
266 case BLK_ZONE_COND_FULL:
267 z->cond = ZBD_ZONE_COND_FULL;
268 break;
269 case BLK_ZONE_COND_READONLY:
270 case BLK_ZONE_COND_OFFLINE:
271 default:
272 /* Treat all these conditions as offline (don't use!) */
273 z->cond = ZBD_ZONE_COND_OFFLINE;
59b67452 274 z->wp = z->start;
b7694961
DLM
275 }
276 }
277
278 ret = nr_zones;
279out:
280 free(hdr);
281 close(fd);
282
283 return ret;
284}
285
286int blkzoned_reset_wp(struct thread_data *td, struct fio_file *f,
287 uint64_t offset, uint64_t length)
288{
289 struct blk_zone_range zr = {
290 .sector = offset >> 9,
291 .nr_sectors = length >> 9,
292 };
b4824992
SK
293 int fd, ret = 0;
294
295 /* If the file is not yet opened, open it for this function. */
296 fd = f->fd;
297 if (fd < 0) {
298 fd = open(f->file_name, O_RDWR | O_LARGEFILE);
299 if (fd < 0)
300 return -errno;
301 }
b7694961 302
b4824992
SK
303 if (ioctl(fd, BLKRESETZONE, &zr) < 0)
304 ret = -errno;
b7694961 305
b4824992
SK
306 if (f->fd < 0)
307 close(fd);
308
309 return ret;
b7694961 310}