]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blobdiff - copy/xfs_copy.c
xfs: print specific dqblk that failed verifiers
[thirdparty/xfsprogs-dev.git] / copy / xfs_copy.c
index f3e52886d8705ada5e90a60ff33064284d2b343f..0b80613f4e64ba6759fb590d87ae0ef526eb30e6 100644 (file)
@@ -28,7 +28,7 @@
 #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;
@@ -43,7 +43,7 @@ unsigned int  source_sectorsize;      /* source disk sectorsize */
 
 xfs_agblock_t  first_agbno;
 
-__uint64_t     barcount[11];
+uint64_t       barcount[11];
 
 unsigned int   num_targets;
 target_control *target;
@@ -62,8 +62,9 @@ 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 */
 
@@ -73,6 +74,16 @@ 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
+signal_maskfunc(int addset, int newset)
+{
+       sigset_t set;
+
+       sigemptyset(&set);
+       sigaddset(&set, addset);
+       sigprocmask(newset, &set, NULL);
+}
+
 void
 do_message(int flags, int code, const char *fmt, ...)
 {
@@ -151,7 +162,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);
                }
        }
@@ -170,20 +181,26 @@ check_errors(void)
  * are taken care of when the buffer's read in
  */
 int
-do_write(thread_args *args)
+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,7 +208,7 @@ 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;
 }
@@ -203,7 +220,7 @@ begin_reader(void *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)
@@ -246,7 +263,7 @@ handler(int sig)
                                                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);
                                }
@@ -296,7 +313,7 @@ usage(void)
 }
 
 void
-init_bar(__uint64_t source_blocks)
+init_bar(uint64_t source_blocks)
 {
        int     i;
 
@@ -305,7 +322,7 @@ init_bar(__uint64_t source_blocks)
 }
 
 int
-bump_bar(int tenths, __uint64_t numblocks)
+bump_bar(int tenths, uint64_t numblocks)
 {
        static char *bar[11] = {
                " 0% ",
@@ -346,6 +363,7 @@ wbuf_init(wbuf *buf, int data_size, int data_align, int min_io_size, int id)
                        return NULL;
        }
        ASSERT(min_io_size % BBSIZE == 0);
+       buf->data_align = data_align;
        buf->min_io_size = min_io_size;
        buf->size = data_size;
        buf->id = id;
@@ -370,9 +388,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();
                }
@@ -458,6 +476,7 @@ void
 write_wbuf(void)
 {
        int             i;
+       int             badness = 0;
 
        /* verify target threads */
        for (i = 0; i < num_targets; i++)
@@ -468,35 +487,48 @@ 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++;
 
-       sigrelse(SIGCHLD);
+       /*
+        * 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);
+       }
+
+       signal_maskfunc(SIGCHLD, SIG_UNBLOCK);
        pthread_mutex_lock(&mainwait);
-       sighold(SIGCHLD);
+       signal_maskfunc(SIGCHLD, SIG_BLOCK);
 }
 
 void
 sb_update_uuid(
-       xfs_sb_t        *sb,
-       ag_header_t     *ag_hdr,
-       thread_args     *tcarg)
+       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 are changing the UUID in the copy, we need
-        * to copy the original UUID into the meta_uuid slot and set the
-        * set the incompat flag if that hasn't already been done.
+        * 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 (!uuid_equal(&tcarg->uuid, &ag_hdr->xfs_sb->sb_uuid) &&
-           xfs_sb_version_hascrc(sb) && !xfs_sb_version_hasmetauuid(sb)) {
+       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,
-                                  &ag_hdr->xfs_sb->sb_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 */
@@ -511,11 +543,11 @@ main(int argc, char **argv)
        int             i, j;
        int             howfar = 0;
        int             open_flags;
-       xfs_off_t       pos, end_pos;
+       xfs_off_t       pos;
        size_t          length;
        int             c;
-       __uint64_t      size, sizeb;
-       __uint64_t      numblocks = 0;
+       uint64_t        size, sizeb;
+       uint64_t        numblocks = 0;
        int             wblocks = 0;
        int             num_threads = 0;
        struct dioattr  d;
@@ -542,7 +574,7 @@ main(int argc, char **argv)
        extern int      optind;
        libxfs_init_t   xargs;
        thread_args     *tcarg;
-       struct stat64   statbuf;
+       struct stat     statbuf;
 
        progname = basename(argv[0]);
 
@@ -623,7 +655,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();
@@ -774,7 +806,7 @@ 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);
@@ -814,7 +846,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);
@@ -842,7 +874,7 @@ main(int argc, char **argv)
 
                        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"),
@@ -885,7 +917,7 @@ main(int argc, char **argv)
        /* set up sigchild signal handler */
 
        signal(SIGCHLD, handler);
-       sighold(SIGCHLD);
+       signal_maskfunc(SIGCHLD, SIG_BLOCK);
 
        /* make children */
 
@@ -931,8 +963,8 @@ 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;
 
@@ -1046,8 +1078,8 @@ main(int argc, char **argv)
                                 * range bigger than required
                                 */
 
-                               sizeb = XFS_AGB_TO_DADDR(mp, agno, 
-                                       be32_to_cpu(rec_ptr->ar_startblock)) - 
+                               sizeb = XFS_AGB_TO_DADDR(mp, agno,
+                                       be32_to_cpu(rec_ptr->ar_startblock)) -
                                                begin;
                                size = roundup(sizeb <<BBSHIFT, wbuf_miniosize);
                                if (size > 0)  {
@@ -1108,7 +1140,8 @@ main(int argc, char **argv)
                                 ((char *) btree_buf.data +
                                  pos - btree_buf.position);
 
-                       ASSERT(be32_to_cpu(block->bb_magic) == XFS_ABTB_MAGIC);
+                       ASSERT(be32_to_cpu(block->bb_magic) == XFS_ABTB_MAGIC ||
+                              be32_to_cpu(block->bb_magic) == XFS_ABTB_CRC_MAGIC);
                }
 
                /*
@@ -1153,29 +1186,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] */
@@ -1190,7 +1205,7 @@ main(int argc, char **argv)
 
                        for (j = 0, tcarg = targ; j < num_targets; j++)  {
                                sb_update_uuid(sb, &ag_hdr, tcarg);
-                               do_write(tcarg);
+                               do_write(tcarg, NULL);
                                tcarg++;
                        }
                }
@@ -1200,6 +1215,7 @@ main(int argc, char **argv)
 
        check_errors();
        libxfs_umount(mp);
+       libxfs_destroy();
 
        return 0;
 }
@@ -1212,7 +1228,7 @@ next_log_chunk(char *p, int offset, void *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;
        }
@@ -1247,7 +1263,7 @@ write_log_header(int fd, wbuf *buf, xfs_mount_t *mp)
                        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);
+       do_write(buf->owner, NULL);
 
        return roundup(logstart + offset, buf->length);
 }
@@ -1272,8 +1288,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;
+}