The branch stable/13 has been updated by jhb:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=80893ea32be08797049b36dc14e2210e40a4f5b8

commit 80893ea32be08797049b36dc14e2210e40a4f5b8
Author:     John Baldwin <j...@freebsd.org>
AuthorDate: 2022-05-05 23:40:04 +0000
Commit:     John Baldwin <j...@freebsd.org>
CommitDate: 2022-05-19 22:01:50 +0000

    pbio: Add locking and remove D_NEEDGIANT.
    
    Use a sx lock to permit uiomove directly into/out of the the per-port
    buffers.  In addition, the sx lock provides a stronger guarantee that
    I think this driver wants which is to single-thread read and write
    calls even while paused.  Finally, replace tsleep with dummy wait
    channels with calls to pause_sig to more clearly communicate the
    intent.
    
    Differential Revision:  https://reviews.freebsd.org/D35081
    
    (cherry picked from commit 51f481235c29fb38b92fb08a830385e39df80093)
---
 sys/dev/pbio/pbio.c | 54 ++++++++++++++++++++++++++++++-----------------------
 1 file changed, 31 insertions(+), 23 deletions(-)

diff --git a/sys/dev/pbio/pbio.c b/sys/dev/pbio/pbio.c
index 516ec3a73408..0fd841cd5720 100644
--- a/sys/dev/pbio/pbio.c
+++ b/sys/dev/pbio/pbio.c
@@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
 #include <dev/pbio/pbioio.h>           /* pbio IOCTL definitions */
 #include <sys/uio.h>
 #include <sys/fcntl.h>
+#include <sys/sx.h>
 #include <isa/isavar.h>
 
 /* Function prototypes (these should all be static) */
@@ -84,11 +85,8 @@ static char *port_names[] = {"a", "b", "ch", "cl"};
 
 #define        pbio_addr(dev)          ((dev)->si_drv1)
 
-#define        PBIOPRI ((PZERO + 5) | PCATCH)
-
 static struct cdevsw pbio_cdevsw = {
        .d_version = D_VERSION,
-       .d_flags = D_NEEDGIANT,
        .d_open = pbioopen,
        .d_read = pbioread,
        .d_write = pbiowrite,
@@ -117,6 +115,7 @@ struct pbio_softc {
        int     iomode;                 /* Virtualized I/O mode port value */
                                        /* The real port is write-only */
        struct resource *res;
+       struct sx lock;
 };
 
 typedef        struct pbio_softc *sc_p;
@@ -230,6 +229,7 @@ pbioattach (device_t dev)
         */
        sc->iomode = 0x9b;              /* All ports to input */
 
+       sx_init(&sc->lock, "pbio");
        for (i = 0; i < PBIO_NPORTS; i++) {
                make_dev_args_init(&args);
                args.mda_devsw = &pbio_cdevsw;
@@ -249,10 +249,12 @@ pbioioctl (struct cdev *dev, u_long cmd, caddr_t data, 
int flag,
     struct thread *td)
 {
        struct pbio_softc *scp;
-       int port;
+       int error, port;
 
+       error = 0;
        port = PORT(dev);
        scp = pbio_addr(dev);
+       sx_xlock(&scp->lock);
        switch (cmd) {
        case PBIO_SETDIFF:
                scp->pd[port].diff = *(int *)data;
@@ -273,16 +275,17 @@ pbioioctl (struct cdev *dev, u_long cmd, caddr_t data, 
int flag,
                *(int *)data = scp->pd[port].opace;
                break;
        default:
-               return ENXIO;
+               error = ENXIO;
        }
-       return (0);
+       sx_xunlock(&scp->lock);
+       return (error);
 }
 
 static  int
 pbioopen(struct cdev *dev, int oflags, int devtype, struct thread *td)
 {
        struct pbio_softc *scp;
-       int ocfg, port;
+       int error, ocfg, port;
        int portbit;                    /* Port configuration bit */
 
        port = PORT(dev);
@@ -297,6 +300,8 @@ pbioopen(struct cdev *dev, int oflags, int devtype, struct 
thread *td)
        }
        ocfg = scp->iomode;
 
+       error = 0;
+       sx_xlock(&scp->lock);
        if (oflags & FWRITE)
                /* Writing == output; zero the bit */
                pboutb(scp, PBIO_CFG, scp->iomode = (ocfg & (~portbit)));
@@ -304,9 +309,10 @@ pbioopen(struct cdev *dev, int oflags, int devtype, struct 
thread *td)
                /* Reading == input; set the bit */
                pboutb(scp, PBIO_CFG, scp->iomode = (ocfg | portbit));
        else
-               return (EACCES);
+               error = EACCES;
+       sx_xunlock(&scp->lock);
 
-       return (0);
+       return (error);
 }
 
 /*
@@ -341,8 +347,7 @@ portval(int port, struct pbio_softc *scp, char *val)
                                scp->pd[port].oldval = *val;
                                return (0);
                        }
-                       err = tsleep((caddr_t)&(scp->pd[port].diff), PBIOPRI,
-                                    "pbiopl", max(1, scp->pd[port].ipace));
+                       err = pause_sig("pbiopl", max(1, scp->pd[port].ipace));
                        if (err == EINTR)
                                return (EINTR);
                } else
@@ -354,26 +359,28 @@ static  int
 pbioread(struct cdev *dev, struct uio *uio, int ioflag)
 {
        struct pbio_softc *scp;
-       int err, i, port, ret, toread;
+       int err, i, port, toread;
        char val;
 
        port = PORT(dev);
        scp = pbio_addr(dev);
 
+       err = 0;
+       sx_xlock(&scp->lock);
        while (uio->uio_resid > 0) {
                toread = min(uio->uio_resid, PBIO_BUFSIZ);
-               if ((ret = uiomove(scp->pd[port].buff, toread, uio)) != 0)
-                       return (ret);
+               if ((err = uiomove(scp->pd[port].buff, toread, uio)) != 0)
+                       break;
                for (i = 0; i < toread; i++) {
                        if ((err = portval(port, scp, &val)) != 0)
-                               return (err);
+                               break;
                        scp->pd[port].buff[i] = val;
                        if (!scp->pd[port].diff && scp->pd[port].ipace)
-                               tsleep((caddr_t)&(scp->pd[port].ipace), PBIOPRI,
-                                       "pbioip", scp->pd[port].ipace);
+                               pause_sig("pbioip", scp->pd[port].ipace);
                }
        }
-       return 0;
+       sx_xunlock(&scp->lock);
+       return (err);
 }
 
 static int
@@ -386,10 +393,12 @@ pbiowrite(struct cdev *dev, struct uio *uio, int ioflag)
        port = PORT(dev);
        scp = pbio_addr(dev);
 
+       ret = 0;
+       sx_xlock(&scp->lock);
        while (uio->uio_resid > 0) {
                towrite = min(uio->uio_resid, PBIO_BUFSIZ);
                if ((ret = uiomove(scp->pd[port].buff, towrite, uio)) != 0)
-                       return (ret);
+                       break;
                for (i = 0; i < towrite; i++) {
                        val = scp->pd[port].buff[i];
                        switch (port) {
@@ -413,12 +422,11 @@ pbiowrite(struct cdev *dev, struct uio *uio, int ioflag)
                                break;
                        }
                        if (scp->pd[port].opace)
-                               tsleep((caddr_t)&(scp->pd[port].opace),
-                                       PBIOPRI, "pbioop",
-                                       scp->pd[port].opace);
+                               pause_sig("pbioop", scp->pd[port].opace);
                }
        }
-       return (0);
+       sx_xunlock(&scp->lock);
+       return (ret);
 }
 
 static  int

Reply via email to