From: Darrick J. Wong Date: Mon, 16 Sep 2024 07:10:02 +0000 (+0200) Subject: libxfs: dirty buffers should be marked uptodate too X-Git-Tag: v6.11.0~91 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=71d2969be616e79bcfaa2d27414337afde40cdfc;p=thirdparty%2Fxfsprogs-dev.git libxfs: dirty buffers should be marked uptodate too I started fuzz-testing the realtime rmap feature with a very large number of realtime allocation groups. There were so many rt groups that repair had to rebuild /realtime in the metadata directory tree, and that directory was big enough to spur the creation of a block format directory. Unfortunately, repair then walks both directory trees to look for unconnceted files. This part of phase 6 emits CRC errors on the newly created buffers for the /realtime directory, declares the directory to be garbage, and moves all the rt rmap inodes to /lost+found, resulting in a corrupt fs. Poking around in gdb, I noticed that the buffer contents were indeed zero, and that UPTODATE was not set. This was very strange, until I added a watch on bp->b_flags to watch for accesses. It turns out that xfs_repair's prefetch code will _get a buffer and zero the contents if UPTODATE is not set. The directory tree code in libxfs will also _get a buffer, initialize it, and log it to the coordinating transaction, which in this case is the transactions used to reconnect the rmap btree inodes to /realtime. At no point does any of that code ever set UPTODATE on the buffer, which is why prefetch zaps the contents. Hence change both buffer dirtying functions to set UPTODATE, since a dirty buffer is by definition at least as recent as whatever's on disk. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- diff --git a/libxfs/rdwr.c b/libxfs/rdwr.c index 0a87e5b6..e430416f 100644 --- a/libxfs/rdwr.c +++ b/libxfs/rdwr.c @@ -902,7 +902,7 @@ libxfs_buf_mark_dirty( */ bp->b_error = 0; bp->b_flags &= ~LIBXFS_B_STALE; - bp->b_flags |= LIBXFS_B_DIRTY; + bp->b_flags |= LIBXFS_B_DIRTY | LIBXFS_B_UPTODATE; } /* Prepare a buffer to be sent to the MRU list. */ diff --git a/libxfs/trans.c b/libxfs/trans.c index 7fec2caf..7e36205c 100644 --- a/libxfs/trans.c +++ b/libxfs/trans.c @@ -687,6 +687,7 @@ libxfs_trans_dirty_buf( ASSERT(bp->b_transp == tp); ASSERT(bip != NULL); + bp->b_flags |= LIBXFS_B_UPTODATE; tp->t_flags |= XFS_TRANS_DIRTY; set_bit(XFS_LI_DIRTY, &bip->bli_item.li_flags); }