In-progress commit of online cleaner.
authorMichael Vrable <mvrable@cs.ucsd.edu>
Tue, 7 Dec 2010 05:40:30 +0000 (21:40 -0800)
committerMichael Vrable <mvrable@cs.ucsd.edu>
Tue, 7 Dec 2010 05:40:30 +0000 (21:40 -0800)
This adds some code to check the cleaner log when the proxy is launched,
but doesn't yet merge any data.

bluesky/CMakeLists.txt
bluesky/bluesky-private.h
bluesky/cleaner.c [new file with mode: 0644]
bluesky/cloudlog.c
bluesky/crypto.c
bluesky/imap.c
bluesky/inode.c
bluesky/log.c

index a3a58bc..f890b33 100644 (file)
@@ -3,9 +3,9 @@ include_directories("${LIBS3_BUILD_DIR}/include" ${KVSTORE_DIR})
 link_directories("${LIBS3_BUILD_DIR}/lib" ${KVSTORE_DIR})
 
 add_library(bluesky SHARED
-            cache.c cloudlog.c crc32c.c crypto.c debug.c dir.c file.c imap.c
-            init.c inode.c log.c serialize.c store.c store-bdb.c store-kv.cc
-            store-multi.c store-s3.c util.c)
+            cache.c cleaner.c cloudlog.c crc32c.c crypto.c debug.c dir.c file.c
+            imap.c init.c inode.c log.c serialize.c store.c store-bdb.c
+            store-kv.cc store-multi.c store-s3.c util.c)
 add_executable(bluesky-test main.c)
 
 set(CMAKE_C_FLAGS "-Wall -std=gnu99 ${CMAKE_C_FLAGS}")
index 20079da..adeb82e 100644 (file)
@@ -78,11 +78,13 @@ BlueSkyRCStr *bluesky_crypt_decrypt(BlueSkyRCStr *in, const uint8_t *key);
 void bluesky_crypt_block_encrypt(gchar *cloud_block, size_t len,
                                  BlueSkyCryptKeys *keys);
 gboolean bluesky_crypt_block_decrypt(gchar *cloud_block, size_t len,
-                                     BlueSkyCryptKeys *keys);
+                                     BlueSkyCryptKeys *keys,
+                                     gboolean allow_unauth);
 void bluesky_cloudlog_encrypt(GString *segment, BlueSkyCryptKeys *keys);
 void bluesky_cloudlog_decrypt(char *segment, size_t len,
                               BlueSkyCryptKeys *keys,
-                              BlueSkyRangeset *items);
+                              BlueSkyRangeset *items,
+                              gboolean allow_unauth);
 
 /* Storage layer.  Requests can be performed asynchronously, so these objects
  * help keep track of operations in progress. */
@@ -402,7 +404,8 @@ struct BlueSkyCacheFile {
     int disk_used;
     BlueSkyFS *fs;
     BlueSkyLog *log;
-    gboolean fetching, ready;   // Cloud data: downloading or ready for use
+    gboolean fetching;          // Cloud data: downloading or ready for use
+    gboolean complete;          // Complete file has been fetched from cloud
     int64_t atime;              // Access time, for cache management
     BlueSkyRangeset *items;     // Locations of valid items
     BlueSkyRangeset *prefetches;// Locations we have been requested to prefetch
@@ -469,6 +472,9 @@ void bluesky_inode_map_minimize(BlueSkyFS *fs);
 
 gboolean bluesky_checkpoint_load(BlueSkyFS *fs);
 
+/* Merging of log state with the work of the cleaner. */
+void bluesky_cleaner_find_checkpoint(BlueSkyFS *fs);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/bluesky/cleaner.c b/bluesky/cleaner.c
new file mode 100644 (file)
index 0000000..ca61d94
--- /dev/null
@@ -0,0 +1,68 @@
+/* Blue Sky: File Systems in the Cloud
+ *
+ * Copyright (C) 2010  The Regents of the University of California
+ * Written by Michael Vrable <mvrable@cs.ucsd.edu>
+ *
+ * TODO: Licensing
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <glib.h>
+#include <string.h>
+
+#include "bluesky-private.h"
+
+/* Proxy component of the file system cleaner.  This consists effectively of
+ * code for merging multiple versions of the file system logs: that generated
+ * by us and that generated by the in-cloud cleaner.  Other logic, such as for
+ * rewriting log segments where needed and deleting old segments, is handled by
+ * the in-cloud cleaner component. */
+
+/* Check the cleaner's logs to find the a more recent checkpoint record.  This
+ * should be called occasionally to see if the cleaner has done any work since
+ * our last check. */
+void bluesky_cleaner_find_checkpoint(BlueSkyFS *fs)
+{
+    char *prefix = g_strdup_printf("log-%08d", BLUESKY_CLOUD_DIR_CLEANER);
+    char *last_segment = bluesky_store_lookup_last(fs->store, prefix);
+    g_free(prefix);
+    if (last_segment == NULL)
+        return;
+
+    g_print("Last cloud log segment: %s\n", last_segment);
+    int seq = atoi(last_segment + 13);
+    g_free(last_segment);
+
+    if (seq <= fs->log_state->latest_cleaner_seq_seen)
+        return;
+
+    g_print("New log segment appeared in cleaner directory: %d\n", seq);
+
+    BlueSkyCacheFile *cachefile;
+    cachefile = bluesky_cachefile_lookup(fs, BLUESKY_CLOUD_DIR_CLEANER, seq,
+                                         TRUE);
+    while (!cachefile->complete)
+        g_cond_wait(cachefile->cond, cachefile->lock);
+
+    g_print("Downloaded latest cleaner segment.\n");
+
+    int64_t offset = -1, length = 0;
+    while (TRUE) {
+        const BlueSkyRangesetItem *item;
+        item = bluesky_rangeset_lookup_next(cachefile->items, offset + 1);
+        if (item == NULL)
+            break;
+        offset = item->start;
+        length = item->length;
+    }
+
+    if (length > 0) {
+        g_print("Last object: %"PRIu64" + %"PRIu64"\n", offset, length);
+    }
+
+    bluesky_cachefile_unref(cachefile);
+    g_mutex_unlock(cachefile->lock);
+}
index 64183b7..0570c5d 100644 (file)
@@ -558,10 +558,16 @@ void bluesky_cloudlog_encrypt(GString *segment, BlueSkyCryptKeys *keys)
 
 /* Make an decryption pass over a cloud log segment to decrypt items which were
  * encrypted.  Also computes a list of all offsets which at which valid
- * cloud log items are found and adds those offsets to items (if non-NULL). */
+ * cloud log items are found and adds those offsets to items (if non-NULL).
+ *
+ * If allow_unauth is set to true, then allow a limited set of unauthenticated
+ * items that may have been rewritten by a file system cleaner.  These include
+ * the checkpoint and inode map records only; other items must still pass
+ * authentication. */
 void bluesky_cloudlog_decrypt(char *segment, size_t len,
                               BlueSkyCryptKeys *keys,
-                              BlueSkyRangeset *items)
+                              BlueSkyRangeset *items,
+                              gboolean allow_unauth)
 {
     char *data = segment;
     size_t remaining_size = len;
@@ -575,7 +581,7 @@ void bluesky_cloudlog_decrypt(char *segment, size_t len,
                            + GUINT32_FROM_LE(header->size3);
         if (item_size > remaining_size)
             break;
-        if (bluesky_crypt_block_decrypt(data, item_size, keys)) {
+        if (bluesky_crypt_block_decrypt(data, item_size, keys, allow_unauth)) {
             if (items != NULL) {
                 if (bluesky_verbose)
                     g_print("  data item at %zx\n", offset);
index fd47491..b79cfa3 100644 (file)
@@ -185,7 +185,8 @@ void bluesky_crypt_block_encrypt(gchar *cloud_block, size_t len,
 }
 
 gboolean bluesky_crypt_block_decrypt(gchar *cloud_block, size_t len,
-                                     BlueSkyCryptKeys *keys)
+                                     BlueSkyCryptKeys *keys,
+                                     gboolean allow_unauth)
 {
     gcry_error_t status;
     uint8_t hmac_check[CRYPTO_HASH_SIZE];
@@ -209,8 +210,15 @@ gboolean bluesky_crypt_block_decrypt(gchar *cloud_block, size_t len,
                        keys->authentication_key,
                        hmac_check);
     if (memcmp(hmac_check, header->crypt_auth, CRYPTO_HASH_SIZE) != 0) {
-        g_warning("Cloud block HMAC does not match!\n");
-        return FALSE;
+        g_warning("Cloud block HMAC does not match!");
+        if (allow_unauth
+            && (header->type == LOGTYPE_INODE_MAP + '0'
+                || header->type == LOGTYPE_CHECKPOINT + '0'))
+        {
+            g_warning("Allowing unauthenticated data from cleaner");
+        } else {
+            return FALSE;
+        }
     }
 
     if (encrypted) {
index ef48e77..c50691e 100644 (file)
@@ -330,7 +330,7 @@ gboolean bluesky_checkpoint_load(BlueSkyFS *fs)
     }
 
     last = bluesky_string_dup(last);
-    bluesky_cloudlog_decrypt(last->data, last->len, fs->keys, NULL);
+    bluesky_cloudlog_decrypt(last->data, last->len, fs->keys, NULL, FALSE);
 
     /* Scan through the contents of the last log segment to find a checkpoint
      * record.  We need to do a linear scan since at this point we don't have a
index ae41d69..34af7de 100644 (file)
@@ -132,6 +132,8 @@ BlueSkyFS *bluesky_init_fs(gchar *name, BlueSkyStore *store,
         bluesky_inode_do_sync(root);
     }
 
+    bluesky_cleaner_find_checkpoint(fs);
+
     return fs;
 }
 
index 89d4258..3fb9ef0 100644 (file)
@@ -413,6 +413,7 @@ BlueSkyCacheFile *bluesky_cachefile_lookup(BlueSkyFS *fs,
         g_mutex_lock(map->lock);
         map->cond = g_cond_new();
         map->filename = g_strdup(logname);
+        map->log_dir = clouddir;
         map->log_seq = log_seq;
         map->log = log;
         g_atomic_int_set(&map->mapcount, 0);
@@ -480,11 +481,16 @@ static void cloudlog_partial_fetch_start(BlueSkyCacheFile *cachefile,
 static void cloudlog_partial_fetch_complete(BlueSkyStoreAsync *async,
                                             BlueSkyCacheFile *cachefile)
 {
-    g_print("Partial fetch of %s from cloud complete, status = %d\n",
+    g_print("Fetch of %s from cloud complete, status = %d\n",
             async->key, async->result);
 
     g_mutex_lock(cachefile->lock);
     if (async->result >= 0) {
+        if (async->len == 0) {
+            g_print("Complete object was fetched.\n");
+            cachefile->complete = TRUE;
+        }
+
         /* Descrypt items fetched and write valid items out to the local log,
          * but only if they do not overlap existing objects.  This will protect
          * against an attack by the cloud provider where one valid object is
@@ -493,9 +499,11 @@ static void cloudlog_partial_fetch_complete(BlueSkyStoreAsync *async,
         BlueSkyRangeset *items = bluesky_rangeset_new();
         int fd = openat(cachefile->log->dirfd, cachefile->filename, O_WRONLY);
         if (fd >= 0) {
+            gboolean allow_unauth;
             async->data = bluesky_string_dup(async->data);
+            allow_unauth = cachefile->log_dir == BLUESKY_CLOUD_DIR_CLEANER;
             bluesky_cloudlog_decrypt(async->data->data, async->data->len,
-                                     cachefile->fs->keys, items);
+                                     cachefile->fs->keys, items, allow_unauth);
             uint64_t item_offset = 0;
             while (TRUE) {
                 const BlueSkyRangesetItem *item;