get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/62106/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 62106,
    "url": "http://patches.dpdk.org/api/patches/62106/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20191028193756.27757-1-jin.yu@intel.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20191028193756.27757-1-jin.yu@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20191028193756.27757-1-jin.yu@intel.com",
    "date": "2019-10-28T19:37:56",
    "name": "vhost: add vhost-user-blk example which support inflight",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "c6cebe432918c1a2642bdca873c0da7f06830016",
    "submitter": {
        "id": 1265,
        "url": "http://patches.dpdk.org/api/people/1265/?format=api",
        "name": "Jin Yu",
        "email": "jin.yu@intel.com"
    },
    "delegate": {
        "id": 2642,
        "url": "http://patches.dpdk.org/api/users/2642/?format=api",
        "username": "mcoquelin",
        "first_name": "Maxime",
        "last_name": "Coquelin",
        "email": "maxime.coquelin@redhat.com"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20191028193756.27757-1-jin.yu@intel.com/mbox/",
    "series": [
        {
            "id": 7107,
            "url": "http://patches.dpdk.org/api/series/7107/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=7107",
            "date": "2019-10-28T19:37:56",
            "name": "vhost: add vhost-user-blk example which support inflight",
            "version": 1,
            "mbox": "http://patches.dpdk.org/series/7107/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/62106/comments/",
    "check": "fail",
    "checks": "http://patches.dpdk.org/api/patches/62106/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 1C9BF1BEDB;\n\tMon, 28 Oct 2019 12:57:35 +0100 (CET)",
            "from mga14.intel.com (mga14.intel.com [192.55.52.115])\n\tby dpdk.org (Postfix) with ESMTP id 260DE1BED4\n\tfor <dev@dpdk.org>; Mon, 28 Oct 2019 12:57:32 +0100 (CET)",
            "from orsmga006.jf.intel.com ([10.7.209.51])\n\tby fmsmga103.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t28 Oct 2019 04:57:32 -0700",
            "from storage36.sh.intel.com ([10.67.110.177])\n\tby orsmga006.jf.intel.com with ESMTP; 28 Oct 2019 04:57:29 -0700"
        ],
        "X-Amp-Result": "SKIPPED(no attachment in message)",
        "X-Amp-File-Uploaded": "False",
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.68,239,1569308400\"; d=\"scan'208\";a=\"203243450\"",
        "From": "Jin Yu <jin.yu@intel.com>",
        "To": "Thomas Monjalon <thomas@monjalon.net>,\n\tJohn McNamara <john.mcnamara@intel.com>,\n\tMarko Kovacevic <marko.kovacevic@intel.com>,\n\tMaxime Coquelin <maxime.coquelin@redhat.com>,\n\tTiwei Bie <tiwei.bie@intel.com>, Zhihong Wang <zhihong.wang@intel.com>",
        "Cc": "dev@dpdk.org,\n\tJin Yu <jin.yu@intel.com>",
        "Date": "Tue, 29 Oct 2019 03:37:56 +0800",
        "Message-Id": "<20191028193756.27757-1-jin.yu@intel.com>",
        "X-Mailer": "git-send-email 2.17.2",
        "In-Reply-To": "<20191009204837.65039-10-jin.yu@intel.com>",
        "References": "<20191009204837.65039-10-jin.yu@intel.com>",
        "Subject": "[dpdk-dev] [PATCH] vhost: add vhost-user-blk example which support\n\tinflight",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "A vhost-user-blk example that support inflight feature. It uses the\nnew APIs that introduced in the first patch, so it can show how these\nAPIs work to support inflight feature.\n\nSigned-off-by: Jin Yu <jin.yu@intel.com>\n---\nV1 - add the case.\nV2 - add the rte_vhost prefix.\nV3 - add packed ring support\nV4 - fix build, MAINTAINERS and add guides\n---\n MAINTAINERS                            |    2 +\n doc/guides/sample_app_ug/index.rst     |    1 +\n doc/guides/sample_app_ug/vhost_blk.rst |   63 ++\n examples/meson.build                   |    2 +-\n examples/vhost_blk/Makefile            |   68 ++\n examples/vhost_blk/blk.c               |  125 +++\n examples/vhost_blk/blk_spec.h          |   95 ++\n examples/vhost_blk/meson.build         |   21 +\n examples/vhost_blk/vhost_blk.c         | 1094 ++++++++++++++++++++++++\n examples/vhost_blk/vhost_blk.h         |  127 +++\n examples/vhost_blk/vhost_blk_compat.c  |  173 ++++\n 11 files changed, 1770 insertions(+), 1 deletion(-)\n create mode 100644 doc/guides/sample_app_ug/vhost_blk.rst\n create mode 100644 examples/vhost_blk/Makefile\n create mode 100644 examples/vhost_blk/blk.c\n create mode 100644 examples/vhost_blk/blk_spec.h\n create mode 100644 examples/vhost_blk/meson.build\n create mode 100644 examples/vhost_blk/vhost_blk.c\n create mode 100644 examples/vhost_blk/vhost_blk.h\n create mode 100644 examples/vhost_blk/vhost_blk_compat.c",
    "diff": "diff --git a/MAINTAINERS b/MAINTAINERS\nindex 717c31801..c22a8312e 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -839,6 +839,8 @@ F: lib/librte_vhost/\n F: doc/guides/prog_guide/vhost_lib.rst\n F: examples/vhost/\n F: doc/guides/sample_app_ug/vhost.rst\n+F: example/vhost_blk/\n+F: doc/guides/sample_app_ug/vhost_blk.rst\n F: examples/vhost_crypto/\n F: examples/vdpa/\n F: doc/guides/sample_app_ug/vdpa.rst\ndiff --git a/doc/guides/sample_app_ug/index.rst b/doc/guides/sample_app_ug/index.rst\nindex a3737c118..613f483f3 100644\n--- a/doc/guides/sample_app_ug/index.rst\n+++ b/doc/guides/sample_app_ug/index.rst\n@@ -40,6 +40,7 @@ Sample Applications User Guides\n     packet_ordering\n     vmdq_dcb_forwarding\n     vhost\n+    vhost_blk\n     vhost_crypto\n     vdpa\n     ip_pipeline\ndiff --git a/doc/guides/sample_app_ug/vhost_blk.rst b/doc/guides/sample_app_ug/vhost_blk.rst\nnew file mode 100644\nindex 000000000..39096e2e4\n--- /dev/null\n+++ b/doc/guides/sample_app_ug/vhost_blk.rst\n@@ -0,0 +1,63 @@\n+..  SPDX-License-Identifier: BSD-3-Clause\n+    Copyright(c) 2010-2017 Intel Corporation.\n+\n+Vhost_blk Sample Application\n+=============================\n+\n+The vhost_blk sample application implemented a simple block device,\n+which used as the  backend of Qemu vhost-user-blk device. Users can extend\n+the exist example to use other type of block device(e.g. AIO) besides\n+memory based block device. Similar with vhost-user-net device, the sample\n+application used domain socket to communicate with Qemu, and the virtio\n+ring (split or packed format) was processed by vhost_blk sample application.\n+\n+The sample application reuse lots codes from SPDK(Storage Performance\n+Development Kit, https://github.com/spdk/spdk) vhost-user-blk target,\n+for DPDK vhost library used in storage area, user can take SPDK as\n+reference as well.\n+\n+Testing steps\n+-------------\n+\n+This section shows the steps how to start a VM with the block device as\n+fast data path for critical application.\n+\n+Compiling the Application\n+-------------------------\n+\n+To compile the sample application see :doc:`compiling`.\n+\n+The application is located in the ``examples`` sub-directory.\n+\n+You will also need to build DPDK both on the host and inside the guest\n+\n+Start the vhost_blk example\n+~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n+\n+.. code-block:: console\n+\n+        ./vhost_blk -m 1024\n+\n+.. _vhost_blk_app_run_vm:\n+\n+Start the VM\n+~~~~~~~~~~~~\n+\n+.. code-block:: console\n+\n+    qemu-system-x86_64 -machine accel=kvm \\\n+        -m $mem -object memory-backend-file,id=mem,size=$mem,\\\n+        mem-path=/dev/hugepages,share=on -numa node,memdev=mem \\\n+        -drive file=os.img,if=none,id=disk \\\n+        -device ide-hd,drive=disk,bootindex=0 \\\n+        -chardev socket,id=char0,reconnect=1,path=/tmp/vhost.socket \\\n+        -device vhost-user-blk-pci,ring_packed=1,chardev=char0,num-queues=1 \\\n+        ...\n+\n+.. note::\n+    You must check whether your Qemu can support \"vhost-user-blk\" or not,\n+    Qemu v4.0 or newer version is required.\n+    reconnect=1 means live recovery support that qemu can reconnect vhost_blk\n+    after we restart vhost_blk example.\n+    ring_packed=1 means the device support packed ring but need the guest kernel\n+    version >= 5.0\ndiff --git a/examples/meson.build b/examples/meson.build\nindex 98ae50a49..10a6bd7ef 100644\n--- a/examples/meson.build\n+++ b/examples/meson.build\n@@ -42,7 +42,7 @@ all_examples = [\n \t'skeleton', 'tep_termination',\n \t'timer', 'vdpa',\n \t'vhost', 'vhost_crypto',\n-\t'vm_power_manager',\n+\t'vhost_blk', 'vm_power_manager',\n \t'vm_power_manager/guest_cli',\n \t'vmdq', 'vmdq_dcb',\n ]\ndiff --git a/examples/vhost_blk/Makefile b/examples/vhost_blk/Makefile\nnew file mode 100644\nindex 000000000..a10a90071\n--- /dev/null\n+++ b/examples/vhost_blk/Makefile\n@@ -0,0 +1,68 @@\n+# SPDX-License-Identifier: BSD-3-Clause\n+# Copyright(c) 2010-2014 Intel Corporation\n+\n+# binary name\n+APP = vhost-blk\n+\n+# all source are stored in SRCS-y\n+SRCS-y := blk.c vhost_blk.c vhost_blk_compat.c\n+\n+# Build using pkg-config variables if possible\n+$(shell pkg-config --exists libdpdk)\n+ifeq ($(.SHELLSTATUS),0)\n+\n+all: shared\n+.PHONY: shared static\n+shared: build/$(APP)-shared\n+\tln -sf $(APP)-shared build/$(APP)\n+static: build/$(APP)-static\n+\tln -sf $(APP)-static build/$(APP)\n+\n+LDFLAGS += -pthread\n+\n+PC_FILE := $(shell pkg-config --path libdpdk)\n+CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)\n+LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)\n+LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)\n+\n+CFLAGS += -DALLOW_EXPERIMENTAL_API\n+\n+build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build\n+\t$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)\n+\n+build/$(APP)-static: $(SRCS-y) Makefile $(PC_FILE) | build\n+\t$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_STATIC)\n+\n+build:\n+\t@mkdir -p $@\n+\n+.PHONY: clean\n+clean:\n+\trm -f build/$(APP) build/$(APP)-static build/$(APP)-shared\n+\ttest -d build && rmdir -p build || true\n+\n+else # Build using legacy build system\n+\n+ifeq ($(RTE_SDK),)\n+$(error \"Please define RTE_SDK environment variable\")\n+endif\n+\n+# Default target, detect a build directory, by looking for a path with a .config\n+RTE_TARGET ?= $(notdir $(abspath $(dir $(firstword $(wildcard $(RTE_SDK)/*/.config)))))\n+\n+include $(RTE_SDK)/mk/rte.vars.mk\n+\n+ifneq ($(CONFIG_RTE_EXEC_ENV_LINUX),y)\n+$(info This application can only operate in a linux environment, \\\n+please change the definition of the RTE_TARGET environment variable)\n+all:\n+else\n+\n+CFLAGS += -DALLOW_EXPERIMENTAL_API\n+CFLAGS += -O2 -D_FILE_OFFSET_BITS=64\n+CFLAGS += $(WERROR_FLAGS)\n+\n+include $(RTE_SDK)/mk/rte.extapp.mk\n+\n+endif\n+endif\ndiff --git a/examples/vhost_blk/blk.c b/examples/vhost_blk/blk.c\nnew file mode 100644\nindex 000000000..424ed3015\n--- /dev/null\n+++ b/examples/vhost_blk/blk.c\n@@ -0,0 +1,125 @@\n+// SPDX-License-Identifier: BSD-3-Clause\n+// Copyright(c) 2010-2019 Intel Corporation\n+\n+/**\n+ * This work is largely based on the \"vhost-user-blk\" implementation by\n+ * SPDK(https://github.com/spdk/spdk).\n+ */\n+\n+#include <stdio.h>\n+#include <stdint.h>\n+#include <unistd.h>\n+#include <assert.h>\n+#include <ctype.h>\n+#include <string.h>\n+#include <stddef.h>\n+\n+#include <rte_atomic.h>\n+#include <rte_cycles.h>\n+#include <rte_log.h>\n+#include <rte_malloc.h>\n+#include <rte_byteorder.h>\n+#include <rte_string_fns.h>\n+\n+#include \"vhost_blk.h\"\n+#include \"blk_spec.h\"\n+\n+static void\n+vhost_strcpy_pad(void *dst, const char *src, size_t size, int pad)\n+{\n+\tsize_t len;\n+\n+\tlen = strlen(src);\n+\tif (len < size) {\n+\t\tmemcpy(dst, src, len);\n+\t\tmemset((char *)dst + len, pad, size - len);\n+\t} else {\n+\t\tmemcpy(dst, src, size);\n+\t}\n+}\n+\n+static int\n+vhost_bdev_blk_readwrite(struct vhost_block_dev *bdev,\n+\t\t\t  struct vhost_blk_task *task,\n+\t\t\t  uint64_t lba_512, __rte_unused uint32_t xfer_len)\n+{\n+\tuint32_t i;\n+\tuint64_t offset;\n+\tuint32_t nbytes = 0;\n+\n+\toffset = lba_512 * 512;\n+\n+\tfor (i = 0; i < task->iovs_cnt; i++) {\n+\t\tif (task->dxfer_dir == BLK_DIR_TO_DEV)\n+\t\t\tmemcpy(bdev->data + offset, task->iovs[i].iov_base,\n+\t\t\t       task->iovs[i].iov_len);\n+\t\telse\n+\t\t\tmemcpy(task->iovs[i].iov_base, bdev->data + offset,\n+\t\t\t       task->iovs[i].iov_len);\n+\t\toffset += task->iovs[i].iov_len;\n+\t\tnbytes += task->iovs[i].iov_len;\n+\t}\n+\n+\treturn nbytes;\n+}\n+\n+int\n+vhost_bdev_process_blk_commands(struct vhost_block_dev *bdev,\n+\t\t\t\t struct vhost_blk_task *task)\n+{\n+\tint used_len;\n+\n+\tif (unlikely(task->data_len > (bdev->blockcnt * bdev->blocklen))) {\n+\t\tfprintf(stderr, \"read or write beyond capacity\\n\");\n+\t\treturn VIRTIO_BLK_S_UNSUPP;\n+\t}\n+\n+\tswitch (task->req->type) {\n+\tcase VIRTIO_BLK_T_IN:\n+\t\tif (unlikely(task->data_len == 0 ||\n+\t\t\t(task->data_len & (512 - 1)) != 0)) {\n+\t\t\tfprintf(stderr,\n+\t\t\t\t\"%s - passed IO buffer is not multiple of 512b\"\n+\t\t\t\t\"(req_idx = %\"PRIu16\").\\n\",\n+\t\t\t\ttask->req->type ? \"WRITE\" : \"READ\",\n+\t\t\t\ttask->head_idx);\n+\t\t\treturn VIRTIO_BLK_S_UNSUPP;\n+\t\t}\n+\n+\t\ttask->dxfer_dir = BLK_DIR_FROM_DEV;\n+\t\tvhost_bdev_blk_readwrite(bdev, task,\n+\t\t\t\t\t task->req->sector, task->data_len);\n+\t\tbreak;\n+\tcase VIRTIO_BLK_T_OUT:\n+\t\tif (unlikely(task->data_len == 0 ||\n+\t\t\t(task->data_len & (512 - 1)) != 0)) {\n+\t\t\tfprintf(stderr,\n+\t\t\t\t\"%s - passed IO buffer is not multiple of 512b\"\n+\t\t\t\t\"(req_idx = %\"PRIu16\").\\n\",\n+\t\t\t\ttask->req->type ? \"WRITE\" : \"READ\",\n+\t\t\t\ttask->head_idx);\n+\t\t\treturn VIRTIO_BLK_S_UNSUPP;\n+\t\t}\n+\n+\t\tif (task->readtype) {\n+\t\t\tfprintf(stderr, \"type isn't right\\n\");\n+\t\t\treturn VIRTIO_BLK_S_IOERR;\n+\t\t}\n+\t\ttask->dxfer_dir = BLK_DIR_TO_DEV;\n+\t\tvhost_bdev_blk_readwrite(bdev, task,\n+\t\t\t\t\t task->req->sector, task->data_len);\n+\t\tbreak;\n+\tcase VIRTIO_BLK_T_GET_ID:\n+\t\tif (!task->iovs_cnt || task->data_len)\n+\t\t\treturn VIRTIO_BLK_S_UNSUPP;\n+\t\tused_len = min(VIRTIO_BLK_ID_BYTES, task->data_len);\n+\t\tvhost_strcpy_pad(task->iovs[0].iov_base,\n+\t\t\t\t bdev->product_name, used_len, ' ');\n+\t\tbreak;\n+\tdefault:\n+\t\tfprintf(stderr, \"unsupported cmd\\n\");\n+\t\treturn VIRTIO_BLK_S_UNSUPP;\n+\t}\n+\n+\treturn VIRTIO_BLK_S_OK;\n+}\ndiff --git a/examples/vhost_blk/blk_spec.h b/examples/vhost_blk/blk_spec.h\nnew file mode 100644\nindex 000000000..5875e2f86\n--- /dev/null\n+++ b/examples/vhost_blk/blk_spec.h\n@@ -0,0 +1,95 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2019 Intel Corporation\n+ */\n+\n+#ifndef _BLK_SPEC_H\n+#define _BLK_SPEC_H\n+\n+#include <stdint.h>\n+\n+#ifndef VHOST_USER_MEMORY_MAX_NREGIONS\n+#define VHOST_USER_MEMORY_MAX_NREGIONS\t\t8\n+#endif\n+\n+#ifndef VHOST_USER_MAX_CONFIG_SIZE\n+#define VHOST_USER_MAX_CONFIG_SIZE\t\t256\n+#endif\n+\n+#ifndef VHOST_USER_PROTOCOL_F_CONFIG\n+#define VHOST_USER_PROTOCOL_F_CONFIG\t\t9\n+#endif\n+\n+#ifndef VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD\n+#define VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD\t12\n+#endif\n+\n+#define VIRTIO_BLK_ID_BYTES\t20\t/* ID string length */\n+\n+#define VIRTIO_BLK_T_IN\t\t\t0\n+#define VIRTIO_BLK_T_OUT\t\t1\n+#define VIRTIO_BLK_T_FLUSH\t\t4\n+#define VIRTIO_BLK_T_GET_ID\t\t8\n+#define VIRTIO_BLK_T_DISCARD\t\t11\n+#define VIRTIO_BLK_T_WRITE_ZEROES\t13\n+\n+#define VIRTIO_BLK_S_OK\t\t\t0\n+#define VIRTIO_BLK_S_IOERR\t\t1\n+#define VIRTIO_BLK_S_UNSUPP\t\t2\n+\n+enum vhost_user_request {\n+\tVHOST_USER_NONE = 0,\n+\tVHOST_USER_GET_FEATURES = 1,\n+\tVHOST_USER_SET_FEATURES = 2,\n+\tVHOST_USER_SET_OWNER = 3,\n+\tVHOST_USER_RESET_OWNER = 4,\n+\tVHOST_USER_SET_MEM_TABLE = 5,\n+\tVHOST_USER_SET_LOG_BASE = 6,\n+\tVHOST_USER_SET_LOG_FD = 7,\n+\tVHOST_USER_SET_VRING_NUM = 8,\n+\tVHOST_USER_SET_VRING_ADDR = 9,\n+\tVHOST_USER_SET_VRING_BASE = 10,\n+\tVHOST_USER_GET_VRING_BASE = 11,\n+\tVHOST_USER_SET_VRING_KICK = 12,\n+\tVHOST_USER_SET_VRING_CALL = 13,\n+\tVHOST_USER_SET_VRING_ERR = 14,\n+\tVHOST_USER_GET_PROTOCOL_FEATURES = 15,\n+\tVHOST_USER_SET_PROTOCOL_FEATURES = 16,\n+\tVHOST_USER_GET_QUEUE_NUM = 17,\n+\tVHOST_USER_SET_VRING_ENABLE = 18,\n+\tVHOST_USER_MAX\n+};\n+\n+/** Get/set config msg payload */\n+struct vhost_user_config {\n+\tuint32_t offset;\n+\tuint32_t size;\n+\tuint32_t flags;\n+\tuint8_t region[VHOST_USER_MAX_CONFIG_SIZE];\n+};\n+\n+/** Fixed-size vhost_memory struct */\n+struct vhost_memory_padded {\n+\tuint32_t nregions;\n+\tuint32_t padding;\n+\tstruct vhost_memory_region regions[VHOST_USER_MEMORY_MAX_NREGIONS];\n+};\n+\n+struct vhost_user_msg {\n+\tenum vhost_user_request request;\n+\n+#define VHOST_USER_VERSION_MASK     0x3\n+#define VHOST_USER_REPLY_MASK       (0x1 << 2)\n+\tuint32_t flags;\n+\tuint32_t size; /**< the following payload size */\n+\tunion {\n+#define VHOST_USER_VRING_IDX_MASK   0xff\n+#define VHOST_USER_VRING_NOFD_MASK  (0x1 << 8)\n+\t\tuint64_t u64;\n+\t\tstruct vhost_vring_state state;\n+\t\tstruct vhost_vring_addr addr;\n+\t\tstruct vhost_memory_padded memory;\n+\t\tstruct vhost_user_config cfg;\n+\t} payload;\n+} __attribute((packed));\n+\n+#endif\ndiff --git a/examples/vhost_blk/meson.build b/examples/vhost_blk/meson.build\nnew file mode 100644\nindex 000000000..857367192\n--- /dev/null\n+++ b/examples/vhost_blk/meson.build\n@@ -0,0 +1,21 @@\n+# SPDX-License-Identifier: BSD-3-Clause\n+# Copyright(c) 2017 Intel Corporation\n+\n+# meson file, for building this example as part of a main DPDK build.\n+#\n+# To build this example as a standalone application with an already-installed\n+# DPDK instance, use 'make'\n+\n+if not is_linux\n+\tbuild = false\n+endif\n+\n+if not cc.has_header('linux/virtio_blk.h')\n+\tbuild = false\n+endif\n+\n+deps += 'vhost'\n+allow_experimental_apis = true\n+sources = files(\n+\t'blk.c', 'vhost_blk.c', 'vhost_blk_compat.c'\n+)\ndiff --git a/examples/vhost_blk/vhost_blk.c b/examples/vhost_blk/vhost_blk.c\nnew file mode 100644\nindex 000000000..8411577ed\n--- /dev/null\n+++ b/examples/vhost_blk/vhost_blk.c\n@@ -0,0 +1,1094 @@\n+// SPDX-License-Identifier: BSD-3-Clause\n+// Copyright(c) 2010-2017 Intel Corporation\n+\n+#include <stdint.h>\n+#include <unistd.h>\n+#include <stdbool.h>\n+#include <signal.h>\n+#include <assert.h>\n+#include <semaphore.h>\n+#include <linux/virtio_blk.h>\n+#include <linux/virtio_ring.h>\n+\n+#include <rte_atomic.h>\n+#include <rte_cycles.h>\n+#include <rte_log.h>\n+#include <rte_malloc.h>\n+#include <rte_vhost.h>\n+\n+#include \"vhost_blk.h\"\n+#include \"blk_spec.h\"\n+\n+#define VIRTQ_DESC_F_NEXT\t1\n+#define VIRTQ_DESC_F_AVAIL\t(1 << 7)\n+#define VIRTQ_DESC_F_USED\t(1 << 15)\n+\n+#define MAX_TASK\t\t12\n+\n+#define VHOST_BLK_FEATURES ((1ULL << VIRTIO_F_RING_PACKED) | \\\n+\t\t\t    (1ULL << VIRTIO_F_VERSION_1) |\\\n+\t\t\t    (1ULL << VIRTIO_F_NOTIFY_ON_EMPTY) | \\\n+\t\t\t    (1ULL << VHOST_USER_F_PROTOCOL_FEATURES))\n+\n+/* Path to folder where character device will be created. Can be set by user. */\n+static char dev_pathname[PATH_MAX] = \"\";\n+static sem_t exit_sem;\n+static int g_should_stop = -1;\n+\n+struct vhost_blk_ctrlr *\n+vhost_blk_ctrlr_find(const char *ctrlr_name)\n+{\n+\tif (ctrlr_name == NULL)\n+\t\treturn NULL;\n+\n+\t/* currently we only support 1 socket file fd */\n+\treturn g_vhost_ctrlr;\n+}\n+\n+static uint64_t gpa_to_vva(int vid, uint64_t gpa, uint64_t *len)\n+{\n+\tchar path[PATH_MAX];\n+\tstruct vhost_blk_ctrlr *ctrlr;\n+\tint ret = 0;\n+\n+\tret = rte_vhost_get_ifname(vid, path, PATH_MAX);\n+\tif (ret) {\n+\t\tfprintf(stderr, \"Cannot get socket name\\n\");\n+\t\tassert(ret != 0);\n+\t}\n+\n+\tctrlr = vhost_blk_ctrlr_find(path);\n+\tif (!ctrlr) {\n+\t\tfprintf(stderr, \"Controller is not ready\\n\");\n+\t\tassert(ctrlr != NULL);\n+\t}\n+\n+\tassert(ctrlr->mem != NULL);\n+\n+\treturn rte_vhost_va_from_guest_pa(ctrlr->mem, gpa, len);\n+}\n+\n+static struct vring_packed_desc *\n+descriptor_get_next_packed(struct rte_vhost_vring *vq,\n+\t\t\t     uint16_t *idx)\n+{\n+\tif (vq->desc_packed[*idx % vq->size].flags & VIRTQ_DESC_F_NEXT) {\n+\t\t*idx += 1;\n+\t\treturn &vq->desc_packed[*idx % vq->size];\n+\t}\n+\n+\treturn NULL;\n+}\n+\n+static bool\n+descriptor_has_next_packed(struct vring_packed_desc *cur_desc)\n+{\n+\treturn !!(cur_desc->flags & VRING_DESC_F_NEXT);\n+}\n+\n+static bool\n+descriptor_is_wr_packed(struct vring_packed_desc *cur_desc)\n+{\n+\treturn !!(cur_desc->flags & VRING_DESC_F_WRITE);\n+}\n+\n+static struct rte_vhost_inflight_desc_packed *\n+inflight_desc_get_next(struct rte_vhost_inflight_info_packed *inflight_packed,\n+\t\t\t       struct rte_vhost_inflight_desc_packed *cur_desc)\n+{\n+\tif (!!(cur_desc->flags & VIRTQ_DESC_F_NEXT))\n+\t\treturn &inflight_packed->desc[cur_desc->next];\n+\n+\treturn NULL;\n+}\n+\n+static bool\n+inflight_desc_has_next(struct rte_vhost_inflight_desc_packed *cur_desc)\n+{\n+\treturn !!(cur_desc->flags & VRING_DESC_F_NEXT);\n+}\n+\n+static bool\n+inflight_desc_is_wr(struct rte_vhost_inflight_desc_packed *cur_desc)\n+{\n+\treturn !!(cur_desc->flags & VRING_DESC_F_WRITE);\n+}\n+\n+static void\n+inflight_process_payload_chain_packed(struct inflight_blk_task *task)\n+{\n+\tvoid *data;\n+\tuint64_t chunck_len;\n+\tstruct vhost_blk_task *blk_task;\n+\tstruct rte_vhost_inflight_desc_packed *desc;\n+\n+\tblk_task = &task->blk_task;\n+\tblk_task->iovs_cnt = 0;\n+\n+\tdo {\n+\t\tdesc = task->inflight_desc;\n+\t\tchunck_len = desc->len;\n+\t\tdata = (void *)(uintptr_t)gpa_to_vva(blk_task->bdev->vid,\n+\t\t\t\t\t\t     desc->addr,\n+\t\t\t\t\t\t     &chunck_len);\n+\t\tif (!data || chunck_len != desc->len) {\n+\t\t\tfprintf(stderr, \"failed to translate desc address.\\n\");\n+\t\t\treturn;\n+\t\t}\n+\n+\t\tblk_task->iovs[blk_task->iovs_cnt].iov_base = data;\n+\t\tblk_task->iovs[blk_task->iovs_cnt].iov_len = desc->len;\n+\t\tblk_task->data_len += desc->len;\n+\t\tblk_task->iovs_cnt++;\n+\t\ttask->inflight_desc = inflight_desc_get_next(\n+\t\t\t\t\ttask->inflight_packed, desc);\n+\t} while (inflight_desc_has_next(task->inflight_desc));\n+\n+\tchunck_len = task->inflight_desc->len;\n+\tblk_task->status = (void *)(uintptr_t)gpa_to_vva(\n+\t\tblk_task->bdev->vid, task->inflight_desc->addr, &chunck_len);\n+\tif (!blk_task->status || chunck_len != task->inflight_desc->len)\n+\t\tfprintf(stderr, \"failed to translate desc address.\\n\");\n+}\n+\n+static void\n+inflight_submit_completion_packed(struct inflight_blk_task *task,\n+\t\t\t\t\t      uint32_t q_idx, uint16_t *used_id,\n+\t\t\t\t\t      bool *used_wrap_counter)\n+{\n+\tstruct vhost_blk_ctrlr *ctrlr;\n+\tstruct rte_vhost_vring *vq;\n+\tstruct vring_packed_desc *desc;\n+\tint ret;\n+\n+\tctrlr = vhost_blk_ctrlr_find(dev_pathname);\n+\tvq = task->blk_task.vq;\n+\n+\tret = rte_vhost_set_last_inflight_io_packed(ctrlr->bdev->vid, q_idx,\n+\t\t\t\t\t\t    task->blk_task.head_idx);\n+\tif (ret != 0)\n+\t\tfprintf(stderr, \"failed to set last inflight io\\n\");\n+\n+\tdesc = &vq->desc_packed[*used_id];\n+\tdesc->id = task->blk_task.buffer_id;\n+\trte_smp_mb();\n+\tif (*used_wrap_counter)\n+\t\tdesc->flags |= VIRTQ_DESC_F_AVAIL | VIRTQ_DESC_F_USED;\n+\telse\n+\t\tdesc->flags &= ~(VIRTQ_DESC_F_AVAIL | VIRTQ_DESC_F_USED);\n+\trte_smp_mb();\n+\n+\t*used_id += task->blk_task.iovs_cnt + 2;\n+\tif (*used_id >= vq->size) {\n+\t\t*used_id -= vq->size;\n+\t\t*used_wrap_counter = !(*used_wrap_counter);\n+\t}\n+\n+\tret = rte_vhost_clr_inflight_desc_packed(ctrlr->bdev->vid, q_idx,\n+\t\t\t\t\t\t task->blk_task.head_idx);\n+\tif (ret != 0)\n+\t\tfprintf(stderr, \"failed to clear inflight io\\n\");\n+\n+\t/* Send an interrupt back to the guest VM so that it knows\n+\t * a completion is ready to be processed.\n+\t */\n+\trte_vhost_vring_call(task->blk_task.bdev->vid, q_idx);\n+}\n+\n+static void\n+submit_completion_packed(struct vhost_blk_task *task, uint32_t q_idx,\n+\t\t\t\t  uint16_t *used_id, bool *used_wrap_counter)\n+{\n+\tstruct vhost_blk_ctrlr *ctrlr;\n+\tstruct rte_vhost_vring *vq;\n+\tstruct vring_packed_desc *desc;\n+\tint ret;\n+\n+\tctrlr = vhost_blk_ctrlr_find(dev_pathname);\n+\tvq = task->vq;\n+\n+\tret = rte_vhost_set_last_inflight_io_packed(ctrlr->bdev->vid, q_idx,\n+\t\t\t\t\t\t    task->inflight_idx);\n+\tif (ret != 0)\n+\t\tfprintf(stderr, \"failed to set last inflight io\\n\");\n+\n+\tdesc = &vq->desc_packed[*used_id];\n+\tdesc->id = task->buffer_id;\n+\trte_smp_mb();\n+\tif (*used_wrap_counter)\n+\t\tdesc->flags |= VIRTQ_DESC_F_AVAIL | VIRTQ_DESC_F_USED;\n+\telse\n+\t\tdesc->flags &= ~(VIRTQ_DESC_F_AVAIL | VIRTQ_DESC_F_USED);\n+\trte_smp_mb();\n+\n+\t*used_id += task->iovs_cnt + 2;\n+\tif (*used_id >= vq->size) {\n+\t\t*used_id -= vq->size;\n+\t\t*used_wrap_counter = !(*used_wrap_counter);\n+\t}\n+\n+\tret = rte_vhost_clr_inflight_desc_packed(ctrlr->bdev->vid, q_idx,\n+\t\t\t\t\t\t task->inflight_idx);\n+\tif (ret != 0)\n+\t\tfprintf(stderr, \"failed to clear inflight io\\n\");\n+\n+\t/* Send an interrupt back to the guest VM so that it knows\n+\t * a completion is ready to be processed.\n+\t */\n+\trte_vhost_vring_call(task->bdev->vid, q_idx);\n+}\n+\n+static void\n+vhost_process_payload_chain_packed(struct vhost_blk_task *task,\n+\tuint16_t *idx)\n+{\n+\tvoid *data;\n+\tuint64_t chunck_len;\n+\n+\ttask->iovs_cnt = 0;\n+\n+\tdo {\n+\t\tchunck_len = task->desc_packed->len;\n+\t\tdata = (void *)(uintptr_t)gpa_to_vva(task->bdev->vid,\n+\t\t\t\t\t\t     task->desc_packed->addr,\n+\t\t\t\t\t\t\t &chunck_len);\n+\t\tif (!data || chunck_len != task->desc_packed->len) {\n+\t\t\tfprintf(stderr, \"failed to translate desc address.\\n\");\n+\t\t\treturn;\n+\t\t}\n+\n+\t\ttask->iovs[task->iovs_cnt].iov_base = data;\n+\t\ttask->iovs[task->iovs_cnt].iov_len = task->desc_packed->len;\n+\t\ttask->data_len += task->desc_packed->len;\n+\t\ttask->iovs_cnt++;\n+\t\ttask->desc_packed = descriptor_get_next_packed(task->vq, idx);\n+\t} while (descriptor_has_next_packed(task->desc_packed));\n+\n+\ttask->last_idx = *idx % task->vq->size;\n+\tchunck_len = task->desc_packed->len;\n+\ttask->status = (void *)(uintptr_t)gpa_to_vva(task->bdev->vid,\n+\t\t\t\t\t\t   task->desc_packed->addr,\n+\t\t\t\t\t\t   &chunck_len);\n+\tif (!task->status || chunck_len != task->desc_packed->len)\n+\t\tfprintf(stderr, \"failed to translate desc address.\\n\");\n+}\n+\n+\n+static int\n+descriptor_is_available(struct rte_vhost_vring *vring, uint16_t idx,\n+\t\t\t\t\tbool avail_wrap_counter)\n+{\n+\tuint16_t flags = vring->desc_packed[idx].flags;\n+\n+\treturn ((!!(flags & VIRTQ_DESC_F_AVAIL) == avail_wrap_counter) &&\n+\t\t(!!(flags & VIRTQ_DESC_F_USED) != avail_wrap_counter));\n+}\n+\n+static void\n+process_requestq_packed(struct vhost_blk_ctrlr *ctrlr, uint32_t q_idx)\n+{\n+\tbool avail_wrap_counter, used_wrap_counter;\n+\tuint16_t avail_idx, used_idx;\n+\tint ret;\n+\tuint64_t chunck_len;\n+\tstruct vhost_blk_queue *blk_vq;\n+\tstruct rte_vhost_vring *vq;\n+\tstruct vhost_blk_task *task;\n+\n+\tblk_vq = &ctrlr->bdev->queues[q_idx];\n+\tvq = &blk_vq->vq;\n+\n+\tavail_idx = blk_vq->last_avail_idx;\n+\tavail_wrap_counter = blk_vq->avail_wrap_counter;\n+\tused_idx = blk_vq->last_used_idx;\n+\tused_wrap_counter = blk_vq->used_wrap_counter;\n+\n+\ttask = rte_zmalloc(NULL, sizeof(*task), 0);\n+\tassert(task != NULL);\n+\ttask->vq = vq;\n+\ttask->bdev = ctrlr->bdev;\n+\n+\twhile (descriptor_is_available(vq, avail_idx, avail_wrap_counter)) {\n+\t\ttask->head_idx = avail_idx;\n+\t\ttask->desc_packed = &task->vq->desc_packed[task->head_idx];\n+\t\ttask->iovs_cnt = 0;\n+\t\ttask->data_len = 0;\n+\t\ttask->req = NULL;\n+\t\ttask->status = NULL;\n+\n+\t\t/* does not support indirect descriptors */\n+\t\tassert((task->desc_packed->flags & VRING_DESC_F_INDIRECT) == 0);\n+\n+\t\tchunck_len = task->desc_packed->len;\n+\t\ttask->req = (void *)(uintptr_t)gpa_to_vva(task->bdev->vid,\n+\t\t\ttask->desc_packed->addr, &chunck_len);\n+\t\tif (!task->req || chunck_len != task->desc_packed->len) {\n+\t\t\tfprintf(stderr, \"failed to translate desc address.\\n\");\n+\t\t\trte_free(task);\n+\t\t\treturn;\n+\t\t}\n+\n+\t\ttask->desc_packed = descriptor_get_next_packed(task->vq,\n+\t\t\t\t\t\t\t\t&avail_idx);\n+\t\tassert(task->desc_packed != NULL);\n+\t\tif (!descriptor_has_next_packed(task->desc_packed)) {\n+\t\t\ttask->dxfer_dir = BLK_DIR_NONE;\n+\t\t\ttask->last_idx = avail_idx % vq->size;\n+\t\t\tchunck_len = task->desc_packed->len;\n+\t\t\ttask->status = (void *)(uintptr_t)\n+\t\t\t\t\t      gpa_to_vva(task->bdev->vid,\n+\t\t\t\t\t\t\ttask->desc_packed->addr,\n+\t\t\t\t\t\t\t&chunck_len);\n+\t\t\tif (!task->status ||\n+\t\t\t\tchunck_len != task->desc_packed->len) {\n+\t\t\t\tfprintf(stderr,\n+\t\t\t\t\t\"failed to translate desc address.\\n\");\n+\t\t\t\trte_free(task);\n+\t\t\t\treturn;\n+\t\t\t}\n+\t\t} else {\n+\t\t\ttask->readtype = descriptor_is_wr_packed(\n+\t\t\t\t\t\t\ttask->desc_packed);\n+\t\t\tvhost_process_payload_chain_packed(task, &avail_idx);\n+\t\t}\n+\t\ttask->buffer_id = vq->desc_packed[task->last_idx].id;\n+\t\trte_vhost_set_inflight_desc_packed(ctrlr->bdev->vid, q_idx,\n+\t\t\t\t\t\t   task->head_idx,\n+\t\t\t\t\t\t   task->last_idx,\n+\t\t\t\t\t\t   &task->inflight_idx);\n+\n+\t\tif (++avail_idx >= vq->size) {\n+\t\t\tavail_idx -= vq->size;\n+\t\t\tavail_wrap_counter = !avail_wrap_counter;\n+\t\t}\n+\t\tblk_vq->last_avail_idx = avail_idx;\n+\t\tblk_vq->avail_wrap_counter = avail_wrap_counter;\n+\n+\t\tret = vhost_bdev_process_blk_commands(ctrlr->bdev, task);\n+\t\tif (ret) {\n+\t\t\t/* invalid response */\n+\t\t\t*task->status = VIRTIO_BLK_S_IOERR;\n+\t\t} else {\n+\t\t\t/* successfully */\n+\t\t\t*task->status = VIRTIO_BLK_S_OK;\n+\t\t}\n+\n+\t\tsubmit_completion_packed(task, q_idx, &used_idx,\n+\t\t\t\t\t\t&used_wrap_counter);\n+\t\tblk_vq->last_used_idx = used_idx;\n+\t\tblk_vq->used_wrap_counter = used_wrap_counter;\n+\t}\n+\n+\trte_free(task);\n+}\n+\n+static void\n+submit_inflight_vq_packed(struct vhost_blk_ctrlr *ctrlr,\n+\tuint16_t q_idx)\n+{\n+\tbool used_wrap_counter;\n+\tint req_idx, ret;\n+\tuint16_t used_idx;\n+\tuint64_t chunck_len;\n+\tstruct vhost_blk_queue *blk_vq;\n+\tstruct rte_vhost_ring_inflight *inflight_vq;\n+\tstruct rte_vhost_resubmit_info *resubmit_info;\n+\tstruct rte_vhost_vring *vq;\n+\tstruct inflight_blk_task *task;\n+\tstruct vhost_blk_task *blk_task;\n+\tstruct rte_vhost_inflight_info_packed *inflight_info;\n+\n+\tblk_vq = &ctrlr->bdev->queues[q_idx];\n+\tvq = &blk_vq->vq;\n+\tinflight_vq = &blk_vq->inflight_vq;\n+\tresubmit_info = inflight_vq->resubmit_inflight;\n+\tinflight_info = inflight_vq->inflight_packed;\n+\tused_idx = blk_vq->last_used_idx;\n+\tused_wrap_counter = blk_vq->used_wrap_counter;\n+\n+\ttask = rte_malloc(NULL, sizeof(*task), 0);\n+\tif (!task) {\n+\t\tfprintf(stderr, \"failed to allocate memory\\n\");\n+\t\treturn;\n+\t}\n+\tblk_task = &task->blk_task;\n+\tblk_task->vq = vq;\n+\tblk_task->bdev = ctrlr->bdev;\n+\ttask->inflight_packed = inflight_vq->inflight_packed;\n+\n+\twhile (resubmit_info->resubmit_num-- > 0) {\n+\t\treq_idx = resubmit_info->resubmit_num;\n+\t\tblk_task->head_idx =\n+\t\t\tresubmit_info->resubmit_list[req_idx].index;\n+\t\ttask->inflight_desc =\n+\t\t\t&inflight_info->desc[blk_task->head_idx];\n+\t\ttask->blk_task.iovs_cnt = 0;\n+\t\ttask->blk_task.data_len = 0;\n+\t\ttask->blk_task.req = NULL;\n+\t\ttask->blk_task.status = NULL;\n+\n+\t\t/* update the avail idx too\n+\t\t * as it's initial value equals to used idx\n+\t\t */\n+\t\tblk_vq->last_avail_idx += task->inflight_desc->num;\n+\t\tif (blk_vq->last_avail_idx >= vq->size) {\n+\t\t\tblk_vq->last_avail_idx -= vq->size;\n+\t\t\tblk_vq->avail_wrap_counter =\n+\t\t\t\t!blk_vq->avail_wrap_counter;\n+\t\t}\n+\n+\t\t/* does not support indirect descriptors */\n+\t\tassert(task->inflight_desc != NULL);\n+\t\tassert((task->inflight_desc->flags &\n+\t\t\tVRING_DESC_F_INDIRECT) == 0);\n+\n+\t\tchunck_len = task->inflight_desc->len;\n+\t\tblk_task->req = (void *)(uintptr_t)\n+\t\t\t\t     gpa_to_vva(blk_task->bdev->vid,\n+\t\t\t\t\t\ttask->inflight_desc->addr,\n+\t\t\t\t\t\t&chunck_len);\n+\t\tif (!blk_task->req ||\n+\t\t\tchunck_len != task->inflight_desc->len) {\n+\t\t\tfprintf(stderr, \"failed to translate desc address.\\n\");\n+\t\t\trte_free(task);\n+\t\t\treturn;\n+\t\t}\n+\n+\t\ttask->inflight_desc = inflight_desc_get_next(\n+\t\t\ttask->inflight_packed, task->inflight_desc);\n+\t\tassert(task->inflight_desc != NULL);\n+\t\tif (!inflight_desc_has_next(task->inflight_desc)) {\n+\t\t\tblk_task->dxfer_dir = BLK_DIR_NONE;\n+\t\t\tchunck_len = task->inflight_desc->len;\n+\t\t\tblk_task->status = (void *)(uintptr_t)\n+\t\t\t\tgpa_to_vva(blk_task->bdev->vid,\n+\t\t\t\t\t\ttask->inflight_desc->addr,\n+\t\t\t\t\t\t&chunck_len);\n+\t\t\tif (!blk_task->status ||\n+\t\t\t    chunck_len != task->inflight_desc->len) {\n+\t\t\t\tfprintf(stderr,\n+\t\t\t\t\t\"failed to translate desc address.\\n\");\n+\t\t\t\trte_free(task);\n+\t\t\t\treturn;\n+\t\t\t}\n+\t\t} else {\n+\t\t\tblk_task->readtype =\n+\t\t\tinflight_desc_is_wr(task->inflight_desc);\n+\t\t\tinflight_process_payload_chain_packed(task);\n+\t\t}\n+\n+\t\tblk_task->buffer_id = task->inflight_desc->id;\n+\n+\t\tret = vhost_bdev_process_blk_commands(ctrlr->bdev, blk_task);\n+\t\tif (ret)\n+\t\t\t/* invalid response */\n+\t\t\t*blk_task->status = VIRTIO_BLK_S_IOERR;\n+\t\telse\n+\t\t\t/* successfully */\n+\t\t\t*blk_task->status = VIRTIO_BLK_S_OK;\n+\n+\t\tinflight_submit_completion_packed(task, q_idx, &used_idx,\n+\t\t\t\t\t\t  &used_wrap_counter);\n+\n+\t\tblk_vq->last_used_idx = used_idx;\n+\t\tblk_vq->used_wrap_counter = used_wrap_counter;\n+\t}\n+\n+\trte_free(task);\n+}\n+\n+static struct vring_desc *\n+descriptor_get_next_split(struct vring_desc *vq_desc,\n+\t\t\t\t   struct vring_desc *cur_desc)\n+{\n+\treturn &vq_desc[cur_desc->next];\n+}\n+\n+static bool\n+descriptor_has_next_split(struct vring_desc *cur_desc)\n+{\n+\treturn !!(cur_desc->flags & VRING_DESC_F_NEXT);\n+}\n+\n+static bool\n+descriptor_is_wr_split(struct vring_desc *cur_desc)\n+{\n+\treturn !!(cur_desc->flags & VRING_DESC_F_WRITE);\n+}\n+\n+static void\n+vhost_process_payload_chain_split(struct vhost_blk_task *task)\n+{\n+\tvoid *data;\n+\tuint64_t chunck_len;\n+\n+\ttask->iovs_cnt = 0;\n+\n+\tdo {\n+\t\tchunck_len = task->desc_split->len;\n+\t\tdata = (void *)(uintptr_t)gpa_to_vva(task->bdev->vid,\n+\t\t\t\t\t\t     task->desc_split->addr,\n+\t\t\t\t\t\t     &chunck_len);\n+\t\tif (!data || chunck_len != task->desc_split->len) {\n+\t\t\tfprintf(stderr, \"failed to translate desc address.\\n\");\n+\t\t\treturn;\n+\t\t}\n+\n+\t\ttask->iovs[task->iovs_cnt].iov_base = data;\n+\t\ttask->iovs[task->iovs_cnt].iov_len = task->desc_split->len;\n+\t\ttask->data_len += task->desc_split->len;\n+\t\ttask->iovs_cnt++;\n+\t\ttask->desc_split =\n+\t\tdescriptor_get_next_split(task->vq->desc, task->desc_split);\n+\t} while (descriptor_has_next_split(task->desc_split));\n+\n+\tchunck_len = task->desc_split->len;\n+\ttask->status = (void *)(uintptr_t)gpa_to_vva(task->bdev->vid,\n+\t\t\t\t\t\t     task->desc_split->addr,\n+\t\t\t\t\t\t     &chunck_len);\n+\tif (!task->status || chunck_len != task->desc_split->len)\n+\t\tfprintf(stderr, \"failed to translate desc address.\\n\");\n+}\n+\n+static void\n+submit_completion_split(struct vhost_blk_task *task, uint32_t vid,\n+\tuint32_t q_idx)\n+{\n+\tstruct rte_vhost_vring *vq;\n+\tstruct vring_used *used;\n+\n+\tvq = task->vq;\n+\tused = vq->used;\n+\n+\trte_vhost_set_last_inflight_io_split(vid, q_idx, task->req_idx);\n+\n+\t/* Fill out the next entry in the \"used\" ring.  id = the\n+\t * index of the descriptor that contained the blk request.\n+\t * len = the total amount of data transferred for the blk\n+\t * request. We must report the correct len, for variable\n+\t * length blk CDBs, where we may return less data than\n+\t * allocated by the guest VM.\n+\t */\n+\tused->ring[used->idx & (vq->size - 1)].id = task->req_idx;\n+\tused->ring[used->idx & (vq->size - 1)].len = task->data_len;\n+\trte_smp_mb();\n+\tused->idx++;\n+\trte_smp_mb();\n+\n+\trte_vhost_clr_inflight_desc_split(vid, q_idx, used->idx, task->req_idx);\n+\n+\t/* Send an interrupt back to the guest VM so that it knows\n+\t * a completion is ready to be processed.\n+\t */\n+\trte_vhost_vring_call(task->bdev->vid, q_idx);\n+}\n+\n+static void\n+submit_inflight_vq_split(struct vhost_blk_ctrlr *ctrlr,\n+\tuint32_t q_idx)\n+{\n+\tstruct vhost_blk_queue *blk_vq;\n+\tstruct rte_vhost_ring_inflight *inflight_vq;\n+\tstruct rte_vhost_resubmit_info *resubmit_inflight;\n+\tstruct rte_vhost_resubmit_desc *resubmit_list;\n+\tstruct vhost_blk_task *task;\n+\tint req_idx;\n+\tuint64_t chunck_len;\n+\tint ret;\n+\n+\tblk_vq = &ctrlr->bdev->queues[q_idx];\n+\tinflight_vq = &blk_vq->inflight_vq;\n+\tresubmit_inflight = inflight_vq->resubmit_inflight;\n+\tresubmit_list = resubmit_inflight->resubmit_list;\n+\n+\ttask = rte_zmalloc(NULL, sizeof(*task), 0);\n+\tassert(task != NULL);\n+\n+\ttask->ctrlr = ctrlr;\n+\ttask->bdev = ctrlr->bdev;\n+\ttask->vq = &blk_vq->vq;\n+\n+\twhile (resubmit_inflight->resubmit_num-- > 0) {\n+\t\treq_idx = resubmit_list[resubmit_inflight->resubmit_num].index;\n+\t\ttask->req_idx = req_idx;\n+\t\ttask->desc_split = &task->vq->desc[task->req_idx];\n+\t\ttask->iovs_cnt = 0;\n+\t\ttask->data_len = 0;\n+\t\ttask->req = NULL;\n+\t\ttask->status = NULL;\n+\n+\t\t/* does not support indirect descriptors */\n+\t\tassert(task->desc_split != NULL);\n+\t\tassert((task->desc_split->flags & VRING_DESC_F_INDIRECT) == 0);\n+\n+\t\tchunck_len = task->desc_split->len;\n+\t\ttask->req = (void *)(uintptr_t)gpa_to_vva(task->bdev->vid,\n+\t\t\t\ttask->desc_split->addr, &chunck_len);\n+\t\tif (!task->req || chunck_len != task->desc_split->len) {\n+\t\t\tfprintf(stderr, \"failed to translate desc address.\\n\");\n+\t\t\trte_free(task);\n+\t\t\treturn;\n+\t\t}\n+\n+\t\ttask->desc_split = descriptor_get_next_split(task->vq->desc,\n+\t\t\t\t\t\t\t     task->desc_split);\n+\t\tif (!descriptor_has_next_split(task->desc_split)) {\n+\t\t\ttask->dxfer_dir = BLK_DIR_NONE;\n+\t\t\tchunck_len = task->desc_split->len;\n+\t\t\ttask->status = (void *)(uintptr_t)\n+\t\t\t\t       gpa_to_vva(task->bdev->vid,\n+\t\t\t\t\t\t  task->desc_split->addr,\n+\t\t\t\t\t\t  &chunck_len);\n+\t\t\tif (!task->status ||\n+\t\t\t\tchunck_len != task->desc_split->len) {\n+\t\t\t\tfprintf(stderr,\n+\t\t\t\t\t\"failed to translate desc address.\\n\");\n+\t\t\t\trte_free(task);\n+\t\t\t\treturn;\n+\t\t\t}\n+\t\t} else {\n+\t\t\ttask->readtype =\n+\t\t\t\tdescriptor_is_wr_split(task->desc_split);\n+\t\t\tvhost_process_payload_chain_split(task);\n+\t\t}\n+\n+\t\tret = vhost_bdev_process_blk_commands(ctrlr->bdev, task);\n+\t\tif (ret) {\n+\t\t\t/* invalid response */\n+\t\t\t*task->status = VIRTIO_BLK_S_IOERR;\n+\t\t} else {\n+\t\t\t/* successfully */\n+\t\t\t*task->status = VIRTIO_BLK_S_OK;\n+\t\t}\n+\t\tsubmit_completion_split(task, ctrlr->bdev->vid, q_idx);\n+\t}\n+\n+\trte_free(task);\n+}\n+\n+static void\n+process_requestq_split(struct vhost_blk_ctrlr *ctrlr, uint32_t q_idx)\n+{\n+\tint ret;\n+\tint req_idx;\n+\tuint16_t last_idx;\n+\tuint64_t chunck_len;\n+\tstruct vhost_blk_queue *blk_vq;\n+\tstruct rte_vhost_vring *vq;\n+\tstruct vhost_blk_task *task;\n+\n+\tblk_vq = &ctrlr->bdev->queues[q_idx];\n+\tvq = &blk_vq->vq;\n+\n+\ttask = rte_zmalloc(NULL, sizeof(*task), 0);\n+\tassert(task != NULL);\n+\ttask->ctrlr = ctrlr;\n+\ttask->bdev = ctrlr->bdev;\n+\ttask->vq = vq;\n+\n+\twhile (vq->avail->idx != blk_vq->last_avail_idx) {\n+\t\tlast_idx = blk_vq->last_avail_idx & (vq->size - 1);\n+\t\treq_idx = vq->avail->ring[last_idx];\n+\t\ttask->req_idx = req_idx;\n+\t\ttask->desc_split = &task->vq->desc[task->req_idx];\n+\t\ttask->iovs_cnt = 0;\n+\t\ttask->data_len = 0;\n+\t\ttask->req = NULL;\n+\t\ttask->status = NULL;\n+\n+\t\trte_vhost_set_inflight_desc_split(ctrlr->bdev->vid, q_idx,\n+\t\t\t\t\t\t\ttask->req_idx);\n+\n+\t\t/* does not support indirect descriptors */\n+\t\tassert((task->desc_split->flags & VRING_DESC_F_INDIRECT) == 0);\n+\n+\t\tchunck_len = task->desc_split->len;\n+\t\ttask->req = (void *)(uintptr_t)gpa_to_vva(task->bdev->vid,\n+\t\t\t\ttask->desc_split->addr, &chunck_len);\n+\t\tif (!task->req || chunck_len != task->desc_split->len) {\n+\t\t\tfprintf(stderr, \"failed to translate desc address.\\n\");\n+\t\t\trte_free(task);\n+\t\t\treturn;\n+\t\t}\n+\n+\t\ttask->desc_split = descriptor_get_next_split(task->vq->desc,\n+\t\t\t\t\t\t\t     task->desc_split);\n+\t\tif (!descriptor_has_next_split(task->desc_split)) {\n+\t\t\ttask->dxfer_dir = BLK_DIR_NONE;\n+\t\t\tchunck_len = task->desc_split->len;\n+\t\t\ttask->status = (void *)(uintptr_t)\n+\t\t\t\t\t      gpa_to_vva(task->bdev->vid,\n+\t\t\t\t\t\t\t task->desc_split->addr,\n+\t\t\t\t\t\t\t &chunck_len);\n+\t\t\tif (!task->status ||\n+\t\t\t\tchunck_len != task->desc_split->len) {\n+\t\t\t\tfprintf(stderr,\n+\t\t\t\t\t\"failed to translate desc address.\\n\");\n+\t\t\t\trte_free(task);\n+\t\t\t\treturn;\n+\t\t\t}\n+\t\t} else {\n+\t\t\ttask->readtype =\n+\t\t\t\tdescriptor_is_wr_split(task->desc_split);\n+\t\t\tvhost_process_payload_chain_split(task);\n+\t\t}\n+\t\tblk_vq->last_avail_idx++;\n+\n+\t\tret = vhost_bdev_process_blk_commands(ctrlr->bdev, task);\n+\t\tif (ret) {\n+\t\t\t/* invalid response */\n+\t\t\t*task->status = VIRTIO_BLK_S_IOERR;\n+\t\t} else {\n+\t\t\t/* successfully */\n+\t\t\t*task->status = VIRTIO_BLK_S_OK;\n+\t\t}\n+\n+\t\tsubmit_completion_split(task, ctrlr->bdev->vid, q_idx);\n+\t}\n+\n+\trte_free(task);\n+}\n+\n+static void *\n+ctrlr_worker(void *arg)\n+{\n+\tstruct vhost_blk_ctrlr *ctrlr = (struct vhost_blk_ctrlr *)arg;\n+\tstruct vhost_blk_queue *blk_vq;\n+\tstruct rte_vhost_ring_inflight *inflight_vq;\n+\tcpu_set_t cpuset;\n+\tpthread_t thread;\n+\tint i;\n+\n+\tfprintf(stdout, \"Ctrlr Worker Thread start\\n\");\n+\n+\tif (ctrlr == NULL || ctrlr->bdev == NULL) {\n+\t\tfprintf(stderr,\n+\t\t\t\"%s: Error, invalid argument passed to worker thread\\n\",\n+\t\t\t__func__);\n+\t\texit(0);\n+\t}\n+\n+\tthread = pthread_self();\n+\tCPU_ZERO(&cpuset);\n+\tCPU_SET(0, &cpuset);\n+\tpthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset);\n+\n+\tfor (i = 0; i < NUM_OF_BLK_QUEUES; i++) {\n+\t\tblk_vq = &ctrlr->bdev->queues[i];\n+\t\tinflight_vq = &blk_vq->inflight_vq;\n+\t\tif (inflight_vq->resubmit_inflight != NULL &&\n+\t\t    inflight_vq->resubmit_inflight->resubmit_num != 0) {\n+\t\t\tif (ctrlr->packed_ring)\n+\t\t\t\tsubmit_inflight_vq_packed(ctrlr, i);\n+\t\t\telse\n+\t\t\t\tsubmit_inflight_vq_split(ctrlr, i);\n+\t\t}\n+\t}\n+\n+\twhile (!g_should_stop && ctrlr->bdev != NULL) {\n+\t\tfor (i = 0; i < NUM_OF_BLK_QUEUES; i++) {\n+\t\t\tif (ctrlr->packed_ring)\n+\t\t\t\tprocess_requestq_packed(ctrlr, i);\n+\t\t\telse\n+\t\t\t\tprocess_requestq_split(ctrlr, i);\n+\t\t}\n+\t}\n+\n+\tg_should_stop = 2;\n+\tfprintf(stdout, \"Ctrlr Worker Thread Exiting\\n\");\n+\tsem_post(&exit_sem);\n+\treturn NULL;\n+}\n+\n+static int\n+new_device(int vid)\n+{\n+\tstruct vhost_blk_ctrlr *ctrlr;\n+\tstruct vhost_blk_queue *blk_vq;\n+\tstruct rte_vhost_vring *vq;\n+\tuint64_t features;\n+\tpthread_t tid;\n+\tint i, ret;\n+\n+\tctrlr = vhost_blk_ctrlr_find(dev_pathname);\n+\tif (!ctrlr) {\n+\t\tfprintf(stderr, \"Controller is not ready\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\tif (ctrlr->started)\n+\t\treturn 0;\n+\n+\tctrlr->bdev->vid = vid;\n+\tret = rte_vhost_get_negotiated_features(vid, &features);\n+\tif (ret) {\n+\t\tfprintf(stderr, \"failed to get the negotiated features\\n\");\n+\t\treturn -1;\n+\t}\n+\tctrlr->packed_ring = !!(features & (1ULL << VIRTIO_F_RING_PACKED));\n+\n+\tret = rte_vhost_get_mem_table(vid, &ctrlr->mem);\n+\tif (ret)\n+\t\tfprintf(stderr, \"Get Controller memory region failed\\n\");\n+\tassert(ctrlr->mem != NULL);\n+\n+\t/* Disable Notifications and init last idx */\n+\tfor (i = 0; i < NUM_OF_BLK_QUEUES; i++) {\n+\t\tblk_vq = &ctrlr->bdev->queues[i];\n+\t\tvq = &blk_vq->vq;\n+\n+\t\tret = rte_vhost_get_vhost_vring(ctrlr->bdev->vid, i, vq);\n+\t\tassert(ret == 0);\n+\n+\t\tret = rte_vhost_get_vring_base(ctrlr->bdev->vid, i,\n+\t\t\t\t\t       &blk_vq->last_avail_idx,\n+\t\t\t\t\t       &blk_vq->last_used_idx);\n+\t\tassert(ret == 0);\n+\n+\t\tret = rte_vhost_get_vhost_ring_inflight(ctrlr->bdev->vid, i,\n+\t\t\t\t\t\t\t&blk_vq->inflight_vq);\n+\t\tassert(ret == 0);\n+\n+\t\tif (ctrlr->packed_ring) {\n+\t\t\t/* for the reconnection */\n+\t\t\tret = rte_vhost_get_vring_base_from_inflight(\n+\t\t\t\tctrlr->bdev->vid, i,\n+\t\t\t\t&blk_vq->last_avail_idx,\n+\t\t\t\t&blk_vq->last_used_idx);\n+\n+\t\t\tblk_vq->avail_wrap_counter = blk_vq->last_avail_idx &\n+\t\t\t\t(1 << 15);\n+\t\t\tblk_vq->last_avail_idx = blk_vq->last_avail_idx &\n+\t\t\t\t0x7fff;\n+\t\t\tblk_vq->used_wrap_counter = blk_vq->last_used_idx &\n+\t\t\t\t(1 << 15);\n+\t\t\tblk_vq->last_used_idx = blk_vq->last_used_idx &\n+\t\t\t\t0x7fff;\n+\t\t}\n+\n+\t\trte_vhost_enable_guest_notification(vid, i, 0);\n+\t}\n+\n+\t/* start polling vring */\n+\tg_should_stop = 0;\n+\tfprintf(stdout, \"New Device %s, Device ID %d\\n\", dev_pathname, vid);\n+\tif (pthread_create(&tid, NULL, &ctrlr_worker, ctrlr) < 0) {\n+\t\tfprintf(stderr, \"Worker Thread Started Failed\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\t/* device has been started */\n+\tctrlr->started = 1;\n+\tpthread_detach(tid);\n+\treturn 0;\n+}\n+\n+static void\n+destroy_device(int vid)\n+{\n+\tchar path[PATH_MAX];\n+\tstruct vhost_blk_ctrlr *ctrlr;\n+\tstruct vhost_blk_queue *blk_vq;\n+\tint i, ret;\n+\n+\tret = rte_vhost_get_ifname(vid, path, PATH_MAX);\n+\tif (ret) {\n+\t\tfprintf(stderr, \"Destroy Ctrlr Failed\\n\");\n+\t\treturn;\n+\t}\n+\n+\tfprintf(stdout, \"Destroy %s Device ID %d\\n\", path, vid);\n+\tctrlr = vhost_blk_ctrlr_find(path);\n+\tif (!ctrlr) {\n+\t\tfprintf(stderr, \"Destroy Ctrlr Failed\\n\");\n+\t\treturn;\n+\t}\n+\n+\tif (!ctrlr->started)\n+\t\treturn;\n+\n+\tg_should_stop = 1;\n+\twhile (g_should_stop != 2)\n+\t\t;\n+\n+\tfor (i = 0; i < NUM_OF_BLK_QUEUES; i++) {\n+\t\tblk_vq = &ctrlr->bdev->queues[i];\n+\t\tif (ctrlr->packed_ring) {\n+\t\t\tblk_vq->last_avail_idx |= (blk_vq->avail_wrap_counter <<\n+\t\t\t\t15);\n+\t\t\tblk_vq->last_used_idx |= (blk_vq->used_wrap_counter <<\n+\t\t\t\t15);\n+\t\t}\n+\t\trte_vhost_set_vring_base(ctrlr->bdev->vid, i,\n+\t\t\t\t\t blk_vq->last_avail_idx,\n+\t\t\t\t\t blk_vq->last_used_idx);\n+\t}\n+\n+\tfree(ctrlr->mem);\n+\n+\tctrlr->started = 0;\n+\tsem_wait(&exit_sem);\n+}\n+\n+static int\n+new_connection(int vid)\n+{\n+\t/* extend the proper features for block device */\n+\tvhost_session_install_rte_compat_hooks(vid);\n+\n+\treturn 0;\n+}\n+\n+struct vhost_device_ops vhost_blk_device_ops = {\n+\t.new_device =  new_device,\n+\t.destroy_device = destroy_device,\n+\t.new_connection = new_connection,\n+};\n+\n+static struct vhost_block_dev *\n+vhost_blk_bdev_construct(const char *bdev_name,\n+\tconst char *bdev_serial, uint32_t blk_size, uint64_t blk_cnt,\n+\tbool wce_enable)\n+{\n+\tstruct vhost_block_dev *bdev;\n+\n+\tbdev = rte_zmalloc(NULL, sizeof(*bdev), RTE_CACHE_LINE_SIZE);\n+\tif (!bdev)\n+\t\treturn NULL;\n+\n+\tstrncpy(bdev->name, bdev_name, sizeof(bdev->name));\n+\tstrncpy(bdev->product_name, bdev_serial, sizeof(bdev->product_name));\n+\tbdev->blocklen = blk_size;\n+\tbdev->blockcnt = blk_cnt;\n+\tbdev->write_cache = wce_enable;\n+\n+\tfprintf(stdout, \"blocklen=%d, blockcnt=%ld\\n\", bdev->blocklen,\n+\t\tbdev->blockcnt);\n+\n+\t/* use memory as disk storage space */\n+\tbdev->data = rte_zmalloc(NULL, blk_cnt * blk_size, 0);\n+\tif (!bdev->data) {\n+\t\tfprintf(stderr, \"no enough reserved huge memory for disk\\n\");\n+\t\tfree(bdev);\n+\t\treturn NULL;\n+\t}\n+\n+\treturn bdev;\n+}\n+\n+static struct vhost_blk_ctrlr *\n+vhost_blk_ctrlr_construct(const char *ctrlr_name)\n+{\n+\tint ret;\n+\tstruct vhost_blk_ctrlr *ctrlr;\n+\tchar *path;\n+\tchar cwd[PATH_MAX];\n+\n+\t/* always use current directory */\n+\tpath = getcwd(cwd, PATH_MAX);\n+\tif (!path) {\n+\t\tfprintf(stderr, \"Cannot get current working directory\\n\");\n+\t\treturn NULL;\n+\t}\n+\tsnprintf(dev_pathname, sizeof(dev_pathname), \"%s/%s\", path, ctrlr_name);\n+\n+\tif (access(dev_pathname, F_OK) != -1) {\n+\t\tif (unlink(dev_pathname) != 0)\n+\t\t\trte_exit(EXIT_FAILURE, \"Cannot remove %s.\\n\",\n+\t\t\t\t dev_pathname);\n+\t}\n+\n+\tif (rte_vhost_driver_register(dev_pathname, 0) != 0) {\n+\t\tfprintf(stderr, \"socket %s already exists\\n\", dev_pathname);\n+\t\treturn NULL;\n+\t}\n+\n+\tret = rte_vhost_driver_set_features(dev_pathname, VHOST_BLK_FEATURES);\n+\tif (ret != 0) {\n+\t\tfprintf(stderr, \"Set vhost driver features failed\\n\");\n+\t\trte_vhost_driver_unregister(dev_pathname);\n+\t\treturn NULL;\n+\t}\n+\n+\t/* set proper features */\n+\tvhost_dev_install_rte_compat_hooks(dev_pathname);\n+\n+\tctrlr = rte_zmalloc(NULL, sizeof(*ctrlr), RTE_CACHE_LINE_SIZE);\n+\tif (!ctrlr) {\n+\t\trte_vhost_driver_unregister(dev_pathname);\n+\t\treturn NULL;\n+\t}\n+\n+\t/* hardcoded block device information with 128MiB */\n+\tctrlr->bdev = vhost_blk_bdev_construct(\"malloc0\", \"vhost_blk_malloc0\",\n+\t\t\t\t\t\t4096, 32768, 0);\n+\tif (!ctrlr->bdev) {\n+\t\trte_free(ctrlr);\n+\t\trte_vhost_driver_unregister(dev_pathname);\n+\t\treturn NULL;\n+\t}\n+\n+\trte_vhost_driver_callback_register(dev_pathname,\n+\t\t\t\t\t   &vhost_blk_device_ops);\n+\n+\treturn ctrlr;\n+}\n+\n+static void\n+signal_handler(__rte_unused int signum)\n+{\n+\tstruct vhost_blk_ctrlr *ctrlr;\n+\n+\tif (access(dev_pathname, F_OK) == 0)\n+\t\tunlink(dev_pathname);\n+\n+\tif (g_should_stop != -1) {\n+\t\tg_should_stop = 1;\n+\t\twhile (g_should_stop != 2)\n+\t\t\t;\n+\t}\n+\n+\tctrlr = vhost_blk_ctrlr_find(dev_pathname);\n+\tif (ctrlr != NULL) {\n+\t\tif (ctrlr->bdev != NULL) {\n+\t\t\trte_free(ctrlr->bdev->data);\n+\t\t\trte_free(ctrlr->bdev);\n+\t\t}\n+\t\trte_free(ctrlr);\n+\t}\n+\n+\trte_vhost_driver_unregister(dev_pathname);\n+\texit(0);\n+}\n+\n+int main(int argc, char *argv[])\n+{\n+\tint ret;\n+\n+\tsignal(SIGINT, signal_handler);\n+\n+\t/* init EAL */\n+\tret = rte_eal_init(argc, argv);\n+\tif (ret < 0)\n+\t\trte_exit(EXIT_FAILURE, \"Error with EAL initialization\\n\");\n+\n+\tg_vhost_ctrlr = vhost_blk_ctrlr_construct(\"vhost.socket\");\n+\tif (g_vhost_ctrlr == NULL) {\n+\t\tfprintf(stderr, \"Construct vhost blk controller failed\\n\");\n+\t\treturn 0;\n+\t}\n+\n+\tif (sem_init(&exit_sem, 0, 0) < 0) {\n+\t\tfprintf(stderr, \"Error init exit_sem\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\trte_vhost_driver_start(dev_pathname);\n+\n+\t/* loop for exit the application */\n+\twhile (1)\n+\t\tsleep(1);\n+\n+\treturn 0;\n+}\n+\ndiff --git a/examples/vhost_blk/vhost_blk.h b/examples/vhost_blk/vhost_blk.h\nnew file mode 100644\nindex 000000000..a7a62fbae\n--- /dev/null\n+++ b/examples/vhost_blk/vhost_blk.h\n@@ -0,0 +1,127 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2010-2017 Intel Corporation\n+ */\n+\n+#ifndef _VHOST_BLK_H_\n+#define _VHOST_BLK_H_\n+\n+#include <stdio.h>\n+#include <sys/uio.h>\n+#include <stdint.h>\n+#include <stdbool.h>\n+#include <linux/virtio_blk.h>\n+#include <linux/virtio_ring.h>\n+\n+#include <rte_vhost.h>\n+\n+struct vring_packed_desc {\n+\t/* Buffer Address. */\n+\t__le64 addr;\n+\t/* Buffer Length. */\n+\t__le32 len;\n+\t/* Buffer ID. */\n+\t__le16 id;\n+\t/* The flags depending on descriptor type. */\n+\t__le16 flags;\n+};\n+\n+struct vhost_blk_queue {\n+\tstruct rte_vhost_vring vq;\n+\tstruct rte_vhost_ring_inflight inflight_vq;\n+\tuint16_t last_avail_idx;\n+\tuint16_t last_used_idx;\n+\tbool avail_wrap_counter;\n+\tbool used_wrap_counter;\n+};\n+\n+#define NUM_OF_BLK_QUEUES 1\n+\n+#ifndef VIRTIO_F_RING_PACKED\n+#define VIRTIO_F_RING_PACKED 34\n+#endif\n+\n+#define min(a, b) (((a) < (b)) ? (a) : (b))\n+\n+struct vhost_block_dev {\n+\t/** ID for vhost library. */\n+\tint vid;\n+\t/** Queues for the block device */\n+\tstruct vhost_blk_queue queues[NUM_OF_BLK_QUEUES];\n+\t/** Unique name for this block device. */\n+\tchar name[64];\n+\n+\t/** Unique product name for this kind of block device. */\n+\tchar product_name[256];\n+\n+\t/** Size in bytes of a logical block for the backend */\n+\tuint32_t blocklen;\n+\n+\t/** Number of blocks */\n+\tuint64_t blockcnt;\n+\n+\t/** write cache enabled, not used at the moment */\n+\tint write_cache;\n+\n+\t/** use memory as disk storage space */\n+\tuint8_t *data;\n+};\n+\n+struct vhost_blk_ctrlr {\n+\tuint8_t started;\n+\tuint8_t packed_ring;\n+\tuint8_t need_restart;\n+\t/** Only support 1 LUN for the example */\n+\tstruct vhost_block_dev *bdev;\n+\t/** VM memory region */\n+\tstruct rte_vhost_memory *mem;\n+} __rte_cache_aligned;\n+\n+#define VHOST_BLK_MAX_IOVS 128\n+\n+enum blk_data_dir {\n+\tBLK_DIR_NONE = 0,\n+\tBLK_DIR_TO_DEV = 1,\n+\tBLK_DIR_FROM_DEV = 2,\n+};\n+\n+struct vhost_blk_task {\n+\tuint8_t readtype;\n+\tuint8_t req_idx;\n+\tuint16_t head_idx;\n+\tuint16_t last_idx;\n+\tuint16_t inflight_idx;\n+\tuint16_t buffer_id;\n+\tuint32_t dxfer_dir;\n+\tuint32_t data_len;\n+\tstruct virtio_blk_outhdr *req;\n+\n+\tvolatile uint8_t *status;\n+\n+\tstruct iovec iovs[VHOST_BLK_MAX_IOVS];\n+\tuint32_t iovs_cnt;\n+\tstruct vring_packed_desc *desc_packed;\n+\tstruct vring_desc *desc_split;\n+\tstruct rte_vhost_vring *vq;\n+\tstruct vhost_block_dev *bdev;\n+\tstruct vhost_blk_ctrlr *ctrlr;\n+};\n+\n+struct inflight_blk_task {\n+\tstruct vhost_blk_task blk_task;\n+\tstruct rte_vhost_inflight_desc_packed *inflight_desc;\n+\tstruct rte_vhost_inflight_info_packed *inflight_packed;\n+};\n+\n+struct vhost_blk_ctrlr *g_vhost_ctrlr;\n+struct vhost_device_ops vhost_blk_device_ops;\n+\n+int vhost_bdev_process_blk_commands(struct vhost_block_dev *bdev,\n+\t\t\t\t     struct vhost_blk_task *task);\n+\n+void vhost_session_install_rte_compat_hooks(uint32_t vid);\n+\n+void vhost_dev_install_rte_compat_hooks(const char *path);\n+\n+struct vhost_blk_ctrlr *vhost_blk_ctrlr_find(const char *ctrlr_name);\n+\n+#endif /* _VHOST_blk_H_ */\ndiff --git a/examples/vhost_blk/vhost_blk_compat.c b/examples/vhost_blk/vhost_blk_compat.c\nnew file mode 100644\nindex 000000000..4accfa498\n--- /dev/null\n+++ b/examples/vhost_blk/vhost_blk_compat.c\n@@ -0,0 +1,173 @@\n+// SPDX-License-Identifier: BSD-3-Clause\n+// Copyright(c) 2010-2017 Intel Corporation\n+\n+#ifndef _VHOST_BLK_COMPAT_H_\n+#define _VHOST_BLK_COMPAT_H_\n+\n+#include <sys/uio.h>\n+#include <stdint.h>\n+#include <linux/virtio_blk.h>\n+#include <linux/virtio_ring.h>\n+\n+#include <rte_vhost.h>\n+#include \"vhost_blk.h\"\n+#include \"blk_spec.h\"\n+\n+#define VHOST_MAX_VQUEUES\t256\n+#define SPDK_VHOST_MAX_VQ_SIZE\t1024\n+\n+#define VHOST_USER_GET_CONFIG\t24\n+#define VHOST_USER_SET_CONFIG\t25\n+\n+static int\n+vhost_blk_get_config(struct vhost_block_dev *bdev, uint8_t *config,\n+\t\t\t  uint32_t len)\n+{\n+\tstruct virtio_blk_config blkcfg;\n+\tuint32_t blk_size;\n+\tuint64_t blkcnt;\n+\n+\tif (bdev == NULL) {\n+\t\t/* We can't just return -1 here as this GET_CONFIG message might\n+\t\t * be caused by a QEMU VM reboot. Returning -1 will indicate an\n+\t\t * error to QEMU, who might then decide to terminate itself.\n+\t\t * We don't want that. A simple reboot shouldn't break the\n+\t\t * system.\n+\t\t *\n+\t\t * Presenting a block device with block size 0 and block count 0\n+\t\t * doesn't cause any problems on QEMU side and the virtio-pci\n+\t\t * device is even still available inside the VM, but there will\n+\t\t * be no block device created for it - the kernel drivers will\n+\t\t * silently reject it.\n+\t\t */\n+\t\tblk_size = 0;\n+\t\tblkcnt = 0;\n+\t} else {\n+\t\tblk_size = bdev->blocklen;\n+\t\tblkcnt = bdev->blockcnt;\n+\t}\n+\n+\tmemset(&blkcfg, 0, sizeof(blkcfg));\n+\tblkcfg.blk_size = blk_size;\n+\t/* minimum I/O size in blocks */\n+\tblkcfg.min_io_size = 1;\n+\t/* expressed in 512 Bytes sectors */\n+\tblkcfg.capacity = (blkcnt * blk_size) / 512;\n+\t/* QEMU can overwrite this value when started */\n+\tblkcfg.num_queues = VHOST_MAX_VQUEUES;\n+\n+\tfprintf(stdout, \"block device:blk_size = %d, blkcnt = %ld\\n\", blk_size,\n+\t\tblkcnt);\n+\n+\tmemcpy(config, &blkcfg, min(len, sizeof(blkcfg)));\n+\n+\treturn 0;\n+}\n+\n+static enum rte_vhost_msg_result\n+extern_vhost_pre_msg_handler(int vid, void *_msg)\n+{\n+\tchar path[PATH_MAX];\n+\tstruct vhost_blk_ctrlr *ctrlr;\n+\tstruct vhost_user_msg *msg = _msg;\n+\tint ret;\n+\n+\tret = rte_vhost_get_ifname(vid, path, PATH_MAX);\n+\tif (ret) {\n+\t\tfprintf(stderr, \"Cannot get socket name\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\tctrlr = vhost_blk_ctrlr_find(path);\n+\tif (!ctrlr) {\n+\t\tfprintf(stderr, \"Controller is not ready\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\tswitch ((int)msg->request) {\n+\tcase VHOST_USER_GET_VRING_BASE:\n+\tcase VHOST_USER_SET_VRING_BASE:\n+\tcase VHOST_USER_SET_VRING_ADDR:\n+\tcase VHOST_USER_SET_VRING_NUM:\n+\tcase VHOST_USER_SET_VRING_KICK:\n+\tcase VHOST_USER_SET_VRING_CALL:\n+\tcase VHOST_USER_SET_MEM_TABLE:\n+\t\tbreak;\n+\tcase VHOST_USER_GET_CONFIG: {\n+\t\tint rc = 0;\n+\n+\t\trc = vhost_blk_get_config(ctrlr->bdev,\n+\t\t\t\t\t  msg->payload.cfg.region,\n+\t\t\t\t\t  msg->payload.cfg.size);\n+\t\tif (rc != 0)\n+\t\t\tmsg->size = 0;\n+\n+\t\treturn RTE_VHOST_MSG_RESULT_REPLY;\n+\t}\n+\tcase VHOST_USER_SET_CONFIG:\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\treturn RTE_VHOST_MSG_RESULT_NOT_HANDLED;\n+}\n+\n+static enum rte_vhost_msg_result\n+extern_vhost_post_msg_handler(int vid, void *_msg)\n+{\n+\tchar path[PATH_MAX];\n+\tstruct vhost_blk_ctrlr *ctrlr;\n+\tstruct vhost_user_msg *msg = _msg;\n+\tint ret;\n+\n+\tret = rte_vhost_get_ifname(vid, path, PATH_MAX);\n+\tif (ret) {\n+\t\tfprintf(stderr, \"Cannot get socket name\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\tctrlr = vhost_blk_ctrlr_find(path);\n+\tif (!ctrlr) {\n+\t\tfprintf(stderr, \"Controller is not ready\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\tswitch (msg->request) {\n+\tcase VHOST_USER_SET_FEATURES:\n+\tcase VHOST_USER_SET_VRING_KICK:\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\treturn RTE_VHOST_MSG_RESULT_NOT_HANDLED;\n+}\n+\n+struct rte_vhost_user_extern_ops g_extern_vhost_ops = {\n+\t.pre_msg_handle = extern_vhost_pre_msg_handler,\n+\t.post_msg_handle = extern_vhost_post_msg_handler,\n+};\n+\n+void\n+vhost_session_install_rte_compat_hooks(uint32_t vid)\n+{\n+\tint rc;\n+\n+\trc = rte_vhost_extern_callback_register(vid, &g_extern_vhost_ops, NULL);\n+\tif (rc != 0)\n+\t\tfprintf(stderr,\n+\t\t\t\"rte_vhost_extern_callback_register() failed for vid = %d\\n\",\n+\t\t\tvid);\n+}\n+\n+void\n+vhost_dev_install_rte_compat_hooks(const char *path)\n+{\n+\tuint64_t protocol_features = 0;\n+\n+\trte_vhost_driver_get_protocol_features(path, &protocol_features);\n+\tprotocol_features |= (1ULL << VHOST_USER_PROTOCOL_F_CONFIG);\n+\tprotocol_features |= (1ULL << VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD);\n+\trte_vhost_driver_set_protocol_features(path, protocol_features);\n+}\n+\n+#endif\n",
    "prefixes": []
}