|
Packit |
345191 |
/*
|
|
Packit |
345191 |
* Copyright (C) 2015 - 2019 Intel Corporation.
|
|
Packit |
345191 |
* All rights reserved.
|
|
Packit |
345191 |
*
|
|
Packit |
345191 |
* Redistribution and use in source and binary forms, with or without
|
|
Packit |
345191 |
* modification, are permitted provided that the following conditions are met:
|
|
Packit |
345191 |
* 1. Redistributions of source code must retain the above copyright notice(s),
|
|
Packit |
345191 |
* this list of conditions and the following disclaimer.
|
|
Packit |
345191 |
* 2. Redistributions in binary form must reproduce the above copyright notice(s),
|
|
Packit |
345191 |
* this list of conditions and the following disclaimer in the documentation
|
|
Packit |
345191 |
* and/or other materials provided with the distribution.
|
|
Packit |
345191 |
*
|
|
Packit |
345191 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS
|
|
Packit |
345191 |
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
Packit |
345191 |
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
Packit |
345191 |
* EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
Packit |
345191 |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
Packit |
345191 |
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
Packit |
345191 |
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
Packit |
345191 |
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
|
Packit |
345191 |
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
Packit |
345191 |
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
345191 |
*/
|
|
Packit |
345191 |
|
|
Packit |
345191 |
#include <memkind/internal/memkind_arena.h>
|
|
Packit |
345191 |
#include <memkind/internal/memkind_pmem.h>
|
|
Packit |
345191 |
#include <memkind/internal/memkind_private.h>
|
|
Packit |
345191 |
#include <memkind/internal/memkind_log.h>
|
|
Packit |
345191 |
|
|
Packit |
345191 |
#include <sys/mman.h>
|
|
Packit |
345191 |
#include <unistd.h>
|
|
Packit |
345191 |
#include <fcntl.h>
|
|
Packit |
345191 |
#include <errno.h>
|
|
Packit |
345191 |
#include <assert.h>
|
|
Packit |
345191 |
|
|
Packit |
345191 |
MEMKIND_EXPORT struct memkind_ops MEMKIND_PMEM_OPS = {
|
|
Packit |
345191 |
.create = memkind_pmem_create,
|
|
Packit |
345191 |
.destroy = memkind_pmem_destroy,
|
|
Packit |
345191 |
.malloc = memkind_arena_malloc,
|
|
Packit |
345191 |
.calloc = memkind_arena_calloc,
|
|
Packit |
345191 |
.posix_memalign = memkind_arena_posix_memalign,
|
|
Packit |
345191 |
.realloc = memkind_arena_realloc,
|
|
Packit |
345191 |
.free = memkind_arena_free,
|
|
Packit |
345191 |
.mmap = memkind_pmem_mmap,
|
|
Packit |
345191 |
.get_mmap_flags = memkind_pmem_get_mmap_flags,
|
|
Packit |
345191 |
.get_arena = memkind_thread_get_arena,
|
|
Packit |
345191 |
.malloc_usable_size = memkind_default_malloc_usable_size,
|
|
Packit |
345191 |
.finalize = memkind_pmem_destroy,
|
|
Packit |
345191 |
.update_memory_usage_policy = memkind_arena_update_memory_usage_policy,
|
|
Packit |
345191 |
.get_stat = memkind_arena_get_kind_stat,
|
|
Packit |
345191 |
.defrag_reallocate = memkind_arena_defrag_reallocate
|
|
Packit |
345191 |
};
|
|
Packit |
345191 |
|
|
Packit |
345191 |
void *pmem_extent_alloc(extent_hooks_t *extent_hooks,
|
|
Packit |
345191 |
void *new_addr,
|
|
Packit |
345191 |
size_t size,
|
|
Packit |
345191 |
size_t alignment,
|
|
Packit |
345191 |
bool *zero,
|
|
Packit |
345191 |
bool *commit,
|
|
Packit |
345191 |
unsigned arena_ind)
|
|
Packit |
345191 |
{
|
|
Packit |
345191 |
int err;
|
|
Packit |
345191 |
void *addr = NULL;
|
|
Packit |
345191 |
|
|
Packit |
345191 |
if (new_addr != NULL) {
|
|
Packit |
345191 |
/* not supported */
|
|
Packit |
345191 |
goto exit;
|
|
Packit |
345191 |
}
|
|
Packit |
345191 |
|
|
Packit |
345191 |
struct memkind *kind = get_kind_by_arena(arena_ind);
|
|
Packit |
345191 |
if (kind == NULL) {
|
|
Packit |
345191 |
return NULL;
|
|
Packit |
345191 |
}
|
|
Packit |
345191 |
|
|
Packit |
345191 |
err = memkind_check_available(kind);
|
|
Packit |
345191 |
if (err) {
|
|
Packit |
345191 |
goto exit;
|
|
Packit |
345191 |
}
|
|
Packit |
345191 |
|
|
Packit |
345191 |
addr = memkind_pmem_mmap(kind, new_addr, size);
|
|
Packit |
345191 |
|
|
Packit |
345191 |
if (addr != MAP_FAILED) {
|
|
Packit |
345191 |
*zero = true;
|
|
Packit |
345191 |
*commit = true;
|
|
Packit |
345191 |
|
|
Packit |
345191 |
/* XXX - check alignment */
|
|
Packit |
345191 |
} else {
|
|
Packit |
345191 |
addr = NULL;
|
|
Packit |
345191 |
}
|
|
Packit |
345191 |
exit:
|
|
Packit |
345191 |
return addr;
|
|
Packit |
345191 |
}
|
|
Packit |
345191 |
|
|
Packit |
345191 |
bool pmem_extent_dalloc(extent_hooks_t *extent_hooks,
|
|
Packit |
345191 |
void *addr,
|
|
Packit |
345191 |
size_t size,
|
|
Packit |
345191 |
bool committed,
|
|
Packit |
345191 |
unsigned arena_ind)
|
|
Packit |
345191 |
{
|
|
Packit |
345191 |
// if madvise fail, it means that addr isn't mapped shared (doesn't come from pmem)
|
|
Packit |
345191 |
// and it should be unmapped to avoid space exhaustion when calling large number of
|
|
Packit |
345191 |
// operations like memkind_create_pmem and memkind_destroy_kind
|
|
Packit |
345191 |
errno = 0;
|
|
Packit |
345191 |
int status = madvise(addr, size, MADV_REMOVE);
|
|
Packit |
345191 |
if (!status) {
|
|
Packit |
345191 |
struct memkind *kind = get_kind_by_arena(arena_ind);
|
|
Packit |
345191 |
struct memkind_pmem *priv = kind->priv;
|
|
Packit |
345191 |
if (pthread_mutex_lock(&priv->pmem_lock) != 0)
|
|
Packit |
345191 |
assert(0 && "failed to acquire mutex");
|
|
Packit |
345191 |
priv->current_size -= size;
|
|
Packit |
345191 |
if (pthread_mutex_unlock(&priv->pmem_lock) != 0)
|
|
Packit |
345191 |
assert(0 && "failed to release mutex");
|
|
Packit |
345191 |
} else {
|
|
Packit |
345191 |
if (errno == EOPNOTSUPP) {
|
|
Packit |
345191 |
log_fatal("Filesystem doesn't support FALLOC_FL_PUNCH_HOLE.");
|
|
Packit |
345191 |
abort();
|
|
Packit |
345191 |
}
|
|
Packit |
345191 |
if (munmap(addr, size) == -1) {
|
|
Packit |
345191 |
log_err("munmap failed!");
|
|
Packit |
345191 |
}
|
|
Packit |
345191 |
}
|
|
Packit |
345191 |
return true;
|
|
Packit |
345191 |
}
|
|
Packit |
345191 |
|
|
Packit |
345191 |
bool pmem_extent_commit(extent_hooks_t *extent_hooks,
|
|
Packit |
345191 |
void *addr,
|
|
Packit |
345191 |
size_t size,
|
|
Packit |
345191 |
size_t offset,
|
|
Packit |
345191 |
size_t length,
|
|
Packit |
345191 |
unsigned arena_ind)
|
|
Packit |
345191 |
{
|
|
Packit |
345191 |
/* do nothing - report success */
|
|
Packit |
345191 |
return false;
|
|
Packit |
345191 |
}
|
|
Packit |
345191 |
|
|
Packit |
345191 |
bool pmem_extent_decommit(extent_hooks_t *extent_hooks,
|
|
Packit |
345191 |
void *addr,
|
|
Packit |
345191 |
size_t size,
|
|
Packit |
345191 |
size_t offset,
|
|
Packit |
345191 |
size_t length,
|
|
Packit |
345191 |
unsigned arena_ind)
|
|
Packit |
345191 |
{
|
|
Packit |
345191 |
/* do nothing - report failure (opt-out) */
|
|
Packit |
345191 |
return true;
|
|
Packit |
345191 |
}
|
|
Packit |
345191 |
|
|
Packit |
345191 |
bool pmem_extent_purge(extent_hooks_t *extent_hooks,
|
|
Packit |
345191 |
void *addr,
|
|
Packit |
345191 |
size_t size,
|
|
Packit |
345191 |
size_t offset,
|
|
Packit |
345191 |
size_t length,
|
|
Packit |
345191 |
unsigned arena_ind)
|
|
Packit |
345191 |
{
|
|
Packit |
345191 |
/* do nothing - report failure (opt-out) */
|
|
Packit |
345191 |
return true;
|
|
Packit |
345191 |
}
|
|
Packit |
345191 |
|
|
Packit |
345191 |
bool pmem_extent_split(extent_hooks_t *extent_hooks,
|
|
Packit |
345191 |
void *addr,
|
|
Packit |
345191 |
size_t size,
|
|
Packit |
345191 |
size_t size_a,
|
|
Packit |
345191 |
size_t size_b,
|
|
Packit |
345191 |
bool committed,
|
|
Packit |
345191 |
unsigned arena_ind)
|
|
Packit |
345191 |
{
|
|
Packit |
345191 |
/* do nothing - report success */
|
|
Packit |
345191 |
return false;
|
|
Packit |
345191 |
}
|
|
Packit |
345191 |
|
|
Packit |
345191 |
bool pmem_extent_merge(extent_hooks_t *extent_hooks,
|
|
Packit |
345191 |
void *addr_a,
|
|
Packit |
345191 |
size_t size_a,
|
|
Packit |
345191 |
void *addr_b,
|
|
Packit |
345191 |
size_t size_b,
|
|
Packit |
345191 |
bool committed,
|
|
Packit |
345191 |
unsigned arena_ind)
|
|
Packit |
345191 |
{
|
|
Packit |
345191 |
/* do nothing - report success */
|
|
Packit |
345191 |
return false;
|
|
Packit |
345191 |
}
|
|
Packit |
345191 |
|
|
Packit |
345191 |
void pmem_extent_destroy(extent_hooks_t *extent_hooks,
|
|
Packit |
345191 |
void *addr,
|
|
Packit |
345191 |
size_t size,
|
|
Packit |
345191 |
bool committed,
|
|
Packit |
345191 |
unsigned arena_ind)
|
|
Packit |
345191 |
{
|
|
Packit |
345191 |
if (munmap(addr, size) == -1) {
|
|
Packit |
345191 |
log_err("munmap failed!");
|
|
Packit |
345191 |
}
|
|
Packit |
345191 |
}
|
|
Packit |
345191 |
|
|
Packit |
345191 |
static extent_hooks_t pmem_extent_hooks = {
|
|
Packit |
345191 |
.alloc = pmem_extent_alloc,
|
|
Packit |
345191 |
.dalloc = pmem_extent_dalloc,
|
|
Packit |
345191 |
.commit = pmem_extent_commit,
|
|
Packit |
345191 |
.decommit = pmem_extent_decommit,
|
|
Packit |
345191 |
.purge_lazy = pmem_extent_purge,
|
|
Packit |
345191 |
.split = pmem_extent_split,
|
|
Packit |
345191 |
.merge = pmem_extent_merge,
|
|
Packit |
345191 |
.destroy = pmem_extent_destroy
|
|
Packit |
345191 |
};
|
|
Packit |
345191 |
|
|
Packit |
345191 |
MEMKIND_EXPORT int memkind_pmem_create(struct memkind *kind,
|
|
Packit |
345191 |
struct memkind_ops *ops, const char *name)
|
|
Packit |
345191 |
{
|
|
Packit |
345191 |
struct memkind_pmem *priv;
|
|
Packit |
345191 |
int err;
|
|
Packit |
345191 |
|
|
Packit |
345191 |
priv = (struct memkind_pmem *)malloc(sizeof(struct memkind_pmem));
|
|
Packit |
345191 |
if (!priv) {
|
|
Packit |
345191 |
log_err("malloc() failed.");
|
|
Packit |
345191 |
return MEMKIND_ERROR_MALLOC;
|
|
Packit |
345191 |
}
|
|
Packit |
345191 |
|
|
Packit |
345191 |
if (pthread_mutex_init(&priv->pmem_lock, NULL) != 0) {
|
|
Packit |
345191 |
err = MEMKIND_ERROR_RUNTIME;
|
|
Packit |
345191 |
goto exit;
|
|
Packit |
345191 |
}
|
|
Packit |
345191 |
|
|
Packit |
345191 |
err = memkind_default_create(kind, ops, name);
|
|
Packit |
345191 |
if (err) {
|
|
Packit |
345191 |
goto exit;
|
|
Packit |
345191 |
}
|
|
Packit |
345191 |
|
|
Packit |
345191 |
err = memkind_arena_create_map(kind, &pmem_extent_hooks);
|
|
Packit |
345191 |
if (err) {
|
|
Packit |
345191 |
goto exit;
|
|
Packit |
345191 |
}
|
|
Packit |
345191 |
|
|
Packit |
345191 |
kind->priv = priv;
|
|
Packit |
345191 |
return 0;
|
|
Packit |
345191 |
|
|
Packit |
345191 |
exit:
|
|
Packit |
345191 |
/* err is set, please don't overwrite it with result of pthread_mutex_destroy */
|
|
Packit |
345191 |
pthread_mutex_destroy(&priv->pmem_lock);
|
|
Packit |
345191 |
free(priv);
|
|
Packit |
345191 |
return err;
|
|
Packit |
345191 |
}
|
|
Packit |
345191 |
|
|
Packit |
345191 |
MEMKIND_EXPORT int memkind_pmem_destroy(struct memkind *kind)
|
|
Packit |
345191 |
{
|
|
Packit |
345191 |
struct memkind_pmem *priv = kind->priv;
|
|
Packit |
345191 |
|
|
Packit |
345191 |
memkind_arena_destroy(kind);
|
|
Packit |
345191 |
|
|
Packit |
345191 |
pthread_mutex_destroy(&priv->pmem_lock);
|
|
Packit |
345191 |
|
|
Packit |
345191 |
(void) close(priv->fd);
|
|
Packit |
345191 |
free(priv);
|
|
Packit |
345191 |
|
|
Packit |
345191 |
return 0;
|
|
Packit |
345191 |
}
|
|
Packit |
345191 |
|
|
Packit |
345191 |
MEMKIND_EXPORT void *memkind_pmem_mmap(struct memkind *kind, void *addr,
|
|
Packit |
345191 |
size_t size)
|
|
Packit |
345191 |
{
|
|
Packit |
345191 |
struct memkind_pmem *priv = kind->priv;
|
|
Packit |
345191 |
void *result;
|
|
Packit |
345191 |
|
|
Packit |
345191 |
if (pthread_mutex_lock(&priv->pmem_lock) != 0)
|
|
Packit |
345191 |
assert(0 && "failed to acquire mutex");
|
|
Packit |
345191 |
|
|
Packit |
345191 |
if (priv->max_size != 0 && priv->current_size + size > priv->max_size) {
|
|
Packit |
345191 |
if (pthread_mutex_unlock(&priv->pmem_lock) != 0)
|
|
Packit |
345191 |
assert(0 && "failed to release mutex");
|
|
Packit |
345191 |
return MAP_FAILED;
|
|
Packit |
345191 |
}
|
|
Packit |
345191 |
|
|
Packit |
345191 |
if ((errno = posix_fallocate(priv->fd, priv->offset, (off_t)size)) != 0) {
|
|
Packit |
345191 |
if (pthread_mutex_unlock(&priv->pmem_lock) != 0)
|
|
Packit |
345191 |
assert(0 && "failed to release mutex");
|
|
Packit |
345191 |
return MAP_FAILED;
|
|
Packit |
345191 |
}
|
|
Packit |
345191 |
|
|
Packit |
345191 |
if ((result = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, priv->fd,
|
|
Packit |
345191 |
priv->offset)) != MAP_FAILED) {
|
|
Packit |
345191 |
priv->offset += size;
|
|
Packit |
345191 |
priv->current_size += size;
|
|
Packit |
345191 |
}
|
|
Packit |
345191 |
|
|
Packit |
345191 |
if (pthread_mutex_unlock(&priv->pmem_lock) != 0)
|
|
Packit |
345191 |
assert(0 && "failed to release mutex");
|
|
Packit |
345191 |
|
|
Packit |
345191 |
return result;
|
|
Packit |
345191 |
}
|
|
Packit |
345191 |
|
|
Packit |
345191 |
MEMKIND_EXPORT int memkind_pmem_get_mmap_flags(struct memkind *kind, int *flags)
|
|
Packit |
345191 |
{
|
|
Packit |
345191 |
*flags = MAP_SHARED;
|
|
Packit |
345191 |
return 0;
|
|
Packit |
345191 |
}
|