Skip to content

Commit

Permalink
wip: ublk zoned
Browse files Browse the repository at this point in the history
  • Loading branch information
metaspace committed Mar 16, 2023
1 parent ba444e0 commit 2c60b9f
Show file tree
Hide file tree
Showing 6 changed files with 224 additions and 11 deletions.
37 changes: 31 additions & 6 deletions include/ublk_cmd.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@
*/
#define UBLK_F_UNPRIVILEGED_DEV (1UL << 5)

/*
* Enable zoned device support
*/
#define UBLK_F_ZONED (1ULL << 6)

/* device state */
#define UBLK_S_DEV_DEAD 0
#define UBLK_S_DEV_LIVE 1
Expand Down Expand Up @@ -155,12 +160,24 @@ struct ublksrv_ctrl_dev_info {
__u64 reserved2;
};

#define UBLK_IO_OP_READ 0
#define UBLK_IO_OP_WRITE 1
#define UBLK_IO_OP_FLUSH 2
#define UBLK_IO_OP_DISCARD 3
#define UBLK_IO_OP_WRITE_SAME 4
#define UBLK_IO_OP_WRITE_ZEROES 5
enum ublk_op {
UBLK_IO_OP_READ = 0,
UBLK_IO_OP_WRITE = 1,
UBLK_IO_OP_FLUSH = 2,
UBLK_IO_OP_DISCARD = 3,
UBLK_IO_OP_WRITE_SAME = 4,
UBLK_IO_OP_WRITE_ZEROES = 5,
UBLK_IO_OP_ZONE_OPEN = 10,
UBLK_IO_OP_ZONE_CLOSE = 11,
UBLK_IO_OP_ZONE_FINISH = 12,
UBLK_IO_OP_ZONE_APPEND = 13,
UBLK_IO_OP_ZONE_RESET = 15,
__UBLK_IO_OP_DRV_IN_START = 32,
UBLK_IO_OP_REPORT_ZONES = __UBLK_IO_OP_DRV_IN_START,
__UBLK_IO_OP_DRV_IN_END = 96,
__UBLK_IO_OP_DRV_OUT_START = __UBLK_IO_OP_DRV_IN_END,
__UBLK_IO_OP_DRV_OUT_END = 160,
};

#define UBLK_IO_F_FAILFAST_DEV (1U << 8)
#define UBLK_IO_F_FAILFAST_TRANSPORT (1U << 9)
Expand Down Expand Up @@ -257,6 +274,12 @@ struct ublk_param_devt {
__u32 disk_minor;
};

struct ublk_param_zoned {
__u32 max_open_zones;
__u32 max_active_zones;
__u8 reserved[24];
};

struct ublk_params {
/*
* Total length of parameters, userspace has to set 'len' for both
Expand All @@ -268,11 +291,13 @@ struct ublk_params {
#define UBLK_PARAM_TYPE_BASIC (1 << 0)
#define UBLK_PARAM_TYPE_DISCARD (1 << 1)
#define UBLK_PARAM_TYPE_DEVT (1 << 2)
#define UBLK_PARAM_TYPE_ZONED (1 << 3)
__u32 types; /* types of parameter included */

struct ublk_param_basic basic;
struct ublk_param_discard discard;
struct ublk_param_devt devt;
struct ublk_param_zoned zoned;
};

#endif
2 changes: 2 additions & 0 deletions include/ublksrv.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ struct ublksrv_tgt_info {
*/
unsigned int iowq_max_workers[2];

uint64_t zone_size_sectors;

unsigned long reserved[4];
};

Expand Down
7 changes: 6 additions & 1 deletion lib/ublksrv_json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,13 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(struct ublk_param_discard,
max_write_zeroes_sectors,
max_discard_segments,
reserved0)

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(struct ublk_param_zoned,
max_open_zones,
max_active_zones)

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(struct ublk_params,
len, types, basic, discard)
len, types, basic, discard, zoned)

int ublksrv_json_write_params(const struct ublk_params *p,
char *jbuf, int len)
Expand Down
126 changes: 125 additions & 1 deletion tgt_loop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

#include <config.h>

#include <linux/blkzoned.h>
#include <poll.h>
#include <stdint.h>
#include <sys/epoll.h>
#include "ublksrv_tgt.h"

Expand Down Expand Up @@ -150,6 +152,28 @@ static int loop_init_tgt(struct ublksrv_dev *dev, int type, int argc, char
return -2;
}

if (info->flags & UBLK_F_ZONED) {
uint32_t zone_size;
if (ioctl(fd, BLKGETZONESZ, &zone_size)) {
syslog(LOG_ERR, "%s: BLKGETSONESZ ioctl failed for %s\n", __func__, file);
return -1;
}

if (zone_size == 0) {
syslog(LOG_ERR, "%s: target %s is not zoned\n",
__func__, file);
return -1;
}

dev->tgt.zone_size_sectors = zone_size;

p.basic.chunk_sectors = zone_size;
p.types |= UBLK_PARAM_TYPE_ZONED;
/* TODO: lift these values from loop target */
p.zoned.max_open_zones = 14;
p.zoned.max_active_zones = 14;
}

if (fstat(fd, &st) < 0)
return -2;

Expand Down Expand Up @@ -305,12 +329,112 @@ static int loop_queue_tgt_io(const struct ublksrv_queue *q,
return 1;
}

static bool __loop_handle_report_zones(const struct ublksrv_queue *q,
const struct ublk_io_data *data, int tag)
{
const struct ublksrv_io_desc *iod = data->iod;
unsigned ublk_op = ublksrv_get_op(iod);

if (ublk_op == UBLK_IO_OP_REPORT_ZONES) {
struct blk_zone_report *report;
int ret = 0;
unsigned int nr_zones =
iod->nr_sectors / q->dev->tgt.zone_size_sectors;
struct blk_zone *zone_info = (struct blk_zone *)iod->addr;

report = (struct blk_zone_report *)malloc(
sizeof(struct blk_zone_report) +
sizeof(struct blk_zone) * nr_zones);

if (!report) {
syslog(LOG_ERR, "%s: failed to allocate", __func__);
ublksrv_complete_io(q, tag, -errno);
return true;
}

report->sector = iod->start_sector;
report->nr_zones = nr_zones;

ret = ioctl(q->dev->tgt.fds[1], BLKREPORTZONE, report);
if (ret) {
syslog(LOG_ERR, "%s: BLKREPORTZONE failed\n", __func__);
ret = -1;
goto out;
}

if (report->nr_zones == 0) {
/* Reporting zero length zone to indicate end */
memset(zone_info, 0, sizeof(*zone_info));
ret = -1;
goto out;
}

// TODO: write directly to io buffer
ret = sizeof(*zone_info) * report->nr_zones;

memcpy(zone_info, &report->zones[0], ret);

out:
free(report);
ublksrv_complete_io(q, tag, ret);
return true;
}

return false;
}

static bool __loop_handle_zone_ops(const struct ublksrv_queue *q,
const struct ublk_io_data *data, int tag)
{
const struct ublksrv_io_desc *iod = data->iod;
unsigned ublk_op = ublksrv_get_op(iod);
unsigned long ioctl_op = 0;
int ret;

switch (ublk_op) {
case UBLK_IO_OP_ZONE_OPEN:
ioctl_op = BLKOPENZONE;
break;
case UBLK_IO_OP_ZONE_CLOSE:
ioctl_op = BLKCLOSEZONE;
break;
case UBLK_IO_OP_ZONE_FINISH:
ioctl_op = BLKFINISHZONE;
break;
case UBLK_IO_OP_ZONE_RESET:
ioctl_op = BLKRESETZONE;
break;
}

if (ioctl_op) {
struct blk_zone_range range = {
.sector = iod->start_sector,
.nr_sectors = q->dev->tgt.zone_size_sectors,
};

ret = ioctl(q->dev->tgt.fds[1], ioctl_op, &range);

if (ret > 0) {
ret = 0;
}

ublksrv_complete_io(q, tag, ret);
return true;
}

return __loop_handle_report_zones(q, data, tag);
}

static co_io_job __loop_handle_io_async(const struct ublksrv_queue *q,
const struct ublk_io_data *data, int tag)
const struct ublk_io_data *data,
int tag)
{
int ret;
struct ublk_io_tgt *io = __ublk_get_io_tgt_data(data);

if (__loop_handle_zone_ops(q, data, tag))
co_return;

io->queued_tgt_io = 0;
again:
ret = loop_queue_tgt_io(q, data, tag);
Expand Down
57 changes: 55 additions & 2 deletions tgt_null.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: MIT or GPL-2.0-only

#include "ublksrv.h"
#include <config.h>
#include <linux/blkzoned.h>

#include "ublksrv_tgt.h"

Expand All @@ -11,11 +13,15 @@ static int null_init_tgt(struct ublksrv_dev *dev, int type, int argc,
const struct ublksrv_ctrl_dev_info *info =
ublksrv_ctrl_get_dev_info(ublksrv_get_ctrl_dev(dev));
int jbuf_size;
unsigned long zone_size = 128;
static const struct option longopts[] = {
{"zone-size", 1, NULL, 's'}, {NULL}};
int opt;
char *jbuf = ublksrv_tgt_return_json_buf(dev, &jbuf_size);
struct ublksrv_tgt_base_json tgt_json = {
.type = type,
};
unsigned long long dev_size = 250UL * 1024 * 1024 * 1024;
unsigned long long dev_size = (1024<<9) * 10;
struct ublk_params p = {
.types = UBLK_PARAM_TYPE_BASIC,
.basic = {
Expand All @@ -27,8 +33,24 @@ static int null_init_tgt(struct ublksrv_dev *dev, int type, int argc,
.dev_sectors = dev_size >> 9,
},
};
int ret;

if (info->flags & UBLK_F_ZONED) {
while ((opt = getopt_long(argc, argv, "-:s:", longopts, NULL)) != -1) {
switch (opt) {
case 's':
zone_size = strtol(optarg, NULL, 10);
break;
}
}

dev->tgt.zone_size_sectors = zone_size;
p.basic.chunk_sectors = zone_size;
p.types |= UBLK_PARAM_TYPE_ZONED;
p.zoned.max_open_zones = 14;
p.zoned.max_active_zones = 14;
}

int ret;
strcpy(tgt_json.name, "null");

if (type != UBLKSRV_TGT_TYPE_NULL)
Expand Down Expand Up @@ -83,6 +105,37 @@ static int null_recovery_tgt(struct ublksrv_dev *dev, int type)
static co_io_job __null_handle_io_async(const struct ublksrv_queue *q,
const struct ublk_io_data *data, int tag)
{
const struct ublksrv_io_desc *iod = data->iod;
unsigned ublk_op = ublksrv_get_op(iod);
uint64_t sector = iod->start_sector;
unsigned long zone_size = q->dev->tgt.zone_size_sectors;
unsigned long dev_sectors = q->dev->tgt.dev_size >> 9;

size_t zone_idx = sector / zone_size;
size_t num_zones = dev_sectors / zone_size;

if (ublk_op == UBLK_IO_OP_REPORT_ZONES) {
struct blk_zone *zone_info = (struct blk_zone *)iod->addr;

// Last zone
if (zone_idx == num_zones) {
/* Reporting zero length zone to indicate end */
memset(zone_info, 0, sizeof(*zone_info));
// TODO: error code
ublksrv_complete_io(q, tag, -1);
co_return;
}

zone_info->start = zone_idx * zone_size;
zone_info->len = zone_size;
zone_info->wp = 0;
zone_info->type = BLK_ZONE_TYPE_SEQWRITE_REQ;
zone_info->cond = 0;
zone_info->capacity = zone_size;

ublksrv_complete_io(q, tag, sizeof(*zone_info));
co_return;
}
ublksrv_complete_io(q, tag, data->iod->nr_sectors << 9);

co_return;
Expand Down
6 changes: 5 additions & 1 deletion ublksrv_tgt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,7 @@ static int cmd_dev_add(int argc, char *argv[])
{ "user_recovery_reissue", 1, NULL, 'i'},
{ "debug_mask", 1, NULL, 0},
{ "unprivileged", 0, NULL, 0},
{ "zoned", 0, NULL, 'x' },
{ NULL }
};
struct ublksrv_dev_data data = {0};
Expand All @@ -611,7 +612,7 @@ static int cmd_dev_add(int argc, char *argv[])

mkpath(data.run_dir);

while ((opt = getopt_long(argc, argv, "-:t:n:d:q:u:g:r:i:z",
while ((opt = getopt_long(argc, argv, "-:t:n:d:q:u:g:r:i:zxs:",
longopts, &option_index)) != -1) {
switch (opt) {
case 'n':
Expand Down Expand Up @@ -647,6 +648,9 @@ static int cmd_dev_add(int argc, char *argv[])
if (!strcmp(longopts[option_index].name, "unprivileged"))
unprivileged = 1;
break;
case 'x':
data.flags |= UBLK_F_ZONED;
break;
}
}

Expand Down

0 comments on commit 2c60b9f

Please sign in to comment.