* list. (Work done by David Beattie)
*/
+#ifndef _GNU_SOURCE
#define _GNU_SOURCE /* for O_DIRECT */
+#endif
#ifndef O_LARGEFILE
#define O_LARGEFILE 0
#include "nls-enable.h"
const char * program_name = "badblocks";
-const char * done_string = N_("done \n");
+const char * done_string = N_("done \n");
static int v_flag = 0; /* verbose */
static int w_flag = 0; /* do r/w test: 0=no, 1=yes,
static blk_t currently_testing = 0;
static blk_t num_blocks = 0;
+static blk_t num_read_errors = 0;
+static blk_t num_write_errors = 0;
+static blk_t num_corruption_errors = 0;
static ext2_badblocks_list bb_list = NULL;
static FILE *out;
static blk_t next_bad = 0;
static ext2_badblocks_iterate bb_iter = NULL;
+enum error_types { READ_ERROR, WRITE_ERROR, CORRUPTION_ERROR };
+
static void *allocate_buffer(size_t size)
{
void *ret = 0;
* This routine reports a new bad block. If the bad block has already
* been seen before, then it returns 0; otherwise it returns 1.
*/
-static int bb_output (blk_t bad)
+static int bb_output (blk_t bad, enum error_types error_type)
{
errcode_t errcode;
position. This should not cause next_bad to change. */
if (bb_iter && bad < next_bad)
ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
+
+ if (error_type == READ_ERROR) {
+ num_read_errors++;
+ } else if (error_type == WRITE_ERROR) {
+ num_write_errors++;
+ } else if (error_type == CORRUPTION_ERROR) {
+ num_corruption_errors++;
+ }
return 1;
}
gettimeofday(&time_end, 0);
len = snprintf(line_buf, sizeof(line_buf),
- _("%6.2f%% done, %s elapsed"),
+ _("%6.2f%% done, %s elapsed. "
+ "(%d/%d/%d errors)"),
calc_percent((unsigned long) currently_testing,
(unsigned long) num_blocks),
- time_diff_format(&time_end, &time_start, diff_buf));
+ time_diff_format(&time_end, &time_start, diff_buf),
+ num_read_errors,
+ num_write_errors,
+ num_corruption_errors);
#ifdef HAVE_MBSTOWCS
len = mbstowcs(NULL, line_buf, sizeof(line_buf));
#endif
#define NANOSEC (1000000000L)
#define MILISEC (1000L)
+#if 0
+ printf("do_read: block %d, try %d\n", current_block, try);
+#endif
set_o_direct(dev, buffer, try * block_size,
((ext2_loff_t) current_block) * block_size);
{
long got;
+#if 0
+ printf("do_write: block %lu, try %d\n", current_block, try);
+#endif
set_o_direct(dev, buffer, try * block_size,
((ext2_loff_t) current_block) * block_size);
int got;
unsigned int bb_count = 0;
errcode_t errcode;
+ blk_t recover_block = ~0;
/* set up abend handler */
capture_terminate(NULL);
if (memcmp (blkbuf+i*block_size,
blkbuf+blocks_at_once*block_size,
block_size))
- bb_count += bb_output(currently_testing + i);
+ bb_count += bb_output(currently_testing + i, CORRUPTION_ERROR);
}
+ if (got == 0 && try == 1)
+ bb_count += bb_output(currently_testing++, READ_ERROR);
currently_testing += got;
- if (got == try) {
- try = blocks_at_once;
- /* recover page-aligned offset for O_DIRECT */
- if ( (blocks_at_once >= sys_page_size >> 9)
- && (currently_testing % (sys_page_size >> 9)!= 0))
- try -= (sys_page_size >> 9)
- - (currently_testing
- % (sys_page_size >> 9));
- continue;
- }
- else
+ if (got != try) {
try = 1;
- if (got == 0) {
- bb_count += bb_output(currently_testing++);
+ if (recover_block == ~0)
+ recover_block = currently_testing - got +
+ blocks_at_once;
+ continue;
+ } else if (currently_testing == recover_block) {
+ try = blocks_at_once;
+ recover_block = ~0;
}
}
num_blocks = 0;
const unsigned int *pattern;
int i, try, got, nr_pattern, pat_idx;
unsigned int bb_count = 0;
+ blk_t recover_block = ~0;
/* set up abend handler */
capture_terminate(NULL);
if (v_flag > 1)
print_status();
+ if (got == 0 && try == 1)
+ bb_count += bb_output(currently_testing++, WRITE_ERROR);
currently_testing += got;
- if (got == try) {
- try = blocks_at_once;
- /* recover page-aligned offset for O_DIRECT */
- if ( (blocks_at_once >= sys_page_size >> 9)
- && (currently_testing %
- (sys_page_size >> 9)!= 0))
- try -= (sys_page_size >> 9)
- - (currently_testing
- % (sys_page_size >> 9));
- continue;
- } else
+ if (got != try) {
try = 1;
- if (got == 0) {
- bb_count += bb_output(currently_testing++);
+ if (recover_block == ~0)
+ recover_block = currently_testing -
+ got + blocks_at_once;
+ continue;
+ } else if (currently_testing == recover_block) {
+ try = blocks_at_once;
+ recover_block = ~0;
}
}
try = last_block - currently_testing;
got = do_read (dev, read_buffer, try, block_size,
currently_testing);
- if (got == 0) {
- bb_count += bb_output(currently_testing++);
+ if (got == 0 && try == 1)
+ bb_count += bb_output(currently_testing++, READ_ERROR);
+ currently_testing += got;
+ if (got != try) {
+ try = 1;
+ if (recover_block == ~0)
+ recover_block = currently_testing -
+ got + blocks_at_once;
continue;
+ } else if (currently_testing == recover_block) {
+ try = blocks_at_once;
+ recover_block = ~0;
}
for (i=0; i < got; i++) {
if (memcmp(read_buffer + i * block_size,
buffer + i * block_size,
block_size))
- bb_count += bb_output(currently_testing+i);
+ bb_count += bb_output(currently_testing+i, CORRUPTION_ERROR);
}
- currently_testing += got;
- /* recover page-aligned offset for O_DIRECT */
- if ( (blocks_at_once >= sys_page_size >> 9)
- && (currently_testing % (sys_page_size >> 9)!= 0))
- try = blocks_at_once - (sys_page_size >> 9)
- - (currently_testing
- % (sys_page_size >> 9));
- else
- try = blocks_at_once;
if (v_flag > 1)
print_status();
}
errcode_t errcode;
unsigned long buf_used;
static unsigned int bb_count;
+ int granularity = blocks_at_once;
+ blk_t recover_block = ~0;
bb_count = 0;
errcode = ext2fs_badblocks_list_iterate_begin(bb_list,&bb_iter);
}
break;
}
- got = try = blocks_at_once - buf_used;
+ got = try = granularity - buf_used;
if (next_bad) {
if (currently_testing == next_bad) {
/* fprintf (out, "%lu\n", nextbad); */
got = do_read (dev, save_ptr, try, block_size,
currently_testing);
if (got == 0) {
+ if (recover_block == ~0)
+ recover_block = currently_testing +
+ blocks_at_once;
+ if (granularity != 1) {
+ granularity = 1;
+ continue;
+ }
/* First block must have been bad. */
- bb_count += bb_output(currently_testing++);
+ bb_count += bb_output(currently_testing++, READ_ERROR);
goto check_for_more;
}
save_ptr += got * block_size;
test_ptr += got * block_size;
currently_testing += got;
- if (got != try)
- bb_count += bb_output(currently_testing++);
+ if (got != try) {
+ try = 1;
+ if (recover_block == ~0)
+ recover_block = currently_testing -
+ got + blocks_at_once;
+ continue;
+ }
check_for_more:
/*
* around, and we're not done yet testing the disk, go
* back and get some more blocks.
*/
- if ((buf_used != blocks_at_once) &&
+ if ((buf_used != granularity) &&
(currently_testing < last_block))
continue;
+ if (currently_testing >= recover_block) {
+ granularity = blocks_at_once;
+ recover_block = ~0;
+ }
+
flush_bufs();
save_currently_testing = currently_testing;
for (i = 0; i < got; ++i)
if (memcmp (test_ptr+i*block_size,
read_ptr+i*block_size, block_size))
- bb_count += bb_output(currently_testing + i);
+ bb_count += bb_output(currently_testing + i, CORRUPTION_ERROR);
if (got < try) {
- bb_count += bb_output(currently_testing + got);
+ bb_count += bb_output(currently_testing + got, READ_ERROR);
got++;
}
FILE * in = NULL;
int block_size = 1024;
unsigned int blocks_at_once = 64;
- blk_t last_block, first_block;
+ blk64_t last_block, first_block;
int num_passes = 0;
int passes_clean = 0;
int dev;
usage();
device_name = argv[optind++];
if (optind > argc - 1) {
- errcode = ext2fs_get_device_size(device_name,
+ errcode = ext2fs_get_device_size2(device_name,
block_size,
&last_block);
if (errcode == EXT2_ET_UNIMPLEMENTED) {
if (v_flag)
fprintf(stderr,
- _("Pass completed, %u bad blocks found.\n"),
- bb_count);
+ _("Pass completed, %u bad blocks found. (%d/%d/%d errors)\n"),
+ bb_count, num_read_errors, num_write_errors, num_corruption_errors);
} while (passes_clean < num_passes);
free(t_patts);
return 0;
}
-