]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - copy/xfs_copy.c
xfs: try to avoid blowing out the transaction reservation when bunmaping a shared...
[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
6b803e5a 19#include "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"
3616eb86 26#include "libxlog.h"
6404bb81
NS
27
28#define rounddown(x, y) (((x)/(y))*(y))
9c4e12fb 29#define uuid_equal(s,d) (platform_uuid_compare((s),(d)) == 0)
6404bb81 30
f594a0d1 31extern int platform_check_ismounted(char *, char *, struct stat *, int);
7066fb24 32
6404bb81
NS
33int logfd;
34char *logfile_name;
35FILE *logerr;
36char LOGFILE_NAME[] = "/var/tmp/xfs_copy.log.XXXXXX";
37
38char *source_name;
39int source_fd;
40
41unsigned int source_blocksize; /* source filesystem blocksize */
42unsigned int source_sectorsize; /* source disk sectorsize */
43
44xfs_agblock_t first_agbno;
45
989b74bc
NS
46__uint64_t barcount[11];
47
6404bb81
NS
48unsigned int num_targets;
49target_control *target;
50
51wbuf w_buf;
52wbuf btree_buf;
53
54pid_t parent_pid;
55unsigned int kids;
56
57thread_control glob_masks;
58thread_args *targ;
59
60pthread_mutex_t mainwait;
61
62#define ACTIVE 1
63#define INACTIVE 2
64
54b0c4dc
BF
65xfs_off_t write_log_trailer(int fd, wbuf *w, xfs_mount_t *mp);
66xfs_off_t write_log_header(int fd, wbuf *w, xfs_mount_t *mp);
b4d947db 67static int format_logs(struct xfs_mount *);
6404bb81
NS
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
ad0a1e9f
JK
77void
78signal_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
6404bb81
NS
87void
88do_message(int flags, int code, const char *fmt, ...)
89{
90 va_list ap;
91 int eek = 0;
92
6f9ef386
TS
93 if (flags & LOG) {
94 va_start(ap, fmt);
6404bb81
NS
95 if (vfprintf(logerr, fmt, ap) <= 0)
96 eek = 1;
6f9ef386
TS
97 va_end(ap);
98 }
6404bb81
NS
99 if (eek)
100 flags |= ERR; /* failed, force stderr */
6f9ef386
TS
101 if (flags & ERR) {
102 va_start(ap, fmt);
6404bb81 103 vfprintf(stderr, fmt, ap);
6f9ef386
TS
104 va_end(ap);
105 } else if (flags & OUT) {
106 va_start(ap, fmt);
6404bb81 107 vfprintf(stdout, fmt, ap);
6f9ef386
TS
108 va_end(ap);
109 }
6404bb81
NS
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)
a92e6823 136#define die_perror() \
989b74bc
NS
137 do { \
138 do_message(ERR|LOG|PRE|LAST, errno, \
139 _("Aborting XFS copy - reason")); \
140 exit(1); \
141 } while (0)
6404bb81 142
3616eb86
BF
143/* workaround craziness in the xlog routines */
144int xlog_recover_do_trans(struct xlog *log, struct xlog_recover *t, int p)
145{
146 return 0;
147}
148
6404bb81
NS
149void
150check_errors(void)
151{
989b74bc 152 int i, first_error = 0;
6404bb81
NS
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
dc8878f4 165 do_log(_("lseek error"));
6404bb81
NS
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 */
989b74bc 183int
96866b03
BF
184do_write(
185 thread_args *args,
186 wbuf *buf)
989b74bc 187{
96866b03
BF
188 int res;
189 int error = 0;
989b74bc 190
96866b03
BF
191 if (!buf)
192 buf = &w_buf;
193
194 if (target[args->id].position != buf->position) {
dc8878f4 195 if (lseek(args->fd, buf->position, SEEK_SET) < 0) {
989b74bc
NS
196 error = target[args->id].err_type = 1;
197 } else {
96866b03 198 target[args->id].position = buf->position;
989b74bc
NS
199 }
200 }
201
96866b03
BF
202 if ((res = write(target[args->id].fd, buf->data,
203 buf->length)) == buf->length) {
989b74bc
NS
204 target[args->id].position += res;
205 } else {
206 error = 2;
207 }
208
209 if (error) {
210 target[args->id].error = errno;
96866b03 211 target[args->id].position = buf->position;
989b74bc
NS
212 }
213 return error;
214}
6404bb81
NS
215
216void *
217begin_reader(void *arg)
218{
219 thread_args *args = arg;
6404bb81
NS
220
221 for (;;) {
222 pthread_mutex_lock(&args->wait);
96866b03 223 if (do_write(args, NULL))
6404bb81 224 goto handle_error;
6404bb81
NS
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
232handle_error:
233 /* error will be logged by primary thread */
234
6404bb81
NS
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);
32a82561 241 return NULL;
6404bb81
NS
242}
243
6404bb81 244void
5e656dbb 245handler(int sig)
6404bb81 246{
d0bbcbcb 247 pid_t pid;
6404bb81
NS
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(
dc8878f4 266 _("%s: lseek error on target %d \"%s\" at offset %lld\n"),
6404bb81
NS
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
32a82561 281 signal(SIGCHLD, handler);
6404bb81
NS
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);
989b74bc 289 do_warn(_("%s: offset was probably %lld\n"),
6404bb81
NS
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);
32a82561 303 signal(SIGCHLD, handler);
6404bb81
NS
304}
305
306void
307usage(void)
308{
309 fprintf(stderr,
30626ef6 310 _("Usage: %s [-bdV] [-L logfile] source target [target ...]\n"),
6404bb81
NS
311 progname);
312 exit(1);
313}
314
6404bb81 315void
989b74bc
NS
316init_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
324int
325bump_bar(int tenths, __uint64_t numblocks)
6404bb81 326{
989b74bc
NS
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;
6404bb81
NS
352}
353
354static xfs_off_t source_position = -1;
355
356wbuf *
357wbuf_init(wbuf *buf, int data_size, int data_align, int min_io_size, int id)
358{
44e9ee90
NS
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 }
6404bb81 365 ASSERT(min_io_size % BBSIZE == 0);
08f2b836 366 buf->data_align = data_align;
6404bb81 367 buf->min_io_size = min_io_size;
44e9ee90
NS
368 buf->size = data_size;
369 buf->id = id;
6404bb81
NS
370 return buf;
371}
372
373void
374read_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) {
dc8878f4 391 lres = lseek(fd, buf->position, SEEK_SET);
6404bb81 392 if (lres < 0LL) {
dc8878f4 393 do_warn(_("%s: lseek failure at offset %lld\n"),
6404bb81
NS
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);
2277ce35 410 exit(1);
6404bb81
NS
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
989b74bc 428void
6404bb81
NS
429read_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;
6bddecbc
DC
443 if (length == 0) {
444 do_log(_("ag header buffer invalid!\n"));
445 exit(1);
446 }
44e9ee90 447
6404bb81
NS
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
6404bb81
NS
462 read_wbuf(fd, buf, mp);
463 ASSERT(buf->length >= length);
464
5e656dbb
BN
465 ag->xfs_sb = (xfs_dsb_t *) (buf->data + diff);
466 ASSERT(be32_to_cpu(ag->xfs_sb->sb_magicnum) == XFS_SB_MAGIC);
6404bb81 467 ag->xfs_agf = (xfs_agf_t *) (buf->data + diff + sectorsize);
5e656dbb
BN
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);
6404bb81
NS
472}
473
989b74bc 474
6404bb81
NS
475void
476write_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
ad0a1e9f 490 signal_maskfunc(SIGCHLD, SIG_UNBLOCK);
6404bb81 491 pthread_mutex_lock(&mainwait);
ad0a1e9f 492 signal_maskfunc(SIGCHLD, SIG_BLOCK);
6404bb81
NS
493}
494
9c4e12fb
ES
495void
496sb_update_uuid(
cbca8955
ES
497 xfs_sb_t *sb, /* Original fs superblock */
498 ag_header_t *ag_hdr, /* AG hdr to update for this copy */
499 thread_args *tcarg) /* Args for this thread, with UUID */
9c4e12fb
ES
500{
501 /*
502 * If this filesystem has CRCs, the original UUID is stamped into
cbca8955
ES
503 * all metadata. If we don't have an existing meta_uuid field in the
504 * the original filesystem and we are changing the UUID in this copy,
505 * we must copy the original sb_uuid to the sb_meta_uuid slot and set
506 * the incompat flag for the feature on this copy.
9c4e12fb 507 */
cbca8955
ES
508 if (xfs_sb_version_hascrc(sb) && !xfs_sb_version_hasmetauuid(sb) &&
509 !uuid_equal(&tcarg->uuid, &sb->sb_uuid)) {
9c4e12fb
ES
510 __be32 feat;
511
512 feat = be32_to_cpu(ag_hdr->xfs_sb->sb_features_incompat);
513 feat |= XFS_SB_FEAT_INCOMPAT_META_UUID;
514 ag_hdr->xfs_sb->sb_features_incompat = cpu_to_be32(feat);
515 platform_uuid_copy(&ag_hdr->xfs_sb->sb_meta_uuid,
cbca8955 516 &sb->sb_uuid);
9c4e12fb
ES
517 }
518
cbca8955 519 /* Copy the (possibly new) fs-identifier UUID into sb_uuid */
9c4e12fb
ES
520 platform_uuid_copy(&ag_hdr->xfs_sb->sb_uuid, &tcarg->uuid);
521
522 /* We may have changed the UUID, so update the superblock CRC */
523 if (xfs_sb_version_hascrc(sb))
524 xfs_update_cksum((char *)ag_hdr->xfs_sb, sb->sb_sectsize,
525 XFS_SB_CRC_OFF);
526}
6404bb81
NS
527
528int
529main(int argc, char **argv)
530{
989b74bc
NS
531 int i, j;
532 int howfar = 0;
6404bb81 533 int open_flags;
54b0c4dc 534 xfs_off_t pos;
6404bb81 535 size_t length;
263b5376 536 int c;
0b9a02a6 537 __uint64_t size, sizeb;
6404bb81 538 __uint64_t numblocks = 0;
6404bb81
NS
539 int wblocks = 0;
540 int num_threads = 0;
541 struct dioattr d;
542 int wbuf_size;
543 int wbuf_align;
544 int wbuf_miniosize;
545 int source_is_file = 0;
546 int buffered_output = 0;
84c032c3 547 int duplicate = 0;
6404bb81
NS
548 uint btree_levels, current_level;
549 ag_header_t ag_hdr;
550 xfs_mount_t *mp;
551 xfs_mount_t mbuf;
3616eb86 552 struct xlog xlog;
6404bb81
NS
553 xfs_buf_t *sbp;
554 xfs_sb_t *sb;
555 xfs_agnumber_t num_ags, agno;
556 xfs_agblock_t bno;
557 xfs_daddr_t begin, next_begin, ag_begin, new_begin, ag_end;
b3563c19 558 struct xfs_btree_block *block;
6404bb81
NS
559 xfs_alloc_ptr_t *ptr;
560 xfs_alloc_rec_t *rec_ptr;
561 extern char *optarg;
562 extern int optind;
563 libxfs_init_t xargs;
564 thread_args *tcarg;
f594a0d1 565 struct stat statbuf;
6404bb81
NS
566
567 progname = basename(argv[0]);
568
569 setlocale(LC_ALL, "");
570 bindtextdomain(PACKAGE, LOCALEDIR);
571 textdomain(PACKAGE);
572
573 while ((c = getopt(argc, argv, "bdL:V")) != EOF) {
574 switch (c) {
575 case 'b':
576 buffered_output = 1;
577 break;
578 case 'd':
84c032c3 579 duplicate = 1;
6404bb81
NS
580 break;
581 case 'L':
582 logfile_name = optarg;
583 break;
584 case 'V':
585 printf(_("%s version %s\n"), progname, VERSION);
586 exit(0);
587 case '?':
588 usage();
589 }
590 }
591
592 if (argc - optind < 2)
593 usage();
594
595 if (logfile_name) {
596 logfd = open(logfile_name, O_CREAT|O_WRONLY|O_EXCL, 0600);
597 } else {
598 logfile_name = LOGFILE_NAME;
599 logfd = mkstemp(logfile_name);
600 }
601
602 if (logfd < 0) {
603 fprintf(stderr, _("%s: couldn't open log file \"%s\"\n"),
604 progname, logfile_name);
605 perror(_("Aborting XFS copy - reason"));
606 exit(1);
607 }
608
609 if ((logerr = fdopen(logfd, "w")) == NULL) {
610 fprintf(stderr, _("%s: couldn't set up logfile stream\n"),
611 progname);
612 perror(_("Aborting XFS copy - reason"));
613 exit(1);
614 }
615
616 source_name = argv[optind];
617 source_fd = -1;
618 optind++;
619
620 num_targets = argc - optind;
621 if ((target = malloc(sizeof(target_control) * num_targets)) == NULL) {
622 do_log(_("Couldn't allocate target array\n"));
623 die_perror();
624 }
625 for (i = 0; optind < argc; i++, optind++) {
626 target[i].name = argv[optind];
627 target[i].fd = -1;
628 target[i].position = -1;
629 target[i].state = INACTIVE;
630 target[i].error = 0;
631 target[i].err_type = 0;
632 }
633
634 parent_pid = getpid();
635
6404bb81
NS
636 /* open up source -- is it a file? */
637
638 open_flags = O_RDONLY;
639
640 if ((source_fd = open(source_name, open_flags)) < 0) {
641 do_log(_("%s: couldn't open source \"%s\"\n"),
642 progname, source_name);
643 die_perror();
644 }
645
f594a0d1 646 if (fstat(source_fd, &statbuf) < 0) {
6404bb81
NS
647 do_log(_("%s: couldn't stat source \"%s\"\n"),
648 progname, source_name);
649 die_perror();
650 }
651
652 if (S_ISREG(statbuf.st_mode))
653 source_is_file = 1;
654
655 if (source_is_file && platform_test_xfs_fd(source_fd)) {
656 if (fcntl(source_fd, F_SETFL, open_flags | O_DIRECT) < 0) {
657 do_log(_("%s: Cannot set direct I/O flag on \"%s\".\n"),
658 progname, source_name);
659 die_perror();
660 }
661 if (xfsctl(source_name, source_fd, XFS_IOC_DIOINFO, &d) < 0) {
662 do_log(_("%s: xfsctl on file \"%s\" failed.\n"),
663 progname, source_name);
664 die_perror();
665 }
666
667 wbuf_align = d.d_mem;
44e9ee90 668 wbuf_size = MIN(d.d_maxiosz, 1 * 1024 * 1024);
6404bb81
NS
669 wbuf_miniosize = d.d_miniosz;
670 } else {
671 /* set arbitrary I/O params, miniosize at least 1 disk block */
672
44e9ee90
NS
673 wbuf_align = getpagesize();
674 wbuf_size = 1 * 1024 * 1024;
6404bb81
NS
675 wbuf_miniosize = -1; /* set after mounting source fs */
676 }
677
678 if (!source_is_file) {
679 /*
680 * check to make sure a filesystem isn't mounted
681 * on the device
682 */
32a82561 683 if (platform_check_ismounted(source_name, NULL, &statbuf, 0)) {
6404bb81
NS
684 do_log(
685 _("%s: Warning -- a filesystem is mounted on the source device.\n"),
686 progname);
687 do_log(
688 _("\t\tGenerated copies may be corrupt unless the source is\n"));
689 do_log(
690 _("\t\tunmounted or mounted read-only. Copy proceeding...\n"));
691 }
692 }
693
694 /* prepare the libxfs_init structure */
695
696 memset(&xargs, 0, sizeof(xargs));
b74a1f6a 697 xargs.isdirect = LIBXFS_DIRECT;
6404bb81 698 xargs.isreadonly = LIBXFS_ISREADONLY;
6404bb81
NS
699
700 if (source_is_file) {
701 xargs.dname = source_name;
702 xargs.disfile = 1;
703 } else
704 xargs.volname = source_name;
705
706 if (!libxfs_init(&xargs)) {
707 do_log(_("%s: couldn't initialize XFS library\n"
708 "%s: Aborting.\n"), progname, progname);
709 exit(1);
710 }
711
6404bb81 712 memset(&mbuf, 0, sizeof(xfs_mount_t));
a1b2cb5e
ES
713
714 /* We don't yet know the sector size, so read maximal size */
75c8b434 715 libxfs_buftarg_init(&mbuf, xargs.ddev, xargs.logdev, xargs.rtdev);
c63ce10a 716 sbp = libxfs_readbuf(mbuf.m_ddev_targp, XFS_SB_DADDR,
a1b2cb5e 717 1 << (XFS_MAX_SECTORSIZE_LOG - BBSHIFT), 0, NULL);
6404bb81 718 sb = &mbuf.m_sb;
5e656dbb 719 libxfs_sb_from_disk(sb, XFS_BUF_TO_SBP(sbp));
6404bb81 720
a1b2cb5e
ES
721 /* Do it again, now with proper length and verifier */
722 libxfs_putbuf(sbp);
723 libxfs_purgebuf(sbp);
724 sbp = libxfs_readbuf(mbuf.m_ddev_targp, XFS_SB_DADDR,
725 1 << (sb->sb_sectlog - BBSHIFT),
726 0, &xfs_sb_buf_ops);
4334e2e8 727 libxfs_putbuf(sbp);
a872b622 728
9aa57116 729 mp = libxfs_mount(&mbuf, sb, xargs.ddev, xargs.logdev, xargs.rtdev, 0);
6404bb81
NS
730 if (mp == NULL) {
731 do_log(_("%s: %s filesystem failed to initialize\n"
732 "%s: Aborting.\n"), progname, source_name, progname);
733 exit(1);
734 } else if (mp->m_sb.sb_inprogress) {
735 do_log(_("%s %s filesystem failed to initialize\n"
736 "%s: Aborting.\n"), progname, source_name, progname);
737 exit(1);
738 } else if (mp->m_sb.sb_logstart == 0) {
739 do_log(_("%s: %s has an external log.\n%s: Aborting.\n"),
740 progname, source_name, progname);
741 exit(1);
742 } else if (mp->m_sb.sb_rextents != 0) {
743 do_log(_("%s: %s has a real-time section.\n"
744 "%s: Aborting.\n"), progname, source_name, progname);
745 exit(1);
746 }
747
3616eb86
BF
748
749 /*
750 * Set up the mount pointer to access the log and check whether the log
751 * is clean. Fail on a dirty or corrupt log in non-duplicate mode
752 * because the log is formatted as part of the copy and we don't want to
753 * destroy data. We also need the current log cycle to format v5
754 * superblock logs correctly.
755 */
756 memset(&xlog, 0, sizeof(struct xlog));
757 mp->m_log = &xlog;
758 c = xlog_is_dirty(mp, mp->m_log, &xargs, 0);
759 if (!duplicate) {
760 if (c == 1) {
761 do_log(_(
762"Error: source filesystem log is dirty. Mount the filesystem to replay the\n"
763"log, unmount and retry xfs_copy.\n"));
764 exit(1);
765 } else if (c < 0) {
766 do_log(_(
767"Error: could not determine the log head or tail of the source filesystem.\n"
768"Mount the filesystem to replay the log or run xfs_repair.\n"));
769 exit(1);
770 }
771 }
772
6404bb81
NS
773 source_blocksize = mp->m_sb.sb_blocksize;
774 source_sectorsize = mp->m_sb.sb_sectsize;
775
776 if (wbuf_miniosize == -1)
777 wbuf_miniosize = source_sectorsize;
778
779 ASSERT(source_blocksize % source_sectorsize == 0);
780 ASSERT(source_sectorsize % BBSIZE == 0);
781
263b5376 782 if (source_blocksize < source_sectorsize) {
6404bb81
NS
783 do_log(_("Error: filesystem block size is smaller than the"
784 " disk sectorsize.\nAborting XFS copy now.\n"));
785 exit(1);
786 }
787
263b5376 788 first_agbno = XFS_AGFL_BLOCK(mp) + 1;
6404bb81 789
6404bb81
NS
790 /* now open targets */
791
792 open_flags = O_RDWR;
793
794 for (i = 0; i < num_targets; i++) {
795 int write_last_block = 0;
44e9ee90 796
f594a0d1 797 if (stat(target[i].name, &statbuf) < 0) {
6404bb81
NS
798 /* ok, assume it's a file and create it */
799
800 do_out(_("Creating file %s\n"), target[i].name);
801
802 open_flags |= O_CREAT;
803 if (!buffered_output)
804 open_flags |= O_DIRECT;
805 write_last_block = 1;
806 } else if (S_ISREG(statbuf.st_mode)) {
807 open_flags |= O_TRUNC;
808 if (!buffered_output)
809 open_flags |= O_DIRECT;
810 write_last_block = 1;
811 } else {
812 /*
813 * check to make sure a filesystem isn't mounted
814 * on the device
815 */
32a82561
NS
816 if (platform_check_ismounted(target[i].name,
817 NULL, &statbuf, 0)) {
6404bb81
NS
818 do_log(_("%s: a filesystem is mounted "
819 "on target device \"%s\".\n"
820 "%s cannot copy to mounted filesystems."
821 " Aborting\n"),
822 progname, target[i].name, progname);
823 exit(1);
824 }
825 }
826
827 target[i].fd = open(target[i].name, open_flags, 0644);
828 if (target[i].fd < 0) {
829 do_log(_("%s: couldn't open target \"%s\"\n"),
830 progname, target[i].name);
831 die_perror();
832 }
833
834 if (write_last_block) {
835 /* ensure regular files are correctly sized */
836
dde67673 837 if (ftruncate(target[i].fd, mp->m_sb.sb_dblocks *
6404bb81
NS
838 source_blocksize)) {
839 do_log(_("%s: cannot grow data section.\n"),
840 progname);
841 die_perror();
842 }
3422261d
NS
843 if (platform_test_xfs_fd(target[i].fd)) {
844 if (xfsctl(target[i].name, target[i].fd,
6404bb81 845 XFS_IOC_DIOINFO, &d) < 0) {
3422261d
NS
846 do_log(
847 _("%s: xfsctl on \"%s\" failed.\n"),
848 progname, target[i].name);
849 die_perror();
850 } else {
851 wbuf_align = MAX(wbuf_align, d.d_mem);
852 wbuf_size = MIN(d.d_maxiosz, wbuf_size);
853 wbuf_miniosize = MAX(d.d_miniosz,
854 wbuf_miniosize);
855 }
6404bb81
NS
856 }
857 } else {
5e656dbb 858 char *lb[XFS_MAX_SECTORSIZE] = { NULL };
989b74bc 859 off64_t off;
6404bb81
NS
860
861 /* ensure device files are sufficiently large */
862
989b74bc
NS
863 off = mp->m_sb.sb_dblocks * source_blocksize;
864 off -= sizeof(lb);
2f9a125c 865 if (pwrite(target[i].fd, lb, sizeof(lb), off) < 0) {
6404bb81
NS
866 do_log(_("%s: failed to write last block\n"),
867 progname);
868 do_log(_("\tIs target \"%s\" too small?\n"),
869 target[i].name);
870 die_perror();
871 }
872 }
6404bb81
NS
873 }
874
875 /* initialize locks and bufs */
876
877 if (pthread_mutex_init(&glob_masks.mutex, NULL) != 0) {
878 do_log(_("Couldn't initialize global thread mask\n"));
879 die_perror();
880 }
881 glob_masks.num_working = 0;
882
883 if (wbuf_init(&w_buf, wbuf_size, wbuf_align,
884 wbuf_miniosize, 0) == NULL) {
885 do_log(_("Error initializing wbuf 0\n"));
886 die_perror();
887 }
888
889 wblocks = wbuf_size / BBSIZE;
890
989b74bc
NS
891 if (wbuf_init(&btree_buf, MAX(source_blocksize, wbuf_miniosize),
892 wbuf_align, wbuf_miniosize, 1) == NULL) {
6404bb81
NS
893 do_log(_("Error initializing btree buf 1\n"));
894 die_perror();
895 }
896
897 if (pthread_mutex_init(&mainwait,NULL) != 0) {
898 do_log(_("Error creating first semaphore.\n"));
899 die_perror();
900 exit(1);
901 }
902 /* need to start out blocking */
44e9ee90 903 pthread_mutex_lock(&mainwait);
6404bb81
NS
904
905 /* set up sigchild signal handler */
906
32a82561 907 signal(SIGCHLD, handler);
ad0a1e9f 908 signal_maskfunc(SIGCHLD, SIG_BLOCK);
6404bb81
NS
909
910 /* make children */
911
912 if ((targ = malloc(num_targets * sizeof(thread_args))) == NULL) {
913 do_log(_("Couldn't malloc space for thread args\n"));
914 die_perror();
915 exit(1);
916 }
917
918 for (i = 0, tcarg = targ; i < num_targets; i++, tcarg++) {
84c032c3 919 if (!duplicate)
4d32d744 920 platform_uuid_generate(&tcarg->uuid);
989b74bc 921 else
4d32d744 922 platform_uuid_copy(&tcarg->uuid, &mp->m_sb.sb_uuid);
989b74bc 923
6404bb81
NS
924 if (pthread_mutex_init(&tcarg->wait, NULL) != 0) {
925 do_log(_("Error creating thread mutex %d\n"), i);
926 die_perror();
927 exit(1);
928 }
929 /* need to start out blocking */
44e9ee90 930 pthread_mutex_lock(&tcarg->wait);
6404bb81
NS
931 }
932
933 for (i = 0, tcarg = targ; i < num_targets; i++, tcarg++) {
934 tcarg->id = i;
935 tcarg->fd = target[i].fd;
936
937 target[i].state = ACTIVE;
938 num_threads++;
939
940 if (pthread_create(&target[i].pid, NULL,
941 begin_reader, (void *)tcarg)) {
942 do_log(_("Error creating thread for target %d\n"), i);
943 die_perror();
944 }
945 }
946
947 ASSERT(num_targets == num_threads);
948
949 /* set up statistics */
950
951 num_ags = mp->m_sb.sb_agcount;
952
989b74bc 953 init_bar(mp->m_sb.sb_blocksize / BBSIZE
6404bb81 954 * ((__uint64_t)mp->m_sb.sb_dblocks
989b74bc 955 - (__uint64_t)mp->m_sb.sb_fdblocks + 10 * num_ags));
6404bb81
NS
956
957 kids = num_targets;
6404bb81
NS
958
959 for (agno = 0; agno < num_ags && kids > 0; agno++) {
960 /* read in first blocks of the ag */
961
962 read_ag_header(source_fd, agno, &w_buf, &ag_hdr, mp,
963 source_blocksize, source_sectorsize);
964
989b74bc 965 /* set the in_progress bit for the first AG */
6404bb81
NS
966
967 if (agno == 0)
5e656dbb 968 ag_hdr.xfs_sb->sb_inprogress = 1;
6404bb81
NS
969
970 /* save what we need (agf) in the btree buffer */
971
dab9b8d6 972 memmove(btree_buf.data, ag_hdr.xfs_agf, source_sectorsize);
6404bb81
NS
973 ag_hdr.xfs_agf = (xfs_agf_t *) btree_buf.data;
974 btree_buf.length = source_blocksize;
975
976 /* write the ag header out */
977
978 write_wbuf();
979
980 /* traverse btree until we get to the leftmost leaf node */
981
5e656dbb 982 bno = be32_to_cpu(ag_hdr.xfs_agf->agf_roots[XFS_BTNUM_BNOi]);
6404bb81 983 current_level = 0;
5e656dbb
BN
984 btree_levels = be32_to_cpu(ag_hdr.xfs_agf->
985 agf_levels[XFS_BTNUM_BNOi]);
6404bb81
NS
986
987 ag_end = XFS_AGB_TO_DADDR(mp, agno,
5e656dbb
BN
988 be32_to_cpu(ag_hdr.xfs_agf->agf_length) - 1)
989 + source_blocksize / BBSIZE;
6404bb81
NS
990
991 for (;;) {
992 /* none of this touches the w_buf buffer */
993
6bddecbc
DC
994 if (current_level >= btree_levels) {
995 do_log(
996 _("Error: current level %d >= btree levels %d\n"),
997 current_level, btree_levels);
998 exit(1);
999 }
6404bb81
NS
1000
1001 current_level++;
1002
1003 btree_buf.position = pos = (xfs_off_t)
1004 XFS_AGB_TO_DADDR(mp,agno,bno) << BBSHIFT;
1005 btree_buf.length = source_blocksize;
1006
1007 read_wbuf(source_fd, &btree_buf, mp);
b3563c19
BN
1008 block = (struct xfs_btree_block *)
1009 ((char *)btree_buf.data +
1010 pos - btree_buf.position);
6404bb81 1011
a872b622
ES
1012 if (be32_to_cpu(block->bb_magic) !=
1013 (xfs_sb_version_hascrc(&mp->m_sb) ?
1014 XFS_ABTB_CRC_MAGIC : XFS_ABTB_MAGIC)) {
1015 do_log(_("Bad btree magic 0x%x\n"),
1016 be32_to_cpu(block->bb_magic));
1017 exit(1);
1018 }
6404bb81 1019
5e656dbb 1020 if (be16_to_cpu(block->bb_level) == 0)
6404bb81
NS
1021 break;
1022
b3563c19 1023 ptr = XFS_ALLOC_PTR_ADDR(mp, block, 1,
5e656dbb
BN
1024 mp->m_alloc_mxr[1]);
1025 bno = be32_to_cpu(ptr[0]);
6404bb81
NS
1026 }
1027
1028 /* align first data copy but don't overwrite ag header */
1029
1030 pos = w_buf.position >> BBSHIFT;
1031 length = w_buf.length >> BBSHIFT;
1032 next_begin = pos + length;
1033 ag_begin = next_begin;
1034
1035 ASSERT(w_buf.position % source_sectorsize == 0);
1036
1037 /* handle the rest of the ag */
1038
1039 for (;;) {
5e656dbb 1040 if (be16_to_cpu(block->bb_level) != 0) {
6404bb81
NS
1041 do_log(
1042 _("WARNING: source filesystem inconsistent.\n"));
1043 do_log(
1044 _(" A leaf btree rec isn't a leaf. Aborting now.\n"));
1045 exit(1);
1046 }
1047
b3563c19 1048 rec_ptr = XFS_ALLOC_REC_ADDR(mp, block, 1);
5e656dbb
BN
1049 for (i = 0; i < be16_to_cpu(block->bb_numrecs);
1050 i++, rec_ptr++) {
6404bb81
NS
1051 /* calculate in daddr's */
1052
1053 begin = next_begin;
1054
1055 /*
1056 * protect against pathological case of a
1057 * hole right after the ag header in a
1058 * mis-aligned case
1059 */
1060
1061 if (begin < ag_begin)
1062 begin = ag_begin;
1063
1064 /*
1065 * round size up to ensure we copy a
1066 * range bigger than required
1067 */
1068
f8149110
JT
1069 sizeb = XFS_AGB_TO_DADDR(mp, agno,
1070 be32_to_cpu(rec_ptr->ar_startblock)) -
5e656dbb 1071 begin;
6404bb81
NS
1072 size = roundup(sizeb <<BBSHIFT, wbuf_miniosize);
1073 if (size > 0) {
1074 /* copy extent */
1075
1076 w_buf.position = (xfs_off_t)
1077 begin << BBSHIFT;
1078
1079 while (size > 0) {
1080 /*
1081 * let lower layer do alignment
1082 */
1083 if (size > w_buf.size) {
1084 w_buf.length = w_buf.size;
1085 size -= w_buf.size;
1086 sizeb -= wblocks;
1087 numblocks += wblocks;
1088 } else {
1089 w_buf.length = size;
1090 numblocks += sizeb;
1091 size = 0;
1092 }
1093
1094 read_wbuf(source_fd, &w_buf, mp);
1095 write_wbuf();
1096
1097 w_buf.position += w_buf.length;
1098
989b74bc
NS
1099 howfar = bump_bar(
1100 howfar, numblocks);
6404bb81
NS
1101 }
1102 }
1103
1104 /* round next starting point down */
1105
1106 new_begin = XFS_AGB_TO_DADDR(mp, agno,
5e656dbb
BN
1107 be32_to_cpu(rec_ptr->ar_startblock) +
1108 be32_to_cpu(rec_ptr->ar_blockcount));
6404bb81
NS
1109 next_begin = rounddown(new_begin,
1110 w_buf.min_io_size >> BBSHIFT);
1111 }
1112
b3563c19 1113 if (be32_to_cpu(block->bb_u.s.bb_rightsib) == NULLAGBLOCK)
6404bb81
NS
1114 break;
1115
1116 /* read in next btree record block */
1117
1118 btree_buf.position = pos = (xfs_off_t)
5e656dbb 1119 XFS_AGB_TO_DADDR(mp, agno, be32_to_cpu(
b3563c19 1120 block->bb_u.s.bb_rightsib)) << BBSHIFT;
6404bb81
NS
1121 btree_buf.length = source_blocksize;
1122
1123 /* let read_wbuf handle alignment */
1124
1125 read_wbuf(source_fd, &btree_buf, mp);
1126
b3563c19
BN
1127 block = (struct xfs_btree_block *)
1128 ((char *) btree_buf.data +
1129 pos - btree_buf.position);
6404bb81 1130
5e656dbb 1131 ASSERT(be32_to_cpu(block->bb_magic) == XFS_ABTB_MAGIC);
6404bb81
NS
1132 }
1133
1134 /*
1135 * write out range of used blocks after last range
1136 * of free blocks in AG
1137 */
1138 if (next_begin < ag_end) {
1139 begin = next_begin;
1140
1141 sizeb = ag_end - begin;
1142 size = roundup(sizeb << BBSHIFT, wbuf_miniosize);
1143
1144 if (size > 0) {
1145 /* copy extent */
1146
1147 w_buf.position = (xfs_off_t) begin << BBSHIFT;
1148
1149 while (size > 0) {
1150 /*
1151 * let lower layer do alignment
1152 */
1153 if (size > w_buf.size) {
1154 w_buf.length = w_buf.size;
1155 size -= w_buf.size;
1156 sizeb -= wblocks;
1157 numblocks += wblocks;
1158 } else {
1159 w_buf.length = size;
1160 numblocks += sizeb;
1161 size = 0;
1162 }
1163
1164 read_wbuf(source_fd, &w_buf, mp);
1165 write_wbuf();
1166
1167 w_buf.position += w_buf.length;
1168
989b74bc 1169 howfar = bump_bar(howfar, numblocks);
6404bb81
NS
1170 }
1171 }
1172 }
1173 }
1174
1175 if (kids > 0) {
54b0c4dc 1176 if (!duplicate)
84c032c3 1177 /* write a clean log using the specified UUID */
54b0c4dc
BF
1178 format_logs(mp);
1179 else
84c032c3 1180 num_ags = 1;
6404bb81 1181
989b74bc
NS
1182 /* reread and rewrite superblocks (UUID and in-progress) */
1183 /* [backwards, so inprogress bit only updated when done] */
1184
989b74bc
NS
1185 for (i = num_ags - 1; i >= 0; i--) {
1186 read_ag_header(source_fd, i, &w_buf, &ag_hdr, mp,
1187 source_blocksize, source_sectorsize);
1188 if (i == 0)
1189 ag_hdr.xfs_sb->sb_inprogress = 0;
6404bb81 1190
989b74bc
NS
1191 /* do each thread in turn, each has its own UUID */
1192
1193 for (j = 0, tcarg = targ; j < num_targets; j++) {
9c4e12fb 1194 sb_update_uuid(sb, &ag_hdr, tcarg);
96866b03 1195 do_write(tcarg, NULL);
989b74bc
NS
1196 tcarg++;
1197 }
1198 }
1199
1200 bump_bar(100, 0);
6404bb81
NS
1201 }
1202
1203 check_errors();
4334e2e8
ES
1204 libxfs_umount(mp);
1205
6404bb81
NS
1206 return 0;
1207}
989b74bc 1208
d60ba955
CH
1209char *
1210next_log_chunk(char *p, int offset, void *private)
989b74bc
NS
1211{
1212 wbuf *buf = (wbuf *)private;
1213
1214 if (buf->length < (int)(p - buf->data) + offset) {
1215 /* need to flush this one, then start afresh */
1216
96866b03 1217 do_write(buf->owner, NULL);
989b74bc
NS
1218 memset(buf->data, 0, buf->length);
1219 return buf->data;
1220 }
1221 return p + offset;
1222}
1223
1224/*
1225 * Writes a log header at the start of the log (with the real
1226 * filesystem UUID embedded into it), and writes to all targets.
44e9ee90 1227 *
989b74bc
NS
1228 * Returns the next buffer-length-aligned disk address.
1229 */
1230xfs_off_t
1231write_log_header(int fd, wbuf *buf, xfs_mount_t *mp)
1232{
d60ba955 1233 char *p = buf->data;
989b74bc
NS
1234 xfs_off_t logstart;
1235 int offset;
1236
1237 logstart = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart) << BBSHIFT;
1238 buf->position = rounddown(logstart, (xfs_off_t)buf->length);
1239
1240 memset(p, 0, buf->size);
1241 if (logstart % buf->length) { /* unaligned */
1242 read_wbuf(fd, buf, mp);
1243 offset = logstart - buf->position;
1244 p += offset;
1245 memset(p, 0, buf->length - offset);
1246 }
1247
1248 offset = libxfs_log_header(p, &buf->owner->uuid,
5e656dbb 1249 xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1,
0c12ba5f
BF
1250 mp->m_sb.sb_logsunit, XLOG_FMT, NULLCOMMITLSN,
1251 NULLCOMMITLSN, next_log_chunk, buf);
96866b03 1252 do_write(buf->owner, NULL);
989b74bc 1253
44e9ee90 1254 return roundup(logstart + offset, buf->length);
989b74bc
NS
1255}
1256
1257/*
1258 * May do an aligned read of the last buffer in the log (& zero
1259 * the start of that buffer). Returns the disk address at the
1260 * end of last aligned buffer in the log.
1261 */
1262xfs_off_t
1263write_log_trailer(int fd, wbuf *buf, xfs_mount_t *mp)
1264{
1265 xfs_off_t logend;
1266 int offset;
1267
1268 logend = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart) << BBSHIFT;
1269 logend += XFS_FSB_TO_B(mp, mp->m_sb.sb_logblocks);
1270
1271 buf->position = rounddown(logend, (xfs_off_t)buf->length);
1272
1273 if (logend % buf->length) { /* unaligned */
1274 read_wbuf(fd, buf, mp);
1275 offset = (int)(logend - buf->position);
1276 memset(buf->data, 0, offset);
96866b03 1277 do_write(buf->owner, NULL);
989b74bc
NS
1278 }
1279
1280 return buf->position;
1281}
54b0c4dc
BF
1282
1283/*
1284 * Clear a log by writing a record at the head, the tail and zeroing everything
1285 * in between.
1286 */
1287static void
1288clear_log(
1289 struct xfs_mount *mp,
1290 thread_args *tcarg)
1291{
1292 xfs_off_t pos;
1293 xfs_off_t end_pos;
1294
1295 w_buf.owner = tcarg;
1296 w_buf.length = rounddown(w_buf.size, w_buf.min_io_size);
1297 pos = write_log_header(source_fd, &w_buf, mp);
1298 end_pos = write_log_trailer(source_fd, &w_buf, mp);
1299 w_buf.position = pos;
1300 memset(w_buf.data, 0, w_buf.length);
1301
1302 while (w_buf.position < end_pos) {
1303 do_write(tcarg, NULL);
1304 w_buf.position += w_buf.length;
1305 }
1306}
1307
b4d947db
BF
1308/*
1309 * Format the log to a particular cycle number. This is required for version 5
1310 * superblock filesystems to provide metadata LSN validity guarantees.
1311 */
54b0c4dc 1312static void
b4d947db
BF
1313format_log(
1314 struct xfs_mount *mp,
1315 thread_args *tcarg,
1316 wbuf *buf)
1317{
1318 int logstart;
1319 int length;
1320 int cycle = XLOG_INIT_CYCLE;
1321
1322 buf->owner = tcarg;
1323 buf->length = buf->size;
1324 buf->position = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart) << BBSHIFT;
1325
1326 logstart = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logstart);
1327 length = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
1328
1329 /*
1330 * Bump the cycle number on v5 superblock filesystems to guarantee that
1331 * all existing metadata LSNs are valid (behind the current LSN) on the
1332 * target fs.
1333 */
1334 if (xfs_sb_version_hascrc(&mp->m_sb))
1335 cycle = mp->m_log->l_curr_cycle + 1;
1336
1337 /*
1338 * Format the entire log into the memory buffer and write it out. If the
1339 * write fails, mark the target inactive so the failure is reported.
1340 */
1341 libxfs_log_clear(NULL, buf->data, logstart, length, &buf->owner->uuid,
1342 xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1,
571a78a7 1343 mp->m_sb.sb_logsunit, XLOG_FMT, cycle, true);
b4d947db
BF
1344 if (do_write(buf->owner, buf))
1345 target[tcarg->id].state = INACTIVE;
1346}
1347
1348static int
54b0c4dc
BF
1349format_logs(
1350 struct xfs_mount *mp)
1351{
1352 thread_args *tcarg;
1353 int i;
b4d947db
BF
1354 wbuf logbuf;
1355 int logsize;
1356
1357 if (xfs_sb_version_hascrc(&mp->m_sb)) {
1358 logsize = XFS_FSB_TO_B(mp, mp->m_sb.sb_logblocks);
1359 if (!wbuf_init(&logbuf, logsize, w_buf.data_align,
1360 w_buf.min_io_size, w_buf.id))
1361 return -ENOMEM;
1362 }
54b0c4dc
BF
1363
1364 for (i = 0, tcarg = targ; i < num_targets; i++) {
b4d947db
BF
1365 if (xfs_sb_version_hascrc(&mp->m_sb))
1366 format_log(mp, tcarg, &logbuf);
1367 else
1368 clear_log(mp, tcarg);
54b0c4dc
BF
1369 tcarg++;
1370 }
b4d947db
BF
1371
1372 if (xfs_sb_version_hascrc(&mp->m_sb))
1373 free(logbuf.data);
1374
1375 return 0;
54b0c4dc 1376}