diff options
-rw-r--r-- | sys/kern/uipc_socket.c | 6 | ||||
-rw-r--r-- | sys/kern/uipc_socket2.c | 8 | ||||
-rw-r--r-- | sys/net/if.c | 14 | ||||
-rw-r--r-- | sys/net/if_pflow.c | 8 | ||||
-rw-r--r-- | sys/net/pf.c | 51 | ||||
-rw-r--r-- | sys/net/pf_ioctl.c | 16 | ||||
-rw-r--r-- | sys/net/pf_norm.c | 4 | ||||
-rw-r--r-- | sys/net/pfvar.h | 7 | ||||
-rw-r--r-- | sys/sys/systm.h | 10 | ||||
-rw-r--r-- | sys/uvm/uvm_vnode.c | 14 |
10 files changed, 76 insertions, 62 deletions
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index 7716e576d7f..edb9618ec45 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uipc_socket.c,v 1.182 2017/04/02 23:40:08 deraadt Exp $ */ +/* $OpenBSD: uipc_socket.c,v 1.183 2017/05/15 12:26:00 mpi Exp $ */ /* $NetBSD: uipc_socket.c,v 1.21 1996/02/04 02:17:52 christos Exp $ */ /* @@ -1038,10 +1038,12 @@ sorflush(struct socket *so) { struct sockbuf *sb = &so->so_rcv; struct protosw *pr = so->so_proto; + sa_family_t af = pr->pr_domain->dom_family; struct sockbuf asb; sb->sb_flags |= SB_NOINTR; - sblock(sb, M_WAITOK, NULL); + sblock(sb, M_WAITOK, + (af != PF_LOCAL && af != PF_ROUTE) ? &netlock : NULL); socantrcvmore(so); sbunlock(sb); asb = *sb; diff --git a/sys/kern/uipc_socket2.c b/sys/kern/uipc_socket2.c index ab72035f63c..4ef71d5c6ca 100644 --- a/sys/kern/uipc_socket2.c +++ b/sys/kern/uipc_socket2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uipc_socket2.c,v 1.75 2017/03/17 17:19:16 mpi Exp $ */ +/* $OpenBSD: uipc_socket2.c,v 1.76 2017/05/15 12:26:00 mpi Exp $ */ /* $NetBSD: uipc_socket2.c,v 1.11 1996/02/04 02:17:55 christos Exp $ */ /* @@ -299,7 +299,11 @@ soassertlocked(struct socket *so) int sosleep(struct socket *so, void *ident, int prio, const char *wmesg, int timo) { - return tsleep(ident, prio, wmesg, timo); + if ((so->so_proto->pr_domain->dom_family != PF_LOCAL) && + (so->so_proto->pr_domain->dom_family != PF_ROUTE)) { + return rwsleep(ident, &netlock, prio, wmesg, timo); + } else + return tsleep(ident, prio, wmesg, timo); } /* diff --git a/sys/net/if.c b/sys/net/if.c index 5f7fb91aa97..9d03d8a1d2e 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if.c,v 1.495 2017/05/09 09:31:07 mpi Exp $ */ +/* $OpenBSD: if.c,v 1.496 2017/05/15 12:26:00 mpi Exp $ */ /* $NetBSD: if.c,v 1.35 1996/05/07 05:26:04 thorpej Exp $ */ /* @@ -230,6 +230,12 @@ struct taskq *softnettq; struct task if_input_task_locked = TASK_INITIALIZER(if_netisr, NULL); /* + * Serialize socket operations to ensure no new sleeping points + * are introduced in IP output paths. + */ +struct rwlock netlock = RWLOCK_INITIALIZER("netlock"); + +/* * Network interface utility routines. */ void @@ -1146,7 +1152,10 @@ if_clone_create(const char *name, int rdomain) if (ifunit(name) != NULL) return (EEXIST); + /* XXXSMP breaks atomicity */ + rw_exit_write(&netlock); ret = (*ifc->ifc_create)(ifc, unit); + rw_enter_write(&netlock); if (ret != 0 || (ifp = ifunit(name)) == NULL) return (ret); @@ -1188,7 +1197,10 @@ if_clone_destroy(const char *name) splx(s); } + /* XXXSMP breaks atomicity */ + rw_exit_write(&netlock); ret = (*ifc->ifc_destroy)(ifp); + rw_enter_write(&netlock); return (ret); } diff --git a/sys/net/if_pflow.c b/sys/net/if_pflow.c index 5dcdea31017..a40fe23862b 100644 --- a/sys/net/if_pflow.c +++ b/sys/net/if_pflow.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_pflow.c,v 1.75 2017/03/17 17:19:16 mpi Exp $ */ +/* $OpenBSD: if_pflow.c,v 1.76 2017/05/15 12:26:00 mpi Exp $ */ /* * Copyright (c) 2011 Florian Obser <florian@narrans.de> @@ -463,9 +463,12 @@ pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data) sc->sc_gcounter=pflowstats.pflow_flows; /* send templates on startup */ if (sc->sc_version == PFLOW_PROTO_10) { + /* XXXSMP breaks atomicity */ + rw_exit_write(&netlock); s = splnet(); pflow_sendout_ipfix_tmpl(sc); splx(s); + rw_enter_write(&netlock); } } else ifp->if_flags &= ~IFF_RUNNING; @@ -505,6 +508,8 @@ pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data) sizeof(pflowr)))) return (error); + /* XXXSMP breaks atomicity */ + rw_exit_write(&netlock); s = splnet(); error = pflow_set(sc, &pflowr); splx(s); @@ -522,6 +527,7 @@ pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data) } else ifp->if_flags &= ~IFF_RUNNING; + rw_enter_write(&netlock); break; default: diff --git a/sys/net/pf.c b/sys/net/pf.c index 7bf2c5e2987..32493720291 100644 --- a/sys/net/pf.c +++ b/sys/net/pf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf.c,v 1.1021 2017/05/05 16:30:39 mikeb Exp $ */ +/* $OpenBSD: pf.c,v 1.1022 2017/05/15 12:26:00 mpi Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -1154,26 +1154,20 @@ pf_state_export(struct pfsync_state *sp, struct pf_state *st) /* END state table stuff */ void -pf_purge_expired_rules(int locked) +pf_purge_expired_rules(void) { struct pf_rule *r; + NET_ASSERT_LOCKED(); + if (SLIST_EMPTY(&pf_rule_gcl)) return; - if (!locked) - rw_enter_write(&pf_consistency_lock); - else - rw_assert_wrlock(&pf_consistency_lock); - while ((r = SLIST_FIRST(&pf_rule_gcl)) != NULL) { SLIST_REMOVE(&pf_rule_gcl, r, pf_rule, gcle); KASSERT(r->rule_flag & PFRULE_EXPIRED); pf_purge_rule(r); } - - if (!locked) - rw_exit_write(&pf_consistency_lock); } void @@ -1194,7 +1188,7 @@ pf_purge_thread(void *v) if (++nloops >= pf_default_rule.timeout[PFTM_INTERVAL]) { pf_purge_expired_fragments(); pf_purge_expired_src_nodes(0); - pf_purge_expired_rules(0); + pf_purge_expired_rules(); nloops = 0; } @@ -1241,27 +1235,20 @@ pf_state_expires(const struct pf_state *state) } void -pf_purge_expired_src_nodes(int waslocked) +pf_purge_expired_src_nodes(void) { struct pf_src_node *cur, *next; - int locked = waslocked; + + NET_ASSERT_LOCKED(); for (cur = RB_MIN(pf_src_tree, &tree_src_tracking); cur; cur = next) { next = RB_NEXT(pf_src_tree, &tree_src_tracking, cur); if (cur->states == 0 && cur->expire <= time_uptime) { - if (! locked) { - rw_enter_write(&pf_consistency_lock); - next = RB_NEXT(pf_src_tree, - &tree_src_tracking, cur); - locked = 1; - } + next = RB_NEXT(pf_src_tree, &tree_src_tracking, cur); pf_remove_src_node(cur); } } - - if (locked && !waslocked) - rw_exit_write(&pf_consistency_lock); } void @@ -1306,7 +1293,10 @@ pf_remove_state(struct pf_state *cur) RB_REMOVE(pf_state_tree_id, &tree_id, cur); #if NPFLOW > 0 if (cur->state_flags & PFSTATE_PFLOW) { + /* XXXSMP breaks atomicity */ + rw_exit_write(&netlock); export_pflow(cur); + rw_enter_write(&netlock); } #endif /* NPFLOW > 0 */ #if NPFSYNC > 0 @@ -1331,13 +1321,12 @@ pf_remove_divert_state(struct pf_state_key *sk) } } -/* callers should hold the write_lock on pf_consistency_lock */ void pf_free_state(struct pf_state *cur) { struct pf_rule_item *ri; - splsoftassert(IPL_SOFTNET); + NET_ASSERT_LOCKED(); #if NPFSYNC > 0 if (pfsync_state_in_use(cur)) @@ -1372,7 +1361,8 @@ pf_purge_expired_states(u_int32_t maxcheck) { static struct pf_state *cur = NULL; struct pf_state *next; - int locked = 0; + + NET_ASSERT_LOCKED(); while (maxcheck--) { /* wrap to start of list when we hit the end */ @@ -1387,25 +1377,14 @@ pf_purge_expired_states(u_int32_t maxcheck) if (cur->timeout == PFTM_UNLINKED) { /* free removed state */ - if (! locked) { - rw_enter_write(&pf_consistency_lock); - locked = 1; - } pf_free_state(cur); } else if (pf_state_expires(cur) <= time_uptime) { /* remove and free expired state */ pf_remove_state(cur); - if (! locked) { - rw_enter_write(&pf_consistency_lock); - locked = 1; - } pf_free_state(cur); } cur = next; } - - if (locked) - rw_exit_write(&pf_consistency_lock); } int diff --git a/sys/net/pf_ioctl.c b/sys/net/pf_ioctl.c index fac156bae3f..7cb7b92ed8a 100644 --- a/sys/net/pf_ioctl.c +++ b/sys/net/pf_ioctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_ioctl.c,v 1.311 2017/05/15 11:23:25 mikeb Exp $ */ +/* $OpenBSD: pf_ioctl.c,v 1.312 2017/05/15 12:26:00 mpi Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -111,7 +111,6 @@ void pf_qid2qname(u_int16_t, char *); void pf_qid_unref(u_int16_t); struct pf_rule pf_default_rule, pf_default_rule_new; -struct rwlock pf_consistency_lock = RWLOCK_INITIALIZER("pfcnslk"); struct { char statusif[IFNAMSIZ]; @@ -999,12 +998,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) return (EACCES); } - if (flags & FWRITE) - rw_enter_write(&pf_consistency_lock); - else - rw_enter_read(&pf_consistency_lock); - - s = splsoftnet(); + NET_LOCK(s); switch (cmd) { case DIOCSTART: @@ -2458,11 +2452,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } fail: - splx(s); - if (flags & FWRITE) - rw_exit_write(&pf_consistency_lock); - else - rw_exit_read(&pf_consistency_lock); + NET_UNLOCK(s); return (error); } diff --git a/sys/net/pf_norm.c b/sys/net/pf_norm.c index 3dfa98abecf..0a9a0df1cb0 100644 --- a/sys/net/pf_norm.c +++ b/sys/net/pf_norm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_norm.c,v 1.203 2017/04/23 11:37:11 sthen Exp $ */ +/* $OpenBSD: pf_norm.c,v 1.204 2017/05/15 12:26:00 mpi Exp $ */ /* * Copyright 2001 Niels Provos <provos@citi.umich.edu> @@ -176,6 +176,8 @@ pf_purge_expired_fragments(void) struct pf_fragment *frag; int32_t expire; + NET_ASSERT_LOCKED(); + expire = time_uptime - pf_default_rule.timeout[PFTM_FRAG]; while ((frag = TAILQ_LAST(&pf_fragqueue, pf_fragqueue)) != NULL) { if (frag->fr_timeout > expire) diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 48d74247965..e2f01130746 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfvar.h,v 1.452 2017/05/15 11:23:25 mikeb Exp $ */ +/* $OpenBSD: pfvar.h,v 1.453 2017/05/15 12:26:00 mpi Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -1632,9 +1632,9 @@ extern void pf_tbladdr_remove(struct pf_addr_wrap *); extern void pf_tbladdr_copyout(struct pf_addr_wrap *); extern void pf_calc_skip_steps(struct pf_rulequeue *); extern void pf_purge_thread(void *); -extern void pf_purge_expired_src_nodes(int); +extern void pf_purge_expired_src_nodes(); extern void pf_purge_expired_states(u_int32_t); -extern void pf_purge_expired_rules(int); +extern void pf_purge_expired_rules(); extern void pf_remove_state(struct pf_state *); extern void pf_remove_divert_state(struct pf_state_key *); extern void pf_free_state(struct pf_state *); @@ -1808,7 +1808,6 @@ int pf_addr_compare(struct pf_addr *, struct pf_addr *, extern struct pf_status pf_status; extern struct pool pf_frent_pl, pf_frag_pl; -extern struct rwlock pf_consistency_lock; struct pf_pool_limit { void *pp; diff --git a/sys/sys/systm.h b/sys/sys/systm.h index 8d925d6294a..45ce7d726a3 100644 --- a/sys/sys/systm.h +++ b/sys/sys/systm.h @@ -1,4 +1,4 @@ -/* $OpenBSD: systm.h,v 1.128 2017/04/30 16:45:46 mpi Exp $ */ +/* $OpenBSD: systm.h,v 1.129 2017/05/15 12:26:00 mpi Exp $ */ /* $NetBSD: systm.h,v 1.50 1996/06/09 04:55:09 briggs Exp $ */ /*- @@ -293,23 +293,31 @@ int uiomove(void *, size_t, struct uio *); #include <sys/rwlock.h> +extern struct rwlock netlock; + #define NET_LOCK(s) \ do { \ + rw_enter_write(&netlock); \ s = splsoftnet(); \ } while (0) #define NET_UNLOCK(s) \ do { \ splx(s); \ + rw_exit_write(&netlock); \ } while (0) #define NET_ASSERT_LOCKED() \ do { \ + if (rw_status(&netlock) != RW_WRITE) \ + splassert_fail(RW_WRITE, rw_status(&netlock), __func__);\ splsoftassert(IPL_SOFTNET); \ } while (0) #define NET_ASSERT_UNLOCKED() \ do { \ + if (rw_status(&netlock) == RW_WRITE) \ + splassert_fail(0, rw_status(&netlock), __func__); \ } while (0) __returns_twice int setjmp(label_t *); diff --git a/sys/uvm/uvm_vnode.c b/sys/uvm/uvm_vnode.c index 449e8796371..d9019c8275d 100644 --- a/sys/uvm/uvm_vnode.c +++ b/sys/uvm/uvm_vnode.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_vnode.c,v 1.96 2017/05/03 02:43:15 guenther Exp $ */ +/* $OpenBSD: uvm_vnode.c,v 1.97 2017/05/15 12:26:00 mpi Exp $ */ /* $NetBSD: uvm_vnode.c,v 1.36 2000/11/24 20:34:01 chs Exp $ */ /* @@ -1176,6 +1176,15 @@ uvn_io(struct uvm_vnode *uvn, vm_page_t *pps, int npages, int flags, int rw) result = vn_lock(vn, LK_EXCLUSIVE | LK_RECURSEFAIL, curproc); if (result == 0) { + int netlocked = (rw_status(&netlock) == RW_WRITE); + + /* + * This process may already have the NET_LOCK(), if we + * faulted in copyin() or copyout() in the network stack. + */ + if (netlocked) + rw_exit_write(&netlock); + /* NOTE: vnode now locked! */ if (rw == UIO_READ) result = VOP_READ(vn, &uio, 0, curproc->p_ucred); @@ -1184,6 +1193,9 @@ uvn_io(struct uvm_vnode *uvn, vm_page_t *pps, int npages, int flags, int rw) (flags & PGO_PDFREECLUST) ? IO_NOCACHE : 0, curproc->p_ucred); + if (netlocked) + rw_enter_write(&netlock); + if ((uvn->u_flags & UVM_VNODE_VNISLOCKED) == 0) VOP_UNLOCK(vn, curproc); } |