Mercurial > illumos > illumos-gate
changeset 9979:006c3455a081
6799660 panic, NULL pointer dereference, ip:ill_capability_ack_thr
6807899 system hang when running dladm delete-vnic
6816455 Panic : assertion failed: (sqp->sq_state & (SQS_DEFAULT|SQS_ILL_BOUND)) == SQS_DEFAULT
author | Thirumalai Srinivasan <Thirumalai.Srinivasan@Sun.COM> |
---|---|
date | Fri, 26 Jun 2009 12:06:35 -0700 |
parents | ce23a6a98c42 |
children | 13d7f3eec672 |
files | usr/src/uts/common/inet/ip/ip.c usr/src/uts/common/inet/ip/ip_if.c usr/src/uts/common/inet/ip/ip_squeue.c usr/src/uts/common/inet/ip_stack.h usr/src/uts/common/inet/squeue.c |
diffstat | 5 files changed, 60 insertions(+), 18 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/uts/common/inet/ip/ip.c Fri Jun 26 12:35:29 2009 -0500 +++ b/usr/src/uts/common/inet/ip/ip.c Fri Jun 26 12:06:35 2009 -0700 @@ -5823,7 +5823,6 @@ mutex_destroy(&ipst->ips_capab_taskq_lock); cv_destroy(&ipst->ips_capab_taskq_cv); - list_destroy(&ipst->ips_capab_taskq_list); mutex_enter(&ipst->ips_mrt_lock); while (!(ipst->ips_mrt_flags & IP_MRT_DONE)) @@ -6118,8 +6117,6 @@ ill_taskq_dispatch, ipst, 0, &p0, TS_RUN, minclsyspri); mutex_init(&ipst->ips_capab_taskq_lock, NULL, MUTEX_DEFAULT, NULL); cv_init(&ipst->ips_capab_taskq_cv, NULL, CV_DEFAULT, NULL); - list_create(&ipst->ips_capab_taskq_list, sizeof (mblk_t), - offsetof(mblk_t, b_next)); /* * Create the mcast_restart_timers_thread() worker thread.
--- a/usr/src/uts/common/inet/ip/ip_if.c Fri Jun 26 12:35:29 2009 -0500 +++ b/usr/src/uts/common/inet/ip/ip_if.c Fri Jun 26 12:06:35 2009 -0700 @@ -3229,14 +3229,18 @@ mutex_enter(&ipst->ips_capab_taskq_lock); for (;;) { - mp = list_head(&ipst->ips_capab_taskq_list); + mp = ipst->ips_capab_taskq_head; while (mp != NULL) { - list_remove(&ipst->ips_capab_taskq_list, mp); + ipst->ips_capab_taskq_head = mp->b_next; + if (ipst->ips_capab_taskq_head == NULL) + ipst->ips_capab_taskq_tail = NULL; mutex_exit(&ipst->ips_capab_taskq_lock); + mp->b_next = NULL; + VERIFY(taskq_dispatch(system_taskq, ill_capability_ack_thr, mp, TQ_SLEEP) != 0); mutex_enter(&ipst->ips_capab_taskq_lock); - mp = list_head(&ipst->ips_capab_taskq_list); + mp = ipst->ips_capab_taskq_head; } if (ipst->ips_capab_taskq_quit) @@ -3245,7 +3249,8 @@ cv_wait(&ipst->ips_capab_taskq_cv, &ipst->ips_capab_taskq_lock); CALLB_CPR_SAFE_END(&cprinfo, &ipst->ips_capab_taskq_lock); } - VERIFY(list_head(&ipst->ips_capab_taskq_list) == NULL); + VERIFY(ipst->ips_capab_taskq_head == NULL); + VERIFY(ipst->ips_capab_taskq_tail == NULL); CALLB_CPR_EXIT(&cprinfo); thread_exit(); } @@ -3264,6 +3269,8 @@ boolean_t reneg; ill = (ill_t *)mp->b_prev; + mp->b_prev = NULL; + VERIFY(ipsq_enter(ill, B_FALSE, CUR_OP) == B_TRUE); if (ill->ill_dlpi_capab_state == IDCS_RESET_SENT || @@ -3335,6 +3342,8 @@ ip_stack_t *ipst = ill->ill_ipst; mp->b_prev = (mblk_t *)ill; + ASSERT(mp->b_next == NULL); + if (taskq_dispatch(system_taskq, ill_capability_ack_thr, mp, TQ_NOSLEEP) != 0) return; @@ -3344,7 +3353,14 @@ * which will do the dispatch using TQ_SLEEP to guarantee success. */ mutex_enter(&ipst->ips_capab_taskq_lock); - list_insert_tail(&ipst->ips_capab_taskq_list, mp); + if (ipst->ips_capab_taskq_head == NULL) { + ASSERT(ipst->ips_capab_taskq_tail == NULL); + ipst->ips_capab_taskq_head = mp; + } else { + ipst->ips_capab_taskq_tail->b_next = mp; + } + ipst->ips_capab_taskq_tail = mp; + cv_signal(&ipst->ips_capab_taskq_cv); mutex_exit(&ipst->ips_capab_taskq_lock); }
--- a/usr/src/uts/common/inet/ip/ip_squeue.c Fri Jun 26 12:35:29 2009 -0500 +++ b/usr/src/uts/common/inet/ip/ip_squeue.c Fri Jun 26 12:06:35 2009 -0700 @@ -203,7 +203,7 @@ * default squeue, in order to support fanout of conns across * CPUs. Try to find a former default squeue that matches this * cpu id on the unbound squeue set. If no such squeue is found, - * find some non-default TCP squeue and steal it. If still no such + * find some non-default TCP squeue that is free. If still no such * candidate is found, create a new squeue. */ @@ -214,17 +214,24 @@ while (*lastsqp) { if ((*lastsqp)->sq_bind == id && (*lastsqp)->sq_state & SQS_DEFAULT) { + /* + * Exact match. Former default squeue of cpu 'id' + */ + ASSERT(!((*lastsqp)->sq_state & SQS_ILL_BOUND)); defaultq_lastp = lastsqp; break; } if (defaultq_lastp == NULL && - !((*lastsqp)->sq_state & SQS_DEFAULT)) { + !((*lastsqp)->sq_state & (SQS_ILL_BOUND | SQS_DEFAULT))) { + /* + * A free non-default TCP squeue + */ defaultq_lastp = lastsqp; } lastsqp = &(*lastsqp)->sq_next; + } - } - if (defaultq_lastp) { + if (defaultq_lastp != NULL) { /* Remove from src set and set SQS_DEFAULT */ sq = *defaultq_lastp; *defaultq_lastp = sq->sq_next; @@ -262,7 +269,8 @@ mutex_enter(&sqset_lock); for (sq = sqs->sqs_head; sq != NULL; sq = sq->sq_next) { /* - * Select a non-default squeue + * Select a non-default TCP squeue that is free i.e. not + * bound to any ill. */ if (!(sq->sq_state & (SQS_DEFAULT | SQS_ILL_BOUND))) break; @@ -564,7 +572,7 @@ mutex_exit(&ill->ill_lock); while (!(sqp->sq_state & SQS_POLL_CLEANUP_DONE)) cv_wait(&sqp->sq_ctrlop_done_cv, &sqp->sq_lock); - sqp->sq_state &= ~(SQS_POLL_CLEANUP_DONE | SQS_ILL_BOUND); + sqp->sq_state &= ~SQS_POLL_CLEANUP_DONE; ASSERT(!(sqp->sq_state & (SQS_POLL_THR_CONTROL | SQS_WORKER_THR_CONTROL | SQS_POLL_QUIESCE_DONE | @@ -574,13 +582,25 @@ mutex_exit(&sqp->sq_lock); /* - * Logically free the squeue. It goes back to the set of unused - * squeues + * Move the squeue to sqset_global_list[0] which holds the set of + * squeues not bound to any cpu. Note that the squeue is still + * considered bound to an ill as long as SQS_ILL_BOUND is set. */ mutex_enter(&sqset_lock); ip_squeue_set_move(sqp, sqset_global_list[0]); mutex_exit(&sqset_lock); + /* + * CPU going offline can also trigger a move of the squeue to the + * unbound set sqset_global_list[0]. However the squeue won't be + * recycled for the next use as long as the SQS_ILL_BOUND flag + * is set. Hence we clear the SQS_ILL_BOUND flag only towards the + * end after the move. + */ + mutex_enter(&sqp->sq_lock); + sqp->sq_state &= ~SQS_ILL_BOUND; + mutex_exit(&sqp->sq_lock); + mutex_enter(&ill->ill_lock); rx_ring->rr_ring_state = RR_FREE; mutex_exit(&ill->ill_lock); @@ -702,7 +722,7 @@ /* Also move default squeue to unbound set */ sqp = sqs->sqs_default; - ASSERT(sqp); + ASSERT(sqp != NULL); ASSERT((sqp->sq_state & (SQS_DEFAULT|SQS_ILL_BOUND)) == SQS_DEFAULT); sqp->sq_next = unbound->sqs_head;
--- a/usr/src/uts/common/inet/ip_stack.h Fri Jun 26 12:35:29 2009 -0500 +++ b/usr/src/uts/common/inet/ip_stack.h Fri Jun 26 12:06:35 2009 -0700 @@ -188,7 +188,8 @@ /* Taskq dispatcher for capability operations */ kmutex_t ips_capab_taskq_lock; kcondvar_t ips_capab_taskq_cv; - list_t ips_capab_taskq_list; + mblk_t *ips_capab_taskq_head; + mblk_t *ips_capab_taskq_tail; kthread_t *ips_capab_taskq_thread; boolean_t ips_capab_taskq_quit;
--- a/usr/src/uts/common/inet/squeue.c Fri Jun 26 12:35:29 2009 -0500 +++ b/usr/src/uts/common/inet/squeue.c Fri Jun 26 12:06:35 2009 -0700 @@ -1055,6 +1055,14 @@ sqp->sq_state &= ~(SQS_PROC|SQS_GET_PKTS); /* LINTED: constant in conditional context */ SQS_POLLING_OFF(sqp, B_TRUE, sq_rx_ring); + + /* + * If there is a pending control operation + * wake up the worker, since it is currently + * not running. + */ + if (sqp->sq_state & SQS_WORKER_THR_CONTROL) + cv_signal(&sqp->sq_worker_cv); } else { /* * Worker thread is already running. We don't need