vhost-blk: add discard/write zeroes commands support
Discard and Write Zeroes commands was supported with commit 1f23816b in Linux virtio-blk driver. While here, also add the support in SPDK vhost target. Change-Id: I425be2a4961eac04e27ff71151d40c8d799cd37d Signed-off-by: Changpeng Liu <changpeng.liu@intel.com> Reviewed-on: https://review.gerrithub.io/c/431723 Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com> Reviewed-by: Darek Stojaczyk <dariusz.stojaczyk@intel.com> Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
This commit is contained in:
parent
0ab3fa895f
commit
232ca0e6e7
@ -38,6 +38,8 @@
|
|||||||
#define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available */
|
#define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available */
|
||||||
#define VIRTIO_BLK_F_TOPOLOGY 10 /* Topology information is available */
|
#define VIRTIO_BLK_F_TOPOLOGY 10 /* Topology information is available */
|
||||||
#define VIRTIO_BLK_F_MQ 12 /* support more than one vq */
|
#define VIRTIO_BLK_F_MQ 12 /* support more than one vq */
|
||||||
|
#define VIRTIO_BLK_F_DISCARD 13 /* DISCARD is supported */
|
||||||
|
#define VIRTIO_BLK_F_WRITE_ZEROES 14 /* WRITE ZEROES is supported */
|
||||||
|
|
||||||
/* Legacy feature bits */
|
/* Legacy feature bits */
|
||||||
#ifndef VIRTIO_BLK_NO_LEGACY
|
#ifndef VIRTIO_BLK_NO_LEGACY
|
||||||
@ -84,6 +86,39 @@ struct virtio_blk_config {
|
|||||||
|
|
||||||
/* number of vqs, only available when VIRTIO_BLK_F_MQ is set */
|
/* number of vqs, only available when VIRTIO_BLK_F_MQ is set */
|
||||||
__u16 num_queues;
|
__u16 num_queues;
|
||||||
|
|
||||||
|
/* the next 3 entries are guarded by VIRTIO_BLK_F_DISCARD */
|
||||||
|
/*
|
||||||
|
* The maximum discard sectors (in 512-byte sectors) for
|
||||||
|
* one segment.
|
||||||
|
*/
|
||||||
|
__u32 max_discard_sectors;
|
||||||
|
/*
|
||||||
|
* The maximum number of discard segments in a
|
||||||
|
* discard command.
|
||||||
|
*/
|
||||||
|
__u32 max_discard_seg;
|
||||||
|
/* Discard commands must be aligned to this number of sectors. */
|
||||||
|
__u32 discard_sector_alignment;
|
||||||
|
|
||||||
|
/* the next 3 entries are guarded by VIRTIO_BLK_F_WRITE_ZEROES */
|
||||||
|
/*
|
||||||
|
* The maximum number of write zeroes sectors (in 512-byte sectors) in
|
||||||
|
* one segment.
|
||||||
|
*/
|
||||||
|
__u32 max_write_zeroes_sectors;
|
||||||
|
/*
|
||||||
|
* The maximum number of segments in a write zeroes
|
||||||
|
* command.
|
||||||
|
*/
|
||||||
|
__u32 max_write_zeroes_seg;
|
||||||
|
/*
|
||||||
|
* Set if a VIRTIO_BLK_T_WRITE_ZEROES request may result in the
|
||||||
|
* deallocation of one or more of the sectors.
|
||||||
|
*/
|
||||||
|
__u8 write_zeroes_may_unmap;
|
||||||
|
|
||||||
|
__u8 unused1[3];
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -112,6 +147,12 @@ struct virtio_blk_config {
|
|||||||
/* Get device ID command */
|
/* Get device ID command */
|
||||||
#define VIRTIO_BLK_T_GET_ID 8
|
#define VIRTIO_BLK_T_GET_ID 8
|
||||||
|
|
||||||
|
/* Discard command */
|
||||||
|
#define VIRTIO_BLK_T_DISCARD 11
|
||||||
|
|
||||||
|
/* Write zeroes command */
|
||||||
|
#define VIRTIO_BLK_T_WRITE_ZEROES 13
|
||||||
|
|
||||||
#ifndef VIRTIO_BLK_NO_LEGACY
|
#ifndef VIRTIO_BLK_NO_LEGACY
|
||||||
/* Barrier before this op. */
|
/* Barrier before this op. */
|
||||||
#define VIRTIO_BLK_T_BARRIER 0x80000000
|
#define VIRTIO_BLK_T_BARRIER 0x80000000
|
||||||
@ -131,6 +172,19 @@ struct virtio_blk_outhdr {
|
|||||||
__virtio64 sector;
|
__virtio64 sector;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Unmap this range (only valid for write zeroes command) */
|
||||||
|
#define VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP 0x00000001
|
||||||
|
|
||||||
|
/* Discard/write zeroes range for each request. */
|
||||||
|
struct virtio_blk_discard_write_zeroes {
|
||||||
|
/* discard/write zeroes start sector */
|
||||||
|
__le64 sector;
|
||||||
|
/* number of discard/write zeroes sectors */
|
||||||
|
__le32 num_sectors;
|
||||||
|
/* flags for this range */
|
||||||
|
__le32 flags;
|
||||||
|
};
|
||||||
|
|
||||||
#ifndef VIRTIO_BLK_NO_LEGACY
|
#ifndef VIRTIO_BLK_NO_LEGACY
|
||||||
struct virtio_scsi_inhdr {
|
struct virtio_scsi_inhdr {
|
||||||
__virtio32 errors;
|
__virtio32 errors;
|
||||||
|
@ -227,6 +227,7 @@ process_blk_request(struct spdk_vhost_blk_task *task, struct spdk_vhost_blk_dev
|
|||||||
struct spdk_vhost_virtqueue *vq)
|
struct spdk_vhost_virtqueue *vq)
|
||||||
{
|
{
|
||||||
const struct virtio_blk_outhdr *req;
|
const struct virtio_blk_outhdr *req;
|
||||||
|
struct virtio_blk_discard_write_zeroes *desc;
|
||||||
struct iovec *iov;
|
struct iovec *iov;
|
||||||
uint32_t type;
|
uint32_t type;
|
||||||
uint32_t payload_len;
|
uint32_t payload_len;
|
||||||
@ -304,6 +305,55 @@ process_blk_request(struct spdk_vhost_blk_task *task, struct spdk_vhost_blk_dev
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case VIRTIO_BLK_T_DISCARD:
|
||||||
|
desc = task->iovs[1].iov_base;
|
||||||
|
if (payload_len != sizeof(*desc)) {
|
||||||
|
SPDK_NOTICELOG("Invalid discard payload size: %u\n", payload_len);
|
||||||
|
invalid_blk_request(task, VIRTIO_BLK_S_IOERR);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = spdk_bdev_unmap(bvdev->bdev_desc, bvdev->bdev_io_channel,
|
||||||
|
desc->sector * 512, desc->num_sectors * 512,
|
||||||
|
blk_request_complete_cb, task);
|
||||||
|
if (rc) {
|
||||||
|
if (rc == -ENOMEM) {
|
||||||
|
SPDK_DEBUGLOG(SPDK_LOG_VHOST_BLK, "No memory, start to queue io.\n");
|
||||||
|
blk_request_queue_io(task);
|
||||||
|
} else {
|
||||||
|
invalid_blk_request(task, VIRTIO_BLK_S_IOERR);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VIRTIO_BLK_T_WRITE_ZEROES:
|
||||||
|
desc = task->iovs[1].iov_base;
|
||||||
|
if (payload_len != sizeof(*desc)) {
|
||||||
|
SPDK_NOTICELOG("Invalid write zeroes payload size: %u\n", payload_len);
|
||||||
|
invalid_blk_request(task, VIRTIO_BLK_S_IOERR);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Zeroed and Unmap the range, SPDK doen't support it. */
|
||||||
|
if (desc->flags & VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP) {
|
||||||
|
SPDK_NOTICELOG("Can't support Write Zeroes with Unmap flag\n");
|
||||||
|
invalid_blk_request(task, VIRTIO_BLK_S_UNSUPP);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = spdk_bdev_write_zeroes(bvdev->bdev_desc, bvdev->bdev_io_channel,
|
||||||
|
desc->sector * 512, desc->num_sectors * 512,
|
||||||
|
blk_request_complete_cb, task);
|
||||||
|
if (rc) {
|
||||||
|
if (rc == -ENOMEM) {
|
||||||
|
SPDK_DEBUGLOG(SPDK_LOG_VHOST_BLK, "No memory, start to queue io.\n");
|
||||||
|
blk_request_queue_io(task);
|
||||||
|
} else {
|
||||||
|
invalid_blk_request(task, VIRTIO_BLK_S_IOERR);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
case VIRTIO_BLK_T_GET_ID:
|
case VIRTIO_BLK_T_GET_ID:
|
||||||
if (!task->iovcnt || !payload_len) {
|
if (!task->iovcnt || !payload_len) {
|
||||||
invalid_blk_request(task, VIRTIO_BLK_S_UNSUPP);
|
invalid_blk_request(task, VIRTIO_BLK_S_UNSUPP);
|
||||||
@ -709,7 +759,7 @@ static int
|
|||||||
spdk_vhost_blk_get_config(struct spdk_vhost_dev *vdev, uint8_t *config,
|
spdk_vhost_blk_get_config(struct spdk_vhost_dev *vdev, uint8_t *config,
|
||||||
uint32_t len)
|
uint32_t len)
|
||||||
{
|
{
|
||||||
struct virtio_blk_config *blkcfg = (struct virtio_blk_config *)config;
|
struct virtio_blk_config blkcfg;
|
||||||
struct spdk_vhost_blk_dev *bvdev;
|
struct spdk_vhost_blk_dev *bvdev;
|
||||||
struct spdk_bdev *bdev;
|
struct spdk_bdev *bdev;
|
||||||
uint32_t blk_size;
|
uint32_t blk_size;
|
||||||
@ -721,10 +771,6 @@ spdk_vhost_blk_get_config(struct spdk_vhost_dev *vdev, uint8_t *config,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len < sizeof(*blkcfg)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bdev = bvdev->bdev;
|
bdev = bvdev->bdev;
|
||||||
if (bdev == NULL) {
|
if (bdev == NULL) {
|
||||||
/* We can't just return -1 here as this GET_CONFIG message might
|
/* We can't just return -1 here as this GET_CONFIG message might
|
||||||
@ -745,17 +791,30 @@ spdk_vhost_blk_get_config(struct spdk_vhost_dev *vdev, uint8_t *config,
|
|||||||
blkcnt = spdk_bdev_get_num_blocks(bdev);
|
blkcnt = spdk_bdev_get_num_blocks(bdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(blkcfg, 0, sizeof(*blkcfg));
|
memset(&blkcfg, 0, sizeof(blkcfg));
|
||||||
blkcfg->blk_size = blk_size;
|
blkcfg.blk_size = blk_size;
|
||||||
/* minimum I/O size in blocks */
|
/* minimum I/O size in blocks */
|
||||||
blkcfg->min_io_size = 1;
|
blkcfg.min_io_size = 1;
|
||||||
/* expressed in 512 Bytes sectors */
|
/* expressed in 512 Bytes sectors */
|
||||||
blkcfg->capacity = (blkcnt * blk_size) / 512;
|
blkcfg.capacity = (blkcnt * blk_size) / 512;
|
||||||
blkcfg->size_max = 131072;
|
blkcfg.size_max = 131072;
|
||||||
/* -2 for REQ and RESP and -1 for region boundary splitting */
|
/* -2 for REQ and RESP and -1 for region boundary splitting */
|
||||||
blkcfg->seg_max = SPDK_VHOST_IOVS_MAX - 2 - 1;
|
blkcfg.seg_max = SPDK_VHOST_IOVS_MAX - 2 - 1;
|
||||||
/* QEMU can overwrite this value when started */
|
/* QEMU can overwrite this value when started */
|
||||||
blkcfg->num_queues = SPDK_VHOST_MAX_VQUEUES;
|
blkcfg.num_queues = SPDK_VHOST_MAX_VQUEUES;
|
||||||
|
|
||||||
|
if (bdev && spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_UNMAP)) {
|
||||||
|
/* 16MiB, expressed in 512 Bytes */
|
||||||
|
blkcfg.max_discard_sectors = 32768;
|
||||||
|
blkcfg.max_discard_seg = 1;
|
||||||
|
blkcfg.discard_sector_alignment = blk_size / 512;
|
||||||
|
}
|
||||||
|
if (bdev && spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_WRITE_ZEROES)) {
|
||||||
|
blkcfg.max_write_zeroes_sectors = 32768;
|
||||||
|
blkcfg.max_write_zeroes_seg = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(config, &blkcfg, spdk_min(len, sizeof(blkcfg)));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -767,10 +826,12 @@ static const struct spdk_vhost_dev_backend vhost_blk_device_backend = {
|
|||||||
(1ULL << VIRTIO_BLK_F_BLK_SIZE) | (1ULL << VIRTIO_BLK_F_TOPOLOGY) |
|
(1ULL << VIRTIO_BLK_F_BLK_SIZE) | (1ULL << VIRTIO_BLK_F_TOPOLOGY) |
|
||||||
(1ULL << VIRTIO_BLK_F_BARRIER) | (1ULL << VIRTIO_BLK_F_SCSI) |
|
(1ULL << VIRTIO_BLK_F_BARRIER) | (1ULL << VIRTIO_BLK_F_SCSI) |
|
||||||
(1ULL << VIRTIO_BLK_F_FLUSH) | (1ULL << VIRTIO_BLK_F_CONFIG_WCE) |
|
(1ULL << VIRTIO_BLK_F_FLUSH) | (1ULL << VIRTIO_BLK_F_CONFIG_WCE) |
|
||||||
(1ULL << VIRTIO_BLK_F_MQ),
|
(1ULL << VIRTIO_BLK_F_MQ) | (1ULL << VIRTIO_BLK_F_DISCARD) |
|
||||||
|
(1ULL << VIRTIO_BLK_F_WRITE_ZEROES),
|
||||||
.disabled_features = SPDK_VHOST_DISABLED_FEATURES | (1ULL << VIRTIO_BLK_F_GEOMETRY) |
|
.disabled_features = SPDK_VHOST_DISABLED_FEATURES | (1ULL << VIRTIO_BLK_F_GEOMETRY) |
|
||||||
(1ULL << VIRTIO_BLK_F_RO) | (1ULL << VIRTIO_BLK_F_FLUSH) | (1ULL << VIRTIO_BLK_F_CONFIG_WCE) |
|
(1ULL << VIRTIO_BLK_F_RO) | (1ULL << VIRTIO_BLK_F_FLUSH) | (1ULL << VIRTIO_BLK_F_CONFIG_WCE) |
|
||||||
(1ULL << VIRTIO_BLK_F_BARRIER) | (1ULL << VIRTIO_BLK_F_SCSI),
|
(1ULL << VIRTIO_BLK_F_BARRIER) | (1ULL << VIRTIO_BLK_F_SCSI) | (1ULL << VIRTIO_BLK_F_DISCARD) |
|
||||||
|
(1ULL << VIRTIO_BLK_F_WRITE_ZEROES),
|
||||||
.start_device = spdk_vhost_blk_start,
|
.start_device = spdk_vhost_blk_start,
|
||||||
.stop_device = spdk_vhost_blk_stop,
|
.stop_device = spdk_vhost_blk_stop,
|
||||||
.vhost_get_config = spdk_vhost_blk_get_config,
|
.vhost_get_config = spdk_vhost_blk_get_config,
|
||||||
@ -827,6 +888,7 @@ spdk_vhost_blk_construct(const char *name, const char *cpumask, const char *dev_
|
|||||||
{
|
{
|
||||||
struct spdk_vhost_blk_dev *bvdev = NULL;
|
struct spdk_vhost_blk_dev *bvdev = NULL;
|
||||||
struct spdk_bdev *bdev;
|
struct spdk_bdev *bdev;
|
||||||
|
uint64_t features = 0;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
spdk_vhost_lock();
|
spdk_vhost_lock();
|
||||||
@ -859,14 +921,24 @@ spdk_vhost_blk_construct(const char *name, const char *cpumask, const char *dev_
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (readonly && rte_vhost_driver_enable_features(bvdev->vdev.path, (1ULL << VIRTIO_BLK_F_RO))) {
|
if (spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_UNMAP)) {
|
||||||
SPDK_ERRLOG("Controller %s: failed to set as a readonly\n", name);
|
features |= (1ULL << VIRTIO_BLK_F_DISCARD);
|
||||||
spdk_bdev_close(bvdev->bdev_desc);
|
}
|
||||||
|
if (spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_WRITE_ZEROES)) {
|
||||||
|
features |= (1ULL << VIRTIO_BLK_F_WRITE_ZEROES);
|
||||||
|
}
|
||||||
|
if (readonly) {
|
||||||
|
features |= (1ULL << VIRTIO_BLK_F_RO);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (features && rte_vhost_driver_enable_features(bvdev->vdev.path, features)) {
|
||||||
|
SPDK_ERRLOG("Controller %s: failed to enable features 0x%"PRIx64"\n", name, features);
|
||||||
|
|
||||||
if (spdk_vhost_dev_unregister(&bvdev->vdev) != 0) {
|
if (spdk_vhost_dev_unregister(&bvdev->vdev) != 0) {
|
||||||
SPDK_ERRLOG("Controller %s: failed to remove controller\n", name);
|
SPDK_ERRLOG("Controller %s: failed to remove controller\n", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spdk_bdev_close(bvdev->bdev_desc);
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user