Commit 21fad313 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Trond Myklebust

nfs: allow intra-file CLONE

Originally CLONE didn't allow for intra-file clones, but we recently
updated the spec to support this feature which is also supported by
local Linux file systems.
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
parent 3a2e1769
...@@ -203,6 +203,7 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd, ...@@ -203,6 +203,7 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd,
struct fd src_file; struct fd src_file;
struct inode *src_inode; struct inode *src_inode;
unsigned int bs = server->clone_blksize; unsigned int bs = server->clone_blksize;
bool same_inode = false;
int ret; int ret;
/* dst file must be opened for writing */ /* dst file must be opened for writing */
...@@ -221,10 +222,8 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd, ...@@ -221,10 +222,8 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd,
src_inode = file_inode(src_file.file); src_inode = file_inode(src_file.file);
/* src and dst must be different files */
ret = -EINVAL;
if (src_inode == dst_inode) if (src_inode == dst_inode)
goto out_fput; same_inode = true;
/* src file must be opened for reading */ /* src file must be opened for reading */
if (!(src_file.file->f_mode & FMODE_READ)) if (!(src_file.file->f_mode & FMODE_READ))
...@@ -249,8 +248,16 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd, ...@@ -249,8 +248,16 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd,
goto out_fput; goto out_fput;
} }
/* verify if ranges are overlapped within the same file */
if (same_inode) {
if (dst_off + count > src_off && dst_off < src_off + count)
goto out_fput;
}
/* XXX: do we lock at all? what if server needs CB_RECALL_LAYOUT? */ /* XXX: do we lock at all? what if server needs CB_RECALL_LAYOUT? */
if (dst_inode < src_inode) { if (same_inode) {
mutex_lock(&src_inode->i_mutex);
} else if (dst_inode < src_inode) {
mutex_lock_nested(&dst_inode->i_mutex, I_MUTEX_PARENT); mutex_lock_nested(&dst_inode->i_mutex, I_MUTEX_PARENT);
mutex_lock_nested(&src_inode->i_mutex, I_MUTEX_CHILD); mutex_lock_nested(&src_inode->i_mutex, I_MUTEX_CHILD);
} else { } else {
...@@ -275,7 +282,9 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd, ...@@ -275,7 +282,9 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd,
truncate_inode_pages_range(&dst_inode->i_data, dst_off, dst_off + count - 1); truncate_inode_pages_range(&dst_inode->i_data, dst_off, dst_off + count - 1);
out_unlock: out_unlock:
if (dst_inode < src_inode) { if (same_inode) {
mutex_unlock(&src_inode->i_mutex);
} else if (dst_inode < src_inode) {
mutex_unlock(&src_inode->i_mutex); mutex_unlock(&src_inode->i_mutex);
mutex_unlock(&dst_inode->i_mutex); mutex_unlock(&dst_inode->i_mutex);
} else { } else {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment