From 243ca327ba96f43f565bb5b25d5a8ab95fcce49e Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Mon, 7 Jul 2008 00:27:22 +0000 Subject: [PATCH] HAMMER Utilities: Sync with 60E * Change the cycle file to hold an entire B-Tree base key, plus an optional TID (used by the mirroring code). * Flesh out the mirroring code. Add timeout (-t) support. Add cycle file support. * When mirror-copy is used have the target sync the filesystem and acknowledge completion and store the completed TID in the cycle file. * Incremental mirroring now works when using mirror-copy with a cycle file. * Add mirror-dump, aka hammer mirror-read ... | hammer mirror-dump, for debugging. --- sbin/hammer/cmd_mirror.c | 446 +++++++++++++++++++++++++++++------- sbin/hammer/cmd_pseudofs.c | 8 +- sbin/hammer/cmd_reblock.c | 9 +- sbin/hammer/cmd_show.c | 7 +- sbin/hammer/cmd_softprune.c | 8 +- sbin/hammer/cycle.c | 47 +++- sbin/hammer/hammer.8 | 5 +- sbin/hammer/hammer.c | 24 +- sbin/hammer/hammer.h | 11 +- 9 files changed, 445 insertions(+), 120 deletions(-) diff --git a/sbin/hammer/cmd_mirror.c b/sbin/hammer/cmd_mirror.c index 99c945525ddd..39dbb96b5506 100644 --- a/sbin/hammer/cmd_mirror.c +++ b/sbin/hammer/cmd_mirror.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sbin/hammer/cmd_mirror.c,v 1.3 2008/07/04 07:20:43 dillon Exp $ + * $DragonFly: src/sbin/hammer/cmd_mirror.c,v 1.4 2008/07/07 00:27:22 dillon Exp $ */ #include "hammer.h" @@ -39,27 +39,35 @@ #define SERIALBUF_SIZE (512 * 1024) struct hammer_pfs_head { - struct hammer_ioc_mrecord mrec; u_int32_t version; struct hammer_pseudofs_data pfsd; }; static int read_mrecords(int fd, char *buf, u_int size, hammer_ioc_mrecord_t pickup); +static struct hammer_ioc_mrecord *read_mrecord(int fdin, int *errorp, + hammer_ioc_mrecord_t pickup); +static void write_mrecord(int fdout, u_int32_t type, void *payload, int bytes); static void generate_mrec_header(int fd, int fdout, hammer_tid_t *tid_begp, hammer_tid_t *tid_endp); static void validate_mrec_header(int fd, int fdin, hammer_tid_t *tid_begp, hammer_tid_t *tid_endp); -static void run_cmd(const char *path, ...); +static void update_pfs_snapshot(int fd, hammer_tid_t snapshot_tid); static void mirror_usage(int code); void hammer_cmd_mirror_read(char **av, int ac) { struct hammer_ioc_mirror_rw mirror; + hammer_ioc_mrecord_t mrec; + hammer_tid_t sync_tid; const char *filesystem; char *buf = malloc(SERIALBUF_SIZE); + int interrupted = 0; + int error; int fd; + int n; + time_t base_t = time(NULL); if (ac > 2) mirror_usage(1); @@ -73,10 +81,22 @@ hammer_cmd_mirror_read(char **av, int ac) if (fd < 0) err(1, "Unable to open %s", filesystem); - hammer_get_cycle(&mirror.key_beg); - + /* + * Write out the PFS header + */ generate_mrec_header(fd, 1, &mirror.tid_beg, &mirror.tid_end); + hammer_get_cycle(&mirror.key_beg, &mirror.tid_beg); + fprintf(stderr, "mirror-read: Mirror from %016llx to %016llx\n", + mirror.tid_beg, mirror.tid_end); + if (mirror.key_beg.obj_id != (int64_t)HAMMER_MIN_OBJID) { + fprintf(stderr, "mirror-read: Resuming at object %016llx\n", + mirror.key_beg.obj_id); + } + + /* + * Write out bulk records + */ mirror.ubuf = buf; mirror.size = SERIALBUF_SIZE; if (ac == 2) @@ -89,26 +109,69 @@ hammer_cmd_mirror_read(char **av, int ac) filesystem, strerror(errno)); exit(1); } - if (mirror.head.flags & HAMMER_IOC_HEAD_INTR) { + if (mirror.count) { + n = write(1, mirror.ubuf, mirror.count); + if (n != mirror.count) { + fprintf(stderr, "Mirror-read %s failed: " + "short write\n", + filesystem); + exit(1); + } + } + mirror.key_beg = mirror.key_cur; + if (TimeoutOpt && + (unsigned)(time(NULL) - base_t) > (unsigned)TimeoutOpt) { fprintf(stderr, "Mirror-read %s interrupted by timer at" - " %016llx %08x\n", + " %016llx\n", filesystem, - mirror.key_cur.obj_id, - mirror.key_cur.localization); - if (CyclePath) - hammer_set_cycle(&mirror.key_cur); - exit(0); + mirror.key_cur.obj_id); + interrupted = 1; + break; } - mirror.key_beg = mirror.key_cur; - if (mirror.count) - write(1, mirror.ubuf, mirror.count); } while (mirror.count != 0); - /* generate_mrec_update(fd, 1); */ + /* + * Write out the termination sync record + */ + write_mrecord(1, HAMMER_MREC_TYPE_SYNC, NULL, 0); - if (CyclePath) - hammer_reset_cycle(); + /* + * If the -2 option was given (automatic when doing mirror-copy), + * a two-way pipe is assumed and we expect a response mrec from + * the target. + */ + if (TwoWayPipeOpt) { + mrec = read_mrecord(0, &error, NULL); + if (mrec == NULL || mrec->type != HAMMER_MREC_TYPE_UPDATE) { + fprintf(stderr, "mirror_read: Did not get final " + "acknowledgement packet from target\n"); + exit(1); + } + if (interrupted) { + if (CyclePath) { + hammer_set_cycle(&mirror.key_cur, mirror.tid_beg); + fprintf(stderr, "Cyclefile %s updated for continuation\n", CyclePath); + } + } else { + sync_tid = *(hammer_tid_t *)(mrec + 1); + if (CyclePath) { + hammer_key_beg_init(&mirror.key_beg); + hammer_set_cycle(&mirror.key_beg, sync_tid); + fprintf(stderr, "Cyclefile %s updated to 0x%016llx\n", + CyclePath, sync_tid); + } else { + fprintf(stderr, "Source can update synctid " + "to 0x%016llx\n", + sync_tid); + } + } + } else if (CyclePath) { + /* NOTE! mirror.tid_beg cannot be updated */ + fprintf(stderr, "Warning: cycle file (-c option) cannot be " + "fully updated unless you use mirror-copy\n"); + hammer_set_cycle(&mirror.key_beg, mirror.tid_beg); + } fprintf(stderr, "Mirror-read %s succeeded\n", filesystem); } @@ -118,8 +181,11 @@ hammer_cmd_mirror_write(char **av, int ac) struct hammer_ioc_mirror_rw mirror; const char *filesystem; char *buf = malloc(SERIALBUF_SIZE); - int fd; struct hammer_ioc_mrecord pickup; + struct hammer_ioc_synctid synctid; + hammer_ioc_mrecord_t mrec; + int error; + int fd; if (ac > 2) mirror_usage(1); @@ -133,13 +199,20 @@ hammer_cmd_mirror_write(char **av, int ac) if (fd < 0) err(1, "Unable to open %s", filesystem); + /* + * Read and process the PFS header + */ validate_mrec_header(fd, 0, &mirror.tid_beg, &mirror.tid_end); mirror.ubuf = buf; mirror.size = SERIALBUF_SIZE; pickup.signature = 0; + pickup.type = 0; + /* + * Read and process bulk records + */ for (;;) { mirror.count = 0; mirror.size = read_mrecords(0, buf, SERIALBUF_SIZE, &pickup); @@ -150,18 +223,104 @@ hammer_cmd_mirror_write(char **av, int ac) filesystem, strerror(errno)); exit(1); } +#if 0 if (mirror.head.flags & HAMMER_IOC_HEAD_INTR) { fprintf(stderr, "Mirror-write %s interrupted by timer at" - " %016llx %08x\n", + " %016llx\n", filesystem, - mirror.key_cur.obj_id, - mirror.key_cur.localization); + mirror.key_cur.obj_id); exit(0); } +#endif mirror.key_beg = mirror.key_cur; } - fprintf(stderr, "Mirror-write %s succeeded\n", filesystem); + + /* + * Read and process the termination sync record. + */ + mrec = read_mrecord(0, &error, &pickup); + if (mrec == NULL || mrec->type != HAMMER_MREC_TYPE_SYNC) { + fprintf(stderr, "Mirror-write %s: Did not get termination " + "sync record\n", + filesystem); + } + + /* + * Update the PFS info on the target so the user has visibility + * into the new snapshot. + */ + update_pfs_snapshot(fd, mirror.tid_end); + + /* + * Sync the target filesystem + */ + bzero(&synctid, sizeof(synctid)); + synctid.op = HAMMER_SYNCTID_SYNC2; + ioctl(fd, HAMMERIOC_SYNCTID, &synctid); + + fprintf(stderr, "Mirror-write %s: succeeded\n", filesystem); + + /* + * Report back to the originator. + */ + if (TwoWayPipeOpt) { + write_mrecord(1, HAMMER_MREC_TYPE_UPDATE, + &mirror.tid_end, sizeof(mirror.tid_end)); + } else { + printf("Source can update synctid to 0x%016llx\n", + mirror.tid_end); + } +} + +void +hammer_cmd_mirror_dump(void) +{ + char *buf = malloc(SERIALBUF_SIZE); + struct hammer_ioc_mrecord pickup; + hammer_ioc_mrecord_t mrec; + int error; + int size; + + /* + * Read and process the PFS header + */ + pickup.signature = 0; + pickup.type = 0; + + mrec = read_mrecord(0, &error, &pickup); + + /* + * Read and process bulk records + */ + for (;;) { + size = read_mrecords(0, buf, SERIALBUF_SIZE, &pickup); + if (size <= 0) + break; + mrec = (void *)buf; + while (mrec < (hammer_ioc_mrecord_t)((char *)buf + size)) { + printf("Record obj=%016llx key=%016llx " + "rt=%02x ot=%02x\n", + mrec->leaf.base.obj_id, + mrec->leaf.base.key, + mrec->leaf.base.rec_type, + mrec->leaf.base.obj_type); + printf(" tids %016llx:%016llx data=%d\n", + mrec->leaf.base.create_tid, + mrec->leaf.base.delete_tid, + mrec->leaf.data_len); + mrec = (void *)((char *)mrec + mrec->rec_size); + } + } + + /* + * Read and process the termination sync record. + */ + mrec = read_mrecord(0, &error, &pickup); + if (mrec == NULL || mrec->type != HAMMER_MREC_TYPE_SYNC) { + fprintf(stderr, "Mirror-dump: Did not get termination " + "sync record\n"); + } } void @@ -170,7 +329,10 @@ hammer_cmd_mirror_copy(char **av, int ac) pid_t pid1; pid_t pid2; int fds[2]; + const char *xav[16]; + char tbuf[16]; char *ptr; + int xac; if (ac != 2) mirror_usage(1); @@ -180,6 +342,8 @@ hammer_cmd_mirror_copy(char **av, int ac) exit(1); } + TwoWayPipeOpt = 1; + /* * Source */ @@ -190,10 +354,26 @@ hammer_cmd_mirror_copy(char **av, int ac) close(fds[1]); if ((ptr = strchr(av[0], ':')) != NULL) { *ptr++ = 0; - run_cmd("/usr/bin/ssh", "ssh", - av[0], "hammer mirror-read", ptr, NULL); + xac = 0; + xav[xac++] = "ssh"; + xav[xac++] = av[0]; + xav[xac++] = "hammer"; + if (VerboseOpt) + xav[xac++] = "-v"; + xav[xac++] = "-2"; + if (TimeoutOpt) { + snprintf(tbuf, sizeof(tbuf), "%d", TimeoutOpt); + xav[xac++] = "-t"; + xav[xac++] = tbuf; + } + xav[xac++] = "mirror-read"; + xav[xac++] = ptr; + xav[xac++] = NULL; + execv("/usr/bin/ssh", (void *)xav); } else { hammer_cmd_mirror_read(av, 1); + fflush(stdout); + fflush(stderr); } _exit(1); } @@ -208,10 +388,21 @@ hammer_cmd_mirror_copy(char **av, int ac) close(fds[1]); if ((ptr = strchr(av[1], ':')) != NULL) { *ptr++ = 0; - run_cmd("/usr/bin/ssh", "ssh", - av[1], "hammer mirror-write", ptr, NULL); + xac = 0; + xav[xac++] = "ssh"; + xav[xac++] = av[1]; + xav[xac++] = "hammer"; + if (VerboseOpt) + xav[xac++] = "-v"; + xav[xac++] = "-2"; + xav[xac++] = "mirror-write"; + xav[xac++] = ptr; + xav[xac++] = NULL; + execv("/usr/bin/ssh", (void *)xav); } else { hammer_cmd_mirror_write(av + 1, 1); + fflush(stdout); + fflush(stderr); } _exit(1); } @@ -224,6 +415,9 @@ hammer_cmd_mirror_copy(char **av, int ac) ; } +/* + * Read and return multiple mrecords + */ static int read_mrecords(int fd, char *buf, u_int size, hammer_ioc_mrecord_t pickup) { @@ -276,11 +470,18 @@ read_mrecords(int fd, char *buf, u_int size, hammer_ioc_mrecord_t pickup) if (size - count < pickup->rec_size) break; + /* + * Stop if the record type is not HAMMER_MREC_TYPE_REC + */ + if (pickup->type != HAMMER_MREC_TYPE_REC) + break; + /* * Read the remainder and clear the pickup signature. */ bcopy(pickup, buf + count, HAMMER_MREC_HEADSIZE); pickup->signature = 0; + pickup->type = 0; for (n = HAMMER_MREC_HEADSIZE; n < pickup->rec_size; n += i) { i = read(fd, buf + count + n, pickup->rec_size - n); if (i <= 0) @@ -302,6 +503,98 @@ read_mrecords(int fd, char *buf, u_int size, hammer_ioc_mrecord_t pickup) return(count); } +/* + * Read and return a single mrecord. The returned mrec->rec_size will be + * adjusted to be the size of the payload. + */ +static +struct hammer_ioc_mrecord * +read_mrecord(int fdin, int *errorp, hammer_ioc_mrecord_t pickup) +{ + hammer_ioc_mrecord_t mrec; + struct hammer_ioc_mrecord mrechd; + size_t bytes; + size_t n; + size_t i; + + if (pickup && pickup->type != 0) { + mrechd = *pickup; + pickup->signature = 0; + pickup->type = 0; + n = HAMMER_MREC_HEADSIZE; + } else { + /* + * Read in the PFSD header from the sender. + */ + for (n = 0; n < HAMMER_MREC_HEADSIZE; n += i) { + i = read(fdin, (char *)&mrechd + n, HAMMER_MREC_HEADSIZE - n); + if (i <= 0) + break; + } + if (n == 0) { + *errorp = 0; /* EOF */ + return(NULL); + } + if (n != HAMMER_MREC_HEADSIZE) { + fprintf(stderr, "short read of mrecord header\n"); + *errorp = EPIPE; + return(NULL); + } + } + if (mrechd.signature != HAMMER_IOC_MIRROR_SIGNATURE) { + fprintf(stderr, "read_mrecord: bad signature\n"); + *errorp = EINVAL; + return(NULL); + } + bytes = mrechd.rec_size; + if (bytes < HAMMER_MREC_HEADSIZE) + bytes = (int)HAMMER_MREC_HEADSIZE; + mrec = malloc(bytes); + *mrec = mrechd; + while (n < bytes) { + i = read(fdin, (char *)mrec + n, bytes - n); + if (i <= 0) + break; + n += i; + } + if (n != bytes) { + fprintf(stderr, "read_mrecord: short read on payload\n"); + *errorp = EPIPE; + return(NULL); + } + if (mrec->rec_crc != crc32((char *)mrec + HAMMER_MREC_CRCOFF, + bytes - HAMMER_MREC_CRCOFF)) { + fprintf(stderr, "read_mrecord: bad CRC\n"); + *errorp = EINVAL; + return(NULL); + } + mrec->rec_size -= HAMMER_MREC_HEADSIZE; + *errorp = 0; + return(mrec); +} + +static +void +write_mrecord(int fdout, u_int32_t type, void *payload, int bytes) +{ + hammer_ioc_mrecord_t mrec; + + mrec = malloc(HAMMER_MREC_HEADSIZE + bytes); + bzero(mrec, sizeof(*mrec)); + mrec->signature = HAMMER_IOC_MIRROR_SIGNATURE; + mrec->type = type; + mrec->rec_size = HAMMER_MREC_HEADSIZE + bytes; + bcopy(payload, mrec + 1, bytes); + mrec->rec_crc = crc32((char *)mrec + HAMMER_MREC_CRCOFF, + mrec->rec_size - HAMMER_MREC_CRCOFF); + if (write(fdout, mrec, mrec->rec_size) != (int)mrec->rec_size) { + fprintf(stderr, "write_mrecord: error %d (%s)\n", + errno, strerror(errno)); + exit(1); + } + free(mrec); +} + /* * Generate a mirroring header with the pfs information of the * originating filesytem. @@ -336,12 +629,8 @@ generate_mrec_header(int fd, int fdout, *tid_endp = pfs_head.pfsd.sync_end_tid; pfs_head.version = pfs.version; - pfs_head.mrec.signature = HAMMER_IOC_MIRROR_SIGNATURE; - pfs_head.mrec.rec_size = sizeof(pfs_head); - pfs_head.mrec.type = HAMMER_MREC_TYPE_PFSD; - pfs_head.mrec.rec_crc = crc32((char *)&pfs_head + HAMMER_MREC_CRCOFF, - sizeof(pfs_head) - HAMMER_MREC_CRCOFF); - write(fdout, &pfs_head, sizeof(pfs_head)); + write_mrecord(fdout, HAMMER_MREC_TYPE_PFSD, + &pfs_head, sizeof(pfs_head)); } /* @@ -353,11 +642,11 @@ validate_mrec_header(int fd, int fdin, hammer_tid_t *tid_begp, hammer_tid_t *tid_endp) { struct hammer_ioc_pseudofs_rw pfs; - struct hammer_pfs_head pfs_head; + struct hammer_pfs_head *pfs_head; struct hammer_pseudofs_data pfsd; + hammer_ioc_mrecord_t mrec; size_t bytes; - size_t n; - size_t i; + int error; /* * Get the PFSD info from the target filesystem. @@ -375,54 +664,33 @@ validate_mrec_header(int fd, int fdin, exit(1); } - /* - * Read in the PFSD header from the sender. - */ - for (n = 0; n < HAMMER_MREC_HEADSIZE; n += i) { - i = read(fdin, (char *)&pfs_head + n, HAMMER_MREC_HEADSIZE - n); - if (i <= 0) - break; - } - if (n != HAMMER_MREC_HEADSIZE) { - fprintf(stderr, "mirror-write: short read of PFS header\n"); + mrec = read_mrecord(fdin, &error, NULL); + if (mrec == NULL) { + if (error == 0) + fprintf(stderr, "validate_mrec_header: short read\n"); exit(1); } - if (pfs_head.mrec.signature != HAMMER_IOC_MIRROR_SIGNATURE) { - fprintf(stderr, "mirror-write: PFS header has bad signature\n"); + if (mrec->type != HAMMER_MREC_TYPE_PFSD) { + fprintf(stderr, "validate_mrec_header: did not get expected " + "PFSD record type\n"); exit(1); } - if (pfs_head.mrec.type != HAMMER_MREC_TYPE_PFSD) { - fprintf(stderr, "mirror-write: Expected PFS header, got mirroring record header instead!\n"); + pfs_head = (void *)(mrec + 1); + bytes = mrec->rec_size; /* post-adjusted for payload */ + if (bytes != sizeof(*pfs_head)) { + fprintf(stderr, "validate_mrec_header: unexpected payload " + "size\n"); exit(1); } - bytes = pfs_head.mrec.rec_size; - if (bytes < HAMMER_MREC_HEADSIZE) - bytes = (int)HAMMER_MREC_HEADSIZE; - if (bytes > sizeof(pfs_head)) - bytes = sizeof(pfs_head); - while (n < bytes) { - i = read(fdin, (char *)&pfs_head + n, bytes - n); - if (i <= 0) - break; - n += i; - } - if (n != bytes) { - fprintf(stderr, "mirror-write: short read of PFS payload\n"); - exit(1); - } - if (pfs_head.version != pfs.version) { - fprintf(stderr, "mirror-write: Version mismatch in PFS header\n"); - exit(1); - } - if (pfs_head.mrec.rec_size != sizeof(pfs_head)) { - fprintf(stderr, "mirror-write: The PFS header has the wrong size!\n"); + if (pfs_head->version != pfs.version) { + fprintf(stderr, "validate_mrec_header: Version mismatch\n"); exit(1); } /* * Whew. Ok, is the read PFS info compatible with the target? */ - if (bcmp(&pfs_head.pfsd.shared_uuid, &pfsd.shared_uuid, sizeof(pfsd.shared_uuid)) != 0) { + if (bcmp(&pfs_head->pfsd.shared_uuid, &pfsd.shared_uuid, sizeof(pfsd.shared_uuid)) != 0) { fprintf(stderr, "mirror-write: source and target have different shared_uuid's!\n"); exit(1); } @@ -430,34 +698,40 @@ validate_mrec_header(int fd, int fdin, fprintf(stderr, "mirror-write: target must be in slave mode\n"); exit(1); } - *tid_begp = pfs_head.pfsd.sync_beg_tid; - *tid_endp = pfs_head.pfsd.sync_end_tid; + *tid_begp = pfs_head->pfsd.sync_beg_tid; + *tid_endp = pfs_head->pfsd.sync_end_tid; + free(mrec); } static void -run_cmd(const char *path, ...) +update_pfs_snapshot(int fd, hammer_tid_t snapshot_tid) { - va_list va; - char *av[16]; - int n; + struct hammer_ioc_pseudofs_rw pfs; + struct hammer_pseudofs_data pfsd; - va_start(va, path); - for (n = 0; n < 16; ++n) { - av[n] = va_arg(va, char *); - if (av[n] == NULL) - break; + bzero(&pfs, sizeof(pfs)); + bzero(&pfsd, sizeof(pfsd)); + pfs.ondisk = &pfsd; + pfs.bytes = sizeof(pfsd); + if (ioctl(fd, HAMMERIOC_GET_PSEUDOFS, &pfs) != 0) { + perror("update_pfs_snapshot (read)"); + exit(1); + } + pfsd.sync_beg_tid = snapshot_tid; + if (ioctl(fd, HAMMERIOC_SET_PSEUDOFS, &pfs) != 0) { + perror("update_pfs_snapshot (rewrite)"); + exit(1); } - va_end(va); - assert(n != 16); - execv(path, av); } + static void mirror_usage(int code) { fprintf(stderr, "hammer mirror-read \n" "hammer mirror-write \n" + "hammer mirror-dump\n" "hammer mirror-copy [[user@]host:]fs [[user@]host:]fs\n" ); exit(code); diff --git a/sbin/hammer/cmd_pseudofs.c b/sbin/hammer/cmd_pseudofs.c index 01b0dbec1118..3cc88a3de283 100644 --- a/sbin/hammer/cmd_pseudofs.c +++ b/sbin/hammer/cmd_pseudofs.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sbin/hammer/cmd_pseudofs.c,v 1.3 2008/07/02 22:05:59 dillon Exp $ + * $DragonFly: src/sbin/hammer/cmd_pseudofs.c,v 1.4 2008/07/07 00:27:22 dillon Exp $ */ #include "hammer.h" @@ -79,6 +79,12 @@ hammer_cmd_pseudofs_create(char **av, int ac) hammer_cmd_pseudofs_update(av, ac, 1); } +void +hammer_cmd_pseudofs_destroy(char **av, int ac) +{ + fprintf(stderr, "pfs-destroy not implemented yet\n"); +} + void hammer_cmd_pseudofs_update(char **av, int ac, int doinit) { diff --git a/sbin/hammer/cmd_reblock.c b/sbin/hammer/cmd_reblock.c index 9e1f6be765f0..8d64da84d3c3 100644 --- a/sbin/hammer/cmd_reblock.c +++ b/sbin/hammer/cmd_reblock.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sbin/hammer/cmd_reblock.c,v 1.9 2008/06/26 04:07:57 dillon Exp $ + * $DragonFly: src/sbin/hammer/cmd_reblock.c,v 1.10 2008/07/07 00:27:22 dillon Exp $ */ #include "hammer.h" @@ -49,11 +49,14 @@ hammer_cmd_reblock(char **av, int ac, int flags) int fd; int perc; + if (TimeoutOpt > 0) + alarm(TimeoutOpt); + bzero(&reblock, sizeof(reblock)); reblock.key_beg.localization = HAMMER_MIN_LOCALIZATION; reblock.key_beg.obj_id = HAMMER_MIN_OBJID; - hammer_get_cycle(&reblock.key_beg); + hammer_get_cycle(&reblock.key_beg, NULL); reblock.key_end.localization = HAMMER_MAX_LOCALIZATION; reblock.key_end.obj_id = HAMMER_MAX_OBJID; @@ -104,7 +107,7 @@ hammer_cmd_reblock(char **av, int ac, int flags) reblock.key_cur.obj_id, reblock.key_cur.localization); if (CyclePath) { - hammer_set_cycle(&reblock.key_cur); + hammer_set_cycle(&reblock.key_cur, 0); } } else { if (CyclePath) diff --git a/sbin/hammer/cmd_show.c b/sbin/hammer/cmd_show.c index 7c44e717b495..693145d97910 100644 --- a/sbin/hammer/cmd_show.c +++ b/sbin/hammer/cmd_show.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sbin/hammer/cmd_show.c,v 1.14 2008/07/02 22:05:59 dillon Exp $ + * $DragonFly: src/sbin/hammer/cmd_show.c,v 1.15 2008/07/07 00:27:22 dillon Exp $ */ #include "hammer.h" @@ -63,8 +63,9 @@ hammer_cmd_show(hammer_off_t node_offset, int depth, volume = get_volume(RootVolNo); node_offset = volume->ondisk->vol0_btree_root; if (VerboseOpt) { - printf("\trecords=%lld\n", - volume->ondisk->vol0_stat_records); + printf("Volume header\trecords=%lld next_tid=%016llx\n", + volume->ondisk->vol0_stat_records, + volume->ondisk->vol0_next_tid); } rel_volume(volume); } diff --git a/sbin/hammer/cmd_softprune.c b/sbin/hammer/cmd_softprune.c index 26c98ac945e3..b2aa898edbcb 100644 --- a/sbin/hammer/cmd_softprune.c +++ b/sbin/hammer/cmd_softprune.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sbin/hammer/cmd_softprune.c,v 1.5 2008/06/26 04:07:57 dillon Exp $ + * $DragonFly: src/sbin/hammer/cmd_softprune.c,v 1.6 2008/07/07 00:27:22 dillon Exp $ */ #include "hammer.h" @@ -68,6 +68,8 @@ hammer_cmd_softprune(char **av, int ac, int everything_opt) base = NULL; rcode = 0; + if (TimeoutOpt > 0) + alarm(TimeoutOpt); /* * NOTE: To restrict to a single file XXX we have to set @@ -81,7 +83,7 @@ hammer_cmd_softprune(char **av, int ac, int everything_opt) template.key_beg.obj_id = HAMMER_MIN_OBJID; template.key_end.localization = HAMMER_MAX_LOCALIZATION; template.key_end.obj_id = HAMMER_MAX_OBJID; - hammer_get_cycle(&template.key_end); + hammer_get_cycle(&template.key_end, NULL); template.stat_oldest_tid = HAMMER_MAX_TID; /* @@ -158,7 +160,7 @@ hammer_cmd_softprune(char **av, int ac, int everything_opt) scan->prune.key_cur.obj_id, scan->prune.key_cur.localization); if (CyclePath) - hammer_set_cycle(&scan->prune.key_cur); + hammer_set_cycle(&scan->prune.key_cur, 0); rcode = 0; } else { if (CyclePath) diff --git a/sbin/hammer/cycle.c b/sbin/hammer/cycle.c index 3d5f0d4d01df..6e5c2f1ac0ab 100644 --- a/sbin/hammer/cycle.c +++ b/sbin/hammer/cycle.c @@ -31,33 +31,56 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sbin/hammer/cycle.c,v 1.4 2008/06/26 04:07:57 dillon Exp $ + * $DragonFly: src/sbin/hammer/cycle.c,v 1.5 2008/07/07 00:27:22 dillon Exp $ */ #include "hammer.h" void -hammer_get_cycle(hammer_base_elm_t base) +hammer_get_cycle(hammer_base_elm_t base, hammer_tid_t *extra) { - FILE *fp; + struct stat st; + int fd; - if (CyclePath && (fp = fopen(CyclePath, "r")) != NULL) { - if (fscanf(fp, "%llx %x\n", &base->obj_id, &base->localization) != 2) { - fprintf(stderr, "Warning: malformed cycle in %s\n", + if (CyclePath && (fd = open(CyclePath, O_RDONLY)) >= 0) { + if (fstat(fd, &st) < 0) { + fprintf(stderr, "cycle-file %s: cannot stat\n", CyclePath); + close(fd); + return; } - fclose(fp); + if (st.st_size < sizeof(*base)) { + fprintf(stderr, "cycle-file %s: clearing old version\n", + CyclePath); + close(fd); + remove(CyclePath); + return; + } + if (read(fd, base, sizeof(*base)) != sizeof(*base)) { + fprintf(stderr, "cycle-file %s: read failed %s\n", + CyclePath, strerror(errno)); + return; + } + if (extra) { + if (read(fd, extra, sizeof(*extra)) != sizeof(*extra)) { + fprintf(stderr, "cycle-file %s: Warning, malformed\n", + CyclePath); + } + } + close(fd); } + /* ok if the file does not exist */ } void -hammer_set_cycle(hammer_base_elm_t base) +hammer_set_cycle(hammer_base_elm_t base, hammer_tid_t extra) { - FILE *fp; + int fd; - if ((fp = fopen(CyclePath, "w")) != NULL) { - fprintf(fp, "%016llx %08x\n", base->obj_id, base->localization); - fclose(fp); + if ((fd = open(CyclePath, O_RDWR|O_CREAT|O_TRUNC, 0666)) >= 0) { + write(fd, base, sizeof(*base)); + write(fd, &extra, sizeof(extra)); + close(fd); } else { fprintf(stderr, "Warning: Unable to write to %s: %s\n", CyclePath, strerror(errno)); diff --git a/sbin/hammer/hammer.8 b/sbin/hammer/hammer.8 index e42c44594f30..f7ea346aedf7 100644 --- a/sbin/hammer/hammer.8 +++ b/sbin/hammer/hammer.8 @@ -30,7 +30,7 @@ .\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $DragonFly: src/sbin/hammer/hammer.8,v 1.30 2008/07/02 22:05:59 dillon Exp $ +.\" $DragonFly: src/sbin/hammer/hammer.8,v 1.31 2008/07/07 00:27:22 dillon Exp $ .Dd June 26, 2008 .Dt HAMMER 8 .Os @@ -311,6 +311,9 @@ Take a mirroring stream on stdin and output it to stdout. This command will fail if the .Ar shared_uuid configuration field for the two filesystems do not match. +.It Ar mirror-dump +A mirror-read can be piped into a mirror-dump to dump an ascii +representation of the mirroring stream. .It Ar mirror-copy Ar [[user@]host:]filesystem Ar [[user@]host:]filesystem This is a shortcut which pipes a mirror-read command to a mirror-write command. If a remote host specification is made the program forks an diff --git a/sbin/hammer/hammer.c b/sbin/hammer/hammer.c index 76620103285c..8a685e1ee3d1 100644 --- a/sbin/hammer/hammer.c +++ b/sbin/hammer/hammer.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sbin/hammer/hammer.c,v 1.29 2008/07/02 22:05:59 dillon Exp $ + * $DragonFly: src/sbin/hammer/hammer.c,v 1.30 2008/07/07 00:27:22 dillon Exp $ */ #include "hammer.h" @@ -45,6 +45,8 @@ static void usage(int exit_code); int RecurseOpt; int VerboseOpt; int NoSyncOpt; +int TwoWayPipeOpt; +int TimeoutOpt; const char *CyclePath; const char *LinkPath; @@ -52,12 +54,14 @@ int main(int ac, char **av) { int ch; - int timeout = 0; u_int32_t status; char *blkdevs = NULL; - while ((ch = getopt(ac, av, "c:dhf:rs:t:v")) != -1) { + while ((ch = getopt(ac, av, "c:dhf:rs:t:v2")) != -1) { switch(ch) { + case '2': + TwoWayPipeOpt = 1; + break; case 'c': CyclePath = optarg; break; @@ -77,7 +81,7 @@ main(int ac, char **av) LinkPath = optarg; break; case 't': - timeout = strtol(optarg, NULL, 0); + TimeoutOpt = strtol(optarg, NULL, 0); break; case 'v': ++VerboseOpt; @@ -94,10 +98,7 @@ main(int ac, char **av) /* not reached */ } - if (timeout > 0) { - signal(SIGALRM, sigalrm); - alarm(timeout); - } + signal(SIGALRM, sigalrm); if (strcmp(av[0], "synctid") == 0) { hammer_cmd_synctid(av + 1, ac - 1); @@ -137,6 +138,10 @@ main(int ac, char **av) hammer_cmd_pseudofs_update(av + 1, ac - 1, 0); exit(0); } + if (strcmp(av[0], "pfs-destroy") == 0) { + hammer_cmd_pseudofs_destroy(av + 1, ac - 1); + exit(0); + } if (strcmp(av[0], "status") == 0) { hammer_cmd_status(av + 1, ac - 1); exit(0); @@ -188,6 +193,8 @@ main(int ac, char **av) hammer_cmd_mirror_write(av + 1, ac - 1); else if (strcmp(av[0], "mirror-copy") == 0) hammer_cmd_mirror_copy(av + 1, ac - 1); + else if (strcmp(av[0], "mirror-dump") == 0) + hammer_cmd_mirror_dump(); else usage(1); exit(0); @@ -259,6 +266,7 @@ usage(int exit_code) "hammer iostats \n" "hammer mirror-read \n" "hammer mirror-write \n" + "hammer mirror-dump\n" "hammer mirror-copy [[user@]host:]" " [[user@]host:]\n" "hammer reblock[-btree/inodes/dirs/data] " diff --git a/sbin/hammer/hammer.h b/sbin/hammer/hammer.h index 68e53121ea74..066224c9802f 100644 --- a/sbin/hammer/hammer.h +++ b/sbin/hammer/hammer.h @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sbin/hammer/hammer.h,v 1.20 2008/07/02 22:05:59 dillon Exp $ + * $DragonFly: src/sbin/hammer/hammer.h,v 1.21 2008/07/07 00:27:22 dillon Exp $ */ #include @@ -53,6 +53,7 @@ #include #include #include +#include #include #include @@ -61,6 +62,8 @@ extern int RecurseOpt; extern int VerboseOpt; +extern int TwoWayPipeOpt; +extern int TimeoutOpt; extern const char *LinkPath; extern const char *CyclePath; @@ -74,16 +77,18 @@ void hammer_cmd_synctid(char **av, int ac); void hammer_cmd_mirror_read(char **av, int ac); void hammer_cmd_mirror_write(char **av, int ac); void hammer_cmd_mirror_copy(char **av, int ac); +void hammer_cmd_mirror_dump(void); void hammer_cmd_history(const char *offset_str, char **av, int ac); void hammer_cmd_blockmap(void); void hammer_cmd_reblock(char **av, int ac, int flags); void hammer_cmd_pseudofs_status(char **av, int ac); void hammer_cmd_pseudofs_create(char **av, int ac); void hammer_cmd_pseudofs_update(char **av, int ac, int doinit); +void hammer_cmd_pseudofs_destroy(char **av, int ac); void hammer_cmd_status(char **av, int ac); void hammer_cmd_snapshot(char **av, int ac); -void hammer_get_cycle(hammer_base_elm_t base); -void hammer_set_cycle(hammer_base_elm_t base); +void hammer_get_cycle(hammer_base_elm_t base, hammer_tid_t *tidp); +void hammer_set_cycle(hammer_base_elm_t base, hammer_tid_t tid); void hammer_reset_cycle(void);