Commit ecde48a1 authored by Qu Wenruo's avatar Qu Wenruo Committed by David Sterba
Browse files

btrfs: expose per-inode stable writes flag



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: default avatarQu Wenruo <wqu@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent aa60fe12
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -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
+0 −1
Original line number Diff line number Diff line
@@ -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);
+2 −0
Original line number Diff line number Diff line
@@ -3924,6 +3924,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:
	/*
@@ -6339,6 +6340,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);
+1 −0
Original line number Diff line number Diff line
@@ -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);