summaryrefslogtreecommitdiff
path: root/drivers/rmnet
diff options
context:
space:
mode:
authorSubash Abhinov Kasiviswanathan <subashab@codeaurora.org>2019-11-29 16:35:09 -0700
committerSubash Abhinov Kasiviswanathan <subashab@codeaurora.org>2019-11-29 16:52:08 -0700
commitbe89ad02e5d82ec54a304c1e947ce66055fc59de (patch)
treef18553b1de378b261ab87ade889fedf518c36dc1 /drivers/rmnet
parent74ba58976f508d25ca187bf9fdaa1ec981745e72 (diff)
downloaddata-kernel-be89ad02e5d82ec54a304c1e947ce66055fc59de.tar.gz
drivers: shs: Protect all file system operations using shs ep lock
This add synchronization between the file system operations and the updates which occur within the shs workqueue. Fixes the following when there are two instances of userspace handlers running and are killed together- <6> Unable to handle kernel paging request at virtual address ffffffbfadadadb4 <2> pc : __free_pages+0x24/0xc0 <2> lr : free_pages+0x38/0x48 <2> Call trace: <2> __free_pages+0x24/0xc0 <2> free_pages+0x38/0x48 <2> rmnet_shs_release_caps+0x9c/0xb0 [rmnet_shs] <2> close_pdeo+0x94/0x120 <2> proc_reg_release+0x64/0x88 <2> __fput+0xdc/0x1d8 <2> ____fput+0x1c/0x28 <2> task_work_run+0x48/0xd0 <2> do_notify_resume+0x950/0x1160 <2> work_pending+0x8/0x14 CRs-fixed: 2576578 Change-Id: I67d1fc4d1f3c93d4497e988c2118c410091f0dd2 Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
Diffstat (limited to 'drivers/rmnet')
-rw-r--r--drivers/rmnet/shs/rmnet_shs_wq.c10
-rw-r--r--drivers/rmnet/shs/rmnet_shs_wq.h6
-rw-r--r--drivers/rmnet/shs/rmnet_shs_wq_mem.c61
3 files changed, 65 insertions, 12 deletions
diff --git a/drivers/rmnet/shs/rmnet_shs_wq.c b/drivers/rmnet/shs/rmnet_shs_wq.c
index 60653bf..4c69b57 100644
--- a/drivers/rmnet/shs/rmnet_shs_wq.c
+++ b/drivers/rmnet/shs/rmnet_shs_wq.c
@@ -2194,3 +2194,13 @@ u64 rmnet_shs_wq_get_max_allowed_pps(u16 cpu)
return rmnet_shs_cpu_rx_max_pps_thresh[cpu];
}
+
+void rmnet_shs_wq_ep_lock_bh(void)
+{
+ spin_lock_bh(&rmnet_shs_ep_lock);
+}
+
+void rmnet_shs_wq_ep_unlock_bh(void)
+{
+ spin_unlock_bh(&rmnet_shs_ep_lock);
+}
diff --git a/drivers/rmnet/shs/rmnet_shs_wq.h b/drivers/rmnet/shs/rmnet_shs_wq.h
index ed37dc8..0d86200 100644
--- a/drivers/rmnet/shs/rmnet_shs_wq.h
+++ b/drivers/rmnet/shs/rmnet_shs_wq.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2019, 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
@@ -285,4 +285,8 @@ int rmnet_shs_wq_try_to_move_flow(u16 cur_cpu, u16 dest_cpu, u32 hash_to_move,
int rmnet_shs_wq_set_flow_segmentation(u32 hash_to_set, u8 seg_enable);
+void rmnet_shs_wq_ep_lock_bh(void);
+
+void rmnet_shs_wq_ep_unlock_bh(void);
+
#endif /*_RMNET_SHS_WQ_H_*/
diff --git a/drivers/rmnet/shs/rmnet_shs_wq_mem.c b/drivers/rmnet/shs/rmnet_shs_wq_mem.c
index e80d424..56b1c34 100644
--- a/drivers/rmnet/shs/rmnet_shs_wq_mem.c
+++ b/drivers/rmnet/shs/rmnet_shs_wq_mem.c
@@ -49,13 +49,14 @@ static int rmnet_shs_vm_fault(struct vm_fault *vmf)
struct page *page = NULL;
struct rmnet_shs_mmap_info *info;
-
+ rmnet_shs_wq_ep_lock_bh();
info = (struct rmnet_shs_mmap_info *) vmf->vma->vm_private_data;
if (info->data) {
page = virt_to_page(info->data);
get_page(page);
vmf->page = page;
}
+ rmnet_shs_wq_ep_unlock_bh();
return 0;
}
@@ -80,13 +81,16 @@ static int rmnet_shs_open_caps(struct inode *inode, struct file *filp)
struct rmnet_shs_mmap_info *info;
rm_err("%s", "SHS_MEM: rmnet_shs_open - entry\n");
+
+ rmnet_shs_wq_ep_lock_bh();
if (!cap_shared) {
- info = kzalloc(sizeof(struct rmnet_shs_mmap_info), GFP_KERNEL);
+ info = kzalloc(sizeof(struct rmnet_shs_mmap_info), GFP_ATOMIC);
if (!info) {
+ rmnet_shs_wq_ep_unlock_bh();
rm_err("%s", "SHS_MEM: rmnet_shs_open - FAILED\n");
return -ENOMEM;
}
- info->data = (char *)get_zeroed_page(GFP_KERNEL);
+ info->data = (char *)get_zeroed_page(GFP_ATOMIC);
cap_shared = info;
rm_err("SHS_MEM: virt_to_phys = 0x%llx cap_shared = 0x%llx\n",
(unsigned long long)virt_to_phys((void *)info),
@@ -94,6 +98,7 @@ static int rmnet_shs_open_caps(struct inode *inode, struct file *filp)
}
filp->private_data = cap_shared;
+ rmnet_shs_wq_ep_unlock_bh();
rm_err("%s", "SHS_MEM: rmnet_shs_open - OK\n");
@@ -105,19 +110,24 @@ static int rmnet_shs_open_g_flows(struct inode *inode, struct file *filp)
struct rmnet_shs_mmap_info *info;
rm_err("%s", "SHS_MEM: rmnet_shs_open g_flows - entry\n");
+
+ rmnet_shs_wq_ep_lock_bh();
if (!gflow_shared) {
- info = kzalloc(sizeof(struct rmnet_shs_mmap_info), GFP_KERNEL);
+ info = kzalloc(sizeof(struct rmnet_shs_mmap_info), GFP_ATOMIC);
if (!info) {
+ rmnet_shs_wq_ep_unlock_bh();
rm_err("%s", "SHS_MEM: rmnet_shs_open - FAILED\n");
return -ENOMEM;
}
- info->data = (char *)get_zeroed_page(GFP_KERNEL);
+ info->data = (char *)get_zeroed_page(GFP_ATOMIC);
gflow_shared = info;
rm_err("SHS_MEM: virt_to_phys = 0x%llx gflow_shared = 0x%llx\n",
(unsigned long long)virt_to_phys((void *)info),
(unsigned long long)virt_to_phys((void *)gflow_shared));
}
filp->private_data = gflow_shared;
+ rmnet_shs_wq_ep_unlock_bh();
+
return 0;
}
@@ -126,34 +136,42 @@ static int rmnet_shs_open_ss_flows(struct inode *inode, struct file *filp)
struct rmnet_shs_mmap_info *info;
rm_err("%s", "SHS_MEM: rmnet_shs_open ss_flows - entry\n");
+
+ rmnet_shs_wq_ep_lock_bh();
if (!ssflow_shared) {
- info = kzalloc(sizeof(struct rmnet_shs_mmap_info), GFP_KERNEL);
+ info = kzalloc(sizeof(struct rmnet_shs_mmap_info), GFP_ATOMIC);
if (!info) {
+ rmnet_shs_wq_ep_unlock_bh();
rm_err("%s", "SHS_MEM: rmnet_shs_open - FAILED\n");
return -ENOMEM;
}
- info->data = (char *)get_zeroed_page(GFP_KERNEL);
+ info->data = (char *)get_zeroed_page(GFP_ATOMIC);
ssflow_shared = info;
rm_err("SHS_MEM: virt_to_phys = 0x%llx ssflow_shared = 0x%llx\n",
(unsigned long long)virt_to_phys((void *)info),
(unsigned long long)virt_to_phys((void *)ssflow_shared));
}
filp->private_data = ssflow_shared;
+ rmnet_shs_wq_ep_unlock_bh();
+
return 0;
}
static ssize_t rmnet_shs_read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
struct rmnet_shs_mmap_info *info;
- int ret;
+ int ret = 0;
rm_err("%s", "SHS_MEM: rmnet_shs_read - entry\n");
+
+ rmnet_shs_wq_ep_lock_bh();
info = filp->private_data;
ret = min_t(size_t, len, RMNET_SHS_BUFFER_SIZE);
if (copy_to_user(buf, info->data, ret))
ret = -EFAULT;
+ rmnet_shs_wq_ep_unlock_bh();
- return 0;
+ return ret;
}
static ssize_t rmnet_shs_write(struct file *filp, const char __user *buf, size_t len, loff_t *off)
@@ -162,12 +180,17 @@ static ssize_t rmnet_shs_write(struct file *filp, const char __user *buf, size_t
int ret;
rm_err("%s", "SHS_MEM: rmnet_shs_write - entry\n");
+
+ rmnet_shs_wq_ep_lock_bh();
info = filp->private_data;
ret = min_t(size_t, len, RMNET_SHS_BUFFER_SIZE);
if (copy_from_user(info->data, buf, ret))
- return -EFAULT;
+ ret = -EFAULT;
else
- return len;
+ ret = len;
+ rmnet_shs_wq_ep_unlock_bh();
+
+ return ret;
}
static int rmnet_shs_release_caps(struct inode *inode, struct file *filp)
@@ -175,6 +198,8 @@ static int rmnet_shs_release_caps(struct inode *inode, struct file *filp)
struct rmnet_shs_mmap_info *info;
rm_err("%s", "SHS_MEM: rmnet_shs_release - entry\n");
+
+ rmnet_shs_wq_ep_lock_bh();
if (cap_shared) {
info = filp->private_data;
cap_shared = NULL;
@@ -182,6 +207,8 @@ static int rmnet_shs_release_caps(struct inode *inode, struct file *filp)
kfree(info);
filp->private_data = NULL;
}
+ rmnet_shs_wq_ep_unlock_bh();
+
return 0;
}
@@ -190,6 +217,8 @@ static int rmnet_shs_release_g_flows(struct inode *inode, struct file *filp)
struct rmnet_shs_mmap_info *info;
rm_err("%s", "SHS_MEM: rmnet_shs_release - entry\n");
+
+ rmnet_shs_wq_ep_lock_bh();
if (gflow_shared) {
info = filp->private_data;
gflow_shared = NULL;
@@ -197,6 +226,8 @@ static int rmnet_shs_release_g_flows(struct inode *inode, struct file *filp)
kfree(info);
filp->private_data = NULL;
}
+ rmnet_shs_wq_ep_unlock_bh();
+
return 0;
}
@@ -205,6 +236,8 @@ static int rmnet_shs_release_ss_flows(struct inode *inode, struct file *filp)
struct rmnet_shs_mmap_info *info;
rm_err("%s", "SHS_MEM: rmnet_shs_release - entry\n");
+
+ rmnet_shs_wq_ep_lock_bh();
if (ssflow_shared) {
info = filp->private_data;
ssflow_shared = NULL;
@@ -212,6 +245,8 @@ static int rmnet_shs_release_ss_flows(struct inode *inode, struct file *filp)
kfree(info);
filp->private_data = NULL;
}
+ rmnet_shs_wq_ep_unlock_bh();
+
return 0;
}
@@ -607,9 +642,11 @@ void rmnet_shs_wq_mem_init(void)
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);
+ rmnet_shs_wq_ep_lock_bh();
cap_shared = NULL;
gflow_shared = NULL;
ssflow_shared = NULL;
+ rmnet_shs_wq_ep_unlock_bh();
}
/* Remove shs files and folders from proc fs */
@@ -620,7 +657,9 @@ void rmnet_shs_wq_mem_deinit(void)
remove_proc_entry(RMNET_SHS_PROC_SS_FLOWS, shs_proc_dir);
remove_proc_entry(RMNET_SHS_PROC_DIR, NULL);
+ rmnet_shs_wq_ep_lock_bh();
cap_shared = NULL;
gflow_shared = NULL;
ssflow_shared = NULL;
+ rmnet_shs_wq_ep_unlock_bh();
}