Commit 28207b510dca ("net: rmnet_data: Add NAPI context for rmnet_data devices") added a NAPI struct per rmnet_data device. This was to ensure that the NAPI struct is always available even if there was a hotplug. However, this seems to be leading to some races where the NAPI struct is accessed concurrently across cores. The race here is between napi_gro_receive on one core with napi_complete running on the other accessing the same NAPI struct. If napi_gro_receive runs slightly earlier, napi_complete would see that the napi->gro_list would be non NULL in __napi_complete even though it had cleared earlier and would lead to a BUG. If napi_complete runs slightly earlier, napi_gro_receive would dereference a NULL pointer even though it had assigned an skb to napi->gro_list. Fix this by using the per cpu backlog struct as the NAPI struct for queuing packets to GRO engine. Access across cores would not be a problem in case of hotplug as they would use core specific structures. CRs-Fixed: 966095 Change-Id: I831df5b93cc6ee77355f2e98af89efcffe825bd8 Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
41 lines
1.5 KiB
C
41 lines
1.5 KiB
C
/*
|
|
* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 and
|
|
* only version 2 as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* RMNET Data Virtual Network Device APIs
|
|
*
|
|
*/
|
|
|
|
#include <linux/types.h>
|
|
|
|
#ifndef _RMNET_DATA_VND_H_
|
|
#define _RMNET_DATA_VND_H_
|
|
|
|
int rmnet_vnd_do_flow_control(struct net_device *dev,
|
|
uint32_t map_flow_id,
|
|
uint16_t v4_seq,
|
|
uint16_t v6_seq,
|
|
int enable);
|
|
struct rmnet_logical_ep_conf_s *rmnet_vnd_get_le_config(struct net_device *dev);
|
|
int rmnet_vnd_get_name(int id, char *name, int name_len);
|
|
int rmnet_vnd_create_dev(int id, struct net_device **new_device,
|
|
const char *prefix);
|
|
int rmnet_vnd_free_dev(int id);
|
|
int rmnet_vnd_rx_fixup(struct sk_buff *skb, struct net_device *dev);
|
|
int rmnet_vnd_tx_fixup(struct sk_buff *skb, struct net_device *dev);
|
|
int rmnet_vnd_is_vnd(struct net_device *dev);
|
|
int rmnet_vnd_add_tc_flow(uint32_t id, uint32_t map_flow, uint32_t tc_flow);
|
|
int rmnet_vnd_del_tc_flow(uint32_t id, uint32_t map_flow, uint32_t tc_flow);
|
|
int rmnet_vnd_init(void);
|
|
void rmnet_vnd_exit(void);
|
|
struct net_device *rmnet_vnd_get_by_id(int id);
|
|
|
|
#endif /* _RMNET_DATA_VND_H_ */
|