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>