mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 10:00:17 +00:00
NFSv4.2: Protect copy offload and clone against 'eof page pollution'
[ Upstream commit b2036bb651 ]
The NFSv4.2 copy offload and clone functions can also end up extending
the size of the destination file, so they too need to call
nfs_truncate_last_folio().
Reported-by: Olga Kornievskaia <okorniev@redhat.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
204099ce65
commit
aae986c580
@@ -363,22 +363,27 @@ out:
|
||||
|
||||
/**
|
||||
* nfs42_copy_dest_done - perform inode cache updates after clone/copy offload
|
||||
* @inode: pointer to destination inode
|
||||
* @file: pointer to destination file
|
||||
* @pos: destination offset
|
||||
* @len: copy length
|
||||
* @oldsize: length of the file prior to clone/copy
|
||||
*
|
||||
* 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)
|
||||
static void nfs42_copy_dest_done(struct file *file, loff_t pos, loff_t len,
|
||||
loff_t oldsize)
|
||||
{
|
||||
struct inode *inode = file_inode(file);
|
||||
struct address_space *mapping = file->f_mapping;
|
||||
loff_t newsize = pos + len;
|
||||
loff_t end = newsize - 1;
|
||||
|
||||
WARN_ON_ONCE(invalidate_inode_pages2_range(inode->i_mapping,
|
||||
pos >> PAGE_SHIFT, end >> PAGE_SHIFT));
|
||||
nfs_truncate_last_folio(mapping, oldsize, pos);
|
||||
WARN_ON_ONCE(invalidate_inode_pages2_range(mapping, pos >> PAGE_SHIFT,
|
||||
end >> PAGE_SHIFT));
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
if (newsize > i_size_read(inode))
|
||||
@@ -411,6 +416,7 @@ static ssize_t _nfs42_proc_copy(struct file *src,
|
||||
struct nfs_server *src_server = NFS_SERVER(src_inode);
|
||||
loff_t pos_src = args->src_pos;
|
||||
loff_t pos_dst = args->dst_pos;
|
||||
loff_t oldsize_dst = i_size_read(dst_inode);
|
||||
size_t count = args->count;
|
||||
ssize_t status;
|
||||
|
||||
@@ -485,7 +491,7 @@ static ssize_t _nfs42_proc_copy(struct file *src,
|
||||
goto out;
|
||||
}
|
||||
|
||||
nfs42_copy_dest_done(dst_inode, pos_dst, res->write_res.count);
|
||||
nfs42_copy_dest_done(dst, pos_dst, res->write_res.count, oldsize_dst);
|
||||
nfs_invalidate_atime(src_inode);
|
||||
status = res->write_res.count;
|
||||
out:
|
||||
@@ -1252,6 +1258,7 @@ static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
|
||||
struct nfs42_clone_res res = {
|
||||
.server = server,
|
||||
};
|
||||
loff_t oldsize_dst = i_size_read(dst_inode);
|
||||
int status;
|
||||
|
||||
msg->rpc_argp = &args;
|
||||
@@ -1286,7 +1293,7 @@ static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
|
||||
/* a zero-length count means clone to EOF in src */
|
||||
if (count == 0 && res.dst_fattr->valid & NFS_ATTR_FATTR_SIZE)
|
||||
count = nfs_size_to_loff_t(res.dst_fattr->size) - dst_offset;
|
||||
nfs42_copy_dest_done(dst_inode, dst_offset, count);
|
||||
nfs42_copy_dest_done(dst_f, dst_offset, count, oldsize_dst);
|
||||
status = nfs_post_op_update_inode(dst_inode, res.dst_fattr);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user