@@ -1535,8 +1535,8 @@ lock_and_cleanup_extent_if_need(struct btrfs_inode *inode, struct page **pages,
static int check_can_nocow(struct btrfs_inode *inode, loff_t pos,
size_t *write_bytes, bool nowait)
{
- struct btrfs_fs_info *fs_info = inode->root->fs_info;
struct btrfs_root *root = inode->root;
+ u32 blocksize = PAGE_SIZE;
u64 lockstart, lockend;
u64 num_bytes;
int ret;
@@ -1547,9 +1547,8 @@ static int check_can_nocow(struct btrfs_inode *inode, loff_t pos,
if (!nowait && !btrfs_drew_try_write_lock(&root->snapshot_lock))
return -EAGAIN;
- lockstart = round_down(pos, fs_info->sectorsize);
- lockend = round_up(pos + *write_bytes,
- fs_info->sectorsize) - 1;
+ lockstart = round_down(pos, blocksize);
+ lockend = round_up(pos + *write_bytes, blocksize) - 1;
num_bytes = lockend - lockstart + 1;
if (nowait) {
@@ -7006,6 +7006,11 @@ noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len,
int found_type;
bool nocow = (BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW);
+ /*
+ * We should only do full page write even for subpage. Thus the offset
+ * should always be page aligned.
+ */
+ ASSERT(IS_ALIGNED(offset, PAGE_SIZE));
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
@@ -7121,6 +7126,16 @@ noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len,
disk_bytenr += offset - key.offset;
if (csum_exist_in_range(fs_info, disk_bytenr, num_bytes))
goto out;
+
+ /*
+ * If the nocow range is smaller than one page, it doesn't make any
+ * sense for subpage case, as we can only submit full page write yet.
+ */
+ if (num_bytes < PAGE_SIZE) {
+ ret = 0;
+ goto out;
+ }
+
/*
* all of the above have passed, it is safe to overwrite this extent
* without cow
For subpage, we can still get sector aligned extent mapper, thus it could lead to the following case: 0 16K 32K 48K 64K |///////| | | \- Hole \- NODATACOW extent If we want to dirty page range [0, 64K) for new write, and we need to check the nocow status, can_nocow_extent() would return 1, with length 16K. But for current subpage data write support, we can only write a full page, but the range [16K, 64K) is hole where writes must be COWed. To solve the problem, just make can_nocow_extent() do extra returned length check. If the result is smaller than one page, we return 0. This behavior change won't affect regular sector size support since in that case num_bytes should already be page aligned. Also modify the callers to always pass page aligned offset for subpage support. Signed-off-by: Qu Wenruo <wqu@suse.com> --- fs/btrfs/file.c | 7 +++---- fs/btrfs/inode.c | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 4 deletions(-)