I recently made a few changes to vnd(4) to make it stricter by better emulating physical disks and their requirements (e.g., raw disk I/O must be done with whole sectors). However, it turns out that a lot of the release scripts depended on the more lenient behavior vnd(4) used to exhibit.
It's too late in the release cycle to attempt to fix up the offending scripts and tools, so we need to revert vnd(4). The diff below reverts these behavioral changes I made to vnd(4): 1. Allow disk reads and writes of less than a complete sector at a time. (This is currently needed for at least sgivol(8), and was previously needed for some of the dd commands in socppc's scripts.) 2. In physio(), don't panic if (*strategy)() didn't do a whole sector worth of I/O. (This is needed because of #1.) 3. Don't flush the disklabel cache when all of the partitions have been closed. (This is currently needed for at least readsgilabel(), because it re-spoofs a bad disklabel on >512-byte sector disks.) 4. Don't complain if the user tries to modify a vnd(4) partition's offset or size while it's open. (I don't believe this is actually necessary with #3, but I think it's better to revert anyway just to avoid further surprises.) Anyway, expect this diff to be used for building releases. If you have other uses for vnd(4), then please test this now and report problems sooner rather than later. Thanks. Index: kern/kern_physio.c =================================================================== RCS file: /home/mdempsky/anoncvs/cvs/src/sys/kern/kern_physio.c,v retrieving revision 1.38 diff -u -p -r1.38 kern_physio.c --- kern/kern_physio.c 7 Jul 2011 16:50:15 -0000 1.38 +++ kern/kern_physio.c 16 Jul 2011 17:37:01 -0000 @@ -199,8 +199,6 @@ physio(void (*strategy)(struct buf *), d panic("done < 0; strategy broken"); if (done > todo) panic("done > todo; strategy broken"); - if ((done % DEV_BSIZE) != 0) - panic("(done % DEV_BSIZE) != 0; strategy broken"); #endif iovp->iov_len -= done; iovp->iov_base = (caddr_t)iovp->iov_base + done; Index: dev/vnd.c =================================================================== RCS file: /home/mdempsky/anoncvs/cvs/src/sys/dev/vnd.c,v retrieving revision 1.146 diff -u -p -r1.146 vnd.c --- dev/vnd.c 8 Jul 2011 20:10:34 -0000 1.146 +++ dev/vnd.c 16 Jul 2011 22:50:03 -0000 @@ -255,8 +255,10 @@ vndclose(dev_t dev, int flags, int mode, disk_closepart(&sc->sc_dk, part, mode); +#if 0 if (sc->sc_dk.dk_openmask == 0) sc->sc_flags &= ~VNF_HAVELABEL; +#endif disk_unlock(&sc->sc_dk); return (0); @@ -269,6 +271,7 @@ vndstrategy(struct buf *bp) struct vnd_softc *sc; struct partition *p; off_t off; + long origbcount; int s; DNPRINTF(VDB_FOLLOW, "vndstrategy(%p): unit %d\n", bp, unit); @@ -284,8 +287,31 @@ vndstrategy(struct buf *bp) goto bad; } - if (bounds_check_with_label(bp, sc->sc_dk.dk_label) == -1) + /* + * Many of the distrib scripts assume they can issue arbitrary + * sized requests to raw vnd devices irrespective of the + * emulated disk geometry. + * + * To continue supporting this, round the block count up to a + * multiple of d_secsize for bounds_check_with_label(), and + * then restore afterwards. + * + * We only do this for non-encrypted vnd, because encryption + * requires operating on blocks at a time. + */ + origbcount = bp->b_bcount; + if (sc->sc_keyctx == NULL) { + u_int32_t secsize = sc->sc_dk.dk_label->d_secsize; + bp->b_bcount = ((origbcount + secsize - 1) & ~(secsize - 1)); + } + + if (bounds_check_with_label(bp, sc->sc_dk.dk_label) == -1) { + bp->b_resid = bp->b_bcount = origbcount; goto done; + } + + if (origbcount < bp->b_bcount) + bp->b_bcount = origbcount; p = &sc->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)]; off = DL_GETPOFFSET(p) * sc->sc_dk.dk_label->d_secsize + @@ -570,7 +596,7 @@ vndioctl(dev_t dev, u_long cmd, caddr_t return (error); error = setdisklabel(sc->sc_dk.dk_label, - (struct disklabel *)addr, sc->sc_dk.dk_openmask); + (struct disklabel *)addr, /* sc->sc_dk.dk_openmask */ 0); if (error == 0) { if (cmd == DIOCWDINFO) error = writedisklabel(DISKLABELDEV(dev),