diff options
author | yz147064 <none@none> | 2006-12-13 10:43:15 -0800 |
---|---|---|
committer | yz147064 <none@none> | 2006-12-13 10:43:15 -0800 |
commit | e71762350b6d2f119e1206a5e15f15aafa47fc95 (patch) | |
tree | 072aa0e547fc9edf73bca1b4e273a2e182e10de4 /usr/src | |
parent | c00b5a30ba544acdf709e498777a211748439f24 (diff) | |
download | illumos-gate-e71762350b6d2f119e1206a5e15f15aafa47fc95.tar.gz |
6400119 ifconfig unplumb hangs in certain scenarios
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/uts/common/inet/ip.h | 1 | ||||
-rw-r--r-- | usr/src/uts/common/inet/ip/ip.c | 28 | ||||
-rw-r--r-- | usr/src/uts/common/inet/ip/ip_if.c | 37 | ||||
-rw-r--r-- | usr/src/uts/common/inet/ip_if.h | 1 |
4 files changed, 66 insertions, 1 deletions
diff --git a/usr/src/uts/common/inet/ip.h b/usr/src/uts/common/inet/ip.h index 9b3fcf0b00..228a9d7ff6 100644 --- a/usr/src/uts/common/inet/ip.h +++ b/usr/src/uts/common/inet/ip.h @@ -2019,6 +2019,7 @@ extern void ill_delete_glist(ill_t *); * ill_resolver_mp ipsq only when ill is up * ill_down_mp ipsq ipsq * ill_dlpi_deferred ipsq ipsq + * ill_dlpi_pending ipsq and ill_lock ipsq or ill_lock * ill_phys_addr_mp ipsq ipsq * ill_phys_addr ipsq up ill * ill_ick ipsq + down ill only when ill is up diff --git a/usr/src/uts/common/inet/ip/ip.c b/usr/src/uts/common/inet/ip/ip.c index 19fd03db15..94efa0083f 100644 --- a/usr/src/uts/common/inet/ip/ip.c +++ b/usr/src/uts/common/inet/ip/ip.c @@ -251,6 +251,7 @@ major_t SCTP6_MAJ; int ip_poll_normal_ms = 100; int ip_poll_normal_ticks = 0; +int ip_modclose_ackwait_ms = 3000; /* * Structure to represent a linked list of msgblks. Used by ip_snmp_ functions. @@ -5368,6 +5369,25 @@ ip_modclose(ill_t *ill) ipif_t *ipif; queue_t *q = ill->ill_rq; hook_nic_event_t *info; + clock_t timeout; + + /* + * Wait for the ACKs of all deferred control messages to be processed. + * In particular, we wait for a potential capability reset initiated + * in ip_sioctl_plink() to complete before proceeding. + * + * Note: we wait for at most ip_modclose_ackwait_ms (by default 3000 ms) + * in case the driver never replies. + */ + timeout = lbolt + MSEC_TO_TICK(ip_modclose_ackwait_ms); + mutex_enter(&ill->ill_lock); + while (ill->ill_dlpi_pending != DL_PRIM_INVAL) { + if (cv_timedwait(&ill->ill_cv, &ill->ill_lock, timeout) < 0) { + /* Timeout */ + break; + } + } + mutex_exit(&ill->ill_lock); /* * Forcibly enter the ipsq after some delay. This is to take @@ -5408,6 +5428,14 @@ ip_modclose(ill_t *ill) mutex_exit(&ill->ill_lock); /* + * Send all the deferred control messages downstream which came in + * during the small window right before ipsq_enter(). We do this + * without waiting for the ACKs because all the ACKs for M_PROTO + * messages are ignored in ip_rput() when ILL_CONDEMNED is set. + */ + ill_send_all_deferred_mp(ill); + + /* * Shut down fragmentation reassembly. * ill_frag_timer won't start a timer again. * Now cancel any existing timer diff --git a/usr/src/uts/common/inet/ip/ip_if.c b/usr/src/uts/common/inet/ip/ip_if.c index 9b03e364cd..cd40a7e91d 100644 --- a/usr/src/uts/common/inet/ip/ip_if.c +++ b/usr/src/uts/common/inet/ip/ip_if.c @@ -787,6 +787,28 @@ ipif_non_duplicate(ipif_t *ipif) } /* + * Send all deferred messages without waiting for their ACKs. + */ +void +ill_send_all_deferred_mp(ill_t *ill) +{ + mblk_t *mp, *next; + + /* + * Clear ill_dlpi_pending so that the message is not queued in + * ill_dlpi_send(). + */ + ill->ill_dlpi_pending = DL_PRIM_INVAL; + + for (mp = ill->ill_dlpi_deferred; mp != NULL; mp = next) { + next = mp->b_next; + mp->b_next = NULL; + ill_dlpi_send(ill, mp); + } + ill->ill_dlpi_deferred = NULL; +} + +/* * ill_delete_tail is called from ip_modclose after all references * to the closing ill are gone. The wait is done in ip_modclose */ @@ -18129,7 +18151,17 @@ ill_dlpi_dispatch(ill_t *ill, mblk_t *mp) break; } - ill->ill_dlpi_pending = prim; + /* + * Except for the ACKs for the M_PCPROTO messages, all other ACKs + * are dropped by ip_rput() if ILL_CONDEMNED is set. Therefore + * we only wait for the ACK of the DL_UNBIND_REQ. + */ + mutex_enter(&ill->ill_lock); + if (!(ill->ill_state_flags & ILL_CONDEMNED) || + (prim == DL_UNBIND_REQ)) { + ill->ill_dlpi_pending = prim; + } + mutex_exit(&ill->ill_lock); /* * Some drivers send M_FLUSH up to IP as part of unbind @@ -18213,7 +18245,10 @@ ill_dlpi_done(ill_t *ill, t_uscalar_t prim) dlpi_prim_str(ill->ill_dlpi_pending), ill->ill_dlpi_pending)); if ((mp = ill->ill_dlpi_deferred) == NULL) { + mutex_enter(&ill->ill_lock); ill->ill_dlpi_pending = DL_PRIM_INVAL; + cv_signal(&ill->ill_cv); + mutex_exit(&ill->ill_lock); return; } diff --git a/usr/src/uts/common/inet/ip_if.h b/usr/src/uts/common/inet/ip_if.h index e32ba29a8e..8b50aaed40 100644 --- a/usr/src/uts/common/inet/ip_if.h +++ b/usr/src/uts/common/inet/ip_if.h @@ -168,6 +168,7 @@ extern uint_t ill_get_next_ifindex(uint_t, boolean_t); extern uint_t ill_get_ifindex_by_name(char *); extern ill_t *ill_get_first(boolean_t isv6); extern void ill_ipif_cache_delete(ire_t *, char *); +extern void ill_send_all_deferred_mp(ill_t *); extern void ill_delete(ill_t *); extern void ill_delete_tail(ill_t *); extern int ill_dl_phys(ill_t *, ipif_t *, mblk_t *, queue_t *); |