mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
xfs: refuse a pNFS LAYOUTCOMMIT of a range without blocks
A client can commit a hole in a LAYOUTCOMMIT, because nfsd does not
check the extents against its layouts. xfs_iomap_write_unwritten() then
allocates written blocks there. A large hole overruns the block
reservation and shuts XFS down. A small one exposes stale data.
Refuse such a range with -EIO, using XFS_BMAPI_CONVERT_ONLY.
Link: https://lore.kernel.org/r/20261014130834.GB15773@lst.de
Fixes: 527851124d ("xfs: implement pNFS export operations")
Cc: stable@vger.kernel.org
Signed-off-by: Daejun Park <daejun7.park@samsung.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
This commit is contained in:
parent
f3ca3498df
commit
bcf0b7f18a
|
|
@ -666,7 +666,7 @@ xfs_dio_write_end_io(
|
|||
* they are converted.
|
||||
*/
|
||||
if (flags & IOMAP_DIO_UNWRITTEN) {
|
||||
error = xfs_iomap_write_unwritten(ip, offset, size, true);
|
||||
error = xfs_iomap_write_unwritten(ip, offset, size, true, 0);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@ xfs_end_ioend_write(
|
|||
if (ioend->io_flags & IOMAP_IOEND_SHARED)
|
||||
error = xfs_reflink_end_cow(ip, offset, size);
|
||||
else if (ioend->io_flags & IOMAP_IOEND_UNWRITTEN)
|
||||
error = xfs_iomap_write_unwritten(ip, offset, size, false);
|
||||
error = xfs_iomap_write_unwritten(ip, offset, size, false, 0);
|
||||
|
||||
if (!error &&
|
||||
!(ioend->io_flags & IOMAP_IOEND_DIRECT) &&
|
||||
|
|
|
|||
|
|
@ -614,7 +614,8 @@ xfs_iomap_write_unwritten(
|
|||
xfs_inode_t *ip,
|
||||
xfs_off_t offset,
|
||||
xfs_off_t count,
|
||||
bool update_isize)
|
||||
bool update_isize,
|
||||
uint32_t bmapi_flags)
|
||||
{
|
||||
xfs_mount_t *mp = ip->i_mount;
|
||||
xfs_fileoff_t offset_fsb;
|
||||
|
|
@ -676,8 +677,21 @@ xfs_iomap_write_unwritten(
|
|||
*/
|
||||
nimaps = 1;
|
||||
error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb,
|
||||
XFS_BMAPI_CONVERT, resblks, &imap,
|
||||
&nimaps);
|
||||
XFS_BMAPI_CONVERT | bmapi_flags,
|
||||
resblks, &imap, &nimaps);
|
||||
if (error == -ENOSR && (bmapi_flags & XFS_BMAPI_CONVERT_ONLY)) {
|
||||
/*
|
||||
* Nothing was mapped: the rest of the range starts
|
||||
* with a hole or a delalloc extent. Nothing was
|
||||
* changed either, but xfs_iext_count_extend() may
|
||||
* have logged the inode, and cancelling a dirty
|
||||
* transaction shuts the filesystem down. Commit it,
|
||||
* as xfs_alloc_file_space() does on -ENOSR.
|
||||
*/
|
||||
error = xfs_trans_commit(tp);
|
||||
xfs_iunlock(ip, XFS_ILOCK_EXCL);
|
||||
return error ? error : -EIO;
|
||||
}
|
||||
if (error)
|
||||
goto error_on_bmapi_transaction;
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ struct xfs_zone_alloc_ctx;
|
|||
int xfs_iomap_write_direct(struct xfs_inode *ip, xfs_fileoff_t offset_fsb,
|
||||
xfs_fileoff_t count_fsb, unsigned int flags,
|
||||
struct xfs_bmbt_irec *imap, u64 *sequence);
|
||||
int xfs_iomap_write_unwritten(struct xfs_inode *, xfs_off_t, xfs_off_t, bool);
|
||||
int xfs_iomap_write_unwritten(struct xfs_inode *ip, xfs_off_t offset,
|
||||
xfs_off_t count, bool update_isize, uint32_t bmapi_flags);
|
||||
xfs_fileoff_t xfs_iomap_eof_align_last_fsb(struct xfs_inode *ip,
|
||||
xfs_fileoff_t end_fsb);
|
||||
|
||||
|
|
|
|||
|
|
@ -344,7 +344,14 @@ xfs_fs_commit_blocks(
|
|||
(end - 1) >> PAGE_SHIFT);
|
||||
WARN_ON_ONCE(error);
|
||||
|
||||
error = xfs_iomap_write_unwritten(ip, start, length, false);
|
||||
/*
|
||||
* A client may only write to blocks that a layout handed out,
|
||||
* and xfs_fs_map_blocks() allocates blocks for any hole in a
|
||||
* write layout, so refuse to allocate blocks for a hole or a
|
||||
* delalloc extent in the committed range.
|
||||
*/
|
||||
error = xfs_iomap_write_unwritten(ip, start, length, false,
|
||||
XFS_BMAPI_CONVERT_ONLY);
|
||||
if (error)
|
||||
goto out_drop_iolock;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user