---
include/xfs_mount.h | 1 +
libxfs/init.c | 20 +++++++++++++-------
repair/agheader.c | 21 +++++++++++++++++++++
repair/xfs_repair.c | 42 ++++++++++++++++++++++++++++++++++++++++++
4 files changed, 77 insertions(+), 7 deletions(-)
diff --git a/include/xfs_mount.h b/include/xfs_mount.h
index 36594643..75230ca5 100644
--- a/include/xfs_mount.h
+++ b/include/xfs_mount.h
@@ -181,6 +181,7 @@ xfs_perag_resv(
extern xfs_mount_t *libxfs_mount (xfs_mount_t *, xfs_sb_t *,
dev_t, dev_t, dev_t, int);
+int libxfs_flush_mount(struct xfs_mount *mp);
int libxfs_umount(struct xfs_mount *mp);
extern void libxfs_rtmount_destroy (xfs_mount_t *);
diff --git a/libxfs/init.c b/libxfs/init.c
index 9fe13b8d..8a8ce3c4 100644
--- a/libxfs/init.c
+++ b/libxfs/init.c
@@ -870,7 +870,7 @@ _("%s: Flushing the %s failed, err=%d!\n"),
* Flush all dirty buffers to stable storage and report on writes that didn't
* make it to stable storage.
*/
-static int
+int
libxfs_flush_mount(
struct xfs_mount *mp)
{
@@ -878,13 +878,13 @@ libxfs_flush_mount(
int err2;
/*
- * Purge the buffer cache to write all dirty buffers to disk and free
- * all incore buffers. Buffers that fail write verification will cause
- * the CORRUPT_WRITE flag to be set in the buftarg. Buffers that
- * cannot be written will cause the LOST_WRITE flag to be set in the
- * buftarg.
+ * Flush the buffer cache to write all dirty buffers to disk. Buffers
+ * that fail write verification will cause the CORRUPT_WRITE flag to be
+ * set in the buftarg. Buffers that cannot be written will cause the
+ * LOST_WRITE flag to be set in the buftarg. Once that's done,
+ * instruct the disks to persist their write caches.
*/
- libxfs_bcache_purge();
+ libxfs_bcache_flush();
/* Flush all kernel and disk write caches, and report failures. */
if (mp->m_ddev_targp) {
@@ -923,6 +923,12 @@ libxfs_umount(
libxfs_rtmount_destroy(mp);
+ /*
+ * Purge the buffer cache to write all dirty buffers to disk and free
+ * all incore buffers, then pick up the outcome when we tell the disks
+ * to persist their write caches.
+ */
+ libxfs_bcache_purge();
error = libxfs_flush_mount(mp);
for (agno = 0; agno < mp->m_maxagi; agno++) {
diff --git a/repair/agheader.c b/repair/agheader.c
index 8bb99489..2af24106 100644
--- a/repair/agheader.c
+++ b/repair/agheader.c
@@ -452,6 +452,27 @@ secondary_sb_whack(
rval |= XR_AG_SB_SEC;
}
+ if (xfs_sb_version_needsrepair(sb)) {
+ if (i == 0) {
+ if (!no_modify)
+ do_warn(
+ _("clearing needsrepair flag and regenerating metadata\n"));
+ else
+ do_warn(
+ _("would clear needsrepair flag and regenerate metadata\n"));
+ } else {
+ /*
+ * Quietly clear needsrepair on the secondary supers as
+ * part of ensuring them. If needsrepair is set on the
+ * primary, it will be cleared at the end of repair
+ * once we've flushed all other dirty blocks to disk.
+ */
+ sb->sb_features_incompat &=
+ ~XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR;
+ rval |= XR_AG_SB_SEC;
+ }
+ }
+
return(rval);
}
diff --git a/repair/xfs_repair.c b/repair/xfs_repair.c
index 40352458..e2e99b21 100644
--- a/repair/xfs_repair.c
+++ b/repair/xfs_repair.c
@@ -712,6 +712,45 @@ check_fs_vs_host_sectsize(
}
}
+/* Clear needsrepair after a successful repair run. */
+void
+clear_needsrepair(
+ struct xfs_mount *mp)
+{
+ struct xfs_buf *bp;
+ int error;
+
+ /*
+ * If we're going to clear NEEDSREPAIR, we need to make absolutely sure
+ * that everything is ok with the ondisk filesystem. Make sure any
+ * dirty buffers are sent to disk and that the disks have persisted
+ * writes to stable storage. If that fails, leave NEEDSREPAIR in
+ * place.
+ */
+ error = -libxfs_flush_mount(mp);
+ if (error) {
+ do_warn(
+ _("Cannot clear needsrepair due to flush failure, err=%d.\n"),
+ error);
+ return;
+ }
+
+ /* Clear needsrepair from the superblock. */
+ bp = libxfs_getsb(mp);
+ if (!bp || bp->b_error) {
+ do_warn(
+ _("Cannot clear needsrepair from primary super, err=%d.\n"),
+ bp ? bp->b_error : ENOMEM);
+ } else {
+ mp->m_sb.sb_features_incompat &=
+ ~XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR;
+ libxfs_sb_to_disk(bp->b_addr, &mp->m_sb);
+ libxfs_buf_mark_dirty(bp);
+ }
+ if (bp)
+ libxfs_buf_relse(bp);
+}
+
int
main(int argc, char **argv)
{
@@ -1128,6 +1167,9 @@ _("Note - stripe unit (%d) and width (%d) were copied from a backup superblock.\
libxfs_bcache_flush();
format_log_max_lsn(mp);
+ if (xfs_sb_version_needsrepair(&mp->m_sb))
+ clear_needsrepair(mp);
+
/* Report failure if anything failed to get written to our fs. */
error = -libxfs_umount(mp);
if (error)