예제 #1
0
static int
dk_translate(struct dk_softc *dksc, struct buf *bp)
{
	int	part;
	int	wlabel;
	daddr_t	blkno;
	struct disklabel *lp;
	struct disk *dk;
	uint64_t numsecs;
	unsigned secsize;

	lp = dksc->sc_dkdev.dk_label;
	dk = &dksc->sc_dkdev;

	part = DISKPART(bp->b_dev);
	numsecs = dk->dk_geom.dg_secperunit;
	secsize = dk->dk_geom.dg_secsize;

	/*
	 * The transfer must be a whole number of blocks and the offset must
	 * not be negative.
	 */
	if ((bp->b_bcount % secsize) != 0 || bp->b_blkno < 0) {
		bp->b_error = EINVAL;
		goto done;
	}

	/* If there is nothing to do, then we are done */
	if (bp->b_bcount == 0)
		goto done;

	wlabel = dksc->sc_flags & (DKF_WLABEL|DKF_LABELLING);
	if (part == RAW_PART) {
		uint64_t numblocks = btodb(numsecs * secsize);
		if (bounds_check_with_mediasize(bp, DEV_BSIZE, numblocks) <= 0)
			goto done;
	} else {
		if (bounds_check_with_label(&dksc->sc_dkdev, bp, wlabel) <= 0)
			goto done;
	}

	/*
	 * Convert the block number to absolute and put it in terms
	 * of the device's logical block size.
	 */
	if (secsize >= DEV_BSIZE)
		blkno = bp->b_blkno / (secsize / DEV_BSIZE);
	else
		blkno = bp->b_blkno * (DEV_BSIZE / secsize);

	if (part != RAW_PART)
		blkno += lp->d_partitions[DISKPART(bp->b_dev)].p_offset;
	bp->b_rawblkno = blkno;

	return -1;

done:
	bp->b_resid = bp->b_bcount;
	return bp->b_error;
}
예제 #2
0
파일: flash.c 프로젝트: goroutines/rumprun
void
flashstrategy(struct buf * const bp)
{
	struct flash_softc *sc;
	const struct flash_interface *flash_if;
	const struct flash_partition *part;
	int unit, device_blks;

	unit = minor(bp->b_dev);
	sc = device_lookup_private(&flash_cd, unit);
	if (sc == NULL) {
		bp->b_error = ENXIO;
		goto done;
	}

	flash_if = sc->flash_if;
	part = &sc->sc_partinfo;

	/* divider */
	KASSERT(flash_if->writesize != 0);

	aprint_debug_dev(sc->sc_dev, "flash_strategy()\n");

	if (!(bp->b_flags & B_READ) && sc->sc_readonly) {
		bp->b_error = EACCES;
		goto done;
	}

	/* check if length is not negative */
	if (bp->b_blkno < 0) {
		bp->b_error = EINVAL;
		goto done;
	}

	/* zero lenght i/o */
	if (bp->b_bcount == 0) {
		goto done;
	}

	device_blks = sc->sc_partinfo.part_size / DEV_BSIZE;
	KASSERT(part->part_offset % DEV_BSIZE == 0);
	bp->b_rawblkno = bp->b_blkno + (part->part_offset / DEV_BSIZE);

	if (bounds_check_with_mediasize(bp, DEV_BSIZE, device_blks) <= 0) {
		goto done;
	}

	bp->b_resid = bp->b_bcount;
	flash_if->submit(sc->sc_parent_dev, bp);

	return;
done:
	bp->b_resid = bp->b_bcount;
	biodone(bp);
}
예제 #3
0
/*
 * Do all IO operations on dm logical devices.
 */
static int
dmstrategy(struct dev_strategy_args *ap)
{
	cdev_t dev = ap->a_head.a_dev;
	struct bio *bio = ap->a_bio;
	struct buf *bp = bio->bio_buf;
	int bypass;

	dm_dev_t *dmv;
	dm_table_t  *tbl;
	dm_table_entry_t *table_en;
	struct buf *nestbuf;

	uint32_t dev_type;

	uint64_t buf_start, buf_len, issued_len;
	uint64_t table_start, table_end;
	uint64_t start, end;

	buf_start = bio->bio_offset;
	buf_len = bp->b_bcount;

	tbl = NULL;

	table_end = 0;
	dev_type = 0;
	issued_len = 0;

	dmv = dev->si_drv1;

	switch(bp->b_cmd) {
	case BUF_CMD_READ:
	case BUF_CMD_WRITE:
	case BUF_CMD_FREEBLKS:
		bypass = 0;
		break;
	case BUF_CMD_FLUSH:
		bypass = 1;
		KKASSERT(buf_len == 0);
		break;
	default:
		bp->b_error = EIO;
		bp->b_resid = bp->b_bcount;
		biodone(bio);
		return 0;
	}

	if (bypass == 0 &&
	    bounds_check_with_mediasize(bio, DEV_BSIZE,
					dm_table_size(&dmv->table_head)) <= 0) {
		bp->b_resid = bp->b_bcount;
		biodone(bio);
		return 0;
	}

	/* Select active table */
	tbl = dm_table_get_entry(&dmv->table_head, DM_TABLE_ACTIVE);

	nestiobuf_init(bio);
	devstat_start_transaction(&dmv->stats);

	/*
	 * Find out what tables I want to select.
	 */
	SLIST_FOREACH(table_en, tbl, next) {
		/*
		 * I need need number of bytes not blocks.
		 */
		table_start = table_en->start * DEV_BSIZE;
		table_end = table_start + (table_en->length) * DEV_BSIZE;

		/*
		 * Calculate the start and end
		 */
		start = MAX(table_start, buf_start);
		end = MIN(table_end, buf_start + buf_len);

		aprint_debug("----------------------------------------\n");
		aprint_debug("table_start %010" PRIu64", table_end %010"
		    PRIu64 "\n", table_start, table_end);
		aprint_debug("buf_start %010" PRIu64", buf_len %010"
		    PRIu64"\n", buf_start, buf_len);
		aprint_debug("start-buf_start %010"PRIu64", end %010"
		    PRIu64"\n", start - buf_start, end);
		aprint_debug("start %010" PRIu64" , end %010"
                    PRIu64"\n", start, end);
		aprint_debug("\n----------------------------------------\n");

		if (bypass) {
			nestbuf = getpbuf(NULL);
			nestbuf->b_flags |= bio->bio_buf->b_flags & B_HASBOGUS;

			nestiobuf_add(bio, nestbuf, 0, 0, &dmv->stats);
			nestbuf->b_bio1.bio_offset = 0;
			table_en->target->strategy(table_en, nestbuf);
		} else if (start < end) {
			nestbuf = getpbuf(NULL);
			nestbuf->b_flags |= bio->bio_buf->b_flags & B_HASBOGUS;

			nestiobuf_add(bio, nestbuf,
				      start - buf_start, (end - start),
				      &dmv->stats);
			issued_len += end - start;

			nestbuf->b_bio1.bio_offset = (start - table_start);
			table_en->target->strategy(table_en, nestbuf);
		}
	}
예제 #4
0
/*
 * Queue the request, and wakeup the kernel thread to handle it.
 */
static void
vndstrategy(struct buf *bp)
{
	int unit = vndunit(bp->b_dev);
	struct vnd_softc *vnd =
	    device_lookup_private(&vnd_cd, unit);
	struct disklabel *lp;
	daddr_t blkno;
	int s = splbio();

	if (vnd == NULL) {
		bp->b_error = ENXIO;
		goto done;
	}
	lp = vnd->sc_dkdev.dk_label;

	if ((vnd->sc_flags & VNF_INITED) == 0) {
		bp->b_error = ENXIO;
		goto done;
	}

	/*
	 * The transfer must be a whole number of blocks.
	 */
	if ((bp->b_bcount % lp->d_secsize) != 0) {
		bp->b_error = EINVAL;
		goto done;
	}

	/*
	 * check if we're read-only.
	 */
	if ((vnd->sc_flags & VNF_READONLY) && !(bp->b_flags & B_READ)) {
		bp->b_error = EACCES;
		goto done;
	}

	/* If it's a nil transfer, wake up the top half now. */
	if (bp->b_bcount == 0) {
		goto done;
	}

	/*
	 * Do bounds checking and adjust transfer.  If there's an error,
	 * the bounds check will flag that for us.
	 */
	if (DISKPART(bp->b_dev) == RAW_PART) {
		if (bounds_check_with_mediasize(bp, DEV_BSIZE,
		    vnd->sc_size) <= 0)
			goto done;
	} else {
		if (bounds_check_with_label(&vnd->sc_dkdev,
		    bp, vnd->sc_flags & (VNF_WLABEL|VNF_LABELLING)) <= 0)
			goto done;
	}

	/*
	 * Put the block number in terms of the logical blocksize
	 * of the "device".
	 */

	blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE);

	/*
	 * Translate the partition-relative block number to an absolute.
	 */
	if (DISKPART(bp->b_dev) != RAW_PART) {
		struct partition *pp;

		pp = &vnd->sc_dkdev.dk_label->d_partitions[
		    DISKPART(bp->b_dev)];
		blkno += pp->p_offset;
	}
	bp->b_rawblkno = blkno;

#ifdef DEBUG
	if (vnddebug & VDB_FOLLOW)
		printf("vndstrategy(%p): unit %d\n", bp, unit);
#endif
	if ((vnd->sc_flags & VNF_USE_VN_RDWR)) {
		KASSERT(vnd->sc_pending >= 0 &&
		    vnd->sc_pending <= VND_MAXPENDING(vnd));
		while (vnd->sc_pending == VND_MAXPENDING(vnd))
			tsleep(&vnd->sc_pending, PRIBIO, "vndpc", 0);
		vnd->sc_pending++;
	}
	bufq_put(vnd->sc_tab, bp);
	wakeup(&vnd->sc_tab);
	splx(s);
	return;

done:
	bp->b_resid = bp->b_bcount;
	biodone(bp);
	splx(s);
}