Skip site navigation (1)Skip section navigation (2)
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>