mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 21:38:32 +08:00
NFSv42: Copy offload should update the file size when appropriate
If the result of a copy offload or clone operation is to grow the
destination file size, then we should update it. The reason is that when
a client holds a delegation, it is authoritative for the file size.
Fixes: 16abd2a0c1
("NFSv4.2: fix client's attribute cache management for copy_file_range")
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
This commit is contained in:
parent
09252177d5
commit
94d202d5ca
@ -269,6 +269,33 @@ out:
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs42_copy_dest_done - perform inode cache updates after clone/copy offload
|
||||
* @inode: pointer to destination inode
|
||||
* @pos: destination offset
|
||||
* @len: copy length
|
||||
*
|
||||
* Punch a hole in the inode page cache, so that the NFS client will
|
||||
* know to retrieve new data.
|
||||
* Update the file size if necessary, and then mark the inode as having
|
||||
* invalid cached values for change attribute, ctime, mtime and space used.
|
||||
*/
|
||||
static void nfs42_copy_dest_done(struct inode *inode, loff_t pos, loff_t len)
|
||||
{
|
||||
loff_t newsize = pos + len;
|
||||
loff_t end = newsize - 1;
|
||||
|
||||
truncate_pagecache_range(inode, pos, end);
|
||||
spin_lock(&inode->i_lock);
|
||||
if (newsize > i_size_read(inode))
|
||||
i_size_write(inode, newsize);
|
||||
nfs_set_cache_invalid(inode, NFS_INO_INVALID_CHANGE |
|
||||
NFS_INO_INVALID_CTIME |
|
||||
NFS_INO_INVALID_MTIME |
|
||||
NFS_INO_INVALID_BLOCKS);
|
||||
spin_unlock(&inode->i_lock);
|
||||
}
|
||||
|
||||
static ssize_t _nfs42_proc_copy(struct file *src,
|
||||
struct nfs_lock_context *src_lock,
|
||||
struct file *dst,
|
||||
@ -362,14 +389,8 @@ static ssize_t _nfs42_proc_copy(struct file *src,
|
||||
goto out;
|
||||
}
|
||||
|
||||
truncate_pagecache_range(dst_inode, pos_dst,
|
||||
pos_dst + res->write_res.count);
|
||||
spin_lock(&dst_inode->i_lock);
|
||||
nfs_set_cache_invalid(
|
||||
dst_inode, NFS_INO_REVAL_PAGECACHE | NFS_INO_REVAL_FORCED |
|
||||
NFS_INO_INVALID_SIZE | NFS_INO_INVALID_ATTR |
|
||||
NFS_INO_INVALID_DATA);
|
||||
spin_unlock(&dst_inode->i_lock);
|
||||
nfs42_copy_dest_done(dst_inode, pos_dst, res->write_res.count);
|
||||
|
||||
spin_lock(&src_inode->i_lock);
|
||||
nfs_set_cache_invalid(src_inode, NFS_INO_REVAL_PAGECACHE |
|
||||
NFS_INO_REVAL_FORCED |
|
||||
@ -1055,8 +1076,10 @@ static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
|
||||
|
||||
status = nfs4_call_sync(server->client, server, msg,
|
||||
&args.seq_args, &res.seq_res, 0);
|
||||
if (status == 0)
|
||||
if (status == 0) {
|
||||
nfs42_copy_dest_done(dst_inode, dst_offset, count);
|
||||
status = nfs_post_op_update_inode(dst_inode, res.dst_fattr);
|
||||
}
|
||||
|
||||
kfree(res.dst_fattr);
|
||||
return status;
|
||||
|
Loading…
Reference in New Issue
Block a user