diff options
author | Theodore Ts'o <tytso@mit.edu> | 2011-02-18 01:19:05 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2011-02-18 01:19:05 -0500 |
commit | 175d43beada4f5c971fa4b495380620644705282 (patch) | |
tree | b09fe4bec67a401f05b8789bf2783d774273dda5 /misc | |
parent | 616f68bf773440d6b6af4fb91c5cde6f74e5e659 (diff) | |
parent | 468d82f430dfdf270b738e14345b879560c2cd9e (diff) | |
download | e2fsprogs-175d43beada4f5c971fa4b495380620644705282.tar.gz |
Merge branch 'maint' into next
Diffstat (limited to 'misc')
-rw-r--r-- | misc/badblocks.8.in | 5 | ||||
-rw-r--r-- | misc/badblocks.c | 136 |
2 files changed, 96 insertions, 45 deletions
diff --git a/misc/badblocks.8.in b/misc/badblocks.8.in index f256c0ee..a5042e07 100644 --- a/misc/badblocks.8.in +++ b/misc/badblocks.8.in @@ -5,7 +5,7 @@ badblocks \- search a device for bad blocks .SH SYNOPSIS .B badblocks [ -.B \-svwnf +.B \-svwnfBX ] [ .B \-b @@ -195,6 +195,9 @@ This option may not be combined with the .B \-n option, as they are mutually exclusive. .TP +.B \-B +Use buffered I/O and do not use Direct I/O, even if it is available. +.TP .B \-X Internal flag only to be used by .BR e2fsck (8) diff --git a/misc/badblocks.c b/misc/badblocks.c index 549a3398..32ff3b2e 100644 --- a/misc/badblocks.c +++ b/misc/badblocks.c @@ -74,6 +74,7 @@ static int t_flag = 0; /* number of test patterns */ static int t_max = 0; /* allocated test patterns */ static unsigned int *t_patts = NULL; /* test patterns */ static int current_O_DIRECT = 0; /* Current status of O_DIRECT flag */ +static int use_buffered_io = 0; static int exclusive_ok = 0; static unsigned int max_bb = 0; /* Abort test if more than this number of bad blocks has been encountered */ static unsigned int d_flag = 0; /* delay factor between reads */ @@ -257,16 +258,21 @@ static void uncapture_terminate(void) signal (SIGUSR2, SIG_DFL); } +/* Linux requires that O_DIRECT I/Os be 512-byte sector aligned */ + +#define O_DIRECT_SIZE 512 + static void set_o_direct(int dev, unsigned char *buffer, size_t size, - blk_t current_block) + ext2_loff_t offset) { #ifdef O_DIRECT int new_flag = O_DIRECT; int flag; - if ((((unsigned long) buffer & (sys_page_size - 1)) != 0) || + if ((use_buffered_io != 0) || + (((unsigned long) buffer & (sys_page_size - 1)) != 0) || ((size & (sys_page_size - 1)) != 0) || - ((current_block & ((sys_page_size >> 9)-1)) != 0)) + ((offset & (O_DIRECT_SIZE - 1)) != 0)) new_flag = 0; if (new_flag != current_O_DIRECT) { @@ -331,7 +337,11 @@ static int do_read (int dev, unsigned char * buffer, int try, int block_size, #define NANOSEC (1000000000L) #define MILISEC (1000L) - set_o_direct(dev, buffer, try * block_size, current_block); +#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); if (v_flag > 1) print_status(); @@ -400,7 +410,11 @@ static int do_write(int dev, unsigned char * buffer, int try, int block_size, { long got; - set_o_direct(dev, buffer, try * block_size, current_block); +#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); if (v_flag > 1) print_status(); @@ -426,6 +440,10 @@ static void flush_bufs(void) { errcode_t retval; +#ifdef O_DIRECT + if (!use_buffered_io) + return; +#endif retval = ext2fs_sync_device(host_dev, 1); if (retval) com_err(program_name, retval, _("during ext2fs_sync_device")); @@ -440,6 +458,7 @@ static unsigned int test_ro (int dev, blk_t last_block, int got; unsigned int bb_count = 0; errcode_t errcode; + blk_t recover_block = ~0; /* set up abend handler */ capture_terminate(NULL); @@ -514,21 +533,18 @@ static unsigned int test_ro (int dev, blk_t last_block, block_size)) bb_count += bb_output(currently_testing + i); } + if (got == 0 && try == 1) + bb_count += bb_output(currently_testing++); 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; @@ -555,6 +571,7 @@ static unsigned int test_rw (int dev, blk_t last_block, 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); @@ -606,21 +623,18 @@ static unsigned int test_rw (int dev, blk_t last_block, if (v_flag > 1) print_status(); + if (got == 0 && try == 1) + bb_count += bb_output(currently_testing++); 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; } } @@ -648,9 +662,18 @@ static unsigned int test_rw (int dev, blk_t last_block, try = last_block - currently_testing; got = do_read (dev, read_buffer, try, block_size, currently_testing); - if (got == 0) { + if (got == 0 && try == 1) bb_count += bb_output(currently_testing++); + 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, @@ -659,14 +682,16 @@ static unsigned int test_rw (int dev, blk_t last_block, bb_count += bb_output(currently_testing+i); } 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 + if (got != try) { + try = 1; + if (!recover_block) + recover_block = currently_testing - + got + blocks_at_once; + continue; + } else if (currently_testing == recover_block) { try = blocks_at_once; + recover_block = 0; + } if (v_flag > 1) print_status(); } @@ -706,6 +731,8 @@ static unsigned int test_nd (int dev, blk_t last_block, 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); @@ -788,7 +815,7 @@ static unsigned int test_nd (int dev, blk_t last_block, } 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); */ @@ -804,6 +831,14 @@ static unsigned int test_nd (int dev, blk_t last_block, got = do_read (dev, save_ptr, try, block_size, currently_testing); if (got == 0) { + if ((currently_testing == 0) || + (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++); goto check_for_more; @@ -830,8 +865,13 @@ static unsigned int test_nd (int dev, blk_t last_block, 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) + recover_block = currently_testing - + got + blocks_at_once; + continue; + } check_for_more: /* @@ -839,10 +879,15 @@ static unsigned int test_nd (int dev, blk_t last_block, * 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; @@ -1021,7 +1066,7 @@ int main (int argc, char ** argv) if (argc && *argv) program_name = *argv; - while ((c = getopt (argc, argv, "b:d:e:fi:o:svwnc:p:h:t:X")) != EOF) { + while ((c = getopt (argc, argv, "b:d:e:fi:o:svwnc:p:h:t:BX")) != EOF) { switch (c) { case 'b': block_size = parse_uint(optarg, "block size"); @@ -1094,6 +1139,9 @@ int main (int argc, char ** argv) t_patts[t_flag++] = pattern; } break; + case 'B': + use_buffered_io = 1; + break; case 'X': exclusive_ok++; break; |