Skip to content

Commit

Permalink
xfs: ensure st_blocks never goes to zero during COW writes
Browse files Browse the repository at this point in the history
COW writes remove the amount overwritten either directly for delalloc
reservations, or in earlier deferred transactions than adding the new
amount back in the bmap map transaction.  This means st_blocks on an
inode where all data is overwritten using the COW path can temporarily
show a 0 st_blocks.  This can easily be reproduced with the pending
zoned device support where all writes use this path and trips the
check in generic/615, but could also happen on a reflink file without
that.

Fix this by temporarily add the pending blocks to be mapped to
i_delayed_blks while the item is queued.

Signed-off-by: Christoph Hellwig <[email protected]>
Reviewed-by: Darrick J. Wong <[email protected]>
Reviewed-by: Dave Chinner <[email protected]>
Signed-off-by: Chandan Babu R <[email protected]>
  • Loading branch information
Christoph Hellwig authored and Chandan Babu R committed Sep 3, 2024
1 parent 866cf1d commit 90fa22d
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 0 deletions.
1 change: 1 addition & 0 deletions fs/xfs/libxfs/xfs_bmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -4856,6 +4856,7 @@ xfs_bmapi_remap(
}

ip->i_nblocks += len;
ip->i_delayed_blks -= len; /* see xfs_bmap_defer_add */
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);

if (ifp->if_format == XFS_DINODE_FMT_BTREE)
Expand Down
17 changes: 17 additions & 0 deletions fs/xfs/xfs_bmap_item.c
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,17 @@ xfs_bmap_defer_add(
trace_xfs_bmap_defer(bi);

xfs_bmap_update_get_group(tp->t_mountp, bi);

/*
* Ensure the deferred mapping is pre-recorded in i_delayed_blks.
*
* Otherwise stat can report zero blocks for an inode that actually has
* data when the entire mapping is in the process of being overwritten
* using the out of place write path. This is undone in xfs_bmapi_remap
* after it has incremented di_nblocks for a successful operation.
*/
if (bi->bi_type == XFS_BMAP_MAP)
bi->bi_owner->i_delayed_blks += bi->bi_bmap.br_blockcount;
xfs_defer_add(tp, &bi->bi_list, &xfs_bmap_update_defer_type);
}

Expand All @@ -367,6 +378,9 @@ xfs_bmap_update_cancel_item(
{
struct xfs_bmap_intent *bi = bi_entry(item);

if (bi->bi_type == XFS_BMAP_MAP)
bi->bi_owner->i_delayed_blks -= bi->bi_bmap.br_blockcount;

xfs_bmap_update_put_group(bi);
kmem_cache_free(xfs_bmap_intent_cache, bi);
}
Expand Down Expand Up @@ -464,6 +478,9 @@ xfs_bui_recover_work(
bi->bi_owner = *ipp;
xfs_bmap_update_get_group(mp, bi);

/* see xfs_bmap_defer_add for details */
if (bi->bi_type == XFS_BMAP_MAP)
bi->bi_owner->i_delayed_blks += bi->bi_bmap.br_blockcount;
xfs_defer_add_item(dfp, &bi->bi_list);
return bi;
}
Expand Down

0 comments on commit 90fa22d

Please sign in to comment.