1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
15 #include "libfrog/platform.h"
17 #define rounddown(x, y) (((x)/(y))*(y))
18 #define uuid_equal(s,d) (platform_uuid_compare((s),(d)) == 0)
20 extern int platform_check_ismounted(char *, char *, struct stat
*, int);
22 static char *logfile_name
;
24 static char LOGFILE_NAME
[] = "/var/tmp/xfs_copy.log.XXXXXX";
26 static char *source_name
;
29 static unsigned int source_blocksize
; /* source filesystem blocksize */
30 static unsigned int source_sectorsize
; /* source disk sectorsize */
32 static xfs_agblock_t first_agbno
;
34 static uint64_t barcount
[11];
36 static unsigned int num_targets
;
37 static target_control
*target
;
40 static wbuf btree_buf
;
42 static unsigned int kids
;
44 static thread_control glob_masks
;
45 static thread_args
*targ
;
47 static pthread_mutex_t mainwait
;
52 xfs_off_t
write_log_trailer(int fd
, wbuf
*w
, xfs_mount_t
*mp
);
53 xfs_off_t
write_log_header(int fd
, wbuf
*w
, xfs_mount_t
*mp
);
54 static int format_logs(struct xfs_mount
*);
56 /* general purpose message reporting routine */
58 #define OUT 0x01 /* use stdout stream */
59 #define ERR 0x02 /* use stderr stream */
60 #define LOG 0x04 /* use logerr stream */
61 #define PRE 0x08 /* append strerror string */
62 #define LAST 0x10 /* final message we print */
65 signal_maskfunc(int addset
, int newset
)
70 sigaddset(&set
, addset
);
71 sigprocmask(newset
, &set
, NULL
);
75 do_message(int flags
, int code
, const char *fmt
, ...)
82 if (vfprintf(logerr
, fmt
, ap
) <= 0)
87 flags
|= ERR
; /* failed, force stderr */
90 vfprintf(stderr
, fmt
, ap
);
92 } else if (flags
& OUT
) {
94 vfprintf(stdout
, fmt
, ap
);
99 do_message(flags
& ~PRE
, 0, ": %s\n", strerror(code
));
102 _("Check logfile \"%s\" for more details\n"),
106 /* logfile is broken, force a write to stderr */
108 fprintf(stderr
, _("%s: could not write to logfile \"%s\".\n"),
109 progname
, logfile_name
);
111 _("Aborting XFS copy -- logfile error -- reason: %s\n"),
113 rcu_unregister_thread();
118 #define do_out(args...) do_message(OUT|LOG, 0, ## args)
119 #define do_log(args...) do_message(ERR|LOG, 0, ## args)
120 #define do_warn(args...) do_message(LOG, 0, ## args)
121 #define do_error(e,s) do_message(ERR|LOG|PRE, e, s)
122 #define do_fatal(e,s) do_message(ERR|LOG|PRE|LAST, e, s)
123 #define do_vfatal(e,s,args...) do_message(ERR|LOG|PRE|LAST, e, s, ## args)
124 #define die_perror() \
126 do_message(ERR|LOG|PRE|LAST, errno, \
127 _("Aborting XFS copy - reason")); \
131 /* workaround craziness in the xlog routines */
132 int xlog_recover_do_trans(struct xlog
*log
, struct xlog_recover
*t
, int p
)
140 int i
, first_error
= 0;
142 for (i
= 0; i
< num_targets
; i
++) {
143 if (target
[i
].state
!= INACTIVE
) {
144 if (platform_flush_device(target
[i
].fd
, 0)) {
145 target
[i
].error
= errno
;
146 target
[i
].state
= INACTIVE
;
147 target
[i
].err_type
= 2;
151 if (target
[i
].state
== INACTIVE
) {
152 if (first_error
== 0) {
155 _("THE FOLLOWING COPIES FAILED TO COMPLETE\n"));
157 do_log(" %s -- ", target
[i
].name
);
158 switch (target
[i
].err_type
) {
160 do_log(_("write error"));
163 do_log(_("lseek error"));
166 do_log(_("flush error"));
169 do_log(_("unknown error type %d"),
173 do_log(_(" at offset %lld\n"), target
[i
].position
);
176 if (first_error
== 0) {
177 fprintf(stdout
, _("All copies completed.\n"));
180 fprintf(stderr
, _("See \"%s\" for more details.\n"),
187 * don't have to worry about alignment and mins because those
188 * are taken care of when the buffer's read in
201 if (target
[args
->id
].position
!= buf
->position
) {
202 if (lseek(args
->fd
, buf
->position
, SEEK_SET
) < 0) {
203 error
= target
[args
->id
].err_type
= 1;
205 target
[args
->id
].position
= buf
->position
;
209 if ((res
= write(target
[args
->id
].fd
, buf
->data
,
210 buf
->length
)) == buf
->length
) {
211 target
[args
->id
].position
+= res
;
217 target
[args
->id
].error
= errno
;
218 target
[args
->id
].position
= buf
->position
;
224 begin_reader(void *arg
)
226 thread_args
*args
= arg
;
228 rcu_register_thread();
230 pthread_mutex_lock(&args
->wait
);
231 if (do_write(args
, NULL
))
233 pthread_mutex_lock(&glob_masks
.mutex
);
234 if (--glob_masks
.num_working
== 0)
235 pthread_mutex_unlock(&mainwait
);
236 pthread_mutex_unlock(&glob_masks
.mutex
);
241 /* error will be logged by primary thread */
243 pthread_mutex_lock(&glob_masks
.mutex
);
244 target
[args
->id
].state
= INACTIVE
;
245 if (--glob_masks
.num_working
== 0)
246 pthread_mutex_unlock(&mainwait
);
247 pthread_mutex_unlock(&glob_masks
.mutex
);
248 rcu_unregister_thread();
263 for (i
= 0; i
< num_targets
; i
++) {
264 if (target
[i
].pid
== pid
) {
265 if (target
[i
].state
== INACTIVE
) {
266 /* thread got an I/O error */
268 if (target
[i
].err_type
== 0) {
270 _("%s: write error on target %d \"%s\" at offset %lld\n"),
271 progname
, i
, target
[i
].name
,
275 _("%s: lseek error on target %d \"%s\" at offset %lld\n"),
276 progname
, i
, target
[i
].name
,
280 do_vfatal(target
[i
].error
,
281 _("Aborting target %d - reason"), i
);
285 _("Aborting XFS copy - no more targets.\n"));
290 signal(SIGCHLD
, handler
);
293 /* it just croaked it bigtime, log it */
296 _("%s: thread %d died unexpectedly, target \"%s\" incomplete\n"),
297 progname
, i
, target
[i
].name
);
298 do_warn(_("%s: offset was probably %lld\n"),
299 progname
, target
[i
].position
);
300 do_fatal(target
[i
].error
,
301 _("Aborting XFS copy - reason"));
307 /* unknown child -- something very wrong */
309 do_warn(_("%s: Unknown child died (should never happen!)\n"), progname
);
312 signal(SIGCHLD
, handler
);
319 _("Usage: %s [-bdV] [-L logfile] source target [target ...]\n"),
325 init_bar(uint64_t source_blocks
)
329 for (i
= 0; i
< 11; i
++)
330 barcount
[i
] = (source_blocks
/10)*i
;
334 bump_bar(int tenths
, uint64_t numblocks
)
336 static char *bar
[11] = {
351 printf("%s", bar
[10]);
354 while (tenths
< 10 && numblocks
> barcount
[tenths
]) {
355 printf("%s", bar
[tenths
]);
363 static xfs_off_t source_position
= -1;
366 wbuf_init(wbuf
*buf
, int data_size
, int data_align
, int min_io_size
, int id
)
368 ASSERT(data_size
% BBSIZE
== 0);
369 while ((buf
->data
= memalign(data_align
, data_size
)) == NULL
) {
371 if (data_size
< min_io_size
)
374 ASSERT(min_io_size
% BBSIZE
== 0);
375 buf
->data_align
= data_align
;
376 buf
->min_io_size
= min_io_size
;
377 buf
->size
= data_size
;
383 read_wbuf(int fd
, wbuf
*buf
, xfs_mount_t
*mp
)
390 newpos
= rounddown(buf
->position
, (xfs_off_t
) buf
->min_io_size
);
392 if (newpos
!= buf
->position
) {
393 diff
= buf
->position
- newpos
;
394 buf
->position
= newpos
;
399 if (source_position
!= buf
->position
) {
400 lres
= lseek(fd
, buf
->position
, SEEK_SET
);
402 do_warn(_("%s: lseek failure at offset %lld\n"),
403 progname
, source_position
);
406 source_position
= buf
->position
;
409 ASSERT(source_position
% source_sectorsize
== 0);
411 /* round up length for direct I/O if necessary */
413 if (buf
->length
% buf
->min_io_size
!= 0)
414 buf
->length
= roundup(buf
->length
, buf
->min_io_size
);
416 if (buf
->length
> buf
->size
) {
417 do_warn(_("assert error: buf->length = %d, buf->size = %d\n"),
418 buf
->length
, buf
->size
);
422 if ((res
= read(fd
, buf
->data
, buf
->length
)) < 0) {
423 do_warn(_("%s: read failure at offset %lld\n"),
424 progname
, source_position
);
428 if (res
< buf
->length
&&
429 source_position
+ res
== mp
->m_sb
.sb_dblocks
* source_blocksize
)
432 ASSERT(res
== buf
->length
);
433 source_position
+= res
;
438 read_ag_header(int fd
, xfs_agnumber_t agno
, wbuf
*buf
, ag_header_t
*ag
,
439 xfs_mount_t
*mp
, int blocksize
, int sectorsize
)
446 /* initial settings */
449 off
= XFS_AG_DADDR(mp
, agno
, XFS_SB_DADDR
);
450 buf
->position
= (xfs_off_t
) off
* (xfs_off_t
) BBSIZE
;
451 length
= buf
->length
= first_agbno
* blocksize
;
453 do_log(_("ag header buffer invalid!\n"));
457 /* handle alignment stuff */
459 newpos
= rounddown(buf
->position
, (xfs_off_t
) buf
->min_io_size
);
460 if (newpos
!= buf
->position
) {
461 diff
= buf
->position
- newpos
;
462 buf
->position
= newpos
;
466 /* round up length for direct I/O if necessary */
468 if (buf
->length
% buf
->min_io_size
!= 0)
469 buf
->length
= roundup(buf
->length
, buf
->min_io_size
);
471 read_wbuf(fd
, buf
, mp
);
472 ASSERT(buf
->length
>= length
);
474 ag
->xfs_sb
= (struct xfs_dsb
*) (buf
->data
+ diff
);
475 ASSERT(be32_to_cpu(ag
->xfs_sb
->sb_magicnum
) == XFS_SB_MAGIC
);
476 ag
->xfs_agf
= (xfs_agf_t
*) (buf
->data
+ diff
+ sectorsize
);
477 ASSERT(be32_to_cpu(ag
->xfs_agf
->agf_magicnum
) == XFS_AGF_MAGIC
);
478 ag
->xfs_agi
= (xfs_agi_t
*) (buf
->data
+ diff
+ 2 * sectorsize
);
479 ASSERT(be32_to_cpu(ag
->xfs_agi
->agi_magicnum
) == XFS_AGI_MAGIC
);
480 ag
->xfs_agfl
= (struct xfs_agfl
*) (buf
->data
+ diff
+ 3 * sectorsize
);
490 /* verify target threads */
491 for (i
= 0; i
< num_targets
; i
++)
492 if (target
[i
].state
!= INACTIVE
)
493 glob_masks
.num_working
++;
495 /* release target threads */
496 for (i
= 0; i
< num_targets
; i
++)
497 if (target
[i
].state
!= INACTIVE
)
498 pthread_mutex_unlock(&targ
[i
].wait
); /* wake up */
503 * If all the targets are inactive then there won't be any io
504 * threads left to release mainwait. We're screwed, so bail out.
506 if (badness
== num_targets
) {
511 signal_maskfunc(SIGCHLD
, SIG_UNBLOCK
);
512 pthread_mutex_lock(&mainwait
);
513 signal_maskfunc(SIGCHLD
, SIG_BLOCK
);
518 struct xfs_mount
*mp
,
519 ag_header_t
*ag_hdr
, /* AG hdr to update for this copy */
520 thread_args
*tcarg
) /* Args for this thread, with UUID */
523 * If this filesystem has CRCs, the original UUID is stamped into
524 * all metadata. If we don't have an existing meta_uuid field in the
525 * the original filesystem and we are changing the UUID in this copy,
526 * we must copy the original sb_uuid to the sb_meta_uuid slot and set
527 * the incompat flag for the feature on this copy.
529 if (xfs_has_crc(mp
) && !xfs_has_metauuid(mp
) &&
530 !uuid_equal(&tcarg
->uuid
, &mp
->m_sb
.sb_uuid
)) {
533 feat
= be32_to_cpu(ag_hdr
->xfs_sb
->sb_features_incompat
);
534 feat
|= XFS_SB_FEAT_INCOMPAT_META_UUID
;
535 ag_hdr
->xfs_sb
->sb_features_incompat
= cpu_to_be32(feat
);
536 platform_uuid_copy(&ag_hdr
->xfs_sb
->sb_meta_uuid
,
540 /* Copy the (possibly new) fs-identifier UUID into sb_uuid */
541 platform_uuid_copy(&ag_hdr
->xfs_sb
->sb_uuid
, &tcarg
->uuid
);
543 /* We may have changed the UUID, so update the superblock CRC */
545 xfs_update_cksum((char *)ag_hdr
->xfs_sb
, mp
->m_sb
.sb_sectsize
,
550 main(int argc
, char **argv
)
559 uint64_t size
, sizeb
;
560 uint64_t numblocks
= 0;
567 int source_is_file
= 0;
568 int buffered_output
= 0;
570 uint btree_levels
, current_level
;
577 xfs_agnumber_t num_ags
, agno
;
579 xfs_daddr_t begin
, next_begin
, ag_begin
, new_begin
, ag_end
;
580 struct xfs_btree_block
*block
;
581 xfs_alloc_ptr_t
*ptr
;
582 xfs_alloc_rec_t
*rec_ptr
;
585 struct libxfs_init xargs
;
590 progname
= basename(argv
[0]);
592 setlocale(LC_ALL
, "");
593 bindtextdomain(PACKAGE
, LOCALEDIR
);
596 while ((c
= getopt(argc
, argv
, "bdL:V")) != EOF
) {
605 logfile_name
= optarg
;
608 printf(_("%s version %s\n"), progname
, VERSION
);
615 if (argc
- optind
< 2)
619 logfd
= open(logfile_name
, O_CREAT
|O_WRONLY
|O_EXCL
, 0600);
621 logfile_name
= LOGFILE_NAME
;
622 logfd
= mkstemp(logfile_name
);
626 fprintf(stderr
, _("%s: couldn't open log file \"%s\"\n"),
627 progname
, logfile_name
);
628 perror(_("Aborting XFS copy - reason"));
632 if ((logerr
= fdopen(logfd
, "w")) == NULL
) {
633 fprintf(stderr
, _("%s: couldn't set up logfile stream\n"),
635 perror(_("Aborting XFS copy - reason"));
639 source_name
= argv
[optind
];
643 num_targets
= argc
- optind
;
644 if ((target
= malloc(sizeof(target_control
) * num_targets
)) == NULL
) {
645 do_log(_("Couldn't allocate target array\n"));
648 for (i
= 0; optind
< argc
; i
++, optind
++) {
649 target
[i
].name
= argv
[optind
];
651 target
[i
].position
= -1;
652 target
[i
].state
= INACTIVE
;
654 target
[i
].err_type
= 0;
657 /* open up source -- is it a file? */
659 open_flags
= O_RDONLY
;
661 if ((source_fd
= open(source_name
, open_flags
)) < 0) {
662 do_log(_("%s: couldn't open source \"%s\"\n"),
663 progname
, source_name
);
667 if (fstat(source_fd
, &statbuf
) < 0) {
668 do_log(_("%s: couldn't stat source \"%s\"\n"),
669 progname
, source_name
);
673 if (S_ISREG(statbuf
.st_mode
))
676 if (source_is_file
&& platform_test_xfs_fd(source_fd
)) {
677 if (fcntl(source_fd
, F_SETFL
, open_flags
| O_DIRECT
) < 0) {
678 do_log(_("%s: Cannot set direct I/O flag on \"%s\".\n"),
679 progname
, source_name
);
682 if (xfsctl(source_name
, source_fd
, XFS_IOC_DIOINFO
, &d
) < 0) {
683 do_log(_("%s: xfsctl on file \"%s\" failed.\n"),
684 progname
, source_name
);
688 wbuf_align
= d
.d_mem
;
689 wbuf_size
= min(d
.d_maxiosz
, 1 * 1024 * 1024);
690 wbuf_miniosize
= d
.d_miniosz
;
692 /* set arbitrary I/O params, miniosize at least 1 disk block */
694 wbuf_align
= getpagesize();
695 wbuf_size
= 1 * 1024 * 1024;
696 wbuf_miniosize
= -1; /* set after mounting source fs */
699 if (!source_is_file
) {
701 * check to make sure a filesystem isn't mounted
704 if (platform_check_ismounted(source_name
, NULL
, &statbuf
, 0)) {
706 _("%s: Warning -- a filesystem is mounted on the source device.\n"),
709 _("\t\tGenerated copies may be corrupt unless the source is\n"));
711 _("\t\tunmounted or mounted read-only. Copy proceeding...\n"));
715 /* prepare the libxfs_init structure */
717 memset(&xargs
, 0, sizeof(xargs
));
718 xargs
.isdirect
= LIBXFS_DIRECT
;
719 xargs
.isreadonly
= LIBXFS_ISREADONLY
;
721 xargs
.dname
= source_name
;
722 xargs
.disfile
= source_is_file
;
724 if (!libxfs_init(&xargs
)) {
725 do_log(_("%s: couldn't initialize XFS library\n"
726 "%s: Aborting.\n"), progname
, progname
);
730 memset(&mbuf
, 0, sizeof(xfs_mount_t
));
732 /* We don't yet know the sector size, so read maximal size */
733 libxfs_buftarg_init(&mbuf
, &xargs
);
734 error
= -libxfs_buf_read_uncached(mbuf
.m_ddev_targp
, XFS_SB_DADDR
,
735 1 << (XFS_MAX_SECTORSIZE_LOG
- BBSHIFT
), 0, &sbp
, NULL
);
737 do_log(_("%s: couldn't read superblock, error=%d\n"),
743 libxfs_sb_from_disk(sb
, sbp
->b_addr
);
745 /* Do it again, now with proper length and verifier */
746 libxfs_buf_relse(sbp
);
748 error
= -libxfs_buf_read_uncached(mbuf
.m_ddev_targp
, XFS_SB_DADDR
,
749 1 << (sb
->sb_sectlog
- BBSHIFT
), 0, &sbp
,
752 do_log(_("%s: couldn't read superblock, error=%d\n"),
756 libxfs_buf_relse(sbp
);
758 mp
= libxfs_mount(&mbuf
, sb
, &xargs
, 0);
760 do_log(_("%s: %s filesystem failed to initialize\n"
761 "%s: Aborting.\n"), progname
, source_name
, progname
);
763 } else if (mp
->m_sb
.sb_inprogress
) {
764 do_log(_("%s %s filesystem failed to initialize\n"
765 "%s: Aborting.\n"), progname
, source_name
, progname
);
767 } else if (mp
->m_sb
.sb_logstart
== 0) {
768 do_log(_("%s: %s has an external log.\n%s: Aborting.\n"),
769 progname
, source_name
, progname
);
771 } else if (mp
->m_sb
.sb_rextents
!= 0) {
772 do_log(_("%s: %s has a real-time section.\n"
773 "%s: Aborting.\n"), progname
, source_name
, progname
);
779 * Set up the mount pointer to access the log and check whether the log
780 * is clean. Fail on a dirty or corrupt log in non-duplicate mode
781 * because the log is formatted as part of the copy and we don't want to
782 * destroy data. We also need the current log cycle to format v5
783 * superblock logs correctly.
785 memset(&xlog
, 0, sizeof(struct xlog
));
787 c
= xlog_is_dirty(mp
, mp
->m_log
);
791 "Error: source filesystem log is dirty. Mount the filesystem to replay the\n"
792 "log, unmount and retry xfs_copy.\n"));
796 "Error: could not determine the log head or tail of the source filesystem.\n"
797 "Mount the filesystem to replay the log or run xfs_repair.\n"));
802 source_blocksize
= mp
->m_sb
.sb_blocksize
;
803 source_sectorsize
= mp
->m_sb
.sb_sectsize
;
805 if (wbuf_miniosize
== -1)
806 wbuf_miniosize
= source_sectorsize
;
808 ASSERT(source_blocksize
% source_sectorsize
== 0);
809 ASSERT(source_sectorsize
% BBSIZE
== 0);
811 if (source_blocksize
< source_sectorsize
) {
812 do_log(_("Error: filesystem block size is smaller than the"
813 " disk sectorsize.\nAborting XFS copy now.\n"));
817 first_agbno
= XFS_AGFL_BLOCK(mp
) + 1;
819 /* now open targets */
823 for (i
= 0; i
< num_targets
; i
++) {
824 int write_last_block
= 0;
826 if (stat(target
[i
].name
, &statbuf
) < 0) {
827 /* ok, assume it's a file and create it */
829 do_out(_("Creating file %s\n"), target
[i
].name
);
831 open_flags
|= O_CREAT
;
832 if (!buffered_output
)
833 open_flags
|= O_DIRECT
;
834 write_last_block
= 1;
835 } else if (S_ISREG(statbuf
.st_mode
)) {
836 open_flags
|= O_TRUNC
;
837 if (!buffered_output
)
838 open_flags
|= O_DIRECT
;
839 write_last_block
= 1;
842 * check to make sure a filesystem isn't mounted
845 if (platform_check_ismounted(target
[i
].name
,
846 NULL
, &statbuf
, 0)) {
847 do_log(_("%s: a filesystem is mounted "
848 "on target device \"%s\".\n"
849 "%s cannot copy to mounted filesystems."
851 progname
, target
[i
].name
, progname
);
856 target
[i
].fd
= open(target
[i
].name
, open_flags
, 0644);
857 if (target
[i
].fd
< 0) {
858 do_log(_("%s: couldn't open target \"%s\"\n"),
859 progname
, target
[i
].name
);
863 if (write_last_block
) {
864 /* ensure regular files are correctly sized */
866 if (ftruncate(target
[i
].fd
, mp
->m_sb
.sb_dblocks
*
868 do_log(_("%s: cannot grow data section.\n"),
872 if (platform_test_xfs_fd(target
[i
].fd
)) {
873 if (xfsctl(target
[i
].name
, target
[i
].fd
,
874 XFS_IOC_DIOINFO
, &d
) < 0) {
876 _("%s: xfsctl on \"%s\" failed.\n"),
877 progname
, target
[i
].name
);
880 wbuf_align
= max(wbuf_align
, d
.d_mem
);
881 wbuf_size
= min(d
.d_maxiosz
, wbuf_size
);
882 wbuf_miniosize
= max(d
.d_miniosz
,
887 char *lb
[XFS_MAX_SECTORSIZE
] = { NULL
};
890 /* ensure device files are sufficiently large */
892 off
= mp
->m_sb
.sb_dblocks
* source_blocksize
;
894 if (pwrite(target
[i
].fd
, lb
, sizeof(lb
), off
) < 0) {
895 do_log(_("%s: failed to write last block\n"),
897 do_log(_("\tIs target \"%s\" too small?\n"),
904 /* initialize locks and bufs */
906 if (pthread_mutex_init(&glob_masks
.mutex
, NULL
) != 0) {
907 do_log(_("Couldn't initialize global thread mask\n"));
910 glob_masks
.num_working
= 0;
912 if (wbuf_init(&w_buf
, wbuf_size
, wbuf_align
,
913 wbuf_miniosize
, 0) == NULL
) {
914 do_log(_("Error initializing wbuf 0\n"));
918 wblocks
= wbuf_size
/ BBSIZE
;
920 if (wbuf_init(&btree_buf
, max(source_blocksize
, wbuf_miniosize
),
921 wbuf_align
, wbuf_miniosize
, 1) == NULL
) {
922 do_log(_("Error initializing btree buf 1\n"));
926 if (pthread_mutex_init(&mainwait
,NULL
) != 0) {
927 do_log(_("Error creating first semaphore.\n"));
931 /* need to start out blocking */
932 pthread_mutex_lock(&mainwait
);
934 /* set up sigchild signal handler */
936 signal(SIGCHLD
, handler
);
937 signal_maskfunc(SIGCHLD
, SIG_BLOCK
);
941 if ((targ
= malloc(num_targets
* sizeof(thread_args
))) == NULL
) {
942 do_log(_("Couldn't malloc space for thread args\n"));
947 for (i
= 0, tcarg
= targ
; i
< num_targets
; i
++, tcarg
++) {
949 platform_uuid_generate(&tcarg
->uuid
);
951 platform_uuid_copy(&tcarg
->uuid
, &mp
->m_sb
.sb_uuid
);
953 if (pthread_mutex_init(&tcarg
->wait
, NULL
) != 0) {
954 do_log(_("Error creating thread mutex %d\n"), i
);
958 /* need to start out blocking */
959 pthread_mutex_lock(&tcarg
->wait
);
962 for (i
= 0, tcarg
= targ
; i
< num_targets
; i
++, tcarg
++) {
964 tcarg
->fd
= target
[i
].fd
;
966 target
[i
].state
= ACTIVE
;
969 if (pthread_create(&target
[i
].pid
, NULL
,
970 begin_reader
, (void *)tcarg
)) {
971 do_log(_("Error creating thread for target %d\n"), i
);
976 ASSERT(num_targets
== num_threads
);
978 /* set up statistics */
980 num_ags
= mp
->m_sb
.sb_agcount
;
982 init_bar(mp
->m_sb
.sb_blocksize
/ BBSIZE
983 * ((uint64_t)mp
->m_sb
.sb_dblocks
984 - (uint64_t)mp
->m_sb
.sb_fdblocks
+ 10 * num_ags
));
988 for (agno
= 0; agno
< num_ags
&& kids
> 0; agno
++) {
989 /* read in first blocks of the ag */
991 read_ag_header(source_fd
, agno
, &w_buf
, &ag_hdr
, mp
,
992 source_blocksize
, source_sectorsize
);
994 /* set the in_progress bit for the first AG */
997 ag_hdr
.xfs_sb
->sb_inprogress
= 1;
999 /* save what we need (agf) in the btree buffer */
1001 memmove(btree_buf
.data
, ag_hdr
.xfs_agf
, source_sectorsize
);
1002 ag_hdr
.xfs_agf
= (xfs_agf_t
*) btree_buf
.data
;
1003 btree_buf
.length
= source_blocksize
;
1005 /* write the ag header out */
1009 /* traverse btree until we get to the leftmost leaf node */
1011 bno
= be32_to_cpu(ag_hdr
.xfs_agf
->agf_roots
[XFS_BTNUM_BNOi
]);
1013 btree_levels
= be32_to_cpu(ag_hdr
.xfs_agf
->
1014 agf_levels
[XFS_BTNUM_BNOi
]);
1016 ag_end
= XFS_AGB_TO_DADDR(mp
, agno
,
1017 be32_to_cpu(ag_hdr
.xfs_agf
->agf_length
) - 1)
1018 + source_blocksize
/ BBSIZE
;
1021 /* none of this touches the w_buf buffer */
1023 if (current_level
>= btree_levels
) {
1025 _("Error: current level %d >= btree levels %d\n"),
1026 current_level
, btree_levels
);
1032 btree_buf
.position
= pos
= (xfs_off_t
)
1033 XFS_AGB_TO_DADDR(mp
,agno
,bno
) << BBSHIFT
;
1034 btree_buf
.length
= source_blocksize
;
1036 read_wbuf(source_fd
, &btree_buf
, mp
);
1037 block
= (struct xfs_btree_block
*)
1038 ((char *)btree_buf
.data
+
1039 pos
- btree_buf
.position
);
1041 if (be32_to_cpu(block
->bb_magic
) !=
1043 XFS_ABTB_CRC_MAGIC
: XFS_ABTB_MAGIC
)) {
1044 do_log(_("Bad btree magic 0x%x\n"),
1045 be32_to_cpu(block
->bb_magic
));
1049 if (be16_to_cpu(block
->bb_level
) == 0)
1052 ptr
= XFS_ALLOC_PTR_ADDR(mp
, block
, 1,
1053 mp
->m_alloc_mxr
[1]);
1054 bno
= be32_to_cpu(ptr
[0]);
1057 /* align first data copy but don't overwrite ag header */
1059 pos
= w_buf
.position
>> BBSHIFT
;
1060 length
= w_buf
.length
>> BBSHIFT
;
1061 next_begin
= pos
+ length
;
1062 ag_begin
= next_begin
;
1064 ASSERT(w_buf
.position
% source_sectorsize
== 0);
1066 /* handle the rest of the ag */
1069 if (be16_to_cpu(block
->bb_level
) != 0) {
1071 _("WARNING: source filesystem inconsistent.\n"));
1073 _(" A leaf btree rec isn't a leaf. Aborting now.\n"));
1077 rec_ptr
= XFS_ALLOC_REC_ADDR(mp
, block
, 1);
1078 for (i
= 0; i
< be16_to_cpu(block
->bb_numrecs
);
1080 /* calculate in daddr's */
1085 * protect against pathological case of a
1086 * hole right after the ag header in a
1090 if (begin
< ag_begin
)
1094 * round size up to ensure we copy a
1095 * range bigger than required
1098 sizeb
= XFS_AGB_TO_DADDR(mp
, agno
,
1099 be32_to_cpu(rec_ptr
->ar_startblock
)) -
1101 size
= roundup(sizeb
<<BBSHIFT
, wbuf_miniosize
);
1105 w_buf
.position
= (xfs_off_t
)
1110 * let lower layer do alignment
1112 if (size
> w_buf
.size
) {
1113 w_buf
.length
= w_buf
.size
;
1116 numblocks
+= wblocks
;
1118 w_buf
.length
= size
;
1123 read_wbuf(source_fd
, &w_buf
, mp
);
1126 w_buf
.position
+= w_buf
.length
;
1133 /* round next starting point down */
1135 new_begin
= XFS_AGB_TO_DADDR(mp
, agno
,
1136 be32_to_cpu(rec_ptr
->ar_startblock
) +
1137 be32_to_cpu(rec_ptr
->ar_blockcount
));
1138 next_begin
= rounddown(new_begin
,
1139 w_buf
.min_io_size
>> BBSHIFT
);
1142 if (be32_to_cpu(block
->bb_u
.s
.bb_rightsib
) == NULLAGBLOCK
)
1145 /* read in next btree record block */
1147 btree_buf
.position
= pos
= (xfs_off_t
)
1148 XFS_AGB_TO_DADDR(mp
, agno
, be32_to_cpu(
1149 block
->bb_u
.s
.bb_rightsib
)) << BBSHIFT
;
1150 btree_buf
.length
= source_blocksize
;
1152 /* let read_wbuf handle alignment */
1154 read_wbuf(source_fd
, &btree_buf
, mp
);
1156 block
= (struct xfs_btree_block
*)
1157 ((char *) btree_buf
.data
+
1158 pos
- btree_buf
.position
);
1160 ASSERT(be32_to_cpu(block
->bb_magic
) == XFS_ABTB_MAGIC
||
1161 be32_to_cpu(block
->bb_magic
) == XFS_ABTB_CRC_MAGIC
);
1165 * write out range of used blocks after last range
1166 * of free blocks in AG
1168 if (next_begin
< ag_end
) {
1171 sizeb
= ag_end
- begin
;
1172 size
= roundup(sizeb
<< BBSHIFT
, wbuf_miniosize
);
1177 w_buf
.position
= (xfs_off_t
) begin
<< BBSHIFT
;
1181 * let lower layer do alignment
1183 if (size
> w_buf
.size
) {
1184 w_buf
.length
= w_buf
.size
;
1187 numblocks
+= wblocks
;
1189 w_buf
.length
= size
;
1194 read_wbuf(source_fd
, &w_buf
, mp
);
1197 w_buf
.position
+= w_buf
.length
;
1199 howfar
= bump_bar(howfar
, numblocks
);
1207 /* write a clean log using the specified UUID */
1212 /* reread and rewrite superblocks (UUID and in-progress) */
1213 /* [backwards, so inprogress bit only updated when done] */
1215 for (i
= num_ags
- 1; i
>= 0; i
--) {
1216 read_ag_header(source_fd
, i
, &w_buf
, &ag_hdr
, mp
,
1217 source_blocksize
, source_sectorsize
);
1219 ag_hdr
.xfs_sb
->sb_inprogress
= 0;
1221 /* do each thread in turn, each has its own UUID */
1223 for (j
= 0, tcarg
= targ
; j
< num_targets
; j
++) {
1224 sb_update_uuid(mp
, &ag_hdr
, tcarg
);
1225 do_write(tcarg
, NULL
);
1235 libxfs_destroy(&xargs
);
1241 next_log_chunk(char *p
, int offset
, void *private)
1243 wbuf
*buf
= (wbuf
*)private;
1245 if (buf
->length
< (int)(p
- buf
->data
) + offset
) {
1246 /* need to flush this one, then start afresh */
1248 do_write(buf
->owner
, NULL
);
1249 memset(buf
->data
, 0, buf
->length
);
1256 * Writes a log header at the start of the log (with the real
1257 * filesystem UUID embedded into it), and writes to all targets.
1259 * Returns the next buffer-length-aligned disk address.
1262 write_log_header(int fd
, wbuf
*buf
, xfs_mount_t
*mp
)
1264 char *p
= buf
->data
;
1268 logstart
= XFS_FSB_TO_DADDR(mp
, mp
->m_sb
.sb_logstart
) << BBSHIFT
;
1269 buf
->position
= rounddown(logstart
, (xfs_off_t
)buf
->length
);
1271 memset(p
, 0, buf
->size
);
1272 if (logstart
% buf
->length
) { /* unaligned */
1273 read_wbuf(fd
, buf
, mp
);
1274 offset
= logstart
- buf
->position
;
1276 memset(p
, 0, buf
->length
- offset
);
1279 offset
= libxfs_log_header(p
, &buf
->owner
->uuid
,
1280 xfs_has_logv2(mp
) ? 2 : 1,
1281 mp
->m_sb
.sb_logsunit
, XLOG_FMT
, NULLCOMMITLSN
,
1282 NULLCOMMITLSN
, next_log_chunk
, buf
);
1283 do_write(buf
->owner
, NULL
);
1285 return roundup(logstart
+ offset
, buf
->length
);
1289 * May do an aligned read of the last buffer in the log (& zero
1290 * the start of that buffer). Returns the disk address at the
1291 * end of last aligned buffer in the log.
1294 write_log_trailer(int fd
, wbuf
*buf
, xfs_mount_t
*mp
)
1299 logend
= XFS_FSB_TO_DADDR(mp
, mp
->m_sb
.sb_logstart
) << BBSHIFT
;
1300 logend
+= XFS_FSB_TO_B(mp
, mp
->m_sb
.sb_logblocks
);
1302 buf
->position
= rounddown(logend
, (xfs_off_t
)buf
->length
);
1304 if (logend
% buf
->length
) { /* unaligned */
1305 read_wbuf(fd
, buf
, mp
);
1306 offset
= (int)(logend
- buf
->position
);
1307 memset(buf
->data
, 0, offset
);
1308 do_write(buf
->owner
, NULL
);
1311 return buf
->position
;
1315 * Clear a log by writing a record at the head, the tail and zeroing everything
1320 struct xfs_mount
*mp
,
1326 w_buf
.owner
= tcarg
;
1327 w_buf
.length
= rounddown(w_buf
.size
, w_buf
.min_io_size
);
1328 pos
= write_log_header(source_fd
, &w_buf
, mp
);
1329 end_pos
= write_log_trailer(source_fd
, &w_buf
, mp
);
1330 w_buf
.position
= pos
;
1331 memset(w_buf
.data
, 0, w_buf
.length
);
1333 while (w_buf
.position
< end_pos
) {
1334 do_write(tcarg
, NULL
);
1335 w_buf
.position
+= w_buf
.length
;
1340 * Format the log to a particular cycle number. This is required for version 5
1341 * superblock filesystems to provide metadata LSN validity guarantees.
1345 struct xfs_mount
*mp
,
1351 int cycle
= XLOG_INIT_CYCLE
;
1354 buf
->length
= buf
->size
;
1355 buf
->position
= XFS_FSB_TO_DADDR(mp
, mp
->m_sb
.sb_logstart
) << BBSHIFT
;
1357 logstart
= XFS_FSB_TO_BB(mp
, mp
->m_sb
.sb_logstart
);
1358 length
= XFS_FSB_TO_BB(mp
, mp
->m_sb
.sb_logblocks
);
1361 * Bump the cycle number on v5 superblock filesystems to guarantee that
1362 * all existing metadata LSNs are valid (behind the current LSN) on the
1365 if (xfs_has_crc(mp
))
1366 cycle
= mp
->m_log
->l_curr_cycle
+ 1;
1369 * Format the entire log into the memory buffer and write it out. If the
1370 * write fails, mark the target inactive so the failure is reported.
1372 libxfs_log_clear(NULL
, buf
->data
, logstart
, length
, &buf
->owner
->uuid
,
1373 xfs_has_logv2(mp
) ? 2 : 1,
1374 mp
->m_sb
.sb_logsunit
, XLOG_FMT
, cycle
, true);
1375 if (do_write(buf
->owner
, buf
))
1376 target
[tcarg
->id
].state
= INACTIVE
;
1381 struct xfs_mount
*mp
)
1388 if (xfs_has_crc(mp
)) {
1389 logsize
= XFS_FSB_TO_B(mp
, mp
->m_sb
.sb_logblocks
);
1390 if (!wbuf_init(&logbuf
, logsize
, w_buf
.data_align
,
1391 w_buf
.min_io_size
, w_buf
.id
))
1395 for (i
= 0, tcarg
= targ
; i
< num_targets
; i
++) {
1396 if (xfs_has_crc(mp
))
1397 format_log(mp
, tcarg
, &logbuf
);
1399 clear_log(mp
, tcarg
);
1403 if (xfs_has_crc(mp
))