f3probe: implement probe_device()

This commit is contained in:
Michel Machado 2014-08-13 15:42:46 -04:00
parent 96f9995d50
commit b1fbd48675
2 changed files with 105 additions and 19 deletions

View File

@ -17,15 +17,16 @@
#include "libprobe.h"
static const char const *ftype_to_name[] = {
static const char const *ftype_to_name[FKTY_MAX] = {
[FKTY_GOOD] = "good",
[FKTY_BAD] = "bad",
[FKTY_LIMBO] = "limbo",
[FKTY_WRAPAROUND] = "wraparound",
[FKTY_MAX] = "max",
};
const char *fake_type_to_name(enum fake_type fake_type)
{
assert(fake_type < FKTY_MAX);
return ftype_to_name[fake_type];
}
@ -67,9 +68,6 @@ static int fdev_read_block(struct device *dev, char *buf, uint64_t block)
switch (fdev->fake_type) {
case FKTY_LIMBO:
if (offset >= GIGABYTE * fdev->file_size_gb) {
/* XXX Support different types of LIMBO.
* For example: all zeros, all ones, and random.
*/
memset(buf, 0, BLOCK_SIZE);
return 0;
}
@ -160,7 +158,6 @@ static void fdev_free(struct device *dev)
assert(!close(fdev->fd));
assert(!unlink(fdev->filename));
free((void *)fdev->filename);
fdev->filename = NULL;
}
/* XXX Validate parameters.
@ -197,7 +194,6 @@ struct device *create_file_device(const char *filename,
filename:
free((void *)fdev->filename);
fdev->filename = NULL;
fdev:
free(fdev);
error:
@ -313,26 +309,115 @@ static inline int dev_get_size_gb(struct device *dev)
return dev->get_size_gb(dev);
}
/* XXX Write random data for testing.
* There would be a random seed, and all the other blocks would be
* this seed XOR'd with the number of the test.
*/
static void fill_buffer(char *buf, int len, int signature)
{
memset(buf, signature, len);
}
static inline int equal_blk(const char *b1, const char *b2)
{
return !memcmp(b1, b2, BLOCK_SIZE);
}
static inline void *align_512(void *p)
{
uintptr_t ip = (uintptr_t)p;
return (void *)( (ip + 511) & ~511 );
}
/* XXX Don't write at the very beginning of the card to avoid
* losing the partition table.
* But write at a random locations to make harder for fake chips
* to become "smarter".
*/
/* XXX Write random data for testing.
* There would be a random seed, and all the other blocks would be
* this seed XOR'd with the number of the test.
*/
/* XXX Finish testing the last block, and the next one that should fail.
* Then report the last block, so user can create the largest partition.
*/
/* XXX Properly handle read and write errors. */
enum fake_type probe_device(struct device *dev, int *preal_size_gb)
{
char buf[BLOCK_SIZE];
int device_size_gb = dev_get_size_gb(dev);
char stack[511 + 3 * BLOCK_SIZE];
char *first_blk, *stamp_blk, *probe_blk;
const int step = GIGABYTE / BLOCK_SIZE;
uint64_t first_pos = 10;
uint64_t pos = first_pos + step;
int i;
/* TODO */
dev_read_block(dev, buf, 10);
dev_write_block(dev, buf, 10);
assert(device_size_gb > 0);
*preal_size_gb = dev_get_size_gb(dev);
/* Aligning these pointers is necessary to directly read and write
* the block device.
* For the file device, this is superfluous.
*/
first_blk = align_512(stack);
stamp_blk = first_blk + BLOCK_SIZE;
probe_blk = stamp_blk + BLOCK_SIZE;
/* Base case. */
fill_buffer(first_blk, BLOCK_SIZE, 1);
dev_write_block(dev, first_blk, first_pos);
dev_read_block(dev, probe_blk, first_pos);
if (!equal_blk(first_blk, probe_blk)) {
/* There is a block before the first 1GB that seems to
* be damaged. Trying a second time...
*/
dev_write_block(dev, first_blk, first_pos);
dev_read_block(dev, probe_blk, first_pos);
if (!equal_blk(first_blk, probe_blk)) {
/* Okay, this device is damaged. */
goto bad;
}
}
/* Inductive step. */
fill_buffer(stamp_blk, BLOCK_SIZE, 2);
for (i = 1; i < device_size_gb; i++) {
dev_write_block(dev, stamp_blk, pos);
dev_read_block(dev, probe_blk, first_pos);
if (!equal_blk(first_blk, probe_blk)) {
/* Wrapping around? */
if (equal_blk(stamp_blk, probe_blk)) {
/* yes. */
*preal_size_gb = i;
return FKTY_WRAPAROUND;
}
/* The block at @first_pos changed to a value
* different from the one written.
* Trying a second time...
*/
dev_write_block(dev, first_blk, first_pos);
dev_write_block(dev, stamp_blk, pos);
dev_read_block(dev, probe_blk, first_pos);
if (!equal_blk(first_blk, probe_blk)) {
if (equal_blk(stamp_blk, probe_blk)) {
*preal_size_gb = i;
return FKTY_WRAPAROUND;
}
/* Okay, this device is damaged. */
goto bad;
}
}
dev_read_block(dev, probe_blk, pos);
if (!equal_blk(stamp_blk, probe_blk)) {
*preal_size_gb = i;
return FKTY_LIMBO;
}
pos += step;
}
*preal_size_gb = device_size_gb;
return FKTY_GOOD;
bad:
*preal_size_gb = 0;
return FKTY_BAD;
}

View File

@ -2,9 +2,10 @@
#define HEADER_LIBPROBE_H
enum fake_type {
FKTY_GOOD,
FKTY_LIMBO,
FKTY_WRAPAROUND,
FKTY_GOOD, /* Device is good. */
FKTY_BAD, /* Device is at least partially damaged. */
FKTY_LIMBO, /* Device discards data after a given limit. */
FKTY_WRAPAROUND,/* Device overwrites data after a given limit. */
FKTY_MAX,
};