@@ -184,7 +184,7 @@ xfs_perag_resv(
extern xfs_mount_t *libxfs_mount (xfs_mount_t *, xfs_sb_t *,
dev_t, dev_t, dev_t, int);
-extern void libxfs_umount (xfs_mount_t *);
+int libxfs_umount(struct xfs_mount *mp);
extern void libxfs_rtmount_destroy (xfs_mount_t *);
#endif /* __XFS_MOUNT_H__ */
@@ -581,6 +581,8 @@ libxfs_buftarg_alloc(
}
btp->bt_mount = mp;
btp->dev = dev;
+ btp->flags = 0;
+
return btp;
}
@@ -803,17 +805,104 @@ libxfs_rtmount_destroy(xfs_mount_t *mp)
mp->m_rsumip = mp->m_rbmip = NULL;
}
+/* Flush a device and report on writes that didn't make it to stable storage. */
+static inline int
+libxfs_flush_buftarg(
+ struct xfs_buftarg *btp,
+ const char *buftarg_descr)
+{
+ int error = 0;
+ int err2;
+
+ /*
+ * Write verifier failures are evidence of a buggy program. Make sure
+ * that this state is always reported to the caller.
+ */
+ if (btp->flags & XFS_BUFTARG_CORRUPT_WRITE) {
+ fprintf(stderr,
+_("%s: Refusing to write a corrupt buffer to the %s!\n"),
+ progname, buftarg_descr);
+ error = -EFSCORRUPTED;
+ }
+
+ if (btp->flags & XFS_BUFTARG_LOST_WRITE) {
+ fprintf(stderr,
+_("%s: Lost a write to the %s!\n"),
+ progname, buftarg_descr);
+ if (!error)
+ error = -EIO;
+ }
+
+ err2 = libxfs_blkdev_issue_flush(btp);
+ if (err2) {
+ fprintf(stderr,
+_("%s: Flushing the %s failed, err=%d!\n"),
+ progname, buftarg_descr, -err2);
+ }
+ if (!error)
+ error = err2;
+
+ return error;
+}
+
+/*
+ * Flush all dirty buffers to stable storage and report on writes that didn't
+ * make it to stable storage.
+ */
+static int
+libxfs_flush_mount(
+ struct xfs_mount *mp)
+{
+ int error = 0;
+ 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.
+ */
+ libxfs_bcache_purge();
+
+ /* Flush all kernel and disk write caches, and report failures. */
+ if (mp->m_ddev_targp) {
+ err2 = libxfs_flush_buftarg(mp->m_ddev_targp, _("data device"));
+ if (!error)
+ error = err2;
+ }
+
+ if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp) {
+ err2 = libxfs_flush_buftarg(mp->m_logdev_targp,
+ _("log device"));
+ if (!error)
+ error = err2;
+ }
+
+ if (mp->m_rtdev_targp) {
+ err2 = libxfs_flush_buftarg(mp->m_rtdev_targp,
+ _("realtime device"));
+ if (!error)
+ error = err2;
+ }
+
+ return error;
+}
+
/*
* Release any resource obtained during a mount.
*/
-void
-libxfs_umount(xfs_mount_t *mp)
+int
+libxfs_umount(
+ struct xfs_mount *mp)
{
struct xfs_perag *pag;
int agno;
+ int error;
libxfs_rtmount_destroy(mp);
- libxfs_bcache_purge();
+
+ error = libxfs_flush_mount(mp);
for (agno = 0; agno < mp->m_maxagi; agno++) {
pag = radix_tree_delete(&mp->m_perag_tree, agno);
@@ -828,6 +917,7 @@ libxfs_umount(xfs_mount_t *mp)
kmem_free(mp->m_logdev_targp);
kmem_free(mp->m_ddev_targp);
+ return error;
}
/*
@@ -23,10 +23,17 @@ struct xfs_perag;
struct xfs_buftarg {
struct xfs_mount *bt_mount;
dev_t dev;
+ unsigned int flags;
};
+/* We purged a dirty buffer and lost a write. */
+#define XFS_BUFTARG_LOST_WRITE (1 << 0)
+/* A dirty buffer failed the write verifier. */
+#define XFS_BUFTARG_CORRUPT_WRITE (1 << 1)
+
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)
@@ -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 */
@@ -1226,6 +1227,19 @@ libxfs_iomove(xfs_buf_t *bp, uint boff, int len, void *data, int flags)
}
}
+/* Complain about (and remember) dropping dirty buffers. */
+static void
+libxfs_whine_dirty_buf(
+ struct xfs_buf *bp)
+{
+ fprintf(stderr, _("%s: Releasing dirty buffer to free list!\n"),
+ progname);
+
+ if (bp->b_error == -EFSCORRUPTED)
+ bp->b_target->flags |= XFS_BUFTARG_CORRUPT_WRITE;
+ bp->b_target->flags |= XFS_BUFTARG_LOST_WRITE;
+}
+
static void
libxfs_brelse(
struct cache_node *node)
@@ -1235,8 +1249,7 @@ libxfs_brelse(
if (!bp)
return;
if (bp->b_flags & LIBXFS_B_DIRTY)
- fprintf(stderr,
- "releasing dirty buffer to free list!\n");
+ libxfs_whine_dirty_buf(bp);
pthread_mutex_lock(&xfs_buf_freelist.cm_mutex);
list_add(&bp->b_node.cn_mru, &xfs_buf_freelist.cm_list);
@@ -1256,8 +1269,7 @@ libxfs_bulkrelse(
list_for_each_entry(bp, list, b_node.cn_mru) {
if (bp->b_flags & LIBXFS_B_DIRTY)
- fprintf(stderr,
- "releasing dirty buffer (bulk) to free list!\n");
+ libxfs_whine_dirty_buf(bp);
count++;
}
@@ -1486,6 +1498,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.
*