summaryrefslogtreecommitdiff
path: root/misc
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2011-02-18 01:19:05 -0500
committerTheodore Ts'o <tytso@mit.edu>2011-02-18 01:19:05 -0500
commit175d43beada4f5c971fa4b495380620644705282 (patch)
treeb09fe4bec67a401f05b8789bf2783d774273dda5 /misc
parent616f68bf773440d6b6af4fb91c5cde6f74e5e659 (diff)
parent468d82f430dfdf270b738e14345b879560c2cd9e (diff)
downloade2fsprogs-175d43beada4f5c971fa4b495380620644705282.tar.gz
Merge branch 'maint' into next
Diffstat (limited to 'misc')
-rw-r--r--misc/badblocks.8.in5
-rw-r--r--misc/badblocks.c136
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;