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;
}