mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-02 08:34:20 +08:00
btrfs: fix iomap_begin length for nocow writes
can_nocow_extent can reduce the len passed in, which needs to be propagated to btrfs_dio_iomap_begin so that iomap does not submit more data then is mapped. This problems exists since the btrfs_get_blocks_direct helper was added in commitc5794e5178
("btrfs: Factor out write portion of btrfs_get_blocks_direct"), but the ordered_extent splitting added in commitb73a6fd1b1
("btrfs: split partial dio bios before submit") added a WARN_ON that made a syzkaller test fail. Reported-by: syzbot+ee90502d5c8fd1d0dd93@syzkaller.appspotmail.com Fixes:c5794e5178
("btrfs: Factor out write portion of btrfs_get_blocks_direct") CC: stable@vger.kernel.org # 6.1+ Tested-by: syzbot+ee90502d5c8fd1d0dd93@syzkaller.appspotmail.com Reviewed-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
79b8ee702c
commit
7833b86595
@ -7264,7 +7264,7 @@ static struct extent_map *create_io_em(struct btrfs_inode *inode, u64 start,
|
||||
static int btrfs_get_blocks_direct_write(struct extent_map **map,
|
||||
struct inode *inode,
|
||||
struct btrfs_dio_data *dio_data,
|
||||
u64 start, u64 len,
|
||||
u64 start, u64 *lenp,
|
||||
unsigned int iomap_flags)
|
||||
{
|
||||
const bool nowait = (iomap_flags & IOMAP_NOWAIT);
|
||||
@ -7275,6 +7275,7 @@ static int btrfs_get_blocks_direct_write(struct extent_map **map,
|
||||
struct btrfs_block_group *bg;
|
||||
bool can_nocow = false;
|
||||
bool space_reserved = false;
|
||||
u64 len = *lenp;
|
||||
u64 prev_len;
|
||||
int ret = 0;
|
||||
|
||||
@ -7345,15 +7346,19 @@ static int btrfs_get_blocks_direct_write(struct extent_map **map,
|
||||
free_extent_map(em);
|
||||
*map = NULL;
|
||||
|
||||
if (nowait)
|
||||
return -EAGAIN;
|
||||
if (nowait) {
|
||||
ret = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we could not allocate data space before locking the file
|
||||
* range and we can't do a NOCOW write, then we have to fail.
|
||||
*/
|
||||
if (!dio_data->data_space_reserved)
|
||||
return -ENOSPC;
|
||||
if (!dio_data->data_space_reserved) {
|
||||
ret = -ENOSPC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have to COW and we have already reserved data space before,
|
||||
@ -7394,6 +7399,7 @@ out:
|
||||
btrfs_delalloc_release_extents(BTRFS_I(inode), len);
|
||||
btrfs_delalloc_release_metadata(BTRFS_I(inode), len, true);
|
||||
}
|
||||
*lenp = len;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -7570,7 +7576,7 @@ static int btrfs_dio_iomap_begin(struct inode *inode, loff_t start,
|
||||
|
||||
if (write) {
|
||||
ret = btrfs_get_blocks_direct_write(&em, inode, dio_data,
|
||||
start, len, flags);
|
||||
start, &len, flags);
|
||||
if (ret < 0)
|
||||
goto unlock_err;
|
||||
unlock_extents = true;
|
||||
|
Loading…
Reference in New Issue
Block a user