]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - copy/xfs_copy.c
xfsprogs: make static things static
[thirdparty/xfsprogs-dev.git] / copy / xfs_copy.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
5 */
6
7 #include "libxfs.h"
8 #include <sys/stat.h>
9 #include <sys/wait.h>
10 #include <pthread.h>
11 #include <signal.h>
12 #include <stdarg.h>
13 #include "xfs_copy.h"
14 #include "libxlog.h"
15
16 #define rounddown(x, y) (((x)/(y))*(y))
17 #define uuid_equal(s,d) (platform_uuid_compare((s),(d)) == 0)
18
19 extern int platform_check_ismounted(char *, char *, struct stat *, int);
20
21 static char *logfile_name;
22 static FILE *logerr;
23 static char LOGFILE_NAME[] = "/var/tmp/xfs_copy.log.XXXXXX";
24
25 static char *source_name;
26 static int source_fd;
27
28 static unsigned int source_blocksize; /* source filesystem blocksize */
29 static unsigned int source_sectorsize; /* source disk sectorsize */
30
31 static xfs_agblock_t first_agbno;
32
33 static uint64_t barcount[11];
34
35 static unsigned int num_targets;
36 static target_control *target;
37
38 static wbuf w_buf;
39 static wbuf btree_buf;
40
41 static unsigned int kids;
42
43 static thread_control glob_masks;
44 static thread_args *targ;
45
46 static pthread_mutex_t mainwait;
47
48 #define ACTIVE 1
49 #define INACTIVE 2
50
51 xfs_off_t write_log_trailer(int fd, wbuf *w, xfs_mount_t *mp);
52 xfs_off_t write_log_header(int fd, wbuf *w, xfs_mount_t *mp);
53 static int format_logs(struct xfs_mount *);
54
55 /* general purpose message reporting routine */
56
57 #define OUT 0x01 /* use stdout stream */
58 #define ERR 0x02 /* use stderr stream */
59 #define LOG 0x04 /* use logerr stream */
60 #define PRE 0x08 /* append strerror string */
61 #define LAST 0x10 /* final message we print */
62
63 static void
64 signal_maskfunc(int addset, int newset)
65 {
66 sigset_t set;
67
68 sigemptyset(&set);
69 sigaddset(&set, addset);
70 sigprocmask(newset, &set, NULL);
71 }
72
73 static void
74 do_message(int flags, int code, const char *fmt, ...)
75 {
76 va_list ap;
77 int eek = 0;
78
79 if (flags & LOG) {
80 va_start(ap, fmt);
81 if (vfprintf(logerr, fmt, ap) <= 0)
82 eek = 1;
83 va_end(ap);
84 }
85 if (eek)
86 flags |= ERR; /* failed, force stderr */
87 if (flags & ERR) {
88 va_start(ap, fmt);
89 vfprintf(stderr, fmt, ap);
90 va_end(ap);
91 } else if (flags & OUT) {
92 va_start(ap, fmt);
93 vfprintf(stdout, fmt, ap);
94 va_end(ap);
95 }
96
97 if (flags & PRE) {
98 do_message(flags & ~PRE, 0, ": %s\n", strerror(code));
99 if (flags & LAST)
100 fprintf(stderr,
101 _("Check logfile \"%s\" for more details\n"),
102 logfile_name);
103 }
104
105 /* logfile is broken, force a write to stderr */
106 if (eek) {
107 fprintf(stderr, _("%s: could not write to logfile \"%s\".\n"),
108 progname, logfile_name);
109 fprintf(stderr,
110 _("Aborting XFS copy -- logfile error -- reason: %s\n"),
111 strerror(errno));
112 pthread_exit(NULL);
113 }
114 }
115
116 #define do_out(args...) do_message(OUT|LOG, 0, ## args)
117 #define do_log(args...) do_message(ERR|LOG, 0, ## args)
118 #define do_warn(args...) do_message(LOG, 0, ## args)
119 #define do_error(e,s) do_message(ERR|LOG|PRE, e, s)
120 #define do_fatal(e,s) do_message(ERR|LOG|PRE|LAST, e, s)
121 #define do_vfatal(e,s,args...) do_message(ERR|LOG|PRE|LAST, e, s, ## args)
122 #define die_perror() \
123 do { \
124 do_message(ERR|LOG|PRE|LAST, errno, \
125 _("Aborting XFS copy - reason")); \
126 exit(1); \
127 } while (0)
128
129 /* workaround craziness in the xlog routines */
130 int xlog_recover_do_trans(struct xlog *log, struct xlog_recover *t, int p)
131 {
132 return 0;
133 }
134
135 static void
136 check_errors(void)
137 {
138 int i, first_error = 0;
139
140 for (i = 0; i < num_targets; i++) {
141 if (target[i].state == INACTIVE) {
142 if (first_error == 0) {
143 first_error++;
144 do_log(
145 _("THE FOLLOWING COPIES FAILED TO COMPLETE\n"));
146 }
147 do_log(" %s -- ", target[i].name);
148 if (target[i].err_type == 0)
149 do_log(_("write error"));
150 else
151 do_log(_("lseek error"));
152 do_log(_(" at offset %lld\n"), target[i].position);
153 }
154 }
155 if (first_error == 0) {
156 fprintf(stdout, _("All copies completed.\n"));
157 fflush(NULL);
158 } else {
159 fprintf(stderr, _("See \"%s\" for more details.\n"),
160 logfile_name);
161 exit(1);
162 }
163 }
164
165 /*
166 * don't have to worry about alignment and mins because those
167 * are taken care of when the buffer's read in
168 */
169 static int
170 do_write(
171 thread_args *args,
172 wbuf *buf)
173 {
174 int res;
175 int error = 0;
176
177 if (!buf)
178 buf = &w_buf;
179
180 if (target[args->id].position != buf->position) {
181 if (lseek(args->fd, buf->position, SEEK_SET) < 0) {
182 error = target[args->id].err_type = 1;
183 } else {
184 target[args->id].position = buf->position;
185 }
186 }
187
188 if ((res = write(target[args->id].fd, buf->data,
189 buf->length)) == buf->length) {
190 target[args->id].position += res;
191 } else {
192 error = 2;
193 }
194
195 if (error) {
196 target[args->id].error = errno;
197 target[args->id].position = buf->position;
198 }
199 return error;
200 }
201
202 static void *
203 begin_reader(void *arg)
204 {
205 thread_args *args = arg;
206
207 for (;;) {
208 pthread_mutex_lock(&args->wait);
209 if (do_write(args, NULL))
210 goto handle_error;
211 pthread_mutex_lock(&glob_masks.mutex);
212 if (--glob_masks.num_working == 0)
213 pthread_mutex_unlock(&mainwait);
214 pthread_mutex_unlock(&glob_masks.mutex);
215 }
216 /* NOTREACHED */
217
218 handle_error:
219 /* error will be logged by primary thread */
220
221 pthread_mutex_lock(&glob_masks.mutex);
222 target[args->id].state = INACTIVE;
223 if (--glob_masks.num_working == 0)
224 pthread_mutex_unlock(&mainwait);
225 pthread_mutex_unlock(&glob_masks.mutex);
226 pthread_exit(NULL);
227 return NULL;
228 }
229
230 static void
231 handler(int sig)
232 {
233 pid_t pid;
234 int status, i;
235
236 pid = wait(&status);
237
238 kids--;
239
240 for (i = 0; i < num_targets; i++) {
241 if (target[i].pid == pid) {
242 if (target[i].state == INACTIVE) {
243 /* thread got an I/O error */
244
245 if (target[i].err_type == 0) {
246 do_warn(
247 _("%s: write error on target %d \"%s\" at offset %lld\n"),
248 progname, i, target[i].name,
249 target[i].position);
250 } else {
251 do_warn(
252 _("%s: lseek error on target %d \"%s\" at offset %lld\n"),
253 progname, i, target[i].name,
254 target[i].position);
255 }
256
257 do_vfatal(target[i].error,
258 _("Aborting target %d - reason"), i);
259
260 if (kids == 0) {
261 do_log(
262 _("Aborting XFS copy - no more targets.\n"));
263 check_errors();
264 pthread_exit(NULL);
265 }
266
267 signal(SIGCHLD, handler);
268 return;
269 } else {
270 /* it just croaked it bigtime, log it */
271
272 do_warn(
273 _("%s: thread %d died unexpectedly, target \"%s\" incomplete\n"),
274 progname, i, target[i].name);
275 do_warn(_("%s: offset was probably %lld\n"),
276 progname, target[i].position);
277 do_fatal(target[i].error,
278 _("Aborting XFS copy - reason"));
279 pthread_exit(NULL);
280 }
281 }
282 }
283
284 /* unknown child -- something very wrong */
285
286 do_warn(_("%s: Unknown child died (should never happen!)\n"), progname);
287 die_perror();
288 pthread_exit(NULL);
289 signal(SIGCHLD, handler);
290 }
291
292 static void
293 usage(void)
294 {
295 fprintf(stderr,
296 _("Usage: %s [-bdV] [-L logfile] source target [target ...]\n"),
297 progname);
298 exit(1);
299 }
300
301 static void
302 init_bar(uint64_t source_blocks)
303 {
304 int i;
305
306 for (i = 0; i < 11; i++)
307 barcount[i] = (source_blocks/10)*i;
308 }
309
310 static int
311 bump_bar(int tenths, uint64_t numblocks)
312 {
313 static char *bar[11] = {
314 " 0% ",
315 " ... 10% ",
316 " ... 20% ",
317 " ... 30% ",
318 " ... 40% ",
319 " ... 50% ",
320 " ... 60% ",
321 " ... 70% ",
322 " ... 80% ",
323 " ... 90% ",
324 " ... 100%\n\n",
325 };
326
327 if (tenths > 10) {
328 printf("%s", bar[10]);
329 fflush(stdout);
330 } else {
331 while (tenths < 10 && numblocks > barcount[tenths]) {
332 printf("%s", bar[tenths]);
333 fflush(stdout);
334 tenths++;
335 }
336 }
337 return tenths;
338 }
339
340 static xfs_off_t source_position = -1;
341
342 static wbuf *
343 wbuf_init(wbuf *buf, int data_size, int data_align, int min_io_size, int id)
344 {
345 ASSERT(data_size % BBSIZE == 0);
346 while ((buf->data = memalign(data_align, data_size)) == NULL) {
347 data_size >>= 1;
348 if (data_size < min_io_size)
349 return NULL;
350 }
351 ASSERT(min_io_size % BBSIZE == 0);
352 buf->data_align = data_align;
353 buf->min_io_size = min_io_size;
354 buf->size = data_size;
355 buf->id = id;
356 return buf;
357 }
358
359 static void
360 read_wbuf(int fd, wbuf *buf, xfs_mount_t *mp)
361 {
362 int res = 0;
363 xfs_off_t lres = 0;
364 xfs_off_t newpos;
365 size_t diff;
366
367 newpos = rounddown(buf->position, (xfs_off_t) buf->min_io_size);
368
369 if (newpos != buf->position) {
370 diff = buf->position - newpos;
371 buf->position = newpos;
372
373 buf->length += diff;
374 }
375
376 if (source_position != buf->position) {
377 lres = lseek(fd, buf->position, SEEK_SET);
378 if (lres < 0LL) {
379 do_warn(_("%s: lseek failure at offset %lld\n"),
380 progname, source_position);
381 die_perror();
382 }
383 source_position = buf->position;
384 }
385
386 ASSERT(source_position % source_sectorsize == 0);
387
388 /* round up length for direct I/O if necessary */
389
390 if (buf->length % buf->min_io_size != 0)
391 buf->length = roundup(buf->length, buf->min_io_size);
392
393 if (buf->length > buf->size) {
394 do_warn(_("assert error: buf->length = %d, buf->size = %d\n"),
395 buf->length, buf->size);
396 exit(1);
397 }
398
399 if ((res = read(fd, buf->data, buf->length)) < 0) {
400 do_warn(_("%s: read failure at offset %lld\n"),
401 progname, source_position);
402 die_perror();
403 }
404
405 if (res < buf->length &&
406 source_position + res == mp->m_sb.sb_dblocks * source_blocksize)
407 res = buf->length;
408 else
409 ASSERT(res == buf->length);
410 source_position += res;
411 buf->length = res;
412 }
413
414 static void
415 read_ag_header(int fd, xfs_agnumber_t agno, wbuf *buf, ag_header_t *ag,
416 xfs_mount_t *mp, int blocksize, int sectorsize)
417 {
418 xfs_daddr_t off;
419 int length;
420 xfs_off_t newpos;
421 size_t diff;
422
423 /* initial settings */
424
425 diff = 0;
426 off = XFS_AG_DADDR(mp, agno, XFS_SB_DADDR);
427 buf->position = (xfs_off_t) off * (xfs_off_t) BBSIZE;
428 length = buf->length = first_agbno * blocksize;
429 if (length == 0) {
430 do_log(_("ag header buffer invalid!\n"));
431 exit(1);
432 }
433
434 /* handle alignment stuff */
435
436 newpos = rounddown(buf->position, (xfs_off_t) buf->min_io_size);
437 if (newpos != buf->position) {
438 diff = buf->position - newpos;
439 buf->position = newpos;
440 buf->length += diff;
441 }
442
443 /* round up length for direct I/O if necessary */
444
445 if (buf->length % buf->min_io_size != 0)
446 buf->length = roundup(buf->length, buf->min_io_size);
447
448 read_wbuf(fd, buf, mp);
449 ASSERT(buf->length >= length);
450
451 ag->xfs_sb = (xfs_dsb_t *) (buf->data + diff);
452 ASSERT(be32_to_cpu(ag->xfs_sb->sb_magicnum) == XFS_SB_MAGIC);
453 ag->xfs_agf = (xfs_agf_t *) (buf->data + diff + sectorsize);
454 ASSERT(be32_to_cpu(ag->xfs_agf->agf_magicnum) == XFS_AGF_MAGIC);
455 ag->xfs_agi = (xfs_agi_t *) (buf->data + diff + 2 * sectorsize);
456 ASSERT(be32_to_cpu(ag->xfs_agi->agi_magicnum) == XFS_AGI_MAGIC);
457 ag->xfs_agfl = (xfs_agfl_t *) (buf->data + diff + 3 * sectorsize);
458 }
459
460
461 static void
462 write_wbuf(void)
463 {
464 int i;
465 int badness = 0;
466
467 /* verify target threads */
468 for (i = 0; i < num_targets; i++)
469 if (target[i].state != INACTIVE)
470 glob_masks.num_working++;
471
472 /* release target threads */
473 for (i = 0; i < num_targets; i++)
474 if (target[i].state != INACTIVE)
475 pthread_mutex_unlock(&targ[i].wait); /* wake up */
476 else
477 badness++;
478
479 /*
480 * If all the targets are inactive then there won't be any io
481 * threads left to release mainwait. We're screwed, so bail out.
482 */
483 if (badness == num_targets) {
484 check_errors();
485 exit(1);
486 }
487
488 signal_maskfunc(SIGCHLD, SIG_UNBLOCK);
489 pthread_mutex_lock(&mainwait);
490 signal_maskfunc(SIGCHLD, SIG_BLOCK);
491 }
492
493 static void
494 sb_update_uuid(
495 xfs_sb_t *sb, /* Original fs superblock */
496 ag_header_t *ag_hdr, /* AG hdr to update for this copy */
497 thread_args *tcarg) /* Args for this thread, with UUID */
498 {
499 /*
500 * If this filesystem has CRCs, the original UUID is stamped into
501 * all metadata. If we don't have an existing meta_uuid field in the
502 * the original filesystem and we are changing the UUID in this copy,
503 * we must copy the original sb_uuid to the sb_meta_uuid slot and set
504 * the incompat flag for the feature on this copy.
505 */
506 if (xfs_sb_version_hascrc(sb) && !xfs_sb_version_hasmetauuid(sb) &&
507 !uuid_equal(&tcarg->uuid, &sb->sb_uuid)) {
508 __be32 feat;
509
510 feat = be32_to_cpu(ag_hdr->xfs_sb->sb_features_incompat);
511 feat |= XFS_SB_FEAT_INCOMPAT_META_UUID;
512 ag_hdr->xfs_sb->sb_features_incompat = cpu_to_be32(feat);
513 platform_uuid_copy(&ag_hdr->xfs_sb->sb_meta_uuid,
514 &sb->sb_uuid);
515 }
516
517 /* Copy the (possibly new) fs-identifier UUID into sb_uuid */
518 platform_uuid_copy(&ag_hdr->xfs_sb->sb_uuid, &tcarg->uuid);
519
520 /* We may have changed the UUID, so update the superblock CRC */
521 if (xfs_sb_version_hascrc(sb))
522 xfs_update_cksum((char *)ag_hdr->xfs_sb, sb->sb_sectsize,
523 XFS_SB_CRC_OFF);
524 }
525
526 int
527 main(int argc, char **argv)
528 {
529 int i, j;
530 int logfd;
531 int howfar = 0;
532 int open_flags;
533 xfs_off_t pos;
534 size_t length;
535 int c;
536 uint64_t size, sizeb;
537 uint64_t numblocks = 0;
538 int wblocks = 0;
539 int num_threads = 0;
540 struct dioattr d;
541 int wbuf_size;
542 int wbuf_align;
543 int wbuf_miniosize;
544 int source_is_file = 0;
545 int buffered_output = 0;
546 int duplicate = 0;
547 uint btree_levels, current_level;
548 ag_header_t ag_hdr;
549 xfs_mount_t *mp;
550 xfs_mount_t mbuf;
551 struct xlog xlog;
552 xfs_buf_t *sbp;
553 xfs_sb_t *sb;
554 xfs_agnumber_t num_ags, agno;
555 xfs_agblock_t bno;
556 xfs_daddr_t begin, next_begin, ag_begin, new_begin, ag_end;
557 struct xfs_btree_block *block;
558 xfs_alloc_ptr_t *ptr;
559 xfs_alloc_rec_t *rec_ptr;
560 extern char *optarg;
561 extern int optind;
562 libxfs_init_t xargs;
563 thread_args *tcarg;
564 struct stat statbuf;
565
566 progname = basename(argv[0]);
567
568 setlocale(LC_ALL, "");
569 bindtextdomain(PACKAGE, LOCALEDIR);
570 textdomain(PACKAGE);
571
572 while ((c = getopt(argc, argv, "bdL:V")) != EOF) {
573 switch (c) {
574 case 'b':
575 buffered_output = 1;
576 break;
577 case 'd':
578 duplicate = 1;
579 break;
580 case 'L':
581 logfile_name = optarg;
582 break;
583 case 'V':
584 printf(_("%s version %s\n"), progname, VERSION);
585 exit(0);
586 case '?':
587 usage();
588 }
589 }
590
591 if (argc - optind < 2)
592 usage();
593
594 if (logfile_name) {
595 logfd = open(logfile_name, O_CREAT|O_WRONLY|O_EXCL, 0600);
596 } else {
597 logfile_name = LOGFILE_NAME;
598 logfd = mkstemp(logfile_name);
599 }
600
601 if (logfd < 0) {
602 fprintf(stderr, _("%s: couldn't open log file \"%s\"\n"),
603 progname, logfile_name);
604 perror(_("Aborting XFS copy - reason"));
605 exit(1);
606 }
607
608 if ((logerr = fdopen(logfd, "w")) == NULL) {
609 fprintf(stderr, _("%s: couldn't set up logfile stream\n"),
610 progname);
611 perror(_("Aborting XFS copy - reason"));
612 exit(1);
613 }
614
615 source_name = argv[optind];
616 source_fd = -1;
617 optind++;
618
619 num_targets = argc - optind;
620 if ((target = malloc(sizeof(target_control) * num_targets)) == NULL) {
621 do_log(_("Couldn't allocate target array\n"));
622 die_perror();
623 }
624 for (i = 0; optind < argc; i++, optind++) {
625 target[i].name = argv[optind];
626 target[i].fd = -1;
627 target[i].position = -1;
628 target[i].state = INACTIVE;
629 target[i].error = 0;
630 target[i].err_type = 0;
631 }
632
633 /* open up source -- is it a file? */
634
635 open_flags = O_RDONLY;
636
637 if ((source_fd = open(source_name, open_flags)) < 0) {
638 do_log(_("%s: couldn't open source \"%s\"\n"),
639 progname, source_name);
640 die_perror();
641 }
642
643 if (fstat(source_fd, &statbuf) < 0) {
644 do_log(_("%s: couldn't stat source \"%s\"\n"),
645 progname, source_name);
646 die_perror();
647 }
648
649 if (S_ISREG(statbuf.st_mode))
650 source_is_file = 1;
651
652 if (source_is_file && platform_test_xfs_fd(source_fd)) {
653 if (fcntl(source_fd, F_SETFL, open_flags | O_DIRECT) < 0) {
654 do_log(_("%s: Cannot set direct I/O flag on \"%s\".\n"),
655 progname, source_name);
656 die_perror();
657 }
658 if (xfsctl(source_name, source_fd, XFS_IOC_DIOINFO, &d) < 0) {
659 do_log(_("%s: xfsctl on file \"%s\" failed.\n"),
660 progname, source_name);
661 die_perror();
662 }
663
664 wbuf_align = d.d_mem;
665 wbuf_size = min(d.d_maxiosz, 1 * 1024 * 1024);
666 wbuf_miniosize = d.d_miniosz;
667 } else {
668 /* set arbitrary I/O params, miniosize at least 1 disk block */
669
670 wbuf_align = getpagesize();
671 wbuf_size = 1 * 1024 * 1024;
672 wbuf_miniosize = -1; /* set after mounting source fs */
673 }
674
675 if (!source_is_file) {
676 /*
677 * check to make sure a filesystem isn't mounted
678 * on the device
679 */
680 if (platform_check_ismounted(source_name, NULL, &statbuf, 0)) {
681 do_log(
682 _("%s: Warning -- a filesystem is mounted on the source device.\n"),
683 progname);
684 do_log(
685 _("\t\tGenerated copies may be corrupt unless the source is\n"));
686 do_log(
687 _("\t\tunmounted or mounted read-only. Copy proceeding...\n"));
688 }
689 }
690
691 /* prepare the libxfs_init structure */
692
693 memset(&xargs, 0, sizeof(xargs));
694 xargs.isdirect = LIBXFS_DIRECT;
695 xargs.isreadonly = LIBXFS_ISREADONLY;
696
697 if (source_is_file) {
698 xargs.dname = source_name;
699 xargs.disfile = 1;
700 } else
701 xargs.volname = source_name;
702
703 if (!libxfs_init(&xargs)) {
704 do_log(_("%s: couldn't initialize XFS library\n"
705 "%s: Aborting.\n"), progname, progname);
706 exit(1);
707 }
708
709 memset(&mbuf, 0, sizeof(xfs_mount_t));
710
711 /* We don't yet know the sector size, so read maximal size */
712 libxfs_buftarg_init(&mbuf, xargs.ddev, xargs.logdev, xargs.rtdev);
713 sbp = libxfs_readbuf(mbuf.m_ddev_targp, XFS_SB_DADDR,
714 1 << (XFS_MAX_SECTORSIZE_LOG - BBSHIFT), 0, NULL);
715 sb = &mbuf.m_sb;
716 libxfs_sb_from_disk(sb, XFS_BUF_TO_SBP(sbp));
717
718 /* Do it again, now with proper length and verifier */
719 libxfs_putbuf(sbp);
720 libxfs_purgebuf(sbp);
721 sbp = libxfs_readbuf(mbuf.m_ddev_targp, XFS_SB_DADDR,
722 1 << (sb->sb_sectlog - BBSHIFT),
723 0, &xfs_sb_buf_ops);
724 libxfs_putbuf(sbp);
725
726 mp = libxfs_mount(&mbuf, sb, xargs.ddev, xargs.logdev, xargs.rtdev, 0);
727 if (mp == NULL) {
728 do_log(_("%s: %s filesystem failed to initialize\n"
729 "%s: Aborting.\n"), progname, source_name, progname);
730 exit(1);
731 } else if (mp->m_sb.sb_inprogress) {
732 do_log(_("%s %s filesystem failed to initialize\n"
733 "%s: Aborting.\n"), progname, source_name, progname);
734 exit(1);
735 } else if (mp->m_sb.sb_logstart == 0) {
736 do_log(_("%s: %s has an external log.\n%s: Aborting.\n"),
737 progname, source_name, progname);
738 exit(1);
739 } else if (mp->m_sb.sb_rextents != 0) {
740 do_log(_("%s: %s has a real-time section.\n"
741 "%s: Aborting.\n"), progname, source_name, progname);
742 exit(1);
743 }
744
745
746 /*
747 * Set up the mount pointer to access the log and check whether the log
748 * is clean. Fail on a dirty or corrupt log in non-duplicate mode
749 * because the log is formatted as part of the copy and we don't want to
750 * destroy data. We also need the current log cycle to format v5
751 * superblock logs correctly.
752 */
753 memset(&xlog, 0, sizeof(struct xlog));
754 mp->m_log = &xlog;
755 c = xlog_is_dirty(mp, mp->m_log, &xargs, 0);
756 if (!duplicate) {
757 if (c == 1) {
758 do_log(_(
759 "Error: source filesystem log is dirty. Mount the filesystem to replay the\n"
760 "log, unmount and retry xfs_copy.\n"));
761 exit(1);
762 } else if (c < 0) {
763 do_log(_(
764 "Error: could not determine the log head or tail of the source filesystem.\n"
765 "Mount the filesystem to replay the log or run xfs_repair.\n"));
766 exit(1);
767 }
768 }
769
770 source_blocksize = mp->m_sb.sb_blocksize;
771 source_sectorsize = mp->m_sb.sb_sectsize;
772
773 if (wbuf_miniosize == -1)
774 wbuf_miniosize = source_sectorsize;
775
776 ASSERT(source_blocksize % source_sectorsize == 0);
777 ASSERT(source_sectorsize % BBSIZE == 0);
778
779 if (source_blocksize < source_sectorsize) {
780 do_log(_("Error: filesystem block size is smaller than the"
781 " disk sectorsize.\nAborting XFS copy now.\n"));
782 exit(1);
783 }
784
785 first_agbno = XFS_AGFL_BLOCK(mp) + 1;
786
787 /* now open targets */
788
789 open_flags = O_RDWR;
790
791 for (i = 0; i < num_targets; i++) {
792 int write_last_block = 0;
793
794 if (stat(target[i].name, &statbuf) < 0) {
795 /* ok, assume it's a file and create it */
796
797 do_out(_("Creating file %s\n"), target[i].name);
798
799 open_flags |= O_CREAT;
800 if (!buffered_output)
801 open_flags |= O_DIRECT;
802 write_last_block = 1;
803 } else if (S_ISREG(statbuf.st_mode)) {
804 open_flags |= O_TRUNC;
805 if (!buffered_output)
806 open_flags |= O_DIRECT;
807 write_last_block = 1;
808 } else {
809 /*
810 * check to make sure a filesystem isn't mounted
811 * on the device
812 */
813 if (platform_check_ismounted(target[i].name,
814 NULL, &statbuf, 0)) {
815 do_log(_("%s: a filesystem is mounted "
816 "on target device \"%s\".\n"
817 "%s cannot copy to mounted filesystems."
818 " Aborting\n"),
819 progname, target[i].name, progname);
820 exit(1);
821 }
822 }
823
824 target[i].fd = open(target[i].name, open_flags, 0644);
825 if (target[i].fd < 0) {
826 do_log(_("%s: couldn't open target \"%s\"\n"),
827 progname, target[i].name);
828 die_perror();
829 }
830
831 if (write_last_block) {
832 /* ensure regular files are correctly sized */
833
834 if (ftruncate(target[i].fd, mp->m_sb.sb_dblocks *
835 source_blocksize)) {
836 do_log(_("%s: cannot grow data section.\n"),
837 progname);
838 die_perror();
839 }
840 if (platform_test_xfs_fd(target[i].fd)) {
841 if (xfsctl(target[i].name, target[i].fd,
842 XFS_IOC_DIOINFO, &d) < 0) {
843 do_log(
844 _("%s: xfsctl on \"%s\" failed.\n"),
845 progname, target[i].name);
846 die_perror();
847 } else {
848 wbuf_align = max(wbuf_align, d.d_mem);
849 wbuf_size = min(d.d_maxiosz, wbuf_size);
850 wbuf_miniosize = max(d.d_miniosz,
851 wbuf_miniosize);
852 }
853 }
854 } else {
855 char *lb[XFS_MAX_SECTORSIZE] = { NULL };
856 off64_t off;
857
858 /* ensure device files are sufficiently large */
859
860 off = mp->m_sb.sb_dblocks * source_blocksize;
861 off -= sizeof(lb);
862 if (pwrite(target[i].fd, lb, sizeof(lb), off) < 0) {
863 do_log(_("%s: failed to write last block\n"),
864 progname);
865 do_log(_("\tIs target \"%s\" too small?\n"),
866 target[i].name);
867 die_perror();
868 }
869 }
870 }
871
872 /* initialize locks and bufs */
873
874 if (pthread_mutex_init(&glob_masks.mutex, NULL) != 0) {
875 do_log(_("Couldn't initialize global thread mask\n"));
876 die_perror();
877 }
878 glob_masks.num_working = 0;
879
880 if (wbuf_init(&w_buf, wbuf_size, wbuf_align,
881 wbuf_miniosize, 0) == NULL) {
882 do_log(_("Error initializing wbuf 0\n"));
883 die_perror();
884 }
885
886 wblocks = wbuf_size / BBSIZE;
887
888 if (wbuf_init(&btree_buf, max(source_blocksize, wbuf_miniosize),
889 wbuf_align, wbuf_miniosize, 1) == NULL) {
890 do_log(_("Error initializing btree buf 1\n"));
891 die_perror();
892 }
893
894 if (pthread_mutex_init(&mainwait,NULL) != 0) {
895 do_log(_("Error creating first semaphore.\n"));
896 die_perror();
897 exit(1);
898 }
899 /* need to start out blocking */
900 pthread_mutex_lock(&mainwait);
901
902 /* set up sigchild signal handler */
903
904 signal(SIGCHLD, handler);
905 signal_maskfunc(SIGCHLD, SIG_BLOCK);
906
907 /* make children */
908
909 if ((targ = malloc(num_targets * sizeof(thread_args))) == NULL) {
910 do_log(_("Couldn't malloc space for thread args\n"));
911 die_perror();
912 exit(1);
913 }
914
915 for (i = 0, tcarg = targ; i < num_targets; i++, tcarg++) {
916 if (!duplicate)
917 platform_uuid_generate(&tcarg->uuid);
918 else
919 platform_uuid_copy(&tcarg->uuid, &mp->m_sb.sb_uuid);
920
921 if (pthread_mutex_init(&tcarg->wait, NULL) != 0) {
922 do_log(_("Error creating thread mutex %d\n"), i);
923 die_perror();
924 exit(1);
925 }
926 /* need to start out blocking */
927 pthread_mutex_lock(&tcarg->wait);
928 }
929
930 for (i = 0, tcarg = targ; i < num_targets; i++, tcarg++) {
931 tcarg->id = i;
932 tcarg->fd = target[i].fd;
933
934 target[i].state = ACTIVE;
935 num_threads++;
936
937 if (pthread_create(&target[i].pid, NULL,
938 begin_reader, (void *)tcarg)) {
939 do_log(_("Error creating thread for target %d\n"), i);
940 die_perror();
941 }
942 }
943
944 ASSERT(num_targets == num_threads);
945
946 /* set up statistics */
947
948 num_ags = mp->m_sb.sb_agcount;
949
950 init_bar(mp->m_sb.sb_blocksize / BBSIZE
951 * ((uint64_t)mp->m_sb.sb_dblocks
952 - (uint64_t)mp->m_sb.sb_fdblocks + 10 * num_ags));
953
954 kids = num_targets;
955
956 for (agno = 0; agno < num_ags && kids > 0; agno++) {
957 /* read in first blocks of the ag */
958
959 read_ag_header(source_fd, agno, &w_buf, &ag_hdr, mp,
960 source_blocksize, source_sectorsize);
961
962 /* set the in_progress bit for the first AG */
963
964 if (agno == 0)
965 ag_hdr.xfs_sb->sb_inprogress = 1;
966
967 /* save what we need (agf) in the btree buffer */
968
969 memmove(btree_buf.data, ag_hdr.xfs_agf, source_sectorsize);
970 ag_hdr.xfs_agf = (xfs_agf_t *) btree_buf.data;
971 btree_buf.length = source_blocksize;
972
973 /* write the ag header out */
974
975 write_wbuf();
976
977 /* traverse btree until we get to the leftmost leaf node */
978
979 bno = be32_to_cpu(ag_hdr.xfs_agf->agf_roots[XFS_BTNUM_BNOi]);
980 current_level = 0;
981 btree_levels = be32_to_cpu(ag_hdr.xfs_agf->
982 agf_levels[XFS_BTNUM_BNOi]);
983
984 ag_end = XFS_AGB_TO_DADDR(mp, agno,
985 be32_to_cpu(ag_hdr.xfs_agf->agf_length) - 1)
986 + source_blocksize / BBSIZE;
987
988 for (;;) {
989 /* none of this touches the w_buf buffer */
990
991 if (current_level >= btree_levels) {
992 do_log(
993 _("Error: current level %d >= btree levels %d\n"),
994 current_level, btree_levels);
995 exit(1);
996 }
997
998 current_level++;
999
1000 btree_buf.position = pos = (xfs_off_t)
1001 XFS_AGB_TO_DADDR(mp,agno,bno) << BBSHIFT;
1002 btree_buf.length = source_blocksize;
1003
1004 read_wbuf(source_fd, &btree_buf, mp);
1005 block = (struct xfs_btree_block *)
1006 ((char *)btree_buf.data +
1007 pos - btree_buf.position);
1008
1009 if (be32_to_cpu(block->bb_magic) !=
1010 (xfs_sb_version_hascrc(&mp->m_sb) ?
1011 XFS_ABTB_CRC_MAGIC : XFS_ABTB_MAGIC)) {
1012 do_log(_("Bad btree magic 0x%x\n"),
1013 be32_to_cpu(block->bb_magic));
1014 exit(1);
1015 }
1016
1017 if (be16_to_cpu(block->bb_level) == 0)
1018 break;
1019
1020 ptr = XFS_ALLOC_PTR_ADDR(mp, block, 1,
1021 mp->m_alloc_mxr[1]);
1022 bno = be32_to_cpu(ptr[0]);
1023 }
1024
1025 /* align first data copy but don't overwrite ag header */
1026
1027 pos = w_buf.position >> BBSHIFT;
1028 length = w_buf.length >> BBSHIFT;
1029 next_begin = pos + length;
1030 ag_begin = next_begin;
1031
1032 ASSERT(w_buf.position % source_sectorsize == 0);
1033
1034 /* handle the rest of the ag */
1035
1036 for (;;) {
1037 if (be16_to_cpu(block->bb_level) != 0) {
1038 do_log(
1039 _("WARNING: source filesystem inconsistent.\n"));
1040 do_log(
1041 _(" A leaf btree rec isn't a leaf. Aborting now.\n"));
1042 exit(1);
1043 }
1044
1045 rec_ptr = XFS_ALLOC_REC_ADDR(mp, block, 1);
1046 for (i = 0; i < be16_to_cpu(block->bb_numrecs);
1047 i++, rec_ptr++) {
1048 /* calculate in daddr's */
1049
1050 begin = next_begin;
1051
1052 /*
1053 * protect against pathological case of a
1054 * hole right after the ag header in a
1055 * mis-aligned case
1056 */
1057
1058 if (begin < ag_begin)
1059 begin = ag_begin;
1060
1061 /*
1062 * round size up to ensure we copy a
1063 * range bigger than required
1064 */
1065
1066 sizeb = XFS_AGB_TO_DADDR(mp, agno,
1067 be32_to_cpu(rec_ptr->ar_startblock)) -
1068 begin;
1069 size = roundup(sizeb <<BBSHIFT, wbuf_miniosize);
1070 if (size > 0) {
1071 /* copy extent */
1072
1073 w_buf.position = (xfs_off_t)
1074 begin << BBSHIFT;
1075
1076 while (size > 0) {
1077 /*
1078 * let lower layer do alignment
1079 */
1080 if (size > w_buf.size) {
1081 w_buf.length = w_buf.size;
1082 size -= w_buf.size;
1083 sizeb -= wblocks;
1084 numblocks += wblocks;
1085 } else {
1086 w_buf.length = size;
1087 numblocks += sizeb;
1088 size = 0;
1089 }
1090
1091 read_wbuf(source_fd, &w_buf, mp);
1092 write_wbuf();
1093
1094 w_buf.position += w_buf.length;
1095
1096 howfar = bump_bar(
1097 howfar, numblocks);
1098 }
1099 }
1100
1101 /* round next starting point down */
1102
1103 new_begin = XFS_AGB_TO_DADDR(mp, agno,
1104 be32_to_cpu(rec_ptr->ar_startblock) +
1105 be32_to_cpu(rec_ptr->ar_blockcount));
1106 next_begin = rounddown(new_begin,
1107 w_buf.min_io_size >> BBSHIFT);
1108 }
1109
1110 if (be32_to_cpu(block->bb_u.s.bb_rightsib) == NULLAGBLOCK)
1111 break;
1112
1113 /* read in next btree record block */
1114
1115 btree_buf.position = pos = (xfs_off_t)
1116 XFS_AGB_TO_DADDR(mp, agno, be32_to_cpu(
1117 block->bb_u.s.bb_rightsib)) << BBSHIFT;
1118 btree_buf.length = source_blocksize;
1119
1120 /* let read_wbuf handle alignment */
1121
1122 read_wbuf(source_fd, &btree_buf, mp);
1123
1124 block = (struct xfs_btree_block *)
1125 ((char *) btree_buf.data +
1126 pos - btree_buf.position);
1127
1128 ASSERT(be32_to_cpu(block->bb_magic) == XFS_ABTB_MAGIC ||
1129 be32_to_cpu(block->bb_magic) == XFS_ABTB_CRC_MAGIC);
1130 }
1131
1132 /*
1133 * write out range of used blocks after last range
1134 * of free blocks in AG
1135 */
1136 if (next_begin < ag_end) {
1137 begin = next_begin;
1138
1139 sizeb = ag_end - begin;
1140 size = roundup(sizeb << BBSHIFT, wbuf_miniosize);
1141
1142 if (size > 0) {
1143 /* copy extent */
1144
1145 w_buf.position = (xfs_off_t) begin << BBSHIFT;
1146
1147 while (size > 0) {
1148 /*
1149 * let lower layer do alignment
1150 */
1151 if (size > w_buf.size) {
1152 w_buf.length = w_buf.size;
1153 size -= w_buf.size;
1154 sizeb -= wblocks;
1155 numblocks += wblocks;
1156 } else {
1157 w_buf.length = size;
1158 numblocks += sizeb;
1159 size = 0;
1160 }
1161
1162 read_wbuf(source_fd, &w_buf, mp);
1163 write_wbuf();
1164
1165 w_buf.position += w_buf.length;
1166
1167 howfar = bump_bar(howfar, numblocks);
1168 }
1169 }
1170 }
1171 }
1172
1173 if (kids > 0) {
1174 if (!duplicate)
1175 /* write a clean log using the specified UUID */
1176 format_logs(mp);
1177 else
1178 num_ags = 1;
1179
1180 /* reread and rewrite superblocks (UUID and in-progress) */
1181 /* [backwards, so inprogress bit only updated when done] */
1182
1183 for (i = num_ags - 1; i >= 0; i--) {
1184 read_ag_header(source_fd, i, &w_buf, &ag_hdr, mp,
1185 source_blocksize, source_sectorsize);
1186 if (i == 0)
1187 ag_hdr.xfs_sb->sb_inprogress = 0;
1188
1189 /* do each thread in turn, each has its own UUID */
1190
1191 for (j = 0, tcarg = targ; j < num_targets; j++) {
1192 sb_update_uuid(sb, &ag_hdr, tcarg);
1193 do_write(tcarg, NULL);
1194 tcarg++;
1195 }
1196 }
1197
1198 bump_bar(100, 0);
1199 }
1200
1201 check_errors();
1202 libxfs_umount(mp);
1203 libxfs_destroy();
1204
1205 return 0;
1206 }
1207
1208 static char *
1209 next_log_chunk(char *p, int offset, void *private)
1210 {
1211 wbuf *buf = (wbuf *)private;
1212
1213 if (buf->length < (int)(p - buf->data) + offset) {
1214 /* need to flush this one, then start afresh */
1215
1216 do_write(buf->owner, NULL);
1217 memset(buf->data, 0, buf->length);
1218 return buf->data;
1219 }
1220 return p + offset;
1221 }
1222
1223 /*
1224 * Writes a log header at the start of the log (with the real
1225 * filesystem UUID embedded into it), and writes to all targets.
1226 *
1227 * Returns the next buffer-length-aligned disk address.
1228 */
1229 xfs_off_t
1230 write_log_header(int fd, wbuf *buf, xfs_mount_t *mp)
1231 {
1232 char *p = buf->data;
1233 xfs_off_t logstart;
1234 int offset;
1235
1236 logstart = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart) << BBSHIFT;
1237 buf->position = rounddown(logstart, (xfs_off_t)buf->length);
1238
1239 memset(p, 0, buf->size);
1240 if (logstart % buf->length) { /* unaligned */
1241 read_wbuf(fd, buf, mp);
1242 offset = logstart - buf->position;
1243 p += offset;
1244 memset(p, 0, buf->length - offset);
1245 }
1246
1247 offset = libxfs_log_header(p, &buf->owner->uuid,
1248 xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1,
1249 mp->m_sb.sb_logsunit, XLOG_FMT, NULLCOMMITLSN,
1250 NULLCOMMITLSN, next_log_chunk, buf);
1251 do_write(buf->owner, NULL);
1252
1253 return roundup(logstart + offset, buf->length);
1254 }
1255
1256 /*
1257 * May do an aligned read of the last buffer in the log (& zero
1258 * the start of that buffer). Returns the disk address at the
1259 * end of last aligned buffer in the log.
1260 */
1261 xfs_off_t
1262 write_log_trailer(int fd, wbuf *buf, xfs_mount_t *mp)
1263 {
1264 xfs_off_t logend;
1265 int offset;
1266
1267 logend = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart) << BBSHIFT;
1268 logend += XFS_FSB_TO_B(mp, mp->m_sb.sb_logblocks);
1269
1270 buf->position = rounddown(logend, (xfs_off_t)buf->length);
1271
1272 if (logend % buf->length) { /* unaligned */
1273 read_wbuf(fd, buf, mp);
1274 offset = (int)(logend - buf->position);
1275 memset(buf->data, 0, offset);
1276 do_write(buf->owner, NULL);
1277 }
1278
1279 return buf->position;
1280 }
1281
1282 /*
1283 * Clear a log by writing a record at the head, the tail and zeroing everything
1284 * in between.
1285 */
1286 static void
1287 clear_log(
1288 struct xfs_mount *mp,
1289 thread_args *tcarg)
1290 {
1291 xfs_off_t pos;
1292 xfs_off_t end_pos;
1293
1294 w_buf.owner = tcarg;
1295 w_buf.length = rounddown(w_buf.size, w_buf.min_io_size);
1296 pos = write_log_header(source_fd, &w_buf, mp);
1297 end_pos = write_log_trailer(source_fd, &w_buf, mp);
1298 w_buf.position = pos;
1299 memset(w_buf.data, 0, w_buf.length);
1300
1301 while (w_buf.position < end_pos) {
1302 do_write(tcarg, NULL);
1303 w_buf.position += w_buf.length;
1304 }
1305 }
1306
1307 /*
1308 * Format the log to a particular cycle number. This is required for version 5
1309 * superblock filesystems to provide metadata LSN validity guarantees.
1310 */
1311 static void
1312 format_log(
1313 struct xfs_mount *mp,
1314 thread_args *tcarg,
1315 wbuf *buf)
1316 {
1317 int logstart;
1318 int length;
1319 int cycle = XLOG_INIT_CYCLE;
1320
1321 buf->owner = tcarg;
1322 buf->length = buf->size;
1323 buf->position = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart) << BBSHIFT;
1324
1325 logstart = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logstart);
1326 length = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
1327
1328 /*
1329 * Bump the cycle number on v5 superblock filesystems to guarantee that
1330 * all existing metadata LSNs are valid (behind the current LSN) on the
1331 * target fs.
1332 */
1333 if (xfs_sb_version_hascrc(&mp->m_sb))
1334 cycle = mp->m_log->l_curr_cycle + 1;
1335
1336 /*
1337 * Format the entire log into the memory buffer and write it out. If the
1338 * write fails, mark the target inactive so the failure is reported.
1339 */
1340 libxfs_log_clear(NULL, buf->data, logstart, length, &buf->owner->uuid,
1341 xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1,
1342 mp->m_sb.sb_logsunit, XLOG_FMT, cycle, true);
1343 if (do_write(buf->owner, buf))
1344 target[tcarg->id].state = INACTIVE;
1345 }
1346
1347 static int
1348 format_logs(
1349 struct xfs_mount *mp)
1350 {
1351 thread_args *tcarg;
1352 int i;
1353 wbuf logbuf;
1354 int logsize;
1355
1356 if (xfs_sb_version_hascrc(&mp->m_sb)) {
1357 logsize = XFS_FSB_TO_B(mp, mp->m_sb.sb_logblocks);
1358 if (!wbuf_init(&logbuf, logsize, w_buf.data_align,
1359 w_buf.min_io_size, w_buf.id))
1360 return -ENOMEM;
1361 }
1362
1363 for (i = 0, tcarg = targ; i < num_targets; i++) {
1364 if (xfs_sb_version_hascrc(&mp->m_sb))
1365 format_log(mp, tcarg, &logbuf);
1366 else
1367 clear_log(mp, tcarg);
1368 tcarg++;
1369 }
1370
1371 if (xfs_sb_version_hascrc(&mp->m_sb))
1372 free(logbuf.data);
1373
1374 return 0;
1375 }