[REFACTOR] move and rename /un/register_us_page_probe()
[kernel/swap-modules.git] / driver / us_slot_manager.c
1 #include <linux/slab.h>
2 #include <linux/hardirq.h>
3 #include <linux/sched.h>
4 #include <linux/mm.h>
5 #include <linux/mman.h>
6 #include <linux/list.h>
7 #include <dbi_insn_slots.h>
8 #include <asm/dbi_kprobes.h>
9
10 static unsigned long alloc_user_pages(struct task_struct *task, unsigned long len, unsigned long prot, unsigned long flags)
11 {
12         unsigned long ret = 0;
13         struct task_struct *otask = current;
14         struct mm_struct *mm;
15         int atomic = in_atomic();
16
17         mm = atomic ? task->active_mm : get_task_mm(task);
18         if (mm) {
19                 if (!atomic) {
20                         if (!down_write_trylock(&mm->mmap_sem)) {
21                                 rcu_read_lock();
22
23                                 up_read(&mm->mmap_sem);
24                                 down_write(&mm->mmap_sem);
25
26                                 rcu_read_unlock();
27                         }
28                 }
29                 // FIXME: its seems to be bad decision to replace 'current' pointer temporarily
30                 current_thread_info()->task = task;
31                 ret = do_mmap_pgoff(NULL, 0, len, prot, flags, 0);
32                 current_thread_info()->task = otask;
33                 if (!atomic) {
34                         downgrade_write (&mm->mmap_sem);
35                         mmput(mm);
36                 }
37         } else {
38                 printk("proc %d has no mm", task->tgid);
39         }
40
41         return ret;
42 }
43
44 static void *sm_alloc_us(struct slot_manager *sm)
45 {
46         struct task_struct *task = sm->data;
47
48         return (void *)alloc_user_pages(task, PAGE_SIZE,
49                                         PROT_EXEC|PROT_READ|PROT_WRITE,
50                                         MAP_ANONYMOUS|MAP_PRIVATE);
51 }
52
53 static void sm_free_us(struct slot_manager *sm, void *ptr)
54 {
55         struct task_struct *task = sm->data;
56
57         /*
58          * E. G.: This code provides kernel dump because of rescheduling while atomic.
59          * As workaround, this code was commented. In this case we will have memory leaks
60          * for instrumented process, but instrumentation process should functionate correctly.
61          * Planned that good solution for this problem will be done during redesigning KProbe
62          * for improving supportability and performance.
63          */
64 #if 0
65         mm = get_task_mm(task);
66         if (mm) {
67                 down_write(&mm->mmap_sem);
68                 do_munmap(mm, (unsigned long)(ptr), PAGE_SIZE);
69                 up_write(&mm->mmap_sem);
70                 mmput(mm);
71         }
72 #endif
73         /* FIXME: implement the removal of memory for task */
74 }
75
76 struct slot_manager *create_sm_us(struct task_struct *task)
77 {
78         struct slot_manager *sm = kmalloc(sizeof(*sm), GFP_ATOMIC);
79         sm->slot_size = UPROBES_TRAMP_LEN;
80         sm->alloc = sm_alloc_us;
81         sm->free = sm_free_us;
82         INIT_HLIST_NODE(&sm->page_list);
83         sm->data = task;
84
85         return sm;
86 }
87
88 void free_sm_us(struct slot_manager *sm)
89 {
90         /* FIXME: free */
91 }