Skip to content

Commit 90fa22d

Browse files
Christoph HellwigChandan Babu R
authored andcommitted
xfs: ensure st_blocks never goes to zero during COW writes
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]>
1 parent 866cf1d commit 90fa22d

File tree

2 files changed

+18
-0
lines changed

2 files changed

+18
-0
lines changed

fs/xfs/libxfs/xfs_bmap.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4856,6 +4856,7 @@ xfs_bmapi_remap(
48564856
}
48574857

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

48614862
if (ifp->if_format == XFS_DINODE_FMT_BTREE)

fs/xfs/xfs_bmap_item.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,17 @@ xfs_bmap_defer_add(
346346
trace_xfs_bmap_defer(bi);
347347

348348
xfs_bmap_update_get_group(tp->t_mountp, bi);
349+
350+
/*
351+
* Ensure the deferred mapping is pre-recorded in i_delayed_blks.
352+
*
353+
* Otherwise stat can report zero blocks for an inode that actually has
354+
* data when the entire mapping is in the process of being overwritten
355+
* using the out of place write path. This is undone in xfs_bmapi_remap
356+
* after it has incremented di_nblocks for a successful operation.
357+
*/
358+
if (bi->bi_type == XFS_BMAP_MAP)
359+
bi->bi_owner->i_delayed_blks += bi->bi_bmap.br_blockcount;
349360
xfs_defer_add(tp, &bi->bi_list, &xfs_bmap_update_defer_type);
350361
}
351362

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

381+
if (bi->bi_type == XFS_BMAP_MAP)
382+
bi->bi_owner->i_delayed_blks -= bi->bi_bmap.br_blockcount;
383+
370384
xfs_bmap_update_put_group(bi);
371385
kmem_cache_free(xfs_bmap_intent_cache, bi);
372386
}
@@ -464,6 +478,9 @@ xfs_bui_recover_work(
464478
bi->bi_owner = *ipp;
465479
xfs_bmap_update_get_group(mp, bi);
466480

481+
/* see xfs_bmap_defer_add for details */
482+
if (bi->bi_type == XFS_BMAP_MAP)
483+
bi->bi_owner->i_delayed_blks += bi->bi_bmap.br_blockcount;
467484
xfs_defer_add_item(dfp, &bi->bi_list);
468485
return bi;
469486
}

0 commit comments

Comments
 (0)