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