---
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);