---

 user/test/Makefile    |    6 
 user/test/tux3graph.c |  591 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 596 insertions(+), 1 deletion(-)

diff -puN user/test/Makefile~tux3graph user/test/Makefile
--- tux3/user/test/Makefile~tux3graph   2008-10-16 01:20:46.000000000 +0900
+++ tux3-hirofumi/user/test/Makefile    2008-10-16 01:20:46.000000000 +0900
@@ -4,7 +4,8 @@ CC += -Wno-unused-parameter -Wno-sign-co
 
 VG=valgrind --error-exitcode=200 --leak-check=full
 
-binaries = vfs.o balloc dleaf ileaf iattr xattr btree dir filemap inode tux3
+binaries = vfs.o balloc dleaf ileaf iattr xattr btree dir filemap inode tux3 \
+       tux3graph
 
 ifeq ($(shell pkg-config fuse && echo found), found)
        binaries += tux3fs tux3fuse
@@ -74,6 +75,9 @@ tux3fs: $(fsdeps) tux3fs.c
 tux3fuse: $(fsdeps) tux3fuse.c
        $(CC) $$(pkg-config --cflags fuse) vfs.o tux3fuse.c -lfuse -otux3fuse
 
+tux3graph: $(fsdeps) tux3graph.c
+       $(CC) vfs.o tux3graph.c -lpopt -o $@
+
 makefs mkfs: tux3 tux3fs
        dd if=/dev/zero of=/tmp/testdev bs=1 count=1 seek=1M
        ./tux3 mkfs /tmp/testdev
diff -puN /dev/null user/test/tux3graph.c
--- /dev/null   2008-10-15 22:04:20.740001114 +0900
+++ tux3-hirofumi/user/test/tux3graph.c 2008-10-16 01:20:46.000000000 +0900
@@ -0,0 +1,591 @@
+/*
+ * Original copyright (c) 2008 Daniel Phillips <[EMAIL PROTECTED]>
+ * Licensed under the GPL version 3
+ *
+ * By contributing changes to this file you grant the original copyright holder
+ * the right to distribute those changes under any license.
+ *
+ * $ tux3graph [-v] volname
+ * $ dot -Tpng -O volname.dot
+ * $ viewer volname.dot.png
+ */
+
+#define include_inode_c
+#include "inode.c"
+#include <popt.h>
+
+#define ARRAY_SIZE(x)          (sizeof(x) / sizeof((x)[0]))
+
+static int fls(uint32_t v)
+{
+       uint32_t mask;
+       int bit = 0;
+       for (bit = 32, mask = 1 << 31; bit; mask >>= 1, bit--)
+               if ((v & mask))
+                       break;
+       return bit;
+}
+
+#define TUX3_BITMAP_INO                0
+#define TUX3_VTABLE_INO                2
+#define TUX3_ATABLE_INO                10
+#define TUX3_ROOTDIR_INO       13
+
+static const char *dtree_names[] = {
+       [TUX3_BITMAP_INO]       = "bitmap",
+       [TUX3_VTABLE_INO]       = "vtable",
+       [TUX3_ATABLE_INO]       = "atable",
+       [TUX3_ROOTDIR_INO]      = "rootdir",
+};
+
+static int verbose;
+#define DRAWN_DTREE    (1 << 0)
+#define DRAWN_DLEAF    (1 << 1)
+#define DRAWN_ILEAF    (1 << 2)
+static int drawn;
+
+struct graph_info {
+       FILE *f;
+       const char *bname;      /* btree name */
+       const char *lname;      /* leaf name */
+};
+
+typedef void (*draw_leaf_t)(struct graph_info *, BTREE, struct buffer *);
+
+static void draw_sb(struct graph_info *gi, struct sb *sb)
+{
+       struct disksuper *txsb = &sb->super;
+
+       fprintf(gi->f,
+               "tux3_sb [\n"
+               "label = \"{ [disksuper] (blocknr %llu)"
+               " | magic %.4s, 0x%02x, 0x%02x, 0x%02x, 0x%02x"
+               " | birthdate %llu | flags 0x%016llx"
+               " | <iroot0> iroot 0x%016llx (depth %u, block %llu)"
+               " | aroot %llu | blockbits %u (size %u) | volblocks %llu"
+               " | freeblocks %llu | nextalloc %llu"
+               " | freeatom %u | atomgen %u }\"\n"
+               "shape = record\n"
+               "];\n",
+               (L)SB_LOC >> sb->blockbits,
+               txsb->magic,
+               (u8)txsb->magic[4], (u8)txsb->magic[5],
+               (u8)txsb->magic[6], (u8)txsb->magic[7],
+               (L)from_be_u64(txsb->birthdate),
+               (L)from_be_u64(txsb->flags), (L)from_be_u64(txsb->iroot),
+               sb->itable.root.depth, (L)sb->itable.root.block,
+               (L)from_be_u64(txsb->aroot), sb->blockbits, sb->blocksize,
+               (L)from_be_u64(txsb->volblocks),
+               (L)from_be_u64(txsb->freeblocks),
+               (L)from_be_u64(txsb->nextalloc),
+               from_be_u32(txsb->freeatom), from_be_u32(txsb->atomgen));
+
+       fprintf(gi->f, "tux3_sb:iroot0:e -> %s_bnode_%llu:n;\n",
+               gi->bname, (L)sb->itable.root.block);
+}
+
+static void draw_bnode(struct graph_info *gi, int levels, int level,
+                      struct buffer *buffer)
+{
+       struct bnode *bnode = buffer->data;
+       block_t blocknr = buffer->index;
+       struct index_entry *index = bnode->entries;
+       int n;
+
+       fprintf(gi->f,
+               "%s_bnode_%llu [\n"
+               "label = \"{ <bnode0> [bnode] | count %u |",
+               gi->bname, (L)blocknr, bnode->count);
+       for (n = 0; n < bnode->count; n++) {
+               fprintf(gi->f,
+                       " %c <f%u> key %llu, block %lld",
+                       n ? '|' : '{', n,
+                       (L)index[n].key, (L)index[n].block);
+       }
+       fprintf(gi->f,
+               " }}\"\n"
+               "shape = record\n"
+               "];\n");
+
+       if (level == levels - 1) {
+               for (n = 0; n < bnode->count; n++) {
+                       fprintf(gi->f,
+                               "%s_bnode_%llu:f%u -> %s_%llu:%s0;\n",
+                               gi->bname, (L)blocknr, n,
+                               gi->lname, (L)index[n].block,
+                               gi->lname);
+               }
+       } else {
+               for (n = 0; n < bnode->count; n++) {
+                       fprintf(gi->f,
+                               "%s_bnode_%llu:f%u -> %s_bnode_%llu:bnode0;\n",
+                               gi->bname, (L)blocknr, n,
+                               gi->bname, (L)index[n].block);
+               }
+       }
+}
+
+static void draw_path(struct graph_info *gi, BTREE, struct path *path)
+{
+       int level;
+       for (level = 0; level < btree->root.depth; level++)
+               draw_bnode(gi, btree->root.depth, level, path[level].buffer);
+}
+
+static int draw_advance(struct graph_info *gi, struct map *map,
+                       struct path *path, int levels)
+{
+       int level = levels;
+       struct buffer *buffer = path[level].buffer;
+       struct bnode *node;
+       do {
+               brelse(buffer);
+               if (!level)
+                       return 0;
+               node = (buffer = path[--level].buffer)->data;
+       } while (level_finished(path, level));
+       do {
+               if (!(buffer = bread(map, path[level].next++->block)))
+                       goto eek;
+               path[++level] = (struct path){
+                       .buffer = buffer,
+                       .next = ((struct bnode *)buffer->data)->entries
+               };
+               if (level < levels)
+                       draw_bnode(gi, levels, level, buffer);
+       } while (level < levels);
+       return 1;
+eek:
+       release_path(path, level);
+       return -EIO;
+}
+
+static void draw_tree(struct graph_info *gi, BTREE, draw_leaf_t draw_leaf)
+{
+       struct path path[30]; // check for overflow!!!
+       struct buffer *buffer;
+
+       if (probe(btree, 0, path))
+               error("tell me why!!!");
+
+       draw_path(gi, btree, path);
+
+       do {
+               buffer = path[btree->root.depth].buffer;
+               draw_leaf(gi, btree, buffer);
+       } while (draw_advance(gi, buffer->map, path, btree->root.depth));
+}
+
+static inline struct group *dleaf_groups(BTREE, struct dleaf *dleaf)
+{
+       return (void *)dleaf + btree->sb->blocksize;
+}
+
+static inline struct group *dleaf_group(struct group *groups, int gr)
+{
+       return groups - (gr + 1);
+}
+
+static inline struct entry *dleaf_entries(struct dleaf *dleaf,
+                                         struct group *groups, int gr)
+{
+       struct entry *entries = (struct entry *)(groups - dleaf->groups);
+       for (int i = 0; i < gr; i++)
+               entries -= dleaf_group(groups, i)->count;
+       return entries;
+}
+
+static inline struct entry *dleaf_entry(struct entry *entries, int ent)
+{
+       return entries - (ent + 1);
+}
+
+static inline int dleaf_extent_count(struct entry *entries, int ent)
+{
+       int offset = ent ? dleaf_entry(entries, ent - 1)->limit : 0;
+       return dleaf_entry(entries, ent)->limit - offset;
+}
+
+static inline struct extent *dleaf_extents(struct dleaf *dleaf,
+                                          struct group *groups,
+                                          int gr, int ent)
+{
+       struct extent *extents = dleaf->table;
+       struct group *group;
+       struct entry *entries;
+       int i;
+
+       for (i = 0; i < gr - 1; i++) {
+               group = dleaf_group(groups, i);
+               entries = dleaf_entries(dleaf, groups, i);
+               extents += dleaf_entry(entries, group->count - 1)->limit;
+       }
+       if (ent) {
+               entries = dleaf_entries(dleaf, groups, i);
+               extents += dleaf_entry(entries, ent)->limit;
+       }
+
+       return extents;
+}
+
+static inline struct extent *dleaf_extent(struct extent *extents, int ex)
+{
+       return extents + ex;
+}
+
+static void draw_dleaf(struct graph_info *gi, BTREE, struct buffer *buffer)
+{
+       struct dleaf *dleaf = buffer->data;
+       block_t blocknr = buffer->index;
+       struct group *groups = dleaf_groups(btree, dleaf);
+       struct extent *extents;
+
+       if (!verbose && (drawn & DRAWN_DLEAF))
+               return;
+       drawn |= DRAWN_DLEAF;
+
+       fprintf(gi->f,
+               "%s_%llu [\n"
+               "label = \"{ <%s0> [%s]"
+               " | magic 0x%04x, free %u, used %u, groups %u",
+               gi->lname, (L)blocknr,
+               gi->lname, gi->lname,
+               dleaf->magic, dleaf->free, dleaf->used, dleaf->groups);
+
+       /* draw extents */
+       for (int gr = 0; gr < dleaf->groups; gr++) {
+               struct group *group = dleaf_group(groups, gr);
+               struct entry *entries = dleaf_entries(dleaf, groups, gr);
+               for (int ent = 0; ent < group->count; ent++) {
+                       int ex_count = dleaf_extent_count(entries, ent);
+                       extents = dleaf_extents(dleaf, groups, gr, ent);
+                       for (int ex = 0; ex < ex_count; ex++) {
+                               fprintf(gi->f,
+                                       " | <gr%uent%uex%u>"
+                                       " block %llu, count %u, version 0x%03x"
+                                       " (extent %u)",
+                                       gr, ent, ex,
+                                       (L)extents[ex].block, extents[ex].count,
+                                       extents[ex].version,
+                                       ex);
+                       }
+               }
+       }
+       fprintf(gi->f,
+               " | .....");
+
+       /* draw entries */
+       for (int gr = dleaf->groups - 1; gr >= 0; gr--) {
+               struct group *group = dleaf_group(groups, gr);
+               struct entry *entries = dleaf_entries(dleaf, groups, gr);
+
+               for (int ent = group->count - 1; ent >= 0; ent--) {
+                       struct entry *entry = dleaf_entry(entries, ent);
+
+                       fprintf(gi->f,
+                               " | <gr%uent%u> limit %u, keylo 0x%06x"
+                               " (entry %u, count %u, iblock %llu)",
+                               gr, ent, entry->limit, entry->keylo,
+                               ent, dleaf_extent_count(entries, ent),
+                               (L)(group->keyhi << 24 | entry->keylo));
+               }
+       }
+
+       /* draw groups */
+       for (int gr = dleaf->groups - 1; gr >= 0; gr--) {
+               struct group *group = dleaf_group(groups, gr);
+
+               fprintf(gi->f,
+                       " | <gr%u> count %u, keyhi 0x%06x (group %u)",
+                       gr, group->count, group->keyhi, gr);
+       }
+
+       fprintf(gi->f,
+               " }\"\n"
+               "shape = record\n"
+               "];\n");
+
+       for (int gr = 0; gr < dleaf->groups; gr++) {
+               struct group *group = dleaf_group(groups, gr);
+               fprintf(gi->f,
+                       "%s_%llu:gr%u:w -> %s_%llu:gr%uent%u:w;\n",
+                       gi->lname, (L)blocknr, gr,
+                       gi->lname, (L)blocknr, gr, 0);
+               for (int ent = 0; ent < group->count; ent++) {
+                       fprintf(gi->f,
+                               "%s_%llu:gr%uent%u:w"
+                               " -> %s_%llu:gr%uent%uex%u:w;\n",
+                               gi->lname, (L)blocknr, gr, ent,
+                               gi->lname, (L)blocknr, gr, ent, 0);
+               }
+       }
+}
+
+static inline u16 *ileaf_dict(BTREE, struct ileaf *ileaf)
+{
+       return (void *)ileaf + btree->sb->blocksize;
+}
+
+static inline u16 __ileaf_atdict(u16 *dict, int at)
+{
+       assert(at > 0);
+       return *(dict - at);
+}
+
+static inline u16 ileaf_attr_size(u16 *dict, int at)
+{
+       int size = __ileaf_atdict(dict, at + 1) - atdict(dict, at);
+       assert(size >= 0);
+       return size;
+}
+
+static void draw_ileaf(struct graph_info *gi, BTREE, struct buffer *buffer)
+{
+       struct ileaf *ileaf = buffer->data;
+       block_t blocknr = buffer->index;
+       u16 *dict = ileaf_dict(btree, ileaf);
+       int at;
+
+       if (!verbose && (drawn & DRAWN_ILEAF))
+               return;
+       drawn |= DRAWN_ILEAF;
+
+       fprintf(gi->f,
+               "%s_%llu [\n"
+               "label = \"{ <%s0> [%s] | magic 0x%04x, count %u, ibase %llu",
+               gi->lname, (L)blocknr, gi->lname,
+               gi->lname, ileaf->magic, ileaf->count, (L)ileaf->ibase);
+
+       /* draw inode attributes */
+       for (at = 0; at < ileaf->count; at++) {
+               u16 size = ileaf_attr_size(dict, at);
+               if (!size)
+                       continue;
+
+               void *attrs = ileaf->table + atdict(dict, at);
+               struct inode inode = {
+                       .sb = btree->sb,
+               };
+               decode_attrs(&inode, attrs, size);
+
+               fprintf(gi->f,
+                       " | <a%d> attrs (ino %llu, size %u,"
+                       " block %llu, depth %d)",
+                       at, (L)ileaf->ibase + at, size,
+                       (L)inode.btree.root.block,
+                       inode.btree.root.depth);
+       }
+       fprintf(gi->f,
+               " | .....");
+
+       /* draw offset part */
+       for (at = ileaf->count; at > 0; at--) {
+               if (at == ileaf->count) {
+                       fprintf(gi->f,
+                               " | <o%d> offset %u (at %d)",
+                               at, atdict(dict, at), at);
+               } else {
+                       fprintf(gi->f,
+                               " | <o%d> offset %u (at %d, ino %llu, size %u)",
+                               at, atdict(dict, at), at, (L)ileaf->ibase + at,
+                               ileaf_attr_size(dict, at));
+               }
+       }
+
+       fprintf(gi->f,
+               " }\"\n"
+               "shape = record\n"
+               "];\n");
+
+       /* draw allows from offset to attributes */
+       for (at = 1; at < ileaf->count; at++) {
+               if (!ileaf_attr_size(dict, at))
+                       continue;
+
+               fprintf(gi->f,
+                       "%s_%llu:o%d:w -> %s_%llu:a%d:w;\n",
+                       gi->lname, (L)blocknr, at,
+                       gi->lname, (L)blocknr, at);
+       }
+
+       /* draw inode's dtree */
+       for (at = 0; at < ileaf->count; at++) {
+               u16 size = ileaf_attr_size(dict, at);
+               if (!size)
+                       continue;
+
+               void *attrs = ileaf->table + atdict(dict, at);
+               struct inode inode = {
+                       .sb = btree->sb,
+               };
+               decode_attrs(&inode, attrs, size);
+
+               char name[64];
+               inum_t ino = ileaf->ibase + at;
+               if (ino < ARRAY_SIZE(dtree_names) && dtree_names[ino])
+                       sprintf(name, "%s_dtree", dtree_names[ino]);
+               else
+                       sprintf(name, "ino%llu_dtree", (L)ino);
+
+               if (verbose || !(drawn & DRAWN_DTREE)) {
+                       drawn |= DRAWN_DTREE;
+
+                       fprintf(gi->f,
+                               "subgraph cluster_%s {"
+                               "label = \"%s\"\n",
+                               name, name);
+                       struct graph_info ginfo = {
+                               .f = gi->f,
+                               .bname = name,
+                               .lname = "dleaf",
+                       };
+                       draw_tree(&ginfo, &inode.btree, draw_dleaf);
+                       fprintf(gi->f, "}\n");
+               }
+               fprintf(gi->f, "%s_%llu:a%d:e -> %s_bnode_%llu:n;\n",
+                       gi->lname, (L)blocknr, at, name,
+                       (L)inode.btree.root.block);
+       }
+}
+
+int main(int argc, const char *argv[])
+{
+       poptContext popt;
+       char *seekarg = NULL;
+       unsigned blocksize = 0;
+       struct poptOption options[] = {
+               { "seek", 's', POPT_ARG_STRING, &seekarg, 0,
+                 "seek offset", "<offset>" },
+               { "blocksize", 'b', POPT_ARG_INT, &blocksize, 0,
+                 "filesystem blocksize", "<size>" },
+               { "verbose", 'v', POPT_ARG_NONE, &verbose, 0,
+                 "verbose", NULL },
+               POPT_AUTOHELP
+               POPT_TABLEEND,
+       };
+       const char *volname = NULL;
+       int ret = 0;
+
+       popt = poptGetContext(NULL, argc, argv, options, 0);
+       poptSetOtherOptionHelp(popt, "<volume>");
+       if (argc < 2)
+               goto usage;
+
+       int c;
+       while ((c = poptGetNextOpt(popt)) >= 0)
+               ;
+       if (c < -1)
+               goto badopt;
+
+       /* open volume, create superblock */
+       volname = poptGetArg(popt);
+       if (!volname)
+               goto usage;
+
+       fd_t fd = open(volname, O_RDWR, S_IRWXU);
+       u64 volsize = 0;
+       if (fdsize64(fd, &volsize))
+               error("fdsize64 failed for '%s' (%s)",
+                     volname, strerror(errno));
+
+       int blockbits = 12;
+       if (blocksize) {
+               blockbits = fls(blocksize) - 1;
+               if (1 << blockbits != blocksize)
+                       error("blocksize must be a power of two");
+       }
+
+       struct dev *dev = &(struct dev){
+               .fd     = fd,
+               .bits   = blockbits
+       };
+       init_buffers(dev, 1 << 20);
+
+       struct sb *sb = &(struct sb){ };
+       *sb = (struct sb){
+               .max_inodes_per_block   = 64,
+               .entries_per_node       = 20,
+               .devmap                 = new_map(dev, NULL),
+               .blockbits              = dev->bits,
+               .blocksize              = 1 << dev->bits,
+               .blockmask              = (1 << dev->bits) - 1,
+               .volblocks              = volsize >> dev->bits,
+               .freeblocks             = volsize >> dev->bits,
+               .itable = (struct btree){
+                       .sb                     = sb,
+                       .ops                    = &itable_ops,
+                       .entries_per_leaf       = 1 << (dev->bits - 6)
+               }
+       };
+
+       if ((errno = -load_sb(sb)))
+               goto eek;
+       if (!(sb->bitmap = new_inode(sb, 0)))
+               goto eek;
+       if (!(sb->rootdir = new_inode(sb, 0xd)))
+               goto eek;
+       if (!(sb->atable = new_inode(sb, 0xa)))
+               goto eek;
+       if ((errno = -open_inode(sb->bitmap)))
+               goto eek;
+       if ((errno = -open_inode(sb->rootdir)))
+               goto eek;
+       if ((errno = -open_inode(sb->atable)))
+               goto eek;
+
+       struct graph_info ginfo;
+       char filename[256];
+       FILE *file;
+       sprintf(filename, "%s.dot", volname);
+       file = fopen(filename, "w");
+       if (!file)
+               error("coundn't open: %s\n", filename);
+
+       ginfo.f = file;
+       fprintf(ginfo.f, "digraph tux3_g {\n");
+
+       ginfo.bname = "itable";
+       ginfo.lname = "ileaf";
+       draw_sb(&ginfo, sb);
+       draw_tree(&ginfo, &sb->itable, draw_ileaf);
+#if 0
+       ginfo.bname = "bitmap_dtree";
+       ginfo.lname = "dleaf";
+       draw_tree(&ginfo, &sb->bitmap->btree, draw_dleaf);
+       ginfo.bname = "rootdir_dtree";
+       ginfo.lname = "dleaf";
+       draw_tree(&ginfo, &sb->rootdir->btree, draw_dleaf);
+       ginfo.bname = "atable_dtree";
+       ginfo.lname = "dleaf";
+       draw_tree(&ginfo, &sb->atable->btree, draw_dleaf);
+#endif
+
+       fprintf(ginfo.f, "}\n");
+       fclose(ginfo.f);
+
+       free_inode(sb->bitmap);
+       free_inode(sb->rootdir);
+       free_inode(sb->atable);
+       free_map(sb->devmap);
+
+out:
+       /* damn, popt doesn't free str returned by poptGetArg() */
+       if (volname)
+               free((char *)volname);
+       poptFreeContext(popt);
+       return ret;
+
+eek:
+       fprintf(stderr, "%s!\n", strerror(errno));
+       ret = 1;
+       goto out;
+usage:
+       poptPrintUsage(popt, stderr, 0);
+       ret = 1;
+       goto out;
+badopt:
+       fprintf(stderr, "%s: %s\n", poptBadOption(popt, POPT_BADOPTION_NOALIAS),
+               poptStrerror(c));
+       ret = 1;
+       goto out;
+}
_

_______________________________________________
Tux3 mailing list
[email protected]
http://tux3.org/cgi-bin/mailman/listinfo/tux3

Reply via email to