get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 103974,
    "url": "http://patches.dpdk.org/api/patches/103974/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20211108185805.3887-5-eagostini@nvidia.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": "<20211108185805.3887-5-eagostini@nvidia.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20211108185805.3887-5-eagostini@nvidia.com",
    "date": "2021-11-08T18:58:00",
    "name": "[v5,4/9] gpudev: support multi-process",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "12bb512b6504c81c8dd3f726c6c80ec27b63c00c",
    "submitter": {
        "id": 1571,
        "url": "http://patches.dpdk.org/api/people/1571/?format=api",
        "name": "Elena Agostini",
        "email": "eagostini@nvidia.com"
    },
    "delegate": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20211108185805.3887-5-eagostini@nvidia.com/mbox/",
    "series": [
        {
            "id": 20381,
            "url": "http://patches.dpdk.org/api/series/20381/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=20381",
            "date": "2021-11-08T18:57:56",
            "name": "GPU library",
            "version": 5,
            "mbox": "http://patches.dpdk.org/series/20381/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/103974/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/103974/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 mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 9E16CA0C4D;\n\tMon,  8 Nov 2021 11:47:41 +0100 (CET)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 4EE1B41134;\n\tMon,  8 Nov 2021 11:47:11 +0100 (CET)",
            "from NAM12-MW2-obe.outbound.protection.outlook.com\n (mail-mw2nam12on2045.outbound.protection.outlook.com [40.107.244.45])\n by mails.dpdk.org (Postfix) with ESMTP id 22EDB410FE\n for <dev@dpdk.org>; Mon,  8 Nov 2021 11:47:08 +0100 (CET)",
            "from MW2PR16CA0042.namprd16.prod.outlook.com (2603:10b6:907:1::19)\n by CY4PR12MB1848.namprd12.prod.outlook.com (2603:10b6:903:11d::23) with\n Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4669.11; Mon, 8 Nov\n 2021 10:47:05 +0000",
            "from CO1NAM11FT064.eop-nam11.prod.protection.outlook.com\n (2603:10b6:907:1:cafe::eb) by MW2PR16CA0042.outlook.office365.com\n (2603:10b6:907:1::19) with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4669.10 via Frontend\n Transport; Mon, 8 Nov 2021 10:47:05 +0000",
            "from mail.nvidia.com (216.228.112.34) by\n CO1NAM11FT064.mail.protection.outlook.com (10.13.175.77) with Microsoft SMTP\n Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id\n 15.20.4669.10 via Frontend Transport; Mon, 8 Nov 2021 10:47:05 +0000",
            "from nvidia.com (172.20.187.6) by HQMAIL107.nvidia.com\n (172.20.187.13) with Microsoft SMTP Server (TLS) id 15.0.1497.18; Mon, 8 Nov\n 2021 10:47:01 +0000"
        ],
        "ARC-Seal": "i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none;\n b=CFyJUpGykiKknlJHj3VIoXin5kEuPopVyxHxL5Oz2bXMC14NA0dxwgyqXcX4qFcDh89v3h+hZuq+zZiccBqWyarjLqjw2wYqOH9oX2Dor6QTsu3xje7UDGVlPfKLBPXl5DojI+ywcWf5xLZS2LinD3Qeer40qnq2hUL6+JB9K+TSltDuVaTVL4IaDd55IRqjp9VtuUohbEjTdLu40VUVS0+l89AIgqgs8igJjEyWwBJVJaYz5gZBFU49FjhLAxy5Cr4wYt7HUF0PHJeQ2KZXpoSg9fWhRpnINuksmcH50HQMtZXzfYQ6oQMfTuBKnGEP7Yb0ByJaiDDu5bcfhbZaKA==",
        "ARC-Message-Signature": "i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com;\n s=arcselector9901;\n h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1;\n bh=1utuGE3qDCyuDfeI8PvdiruktOTYEdv9GIs8dNYtH60=;\n b=Sj3HH9ijbHYqd+lEqKP2S+lmC+Iipq2/hVkyFDFjZZ+uOG2ok1Jeet+jOOI/Pzm/PPO0O5a9YsLgxj9lYjHsFLeIb8uLQ7FAvRz/1Xy+/73+FdVLyNiRKlCMNqkjANpZ3P3Rt7sFo3NhmYYox/qEVpjLkpGghol0F/3ptadi9NWrlnhIhX//xq+IMEeqX2PFLBSuQVSYhaL4ODjQrRWDtPtLRBgsEomazGia4H2Hipg0nCYutAi5UKbDalJcvO/Xf98yhZv+JHocj6niHsMUTRk7VVjURWuKpg5fusMHuzLSI+b+sBtpgPHRHLdwXN7knixKai7yr0xCPGGlWWiylQ==",
        "ARC-Authentication-Results": "i=1; mx.microsoft.com 1; spf=pass (sender ip is\n 216.228.112.34) smtp.rcpttodomain=monjalon.net smtp.mailfrom=nvidia.com;\n dmarc=pass (p=quarantine sp=quarantine pct=100) action=none\n header.from=nvidia.com; dkim=none (message not signed); arc=none",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com;\n s=selector2;\n h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;\n bh=1utuGE3qDCyuDfeI8PvdiruktOTYEdv9GIs8dNYtH60=;\n b=Uqc/eJ2XNe6lsmbqq1a4TmWCs/SrMIbZPq/H8VMNqnvla/SQx1/1Q7Qsfeo/ostYeDyzzXdB82WbKUp/Gs1+y5oMdrzUB0USNr4WsXxX/d4Qj5bq8DWoXaUULPAY0fHlAvuv6nXUJTFQ3HsUsJAxxywG4G4piRgW7+Z3qonqI/pOoHCF0w+VaZBuvEXvQfIFctuQCJa4ltewaUXovzWfUhvsK40omGhqGmsL4q/A75xaEedY7wwFVv2Us44pwOqvDb7nFxiswNAeukECZ7TMgDcKnnfbq9vL2xti44XEsLRA824NqnzUYwKfopR6g/L9AVdPJS728L/fUPetIE58eg==",
        "X-MS-Exchange-Authentication-Results": "spf=pass (sender IP is 216.228.112.34)\n smtp.mailfrom=nvidia.com; monjalon.net; dkim=none (message not signed)\n header.d=none;monjalon.net; dmarc=pass action=none header.from=nvidia.com;",
        "Received-SPF": "Pass (protection.outlook.com: domain of nvidia.com designates\n 216.228.112.34 as permitted sender) receiver=protection.outlook.com;\n client-ip=216.228.112.34; helo=mail.nvidia.com;",
        "From": "<eagostini@nvidia.com>",
        "To": "<dev@dpdk.org>",
        "CC": "Thomas Monjalon <thomas@monjalon.net>",
        "Date": "Mon, 8 Nov 2021 18:58:00 +0000",
        "Message-ID": "<20211108185805.3887-5-eagostini@nvidia.com>",
        "X-Mailer": "git-send-email 2.17.1",
        "In-Reply-To": "<20211108185805.3887-1-eagostini@nvidia.com>",
        "References": "<20210602203531.2288645-1-thomas@monjalon.net>\n <20211108185805.3887-1-eagostini@nvidia.com>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain",
        "X-Originating-IP": "[172.20.187.6]",
        "X-ClientProxiedBy": "HQMAIL105.nvidia.com (172.20.187.12) To\n HQMAIL107.nvidia.com (172.20.187.13)",
        "X-EOPAttributedMessage": "0",
        "X-MS-PublicTrafficType": "Email",
        "X-MS-Office365-Filtering-Correlation-Id": "d7f889ca-bb10-4d49-3cad-08d9a2a51ae0",
        "X-MS-TrafficTypeDiagnostic": "CY4PR12MB1848:",
        "X-LD-Processed": "43083d15-7273-40c1-b7db-39efd9ccc17a,ExtAddr",
        "X-Microsoft-Antispam-PRVS": "\n <CY4PR12MB184812AE1993A7AABA4D758ECD919@CY4PR12MB1848.namprd12.prod.outlook.com>",
        "X-MS-Oob-TLC-OOBClassifiers": "OLM:2043;",
        "X-MS-Exchange-SenderADCheck": "1",
        "X-MS-Exchange-AntiSpam-Relay": "0",
        "X-Microsoft-Antispam": "BCL:0;",
        "X-Microsoft-Antispam-Message-Info": "\n ucAkYmN4deypUETUkkPteQU6RasIFnvj0nrZEkpPlletkQ2n53wjhfx6Y5UnD9Y3ttmQqjI7xvKKlB/89vy+e3Ht4T20FjlhZFq3pHRgiS1mF90K0+rn1xnMFgxi451EnFGuexbI2gyLn2vRvn0lvrLf/iVxNucspLZJihUf+954d071rHFkU7v/J+tBtPJo3Mu5hc+EH+3c9xbnlHKdYV9oiwSBBUr3RT5xiyTQWYedPMEgCIXkqO1Q02MVQzYeEKQvT4fG//qZzJ6snzWJXND0vsOz3T0+GyqZfV7E/27mT4LqdKhCOF3lLeGh81eBxR0dQS8X1hnJ5UTwDRjoP4YQRFKJLleVk6Od3yT55/gZk+t6TMwGq8u2pB/S6cPSZIDuB2CYRR/yycbCIRXjRLK3VbLCIKgJjyQS4tWkM6nlPyMtND5q0W1MCk9bQiP5PTooSSwIs+iiTWtRHQJ78GVMZbgkIjQqnuqIyzCEuUtlSMh1T+/96oTDRxPpSCjgWB0Ajf5cAPfusM9KWxUeS1SXsIwdTRLn26GxFqxLN8nQ6EigzWe2SxqFYv9mvrxC5cTRfAaisVZyd5GgSuyKuU4sdGVtptKGOhzBxJqhnigFvEuME7J/960utds3Yz0EmGPfnR3v67MYLkJFt9G2R1azvWTToNv275c4HDzPulhyuYWsq+jp9F8KsuwyHrn1kdNX50G8Oxv8GwXSQGgPBA==",
        "X-Forefront-Antispam-Report": "CIP:216.228.112.34; CTRY:US; LANG:en; SCL:1;\n SRV:;\n IPV:NLI; SFV:NSPM; H:mail.nvidia.com; PTR:schybrid03.nvidia.com; CAT:NONE;\n SFS:(4636009)(46966006)(36840700001)(7696005)(36860700001)(336012)(55016002)(86362001)(8936002)(16526019)(186003)(2616005)(2876002)(6916009)(36756003)(82310400003)(26005)(316002)(426003)(30864003)(70586007)(70206006)(508600001)(83380400001)(47076005)(8676002)(7636003)(356005)(1076003)(6286002)(2906002)(4326008)(5660300002);\n DIR:OUT; SFP:1101;",
        "X-OriginatorOrg": "Nvidia.com",
        "X-MS-Exchange-CrossTenant-OriginalArrivalTime": "08 Nov 2021 10:47:05.2373 (UTC)",
        "X-MS-Exchange-CrossTenant-Network-Message-Id": "\n d7f889ca-bb10-4d49-3cad-08d9a2a51ae0",
        "X-MS-Exchange-CrossTenant-Id": "43083d15-7273-40c1-b7db-39efd9ccc17a",
        "X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp": "\n TenantId=43083d15-7273-40c1-b7db-39efd9ccc17a; Ip=[216.228.112.34];\n Helo=[mail.nvidia.com]",
        "X-MS-Exchange-CrossTenant-AuthSource": "\n CO1NAM11FT064.eop-nam11.prod.protection.outlook.com",
        "X-MS-Exchange-CrossTenant-AuthAs": "Anonymous",
        "X-MS-Exchange-CrossTenant-FromEntityHeader": "HybridOnPrem",
        "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "CY4PR12MB1848",
        "Subject": "[dpdk-dev] [PATCH v5 4/9] gpudev: support multi-process",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "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": "From: Thomas Monjalon <thomas@monjalon.net>\n\nThe device data shared between processes are moved in a struct\nallocated in a shared memory (a new memzone for all GPUs).\nThe main struct rte_gpu references the shared memory\nvia the pointer mpshared.\n\nThe API function rte_gpu_attach() is added to attach a device\nfrom the secondary process.\nThe function rte_gpu_allocate() can be used only by primary process.\n\nSigned-off-by: Thomas Monjalon <thomas@monjalon.net>\n---\n lib/gpudev/gpudev.c        | 127 +++++++++++++++++++++++++++++++------\n lib/gpudev/gpudev_driver.h |  25 ++++++--\n lib/gpudev/version.map     |   1 +\n 3 files changed, 127 insertions(+), 26 deletions(-)",
    "diff": "diff --git a/lib/gpudev/gpudev.c b/lib/gpudev/gpudev.c\nindex aaf41e6071..17e371102a 100644\n--- a/lib/gpudev/gpudev.c\n+++ b/lib/gpudev/gpudev.c\n@@ -5,6 +5,7 @@\n #include <rte_eal.h>\n #include <rte_tailq.h>\n #include <rte_string_fns.h>\n+#include <rte_memzone.h>\n #include <rte_errno.h>\n #include <rte_log.h>\n \n@@ -28,6 +29,12 @@ static int16_t gpu_max;\n /* Number of currently valid devices */\n static int16_t gpu_count;\n \n+/* Shared memory between processes. */\n+static const char *GPU_MEMZONE = \"rte_gpu_shared\";\n+static struct {\n+\t__extension__ struct rte_gpu_mpshared gpus[0];\n+} *gpu_shared_mem;\n+\n /* Event callback object */\n struct rte_gpu_callback {\n \tTAILQ_ENTRY(rte_gpu_callback) next;\n@@ -75,7 +82,7 @@ bool\n rte_gpu_is_valid(int16_t dev_id)\n {\n \tif (dev_id >= 0 && dev_id < gpu_max &&\n-\t\tgpus[dev_id].state == RTE_GPU_STATE_INITIALIZED)\n+\t\tgpus[dev_id].process_state == RTE_GPU_STATE_INITIALIZED)\n \t\treturn true;\n \treturn false;\n }\n@@ -85,7 +92,7 @@ gpu_match_parent(int16_t dev_id, int16_t parent)\n {\n \tif (parent == RTE_GPU_ID_ANY)\n \t\treturn true;\n-\treturn gpus[dev_id].info.parent == parent;\n+\treturn gpus[dev_id].mpshared->info.parent == parent;\n }\n \n int16_t\n@@ -94,7 +101,7 @@ rte_gpu_find_next(int16_t dev_id, int16_t parent)\n \tif (dev_id < 0)\n \t\tdev_id = 0;\n \twhile (dev_id < gpu_max &&\n-\t\t\t(gpus[dev_id].state == RTE_GPU_STATE_UNUSED ||\n+\t\t\t(gpus[dev_id].process_state == RTE_GPU_STATE_UNUSED ||\n \t\t\t!gpu_match_parent(dev_id, parent)))\n \t\tdev_id++;\n \n@@ -109,7 +116,7 @@ gpu_find_free_id(void)\n \tint16_t dev_id;\n \n \tfor (dev_id = 0; dev_id < gpu_max; dev_id++) {\n-\t\tif (gpus[dev_id].state == RTE_GPU_STATE_UNUSED)\n+\t\tif (gpus[dev_id].process_state == RTE_GPU_STATE_UNUSED)\n \t\t\treturn dev_id;\n \t}\n \treturn RTE_GPU_ID_NONE;\n@@ -136,12 +143,35 @@ rte_gpu_get_by_name(const char *name)\n \n \tRTE_GPU_FOREACH(dev_id) {\n \t\tdev = &gpus[dev_id];\n-\t\tif (strncmp(name, dev->name, RTE_DEV_NAME_MAX_LEN) == 0)\n+\t\tif (strncmp(name, dev->mpshared->name, RTE_DEV_NAME_MAX_LEN) == 0)\n \t\t\treturn dev;\n \t}\n \treturn NULL;\n }\n \n+static int\n+gpu_shared_mem_init(void)\n+{\n+\tconst struct rte_memzone *memzone;\n+\n+\tif (rte_eal_process_type() == RTE_PROC_PRIMARY) {\n+\t\tmemzone = rte_memzone_reserve(GPU_MEMZONE,\n+\t\t\t\tsizeof(*gpu_shared_mem) +\n+\t\t\t\tsizeof(*gpu_shared_mem->gpus) * gpu_max,\n+\t\t\t\tSOCKET_ID_ANY, 0);\n+\t} else {\n+\t\tmemzone = rte_memzone_lookup(GPU_MEMZONE);\n+\t}\n+\tif (memzone == NULL) {\n+\t\tGPU_LOG(ERR, \"cannot initialize shared memory\");\n+\t\trte_errno = ENOMEM;\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tgpu_shared_mem = memzone->addr;\n+\treturn 0;\n+}\n+\n struct rte_gpu *\n rte_gpu_allocate(const char *name)\n {\n@@ -163,6 +193,10 @@ rte_gpu_allocate(const char *name)\n \tif (gpus == NULL && rte_gpu_init(RTE_GPU_DEFAULT_MAX) < 0)\n \t\treturn NULL;\n \n+\t/* initialize shared memory before adding first device */\n+\tif (gpu_shared_mem == NULL && gpu_shared_mem_init() < 0)\n+\t\treturn NULL;\n+\n \tif (rte_gpu_get_by_name(name) != NULL) {\n \t\tGPU_LOG(ERR, \"device with name %s already exists\", name);\n \t\trte_errno = EEXIST;\n@@ -178,16 +212,20 @@ rte_gpu_allocate(const char *name)\n \tdev = &gpus[dev_id];\n \tmemset(dev, 0, sizeof(*dev));\n \n-\tif (rte_strscpy(dev->name, name, RTE_DEV_NAME_MAX_LEN) < 0) {\n+\tdev->mpshared = &gpu_shared_mem->gpus[dev_id];\n+\tmemset(dev->mpshared, 0, sizeof(*dev->mpshared));\n+\n+\tif (rte_strscpy(dev->mpshared->name, name, RTE_DEV_NAME_MAX_LEN) < 0) {\n \t\tGPU_LOG(ERR, \"device name too long: %s\", name);\n \t\trte_errno = ENAMETOOLONG;\n \t\treturn NULL;\n \t}\n-\tdev->info.name = dev->name;\n-\tdev->info.dev_id = dev_id;\n-\tdev->info.numa_node = -1;\n-\tdev->info.parent = RTE_GPU_ID_NONE;\n+\tdev->mpshared->info.name = dev->mpshared->name;\n+\tdev->mpshared->info.dev_id = dev_id;\n+\tdev->mpshared->info.numa_node = -1;\n+\tdev->mpshared->info.parent = RTE_GPU_ID_NONE;\n \tTAILQ_INIT(&dev->callbacks);\n+\t__atomic_fetch_add(&dev->mpshared->process_refcnt, 1, __ATOMIC_RELAXED);\n \n \tgpu_count++;\n \tGPU_LOG(DEBUG, \"new device %s (id %d) of total %d\",\n@@ -195,6 +233,55 @@ rte_gpu_allocate(const char *name)\n \treturn dev;\n }\n \n+struct rte_gpu *\n+rte_gpu_attach(const char *name)\n+{\n+\tint16_t dev_id;\n+\tstruct rte_gpu *dev;\n+\tstruct rte_gpu_mpshared *shared_dev;\n+\n+\tif (rte_eal_process_type() != RTE_PROC_SECONDARY) {\n+\t\tGPU_LOG(ERR, \"only secondary process can attach device\");\n+\t\trte_errno = EPERM;\n+\t\treturn NULL;\n+\t}\n+\tif (name == NULL) {\n+\t\tGPU_LOG(ERR, \"attach device without a name\");\n+\t\trte_errno = EINVAL;\n+\t\treturn NULL;\n+\t}\n+\n+\t/* implicit initialization of library before adding first device */\n+\tif (gpus == NULL && rte_gpu_init(RTE_GPU_DEFAULT_MAX) < 0)\n+\t\treturn NULL;\n+\n+\t/* initialize shared memory before adding first device */\n+\tif (gpu_shared_mem == NULL && gpu_shared_mem_init() < 0)\n+\t\treturn NULL;\n+\n+\tfor (dev_id = 0; dev_id < gpu_max; dev_id++) {\n+\t\tshared_dev = &gpu_shared_mem->gpus[dev_id];\n+\t\tif (strncmp(name, shared_dev->name, RTE_DEV_NAME_MAX_LEN) == 0)\n+\t\t\tbreak;\n+\t}\n+\tif (dev_id >= gpu_max) {\n+\t\tGPU_LOG(ERR, \"device with name %s not found\", name);\n+\t\trte_errno = ENOENT;\n+\t\treturn NULL;\n+\t}\n+\tdev = &gpus[dev_id];\n+\tmemset(dev, 0, sizeof(*dev));\n+\n+\tTAILQ_INIT(&dev->callbacks);\n+\tdev->mpshared = shared_dev;\n+\t__atomic_fetch_add(&dev->mpshared->process_refcnt, 1, __ATOMIC_RELAXED);\n+\n+\tgpu_count++;\n+\tGPU_LOG(DEBUG, \"attached device %s (id %d) of total %d\",\n+\t\t\tname, dev_id, gpu_count);\n+\treturn dev;\n+}\n+\n int16_t\n rte_gpu_add_child(const char *name, int16_t parent, uint64_t child_context)\n {\n@@ -210,11 +297,11 @@ rte_gpu_add_child(const char *name, int16_t parent, uint64_t child_context)\n \tif (dev == NULL)\n \t\treturn -rte_errno;\n \n-\tdev->info.parent = parent;\n-\tdev->info.context = child_context;\n+\tdev->mpshared->info.parent = parent;\n+\tdev->mpshared->info.context = child_context;\n \n \trte_gpu_complete_new(dev);\n-\treturn dev->info.dev_id;\n+\treturn dev->mpshared->info.dev_id;\n }\n \n void\n@@ -223,8 +310,7 @@ rte_gpu_complete_new(struct rte_gpu *dev)\n \tif (dev == NULL)\n \t\treturn;\n \n-\tdev->state = RTE_GPU_STATE_INITIALIZED;\n-\tdev->state = RTE_GPU_STATE_INITIALIZED;\n+\tdev->process_state = RTE_GPU_STATE_INITIALIZED;\n \trte_gpu_notify(dev, RTE_GPU_EVENT_NEW);\n }\n \n@@ -237,7 +323,7 @@ rte_gpu_release(struct rte_gpu *dev)\n \t\trte_errno = ENODEV;\n \t\treturn -rte_errno;\n \t}\n-\tdev_id = dev->info.dev_id;\n+\tdev_id = dev->mpshared->info.dev_id;\n \tRTE_GPU_FOREACH_CHILD(child, dev_id) {\n \t\tGPU_LOG(ERR, \"cannot release device %d with child %d\",\n \t\t\t\tdev_id, child);\n@@ -246,11 +332,12 @@ rte_gpu_release(struct rte_gpu *dev)\n \t}\n \n \tGPU_LOG(DEBUG, \"free device %s (id %d)\",\n-\t\t\tdev->info.name, dev->info.dev_id);\n+\t\t\tdev->mpshared->info.name, dev->mpshared->info.dev_id);\n \trte_gpu_notify(dev, RTE_GPU_EVENT_DEL);\n \n \tgpu_free_callbacks(dev);\n-\tdev->state = RTE_GPU_STATE_UNUSED;\n+\tdev->process_state = RTE_GPU_STATE_UNUSED;\n+\t__atomic_fetch_sub(&dev->mpshared->process_refcnt, 1, __ATOMIC_RELAXED);\n \tgpu_count--;\n \n \treturn 0;\n@@ -403,7 +490,7 @@ rte_gpu_notify(struct rte_gpu *dev, enum rte_gpu_event event)\n \tint16_t dev_id;\n \tstruct rte_gpu_callback *callback;\n \n-\tdev_id = dev->info.dev_id;\n+\tdev_id = dev->mpshared->info.dev_id;\n \trte_rwlock_read_lock(&gpu_callback_lock);\n \tTAILQ_FOREACH(callback, &dev->callbacks, next) {\n \t\tif (callback->event != event || callback->function == NULL)\n@@ -431,7 +518,7 @@ rte_gpu_info_get(int16_t dev_id, struct rte_gpu_info *info)\n \t}\n \n \tif (dev->ops.dev_info_get == NULL) {\n-\t\t*info = dev->info;\n+\t\t*info = dev->mpshared->info;\n \t\treturn 0;\n \t}\n \treturn GPU_DRV_RET(dev->ops.dev_info_get(dev, info));\ndiff --git a/lib/gpudev/gpudev_driver.h b/lib/gpudev/gpudev_driver.h\nindex 4d0077161c..9459c7e30f 100644\n--- a/lib/gpudev/gpudev_driver.h\n+++ b/lib/gpudev/gpudev_driver.h\n@@ -35,19 +35,28 @@ struct rte_gpu_ops {\n \trte_gpu_close_t *dev_close;\n };\n \n-struct rte_gpu {\n-\t/* Backing device. */\n-\tstruct rte_device *device;\n+struct rte_gpu_mpshared {\n \t/* Unique identifier name. */\n \tchar name[RTE_DEV_NAME_MAX_LEN]; /* Updated by this library. */\n+\t/* Driver-specific private data shared in multi-process. */\n+\tvoid *dev_private;\n \t/* Device info structure. */\n \tstruct rte_gpu_info info;\n+\t/* Counter of processes using the device. */\n+\tuint16_t process_refcnt; /* Updated by this library. */\n+};\n+\n+struct rte_gpu {\n+\t/* Backing device. */\n+\tstruct rte_device *device;\n+\t/* Data shared between processes. */\n+\tstruct rte_gpu_mpshared *mpshared;\n \t/* Driver functions. */\n \tstruct rte_gpu_ops ops;\n \t/* Event callback list. */\n \tTAILQ_HEAD(rte_gpu_callback_list, rte_gpu_callback) callbacks;\n \t/* Current state (used or not) in the running process. */\n-\tenum rte_gpu_state state; /* Updated by this library. */\n+\tenum rte_gpu_state process_state; /* Updated by this library. */\n \t/* Driver-specific private data for the running process. */\n \tvoid *process_private;\n } __rte_cache_aligned;\n@@ -55,15 +64,19 @@ struct rte_gpu {\n __rte_internal\n struct rte_gpu *rte_gpu_get_by_name(const char *name);\n \n-/* First step of initialization */\n+/* First step of initialization in primary process. */\n __rte_internal\n struct rte_gpu *rte_gpu_allocate(const char *name);\n \n+/* First step of initialization in secondary process. */\n+__rte_internal\n+struct rte_gpu *rte_gpu_attach(const char *name);\n+\n /* Last step of initialization. */\n __rte_internal\n void rte_gpu_complete_new(struct rte_gpu *dev);\n \n-/* Last step of removal. */\n+/* Last step of removal (primary or secondary process). */\n __rte_internal\n int rte_gpu_release(struct rte_gpu *dev);\n \ndiff --git a/lib/gpudev/version.map b/lib/gpudev/version.map\nindex 4a934ed933..58dc632393 100644\n--- a/lib/gpudev/version.map\n+++ b/lib/gpudev/version.map\n@@ -17,6 +17,7 @@ INTERNAL {\n \tglobal:\n \n \trte_gpu_allocate;\n+\trte_gpu_attach;\n \trte_gpu_complete_new;\n \trte_gpu_get_by_name;\n \trte_gpu_notify;\n",
    "prefixes": [
        "v5",
        "4/9"
    ]
}