Jelajahi Sumber

Fixed issue with exhaustive + out-of-order powerloss testing

Unlike the heuristic based testing, exhaustive powerloss testing
effectively forks the current test and runs both the interrupted and
uninterrupted test states to completion. But emubd wasn't expecting
bd->cfg->powerloss_cb to return.

The fix here is to keep track to both the old+new out-of-order block
states and unrevert them if bd->cfg->powerloss_cb returns.

This may leak the temporary copy, but powerloss testing is already
inherently leaky.
Christopher Haster 1 tahun lalu
induk
melakukan
fc2aa3350c
1 mengubah file dengan 36 tambahan dan 8 penghapusan
  1. 36 8
      bd/lfs_emubd.c

+ 36 - 8
bd/lfs_emubd.c

@@ -217,15 +217,18 @@ static int lfs_emubd_powerloss(const struct lfs_config *cfg) {
     lfs_emubd_t *bd = cfg->context;
 
     // emulate out-of-order writes?
+    lfs_emubd_block_t *ooo_data = NULL;
     if (bd->cfg->powerloss_behavior == LFS_EMUBD_POWERLOSS_OOO
             && bd->ooo_block != -1) {
         // since writes between syncs are allowed to be out-of-order, it
         // shouldn't hurt to restore the first write on powerloss, right?
-        lfs_emubd_decblock(bd->blocks[bd->ooo_block]);
-        bd->blocks[bd->ooo_block] = bd->ooo_data;
+        ooo_data = bd->blocks[bd->ooo_block];
+        bd->blocks[bd->ooo_block] = lfs_emubd_incblock(bd->ooo_data);
 
         // mirror to disk file?
-        if (bd->disk && (bd->ooo_data || bd->cfg->erase_value != -1)) {
+        if (bd->disk
+                && (bd->blocks[bd->ooo_block]
+                    || bd->cfg->erase_value != -1)) {
             off_t res1 = lseek(bd->disk->fd,
                     (off_t)bd->ooo_block*bd->cfg->erase_size,
                     SEEK_SET);
@@ -234,22 +237,47 @@ static int lfs_emubd_powerloss(const struct lfs_config *cfg) {
             }
 
             ssize_t res2 = write(bd->disk->fd,
-                    (bd->ooo_data)
-                        ? bd->ooo_data->data
+                    (bd->blocks[bd->ooo_block])
+                        ? bd->blocks[bd->ooo_block]->data
                         : bd->disk->scratch,
                     bd->cfg->erase_size);
             if (res2 < 0) {
                 return -errno;
             }
         }
-
-        bd->ooo_block = -1;
-        bd->ooo_data = NULL;
     }
 
     // simulate power loss
     bd->cfg->powerloss_cb(bd->cfg->powerloss_data);
 
+    // if we continue, undo out-of-order write emulation
+    if (bd->cfg->powerloss_behavior == LFS_EMUBD_POWERLOSS_OOO
+            && bd->ooo_block != -1) {
+        lfs_emubd_decblock(bd->blocks[bd->ooo_block]);
+        bd->blocks[bd->ooo_block] = ooo_data;
+
+        // mirror to disk file?
+        if (bd->disk
+                && (bd->blocks[bd->ooo_block]
+                    || bd->cfg->erase_value != -1)) {
+            off_t res1 = lseek(bd->disk->fd,
+                    (off_t)bd->ooo_block*bd->cfg->erase_size,
+                    SEEK_SET);
+            if (res1 < 0) {
+                return -errno;
+            }
+
+            ssize_t res2 = write(bd->disk->fd,
+                    (bd->blocks[bd->ooo_block])
+                        ? bd->blocks[bd->ooo_block]->data
+                        : bd->disk->scratch,
+                    bd->cfg->erase_size);
+            if (res2 < 0) {
+                return -errno;
+            }
+        }
+    }
+
     return 0;
 }