Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev Make vnd do I/O to the underlying file from thread c...
details: https://anonhg.NetBSD.org/src/rev/ddd4f82164fb
branches: trunk
changeset: 579894:ddd4f82164fb
user: bouyer <bouyer%NetBSD.org@localhost>
date: Wed Mar 30 19:23:08 2005 +0000
description:
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@
diffstat:
sys/dev/vnd.c | 443 ++++++++++++++++++++++++++++++------------------------
sys/dev/vndvar.h | 12 +-
2 files changed, 255 insertions(+), 200 deletions(-)
diffs (truncated from 616 to 300 lines):
diff -r c3e12c5bd88d -r ddd4f82164fb sys/dev/vnd.c
--- a/sys/dev/vnd.c Wed Mar 30 19:17:45 2005 +0000
+++ b/sys/dev/vnd.c Wed Mar 30 19:23:08 2005 +0000
@@ -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.
@@ -133,7 +133,7 @@
*/
#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)
#include "fs_nfs.h"
@@ -143,6 +143,7 @@
#include <sys/systm.h>
#include <sys/namei.h>
#include <sys/proc.h>
+#include <sys/kthread.h>
#include <sys/errno.h>
#include <sys/buf.h>
#include <sys/bufq.h>
@@ -190,10 +191,10 @@
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_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))
struct vnd_softc *vnd_softc;
@@ -207,7 +208,6 @@
int vnddetach(void);
static void vndclear(struct vnd_softc *, int);
-static void vndstart(struct vnd_softc *);
static int vndsetcred(struct vnd_softc *, struct ucred *);
static void vndthrottle(struct vnd_softc *, struct vnode *);
static void vndiodone(struct buf *);
@@ -221,6 +221,8 @@
static int vndlock(struct vnd_softc *);
static void vndunlock(struct vnd_softc *);
+void vndthread(void *);
+
static dev_type_open(vndopen);
static dev_type_close(vndclose);
static dev_type_read(vndread);
@@ -393,38 +395,24 @@
}
/*
- * 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
vndstrategy(struct buf *bp)
{
int unit = vndunit(bp->b_dev);
struct vnd_softc *vnd = &vnd_softc[unit];
- struct vndxfer *vnx;
- struct mount *mp;
- int s, bsize, resid;
- off_t bn;
- caddr_t addr;
- int sz, flags, error, wlabel;
- struct disklabel *lp;
- struct partition *pp;
+ struct disklabel *lp = vnd->sc_dkdev.dk_label;
+ int s = splbio();
-#ifdef DEBUG
- if (vnddebug & VDB_FOLLOW)
- printf("vndstrategy(%p): unit %d\n", bp, unit);
-#endif
+ bp->b_resid = bp->b_bcount;
+
if ((vnd->sc_flags & VNF_INITED) == 0) {
bp->b_error = ENXIO;
bp->b_flags |= B_ERROR;
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.
*/
@@ -435,15 +423,6 @@
}
/*
- * 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.
*/
if ((vnd->sc_flags & VNF_READONLY) && !(bp->b_flags & B_READ)) {
@@ -452,193 +431,248 @@
goto done;
}
- 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.
+ * 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) {
- pp = &vnd->sc_dkdev.dk_label->d_partitions[DISKPART(bp->b_dev)];
- bn += pp->p_offset;
+ if (bounds_check_with_label(&vnd->sc_dkdev,
+ bp, vnd->sc_flags & (VNF_WLABEL|VNF_LABELLING)) <= 0)
+ goto done;
}
- /* ...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;
+ /* If it's a nil transfer, wake up the top half now. */
+ if (bp->b_bcount == 0)
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);
+#ifdef DEBUG
+ if (vnddebug & VDB_FOLLOW)
+ printf("vndstrategy(%p): unit %d\n", bp, unit);
+#endif
+ BUFQ_PUT(&vnd->sc_tab, bp);
+ wakeup(&vnd->sc_tab);
+ splx(s);
+ return;
+done:
+ biodone(bp);
splx(s);
- vnx->vx_flags = VX_BUSY;
- vnx->vx_error = 0;
- vnx->vx_pending = 0;
- vnx->vx_bp = bp;
+}
+
+void
+vndthread(void *arg)
+{
+ 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;
- if ((flags & B_READ) == 0)
- vn_start_write(vnd->sc_vp, &mp, V_WAIT);
+ s = splbio();
+ vnd->sc_flags |= VNF_KTHREAD;
+ wakeup(&vnd->sc_kthread);
+
+ /*
+ * Dequeue requests, break them into bsize pieces and submit using
+ * VOP_BMAP/VOP_STRATEGY.
+ */
+ while ((vnd->sc_flags & VNF_VUNCONF) == 0) {
+ bp = BUFQ_GET(&vnd->sc_tab);
+ if (bp == NULL) {
+ tsleep(&vnd->sc_tab, PRIBIO, "vndbp", 0);
+ continue;
+ };
+ splx(s);
+
+#ifdef DEBUG
+ if (vnddebug & VDB_FOLLOW)
+ printf("vndthread(%p\n", bp);
+#endif
+ lp = vnd->sc_dkdev.dk_label;
+ bp->b_resid = bp->b_bcount;
- for (resid = bp->b_resid; resid; resid -= sz) {
- struct vndbuf *nbp;
- struct vnode *vp;
- daddr_t nbn;
- int off, nra;
+ /*
+ * 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;
- 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 (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;
- if (error == 0 && (long)nbn == -1)
- error = EIO;
+ /*
+ * 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);
/*
- * 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).
+ * 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.
*/
- if (error) {
- s = splbio();
- vnx->vx_error = error;
- goto out;
- }
+ 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;
+
+ /*
Home |
Main Index |
Thread Index |
Old Index