aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/fork.c87
1 files changed, 56 insertions, 31 deletions
diff --git a/kernel/fork.c b/kernel/fork.c
index 07dd241aa1e0..d1aceaea3f33 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -446,6 +446,55 @@ void mm_release(struct task_struct *tsk, struct mm_struct *mm)
446 } 446 }
447} 447}
448 448
449/*
450 * Allocate a new mm structure and copy contents from the
451 * mm structure of the passed in task structure.
452 */
453static struct mm_struct *dup_mm(struct task_struct *tsk)
454{
455 struct mm_struct *mm, *oldmm = current->mm;
456 int err;
457
458 if (!oldmm)
459 return NULL;
460
461 mm = allocate_mm();
462 if (!mm)
463 goto fail_nomem;
464
465 memcpy(mm, oldmm, sizeof(*mm));
466
467 if (!mm_init(mm))
468 goto fail_nomem;
469
470 if (init_new_context(tsk, mm))
471 goto fail_nocontext;
472
473 err = dup_mmap(mm, oldmm);
474 if (err)
475 goto free_pt;
476
477 mm->hiwater_rss = get_mm_rss(mm);
478 mm->hiwater_vm = mm->total_vm;
479
480 return mm;
481
482free_pt:
483 mmput(mm);
484
485fail_nomem:
486 return NULL;
487
488fail_nocontext:
489 /*
490 * If init_new_context() failed, we cannot use mmput() to free the mm
491 * because it calls destroy_context()
492 */
493 mm_free_pgd(mm);
494 free_mm(mm);
495 return NULL;
496}
497
449static int copy_mm(unsigned long clone_flags, struct task_struct * tsk) 498static int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
450{ 499{
451 struct mm_struct * mm, *oldmm; 500 struct mm_struct * mm, *oldmm;
@@ -473,43 +522,17 @@ static int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
473 } 522 }
474 523
475 retval = -ENOMEM; 524 retval = -ENOMEM;
476 mm = allocate_mm(); 525 mm = dup_mm(tsk);
477 if (!mm) 526 if (!mm)
478 goto fail_nomem; 527 goto fail_nomem;
479 528
480 /* Copy the current MM stuff.. */
481 memcpy(mm, oldmm, sizeof(*mm));
482 if (!mm_init(mm))
483 goto fail_nomem;
484
485 if (init_new_context(tsk,mm))
486 goto fail_nocontext;
487
488 retval = dup_mmap(mm, oldmm);
489 if (retval)
490 goto free_pt;
491
492 mm->hiwater_rss = get_mm_rss(mm);
493 mm->hiwater_vm = mm->total_vm;
494
495good_mm: 529good_mm:
496 tsk->mm = mm; 530 tsk->mm = mm;
497 tsk->active_mm = mm; 531 tsk->active_mm = mm;
498 return 0; 532 return 0;
499 533
500free_pt:
501 mmput(mm);
502fail_nomem: 534fail_nomem:
503 return retval; 535 return retval;
504
505fail_nocontext:
506 /*
507 * If init_new_context() failed, we cannot use mmput() to free the mm
508 * because it calls destroy_context()
509 */
510 mm_free_pgd(mm);
511 free_mm(mm);
512 return retval;
513} 536}
514 537
515static inline struct fs_struct *__copy_fs_struct(struct fs_struct *old) 538static 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 **
1423} 1446}
1424 1447
1425/* 1448/*
1426 * Unsharing of vm for tasks created with CLONE_VM is not supported yet 1449 * Unshare vm if it is being shared
1427 */ 1450 */
1428static int unshare_vm(unsigned long unshare_flags, struct mm_struct **new_mmp) 1451static int unshare_vm(unsigned long unshare_flags, struct mm_struct **new_mmp)
1429{ 1452{
1430 struct mm_struct *mm = current->mm; 1453 struct mm_struct *mm = current->mm;
1431 1454
1432 if ((unshare_flags & CLONE_VM) && 1455 if ((unshare_flags & CLONE_VM) &&
1433 (mm && atomic_read(&mm->mm_users) > 1)) 1456 (mm && atomic_read(&mm->mm_users) > 1)) {
1434 return -EINVAL; 1457 *new_mmp = dup_mm(current);
1458 if (!*new_mmp)
1459 return -ENOMEM;
1460 }
1435 1461
1436 return 0; 1462 return 0;
1437
1438} 1463}
1439 1464
1440/* 1465/*