xref: /dflybsd-src/sys/dev/virtual/vkernel/disk/vdisk.c (revision 2c7fc62c34e66939c6430317df267a85d2c41e37)
19ed84223SSascha Wildner /*
254ea00b8SMatthew Dillon  * Copyright (c) 2006,2016 The DragonFly Project.  All rights reserved.
39ed84223SSascha Wildner  *
49ed84223SSascha Wildner  * This code is derived from software contributed to The DragonFly Project
59ed84223SSascha Wildner  * by Matthew Dillon <dillon@backplane.com>
69ed84223SSascha Wildner  *
79ed84223SSascha Wildner  * Redistribution and use in source and binary forms, with or without
89ed84223SSascha Wildner  * modification, are permitted provided that the following conditions
99ed84223SSascha Wildner  * are met:
109ed84223SSascha Wildner  *
119ed84223SSascha Wildner  * 1. Redistributions of source code must retain the above copyright
129ed84223SSascha Wildner  *    notice, this list of conditions and the following disclaimer.
139ed84223SSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
149ed84223SSascha Wildner  *    notice, this list of conditions and the following disclaimer in
159ed84223SSascha Wildner  *    the documentation and/or other materials provided with the
169ed84223SSascha Wildner  *    distribution.
179ed84223SSascha Wildner  * 3. Neither the name of The DragonFly Project nor the names of its
189ed84223SSascha Wildner  *    contributors may be used to endorse or promote products derived
199ed84223SSascha Wildner  *    from this software without specific, prior written permission.
209ed84223SSascha Wildner  *
219ed84223SSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
229ed84223SSascha Wildner  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
239ed84223SSascha Wildner  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
249ed84223SSascha Wildner  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
259ed84223SSascha Wildner  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
269ed84223SSascha Wildner  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
279ed84223SSascha Wildner  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
289ed84223SSascha Wildner  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
299ed84223SSascha Wildner  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
309ed84223SSascha Wildner  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
319ed84223SSascha Wildner  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
329ed84223SSascha Wildner  * SUCH DAMAGE.
339ed84223SSascha Wildner  *
349ed84223SSascha Wildner  */
359ed84223SSascha Wildner 
369ed84223SSascha Wildner /*
379ed84223SSascha Wildner  * Virtual disk driver
389ed84223SSascha Wildner  */
399ed84223SSascha Wildner #include <sys/types.h>
409ed84223SSascha Wildner #include <sys/param.h>
419ed84223SSascha Wildner #include <sys/systm.h>
429ed84223SSascha Wildner #include <sys/kernel.h>
439ed84223SSascha Wildner #include <sys/malloc.h>
449ed84223SSascha Wildner #include <sys/conf.h>
459ed84223SSascha Wildner #include <sys/bus.h>
469ed84223SSascha Wildner #include <sys/buf.h>
479ed84223SSascha Wildner #include <sys/devicestat.h>
489ed84223SSascha Wildner #include <sys/disk.h>
499ed84223SSascha Wildner #include <machine/cothread.h>
509ed84223SSascha Wildner #include <machine/md_var.h>
519ed84223SSascha Wildner 
529ed84223SSascha Wildner #include <sys/buf2.h>
539ed84223SSascha Wildner 
549ed84223SSascha Wildner #include <sys/stat.h>
559ed84223SSascha Wildner #include <unistd.h>
569ed84223SSascha Wildner 
579ed84223SSascha Wildner struct vkd_softc {
589ed84223SSascha Wildner 	struct bio_queue_head bio_queue;
599ed84223SSascha Wildner 	struct devstat stats;
609ed84223SSascha Wildner 	struct disk disk;
619ed84223SSascha Wildner 	cothread_t	cotd;
629ed84223SSascha Wildner 	TAILQ_HEAD(, bio) cotd_queue;
639ed84223SSascha Wildner 	TAILQ_HEAD(, bio) cotd_done;
649ed84223SSascha Wildner 	cdev_t dev;
659ed84223SSascha Wildner 	int unit;
669ed84223SSascha Wildner 	int fd;
6754ea00b8SMatthew Dillon 	int flags;
6854ea00b8SMatthew Dillon 	off_t	size;		/* in bytes */
6954ea00b8SMatthew Dillon 	char	*map_buf;	/* COW mode only */
709ed84223SSascha Wildner };
719ed84223SSascha Wildner 
729ed84223SSascha Wildner static void vkd_io_thread(cothread_t cotd);
739ed84223SSascha Wildner static void vkd_io_intr(cothread_t cotd);
749ed84223SSascha Wildner static void vkd_doio(struct vkd_softc *sc, struct bio *bio);
759ed84223SSascha Wildner 
769ed84223SSascha Wildner static d_strategy_t	vkdstrategy;
779ed84223SSascha Wildner static d_open_t		vkdopen;
789ed84223SSascha Wildner 
799ed84223SSascha Wildner static struct dev_ops vkd_ops = {
809ed84223SSascha Wildner 	{ "vkd", 0, D_DISK },
819ed84223SSascha Wildner         .d_open =	vkdopen,
829ed84223SSascha Wildner         .d_close =	nullclose,
839ed84223SSascha Wildner         .d_read =	physread,
849ed84223SSascha Wildner         .d_write =	physwrite,
859ed84223SSascha Wildner         .d_strategy =	vkdstrategy,
869ed84223SSascha Wildner };
879ed84223SSascha Wildner 
889ed84223SSascha Wildner static void
vkdinit(void * dummy __unused)899ed84223SSascha Wildner vkdinit(void *dummy __unused)
909ed84223SSascha Wildner {
919ed84223SSascha Wildner 	struct vkdisk_info *dsk;
929ed84223SSascha Wildner 	struct vkd_softc *sc;
939ed84223SSascha Wildner 	struct disk_info info;
949ed84223SSascha Wildner 	struct stat st;
959ed84223SSascha Wildner 	int i;
969ed84223SSascha Wildner 
979ed84223SSascha Wildner 	for (i = 0; i < DiskNum; i++) {
989ed84223SSascha Wildner 		/* check that the 'bus device' has been initialized */
999ed84223SSascha Wildner 		dsk = &DiskInfo[i];
1009ed84223SSascha Wildner 		if (dsk == NULL || dsk->type != VKD_DISK)
1019ed84223SSascha Wildner 			continue;
1029ed84223SSascha Wildner 		if (dsk->fd < 0 || fstat(dsk->fd, &st) < 0)
1039ed84223SSascha Wildner 			continue;
1049ed84223SSascha Wildner 
1059ed84223SSascha Wildner 		/*
1069ed84223SSascha Wildner 		 * Devices may return a st_size of 0, try to use
1079ed84223SSascha Wildner 		 * lseek.
1089ed84223SSascha Wildner 		 */
1099ed84223SSascha Wildner 		if (st.st_size == 0) {
1109ed84223SSascha Wildner 			st.st_size = lseek(dsk->fd, 0L, SEEK_END);
1119ed84223SSascha Wildner 			if (st.st_size == -1)
1129ed84223SSascha Wildner 				st.st_size = 0;
1139ed84223SSascha Wildner 		}
1149ed84223SSascha Wildner 
1159ed84223SSascha Wildner 		/* and create a new device */
1169ed84223SSascha Wildner 		sc = kmalloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
1179ed84223SSascha Wildner 		sc->unit = dsk->unit;
1189ed84223SSascha Wildner 		sc->fd = dsk->fd;
11954ea00b8SMatthew Dillon 		sc->size = st.st_size;
12054ea00b8SMatthew Dillon 		sc->flags = dsk->flags;
1219ed84223SSascha Wildner 		bioq_init(&sc->bio_queue);
1229ed84223SSascha Wildner 		devstat_add_entry(&sc->stats, "vkd", sc->unit, DEV_BSIZE,
1239ed84223SSascha Wildner 				  DEVSTAT_NO_ORDERED_TAGS,
1249ed84223SSascha Wildner 				  DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_OTHER,
1259ed84223SSascha Wildner 				  DEVSTAT_PRIORITY_DISK);
1269ed84223SSascha Wildner 		sc->dev = disk_create(sc->unit, &sc->disk, &vkd_ops);
1279ed84223SSascha Wildner 		sc->dev->si_drv1 = sc;
128db11ac4fSFrançois Tigeot 		sc->dev->si_iosize_max = min(MAXPHYS,256*1024);
1299ed84223SSascha Wildner 
13054ea00b8SMatthew Dillon 		/*
13154ea00b8SMatthew Dillon 		 * Use a private mmap if COW mode is requested.
13254ea00b8SMatthew Dillon 		 */
13354ea00b8SMatthew Dillon 		if (sc->flags & 1) {
13454ea00b8SMatthew Dillon 			sc->map_buf = mmap(NULL, sc->size,
13554ea00b8SMatthew Dillon 					   PROT_READ|PROT_WRITE,
13654ea00b8SMatthew Dillon 					   MAP_PRIVATE,
13754ea00b8SMatthew Dillon 					   sc->fd, 0);
13854ea00b8SMatthew Dillon 			if ((void *)sc->map_buf == MAP_FAILED) {
139*2c7fc62cSMatthew Dillon 				panic("vkd: cannot mmap %jd MBytes\n",
140*2c7fc62cSMatthew Dillon 				      (intmax_t)sc->size / (1024 * 1024));
14154ea00b8SMatthew Dillon 			}
14254ea00b8SMatthew Dillon 			kprintf("vkd%d: COW disk\n", sc->unit);
14354ea00b8SMatthew Dillon 		}
14454ea00b8SMatthew Dillon 
1459ed84223SSascha Wildner 		TAILQ_INIT(&sc->cotd_queue);
1469ed84223SSascha Wildner 		TAILQ_INIT(&sc->cotd_done);
14754ea00b8SMatthew Dillon 		sc->cotd = cothread_create(vkd_io_thread, vkd_io_intr,
14854ea00b8SMatthew Dillon 					   sc, "vkd");
1499ed84223SSascha Wildner 
1509ed84223SSascha Wildner 		bzero(&info, sizeof(info));
1519ed84223SSascha Wildner 		info.d_media_blksize = DEV_BSIZE;
1529ed84223SSascha Wildner 		info.d_media_blocks = st.st_size / info.d_media_blksize;
1539ed84223SSascha Wildner 
1549ed84223SSascha Wildner 		info.d_nheads = 1;
1559ed84223SSascha Wildner 		info.d_ncylinders = 1;
1569ed84223SSascha Wildner 		info.d_secpertrack = info.d_media_blocks;
1579ed84223SSascha Wildner 		info.d_secpercyl = info.d_secpertrack * info.d_nheads;
1589ed84223SSascha Wildner 
1592a4f37b8SAntonio Huete Jimenez 		if (dsk->serno) {
16054ea00b8SMatthew Dillon 			info.d_serialno =
16154ea00b8SMatthew Dillon 				kmalloc(SERNOLEN, M_TEMP, M_WAITOK | M_ZERO);
1622a4f37b8SAntonio Huete Jimenez 			strlcpy(info.d_serialno, dsk->serno, SERNOLEN);
1632a4f37b8SAntonio Huete Jimenez 		}
1649ed84223SSascha Wildner 		disk_setdiskinfo(&sc->disk, &info);
1657eb18c8eSAntonio Huete Jimenez 
1667eb18c8eSAntonio Huete Jimenez 		/* Announce disk details */
1677eb18c8eSAntonio Huete Jimenez 		kprintf("vkd%d: <Virtual disk> ", i);
1687eb18c8eSAntonio Huete Jimenez 		if (info.d_serialno)
1697eb18c8eSAntonio Huete Jimenez 			kprintf("Serial Number %s", info.d_serialno);
1707eb18c8eSAntonio Huete Jimenez 		kprintf("\nvkd%d: %dMB (%ju %d byte sectors)\n",
17154ea00b8SMatthew Dillon 			i, (int)(st.st_size / 1024 / 1024),
17254ea00b8SMatthew Dillon 			info.d_media_blocks, info.d_media_blksize);
1739ed84223SSascha Wildner 	}
1749ed84223SSascha Wildner }
1759ed84223SSascha Wildner 
1769ed84223SSascha Wildner SYSINIT(vkdisk, SI_SUB_DRIVERS, SI_ORDER_FIRST, vkdinit, NULL);
1779ed84223SSascha Wildner 
1789ed84223SSascha Wildner static int
vkdopen(struct dev_open_args * ap)1799ed84223SSascha Wildner vkdopen(struct dev_open_args *ap)
1809ed84223SSascha Wildner {
1819ed84223SSascha Wildner 	struct vkd_softc *sc;
1829ed84223SSascha Wildner 	/* struct disk_info info; */
1839ed84223SSascha Wildner 	struct stat st;
1849ed84223SSascha Wildner 	cdev_t dev;
1859ed84223SSascha Wildner 
1869ed84223SSascha Wildner 	dev = ap->a_head.a_dev;
1879ed84223SSascha Wildner 	sc = dev->si_drv1;
1889ed84223SSascha Wildner 	if (fstat(sc->fd, &st) < 0)
1899ed84223SSascha Wildner 		return(ENXIO);
1909ed84223SSascha Wildner 
1919ed84223SSascha Wildner 	/*
1929ed84223SSascha Wildner 	 * Devices may return a st_size of 0, try to use
1939ed84223SSascha Wildner 	 * lseek.
1949ed84223SSascha Wildner 	 */
1959ed84223SSascha Wildner 	if (st.st_size == 0) {
1969ed84223SSascha Wildner 		st.st_size = lseek(sc->fd, 0L, SEEK_END);
1979ed84223SSascha Wildner 		if (st.st_size == -1)
1989ed84223SSascha Wildner 			st.st_size = 0;
1999ed84223SSascha Wildner 	}
2009ed84223SSascha Wildner 	if (st.st_size == 0)
2019ed84223SSascha Wildner 		return(ENXIO);
2029ed84223SSascha Wildner 
2039ed84223SSascha Wildner /*
2049ed84223SSascha Wildner 	bzero(&info, sizeof(info));
2059ed84223SSascha Wildner 	info.d_media_blksize = DEV_BSIZE;
2069ed84223SSascha Wildner 	info.d_media_blocks = st.st_size / info.d_media_blksize;
2079ed84223SSascha Wildner 
2089ed84223SSascha Wildner 	info.d_nheads = 1;
2099ed84223SSascha Wildner 	info.d_ncylinders = 1;
2109ed84223SSascha Wildner 	info.d_secpertrack = info.d_media_blocks;
2119ed84223SSascha Wildner 	info.d_secpercyl = info.d_secpertrack * info.d_nheads;
2129ed84223SSascha Wildner 
2139ed84223SSascha Wildner 	disk_setdiskinfo(&sc->disk, &info); */
2149ed84223SSascha Wildner 	return(0);
2159ed84223SSascha Wildner }
2169ed84223SSascha Wildner 
2179ed84223SSascha Wildner static int
vkdstrategy(struct dev_strategy_args * ap)2189ed84223SSascha Wildner vkdstrategy(struct dev_strategy_args *ap)
2199ed84223SSascha Wildner {
2209ed84223SSascha Wildner 	struct bio *bio = ap->a_bio;
2219ed84223SSascha Wildner 	struct vkd_softc *sc;
2229ed84223SSascha Wildner 	cdev_t dev;
2239ed84223SSascha Wildner 
2249ed84223SSascha Wildner 	dev = ap->a_head.a_dev;
2259ed84223SSascha Wildner 	sc = dev->si_drv1;
2269ed84223SSascha Wildner 
2279ed84223SSascha Wildner 	devstat_start_transaction(&sc->stats);
2289ed84223SSascha Wildner 	cothread_lock(sc->cotd, 0);
2299ed84223SSascha Wildner 	TAILQ_INSERT_TAIL(&sc->cotd_queue, bio, bio_act);
2309ed84223SSascha Wildner 	cothread_signal(sc->cotd);
2319ed84223SSascha Wildner 	cothread_unlock(sc->cotd, 0);
2329ed84223SSascha Wildner 
2339ed84223SSascha Wildner 	return(0);
2349ed84223SSascha Wildner }
2359ed84223SSascha Wildner 
2369ed84223SSascha Wildner static
2379ed84223SSascha Wildner void
vkd_io_intr(cothread_t cotd)2389ed84223SSascha Wildner vkd_io_intr(cothread_t cotd)
2399ed84223SSascha Wildner {
2409ed84223SSascha Wildner 	struct vkd_softc *sc;
2419ed84223SSascha Wildner 	struct bio *bio;
2429ed84223SSascha Wildner 	TAILQ_HEAD(, bio) tmpq;
2439ed84223SSascha Wildner 
2449ed84223SSascha Wildner 	sc = cotd->arg;
2459ed84223SSascha Wildner 
2469ed84223SSascha Wildner 	/*
2479ed84223SSascha Wildner 	 * We can't call back into the kernel while holding cothread!
2489ed84223SSascha Wildner 	 */
2499ed84223SSascha Wildner 	TAILQ_INIT(&tmpq);
2509ed84223SSascha Wildner 	cothread_lock(cotd, 0);
2519ed84223SSascha Wildner 	while ((bio = TAILQ_FIRST(&sc->cotd_done)) != NULL) {
2529ed84223SSascha Wildner 		TAILQ_REMOVE(&sc->cotd_done, bio, bio_act);
2539ed84223SSascha Wildner 		TAILQ_INSERT_TAIL(&tmpq, bio, bio_act);
2549ed84223SSascha Wildner 	}
2559ed84223SSascha Wildner 	cothread_unlock(cotd, 0);
2569ed84223SSascha Wildner 
2579ed84223SSascha Wildner 	while ((bio = TAILQ_FIRST(&tmpq)) != NULL) {
2589ed84223SSascha Wildner 		TAILQ_REMOVE(&tmpq, bio, bio_act);
2599ed84223SSascha Wildner 		devstat_end_transaction_buf(&sc->stats, bio->bio_buf);
2609ed84223SSascha Wildner 		biodone(bio);
2619ed84223SSascha Wildner 	}
2629ed84223SSascha Wildner }
2639ed84223SSascha Wildner 
2649ed84223SSascha Wildner /*
2659ed84223SSascha Wildner  * WARNING!  This runs as a cothread and has no access to mycpu nor can it
2669ed84223SSascha Wildner  * make vkernel-specific calls other then cothread_*() calls.
2679ed84223SSascha Wildner  *
2689ed84223SSascha Wildner  * WARNING!  A signal can occur and be discarded prior to our initial
2699ed84223SSascha Wildner  * call to cothread_lock().  Process pending I/O before waiting.
2709ed84223SSascha Wildner  */
2719ed84223SSascha Wildner static
2729ed84223SSascha Wildner void
vkd_io_thread(cothread_t cotd)2739ed84223SSascha Wildner vkd_io_thread(cothread_t cotd)
2749ed84223SSascha Wildner {
2759ed84223SSascha Wildner 	struct bio *bio;
2769ed84223SSascha Wildner 	struct vkd_softc *sc = cotd->arg;
2779ed84223SSascha Wildner 	int count;
2789ed84223SSascha Wildner 
2799ed84223SSascha Wildner 	cothread_lock(cotd, 1);
2809ed84223SSascha Wildner 	for (;;) {
2819ed84223SSascha Wildner 		count = 0;
2829ed84223SSascha Wildner 		while ((bio = TAILQ_FIRST(&sc->cotd_queue)) != NULL) {
2839ed84223SSascha Wildner 			TAILQ_REMOVE(&sc->cotd_queue, bio, bio_act);
2849ed84223SSascha Wildner 			cothread_unlock(cotd, 1);
2859ed84223SSascha Wildner 			vkd_doio(sc, bio);
2869ed84223SSascha Wildner 			cothread_lock(cotd, 1);
2879ed84223SSascha Wildner 			TAILQ_INSERT_TAIL(&sc->cotd_done, bio, bio_act);
2889ed84223SSascha Wildner 			if (++count == 8) {
2899ed84223SSascha Wildner 				cothread_intr(cotd);
2909ed84223SSascha Wildner 				count = 0;
2919ed84223SSascha Wildner 			}
2929ed84223SSascha Wildner 		}
2939ed84223SSascha Wildner 		if (count)
2949ed84223SSascha Wildner 			cothread_intr(cotd);
2959ed84223SSascha Wildner 		cothread_wait(cotd);	/* interlocks cothread lock */
2969ed84223SSascha Wildner 	}
2979ed84223SSascha Wildner 	/* NOT REACHED */
2989ed84223SSascha Wildner 	cothread_unlock(cotd, 1);
2999ed84223SSascha Wildner }
3009ed84223SSascha Wildner 
3019ed84223SSascha Wildner static
3029ed84223SSascha Wildner void
vkd_doio(struct vkd_softc * sc,struct bio * bio)3039ed84223SSascha Wildner vkd_doio(struct vkd_softc *sc, struct bio *bio)
3049ed84223SSascha Wildner {
3059ed84223SSascha Wildner 	struct buf *bp = bio->bio_buf;
3069ed84223SSascha Wildner 	int n;
3079ed84223SSascha Wildner 
3089ed84223SSascha Wildner 	switch(bp->b_cmd) {
3099ed84223SSascha Wildner 	case BUF_CMD_READ:
31054ea00b8SMatthew Dillon 		if (sc->map_buf) {
31154ea00b8SMatthew Dillon 			bcopy(sc->map_buf + bio->bio_offset,
31254ea00b8SMatthew Dillon 			      bp->b_data,
31354ea00b8SMatthew Dillon 			      bp->b_bcount);
31454ea00b8SMatthew Dillon 			n = bp->b_bcount;
31554ea00b8SMatthew Dillon 		} else {
31654ea00b8SMatthew Dillon 			n = pread(sc->fd, bp->b_data, bp->b_bcount,
31754ea00b8SMatthew Dillon 				  bio->bio_offset);
31854ea00b8SMatthew Dillon 		}
3199ed84223SSascha Wildner 		break;
3209ed84223SSascha Wildner 	case BUF_CMD_WRITE:
3219ed84223SSascha Wildner 		/* XXX HANDLE SHORT WRITE XXX */
32254ea00b8SMatthew Dillon 		if (sc->map_buf) {
32354ea00b8SMatthew Dillon 			bcopy(bp->b_data,
32454ea00b8SMatthew Dillon 			      sc->map_buf + bio->bio_offset,
32554ea00b8SMatthew Dillon 			      bp->b_bcount);
32654ea00b8SMatthew Dillon 			n = bp->b_bcount;
32754ea00b8SMatthew Dillon 		} else {
32854ea00b8SMatthew Dillon 			n = pwrite(sc->fd, bp->b_data, bp->b_bcount,
32954ea00b8SMatthew Dillon 				   bio->bio_offset);
33054ea00b8SMatthew Dillon 		}
3319ed84223SSascha Wildner 		break;
3329ed84223SSascha Wildner 	case BUF_CMD_FLUSH:
33354ea00b8SMatthew Dillon 		if (sc->map_buf == NULL && fsync(sc->fd) < 0)
3349ed84223SSascha Wildner 			n = -1;
3359ed84223SSascha Wildner 		else
3369ed84223SSascha Wildner 			n = bp->b_bcount;
3379ed84223SSascha Wildner 		break;
3389ed84223SSascha Wildner 	default:
3399ed84223SSascha Wildner 		panic("vkd: bad b_cmd %d", bp->b_cmd);
3409ed84223SSascha Wildner 		break; /* not reached */
3419ed84223SSascha Wildner 	}
34254ea00b8SMatthew Dillon 	if (bp->b_bcount != n) {
3439ed84223SSascha Wildner 		bp->b_error = EIO;
3449ed84223SSascha Wildner 		bp->b_flags |= B_ERROR;
3459ed84223SSascha Wildner 	}
3469ed84223SSascha Wildner 	bp->b_resid = bp->b_bcount - n;
3479ed84223SSascha Wildner }
348