From fe2b07cf3f79430f9b4d16a8d567ea9b6178d9d2 Mon Sep 17 00:00:00 2001 From: Michael Vrable Date: Thu, 3 Sep 2009 21:47:29 -0700 Subject: [PATCH] Split handling of file data out of inode.c. --- bluesky/CMakeLists.txt | 2 +- bluesky/file.c | 190 +++++++++++++++++++++++++++++++++++++++++ bluesky/inode.c | 175 ------------------------------------- 3 files changed, 191 insertions(+), 176 deletions(-) create mode 100644 bluesky/file.c diff --git a/bluesky/CMakeLists.txt b/bluesky/CMakeLists.txt index d576192..c4fe011 100644 --- a/bluesky/CMakeLists.txt +++ b/bluesky/CMakeLists.txt @@ -1,6 +1,6 @@ link_directories(/home/mvrable/scratch/libs3-1.4/build/lib) -add_library(bluesky SHARED crypto.c dir.c inode.c serialize.c store.c s3store.c) +add_library(bluesky SHARED crypto.c dir.c file.c inode.c serialize.c store.c s3store.c) add_executable(bluesky-test main.c) set(CMAKE_C_FLAGS "-std=gnu99 ${CMAKE_C_FLAGS}") diff --git a/bluesky/file.c b/bluesky/file.c new file mode 100644 index 0000000..5a4fe9b --- /dev/null +++ b/bluesky/file.c @@ -0,0 +1,190 @@ +/* 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: handling of regular files and caching of file data. */ + +/* 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 = bluesky_crypt_decrypt(string, fs->encryption_key); + block->type = BLUESKY_BLOCK_CACHED; + bluesky_string_unref(string); +} + +/* 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; + + BlueSkyRCStr *data = block->data; + data = bluesky_crypt_encrypt(data, fs->encryption_key); + + GChecksum *csum = g_checksum_new(G_CHECKSUM_SHA256); + g_checksum_update(csum, data->data, data->len); + gchar *name = g_strdup(g_checksum_get_string(csum)); + + g_print("Flushing block as %s\n", name); + s3store_put(fs->store, name, 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); + bluesky_string_unref(data); +} diff --git a/bluesky/inode.c b/bluesky/inode.c index e4902cd..d7d6c92 100644 --- a/bluesky/inode.c +++ b/bluesky/inode.c @@ -198,178 +198,3 @@ void bluesky_insert_inode(BlueSkyFS *fs, BlueSkyInode *inode) 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 = bluesky_crypt_decrypt(string, fs->encryption_key); - block->type = BLUESKY_BLOCK_CACHED; - bluesky_string_unref(string); -} - -/* 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; - - BlueSkyRCStr *data = block->data; - data = bluesky_crypt_encrypt(data, fs->encryption_key); - - GChecksum *csum = g_checksum_new(G_CHECKSUM_SHA256); - g_checksum_update(csum, data->data, data->len); - gchar *name = g_strdup(g_checksum_get_string(csum)); - - g_print("Flushing block as %s\n", name); - s3store_put(fs->store, name, 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); - bluesky_string_unref(data); -} -- 2.20.1