* Seek for old fragment queue header that can be reused. Try to * reuse a header from currently locked hash bucket. */
| 782 | * reuse a header from currently locked hash bucket. |
| 783 | */ |
| 784 | static struct ipq * |
| 785 | ipq_reuse(int start) |
| 786 | { |
| 787 | struct ipq *fp; |
| 788 | int bucket, i; |
| 789 | |
| 790 | IPQ_LOCK_ASSERT(start); |
| 791 | |
| 792 | for (i = 0; i < IPREASS_NHASH; i++) { |
| 793 | bucket = (start + i) % IPREASS_NHASH; |
| 794 | if (bucket != start && IPQ_TRYLOCK(bucket) == 0) |
| 795 | continue; |
| 796 | fp = TAILQ_LAST(&V_ipq[bucket].head, ipqhead); |
| 797 | if (fp) { |
| 798 | struct mbuf *m; |
| 799 | |
| 800 | IPSTAT_ADD(ips_fragtimeout, fp->ipq_nfrags); |
| 801 | atomic_subtract_int(&nfrags, fp->ipq_nfrags); |
| 802 | while (fp->ipq_frags) { |
| 803 | m = fp->ipq_frags; |
| 804 | fp->ipq_frags = m->m_nextpkt; |
| 805 | m_freem(m); |
| 806 | } |
| 807 | TAILQ_REMOVE(&V_ipq[bucket].head, fp, ipq_list); |
| 808 | V_ipq[bucket].count--; |
| 809 | if (bucket != start) |
| 810 | IPQ_UNLOCK(bucket); |
| 811 | break; |
| 812 | } |
| 813 | if (bucket != start) |
| 814 | IPQ_UNLOCK(bucket); |
| 815 | } |
| 816 | IPQ_LOCK_ASSERT(start); |
| 817 | return (fp); |
| 818 | } |
| 819 | |
| 820 | /* |
| 821 | * Free a fragment reassembly header and all associated datagrams. |