From: Vyacheslav Cherkashin Date: Fri, 4 Apr 2014 09:56:26 +0000 (+0400) Subject: [FIX] US probes removal synchronization X-Git-Tag: Tizen_SDK_2.3~95 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F34%2F19034%2F3;p=kernel%2Fswap-modules.git [FIX] US probes removal synchronization Change-Id: Iacb0cafaa55925e218451e2890ba3249aba23914 Signed-off-by: Vyacheslav Cherkashin --- diff --git a/us_manager/helper.c b/us_manager/helper.c index 9ce30b6..c733811 100644 --- a/us_manager/helper.c +++ b/us_manager/helper.c @@ -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(©_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(©_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(©_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) diff --git a/us_manager/pf/pf_group.c b/us_manager/pf/pf_group.c index b8f01df..042c907 100644 --- a/us_manager/pf/pf_group.c +++ b/us_manager/pf/pf_group.c @@ -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(); } diff --git a/us_manager/sspt/sspt_proc.c b/us_manager/sspt/sspt_proc.c index 7330fc2..f769332 100644 --- a/us_manager/sspt/sspt_proc.c +++ b/us_manager/sspt/sspt_proc.c @@ -56,7 +56,28 @@ } 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) { diff --git a/us_manager/sspt/sspt_proc.h b/us_manager/sspt/sspt_proc.h index 5f98644..5fa7528 100644 --- a/us_manager/sspt/sspt_proc.h +++ b/us_manager/sspt/sspt_proc.h @@ -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__ */