From: Darrick J. Wong <djwong@xxxxxxxxxx> 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 <djwong@xxxxxxxxxx> --- libxfs/rdwr.c | 2 +- libxfs/trans.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libxfs/rdwr.c b/libxfs/rdwr.c index 17abced06c9..a3b30510926 100644 --- a/libxfs/rdwr.c +++ b/libxfs/rdwr.c @@ -959,7 +959,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 aab9923d9ad..3c5d6383e8c 100644 --- a/libxfs/trans.c +++ b/libxfs/trans.c @@ -716,6 +716,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); }