mirror of
https://github.com/AltraMayor/f3.git
synced 2025-08-03 18:46:00 -04:00
f3probe/f3brew: add cache to the model
F3 users have identified fake flashes that reserve a portion of their good memory to use as a permanent cache. This patch adds this feature to our model in order to allow us to develop a new probe algorithm to deal with it.
This commit is contained in:
parent
57fded9501
commit
3f0efeb12f
24
f3brew.c
24
f3brew.c
@ -33,6 +33,10 @@ static struct argp_option options[] = {
|
||||
"Wrap parameter of the emulated drive", 0},
|
||||
{"debug-block-order", 'b', "ORDER", OPTION_HIDDEN,
|
||||
"Block size of the emulated drive is 2^ORDER Bytes", 0},
|
||||
{"debug-cache-order", 'c', "ORDER", OPTION_HIDDEN,
|
||||
"Cache size of the emulated drive is 2^ORDER blocks", 0},
|
||||
{"debug-strict-cache", 'o', NULL, OPTION_HIDDEN,
|
||||
"Force the cache to be strict", 0},
|
||||
{"debug-keep-file", 'k', NULL, OPTION_HIDDEN,
|
||||
"Don't remove file used for emulating the drive", 0},
|
||||
{"reset-type", 's', "TYPE", 0,
|
||||
@ -66,6 +70,8 @@ struct args {
|
||||
uint64_t fake_size_byte;
|
||||
int wrap;
|
||||
int block_order;
|
||||
int cache_order;
|
||||
int strict_cache;
|
||||
|
||||
/* What to do. */
|
||||
uint64_t first_block;
|
||||
@ -118,6 +124,20 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state)
|
||||
args->debug = true;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
ll = arg_to_ll_bytes(state, arg);
|
||||
if (ll < -1 || ll > 64)
|
||||
argp_error(state,
|
||||
"Cache order must be in the interval [-1, 64]");
|
||||
args->cache_order = ll;
|
||||
args->debug = true;
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
args->strict_cache = true;
|
||||
args->debug = true;
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
args->keep_file = true;
|
||||
args->debug = true;
|
||||
@ -384,6 +404,8 @@ int main(int argc, char **argv)
|
||||
.fake_size_byte = 1ULL << 34,
|
||||
.wrap = 31,
|
||||
.block_order = 0,
|
||||
.cache_order = -1,
|
||||
.strict_cache = false,
|
||||
.first_block = 0,
|
||||
.last_block = -1ULL,
|
||||
};
|
||||
@ -397,7 +419,7 @@ int main(int argc, char **argv)
|
||||
dev = args.debug
|
||||
? create_file_device(args.filename, args.real_size_byte,
|
||||
args.fake_size_byte, args.wrap, args.block_order,
|
||||
args.keep_file)
|
||||
args.cache_order, args.strict_cache, args.keep_file)
|
||||
: create_block_device(args.filename, args.reset_type);
|
||||
if (!dev) {
|
||||
fprintf(stderr, "\nApplication cannot continue, finishing...\n");
|
||||
|
54
f3probe.c
54
f3probe.c
@ -35,6 +35,10 @@ static struct argp_option options[] = {
|
||||
"Wrap parameter of the emulated drive", 0},
|
||||
{"debug-block-order", 'b', "ORDER", OPTION_HIDDEN,
|
||||
"Block size of the emulated drive is 2^ORDER Bytes", 0},
|
||||
{"debug-cache-order", 'c', "ORDER", OPTION_HIDDEN,
|
||||
"Cache size of the emulated drive is 2^ORDER blocks", 0},
|
||||
{"debug-strict-cache", 'o', NULL, OPTION_HIDDEN,
|
||||
"Force the cache to be strict", 0},
|
||||
{"debug-keep-file", 'k', NULL, OPTION_HIDDEN,
|
||||
"Don't remove file used for emulating the drive", 0},
|
||||
{"debug-unit-test", 'u', NULL, OPTION_HIDDEN,
|
||||
@ -70,6 +74,8 @@ struct args {
|
||||
uint64_t fake_size_byte;
|
||||
int wrap;
|
||||
int block_order;
|
||||
int cache_order;
|
||||
int strict_cache;
|
||||
};
|
||||
|
||||
static error_t parse_opt(int key, char *arg, struct argp_state *state)
|
||||
@ -118,6 +124,20 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state)
|
||||
args->debug = true;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
ll = arg_to_ll_bytes(state, arg);
|
||||
if (ll < -1 || ll > 64)
|
||||
argp_error(state,
|
||||
"Cache order must be in the interval [-1, 64]");
|
||||
args->cache_order = ll;
|
||||
args->debug = true;
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
args->strict_cache = true;
|
||||
args->debug = true;
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
args->keep_file = true;
|
||||
args->debug = true;
|
||||
@ -184,29 +204,43 @@ struct unit_test_item {
|
||||
uint64_t fake_size_byte;
|
||||
int wrap;
|
||||
int block_order;
|
||||
int cache_order;
|
||||
int strict_cache;
|
||||
};
|
||||
|
||||
static const struct unit_test_item ftype_to_params[] = {
|
||||
/* Smallest good drive. */
|
||||
{1ULL << 20, 1ULL << 20, 20, 9},
|
||||
{1ULL << 21, 1ULL << 21, 21, 9, -1, false},
|
||||
|
||||
/* Good, 4KB-block, 1GB drive. */
|
||||
{1ULL << 30, 1ULL << 30, 30, 12},
|
||||
{1ULL << 30, 1ULL << 30, 30, 12, -1, false},
|
||||
|
||||
/* Bad drive. */
|
||||
{0, 1ULL << 30, 30, 9},
|
||||
{0, 1ULL << 30, 30, 9, -1, false},
|
||||
|
||||
/* Geometry of a real limbo drive. */
|
||||
{1777645568ULL, 32505331712ULL, 35, 9},
|
||||
{1777645568ULL, 32505331712ULL, 35, 9, -1, false},
|
||||
|
||||
/* Wraparound drive. */
|
||||
{1ULL << 31, 1ULL << 34, 31, 9},
|
||||
{1ULL << 31, 1ULL << 34, 31, 9, -1, false},
|
||||
|
||||
/* Chain drive. */
|
||||
{1ULL << 31, 1ULL << 34, 32, 9},
|
||||
{1ULL << 31, 1ULL << 34, 32, 9, -1, false},
|
||||
|
||||
/* Extreme case for memory usage (limbo drive). */
|
||||
{1ULL << 20, 1ULL << 40, 40, 9},
|
||||
{(1ULL<<20)+512,1ULL << 40, 40, 9, -1, false},
|
||||
|
||||
/* Geomerty of a real limbo drive with 256MB of strict cache. */
|
||||
{7600799744ULL, 67108864000ULL, 36, 9, 19, true},
|
||||
|
||||
/* The drive before with a non-strict cache. */
|
||||
{7600799744ULL, 67108864000ULL, 36, 9, 19, false},
|
||||
|
||||
/* The devil drive I. */
|
||||
{0, 1ULL << 40, 40, 9, 21, true},
|
||||
|
||||
/* The devil drive II. */
|
||||
{0, 1ULL << 40, 40, 9, 21, false},
|
||||
};
|
||||
|
||||
#define UNIT_TEST_N_CASES \
|
||||
@ -232,7 +266,7 @@ static int unit_test(const char *filename)
|
||||
|
||||
dev = create_file_device(filename, item->real_size_byte,
|
||||
item->fake_size_byte, item->wrap, item->block_order,
|
||||
false);
|
||||
item->cache_order, item->strict_cache, false);
|
||||
assert(dev);
|
||||
max_probe_blocks = probe_device_max_blocks(dev);
|
||||
assert(!probe_device(dev, &real_size_byte, &announced_size_byte,
|
||||
@ -314,7 +348,7 @@ static int test_device(struct args *args)
|
||||
dev = args->debug
|
||||
? create_file_device(args->filename, args->real_size_byte,
|
||||
args->fake_size_byte, args->wrap, args->block_order,
|
||||
args->keep_file)
|
||||
args->cache_order, args->strict_cache, args->keep_file)
|
||||
: create_block_device(args->filename, args->reset_type);
|
||||
if (!dev) {
|
||||
fprintf(stderr, "\nApplication cannot continue, finishing...\n");
|
||||
@ -448,6 +482,8 @@ int main(int argc, char **argv)
|
||||
.fake_size_byte = 1ULL << 34,
|
||||
.wrap = 31,
|
||||
.block_order = 0,
|
||||
.cache_order = -1,
|
||||
.strict_cache = false,
|
||||
};
|
||||
|
||||
/* Read parameters. */
|
||||
|
73
libdevs.c
73
libdevs.c
@ -154,6 +154,9 @@ struct file_device {
|
||||
int fd;
|
||||
uint64_t real_size_byte;
|
||||
uint64_t address_mask;
|
||||
uint64_t cache_mask;
|
||||
uint64_t *cache_entries;
|
||||
char *cache_blocks;
|
||||
};
|
||||
|
||||
static inline struct file_device *dev_fdev(struct device *dev)
|
||||
@ -170,7 +173,22 @@ static int fdev_read_block(struct device *dev, char *buf, int length,
|
||||
|
||||
offset &= fdev->address_mask;
|
||||
if (offset >= fdev->real_size_byte) {
|
||||
memset(buf, 0, length);
|
||||
int block_order;
|
||||
uint64_t cache_pos;
|
||||
|
||||
if (!fdev->cache_blocks)
|
||||
goto no_block; /* No cache available. */
|
||||
|
||||
block_order = dev_get_block_order(&fdev->dev);
|
||||
cache_pos = (offset >> block_order) & fdev->cache_mask;
|
||||
assert(length == (1LL << block_order));
|
||||
|
||||
if (fdev->cache_entries &&
|
||||
fdev->cache_entries[cache_pos] != offset)
|
||||
goto no_block;
|
||||
|
||||
memmove(buf, &fdev->cache_blocks[cache_pos << block_order],
|
||||
length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -193,6 +211,10 @@ static int fdev_read_block(struct device *dev, char *buf, int length,
|
||||
} while (done < length);
|
||||
|
||||
return 0;
|
||||
|
||||
no_block:
|
||||
memset(buf, 0, length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_all(int fd, const char *buf, int count)
|
||||
@ -216,8 +238,24 @@ static int fdev_write_block(struct device *dev, const char *buf, int length,
|
||||
off_t off_ret;
|
||||
|
||||
offset &= fdev->address_mask;
|
||||
if (offset >= fdev->real_size_byte)
|
||||
if (offset >= fdev->real_size_byte) {
|
||||
/* Block beyond real memory. */
|
||||
int block_order;
|
||||
uint64_t cache_pos;
|
||||
|
||||
if (!fdev->cache_blocks)
|
||||
return 0; /* No cache available. */
|
||||
block_order = dev_get_block_order(&fdev->dev);
|
||||
cache_pos = (offset >> block_order) & fdev->cache_mask;
|
||||
assert(length == (1LL << block_order));
|
||||
memmove(&fdev->cache_blocks[cache_pos << block_order],
|
||||
buf, length);
|
||||
|
||||
if (fdev->cache_entries)
|
||||
fdev->cache_entries[cache_pos] = offset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
off_ret = lseek(fdev->fd, offset, SEEK_SET);
|
||||
if (off_ret < 0)
|
||||
@ -230,6 +268,8 @@ static int fdev_write_block(struct device *dev, const char *buf, int length,
|
||||
static void fdev_free(struct device *dev)
|
||||
{
|
||||
struct file_device *fdev = dev_fdev(dev);
|
||||
free(fdev->cache_blocks);
|
||||
free(fdev->cache_entries);
|
||||
free((void *)fdev->filename);
|
||||
assert(!close(fdev->fd));
|
||||
}
|
||||
@ -241,7 +281,8 @@ static const char *fdev_get_filename(struct device *dev)
|
||||
|
||||
struct device *create_file_device(const char *filename,
|
||||
uint64_t real_size_byte, uint64_t fake_size_byte, int wrap,
|
||||
int block_order, int keep_file)
|
||||
int block_order, int cache_order, int strict_cache,
|
||||
int keep_file)
|
||||
{
|
||||
struct file_device *fdev;
|
||||
|
||||
@ -253,10 +294,29 @@ struct device *create_file_device(const char *filename,
|
||||
if (!fdev->filename)
|
||||
goto fdev;
|
||||
|
||||
fdev->cache_mask = 0;
|
||||
fdev->cache_entries = NULL;
|
||||
fdev->cache_blocks = NULL;
|
||||
if (cache_order >= 0) {
|
||||
fdev->cache_mask = (((uint64_t)1) << cache_order) - 1;
|
||||
if (strict_cache) {
|
||||
size_t size = sizeof(*fdev->cache_entries) <<
|
||||
cache_order;
|
||||
fdev->cache_entries = malloc(size);
|
||||
if (!fdev->cache_entries)
|
||||
goto cache;
|
||||
memset(fdev->cache_entries, 0, size);
|
||||
}
|
||||
fdev->cache_blocks = malloc(((uint64_t)1) <<
|
||||
(cache_order + block_order));
|
||||
if (!fdev->cache_blocks)
|
||||
goto cache;
|
||||
}
|
||||
|
||||
fdev->fd = open(filename, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
|
||||
if (fdev->fd < 0) {
|
||||
err(errno, "Can't create file `%s'", filename);
|
||||
goto filename;
|
||||
goto cache;
|
||||
}
|
||||
if (!keep_file) {
|
||||
/* Unlinking the file now guarantees that it won't exist if
|
||||
@ -294,7 +354,10 @@ keep_file:
|
||||
if (keep_file)
|
||||
unlink(filename);
|
||||
assert(!close(fdev->fd));
|
||||
filename:
|
||||
cache:
|
||||
free(fdev->cache_blocks);
|
||||
free(fdev->cache_entries);
|
||||
/* filename: this label is not being used. */
|
||||
free((void *)fdev->filename);
|
||||
fdev:
|
||||
free(fdev);
|
||||
|
@ -68,7 +68,8 @@ static inline int dev_write_and_reset(struct device *dev, const char *buf,
|
||||
|
||||
struct device *create_file_device(const char *filename,
|
||||
uint64_t real_size_byte, uint64_t fake_size_byte, int wrap,
|
||||
int block_order, int keep_file);
|
||||
int block_order, int cache_order, int strict_cache,
|
||||
int keep_file);
|
||||
|
||||
/* XXX Add support for block devices backed by SCSI and ATA. */
|
||||
enum reset_type {
|
||||
|
Loading…
x
Reference in New Issue
Block a user