Added some fixes for continuous data transfer
[kernel/swap-modules.git] / kprobe / kprobes.c
index 9b70c2f..a90082a 100644 (file)
@@ -59,6 +59,10 @@ int src_register_die_notifier(struct notifier_block *nb)
        return err;
 }
 */
+
+int get_user_pages_uprobe(struct task_struct *tsk, struct mm_struct *mm,
+                         unsigned long start, int len, int write, int force,
+                         struct page **pages, struct vm_area_struct **vmas);
 /**
  * hlist_replace_rcu - replace old entry by new one
  * @old : the element to be replaced
@@ -138,7 +142,7 @@ get_kprobe (void *addr, int tgid, struct task_struct *ctask)
 
        if (ctask && ctask->active_mm)
        {
-               ret = get_user_pages_atomic (ctask, ctask->active_mm, (unsigned long) addr, 1, 0, 0, &tpage, NULL);
+               ret = get_user_pages_uprobe (ctask, ctask->active_mm, (unsigned long) addr, 1, 0, 0, &tpage, NULL);
                if (ret <= 0)
                        DBPRINTF ("get_user_pages for task %d at %p failed!", current->pid, addr);
                else
@@ -203,7 +207,7 @@ get_kprobe (void *addr, int tgid, struct task_struct *ctask)
                                {
                                        if (page_present (task->active_mm, (unsigned long) p->addr))
                                        {
-                                               ret = get_user_pages_atomic (task, task->active_mm, (unsigned long) p->addr, 1, 0, 0, &page, &vma);
+                                               ret = get_user_pages_uprobe (task, task->active_mm, (unsigned long) p->addr, 1, 0, 0, &page, &vma);
                                                if (ret <= 0)
                                                        DBPRINTF ("get_user_pages for task %d at %p failed!", p->tgid, p->addr);
                                        }
@@ -1009,10 +1013,7 @@ register_uretprobe (struct task_struct *task, struct mm_struct *mm, struct kretp
 
        rp->nmissed = 0;
 #if 0
-       if (atomic)
-               ret = get_user_pages_atomic (task, mm, (unsigned long) rp->kp.addr, 1, 1, 1, &pages[0], &vmas[0]);
-       else
-               ret = get_user_pages (task, mm, (unsigned long) rp->kp.addr, 1, 1, 1, &pages[0], &vmas[0]);
+       ret = get_user_pages_uprobe (task, mm, (unsigned long) rp->kp.addr, 1, 1, 1, &pages[0], &vmas[0]);
        if (ret <= 0)
        {
                DBPRINTF ("get_user_pages for %p failed!", rp->kp.addr);
@@ -1026,10 +1027,7 @@ register_uretprobe (struct task_struct *task, struct mm_struct *mm, struct kretp
        // if 2nd instruction is on the 2nd page
        if ((((unsigned long) (rp->kp.addr + 1)) & ~PAGE_MASK) == 0)
        {
-               if (atomic)
-                       ret = get_user_pages_atomic (task, mm, (unsigned long) (rp->kp.addr + 1), 1, 1, 1, &pages[1], &vmas[1]);
-               else
-                       ret = get_user_pages (task, mm, (unsigned long) (rp->kp.addr + 1), 1, 1, 1, &pages[1], &vmas[1]);
+         ret = get_user_pages_uprobe (task, mm, (unsigned long) (rp->kp.addr + 1), 1, 1, 1, &pages[1], &vmas[1]);
                if (ret <= 0)
                {
                        DBPRINTF ("get_user_pages for %p failed!", rp->kp.addr + 1);
@@ -1169,13 +1167,9 @@ unregister_uretprobe (struct task_struct *task, struct kretprobe *rp, int atomic
 #endif
                return;
        }
-       if (atomic)
-               ret = get_user_pages_atomic (task, mm, (unsigned long) rp->kp.addr, 1, 1, 1, &pages[0], &vmas[0]);
-       else
-       {
-               down_read (&mm->mmap_sem);
-               ret = get_user_pages (task, mm, (unsigned long) rp->kp.addr, 1, 1, 1, &pages[0], &vmas[0]);
-       }
+       down_read (&mm->mmap_sem);
+       ret = get_user_pages_uprobe (task, mm, (unsigned long) rp->kp.addr, 1, 1, 1, &pages[0], &vmas[0]);
+
        if (ret <= 0)
        {
                DBPRINTF ("get_user_pages for %p failed!", rp->kp.addr);
@@ -1187,10 +1181,8 @@ unregister_uretprobe (struct task_struct *task, struct kretprobe *rp, int atomic
                kaddrs[0] = kmap (pages[0]) + ((unsigned long) rp->kp.addr & ~PAGE_MASK);
        if ((((unsigned long) (rp->kp.addr + 1)) & ~PAGE_MASK) == 0)
        {
-               if (atomic)
-                       ret = get_user_pages_atomic (task, mm, (unsigned long) (rp->kp.addr + 1), 1, 1, 1, &pages[1], &vmas[1]);
-               else
-                       ret = get_user_pages (task, mm, (unsigned long) (rp->kp.addr + 1), 1, 1, 1, &pages[1], &vmas[1]);
+         
+         ret = get_user_pages_uprobe (task, mm, (unsigned long) (rp->kp.addr + 1), 1, 1, 1, &pages[1], &vmas[1]);
                if (ret <= 0)
                {
                        DBPRINTF ("get_user_pages for %p failed!", rp->kp.addr + 1);
@@ -1309,7 +1301,7 @@ unregister_all_uprobes (struct task_struct *task, int atomic)
 #define GUP_FLAGS_IGNORE_VMA_PERMISSIONS 0x4
 #define GUP_FLAGS_IGNORE_SIGKILL         0x8
 
-
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
 static inline int use_zero_page(struct vm_area_struct *vma)
 {
        /*
@@ -1326,6 +1318,7 @@ static inline int use_zero_page(struct vm_area_struct *vma)
         */
        return !vma->vm_ops || !vma->vm_ops->fault;
 }
+#endif
 
 int __get_user_pages_uprobe(struct task_struct *tsk, struct mm_struct *mm,
                     unsigned long start, int len, int flags,
@@ -1401,8 +1394,13 @@ int __get_user_pages_uprobe(struct task_struct *tsk, struct mm_struct *mm,
                        return i ? : -EFAULT;
 
                if (is_vm_hugetlb_page(vma)) {
+#if  LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18)
+                       i = follow_hugetlb_page(mm, vma, pages, vmas,
+                                               &start, &len, i);
+#else
                        i = follow_hugetlb_page(mm, vma, pages, vmas,
                                                &start, &len, i, write);
+#endif
                        continue;
                }
 
@@ -1410,14 +1408,17 @@ int __get_user_pages_uprobe(struct task_struct *tsk, struct mm_struct *mm,
                if (pages)
                        foll_flags |= FOLL_GET;
 
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,30)
                if (!write && use_zero_page(vma))
                  foll_flags |= FOLL_ANON;
 #endif
+#endif
 
                do {
                        struct page *page;
 
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
                        /*
                         * If we have a pending SIGKILL, don't keep faulting
                         * pages and potentially allocating memory, unless
@@ -1428,6 +1429,7 @@ int __get_user_pages_uprobe(struct task_struct *tsk, struct mm_struct *mm,
                        if (unlikely(!ignore_sigkill &&
                                        fatal_signal_pending(current)))
                                return i ? i : -ERESTARTSYS;
+#endif
 
                        if (write)
                                foll_flags |= FOLL_WRITE;
@@ -1440,18 +1442,39 @@ int __get_user_pages_uprobe(struct task_struct *tsk, struct mm_struct *mm,
                                int ret;
                                ret = handle_mm_fault(mm, vma, start,
                                                foll_flags & FOLL_WRITE);
+
+#if  LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18)
+                               if (ret & VM_FAULT_WRITE)
+                                 foll_flags &= ~FOLL_WRITE;
+                               
+                               switch (ret & ~VM_FAULT_WRITE) {
+                               case VM_FAULT_MINOR:
+                                 tsk->min_flt++;
+                                 break;
+                               case VM_FAULT_MAJOR:
+                                 tsk->maj_flt++;
+                                 break;
+                               case VM_FAULT_SIGBUS:
+                                 return i ? i : -EFAULT;
+                               case VM_FAULT_OOM:
+                                 return i ? i : -ENOMEM;
+                               default:
+                                 BUG();
+                               }
+                               
+#else
                                if (ret & VM_FAULT_ERROR) {
-                                       if (ret & VM_FAULT_OOM)
-                                               return i ? i : -ENOMEM;
-                                       else if (ret & VM_FAULT_SIGBUS)
-                                               return i ? i : -EFAULT;
-                                       BUG();
+                                 if (ret & VM_FAULT_OOM)
+                                   return i ? i : -ENOMEM;
+                                 else if (ret & VM_FAULT_SIGBUS)
+                                   return i ? i : -EFAULT;
+                                 BUG();
                                }
                                if (ret & VM_FAULT_MAJOR)
-                                       tsk->maj_flt++;
+                                 tsk->maj_flt++;
                                else
-                                       tsk->min_flt++;
-
+                                 tsk->min_flt++;
+                               
                                /*
                                 * The VM_FAULT_WRITE bit tells us that
                                 * do_wp_page has broken COW when necessary,
@@ -1466,16 +1489,23 @@ int __get_user_pages_uprobe(struct task_struct *tsk, struct mm_struct *mm,
                                 */
                                if ((ret & VM_FAULT_WRITE) &&
                                    !(vma->vm_flags & VM_WRITE))
-                                       foll_flags &= ~FOLL_WRITE;
-
+                                 foll_flags &= ~FOLL_WRITE;
+                               
                                //cond_resched();
+#endif
+                               
                        }
+
                        if (IS_ERR(page))
                                return i ? i : PTR_ERR(page);
                        if (pages) {
                                pages[i] = page;
 
+#if  LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18)
+                               flush_anon_page(page, start);
+#else
                                flush_anon_page(vma, page, start);
+#endif
                                flush_dcache_page(page);
                        }
                        if (vmas)
@@ -1492,6 +1522,7 @@ int get_user_pages_uprobe(struct task_struct *tsk, struct mm_struct *mm,
                unsigned long start, int len, int write, int force,
                struct page **pages, struct vm_area_struct **vmas)
 {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
        int flags = 0;
 
        if (write)
@@ -1502,6 +1533,11 @@ int get_user_pages_uprobe(struct task_struct *tsk, struct mm_struct *mm,
        return __get_user_pages_uprobe(tsk, mm,
                                start, len, flags,
                                pages, vmas);
+#else
+       return get_user_pages(tsk, mm,
+                                                 start, len, write, force,
+                                                 pages, vmas);
+#endif
 }
 
 int