OSDN Git Service

cifs: fail i/o on soft mounts if sessionsetup errors out
[sagit-ice-cold/kernel_xiaomi_msm8998.git] / mm / util.c
index d5259b6..db39235 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -80,6 +80,8 @@ EXPORT_SYMBOL(kstrdup_const);
  * @s: the string to duplicate
  * @max: read at most @max chars from @s
  * @gfp: the GFP mask used in the kmalloc() call when allocating memory
+ *
+ * Note: Use kmemdup_nul() instead if the size is known exactly.
  */
 char *kstrndup(const char *s, size_t max, gfp_t gfp)
 {
@@ -118,6 +120,28 @@ void *kmemdup(const void *src, size_t len, gfp_t gfp)
 EXPORT_SYMBOL(kmemdup);
 
 /**
+ * kmemdup_nul - Create a NUL-terminated string from unterminated data
+ * @s: The data to stringify
+ * @len: The size of the data
+ * @gfp: the GFP mask used in the kmalloc() call when allocating memory
+ */
+char *kmemdup_nul(const char *s, size_t len, gfp_t gfp)
+{
+       char *buf;
+
+       if (!s)
+               return NULL;
+
+       buf = kmalloc_track_caller(len + 1, gfp);
+       if (buf) {
+               memcpy(buf, s, len);
+               buf[len] = '\0';
+       }
+       return buf;
+}
+EXPORT_SYMBOL(kmemdup_nul);
+
+/**
  * memdup_user - duplicate memory region from user space
  *
  * @src: source address in user space
@@ -254,7 +278,7 @@ int __weak get_user_pages_fast(unsigned long start,
 {
        struct mm_struct *mm = current->mm;
        return get_user_pages_unlocked(current, mm, start, nr_pages,
-                                      write, 0, pages);
+                                      pages, write ? FOLL_WRITE : 0);
 }
 EXPORT_SYMBOL_GPL(get_user_pages_fast);
 
@@ -404,17 +428,25 @@ int get_cmdline(struct task_struct *task, char *buffer, int buflen)
        int res = 0;
        unsigned int len;
        struct mm_struct *mm = get_task_mm(task);
+       unsigned long arg_start, arg_end, env_start, env_end;
        if (!mm)
                goto out;
        if (!mm->arg_end)
                goto out_mm;    /* Shh! No looking before we're done */
 
-       len = mm->arg_end - mm->arg_start;
+       down_read(&mm->mmap_sem);
+       arg_start = mm->arg_start;
+       arg_end = mm->arg_end;
+       env_start = mm->env_start;
+       env_end = mm->env_end;
+       up_read(&mm->mmap_sem);
+
+       len = arg_end - arg_start;
 
        if (len > buflen)
                len = buflen;
 
-       res = access_process_vm(task, mm->arg_start, buffer, len, 0);
+       res = access_process_vm(task, arg_start, buffer, len, 0);
 
        /*
         * If the nul at the end of args has been overwritten, then
@@ -425,10 +457,10 @@ int get_cmdline(struct task_struct *task, char *buffer, int buflen)
                if (len < res) {
                        res = len;
                } else {
-                       len = mm->env_end - mm->env_start;
+                       len = env_end - env_start;
                        if (len > buflen - res)
                                len = buflen - res;
-                       res += access_process_vm(task, mm->env_start,
+                       res += access_process_vm(task, env_start,
                                                 buffer+res, len, 0);
                        res = strnlen(buffer, res);
                }