X-Git-Url: http://git.vrable.net/?a=blobdiff_plain;f=inode.c;fp=inode.c;h=0000000000000000000000000000000000000000;hb=70fdd2326239a9a5e02b3c3699d2588d5fee48fa;hp=7ea8dbf2af026b0e74f4235003f040b6bac303c8;hpb=e176f19a88257f6d8cca5c21dce012796806ffd8;p=bluesky.git diff --git a/inode.c b/inode.c deleted file mode 100644 index 7ea8dbf..0000000 --- a/inode.c +++ /dev/null @@ -1,355 +0,0 @@ -/* Blue Sky: File Systems in the Cloud - * - * Copyright (C) 2009 The Regents of the University of California - * Written by Michael Vrable - * - * TODO: Licensing - */ - -#include -#include -#include - -#include "bluesky.h" - -/* Core filesystem. Different proxies, such as the NFSv3 one, interface to - * this, but the core actually tracks the data which is stored. So far we just - * implement an in-memory filesystem, but eventually this will be state which - * is persisted to the cloud. */ - -/* Return the current time, in microseconds since the epoch. */ -int64_t bluesky_get_current_time() -{ - GTimeVal t; - g_get_current_time(&t); - return (int64_t)t.tv_sec * 1000000 + t.tv_usec; -} - -/* Update an inode to indicate that a modification was made. This increases - * the change counter, updates the ctime to the current time, and optionally - * updates the mtime. */ -void bluesky_inode_update_ctime(BlueSkyInode *inode, gboolean update_mtime) -{ - int64_t now = bluesky_get_current_time(); - inode->change_count++; - inode->ctime = now; - if (update_mtime) - inode->mtime = now; -} - -/* Compute the HMAC keyed-hash function using the given hash algorithm, data, - * and key. */ -void compute_hmac(GChecksumType algo, - const guchar *data, gsize data_len, - const guchar *key, gsize key_len, - guint8 *buffer, gsize *digest_len) -{ - int block_size; - - switch (algo) { - case G_CHECKSUM_MD5: - case G_CHECKSUM_SHA1: - case G_CHECKSUM_SHA256: - block_size = 64; - break; - default: - g_error("Unknown hash algorithm for HMAC: %d\n", algo); - } - - gsize digest_size = g_checksum_type_get_length(algo); - - guchar keybuf[block_size]; - memset(keybuf, 0, block_size); - memcpy(keybuf, key, MIN(block_size, key_len)); - for (int i = 0; i < block_size; i++) - keybuf[i] ^= 0x36; - - GChecksum *csum1 = g_checksum_new(algo); - g_checksum_update(csum1, keybuf, block_size); - g_checksum_update(csum1, data, data_len); - guint8 digest[digest_size]; - g_checksum_get_digest(csum1, digest, &digest_size); - - memset(keybuf, 0, block_size); - memcpy(keybuf, key, MIN(block_size, key_len)); - for (int i = 0; i < block_size; i++) - keybuf[i] ^= 0x5c; - - GChecksum *csum2 = g_checksum_new(algo); - g_checksum_update(csum2, keybuf, block_size); - g_checksum_update(csum2, digest, digest_size); - - g_checksum_get_digest(csum2, buffer, digest_len); - - g_checksum_free(csum1); - g_checksum_free(csum2); -} - -/* Unfortunately a glib hash table is only guaranteed to be able to store - * 32-bit keys if we use the key directly. If we want 64-bit inode numbers, - * we'll have to allocate memory to store the 64-bit inumber, and use a pointer - * to it. Rather than allocate the memory for the key, we'll just include a - * pointer to the 64-bit inum stored in the inode itself, so that we don't need - * to do any more memory management. */ -static guint bluesky_fs_key_hash_func(gconstpointer key) -{ - uint64_t inum = *(const uint64_t *)key; - return (guint)inum; -} - -static gboolean bluesky_fs_key_equal_func(gconstpointer a, gconstpointer b) -{ - uint64_t i1 = *(const uint64_t *)a; - uint64_t i2 = *(const uint64_t *)b; - return i1 == i2; -} - -/* Filesystem-level operations. A filesystem is like a directory tree that we - * are willing to export. */ -BlueSkyFS *bluesky_new_fs(gchar *name) -{ - BlueSkyFS *fs = g_new0(BlueSkyFS, 1); - fs->lock = g_mutex_new(); - fs->name = g_strdup(name); - fs->inodes = g_hash_table_new(bluesky_fs_key_hash_func, - bluesky_fs_key_equal_func); - fs->next_inum = BLUESKY_ROOT_INUM + 1; - fs->store = s3store_new(); - - return fs; -} - -/* Allocate a fresh inode number which has not been used before within a - * filesystem. */ -uint64_t bluesky_fs_alloc_inode(BlueSkyFS *fs) -{ - uint64_t inum; - - g_mutex_lock(fs->lock); - inum = fs->next_inum; - fs->next_inum++; - g_mutex_unlock(fs->lock); - - return inum; -} - -BlueSkyInode *bluesky_new_inode(uint64_t inum, BlueSkyFS *fs, - BlueSkyFileType type) -{ - BlueSkyInode *i = g_new0(BlueSkyInode, 1); - - i->lock = g_mutex_new(); - i->type = type; - i->fs = fs; - i->inum = inum; - - switch (type) { - case BLUESKY_REGULAR: - i->blocks = g_array_new(FALSE, TRUE, sizeof(BlueSkyBlock)); - break; - case BLUESKY_DIRECTORY: - i->dirents = g_sequence_new(bluesky_dirent_destroy); - i->dirhash = g_hash_table_new(g_str_hash, g_str_equal); - break; - case BLUESKY_BLOCK: - case BLUESKY_CHARACTER: - case BLUESKY_SYMLINK: - case BLUESKY_SOCKET: - case BLUESKY_FIFO: - break; - } - - return i; -} - -/* Retrieve an inode from the filesystem. Eventually this will be a cache and - * so we might need to go fetch the inode from elsewhere; for now all - * filesystem state is stored here. */ -BlueSkyInode *bluesky_get_inode(BlueSkyFS *fs, uint64_t inum) -{ - BlueSkyInode *inode = NULL; - - g_mutex_lock(fs->lock); - inode = (BlueSkyInode *)g_hash_table_lookup(fs->inodes, &inum); - g_mutex_unlock(fs->lock); - - return inode; -} - -/* Insert an inode into the filesystem inode cache. */ -void bluesky_insert_inode(BlueSkyFS *fs, BlueSkyInode *inode) -{ - g_mutex_lock(fs->lock); - g_hash_table_insert(fs->inodes, &inode->inum, inode); - g_mutex_unlock(fs->lock); -} - -/* Mark a given block dirty and make sure that data is faulted in so that it - * can be written to. */ -void bluesky_block_touch(BlueSkyInode *inode, uint64_t i) -{ - g_return_if_fail(i < inode->blocks->len); - BlueSkyBlock *block = &g_array_index(inode->blocks, BlueSkyBlock, i); - - switch (block->type) { - case BLUESKY_BLOCK_ZERO: - block->data = bluesky_string_new(g_malloc0(BLUESKY_BLOCK_SIZE), - BLUESKY_BLOCK_SIZE); - break; - case BLUESKY_BLOCK_REF: - bluesky_block_fetch(inode->fs, block); - g_assert(block->type == BLUESKY_BLOCK_CACHED); - /* Fall through */ - case BLUESKY_BLOCK_CACHED: - case BLUESKY_BLOCK_DIRTY: - block->data = bluesky_string_dup(block->data); - break; - } - - block->type = BLUESKY_BLOCK_DIRTY; -} - -/* Set the size of a file. This will truncate or extend the file as needed. - * Newly-allocated bytes are zeroed. */ -void bluesky_file_truncate(BlueSkyInode *inode, uint64_t size) -{ - g_return_if_fail(size <= BLUESKY_MAX_FILE_SIZE); - - if (size == inode->size) - return; - - uint64_t blocks = (size + BLUESKY_BLOCK_SIZE - 1) / BLUESKY_BLOCK_SIZE; - - if (blocks > inode->blocks->len) { - /* Need to add new blocks to the end of a file. New block structures - * are automatically zeroed, which initializes them to be pointers to - * zero blocks so we don't need to do any more work. */ - g_array_set_size(inode->blocks, blocks); - } else if (blocks < inode->blocks->len) { - /* Delete blocks from a file. Must reclaim memory. */ - for (guint i = inode->blocks->len; i < blocks; i++) { - BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock, i); - g_free(b->ref); - bluesky_string_unref(b->data); - } - g_array_set_size(inode->blocks, blocks); - } - - /* If the file size is being decreased, ensure that any trailing data in - * the last block is zeroed. */ - if (size < inode->size) { - BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock, - blocks - 1); - if (b->type != BLUESKY_BLOCK_ZERO) { - bluesky_block_touch(inode, blocks - 1); - int end_offset = size % BLUESKY_BLOCK_SIZE; - if (end_offset > 0) { - memset(&b->data->data[end_offset], 0, - BLUESKY_BLOCK_SIZE - end_offset); - } - } - } - - inode->size = size; - bluesky_inode_update_ctime(inode, 1); -} - -void bluesky_file_write(BlueSkyInode *inode, uint64_t offset, - const char *data, gint len) -{ - g_return_if_fail(inode->type == BLUESKY_REGULAR); - g_return_if_fail(offset < inode->size); - g_return_if_fail(len <= inode->size - offset); - - if (len == 0) - return; - - while (len > 0) { - uint64_t block_num = offset / BLUESKY_BLOCK_SIZE; - gint block_offset = offset % BLUESKY_BLOCK_SIZE; - gint bytes = MIN(BLUESKY_BLOCK_SIZE - block_offset, len); - - bluesky_block_touch(inode, block_num); - BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock, - block_num); - memcpy(&b->data->data[block_offset], data, bytes); - bluesky_block_flush(inode->fs, b); - - offset += bytes; - data += bytes; - len -= bytes; - } - - bluesky_inode_update_ctime(inode, 1); -} - -void bluesky_file_read(BlueSkyInode *inode, uint64_t offset, - char *buf, gint len) -{ - g_return_if_fail(inode->type == BLUESKY_REGULAR); - g_return_if_fail(offset < inode->size); - g_return_if_fail(len <= inode->size - offset); - - while (len > 0) { - uint64_t block_num = offset / BLUESKY_BLOCK_SIZE; - gint block_offset = offset % BLUESKY_BLOCK_SIZE; - gint bytes = MIN(BLUESKY_BLOCK_SIZE - block_offset, len); - - BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock, - block_num); - switch (b->type) { - case BLUESKY_BLOCK_ZERO: - memset(buf, 0, bytes); - break; - case BLUESKY_BLOCK_REF: - bluesky_block_fetch(inode->fs, b); - /* Fall through */ - case BLUESKY_BLOCK_CACHED: - case BLUESKY_BLOCK_DIRTY: - memcpy(buf, &b->data->data[block_offset], bytes); - break; - } - - offset += bytes; - buf += bytes; - len -= bytes; - } -} - -/* Read the given block from cloud-backed storage if the data is not already - * cached. */ -void bluesky_block_fetch(BlueSkyFS *fs, BlueSkyBlock *block) -{ - if (block->type != BLUESKY_BLOCK_REF) - return; - - g_print("Fetching block from %s\n", block->ref); - BlueSkyRCStr *string = s3store_get(fs->store, block->ref); - - bluesky_string_unref(block->data); - block->data = string; - block->type = BLUESKY_BLOCK_CACHED; -} - -/* Write the given block to cloud-backed storage and mark it clean. */ -void bluesky_block_flush(BlueSkyFS *fs, BlueSkyBlock *block) -{ - if (block->type != BLUESKY_BLOCK_DIRTY) - return; - - GChecksum *csum = g_checksum_new(G_CHECKSUM_SHA256); - g_checksum_update(csum, block->data->data, block->data->len); - gchar *name = g_strdup(g_checksum_get_string(csum)); - - g_print("Flushing block as %s\n", name); - s3store_put(fs->store, name, block->data); - g_free(block->ref); - block->ref = name; - - /* block->type = BLUESKY_BLOCK_CACHED; */ - bluesky_string_unref(block->data); - block->data = NULL; - block->type = BLUESKY_BLOCK_REF; - - g_checksum_free(csum); -}