[PATCH] unshare system call -v5: unshare vm
authorJANAK DESAI <janak@us.ibm.com>
Tue, 7 Feb 2006 20:59:01 +0000 (12:59 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Wed, 8 Feb 2006 00:12:34 +0000 (16:12 -0800)
If vm structure is being shared, allocate a new one and copy information from
the current, shared, structure.

Signed-off-by: Janak Desai <janak@us.ibm.com>
Cc: Al Viro <viro@ftp.linux.org.uk>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Michael Kerrisk <mtk-manpages@gmx.net>
Cc: Andi Kleen <ak@muc.de>
Cc: Paul Mackerras <paulus@samba.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
kernel/fork.c

index 07dd241aa1e0ee8c00a9728c98ade4a8931bb159..d1aceaea3f33ee0ecf4918b782bf02f2f2a381d4 100644 (file)
@@ -446,6 +446,55 @@ void mm_release(struct task_struct *tsk, struct mm_struct *mm)
        }
 }
 
+/*
+ * Allocate a new mm structure and copy contents from the
+ * mm structure of the passed in task structure.
+ */
+static struct mm_struct *dup_mm(struct task_struct *tsk)
+{
+       struct mm_struct *mm, *oldmm = current->mm;
+       int err;
+
+       if (!oldmm)
+               return NULL;
+
+       mm = allocate_mm();
+       if (!mm)
+               goto fail_nomem;
+
+       memcpy(mm, oldmm, sizeof(*mm));
+
+       if (!mm_init(mm))
+               goto fail_nomem;
+
+       if (init_new_context(tsk, mm))
+               goto fail_nocontext;
+
+       err = dup_mmap(mm, oldmm);
+       if (err)
+               goto free_pt;
+
+       mm->hiwater_rss = get_mm_rss(mm);
+       mm->hiwater_vm = mm->total_vm;
+
+       return mm;
+
+free_pt:
+       mmput(mm);
+
+fail_nomem:
+       return NULL;
+
+fail_nocontext:
+       /*
+        * If init_new_context() failed, we cannot use mmput() to free the mm
+        * because it calls destroy_context()
+        */
+       mm_free_pgd(mm);
+       free_mm(mm);
+       return NULL;
+}
+
 static int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
 {
        struct mm_struct * mm, *oldmm;
@@ -473,43 +522,17 @@ static int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
        }
 
        retval = -ENOMEM;
-       mm = allocate_mm();
+       mm = dup_mm(tsk);
        if (!mm)
                goto fail_nomem;
 
-       /* Copy the current MM stuff.. */
-       memcpy(mm, oldmm, sizeof(*mm));
-       if (!mm_init(mm))
-               goto fail_nomem;
-
-       if (init_new_context(tsk,mm))
-               goto fail_nocontext;
-
-       retval = dup_mmap(mm, oldmm);
-       if (retval)
-               goto free_pt;
-
-       mm->hiwater_rss = get_mm_rss(mm);
-       mm->hiwater_vm = mm->total_vm;
-
 good_mm:
        tsk->mm = mm;
        tsk->active_mm = mm;
        return 0;
 
-free_pt:
-       mmput(mm);
 fail_nomem:
        return retval;
-
-fail_nocontext:
-       /*
-        * If init_new_context() failed, we cannot use mmput() to free the mm
-        * because it calls destroy_context()
-        */
-       mm_free_pgd(mm);
-       free_mm(mm);
-       return retval;
 }
 
 static inline struct fs_struct *__copy_fs_struct(struct fs_struct *old)
@@ -1423,18 +1446,20 @@ static int unshare_sighand(unsigned long unshare_flags, struct sighand_struct **
 }
 
 /*
- * Unsharing of vm for tasks created with CLONE_VM is not supported yet
+ * Unshare vm if it is being shared
  */
 static int unshare_vm(unsigned long unshare_flags, struct mm_struct **new_mmp)
 {
        struct mm_struct *mm = current->mm;
 
        if ((unshare_flags & CLONE_VM) &&
-           (mm && atomic_read(&mm->mm_users) > 1))
-               return -EINVAL;
+           (mm && atomic_read(&mm->mm_users) > 1)) {
+               *new_mmp = dup_mm(current);
+               if (!*new_mmp)
+                       return -ENOMEM;
+       }
 
        return 0;
-
 }
 
 /*