From owner-p4-projects@FreeBSD.ORG Fri Aug 22 09:27:07 2003 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id AE3E416A4C1; Fri, 22 Aug 2003 09:27:06 -0700 (PDT) Delivered-To: perforce@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 17D9016A4D9 for ; Fri, 22 Aug 2003 09:27:06 -0700 (PDT) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id 4ACC743FEA for ; Fri, 22 Aug 2003 09:27:05 -0700 (PDT) (envelope-from sam@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.12.6/8.12.6) with ESMTP id h7MGR50U023715 for ; Fri, 22 Aug 2003 09:27:05 -0700 (PDT) (envelope-from sam@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.12.6/8.12.6/Submit) id h7MGR4ES023712 for perforce@freebsd.org; Fri, 22 Aug 2003 09:27:04 -0700 (PDT) Date: Fri, 22 Aug 2003 09:27:04 -0700 (PDT) Message-Id: <200308221627.h7MGR4ES023712@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to sam@freebsd.org using -f From: Sam Leffler To: Perforce Change Reviews Subject: PERFORCE change 36676 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 22 Aug 2003 16:27:07 -0000 http://perforce.freebsd.org/chv.cgi?CH=36676 Change 36676 by sam@sam_ebb on 2003/08/22 09:26:57 checkpoint dummynet locking work Affected files ... .. //depot/projects/netperf/sys/netinet/ip_dummynet.c#4 edit .. //depot/projects/netperf/sys/netinet/ip_fw2.c#3 edit Differences ... ==== //depot/projects/netperf/sys/netinet/ip_dummynet.c#4 (text+ko) ==== @@ -27,8 +27,7 @@ * $FreeBSD: src/sys/netinet/ip_dummynet.c,v 1.68 2003/07/31 10:24:36 maxim Exp $ */ -#define DEB(x) -#define DDB(x) x +#define DUMMYNET_DEBUG /* * This module implements IP dummynet, a bandwidth limiter/delay emulator @@ -123,7 +122,7 @@ static struct dn_pipe *all_pipes = NULL ; /* list of all pipes */ static struct dn_flow_set *all_flow_sets = NULL ;/* list of all flow_sets */ -static struct callout_handle dn_timeout; +static struct callout dn_timeout; #ifdef SYSCTL_NODE SYSCTL_NODE(_net_inet_ip, OID_AUTO, dummynet, @@ -153,6 +152,23 @@ CTLFLAG_RD, &red_max_pkt_size, 0, "RED Max packet size"); #endif +#define DUMMYNET_DEBUG +#ifdef DUMMYNET_DEBUG +int dummynet_debug = 0; +#ifdef SYSCTL_NODE +SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, debug, CTLFLAG_RW, &dummynet_debug, + 0, "control debugging printfs"); +#endif +#define DPRINTF(X) if (dummynet_debug) printf X +#else +#define DPRINTF(X) +#endif + +static struct mtx dummynet_mtx; +#define DUMMYNET_LOCK() mtx_lock(&dummynet_mtx); +#define DUMMYNET_UNLOCK() mtx_unlock(&dummynet_mtx); +#define DUMMYNET_LOCK_ASSERT(_what) mtx_assert(&dummynet_mtx, _what); + static int config_pipe(struct dn_pipe *p); static int ip_dn_ctl(struct sockopt *sopt); @@ -201,14 +217,14 @@ struct dn_heap_entry *p; if (h->size >= new_size ) { - printf("dummynet: heap_init, Bogus call, have %d want %d\n", + printf("dummynet: %s, Bogus call, have %d want %d\n", __func__, h->size, new_size); return 0 ; } new_size = (new_size + HEAP_INCREMENT ) & ~HEAP_INCREMENT ; p = malloc(new_size * sizeof(*p), M_DUMMYNET, M_NOWAIT); if (p == NULL) { - printf("dummynet: heap_init, resize %d failed\n", new_size ); + printf("dummynet: %s, resize %d failed\n", __func__, new_size ); return 1 ; /* error */ } if (h->size > 0) { @@ -434,6 +450,7 @@ case DN_TO_BDG_FWD : if (!BDG_LOADED) { /* somebody unloaded the bridge module. Drop pkt */ + /* XXX rate limit */ printf("dummynet: dropping bridged packet trapped in pipe\n"); m_freem(pkt->dn_m); break; @@ -525,6 +542,8 @@ struct dn_pipe *p = q->fs->pipe ; int p_was_empty ; + DUMMYNET_LOCK_ASSERT(MA_OWNED); + if (p == NULL) { printf("dummynet: ready_event- pipe is gone\n"); return ; @@ -589,14 +608,16 @@ struct dn_heap *sch = &(p->scheduler_heap); struct dn_heap *neh = &(p->not_eligible_heap) ; + DUMMYNET_LOCK_ASSERT(MA_OWNED); + if (p->if_name[0] == 0) /* tx clock is simulated */ p->numbytes += ( curr_time - p->sched_time ) * p->bandwidth; else { /* tx clock is for real, the ifq must be empty or this is a NOP */ if (p->ifp && p->ifp->if_snd.ifq_head != NULL) return ; else { - DEB(printf("dummynet: pipe %d ready from %s --\n", - p->pipe_nr, p->if_name);) + DPRINTF(("dummynet: pipe %d ready from %s --\n", + p->pipe_nr, p->if_name)); } } @@ -705,7 +726,6 @@ { void *p ; /* generic parameter to handler */ struct dn_heap *h ; - int s ; struct dn_heap *heaps[3]; int i; struct dn_pipe *pe ; @@ -713,14 +733,15 @@ heaps[0] = &ready_heap ; /* fixed-rate queues */ heaps[1] = &wfq_ready_heap ; /* wfq queues */ heaps[2] = &extract_heap ; /* delay line */ - s = splimp(); /* see note on top, splnet() is not enough */ + + DUMMYNET_LOCK(); curr_time++ ; for (i=0; i < 3 ; i++) { h = heaps[i]; while (h->elements > 0 && DN_KEY_LEQ(h->p[0].key, curr_time) ) { - DDB(if (h->p[0].key > curr_time) + if (h->p[0].key > curr_time) printf("dummynet: warning, heap %d is %d ticks late\n", - i, (int)(curr_time - h->p[0].key));) + i, (int)(curr_time - h->p[0].key)); p = h->p[0].object ; /* store a copy before heap_extract */ heap_extract(h, NULL); /* need to extract before processing */ if (i == 0) @@ -746,8 +767,9 @@ q->S = q->F + 1 ; /* mark timestamp as invalid */ pe->sum -= q->fs->weight ; } - splx(s); - dn_timeout = timeout(dummynet, NULL, 1); + DUMMYNET_UNLOCK(); + + callout_reset(&dn_timeout, 1, dummynet, NULL); } /* @@ -758,6 +780,7 @@ { struct dn_pipe *p; + DUMMYNET_LOCK(); for (p = all_pipes; p ; p = p->next ) if (p->ifp == ifp) break ; @@ -767,16 +790,18 @@ for (p = all_pipes; p ; p = p->next ) if (!strcmp(p->if_name, buf) ) { p->ifp = ifp ; - DEB(printf("dummynet: ++ tx rdy from %s (now found)\n", buf);) + DPRINTF(("dummynet: ++ tx rdy from %s (now found)\n", buf)); break ; } } if (p != NULL) { - DEB(printf("dummynet: ++ tx rdy from %s%d - qlen %d\n", ifp->if_name, - ifp->if_unit, ifp->if_snd.ifq_len);) + DPRINTF(("dummynet: ++ tx rdy from %s%d - qlen %d\n", ifp->if_name, + ifp->if_unit, ifp->if_snd.ifq_len)); p->numbytes = 0 ; /* mark ready for I/O */ ready_event_wfq(p); } + DUMMYNET_UNLOCK(); + return 0; } @@ -937,7 +962,7 @@ /* queue in bytes or packets ? */ u_int q_size = (fs->flags_fs & DN_QSIZE_IS_BYTES) ? q->len_bytes : q->len; - DEB(printf("\ndummynet: %d q: %2u ", (int) curr_time, q_size);) + DPRINTF(("\ndummynet: %d q: %2u ", (int) curr_time, q_size)); /* average queue size estimation */ if (q_size != 0) { @@ -963,7 +988,7 @@ SCALE_MUL(q->avg, fs->w_q_lookup[t]) : 0; } } - DEB(printf("dummynet: avg: %u ", SCALE_VAL(q->avg));) + DPRINTF(("dummynet: avg: %u ", SCALE_VAL(q->avg))); /* should i drop ? */ @@ -982,7 +1007,7 @@ p_b = SCALE_MUL((int64_t) fs->c_3, (int64_t) q->avg) - fs->c_4; } else { q->count = -1; - DEB(printf("dummynet: - drop");); + DPRINTF(("dummynet: - drop")); return 1 ; } } else if (q->avg > fs->min_th) { @@ -1004,7 +1029,7 @@ */ if (SCALE_MUL(p_b, SCALE((int64_t) q->count)) > q->random) { q->count = 0; - DEB(printf("dummynet: - red drop");) + DPRINTF(("dummynet: - red drop")); /* after a drop we calculate a new random value */ q->random = random() & 0xffff; return 1; /* drop */ @@ -1086,7 +1111,6 @@ struct dn_pipe *pipe ; u_int64_t len = m->m_pkthdr.len ; struct dn_flow_queue *q = NULL ; - int s = splimp(); int is_pipe; #if IPFW2 ipfw_insn *cmd = fwa->rule->cmd + fwa->rule->act_ofs; @@ -1100,6 +1124,7 @@ pipe_nr &= 0xffff ; + DUMMYNET_LOCK(); /* * This is a dummynet rule, so we expect an O_PIPE or O_QUEUE rule. */ @@ -1240,21 +1265,21 @@ if (pipe->numbytes >= 0) { /* pipe is idle */ if (pipe->scheduler_heap.elements != 1) printf("dummynet: OUCH! pipe should have been idle!\n"); - DEB(printf("dummynet: waking up pipe %d at %d\n", - pipe->pipe_nr, (int)(q->F >> MY_M)); ) + DPRINTF(("dummynet: waking up pipe %d at %d\n", + pipe->pipe_nr, (int)(q->F >> MY_M))); pipe->sched_time = curr_time ; ready_event_wfq(pipe); } } } done: - splx(s); + DUMMYNET_UNLOCK(); return 0; dropit: - splx(s); if (q) q->drops++ ; + DUMMYNET_UNLOCK(); m_freem(m); return ( (fs && (fs->flags_fs & DN_NOERROR)) ? 0 : ENOBUFS); } @@ -1283,6 +1308,8 @@ struct dn_flow_queue *q, *qn ; int i ; + DUMMYNET_LOCK_ASSERT(MA_OWNED); + for (i = 0 ; i <= fs->rq_size ; i++ ) { for (q = fs->rq[i] ; q ; q = qn ) { for (pkt = q->head ; pkt ; ) @@ -1334,10 +1361,8 @@ { struct dn_pipe *curr_p, *p ; struct dn_flow_set *fs, *curr_fs; - int s ; - s = splimp() ; - + DUMMYNET_LOCK(); /* remove all references to pipes ...*/ flush_pipe_ptrs(NULL); /* prevent future matches... */ @@ -1349,7 +1374,8 @@ heap_free(&ready_heap); heap_free(&wfq_ready_heap); heap_free(&extract_heap); - splx(s) ; + DUMMYNET_UNLOCK(); + /* * Now purge all queued pkts and delete all pipes */ @@ -1393,6 +1419,8 @@ struct dn_pkt *pkt ; struct dn_flow_set *fs ; + DUMMYNET_LOCK_ASSERT(MA_OWNED); + /* * If the rule references a queue (dn_flow_set), then scan * the flow set, otherwise scan pipes. Should do either, but doing @@ -1516,7 +1544,7 @@ static int config_pipe(struct dn_pipe *p) { - int i, r, s; + int i, r; struct dn_flow_set *pfs = &(p->fs); struct dn_flow_queue *q; @@ -1534,6 +1562,8 @@ return EINVAL ; if (p->pipe_nr != 0) { /* this is a pipe */ struct dn_pipe *x, *a, *b; + + DUMMYNET_LOCK(); /* locate pipe */ for (a = NULL , b = all_pipes ; b && b->pipe_nr < p->pipe_nr ; a = b , b = b->next) ; @@ -1552,15 +1582,12 @@ x->idle_heap.offset=OFFSET_OF(struct dn_flow_queue, heap_pos); } else { x = b; - s = splimp(); /* Flush accumulated credit for all queues */ for (i = 0; i <= x->fs.rq_size; i++) for (q = x->fs.rq[i]; q; q = q->next) q->numbytes = 0; - splx(s); } - s = splimp(); x->bandwidth = p->bandwidth ; x->numbytes = 0; /* just in case... */ bcopy(p->if_name, x->if_name, sizeof(p->if_name) ); @@ -1572,8 +1599,8 @@ if ( x->fs.rq == NULL ) { /* a new pipe */ r = alloc_hash(&(x->fs), pfs) ; if (r) { + DUMMYNET_UNLOCK(); free(x, M_DUMMYNET); - splx(s); return r ; } x->next = b ; @@ -1582,10 +1609,11 @@ else a->next = x ; } - splx(s); + DUMMYNET_UNLOCK(); } else { /* config queue */ struct dn_flow_set *x, *a, *b ; + DUMMYNET_LOCK(); /* locate flow_set */ for (a=NULL, b=all_flow_sets ; b && b->fs_nr < pfs->fs_nr ; a = b , b = b->next) ; @@ -1595,6 +1623,7 @@ return EINVAL ; x = malloc(sizeof(struct dn_flow_set), M_DUMMYNET, M_NOWAIT|M_ZERO); if (x == NULL) { + DUMMYNET_UNLOCK(); printf("dummynet: no memory for new flow_set\n"); return ENOSPC; } @@ -1611,14 +1640,13 @@ return EINVAL ; x = b; } - s = splimp(); set_fs_parms(x, pfs); if ( x->rq == NULL ) { /* a new flow_set */ r = alloc_hash(x, pfs) ; if (r) { + DUMMYNET_UNLOCK(); free(x, M_DUMMYNET); - splx(s); return r ; } x->next = b; @@ -1627,7 +1655,7 @@ else a->next = x; } - splx(s); + DUMMYNET_UNLOCK(); } return 0 ; } @@ -1680,6 +1708,8 @@ struct dn_pipe *p; struct dn_pkt *pkt; + DUMMYNET_LOCK_ASSERT(MA_OWNED); + heap_free(&ready_heap); heap_free(&wfq_ready_heap); heap_free(&extract_heap); @@ -1701,8 +1731,6 @@ static int delete_pipe(struct dn_pipe *p) { - int s ; - if (p->pipe_nr == 0 && p->fs.fs_nr == 0) return EINVAL ; if (p->pipe_nr != 0 && p->fs.fs_nr != 0) @@ -1711,13 +1739,14 @@ struct dn_pipe *a, *b; struct dn_flow_set *fs; + DUMMYNET_LOCK(); /* locate pipe */ for (a = NULL , b = all_pipes ; b && b->pipe_nr < p->pipe_nr ; a = b , b = b->next) ; - if (b == NULL || (b->pipe_nr != p->pipe_nr) ) + if (b == NULL || (b->pipe_nr != p->pipe_nr) ) { + DUMMYNET_UNLOCK(); return EINVAL ; /* not found */ - - s = splimp() ; + } /* unlink from list of pipes */ if (a == NULL) @@ -1740,18 +1769,21 @@ /* remove reference to here from extract_heap and wfq_ready_heap */ pipe_remove_from_heap(&extract_heap, b); pipe_remove_from_heap(&wfq_ready_heap, b); - splx(s); + DUMMYNET_UNLOCK(); + free(b, M_DUMMYNET); } else { /* this is a WF2Q queue (dn_flow_set) */ struct dn_flow_set *a, *b; + DUMMYNET_LOCK(); /* locate set */ for (a = NULL, b = all_flow_sets ; b && b->fs_nr < p->fs.fs_nr ; a = b , b = b->next) ; - if (b == NULL || (b->fs_nr != p->fs.fs_nr) ) + if (b == NULL || (b->fs_nr != p->fs.fs_nr) ) { + DUMMYNET_UNLOCK(); return EINVAL ; /* not found */ + } - s = splimp() ; if (a == NULL) all_flow_sets = b->next ; else @@ -1769,7 +1801,7 @@ #endif } purge_flow_set(b, 1); - splx(s); + DUMMYNET_UNLOCK(); } return 0 ; } @@ -1783,6 +1815,8 @@ int i, copied = 0 ; struct dn_flow_queue *q, *qp = (struct dn_flow_queue *)bp; + DUMMYNET_LOCK_ASSERT(MA_OWNED); + for (i = 0 ; i <= set->rq_size ; i++) for (q = set->rq[i] ; q ; q = q->next, qp++ ) { if (q->hash_slot != i) @@ -1811,9 +1845,10 @@ size_t size ; struct dn_flow_set *set ; struct dn_pipe *p ; - int s, error=0 ; + int error=0 ; - s = splimp(); + /* XXX lock held too long */ + DUMMYNET_LOCK(); /* * compute size of data structures: list of pipes and flow_sets. */ @@ -1825,7 +1860,7 @@ set->rq_elements * sizeof(struct dn_flow_queue); buf = malloc(size, M_TEMP, M_NOWAIT); if (buf == 0) { - splx(s); + DUMMYNET_UNLOCK(); return ENOBUFS ; } for (p = all_pipes, bp = buf ; p ; p = p->next ) { @@ -1864,7 +1899,8 @@ bp += sizeof( *set ) ; bp = dn_copy_set( set, bp ); } - splx(s); + DUMMYNET_UNLOCK(); + error = sooptcopyout(sopt, buf, size); free(buf, M_TEMP); return error ; @@ -1927,7 +1963,11 @@ static void ip_dn_init(void) { - printf("DUMMYNET initialized (011031)\n"); + if (bootverbose) + printf("DUMMYNET initialized (011031)\n"); + + mtx_init(&dummynet_mtx, "dummynet", NULL, MTX_DEF); + all_pipes = NULL ; all_flow_sets = NULL ; ready_heap.size = ready_heap.elements = 0 ; @@ -1938,27 +1978,40 @@ extract_heap.size = extract_heap.elements = 0 ; extract_heap.offset = 0 ; + ip_dn_ctl_ptr = ip_dn_ctl; ip_dn_io_ptr = dummynet_io; ip_dn_ruledel_ptr = dn_rule_delete; - bzero(&dn_timeout, sizeof(struct callout_handle)); - dn_timeout = timeout(dummynet, NULL, 1); + + callout_init(&dn_timeout, CALLOUT_MPSAFE); + callout_reset(&dn_timeout, 1, dummynet, NULL); +} + +#ifdef KLD_MODULE +static void +ip_dn_destroy(void) +{ + ip_dn_ctl_ptr = NULL; + ip_dn_io_ptr = NULL; + ip_dn_ruledel_ptr = NULL; + + callout_stop(&dn_timeout); + dummynet_flush(); + + mtx_destroy(&dummynet_mtx); } +#endif /* KLD_MODULE */ static int dummynet_modevent(module_t mod, int type, void *data) { - int s; switch (type) { case MOD_LOAD: - s = splimp(); if (DUMMYNET_LOADED) { - splx(s); printf("DUMMYNET already loaded\n"); return EEXIST ; } ip_dn_init(); - splx(s); break; case MOD_UNLOAD: @@ -1966,13 +2019,7 @@ printf("dummynet statically compiled, cannot unload\n"); return EINVAL ; #else - s = splimp(); - untimeout(dummynet, NULL, dn_timeout); - dummynet_flush(); - ip_dn_ctl_ptr = NULL; - ip_dn_io_ptr = NULL; - ip_dn_ruledel_ptr = NULL; - splx(s); + ip_dn_destroy(); #endif break ; default: ==== //depot/projects/netperf/sys/netinet/ip_fw2.c#3 (text+ko) ==== @@ -2102,8 +2102,7 @@ { struct ip_fw *rule; - IPFW_LOCK_ASSERT(&layer3_chain, MA_OWNED); - + IPFW_LOCK(&layer3_chain); for (rule = layer3_chain.rules; rule; rule = rule->next) { ipfw_insn_pipe *cmd = (ipfw_insn_pipe *)ACTION_PTR(rule); @@ -2119,6 +2118,7 @@ !bcmp(&cmd->pipe_ptr, &match, sizeof(match)) ) bzero(&cmd->pipe_ptr, sizeof(cmd->pipe_ptr)); } + IPFW_UNLOCK(&layer3_chain); } /*