Blame view

include/wendelin/bigfile/ram.h 5.58 KB
Kirill Smelkov committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 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 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 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 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
#ifndef _WENDELIN_BIGFILE_RAM_H_
#define _WENDELIN_BIGFILE_RAM_H_

/* Wendelin.bigfile | Interfaces to work with RAM
 * Copyright (C) 2014-2015  Nexedi SA and Contributors.
 *                          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
 * the terms of 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.
 *
 * 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.
 *
 * ~~~~~~~~
 * TODO write why this needed (shmfs, hugetlbfs, ...)
 *
 *
 * - need to track pages state      (to support commit / abort)
 *
 * - need to "unload" non-dirty pages to free place for requested new data (reclaim)
 *
 * - need to be able to map a page into several places (to support
 *   overlapping-in-file mappings done not neccessarily adjacent-in-time to
 *   each other - there is no guarantee mapping them adjacent in address space
 *   is possible)
 *
 * XXX
 */

#include <wendelin/list.h>
#include <wendelin/bigfile/types.h>


typedef struct RAMH RAMH;
typedef struct Page Page;


/* RAM - something that provides access to memory (ex. via shmfs, hugetlbfs).
 *
 * Can create pages from memory allocated from backend and give memory back to
 * system on request.
 *
 * Pages allocation/deallocation is done through handles (see RAMH).
 */
struct RAM {
    const struct ram_ops *ram_ops;

    size_t pagesize;
    struct list_head    lru_list;   /* RAM pages in usage order (_ -> page->lru) */
};
typedef struct RAM RAM;


/* RAM operations - implemented by RAM backend */
struct ram_ops {
    size_t  (*get_current_maxsize)  (RAM *ram);
    RAMH *  (*ramh_open)            (RAM *ram);
    void    (*close)                (RAM *ram);
};



/* get RAM current max size (in pages)
 *
 * Maximum size is RAM current whole size, which is shared by RAM Handles and
 * other independent-from-us users (possibly from another processes).
 *
 * So amount of ram allocated for all RAM Handles could a) not be bigger than
 * this, and b) there is no guarantee that this maximum could be achieved via
 * allocating for RAMH only.
 *
 * Maximum is "current" because it can change dynamically - ex. via RAM
 * hotplug.
 */
size_t ram_get_current_maxsize(RAM *ram);


/* open RAM handle
 *
 * Open new handle for memory inside RAM. Close the handle with ramh_close()
 */
RAMH *ramh_open(RAM *ram);


/* close RAM
 *
 * TODO text
 */
void ram_close(RAM *ram);


/* RAM Handle - handle to allocate/free pages from/to RAM
 *
 * Additional level on top of RAM which allows to group pages allocation.
 *
 * RAM backends are assumed to be organized that for a RAM handle, all pages
 * allocated via that handle are provided by a single file in the OS kernel.
 *
 * With such organization, if 2 pages are allocated with adjacent pgoffset
 * and mapped adjacent to each-other in address space - there will be only 1
 * in-os-kernel VMA representing those 2 pages mapping.
 *
 * ( #os-vma should be kept to a minimum, because on every pagefault OS kernel
 *   needs to lookup faulting_addr -> os_vma )
 */
struct RAMH {
    const struct ramh_ops *ramh_ops;

    RAM     *ram;
};
typedef struct RAMH RAMH;

struct ramh_ops {
#define RAMH_PGOFF_ALLOCFAIL    ((pgoff_t)-1ULL)
    /* @return: allocated ram_pgoffset  | RAMH_PGOFF_ALLOCFAIL  */
    pgoff_t (*alloc_page)   (RAMH *ramh, pgoff_t pgoffset_hint);

    void *  (*mmap_page)    (RAMH *ramh, pgoff_t ramh_pgoffset, void *addr, int prot);

    void    (*drop_memory)  (RAMH *ramh, pgoff_t ramh_pgoffset);
    void    (*close)        (RAMH *ramh);
};


/* allocate new page for ramh memory
 *
 * @pgoffset_hint   hint at which offset to allocate memory -
 *
 *                  - could be used so that f_offsets coincide with ramh_offsets
 *                  and as the result, allocated areas constitute of contiguous
 *                  ramh memory = only 1 kernel VMA for whole area.
 *
 * @return          new page | NULL
 *
 * XXX write on how to free pages (= drop & free(struct Page) ?)
 *
 * NOTE after allocation, page->fileh & page->f_pgoffset are unset
 */
Page *ramh_alloc_page(RAMH *ramh, pgoff_t pgoffset_hint);


/* release ramh memory-page at ramh_pgoffset to OS
 *
 * After this call previous content of the memory-page is lost and the memory
 * is released to OS.
 *
 * The memory is still accessible for mmaping but will read as all zeros - on
 * first access OS would again allocate memory for it from scratch.
 */
void  ramh_drop_memory(RAMH *ramh, pgoff_t ramh_pgoffset);


/* close RAMH handle
 *
 * NOTE it is an error to call close() with mappings from ramh left
 */
void ramh_close(RAMH *ramh);



/* get default RAM by type
 *
 * @ram_type    str for ram-type    |NULL - get for default type
 */
RAM *ram_get_default(const char *ram_type);

/* create new RAM instance
 *
 * @ram_type    str for ram-type    |NULL - create for default type
 * @arg         str to pass to ram_type RAM constructor  (NULL - use defaults)
 */
RAM *ram_new(const char *ram_type, const char *arg);


/* RAM type registration (for RAM implementers) */
struct ram_type {
    const char *name;
    RAM *   (*ram_new) (const char *arg);
};

void ram_register_type(const struct ram_type *ram_type);


#endif