dma: Introduce memory domain

Memory domain is used to describe memory which belongs to
another address space (e.g. GPU memory or host memory)
Memory domain can be configured with callbacks to translate
data to another memory domain and to fetch data to
local buffers.

Memory domains will be used in extended
bdev/nvme API added in the following patches.

Change-Id: I0dcc7108a4fbf416a11575aa5cf5d7ec501b3d8b
Signed-off-by: Alexey Marchuk <alexeymar@mellanox.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/8126
Community-CI: Broadcom CI <spdk-ci.pdl@broadcom.com>
Community-CI: Mellanox Build Bot
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Paul Luse <paul.e.luse@intel.com>
Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-by: Ziye Yang <ziye.yang@intel.com>
This commit is contained in:
Alexey Marchuk 2021-04-26 09:29:38 +03:00 committed by Tomasz Zawadzki
parent 6792ae70f1
commit 4e52791092
13 changed files with 904 additions and 2 deletions

View File

@ -2,6 +2,14 @@
## v21.10: (Upcoming Release)
### dma
A new library, lib/dma, has been added. This library provides the necessary infrastructure for
handling systems and devices with multiple memory domains. For example, a PCIe add-in card with an
SoC may be running SPDK on the SoC. That SoC has its own local memory, but SPDK may be controlling
devices that can also access the host system memory. This library provides infrastructure to enumerate
the memory domains and request hardware perform DMA transfers between them.
### log
Added API `spdk_log_to_syslog_level` to return syslog level based on SPDK's

282
include/spdk/dma.h Normal file
View File

@ -0,0 +1,282 @@
/*-
* BSD LICENSE
*
* Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Nvidia Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SPDK_DMA_H
#define SPDK_DMA_H
#include "spdk/assert.h"
#include "spdk/queue.h"
#include "spdk/stdinc.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Identifier of SPDK internal DMA device of RDMA type
*/
#define SPDK_RDMA_DMA_DEVICE "SPDK_RDMA_DMA_DEVICE"
enum spdk_dma_device_type {
/** RDMA devices are capable of performing DMA operations on memory domains using the standard
* RDMA model (protection domain, remote key, address). */
SPDK_DMA_DEVICE_TYPE_RDMA,
/** DMA devices are capable of performing DMA operations on memory domains using physical or
* I/O virtual addresses. */
SPDK_DMA_DEVICE_TYPE_DMA
};
struct spdk_memory_domain;
/**
* Definition of completion callback to be called by fetch function.
*
* \param ctx User context passed to fetch function
* \param iov Pointer to iovs that hold result of fetch function
* \param iovcnt iov array size
* \param rc Result of asynchronous fetch function. Data in iov is valid only when rc is 0
*/
typedef void (*spdk_memory_domain_fetch_data_cpl_cb)(void *ctx, void *iov, uint32_t iovcnt, int rc);
/**
* Definition of function which asynchronously fetches data from src_domain to local memory domain.
* Implementation of this function must call \b cpl_cb only when it returns 0. All other return codes mean failure.
*
* \param src_domain Memory domain to which the data buffer belongs
* \param src_domain_ctx Optional context passed by upper layer with IO request
* \param src_iov Iov vector in \b src_domain space
* \param src_iovcnt src_iov array size
* \param dst_iov Iov vector in local memory domain space, data buffers must be allocated by the caller of
* this function, total size of data buffers must not be less than the size of data in \b src_iov.
* \param dst_iovcnt dst_iov array size
* \param cpl_cb A callback to be called when fetch operation completes
* \param cpl_cb_arg Optional argument to be passed to \b cpl_cb
* \return 0 on success, negated errno on failure
*/
typedef int (*spdk_memory_domain_fetch_data_cb)(struct spdk_memory_domain *src_domain,
void *src_domain_ctx,
struct iovec *src_iov, uint32_t src_iovcnt, struct iovec *dst_iov, uint32_t dst_iovcnt,
spdk_memory_domain_fetch_data_cpl_cb cpl_cb, void *cpl_cb_arg);
struct spdk_memory_domain_translation_result {
/** size of this structure in bytes */
size_t size;
/** Address of data buffer translated into destination memory domain space */
void *addr;
/** Size of the data buffer */
size_t len;
/** Destination domain passed to translation function */
struct spdk_memory_domain *dst_domain;
union {
struct {
uint32_t lkey;
uint32_t rkey;
} rdma;
};
};
struct spdk_memory_domain_translation_ctx {
/** size of this structure in bytes */
size_t size;
union {
struct {
/* Opaque handle for ibv_qp */
void *ibv_qp;
} rdma;
};
};
/**
* Definition of function which translates data from src_domain to a form accessible by dst_domain.
*
* \param src_domain Memory domain to which the data buffer belongs
* \param src_domain_ctx Optional context passed by upper layer with IO request
* \param dst_domain Memory domain which determines type of translation function
* \param dst_domain_ctx Ancillary data for dst_domain
* \param addr Data buffer address in \b src_domain memory space which should be translated into \b dst_domain
* \param len Length of data buffer
* \param result Result of translation function
* \return 0 on success, negated errno on failure
*/
typedef int (*spdk_memory_domain_translate_memory_cb)(struct spdk_memory_domain *src_domain,
void *src_domain_ctx, struct spdk_memory_domain *dst_domain,
struct spdk_memory_domain_translation_ctx *dst_domain_ctx, void *addr, size_t len,
struct spdk_memory_domain_translation_result *result);
struct spdk_memory_domain_ctx {
/** size of this structure in bytes */
size_t size;
union {
struct {
/* Opaque handle for ibv_pd */
void *ibv_pd;
} rdma;
};
};
/**
* Creates a new memory domain of the specified type.
*
* Translation functions can be provided to translate addresses from one memory domain to another.
* If the two domains both use the same addressing scheme for, then this translation does nothing.
* However, it is possible that the two memory domains may address the same physical memory
* differently, so this translation step is required.
*
* \param domain Double pointer to memory domain to be allocated by this function
* \param type Type of the DMA device which can access this memory domain
* \param ctx Optional memory domain context
* \param id String identifier representing the DMA device that can access this memory domain.
* \return 0 on success, negated errno on failure
*/
int spdk_memory_domain_create(struct spdk_memory_domain **domain, enum spdk_dma_device_type type,
struct spdk_memory_domain_ctx *ctx, const char *id);
/**
* Set translation function for memory domain. Overwrites existing translation function.
*
* \param domain Memory domain
* \param translate_cb Translation function
*/
void spdk_memory_domain_set_translation(struct spdk_memory_domain *domain,
spdk_memory_domain_translate_memory_cb translate_cb);
/**
* Set fetch function for memory domain. Overwrites existing fetch function.
*
* \param domain Memory domain
* \param fetch_cb Fetch function
*/
void spdk_memory_domain_set_fetch(struct spdk_memory_domain *domain,
spdk_memory_domain_fetch_data_cb fetch_cb);
/**
* Get the context passed by the user in \ref spdk_memory_domain_create
*
* \param domain Memory domain
* \return Memory domain context
*/
struct spdk_memory_domain_ctx *spdk_memory_domain_get_context(struct spdk_memory_domain *domain);
/**
* Get type of the DMA device that can access this memory domain
*
* \param domain Memory domain
* \return DMA device type
*/
enum spdk_dma_device_type spdk_memory_domain_get_dma_device_type(struct spdk_memory_domain *domain);
/**
* Get an identifier representing the DMA device that can access this memory domain
* \param domain Memory domain
* \return DMA device identifier
*/
const char *spdk_memory_domain_get_dma_device_id(struct spdk_memory_domain *domain);
/**
* Destroy memory domain
*
* \param domain Memory domain
*/
void spdk_memory_domain_destroy(struct spdk_memory_domain *domain);
/**
* Asynchronously fetch data which is described by \b src_domain and located in \b src_iov to a location
* \b dst_iov local memory space.
*
* \param src_domain Memory domain in which space data buffer is located
* \param src_domain_ctx User defined context
* \param src_iov Source data iov
* \param src_iov_cnt The number of elements in \b src_iov
* \param dst_iov Destination iov
* \param dst_iov_cnt The number of elements in \b dst_iov
* \param cpl_cb Completion callback
* \param cpl_cb_arg Completion callback argument
* \return 0 on success, negated errno on failure. fetch_cb implementation must only call the callback when 0
* is returned
*/
int spdk_memory_domain_fetch_data(struct spdk_memory_domain *src_domain, void *src_domain_ctx,
struct iovec *src_iov, uint32_t src_iov_cnt, struct iovec *dst_iov, uint32_t dst_iov_cnt,
spdk_memory_domain_fetch_data_cpl_cb cpl_cb, void *cpl_cb_arg);
/**
* Translate data located in \b src_domain space at address \b addr with size \b len into an equivalent
* description of memory in dst_domain.
*
* This function calls \b src_domain translation callback, the callback needs to be set using \ref
* spdk_memory_domain_set_translation function.
* No data is moved during this operation. Both src_domain and dst_domain must describe the same physical memory,
* just from the point of view of two different memory domain. This is a translation of the description of the memory only.
* Result of translation is stored in \b result, its content depends on the type of \b dst_domain.
*
* \param src_domain Memory domain in which address space data buffer is located
* \param src_domain_ctx User defined context
* \param dst_domain Memory domain in which memory space data buffer should be translated
* \param dst_domain_ctx Ancillary data for dst_domain
* \param addr Addres in \b src_domain memory space
* \param len Length of the data
* \param result Translation result. The content of the translation result is only valid if this
* function returns 0.
* \return 0 on success, negated errno on failure.
*/
int spdk_memory_domain_translate_data(struct spdk_memory_domain *src_domain, void *src_domain_ctx,
struct spdk_memory_domain *dst_domain, struct spdk_memory_domain_translation_ctx *dst_domain_ctx,
void *addr, size_t len, struct spdk_memory_domain_translation_result *result);
/**
* Get the first memory domain.
*
* Combined with \ref spdk_memory_domain_get_next to iterate over all memory domains
*
* \param id Optional identifier representing the DMA device that can access a memory domain, if set
* then this function returns the first memory domain which id matches or NULL
* \return Pointer to the first memory domain or NULL
*/
struct spdk_memory_domain *spdk_memory_domain_get_first(const char *id);
/**
* Get the next memory domain.
*
* \param prev Previous memory domain
* \param id Optional identifier representing the DMA device that can access a memory domain, if set
* then this function returns the next memory domain which id matches or NULL
* \return Pointer to next memory domain or NULL;
*/
struct spdk_memory_domain *spdk_memory_domain_get_next(struct spdk_memory_domain *prev,
const char *id);
#ifdef __cplusplus
}
#endif
#endif /* SPDK_DMA_H */

View File

@ -35,7 +35,7 @@ SPDK_ROOT_DIR := $(abspath $(CURDIR)/..)
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
include $(SPDK_ROOT_DIR)/mk/spdk.lib_deps.mk
DIRS-y += bdev blob blobfs conf accel event json jsonrpc \
DIRS-y += bdev blob blobfs conf dma accel event json jsonrpc \
log lvol rpc sock thread trace util nvme vmd nvmf scsi \
ioat ut_mock iscsi notify init
ifeq ($(OS),Linux)

45
lib/dma/Makefile Normal file
View File

@ -0,0 +1,45 @@
#
# BSD LICENSE
#
# Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Nvidia Corporation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..)
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
SO_VER := 1
SO_MINOR := 0
SO_SUFFIX := $(SO_VER).$(SO_MINOR)
LIBNAME = dma
C_SRCS = dma.c
SPDK_MAP_FILE = $(abspath $(CURDIR)/spdk_dma.map)
include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk

252
lib/dma/dma.c Normal file
View File

@ -0,0 +1,252 @@
/*-
* BSD LICENSE
*
* Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Nvidia Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "spdk/dma.h"
#include "spdk/log.h"
#include "spdk/util.h"
#include "spdk/likely.h"
pthread_mutex_t g_dma_mutex = PTHREAD_MUTEX_INITIALIZER;
TAILQ_HEAD(, spdk_memory_domain) g_dma_memory_domains = TAILQ_HEAD_INITIALIZER(
g_dma_memory_domains);
struct spdk_memory_domain {
enum spdk_dma_device_type type;
spdk_memory_domain_fetch_data_cb fetch_cb;
spdk_memory_domain_translate_memory_cb translate_cb;
TAILQ_ENTRY(spdk_memory_domain) link;
struct spdk_memory_domain_ctx *ctx;
char *id;
};
int
spdk_memory_domain_create(struct spdk_memory_domain **_domain, enum spdk_dma_device_type type,
struct spdk_memory_domain_ctx *ctx, const char *id)
{
struct spdk_memory_domain *domain;
size_t ctx_size;
if (!_domain) {
return -EINVAL;
}
if (ctx && ctx->size == 0) {
SPDK_ERRLOG("Context size can't be 0\n");
return -EINVAL;
}
domain = calloc(1, sizeof(*domain));
if (!domain) {
SPDK_ERRLOG("Failed to allocate memory");
return -ENOMEM;
}
if (id) {
domain->id = strdup(id);
if (!domain->id) {
SPDK_ERRLOG("Failed to allocate memory");
free(domain);
return -ENOMEM;
}
}
if (ctx) {
domain->ctx = calloc(1, sizeof(*domain->ctx));
if (!domain->ctx) {
SPDK_ERRLOG("Failed to allocate memory");
free(domain->id);
free(domain);
return -ENOMEM;
}
ctx_size = spdk_min(sizeof(*domain->ctx), ctx->size);
memcpy(domain->ctx, ctx, ctx_size);
domain->ctx->size = ctx_size;
}
domain->type = type;
pthread_mutex_lock(&g_dma_mutex);
TAILQ_INSERT_TAIL(&g_dma_memory_domains, domain, link);
pthread_mutex_unlock(&g_dma_mutex);
*_domain = domain;
return 0;
}
void
spdk_memory_domain_set_translation(struct spdk_memory_domain *domain,
spdk_memory_domain_translate_memory_cb translate_cb)
{
if (!domain) {
return;
}
domain->translate_cb = translate_cb;
}
void
spdk_memory_domain_set_fetch(struct spdk_memory_domain *domain,
spdk_memory_domain_fetch_data_cb fetch_cb)
{
if (!domain) {
return;
}
domain->fetch_cb = fetch_cb;
}
struct spdk_memory_domain_ctx *
spdk_memory_domain_get_context(struct spdk_memory_domain *domain)
{
assert(domain);
return domain->ctx;
}
enum spdk_dma_device_type spdk_memory_domain_get_dma_device_type(struct spdk_memory_domain *domain)
{
assert(domain);
return domain->type;
}
const char *
spdk_memory_domain_get_dma_device_id(struct spdk_memory_domain *domain)
{
assert(domain);
return domain->id;
}
void
spdk_memory_domain_destroy(struct spdk_memory_domain *domain)
{
if (!domain) {
return;
}
pthread_mutex_lock(&g_dma_mutex);
TAILQ_REMOVE(&g_dma_memory_domains, domain, link);
pthread_mutex_unlock(&g_dma_mutex);
free(domain->ctx);
free(domain->id);
free(domain);
}
int
spdk_memory_domain_fetch_data(struct spdk_memory_domain *src_domain, void *src_domain_ctx,
struct iovec *src_iov, uint32_t src_iov_cnt, struct iovec *dst_iov, uint32_t dst_iov_cnt,
spdk_memory_domain_fetch_data_cpl_cb cpl_cb, void *cpl_cb_arg)
{
assert(src_domain);
assert(src_iov);
assert(dst_iov);
if (spdk_unlikely(!src_domain->fetch_cb)) {
return -ENOTSUP;
}
return src_domain->fetch_cb(src_domain, src_domain_ctx, src_iov, src_iov_cnt, dst_iov, dst_iov_cnt,
cpl_cb, cpl_cb_arg);
}
int
spdk_memory_domain_translate_data(struct spdk_memory_domain *src_domain, void *src_domain_ctx,
struct spdk_memory_domain *dst_domain, struct spdk_memory_domain_translation_ctx *dst_domain_ctx,
void *addr, size_t len, struct spdk_memory_domain_translation_result *result)
{
assert(src_domain);
assert(dst_domain);
assert(result);
if (spdk_unlikely(!src_domain->translate_cb)) {
return -ENOTSUP;
}
return src_domain->translate_cb(src_domain, src_domain_ctx, dst_domain, dst_domain_ctx, addr, len,
result);
}
struct spdk_memory_domain *
spdk_memory_domain_get_first(const char *id)
{
struct spdk_memory_domain *domain;
if (!id) {
pthread_mutex_lock(&g_dma_mutex);
domain = TAILQ_FIRST(&g_dma_memory_domains);
pthread_mutex_unlock(&g_dma_mutex);
return domain;
}
pthread_mutex_lock(&g_dma_mutex);
TAILQ_FOREACH(domain, &g_dma_memory_domains, link) {
if (!strcmp(domain->id, id)) {
break;
}
}
pthread_mutex_unlock(&g_dma_mutex);
return domain;
}
struct spdk_memory_domain *
spdk_memory_domain_get_next(struct spdk_memory_domain *prev, const char *id)
{
struct spdk_memory_domain *domain;
if (!prev) {
return NULL;
}
pthread_mutex_lock(&g_dma_mutex);
domain = TAILQ_NEXT(prev, link);
pthread_mutex_unlock(&g_dma_mutex);
if (!id || !domain) {
return domain;
}
pthread_mutex_lock(&g_dma_mutex);
TAILQ_FOREACH_FROM(domain, &g_dma_memory_domains, link) {
if (!strcmp(domain->id, id)) {
break;
}
}
pthread_mutex_unlock(&g_dma_mutex);
return domain;
}

18
lib/dma/spdk_dma.map Normal file
View File

@ -0,0 +1,18 @@
{
global:
# public functions
spdk_memory_domain_create;
spdk_memory_domain_set_translation;
spdk_memory_domain_set_fetch;
spdk_memory_domain_get_context;
spdk_memory_domain_get_dma_device_type;
spdk_memory_domain_get_dma_device_id;
spdk_memory_domain_destroy;
spdk_memory_domain_fetch_data;
spdk_memory_domain_translate_data;
spdk_memory_domain_get_first;
spdk_memory_domain_get_next;
local: *;
};

View File

@ -51,6 +51,7 @@ DEPDIRS-idxd := log
DEPDIRS-sock := log $(JSON_LIBS)
DEPDIRS-util := log
DEPDIRS-vmd := log
DEPDIRS-dma := log
ifeq ($(CONFIG_VFIO_USER),y)
DEPDIRS-vfio_user := log
endif

View File

@ -34,7 +34,7 @@
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../..)
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
DIRS-y = accel bdev blob blobfs event ioat iscsi json jsonrpc log lvol
DIRS-y = accel bdev blob blobfs dma event ioat iscsi json jsonrpc log lvol
DIRS-y += notify nvme nvmf scsi sock thread util env_dpdk init
DIRS-$(CONFIG_IDXD) += idxd
DIRS-$(CONFIG_REDUCE) += reduce

View File

@ -0,0 +1,43 @@
#
# BSD LICENSE
#
# Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Nvidia Corporation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../..)
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
DIRS-y = dma.c
.PHONY: all clean $(DIRS-y)
all: $(DIRS-y)
clean: $(DIRS-y)
include $(SPDK_ROOT_DIR)/mk/spdk.subdirs.mk

1
test/unit/lib/dma/dma.c/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
dma_ut

View File

@ -0,0 +1,37 @@
#
# BSD LICENSE
#
# Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Nvidia Corporation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../../..)
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
TEST_FILE = dma_ut.c
include $(SPDK_ROOT_DIR)/mk/spdk.unittest.mk

View File

@ -0,0 +1,214 @@
/*-
* BSD LICENSE
*
* Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Nvidia Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "spdk/stdinc.h"
#include "spdk_cunit.h"
#include "common/lib/test_env.c"
#include "unit/lib/json_mock.c"
#include "dma/dma.c"
static bool g_memory_domain_fetch_called;
static bool g_memory_domain_translate_called;
static int g_memory_domain_cb_rc = 123;
static void
test_memory_domain_fetch_data_cpl_cb(void *ctx, void *iov, uint32_t iovcnt, int rc)
{
}
static int test_memory_domain_fetch_data_cb(struct spdk_memory_domain *src_device,
void *src_device_ctx, struct iovec *src_iov, uint32_t src_iovcnt, struct iovec *dst_iov,
uint32_t dst_iovcnt, spdk_memory_domain_fetch_data_cpl_cb cpl_cb, void *cpl_cb_arg)
{
g_memory_domain_fetch_called = true;
return g_memory_domain_cb_rc;
}
static int
test_memory_domain_translate_memory_cb(struct spdk_memory_domain *src_device, void *src_device_ctx,
struct spdk_memory_domain *dst_device, struct spdk_memory_domain_translation_ctx *dst_device_ctx,
void *addr, size_t len, struct spdk_memory_domain_translation_result *result)
{
g_memory_domain_translate_called = true;
return g_memory_domain_cb_rc;
}
static void
test_dma(void)
{
void *test_ibv_pd = (void *)0xdeadbeaf;
struct iovec src_iov = {}, dst_iov = {};
struct spdk_memory_domain *domain = NULL, *domain_2 = NULL, *domain_3 = NULL;
struct spdk_memory_domain_ctx memory_domain_ctx = {
.rdma = { .ibv_pd = test_ibv_pd }
};
struct spdk_memory_domain_ctx *stored_memory_domain_ctx;
struct spdk_memory_domain_translation_result translation_result;
const char *id;
int rc;
/* Create memory domain. No device ptr, expect fail */
rc = spdk_memory_domain_create(NULL, SPDK_DMA_DEVICE_TYPE_RDMA, &memory_domain_ctx, "test");
CU_ASSERT(rc != 0);
/* Create memory domain. ctx with zero size, expect fail */
memory_domain_ctx.size = 0;
rc = spdk_memory_domain_create(&domain, SPDK_DMA_DEVICE_TYPE_RDMA, &memory_domain_ctx, "test");
CU_ASSERT(rc != 0);
/* Create memory domain. expect pass */
memory_domain_ctx.size = sizeof(memory_domain_ctx);
rc = spdk_memory_domain_create(&domain, SPDK_DMA_DEVICE_TYPE_RDMA, &memory_domain_ctx, "test");
CU_ASSERT(rc == 0);
SPDK_CU_ASSERT_FATAL(domain != NULL);
/* Get context. Expect pass */
stored_memory_domain_ctx = spdk_memory_domain_get_context(domain);
SPDK_CU_ASSERT_FATAL(stored_memory_domain_ctx != NULL);
CU_ASSERT(stored_memory_domain_ctx->rdma.ibv_pd == test_ibv_pd);
/* Get DMA device type. Expect pass */
CU_ASSERT(spdk_memory_domain_get_dma_device_type(domain) == SPDK_DMA_DEVICE_TYPE_RDMA);
/* Get DMA id. Expect pass */
id = spdk_memory_domain_get_dma_device_id(domain);
CU_ASSERT((!strcmp(id, domain->id)));
/* Fetch data, callback is NULL. Expect fail */
g_memory_domain_fetch_called = false;
rc = spdk_memory_domain_fetch_data(domain, NULL, &src_iov, 1, &dst_iov, 1,
test_memory_domain_fetch_data_cpl_cb, NULL);
CU_ASSERT(rc == -ENOTSUP);
CU_ASSERT(g_memory_domain_fetch_called == false);
/* Set fetch callback */
spdk_memory_domain_set_fetch(domain, test_memory_domain_fetch_data_cb);
/* Fetch data. Expect pass */
rc = spdk_memory_domain_fetch_data(domain, NULL, &src_iov, 1, &dst_iov, 1,
test_memory_domain_fetch_data_cpl_cb, NULL);
CU_ASSERT(rc == g_memory_domain_cb_rc);
CU_ASSERT(g_memory_domain_fetch_called == true);
/* Translate data, callback is NULL. Expect fail */
g_memory_domain_translate_called = false;
rc = spdk_memory_domain_translate_data(domain, NULL, domain, NULL, (void *)0xfeeddbeef, 0x1000,
&translation_result);
CU_ASSERT(rc == -ENOTSUP);
CU_ASSERT(g_memory_domain_translate_called == false);
/* Set translate callback */
spdk_memory_domain_set_translation(domain, test_memory_domain_translate_memory_cb);
/* Translate data. Expect pass */
g_memory_domain_translate_called = false;
rc = spdk_memory_domain_translate_data(domain, NULL, domain, NULL, (void *)0xfeeddbeef, 0x1000,
&translation_result);
CU_ASSERT(rc == g_memory_domain_cb_rc);
CU_ASSERT(g_memory_domain_translate_called == true);
/* Set translation callback to NULL. Expect pass */
spdk_memory_domain_set_translation(domain, NULL);
CU_ASSERT(domain->translate_cb == NULL);
/* Set translation callback. Expect pass */
spdk_memory_domain_set_translation(domain, test_memory_domain_translate_memory_cb);
CU_ASSERT(domain->translate_cb == test_memory_domain_translate_memory_cb);
/* Set fetch callback to NULL. Expect pass */
spdk_memory_domain_set_fetch(domain, NULL);
CU_ASSERT(domain->fetch_cb == NULL);
/* Set translation_callback. Expect pass */
spdk_memory_domain_set_fetch(domain, test_memory_domain_fetch_data_cb);
CU_ASSERT(domain->fetch_cb == test_memory_domain_fetch_data_cb);
/* Create 2nd and 3rd memory domains with equal id to test enumeration */
rc = spdk_memory_domain_create(&domain_2, SPDK_DMA_DEVICE_TYPE_RDMA, &memory_domain_ctx, "test_2");
CU_ASSERT(rc == 0);
rc = spdk_memory_domain_create(&domain_3, SPDK_DMA_DEVICE_TYPE_RDMA, &memory_domain_ctx, "test_2");
CU_ASSERT(rc == 0);
CU_ASSERT(spdk_memory_domain_get_first("test") == domain);
CU_ASSERT(spdk_memory_domain_get_next(domain, "test") == NULL);
CU_ASSERT(spdk_memory_domain_get_first("test_2") == domain_2);
CU_ASSERT(spdk_memory_domain_get_next(domain_2, "test_2") == domain_3);
CU_ASSERT(spdk_memory_domain_get_next(domain_3, "test_2") == NULL);
CU_ASSERT(spdk_memory_domain_get_first(NULL) == domain);
CU_ASSERT(spdk_memory_domain_get_next(domain, NULL) == domain_2);
CU_ASSERT(spdk_memory_domain_get_next(domain_2, NULL) == domain_3);
CU_ASSERT(spdk_memory_domain_get_next(domain_3, NULL) == NULL);
/* Remove 2nd device, repeat iteration */
spdk_memory_domain_destroy(domain_2);
CU_ASSERT(spdk_memory_domain_get_first(NULL) == domain);
CU_ASSERT(spdk_memory_domain_get_next(domain, NULL) == domain_3);
CU_ASSERT(spdk_memory_domain_get_next(domain_3, NULL) == NULL);
/* Remove 3rd device, repeat iteration */
spdk_memory_domain_destroy(domain_3);
CU_ASSERT(spdk_memory_domain_get_first(NULL) == domain);
CU_ASSERT(spdk_memory_domain_get_next(domain, NULL) == NULL);
CU_ASSERT(spdk_memory_domain_get_first("test_2") == NULL);
/* Destroy memory domain, domain == NULL */
spdk_memory_domain_destroy(NULL);
CU_ASSERT(spdk_memory_domain_get_first(NULL) == domain);
/* Destroy memory domain */
spdk_memory_domain_destroy(domain);
CU_ASSERT(spdk_memory_domain_get_first(NULL) == NULL);
}
int
main(int argc, char **argv)
{
CU_pSuite suite = NULL;
unsigned int num_failures;
CU_set_error_action(CUEA_ABORT);
CU_initialize_registry();
suite = CU_add_suite("dma_suite", NULL, NULL);
CU_ADD_TEST(suite, test_dma);
CU_basic_set_mode(CU_BRM_VERBOSE);
CU_basic_run_tests();
num_failures = CU_get_number_of_failures();
CU_cleanup_registry();
return num_failures;
}

View File

@ -239,6 +239,7 @@ run_test "unittest_util" unittest_util
if grep -q '#define SPDK_CONFIG_VHOST 1' $rootdir/include/spdk/config.h; then
run_test "unittest_vhost" $valgrind $testdir/lib/vhost/vhost.c/vhost_ut
fi
run_test "unittest_dma" $valgrind $testdir/lib/dma/dma.c/dma_ut
run_test "unittest_init" unittest_init