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*243ca327SMatthew Dillon * $DragonFly: src/sbin/hammer/cmd_mirror.c,v 1.4 2008/07/07 00:27:22 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 u_int32_t version; 4334ebae70SMatthew Dillon struct hammer_pseudofs_data pfsd; 4434ebae70SMatthew Dillon }; 4534ebae70SMatthew Dillon 46a7fbbf91SMatthew Dillon static int read_mrecords(int fd, char *buf, u_int size, 47a7fbbf91SMatthew Dillon hammer_ioc_mrecord_t pickup); 48*243ca327SMatthew Dillon static struct hammer_ioc_mrecord *read_mrecord(int fdin, int *errorp, 49*243ca327SMatthew Dillon hammer_ioc_mrecord_t pickup); 50*243ca327SMatthew Dillon static void write_mrecord(int fdout, u_int32_t type, void *payload, int bytes); 5134ebae70SMatthew Dillon static void generate_mrec_header(int fd, int fdout, 5234ebae70SMatthew Dillon hammer_tid_t *tid_begp, hammer_tid_t *tid_endp); 5334ebae70SMatthew Dillon static void validate_mrec_header(int fd, int fdin, 5434ebae70SMatthew Dillon hammer_tid_t *tid_begp, hammer_tid_t *tid_endp); 55*243ca327SMatthew Dillon static void update_pfs_snapshot(int fd, hammer_tid_t snapshot_tid); 56a7fbbf91SMatthew Dillon static void mirror_usage(int code); 57a7fbbf91SMatthew Dillon 58a7fbbf91SMatthew Dillon void 59a7fbbf91SMatthew Dillon hammer_cmd_mirror_read(char **av, int ac) 60a7fbbf91SMatthew Dillon { 61a7fbbf91SMatthew Dillon struct hammer_ioc_mirror_rw mirror; 62*243ca327SMatthew Dillon hammer_ioc_mrecord_t mrec; 63*243ca327SMatthew Dillon hammer_tid_t sync_tid; 64a7fbbf91SMatthew Dillon const char *filesystem; 65a7fbbf91SMatthew Dillon char *buf = malloc(SERIALBUF_SIZE); 66*243ca327SMatthew Dillon int interrupted = 0; 67*243ca327SMatthew Dillon int error; 68a7fbbf91SMatthew Dillon int fd; 69*243ca327SMatthew Dillon int n; 70*243ca327SMatthew Dillon time_t base_t = time(NULL); 71a7fbbf91SMatthew Dillon 72a7fbbf91SMatthew Dillon if (ac > 2) 73a7fbbf91SMatthew Dillon mirror_usage(1); 74a7fbbf91SMatthew Dillon filesystem = av[0]; 75a7fbbf91SMatthew Dillon 76a7fbbf91SMatthew Dillon bzero(&mirror, sizeof(mirror)); 77a7fbbf91SMatthew Dillon hammer_key_beg_init(&mirror.key_beg); 78a7fbbf91SMatthew Dillon hammer_key_end_init(&mirror.key_end); 79a7fbbf91SMatthew Dillon 80a7fbbf91SMatthew Dillon fd = open(filesystem, O_RDONLY); 81a7fbbf91SMatthew Dillon if (fd < 0) 82a7fbbf91SMatthew Dillon err(1, "Unable to open %s", filesystem); 83a7fbbf91SMatthew Dillon 84*243ca327SMatthew Dillon /* 85*243ca327SMatthew Dillon * Write out the PFS header 86*243ca327SMatthew Dillon */ 8734ebae70SMatthew Dillon generate_mrec_header(fd, 1, &mirror.tid_beg, &mirror.tid_end); 88*243ca327SMatthew Dillon hammer_get_cycle(&mirror.key_beg, &mirror.tid_beg); 8934ebae70SMatthew Dillon 90*243ca327SMatthew Dillon fprintf(stderr, "mirror-read: Mirror from %016llx to %016llx\n", 91*243ca327SMatthew Dillon mirror.tid_beg, mirror.tid_end); 92*243ca327SMatthew Dillon if (mirror.key_beg.obj_id != (int64_t)HAMMER_MIN_OBJID) { 93*243ca327SMatthew Dillon fprintf(stderr, "mirror-read: Resuming at object %016llx\n", 94*243ca327SMatthew Dillon mirror.key_beg.obj_id); 95*243ca327SMatthew Dillon } 96*243ca327SMatthew Dillon 97*243ca327SMatthew Dillon /* 98*243ca327SMatthew Dillon * Write out bulk records 99*243ca327SMatthew Dillon */ 100a7fbbf91SMatthew Dillon mirror.ubuf = buf; 101a7fbbf91SMatthew Dillon mirror.size = SERIALBUF_SIZE; 10234ebae70SMatthew Dillon if (ac == 2) 10334ebae70SMatthew Dillon mirror.tid_beg = strtoull(av[1], NULL, 0); 104a7fbbf91SMatthew Dillon 105a7fbbf91SMatthew Dillon do { 106a7fbbf91SMatthew Dillon mirror.count = 0; 107a7fbbf91SMatthew Dillon if (ioctl(fd, HAMMERIOC_MIRROR_READ, &mirror) < 0) { 108a7fbbf91SMatthew Dillon fprintf(stderr, "Mirror-read %s failed: %s\n", 109a7fbbf91SMatthew Dillon filesystem, strerror(errno)); 110a7fbbf91SMatthew Dillon exit(1); 111a7fbbf91SMatthew Dillon } 112*243ca327SMatthew Dillon if (mirror.count) { 113*243ca327SMatthew Dillon n = write(1, mirror.ubuf, mirror.count); 114*243ca327SMatthew Dillon if (n != mirror.count) { 115*243ca327SMatthew Dillon fprintf(stderr, "Mirror-read %s failed: " 116*243ca327SMatthew Dillon "short write\n", 117*243ca327SMatthew Dillon filesystem); 118*243ca327SMatthew Dillon exit(1); 119*243ca327SMatthew Dillon } 120a7fbbf91SMatthew Dillon } 121a7fbbf91SMatthew Dillon mirror.key_beg = mirror.key_cur; 122*243ca327SMatthew Dillon if (TimeoutOpt && 123*243ca327SMatthew Dillon (unsigned)(time(NULL) - base_t) > (unsigned)TimeoutOpt) { 124*243ca327SMatthew Dillon fprintf(stderr, 125*243ca327SMatthew Dillon "Mirror-read %s interrupted by timer at" 126*243ca327SMatthew Dillon " %016llx\n", 127*243ca327SMatthew Dillon filesystem, 128*243ca327SMatthew Dillon mirror.key_cur.obj_id); 129*243ca327SMatthew Dillon interrupted = 1; 130*243ca327SMatthew Dillon break; 131*243ca327SMatthew Dillon } 132a7fbbf91SMatthew Dillon } while (mirror.count != 0); 133a7fbbf91SMatthew Dillon 134*243ca327SMatthew Dillon /* 135*243ca327SMatthew Dillon * Write out the termination sync record 136*243ca327SMatthew Dillon */ 137*243ca327SMatthew Dillon write_mrecord(1, HAMMER_MREC_TYPE_SYNC, NULL, 0); 13834ebae70SMatthew Dillon 139*243ca327SMatthew Dillon /* 140*243ca327SMatthew Dillon * If the -2 option was given (automatic when doing mirror-copy), 141*243ca327SMatthew Dillon * a two-way pipe is assumed and we expect a response mrec from 142*243ca327SMatthew Dillon * the target. 143*243ca327SMatthew Dillon */ 144*243ca327SMatthew Dillon if (TwoWayPipeOpt) { 145*243ca327SMatthew Dillon mrec = read_mrecord(0, &error, NULL); 146*243ca327SMatthew Dillon if (mrec == NULL || mrec->type != HAMMER_MREC_TYPE_UPDATE) { 147*243ca327SMatthew Dillon fprintf(stderr, "mirror_read: Did not get final " 148*243ca327SMatthew Dillon "acknowledgement packet from target\n"); 149*243ca327SMatthew Dillon exit(1); 150*243ca327SMatthew Dillon } 151*243ca327SMatthew Dillon if (interrupted) { 152*243ca327SMatthew Dillon if (CyclePath) { 153*243ca327SMatthew Dillon hammer_set_cycle(&mirror.key_cur, mirror.tid_beg); 154*243ca327SMatthew Dillon fprintf(stderr, "Cyclefile %s updated for continuation\n", CyclePath); 155*243ca327SMatthew Dillon } 156*243ca327SMatthew Dillon } else { 157*243ca327SMatthew Dillon sync_tid = *(hammer_tid_t *)(mrec + 1); 158*243ca327SMatthew Dillon if (CyclePath) { 159*243ca327SMatthew Dillon hammer_key_beg_init(&mirror.key_beg); 160*243ca327SMatthew Dillon hammer_set_cycle(&mirror.key_beg, sync_tid); 161*243ca327SMatthew Dillon fprintf(stderr, "Cyclefile %s updated to 0x%016llx\n", 162*243ca327SMatthew Dillon CyclePath, sync_tid); 163*243ca327SMatthew Dillon } else { 164*243ca327SMatthew Dillon fprintf(stderr, "Source can update synctid " 165*243ca327SMatthew Dillon "to 0x%016llx\n", 166*243ca327SMatthew Dillon sync_tid); 167*243ca327SMatthew Dillon } 168*243ca327SMatthew Dillon } 169*243ca327SMatthew Dillon } else if (CyclePath) { 170*243ca327SMatthew Dillon /* NOTE! mirror.tid_beg cannot be updated */ 171*243ca327SMatthew Dillon fprintf(stderr, "Warning: cycle file (-c option) cannot be " 172*243ca327SMatthew Dillon "fully updated unless you use mirror-copy\n"); 173*243ca327SMatthew Dillon hammer_set_cycle(&mirror.key_beg, mirror.tid_beg); 174*243ca327SMatthew Dillon } 175a7fbbf91SMatthew Dillon fprintf(stderr, "Mirror-read %s succeeded\n", filesystem); 176a7fbbf91SMatthew Dillon } 177a7fbbf91SMatthew Dillon 178a7fbbf91SMatthew Dillon void 179a7fbbf91SMatthew Dillon hammer_cmd_mirror_write(char **av, int ac) 180a7fbbf91SMatthew Dillon { 181a7fbbf91SMatthew Dillon struct hammer_ioc_mirror_rw mirror; 182a7fbbf91SMatthew Dillon const char *filesystem; 183a7fbbf91SMatthew Dillon char *buf = malloc(SERIALBUF_SIZE); 184a7fbbf91SMatthew Dillon struct hammer_ioc_mrecord pickup; 185*243ca327SMatthew Dillon struct hammer_ioc_synctid synctid; 186*243ca327SMatthew Dillon hammer_ioc_mrecord_t mrec; 187*243ca327SMatthew Dillon int error; 188*243ca327SMatthew Dillon int fd; 189a7fbbf91SMatthew Dillon 190a7fbbf91SMatthew Dillon if (ac > 2) 191a7fbbf91SMatthew Dillon mirror_usage(1); 192a7fbbf91SMatthew Dillon filesystem = av[0]; 193a7fbbf91SMatthew Dillon 194a7fbbf91SMatthew Dillon bzero(&mirror, sizeof(mirror)); 195a7fbbf91SMatthew Dillon hammer_key_beg_init(&mirror.key_beg); 196a7fbbf91SMatthew Dillon hammer_key_end_init(&mirror.key_end); 197a7fbbf91SMatthew Dillon 198a7fbbf91SMatthew Dillon fd = open(filesystem, O_RDONLY); 199a7fbbf91SMatthew Dillon if (fd < 0) 200a7fbbf91SMatthew Dillon err(1, "Unable to open %s", filesystem); 201a7fbbf91SMatthew Dillon 202*243ca327SMatthew Dillon /* 203*243ca327SMatthew Dillon * Read and process the PFS header 204*243ca327SMatthew Dillon */ 20534ebae70SMatthew Dillon validate_mrec_header(fd, 0, &mirror.tid_beg, &mirror.tid_end); 20634ebae70SMatthew Dillon 207a7fbbf91SMatthew Dillon mirror.ubuf = buf; 208a7fbbf91SMatthew Dillon mirror.size = SERIALBUF_SIZE; 209a7fbbf91SMatthew Dillon 210a7fbbf91SMatthew Dillon pickup.signature = 0; 211*243ca327SMatthew Dillon pickup.type = 0; 212a7fbbf91SMatthew Dillon 213*243ca327SMatthew Dillon /* 214*243ca327SMatthew Dillon * Read and process bulk records 215*243ca327SMatthew Dillon */ 216a7fbbf91SMatthew Dillon for (;;) { 217a7fbbf91SMatthew Dillon mirror.count = 0; 218a7fbbf91SMatthew Dillon mirror.size = read_mrecords(0, buf, SERIALBUF_SIZE, &pickup); 219a7fbbf91SMatthew Dillon if (mirror.size <= 0) 220a7fbbf91SMatthew Dillon break; 221a7fbbf91SMatthew Dillon if (ioctl(fd, HAMMERIOC_MIRROR_WRITE, &mirror) < 0) { 222a7fbbf91SMatthew Dillon fprintf(stderr, "Mirror-write %s failed: %s\n", 223a7fbbf91SMatthew Dillon filesystem, strerror(errno)); 224a7fbbf91SMatthew Dillon exit(1); 225a7fbbf91SMatthew Dillon } 226*243ca327SMatthew Dillon #if 0 227a7fbbf91SMatthew Dillon if (mirror.head.flags & HAMMER_IOC_HEAD_INTR) { 228a7fbbf91SMatthew Dillon fprintf(stderr, 229a7fbbf91SMatthew Dillon "Mirror-write %s interrupted by timer at" 230*243ca327SMatthew Dillon " %016llx\n", 231a7fbbf91SMatthew Dillon filesystem, 232*243ca327SMatthew Dillon mirror.key_cur.obj_id); 233a7fbbf91SMatthew Dillon exit(0); 234a7fbbf91SMatthew Dillon } 235*243ca327SMatthew Dillon #endif 236a7fbbf91SMatthew Dillon mirror.key_beg = mirror.key_cur; 237a7fbbf91SMatthew Dillon } 238*243ca327SMatthew Dillon 239*243ca327SMatthew Dillon /* 240*243ca327SMatthew Dillon * Read and process the termination sync record. 241*243ca327SMatthew Dillon */ 242*243ca327SMatthew Dillon mrec = read_mrecord(0, &error, &pickup); 243*243ca327SMatthew Dillon if (mrec == NULL || mrec->type != HAMMER_MREC_TYPE_SYNC) { 244*243ca327SMatthew Dillon fprintf(stderr, "Mirror-write %s: Did not get termination " 245*243ca327SMatthew Dillon "sync record\n", 246*243ca327SMatthew Dillon filesystem); 247*243ca327SMatthew Dillon } 248*243ca327SMatthew Dillon 249*243ca327SMatthew Dillon /* 250*243ca327SMatthew Dillon * Update the PFS info on the target so the user has visibility 251*243ca327SMatthew Dillon * into the new snapshot. 252*243ca327SMatthew Dillon */ 253*243ca327SMatthew Dillon update_pfs_snapshot(fd, mirror.tid_end); 254*243ca327SMatthew Dillon 255*243ca327SMatthew Dillon /* 256*243ca327SMatthew Dillon * Sync the target filesystem 257*243ca327SMatthew Dillon */ 258*243ca327SMatthew Dillon bzero(&synctid, sizeof(synctid)); 259*243ca327SMatthew Dillon synctid.op = HAMMER_SYNCTID_SYNC2; 260*243ca327SMatthew Dillon ioctl(fd, HAMMERIOC_SYNCTID, &synctid); 261*243ca327SMatthew Dillon 262*243ca327SMatthew Dillon fprintf(stderr, "Mirror-write %s: succeeded\n", filesystem); 263*243ca327SMatthew Dillon 264*243ca327SMatthew Dillon /* 265*243ca327SMatthew Dillon * Report back to the originator. 266*243ca327SMatthew Dillon */ 267*243ca327SMatthew Dillon if (TwoWayPipeOpt) { 268*243ca327SMatthew Dillon write_mrecord(1, HAMMER_MREC_TYPE_UPDATE, 269*243ca327SMatthew Dillon &mirror.tid_end, sizeof(mirror.tid_end)); 270*243ca327SMatthew Dillon } else { 271*243ca327SMatthew Dillon printf("Source can update synctid to 0x%016llx\n", 272*243ca327SMatthew Dillon mirror.tid_end); 273*243ca327SMatthew Dillon } 274*243ca327SMatthew Dillon } 275*243ca327SMatthew Dillon 276*243ca327SMatthew Dillon void 277*243ca327SMatthew Dillon hammer_cmd_mirror_dump(void) 278*243ca327SMatthew Dillon { 279*243ca327SMatthew Dillon char *buf = malloc(SERIALBUF_SIZE); 280*243ca327SMatthew Dillon struct hammer_ioc_mrecord pickup; 281*243ca327SMatthew Dillon hammer_ioc_mrecord_t mrec; 282*243ca327SMatthew Dillon int error; 283*243ca327SMatthew Dillon int size; 284*243ca327SMatthew Dillon 285*243ca327SMatthew Dillon /* 286*243ca327SMatthew Dillon * Read and process the PFS header 287*243ca327SMatthew Dillon */ 288*243ca327SMatthew Dillon pickup.signature = 0; 289*243ca327SMatthew Dillon pickup.type = 0; 290*243ca327SMatthew Dillon 291*243ca327SMatthew Dillon mrec = read_mrecord(0, &error, &pickup); 292*243ca327SMatthew Dillon 293*243ca327SMatthew Dillon /* 294*243ca327SMatthew Dillon * Read and process bulk records 295*243ca327SMatthew Dillon */ 296*243ca327SMatthew Dillon for (;;) { 297*243ca327SMatthew Dillon size = read_mrecords(0, buf, SERIALBUF_SIZE, &pickup); 298*243ca327SMatthew Dillon if (size <= 0) 299*243ca327SMatthew Dillon break; 300*243ca327SMatthew Dillon mrec = (void *)buf; 301*243ca327SMatthew Dillon while (mrec < (hammer_ioc_mrecord_t)((char *)buf + size)) { 302*243ca327SMatthew Dillon printf("Record obj=%016llx key=%016llx " 303*243ca327SMatthew Dillon "rt=%02x ot=%02x\n", 304*243ca327SMatthew Dillon mrec->leaf.base.obj_id, 305*243ca327SMatthew Dillon mrec->leaf.base.key, 306*243ca327SMatthew Dillon mrec->leaf.base.rec_type, 307*243ca327SMatthew Dillon mrec->leaf.base.obj_type); 308*243ca327SMatthew Dillon printf(" tids %016llx:%016llx data=%d\n", 309*243ca327SMatthew Dillon mrec->leaf.base.create_tid, 310*243ca327SMatthew Dillon mrec->leaf.base.delete_tid, 311*243ca327SMatthew Dillon mrec->leaf.data_len); 312*243ca327SMatthew Dillon mrec = (void *)((char *)mrec + mrec->rec_size); 313*243ca327SMatthew Dillon } 314*243ca327SMatthew Dillon } 315*243ca327SMatthew Dillon 316*243ca327SMatthew Dillon /* 317*243ca327SMatthew Dillon * Read and process the termination sync record. 318*243ca327SMatthew Dillon */ 319*243ca327SMatthew Dillon mrec = read_mrecord(0, &error, &pickup); 320*243ca327SMatthew Dillon if (mrec == NULL || mrec->type != HAMMER_MREC_TYPE_SYNC) { 321*243ca327SMatthew Dillon fprintf(stderr, "Mirror-dump: Did not get termination " 322*243ca327SMatthew Dillon "sync record\n"); 323*243ca327SMatthew Dillon } 324a7fbbf91SMatthew Dillon } 325a7fbbf91SMatthew Dillon 326a7fbbf91SMatthew Dillon void 327a7fbbf91SMatthew Dillon hammer_cmd_mirror_copy(char **av, int ac) 328a7fbbf91SMatthew Dillon { 32934ebae70SMatthew Dillon pid_t pid1; 33034ebae70SMatthew Dillon pid_t pid2; 33134ebae70SMatthew Dillon int fds[2]; 332*243ca327SMatthew Dillon const char *xav[16]; 333*243ca327SMatthew Dillon char tbuf[16]; 33434ebae70SMatthew Dillon char *ptr; 335*243ca327SMatthew Dillon int xac; 33634ebae70SMatthew Dillon 33734ebae70SMatthew Dillon if (ac != 2) 33834ebae70SMatthew Dillon mirror_usage(1); 33934ebae70SMatthew Dillon 34034ebae70SMatthew Dillon if (pipe(fds) < 0) { 34134ebae70SMatthew Dillon perror("pipe"); 34234ebae70SMatthew Dillon exit(1); 34334ebae70SMatthew Dillon } 34434ebae70SMatthew Dillon 345*243ca327SMatthew Dillon TwoWayPipeOpt = 1; 346*243ca327SMatthew Dillon 34734ebae70SMatthew Dillon /* 34834ebae70SMatthew Dillon * Source 34934ebae70SMatthew Dillon */ 35034ebae70SMatthew Dillon if ((pid1 = fork()) == 0) { 35134ebae70SMatthew Dillon dup2(fds[0], 0); 35234ebae70SMatthew Dillon dup2(fds[0], 1); 35334ebae70SMatthew Dillon close(fds[0]); 35434ebae70SMatthew Dillon close(fds[1]); 35534ebae70SMatthew Dillon if ((ptr = strchr(av[0], ':')) != NULL) { 35634ebae70SMatthew Dillon *ptr++ = 0; 357*243ca327SMatthew Dillon xac = 0; 358*243ca327SMatthew Dillon xav[xac++] = "ssh"; 359*243ca327SMatthew Dillon xav[xac++] = av[0]; 360*243ca327SMatthew Dillon xav[xac++] = "hammer"; 361*243ca327SMatthew Dillon if (VerboseOpt) 362*243ca327SMatthew Dillon xav[xac++] = "-v"; 363*243ca327SMatthew Dillon xav[xac++] = "-2"; 364*243ca327SMatthew Dillon if (TimeoutOpt) { 365*243ca327SMatthew Dillon snprintf(tbuf, sizeof(tbuf), "%d", TimeoutOpt); 366*243ca327SMatthew Dillon xav[xac++] = "-t"; 367*243ca327SMatthew Dillon xav[xac++] = tbuf; 368*243ca327SMatthew Dillon } 369*243ca327SMatthew Dillon xav[xac++] = "mirror-read"; 370*243ca327SMatthew Dillon xav[xac++] = ptr; 371*243ca327SMatthew Dillon xav[xac++] = NULL; 372*243ca327SMatthew Dillon execv("/usr/bin/ssh", (void *)xav); 37334ebae70SMatthew Dillon } else { 37434ebae70SMatthew Dillon hammer_cmd_mirror_read(av, 1); 375*243ca327SMatthew Dillon fflush(stdout); 376*243ca327SMatthew Dillon fflush(stderr); 37734ebae70SMatthew Dillon } 37853d93cc7SMatthew Dillon _exit(1); 37934ebae70SMatthew Dillon } 38034ebae70SMatthew Dillon 38134ebae70SMatthew Dillon /* 38234ebae70SMatthew Dillon * Target 38334ebae70SMatthew Dillon */ 38434ebae70SMatthew Dillon if ((pid2 = fork()) == 0) { 38534ebae70SMatthew Dillon dup2(fds[1], 0); 38634ebae70SMatthew Dillon dup2(fds[1], 1); 38734ebae70SMatthew Dillon close(fds[0]); 38834ebae70SMatthew Dillon close(fds[1]); 38934ebae70SMatthew Dillon if ((ptr = strchr(av[1], ':')) != NULL) { 39034ebae70SMatthew Dillon *ptr++ = 0; 391*243ca327SMatthew Dillon xac = 0; 392*243ca327SMatthew Dillon xav[xac++] = "ssh"; 393*243ca327SMatthew Dillon xav[xac++] = av[1]; 394*243ca327SMatthew Dillon xav[xac++] = "hammer"; 395*243ca327SMatthew Dillon if (VerboseOpt) 396*243ca327SMatthew Dillon xav[xac++] = "-v"; 397*243ca327SMatthew Dillon xav[xac++] = "-2"; 398*243ca327SMatthew Dillon xav[xac++] = "mirror-write"; 399*243ca327SMatthew Dillon xav[xac++] = ptr; 400*243ca327SMatthew Dillon xav[xac++] = NULL; 401*243ca327SMatthew Dillon execv("/usr/bin/ssh", (void *)xav); 40234ebae70SMatthew Dillon } else { 40334ebae70SMatthew Dillon hammer_cmd_mirror_write(av + 1, 1); 404*243ca327SMatthew Dillon fflush(stdout); 405*243ca327SMatthew Dillon fflush(stderr); 40634ebae70SMatthew Dillon } 40753d93cc7SMatthew Dillon _exit(1); 40834ebae70SMatthew Dillon } 40934ebae70SMatthew Dillon close(fds[0]); 41034ebae70SMatthew Dillon close(fds[1]); 41134ebae70SMatthew Dillon 41234ebae70SMatthew Dillon while (waitpid(pid1, NULL, 0) <= 0) 41334ebae70SMatthew Dillon ; 41434ebae70SMatthew Dillon while (waitpid(pid2, NULL, 0) <= 0) 41534ebae70SMatthew Dillon ; 416a7fbbf91SMatthew Dillon } 417a7fbbf91SMatthew Dillon 418*243ca327SMatthew Dillon /* 419*243ca327SMatthew Dillon * Read and return multiple mrecords 420*243ca327SMatthew Dillon */ 421a7fbbf91SMatthew Dillon static int 422a7fbbf91SMatthew Dillon read_mrecords(int fd, char *buf, u_int size, hammer_ioc_mrecord_t pickup) 423a7fbbf91SMatthew Dillon { 424a7fbbf91SMatthew Dillon u_int count; 425a7fbbf91SMatthew Dillon size_t n; 426a7fbbf91SMatthew Dillon size_t i; 427a7fbbf91SMatthew Dillon 428a7fbbf91SMatthew Dillon count = 0; 429a7fbbf91SMatthew Dillon while (size - count >= HAMMER_MREC_HEADSIZE) { 430a7fbbf91SMatthew Dillon /* 431a7fbbf91SMatthew Dillon * Cached the record header in case we run out of buffer 432a7fbbf91SMatthew Dillon * space. 433a7fbbf91SMatthew Dillon */ 434a7fbbf91SMatthew Dillon if (pickup->signature == 0) { 435a7fbbf91SMatthew Dillon for (n = 0; n < HAMMER_MREC_HEADSIZE; n += i) { 436a7fbbf91SMatthew Dillon i = read(fd, (char *)pickup + n, 437a7fbbf91SMatthew Dillon HAMMER_MREC_HEADSIZE - n); 438a7fbbf91SMatthew Dillon if (i <= 0) 439a7fbbf91SMatthew Dillon break; 440a7fbbf91SMatthew Dillon } 441a7fbbf91SMatthew Dillon if (n == 0) 442a7fbbf91SMatthew Dillon break; 443a7fbbf91SMatthew Dillon if (n != HAMMER_MREC_HEADSIZE) { 444a7fbbf91SMatthew Dillon fprintf(stderr, "read_mrecords: short read on pipe\n"); 445a7fbbf91SMatthew Dillon exit(1); 446a7fbbf91SMatthew Dillon } 447a7fbbf91SMatthew Dillon 448a7fbbf91SMatthew Dillon if (pickup->signature != HAMMER_IOC_MIRROR_SIGNATURE) { 449a7fbbf91SMatthew Dillon fprintf(stderr, "read_mrecords: malformed record on pipe, bad signature\n"); 450a7fbbf91SMatthew Dillon exit(1); 451a7fbbf91SMatthew Dillon } 452a7fbbf91SMatthew Dillon if (pickup->rec_crc != crc32((char *)pickup + HAMMER_MREC_CRCOFF, HAMMER_MREC_HEADSIZE - HAMMER_MREC_CRCOFF)) { 453a7fbbf91SMatthew Dillon fprintf(stderr, "read_mrecords: malformed record on pipe, bad crc\n"); 454a7fbbf91SMatthew Dillon exit(1); 455a7fbbf91SMatthew Dillon } 456a7fbbf91SMatthew Dillon } 457a7fbbf91SMatthew Dillon if (pickup->rec_size < HAMMER_MREC_HEADSIZE || 458a7fbbf91SMatthew Dillon pickup->rec_size > HAMMER_MREC_HEADSIZE + HAMMER_XBUFSIZE) { 459a7fbbf91SMatthew Dillon fprintf(stderr, "read_mrecords: malformed record on pipe, illegal rec_size\n"); 460a7fbbf91SMatthew Dillon exit(1); 461a7fbbf91SMatthew Dillon } 462a7fbbf91SMatthew Dillon if (HAMMER_MREC_HEADSIZE + pickup->leaf.data_len > pickup->rec_size) { 463a7fbbf91SMatthew Dillon fprintf(stderr, "read_mrecords: malformed record on pipe, illegal element data_len\n"); 464a7fbbf91SMatthew Dillon exit(1); 465a7fbbf91SMatthew Dillon } 466a7fbbf91SMatthew Dillon 467a7fbbf91SMatthew Dillon /* 468a7fbbf91SMatthew Dillon * Stop if we have insufficient space for the record and data. 469a7fbbf91SMatthew Dillon */ 470a7fbbf91SMatthew Dillon if (size - count < pickup->rec_size) 471a7fbbf91SMatthew Dillon break; 472a7fbbf91SMatthew Dillon 473a7fbbf91SMatthew Dillon /* 474*243ca327SMatthew Dillon * Stop if the record type is not HAMMER_MREC_TYPE_REC 475*243ca327SMatthew Dillon */ 476*243ca327SMatthew Dillon if (pickup->type != HAMMER_MREC_TYPE_REC) 477*243ca327SMatthew Dillon break; 478*243ca327SMatthew Dillon 479*243ca327SMatthew Dillon /* 480a7fbbf91SMatthew Dillon * Read the remainder and clear the pickup signature. 481a7fbbf91SMatthew Dillon */ 482a7fbbf91SMatthew Dillon bcopy(pickup, buf + count, HAMMER_MREC_HEADSIZE); 483a7fbbf91SMatthew Dillon pickup->signature = 0; 484*243ca327SMatthew Dillon pickup->type = 0; 485a7fbbf91SMatthew Dillon for (n = HAMMER_MREC_HEADSIZE; n < pickup->rec_size; n += i) { 486a7fbbf91SMatthew Dillon i = read(fd, buf + count + n, pickup->rec_size - n); 487a7fbbf91SMatthew Dillon if (i <= 0) 488a7fbbf91SMatthew Dillon break; 489a7fbbf91SMatthew Dillon } 490a7fbbf91SMatthew Dillon if (n != pickup->rec_size) { 491a7fbbf91SMatthew Dillon fprintf(stderr, "read_mrecords: short read on pipe\n"); 492a7fbbf91SMatthew Dillon exit(1); 493a7fbbf91SMatthew Dillon } 494a7fbbf91SMatthew Dillon if (pickup->leaf.data_len && pickup->leaf.data_offset) { 495a7fbbf91SMatthew Dillon if (hammer_crc_test_leaf(buf + count + HAMMER_MREC_HEADSIZE, &pickup->leaf) == 0) { 496a7fbbf91SMatthew 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); 497a7fbbf91SMatthew Dillon fprintf(stderr, "continuing, but there are problems\n"); 498a7fbbf91SMatthew Dillon } 499a7fbbf91SMatthew Dillon } 500a7fbbf91SMatthew Dillon 501a7fbbf91SMatthew Dillon count += pickup->rec_size; 502a7fbbf91SMatthew Dillon } 503a7fbbf91SMatthew Dillon return(count); 504a7fbbf91SMatthew Dillon } 505a7fbbf91SMatthew Dillon 50634ebae70SMatthew Dillon /* 507*243ca327SMatthew Dillon * Read and return a single mrecord. The returned mrec->rec_size will be 508*243ca327SMatthew Dillon * adjusted to be the size of the payload. 509*243ca327SMatthew Dillon */ 510*243ca327SMatthew Dillon static 511*243ca327SMatthew Dillon struct hammer_ioc_mrecord * 512*243ca327SMatthew Dillon read_mrecord(int fdin, int *errorp, hammer_ioc_mrecord_t pickup) 513*243ca327SMatthew Dillon { 514*243ca327SMatthew Dillon hammer_ioc_mrecord_t mrec; 515*243ca327SMatthew Dillon struct hammer_ioc_mrecord mrechd; 516*243ca327SMatthew Dillon size_t bytes; 517*243ca327SMatthew Dillon size_t n; 518*243ca327SMatthew Dillon size_t i; 519*243ca327SMatthew Dillon 520*243ca327SMatthew Dillon if (pickup && pickup->type != 0) { 521*243ca327SMatthew Dillon mrechd = *pickup; 522*243ca327SMatthew Dillon pickup->signature = 0; 523*243ca327SMatthew Dillon pickup->type = 0; 524*243ca327SMatthew Dillon n = HAMMER_MREC_HEADSIZE; 525*243ca327SMatthew Dillon } else { 526*243ca327SMatthew Dillon /* 527*243ca327SMatthew Dillon * Read in the PFSD header from the sender. 528*243ca327SMatthew Dillon */ 529*243ca327SMatthew Dillon for (n = 0; n < HAMMER_MREC_HEADSIZE; n += i) { 530*243ca327SMatthew Dillon i = read(fdin, (char *)&mrechd + n, HAMMER_MREC_HEADSIZE - n); 531*243ca327SMatthew Dillon if (i <= 0) 532*243ca327SMatthew Dillon break; 533*243ca327SMatthew Dillon } 534*243ca327SMatthew Dillon if (n == 0) { 535*243ca327SMatthew Dillon *errorp = 0; /* EOF */ 536*243ca327SMatthew Dillon return(NULL); 537*243ca327SMatthew Dillon } 538*243ca327SMatthew Dillon if (n != HAMMER_MREC_HEADSIZE) { 539*243ca327SMatthew Dillon fprintf(stderr, "short read of mrecord header\n"); 540*243ca327SMatthew Dillon *errorp = EPIPE; 541*243ca327SMatthew Dillon return(NULL); 542*243ca327SMatthew Dillon } 543*243ca327SMatthew Dillon } 544*243ca327SMatthew Dillon if (mrechd.signature != HAMMER_IOC_MIRROR_SIGNATURE) { 545*243ca327SMatthew Dillon fprintf(stderr, "read_mrecord: bad signature\n"); 546*243ca327SMatthew Dillon *errorp = EINVAL; 547*243ca327SMatthew Dillon return(NULL); 548*243ca327SMatthew Dillon } 549*243ca327SMatthew Dillon bytes = mrechd.rec_size; 550*243ca327SMatthew Dillon if (bytes < HAMMER_MREC_HEADSIZE) 551*243ca327SMatthew Dillon bytes = (int)HAMMER_MREC_HEADSIZE; 552*243ca327SMatthew Dillon mrec = malloc(bytes); 553*243ca327SMatthew Dillon *mrec = mrechd; 554*243ca327SMatthew Dillon while (n < bytes) { 555*243ca327SMatthew Dillon i = read(fdin, (char *)mrec + n, bytes - n); 556*243ca327SMatthew Dillon if (i <= 0) 557*243ca327SMatthew Dillon break; 558*243ca327SMatthew Dillon n += i; 559*243ca327SMatthew Dillon } 560*243ca327SMatthew Dillon if (n != bytes) { 561*243ca327SMatthew Dillon fprintf(stderr, "read_mrecord: short read on payload\n"); 562*243ca327SMatthew Dillon *errorp = EPIPE; 563*243ca327SMatthew Dillon return(NULL); 564*243ca327SMatthew Dillon } 565*243ca327SMatthew Dillon if (mrec->rec_crc != crc32((char *)mrec + HAMMER_MREC_CRCOFF, 566*243ca327SMatthew Dillon bytes - HAMMER_MREC_CRCOFF)) { 567*243ca327SMatthew Dillon fprintf(stderr, "read_mrecord: bad CRC\n"); 568*243ca327SMatthew Dillon *errorp = EINVAL; 569*243ca327SMatthew Dillon return(NULL); 570*243ca327SMatthew Dillon } 571*243ca327SMatthew Dillon mrec->rec_size -= HAMMER_MREC_HEADSIZE; 572*243ca327SMatthew Dillon *errorp = 0; 573*243ca327SMatthew Dillon return(mrec); 574*243ca327SMatthew Dillon } 575*243ca327SMatthew Dillon 576*243ca327SMatthew Dillon static 577*243ca327SMatthew Dillon void 578*243ca327SMatthew Dillon write_mrecord(int fdout, u_int32_t type, void *payload, int bytes) 579*243ca327SMatthew Dillon { 580*243ca327SMatthew Dillon hammer_ioc_mrecord_t mrec; 581*243ca327SMatthew Dillon 582*243ca327SMatthew Dillon mrec = malloc(HAMMER_MREC_HEADSIZE + bytes); 583*243ca327SMatthew Dillon bzero(mrec, sizeof(*mrec)); 584*243ca327SMatthew Dillon mrec->signature = HAMMER_IOC_MIRROR_SIGNATURE; 585*243ca327SMatthew Dillon mrec->type = type; 586*243ca327SMatthew Dillon mrec->rec_size = HAMMER_MREC_HEADSIZE + bytes; 587*243ca327SMatthew Dillon bcopy(payload, mrec + 1, bytes); 588*243ca327SMatthew Dillon mrec->rec_crc = crc32((char *)mrec + HAMMER_MREC_CRCOFF, 589*243ca327SMatthew Dillon mrec->rec_size - HAMMER_MREC_CRCOFF); 590*243ca327SMatthew Dillon if (write(fdout, mrec, mrec->rec_size) != (int)mrec->rec_size) { 591*243ca327SMatthew Dillon fprintf(stderr, "write_mrecord: error %d (%s)\n", 592*243ca327SMatthew Dillon errno, strerror(errno)); 593*243ca327SMatthew Dillon exit(1); 594*243ca327SMatthew Dillon } 595*243ca327SMatthew Dillon free(mrec); 596*243ca327SMatthew Dillon } 597*243ca327SMatthew Dillon 598*243ca327SMatthew Dillon /* 59934ebae70SMatthew Dillon * Generate a mirroring header with the pfs information of the 60034ebae70SMatthew Dillon * originating filesytem. 60134ebae70SMatthew Dillon */ 60234ebae70SMatthew Dillon static void 60334ebae70SMatthew Dillon generate_mrec_header(int fd, int fdout, 60434ebae70SMatthew Dillon hammer_tid_t *tid_begp, hammer_tid_t *tid_endp) 60534ebae70SMatthew Dillon { 60634ebae70SMatthew Dillon struct hammer_ioc_pseudofs_rw pfs; 60734ebae70SMatthew Dillon struct hammer_pfs_head pfs_head; 60834ebae70SMatthew Dillon 60934ebae70SMatthew Dillon bzero(&pfs, sizeof(pfs)); 61034ebae70SMatthew Dillon bzero(&pfs_head, sizeof(pfs_head)); 61134ebae70SMatthew Dillon pfs.ondisk = &pfs_head.pfsd; 61234ebae70SMatthew Dillon pfs.bytes = sizeof(pfs_head.pfsd); 61334ebae70SMatthew Dillon if (ioctl(fd, HAMMERIOC_GET_PSEUDOFS, &pfs) != 0) { 61434ebae70SMatthew Dillon fprintf(stderr, "mirror-read: not a HAMMER fs/pseudofs!\n"); 61534ebae70SMatthew Dillon exit(1); 61634ebae70SMatthew Dillon } 61734ebae70SMatthew Dillon if (pfs.version != HAMMER_IOC_PSEUDOFS_VERSION) { 61834ebae70SMatthew Dillon fprintf(stderr, "mirror-read: HAMMER pfs version mismatch!\n"); 61934ebae70SMatthew Dillon exit(1); 62034ebae70SMatthew Dillon } 62134ebae70SMatthew Dillon 62234ebae70SMatthew Dillon /* 62334ebae70SMatthew Dillon * sync_beg_tid - lowest TID on source after which a full history 62434ebae70SMatthew Dillon * is available. 62534ebae70SMatthew Dillon * 62634ebae70SMatthew Dillon * sync_end_tid - highest fully synchronized TID from source. 62734ebae70SMatthew Dillon */ 62834ebae70SMatthew Dillon *tid_begp = pfs_head.pfsd.sync_beg_tid; 62934ebae70SMatthew Dillon *tid_endp = pfs_head.pfsd.sync_end_tid; 63034ebae70SMatthew Dillon 63134ebae70SMatthew Dillon pfs_head.version = pfs.version; 632*243ca327SMatthew Dillon write_mrecord(fdout, HAMMER_MREC_TYPE_PFSD, 633*243ca327SMatthew Dillon &pfs_head, sizeof(pfs_head)); 63434ebae70SMatthew Dillon } 63534ebae70SMatthew Dillon 63634ebae70SMatthew Dillon /* 63734ebae70SMatthew Dillon * Validate the pfs information from the originating filesystem 63834ebae70SMatthew Dillon * against the target filesystem. shared_uuid must match. 63934ebae70SMatthew Dillon */ 64034ebae70SMatthew Dillon static void 64134ebae70SMatthew Dillon validate_mrec_header(int fd, int fdin, 64234ebae70SMatthew Dillon hammer_tid_t *tid_begp, hammer_tid_t *tid_endp) 64334ebae70SMatthew Dillon { 64434ebae70SMatthew Dillon struct hammer_ioc_pseudofs_rw pfs; 645*243ca327SMatthew Dillon struct hammer_pfs_head *pfs_head; 64634ebae70SMatthew Dillon struct hammer_pseudofs_data pfsd; 647*243ca327SMatthew Dillon hammer_ioc_mrecord_t mrec; 64834ebae70SMatthew Dillon size_t bytes; 649*243ca327SMatthew Dillon int error; 65034ebae70SMatthew Dillon 65134ebae70SMatthew Dillon /* 65234ebae70SMatthew Dillon * Get the PFSD info from the target filesystem. 65334ebae70SMatthew Dillon */ 65434ebae70SMatthew Dillon bzero(&pfs, sizeof(pfs)); 65534ebae70SMatthew Dillon bzero(&pfsd, sizeof(pfsd)); 65634ebae70SMatthew Dillon pfs.ondisk = &pfsd; 65734ebae70SMatthew Dillon pfs.bytes = sizeof(pfsd); 65834ebae70SMatthew Dillon if (ioctl(fd, HAMMERIOC_GET_PSEUDOFS, &pfs) != 0) { 65934ebae70SMatthew Dillon fprintf(stderr, "mirror-write: not a HAMMER fs/pseudofs!\n"); 66034ebae70SMatthew Dillon exit(1); 66134ebae70SMatthew Dillon } 66234ebae70SMatthew Dillon if (pfs.version != HAMMER_IOC_PSEUDOFS_VERSION) { 66334ebae70SMatthew Dillon fprintf(stderr, "mirror-write: HAMMER pfs version mismatch!\n"); 66434ebae70SMatthew Dillon exit(1); 66534ebae70SMatthew Dillon } 66634ebae70SMatthew Dillon 667*243ca327SMatthew Dillon mrec = read_mrecord(fdin, &error, NULL); 668*243ca327SMatthew Dillon if (mrec == NULL) { 669*243ca327SMatthew Dillon if (error == 0) 670*243ca327SMatthew Dillon fprintf(stderr, "validate_mrec_header: short read\n"); 67134ebae70SMatthew Dillon exit(1); 67234ebae70SMatthew Dillon } 673*243ca327SMatthew Dillon if (mrec->type != HAMMER_MREC_TYPE_PFSD) { 674*243ca327SMatthew Dillon fprintf(stderr, "validate_mrec_header: did not get expected " 675*243ca327SMatthew Dillon "PFSD record type\n"); 67634ebae70SMatthew Dillon exit(1); 67734ebae70SMatthew Dillon } 678*243ca327SMatthew Dillon pfs_head = (void *)(mrec + 1); 679*243ca327SMatthew Dillon bytes = mrec->rec_size; /* post-adjusted for payload */ 680*243ca327SMatthew Dillon if (bytes != sizeof(*pfs_head)) { 681*243ca327SMatthew Dillon fprintf(stderr, "validate_mrec_header: unexpected payload " 682*243ca327SMatthew Dillon "size\n"); 68334ebae70SMatthew Dillon exit(1); 68434ebae70SMatthew Dillon } 685*243ca327SMatthew Dillon if (pfs_head->version != pfs.version) { 686*243ca327SMatthew Dillon fprintf(stderr, "validate_mrec_header: Version mismatch\n"); 68734ebae70SMatthew Dillon exit(1); 68834ebae70SMatthew Dillon } 68934ebae70SMatthew Dillon 69034ebae70SMatthew Dillon /* 69134ebae70SMatthew Dillon * Whew. Ok, is the read PFS info compatible with the target? 69234ebae70SMatthew Dillon */ 693*243ca327SMatthew Dillon if (bcmp(&pfs_head->pfsd.shared_uuid, &pfsd.shared_uuid, sizeof(pfsd.shared_uuid)) != 0) { 69434ebae70SMatthew Dillon fprintf(stderr, "mirror-write: source and target have different shared_uuid's!\n"); 69534ebae70SMatthew Dillon exit(1); 69634ebae70SMatthew Dillon } 69734ebae70SMatthew Dillon if ((pfsd.mirror_flags & HAMMER_PFSD_SLAVE) == 0) { 69834ebae70SMatthew Dillon fprintf(stderr, "mirror-write: target must be in slave mode\n"); 69934ebae70SMatthew Dillon exit(1); 70034ebae70SMatthew Dillon } 701*243ca327SMatthew Dillon *tid_begp = pfs_head->pfsd.sync_beg_tid; 702*243ca327SMatthew Dillon *tid_endp = pfs_head->pfsd.sync_end_tid; 703*243ca327SMatthew Dillon free(mrec); 70434ebae70SMatthew Dillon } 70534ebae70SMatthew Dillon 70634ebae70SMatthew Dillon static void 707*243ca327SMatthew Dillon update_pfs_snapshot(int fd, hammer_tid_t snapshot_tid) 70834ebae70SMatthew Dillon { 709*243ca327SMatthew Dillon struct hammer_ioc_pseudofs_rw pfs; 710*243ca327SMatthew Dillon struct hammer_pseudofs_data pfsd; 71134ebae70SMatthew Dillon 712*243ca327SMatthew Dillon bzero(&pfs, sizeof(pfs)); 713*243ca327SMatthew Dillon bzero(&pfsd, sizeof(pfsd)); 714*243ca327SMatthew Dillon pfs.ondisk = &pfsd; 715*243ca327SMatthew Dillon pfs.bytes = sizeof(pfsd); 716*243ca327SMatthew Dillon if (ioctl(fd, HAMMERIOC_GET_PSEUDOFS, &pfs) != 0) { 717*243ca327SMatthew Dillon perror("update_pfs_snapshot (read)"); 718*243ca327SMatthew Dillon exit(1); 71934ebae70SMatthew Dillon } 720*243ca327SMatthew Dillon pfsd.sync_beg_tid = snapshot_tid; 721*243ca327SMatthew Dillon if (ioctl(fd, HAMMERIOC_SET_PSEUDOFS, &pfs) != 0) { 722*243ca327SMatthew Dillon perror("update_pfs_snapshot (rewrite)"); 723*243ca327SMatthew Dillon exit(1); 72434ebae70SMatthew Dillon } 725*243ca327SMatthew Dillon } 726*243ca327SMatthew Dillon 72734ebae70SMatthew Dillon 728a7fbbf91SMatthew Dillon static void 729a7fbbf91SMatthew Dillon mirror_usage(int code) 730a7fbbf91SMatthew Dillon { 731a7fbbf91SMatthew Dillon fprintf(stderr, 732a7fbbf91SMatthew Dillon "hammer mirror-read <filesystem>\n" 733a7fbbf91SMatthew Dillon "hammer mirror-write <filesystem>\n" 734*243ca327SMatthew Dillon "hammer mirror-dump\n" 735a7fbbf91SMatthew Dillon "hammer mirror-copy [[user@]host:]fs [[user@]host:]fs\n" 736a7fbbf91SMatthew Dillon ); 737a7fbbf91SMatthew Dillon exit(code); 738a7fbbf91SMatthew Dillon } 739