Skip to content

Commit

Permalink
btrfs: expose per-inode stable writes flag
Browse files Browse the repository at this point in the history
[ Upstream commit ecde48a ]

The address space flag AS_STABLE_WRITES determine if FGP_STABLE for will
wait for the folio to finish its writeback.

For btrfs, due to the default data checksum behavior, if we modify the
folio while it's still under writeback, it will cause data checksum
mismatch.  Thus for quite some call sites we manually call
folio_wait_writeback() to prevent such problem from happening.

Currently there is only one call site inside btrfs really utilizing
FGP_STABLE, and in that case we also manually call folio_wait_writeback()
to do the waiting.

But it's better to properly expose the stable writes flag to a per-inode
basis, to allow call sites to fully benefit from FGP_STABLE flag.
E.g. for inodes with NODATASUM allowing beginning dirtying the page
without waiting for writeback.

This involves:

- Update the mapping's stable write flag when setting/clearing NODATASUM
  inode flag using ioctl
  This only works for empty files, so it should be fine.

- Update the mapping's stable write flag when reading an inode from disk

- Remove the explicit folio_wait_writeback() for FGP_BEGINWRITE call
  site

Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Stable-dep-of: 48c1d1b ("btrfs: fix the inode leak in btrfs_iget()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
Qu Wenruo authored and Greg Kroah-Hartman committed May 9, 2025
1 parent 7ec0416 commit ae58472
Show file tree
Hide file tree
Showing 4 changed files with 11 additions and 1 deletion.
8 changes: 8 additions & 0 deletions fs/btrfs/btrfs_inode.h
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,14 @@ static inline void btrfs_assert_inode_locked(struct btrfs_inode *inode)
lockdep_assert_held(&inode->vfs_inode.i_rwsem);
}

static inline void btrfs_update_inode_mapping_flags(struct btrfs_inode *inode)
{
if (inode->flags & BTRFS_INODE_NODATASUM)
mapping_clear_stable_writes(inode->vfs_inode.i_mapping);
else
mapping_set_stable_writes(inode->vfs_inode.i_mapping);
}

/* Array of bytes with variable length, hexadecimal format 0x1234 */
#define CSUM_FMT "0x%*phN"
#define CSUM_FMT_VALUE(size, bytes) size, bytes
Expand Down
1 change: 0 additions & 1 deletion fs/btrfs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -874,7 +874,6 @@ static noinline int prepare_one_folio(struct inode *inode, struct folio **folio_
ret = PTR_ERR(folio);
return ret;
}
folio_wait_writeback(folio);
/* Only support page sized folio yet. */
ASSERT(folio_order(folio) == 0);
ret = set_folio_extent_mapped(folio);
Expand Down
2 changes: 2 additions & 0 deletions fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -3925,6 +3925,7 @@ static int btrfs_read_locked_inode(struct inode *inode, struct btrfs_path *path)

btrfs_inode_split_flags(btrfs_inode_flags(leaf, inode_item),
&BTRFS_I(inode)->flags, &BTRFS_I(inode)->ro_flags);
btrfs_update_inode_mapping_flags(BTRFS_I(inode));

cache_index:
/*
Expand Down Expand Up @@ -6340,6 +6341,7 @@ int btrfs_create_new_inode(struct btrfs_trans_handle *trans,
if (btrfs_test_opt(fs_info, NODATACOW))
BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW |
BTRFS_INODE_NODATASUM;
btrfs_update_inode_mapping_flags(BTRFS_I(inode));
}

ret = btrfs_insert_inode_locked(inode);
Expand Down
1 change: 1 addition & 0 deletions fs/btrfs/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@ int btrfs_fileattr_set(struct mnt_idmap *idmap,

update_flags:
binode->flags = binode_flags;
btrfs_update_inode_mapping_flags(binode);
btrfs_sync_inode_flags_to_i_flags(inode);
inode_inc_iversion(inode);
inode_set_ctime_current(inode);
Expand Down

0 comments on commit ae58472

Please sign in to comment.