per Intel policy to include file commit date using git cmd below. The policy does not apply to non-Intel (C) notices. git log --follow -C90% --format=%ad --date default <file> | tail -1 and then pull just the 4 digit year from the result. Intel copyrights were not added to files where Intel either had no contribution ot the contribution lacked substance (ie license header updates, formatting changes, etc). Contribution date used "--follow -C95%" to get the most accurate date. Note that several files in this patch didn't end the license/(c) block with a blank comment line so these were added as the vast majority of files do have this last blank line. Simply there for consistency. Signed-off-by: paul luse <paul.e.luse@intel.com> Change-Id: Id5b7ce4f658fe87132f14139ead58d6e285c04d4 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15192 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com> Community-CI: Mellanox Build Bot
245 lines
6.2 KiB
C
245 lines
6.2 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright (C) 2020 Intel Corporation.
|
|
* All rights reserved.
|
|
* Copyright (c) 2021 Mellanox Technologies LTD. All rights reserved.
|
|
*/
|
|
|
|
#include "nvme_internal.h"
|
|
|
|
struct spdk_nvme_poll_group *
|
|
spdk_nvme_poll_group_create(void *ctx, struct spdk_nvme_accel_fn_table *table)
|
|
{
|
|
struct spdk_nvme_poll_group *group;
|
|
|
|
group = calloc(1, sizeof(*group));
|
|
if (group == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
group->accel_fn_table.table_size = sizeof(struct spdk_nvme_accel_fn_table);
|
|
if (table && table->table_size != 0) {
|
|
group->accel_fn_table.table_size = table->table_size;
|
|
#define SET_FIELD(field) \
|
|
if (offsetof(struct spdk_nvme_accel_fn_table, field) + sizeof(table->field) <= table->table_size) { \
|
|
group->accel_fn_table.field = table->field; \
|
|
} \
|
|
|
|
SET_FIELD(submit_accel_crc32c);
|
|
/* Do not remove this statement, you should always update this statement when you adding a new field,
|
|
* and do not forget to add the SET_FIELD statement for your added field. */
|
|
SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_accel_fn_table) == 16, "Incorrect size");
|
|
|
|
#undef SET_FIELD
|
|
}
|
|
|
|
group->ctx = ctx;
|
|
STAILQ_INIT(&group->tgroups);
|
|
|
|
return group;
|
|
}
|
|
|
|
struct spdk_nvme_poll_group *
|
|
spdk_nvme_qpair_get_optimal_poll_group(struct spdk_nvme_qpair *qpair)
|
|
{
|
|
struct spdk_nvme_transport_poll_group *tgroup;
|
|
|
|
tgroup = nvme_transport_qpair_get_optimal_poll_group(qpair->transport, qpair);
|
|
|
|
if (tgroup == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
return tgroup->group;
|
|
}
|
|
|
|
int
|
|
spdk_nvme_poll_group_add(struct spdk_nvme_poll_group *group, struct spdk_nvme_qpair *qpair)
|
|
{
|
|
struct spdk_nvme_transport_poll_group *tgroup;
|
|
const struct spdk_nvme_transport *transport;
|
|
|
|
if (nvme_qpair_get_state(qpair) != NVME_QPAIR_DISCONNECTED) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
STAILQ_FOREACH(tgroup, &group->tgroups, link) {
|
|
if (tgroup->transport == qpair->transport) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* See if a new transport has been added (dlopen style) and we need to update the poll group */
|
|
if (!tgroup) {
|
|
transport = nvme_get_first_transport();
|
|
while (transport != NULL) {
|
|
if (transport == qpair->transport) {
|
|
tgroup = nvme_transport_poll_group_create(transport);
|
|
if (tgroup == NULL) {
|
|
return -ENOMEM;
|
|
}
|
|
tgroup->group = group;
|
|
STAILQ_INSERT_TAIL(&group->tgroups, tgroup, link);
|
|
break;
|
|
}
|
|
transport = nvme_get_next_transport(transport);
|
|
}
|
|
}
|
|
|
|
return tgroup ? nvme_transport_poll_group_add(tgroup, qpair) : -ENODEV;
|
|
}
|
|
|
|
int
|
|
spdk_nvme_poll_group_remove(struct spdk_nvme_poll_group *group, struct spdk_nvme_qpair *qpair)
|
|
{
|
|
struct spdk_nvme_transport_poll_group *tgroup;
|
|
|
|
STAILQ_FOREACH(tgroup, &group->tgroups, link) {
|
|
if (tgroup->transport == qpair->transport) {
|
|
return nvme_transport_poll_group_remove(tgroup, qpair);
|
|
}
|
|
}
|
|
|
|
return -ENODEV;
|
|
}
|
|
|
|
int
|
|
nvme_poll_group_connect_qpair(struct spdk_nvme_qpair *qpair)
|
|
{
|
|
return nvme_transport_poll_group_connect_qpair(qpair);
|
|
}
|
|
|
|
int
|
|
nvme_poll_group_disconnect_qpair(struct spdk_nvme_qpair *qpair)
|
|
{
|
|
return nvme_transport_poll_group_disconnect_qpair(qpair);
|
|
}
|
|
|
|
int64_t
|
|
spdk_nvme_poll_group_process_completions(struct spdk_nvme_poll_group *group,
|
|
uint32_t completions_per_qpair, spdk_nvme_disconnected_qpair_cb disconnected_qpair_cb)
|
|
{
|
|
struct spdk_nvme_transport_poll_group *tgroup;
|
|
int64_t local_completions = 0, error_reason = 0, num_completions = 0;
|
|
|
|
if (disconnected_qpair_cb == NULL) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
STAILQ_FOREACH(tgroup, &group->tgroups, link) {
|
|
local_completions = nvme_transport_poll_group_process_completions(tgroup, completions_per_qpair,
|
|
disconnected_qpair_cb);
|
|
if (local_completions < 0 && error_reason == 0) {
|
|
error_reason = local_completions;
|
|
} else {
|
|
num_completions += local_completions;
|
|
/* Just to be safe */
|
|
assert(num_completions >= 0);
|
|
}
|
|
}
|
|
|
|
return error_reason ? error_reason : num_completions;
|
|
}
|
|
|
|
void *
|
|
spdk_nvme_poll_group_get_ctx(struct spdk_nvme_poll_group *group)
|
|
{
|
|
return group->ctx;
|
|
}
|
|
|
|
int
|
|
spdk_nvme_poll_group_destroy(struct spdk_nvme_poll_group *group)
|
|
{
|
|
struct spdk_nvme_transport_poll_group *tgroup, *tmp_tgroup;
|
|
|
|
STAILQ_FOREACH_SAFE(tgroup, &group->tgroups, link, tmp_tgroup) {
|
|
STAILQ_REMOVE(&group->tgroups, tgroup, spdk_nvme_transport_poll_group, link);
|
|
if (nvme_transport_poll_group_destroy(tgroup) != 0) {
|
|
STAILQ_INSERT_TAIL(&group->tgroups, tgroup, link);
|
|
return -EBUSY;
|
|
}
|
|
|
|
}
|
|
|
|
free(group);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
spdk_nvme_poll_group_get_stats(struct spdk_nvme_poll_group *group,
|
|
struct spdk_nvme_poll_group_stat **stats)
|
|
{
|
|
struct spdk_nvme_transport_poll_group *tgroup;
|
|
struct spdk_nvme_poll_group_stat *result;
|
|
uint32_t transports_count = 0;
|
|
/* Not all transports used by this poll group may support statistics reporting */
|
|
uint32_t reported_stats_count = 0;
|
|
int rc;
|
|
|
|
assert(group);
|
|
assert(stats);
|
|
|
|
result = calloc(1, sizeof(*result));
|
|
if (!result) {
|
|
SPDK_ERRLOG("Failed to allocate memory for poll group statistics\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
STAILQ_FOREACH(tgroup, &group->tgroups, link) {
|
|
transports_count++;
|
|
}
|
|
|
|
result->transport_stat = calloc(transports_count, sizeof(*result->transport_stat));
|
|
if (!result->transport_stat) {
|
|
SPDK_ERRLOG("Failed to allocate memory for poll group statistics\n");
|
|
free(result);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
STAILQ_FOREACH(tgroup, &group->tgroups, link) {
|
|
rc = nvme_transport_poll_group_get_stats(tgroup, &result->transport_stat[reported_stats_count]);
|
|
if (rc == 0) {
|
|
reported_stats_count++;
|
|
}
|
|
}
|
|
|
|
if (reported_stats_count == 0) {
|
|
free(result->transport_stat);
|
|
free(result);
|
|
SPDK_DEBUGLOG(nvme, "No transport statistics available\n");
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
result->num_transports = reported_stats_count;
|
|
*stats = result;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
spdk_nvme_poll_group_free_stats(struct spdk_nvme_poll_group *group,
|
|
struct spdk_nvme_poll_group_stat *stat)
|
|
{
|
|
struct spdk_nvme_transport_poll_group *tgroup;
|
|
uint32_t i;
|
|
uint32_t freed_stats __attribute__((unused)) = 0;
|
|
|
|
assert(group);
|
|
assert(stat);
|
|
|
|
for (i = 0; i < stat->num_transports; i++) {
|
|
STAILQ_FOREACH(tgroup, &group->tgroups, link) {
|
|
if (nvme_transport_get_trtype(tgroup->transport) == stat->transport_stat[i]->trtype) {
|
|
nvme_transport_poll_group_free_stats(tgroup, stat->transport_stat[i]);
|
|
freed_stats++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
assert(freed_stats == stat->num_transports);
|
|
|
|
free(stat->transport_stat);
|
|
free(stat);
|
|
}
|