]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - copy/xfs_copy.c
xfs_copy: use POSIX signal API
[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 stat64 *, 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(_("lseek64 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 (lseek64(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: lseek64 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 = lseek64(fd, buf->position, SEEK_SET);
392 if (lres < 0LL) {
393 do_warn(_("%s: lseek64 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
480 /* verify target threads */
481 for (i = 0; i < num_targets; i++)
482 if (target[i].state != INACTIVE)
483 glob_masks.num_working++;
484
485 /* release target threads */
486 for (i = 0; i < num_targets; i++)
487 if (target[i].state != INACTIVE)
488 pthread_mutex_unlock(&targ[i].wait); /* wake up */
489
490 signal_maskfunc(SIGCHLD, SIG_UNBLOCK);
491 pthread_mutex_lock(&mainwait);
492 signal_maskfunc(SIGCHLD, SIG_BLOCK);
493 }
494
495 void
496 sb_update_uuid(
497 xfs_sb_t *sb,
498 ag_header_t *ag_hdr,
499 thread_args *tcarg)
500 {
501 /*
502 * If this filesystem has CRCs, the original UUID is stamped into
503 * all metadata. If we are changing the UUID in the copy, we need
504 * to copy the original UUID into the meta_uuid slot and set the
505 * set the incompat flag if that hasn't already been done.
506 */
507 if (!uuid_equal(&tcarg->uuid, &ag_hdr->xfs_sb->sb_uuid) &&
508 xfs_sb_version_hascrc(sb) && !xfs_sb_version_hasmetauuid(sb)) {
509 __be32 feat;
510
511 feat = be32_to_cpu(ag_hdr->xfs_sb->sb_features_incompat);
512 feat |= XFS_SB_FEAT_INCOMPAT_META_UUID;
513 ag_hdr->xfs_sb->sb_features_incompat = cpu_to_be32(feat);
514 platform_uuid_copy(&ag_hdr->xfs_sb->sb_meta_uuid,
515 &ag_hdr->xfs_sb->sb_uuid);
516 }
517
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 howfar = 0;
531 int open_flags;
532 xfs_off_t pos;
533 size_t length;
534 int c;
535 __uint64_t size, sizeb;
536 __uint64_t numblocks = 0;
537 int wblocks = 0;
538 int num_threads = 0;
539 struct dioattr d;
540 int wbuf_size;
541 int wbuf_align;
542 int wbuf_miniosize;
543 int source_is_file = 0;
544 int buffered_output = 0;
545 int duplicate = 0;
546 uint btree_levels, current_level;
547 ag_header_t ag_hdr;
548 xfs_mount_t *mp;
549 xfs_mount_t mbuf;
550 struct xlog xlog;
551 xfs_buf_t *sbp;
552 xfs_sb_t *sb;
553 xfs_agnumber_t num_ags, agno;
554 xfs_agblock_t bno;
555 xfs_daddr_t begin, next_begin, ag_begin, new_begin, ag_end;
556 struct xfs_btree_block *block;
557 xfs_alloc_ptr_t *ptr;
558 xfs_alloc_rec_t *rec_ptr;
559 extern char *optarg;
560 extern int optind;
561 libxfs_init_t xargs;
562 thread_args *tcarg;
563 struct stat64 statbuf;
564
565 progname = basename(argv[0]);
566
567 setlocale(LC_ALL, "");
568 bindtextdomain(PACKAGE, LOCALEDIR);
569 textdomain(PACKAGE);
570
571 while ((c = getopt(argc, argv, "bdL:V")) != EOF) {
572 switch (c) {
573 case 'b':
574 buffered_output = 1;
575 break;
576 case 'd':
577 duplicate = 1;
578 break;
579 case 'L':
580 logfile_name = optarg;
581 break;
582 case 'V':
583 printf(_("%s version %s\n"), progname, VERSION);
584 exit(0);
585 case '?':
586 usage();
587 }
588 }
589
590 if (argc - optind < 2)
591 usage();
592
593 if (logfile_name) {
594 logfd = open(logfile_name, O_CREAT|O_WRONLY|O_EXCL, 0600);
595 } else {
596 logfile_name = LOGFILE_NAME;
597 logfd = mkstemp(logfile_name);
598 }
599
600 if (logfd < 0) {
601 fprintf(stderr, _("%s: couldn't open log file \"%s\"\n"),
602 progname, logfile_name);
603 perror(_("Aborting XFS copy - reason"));
604 exit(1);
605 }
606
607 if ((logerr = fdopen(logfd, "w")) == NULL) {
608 fprintf(stderr, _("%s: couldn't set up logfile stream\n"),
609 progname);
610 perror(_("Aborting XFS copy - reason"));
611 exit(1);
612 }
613
614 source_name = argv[optind];
615 source_fd = -1;
616 optind++;
617
618 num_targets = argc - optind;
619 if ((target = malloc(sizeof(target_control) * num_targets)) == NULL) {
620 do_log(_("Couldn't allocate target array\n"));
621 die_perror();
622 }
623 for (i = 0; optind < argc; i++, optind++) {
624 target[i].name = argv[optind];
625 target[i].fd = -1;
626 target[i].position = -1;
627 target[i].state = INACTIVE;
628 target[i].error = 0;
629 target[i].err_type = 0;
630 }
631
632 parent_pid = getpid();
633
634 /* open up source -- is it a file? */
635
636 open_flags = O_RDONLY;
637
638 if ((source_fd = open(source_name, open_flags)) < 0) {
639 do_log(_("%s: couldn't open source \"%s\"\n"),
640 progname, source_name);
641 die_perror();
642 }
643
644 if (fstat64(source_fd, &statbuf) < 0) {
645 do_log(_("%s: couldn't stat source \"%s\"\n"),
646 progname, source_name);
647 die_perror();
648 }
649
650 if (S_ISREG(statbuf.st_mode))
651 source_is_file = 1;
652
653 if (source_is_file && platform_test_xfs_fd(source_fd)) {
654 if (fcntl(source_fd, F_SETFL, open_flags | O_DIRECT) < 0) {
655 do_log(_("%s: Cannot set direct I/O flag on \"%s\".\n"),
656 progname, source_name);
657 die_perror();
658 }
659 if (xfsctl(source_name, source_fd, XFS_IOC_DIOINFO, &d) < 0) {
660 do_log(_("%s: xfsctl on file \"%s\" failed.\n"),
661 progname, source_name);
662 die_perror();
663 }
664
665 wbuf_align = d.d_mem;
666 wbuf_size = MIN(d.d_maxiosz, 1 * 1024 * 1024);
667 wbuf_miniosize = d.d_miniosz;
668 } else {
669 /* set arbitrary I/O params, miniosize at least 1 disk block */
670
671 wbuf_align = getpagesize();
672 wbuf_size = 1 * 1024 * 1024;
673 wbuf_miniosize = -1; /* set after mounting source fs */
674 }
675
676 if (!source_is_file) {
677 /*
678 * check to make sure a filesystem isn't mounted
679 * on the device
680 */
681 if (platform_check_ismounted(source_name, NULL, &statbuf, 0)) {
682 do_log(
683 _("%s: Warning -- a filesystem is mounted on the source device.\n"),
684 progname);
685 do_log(
686 _("\t\tGenerated copies may be corrupt unless the source is\n"));
687 do_log(
688 _("\t\tunmounted or mounted read-only. Copy proceeding...\n"));
689 }
690 }
691
692 /* prepare the libxfs_init structure */
693
694 memset(&xargs, 0, sizeof(xargs));
695 xargs.isdirect = LIBXFS_DIRECT;
696 xargs.isreadonly = LIBXFS_ISREADONLY;
697
698 if (source_is_file) {
699 xargs.dname = source_name;
700 xargs.disfile = 1;
701 } else
702 xargs.volname = source_name;
703
704 if (!libxfs_init(&xargs)) {
705 do_log(_("%s: couldn't initialize XFS library\n"
706 "%s: Aborting.\n"), progname, progname);
707 exit(1);
708 }
709
710 memset(&mbuf, 0, sizeof(xfs_mount_t));
711
712 /* We don't yet know the sector size, so read maximal size */
713 libxfs_buftarg_init(&mbuf, xargs.ddev, xargs.logdev, xargs.rtdev);
714 sbp = libxfs_readbuf(mbuf.m_ddev_targp, XFS_SB_DADDR,
715 1 << (XFS_MAX_SECTORSIZE_LOG - BBSHIFT), 0, NULL);
716 sb = &mbuf.m_sb;
717 libxfs_sb_from_disk(sb, XFS_BUF_TO_SBP(sbp));
718
719 /* Do it again, now with proper length and verifier */
720 libxfs_putbuf(sbp);
721 libxfs_purgebuf(sbp);
722 sbp = libxfs_readbuf(mbuf.m_ddev_targp, XFS_SB_DADDR,
723 1 << (sb->sb_sectlog - BBSHIFT),
724 0, &xfs_sb_buf_ops);
725 libxfs_putbuf(sbp);
726
727 mp = libxfs_mount(&mbuf, sb, xargs.ddev, xargs.logdev, xargs.rtdev, 0);
728 if (mp == NULL) {
729 do_log(_("%s: %s filesystem failed to initialize\n"
730 "%s: Aborting.\n"), progname, source_name, progname);
731 exit(1);
732 } else if (mp->m_sb.sb_inprogress) {
733 do_log(_("%s %s filesystem failed to initialize\n"
734 "%s: Aborting.\n"), progname, source_name, progname);
735 exit(1);
736 } else if (mp->m_sb.sb_logstart == 0) {
737 do_log(_("%s: %s has an external log.\n%s: Aborting.\n"),
738 progname, source_name, progname);
739 exit(1);
740 } else if (mp->m_sb.sb_rextents != 0) {
741 do_log(_("%s: %s has a real-time section.\n"
742 "%s: Aborting.\n"), progname, source_name, progname);
743 exit(1);
744 }
745
746
747 /*
748 * Set up the mount pointer to access the log and check whether the log
749 * is clean. Fail on a dirty or corrupt log in non-duplicate mode
750 * because the log is formatted as part of the copy and we don't want to
751 * destroy data. We also need the current log cycle to format v5
752 * superblock logs correctly.
753 */
754 memset(&xlog, 0, sizeof(struct xlog));
755 mp->m_log = &xlog;
756 c = xlog_is_dirty(mp, mp->m_log, &xargs, 0);
757 if (!duplicate) {
758 if (c == 1) {
759 do_log(_(
760 "Error: source filesystem log is dirty. Mount the filesystem to replay the\n"
761 "log, unmount and retry xfs_copy.\n"));
762 exit(1);
763 } else if (c < 0) {
764 do_log(_(
765 "Error: could not determine the log head or tail of the source filesystem.\n"
766 "Mount the filesystem to replay the log or run xfs_repair.\n"));
767 exit(1);
768 }
769 }
770
771 source_blocksize = mp->m_sb.sb_blocksize;
772 source_sectorsize = mp->m_sb.sb_sectsize;
773
774 if (wbuf_miniosize == -1)
775 wbuf_miniosize = source_sectorsize;
776
777 ASSERT(source_blocksize % source_sectorsize == 0);
778 ASSERT(source_sectorsize % BBSIZE == 0);
779
780 if (source_blocksize < source_sectorsize) {
781 do_log(_("Error: filesystem block size is smaller than the"
782 " disk sectorsize.\nAborting XFS copy now.\n"));
783 exit(1);
784 }
785
786 first_agbno = XFS_AGFL_BLOCK(mp) + 1;
787
788 /* now open targets */
789
790 open_flags = O_RDWR;
791
792 for (i = 0; i < num_targets; i++) {
793 int write_last_block = 0;
794
795 if (stat64(target[i].name, &statbuf) < 0) {
796 /* ok, assume it's a file and create it */
797
798 do_out(_("Creating file %s\n"), target[i].name);
799
800 open_flags |= O_CREAT;
801 if (!buffered_output)
802 open_flags |= O_DIRECT;
803 write_last_block = 1;
804 } else if (S_ISREG(statbuf.st_mode)) {
805 open_flags |= O_TRUNC;
806 if (!buffered_output)
807 open_flags |= O_DIRECT;
808 write_last_block = 1;
809 } else {
810 /*
811 * check to make sure a filesystem isn't mounted
812 * on the device
813 */
814 if (platform_check_ismounted(target[i].name,
815 NULL, &statbuf, 0)) {
816 do_log(_("%s: a filesystem is mounted "
817 "on target device \"%s\".\n"
818 "%s cannot copy to mounted filesystems."
819 " Aborting\n"),
820 progname, target[i].name, progname);
821 exit(1);
822 }
823 }
824
825 target[i].fd = open(target[i].name, open_flags, 0644);
826 if (target[i].fd < 0) {
827 do_log(_("%s: couldn't open target \"%s\"\n"),
828 progname, target[i].name);
829 die_perror();
830 }
831
832 if (write_last_block) {
833 /* ensure regular files are correctly sized */
834
835 if (ftruncate64(target[i].fd, mp->m_sb.sb_dblocks *
836 source_blocksize)) {
837 do_log(_("%s: cannot grow data section.\n"),
838 progname);
839 die_perror();
840 }
841 if (platform_test_xfs_fd(target[i].fd)) {
842 if (xfsctl(target[i].name, target[i].fd,
843 XFS_IOC_DIOINFO, &d) < 0) {
844 do_log(
845 _("%s: xfsctl on \"%s\" failed.\n"),
846 progname, target[i].name);
847 die_perror();
848 } else {
849 wbuf_align = MAX(wbuf_align, d.d_mem);
850 wbuf_size = MIN(d.d_maxiosz, wbuf_size);
851 wbuf_miniosize = MAX(d.d_miniosz,
852 wbuf_miniosize);
853 }
854 }
855 } else {
856 char *lb[XFS_MAX_SECTORSIZE] = { NULL };
857 off64_t off;
858
859 /* ensure device files are sufficiently large */
860
861 off = mp->m_sb.sb_dblocks * source_blocksize;
862 off -= sizeof(lb);
863 if (pwrite64(target[i].fd, lb, sizeof(lb), off) < 0) {
864 do_log(_("%s: failed to write last block\n"),
865 progname);
866 do_log(_("\tIs target \"%s\" too small?\n"),
867 target[i].name);
868 die_perror();
869 }
870 }
871 }
872
873 /* initialize locks and bufs */
874
875 if (pthread_mutex_init(&glob_masks.mutex, NULL) != 0) {
876 do_log(_("Couldn't initialize global thread mask\n"));
877 die_perror();
878 }
879 glob_masks.num_working = 0;
880
881 if (wbuf_init(&w_buf, wbuf_size, wbuf_align,
882 wbuf_miniosize, 0) == NULL) {
883 do_log(_("Error initializing wbuf 0\n"));
884 die_perror();
885 }
886
887 wblocks = wbuf_size / BBSIZE;
888
889 if (wbuf_init(&btree_buf, MAX(source_blocksize, wbuf_miniosize),
890 wbuf_align, wbuf_miniosize, 1) == NULL) {
891 do_log(_("Error initializing btree buf 1\n"));
892 die_perror();
893 }
894
895 if (pthread_mutex_init(&mainwait,NULL) != 0) {
896 do_log(_("Error creating first semaphore.\n"));
897 die_perror();
898 exit(1);
899 }
900 /* need to start out blocking */
901 pthread_mutex_lock(&mainwait);
902
903 /* set up sigchild signal handler */
904
905 signal(SIGCHLD, handler);
906 signal_maskfunc(SIGCHLD, SIG_BLOCK);
907
908 /* make children */
909
910 if ((targ = malloc(num_targets * sizeof(thread_args))) == NULL) {
911 do_log(_("Couldn't malloc space for thread args\n"));
912 die_perror();
913 exit(1);
914 }
915
916 for (i = 0, tcarg = targ; i < num_targets; i++, tcarg++) {
917 if (!duplicate)
918 platform_uuid_generate(&tcarg->uuid);
919 else
920 platform_uuid_copy(&tcarg->uuid, &mp->m_sb.sb_uuid);
921
922 if (pthread_mutex_init(&tcarg->wait, NULL) != 0) {
923 do_log(_("Error creating thread mutex %d\n"), i);
924 die_perror();
925 exit(1);
926 }
927 /* need to start out blocking */
928 pthread_mutex_lock(&tcarg->wait);
929 }
930
931 for (i = 0, tcarg = targ; i < num_targets; i++, tcarg++) {
932 tcarg->id = i;
933 tcarg->fd = target[i].fd;
934
935 target[i].state = ACTIVE;
936 num_threads++;
937
938 if (pthread_create(&target[i].pid, NULL,
939 begin_reader, (void *)tcarg)) {
940 do_log(_("Error creating thread for target %d\n"), i);
941 die_perror();
942 }
943 }
944
945 ASSERT(num_targets == num_threads);
946
947 /* set up statistics */
948
949 num_ags = mp->m_sb.sb_agcount;
950
951 init_bar(mp->m_sb.sb_blocksize / BBSIZE
952 * ((__uint64_t)mp->m_sb.sb_dblocks
953 - (__uint64_t)mp->m_sb.sb_fdblocks + 10 * num_ags));
954
955 kids = num_targets;
956
957 for (agno = 0; agno < num_ags && kids > 0; agno++) {
958 /* read in first blocks of the ag */
959
960 read_ag_header(source_fd, agno, &w_buf, &ag_hdr, mp,
961 source_blocksize, source_sectorsize);
962
963 /* set the in_progress bit for the first AG */
964
965 if (agno == 0)
966 ag_hdr.xfs_sb->sb_inprogress = 1;
967
968 /* save what we need (agf) in the btree buffer */
969
970 memmove(btree_buf.data, ag_hdr.xfs_agf, source_sectorsize);
971 ag_hdr.xfs_agf = (xfs_agf_t *) btree_buf.data;
972 btree_buf.length = source_blocksize;
973
974 /* write the ag header out */
975
976 write_wbuf();
977
978 /* traverse btree until we get to the leftmost leaf node */
979
980 bno = be32_to_cpu(ag_hdr.xfs_agf->agf_roots[XFS_BTNUM_BNOi]);
981 current_level = 0;
982 btree_levels = be32_to_cpu(ag_hdr.xfs_agf->
983 agf_levels[XFS_BTNUM_BNOi]);
984
985 ag_end = XFS_AGB_TO_DADDR(mp, agno,
986 be32_to_cpu(ag_hdr.xfs_agf->agf_length) - 1)
987 + source_blocksize / BBSIZE;
988
989 for (;;) {
990 /* none of this touches the w_buf buffer */
991
992 if (current_level >= btree_levels) {
993 do_log(
994 _("Error: current level %d >= btree levels %d\n"),
995 current_level, btree_levels);
996 exit(1);
997 }
998
999 current_level++;
1000
1001 btree_buf.position = pos = (xfs_off_t)
1002 XFS_AGB_TO_DADDR(mp,agno,bno) << BBSHIFT;
1003 btree_buf.length = source_blocksize;
1004
1005 read_wbuf(source_fd, &btree_buf, mp);
1006 block = (struct xfs_btree_block *)
1007 ((char *)btree_buf.data +
1008 pos - btree_buf.position);
1009
1010 if (be32_to_cpu(block->bb_magic) !=
1011 (xfs_sb_version_hascrc(&mp->m_sb) ?
1012 XFS_ABTB_CRC_MAGIC : XFS_ABTB_MAGIC)) {
1013 do_log(_("Bad btree magic 0x%x\n"),
1014 be32_to_cpu(block->bb_magic));
1015 exit(1);
1016 }
1017
1018 if (be16_to_cpu(block->bb_level) == 0)
1019 break;
1020
1021 ptr = XFS_ALLOC_PTR_ADDR(mp, block, 1,
1022 mp->m_alloc_mxr[1]);
1023 bno = be32_to_cpu(ptr[0]);
1024 }
1025
1026 /* align first data copy but don't overwrite ag header */
1027
1028 pos = w_buf.position >> BBSHIFT;
1029 length = w_buf.length >> BBSHIFT;
1030 next_begin = pos + length;
1031 ag_begin = next_begin;
1032
1033 ASSERT(w_buf.position % source_sectorsize == 0);
1034
1035 /* handle the rest of the ag */
1036
1037 for (;;) {
1038 if (be16_to_cpu(block->bb_level) != 0) {
1039 do_log(
1040 _("WARNING: source filesystem inconsistent.\n"));
1041 do_log(
1042 _(" A leaf btree rec isn't a leaf. Aborting now.\n"));
1043 exit(1);
1044 }
1045
1046 rec_ptr = XFS_ALLOC_REC_ADDR(mp, block, 1);
1047 for (i = 0; i < be16_to_cpu(block->bb_numrecs);
1048 i++, rec_ptr++) {
1049 /* calculate in daddr's */
1050
1051 begin = next_begin;
1052
1053 /*
1054 * protect against pathological case of a
1055 * hole right after the ag header in a
1056 * mis-aligned case
1057 */
1058
1059 if (begin < ag_begin)
1060 begin = ag_begin;
1061
1062 /*
1063 * round size up to ensure we copy a
1064 * range bigger than required
1065 */
1066
1067 sizeb = XFS_AGB_TO_DADDR(mp, agno,
1068 be32_to_cpu(rec_ptr->ar_startblock)) -
1069 begin;
1070 size = roundup(sizeb <<BBSHIFT, wbuf_miniosize);
1071 if (size > 0) {
1072 /* copy extent */
1073
1074 w_buf.position = (xfs_off_t)
1075 begin << BBSHIFT;
1076
1077 while (size > 0) {
1078 /*
1079 * let lower layer do alignment
1080 */
1081 if (size > w_buf.size) {
1082 w_buf.length = w_buf.size;
1083 size -= w_buf.size;
1084 sizeb -= wblocks;
1085 numblocks += wblocks;
1086 } else {
1087 w_buf.length = size;
1088 numblocks += sizeb;
1089 size = 0;
1090 }
1091
1092 read_wbuf(source_fd, &w_buf, mp);
1093 write_wbuf();
1094
1095 w_buf.position += w_buf.length;
1096
1097 howfar = bump_bar(
1098 howfar, numblocks);
1099 }
1100 }
1101
1102 /* round next starting point down */
1103
1104 new_begin = XFS_AGB_TO_DADDR(mp, agno,
1105 be32_to_cpu(rec_ptr->ar_startblock) +
1106 be32_to_cpu(rec_ptr->ar_blockcount));
1107 next_begin = rounddown(new_begin,
1108 w_buf.min_io_size >> BBSHIFT);
1109 }
1110
1111 if (be32_to_cpu(block->bb_u.s.bb_rightsib) == NULLAGBLOCK)
1112 break;
1113
1114 /* read in next btree record block */
1115
1116 btree_buf.position = pos = (xfs_off_t)
1117 XFS_AGB_TO_DADDR(mp, agno, be32_to_cpu(
1118 block->bb_u.s.bb_rightsib)) << BBSHIFT;
1119 btree_buf.length = source_blocksize;
1120
1121 /* let read_wbuf handle alignment */
1122
1123 read_wbuf(source_fd, &btree_buf, mp);
1124
1125 block = (struct xfs_btree_block *)
1126 ((char *) btree_buf.data +
1127 pos - btree_buf.position);
1128
1129 ASSERT(be32_to_cpu(block->bb_magic) == XFS_ABTB_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
1204 return 0;
1205 }
1206
1207 char *
1208 next_log_chunk(char *p, int offset, void *private)
1209 {
1210 wbuf *buf = (wbuf *)private;
1211
1212 if (buf->length < (int)(p - buf->data) + offset) {
1213 /* need to flush this one, then start afresh */
1214
1215 do_write(buf->owner, NULL);
1216 memset(buf->data, 0, buf->length);
1217 return buf->data;
1218 }
1219 return p + offset;
1220 }
1221
1222 /*
1223 * Writes a log header at the start of the log (with the real
1224 * filesystem UUID embedded into it), and writes to all targets.
1225 *
1226 * Returns the next buffer-length-aligned disk address.
1227 */
1228 xfs_off_t
1229 write_log_header(int fd, wbuf *buf, xfs_mount_t *mp)
1230 {
1231 char *p = buf->data;
1232 xfs_off_t logstart;
1233 int offset;
1234
1235 logstart = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart) << BBSHIFT;
1236 buf->position = rounddown(logstart, (xfs_off_t)buf->length);
1237
1238 memset(p, 0, buf->size);
1239 if (logstart % buf->length) { /* unaligned */
1240 read_wbuf(fd, buf, mp);
1241 offset = logstart - buf->position;
1242 p += offset;
1243 memset(p, 0, buf->length - offset);
1244 }
1245
1246 offset = libxfs_log_header(p, &buf->owner->uuid,
1247 xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1,
1248 mp->m_sb.sb_logsunit, XLOG_FMT, NULLCOMMITLSN,
1249 NULLCOMMITLSN, next_log_chunk, buf);
1250 do_write(buf->owner, NULL);
1251
1252 return roundup(logstart + offset, buf->length);
1253 }
1254
1255 /*
1256 * May do an aligned read of the last buffer in the log (& zero
1257 * the start of that buffer). Returns the disk address at the
1258 * end of last aligned buffer in the log.
1259 */
1260 xfs_off_t
1261 write_log_trailer(int fd, wbuf *buf, xfs_mount_t *mp)
1262 {
1263 xfs_off_t logend;
1264 int offset;
1265
1266 logend = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart) << BBSHIFT;
1267 logend += XFS_FSB_TO_B(mp, mp->m_sb.sb_logblocks);
1268
1269 buf->position = rounddown(logend, (xfs_off_t)buf->length);
1270
1271 if (logend % buf->length) { /* unaligned */
1272 read_wbuf(fd, buf, mp);
1273 offset = (int)(logend - buf->position);
1274 memset(buf->data, 0, offset);
1275 do_write(buf->owner, NULL);
1276 }
1277
1278 return buf->position;
1279 }
1280
1281 /*
1282 * Clear a log by writing a record at the head, the tail and zeroing everything
1283 * in between.
1284 */
1285 static void
1286 clear_log(
1287 struct xfs_mount *mp,
1288 thread_args *tcarg)
1289 {
1290 xfs_off_t pos;
1291 xfs_off_t end_pos;
1292
1293 w_buf.owner = tcarg;
1294 w_buf.length = rounddown(w_buf.size, w_buf.min_io_size);
1295 pos = write_log_header(source_fd, &w_buf, mp);
1296 end_pos = write_log_trailer(source_fd, &w_buf, mp);
1297 w_buf.position = pos;
1298 memset(w_buf.data, 0, w_buf.length);
1299
1300 while (w_buf.position < end_pos) {
1301 do_write(tcarg, NULL);
1302 w_buf.position += w_buf.length;
1303 }
1304 }
1305
1306 /*
1307 * Format the log to a particular cycle number. This is required for version 5
1308 * superblock filesystems to provide metadata LSN validity guarantees.
1309 */
1310 static void
1311 format_log(
1312 struct xfs_mount *mp,
1313 thread_args *tcarg,
1314 wbuf *buf)
1315 {
1316 int logstart;
1317 int length;
1318 int cycle = XLOG_INIT_CYCLE;
1319
1320 buf->owner = tcarg;
1321 buf->length = buf->size;
1322 buf->position = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart) << BBSHIFT;
1323
1324 logstart = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logstart);
1325 length = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
1326
1327 /*
1328 * Bump the cycle number on v5 superblock filesystems to guarantee that
1329 * all existing metadata LSNs are valid (behind the current LSN) on the
1330 * target fs.
1331 */
1332 if (xfs_sb_version_hascrc(&mp->m_sb))
1333 cycle = mp->m_log->l_curr_cycle + 1;
1334
1335 /*
1336 * Format the entire log into the memory buffer and write it out. If the
1337 * write fails, mark the target inactive so the failure is reported.
1338 */
1339 libxfs_log_clear(NULL, buf->data, logstart, length, &buf->owner->uuid,
1340 xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1,
1341 mp->m_sb.sb_logsunit, XLOG_FMT, cycle, true);
1342 if (do_write(buf->owner, buf))
1343 target[tcarg->id].state = INACTIVE;
1344 }
1345
1346 static int
1347 format_logs(
1348 struct xfs_mount *mp)
1349 {
1350 thread_args *tcarg;
1351 int i;
1352 wbuf logbuf;
1353 int logsize;
1354
1355 if (xfs_sb_version_hascrc(&mp->m_sb)) {
1356 logsize = XFS_FSB_TO_B(mp, mp->m_sb.sb_logblocks);
1357 if (!wbuf_init(&logbuf, logsize, w_buf.data_align,
1358 w_buf.min_io_size, w_buf.id))
1359 return -ENOMEM;
1360 }
1361
1362 for (i = 0, tcarg = targ; i < num_targets; i++) {
1363 if (xfs_sb_version_hascrc(&mp->m_sb))
1364 format_log(mp, tcarg, &logbuf);
1365 else
1366 clear_log(mp, tcarg);
1367 tcarg++;
1368 }
1369
1370 if (xfs_sb_version_hascrc(&mp->m_sb))
1371 free(logbuf.data);
1372
1373 return 0;
1374 }