Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 3 Apr 2009 04:09:10 +0000 (21:09 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 3 Apr 2009 04:09:10 +0000 (21:09 -0700)
* '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()

57 files changed:
arch/cris/kernel/process.c
arch/powerpc/platforms/cell/spufs/inode.c
drivers/char/tty_audit.c
drivers/char/tty_ldisc.c
fs/Makefile
fs/binfmt_elf.c
fs/binfmt_som.c
fs/block_dev.c
fs/btrfs/acl.c
fs/btrfs/ioctl.c
fs/buffer.c
fs/cifs/dir.c
fs/cifs/inode.c
fs/compat.c
fs/dcache.c
fs/exec.c
fs/ext2/acl.c
fs/ext3/acl.c
fs/ext4/acl.c
fs/fat/inode.c
fs/fs_struct.c [new file with mode: 0644]
fs/generic_acl.c
fs/gfs2/acl.c
fs/hfsplus/options.c
fs/hpfs/super.c
fs/internal.h
fs/jffs2/acl.c
fs/jfs/acl.c
fs/mpage.c
fs/namei.c
fs/namespace.c
fs/nfs/nfs3proc.c
fs/nfs/nfs4proc.c
fs/nfsd/nfssvc.c
fs/ocfs2/acl.c
fs/omfs/inode.c
fs/open.c
fs/proc/base.c
fs/proc/task_nommu.c
fs/reiserfs/xattr_acl.c
fs/xfs/linux-2.6/xfs_iops.c
include/linux/buffer_head.h
include/linux/fs.h
include/linux/fs_struct.h
include/linux/mnt_namespace.h
include/linux/mpage.h
include/linux/nsproxy.h
include/linux/sched.h
init/do_mounts.c
ipc/mqueue.c
kernel/auditsc.c
kernel/exec_domain.c
kernel/exit.c
kernel/fork.c
kernel/sys.c
net/unix/af_unix.c
security/tomoyo/realpath.c

index 60816e876455112047e21d6191a1a2380aa27dd0..4df0b320d524e351847e9f2b270237731b2b1607 100644 (file)
@@ -19,7 +19,6 @@
 #include <asm/system.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
-#include <linux/fs_struct.h>
 #include <linux/init_task.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
index 64f068540d0dab1f33c21e2518f8aef23040239c..706eb5c7e2ee45c9cb71d5c09fc5517d12966df4 100644 (file)
@@ -635,7 +635,7 @@ long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode,
        if (dentry->d_inode)
                goto out_dput;
 
-       mode &= ~current->fs->umask;
+       mode &= ~current_umask();
 
        if (flags & SPU_CREATE_GANG)
                ret = spufs_create_gang(nd->path.dentry->d_inode,
index 34ab6d798f819ebf2a62ad56f0abdfec1addd8d2..55ba6f142883f6de16cc0460b540bbc64b932738 100644 (file)
@@ -10,8 +10,6 @@
  */
 
 #include <linux/audit.h>
-#include <linux/file.h>
-#include <linux/fdtable.h>
 #include <linux/tty.h>
 
 struct tty_audit_buf {
index 7a84b406a9522d633f6eab84ada8134319b2aeac..f78f5b0127a88501ec0b21cf9d42c517209ad933 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/tty_flip.h>
 #include <linux/devpts_fs.h>
 #include <linux/file.h>
-#include <linux/fdtable.h>
 #include <linux/console.h>
 #include <linux/timer.h>
 #include <linux/ctype.h>
index 6e82a307bcd436c6d131b67f120c4324ad34aafe..b5cd8e18dd9feb14317339cf5220d39102d48f0a 100644 (file)
@@ -11,7 +11,7 @@ obj-y :=      open.o read_write.o file_table.o super.o \
                attr.o bad_inode.o file.o filesystems.o namespace.o \
                seq_file.o xattr.o libfs.o fs-writeback.o \
                pnode.o drop_caches.o splice.o sync.o utimes.o \
-               stack.o
+               stack.o fs_struct.o
 
 ifeq ($(CONFIG_BLOCK),y)
 obj-y +=       buffer.o bio.o block_dev.o direct-io.o mpage.o ioprio.o
index 33b7235f853b2d46a7a685d805163d57ee0ef505..40381df348697263027536cd182e4b1294052bd7 100644 (file)
@@ -12,8 +12,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/fs.h>
-#include <linux/stat.h>
-#include <linux/time.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
 #include <linux/errno.h>
 #include <linux/binfmts.h>
 #include <linux/string.h>
 #include <linux/file.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
 #include <linux/slab.h>
-#include <linux/shm.h>
 #include <linux/personality.h>
 #include <linux/elfcore.h>
 #include <linux/init.h>
 #include <linux/highuid.h>
-#include <linux/smp.h>
 #include <linux/compiler.h>
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
 #include <linux/security.h>
-#include <linux/syscalls.h>
 #include <linux/random.h>
 #include <linux/elf.h>
 #include <linux/utsname.h>
@@ -576,7 +569,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
        unsigned long error;
        struct elf_phdr *elf_ppnt, *elf_phdata;
        unsigned long elf_bss, elf_brk;
-       int elf_exec_fileno;
        int retval, i;
        unsigned int size;
        unsigned long elf_entry;
@@ -631,12 +623,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
                goto out_free_ph;
        }
 
-       retval = get_unused_fd();
-       if (retval < 0)
-               goto out_free_ph;
-       get_file(bprm->file);
-       fd_install(elf_exec_fileno = retval, bprm->file);
-
        elf_ppnt = elf_phdata;
        elf_bss = 0;
        elf_brk = 0;
@@ -655,13 +641,13 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
                        retval = -ENOEXEC;
                        if (elf_ppnt->p_filesz > PATH_MAX || 
                            elf_ppnt->p_filesz < 2)
-                               goto out_free_file;
+                               goto out_free_ph;
 
                        retval = -ENOMEM;
                        elf_interpreter = kmalloc(elf_ppnt->p_filesz,
                                                  GFP_KERNEL);
                        if (!elf_interpreter)
-                               goto out_free_file;
+                               goto out_free_ph;
 
                        retval = kernel_read(bprm->file, elf_ppnt->p_offset,
                                             elf_interpreter,
@@ -956,8 +942,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 
        kfree(elf_phdata);
 
-       sys_close(elf_exec_fileno);
-
        set_binfmt(&elf_format);
 
 #ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES
@@ -1028,8 +1012,6 @@ out_free_dentry:
                fput(interpreter);
 out_free_interp:
        kfree(elf_interpreter);
-out_free_file:
-       sys_close(elf_exec_fileno);
 out_free_ph:
        kfree(elf_phdata);
        goto out;
index 08644a61616e1e7bb6cacb655de0ad06387d3ada..eff74b9c9e77cf8f0b933adb2addcc9aac899a46 100644 (file)
@@ -188,7 +188,6 @@ out:
 static int
 load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
 {
-       int som_exec_fileno;
        int retval;
        unsigned int size;
        unsigned long som_entry;
@@ -220,12 +219,6 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
                goto out_free;
        }
 
-       retval = get_unused_fd();
-       if (retval < 0)
-               goto out_free;
-       get_file(bprm->file);
-       fd_install(som_exec_fileno = retval, bprm->file);
-
        /* Flush all traces of the currently running executable */
        retval = flush_old_exec(bprm);
        if (retval)
index 8c3c6899ccf33f433969e1b48b045a6a896b55ef..f45dbc18dd175891950ddb84fffa2bc6ce0df117 100644 (file)
@@ -204,6 +204,7 @@ int fsync_bdev(struct block_device *bdev)
        }
        return sync_blockdev(bdev);
 }
+EXPORT_SYMBOL(fsync_bdev);
 
 /**
  * freeze_bdev  --  lock a filesystem and force it into a consistent state
index 1d53b62dbba51aa61896c8e78ab50b6544e5c267..7fdd184a528d11caa58ddb37f8d59d07de17a517 100644 (file)
@@ -256,7 +256,7 @@ int btrfs_init_acl(struct inode *inode, struct inode *dir)
                }
 
                if (!acl)
-                       inode->i_mode &= ~current->fs->umask;
+                       inode->i_mode &= ~current_umask();
        }
 
        if (IS_POSIXACL(dir) && acl) {
index bca729fc80c83e07a3847b2b7bb6e73123d6c30f..7594bec1be10066619db8ebb578d03f5d2101de1 100644 (file)
@@ -267,7 +267,7 @@ static noinline int btrfs_mksubvol(struct path *parent, char *name,
                goto out_dput;
 
        if (!IS_POSIXACL(parent->dentry->d_inode))
-               mode &= ~current->fs->umask;
+               mode &= ~current_umask();
 
        error = mnt_want_write(parent->mnt);
        if (error)
index 2963858f0f31f106b878966c75ca09991c7486f7..c2fa1be4923d19885dab161d45a53588ff296ac5 100644 (file)
@@ -3315,7 +3315,6 @@ EXPORT_SYMBOL(cont_write_begin);
 EXPORT_SYMBOL(end_buffer_read_sync);
 EXPORT_SYMBOL(end_buffer_write_sync);
 EXPORT_SYMBOL(file_fsync);
-EXPORT_SYMBOL(fsync_bdev);
 EXPORT_SYMBOL(generic_block_bmap);
 EXPORT_SYMBOL(generic_cont_expand_simple);
 EXPORT_SYMBOL(init_buffer);
index 2f35cccfcd8d202423c4e9e1434d139cf78dc084..54dce78fbb7320cdc7d6449fa347142838d51eba 100644 (file)
@@ -254,7 +254,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
                return -ENOMEM;
        }
 
-       mode &= ~current->fs->umask;
+       mode &= ~current_umask();
        if (oplockEnabled)
                oplock = REQ_OPLOCK;
 
@@ -479,7 +479,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
                rc = -ENOMEM;
        else if (pTcon->unix_ext) {
                struct cifs_unix_set_info_args args = {
-                       .mode   = mode & ~current->fs->umask,
+                       .mode   = mode & ~current_umask(),
                        .ctime  = NO_CHANGE_64,
                        .atime  = NO_CHANGE_64,
                        .mtime  = NO_CHANGE_64,
index a8797cc60805e4b732a4f1557f8590f353073455..f121a80fdd6fa15e7d6d61ddc8576f9be46550f0 100644 (file)
@@ -1125,7 +1125,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
                        goto mkdir_out;
                }
 
-               mode &= ~current->fs->umask;
+               mode &= ~current_umask();
                rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT,
                                mode, NULL /* netfid */, pInfo, &oplock,
                                full_path, cifs_sb->local_nls,
@@ -1204,7 +1204,7 @@ mkdir_get_info:
                if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
                                direntry->d_inode->i_nlink = 2;
 
-               mode &= ~current->fs->umask;
+               mode &= ~current_umask();
                /* must turn on setgid bit if parent dir has it */
                if (inode->i_mode & S_ISGID)
                        mode |= S_ISGID;
index 440a019256ddde7a0283f23496f629a97e1f6b13..1c859dae758f8a01efa3e1e793bcfffc42fce604 100644 (file)
@@ -51,6 +51,7 @@
 #include <linux/poll.h>
 #include <linux/mm.h>
 #include <linux/eventpoll.h>
+#include <linux/fs_struct.h>
 
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
@@ -1502,12 +1503,15 @@ int compat_do_execve(char * filename,
        bprm->cred = prepare_exec_creds();
        if (!bprm->cred)
                goto out_unlock;
-       check_unsafe_exec(bprm);
+
+       retval = check_unsafe_exec(bprm);
+       if (retval)
+               goto out_unlock;
 
        file = open_exec(filename);
        retval = PTR_ERR(file);
        if (IS_ERR(file))
-               goto out_unlock;
+               goto out_unmark;
 
        sched_exec();
 
@@ -1549,6 +1553,9 @@ int compat_do_execve(char * filename,
                goto out;
 
        /* execve succeeded */
+       write_lock(&current->fs->lock);
+       current->fs->in_exec = 0;
+       write_unlock(&current->fs->lock);
        current->in_execve = 0;
        mutex_unlock(&current->cred_exec_mutex);
        acct_update_integrals(current);
@@ -1567,6 +1574,11 @@ out_file:
                fput(bprm->file);
        }
 
+out_unmark:
+       write_lock(&current->fs->lock);
+       current->fs->in_exec = 0;
+       write_unlock(&current->fs->lock);
+
 out_unlock:
        current->in_execve = 0;
        mutex_unlock(&current->cred_exec_mutex);
index 90bbd7e1b116d0ec48a07d8dab88c5086fb647d6..761d30be2683c42daf960535269633aab510fec3 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/syscalls.h>
 #include <linux/string.h>
 #include <linux/mm.h>
-#include <linux/fdtable.h>
 #include <linux/fs.h>
 #include <linux/fsnotify.h>
 #include <linux/slab.h>
@@ -32,6 +31,7 @@
 #include <linux/seqlock.h>
 #include <linux/swap.h>
 #include <linux/bootmem.h>
+#include <linux/fs_struct.h>
 #include "internal.h"
 
 int sysctl_vfs_cache_pressure __read_mostly = 100;
index c5128fbc9165235832a3851b663eb23a2ab8935d..052a961e41aad189b264c22e11cfd65a77a1ef22 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -53,6 +53,7 @@
 #include <linux/tracehook.h>
 #include <linux/kmod.h>
 #include <linux/fsnotify.h>
+#include <linux/fs_struct.h>
 
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
@@ -1056,28 +1057,35 @@ EXPORT_SYMBOL(install_exec_creds);
  * - the caller must hold current->cred_exec_mutex to protect against
  *   PTRACE_ATTACH
  */
-void check_unsafe_exec(struct linux_binprm *bprm)
+int check_unsafe_exec(struct linux_binprm *bprm)
 {
        struct task_struct *p = current, *t;
        unsigned long flags;
-       unsigned n_fs, n_sighand;
+       unsigned n_fs;
+       int res = 0;
 
        bprm->unsafe = tracehook_unsafe_exec(p);
 
        n_fs = 1;
-       n_sighand = 1;
+       write_lock(&p->fs->lock);
        lock_task_sighand(p, &flags);
        for (t = next_thread(p); t != p; t = next_thread(t)) {
                if (t->fs == p->fs)
                        n_fs++;
-               n_sighand++;
        }
 
-       if (atomic_read(&p->fs->count) > n_fs ||
-           atomic_read(&p->sighand->count) > n_sighand)
+       if (p->fs->users > n_fs) {
                bprm->unsafe |= LSM_UNSAFE_SHARE;
+       } else {
+               if (p->fs->in_exec)
+                       res = -EAGAIN;
+               p->fs->in_exec = 1;
+       }
 
        unlock_task_sighand(p, &flags);
+       write_unlock(&p->fs->lock);
+
+       return res;
 }
 
 /* 
@@ -1296,12 +1304,15 @@ int do_execve(char * filename,
        bprm->cred = prepare_exec_creds();
        if (!bprm->cred)
                goto out_unlock;
-       check_unsafe_exec(bprm);
+
+       retval = check_unsafe_exec(bprm);
+       if (retval)
+               goto out_unlock;
 
        file = open_exec(filename);
        retval = PTR_ERR(file);
        if (IS_ERR(file))
-               goto out_unlock;
+               goto out_unmark;
 
        sched_exec();
 
@@ -1344,6 +1355,9 @@ int do_execve(char * filename,
                goto out;
 
        /* execve succeeded */
+       write_lock(&current->fs->lock);
+       current->fs->in_exec = 0;
+       write_unlock(&current->fs->lock);
        current->in_execve = 0;
        mutex_unlock(&current->cred_exec_mutex);
        acct_update_integrals(current);
@@ -1362,6 +1376,11 @@ out_file:
                fput(bprm->file);
        }
 
+out_unmark:
+       write_lock(&current->fs->lock);
+       current->fs->in_exec = 0;
+       write_unlock(&current->fs->lock);
+
 out_unlock:
        current->in_execve = 0;
        mutex_unlock(&current->cred_exec_mutex);
index ae8c4f850b27d0e83e28e684a07637a992abbe69..d46e38cb85c557e273e8206c32b38c9426799ae3 100644 (file)
@@ -318,7 +318,7 @@ ext2_init_acl(struct inode *inode, struct inode *dir)
                                return PTR_ERR(acl);
                }
                if (!acl)
-                       inode->i_mode &= ~current->fs->umask;
+                       inode->i_mode &= ~current_umask();
        }
        if (test_opt(inode->i_sb, POSIX_ACL) && acl) {
                struct posix_acl *clone;
index b60bb241880c86f50420e13411dc19b1148e1a51..d81ef2fdb08e0aeca8e533963db7f7feeecbd386 100644 (file)
@@ -323,7 +323,7 @@ ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
                                return PTR_ERR(acl);
                }
                if (!acl)
-                       inode->i_mode &= ~current->fs->umask;
+                       inode->i_mode &= ~current_umask();
        }
        if (test_opt(inode->i_sb, POSIX_ACL) && acl) {
                struct posix_acl *clone;
index 694ed6fadcc8c59e1936a49919c67a427ba670e5..647e0d65a2844e227a774cf4b629e5739a0df0cd 100644 (file)
@@ -323,7 +323,7 @@ ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
                                return PTR_ERR(acl);
                }
                if (!acl)
-                       inode->i_mode &= ~current->fs->umask;
+                       inode->i_mode &= ~current_umask();
        }
        if (test_opt(inode->i_sb, POSIX_ACL) && acl) {
                struct posix_acl *clone;
index 2cc952e4c3dc37279a8fde4f1279408c4151d474..296785a0dec8068471d5e5764fd41cea1bcc9903 100644 (file)
@@ -934,7 +934,7 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug,
 
        opts->fs_uid = current_uid();
        opts->fs_gid = current_gid();
-       opts->fs_fmask = opts->fs_dmask = current->fs->umask;
+       opts->fs_fmask = current_umask();
        opts->allow_utime = -1;
        opts->codepage = fat_default_codepage;
        opts->iocharset = fat_default_iocharset;
diff --git a/fs/fs_struct.c b/fs/fs_struct.c
new file mode 100644 (file)
index 0000000..eee0590
--- /dev/null
@@ -0,0 +1,177 @@
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/path.h>
+#include <linux/slab.h>
+#include <linux/fs_struct.h>
+
+/*
+ * Replace the fs->{rootmnt,root} with {mnt,dentry}. Put the old values.
+ * It can block.
+ */
+void set_fs_root(struct fs_struct *fs, struct path *path)
+{
+       struct path old_root;
+
+       write_lock(&fs->lock);
+       old_root = fs->root;
+       fs->root = *path;
+       path_get(path);
+       write_unlock(&fs->lock);
+       if (old_root.dentry)
+               path_put(&old_root);
+}
+
+/*
+ * Replace the fs->{pwdmnt,pwd} with {mnt,dentry}. Put the old values.
+ * It can block.
+ */
+void set_fs_pwd(struct fs_struct *fs, struct path *path)
+{
+       struct path old_pwd;
+
+       write_lock(&fs->lock);
+       old_pwd = fs->pwd;
+       fs->pwd = *path;
+       path_get(path);
+       write_unlock(&fs->lock);
+
+       if (old_pwd.dentry)
+               path_put(&old_pwd);
+}
+
+void chroot_fs_refs(struct path *old_root, struct path *new_root)
+{
+       struct task_struct *g, *p;
+       struct fs_struct *fs;
+       int count = 0;
+
+       read_lock(&tasklist_lock);
+       do_each_thread(g, p) {
+               task_lock(p);
+               fs = p->fs;
+               if (fs) {
+                       write_lock(&fs->lock);
+                       if (fs->root.dentry == old_root->dentry
+                           && fs->root.mnt == old_root->mnt) {
+                               path_get(new_root);
+                               fs->root = *new_root;
+                               count++;
+                       }
+                       if (fs->pwd.dentry == old_root->dentry
+                           && fs->pwd.mnt == old_root->mnt) {
+                               path_get(new_root);
+                               fs->pwd = *new_root;
+                               count++;
+                       }
+                       write_unlock(&fs->lock);
+               }
+               task_unlock(p);
+       } while_each_thread(g, p);
+       read_unlock(&tasklist_lock);
+       while (count--)
+               path_put(old_root);
+}
+
+void free_fs_struct(struct fs_struct *fs)
+{
+       path_put(&fs->root);
+       path_put(&fs->pwd);
+       kmem_cache_free(fs_cachep, fs);
+}
+
+void exit_fs(struct task_struct *tsk)
+{
+       struct fs_struct *fs = tsk->fs;
+
+       if (fs) {
+               int kill;
+               task_lock(tsk);
+               write_lock(&fs->lock);
+               tsk->fs = NULL;
+               kill = !--fs->users;
+               write_unlock(&fs->lock);
+               task_unlock(tsk);
+               if (kill)
+                       free_fs_struct(fs);
+       }
+}
+
+struct fs_struct *copy_fs_struct(struct fs_struct *old)
+{
+       struct fs_struct *fs = kmem_cache_alloc(fs_cachep, GFP_KERNEL);
+       /* We don't need to lock fs - think why ;-) */
+       if (fs) {
+               fs->users = 1;
+               fs->in_exec = 0;
+               rwlock_init(&fs->lock);
+               fs->umask = old->umask;
+               read_lock(&old->lock);
+               fs->root = old->root;
+               path_get(&old->root);
+               fs->pwd = old->pwd;
+               path_get(&old->pwd);
+               read_unlock(&old->lock);
+       }
+       return fs;
+}
+
+int unshare_fs_struct(void)
+{
+       struct fs_struct *fs = current->fs;
+       struct fs_struct *new_fs = copy_fs_struct(fs);
+       int kill;
+
+       if (!new_fs)
+               return -ENOMEM;
+
+       task_lock(current);
+       write_lock(&fs->lock);
+       kill = !--fs->users;
+       current->fs = new_fs;
+       write_unlock(&fs->lock);
+       task_unlock(current);
+
+       if (kill)
+               free_fs_struct(fs);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(unshare_fs_struct);
+
+int current_umask(void)
+{
+       return current->fs->umask;
+}
+EXPORT_SYMBOL(current_umask);
+
+/* to be mentioned only in INIT_TASK */
+struct fs_struct init_fs = {
+       .users          = 1,
+       .lock           = __RW_LOCK_UNLOCKED(init_fs.lock),
+       .umask          = 0022,
+};
+
+void daemonize_fs_struct(void)
+{
+       struct fs_struct *fs = current->fs;
+
+       if (fs) {
+               int kill;
+
+               task_lock(current);
+
+               write_lock(&init_fs.lock);
+               init_fs.users++;
+               write_unlock(&init_fs.lock);
+
+               write_lock(&fs->lock);
+               current->fs = &init_fs;
+               kill = !--fs->users;
+               write_unlock(&fs->lock);
+
+               task_unlock(current);
+               if (kill)
+                       free_fs_struct(fs);
+       }
+}
index 995d63b2e747556c879c52be194375196995b58a..e0b53aa7bbec11037ba8f9c2bd35f33392249ecd 100644 (file)
@@ -134,7 +134,7 @@ generic_acl_init(struct inode *inode, struct inode *dir,
        mode_t mode = inode->i_mode;
        int error;
 
-       inode->i_mode = mode & ~current->fs->umask;
+       inode->i_mode = mode & ~current_umask();
        if (!S_ISLNK(inode->i_mode))
                acl = ops->getacl(dir, ACL_TYPE_DEFAULT);
        if (acl) {
index 43764f4fa763a148f8bd0b67ed69b8755fa070be..fa881bdc3d8577647d486aa7772eecc3b72177d3 100644 (file)
@@ -215,7 +215,7 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip)
        if (error)
                return error;
        if (!acl) {
-               mode &= ~current->fs->umask;
+               mode &= ~current_umask();
                if (mode != ip->i_inode.i_mode)
                        error = munge_mode(ip, mode);
                return error;
index bab7f8d1bdfa9f97ad8f3c85786daf9ecbc3c9df..3fcbb0e1f6fc09ea43f1918d4099f695937b0db1 100644 (file)
@@ -48,7 +48,7 @@ void hfsplus_fill_defaults(struct hfsplus_sb_info *opts)
 
        opts->creator = HFSPLUS_DEF_CR_TYPE;
        opts->type = HFSPLUS_DEF_CR_TYPE;
-       opts->umask = current->fs->umask;
+       opts->umask = current_umask();
        opts->uid = current_uid();
        opts->gid = current_gid();
        opts->part = -1;
index c40f6e24244476d3af40988d7320cbf4de3ac0f5..fecf402d7b8a42ce7f7bf4b1595e71f51d5b88b5 100644 (file)
@@ -480,7 +480,7 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent)
 
        uid = current_uid();
        gid = current_gid();
-       umask = current->fs->umask;
+       umask = current_umask();
        lowercase = 0;
        conv = CONV_BINARY;
        eas = 2;
index 53af885f173243df3a5bf0906b589edccece84db..b4dac4fb6b61fbff06d9357d9c75415bbab0a3ac 100644 (file)
@@ -11,6 +11,7 @@
 
 struct super_block;
 struct linux_binprm;
+struct path;
 
 /*
  * block_dev.c
@@ -43,7 +44,7 @@ extern void __init chrdev_init(void);
 /*
  * exec.c
  */
-extern void check_unsafe_exec(struct linux_binprm *);
+extern int check_unsafe_exec(struct linux_binprm *);
 
 /*
  * namespace.c
@@ -60,3 +61,8 @@ extern void umount_tree(struct vfsmount *, int, struct list_head *);
 extern struct vfsmount *copy_tree(struct vfsmount *, struct dentry *, int);
 
 extern void __init mnt_init(void);
+
+/*
+ * fs_struct.c
+ */
+extern void chroot_fs_refs(struct path *, struct path *);
index d98713777a1b62f2aa12f659dd872616d2dbeb4a..77ccf8cb0823c805ff9af233aba63404d0df01a2 100644 (file)
@@ -336,7 +336,7 @@ int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, int *i_mode)
                return PTR_ERR(acl);
 
        if (!acl) {
-               *i_mode &= ~current->fs->umask;
+               *i_mode &= ~current_umask();
        } else {
                if (S_ISDIR(*i_mode))
                        jffs2_iset_acl(inode, &f->i_acl_default, acl);
index a166c1669e823823844790f43e04ee13a14a6011..06ca1b8d205459e2a2bbbfb35282d0f576ee788c 100644 (file)
@@ -182,7 +182,7 @@ int jfs_init_acl(tid_t tid, struct inode *inode, struct inode *dir)
 cleanup:
                posix_acl_release(acl);
        } else
-               inode->i_mode &= ~current->fs->umask;
+               inode->i_mode &= ~current_umask();
 
        JFS_IP(inode)->mode2 = (JFS_IP(inode)->mode2 & 0xffff0000) |
                               inode->i_mode;
index 16c3ef37eae348ed97ad90229d427449699315a3..680ba60863ffb2dee0f81ffbda6974c419c79668 100644 (file)
@@ -82,7 +82,7 @@ static void mpage_end_io_write(struct bio *bio, int err)
        bio_put(bio);
 }
 
-struct bio *mpage_bio_submit(int rw, struct bio *bio)
+static struct bio *mpage_bio_submit(int rw, struct bio *bio)
 {
        bio->bi_end_io = mpage_end_io_read;
        if (rw == WRITE)
@@ -90,7 +90,6 @@ struct bio *mpage_bio_submit(int rw, struct bio *bio)
        submit_bio(rw, bio);
        return NULL;
 }
-EXPORT_SYMBOL(mpage_bio_submit);
 
 static struct bio *
 mpage_alloc(struct block_device *bdev,
@@ -439,7 +438,14 @@ EXPORT_SYMBOL(mpage_readpage);
  * just allocate full-size (16-page) BIOs.
  */
 
-int __mpage_writepage(struct page *page, struct writeback_control *wbc,
+struct mpage_data {
+       struct bio *bio;
+       sector_t last_block_in_bio;
+       get_block_t *get_block;
+       unsigned use_writepage;
+};
+
+static int __mpage_writepage(struct page *page, struct writeback_control *wbc,
                      void *data)
 {
        struct mpage_data *mpd = data;
@@ -648,7 +654,6 @@ out:
        mpd->bio = bio;
        return ret;
 }
-EXPORT_SYMBOL(__mpage_writepage);
 
 /**
  * mpage_writepages - walk the list of dirty pages of the given address space & writepage() all of them
index d040ce11785d6acb115154da5e83a7500909df13..b8433ebfae055424c5d953ff3ff9c96bc7c7a628 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/file.h>
 #include <linux/fcntl.h>
 #include <linux/device_cgroup.h>
+#include <linux/fs_struct.h>
 #include <asm/uaccess.h>
 
 #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
@@ -1578,7 +1579,7 @@ static int __open_namei_create(struct nameidata *nd, struct path *path,
        struct dentry *dir = nd->path.dentry;
 
        if (!IS_POSIXACL(dir->d_inode))
-               mode &= ~current->fs->umask;
+               mode &= ~current_umask();
        error = security_path_mknod(&nd->path, path->dentry, mode, 0);
        if (error)
                goto out_unlock;
@@ -1989,7 +1990,7 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, int, mode,
                goto out_unlock;
        }
        if (!IS_POSIXACL(nd.path.dentry->d_inode))
-               mode &= ~current->fs->umask;
+               mode &= ~current_umask();
        error = may_mknod(mode);
        if (error)
                goto out_dput;
@@ -2067,7 +2068,7 @@ SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, int, mode)
                goto out_unlock;
 
        if (!IS_POSIXACL(nd.path.dentry->d_inode))
-               mode &= ~current->fs->umask;
+               mode &= ~current_umask();
        error = mnt_want_write(nd.path.mnt);
        if (error)
                goto out_dput;
@@ -2897,10 +2898,3 @@ EXPORT_SYMBOL(vfs_symlink);
 EXPORT_SYMBOL(vfs_unlink);
 EXPORT_SYMBOL(dentry_unhash);
 EXPORT_SYMBOL(generic_readlink);
-
-/* to be mentioned only in INIT_TASK */
-struct fs_struct init_fs = {
-       .count          = ATOMIC_INIT(1),
-       .lock           = __RW_LOCK_UNLOCKED(init_fs.lock),
-       .umask          = 0022,
-};
index 0a42e0e9602766939a6ac0a2e444df2992adc3f9..c6f54e4c42901f2cf0d91432507962fbc91552b7 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/ramfs.h>
 #include <linux/log2.h>
 #include <linux/idr.h>
+#include <linux/fs_struct.h>
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
 #include "pnode.h"
@@ -2092,66 +2093,6 @@ out1:
        return retval;
 }
 
-/*
- * Replace the fs->{rootmnt,root} with {mnt,dentry}. Put the old values.
- * It can block. Requires the big lock held.
- */
-void set_fs_root(struct fs_struct *fs, struct path *path)
-{
-       struct path old_root;
-
-       write_lock(&fs->lock);
-       old_root = fs->root;
-       fs->root = *path;
-       path_get(path);
-       write_unlock(&fs->lock);
-       if (old_root.dentry)
-               path_put(&old_root);
-}
-
-/*
- * Replace the fs->{pwdmnt,pwd} with {mnt,dentry}. Put the old values.
- * It can block. Requires the big lock held.
- */
-void set_fs_pwd(struct fs_struct *fs, struct path *path)
-{
-       struct path old_pwd;
-
-       write_lock(&fs->lock);
-       old_pwd = fs->pwd;
-       fs->pwd = *path;
-       path_get(path);
-       write_unlock(&fs->lock);
-
-       if (old_pwd.dentry)
-               path_put(&old_pwd);
-}
-
-static void chroot_fs_refs(struct path *old_root, struct path *new_root)
-{
-       struct task_struct *g, *p;
-       struct fs_struct *fs;
-
-       read_lock(&tasklist_lock);
-       do_each_thread(g, p) {
-               task_lock(p);
-               fs = p->fs;
-               if (fs) {
-                       atomic_inc(&fs->count);
-                       task_unlock(p);
-                       if (fs->root.dentry == old_root->dentry
-                           && fs->root.mnt == old_root->mnt)
-                               set_fs_root(fs, new_root);
-                       if (fs->pwd.dentry == old_root->dentry
-                           && fs->pwd.mnt == old_root->mnt)
-                               set_fs_pwd(fs, new_root);
-                       put_fs_struct(fs);
-               } else
-                       task_unlock(p);
-       } while_each_thread(g, p);
-       read_unlock(&tasklist_lock);
-}
-
 /*
  * pivot_root Semantics:
  * Moves the root file system of the current process to the directory put_old,
index b82fe6847f14ebfeba27f3bf01303f6f4df63236..d0cc5ce0edfe8ada1d9598143e291c3683882393 100644 (file)
@@ -328,7 +328,7 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
                data->arg.create.verifier[1] = current->pid;
        }
 
-       sattr->ia_mode &= ~current->fs->umask;
+       sattr->ia_mode &= ~current_umask();
 
        for (;;) {
                status = nfs3_do_create(dir, dentry, data);
@@ -528,7 +528,7 @@ nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
 
        dprintk("NFS call  mkdir %s\n", dentry->d_name.name);
 
-       sattr->ia_mode &= ~current->fs->umask;
+       sattr->ia_mode &= ~current_umask();
 
        data = nfs3_alloc_createdata();
        if (data == NULL)
@@ -639,7 +639,7 @@ nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
        dprintk("NFS call  mknod %s %u:%u\n", dentry->d_name.name,
                        MAJOR(rdev), MINOR(rdev));
 
-       sattr->ia_mode &= ~current->fs->umask;
+       sattr->ia_mode &= ~current_umask();
 
        data = nfs3_alloc_createdata();
        if (data == NULL)
index 97bacccff57947fe756dc8bae29ad06e57d0159b..a4d242680299fa91795fc43ffe7492c63cf4dedf 100644 (file)
@@ -1501,7 +1501,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
                attr.ia_mode = nd->intent.open.create_mode;
                attr.ia_valid = ATTR_MODE;
                if (!IS_POSIXACL(dir))
-                       attr.ia_mode &= ~current->fs->umask;
+                       attr.ia_mode &= ~current_umask();
        } else {
                attr.ia_valid = 0;
                BUG_ON(nd->intent.open.flags & O_CREAT);
index bc3567bab8c47dfb98a50aa00ef6dd5b068e40e2..7c09852be713b91ef9de1f507aafb04ad61a35a9 100644 (file)
@@ -403,7 +403,6 @@ static int
 nfsd(void *vrqstp)
 {
        struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp;
-       struct fs_struct *fsp;
        int err, preverr = 0;
 
        /* Lock module and set up kernel thread */
@@ -412,13 +411,11 @@ nfsd(void *vrqstp)
        /* At this point, the thread shares current->fs
         * with the init process. We need to create files with a
         * umask of 0 instead of init's umask. */
-       fsp = copy_fs_struct(current->fs);
-       if (!fsp) {
+       if (unshare_fs_struct() < 0) {
                printk("Unable to start nfsd thread: out of memory\n");
                goto out;
        }
-       exit_fs(current);
-       current->fs = fsp;
+
        current->fs->umask = 0;
 
        /*
index 12dfb44c22e57d3e82e8ed038de231008e926c9a..fbeaec762103a91eacd396f47a999244303954ee 100644 (file)
@@ -296,7 +296,7 @@ int ocfs2_init_acl(handle_t *handle,
                                return PTR_ERR(acl);
                }
                if (!acl)
-                       inode->i_mode &= ~current->fs->umask;
+                       inode->i_mode &= ~current_umask();
        }
        if ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) && acl) {
                struct posix_acl *clone;
index d79e808fd028dbdd7fb31aa4390a84d50010440e..379ae5fb441154a0f2e27fb0f9b34846c7ca089a 100644 (file)
@@ -426,7 +426,7 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent)
 
        sbi->s_uid = current_uid();
        sbi->s_gid = current_gid();
-       sbi->s_dmask = sbi->s_fmask = current->fs->umask;
+       sbi->s_dmask = sbi->s_fmask = current_umask();
 
        if (!parse_options((char *) data, sbi))
                goto end;
index 75b61677daafa9fdf0317ae58afd5d017ef03c2e..377eb25b6abfd84a11dadb716cb03cffe6b32f99 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -29,6 +29,7 @@
 #include <linux/rcupdate.h>
 #include <linux/audit.h>
 #include <linux/falloc.h>
+#include <linux/fs_struct.h>
 
 int vfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
index e0afd326b6881b7ff2506e1d9041ed12c7ce1e0d..f71559784bfb9bbc70b4d021cd2120c4bfa2121c 100644 (file)
@@ -80,6 +80,7 @@
 #include <linux/oom.h>
 #include <linux/elf.h>
 #include <linux/pid_namespace.h>
+#include <linux/fs_struct.h>
 #include "internal.h"
 
 /* NOTE:
index 370be0a2c9098ea411ed98bd49d2de929392f32f..863464d5519c935df03a510f9ab03f7e731f14e9 100644 (file)
@@ -2,6 +2,7 @@
 #include <linux/mm.h>
 #include <linux/file.h>
 #include <linux/fdtable.h>
+#include <linux/fs_struct.h>
 #include <linux/mount.h>
 #include <linux/ptrace.h>
 #include <linux/seq_file.h>
@@ -49,7 +50,7 @@ void task_mem(struct seq_file *m, struct mm_struct *mm)
        else
                bytes += kobjsize(mm);
        
-       if (current->fs && atomic_read(&current->fs->count) > 1)
+       if (current->fs && current->fs->users > 1)
                sbytes += kobjsize(current->fs);
        else
                bytes += kobjsize(current->fs);
index d423416d93d14a90e894331b574f238b45055d78..c303c426fe2ba6ffec8d708323026f36fbd40f90 100644 (file)
@@ -428,7 +428,7 @@ reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
        } else {
              apply_umask:
                /* no ACL, apply umask */
-               inode->i_mode &= ~current->fs->umask;
+               inode->i_mode &= ~current_umask();
        }
 
        return err;
index 7aa53fefc67fafe14bb54db40398f79945f1baae..2940612e3aeb4bf2f47c17bed0ed7982e121f327 100644 (file)
@@ -227,7 +227,7 @@ xfs_vn_mknod(
        xfs_dentry_to_name(&name, dentry);
 
        if (IS_POSIXACL(dir) && !default_acl)
-               mode &= ~current->fs->umask;
+               mode &= ~current_umask();
 
        switch (mode & S_IFMT) {
        case S_IFCHR:
@@ -416,7 +416,7 @@ xfs_vn_symlink(
        mode_t          mode;
 
        mode = S_IFLNK |
-               (irix_symlink_mode ? 0777 & ~current->fs->umask : S_IRWXUGO);
+               (irix_symlink_mode ? 0777 & ~current_umask() : S_IRWXUGO);
        xfs_dentry_to_name(&name, dentry);
 
        error = xfs_symlink(XFS_I(dir), &name, symname, mode, &cip, NULL);
index 3d7bcde2e3325dacb1e5ec32ee3f1a50ad4e1725..7b73bb8f19708ebbfc672bf18b489ae198310939 100644 (file)
@@ -332,22 +332,10 @@ extern int __set_page_dirty_buffers(struct page *page);
 
 static inline void buffer_init(void) {}
 static inline int try_to_free_buffers(struct page *page) { return 1; }
-static inline int sync_blockdev(struct block_device *bdev) { return 0; }
 static inline int inode_has_buffers(struct inode *inode) { return 0; }
 static inline void invalidate_inode_buffers(struct inode *inode) {}
 static inline int remove_inode_buffers(struct inode *inode) { return 1; }
 static inline int sync_mapping_buffers(struct address_space *mapping) { return 0; }
-static inline void invalidate_bdev(struct block_device *bdev) {}
-
-static inline struct super_block *freeze_bdev(struct block_device *sb)
-{
-       return NULL;
-}
-
-static inline int thaw_bdev(struct block_device *bdev, struct super_block *sb)
-{
-       return 0;
-}
 
 #endif /* CONFIG_BLOCK */
 #endif /* _LINUX_BUFFER_HEAD_H */
index 61211ad823fe6b4e251e048866751cffd4409741..a09e17c8f5fd9137720b008196aa29f45ff17bfb 100644 (file)
@@ -1741,6 +1741,8 @@ extern void drop_collected_mounts(struct vfsmount *);
 
 extern int vfs_statfs(struct dentry *, struct kstatfs *);
 
+extern int current_umask(void);
+
 /* /sys/fs */
 extern struct kobject *fs_kobj;
 
@@ -1885,6 +1887,18 @@ extern int fsync_super(struct super_block *);
 extern int fsync_no_super(struct block_device *);
 #else
 static inline void bd_forget(struct inode *inode) {}
+static inline int sync_blockdev(struct block_device *bdev) { return 0; }
+static inline void invalidate_bdev(struct block_device *bdev) {}
+
+static inline struct super_block *freeze_bdev(struct block_device *sb)
+{
+       return NULL;
+}
+
+static inline int thaw_bdev(struct block_device *bdev, struct super_block *sb)
+{
+       return 0;
+}
 #endif
 extern const struct file_operations def_blk_fops;
 extern const struct file_operations def_chr_fops;
index 18b467dbe278bf4b399274ff272355d2984530ce..78a05bfcd8ebd6075b2add0da9da064804e645d6 100644 (file)
@@ -4,12 +4,10 @@
 #include <linux/path.h>
 
 struct fs_struct {
-       atomic_t count; /* This usage count is used by check_unsafe_exec() for
-                        * security checking purposes - therefore it may not be
-                        * incremented, except by clone(CLONE_FS).
-                        */
+       int users;
        rwlock_t lock;
        int umask;
+       int in_exec;
        struct path root, pwd;
 };
 
@@ -19,6 +17,8 @@ extern void exit_fs(struct task_struct *);
 extern void set_fs_root(struct fs_struct *, struct path *);
 extern void set_fs_pwd(struct fs_struct *, struct path *);
 extern struct fs_struct *copy_fs_struct(struct fs_struct *);
-extern void put_fs_struct(struct fs_struct *);
+extern void free_fs_struct(struct fs_struct *);
+extern void daemonize_fs_struct(void);
+extern int unshare_fs_struct(void);
 
 #endif /* _LINUX_FS_STRUCT_H */
index 830bbcd449d6c97c9e09a51bce33fabcd163d087..3a059298cc197e9c470c47d6338931557fd6ec43 100644 (file)
@@ -22,6 +22,8 @@ struct proc_mounts {
        int event;
 };
 
+struct fs_struct;
+
 extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_namespace *,
                struct fs_struct *);
 extern void __put_mnt_ns(struct mnt_namespace *ns);
index 5c42821da2d19d7f010071b272e76147056646ab..068a0c9946af7e1f780f8cd287a517a14852286b 100644 (file)
  */
 #ifdef CONFIG_BLOCK
 
-struct mpage_data {
-       struct bio *bio;
-       sector_t last_block_in_bio;
-       get_block_t *get_block;
-       unsigned use_writepage;
-};
-
 struct writeback_control;
 
-struct bio *mpage_bio_submit(int rw, struct bio *bio);
 int mpage_readpages(struct address_space *mapping, struct list_head *pages,
                                unsigned nr_pages, get_block_t get_block);
 int mpage_readpage(struct page *page, get_block_t get_block);
-int __mpage_writepage(struct page *page, struct writeback_control *wbc,
-                     void *data);
 int mpage_writepages(struct address_space *mapping,
                struct writeback_control *wbc, get_block_t get_block);
 int mpage_writepage(struct page *page, get_block_t *get_block,
index afad7dec1b36fd2fee9e967c804f6b3f87a69bf8..7b370c7cfeffb27db00d71fa2127381abdbfd518 100644 (file)
@@ -8,6 +8,7 @@ struct mnt_namespace;
 struct uts_namespace;
 struct ipc_namespace;
 struct pid_namespace;
+struct fs_struct;
 
 /*
  * A structure to contain pointers to all per-process
index 206ac003e8c0ba2b3f492e6e2dd4ec15d53b1b47..9da5aa0771ef906b7e09b6cde69f31ff952a4f07 100644 (file)
@@ -68,7 +68,7 @@ struct sched_param {
 #include <linux/smp.h>
 #include <linux/sem.h>
 #include <linux/signal.h>
-#include <linux/fs_struct.h>
+#include <linux/path.h>
 #include <linux/compiler.h>
 #include <linux/completion.h>
 #include <linux/pid.h>
@@ -97,6 +97,7 @@ struct futex_pi_state;
 struct robust_list_head;
 struct bio;
 struct bts_tracer;
+struct fs_struct;
 
 /*
  * List of flags we want to share for kernel threads,
index 8d4ff5afc1d80b56963cbf119b162a3ebce61124..dd7ee5f203f3f9c476a92d9ef39257a2791b132f 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/fs.h>
 #include <linux/initrd.h>
 #include <linux/async.h>
+#include <linux/fs_struct.h>
 
 #include <linux/nfs_fs.h>
 #include <linux/nfs_fs_sb.h>
index a8ddadbc74594cc6822c706b92f9f429359d0cce..916785363f0f104ac6820fd27dfeaba71bde2727 100644 (file)
@@ -602,7 +602,7 @@ static struct file *do_create(struct dentry *dir, struct dentry *dentry,
                dentry->d_fsdata = attr;
        }
 
-       mode &= ~current->fs->umask;
+       mode &= ~current_umask();
        ret = mnt_want_write(mqueue_mnt);
        if (ret)
                goto out;
index 8cbddff6c283a569acb2b1c707b2448f67771e44..2bfc647867654874df4c36d8009e87c5f6764728 100644 (file)
@@ -66,6 +66,7 @@
 #include <linux/syscalls.h>
 #include <linux/inotify.h>
 #include <linux/capability.h>
+#include <linux/fs_struct.h>
 
 #include "audit.h"
 
index 667c841c2952d6966a08ba9b11e00ad99d06520a..c35452cadded85de8e4505def877b3c5561c991f 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/syscalls.h>
 #include <linux/sysctl.h>
 #include <linux/types.h>
+#include <linux/fs_struct.h>
 
 
 static void default_handler(int, struct pt_regs *);
@@ -145,28 +146,6 @@ __set_personality(u_long personality)
                return 0;
        }
 
-       if (atomic_read(&current->fs->count) != 1) {
-               struct fs_struct *fsp, *ofsp;
-
-               fsp = copy_fs_struct(current->fs);
-               if (fsp == NULL) {
-                       module_put(ep->module);
-                       return -ENOMEM;
-               }
-
-               task_lock(current);
-               ofsp = current->fs;
-               current->fs = fsp;
-               task_unlock(current);
-
-               put_fs_struct(ofsp);
-       }
-
-       /*
-        * At that point we are guaranteed to be the sole owner of
-        * current->fs.
-        */
-
        current->personality = personality;
        oep = current_thread_info()->exec_domain;
        current_thread_info()->exec_domain = ep;
index 3bec141c82f690b0ecb0cf1678c7a964e04c8521..6686ed1e4aa3aedd25a613d3ad7282798392f224 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/blkdev.h>
 #include <linux/task_io_accounting_ops.h>
 #include <linux/tracehook.h>
+#include <linux/fs_struct.h>
 #include <linux/init_task.h>
 #include <trace/sched.h>
 
@@ -420,7 +421,6 @@ EXPORT_SYMBOL(disallow_signal);
 void daemonize(const char *name, ...)
 {
        va_list args;
-       struct fs_struct *fs;
        sigset_t blocked;
 
        va_start(args, name);
@@ -453,11 +453,7 @@ void daemonize(const char *name, ...)
 
        /* Become as one with the init task */
 
-       exit_fs(current);       /* current->fs->count--; */
-       fs = init_task.fs;
-       current->fs = fs;
-       atomic_inc(&fs->count);
-
+       daemonize_fs_struct();
        exit_files(current);
        current->files = init_task.files;
        atomic_inc(&current->files->count);
@@ -556,30 +552,6 @@ void exit_files(struct task_struct *tsk)
        }
 }
 
-void put_fs_struct(struct fs_struct *fs)
-{
-       /* No need to hold fs->lock if we are killing it */
-       if (atomic_dec_and_test(&fs->count)) {
-               path_put(&fs->root);
-               path_put(&fs->pwd);
-               kmem_cache_free(fs_cachep, fs);
-       }
-}
-
-void exit_fs(struct task_struct *tsk)
-{
-       struct fs_struct * fs = tsk->fs;
-
-       if (fs) {
-               task_lock(tsk);
-               tsk->fs = NULL;
-               task_unlock(tsk);
-               put_fs_struct(fs);
-       }
-}
-
-EXPORT_SYMBOL_GPL(exit_fs);
-
 #ifdef CONFIG_MM_OWNER
 /*
  * Task p is exiting and it owned mm, lets find a new owner for it
index f74458231449fb2d63caa8093f4a9b7ae664016a..660c2b8765bce0e112c26460fe037714b6ea3ac5 100644 (file)
@@ -60,6 +60,7 @@
 #include <linux/tty.h>
 #include <linux/proc_fs.h>
 #include <linux/blkdev.h>
+#include <linux/fs_struct.h>
 #include <trace/sched.h>
 #include <linux/magic.h>
 
@@ -681,38 +682,21 @@ fail_nomem:
        return retval;
 }
 
-static struct fs_struct *__copy_fs_struct(struct fs_struct *old)
-{
-       struct fs_struct *fs = kmem_cache_alloc(fs_cachep, GFP_KERNEL);
-       /* We don't need to lock fs - think why ;-) */
-       if (fs) {
-               atomic_set(&fs->count, 1);
-               rwlock_init(&fs->lock);
-               fs->umask = old->umask;
-               read_lock(&old->lock);
-               fs->root = old->root;
-               path_get(&old->root);
-               fs->pwd = old->pwd;
-               path_get(&old->pwd);
-               read_unlock(&old->lock);
-       }
-       return fs;
-}
-
-struct fs_struct *copy_fs_struct(struct fs_struct *old)
-{
-       return __copy_fs_struct(old);
-}
-
-EXPORT_SYMBOL_GPL(copy_fs_struct);
-
 static int copy_fs(unsigned long clone_flags, struct task_struct *tsk)
 {
+       struct fs_struct *fs = current->fs;
        if (clone_flags & CLONE_FS) {
-               atomic_inc(&current->fs->count);
+               /* tsk->fs is already what we want */
+               write_lock(&fs->lock);
+               if (fs->in_exec) {
+                       write_unlock(&fs->lock);
+                       return -EAGAIN;
+               }
+               fs->users++;
+               write_unlock(&fs->lock);
                return 0;
        }
-       tsk->fs = __copy_fs_struct(current->fs);
+       tsk->fs = copy_fs_struct(fs);
        if (!tsk->fs)
                return -ENOMEM;
        return 0;
@@ -1544,12 +1528,16 @@ static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp)
 {
        struct fs_struct *fs = current->fs;
 
-       if ((unshare_flags & CLONE_FS) &&
-           (fs && atomic_read(&fs->count) > 1)) {
-               *new_fsp = __copy_fs_struct(current->fs);
-               if (!*new_fsp)
-                       return -ENOMEM;
-       }
+       if (!(unshare_flags & CLONE_FS) || !fs)
+               return 0;
+
+       /* don't need lock here; in the worst case we'll do useless copy */
+       if (fs->users == 1)
+               return 0;
+
+       *new_fsp = copy_fs_struct(fs);
+       if (!*new_fsp)
+               return -ENOMEM;
 
        return 0;
 }
@@ -1665,8 +1653,13 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags)
 
                if (new_fs) {
                        fs = current->fs;
+                       write_lock(&fs->lock);
                        current->fs = new_fs;
-                       new_fs = fs;
+                       if (--fs->users)
+                               new_fs = NULL;
+                       else
+                               new_fs = fs;
+                       write_unlock(&fs->lock);
                }
 
                if (new_mm) {
@@ -1705,7 +1698,7 @@ bad_unshare_cleanup_sigh:
 
 bad_unshare_cleanup_fs:
        if (new_fs)
-               put_fs_struct(new_fs);
+               free_fs_struct(new_fs);
 
 bad_unshare_cleanup_thread:
 bad_unshare_out:
index 742cefa527e67e1f4b42d55abcb76bbbebadbbfe..51dbb55604e847991023697267d26c9216497ce7 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/seccomp.h>
 #include <linux/cpu.h>
 #include <linux/ptrace.h>
+#include <linux/fs_struct.h>
 
 #include <linux/compat.h>
 #include <linux/syscalls.h>
index baac91049b0ea0efcafb0259ff4146cc2d0e41f6..9dcc6e7f96ec2126039ce6b57768b7274bf5f19e 100644 (file)
@@ -832,7 +832,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
                 * All right, let's create it.
                 */
                mode = S_IFSOCK |
-                      (SOCK_INODE(sock)->i_mode & ~current->fs->umask);
+                      (SOCK_INODE(sock)->i_mode & ~current_umask());
                err = mnt_want_write(nd.path.mnt);
                if (err)
                        goto out_mknod_dput;
index d47f16b844b2300090e02d8f017d2213610f4d33..3bbe01a7a4b5cd9eaa713760bc4a4423d07eb884 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/types.h>
 #include <linux/mount.h>
 #include <linux/mnt_namespace.h>
+#include <linux/fs_struct.h>
 #include "common.h"
 #include "realpath.h"