Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/net Avoid calling copyout with holding mutex(IPL_NET)
details: https://anonhg.NetBSD.org/src/rev/3ec5e44307a9
branches: trunk
changeset: 330826:3ec5e44307a9
user: ozaki-r <ozaki-r%NetBSD.org@localhost>
date: Wed Jul 23 05:32:23 2014 +0000
description:
Avoid calling copyout with holding mutex(IPL_NET)
Because copyout may lead a page fault that may sleep, we have to pull it
out from the critical section of mutex(IPL_NET) in bridge_ioctl_gifs.
diffstat:
sys/net/if_bridge.c | 61 ++++++++++++++++++++++++++++------------------------
1 files changed, 33 insertions(+), 28 deletions(-)
diffs (96 lines):
diff -r 39bc0d358940 -r 3ec5e44307a9 sys/net/if_bridge.c
--- a/sys/net/if_bridge.c Wed Jul 23 05:00:38 2014 +0000
+++ b/sys/net/if_bridge.c Wed Jul 23 05:32:23 2014 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: if_bridge.c,v 1.89 2014/07/23 04:09:48 ozaki-r Exp $ */
+/* $NetBSD: if_bridge.c,v 1.90 2014/07/23 05:32:23 ozaki-r Exp $ */
/*
* Copyright 2001 Wasabi Systems, Inc.
@@ -80,7 +80,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_bridge.c,v 1.89 2014/07/23 04:09:48 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_bridge.c,v 1.90 2014/07/23 05:32:23 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_bridge_ipf.h"
@@ -979,8 +979,8 @@
{
struct ifbifconf *bifc = arg;
struct bridge_iflist *bif;
- struct ifbreq breq;
- int count, len, error = 0;
+ struct ifbreq *breqs;
+ int i, count, error = 0;
BRIDGE_LOCK(sc);
@@ -988,37 +988,42 @@
LIST_FOREACH(bif, &sc->sc_iflist, bif_next)
count++;
- if (bifc->ifbic_len == 0) {
+ if (bifc->ifbic_len == 0 || bifc->ifbic_len < (sizeof(*breqs) * count)) {
BRIDGE_UNLOCK(sc);
- bifc->ifbic_len = sizeof(breq) * count;
- return (0);
+ /* Tell that a larger buffer is needed */
+ bifc->ifbic_len = sizeof(*breqs) * count;
+ return 0;
}
- count = 0;
- len = bifc->ifbic_len;
- memset(&breq, 0, sizeof breq);
+ breqs = malloc(sizeof(*breqs) * count, M_DEVBUF, M_NOWAIT);
+
+ i = 0;
LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
- if (len < sizeof(breq))
- break;
-
- strlcpy(breq.ifbr_ifsname, bif->bif_ifp->if_xname,
- sizeof(breq.ifbr_ifsname));
- breq.ifbr_ifsflags = bif->bif_flags;
- breq.ifbr_state = bif->bif_state;
- breq.ifbr_priority = bif->bif_priority;
- breq.ifbr_path_cost = bif->bif_path_cost;
- breq.ifbr_portno = bif->bif_ifp->if_index & 0xff;
- error = copyout(&breq, bifc->ifbic_req + count, sizeof(breq));
+ struct ifbreq *breq = &breqs[i++];
+ memset(breq, 0, sizeof(*breq));
+
+ strlcpy(breq->ifbr_ifsname, bif->bif_ifp->if_xname,
+ sizeof(breq->ifbr_ifsname));
+ breq->ifbr_ifsflags = bif->bif_flags;
+ breq->ifbr_state = bif->bif_state;
+ breq->ifbr_priority = bif->bif_priority;
+ breq->ifbr_path_cost = bif->bif_path_cost;
+ breq->ifbr_portno = bif->bif_ifp->if_index & 0xff;
+ }
+
+ /* Don't call copyout with holding the mutex */
+ BRIDGE_UNLOCK(sc);
+
+ for (i = 0; i < count; i++) {
+ error = copyout(&breqs[i], bifc->ifbic_req + i, sizeof(*breqs));
if (error)
break;
- count++;
- len -= sizeof(breq);
}
-
- BRIDGE_UNLOCK(sc);
-
- bifc->ifbic_len = sizeof(breq) * count;
- return (error);
+ bifc->ifbic_len = sizeof(*breqs) * i;
+
+ free(breqs, M_DEVBUF);
+
+ return error;
}
static int
Home |
Main Index |
Thread Index |
Old Index