Files
mckernel/kernel/include/memobj.h
Dominique Martinet 39f9d7fdff Handle hugetlbfs file mapping
Hugetlbfs file mappings are handled differently than regular files:
 - pager_req_create will tell us the file is in a hugetlbfs
 - allocate memory upfront, we need to fail if not enough memory
 - the memory needs to be given again if another process maps the same
   file

This implementation still has some hacks, in particular, the memory
needs to be freed when all mappings are done and the file has been
deleted/closed by all processes.
We cannot know when the file is closed/unlinked easily, so clean up
memory when all processes have exited.

To test, install libhugetlbfs and link a program with the additional
LDFLAGS += -B /usr/share/libhugetlbfs -Wl,--hugetlbfs-align

Then run with HUGETLB_ELFMAP=RW set, you can check this works with
HUGETLB_DEBUG=1 HUGETLB_VERBOSE=2

Change-Id: I327920ff06efd82e91b319b27319f41912169af1
2018-10-11 08:54:13 +00:00

166 lines
4.4 KiB
C

/* memobj.h COPYRIGHT FUJITSU LIMITED 2015-2016 */
/**
* \file memobj.h
* License details are found in the file LICENSE.
* \brief
* defines and declares for memory object
* \author Gou Nakamura <go.nakamura.yw@hitachi-solutions.com> \par
* Copyright (C) 2013 Hitachi, Ltd.
*/
/*
* HISTORY:
*/
#ifndef HEADER_MEMOBJ_H
#define HEADER_MEMOBJ_H
#include <ihk/types.h>
#include <ihk/atomic.h>
#include <ihk/lock.h>
#include <errno.h>
#include <list.h>
#include <pager.h>
#ifdef POSTK_DEBUG_ARCH_DEP_18 /* coredump arch separation. */
#else /* POSTK_DEBUG_ARCH_DEP_18 */
/* begin types.h */
typedef int32_t key_t;
typedef uint32_t uid_t;
typedef uint32_t gid_t;
typedef int64_t time_t;
typedef int32_t pid_t;
/* end types.h */
#endif /* POSTK_DEBUG_ARCH_DEP_18 */
enum {
/* for memobj.flags */
MF_HAS_PAGER = 0x0001,
MF_SHMDT_OK = 0x0002,
MF_IS_REMOVABLE = 0x0004,
MF_PREFETCH = 0x0008,
MF_ZEROFILL = 0x0010,
MF_REG_FILE = 0x1000,
MF_DEV_FILE = 0x2000,
MF_PREMAP = 0x8000,
MF_XPMEM = 0x10000, /* To identify XPMEM attachment pages for rusage accounting */
MF_ZEROOBJ = 0x20000, /* To identify pages of anonymous, on-demand paging ranges for rusage accounting */
MF_SHM = 0x40000,
MF_HUGETLBFS = 0x100000,
};
#define MEMOBJ_READY 0
#define MEMOBJ_TO_BE_PREFETCHED 1
struct memobj {
struct memobj_ops *ops;
uint32_t flags;
uint32_t status;
size_t size;
ihk_atomic_t refcnt;
/* For pre-mapped memobjects */
void **pages;
int nr_pages;
char *path;
};
typedef void memobj_free_func_t(struct memobj *obj);
typedef int memobj_get_page_func_t(struct memobj *obj, off_t off, int p2align, uintptr_t *physp, unsigned long *flag, uintptr_t virt_addr);
typedef uintptr_t memobj_copy_page_func_t(struct memobj *obj, uintptr_t orgphys, int p2align);
typedef int memobj_flush_page_func_t(struct memobj *obj, uintptr_t phys, size_t pgsize);
typedef int memobj_invalidate_page_func_t(struct memobj *obj, uintptr_t phys, size_t pgsize);
typedef int memobj_lookup_page_func_t(struct memobj *obj, off_t off, int p2align, uintptr_t *physp, unsigned long *flag);
struct memobj_ops {
memobj_free_func_t *free;
memobj_get_page_func_t *get_page;
memobj_copy_page_func_t *copy_page;
memobj_flush_page_func_t *flush_page;
memobj_invalidate_page_func_t *invalidate_page;
memobj_lookup_page_func_t *lookup_page;
};
static inline int memobj_ref(struct memobj *obj)
{
return ihk_atomic_inc_return(&obj->refcnt);
}
static inline int memobj_unref(struct memobj *obj)
{
int cnt;
if ((cnt = ihk_atomic_dec_return(&obj->refcnt)) == 0) {
(*obj->ops->free)(obj);
}
return cnt;
}
static inline int memobj_get_page(struct memobj *obj, off_t off,
int p2align, uintptr_t *physp, unsigned long *pflag, uintptr_t virt_addr)
{
if (obj->ops->get_page) {
return (*obj->ops->get_page)(obj, off, p2align, physp, pflag, virt_addr);
}
return -ENXIO;
}
static inline uintptr_t memobj_copy_page(struct memobj *obj,
uintptr_t orgphys, int p2align)
{
if (obj->ops->copy_page) {
return (*obj->ops->copy_page)(obj, orgphys, p2align);
}
return -ENXIO;
}
static inline int memobj_flush_page(struct memobj *obj, uintptr_t phys, size_t pgsize)
{
if (obj->ops->flush_page) {
return (*obj->ops->flush_page)(obj, phys, pgsize);
}
return 0;
}
static inline int memobj_invalidate_page(struct memobj *obj, uintptr_t phys,
size_t pgsize)
{
if (obj->ops->invalidate_page) {
return (*obj->ops->invalidate_page)(obj, phys, pgsize);
}
return 0;
}
static inline int memobj_lookup_page(struct memobj *obj, off_t off,
int p2align, uintptr_t *physp, unsigned long *pflag)
{
if (obj->ops->lookup_page) {
return (*obj->ops->lookup_page)(obj, off, p2align, physp, pflag);
}
return -ENXIO;
}
static inline int memobj_has_pager(struct memobj *obj)
{
return !!(obj->flags & MF_HAS_PAGER);
}
static inline int memobj_is_removable(struct memobj *obj)
{
return !!(obj->flags & MF_IS_REMOVABLE);
}
int fileobj_create(int fd, struct memobj **objp, int *maxprotp, uintptr_t virt_addr);
struct shmid_ds;
int shmobj_create(struct shmid_ds *ds, struct memobj **objp);
int zeroobj_create(struct memobj **objp);
int devobj_create(int fd, size_t len, off_t off, struct memobj **objp, int *maxprotp,
int prot, int populate_flags);
int hugefileobj_pre_create(struct pager_create_result *result,
struct memobj **objp, int *maxprotp);
int hugefileobj_create(struct memobj *obj, size_t len, off_t off,
int *pgshiftp, uintptr_t virt_addr);
void hugefileobj_cleanup(void);
#endif /* HEADER_MEMOBJ_H */