mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
FSIF: extend protocol to multi-grant requests and multi-page ring
To improve throughput and inline the stat response. Signed-off-by: Grzegorz Milos <gm281@cam.ac.uk> Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
This commit is contained in:
1 parent
ee449f80fd
commit
e5ba23a1d9
8 files changed
+283
-122
No files matched your search
+184
-60
@@ -50,6 +50,8 @@
|
||||
|
||||
struct fs_request;
|
||||
struct fs_import *fs_import;
|
||||
void *alloc_buffer_page(struct fs_request *req, domid_t domid, grant_ref_t *gref);
|
||||
void free_buffer_page(struct fs_request *req);
|
||||
|
||||
/******************************************************************************/
|
||||
/* RING REQUEST/RESPONSES HANDLING */
|
||||
@@ -57,13 +59,21 @@ struct fs_import *fs_import;
|
||||
|
||||
struct fs_request
|
||||
{
|
||||
void *page;
|
||||
grant_ref_t gref;
|
||||
void *private1; /* Specific to request type */
|
||||
void *private2;
|
||||
struct thread *thread; /* Thread blocked on this request */
|
||||
struct fsif_response shadow_rsp; /* Response copy writen by the
|
||||
interrupt handler */
|
||||
};
|
||||
|
||||
struct fs_rw_gnts
|
||||
{
|
||||
/* TODO 16 bit? */
|
||||
int count;
|
||||
grant_ref_t grefs[FSIF_NR_READ_GNTS];
|
||||
void *pages[FSIF_NR_READ_GNTS];
|
||||
};
|
||||
|
||||
/* Ring operations:
|
||||
* FSIF ring is used differently to Linux-like split devices. This stems from
|
||||
* the fact that no I/O request queue is present. The use of some of the macros
|
||||
@@ -177,6 +187,8 @@ int fs_open(struct fs_import *import, char *file)
|
||||
{
|
||||
struct fs_request *fsr;
|
||||
unsigned short priv_req_id;
|
||||
grant_ref_t gref;
|
||||
void *buffer;
|
||||
RING_IDX back_req_id;
|
||||
struct fsif_request *req;
|
||||
int fd;
|
||||
@@ -189,14 +201,15 @@ int fs_open(struct fs_import *import, char *file)
|
||||
priv_req_id = get_id_from_freelist(import->freelist);
|
||||
DEBUG("Request id for fs_open call is: %d\n", priv_req_id);
|
||||
fsr = &import->requests[priv_req_id];
|
||||
DEBUG("gref id=%d\n", fsr->gref);
|
||||
buffer = alloc_buffer_page(fsr, import->dom_id, &gref);
|
||||
DEBUG("gref id=%d\n", gref);
|
||||
fsr->thread = current;
|
||||
sprintf(fsr->page, "%s", file);
|
||||
sprintf(buffer, "%s", file);
|
||||
|
||||
req = RING_GET_REQUEST(&import->ring, back_req_id);
|
||||
req->type = REQ_FILE_OPEN;
|
||||
req->id = priv_req_id;
|
||||
req->u.fopen.gref = fsr->gref;
|
||||
req->u.fopen.gref = gref;
|
||||
|
||||
/* Set blocked flag before commiting the request, thus avoiding missed
|
||||
* response race */
|
||||
@@ -207,6 +220,7 @@ int fs_open(struct fs_import *import, char *file)
|
||||
/* Read the response */
|
||||
fd = (int)fsr->shadow_rsp.ret_val;
|
||||
DEBUG("The following FD returned: %d\n", fd);
|
||||
free_buffer_page(fsr);
|
||||
add_id_to_freelist(priv_req_id, import->freelist);
|
||||
|
||||
return fd;
|
||||
@@ -254,11 +268,13 @@ ssize_t fs_read(struct fs_import *import, int fd, void *buf,
|
||||
{
|
||||
struct fs_request *fsr;
|
||||
unsigned short priv_req_id;
|
||||
struct fs_rw_gnts gnts;
|
||||
RING_IDX back_req_id;
|
||||
struct fsif_request *req;
|
||||
ssize_t ret;
|
||||
int i;
|
||||
|
||||
BUG_ON(len > PAGE_SIZE);
|
||||
BUG_ON(len > PAGE_SIZE * FSIF_NR_READ_GNTS);
|
||||
|
||||
/* Prepare request for the backend */
|
||||
back_req_id = reserve_fsif_request(import);
|
||||
@@ -268,18 +284,28 @@ ssize_t fs_read(struct fs_import *import, int fd, void *buf,
|
||||
priv_req_id = get_id_from_freelist(import->freelist);
|
||||
DEBUG("Request id for fs_read call is: %d\n", priv_req_id);
|
||||
fsr = &import->requests[priv_req_id];
|
||||
DEBUG("gref=%d\n", fsr->gref);
|
||||
fsr->thread = current;
|
||||
memset(fsr->page, 0, PAGE_SIZE);
|
||||
|
||||
req = RING_GET_REQUEST(&import->ring, back_req_id);
|
||||
req->type = REQ_FILE_READ;
|
||||
req->id = priv_req_id;
|
||||
req->u.fread.fd = fd;
|
||||
req->u.fread.gref = fsr->gref;
|
||||
req->u.fread.len = len;
|
||||
req->u.fread.offset = offset;
|
||||
|
||||
|
||||
ASSERT(len > 0);
|
||||
gnts.count = ((len - 1) / PAGE_SIZE) + 1;
|
||||
for(i=0; i<gnts.count; i++)
|
||||
{
|
||||
gnts.pages[i] = (void *)alloc_page();
|
||||
gnts.grefs[i] = gnttab_grant_access(import->dom_id,
|
||||
virt_to_mfn(gnts.pages[i]),
|
||||
0);
|
||||
memset(gnts.pages[i], 0, PAGE_SIZE);
|
||||
req->u.fread.grefs[i] = gnts.grefs[i];
|
||||
}
|
||||
fsr->thread = current;
|
||||
|
||||
/* Set blocked flag before commiting the request, thus avoiding missed
|
||||
* response race */
|
||||
block(current);
|
||||
@@ -290,7 +316,19 @@ ssize_t fs_read(struct fs_import *import, int fd, void *buf,
|
||||
ret = (ssize_t)fsr->shadow_rsp.ret_val;
|
||||
DEBUG("The following ret value returned %d\n", ret);
|
||||
if(ret > 0)
|
||||
memcpy(buf, fsr->page, ret);
|
||||
{
|
||||
ssize_t to_copy = ret, current_copy;
|
||||
for(i=0; i<gnts.count; i++)
|
||||
{
|
||||
gnttab_end_access(gnts.grefs[i]);
|
||||
current_copy = to_copy > PAGE_SIZE ? PAGE_SIZE : to_copy;
|
||||
if(current_copy > 0)
|
||||
memcpy(buf, gnts.pages[i], current_copy);
|
||||
to_copy -= current_copy;
|
||||
buf = (char*) buf + current_copy;
|
||||
free_page(gnts.pages[i]);
|
||||
}
|
||||
}
|
||||
add_id_to_freelist(priv_req_id, import->freelist);
|
||||
|
||||
return ret;
|
||||
@@ -301,11 +339,13 @@ ssize_t fs_write(struct fs_import *import, int fd, void *buf,
|
||||
{
|
||||
struct fs_request *fsr;
|
||||
unsigned short priv_req_id;
|
||||
struct fs_rw_gnts gnts;
|
||||
RING_IDX back_req_id;
|
||||
struct fsif_request *req;
|
||||
ssize_t ret;
|
||||
ssize_t ret, to_copy;
|
||||
int i;
|
||||
|
||||
BUG_ON(len > PAGE_SIZE);
|
||||
BUG_ON(len > PAGE_SIZE * FSIF_NR_WRITE_GNTS);
|
||||
|
||||
/* Prepare request for the backend */
|
||||
back_req_id = reserve_fsif_request(import);
|
||||
@@ -315,20 +355,35 @@ ssize_t fs_write(struct fs_import *import, int fd, void *buf,
|
||||
priv_req_id = get_id_from_freelist(import->freelist);
|
||||
DEBUG("Request id for fs_read call is: %d\n", priv_req_id);
|
||||
fsr = &import->requests[priv_req_id];
|
||||
DEBUG("gref=%d\n", fsr->gref);
|
||||
fsr->thread = current;
|
||||
memcpy(fsr->page, buf, len);
|
||||
BUG_ON(len > PAGE_SIZE);
|
||||
memset((char *)fsr->page + len, 0, PAGE_SIZE - len);
|
||||
|
||||
req = RING_GET_REQUEST(&import->ring, back_req_id);
|
||||
req->type = REQ_FILE_WRITE;
|
||||
req->id = priv_req_id;
|
||||
req->u.fwrite.fd = fd;
|
||||
req->u.fwrite.gref = fsr->gref;
|
||||
req->u.fwrite.len = len;
|
||||
req->u.fwrite.offset = offset;
|
||||
|
||||
ASSERT(len > 0);
|
||||
gnts.count = ((len - 1) / PAGE_SIZE) + 1;
|
||||
to_copy = len;
|
||||
for(i=0; i<gnts.count; i++)
|
||||
{
|
||||
int current_copy = (to_copy > PAGE_SIZE ? PAGE_SIZE : to_copy);
|
||||
gnts.pages[i] = (void *)alloc_page();
|
||||
gnts.grefs[i] = gnttab_grant_access(import->dom_id,
|
||||
virt_to_mfn(gnts.pages[i]),
|
||||
0);
|
||||
memcpy(gnts.pages[i], buf, current_copy);
|
||||
if(current_copy < PAGE_SIZE)
|
||||
memset((char *)gnts.pages[i] + current_copy,
|
||||
0,
|
||||
PAGE_SIZE - current_copy);
|
||||
req->u.fwrite.grefs[i] = gnts.grefs[i];
|
||||
to_copy -= current_copy;
|
||||
buf = (char*) buf + current_copy;
|
||||
}
|
||||
fsr->thread = current;
|
||||
|
||||
/* Set blocked flag before commiting the request, thus avoiding missed
|
||||
* response race */
|
||||
block(current);
|
||||
@@ -338,6 +393,11 @@ ssize_t fs_write(struct fs_import *import, int fd, void *buf,
|
||||
/* Read the response */
|
||||
ret = (ssize_t)fsr->shadow_rsp.ret_val;
|
||||
DEBUG("The following ret value returned %d\n", ret);
|
||||
for(i=0; i<gnts.count; i++)
|
||||
{
|
||||
gnttab_end_access(gnts.grefs[i]);
|
||||
free_page(gnts.pages[i]);
|
||||
}
|
||||
add_id_to_freelist(priv_req_id, import->freelist);
|
||||
|
||||
return ret;
|
||||
@@ -361,15 +421,12 @@ int fs_stat(struct fs_import *import,
|
||||
priv_req_id = get_id_from_freelist(import->freelist);
|
||||
DEBUG("Request id for fs_stat call is: %d\n", priv_req_id);
|
||||
fsr = &import->requests[priv_req_id];
|
||||
DEBUG("gref=%d\n", fsr->gref);
|
||||
fsr->thread = current;
|
||||
memset(fsr->page, 0, PAGE_SIZE);
|
||||
|
||||
req = RING_GET_REQUEST(&import->ring, back_req_id);
|
||||
req->type = REQ_STAT;
|
||||
req->id = priv_req_id;
|
||||
req->u.fstat.fd = fd;
|
||||
req->u.fstat.gref = fsr->gref;
|
||||
|
||||
/* Set blocked flag before commiting the request, thus avoiding missed
|
||||
* response race */
|
||||
@@ -380,7 +437,9 @@ int fs_stat(struct fs_import *import,
|
||||
/* Read the response */
|
||||
ret = (int)fsr->shadow_rsp.ret_val;
|
||||
DEBUG("Following ret from fstat: %d\n", ret);
|
||||
memcpy(stat, fsr->page, sizeof(struct fsif_stat_response));
|
||||
memcpy(stat,
|
||||
&fsr->shadow_rsp.fstat,
|
||||
sizeof(struct fsif_stat_response));
|
||||
add_id_to_freelist(priv_req_id, import->freelist);
|
||||
|
||||
return ret;
|
||||
@@ -430,6 +489,8 @@ int fs_remove(struct fs_import *import, char *file)
|
||||
{
|
||||
struct fs_request *fsr;
|
||||
unsigned short priv_req_id;
|
||||
grant_ref_t gref;
|
||||
void *buffer;
|
||||
RING_IDX back_req_id;
|
||||
struct fsif_request *req;
|
||||
int ret;
|
||||
@@ -442,14 +503,15 @@ int fs_remove(struct fs_import *import, char *file)
|
||||
priv_req_id = get_id_from_freelist(import->freelist);
|
||||
DEBUG("Request id for fs_open call is: %d\n", priv_req_id);
|
||||
fsr = &import->requests[priv_req_id];
|
||||
DEBUG("gref=%d\n", fsr->gref);
|
||||
buffer = alloc_buffer_page(fsr, import->dom_id, &gref);
|
||||
DEBUG("gref=%d\n", gref);
|
||||
fsr->thread = current;
|
||||
sprintf(fsr->page, "%s", file);
|
||||
sprintf(buffer, "%s", file);
|
||||
|
||||
req = RING_GET_REQUEST(&import->ring, back_req_id);
|
||||
req->type = REQ_REMOVE;
|
||||
req->id = priv_req_id;
|
||||
req->u.fremove.gref = fsr->gref;
|
||||
req->u.fremove.gref = gref;
|
||||
|
||||
/* Set blocked flag before commiting the request, thus avoiding missed
|
||||
* response race */
|
||||
@@ -460,6 +522,7 @@ int fs_remove(struct fs_import *import, char *file)
|
||||
/* Read the response */
|
||||
ret = (int)fsr->shadow_rsp.ret_val;
|
||||
DEBUG("The following ret: %d\n", ret);
|
||||
free_buffer_page(fsr);
|
||||
add_id_to_freelist(priv_req_id, import->freelist);
|
||||
|
||||
return ret;
|
||||
@@ -472,6 +535,8 @@ int fs_rename(struct fs_import *import,
|
||||
{
|
||||
struct fs_request *fsr;
|
||||
unsigned short priv_req_id;
|
||||
grant_ref_t gref;
|
||||
void *buffer;
|
||||
RING_IDX back_req_id;
|
||||
struct fsif_request *req;
|
||||
int ret;
|
||||
@@ -486,15 +551,16 @@ int fs_rename(struct fs_import *import,
|
||||
priv_req_id = get_id_from_freelist(import->freelist);
|
||||
DEBUG("Request id for fs_open call is: %d\n", priv_req_id);
|
||||
fsr = &import->requests[priv_req_id];
|
||||
DEBUG("gref=%d\n", fsr->gref);
|
||||
buffer = alloc_buffer_page(fsr, import->dom_id, &gref);
|
||||
DEBUG("gref=%d\n", gref);
|
||||
fsr->thread = current;
|
||||
sprintf(fsr->page, "%s%s%c%s%s",
|
||||
sprintf(buffer, "%s%s%c%s%s",
|
||||
old_header, old_file_name, '\0', new_header, new_file_name);
|
||||
|
||||
req = RING_GET_REQUEST(&import->ring, back_req_id);
|
||||
req->type = REQ_RENAME;
|
||||
req->id = priv_req_id;
|
||||
req->u.frename.gref = fsr->gref;
|
||||
req->u.frename.gref = gref;
|
||||
req->u.frename.old_name_offset = strlen(old_header);
|
||||
req->u.frename.new_name_offset = strlen(old_header) +
|
||||
strlen(old_file_name) +
|
||||
@@ -511,6 +577,7 @@ int fs_rename(struct fs_import *import,
|
||||
/* Read the response */
|
||||
ret = (int)fsr->shadow_rsp.ret_val;
|
||||
DEBUG("The following ret: %d\n", ret);
|
||||
free_buffer_page(fsr);
|
||||
add_id_to_freelist(priv_req_id, import->freelist);
|
||||
|
||||
return ret;
|
||||
@@ -521,6 +588,8 @@ int fs_create(struct fs_import *import, char *name,
|
||||
{
|
||||
struct fs_request *fsr;
|
||||
unsigned short priv_req_id;
|
||||
grant_ref_t gref;
|
||||
void *buffer;
|
||||
RING_IDX back_req_id;
|
||||
struct fsif_request *req;
|
||||
int ret;
|
||||
@@ -533,14 +602,15 @@ int fs_create(struct fs_import *import, char *name,
|
||||
priv_req_id = get_id_from_freelist(import->freelist);
|
||||
DEBUG("Request id for fs_create call is: %d\n", priv_req_id);
|
||||
fsr = &import->requests[priv_req_id];
|
||||
DEBUG("gref=%d\n", fsr->gref);
|
||||
buffer = alloc_buffer_page(fsr, import->dom_id, &gref);
|
||||
DEBUG("gref=%d\n", gref);
|
||||
fsr->thread = current;
|
||||
sprintf(fsr->page, "%s", name);
|
||||
sprintf(buffer, "%s", name);
|
||||
|
||||
req = RING_GET_REQUEST(&import->ring, back_req_id);
|
||||
req->type = REQ_CREATE;
|
||||
req->id = priv_req_id;
|
||||
req->u.fcreate.gref = fsr->gref;
|
||||
req->u.fcreate.gref = gref;
|
||||
req->u.fcreate.directory = directory;
|
||||
req->u.fcreate.mode = mode;
|
||||
|
||||
@@ -553,6 +623,7 @@ int fs_create(struct fs_import *import, char *name,
|
||||
/* Read the response */
|
||||
ret = (int)fsr->shadow_rsp.ret_val;
|
||||
DEBUG("The following ret: %d\n", ret);
|
||||
free_buffer_page(fsr);
|
||||
add_id_to_freelist(priv_req_id, import->freelist);
|
||||
|
||||
return ret;
|
||||
@@ -563,6 +634,8 @@ char** fs_list(struct fs_import *import, char *name,
|
||||
{
|
||||
struct fs_request *fsr;
|
||||
unsigned short priv_req_id;
|
||||
grant_ref_t gref;
|
||||
void *buffer;
|
||||
RING_IDX back_req_id;
|
||||
struct fsif_request *req;
|
||||
char **files, *current_file;
|
||||
@@ -579,14 +652,15 @@ char** fs_list(struct fs_import *import, char *name,
|
||||
priv_req_id = get_id_from_freelist(import->freelist);
|
||||
DEBUG("Request id for fs_list call is: %d\n", priv_req_id);
|
||||
fsr = &import->requests[priv_req_id];
|
||||
DEBUG("gref=%d\n", fsr->gref);
|
||||
buffer = alloc_buffer_page(fsr, import->dom_id, &gref);
|
||||
DEBUG("gref=%d\n", gref);
|
||||
fsr->thread = current;
|
||||
sprintf(fsr->page, "%s", name);
|
||||
sprintf(buffer, "%s", name);
|
||||
|
||||
req = RING_GET_REQUEST(&import->ring, back_req_id);
|
||||
req->type = REQ_DIR_LIST;
|
||||
req->id = priv_req_id;
|
||||
req->u.flist.gref = fsr->gref;
|
||||
req->u.flist.gref = gref;
|
||||
req->u.flist.offset = offset;
|
||||
|
||||
/* Set blocked flag before commiting the request, thus avoiding missed
|
||||
@@ -600,7 +674,7 @@ char** fs_list(struct fs_import *import, char *name,
|
||||
files = NULL;
|
||||
if(*nr_files <= 0) goto exit;
|
||||
files = malloc(sizeof(char*) * (*nr_files));
|
||||
current_file = fsr->page;
|
||||
current_file = buffer;
|
||||
for(i=0; i<*nr_files; i++)
|
||||
{
|
||||
files[i] = strdup(current_file);
|
||||
@@ -608,6 +682,7 @@ char** fs_list(struct fs_import *import, char *name,
|
||||
}
|
||||
if(has_more != NULL)
|
||||
*has_more = fsr->shadow_rsp.ret_val & HAS_MORE_FLAG;
|
||||
free_buffer_page(fsr);
|
||||
add_id_to_freelist(priv_req_id, import->freelist);
|
||||
exit:
|
||||
return files;
|
||||
@@ -655,6 +730,8 @@ int64_t fs_space(struct fs_import *import, char *location)
|
||||
{
|
||||
struct fs_request *fsr;
|
||||
unsigned short priv_req_id;
|
||||
grant_ref_t gref;
|
||||
void *buffer;
|
||||
RING_IDX back_req_id;
|
||||
struct fsif_request *req;
|
||||
int64_t ret;
|
||||
@@ -667,14 +744,15 @@ int64_t fs_space(struct fs_import *import, char *location)
|
||||
priv_req_id = get_id_from_freelist(import->freelist);
|
||||
DEBUG("Request id for fs_space is: %d\n", priv_req_id);
|
||||
fsr = &import->requests[priv_req_id];
|
||||
DEBUG("gref=%d\n", fsr->gref);
|
||||
buffer = alloc_buffer_page(fsr, import->dom_id, &gref);
|
||||
DEBUG("gref=%d\n", gref);
|
||||
fsr->thread = current;
|
||||
sprintf(fsr->page, "%s", location);
|
||||
sprintf(buffer, "%s", location);
|
||||
|
||||
req = RING_GET_REQUEST(&import->ring, back_req_id);
|
||||
req->type = REQ_FS_SPACE;
|
||||
req->id = priv_req_id;
|
||||
req->u.fspace.gref = fsr->gref;
|
||||
req->u.fspace.gref = gref;
|
||||
|
||||
/* Set blocked flag before commiting the request, thus avoiding missed
|
||||
* response race */
|
||||
@@ -685,6 +763,7 @@ int64_t fs_space(struct fs_import *import, char *location)
|
||||
/* Read the response */
|
||||
ret = (int64_t)fsr->shadow_rsp.ret_val;
|
||||
DEBUG("The following returned: %lld\n", ret);
|
||||
free_buffer_page(fsr);
|
||||
add_id_to_freelist(priv_req_id, import->freelist);
|
||||
|
||||
return ret;
|
||||
@@ -732,6 +811,23 @@ int fs_sync(struct fs_import *import, int fd)
|
||||
/* END OF INDIVIDUAL FILE OPERATIONS */
|
||||
/******************************************************************************/
|
||||
|
||||
void *alloc_buffer_page(struct fs_request *req, domid_t domid, grant_ref_t *gref)
|
||||
{
|
||||
void *page;
|
||||
|
||||
page = (void *)alloc_page();
|
||||
*gref = gnttab_grant_access(domid, virt_to_mfn(page), 0);
|
||||
req->private1 = page;
|
||||
req->private2 = (void *)(uint64_t)(*gref);
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
void free_buffer_page(struct fs_request *req)
|
||||
{
|
||||
gnttab_end_access((grant_ref_t)(uint64_t)req->private2);
|
||||
free_page(req->private1);
|
||||
}
|
||||
|
||||
static void fsfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
|
||||
{
|
||||
@@ -797,15 +893,7 @@ static void alloc_request_table(struct fs_import *import)
|
||||
import->freelist = xmalloc_array(unsigned short, import->nr_entries + 1);
|
||||
memset(import->freelist, 0, sizeof(unsigned short) * (import->nr_entries + 1));
|
||||
for(i=0; i<import->nr_entries; i++)
|
||||
{
|
||||
/* TODO: that's a lot of memory */
|
||||
requests[i].page = (void *)alloc_page();
|
||||
requests[i].gref = gnttab_grant_access(import->dom_id,
|
||||
virt_to_mfn(requests[i].page),
|
||||
0);
|
||||
//printk(" ===>> Page=%lx, gref=%d, mfn=%lx\n", requests[i].page, requests[i].gref, virt_to_mfn(requests[i].page));
|
||||
add_id_to_freelist(i, import->freelist);
|
||||
}
|
||||
import->requests = requests;
|
||||
}
|
||||
|
||||
@@ -818,22 +906,27 @@ static void alloc_request_table(struct fs_import *import)
|
||||
void test_fs_import(void *data)
|
||||
{
|
||||
struct fs_import *import = (struct fs_import *)data;
|
||||
int ret, fd, i;
|
||||
int ret, fd, i, repeat_count;
|
||||
int32_t nr_files;
|
||||
char buffer[1024];
|
||||
ssize_t offset;
|
||||
char **files;
|
||||
long ret64;
|
||||
|
||||
struct fsif_stat_response stat;
|
||||
|
||||
repeat_count = 10;
|
||||
/* Sleep for 1s and then try to open a file */
|
||||
msleep(1000);
|
||||
again:
|
||||
ret = fs_create(import, "mini-os-created-directory", 1, 0777);
|
||||
printk("Directory create: %d\n", ret);
|
||||
|
||||
ret = fs_create(import, "mini-os-created-directory/mini-os-created-file", 0, 0666);
|
||||
sprintf(buffer, "mini-os-created-directory/mini-os-created-file-%d",
|
||||
repeat_count);
|
||||
ret = fs_create(import, buffer, 0, 0666);
|
||||
printk("File create: %d\n", ret);
|
||||
|
||||
fd = fs_open(import, "mini-os-created-directory/mini-os-created-file");
|
||||
fd = fs_open(import, buffer);
|
||||
printk("File descriptor: %d\n", fd);
|
||||
if(fd < 0) return;
|
||||
|
||||
@@ -847,7 +940,16 @@ void test_fs_import(void *data)
|
||||
return;
|
||||
offset += ret;
|
||||
}
|
||||
|
||||
ret = fs_stat(import, fd, &stat);
|
||||
printk("Ret after stat: %d\n", ret);
|
||||
printk(" st_mode=%o\n", stat.stat_mode);
|
||||
printk(" st_uid =%d\n", stat.stat_uid);
|
||||
printk(" st_gid =%d\n", stat.stat_gid);
|
||||
printk(" st_size=%ld\n", stat.stat_size);
|
||||
printk(" st_atime=%ld\n", stat.stat_atime);
|
||||
printk(" st_mtime=%ld\n", stat.stat_mtime);
|
||||
printk(" st_ctime=%ld\n", stat.stat_ctime);
|
||||
|
||||
ret = fs_close(import, fd);
|
||||
printk("Closed fd: %d, ret=%d\n", fd, ret);
|
||||
|
||||
@@ -858,6 +960,9 @@ void test_fs_import(void *data)
|
||||
|
||||
ret64 = fs_space(import, "/");
|
||||
printk("Free space: %lld (=%lld Mb)\n", ret64, (ret64 >> 20));
|
||||
repeat_count--;
|
||||
if(repeat_count > 0)
|
||||
goto again;
|
||||
|
||||
}
|
||||
|
||||
@@ -924,20 +1029,21 @@ static int init_fs_import(struct fs_import *import)
|
||||
xenbus_transaction_t xbt;
|
||||
char nodename[1024], r_nodename[1024], token[128], *message = NULL;
|
||||
struct fsif_sring *sring;
|
||||
int retry = 0;
|
||||
int i, retry = 0;
|
||||
domid_t self_id;
|
||||
xenbus_event_queue events = NULL;
|
||||
|
||||
printk("Initialising FS fortend to backend dom %d\n", import->dom_id);
|
||||
/* Allocate page for the shared ring */
|
||||
sring = (struct fsif_sring*) alloc_page();
|
||||
memset(sring, 0, PAGE_SIZE);
|
||||
sring = (struct fsif_sring*) alloc_pages(FSIF_RING_SIZE_ORDER);
|
||||
memset(sring, 0, PAGE_SIZE * FSIF_RING_SIZE_PAGES);
|
||||
|
||||
/* Init the shared ring */
|
||||
SHARED_RING_INIT(sring);
|
||||
ASSERT(FSIF_NR_READ_GNTS == FSIF_NR_WRITE_GNTS);
|
||||
|
||||
/* Init private frontend ring */
|
||||
FRONT_RING_INIT(&import->ring, sring, PAGE_SIZE);
|
||||
FRONT_RING_INIT(&import->ring, sring, PAGE_SIZE * FSIF_RING_SIZE_PAGES);
|
||||
import->nr_entries = import->ring.nr_ents;
|
||||
|
||||
/* Allocate table of requests */
|
||||
@@ -945,7 +1051,11 @@ static int init_fs_import(struct fs_import *import)
|
||||
init_SEMAPHORE(&import->reqs_sem, import->nr_entries);
|
||||
|
||||
/* Grant access to the shared ring */
|
||||
import->gnt_ref = gnttab_grant_access(import->dom_id, virt_to_mfn(sring), 0);
|
||||
for(i=0; i<FSIF_RING_SIZE_PAGES; i++)
|
||||
import->gnt_refs[i] =
|
||||
gnttab_grant_access(import->dom_id,
|
||||
virt_to_mfn((char *)sring + i * PAGE_SIZE),
|
||||
0);
|
||||
|
||||
/* Allocate event channel */
|
||||
BUG_ON(evtchn_alloc_unbound(import->dom_id,
|
||||
@@ -969,13 +1079,27 @@ again:
|
||||
|
||||
err = xenbus_printf(xbt,
|
||||
nodename,
|
||||
"ring-ref",
|
||||
"ring-size",
|
||||
"%u",
|
||||
import->gnt_ref);
|
||||
FSIF_RING_SIZE_PAGES);
|
||||
if (err) {
|
||||
message = "writing ring-ref";
|
||||
message = "writing ring-size";
|
||||
goto abort_transaction;
|
||||
}
|
||||
|
||||
for(i=0; i<FSIF_RING_SIZE_PAGES; i++)
|
||||
{
|
||||
sprintf(r_nodename, "ring-ref-%d", i);
|
||||
err = xenbus_printf(xbt,
|
||||
nodename,
|
||||
r_nodename,
|
||||
"%u",
|
||||
import->gnt_refs[i]);
|
||||
if (err) {
|
||||
message = "writing ring-refs";
|
||||
goto abort_transaction;
|
||||
}
|
||||
}
|
||||
|
||||
err = xenbus_printf(xbt,
|
||||
nodename,
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
#include <mini-os/semaphore.h>
|
||||
#include <mini-os/types.h>
|
||||
|
||||
#define FSIF_RING_SIZE_ORDER 1
|
||||
#define FSIF_RING_SIZE_PAGES (1<<FSIF_RING_SIZE_ORDER)
|
||||
|
||||
struct fs_import
|
||||
{
|
||||
domid_t dom_id; /* dom id of the exporting domain */
|
||||
@@ -14,7 +17,7 @@ struct fs_import
|
||||
unsigned int nr_entries; /* Number of entries in rings & request
|
||||
array */
|
||||
struct fsif_front_ring ring; /* frontend ring (contains shared ring) */
|
||||
int gnt_ref; /* grant reference to the shared ring */
|
||||
u32 gnt_refs[FSIF_RING_SIZE_PAGES]; /* grant references to the shared ring */
|
||||
evtchn_port_t local_port; /* local event channel port */
|
||||
char *backend; /* XenBus location of the backend */
|
||||
struct fs_request *requests; /* Table of requests */
|
||||
|
||||
@@ -231,8 +231,8 @@ int read(int fd, void *buf, size_t nbytes)
|
||||
}
|
||||
case FTYPE_FILE: {
|
||||
ssize_t ret;
|
||||
if (nbytes > PAGE_SIZE)
|
||||
nbytes = PAGE_SIZE;
|
||||
if (nbytes > PAGE_SIZE * FSIF_NR_READ_GNTS)
|
||||
nbytes = PAGE_SIZE * FSIF_NR_READ_GNTS;
|
||||
ret = fs_read(fs_import, files[fd].file.fd, buf, nbytes, files[fd].file.offset);
|
||||
if (ret > 0) {
|
||||
files[fd].file.offset += ret;
|
||||
@@ -292,8 +292,8 @@ int write(int fd, const void *buf, size_t nbytes)
|
||||
return nbytes;
|
||||
case FTYPE_FILE: {
|
||||
ssize_t ret;
|
||||
if (nbytes > PAGE_SIZE)
|
||||
nbytes = PAGE_SIZE;
|
||||
if (nbytes > PAGE_SIZE * FSIF_NR_WRITE_GNTS)
|
||||
nbytes = PAGE_SIZE * FSIF_NR_WRITE_GNTS;
|
||||
ret = fs_write(fs_import, files[fd].file.fd, (void *) buf, nbytes, files[fd].file.offset);
|
||||
if (ret > 0) {
|
||||
files[fd].file.offset += ret;
|
||||
|
||||
@@ -147,7 +147,8 @@ moretodo:
|
||||
int i;
|
||||
struct fs_op *op;
|
||||
|
||||
printf("Got a request at %d\n", cons);
|
||||
printf("Got a request at %d (of %d)\n",
|
||||
cons, RING_SIZE(&mount->ring));
|
||||
req = RING_GET_REQUEST(&mount->ring, cons);
|
||||
printf("Request type=%d\n", req->type);
|
||||
for(i=0;;i++)
|
||||
@@ -198,6 +199,7 @@ static void handle_connection(int frontend_dom_id, int export_id, char *frontend
|
||||
int evt_port;
|
||||
pthread_t handling_thread;
|
||||
struct fsif_sring *sring;
|
||||
uint32_t dom_ids[MAX_RING_SIZE];
|
||||
int i;
|
||||
|
||||
printf("Handling connection from dom=%d, for export=%d\n",
|
||||
@@ -222,7 +224,7 @@ static void handle_connection(int frontend_dom_id, int export_id, char *frontend
|
||||
mount->mount_id = mount_id++;
|
||||
xenbus_read_mount_request(mount, frontend);
|
||||
printf("Frontend found at: %s (gref=%d, evtchn=%d)\n",
|
||||
mount->frontend, mount->gref, mount->remote_evtchn);
|
||||
mount->frontend, mount->grefs[0], mount->remote_evtchn);
|
||||
xenbus_write_backend_node(mount);
|
||||
mount->evth = -1;
|
||||
mount->evth = xc_evtchn_open();
|
||||
@@ -235,11 +237,15 @@ static void handle_connection(int frontend_dom_id, int export_id, char *frontend
|
||||
mount->gnth = -1;
|
||||
mount->gnth = xc_gnttab_open();
|
||||
assert(mount->gnth != -1);
|
||||
sring = xc_gnttab_map_grant_ref(mount->gnth,
|
||||
mount->dom_id,
|
||||
mount->gref,
|
||||
PROT_READ | PROT_WRITE);
|
||||
BACK_RING_INIT(&mount->ring, sring, XC_PAGE_SIZE);
|
||||
for(i=0; i<mount->shared_ring_size; i++)
|
||||
dom_ids[i] = mount->dom_id;
|
||||
sring = xc_gnttab_map_grant_refs(mount->gnth,
|
||||
mount->shared_ring_size,
|
||||
dom_ids,
|
||||
mount->grefs,
|
||||
PROT_READ | PROT_WRITE);
|
||||
|
||||
BACK_RING_INIT(&mount->ring, sring, mount->shared_ring_size * XC_PAGE_SIZE);
|
||||
mount->nr_entries = mount->ring.nr_ents;
|
||||
for (i = 0; i < MAX_FDS; i++)
|
||||
mount->fds[i] = -1;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#define EXPORTS_NODE ROOT_NODE"/"EXPORTS_SUBNODE
|
||||
#define WATCH_NODE EXPORTS_NODE"/requests"
|
||||
#define MAX_FDS 16
|
||||
#define MAX_RING_SIZE 16
|
||||
|
||||
struct fs_export
|
||||
{
|
||||
@@ -26,6 +27,7 @@ struct fs_request
|
||||
{
|
||||
int active;
|
||||
void *page; /* Pointer to mapped grant */
|
||||
int count;
|
||||
struct fsif_request req_shadow;
|
||||
struct aiocb aiocb;
|
||||
};
|
||||
@@ -37,11 +39,12 @@ struct fs_mount
|
||||
int dom_id;
|
||||
char *frontend;
|
||||
int mount_id; /* = backend id */
|
||||
grant_ref_t gref;
|
||||
grant_ref_t grefs[MAX_RING_SIZE];
|
||||
evtchn_port_t remote_evtchn;
|
||||
int evth; /* Handle to the event channel */
|
||||
evtchn_port_t local_evtchn;
|
||||
int gnth;
|
||||
int shared_ring_size; /* in pages */
|
||||
struct fsif_back_ring ring;
|
||||
int nr_entries;
|
||||
struct fs_request *requests;
|
||||
|
||||
+46
-40
@@ -123,19 +123,24 @@ static void dispatch_file_close(struct fs_mount *mount, struct fsif_request *req
|
||||
rsp->ret_val = (uint64_t)ret;
|
||||
}
|
||||
|
||||
#define MAX_GNTS 16
|
||||
static void dispatch_file_read(struct fs_mount *mount, struct fsif_request *req)
|
||||
{
|
||||
void *buf;
|
||||
int fd;
|
||||
int fd, i, count;
|
||||
uint16_t req_id;
|
||||
unsigned short priv_id;
|
||||
struct fs_request *priv_req;
|
||||
|
||||
/* Read the request */
|
||||
buf = xc_gnttab_map_grant_ref(mount->gnth,
|
||||
mount->dom_id,
|
||||
req->u.fread.gref,
|
||||
PROT_WRITE);
|
||||
assert(req->u.fread.len > 0);
|
||||
count = (req->u.fread.len - 1) / XC_PAGE_SIZE + 1;
|
||||
assert(count <= FSIF_NR_READ_GNTS);
|
||||
buf = xc_gnttab_map_domain_grant_refs(mount->gnth,
|
||||
count,
|
||||
mount->dom_id,
|
||||
req->u.fread.grefs,
|
||||
PROT_WRITE);
|
||||
|
||||
req_id = req->id;
|
||||
printf("File read issued for FD=%d (len=%"PRIu64", offest=%"PRIu64")\n",
|
||||
@@ -150,6 +155,7 @@ static void dispatch_file_read(struct fs_mount *mount, struct fsif_request *req)
|
||||
printf("Private id is: %d\n", priv_id);
|
||||
priv_req = &mount->requests[priv_id];
|
||||
priv_req->page = buf;
|
||||
priv_req->count = count;
|
||||
|
||||
/* Dispatch AIO read request */
|
||||
bzero(&priv_req->aiocb, sizeof(struct aiocb));
|
||||
@@ -172,7 +178,9 @@ static void end_file_read(struct fs_mount *mount, struct fs_request *priv_req)
|
||||
uint16_t req_id;
|
||||
|
||||
/* Release the grant */
|
||||
assert(xc_gnttab_munmap(mount->gnth, priv_req->page, 1) == 0);
|
||||
assert(xc_gnttab_munmap(mount->gnth,
|
||||
priv_req->page,
|
||||
priv_req->count) == 0);
|
||||
|
||||
/* Get a response from the ring */
|
||||
rsp_idx = mount->ring.rsp_prod_pvt++;
|
||||
@@ -186,16 +194,20 @@ static void end_file_read(struct fs_mount *mount, struct fs_request *priv_req)
|
||||
static void dispatch_file_write(struct fs_mount *mount, struct fsif_request *req)
|
||||
{
|
||||
void *buf;
|
||||
int fd;
|
||||
int fd, count, i;
|
||||
uint16_t req_id;
|
||||
unsigned short priv_id;
|
||||
struct fs_request *priv_req;
|
||||
|
||||
/* Read the request */
|
||||
buf = xc_gnttab_map_grant_ref(mount->gnth,
|
||||
mount->dom_id,
|
||||
req->u.fwrite.gref,
|
||||
PROT_READ);
|
||||
assert(req->u.fwrite.len > 0);
|
||||
count = (req->u.fwrite.len - 1) / XC_PAGE_SIZE + 1;
|
||||
assert(count <= FSIF_NR_WRITE_GNTS);
|
||||
buf = xc_gnttab_map_domain_grant_refs(mount->gnth,
|
||||
count,
|
||||
mount->dom_id,
|
||||
req->u.fwrite.grefs,
|
||||
PROT_READ);
|
||||
|
||||
req_id = req->id;
|
||||
printf("File write issued for FD=%d (len=%"PRIu64", offest=%"PRIu64")\n",
|
||||
@@ -210,6 +222,7 @@ static void dispatch_file_write(struct fs_mount *mount, struct fsif_request *req
|
||||
printf("Private id is: %d\n", priv_id);
|
||||
priv_req = &mount->requests[priv_id];
|
||||
priv_req->page = buf;
|
||||
priv_req->count = count;
|
||||
|
||||
/* Dispatch AIO write request */
|
||||
bzero(&priv_req->aiocb, sizeof(struct aiocb));
|
||||
@@ -232,7 +245,9 @@ static void end_file_write(struct fs_mount *mount, struct fs_request *priv_req)
|
||||
uint16_t req_id;
|
||||
|
||||
/* Release the grant */
|
||||
assert(xc_gnttab_munmap(mount->gnth, priv_req->page, 1) == 0);
|
||||
assert(xc_gnttab_munmap(mount->gnth,
|
||||
priv_req->page,
|
||||
priv_req->count) == 0);
|
||||
|
||||
/* Get a response from the ring */
|
||||
rsp_idx = mount->ring.rsp_prod_pvt++;
|
||||
@@ -252,12 +267,6 @@ static void dispatch_stat(struct fs_mount *mount, struct fsif_request *req)
|
||||
RING_IDX rsp_idx;
|
||||
fsif_response_t *rsp;
|
||||
|
||||
/* Read the request */
|
||||
buf = xc_gnttab_map_grant_ref(mount->gnth,
|
||||
mount->dom_id,
|
||||
req->u.fstat.gref,
|
||||
PROT_WRITE);
|
||||
|
||||
req_id = req->id;
|
||||
if (req->u.fstat.fd < MAX_FDS)
|
||||
fd = mount->fds[req->u.fstat.fd];
|
||||
@@ -273,34 +282,31 @@ static void dispatch_stat(struct fs_mount *mount, struct fsif_request *req)
|
||||
/* Stat, and create the response */
|
||||
ret = fstat(fd, &stat);
|
||||
printf("Mode=%o, uid=%d, a_time=%ld\n",
|
||||
stat.st_mode, stat.st_uid, (long)stat.st_atime);
|
||||
buf->stat_mode = stat.st_mode;
|
||||
buf->stat_uid = stat.st_uid;
|
||||
buf->stat_gid = stat.st_gid;
|
||||
#ifdef BLKGETSIZE
|
||||
if (S_ISBLK(stat.st_mode)) {
|
||||
unsigned long sectors;
|
||||
if (ioctl(fd, BLKGETSIZE, §ors)) {
|
||||
perror("getting device size\n");
|
||||
buf->stat_size = 0;
|
||||
} else
|
||||
buf->stat_size = sectors << 9;
|
||||
} else
|
||||
#endif
|
||||
buf->stat_size = stat.st_size;
|
||||
buf->stat_atime = stat.st_atime;
|
||||
buf->stat_mtime = stat.st_mtime;
|
||||
buf->stat_ctime = stat.st_ctime;
|
||||
|
||||
/* Release the grant */
|
||||
assert(xc_gnttab_munmap(mount->gnth, buf, 1) == 0);
|
||||
stat.st_mode, stat.st_uid, stat.st_atime);
|
||||
|
||||
/* Get a response from the ring */
|
||||
rsp_idx = mount->ring.rsp_prod_pvt++;
|
||||
printf("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
|
||||
rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
|
||||
rsp->id = req_id;
|
||||
rsp->ret_val = (uint64_t)ret;
|
||||
rsp->fstat.stat_ret = (uint32_t)ret;
|
||||
rsp->fstat.stat_mode = stat.st_mode;
|
||||
rsp->fstat.stat_uid = stat.st_uid;
|
||||
rsp->fstat.stat_gid = stat.st_gid;
|
||||
#ifdef BLKGETSIZE
|
||||
if (S_ISBLK(stat.st_mode)) {
|
||||
unsigned long sectors;
|
||||
if (ioctl(fd, BLKGETSIZE, §ors)) {
|
||||
perror("getting device size\n");
|
||||
rsp->fstat.stat_size = 0;
|
||||
} else
|
||||
rsp->fstat.stat_size = sectors << 9;
|
||||
} else
|
||||
#endif
|
||||
rsp->fstat.stat_size = stat.st_size;
|
||||
rsp->fstat.stat_atime = stat.st_atime;
|
||||
rsp->fstat.stat_mtime = stat.st_mtime;
|
||||
rsp->fstat.stat_ctime = stat.st_ctime;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -113,6 +113,7 @@ void xenbus_read_mount_request(struct fs_mount *mount, char *frontend)
|
||||
{
|
||||
char node[1024];
|
||||
char *s;
|
||||
int i;
|
||||
|
||||
assert(xsh != NULL);
|
||||
#if 0
|
||||
@@ -125,10 +126,18 @@ void xenbus_read_mount_request(struct fs_mount *mount, char *frontend)
|
||||
s = xs_read(xsh, XBT_NULL, node, NULL);
|
||||
assert(strcmp(s, STATE_READY) == 0);
|
||||
free(s);
|
||||
snprintf(node, sizeof(node), "%s/ring-ref", frontend);
|
||||
snprintf(node, sizeof(node), "%s/ring-size", frontend);
|
||||
s = xs_read(xsh, XBT_NULL, node, NULL);
|
||||
mount->gref = atoi(s);
|
||||
mount->shared_ring_size = atoi(s);
|
||||
assert(mount->shared_ring_size <= MAX_RING_SIZE);
|
||||
free(s);
|
||||
for(i=0; i<mount->shared_ring_size; i++)
|
||||
{
|
||||
snprintf(node, sizeof(node), "%s/ring-ref-%d", frontend, i);
|
||||
s = xs_read(xsh, XBT_NULL, node, NULL);
|
||||
mount->grefs[i] = atoi(s);
|
||||
free(s);
|
||||
}
|
||||
snprintf(node, sizeof(node), "%s/event-channel", frontend);
|
||||
s = xs_read(xsh, XBT_NULL, node, NULL);
|
||||
mount->remote_evtchn = atoi(s);
|
||||
|
||||
@@ -54,30 +54,31 @@ struct fsif_close_request {
|
||||
|
||||
struct fsif_read_request {
|
||||
uint32_t fd;
|
||||
grant_ref_t gref;
|
||||
int32_t pad;
|
||||
uint64_t len;
|
||||
uint64_t offset;
|
||||
grant_ref_t grefs[1]; /* Variable length */
|
||||
};
|
||||
|
||||
struct fsif_write_request {
|
||||
uint32_t fd;
|
||||
grant_ref_t gref;
|
||||
int32_t pad;
|
||||
uint64_t len;
|
||||
uint64_t offset;
|
||||
grant_ref_t grefs[1]; /* Variable length */
|
||||
};
|
||||
|
||||
struct fsif_stat_request {
|
||||
uint32_t fd;
|
||||
grant_ref_t gref;
|
||||
};
|
||||
|
||||
/* This structure is a copy of some fields from stat structure, writen to the
|
||||
* granted page. */
|
||||
/* This structure is a copy of some fields from stat structure, returned
|
||||
* via the ring. */
|
||||
struct fsif_stat_response {
|
||||
int32_t stat_mode;
|
||||
uint32_t stat_uid;
|
||||
uint32_t stat_gid;
|
||||
int32_t pad;
|
||||
int32_t stat_ret;
|
||||
int64_t stat_size;
|
||||
int64_t stat_atime;
|
||||
int64_t stat_mtime;
|
||||
@@ -165,11 +166,20 @@ struct fsif_response {
|
||||
uint16_t id;
|
||||
uint16_t pad1;
|
||||
uint32_t pad2;
|
||||
uint64_t ret_val;
|
||||
union {
|
||||
uint64_t ret_val;
|
||||
struct fsif_stat_response fstat;
|
||||
};
|
||||
};
|
||||
|
||||
typedef struct fsif_response fsif_response_t;
|
||||
|
||||
#define FSIF_RING_ENTRY_SIZE 64
|
||||
|
||||
#define FSIF_NR_READ_GNTS ((FSIF_RING_ENTRY_SIZE - sizeof(struct fsif_read_request)) / \
|
||||
sizeof(grant_ref_t) + 1)
|
||||
#define FSIF_NR_WRITE_GNTS ((FSIF_RING_ENTRY_SIZE - sizeof(struct fsif_write_request)) / \
|
||||
sizeof(grant_ref_t) + 1)
|
||||
|
||||
DEFINE_RING_TYPES(fsif, struct fsif_request, struct fsif_response);
|
||||
|
||||
|
||||