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
  ****************************************************************************/

Reply via email to