[FIX] US probes removal synchronization 34/19034/3
authorVyacheslav Cherkashin <v.cherkashin@samsung.com>
Fri, 4 Apr 2014 09:56:26 +0000 (13:56 +0400)
committerDmitry Kovalenko <d.kovalenko@samsung.com>
Mon, 7 Apr 2014 05:55:03 +0000 (22:55 -0700)
Change-Id: Iacb0cafaa55925e218451e2890ba3249aba23914
Signed-off-by: Vyacheslav Cherkashin <v.cherkashin@samsung.com>
us_manager/helper.c
us_manager/pf/pf_group.c
us_manager/sspt/sspt_proc.c
us_manager/sspt/sspt_proc.h

index 9ce30b6..c733811 100644 (file)
@@ -36,6 +36,9 @@ struct task_struct;
 
 struct task_struct *check_task(struct task_struct *task);
 
+static atomic_t stop_flag = ATOMIC_INIT(0);
+
+
 /*
  ******************************************************************************
  *                               do_page_fault()                              *
@@ -103,6 +106,7 @@ static void unregister_mf(void)
  *                              copy_process()                                *
  ******************************************************************************
  */
+static atomic_t copy_process_cnt = ATOMIC_INIT(0);
 
 static void recover_child(struct task_struct *child_task, struct sspt_proc *proc)
 {
@@ -112,10 +116,25 @@ static void recover_child(struct task_struct *child_task, struct sspt_proc *proc
 
 static void rm_uprobes_child(struct task_struct *task)
 {
-       struct sspt_proc *proc = sspt_proc_get_by_task(current);
-       if(proc) {
+       struct sspt_proc *proc;
+
+       sspt_proc_write_lock();
+
+       proc = sspt_proc_get_by_task(current);
+       if (proc)
                recover_child(task, proc);
-       }
+
+       sspt_proc_write_unlock();
+}
+
+static int entry_handler_cp(struct kretprobe_instance *ri, struct pt_regs *regs)
+{
+       atomic_inc(&copy_process_cnt);
+
+       if (atomic_read(&stop_flag))
+               call_mm_release(current);
+
+       return 0;
 }
 
 /* Delete uprobs in children at fork */
@@ -130,10 +149,13 @@ static int ret_handler_cp(struct kretprobe_instance *ri, struct pt_regs *regs)
                rm_uprobes_child(task);
        }
 out:
+       atomic_dec(&copy_process_cnt);
+
        return 0;
 }
 
 static struct kretprobe cp_kretprobe = {
+       .entry_handler = entry_handler_cp,
        .handler = ret_handler_cp,
 };
 
@@ -150,7 +172,11 @@ static int register_cp(void)
 
 static void unregister_cp(void)
 {
-       dbi_unregister_kretprobe(&cp_kretprobe);
+       dbi_unregister_kretprobe_top(&cp_kretprobe, 0);
+       do {
+               synchronize_sched();
+       } while (atomic_read(&copy_process_cnt));
+       dbi_unregister_kretprobe_bottom(&cp_kretprobe);
 }
 
 
@@ -214,7 +240,10 @@ struct unmap_data {
        size_t len;
 };
 
-static void remove_unmap_probes(struct sspt_proc *proc, struct unmap_data *umd)
+static atomic_t unmap_cnt = ATOMIC_INIT(0);
+
+static void __remove_unmap_probes(struct sspt_proc *proc,
+                                 struct unmap_data *umd)
 {
        struct task_struct *task = proc->task;
        unsigned long start = umd->start;
@@ -242,15 +271,34 @@ static void remove_unmap_probes(struct sspt_proc *proc, struct unmap_data *umd)
        }
 }
 
+static void remove_unmap_probes(struct task_struct *task,
+                               struct unmap_data *umd)
+{
+       struct sspt_proc *proc;
+
+       sspt_proc_write_lock();
+
+       proc = sspt_proc_get_by_task(task);
+       if (proc)
+               __remove_unmap_probes(proc, umd);
+
+       sspt_proc_write_unlock();
+}
 
 static int entry_handler_unmap(struct kretprobe_instance *ri,
                               struct pt_regs *regs)
 {
        struct unmap_data *data = (struct unmap_data *)ri->data;
+       struct task_struct *task = current->group_leader;
+
+       atomic_inc(&unmap_cnt);
 
        data->start = swap_get_karg(regs, 1);
        data->len = (size_t)swap_get_karg(regs, 2);
 
+       if (!is_kthread(task) && atomic_read(&stop_flag))
+               remove_unmap_probes(task, data);
+
        return 0;
 }
 
@@ -258,16 +306,15 @@ static int ret_handler_unmap(struct kretprobe_instance *ri,
                             struct pt_regs *regs)
 {
        struct task_struct *task;
-       struct sspt_proc *proc;
 
        task = current->group_leader;
        if (is_kthread(task) ||
            get_regs_ret_val(regs))
                return 0;
 
-       proc = sspt_proc_get_by_task(task);
-       if (proc)
-               remove_unmap_probes(proc, (struct unmap_data *)ri->data);
+       remove_unmap_probes(task, (struct unmap_data *)ri->data);
+
+       atomic_dec(&unmap_cnt);
 
        return 0;
 }
@@ -291,7 +338,11 @@ static int register_unmap(void)
 
 static void unregister_unmap(void)
 {
-       dbi_unregister_kretprobe(&unmap_kretprobe);
+       dbi_unregister_kretprobe_top(&unmap_kretprobe, 0);
+       do {
+               synchronize_sched();
+       } while (atomic_read(&unmap_cnt));
+       dbi_unregister_kretprobe_bottom(&unmap_kretprobe);
 }
 
 
@@ -358,6 +409,8 @@ int register_helper(void)
 {
        int ret = 0;
 
+       atomic_set(&stop_flag, 0);
+
        /* install probe on 'do_munmap' to detect when for remove US probes */
        ret = register_unmap();
        if (ret)
@@ -406,6 +459,7 @@ unreg_unmap:
 void unregister_helper_top(void)
 {
        unregister_mf();
+       atomic_set(&stop_flag, 1);
 }
 
 void unregister_helper_bottom(void)
index b8f01df..042c907 100644 (file)
@@ -271,6 +271,7 @@ void call_page_fault(struct task_struct *task, unsigned long page_addr)
        }
 }
 
+/* called with sspt_proc_write_lock() */
 void uninstall_proc(struct sspt_proc *proc)
 {
        struct task_struct *task = proc->task;
@@ -297,10 +298,14 @@ void call_mm_release(struct task_struct *task)
 {
        struct sspt_proc *proc;
 
+       sspt_proc_write_lock();
+
        proc = sspt_proc_get_by_task(task);
        if (proc)
                /* TODO: uninstall_proc - is not atomic context */
                uninstall_proc(proc);
+
+       sspt_proc_write_unlock();
 }
 
 void uninstall_page(unsigned long addr)
@@ -346,8 +351,10 @@ static void on_each_uninstall_proc(struct sspt_proc *proc, void *data)
 
 void uninstall_all(void)
 {
-       wait_proc_lock();
+       sspt_proc_write_lock();
        on_each_proc_no_lock(on_each_uninstall_proc, NULL);
+       sspt_proc_write_unlock();
+
        clean_pfg();
 }
 
index 7330fc2..f769332 100644 (file)
        }
 
 static LIST_HEAD(proc_probes_list);
-static DEFINE_SPINLOCK(proc_lock);
+static DEFINE_RWLOCK(sspt_proc_rwlock);
+
+void sspt_proc_read_lock(void)
+{
+       read_lock(&sspt_proc_rwlock);
+}
+
+void sspt_proc_read_unlock(void)
+{
+       read_unlock(&sspt_proc_rwlock);
+}
+
+void sspt_proc_write_lock(void)
+{
+       write_lock(&sspt_proc_rwlock);
+}
+
+void sspt_proc_write_unlock(void)
+{
+       write_unlock(&sspt_proc_rwlock);
+}
+
 
 struct sspt_proc *sspt_proc_create(struct task_struct *task, void *priv)
 {
@@ -83,14 +104,13 @@ struct sspt_proc *sspt_proc_create(struct task_struct *task, void *priv)
        return proc;
 }
 
+/* called with sspt_proc_write_lock() */
 void sspt_proc_free(struct sspt_proc *proc)
 {
        struct sspt_file *file, *n;
 
        /* delete from list */
-       spin_lock(&proc_lock);
        list_del(&proc->list);
-       spin_unlock(&proc_lock);
 
        list_for_each_entry_safe(file, n, &proc->file_list, list) {
                list_del(&file->list);
@@ -128,18 +148,12 @@ void on_each_proc_no_lock(void (*func)(struct sspt_proc *, void *), void *data)
 
 void on_each_proc(void (*func)(struct sspt_proc *, void *), void *data)
 {
-       spin_lock(&proc_lock);
+       sspt_proc_read_lock();
        on_each_proc_no_lock(func, data);
-       spin_unlock(&proc_lock);
+       sspt_proc_read_unlock();
 }
 EXPORT_SYMBOL_GPL(on_each_proc);
 
-void wait_proc_lock(void)
-{
-       spin_lock(&proc_lock);
-       spin_unlock(&proc_lock);
-}
-
 struct sspt_proc *sspt_proc_get_by_task_or_new(struct task_struct *task,
                                               void *priv)
 {
index 5f98644..5fa7528 100644 (file)
@@ -54,7 +54,6 @@ void sspt_proc_free(struct sspt_proc *proc);
 void on_each_proc_no_lock(void (*func)(struct sspt_proc *, void *),
                          void *data);
 void on_each_proc(void (*func)(struct sspt_proc *, void *), void *data);
-void wait_proc_lock(void);
 
 struct sspt_proc *sspt_proc_get_by_task(struct task_struct *task);
 struct sspt_proc *sspt_proc_get_by_task_or_new(struct task_struct *task,
@@ -74,4 +73,10 @@ int sspt_proc_get_files_by_region(struct sspt_proc *proc,
                                  unsigned long start, size_t len);
 void sspt_proc_insert_files(struct sspt_proc *proc, struct list_head *head);
 
+void sspt_proc_read_lock(void);
+void sspt_proc_read_unlock(void);
+void sspt_proc_write_lock(void);
+void sspt_proc_write_unlock(void);
+
+
 #endif /* __SSPT_PROC__ */