diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -437,7 +437,7 @@ } struct tcp_function_block * -find_and_ref_tcp_fb(struct tcp_function_block *blk) +tcp_find_and_ref_fb(struct tcp_function_block *blk) { struct tcp_function_block *rblk; @@ -480,8 +480,8 @@ return (found); } -static struct tcp_function_block * -find_and_ref_tcp_default_fb(void) +struct tcp_function_block * +tcp_find_and_ref_default_fb(void) { struct tcp_function_block *rblk; @@ -510,7 +510,7 @@ * default, unless this stack is the user-selected * default. */ - tfb = find_and_ref_tcp_default_fb(); + tfb = tcp_find_and_ref_default_fb(); if (tfb == tp->t_fb) { refcount_release(&tfb->tfb_refcnt); tfb = NULL; @@ -546,7 +546,7 @@ * If that wasn't feasible, use the built-in default * stack which is not allowed to reject anyone. */ - tfb = find_and_ref_tcp_fb(&tcp_def_funcblk); + tfb = tcp_find_and_ref_fb(&tcp_def_funcblk); if (tfb == NULL) { /* there always should be a default */ panic("Can't refer to tcp_def_funcblk"); @@ -2178,9 +2178,11 @@ * Create a new TCP control block, making an empty reassembly queue and hooking * it to the argument protocol control block. The `inp' parameter must have * come from the zone allocator set up by tcpcbstor declaration. + * The caller needs to provide a pointer to a TCP function block, for which + * it holds a reference count. */ struct tcpcb * -tcp_newtcpcb(struct inpcb *inp) +tcp_newtcpcb(struct inpcb *inp, struct tcp_function_block *tfb) { struct tcpcb *tp = intotcpcb(inp); #ifdef INET6 @@ -2197,10 +2199,7 @@ /* Initialise cc_var struct for this tcpcb. */ tp->t_ccv.type = IPPROTO_TCP; tp->t_ccv.ccvc.tcp = tp; - rw_rlock(&tcp_function_lock); - tp->t_fb = V_tcp_func_set_ptr; - refcount_acquire(&tp->t_fb->tfb_refcnt); - rw_runlock(&tcp_function_lock); + tp->t_fb = tfb; /* * Use the current system default CC algorithm. */ @@ -2209,17 +2208,11 @@ if (CC_ALGO(tp)->cb_init != NULL) if (CC_ALGO(tp)->cb_init(&tp->t_ccv, NULL) > 0) { cc_detach(tp); - if (tp->t_fb->tfb_tcp_fb_fini) - (*tp->t_fb->tfb_tcp_fb_fini)(tp, 1); - refcount_release(&tp->t_fb->tfb_refcnt); return (NULL); } #ifdef TCP_HHOOK if (khelp_init_osd(HELPER_CLASS_TCP, &tp->t_osd)) { - if (tp->t_fb->tfb_tcp_fb_fini) - (*tp->t_fb->tfb_tcp_fb_fini)(tp, 1); - refcount_release(&tp->t_fb->tfb_refcnt); return (NULL); } #endif @@ -2293,7 +2286,6 @@ tp->t_pacing_rate = -1; if (tp->t_fb->tfb_tcp_fb_init) { if ((*tp->t_fb->tfb_tcp_fb_init)(tp, &tp->t_fb_ptr)) { - refcount_release(&tp->t_fb->tfb_refcnt); return (NULL); } } diff --git a/sys/netinet/tcp_syncache.c b/sys/netinet/tcp_syncache.c --- a/sys/netinet/tcp_syncache.c +++ b/sys/netinet/tcp_syncache.c @@ -777,7 +777,7 @@ static struct socket * syncache_socket(struct syncache *sc, struct socket *lso, struct mbuf *m) { - struct tcp_function_block *blk; + struct tcp_function_block *tfb; struct inpcb *inp = NULL; struct socket *so; struct tcpcb *tp; @@ -802,7 +802,13 @@ goto allocfail; } inp = sotoinpcb(so); - if ((tp = tcp_newtcpcb(inp)) == NULL) { + if (V_functions_inherit_listen_socket_stack) + tfb = tcp_find_and_ref_fb(sototcpcb(lso)->t_fb); + else + tfb = tcp_find_and_ref_default_fb(); + KASSERT(tfb != NULL, ("Cannot find TCP function block.")); + if ((tp = tcp_newtcpcb(inp, tfb)) == NULL) { + refcount_release(&tfb->tfb_refcnt); in_pcbfree(inp); sodealloc(so); goto allocfail; @@ -912,37 +918,6 @@ tp->t_port = sc->sc_port; tcp_rcvseqinit(tp); tcp_sendseqinit(tp); - blk = sototcpcb(lso)->t_fb; - if (V_functions_inherit_listen_socket_stack && blk != tp->t_fb) { - /* - * Our parents t_fb was not the default, - * we need to release our ref on tp->t_fb and - * pickup one on the new entry. - */ - struct tcp_function_block *rblk; - void *ptr = NULL; - - rblk = find_and_ref_tcp_fb(blk); - KASSERT(rblk != NULL, - ("cannot find blk %p out of syncache?", blk)); - - if (rblk->tfb_tcp_fb_init == NULL || - (*rblk->tfb_tcp_fb_init)(tp, &ptr) == 0) { - /* Release the old stack */ - if (tp->t_fb->tfb_tcp_fb_fini != NULL) - (*tp->t_fb->tfb_tcp_fb_fini)(tp, 0); - refcount_release(&tp->t_fb->tfb_refcnt); - /* Now set in all the pointers */ - tp->t_fb = rblk; - tp->t_fb_ptr = ptr; - } else { - /* - * Initialization failed. Release the reference count on - * the looked up default stack. - */ - refcount_release(&rblk->tfb_refcnt); - } - } tp->snd_wl1 = sc->sc_irs; tp->snd_max = tp->iss + 1; tp->snd_nxt = tp->iss + 1; @@ -1053,6 +1028,7 @@ return (NULL); abort: + refcount_release(&tfb->tfb_refcnt); in_pcbfree(inp); sodealloc(so); if ((s = tcp_log_addrs(&sc->sc_inc, NULL, NULL, NULL))) { diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -156,6 +156,7 @@ tcp_usr_attach(struct socket *so, int proto, struct thread *td) { struct inpcb *inp; + struct tcp_function_block *tfb; struct tcpcb *tp = NULL; int error; @@ -172,9 +173,11 @@ if (error) goto out; inp = sotoinpcb(so); - tp = tcp_newtcpcb(inp); + tfb = tcp_find_and_ref_default_fb(); + tp = tcp_newtcpcb(inp, tfb); if (tp == NULL) { error = ENOBUFS; + refcount_release(&tfb->tfb_refcnt); in_pcbfree(inp); goto out; } diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -1403,8 +1403,8 @@ int find_tcp_function_alias(struct tcp_function_block *blk, struct tcp_function_set *fs); uint32_t tcp_get_srtt(struct tcpcb *tp, int granularity); void tcp_switch_back_to_default(struct tcpcb *tp); -struct tcp_function_block * -find_and_ref_tcp_fb(struct tcp_function_block *fs); +struct tcp_function_block *tcp_find_and_ref_fb(struct tcp_function_block *fs); +struct tcp_function_block *tcp_find_and_ref_default_fb(void); int tcp_default_ctloutput(struct tcpcb *tp, struct sockopt *sopt); int tcp_ctloutput_set(struct inpcb *inp, struct sockopt *sopt); void tcp_log_socket_option(struct tcpcb *tp, uint32_t option_num, @@ -1445,7 +1445,7 @@ void tcp_mss(struct tcpcb *, int); int tcp_mssopt(struct in_conninfo *); struct tcpcb * - tcp_newtcpcb(struct inpcb *); + tcp_newtcpcb(struct inpcb *, struct tcp_function_block *); int tcp_default_output(struct tcpcb *); void tcp_state_change(struct tcpcb *, int); void tcp_respond(struct tcpcb *, void *,