+README/"Linux kernel flaw" and its handling (last sector failed reads)
authorshort <>
Tue, 6 Aug 2002 14:30:49 +0000 (14:30 +0000)
committershort <>
Tue, 6 Aug 2002 14:30:49 +0000 (14:30 +0000)
README
badblock-guess.c

diff --git a/README b/README
index fee9795..b02fc61 100644 (file)
--- a/README
+++ b/README
@@ -91,6 +91,21 @@ performance about 90KB/s (approx. 7.5GB/24hours if no badblocks read retrying
 is needed). YMMV.
 
 
+Linux kernel flaw
+-----------------
+
+Linux kernels have internal blocksize 1KB but the partitions can be sized by
+512 sectors and thus the last odd partition sector gets inaccessible.
+This isn't a problem for a the disk devices as AFAIK all the disks have always
+even number of sectors.
+
+This program is aware of this flaw and it will not report last such sector as
+BAD - just the appropriate warning is supplied (to stderr). This may be visible
+for example while recovering NTFS partition with odd cylinder number (=>odd
+sector count) as NTFS uses the last partition sector for its superblock backup.
+Fortunately CHKDSK will fix it back, of course.
+
+
 Compilation
 -----------
 
index f715cd1..e7dacd2 100644 (file)
@@ -274,6 +274,13 @@ ext2_loff_t gotext2_loff;
                exit(EXIT_FAILURE);
                }
        if (len!=(gotssize=write(dst_fd,buf,len))) {
+               /* see README/"Linux kernel flaw" */
+               /* no "start==src_len-1" checking here, we may write larger blocks! */
+               if (gotssize==((src_len&~1)-start)*BLOCK
+                               /* -1 instead of 0 is given when no bytes were written */
+                               || (gotssize==-1 && start==src_len-1 && end==src_len))
+                       return; /* suppress error message */
+
                fprintf(stderr,"write(\"%s\",@%llu-@%llu=%llu=%lluB)=%lld: %m\n",dst_name,
                                (unsigned long long)start,
                                (unsigned long long)end,
@@ -284,11 +291,29 @@ ext2_loff_t gotext2_loff;
                }
 }
 
+static void range_zero(ext2_loff_t start,ext2_loff_t end)
+{
+static const unsigned char buf_zero[BUF_ZERO_BLOCKS*BLOCK];
+
+       g_return_if_fail(start<end);
+
+       while (start<end) {
+               ext2_loff_t mid=((end-start)>BUF_ZERO_BLOCKS ? start+BUF_ZERO_BLOCKS : end);
+               g_assert(mid>=start);
+               g_assert(mid<=end);
+
+               write_dst(start,mid,buf_zero);
+
+               start=mid;
+               }
+}
+
 static void process(ext2_loff_t start,ext2_loff_t end)
 {
 unsigned char block_buf[BLOCK];
 ext2_loff_t bads;
 ext2_loff_t gotext2_loff;
+ssize_t gotssize;
 
        g_return_if_fail(start<end);
        g_return_if_fail(end<=src_len);
@@ -308,9 +333,18 @@ restart:   /* continues when the block was successfuly read */
                exit(EXIT_FAILURE);
                }
        stat_todo--;    /* for the forthcoming read() */
-       if (!simulate_bads && sizeof(block_buf)==read(src_fd,block_buf,sizeof(block_buf))) {
+       if (!simulate_bads && (sizeof(block_buf)==(gotssize=read(src_fd,block_buf,sizeof(block_buf)))
+                                       /* see README/"Linux kernel flaw" */
+                                       || (start==src_len-1 && gotssize==((src_len&~1)-start)*BLOCK))
+                       ) {
                /* success read */
-               write_dst(start,start+1,block_buf);
+               if (gotssize==sizeof(block_buf))
+                       write_dst(start,start+1,block_buf);
+               else {
+                       /* handle README/"Linux kernel flaw" */
+                       fprintf(stderr,"WARNING: Ignored disk-last sector read failure; see README/\"Linux kernel flaw\"\n");
+                       range_zero(start,start+1);
+                       }
                start++;
                if (start>=end) /* finished */
                        return;
@@ -337,23 +371,6 @@ ext2_loff_t mid=(start+end)/2;
                }
 }
 
-static void range_zero(ext2_loff_t start,ext2_loff_t end)
-{
-static const unsigned char buf_zero[BUF_ZERO_BLOCKS*BLOCK];
-
-       g_return_if_fail(start<end);
-
-       while (start<end) {
-               ext2_loff_t mid=((end-start)>BUF_ZERO_BLOCKS ? start+BUF_ZERO_BLOCKS : end);
-               g_assert(mid>=start);
-               g_assert(mid<=end);
-
-               write_dst(start,mid,buf_zero);
-
-               start=mid;
-               }
-}
-
 static void finish(void)
 {
 struct range *todo_linear=tree_linearize(todo_tree),*todol;