Commit a0a7ec308f1be5957b20a1a535d21f683dfd83f0
Committed by
Linus Torvalds
1 parent
741a295130
Exists in
master
and in
4 other branches
[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>
Showing 1 changed file with 56 additions and 31 deletions Side-by-side Diff
kernel/fork.c
... | ... | @@ -446,6 +446,55 @@ |
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 | 498 | static int copy_mm(unsigned long clone_flags, struct task_struct * tsk) |
450 | 499 | { |
451 | 500 | struct mm_struct * mm, *oldmm; |
452 | 501 | |
453 | 502 | |
454 | 503 | |
... | ... | @@ -473,43 +522,17 @@ |
473 | 522 | } |
474 | 523 | |
475 | 524 | retval = -ENOMEM; |
476 | - mm = allocate_mm(); | |
525 | + mm = dup_mm(tsk); | |
477 | 526 | if (!mm) |
478 | 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 | 529 | good_mm: |
496 | 530 | tsk->mm = mm; |
497 | 531 | tsk->active_mm = mm; |
498 | 532 | return 0; |
499 | 533 | |
500 | -free_pt: | |
501 | - mmput(mm); | |
502 | 534 | fail_nomem: |
503 | 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 | 538 | static inline struct fs_struct *__copy_fs_struct(struct fs_struct *old) |
516 | 539 | |
517 | 540 | |
... | ... | @@ -1423,18 +1446,20 @@ |
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 | 1451 | static int unshare_vm(unsigned long unshare_flags, struct mm_struct **new_mmp) |
1429 | 1452 | { |
1430 | 1453 | struct mm_struct *mm = current->mm; |
1431 | 1454 | |
1432 | 1455 | if ((unshare_flags & CLONE_VM) && |
1433 | - (mm && atomic_read(&mm->mm_users) > 1)) | |
1434 | - return -EINVAL; | |
1456 | + (mm && atomic_read(&mm->mm_users) > 1)) { | |
1457 | + *new_mmp = dup_mm(current); | |
1458 | + if (!*new_mmp) | |
1459 | + return -ENOMEM; | |
1460 | + } | |
1435 | 1461 | |
1436 | 1462 | return 0; |
1437 | - | |
1438 | 1463 | } |
1439 | 1464 | |
1440 | 1465 | /* |