Add filesystem superblock serialization.
authorMichael Vrable <mvrable@cs.ucsd.edu>
Thu, 29 Oct 2009 22:41:14 +0000 (15:41 -0700)
committerMichael Vrable <mvrable@cs.ucsd.edu>
Thu, 29 Oct 2009 22:41:14 +0000 (15:41 -0700)
Also fix deserialization of case-folded directory entries.  Together, these
chagnes should allow a filesystem state to be reloaded properly.

bluesky/bluesky.h
bluesky/dir.c
bluesky/inode.c
bluesky/serialize.c

index e141dd3..8eff412 100644 (file)
@@ -189,6 +189,9 @@ typedef struct {
 } BlueSkyBlock;
 
 BlueSkyFS *bluesky_new_fs(gchar *name);
+BlueSkyFS *bluesky_init_fs(gchar *name, BlueSkyStore *store);
+void bluesky_superblock_flush(BlueSkyFS *fs);
+
 int64_t bluesky_get_current_time();
 void bluesky_inode_update_ctime(BlueSkyInode *inode, gboolean update_mtime);
 uint64_t bluesky_fs_alloc_inode(BlueSkyFS *fs);
@@ -201,7 +204,7 @@ void bluesky_dirent_destroy(gpointer dirent);
 uint64_t bluesky_directory_hash(gchar *name);
 uint64_t bluesky_directory_lookup(BlueSkyInode *inode, gchar *name);
 uint64_t bluesky_directory_ilookup(BlueSkyInode *inode, gchar *name);
-gboolean bluesky_directory_insert(BlueSkyInode *dir, gchar *name,
+gboolean bluesky_directory_insert(BlueSkyInode *dir, const gchar *name,
                                   uint64_t inum);
 void bluesky_directory_dump(BlueSkyInode *dir);
 
@@ -216,6 +219,9 @@ void bluesky_file_read(BlueSkyInode *inode, uint64_t offset,
 
 void bluesky_inode_flush(BlueSkyFS *fs, BlueSkyInode *inode);
 void bluesky_inode_fetch(BlueSkyFS *fs, uint64_t inum);
+
+void bluesky_serialize_superblock(GString *out, BlueSkyFS *fs);
+BlueSkyFS *bluesky_deserialize_superblock(const gchar *buf);
 void bluesky_serialize_inode(GString *out, BlueSkyInode *inode);
 BlueSkyInode *bluesky_deserialize_inode(BlueSkyFS *fs, const gchar *buf);
 
index 82f3baa..cb3b23f 100644 (file)
@@ -69,7 +69,8 @@ uint64_t bluesky_directory_ilookup(BlueSkyInode *inode, gchar *name)
 
 /* Insert a new entry into a directory.  Should be called with the inode lock
  * already held. */
-gboolean bluesky_directory_insert(BlueSkyInode *dir, gchar *name, uint64_t inum)
+gboolean bluesky_directory_insert(BlueSkyInode *dir,
+                                  const gchar *name, uint64_t inum)
 {
     g_return_val_if_fail(dir->type == BLUESKY_DIRECTORY, FALSE);
 
index b62870d..cc4dc3c 100644 (file)
@@ -73,6 +73,36 @@ BlueSkyFS *bluesky_new_fs(gchar *name)
     return fs;
 }
 
+BlueSkyFS *bluesky_init_fs(gchar *name, BlueSkyStore *store)
+{
+    BlueSkyRCStr *data = bluesky_store_get(store, "superblock");
+    if (data != NULL) {
+        BlueSkyFS *fs = bluesky_deserialize_superblock(data->data);
+        if (fs != NULL) {
+            fs->store = store;
+            g_print("Loaded filesystem superblock\n");
+            g_free(fs->name);
+            fs->name = g_strdup(name);
+            return fs;
+        }
+    }
+
+    g_print("Initializing fresh filesystem\n");
+    BlueSkyFS *fs = bluesky_new_fs(name);
+    fs->store = store;
+
+    BlueSkyInode *root = bluesky_new_inode(BLUESKY_ROOT_INUM, fs,
+                                           BLUESKY_DIRECTORY);
+    root->nlink = 1;
+    root->mode = 0755;
+    bluesky_insert_inode(fs, root);
+
+    bluesky_inode_flush(fs, root);
+    bluesky_superblock_flush(fs);
+
+    return fs;
+}
+
 /* Inode reference counting. */
 void bluesky_inode_ref(BlueSkyInode *inode)
 {
@@ -96,6 +126,8 @@ uint64_t bluesky_fs_alloc_inode(BlueSkyFS *fs)
     inum = fs->next_inum;
     fs->next_inum++;
 
+    bluesky_superblock_flush(fs);
+
     return inum;
 }
 
@@ -191,3 +223,17 @@ void bluesky_inode_fetch(BlueSkyFS *fs, uint64_t inum)
         g_print("Loaded inode %"PRIu64"\n", inum);
     }
 }
+
+/* Synchronize filesystem superblock to stable storage. */
+void bluesky_superblock_flush(BlueSkyFS *fs)
+{
+    GString *buf = g_string_new("");
+    bluesky_serialize_superblock(buf, fs);
+
+    g_print("Syncing superblock...\n");
+
+    gsize len = buf->len;
+    BlueSkyRCStr *data = bluesky_string_new(g_string_free(buf, FALSE), len);
+    bluesky_store_put(fs->store, "superblock", data);
+}
+
index c806d88..7f7f041 100644 (file)
  * can be written to persistent storage.  All data is stored in little-endian
  * format. */
 
+/* Magic signature and structure of serialized superblocks. */
+
+#define SUPERBLOCK_MAGIC 0x65ca91e91b124234ULL
+
+struct serialized_superblock {
+    uint64_t signature;         /* SUPERBLOCK_MAGIC */
+    uint64_t next_inum;
+} __attribute__((packed));
+
 /* Magic signature for serialized inodes. */
 
 #define INODE_MAGIC 0xa6832100943d71e6ULL
@@ -35,6 +44,29 @@ struct serialized_inode {
     int64_t ntime;
 } __attribute__((packed));
 
+void bluesky_serialize_superblock(GString *out, BlueSkyFS *fs)
+{
+    struct serialized_superblock buf;
+
+    buf.signature = GUINT64_TO_LE(SUPERBLOCK_MAGIC);
+    buf.next_inum = GUINT64_TO_LE(fs->next_inum);
+
+    g_string_append_len(out, (gchar *)&buf, sizeof(buf));
+}
+
+BlueSkyFS *bluesky_deserialize_superblock(const gchar *buf)
+{
+    struct serialized_superblock *raw = (struct serialized_superblock *)buf;
+
+    if (GUINT64_FROM_LE(raw->signature) != SUPERBLOCK_MAGIC)
+        return NULL;
+
+    BlueSkyFS *fs = bluesky_new_fs("deserialized");
+    fs->next_inum = GUINT64_FROM_LE(raw->next_inum);
+
+    return fs;
+}
+
 void bluesky_serialize_inode(GString *out, BlueSkyInode *inode)
 {
     struct serialized_inode buf;
@@ -152,10 +184,13 @@ BlueSkyInode *bluesky_deserialize_inode(BlueSkyFS *fs, const gchar *buf)
             dirent->cookie = GUINT64_FROM_LE(d->seq);
             dirent->inum = GUINT64_FROM_LE(d->inum);
             dirent->name = g_strdup(d->name);
+            dirent->name_folded = bluesky_lowercase(d->name);
 
             g_sequence_insert_sorted(inode->dirents, dirent,
                                      bluesky_dirent_compare, NULL);
             g_hash_table_insert(inode->dirhash, dirent->name, dirent);
+            g_hash_table_insert(inode->dirhash_folded, dirent->name_folded,
+                                dirent);
 
             g_print("  dirent[%08x]: %s -> %"PRIu64"\n",
                     dirent->cookie, dirent->name, dirent->inum);