@@ -138,8 +138,7 @@ static int ovl_copy_up_data(struct path *old, struct path *new, loff_t len)
{
struct file *old_file;
struct file *new_file;
- loff_t old_pos = 0;
- loff_t new_pos = 0;
+ loff_t pos = 0;
int error = 0;
if (len == 0)
@@ -155,38 +154,27 @@ static int ovl_copy_up_data(struct path *old, struct path *new, loff_t len)
goto out_fput;
}
- /* Try to use clone_file_range to clone up within the same fs */
- error = vfs_clone_file_range(old_file, 0, new_file, 0, len);
- if (!error)
- goto out;
- /* Couldn't clone, so now we try to copy the data */
- error = 0;
-
- /* FIXME: copy up sparse files efficiently */
- while (len) {
+ while (pos < len) {
size_t this_len = OVL_COPY_UP_CHUNK_SIZE;
long bytes;
- if (len < this_len)
- this_len = len;
+ if (len - pos < this_len)
+ this_len = len - pos;
if (signal_pending_state(TASK_KILLABLE, current)) {
error = -EINTR;
break;
}
- bytes = do_splice_direct(old_file, &old_pos,
- new_file, &new_pos,
- this_len, SPLICE_F_MOVE);
+ bytes = do_copy_file_range(old_file, pos,
+ new_file, pos,
+ this_len, 0, SPLICE_F_MOVE);
if (bytes <= 0) {
error = bytes;
break;
}
- WARN_ON(old_pos != new_pos);
-
- len -= bytes;
+ pos += bytes;
}
-out:
if (!error)
error = vfs_fsync(new_file, 0);
fput(new_file);
@@ -1542,9 +1542,10 @@ COMPAT_SYSCALL_DEFINE4(sendfile64, int, out_fd, int, in_fd,
}
#endif
-static ssize_t do_copy_file_range(struct file *file_in, loff_t pos_in,
+ssize_t do_copy_file_range(struct file *file_in, loff_t pos_in,
struct file *file_out, loff_t pos_out,
- size_t len, unsigned int flags)
+ size_t len, unsigned int flags,
+ unsigned int splice_flags)
{
struct inode *inode_in = file_inode(file_in);
struct inode *inode_out = file_inode(file_out);
@@ -1629,6 +1630,7 @@ static ssize_t do_copy_file_range(struct file *file_in, loff_t pos_in,
out:
return total ? total : ret;
}
+EXPORT_SYMBOL(do_copy_file_range);
/*
* copy_file_range() differs from regular file read and write in that it
@@ -1667,7 +1669,7 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
file_start_write(file_out);
ret = do_copy_file_range(file_in, pos_in,
- file_out, pos_out, len, flags);
+ file_out, pos_out, len, flags, 0);
if (ret > 0) {
fsnotify_access(file_in);
@@ -1799,6 +1799,9 @@ extern ssize_t vfs_read(struct file *, char __user *, size_t, loff_t *);
extern ssize_t vfs_write(struct file *, const char __user *, size_t, loff_t *);
extern ssize_t vfs_readv(struct file *, const struct iovec __user *,
unsigned long, loff_t *, rwf_t);
+extern ssize_t do_copy_file_range(struct file *, loff_t , struct file *,
+ loff_t , size_t, unsigned int,
+ unsigned int);
extern ssize_t vfs_copy_file_range(struct file *, loff_t , struct file *,
loff_t, size_t, unsigned int);
extern int vfs_clone_file_prep_inodes(struct inode *inode_in, loff_t pos_in,