diff options
author | JANAK DESAI <janak@us.ibm.com> | 2006-02-07 15:59:01 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-02-07 19:12:34 -0500 |
commit | a0a7ec308f1be5957b20a1a535d21f683dfd83f0 (patch) | |
tree | 3814ee7b6aa51558d7c2200e41d587c9150389e5 /kernel/fork.c | |
parent | 741a295130606143edbf9fc740f633dbc1e6225f (diff) |
[PATCH] unshare system call -v5: unshare vm
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>
Diffstat (limited to 'kernel/fork.c')
-rw-r--r-- | kernel/fork.c | 87 |
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 | */ | ||
453 | static 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 | |||
482 | free_pt: | ||
483 | mmput(mm); | ||
484 | |||
485 | fail_nomem: | ||
486 | return NULL; | ||
487 | |||
488 | fail_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 | |||
449 | static int copy_mm(unsigned long clone_flags, struct task_struct * tsk) | 498 | static 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 | |||
495 | good_mm: | 529 | good_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 | ||
500 | free_pt: | ||
501 | mmput(mm); | ||
502 | fail_nomem: | 534 | fail_nomem: |
503 | return retval; | 535 | return retval; |
504 | |||
505 | fail_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 | ||
515 | static inline struct fs_struct *__copy_fs_struct(struct fs_struct *old) | 538 | 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 ** | |||
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 | */ |
1428 | static int unshare_vm(unsigned long unshare_flags, struct mm_struct **new_mmp) | 1451 | static 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 | /* |