The branch stable/12 has been updated by markj:

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

commit bd422989a99b5acbc1017945a115f111ac81c131
Author:     Marcel Moolenaar <mar...@freebsd.org>
AuthorDate: 2019-07-04 02:51:34 +0000
Commit:     Mark Johnston <ma...@freebsd.org>
CommitDate: 2021-04-06 15:20:13 +0000

    Lock busdma operations and serialize detach against open/close
    
    Use sx to allow M_WAITOK allocations (suggested by markj).
    
    admbugs: 782
    Reviewed by:    markj
    
    (cherry picked from commit 9f011bca829751ed3552ac94fe7c865d75fabfc4)
---
 sys/dev/proto/proto.h        |  8 ++++--
 sys/dev/proto/proto_busdma.c | 27 +++++++++++++++---
 sys/dev/proto/proto_busdma.h |  3 +-
 sys/dev/proto/proto_core.c   | 66 +++++++++++++++++++++++++++++++-------------
 4 files changed, 77 insertions(+), 27 deletions(-)

diff --git a/sys/dev/proto/proto.h b/sys/dev/proto/proto.h
index cf89512f6ea7..14f6af648f82 100644
--- a/sys/dev/proto/proto.h
+++ b/sys/dev/proto/proto.h
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2014, 2015 Marcel Moolenaar
+ * Copyright (c) 2014, 2015, 2019 Marcel Moolenaar
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,7 +36,8 @@
 #define        PROTO_RES_BUSDMA        11
 
 struct proto_res {
-       int             r_type;
+       u_int           r_type:8;
+       u_int           r_opened:1;
        int             r_rid;
        union {
                struct resource *res;
@@ -47,13 +48,14 @@ struct proto_res {
                void            *cookie;
                struct cdev     *cdev;
        } r_u;
-       uintptr_t       r_opened;
 };
 
 struct proto_softc {
        device_t        sc_dev;
        struct proto_res sc_res[PROTO_RES_MAX];
        int             sc_rescnt;
+       int             sc_opencnt;
+       struct mtx      sc_mtx;
 };
 
 extern devclass_t proto_devclass;
diff --git a/sys/dev/proto/proto_busdma.c b/sys/dev/proto/proto_busdma.c
index 6f6bf7b08916..6838af1e3a1e 100644
--- a/sys/dev/proto/proto_busdma.c
+++ b/sys/dev/proto/proto_busdma.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2015 Marcel Moolenaar
+ * Copyright (c) 2015, 2019 Marcel Moolenaar
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/queue.h>
 #include <sys/rman.h>
 #include <sys/sbuf.h>
+#include <sys/sx.h>
 #include <sys/uio.h>
 #include <vm/vm.h>
 #include <vm/pmap.h>
@@ -355,6 +356,7 @@ proto_busdma_attach(struct proto_softc *sc)
        struct proto_busdma *busdma;
 
        busdma = malloc(sizeof(*busdma), M_PROTO_BUSDMA, M_WAITOK | M_ZERO);
+       sx_init(&busdma->sxlck, "proto-busdma");
        return (busdma);
 }
 
@@ -363,6 +365,7 @@ proto_busdma_detach(struct proto_softc *sc, struct 
proto_busdma *busdma)
 {
 
        proto_busdma_cleanup(sc, busdma);
+       sx_destroy(&busdma->sxlck);
        free(busdma, M_PROTO_BUSDMA);
        return (0);
 }
@@ -373,10 +376,12 @@ proto_busdma_cleanup(struct proto_softc *sc, struct 
proto_busdma *busdma)
        struct proto_md *md, *md1;
        struct proto_tag *tag, *tag1;
 
+       sx_xlock(&busdma->sxlck);
        LIST_FOREACH_SAFE(md, &busdma->mds, mds, md1)
                proto_busdma_md_destroy_internal(busdma, md);
        LIST_FOREACH_SAFE(tag, &busdma->tags, tags, tag1)
                proto_busdma_tag_destroy(busdma, tag);
+       sx_xunlock(&busdma->sxlck);
        return (0);
 }
 
@@ -388,6 +393,8 @@ proto_busdma_ioctl(struct proto_softc *sc, struct 
proto_busdma *busdma,
        struct proto_md *md;
        int error;
 
+       sx_xlock(&busdma->sxlck);
+
        error = 0;
        switch (ioc->request) {
        case PROTO_IOC_BUSDMA_TAG_CREATE:
@@ -470,6 +477,9 @@ proto_busdma_ioctl(struct proto_softc *sc, struct 
proto_busdma *busdma,
                error = EINVAL;
                break;
        }
+
+       sx_xunlock(&busdma->sxlck);
+
        return (error);
 }
 
@@ -477,11 +487,20 @@ int
 proto_busdma_mmap_allowed(struct proto_busdma *busdma, vm_paddr_t physaddr)
 {
        struct proto_md *md;
+       int result;
 
+       sx_xlock(&busdma->sxlck);
+
+       result = 0;
        LIST_FOREACH(md, &busdma->mds, mds) {
                if (physaddr >= trunc_page(md->physaddr) &&
-                   physaddr <= trunc_page(md->physaddr + md->tag->maxsz))
-                       return (1);
+                   physaddr <= trunc_page(md->physaddr + md->tag->maxsz)) {
+                       result = 1;
+                       break;
+               }
        }
-       return (0);
+
+       sx_xunlock(&busdma->sxlck);
+
+       return (result);
 }
diff --git a/sys/dev/proto/proto_busdma.h b/sys/dev/proto/proto_busdma.h
index 2b645cebcc4d..a3a3f0087ba3 100644
--- a/sys/dev/proto/proto_busdma.h
+++ b/sys/dev/proto/proto_busdma.h
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2015 Marcel Moolenaar
+ * Copyright (c) 2015, 2019 Marcel Moolenaar
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -60,6 +60,7 @@ struct proto_busdma {
        LIST_HEAD(,proto_tag)   tags;
        LIST_HEAD(,proto_md)    mds;
        bus_dma_tag_t           bd_roottag;
+       struct sx               sxlck;
 };
 
 struct proto_busdma *proto_busdma_attach(struct proto_softc *);
diff --git a/sys/dev/proto/proto_core.c b/sys/dev/proto/proto_core.c
index 83da523b1cbb..404ba498f09d 100644
--- a/sys/dev/proto/proto_core.c
+++ b/sys/dev/proto/proto_core.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2014, 2015 Marcel Moolenaar
+ * Copyright (c) 2014, 2015, 2019 Marcel Moolenaar
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -184,6 +184,7 @@ proto_attach(device_t dev)
 
        sc = device_get_softc(dev);
        sc->sc_dev = dev;
+       mtx_init(&sc->sc_mtx, "proto-softc", NULL, MTX_DEF);
 
        for (res = 0; res < sc->sc_rescnt; res++) {
                r = sc->sc_res + res;
@@ -231,15 +232,16 @@ proto_detach(device_t dev)
 
        sc = device_get_softc(dev);
 
-       /* Don't detach if we have open device files. */
-       for (res = 0; res < sc->sc_rescnt; res++) {
-               r = sc->sc_res + res;
-               if (r->r_opened)
-                       return (EBUSY);
-       }
+       mtx_lock(&sc->sc_mtx);
+       if (sc->sc_opencnt == 0)
+               sc->sc_opencnt = -1;
+       mtx_unlock(&sc->sc_mtx);
+       if (sc->sc_opencnt > 0)
+               return (EBUSY);
 
        for (res = 0; res < sc->sc_rescnt; res++) {
                r = sc->sc_res + res;
+
                switch (r->r_type) {
                case SYS_RES_IRQ:
                        /* XXX TODO */
@@ -252,21 +254,25 @@ proto_detach(device_t dev)
                        break;
                case SYS_RES_MEMORY:
                case SYS_RES_IOPORT:
+                       destroy_dev(r->r_u.cdev);
                        bus_release_resource(dev, r->r_type, r->r_rid,
                            r->r_d.res);
-                       destroy_dev(r->r_u.cdev);
                        break;
                case PROTO_RES_PCICFG:
                        destroy_dev(r->r_u.cdev);
                        break;
                case PROTO_RES_BUSDMA:
-                       proto_busdma_detach(sc, r->r_d.busdma);
                        destroy_dev(r->r_u.cdev);
+                       proto_busdma_detach(sc, r->r_d.busdma);
                        break;
                }
                r->r_type = PROTO_RES_UNUSED;
        }
+       mtx_lock(&sc->sc_mtx);
        sc->sc_rescnt = 0;
+       sc->sc_opencnt = 0;
+       mtx_unlock(&sc->sc_mtx);
+       mtx_destroy(&sc->sc_mtx);
        return (0);
 }
 
@@ -278,11 +284,23 @@ static int
 proto_open(struct cdev *cdev, int oflags, int devtype, struct thread *td)
 {
        struct proto_res *r;
+       struct proto_softc *sc;
+       int error;
 
-       r = cdev->si_drv2;
-       if (!atomic_cmpset_acq_ptr(&r->r_opened, 0UL, (uintptr_t)td->td_proc))
-               return (EBUSY);
-       return (0);
+       sc = cdev->si_drv1;
+       mtx_lock(&sc->sc_mtx);
+       if (sc->sc_opencnt >= 0) {
+               r = cdev->si_drv2;
+               if (!r->r_opened) {
+                       r->r_opened = 1;
+                       sc->sc_opencnt++;
+                       error = 0;
+               } else
+                       error = EBUSY;
+       } else
+               error = ENXIO;
+       mtx_unlock(&sc->sc_mtx);
+       return (error);
 }
 
 static int
@@ -290,14 +308,24 @@ proto_close(struct cdev *cdev, int fflag, int devtype, 
struct thread *td)
 {
        struct proto_res *r;
        struct proto_softc *sc;
+       int error;
 
        sc = cdev->si_drv1;
-       r = cdev->si_drv2;
-       if (!atomic_cmpset_acq_ptr(&r->r_opened, (uintptr_t)td->td_proc, 0UL))
-               return (ENXIO);
-       if (r->r_type == PROTO_RES_BUSDMA)
-               proto_busdma_cleanup(sc, r->r_d.busdma);
-       return (0);
+       mtx_lock(&sc->sc_mtx);
+       if (sc->sc_opencnt > 0) {
+               r = cdev->si_drv2;
+               if (r->r_opened) {
+                       if (r->r_type == PROTO_RES_BUSDMA)
+                               proto_busdma_cleanup(sc, r->r_d.busdma);
+                       r->r_opened = 0;
+                       sc->sc_opencnt--;
+                       error = 0;
+               } else
+                       error = ENXIO;
+       } else
+               error = ENXIO;
+       mtx_unlock(&sc->sc_mtx);
+       return (error);
 }
 
 static int
_______________________________________________
dev-commits-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-all
To unsubscribe, send any mail to "dev-commits-src-all-unsubscr...@freebsd.org"

Reply via email to