This is an automated email from the ASF dual-hosted git repository.
xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 0884a521e58 drivers/vhost: add vhost-blk backend
0884a521e58 is described below
commit 0884a521e587198fa303611c5f13a154b6f6d196
Author: Yongrong Wang <[email protected]>
AuthorDate: Fri Aug 30 18:45:07 2024 +0800
drivers/vhost: add vhost-blk backend
Add the device side of virtio-blk. The frontend's block requests are
served from a local block device or file whose path the driver reads
from the device config space (struct vhost_blk_config_s), on a
dedicated kernel thread.
IN and OUT requests seek to req->sector and read or write the data
buffer; FLUSH issues BIOC_FLUSH when VIRTIO_BLK_F_FLUSH was negotiated.
The result is written to the status byte of the last descriptor.
Signed-off-by: Yongrong Wang <[email protected]>
Signed-off-by: yintao <[email protected]>
---
drivers/vhost/CMakeLists.txt | 4 +
drivers/vhost/Kconfig | 17 ++
drivers/vhost/Make.defs | 4 +
drivers/vhost/vhost-blk.c | 338 ++++++++++++++++++++++++++++++++++++++
drivers/vhost/vhost-blk.h | 61 +++++++
drivers/vhost/vhost.c | 9 +
include/nuttx/virtio/virtio-blk.h | 11 ++
7 files changed, 444 insertions(+)
diff --git a/drivers/vhost/CMakeLists.txt b/drivers/vhost/CMakeLists.txt
index faad9b1f999..3ee25b8938a 100644
--- a/drivers/vhost/CMakeLists.txt
+++ b/drivers/vhost/CMakeLists.txt
@@ -25,6 +25,10 @@ if(CONFIG_DRIVERS_VHOST)
list(APPEND SRCS vhost.c)
endif()
+if(CONFIG_DRIVERS_VHOST_BLK)
+ list(APPEND SRCS vhost-blk.c)
+endif()
+
if(CONFIG_DRIVERS_VHOST_CAN)
list(APPEND SRCS vhost-can.c)
endif()
diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig
index db7a8caa659..4ae63dd5e62 100644
--- a/drivers/vhost/Kconfig
+++ b/drivers/vhost/Kconfig
@@ -33,6 +33,23 @@ config DRIVERS_VHOST_I2C
one NuttX instance export an I2C bus to a remote VirtIO I2C
frontend,
the native-VirtIO counterpart of the RPMSG I2C server.
+config DRIVERS_VHOST_BLK
+ bool "Virtual Host Blk Device Support"
+ default n
+ select DRIVERS_VHOST
+
+if DRIVERS_VHOST_BLK
+
+config DRIVERS_VHOST_BLK_PRIORITY
+ int "vhost blk thread priority"
+ default 224
+
+config DRIVERS_VHOST_BLK_STACKSIZE
+ int "vhost blk stack size"
+ default 4096
+
+endif # DRIVERS_VHOST_BLK
+
config DRIVERS_VHOST_RNG
bool "Virtual Host Rng Device Support"
default n
diff --git a/drivers/vhost/Make.defs b/drivers/vhost/Make.defs
index 3f810163021..4730bd45bf0 100644
--- a/drivers/vhost/Make.defs
+++ b/drivers/vhost/Make.defs
@@ -26,6 +26,10 @@ ifeq ($(CONFIG_DRIVERS_VHOST),y)
CSRCS += vhost.c
endif
+ifeq ($(CONFIG_DRIVERS_VHOST_BLK),y)
+ CSRCS += vhost-blk.c
+endif
+
ifeq ($(CONFIG_DRIVERS_VHOST_CAN),y)
CSRCS += vhost-can.c
endif
diff --git a/drivers/vhost/vhost-blk.c b/drivers/vhost/vhost-blk.c
new file mode 100644
index 00000000000..eb51369870a
--- /dev/null
+++ b/drivers/vhost/vhost-blk.c
@@ -0,0 +1,338 @@
+/****************************************************************************
+ * drivers/vhost/vhost-blk.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <debug.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include <nuttx/fs/fs.h>
+#include <nuttx/fs/ioctl.h>
+#include <nuttx/kthread.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/vhost/vhost.h>
+#include <nuttx/virtio/virtio-blk.h>
+#include <nuttx/virtio/virtio-config.h>
+
+#include "vhost-blk.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct vhost_blk_priv_s
+{
+ FAR struct vhost_device *hdev; /* Virtio device */
+ sem_t semrx;
+ pid_t pid;
+ struct file bdev;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* BLK block_operations functions and they helper function */
+
+static ssize_t vhost_blk_rdwr_handler(FAR struct vhost_blk_priv_s *priv,
+ FAR struct virtio_blk_req_s *req,
+ uint16_t idx, FAR uint16_t *next_idx,
+ bool write);
+
+/* Other functions */
+
+static int vhost_blk_probe(FAR struct vhost_device *vdev);
+static void vhost_blk_remove(FAR struct vhost_device *vdev);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct vhost_driver g_vhost_blk_driver =
+{
+ LIST_INITIAL_VALUE(g_vhost_blk_driver.node), /* node */
+ VIRTIO_ID_BLOCK, /* device id */
+ vhost_blk_probe, /* probe */
+ vhost_blk_remove, /* remove */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: vhost_blk_read_handler
+ ****************************************************************************/
+
+static ssize_t vhost_blk_rdwr_handler(FAR struct vhost_blk_priv_s *priv,
+ FAR struct virtio_blk_req_s *req,
+ uint16_t idx, FAR uint16_t *next_idx,
+ bool write)
+{
+ FAR struct virtqueue *vq = priv->hdev->vrings_info[0].vq;
+ struct virtqueue_buf vb;
+ ssize_t ret = -EIO;
+ uint32_t len;
+
+ vb.buf = virtqueue_get_next_avail_buffer(vq, idx, next_idx, &len);
+ if (vb.buf == NULL)
+ {
+ return -ENOBUFS;
+ }
+
+ file_seek(&priv->bdev,
+ req->sector << VIRTIO_BLK_SECTOR_BITS, SEEK_SET);
+
+ if (write)
+ {
+ ret = file_write(&priv->bdev, vb.buf, len);
+ }
+ else
+ {
+ ret = file_read(&priv->bdev, vb.buf, len);
+ }
+
+ if (ret < 0)
+ {
+ vhosterr("%s error ret=%zd\n", write ? "Write" : "Read", ret);
+ }
+
+ vb.len = ret;
+ return ret;
+}
+
+/****************************************************************************
+ * Name: vhost_blk_handler
+ ****************************************************************************/
+
+static int vhost_blk_handler(FAR struct vhost_blk_priv_s *priv,
+ FAR struct virtqueue *vq,
+ FAR void *buf, uint16_t idx)
+{
+ FAR struct virtio_blk_req_s *req = (FAR struct virtio_blk_req_s *)buf;
+ FAR struct virtio_blk_resp_s *resp;
+ int ret = -EINVAL;
+
+ switch (req->type)
+ {
+ case VIRTIO_BLK_T_IN:
+ ret = vhost_blk_rdwr_handler(priv, req, idx, &idx, false);
+ break;
+ case VIRTIO_BLK_T_OUT:
+ ret = vhost_blk_rdwr_handler(priv, req, idx, &idx, true);
+ break;
+ case VIRTIO_BLK_T_FLUSH:
+ if (vhost_has_feature(priv->hdev, VIRTIO_BLK_F_FLUSH))
+ {
+ ret = file_ioctl(&priv->bdev, BIOC_FLUSH, 0);
+ }
+ break;
+ }
+
+ resp = virtqueue_get_next_avail_buffer(vq, idx, &idx, NULL);
+ if (resp == NULL)
+ {
+ return -ENOBUFS;
+ }
+
+ resp->status = ret < 0 ? VIRTIO_BLK_S_IOERR : VIRTIO_BLK_S_OK;
+ return ret;
+}
+
+/****************************************************************************
+ * Name: vhost_blk_work
+ ****************************************************************************/
+
+static void vhost_blk_work(FAR struct vhost_blk_priv_s *priv)
+{
+ FAR struct virtqueue *vq;
+ FAR void *buf;
+ uint32_t len;
+ uint16_t idx;
+ int ret;
+
+ vq = priv->hdev->vrings_info[0].vq;
+ for (; ; )
+ {
+ buf = virtqueue_get_first_avail_buffer(vq, &idx, &len);
+ if (buf == NULL)
+ {
+ break;
+ }
+
+ ret = vhost_blk_handler(priv, vq, buf, idx);
+ if (ret < 0)
+ {
+ vhosterr("handler failed, ret=%d\n", ret);
+ }
+
+ virtqueue_add_consumed_buffer(vq, idx, len);
+ }
+
+ virtqueue_kick(vq);
+}
+
+/****************************************************************************
+ * Name: vhost_blk_thread
+ ****************************************************************************/
+
+static int vhost_blk_thread(int argc, FAR char *argv[])
+{
+ FAR struct vhost_blk_priv_s *priv =
+ (FAR struct vhost_blk_priv_s *)((uintptr_t)strtoul(argv[1], NULL, 16));
+
+ while (1)
+ {
+ nxsem_wait_uninterruptible(&priv->semrx);
+ vhost_blk_work(priv);
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ * Name: vhost_blk_callback
+ ****************************************************************************/
+
+static void vhost_blk_callback(FAR struct virtqueue *vq)
+{
+ FAR struct vhost_blk_priv_s *priv = vq->vq_dev->priv;
+ int semcount;
+
+ nxsem_get_value(&priv->semrx, &semcount);
+ while (semcount++ < 1)
+ {
+ nxsem_post(&priv->semrx);
+ }
+}
+
+/****************************************************************************
+ * Name: vhost_blk_probe
+ ****************************************************************************/
+
+static int vhost_blk_probe(FAR struct vhost_device *hdev)
+{
+ FAR struct vhost_blk_priv_s *priv;
+ FAR const char *vqname[1];
+ vq_callback callback[1];
+ FAR char *argv[2];
+ char path[PATH_MAX];
+ char arg0[32];
+ int ret;
+
+ /* Alloc the vhost block driver private data */
+
+ priv = kmm_zalloc(sizeof(*priv));
+ if (priv == NULL)
+ {
+ vhosterr("No enough memory\n");
+ return -ENOMEM;
+ }
+
+ /* Init the vhost block driver */
+
+ priv->hdev = hdev;
+ hdev->priv = priv;
+ nxsem_init(&priv->semrx, 0, 0);
+
+ /* Read the block config path */
+
+ vhost_read_config_member(priv->hdev, struct vhost_blk_config_s,
+ path, &path);
+ ret = file_open(&priv->bdev, path, O_RDWR | O_CLOEXEC);
+ if (ret < 0)
+ {
+ vhosterr("ERROR: Failed to open block driver\n");
+ goto err_init;
+ }
+
+ vqname[0] = "virtio_blk";
+ callback[0] = vhost_blk_callback;
+ ret = vhost_create_virtqueues(hdev, 0, 1, vqname, callback, NULL);
+ if (ret < 0)
+ {
+ vhosterr("vhost_device_create_virtqueue failed, ret=%d\n", ret);
+ goto err_vq;
+ }
+
+ snprintf(arg0, sizeof(arg0), "%p", priv);
+ argv[0] = arg0;
+ argv[1] = NULL;
+
+ priv->pid = kthread_create("vhost-blk",
+ CONFIG_DRIVERS_VHOST_BLK_PRIORITY,
+ CONFIG_DRIVERS_VHOST_BLK_STACKSIZE,
+ vhost_blk_thread, argv);
+ if (priv->pid < 0)
+ {
+ vhosterr("vhost blk thread create failed %d\n", priv->pid);
+ ret = priv->pid;
+ goto err_thread;
+ }
+
+ virtqueue_enable_cb(hdev->vrings_info[0].vq);
+ return ret;
+
+err_thread:
+ vhost_delete_virtqueues(hdev);
+err_vq:
+ file_close(&priv->bdev);
+ nxsem_destroy(&priv->semrx);
+err_init:
+ kmm_free(priv);
+ return ret;
+}
+
+/****************************************************************************
+ * Name: vhost_blk_remove
+ ****************************************************************************/
+
+static void vhost_blk_remove(FAR struct vhost_device *hdev)
+{
+ FAR struct vhost_blk_priv_s *priv = hdev->priv;
+
+ virtqueue_disable_cb(hdev->vrings_info[0].vq);
+ kthread_delete(priv->pid);
+ vhost_delete_virtqueues(hdev);
+ file_close(&priv->bdev);
+ nxsem_destroy(&priv->semrx);
+ kmm_free(priv);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: vhost_register_blk_driver
+ ****************************************************************************/
+
+int vhost_register_blk_driver(void)
+{
+ return vhost_register_driver(&g_vhost_blk_driver);
+}
diff --git a/drivers/vhost/vhost-blk.h b/drivers/vhost/vhost-blk.h
new file mode 100644
index 00000000000..e1e097960da
--- /dev/null
+++ b/drivers/vhost/vhost-blk.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+ * drivers/vhost/vhost-blk.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __DRIVERS_VHOST_VHOST_BLK_H
+#define __DRIVERS_VHOST_VHOST_BLK_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#ifdef CONFIG_DRIVERS_VHOST_BLK
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+int vhost_register_blk_driver(void);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CONFIG_DRIVERS_VHOST_BLK */
+
+#endif /* __DRIVERS_VHOST_VHOST_BLK_H */
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index 1441707910b..e991de2853e 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -35,6 +35,7 @@
# include "vhost-net.h"
#endif
+#include "vhost-blk.h"
#include "vhost-can.h"
#include "vhost-i2c.h"
#include "vhost-rng.h"
@@ -522,6 +523,14 @@ void vhost_register_drivers(void)
}
#endif
+#ifdef CONFIG_DRIVERS_VHOST_BLK
+ ret = vhost_register_blk_driver();
+ if (ret < 0)
+ {
+ vhosterr("vhost_register_blk_driver failed, ret=%d\n", ret);
+ }
+#endif
+
#ifdef CONFIG_DRIVERS_VHOST_CAN
ret = vhost_register_can_driver();
if (ret < 0)
diff --git a/include/nuttx/virtio/virtio-blk.h
b/include/nuttx/virtio/virtio-blk.h
index d199b5e6b4c..34c1be29986 100644
--- a/include/nuttx/virtio/virtio-blk.h
+++ b/include/nuttx/virtio/virtio-blk.h
@@ -25,8 +25,11 @@
* Included Files
****************************************************************************/
+#include <limits.h>
#include <stdint.h>
+#include <nuttx/compiler.h>
+
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
@@ -57,6 +60,8 @@
#define VIRTIO_BLK_SECTOR_BITS 9
#define VIRTIO_BLK_SECTOR_SIZE (1UL << VIRTIO_BLK_SECTOR_BITS)
+#define VIRTIO_BLK_PATH_SIZE PATH_MAX
+
/****************************************************************************
* Public Type Definitions
****************************************************************************/
@@ -105,6 +110,12 @@ begin_packed_struct struct virtio_blk_config_s
uint32_t secure_erase_sector_alignment;
} end_packed_struct;
+begin_packed_struct struct vhost_blk_config_s
+{
+ struct virtio_blk_config_s config;
+ char path[VIRTIO_BLK_PATH_SIZE];
+} end_packed_struct;
+
/****************************************************************************
* Public Function Prototypes
****************************************************************************/