Received: by 2002:a25:ab43:0:0:0:0:0 with SMTP id u61csp309378ybi; Wed, 29 May 2019 21:59:54 -0700 (PDT) X-Google-Smtp-Source: APXvYqzWvW0tAWobwCiumtmqAFiHLyPI3FqYK8kecfaiX+eadru18bL1/CLdvBqNDydlHRxRkNVT X-Received: by 2002:a17:902:728a:: with SMTP id d10mr1970579pll.90.1559192394658; Wed, 29 May 2019 21:59:54 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1559192394; cv=none; d=google.com; s=arc-20160816; b=n5pFeukMRHR9fpPhFCpRsRB9erHQoDYPDFG4f1AvKnm5erLIOSY5FE9tq6UUzFObug JL6mj7BrFpVYIs0K7QDgQ8LzNUlQTjx2B+E5tAZAH6CbR3mzuzgfx2qzDU4EZZfg1wIv CBqFTpdrAO7WRFEHl1kcDNwIjW0+/Uw+Fy2w4Syl5+x/kyWqnX+KhakZ2ipgQuEBW/N3 Jw81uEAnL2iv1Uq8f/QSgN+YL3Plw3cYquCg3nTyb3Z9aVRAjfzhyB4/RSEIAUxLcPpS 2qARQpzob102uC/WrU0PyijNVtXSQ7IEkw6uLc494OzWorwxgu8wRI93ieuHHbFQGOYf aWpA== 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=woiNZEgFlJx/tB6ownPyr2xaJF17atPm7+BG1u4rLXc=; b=y/ueyuAOuR1TN1CkpU0TqnelqsxOKtouuWlFgRSh83wdNgNsiFw7hxM23m0Pwlcsy4 Nd3BunlH3738sJjoO3KBFj4w7RDETUuFQBFrqMbRw3J5CvHrl2sQLVbWIiNOBsR9OzTz AYv1VLB+5/dcl0D0YvV9R4Dx1JJqawXVdg+PWQ086+12pd2c3EfzG9ngYsUVXD1Racbc xiCnS1MvioE5Un+ZHgTJjGKCsQxkQuBZ1A8btt/0UpkuIZBxm2JJqFf4FHJ8X4RnMJuG gtWVIubW6wM1Yc5aWcV5ApxXig2cpPlAMuTHCTp3pl49aPeoLIMU1qgmg6QTTxIy6XUI NLhw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=ocuDJZaC; 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 o1si2120148plb.179.2019.05.29.21.59.39; Wed, 29 May 2019 21:59:54 -0700 (PDT) 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=ocuDJZaC; 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 S2389110AbfE3E4i (ORCPT + 99 others); Thu, 30 May 2019 00:56:38 -0400 Received: from mail.kernel.org ([198.145.29.99]:46114 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727903AbfE3DKC (ORCPT ); Wed, 29 May 2019 23:10:02 -0400 Received: from localhost (ip67-88-213-2.z213-88-67.customer.algx.net [67.88.213.2]) (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 7057A24479; Thu, 30 May 2019 03:10:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1559185801; bh=pyLVT5jjSMOmdf9KYk85VVQ1ALZ3fRp8H02+QUiro8k=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ocuDJZaCD2bkn/mly6MJtPOwvaOFSFiaoe5ENqg+w0zpg+NNOBhB7E4zUk684UFoE Fjz+eorDOocHoDfoGQDxfeQwkAQY5nRK3w7nGKbiGmw8AN2jN0PeiRZlrfSThf/PcV IlK2DplCHBYH6vJxuiGkzwPVM97tEsBvGF/dOx6g= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Bodong Wang , Parav Pandit , Vu Pham , Saeed Mahameed , Sasha Levin Subject: [PATCH 5.1 080/405] net/mlx5: E-Switch, Use atomic rep state to serialize state change Date: Wed, 29 May 2019 20:01:18 -0700 Message-Id: <20190530030545.043409309@linuxfoundation.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190530030540.291644921@linuxfoundation.org> References: <20190530030540.291644921@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 [ Upstream commit 6f4e02193c9a9ea54dd3151cf97489fa787cd0e6 ] When the state of rep was introduced, it was also designed to prevent duplicate unloading of the same rep. Considering the following two flows when an eswitch manager is at switchdev mode with n VF reps loaded. +--------------------------------------+--------------------------------+ | cpu-0 | cpu-1 | | -------- | -------- | | mlx5_ib_remove | mlx5_eswitch_disable_sriov | | mlx5_ib_unregister_vport_reps | esw_offloads_cleanup | | mlx5_eswitch_unregister_vport_reps | esw_offloads_unload_all_reps | | __unload_reps_all_vport | __unload_reps_all_vport | +--------------------------------------+--------------------------------+ These two flows will try to unload the same rep. Per original design, once one flow unloads the rep, the state moves to REGISTERED. The 2nd flow will no longer needs to do the unload and bails out. However, as read and write of the state is not atomic, when 1st flow is doing the unload, the state is still LOADED, 2nd flow is able to do the same unload action. Kernel crash will happen. To solve this, driver should do atomic test-and-set for the state. So that only one flow can change the rep state from LOADED to REGISTERED, and proceed to do the actual unloading. Since the state is changing to atomic type, all other read/write should be atomic action as well. Fixes: f121e0ea9586 (net/mlx5: E-Switch, Add state to eswitch vport representors) Signed-off-by: Bodong Wang Reviewed-by: Parav Pandit Reviewed-by: Vu Pham Signed-off-by: Saeed Mahameed Signed-off-by: Sasha Levin --- .../mellanox/mlx5/core/eswitch_offloads.c | 36 +++++++++---------- include/linux/mlx5/eswitch.h | 2 +- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 9b2d78ee22b88..d2d8da133082c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -363,7 +363,7 @@ static int esw_set_global_vlan_pop(struct mlx5_eswitch *esw, u8 val) esw_debug(esw->dev, "%s applying global %s policy\n", __func__, val ? "pop" : "none"); for (vf_vport = 1; vf_vport < esw->enabled_vports; vf_vport++) { rep = &esw->offloads.vport_reps[vf_vport]; - if (rep->rep_if[REP_ETH].state != REP_LOADED) + if (atomic_read(&rep->rep_if[REP_ETH].state) != REP_LOADED) continue; err = __mlx5_eswitch_set_vport_vlan(esw, rep->vport, 0, 0, val); @@ -1306,7 +1306,8 @@ int esw_offloads_init_reps(struct mlx5_eswitch *esw) ether_addr_copy(rep->hw_id, hw_id); for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++) - rep->rep_if[rep_type].state = REP_UNREGISTERED; + atomic_set(&rep->rep_if[rep_type].state, + REP_UNREGISTERED); } return 0; @@ -1315,11 +1316,9 @@ int esw_offloads_init_reps(struct mlx5_eswitch *esw) static void __esw_offloads_unload_rep(struct mlx5_eswitch *esw, struct mlx5_eswitch_rep *rep, u8 rep_type) { - if (rep->rep_if[rep_type].state != REP_LOADED) - return; - - rep->rep_if[rep_type].unload(rep); - rep->rep_if[rep_type].state = REP_REGISTERED; + if (atomic_cmpxchg(&rep->rep_if[rep_type].state, + REP_LOADED, REP_REGISTERED) == REP_LOADED) + rep->rep_if[rep_type].unload(rep); } static void __unload_reps_special_vport(struct mlx5_eswitch *esw, u8 rep_type) @@ -1380,16 +1379,15 @@ static int __esw_offloads_load_rep(struct mlx5_eswitch *esw, { int err = 0; - if (rep->rep_if[rep_type].state != REP_REGISTERED) - return 0; - - err = rep->rep_if[rep_type].load(esw->dev, rep); - if (err) - return err; - - rep->rep_if[rep_type].state = REP_LOADED; + if (atomic_cmpxchg(&rep->rep_if[rep_type].state, + REP_REGISTERED, REP_LOADED) == REP_REGISTERED) { + err = rep->rep_if[rep_type].load(esw->dev, rep); + if (err) + atomic_set(&rep->rep_if[rep_type].state, + REP_REGISTERED); + } - return 0; + return err; } static int __load_reps_special_vport(struct mlx5_eswitch *esw, u8 rep_type) @@ -2076,7 +2074,7 @@ void mlx5_eswitch_register_vport_reps(struct mlx5_eswitch *esw, rep_if->get_proto_dev = __rep_if->get_proto_dev; rep_if->priv = __rep_if->priv; - rep_if->state = REP_REGISTERED; + atomic_set(&rep_if->state, REP_REGISTERED); } } EXPORT_SYMBOL(mlx5_eswitch_register_vport_reps); @@ -2091,7 +2089,7 @@ void mlx5_eswitch_unregister_vport_reps(struct mlx5_eswitch *esw, u8 rep_type) __unload_reps_all_vport(esw, max_vf, rep_type); mlx5_esw_for_all_reps(esw, i, rep) - rep->rep_if[rep_type].state = REP_UNREGISTERED; + atomic_set(&rep->rep_if[rep_type].state, REP_UNREGISTERED); } EXPORT_SYMBOL(mlx5_eswitch_unregister_vport_reps); @@ -2111,7 +2109,7 @@ void *mlx5_eswitch_get_proto_dev(struct mlx5_eswitch *esw, rep = mlx5_eswitch_get_rep(esw, vport); - if (rep->rep_if[rep_type].state == REP_LOADED && + if (atomic_read(&rep->rep_if[rep_type].state) == REP_LOADED && rep->rep_if[rep_type].get_proto_dev) return rep->rep_if[rep_type].get_proto_dev(rep); return NULL; diff --git a/include/linux/mlx5/eswitch.h b/include/linux/mlx5/eswitch.h index 96d8435421de8..0ca77dd1429c0 100644 --- a/include/linux/mlx5/eswitch.h +++ b/include/linux/mlx5/eswitch.h @@ -35,7 +35,7 @@ struct mlx5_eswitch_rep_if { void (*unload)(struct mlx5_eswitch_rep *rep); void *(*get_proto_dev)(struct mlx5_eswitch_rep *rep); void *priv; - u8 state; + atomic_t state; }; struct mlx5_eswitch_rep { -- 2.20.1