git: bd422989a99b - stable/12 - Lock busdma operations and serialize detach against open/close

Mark Johnston markj at FreeBSD.org
Tue Apr 6 15:20:47 UTC 2021


The branch stable/12 has been updated by markj:

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

commit bd422989a99b5acbc1017945a115f111ac81c131
Author:     Marcel Moolenaar <marcel at FreeBSD.org>
AuthorDate: 2019-07-04 02:51:34 +0000
Commit:     Mark Johnston <markj at 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


More information about the dev-commits-src-all mailing list