From: Darrick J. Wong <djwong@xxxxxxxxxx> Support restoring log data to an external log device, if the dumped filesystem had one. Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> --- man/man8/xfs_mdrestore.8 | 8 ++ mdrestore/xfs_mdrestore.c | 176 +++++++++++++++++++++++++++++++-------------- 2 files changed, 131 insertions(+), 53 deletions(-) diff --git a/man/man8/xfs_mdrestore.8 b/man/man8/xfs_mdrestore.8 index 72f3b297787..4626b98e749 100644 --- a/man/man8/xfs_mdrestore.8 +++ b/man/man8/xfs_mdrestore.8 @@ -5,12 +5,17 @@ xfs_mdrestore \- restores an XFS metadump image to a filesystem image .B xfs_mdrestore [ .B \-gi +] [ +.B \-l logdev ] .I source .I target .br .B xfs_mdrestore .B \-i +[ +.B \-l logdev +] .I source .br .B xfs_mdrestore \-V @@ -43,6 +48,9 @@ can be destroyed. .B \-g Shows restore progress on stdout. .TP +.B \-l +Restore log contents to this external log device. +.TP .B \-i Shows metadump information on stdout. If no .I target diff --git a/mdrestore/xfs_mdrestore.c b/mdrestore/xfs_mdrestore.c index 9f8cbe98cd6..4318fac9008 100644 --- a/mdrestore/xfs_mdrestore.c +++ b/mdrestore/xfs_mdrestore.c @@ -38,6 +38,67 @@ print_progress(const char *fmt, ...) progress_since_warning = 1; } +extern int platform_check_ismounted(char *, char *, struct stat *, int); + +static int +open_device( + char *path, + int *is_target_file) +{ + struct stat statbuf; + int open_flags = O_RDWR; + int dst_fd; + + *is_target_file = 0; + if (stat(path, &statbuf) < 0) { + /* ok, assume it's a file and create it */ + open_flags |= O_CREAT; + *is_target_file = 1; + } else if (S_ISREG(statbuf.st_mode)) { + open_flags |= O_TRUNC; + *is_target_file = 1; + } else { + /* + * check to make sure a filesystem isn't mounted on the device + */ + if (platform_check_ismounted(path, NULL, &statbuf, 0)) + fatal("a filesystem is mounted on target device \"%s\"," + " cannot restore to a mounted filesystem.\n", + path); + } + + dst_fd = open(path, open_flags, 0644); + if (dst_fd < 0) + fatal("couldn't open target \"%s\"\n", path); + + return dst_fd; +} + +static void +check_dev( + int dst_fd, + int is_target_file, + unsigned long long bytes) +{ + if (is_target_file) { + /* ensure regular files are correctly sized */ + + if (ftruncate(dst_fd, bytes)) + fatal("cannot set filesystem image size: %s\n", + strerror(errno)); + } else { + /* ensure device is sufficiently large enough */ + + char *lb[XFS_MAX_SECTORSIZE] = { NULL }; + off64_t off; + + off = bytes - sizeof(lb); + if (pwrite(dst_fd, lb, sizeof(lb), off) < 0) + fatal("failed to write last block, is target too " + "small? (error: %s)\n", strerror(errno)); + } +} + /* * perform_restore() -- do the actual work to restore the metadump * @@ -53,7 +114,8 @@ perform_restore( FILE *src_f, int dst_fd, int is_target_file, - const struct xfs_metablock *mbp) + const struct xfs_metablock *mbp, + char *log_path) { struct xfs_metablock *metablock; /* header + index + blocks */ __be64 *block_index; @@ -64,6 +126,10 @@ perform_restore( int mb_count; xfs_sb_t sb; int64_t bytes_read; + int log_fd = -1; + bool is_mdx; + + is_mdx = mbp->mb_magic == cpu_to_be32(XFS_MDX_MAGIC); block_size = 1 << mbp->mb_blocklog; max_indices = (block_size - sizeof(xfs_metablock_t)) / sizeof(__be64); @@ -76,6 +142,7 @@ perform_restore( if (mb_count == 0 || mb_count > max_indices) fatal("bad block count: %u\n", mb_count); + memcpy(metablock, mbp, sizeof(struct xfs_metablock)); block_index = (__be64 *)((char *)metablock + sizeof(xfs_metablock_t)); block_buffer = (char *)metablock + block_size; @@ -106,32 +173,43 @@ perform_restore( ((struct xfs_dsb*)block_buffer)->sb_inprogress = 1; - if (is_target_file) { - /* ensure regular files are correctly sized */ - - if (ftruncate(dst_fd, sb.sb_dblocks * sb.sb_blocksize)) - fatal("cannot set filesystem image size: %s\n", - strerror(errno)); - } else { - /* ensure device is sufficiently large enough */ - - char *lb[XFS_MAX_SECTORSIZE] = { NULL }; - off64_t off; - - off = sb.sb_dblocks * sb.sb_blocksize - sizeof(lb); - if (pwrite(dst_fd, lb, sizeof(lb), off) < 0) - fatal("failed to write last block, is target too " - "small? (error: %s)\n", strerror(errno)); - } + check_dev(dst_fd, is_target_file, sb.sb_dblocks * sb.sb_blocksize); bytes_read = 0; for (;;) { + int write_fd = dst_fd; + + if (metablock->mb_magic != mbp->mb_magic) + fatal("magic value 0x%x wrong, expected 0x%x\n", + metablock->mb_magic, mbp->mb_magic); + + if (metablock->mb_info & XFS_METADUMP_LOGDEV) { + int log_is_file; + + if (!is_mdx) + fatal("logdev set on an old style metadump?\n"); + if (log_fd == -1) { + if (!log_path) + fatal( + "metadump has log contents but -l was not specified?\n"); + log_fd = open_device(log_path, &log_is_file); + check_dev(log_fd, log_is_file, + sb.sb_logblocks * sb.sb_blocksize); + } + write_fd = log_fd; + } + if (metablock->mb_info & XFS_METADUMP_RTDEV) { + if (!is_mdx) + fatal("rtdev set on an old style metadump?\n"); + fatal("rtdev not supported\n"); + } + if (show_progress && (bytes_read & ((1 << 20) - 1)) == 0) print_progress("%lld MB read", bytes_read >> 20); for (cur_index = 0; cur_index < mb_count; cur_index++) { - if (pwrite(dst_fd, &block_buffer[cur_index << + if (pwrite(write_fd, &block_buffer[cur_index << mbp->mb_blocklog], block_size, be64_to_cpu(block_index[cur_index]) << BBSHIFT) < 0) @@ -139,11 +217,20 @@ perform_restore( be64_to_cpu(block_index[cur_index]) << BBSHIFT, strerror(errno)); } - if (mb_count < max_indices) - break; + if (is_mdx) { + size_t nr = fread(metablock, block_size, 1, src_f); - if (fread(metablock, block_size, 1, src_f) != 1) - fatal("error reading from metadump file\n"); + if (nr == 0) + break; + if (nr != 1) + fatal("error reading from extended metadump file\n"); + } else { + if (mb_count < max_indices) + break; + + if (fread(metablock, block_size, 1, src_f) != 1) + fatal("error reading from metadump file\n"); + } mb_count = be16_to_cpu(metablock->mb_count); if (mb_count == 0) @@ -170,38 +257,41 @@ perform_restore( if (pwrite(dst_fd, block_buffer, sb.sb_sectsize, 0) < 0) fatal("error writing primary superblock: %s\n", strerror(errno)); + if (log_fd >= 0) + close(log_fd); + free(metablock); } static void usage(void) { - fprintf(stderr, "Usage: %s [-V] [-g] [-i] source target\n", progname); + fprintf(stderr, "Usage: %s [-V] [-g] [-i] [-l logdev] source target\n", progname); exit(1); } -extern int platform_check_ismounted(char *, char *, struct stat *, int); - int main( int argc, char **argv) { + char *log_path = NULL; FILE *src_f; int dst_fd; int c; - int open_flags; - struct stat statbuf; int is_target_file; struct xfs_metablock mb; progname = basename(argv[0]); - while ((c = getopt(argc, argv, "giV")) != EOF) { + while ((c = getopt(argc, argv, "gl:iV")) != EOF) { switch (c) { case 'g': show_progress = 1; break; + case 'l': + log_path = optarg; + break; case 'i': show_info = 1; break; @@ -238,7 +328,8 @@ main( if (fread(&mb, sizeof(mb), 1, src_f) != 1) fatal("error reading from metadump file\n"); - if (mb.mb_magic != cpu_to_be32(XFS_MD_MAGIC)) + if (mb.mb_magic != cpu_to_be32(XFS_MD_MAGIC) && + mb.mb_magic != cpu_to_be32(XFS_MDX_MAGIC)) fatal("specified file is not a metadata dump\n"); if (show_info) { @@ -260,30 +351,9 @@ main( optind++; /* check and open target */ - open_flags = O_RDWR; - is_target_file = 0; - if (stat(argv[optind], &statbuf) < 0) { - /* ok, assume it's a file and create it */ - open_flags |= O_CREAT; - is_target_file = 1; - } else if (S_ISREG(statbuf.st_mode)) { - open_flags |= O_TRUNC; - is_target_file = 1; - } else { - /* - * check to make sure a filesystem isn't mounted on the device - */ - if (platform_check_ismounted(argv[optind], NULL, &statbuf, 0)) - fatal("a filesystem is mounted on target device \"%s\"," - " cannot restore to a mounted filesystem.\n", - argv[optind]); - } + dst_fd = open_device(argv[optind], &is_target_file); - dst_fd = open(argv[optind], open_flags, 0644); - if (dst_fd < 0) - fatal("couldn't open target \"%s\"\n", argv[optind]); - - perform_restore(src_f, dst_fd, is_target_file, &mb); + perform_restore(src_f, dst_fd, is_target_file, &mb, log_path); close(dst_fd); if (src_f != stdin)