} 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);
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);
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);
/* 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);
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)
{
inum = fs->next_inum;
fs->next_inum++;
+ bluesky_superblock_flush(fs);
+
return 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);
+}
+
* 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
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;
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);