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