Skip to content

Commit 7833b86

Browse files
Christoph Hellwigkdave
authored andcommitted
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 commit c5794e5 ("btrfs: Factor out write portion of btrfs_get_blocks_direct"), but the ordered_extent splitting added in commit b73a6fd ("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: c5794e5 ("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>
1 parent 79b8ee7 commit 7833b86

File tree

1 file changed

+12
-6
lines changed

1 file changed

+12
-6
lines changed

fs/btrfs/inode.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7264,7 +7264,7 @@ static struct extent_map *create_io_em(struct btrfs_inode *inode, u64 start,
72647264
static int btrfs_get_blocks_direct_write(struct extent_map **map,
72657265
struct inode *inode,
72667266
struct btrfs_dio_data *dio_data,
7267-
u64 start, u64 len,
7267+
u64 start, u64 *lenp,
72687268
unsigned int iomap_flags)
72697269
{
72707270
const bool nowait = (iomap_flags & IOMAP_NOWAIT);
@@ -7275,6 +7275,7 @@ static int btrfs_get_blocks_direct_write(struct extent_map **map,
72757275
struct btrfs_block_group *bg;
72767276
bool can_nocow = false;
72777277
bool space_reserved = false;
7278+
u64 len = *lenp;
72787279
u64 prev_len;
72797280
int ret = 0;
72807281

@@ -7345,15 +7346,19 @@ static int btrfs_get_blocks_direct_write(struct extent_map **map,
73457346
free_extent_map(em);
73467347
*map = NULL;
73477348

7348-
if (nowait)
7349-
return -EAGAIN;
7349+
if (nowait) {
7350+
ret = -EAGAIN;
7351+
goto out;
7352+
}
73507353

73517354
/*
73527355
* If we could not allocate data space before locking the file
73537356
* range and we can't do a NOCOW write, then we have to fail.
73547357
*/
7355-
if (!dio_data->data_space_reserved)
7356-
return -ENOSPC;
7358+
if (!dio_data->data_space_reserved) {
7359+
ret = -ENOSPC;
7360+
goto out;
7361+
}
73577362

73587363
/*
73597364
* We have to COW and we have already reserved data space before,
@@ -7394,6 +7399,7 @@ static int btrfs_get_blocks_direct_write(struct extent_map **map,
73947399
btrfs_delalloc_release_extents(BTRFS_I(inode), len);
73957400
btrfs_delalloc_release_metadata(BTRFS_I(inode), len, true);
73967401
}
7402+
*lenp = len;
73977403
return ret;
73987404
}
73997405

@@ -7570,7 +7576,7 @@ static int btrfs_dio_iomap_begin(struct inode *inode, loff_t start,
75707576

75717577
if (write) {
75727578
ret = btrfs_get_blocks_direct_write(&em, inode, dio_data,
7573-
start, len, flags);
7579+
start, &len, flags);
75747580
if (ret < 0)
75757581
goto unlock_err;
75767582
unlock_extents = true;

0 commit comments

Comments
 (0)