Re: router timer mutex
On Thu, Apr 28, 2022 at 07:24:22PM +0200, Alexander Bluhm wrote: > I still need an ok for this diff. It is the final step before we > can run IP forwaring in parallel. Fine with me. If it holds you back put it in OK claudio@ I will rip the rttimer code appart in the next days and make that API a lot simpler. > bluhm > > On Thu, Apr 21, 2022 at 05:44:17PM +0200, Alexander Bluhm wrote: > > On Wed, Apr 20, 2022 at 08:12:51PM +0200, Alexander Bluhm wrote: > > > mvs@ reminded me of a crash I have seen in December. Route timers > > > are not MP safe, but I think this can be fixed with a mutex. The > > > idea is to protect the global lists with a mutex and move the rttimer > > > into a temporary list. Then the callback and pool put can be called > > > later without mutex. > > > > I have a tiny update to the diff. > > > > - Global locks are documented with capital letter, so use [T]. > > > > - rt_timer_add() grabbed the mutex twice, first remove then add. > > Better exchange in one critical section. pool_get before and > > pool_put after. > > > > ok? > > > > Index: net/route.c > > === > > RCS file: /data/mirror/openbsd/cvs/src/sys/net/route.c,v > > retrieving revision 1.406 > > diff -u -p -r1.406 route.c > > --- net/route.c 20 Apr 2022 17:58:22 - 1.406 > > +++ net/route.c 21 Apr 2022 13:31:52 - > > @@ -1361,7 +1361,8 @@ rt_ifa_purge_walker(struct rtentry *rt, > > * for multiple queues for efficiency's sake... > > */ > > > > -LIST_HEAD(, rttimer_queue) rttimer_queue_head; > > +struct mutex rttimer_mtx; > > +LIST_HEAD(, rttimer_queue) rttimer_queue_head; /* [T] */ > > > > #define RTTIMER_CALLOUT(r) { \ > > if (r->rtt_func != NULL) { \ > > @@ -1393,6 +1394,7 @@ rt_timer_init(void) > > pool_init(_queue_pool, sizeof(struct rttimer_queue), 0, > > IPL_MPFLOOR, 0, "rttmrq", NULL); > > > > + mtx_init(_mtx, IPL_MPFLOOR); > > LIST_INIT(_queue_head); > > timeout_set_proc(_timer_timeout, rt_timer_timer, _timer_timeout); > > timeout_add_sec(_timer_timeout, 1); > > @@ -1408,7 +1410,10 @@ rt_timer_queue_create(int timeout) > > rtq->rtq_timeout = timeout; > > rtq->rtq_count = 0; > > TAILQ_INIT(>rtq_head); > > + > > + mtx_enter(_mtx); > > LIST_INSERT_HEAD(_queue_head, rtq, rtq_link); > > + mtx_leave(_mtx); > > > > return (rtq); > > } > > @@ -1416,28 +1421,36 @@ rt_timer_queue_create(int timeout) > > void > > rt_timer_queue_change(struct rttimer_queue *rtq, int timeout) > > { > > + mtx_enter(_mtx); > > rtq->rtq_timeout = timeout; > > + mtx_leave(_mtx); > > } > > > > void > > rt_timer_queue_destroy(struct rttimer_queue *rtq) > > { > > - struct rttimer *r; > > + struct rttimer *r; > > + TAILQ_HEAD(, rttimer)rttlist; > > > > NET_ASSERT_LOCKED(); > > > > + TAILQ_INIT(); > > + mtx_enter(_mtx); > > while ((r = TAILQ_FIRST(>rtq_head)) != NULL) { > > LIST_REMOVE(r, rtt_link); > > TAILQ_REMOVE(>rtq_head, r, rtt_next); > > + TAILQ_INSERT_TAIL(, r, rtt_next); > > + KASSERT(rtq->rtq_count > 0); > > + rtq->rtq_count--; > > + } > > + LIST_REMOVE(rtq, rtq_link); > > + mtx_leave(_mtx); > > + > > + while ((r = TAILQ_FIRST()) != NULL) { > > + TAILQ_REMOVE(, r, rtt_next); > > RTTIMER_CALLOUT(r); > > pool_put(_pool, r); > > - if (rtq->rtq_count > 0) > > - rtq->rtq_count--; > > - else > > - printf("rt_timer_queue_destroy: rtq_count reached 0\n"); > > } > > - > > - LIST_REMOVE(rtq, rtq_link); > > pool_put(_queue_pool, rtq); > > } > > > > @@ -1450,15 +1463,22 @@ rt_timer_queue_count(struct rttimer_queu > > void > > rt_timer_remove_all(struct rtentry *rt) > > { > > - struct rttimer *r; > > + struct rttimer *r; > > + TAILQ_HEAD(, rttimer)rttlist; > > > > + TAILQ_INIT(); > > + mtx_enter(_mtx); > > while ((r = LIST_FIRST(>rt_timer)) != NULL) { > > LIST_REMOVE(r, rtt_link); > > TAILQ_REMOVE(>rtt_queue->rtq_head, r, rtt_next); > > - if (r->rtt_queue->rtq_count > 0) > > - r->rtt_queue->rtq_count--; > > - else > > - printf("rt_timer_remove_all: rtq_count reached 0\n"); > > + TAILQ_INSERT_TAIL(, r, rtt_next); > > + KASSERT(r->rtt_queue->rtq_count > 0); > > + r->rtt_queue->rtq_count--; > > + } > > + mtx_leave(_mtx); > > + > > + while ((r = TAILQ_FIRST()) != NULL) { > > + TAILQ_REMOVE(, r, rtt_next); > > pool_put(_pool, r); > > } > > } > > @@ -1467,12 +1487,23 @@ int > > rt_timer_add(struct rtentry *rt, void (*func)(struct rtentry *, > > struct rttimer *), struct rttimer_queue *queue, u_int rtableid) > >
Re: router timer mutex
I still need an ok for this diff. It is the final step before we can run IP forwaring in parallel. bluhm On Thu, Apr 21, 2022 at 05:44:17PM +0200, Alexander Bluhm wrote: > On Wed, Apr 20, 2022 at 08:12:51PM +0200, Alexander Bluhm wrote: > > mvs@ reminded me of a crash I have seen in December. Route timers > > are not MP safe, but I think this can be fixed with a mutex. The > > idea is to protect the global lists with a mutex and move the rttimer > > into a temporary list. Then the callback and pool put can be called > > later without mutex. > > I have a tiny update to the diff. > > - Global locks are documented with capital letter, so use [T]. > > - rt_timer_add() grabbed the mutex twice, first remove then add. > Better exchange in one critical section. pool_get before and > pool_put after. > > ok? > > Index: net/route.c > === > RCS file: /data/mirror/openbsd/cvs/src/sys/net/route.c,v > retrieving revision 1.406 > diff -u -p -r1.406 route.c > --- net/route.c 20 Apr 2022 17:58:22 - 1.406 > +++ net/route.c 21 Apr 2022 13:31:52 - > @@ -1361,7 +1361,8 @@ rt_ifa_purge_walker(struct rtentry *rt, > * for multiple queues for efficiency's sake... > */ > > -LIST_HEAD(, rttimer_queue) rttimer_queue_head; > +struct mutex rttimer_mtx; > +LIST_HEAD(, rttimer_queue) rttimer_queue_head; /* [T] */ > > #define RTTIMER_CALLOUT(r) { \ > if (r->rtt_func != NULL) { \ > @@ -1393,6 +1394,7 @@ rt_timer_init(void) > pool_init(_queue_pool, sizeof(struct rttimer_queue), 0, > IPL_MPFLOOR, 0, "rttmrq", NULL); > > + mtx_init(_mtx, IPL_MPFLOOR); > LIST_INIT(_queue_head); > timeout_set_proc(_timer_timeout, rt_timer_timer, _timer_timeout); > timeout_add_sec(_timer_timeout, 1); > @@ -1408,7 +1410,10 @@ rt_timer_queue_create(int timeout) > rtq->rtq_timeout = timeout; > rtq->rtq_count = 0; > TAILQ_INIT(>rtq_head); > + > + mtx_enter(_mtx); > LIST_INSERT_HEAD(_queue_head, rtq, rtq_link); > + mtx_leave(_mtx); > > return (rtq); > } > @@ -1416,28 +1421,36 @@ rt_timer_queue_create(int timeout) > void > rt_timer_queue_change(struct rttimer_queue *rtq, int timeout) > { > + mtx_enter(_mtx); > rtq->rtq_timeout = timeout; > + mtx_leave(_mtx); > } > > void > rt_timer_queue_destroy(struct rttimer_queue *rtq) > { > - struct rttimer *r; > + struct rttimer *r; > + TAILQ_HEAD(, rttimer)rttlist; > > NET_ASSERT_LOCKED(); > > + TAILQ_INIT(); > + mtx_enter(_mtx); > while ((r = TAILQ_FIRST(>rtq_head)) != NULL) { > LIST_REMOVE(r, rtt_link); > TAILQ_REMOVE(>rtq_head, r, rtt_next); > + TAILQ_INSERT_TAIL(, r, rtt_next); > + KASSERT(rtq->rtq_count > 0); > + rtq->rtq_count--; > + } > + LIST_REMOVE(rtq, rtq_link); > + mtx_leave(_mtx); > + > + while ((r = TAILQ_FIRST()) != NULL) { > + TAILQ_REMOVE(, r, rtt_next); > RTTIMER_CALLOUT(r); > pool_put(_pool, r); > - if (rtq->rtq_count > 0) > - rtq->rtq_count--; > - else > - printf("rt_timer_queue_destroy: rtq_count reached 0\n"); > } > - > - LIST_REMOVE(rtq, rtq_link); > pool_put(_queue_pool, rtq); > } > > @@ -1450,15 +1463,22 @@ rt_timer_queue_count(struct rttimer_queu > void > rt_timer_remove_all(struct rtentry *rt) > { > - struct rttimer *r; > + struct rttimer *r; > + TAILQ_HEAD(, rttimer)rttlist; > > + TAILQ_INIT(); > + mtx_enter(_mtx); > while ((r = LIST_FIRST(>rt_timer)) != NULL) { > LIST_REMOVE(r, rtt_link); > TAILQ_REMOVE(>rtt_queue->rtq_head, r, rtt_next); > - if (r->rtt_queue->rtq_count > 0) > - r->rtt_queue->rtq_count--; > - else > - printf("rt_timer_remove_all: rtq_count reached 0\n"); > + TAILQ_INSERT_TAIL(, r, rtt_next); > + KASSERT(r->rtt_queue->rtq_count > 0); > + r->rtt_queue->rtq_count--; > + } > + mtx_leave(_mtx); > + > + while ((r = TAILQ_FIRST()) != NULL) { > + TAILQ_REMOVE(, r, rtt_next); > pool_put(_pool, r); > } > } > @@ -1467,12 +1487,23 @@ int > rt_timer_add(struct rtentry *rt, void (*func)(struct rtentry *, > struct rttimer *), struct rttimer_queue *queue, u_int rtableid) > { > - struct rttimer *r; > + struct rttimer *r, *rnew; > time_t current_time; > > + rnew = pool_get(_pool, PR_NOWAIT | PR_ZERO); > + if (rnew == NULL) > + return (ENOBUFS); > + > current_time = getuptime(); > - rt->rt_expire = current_time + queue->rtq_timeout; > > + rnew->rtt_rt
Re: router timer mutex
On Wed, Apr 20, 2022 at 08:12:51PM +0200, Alexander Bluhm wrote: > mvs@ reminded me of a crash I have seen in December. Route timers > are not MP safe, but I think this can be fixed with a mutex. The > idea is to protect the global lists with a mutex and move the rttimer > into a temporary list. Then the callback and pool put can be called > later without mutex. I have a tiny update to the diff. - Global locks are documented with capital letter, so use [T]. - rt_timer_add() grabbed the mutex twice, first remove then add. Better exchange in one critical section. pool_get before and pool_put after. ok? Index: net/route.c === RCS file: /data/mirror/openbsd/cvs/src/sys/net/route.c,v retrieving revision 1.406 diff -u -p -r1.406 route.c --- net/route.c 20 Apr 2022 17:58:22 - 1.406 +++ net/route.c 21 Apr 2022 13:31:52 - @@ -1361,7 +1361,8 @@ rt_ifa_purge_walker(struct rtentry *rt, * for multiple queues for efficiency's sake... */ -LIST_HEAD(, rttimer_queue) rttimer_queue_head; +struct mutex rttimer_mtx; +LIST_HEAD(, rttimer_queue) rttimer_queue_head; /* [T] */ #define RTTIMER_CALLOUT(r) { \ if (r->rtt_func != NULL) { \ @@ -1393,6 +1394,7 @@ rt_timer_init(void) pool_init(_queue_pool, sizeof(struct rttimer_queue), 0, IPL_MPFLOOR, 0, "rttmrq", NULL); + mtx_init(_mtx, IPL_MPFLOOR); LIST_INIT(_queue_head); timeout_set_proc(_timer_timeout, rt_timer_timer, _timer_timeout); timeout_add_sec(_timer_timeout, 1); @@ -1408,7 +1410,10 @@ rt_timer_queue_create(int timeout) rtq->rtq_timeout = timeout; rtq->rtq_count = 0; TAILQ_INIT(>rtq_head); + + mtx_enter(_mtx); LIST_INSERT_HEAD(_queue_head, rtq, rtq_link); + mtx_leave(_mtx); return (rtq); } @@ -1416,28 +1421,36 @@ rt_timer_queue_create(int timeout) void rt_timer_queue_change(struct rttimer_queue *rtq, int timeout) { + mtx_enter(_mtx); rtq->rtq_timeout = timeout; + mtx_leave(_mtx); } void rt_timer_queue_destroy(struct rttimer_queue *rtq) { - struct rttimer *r; + struct rttimer *r; + TAILQ_HEAD(, rttimer)rttlist; NET_ASSERT_LOCKED(); + TAILQ_INIT(); + mtx_enter(_mtx); while ((r = TAILQ_FIRST(>rtq_head)) != NULL) { LIST_REMOVE(r, rtt_link); TAILQ_REMOVE(>rtq_head, r, rtt_next); + TAILQ_INSERT_TAIL(, r, rtt_next); + KASSERT(rtq->rtq_count > 0); + rtq->rtq_count--; + } + LIST_REMOVE(rtq, rtq_link); + mtx_leave(_mtx); + + while ((r = TAILQ_FIRST()) != NULL) { + TAILQ_REMOVE(, r, rtt_next); RTTIMER_CALLOUT(r); pool_put(_pool, r); - if (rtq->rtq_count > 0) - rtq->rtq_count--; - else - printf("rt_timer_queue_destroy: rtq_count reached 0\n"); } - - LIST_REMOVE(rtq, rtq_link); pool_put(_queue_pool, rtq); } @@ -1450,15 +1463,22 @@ rt_timer_queue_count(struct rttimer_queu void rt_timer_remove_all(struct rtentry *rt) { - struct rttimer *r; + struct rttimer *r; + TAILQ_HEAD(, rttimer)rttlist; + TAILQ_INIT(); + mtx_enter(_mtx); while ((r = LIST_FIRST(>rt_timer)) != NULL) { LIST_REMOVE(r, rtt_link); TAILQ_REMOVE(>rtt_queue->rtq_head, r, rtt_next); - if (r->rtt_queue->rtq_count > 0) - r->rtt_queue->rtq_count--; - else - printf("rt_timer_remove_all: rtq_count reached 0\n"); + TAILQ_INSERT_TAIL(, r, rtt_next); + KASSERT(r->rtt_queue->rtq_count > 0); + r->rtt_queue->rtq_count--; + } + mtx_leave(_mtx); + + while ((r = TAILQ_FIRST()) != NULL) { + TAILQ_REMOVE(, r, rtt_next); pool_put(_pool, r); } } @@ -1467,12 +1487,23 @@ int rt_timer_add(struct rtentry *rt, void (*func)(struct rtentry *, struct rttimer *), struct rttimer_queue *queue, u_int rtableid) { - struct rttimer *r; + struct rttimer *r, *rnew; time_t current_time; + rnew = pool_get(_pool, PR_NOWAIT | PR_ZERO); + if (rnew == NULL) + return (ENOBUFS); + current_time = getuptime(); - rt->rt_expire = current_time + queue->rtq_timeout; + rnew->rtt_rt = rt; + rnew->rtt_time = current_time; + rnew->rtt_func = func; + rnew->rtt_queue = queue; + rnew->rtt_tableid = rtableid; + + mtx_enter(_mtx); + rt->rt_expire = current_time + queue->rtq_timeout; /* * If there's already a timer with this action, destroy it
Re: router timer mutex
On Wed, Apr 20, 2022 at 08:12:51PM +0200, Alexander Bluhm wrote: > Hi, > > mvs@ reminded me of a crash I have seen in December. Route timers > are not MP safe, but I think this can be fixed with a mutex. The > idea is to protect the global lists with a mutex and move the rttimer > into a temporary list. Then the callback and pool put can be called > later without mutex. > > It survived a full regress with witness. > > Hrvoje: Can you put this on your test machine together with parallel > IP forwarding? > > ok? I would have prefer if the code was refactored first. The removal of a rt_timer is copied over in 4 or 5 places with almost no difference. In the rt_timer_queue_destroy() case you can use TAILQ_CONCAT and kill one loop. Also I would use TAILQ_HEAD_INITIALIZER() instead of TAILQ_INIT(). To be honest most of this code should be directly replaced with the timeout API. I bet the timeout API is more efficent. > Index: net/route.c > === > RCS file: /cvs/src/sys/net/route.c,v > retrieving revision 1.406 > diff -u -p -r1.406 route.c > --- net/route.c 20 Apr 2022 17:58:22 - 1.406 > +++ net/route.c 20 Apr 2022 18:00:39 - > @@ -1361,7 +1361,8 @@ rt_ifa_purge_walker(struct rtentry *rt, > * for multiple queues for efficiency's sake... > */ > > -LIST_HEAD(, rttimer_queue) rttimer_queue_head; > +struct mutex rttimer_mtx; > +LIST_HEAD(, rttimer_queue) rttimer_queue_head; /* [t] */ > > #define RTTIMER_CALLOUT(r) { \ > if (r->rtt_func != NULL) { \ > @@ -1393,6 +1394,7 @@ rt_timer_init(void) > pool_init(_queue_pool, sizeof(struct rttimer_queue), 0, > IPL_MPFLOOR, 0, "rttmrq", NULL); > > + mtx_init(_mtx, IPL_MPFLOOR); > LIST_INIT(_queue_head); > timeout_set_proc(_timer_timeout, rt_timer_timer, _timer_timeout); > timeout_add_sec(_timer_timeout, 1); > @@ -1408,7 +1410,10 @@ rt_timer_queue_create(int timeout) > rtq->rtq_timeout = timeout; > rtq->rtq_count = 0; > TAILQ_INIT(>rtq_head); > + > + mtx_enter(_mtx); > LIST_INSERT_HEAD(_queue_head, rtq, rtq_link); > + mtx_leave(_mtx); > > return (rtq); > } > @@ -1416,28 +1421,36 @@ rt_timer_queue_create(int timeout) > void > rt_timer_queue_change(struct rttimer_queue *rtq, int timeout) > { > + mtx_enter(_mtx); > rtq->rtq_timeout = timeout; > + mtx_leave(_mtx); > } > > void > rt_timer_queue_destroy(struct rttimer_queue *rtq) > { > - struct rttimer *r; > + struct rttimer *r; > + TAILQ_HEAD(, rttimer)rttlist; > > NET_ASSERT_LOCKED(); > > + TAILQ_INIT(); > + mtx_enter(_mtx); > while ((r = TAILQ_FIRST(>rtq_head)) != NULL) { > LIST_REMOVE(r, rtt_link); > TAILQ_REMOVE(>rtq_head, r, rtt_next); > + TAILQ_INSERT_TAIL(, r, rtt_next); > + KASSERT(rtq->rtq_count > 0); > + rtq->rtq_count--; > + } > + LIST_REMOVE(rtq, rtq_link); > + mtx_leave(_mtx); > + > + while ((r = TAILQ_FIRST()) != NULL) { > + TAILQ_REMOVE(, r, rtt_next); > RTTIMER_CALLOUT(r); > pool_put(_pool, r); > - if (rtq->rtq_count > 0) > - rtq->rtq_count--; > - else > - printf("rt_timer_queue_destroy: rtq_count reached 0\n"); > } > - > - LIST_REMOVE(rtq, rtq_link); > pool_put(_queue_pool, rtq); > } > > @@ -1450,15 +1463,22 @@ rt_timer_queue_count(struct rttimer_queu > void > rt_timer_remove_all(struct rtentry *rt) > { > - struct rttimer *r; > + struct rttimer *r; > + TAILQ_HEAD(, rttimer)rttlist; > > + TAILQ_INIT(); > + mtx_enter(_mtx); > while ((r = LIST_FIRST(>rt_timer)) != NULL) { > LIST_REMOVE(r, rtt_link); > TAILQ_REMOVE(>rtt_queue->rtq_head, r, rtt_next); > - if (r->rtt_queue->rtq_count > 0) > - r->rtt_queue->rtq_count--; > - else > - printf("rt_timer_remove_all: rtq_count reached 0\n"); > + TAILQ_INSERT_TAIL(, r, rtt_next); > + KASSERT(r->rtt_queue->rtq_count > 0); > + r->rtt_queue->rtq_count--; > + } > + mtx_leave(_mtx); > + > + while ((r = TAILQ_FIRST()) != NULL) { > + TAILQ_REMOVE(, r, rtt_next); > pool_put(_pool, r); > } > } > @@ -1471,8 +1491,9 @@ rt_timer_add(struct rtentry *rt, void (* > time_t current_time; > > current_time = getuptime(); > - rt->rt_expire = current_time + queue->rtq_timeout; > > + mtx_enter(_mtx); > + rt->rt_expire = current_time + queue->rtq_timeout; > /* >* If there's already a timer with this action, destroy it before >* we add a new one. > @@ -1481,27 +1502,31
Re: router timer mutex
On 20.4.2022. 20:12, Alexander Bluhm wrote: > Hi, > > mvs@ reminded me of a crash I have seen in December. Route timers > are not MP safe, but I think this can be fixed with a mutex. The > idea is to protect the global lists with a mutex and move the rttimer > into a temporary list. Then the callback and pool put can be called > later without mutex. > > It survived a full regress with witness. > > Hrvoje: Can you put this on your test machine together with parallel > IP forwarding? > > ok? No problem, I'm running this and parallel forwarding diff in lab and production.
router timer mutex
Hi, mvs@ reminded me of a crash I have seen in December. Route timers are not MP safe, but I think this can be fixed with a mutex. The idea is to protect the global lists with a mutex and move the rttimer into a temporary list. Then the callback and pool put can be called later without mutex. It survived a full regress with witness. Hrvoje: Can you put this on your test machine together with parallel IP forwarding? ok? bluhm Index: net/route.c === RCS file: /cvs/src/sys/net/route.c,v retrieving revision 1.406 diff -u -p -r1.406 route.c --- net/route.c 20 Apr 2022 17:58:22 - 1.406 +++ net/route.c 20 Apr 2022 18:00:39 - @@ -1361,7 +1361,8 @@ rt_ifa_purge_walker(struct rtentry *rt, * for multiple queues for efficiency's sake... */ -LIST_HEAD(, rttimer_queue) rttimer_queue_head; +struct mutex rttimer_mtx; +LIST_HEAD(, rttimer_queue) rttimer_queue_head; /* [t] */ #define RTTIMER_CALLOUT(r) { \ if (r->rtt_func != NULL) { \ @@ -1393,6 +1394,7 @@ rt_timer_init(void) pool_init(_queue_pool, sizeof(struct rttimer_queue), 0, IPL_MPFLOOR, 0, "rttmrq", NULL); + mtx_init(_mtx, IPL_MPFLOOR); LIST_INIT(_queue_head); timeout_set_proc(_timer_timeout, rt_timer_timer, _timer_timeout); timeout_add_sec(_timer_timeout, 1); @@ -1408,7 +1410,10 @@ rt_timer_queue_create(int timeout) rtq->rtq_timeout = timeout; rtq->rtq_count = 0; TAILQ_INIT(>rtq_head); + + mtx_enter(_mtx); LIST_INSERT_HEAD(_queue_head, rtq, rtq_link); + mtx_leave(_mtx); return (rtq); } @@ -1416,28 +1421,36 @@ rt_timer_queue_create(int timeout) void rt_timer_queue_change(struct rttimer_queue *rtq, int timeout) { + mtx_enter(_mtx); rtq->rtq_timeout = timeout; + mtx_leave(_mtx); } void rt_timer_queue_destroy(struct rttimer_queue *rtq) { - struct rttimer *r; + struct rttimer *r; + TAILQ_HEAD(, rttimer)rttlist; NET_ASSERT_LOCKED(); + TAILQ_INIT(); + mtx_enter(_mtx); while ((r = TAILQ_FIRST(>rtq_head)) != NULL) { LIST_REMOVE(r, rtt_link); TAILQ_REMOVE(>rtq_head, r, rtt_next); + TAILQ_INSERT_TAIL(, r, rtt_next); + KASSERT(rtq->rtq_count > 0); + rtq->rtq_count--; + } + LIST_REMOVE(rtq, rtq_link); + mtx_leave(_mtx); + + while ((r = TAILQ_FIRST()) != NULL) { + TAILQ_REMOVE(, r, rtt_next); RTTIMER_CALLOUT(r); pool_put(_pool, r); - if (rtq->rtq_count > 0) - rtq->rtq_count--; - else - printf("rt_timer_queue_destroy: rtq_count reached 0\n"); } - - LIST_REMOVE(rtq, rtq_link); pool_put(_queue_pool, rtq); } @@ -1450,15 +1463,22 @@ rt_timer_queue_count(struct rttimer_queu void rt_timer_remove_all(struct rtentry *rt) { - struct rttimer *r; + struct rttimer *r; + TAILQ_HEAD(, rttimer)rttlist; + TAILQ_INIT(); + mtx_enter(_mtx); while ((r = LIST_FIRST(>rt_timer)) != NULL) { LIST_REMOVE(r, rtt_link); TAILQ_REMOVE(>rtt_queue->rtq_head, r, rtt_next); - if (r->rtt_queue->rtq_count > 0) - r->rtt_queue->rtq_count--; - else - printf("rt_timer_remove_all: rtq_count reached 0\n"); + TAILQ_INSERT_TAIL(, r, rtt_next); + KASSERT(r->rtt_queue->rtq_count > 0); + r->rtt_queue->rtq_count--; + } + mtx_leave(_mtx); + + while ((r = TAILQ_FIRST()) != NULL) { + TAILQ_REMOVE(, r, rtt_next); pool_put(_pool, r); } } @@ -1471,8 +1491,9 @@ rt_timer_add(struct rtentry *rt, void (* time_t current_time; current_time = getuptime(); - rt->rt_expire = current_time + queue->rtq_timeout; + mtx_enter(_mtx); + rt->rt_expire = current_time + queue->rtq_timeout; /* * If there's already a timer with this action, destroy it before * we add a new one. @@ -1481,27 +1502,31 @@ rt_timer_add(struct rtentry *rt, void (* if (r->rtt_func == func) { LIST_REMOVE(r, rtt_link); TAILQ_REMOVE(>rtt_queue->rtq_head, r, rtt_next); - if (r->rtt_queue->rtq_count > 0) - r->rtt_queue->rtq_count--; - else - printf("rt_timer_add: rtq_count reached 0\n"); - pool_put(_pool, r); + KASSERT(r->rtt_queue->rtq_count > 0); + r->rtt_queue->rtq_count--;