get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 85393,
    "url": "https://patches.dpdk.org/api/patches/85393/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/20201218073851.93609-5-chenbo.xia@intel.com/",
    "project": {
        "id": 1,
        "url": "https://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": "<20201218073851.93609-5-chenbo.xia@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20201218073851.93609-5-chenbo.xia@intel.com",
    "date": "2020-12-18T07:38:46",
    "name": "[4/9] vfio_user: implement DMA table and socket address API",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "c50c9b2fe43ef0d59cb0c3f6f749566976ebaa45",
    "submitter": {
        "id": 1276,
        "url": "https://patches.dpdk.org/api/people/1276/?format=api",
        "name": "Chenbo Xia",
        "email": "chenbo.xia@intel.com"
    },
    "delegate": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/20201218073851.93609-5-chenbo.xia@intel.com/mbox/",
    "series": [
        {
            "id": 14361,
            "url": "https://patches.dpdk.org/api/series/14361/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=14361",
            "date": "2020-12-18T07:38:42",
            "name": "Introduce vfio-user library",
            "version": 1,
            "mbox": "https://patches.dpdk.org/series/14361/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/85393/comments/",
    "check": "warning",
    "checks": "https://patches.dpdk.org/api/patches/85393/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from dpdk.org (dpdk.org [92.243.14.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id A6EE1A09F6;\n\tFri, 18 Dec 2020 08:55:37 +0100 (CET)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 063F3CA8F;\n\tFri, 18 Dec 2020 08:54:24 +0100 (CET)",
            "from mga05.intel.com (mga05.intel.com [192.55.52.43])\n by dpdk.org (Postfix) with ESMTP id A38D0CA54\n for <dev@dpdk.org>; Fri, 18 Dec 2020 08:54:21 +0100 (CET)",
            "from fmsmga008.fm.intel.com ([10.253.24.58])\n by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 17 Dec 2020 23:54:21 -0800",
            "from npg-dpdk-virtio-xiachenbo-nw.sh.intel.com ([10.67.119.123])\n by fmsmga008.fm.intel.com with ESMTP; 17 Dec 2020 23:54:18 -0800"
        ],
        "IronPort-SDR": [
            "\n arNhf7PYOQmORsicec9ASIVUX9rQ4w0B8OGBNn9+dV3c3uS5N34H+yA9SBJsDR+3axNMoVH+5B\n lLejSNSrgAbA==",
            "\n 4L0zK9vDViodTlFfEK2xVAcc7/zGrOsHC1Y3aipATKYwtMJxNQtpxyqWq8ihmWAI/8VWxpNSeK\n LsiT9p7L+JUw=="
        ],
        "X-IronPort-AV": [
            "E=McAfee;i=\"6000,8403,9838\"; a=\"260126161\"",
            "E=Sophos;i=\"5.78,429,1599548400\"; d=\"scan'208\";a=\"260126161\"",
            "E=Sophos;i=\"5.78,429,1599548400\"; d=\"scan'208\";a=\"340270357\""
        ],
        "X-ExtLoop1": "1",
        "From": "Chenbo Xia <chenbo.xia@intel.com>",
        "To": "dev@dpdk.org,\n\tthomas@monjalon.net,\n\tdavid.marchand@redhat.com",
        "Cc": "stephen@networkplumber.org, cunming.liang@intel.com, xiuchun.lu@intel.com,\n miao.li@intel.com, jingjing.wu@intel.com",
        "Date": "Fri, 18 Dec 2020 15:38:46 +0800",
        "Message-Id": "<20201218073851.93609-5-chenbo.xia@intel.com>",
        "X-Mailer": "git-send-email 2.17.1",
        "In-Reply-To": "<20201218073851.93609-1-chenbo.xia@intel.com>",
        "References": "<20201218073851.93609-1-chenbo.xia@intel.com>",
        "Subject": "[dpdk-dev] [PATCH 4/9] vfio_user: implement DMA table and socket\n\taddress API",
        "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 <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 <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "This patch introduces an API called rte_vfio_user_get_mem_table()\nfor emulated devices to acquire DMA memory table from vfio-user\nlibrary.\n\nNotify operations are also introduced to notify the emulated\ndevices of several events. Another socket address API is introduced\nfor translation between device ID and socket address in notify\ncallbacks.\n\nSigned-off-by: Chenbo Xia <chenbo.xia@intel.com>\nSigned-off-by: Xiuchun Lu <xiuchun.lu@intel.com>\n---\n lib/librte_vfio_user/rte_vfio_user.h    |  75 ++++-\n lib/librte_vfio_user/version.map        |   2 +\n lib/librte_vfio_user/vfio_user_base.h   |   2 +\n lib/librte_vfio_user/vfio_user_server.c | 363 +++++++++++++++++++++++-\n lib/librte_vfio_user/vfio_user_server.h |   3 +\n 5 files changed, 437 insertions(+), 8 deletions(-)",
    "diff": "diff --git a/lib/librte_vfio_user/rte_vfio_user.h b/lib/librte_vfio_user/rte_vfio_user.h\nindex 8a999c7aa0..044c43e7dc 100644\n--- a/lib/librte_vfio_user/rte_vfio_user.h\n+++ b/lib/librte_vfio_user/rte_vfio_user.h\n@@ -5,10 +5,52 @@\n #ifndef _RTE_VFIO_USER_H\n #define _RTE_VFIO_USER_H\n \n+#include <stdint.h>\n+#include <stddef.h>\n+#include <stdbool.h>\n #include <linux/vfio.h>\n+#include <sys/types.h>\n \n #include <rte_compat.h>\n \n+#define RTE_VUSER_MAX_DMA 256\n+\n+struct rte_vfio_user_notify_ops {\n+\t/* Add device */\n+\tint (*new_device)(int dev_id);\n+\t/* Remove device */\n+\tvoid (*destroy_device)(int dev_id);\n+\t/* Update device status */\n+\tint (*update_status)(int dev_id);\n+\t/* Lock or unlock data path */\n+\tint (*lock_dp)(int dev_id, int lock);\n+\t/* Reset device */\n+\tint (*reset_device)(int dev_id);\n+};\n+\n+struct rte_vfio_user_mem_reg {\n+\tuint64_t gpa;\n+\tuint64_t size;\n+\tuint64_t fd_offset;\n+\tuint32_t protection;\t/* attributes in <sys/mman.h> */\n+#define RTE_VUSER_MEM_MAPPABLE\t(0x1 << 0)\n+\tuint32_t flags;\n+};\n+\n+struct rte_vfio_user_mtb_entry {\n+\tuint64_t gpa;\n+\tuint64_t size;\n+\tuint64_t host_user_addr;\n+\tvoid\t *mmap_addr;\n+\tuint64_t mmap_size;\n+\tint fd;\n+};\n+\n+struct rte_vfio_user_mem {\n+\tuint32_t entry_num;\n+\tstruct rte_vfio_user_mtb_entry entry[RTE_VUSER_MAX_DMA];\n+};\n+\n struct rte_vfio_user_reg_info;\n \n typedef ssize_t (*rte_vfio_user_reg_acc_t)(struct rte_vfio_user_reg_info *reg,\n@@ -32,6 +74,8 @@ struct rte_vfio_user_regions {\n  *\t*rte_vfio_user_register\n  *\t*rte_vfio_user_unregister\n  *\t*rte_vfio_user_start\n+ *\t*rte_vfio_get_sock_addr\n+ *\t*rte_vfio_user_get_mem_table\n  *\t*rte_vfio_user_set_dev_info\n  *\t*rte_vfio_user_set_reg_info\n  */\n@@ -41,11 +85,14 @@ struct rte_vfio_user_regions {\n  *\n  * @param sock_addr\n  *   Unix domain socket address\n+ * @param ops\n+ *   Notify ops for the device\n  * @return\n  *   0 on success, -1 on failure\n  */\n __rte_experimental\n-int rte_vfio_user_register(const char *sock_addr);\n+int rte_vfio_user_register(const char *sock_addr,\n+\tconst struct rte_vfio_user_notify_ops *ops);\n \n /**\n  * Unregister a vfio-user device.\n@@ -70,6 +117,17 @@ int rte_vfio_user_unregister(const char *sock_addr);\n __rte_experimental\n int rte_vfio_user_start(const char *sock_addr);\n \n+/**\n+ * Get the memory table of a vfio-user device.\n+ *\n+ * @param dev_id\n+ *   Vfio-user device ID\n+ * @return\n+ *   Pointer to memory table on success, NULL on failure\n+ */\n+__rte_experimental\n+const struct rte_vfio_user_mem *rte_vfio_user_get_mem_table(int dev_id);\n+\n /**\n  * Set the device information for a vfio-user device.\n  *\n@@ -108,4 +166,19 @@ __rte_experimental\n int rte_vfio_user_set_reg_info(const char *sock_addr,\n \tstruct rte_vfio_user_regions *reg);\n \n+/**\n+ * Get the socket address for a vfio-user device.\n+ *\n+ * @param dev_id\n+ *   Vfio-user device ID\n+ * @param[out] buf\n+ *   Buffer to store socket address\n+ * @param len\n+ *   The length of the buffer\n+ * @return\n+ *   0 on success, -1 on failure\n+ */\n+__rte_experimental\n+int rte_vfio_get_sock_addr(int dev_id, char *buf, size_t len);\n+\n #endif\ndiff --git a/lib/librte_vfio_user/version.map b/lib/librte_vfio_user/version.map\nindex 0f4f5acba5..3a50b5ef0e 100644\n--- a/lib/librte_vfio_user/version.map\n+++ b/lib/librte_vfio_user/version.map\n@@ -4,6 +4,8 @@ EXPERIMENTAL {\n \trte_vfio_user_register;\n \trte_vfio_user_unregister;\n \trte_vfio_user_start;\n+\trte_vfio_get_sock_addr;\n+\trte_vfio_user_get_mem_table;\n \trte_vfio_user_set_dev_info;\n \trte_vfio_user_set_reg_info;\n \ndiff --git a/lib/librte_vfio_user/vfio_user_base.h b/lib/librte_vfio_user/vfio_user_base.h\nindex 0d8abde816..5f5e651e87 100644\n--- a/lib/librte_vfio_user/vfio_user_base.h\n+++ b/lib/librte_vfio_user/vfio_user_base.h\n@@ -9,6 +9,7 @@\n \n #include \"rte_vfio_user.h\"\n \n+#define VFIO_USER_MSG_MAX_NREG 8\n #define VFIO_USER_VERSION_MAJOR 1\n #define VFIO_USER_VERSION_MINOR 0\n #define VFIO_USER_MAX_RSVD 512\n@@ -79,6 +80,7 @@ typedef struct vfio_user_msg {\n \tuint32_t err;\t\t\t\t/* Valid in reply, optional */\n \tunion {\n \t\tstruct vfio_user_version ver;\n+\t\tstruct rte_vfio_user_mem_reg memory[VFIO_USER_MSG_MAX_NREG];\n \t\tstruct vfio_device_info dev_info;\n \t\tstruct vfio_user_reg reg_info;\n \t\tstruct vfio_user_reg_rw reg_rw;\ndiff --git a/lib/librte_vfio_user/vfio_user_server.c b/lib/librte_vfio_user/vfio_user_server.c\nindex d882f2ccbe..1162e463b7 100644\n--- a/lib/librte_vfio_user/vfio_user_server.c\n+++ b/lib/librte_vfio_user/vfio_user_server.c\n@@ -7,6 +7,7 @@\n #include <pthread.h>\n #include <inttypes.h>\n #include <sys/socket.h>\n+#include <sys/mman.h>\n #include <sys/un.h>\n \n #include \"vfio_user_server.h\"\n@@ -39,6 +40,211 @@ static int vfio_user_negotiate_version(struct vfio_user_server *dev,\n \t\treturn -ENOTSUP;\n }\n \n+static int mmap_one_region(struct rte_vfio_user_mtb_entry *entry,\n+\tstruct rte_vfio_user_mem_reg *memory, int fd)\n+{\n+\tif (fd != -1) {\n+\t\tif (memory->fd_offset >= -memory->size) {\n+\t\t\tVFIO_USER_LOG(ERR, \"memory fd_offset and size overflow\\n\");\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t\tentry->mmap_size = memory->fd_offset + memory->size;\n+\t\tentry->mmap_addr = mmap(NULL,\n+\t\t\tentry->mmap_size,\n+\t\t\tmemory->protection, MAP_SHARED,\n+\t\t\tfd, 0);\n+\t\tif (entry->mmap_addr == MAP_FAILED) {\n+\t\t\tVFIO_USER_LOG(ERR, \"Failed to mmap dma region\\n\");\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tentry->host_user_addr =\n+\t\t\t(uint64_t)entry->mmap_addr + memory->fd_offset;\n+\t\tentry->fd = fd;\n+\t} else {\n+\t\tentry->mmap_size = 0;\n+\t\tentry->mmap_addr = NULL;\n+\t\tentry->host_user_addr = 0;\n+\t\tentry->fd = -1;\n+\t}\n+\n+\tentry->gpa = memory->gpa;\n+\tentry->size = memory->size;\n+\n+\treturn 0;\n+}\n+\n+static uint32_t add_one_region(struct rte_vfio_user_mem *mem,\n+\tstruct rte_vfio_user_mem_reg *memory, int fd)\n+{\n+\tstruct rte_vfio_user_mtb_entry *entry = &mem->entry[0];\n+\tuint32_t num = mem->entry_num, i, j;\n+\tuint32_t sz = sizeof(struct rte_vfio_user_mtb_entry);\n+\tstruct rte_vfio_user_mtb_entry ent;\n+\tint err = 0;\n+\n+\tif (mem->entry_num == RTE_VUSER_MAX_DMA) {\n+\t\tVFIO_USER_LOG(ERR, \"Add mem region failed, reach max!\\n\");\n+\t\treturn -EBUSY;\n+\t}\n+\n+\tfor (i = 0; i < num; i++) {\n+\t\tentry = &mem->entry[i];\n+\n+\t\tif (memory->gpa == entry->gpa &&\n+\t\t\tmemory->size == entry->size)\n+\t\t\treturn -EEXIST;\n+\n+\t\tif (memory->gpa > entry->gpa &&\n+\t\t\tmemory->gpa >= entry->gpa + entry->size)\n+\t\t\tcontinue;\n+\n+\t\tif (memory->gpa < entry->gpa &&\n+\t\t\tmemory->gpa + memory->size <= entry->gpa)\n+\t\t\tbreak;\n+\n+\t\treturn -EINVAL;\n+\t}\n+\n+\terr = mmap_one_region(&ent, memory, fd);\n+\tif (err)\n+\t\treturn err;\n+\n+\tfor (j = num; j > i; j--)\n+\t\tmemcpy(&mem->entry[j], &mem->entry[j - 1], sz);\n+\tmemcpy(&mem->entry[i], &ent, sz);\n+\tmem->entry_num++;\n+\n+\tVFIO_USER_LOG(DEBUG, \"DMA MAP(gpa: 0x%\" PRIx64 \", sz: 0x%\" PRIx64\n+\t\t\t\", hva: 0x%\" PRIx64 \", ma: 0x%\" PRIx64\n+\t\t\t\", msz: 0x%\" PRIx64 \", fd: %d)\\n\", ent.gpa,\n+\t\t\tent.size, ent.host_user_addr, (uint64_t)ent.mmap_addr,\n+\t\t\tent.mmap_size, ent.fd);\n+\treturn 0;\n+}\n+\n+static void del_one_region(struct rte_vfio_user_mem *mem,\n+\tstruct rte_vfio_user_mem_reg *memory)\n+{\n+\tstruct rte_vfio_user_mtb_entry *entry;\n+\tuint32_t num = mem->entry_num, i, j;\n+\tuint32_t sz = sizeof(struct rte_vfio_user_mtb_entry);\n+\n+\tif (mem->entry_num == 0) {\n+\t\tVFIO_USER_LOG(ERR, \"Delete mem region failed (No region exists)!\\n\");\n+\t\treturn;\n+\t}\n+\n+\tfor (i = 0; i < num; i++) {\n+\t\tentry = &mem->entry[i];\n+\n+\t\tif (memory->gpa == entry->gpa &&\n+\t\t\tmemory->size == entry->size) {\n+\t\t\tif (entry->mmap_addr != NULL) {\n+\t\t\t\tmunmap(entry->mmap_addr, entry->mmap_size);\n+\t\t\t\tmem->entry[i].mmap_size = 0;\n+\t\t\t\tmem->entry[i].mmap_addr = NULL;\n+\t\t\t\tmem->entry[i].host_user_addr = 0;\n+\t\t\t\tmem->entry[i].fd = -1;\n+\t\t\t}\n+\n+\t\t\tmem->entry[i].gpa = 0;\n+\t\t\tmem->entry[i].size = 0;\n+\n+\t\t\tfor (j = i; j < num - 1; j++) {\n+\t\t\t\tmemcpy(&mem->entry[j], &mem->entry[j + 1],\n+\t\t\t\t\tsz);\n+\t\t\t}\n+\t\t\tmem->entry_num--;\n+\n+\t\t\tVFIO_USER_LOG(DEBUG, \"DMA UNMAP(gpa: 0x%\" PRIx64\n+\t\t\t\t\", sz: 0x%\" PRIx64 \", hva: 0x%\" PRIx64\n+\t\t\t\t\", ma: 0x%\" PRIx64\", msz: 0x%\" PRIx64\n+\t\t\t\t\", fd: %d)\\n\", entry->gpa, entry->size,\n+\t\t\t\tentry->host_user_addr,\n+\t\t\t\t(uint64_t)entry->mmap_addr, entry->mmap_size,\n+\t\t\t\tentry->fd);\n+\n+\t\t\treturn;\n+\t\t}\n+\t}\n+\n+\tVFIO_USER_LOG(ERR, \"Failed to find the region for dma unmap!\\n\");\n+}\n+\n+static int vfio_user_dma_map(struct vfio_user_server *dev, VFIO_USER_MSG *msg)\n+{\n+\tstruct rte_vfio_user_mem_reg *memory = msg->payload.memory;\n+\tuint32_t region_num, expected_fd = 0;\n+\tuint32_t i, j, fd, fd_idx = 0;\n+\tint ret = 0;\n+\n+\tif ((msg->size - VFIO_USER_MSG_HDR_SIZE) % sizeof(*memory) != 0) {\n+\t\tVFIO_USER_LOG(ERR, \"Invalid msg size for dma map\\n\");\n+\t\tvfio_user_close_msg_fds(msg);\n+\t\tret = -EINVAL;\n+\t\tgoto err;\n+\t}\n+\n+\tregion_num = (msg->size - VFIO_USER_MSG_HDR_SIZE)\n+\t\t/ sizeof(struct rte_vfio_user_mem_reg);\n+\n+\tfor (i = 0; i < region_num; i++) {\n+\t\tif (memory[i].flags & RTE_VUSER_MEM_MAPPABLE)\n+\t\t\texpected_fd++;\n+\t}\n+\n+\tif (vfio_user_check_msg_fdnum(msg, expected_fd) != 0) {\n+\t\tret = -EINVAL;\n+\t\tgoto err;\n+\t}\n+\n+\tfor (i = 0; i < region_num; i++) {\n+\t\tfd = (memory[i].flags & RTE_VUSER_MEM_MAPPABLE) ?\n+\t\t\tmsg->fds[fd_idx++] : -1;\n+\n+\t\tret = add_one_region(dev->mem, memory + i, fd);\n+\t\tif (ret < 0) {\n+\t\t\tVFIO_USER_LOG(ERR, \"Failed to add dma map\\n\");\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tif (i != region_num) {\n+\t\t/* Clear all mmaped region and fds */\n+\t\tfor (j = 0; j < region_num; j++) {\n+\t\t\tif (j < i)\n+\t\t\t\tdel_one_region(dev->mem, memory + j);\n+\t\t\telse\n+\t\t\t\tclose(msg->fds[j]);\n+\t\t}\n+\t}\n+err:\n+\t/* Do not reply fds back */\n+\tmsg->fd_num = 0;\n+\treturn ret;\n+}\n+\n+static int vfio_user_dma_unmap(struct vfio_user_server *dev, VFIO_USER_MSG *msg)\n+{\n+\tstruct rte_vfio_user_mem_reg *memory = msg->payload.memory;\n+\tuint32_t region_num = (msg->size - VFIO_USER_MSG_HDR_SIZE)\n+\t\t/ sizeof(struct rte_vfio_user_mem_reg);\n+\tuint32_t i;\n+\n+\tif (vfio_user_check_msg_fdnum(msg, 0) != 0)\n+\t\treturn -EINVAL;\n+\n+\tif ((msg->size - VFIO_USER_MSG_HDR_SIZE) % sizeof(*memory) != 0) {\n+\t\tVFIO_USER_LOG(ERR, \"Invalid msg size for dma unmap\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tfor (i = 0; i < region_num; i++)\n+\t\tdel_one_region(dev->mem, memory);\n+\n+\treturn 0;\n+}\n static int vfio_user_device_get_info(struct vfio_user_server *dev,\n \tVFIO_USER_MSG *msg)\n {\n@@ -173,11 +379,62 @@ static int vfio_user_region_write(struct vfio_user_server *dev,\n \treturn 0;\n }\n \n+static inline void vfio_user_destroy_mem_entries(struct rte_vfio_user_mem *mem)\n+{\n+\tstruct rte_vfio_user_mtb_entry *ent;\n+\tuint32_t i;\n+\n+\tfor (i = 0; i < mem->entry_num; i++) {\n+\t\tent = &mem->entry[i];\n+\t\tif (ent->host_user_addr) {\n+\t\t\tmunmap(ent->mmap_addr, ent->mmap_size);\n+\t\t\tclose(ent->fd);\n+\t\t}\n+\t}\n+\n+\tmemset(mem, 0, sizeof(*mem));\n+}\n+\n+static inline void vfio_user_destroy_mem(struct vfio_user_server *dev)\n+{\n+\tstruct rte_vfio_user_mem *mem = dev->mem;\n+\n+\tif (!mem)\n+\t\treturn;\n+\n+\tvfio_user_destroy_mem_entries(mem);\n+\n+\tfree(mem);\n+\tdev->mem = NULL;\n+}\n+\n+static int vfio_user_device_reset(struct vfio_user_server *dev,\n+\tVFIO_USER_MSG *msg)\n+{\n+\tstruct vfio_device_info *dev_info;\n+\n+\tif (vfio_user_check_msg_fdnum(msg, 0) != 0)\n+\t\treturn -EINVAL;\n+\n+\tdev_info = dev->dev_info;\n+\n+\tif (!(dev_info->flags & VFIO_DEVICE_FLAGS_RESET))\n+\t\treturn -ENOTSUP;\n+\n+\tvfio_user_destroy_mem_entries(dev->mem);\n+\tdev->is_ready = 0;\n+\n+\tif (dev->ops->reset_device)\n+\t\tdev->ops->reset_device(dev->dev_id);\n+\n+\treturn 0;\n+}\n+\n static vfio_user_msg_handler_t vfio_user_msg_handlers[VFIO_USER_MAX] = {\n \t[VFIO_USER_NONE] = NULL,\n \t[VFIO_USER_VERSION] = vfio_user_negotiate_version,\n-\t[VFIO_USER_DMA_MAP] = NULL,\n-\t[VFIO_USER_DMA_UNMAP] = NULL,\n+\t[VFIO_USER_DMA_MAP] = vfio_user_dma_map,\n+\t[VFIO_USER_DMA_UNMAP] = vfio_user_dma_unmap,\n \t[VFIO_USER_DEVICE_GET_INFO] = vfio_user_device_get_info,\n \t[VFIO_USER_DEVICE_GET_REGION_INFO] = vfio_user_device_get_reg_info,\n \t[VFIO_USER_DEVICE_GET_IRQ_INFO] = NULL,\n@@ -187,7 +444,7 @@ static vfio_user_msg_handler_t vfio_user_msg_handlers[VFIO_USER_MAX] = {\n \t[VFIO_USER_DMA_READ] = NULL,\n \t[VFIO_USER_DMA_WRITE] = NULL,\n \t[VFIO_USER_VM_INTERRUPT] = NULL,\n-\t[VFIO_USER_DEVICE_RESET] = NULL,\n+\t[VFIO_USER_DEVICE_RESET] = vfio_user_device_reset,\n };\n \n static struct vfio_user_server_socket *\n@@ -518,12 +775,27 @@ static inline struct vfio_user_server *vfio_user_get_device(int dev_id)\n \treturn dev;\n }\n \n+static inline int vfio_user_is_ready(struct vfio_user_server *dev)\n+{\n+\t/* vfio-user currently has no definition of when the device is ready.\n+\t * For now, we define it as when the device has at least one dma\n+\t * memory table entry.\n+\t */\n+\tif (dev->mem->entry_num > 0) {\n+\t\tdev->is_ready = 1;\n+\t\treturn 1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n static int vfio_user_message_handler(int dev_id, int fd)\n {\n \tstruct vfio_user_server *dev;\n \tVFIO_USER_MSG msg;\n \tuint32_t cmd;\n \tint ret = 0;\n+\tint dev_locked = 0;\n \n \tdev = vfio_user_get_device(dev_id);\n \tif (!dev)\n@@ -552,6 +824,17 @@ static int vfio_user_message_handler(int dev_id, int fd)\n \t\treturn -1;\n \t}\n \n+\t/*\n+\t * Below messages should lock the data path upon receiving\n+\t * to avoid errors in data path handling\n+\t */\n+\tif ((cmd == VFIO_USER_DMA_MAP || cmd == VFIO_USER_DMA_UNMAP ||\n+\t\tcmd == VFIO_USER_DEVICE_RESET)\n+\t\t&& dev->ops->lock_dp) {\n+\t\tdev->ops->lock_dp(dev_id, 1);\n+\t\tdev_locked = 1;\n+\t}\n+\n \tif (vfio_user_msg_handlers[cmd])\n \t\tret = vfio_user_msg_handlers[cmd](dev, &msg);\n \telse {\n@@ -584,7 +867,18 @@ static int vfio_user_message_handler(int dev_id, int fd)\n \t\t}\n \t}\n \n+\tif (!dev->is_ready) {\n+\t\tif (vfio_user_is_ready(dev) && dev->ops->new_device)\n+\t\t\tdev->ops->new_device(dev_id);\n+\t} else {\n+\t\tif ((cmd == VFIO_USER_DMA_MAP || cmd == VFIO_USER_DMA_UNMAP)\n+\t\t\t&& dev->ops->update_status)\n+\t\t\tdev->ops->update_status(dev_id);\n+\t}\n+\n handle_end:\n+\tif (dev_locked)\n+\t\tdev->ops->lock_dp(dev_id, 0);\n \treturn ret;\n }\n \n@@ -601,8 +895,12 @@ static int vfio_user_sock_read(int fd, void *data)\n \t\tclose(fd);\n \t\tsk->conn_fd = -1;\n \t\tdev = vfio_user_get_device(dev_id);\n-\t\tif (dev)\n+\t\tif (dev) {\n+\t\t\tdev->ops->destroy_device(dev_id);\n+\t\t\tvfio_user_destroy_mem_entries(dev->mem);\n+\t\t\tdev->is_ready = 0;\n \t\t\tdev->msg_id = 0;\n+\t\t}\n \t}\n \n \treturn ret;\n@@ -733,13 +1031,14 @@ vfio_user_start_server(struct vfio_user_server_socket *sk)\n \treturn -1;\n }\n \n-int rte_vfio_user_register(const char *sock_addr)\n+int rte_vfio_user_register(const char *sock_addr,\n+\tconst struct rte_vfio_user_notify_ops *ops)\n {\n \tstruct vfio_user_server_socket *sk;\n \tstruct vfio_user_server *dev;\n \tint dev_id;\n \n-\tif (!sock_addr)\n+\tif (!sock_addr || !ops)\n \t\treturn -1;\n \n \tsk = vfio_user_create_sock(sock_addr);\n@@ -757,11 +1056,22 @@ int rte_vfio_user_register(const char *sock_addr)\n \n \tdev = vfio_user_get_device(dev_id);\n \n+\tdev->mem = malloc(sizeof(struct rte_vfio_user_mem));\n+\tif (!dev->mem) {\n+\t\tVFIO_USER_LOG(ERR, \"Failed to alloc vfio_user_mem\\n\");\n+\t\tgoto err_mem;\n+\t}\n+\tmemset(dev->mem, 0, sizeof(struct rte_vfio_user_mem));\n+\n \tdev->ver.major = VFIO_USER_VERSION_MAJOR;\n \tdev->ver.minor = VFIO_USER_VERSION_MINOR;\n+\tdev->ops = ops;\n+\tdev->is_ready = 0;\n \n \treturn 0;\n \n+err_mem:\n+\tvfio_user_del_device(dev);\n err_add_dev:\n \tvfio_user_delete_sock(sk);\n exit:\n@@ -798,7 +1108,7 @@ int rte_vfio_user_unregister(const char *sock_addr)\n \t\t\t\"device not found.\\n\");\n \t\treturn -1;\n \t}\n-\n+\tvfio_user_destroy_mem(dev);\n \tvfio_user_del_device(dev);\n \n \treturn 0;\n@@ -920,3 +1230,42 @@ int rte_vfio_user_set_reg_info(const char *sock_addr,\n \n \treturn 0;\n }\n+\n+int rte_vfio_get_sock_addr(int dev_id, char *buf, size_t len)\n+{\n+\tstruct vfio_user_server *dev;\n+\n+\tdev = vfio_user_get_device(dev_id);\n+\tif (!dev) {\n+\t\tVFIO_USER_LOG(ERR, \"Failed to get sock address:\"\n+\t\t\t\"device %d not found.\\n\", dev_id);\n+\t\treturn -1;\n+\t}\n+\n+\tlen = len > sizeof(dev->sock_addr) ?\n+\t\tsizeof(dev->sock_addr) : len;\n+\tstrncpy(buf, dev->sock_addr, len);\n+\tbuf[len - 1] = '\\0';\n+\n+\treturn 0;\n+}\n+\n+const struct rte_vfio_user_mem *rte_vfio_user_get_mem_table(int dev_id)\n+{\n+\tstruct vfio_user_server *dev;\n+\n+\tdev = vfio_user_get_device(dev_id);\n+\tif (!dev) {\n+\t\tVFIO_USER_LOG(ERR, \"Failed to get memory table:\"\n+\t\t\t\"device %d not found.\\n\", dev_id);\n+\t\treturn NULL;\n+\t}\n+\n+\tif (!dev->mem) {\n+\t\tVFIO_USER_LOG(ERR, \"Failed to get memory table for device %d:\"\n+\t\t\t\"memory table not allocated.\\n\", dev_id);\n+\t\treturn NULL;\n+\t}\n+\n+\treturn dev->mem;\n+}\ndiff --git a/lib/librte_vfio_user/vfio_user_server.h b/lib/librte_vfio_user/vfio_user_server.h\nindex e8fb61cb3e..737940de62 100644\n--- a/lib/librte_vfio_user/vfio_user_server.h\n+++ b/lib/librte_vfio_user/vfio_user_server.h\n@@ -11,11 +11,14 @@\n \n struct vfio_user_server {\n \tint dev_id;\n+\tint is_ready;\n \tint started;\n \tint conn_fd;\n \tuint32_t msg_id;\n \tchar sock_addr[PATH_MAX];\n+\tconst struct rte_vfio_user_notify_ops *ops;\n \tstruct vfio_user_version ver;\n+\tstruct rte_vfio_user_mem *mem;\n \tstruct vfio_device_info *dev_info;\n \tstruct rte_vfio_user_regions *reg;\n };\n",
    "prefixes": [
        "4/9"
    ]
}