mem: add external API to retrieve page fd

Now that we can retrieve page fd's internally, we can expose it
as an external API. This will add two flavors of API - thread-safe
and non-thread-safe. Fix up internal API's to return values we need
without modifying rte_errno internally if called from within EAL.

We do not want calling code to accidentally close an internal fd, so
we make a duplicate of it before we return it to the user. Caller is
therefore responsible for closing this fd.

Signed-off-by: Anatoly Burakov <anatoly.burakov@intel.com>
Reviewed-by: Maxime Coquelin <maxime.coquelin@redhat.com>
This commit is contained in:
Anatoly Burakov 2018-09-04 16:15:48 +01:00 committed by Thomas Monjalon
parent 1009ba1704
commit 41dbdb6872
6 changed files with 118 additions and 9 deletions

View File

@ -4,6 +4,7 @@
#include <inttypes.h>
#include <rte_errno.h>
#include <rte_log.h>
#include <rte_memory.h>
@ -50,13 +51,13 @@ eal_memalloc_sync_with_primary(void)
int
eal_memalloc_get_seg_fd(int list_idx, int seg_idx)
{
return -1;
return -ENOTSUP;
}
int
eal_memalloc_set_seg_fd(int list_idx, int seg_idx, int fd)
{
return -1;
return -ENOTSUP;
}
int

View File

@ -550,6 +550,55 @@ rte_memseg_list_walk(rte_memseg_list_walk_t func, void *arg)
return ret;
}
int __rte_experimental
rte_memseg_get_fd_thread_unsafe(const struct rte_memseg *ms)
{
struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
struct rte_memseg_list *msl;
struct rte_fbarray *arr;
int msl_idx, seg_idx, ret;
if (ms == NULL) {
rte_errno = EINVAL;
return -1;
}
msl = rte_mem_virt2memseg_list(ms->addr);
if (msl == NULL) {
rte_errno = EINVAL;
return -1;
}
arr = &msl->memseg_arr;
msl_idx = msl - mcfg->memsegs;
seg_idx = rte_fbarray_find_idx(arr, ms);
if (!rte_fbarray_is_used(arr, seg_idx)) {
rte_errno = ENOENT;
return -1;
}
ret = eal_memalloc_get_seg_fd(msl_idx, seg_idx);
if (ret < 0) {
rte_errno = -ret;
ret = -1;
}
return ret;
}
int __rte_experimental
rte_memseg_get_fd(const struct rte_memseg *ms)
{
struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
int ret;
rte_rwlock_read_lock(&mcfg->memory_hotplug_lock);
ret = rte_memseg_get_fd_thread_unsafe(ms);
rte_rwlock_read_unlock(&mcfg->memory_hotplug_lock);
return ret;
}
/* init memory subsystem */
int
rte_eal_memory_init(void)

View File

@ -76,9 +76,11 @@ eal_memalloc_mem_alloc_validator_unregister(const char *name, int socket_id);
int
eal_memalloc_mem_alloc_validate(int socket_id, size_t new_len);
/* returns fd or -errno */
int
eal_memalloc_get_seg_fd(int list_idx, int seg_idx);
/* returns 0 or -errno */
int
eal_memalloc_set_seg_fd(int list_idx, int seg_idx, int fd);

View File

@ -317,6 +317,54 @@ rte_memseg_contig_walk_thread_unsafe(rte_memseg_contig_walk_t func, void *arg);
int __rte_experimental
rte_memseg_list_walk_thread_unsafe(rte_memseg_list_walk_t func, void *arg);
/**
* Return file descriptor associated with a particular memseg (if available).
*
* @note This function read-locks the memory hotplug subsystem, and thus cannot
* be used within memory-related callback functions.
*
* @note This returns an internal file descriptor. Performing any operations on
* this file descriptor is inherently dangerous, so it should be treated
* as read-only for all intents and purposes.
*
* @param ms
* A pointer to memseg for which to get file descriptor.
*
* @return
* Valid file descriptor in case of success.
* -1 in case of error, with ``rte_errno`` set to the following values:
* - EINVAL - ``ms`` pointer was NULL or did not point to a valid memseg
* - ENODEV - ``ms`` fd is not available
* - ENOENT - ``ms`` is an unused segment
* - ENOTSUP - segment fd's are not supported
*/
int __rte_experimental
rte_memseg_get_fd(const struct rte_memseg *ms);
/**
* Return file descriptor associated with a particular memseg (if available).
*
* @note This function does not perform any locking, and is only safe to call
* from within memory-related callback functions.
*
* @note This returns an internal file descriptor. Performing any operations on
* this file descriptor is inherently dangerous, so it should be treated
* as read-only for all intents and purposes.
*
* @param ms
* A pointer to memseg for which to get file descriptor.
*
* @return
* Valid file descriptor in case of success.
* -1 in case of error, with ``rte_errno`` set to the following values:
* - EINVAL - ``ms`` pointer was NULL or did not point to a valid memseg
* - ENODEV - ``ms`` fd is not available
* - ENOENT - ``ms`` is an unused segment
* - ENOTSUP - segment fd's are not supported
*/
int __rte_experimental
rte_memseg_get_fd_thread_unsafe(const struct rte_memseg *ms);
/**
* Dump the physical memory layout to a file.
*

View File

@ -34,6 +34,7 @@
#include <rte_log.h>
#include <rte_eal_memconfig.h>
#include <rte_eal.h>
#include <rte_errno.h>
#include <rte_memory.h>
#include <rte_spinlock.h>
@ -1381,7 +1382,7 @@ eal_memalloc_set_seg_fd(int list_idx, int seg_idx, int fd)
int len = mcfg->memsegs[list_idx].memseg_arr.len;
if (alloc_list(list_idx, len) < 0)
return -1;
return -ENOMEM;
}
fd_list[list_idx].fds[seg_idx] = fd;
@ -1391,12 +1392,18 @@ eal_memalloc_set_seg_fd(int list_idx, int seg_idx, int fd)
int
eal_memalloc_get_seg_fd(int list_idx, int seg_idx)
{
if (internal_config.single_file_segments)
return fd_list[list_idx].memseg_list_fd;
/* list not initialized */
if (fd_list[list_idx].len == 0)
return -1;
return fd_list[list_idx].fds[seg_idx];
int fd;
if (internal_config.single_file_segments) {
fd = fd_list[list_idx].memseg_list_fd;
} else if (fd_list[list_idx].len == 0) {
/* list not initialized */
fd = -1;
} else {
fd = fd_list[list_idx].fds[seg_idx];
}
if (fd < 0)
return -ENODEV;
return fd;
}
int

View File

@ -327,6 +327,8 @@ EXPERIMENTAL {
rte_mem_virt2memseg_list;
rte_memseg_contig_walk;
rte_memseg_contig_walk_thread_unsafe;
rte_memseg_get_fd;
rte_memseg_get_fd_thread_unsafe;
rte_memseg_list_walk;
rte_memseg_list_walk_thread_unsafe;
rte_memseg_walk;