Re: [PATCH 4/4] misc: make all tools check that metadata updates have been committed

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 





On 2/4/20 5:47 PM, Darrick J. Wong wrote:
From: Darrick J. Wong <darrick.wong@xxxxxxxxxx>

Add a new function that will ensure that everything we changed has
landed on stable media, and report the results.  Teach the individual
programs to report when things go wrong.

Signed-off-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx>
Ok, looks functionally sane to me:
Reviewed-by: Allison Collins <allison.henderson@xxxxxxxxxx>

---
  db/init.c           |   14 ++++++++++++++
  include/xfs_mount.h |    3 +++
  libxfs/init.c       |   43 +++++++++++++++++++++++++++++++++++++++++++
  libxfs/libxfs_io.h  |    2 ++
  libxfs/rdwr.c       |   27 +++++++++++++++++++++++++--
  mkfs/xfs_mkfs.c     |   15 +++++++++++++++
  repair/xfs_repair.c |   35 +++++++++++++++++++++++++++++++++++
  7 files changed, 137 insertions(+), 2 deletions(-)


diff --git a/db/init.c b/db/init.c
index 0ac37368..e92de232 100644
--- a/db/init.c
+++ b/db/init.c
@@ -184,6 +184,7 @@ main(
  	char	*input;
  	char	**v;
  	int	start_iocur_sp;
+	int	d, l, r;
init(argc, argv);
  	start_iocur_sp = iocur_sp;
@@ -216,6 +217,19 @@ main(
  	 */
  	while (iocur_sp > start_iocur_sp)
  		pop_cur();
+
+	libxfs_flush_devices(mp, &d, &l, &r);
+	if (d)
+		fprintf(stderr, _("%s: cannot flush data device (%d).\n"),
+				progname, d);
+	if (l)
+		fprintf(stderr, _("%s: cannot flush log device (%d).\n"),
+				progname, l);
+	if (r)
+		fprintf(stderr, _("%s: cannot flush realtime device (%d).\n"),
+				progname, r);
+
+
  	libxfs_umount(mp);
  	if (x.ddev)
  		libxfs_device_close(x.ddev);
diff --git a/include/xfs_mount.h b/include/xfs_mount.h
index 29b3cc1b..c80aaf69 100644
--- a/include/xfs_mount.h
+++ b/include/xfs_mount.h
@@ -187,4 +187,7 @@ extern xfs_mount_t	*libxfs_mount (xfs_mount_t *, xfs_sb_t *,
  extern void	libxfs_umount (xfs_mount_t *);
  extern void	libxfs_rtmount_destroy (xfs_mount_t *);
+void libxfs_flush_devices(struct xfs_mount *mp, int *datadev, int *logdev,
+		int *rtdev);
+
  #endif	/* __XFS_MOUNT_H__ */
diff --git a/libxfs/init.c b/libxfs/init.c
index a0d4b7f4..d1d3f4df 100644
--- a/libxfs/init.c
+++ b/libxfs/init.c
@@ -569,6 +569,8 @@ libxfs_buftarg_alloc(
  	}
  	btp->bt_mount = mp;
  	btp->dev = dev;
+	btp->lost_writes = false;
+
  	return btp;
  }
@@ -791,6 +793,47 @@ libxfs_rtmount_destroy(xfs_mount_t *mp)
  	mp->m_rsumip = mp->m_rbmip = NULL;
  }
+static inline int
+libxfs_flush_buftarg(
+	struct xfs_buftarg	*btp)
+{
+	if (btp->lost_writes)
+		return -ENOTRECOVERABLE;
+
+	return libxfs_blkdev_issue_flush(btp);
+}
+
+/*
+ * Purge the buffer cache to write all dirty buffers to disk and free all
+ * incore buffers.  Buffers that cannot be written will cause the lost_writes
+ * flag to be set in the buftarg.  If there were no lost writes, flush the
+ * device to make sure the writes made it to stable storage.
+ *
+ * For each device, the return code will be set to -ENOTRECOVERABLE if we
+ * couldn't write something to disk; or the results of the block device flush
+ * operation.
+ */
+void
+libxfs_flush_devices(
+	struct xfs_mount	*mp,
+	int			*datadev,
+	int			*logdev,
+	int			*rtdev)
+{
+	*datadev = *logdev = *rtdev = 0;
+
+	libxfs_bcache_purge();
+
+	if (mp->m_ddev_targp)
+		*datadev = libxfs_flush_buftarg(mp->m_ddev_targp);
+
+	if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp)
+		*logdev = libxfs_flush_buftarg(mp->m_logdev_targp);
+
+	if (mp->m_rtdev_targp)
+		*rtdev = libxfs_flush_buftarg(mp->m_rtdev_targp);
+}
+
  /*
   * Release any resource obtained during a mount.
   */
diff --git a/libxfs/libxfs_io.h b/libxfs/libxfs_io.h
index 579df52b..fc0fd060 100644
--- a/libxfs/libxfs_io.h
+++ b/libxfs/libxfs_io.h
@@ -23,10 +23,12 @@ struct xfs_perag;
  struct xfs_buftarg {
  	struct xfs_mount	*bt_mount;
  	dev_t			dev;
+	bool			lost_writes;
  };
extern void libxfs_buftarg_init(struct xfs_mount *mp, dev_t ddev,
  				    dev_t logdev, dev_t rtdev);
+int libxfs_blkdev_issue_flush(struct xfs_buftarg *btp);
#define LIBXFS_BBTOOFF64(bbs) (((xfs_off_t)(bbs)) << BBSHIFT) diff --git a/libxfs/rdwr.c b/libxfs/rdwr.c
index 8b47d438..92e497f9 100644
--- a/libxfs/rdwr.c
+++ b/libxfs/rdwr.c
@@ -17,6 +17,7 @@
  #include "xfs_inode_fork.h"
  #include "xfs_inode.h"
  #include "xfs_trans.h"
+#include "libfrog/platform.h"
#include "libxfs.h" /* for LIBXFS_EXIT_ON_FAILURE */ @@ -1227,9 +1228,11 @@ libxfs_brelse( if (!bp)
  		return;
-	if (bp->b_flags & LIBXFS_B_DIRTY)
+	if (bp->b_flags & LIBXFS_B_DIRTY) {
  		fprintf(stderr,
  			"releasing dirty buffer to free list!\n");
+		bp->b_target->lost_writes = true;
+	}
pthread_mutex_lock(&xfs_buf_freelist.cm_mutex);
  	list_add(&bp->b_node.cn_mru, &xfs_buf_freelist.cm_list);
@@ -1248,9 +1251,11 @@ libxfs_bulkrelse(
  		return 0 ;
list_for_each_entry(bp, list, b_node.cn_mru) {
-		if (bp->b_flags & LIBXFS_B_DIRTY)
+		if (bp->b_flags & LIBXFS_B_DIRTY) {
  			fprintf(stderr,
  				"releasing dirty buffer (bulk) to free list!\n");
+			bp->b_target->lost_writes = true;
+		}
  		count++;
  	}
@@ -1479,6 +1484,24 @@ libxfs_irele(
  	kmem_cache_free(xfs_inode_zone, ip);
  }
+/*
+ * Flush everything dirty in the kernel and disk write caches to stable media.
+ * Returns 0 for success or a negative error code.
+ */
+int
+libxfs_blkdev_issue_flush(
+	struct xfs_buftarg	*btp)
+{
+	int			fd, ret;
+
+	if (btp->dev == 0)
+		return 0;
+
+	fd = libxfs_device_to_fd(btp->dev);
+	ret = platform_flush_device(fd, btp->dev);
+	return ret ? -errno : 0;
+}
+
  /*
   * Write out a buffer list synchronously.
   *
diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 1f5d2105..6b182264 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -3644,6 +3644,7 @@ main(
  	char			*protofile = NULL;
  	char			*protostring = NULL;
  	int			worst_freelist = 0;
+	int			d, l, r;
struct libxfs_xinit xi = {
  		.isdirect = LIBXFS_DIRECT,
@@ -3940,6 +3941,20 @@ main(
  	(XFS_BUF_TO_SBP(buf))->sb_inprogress = 0;
  	libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
+ /* Make sure our new fs made it to stable storage. */
+	libxfs_flush_devices(mp, &d, &l, &r);
+	if (d)
+		fprintf(stderr, _("%s: cannot flush data device (%d).\n"),
+				progname, d);
+	if (l)
+		fprintf(stderr, _("%s: cannot flush log device (%d).\n"),
+				progname, l);
+	if (r)
+		fprintf(stderr, _("%s: cannot flush realtime device (%d).\n"),
+				progname, r);
+	if (d || l || r)
+		return 1;
+
  	libxfs_umount(mp);
  	if (xi.rtdev)
  		libxfs_device_close(xi.rtdev);
diff --git a/repair/xfs_repair.c b/repair/xfs_repair.c
index eb1ce546..c0a77cad 100644
--- a/repair/xfs_repair.c
+++ b/repair/xfs_repair.c
@@ -690,6 +690,36 @@ check_fs_vs_host_sectsize(
  	}
  }
+/* Flush the devices and complain if anything bad happened. */
+static bool
+check_write_failed(
+	struct xfs_mount	*mp)
+{
+	int			d, l, r;
+
+	libxfs_flush_devices(mp, &d, &l, &r);
+
+	if (d == -ENOTRECOVERABLE)
+		do_warn(_("Lost writes to data device, please re-run.\n"));
+	else if (d)
+		do_warn(_("Error %d flushing data device, please re-run.\n"),
+				-d);
+
+	if (l == -ENOTRECOVERABLE)
+		do_warn(_("Lost writes to log device, please re-run.\n"));
+	else if (l)
+		do_warn(_("Error %d flushing log device, please re-run.\n"),
+				-l);
+
+	if (r == -ENOTRECOVERABLE)
+		do_warn(_("Lost writes to realtime device, please re-run.\n"));
+	else if (r)
+		do_warn(_("Error %d flushing realtime device, please re-run.\n"),
+				-r);
+
+	return d || l || r;
+}
+
  int
  main(int argc, char **argv)
  {
@@ -703,6 +733,7 @@ main(int argc, char **argv)
  	struct xfs_sb	psb;
  	int		rval;
  	struct xfs_ino_geometry	*igeo;
+	bool		writes_failed;
progname = basename(argv[0]);
  	setlocale(LC_ALL, "");
@@ -1106,6 +1137,8 @@ _("Note - stripe unit (%d) and width (%d) were copied from a backup superblock.\
  	format_log_max_lsn(mp);
  	libxfs_umount(mp);
+ writes_failed = check_write_failed(mp);
+
  	if (x.rtdev)
  		libxfs_device_close(x.rtdev);
  	if (x.logdev && x.logdev != x.ddev)
@@ -1125,6 +1158,8 @@ _("Repair of readonly mount complete.  Immediate reboot encouraged.\n"));
free(msgbuf); + if (writes_failed)
+		return 1;
  	if (fs_is_dirty && report_corrected)
  		return (4);
  	return (0);




[Index of Archives]     [XFS Filesystem Development (older mail)]     [Linux Filesystem Development]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux RAID]     [Linux SCSI]


  Powered by Linux