diff --git a/f3probe.c b/f3probe.c index 21babb1..a197e75 100644 --- a/f3probe.c +++ b/f3probe.c @@ -1,4 +1,5 @@ #define _POSIX_C_SOURCE 200809L +#define _GNU_SOURCE #include #include @@ -51,6 +52,8 @@ static struct argp_option options[] = { "Reset method to use during the probe", 0}, {"time-ops", 't', NULL, 0, "Time reads, writes, and resets", 0}, + {"fix", 'i', NULL, 0, + "Run f3fix if counterfeit flash memory detected", 0}, { 0 } }; @@ -76,6 +79,7 @@ struct args { int block_order; int cache_order; int strict_cache; + bool fix; }; static error_t parse_opt(int key, char *arg, struct argp_state *state) @@ -167,7 +171,11 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) case 't': args->time_ops = true; break; - + + case 'i': + args->fix = true; + break; + case ARGP_KEY_INIT: args->filename = NULL; break; @@ -373,7 +381,9 @@ static int test_device(struct args *args) uint64_t read_count, read_time_us; uint64_t write_count, write_time_us; uint64_t reset_count, reset_time_us; + uint64_t last_good_sector; const char *final_dev_filename; + char *fix_cmd; dev = args->debug ? create_file_device(args->filename, args->real_size_byte, @@ -474,8 +484,9 @@ static int test_device(struct args *args) case FKTY_LIMBO: case FKTY_WRAPAROUND: case FKTY_CHAIN: { - uint64_t last_good_sector = (real_size_byte >> 9) - 1; + last_good_sector = (real_size_byte >> 9) - 1; assert(block_order >= 9); + assert(asprintf(&fix_cmd, "f3fix --last-sec=%" PRIu64 " %s", last_good_sector, final_dev_filename) > 0); printf("Bad news: The device `%s' is a counterfeit of type %s\n\n" "You can \"fix\" this device using the following command:\n" "f3fix --last-sec=%" PRIu64 " %s\n", @@ -507,6 +518,10 @@ static int test_device(struct args *args) report_ops("Reset", reset_count, reset_time_us); } + if (args->fix && fix_cmd) { + system(fix_cmd); + } + free(fix_cmd); free((void *)final_dev_filename); return fake_type == FKTY_GOOD ? 0 : 100 + fake_type; } @@ -545,6 +560,7 @@ int main(int argc, char **argv) .block_order = 0, .cache_order = -1, .strict_cache = false, + .fix = false, }; /* Read parameters. */ diff --git a/f3read.c b/f3read.c index 7537b2e..05f7059 100644 --- a/f3read.c +++ b/f3read.c @@ -40,6 +40,8 @@ static struct argp_option options[] = { "Maximum read rate", 0}, {"show-progress", 'p', "NUM", 0, "Show progress if NUM is not zero", 0}, + {"delete", 'd', NULL, 0, + "Delete corrupted NUM.h2w files", 0}, { 0 } }; @@ -48,6 +50,7 @@ struct args { long end_at; long max_read_rate; int show_progress; + bool delete; const char *dev_path; }; @@ -85,6 +88,10 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) args->show_progress = !!arg_to_long(state, arg); break; + case 'd': + args->delete = true; + break; + case ARGP_KEY_INIT: args->dev_path = NULL; break; @@ -340,7 +347,7 @@ static inline void pr_avg_speed(double speed) } static void iterate_files(const char *path, const long *files, - long start_at, long end_at, long max_read_rate, int progress) + long start_at, long end_at, long max_read_rate, int progress, bool delete) { uint64_t tot_ok, tot_corrupted, tot_changed, tot_overwritten, tot_size; int and_read_all = 1; @@ -379,6 +386,14 @@ static void iterate_files(const char *path, const long *files, tot_overwritten += stats.secs_overwritten; tot_size += stats.bytes_read; and_read_all = and_read_all && stats.read_all; + if (delete && (stats.secs_corrupted || tot_changed || tot_overwritten)) { + const char *filename; + char *full_fn = full_fn_from_number(&filename, path, *files); + assert(full_fn); + if (unlink(full_fn)) + err(errno, "Can't remove file %s\n", full_fn); + free(full_fn); + } files++; } assert(!gettimeofday(&t2, NULL)); @@ -428,6 +443,7 @@ int main(int argc, char **argv) .max_read_rate = 0, /* If stdout isn't a terminal, supress progress. */ .show_progress = isatty(STDOUT_FILENO), + .delete = false, }; /* Read parameters. */ @@ -437,7 +453,7 @@ int main(int argc, char **argv) files = ls_my_files(args.dev_path, args.start_at, args.end_at); iterate_files(args.dev_path, files, args.start_at, args.end_at, - args.max_read_rate, args.show_progress); + args.max_read_rate, args.show_progress, args.delete); free((void *)files); return 0; } diff --git a/f3write.c b/f3write.c index 20e30dc..a350d5e 100644 --- a/f3write.c +++ b/f3write.c @@ -39,6 +39,8 @@ static struct argp_option options[] = { "Maximum write rate", 0}, {"show-progress", 'p', "NUM", 0, "Show progress if NUM is not zero", 0}, + {"keep", 'k', 0, 0, + "Keep existing NUM.h2w files instead of removing them", 0}, { 0 } }; @@ -47,6 +49,7 @@ struct args { long end_at; long max_write_rate; int show_progress; + bool keep; const char *dev_path; }; @@ -84,6 +87,10 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) args->show_progress = !!arg_to_long(state, arg); break; + case 'k': + args->keep = true; + break; + case ARGP_KEY_INIT: args->dev_path = NULL; break; @@ -170,7 +177,7 @@ static int write_chunk(int fd, size_t chunk_size, uint64_t *poffset) /* Return true when disk is full. */ static int create_and_fill_file(const char *path, long number, size_t size, - int *phas_suggested_max_write_rate, struct flow *fw) + int *phas_suggested_max_write_rate, struct flow *fw, bool keep) { char *full_fn; const char *filename; @@ -184,16 +191,24 @@ static int create_and_fill_file(const char *path, long number, size_t size, /* Create the file. */ full_fn = full_fn_from_number(&filename, path, number); assert(full_fn); + printf("Creating file %s ... ", filename); fflush(stdout); - fd = open(full_fn, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR); + fd = open(full_fn, O_CREAT | O_WRONLY | O_EXCL, S_IRUSR | S_IWUSR); if (fd < 0) { if (errno == ENOSPC) { printf("No space left.\n"); free(full_fn); return true; } - err(errno, "Can't create file %s", full_fn); + if (errno == EEXIST) { + if (keep) { + printf("Skipped.\n"); + free(full_fn); + return false; + } + err(errno, "Unexpectedly found file %s, but option --keep is not in use", full_fn); + } } assert(fd >= 0); @@ -273,7 +288,7 @@ static int flush_chunk(const struct flow *fw, int fd) } static int fill_fs(const char *path, long start_at, long end_at, - long max_write_rate, int progress) + long max_write_rate, int progress, bool keep) { uint64_t free_space; struct flow fw; @@ -310,7 +325,7 @@ static int fill_fs(const char *path, long start_at, long end_at, assert(!gettimeofday(&t1, NULL)); for (i = start_at; i <= end_at; i++) if (create_and_fill_file(path, i, GIGABYTES, - &has_suggested_max_write_rate, &fw)) + &has_suggested_max_write_rate, &fw, keep)) break; assert(!gettimeofday(&t2, NULL)); @@ -360,6 +375,7 @@ int main(int argc, char **argv) .start_at = 0, .end_at = LONG_MAX - 1, .max_write_rate = 0, + .keep = false, /* If stdout isn't a terminal, supress progress. */ .show_progress = isatty(STDOUT_FILENO), }; @@ -368,8 +384,9 @@ int main(int argc, char **argv) argp_parse(&argp, argc, argv, 0, NULL, &args); print_header(stdout, "write"); - unlink_old_files(args.dev_path, args.start_at, args.end_at); + if(!args.keep) + unlink_old_files(args.dev_path, args.start_at, args.end_at); return fill_fs(args.dev_path, args.start_at, args.end_at, - args.max_write_rate, args.show_progress); + args.max_write_rate, args.show_progress, args.keep); }