Received: by 2002:a17:90a:9307:0:0:0:0 with SMTP id p7csp3958032pjo; Tue, 3 Mar 2020 10:05:33 -0800 (PST) X-Google-Smtp-Source: ADFU+vvU+jAZ1U5/rajDcse5zpx24rUYE+zVehD48iEDAjTGKwFfgtTzckss+me1CmZ5YHDiXvYK X-Received: by 2002:aca:5403:: with SMTP id i3mr3392566oib.107.1583258733228; Tue, 03 Mar 2020 10:05:33 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1583258733; cv=none; d=google.com; s=arc-20160816; b=c+mh5y6xWAZ6OcQGzj7lm9VwRU5NVYmpKvmktOYMRByN3kRJuYAF2VV0IcZSQhbxNR VklZbuq3mewMgkAxrQc1oBFSU9Gd/8x4m1HeiENdACerinECRl9yLRMk2uZ0/+ANFQi6 18VHIsG2p9dWhhWhCJOXwLy/HOB/AStQe90cXoUcbDpf1oFfsKOErvTncFLWIGvmhA/n x7iI7ece3nVYO2Cmwg/NLzFI747Uq7Ow+CEVzTqIgbT9ZRcnhCyOnaO3TtVStwrzJZ9p Pdbln7k3aAz6VjhcWpafiMPI0EmXQM809cNAX9igWRaG5N3AVpaPeKrcyeRjngsMVETz Vxrw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=FLDEFAsChoUwNng6sklf8Jpnpk6sA0f4W5OLMxmfT6Y=; b=aHZWXdVDIMC5IaseE9HpgUiXueWjTlOr3Oj/xKzweEpV36Tk1LzhVJH0Ok9DhgYDck mJ2E2ESQY/u6KyiWpbgfPnOELR2xvqtBHNkTK5s8bEF9OxSN5b6LJYNpMzDOIVj24ZXy sMxPQpVK3OrW4MW1eS7SHC1nFjMyaAGm+HNFnUtGdKsy42wXzGTogm7k2Eec6TvnJ31F JpvHQz7r3OQHNd3MiwoEn6oPs9Nn/1j3KJZEo32MAkoL0GkF6GjvdfSnf+Nk2HEnN9Yr QmqLblPswoRvzQDxnUmPffHeda9ME3U3FMkqYCodagXeAmVLMLhHDVUNdFELnWpUarIr GwgQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=16jB1eGI; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id q11si6820500oti.270.2020.03.03.10.05.21; Tue, 03 Mar 2020 10:05:33 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=16jB1eGI; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387417AbgCCSAI (ORCPT + 99 others); Tue, 3 Mar 2020 13:00:08 -0500 Received: from mail.kernel.org ([198.145.29.99]:43676 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2387724AbgCCSAF (ORCPT ); Tue, 3 Mar 2020 13:00:05 -0500 Received: from localhost (83-86-89-107.cable.dynamic.v4.ziggo.nl [83.86.89.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id A394720870; Tue, 3 Mar 2020 18:00:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1583258404; bh=1BLt8yG0Ib8eC2ZyKs4srI96G0OIxxlYaqLtkkZ1u7o=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=16jB1eGI0RI6EZ/VjsBRSMI3gvYsXUc/R++H5jeQ/Lt7192BTujU+fvlx/1HB/Vvj xtfsdZR2OgyU6zz4V/z4Km6bioT7kwG/0EdM3GriRR6+J7K7mWk2SV0bW6rBHHlULU 94qLP36T2IR/WXtdu30W6O/COpxn6ulQa9JYIyKs= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Ariel Elior , Michal Kalderon , "David S. Miller" Subject: [PATCH 4.19 37/87] qede: Fix race between rdma destroy workqueue and link change event Date: Tue, 3 Mar 2020 18:43:28 +0100 Message-Id: <20200303174353.848357265@linuxfoundation.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200303174349.075101355@linuxfoundation.org> References: <20200303174349.075101355@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Michal Kalderon [ Upstream commit af6565adb02d3129d3fae4d9d5da945abaf4417a ] If an event is added while the rdma workqueue is being destroyed it could lead to several races, list corruption, null pointer dereference during queue_work or init_queue. This fixes the race between the two flows which can occur during shutdown. A kref object and a completion object are added to the rdma_dev structure, these are initialized before the workqueue is created. The refcnt is used to indicate work is being added to the workqueue and ensures the cleanup flow won't start while we're in the middle of adding the event. Once the work is added, the refcnt is decreased and the cleanup flow is safe to run. Fixes: cee9fbd8e2e ("qede: Add qedr framework") Signed-off-by: Ariel Elior Signed-off-by: Michal Kalderon Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/qlogic/qede/qede.h | 2 + drivers/net/ethernet/qlogic/qede/qede_rdma.c | 29 ++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) --- a/drivers/net/ethernet/qlogic/qede/qede.h +++ b/drivers/net/ethernet/qlogic/qede/qede.h @@ -162,6 +162,8 @@ struct qede_rdma_dev { struct list_head entry; struct list_head rdma_event_list; struct workqueue_struct *rdma_wq; + struct kref refcnt; + struct completion event_comp; }; struct qede_ptp; --- a/drivers/net/ethernet/qlogic/qede/qede_rdma.c +++ b/drivers/net/ethernet/qlogic/qede/qede_rdma.c @@ -57,6 +57,9 @@ static void _qede_rdma_dev_add(struct qe static int qede_rdma_create_wq(struct qede_dev *edev) { INIT_LIST_HEAD(&edev->rdma_info.rdma_event_list); + kref_init(&edev->rdma_info.refcnt); + init_completion(&edev->rdma_info.event_comp); + edev->rdma_info.rdma_wq = create_singlethread_workqueue("rdma_wq"); if (!edev->rdma_info.rdma_wq) { DP_NOTICE(edev, "qedr: Could not create workqueue\n"); @@ -81,8 +84,23 @@ static void qede_rdma_cleanup_event(stru } } +static void qede_rdma_complete_event(struct kref *ref) +{ + struct qede_rdma_dev *rdma_dev = + container_of(ref, struct qede_rdma_dev, refcnt); + + /* no more events will be added after this */ + complete(&rdma_dev->event_comp); +} + static void qede_rdma_destroy_wq(struct qede_dev *edev) { + /* Avoid race with add_event flow, make sure it finishes before + * we start accessing the list and cleaning up the work + */ + kref_put(&edev->rdma_info.refcnt, qede_rdma_complete_event); + wait_for_completion(&edev->rdma_info.event_comp); + qede_rdma_cleanup_event(edev); destroy_workqueue(edev->rdma_info.rdma_wq); } @@ -287,15 +305,24 @@ static void qede_rdma_add_event(struct q if (!edev->rdma_info.qedr_dev) return; + /* We don't want the cleanup flow to start while we're allocating and + * scheduling the work + */ + if (!kref_get_unless_zero(&edev->rdma_info.refcnt)) + return; /* already being destroyed */ + event_node = qede_rdma_get_free_event_node(edev); if (!event_node) - return; + goto out; event_node->event = event; event_node->ptr = edev; INIT_WORK(&event_node->work, qede_rdma_handle_event); queue_work(edev->rdma_info.rdma_wq, &event_node->work); + +out: + kref_put(&edev->rdma_info.refcnt, qede_rdma_complete_event); } void qede_rdma_dev_event_open(struct qede_dev *edev)