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