@@ -22,6 +22,7 @@
#include "spacemap.h"
#include "vfs.h"
#include "common.h"
+#include "libfrog/bulkstat.h"
/*
* Phase 6: Verify data file integrity.
@@ -381,6 +382,24 @@ report_dirent_loss(
return error;
}
+struct ioerr_filerange {
+ uint64_t physical;
+ uint64_t length;
+};
+
+/*
+ * If reverse mapping and parent pointers are enabled, we can map media errors
+ * directly back to a filename and a file position without needing to walk the
+ * directory tree.
+ */
+static inline bool
+can_use_pptrs(
+ const struct scrub_ctx *ctx)
+{
+ return (ctx->mnt.fsgeom.flags & XFS_FSOP_GEOM_FLAGS_PARENT) &&
+ (ctx->mnt.fsgeom.flags & XFS_FSOP_GEOM_FLAGS_RMAPBT);
+}
+
/* Use a fsmap to report metadata lost to a media error. */
static int
report_ioerr_fsmap(
@@ -389,16 +408,18 @@ report_ioerr_fsmap(
void *arg)
{
const char *type;
+ struct xfs_bulkstat bs = { };
char buf[DESCR_BUFSZ];
- uint64_t err_physical = *(uint64_t *)arg;
+ struct ioerr_filerange *fr = arg;
uint64_t err_off;
+ int ret;
/* Don't care about unwritten extents. */
if (map->fmr_flags & FMR_OF_PREALLOC)
return 0;
- if (err_physical > map->fmr_physical)
- err_off = err_physical - map->fmr_physical;
+ if (fr->physical > map->fmr_physical)
+ err_off = fr->physical - map->fmr_physical;
else
err_off = 0;
@@ -421,23 +442,43 @@ report_ioerr_fsmap(
}
}
+ if (can_use_pptrs(ctx)) {
+ ret = -xfrog_bulkstat_single(&ctx->mnt, map->fmr_owner, 0, &bs);
+ if (ret)
+ str_liberror(ctx, ret,
+ _("bulkstat for media error report"));
+ }
+
/* Report extent maps */
if (map->fmr_flags & FMR_OF_EXTENT_MAP) {
bool attr = (map->fmr_flags & FMR_OF_ATTR_FORK);
scrub_render_ino_descr(ctx, buf, DESCR_BUFSZ,
- map->fmr_owner, 0, " %s",
+ map->fmr_owner, bs.bs_gen, " %s",
attr ? _("extended attribute") :
_("file data"));
str_corrupt(ctx, buf, _("media error in extent map"));
}
/*
- * XXX: If we had a getparent() call we could report IO errors
- * efficiently. Until then, we'll have to scan the dir tree
- * to find the bad file's pathname.
+ * If directory parent pointers are available, use that to find the
+ * pathname to a file, and report that path as having lost its
+ * extended attributes, or the precise offset of the lost file data.
*/
+ if (!can_use_pptrs(ctx))
+ return 0;
+ scrub_render_ino_descr(ctx, buf, DESCR_BUFSZ, map->fmr_owner,
+ bs.bs_gen, NULL);
+
+ if (map->fmr_flags & FMR_OF_ATTR_FORK) {
+ str_corrupt(ctx, buf, _("media error in extended attributes"));
+ return 0;
+ }
+
+ str_unfixable_error(ctx, buf,
+ _("media error at data offset %llu length %llu."),
+ err_off, fr->length);
return 0;
}
@@ -452,6 +493,10 @@ report_ioerr(
void *arg)
{
struct fsmap keys[2];
+ struct ioerr_filerange fr = {
+ .physical = start,
+ .length = length,
+ };
struct disk_ioerr_report *dioerr = arg;
dev_t dev;
@@ -467,7 +512,7 @@ report_ioerr(
(keys + 1)->fmr_offset = ULLONG_MAX;
(keys + 1)->fmr_flags = UINT_MAX;
return -scrub_iterate_fsmap(dioerr->ctx, keys, report_ioerr_fsmap,
- &start);
+ &fr);
}
/* Report all the media errors found on a disk. */
@@ -511,10 +556,16 @@ report_all_media_errors(
return ret;
}
- /* Scan the directory tree to get file paths. */
- ret = scan_fs_tree(ctx, report_dir_loss, report_dirent_loss, vs);
- if (ret)
- return ret;
+ /*
+ * Scan the directory tree to get file paths if we didn't already use
+ * directory parent pointers to report the loss.
+ */
+ if (!can_use_pptrs(ctx)) {
+ ret = scan_fs_tree(ctx, report_dir_loss, report_dirent_loss,
+ vs);
+ if (ret)
+ return ret;
+ }
/* Scan for unlinked files. */
return scrub_scan_all_inodes(ctx, report_inode_loss, vs);