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