vfs: no fallback for ->copy_file_range
Now that we have generic_copy_file_range(), remove it as a fallback case when offloads fail. This puts the responsibility for executing fallbacks on the filesystems that implement ->copy_file_range and allows us to add operational validity checks to generic_copy_file_range(). Rework vfs_copy_file_range() to call a new do_copy_file_range() helper to execute the copying callout, and move calls to generic_file_copy_range() into filesystem methods where they currently return failures. [Amir] overlayfs is not responsible of executing the fallback. It is the responsibility of the underlying filesystem. Signed-off-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Amir Goldstein <amir73il@gmail.com> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
This commit is contained in:
Родитель
f16acc9d9b
Коммит
64bf5ff58d
|
@ -1889,7 +1889,7 @@ static int is_file_size_ok(struct inode *src_inode, struct inode *dst_inode,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t ceph_copy_file_range(struct file *src_file, loff_t src_off,
|
||||
static ssize_t __ceph_copy_file_range(struct file *src_file, loff_t src_off,
|
||||
struct file *dst_file, loff_t dst_off,
|
||||
size_t len, unsigned int flags)
|
||||
{
|
||||
|
@ -2100,6 +2100,21 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t ceph_copy_file_range(struct file *src_file, loff_t src_off,
|
||||
struct file *dst_file, loff_t dst_off,
|
||||
size_t len, unsigned int flags)
|
||||
{
|
||||
ssize_t ret;
|
||||
|
||||
ret = __ceph_copy_file_range(src_file, src_off, dst_file, dst_off,
|
||||
len, flags);
|
||||
|
||||
if (ret == -EOPNOTSUPP)
|
||||
ret = generic_copy_file_range(src_file, src_off, dst_file,
|
||||
dst_off, len, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct file_operations ceph_file_fops = {
|
||||
.open = ceph_open,
|
||||
.release = ceph_release,
|
||||
|
|
|
@ -1148,6 +1148,10 @@ static ssize_t cifs_copy_file_range(struct file *src_file, loff_t off,
|
|||
rc = cifs_file_copychunk_range(xid, src_file, off, dst_file, destoff,
|
||||
len, flags);
|
||||
free_xid(xid);
|
||||
|
||||
if (rc == -EOPNOTSUPP)
|
||||
rc = generic_copy_file_range(src_file, off, dst_file,
|
||||
destoff, len, flags);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -3112,7 +3112,7 @@ out:
|
|||
return err;
|
||||
}
|
||||
|
||||
static ssize_t fuse_copy_file_range(struct file *file_in, loff_t pos_in,
|
||||
static ssize_t __fuse_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)
|
||||
{
|
||||
|
@ -3194,6 +3194,21 @@ out:
|
|||
return err;
|
||||
}
|
||||
|
||||
static ssize_t fuse_copy_file_range(struct file *src_file, loff_t src_off,
|
||||
struct file *dst_file, loff_t dst_off,
|
||||
size_t len, unsigned int flags)
|
||||
{
|
||||
ssize_t ret;
|
||||
|
||||
ret = __fuse_copy_file_range(src_file, src_off, dst_file, dst_off,
|
||||
len, flags);
|
||||
|
||||
if (ret == -EOPNOTSUPP)
|
||||
ret = generic_copy_file_range(src_file, src_off, dst_file,
|
||||
dst_off, len, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations fuse_file_operations = {
|
||||
.llseek = fuse_file_llseek,
|
||||
.read_iter = fuse_file_read_iter,
|
||||
|
|
|
@ -129,7 +129,7 @@ nfs4_file_flush(struct file *file, fl_owner_t id)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_NFS_V4_2
|
||||
static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
|
||||
static ssize_t __nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
|
||||
struct file *file_out, loff_t pos_out,
|
||||
size_t count, unsigned int flags)
|
||||
{
|
||||
|
@ -140,6 +140,20 @@ static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
|
|||
return nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count);
|
||||
}
|
||||
|
||||
static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
|
||||
struct file *file_out, loff_t pos_out,
|
||||
size_t count, unsigned int flags)
|
||||
{
|
||||
ssize_t ret;
|
||||
|
||||
ret = __nfs4_copy_file_range(file_in, pos_in, file_out, pos_out, count,
|
||||
flags);
|
||||
if (ret == -EOPNOTSUPP)
|
||||
ret = generic_copy_file_range(file_in, pos_in, file_out,
|
||||
pos_out, count, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence)
|
||||
{
|
||||
loff_t ret;
|
||||
|
|
|
@ -1595,6 +1595,19 @@ ssize_t generic_copy_file_range(struct file *file_in, loff_t pos_in,
|
|||
}
|
||||
EXPORT_SYMBOL(generic_copy_file_range);
|
||||
|
||||
static 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)
|
||||
{
|
||||
if (file_out->f_op->copy_file_range)
|
||||
return file_out->f_op->copy_file_range(file_in, pos_in,
|
||||
file_out, pos_out,
|
||||
len, flags);
|
||||
|
||||
return generic_copy_file_range(file_in, pos_in, file_out, pos_out, len,
|
||||
flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* copy_file_range() differs from regular file read and write in that it
|
||||
* specifically allows return partial success. When it does so is up to
|
||||
|
@ -1655,15 +1668,9 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
|
|||
}
|
||||
}
|
||||
|
||||
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)
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = generic_copy_file_range(file_in, pos_in, file_out, pos_out, len,
|
||||
ret = do_copy_file_range(file_in, pos_in, file_out, pos_out, len,
|
||||
flags);
|
||||
WARN_ON_ONCE(ret == -EOPNOTSUPP);
|
||||
done:
|
||||
if (ret > 0) {
|
||||
fsnotify_access(file_in);
|
||||
|
|
Загрузка…
Ссылка в новой задаче