/* 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)
+ * can be written to.
+ *
+ * If preserve is set to false, this is a hint that the block is about to be
+ * entirely overwritten. In this case, a dirty block is made available but any
+ * prior contents might be lost. A value of preserve = TRUE is always safe. */
+void bluesky_block_touch(BlueSkyInode *inode, uint64_t i, gboolean preserve)
{
g_return_if_fail(i < inode->blocks->len);
BlueSkyBlock *block = &g_array_index(inode->blocks, BlueSkyBlock, i);
block->dirty = bluesky_string_new(g_malloc0(block_len), block_len);
break;
case BLUESKY_BLOCK_REF:
- // FIXME: locking on the cloudlog?
- bluesky_block_fetch(inode, block, NULL);
- bluesky_string_ref(block->ref->data);
- block->dirty = bluesky_string_dup(block->ref->data);
+ if (preserve) {
+ // FIXME: locking on the cloudlog?
+ bluesky_block_fetch(inode, block, NULL);
+ bluesky_string_ref(block->ref->data);
+ block->dirty = bluesky_string_dup(block->ref->data);
+ } else {
+ block->dirty = bluesky_string_new(g_malloc0(block_len), block_len);
+ }
break;
case BLUESKY_BLOCK_DIRTY:
block->dirty = bluesky_string_dup(block->dirty);
if (b->type != BLUESKY_BLOCK_ZERO
&& (b->type == BLUESKY_BLOCK_REF
|| b->dirty->len < BLUESKY_BLOCK_SIZE)) {
- bluesky_block_touch(inode, inode->blocks->len - 1);
+ bluesky_block_touch(inode, inode->blocks->len - 1, TRUE);
gsize old_size = b->dirty->len;
bluesky_string_resize(b->dirty, BLUESKY_BLOCK_SIZE);
memset(&b->dirty->data[old_size], 0,
blocks - 1);
if (b->type != BLUESKY_BLOCK_ZERO) {
- bluesky_block_touch(inode, blocks - 1);
+ bluesky_block_touch(inode, blocks - 1, TRUE);
gsize old_size = b->dirty->len;
gsize new_size = size - (blocks - 1) * BLUESKY_BLOCK_SIZE;
return;
// TODO: Optimization: If we are entirely overwriting a block we don't need
- // to fetch it frm storage first.
+ // to fetch it frm storage first. We don't yet handle the case where the
+ // partial last block of a file is entirely overwritten.
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);
+ gboolean preserve = TRUE;
+ if (block_offset == 0 && bytes == BLUESKY_BLOCK_SIZE) {
+ preserve = FALSE;
+ }
+ bluesky_block_touch(inode, block_num, preserve);
BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock,
block_num);
memcpy(&b->dirty->data[block_offset], data, bytes);