Date: Wed, 10 Jul 1996 05:37:31 +1000 From: Bruce Evans <bde@zeta.org.au> To: franky@pinewood.nl, freebsd-hackers@FreeBSD.org Subject: Re: >2G partition blues Message-ID: <199607091937.FAA02250@godzilla.zeta.org.au>
next in thread | raw e-mail | index | archive | help
> if (-1 == lseek(fd,block * 512,SEEK_SET)) <=== PROBLEM
> err(1,"lseek");
>When 'block' is larger than 4194303 (>2G partition), the result
>'block * 512' will yield a negative number, which is cast to (off_t),
>which is also NEGATIVE.
>Strangely the lseek() succeeds, but the following write(2) fails:
lseek() always succeeds if its fd and `whence' args are valid. Even
lseeking to offset -1 succeeds, so if there is any possiblity that the
offset arg is -1 and valid, then the error check must be written
something like:
errno = 0;
if (-1 == lseek(...) && errno != 0)
err(...);
> write: Input/Output Error.
Writing to negative offsets is unlikely to work, but it might for huge
sparse file systems or /dev/[k]mem on 64-bit machines. Lseeking to
negative offsets in /dev/kmem is common on 32-bit machines with 32-bit
off_t's.
>I suspect that FreeBSD has many more such problems, as I experience
I hope most are already fixed.
>There is a similar problem in sysinstall in the 2.2-960612-SNAPSHOT
>release. Sysinstall aborts with:
> Debugger("Slice got negative blocknumber") called.
Negative block numbers are now known to be caused by writes to negative
offsets on raw and buffered devices:
(1) physio() doesn't check for negative blkno's or other overflows:
bp->b_blkno = btodb(uio->uio_offset);
Here uio_offset is 64 bits (negative values should be treated as large
unsigned values so that seeks to "negative" offsets in 64-bit /dev/kmem's
work) and btodb divides by DEV_BSIZE = 512, so the LHS must be 55 bits,
but the LHS is only 31 bits (negative values are invalid).
(2) spec_read(0 and spec_write() don't check for negative bn's or other
overflows:
bn = (uio->uio_offset >> DEV_BSHIFT) &~ (bscale - 1);
This overflows in one more way for negative offsets. It should be written
something like:
off_t bn1;
bn1 = btodb(uio->uio_offset) & ~(bscale - 1);
bn = bn1;
if (bn != bn1)
overflow_error();
The original code was valid when daddr_t was the same size as off_t and
disks with "negative" sizes (2G-4G) were a dream.
(3) Negative blkno's don't occur for file systems because offsets < 0 or
>= 2^40 aren't within any file.
Bruce
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199607091937.FAA02250>
