get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 35141,
    "url": "http://patches.dpdk.org/api/patches/35141/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1518468702-16719-4-git-send-email-matan@mellanox.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": "<1518468702-16719-4-git-send-email-matan@mellanox.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1518468702-16719-4-git-send-email-matan@mellanox.com",
    "date": "2018-02-12T20:51:42",
    "name": "[dpdk-dev,v7,3/3] net/failsafe: fix hotplug races",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "602925efd1fd9b1a6ab097dc443a1d5df145e6d8",
    "submitter": {
        "id": 796,
        "url": "http://patches.dpdk.org/api/people/796/?format=api",
        "name": "Matan Azrad",
        "email": "matan@mellanox.com"
    },
    "delegate": null,
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/1518468702-16719-4-git-send-email-matan@mellanox.com/mbox/",
    "series": [],
    "comments": "http://patches.dpdk.org/api/patches/35141/comments/",
    "check": "fail",
    "checks": "http://patches.dpdk.org/api/patches/35141/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 BE0971B3DB;\n\tMon, 12 Feb 2018 21:52:09 +0100 (CET)",
            "from EUR01-VE1-obe.outbound.protection.outlook.com\n\t(mail-ve1eur01on0042.outbound.protection.outlook.com [104.47.1.42])\n\tby dpdk.org (Postfix) with ESMTP id 988FF1B3C2;\n\tMon, 12 Feb 2018 21:52:05 +0100 (CET)",
            "from mellanox.com (37.142.13.130) by\n\tDB6PR0501MB2664.eurprd05.prod.outlook.com (2603:10a6:4:80::22) with\n\tMicrosoft SMTP Server (version=TLS1_2,\n\tcipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.20.485.10;\n\tMon, 12 Feb 2018 20:52:02 +0000"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=Mellanox.com;\n\ts=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version;\n\tbh=LEuzDLBn/bvMpiW7T3Tvab8pyh+ZH4xE8v5kZO1QeK8=;\n\tb=PP9vE7pK2CeM25qdk0kFULyKAAxd7mmTqlYW0JxV2vRKAu1BZuj/hGj2xKKCIqqjJMDNwVM69LyyFkYedoGHsyIUA4fLad4oUNRvTX8DeVE6pZIkuLPAGTfLhy01hJxLdQMhec7Fh7vDONx7R7eBIdqf3w8D9/aNrDJYQE4zOYw=",
        "Authentication-Results": "spf=none (sender IP is )\n\tsmtp.mailfrom=matan@mellanox.com; ",
        "From": "Matan Azrad <matan@mellanox.com>",
        "To": "Gaetan Rivet <gaetan.rivet@6wind.com>",
        "Cc": "dev@dpdk.org,\n\tstable@dpdk.org",
        "Date": "Mon, 12 Feb 2018 20:51:42 +0000",
        "Message-Id": "<1518468702-16719-4-git-send-email-matan@mellanox.com>",
        "X-Mailer": "git-send-email 1.9.5",
        "In-Reply-To": "<1518468702-16719-1-git-send-email-matan@mellanox.com>",
        "References": "<1518369872-12324-1-git-send-email-matan@mellanox.com>\n\t<1518468702-16719-1-git-send-email-matan@mellanox.com>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain",
        "X-Originating-IP": "[37.142.13.130]",
        "X-ClientProxiedBy": "HE1P191CA0004.EURP191.PROD.OUTLOOK.COM\n\t(2603:10a6:3:cf::14)\n\tTo DB6PR0501MB2664.eurprd05.prod.outlook.com\n\t(2603:10a6:4:80::22)",
        "X-MS-PublicTrafficType": "Email",
        "X-MS-Office365-Filtering-HT": "Tenant",
        "X-MS-Office365-Filtering-Correlation-Id": "a86978a3-d231-4985-8cb6-08d5725a7888",
        "X-Microsoft-Antispam": "UriScan:; BCL:0; PCL:0;\n\tRULEID:(7020095)(4652020)(48565401081)(4534165)(4627221)(201703031133081)(201702281549075)(5600026)(4604075)(2017052603307)(7153060)(7193020);\n\tSRVR:DB6PR0501MB2664; ",
        "X-Microsoft-Exchange-Diagnostics": [
            "1; DB6PR0501MB2664;\n\t3:h9vgNdwy5tT7IT+1uT1i2oo1wVHh40C4Xv+Nt+Uil5d7hFiGjuS30wW7QlX8cM3HdH+coJNdvKtl3cJHQAUYhPBeGCxYX0/jaxijheo5kKPhuPLlQ89747+4+/oMvNxx3y4OLtFLfYIo/lSdID0FPOV219rzLKiRbchX06+t07cPgqHg38rxlqCBFR4hHd8awpoAgdcOf6fck5HPTOAq8MWe+Kcp4Wf5tG1mLWoHuLG9m3gVsEk3jFoD+lbJ+y+e;\n\t25:k6aIwsugWd3oTf70lXtGdg/oACmDXDbxJJDZDxHbLMNfv7TewAF7Q8vN19NVS7M8B0K3vFbqcVLbJoGnXsPm/mjYI/9sepDJzGdneetWSH//k5VapMRYqd+Ez0dyvWR3wznTwRdDP87bjBRrMHIfZFs6k1xBRyISLYxGD3g16PpHKXIjGxHur/7c14x7rwxfINmq3/rI+vsVoQIoa36jRM1wl7S9rlzTb/+iRbL87jgroTJ9krBaleHmEwfY9/3Ag/O3lO8k9dBPsqAY4xlQREbmsCf1lrP0BnwgP3oEW/8ow0ibXS8WgkZ7ULk4HD53+bCGM8Zdx3GN65TMEA0Izg==;\n\t31:yBsXX5d/VOVieD0ASCtP+fiaWaNRCW//C14MFBqeGYS5MX8F3BTlmvivPZ/mts54GA1rlVA1INAzjvbsv+GcFH9SYtzPaGrq1KsEHtbK54Hu2XtLy9RNKpVTS0bNcNsbLqj9ibsO9/J/eSu9UGJK6cP61Ue3AJNvFdvdubpfkSf5VuepicDzyUUDa2q7gF8/XAdv8VzrXQlOCMMkG7WK8AmYjjF1SGU6yZZl39Cewms=",
            "1; DB6PR0501MB2664;\n\t20:7e0JfMCgfbswxdg4AaD6dz+4g8uTV7oFq25rB0Ll1bHgAmdslq+YQjnN/GA92zLG1nWZR28Op3Fog1vuvUF/qFgpj3dSxJx9Yl8QeYSHFDOBs9CC/dLJHXKaHy6dr2vwErzzedT/0whQW5qe8GPc4gzE4I/5YvcLP2rEl5m5XYEzLlIwSEGtm5JJbSMZxKKwD+7yrebDjYHH33Fak/F9CHCDPIGm+qKh/bsPVHa73g+JVltPosVW+/3czeXy1fKRGUoBZaE4ZHomJIvuh9COFfUk4vNlcyP3F3Mzz1BK9zQTs+kMHWulFJdQU5vaWNa5irAABS/7b3u6VR4eXo/XMI1Uc2wyIgEE6m3BE4pXK6oOcf6Ap6yWw3iHdCjtnUEdIDWwZRvZTTlEW5uH0v4no76ueAFZ35z+TDI6kjInqxPLTECnKitxK6Vfs5z7DCQvNQdE/98yrZjwTFMoK3dM8oKpiNBq2TOe+vaSTiUHrW8LeEccWdEQtvzRB1HofO1W;\n\t4:P9SnT2vmtIVoyxVPW7eSDCDZirQgqdPjnEKBuHX2H8QiAxxXgp+QBOE+xRX2Q8fCTu+bjyjrt1ndImHgK9UKbs7y8tyM+rtxZhlIWJ2G3qO6LD/CXLFE7y3VHvhU11GWEPtQd+4m8/B8jtkoj/SIiIZ/cPQdXJsJ5pqJpr9SIfohaND6rSBfGWK5/IFT+V9ddp3rYXdHRX6HNz/MKKnV0AcfztCl9kpuagExUJYhFZBLOqieQCA6boB/fvUBDPrxAX1bq9S1sglcBwxtrKemjSO8ePLf/5qtrl1c/fmoeNJD+ucZU+HxtCJCtH+H25Sm",
            "=?us-ascii?Q?1; DB6PR0501MB2664;\n\t23:FJTKh5IosHeAlHwmbkc+FufTJUVbaC0bVg2W7tO?=\n\tyTL8Me1av9HF/SMXZnynmRsKcBUAtkJInbEODYZv79WXM/r2WIbw6NSeYQ7Z+2OOqja+PZno4BKsTH25cnT6G9ZOfhthDXfmaiddmNMSJqxGKEV7bqN88d6ba557BrowzPMmGPOH0MFckuhEZVKBDMO82I9WkXzayeX3pIHlWUiJa0POrKxjYDXja9TNV3Oww6kE+5av/eamHhSjEcTQNhUNMA3Htsmd7sRzM3rQ2U05ZGBZK0Bral3XqVUNjC5rz02OFzdsVsUjzbEWHOVDl/wEgkhQ5CqxpDrxlB3rRqMXzGA+d4xthojvZPzLjEeOjcHdNGL/k2oYjjB+cTHkeA4BO3KuPWB/XcPTbjOh4R14tgH7uec8IR6d2wx1iT3NeoxKMjE50Uy9kc8SbOl4RTH2FRDJl7bGkPM7cDVn++CMKkfhcGXOkcqHrv14z1CNEZX1sw7o7oRvIv5MfjgNPCiLY6NEaIR43llWOPuyoa7Lf+Y5AiN6/RnsvMLiUiDi7kLEPWgsinA2YpcowXkwZ7dltYn+FfmxQ1+EoQngRR4zwhJysaVolCKnIwCHUe7zXo9NHJsXOitw5AuLnxldBjl5cOn2eS3KOKrATLIFFdk58O4wwufWcoagd8KUY9+kVZ0NYT4N1U2eID4dplxKiMoPmYZ3nlnGqwMyFa9vo213Czs2yzOoYMg2P+Cnv0S30rw6BSSkLiAQs7Nk3gGbESGpRgerR+AEIU2OGyMyiWj6B23h3YV8h7hHK/vRGcXt4SUEP4v7B8jzvGzq/M/QH3as7/c8QJfBEHMci93P4olCZUSU7jytoynx0xGuGu6Zy7qdbmgB2iLCXsVcgprS9mPfkxlNIje5LAURsMBsoed/vsXys0aSzSUMqhngBVD8+6gngUpOXLKJcW5fzkrbFLSBYwupPdJ2y3+Ik1Eltg6tvl4qwc/E9rO4bw5uVHRgm+ySJtz6lC6ng5mLdc0LeK4RDS1rJucCBHHld0t9hZJhxbsomUIpq+vuwvx9aPfkbuUBF5PtKVIVB/LgVUKkV/8YpNmENdTsMJdqztVPUGp60pYY/AlniSsyi68tVmBLhrc0w17lfC96TJXGke5ATGfotk/DhZr/amlT7sosEyjUCdRX27oo8fujeaXGrnlordcxZ0r45XgP6yeVTemMQyLhv",
            "1; DB6PR0501MB2664;\n\t6:KkZbuDVedKqOE1kU6s2I+kZDtL6nMEpgwz6K8KoiSt/O11JVpUiAZlNODYPSEedgxXQR2h/b3gANWY8sr0Meu+izkTMEOWe2boBXcqgS4wYfxaUlyaj1ckOulxqI6k2TxJPhLvlRSTxgiKP7imJzd6PsFpTOO+XZWKXhVuLzA8Vpg4QGZVtD+qce8immhTBgGY6BErwgAxEcKzHJ9PwK2H+bQcgbbcOd4FVo2YEYfCzl1hgSIKIHQp0GXUMezqH0u0qNTio7LY4JZk6kayT18dwNm/xoQ4NhLz9Ta5cFzH8oaC3V/W+GNQrHAD37DWlOV0L1zFyQo3Qm7Y2e0kDnf5LYAoSdP7SONgzAxJxaH/Q=;\n\t5:SHSmqRbvb4SgjIE4L9uu7pA4nKNvozcKB09dTphQtc7Nab3H1RoRq+sKl1ila1660DexeGpGJXhKRfos0NiwOqd2dK3E3n62eYbpRW9k4vGB3VhBrAliDr4G/qN4XzIr03atbIzePVJZhX0mIWngwP2m59kUUmP2EF7CogBeFwM=;\n\t24:I01zmEiCSsK9cz7aDx/FS9aKy9Z5gXxxPabs2fWON2E65XTQgsAx4FF1kBtwxHLZT/5HIxc1JaGkxLzzwxo9W+8rdXcuLS15qVHwYx8s35U=;\n\t7:ISBe2hr0X+95dZjY6cGCDiCZWiFkq/5lRxnJpcEgiz9uQjDxtsVLYFXt9zw8UzLmuhbTVxp+bzzSCEXhl7LJt33U5/4QIX2tSMCjcI9Du0EMK6aumsKe7kQR6/I0uc/UaTXkg6g4MUF2814CxNqTC4O1QxlwOLmtXhfCTjq+VibsYepabncJ3Tv7TYNhZn8gwNn2ggV2deGgcwGW5rLxx29+QTx9SU/p9PT+K7hlK458hL7jTSzsKNp9COGoC7EQ"
        ],
        "X-MS-TrafficTypeDiagnostic": "DB6PR0501MB2664:",
        "X-Microsoft-Antispam-PRVS": "<DB6PR0501MB26648FB7E1CFA72EA1D0FAA4D2F70@DB6PR0501MB2664.eurprd05.prod.outlook.com>",
        "X-Exchange-Antispam-Report-Test": "UriScan:(60795455431006);",
        "X-Exchange-Antispam-Report-CFA-Test": "BCL:0; PCL:0;\n\tRULEID:(6040501)(2401047)(5005006)(8121501046)(10201501046)(93006095)(93001095)(3002001)(3231101)(944501161)(6055026)(6041288)(20161123564045)(20161123560045)(20161123558120)(20161123562045)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(6072148)(201708071742011);\n\tSRVR:DB6PR0501MB2664; BCL:0; PCL:0; RULEID:; SRVR:DB6PR0501MB2664; ",
        "X-Forefront-PRVS": "0581B5AB35",
        "X-Forefront-Antispam-Report": "SFV:NSPM;\n\tSFS:(10009020)(346002)(39860400002)(396003)(39380400002)(366004)(376002)(189003)(199004)(478600001)(8936002)(6666003)(81166006)(81156014)(50226002)(76176011)(68736007)(6916009)(69596002)(8676002)(2950100002)(305945005)(7736002)(33026002)(316002)(36756003)(21086003)(16586007)(48376002)(105586002)(26005)(55016002)(25786009)(4326008)(186003)(53936002)(97736004)(66066001)(16526019)(106356001)(47776003)(52116002)(51416003)(5660300001)(59450400001)(7696005)(2906002)(386003)(575784001)(86362001)(6116002)(50466002)(3846002);\n\tDIR:OUT; SFP:1101; SCL:1; SRVR:DB6PR0501MB2664; H:mellanox.com; FPR:;\n\tSPF:None; \n\tPTR:InfoNoRecords; MX:1; A:1; LANG:en; ",
        "Received-SPF": "None (protection.outlook.com: mellanox.com does not designate\n\tpermitted sender hosts)",
        "SpamDiagnosticOutput": "1:99",
        "SpamDiagnosticMetadata": "NSPM",
        "X-OriginatorOrg": "Mellanox.com",
        "X-MS-Exchange-CrossTenant-OriginalArrivalTime": "12 Feb 2018 20:52:02.6693\n\t(UTC)",
        "X-MS-Exchange-CrossTenant-Network-Message-Id": "a86978a3-d231-4985-8cb6-08d5725a7888",
        "X-MS-Exchange-CrossTenant-FromEntityHeader": "Hosted",
        "X-MS-Exchange-CrossTenant-Id": "a652971c-7d2e-4d9b-a6a4-d149256f461b",
        "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "DB6PR0501MB2664",
        "Subject": "[dpdk-dev] [PATCH v7 3/3] net/failsafe: fix hotplug races",
        "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://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Fail-safe uses a periodic alarm mechanism, running from the host\nthread, to manage the hot-plug events of its sub-devices. This\nmanagement requires a lot of sub-devices PMDs operations\n(stop, close, start, configure, etc.).\n\nWhile the hot-plug alarm runs in the host thread, the application may\ncall fail-safe operations, which directly trigger the sub-devices PMDs\noperations as well. This call may occur from any thread decided by the\napplication (probably the master thread).\n\nThus, more than one operation can be executed to a sub-device at the\nsame time. This can initiate a lot of races in the sub-PMDs.\n\nMoreover, some control operations update the fail-safe internal\ndatabases, which can be used by the alarm mechanism at the same time.\nThis can also initiate races and crashes.\n\nFail-safe is the owner of its sub-devices and must synchronize their\nuse according to the ETHDEV ownership rules.\n\nSynchronize hot-plug management by a new lock mechanism uses a mutex to\natomically defend each critical section in the fail-safe hot-plug\nmechanism and control operations to prevent any races between them.\n\nFixes: a46f8d5 (\"net/failsafe: add fail-safe PMD\")\nCc: stable@dpdk.org\n\nSigned-off-by: Matan Azrad <matan@mellanox.com>\n---\n drivers/net/failsafe/Makefile           |   1 +\n drivers/net/failsafe/failsafe.c         |  35 ++++++++\n drivers/net/failsafe/failsafe_ether.c   |   5 ++\n drivers/net/failsafe/failsafe_flow.c    |  20 ++++-\n drivers/net/failsafe/failsafe_ops.c     | 148 ++++++++++++++++++++++++++------\n drivers/net/failsafe/failsafe_private.h |  56 ++++++++++++\n 6 files changed, 239 insertions(+), 26 deletions(-)",
    "diff": "diff --git a/drivers/net/failsafe/Makefile b/drivers/net/failsafe/Makefile\nindex d1ae899..bd2f019 100644\n--- a/drivers/net/failsafe/Makefile\n+++ b/drivers/net/failsafe/Makefile\n@@ -68,5 +68,6 @@ CFLAGS += -pedantic\n LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring\n LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs\n LDLIBS += -lrte_bus_vdev\n+LDLIBS += -lpthread\n \n include $(RTE_SDK)/mk/rte.lib.mk\ndiff --git a/drivers/net/failsafe/failsafe.c b/drivers/net/failsafe/failsafe.c\nindex 7b2cdbb..c499bfb 100644\n--- a/drivers/net/failsafe/failsafe.c\n+++ b/drivers/net/failsafe/failsafe.c\n@@ -113,17 +113,46 @@ fs_hotplug_alarm(void *arg)\n \t\t\tbreak;\n \t/* if we have non-probed device */\n \tif (i != PRIV(dev)->subs_tail) {\n+\t\tif (fs_lock(dev, 1) != 0)\n+\t\t\tgoto reinstall;\n \t\tret = failsafe_eth_dev_state_sync(dev);\n+\t\tfs_unlock(dev, 1);\n \t\tif (ret)\n \t\t\tERROR(\"Unable to synchronize sub_device state\");\n \t}\n \tfailsafe_dev_remove(dev);\n+reinstall:\n \tret = failsafe_hotplug_alarm_install(dev);\n \tif (ret)\n \t\tERROR(\"Unable to set up next alarm\");\n }\n \n static int\n+fs_mutex_init(struct fs_priv *priv)\n+{\n+\tint ret;\n+\tpthread_mutexattr_t attr;\n+\n+\tret = pthread_mutexattr_init(&attr);\n+\tif (ret) {\n+\t\tERROR(\"Cannot initiate mutex attributes - %s\", strerror(ret));\n+\t\treturn ret;\n+\t}\n+\t/* Allow mutex relocks for the thread holding the mutex. */\n+\tret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);\n+\tif (ret) {\n+\t\tERROR(\"Cannot set mutex type - %s\", strerror(ret));\n+\t\treturn ret;\n+\t}\n+\tret = pthread_mutex_init(&priv->hotplug_mutex, &attr);\n+\tif (ret) {\n+\t\tERROR(\"Cannot initiate mutex - %s\", strerror(ret));\n+\t\treturn ret;\n+\t}\n+\treturn 0;\n+}\n+\n+static int\n fs_eth_dev_create(struct rte_vdev_device *vdev)\n {\n \tstruct rte_eth_dev *dev;\n@@ -176,6 +205,9 @@ fs_eth_dev_create(struct rte_vdev_device *vdev)\n \tret = failsafe_eal_init(dev);\n \tif (ret)\n \t\tgoto free_args;\n+\tret = fs_mutex_init(priv);\n+\tif (ret)\n+\t\tgoto free_args;\n \tret = failsafe_hotplug_alarm_install(dev);\n \tif (ret) {\n \t\tERROR(\"Could not set up plug-in event detection\");\n@@ -250,6 +282,9 @@ fs_rte_eth_free(const char *name)\n \t\tERROR(\"Error while uninitializing sub-EAL\");\n \tfailsafe_args_free(dev);\n \tfs_sub_device_free(dev);\n+\tret = pthread_mutex_destroy(&PRIV(dev)->hotplug_mutex);\n+\tif (ret)\n+\t\tERROR(\"Error while destroying hotplug mutex\");\n \trte_free(PRIV(dev));\n \trte_eth_dev_release_port(dev);\n \treturn ret;\ndiff --git a/drivers/net/failsafe/failsafe_ether.c b/drivers/net/failsafe/failsafe_ether.c\nindex d820faf..2c0bf93 100644\n--- a/drivers/net/failsafe/failsafe_ether.c\n+++ b/drivers/net/failsafe/failsafe_ether.c\n@@ -328,8 +328,11 @@ failsafe_dev_remove(struct rte_eth_dev *dev)\n \n \tFOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE)\n \t\tif (sdev->remove && fs_rxtx_clean(sdev)) {\n+\t\t\tif (fs_lock(dev, 1) != 0)\n+\t\t\t\treturn;\n \t\t\tfs_dev_stats_save(sdev);\n \t\t\tfs_dev_remove(sdev);\n+\t\t\tfs_unlock(dev, 1);\n \t\t}\n }\n \n@@ -429,6 +432,7 @@ failsafe_eth_rmv_event_callback(uint16_t port_id __rte_unused,\n {\n \tstruct sub_device *sdev = cb_arg;\n \n+\tfs_lock(sdev->fs_dev, 0);\n \t/* Switch as soon as possible tx_dev. */\n \tfs_switch_dev(sdev->fs_dev, sdev);\n \t/* Use safe bursts in any case. */\n@@ -438,6 +442,7 @@ failsafe_eth_rmv_event_callback(uint16_t port_id __rte_unused,\n \t * the callback at the source of the current thread context.\n \t */\n \tsdev->remove = 1;\n+\tfs_unlock(sdev->fs_dev, 0);\n \treturn 0;\n }\n \ndiff --git a/drivers/net/failsafe/failsafe_flow.c b/drivers/net/failsafe/failsafe_flow.c\nindex 4d18e8e..ec8c909 100644\n--- a/drivers/net/failsafe/failsafe_flow.c\n+++ b/drivers/net/failsafe/failsafe_flow.c\n@@ -55,6 +55,7 @@ fs_flow_validate(struct rte_eth_dev *dev,\n \tuint8_t i;\n \tint ret;\n \n+\tfs_lock(dev, 0);\n \tFOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {\n \t\tDEBUG(\"Calling rte_flow_validate on sub_device %d\", i);\n \t\tret = rte_flow_validate(PORT_ID(sdev),\n@@ -62,9 +63,11 @@ fs_flow_validate(struct rte_eth_dev *dev,\n \t\tif ((ret = fs_err(sdev, ret))) {\n \t\t\tERROR(\"Operation rte_flow_validate failed for sub_device %d\"\n \t\t\t      \" with error %d\", i, ret);\n+\t\t\tfs_unlock(dev, 0);\n \t\t\treturn ret;\n \t\t}\n \t}\n+\tfs_unlock(dev, 0);\n \treturn 0;\n }\n \n@@ -79,6 +82,7 @@ fs_flow_create(struct rte_eth_dev *dev,\n \tstruct rte_flow *flow;\n \tuint8_t i;\n \n+\tfs_lock(dev, 0);\n \tflow = fs_flow_allocate(attr, patterns, actions);\n \tFOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {\n \t\tflow->flows[i] = rte_flow_create(PORT_ID(sdev),\n@@ -90,6 +94,7 @@ fs_flow_create(struct rte_eth_dev *dev,\n \t\t}\n \t}\n \tTAILQ_INSERT_TAIL(&PRIV(dev)->flow_list, flow, next);\n+\tfs_unlock(dev, 0);\n \treturn flow;\n err:\n \tFOREACH_SUBDEV(sdev, i, dev) {\n@@ -98,6 +103,7 @@ err:\n \t\t\t\tflow->flows[i], error);\n \t}\n \tfs_flow_release(&flow);\n+\tfs_unlock(dev, 0);\n \treturn NULL;\n }\n \n@@ -115,6 +121,7 @@ fs_flow_destroy(struct rte_eth_dev *dev,\n \t\treturn -EINVAL;\n \t}\n \tret = 0;\n+\tfs_lock(dev, 0);\n \tFOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {\n \t\tint local_ret;\n \n@@ -131,6 +138,7 @@ fs_flow_destroy(struct rte_eth_dev *dev,\n \t}\n \tTAILQ_REMOVE(&PRIV(dev)->flow_list, flow, next);\n \tfs_flow_release(&flow);\n+\tfs_unlock(dev, 0);\n \treturn ret;\n }\n \n@@ -144,12 +152,14 @@ fs_flow_flush(struct rte_eth_dev *dev,\n \tuint8_t i;\n \tint ret;\n \n+\tfs_lock(dev, 0);\n \tFOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {\n \t\tDEBUG(\"Calling rte_flow_flush on sub_device %d\", i);\n \t\tret = rte_flow_flush(PORT_ID(sdev), error);\n \t\tif ((ret = fs_err(sdev, ret))) {\n \t\t\tERROR(\"Operation rte_flow_flush failed for sub_device %d\"\n \t\t\t      \" with error %d\", i, ret);\n+\t\t\tfs_unlock(dev, 0);\n \t\t\treturn ret;\n \t\t}\n \t}\n@@ -157,6 +167,7 @@ fs_flow_flush(struct rte_eth_dev *dev,\n \t\tTAILQ_REMOVE(&PRIV(dev)->flow_list, flow, next);\n \t\tfs_flow_release(&flow);\n \t}\n+\tfs_unlock(dev, 0);\n \treturn 0;\n }\n \n@@ -169,15 +180,19 @@ fs_flow_query(struct rte_eth_dev *dev,\n {\n \tstruct sub_device *sdev;\n \n+\tfs_lock(dev, 0);\n \tsdev = TX_SUBDEV(dev);\n \tif (sdev != NULL) {\n \t\tint ret = rte_flow_query(PORT_ID(sdev),\n \t\t\t\t\t flow->flows[SUB_ID(sdev)],\n \t\t\t\t\t type, arg, error);\n \n-\t\tif ((ret = fs_err(sdev, ret)))\n+\t\tif ((ret = fs_err(sdev, ret))) {\n+\t\t\tfs_unlock(dev, 0);\n \t\t\treturn ret;\n+\t\t}\n \t}\n+\tfs_unlock(dev, 0);\n \tWARN(\"No active sub_device to query about its flow\");\n \treturn -1;\n }\n@@ -191,6 +206,7 @@ fs_flow_isolate(struct rte_eth_dev *dev,\n \tuint8_t i;\n \tint ret;\n \n+\tfs_lock(dev, 0);\n \tFOREACH_SUBDEV(sdev, i, dev) {\n \t\tif (sdev->state < DEV_PROBED)\n \t\t\tcontinue;\n@@ -202,11 +218,13 @@ fs_flow_isolate(struct rte_eth_dev *dev,\n \t\tif ((ret = fs_err(sdev, ret))) {\n \t\t\tERROR(\"Operation rte_flow_isolate failed for sub_device %d\"\n \t\t\t      \" with error %d\", i, ret);\n+\t\t\tfs_unlock(dev, 0);\n \t\t\treturn ret;\n \t\t}\n \t\tsdev->flow_isolated = set;\n \t}\n \tPRIV(dev)->flow_isolated = set;\n+\tfs_unlock(dev, 0);\n \treturn 0;\n }\n \ndiff --git a/drivers/net/failsafe/failsafe_ops.c b/drivers/net/failsafe/failsafe_ops.c\nindex f0e48c1..fe64c68 100644\n--- a/drivers/net/failsafe/failsafe_ops.c\n+++ b/drivers/net/failsafe/failsafe_ops.c\n@@ -94,6 +94,7 @@ fs_dev_configure(struct rte_eth_dev *dev)\n \tuint8_t i;\n \tint ret;\n \n+\tfs_lock(dev, 0);\n \tsupp_tx_offloads = PRIV(dev)->infos.tx_offload_capa;\n \ttx_offloads = dev->data->dev_conf.txmode.offloads;\n \tif ((tx_offloads & supp_tx_offloads) != tx_offloads) {\n@@ -101,6 +102,7 @@ fs_dev_configure(struct rte_eth_dev *dev)\n \t\tERROR(\"Some Tx offloads are not supported, \"\n \t\t      \"requested 0x%\" PRIx64 \" supported 0x%\" PRIx64,\n \t\t      tx_offloads, supp_tx_offloads);\n+\t\tfs_unlock(dev, 0);\n \t\treturn -rte_errno;\n \t}\n \tFOREACH_SUBDEV(sdev, i, dev) {\n@@ -139,6 +141,7 @@ fs_dev_configure(struct rte_eth_dev *dev)\n \t\t\tif (!fs_err(sdev, ret))\n \t\t\t\tcontinue;\n \t\t\tERROR(\"Could not configure sub_device %d\", i);\n+\t\t\tfs_unlock(dev, 0);\n \t\t\treturn ret;\n \t\t}\n \t\tif (rmv_interrupt) {\n@@ -165,6 +168,7 @@ fs_dev_configure(struct rte_eth_dev *dev)\n \t}\n \tif (PRIV(dev)->state < DEV_ACTIVE)\n \t\tPRIV(dev)->state = DEV_ACTIVE;\n+\tfs_unlock(dev, 0);\n \treturn 0;\n }\n \n@@ -175,9 +179,12 @@ fs_dev_start(struct rte_eth_dev *dev)\n \tuint8_t i;\n \tint ret;\n \n+\tfs_lock(dev, 0);\n \tret = failsafe_rx_intr_install(dev);\n-\tif (ret)\n+\tif (ret) {\n+\t\tfs_unlock(dev, 0);\n \t\treturn ret;\n+\t}\n \tFOREACH_SUBDEV(sdev, i, dev) {\n \t\tif (sdev->state != DEV_ACTIVE)\n \t\t\tcontinue;\n@@ -186,6 +193,7 @@ fs_dev_start(struct rte_eth_dev *dev)\n \t\tif (ret) {\n \t\t\tif (!fs_err(sdev, ret))\n \t\t\t\tcontinue;\n+\t\t\tfs_unlock(dev, 0);\n \t\t\treturn ret;\n \t\t}\n \t\tret = failsafe_rx_intr_install_subdevice(sdev);\n@@ -193,6 +201,7 @@ fs_dev_start(struct rte_eth_dev *dev)\n \t\t\tif (!fs_err(sdev, ret))\n \t\t\t\tcontinue;\n \t\t\trte_eth_dev_stop(PORT_ID(sdev));\n+\t\t\tfs_unlock(dev, 0);\n \t\t\treturn ret;\n \t\t}\n \t\tsdev->state = DEV_STARTED;\n@@ -200,6 +209,7 @@ fs_dev_start(struct rte_eth_dev *dev)\n \tif (PRIV(dev)->state < DEV_STARTED)\n \t\tPRIV(dev)->state = DEV_STARTED;\n \tfs_switch_dev(dev, NULL);\n+\tfs_unlock(dev, 0);\n \treturn 0;\n }\n \n@@ -209,6 +219,7 @@ fs_dev_stop(struct rte_eth_dev *dev)\n \tstruct sub_device *sdev;\n \tuint8_t i;\n \n+\tfs_lock(dev, 0);\n \tPRIV(dev)->state = DEV_STARTED - 1;\n \tFOREACH_SUBDEV_STATE(sdev, i, dev, DEV_STARTED) {\n \t\trte_eth_dev_stop(PORT_ID(sdev));\n@@ -216,6 +227,7 @@ fs_dev_stop(struct rte_eth_dev *dev)\n \t\tsdev->state = DEV_STARTED - 1;\n \t}\n \tfailsafe_rx_intr_uninstall(dev);\n+\tfs_unlock(dev, 0);\n }\n \n static int\n@@ -225,15 +237,18 @@ fs_dev_set_link_up(struct rte_eth_dev *dev)\n \tuint8_t i;\n \tint ret;\n \n+\tfs_lock(dev, 0);\n \tFOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {\n \t\tDEBUG(\"Calling rte_eth_dev_set_link_up on sub_device %d\", i);\n \t\tret = rte_eth_dev_set_link_up(PORT_ID(sdev));\n \t\tif ((ret = fs_err(sdev, ret))) {\n \t\t\tERROR(\"Operation rte_eth_dev_set_link_up failed for sub_device %d\"\n \t\t\t      \" with error %d\", i, ret);\n+\t\t\tfs_unlock(dev, 0);\n \t\t\treturn ret;\n \t\t}\n \t}\n+\tfs_unlock(dev, 0);\n \treturn 0;\n }\n \n@@ -244,15 +259,18 @@ fs_dev_set_link_down(struct rte_eth_dev *dev)\n \tuint8_t i;\n \tint ret;\n \n+\tfs_lock(dev, 0);\n \tFOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {\n \t\tDEBUG(\"Calling rte_eth_dev_set_link_down on sub_device %d\", i);\n \t\tret = rte_eth_dev_set_link_down(PORT_ID(sdev));\n \t\tif ((ret = fs_err(sdev, ret))) {\n \t\t\tERROR(\"Operation rte_eth_dev_set_link_down failed for sub_device %d\"\n \t\t\t      \" with error %d\", i, ret);\n+\t\t\tfs_unlock(dev, 0);\n \t\t\treturn ret;\n \t\t}\n \t}\n+\tfs_unlock(dev, 0);\n \treturn 0;\n }\n \n@@ -263,6 +281,7 @@ fs_dev_close(struct rte_eth_dev *dev)\n \tstruct sub_device *sdev;\n \tuint8_t i;\n \n+\tfs_lock(dev, 0);\n \tfailsafe_hotplug_alarm_cancel(dev);\n \tif (PRIV(dev)->state == DEV_STARTED)\n \t\tdev->dev_ops->dev_stop(dev);\n@@ -273,6 +292,7 @@ fs_dev_close(struct rte_eth_dev *dev)\n \t\tsdev->state = DEV_ACTIVE - 1;\n \t}\n \tfs_dev_free_queues(dev);\n+\tfs_unlock(dev, 0);\n }\n \n static bool\n@@ -305,14 +325,16 @@ fs_rx_queue_release(void *queue)\n \tif (queue == NULL)\n \t\treturn;\n \trxq = queue;\n+\tdev = rxq->priv->dev;\n+\tfs_lock(dev, 0);\n \tif (rxq->event_fd > 0)\n \t\tclose(rxq->event_fd);\n-\tdev = rxq->priv->dev;\n \tFOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE)\n \t\tSUBOPS(sdev, rx_queue_release)\n \t\t\t(ETH(sdev)->data->rx_queues[rxq->qid]);\n \tdev->data->rx_queues[rxq->qid] = NULL;\n \trte_free(rxq);\n+\tfs_unlock(dev, 0);\n }\n \n static int\n@@ -338,6 +360,7 @@ fs_rx_queue_setup(struct rte_eth_dev *dev,\n \tuint8_t i;\n \tint ret;\n \n+\tfs_lock(dev, 0);\n \trxq = dev->data->rx_queues[rx_queue_id];\n \tif (rxq != NULL) {\n \t\tfs_rx_queue_release(rxq);\n@@ -353,14 +376,17 @@ fs_rx_queue_setup(struct rte_eth_dev *dev,\n \t\t      dev->data->dev_conf.rxmode.offloads,\n \t\t      PRIV(dev)->infos.rx_offload_capa |\n \t\t      PRIV(dev)->infos.rx_queue_offload_capa);\n+\t\tfs_unlock(dev, 0);\n \t\treturn -rte_errno;\n \t}\n \trxq = rte_zmalloc(NULL,\n \t\t\t  sizeof(*rxq) +\n \t\t\t  sizeof(rte_atomic64_t) * PRIV(dev)->subs_tail,\n \t\t\t  RTE_CACHE_LINE_SIZE);\n-\tif (rxq == NULL)\n+\tif (rxq == NULL) {\n+\t\tfs_unlock(dev, 0);\n \t\treturn -ENOMEM;\n+\t}\n \tFOREACH_SUBDEV(sdev, i, dev)\n \t\trte_atomic64_init(&rxq->refcnt[i]);\n \trxq->qid = rx_queue_id;\n@@ -371,8 +397,10 @@ fs_rx_queue_setup(struct rte_eth_dev *dev,\n \trxq->priv = PRIV(dev);\n \trxq->sdev = PRIV(dev)->subs;\n \tret = rte_intr_efd_enable(&intr_handle, 1);\n-\tif (ret < 0)\n+\tif (ret < 0) {\n+\t\tfs_unlock(dev, 0);\n \t\treturn ret;\n+\t}\n \trxq->event_fd = intr_handle.efds[0];\n \tdev->data->rx_queues[rx_queue_id] = rxq;\n \tFOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {\n@@ -385,9 +413,11 @@ fs_rx_queue_setup(struct rte_eth_dev *dev,\n \t\t\tgoto free_rxq;\n \t\t}\n \t}\n+\tfs_unlock(dev, 0);\n \treturn 0;\n free_rxq:\n \tfs_rx_queue_release(rxq);\n+\tfs_unlock(dev, 0);\n \treturn ret;\n }\n \n@@ -400,20 +430,21 @@ fs_rx_intr_enable(struct rte_eth_dev *dev, uint16_t idx)\n \tint ret;\n \tint rc = 0;\n \n+\tfs_lock(dev, 0);\n \tif (idx >= dev->data->nb_rx_queues) {\n-\t\trte_errno = EINVAL;\n-\t\treturn -rte_errno;\n+\t\trc = -EINVAL;\n+\t\tgoto unlock;\n \t}\n \trxq = dev->data->rx_queues[idx];\n \tif (rxq == NULL || rxq->event_fd <= 0) {\n-\t\trte_errno = EINVAL;\n-\t\treturn -rte_errno;\n+\t\trc = -EINVAL;\n+\t\tgoto unlock;\n \t}\n \t/* Fail if proxy service is nor running. */\n \tif (PRIV(dev)->rxp.sstate != SS_RUNNING) {\n \t\tERROR(\"failsafe interrupt services are not running\");\n-\t\trte_errno = EAGAIN;\n-\t\treturn -rte_errno;\n+\t\trc = -EAGAIN;\n+\t\tgoto unlock;\n \t}\n \trxq->enable_events = 1;\n \tFOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {\n@@ -422,6 +453,8 @@ fs_rx_intr_enable(struct rte_eth_dev *dev, uint16_t idx)\n \t\tif (ret)\n \t\t\trc = ret;\n \t}\n+unlock:\n+\tfs_unlock(dev, 0);\n \tif (rc)\n \t\trte_errno = -rc;\n \treturn rc;\n@@ -437,14 +470,15 @@ fs_rx_intr_disable(struct rte_eth_dev *dev, uint16_t idx)\n \tint rc = 0;\n \tint ret;\n \n+\tfs_lock(dev, 0);\n \tif (idx >= dev->data->nb_rx_queues) {\n-\t\trte_errno = EINVAL;\n-\t\treturn -rte_errno;\n+\t\trc = -EINVAL;\n+\t\tgoto unlock;\n \t}\n \trxq = dev->data->rx_queues[idx];\n \tif (rxq == NULL || rxq->event_fd <= 0) {\n-\t\trte_errno = EINVAL;\n-\t\treturn -rte_errno;\n+\t\trc = -EINVAL;\n+\t\tgoto unlock;\n \t}\n \trxq->enable_events = 0;\n \tFOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {\n@@ -456,6 +490,8 @@ fs_rx_intr_disable(struct rte_eth_dev *dev, uint16_t idx)\n \t/* Clear pending events */\n \twhile (read(rxq->event_fd, &u64, sizeof(uint64_t)) >  0)\n \t\t;\n+unlock:\n+\tfs_unlock(dev, 0);\n \tif (rc)\n \t\trte_errno = -rc;\n \treturn rc;\n@@ -492,11 +528,13 @@ fs_tx_queue_release(void *queue)\n \t\treturn;\n \ttxq = queue;\n \tdev = txq->priv->dev;\n+\tfs_lock(dev, 0);\n \tFOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE)\n \t\tSUBOPS(sdev, tx_queue_release)\n \t\t\t(ETH(sdev)->data->tx_queues[txq->qid]);\n \tdev->data->tx_queues[txq->qid] = NULL;\n \trte_free(txq);\n+\tfs_unlock(dev, 0);\n }\n \n static int\n@@ -511,6 +549,7 @@ fs_tx_queue_setup(struct rte_eth_dev *dev,\n \tuint8_t i;\n \tint ret;\n \n+\tfs_lock(dev, 0);\n \ttxq = dev->data->tx_queues[tx_queue_id];\n \tif (txq != NULL) {\n \t\tfs_tx_queue_release(txq);\n@@ -531,14 +570,17 @@ fs_tx_queue_setup(struct rte_eth_dev *dev,\n \t\t      dev->data->dev_conf.txmode.offloads,\n \t\t      PRIV(dev)->infos.tx_offload_capa |\n \t\t      PRIV(dev)->infos.tx_queue_offload_capa);\n+\t\tfs_unlock(dev, 0);\n \t\treturn -rte_errno;\n \t}\n \ttxq = rte_zmalloc(\"ethdev TX queue\",\n \t\t\t  sizeof(*txq) +\n \t\t\t  sizeof(rte_atomic64_t) * PRIV(dev)->subs_tail,\n \t\t\t  RTE_CACHE_LINE_SIZE);\n-\tif (txq == NULL)\n+\tif (txq == NULL) {\n+\t\tfs_unlock(dev, 0);\n \t\treturn -ENOMEM;\n+\t}\n \tFOREACH_SUBDEV(sdev, i, dev)\n \t\trte_atomic64_init(&txq->refcnt[i]);\n \ttxq->qid = tx_queue_id;\n@@ -557,9 +599,11 @@ fs_tx_queue_setup(struct rte_eth_dev *dev,\n \t\t\tgoto free_txq;\n \t\t}\n \t}\n+\tfs_unlock(dev, 0);\n \treturn 0;\n free_txq:\n \tfs_tx_queue_release(txq);\n+\tfs_unlock(dev, 0);\n \treturn ret;\n }\n \n@@ -586,8 +630,10 @@ fs_promiscuous_enable(struct rte_eth_dev *dev)\n \tstruct sub_device *sdev;\n \tuint8_t i;\n \n+\tfs_lock(dev, 0);\n \tFOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE)\n \t\trte_eth_promiscuous_enable(PORT_ID(sdev));\n+\tfs_unlock(dev, 0);\n }\n \n static void\n@@ -596,8 +642,10 @@ fs_promiscuous_disable(struct rte_eth_dev *dev)\n \tstruct sub_device *sdev;\n \tuint8_t i;\n \n+\tfs_lock(dev, 0);\n \tFOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE)\n \t\trte_eth_promiscuous_disable(PORT_ID(sdev));\n+\tfs_unlock(dev, 0);\n }\n \n static void\n@@ -606,8 +654,10 @@ fs_allmulticast_enable(struct rte_eth_dev *dev)\n \tstruct sub_device *sdev;\n \tuint8_t i;\n \n+\tfs_lock(dev, 0);\n \tFOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE)\n \t\trte_eth_allmulticast_enable(PORT_ID(sdev));\n+\tfs_unlock(dev, 0);\n }\n \n static void\n@@ -616,8 +666,10 @@ fs_allmulticast_disable(struct rte_eth_dev *dev)\n \tstruct sub_device *sdev;\n \tuint8_t i;\n \n+\tfs_lock(dev, 0);\n \tFOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE)\n \t\trte_eth_allmulticast_disable(PORT_ID(sdev));\n+\tfs_unlock(dev, 0);\n }\n \n static int\n@@ -628,6 +680,7 @@ fs_link_update(struct rte_eth_dev *dev,\n \tuint8_t i;\n \tint ret;\n \n+\tfs_lock(dev, 0);\n \tFOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {\n \t\tDEBUG(\"Calling link_update on sub_device %d\", i);\n \t\tret = (SUBOPS(sdev, link_update))(ETH(sdev), wait_to_complete);\n@@ -635,6 +688,7 @@ fs_link_update(struct rte_eth_dev *dev,\n \t\t    rte_eth_dev_is_removed(PORT_ID(sdev)) == 0) {\n \t\t\tERROR(\"Link update failed for sub_device %d with error %d\",\n \t\t\t      i, ret);\n+\t\t\tfs_unlock(dev, 0);\n \t\t\treturn ret;\n \t\t}\n \t}\n@@ -646,9 +700,11 @@ fs_link_update(struct rte_eth_dev *dev,\n \t\tl2 = &ETH(TX_SUBDEV(dev))->data->dev_link;\n \t\tif (memcmp(l1, l2, sizeof(*l1))) {\n \t\t\t*l1 = *l2;\n+\t\t\tfs_unlock(dev, 0);\n \t\t\treturn 0;\n \t\t}\n \t}\n+\tfs_unlock(dev, 0);\n \treturn -1;\n }\n \n@@ -661,6 +717,7 @@ fs_stats_get(struct rte_eth_dev *dev,\n \tuint8_t i;\n \tint ret;\n \n+\tfs_lock(dev, 0);\n \trte_memcpy(stats, &PRIV(dev)->stats_accumulator, sizeof(*stats));\n \tFOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {\n \t\tstruct rte_eth_stats *snapshot = &sdev->stats_snapshot.stats;\n@@ -676,12 +733,14 @@ fs_stats_get(struct rte_eth_dev *dev,\n \t\t\tERROR(\"Operation rte_eth_stats_get failed for sub_device %d with error %d\",\n \t\t\t\t  i, ret);\n \t\t\t*timestamp = 0;\n+\t\t\tfs_unlock(dev, 0);\n \t\t\treturn ret;\n \t\t}\n \t\t*timestamp = rte_rdtsc();\n inc:\n \t\tfailsafe_stats_increment(stats, snapshot);\n \t}\n+\tfs_unlock(dev, 0);\n \treturn 0;\n }\n \n@@ -691,11 +750,13 @@ fs_stats_reset(struct rte_eth_dev *dev)\n \tstruct sub_device *sdev;\n \tuint8_t i;\n \n+\tfs_lock(dev, 0);\n \tFOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {\n \t\trte_eth_stats_reset(PORT_ID(sdev));\n \t\tmemset(&sdev->stats_snapshot, 0, sizeof(struct rte_eth_stats));\n \t}\n \tmemset(&PRIV(dev)->stats_accumulator, 0, sizeof(struct rte_eth_stats));\n+\tfs_unlock(dev, 0);\n }\n \n /**\n@@ -771,14 +832,20 @@ fs_dev_supported_ptypes_get(struct rte_eth_dev *dev)\n {\n \tstruct sub_device *sdev;\n \tstruct rte_eth_dev *edev;\n+\tconst uint32_t *ret;\n \n+\tfs_lock(dev, 0);\n \tsdev = TX_SUBDEV(dev);\n-\tif (sdev == NULL)\n-\t\treturn NULL;\n+\tif (sdev == NULL) {\n+\t\tret = NULL;\n+\t\tgoto unlock;\n+\t}\n \tedev = ETH(sdev);\n \t/* ENOTSUP: counts as no supported ptypes */\n-\tif (SUBOPS(sdev, dev_supported_ptypes_get) == NULL)\n-\t\treturn NULL;\n+\tif (SUBOPS(sdev, dev_supported_ptypes_get) == NULL) {\n+\t\tret = NULL;\n+\t\tgoto unlock;\n+\t}\n \t/*\n \t * The API does not permit to do a clean AND of all ptypes,\n \t * It is also incomplete by design and we do not really care\n@@ -786,7 +853,10 @@ fs_dev_supported_ptypes_get(struct rte_eth_dev *dev)\n \t * We just return the ptypes of the device of highest\n \t * priority, usually the PREFERRED device.\n \t */\n-\treturn SUBOPS(sdev, dev_supported_ptypes_get)(edev);\n+\tret = SUBOPS(sdev, dev_supported_ptypes_get)(edev);\n+unlock:\n+\tfs_unlock(dev, 0);\n+\treturn ret;\n }\n \n static int\n@@ -796,15 +866,18 @@ fs_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)\n \tuint8_t i;\n \tint ret;\n \n+\tfs_lock(dev, 0);\n \tFOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {\n \t\tDEBUG(\"Calling rte_eth_dev_set_mtu on sub_device %d\", i);\n \t\tret = rte_eth_dev_set_mtu(PORT_ID(sdev), mtu);\n \t\tif ((ret = fs_err(sdev, ret))) {\n \t\t\tERROR(\"Operation rte_eth_dev_set_mtu failed for sub_device %d with error %d\",\n \t\t\t      i, ret);\n+\t\t\tfs_unlock(dev, 0);\n \t\t\treturn ret;\n \t\t}\n \t}\n+\tfs_unlock(dev, 0);\n \treturn 0;\n }\n \n@@ -815,15 +888,18 @@ fs_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)\n \tuint8_t i;\n \tint ret;\n \n+\tfs_lock(dev, 0);\n \tFOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {\n \t\tDEBUG(\"Calling rte_eth_dev_vlan_filter on sub_device %d\", i);\n \t\tret = rte_eth_dev_vlan_filter(PORT_ID(sdev), vlan_id, on);\n \t\tif ((ret = fs_err(sdev, ret))) {\n \t\t\tERROR(\"Operation rte_eth_dev_vlan_filter failed for sub_device %d\"\n \t\t\t      \" with error %d\", i, ret);\n+\t\t\tfs_unlock(dev, 0);\n \t\t\treturn ret;\n \t\t}\n \t}\n+\tfs_unlock(dev, 0);\n \treturn 0;\n }\n \n@@ -832,13 +908,22 @@ fs_flow_ctrl_get(struct rte_eth_dev *dev,\n \t\tstruct rte_eth_fc_conf *fc_conf)\n {\n \tstruct sub_device *sdev;\n+\tint ret;\n \n+\tfs_lock(dev, 0);\n \tsdev = TX_SUBDEV(dev);\n-\tif (sdev == NULL)\n-\t\treturn 0;\n-\tif (SUBOPS(sdev, flow_ctrl_get) == NULL)\n-\t\treturn -ENOTSUP;\n-\treturn SUBOPS(sdev, flow_ctrl_get)(ETH(sdev), fc_conf);\n+\tif (sdev == NULL) {\n+\t\tret = 0;\n+\t\tgoto unlock;\n+\t}\n+\tif (SUBOPS(sdev, flow_ctrl_get) == NULL) {\n+\t\tret = -ENOTSUP;\n+\t\tgoto unlock;\n+\t}\n+\tret = SUBOPS(sdev, flow_ctrl_get)(ETH(sdev), fc_conf);\n+unlock:\n+\tfs_unlock(dev, 0);\n+\treturn ret;\n }\n \n static int\n@@ -849,15 +934,18 @@ fs_flow_ctrl_set(struct rte_eth_dev *dev,\n \tuint8_t i;\n \tint ret;\n \n+\tfs_lock(dev, 0);\n \tFOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {\n \t\tDEBUG(\"Calling rte_eth_dev_flow_ctrl_set on sub_device %d\", i);\n \t\tret = rte_eth_dev_flow_ctrl_set(PORT_ID(sdev), fc_conf);\n \t\tif ((ret = fs_err(sdev, ret))) {\n \t\t\tERROR(\"Operation rte_eth_dev_flow_ctrl_set failed for sub_device %d\"\n \t\t\t      \" with error %d\", i, ret);\n+\t\t\tfs_unlock(dev, 0);\n \t\t\treturn ret;\n \t\t}\n \t}\n+\tfs_unlock(dev, 0);\n \treturn 0;\n }\n \n@@ -867,6 +955,7 @@ fs_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index)\n \tstruct sub_device *sdev;\n \tuint8_t i;\n \n+\tfs_lock(dev, 0);\n \t/* No check: already done within the rte_eth_dev_mac_addr_remove\n \t * call for the fail-safe device.\n \t */\n@@ -874,6 +963,7 @@ fs_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index)\n \t\trte_eth_dev_mac_addr_remove(PORT_ID(sdev),\n \t\t\t\t&dev->data->mac_addrs[index]);\n \tPRIV(dev)->mac_addr_pool[index] = 0;\n+\tfs_unlock(dev, 0);\n }\n \n static int\n@@ -887,11 +977,13 @@ fs_mac_addr_add(struct rte_eth_dev *dev,\n \tuint8_t i;\n \n \tRTE_ASSERT(index < FAILSAFE_MAX_ETHADDR);\n+\tfs_lock(dev, 0);\n \tFOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {\n \t\tret = rte_eth_dev_mac_addr_add(PORT_ID(sdev), mac_addr, vmdq);\n \t\tif ((ret = fs_err(sdev, ret))) {\n \t\t\tERROR(\"Operation rte_eth_dev_mac_addr_add failed for sub_device %\"\n \t\t\t      PRIu8 \" with error %d\", i, ret);\n+\t\t\tfs_unlock(dev, 0);\n \t\t\treturn ret;\n \t\t}\n \t}\n@@ -900,6 +992,7 @@ fs_mac_addr_add(struct rte_eth_dev *dev,\n \t\tPRIV(dev)->nb_mac_addr = index;\n \t}\n \tPRIV(dev)->mac_addr_pool[index] = vmdq;\n+\tfs_unlock(dev, 0);\n \treturn 0;\n }\n \n@@ -909,8 +1002,10 @@ fs_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)\n \tstruct sub_device *sdev;\n \tuint8_t i;\n \n+\tfs_lock(dev, 0);\n \tFOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE)\n \t\trte_eth_dev_default_mac_addr_set(PORT_ID(sdev), mac_addr);\n+\tfs_unlock(dev, 0);\n }\n \n static int\n@@ -928,15 +1023,18 @@ fs_filter_ctrl(struct rte_eth_dev *dev,\n \t\t*(const void **)arg = &fs_flow_ops;\n \t\treturn 0;\n \t}\n+\tfs_lock(dev, 0);\n \tFOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {\n \t\tDEBUG(\"Calling rte_eth_dev_filter_ctrl on sub_device %d\", i);\n \t\tret = rte_eth_dev_filter_ctrl(PORT_ID(sdev), type, op, arg);\n \t\tif ((ret = fs_err(sdev, ret))) {\n \t\t\tERROR(\"Operation rte_eth_dev_filter_ctrl failed for sub_device %d\"\n \t\t\t      \" with error %d\", i, ret);\n+\t\t\tfs_unlock(dev, 0);\n \t\t\treturn ret;\n \t\t}\n \t}\n+\tfs_unlock(dev, 0);\n \treturn 0;\n }\n \ndiff --git a/drivers/net/failsafe/failsafe_private.h b/drivers/net/failsafe/failsafe_private.h\nindex f3be152..5b84db9 100644\n--- a/drivers/net/failsafe/failsafe_private.h\n+++ b/drivers/net/failsafe/failsafe_private.h\n@@ -7,6 +7,7 @@\n #define _RTE_ETH_FAILSAFE_PRIVATE_H_\n \n #include <sys/queue.h>\n+#include <pthread.h>\n \n #include <rte_atomic.h>\n #include <rte_dev.h>\n@@ -161,6 +162,9 @@ struct fs_priv {\n \t * appropriate failsafe Rx queue.\n \t */\n \tstruct rx_proxy rxp;\n+\tpthread_mutex_t hotplug_mutex;\n+\t/* Hot-plug mutex is locked by the alarm mechanism. */\n+\tvolatile unsigned int alarm_lock:1;\n \tunsigned int pending_alarm:1; /* An alarm is pending */\n \t/* flow isolation state */\n \tint flow_isolated:1;\n@@ -347,6 +351,58 @@ fs_find_next(struct rte_eth_dev *dev,\n }\n \n /*\n+ * Lock hot-plug mutex.\n+ * is_alarm means that the caller is, for sure, the hot-plug alarm mechanism.\n+ */\n+static inline int\n+fs_lock(struct rte_eth_dev *dev, unsigned int is_alarm)\n+{\n+\tint ret;\n+\n+\tif (is_alarm) {\n+\t\tret = pthread_mutex_trylock(&PRIV(dev)->hotplug_mutex);\n+\t\tif (ret) {\n+\t\t\tDEBUG(\"Hot-plug mutex lock trying failed(%s), will try\"\n+\t\t\t      \" again later...\", strerror(ret));\n+\t\t\treturn ret;\n+\t\t}\n+\t\tPRIV(dev)->alarm_lock = 1;\n+\t} else {\n+\t\tret = pthread_mutex_lock(&PRIV(dev)->hotplug_mutex);\n+\t\tif (ret) {\n+\t\t\tERROR(\"Cannot lock mutex(%s)\", strerror(ret));\n+\t\t\treturn ret;\n+\t\t}\n+\t}\n+\tDEBUG(\"Hot-plug mutex was locked by thread %lu%s\", pthread_self(),\n+\t      PRIV(dev)->alarm_lock ? \" by the hot-plug alarm\" : \"\");\n+\treturn ret;\n+}\n+\n+/*\n+ * Unlock hot-plug mutex.\n+ * is_alarm means that the caller is, for sure, the hot-plug alarm mechanism.\n+ */\n+static inline void\n+fs_unlock(struct rte_eth_dev *dev, unsigned int is_alarm)\n+{\n+\tint ret;\n+\tunsigned int prev_alarm_lock = PRIV(dev)->alarm_lock;\n+\n+\tif (is_alarm) {\n+\t\tRTE_ASSERT(PRIV(dev)->alarm_lock == 1);\n+\t\tPRIV(dev)->alarm_lock = 0;\n+\t}\n+\tret = pthread_mutex_unlock(&PRIV(dev)->hotplug_mutex);\n+\tif (ret)\n+\t\tERROR(\"Cannot unlock hot-plug mutex(%s)\", strerror(ret));\n+\telse\n+\t\tDEBUG(\"Hot-plug mutex was unlocked by thread %lu%s\",\n+\t\t      pthread_self(),\n+\t\t      prev_alarm_lock ? \" by the hot-plug alarm\" : \"\");\n+}\n+\n+/*\n  * Switch emitting device.\n  * If banned is set, banned must not be considered for\n  * the role of emitting device.\n",
    "prefixes": [
        "dpdk-dev",
        "v7",
        "3/3"
    ]
}