Module Name:    src
Committed By:   bouyer
Date:           Sat Jul 20 15:34:41 UTC 2019

Modified Files:
        src/sys/netcan: can.c can_pcb.c

Log Message:
Don't kmem_alloc()/kmem_free() with spin lock held: call can_pcbsetfilter()
without canp_mtx; take it here and check canp_state before updating the
canp_filters.


To generate a diff of this commit:
cvs rdiff -u -r1.6 -r1.7 src/sys/netcan/can.c
cvs rdiff -u -r1.7 -r1.8 src/sys/netcan/can_pcb.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/netcan/can.c
diff -u src/sys/netcan/can.c:1.6 src/sys/netcan/can.c:1.7
--- src/sys/netcan/can.c:1.6	Thu Nov 15 10:23:56 2018
+++ src/sys/netcan/can.c	Sat Jul 20 15:34:41 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: can.c,v 1.6 2018/11/15 10:23:56 maxv Exp $	*/
+/*	$NetBSD: can.c,v 1.7 2019/07/20 15:34:41 bouyer Exp $	*/
 
 /*-
  * Copyright (c) 2003, 2017 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: can.c,v 1.6 2018/11/15 10:23:56 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: can.c,v 1.7 2019/07/20 15:34:41 bouyer Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -924,9 +924,7 @@ can_raw_setop(struct canpcb *canp, struc
 		int nfilters = sopt->sopt_size / sizeof(struct can_filter);
 		if (sopt->sopt_size % sizeof(struct can_filter) != 0)
 			return EINVAL;
-		mutex_enter(&canp->canp_mtx);
 		error = can_pcbsetfilter(canp, sopt->sopt_data, nfilters);
-		mutex_exit(&canp->canp_mtx);
 		break;
 		}
 	default:

Index: src/sys/netcan/can_pcb.c
diff -u src/sys/netcan/can_pcb.c:1.7 src/sys/netcan/can_pcb.c:1.8
--- src/sys/netcan/can_pcb.c:1.7	Mon Feb 25 06:49:44 2019
+++ src/sys/netcan/can_pcb.c	Sat Jul 20 15:34:41 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: can_pcb.c,v 1.7 2019/02/25 06:49:44 maxv Exp $	*/
+/*	$NetBSD: can_pcb.c,v 1.8 2019/07/20 15:34:41 bouyer Exp $	*/
 
 /*-
  * Copyright (c) 2003, 2017 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: can_pcb.c,v 1.7 2019/02/25 06:49:44 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: can_pcb.c,v 1.8 2019/07/20 15:34:41 bouyer Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -193,8 +193,8 @@ can_pcbdetach(void *v)
 	so->so_pcb = NULL;
 	mutex_enter(&canp->canp_mtx);
 	can_pcbstate(canp, CANP_DETACHED);
-	can_pcbsetfilter(canp, NULL, 0);
 	mutex_exit(&canp->canp_mtx);
+	can_pcbsetfilter(canp, NULL, 0);
 	TAILQ_REMOVE(&canp->canp_table->canpt_queue, canp, canp_queue);
 	sofree(so); /* sofree drops the softnet_lock */
 	canp_unref(canp);
@@ -243,7 +243,9 @@ can_pcbsetfilter(struct canpcb *canp, st
 {
 
 	struct can_filter *newf;
-	KASSERT(mutex_owned(&canp->canp_mtx));
+	struct can_filter *oldf;
+	int oldnf;
+	int error = 0;
 
 	if (nfilters > 0) {
 		newf =
@@ -252,13 +254,24 @@ can_pcbsetfilter(struct canpcb *canp, st
 	} else {
 		newf = NULL;
 	}
-	if (canp->canp_filters != NULL) {
-		kmem_free(canp->canp_filters,
-		    sizeof(struct can_filter) * canp->canp_nfilters);
+	mutex_enter(&canp->canp_mtx);
+	oldf = canp->canp_filters;
+	oldnf = canp->canp_nfilters;
+	if (newf != NULL && canp->canp_state == CANP_DETACHED) {
+		error = ECONNRESET;
+	} else {
+		canp->canp_filters = newf;
+		canp->canp_nfilters = nfilters;
+		newf = NULL;
+	}
+	mutex_exit(&canp->canp_mtx);
+	if (oldf != NULL) {
+		kmem_free(oldf, sizeof(struct can_filter) * oldnf);
 	}
-	canp->canp_filters = newf;
-	canp->canp_nfilters = nfilters;
-	return 0;
+	if (newf != NULL) {
+		kmem_free(newf, sizeof(struct can_filter) * nfilters);
+	}
+	return error;
 }
 
 

Reply via email to