Merge tag 'libnvdimm-for-5.1' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm...
[linux-2.6-block.git] / fs / open.c
index d0e955b558ad84ce2d6f98f6ccb490185bc36cc2..0285ce7dbd515c8c7bfd9e63f0211cabfb818801 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -68,7 +68,6 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
 long vfs_truncate(const struct path *path, loff_t length)
 {
        struct inode *inode;
-       struct dentry *upperdentry;
        long error;
 
        inode = path->dentry->d_inode;
@@ -91,17 +90,7 @@ long vfs_truncate(const struct path *path, loff_t length)
        if (IS_APPEND(inode))
                goto mnt_drop_write_and_out;
 
-       /*
-        * If this is an overlayfs then do as if opening the file so we get
-        * write access on the upper inode, not on the overlay inode.  For
-        * non-overlay filesystems d_real() is an identity function.
-        */
-       upperdentry = d_real(path->dentry, NULL, O_WRONLY, 0);
-       error = PTR_ERR(upperdentry);
-       if (IS_ERR(upperdentry))
-               goto mnt_drop_write_and_out;
-
-       error = get_write_access(upperdentry->d_inode);
+       error = get_write_access(inode);
        if (error)
                goto mnt_drop_write_and_out;
 
@@ -120,7 +109,7 @@ long vfs_truncate(const struct path *path, loff_t length)
                error = do_truncate(path->dentry, length, 0, NULL);
 
 put_write_and_out:
-       put_write_access(upperdentry->d_inode);
+       put_write_access(inode);
 mnt_drop_write_and_out:
        mnt_drop_write(path->mnt);
 out:
@@ -707,12 +696,12 @@ int ksys_fchown(unsigned int fd, uid_t user, gid_t group)
        if (!f.file)
                goto out;
 
-       error = mnt_want_write_file_path(f.file);
+       error = mnt_want_write_file(f.file);
        if (error)
                goto out_fput;
        audit_file(f.file);
        error = chown_common(&f.file->f_path, user, group);
-       mnt_drop_write_file_path(f.file);
+       mnt_drop_write_file(f.file);
 out_fput:
        fdput(f);
 out:
@@ -724,27 +713,13 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group)
        return ksys_fchown(fd, user, group);
 }
 
-int open_check_o_direct(struct file *f)
-{
-       /* NB: we're sure to have correct a_ops only after f_op->open */
-       if (f->f_flags & O_DIRECT) {
-               if (!f->f_mapping->a_ops || !f->f_mapping->a_ops->direct_IO)
-                       return -EINVAL;
-       }
-       return 0;
-}
-
 static int do_dentry_open(struct file *f,
                          struct inode *inode,
-                         int (*open)(struct inode *, struct file *),
-                         const struct cred *cred)
+                         int (*open)(struct inode *, struct file *))
 {
        static const struct file_operations empty_fops = {};
        int error;
 
-       f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK |
-                               FMODE_PREAD | FMODE_PWRITE;
-
        path_get(&f->f_path);
        f->f_inode = inode;
        f->f_mapping = inode->i_mapping;
@@ -753,7 +728,7 @@ static int do_dentry_open(struct file *f,
        f->f_wb_err = filemap_sample_wb_err(f->f_mapping);
 
        if (unlikely(f->f_flags & O_PATH)) {
-               f->f_mode = FMODE_PATH;
+               f->f_mode = FMODE_PATH | FMODE_OPENED;
                f->f_op = &empty_fops;
                return 0;
        }
@@ -780,7 +755,7 @@ static int do_dentry_open(struct file *f,
                goto cleanup_all;
        }
 
-       error = security_file_open(f, cred);
+       error = security_file_open(f);
        if (error)
                goto cleanup_all;
 
@@ -788,6 +763,8 @@ static int do_dentry_open(struct file *f,
        if (error)
                goto cleanup_all;
 
+       /* normally all 3 are set; ->open() can clear them if needed */
+       f->f_mode |= FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE;
        if (!open)
                open = f->f_op->open;
        if (open) {
@@ -795,6 +772,7 @@ static int do_dentry_open(struct file *f,
                if (error)
                        goto cleanup_all;
        }
+       f->f_mode |= FMODE_OPENED;
        if ((f->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
                i_readcount_inc(inode);
        if ((f->f_mode & FMODE_READ) &&
@@ -809,9 +787,16 @@ static int do_dentry_open(struct file *f,
 
        file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping);
 
+       /* NB: we're sure to have correct a_ops only after f_op->open */
+       if (f->f_flags & O_DIRECT) {
+               if (!f->f_mapping->a_ops || !f->f_mapping->a_ops->direct_IO)
+                       return -EINVAL;
+       }
        return 0;
 
 cleanup_all:
+       if (WARN_ON_ONCE(error > 0))
+               error = -EINVAL;
        fops_put(f->f_op);
        if (f->f_mode & FMODE_WRITER) {
                put_write_access(inode);
@@ -847,19 +832,12 @@ cleanup_file:
  * Returns zero on success or -errno if the open failed.
  */
 int finish_open(struct file *file, struct dentry *dentry,
-               int (*open)(struct inode *, struct file *),
-               int *opened)
+               int (*open)(struct inode *, struct file *))
 {
-       int error;
-       BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */
+       BUG_ON(file->f_mode & FMODE_OPENED); /* once it's opened, it's opened */
 
        file->f_path.dentry = dentry;
-       error = do_dentry_open(file, d_backing_inode(dentry), open,
-                              current_cred());
-       if (!error)
-               *opened |= FILE_OPENED;
-
-       return error;
+       return do_dentry_open(file, d_backing_inode(dentry), open);
 }
 EXPORT_SYMBOL(finish_open);
 
@@ -874,13 +852,13 @@ EXPORT_SYMBOL(finish_open);
  * NB: unlike finish_open() this function does consume the dentry reference and
  * the caller need not dput() it.
  *
- * Returns "1" which must be the return value of ->atomic_open() after having
+ * Returns "0" which must be the return value of ->atomic_open() after having
  * called this function.
  */
 int finish_no_open(struct file *file, struct dentry *dentry)
 {
        file->f_path.dentry = dentry;
-       return 1;
+       return 0;
 }
 EXPORT_SYMBOL(finish_no_open);
 
@@ -896,16 +874,10 @@ EXPORT_SYMBOL(file_path);
  * @file: newly allocated file with f_flag initialized
  * @cred: credentials to use
  */
-int vfs_open(const struct path *path, struct file *file,
-            const struct cred *cred)
+int vfs_open(const struct path *path, struct file *file)
 {
-       struct dentry *dentry = d_real(path->dentry, NULL, file->f_flags, 0);
-
-       if (IS_ERR(dentry))
-               return PTR_ERR(dentry);
-
        file->f_path = *path;
-       return do_dentry_open(file, d_backing_inode(dentry), NULL, cred);
+       return do_dentry_open(file, d_backing_inode(path->dentry), NULL);
 }
 
 struct file *dentry_open(const struct path *path, int flags,
@@ -919,19 +891,11 @@ struct file *dentry_open(const struct path *path, int flags,
        /* We must always pass in a valid mount pointer. */
        BUG_ON(!path->mnt);
 
-       f = get_empty_filp();
+       f = alloc_empty_file(flags, cred);
        if (!IS_ERR(f)) {
-               f->f_flags = flags;
-               error = vfs_open(path, f, 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);
+               error = vfs_open(path, f);
+               if (error) {
+                       fput(f);
                        f = ERR_PTR(error);
                }
        }
@@ -939,6 +903,24 @@ struct file *dentry_open(const struct path *path, int flags,
 }
 EXPORT_SYMBOL(dentry_open);
 
+struct file *open_with_fake_path(const struct path *path, int flags,
+                               struct inode *inode, const struct cred *cred)
+{
+       struct file *f = alloc_empty_file_noaccount(flags, cred);
+       if (!IS_ERR(f)) {
+               int error;
+
+               f->f_path = *path;
+               error = do_dentry_open(f, inode, NULL);
+               if (error) {
+                       fput(f);
+                       f = ERR_PTR(error);
+               }
+       }
+       return f;
+}
+EXPORT_SYMBOL(open_with_fake_path);
+
 static inline int build_open_flags(int flags, umode_t mode, struct open_flags *op)
 {
        int lookup_flags = 0;
@@ -1063,26 +1045,6 @@ struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt,
 }
 EXPORT_SYMBOL(file_open_root);
 
-struct file *filp_clone_open(struct file *oldfile)
-{
-       struct file *file;
-       int retval;
-
-       file = get_empty_filp();
-       if (IS_ERR(file))
-               return file;
-
-       file->f_flags = oldfile->f_flags;
-       retval = vfs_open(&oldfile->f_path, file, oldfile->f_cred);
-       if (retval) {
-               put_filp(file);
-               return ERR_PTR(retval);
-       }
-
-       return file;
-}
-EXPORT_SYMBOL(filp_clone_open);
-
 long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
 {
        struct open_flags op;