Commit a0a7ec308f1be5957b20a1a535d21f683dfd83f0

Authored by JANAK DESAI
Committed by Linus Torvalds
1 parent 741a295130

[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

... ... @@ -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 /*