summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Peng <robinpeng@google.com>2020-05-12 17:52:57 +0800
committerRobin Peng <robinpeng@google.com>2020-05-12 17:52:57 +0800
commit3b1bb7c4a63e74a83e928ebfe8e71b83239323d6 (patch)
tree77ecddf2b9f5b2558a75d1bd539a7e79ce86f666
parent10ec95724fcf6572bf3f810d307b507038173cbc (diff)
parent53e29353b1241bdaecfba8c90837c87430af47e3 (diff)
downloaddata-kernel-3b1bb7c4a63e74a83e928ebfe8e71b83239323d6.tar.gz
Merge branch 'LA.UM.9.12.R2.10.00.00.685.004' into qcom-msm-4.19-7250
Change-Id: Id5c7b76427c4e3368bf16fdd9badec699dc5b158
-rw-r--r--drivers/rmnet/shs/rmnet_shs_config.h1
-rwxr-xr-xdrivers/rmnet/shs/rmnet_shs_main.c74
-rw-r--r--drivers/rmnet/shs/rmnet_shs_wq.c3
-rw-r--r--drivers/rmnet/shs/rmnet_shs_wq_mem.c9
4 files changed, 85 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 0f6ea40..dec38c4 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];
@@ -1482,6 +1491,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();
@@ -1540,6 +1607,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;
@@ -1563,6 +1631,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;
}
@@ -1846,6 +1918,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 2678d8b..f300c22 100644
--- a/drivers/rmnet/shs/rmnet_shs_wq.c
+++ b/drivers/rmnet/shs/rmnet_shs_wq.c
@@ -2153,8 +2153,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;
diff --git a/drivers/rmnet/shs/rmnet_shs_wq_mem.c b/drivers/rmnet/shs/rmnet_shs_wq_mem.c
index 062edb7..e914d78 100644
--- a/drivers/rmnet/shs/rmnet_shs_wq_mem.c
+++ b/drivers/rmnet/shs/rmnet_shs_wq_mem.c
@@ -955,8 +955,17 @@ void rmnet_shs_wq_mem_update_cached_netdevs(void)
/* Creates the proc folder and files for shs shared memory */
void rmnet_shs_wq_mem_init(void)
{
+ kuid_t shs_uid;
+ kgid_t shs_gid;
+
shs_proc_dir = proc_mkdir("shs", NULL);
+ shs_uid = make_kuid(&init_user_ns, 1001);
+ shs_gid = make_kgid(&init_user_ns, 1001);
+
+ if (uid_valid(shs_uid) && gid_valid(shs_gid))
+ proc_set_user(shs_proc_dir, shs_uid, shs_gid);
+
proc_create(RMNET_SHS_PROC_CAPS, 0644, shs_proc_dir, &rmnet_shs_caps_fops);
proc_create(RMNET_SHS_PROC_G_FLOWS, 0644, shs_proc_dir, &rmnet_shs_g_flows_fops);
proc_create(RMNET_SHS_PROC_SS_FLOWS, 0644, shs_proc_dir, &rmnet_shs_ss_flows_fops);