]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blobdiff - copy/xfs_copy.c
xfsprogs: make static things static
[thirdparty/xfsprogs-dev.git] / copy / xfs_copy.c
index f99f04b5a2eecdea2ca9ebfdfc74ea27f976e63d..64761b3a03c7881bb3cdc8801b9e1171cdddd008 100644 (file)
@@ -1,81 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.  Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
  */
 
-#include <xfs/libxfs.h>
+#include "libxfs.h"
 #include <sys/stat.h>
 #include <sys/wait.h>
 #include <pthread.h>
 #include <signal.h>
 #include <stdarg.h>
 #include "xfs_copy.h"
+#include "libxlog.h"
 
 #define        rounddown(x, y) (((x)/(y))*(y))
+#define uuid_equal(s,d) (platform_uuid_compare((s),(d)) == 0)
 
-extern int     platform_check_ismounted(char *, char *, struct stat64 *, int);
+extern int     platform_check_ismounted(char *, char *, struct stat *, int);
 
-int            logfd;
-char           *logfile_name;
-FILE           *logerr;
-char           LOGFILE_NAME[] = "/var/tmp/xfs_copy.log.XXXXXX";
+static char            *logfile_name;
+static FILE            *logerr;
+static char            LOGFILE_NAME[] = "/var/tmp/xfs_copy.log.XXXXXX";
 
-char           *source_name;
-int            source_fd;
+static char            *source_name;
+static int             source_fd;
 
-unsigned int   source_blocksize;       /* source filesystem blocksize */
-unsigned int   source_sectorsize;      /* source disk sectorsize */
+static unsigned int    source_blocksize;       /* source filesystem blocksize */
+static unsigned int    source_sectorsize;      /* source disk sectorsize */
 
-xfs_agblock_t  first_agbno;
+static xfs_agblock_t   first_agbno;
 
-__uint64_t     barcount[11];
+static uint64_t        barcount[11];
 
-unsigned int   num_targets;
-target_control *target;
+static unsigned int    num_targets;
+static target_control  *target;
 
-wbuf           w_buf;
-wbuf           btree_buf;
+static wbuf            w_buf;
+static wbuf            btree_buf;
 
-pid_t          parent_pid;
-unsigned int   kids;
+static unsigned int    kids;
 
-thread_control glob_masks;
-thread_args    *targ;
+static thread_control  glob_masks;
+static thread_args     *targ;
 
-pthread_mutex_t        mainwait;
+static pthread_mutex_t mainwait;
 
 #define ACTIVE         1
 #define INACTIVE       2
 
-xfs_off_t write_log_trailer(int fd, wbuf *w, xfs_mount_t *mp);
-xfs_off_t write_log_header(int fd, wbuf *w, xfs_mount_t *mp);
+xfs_off_t      write_log_trailer(int fd, wbuf *w, xfs_mount_t *mp);
+xfs_off_t      write_log_header(int fd, wbuf *w, xfs_mount_t *mp);
+static int     format_logs(struct xfs_mount *);
 
 /* general purpose message reporting routine */
 
@@ -85,23 +60,39 @@ xfs_off_t write_log_header(int fd, wbuf *w, xfs_mount_t *mp);
 #define PRE    0x08            /* append strerror string */
 #define LAST   0x10            /* final message we print */
 
-void
+static void
+signal_maskfunc(int addset, int newset)
+{
+       sigset_t set;
+
+       sigemptyset(&set);
+       sigaddset(&set, addset);
+       sigprocmask(newset, &set, NULL);
+}
+
+static void
 do_message(int flags, int code, const char *fmt, ...)
 {
        va_list ap;
        int     eek = 0;
 
-       va_start(ap, fmt);
-       if (flags & LOG)
+       if (flags & LOG) {
+               va_start(ap, fmt);
                if (vfprintf(logerr, fmt, ap) <= 0)
                        eek = 1;
+               va_end(ap);
+       }
        if (eek)
                flags |= ERR;   /* failed, force stderr */
-       if (flags & ERR)
+       if (flags & ERR) {
+               va_start(ap, fmt);
                vfprintf(stderr, fmt, ap);
-       else if (flags & OUT)
+               va_end(ap);
+       } else if (flags & OUT) {
+               va_start(ap, fmt);
                vfprintf(stdout, fmt, ap);
-       va_end(ap);
+               va_end(ap);
+       }
 
        if (flags & PRE) {
                do_message(flags & ~PRE, 0, ":  %s\n", strerror(code));
@@ -135,7 +126,13 @@ do_message(int flags, int code, const char *fmt, ...)
                        exit(1); \
                } while (0)
 
-void
+/* workaround craziness in the xlog routines */
+int xlog_recover_do_trans(struct xlog *log, struct xlog_recover *t, int p)
+{
+       return 0;
+}
+
+static void
 check_errors(void)
 {
        int     i, first_error = 0;
@@ -151,7 +148,7 @@ check_errors(void)
                        if (target[i].err_type == 0)
                                do_log(_("write error"));
                        else
-                               do_log(_("lseek64 error"));
+                               do_log(_("lseek error"));
                        do_log(_(" at offset %lld\n"), target[i].position);
                }
        }
@@ -169,21 +166,27 @@ check_errors(void)
  * don't have to worry about alignment and mins because those
  * are taken care of when the buffer's read in
  */
-int
-do_write(thread_args *args)
+static int
+do_write(
+       thread_args     *args,
+       wbuf            *buf)
 {
-       int     res, error = 0;
+       int             res;
+       int             error = 0;
+
+       if (!buf)
+               buf = &w_buf;
 
-       if (target[args->id].position != w_buf.position)  {
-               if (lseek64(args->fd, w_buf.position, SEEK_SET) < 0)  {
+       if (target[args->id].position != buf->position)  {
+               if (lseek(args->fd, buf->position, SEEK_SET) < 0)  {
                        error = target[args->id].err_type = 1;
                } else  {
-                       target[args->id].position = w_buf.position;
+                       target[args->id].position = buf->position;
                }
        }
 
-       if ((res = write(target[args->id].fd, w_buf.data,
-                               w_buf.length)) == w_buf.length)  {
+       if ((res = write(target[args->id].fd, buf->data,
+                               buf->length)) == buf->length)  {
                target[args->id].position += res;
        } else  {
                error = 2;
@@ -191,19 +194,19 @@ do_write(thread_args *args)
 
        if (error) {
                target[args->id].error = errno;
-               target[args->id].position = w_buf.position;
+               target[args->id].position = buf->position;
        }
        return error;
 }
 
-void *
+static void *
 begin_reader(void *arg)
 {
        thread_args     *args = arg;
 
        for (;;) {
                pthread_mutex_lock(&args->wait);
-               if (do_write(args))
+               if (do_write(args, NULL))
                        goto handle_error;
                pthread_mutex_lock(&glob_masks.mutex);
                if (--glob_masks.num_working == 0)
@@ -224,29 +227,10 @@ handle_error:
        return NULL;
 }
 
-void
-killall(void)
+static void
+handler(int sig)
 {
-       int i;
-
-       /* only the parent gets to kill things */
-
-       if (getpid() != parent_pid)
-               return;
-
-       for (i = 0; i < num_targets; i++)  {
-               if (target[i].state == ACTIVE)  {
-                       /* kill up target threads */
-                       pthread_kill(target[i].pid, SIGKILL);
-                       pthread_mutex_unlock(&targ[i].wait);
-               }
-       }
-}
-
-void
-handler()
-{
-       pid_t   pid = getpid();
+       pid_t   pid;
        int     status, i;
 
        pid = wait(&status);
@@ -265,7 +249,7 @@ handler()
                                                target[i].position);
                                } else  {
                                        do_warn(
-               _("%s:  lseek64 error on target %d \"%s\" at offset %lld\n"),
+               _("%s:  lseek error on target %d \"%s\" at offset %lld\n"),
                                                progname, i, target[i].name,
                                                target[i].position);
                                }
@@ -305,17 +289,17 @@ handler()
        signal(SIGCHLD, handler);
 }
 
-void
+static void
 usage(void)
 {
        fprintf(stderr,
-               _("Usage: %s [-bd] [-L logfile] source target [target ...]\n"),
+               _("Usage: %s [-bdV] [-L logfile] source target [target ...]\n"),
                progname);
        exit(1);
 }
 
-void
-init_bar(__uint64_t source_blocks)
+static void
+init_bar(uint64_t source_blocks)
 {
        int     i;
 
@@ -323,8 +307,8 @@ init_bar(__uint64_t source_blocks)
                barcount[i] = (source_blocks/10)*i;
 }
 
-int
-bump_bar(int tenths, __uint64_t numblocks)
+static int
+bump_bar(int tenths, uint64_t numblocks)
 {
        static char *bar[11] = {
                " 0% ",
@@ -355,19 +339,24 @@ bump_bar(int tenths, __uint64_t numblocks)
 
 static xfs_off_t source_position = -1;
 
-wbuf *
+static wbuf *
 wbuf_init(wbuf *buf, int data_size, int data_align, int min_io_size, int id)
 {
-       buf->id = id;
-       if ((buf->data = memalign(data_align, data_size)) == NULL)
-               return NULL;
+       ASSERT(data_size % BBSIZE == 0);
+       while ((buf->data = memalign(data_align, data_size)) == NULL) {
+               data_size >>= 1;
+               if (data_size < min_io_size)
+                       return NULL;
+       }
        ASSERT(min_io_size % BBSIZE == 0);
+       buf->data_align = data_align;
        buf->min_io_size = min_io_size;
-       buf->size = MAX(data_size, 2*min_io_size);
+       buf->size = data_size;
+       buf->id = id;
        return buf;
 }
 
-void
+static void
 read_wbuf(int fd, wbuf *buf, xfs_mount_t *mp)
 {
        int             res = 0;
@@ -385,9 +374,9 @@ read_wbuf(int fd, wbuf *buf, xfs_mount_t *mp)
        }
 
        if (source_position != buf->position)  {
-               lres = lseek64(fd, buf->position, SEEK_SET);
+               lres = lseek(fd, buf->position, SEEK_SET);
                if (lres < 0LL)  {
-                       do_warn(_("%s:  lseek64 failure at offset %lld\n"),
+                       do_warn(_("%s:  lseek failure at offset %lld\n"),
                                progname, source_position);
                        die_perror();
                }
@@ -404,8 +393,7 @@ read_wbuf(int fd, wbuf *buf, xfs_mount_t *mp)
        if (buf->length > buf->size)  {
                do_warn(_("assert error:  buf->length = %d, buf->size = %d\n"),
                        buf->length, buf->size);
-               killall();
-               abort();
+               exit(1);
        }
 
        if ((res = read(fd, buf->data, buf->length)) < 0)  {
@@ -423,7 +411,7 @@ read_wbuf(int fd, wbuf *buf, xfs_mount_t *mp)
        buf->length = res;
 }
 
-void
+static void
 read_ag_header(int fd, xfs_agnumber_t agno, wbuf *buf, ag_header_t *ag,
                xfs_mount_t *mp, int blocksize, int sectorsize)
 {
@@ -438,7 +426,11 @@ read_ag_header(int fd, xfs_agnumber_t agno, wbuf *buf, ag_header_t *ag,
        off = XFS_AG_DADDR(mp, agno, XFS_SB_DADDR);
        buf->position = (xfs_off_t) off * (xfs_off_t) BBSIZE;
        length = buf->length = first_agbno * blocksize;
-       
+       if (length == 0) {
+               do_log(_("ag header buffer invalid!\n"));
+               exit(1);
+       }
+
        /* handle alignment stuff */
 
        newpos = rounddown(buf->position, (xfs_off_t) buf->min_io_size);
@@ -453,24 +445,24 @@ read_ag_header(int fd, xfs_agnumber_t agno, wbuf *buf, ag_header_t *ag,
        if (buf->length % buf->min_io_size != 0)
                buf->length = roundup(buf->length, buf->min_io_size);
 
-       ASSERT(length != 0);
        read_wbuf(fd, buf, mp);
        ASSERT(buf->length >= length);
 
-       ag->xfs_sb = (xfs_sb_t *) (buf->data + diff);
-       ASSERT(INT_GET(ag->xfs_sb->sb_magicnum, ARCH_CONVERT)==XFS_SB_MAGIC);
+       ag->xfs_sb = (xfs_dsb_t *) (buf->data + diff);
+       ASSERT(be32_to_cpu(ag->xfs_sb->sb_magicnum) == XFS_SB_MAGIC);
        ag->xfs_agf = (xfs_agf_t *) (buf->data + diff + sectorsize);
-       ASSERT(INT_GET(ag->xfs_agf->agf_magicnum, ARCH_CONVERT)==XFS_AGF_MAGIC);
-       ag->xfs_agi = (xfs_agi_t *) (buf->data + diff + 2*sectorsize);
-       ASSERT(INT_GET(ag->xfs_agi->agi_magicnum, ARCH_CONVERT)==XFS_AGI_MAGIC);
-       ag->xfs_agfl = (xfs_agfl_t *) (buf->data + diff + 3*sectorsize);
+       ASSERT(be32_to_cpu(ag->xfs_agf->agf_magicnum) == XFS_AGF_MAGIC);
+       ag->xfs_agi = (xfs_agi_t *) (buf->data + diff + 2 * sectorsize);
+       ASSERT(be32_to_cpu(ag->xfs_agi->agi_magicnum) == XFS_AGI_MAGIC);
+       ag->xfs_agfl = (xfs_agfl_t *) (buf->data + diff + 3 * sectorsize);
 }
 
 
-void
+static void
 write_wbuf(void)
 {
        int             i;
+       int             badness = 0;
 
        /* verify target threads */
        for (i = 0; i < num_targets; i++)
@@ -481,24 +473,68 @@ write_wbuf(void)
        for (i = 0; i < num_targets; i++)
                if (target[i].state != INACTIVE)
                        pthread_mutex_unlock(&targ[i].wait);    /* wake up */
+               else
+                       badness++;
+
+       /*
+        * If all the targets are inactive then there won't be any io
+        * threads left to release mainwait.  We're screwed, so bail out.
+        */
+       if (badness == num_targets) {
+               check_errors();
+               exit(1);
+       }
 
-       sigrelse(SIGCHLD);
+       signal_maskfunc(SIGCHLD, SIG_UNBLOCK);
        pthread_mutex_lock(&mainwait);
-       sighold(SIGCHLD);
+       signal_maskfunc(SIGCHLD, SIG_BLOCK);
 }
 
+static void
+sb_update_uuid(
+       xfs_sb_t        *sb,            /* Original fs superblock */
+       ag_header_t     *ag_hdr,        /* AG hdr to update for this copy */
+       thread_args     *tcarg)         /* Args for this thread, with UUID */
+{
+       /*
+        * If this filesystem has CRCs, the original UUID is stamped into
+        * all metadata.  If we don't have an existing meta_uuid field in the
+        * the original filesystem and we are changing the UUID in this copy,
+        * we must copy the original sb_uuid to the sb_meta_uuid slot and set
+        * the incompat flag for the feature on this copy.
+        */
+       if (xfs_sb_version_hascrc(sb) && !xfs_sb_version_hasmetauuid(sb) &&
+           !uuid_equal(&tcarg->uuid, &sb->sb_uuid)) {
+               __be32 feat;
+
+               feat = be32_to_cpu(ag_hdr->xfs_sb->sb_features_incompat);
+               feat |= XFS_SB_FEAT_INCOMPAT_META_UUID;
+               ag_hdr->xfs_sb->sb_features_incompat = cpu_to_be32(feat);
+               platform_uuid_copy(&ag_hdr->xfs_sb->sb_meta_uuid,
+                                  &sb->sb_uuid);
+       }
+
+       /* Copy the (possibly new) fs-identifier UUID into sb_uuid */
+       platform_uuid_copy(&ag_hdr->xfs_sb->sb_uuid, &tcarg->uuid);
+
+       /* We may have changed the UUID, so update the superblock CRC */
+       if (xfs_sb_version_hascrc(sb))
+               xfs_update_cksum((char *)ag_hdr->xfs_sb, sb->sb_sectsize,
+                                                        XFS_SB_CRC_OFF);
+}
 
 int
 main(int argc, char **argv)
 {
        int             i, j;
+       int             logfd;
        int             howfar = 0;
        int             open_flags;
-       xfs_off_t       pos, end_pos;
+       xfs_off_t       pos;
        size_t          length;
-       int             c, first_residue, tmp_residue;
-       __uint64_t      size, sizeb;
-       __uint64_t      numblocks = 0;
+       int             c;
+       uint64_t        size, sizeb;
+       uint64_t        numblocks = 0;
        int             wblocks = 0;
        int             num_threads = 0;
        struct dioattr  d;
@@ -512,19 +548,20 @@ main(int argc, char **argv)
        ag_header_t     ag_hdr;
        xfs_mount_t     *mp;
        xfs_mount_t     mbuf;
+       struct xlog     xlog;
        xfs_buf_t       *sbp;
        xfs_sb_t        *sb;
        xfs_agnumber_t  num_ags, agno;
        xfs_agblock_t   bno;
        xfs_daddr_t     begin, next_begin, ag_begin, new_begin, ag_end;
-       xfs_alloc_block_t *block;
+       struct xfs_btree_block *block;
        xfs_alloc_ptr_t *ptr;
        xfs_alloc_rec_t *rec_ptr;
        extern char     *optarg;
        extern int      optind;
        libxfs_init_t   xargs;
        thread_args     *tcarg;
-       struct stat64   statbuf;
+       struct stat     statbuf;
 
        progname = basename(argv[0]);
 
@@ -593,13 +630,6 @@ main(int argc, char **argv)
                target[i].err_type = 0;
        }
 
-       parent_pid = getpid();
-
-       if (atexit(killall))  {
-               do_log(_("%s: couldn't register atexit function.\n"), progname);
-               die_perror();
-       }
-
        /* open up source -- is it a file? */
 
        open_flags = O_RDONLY;
@@ -610,7 +640,7 @@ main(int argc, char **argv)
                die_perror();
        }
 
-       if (fstat64(source_fd, &statbuf) < 0)  {
+       if (fstat(source_fd, &statbuf) < 0)  {
                do_log(_("%s:  couldn't stat source \"%s\"\n"),
                        progname, source_name);
                die_perror();
@@ -632,13 +662,13 @@ main(int argc, char **argv)
                }
 
                wbuf_align = d.d_mem;
-               wbuf_size = d.d_maxiosz;
+               wbuf_size = min(d.d_maxiosz, 1 * 1024 * 1024);
                wbuf_miniosize = d.d_miniosz;
        } else  {
                /* set arbitrary I/O params, miniosize at least 1 disk block */
 
-               wbuf_align = 4096*4;
-               wbuf_size = 1024 * 4000;
+               wbuf_align = getpagesize();
+               wbuf_size = 1 * 1024 * 1024;
                wbuf_miniosize = -1;    /* set after mounting source fs */
        }
 
@@ -661,9 +691,8 @@ main(int argc, char **argv)
        /* prepare the libxfs_init structure */
 
        memset(&xargs, 0, sizeof(xargs));
-       xargs.notvolmsg = "oh no %s";
+       xargs.isdirect = LIBXFS_DIRECT;
        xargs.isreadonly = LIBXFS_ISREADONLY;
-       xargs.notvolok = 1;
 
        if (source_is_file)  {
                xargs.dname = source_name;
@@ -677,14 +706,24 @@ main(int argc, char **argv)
                exit(1);
        }
 
-       /* prepare the mount structure */
-
-       sbp = libxfs_readbuf(xargs.ddev, XFS_SB_DADDR, 1, 0);
        memset(&mbuf, 0, sizeof(xfs_mount_t));
+
+       /* We don't yet know the sector size, so read maximal size */
+       libxfs_buftarg_init(&mbuf, xargs.ddev, xargs.logdev, xargs.rtdev);
+       sbp = libxfs_readbuf(mbuf.m_ddev_targp, XFS_SB_DADDR,
+                            1 << (XFS_MAX_SECTORSIZE_LOG - BBSHIFT), 0, NULL);
        sb = &mbuf.m_sb;
-       libxfs_xlate_sb(XFS_BUF_PTR(sbp), sb, 1, XFS_SB_ALL_BITS);
+       libxfs_sb_from_disk(sb, XFS_BUF_TO_SBP(sbp));
 
-       mp = libxfs_mount(&mbuf, sb, xargs.ddev, xargs.logdev, xargs.rtdev, 1);
+       /* Do it again, now with proper length and verifier */
+       libxfs_putbuf(sbp);
+       libxfs_purgebuf(sbp);
+       sbp = libxfs_readbuf(mbuf.m_ddev_targp, XFS_SB_DADDR,
+                            1 << (sb->sb_sectlog - BBSHIFT),
+                            0, &xfs_sb_buf_ops);
+       libxfs_putbuf(sbp);
+
+       mp = libxfs_mount(&mbuf, sb, xargs.ddev, xargs.logdev, xargs.rtdev, 0);
        if (mp == NULL) {
                do_log(_("%s: %s filesystem failed to initialize\n"
                        "%s: Aborting.\n"), progname, source_name, progname);
@@ -703,6 +742,31 @@ main(int argc, char **argv)
                exit(1);
        }
 
+
+       /*
+        * Set up the mount pointer to access the log and check whether the log
+        * is clean. Fail on a dirty or corrupt log in non-duplicate mode
+        * because the log is formatted as part of the copy and we don't want to
+        * destroy data. We also need the current log cycle to format v5
+        * superblock logs correctly.
+        */
+       memset(&xlog, 0, sizeof(struct xlog));
+       mp->m_log = &xlog;
+       c = xlog_is_dirty(mp, mp->m_log, &xargs, 0);
+       if (!duplicate) {
+               if (c == 1) {
+                       do_log(_(
+"Error: source filesystem log is dirty. Mount the filesystem to replay the\n"
+"log, unmount and retry xfs_copy.\n"));
+                       exit(1);
+               } else if (c < 0) {
+                       do_log(_(
+"Error: could not determine the log head or tail of the source filesystem.\n"
+"Mount the filesystem to replay the log or run xfs_repair.\n"));
+                       exit(1);
+               }
+       }
+
        source_blocksize = mp->m_sb.sb_blocksize;
        source_sectorsize = mp->m_sb.sb_sectsize;
 
@@ -712,27 +776,13 @@ main(int argc, char **argv)
        ASSERT(source_blocksize % source_sectorsize == 0);
        ASSERT(source_sectorsize % BBSIZE == 0);
 
-       if (source_blocksize > source_sectorsize)  {
-               /* get number of leftover sectors in last block of ag header */
-
-               tmp_residue = ((XFS_AGFL_DADDR(mp) + 1) * source_sectorsize)
-                                       % source_blocksize;
-               first_residue = (tmp_residue == 0) ? 0 :
-                       source_blocksize - tmp_residue;
-               ASSERT(first_residue % source_sectorsize == 0);
-       } else if (source_blocksize == source_sectorsize)  {
-               first_residue = 0;
-       } else  {
+       if (source_blocksize < source_sectorsize)  {
                do_log(_("Error:  filesystem block size is smaller than the"
                        " disk sectorsize.\nAborting XFS copy now.\n"));
                exit(1);
        }
 
-       first_agbno = (((XFS_AGFL_DADDR(mp) + 1) * source_sectorsize)
-                               + first_residue) / source_blocksize;
-       ASSERT(first_agbno != 0);
-       ASSERT( ((((XFS_AGFL_DADDR(mp) + 1) * source_sectorsize)
-                               + first_residue) % source_blocksize) == 0);
+       first_agbno = XFS_AGFL_BLOCK(mp) + 1;
 
        /* now open targets */
 
@@ -740,8 +790,8 @@ main(int argc, char **argv)
 
        for (i = 0; i < num_targets; i++)  {
                int     write_last_block = 0;
-       
-               if (stat64(target[i].name, &statbuf) < 0)  {
+
+               if (stat(target[i].name, &statbuf) < 0)  {
                        /* ok, assume it's a file and create it */
 
                        do_out(_("Creating file %s\n"), target[i].name);
@@ -781,7 +831,7 @@ main(int argc, char **argv)
                if (write_last_block)  {
                        /* ensure regular files are correctly sized */
 
-                       if (ftruncate64(target[i].fd, mp->m_sb.sb_dblocks *
+                       if (ftruncate(target[i].fd, mp->m_sb.sb_dblocks *
                                                source_blocksize))  {
                                do_log(_("%s:  cannot grow data section.\n"),
                                        progname);
@@ -795,21 +845,21 @@ main(int argc, char **argv)
                                                progname, target[i].name);
                                        die_perror();
                                } else {
-                                       wbuf_align = MAX(wbuf_align, d.d_mem);
-                                       wbuf_size = MIN(d.d_maxiosz, wbuf_size);
-                                       wbuf_miniosize = MAX(d.d_miniosz,
+                                       wbuf_align = max(wbuf_align, d.d_mem);
+                                       wbuf_size = min(d.d_maxiosz, wbuf_size);
+                                       wbuf_miniosize = max(d.d_miniosz,
                                                                wbuf_miniosize);
                                }
                        }
                } else  {
-                       char    *lb[XFS_MAX_SECTORSIZE] = { 0 };
+                       char    *lb[XFS_MAX_SECTORSIZE] = { NULL };
                        off64_t off;
 
                        /* ensure device files are sufficiently large */
 
                        off = mp->m_sb.sb_dblocks * source_blocksize;
                        off -= sizeof(lb);
-                       if (pwrite64(target[i].fd, lb, sizeof(lb), off) < 0)  {
+                       if (pwrite(target[i].fd, lb, sizeof(lb), off) < 0)  {
                                do_log(_("%s:  failed to write last block\n"),
                                        progname);
                                do_log(_("\tIs target \"%s\" too small?\n"),
@@ -835,7 +885,7 @@ main(int argc, char **argv)
 
        wblocks = wbuf_size / BBSIZE;
 
-       if (wbuf_init(&btree_buf, MAX(source_blocksize, wbuf_miniosize),
+       if (wbuf_init(&btree_buf, max(source_blocksize, wbuf_miniosize),
                                wbuf_align, wbuf_miniosize, 1) == NULL)  {
                do_log(_("Error initializing btree buf 1\n"));
                die_perror();
@@ -847,12 +897,12 @@ main(int argc, char **argv)
                exit(1);
        }
        /* need to start out blocking */
-       pthread_mutex_lock(&mainwait); 
+       pthread_mutex_lock(&mainwait);
 
        /* set up sigchild signal handler */
 
        signal(SIGCHLD, handler);
-       sighold(SIGCHLD);
+       signal_maskfunc(SIGCHLD, SIG_BLOCK);
 
        /* make children */
 
@@ -864,9 +914,9 @@ main(int argc, char **argv)
 
        for (i = 0, tcarg = targ; i < num_targets; i++, tcarg++)  {
                if (!duplicate)
-                       uuid_generate(tcarg->uuid);
+                       platform_uuid_generate(&tcarg->uuid);
                else
-                       uuid_copy(tcarg->uuid, mp->m_sb.sb_uuid);
+                       platform_uuid_copy(&tcarg->uuid, &mp->m_sb.sb_uuid);
 
                if (pthread_mutex_init(&tcarg->wait, NULL) != 0)  {
                        do_log(_("Error creating thread mutex %d\n"), i);
@@ -874,7 +924,7 @@ main(int argc, char **argv)
                        exit(1);
                }
                /* need to start out blocking */
-               pthread_mutex_lock(&tcarg->wait); 
+               pthread_mutex_lock(&tcarg->wait);
        }
 
        for (i = 0, tcarg = targ; i < num_targets; i++, tcarg++)  {
@@ -898,11 +948,10 @@ main(int argc, char **argv)
        num_ags = mp->m_sb.sb_agcount;
 
        init_bar(mp->m_sb.sb_blocksize / BBSIZE
-                       * ((__uint64_t)mp->m_sb.sb_dblocks
-                           - (__uint64_t)mp->m_sb.sb_fdblocks + 10 * num_ags));
+                       * ((uint64_t)mp->m_sb.sb_dblocks
+                           - (uint64_t)mp->m_sb.sb_fdblocks + 10 * num_ags));
 
        kids = num_targets;
-       block = (xfs_alloc_block_t *) btree_buf.data;
 
        for (agno = 0; agno < num_ags && kids > 0; agno++)  {
                /* read in first blocks of the ag */
@@ -913,11 +962,11 @@ main(int argc, char **argv)
                /* set the in_progress bit for the first AG */
 
                if (agno == 0)
-                       INT_SET(ag_hdr.xfs_sb->sb_inprogress, ARCH_CONVERT, 1);
+                       ag_hdr.xfs_sb->sb_inprogress = 1;
 
                /* save what we need (agf) in the btree buffer */
 
-               bcopy(ag_hdr.xfs_agf, btree_buf.data, source_sectorsize);
+               memmove(btree_buf.data, ag_hdr.xfs_agf, source_sectorsize);
                ag_hdr.xfs_agf = (xfs_agf_t *) btree_buf.data;
                btree_buf.length = source_blocksize;
 
@@ -927,21 +976,24 @@ main(int argc, char **argv)
 
                /* traverse btree until we get to the leftmost leaf node */
 
-               bno = INT_GET(ag_hdr.xfs_agf->agf_roots[XFS_BTNUM_BNOi],
-                       ARCH_CONVERT);
+               bno = be32_to_cpu(ag_hdr.xfs_agf->agf_roots[XFS_BTNUM_BNOi]);
                current_level = 0;
-               btree_levels = INT_GET(
-                       ag_hdr.xfs_agf->agf_levels[XFS_BTNUM_BNOi],
-                       ARCH_CONVERT);
+               btree_levels = be32_to_cpu(ag_hdr.xfs_agf->
+                                               agf_levels[XFS_BTNUM_BNOi]);
 
                ag_end = XFS_AGB_TO_DADDR(mp, agno,
-                       INT_GET(ag_hdr.xfs_agf->agf_length,ARCH_CONVERT) - 1)
-                       + source_blocksize/BBSIZE;
+                               be32_to_cpu(ag_hdr.xfs_agf->agf_length) - 1)
+                               + source_blocksize / BBSIZE;
 
                for (;;) {
                        /* none of this touches the w_buf buffer */
 
-                       ASSERT(current_level < btree_levels);
+                       if (current_level >= btree_levels) {
+                               do_log(
+                       _("Error: current level %d >= btree levels %d\n"),
+                                       current_level, btree_levels);
+                               exit(1);
+                       }
 
                        current_level++;
 
@@ -950,19 +1002,24 @@ main(int argc, char **argv)
                        btree_buf.length = source_blocksize;
 
                        read_wbuf(source_fd, &btree_buf, mp);
-                       block = (xfs_alloc_block_t *) ((char *) btree_buf.data
-                                       + pos - btree_buf.position);
-
-                       ASSERT(INT_GET(block->bb_magic,ARCH_CONVERT) ==
-                               XFS_ABTB_MAGIC);
+                       block = (struct xfs_btree_block *)
+                                ((char *)btree_buf.data +
+                                 pos - btree_buf.position);
+
+                       if (be32_to_cpu(block->bb_magic) !=
+                           (xfs_sb_version_hascrc(&mp->m_sb) ?
+                            XFS_ABTB_CRC_MAGIC : XFS_ABTB_MAGIC)) {
+                               do_log(_("Bad btree magic 0x%x\n"),
+                                       be32_to_cpu(block->bb_magic));
+                               exit(1);
+                       }
 
-                       if (INT_GET(block->bb_level,ARCH_CONVERT) == 0)
+                       if (be16_to_cpu(block->bb_level) == 0)
                                break;
 
-                       ptr = XFS_BTREE_PTR_ADDR(sourceb_blocksize, xfs_alloc,
-                               block, 1, mp->m_alloc_mxr[1]),
-
-                       bno = INT_GET(ptr[0], ARCH_CONVERT);
+                       ptr = XFS_ALLOC_PTR_ADDR(mp, block, 1,
+                                                       mp->m_alloc_mxr[1]);
+                       bno = be32_to_cpu(ptr[0]);
                }
 
                /* align first data copy but don't overwrite ag header */
@@ -977,7 +1034,7 @@ main(int argc, char **argv)
                /* handle the rest of the ag */
 
                for (;;) {
-                       if (INT_GET(block->bb_level,ARCH_CONVERT) != 0)  {
+                       if (be16_to_cpu(block->bb_level) != 0)  {
                                do_log(
                        _("WARNING:  source filesystem inconsistent.\n"));
                                do_log(
@@ -985,12 +1042,9 @@ main(int argc, char **argv)
                                exit(1);
                        }
 
-                       rec_ptr = XFS_BTREE_REC_ADDR(source_blocksize,
-                               xfs_alloc, block, 1, mp->m_alloc_mxr[0]);
-
-                       for (i = 0;
-                            i < INT_GET(block->bb_numrecs,ARCH_CONVERT);
-                            i++, rec_ptr++)  {
+                       rec_ptr = XFS_ALLOC_REC_ADDR(mp, block, 1);
+                       for (i = 0; i < be16_to_cpu(block->bb_numrecs);
+                                                       i++, rec_ptr++)  {
                                /* calculate in daddr's */
 
                                begin = next_begin;
@@ -1010,8 +1064,8 @@ main(int argc, char **argv)
                                 */
 
                                sizeb = XFS_AGB_TO_DADDR(mp, agno,
-                                       INT_GET(rec_ptr->ar_startblock,
-                                               ARCH_CONVERT)) - begin;
+                                       be32_to_cpu(rec_ptr->ar_startblock)) -
+                                               begin;
                                size = roundup(sizeb <<BBSHIFT, wbuf_miniosize);
                                if (size > 0)  {
                                        /* copy extent */
@@ -1047,35 +1101,32 @@ main(int argc, char **argv)
                                /* round next starting point down */
 
                                new_begin = XFS_AGB_TO_DADDR(mp, agno,
-                                               INT_GET(rec_ptr->ar_startblock,
-                                                       ARCH_CONVERT) +
-                                               INT_GET(rec_ptr->ar_blockcount,
-                                                       ARCH_CONVERT));
+                                               be32_to_cpu(rec_ptr->ar_startblock) +
+                                               be32_to_cpu(rec_ptr->ar_blockcount));
                                next_begin = rounddown(new_begin,
                                                w_buf.min_io_size >> BBSHIFT);
                        }
 
-                       if (INT_GET(block->bb_rightsib,ARCH_CONVERT) ==
-                           NULLAGBLOCK)
+                       if (be32_to_cpu(block->bb_u.s.bb_rightsib) == NULLAGBLOCK)
                                break;
 
                        /* read in next btree record block */
 
                        btree_buf.position = pos = (xfs_off_t)
-                               XFS_AGB_TO_DADDR(mp, agno,
-                                       INT_GET(block->bb_rightsib,
-                                               ARCH_CONVERT)) << BBSHIFT;
+                               XFS_AGB_TO_DADDR(mp, agno, be32_to_cpu(
+                                               block->bb_u.s.bb_rightsib)) << BBSHIFT;
                        btree_buf.length = source_blocksize;
 
                        /* let read_wbuf handle alignment */
 
                        read_wbuf(source_fd, &btree_buf, mp);
 
-                       block = (xfs_alloc_block_t *) ((char *) btree_buf.data
-                                       + pos - btree_buf.position);
+                       block = (struct xfs_btree_block *)
+                                ((char *) btree_buf.data +
+                                 pos - btree_buf.position);
 
-                       ASSERT(INT_GET(block->bb_magic,ARCH_CONVERT) ==
-                               XFS_ABTB_MAGIC);
+                       ASSERT(be32_to_cpu(block->bb_magic) == XFS_ABTB_MAGIC ||
+                              be32_to_cpu(block->bb_magic) == XFS_ABTB_CRC_MAGIC);
                }
 
                /*
@@ -1120,29 +1171,11 @@ main(int argc, char **argv)
        }
 
        if (kids > 0)  {
-               if (!duplicate)  {
-
+               if (!duplicate)
                        /* write a clean log using the specified UUID */
-                       for (j = 0, tcarg = targ; j < num_targets; j++)  {
-                               w_buf.owner = tcarg;
-                               w_buf.length = rounddown(w_buf.size,
-                                                        w_buf.min_io_size);
-                               pos = write_log_header(
-                                                       source_fd, &w_buf, mp);
-                               end_pos = write_log_trailer(
-                                                       source_fd, &w_buf, mp);
-                               w_buf.position = pos;
-                               memset(w_buf.data, 0, w_buf.length);
-
-                               while (w_buf.position < end_pos)  {
-                                       do_write(tcarg);
-                                       w_buf.position += w_buf.length;
-                               }
-                               tcarg++;
-                       }
-               } else {
+                       format_logs(mp);
+               else
                        num_ags = 1;
-               }
 
                /* reread and rewrite superblocks (UUID and in-progress) */
                /* [backwards, so inprogress bit only updated when done] */
@@ -1156,8 +1189,8 @@ main(int argc, char **argv)
                        /* do each thread in turn, each has its own UUID */
 
                        for (j = 0, tcarg = targ; j < num_targets; j++)  {
-                               uuid_copy(ag_hdr.xfs_sb->sb_uuid, tcarg->uuid);
-                               do_write(tcarg);
+                               sb_update_uuid(sb, &ag_hdr, tcarg);
+                               do_write(tcarg, NULL);
                                tcarg++;
                        }
                }
@@ -1166,21 +1199,21 @@ main(int argc, char **argv)
        }
 
        check_errors();
-       killall();
-       pthread_exit(NULL);             
-       /*NOTREACHED*/
+       libxfs_umount(mp);
+       libxfs_destroy();
+
        return 0;
 }
 
-xfs_caddr_t
-next_log_chunk(xfs_caddr_t p, int offset, void *private)
+static char *
+next_log_chunk(char *p, int offset, void *private)
 {
        wbuf    *buf = (wbuf *)private;
 
        if (buf->length < (int)(p - buf->data) + offset) {
                /* need to flush this one, then start afresh */
 
-               do_write(buf->owner);
+               do_write(buf->owner, NULL);
                memset(buf->data, 0, buf->length);
                return buf->data;
        }
@@ -1190,13 +1223,13 @@ next_log_chunk(xfs_caddr_t p, int offset, void *private)
 /*
  * Writes a log header at the start of the log (with the real
  * filesystem UUID embedded into it), and writes to all targets.
- * 
+ *
  * Returns the next buffer-length-aligned disk address.
  */
 xfs_off_t
 write_log_header(int fd, wbuf *buf, xfs_mount_t *mp)
 {
-       xfs_caddr_t     p = buf->data;
+       char            *p = buf->data;
        xfs_off_t       logstart;
        int             offset;
 
@@ -1212,12 +1245,12 @@ write_log_header(int fd, wbuf *buf, xfs_mount_t *mp)
        }
 
        offset = libxfs_log_header(p, &buf->owner->uuid,
-                       XFS_SB_VERSION_HASLOGV2(&mp->m_sb) ? 2 : 1,
-                       mp->m_sb.sb_logsunit, XLOG_FMT,
-                       next_log_chunk, buf);
-       do_write(buf->owner);
+                       xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1,
+                       mp->m_sb.sb_logsunit, XLOG_FMT, NULLCOMMITLSN,
+                       NULLCOMMITLSN, next_log_chunk, buf);
+       do_write(buf->owner, NULL);
 
-       return logstart + roundup(offset, buf->length);
+       return roundup(logstart + offset, buf->length);
 }
 
 /*
@@ -1240,8 +1273,103 @@ write_log_trailer(int fd, wbuf *buf, xfs_mount_t *mp)
                read_wbuf(fd, buf, mp);
                offset = (int)(logend - buf->position);
                memset(buf->data, 0, offset);
-               do_write(buf->owner);
+               do_write(buf->owner, NULL);
        }
 
        return buf->position;
 }
+
+/*
+ * Clear a log by writing a record at the head, the tail and zeroing everything
+ * in between.
+ */
+static void
+clear_log(
+       struct xfs_mount        *mp,
+       thread_args             *tcarg)
+{
+       xfs_off_t               pos;
+       xfs_off_t               end_pos;
+
+       w_buf.owner = tcarg;
+       w_buf.length = rounddown(w_buf.size, w_buf.min_io_size);
+       pos = write_log_header(source_fd, &w_buf, mp);
+       end_pos = write_log_trailer(source_fd, &w_buf, mp);
+       w_buf.position = pos;
+       memset(w_buf.data, 0, w_buf.length);
+
+       while (w_buf.position < end_pos)  {
+               do_write(tcarg, NULL);
+               w_buf.position += w_buf.length;
+       }
+}
+
+/*
+ * Format the log to a particular cycle number. This is required for version 5
+ * superblock filesystems to provide metadata LSN validity guarantees.
+ */
+static void
+format_log(
+       struct xfs_mount        *mp,
+       thread_args             *tcarg,
+       wbuf                    *buf)
+{
+       int                     logstart;
+       int                     length;
+       int                     cycle = XLOG_INIT_CYCLE;
+
+       buf->owner = tcarg;
+       buf->length = buf->size;
+       buf->position = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart) << BBSHIFT;
+
+       logstart = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logstart);
+       length = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
+
+       /*
+        * Bump the cycle number on v5 superblock filesystems to guarantee that
+        * all existing metadata LSNs are valid (behind the current LSN) on the
+        * target fs.
+        */
+       if (xfs_sb_version_hascrc(&mp->m_sb))
+               cycle = mp->m_log->l_curr_cycle + 1;
+
+       /*
+        * Format the entire log into the memory buffer and write it out. If the
+        * write fails, mark the target inactive so the failure is reported.
+        */
+       libxfs_log_clear(NULL, buf->data, logstart, length, &buf->owner->uuid,
+                        xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1,
+                        mp->m_sb.sb_logsunit, XLOG_FMT, cycle, true);
+       if (do_write(buf->owner, buf))
+               target[tcarg->id].state = INACTIVE;
+}
+
+static int
+format_logs(
+       struct xfs_mount        *mp)
+{
+       thread_args             *tcarg;
+       int                     i;
+       wbuf                    logbuf;
+       int                     logsize;
+
+       if (xfs_sb_version_hascrc(&mp->m_sb)) {
+               logsize = XFS_FSB_TO_B(mp, mp->m_sb.sb_logblocks);
+               if (!wbuf_init(&logbuf, logsize, w_buf.data_align,
+                              w_buf.min_io_size, w_buf.id))
+                       return -ENOMEM;
+       }
+
+       for (i = 0, tcarg = targ; i < num_targets; i++)  {
+               if (xfs_sb_version_hascrc(&mp->m_sb))
+                       format_log(mp, tcarg, &logbuf);
+               else
+                       clear_log(mp, tcarg);
+               tcarg++;
+       }
+
+       if (xfs_sb_version_hascrc(&mp->m_sb))
+               free(logbuf.data);
+
+       return 0;
+}