684 changes: 644 additions & 40 deletions block/file-posix.c

Large diffs are not rendered by default.

68 changes: 68 additions & 0 deletions block/io.c
Expand Up @@ -3115,6 +3115,74 @@ int coroutine_fn bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf)
return co.ret;
}

int coroutine_fn bdrv_co_zone_report(BlockDriverState *bs, int64_t offset,
unsigned int *nr_zones,
BlockZoneDescriptor *zones)
{
BlockDriver *drv = bs->drv;
CoroutineIOCompletion co = {
.coroutine = qemu_coroutine_self(),
};
IO_CODE();

bdrv_inc_in_flight(bs);
if (!drv || !drv->bdrv_co_zone_report || bs->bl.zoned == BLK_Z_NONE) {
co.ret = -ENOTSUP;
goto out;
}
co.ret = drv->bdrv_co_zone_report(bs, offset, nr_zones, zones);
out:
bdrv_dec_in_flight(bs);
return co.ret;
}

int coroutine_fn bdrv_co_zone_mgmt(BlockDriverState *bs, BlockZoneOp op,
int64_t offset, int64_t len)
{
BlockDriver *drv = bs->drv;
CoroutineIOCompletion co = {
.coroutine = qemu_coroutine_self(),
};
IO_CODE();

bdrv_inc_in_flight(bs);
if (!drv || !drv->bdrv_co_zone_mgmt || bs->bl.zoned == BLK_Z_NONE) {
co.ret = -ENOTSUP;
goto out;
}
co.ret = drv->bdrv_co_zone_mgmt(bs, op, offset, len);
out:
bdrv_dec_in_flight(bs);
return co.ret;
}

int coroutine_fn bdrv_co_zone_append(BlockDriverState *bs, int64_t *offset,
QEMUIOVector *qiov,
BdrvRequestFlags flags)
{
int ret;
BlockDriver *drv = bs->drv;
CoroutineIOCompletion co = {
.coroutine = qemu_coroutine_self(),
};
IO_CODE();

ret = bdrv_check_qiov_request(*offset, qiov->size, qiov, 0, NULL);
if (ret < 0) {
return ret;
}

bdrv_inc_in_flight(bs);
if (!drv || !drv->bdrv_co_zone_append || bs->bl.zoned == BLK_Z_NONE) {
co.ret = -ENOTSUP;
goto out;
}
co.ret = drv->bdrv_co_zone_append(bs, offset, qiov, flags);
out:
bdrv_dec_in_flight(bs);
return co.ret;
}

void *qemu_blockalign(BlockDriverState *bs, size_t size)
{
IO_CODE();
Expand Down
4 changes: 4 additions & 0 deletions block/io_uring.c
Expand Up @@ -350,6 +350,10 @@ static int luring_do_submit(int fd, LuringAIOCB *luringcb, LuringState *s,
io_uring_prep_writev(sqes, fd, luringcb->qiov->iov,
luringcb->qiov->niov, offset);
break;
case QEMU_AIO_ZONE_APPEND:
io_uring_prep_writev(sqes, fd, luringcb->qiov->iov,
luringcb->qiov->niov, offset);
break;
case QEMU_AIO_READ:
io_uring_prep_readv(sqes, fd, luringcb->qiov->iov,
luringcb->qiov->niov, offset);
Expand Down
3 changes: 3 additions & 0 deletions block/linux-aio.c
Expand Up @@ -394,6 +394,9 @@ static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset,
case QEMU_AIO_WRITE:
io_prep_pwritev(iocbs, fd, qiov->iov, qiov->niov, offset);
break;
case QEMU_AIO_ZONE_APPEND:
io_prep_pwritev(iocbs, fd, qiov->iov, qiov->niov, offset);
break;
case QEMU_AIO_READ:
io_prep_preadv(iocbs, fd, qiov->iov, qiov->niov, offset);
break;
Expand Down
11 changes: 11 additions & 0 deletions block/qapi-sysemu.c
Expand Up @@ -517,6 +517,7 @@ void qmp_block_latency_histogram_set(
bool has_boundaries, uint64List *boundaries,
bool has_boundaries_read, uint64List *boundaries_read,
bool has_boundaries_write, uint64List *boundaries_write,
bool has_boundaries_append, uint64List *boundaries_append,
bool has_boundaries_flush, uint64List *boundaries_flush,
Error **errp)
{
Expand Down Expand Up @@ -557,6 +558,16 @@ void qmp_block_latency_histogram_set(
}
}

if (has_boundaries || has_boundaries_append) {
ret = block_latency_histogram_set(
stats, BLOCK_ACCT_ZONE_APPEND,
has_boundaries_append ? boundaries_append : boundaries);
if (ret) {
error_setg(errp, "Device '%s' set append write boundaries fail", id);
return;
}
}

if (has_boundaries || has_boundaries_flush) {
ret = block_latency_histogram_set(
stats, BLOCK_ACCT_FLUSH,
Expand Down
18 changes: 18 additions & 0 deletions block/qapi.c
Expand Up @@ -533,27 +533,36 @@ static void bdrv_query_blk_stats(BlockDeviceStats *ds, BlockBackend *blk)

ds->rd_bytes = stats->nr_bytes[BLOCK_ACCT_READ];
ds->wr_bytes = stats->nr_bytes[BLOCK_ACCT_WRITE];
ds->zone_append_bytes = stats->nr_bytes[BLOCK_ACCT_ZONE_APPEND];
ds->unmap_bytes = stats->nr_bytes[BLOCK_ACCT_UNMAP];
ds->rd_operations = stats->nr_ops[BLOCK_ACCT_READ];
ds->wr_operations = stats->nr_ops[BLOCK_ACCT_WRITE];
ds->zone_append_operations = stats->nr_ops[BLOCK_ACCT_ZONE_APPEND];
ds->unmap_operations = stats->nr_ops[BLOCK_ACCT_UNMAP];

ds->failed_rd_operations = stats->failed_ops[BLOCK_ACCT_READ];
ds->failed_wr_operations = stats->failed_ops[BLOCK_ACCT_WRITE];
ds->failed_zone_append_operations =
stats->failed_ops[BLOCK_ACCT_ZONE_APPEND];
ds->failed_flush_operations = stats->failed_ops[BLOCK_ACCT_FLUSH];
ds->failed_unmap_operations = stats->failed_ops[BLOCK_ACCT_UNMAP];

ds->invalid_rd_operations = stats->invalid_ops[BLOCK_ACCT_READ];
ds->invalid_wr_operations = stats->invalid_ops[BLOCK_ACCT_WRITE];
ds->invalid_zone_append_operations =
stats->invalid_ops[BLOCK_ACCT_ZONE_APPEND];
ds->invalid_flush_operations =
stats->invalid_ops[BLOCK_ACCT_FLUSH];
ds->invalid_unmap_operations = stats->invalid_ops[BLOCK_ACCT_UNMAP];

ds->rd_merged = stats->merged[BLOCK_ACCT_READ];
ds->wr_merged = stats->merged[BLOCK_ACCT_WRITE];
ds->zone_append_merged = stats->merged[BLOCK_ACCT_ZONE_APPEND];
ds->unmap_merged = stats->merged[BLOCK_ACCT_UNMAP];
ds->flush_operations = stats->nr_ops[BLOCK_ACCT_FLUSH];
ds->wr_total_time_ns = stats->total_time_ns[BLOCK_ACCT_WRITE];
ds->zone_append_total_time_ns =
stats->total_time_ns[BLOCK_ACCT_ZONE_APPEND];
ds->rd_total_time_ns = stats->total_time_ns[BLOCK_ACCT_READ];
ds->flush_total_time_ns = stats->total_time_ns[BLOCK_ACCT_FLUSH];
ds->unmap_total_time_ns = stats->total_time_ns[BLOCK_ACCT_UNMAP];
Expand All @@ -571,6 +580,7 @@ static void bdrv_query_blk_stats(BlockDeviceStats *ds, BlockBackend *blk)

TimedAverage *rd = &ts->latency[BLOCK_ACCT_READ];
TimedAverage *wr = &ts->latency[BLOCK_ACCT_WRITE];
TimedAverage *zap = &ts->latency[BLOCK_ACCT_ZONE_APPEND];
TimedAverage *fl = &ts->latency[BLOCK_ACCT_FLUSH];

dev_stats->interval_length = ts->interval_length;
Expand All @@ -583,6 +593,10 @@ static void bdrv_query_blk_stats(BlockDeviceStats *ds, BlockBackend *blk)
dev_stats->max_wr_latency_ns = timed_average_max(wr);
dev_stats->avg_wr_latency_ns = timed_average_avg(wr);

dev_stats->min_zone_append_latency_ns = timed_average_min(zap);
dev_stats->max_zone_append_latency_ns = timed_average_max(zap);
dev_stats->avg_zone_append_latency_ns = timed_average_avg(zap);

dev_stats->min_flush_latency_ns = timed_average_min(fl);
dev_stats->max_flush_latency_ns = timed_average_max(fl);
dev_stats->avg_flush_latency_ns = timed_average_avg(fl);
Expand All @@ -591,6 +605,8 @@ static void bdrv_query_blk_stats(BlockDeviceStats *ds, BlockBackend *blk)
block_acct_queue_depth(ts, BLOCK_ACCT_READ);
dev_stats->avg_wr_queue_depth =
block_acct_queue_depth(ts, BLOCK_ACCT_WRITE);
dev_stats->avg_zone_append_queue_depth =
block_acct_queue_depth(ts, BLOCK_ACCT_ZONE_APPEND);

QAPI_LIST_PREPEND(ds->timed_stats, dev_stats);
}
Expand All @@ -600,6 +616,8 @@ static void bdrv_query_blk_stats(BlockDeviceStats *ds, BlockBackend *blk)
= bdrv_latency_histogram_stats(&hgram[BLOCK_ACCT_READ]);
ds->wr_latency_histogram
= bdrv_latency_histogram_stats(&hgram[BLOCK_ACCT_WRITE]);
ds->zone_append_latency_histogram
= bdrv_latency_histogram_stats(&hgram[BLOCK_ACCT_ZONE_APPEND]);
ds->flush_latency_histogram
= bdrv_latency_histogram_stats(&hgram[BLOCK_ACCT_FLUSH]);
}
Expand Down
26 changes: 26 additions & 0 deletions block/raw-format.c
Expand Up @@ -317,6 +317,28 @@ raw_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
return bdrv_co_pdiscard(bs->file, offset, bytes);
}

static int coroutine_fn GRAPH_RDLOCK
raw_co_zone_report(BlockDriverState *bs, int64_t offset,
unsigned int *nr_zones,
BlockZoneDescriptor *zones)
{
return bdrv_co_zone_report(bs->file->bs, offset, nr_zones, zones);
}

static int coroutine_fn GRAPH_RDLOCK
raw_co_zone_mgmt(BlockDriverState *bs, BlockZoneOp op,
int64_t offset, int64_t len)
{
return bdrv_co_zone_mgmt(bs->file->bs, op, offset, len);
}

static int coroutine_fn GRAPH_RDLOCK
raw_co_zone_append(BlockDriverState *bs,int64_t *offset, QEMUIOVector *qiov,
BdrvRequestFlags flags)
{
return bdrv_co_zone_append(bs->file->bs, offset, qiov, flags);
}

static int64_t coroutine_fn GRAPH_RDLOCK
raw_co_getlength(BlockDriverState *bs)
{
Expand Down Expand Up @@ -608,6 +630,7 @@ static void raw_child_perm(BlockDriverState *bs, BdrvChild *c,
BlockDriver bdrv_raw = {
.format_name = "raw",
.instance_size = sizeof(BDRVRawState),
.supports_zoned_children = true,
.bdrv_probe = &raw_probe,
.bdrv_reopen_prepare = &raw_reopen_prepare,
.bdrv_reopen_commit = &raw_reopen_commit,
Expand All @@ -619,6 +642,9 @@ BlockDriver bdrv_raw = {
.bdrv_co_pwritev = &raw_co_pwritev,
.bdrv_co_pwrite_zeroes = &raw_co_pwrite_zeroes,
.bdrv_co_pdiscard = &raw_co_pdiscard,
.bdrv_co_zone_report = &raw_co_zone_report,
.bdrv_co_zone_mgmt = &raw_co_zone_mgmt,
.bdrv_co_zone_append = &raw_co_zone_append,
.bdrv_co_block_status = &raw_co_block_status,
.bdrv_co_copy_range_from = &raw_co_copy_range_from,
.bdrv_co_copy_range_to = &raw_co_copy_range_to,
Expand Down
4 changes: 4 additions & 0 deletions block/trace-events
Expand Up @@ -209,6 +209,10 @@ file_FindEjectableOpticalMedia(const char *media) "Matching using %s"
file_setup_cdrom(const char *partition) "Using %s as optical disc"
file_hdev_is_sg(int type, int version) "SG device found: type=%d, version=%d"
file_flush_fdatasync_failed(int err) "errno %d"
zbd_zone_report(void *bs, unsigned int nr_zones, int64_t sector) "bs %p report %d zones starting at sector offset 0x%" PRIx64 ""
zbd_zone_mgmt(void *bs, const char *op_name, int64_t sector, int64_t len) "bs %p %s starts at sector offset 0x%" PRIx64 " over a range of 0x%" PRIx64 " sectors"
zbd_zone_append(void *bs, int64_t sector) "bs %p append at sector offset 0x%" PRIx64 ""
zbd_zone_append_complete(void *bs, int64_t sector) "bs %p returns append sector 0x%" PRIx64 ""

# ssh.c
sftp_error(const char *op, const char *ssh_err, int ssh_err_code, int sftp_err_code) "%s failed: %s (libssh error code: %d, sftp error code: %d)"
1 change: 1 addition & 0 deletions docs/devel/index-api.rst
Expand Up @@ -12,3 +12,4 @@ generated from in-code annotations to function prototypes.
memory
modules
ui
zoned-storage
62 changes: 62 additions & 0 deletions docs/devel/zoned-storage.rst
@@ -0,0 +1,62 @@
=============
zoned-storage
=============

Zoned Block Devices (ZBDs) divide the LBA space into block regions called zones
that are larger than the LBA size. They can only allow sequential writes, which
can reduce write amplification in SSDs, and potentially lead to higher
throughput and increased capacity. More details about ZBDs can be found at:

https://zonedstorage.io/docs/introduction/zoned-storage

1. Block layer APIs for zoned storage
-------------------------------------
QEMU block layer supports three zoned storage models:
- BLK_Z_HM: The host-managed zoned model only allows sequential writes access
to zones. It supports ZBD-specific I/O commands that can be used by a host to
manage the zones of a device.
- BLK_Z_HA: The host-aware zoned model allows random write operations in
zones, making it backward compatible with regular block devices.
- BLK_Z_NONE: The non-zoned model has no zones support. It includes both
regular and drive-managed ZBD devices. ZBD-specific I/O commands are not
supported.

The block device information resides inside BlockDriverState. QEMU uses
BlockLimits struct(BlockDriverState::bl) that is continuously accessed by the
block layer while processing I/O requests. A BlockBackend has a root pointer to
a BlockDriverState graph(for example, raw format on top of file-posix). The
zoned storage information can be propagated from the leaf BlockDriverState all
the way up to the BlockBackend. If the zoned storage model in file-posix is
set to BLK_Z_HM, then block drivers will declare support for zoned host device.

The block layer APIs support commands needed for zoned storage devices,
including report zones, four zone operations, and zone append.

2. Emulating zoned storage controllers
--------------------------------------
When the BlockBackend's BlockLimits model reports a zoned storage device, users
like the virtio-blk emulation or the qemu-io-cmds.c utility can use block layer
APIs for zoned storage emulation or testing.

For example, to test zone_report on a null_blk device using qemu-io is::

$ path/to/qemu-io --image-opts -n driver=host_device,filename=/dev/nullb0 -c "zrp offset nr_zones"

To expose the host's zoned block device through virtio-blk, the command line
can be (includes the -device parameter)::

-blockdev node-name=drive0,driver=host_device,filename=/dev/nullb0,cache.direct=on \
-device virtio-blk-pci,drive=drive0

Or only use the -drive parameter::

-driver driver=host_device,file=/dev/nullb0,if=virtio,cache.direct=on

Additionally, QEMU has several ways of supporting zoned storage, including:
(1) Using virtio-scsi: --device scsi-block allows for the passing through of
SCSI ZBC devices, enabling the attachment of ZBC or ZAC HDDs to QEMU.
(2) PCI device pass-through: While NVMe ZNS emulation is available for testing
purposes, it cannot yet pass through a zoned device from the host. To pass on
the NVMe ZNS device to the guest, use VFIO PCI pass the entire NVMe PCI adapter
through to the guest. Likewise, an HDD HBA can be passed on to QEMU all HDDs
attached to the HBA.
6 changes: 6 additions & 0 deletions docs/system/qemu-block-drivers.rst.inc
Expand Up @@ -430,6 +430,12 @@ Hard disks
you may corrupt your host data (use the ``-snapshot`` command
line option or modify the device permissions accordingly).

Zoned block devices
Zoned block devices can be passed through to the guest if the emulated storage
controller supports zoned storage. Use ``--blockdev host_device,
node-name=drive0,filename=/dev/nullb0,cache.direct=on`` to pass through
``/dev/nullb0`` as ``drive0``.

Windows
^^^^^^^

Expand Down
7 changes: 7 additions & 0 deletions hw/block/trace-events
Expand Up @@ -44,9 +44,16 @@ pflash_write_unknown(const char *name, uint8_t cmd) "%s: unknown command 0x%02x"
# virtio-blk.c
virtio_blk_req_complete(void *vdev, void *req, int status) "vdev %p req %p status %d"
virtio_blk_rw_complete(void *vdev, void *req, int ret) "vdev %p req %p ret %d"
virtio_blk_zone_report_complete(void *vdev, void *req, unsigned int nr_zones, int ret) "vdev %p req %p nr_zones %u ret %d"
virtio_blk_zone_mgmt_complete(void *vdev, void *req, int ret) "vdev %p req %p ret %d"
virtio_blk_zone_append_complete(void *vdev, void *req, int64_t sector, int ret) "vdev %p req %p, append sector 0x%" PRIx64 " ret %d"
virtio_blk_handle_write(void *vdev, void *req, uint64_t sector, size_t nsectors) "vdev %p req %p sector %"PRIu64" nsectors %zu"
virtio_blk_handle_read(void *vdev, void *req, uint64_t sector, size_t nsectors) "vdev %p req %p sector %"PRIu64" nsectors %zu"
virtio_blk_submit_multireq(void *vdev, void *mrb, int start, int num_reqs, uint64_t offset, size_t size, bool is_write) "vdev %p mrb %p start %d num_reqs %d offset %"PRIu64" size %zu is_write %d"
virtio_blk_handle_zone_report(void *vdev, void *req, int64_t sector, unsigned int nr_zones) "vdev %p req %p sector 0x%" PRIx64 " nr_zones %u"
virtio_blk_handle_zone_mgmt(void *vdev, void *req, uint8_t op, int64_t sector, int64_t len) "vdev %p req %p op 0x%x sector 0x%" PRIx64 " len 0x%" PRIx64 ""
virtio_blk_handle_zone_reset_all(void *vdev, void *req, int64_t sector, int64_t len) "vdev %p req %p sector 0x%" PRIx64 " cap 0x%" PRIx64 ""
virtio_blk_handle_zone_append(void *vdev, void *req, int64_t sector) "vdev %p req %p, append sector 0x%" PRIx64 ""

# hd-geometry.c
hd_geometry_lchs_guess(void *blk, int cyls, int heads, int secs) "blk %p LCHS %d %d %d"
Expand Down
2 changes: 2 additions & 0 deletions hw/block/virtio-blk-common.c
Expand Up @@ -29,6 +29,8 @@ static const VirtIOFeature feature_sizes[] = {
.end = endof(struct virtio_blk_config, discard_sector_alignment)},
{.flags = 1ULL << VIRTIO_BLK_F_WRITE_ZEROES,
.end = endof(struct virtio_blk_config, write_zeroes_may_unmap)},
{.flags = 1ULL << VIRTIO_BLK_F_ZONED,
.end = endof(struct virtio_blk_config, zoned)},
{}
};

Expand Down
405 changes: 405 additions & 0 deletions hw/block/virtio-blk.c

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions hw/virtio/virtio-qmp.c
Expand Up @@ -176,6 +176,8 @@ static const qmp_virtio_feature_map_t virtio_blk_feature_map[] = {
"VIRTIO_BLK_F_DISCARD: Discard command supported"),
FEATURE_ENTRY(VIRTIO_BLK_F_WRITE_ZEROES, \
"VIRTIO_BLK_F_WRITE_ZEROES: Write zeroes command supported"),
FEATURE_ENTRY(VIRTIO_BLK_F_ZONED, \
"VIRTIO_BLK_F_ZONED: Zoned block devices"),
#ifndef VIRTIO_BLK_NO_LEGACY
FEATURE_ENTRY(VIRTIO_BLK_F_BARRIER, \
"VIRTIO_BLK_F_BARRIER: Request barriers supported"),
Expand Down
1 change: 1 addition & 0 deletions include/block/accounting.h
Expand Up @@ -37,6 +37,7 @@ enum BlockAcctType {
BLOCK_ACCT_READ,
BLOCK_ACCT_WRITE,
BLOCK_ACCT_FLUSH,
BLOCK_ACCT_ZONE_APPEND,
BLOCK_ACCT_UNMAP,
BLOCK_MAX_IOTYPE,
};
Expand Down
57 changes: 57 additions & 0 deletions include/block/block-common.h
Expand Up @@ -75,6 +75,57 @@ typedef struct BlockDriver BlockDriver;
typedef struct BdrvChild BdrvChild;
typedef struct BdrvChildClass BdrvChildClass;

typedef enum BlockZoneOp {
BLK_ZO_OPEN,
BLK_ZO_CLOSE,
BLK_ZO_FINISH,
BLK_ZO_RESET,
} BlockZoneOp;

typedef enum BlockZoneModel {
BLK_Z_NONE = 0x0, /* Regular block device */
BLK_Z_HM = 0x1, /* Host-managed zoned block device */
BLK_Z_HA = 0x2, /* Host-aware zoned block device */
} BlockZoneModel;

typedef enum BlockZoneState {
BLK_ZS_NOT_WP = 0x0,
BLK_ZS_EMPTY = 0x1,
BLK_ZS_IOPEN = 0x2,
BLK_ZS_EOPEN = 0x3,
BLK_ZS_CLOSED = 0x4,
BLK_ZS_RDONLY = 0xD,
BLK_ZS_FULL = 0xE,
BLK_ZS_OFFLINE = 0xF,
} BlockZoneState;

typedef enum BlockZoneType {
BLK_ZT_CONV = 0x1, /* Conventional random writes supported */
BLK_ZT_SWR = 0x2, /* Sequential writes required */
BLK_ZT_SWP = 0x3, /* Sequential writes preferred */
} BlockZoneType;

/*
* Zone descriptor data structure.
* Provides information on a zone with all position and size values in bytes.
*/
typedef struct BlockZoneDescriptor {
uint64_t start;
uint64_t length;
uint64_t cap;
uint64_t wp;
BlockZoneType type;
BlockZoneState state;
} BlockZoneDescriptor;

/*
* Track write pointers of a zone in bytes.
*/
typedef struct BlockZoneWps {
CoMutex colock;
uint64_t wp[];
} BlockZoneWps;

typedef struct BlockDriverInfo {
/* in bytes, 0 if irrelevant */
int cluster_size;
Expand Down Expand Up @@ -197,6 +248,12 @@ typedef enum {
#define BDRV_SECTOR_BITS 9
#define BDRV_SECTOR_SIZE (1ULL << BDRV_SECTOR_BITS)

/*
* Get the first most significant bit of wp. If it is zero, then
* the zone type is SWR.
*/
#define BDRV_ZT_IS_CONV(wp) (wp & (1ULL << 63))

#define BDRV_REQUEST_MAX_SECTORS MIN_CONST(SIZE_MAX >> BDRV_SECTOR_BITS, \
INT_MAX >> BDRV_SECTOR_BITS)
#define BDRV_REQUEST_MAX_BYTES (BDRV_REQUEST_MAX_SECTORS << BDRV_SECTOR_BITS)
Expand Down
13 changes: 13 additions & 0 deletions include/block/block-io.h
Expand Up @@ -111,6 +111,19 @@ int coroutine_fn GRAPH_RDLOCK bdrv_co_flush(BlockDriverState *bs);
int coroutine_fn GRAPH_RDLOCK bdrv_co_pdiscard(BdrvChild *child, int64_t offset,
int64_t bytes);

/* Report zone information of zone block device. */
int coroutine_fn GRAPH_RDLOCK bdrv_co_zone_report(BlockDriverState *bs,
int64_t offset,
unsigned int *nr_zones,
BlockZoneDescriptor *zones);
int coroutine_fn GRAPH_RDLOCK bdrv_co_zone_mgmt(BlockDriverState *bs,
BlockZoneOp op,
int64_t offset, int64_t len);
int coroutine_fn GRAPH_RDLOCK bdrv_co_zone_append(BlockDriverState *bs,
int64_t *offset,
QEMUIOVector *qiov,
BdrvRequestFlags flags);

bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs);
int bdrv_block_status(BlockDriverState *bs, int64_t offset,
int64_t bytes, int64_t *pnum, int64_t *map,
Expand Down
37 changes: 37 additions & 0 deletions include/block/block_int-common.h
Expand Up @@ -137,6 +137,11 @@ struct BlockDriver {
*/
bool is_format;

/*
* Set to true if the BlockDriver supports zoned children.
*/
bool supports_zoned_children;

/*
* Drivers not implementing bdrv_parse_filename nor bdrv_open should have
* this field set to true, except ones that are defined only by their
Expand Down Expand Up @@ -712,6 +717,15 @@ struct BlockDriver {
int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_load_vmstate)(
BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos);

int coroutine_fn (*bdrv_co_zone_report)(BlockDriverState *bs,
int64_t offset, unsigned int *nr_zones,
BlockZoneDescriptor *zones);
int coroutine_fn (*bdrv_co_zone_mgmt)(BlockDriverState *bs, BlockZoneOp op,
int64_t offset, int64_t len);
int coroutine_fn (*bdrv_co_zone_append)(BlockDriverState *bs,
int64_t *offset, QEMUIOVector *qiov,
BdrvRequestFlags flags);

/* removable device specific */
bool coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_is_inserted)(
BlockDriverState *bs);
Expand Down Expand Up @@ -861,6 +875,26 @@ typedef struct BlockLimits {
* an explicit monitor command to load the disk inside the guest).
*/
bool has_variable_length;

/* device zone model */
BlockZoneModel zoned;

/* zone size expressed in bytes */
uint32_t zone_size;

/* total number of zones */
uint32_t nr_zones;

/* maximum sectors of a zone append write operation */
int64_t max_append_sectors;

/* maximum number of open zones */
int64_t max_open_zones;

/* maximum number of active zones */
int64_t max_active_zones;

int64_t write_granularity;
} BlockLimits;

typedef struct BdrvOpBlocker BdrvOpBlocker;
Expand Down Expand Up @@ -1222,6 +1256,9 @@ struct BlockDriverState {
CoMutex bsc_modify_lock;
/* Always non-NULL, but must only be dereferenced under an RCU read guard */
BdrvBlockStatusCache *block_status_cache;

/* array of write pointers' location of each zone in the zoned device. */
BlockZoneWps *wps;
};

struct BlockBackendRootState {
Expand Down
8 changes: 7 additions & 1 deletion include/block/raw-aio.h
Expand Up @@ -28,6 +28,9 @@
#define QEMU_AIO_WRITE_ZEROES 0x0020
#define QEMU_AIO_COPY_RANGE 0x0040
#define QEMU_AIO_TRUNCATE 0x0080
#define QEMU_AIO_ZONE_REPORT 0x0100
#define QEMU_AIO_ZONE_MGMT 0x0200
#define QEMU_AIO_ZONE_APPEND 0x0400
#define QEMU_AIO_TYPE_MASK \
(QEMU_AIO_READ | \
QEMU_AIO_WRITE | \
Expand All @@ -36,7 +39,10 @@
QEMU_AIO_DISCARD | \
QEMU_AIO_WRITE_ZEROES | \
QEMU_AIO_COPY_RANGE | \
QEMU_AIO_TRUNCATE)
QEMU_AIO_TRUNCATE | \
QEMU_AIO_ZONE_REPORT | \
QEMU_AIO_ZONE_MGMT | \
QEMU_AIO_ZONE_APPEND)

/* AIO flags */
#define QEMU_AIO_MISALIGNED 0x1000
Expand Down
12 changes: 12 additions & 0 deletions include/standard-headers/drm/drm_fourcc.h
Expand Up @@ -87,6 +87,18 @@ extern "C" {
*
* The authoritative list of format modifier codes is found in
* `include/uapi/drm/drm_fourcc.h`
*
* Open Source User Waiver
* -----------------------
*
* Because this is the authoritative source for pixel formats and modifiers
* referenced by GL, Vulkan extensions and other standards and hence used both
* by open source and closed source driver stacks, the usual requirement for an
* upstream in-kernel or open source userspace user does not apply.
*
* To ensure, as much as feasible, compatibility across stacks and avoid
* confusion with incompatible enumerations stakeholders for all relevant driver
* stacks should approve additions.
*/

#define fourcc_code(a, b, c, d) ((uint32_t)(a) | ((uint32_t)(b) << 8) | \
Expand Down
48 changes: 47 additions & 1 deletion include/standard-headers/linux/ethtool.h
Expand Up @@ -711,6 +711,24 @@ enum ethtool_stringset {
ETH_SS_COUNT
};

/**
* enum ethtool_mac_stats_src - source of ethtool MAC statistics
* @ETHTOOL_MAC_STATS_SRC_AGGREGATE:
* if device supports a MAC merge layer, this retrieves the aggregate
* statistics of the eMAC and pMAC. Otherwise, it retrieves just the
* statistics of the single (express) MAC.
* @ETHTOOL_MAC_STATS_SRC_EMAC:
* if device supports a MM layer, this retrieves the eMAC statistics.
* Otherwise, it retrieves the statistics of the single (express) MAC.
* @ETHTOOL_MAC_STATS_SRC_PMAC:
* if device supports a MM layer, this retrieves the pMAC statistics.
*/
enum ethtool_mac_stats_src {
ETHTOOL_MAC_STATS_SRC_AGGREGATE,
ETHTOOL_MAC_STATS_SRC_EMAC,
ETHTOOL_MAC_STATS_SRC_PMAC,
};

/**
* enum ethtool_module_power_mode_policy - plug-in module power mode policy
* @ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH: Module is always in high power mode.
Expand Down Expand Up @@ -779,6 +797,31 @@ enum ethtool_podl_pse_pw_d_status {
ETHTOOL_PODL_PSE_PW_D_STATUS_ERROR,
};

/**
* enum ethtool_mm_verify_status - status of MAC Merge Verify function
* @ETHTOOL_MM_VERIFY_STATUS_UNKNOWN:
* verification status is unknown
* @ETHTOOL_MM_VERIFY_STATUS_INITIAL:
* the 802.3 Verify State diagram is in the state INIT_VERIFICATION
* @ETHTOOL_MM_VERIFY_STATUS_VERIFYING:
* the Verify State diagram is in the state VERIFICATION_IDLE,
* SEND_VERIFY or WAIT_FOR_RESPONSE
* @ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED:
* indicates that the Verify State diagram is in the state VERIFIED
* @ETHTOOL_MM_VERIFY_STATUS_FAILED:
* the Verify State diagram is in the state VERIFY_FAIL
* @ETHTOOL_MM_VERIFY_STATUS_DISABLED:
* verification of preemption operation is disabled
*/
enum ethtool_mm_verify_status {
ETHTOOL_MM_VERIFY_STATUS_UNKNOWN,
ETHTOOL_MM_VERIFY_STATUS_INITIAL,
ETHTOOL_MM_VERIFY_STATUS_VERIFYING,
ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED,
ETHTOOL_MM_VERIFY_STATUS_FAILED,
ETHTOOL_MM_VERIFY_STATUS_DISABLED,
};

/**
* struct ethtool_gstrings - string set for data tagging
* @cmd: Command number = %ETHTOOL_GSTRINGS
Expand Down Expand Up @@ -1183,7 +1226,7 @@ struct ethtool_rxnfc {
uint32_t rule_cnt;
uint32_t rss_context;
};
uint32_t rule_locs[0];
uint32_t rule_locs[];
};


Expand Down Expand Up @@ -1741,6 +1784,9 @@ enum ethtool_link_mode_bit_indices {
ETHTOOL_LINK_MODE_800000baseDR8_2_Full_BIT = 96,
ETHTOOL_LINK_MODE_800000baseSR8_Full_BIT = 97,
ETHTOOL_LINK_MODE_800000baseVR8_Full_BIT = 98,
ETHTOOL_LINK_MODE_10baseT1S_Full_BIT = 99,
ETHTOOL_LINK_MODE_10baseT1S_Half_BIT = 100,
ETHTOOL_LINK_MODE_10baseT1S_P2MP_Half_BIT = 101,

/* must be last entry */
__ETHTOOL_LINK_MODE_MASK_NBITS
Expand Down
45 changes: 44 additions & 1 deletion include/standard-headers/linux/fuse.h
Expand Up @@ -201,6 +201,11 @@
* 7.38
* - add FUSE_EXPIRE_ONLY flag to fuse_notify_inval_entry
* - add FOPEN_PARALLEL_DIRECT_WRITES
* - add total_extlen to fuse_in_header
* - add FUSE_MAX_NR_SECCTX
* - add extension header
* - add FUSE_EXT_GROUPS
* - add FUSE_CREATE_SUPP_GROUP
*/

#ifndef _LINUX_FUSE_H
Expand Down Expand Up @@ -358,6 +363,8 @@ struct fuse_file_lock {
* FUSE_SECURITY_CTX: add security context to create, mkdir, symlink, and
* mknod
* FUSE_HAS_INODE_DAX: use per inode DAX
* FUSE_CREATE_SUPP_GROUP: add supplementary group info to create, mkdir,
* symlink and mknod (single group that matches parent)
*/
#define FUSE_ASYNC_READ (1 << 0)
#define FUSE_POSIX_LOCKS (1 << 1)
Expand Down Expand Up @@ -394,6 +401,7 @@ struct fuse_file_lock {
/* bits 32..63 get shifted down 32 bits into the flags2 field */
#define FUSE_SECURITY_CTX (1ULL << 32)
#define FUSE_HAS_INODE_DAX (1ULL << 33)
#define FUSE_CREATE_SUPP_GROUP (1ULL << 34)

/**
* CUSE INIT request/reply flags
Expand Down Expand Up @@ -499,6 +507,17 @@ struct fuse_file_lock {
*/
#define FUSE_EXPIRE_ONLY (1 << 0)

/**
* extension type
* FUSE_MAX_NR_SECCTX: maximum value of &fuse_secctx_header.nr_secctx
* FUSE_EXT_GROUPS: &fuse_supp_groups extension
*/
enum fuse_ext_type {
/* Types 0..31 are reserved for fuse_secctx_header */
FUSE_MAX_NR_SECCTX = 31,
FUSE_EXT_GROUPS = 32,
};

enum fuse_opcode {
FUSE_LOOKUP = 1,
FUSE_FORGET = 2, /* no reply */
Expand Down Expand Up @@ -882,7 +901,8 @@ struct fuse_in_header {
uint32_t uid;
uint32_t gid;
uint32_t pid;
uint32_t padding;
uint16_t total_extlen; /* length of extensions in 8byte units */
uint16_t padding;
};

struct fuse_out_header {
Expand Down Expand Up @@ -1043,4 +1063,27 @@ struct fuse_secctx_header {
uint32_t nr_secctx;
};

/**
* struct fuse_ext_header - extension header
* @size: total size of this extension including this header
* @type: type of extension
*
* This is made compatible with fuse_secctx_header by using type values >
* FUSE_MAX_NR_SECCTX
*/
struct fuse_ext_header {
uint32_t size;
uint32_t type;
};

/**
* struct fuse_supp_groups - Supplementary group extension
* @nr_groups: number of supplementary groups
* @groups: flexible array of group IDs
*/
struct fuse_supp_groups {
uint32_t nr_groups;
uint32_t groups[];
};

#endif /* _LINUX_FUSE_H */
1 change: 1 addition & 0 deletions include/standard-headers/linux/pci_regs.h
Expand Up @@ -693,6 +693,7 @@
#define PCI_EXP_LNKCTL2_TX_MARGIN 0x0380 /* Transmit Margin */
#define PCI_EXP_LNKCTL2_HASD 0x0020 /* HW Autonomous Speed Disable */
#define PCI_EXP_LNKSTA2 0x32 /* Link Status 2 */
#define PCI_EXP_LNKSTA2_FLIT 0x0400 /* Flit Mode Status */
#define PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 0x32 /* end of v2 EPs w/ link */
#define PCI_EXP_SLTCAP2 0x34 /* Slot Capabilities 2 */
#define PCI_EXP_SLTCAP2_IBPD 0x00000001 /* In-band PD Disable Supported */
Expand Down
2 changes: 2 additions & 0 deletions include/standard-headers/linux/vhost_types.h
Expand Up @@ -163,5 +163,7 @@ struct vhost_vdpa_iova_range {
#define VHOST_BACKEND_F_IOTLB_ASID 0x3
/* Device can be suspended */
#define VHOST_BACKEND_F_SUSPEND 0x4
/* Device can be resumed */
#define VHOST_BACKEND_F_RESUME 0x5

#endif
105 changes: 105 additions & 0 deletions include/standard-headers/linux/virtio_blk.h
Expand Up @@ -41,6 +41,7 @@
#define VIRTIO_BLK_F_DISCARD 13 /* DISCARD is supported */
#define VIRTIO_BLK_F_WRITE_ZEROES 14 /* WRITE ZEROES is supported */
#define VIRTIO_BLK_F_SECURE_ERASE 16 /* Secure Erase is supported */
#define VIRTIO_BLK_F_ZONED 17 /* Zoned block device */

/* Legacy feature bits */
#ifndef VIRTIO_BLK_NO_LEGACY
Expand Down Expand Up @@ -135,6 +136,16 @@ struct virtio_blk_config {
/* Secure erase commands must be aligned to this number of sectors. */
__virtio32 secure_erase_sector_alignment;

/* Zoned block device characteristics (if VIRTIO_BLK_F_ZONED) */
struct virtio_blk_zoned_characteristics {
__virtio32 zone_sectors;
__virtio32 max_open_zones;
__virtio32 max_active_zones;
__virtio32 max_append_sectors;
__virtio32 write_granularity;
uint8_t model;
uint8_t unused2[3];
} zoned;
} QEMU_PACKED;

/*
Expand Down Expand Up @@ -172,6 +183,27 @@ struct virtio_blk_config {
/* Secure erase command */
#define VIRTIO_BLK_T_SECURE_ERASE 14

/* Zone append command */
#define VIRTIO_BLK_T_ZONE_APPEND 15

/* Report zones command */
#define VIRTIO_BLK_T_ZONE_REPORT 16

/* Open zone command */
#define VIRTIO_BLK_T_ZONE_OPEN 18

/* Close zone command */
#define VIRTIO_BLK_T_ZONE_CLOSE 20

/* Finish zone command */
#define VIRTIO_BLK_T_ZONE_FINISH 22

/* Reset zone command */
#define VIRTIO_BLK_T_ZONE_RESET 24

/* Reset All zones command */
#define VIRTIO_BLK_T_ZONE_RESET_ALL 26

#ifndef VIRTIO_BLK_NO_LEGACY
/* Barrier before this op. */
#define VIRTIO_BLK_T_BARRIER 0x80000000
Expand All @@ -191,6 +223,72 @@ struct virtio_blk_outhdr {
__virtio64 sector;
};

/*
* Supported zoned device models.
*/

/* Regular block device */
#define VIRTIO_BLK_Z_NONE 0
/* Host-managed zoned device */
#define VIRTIO_BLK_Z_HM 1
/* Host-aware zoned device */
#define VIRTIO_BLK_Z_HA 2

/*
* Zone descriptor. A part of VIRTIO_BLK_T_ZONE_REPORT command reply.
*/
struct virtio_blk_zone_descriptor {
/* Zone capacity */
__virtio64 z_cap;
/* The starting sector of the zone */
__virtio64 z_start;
/* Zone write pointer position in sectors */
__virtio64 z_wp;
/* Zone type */
uint8_t z_type;
/* Zone state */
uint8_t z_state;
uint8_t reserved[38];
};

struct virtio_blk_zone_report {
__virtio64 nr_zones;
uint8_t reserved[56];
struct virtio_blk_zone_descriptor zones[];
};

/*
* Supported zone types.
*/

/* Conventional zone */
#define VIRTIO_BLK_ZT_CONV 1
/* Sequential Write Required zone */
#define VIRTIO_BLK_ZT_SWR 2
/* Sequential Write Preferred zone */
#define VIRTIO_BLK_ZT_SWP 3

/*
* Zone states that are available for zones of all types.
*/

/* Not a write pointer (conventional zones only) */
#define VIRTIO_BLK_ZS_NOT_WP 0
/* Empty */
#define VIRTIO_BLK_ZS_EMPTY 1
/* Implicitly Open */
#define VIRTIO_BLK_ZS_IOPEN 2
/* Explicitly Open */
#define VIRTIO_BLK_ZS_EOPEN 3
/* Closed */
#define VIRTIO_BLK_ZS_CLOSED 4
/* Read-Only */
#define VIRTIO_BLK_ZS_RDONLY 13
/* Full */
#define VIRTIO_BLK_ZS_FULL 14
/* Offline */
#define VIRTIO_BLK_ZS_OFFLINE 15

/* Unmap this range (only valid for write zeroes command) */
#define VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP 0x00000001

Expand All @@ -217,4 +315,11 @@ struct virtio_scsi_inhdr {
#define VIRTIO_BLK_S_OK 0
#define VIRTIO_BLK_S_IOERR 1
#define VIRTIO_BLK_S_UNSUPP 2

/* Error codes that are specific to zoned block devices */
#define VIRTIO_BLK_S_ZONE_INVALID_CMD 3
#define VIRTIO_BLK_S_ZONE_UNALIGNED_WP 4
#define VIRTIO_BLK_S_ZONE_OPEN_RESOURCE 5
#define VIRTIO_BLK_S_ZONE_ACTIVE_RESOURCE 6

#endif /* _LINUX_VIRTIO_BLK_H */
27 changes: 27 additions & 0 deletions include/sysemu/block-backend-io.h
Expand Up @@ -46,6 +46,16 @@ BlockAIOCB *blk_aio_pwritev(BlockBackend *blk, int64_t offset,
BlockCompletionFunc *cb, void *opaque);
BlockAIOCB *blk_aio_flush(BlockBackend *blk,
BlockCompletionFunc *cb, void *opaque);
BlockAIOCB *blk_aio_zone_report(BlockBackend *blk, int64_t offset,
unsigned int *nr_zones,
BlockZoneDescriptor *zones,
BlockCompletionFunc *cb, void *opaque);
BlockAIOCB *blk_aio_zone_mgmt(BlockBackend *blk, BlockZoneOp op,
int64_t offset, int64_t len,
BlockCompletionFunc *cb, void *opaque);
BlockAIOCB *blk_aio_zone_append(BlockBackend *blk, int64_t *offset,
QEMUIOVector *qiov, BdrvRequestFlags flags,
BlockCompletionFunc *cb, void *opaque);
BlockAIOCB *blk_aio_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes,
BlockCompletionFunc *cb, void *opaque);
void blk_aio_cancel_async(BlockAIOCB *acb);
Expand Down Expand Up @@ -191,6 +201,23 @@ int co_wrapper_mixed blk_pwrite_zeroes(BlockBackend *blk, int64_t offset,
int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset,
int64_t bytes, BdrvRequestFlags flags);

int coroutine_fn blk_co_zone_report(BlockBackend *blk, int64_t offset,
unsigned int *nr_zones,
BlockZoneDescriptor *zones);
int co_wrapper_mixed blk_zone_report(BlockBackend *blk, int64_t offset,
unsigned int *nr_zones,
BlockZoneDescriptor *zones);
int coroutine_fn blk_co_zone_mgmt(BlockBackend *blk, BlockZoneOp op,
int64_t offset, int64_t len);
int co_wrapper_mixed blk_zone_mgmt(BlockBackend *blk, BlockZoneOp op,
int64_t offset, int64_t len);
int coroutine_fn blk_co_zone_append(BlockBackend *blk, int64_t *offset,
QEMUIOVector *qiov,
BdrvRequestFlags flags);
int co_wrapper_mixed blk_zone_append(BlockBackend *blk, int64_t *offset,
QEMUIOVector *qiov,
BdrvRequestFlags flags);

int co_wrapper_mixed blk_pdiscard(BlockBackend *blk, int64_t offset,
int64_t bytes);
int coroutine_fn blk_co_pdiscard(BlockBackend *blk, int64_t offset,
Expand Down
1 change: 1 addition & 0 deletions linux-headers/asm-arm64/kvm.h
Expand Up @@ -109,6 +109,7 @@ struct kvm_regs {
#define KVM_ARM_VCPU_SVE 4 /* enable SVE for this CPU */
#define KVM_ARM_VCPU_PTRAUTH_ADDRESS 5 /* VCPU uses address authentication */
#define KVM_ARM_VCPU_PTRAUTH_GENERIC 6 /* VCPU uses generic authentication */
#define KVM_ARM_VCPU_HAS_EL2 7 /* Support nested virtualization */

struct kvm_vcpu_init {
__u32 target;
Expand Down
34 changes: 32 additions & 2 deletions linux-headers/asm-x86/kvm.h
Expand Up @@ -9,6 +9,7 @@

#include <linux/types.h>
#include <linux/ioctl.h>
#include <linux/stddef.h>

#define KVM_PIO_PAGE_OFFSET 1
#define KVM_COALESCED_MMIO_PAGE_OFFSET 2
Expand Down Expand Up @@ -505,8 +506,8 @@ struct kvm_nested_state {
* KVM_{GET,PUT}_NESTED_STATE ioctl values.
*/
union {
struct kvm_vmx_nested_state_data vmx[0];
struct kvm_svm_nested_state_data svm[0];
__DECLARE_FLEX_ARRAY(struct kvm_vmx_nested_state_data, vmx);
__DECLARE_FLEX_ARRAY(struct kvm_svm_nested_state_data, svm);
} data;
};

Expand All @@ -523,6 +524,35 @@ struct kvm_pmu_event_filter {
#define KVM_PMU_EVENT_ALLOW 0
#define KVM_PMU_EVENT_DENY 1

#define KVM_PMU_EVENT_FLAG_MASKED_EVENTS BIT(0)
#define KVM_PMU_EVENT_FLAGS_VALID_MASK (KVM_PMU_EVENT_FLAG_MASKED_EVENTS)

/*
* Masked event layout.
* Bits Description
* ---- -----------
* 7:0 event select (low bits)
* 15:8 umask match
* 31:16 unused
* 35:32 event select (high bits)
* 36:54 unused
* 55 exclude bit
* 63:56 umask mask
*/

#define KVM_PMU_ENCODE_MASKED_ENTRY(event_select, mask, match, exclude) \
(((event_select) & 0xFFULL) | (((event_select) & 0XF00ULL) << 24) | \
(((mask) & 0xFFULL) << 56) | \
(((match) & 0xFFULL) << 8) | \
((__u64)(!!(exclude)) << 55))

#define KVM_PMU_MASKED_ENTRY_EVENT_SELECT \
(GENMASK_ULL(7, 0) | GENMASK_ULL(35, 32))
#define KVM_PMU_MASKED_ENTRY_UMASK_MASK (GENMASK_ULL(63, 56))
#define KVM_PMU_MASKED_ENTRY_UMASK_MATCH (GENMASK_ULL(15, 8))
#define KVM_PMU_MASKED_ENTRY_EXCLUDE (BIT_ULL(55))
#define KVM_PMU_MASKED_ENTRY_UMASK_MASK_SHIFT (56)

/* for KVM_{GET,SET,HAS}_DEVICE_ATTR */
#define KVM_VCPU_TSC_CTRL 0 /* control group for the timestamp counter (TSC) */
#define KVM_VCPU_TSC_OFFSET 0 /* attribute for the TSC offset */
Expand Down
9 changes: 9 additions & 0 deletions linux-headers/linux/kvm.h
Expand Up @@ -581,6 +581,8 @@ struct kvm_s390_mem_op {
struct {
__u8 ar; /* the access register number */
__u8 key; /* access key, ignored if flag unset */
__u8 pad1[6]; /* ignored */
__u64 old_addr; /* ignored if cmpxchg flag unset */
};
__u32 sida_offset; /* offset into the sida */
__u8 reserved[32]; /* ignored */
Expand All @@ -593,11 +595,17 @@ struct kvm_s390_mem_op {
#define KVM_S390_MEMOP_SIDA_WRITE 3
#define KVM_S390_MEMOP_ABSOLUTE_READ 4
#define KVM_S390_MEMOP_ABSOLUTE_WRITE 5
#define KVM_S390_MEMOP_ABSOLUTE_CMPXCHG 6

/* flags for kvm_s390_mem_op->flags */
#define KVM_S390_MEMOP_F_CHECK_ONLY (1ULL << 0)
#define KVM_S390_MEMOP_F_INJECT_EXCEPTION (1ULL << 1)
#define KVM_S390_MEMOP_F_SKEY_PROTECTION (1ULL << 2)

/* flags specifying extension support via KVM_CAP_S390_MEM_OP_EXTENSION */
#define KVM_S390_MEMOP_EXTENSION_CAP_BASE (1 << 0)
#define KVM_S390_MEMOP_EXTENSION_CAP_CMPXCHG (1 << 1)

/* for KVM_INTERRUPT */
struct kvm_interrupt {
/* in */
Expand Down Expand Up @@ -1173,6 +1181,7 @@ struct kvm_ppc_resize_hpt {
#define KVM_CAP_DIRTY_LOG_RING_ACQ_REL 223
#define KVM_CAP_S390_PROTECTED_ASYNC_DISABLE 224
#define KVM_CAP_DIRTY_LOG_RING_WITH_BITMAP 225
#define KVM_CAP_PMU_EVENT_MASKED_EVENTS 226

#ifdef KVM_CAP_IRQ_ROUTING

Expand Down
15 changes: 9 additions & 6 deletions linux-headers/linux/vfio.h
Expand Up @@ -49,7 +49,11 @@
/* Supports VFIO_DMA_UNMAP_FLAG_ALL */
#define VFIO_UNMAP_ALL 9

/* Supports the vaddr flag for DMA map and unmap */
/*
* Supports the vaddr flag for DMA map and unmap. Not supported for mediated
* devices, so this capability is subject to change as groups are added or
* removed.
*/
#define VFIO_UPDATE_VADDR 10

/*
Expand Down Expand Up @@ -1343,8 +1347,7 @@ struct vfio_iommu_type1_info_dma_avail {
* Map process virtual addresses to IO virtual addresses using the
* provided struct vfio_dma_map. Caller sets argsz. READ &/ WRITE required.
*
* If flags & VFIO_DMA_MAP_FLAG_VADDR, update the base vaddr for iova, and
* unblock translation of host virtual addresses in the iova range. The vaddr
* If flags & VFIO_DMA_MAP_FLAG_VADDR, update the base vaddr for iova. The vaddr
* must have previously been invalidated with VFIO_DMA_UNMAP_FLAG_VADDR. To
* maintain memory consistency within the user application, the updated vaddr
* must address the same memory object as originally mapped. Failure to do so
Expand Down Expand Up @@ -1395,9 +1398,9 @@ struct vfio_bitmap {
* must be 0. This cannot be combined with the get-dirty-bitmap flag.
*
* If flags & VFIO_DMA_UNMAP_FLAG_VADDR, do not unmap, but invalidate host
* virtual addresses in the iova range. Tasks that attempt to translate an
* iova's vaddr will block. DMA to already-mapped pages continues. This
* cannot be combined with the get-dirty-bitmap flag.
* virtual addresses in the iova range. DMA to already-mapped pages continues.
* Groups may not be added to the container while any addresses are invalid.
* This cannot be combined with the get-dirty-bitmap flag.
*/
struct vfio_iommu_type1_dma_unmap {
__u32 argsz;
Expand Down
8 changes: 8 additions & 0 deletions linux-headers/linux/vhost.h
Expand Up @@ -180,4 +180,12 @@
*/
#define VHOST_VDPA_SUSPEND _IO(VHOST_VIRTIO, 0x7D)

/* Resume a device so it can resume processing virtqueue requests
*
* After the return of this ioctl the device will have restored all the
* necessary states and it is fully operational to continue processing the
* virtqueue descriptors.
*/
#define VHOST_VDPA_RESUME _IO(VHOST_VIRTIO, 0x7E)

#endif
4 changes: 4 additions & 0 deletions meson.build
Expand Up @@ -1966,6 +1966,7 @@ config_host_data.set('CONFIG_REPLICATION', get_option('replication').allowed())
# has_header
config_host_data.set('CONFIG_EPOLL', cc.has_header('sys/epoll.h'))
config_host_data.set('CONFIG_LINUX_MAGIC_H', cc.has_header('linux/magic.h'))
config_host_data.set('CONFIG_BLKZONED', cc.has_header('linux/blkzoned.h'))
config_host_data.set('CONFIG_VALGRIND_H', cc.has_header('valgrind/valgrind.h'))
config_host_data.set('HAVE_BTRFS_H', cc.has_header('linux/btrfs.h'))
config_host_data.set('HAVE_DRM_H', cc.has_header('libdrm/drm.h'))
Expand Down Expand Up @@ -2052,6 +2053,9 @@ config_host_data.set('HAVE_SIGEV_NOTIFY_THREAD_ID',
config_host_data.set('HAVE_STRUCT_STAT_ST_ATIM',
cc.has_member('struct stat', 'st_atim',
prefix: '#include <sys/stat.h>'))
config_host_data.set('HAVE_BLK_ZONE_REP_CAPACITY',
cc.has_member('struct blk_zone', 'capacity',
prefix: '#include <linux/blkzoned.h>'))

# has_type
config_host_data.set('CONFIG_IOVEC',
Expand Down
68 changes: 57 additions & 11 deletions qapi/block-core.json
Expand Up @@ -849,6 +849,10 @@
# @min_wr_latency_ns: Minimum latency of write operations in the
# defined interval, in nanoseconds.
#
# @min_zone_append_latency_ns: Minimum latency of zone append operations
# in the defined interval, in nanoseconds
# (since 8.1)
#
# @min_flush_latency_ns: Minimum latency of flush operations in the
# defined interval, in nanoseconds.
#
Expand All @@ -858,6 +862,10 @@
# @max_wr_latency_ns: Maximum latency of write operations in the
# defined interval, in nanoseconds.
#
# @max_zone_append_latency_ns: Maximum latency of zone append operations
# in the defined interval, in nanoseconds
# (since 8.1)
#
# @max_flush_latency_ns: Maximum latency of flush operations in the
# defined interval, in nanoseconds.
#
Expand All @@ -867,6 +875,10 @@
# @avg_wr_latency_ns: Average latency of write operations in the
# defined interval, in nanoseconds.
#
# @avg_zone_append_latency_ns: Average latency of zone append operations
# in the defined interval, in nanoseconds
# (since 8.1)
#
# @avg_flush_latency_ns: Average latency of flush operations in the
# defined interval, in nanoseconds.
#
Expand All @@ -876,15 +888,23 @@
# @avg_wr_queue_depth: Average number of pending write operations
# in the defined interval.
#
# @avg_zone_append_queue_depth: Average number of pending zone append
# operations in the defined interval
# (since 8.1).
#
# Since: 2.5
##
{ 'struct': 'BlockDeviceTimedStats',
'data': { 'interval_length': 'int', 'min_rd_latency_ns': 'int',
'max_rd_latency_ns': 'int', 'avg_rd_latency_ns': 'int',
'min_wr_latency_ns': 'int', 'max_wr_latency_ns': 'int',
'avg_wr_latency_ns': 'int', 'min_flush_latency_ns': 'int',
'max_flush_latency_ns': 'int', 'avg_flush_latency_ns': 'int',
'avg_rd_queue_depth': 'number', 'avg_wr_queue_depth': 'number' } }
'avg_wr_latency_ns': 'int', 'min_zone_append_latency_ns': 'int',
'max_zone_append_latency_ns': 'int',
'avg_zone_append_latency_ns': 'int',
'min_flush_latency_ns': 'int', 'max_flush_latency_ns': 'int',
'avg_flush_latency_ns': 'int', 'avg_rd_queue_depth': 'number',
'avg_wr_queue_depth': 'number',
'avg_zone_append_queue_depth': 'number' } }

##
# @BlockDeviceStats:
Expand All @@ -895,12 +915,18 @@
#
# @wr_bytes: The number of bytes written by the device.
#
# @zone_append_bytes: The number of bytes appended by the zoned devices
# (since 8.1)
#
# @unmap_bytes: The number of bytes unmapped by the device (Since 4.2)
#
# @rd_operations: The number of read operations performed by the device.
#
# @wr_operations: The number of write operations performed by the device.
#
# @zone_append_operations: The number of zone append operations performed
# by the zoned devices (since 8.1)
#
# @flush_operations: The number of cache flush operations performed by the
# device (since 0.15)
#
Expand All @@ -911,6 +937,9 @@
#
# @wr_total_time_ns: Total time spent on writes in nanoseconds (since 0.15).
#
# @zone_append_total_time_ns: Total time spent on zone append writes
# in nanoseconds (since 8.1)
#
# @flush_total_time_ns: Total time spent on cache flushes in nanoseconds
# (since 0.15).
#
Expand All @@ -928,6 +957,9 @@
# @wr_merged: Number of write requests that have been merged into another
# request (Since 2.3).
#
# @zone_append_merged: Number of zone append requests that have been merged
# into another request (since 8.1)
#
# @unmap_merged: Number of unmap requests that have been merged into another
# request (Since 4.2)
#
Expand All @@ -941,6 +973,10 @@
# @failed_wr_operations: The number of failed write operations
# performed by the device (Since 2.5)
#
# @failed_zone_append_operations: The number of failed zone append write
# operations performed by the zoned devices
# (since 8.1)
#
# @failed_flush_operations: The number of failed flush operations
# performed by the device (Since 2.5)
#
Expand All @@ -953,6 +989,9 @@
# @invalid_wr_operations: The number of invalid write operations
# performed by the device (Since 2.5)
#
# @invalid_zone_append_operations: The number of invalid zone append operations
# performed by the zoned device (since 8.1)
#
# @invalid_flush_operations: The number of invalid flush operations
# performed by the device (Since 2.5)
#
Expand All @@ -972,27 +1011,34 @@
#
# @wr_latency_histogram: @BlockLatencyHistogramInfo. (Since 4.0)
#
# @zone_append_latency_histogram: @BlockLatencyHistogramInfo. (since 8.1)
#
# @flush_latency_histogram: @BlockLatencyHistogramInfo. (Since 4.0)
#
# Since: 0.14
##
{ 'struct': 'BlockDeviceStats',
'data': {'rd_bytes': 'int', 'wr_bytes': 'int', 'unmap_bytes' : 'int',
'rd_operations': 'int', 'wr_operations': 'int',
'data': {'rd_bytes': 'int', 'wr_bytes': 'int', 'zone_append_bytes': 'int',
'unmap_bytes' : 'int', 'rd_operations': 'int',
'wr_operations': 'int', 'zone_append_operations': 'int',
'flush_operations': 'int', 'unmap_operations': 'int',
'rd_total_time_ns': 'int', 'wr_total_time_ns': 'int',
'flush_total_time_ns': 'int', 'unmap_total_time_ns': 'int',
'wr_highest_offset': 'int',
'rd_merged': 'int', 'wr_merged': 'int', 'unmap_merged': 'int',
'*idle_time_ns': 'int',
'zone_append_total_time_ns': 'int', 'flush_total_time_ns': 'int',
'unmap_total_time_ns': 'int', 'wr_highest_offset': 'int',
'rd_merged': 'int', 'wr_merged': 'int', 'zone_append_merged': 'int',
'unmap_merged': 'int', '*idle_time_ns': 'int',
'failed_rd_operations': 'int', 'failed_wr_operations': 'int',
'failed_flush_operations': 'int', 'failed_unmap_operations': 'int',
'invalid_rd_operations': 'int', 'invalid_wr_operations': 'int',
'failed_zone_append_operations': 'int',
'failed_flush_operations': 'int',
'failed_unmap_operations': 'int', 'invalid_rd_operations': 'int',
'invalid_wr_operations': 'int',
'invalid_zone_append_operations': 'int',
'invalid_flush_operations': 'int', 'invalid_unmap_operations': 'int',
'account_invalid': 'bool', 'account_failed': 'bool',
'timed_stats': ['BlockDeviceTimedStats'],
'*rd_latency_histogram': 'BlockLatencyHistogramInfo',
'*wr_latency_histogram': 'BlockLatencyHistogramInfo',
'*zone_append_latency_histogram': 'BlockLatencyHistogramInfo',
'*flush_latency_histogram': 'BlockLatencyHistogramInfo' } }

##
Expand Down
4 changes: 4 additions & 0 deletions qapi/block.json
Expand Up @@ -525,6 +525,9 @@
# @boundaries-write: list of interval boundary values for write latency
# histogram.
#
# @boundaries-zap: list of interval boundary values for zone append write
# latency histogram.
#
# @boundaries-flush: list of interval boundary values for flush latency
# histogram.
#
Expand Down Expand Up @@ -573,5 +576,6 @@
'*boundaries': ['uint64'],
'*boundaries-read': ['uint64'],
'*boundaries-write': ['uint64'],
'*boundaries-zap': ['uint64'],
'*boundaries-flush': ['uint64'] },
'allow-preconfig': true }
224 changes: 224 additions & 0 deletions qemu-io-cmds.c
Expand Up @@ -1730,6 +1730,224 @@ static const cmdinfo_t flush_cmd = {
.oneline = "flush all in-core file state to disk",
};

static inline int64_t tosector(int64_t bytes)
{
return bytes >> BDRV_SECTOR_BITS;
}

static int zone_report_f(BlockBackend *blk, int argc, char **argv)
{
int ret;
int64_t offset;
unsigned int nr_zones;

++optind;
offset = cvtnum(argv[optind]);
++optind;
nr_zones = cvtnum(argv[optind]);

g_autofree BlockZoneDescriptor *zones = NULL;
zones = g_new(BlockZoneDescriptor, nr_zones);
ret = blk_zone_report(blk, offset, &nr_zones, zones);
if (ret < 0) {
printf("zone report failed: %s\n", strerror(-ret));
} else {
for (int i = 0; i < nr_zones; ++i) {
printf("start: 0x%" PRIx64 ", len 0x%" PRIx64 ", "
"cap"" 0x%" PRIx64 ", wptr 0x%" PRIx64 ", "
"zcond:%u, [type: %u]\n",
tosector(zones[i].start), tosector(zones[i].length),
tosector(zones[i].cap), tosector(zones[i].wp),
zones[i].state, zones[i].type);
}
}
return ret;
}

static const cmdinfo_t zone_report_cmd = {
.name = "zone_report",
.altname = "zrp",
.cfunc = zone_report_f,
.argmin = 2,
.argmax = 2,
.args = "offset number",
.oneline = "report zone information",
};

static int zone_open_f(BlockBackend *blk, int argc, char **argv)
{
int ret;
int64_t offset, len;
++optind;
offset = cvtnum(argv[optind]);
++optind;
len = cvtnum(argv[optind]);
ret = blk_zone_mgmt(blk, BLK_ZO_OPEN, offset, len);
if (ret < 0) {
printf("zone open failed: %s\n", strerror(-ret));
}
return ret;
}

static const cmdinfo_t zone_open_cmd = {
.name = "zone_open",
.altname = "zo",
.cfunc = zone_open_f,
.argmin = 2,
.argmax = 2,
.args = "offset len",
.oneline = "explicit open a range of zones in zone block device",
};

static int zone_close_f(BlockBackend *blk, int argc, char **argv)
{
int ret;
int64_t offset, len;
++optind;
offset = cvtnum(argv[optind]);
++optind;
len = cvtnum(argv[optind]);
ret = blk_zone_mgmt(blk, BLK_ZO_CLOSE, offset, len);
if (ret < 0) {
printf("zone close failed: %s\n", strerror(-ret));
}
return ret;
}

static const cmdinfo_t zone_close_cmd = {
.name = "zone_close",
.altname = "zc",
.cfunc = zone_close_f,
.argmin = 2,
.argmax = 2,
.args = "offset len",
.oneline = "close a range of zones in zone block device",
};

static int zone_finish_f(BlockBackend *blk, int argc, char **argv)
{
int ret;
int64_t offset, len;
++optind;
offset = cvtnum(argv[optind]);
++optind;
len = cvtnum(argv[optind]);
ret = blk_zone_mgmt(blk, BLK_ZO_FINISH, offset, len);
if (ret < 0) {
printf("zone finish failed: %s\n", strerror(-ret));
}
return ret;
}

static const cmdinfo_t zone_finish_cmd = {
.name = "zone_finish",
.altname = "zf",
.cfunc = zone_finish_f,
.argmin = 2,
.argmax = 2,
.args = "offset len",
.oneline = "finish a range of zones in zone block device",
};

static int zone_reset_f(BlockBackend *blk, int argc, char **argv)
{
int ret;
int64_t offset, len;
++optind;
offset = cvtnum(argv[optind]);
++optind;
len = cvtnum(argv[optind]);
ret = blk_zone_mgmt(blk, BLK_ZO_RESET, offset, len);
if (ret < 0) {
printf("zone reset failed: %s\n", strerror(-ret));
}
return ret;
}

static const cmdinfo_t zone_reset_cmd = {
.name = "zone_reset",
.altname = "zrs",
.cfunc = zone_reset_f,
.argmin = 2,
.argmax = 2,
.args = "offset len",
.oneline = "reset a zone write pointer in zone block device",
};

static int do_aio_zone_append(BlockBackend *blk, QEMUIOVector *qiov,
int64_t *offset, int flags, int *total)
{
int async_ret = NOT_DONE;

blk_aio_zone_append(blk, offset, qiov, flags, aio_rw_done, &async_ret);
while (async_ret == NOT_DONE) {
main_loop_wait(false);
}

*total = qiov->size;
return async_ret < 0 ? async_ret : 1;
}

static int zone_append_f(BlockBackend *blk, int argc, char **argv)
{
int ret;
bool pflag = false;
int flags = 0;
int total = 0;
int64_t offset;
char *buf;
int c, nr_iov;
int pattern = 0xcd;
QEMUIOVector qiov;

if (optind > argc - 3) {
return -EINVAL;
}

if ((c = getopt(argc, argv, "p")) != -1) {
pflag = true;
}

offset = cvtnum(argv[optind]);
if (offset < 0) {
print_cvtnum_err(offset, argv[optind]);
return offset;
}
optind++;
nr_iov = argc - optind;
buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, pattern,
flags & BDRV_REQ_REGISTERED_BUF);
if (buf == NULL) {
return -EINVAL;
}
ret = do_aio_zone_append(blk, &qiov, &offset, flags, &total);
if (ret < 0) {
printf("zone append failed: %s\n", strerror(-ret));
goto out;
}

if (pflag) {
printf("After zap done, the append sector is 0x%" PRIx64 "\n",
tosector(offset));
}

out:
qemu_io_free(blk, buf, qiov.size,
flags & BDRV_REQ_REGISTERED_BUF);
qemu_iovec_destroy(&qiov);
return ret;
}

static const cmdinfo_t zone_append_cmd = {
.name = "zone_append",
.altname = "zap",
.cfunc = zone_append_f,
.argmin = 3,
.argmax = 4,
.args = "offset len [len..]",
.oneline = "append write a number of bytes at a specified offset",
};

static int truncate_f(BlockBackend *blk, int argc, char **argv);
static const cmdinfo_t truncate_cmd = {
.name = "truncate",
Expand Down Expand Up @@ -2523,6 +2741,12 @@ static void __attribute((constructor)) init_qemuio_commands(void)
qemuio_add_command(&aio_write_cmd);
qemuio_add_command(&aio_flush_cmd);
qemuio_add_command(&flush_cmd);
qemuio_add_command(&zone_report_cmd);
qemuio_add_command(&zone_open_cmd);
qemuio_add_command(&zone_close_cmd);
qemuio_add_command(&zone_finish_cmd);
qemuio_add_command(&zone_reset_cmd);
qemuio_add_command(&zone_append_cmd);
qemuio_add_command(&truncate_cmd);
qemuio_add_command(&length_cmd);
qemuio_add_command(&info_cmd);
Expand Down
105 changes: 105 additions & 0 deletions tests/qemu-iotests/tests/zoned
@@ -0,0 +1,105 @@
#!/usr/bin/env bash
#
# Test zone management operations.
#

seq="$(basename $0)"
echo "QA output created by $seq"
status=1 # failure is the default!

_cleanup()
{
_cleanup_test_img
sudo -n rmmod null_blk
}
trap "_cleanup; exit \$status" 0 1 2 3 15

# get standard environment, filters and checks
. ../common.rc
. ../common.filter
. ../common.qemu

# This test only runs on Linux hosts with raw image files.
_supported_fmt raw
_supported_proto file
_supported_os Linux

sudo -n true || \
_notrun 'Password-less sudo required'

IMG="--image-opts -n driver=host_device,filename=/dev/nullb0"
QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT

echo "Testing a null_blk device:"
echo "case 1: if the operations work"
sudo -n modprobe null_blk nr_devices=1 zoned=1
sudo -n chmod 0666 /dev/nullb0

echo "(1) report the first zone:"
$QEMU_IO $IMG -c "zrp 0 1"
echo
echo "report the first 10 zones"
$QEMU_IO $IMG -c "zrp 0 10"
echo
echo "report the last zone:"
$QEMU_IO $IMG -c "zrp 0x3e70000000 2" # 0x3e70000000 / 512 = 0x1f380000
echo
echo
echo "(2) opening the first zone"
$QEMU_IO $IMG -c "zo 0 268435456" # 268435456 / 512 = 524288
echo "report after:"
$QEMU_IO $IMG -c "zrp 0 1"
echo
echo "opening the second zone"
$QEMU_IO $IMG -c "zo 268435456 268435456" #
echo "report after:"
$QEMU_IO $IMG -c "zrp 268435456 1"
echo
echo "opening the last zone"
$QEMU_IO $IMG -c "zo 0x3e70000000 268435456"
echo "report after:"
$QEMU_IO $IMG -c "zrp 0x3e70000000 2"
echo
echo
echo "(3) closing the first zone"
$QEMU_IO $IMG -c "zc 0 268435456"
echo "report after:"
$QEMU_IO $IMG -c "zrp 0 1"
echo
echo "closing the last zone"
$QEMU_IO $IMG -c "zc 0x3e70000000 268435456"
echo "report after:"
$QEMU_IO $IMG -c "zrp 0x3e70000000 2"
echo
echo
echo "(4) finishing the second zone"
$QEMU_IO $IMG -c "zf 268435456 268435456"
echo "After finishing a zone:"
$QEMU_IO $IMG -c "zrp 268435456 1"
echo
echo
echo "(5) resetting the second zone"
$QEMU_IO $IMG -c "zrs 268435456 268435456"
echo "After resetting a zone:"
$QEMU_IO $IMG -c "zrp 268435456 1"
echo
echo
echo "(6) append write" # the physical block size of the device is 4096
$QEMU_IO $IMG -c "zrp 0 1"
$QEMU_IO $IMG -c "zap -p 0 0x1000 0x2000"
echo "After appending the first zone firstly:"
$QEMU_IO $IMG -c "zrp 0 1"
$QEMU_IO $IMG -c "zap -p 0 0x1000 0x2000"
echo "After appending the first zone secondly:"
$QEMU_IO $IMG -c "zrp 0 1"
$QEMU_IO $IMG -c "zap -p 268435456 0x1000 0x2000"
echo "After appending the second zone firstly:"
$QEMU_IO $IMG -c "zrp 268435456 1"
$QEMU_IO $IMG -c "zap -p 268435456 0x1000 0x2000"
echo "After appending the second zone secondly:"
$QEMU_IO $IMG -c "zrp 268435456 1"

# success, all done
echo "*** done"
rm -f $seq.full
status=0
69 changes: 69 additions & 0 deletions tests/qemu-iotests/tests/zoned.out
@@ -0,0 +1,69 @@
QA output created by zoned
Testing a null_blk device:
case 1: if the operations work
(1) report the first zone:
start: 0x0, len 0x80000, cap 0x80000, wptr 0x0, zcond:1, [type: 2]

report the first 10 zones
start: 0x0, len 0x80000, cap 0x80000, wptr 0x0, zcond:1, [type: 2]
start: 0x80000, len 0x80000, cap 0x80000, wptr 0x80000, zcond:1, [type: 2]
start: 0x100000, len 0x80000, cap 0x80000, wptr 0x100000, zcond:1, [type: 2]
start: 0x180000, len 0x80000, cap 0x80000, wptr 0x180000, zcond:1, [type: 2]
start: 0x200000, len 0x80000, cap 0x80000, wptr 0x200000, zcond:1, [type: 2]
start: 0x280000, len 0x80000, cap 0x80000, wptr 0x280000, zcond:1, [type: 2]
start: 0x300000, len 0x80000, cap 0x80000, wptr 0x300000, zcond:1, [type: 2]
start: 0x380000, len 0x80000, cap 0x80000, wptr 0x380000, zcond:1, [type: 2]
start: 0x400000, len 0x80000, cap 0x80000, wptr 0x400000, zcond:1, [type: 2]
start: 0x480000, len 0x80000, cap 0x80000, wptr 0x480000, zcond:1, [type: 2]

report the last zone:
start: 0x1f380000, len 0x80000, cap 0x80000, wptr 0x1f380000, zcond:1, [type: 2]


(2) opening the first zone
report after:
start: 0x0, len 0x80000, cap 0x80000, wptr 0x0, zcond:3, [type: 2]

opening the second zone
report after:
start: 0x80000, len 0x80000, cap 0x80000, wptr 0x80000, zcond:3, [type: 2]

opening the last zone
report after:
start: 0x1f380000, len 0x80000, cap 0x80000, wptr 0x1f380000, zcond:3, [type: 2]


(3) closing the first zone
report after:
start: 0x0, len 0x80000, cap 0x80000, wptr 0x0, zcond:1, [type: 2]

closing the last zone
report after:
start: 0x1f380000, len 0x80000, cap 0x80000, wptr 0x1f380000, zcond:1, [type: 2]


(4) finishing the second zone
After finishing a zone:
start: 0x80000, len 0x80000, cap 0x80000, wptr 0x100000, zcond:14, [type: 2]


(5) resetting the second zone
After resetting a zone:
start: 0x80000, len 0x80000, cap 0x80000, wptr 0x80000, zcond:1, [type: 2]


(6) append write
start: 0x0, len 0x80000, cap 0x80000, wptr 0x0, zcond:1, [type: 2]
After zap done, the append sector is 0x0
After appending the first zone firstly:
start: 0x0, len 0x80000, cap 0x80000, wptr 0x18, zcond:2, [type: 2]
After zap done, the append sector is 0x18
After appending the first zone secondly:
start: 0x0, len 0x80000, cap 0x80000, wptr 0x30, zcond:2, [type: 2]
After zap done, the append sector is 0x80000
After appending the second zone firstly:
start: 0x80000, len 0x80000, cap 0x80000, wptr 0x80018, zcond:2, [type: 2]
After zap done, the append sector is 0x80018
After appending the second zone secondly:
start: 0x80000, len 0x80000, cap 0x80000, wptr 0x80030, zcond:2, [type: 2]
*** done