static int efab_tcp_drop_from_acceptq(ci_private_t *priv, void *arg) { struct oo_op_tcp_drop_from_acceptq *carg = arg; tcp_helper_resource_t *thr; tcp_helper_endpoint_t *ep; citp_waitable *w; ci_tcp_state *ts; int rc = -EINVAL; /* find stack */ rc = efab_thr_table_lookup(NULL, carg->stack_id, EFAB_THR_TABLE_LOOKUP_CHECK_USER | EFAB_THR_TABLE_LOOKUP_NO_UL, &thr); if( rc < 0 ) return rc; ci_assert( thr->k_ref_count & TCP_HELPER_K_RC_NO_USERLAND ); /* find endpoint and drop OS socket */ ep = ci_trs_get_valid_ep(thr, carg->sock_id); if( ep == NULL ) goto fail1; w = SP_TO_WAITABLE(&thr->netif, carg->sock_id); if( !(w->state & CI_TCP_STATE_TCP) || w->state == CI_TCP_LISTEN ) goto fail2; ts = SP_TO_TCP(&thr->netif, carg->sock_id); ci_assert(ep->os_port_keeper); ci_assert_equal(ep->os_socket, NULL); LOG_TV(ci_log("%s: send reset to non-accepted connection", __FUNCTION__)); /* copy from ci_tcp_listen_shutdown_queues() */ ci_assert(ts->s.b.sb_aflags & CI_SB_AFLAG_TCP_IN_ACCEPTQ); rc = ci_netif_lock(&thr->netif); if( rc != 0 ) { ci_assert_equal(rc, -EINTR); rc = -ERESTARTSYS; goto fail2; } ci_bit_clear(&ts->s.b.sb_aflags, CI_SB_AFLAG_TCP_IN_ACCEPTQ_BIT); /* We have no way to close this connection from the other side: * there was no RST from peer. */ ci_assert_nequal(ts->s.b.state, CI_TCP_CLOSED); ci_assert_nequal(ts->s.b.state, CI_TCP_TIME_WAIT); ci_tcp_send_rst(&thr->netif, ts); ci_tcp_drop(&thr->netif, ts, ECONNRESET); ci_assert_equal(ep->os_port_keeper, NULL); ci_netif_unlock(&thr->netif); efab_tcp_helper_k_ref_count_dec(thr, 1); return 0; fail1: efab_thr_release(thr); fail2: ci_log("%s: inconsistent ep %d:%d", __func__, carg->stack_id, carg->sock_id); return rc; }
static void ci_drop_orphan(ci_netif * ni) { ci_irqlock_state_t lock_flags; tcp_helper_resource_t* trs; int dec_needed; /* Called when connection closes AFTER the file descriptor closes * - in kernel mode, if user mode has gone away, we call * efab_tcp_helper_k_ref_count_dec() to decrement count * of such connections so we can free the stack when * they've all gone away. */ if( ni->flags & CI_NETIF_FLAGS_DROP_SOCK_REFS ) { trs = netif2tcp_helper_resource(ni); dec_needed = 0; ci_irqlock_lock(&trs->lock, &lock_flags); if( trs->n_ep_closing_refs > 0 ) { --trs->n_ep_closing_refs; dec_needed = 1; } ci_irqlock_unlock(&trs->lock, &lock_flags); if( dec_needed ) efab_tcp_helper_k_ref_count_dec(trs, 0); } }
static void oo_epoll_release_common(struct oo_epoll_private* priv) { int i; /* Release references to all stacks */ for( i = 0; i < epoll_max_stacks; i++ ) { if( priv->stacks[i] == NULL ) break; efab_tcp_helper_k_ref_count_dec(priv->stacks[i], 1); priv->stacks[i] = NULL; } kfree(priv->stacks); }
static int efab_tcp_helper_get_info(ci_private_t *unused, void *arg) { ci_netif_info_t *info = arg; int index, rc=0; tcp_helper_resource_t* thr = NULL; ci_netif* ni = NULL; int flags = EFAB_THR_TABLE_LOOKUP_CHECK_USER | EFAB_THR_TABLE_LOOKUP_NO_WARN; #if CI_CFG_EFAB_EPLOCK_RECORD_CONTENTIONS int j; eplock_resource_t* eplock_rs; #endif info->ni_exists = 0; info->ni_no_perms_exists = 0; if( info->ni_orphan ) { flags |= EFAB_THR_TABLE_LOOKUP_NO_UL; info->ni_orphan = 0; } rc = efab_thr_table_lookup(NULL, info->ni_index, flags, &thr); if( rc == 0 ) { info->ni_exists = 1; info->ni_orphan = (thr->k_ref_count & TCP_HELPER_K_RC_NO_USERLAND); ni = &thr->netif; info->mmap_bytes = thr->mem_mmap_bytes; info->k_ref_count = thr->k_ref_count; info->rs_ref_count = oo_atomic_read(&thr->ref_count); memcpy(info->ni_name, ni->state->name, sizeof(ni->state->name)); } else if( rc == -EACCES ) { info->ni_no_perms_id = info->ni_index; if( efab_thr_get_inaccessible_stack_info(info->ni_index, &info->ni_no_perms_uid, &info->ni_no_perms_euid, &info->ni_no_perms_share_with, info->ni_no_perms_name) == 0 ) info->ni_no_perms_exists = 1; } /* sub-ops that do not need the netif to exist */ if( info->ni_subop == CI_DBG_NETIF_INFO_GET_NEXT_NETIF ) { tcp_helper_resource_t* next_thr; info->u.ni_next_ni.index = -1; for( index = info->ni_index + 1; index < 10000 /* FIXME: magic! */; ++index ) { rc = efab_thr_table_lookup(NULL, index, flags, &next_thr); if( rc == 0 ) { if( next_thr->k_ref_count & TCP_HELPER_K_RC_NO_USERLAND ) efab_tcp_helper_k_ref_count_dec(next_thr, 1); else efab_thr_release(next_thr); info->u.ni_next_ni.index = index; break; } if( rc == -EACCES ) { info->u.ni_next_ni.index = index; break; } } rc = 0; } else if( info->ni_subop == CI_DBG_NETIF_INFO_NOOP ) { rc = 0; } if (!info->ni_exists) return 0; /* sub-ops that need the netif to exist */ switch (info->ni_subop) { case CI_DBG_NETIF_INFO_GET_ENDPOINT_STATE: index = info->u.ni_endpoint.index; info->u.ni_endpoint.max = thr->netif.ep_tbl_n; if ((index < 0) || (index >= (int)thr->netif.ep_tbl_n)) { info->u.ni_endpoint.state = CI_TCP_STATE_FREE; } else { citp_waitable_obj* wo = ID_TO_WAITABLE_OBJ(ni, index); info->u.ni_endpoint.state = wo->waitable.state; if( wo->waitable.state == CI_TCP_STATE_UDP ) { ci_udp_state* us = &wo->udp; info->u.ni_endpoint.udpstate = us->udpflags; info->u.ni_endpoint.rx_pkt_ul = us->recv_q.pkts_delivered; info->u.ni_endpoint.rx_pkt_kn = us->stats.n_rx_os; } else if( wo->waitable.state & CI_TCP_STATE_TCP_CONN ) { ci_tcp_state* ts = &wo->tcp; info->u.ni_endpoint.tx_pkts_max = ts->so_sndbuf_pkts; info->u.ni_endpoint.tx_pkts_num = ts->send.num; } if( wo->waitable.state & CI_TCP_STATE_SOCKET ) { ci_sock_cmn* s = &wo->sock; info->u.ni_endpoint.protocol = (int) sock_protocol(s); info->u.ni_endpoint.laddr = sock_laddr_be32(s); info->u.ni_endpoint.lport = (int) sock_lport_be16(s); info->u.ni_endpoint.raddr = sock_raddr_be32(s); info->u.ni_endpoint.rport = (int) sock_rport_be16(s); } } break; case CI_DBG_NETIF_INFO_GET_NEXT_NETIF: /* If the current netif is found, we need to succeed */ break; case CI_DBG_NETIF_INFO_NOOP: /* Always succeeds, rc already set */ break; default: rc = -EINVAL; break; } if( thr ) { /* Lookup needs a matching efab_thr_release() in case of ordinary * stack but just a ref_count_dec in case of orphan */ if( thr->k_ref_count & TCP_HELPER_K_RC_NO_USERLAND ) efab_tcp_helper_k_ref_count_dec(thr, 1); else efab_thr_release(thr); } return rc; }