[FIX] Ksyms: Fix warnings
[kernel/swap-modules.git] / us_manager / helper.c
index 7fbe6b0..7ee6c1e 100644 (file)
@@ -1,9 +1,34 @@
-#include <dbi_kprobes.h>
-#include <dbi_kprobes_deps.h>
-#include <ksyms.h>
-#include "us_proc_inst.h"
+/*
+ *  SWAP uprobe manager
+ *  modules/us_manager/helper.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) Samsung Electronics, 2013
+ *
+ * 2013         Vyacheslav Cherkashin: SWAP us_manager implement
+ *
+ */
+
+
+#include <kprobe/dbi_kprobes.h>
+#include <kprobe/dbi_kprobes_deps.h>
+#include <ksyms/ksyms.h>
+#include <writer/kernel_operations.h>
+#include <writer/swap_writer_module.h>
 #include "us_slot_manager.h"
-#include "storage.h"
 #include "sspt/sspt.h"
 #include "helper.h"
 
@@ -21,65 +46,34 @@ struct pf_data {
        unsigned long addr;
 };
 
-static int entry_handler_pf(struct kretprobe_instance *ri, struct pt_regs *regs)
+static int entry_handler_mf(struct kretprobe_instance *ri, struct pt_regs *regs)
 {
        struct pf_data *data = (struct pf_data *)ri->data;
 
-#if defined(CONFIG_X86)
-       data->addr = read_cr2();
-#elif defined(CONFIG_ARM)
-       data->addr = regs->ARM_r0;
-#else
-#error this architecture is not supported
-#endif
+       data->addr = swap_get_karg(regs, 2);
 
        return 0;
 }
 
 /* Detects when IPs are really loaded into phy mem and installs probes. */
-static int ret_handler_pf(struct kretprobe_instance *ri, struct pt_regs *regs)
+static int ret_handler_mf(struct kretprobe_instance *ri, struct pt_regs *regs)
 {
-       struct task_struct *task;
-       struct sspt_proc *proc;
-
-       install_page(((struct pf_data *)ri->data)->addr);
-       return 0;
+       struct task_struct *task = current;
+       unsigned long page_addr;
 
-       /*
-        * Because process threads have same address space
-        * we instrument only group_leader of all this threads
-        */
-       task = current->group_leader;
        if (is_kthread(task))
                return 0;
 
-       proc = sspt_proc_get_by_task(task);
-       if (proc)
-               goto install_proc;
-
-       task = check_task(task);
-       if (task) {
-               proc = sspt_proc_get_new(task);
-               goto install_proc;
-       }
-
-       return 0;
-
-install_proc:
-       if (proc->first_install) {
-               unsigned long page;
-               page = ((struct pf_data *)ri->data)->addr & PAGE_MASK;
-               sspt_proc_install_page(proc, page);
-       } else {
-               sspt_proc_install(proc);
-       }
+       /* TODO: check return value */
+       page_addr = ((struct pf_data *)ri->data)->addr & PAGE_MASK;
+       call_page_fault(task, page_addr);
 
        return 0;
 }
 
-static struct kretprobe pf_kretprobe = {
-       .entry_handler = entry_handler_pf,
-       .handler = ret_handler_pf,
+static struct kretprobe mf_kretprobe = {
+       .entry_handler = entry_handler_mf,
+       .handler = ret_handler_mf,
        .data_size = sizeof(struct pf_data)
 };
 
@@ -115,13 +109,6 @@ static int ret_handler_cp(struct kretprobe_instance *ri, struct pt_regs *regs)
 
        if(task->mm != current->mm) {   /* check flags CLONE_VM */
                rm_uprobes_child(task);
-
-               if (check_task(current)) {
-                       struct sspt_proc *proc;
-
-                       proc = sspt_proc_get_new(task);
-                       sspt_proc_install(proc);
-               }
        }
 out:
        return 0;
@@ -142,16 +129,7 @@ static struct kretprobe cp_kretprobe = {
 /* Detects when target process removes IPs. */
 static int mr_pre_handler(struct kprobe *p, struct pt_regs *regs)
 {
-       struct sspt_proc *proc = NULL;
-       struct task_struct *task;
-
-#if defined(CONFIG_X86)
-       task = (struct task_struct *)regs->EREG(ax);
-#elif defined(CONFIG_ARM)
-       task = (struct task_struct *)regs->ARM_r0;
-#else
-#error this architecture is not supported
-#endif
+       struct task_struct *task = (struct task_struct *)swap_get_karg(regs, 0);
 
        if (is_kthread(task))
                goto out;
@@ -160,16 +138,7 @@ static int mr_pre_handler(struct kprobe *p, struct pt_regs *regs)
                goto out;
        }
 
-       proc = sspt_proc_get_by_task(task);
-       if (proc) {
-               int ret = sspt_proc_uninstall(proc, task, US_UNREGS_PROBE);
-               if (ret != 0) {
-                       printk("failed to uninstall IPs (%d)!\n", ret);
-               }
-
-               dbi_unregister_all_uprobes(task);
-       }
-
+       call_mm_release(task);
 out:
        return 0;
 }
@@ -185,91 +154,111 @@ static struct kprobe mr_kprobe = {
  *                                 do_munmap()                                *
  ******************************************************************************
  */
+struct unmap_data {
+       unsigned long start;
+       size_t len;
+};
 
-static int remove_unmap_probes(struct task_struct *task, struct sspt_proc *proc, unsigned long start, size_t len)
+static void remove_unmap_probes(struct sspt_proc *proc, struct unmap_data *umd)
 {
-       struct mm_struct *mm = task->mm;
-       struct vm_area_struct *vma;
-
-       if ((start & ~PAGE_MASK) || start > TASK_SIZE || len > TASK_SIZE - start) {
-               return -EINVAL;
-       }
+       struct task_struct *task = proc->task;
+       unsigned long start = umd->start;
+       size_t len = PAGE_ALIGN(umd->len);
+       LIST_HEAD(head);
 
-       if ((len = PAGE_ALIGN(len)) == 0) {
-               return -EINVAL;
-       }
-
-       vma = find_vma(mm, start);
-       if (vma && check_vma(vma)) {
-               struct sspt_file *file;
+       if (sspt_proc_get_files_by_region(proc, &head, start, len)) {
+               struct sspt_file *file, *n;
                unsigned long end = start + len;
-               struct dentry *dentry = vma->vm_file->f_dentry;
 
-               file = sspt_proc_find_file(proc, dentry);
-               if (file) {
-                       if (vma->vm_start == start || vma->vm_end == end) {
-                               sspt_file_uninstall(file, task, US_UNREGS_PROBE);
-                               file->loaded = 0;
+               list_for_each_entry_safe(file, n, &head, list) {
+                       if (file->vm_start >= end)
+                               continue;
+
+                       if (file->vm_start >= start) {
+                               sspt_file_uninstall(file, task, US_UNINSTALL);
                        } else {
-                               unsigned long page_addr;
-                               struct sspt_page *page;
-
-                               for (page_addr = vma->vm_start; page_addr < vma->vm_end; page_addr += PAGE_SIZE) {
-                                       page = sspt_find_page_mapped(file, page_addr);
-                                       if (page) {
-                                               sspt_unregister_page(page, US_UNREGS_PROBE, task);
-                                       }
-                               }
-
-                               if (sspt_file_check_install_pages(file)) {
-                                       file->loaded = 0;
-                               }
+                               /* TODO: uninstall pages: start..file->vm_end */
                        }
                }
+
+               sspt_proc_insert_files(proc, &head);
+
+               proc_unmap_msg(start, end);
        }
+}
+
+
+static int entry_handler_unmap(struct kretprobe_instance *ri,
+                              struct pt_regs *regs)
+{
+       struct unmap_data *data = (struct unmap_data *)ri->data;
+
+       data->start = swap_get_karg(regs, 1);
+       data->len = (size_t)swap_get_karg(regs, 2);
 
        return 0;
 }
 
-/* Detects when target removes IPs. */
-static int unmap_pre_handler(struct kprobe *p, struct pt_regs *regs)
+static int ret_handler_unmap(struct kretprobe_instance *ri,
+                            struct pt_regs *regs)
 {
-       /* for ARM */
-       struct mm_struct *mm;
-       unsigned long start;
-       size_t len;
+       struct task_struct *task;
+       struct sspt_proc *proc;
 
-#if defined(CONFIG_X86)
-       mm = (struct mm_struct *)regs->EREG(ax);
-       start = regs->EREG(dx);
-       len = (size_t)regs->EREG(cx);
-#elif defined(CONFIG_ARM)
-       mm = (struct mm_struct *)regs->ARM_r0;
-       start = regs->ARM_r1;
-       len = (size_t)regs->ARM_r2;
-#else
-#error this architecture is not supported
-#endif
-
-       struct sspt_proc *proc = NULL;
-       struct task_struct *task = current;
+       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);
+
+       return 0;
+}
 
+static struct kretprobe unmap_kretprobe = {
+       .entry_handler = entry_handler_unmap,
+       .handler = ret_handler_unmap,
+       .data_size = sizeof(struct unmap_data)
+};
+
+
+
+/*
+ ******************************************************************************
+ *                               do_mmap_pgoff()                              *
+ ******************************************************************************
+ */
+static int ret_handler_mmap(struct kretprobe_instance *ri,
+                           struct pt_regs *regs)
+{
+       struct sspt_proc *proc;
+       struct task_struct *task;
+       unsigned long start_addr;
+       struct vm_area_struct *vma;
+
+       task = current->group_leader;
        if (is_kthread(task))
-               goto out;
+               return 0;
+
+       start_addr = (unsigned long)get_regs_ret_val(regs);
+       if (IS_ERR_VALUE(start_addr))
+               return 0;
 
        proc = sspt_proc_get_by_task(task);
-       if (proc) {
-               if (remove_unmap_probes(task, proc, start, len)) {
-                       printk("ERROR do_munmap: start=%lx, len=%x\n", start, len);
-               }
-       }
+       if (proc == NULL)
+               return 0;
+
+       vma = find_vma_intersection(task->mm, start_addr, start_addr + 1);
+       if (vma && check_vma(vma))
+               pcoc_map_msg(vma);
 
-out:
        return 0;
 }
 
-static struct kprobe unmap_kprobe = {
-       .pre_handler = unmap_pre_handler
+static struct kretprobe mmap_kretprobe = {
+       .handler = ret_handler_mmap
 };
 
 
@@ -279,7 +268,7 @@ int register_helper(void)
        int ret = 0;
 
        /* install kprobe on 'do_munmap' to detect when for remove user space probes */
-       ret = dbi_register_kprobe(&unmap_kprobe);
+       ret = dbi_register_kretprobe(&unmap_kretprobe);
        if (ret) {
                printk("dbi_register_kprobe(do_munmap) result=%d!\n", ret);
                return ret;
@@ -300,51 +289,65 @@ int register_helper(void)
                goto unregister_mr;
        }
 
-       /* install kretprobe on 'do_page_fault' to detect when they will be loaded */
-       ret = dbi_register_kretprobe(&pf_kretprobe);
+       /* install kretprobe on 'do_mmap_pgoff' to detect when mapping file */
+       ret = dbi_register_kretprobe(&mmap_kretprobe);
        if (ret) {
-               printk("dbi_register_kretprobe(do_page_fault) result=%d!\n", ret);
+               printk("dbi_register_kretprobe(do_mmap_pgoff) result=%d!\n", ret);
                goto unregister_cp;
        }
 
+       /* install kretprobe on 'handle_mm_fault' to detect when they will be loaded */
+       ret = dbi_register_kretprobe(&mf_kretprobe);
+       if (ret) {
+               printk("dbi_register_kretprobe(do_page_fault) result=%d!\n", ret);
+               goto unregister_mmap;
+       }
+
        return ret;
 
+
+unregister_mmap:
+       dbi_unregister_kretprobe(&mmap_kretprobe);
+
 unregister_cp:
        dbi_unregister_kretprobe(&cp_kretprobe);
 
 unregister_mr:
-       dbi_unregister_kprobe(&mr_kprobe, NULL);
+       dbi_unregister_kprobe(&mr_kprobe);
 
 unregister_unmap:
-       dbi_unregister_kprobe(&unmap_kprobe, NULL);
+       dbi_unregister_kretprobe(&unmap_kretprobe);
 
        return ret;
 }
 
 void unregister_helper(void)
 {
-       /* uninstall kretprobe with 'do_page_fault' */
-       dbi_unregister_kretprobe(&pf_kretprobe);
+       /* uninstall kretprobe with 'handle_mm_fault' */
+       dbi_unregister_kretprobe(&mf_kretprobe);
+
+       /* uninstall kretprobe with 'do_mmap_pgoff' */
+       dbi_unregister_kretprobe(&mmap_kretprobe);
 
        /* uninstall kretprobe with 'copy_process' */
        dbi_unregister_kretprobe(&cp_kretprobe);
 
        /* uninstall kprobe with 'mm_release' */
-       dbi_unregister_kprobe(&mr_kprobe, NULL);
+       dbi_unregister_kprobe(&mr_kprobe);
 
-       /* uninstall kprobe with 'do_munmap' */
-       dbi_unregister_kprobe(&unmap_kprobe, NULL);
+       /* uninstall kretprobe with 'do_munmap' */
+       dbi_unregister_kretprobe(&unmap_kretprobe);
 }
 
 int init_helper(void)
 {
        unsigned long addr;
-       addr = swap_ksyms("do_page_fault");
+       addr = swap_ksyms("handle_mm_fault");
        if (addr == 0) {
-               printk("Cannot find address for page fault function!\n");
+               printk("Cannot find address for handle_mm_fault function!\n");
                return -EINVAL;
        }
-       pf_kretprobe.kp.addr = (kprobe_opcode_t *)addr;
+       mf_kretprobe.kp.addr = (kprobe_opcode_t *)addr;
 
        addr = swap_ksyms("copy_process");
        if (addr == 0) {
@@ -365,7 +368,14 @@ int init_helper(void)
                printk("Cannot find address for do_munmap function!\n");
                return -EINVAL;
        }
-       unmap_kprobe.addr = (kprobe_opcode_t *)addr;
+       unmap_kretprobe.kp.addr = (kprobe_opcode_t *)addr;
+
+       addr = swap_ksyms("do_mmap_pgoff");
+       if (addr == 0) {
+               printk("Cannot find address for do_mmap_pgoff function!\n");
+               return -EINVAL;
+       }
+       mmap_kretprobe.kp.addr = (kprobe_opcode_t *)addr;
 
        return 0;
 }