static void spdk_app_config_dump_global_section(FILE *fp) { if (NULL == fp) return; /* FIXME - lookup log facility and put it in place of "local7" below */ fprintf(fp, GLOBAL_CONFIG_TMPL, spdk_app_get_core_mask(), spdk_trace_get_tpoint_group_mask(), "local7"); }
/** \brief Create an NVMf fabric connection from the given parameters and schedule it on a reactor thread. \code # identify reactor where the new connections work item will be scheduled reactor = nvmf_allocate_reactor() schedule fabric connection work item on reactor \endcode */ int spdk_nvmf_startup_conn(struct spdk_nvmf_conn *conn) { int lcore; struct spdk_nvmf_conn *admin_conn; uint64_t nvmf_session_core = spdk_app_get_core_mask(); /* * if starting IO connection then determine core * allocated to admin queue to request core mask. * Can not assume nvmf session yet created at time * of fabric connection setup. Rely on fabric * function to locate matching controller session. */ if (conn->type == CONN_TYPE_IOQ && conn->cntlid != 0) { admin_conn = spdk_find_nvmf_conn_by_cntlid(conn->cntlid); if (admin_conn != NULL) { SPDK_TRACELOG(SPDK_TRACE_DEBUG, "Located admin conn session core %d\n", admin_conn->poller.lcore); nvmf_session_core = 1ULL << admin_conn->poller.lcore; } } lcore = nvmf_allocate_reactor(nvmf_session_core); if (lcore < 0) { SPDK_ERRLOG("Unable to find core to launch connection.\n"); goto err0; } conn->state = CONN_STATE_RUNNING; SPDK_NOTICELOG("Launching nvmf connection[qid=%d] on core: %d\n", conn->qid, lcore); conn->poller.fn = spdk_nvmf_conn_do_work; conn->poller.arg = conn; rte_atomic32_inc(&g_num_connections[lcore]); spdk_poller_register(&conn->poller, lcore, NULL); return 0; err0: free_conn(conn); return -1; }
static int nvmf_allocate_reactor(uint64_t cpumask) { int i, selected_core; enum rte_lcore_state_t state; int master_lcore = rte_get_master_lcore(); int32_t num_pollers, min_pollers; cpumask &= spdk_app_get_core_mask(); if (cpumask == 0) { return 0; } min_pollers = INT_MAX; selected_core = 0; for (i = 0; i < RTE_MAX_LCORE; i++) { if (!((1ULL << i) & cpumask)) { continue; } /* * DPDK returns WAIT for the master lcore instead of RUNNING. * So we always treat the reactor on master core as RUNNING. */ if (i == master_lcore) { state = RUNNING; } else { state = rte_eal_get_lcore_state(i); } if (state == FINISHED) { rte_eal_wait_lcore(i); } switch (state) { case WAIT: case FINISHED: /* Idle cores have 0 pollers */ if (0 < min_pollers) { selected_core = i; min_pollers = 0; } break; case RUNNING: /* This lcore is running, check how many pollers it already has */ num_pollers = rte_atomic32_read(&g_num_connections[i]); /* Fill each lcore to target minimum, else select least loaded lcore */ if (num_pollers < (SPDK_NVMF_DEFAULT_NUM_SESSIONS_PER_LCORE * g_nvmf_tgt.MaxConnectionsPerSession)) { /* If fewer than the target number of session connections * exist then add to this lcore */ return i; } else if (num_pollers < min_pollers) { /* Track the lcore that has the minimum number of pollers * to be used if no lcores have already met our criteria */ selected_core = i; min_pollers = num_pollers; } break; } } return selected_core; }