1a7fbbf91SMatthew Dillon /* 2a7fbbf91SMatthew Dillon * Copyright (c) 2008 The DragonFly Project. All rights reserved. 3a7fbbf91SMatthew Dillon * 4a7fbbf91SMatthew Dillon * This code is derived from software contributed to The DragonFly Project 5a7fbbf91SMatthew Dillon * by Matthew Dillon <dillon@backplane.com> 6a7fbbf91SMatthew Dillon * 7a7fbbf91SMatthew Dillon * Redistribution and use in source and binary forms, with or without 8a7fbbf91SMatthew Dillon * modification, are permitted provided that the following conditions 9a7fbbf91SMatthew Dillon * are met: 10a7fbbf91SMatthew Dillon * 11a7fbbf91SMatthew Dillon * 1. Redistributions of source code must retain the above copyright 12a7fbbf91SMatthew Dillon * notice, this list of conditions and the following disclaimer. 13a7fbbf91SMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright 14a7fbbf91SMatthew Dillon * notice, this list of conditions and the following disclaimer in 15a7fbbf91SMatthew Dillon * the documentation and/or other materials provided with the 16a7fbbf91SMatthew Dillon * distribution. 17a7fbbf91SMatthew Dillon * 3. Neither the name of The DragonFly Project nor the names of its 18a7fbbf91SMatthew Dillon * contributors may be used to endorse or promote products derived 19a7fbbf91SMatthew Dillon * from this software without specific, prior written permission. 20a7fbbf91SMatthew Dillon * 21a7fbbf91SMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22a7fbbf91SMatthew Dillon * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23a7fbbf91SMatthew Dillon * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24a7fbbf91SMatthew Dillon * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25a7fbbf91SMatthew Dillon * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26a7fbbf91SMatthew Dillon * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27a7fbbf91SMatthew Dillon * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28a7fbbf91SMatthew Dillon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29a7fbbf91SMatthew Dillon * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30a7fbbf91SMatthew Dillon * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31a7fbbf91SMatthew Dillon * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32a7fbbf91SMatthew Dillon * SUCH DAMAGE. 33a7fbbf91SMatthew Dillon * 34*53d93cc7SMatthew Dillon * $DragonFly: src/sbin/hammer/cmd_mirror.c,v 1.3 2008/07/04 07:20:43 dillon Exp $ 35a7fbbf91SMatthew Dillon */ 36a7fbbf91SMatthew Dillon 37a7fbbf91SMatthew Dillon #include "hammer.h" 38a7fbbf91SMatthew Dillon 39a7fbbf91SMatthew Dillon #define SERIALBUF_SIZE (512 * 1024) 40a7fbbf91SMatthew Dillon 4134ebae70SMatthew Dillon struct hammer_pfs_head { 4234ebae70SMatthew Dillon struct hammer_ioc_mrecord mrec; 4334ebae70SMatthew Dillon u_int32_t version; 4434ebae70SMatthew Dillon struct hammer_pseudofs_data pfsd; 4534ebae70SMatthew Dillon }; 4634ebae70SMatthew Dillon 47a7fbbf91SMatthew Dillon static int read_mrecords(int fd, char *buf, u_int size, 48a7fbbf91SMatthew Dillon hammer_ioc_mrecord_t pickup); 4934ebae70SMatthew Dillon static void generate_mrec_header(int fd, int fdout, 5034ebae70SMatthew Dillon hammer_tid_t *tid_begp, hammer_tid_t *tid_endp); 5134ebae70SMatthew Dillon static void validate_mrec_header(int fd, int fdin, 5234ebae70SMatthew Dillon hammer_tid_t *tid_begp, hammer_tid_t *tid_endp); 5334ebae70SMatthew Dillon static void run_cmd(const char *path, ...); 54a7fbbf91SMatthew Dillon static void mirror_usage(int code); 55a7fbbf91SMatthew Dillon 56a7fbbf91SMatthew Dillon void 57a7fbbf91SMatthew Dillon hammer_cmd_mirror_read(char **av, int ac) 58a7fbbf91SMatthew Dillon { 59a7fbbf91SMatthew Dillon struct hammer_ioc_mirror_rw mirror; 60a7fbbf91SMatthew Dillon const char *filesystem; 61a7fbbf91SMatthew Dillon char *buf = malloc(SERIALBUF_SIZE); 62a7fbbf91SMatthew Dillon int fd; 63a7fbbf91SMatthew Dillon 64a7fbbf91SMatthew Dillon if (ac > 2) 65a7fbbf91SMatthew Dillon mirror_usage(1); 66a7fbbf91SMatthew Dillon filesystem = av[0]; 67a7fbbf91SMatthew Dillon 68a7fbbf91SMatthew Dillon bzero(&mirror, sizeof(mirror)); 69a7fbbf91SMatthew Dillon hammer_key_beg_init(&mirror.key_beg); 70a7fbbf91SMatthew Dillon hammer_key_end_init(&mirror.key_end); 71a7fbbf91SMatthew Dillon 72a7fbbf91SMatthew Dillon fd = open(filesystem, O_RDONLY); 73a7fbbf91SMatthew Dillon if (fd < 0) 74a7fbbf91SMatthew Dillon err(1, "Unable to open %s", filesystem); 75a7fbbf91SMatthew Dillon 76a7fbbf91SMatthew Dillon hammer_get_cycle(&mirror.key_beg); 77a7fbbf91SMatthew Dillon 7834ebae70SMatthew Dillon generate_mrec_header(fd, 1, &mirror.tid_beg, &mirror.tid_end); 7934ebae70SMatthew Dillon 80a7fbbf91SMatthew Dillon mirror.ubuf = buf; 81a7fbbf91SMatthew Dillon mirror.size = SERIALBUF_SIZE; 8234ebae70SMatthew Dillon if (ac == 2) 8334ebae70SMatthew Dillon mirror.tid_beg = strtoull(av[1], NULL, 0); 84a7fbbf91SMatthew Dillon 85a7fbbf91SMatthew Dillon do { 86a7fbbf91SMatthew Dillon mirror.count = 0; 87a7fbbf91SMatthew Dillon if (ioctl(fd, HAMMERIOC_MIRROR_READ, &mirror) < 0) { 88a7fbbf91SMatthew Dillon fprintf(stderr, "Mirror-read %s failed: %s\n", 89a7fbbf91SMatthew Dillon filesystem, strerror(errno)); 90a7fbbf91SMatthew Dillon exit(1); 91a7fbbf91SMatthew Dillon } 92a7fbbf91SMatthew Dillon if (mirror.head.flags & HAMMER_IOC_HEAD_INTR) { 93a7fbbf91SMatthew Dillon fprintf(stderr, 94a7fbbf91SMatthew Dillon "Mirror-read %s interrupted by timer at" 95a7fbbf91SMatthew Dillon " %016llx %08x\n", 96a7fbbf91SMatthew Dillon filesystem, 97a7fbbf91SMatthew Dillon mirror.key_cur.obj_id, 98a7fbbf91SMatthew Dillon mirror.key_cur.localization); 99a7fbbf91SMatthew Dillon if (CyclePath) 100a7fbbf91SMatthew Dillon hammer_set_cycle(&mirror.key_cur); 101a7fbbf91SMatthew Dillon exit(0); 102a7fbbf91SMatthew Dillon } 103a7fbbf91SMatthew Dillon mirror.key_beg = mirror.key_cur; 104a7fbbf91SMatthew Dillon if (mirror.count) 105a7fbbf91SMatthew Dillon write(1, mirror.ubuf, mirror.count); 106a7fbbf91SMatthew Dillon } while (mirror.count != 0); 107a7fbbf91SMatthew Dillon 10834ebae70SMatthew Dillon /* generate_mrec_update(fd, 1); */ 10934ebae70SMatthew Dillon 110a7fbbf91SMatthew Dillon if (CyclePath) 111a7fbbf91SMatthew Dillon hammer_reset_cycle(); 112a7fbbf91SMatthew Dillon fprintf(stderr, "Mirror-read %s succeeded\n", filesystem); 113a7fbbf91SMatthew Dillon } 114a7fbbf91SMatthew Dillon 115a7fbbf91SMatthew Dillon void 116a7fbbf91SMatthew Dillon hammer_cmd_mirror_write(char **av, int ac) 117a7fbbf91SMatthew Dillon { 118a7fbbf91SMatthew Dillon struct hammer_ioc_mirror_rw mirror; 119a7fbbf91SMatthew Dillon const char *filesystem; 120a7fbbf91SMatthew Dillon char *buf = malloc(SERIALBUF_SIZE); 121a7fbbf91SMatthew Dillon int fd; 122a7fbbf91SMatthew Dillon struct hammer_ioc_mrecord pickup; 123a7fbbf91SMatthew Dillon 124a7fbbf91SMatthew Dillon if (ac > 2) 125a7fbbf91SMatthew Dillon mirror_usage(1); 126a7fbbf91SMatthew Dillon filesystem = av[0]; 127a7fbbf91SMatthew Dillon 128a7fbbf91SMatthew Dillon bzero(&mirror, sizeof(mirror)); 129a7fbbf91SMatthew Dillon hammer_key_beg_init(&mirror.key_beg); 130a7fbbf91SMatthew Dillon hammer_key_end_init(&mirror.key_end); 131a7fbbf91SMatthew Dillon 132a7fbbf91SMatthew Dillon fd = open(filesystem, O_RDONLY); 133a7fbbf91SMatthew Dillon if (fd < 0) 134a7fbbf91SMatthew Dillon err(1, "Unable to open %s", filesystem); 135a7fbbf91SMatthew Dillon 13634ebae70SMatthew Dillon validate_mrec_header(fd, 0, &mirror.tid_beg, &mirror.tid_end); 13734ebae70SMatthew Dillon 138a7fbbf91SMatthew Dillon mirror.ubuf = buf; 139a7fbbf91SMatthew Dillon mirror.size = SERIALBUF_SIZE; 140a7fbbf91SMatthew Dillon 141a7fbbf91SMatthew Dillon pickup.signature = 0; 142a7fbbf91SMatthew Dillon 143a7fbbf91SMatthew Dillon for (;;) { 144a7fbbf91SMatthew Dillon mirror.count = 0; 145a7fbbf91SMatthew Dillon mirror.size = read_mrecords(0, buf, SERIALBUF_SIZE, &pickup); 146a7fbbf91SMatthew Dillon if (mirror.size <= 0) 147a7fbbf91SMatthew Dillon break; 148a7fbbf91SMatthew Dillon if (ioctl(fd, HAMMERIOC_MIRROR_WRITE, &mirror) < 0) { 149a7fbbf91SMatthew Dillon fprintf(stderr, "Mirror-write %s failed: %s\n", 150a7fbbf91SMatthew Dillon filesystem, strerror(errno)); 151a7fbbf91SMatthew Dillon exit(1); 152a7fbbf91SMatthew Dillon } 153a7fbbf91SMatthew Dillon if (mirror.head.flags & HAMMER_IOC_HEAD_INTR) { 154a7fbbf91SMatthew Dillon fprintf(stderr, 155a7fbbf91SMatthew Dillon "Mirror-write %s interrupted by timer at" 156a7fbbf91SMatthew Dillon " %016llx %08x\n", 157a7fbbf91SMatthew Dillon filesystem, 158a7fbbf91SMatthew Dillon mirror.key_cur.obj_id, 159a7fbbf91SMatthew Dillon mirror.key_cur.localization); 160a7fbbf91SMatthew Dillon exit(0); 161a7fbbf91SMatthew Dillon } 162a7fbbf91SMatthew Dillon mirror.key_beg = mirror.key_cur; 163a7fbbf91SMatthew Dillon } 164a7fbbf91SMatthew Dillon fprintf(stderr, "Mirror-write %s succeeded\n", filesystem); 165a7fbbf91SMatthew Dillon } 166a7fbbf91SMatthew Dillon 167a7fbbf91SMatthew Dillon void 168a7fbbf91SMatthew Dillon hammer_cmd_mirror_copy(char **av, int ac) 169a7fbbf91SMatthew Dillon { 17034ebae70SMatthew Dillon pid_t pid1; 17134ebae70SMatthew Dillon pid_t pid2; 17234ebae70SMatthew Dillon int fds[2]; 17334ebae70SMatthew Dillon char *ptr; 17434ebae70SMatthew Dillon 17534ebae70SMatthew Dillon if (ac != 2) 17634ebae70SMatthew Dillon mirror_usage(1); 17734ebae70SMatthew Dillon 17834ebae70SMatthew Dillon if (pipe(fds) < 0) { 17934ebae70SMatthew Dillon perror("pipe"); 18034ebae70SMatthew Dillon exit(1); 18134ebae70SMatthew Dillon } 18234ebae70SMatthew Dillon 18334ebae70SMatthew Dillon /* 18434ebae70SMatthew Dillon * Source 18534ebae70SMatthew Dillon */ 18634ebae70SMatthew Dillon if ((pid1 = fork()) == 0) { 18734ebae70SMatthew Dillon dup2(fds[0], 0); 18834ebae70SMatthew Dillon dup2(fds[0], 1); 18934ebae70SMatthew Dillon close(fds[0]); 19034ebae70SMatthew Dillon close(fds[1]); 19134ebae70SMatthew Dillon if ((ptr = strchr(av[0], ':')) != NULL) { 19234ebae70SMatthew Dillon *ptr++ = 0; 19334ebae70SMatthew Dillon run_cmd("/usr/bin/ssh", "ssh", 19434ebae70SMatthew Dillon av[0], "hammer mirror-read", ptr, NULL); 19534ebae70SMatthew Dillon } else { 19634ebae70SMatthew Dillon hammer_cmd_mirror_read(av, 1); 19734ebae70SMatthew Dillon } 198*53d93cc7SMatthew Dillon _exit(1); 19934ebae70SMatthew Dillon } 20034ebae70SMatthew Dillon 20134ebae70SMatthew Dillon /* 20234ebae70SMatthew Dillon * Target 20334ebae70SMatthew Dillon */ 20434ebae70SMatthew Dillon if ((pid2 = fork()) == 0) { 20534ebae70SMatthew Dillon dup2(fds[1], 0); 20634ebae70SMatthew Dillon dup2(fds[1], 1); 20734ebae70SMatthew Dillon close(fds[0]); 20834ebae70SMatthew Dillon close(fds[1]); 20934ebae70SMatthew Dillon if ((ptr = strchr(av[1], ':')) != NULL) { 21034ebae70SMatthew Dillon *ptr++ = 0; 21134ebae70SMatthew Dillon run_cmd("/usr/bin/ssh", "ssh", 21234ebae70SMatthew Dillon av[1], "hammer mirror-write", ptr, NULL); 21334ebae70SMatthew Dillon } else { 21434ebae70SMatthew Dillon hammer_cmd_mirror_write(av + 1, 1); 21534ebae70SMatthew Dillon } 216*53d93cc7SMatthew Dillon _exit(1); 21734ebae70SMatthew Dillon } 21834ebae70SMatthew Dillon close(fds[0]); 21934ebae70SMatthew Dillon close(fds[1]); 22034ebae70SMatthew Dillon 22134ebae70SMatthew Dillon while (waitpid(pid1, NULL, 0) <= 0) 22234ebae70SMatthew Dillon ; 22334ebae70SMatthew Dillon while (waitpid(pid2, NULL, 0) <= 0) 22434ebae70SMatthew Dillon ; 225a7fbbf91SMatthew Dillon } 226a7fbbf91SMatthew Dillon 227a7fbbf91SMatthew Dillon static int 228a7fbbf91SMatthew Dillon read_mrecords(int fd, char *buf, u_int size, hammer_ioc_mrecord_t pickup) 229a7fbbf91SMatthew Dillon { 230a7fbbf91SMatthew Dillon u_int count; 231a7fbbf91SMatthew Dillon size_t n; 232a7fbbf91SMatthew Dillon size_t i; 233a7fbbf91SMatthew Dillon 234a7fbbf91SMatthew Dillon count = 0; 235a7fbbf91SMatthew Dillon while (size - count >= HAMMER_MREC_HEADSIZE) { 236a7fbbf91SMatthew Dillon /* 237a7fbbf91SMatthew Dillon * Cached the record header in case we run out of buffer 238a7fbbf91SMatthew Dillon * space. 239a7fbbf91SMatthew Dillon */ 240a7fbbf91SMatthew Dillon if (pickup->signature == 0) { 241a7fbbf91SMatthew Dillon for (n = 0; n < HAMMER_MREC_HEADSIZE; n += i) { 242a7fbbf91SMatthew Dillon i = read(fd, (char *)pickup + n, 243a7fbbf91SMatthew Dillon HAMMER_MREC_HEADSIZE - n); 244a7fbbf91SMatthew Dillon if (i <= 0) 245a7fbbf91SMatthew Dillon break; 246a7fbbf91SMatthew Dillon } 247a7fbbf91SMatthew Dillon if (n == 0) 248a7fbbf91SMatthew Dillon break; 249a7fbbf91SMatthew Dillon if (n != HAMMER_MREC_HEADSIZE) { 250a7fbbf91SMatthew Dillon fprintf(stderr, "read_mrecords: short read on pipe\n"); 251a7fbbf91SMatthew Dillon exit(1); 252a7fbbf91SMatthew Dillon } 253a7fbbf91SMatthew Dillon 254a7fbbf91SMatthew Dillon if (pickup->signature != HAMMER_IOC_MIRROR_SIGNATURE) { 255a7fbbf91SMatthew Dillon fprintf(stderr, "read_mrecords: malformed record on pipe, bad signature\n"); 256a7fbbf91SMatthew Dillon exit(1); 257a7fbbf91SMatthew Dillon } 258a7fbbf91SMatthew Dillon if (pickup->rec_crc != crc32((char *)pickup + HAMMER_MREC_CRCOFF, HAMMER_MREC_HEADSIZE - HAMMER_MREC_CRCOFF)) { 259a7fbbf91SMatthew Dillon fprintf(stderr, "read_mrecords: malformed record on pipe, bad crc\n"); 260a7fbbf91SMatthew Dillon exit(1); 261a7fbbf91SMatthew Dillon } 262a7fbbf91SMatthew Dillon } 263a7fbbf91SMatthew Dillon if (pickup->rec_size < HAMMER_MREC_HEADSIZE || 264a7fbbf91SMatthew Dillon pickup->rec_size > HAMMER_MREC_HEADSIZE + HAMMER_XBUFSIZE) { 265a7fbbf91SMatthew Dillon fprintf(stderr, "read_mrecords: malformed record on pipe, illegal rec_size\n"); 266a7fbbf91SMatthew Dillon exit(1); 267a7fbbf91SMatthew Dillon } 268a7fbbf91SMatthew Dillon if (HAMMER_MREC_HEADSIZE + pickup->leaf.data_len > pickup->rec_size) { 269a7fbbf91SMatthew Dillon fprintf(stderr, "read_mrecords: malformed record on pipe, illegal element data_len\n"); 270a7fbbf91SMatthew Dillon exit(1); 271a7fbbf91SMatthew Dillon } 272a7fbbf91SMatthew Dillon 273a7fbbf91SMatthew Dillon /* 274a7fbbf91SMatthew Dillon * Stop if we have insufficient space for the record and data. 275a7fbbf91SMatthew Dillon */ 276a7fbbf91SMatthew Dillon if (size - count < pickup->rec_size) 277a7fbbf91SMatthew Dillon break; 278a7fbbf91SMatthew Dillon 279a7fbbf91SMatthew Dillon /* 280a7fbbf91SMatthew Dillon * Read the remainder and clear the pickup signature. 281a7fbbf91SMatthew Dillon */ 282a7fbbf91SMatthew Dillon bcopy(pickup, buf + count, HAMMER_MREC_HEADSIZE); 283a7fbbf91SMatthew Dillon pickup->signature = 0; 284a7fbbf91SMatthew Dillon for (n = HAMMER_MREC_HEADSIZE; n < pickup->rec_size; n += i) { 285a7fbbf91SMatthew Dillon i = read(fd, buf + count + n, pickup->rec_size - n); 286a7fbbf91SMatthew Dillon if (i <= 0) 287a7fbbf91SMatthew Dillon break; 288a7fbbf91SMatthew Dillon } 289a7fbbf91SMatthew Dillon if (n != pickup->rec_size) { 290a7fbbf91SMatthew Dillon fprintf(stderr, "read_mrecords: short read on pipe\n"); 291a7fbbf91SMatthew Dillon exit(1); 292a7fbbf91SMatthew Dillon } 293a7fbbf91SMatthew Dillon if (pickup->leaf.data_len && pickup->leaf.data_offset) { 294a7fbbf91SMatthew Dillon if (hammer_crc_test_leaf(buf + count + HAMMER_MREC_HEADSIZE, &pickup->leaf) == 0) { 295a7fbbf91SMatthew Dillon fprintf(stderr, "read_mrecords: data_crc did not match data! obj=%016llx key=%016llx\n", pickup->leaf.base.obj_id, pickup->leaf.base.key); 296a7fbbf91SMatthew Dillon fprintf(stderr, "continuing, but there are problems\n"); 297a7fbbf91SMatthew Dillon } 298a7fbbf91SMatthew Dillon } 299a7fbbf91SMatthew Dillon 300a7fbbf91SMatthew Dillon count += pickup->rec_size; 301a7fbbf91SMatthew Dillon } 302a7fbbf91SMatthew Dillon return(count); 303a7fbbf91SMatthew Dillon } 304a7fbbf91SMatthew Dillon 30534ebae70SMatthew Dillon /* 30634ebae70SMatthew Dillon * Generate a mirroring header with the pfs information of the 30734ebae70SMatthew Dillon * originating filesytem. 30834ebae70SMatthew Dillon */ 30934ebae70SMatthew Dillon static void 31034ebae70SMatthew Dillon generate_mrec_header(int fd, int fdout, 31134ebae70SMatthew Dillon hammer_tid_t *tid_begp, hammer_tid_t *tid_endp) 31234ebae70SMatthew Dillon { 31334ebae70SMatthew Dillon struct hammer_ioc_pseudofs_rw pfs; 31434ebae70SMatthew Dillon struct hammer_pfs_head pfs_head; 31534ebae70SMatthew Dillon 31634ebae70SMatthew Dillon bzero(&pfs, sizeof(pfs)); 31734ebae70SMatthew Dillon bzero(&pfs_head, sizeof(pfs_head)); 31834ebae70SMatthew Dillon pfs.ondisk = &pfs_head.pfsd; 31934ebae70SMatthew Dillon pfs.bytes = sizeof(pfs_head.pfsd); 32034ebae70SMatthew Dillon if (ioctl(fd, HAMMERIOC_GET_PSEUDOFS, &pfs) != 0) { 32134ebae70SMatthew Dillon fprintf(stderr, "mirror-read: not a HAMMER fs/pseudofs!\n"); 32234ebae70SMatthew Dillon exit(1); 32334ebae70SMatthew Dillon } 32434ebae70SMatthew Dillon if (pfs.version != HAMMER_IOC_PSEUDOFS_VERSION) { 32534ebae70SMatthew Dillon fprintf(stderr, "mirror-read: HAMMER pfs version mismatch!\n"); 32634ebae70SMatthew Dillon exit(1); 32734ebae70SMatthew Dillon } 32834ebae70SMatthew Dillon 32934ebae70SMatthew Dillon /* 33034ebae70SMatthew Dillon * sync_beg_tid - lowest TID on source after which a full history 33134ebae70SMatthew Dillon * is available. 33234ebae70SMatthew Dillon * 33334ebae70SMatthew Dillon * sync_end_tid - highest fully synchronized TID from source. 33434ebae70SMatthew Dillon */ 33534ebae70SMatthew Dillon *tid_begp = pfs_head.pfsd.sync_beg_tid; 33634ebae70SMatthew Dillon *tid_endp = pfs_head.pfsd.sync_end_tid; 33734ebae70SMatthew Dillon 33834ebae70SMatthew Dillon pfs_head.version = pfs.version; 33934ebae70SMatthew Dillon pfs_head.mrec.signature = HAMMER_IOC_MIRROR_SIGNATURE; 34034ebae70SMatthew Dillon pfs_head.mrec.rec_size = sizeof(pfs_head); 34134ebae70SMatthew Dillon pfs_head.mrec.type = HAMMER_MREC_TYPE_PFSD; 34234ebae70SMatthew Dillon pfs_head.mrec.rec_crc = crc32((char *)&pfs_head + HAMMER_MREC_CRCOFF, 34334ebae70SMatthew Dillon sizeof(pfs_head) - HAMMER_MREC_CRCOFF); 34434ebae70SMatthew Dillon write(fdout, &pfs_head, sizeof(pfs_head)); 34534ebae70SMatthew Dillon } 34634ebae70SMatthew Dillon 34734ebae70SMatthew Dillon /* 34834ebae70SMatthew Dillon * Validate the pfs information from the originating filesystem 34934ebae70SMatthew Dillon * against the target filesystem. shared_uuid must match. 35034ebae70SMatthew Dillon */ 35134ebae70SMatthew Dillon static void 35234ebae70SMatthew Dillon validate_mrec_header(int fd, int fdin, 35334ebae70SMatthew Dillon hammer_tid_t *tid_begp, hammer_tid_t *tid_endp) 35434ebae70SMatthew Dillon { 35534ebae70SMatthew Dillon struct hammer_ioc_pseudofs_rw pfs; 35634ebae70SMatthew Dillon struct hammer_pfs_head pfs_head; 35734ebae70SMatthew Dillon struct hammer_pseudofs_data pfsd; 35834ebae70SMatthew Dillon size_t bytes; 35934ebae70SMatthew Dillon size_t n; 36034ebae70SMatthew Dillon size_t i; 36134ebae70SMatthew Dillon 36234ebae70SMatthew Dillon /* 36334ebae70SMatthew Dillon * Get the PFSD info from the target filesystem. 36434ebae70SMatthew Dillon */ 36534ebae70SMatthew Dillon bzero(&pfs, sizeof(pfs)); 36634ebae70SMatthew Dillon bzero(&pfsd, sizeof(pfsd)); 36734ebae70SMatthew Dillon pfs.ondisk = &pfsd; 36834ebae70SMatthew Dillon pfs.bytes = sizeof(pfsd); 36934ebae70SMatthew Dillon if (ioctl(fd, HAMMERIOC_GET_PSEUDOFS, &pfs) != 0) { 37034ebae70SMatthew Dillon fprintf(stderr, "mirror-write: not a HAMMER fs/pseudofs!\n"); 37134ebae70SMatthew Dillon exit(1); 37234ebae70SMatthew Dillon } 37334ebae70SMatthew Dillon if (pfs.version != HAMMER_IOC_PSEUDOFS_VERSION) { 37434ebae70SMatthew Dillon fprintf(stderr, "mirror-write: HAMMER pfs version mismatch!\n"); 37534ebae70SMatthew Dillon exit(1); 37634ebae70SMatthew Dillon } 37734ebae70SMatthew Dillon 37834ebae70SMatthew Dillon /* 37934ebae70SMatthew Dillon * Read in the PFSD header from the sender. 38034ebae70SMatthew Dillon */ 38134ebae70SMatthew Dillon for (n = 0; n < HAMMER_MREC_HEADSIZE; n += i) { 38234ebae70SMatthew Dillon i = read(fdin, (char *)&pfs_head + n, HAMMER_MREC_HEADSIZE - n); 38334ebae70SMatthew Dillon if (i <= 0) 38434ebae70SMatthew Dillon break; 38534ebae70SMatthew Dillon } 38634ebae70SMatthew Dillon if (n != HAMMER_MREC_HEADSIZE) { 38734ebae70SMatthew Dillon fprintf(stderr, "mirror-write: short read of PFS header\n"); 38834ebae70SMatthew Dillon exit(1); 38934ebae70SMatthew Dillon } 39034ebae70SMatthew Dillon if (pfs_head.mrec.signature != HAMMER_IOC_MIRROR_SIGNATURE) { 39134ebae70SMatthew Dillon fprintf(stderr, "mirror-write: PFS header has bad signature\n"); 39234ebae70SMatthew Dillon exit(1); 39334ebae70SMatthew Dillon } 39434ebae70SMatthew Dillon if (pfs_head.mrec.type != HAMMER_MREC_TYPE_PFSD) { 39534ebae70SMatthew Dillon fprintf(stderr, "mirror-write: Expected PFS header, got mirroring record header instead!\n"); 39634ebae70SMatthew Dillon exit(1); 39734ebae70SMatthew Dillon } 39834ebae70SMatthew Dillon bytes = pfs_head.mrec.rec_size; 39934ebae70SMatthew Dillon if (bytes < HAMMER_MREC_HEADSIZE) 40034ebae70SMatthew Dillon bytes = (int)HAMMER_MREC_HEADSIZE; 40134ebae70SMatthew Dillon if (bytes > sizeof(pfs_head)) 40234ebae70SMatthew Dillon bytes = sizeof(pfs_head); 40334ebae70SMatthew Dillon while (n < bytes) { 40434ebae70SMatthew Dillon i = read(fdin, (char *)&pfs_head + n, bytes - n); 40534ebae70SMatthew Dillon if (i <= 0) 40634ebae70SMatthew Dillon break; 40734ebae70SMatthew Dillon n += i; 40834ebae70SMatthew Dillon } 40934ebae70SMatthew Dillon if (n != bytes) { 41034ebae70SMatthew Dillon fprintf(stderr, "mirror-write: short read of PFS payload\n"); 41134ebae70SMatthew Dillon exit(1); 41234ebae70SMatthew Dillon } 41334ebae70SMatthew Dillon if (pfs_head.version != pfs.version) { 41434ebae70SMatthew Dillon fprintf(stderr, "mirror-write: Version mismatch in PFS header\n"); 41534ebae70SMatthew Dillon exit(1); 41634ebae70SMatthew Dillon } 41734ebae70SMatthew Dillon if (pfs_head.mrec.rec_size != sizeof(pfs_head)) { 41834ebae70SMatthew Dillon fprintf(stderr, "mirror-write: The PFS header has the wrong size!\n"); 41934ebae70SMatthew Dillon exit(1); 42034ebae70SMatthew Dillon } 42134ebae70SMatthew Dillon 42234ebae70SMatthew Dillon /* 42334ebae70SMatthew Dillon * Whew. Ok, is the read PFS info compatible with the target? 42434ebae70SMatthew Dillon */ 42534ebae70SMatthew Dillon if (bcmp(&pfs_head.pfsd.shared_uuid, &pfsd.shared_uuid, sizeof(pfsd.shared_uuid)) != 0) { 42634ebae70SMatthew Dillon fprintf(stderr, "mirror-write: source and target have different shared_uuid's!\n"); 42734ebae70SMatthew Dillon exit(1); 42834ebae70SMatthew Dillon } 42934ebae70SMatthew Dillon if ((pfsd.mirror_flags & HAMMER_PFSD_SLAVE) == 0) { 43034ebae70SMatthew Dillon fprintf(stderr, "mirror-write: target must be in slave mode\n"); 43134ebae70SMatthew Dillon exit(1); 43234ebae70SMatthew Dillon } 43334ebae70SMatthew Dillon *tid_begp = pfs_head.pfsd.sync_beg_tid; 43434ebae70SMatthew Dillon *tid_endp = pfs_head.pfsd.sync_end_tid; 43534ebae70SMatthew Dillon } 43634ebae70SMatthew Dillon 43734ebae70SMatthew Dillon static void 43834ebae70SMatthew Dillon run_cmd(const char *path, ...) 43934ebae70SMatthew Dillon { 44034ebae70SMatthew Dillon va_list va; 44134ebae70SMatthew Dillon char *av[16]; 44234ebae70SMatthew Dillon int n; 44334ebae70SMatthew Dillon 44434ebae70SMatthew Dillon va_start(va, path); 44534ebae70SMatthew Dillon for (n = 0; n < 16; ++n) { 44634ebae70SMatthew Dillon av[n] = va_arg(va, char *); 44734ebae70SMatthew Dillon if (av[n] == NULL) 44834ebae70SMatthew Dillon break; 44934ebae70SMatthew Dillon } 45034ebae70SMatthew Dillon va_end(va); 45134ebae70SMatthew Dillon assert(n != 16); 45234ebae70SMatthew Dillon execv(path, av); 45334ebae70SMatthew Dillon } 45434ebae70SMatthew Dillon 455a7fbbf91SMatthew Dillon static void 456a7fbbf91SMatthew Dillon mirror_usage(int code) 457a7fbbf91SMatthew Dillon { 458a7fbbf91SMatthew Dillon fprintf(stderr, 459a7fbbf91SMatthew Dillon "hammer mirror-read <filesystem>\n" 460a7fbbf91SMatthew Dillon "hammer mirror-write <filesystem>\n" 461a7fbbf91SMatthew Dillon "hammer mirror-copy [[user@]host:]fs [[user@]host:]fs\n" 462a7fbbf91SMatthew Dillon ); 463a7fbbf91SMatthew Dillon exit(code); 464a7fbbf91SMatthew Dillon } 465