HAMMER VFS - Use full-block undos for B-Tree nodes
authorMatthew Dillon <dillon@apollo.backplane.com>
Sat, 13 Oct 2012 17:03:03 +0000 (10:03 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Sat, 13 Oct 2012 17:03:03 +0000 (10:03 -0700)
* Use a full-block undos instead of small byte-range undos for
  B-Tree nodes.

  There is no bug here per-say, but we are trying to improve
  HAMMER's ability to recover after a power failure where a disk
  drive is writing to the platter at the time of the failure.
  While we have no control over any unrelated sectors that might
  get smashed by such an event, the concern is that sectors being
  specifically written might get corrupted beyond the ability for
  the byte-range undo to fix.

  The reason is that if, say, only 50 bytes in a B-Tree node need
  updating, HAMMER must still do a 16K physical write to disk, so
  really any portion of that 16K can wind up corrupt on a power
  failure, not just the 50 bytes being changed.

  So instead of writing a byte-ranged 50-byte UNDO we now write
  a 16K undo for B-Tree elements.

* The hope is that this will improve cases where HAMMER has become
  unmountable due to CRC errors in the B-Tree closer to the root of
  the B-Tree (which are usually updated to update only the mirror_tid)

Reported-by: sgeorge, marino
sys/vfs/hammer/hammer.h
sys/vfs/hammer/hammer_vfsops.c

index f837a07..a851422 100644 (file)
@@ -1057,6 +1057,7 @@ extern int hammer_verify_zone;
 extern int hammer_verify_data;
 extern int hammer_write_mode;
 extern int hammer_double_buffer;
+extern int hammer_btree_full_undo;
 extern int hammer_yield_check;
 extern int hammer_fsync_mode;
 extern int hammer_autoflush;
@@ -1575,10 +1576,16 @@ hammer_modify_node(hammer_transaction_t trans, hammer_node_t node,
                 (char *)base + len <=
                    (char *)node->ondisk + sizeof(*node->ondisk));
        KKASSERT((node->flags & HAMMER_NODE_CRCBAD) == 0);
-       hammer_modify_buffer(trans, node->buffer, base, len);
-       crcptr = &node->ondisk->crc;
-       hammer_modify_buffer(trans, node->buffer, crcptr, sizeof(hammer_crc_t));
-       --node->buffer->io.modify_refs; /* only want one ref */
+
+       if (hammer_btree_full_undo) {
+               hammer_modify_node_all(trans, node);
+       } else {
+               hammer_modify_buffer(trans, node->buffer, base, len);
+               crcptr = &node->ondisk->crc;
+               hammer_modify_buffer(trans, node->buffer,
+                                    crcptr, sizeof(hammer_crc_t));
+               --node->buffer->io.modify_refs; /* only want one ref */
+       }
 }
 
 /*
index 7090e25..a94111a 100644 (file)
@@ -112,6 +112,7 @@ int hammer_verify_zone;
 int hammer_verify_data = 1;
 int hammer_write_mode;
 int hammer_double_buffer;
+int hammer_btree_full_undo = 1;
 int hammer_yield_check = 16;
 int hammer_fsync_mode = 3;
 int64_t hammer_contention_count;
@@ -157,6 +158,9 @@ SYSCTL_INT(_vfs_hammer, OID_AUTO, cluster_enable, CTLFLAG_RW,
  * 0 - live dedup is disabled
  * 1 - dedup cache is populated on reads only
  * 2 - dedup cache is populated on both reads and writes
+ *
+ * LIVE_DEDUP IS DISABLED PERMANENTLY!  This feature appears to cause
+ * blockmap corruption over time so we've turned it off permanently.
  */
 SYSCTL_INT(_vfs_hammer, OID_AUTO, live_dedup, CTLFLAG_RD,
           &hammer_live_dedup, 0, "Enable live dedup (experimental)");
@@ -277,6 +281,8 @@ SYSCTL_INT(_vfs_hammer, OID_AUTO, write_mode, CTLFLAG_RW,
           &hammer_write_mode, 0, "");
 SYSCTL_INT(_vfs_hammer, OID_AUTO, double_buffer, CTLFLAG_RW,
           &hammer_double_buffer, 0, "");
+SYSCTL_INT(_vfs_hammer, OID_AUTO, btree_full_undo, CTLFLAG_RW,
+          &hammer_btree_full_undo, 0, "");
 SYSCTL_INT(_vfs_hammer, OID_AUTO, yield_check, CTLFLAG_RW,
           &hammer_yield_check, 0, "");
 SYSCTL_INT(_vfs_hammer, OID_AUTO, fsync_mode, CTLFLAG_RW,