Date: Sat, 06 Sep 2003 19:38:04 +0200 From: Matthias Andree <ma@dt.e-technik.uni-dortmund.de> To: freebsd-stable@freebsd.org Subject: KERNEL BUG: lseek() broken on raw devices Message-ID: <m3vfs595s3.fsf@merlin.emma.line.org>
next in thread | raw e-mail | index | archive | help
Hi, I just figured FreeBSD will happily write data (disk blocks) from byte #0 even after successful lseek(fd, 17, SEEK_SET) returned 17, at least on da(4) partitions such as rda0s1f. Tested on 4.9-PRERELEASE checked out early Sep 5th. I'd suggest that lseek to a non-sector boundary returns either (off_t)-1 and EINVAL (preferred) or at least returns the actual position (though few applications will handle that properly), or that write() returns -1 and EINVAL when writing to such a non-aligned location. Try this DESTRUCTIVE test on a scratch or spare partition that may lose all its data. Note that some devices are halfway fine; vn0c lets the seek succeed but returns EINVAL for the subsequent write, so make sure to try this on a da partition (comment out your swap partition, reboot, and use your freshly-deactivated swap partition if need be). NIT PICK: write(2) EINVAL means "The pointer associated with d was negative." (d is the file descriptor) Expected behaviour: either abort with "Invalid argument" on lseek bs/2 or on write or print "OK". #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/disklabel.h> void barf(const char *t) __attribute__((noreturn)); void barf(const char *t) { perror(t); exit(EXIT_FAILURE); } int main(int argc, char **argv) { int bs, fd = open(argc > 1 ? argv[1] : "/dev/rda0s1f", O_RDWR); int want = 0x66, t; struct disklabel dl; char *x; if (fd < 0) barf("open"); if (0 == ioctl(fd, DIOCGDINFO, &dl)) { printf("sector size: %lu\n", (unsigned long)(bs = dl.d_secsize)) ; } else barf("ioctl DIOCGDINFO"); /* this writes bs = blocksize times the byte 0x66 at offset #0 * then seeks to offset #bs/2 then writes bs times the byte 0x33. */ if (!(x = malloc(bs))) barf("malloc"); memset(x, want, bs); if (lseek(fd, 0, SEEK_SET) == (off_t)-1) barf("lseek 0"); if (write(fd, x, bs) < bs) barf("write"); memset(x, 0x33, bs); t = lseek(fd, bs >> 1, SEEK_SET); if (t == -1) barf("lseek bs/2"); printf("seeked to byte #%d\n", t); if (write(fd, x, bs) < bs) barf("write"); if (lseek(fd, 0, SEEK_SET) == (off_t)-1) barf("lseek 0"); if (read(fd, x, bs) < bs) barf("read"); if (x[0] == want) puts("OK"); else printf("KERNEL BUG: byte #0 is %x, should be %x\n", x[0], want); free(x); return 0; } -- Matthias Andree Encrypt your mail: my GnuPG key ID is 0x052E7D95
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?m3vfs595s3.fsf>