Make vnd do I/O to the underlying file from thread context. This
allows the strategy routine to be called from interrupt context, fixes PR kern/29775 by Juan RP. Now that pool_get() is only called from thread context, change PR_NOWAIT to PR_WAITOK. Fix PR kern/26272 by Juergen Hannken-Illjes. OK'd by thorpej@
This commit is contained in:
parent
7174de81d3
commit
007f04c4a8
455
sys/dev/vnd.c
455
sys/dev/vnd.c
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: vnd.c,v 1.111 2004/10/28 07:07:39 yamt Exp $ */
|
/* $NetBSD: vnd.c,v 1.112 2005/03/30 19:23:08 bouyer Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
|
* Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
|
||||||
@ -133,7 +133,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__KERNEL_RCSID(0, "$NetBSD: vnd.c,v 1.111 2004/10/28 07:07:39 yamt Exp $");
|
__KERNEL_RCSID(0, "$NetBSD: vnd.c,v 1.112 2005/03/30 19:23:08 bouyer Exp $");
|
||||||
|
|
||||||
#if defined(_KERNEL_OPT)
|
#if defined(_KERNEL_OPT)
|
||||||
#include "fs_nfs.h"
|
#include "fs_nfs.h"
|
||||||
@ -143,6 +143,7 @@ __KERNEL_RCSID(0, "$NetBSD: vnd.c,v 1.111 2004/10/28 07:07:39 yamt Exp $");
|
|||||||
#include <sys/systm.h>
|
#include <sys/systm.h>
|
||||||
#include <sys/namei.h>
|
#include <sys/namei.h>
|
||||||
#include <sys/proc.h>
|
#include <sys/proc.h>
|
||||||
|
#include <sys/kthread.h>
|
||||||
#include <sys/errno.h>
|
#include <sys/errno.h>
|
||||||
#include <sys/buf.h>
|
#include <sys/buf.h>
|
||||||
#include <sys/bufq.h>
|
#include <sys/bufq.h>
|
||||||
@ -190,10 +191,10 @@ struct vndbuf {
|
|||||||
struct vndxfer *vb_xfer;
|
struct vndxfer *vb_xfer;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define VND_GETXFER(vnd) pool_get(&(vnd)->sc_vxpool, PR_NOWAIT)
|
#define VND_GETXFER(vnd) pool_get(&(vnd)->sc_vxpool, PR_WAITOK)
|
||||||
#define VND_PUTXFER(vnd, vx) pool_put(&(vnd)->sc_vxpool, (vx))
|
#define VND_PUTXFER(vnd, vx) pool_put(&(vnd)->sc_vxpool, (vx))
|
||||||
|
|
||||||
#define VND_GETBUF(vnd) pool_get(&(vnd)->sc_vbpool, PR_NOWAIT)
|
#define VND_GETBUF(vnd) pool_get(&(vnd)->sc_vbpool, PR_WAITOK)
|
||||||
#define VND_PUTBUF(vnd, vb) pool_put(&(vnd)->sc_vbpool, (vb))
|
#define VND_PUTBUF(vnd, vb) pool_put(&(vnd)->sc_vbpool, (vb))
|
||||||
|
|
||||||
struct vnd_softc *vnd_softc;
|
struct vnd_softc *vnd_softc;
|
||||||
@ -207,7 +208,6 @@ void vndattach(int);
|
|||||||
int vnddetach(void);
|
int vnddetach(void);
|
||||||
|
|
||||||
static void vndclear(struct vnd_softc *, int);
|
static void vndclear(struct vnd_softc *, int);
|
||||||
static void vndstart(struct vnd_softc *);
|
|
||||||
static int vndsetcred(struct vnd_softc *, struct ucred *);
|
static int vndsetcred(struct vnd_softc *, struct ucred *);
|
||||||
static void vndthrottle(struct vnd_softc *, struct vnode *);
|
static void vndthrottle(struct vnd_softc *, struct vnode *);
|
||||||
static void vndiodone(struct buf *);
|
static void vndiodone(struct buf *);
|
||||||
@ -221,6 +221,8 @@ static void vndgetdisklabel(dev_t);
|
|||||||
static int vndlock(struct vnd_softc *);
|
static int vndlock(struct vnd_softc *);
|
||||||
static void vndunlock(struct vnd_softc *);
|
static void vndunlock(struct vnd_softc *);
|
||||||
|
|
||||||
|
void vndthread(void *);
|
||||||
|
|
||||||
static dev_type_open(vndopen);
|
static dev_type_open(vndopen);
|
||||||
static dev_type_close(vndclose);
|
static dev_type_close(vndclose);
|
||||||
static dev_type_read(vndread);
|
static dev_type_read(vndread);
|
||||||
@ -393,38 +395,24 @@ vndclose(dev_t dev, int flags, int mode, struct proc *p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Break the request into bsize pieces and submit using VOP_BMAP/VOP_STRATEGY.
|
* Qeue the request, and wakeup the kernel thread to handle it.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
vndstrategy(struct buf *bp)
|
vndstrategy(struct buf *bp)
|
||||||
{
|
{
|
||||||
int unit = vndunit(bp->b_dev);
|
int unit = vndunit(bp->b_dev);
|
||||||
struct vnd_softc *vnd = &vnd_softc[unit];
|
struct vnd_softc *vnd = &vnd_softc[unit];
|
||||||
struct vndxfer *vnx;
|
struct disklabel *lp = vnd->sc_dkdev.dk_label;
|
||||||
struct mount *mp;
|
int s = splbio();
|
||||||
int s, bsize, resid;
|
|
||||||
off_t bn;
|
bp->b_resid = bp->b_bcount;
|
||||||
caddr_t addr;
|
|
||||||
int sz, flags, error, wlabel;
|
|
||||||
struct disklabel *lp;
|
|
||||||
struct partition *pp;
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
if (vnddebug & VDB_FOLLOW)
|
|
||||||
printf("vndstrategy(%p): unit %d\n", bp, unit);
|
|
||||||
#endif
|
|
||||||
if ((vnd->sc_flags & VNF_INITED) == 0) {
|
if ((vnd->sc_flags & VNF_INITED) == 0) {
|
||||||
bp->b_error = ENXIO;
|
bp->b_error = ENXIO;
|
||||||
bp->b_flags |= B_ERROR;
|
bp->b_flags |= B_ERROR;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If it's a nil transfer, wake up the top half now. */
|
|
||||||
if (bp->b_bcount == 0)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
lp = vnd->sc_dkdev.dk_label;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The transfer must be a whole number of blocks.
|
* The transfer must be a whole number of blocks.
|
||||||
*/
|
*/
|
||||||
@ -434,15 +422,6 @@ vndstrategy(struct buf *bp)
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Do bounds checking and adjust transfer. If there's an error,
|
|
||||||
* the bounds check will flag that for us.
|
|
||||||
*/
|
|
||||||
wlabel = vnd->sc_flags & (VNF_WLABEL|VNF_LABELLING);
|
|
||||||
if (DISKPART(bp->b_dev) != RAW_PART)
|
|
||||||
if (bounds_check_with_label(&vnd->sc_dkdev, bp, wlabel) <= 0)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* check if we're read-only.
|
* check if we're read-only.
|
||||||
*/
|
*/
|
||||||
@ -452,194 +431,249 @@ vndstrategy(struct buf *bp)
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
bp->b_resid = bp->b_bcount;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Put the block number in terms of the logical blocksize
|
* Do bounds checking and adjust transfer. If there's an error,
|
||||||
* of the "device".
|
* the bounds check will flag that for us.
|
||||||
*/
|
|
||||||
bn = bp->b_blkno / (lp->d_secsize / DEV_BSIZE);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Translate the partition-relative block number to an absolute.
|
|
||||||
*/
|
*/
|
||||||
if (DISKPART(bp->b_dev) != RAW_PART) {
|
if (DISKPART(bp->b_dev) != RAW_PART) {
|
||||||
pp = &vnd->sc_dkdev.dk_label->d_partitions[DISKPART(bp->b_dev)];
|
if (bounds_check_with_label(&vnd->sc_dkdev,
|
||||||
bn += pp->p_offset;
|
bp, vnd->sc_flags & (VNF_WLABEL|VNF_LABELLING)) <= 0)
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ...and convert to a byte offset within the file. */
|
/* If it's a nil transfer, wake up the top half now. */
|
||||||
bn *= lp->d_secsize;
|
if (bp->b_bcount == 0)
|
||||||
|
|
||||||
if (vnd->sc_vp->v_mount == NULL) {
|
|
||||||
bp->b_error = ENXIO;
|
|
||||||
bp->b_flags |= B_ERROR;
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
|
||||||
bsize = vnd->sc_vp->v_mount->mnt_stat.f_iosize;
|
|
||||||
addr = bp->b_data;
|
|
||||||
flags = (bp->b_flags & (B_READ|B_ASYNC)) | B_CALL;
|
|
||||||
|
|
||||||
/* Allocate a header for this transfer and link it to the buffer */
|
|
||||||
s = splbio();
|
|
||||||
vnx = VND_GETXFER(vnd);
|
|
||||||
splx(s);
|
|
||||||
vnx->vx_flags = VX_BUSY;
|
|
||||||
vnx->vx_error = 0;
|
|
||||||
vnx->vx_pending = 0;
|
|
||||||
vnx->vx_bp = bp;
|
|
||||||
|
|
||||||
if ((flags & B_READ) == 0)
|
|
||||||
vn_start_write(vnd->sc_vp, &mp, V_WAIT);
|
|
||||||
|
|
||||||
for (resid = bp->b_resid; resid; resid -= sz) {
|
|
||||||
struct vndbuf *nbp;
|
|
||||||
struct vnode *vp;
|
|
||||||
daddr_t nbn;
|
|
||||||
int off, nra;
|
|
||||||
|
|
||||||
nra = 0;
|
|
||||||
vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY | LK_CANRECURSE);
|
|
||||||
error = VOP_BMAP(vnd->sc_vp, bn / bsize, &vp, &nbn, &nra);
|
|
||||||
VOP_UNLOCK(vnd->sc_vp, 0);
|
|
||||||
|
|
||||||
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) {
|
|
||||||
s = splbio();
|
|
||||||
vnx->vx_error = error;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (!dovndcluster)
|
if (vnddebug & VDB_FOLLOW)
|
||||||
nra = 0;
|
printf("vndstrategy(%p): unit %d\n", bp, unit);
|
||||||
#endif
|
#endif
|
||||||
|
BUFQ_PUT(&vnd->sc_tab, bp);
|
||||||
if ((off = bn % bsize) != 0)
|
wakeup(&vnd->sc_tab);
|
||||||
sz = bsize - off;
|
|
||||||
else
|
|
||||||
sz = (1 + nra) * bsize;
|
|
||||||
if (resid < sz)
|
|
||||||
sz = resid;
|
|
||||||
#ifdef DEBUG
|
|
||||||
if (vnddebug & VDB_IO)
|
|
||||||
printf("vndstrategy: vp %p/%p bn 0x%qx/0x%" PRIx64
|
|
||||||
" sz 0x%x\n",
|
|
||||||
vnd->sc_vp, vp, (long long)bn, nbn, sz);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
s = splbio();
|
|
||||||
nbp = VND_GETBUF(vnd);
|
|
||||||
splx(s);
|
|
||||||
BUF_INIT(&nbp->vb_buf);
|
|
||||||
nbp->vb_buf.b_flags = flags;
|
|
||||||
nbp->vb_buf.b_bcount = sz;
|
|
||||||
nbp->vb_buf.b_bufsize = round_page((ulong)addr + sz)
|
|
||||||
- trunc_page((ulong) addr);
|
|
||||||
nbp->vb_buf.b_error = 0;
|
|
||||||
nbp->vb_buf.b_data = addr;
|
|
||||||
nbp->vb_buf.b_blkno = nbp->vb_buf.b_rawblkno = nbn + btodb(off);
|
|
||||||
nbp->vb_buf.b_proc = bp->b_proc;
|
|
||||||
nbp->vb_buf.b_iodone = vndiodone;
|
|
||||||
nbp->vb_buf.b_vp = vp;
|
|
||||||
|
|
||||||
nbp->vb_xfer = vnx;
|
|
||||||
|
|
||||||
BIO_COPYPRIO(&nbp->vb_buf, bp);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Just sort by block number
|
|
||||||
*/
|
|
||||||
s = splbio();
|
|
||||||
if (vnx->vx_error != 0) {
|
|
||||||
VND_PUTBUF(vnd, nbp);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
vnx->vx_pending++;
|
|
||||||
|
|
||||||
BUFQ_PUT(&vnd->sc_tab, &nbp->vb_buf);
|
|
||||||
vndstart(vnd);
|
|
||||||
splx(s);
|
|
||||||
bn += sz;
|
|
||||||
addr += sz;
|
|
||||||
}
|
|
||||||
|
|
||||||
s = splbio();
|
|
||||||
|
|
||||||
out: /* Arrive here at splbio */
|
|
||||||
if ((flags & B_READ) == 0)
|
|
||||||
vn_finished_write(mp, 0);
|
|
||||||
vnx->vx_flags &= ~VX_BUSY;
|
|
||||||
if (vnx->vx_pending == 0) {
|
|
||||||
if (vnx->vx_error != 0) {
|
|
||||||
bp->b_error = vnx->vx_error;
|
|
||||||
bp->b_flags |= B_ERROR;
|
|
||||||
}
|
|
||||||
VND_PUTXFER(vnd, vnx);
|
|
||||||
biodone(bp);
|
|
||||||
}
|
|
||||||
splx(s);
|
splx(s);
|
||||||
return;
|
return;
|
||||||
|
done:
|
||||||
done:
|
|
||||||
biodone(bp);
|
biodone(bp);
|
||||||
|
splx(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void
|
||||||
* Feed requests sequentially.
|
vndthread(void *arg)
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
vndstart(struct vnd_softc *vnd)
|
|
||||||
{
|
{
|
||||||
struct buf *bp;
|
struct vnd_softc *vnd = arg;
|
||||||
|
struct buf *bp;
|
||||||
|
struct vndxfer *vnx;
|
||||||
|
struct mount *mp;
|
||||||
|
int s, bsize, resid;
|
||||||
|
off_t bn;
|
||||||
|
caddr_t addr;
|
||||||
|
int sz, flags, error;
|
||||||
|
struct disklabel *lp;
|
||||||
|
struct partition *pp;
|
||||||
|
|
||||||
|
s = splbio();
|
||||||
|
vnd->sc_flags |= VNF_KTHREAD;
|
||||||
|
wakeup(&vnd->sc_kthread);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Dequeue now since lower level strategy routine might
|
* Dequeue requests, break them into bsize pieces and submit using
|
||||||
* queue using same links
|
* VOP_BMAP/VOP_STRATEGY.
|
||||||
*/
|
*/
|
||||||
|
while ((vnd->sc_flags & VNF_VUNCONF) == 0) {
|
||||||
if ((vnd->sc_flags & VNF_BUSY) != 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
vnd->sc_flags |= VNF_BUSY;
|
|
||||||
|
|
||||||
while (vnd->sc_active < vnd->sc_maxactive) {
|
|
||||||
bp = BUFQ_GET(&vnd->sc_tab);
|
bp = BUFQ_GET(&vnd->sc_tab);
|
||||||
if (bp == NULL)
|
if (bp == NULL) {
|
||||||
break;
|
tsleep(&vnd->sc_tab, PRIBIO, "vndbp", 0);
|
||||||
vnd->sc_active++;
|
continue;
|
||||||
|
};
|
||||||
|
splx(s);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (vnddebug & VDB_IO)
|
if (vnddebug & VDB_FOLLOW)
|
||||||
printf("vndstart(%ld): bp %p vp %p blkno 0x%" PRIx64
|
printf("vndthread(%p\n", bp);
|
||||||
" flags %x addr %p cnt 0x%x\n",
|
#endif
|
||||||
(long) (vnd-vnd_softc), bp, bp->b_vp, bp->b_blkno,
|
lp = vnd->sc_dkdev.dk_label;
|
||||||
bp->b_flags, bp->b_data, bp->b_bcount);
|
bp->b_resid = bp->b_bcount;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Put the block number in terms of the logical blocksize
|
||||||
|
* of the "device".
|
||||||
|
*/
|
||||||
|
bn = bp->b_blkno / (lp->d_secsize / DEV_BSIZE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Translate the partition-relative block number to an absolute.
|
||||||
|
*/
|
||||||
|
if (DISKPART(bp->b_dev) != RAW_PART) {
|
||||||
|
pp = &vnd->sc_dkdev.dk_label->d_partitions[
|
||||||
|
DISKPART(bp->b_dev)];
|
||||||
|
bn += pp->p_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ...and convert to a byte offset within the file. */
|
||||||
|
bn *= lp->d_secsize;
|
||||||
|
|
||||||
|
if (vnd->sc_vp->v_mount == NULL) {
|
||||||
|
bp->b_error = ENXIO;
|
||||||
|
bp->b_flags |= B_ERROR;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
bsize = vnd->sc_vp->v_mount->mnt_stat.f_iosize;
|
||||||
|
addr = bp->b_data;
|
||||||
|
flags = (bp->b_flags & (B_READ|B_ASYNC)) | B_CALL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate a header for this transfer and link it to the
|
||||||
|
* buffer
|
||||||
|
*/
|
||||||
|
s = splbio();
|
||||||
|
vnx = VND_GETXFER(vnd);
|
||||||
|
splx(s);
|
||||||
|
vnx->vx_flags = VX_BUSY;
|
||||||
|
vnx->vx_error = 0;
|
||||||
|
vnx->vx_pending = 0;
|
||||||
|
vnx->vx_bp = bp;
|
||||||
|
|
||||||
|
if ((flags & B_READ) == 0)
|
||||||
|
vn_start_write(vnd->sc_vp, &mp, V_WAIT);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Feed requests sequentially.
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
for (resid = bp->b_resid; resid; resid -= sz) {
|
||||||
|
struct vndbuf *nbp;
|
||||||
|
struct vnode *vp;
|
||||||
|
daddr_t nbn;
|
||||||
|
int off, nra;
|
||||||
|
|
||||||
|
nra = 0;
|
||||||
|
vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY | LK_CANRECURSE);
|
||||||
|
error = VOP_BMAP(vnd->sc_vp, bn / bsize, &vp, &nbn, &nra);
|
||||||
|
VOP_UNLOCK(vnd->sc_vp, 0);
|
||||||
|
|
||||||
|
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) {
|
||||||
|
s = splbio();
|
||||||
|
vnx->vx_error = error;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (!dovndcluster)
|
||||||
|
nra = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Instrumentation. */
|
if ((off = bn % bsize) != 0)
|
||||||
disk_busy(&vnd->sc_dkdev);
|
sz = bsize - off;
|
||||||
|
else
|
||||||
|
sz = (1 + nra) * bsize;
|
||||||
|
if (resid < sz)
|
||||||
|
sz = resid;
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (vnddebug & VDB_IO)
|
||||||
|
printf("vndstrategy: vp %p/%p bn 0x%qx/0x%" PRIx64
|
||||||
|
" sz 0x%x\n",
|
||||||
|
vnd->sc_vp, vp, (long long)bn, nbn, sz);
|
||||||
|
#endif
|
||||||
|
|
||||||
if ((bp->b_flags & B_READ) == 0)
|
s = splbio();
|
||||||
bp->b_vp->v_numoutput++;
|
while (vnd->sc_active >= vnd->sc_maxactive) {
|
||||||
VOP_STRATEGY(bp->b_vp, bp);
|
tsleep(&vnd->sc_tab, PRIBIO, "vndac", 0);
|
||||||
|
if (vnd->sc_flags & VNF_VUNCONF)
|
||||||
|
goto kthread_end;
|
||||||
|
}
|
||||||
|
vnd->sc_active++;
|
||||||
|
nbp = VND_GETBUF(vnd);
|
||||||
|
splx(s);
|
||||||
|
BUF_INIT(&nbp->vb_buf);
|
||||||
|
nbp->vb_buf.b_flags = flags;
|
||||||
|
nbp->vb_buf.b_bcount = sz;
|
||||||
|
nbp->vb_buf.b_bufsize = round_page((ulong)addr + sz)
|
||||||
|
- trunc_page((ulong) addr);
|
||||||
|
nbp->vb_buf.b_error = 0;
|
||||||
|
nbp->vb_buf.b_data = addr;
|
||||||
|
nbp->vb_buf.b_blkno = nbp->vb_buf.b_rawblkno = nbn + btodb(off);
|
||||||
|
nbp->vb_buf.b_proc = bp->b_proc;
|
||||||
|
nbp->vb_buf.b_iodone = vndiodone;
|
||||||
|
nbp->vb_buf.b_vp = vp;
|
||||||
|
|
||||||
|
nbp->vb_xfer = vnx;
|
||||||
|
|
||||||
|
BIO_COPYPRIO(&nbp->vb_buf, bp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Just sort by block number
|
||||||
|
*/
|
||||||
|
s = splbio();
|
||||||
|
if (vnx->vx_error != 0) {
|
||||||
|
VND_PUTBUF(vnd, nbp);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
vnx->vx_pending++;
|
||||||
|
#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
|
||||||
|
|
||||||
|
/* Instrumentation. */
|
||||||
|
disk_busy(&vnd->sc_dkdev);
|
||||||
|
|
||||||
|
if ((nbp->vb_buf.b_flags & B_READ) == 0)
|
||||||
|
vp->v_numoutput++;
|
||||||
|
VOP_STRATEGY(vp, &nbp->vb_buf);
|
||||||
|
|
||||||
|
splx(s);
|
||||||
|
bn += sz;
|
||||||
|
addr += sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = splbio();
|
||||||
|
|
||||||
|
out: /* Arrive here at splbio */
|
||||||
|
if ((flags & B_READ) == 0)
|
||||||
|
vn_finished_write(mp, 0);
|
||||||
|
vnx->vx_flags &= ~VX_BUSY;
|
||||||
|
if (vnx->vx_pending == 0) {
|
||||||
|
if (vnx->vx_error != 0) {
|
||||||
|
bp->b_error = vnx->vx_error;
|
||||||
|
bp->b_flags |= B_ERROR;
|
||||||
|
}
|
||||||
|
VND_PUTXFER(vnd, vnx);
|
||||||
|
biodone(bp);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
done:
|
||||||
|
biodone(bp);
|
||||||
|
s = splbio();
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
vnd->sc_flags &= ~VNF_BUSY;
|
|
||||||
|
kthread_end:
|
||||||
|
vnd->sc_flags &= (~VNF_KTHREAD | VNF_VUNCONF);
|
||||||
|
wakeup(&vnd->sc_kthread);
|
||||||
|
splx(s);
|
||||||
|
kthread_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
vndiodone(struct buf *bp)
|
vndiodone(struct buf *bp)
|
||||||
{
|
{
|
||||||
@ -710,7 +744,7 @@ vndiodone(struct buf *bp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
vnd->sc_active--;
|
vnd->sc_active--;
|
||||||
vndstart(vnd);
|
wakeup(&vnd->sc_tab);
|
||||||
splx(s);
|
splx(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -906,9 +940,23 @@ vndioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
|
|||||||
|
|
||||||
if ((error = vndsetcred(vnd, p->p_ucred)) != 0)
|
if ((error = vndsetcred(vnd, p->p_ucred)) != 0)
|
||||||
goto close_and_exit;
|
goto close_and_exit;
|
||||||
|
|
||||||
|
memset(vnd->sc_xname, 0, sizeof(vnd->sc_xname)); /* XXX */
|
||||||
|
snprintf(vnd->sc_xname, sizeof(vnd->sc_xname), "vnd%d", unit);
|
||||||
|
|
||||||
|
|
||||||
vndthrottle(vnd, vnd->sc_vp);
|
vndthrottle(vnd, vnd->sc_vp);
|
||||||
vio->vnd_size = dbtob(vnd->sc_size);
|
vio->vnd_size = dbtob(vnd->sc_size);
|
||||||
vnd->sc_flags |= VNF_INITED;
|
vnd->sc_flags |= VNF_INITED;
|
||||||
|
|
||||||
|
/* create the kernel thread, wait for it to be up */
|
||||||
|
error = kthread_create1(vndthread, vnd, &vnd->sc_kthread,
|
||||||
|
vnd->sc_xname);
|
||||||
|
if (error)
|
||||||
|
goto close_and_exit;
|
||||||
|
while ((vnd->sc_flags & VNF_KTHREAD) == 0) {
|
||||||
|
tsleep(&vnd->sc_kthread, PRIBIO, "vndthr", 0);
|
||||||
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (vnddebug & VDB_INIT)
|
if (vnddebug & VDB_INIT)
|
||||||
printf("vndioctl: SET vp %p size 0x%lx %d/%d/%d/%d\n",
|
printf("vndioctl: SET vp %p size 0x%lx %d/%d/%d/%d\n",
|
||||||
@ -920,8 +968,6 @@ vndioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Attach the disk. */
|
/* Attach the disk. */
|
||||||
memset(vnd->sc_xname, 0, sizeof(vnd->sc_xname)); /* XXX */
|
|
||||||
snprintf(vnd->sc_xname, sizeof(vnd->sc_xname), "vnd%d", unit);
|
|
||||||
vnd->sc_dkdev.dk_name = vnd->sc_xname;
|
vnd->sc_dkdev.dk_name = vnd->sc_xname;
|
||||||
disk_attach(&vnd->sc_dkdev);
|
disk_attach(&vnd->sc_dkdev);
|
||||||
|
|
||||||
@ -1214,9 +1260,16 @@ vndclear(struct vnd_softc *vnd, int myminor)
|
|||||||
|
|
||||||
if ((vnd->sc_flags & VNF_READONLY) == 0)
|
if ((vnd->sc_flags & VNF_READONLY) == 0)
|
||||||
fflags |= FWRITE;
|
fflags |= FWRITE;
|
||||||
vnd->sc_flags &= ~(VNF_INITED | VNF_READONLY | VNF_VLABEL);
|
|
||||||
|
vnd->sc_flags |= VNF_VUNCONF;
|
||||||
|
wakeup(&vnd->sc_tab);
|
||||||
|
while (vnd->sc_flags & VNF_KTHREAD)
|
||||||
|
tsleep(&vnd->sc_kthread, PRIBIO, "vnthr", 0);
|
||||||
|
|
||||||
|
vnd->sc_flags &=
|
||||||
|
~(VNF_INITED | VNF_READONLY | VNF_VLABEL | VNF_VUNCONF);
|
||||||
if (vp == (struct vnode *)0)
|
if (vp == (struct vnode *)0)
|
||||||
panic("vndioctl: null vp");
|
panic("vndclear: null vp");
|
||||||
(void) vn_close(vp, fflags, vnd->sc_cred, p);
|
(void) vn_close(vp, fflags, vnd->sc_cred, p);
|
||||||
crfree(vnd->sc_cred);
|
crfree(vnd->sc_cred);
|
||||||
vnd->sc_vp = (struct vnode *)0;
|
vnd->sc_vp = (struct vnode *)0;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: vndvar.h,v 1.13 2005/02/27 00:26:58 perry Exp $ */
|
/* $NetBSD: vndvar.h,v 1.14 2005/03/30 19:23:08 bouyer Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
|
* Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
|
||||||
@ -162,6 +162,7 @@ struct vnd_softc {
|
|||||||
struct vndgeom sc_geom; /* virtual geometry */
|
struct vndgeom sc_geom; /* virtual geometry */
|
||||||
struct pool sc_vxpool; /* vndxfer pool */
|
struct pool sc_vxpool; /* vndxfer pool */
|
||||||
struct pool sc_vbpool; /* vndbuf pool */
|
struct pool sc_vbpool; /* vndbuf pool */
|
||||||
|
struct proc *sc_kthread; /* kernel thread */
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -171,10 +172,11 @@ struct vnd_softc {
|
|||||||
#define VNF_LABELLING 0x004 /* unit is currently being labelled */
|
#define VNF_LABELLING 0x004 /* unit is currently being labelled */
|
||||||
#define VNF_WANTED 0x008 /* someone is waiting to obtain a lock */
|
#define VNF_WANTED 0x008 /* someone is waiting to obtain a lock */
|
||||||
#define VNF_LOCKED 0x010 /* unit is locked */
|
#define VNF_LOCKED 0x010 /* unit is locked */
|
||||||
#define VNF_BUSY 0x020 /* unit is busy */
|
#define VNF_READONLY 0x020 /* unit is read-only */
|
||||||
#define VNF_READONLY 0x040 /* unit is read-only */
|
#define VNF_KLABEL 0x040 /* keep label on close */
|
||||||
#define VNF_KLABEL 0x080 /* keep label on close */
|
#define VNF_VLABEL 0x080 /* label is valid */
|
||||||
#define VNF_VLABEL 0x100 /* label is valid */
|
#define VNF_KTHREAD 0x100 /* thread is running */
|
||||||
|
#define VNF_VUNCONF 0x200 /* device is unconfiguring */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A simple structure for describing which vnd units are in use.
|
* A simple structure for describing which vnd units are in use.
|
||||||
|
Loading…
Reference in New Issue
Block a user