Whamcloud - gitweb
ChangeLog, badblocks.8.in, badblocks.c:
authorTheodore Ts'o <tytso@mit.edu>
Mon, 3 Apr 2000 16:01:11 +0000 (16:01 +0000)
committerTheodore Ts'o <tytso@mit.edu>
Mon, 3 Apr 2000 16:01:11 +0000 (16:01 +0000)
  badblocks.8.in: Updated manual page with suggestions from David
   Beattie.
  badblocks.c (test_nd): Generalized cleanup and bug-fixes.  We now
   explicitly clear out the signal handlers to prevent a longjmp to a
   deactivated stack frame.
   (test_rw): Fixed a signed vs. unsigned comparison error.

misc/ChangeLog
misc/badblocks.8.in
misc/badblocks.c

index 56b4e8f..78fa469 100644 (file)
@@ -1,5 +1,13 @@
 2000-04-03  Theodore Ts'o  <tytso@valinux.com>
 
+       * badblocks.8.in: Updated manual page with suggestions from David
+               Beattie.
+
+       * badblocks.c (test_nd): Generalized cleanup and bug-fixes.   We
+               now explicitly clear out the signal handlers to prevent a
+               longjmp to a deactivated stack frame.  
+               (test_rw): Fixed a signed vs. unsigned comparison error.
+
        * badblocks.8.in, chattr.1.in, dumpe2fs.8.in, lsattr.1.in,
                mklost+found.8.in, tune2fs.8.in: Update Remy Card's e-mail
                address.  
index 9dfe0f2..264ccd8 100644 (file)
@@ -44,10 +44,37 @@ Specify the size of blocks in bytes.
 .TP
 .BI \-c " number of blocks"
 is the number of blocks which are tested at a time.  The default is 16.
+Increasing this number will increase the efficiency of
+.B badblocks
+but also will increase its memory usage.
+.B Badblocks
+needs memory proportional to the number of blocks tested at once, in
+read-only mode, proportional to twice that number in read-write mode,
+and proportional to three times that number in non-destructive read-write
+mode.  If you set the number-of-blocks parameter to too high a value,
+.B badblocks
+will exit almost immediately with an out-of-memory error "while allocating
+buffers".  If you set it too low, however, for a non-destructive-write-mode
+test, then you are less likely to detect questionable blocks on an unreliable
+hard drive (i.e., one that holds its data for a while even in bad areas, but
+which loses the data in truely bad blocks, over time), since the
+read-and-compare stage of the test will occur sooner after the data is written.
 .TP
 .BI \-i " input_file"
-Read a list of already existing known bad blocks.  Badblocks will skip 
-testing these blocks since they are known bad.
+Read a list of already existing known bad blocks.
+.B Badblocks
+will skip testing these blocks since they are known to be bad.  If
+.I input_file
+is specified as "-", the list will be read from the standard input.
+Blocks listed in this list will be omitted from the list of
+.I new
+bad blocks produced on the standard output or in the output file.
+The
+.B \-b
+option of
+.BR dumpe2fs (8)
+can be used to retrieve the list of blocks currently marked bad on
+an existing filesystem, in a format suitable for use with this option.
 .TP
 .BI \-o " output_file"
 Write the list of bad blocks to the specified file.  Without this option,
@@ -62,8 +89,11 @@ or
 .BR mke2fs (8).
 .TP
 .BI \-p " num_passes"
-Repeat scanning the disk until there are no new blocks discovered after
-num_passes scans of the disk.
+Repeat scanning the disk until there are no new blocks discovered in
+num_passes consecutive scans of the disk.
+Default is 0, meaning
+.B badblocks
+will exit after the first pass.
 .TP
 .B \-n
 Use non-destructive read-write mode.
@@ -84,12 +114,15 @@ every block of the device, reading every block and comparing the contents.
 Never use the
 .B \-w
 option on an device containing an existing file system.
-This option erases data!
+This option erases data!  If you want to do write-mode testing on
+an existing file system, use the
+.B \-n
+option.  It is slower, but it will preserve your data.
 .SH AUTHOR
 .B badblocks
 was written by Remy Card <Remy.Card@linux.org>.  Current maintainer is
 Theodore Ts'o <tytso@alum.mit.edu>.  Non-destructive read/write test
-implemented by David Beattie <dbeattie@usa.net>.
+implemented by David Beattie <dbeattie@softhome.net>.
 .SH AVAILABILITY
 .B badblocks
 is part of the e2fsprogs package and is available for anonymous 
index 1a47984..475c9c3 100644 (file)
 const char * program_name = "badblocks";
 const char * done_string = N_("done                        \n");
 
-int v_flag = 0;                        /* verbose */
-int w_flag = 0;                        /* do r/w test: 0=no, 1=yes, 2=non-destructive */
-int s_flag = 0;                        /* show progress of test */
+static int v_flag = 0;                 /* verbose */
+static int w_flag = 0;                 /* do r/w test: 0=no, 1=yes,
+                                        * 2=non-destructive */
+static int s_flag = 0;                 /* show progress of test */
+
+static char *blkbuf;           /* Allocation array for bad block testing */
+
 
 static void usage(void)
 {
@@ -141,6 +145,17 @@ static void capture_terminate (jmp_buf term_addr)
        signal (SIGUSR2, terminate_intr);
 }
 
+static void uncapture_terminate()
+{
+       terminate_addr = NULL;
+       signal (SIGHUP, SIG_DFL);
+       signal (SIGINT, SIG_DFL);
+       signal (SIGPIPE, SIG_DFL);
+       signal (SIGTERM, SIG_DFL);
+       signal (SIGUSR1, SIG_DFL);
+       signal (SIGUSR2, SIG_DFL);
+}
+
 /*
  * Perform a read of a sequence of blocks; return the number of blocks
  *    successfully sequentially read.
@@ -369,9 +384,9 @@ static unsigned int test_rw (int dev, unsigned long blocks_count,
                        if (v_flag > 1)
                                print_status();
                        if ((read (dev, buffer + block_size, block_size) 
-                            < block_size) ||
+                            != block_size) ||
                            memcmp(buffer, buffer + block_size, block_size))
-                               bb_count = bb_output(currently_testing);
+                               bb_count += bb_output(currently_testing);
                }
                num_blocks = 0;
                alarm (0);
@@ -396,11 +411,8 @@ static unsigned int test_nd (int dev, unsigned long blocks_count,
        jmp_buf terminate_env;
        errcode_t errcode;
        /* These are static to prevent being clobbered by the longjmp */
-       static long buf_used;
-       static unsigned int bb_count;
-
-       bb_count = 0;
-       buf_used = 0;
+       static long buf_used = 0;
+       static unsigned int bb_count = 0;
 
        errcode = ext2fs_badblocks_list_iterate_begin(bb_list,&bb_iter);
        if (errcode) {
@@ -441,132 +453,13 @@ static unsigned int test_nd (int dev, unsigned long blocks_count,
                if (v_flag <= 1)
                        alarm_intr(SIGALRM);
        }
-       if (! setjmp(terminate_env)) {
-               /* set up abend handler */
-               capture_terminate(terminate_env);
-
-               buf_used = 0; save_ptr = blkbuf;
-               test_ptr = blkbuf + (blocks_at_once * block_size);
-               currently_testing = from_count;
-               num_blocks = blocks_count;
-
-               while (currently_testing < blocks_count) {
-                       try = blocks_at_once - buf_used;
-                       if (next_bad) {
-                               if (currently_testing == next_bad) {
-                                       /* fprintf (out, "%lu\n", nextbad); */
-                                       ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
-                                       bufblk[buf_used] = currently_testing++;
-                                       goto test_full_buf;
-                               }
-                               else if (currently_testing + try > next_bad)
-                                       try = next_bad - currently_testing;
-                       }
-                       if (currently_testing + try > blocks_count)
-                               try = blocks_count - currently_testing;
-                       got = do_read (dev, save_ptr, try, block_size,
-                                      currently_testing);
-
-                       /* if reading succeeded, write the test data */
-                       if (got) {
-                               long written;
-
-                               written = do_write (dev, test_ptr, got, 
-                                                   block_size,
-                                                   currently_testing);
-                               if (written != got)
-                                       com_err (program_name, errno,
-                                _("during test data write, block %lu"),
-                                                currently_testing + written);
-                       }
-
-                       bufblk[buf_used] = currently_testing;
-                       bufblks[buf_used] = got;
-                       buf_used += got;
-                       save_ptr += got * block_size;
-                       test_ptr += got * block_size;
-                       currently_testing += got;
-                       if (got != try)
-                               bb_count += bb_output(currently_testing++);
-
-                       test_full_buf:
-                       /*
-                        * If there's room for more blocks to be
-                        * tested this around, and we're not done yet
-                        * testing the disk, go back and get some
-                        * more blocks.
-                        */
-                       if ((buf_used != blocks_at_once) &&
-                           (currently_testing != blocks_count))
-                               continue;
-
-                       flush_bufs (dev, 1);
-
-                       /*
-                        * for each contiguous block that we read into
-                        * the buffer (and wrote test data into
-                        * afterwards), read it back (looping if
-                        * necessary, to get past newly discovered
-                        * unreadable blocks, of which there should be
-                        * none, but with a hard drive which is
-                        * unreliable, it has happened), and compare
-                        * with the test data that was written; output
-                        * to the bad block list if it doesn't match.
-                        */
-                       used2 = 0;
-                       save_ptr = blkbuf;
-                       test_ptr = blkbuf + (blocks_at_once * block_size);
-                       read_ptr = blkbuf + (2 * blocks_at_once * block_size);
-                       currently_testing = bufblk[0];
-                       try = bufblks[0];
-                       while (currently_testing < blocks_count) {
-
-                               got = do_read (dev, read_ptr, try,
-                                              block_size, currently_testing);
-
-                               /* test the comparison between all the
-                                  blocks successfully read  */
-                               for (i = 0; i < got; ++i)
-                                       if (memcmp (test_ptr, read_ptr,
-                                                   block_size))
-                                               bb_count += bb_output(currently_testing + i);
-                               if (got == 0) {
-                                       bb_count += bb_output(currently_testing);
-                                       got = 1;
-                               }
-                                       
-                               /* when done, write back original data */
-                               do_write (dev, save_ptr, got, block_size, 
-                                         currently_testing);
-
-                               currently_testing += got;
-                               save_ptr += bufblks[got] * block_size;
-                               test_ptr += bufblks[got] * block_size;
-                               read_ptr += bufblks[got] * block_size;
-                               try -= got;
-
-                               if (try == 0) {
-                                       used2 += bufblks[used2];
-                                       if (used2 >= blocks_at_once)
-                                               break;
-                                       currently_testing = bufblk[used2];
-                                       try = bufblks[used2];
-                               }
-                       }
-
-                       /* empty the buffer so it can be reused */
-                       buf_used = 0;
-               }
-               num_blocks = 0;
-               alarm(0);
-               if (s_flag || v_flag > 1)
-                       fprintf(stderr, _(done_string));
-
-       } else {
-               /* abnormal termination by a signal is handled here */
-               /* logic is: write back the data that is in the buffer,
-                  so that we can maintain data integrity on disk.  Then
-                  abort. */
+       if (setjmp(terminate_env)) {
+               /*
+                * Abnormal termination by a signal is handled here.
+                * buf_used will always contain the number of blocks
+                * saved in a non-destructive test, so they can be
+                * rewritten back to the disk.
+                */
                long buf_written;
 
                fprintf(stderr, _("Interrupt caught, cleaning up\n"));
@@ -581,6 +474,124 @@ static unsigned int test_nd (int dev, unsigned long blocks_count,
                fflush (out);
                exit(1);
        }
+       
+       /* set up abend handler */
+       capture_terminate(terminate_env);
+
+       buf_used = 0; save_ptr = blkbuf;
+       test_ptr = blkbuf + (blocks_at_once * block_size);
+       currently_testing = from_count;
+       num_blocks = blocks_count;
+
+       while (currently_testing < blocks_count) {
+               try = blocks_at_once - buf_used;
+               if (next_bad) {
+                       if (currently_testing == next_bad) {
+                               /* fprintf (out, "%lu\n", nextbad); */
+                               ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
+                               bufblk[buf_used] = currently_testing++;
+                               goto test_full_buf;
+                       }
+                       else if (currently_testing + try > next_bad)
+                               try = next_bad - currently_testing;
+               }
+               if (currently_testing + try > blocks_count)
+                       try = blocks_count - currently_testing;
+               got = do_read (dev, save_ptr, try, block_size,
+                              currently_testing);
+
+               /* if reading succeeded, write the test data */
+               if (got) {
+                       long written;
+
+                       written = do_write (dev, test_ptr, got, block_size,
+                                           currently_testing);
+                       if (written != got)
+                               com_err (program_name, errno,
+                                _("during test data write, block %lu"),
+                                        currently_testing + written);
+               }
+
+               bufblk[buf_used] = currently_testing;
+               bufblks[buf_used] = got;
+               buf_used += got;
+               save_ptr += got * block_size;
+               test_ptr += got * block_size;
+               currently_testing += got;
+               if (got != try)
+                       bb_count += bb_output(currently_testing++);
+
+       test_full_buf:
+               /*
+                * If there's room for more blocks to be tested this
+                * around, and we're not done yet testing the disk, go
+                * back and get some more blocks.
+                */
+               if ((buf_used != blocks_at_once) &&
+                   (currently_testing != blocks_count))
+                       continue;
+
+               flush_bufs (dev, 1);
+
+               /*
+                * for each contiguous block that we read into the
+                * buffer (and wrote test data into afterwards), read
+                * it back (looping if necessary, to get past newly
+                * discovered unreadable blocks, of which there should
+                * be none, but with a hard drive which is unreliable,
+                * it has happened), and compare with the test data
+                * that was written; output to the bad block list if
+                * it doesn't match.
+                */
+               used2 = 0;
+               save_ptr = blkbuf;
+               test_ptr = blkbuf + (blocks_at_once * block_size);
+               read_ptr = blkbuf + (2 * blocks_at_once * block_size);
+               currently_testing = bufblk[0];
+               try = bufblks[0];
+
+               while (currently_testing < blocks_count) {
+                       got = do_read (dev, read_ptr, try,
+                                      block_size, currently_testing);
+
+                       /* test the comparison between all the
+                          blocks successfully read  */
+                       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);
+                       if (got < try) {
+                               bb_count += bb_output(currently_testing + got);
+                               got++;
+                       }
+                                       
+                       /* when done, write back original data */
+                       do_write (dev, save_ptr, got, block_size,
+                                 currently_testing);
+
+                       currently_testing += got;
+                       save_ptr += got * block_size;
+                       test_ptr += got * block_size;
+                       read_ptr += got * block_size;
+                       try -= got;
+
+                       if (try == 0) {
+                               used2 += bufblks[used2];
+                               if (used2 >= blocks_at_once)
+                                       break;
+                               currently_testing = bufblk[used2];
+                               try = bufblks[used2];
+                       }
+               }
+
+               /* empty the buffer so it can be reused */
+               buf_used = 0;
+       }
+       num_blocks = 0;
+       alarm(0);
+       uncapture_terminate();
+       if (s_flag || v_flag > 1)
+               fprintf(stderr, _(done_string));
 
        fflush(stderr);
        free(blkbuf);
@@ -608,6 +619,10 @@ int main (int argc, char ** argv)
        int passes_clean = 0;
        int dev;
        errcode_t errcode;
+       unsigned int (*test_func)(int dev, unsigned long blocks_count,
+                                 int block_size, unsigned long from_count,
+                                 unsigned long blocks_at_once);
+       size_t  buf_size;
 
        setbuf(stdout, NULL);
        setbuf(stderr, NULL);
@@ -616,6 +631,8 @@ int main (int argc, char ** argv)
        bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
        textdomain(NLS_CAT_NAME);
 #endif
+       test_func = test_ro;
+       
        if (argc && *argv)
                program_name = *argv;
        while ((c = getopt (argc, argv, "b:i:o:svwnc:p:h:")) != EOF) {
@@ -641,10 +658,15 @@ int main (int argc, char ** argv)
                        v_flag++;
                        break;
                case 'w':
-                       if (! w_flag)
-                               w_flag = 1;
+                       if (w_flag)
+                               usage();
+                       test_func = test_rw;
+                       w_flag = 1;
                        break;
                case 'n':
+                       if (w_flag)
+                               usage();
+                       test_func = test_nd;
                        w_flag = 2;
                        break;
                case 'c':
@@ -768,15 +790,13 @@ int main (int argc, char ** argv)
        do {
                unsigned int bb_count;
 
-               (bb_count =
-
-               (w_flag == 2 ? test_nd
-                   : w_flag ? test_rw
-                            : test_ro)
-                                       (dev, blocks_count, block_size, from_count,
-                                             blocks_at_once)
-               )       ? passes_clean = 0 : ++passes_clean;
-
+               bb_count = test_func(dev, blocks_count, block_size,
+                                    from_count, blocks_at_once);
+               if (bb_count)
+                       passes_clean = 0;
+               else
+                       ++passes_clean;
+               
                if (v_flag)
                        fprintf(stderr,
                                _("Pass completed, %u bad blocks found.\n"),