Module Name: src Committed By: ozaki-r Date: Wed Jul 23 05:32:23 UTC 2014
Modified Files: src/sys/net: if_bridge.c Log Message: 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. To generate a diff of this commit: cvs rdiff -u -r1.89 -r1.90 src/sys/net/if_bridge.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/net/if_bridge.c diff -u src/sys/net/if_bridge.c:1.89 src/sys/net/if_bridge.c:1.90 --- src/sys/net/if_bridge.c:1.89 Wed Jul 23 04:09:48 2014 +++ src/sys/net/if_bridge.c Wed Jul 23 05:32:23 2014 @@ -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 @@ bridge_ioctl_gifs(struct bridge_softc *s { 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 @@ bridge_ioctl_gifs(struct bridge_softc *s 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; + 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; + } - 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)); + /* 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); } + bifc->ifbic_len = sizeof(*breqs) * i; - BRIDGE_UNLOCK(sc); + free(breqs, M_DEVBUF); - bifc->ifbic_len = sizeof(breq) * count; - return (error); + return error; } static int