-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Generalize the implementation of the zbd zonemode for non-linux systems and Linux systems without the blkzoned.h header file (that is, linux systems with a kernel predating v4.10 or kernels compiled without zoned block device support). The configuration option CONFIG_HAS_BLKZONED determines if the system supports or not zoned block devices. This option can be set for Linux only for now. If it is set, the file oslib/linux-blkzoned.c is compiled and the 3 functions defined are used by the zbd.c code to determine a block device zoned model, get zone information and reset zones. For systems that do not set the CONFIG_HAS_BLKZONED option, zonemode=zbd will be useable with regular block devices with the zbd code emulating zones as is already done currently. Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
- Loading branch information
1 parent
ebc403f
commit b769496
Showing
11 changed files
with
517 additions
and
282 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
/* | ||
* Copyright (C) 2020 Western Digital Corporation or its affiliates. | ||
* | ||
* This file is released under the GPL. | ||
*/ | ||
#ifndef FIO_BLKZONED_H | ||
#define FIO_BLKZONED_H | ||
|
||
#include "zbd_types.h" | ||
|
||
#ifdef CONFIG_HAS_BLKZONED | ||
extern int blkzoned_get_zoned_model(struct thread_data *td, | ||
struct fio_file *f, enum zbd_zoned_model *model); | ||
extern int blkzoned_report_zones(struct thread_data *td, | ||
struct fio_file *f, uint64_t offset, | ||
struct zbd_zone *zones, unsigned int nr_zones); | ||
extern int blkzoned_reset_wp(struct thread_data *td, struct fio_file *f, | ||
uint64_t offset, uint64_t length); | ||
#else | ||
/* | ||
* Define stubs for systems that do not have zoned block device support. | ||
*/ | ||
static inline int blkzoned_get_zoned_model(struct thread_data *td, | ||
struct fio_file *f, enum zbd_zoned_model *model) | ||
{ | ||
/* | ||
* If this is a block device file, allow zbd emulation. | ||
*/ | ||
if (f->filetype == FIO_TYPE_BLOCK) { | ||
*model = ZBD_NONE; | ||
return 0; | ||
} | ||
|
||
return -ENODEV; | ||
} | ||
static inline int blkzoned_report_zones(struct thread_data *td, | ||
struct fio_file *f, uint64_t offset, | ||
struct zbd_zone *zones, unsigned int nr_zones) | ||
{ | ||
return -EIO; | ||
} | ||
static inline int blkzoned_reset_wp(struct thread_data *td, struct fio_file *f, | ||
uint64_t offset, uint64_t length) | ||
{ | ||
return -EIO; | ||
} | ||
#endif | ||
|
||
#endif /* FIO_BLKZONED_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,219 @@ | ||
/* | ||
* Copyright (C) 2020 Western Digital Corporation or its affiliates. | ||
* | ||
* This file is released under the GPL. | ||
*/ | ||
#include <errno.h> | ||
#include <string.h> | ||
#include <stdlib.h> | ||
#include <dirent.h> | ||
#include <fcntl.h> | ||
#include <sys/ioctl.h> | ||
#include <sys/stat.h> | ||
#include <unistd.h> | ||
|
||
#include "file.h" | ||
#include "fio.h" | ||
#include "lib/pow2.h" | ||
#include "log.h" | ||
#include "oslib/asprintf.h" | ||
#include "smalloc.h" | ||
#include "verify.h" | ||
#include "zbd_types.h" | ||
|
||
#include <linux/blkzoned.h> | ||
|
||
/* | ||
* Read up to 255 characters from the first line of a file. Strip the trailing | ||
* newline. | ||
*/ | ||
static char *read_file(const char *path) | ||
{ | ||
char line[256], *p = line; | ||
FILE *f; | ||
|
||
f = fopen(path, "rb"); | ||
if (!f) | ||
return NULL; | ||
if (!fgets(line, sizeof(line), f)) | ||
line[0] = '\0'; | ||
strsep(&p, "\n"); | ||
fclose(f); | ||
|
||
return strdup(line); | ||
} | ||
|
||
int blkzoned_get_zoned_model(struct thread_data *td, struct fio_file *f, | ||
enum zbd_zoned_model *model) | ||
{ | ||
const char *file_name = f->file_name; | ||
char *zoned_attr_path = NULL; | ||
char *model_str = NULL; | ||
struct stat statbuf; | ||
char *sys_devno_path = NULL; | ||
char *part_attr_path = NULL; | ||
char *part_str = NULL; | ||
char sys_path[PATH_MAX]; | ||
ssize_t sz; | ||
char *delim = NULL; | ||
|
||
if (f->filetype != FIO_TYPE_BLOCK) { | ||
*model = ZBD_IGNORE; | ||
return 0; | ||
} | ||
|
||
*model = ZBD_NONE; | ||
|
||
if (stat(file_name, &statbuf) < 0) | ||
goto out; | ||
|
||
if (asprintf(&sys_devno_path, "/sys/dev/block/%d:%d", | ||
major(statbuf.st_rdev), minor(statbuf.st_rdev)) < 0) | ||
goto out; | ||
|
||
sz = readlink(sys_devno_path, sys_path, sizeof(sys_path) - 1); | ||
if (sz < 0) | ||
goto out; | ||
sys_path[sz] = '\0'; | ||
|
||
/* | ||
* If the device is a partition device, cut the device name in the | ||
* canonical sysfs path to obtain the sysfs path of the holder device. | ||
* e.g.: /sys/devices/.../sda/sda1 -> /sys/devices/.../sda | ||
*/ | ||
if (asprintf(&part_attr_path, "/sys/dev/block/%s/partition", | ||
sys_path) < 0) | ||
goto out; | ||
part_str = read_file(part_attr_path); | ||
if (part_str && *part_str == '1') { | ||
delim = strrchr(sys_path, '/'); | ||
if (!delim) | ||
goto out; | ||
*delim = '\0'; | ||
} | ||
|
||
if (asprintf(&zoned_attr_path, | ||
"/sys/dev/block/%s/queue/zoned", sys_path) < 0) | ||
goto out; | ||
|
||
model_str = read_file(zoned_attr_path); | ||
if (!model_str) | ||
goto out; | ||
dprint(FD_ZBD, "%s: zbd model string: %s\n", file_name, model_str); | ||
if (strcmp(model_str, "host-aware") == 0) | ||
*model = ZBD_HOST_AWARE; | ||
else if (strcmp(model_str, "host-managed") == 0) | ||
*model = ZBD_HOST_MANAGED; | ||
out: | ||
free(model_str); | ||
free(zoned_attr_path); | ||
free(part_str); | ||
free(part_attr_path); | ||
free(sys_devno_path); | ||
return 0; | ||
} | ||
|
||
int blkzoned_report_zones(struct thread_data *td, struct fio_file *f, | ||
uint64_t offset, struct zbd_zone *zones, | ||
unsigned int nr_zones) | ||
{ | ||
struct blk_zone_report *hdr = NULL; | ||
struct blk_zone *blkz; | ||
struct zbd_zone *z; | ||
unsigned int i; | ||
int fd = -1, ret; | ||
|
||
fd = open(f->file_name, O_RDONLY | O_LARGEFILE); | ||
if (fd < 0) | ||
return -errno; | ||
|
||
hdr = calloc(1, sizeof(struct blk_zone_report) + | ||
nr_zones * sizeof(struct blk_zone)); | ||
if (!hdr) { | ||
ret = -ENOMEM; | ||
goto out; | ||
} | ||
|
||
hdr->nr_zones = nr_zones; | ||
hdr->sector = offset >> 9; | ||
ret = ioctl(fd, BLKREPORTZONE, hdr); | ||
if (ret) { | ||
ret = -errno; | ||
goto out; | ||
} | ||
|
||
nr_zones = hdr->nr_zones; | ||
blkz = &hdr->zones[0]; | ||
z = &zones[0]; | ||
for (i = 0; i < nr_zones; i++, z++, blkz++) { | ||
z->start = blkz->start << 9; | ||
z->wp = blkz->wp << 9; | ||
z->len = blkz->len << 9; | ||
|
||
switch (blkz->type) { | ||
case BLK_ZONE_TYPE_CONVENTIONAL: | ||
z->type = ZBD_ZONE_TYPE_CNV; | ||
break; | ||
case BLK_ZONE_TYPE_SEQWRITE_REQ: | ||
z->type = ZBD_ZONE_TYPE_SWR; | ||
break; | ||
case BLK_ZONE_TYPE_SEQWRITE_PREF: | ||
z->type = ZBD_ZONE_TYPE_SWP; | ||
break; | ||
default: | ||
td_verror(td, errno, "invalid zone type"); | ||
log_err("%s: invalid type for zone at sector %llu.\n", | ||
f->file_name, (unsigned long long)offset >> 9); | ||
ret = -EIO; | ||
goto out; | ||
} | ||
|
||
switch (blkz->cond) { | ||
case BLK_ZONE_COND_NOT_WP: | ||
z->cond = ZBD_ZONE_COND_NOT_WP; | ||
break; | ||
case BLK_ZONE_COND_EMPTY: | ||
z->cond = ZBD_ZONE_COND_EMPTY; | ||
break; | ||
case BLK_ZONE_COND_IMP_OPEN: | ||
z->cond = ZBD_ZONE_COND_IMP_OPEN; | ||
break; | ||
case BLK_ZONE_COND_EXP_OPEN: | ||
z->cond = ZBD_ZONE_COND_EXP_OPEN; | ||
break; | ||
case BLK_ZONE_COND_CLOSED: | ||
z->cond = ZBD_ZONE_COND_CLOSED; | ||
break; | ||
case BLK_ZONE_COND_FULL: | ||
z->cond = ZBD_ZONE_COND_FULL; | ||
break; | ||
case BLK_ZONE_COND_READONLY: | ||
case BLK_ZONE_COND_OFFLINE: | ||
default: | ||
/* Treat all these conditions as offline (don't use!) */ | ||
z->cond = ZBD_ZONE_COND_OFFLINE; | ||
break; | ||
} | ||
} | ||
|
||
ret = nr_zones; | ||
out: | ||
free(hdr); | ||
close(fd); | ||
|
||
return ret; | ||
} | ||
|
||
int blkzoned_reset_wp(struct thread_data *td, struct fio_file *f, | ||
uint64_t offset, uint64_t length) | ||
{ | ||
struct blk_zone_range zr = { | ||
.sector = offset >> 9, | ||
.nr_sectors = length >> 9, | ||
}; | ||
|
||
if (ioctl(f->fd, BLKRESETZONE, &zr) < 0) | ||
return -errno; | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.