ram.c 3.89 KB
Newer Older
Kirill Smelkov's avatar
Kirill Smelkov committed
1
/* Wendelin.bigfile | Interfaces to work with RAM
2
 * Copyright (C) 2014-2019  Nexedi SA and Contributors.
Kirill Smelkov's avatar
Kirill Smelkov committed
3 4 5 6 7 8 9
 *                          Kirill Smelkov <kirr@nexedi.com>
 *
 * This program is free software: you can Use, Study, Modify and Redistribute
 * it under the terms of the GNU General Public License version 3, or (at your
 * option) any later version, as published by the Free Software Foundation.
 *
 * You can also Link and Combine this program with other software covered by
10 11 12 13
 * the terms of any of the Free Software licenses or any of the Open Source
 * Initiative approved licenses and Convey the resulting work. Corresponding
 * source of such a combination shall include the source code for all other
 * software used.
Kirill Smelkov's avatar
Kirill Smelkov committed
14 15 16 17 18
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * See COPYING file for full licensing terms.
19
 * See https://www.nexedi.com/licensing for rationale and options.
Kirill Smelkov's avatar
Kirill Smelkov committed
20 21 22 23 24 25
 *
 *
 * TODO write why this needed (shmfs, hugetlbfs, ...)
 */

#include <wendelin/bigfile/ram.h>
26
#include <wendelin/bigfile/file.h>
Kirill Smelkov's avatar
Kirill Smelkov committed
27
#include <wendelin/bigfile/virtmem.h>
28
#include <wendelin/bigfile/pagemap.h>
Kirill Smelkov's avatar
Kirill Smelkov committed
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
#include <wendelin/utils.h>
#include <wendelin/bug.h>


/* ramh_ops */

Page *ramh_alloc_page(RAMH *ramh, pgoff_t pgoffset_hint)
{
    struct Page *page;
    pgoff_t ramh_pgoffset;

    // XXX ok to malloc, or better do more structured allocations?
    page = zalloc(sizeof(*page));
    if (!page)
        return NULL;

    ramh_pgoffset = ramh->ramh_ops->alloc_page(ramh, pgoffset_hint);
    if (ramh_pgoffset == RAMH_PGOFF_ALLOCFAIL) {
        free(page);
        return NULL;
    }

    page->state = PAGE_EMPTY;
    /* ->file & ->f_pgoffset are left unset */
    page->ramh  = ramh;
    page->ramh_pgoffset = ramh_pgoffset;
    INIT_LIST_HEAD(&page->lru); /* NOTE ->lru    left unlinked */
56
    INIT_LIST_HEAD(&page->in_dirty);	/* initially not in dirty list */
Kirill Smelkov's avatar
Kirill Smelkov committed
57 58 59 60 61 62 63 64 65 66 67 68 69 70
    page->refcnt = 0;

    return page;
}


void ramh_drop_memory(RAMH *ramh, pgoff_t ramh_pgoffset)
{
    return ramh->ramh_ops->drop_memory(ramh, ramh_pgoffset);
}


void ramh_close(RAMH *ramh)
{
71
    /* NOTE ->close() should free ramh structure itself */
Kirill Smelkov's avatar
Kirill Smelkov committed
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
    ramh->ramh_ops->close(ramh);
}



/* ram_ops */
size_t ram_get_current_maxsize(RAM *ram)
{
    return ram->ram_ops->get_current_maxsize(ram);
}

RAMH *ramh_open(RAM *ram)
{
    return ram->ram_ops->ramh_open(ram);
}

void ram_close(RAM *ram)
{
90 91 92 93
    // TODO assert that
    // - there are no ramh open left
    // - there are no pages on ram->lru_list
    return ram->ram_ops->close(ram);
Kirill Smelkov's avatar
Kirill Smelkov committed
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
}



/* RAM types */
static LIST_HEAD(ram_types);
struct ram_type_entry {
    const struct ram_type *ram_type;
    RAM *default_ram;

    struct list_head    list;
};


void ram_register_type(const struct ram_type *ram_type)
{
    struct ram_type_entry *rte = xzalloc(sizeof(*rte));

    rte->ram_type = ram_type;
    list_add_tail(&rte->list, &ram_types);
}


static const char ram_type_default[] = "shmfs"; /* default type for !ram_type */

RAM *ram_new(const char *ram_type, const char *arg)
{
    struct list_head *h;

    if (!ram_type)
        ram_type = ram_type_default;

    list_for_each(h, &ram_types) {
        struct ram_type_entry *rte = list_entry(h, typeof(*rte), list);
        const struct ram_type *rt  = rte->ram_type;

        if (!strcmp(rt->name, ram_type))
            return rt->ram_new(arg);
    }

    return NULL;
}


RAM *ram_get_default(const char *ram_type)
{
    struct list_head *h;

    if (!ram_type)
        ram_type = ram_type_default;

    list_for_each(h, &ram_types) {
        struct ram_type_entry *rte = list_entry(h, typeof(*rte), list);
        const struct ram_type *rt  = rte->ram_type;

        if (strcmp(rt->name, ram_type))
            continue;

        if (!rte->default_ram)
            rte->default_ram = rt->ram_new(NULL);

        BUG_ON(!rte->default_ram);
        return rte->default_ram;
    }

    BUG();
}