1 /* Blue Sky: File Systems in the Cloud
3 * Copyright (C) 2009 The Regents of the University of California
4 * Written by Michael Vrable <mvrable@cs.ucsd.edu>
13 #include "bluesky-private.h"
15 /* Core filesystem: handling of regular files and caching of file data. */
17 /* Mark a given block dirty and make sure that data is faulted in so that it
18 * can be written to. */
19 void bluesky_block_touch(BlueSkyInode *inode, uint64_t i)
21 g_return_if_fail(i < inode->blocks->len);
22 BlueSkyBlock *block = &g_array_index(inode->blocks, BlueSkyBlock, i);
25 if (i < inode->blocks->len - 1) {
26 block_len = BLUESKY_BLOCK_SIZE;
28 block_len = inode->size - i * BLUESKY_BLOCK_SIZE;
31 switch (block->type) {
32 case BLUESKY_BLOCK_ZERO:
33 g_print("Allocating zero block of size %zd\n", block_len);
34 block->data = bluesky_string_new(g_malloc0(block_len), block_len);
36 case BLUESKY_BLOCK_REF:
37 bluesky_block_fetch(inode->fs, block);
38 g_assert(block->type == BLUESKY_BLOCK_CACHED);
40 case BLUESKY_BLOCK_CACHED:
41 case BLUESKY_BLOCK_DIRTY:
42 block->data = bluesky_string_dup(block->data);
46 block->type = BLUESKY_BLOCK_DIRTY;
49 /* Set the size of a file. This will truncate or extend the file as needed.
50 * Newly-allocated bytes are zeroed. */
51 void bluesky_file_truncate(BlueSkyInode *inode, uint64_t size)
53 g_return_if_fail(size <= BLUESKY_MAX_FILE_SIZE);
55 if (size == inode->size)
58 uint64_t blocks = (size + BLUESKY_BLOCK_SIZE - 1) / BLUESKY_BLOCK_SIZE;
60 if (blocks > inode->blocks->len) {
61 /* Need to add new blocks to the end of a file. New block structures
62 * are automatically zeroed, which initializes them to be pointers to
63 * zero blocks so we don't need to do any more work. */
64 g_array_set_size(inode->blocks, blocks);
65 } else if (blocks < inode->blocks->len) {
66 /* Delete blocks from a file. Must reclaim memory. */
67 for (guint i = inode->blocks->len; i < blocks; i++) {
68 BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock, i);
70 bluesky_string_unref(b->data);
72 g_array_set_size(inode->blocks, blocks);
75 /* Ensure the last block of the file is properly sized. If the block is
76 * extended, newly-added bytes must be zeroed. */
78 BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock,
81 if (b->type != BLUESKY_BLOCK_ZERO) {
82 bluesky_block_touch(inode, blocks - 1);
83 gsize old_size = b->data->len;
84 gsize new_size = size - (blocks - 1) * BLUESKY_BLOCK_SIZE;
86 bluesky_string_resize(b->data, new_size);
88 if (new_size > old_size) {
89 memset(&b->data->data[old_size], 0, new_size - old_size);
95 bluesky_inode_update_ctime(inode, 1);
98 void bluesky_file_write(BlueSkyInode *inode, uint64_t offset,
99 const char *data, gint len)
101 g_return_if_fail(inode->type == BLUESKY_REGULAR);
102 g_return_if_fail(offset < inode->size);
103 g_return_if_fail(len <= inode->size - offset);
109 uint64_t block_num = offset / BLUESKY_BLOCK_SIZE;
110 gint block_offset = offset % BLUESKY_BLOCK_SIZE;
111 gint bytes = MIN(BLUESKY_BLOCK_SIZE - block_offset, len);
113 bluesky_block_touch(inode, block_num);
114 BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock,
116 memcpy(&b->data->data[block_offset], data, bytes);
117 bluesky_block_flush(inode->fs, b);
124 bluesky_inode_update_ctime(inode, 1);
125 bluesky_inode_flush(inode->fs, inode);
128 void bluesky_file_read(BlueSkyInode *inode, uint64_t offset,
131 g_return_if_fail(inode->type == BLUESKY_REGULAR);
132 g_return_if_fail(offset < inode->size);
133 g_return_if_fail(len <= inode->size - offset);
136 uint64_t block_num = offset / BLUESKY_BLOCK_SIZE;
137 gint block_offset = offset % BLUESKY_BLOCK_SIZE;
138 gint bytes = MIN(BLUESKY_BLOCK_SIZE - block_offset, len);
140 BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock,
143 case BLUESKY_BLOCK_ZERO:
144 memset(buf, 0, bytes);
146 case BLUESKY_BLOCK_REF:
147 bluesky_block_fetch(inode->fs, b);
149 case BLUESKY_BLOCK_CACHED:
150 case BLUESKY_BLOCK_DIRTY:
151 memcpy(buf, &b->data->data[block_offset], bytes);
161 /* Read the given block from cloud-backed storage if the data is not already
163 void bluesky_block_fetch(BlueSkyFS *fs, BlueSkyBlock *block)
165 if (block->type != BLUESKY_BLOCK_REF)
168 BlueSkyRCStr *string = bluesky_store_get(fs->store, block->ref);
170 bluesky_string_unref(block->data);
171 block->data = string;
172 block->type = BLUESKY_BLOCK_CACHED;
175 /* Write the given block to cloud-backed storage and mark it clean. */
176 void bluesky_block_flush(BlueSkyFS *fs, BlueSkyBlock *block)
178 if (block->type != BLUESKY_BLOCK_DIRTY)
181 BlueSkyRCStr *data = block->data;
183 GChecksum *csum = g_checksum_new(G_CHECKSUM_SHA256);
184 g_checksum_update(csum, data->data, data->len);
185 gchar *name = g_strdup(g_checksum_get_string(csum));
187 bluesky_store_put(fs->store, name, data);
191 /* block->type = BLUESKY_BLOCK_CACHED; */
192 bluesky_string_unref(block->data);
194 block->type = BLUESKY_BLOCK_REF;
196 g_checksum_free(csum);
197 //bluesky_string_unref(data);