[Intel-wired-lan] [PATCH net] igb: Fix oops caused by missing queue pairing

Suzuki Shota suzuki_shota_t3 at lab.ntt.co.jp
Thu Jul 23 05:56:44 UTC 2015


Dear Jeffrey,

With regard to the patch I submitted,
would you tell me the review status of it?
(I'm watching Patchwork of intel-wired-lan,
 but the state of my patch is still 'New')

Do I have to do other things?

Regards,
Shota Suzuki

On 2015/07/01 9:25, Shota Suzuki wrote:
> When initializing igb driver (e.g. 82576, I350), IGB_FLAG_QUEUE_PAIRS is
> set if adapter->rss_queues exceeds half of max_rss_queues in
> igb_init_queue_configuration().
> On the other hand, IGB_FLAG_QUEUE_PAIRS is not set even if the number of
> queues exceeds half of max_combined in igb_set_channels() when changing
> the number of queues by "ethtool -L".
> In this case, if numvecs is larger than MAX_MSIX_ENTRIES (10), the size
> of adapter->msix_entries[], an overflow can occur in
> igb_set_interrupt_capability(), which in turn leads to an oops.
> 
> Fix this problem as follows:
>   - When changing the number of queues by "ethtool -L", set
>     IGB_FLAG_QUEUE_PAIRS in the same way as initializing igb driver.
>   - When increasing the size of q_vector, reallocate it appropriately.
>     (With IGB_FLAG_QUEUE_PAIRS set, the size of q_vector gets larger.)
> 
> Another possible way to fix this problem is to cap the queues at its
> initial number, which is the number of the initial online cpus. But this
> is not the optimal way because we cannnot increase queues when another
> cpu becomes online.
> 
> Note that before commit cd14ef54d25b ("igb: Change to use statically
> allocated array for MSIx entries"), this problem did not cause oops
> but just made the number of queues become 1 because of entering msi_only
> mode in igb_set_interrupt_capability().
> 
> Fixes: 907b7835799f ("igb: Add ethtool support to configure number of channels")
> Signed-off-by: Shota Suzuki <suzuki_shota_t3 at lab.ntt.co.jp>
> ---
> Although we might be able to additionally unset IGB_FLAG_QUEUE_PAIRS
> when it is not needed, this patch doesn't change existing behaviour
> because such a change is not a bug fix.
> 
>   drivers/net/ethernet/intel/igb/igb.h         |  1 +
>   drivers/net/ethernet/intel/igb/igb_ethtool.c |  5 ++++-
>   drivers/net/ethernet/intel/igb/igb_main.c    | 16 ++++++++++++++--
>   3 files changed, 19 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
> index c2bd4f9..212d668 100644
> --- a/drivers/net/ethernet/intel/igb/igb.h
> +++ b/drivers/net/ethernet/intel/igb/igb.h
> @@ -540,6 +540,7 @@ void igb_ptp_rx_pktstamp(struct igb_q_vector *q_vector, unsigned char *va,
>   			 struct sk_buff *skb);
>   int igb_ptp_set_ts_config(struct net_device *netdev, struct ifreq *ifr);
>   int igb_ptp_get_ts_config(struct net_device *netdev, struct ifreq *ifr);
> +void igb_set_flag_queue_pairs(struct igb_adapter *, const u32);
>   #ifdef CONFIG_IGB_HWMON
>   void igb_sysfs_exit(struct igb_adapter *adapter);
>   int igb_sysfs_init(struct igb_adapter *adapter);
> diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
> index d5673eb..0afc091 100644
> --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
> +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
> @@ -2991,6 +2991,7 @@ static int igb_set_channels(struct net_device *netdev,
>   {
>   	struct igb_adapter *adapter = netdev_priv(netdev);
>   	unsigned int count = ch->combined_count;
> +	unsigned int max_combined = 0;
>   
>   	/* Verify they are not requesting separate vectors */
>   	if (!count || ch->rx_count || ch->tx_count)
> @@ -3001,11 +3002,13 @@ static int igb_set_channels(struct net_device *netdev,
>   		return -EINVAL;
>   
>   	/* Verify the number of channels doesn't exceed hw limits */
> -	if (count > igb_max_channels(adapter))
> +	max_combined = igb_max_channels(adapter);
> +	if (count > max_combined)
>   		return -EINVAL;
>   
>   	if (count != adapter->rss_queues) {
>   		adapter->rss_queues = count;
> +		igb_set_flag_queue_pairs(adapter, max_combined);
>   
>   		/* Hardware has to reinitialize queues and interrupts to
>   		 * match the new configuration.
> diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
> index f287186..59dc2b4 100644
> --- a/drivers/net/ethernet/intel/igb/igb_main.c
> +++ b/drivers/net/ethernet/intel/igb/igb_main.c
> @@ -1205,10 +1205,14 @@ static int igb_alloc_q_vector(struct igb_adapter *adapter,
>   
>   	/* allocate q_vector and rings */
>   	q_vector = adapter->q_vector[v_idx];
> -	if (!q_vector)
> +	if (!q_vector) {
>   		q_vector = kzalloc(size, GFP_KERNEL);
> -	else
> +	} else if (size > ksize(q_vector)) {
> +		kfree_rcu(q_vector, rcu);
> +		q_vector = kzalloc(size, GFP_KERNEL);
> +	} else {
>   		memset(q_vector, 0, size);
> +	}
>   	if (!q_vector)
>   		return -ENOMEM;
>   
> @@ -2888,6 +2892,14 @@ static void igb_init_queue_configuration(struct igb_adapter *adapter)
>   
>   	adapter->rss_queues = min_t(u32, max_rss_queues, num_online_cpus());
>   
> +	igb_set_flag_queue_pairs(adapter, max_rss_queues);
> +}
> +
> +void igb_set_flag_queue_pairs(struct igb_adapter *adapter,
> +			      const u32 max_rss_queues)
> +{
> +	struct e1000_hw *hw = &adapter->hw;
> +
>   	/* Determine if we need to pair queues. */
>   	switch (hw->mac.type) {
>   	case e1000_82575:
> 


More information about the Intel-wired-lan mailing list