* [PATCH] btrfs: update generation of hole file extent item when merging holes
@ 2022-08-08 11:18 fdmanana
2022-08-08 19:09 ` Josef Bacik
2022-08-18 12:10 ` David Sterba
0 siblings, 2 replies; 3+ messages in thread
From: fdmanana @ 2022-08-08 11:18 UTC (permalink / raw)
To: linux-btrfs
From: Filipe Manana <fdmanana@suse.com>
When punching a hole into a file range that is adjacent with a hole and we
are not using the no-holes feature, we expand the range of the adjacent
file extent item that represents a hole, to save metadata space.
However we don't update the generation of hole file extent item, which
means a full fsync will not log that file extent item if the fsync happens
in a later transaction (since commit 7f30c07288bb9e ("btrfs: stop copying
old file extents when doing a full fsync")).
For example, if we do this:
$ mkfs.btrfs -f -O ^no-holes /dev/sdb
$ mount /dev/sdb /mnt
$ xfs_io -f -c "pwrite -S 0xab 2M 2M" /mnt/foobar
$ sync
We end up with 2 file extent items in our file:
1) One that represents the hole for the file range [0, 2M), with a
generation of 7;
2) Another one that represents an extent covering the range [2M, 4M).
After that if we do the following:
$ xfs_io -c "fpunch 2M 2M" /mnt/foobar
We end up with a single file extent item in the file, which represents a
hole for the range [0, 4M) and with a generation of 7 - because we end
dropping the data extent for range [2M, 4M) and then update the file
extent item that represented the hole at [0, 2M), by increasing
length from 2M to 4M.
Then doing a full fsync and power failing:
$ xfs_io -c "fsync" /mnt/foobar
<power failure>
will result in the full fsync not logging the file extent item that
represents the hole for the range [0, 4M), because its generation is 7,
which is lower than the generation of the current transaction (8).
As a consequence, after mounting again the filesystem (after log replay),
the region [2M, 4M) does not have a hole, it still points to the
previous data extent.
So fix this by always updating the generation of existing file extent
items representing holes when we merge/expand them. This solves the
problem and it's the same approach as when we merge prealloc extents that
got written (at btrfs_mark_extent_written()). Setting the generation to
the current transaction's generation is also what we do when merging
the new hole extent map with the previous one or the next one.
A test case for fstests, covering both cases of hole file extent item
merging (to the left and to the right), will be sent soon.
Fixes: 7f30c07288bb9e ("btrfs: stop copying old file extents when doing a full fsync")
CC: stable@vger.kernel.org # 5.18+
Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
fs/btrfs/file.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 687fb372093f..470421955de4 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -2499,6 +2499,7 @@ static int fill_holes(struct btrfs_trans_handle *trans,
btrfs_set_file_extent_num_bytes(leaf, fi, num_bytes);
btrfs_set_file_extent_ram_bytes(leaf, fi, num_bytes);
btrfs_set_file_extent_offset(leaf, fi, 0);
+ btrfs_set_file_extent_generation(leaf, fi, trans->transid);
btrfs_mark_buffer_dirty(leaf);
goto out;
}
@@ -2515,6 +2516,7 @@ static int fill_holes(struct btrfs_trans_handle *trans,
btrfs_set_file_extent_num_bytes(leaf, fi, num_bytes);
btrfs_set_file_extent_ram_bytes(leaf, fi, num_bytes);
btrfs_set_file_extent_offset(leaf, fi, 0);
+ btrfs_set_file_extent_generation(leaf, fi, trans->transid);
btrfs_mark_buffer_dirty(leaf);
goto out;
}
--
2.35.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] btrfs: update generation of hole file extent item when merging holes
2022-08-08 11:18 [PATCH] btrfs: update generation of hole file extent item when merging holes fdmanana
@ 2022-08-08 19:09 ` Josef Bacik
2022-08-18 12:10 ` David Sterba
1 sibling, 0 replies; 3+ messages in thread
From: Josef Bacik @ 2022-08-08 19:09 UTC (permalink / raw)
To: fdmanana; +Cc: linux-btrfs
On Mon, Aug 08, 2022 at 12:18:37PM +0100, fdmanana@kernel.org wrote:
> From: Filipe Manana <fdmanana@suse.com>
>
> When punching a hole into a file range that is adjacent with a hole and we
> are not using the no-holes feature, we expand the range of the adjacent
> file extent item that represents a hole, to save metadata space.
>
> However we don't update the generation of hole file extent item, which
> means a full fsync will not log that file extent item if the fsync happens
> in a later transaction (since commit 7f30c07288bb9e ("btrfs: stop copying
> old file extents when doing a full fsync")).
>
> For example, if we do this:
>
> $ mkfs.btrfs -f -O ^no-holes /dev/sdb
> $ mount /dev/sdb /mnt
> $ xfs_io -f -c "pwrite -S 0xab 2M 2M" /mnt/foobar
> $ sync
>
> We end up with 2 file extent items in our file:
>
> 1) One that represents the hole for the file range [0, 2M), with a
> generation of 7;
>
> 2) Another one that represents an extent covering the range [2M, 4M).
>
> After that if we do the following:
>
> $ xfs_io -c "fpunch 2M 2M" /mnt/foobar
>
> We end up with a single file extent item in the file, which represents a
> hole for the range [0, 4M) and with a generation of 7 - because we end
> dropping the data extent for range [2M, 4M) and then update the file
> extent item that represented the hole at [0, 2M), by increasing
> length from 2M to 4M.
>
> Then doing a full fsync and power failing:
>
> $ xfs_io -c "fsync" /mnt/foobar
> <power failure>
>
> will result in the full fsync not logging the file extent item that
> represents the hole for the range [0, 4M), because its generation is 7,
> which is lower than the generation of the current transaction (8).
> As a consequence, after mounting again the filesystem (after log replay),
> the region [2M, 4M) does not have a hole, it still points to the
> previous data extent.
>
> So fix this by always updating the generation of existing file extent
> items representing holes when we merge/expand them. This solves the
> problem and it's the same approach as when we merge prealloc extents that
> got written (at btrfs_mark_extent_written()). Setting the generation to
> the current transaction's generation is also what we do when merging
> the new hole extent map with the previous one or the next one.
>
> A test case for fstests, covering both cases of hole file extent item
> merging (to the left and to the right), will be sent soon.
>
> Fixes: 7f30c07288bb9e ("btrfs: stop copying old file extents when doing a full fsync")
> CC: stable@vger.kernel.org # 5.18+
> Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Thanks,
Josef
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] btrfs: update generation of hole file extent item when merging holes
2022-08-08 11:18 [PATCH] btrfs: update generation of hole file extent item when merging holes fdmanana
2022-08-08 19:09 ` Josef Bacik
@ 2022-08-18 12:10 ` David Sterba
1 sibling, 0 replies; 3+ messages in thread
From: David Sterba @ 2022-08-18 12:10 UTC (permalink / raw)
To: fdmanana; +Cc: linux-btrfs
On Mon, Aug 08, 2022 at 12:18:37PM +0100, fdmanana@kernel.org wrote:
> From: Filipe Manana <fdmanana@suse.com>
>
> When punching a hole into a file range that is adjacent with a hole and we
> are not using the no-holes feature, we expand the range of the adjacent
> file extent item that represents a hole, to save metadata space.
>
> However we don't update the generation of hole file extent item, which
> means a full fsync will not log that file extent item if the fsync happens
> in a later transaction (since commit 7f30c07288bb9e ("btrfs: stop copying
> old file extents when doing a full fsync")).
>
> For example, if we do this:
>
> $ mkfs.btrfs -f -O ^no-holes /dev/sdb
> $ mount /dev/sdb /mnt
> $ xfs_io -f -c "pwrite -S 0xab 2M 2M" /mnt/foobar
> $ sync
>
> We end up with 2 file extent items in our file:
>
> 1) One that represents the hole for the file range [0, 2M), with a
> generation of 7;
>
> 2) Another one that represents an extent covering the range [2M, 4M).
>
> After that if we do the following:
>
> $ xfs_io -c "fpunch 2M 2M" /mnt/foobar
>
> We end up with a single file extent item in the file, which represents a
> hole for the range [0, 4M) and with a generation of 7 - because we end
> dropping the data extent for range [2M, 4M) and then update the file
> extent item that represented the hole at [0, 2M), by increasing
> length from 2M to 4M.
>
> Then doing a full fsync and power failing:
>
> $ xfs_io -c "fsync" /mnt/foobar
> <power failure>
>
> will result in the full fsync not logging the file extent item that
> represents the hole for the range [0, 4M), because its generation is 7,
> which is lower than the generation of the current transaction (8).
> As a consequence, after mounting again the filesystem (after log replay),
> the region [2M, 4M) does not have a hole, it still points to the
> previous data extent.
>
> So fix this by always updating the generation of existing file extent
> items representing holes when we merge/expand them. This solves the
> problem and it's the same approach as when we merge prealloc extents that
> got written (at btrfs_mark_extent_written()). Setting the generation to
> the current transaction's generation is also what we do when merging
> the new hole extent map with the previous one or the next one.
>
> A test case for fstests, covering both cases of hole file extent item
> merging (to the left and to the right), will be sent soon.
>
> Fixes: 7f30c07288bb9e ("btrfs: stop copying old file extents when doing a full fsync")
> CC: stable@vger.kernel.org # 5.18+
> Signed-off-by: Filipe Manana <fdmanana@suse.com>
Added to misc-next, thanks.
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2022-08-18 12:15 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-08-08 11:18 [PATCH] btrfs: update generation of hole file extent item when merging holes fdmanana
2022-08-08 19:09 ` Josef Bacik
2022-08-18 12:10 ` David Sterba
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).