aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/fork.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-04-03 00:09:10 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-04-03 00:09:10 -0400
commit8fe74cf053de7ad2124a894996f84fa890a81093 (patch)
tree77dcd8fbf33ce53a3821942233962fb28c6f2848 /kernel/fork.c
parentc2eb2fa6d2b6fe122d3479ec5b28d978418b2698 (diff)
parentced117c73edc917e96dea7cca98c91383f0792f7 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: Remove two unneeded exports and make two symbols static in fs/mpage.c Cleanup after commit 585d3bc06f4ca57f975a5a1f698f65a45ea66225 Trim includes of fdtable.h Don't crap into descriptor table in binfmt_som Trim includes in binfmt_elf Don't mess with descriptor table in load_elf_binary() Get rid of indirect include of fs_struct.h New helper - current_umask() check_unsafe_exec() doesn't care about signal handlers sharing New locking/refcounting for fs_struct Take fs_struct handling to new file (fs/fs_struct.c) Get rid of bumping fs_struct refcount in pivot_root(2) Kill unsharing fs_struct in __set_personality()
Diffstat (limited to 'kernel/fork.c')
-rw-r--r--kernel/fork.c63
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
684static 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
702struct fs_struct *copy_fs_struct(struct fs_struct *old)
703{
704 return __copy_fs_struct(old);
705}
706
707EXPORT_SYMBOL_GPL(copy_fs_struct);
708
709static int copy_fs(unsigned long clone_flags, struct task_struct *tsk) 685static 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(&current->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
1706bad_unshare_cleanup_fs: 1699bad_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
1710bad_unshare_cleanup_thread: 1703bad_unshare_cleanup_thread:
1711bad_unshare_out: 1704bad_unshare_out: