return ovl_real_fileattr_set(new, &newfa);
 }
 
-static int ovl_copy_up_data(struct ovl_fs *ofs, struct path *old,
-                           struct path *new, loff_t len)
+static int ovl_copy_up_file(struct ovl_fs *ofs, struct dentry *dentry,
+                           struct file *new_file, loff_t len)
 {
+       struct path datapath;
        struct file *old_file;
-       struct file *new_file;
        loff_t old_pos = 0;
        loff_t new_pos = 0;
        loff_t cloned;
        bool skip_hole = false;
        int error = 0;
 
-       if (len == 0)
-               return 0;
+       ovl_path_lowerdata(dentry, &datapath);
+       if (WARN_ON(datapath.dentry == NULL))
+               return -EIO;
 
-       old_file = ovl_path_open(old, O_LARGEFILE | O_RDONLY);
+       old_file = ovl_path_open(&datapath, O_LARGEFILE | O_RDONLY);
        if (IS_ERR(old_file))
                return PTR_ERR(old_file);
 
-       new_file = ovl_path_open(new, O_LARGEFILE | O_WRONLY);
-       if (IS_ERR(new_file)) {
-               error = PTR_ERR(new_file);
-               goto out_fput;
-       }
-
        /* Try to use clone_file_range to clone up within the same fs */
        cloned = do_clone_file_range(old_file, 0, new_file, 0, len, 0);
        if (cloned == len)
-               goto out;
+               goto out_fput;
        /* Couldn't clone, so now we try to copy the data */
 
        /* Check if lower fs supports seek operation */
 
                len -= bytes;
        }
-out:
        if (!error && ovl_should_sync(ofs))
                error = vfs_fsync(new_file, 0);
-       fput(new_file);
 out_fput:
        fput(old_file);
        return error;
        return err;
 }
 
-static int ovl_copy_up_inode(struct ovl_copy_up_ctx *c, struct dentry *temp)
+static int ovl_copy_up_data(struct ovl_copy_up_ctx *c, const struct path *temp)
 {
        struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb);
-       struct inode *inode = d_inode(c->dentry);
-       struct path upperpath, datapath;
+       struct file *new_file;
        int err;
 
-       ovl_path_upper(c->dentry, &upperpath);
-       if (WARN_ON(upperpath.dentry != NULL))
-               return -EIO;
+       if (!S_ISREG(c->stat.mode) || c->metacopy || !c->stat.size)
+               return 0;
 
-       upperpath.dentry = temp;
+       new_file = ovl_path_open(temp, O_LARGEFILE | O_WRONLY);
+       if (IS_ERR(new_file))
+               return PTR_ERR(new_file);
 
-       /*
-        * Copy up data first and then xattrs. Writing data after
-        * xattrs will remove security.capability xattr automatically.
-        */
-       if (S_ISREG(c->stat.mode) && !c->metacopy) {
-               ovl_path_lowerdata(c->dentry, &datapath);
-               err = ovl_copy_up_data(ofs, &datapath, &upperpath,
-                                      c->stat.size);
-               if (err)
-                       return err;
-       }
+       err = ovl_copy_up_file(ofs, c->dentry, new_file, c->stat.size);
+       fput(new_file);
+
+       return err;
+}
+
+static int ovl_copy_up_metadata(struct ovl_copy_up_ctx *c, struct dentry *temp)
+{
+       struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb);
+       struct inode *inode = d_inode(c->dentry);
+       struct path upperpath = { .mnt = ovl_upper_mnt(ofs), .dentry = temp };
+       int err;
 
        err = ovl_copy_xattr(c->dentry->d_sb, &c->lowerpath, temp);
        if (err)
        struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb);
        struct inode *inode;
        struct inode *udir = d_inode(c->destdir), *wdir = d_inode(c->workdir);
+       struct path path = { .mnt = ovl_upper_mnt(ofs) };
        struct dentry *temp, *upper;
        struct ovl_cu_creds cc;
        int err;
        if (IS_ERR(temp))
                goto unlock;
 
-       err = ovl_copy_up_inode(c, temp);
+       /*
+        * Copy up data first and then xattrs. Writing data after
+        * xattrs will remove security.capability xattr automatically.
+        */
+       path.dentry = temp;
+       err = ovl_copy_up_data(c, &path);
+       if (err)
+               goto cleanup;
+
+       err = ovl_copy_up_metadata(c, temp);
        if (err)
                goto cleanup;
 
        struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb);
        struct inode *udir = d_inode(c->destdir);
        struct dentry *temp, *upper;
+       struct file *tmpfile;
        struct ovl_cu_creds cc;
        int err;
 
        if (err)
                return err;
 
-       temp = ovl_do_tmpfile(ofs, c->workdir, c->stat.mode);
+       tmpfile = ovl_do_tmpfile(ofs, c->workdir, c->stat.mode);
        ovl_revert_cu_creds(&cc);
 
-       if (IS_ERR(temp))
-               return PTR_ERR(temp);
+       if (IS_ERR(tmpfile))
+               return PTR_ERR(tmpfile);
 
-       err = ovl_copy_up_inode(c, temp);
+       temp = tmpfile->f_path.dentry;
+       if (!c->metacopy && c->stat.size) {
+               err = ovl_copy_up_file(ofs, c->dentry, tmpfile, c->stat.size);
+               if (err)
+                       return err;
+       }
+
+       err = ovl_copy_up_metadata(c, temp);
        if (err)
-               goto out_dput;
+               goto out_fput;
 
        inode_lock_nested(udir, I_MUTEX_PARENT);
 
        inode_unlock(udir);
 
        if (err)
-               goto out_dput;
+               goto out_fput;
 
        if (!c->metacopy)
                ovl_set_upperdata(d_inode(c->dentry));
-       ovl_inode_update(d_inode(c->dentry), temp);
+       ovl_inode_update(d_inode(c->dentry), dget(temp));
 
-       return 0;
-
-out_dput:
-       dput(temp);
+out_fput:
+       fput(tmpfile);
        return err;
 }
 
 static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c)
 {
        struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb);
-       struct path upperpath, datapath;
+       struct path upperpath;
        int err;
        char *capability = NULL;
        ssize_t cap_size;
        if (WARN_ON(upperpath.dentry == NULL))
                return -EIO;
 
-       ovl_path_lowerdata(c->dentry, &datapath);
-       if (WARN_ON(datapath.dentry == NULL))
-               return -EIO;
-
        if (c->stat.size) {
                err = cap_size = ovl_getxattr_value(&upperpath, XATTR_NAME_CAPS,
                                                    &capability);
                        goto out;
        }
 
-       err = ovl_copy_up_data(ofs, &datapath, &upperpath, c->stat.size);
+       err = ovl_copy_up_data(c, &upperpath);
        if (err)
                goto out_free;
 
 
        return err;
 }
 
-static inline struct dentry *ovl_do_tmpfile(struct ovl_fs *ofs,
-                                           struct dentry *dentry, umode_t mode)
+static inline struct file *ovl_do_tmpfile(struct ovl_fs *ofs,
+                                         struct dentry *dentry, umode_t mode)
 {
-       struct dentry *ret = vfs_tmpfile(ovl_upper_mnt_userns(ofs), dentry, mode, 0);
-       int err = PTR_ERR_OR_ZERO(ret);
+       struct path path = { .mnt = ovl_upper_mnt(ofs), .dentry = dentry };
+       struct file *file = vfs_tmpfile_open(ovl_upper_mnt_userns(ofs), &path, mode,
+                                       O_LARGEFILE | O_WRONLY, current_cred());
+       int err = PTR_ERR_OR_ZERO(file);
 
        pr_debug("tmpfile(%pd2, 0%o) = %i\n", dentry, mode, err);
-       return ret;
+       return file;
 }
 
 static inline struct dentry *ovl_lookup_upper(struct ovl_fs *ofs,
 void ovl_dir_modified(struct dentry *dentry, bool impurity);
 u64 ovl_dentry_version_get(struct dentry *dentry);
 bool ovl_is_whiteout(struct dentry *dentry);
-struct file *ovl_path_open(struct path *path, int flags);
+struct file *ovl_path_open(const struct path *path, int flags);
 int ovl_copy_up_start(struct dentry *dentry, int flags);
 void ovl_copy_up_end(struct dentry *dentry);
 bool ovl_already_copied_up(struct dentry *dentry, int flags);