netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Dany Madden <drt@linux.ibm.com>
To: Sukadev Bhattiprolu <sukadev@linux.ibm.com>
Cc: netdev@vger.kernel.org, Lijun Pan <ljp@linux.ibm.com>,
	Rick Lindsley <ricklind@linux.ibm.com>,
	abdhalee@in.ibm.com
Subject: Re: [PATCH net 1/2] ibmvnic: fix a race between open and reset
Date: Mon, 01 Feb 2021 09:39:29 -0800	[thread overview]
Message-ID: <eddd62ab4e7f2a91b5544df709ecc0d3@imap.linux.ibm.com> (raw)
In-Reply-To: <20210129034711.518250-1-sukadev@linux.ibm.com>

On 2021-01-28 19:47, Sukadev Bhattiprolu wrote:
> __ibmvnic_reset() currently reads the adapter->state before getting the
> rtnl and saves that state as the "target state" for the reset. If this
> read occurs when adapter is in PROBED state, the target state would be
> PROBED.
> 
> Just after the target state is saved, and before the actual reset 
> process
> is started (i.e before rtnl is acquired) if we get an ibmvnic_open() 
> call
> we would move the adapter to OPEN state.
> 
> But when the reset is processed (after ibmvnic_open()) drops the rtnl),
> it will leave the adapter in PROBED state even though we already moved
> it to OPEN.
> 
> To fix this, use the RTNL to improve the serialization when 
> reading/updating
> the adapter state. i.e determine the target state of a reset only after
> getting the RTNL. And if a reset is in progress during an open, simply
> set the target state of the adapter and let the reset code finish the
> open (like we currently do if failover is pending).
> 
> One twist to this serialization is if the adapter state changes when we
> drop the RTNL to update the link state. Account for this by checking if
> there was an intervening open and update the target state for the reset
> accordingly (see new comments in the code). Note that only the reset
> functions and ibmvnic_open() can set the adapter to OPEN state and this
> must happen under rtnl.
> 
> Fixes: 7d7195a026ba ("ibmvnic: Do not process device remove during
> device reset")
> Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.ibm.com>

Reviewed-by: Dany Madden <drt@linux.ibm.com>

> ---
>  drivers/net/ethernet/ibm/ibmvnic.c | 72 +++++++++++++++++++++++++++---
>  1 file changed, 65 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/net/ethernet/ibm/ibmvnic.c
> b/drivers/net/ethernet/ibm/ibmvnic.c
> index 8820c98ea891..cb7ddfefb03e 100644
> --- a/drivers/net/ethernet/ibm/ibmvnic.c
> +++ b/drivers/net/ethernet/ibm/ibmvnic.c
> @@ -1197,12 +1197,26 @@ static int ibmvnic_open(struct net_device 
> *netdev)
>  	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
>  	int rc;
> 
> -	/* If device failover is pending, just set device state and return.
> -	 * Device operation will be handled by reset routine.
> +	WARN_ON_ONCE(!rtnl_is_locked());
> +
> +	/**
> +	 * If device failover is pending or we are about to reset, just set
> +	 * device state and return. Device operation will be handled by reset
> +	 * routine.
> +	 *
> +	 * It should be safe to overwrite the adapter->state here. Since
> +	 * we hold the rtnl, either the reset has not actually started or
> +	 * the rtnl got dropped during the set_link_state() in do_reset().
> +	 * In the former case, no one else is changing the state (again we
> +	 * have the rtnl) and in the latter case, do_reset() will detect and
> +	 * honor our setting below.
>  	 */
> -	if (adapter->failover_pending) {
> +	if (adapter->failover_pending || (test_bit(0, &adapter->resetting))) 
> {
> +		netdev_dbg(netdev, "[S:%d FOP:%d] Resetting, deferring open\n",
> +			   adapter->state, adapter->failover_pending);
>  		adapter->state = VNIC_OPEN;
> -		return 0;
> +		rc = 0;
> +		goto out;
>  	}
> 
>  	if (adapter->state != VNIC_CLOSED) {
> @@ -1222,10 +1236,12 @@ static int ibmvnic_open(struct net_device 
> *netdev)
> 
>  out:
>  	/*
> -	 * If open fails due to a pending failover, set device state and
> -	 * return. Device operation will be handled by reset routine.
> +	 * If open failed and there is a pending failover or in-progress 
> reset,
> +	 * set device state and return. Device operation will be handled by
> +	 * reset routine. See also comments above regarding rtnl.
>  	 */
> -	if (rc && adapter->failover_pending) {
> +	if (rc &&
> +	    (adapter->failover_pending || (test_bit(0, 
> &adapter->resetting)))) {
>  		adapter->state = VNIC_OPEN;
>  		rc = 0;
>  	}
> @@ -1939,6 +1955,14 @@ static int do_change_param_reset(struct
> ibmvnic_adapter *adapter,
>  	netdev_dbg(adapter->netdev, "Change param resetting driver (%d)\n",
>  		   rwi->reset_reason);
> 
> +	/* read the state and check (again) after getting rtnl */
> +	reset_state = adapter->state;
> +
> +	if (reset_state == VNIC_REMOVING || reset_state == VNIC_REMOVED) {
> +		rc = -EBUSY;
> +		goto out;
> +	}
> +
>  	netif_carrier_off(netdev);
>  	adapter->reset_reason = rwi->reset_reason;
> 
> @@ -2037,6 +2061,14 @@ static int do_reset(struct ibmvnic_adapter 
> *adapter,
>  	if (rwi->reset_reason == VNIC_RESET_FAILOVER)
>  		adapter->failover_pending = false;
> 
> +	/* read the state and check (again) after getting rtnl */
> +	reset_state = adapter->state;
> +
> +	if (reset_state == VNIC_REMOVING || reset_state == VNIC_REMOVED) {
> +		rc = -EBUSY;
> +		goto out;
> +	}
> +
>  	netif_carrier_off(netdev);
>  	adapter->reset_reason = rwi->reset_reason;
> 
> @@ -2063,7 +2095,25 @@ static int do_reset(struct ibmvnic_adapter 
> *adapter,
>  		if (rc)
>  			goto out;
> 
> +		if (adapter->state == VNIC_OPEN) {
> +			/**
> +			 * When we dropped rtnl, ibmvnic_open() got it and
> +			 * noticed that we are resetting and set the adapter
> +			 * state to OPEN. Update our new "target" state,
> +			 * and resume the reset from VNIC_CLOSING state.
> +			 */
> +			netdev_dbg(netdev,
> +				   "Open changed state from %d, updating.\n",
> +				    reset_state);
> +			reset_state = VNIC_OPEN;
> +			adapter->state = VNIC_CLOSING;
> +		}
> +
>  		if (adapter->state != VNIC_CLOSING) {
> +			/**
> +			 * If someone else changed the adapter state
> +			 * when we dropped the rtnl, fail the reset
> +			 */
>  			rc = -1;
>  			goto out;
>  		}
> @@ -2197,6 +2247,14 @@ static int do_hard_reset(struct ibmvnic_adapter 
> *adapter,
>  	netdev_dbg(adapter->netdev, "Hard resetting driver (%d)\n",
>  		   rwi->reset_reason);
> 
> +	/* read the state and check (again) after getting rtnl */
> +	reset_state = adapter->state;
> +
> +	if (reset_state == VNIC_REMOVING || reset_state == VNIC_REMOVED) {
> +		rc = -EBUSY;
> +		goto out;
> +	}
> +
>  	netif_carrier_off(netdev);
>  	adapter->reset_reason = rwi->reset_reason;

  parent reply	other threads:[~2021-02-01 17:40 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-01-29  3:47 [PATCH net 1/2] ibmvnic: fix a race between open and reset Sukadev Bhattiprolu
2021-01-29  3:47 ` [PATCH net 2/2] ibmvnic: fix race with multiple open/close Sukadev Bhattiprolu
2021-01-30 15:04   ` Willem de Bruijn
2021-02-02  2:21     ` Sukadev Bhattiprolu
2021-02-01 17:39 ` Dany Madden [this message]
2021-02-02  2:38 ` [PATCH net 1/2] ibmvnic: fix a race between open and reset Jakub Kicinski
2021-02-03  5:08   ` Sukadev Bhattiprolu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=eddd62ab4e7f2a91b5544df709ecc0d3@imap.linux.ibm.com \
    --to=drt@linux.ibm.com \
    --cc=abdhalee@in.ibm.com \
    --cc=ljp@linux.ibm.com \
    --cc=netdev@vger.kernel.org \
    --cc=ricklind@linux.ibm.com \
    --cc=sukadev@linux.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).