get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 69074,
    "url": "http://patchwork.dpdk.org/api/patches/69074/?format=api",
    "web_url": "http://patchwork.dpdk.org/project/dpdk/patch/20200422033006.1124-2-honnappa.nagarahalli@arm.com/",
    "project": {
        "id": 1,
        "url": "http://patchwork.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": "<20200422033006.1124-2-honnappa.nagarahalli@arm.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20200422033006.1124-2-honnappa.nagarahalli@arm.com",
    "date": "2020-04-22T03:30:03",
    "name": "[v5,1/4] lib/rcu: add resource reclamation APIs",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "ee03d84f31953e0af536423daeb98e820ab1d92d",
    "submitter": {
        "id": 1045,
        "url": "http://patchwork.dpdk.org/api/people/1045/?format=api",
        "name": "Honnappa Nagarahalli",
        "email": "honnappa.nagarahalli@arm.com"
    },
    "delegate": {
        "id": 24651,
        "url": "http://patchwork.dpdk.org/api/users/24651/?format=api",
        "username": "dmarchand",
        "first_name": "David",
        "last_name": "Marchand",
        "email": "david.marchand@redhat.com"
    },
    "mbox": "http://patchwork.dpdk.org/project/dpdk/patch/20200422033006.1124-2-honnappa.nagarahalli@arm.com/mbox/",
    "series": [
        {
            "id": 9558,
            "url": "http://patchwork.dpdk.org/api/series/9558/?format=api",
            "web_url": "http://patchwork.dpdk.org/project/dpdk/list/?series=9558",
            "date": "2020-04-22T03:30:02",
            "name": "Add RCU reclamation APIs",
            "version": 5,
            "mbox": "http://patchwork.dpdk.org/series/9558/mbox/"
        }
    ],
    "comments": "http://patchwork.dpdk.org/api/patches/69074/comments/",
    "check": "fail",
    "checks": "http://patchwork.dpdk.org/api/patches/69074/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 34BCFA05A1;\n\tWed, 22 Apr 2020 05:31:06 +0200 (CEST)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 12B9B1D176;\n\tWed, 22 Apr 2020 05:30:43 +0200 (CEST)",
            "from foss.arm.com (foss.arm.com [217.140.110.172])\n by dpdk.org (Postfix) with ESMTP id 7ADFC1C2F7\n for <dev@dpdk.org>; Wed, 22 Apr 2020 05:30:38 +0200 (CEST)",
            "from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14])\n by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id D843130E;\n Tue, 21 Apr 2020 20:30:32 -0700 (PDT)",
            "from qc2400f-1.austin.arm.com (qc2400f-1.austin.arm.com\n [10.118.14.48])\n by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id A45E63F6CF;\n Tue, 21 Apr 2020 20:30:32 -0700 (PDT)"
        ],
        "From": "Honnappa Nagarahalli <honnappa.nagarahalli@arm.com>",
        "To": "konstantin.ananyev@intel.com, stephen@networkplumber.org,\n vladimir.medvedkin@intel.com, dev@dpdk.org",
        "Cc": "honnappa.nagarahalli@arm.com, david.marchand@redhat.com,\n ruifeng.wang@arm.com, dharmik.thakkar@arm.com, nd@arm.com",
        "Date": "Tue, 21 Apr 2020 22:30:03 -0500",
        "Message-Id": "<20200422033006.1124-2-honnappa.nagarahalli@arm.com>",
        "X-Mailer": "git-send-email 2.17.1",
        "In-Reply-To": "<20200422033006.1124-1-honnappa.nagarahalli@arm.com>",
        "References": "<20191001062917.35578-1-honnappa.nagarahalli@arm.com>\n <20200422033006.1124-1-honnappa.nagarahalli@arm.com>",
        "Subject": "[dpdk-dev] [PATCH v5 1/4] lib/rcu: add resource reclamation APIs",
        "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": "Add resource reclamation APIs to make it simple for applications\nand libraries to integrate rte_rcu library.\n\nSigned-off-by: Honnappa Nagarahalli <honnappa.nagarahalli@arm.com>\nReviewed-by: Ola Liljedhal <ola.liljedhal@arm.com>\nReviewed-by: Ruifeng Wang <ruifeng.wang@arm.com>\nAcked-by: Konstantin Ananyev <konstantin.ananyev@intel.com>\n---\n lib/librte_rcu/Makefile            |   2 +-\n lib/librte_rcu/meson.build         |   7 +\n lib/librte_rcu/rcu_qsbr_pvt.h      |  66 +++++++++\n lib/librte_rcu/rte_rcu_qsbr.c      | 227 ++++++++++++++++++++++++++++-\n lib/librte_rcu/rte_rcu_qsbr.h      | 194 +++++++++++++++++++++++-\n lib/librte_rcu/rte_rcu_version.map |   4 +\n lib/meson.build                    |   6 +-\n 7 files changed, 501 insertions(+), 5 deletions(-)\n create mode 100644 lib/librte_rcu/rcu_qsbr_pvt.h",
    "diff": "diff --git a/lib/librte_rcu/Makefile b/lib/librte_rcu/Makefile\nindex 728669975..553bca2ef 100644\n--- a/lib/librte_rcu/Makefile\n+++ b/lib/librte_rcu/Makefile\n@@ -7,7 +7,7 @@ include $(RTE_SDK)/mk/rte.vars.mk\n LIB = librte_rcu.a\n \n CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3\n-LDLIBS += -lrte_eal\n+LDLIBS += -lrte_eal -lrte_ring\n \n EXPORT_MAP := rte_rcu_version.map\n \ndiff --git a/lib/librte_rcu/meson.build b/lib/librte_rcu/meson.build\nindex c009ae4b7..3eb2ace17 100644\n--- a/lib/librte_rcu/meson.build\n+++ b/lib/librte_rcu/meson.build\n@@ -3,3 +3,10 @@\n \n sources = files('rte_rcu_qsbr.c')\n headers = files('rte_rcu_qsbr.h')\n+\n+# for clang 32-bit compiles we need libatomic for 64-bit atomic ops\n+if cc.get_id() == 'clang' and dpdk_conf.get('RTE_ARCH_64') == false\n+\text_deps += cc.find_library('atomic')\n+endif\n+\n+deps += ['ring']\ndiff --git a/lib/librte_rcu/rcu_qsbr_pvt.h b/lib/librte_rcu/rcu_qsbr_pvt.h\nnew file mode 100644\nindex 000000000..63f7a5fff\n--- /dev/null\n+++ b/lib/librte_rcu/rcu_qsbr_pvt.h\n@@ -0,0 +1,66 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright (c) 2020 Arm Limited\n+ */\n+\n+#ifndef _RTE_RCU_QSBR_PVT_H_\n+#define _RTE_RCU_QSBR_PVT_H_\n+\n+/**\n+ * This file is private to the RCU library. It should not be included\n+ * by the user of this library.\n+ */\n+\n+#ifdef __cplusplus\n+extern \"C\" {\n+#endif\n+\n+#include <rte_ring.h>\n+#include <rte_ring_elem.h>\n+\n+#include \"rte_rcu_qsbr.h\"\n+\n+/* Defer queue structure.\n+ * This structure holds the defer queue. The defer queue is used to\n+ * hold the deleted entries from the data structure that are not\n+ * yet freed.\n+ */\n+struct rte_rcu_qsbr_dq {\n+\tstruct rte_rcu_qsbr *v; /**< RCU QSBR variable used by this queue.*/\n+\tstruct rte_ring *r;     /**< RCU QSBR defer queue. */\n+\tuint32_t size;\n+\t/**< Number of elements in the defer queue */\n+\tuint32_t esize;\n+\t/**< Size (in bytes) of data, including the token, stored on the\n+\t *   defer queue.\n+\t */\n+\tuint32_t trigger_reclaim_limit;\n+\t/**< Trigger automatic reclamation after the defer queue\n+\t *   has atleast these many resources waiting.\n+\t */\n+\tuint32_t max_reclaim_size;\n+\t/**< Reclaim at the max these many resources during auto\n+\t *   reclamation.\n+\t */\n+\trte_rcu_qsbr_free_resource_t free_fn;\n+\t/**< Function to call to free the resource. */\n+\tvoid *p;\n+\t/**< Pointer passed to the free function. Typically, this is the\n+\t *   pointer to the data structure to which the resource to free\n+\t *   belongs.\n+\t */\n+};\n+\n+/* Internal structure to represent the element on the defer queue.\n+ * Use alias as a character array is type casted to a variable\n+ * of this structure type.\n+ */\n+typedef struct {\n+\tuint64_t token;  /**< Token */\n+\tuint8_t elem[0]; /**< Pointer to user element */\n+} __attribute__((__may_alias__)) __rte_rcu_qsbr_dq_elem_t;\n+\n+#ifdef __cplusplus\n+}\n+#endif\n+\n+#endif /* _RTE_RCU_QSBR_PVT_H_ */\ndiff --git a/lib/librte_rcu/rte_rcu_qsbr.c b/lib/librte_rcu/rte_rcu_qsbr.c\nindex 2f3fad776..6a429d8b3 100644\n--- a/lib/librte_rcu/rte_rcu_qsbr.c\n+++ b/lib/librte_rcu/rte_rcu_qsbr.c\n@@ -1,6 +1,6 @@\n /* SPDX-License-Identifier: BSD-3-Clause\n  *\n- * Copyright (c) 2018 Arm Limited\n+ * Copyright (c) 2018-2020 Arm Limited\n  */\n \n #include <stdio.h>\n@@ -18,8 +18,10 @@\n #include <rte_per_lcore.h>\n #include <rte_lcore.h>\n #include <rte_errno.h>\n+#include <rte_ring_elem.h>\n \n #include \"rte_rcu_qsbr.h\"\n+#include \"rcu_qsbr_pvt.h\"\n \n /* Get the memory size of QSBR variable */\n size_t\n@@ -270,6 +272,229 @@ rte_rcu_qsbr_dump(FILE *f, struct rte_rcu_qsbr *v)\n \treturn 0;\n }\n \n+/* Create a queue used to store the data structure elements that can\n+ * be freed later. This queue is referred to as 'defer queue'.\n+ */\n+struct rte_rcu_qsbr_dq *\n+rte_rcu_qsbr_dq_create(const struct rte_rcu_qsbr_dq_parameters *params)\n+{\n+\tstruct rte_rcu_qsbr_dq *dq;\n+\tuint32_t qs_fifo_size;\n+\tunsigned int flags;\n+\n+\tif (params == NULL || params->free_fn == NULL ||\n+\t\tparams->v == NULL || params->name == NULL ||\n+\t\tparams->size == 0 || params->esize == 0 ||\n+\t\t(params->esize % 4 != 0)) {\n+\t\trte_log(RTE_LOG_ERR, rte_rcu_log_type,\n+\t\t\t\"%s(): Invalid input parameter\\n\", __func__);\n+\t\trte_errno = EINVAL;\n+\n+\t\treturn NULL;\n+\t}\n+\t/* If auto reclamation is configured, reclaim limit\n+\t * should be a valid value.\n+\t */\n+\tif ((params->trigger_reclaim_limit <= params->size) &&\n+\t    (params->max_reclaim_size == 0)) {\n+\t\trte_log(RTE_LOG_ERR, rte_rcu_log_type,\n+\t\t\t\"%s(): Invalid input parameter, size = %u, trigger_reclaim_limit = %u, max_reclaim_size = %u\\n\",\n+\t\t\t__func__, params->size, params->trigger_reclaim_limit,\n+\t\t\tparams->max_reclaim_size);\n+\t\trte_errno = EINVAL;\n+\n+\t\treturn NULL;\n+\t}\n+\n+\tdq = rte_zmalloc(NULL, sizeof(struct rte_rcu_qsbr_dq),\n+\t\t\t RTE_CACHE_LINE_SIZE);\n+\tif (dq == NULL) {\n+\t\trte_errno = ENOMEM;\n+\n+\t\treturn NULL;\n+\t}\n+\n+\t/* Decide the flags for the ring.\n+\t * If MT safety is requested, use RTS for ring enqueue as most\n+\t * use cases involve dq-enqueue happening on the control plane.\n+\t * Ring dequeue is always HTS due to the possibility of revert.\n+\t */\n+\tflags = RING_F_MP_RTS_ENQ;\n+\tif (params->flags & RTE_RCU_QSBR_DQ_MT_UNSAFE)\n+\t\tflags = RING_F_SP_ENQ;\n+\tflags |= RING_F_MC_HTS_DEQ;\n+\t/* round up qs_fifo_size to next power of two that is not less than\n+\t * max_size.\n+\t */\n+\tqs_fifo_size = rte_align32pow2(params->size + 1);\n+\t/* Add token size to ring element size */\n+\tdq->r = rte_ring_create_elem(params->name,\n+\t\t\t__RTE_QSBR_TOKEN_SIZE + params->esize,\n+\t\t\tqs_fifo_size, SOCKET_ID_ANY, flags);\n+\tif (dq->r == NULL) {\n+\t\trte_log(RTE_LOG_ERR, rte_rcu_log_type,\n+\t\t\t\"%s(): defer queue create failed\\n\", __func__);\n+\t\trte_free(dq);\n+\t\treturn NULL;\n+\t}\n+\n+\tdq->v = params->v;\n+\tdq->size = params->size;\n+\tdq->esize = __RTE_QSBR_TOKEN_SIZE + params->esize;\n+\tdq->trigger_reclaim_limit = params->trigger_reclaim_limit;\n+\tdq->max_reclaim_size = params->max_reclaim_size;\n+\tdq->free_fn = params->free_fn;\n+\tdq->p = params->p;\n+\n+\treturn dq;\n+}\n+\n+/* Enqueue one resource to the defer queue to free after the grace\n+ * period is over.\n+ */\n+int rte_rcu_qsbr_dq_enqueue(struct rte_rcu_qsbr_dq *dq, void *e)\n+{\n+\t__rte_rcu_qsbr_dq_elem_t *dq_elem;\n+\tuint32_t cur_size;\n+\n+\tif (dq == NULL || e == NULL) {\n+\t\trte_log(RTE_LOG_ERR, rte_rcu_log_type,\n+\t\t\t\"%s(): Invalid input parameter\\n\", __func__);\n+\t\trte_errno = EINVAL;\n+\n+\t\treturn 1;\n+\t}\n+\n+\tchar data[dq->esize];\n+\tdq_elem = (__rte_rcu_qsbr_dq_elem_t *)data;\n+\t/* Start the grace period */\n+\tdq_elem->token = rte_rcu_qsbr_start(dq->v);\n+\n+\t/* Reclaim resources if the queue size has hit the reclaim\n+\t * limit. This helps the queue from growing too large and\n+\t * allows time for reader threads to report their quiescent state.\n+\t */\n+\tcur_size = rte_ring_count(dq->r);\n+\tif (cur_size > dq->trigger_reclaim_limit) {\n+\t\trte_log(RTE_LOG_INFO, rte_rcu_log_type,\n+\t\t\t\"%s(): Triggering reclamation\\n\", __func__);\n+\t\trte_rcu_qsbr_dq_reclaim(dq, dq->max_reclaim_size,\n+\t\t\t\t\t\tNULL, NULL, NULL);\n+\t}\n+\n+\t/* Enqueue the token and resource. Generating the token and\n+\t * enqueuing (token + resource) on the queue is not an\n+\t * atomic operation. When the defer queue is shared by multiple\n+\t * writers, this might result in tokens enqueued out of order\n+\t * on the queue. So, some tokens might wait longer than they\n+\t * are required to be reclaimed.\n+\t */\n+\tmemcpy(dq_elem->elem, e, dq->esize - __RTE_QSBR_TOKEN_SIZE);\n+\t/* Check the status as enqueue might fail since the other threads\n+\t * might have used up the freed space.\n+\t * Enqueue uses the configured flags when the DQ was created.\n+\t */\n+\tif (rte_ring_enqueue_elem(dq->r, data, dq->esize) != 0) {\n+\t\trte_log(RTE_LOG_ERR, rte_rcu_log_type,\n+\t\t\t\"%s(): Enqueue failed\\n\", __func__);\n+\t\t/* Note that the token generated above is not used.\n+\t\t * Other than wasting tokens, it should not cause any\n+\t\t * other issues.\n+\t\t */\n+\t\trte_log(RTE_LOG_INFO, rte_rcu_log_type,\n+\t\t\t\"%s(): Skipped enqueuing token = %\"PRIu64\"\\n\",\n+\t\t\t__func__, dq_elem->token);\n+\n+\t\trte_errno = ENOSPC;\n+\t\treturn 1;\n+\t}\n+\n+\trte_log(RTE_LOG_INFO, rte_rcu_log_type,\n+\t\t\"%s(): Enqueued token = %\"PRIu64\"\\n\", __func__, dq_elem->token);\n+\n+\treturn 0;\n+}\n+\n+/* Reclaim resources from the defer queue. */\n+int\n+rte_rcu_qsbr_dq_reclaim(struct rte_rcu_qsbr_dq *dq, unsigned int n,\n+\t\t\tunsigned int *freed, unsigned int *pending,\n+\t\t\tunsigned int *available)\n+{\n+\tuint32_t cnt;\n+\t__rte_rcu_qsbr_dq_elem_t *dq_elem;\n+\n+\tif (dq == NULL || n == 0) {\n+\t\trte_log(RTE_LOG_ERR, rte_rcu_log_type,\n+\t\t\t\"%s(): Invalid input parameter\\n\", __func__);\n+\t\trte_errno = EINVAL;\n+\n+\t\treturn 1;\n+\t}\n+\n+\tcnt = 0;\n+\n+\tchar data[dq->esize];\n+\t/* Check reader threads quiescent state and reclaim resources */\n+\twhile (cnt < n &&\n+\t\trte_ring_dequeue_bulk_elem_start(dq->r, &data,\n+\t\t\t\t\tdq->esize, 1, available) != 0) {\n+\t\tdq_elem = (__rte_rcu_qsbr_dq_elem_t *)data;\n+\n+\t\t/* Reclaim the resource */\n+\t\tif (rte_rcu_qsbr_check(dq->v, dq_elem->token, false) != 1) {\n+\t\t\trte_ring_dequeue_elem_finish(dq->r, 0);\n+\t\t\tbreak;\n+\t\t}\n+\t\trte_ring_dequeue_elem_finish(dq->r, 1);\n+\n+\t\trte_log(RTE_LOG_INFO, rte_rcu_log_type,\n+\t\t\t\"%s(): Reclaimed token = %\"PRIu64\"\\n\",\n+\t\t\t__func__, dq_elem->token);\n+\n+\t\tdq->free_fn(dq->p, dq_elem->elem, 1);\n+\n+\t\tcnt++;\n+\t}\n+\n+\trte_log(RTE_LOG_INFO, rte_rcu_log_type,\n+\t\t\"%s(): Reclaimed %u resources\\n\", __func__, cnt);\n+\n+\tif (freed != NULL)\n+\t\t*freed = cnt;\n+\tif (pending != NULL)\n+\t\t*pending = rte_ring_count(dq->r);\n+\n+\treturn 0;\n+}\n+\n+/* Delete a defer queue. */\n+int\n+rte_rcu_qsbr_dq_delete(struct rte_rcu_qsbr_dq *dq)\n+{\n+\tunsigned int pending;\n+\n+\tif (dq == NULL) {\n+\t\trte_log(RTE_LOG_DEBUG, rte_rcu_log_type,\n+\t\t\t\"%s(): Invalid input parameter\\n\", __func__);\n+\n+\t\treturn 0;\n+\t}\n+\n+\t/* Reclaim all the resources */\n+\trte_rcu_qsbr_dq_reclaim(dq, ~0, NULL, &pending, NULL);\n+\tif (pending != 0) {\n+\t\trte_errno = EAGAIN;\n+\n+\t\treturn 1;\n+\t}\n+\n+\trte_ring_free(dq->r);\n+\trte_free(dq);\n+\n+\treturn 0;\n+}\n+\n int rte_rcu_log_type;\n \n RTE_INIT(rte_rcu_register)\ndiff --git a/lib/librte_rcu/rte_rcu_qsbr.h b/lib/librte_rcu/rte_rcu_qsbr.h\nindex 0b5585925..e2fc7f83e 100644\n--- a/lib/librte_rcu/rte_rcu_qsbr.h\n+++ b/lib/librte_rcu/rte_rcu_qsbr.h\n@@ -1,5 +1,5 @@\n /* SPDX-License-Identifier: BSD-3-Clause\n- * Copyright (c) 2018 Arm Limited\n+ * Copyright (c) 2018-2020 Arm Limited\n  */\n \n #ifndef _RTE_RCU_QSBR_H_\n@@ -34,6 +34,7 @@ extern \"C\" {\n #include <rte_lcore.h>\n #include <rte_debug.h>\n #include <rte_atomic.h>\n+#include <rte_ring.h>\n \n extern int rte_rcu_log_type;\n \n@@ -84,6 +85,7 @@ struct rte_rcu_qsbr_cnt {\n #define __RTE_QSBR_CNT_THR_OFFLINE 0\n #define __RTE_QSBR_CNT_INIT 1\n #define __RTE_QSBR_CNT_MAX ((uint64_t)~0)\n+#define __RTE_QSBR_TOKEN_SIZE sizeof(uint64_t)\n \n /* RTE Quiescent State variable structure.\n  * This structure has two elements that vary in size based on the\n@@ -114,6 +116,86 @@ struct rte_rcu_qsbr {\n \t */\n } __rte_cache_aligned;\n \n+/**\n+ * Call back function called to free the resources.\n+ *\n+ * @param p\n+ *   Pointer provided while creating the defer queue\n+ * @param e\n+ *   Pointer to the resource data stored on the defer queue\n+ * @param n\n+ *   Number of resources to free. Currently, this is set to 1.\n+ *\n+ * @return\n+ *   None\n+ */\n+typedef void (*rte_rcu_qsbr_free_resource_t)(void *p, void *e, unsigned int n);\n+\n+#define RTE_RCU_QSBR_DQ_NAMESIZE RTE_RING_NAMESIZE\n+\n+/**\n+ * Various flags supported.\n+ */\n+/**< Enqueue and reclaim operations are multi-thread safe by default.\n+ *   The call back functions registered to free the resources are\n+ *   assumed to be multi-thread safe.\n+ *   Set this flag is multi-thread safety is not required.\n+ */\n+#define RTE_RCU_QSBR_DQ_MT_UNSAFE 1\n+\n+/**\n+ * Parameters used when creating the defer queue.\n+ */\n+struct rte_rcu_qsbr_dq_parameters {\n+\tconst char *name;\n+\t/**< Name of the queue. */\n+\tuint32_t flags;\n+\t/**< Flags to control API behaviors */\n+\tuint32_t size;\n+\t/**< Number of entries in queue. Typically, this will be\n+\t *   the same as the maximum number of entries supported in the\n+\t *   lock free data structure.\n+\t *   Data structures with unbounded number of entries is not\n+\t *   supported currently.\n+\t */\n+\tuint32_t esize;\n+\t/**< Size (in bytes) of each element in the defer queue.\n+\t *   This has to be multiple of 4B.\n+\t */\n+\tuint32_t trigger_reclaim_limit;\n+\t/**< Trigger automatic reclamation after the defer queue\n+\t *   has atleast these many resources waiting. This auto\n+\t *   reclamation is triggered in rte_rcu_qsbr_dq_enqueue API\n+\t *   call.\n+\t *   If this is greater than 'size', auto reclamation is\n+\t *   not triggered.\n+\t *   If this is set to 0, auto reclamation is triggered\n+\t *   in every call to rte_rcu_qsbr_dq_enqueue API.\n+\t */\n+\tuint32_t max_reclaim_size;\n+\t/**< When automatic reclamation is enabled, reclaim at the max\n+\t *   these many resources. This should contain a valid value, if\n+\t *   auto reclamation is on. Setting this to 'size' or greater will\n+\t *   reclaim all possible resources currently on the defer queue.\n+\t */\n+\trte_rcu_qsbr_free_resource_t free_fn;\n+\t/**< Function to call to free the resource. */\n+\tvoid *p;\n+\t/**< Pointer passed to the free function. Typically, this is the\n+\t *   pointer to the data structure to which the resource to free\n+\t *   belongs. This can be NULL.\n+\t */\n+\tstruct rte_rcu_qsbr *v;\n+\t/**< RCU QSBR variable to use for this defer queue */\n+};\n+\n+/* RTE defer queue structure.\n+ * This structure holds the defer queue. The defer queue is used to\n+ * hold the deleted entries from the data structure that are not\n+ * yet freed.\n+ */\n+struct rte_rcu_qsbr_dq;\n+\n /**\n  * @warning\n  * @b EXPERIMENTAL: this API may change without prior notice\n@@ -692,6 +774,116 @@ __rte_experimental\n int\n rte_rcu_qsbr_dump(FILE *f, struct rte_rcu_qsbr *v);\n \n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Create a queue used to store the data structure elements that can\n+ * be freed later. This queue is referred to as 'defer queue'.\n+ *\n+ * @param params\n+ *   Parameters to create a defer queue.\n+ * @return\n+ *   On success - Valid pointer to defer queue\n+ *   On error - NULL\n+ *   Possible rte_errno codes are:\n+ *   - EINVAL - NULL parameters are passed\n+ *   - ENOMEM - Not enough memory\n+ */\n+__rte_experimental\n+struct rte_rcu_qsbr_dq *\n+rte_rcu_qsbr_dq_create(const struct rte_rcu_qsbr_dq_parameters *params);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Enqueue one resource to the defer queue and start the grace period.\n+ * The resource will be freed later after at least one grace period\n+ * is over.\n+ *\n+ * If the defer queue is full, it will attempt to reclaim resources.\n+ * It will also reclaim resources at regular intervals to avoid\n+ * the defer queue from growing too big.\n+ *\n+ * Multi-thread safety is provided as the defer queue configuration.\n+ * When multi-thread safety is requested, it is possible that the\n+ * resources are not stored in their order of deletion. This results\n+ * in resources being held in the defer queue longer than they should.\n+ *\n+ * @param dq\n+ *   Defer queue to allocate an entry from.\n+ * @param e\n+ *   Pointer to resource data to copy to the defer queue. The size of\n+ *   the data to copy is equal to the element size provided when the\n+ *   defer queue was created.\n+ * @return\n+ *   On success - 0\n+ *   On error - 1 with rte_errno set to\n+ *   - EINVAL - NULL parameters are passed\n+ *   - ENOSPC - Defer queue is full. This condition can not happen\n+ *\t\tif the defer queue size is equal (or larger) than the\n+ *\t\tnumber of elements in the data structure.\n+ */\n+__rte_experimental\n+int\n+rte_rcu_qsbr_dq_enqueue(struct rte_rcu_qsbr_dq *dq, void *e);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Free quesed resources from the defer queue.\n+ *\n+ * This API is multi-thread safe.\n+ *\n+ * @param dq\n+ *   Defer queue to free an entry from.\n+ * @param n\n+ *   Maximum number of resources to free.\n+ * @param freed\n+ *   Number of resources that were freed.\n+ * @param pending\n+ *   Number of resources pending on the defer queue. This number might not\n+ *   be acurate if multi-thread safety is configured.\n+ * @param available\n+ *   Number of resources that can be added to the defer queue.\n+ *   This number might not be acurate if multi-thread safety is configured.\n+ * @return\n+ *   On successful reclamation of at least 1 resource - 0\n+ *   On error - 1 with rte_errno set to\n+ *   - EINVAL - NULL parameters are passed\n+ */\n+__rte_experimental\n+int\n+rte_rcu_qsbr_dq_reclaim(struct rte_rcu_qsbr_dq *dq, unsigned int n,\n+\tunsigned int *freed, unsigned int *pending, unsigned int *available);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Delete a defer queue.\n+ *\n+ * It tries to reclaim all the resources on the defer queue.\n+ * If any of the resources have not completed the grace period\n+ * the reclamation stops and returns immediately. The rest of\n+ * the resources are not reclaimed and the defer queue is not\n+ * freed.\n+ *\n+ * @param dq\n+ *   Defer queue to delete.\n+ * @return\n+ *   On success - 0\n+ *   On error - 1\n+ *   Possible rte_errno codes are:\n+ *   - EAGAIN - Some of the resources have not completed at least 1 grace\n+ *\t\tperiod, try again.\n+ */\n+__rte_experimental\n+int\n+rte_rcu_qsbr_dq_delete(struct rte_rcu_qsbr_dq *dq);\n+\n #ifdef __cplusplus\n }\n #endif\ndiff --git a/lib/librte_rcu/rte_rcu_version.map b/lib/librte_rcu/rte_rcu_version.map\nindex f8b9ef2ab..dfac88a37 100644\n--- a/lib/librte_rcu/rte_rcu_version.map\n+++ b/lib/librte_rcu/rte_rcu_version.map\n@@ -8,6 +8,10 @@ EXPERIMENTAL {\n \trte_rcu_qsbr_synchronize;\n \trte_rcu_qsbr_thread_register;\n \trte_rcu_qsbr_thread_unregister;\n+\trte_rcu_qsbr_dq_create;\n+\trte_rcu_qsbr_dq_enqueue;\n+\trte_rcu_qsbr_dq_reclaim;\n+\trte_rcu_qsbr_dq_delete;\n \n \tlocal: *;\n };\ndiff --git a/lib/meson.build b/lib/meson.build\nindex 63c17ee75..c28b8df83 100644\n--- a/lib/meson.build\n+++ b/lib/meson.build\n@@ -11,7 +11,9 @@\n libraries = [\n \t'kvargs', # eal depends on kvargs\n \t'eal', # everything depends on eal\n-\t'ring', 'mempool', 'mbuf', 'net', 'meter', 'ethdev', 'pci', # core\n+\t'ring',\n+\t'rcu', # rcu depends on ring\n+\t'mempool', 'mbuf', 'net', 'meter', 'ethdev', 'pci', # core\n \t'cmdline',\n \t'metrics', # bitrate/latency stats depends on this\n \t'hash',    # efd depends on this\n@@ -22,7 +24,7 @@ libraries = [\n \t'gro', 'gso', 'ip_frag', 'jobstats',\n \t'kni', 'latencystats', 'lpm', 'member',\n \t'power', 'pdump', 'rawdev',\n-\t'rcu', 'rib', 'reorder', 'sched', 'security', 'stack', 'vhost',\n+\t'rib', 'reorder', 'sched', 'security', 'stack', 'vhost',\n \t# ipsec lib depends on net, crypto and security\n \t'ipsec',\n \t#fib lib depends on rib\n",
    "prefixes": [
        "v5",
        "1/4"
    ]
}