From: Stefano Garzarella <sgarzare@redhat.com>
To: virtualization@lists.linux-foundation.org
Cc: Xie Yongji <xieyongji@bytedance.com>,
"Michael S. Tsirkin" <mst@redhat.com>,
Stefano Garzarella <sgarzare@redhat.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>,
kvm@vger.kernel.org
Subject: [PATCH RFC v2 09/10] vdpa_sim_blk: implement ramdisk behaviour
Date: Thu, 28 Jan 2021 15:41:26 +0100 [thread overview]
Message-ID: <20210128144127.113245-10-sgarzare@redhat.com> (raw)
In-Reply-To: <20210128144127.113245-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.
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 999f9ca0b628..fc47e8320358 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, Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2021, Red Hat Inc. All rights reserved.
*
*/
@@ -13,6 +14,7 @@
#include <linux/sched.h>
#include <linux/vringh.h>
#include <linux/vdpa.h>
+#include <linux/blkdev.h>
#include <uapi/linux/virtio_blk.h>
#include "vdpa_sim.h"
@@ -36,10 +38,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);
@@ -53,22 +196,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.29.2
next prev parent reply other threads:[~2021-01-28 14:48 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-01-28 14:41 [PATCH RFC v2 00/10] vdpa: add vdpa simulator for block device Stefano Garzarella
2021-01-28 14:41 ` [PATCH RFC v2 01/10] vdpa_sim: use iova module to allocate IOVA addresses Stefano Garzarella
2021-01-28 14:41 ` [PATCH RFC v2 02/10] vringh: add 'iotlb_lock' to synchronize iotlb accesses Stefano Garzarella
2021-01-29 7:43 ` Jason Wang
[not found] ` <20210129091850.gatf3ih3knw2p4l4@steredhat>
2021-02-01 6:31 ` Jason Wang
2021-01-28 14:41 ` [PATCH RFC v2 03/10] vringh: reset kiov 'consumed' field in __vringh_iov() Stefano Garzarella
2021-02-01 5:40 ` Jason Wang
2021-02-01 10:21 ` Stefano Garzarella
2021-02-02 3:26 ` Jason Wang
2021-01-28 14:41 ` [PATCH RFC v2 04/10] vringh: implement vringh_kiov_advance() Stefano Garzarella
2021-02-01 5:43 ` Jason Wang
2021-02-01 10:23 ` Stefano Garzarella
2021-01-28 14:41 ` [PATCH RFC v2 05/10] vringh: add vringh_kiov_length() helper Stefano Garzarella
2021-02-01 5:46 ` Jason Wang
2021-01-28 14:41 ` [PATCH RFC v2 06/10] vdpa_sim: cleanup kiovs in vdpasim_free() Stefano Garzarella
2021-02-01 5:47 ` Jason Wang
2021-01-28 14:41 ` [PATCH RFC v2 07/10] vdpa: Remove the restriction that only supports virtio-net devices Stefano Garzarella
2021-01-28 14:41 ` [PATCH RFC v2 08/10] vdpa: add vdpa simulator for block device Stefano Garzarella
2021-01-31 15:31 ` Max Gurtovoy
2021-02-01 8:29 ` Stefano Garzarella
2021-02-01 5:50 ` Jason Wang
2021-02-02 9:34 ` Stefan Hajnoczi
2021-02-02 15:49 ` Stefano Garzarella
2021-02-03 16:45 ` Stefan Hajnoczi
2021-02-04 8:02 ` Stefano Garzarella
2021-01-28 14:41 ` Stefano Garzarella [this message]
2021-02-01 6:03 ` [PATCH RFC v2 09/10] vdpa_sim_blk: implement ramdisk behaviour Jason Wang
2021-02-02 9:41 ` Stefan Hajnoczi
2021-01-28 14:41 ` [PATCH RFC v2 10/10] vdpa_sim_blk: handle VIRTIO_BLK_T_GET_ID Stefano Garzarella
2021-02-01 6:04 ` Jason Wang
2021-02-02 9:44 ` Stefan Hajnoczi
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=20210128144127.113245-10-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=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).