HAMMER Utilities: enhanced show, timeout option
authorMatthew Dillon <dillon@dragonflybsd.org>
Sun, 4 May 2008 19:18:17 +0000 (19:18 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Sun, 4 May 2008 19:18:17 +0000 (19:18 +0000)
* Enchange the show command when used with -vvv.  The command now reports
  directory entries and basic information about inodes.

* Add the [-t timeout] option.  The idea is to use this to limit the amount
  of time hammer spends reblocking or pruning a filesystem when running the
  command from a cron job.

* Adjust the format of the softlink option to be more consistent.

sbin/hammer/cmd_prune.c
sbin/hammer/cmd_reblock.c
sbin/hammer/cmd_show.c
sbin/hammer/hammer.8
sbin/hammer/hammer.c

index fa5a233..ac4199b 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/Attic/cmd_prune.c,v 1.4 2008/03/20 04:03:03 dillon Exp $
+ * $DragonFly: src/sbin/hammer/Attic/cmd_prune.c,v 1.5 2008/05/04 19:18:17 dillon Exp $
  */
 
 #include "hammer.h"
@@ -93,10 +93,16 @@ hammer_cmd_prune(char **av, int ac)
        fd = open(filesystem, O_RDONLY);
        if (fd < 0)
                err(1, "Unable to open %s", filesystem);
-       if (ioctl(fd, HAMMERIOC_PRUNE, &prune) < 0)
-               printf("Prune %s failed: %s\n", filesystem, strerror(errno));
-       else
+       if (ioctl(fd, HAMMERIOC_PRUNE, &prune) < 0) {
+               if (errno == EINTR) {
+                       printf("Prune %s interrupted by timer\n", filesystem);
+               } else {
+                       printf("Prune %s failed: %s\n",
+                              filesystem, strerror(errno));
+               }
+       } else {
                printf("Prune %s succeeded\n", filesystem);
+       }
        close(fd);
        if (LinkPath)
                hammer_prune_create_links(filesystem, &prune);
@@ -311,7 +317,7 @@ hammer_prune_make_softlink(const char *filesystem, hammer_tid_t tid)
        if (tid % (1000000000ULL * 60 * 60 * 24) == 0) {
                strftime(buf, sizeof(buf), "snap-%d%b%Y", tp);
        } else if (tid % (1000000000ULL * 60 * 60) == 0) {
-               strftime(buf, sizeof(buf), "snap-%d%b%Y_%H", tp);
+               strftime(buf, sizeof(buf), "snap-%d%b%Y_%H%M", tp);
        } else if (tid % (1000000000ULL * 60) == 0) {
                strftime(buf, sizeof(buf), "snap-%d%b%Y_%H%M", tp);
        } else {
index 97ce0f5..c396c0a 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.1 2008/03/18 05:21:53 dillon Exp $
+ * $DragonFly: src/sbin/hammer/cmd_reblock.c,v 1.2 2008/05/04 19:18:17 dillon Exp $
  */
 
 #include "hammer.h"
@@ -73,10 +73,16 @@ hammer_cmd_reblock(char **av, int ac)
        fd = open(filesystem, O_RDONLY);
        if (fd < 0)
                err(1, "Unable to open %s", filesystem);
-       if (ioctl(fd, HAMMERIOC_REBLOCK, &reblock) < 0)
-               printf("Reblock %s failed: %s\n", filesystem, strerror(errno));
-       else
+       if (ioctl(fd, HAMMERIOC_REBLOCK, &reblock) < 0) {
+               if (errno == EINTR) {
+                       printf("Reblock %s interrupted by timer\n", filesystem);
+               } else {
+                       printf("Reblock %s failed: %s\n",
+                              filesystem, strerror(errno));
+               }
+       } else {
                printf("Reblock %s succeeded\n", filesystem);
+       }
        close(fd);
        printf("Reblocked:\n"
               "    %lld/%lld btree nodes\n"
index dceb480..9528e7d 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.6 2008/02/23 03:01:06 dillon Exp $
+ * $DragonFly: src/sbin/hammer/cmd_show.c,v 1.7 2008/05/04 19:18:17 dillon Exp $
  */
 
 #include "hammer.h"
 #define FLAG_TOOFARLEFT                0x0001
 #define FLAG_TOOFARRIGHT       0x0002
 #define FLAG_BADTYPE           0x0004
+#define FLAG_BADCHILDPARENT    0x0008
 
 static void print_btree_node(hammer_off_t node_offset, int depth, int spike,
                        hammer_base_elm_t left_bound,
                        hammer_base_elm_t right_bound);
 static void print_btree_elm(hammer_btree_elm_t elm, int i, u_int8_t type,
                        int flags, const char *label);
-static int print_elm_flags(hammer_node_ondisk_t node, hammer_btree_elm_t elm,
-                       u_int8_t btype, hammer_base_elm_t left_bound,
+static int print_elm_flags(hammer_node_ondisk_t node, hammer_off_t node_offset,
+                       hammer_btree_elm_t elm, u_int8_t btype,
+                       hammer_base_elm_t left_bound,
                        hammer_base_elm_t right_bound);
 static void print_bigblock_fill(hammer_off_t offset);
+static void print_record(hammer_btree_elm_t elm);
 
 void
 hammer_cmd_show(hammer_off_t node_offset, int depth,
@@ -93,13 +96,15 @@ print_btree_node(hammer_off_t node_offset, int depth, int spike,
 
                for (i = 0; i < node->count; ++i) {
                        elm = &node->elms[i];
-                       flags = print_elm_flags(node, elm, elm->base.btype,
+                       flags = print_elm_flags(node, node_offset,
+                                               elm, elm->base.btype,
                                                left_bound, right_bound);
                        print_btree_elm(elm, i, node->type, flags, "ELM");
                }
                if (node->type == HAMMER_BTREE_TYPE_INTERNAL) {
                        elm = &node->elms[i];
-                       flags = print_elm_flags(node, elm, 'I',
+                       flags = print_elm_flags(node, node_offset,
+                                               elm, 'I',
                                                left_bound, right_bound);
                        print_btree_elm(elm, i, node->type, flags, "RBN");
                }
@@ -138,6 +143,8 @@ print_btree_elm(hammer_btree_elm_t elm, int i, u_int8_t type,
                flagstr[3] = 'R';
        if (flags & FLAG_BADTYPE)
                flagstr[4] = 'T';
+       if (flags & FLAG_BADCHILDPARENT)
+               flagstr[4] = 'C';
 
        printf("%s\t%s %2d %c ",
               flagstr, label, i,
@@ -147,7 +154,8 @@ print_btree_elm(hammer_btree_elm_t elm, int i, u_int8_t type,
               elm->base.key,
               elm->base.rec_type,
               elm->base.obj_type);
-       printf("\t         tids %016llx:%016llx ",
+       printf("\t       %c tids %016llx:%016llx ",
+               (elm->base.delete_tid ? 'd' : ' '),
               elm->base.create_tid,
               elm->base.delete_tid);
 
@@ -168,6 +176,8 @@ print_btree_elm(hammer_btree_elm_t elm, int i, u_int8_t type,
                                printf(", ");
                                print_bigblock_fill(elm->leaf.data_offset);
                        }
+                       if (VerboseOpt > 1)
+                               print_record(elm);
                        break;
                }
                break;
@@ -179,14 +189,25 @@ print_btree_elm(hammer_btree_elm_t elm, int i, u_int8_t type,
 
 static
 int
-print_elm_flags(hammer_node_ondisk_t node, hammer_btree_elm_t elm,
-               u_int8_t btype,
+print_elm_flags(hammer_node_ondisk_t node, hammer_off_t node_offset,
+               hammer_btree_elm_t elm, u_int8_t btype,
                hammer_base_elm_t left_bound, hammer_base_elm_t right_bound)
 {
        int flags = 0;
 
        switch(node->type) {
        case HAMMER_BTREE_TYPE_INTERNAL:
+               if (elm->internal.subtree_offset) {
+                       struct buffer_info *buffer = NULL;
+                       hammer_node_ondisk_t subnode;
+
+                       subnode = get_node(elm->internal.subtree_offset,
+                                          &buffer);
+                       if (subnode->parent != node_offset)
+                               flags |= FLAG_BADCHILDPARENT;
+                       rel_buffer(buffer);
+               }
+
                switch(btype) {
                case HAMMER_BTREE_TYPE_INTERNAL:
                        if (left_bound == NULL || right_bound == NULL)
@@ -250,3 +271,60 @@ print_bigblock_fill(hammer_off_t offset)
        );
 }
 
+static
+void
+print_record(hammer_btree_elm_t elm)
+{
+       struct buffer_info *rec_buffer;
+       struct buffer_info *data_buffer;
+       hammer_record_ondisk_t rec;
+       hammer_off_t rec_offset;
+       hammer_off_t data_offset;
+       int32_t data_len;
+       char *data;
+
+       rec_offset = elm->leaf.rec_offset;
+       data_offset = elm->leaf.data_offset;
+       data_len = elm->leaf.data_len;
+       rec_buffer = NULL;
+       data_buffer = NULL;
+
+       rec = get_buffer_data(rec_offset, &rec_buffer, 0);
+       if (data_offset)
+               data = get_buffer_data(data_offset, &data_buffer, 0);
+       else
+               data = NULL;
+
+       printf("\n%17s", "");
+       if (rec == NULL) {
+               printf("record FAILED\n");
+               return;
+       }
+       switch(rec->base.base.rec_type) {
+       case HAMMER_RECTYPE_INODE:
+               printf("size=%lld nlinks=%lld",
+                      rec->inode.ino_size, rec->inode.ino_nlinks);
+               break;
+       case HAMMER_RECTYPE_DIRENTRY:
+               printf("dir-entry ino=%016llx name=\"%*.*s\"",
+                      rec->entry.obj_id,
+                      data_len, data_len, data);
+               break;
+       case HAMMER_RECTYPE_FIX:
+               switch(rec->base.base.key) {
+               case HAMMER_FIXKEY_SYMLINK:
+                       printf("symlink=\"%*.*s\"", data_len, data_len, data);
+                       break;
+               default:
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+       if (rec_buffer)
+               rel_buffer(rec_buffer);
+       if (data_buffer)
+               rel_buffer(data_buffer);
+}
+
index 8d3f488..e08deda 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.11 2008/04/14 08:17:09 swildner Exp $
+.\" $DragonFly: src/sbin/hammer/hammer.8,v 1.12 2008/05/04 19:18:17 dillon Exp $
 .Dd December 31, 2007
 .Dt HAMMER 8
 .Os
@@ -42,6 +42,7 @@
 .Op Fl hrx
 .Op Fl f Ar blkdev[:blkdev]*
 .Op Fl s Ar linkpath
+.Op Fl t Ar timeout
 .Ar command
 .Ar ...
 .Sh DESCRIPTION
@@ -61,6 +62,10 @@ Specify the volumes making up a HAMMER filesystem.
 .It Fl s Ar linkpath
 When pruning a filesystem you can instruct HAMMER to create softlinks
 to available snapshots.
+.It Fl t Ar timeout
+When pruning and reblocking you can tell the utility to stop after a
+certain period of time.
+This option is typically used to limit the time spent reblocking.
 .It Fl v
 Increase verboseness.  May be specified multiple times.
 .It Fl x
index c931aa5..49db592 100644 (file)
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sbin/hammer/hammer.c,v 1.13 2008/03/25 03:57:58 dillon Exp $
+ * $DragonFly: src/sbin/hammer/hammer.c,v 1.14 2008/05/04 19:18:17 dillon Exp $
  */
 
 #include "hammer.h"
+#include <signal.h>
 #include <math.h>
 
 static void hammer_parsetime(u_int64_t *tidp, const char *timestr);
 static void hammer_waitsync(int dosleep);
 static void hammer_parsedevs(const char *blkdevs);
+static void sigalrm(int signo);
 static void usage(int exit_code);
 
 int RecurseOpt;
@@ -53,10 +55,11 @@ main(int ac, char **av)
        struct timeval tv;
        u_int64_t tid;
        int ch;
+       int timeout = 0;
        u_int32_t status;
        char *blkdevs = NULL;
 
-       while ((ch = getopt(ac, av, "hf:rs:vx")) != -1) {
+       while ((ch = getopt(ac, av, "hf:rs:t:vx")) != -1) {
                switch(ch) {
                case 'h':
                        usage(0);
@@ -70,6 +73,9 @@ main(int ac, char **av)
                case 's':
                        LinkPath = optarg;
                        break;
+               case 't':
+                       timeout = strtol(optarg, NULL, 0);
+                       break;
                case 'v':
                        ++VerboseOpt;
                        break;
@@ -88,6 +94,11 @@ main(int ac, char **av)
                /* not reached */
        }
 
+       if (timeout > 0) {
+               signal(SIGALRM, sigalrm);
+               alarm(timeout);
+       }
+
        if (strcmp(av[0], "now") == 0) {
                hammer_waitsync(1);
                tid = (hammer_tid_t)time(NULL) * 1000000000LLU;
@@ -290,6 +301,13 @@ hammer_parsedevs(const char *blkdevs)
        }
 }
 
+static
+void
+sigalrm(int signo __unused)
+{
+       /* do nothing (interrupts HAMMER ioctl) */
+}
+
 static
 void
 usage(int exit_code)