summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authoryz147064 <none@none>2006-12-13 10:43:15 -0800
committeryz147064 <none@none>2006-12-13 10:43:15 -0800
commite71762350b6d2f119e1206a5e15f15aafa47fc95 (patch)
tree072aa0e547fc9edf73bca1b4e273a2e182e10de4 /usr/src
parentc00b5a30ba544acdf709e498777a211748439f24 (diff)
downloadillumos-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.h1
-rw-r--r--usr/src/uts/common/inet/ip/ip.c28
-rw-r--r--usr/src/uts/common/inet/ip/ip_if.c37
-rw-r--r--usr/src/uts/common/inet/ip_if.h1
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 *);