From: Stefano Garzarella <sgarzare@redhat.com>
To: virtualization@lists.linux-foundation.org
Cc: netdev@vger.kernel.org, Xie Yongji <xieyongji@bytedance.com>,
Laurent Vivier <lvivier@redhat.com>,
Stefan Hajnoczi <stefanha@redhat.com>,
linux-kernel@vger.kernel.org, Max Gurtovoy <mgurtovoy@nvidia.com>,
Jason Wang <jasowang@redhat.com>, Parav Pandit <parav@nvidia.com>,
"Michael S. Tsirkin" <mst@redhat.com>,
kvm@vger.kernel.org
Subject: [PATCH v4 12/14] vdpa_sim_blk: implement ramdisk behaviour
Date: Mon, 15 Mar 2021 17:34:48 +0100 [thread overview]
Message-ID: <20210315163450.254396-13-sgarzare@redhat.com> (raw)
In-Reply-To: <20210315163450.254396-1-sgarzare@redhat.com>
The previous implementation wrote only the status of each request.
This patch implements a more accurate block device simulator,
providing a ramdisk-like behavior and adding input validation.
Acked-by: Jason Wang <jasowang@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
---
v2:
- used %zd %zx to print size_t and ssize_t variables in dev_err()
- removed unnecessary new line [Jason]
- moved VIRTIO_BLK_T_GET_ID in another patch [Jason]
- used push/pull instead of write/read terminology
- added vdpasim_blk_check_range() to avoid overflows [Stefan]
- use vdpasim*_to_cpu instead of le*_to_cpu
- used vringh_kiov_length() helper [Jason]
---
drivers/vdpa/vdpa_sim/vdpa_sim_blk.c | 164 ++++++++++++++++++++++++---
1 file changed, 146 insertions(+), 18 deletions(-)
diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c b/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c
index 64926a70af5e..a31964e3e5a4 100644
--- a/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c
+++ b/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c
@@ -3,6 +3,7 @@
* VDPA simulator for block device.
*
* Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2021, Red Hat Inc. All rights reserved.
*
*/
@@ -14,6 +15,7 @@
#include <linux/blkdev.h>
#include <linux/vringh.h>
#include <linux/vdpa.h>
+#include <linux/blkdev.h>
#include <uapi/linux/virtio_blk.h>
#include "vdpa_sim.h"
@@ -37,10 +39,151 @@
static struct vdpasim *vdpasim_blk_dev;
+static bool vdpasim_blk_check_range(u64 start_sector, size_t range_size)
+{
+ u64 range_sectors = range_size >> SECTOR_SHIFT;
+
+ if (range_size > VDPASIM_BLK_SIZE_MAX * VDPASIM_BLK_SEG_MAX)
+ return false;
+
+ if (start_sector > VDPASIM_BLK_CAPACITY)
+ return false;
+
+ if (range_sectors > VDPASIM_BLK_CAPACITY - start_sector)
+ return false;
+
+ return true;
+}
+
+/* Returns 'true' if the request is handled (with or without an I/O error)
+ * and the status is correctly written in the last byte of the 'in iov',
+ * 'false' otherwise.
+ */
+static bool vdpasim_blk_handle_req(struct vdpasim *vdpasim,
+ struct vdpasim_virtqueue *vq)
+{
+ size_t pushed = 0, to_pull, to_push;
+ struct virtio_blk_outhdr hdr;
+ ssize_t bytes;
+ loff_t offset;
+ u64 sector;
+ u8 status;
+ u32 type;
+ int ret;
+
+ ret = vringh_getdesc_iotlb(&vq->vring, &vq->out_iov, &vq->in_iov,
+ &vq->head, GFP_ATOMIC);
+ if (ret != 1)
+ return false;
+
+ if (vq->out_iov.used < 1 || vq->in_iov.used < 1) {
+ dev_err(&vdpasim->vdpa.dev, "missing headers - out_iov: %u in_iov %u\n",
+ vq->out_iov.used, vq->in_iov.used);
+ return false;
+ }
+
+ if (vq->in_iov.iov[vq->in_iov.used - 1].iov_len < 1) {
+ dev_err(&vdpasim->vdpa.dev, "request in header too short\n");
+ return false;
+ }
+
+ /* The last byte is the status and we checked if the last iov has
+ * enough room for it.
+ */
+ to_push = vringh_kiov_length(&vq->in_iov) - 1;
+
+ to_pull = vringh_kiov_length(&vq->out_iov);
+
+ bytes = vringh_iov_pull_iotlb(&vq->vring, &vq->out_iov, &hdr,
+ sizeof(hdr));
+ if (bytes != sizeof(hdr)) {
+ dev_err(&vdpasim->vdpa.dev, "request out header too short\n");
+ return false;
+ }
+
+ to_pull -= bytes;
+
+ type = vdpasim32_to_cpu(vdpasim, hdr.type);
+ sector = vdpasim64_to_cpu(vdpasim, hdr.sector);
+ offset = sector << SECTOR_SHIFT;
+ status = VIRTIO_BLK_S_OK;
+
+ switch (type) {
+ case VIRTIO_BLK_T_IN:
+ if (!vdpasim_blk_check_range(sector, to_push)) {
+ dev_err(&vdpasim->vdpa.dev,
+ "reading over the capacity - offset: 0x%llx len: 0x%zx\n",
+ offset, to_push);
+ status = VIRTIO_BLK_S_IOERR;
+ break;
+ }
+
+ bytes = vringh_iov_push_iotlb(&vq->vring, &vq->in_iov,
+ vdpasim->buffer + offset,
+ to_push);
+ if (bytes < 0) {
+ dev_err(&vdpasim->vdpa.dev,
+ "vringh_iov_push_iotlb() error: %zd offset: 0x%llx len: 0x%zx\n",
+ bytes, offset, to_push);
+ status = VIRTIO_BLK_S_IOERR;
+ break;
+ }
+
+ pushed += bytes;
+ break;
+
+ case VIRTIO_BLK_T_OUT:
+ if (!vdpasim_blk_check_range(sector, to_pull)) {
+ dev_err(&vdpasim->vdpa.dev,
+ "writing over the capacity - offset: 0x%llx len: 0x%zx\n",
+ offset, to_pull);
+ status = VIRTIO_BLK_S_IOERR;
+ break;
+ }
+
+ bytes = vringh_iov_pull_iotlb(&vq->vring, &vq->out_iov,
+ vdpasim->buffer + offset,
+ to_pull);
+ if (bytes < 0) {
+ dev_err(&vdpasim->vdpa.dev,
+ "vringh_iov_pull_iotlb() error: %zd offset: 0x%llx len: 0x%zx\n",
+ bytes, offset, to_pull);
+ status = VIRTIO_BLK_S_IOERR;
+ break;
+ }
+ break;
+
+ default:
+ dev_warn(&vdpasim->vdpa.dev,
+ "Unsupported request type %d\n", type);
+ status = VIRTIO_BLK_S_IOERR;
+ break;
+ }
+
+ /* If some operations fail, we need to skip the remaining bytes
+ * to put the status in the last byte
+ */
+ if (to_push - pushed > 0)
+ vringh_kiov_advance(&vq->in_iov, to_push - pushed);
+
+ /* Last byte is the status */
+ bytes = vringh_iov_push_iotlb(&vq->vring, &vq->in_iov, &status, 1);
+ if (bytes != 1)
+ return false;
+
+ pushed += bytes;
+
+ /* Make sure data is wrote before advancing index */
+ smp_wmb();
+
+ vringh_complete_iotlb(&vq->vring, vq->head, pushed);
+
+ return true;
+}
+
static void vdpasim_blk_work(struct work_struct *work)
{
struct vdpasim *vdpasim = container_of(work, struct vdpasim, work);
- u8 status = VIRTIO_BLK_S_OK;
int i;
spin_lock(&vdpasim->lock);
@@ -54,22 +197,7 @@ static void vdpasim_blk_work(struct work_struct *work)
if (!vq->ready)
continue;
- while (vringh_getdesc_iotlb(&vq->vring, &vq->out_iov,
- &vq->in_iov, &vq->head,
- GFP_ATOMIC) > 0) {
- int write;
-
- vq->in_iov.i = vq->in_iov.used - 1;
- write = vringh_iov_push_iotlb(&vq->vring, &vq->in_iov,
- &status, 1);
- if (write <= 0)
- break;
-
- /* Make sure data is wrote before advancing index */
- smp_wmb();
-
- vringh_complete_iotlb(&vq->vring, vq->head, write);
-
+ while (vdpasim_blk_handle_req(vdpasim, vq)) {
/* Make sure used is visible before rasing the interrupt. */
smp_wmb();
@@ -109,7 +237,7 @@ static int __init vdpasim_blk_init(void)
dev_attr.config_size = sizeof(struct virtio_blk_config);
dev_attr.get_config = vdpasim_blk_get_config;
dev_attr.work_fn = vdpasim_blk_work;
- dev_attr.buffer_size = PAGE_SIZE;
+ dev_attr.buffer_size = VDPASIM_BLK_CAPACITY << SECTOR_SHIFT;
vdpasim_blk_dev = vdpasim_create(&dev_attr);
if (IS_ERR(vdpasim_blk_dev)) {
--
2.30.2
next prev parent reply other threads:[~2021-03-15 16:37 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-03-15 16:34 [PATCH v4 00/14] vdpa: add vdpa simulator for block device Stefano Garzarella
2021-03-15 16:34 ` [PATCH v4 01/14] vdpa_sim: use iova module to allocate IOVA addresses Stefano Garzarella
2021-03-15 16:34 ` [PATCH v4 02/14] vringh: add 'iotlb_lock' to synchronize iotlb accesses Stefano Garzarella
2021-03-15 16:34 ` [PATCH v4 03/14] vringh: reset kiov 'consumed' field in __vringh_iov() Stefano Garzarella
2021-03-15 16:34 ` [PATCH v4 04/14] vringh: explain more about cleaning riov and wiov Stefano Garzarella
2021-03-15 16:34 ` [PATCH v4 05/14] vringh: implement vringh_kiov_advance() Stefano Garzarella
2021-03-15 16:34 ` [PATCH v4 06/14] vringh: add vringh_kiov_length() helper Stefano Garzarella
2021-03-15 16:51 ` Laurent Vivier
2021-03-15 17:06 ` Stefano Garzarella
2021-03-15 16:34 ` [PATCH v4 07/14] vdpa_sim: cleanup kiovs in vdpasim_free() Stefano Garzarella
2021-03-15 16:34 ` [PATCH v4 08/14] vdpa: add get_config_size callback in vdpa_config_ops Stefano Garzarella
2021-03-18 3:21 ` Jason Wang
2021-03-15 16:34 ` [PATCH v4 09/14] vhost/vdpa: use get_config_size callback in vhost_vdpa_config_validate() Stefano Garzarella
2021-03-18 3:22 ` Jason Wang
2021-03-15 16:34 ` [PATCH v4 10/14] vhost/vdpa: Remove the restriction that only supports virtio-net devices Stefano Garzarella
2021-03-18 3:24 ` Jason Wang
2021-03-15 16:34 ` [PATCH v4 11/14] vdpa: add vdpa simulator for block device Stefano Garzarella
2021-03-15 16:34 ` Stefano Garzarella [this message]
2021-03-15 16:34 ` [PATCH v4 13/14] vdpa_sim_blk: handle VIRTIO_BLK_T_GET_ID Stefano Garzarella
2021-03-15 16:34 ` [PATCH v4 14/14] vdpa_sim_blk: add support for vdpa management tool Stefano Garzarella
2021-03-18 3:31 ` Jason Wang
2021-04-12 8:18 ` [PATCH v4 00/14] vdpa: add vdpa simulator for block device Stefano Garzarella
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210315163450.254396-13-sgarzare@redhat.com \
--to=sgarzare@redhat.com \
--cc=jasowang@redhat.com \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=lvivier@redhat.com \
--cc=mgurtovoy@nvidia.com \
--cc=mst@redhat.com \
--cc=netdev@vger.kernel.org \
--cc=parav@nvidia.com \
--cc=stefanha@redhat.com \
--cc=virtualization@lists.linux-foundation.org \
--cc=xieyongji@bytedance.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).