Browse Source

Merge remote-tracking branch 'public/bug8031' into maint-0.2.4

Nick Mathewson 12 years ago
parent
commit
de7e99f8bb
2 changed files with 49 additions and 24 deletions
  1. 7 0
      changes/bug8031
  2. 42 24
      src/or/microdesc.c

+ 7 - 0
changes/bug8031

@@ -0,0 +1,7 @@
+  o Minor bugfixes:
+    - Use direct writes rather than stdio when building microdescriptor
+      caches, in an attempt to mitigate bug 8031, or at least make it
+      less common.
+    - Warn more aggressively when flushing microdescriptors to a
+      microdescriptor cache fails, in an attempt to mitegate bug 8031,
+      or at least make it more diagnosable.

+ 42 - 24
src/or/microdesc.c

@@ -71,7 +71,7 @@ HT_GENERATE(microdesc_map, microdesc_t, node,
  * *<b>annotation_len_out</b> to the number of bytes written as
  * *<b>annotation_len_out</b> to the number of bytes written as
  * annotations. */
  * annotations. */
 static ssize_t
 static ssize_t
-dump_microdescriptor(FILE *f, microdesc_t *md, size_t *annotation_len_out)
+dump_microdescriptor(int fd, microdesc_t *md, size_t *annotation_len_out)
 {
 {
   ssize_t r = 0;
   ssize_t r = 0;
   size_t written;
   size_t written;
@@ -81,10 +81,10 @@ dump_microdescriptor(FILE *f, microdesc_t *md, size_t *annotation_len_out)
     char annotation[ISO_TIME_LEN+32];
     char annotation[ISO_TIME_LEN+32];
     format_iso_time(buf, md->last_listed);
     format_iso_time(buf, md->last_listed);
     tor_snprintf(annotation, sizeof(annotation), "@last-listed %s\n", buf);
     tor_snprintf(annotation, sizeof(annotation), "@last-listed %s\n", buf);
-    if (fputs(annotation, f) < 0) {
+    if (write_all(fd, annotation, strlen(annotation), 0) < 0) {
       log_warn(LD_DIR,
       log_warn(LD_DIR,
                "Couldn't write microdescriptor annotation: %s",
                "Couldn't write microdescriptor annotation: %s",
-               strerror(ferror(f)));
+               strerror(errno));
       return -1;
       return -1;
     }
     }
     r += strlen(annotation);
     r += strlen(annotation);
@@ -93,13 +93,13 @@ dump_microdescriptor(FILE *f, microdesc_t *md, size_t *annotation_len_out)
     *annotation_len_out = 0;
     *annotation_len_out = 0;
   }
   }
 
 
-  md->off = (off_t) ftell(f);
-  written = fwrite(md->body, 1, md->bodylen, f);
+  md->off = tor_fd_getpos(fd);
+  written = write_all(fd, md->body, md->bodylen, 0);
   if (written != md->bodylen) {
   if (written != md->bodylen) {
     log_warn(LD_DIR,
     log_warn(LD_DIR,
              "Couldn't dump microdescriptor (wrote %lu out of %lu): %s",
              "Couldn't dump microdescriptor (wrote %lu out of %lu): %s",
              (unsigned long)written, (unsigned long)md->bodylen,
              (unsigned long)written, (unsigned long)md->bodylen,
-             strerror(ferror(f)));
+             strerror(errno));
     return -1;
     return -1;
   }
   }
   r += md->bodylen;
   r += md->bodylen;
@@ -198,15 +198,15 @@ microdescs_add_list_to_cache(microdesc_cache_t *cache,
 {
 {
   smartlist_t *added;
   smartlist_t *added;
   open_file_t *open_file = NULL;
   open_file_t *open_file = NULL;
-  FILE *f = NULL;
+  int fd = -1;
   //  int n_added = 0;
   //  int n_added = 0;
   ssize_t size = 0;
   ssize_t size = 0;
 
 
   if (where == SAVED_NOWHERE && !no_save) {
   if (where == SAVED_NOWHERE && !no_save) {
-    f = start_writing_to_stdio_file(cache->journal_fname,
-                                    OPEN_FLAGS_APPEND|O_BINARY,
-                                    0600, &open_file);
-    if (!f) {
+    fd = start_writing_to_file(cache->journal_fname,
+                               OPEN_FLAGS_APPEND|O_BINARY,
+                               0600, &open_file);
+    if (fd < 0) {
       log_warn(LD_DIR, "Couldn't append to journal in %s: %s",
       log_warn(LD_DIR, "Couldn't append to journal in %s: %s",
                cache->journal_fname, strerror(errno));
                cache->journal_fname, strerror(errno));
       return NULL;
       return NULL;
@@ -228,9 +228,9 @@ microdescs_add_list_to_cache(microdesc_cache_t *cache,
     }
     }
 
 
     /* Okay, it's a new one. */
     /* Okay, it's a new one. */
-    if (f) {
+    if (fd >= 0) {
       size_t annotation_len;
       size_t annotation_len;
-      size = dump_microdescriptor(f, md, &annotation_len);
+      size = dump_microdescriptor(fd, md, &annotation_len);
       if (size < 0) {
       if (size < 0) {
         /* we already warned in dump_microdescriptor */
         /* we already warned in dump_microdescriptor */
         abort_writing_to_file(open_file);
         abort_writing_to_file(open_file);
@@ -252,8 +252,14 @@ microdescs_add_list_to_cache(microdesc_cache_t *cache,
     cache->total_len_seen += md->bodylen;
     cache->total_len_seen += md->bodylen;
   } SMARTLIST_FOREACH_END(md);
   } SMARTLIST_FOREACH_END(md);
 
 
-  if (f)
-    finish_writing_to_file(open_file); /*XXX Check me.*/
+  if (fd >= 0) {
+    if (finish_writing_to_file(open_file) < 0) {
+      log_warn(LD_DIR, "Error appending to microdescriptor file: %s",
+               strerror(errno));
+      smartlist_clear(added);
+      return added;
+    }
+  }
 
 
   {
   {
     networkstatus_t *ns = networkstatus_get_latest_consensus();
     networkstatus_t *ns = networkstatus_get_latest_consensus();
@@ -406,11 +412,11 @@ int
 microdesc_cache_rebuild(microdesc_cache_t *cache, int force)
 microdesc_cache_rebuild(microdesc_cache_t *cache, int force)
 {
 {
   open_file_t *open_file;
   open_file_t *open_file;
-  FILE *f;
+  int fd = -1;
   microdesc_t **mdp;
   microdesc_t **mdp;
   smartlist_t *wrote;
   smartlist_t *wrote;
   ssize_t size;
   ssize_t size;
-  off_t off = 0;
+  off_t off = 0, off_real;
   int orig_size, new_size;
   int orig_size, new_size;
 
 
   if (cache == NULL) {
   if (cache == NULL) {
@@ -430,10 +436,10 @@ microdesc_cache_rebuild(microdesc_cache_t *cache, int force)
   orig_size = (int)(cache->cache_content ? cache->cache_content->size : 0);
   orig_size = (int)(cache->cache_content ? cache->cache_content->size : 0);
   orig_size += (int)cache->journal_len;
   orig_size += (int)cache->journal_len;
 
 
-  f = start_writing_to_stdio_file(cache->cache_fname,
-                                  OPEN_FLAGS_REPLACE|O_BINARY,
-                                  0600, &open_file);
-  if (!f)
+  fd = start_writing_to_file(cache->cache_fname,
+                             OPEN_FLAGS_REPLACE|O_BINARY,
+                             0600, &open_file);
+  if (fd < 0)
     return -1;
     return -1;
 
 
   wrote = smartlist_new();
   wrote = smartlist_new();
@@ -444,7 +450,7 @@ microdesc_cache_rebuild(microdesc_cache_t *cache, int force)
     if (md->no_save)
     if (md->no_save)
       continue;
       continue;
 
 
-    size = dump_microdescriptor(f, md, &annotation_len);
+    size = dump_microdescriptor(fd, md, &annotation_len);
     if (size < 0) {
     if (size < 0) {
       /* XXX handle errors from dump_microdescriptor() */
       /* XXX handle errors from dump_microdescriptor() */
       /* log?  return -1?  die?  coredump the universe? */
       /* log?  return -1?  die?  coredump the universe? */
@@ -453,6 +459,14 @@ microdesc_cache_rebuild(microdesc_cache_t *cache, int force)
     tor_assert(((size_t)size) == annotation_len + md->bodylen);
     tor_assert(((size_t)size) == annotation_len + md->bodylen);
     md->off = off + annotation_len;
     md->off = off + annotation_len;
     off += size;
     off += size;
+    off_real = tor_fd_getpos(fd);
+    if (off_real != off) {
+      log_warn(LD_BUG, "Discontinuity in position in microdescriptor cache."
+               "By my count, I'm at "I64_FORMAT
+               ", but I should be at "I64_FORMAT,
+               I64_PRINTF_ARG(off), I64_PRINTF_ARG(off_real));
+      off = off_real;
+    }
     if (md->saved_location != SAVED_IN_CACHE) {
     if (md->saved_location != SAVED_IN_CACHE) {
       tor_free(md->body);
       tor_free(md->body);
       md->saved_location = SAVED_IN_CACHE;
       md->saved_location = SAVED_IN_CACHE;
@@ -460,11 +474,15 @@ microdesc_cache_rebuild(microdesc_cache_t *cache, int force)
     smartlist_add(wrote, md);
     smartlist_add(wrote, md);
   }
   }
 
 
+  if (finish_writing_to_file(open_file) < 0) {
+    log_warn(LD_DIR, "Error rebuilding microdescriptor cache: %s",
+             strerror(errno));
+    return -1;
+  }
+
   if (cache->cache_content)
   if (cache->cache_content)
     tor_munmap_file(cache->cache_content);
     tor_munmap_file(cache->cache_content);
 
 
-  finish_writing_to_file(open_file); /*XXX Check me.*/
-
   cache->cache_content = tor_mmap_file(cache->cache_fname);
   cache->cache_content = tor_mmap_file(cache->cache_fname);
 
 
   if (!cache->cache_content && smartlist_len(wrote)) {
   if (!cache->cache_content && smartlist_len(wrote)) {