udf: Refuse RW mount of the filesystem instead of making it RO
[linux-3.10.git] / fs / open.c
index 28fbacb..8c74100 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -30,6 +30,7 @@
 #include <linux/fs_struct.h>
 #include <linux/ima.h>
 #include <linux/dnotify.h>
+#include <linux/compat.h>
 
 #include "internal.h"
 
@@ -61,33 +62,22 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
        return ret;
 }
 
-static long do_sys_truncate(const char __user *pathname, loff_t length)
+long vfs_truncate(struct path *path, loff_t length)
 {
-       struct path path;
        struct inode *inode;
-       int error;
+       long error;
 
-       error = -EINVAL;
-       if (length < 0) /* sorry, but loff_t says... */
-               goto out;
-
-       error = user_path(pathname, &path);
-       if (error)
-               goto out;
-       inode = path.dentry->d_inode;
+       inode = path->dentry->d_inode;
 
        /* For directories it's -EISDIR, for other non-regulars - -EINVAL */
-       error = -EISDIR;
        if (S_ISDIR(inode->i_mode))
-               goto dput_and_out;
-
-       error = -EINVAL;
+               return -EISDIR;
        if (!S_ISREG(inode->i_mode))
-               goto dput_and_out;
+               return -EINVAL;
 
-       error = mnt_want_write(path.mnt);
+       error = mnt_want_write(path->mnt);
        if (error)
-               goto dput_and_out;
+               goto out;
 
        error = inode_permission(inode, MAY_WRITE);
        if (error)
@@ -111,48 +101,76 @@ static long do_sys_truncate(const char __user *pathname, loff_t length)
 
        error = locks_verify_truncate(inode, NULL, length);
        if (!error)
-               error = security_path_truncate(&path);
+               error = security_path_truncate(path);
        if (!error)
-               error = do_truncate(path.dentry, length, 0, NULL);
+               error = do_truncate(path->dentry, length, 0, NULL);
 
 put_write_and_out:
        put_write_access(inode);
 mnt_drop_write_and_out:
-       mnt_drop_write(path.mnt);
-dput_and_out:
-       path_put(&path);
+       mnt_drop_write(path->mnt);
 out:
        return error;
 }
+EXPORT_SYMBOL_GPL(vfs_truncate);
+
+static long do_sys_truncate(const char __user *pathname, loff_t length)
+{
+       unsigned int lookup_flags = LOOKUP_FOLLOW;
+       struct path path;
+       int error;
+
+       if (length < 0) /* sorry, but loff_t says... */
+               return -EINVAL;
+
+retry:
+       error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
+       if (!error) {
+               error = vfs_truncate(&path, length);
+               path_put(&path);
+       }
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
+       return error;
+}
 
 SYSCALL_DEFINE2(truncate, const char __user *, path, long, length)
 {
        return do_sys_truncate(path, length);
 }
 
+#ifdef CONFIG_COMPAT
+COMPAT_SYSCALL_DEFINE2(truncate, const char __user *, path, compat_off_t, length)
+{
+       return do_sys_truncate(path, length);
+}
+#endif
+
 static long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
 {
-       struct inode * inode;
+       struct inode *inode;
        struct dentry *dentry;
-       struct file * file;
+       struct fd f;
        int error;
 
        error = -EINVAL;
        if (length < 0)
                goto out;
        error = -EBADF;
-       file = fget(fd);
-       if (!file)
+       f = fdget(fd);
+       if (!f.file)
                goto out;
 
        /* explicitly opened as large or we are on 64-bit box */
-       if (file->f_flags & O_LARGEFILE)
+       if (f.file->f_flags & O_LARGEFILE)
                small = 0;
 
-       dentry = file->f_path.dentry;
+       dentry = f.file->f_path.dentry;
        inode = dentry->d_inode;
        error = -EINVAL;
-       if (!S_ISREG(inode->i_mode) || !(file->f_mode & FMODE_WRITE))
+       if (!S_ISREG(inode->i_mode) || !(f.file->f_mode & FMODE_WRITE))
                goto out_putf;
 
        error = -EINVAL;
@@ -164,59 +182,48 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
        if (IS_APPEND(inode))
                goto out_putf;
 
-       error = locks_verify_truncate(inode, file, length);
+       sb_start_write(inode->i_sb);
+       error = locks_verify_truncate(inode, f.file, length);
        if (!error)
-               error = security_path_truncate(&file->f_path);
+               error = security_path_truncate(&f.file->f_path);
        if (!error)
-               error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file);
+               error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, f.file);
+       sb_end_write(inode->i_sb);
 out_putf:
-       fput(file);
+       fdput(f);
 out:
        return error;
 }
 
 SYSCALL_DEFINE2(ftruncate, unsigned int, fd, unsigned long, length)
 {
-       long ret = do_sys_ftruncate(fd, length, 1);
-       /* avoid REGPARM breakage on x86: */
-       asmlinkage_protect(2, ret, fd, length);
-       return ret;
+       return do_sys_ftruncate(fd, length, 1);
 }
 
-/* LFS versions of truncate are only needed on 32 bit machines */
-#if BITS_PER_LONG == 32
-SYSCALL_DEFINE(truncate64)(const char __user * path, loff_t length)
+#ifdef CONFIG_COMPAT
+COMPAT_SYSCALL_DEFINE2(ftruncate, unsigned int, fd, compat_ulong_t, length)
 {
-       return do_sys_truncate(path, length);
+       return do_sys_ftruncate(fd, length, 1);
 }
-#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
-asmlinkage long SyS_truncate64(long path, loff_t length)
-{
-       return SYSC_truncate64((const char __user *) path, length);
-}
-SYSCALL_ALIAS(sys_truncate64, SyS_truncate64);
 #endif
 
-SYSCALL_DEFINE(ftruncate64)(unsigned int fd, loff_t length)
+/* LFS versions of truncate are only needed on 32 bit machines */
+#if BITS_PER_LONG == 32
+SYSCALL_DEFINE2(truncate64, const char __user *, path, loff_t, length)
 {
-       long ret = do_sys_ftruncate(fd, length, 0);
-       /* avoid REGPARM breakage on x86: */
-       asmlinkage_protect(2, ret, fd, length);
-       return ret;
+       return do_sys_truncate(path, length);
 }
-#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
-asmlinkage long SyS_ftruncate64(long fd, loff_t length)
+
+SYSCALL_DEFINE2(ftruncate64, unsigned int, fd, loff_t, length)
 {
-       return SYSC_ftruncate64((unsigned int) fd, length);
+       return do_sys_ftruncate(fd, length, 0);
 }
-SYSCALL_ALIAS(sys_ftruncate64, SyS_ftruncate64);
-#endif
 #endif /* BITS_PER_LONG == 32 */
 
 
 int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
 {
-       struct inode *inode = file->f_path.dentry->d_inode;
+       struct inode *inode = file_inode(file);
        long ret;
 
        if (offset < 0 || len <= 0)
@@ -266,31 +273,24 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
        if (!file->f_op->fallocate)
                return -EOPNOTSUPP;
 
-       return file->f_op->fallocate(file, mode, offset, len);
+       sb_start_write(inode->i_sb);
+       ret = file->f_op->fallocate(file, mode, offset, len);
+       sb_end_write(inode->i_sb);
+       return ret;
 }
 
-SYSCALL_DEFINE(fallocate)(int fd, int mode, loff_t offset, loff_t len)
+SYSCALL_DEFINE4(fallocate, int, fd, int, mode, loff_t, offset, loff_t, len)
 {
-       struct file *file;
+       struct fd f = fdget(fd);
        int error = -EBADF;
 
-       file = fget(fd);
-       if (file) {
-               error = do_fallocate(file, mode, offset, len);
-               fput(file);
+       if (f.file) {
+               error = do_fallocate(f.file, mode, offset, len);
+               fdput(f);
        }
-
        return error;
 }
 
-#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
-asmlinkage long SyS_fallocate(long fd, long mode, loff_t offset, loff_t len)
-{
-       return SYSC_fallocate((int)fd, (int)mode, offset, len);
-}
-SYSCALL_ALIAS(sys_fallocate, SyS_fallocate);
-#endif
-
 /*
  * access() needs to use the real uid/gid, not the effective uid/gid.
  * We do this by temporarily clearing all FS-related capabilities and
@@ -303,6 +303,7 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
        struct path path;
        struct inode *inode;
        int res;
+       unsigned int lookup_flags = LOOKUP_FOLLOW;
 
        if (mode & ~S_IRWXO)    /* where's F_OK, X_OK, W_OK, R_OK? */
                return -EINVAL;
@@ -325,8 +326,8 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
        }
 
        old_cred = override_creds(override_cred);
-
-       res = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path);
+retry:
+       res = user_path_at(dfd, filename, lookup_flags, &path);
        if (res)
                goto out;
 
@@ -361,6 +362,10 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
 
 out_path_release:
        path_put(&path);
+       if (retry_estale(res, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
 out:
        revert_creds(old_cred);
        put_cred(override_cred);
@@ -376,8 +381,9 @@ SYSCALL_DEFINE1(chdir, const char __user *, filename)
 {
        struct path path;
        int error;
-
-       error = user_path_dir(filename, &path);
+       unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
+retry:
+       error = user_path_at(AT_FDCWD, filename, lookup_flags, &path);
        if (error)
                goto out;
 
@@ -389,22 +395,25 @@ SYSCALL_DEFINE1(chdir, const char __user *, filename)
 
 dput_and_out:
        path_put(&path);
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
 out:
        return error;
 }
 
 SYSCALL_DEFINE1(fchdir, unsigned int, fd)
 {
-       struct file *file;
+       struct fd f = fdget_raw(fd);
        struct inode *inode;
-       int error, fput_needed;
+       int error = -EBADF;
 
        error = -EBADF;
-       file = fget_raw_light(fd, &fput_needed);
-       if (!file)
+       if (!f.file)
                goto out;
 
-       inode = file->f_path.dentry->d_inode;
+       inode = file_inode(f.file);
 
        error = -ENOTDIR;
        if (!S_ISDIR(inode->i_mode))
@@ -412,9 +421,9 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd)
 
        error = inode_permission(inode, MAY_EXEC | MAY_CHDIR);
        if (!error)
-               set_fs_pwd(current->fs, &file->f_path);
+               set_fs_pwd(current->fs, &f.file->f_path);
 out_putf:
-       fput_light(file, fput_needed);
+       fdput(f);
 out:
        return error;
 }
@@ -423,8 +432,9 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename)
 {
        struct path path;
        int error;
-
-       error = user_path_dir(filename, &path);
+       unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
+retry:
+       error = user_path_at(AT_FDCWD, filename, lookup_flags, &path);
        if (error)
                goto out;
 
@@ -433,7 +443,7 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename)
                goto dput_and_out;
 
        error = -EPERM;
-       if (!capable(CAP_SYS_CHROOT))
+       if (!nsown_capable(CAP_SYS_CHROOT))
                goto dput_and_out;
        error = security_path_chroot(&path);
        if (error)
@@ -443,6 +453,10 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename)
        error = 0;
 dput_and_out:
        path_put(&path);
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
 out:
        return error;
 }
@@ -476,7 +490,7 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd, umode_t, mode)
 
        file = fget(fd);
        if (file) {
-               audit_inode(NULL, file->f_path.dentry);
+               audit_inode(NULL, file->f_path.dentry, 0);
                err = chmod_common(&file->f_path, mode);
                fput(file);
        }
@@ -487,11 +501,16 @@ SYSCALL_DEFINE3(fchmodat, int, dfd, const char __user *, filename, umode_t, mode
 {
        struct path path;
        int error;
-
-       error = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path);
+       unsigned int lookup_flags = LOOKUP_FOLLOW;
+retry:
+       error = user_path_at(dfd, filename, lookup_flags, &path);
        if (!error) {
                error = chmod_common(&path, mode);
                path_put(&path);
+               if (retry_estale(error, lookup_flags)) {
+                       lookup_flags |= LOOKUP_REVAL;
+                       goto retry;
+               }
        }
        return error;
 }
@@ -529,7 +548,7 @@ static int chown_common(struct path *path, uid_t user, gid_t group)
                newattrs.ia_valid |=
                        ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV;
        mutex_lock(&inode->i_mutex);
-       error = security_path_chown(path, user, group);
+       error = security_path_chown(path, uid, gid);
        if (!error)
                error = notify_change(path->dentry, &newattrs);
        mutex_unlock(&inode->i_mutex);
@@ -537,25 +556,6 @@ static int chown_common(struct path *path, uid_t user, gid_t group)
        return error;
 }
 
-SYSCALL_DEFINE3(chown, const char __user *, filename, uid_t, user, gid_t, group)
-{
-       struct path path;
-       int error;
-
-       error = user_path(filename, &path);
-       if (error)
-               goto out;
-       error = mnt_want_write(path.mnt);
-       if (error)
-               goto out_release;
-       error = chown_common(&path, user, group);
-       mnt_drop_write(path.mnt);
-out_release:
-       path_put(&path);
-out:
-       return error;
-}
-
 SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user,
                gid_t, group, int, flag)
 {
@@ -569,6 +569,7 @@ SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user,
        lookup_flags = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
        if (flag & AT_EMPTY_PATH)
                lookup_flags |= LOOKUP_EMPTY;
+retry:
        error = user_path_at(dfd, filename, lookup_flags, &path);
        if (error)
                goto out;
@@ -579,48 +580,41 @@ SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user,
        mnt_drop_write(path.mnt);
 out_release:
        path_put(&path);
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
 out:
        return error;
 }
 
-SYSCALL_DEFINE3(lchown, const char __user *, filename, uid_t, user, gid_t, group)
+SYSCALL_DEFINE3(chown, const char __user *, filename, uid_t, user, gid_t, group)
 {
-       struct path path;
-       int error;
+       return sys_fchownat(AT_FDCWD, filename, user, group, 0);
+}
 
-       error = user_lpath(filename, &path);
-       if (error)
-               goto out;
-       error = mnt_want_write(path.mnt);
-       if (error)
-               goto out_release;
-       error = chown_common(&path, user, group);
-       mnt_drop_write(path.mnt);
-out_release:
-       path_put(&path);
-out:
-       return error;
+SYSCALL_DEFINE3(lchown, const char __user *, filename, uid_t, user, gid_t, group)
+{
+       return sys_fchownat(AT_FDCWD, filename, user, group,
+                           AT_SYMLINK_NOFOLLOW);
 }
 
 SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group)
 {
-       struct file * file;
+       struct fd f = fdget(fd);
        int error = -EBADF;
-       struct dentry * dentry;
 
-       file = fget(fd);
-       if (!file)
+       if (!f.file)
                goto out;
 
-       error = mnt_want_write_file(file);
+       error = mnt_want_write_file(f.file);
        if (error)
                goto out_fput;
-       dentry = file->f_path.dentry;
-       audit_inode(NULL, dentry);
-       error = chown_common(&file->f_path, user, group);
-       mnt_drop_write_file(file);
+       audit_inode(NULL, f.file->f_path.dentry, 0);
+       error = chown_common(&f.file->f_path, user, group);
+       mnt_drop_write_file(f.file);
 out_fput:
-       fput(file);
+       fdput(f);
 out:
        return error;
 }
@@ -647,7 +641,7 @@ static inline int __get_file_write_access(struct inode *inode,
                /*
                 * Balanced in __fput()
                 */
-               error = mnt_want_write(mnt);
+               error = __mnt_want_write(mnt);
                if (error)
                        put_write_access(inode);
        }
@@ -667,8 +661,7 @@ int open_check_o_direct(struct file *f)
        return 0;
 }
 
-static int do_dentry_open(struct dentry *dentry, struct vfsmount *mnt,
-                         struct file *f,
+static int do_dentry_open(struct file *f,
                          int (*open)(struct inode *, struct file *),
                          const struct cred *cred)
 {
@@ -682,9 +675,10 @@ static int do_dentry_open(struct dentry *dentry, struct vfsmount *mnt,
        if (unlikely(f->f_flags & O_PATH))
                f->f_mode = FMODE_PATH;
 
-       inode = dentry->d_inode;
+       path_get(&f->f_path);
+       inode = f->f_inode = f->f_path.dentry->d_inode;
        if (f->f_mode & FMODE_WRITE) {
-               error = __get_file_write_access(inode, mnt);
+               error = __get_file_write_access(inode, f->f_path.mnt);
                if (error)
                        goto cleanup_file;
                if (!special_file(inode->i_mode))
@@ -692,9 +686,6 @@ static int do_dentry_open(struct dentry *dentry, struct vfsmount *mnt,
        }
 
        f->f_mapping = inode->i_mapping;
-       f->f_path.dentry = dentry;
-       f->f_path.mnt = mnt;
-       f->f_pos = 0;
        file_sb_list_add(f, inode->i_sb);
 
        if (unlikely(f->f_mode & FMODE_PATH)) {
@@ -730,6 +721,7 @@ static int do_dentry_open(struct dentry *dentry, struct vfsmount *mnt,
 
 cleanup_all:
        fops_put(f->f_op);
+       file_sb_list_del(f);
        if (f->f_mode & FMODE_WRITE) {
                put_write_access(inode);
                if (!special_file(inode->i_mode)) {
@@ -740,15 +732,14 @@ cleanup_all:
                         * here, so just reset the state.
                         */
                        file_reset_write(f);
-                       mnt_drop_write(mnt);
+                       __mnt_drop_write(f->f_path.mnt);
                }
        }
-       file_sb_list_del(f);
-       f->f_path.dentry = NULL;
-       f->f_path.mnt = NULL;
 cleanup_file:
-       dput(dentry);
-       mntput(mnt);
+       path_put(&f->f_path);
+       f->f_path.mnt = NULL;
+       f->f_path.dentry = NULL;
+       f->f_inode = NULL;
        return error;
 }
 
@@ -770,10 +761,8 @@ int finish_open(struct file *file, struct dentry *dentry,
        int error;
        BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */
 
-       mntget(file->f_path.mnt);
-       dget(dentry);
-
-       error = do_dentry_open(dentry, file->f_path.mnt, file, open, current_cred());
+       file->f_path.dentry = dentry;
+       error = do_dentry_open(file, open, current_cred());
        if (!error)
                *opened |= FILE_OPENED;
 
@@ -797,11 +786,7 @@ int finish_no_open(struct file *file, struct dentry *dentry)
 }
 EXPORT_SYMBOL(finish_no_open);
 
-/*
- * dentry_open() will have done dput(dentry) and mntput(mnt) if it returns an
- * error.
- */
-struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags,
+struct file *dentry_open(const struct path *path, int flags,
                         const struct cred *cred)
 {
        int error;
@@ -810,87 +795,41 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags,
        validate_creds(cred);
 
        /* We must always pass in a valid mount pointer. */
-       BUG_ON(!mnt);
+       BUG_ON(!path->mnt);
 
-       error = -ENFILE;
        f = get_empty_filp();
-       if (f == NULL) {
-               dput(dentry);
-               mntput(mnt);
-               return ERR_PTR(error);
-       }
-
-       f->f_flags = flags;
-       error = do_dentry_open(dentry, mnt, f, NULL, cred);
-       if (!error) {
-               error = open_check_o_direct(f);
-               if (error) {
-                       fput(f);
+       if (!IS_ERR(f)) {
+               f->f_flags = flags;
+               f->f_path = *path;
+               error = do_dentry_open(f, NULL, cred);
+               if (!error) {
+                       /* from now on we need fput() to dispose of f */
+                       error = open_check_o_direct(f);
+                       if (error) {
+                               fput(f);
+                               f = ERR_PTR(error);
+                       }
+               } else { 
+                       put_filp(f);
                        f = ERR_PTR(error);
                }
-       } else { 
-               put_filp(f);
-               f = ERR_PTR(error);
        }
        return f;
 }
 EXPORT_SYMBOL(dentry_open);
 
-static void __put_unused_fd(struct files_struct *files, unsigned int fd)
-{
-       struct fdtable *fdt = files_fdtable(files);
-       __clear_open_fd(fd, fdt);
-       if (fd < files->next_fd)
-               files->next_fd = fd;
-}
-
-void put_unused_fd(unsigned int fd)
-{
-       struct files_struct *files = current->files;
-       spin_lock(&files->file_lock);
-       __put_unused_fd(files, fd);
-       spin_unlock(&files->file_lock);
-}
-
-EXPORT_SYMBOL(put_unused_fd);
-
-/*
- * Install a file pointer in the fd array.
- *
- * The VFS is full of places where we drop the files lock between
- * setting the open_fds bitmap and installing the file in the file
- * array.  At any such point, we are vulnerable to a dup2() race
- * installing a file in the array before us.  We need to detect this and
- * fput() the struct file we are about to overwrite in this case.
- *
- * It should never happen - if we allow dup2() do it, _really_ bad things
- * will follow.
- */
-
-void fd_install(unsigned int fd, struct file *file)
-{
-       struct files_struct *files = current->files;
-       struct fdtable *fdt;
-       spin_lock(&files->file_lock);
-       fdt = files_fdtable(files);
-       BUG_ON(fdt->fd[fd] != NULL);
-       rcu_assign_pointer(fdt->fd[fd], file);
-       spin_unlock(&files->file_lock);
-}
-
-EXPORT_SYMBOL(fd_install);
-
 static inline int build_open_flags(int flags, umode_t mode, struct open_flags *op)
 {
        int lookup_flags = 0;
        int acc_mode;
 
-       if (!(flags & O_CREAT))
-               mode = 0;
-       op->mode = mode;
+       if (flags & O_CREAT)
+               op->mode = (mode & S_IALLUGO) | S_IFREG;
+       else
+               op->mode = 0;
 
        /* Must never be set by userspace */
-       flags &= ~FMODE_NONOTIFY;
+       flags &= ~FMODE_NONOTIFY & ~O_CLOEXEC;
 
        /*
         * O_SYNC is implemented as __O_SYNC|O_DSYNC.  As many places only
@@ -941,6 +880,24 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o
 }
 
 /**
+ * file_open_name - open file and return file pointer
+ *
+ * @name:      struct filename containing path to open
+ * @flags:     open flags as per the open(2) second argument
+ * @mode:      mode for the new file if O_CREAT is set, else ignored
+ *
+ * This is the helper to open a file from kernelspace if you really
+ * have to.  But in generally you should not do this, so please move
+ * along, nothing to see here..
+ */
+struct file *file_open_name(struct filename *name, int flags, umode_t mode)
+{
+       struct open_flags op;
+       int lookup = build_open_flags(flags, mode, &op);
+       return do_filp_open(AT_FDCWD, name, &op, lookup);
+}
+
+/**
  * filp_open - open file and return file pointer
  *
  * @filename:  path to open
@@ -953,9 +910,8 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o
  */
 struct file *filp_open(const char *filename, int flags, umode_t mode)
 {
-       struct open_flags op;
-       int lookup = build_open_flags(flags, mode, &op);
-       return do_filp_open(AT_FDCWD, filename, &op, lookup);
+       struct filename name = {.name = filename};
+       return file_open_name(&name, flags, mode);
 }
 EXPORT_SYMBOL(filp_open);
 
@@ -977,7 +933,7 @@ long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
 {
        struct open_flags op;
        int lookup = build_open_flags(flags, mode, &op);
-       char *tmp = getname(filename);
+       struct filename *tmp = getname(filename);
        int fd = PTR_ERR(tmp);
 
        if (!IS_ERR(tmp)) {
@@ -999,29 +955,19 @@ long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
 
 SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
 {
-       long ret;
-
        if (force_o_largefile())
                flags |= O_LARGEFILE;
 
-       ret = do_sys_open(AT_FDCWD, filename, flags, mode);
-       /* avoid REGPARM breakage on x86: */
-       asmlinkage_protect(3, ret, filename, flags, mode);
-       return ret;
+       return do_sys_open(AT_FDCWD, filename, flags, mode);
 }
 
 SYSCALL_DEFINE4(openat, int, dfd, const char __user *, filename, int, flags,
                umode_t, mode)
 {
-       long ret;
-
        if (force_o_largefile())
                flags |= O_LARGEFILE;
 
-       ret = do_sys_open(dfd, filename, flags, mode);
-       /* avoid REGPARM breakage on x86: */
-       asmlinkage_protect(4, ret, dfd, filename, flags, mode);
-       return ret;
+       return do_sys_open(dfd, filename, flags, mode);
 }
 
 #ifndef __alpha__
@@ -1070,23 +1016,7 @@ EXPORT_SYMBOL(filp_close);
  */
 SYSCALL_DEFINE1(close, unsigned int, fd)
 {
-       struct file * filp;
-       struct files_struct *files = current->files;
-       struct fdtable *fdt;
-       int retval;
-
-       spin_lock(&files->file_lock);
-       fdt = files_fdtable(files);
-       if (fd >= fdt->max_fds)
-               goto out_unlock;
-       filp = fdt->fd[fd];
-       if (!filp)
-               goto out_unlock;
-       rcu_assign_pointer(fdt->fd[fd], NULL);
-       __clear_close_on_exec(fd, fdt);
-       __put_unused_fd(files, fd);
-       spin_unlock(&files->file_lock);
-       retval = filp_close(filp, files);
+       int retval = __close_fd(current->files, fd);
 
        /* can't restart close syscall because file table entry was cleared */
        if (unlikely(retval == -ERESTARTSYS ||
@@ -1096,10 +1026,6 @@ SYSCALL_DEFINE1(close, unsigned int, fd)
                retval = -EINTR;
 
        return retval;
-
-out_unlock:
-       spin_unlock(&files->file_lock);
-       return -EBADF;
 }
 EXPORT_SYMBOL(sys_close);