User Space:swapout (this is a rebase commit to merge into development)

This commit is contained in:
Hitoshi Iizuka
2017-10-26 20:29:16 +09:00
parent 5a8d1f09e8
commit aebacb243e
51 changed files with 2649 additions and 38 deletions

View File

@@ -96,7 +96,7 @@ struct swapinfo {
struct arealist swap_area;
struct arealist mlock_area;
struct mlockcntnr mlock_container;
#define UDATA_BUFSIZE (8*1024)
#define UDATA_BUFSIZE PAGE_SIZE
char *swapfname;
char *udata_buf; /* To read-store data from Linux to user space */
@@ -295,7 +295,7 @@ static int
pager_open(struct swapinfo *si, char *fname, int flag, int mode)
{
int fd;
strcpy(si->udata_buf, fname);
copy_to_user(si->udata_buf, fname, strlen(fname) + 1);
fd = linux_open(si->udata_buf, flag, mode);
return fd;
}
@@ -303,22 +303,69 @@ pager_open(struct swapinfo *si, char *fname, int flag, int mode)
static int
pager_unlink(struct swapinfo *si, char *fname)
{
strcpy(si->udata_buf, fname);
copy_to_user(si->udata_buf, fname, strlen(fname) + 1);
return linux_unlink(si->udata_buf);
}
static int
pager_copy_from_user(void * dst, void * from, size_t size, struct process_vm *vm)
{
int ret;
void *virt;
unsigned long psize;
unsigned long rphys;
int faulted = 0;
if (size > PAGE_SIZE) {
ret = -EFAULT;
return ret;
}
retry_lookup:
/* remember page */
ret = ihk_mc_pt_virt_to_phys_size(vm->address_space->page_table,
dst, &rphys, &psize);
if (ret) {
uint64_t reason = PF_POPULATE | PF_WRITE | PF_USER;
void *addr= (void *)(((unsigned long)dst)& PAGE_MASK);
if (faulted) {
ret = -EFAULT;
return ret;
}
ret = page_fault_process_vm(vm, addr, reason);
if (ret) {
ret = -EFAULT;
return ret;
}
faulted = 1;
goto retry_lookup;
}
virt = phys_to_virt(rphys);
ret = copy_from_user(virt, from, size);
return ret;
}
static ssize_t
pager_read(struct swapinfo *si, int fd, void *start, size_t size)
pager_read(struct swapinfo *si, int fd, void *start, size_t size,struct process_vm *vm)
{
ssize_t off, sz, rs;
kprintf("pager_read: %lx (%lx)\n", start, size);
for (off = 0; off < size; off += sz) {
sz = size - off;
sz = (sz > UDATA_BUFSIZE) ? UDATA_BUFSIZE : sz;
rs = linux_read(fd, si->udata_buf, sz);
if (rs != sz) return rs;
copy_to_user(start + off, si->udata_buf, sz);
rs = pager_copy_from_user(start + off, si->udata_buf, sz, vm);
if (rs != 0) return rs;
}
return off;
}
@@ -354,23 +401,26 @@ mlocklist_req(unsigned long start, unsigned long end, struct addrpair *addr, int
static int
mlocklist_morereq(struct swapinfo *si, unsigned long *start)
{
struct areaent *ent = si->mlock_area.tail;
struct areaent went,*ent = si->mlock_area.tail;
copy_from_user(&went, ent, sizeof(struct areaent));
dkprintf("mlocklist_morereq: start = %ld and = %ld\n",
ent->pair[ent->count].start, ent->pair[ent->count].end);
if (ent->pair[ent->count].start != (unsigned long) -1) {
went.pair[went.count].start, went.pair[went.count].end);
if (went.pair[went.count].start != (unsigned long) -1) {
return 0;
}
*start = ent->pair[ent->count].end;
*start = went.pair[went.count].end;
return 1;
}
static int
arealist_alloc(struct swapinfo *si, struct arealist *areap)
{
struct areaent went;
areap->head = areap->tail = myalloc(si, sizeof(struct areaent));
if (areap->head == NULL) return -ENOMEM;
memset(areap->head, 0, sizeof(struct areaent));
memset(&went, 0, sizeof(struct areaent));
copy_to_user(areap->head, &went, sizeof(struct areaent));
return 0;
}
@@ -402,7 +452,7 @@ arealist_free(struct arealist *area)
static int
arealist_get(struct swapinfo *si, struct addrpair **pair, struct arealist *area)
{
struct areaent *tmp;
struct areaent *tmp,wtmp;
struct areaent *tail = area->tail;
if (tail->count < MLOCKADDRS_SIZE - 1) { /* at least two entries are needed */
if (pair) *pair = &tail->pair[tail->count];
@@ -412,8 +462,10 @@ arealist_get(struct swapinfo *si, struct addrpair **pair, struct arealist *area)
if (tmp == NULL) {
return -1;
}
memset(tmp, 0, sizeof(struct areaent));
area->tail->next = tmp;
memset(&wtmp, 0, sizeof(struct areaent));
copy_to_user(tmp, &wtmp, sizeof(struct areaent));
copy_to_user(&(area->tail->next), &tmp, sizeof(struct areaent *));
area->tail = tmp;
if (pair) *pair = area->tail->pair;
return MLOCKADDRS_SIZE;
@@ -422,7 +474,10 @@ arealist_get(struct swapinfo *si, struct addrpair **pair, struct arealist *area)
static void
arealist_update(int cnt, struct arealist *area)
{
area->tail->count += cnt;
int i;
copy_from_user(&i, &(area->tail->count), sizeof(int));
i += cnt;
copy_to_user(&(area->tail->count), &i, sizeof(int));
area->count += cnt;
}
@@ -431,11 +486,13 @@ arealist_add(struct swapinfo *si, unsigned long start, unsigned long end,
unsigned long flag, struct arealist *area)
{
int cc;
struct addrpair *addr;
struct addrpair *addr,waddr;
cc = arealist_get(si, &addr, area);
if (cc < 0) return -1;
addr->start = start; addr->end = end; addr->flag = flag;
waddr.start = start; waddr.end = end; waddr.flag = flag;
copy_to_user(addr, &waddr, sizeof(struct addrpair));
arealist_update(1, area);
return 0;
}
@@ -444,27 +501,31 @@ static int
arealist_preparewrite(struct arealist *areap, struct swap_areainfo *info,
ssize_t off, struct process_vm *vm, int flag)
{
struct areaent *ent;
struct areaent *ent,went;
int count = 0;
ssize_t totsz = 0;
unsigned long pos;
struct page_table *pt = vm->address_space->page_table;
for (ent = areap->head; ent != NULL; ent = ent->next) {
int i;
for (i = 0; i < ent->count; i++, count++) {
ssize_t sz = ent->pair[i].end - ent->pair[i].start;
info[count].start = ent->pair[i].start;
info[count].end = ent->pair[i].end;
info[count].flag = ent->pair[i].flag;
copy_from_user(&went, ent, sizeof(struct areaent));
for (i = 0; i < went.count; i++, count++) {
ssize_t sz = went.pair[i].end - went.pair[i].start;
copy_to_user(&(info[count].start), &(went.pair[i].start), sizeof(unsigned long));
copy_to_user(&(info[count].end), &(went.pair[i].end), sizeof(unsigned long));
copy_to_user(&(info[count].flag), &(went.pair[i].flag), sizeof(unsigned long));
if (flag) { /* position in file */
info[count].pos = off + totsz;
pos = off + totsz;
} else { /* physical memory */
if (ihk_mc_pt_virt_to_phys(pt,
(void*) ent->pair[i].start,
&info[count].pos)) {
&pos)) {
kprintf("Cannot get phys\n");
}
}
copy_to_user(&(info[count].pos), &pos, sizeof(unsigned long));
totsz += sz;
}
}
@@ -489,6 +550,7 @@ arealist_print(char *msg, struct arealist *areap, int count)
for (ent = areap->head; ent != NULL; ent = ent->next) {
int i;
for (i = 0; i < ent->count; i++) {
kprintf("\t%p -- %p\n",
(void*) ent->pair[i].start, (void*) ent->pair[i].end);
}
@@ -608,13 +670,13 @@ do_pagein(int flag)
extern int ihk_mc_pt_print_pte(struct page_table *pt, void *virt);
sz = si->swap_info[i].end - si->swap_info[i].start;
dkprintf("pagein: %016lx:%016lx sz(%lx)\n", si->swap_info[i].start, si->swap_info[i].end, sz);
rs = pager_read(si, fd, (void*) si->swap_info[i].start, sz);
rs = pager_read(si, fd, (void*) si->swap_info[i].start, sz, vm);
if (rs != sz) goto err;
// ihk_mc_pt_print_pte(vm->address_space->page_table, (void*) si->swap_info[i].start);
}
linux_close(fd);
print_region("after pagin", vm);
kprintf("do_pagein: done, currss(%lx)\n", vm->currss);
dkprintf("do_pagein: done, currss(%lx)\n", vm->currss);
vm->swapinfo = NULL;
kfree(si->swapfname);
kfree(si);
@@ -679,7 +741,8 @@ do_pageout(char *fname, void *buf, size_t size, int flag)
goto err;
}
fd = linux_open(fname, O_RDWR|O_CREAT|O_TRUNC, 0600);
copy_to_user(si->udata_buf, si->swapfname, strlen(si->swapfname) + 1);
fd = linux_open(si->udata_buf, O_RDWR|O_CREAT|O_TRUNC, 0600);
if (fd < 0) {
ekprintf("do_pageout: Cannot open/create file: %s\n", fname);
cc = fd;
@@ -752,10 +815,10 @@ do_pageout(char *fname, void *buf, size_t size, int flag)
/* preparing page store */
si->swphdr = myalloc(si, sizeof(struct swap_header));
strncpy(si->swphdr->magic, MCKERNEL_SWAP, SWAP_HLEN);
strncpy(si->swphdr->version, MCKERNEL_SWAP_VERSION, SWAP_HLEN);
si->swphdr->count_sarea = si->swap_area.count;
si->swphdr->count_marea = si->mlock_area.count;
copy_to_user(&(si->swphdr->magic), MCKERNEL_SWAP, SWAP_HLEN);
copy_to_user(&(si->swphdr->version), MCKERNEL_SWAP_VERSION, SWAP_HLEN);
copy_to_user(&(si->swphdr->count_sarea), &(si->swap_area.count), sizeof(unsigned int));
copy_to_user(&(si->swphdr->count_marea), &(si->mlock_area.count), sizeof(unsigned int));
if ((cc = pager_write(fd, si->swphdr, sizeof(struct swap_header)))
!= sizeof(struct swap_header)) {
if (cc >= 0)
@@ -779,8 +842,10 @@ do_pageout(char *fname, void *buf, size_t size, int flag)
if ((cc = arealist_write(fd, si->mlock_info, si->mlock_area.count)) < 0) goto err;
/* now pages are stored */
for (i = 0; i < si->swap_area.count; i++) {
sz = si->swap_info[i].end - si->swap_info[i].start;
if ((cc = pager_write(fd, (void*) si->swap_info[i].start, sz)) != sz) {
struct swap_areainfo sw_info;
copy_from_user(&sw_info, &(si->swap_info[i]), sizeof(struct swap_areainfo));
sz = sw_info.end - sw_info.start;
if ((cc = pager_write(fd, (void*) sw_info.start, sz)) != sz) {
if (cc >= 0)
cc = -EIO;
goto err;
@@ -792,10 +857,12 @@ do_pageout(char *fname, void *buf, size_t size, int flag)
}
kprintf("removing physical memory\n");
for (i = 0; i < si->swap_area.count; i++) {
struct swap_areainfo sw_info;
copy_from_user(&sw_info, &(si->swap_info[i]), sizeof(struct swap_areainfo));
cc = ihk_mc_pt_free_range(vm->address_space->page_table,
vm,
(void*) si->swap_info[i].start,
(void*) si->swap_info[i].end, NULL);
(void*) sw_info.start,
(void*) sw_info.end, NULL);
if (cc < 0) {
kprintf("ihk_mc_pt_clear_range returns: %d\n", cc);
}
@@ -811,8 +878,10 @@ do_pageout(char *fname, void *buf, size_t size, int flag)
* except TEXT, STACK, readonly pages, are not invalid.
*/
for (i = 0; i < si->swap_area.count; i++) {
sz = si->swap_info[i].end - si->swap_info[i].start;
cc = linux_munmap((void*) si->swap_info[i].start, sz, 0);
struct swap_areainfo sw_info;
copy_from_user(&sw_info, &(si->swap_info[i]), sizeof(struct swap_areainfo));
sz = sw_info.end - sw_info.start;
cc = linux_munmap((void*) sw_info.start, sz, 0);
if (cc < 0) {
kprintf("do_pageout: Cannot munmap: %lx len(%lx)\n",
si->swap_info[i].start, sz);