Blame src/memkind_pmem.c

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
}