* Call with a referenced and locked bucket. * Will return true if the bucket was freed; otherwise, false. * tlb: The bucket to unreference. * tree_locked: A pointer to the state of the tree lock. If the tree lock * state changes, the function will update it. * inp: If not NULL and the function needs to drop the inp lock to relock the * tree, it will do so. (The caller must ensure inp w
| 374 | * probably by holding a reference to it.) |
| 375 | */ |
| 376 | static bool |
| 377 | tcp_log_unref_bucket(struct tcp_log_id_bucket *tlb, int *tree_locked, |
| 378 | struct inpcb *inp) |
| 379 | { |
| 380 | |
| 381 | KASSERT(tlb != NULL, ("%s: called with NULL tlb", __func__)); |
| 382 | KASSERT(tree_locked != NULL, ("%s: called with NULL tree_locked", |
| 383 | __func__)); |
| 384 | |
| 385 | tcp_log_id_validate_tree_lock(*tree_locked); |
| 386 | |
| 387 | /* |
| 388 | * Did we hold the last reference on the tlb? If so, we may need |
| 389 | * to free it. (Note that we can realistically only execute the |
| 390 | * loop twice: once without a write lock and once with a write |
| 391 | * lock.) |
| 392 | */ |
| 393 | while (TCPID_BUCKET_UNREF(tlb)) { |
| 394 | /* |
| 395 | * We need a write lock on the tree to free this. |
| 396 | * If we can upgrade the tree lock, this is "easy". If we |
| 397 | * can't upgrade the tree lock, we need to do this the |
| 398 | * "hard" way: unwind all our locks and relock everything. |
| 399 | * In the meantime, anything could have changed. We even |
| 400 | * need to validate that we still need to free the bucket. |
| 401 | */ |
| 402 | if (*tree_locked == TREE_RLOCKED && TCPID_TREE_UPGRADE()) |
| 403 | *tree_locked = TREE_WLOCKED; |
| 404 | else if (*tree_locked != TREE_WLOCKED) { |
| 405 | TCPID_BUCKET_REF(tlb); |
| 406 | if (inp != NULL) |
| 407 | INP_WUNLOCK(inp); |
| 408 | TCPID_BUCKET_UNLOCK(tlb); |
| 409 | if (*tree_locked == TREE_RLOCKED) |
| 410 | TCPID_TREE_RUNLOCK(); |
| 411 | TCPID_TREE_WLOCK(); |
| 412 | *tree_locked = TREE_WLOCKED; |
| 413 | TCPID_BUCKET_LOCK(tlb); |
| 414 | if (inp != NULL) |
| 415 | INP_WLOCK(inp); |
| 416 | continue; |
| 417 | } |
| 418 | |
| 419 | /* |
| 420 | * We have an empty bucket and a write lock on the tree. |
| 421 | * Remove the empty bucket. |
| 422 | */ |
| 423 | tcp_log_remove_bucket(tlb); |
| 424 | return (true); |
| 425 | } |
| 426 | return (false); |
| 427 | } |
| 428 | |
| 429 | /* |
| 430 | * Call with a locked bucket. This function will release the lock on the |
no test coverage detected