Skip to content

Commit 0124855

Browse files
fdmananakdave
authored andcommitted
btrfs: add and use helpers for reading and writing last_trans_committed
Currently the last_trans_committed field of struct btrfs_fs_info is modified and read without any locking or other protection. For example early in the fsync path, skip_inode_logging() is called which reads fs_info->last_trans_committed, but at the same time we can have a transaction commit completing and updating that field. In the case of an fsync this is harmless and any data race should be rare and at most cause an unnecessary logging of an inode. To avoid data race warnings from tools like KCSAN and other issues such as load and store tearing (amongst others, see [1]), create helpers to access the last_trans_committed field of struct btrfs_fs_info using READ_ONCE() and WRITE_ONCE(), and use these helpers everywhere. [1] https://lwn.net/Articles/793253/ Signed-off-by: Filipe Manana <fdmanana@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent 4a4f8fe commit 0124855

8 files changed

Lines changed: 30 additions & 14 deletions

File tree

fs/btrfs/disk-io.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ blk_status_t btree_csum_one_bio(struct btrfs_bio *bbio)
244244
struct extent_buffer *eb = bbio->private;
245245
struct btrfs_fs_info *fs_info = eb->fs_info;
246246
u64 found_start = btrfs_header_bytenr(eb);
247+
u64 last_trans;
247248
u8 result[BTRFS_CSUM_SIZE];
248249
int ret;
249250

@@ -281,12 +282,12 @@ blk_status_t btree_csum_one_bio(struct btrfs_bio *bbio)
281282
* Also check the generation, the eb reached here must be newer than
282283
* last committed. Or something seriously wrong happened.
283284
*/
284-
if (unlikely(btrfs_header_generation(eb) <= fs_info->last_trans_committed)) {
285+
last_trans = btrfs_get_last_trans_committed(fs_info);
286+
if (unlikely(btrfs_header_generation(eb) <= last_trans)) {
285287
ret = -EUCLEAN;
286288
btrfs_err(fs_info,
287289
"block=%llu bad generation, have %llu expect > %llu",
288-
eb->start, btrfs_header_generation(eb),
289-
fs_info->last_trans_committed);
290+
eb->start, btrfs_header_generation(eb), last_trans);
290291
goto error;
291292
}
292293
write_extent_buffer(eb, result, 0, fs_info->csum_size);
@@ -2653,7 +2654,7 @@ static int __cold init_tree_roots(struct btrfs_fs_info *fs_info)
26532654

26542655
/* All successful */
26552656
fs_info->generation = btrfs_header_generation(tree_root->node);
2656-
fs_info->last_trans_committed = fs_info->generation;
2657+
btrfs_set_last_trans_committed(fs_info, fs_info->generation);
26572658
fs_info->last_reloc_trans = 0;
26582659

26592660
/* Always begin writing backup roots after the one being used */

fs/btrfs/file.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1760,7 +1760,7 @@ static inline bool skip_inode_logging(const struct btrfs_log_ctx *ctx)
17601760
* and for a fast fsync we don't wait for that, we only wait for the
17611761
* writeback to complete.
17621762
*/
1763-
if (inode->last_trans <= fs_info->last_trans_committed &&
1763+
if (inode->last_trans <= btrfs_get_last_trans_committed(fs_info) &&
17641764
(test_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &inode->runtime_flags) ||
17651765
list_empty(&ctx->ordered_extents)))
17661766
return true;

fs/btrfs/fs.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,10 @@ struct btrfs_fs_info {
423423
* Should always be updated using btrfs_set_fs_generation().
424424
*/
425425
u64 generation;
426+
/*
427+
* Always use btrfs_get_last_trans_committed() and
428+
* btrfs_set_last_trans_committed() to read and update this field.
429+
*/
426430
u64 last_trans_committed;
427431
/*
428432
* Generation of the last transaction used for block group relocation
@@ -833,6 +837,16 @@ static inline void btrfs_set_fs_generation(struct btrfs_fs_info *fs_info, u64 ge
833837
WRITE_ONCE(fs_info->generation, gen);
834838
}
835839

840+
static inline u64 btrfs_get_last_trans_committed(const struct btrfs_fs_info *fs_info)
841+
{
842+
return READ_ONCE(fs_info->last_trans_committed);
843+
}
844+
845+
static inline void btrfs_set_last_trans_committed(struct btrfs_fs_info *fs_info, u64 gen)
846+
{
847+
WRITE_ONCE(fs_info->last_trans_committed, gen);
848+
}
849+
836850
static inline void btrfs_set_last_root_drop_gen(struct btrfs_fs_info *fs_info,
837851
u64 gen)
838852
{

fs/btrfs/ioctl.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3131,7 +3131,7 @@ static noinline long btrfs_ioctl_start_sync(struct btrfs_root *root,
31313131
return PTR_ERR(trans);
31323132

31333133
/* No running transaction, don't bother */
3134-
transid = root->fs_info->last_trans_committed;
3134+
transid = btrfs_get_last_trans_committed(root->fs_info);
31353135
goto out;
31363136
}
31373137
transid = trans->transid;

fs/btrfs/scrub.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2787,7 +2787,7 @@ static noinline_for_stack int scrub_supers(struct scrub_ctx *sctx,
27872787
if (scrub_dev->fs_devices != fs_info->fs_devices)
27882788
gen = scrub_dev->generation;
27892789
else
2790-
gen = fs_info->last_trans_committed;
2790+
gen = btrfs_get_last_trans_committed(fs_info);
27912791

27922792
for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
27932793
bytenr = btrfs_sb_offset(i);

fs/btrfs/super.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2217,6 +2217,7 @@ static int check_dev_super(struct btrfs_device *dev)
22172217
{
22182218
struct btrfs_fs_info *fs_info = dev->fs_info;
22192219
struct btrfs_super_block *sb;
2220+
u64 last_trans;
22202221
u16 csum_type;
22212222
int ret = 0;
22222223

@@ -2252,10 +2253,10 @@ static int check_dev_super(struct btrfs_device *dev)
22522253
if (ret < 0)
22532254
goto out;
22542255

2255-
if (btrfs_super_generation(sb) != fs_info->last_trans_committed) {
2256+
last_trans = btrfs_get_last_trans_committed(fs_info);
2257+
if (btrfs_super_generation(sb) != last_trans) {
22562258
btrfs_err(fs_info, "transid mismatch, has %llu expect %llu",
2257-
btrfs_super_generation(sb),
2258-
fs_info->last_trans_committed);
2259+
btrfs_super_generation(sb), last_trans);
22592260
ret = -EUCLEAN;
22602261
goto out;
22612262
}

fs/btrfs/transaction.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -980,7 +980,7 @@ int btrfs_wait_for_commit(struct btrfs_fs_info *fs_info, u64 transid)
980980
int ret = 0;
981981

982982
if (transid) {
983-
if (transid <= fs_info->last_trans_committed)
983+
if (transid <= btrfs_get_last_trans_committed(fs_info))
984984
goto out;
985985

986986
/* find specified transaction */
@@ -1004,7 +1004,7 @@ int btrfs_wait_for_commit(struct btrfs_fs_info *fs_info, u64 transid)
10041004
* raced with btrfs_commit_transaction
10051005
*/
10061006
if (!cur_trans) {
1007-
if (transid > fs_info->last_trans_committed)
1007+
if (transid > btrfs_get_last_trans_committed(fs_info))
10081008
ret = -EINVAL;
10091009
goto out;
10101010
}
@@ -2587,7 +2587,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
25872587
if (test_bit(BTRFS_TRANS_HAVE_FREE_BGS, &cur_trans->flags))
25882588
btrfs_clear_space_info_full(fs_info);
25892589

2590-
fs_info->last_trans_committed = cur_trans->transid;
2590+
btrfs_set_last_trans_committed(fs_info, cur_trans->transid);
25912591
/*
25922592
* We needn't acquire the lock here because there is no other task
25932593
* which can change it.

fs/btrfs/tree-checker.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2051,7 +2051,7 @@ int btrfs_verify_level_key(struct extent_buffer *eb, int level,
20512051
* So we only checks tree blocks which is read from disk, whose
20522052
* generation <= fs_info->last_trans_committed.
20532053
*/
2054-
if (btrfs_header_generation(eb) > fs_info->last_trans_committed)
2054+
if (btrfs_header_generation(eb) > btrfs_get_last_trans_committed(fs_info))
20552055
return 0;
20562056

20572057
/* We have @first_key, so this @eb must have at least one item */

0 commit comments

Comments
 (0)