Improve the teardown of the SCTP stack.

Obtained from:	bz@
MFC after: 1 week
This commit is contained in:
Michael Tuexen 2016-02-16 19:36:25 +00:00
parent ae038fc336
commit 2b1c7de4d8
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=295668
5 changed files with 109 additions and 54 deletions

View File

@ -3248,6 +3248,7 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa,
} else {
struct sctp_asconf_iterator *asc;
struct sctp_laddr *wi;
int ret;
SCTP_MALLOC(asc, struct sctp_asconf_iterator *,
sizeof(struct sctp_asconf_iterator),
@ -3269,7 +3270,7 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa,
wi->action = type;
atomic_add_int(&ifa->refcount, 1);
LIST_INSERT_HEAD(&asc->list_of_work, wi, sctp_nxt_addr);
(void)sctp_initiate_iterator(sctp_asconf_iterator_ep,
ret = sctp_initiate_iterator(sctp_asconf_iterator_ep,
sctp_asconf_iterator_stcb,
sctp_asconf_iterator_ep_end,
SCTP_PCB_ANY_FLAGS,
@ -3277,6 +3278,12 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa,
SCTP_ASOC_ANY_STATE,
(void *)asc, 0,
sctp_asconf_iterator_end, inp, 0);
if (ret) {
SCTP_PRINTF("Failed to initiate iterator for addr_mgmt_ep_sa\n");
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EFAULT);
sctp_asconf_iterator_end(asc, 0);
return (EFAULT);
}
}
return (0);
} else {

View File

@ -293,6 +293,10 @@ sctp_addr_change(struct ifaddr *ifa, int cmd)
{
uint32_t ifa_flags = 0;
if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) {
return;
}
/*
* BSD only has one VRF, if this changes we will need to hook in the
* right things here to get the id to pass to the address managment

View File

@ -2781,8 +2781,45 @@ sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp,
SCTP_INP_WUNLOCK(old_inp);
}
/*
* insert an laddr entry with the given ifa for the desired list
*/
static int
sctp_insert_laddr(struct sctpladdr *list, struct sctp_ifa *ifa, uint32_t act)
{
struct sctp_laddr *laddr;
laddr = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_laddr), struct sctp_laddr);
if (laddr == NULL) {
/* out of memory? */
SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
return (EINVAL);
}
SCTP_INCR_LADDR_COUNT();
bzero(laddr, sizeof(*laddr));
(void)SCTP_GETTIME_TIMEVAL(&laddr->start_time);
laddr->ifa = ifa;
laddr->action = act;
atomic_add_int(&ifa->refcount, 1);
/* insert it */
LIST_INSERT_HEAD(list, laddr, sctp_nxt_addr);
return (0);
}
/*
* Remove an laddr entry from the local address list (on an assoc)
*/
static void
sctp_remove_laddr(struct sctp_laddr *laddr)
{
/* remove from the list */
LIST_REMOVE(laddr, sctp_nxt_addr);
sctp_free_ifa(laddr->ifa);
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_laddr), laddr);
SCTP_DECR_LADDR_COUNT();
}
/* sctp_ifap is used to bypass normal local address validation checks */
int
@ -5508,46 +5545,6 @@ sctp_add_local_addr_restricted(struct sctp_tcb *stcb, struct sctp_ifa *ifa)
return;
}
/*
* insert an laddr entry with the given ifa for the desired list
*/
int
sctp_insert_laddr(struct sctpladdr *list, struct sctp_ifa *ifa, uint32_t act)
{
struct sctp_laddr *laddr;
laddr = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_laddr), struct sctp_laddr);
if (laddr == NULL) {
/* out of memory? */
SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
return (EINVAL);
}
SCTP_INCR_LADDR_COUNT();
bzero(laddr, sizeof(*laddr));
(void)SCTP_GETTIME_TIMEVAL(&laddr->start_time);
laddr->ifa = ifa;
laddr->action = act;
atomic_add_int(&ifa->refcount, 1);
/* insert it */
LIST_INSERT_HEAD(list, laddr, sctp_nxt_addr);
return (0);
}
/*
* Remove an laddr entry from the local address list (on an assoc)
*/
void
sctp_remove_laddr(struct sctp_laddr *laddr)
{
/* remove from the list */
LIST_REMOVE(laddr, sctp_nxt_addr);
sctp_free_ifa(laddr->ifa);
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_laddr), laddr);
SCTP_DECR_LADDR_COUNT();
}
/*
* Remove a local address from the TCB local address restricted list
*/
@ -5918,12 +5915,33 @@ sctp_pcb_finish(void)
int i;
struct sctp_iterator *it, *nit;
if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) {
SCTP_PRINTF("%s: race condition on teardown.\n", __func__);
return;
}
SCTP_BASE_VAR(sctp_pcb_initialized) = 0;
/*
* In FreeBSD the iterator thread never exits but we do clean up.
* The only way FreeBSD reaches here is if we have VRF's but we
* still add the ifdef to make it compile on old versions.
*/
retry:
SCTP_IPI_ITERATOR_WQ_LOCK();
/*
* sctp_iterator_worker() might be working on an it entry without
* holding the lock. We won't find it on the list either and
* continue and free/destroy it. While holding the lock, spin, to
* avoid the race condition as sctp_iterator_worker() will have to
* wait to re-aquire the lock.
*/
if (sctp_it_ctl.iterator_running != 0 || sctp_it_ctl.cur_it != NULL) {
SCTP_IPI_ITERATOR_WQ_UNLOCK();
SCTP_PRINTF("%s: Iterator running while we held the lock. Retry. "
"cur_it=%p\n", __func__, sctp_it_ctl.cur_it);
DELAY(10);
goto retry;
}
TAILQ_FOREACH_SAFE(it, &sctp_it_ctl.iteratorhead, sctp_nxt_itr, nit) {
if (it->vn != curvnet) {
continue;
@ -5941,7 +5959,7 @@ sctp_pcb_finish(void)
sctp_it_ctl.iterator_flags |= SCTP_ITERATOR_STOP_CUR_IT;
}
SCTP_ITERATOR_UNLOCK();
SCTP_OS_TIMER_STOP(&SCTP_BASE_INFO(addr_wq_timer.timer));
SCTP_OS_TIMER_STOP_DRAIN(&SCTP_BASE_INFO(addr_wq_timer.timer));
SCTP_WQ_ADDR_LOCK();
LIST_FOREACH_SAFE(wi, &SCTP_BASE_INFO(addr_wq), sctp_nxt_addr, nwi) {
LIST_REMOVE(wi, sctp_nxt_addr);
@ -6008,6 +6026,14 @@ sctp_pcb_finish(void)
SCTP_WQ_ADDR_DESTROY();
/* Get rid of other stuff too. */
if (SCTP_BASE_INFO(sctp_asochash) != NULL)
SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_asochash), SCTP_BASE_INFO(hashasocmark));
if (SCTP_BASE_INFO(sctp_ephash) != NULL)
SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_ephash), SCTP_BASE_INFO(hashmark));
if (SCTP_BASE_INFO(sctp_tcpephash) != NULL)
SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_tcpephash), SCTP_BASE_INFO(hashtcpmark));
SCTP_ZONE_DESTROY(SCTP_BASE_INFO(ipi_zone_ep));
SCTP_ZONE_DESTROY(SCTP_BASE_INFO(ipi_zone_asoc));
SCTP_ZONE_DESTROY(SCTP_BASE_INFO(ipi_zone_laddr));
@ -6017,13 +6043,7 @@ sctp_pcb_finish(void)
SCTP_ZONE_DESTROY(SCTP_BASE_INFO(ipi_zone_strmoq));
SCTP_ZONE_DESTROY(SCTP_BASE_INFO(ipi_zone_asconf));
SCTP_ZONE_DESTROY(SCTP_BASE_INFO(ipi_zone_asconf_ack));
/* Get rid of other stuff to */
if (SCTP_BASE_INFO(sctp_asochash) != NULL)
SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_asochash), SCTP_BASE_INFO(hashasocmark));
if (SCTP_BASE_INFO(sctp_ephash) != NULL)
SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_ephash), SCTP_BASE_INFO(hashmark));
if (SCTP_BASE_INFO(sctp_tcpephash) != NULL)
SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_tcpephash), SCTP_BASE_INFO(hashtcpmark));
#if defined(__FreeBSD__) && defined(SMP) && defined(SCTP_USE_PERCPU_STAT)
SCTP_FREE(SCTP_BASE_STATS, SCTP_M_MCORE);
#endif
@ -6987,6 +7007,11 @@ sctp_initiate_iterator(inp_func inpf,
if (af == NULL) {
return (-1);
}
if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) {
SCTP_PRINTF("%s: abort on initialize being %d\n", __func__,
SCTP_BASE_VAR(sctp_pcb_initialized));
return (-1);
}
SCTP_MALLOC(it, struct sctp_iterator *, sizeof(struct sctp_iterator),
SCTP_M_ITER);
if (it == NULL) {
@ -7025,6 +7050,13 @@ sctp_initiate_iterator(inp_func inpf,
}
SCTP_IPI_ITERATOR_WQ_LOCK();
if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) {
SCTP_IPI_ITERATOR_WQ_UNLOCK();
SCTP_PRINTF("%s: rollback on initialize being %d it=%p\n", __func__,
SCTP_BASE_VAR(sctp_pcb_initialized), it);
SCTP_FREE(it, SCTP_M_ITER);
return (-1);
}
TAILQ_INSERT_TAIL(&sctp_it_ctl.iteratorhead, it, sctp_nxt_itr);
if (sctp_it_ctl.iterator_running == 0) {

View File

@ -598,10 +598,6 @@ void
void sctp_add_local_addr_ep(struct sctp_inpcb *, struct sctp_ifa *, uint32_t);
int sctp_insert_laddr(struct sctpladdr *, struct sctp_ifa *, uint32_t);
void sctp_remove_laddr(struct sctp_laddr *);
void sctp_del_local_addr_ep(struct sctp_inpcb *, struct sctp_ifa *);
int sctp_add_remote_addr(struct sctp_tcb *, struct sockaddr *, struct sctp_nets **, int, int);

View File

@ -1470,7 +1470,9 @@ sctp_handle_addr_wq(void)
if (asc->cnt == 0) {
SCTP_FREE(asc, SCTP_M_ASC_IT);
} else {
(void)sctp_initiate_iterator(sctp_asconf_iterator_ep,
int ret;
ret = sctp_initiate_iterator(sctp_asconf_iterator_ep,
sctp_asconf_iterator_stcb,
NULL, /* No ep end for boundall */
SCTP_PCB_FLAGS_BOUNDALL,
@ -1478,6 +1480,20 @@ sctp_handle_addr_wq(void)
SCTP_ASOC_ANY_STATE,
(void *)asc, 0,
sctp_asconf_iterator_end, NULL, 0);
if (ret) {
SCTP_PRINTF("Failed to initiate iterator for handle_addr_wq\n");
/* Freeing if we are stopping or put back on the addr_wq. */
if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) {
sctp_asconf_iterator_end(asc, 0);
} else {
SCTP_WQ_ADDR_LOCK();
LIST_FOREACH(wi, &asc->list_of_work, sctp_nxt_addr) {
LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr);
}
SCTP_WQ_ADDR_UNLOCK();
SCTP_FREE(asc, SCTP_M_ASC_IT);
}
}
}
}