示例#1
0
/*
 * Read a cluster from the snapshotted block device to the cache.
 */
static int
fss_read_cluster(struct fss_softc *sc, u_int32_t cl)
{
	int error, todo, offset, len;
	daddr_t dblk;
	struct buf *bp, *mbp;
	struct fss_cache *scp, *scl;

	/*
	 * Get a free cache slot.
	 */
	scl = sc->sc_cache+sc->sc_cache_size;

	mutex_enter(&sc->sc_slock);

restart:
	if (isset(sc->sc_copied, cl) || !FSS_ISVALID(sc)) {
		mutex_exit(&sc->sc_slock);
		return 0;
	}

	for (scp = sc->sc_cache; scp < scl; scp++)
		if (scp->fc_cluster == cl) {
			if (scp->fc_type == FSS_CACHE_VALID) {
				mutex_exit(&sc->sc_slock);
				return 0;
			} else if (scp->fc_type == FSS_CACHE_BUSY) {
				cv_wait(&scp->fc_state_cv, &sc->sc_slock);
				goto restart;
			}
		}

	for (scp = sc->sc_cache; scp < scl; scp++)
		if (scp->fc_type == FSS_CACHE_FREE) {
			scp->fc_type = FSS_CACHE_BUSY;
			scp->fc_cluster = cl;
			break;
		}
	if (scp >= scl) {
		cv_wait(&sc->sc_cache_cv, &sc->sc_slock);
		goto restart;
	}

	mutex_exit(&sc->sc_slock);

	/*
	 * Start the read.
	 */
	dblk = btodb(FSS_CLTOB(sc, cl));
	if (cl == sc->sc_clcount-1) {
		todo = sc->sc_clresid;
		memset((char *)scp->fc_data + todo, 0, FSS_CLSIZE(sc) - todo);
	} else
		todo = FSS_CLSIZE(sc);
	offset = 0;
	mbp = getiobuf(NULL, true);
	mbp->b_bufsize = todo;
	mbp->b_data = scp->fc_data;
	mbp->b_resid = mbp->b_bcount = todo;
	mbp->b_flags = B_READ;
	mbp->b_cflags = BC_BUSY;
	mbp->b_dev = sc->sc_bdev;
	while (todo > 0) {
		len = todo;
		if (len > MAXPHYS)
			len = MAXPHYS;
		if (btodb(FSS_CLTOB(sc, cl)) == dblk && len == todo)
			bp = mbp;
		else {
			bp = getiobuf(NULL, true);
			nestiobuf_setup(mbp, bp, offset, len);
		}
		bp->b_lblkno = 0;
		bp->b_blkno = dblk;
		bdev_strategy(bp);
		dblk += btodb(len);
		offset += len;
		todo -= len;
	}
	error = biowait(mbp);
	putiobuf(mbp);

	mutex_enter(&sc->sc_slock);
	scp->fc_type = (error ? FSS_CACHE_FREE : FSS_CACHE_VALID);
	cv_broadcast(&scp->fc_state_cv);
	if (error == 0) {
		setbit(sc->sc_copied, scp->fc_cluster);
		cv_signal(&sc->sc_work_cv);
	}
	mutex_exit(&sc->sc_slock);

	return error;
}
示例#2
0
/*
 * Handes the read/write request given in 'bp' using the vnode's VOP_BMAP
 * and VOP_STRATEGY operations.
 *
 * 'obp' is a pointer to the original request fed to the vnd device.
 */
static void
handle_with_strategy(struct vnd_softc *vnd, const struct buf *obp,
    struct buf *bp)
{
	int bsize, error, flags, skipped;
	size_t resid, sz;
	off_t bn, offset;
	struct vnode *vp;

	flags = obp->b_flags;

	if (!(flags & B_READ)) {
		vp = bp->b_vp;
		mutex_enter(vp->v_interlock);
		vp->v_numoutput++;
		mutex_exit(vp->v_interlock);
	}

	/* convert to a byte offset within the file. */
	bn = obp->b_rawblkno * vnd->sc_dkdev.dk_label->d_secsize;

	bsize = vnd->sc_vp->v_mount->mnt_stat.f_iosize;
	skipped = 0;

	/*
	 * Break the request into bsize pieces and feed them
	 * sequentially using VOP_BMAP/VOP_STRATEGY.
	 * We do it this way to keep from flooding NFS servers if we
	 * are connected to an NFS file.  This places the burden on
	 * the client rather than the server.
	 */
	error = 0;
	bp->b_resid = bp->b_bcount;
	for (offset = 0, resid = bp->b_resid; resid;
	    resid -= sz, offset += sz) {
		struct buf *nbp;
		daddr_t nbn;
		int off, nra;

		nra = 0;
		vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY);
		error = VOP_BMAP(vnd->sc_vp, bn / bsize, &vp, &nbn, &nra);
		VOP_UNLOCK(vnd->sc_vp);

		if (error == 0 && (long)nbn == -1)
			error = EIO;

		/*
		 * If there was an error or a hole in the file...punt.
		 * Note that we may have to wait for any operations
		 * that we have already fired off before releasing
		 * the buffer.
		 *
		 * XXX we could deal with holes here but it would be
		 * a hassle (in the write case).
		 */
		if (error) {
			skipped += resid;
			break;
		}

#ifdef DEBUG
		if (!dovndcluster)
			nra = 0;
#endif

		off = bn % bsize;
		sz = MIN(((off_t)1 + nra) * bsize - off, resid);
#ifdef	DEBUG
		if (vnddebug & VDB_IO)
			printf("vndstrategy: vp %p/%p bn 0x%qx/0x%" PRIx64
			    " sz 0x%zx\n", vnd->sc_vp, vp, (long long)bn,
			    nbn, sz);
#endif

		nbp = getiobuf(vp, true);
		nestiobuf_setup(bp, nbp, offset, sz);
		nbp->b_blkno = nbn + btodb(off);

#if 0 /* XXX #ifdef DEBUG */
		if (vnddebug & VDB_IO)
			printf("vndstart(%ld): bp %p vp %p blkno "
			    "0x%" PRIx64 " flags %x addr %p cnt 0x%x\n",
			    (long) (vnd-vnd_softc), &nbp->vb_buf,
			    nbp->vb_buf.b_vp, nbp->vb_buf.b_blkno,
			    nbp->vb_buf.b_flags, nbp->vb_buf.b_data,
			    nbp->vb_buf.b_bcount);
#endif
		VOP_STRATEGY(vp, nbp);
		bn += sz;
	}
	nestiobuf_done(bp, skipped, error);
}