Explorar o código

Readded support for mirror writes to a file in testbd

Before this was available implicitly by supporting both rambd and filebd
as backends, but now that testbd is a bit more complicated and no longer
maps directly to a block-device, this needs to be explicitly supported.
Christopher Haster %!s(int64=3) %!d(string=hai) anos
pai
achega
3f4f85986e
Modificáronse 3 ficheiros con 95 adicións e 50 borrados
  1. 84 42
      bd/lfs_testbd.c
  2. 7 8
      bd/lfs_testbd.h
  3. 4 0
      runners/test_runner.c

+ 84 - 42
bd/lfs_testbd.c

@@ -6,9 +6,17 @@
  * Copyright (c) 2017, Arm Limited. All rights reserved.
  * SPDX-License-Identifier: BSD-3-Clause
  */
+
 #include "bd/lfs_testbd.h"
 
 #include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
 
 
 // access to lazily-allocated/copy-on-write blocks
@@ -116,10 +124,41 @@ int lfs_testbd_createcfg(const struct lfs_config *cfg, const char *path,
 
     // setup testing things
     bd->power_cycles = bd->cfg->power_cycles;
+    bd->disk_fd = -1;
+    bd->disk_scratch_block = NULL;
+
     bd->branches = NULL;
     bd->branch_capacity = 0;
     bd->branch_count = 0;
 
+    if (bd->cfg->disk_path) {
+        #ifdef _WIN32
+        bd->disk_fd = open(bd->cfg->disk_path,
+                O_RDWR | O_CREAT | O_BINARY, 0666);
+        #else
+        bd->disk_fd = open(bd->cfg->disk_path,
+                O_RDWR | O_CREAT, 0666);
+        #endif
+        if (bd->disk_fd < 0) {
+            int err = -errno;
+            LFS_TESTBD_TRACE("lfs_testbd_create -> %d", err);
+            return err;
+        }
+
+        // if we're emulating erase values, we can keep a block around in
+        // memory of just the erase state to speed up emulated erases
+        if (bd->cfg->erase_value != -1) {
+            bd->disk_scratch_block = malloc(cfg->block_size);
+            if (!bd->disk_scratch_block) {
+                LFS_TESTBD_TRACE("lfs_testbd_createcfg -> %d", LFS_ERR_NOMEM);
+                return LFS_ERR_NOMEM;
+            }
+            memset(bd->disk_scratch_block,
+                    bd->cfg->erase_value,
+                    cfg->block_size);
+        }
+    }
+
     LFS_TESTBD_TRACE("lfs_testbd_createcfg -> %d", 0);
     return 0;
 }
@@ -154,54 +193,17 @@ int lfs_testbd_destroy(const struct lfs_config *cfg) {
     free(bd->blocks);
     free(bd->branches);
 
+    if (bd->disk_fd >= 0) {
+        close(bd->disk_fd);
+        free(bd->disk_scratch_block);
+    }
+
     LFS_TESTBD_TRACE("lfs_testbd_destroy -> %d", 0);
     return 0;
 }
 
 
 
-///// Internal mapping to block devices ///
-//static int lfs_testbd_rawread(const struct lfs_config *cfg, lfs_block_t block,
-//        lfs_off_t off, void *buffer, lfs_size_t size) {
-//    lfs_testbd_t *bd = cfg->context;
-//    if (bd->persist) {
-//        return lfs_filebd_read(cfg, block, off, buffer, size);
-//    } else {
-//        return lfs_rambd_read(cfg, block, off, buffer, size);
-//    }
-//}
-//
-//static int lfs_testbd_rawprog(const struct lfs_config *cfg, lfs_block_t block,
-//        lfs_off_t off, const void *buffer, lfs_size_t size) {
-//    lfs_testbd_t *bd = cfg->context;
-//    if (bd->persist) {
-//        return lfs_filebd_prog(cfg, block, off, buffer, size);
-//    } else {
-//        return lfs_rambd_prog(cfg, block, off, buffer, size);
-//    }
-//}
-//
-//static int lfs_testbd_rawerase(const struct lfs_config *cfg,
-//        lfs_block_t block) {
-//    lfs_testbd_t *bd = cfg->context;
-//    if (bd->persist) {
-//        return lfs_filebd_erase(cfg, block);
-//    } else {
-//        return lfs_rambd_erase(cfg, block);
-//    }
-//}
-//
-//static int lfs_testbd_rawsync(const struct lfs_config *cfg) {
-//    lfs_testbd_t *bd = cfg->context;
-//    if (bd->persist) {
-//        return lfs_filebd_sync(cfg);
-//    } else {
-//        return lfs_rambd_sync(cfg);
-//    }
-//}
-
-
-
 // block device API
 
 int lfs_testbd_read(const struct lfs_config *cfg, lfs_block_t block,
@@ -285,6 +287,25 @@ int lfs_testbd_prog(const struct lfs_config *cfg, lfs_block_t block,
     // prog data
     memcpy(&b->data[off], buffer, size);
 
+    // mirror to disk file?
+    if (bd->disk_fd >= 0) {
+        off_t res1 = lseek(bd->disk_fd,
+                (off_t)block*cfg->block_size + (off_t)off,
+                SEEK_SET);
+        if (res1 < 0) {
+            int err = -errno;
+            LFS_TESTBD_TRACE("lfs_testbd_prog -> %d", err);
+            return err;
+        }
+
+        ssize_t res2 = write(bd->disk_fd, buffer, size);
+        if (res2 < 0) {
+            int err = -errno;
+            LFS_TESTBD_TRACE("lfs_testbd_prog -> %d", err);
+            return err;
+        }
+    }
+
     // lose power?
     if (bd->power_cycles > 0) {
         bd->power_cycles -= 1;
@@ -342,6 +363,27 @@ int lfs_testbd_erase(const struct lfs_config *cfg, lfs_block_t block) {
     // emulate an erase value?
     if (bd->cfg->erase_value != -1) {
         memset(b->data, bd->cfg->erase_value, cfg->block_size);
+
+        // mirror to disk file?
+        if (bd->disk_fd >= 0) {
+            off_t res1 = lseek(bd->disk_fd,
+                    (off_t)block*cfg->block_size,
+                    SEEK_SET);
+            if (res1 < 0) {
+                int err = -errno;
+                LFS_TESTBD_TRACE("lfs_testbd_erase -> %d", err);
+                return err;
+            }
+
+            ssize_t res2 = write(bd->disk_fd,
+                    bd->disk_scratch_block,
+                    cfg->block_size);
+            if (res2 < 0) {
+                int err = -errno;
+                LFS_TESTBD_TRACE("lfs_testbd_erase -> %d", err);
+                return err;
+            }
+        }
     }
 
     // lose power?

+ 7 - 8
bd/lfs_testbd.h

@@ -90,14 +90,9 @@ struct lfs_testbd_config {
     // heavy memory usage!
     bool track_branches;
 
-//    // Optional buffer for RAM block device.
-//    void *buffer;
-//
-//    // Optional buffer for wear.
-//    void *wear_buffer;
-//
-//    // Optional buffer for scratch memory, needed when erase_value != -1.
-//    void *scratch_buffer;
+    // Path to file to use as a mirror of the disk. This provides a way to view
+    // the current state of the block device.
+    const char *disk_path;
 };
 
 // A reference counted block
@@ -112,7 +107,11 @@ typedef struct lfs_testbd_block {
 typedef struct lfs_testbd {
     // array of copy-on-write blocks
     lfs_testbd_block_t **blocks;
+
+    // some other test state
     uint32_t power_cycles;
+    int disk_fd;
+    uint8_t *disk_scratch_block;
 
     // array of tracked branches
     struct lfs_testbd *branches;

+ 4 - 0
runners/test_runner.c

@@ -610,6 +610,7 @@ static void run_powerloss_none(
         .erase_value        = ERASE_VALUE,
         .erase_cycles       = ERASE_CYCLES,
         .badblock_behavior  = BADBLOCK_BEHAVIOR,
+        .disk_path          = test_disk,
     };
 
     int err = lfs_testbd_createcfg(&cfg, test_disk, &bdcfg);
@@ -672,6 +673,7 @@ static void run_powerloss_linear(
         .erase_value        = ERASE_VALUE,
         .erase_cycles       = ERASE_CYCLES,
         .badblock_behavior  = BADBLOCK_BEHAVIOR,
+        .disk_path          = test_disk,
         .power_cycles       = i,
         .powerloss_behavior = POWERLOSS_BEHAVIOR,
         .powerloss_cb       = powerloss_longjmp,
@@ -748,6 +750,7 @@ static void run_powerloss_exponential(
         .erase_value        = ERASE_VALUE,
         .erase_cycles       = ERASE_CYCLES,
         .badblock_behavior  = BADBLOCK_BEHAVIOR,
+        .disk_path          = test_disk,
         .power_cycles       = i,
         .powerloss_behavior = POWERLOSS_BEHAVIOR,
         .powerloss_cb       = powerloss_longjmp,
@@ -822,6 +825,7 @@ static void run_powerloss_cycles(
         .erase_value        = ERASE_VALUE,
         .erase_cycles       = ERASE_CYCLES,
         .badblock_behavior  = BADBLOCK_BEHAVIOR,
+        .disk_path          = test_disk,
         .power_cycles       = (i < cycle_count) ? cycles[i] : 0,
         .powerloss_behavior = POWERLOSS_BEHAVIOR,
         .powerloss_cb       = powerloss_longjmp,