Improve the locking of address lists by adding some asserts and
rearranging the addition of address such that the lock is not given up during checking and adding. MFC after: 1 week
This commit is contained in:
parent
f3856e6881
commit
7f0ad2274b
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=363275
@ -177,6 +177,13 @@ __FBSDID("$FreeBSD$");
|
|||||||
rw_wunlock(&SCTP_BASE_INFO(ipi_addr_mtx)); \
|
rw_wunlock(&SCTP_BASE_INFO(ipi_addr_mtx)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#define SCTP_IPI_ADDR_LOCK_ASSERT() do { \
|
||||||
|
rw_assert(&SCTP_BASE_INFO(ipi_addr_mtx), RA_LOCKED); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define SCTP_IPI_ADDR_WLOCK_ASSERT() do { \
|
||||||
|
rw_assert(&SCTP_BASE_INFO(ipi_addr_mtx), RA_WLOCKED); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define SCTP_IPI_ITERATOR_WQ_INIT() do { \
|
#define SCTP_IPI_ITERATOR_WQ_INIT() do { \
|
||||||
mtx_init(&sctp_it_ctl.ipi_iterator_wq_mtx, "sctp-it-wq", \
|
mtx_init(&sctp_it_ctl.ipi_iterator_wq_mtx, "sctp-it-wq", \
|
||||||
|
@ -200,6 +200,7 @@ sctp_find_ifn(void *ifn, uint32_t ifn_index)
|
|||||||
* We assume the lock is held for the addresses if that's wrong
|
* We assume the lock is held for the addresses if that's wrong
|
||||||
* problems could occur :-)
|
* problems could occur :-)
|
||||||
*/
|
*/
|
||||||
|
SCTP_IPI_ADDR_LOCK_ASSERT();
|
||||||
hash_ifn_head = &SCTP_BASE_INFO(vrf_ifn_hash)[(ifn_index & SCTP_BASE_INFO(vrf_ifn_hashmark))];
|
hash_ifn_head = &SCTP_BASE_INFO(vrf_ifn_hash)[(ifn_index & SCTP_BASE_INFO(vrf_ifn_hashmark))];
|
||||||
LIST_FOREACH(sctp_ifnp, hash_ifn_head, next_bucket) {
|
LIST_FOREACH(sctp_ifnp, hash_ifn_head, next_bucket) {
|
||||||
if (sctp_ifnp->ifn_index == ifn_index) {
|
if (sctp_ifnp->ifn_index == ifn_index) {
|
||||||
@ -295,12 +296,16 @@ sctp_delete_ifn(struct sctp_ifn *sctp_ifnp, int hold_addr_lock)
|
|||||||
/* Not in the list.. sorry */
|
/* Not in the list.. sorry */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (hold_addr_lock == 0)
|
if (hold_addr_lock == 0) {
|
||||||
SCTP_IPI_ADDR_WLOCK();
|
SCTP_IPI_ADDR_WLOCK();
|
||||||
|
} else {
|
||||||
|
SCTP_IPI_ADDR_WLOCK_ASSERT();
|
||||||
|
}
|
||||||
LIST_REMOVE(sctp_ifnp, next_bucket);
|
LIST_REMOVE(sctp_ifnp, next_bucket);
|
||||||
LIST_REMOVE(sctp_ifnp, next_ifn);
|
LIST_REMOVE(sctp_ifnp, next_ifn);
|
||||||
if (hold_addr_lock == 0)
|
if (hold_addr_lock == 0) {
|
||||||
SCTP_IPI_ADDR_WUNLOCK();
|
SCTP_IPI_ADDR_WUNLOCK();
|
||||||
|
}
|
||||||
/* Take away the reference, and possibly free it */
|
/* Take away the reference, and possibly free it */
|
||||||
sctp_free_ifn(sctp_ifnp);
|
sctp_free_ifn(sctp_ifnp);
|
||||||
}
|
}
|
||||||
@ -486,8 +491,8 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
|
|||||||
int dynamic_add)
|
int dynamic_add)
|
||||||
{
|
{
|
||||||
struct sctp_vrf *vrf;
|
struct sctp_vrf *vrf;
|
||||||
struct sctp_ifn *sctp_ifnp = NULL;
|
struct sctp_ifn *sctp_ifnp, *new_sctp_ifnp;
|
||||||
struct sctp_ifa *sctp_ifap = NULL;
|
struct sctp_ifa *sctp_ifap, *new_sctp_ifap;
|
||||||
struct sctp_ifalist *hash_addr_head;
|
struct sctp_ifalist *hash_addr_head;
|
||||||
struct sctp_ifnlist *hash_ifn_head;
|
struct sctp_ifnlist *hash_ifn_head;
|
||||||
uint32_t hash_of_addr;
|
uint32_t hash_of_addr;
|
||||||
@ -497,6 +502,23 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
|
|||||||
SCTPDBG(SCTP_DEBUG_PCB4, "vrf_id 0x%x: adding address: ", vrf_id);
|
SCTPDBG(SCTP_DEBUG_PCB4, "vrf_id 0x%x: adding address: ", vrf_id);
|
||||||
SCTPDBG_ADDR(SCTP_DEBUG_PCB4, addr);
|
SCTPDBG_ADDR(SCTP_DEBUG_PCB4, addr);
|
||||||
#endif
|
#endif
|
||||||
|
SCTP_MALLOC(new_sctp_ifnp, struct sctp_ifn *,
|
||||||
|
sizeof(struct sctp_ifn), SCTP_M_IFN);
|
||||||
|
if (new_sctp_ifnp == NULL) {
|
||||||
|
#ifdef INVARIANTS
|
||||||
|
panic("No memory for IFN");
|
||||||
|
#endif
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
SCTP_MALLOC(new_sctp_ifap, struct sctp_ifa *, sizeof(struct sctp_ifa), SCTP_M_IFA);
|
||||||
|
if (new_sctp_ifap == NULL) {
|
||||||
|
#ifdef INVARIANTS
|
||||||
|
panic("No memory for IFA");
|
||||||
|
#endif
|
||||||
|
SCTP_FREE(new_sctp_ifnp, SCTP_M_IFN);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
SCTP_IPI_ADDR_WLOCK();
|
SCTP_IPI_ADDR_WLOCK();
|
||||||
sctp_ifnp = sctp_find_ifn(ifn, ifn_index);
|
sctp_ifnp = sctp_find_ifn(ifn, ifn_index);
|
||||||
if (sctp_ifnp) {
|
if (sctp_ifnp) {
|
||||||
@ -507,6 +529,8 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
|
|||||||
vrf = sctp_allocate_vrf(vrf_id);
|
vrf = sctp_allocate_vrf(vrf_id);
|
||||||
if (vrf == NULL) {
|
if (vrf == NULL) {
|
||||||
SCTP_IPI_ADDR_WUNLOCK();
|
SCTP_IPI_ADDR_WUNLOCK();
|
||||||
|
SCTP_FREE(new_sctp_ifnp, SCTP_M_IFN);
|
||||||
|
SCTP_FREE(new_sctp_ifap, SCTP_M_IFA);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -516,15 +540,8 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
|
|||||||
* build one and add it, can't hold lock until after malloc
|
* build one and add it, can't hold lock until after malloc
|
||||||
* done though.
|
* done though.
|
||||||
*/
|
*/
|
||||||
SCTP_IPI_ADDR_WUNLOCK();
|
sctp_ifnp = new_sctp_ifnp;
|
||||||
SCTP_MALLOC(sctp_ifnp, struct sctp_ifn *,
|
new_sctp_ifnp = NULL;
|
||||||
sizeof(struct sctp_ifn), SCTP_M_IFN);
|
|
||||||
if (sctp_ifnp == NULL) {
|
|
||||||
#ifdef INVARIANTS
|
|
||||||
panic("No memory for IFN");
|
|
||||||
#endif
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
memset(sctp_ifnp, 0, sizeof(struct sctp_ifn));
|
memset(sctp_ifnp, 0, sizeof(struct sctp_ifn));
|
||||||
sctp_ifnp->ifn_index = ifn_index;
|
sctp_ifnp->ifn_index = ifn_index;
|
||||||
sctp_ifnp->ifn_p = ifn;
|
sctp_ifnp->ifn_p = ifn;
|
||||||
@ -540,7 +557,6 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
|
|||||||
}
|
}
|
||||||
hash_ifn_head = &SCTP_BASE_INFO(vrf_ifn_hash)[(ifn_index & SCTP_BASE_INFO(vrf_ifn_hashmark))];
|
hash_ifn_head = &SCTP_BASE_INFO(vrf_ifn_hash)[(ifn_index & SCTP_BASE_INFO(vrf_ifn_hashmark))];
|
||||||
LIST_INIT(&sctp_ifnp->ifalist);
|
LIST_INIT(&sctp_ifnp->ifalist);
|
||||||
SCTP_IPI_ADDR_WLOCK();
|
|
||||||
LIST_INSERT_HEAD(hash_ifn_head, sctp_ifnp, next_bucket);
|
LIST_INSERT_HEAD(hash_ifn_head, sctp_ifnp, next_bucket);
|
||||||
LIST_INSERT_HEAD(&vrf->ifnlist, sctp_ifnp, next_ifn);
|
LIST_INSERT_HEAD(&vrf->ifnlist, sctp_ifnp, next_ifn);
|
||||||
atomic_add_int(&SCTP_BASE_INFO(ipi_count_ifns), 1);
|
atomic_add_int(&SCTP_BASE_INFO(ipi_count_ifns), 1);
|
||||||
@ -567,6 +583,10 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
|
|||||||
}
|
}
|
||||||
exit_stage_left:
|
exit_stage_left:
|
||||||
SCTP_IPI_ADDR_WUNLOCK();
|
SCTP_IPI_ADDR_WUNLOCK();
|
||||||
|
if (new_sctp_ifnp != NULL) {
|
||||||
|
SCTP_FREE(new_sctp_ifnp, SCTP_M_IFN);
|
||||||
|
}
|
||||||
|
SCTP_FREE(new_sctp_ifap, SCTP_M_IFA);
|
||||||
return (sctp_ifap);
|
return (sctp_ifap);
|
||||||
} else {
|
} else {
|
||||||
if (sctp_ifap->ifn_p) {
|
if (sctp_ifap->ifn_p) {
|
||||||
@ -593,14 +613,7 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
|
|||||||
goto exit_stage_left;
|
goto exit_stage_left;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SCTP_IPI_ADDR_WUNLOCK();
|
sctp_ifap = new_sctp_ifap;
|
||||||
SCTP_MALLOC(sctp_ifap, struct sctp_ifa *, sizeof(struct sctp_ifa), SCTP_M_IFA);
|
|
||||||
if (sctp_ifap == NULL) {
|
|
||||||
#ifdef INVARIANTS
|
|
||||||
panic("No memory for IFA");
|
|
||||||
#endif
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
memset(sctp_ifap, 0, sizeof(struct sctp_ifa));
|
memset(sctp_ifap, 0, sizeof(struct sctp_ifa));
|
||||||
sctp_ifap->ifn_p = sctp_ifnp;
|
sctp_ifap->ifn_p = sctp_ifnp;
|
||||||
atomic_add_int(&sctp_ifnp->refcount, 1);
|
atomic_add_int(&sctp_ifnp->refcount, 1);
|
||||||
@ -660,7 +673,6 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
|
|||||||
(sctp_ifap->src_is_loop == 0)) {
|
(sctp_ifap->src_is_loop == 0)) {
|
||||||
sctp_ifap->src_is_glob = 1;
|
sctp_ifap->src_is_glob = 1;
|
||||||
}
|
}
|
||||||
SCTP_IPI_ADDR_WLOCK();
|
|
||||||
hash_addr_head = &vrf->vrf_addr_hash[(hash_of_addr & vrf->vrf_addr_hashmark)];
|
hash_addr_head = &vrf->vrf_addr_hash[(hash_of_addr & vrf->vrf_addr_hashmark)];
|
||||||
LIST_INSERT_HEAD(hash_addr_head, sctp_ifap, next_bucket);
|
LIST_INSERT_HEAD(hash_addr_head, sctp_ifap, next_bucket);
|
||||||
sctp_ifap->refcount = 1;
|
sctp_ifap->refcount = 1;
|
||||||
@ -672,6 +684,10 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
|
|||||||
sctp_ifnp->registered_af = new_ifn_af;
|
sctp_ifnp->registered_af = new_ifn_af;
|
||||||
}
|
}
|
||||||
SCTP_IPI_ADDR_WUNLOCK();
|
SCTP_IPI_ADDR_WUNLOCK();
|
||||||
|
if (new_sctp_ifnp != NULL) {
|
||||||
|
SCTP_FREE(new_sctp_ifnp, SCTP_M_IFN);
|
||||||
|
}
|
||||||
|
|
||||||
if (dynamic_add) {
|
if (dynamic_add) {
|
||||||
/*
|
/*
|
||||||
* Bump up the refcount so that when the timer completes it
|
* Bump up the refcount so that when the timer completes it
|
||||||
@ -5906,6 +5922,7 @@ sctp_pcb_finish(void)
|
|||||||
* free the vrf/ifn/ifa lists and hashes (be sure address monitor is
|
* free the vrf/ifn/ifa lists and hashes (be sure address monitor is
|
||||||
* destroyed first).
|
* destroyed first).
|
||||||
*/
|
*/
|
||||||
|
SCTP_IPI_ADDR_WLOCK();
|
||||||
vrf_bucket = &SCTP_BASE_INFO(sctp_vrfhash)[(SCTP_DEFAULT_VRFID & SCTP_BASE_INFO(hashvrfmark))];
|
vrf_bucket = &SCTP_BASE_INFO(sctp_vrfhash)[(SCTP_DEFAULT_VRFID & SCTP_BASE_INFO(hashvrfmark))];
|
||||||
LIST_FOREACH_SAFE(vrf, vrf_bucket, next_vrf, nvrf) {
|
LIST_FOREACH_SAFE(vrf, vrf_bucket, next_vrf, nvrf) {
|
||||||
LIST_FOREACH_SAFE(ifn, &vrf->ifnlist, next_ifn, nifn) {
|
LIST_FOREACH_SAFE(ifn, &vrf->ifnlist, next_ifn, nifn) {
|
||||||
@ -5925,6 +5942,7 @@ sctp_pcb_finish(void)
|
|||||||
LIST_REMOVE(vrf, next_vrf);
|
LIST_REMOVE(vrf, next_vrf);
|
||||||
SCTP_FREE(vrf, SCTP_M_VRF);
|
SCTP_FREE(vrf, SCTP_M_VRF);
|
||||||
}
|
}
|
||||||
|
SCTP_IPI_ADDR_WUNLOCK();
|
||||||
/* free the vrf hashes */
|
/* free the vrf hashes */
|
||||||
SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_vrfhash), SCTP_BASE_INFO(hashvrfmark));
|
SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_vrfhash), SCTP_BASE_INFO(hashvrfmark));
|
||||||
SCTP_HASH_FREE(SCTP_BASE_INFO(vrf_ifn_hash), SCTP_BASE_INFO(vrf_ifn_hashmark));
|
SCTP_HASH_FREE(SCTP_BASE_INFO(vrf_ifn_hash), SCTP_BASE_INFO(vrf_ifn_hashmark));
|
||||||
|
@ -1004,9 +1004,6 @@ sctp_fill_user_address(struct sockaddr *dst, struct sockaddr *src)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* NOTE: assumes addr lock is held
|
|
||||||
*/
|
|
||||||
static size_t
|
static size_t
|
||||||
sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
|
sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
|
||||||
struct sctp_tcb *stcb,
|
struct sctp_tcb *stcb,
|
||||||
@ -1026,6 +1023,7 @@ sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
|
|||||||
#endif
|
#endif
|
||||||
struct sctp_vrf *vrf;
|
struct sctp_vrf *vrf;
|
||||||
|
|
||||||
|
SCTP_IPI_ADDR_LOCK_ASSERT();
|
||||||
actual = 0;
|
actual = 0;
|
||||||
if (limit == 0)
|
if (limit == 0)
|
||||||
return (actual);
|
return (actual);
|
||||||
@ -1258,9 +1256,6 @@ sctp_fill_up_addresses(struct sctp_inpcb *inp,
|
|||||||
return (size);
|
return (size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* NOTE: assumes addr lock is held
|
|
||||||
*/
|
|
||||||
static int
|
static int
|
||||||
sctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id)
|
sctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id)
|
||||||
{
|
{
|
||||||
@ -1274,6 +1269,7 @@ sctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id)
|
|||||||
* bound-all case a TCB may NOT include the loopback or other
|
* bound-all case a TCB may NOT include the loopback or other
|
||||||
* addresses as well.
|
* addresses as well.
|
||||||
*/
|
*/
|
||||||
|
SCTP_IPI_ADDR_LOCK_ASSERT();
|
||||||
vrf = sctp_find_vrf(vrf_id);
|
vrf = sctp_find_vrf(vrf_id);
|
||||||
if (vrf == NULL) {
|
if (vrf == NULL) {
|
||||||
return (0);
|
return (0);
|
||||||
|
@ -5296,8 +5296,11 @@ sctp_find_ifa_by_addr(struct sockaddr *addr, uint32_t vrf_id, int holds_lock)
|
|||||||
struct sctp_ifalist *hash_head;
|
struct sctp_ifalist *hash_head;
|
||||||
uint32_t hash_of_addr;
|
uint32_t hash_of_addr;
|
||||||
|
|
||||||
if (holds_lock == 0)
|
if (holds_lock == 0) {
|
||||||
SCTP_IPI_ADDR_RLOCK();
|
SCTP_IPI_ADDR_RLOCK();
|
||||||
|
} else {
|
||||||
|
SCTP_IPI_ADDR_LOCK_ASSERT();
|
||||||
|
}
|
||||||
|
|
||||||
vrf = sctp_find_vrf(vrf_id);
|
vrf = sctp_find_vrf(vrf_id);
|
||||||
if (vrf == NULL) {
|
if (vrf == NULL) {
|
||||||
@ -6429,7 +6432,7 @@ sctp_dynamic_set_primary(struct sockaddr *sa, uint32_t vrf_id)
|
|||||||
struct sctp_ifa *ifa;
|
struct sctp_ifa *ifa;
|
||||||
struct sctp_laddr *wi;
|
struct sctp_laddr *wi;
|
||||||
|
|
||||||
ifa = sctp_find_ifa_by_addr(sa, vrf_id, 0);
|
ifa = sctp_find_ifa_by_addr(sa, vrf_id, SCTP_ADDR_NOT_LOCKED);
|
||||||
if (ifa == NULL) {
|
if (ifa == NULL) {
|
||||||
SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EADDRNOTAVAIL);
|
SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EADDRNOTAVAIL);
|
||||||
return (EADDRNOTAVAIL);
|
return (EADDRNOTAVAIL);
|
||||||
|
Loading…
Reference in New Issue
Block a user