Tizen 2.4.0 rev3 SDK Public Release
[kernel/swap-modules.git] / task_data / task_data.c
index 1610284..cc32765 100644 (file)
@@ -6,6 +6,7 @@
 #include <kprobe/swap_kprobes.h>
 #include <ksyms/ksyms.h>
 #include <master/swap_initializer.h>
+#include <us_manager/callbacks.h>
 #include "task_data.h"
 
 /* lower bits are used as flags */
@@ -26,6 +27,9 @@ struct task_data {
 #define get_magic(td) ((td)->magic & TD_MAGIC_MASK)
 #define get_flags(td) ((td)->magic & TD_FLAGS_MASK)
 
+static int __task_data_cbs_start_h = -1;
+static int __task_data_cbs_stop_h = -1;
+
 static inline struct task_data *__td(struct task_struct *task)
 {
        return (struct task_data *)(end_of_stack(task) + TD_OFFSET);
@@ -81,13 +85,19 @@ void swap_task_data_set(struct task_struct *task, void *data,
 }
 EXPORT_SYMBOL_GPL(swap_task_data_set);
 
+
+static atomic_t start_flag = ATOMIC_INIT(0);
+
 static int copy_process_ret_handler(struct kretprobe_instance *ri,
                                    struct pt_regs *regs)
 {
        struct task_struct *task;
 
+       if (atomic_read(&start_flag) == 0)
+               return 0;
+
        task = (struct task_struct *)regs_return_value(regs);
-       if (task)
+       if (!IS_ERR(task))
                swap_task_data_clean(task);
 
        return 0;
@@ -95,8 +105,12 @@ static int copy_process_ret_handler(struct kretprobe_instance *ri,
 
 static int do_exit_handler(struct kprobe *p, struct pt_regs *regs)
 {
-       struct task_data *td = __td(current);
+       struct task_data *td;
+
+       if (atomic_read(&start_flag) == 0)
+               return 0;
 
+       td = __td(current);
        __td_free(td);
 
        return 0;
@@ -113,42 +127,15 @@ static struct kprobe do_exit_probe = {
 static int __task_data_init(void *data)
 {
        struct task_struct *g, *t;
-       unsigned long addr;
-       int ret;
-
-       addr = swap_ksyms_substr("copy_process");
-       if (addr == 0) {
-               printk(TD_PREFIX "Cannot find address for copy_process\n");
-               return -EINVAL;
-       }
-       copy_process_rp.kp.addr = (kprobe_opcode_t *)addr;
-       ret = swap_register_kretprobe(&copy_process_rp);
-       if (ret)
-               goto reg_failed;
 
-       addr = swap_ksyms_substr("do_exit");
-       if (addr == 0) {
-               printk(TD_PREFIX "Cannot find address for do_exit\n");
-               return -EINVAL;
-       }
-       do_exit_probe.addr = (kprobe_opcode_t *)addr;
-       ret = swap_register_kprobe(&do_exit_probe);
-       if (ret)
-               goto unreg_copy_process;
+       /* set start_flags */
+       atomic_set(&start_flag, 1);
 
        do_each_thread(g, t) {
                swap_task_data_clean(t);
        } while_each_thread(g, t);
 
        return 0;
-
-unreg_copy_process:
-       swap_unregister_kretprobe(&copy_process_rp);
-
-reg_failed:
-       printk(TD_PREFIX "0x%lx: probe registration failed\n", addr);
-
-       return ret;
 }
 
 static int __task_data_exit(void *data)
@@ -156,46 +143,108 @@ static int __task_data_exit(void *data)
        struct task_struct *g, *t;
        struct task_data *td;
 
-       swap_unregister_kprobe(&do_exit_probe);
-       swap_unregister_kretprobe(&copy_process_rp);
-
        do_each_thread(g, t) {
                td = __td(t);
                __td_free(td);
        } while_each_thread(g, t);
 
+       /* reset start_flags */
+       atomic_set(&start_flag, 0);
+
        return 0;
 }
 
-static int task_data_init(void)
+static void task_data_start(void)
 {
        int ret;
 
+       ret = swap_register_kprobe(&do_exit_probe);
+       if (ret) {
+               pr_err(TD_PREFIX "register on 'do_exit' failed: ret=%d\n", ret);
+               return;
+       }
+
+       ret = swap_register_kretprobe(&copy_process_rp);
+       if (ret) {
+               swap_unregister_kprobe(&do_exit_probe);
+               pr_err(TD_PREFIX "register on 'copy_process' failed: ret=%d\n", ret);
+               return;
+       }
+
        /* stop_machine: cannot get tasklist_lock from module */
        ret = stop_machine(__task_data_init, NULL, NULL);
        if (ret)
                printk(TD_PREFIX "task data initialization failed: %d\n", ret);
-
-       return ret;
 }
 
-static void task_data_exit(void)
+static void task_data_stop(void)
 {
        int ret;
 
        /* stop_machine: the same here */
-       ret = stop_machine(__task_data_exit, &copy_process_rp, NULL);
+       ret = stop_machine(__task_data_exit, NULL, NULL);
        if (ret) {
                printk(TD_PREFIX "task data cleanup failed: %d\n", ret);
                /* something went wrong: at least make sure we unregister
                 * all the installed probes */
                swap_unregister_kprobe(&do_exit_probe);
-               swap_unregister_kretprobe(&copy_process_rp);
        }
+
+       swap_unregister_kretprobe(&copy_process_rp);
+       swap_unregister_kprobe(&do_exit_probe);
 }
 
-SWAP_LIGHT_INIT_MODULE(NULL, task_data_init, task_data_exit, NULL, NULL);
+static int task_data_once(void)
+{
+       const char *sym;
+
+       sym = "copy_process";
+       copy_process_rp.kp.addr = (kprobe_opcode_t *)swap_ksyms_substr(sym);
+       if (copy_process_rp.kp.addr == NULL)
+               goto not_found;
+
+       sym = "do_exit";
+       do_exit_probe.addr = (kprobe_opcode_t *)swap_ksyms_substr(sym);
+       if (do_exit_probe.addr == NULL)
+               goto not_found;
+
+       return 0;
+
+not_found:
+       pr_err(TD_PREFIX "ERROR: symbol %s(...) not found\n", sym);
+       return -ESRCH;
+}
+
+static int task_data_init(void)
+{
+       int ret = 0;
+
+       __task_data_cbs_start_h = us_manager_reg_cb(START_CB, task_data_start);
+       if (__task_data_cbs_start_h < 0) {
+               ret = __task_data_cbs_start_h;
+               printk(KERN_ERR TD_PREFIX "start_cb registration failed\n");
+               goto out;
+       }
+
+       __task_data_cbs_stop_h = us_manager_reg_cb(STOP_CB_TD, task_data_stop);
+       if (__task_data_cbs_stop_h < 0) {
+               ret = __task_data_cbs_stop_h;
+               us_manager_unreg_cb(__task_data_cbs_start_h);
+               printk(KERN_ERR TD_PREFIX "stop_cb registration failed\n");
+       }
+
+out:
+       return ret;
+}
+
+static void task_data_exit(void)
+{
+       us_manager_unreg_cb(__task_data_cbs_start_h);
+       us_manager_unreg_cb(__task_data_cbs_stop_h);
+}
 
+SWAP_LIGHT_INIT_MODULE(task_data_once, task_data_init, task_data_exit,
+                      NULL, NULL);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("SWAP Task Data Module");