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