HAMMER - Enhance cleanup utility for HAMMER v3
authorMatthew Dillon <dillon@apollo.backplane.com>
Thu, 15 Oct 2009 00:26:55 +0000 (17:26 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Thu, 15 Oct 2009 00:26:55 +0000 (17:26 -0700)
* For each PFS if the snapshots directory has not been overridden in
  the PFS config it will be migrated from <fs>/snapshots to
  /var/hammer/<path_from_root>.  The snapshots directory for the
  root directory itself will be called /var/hammer/root.  The old
  <fs>/snapshots directory will then removed.

  If a PFS has a snapshots directory config set no migration will
  occur.  Users can migrate it manually and then clear the snapshots
  directory in the PFS config if they desire.  We can't do it
  automatically because users might use this mechanic to mix snapshots
  with the live backup and needless to say cpdup()ing a live backup
  into /var is probably a bad idea.

* Fix a bug when generating softlinks in a directory that is not
  under the PFS being snapshotted.

* Add an optional third argument to the 'hammer snapshot' directive
  to allow a meta-data note to be specified.  The meta-data entry
  is created whether you specify a note or not.

sbin/hammer/cmd_cleanup.c
sbin/hammer/cmd_snapshot.c
sbin/hammer/hammer.8

index de830a7..2a37771 100644 (file)
@@ -79,8 +79,7 @@ static void cleanup_softlinks(int fd, int new_config,
                        const char *snapshots_path, int arg2, char *arg3);
 static int check_expired(const char *fpath, int arg2);
 
-static int create_snapshot(int new_config, const char *path,
-                       const char *snapshots_path);
+static int create_snapshot(const char *path, const char *snapshots_path);
 static int cleanup_rebalance(const char *path, const char *snapshots_path,
                        int arg1, int arg2);
 static int cleanup_prune(const char *path, const char *snapshots_path,
@@ -92,6 +91,12 @@ static int cleanup_recopy(const char *path, const char *snapshots_path,
 
 static void runcmd(int *resp, const char *ctl, ...);
 
+/*
+ * WARNING: Do not make the SNAPSHOTS_BASE "/var/snapshots" because
+ * it will interfere with the older HAMMER VERS < 3 snapshots directory
+ * for the /var PFS.
+ */
+#define SNAPSHOTS_BASE "/var/hammer"   /* HAMMER VERS >= 3 */
 #define WS     " \t\r\n"
 
 struct didpfs *FirstPFS;
@@ -160,6 +165,7 @@ do_cleanup(const char *path)
        int snapshots_disabled = 0;
        int prune_warning = 0;
        int new_config = 0;
+       int snapshots_from_pfs = 0;
        int fd;
        int r;
        int found_rebal = 0;
@@ -218,10 +224,14 @@ do_cleanup(const char *path)
        didpfs->uuid = mrec_tmp.pfs.pfsd.unique_uuid;
 
        /*
-        * Figure out where the snapshot directory is.
+        * Calculate the old snapshots directory for HAMMER VERSION < 3
+        *
+        * If the directory is explicitly specified in the PFS config
+        * we flag it and will not migrate it later.
         */
        if (mrec_tmp.pfs.pfsd.snapshots[0] == '/') {
                asprintf(&snapshots_path, "%s", mrec_tmp.pfs.pfsd.snapshots);
+               snapshots_from_pfs = 1;
        } else if (mrec_tmp.pfs.pfsd.snapshots[0]) {
                printf(" WARNING: pfs-slave's snapshots dir is not absolute\n");
                close(fd);
@@ -239,21 +249,8 @@ do_cleanup(const char *path)
        }
 
        /*
-        * Create a snapshot directory if necessary, and a config file if
-        * necessary.
-        *
-        * If the filesystem is running version >= 3 migrate the config
-        * file to meta-data.
+        * Check for old-style config file
         */
-       if (stat(snapshots_path, &st) < 0) {
-               if (mkdir(snapshots_path, 0755) != 0) {
-                       free(snapshots_path);
-                       printf(" unable to create snapshot dir \"%s\": %s\n",
-                               snapshots_path, strerror(errno));
-                       close(fd);
-                       return;
-               }
-       }
        asprintf(&config_path, "%s/config", snapshots_path);
        fp = fopen(config_path, "r");
 
@@ -287,6 +284,22 @@ do_cleanup(const char *path)
                }
                new_config = 1;
        } else {
+               /*
+                * Create missing snapshots directory for HAMMER VERSION < 3
+                */
+               if (stat(snapshots_path, &st) < 0) {
+                       if (mkdir(snapshots_path, 0755) != 0) {
+                               free(snapshots_path);
+                               printf(" unable to create snapshot dir \"%s\": %s\n",
+                                       snapshots_path, strerror(errno));
+                               close(fd);
+                               return;
+                       }
+               }
+
+               /*
+                *  Create missing config file for HAMMER VERSION < 3
+                */
                if (fp == NULL) {
                        config_init(path, &config);
                        fp = fopen(config_path, "w");
@@ -301,6 +314,54 @@ do_cleanup(const char *path)
                }
        }
 
+       /*
+        * If snapshots_from_pfs is not set we calculate the new snapshots
+        * directory default (in /var) for HAMMER VERSION >= 3 and migrate
+        * the old snapshots directory over.
+        *
+        * People who have set an explicit snapshots directory will have
+        * to migrate the data manually into /var/hammer, or not bother at
+        * all.  People running slaves may wish to migrate it and then
+        * clear the snapshots specification in the PFS config for the
+        * slave.
+        */
+       if (new_config && snapshots_from_pfs == 0) {
+               char *npath;
+
+               assert(path[0] == '/');
+               if (strcmp(path, "/") == 0)
+                       asprintf(&npath, "%s/root", SNAPSHOTS_BASE);
+               else
+                       asprintf(&npath, "%s/%s", SNAPSHOTS_BASE, path + 1);
+               if (stat(npath, &st) < 0 && errno == ENOENT) {
+                       if (stat(snapshots_path, &st) < 0 && errno == ENOENT) {
+                               printf(" HAMMER UPGRADE: Creating snapshots\n"
+                                      "\tCreating snapshots in %s\n",
+                                      npath);
+                               runcmd(&r, "mkdir -p %s", npath);
+                       } else {
+                               printf(" HAMMER UPGRADE: Moving snapshots\n"
+                                      "\tMoving snapshots from %s to %s\n",
+                                      snapshots_path, npath);
+                               runcmd(&r, "mkdir -p %s", npath);
+                               runcmd(&r, "cpdup %s %s", snapshots_path, npath);
+                               if (r != 0) {
+                           printf("Unable to move snapshots directory!\n");
+                           printf("Please fix this critical error.\n");
+                           printf("Aborting cleanup of %s\n", path);
+                                       close(fd);
+                                       return;
+                               }
+                               runcmd(&r, "rm -rf %s", snapshots_path);
+                       }
+               }
+               free(snapshots_path);
+               snapshots_path = npath;
+       }
+
+       /*
+        * Lock the PFS.  fd is the base directory of the mounted PFS.
+        */
        if (flock(fd, LOCK_EX|LOCK_NB) == -1) {
                if (errno == EWOULDBLOCK)
                        printf(" PFS #%d locked by other process\n", pfs.pfs_id);
@@ -358,8 +419,7 @@ do_cleanup(const char *path)
                                cleanup_softlinks(fd, new_config,
                                                  snapshots_path,
                                                  arg2, arg3);
-                               r = create_snapshot(new_config,
-                                                   path, snapshots_path);
+                               r = create_snapshot(path, snapshots_path);
                        } else {
                                printf("skip\n");
                        }
@@ -428,7 +488,7 @@ do_cleanup(const char *path)
 
        /*
         * Add new rebalance feature if the config doesn't have it.
-        * (old style config only)
+        * (old style config only).
         */
        if (new_config == 0 && found_rebal == 0) {
                if ((fp = fopen(config_path, "r+")) != NULL) {
@@ -922,21 +982,11 @@ check_expired(const char *fpath, int arg2)
  * Issue a snapshot.
  */
 static int
-create_snapshot(int new_config, const char *path, const char *snapshots_path)
+create_snapshot(const char *path, const char *snapshots_path)
 {
        int r;
 
-       if (new_config) {
-               /*
-                * New-style snapshot >= version 3.
-                */
-               runcmd(&r, "hammer snap %s cleanup", snapshots_path);
-       } else {
-               /*
-                * Old-style snapshot prior to version 3
-                */
-               runcmd(&r, "hammer snapshot %s %s", path, snapshots_path);
-       }
+       runcmd(&r, "hammer snapshot %s %s", path, snapshots_path);
        return(r);
 }
 
index 1fe9fd4..cab7ece 100644 (file)
@@ -269,6 +269,7 @@ hammer_cmd_snapshot(char **av, int ac)
        struct hammer_ioc_synctid synctid;
        char *from;
        char *to;
+       char *note = NULL;
 
        if (ac == 1) {
                filesystem = NULL;
@@ -276,6 +277,10 @@ hammer_cmd_snapshot(char **av, int ac)
        } else if (ac == 2) {
                filesystem = av[0];
                softlink_dir = av[1];
+       } else if (ac == 3) {
+               filesystem = av[0];
+               softlink_dir = av[1];
+               note = av[2];
        } else {
                snapshot_usage(1);
                /* not reached */
@@ -361,7 +366,7 @@ hammer_cmd_snapshot(char **av, int ac)
 
        asprintf(&from, "%s/@@0x%016jx", filesystem, (uintmax_t)synctid.tid);
 
-       snapshot_add(fd, from, to, NULL, synctid.tid);
+       snapshot_add(fd, from, to, note, synctid.tid);
 
        close(fd);
        printf("%s\n", to);
@@ -382,6 +387,9 @@ snapshot_add(int fd, const char *fsym, const char *tsym, const char *label,
         bzero(&version, sizeof(version));
         bzero(&snapshot, sizeof(snapshot));
 
+       /*
+        * For HAMMER filesystem v3+ the snapshot is recorded in meta-data.
+        */
         if (ioctl(fd, HAMMERIOC_GET_VERSION, &version) == 0 &&
            version.cur_version >= 3) {
                snapshot.index = 0;
@@ -402,6 +410,11 @@ snapshot_add(int fd, const char *fsym, const char *tsym, const char *label,
                                strerror(snapshot.head.error));
                }
         }
+
+       /*
+        * Create a symlink for the snapshot.  If a file exists with the same
+        * name the new symlink will replace it.
+        */
        if (fsym && tsym) {
                remove(tsym);
                if (symlink(fsym, tsym) < 0) {
index 2c6c627..51345a8 100644 (file)
@@ -452,7 +452,7 @@ together with any other device that make the filesystem, colon-separated to
 .Xr mount_hammer 8 .
 .\" ==== snapshot ====
 .It Cm snapshot Oo Ar filesystem Oc Ar snapshot-dir
-(HAMMER VERSIONS LESS THEN 3)
+.It Cm snapshot Ar filesystem Ar snapshot-dir Ar note
 Takes a snapshot of the file system either explicitly given by
 .Ar filesystem
 or implicitly derived from the
@@ -488,9 +488,11 @@ hammer snapshot /mysnapshots
 hammer snapshot /mysnapshots/%Y-%m-%d
 
 hammer snapshot /obj /mysnapshots/obj-%Y-%m-%d
+
+hammer snapshot /usr /my/snaps/for/usr "note"
 .Ed
 .Pp
-would create symlinks similar to:
+Would create symlinks similar to:
 .Bd -literal -offset indent
 /mysnapshots/snap-20080627-1210 -> /@@0x10d2cd05b7270d16
 
@@ -498,6 +500,13 @@ would create symlinks similar to:
 
 /mysnapshots/obj-2008-06-27 -> /obj@@0x10d2cd05b7270d16
 .Ed
+.Pp
+When run on a
+.Nm HAMMER
+version 3+ filesystem the snapshot is also recorded in meta-data
+along with the optional note.  See the
+.Cm snapls
+directive.
 .\" ==== snap* ====
 .It Cm snap Ar path Op "note"
 (HAMMER VERSION 3+)