KVM: PPC: Fix PR KVM on POWER7 bare metal
[linux-flexiantxendom0-3.2.10.git] / mm / util.c
index 834db7b..ae962b3 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -1,11 +1,13 @@
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/string.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/err.h>
 #include <linux/sched.h>
 #include <asm/uaccess.h>
 
+#include "internal.h"
+
 #define CREATE_TRACE_POINTS
 #include <trace/events/kmem.h>
 
@@ -204,15 +206,10 @@ char *strndup_user(const char __user *s, long n)
        if (length > n)
                return ERR_PTR(-EINVAL);
 
-       p = kmalloc(length, GFP_KERNEL);
-
-       if (!p)
-               return ERR_PTR(-ENOMEM);
+       p = memdup_user(s, length);
 
-       if (copy_from_user(p, s, length)) {
-               kfree(p);
-               return ERR_PTR(-EFAULT);
-       }
+       if (IS_ERR(p))
+               return p;
 
        p[length - 1] = '\0';
 
@@ -220,6 +217,69 @@ char *strndup_user(const char __user *s, long n)
 }
 EXPORT_SYMBOL(strndup_user);
 
+void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma,
+               struct vm_area_struct *prev, struct rb_node *rb_parent)
+{
+       struct vm_area_struct *next;
+
+       vma->vm_prev = prev;
+       if (prev) {
+               next = prev->vm_next;
+               prev->vm_next = vma;
+       } else {
+               mm->mmap = vma;
+               if (rb_parent)
+                       next = rb_entry(rb_parent,
+                                       struct vm_area_struct, vm_rb);
+               else
+                       next = NULL;
+       }
+       vma->vm_next = next;
+       if (next)
+               next->vm_prev = vma;
+}
+
+/* Check if the vma is being used as a stack by this task */
+static int vm_is_stack_for_task(struct task_struct *t,
+                               struct vm_area_struct *vma)
+{
+       return (vma->vm_start <= KSTK_ESP(t) && vma->vm_end >= KSTK_ESP(t));
+}
+
+/*
+ * Check if the vma is being used as a stack.
+ * If is_group is non-zero, check in the entire thread group or else
+ * just check in the current task. Returns the pid of the task that
+ * the vma is stack for.
+ */
+pid_t vm_is_stack(struct task_struct *task,
+                 struct vm_area_struct *vma, int in_group)
+{
+       pid_t ret = 0;
+
+       if (vm_is_stack_for_task(task, vma))
+               return task->pid;
+
+       if (in_group) {
+               struct task_struct *t;
+               rcu_read_lock();
+               if (!pid_alive(task))
+                       goto done;
+
+               t = task;
+               do {
+                       if (vm_is_stack_for_task(t, vma)) {
+                               ret = t->pid;
+                               goto done;
+                       }
+               } while_each_thread(task, t);
+done:
+               rcu_read_unlock();
+       }
+
+       return ret;
+}
+
 #if defined(CONFIG_MMU) && !defined(HAVE_ARCH_PICK_MMAP_LAYOUT)
 void arch_pick_mmap_layout(struct mm_struct *mm)
 {
@@ -229,6 +289,19 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
 }
 #endif
 
+/*
+ * Like get_user_pages_fast() except its IRQ-safe in that it won't fall
+ * back to the regular GUP.
+ * If the architecture not support this function, simply return with no
+ * page pinned
+ */
+int __attribute__((weak)) __get_user_pages_fast(unsigned long start,
+                                int nr_pages, int write, struct page **pages)
+{
+       return 0;
+}
+EXPORT_SYMBOL_GPL(__get_user_pages_fast);
+
 /**
  * get_user_pages_fast() - pin user pages in memory
  * @start:     starting user address