}
-void
-set_cur(
- const typ_t *type,
- xfs_daddr_t blknum,
- int len,
- int ring_flag,
- bbmap_t *bbmap)
+static void
+__set_cur(
+ struct xfs_buftarg *btargp,
+ const typ_t *type,
+ xfs_daddr_t blknum,
+ int len,
+ int ring_flag,
+ bbmap_t *bbmap)
{
- struct xfs_buf *bp;
- xfs_ino_t dirino;
- xfs_ino_t ino;
- uint16_t mode;
+ struct xfs_buf *bp;
+ xfs_ino_t dirino;
+ xfs_ino_t ino;
+ uint16_t mode;
const struct xfs_buf_ops *ops = type ? type->bops : NULL;
int error;
if (!iocur_top->bbmap)
return;
memcpy(iocur_top->bbmap, bbmap, sizeof(struct bbmap));
- error = -libxfs_buf_read_map(mp->m_ddev_targp, bbmap->b,
+ error = -libxfs_buf_read_map(btargp, bbmap->b,
bbmap->nmaps, LIBXFS_READBUF_SALVAGE, &bp,
ops);
} else {
- error = -libxfs_buf_read(mp->m_ddev_targp, blknum, len,
+ error = -libxfs_buf_read(btargp, blknum, len,
LIBXFS_READBUF_SALVAGE, &bp, ops);
iocur_top->bbmap = NULL;
}
ring_add();
}
+void
+set_cur(
+ const typ_t *type,
+ xfs_daddr_t blknum,
+ int len,
+ int ring_flag,
+ bbmap_t *bbmap)
+{
+ __set_cur(mp->m_ddev_targp, type, blknum, len, ring_flag, bbmap);
+}
+
+void
+set_log_cur(
+ const typ_t *type,
+ xfs_daddr_t blknum,
+ int len,
+ int ring_flag,
+ bbmap_t *bbmap)
+{
+ if (mp->m_logdev_targp->bt_bdev == mp->m_ddev_targp->bt_bdev) {
+ fprintf(stderr, "no external log specified\n");
+ exitcode = 1;
+ return;
+ }
+
+ __set_cur(mp->m_logdev_targp, type, blknum, len, ring_flag, bbmap);
+}
+
+
void
set_iocur_type(
const typ_t *type)
static const cmdinfo_t metadump_cmd =
{ "metadump", NULL, metadump_f, 0, -1, 0,
- N_("[-a] [-e] [-g] [-m max_extent] [-w] [-o] filename"),
+ N_("[-a] [-e] [-g] [-m max_extent] [-w] [-o] [-v 1|2] filename"),
N_("dump metadata to a file"), metadump_help };
struct metadump_ops {
bool zero_stale_data;
bool progress_since_warning;
bool dirty_log;
+ bool external_log;
bool stdout_metadump;
xfs_ino_t cur_ino;
/* Metadump file */
" -g -- Display dump progress\n"
" -m -- Specify max extent size in blocks to copy (default = %d blocks)\n"
" -o -- Don't obfuscate names and extended attributes\n"
+" -v -- Metadump version to be used\n"
" -w -- Show warnings of bad metadata information\n"
"\n"), DEFAULT_MAX_EXT_SIZE);
}
print_progress("Copying log");
push_cur();
- set_cur(&typtab[TYP_LOG], XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart),
- mp->m_sb.sb_logblocks * blkbb, DB_RING_IGN, NULL);
+ if (metadump.external_log) {
+ ASSERT(mp->m_sb.sb_logstart == 0);
+ set_log_cur(&typtab[TYP_LOG],
+ XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart),
+ mp->m_sb.sb_logblocks * blkbb, DB_RING_IGN,
+ NULL);
+ } else {
+ ASSERT(mp->m_sb.sb_logstart != 0);
+ set_cur(&typtab[TYP_LOG],
+ XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart),
+ mp->m_sb.sb_logblocks * blkbb, DB_RING_IGN,
+ NULL);
+ }
+
if (iocur_top->data == NULL) {
pop_cur();
print_warning("cannot read log");
compat_flags |= XFS_MD2_COMPAT_FULLBLOCKS;
if (metadump.dirty_log)
compat_flags |= XFS_MD2_COMPAT_DIRTYLOG;
+ if (metadump.external_log)
+ compat_flags |= XFS_MD2_COMPAT_EXTERNALLOG;
xmh.xmh_compat_flags = cpu_to_be32(compat_flags);
int outfd = -1;
int ret;
char *p;
+ bool version_opt_set = false;
exitcode = 1;
metadump.obfuscate = true;
metadump.zero_stale_data = true;
metadump.dirty_log = false;
+ metadump.external_log = false;
if (mp->m_sb.sb_magicnum != XFS_SB_MAGIC) {
print_warning("bad superblock magic number %x, giving up",
return 0;
}
- while ((c = getopt(argc, argv, "aegm:ow")) != EOF) {
+ while ((c = getopt(argc, argv, "aegm:ov:w")) != EOF) {
switch (c) {
case 'a':
metadump.zero_stale_data = false;
case 'o':
metadump.obfuscate = false;
break;
+ case 'v':
+ metadump.version = (int)strtol(optarg, &p, 0);
+ if (*p != '\0' ||
+ (metadump.version != 1 &&
+ metadump.version != 2)) {
+ print_warning("bad metadump version: %s",
+ optarg);
+ return 0;
+ }
+ version_opt_set = true;
+ break;
case 'w':
metadump.show_warnings = true;
break;
return 0;
}
- /* If we'll copy the log, see if the log is dirty */
- if (mp->m_sb.sb_logstart) {
+ if (mp->m_logdev_targp->bt_bdev != mp->m_ddev_targp->bt_bdev)
+ metadump.external_log = true;
+
+ if (metadump.external_log && !version_opt_set)
+ metadump.version = 2;
+
+ if (metadump.version == 2 && mp->m_sb.sb_logstart == 0 &&
+ !metadump.external_log) {
+ print_warning("external log device not loaded, use -l");
+ return 1;
+ }
+
+ /*
+ * If we'll copy the log, see if the log is dirty.
+ *
+ * Metadump v1 does not support dumping the contents of an external
+ * log. Hence we skip the dirty log check.
+ */
+ if (!(metadump.version == 1 && metadump.external_log)) {
push_cur();
- set_cur(&typtab[TYP_LOG],
- XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart),
- mp->m_sb.sb_logblocks * blkbb, DB_RING_IGN, NULL);
+ if (metadump.external_log) {
+ ASSERT(mp->m_sb.sb_logstart == 0);
+ set_log_cur(&typtab[TYP_LOG],
+ XFS_FSB_TO_DADDR(mp,
+ mp->m_sb.sb_logstart),
+ mp->m_sb.sb_logblocks * blkbb,
+ DB_RING_IGN, NULL);
+ } else {
+ ASSERT(mp->m_sb.sb_logstart != 0);
+ set_cur(&typtab[TYP_LOG],
+ XFS_FSB_TO_DADDR(mp,
+ mp->m_sb.sb_logstart),
+ mp->m_sb.sb_logblocks * blkbb,
+ DB_RING_IGN, NULL);
+ }
+
if (iocur_top->data) { /* best effort */
struct xlog log;
if (!exitcode)
exitcode = !copy_sb_inodes();
- /* copy log if it's internal */
- if ((mp->m_sb.sb_logstart != 0) && !exitcode)
+ /* copy log */
+ if (!exitcode && !(metadump.version == 1 && metadump.external_log))
exitcode = !copy_log();
/* write the remaining index */