diff options
author | Subash Abhinov Kasiviswanathan <subashab@codeaurora.org> | 2020-04-25 11:34:21 -0700 |
---|---|---|
committer | Subash Abhinov Kasiviswanathan <subashab@codeaurora.org> | 2020-04-29 11:57:11 -0700 |
commit | 41a217b8a78febda9aff502798ec5b04e1e9235d (patch) | |
tree | 25b6ca96d98e35b533447242dd70e517a85ac6dc | |
parent | fb91dea97b5113e5070dca31dcebfe3ff309bc64 (diff) | |
download | data-kernel-41a217b8a78febda9aff502798ec5b04e1e9235d.tar.gz |
drivers: rmnet: shs: Add oom handler
Add RX packet drops when out of memory reaper runs.
Remove WQ_MEM_RECLAIM from rmnet_shs_wq.
Change-Id: I4b9ff4762be272ca162beb9aa691db1c29467cbf
Acked-by: Raul Martinez <mraul@qti.qualcomm.com>
Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
-rw-r--r-- | drivers/rmnet/shs/rmnet_shs_config.h | 1 | ||||
-rwxr-xr-x | drivers/rmnet/shs/rmnet_shs_main.c | 74 | ||||
-rw-r--r-- | drivers/rmnet/shs/rmnet_shs_wq.c | 3 |
3 files changed, 76 insertions, 2 deletions
diff --git a/drivers/rmnet/shs/rmnet_shs_config.h b/drivers/rmnet/shs/rmnet_shs_config.h index e55f5f8..10b8f58 100644 --- a/drivers/rmnet/shs/rmnet_shs_config.h +++ b/drivers/rmnet/shs/rmnet_shs_config.h @@ -47,6 +47,7 @@ enum rmnet_shs_crit_err_e { RMNET_SHS_WQ_NODE_MALLOC_ERR, RMNET_SHS_WQ_NL_SOCKET_ERR, RMNET_SHS_CPU_FLOWS_BNDS_ERR, + RMNET_SHS_OUT_OF_MEM_ERR, RMNET_SHS_CRIT_ERR_MAX }; diff --git a/drivers/rmnet/shs/rmnet_shs_main.c b/drivers/rmnet/shs/rmnet_shs_main.c index 31584ec..10aceae 100755 --- a/drivers/rmnet/shs/rmnet_shs_main.c +++ b/drivers/rmnet/shs/rmnet_shs_main.c @@ -16,6 +16,7 @@ #include <net/sock.h> #include <linux/netlink.h> #include <linux/ip.h> +#include <linux/oom.h> #include <net/ip.h> #include <linux/ipv6.h> @@ -40,14 +41,22 @@ #define MIN_MS 5 #define BACKLOG_CHECK 1 +#define GET_PQUEUE(CPU) (per_cpu(softnet_data, CPU).input_pkt_queue) +#define GET_IQUEUE(CPU) (per_cpu(softnet_data, CPU).process_queue) #define GET_QTAIL(SD, CPU) (per_cpu(SD, CPU).input_queue_tail) #define GET_QHEAD(SD, CPU) (per_cpu(SD, CPU).input_queue_head) #define GET_CTIMER(CPU) rmnet_shs_cfg.core_flush[CPU].core_timer +/* Specific CPU RMNET runs on */ +#define RMNET_CPU 1 #define SKB_FLUSH 0 #define INCREMENT 1 #define DECREMENT 0 /* Local Definitions and Declarations */ +unsigned int rmnet_oom_pkt_limit __read_mostly = 5000; +module_param(rmnet_oom_pkt_limit, uint, 0644); +MODULE_PARM_DESC(rmnet_oom_pkt_limit, "Max rmnet pre-backlog"); + DEFINE_SPINLOCK(rmnet_shs_ht_splock); DEFINE_HASHTABLE(RMNET_SHS_HT, RMNET_SHS_HT_SIZE); struct rmnet_shs_cpu_node_s rmnet_shs_cpu_node_tbl[MAX_CPUS]; @@ -1439,6 +1448,64 @@ unsigned int rmnet_shs_rx_wq_exit(void) return cpu_switch; } +int rmnet_shs_drop_backlog(struct sk_buff_head *list, int cpu) +{ + struct sk_buff *skb; + struct softnet_data *sd = &per_cpu(softnet_data, cpu); + + rtnl_lock(); + while ((skb = skb_dequeue_tail(list)) != NULL) { + if (rmnet_is_real_dev_registered(skb->dev)) { + rmnet_shs_crit_err[RMNET_SHS_OUT_OF_MEM_ERR]++; + /* Increment sd and netdev drop stats*/ + atomic_long_inc(&skb->dev->rx_dropped); + input_queue_head_incr(sd); + sd->dropped++; + kfree_skb(skb); + } + } + rtnl_unlock(); + + return 0; +} + +static int rmnet_shs_oom_notify(struct notifier_block *self, + unsigned long emtpy, void *free) +{ + int input_qlen, process_qlen, cpu; + int *nfree = (int*)free; + struct sk_buff_head *process_q; + struct sk_buff_head *input_q; + + local_bh_disable(); + for_each_possible_cpu(cpu) { + + process_q = &GET_PQUEUE(cpu); + input_q = &GET_IQUEUE(cpu); + input_qlen = skb_queue_len(process_q); + process_qlen = skb_queue_len(input_q); + + if (rmnet_oom_pkt_limit && + (input_qlen + process_qlen) >= rmnet_oom_pkt_limit) { + rmnet_shs_drop_backlog(&per_cpu(softnet_data, + cpu).input_pkt_queue, cpu); + input_qlen = skb_queue_len(process_q); + process_qlen = skb_queue_len(input_q); + if (process_qlen >= rmnet_oom_pkt_limit) { + rmnet_shs_drop_backlog(process_q, cpu); + } + /* Let oom_killer know memory was freed */ + (*nfree)++; + } + } + local_bh_enable(); + return 0; +} + +static struct notifier_block rmnet_oom_nb = { + .notifier_call = rmnet_shs_oom_notify, +}; + void rmnet_shs_ps_on_hdlr(void *port) { rmnet_shs_wq_pause(); @@ -1497,6 +1564,7 @@ void rmnet_shs_dl_trl_handler(struct rmnet_map_dl_ind_trl *dltrl) void rmnet_shs_init(struct net_device *dev, struct net_device *vnd) { struct rps_map *map; + int rc; u8 num_cpu; u8 map_mask; u8 map_len; @@ -1520,6 +1588,10 @@ void rmnet_shs_init(struct net_device *dev, struct net_device *vnd) INIT_LIST_HEAD(&rmnet_shs_cpu_node_tbl[num_cpu].node_list_id); rmnet_shs_freq_init(); + rc = register_oom_notifier(&rmnet_oom_nb); + if (rc < 0) { + pr_info("Rmnet_shs_oom register failure"); + } rmnet_shs_cfg.rmnet_shs_init_complete = 1; } @@ -1803,6 +1875,8 @@ void rmnet_shs_exit(unsigned int cpu_switch) rmnet_map_dl_ind_deregister(rmnet_shs_cfg.port, &rmnet_shs_cfg.dl_mrk_ind_cb); rmnet_shs_cfg.is_reg_dl_mrk_ind = 0; + unregister_oom_notifier(&rmnet_oom_nb); + if (rmnet_shs_cfg.is_timer_init) hrtimer_cancel(&rmnet_shs_cfg.hrtimer_shs); diff --git a/drivers/rmnet/shs/rmnet_shs_wq.c b/drivers/rmnet/shs/rmnet_shs_wq.c index 53f5826..c91a743 100644 --- a/drivers/rmnet/shs/rmnet_shs_wq.c +++ b/drivers/rmnet/shs/rmnet_shs_wq.c @@ -2151,8 +2151,7 @@ void rmnet_shs_wq_init(struct net_device *dev) trace_rmnet_shs_wq_high(RMNET_SHS_WQ_INIT, RMNET_SHS_WQ_INIT_START, 0xDEF, 0xDEF, 0xDEF, 0xDEF, NULL, NULL); - rmnet_shs_wq = alloc_workqueue("rmnet_shs_wq", - WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, 1); + rmnet_shs_wq = alloc_workqueue("rmnet_shs_wq", WQ_CPU_INTENSIVE, 1); if (!rmnet_shs_wq) { rmnet_shs_crit_err[RMNET_SHS_WQ_ALLOC_WQ_ERR]++; return; |