HAMMER Utilities: Sync with 60E
authorMatthew Dillon <dillon@dragonflybsd.org>
Mon, 7 Jul 2008 00:27:22 +0000 (00:27 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Mon, 7 Jul 2008 00:27:22 +0000 (00:27 +0000)
* 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
sbin/hammer/cmd_pseudofs.c
sbin/hammer/cmd_reblock.c
sbin/hammer/cmd_show.c
sbin/hammer/cmd_softprune.c
sbin/hammer/cycle.c
sbin/hammer/hammer.8
sbin/hammer/hammer.c
sbin/hammer/hammer.h

index 99c9455..39dbb96 100644 (file)
@@ -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"
 #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 <filesystem>\n"
                "hammer mirror-write <filesystem>\n"
+               "hammer mirror-dump\n"
                "hammer mirror-copy [[user@]host:]fs [[user@]host:]fs\n"
        );
        exit(code);
index 01b0dbe..3cc88a3 100644 (file)
@@ -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)
 {
index 9e1f6be..8d64da8 100644 (file)
@@ -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)
index 7c44e71..693145d 100644 (file)
@@ -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);
        }
index 26c98ac..b2aa898 100644 (file)
@@ -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)
index 3d5f0d4..6e5c2f1 100644 (file)
  * 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));
index e42c445..f7ea346 100644 (file)
@@ -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
index 7662010..8a685e1 100644 (file)
@@ -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 <interval>\n"
                "hammer mirror-read <filesystem>\n"
                "hammer mirror-write <filesystem>\n"
+               "hammer mirror-dump\n"
                "hammer mirror-copy [[user@]host:]<filesystem>"
                                  " [[user@]host:]<filesystem>\n"
                "hammer reblock[-btree/inodes/dirs/data] "
index 68e5312..066224c 100644 (file)
@@ -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 <sys/types.h>
@@ -53,6 +53,7 @@
 #include <assert.h>
 #include <err.h>
 #include <ctype.h>
+#include <signal.h>
 #include <dirent.h>
 #include <uuid.h>
 
@@ -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);