bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: shred and odd partition sizes


From: Bruno Haible
Subject: Re: shred and odd partition sizes
Date: Thu, 24 Aug 2006 21:59:17 +0200
User-agent: KMail/1.9.1

Paul Eggert wrote:
> 'shred' already attempts to do just that -- it attempts to deduce the
> size by looking at the errno value after failed 'write'.

Good, then it probably needs only a small tweak.

> What's the size of the partition in question, exactly?

I can't tell that any more. An upper bound is 523 * 63 * 255 sectors à
512 bytes.

> After reading through the 'shred' code, here's my guess as to what
> happens:
> 
> First, 'shred' uses lseek (fd, 0, SEEK_END) to determine the size
> of the device.  It gets the value 4,301,789,184 (this is 4,200,966
> * 1024).
> 
> Then, 'shred' writes a series of 12 KiB buffers.  It writes
> 350,080 buffers successfully, for a total of 4,301,783,040 bytes.
> Subtracting this last value from the size 4,301,789,184, it gets 6
> KiB, so it decides to write a 6 KiB buffer.  But it gets a short
> write of 4 KiB, which means that the file offset is now
> 4,301,787,136 (the number in the diagnostic quoted above).  It
> then tries to write the last 2 KiB but gets an I/O error, which it
> reports.
> 
> At this point 'shred' is supposed to use lseek to skip around the
> "bad block" (which I suspect is not really a bad block, though I
> don't know what it is).  So it lseeks to 4,301,787,136 + 512 =
> 4,301,787,648 and tries to write 2 KiB - 512 B = 1,536 bytes.
> This write reports that 1 byte (!) got written, so it then tries
> to write 1,535 bytes.  This last write fails, so it reports a
> write error at offset 4,301,787,137.  Since this offset is not a
> multiple of 512, dopass returns -1.

Thanks for explaining; now I understand the code better. Maybe the fix
is simply to make a write at a byte not divisible by 512 less fatal.
I.e. let dopass continue searching for bad blocks (shouldn't find many,
as we're near the end of the device anyway), instead of giving up.

> That is because dopass returned -1.  It normally doesn't do that,
> even for an attempt to write past the end of the device, but if it
> gets really weird results it will.

Can we treat a write error as "not so weird"?

> > The only option that helps is to use the --size option with a value of the
> > limit mentioned above (4200966), minus 2, times 1024.
> 
> This suggests that the operating system is lying about the device
> size, and is claiming that it is 4,200,966 * 1024 = 4,301,789,184
> bytes, whereas it is "really" 2,048 bytes smaller.

Certainly. I have no other explanation for the missing 2048 bytes.
But we cannot do anything about it.

> Perhaps you can use 'strace' to check my guesses above?

Too late. The machine's already wiped out, sorry.

The appended patch might fix these cases and is at the same time safe.


2006-08-24  Bruno Haible  <address@hidden>

        * src/shred.c (dopass): Assume a continuable error if EIO even
        if the current position is not a multiple of 512.

*** shred.c     13 Aug 2006 21:21:52 -0000      1.126
--- shred.c     24 Aug 2006 19:49:19 -0000
***************
*** 452,465 ****
                   * over them.  It works because lim is always a multiple
                   * of 512, except at the end.
                   */
!                 if (errnum == EIO && soff % 512 == 0 && lim >= soff + 512
                      && size != -1)
                    {
!                     if (lseek (fd, (off_t) (offset + soff + 512), SEEK_SET)
                          != -1)
                        {
                          /* Arrange to skip this block. */
!                         ssize = 512;
                          write_error = true;
                          continue;
                        }
--- 452,466 ----
                   * over them.  It works because lim is always a multiple
                   * of 512, except at the end.
                   */
!                 if (errnum == EIO && lim >= (soff | 0x1ff) + 1
                      && size != -1)
                    {
!                     if (lseek (fd, (off_t) (offset + (soff | 0x1ff) + 1),
!                                SEEK_SET)
                          != -1)
                        {
                          /* Arrange to skip this block. */
!                         ssize = ((soff | 0x1ff) + 1) - soff;
                          write_error = true;
                          continue;
                        }




reply via email to

[Prev in Thread] Current Thread [Next in Thread]