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>
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);
24 switch (block->type) {
25 case BLUESKY_BLOCK_ZERO:
26 block->data = bluesky_string_new(g_malloc0(BLUESKY_BLOCK_SIZE),
29 case BLUESKY_BLOCK_REF:
30 bluesky_block_fetch(inode->fs, block);
31 g_assert(block->type == BLUESKY_BLOCK_CACHED);
33 case BLUESKY_BLOCK_CACHED:
34 case BLUESKY_BLOCK_DIRTY:
35 block->data = bluesky_string_dup(block->data);
39 block->type = BLUESKY_BLOCK_DIRTY;
42 /* Set the size of a file. This will truncate or extend the file as needed.
43 * Newly-allocated bytes are zeroed. */
44 void bluesky_file_truncate(BlueSkyInode *inode, uint64_t size)
46 g_return_if_fail(size <= BLUESKY_MAX_FILE_SIZE);
48 if (size == inode->size)
51 uint64_t blocks = (size + BLUESKY_BLOCK_SIZE - 1) / BLUESKY_BLOCK_SIZE;
53 if (blocks > inode->blocks->len) {
54 /* Need to add new blocks to the end of a file. New block structures
55 * are automatically zeroed, which initializes them to be pointers to
56 * zero blocks so we don't need to do any more work. */
57 g_array_set_size(inode->blocks, blocks);
58 } else if (blocks < inode->blocks->len) {
59 /* Delete blocks from a file. Must reclaim memory. */
60 for (guint i = inode->blocks->len; i < blocks; i++) {
61 BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock, i);
63 bluesky_string_unref(b->data);
65 g_array_set_size(inode->blocks, blocks);
68 /* If the file size is being decreased, ensure that any trailing data in
69 * the last block is zeroed. */
70 if (size < inode->size) {
71 BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock,
73 if (b->type != BLUESKY_BLOCK_ZERO) {
74 bluesky_block_touch(inode, blocks - 1);
75 int end_offset = size % BLUESKY_BLOCK_SIZE;
77 memset(&b->data->data[end_offset], 0,
78 BLUESKY_BLOCK_SIZE - end_offset);
84 bluesky_inode_update_ctime(inode, 1);
87 void bluesky_file_write(BlueSkyInode *inode, uint64_t offset,
88 const char *data, gint len)
90 g_print("Start write: %ld\n", bluesky_now_hires());
91 g_return_if_fail(inode->type == BLUESKY_REGULAR);
92 g_return_if_fail(offset < inode->size);
93 g_return_if_fail(len <= inode->size - offset);
99 uint64_t block_num = offset / BLUESKY_BLOCK_SIZE;
100 gint block_offset = offset % BLUESKY_BLOCK_SIZE;
101 gint bytes = MIN(BLUESKY_BLOCK_SIZE - block_offset, len);
103 bluesky_block_touch(inode, block_num);
104 BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock,
106 memcpy(&b->data->data[block_offset], data, bytes);
107 bluesky_block_flush(inode->fs, b);
114 bluesky_inode_update_ctime(inode, 1);
115 bluesky_inode_flush(inode->fs, inode);
116 g_print("End write: %ld\n", bluesky_now_hires());
119 void bluesky_file_read(BlueSkyInode *inode, uint64_t offset,
122 g_return_if_fail(inode->type == BLUESKY_REGULAR);
123 g_return_if_fail(offset < inode->size);
124 g_return_if_fail(len <= inode->size - offset);
127 uint64_t block_num = offset / BLUESKY_BLOCK_SIZE;
128 gint block_offset = offset % BLUESKY_BLOCK_SIZE;
129 gint bytes = MIN(BLUESKY_BLOCK_SIZE - block_offset, len);
131 BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock,
134 case BLUESKY_BLOCK_ZERO:
135 memset(buf, 0, bytes);
137 case BLUESKY_BLOCK_REF:
138 bluesky_block_fetch(inode->fs, b);
140 case BLUESKY_BLOCK_CACHED:
141 case BLUESKY_BLOCK_DIRTY:
142 memcpy(buf, &b->data->data[block_offset], bytes);
152 /* Read the given block from cloud-backed storage if the data is not already
154 void bluesky_block_fetch(BlueSkyFS *fs, BlueSkyBlock *block)
156 if (block->type != BLUESKY_BLOCK_REF)
159 g_print("Fetching block from %s\n", block->ref);
160 BlueSkyRCStr *string = bluesky_store_get(fs->store, block->ref);
162 bluesky_string_unref(block->data);
163 block->data = bluesky_crypt_decrypt(string, fs->encryption_key);
164 block->type = BLUESKY_BLOCK_CACHED;
165 bluesky_string_unref(string);
168 /* Write the given block to cloud-backed storage and mark it clean. */
169 void bluesky_block_flush(BlueSkyFS *fs, BlueSkyBlock *block)
171 if (block->type != BLUESKY_BLOCK_DIRTY)
174 BlueSkyRCStr *data = block->data;
175 data = bluesky_crypt_encrypt(data, fs->encryption_key);
177 GChecksum *csum = g_checksum_new(G_CHECKSUM_SHA256);
178 g_checksum_update(csum, data->data, data->len);
179 gchar *name = g_strdup(g_checksum_get_string(csum));
181 g_print("Flushing block as %s\n", name);
182 bluesky_store_put(fs->store, name, data);
186 /* block->type = BLUESKY_BLOCK_CACHED; */
187 bluesky_string_unref(block->data);
189 block->type = BLUESKY_BLOCK_REF;
191 g_checksum_free(csum);
192 bluesky_string_unref(data);