浏览代码

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 年之前
父节点
当前提交
fc2aa3350c
共有 1 个文件被更改,包括 36 次插入8 次删除
  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;
     lfs_emubd_t *bd = cfg->context;
 
 
     // emulate out-of-order writes?
     // emulate out-of-order writes?
+    lfs_emubd_block_t *ooo_data = NULL;
     if (bd->cfg->powerloss_behavior == LFS_EMUBD_POWERLOSS_OOO
     if (bd->cfg->powerloss_behavior == LFS_EMUBD_POWERLOSS_OOO
             && bd->ooo_block != -1) {
             && bd->ooo_block != -1) {
         // since writes between syncs are allowed to be out-of-order, it
         // since writes between syncs are allowed to be out-of-order, it
         // shouldn't hurt to restore the first write on powerloss, right?
         // 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?
         // 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 res1 = lseek(bd->disk->fd,
                     (off_t)bd->ooo_block*bd->cfg->erase_size,
                     (off_t)bd->ooo_block*bd->cfg->erase_size,
                     SEEK_SET);
                     SEEK_SET);
@@ -234,22 +237,47 @@ static int lfs_emubd_powerloss(const struct lfs_config *cfg) {
             }
             }
 
 
             ssize_t res2 = write(bd->disk->fd,
             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->disk->scratch,
                     bd->cfg->erase_size);
                     bd->cfg->erase_size);
             if (res2 < 0) {
             if (res2 < 0) {
                 return -errno;
                 return -errno;
             }
             }
         }
         }
-
-        bd->ooo_block = -1;
-        bd->ooo_data = NULL;
     }
     }
 
 
     // simulate power loss
     // simulate power loss
     bd->cfg->powerloss_cb(bd->cfg->powerloss_data);
     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;
     return 0;
 }
 }