1 #include <linux/kernel.h>
2 #include <linux/module.h>
3 #include <linux/sched.h>
4 #include <linux/stop_machine.h>
5 #include <linux/slab.h>
6 #include <kprobe/swap_kprobes.h>
7 #include <ksyms/ksyms.h>
8 #include <master/swap_initializer.h>
9 #include <us_manager/callbacks.h>
10 #include "task_data.h"
12 /* lower bits are used as flags */
13 #define TD_MAGIC_MASK 0xfffffff0
14 #define TD_FLAGS_MASK (~TD_MAGIC_MASK)
16 #define __DEFINE_TD_MAGIC(m) ((m) & TD_MAGIC_MASK)
18 #define TD_MAGIC __DEFINE_TD_MAGIC(0xbebebebe)
19 #define TD_OFFSET 1 /* skip STACK_END_MAGIC */
20 #define TD_PREFIX "[TASK_DATA] "
25 } __attribute__((packed));
27 #define get_magic(td) ((td)->magic & TD_MAGIC_MASK)
28 #define get_flags(td) ((td)->magic & TD_FLAGS_MASK)
30 static int __task_data_cbs_start_h = -1;
31 static int __task_data_cbs_stop_h = -1;
33 static inline struct task_data *__td(struct task_struct *task)
35 return (struct task_data *)(end_of_stack(task) + TD_OFFSET);
38 static inline bool __td_check(struct task_data *td)
40 return (get_magic(td) == TD_MAGIC);
43 static inline void __td_init(struct task_data *td, void *data,
46 td->magic = TD_MAGIC | (flags & TD_FLAGS_MASK);
50 static inline void __td_free(struct task_data *td)
52 unsigned long flags = get_flags(td);
53 bool ok = __td_check(td);
55 /* freeing the data if consistency check fails is dangerous:
56 * better leave it as a memory leak instead */
58 if ((flags & SWAP_TD_FREE) && td->data)
65 WARN(!ok, TD_PREFIX "td(%p) check failed: %08lx", td, get_magic(td));
68 void *swap_task_data_get(struct task_struct *task, int *ok)
70 struct task_data *td = __td(task);
77 EXPORT_SYMBOL_GPL(swap_task_data_get);
79 void swap_task_data_set(struct task_struct *task, void *data,
82 struct task_data *td = __td(task);
84 __td_init(td, data, flags);
86 EXPORT_SYMBOL_GPL(swap_task_data_set);
89 static atomic_t start_flag = ATOMIC_INIT(0);
91 static int copy_process_ret_handler(struct kretprobe_instance *ri,
94 struct task_struct *task;
96 if (atomic_read(&start_flag) == 0)
99 task = (struct task_struct *)regs_return_value(regs);
101 swap_task_data_clean(task);
106 static int do_exit_handler(struct kprobe *p, struct pt_regs *regs)
108 struct task_data *td;
110 if (atomic_read(&start_flag) == 0)
119 static struct kretprobe copy_process_rp = {
120 .handler = copy_process_ret_handler
123 static struct kprobe do_exit_probe = {
124 .pre_handler = do_exit_handler
127 static int __task_data_init(void *data)
129 struct task_struct *g, *t;
131 /* set start_flags */
132 atomic_set(&start_flag, 1);
134 do_each_thread(g, t) {
135 swap_task_data_clean(t);
136 } while_each_thread(g, t);
141 static int __task_data_exit(void *data)
143 struct task_struct *g, *t;
144 struct task_data *td;
146 do_each_thread(g, t) {
149 } while_each_thread(g, t);
151 /* reset start_flags */
152 atomic_set(&start_flag, 0);
157 static void task_data_start(void)
161 ret = swap_register_kprobe(&do_exit_probe);
163 pr_err(TD_PREFIX "register on 'do_exit' failed: ret=%d\n", ret);
167 ret = swap_register_kretprobe(©_process_rp);
169 swap_unregister_kprobe(&do_exit_probe);
170 pr_err(TD_PREFIX "register on 'copy_process' failed: ret=%d\n", ret);
174 /* stop_machine: cannot get tasklist_lock from module */
175 ret = stop_machine(__task_data_init, NULL, NULL);
177 printk(TD_PREFIX "task data initialization failed: %d\n", ret);
180 static void task_data_stop(void)
184 /* stop_machine: the same here */
185 ret = stop_machine(__task_data_exit, NULL, NULL);
187 printk(TD_PREFIX "task data cleanup failed: %d\n", ret);
188 /* something went wrong: at least make sure we unregister
189 * all the installed probes */
190 swap_unregister_kprobe(&do_exit_probe);
193 swap_unregister_kretprobe(©_process_rp);
194 swap_unregister_kprobe(&do_exit_probe);
197 static int task_data_once(void)
201 sym = "copy_process";
202 copy_process_rp.kp.addr = (kprobe_opcode_t *)swap_ksyms_substr(sym);
203 if (copy_process_rp.kp.addr == NULL)
207 do_exit_probe.addr = (kprobe_opcode_t *)swap_ksyms_substr(sym);
208 if (do_exit_probe.addr == NULL)
214 pr_err(TD_PREFIX "ERROR: symbol %s(...) not found\n", sym);
218 static int task_data_init(void)
222 __task_data_cbs_start_h = us_manager_reg_cb(START_CB, task_data_start);
223 if (__task_data_cbs_start_h < 0) {
224 ret = __task_data_cbs_start_h;
225 printk(KERN_ERR TD_PREFIX "start_cb registration failed\n");
229 __task_data_cbs_stop_h = us_manager_reg_cb(STOP_CB_TD, task_data_stop);
230 if (__task_data_cbs_stop_h < 0) {
231 ret = __task_data_cbs_stop_h;
232 us_manager_unreg_cb(__task_data_cbs_start_h);
233 printk(KERN_ERR TD_PREFIX "stop_cb registration failed\n");
240 static void task_data_exit(void)
242 us_manager_unreg_cb(__task_data_cbs_start_h);
243 us_manager_unreg_cb(__task_data_cbs_stop_h);
246 SWAP_LIGHT_INIT_MODULE(task_data_once, task_data_init, task_data_exit,
249 MODULE_LICENSE("GPL");
250 MODULE_DESCRIPTION("SWAP Task Data Module");