diff options
Diffstat (limited to 'kernel/fork.c')
-rw-r--r-- | kernel/fork.c | 63 |
1 files changed, 28 insertions, 35 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index f74458231449..660c2b8765bc 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -60,6 +60,7 @@ | |||
60 | #include <linux/tty.h> | 60 | #include <linux/tty.h> |
61 | #include <linux/proc_fs.h> | 61 | #include <linux/proc_fs.h> |
62 | #include <linux/blkdev.h> | 62 | #include <linux/blkdev.h> |
63 | #include <linux/fs_struct.h> | ||
63 | #include <trace/sched.h> | 64 | #include <trace/sched.h> |
64 | #include <linux/magic.h> | 65 | #include <linux/magic.h> |
65 | 66 | ||
@@ -681,38 +682,21 @@ fail_nomem: | |||
681 | return retval; | 682 | return retval; |
682 | } | 683 | } |
683 | 684 | ||
684 | static struct fs_struct *__copy_fs_struct(struct fs_struct *old) | ||
685 | { | ||
686 | struct fs_struct *fs = kmem_cache_alloc(fs_cachep, GFP_KERNEL); | ||
687 | /* We don't need to lock fs - think why ;-) */ | ||
688 | if (fs) { | ||
689 | atomic_set(&fs->count, 1); | ||
690 | rwlock_init(&fs->lock); | ||
691 | fs->umask = old->umask; | ||
692 | read_lock(&old->lock); | ||
693 | fs->root = old->root; | ||
694 | path_get(&old->root); | ||
695 | fs->pwd = old->pwd; | ||
696 | path_get(&old->pwd); | ||
697 | read_unlock(&old->lock); | ||
698 | } | ||
699 | return fs; | ||
700 | } | ||
701 | |||
702 | struct fs_struct *copy_fs_struct(struct fs_struct *old) | ||
703 | { | ||
704 | return __copy_fs_struct(old); | ||
705 | } | ||
706 | |||
707 | EXPORT_SYMBOL_GPL(copy_fs_struct); | ||
708 | |||
709 | static int copy_fs(unsigned long clone_flags, struct task_struct *tsk) | 685 | static int copy_fs(unsigned long clone_flags, struct task_struct *tsk) |
710 | { | 686 | { |
687 | struct fs_struct *fs = current->fs; | ||
711 | if (clone_flags & CLONE_FS) { | 688 | if (clone_flags & CLONE_FS) { |
712 | atomic_inc(¤t->fs->count); | 689 | /* tsk->fs is already what we want */ |
690 | write_lock(&fs->lock); | ||
691 | if (fs->in_exec) { | ||
692 | write_unlock(&fs->lock); | ||
693 | return -EAGAIN; | ||
694 | } | ||
695 | fs->users++; | ||
696 | write_unlock(&fs->lock); | ||
713 | return 0; | 697 | return 0; |
714 | } | 698 | } |
715 | tsk->fs = __copy_fs_struct(current->fs); | 699 | tsk->fs = copy_fs_struct(fs); |
716 | if (!tsk->fs) | 700 | if (!tsk->fs) |
717 | return -ENOMEM; | 701 | return -ENOMEM; |
718 | return 0; | 702 | return 0; |
@@ -1544,12 +1528,16 @@ static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp) | |||
1544 | { | 1528 | { |
1545 | struct fs_struct *fs = current->fs; | 1529 | struct fs_struct *fs = current->fs; |
1546 | 1530 | ||
1547 | if ((unshare_flags & CLONE_FS) && | 1531 | if (!(unshare_flags & CLONE_FS) || !fs) |
1548 | (fs && atomic_read(&fs->count) > 1)) { | 1532 | return 0; |
1549 | *new_fsp = __copy_fs_struct(current->fs); | 1533 | |
1550 | if (!*new_fsp) | 1534 | /* don't need lock here; in the worst case we'll do useless copy */ |
1551 | return -ENOMEM; | 1535 | if (fs->users == 1) |
1552 | } | 1536 | return 0; |
1537 | |||
1538 | *new_fsp = copy_fs_struct(fs); | ||
1539 | if (!*new_fsp) | ||
1540 | return -ENOMEM; | ||
1553 | 1541 | ||
1554 | return 0; | 1542 | return 0; |
1555 | } | 1543 | } |
@@ -1665,8 +1653,13 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags) | |||
1665 | 1653 | ||
1666 | if (new_fs) { | 1654 | if (new_fs) { |
1667 | fs = current->fs; | 1655 | fs = current->fs; |
1656 | write_lock(&fs->lock); | ||
1668 | current->fs = new_fs; | 1657 | current->fs = new_fs; |
1669 | new_fs = fs; | 1658 | if (--fs->users) |
1659 | new_fs = NULL; | ||
1660 | else | ||
1661 | new_fs = fs; | ||
1662 | write_unlock(&fs->lock); | ||
1670 | } | 1663 | } |
1671 | 1664 | ||
1672 | if (new_mm) { | 1665 | if (new_mm) { |
@@ -1705,7 +1698,7 @@ bad_unshare_cleanup_sigh: | |||
1705 | 1698 | ||
1706 | bad_unshare_cleanup_fs: | 1699 | bad_unshare_cleanup_fs: |
1707 | if (new_fs) | 1700 | if (new_fs) |
1708 | put_fs_struct(new_fs); | 1701 | free_fs_struct(new_fs); |
1709 | 1702 | ||
1710 | bad_unshare_cleanup_thread: | 1703 | bad_unshare_cleanup_thread: |
1711 | bad_unshare_out: | 1704 | bad_unshare_out: |