|
@@ -1542,20 +1542,37 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
|
|
|
if (ret)
|
|
|
return ret;
|
|
|
|
|
|
- ret = -EOPNOTSUPP;
|
|
|
- if (file_out->f_op->copy_file_range)
|
|
|
+ /*
|
|
|
+ * Try cloning first, this is supported by more file systems, and
|
|
|
+ * more efficient if both clone and copy are supported (e.g. NFS).
|
|
|
+ */
|
|
|
+ if (file_in->f_op->clone_file_range) {
|
|
|
+ ret = file_in->f_op->clone_file_range(file_in, pos_in,
|
|
|
+ file_out, pos_out, len);
|
|
|
+ if (ret == 0) {
|
|
|
+ ret = len;
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (file_out->f_op->copy_file_range) {
|
|
|
ret = file_out->f_op->copy_file_range(file_in, pos_in, file_out,
|
|
|
pos_out, len, flags);
|
|
|
- if (ret == -EOPNOTSUPP)
|
|
|
- ret = do_splice_direct(file_in, &pos_in, file_out, &pos_out,
|
|
|
- len > MAX_RW_COUNT ? MAX_RW_COUNT : len, 0);
|
|
|
+ if (ret != -EOPNOTSUPP)
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
|
|
|
+ ret = do_splice_direct(file_in, &pos_in, file_out, &pos_out,
|
|
|
+ len > MAX_RW_COUNT ? MAX_RW_COUNT : len, 0);
|
|
|
+
|
|
|
+done:
|
|
|
if (ret > 0) {
|
|
|
fsnotify_access(file_in);
|
|
|
add_rchar(current, ret);
|
|
|
fsnotify_modify(file_out);
|
|
|
add_wchar(current, ret);
|
|
|
}
|
|
|
+
|
|
|
inc_syscr(current);
|
|
|
inc_syscw(current);
|
|
|
|