mirror of
https://github.com/AltraMayor/f3.git
synced 2025-09-19 03:58:55 -04:00
f3probe: probe with less resets
Of all three operations called on the flash drive being probed (i.e. reading blocks, writing blocks, and resetting the drive), the most time-consuming operation is reliably resetting the drive. This patch reduces the number of resets writing and reading more blocks.
This commit is contained in:
parent
312c9170e7
commit
a952fb7244
@ -229,13 +229,14 @@ static int unit_test(const char *filename)
|
|||||||
|
|
||||||
enum fake_type fake_type;
|
enum fake_type fake_type;
|
||||||
uint64_t real_size_byte, announced_size_byte;
|
uint64_t real_size_byte, announced_size_byte;
|
||||||
int wrap, block_order;
|
int wrap, block_order, max_probe_blocks;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
|
||||||
dev = create_file_device(filename, item->real_size_byte,
|
dev = create_file_device(filename, item->real_size_byte,
|
||||||
item->fake_size_byte, item->wrap, item->block_order,
|
item->fake_size_byte, item->wrap, item->block_order,
|
||||||
false);
|
false);
|
||||||
assert(dev);
|
assert(dev);
|
||||||
|
max_probe_blocks = probe_device_max_blocks(dev);
|
||||||
probe_device(dev, &real_size_byte, &announced_size_byte,
|
probe_device(dev, &real_size_byte, &announced_size_byte,
|
||||||
&wrap, &block_order);
|
&wrap, &block_order);
|
||||||
free_device(dev);
|
free_device(dev);
|
||||||
@ -254,7 +255,8 @@ static int unit_test(const char *filename)
|
|||||||
wrap == item->wrap &&
|
wrap == item->wrap &&
|
||||||
block_order == item->block_order) {
|
block_order == item->block_order) {
|
||||||
success++;
|
success++;
|
||||||
printf("\t\tPerfect!\n\n");
|
printf("\t\tPerfect!\tMax # of probed blocks: %i\n\n",
|
||||||
|
max_probe_blocks);
|
||||||
} else {
|
} else {
|
||||||
double ret_f_real = real_size_byte;
|
double ret_f_real = real_size_byte;
|
||||||
double ret_f_fake = announced_size_byte;
|
double ret_f_fake = announced_size_byte;
|
||||||
|
188
libprobe.c
188
libprobe.c
@ -725,6 +725,63 @@ static inline int equal_blk(struct device *dev, const char *b1, const char *b2)
|
|||||||
return !memcmp(b1, b2, dev_get_block_size(dev));
|
return !memcmp(b1, b2, dev_get_block_size(dev));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return true if @b1 and b2 are at most @tolerance_byte bytes different. */
|
||||||
|
static int similar_blk(struct device *dev, const char *b1, const char *b2,
|
||||||
|
int tolerance_byte)
|
||||||
|
{
|
||||||
|
const int block_size = dev_get_block_size(dev);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < block_size; i++) {
|
||||||
|
if (*b1 != *b2) {
|
||||||
|
tolerance_byte--;
|
||||||
|
if (tolerance_byte <= 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
b1++;
|
||||||
|
b2++;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if the block at @pos is damaged. */
|
||||||
|
static int test_block(struct device *dev,
|
||||||
|
const char *stamp_blk, char *probe_blk, uint64_t pos)
|
||||||
|
{
|
||||||
|
/* Write block. */
|
||||||
|
if (dev_write_block(dev, stamp_blk, pos) &&
|
||||||
|
dev_write_block(dev, stamp_blk, pos))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* Reset. */
|
||||||
|
if (dev_reset(dev) && dev_reset(dev))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test block.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (dev_read_block(dev, probe_blk, pos) &&
|
||||||
|
dev_read_block(dev, probe_blk, pos))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (equal_blk(dev, stamp_blk, probe_blk))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Save time with certainly damaged blocks. */
|
||||||
|
if (!similar_blk(dev, stamp_blk, probe_blk, 8)) {
|
||||||
|
/* The probe block is damaged. */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The probe block seems to be damaged.
|
||||||
|
* Trying a second time...
|
||||||
|
*/
|
||||||
|
return dev_write_and_reset(dev, stamp_blk, pos) ||
|
||||||
|
dev_read_block(dev, probe_blk, pos) ||
|
||||||
|
!equal_blk(dev, stamp_blk, probe_blk);
|
||||||
|
}
|
||||||
|
|
||||||
/* Minimum size of the memory chunk used to build flash drives.
|
/* Minimum size of the memory chunk used to build flash drives.
|
||||||
* It must be a power of two.
|
* It must be a power of two.
|
||||||
*/
|
*/
|
||||||
@ -766,61 +823,66 @@ static int search_wrap(struct device *dev,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return true if @b1 and b2 are at most @tolerance_byte bytes different. */
|
#define TEST_N_BLOCKS 1024
|
||||||
static int similar_blk(struct device *dev, const char *b1, const char *b2,
|
|
||||||
int tolerance_byte)
|
|
||||||
{
|
|
||||||
const int block_size = dev_get_block_size(dev);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < block_size; i++) {
|
static int write_test_blocks(struct device *dev, const char *stamp_blk,
|
||||||
if (*b1 != *b2) {
|
uint64_t left_pos, uint64_t right_pos,
|
||||||
tolerance_byte--;
|
uint64_t *pa, uint64_t *pb, uint64_t *pmax_idx)
|
||||||
if (tolerance_byte <= 0)
|
{
|
||||||
return false;
|
uint64_t pos = left_pos + 1;
|
||||||
}
|
uint64_t last_pos;
|
||||||
b1++;
|
|
||||||
b2++;
|
/* Find coeficients of function a*idx + b where idx <= max_idx. */
|
||||||
}
|
assert(left_pos < right_pos);
|
||||||
return true;
|
*pb = pos;
|
||||||
|
*pa = (right_pos - *pb) / TEST_N_BLOCKS;
|
||||||
|
*pa = !*pa ? 1ULL : *pa;
|
||||||
|
*pmax_idx = (right_pos - *pb) / *pa;
|
||||||
|
if (*pmax_idx >= TEST_N_BLOCKS)
|
||||||
|
*pmax_idx = TEST_N_BLOCKS - 1;
|
||||||
|
last_pos = *pa * *pmax_idx + *pb;
|
||||||
|
assert(last_pos <= right_pos);
|
||||||
|
|
||||||
|
/* Write test blocks. */
|
||||||
|
for (; pos <= last_pos; pos += *pa)
|
||||||
|
if (dev_write_block(dev, stamp_blk, pos) &&
|
||||||
|
dev_write_block(dev, stamp_blk, pos))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return true if the block @pos is damaged. */
|
/* Return true if the test block at @pos is damaged. */
|
||||||
static int test_block(struct device *dev,
|
static int test_test_block(struct device *dev,
|
||||||
const char *stamp_blk, char *probe_blk, uint64_t pos)
|
const char *stamp_blk, char *probe_blk, uint64_t pos)
|
||||||
{
|
{
|
||||||
/* Write block. */
|
|
||||||
if (dev_write_block(dev, stamp_blk, pos) &&
|
|
||||||
dev_write_block(dev, stamp_blk, pos))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
/* Reset. */
|
|
||||||
if (dev_reset(dev) && dev_reset(dev))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test block.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (dev_read_block(dev, probe_blk, pos) &&
|
if (dev_read_block(dev, probe_blk, pos) &&
|
||||||
dev_read_block(dev, probe_blk, pos))
|
dev_read_block(dev, probe_blk, pos))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (equal_blk(dev, stamp_blk, probe_blk))
|
return !equal_blk(dev, stamp_blk, probe_blk);
|
||||||
return false;
|
}
|
||||||
|
|
||||||
/* Save time with certainly damaged blocks. */
|
static int probe_test_blocks(struct device *dev,
|
||||||
if (!similar_blk(dev, stamp_blk, probe_blk, 8)) {
|
const char *stamp_blk, char *probe_blk,
|
||||||
/* The probe block is damaged. */
|
uint64_t *pleft_pos, uint64_t *pright_pos,
|
||||||
return true;
|
uint64_t a, uint64_t b, uint64_t max_idx)
|
||||||
|
{
|
||||||
|
/* Signed variables. */
|
||||||
|
int64_t left_idx = 0;
|
||||||
|
int64_t right_idx = max_idx;
|
||||||
|
int64_t idx = right_idx;
|
||||||
|
while (left_idx <= right_idx) {
|
||||||
|
uint64_t pos = a * idx + b;
|
||||||
|
if (test_test_block(dev, stamp_blk, probe_blk, pos)) {
|
||||||
|
right_idx = idx - 1;
|
||||||
|
*pright_pos = pos;
|
||||||
|
} else {
|
||||||
|
left_idx = idx + 1;
|
||||||
|
*pleft_pos = pos;
|
||||||
|
}
|
||||||
|
idx = (left_idx + right_idx) / 2;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
/* The probe block seems to be damaged.
|
|
||||||
* Trying a second time...
|
|
||||||
*/
|
|
||||||
return dev_write_and_reset(dev, stamp_blk, pos) ||
|
|
||||||
dev_read_block(dev, probe_blk, pos) ||
|
|
||||||
!equal_blk(dev, stamp_blk, probe_blk);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Caller must guarantee that the left bock is good, and written. */
|
/* Caller must guarantee that the left bock is good, and written. */
|
||||||
@ -828,15 +890,24 @@ static int search_edge(struct device *dev,
|
|||||||
uint64_t *pleft_pos, uint64_t right_pos,
|
uint64_t *pleft_pos, uint64_t right_pos,
|
||||||
const char *stamp_blk, char *probe_blk)
|
const char *stamp_blk, char *probe_blk)
|
||||||
{
|
{
|
||||||
uint64_t pos = right_pos;
|
uint64_t gap = right_pos - *pleft_pos;
|
||||||
do {
|
uint64_t prv_gap = gap + 1;
|
||||||
if (test_block(dev, stamp_blk, probe_blk, pos))
|
while (prv_gap > gap && gap >= 1) {
|
||||||
right_pos = pos;
|
uint64_t a, b, max_idx;
|
||||||
else
|
if (write_test_blocks(dev, stamp_blk, *pleft_pos, right_pos,
|
||||||
*pleft_pos = pos;
|
&a, &b, &max_idx))
|
||||||
pos = (*pleft_pos + right_pos) / 2;
|
return true;
|
||||||
} while (right_pos - *pleft_pos >= 2);
|
/* Reset. */
|
||||||
return false;
|
if (dev_reset(dev) && dev_reset(dev))
|
||||||
|
return true;
|
||||||
|
if (probe_test_blocks(dev, stamp_blk, probe_blk,
|
||||||
|
pleft_pos, &right_pos, a, b, max_idx))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
prv_gap = gap;
|
||||||
|
gap = right_pos - *pleft_pos;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX Write random data to make it harder for fake chips to become "smarter".
|
/* XXX Write random data to make it harder for fake chips to become "smarter".
|
||||||
@ -868,7 +939,16 @@ static int ceiling_log2(uint64_t x)
|
|||||||
|
|
||||||
int probe_device_max_blocks(struct device *dev)
|
int probe_device_max_blocks(struct device *dev)
|
||||||
{
|
{
|
||||||
return 4 * ceiling_log2(dev_get_size_byte(dev));
|
uint64_t num_blocks = dev_get_size_byte(dev) >>
|
||||||
|
dev_get_block_order(dev);
|
||||||
|
int num_blocks_order = ceiling_log2(num_blocks);
|
||||||
|
div_t div_num_passes = div(num_blocks_order, ilog2(TEST_N_BLOCKS));
|
||||||
|
int num_passes = div_num_passes.quot + (div_num_passes.rem ? 1 : 0);
|
||||||
|
return
|
||||||
|
/* search_wrap() */
|
||||||
|
1 +
|
||||||
|
/* Search_edge() */
|
||||||
|
num_passes * TEST_N_BLOCKS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX Properly handle read and write errors.
|
/* XXX Properly handle read and write errors.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user