HAMMER Utillities: Sync with 61D
authorMatthew Dillon <dillon@dragonflybsd.org>
Sat, 12 Jul 2008 02:48:46 +0000 (02:48 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Sat, 12 Jul 2008 02:48:46 +0000 (02:48 +0000)
* Add the new pfs-upgrade, pfs-downgrade, and pfs-destroy directives.

* Add more safeties to the PFS directives.

sbin/hammer/cmd_mirror.c
sbin/hammer/cmd_pseudofs.c
sbin/hammer/hammer.8
sbin/hammer/hammer.c
sbin/hammer/hammer.h

index aca0b93..6360b8a 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.7 2008/07/10 04:44:58 dillon Exp $
+ * $DragonFly: src/sbin/hammer/cmd_mirror.c,v 1.8 2008/07/12 02:48:46 dillon Exp $
  */
 
 #include "hammer.h"
@@ -133,6 +133,12 @@ hammer_cmd_mirror_read(char **av, int ac)
                                filesystem, strerror(errno));
                        exit(1);
                }
+               if (mirror.head.flags & HAMMER_IOC_HEAD_ERROR) {
+                       fprintf(stderr,
+                               "Mirror-read %s fatal error %d\n",
+                               filesystem, mirror.head.error);
+                       exit(1);
+               }
                if (mirror.count) {
                        n = write(1, mirror.ubuf, mirror.count);
                        if (n != mirror.count) {
@@ -880,10 +886,12 @@ update_pfs_snapshot(int fd, hammer_tid_t snapshot_tid, int pfs_id)
                perror("update_pfs_snapshot (read)");
                exit(1);
        }
-       pfsd.sync_end_tid = snapshot_tid;
-       if (ioctl(fd, HAMMERIOC_SET_PSEUDOFS, &pfs) != 0) {
-               perror("update_pfs_snapshot (rewrite)");
-               exit(1);
+       if (pfsd.sync_end_tid != snapshot_tid) {
+               pfsd.sync_end_tid = snapshot_tid;
+               if (ioctl(fd, HAMMERIOC_SET_PSEUDOFS, &pfs) != 0) {
+                       perror("update_pfs_snapshot (rewrite)");
+                       exit(1);
+               }
        }
 }
 
index 87516f6..79d2be2 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.5 2008/07/09 10:32:30 dillon Exp $
+ * $DragonFly: src/sbin/hammer/cmd_pseudofs.c,v 1.6 2008/07/12 02:48:46 dillon Exp $
  */
 
 #include "hammer.h"
@@ -40,6 +40,7 @@ static void parse_pfsd_options(char **av, int ac, hammer_pseudofs_data_t pfsd);
 static void init_pfsd(hammer_pseudofs_data_t pfsd, int is_slave);
 static void dump_pfsd(hammer_pseudofs_data_t pfsd);
 static void pseudofs_usage(int code);
+static int getyn(void);
 
 /*
  * Calculate the pfs_id given a path to a directory or a @@PFS or @@%llx:%d
@@ -70,6 +71,33 @@ getpfs(struct hammer_ioc_pseudofs_rw *pfs, const char *path)
                dirpath = strdup(".");
 
        if (lstat(path, &st) == 0 && S_ISLNK(st.st_mode)) {
+               /*
+                * Avoid foot-shooting.  Don't let the user access a PFS
+                * softlink via a PFS.  PFS softlinks may only be accessed
+                * via the master filesystem.
+                */
+               fd = open(dirpath, O_RDONLY);
+               if (fd < 0)
+                       goto done;
+               pfs->pfs_id = -1;
+               ioctl(fd, HAMMERIOC_GET_PSEUDOFS, pfs);
+               if (pfs->pfs_id != 0) {
+                       fprintf(stderr,
+                               "You are attempting to access a PFS softlink "
+                               "from a PFS.  It may not represent the PFS\n"
+                               "on the main filesystem mount that you "
+                               "expect!  You may only access PFS softlinks\n"
+                               "via the main filesystem mount!\n");
+                       exit(1);
+               }
+               close(fd);
+
+               /*
+                * Extract the PFS from the link.  HAMMER will automatically
+                * convert @@PFS%05d links so if actually see one in that
+                * form the target PFS may not exist or may be corrupt.  But
+                * we can extract the PFS id anyway.
+                */
                n = readlink(path, buf, sizeof(buf) - 1);
                if (n < 0)
                        n = 0;
@@ -224,7 +252,139 @@ hammer_cmd_pseudofs_create(char **av, int ac, int is_slave)
 void
 hammer_cmd_pseudofs_destroy(char **av, int ac)
 {
-       fprintf(stderr, "pfs-destroy not implemented yet\n");
+       struct hammer_ioc_pseudofs_rw pfs;
+       struct stat st;
+       int fd;
+       int i;
+
+       if (ac == 0)
+               pseudofs_usage(1);
+       bzero(&pfs, sizeof(pfs));
+       fd = getpfs(&pfs, av[0]);
+
+       if (pfs.pfs_id == 0) {
+               fprintf(stderr, "You cannot destroy PFS#0\n");
+               exit(1);
+       }
+       printf("You have requested that PFS#%d (%s) be destroyed\n",
+               pfs.pfs_id, pfs.ondisk->label);
+       printf("This will irrevocably destroy all data on this PFS!!!!!\n");
+       printf("Do you really want to do this? ");
+       fflush(stdout);
+       if (getyn() == 0) {
+               fprintf(stderr, "No action taken on PFS#%d\n", pfs.pfs_id);
+               exit(1);
+       }
+
+       if ((pfs.ondisk->mirror_flags & HAMMER_PFSD_SLAVE) == 0) {
+               printf("This PFS is currently setup as a MASTER!\n");
+               printf("Are you absolutely sure you want to destroy it? ");
+               fflush(stdout);
+               if (getyn() == 0) {
+                       fprintf(stderr, "No action taken on PFS#%d\n",
+                               pfs.pfs_id);
+                       exit(1);
+               }
+       }
+
+       printf("Destroying PFS #%d (%s) in ", pfs.pfs_id, pfs.ondisk->label);
+       for (i = 5; i; --i) {
+               printf(" %d", i);
+               fflush(stdout);
+               sleep(1);
+       }
+       printf(".. starting destruction pass\n");
+       fflush(stdout);
+
+       /*
+        * Set the sync_beg_tid and sync_end_tid's to 1, once we start the
+        * RMR the PFS is basically destroyed even if someone ^C's it.
+        */
+       pfs.ondisk->mirror_flags |= HAMMER_PFSD_SLAVE;
+       pfs.ondisk->master_id = -1;
+       pfs.ondisk->sync_beg_tid = 1;
+       pfs.ondisk->sync_end_tid = 1;
+
+       if (ioctl(fd, HAMMERIOC_SET_PSEUDOFS, &pfs) < 0) {
+               fprintf(stderr, "Unable to update the PFS configuration: %s\n",
+                       strerror(errno));
+               exit(1);
+       }
+
+       /*
+        * Ok, do it.  Remove the softlink on success.
+        */
+       if (ioctl(fd, HAMMERIOC_RMR_PSEUDOFS, &pfs) == 0) {
+               printf("pfs-destroy of PFS#%d succeeded!\n", pfs.pfs_id);
+               if (lstat(av[0], &st) == 0 && S_ISLNK(st.st_mode)) {
+                       if (remove(av[0]) < 0) {
+                               fprintf(stderr, "Unable to remove softlink: %s "
+                                       "(but the PFS has been destroyed)\n",
+                                       av[0]);
+                               /* exit status 0 anyway */
+                       }
+               }
+       } else {
+               printf("pfs-destroy of PFS#%d failed: %s\n",
+                       pfs.pfs_id, strerror(errno));
+       }
+}
+
+void
+hammer_cmd_pseudofs_upgrade(char **av, int ac)
+{
+       struct hammer_ioc_pseudofs_rw pfs;
+       int fd;
+
+       if (ac == 0)
+               pseudofs_usage(1);
+       bzero(&pfs, sizeof(pfs));
+       fd = getpfs(&pfs, av[0]);
+
+       if (pfs.pfs_id == 0) {
+               fprintf(stderr, "You cannot upgrade PFS#0"
+                               " (It should already be a master)\n");
+               exit(1);
+       }
+       if (pfs.ondisk->master_id == -1) {
+               fprintf(stderr, "You must configure a master id before "
+                               "upgrading a slave to a master.\n"
+                               "Use pfs-update ... master=<id> first.\n");
+               exit(1);
+       }
+
+       if (ioctl(fd, HAMMERIOC_UPG_PSEUDOFS, &pfs) == 0) {
+               printf("pfs-upgrade of PFS#%d (%s) succeeded\n",
+                       pfs.pfs_id, pfs.ondisk->label);
+       } else {
+               fprintf(stderr, "pfs-upgrade of PFS#%d (%s) failed: %s\n",
+                       pfs.pfs_id, pfs.ondisk->label, strerror(errno));
+       }
+}
+
+void
+hammer_cmd_pseudofs_downgrade(char **av, int ac)
+{
+       struct hammer_ioc_pseudofs_rw pfs;
+       int fd;
+
+       if (ac == 0)
+               pseudofs_usage(1);
+       bzero(&pfs, sizeof(pfs));
+       fd = getpfs(&pfs, av[0]);
+
+       if (pfs.pfs_id == 0) {
+               fprintf(stderr, "You cannot downgrade PFS#0\n");
+               exit(1);
+       }
+
+       if (ioctl(fd, HAMMERIOC_DGD_PSEUDOFS, &pfs) == 0) {
+               printf("pfs-downgrade of PFS#%d (%s) succeeded\n",
+                       pfs.pfs_id, pfs.ondisk->label);
+       } else {
+               fprintf(stderr, "pfs-upgrade of PFS#%d (%s) failed: %s\n",
+                       pfs.pfs_id, pfs.ondisk->label, strerror(errno));
+       }
 }
 
 void
@@ -241,11 +401,13 @@ hammer_cmd_pseudofs_update(char **av, int ac)
        printf("%s\n", av[0]);
        fflush(stdout);
 
-       if (fd >= 0 && ioctl(fd, HAMMERIOC_GET_PSEUDOFS, &pfs) == 0) {
+       if (ioctl(fd, HAMMERIOC_GET_PSEUDOFS, &pfs) == 0) {
                parse_pfsd_options(av + 1, ac - 1, pfs.ondisk);
                if ((pfs.ondisk->mirror_flags & HAMMER_PFSD_SLAVE) &&
                    pfs.pfs_id == 0) {
-                       fprintf(stderr, "The real mount point cannot be made a PFS slave, only PFS sub-directories can be made slaves\n");
+                       printf("The real mount point cannot be made a PFS "
+                              "slave, only PFS sub-directories can be made "
+                              "slaves\n");
                        exit(1);
                }
                pfs.bytes = sizeof(*pfs.ondisk);
@@ -260,9 +422,6 @@ hammer_cmd_pseudofs_update(char **av, int ac)
                        printf("Unable to adjust pfs configuration: %s\n", strerror(errno));
                        exit(1);
                }
-       } else {
-               printf("PFS Creation failed: %s\n", strerror(errno));
-               exit(1);
        }
 }
 
@@ -300,10 +459,20 @@ dump_pfsd(hammer_pseudofs_data_t pfsd)
        printf("    unique-uuid=%s\n", str);
        if (pfsd->mirror_flags & HAMMER_PFSD_SLAVE) {
                printf("    slave\n");
-       } else if (pfsd->master_id < 0) {
-               printf("    no-mirror\n");
+       }
+       if (pfsd->master_id < 0) {
+               if (pfsd->mirror_flags & HAMMER_PFSD_SLAVE) {
+                       printf("    master=-1 "
+                              "(no upgrade id assigned for slave)\n");
+               } else {
+                       printf("    no-mirror "
+                              "(mirror TID propagation disabled)\n");
+               }
        } else {
-               printf("    master=%d\n", pfsd->master_id);
+               printf("    master=%d", pfsd->master_id);
+               if (pfsd->mirror_flags & HAMMER_PFSD_SLAVE)
+                       printf(" (only if upgraded, currently a slave)");
+               printf("\n");
        }
        printf("    label=\"%s\"\n", pfsd->label);
 }
@@ -353,21 +522,25 @@ parse_pfsd_options(char **av, int ac, hammer_pseudofs_data_t pfsd)
                        uuid_from_string(ptr, &pfsd->unique_uuid, &status);
                } else if (strcmp(cmd, "master") == 0) {
                        if (pfsd->mirror_flags & HAMMER_PFSD_SLAVE) {
-                               fprintf(stderr, "master mode cannot be set on a slave PFS\n");
-                               exit(1);
+                               printf("NOTE: This PFS is a slave, the master "
+                                      "id you are setting only applies\n"
+                                      "when you pfs-upgrade the PFS to "
+                                      "a master!\n");
                        }
                        pfsd->master_id = strtol(ptr, NULL, 0);
-                       pfsd->mirror_flags &= ~HAMMER_PFSD_SLAVE;
                } else if (strcmp(cmd, "slave") == 0) {
                        if ((pfsd->mirror_flags & HAMMER_PFSD_SLAVE) == 0) {
-                               fprintf(stderr, "slave mode cannot be set on a master PFS\n");
+                               fprintf(stderr,
+                                       "slave mode cannot be set on a master "
+                                       "PFS, use pfs-upgrade instead!\n");
                                exit(1);
                        }
-                       pfsd->master_id = -1;
                        pfsd->mirror_flags |= HAMMER_PFSD_SLAVE;
                } else if (strcmp(cmd, "no-mirror") == 0) {
                        if (pfsd->mirror_flags & HAMMER_PFSD_SLAVE) {
-                               fprintf(stderr, "no-mirror master mode cannot be set on a slave PFS\n");
+                               fprintf(stderr,
+                                       "no-mirror mode cannot be set on a "
+                                       "slave PFS\n");
                                exit(1);
                        }
                        pfsd->master_id = -1;
@@ -406,9 +579,12 @@ pseudofs_usage(int code)
                "hammer pfs-status <dirpath1>...<dirpathN>\n"
                "hammer pfs-master <dirpath> [options]\n"
                "hammer pfs-slave <dirpath> [options]\n"
-               "hammer pfs-destroy <dirpath>\n"
                "hammer pfs-update <dirpath> [options]\n"
+               "hammer pfs-upgrade <dirpath>\n"
+               "hammer pfs-downgrade <dirpath>\n"
+               "hammer pfs-destroy <dirpath>\n"
                "\n"
+               "options:\n"
                "    sync-beg-tid=0x16llx\n"
                "    sync-end-tid=0x16llx\n"
                "    shared-uuid=0x16llx\n"
@@ -421,3 +597,25 @@ pseudofs_usage(int code)
        exit(code);
 }
 
+static
+int
+getyn(void)
+{
+       char buf[256];
+       int len;
+
+       if (fgets(buf, sizeof(buf), stdin) == NULL)
+               return(0);
+       len = strlen(buf);
+       while (len && (buf[len-1] == '\n' || buf[len-1] == '\r'))
+               --len;
+       buf[len] = 0;
+       if (strcmp(buf, "y") == 0 ||
+           strcmp(buf, "yes") == 0 ||
+           strcmp(buf, "Y") == 0 ||
+           strcmp(buf, "YES") == 0) {
+               return(1);
+       }
+       return(0);
+}
+
index 9abbc38..53aab36 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.34 2008/07/09 18:32:19 swildner Exp $
+.\" $DragonFly: src/sbin/hammer/hammer.8,v 1.35 2008/07/12 02:48:46 dillon Exp $
 .Dd June 26, 2008
 .Dt HAMMER 8
 .Os
@@ -275,8 +275,27 @@ A PFS can only be truely destroyed with the
 .AR pfs-destroy
 directive.
 Removing the softlink will not destroy the underlying PFS.
+.It Ar pfs-upgrade Ar dirpath
+Upgrade a PFS from slave to master operation.  The PFS becomes writable.
+A master id must already be assigned to the PFS.
+.Pp
+WARNING!  HAMMER currently supports only single masters and using
+this command can easily result in filesystem corruption if you don't
+know what you are doing.
+.Pp
+This directive will refuse to run if any programs have open descriptors
+in the PFS, including programs chdir'd into the PFS.
+.It Ar pfs-downgrade Ar dirpath
+Downgrade a master PFS from master to slave operation.  The PFS becomes
+read-only and access will be locked to its sync_end_tid.
+.Pp
+This directive will refuse to run if any programs have open descriptors
+in the PFS, including programs chdir'd into the PFS.
 .It Ar pfs-destroy Ar dirpath
 This permanently destroys a PFS.
+.Pp
+This directive will refuse to run if any programs have open descriptors
+in the PFS, including programs chdir'd into the PFS.
 .It Ar pfs-update Ar dirpath Op options
 Update the configuration parameters for an existing HAMMER filesystem
 or pseudo-filesystem.  Options that may be specified:
@@ -355,11 +374,39 @@ representation of the mirroring stream.
 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 a
 ssh and execs the mirror-read and/or mirror-write on the appropriate host.
+The source may be a master or slave PFS, and the target must be a slave PFS.
 .Pp
-This command also turns on the two-way protocol feature which automatically
-negotiates TID ranges without having to use a cycle file.
+This command also established full duplex communication and turns on
+the two-way protocol feature which automatically negotiates TID ranges 
+without having to use a cycle file.
+If the operation completes successfully the target PFS's sync_end_tid will
+be updated.  Note that you must re-chdir into the target PFS to see the
+updated information.  If you do not you will still be in the previous snapshot.
 .El
 .\".Sh EXAMPLES
+.Sh PSEUDO FILESYSTEM (PFS) NOTES
+The root of a PFS is not hooked into the primary HAMMER filesystem as a
+directory.
+Instead, HAMMER creates a special softlink called "@@PFS%05d" (exactly 10
+characters long) in the primary HAMMER filesystem.
+HAMMER then modifies the contents of the softlink as read by
+.Xr readlink 2 ,
+and thus what you see with an ls command or if you were to cd into the link.
+If the PFS is a master the link reflects the current state of the PFS.
+If the PFS is a slave the link reflects the last completed snapshot, and the
+contents of the link will change when the next snapshot is completed, and
+so forth.
+.Pp
+PFS support is currently very new and experimental.  The
+.Nm
+utility
+employs numerous safeties to reduce user foot-shooting.
+The
+.Ar mirror-copy
+directive requires that the target be configured as a slave and that the
+.Ar shared-uuid
+field of the mirroring source and target match.
+.Pp
 .Sh DIAGNOSTICS
 .Ex -std
 .Sh SEE ALSO
index 04b788e..40f3b42 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.32 2008/07/09 18:32:19 swildner Exp $
+ * $DragonFly: src/sbin/hammer/hammer.c,v 1.33 2008/07/12 02:48:46 dillon Exp $
  */
 
 #include "hammer.h"
@@ -142,6 +142,14 @@ main(int ac, char **av)
                hammer_cmd_pseudofs_update(av + 1, ac - 1);
                exit(0);
        }
+       if (strcmp(av[0], "pfs-upgrade") == 0) {
+               hammer_cmd_pseudofs_upgrade(av + 1, ac - 1);
+               exit(0);
+       }
+       if (strcmp(av[0], "pfs-downgrade") == 0) {
+               hammer_cmd_pseudofs_downgrade(av + 1, ac - 1);
+               exit(0);
+       }
        if (strcmp(av[0], "pfs-destroy") == 0) {
                hammer_cmd_pseudofs_destroy(av + 1, ac - 1);
                exit(0);
@@ -279,6 +287,9 @@ usage(int exit_code)
                "hammer pfs-master <dirpath> [options]\n"
                "hammer pfs-slave <dirpath> [options]\n"
                "hammer pfs-update <dirpath> [options]\n"
+               "hammer pfs-upgrade <dirpath>\n"
+               "hammer pfs-downgrade <dirpath>\n"
+               "hammer pfs-destroy <dirpath>\n"
                "hammer history[@offset[,len]] <file-1>...<file-N>\n"
                "hammer -f blkdevs [-r] show\n"
                "hammer -f blkdevs blockmap\n"
index 1bb9f4e..802d31d 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.22 2008/07/09 10:32:30 dillon Exp $
+ * $DragonFly: src/sbin/hammer/hammer.h,v 1.23 2008/07/12 02:48:46 dillon Exp $
  */
 
 #include <sys/types.h>
@@ -85,6 +85,8 @@ void hammer_cmd_pseudofs_status(char **av, int ac);
 void hammer_cmd_pseudofs_create(char **av, int ac, int is_slave);
 void hammer_cmd_pseudofs_update(char **av, int ac);
 void hammer_cmd_pseudofs_destroy(char **av, int ac);
+void hammer_cmd_pseudofs_upgrade(char **av, int ac);
+void hammer_cmd_pseudofs_downgrade(char **av, int ac);
 void hammer_cmd_status(char **av, int ac);
 void hammer_cmd_snapshot(char **av, int ac);