aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2008-08-01 09:37:10 +0100
committerKeir Fraser <keir.fraser@citrix.com>2008-08-01 09:37:10 +0100
commite5ba23a1d98db4e433a5edc85eb3242298cd3275 (patch)
tree985a178f2764181d516898f665588926682a402b
parentee449f80fde4a9bd323209f61a734bf88753c752 (diff)
downloadxen-e5ba23a1d98db4e433a5edc85eb3242298cd3275.tar.gz
xen-e5ba23a1d98db4e433a5edc85eb3242298cd3275.tar.bz2
xen-e5ba23a1d98db4e433a5edc85eb3242298cd3275.zip
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>
-rw-r--r--extras/mini-os/fs-front.c244
-rw-r--r--extras/mini-os/include/fs.h5
-rw-r--r--extras/mini-os/lib/sys.c8
-rw-r--r--tools/fs-back/fs-backend.c20
-rw-r--r--tools/fs-back/fs-backend.h5
-rw-r--r--tools/fs-back/fs-ops.c82
-rw-r--r--tools/fs-back/fs-xenbus.c13
-rw-r--r--xen/include/public/io/fsif.h24
8 files changed, 281 insertions, 120 deletions
diff --git a/extras/mini-os/fs-front.c b/extras/mini-os/fs-front.c
index f199c348a5..a14699f014 100644
--- a/extras/mini-os/fs-front.c
+++ b/extras/mini-os/fs-front.c
@@ -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,
diff --git a/extras/mini-os/include/fs.h b/extras/mini-os/include/fs.h
index d60f0c964b..cd8262e54d 100644
--- a/extras/mini-os/include/fs.h
+++ b/extras/mini-os/include/fs.h
@@ -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 */
diff --git a/extras/mini-os/lib/sys.c b/extras/mini-os/lib/sys.c
index 517562d3af..457bde3c8d 100644
--- a/extras/mini-os/lib/sys.c
+++ b/extras/mini-os/lib/sys.c
@@ -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;
diff --git a/tools/fs-back/fs-backend.c b/tools/fs-back/fs-backend.c
index 14c48ba967..f0d2758627 100644
--- a/tools/fs-back/fs-backend.c
+++ b/tools/fs-back/fs-backend.c
@@ -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;
diff --git a/tools/fs-back/fs-backend.h b/tools/fs-back/fs-backend.h
index 2999a60f32..b2a6be6f4a 100644
--- a/tools/fs-back/fs-backend.h
+++ b/tools/fs-back/fs-backend.h
@@ -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;
diff --git a/tools/fs-back/fs-ops.c b/tools/fs-back/fs-ops.c
index de6c4a6456..f8d1f9908f 100644
--- a/tools/fs-back/fs-ops.c
+++ b/tools/fs-back/fs-ops.c
@@ -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;
+ 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->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, &sectors)) {
perror("getting device size\n");
- buf->stat_size = 0;
+ rsp->fstat.stat_size = 0;
} else
- buf->stat_size = sectors << 9;
+ rsp->fstat.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);
-
- /* 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_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;
}
diff --git a/tools/fs-back/fs-xenbus.c b/tools/fs-back/fs-xenbus.c
index 552ebf5ca6..6a86e245e0 100644
--- a/tools/fs-back/fs-xenbus.c
+++ b/tools/fs-back/fs-xenbus.c
@@ -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);
diff --git a/xen/include/public/io/fsif.h b/xen/include/public/io/fsif.h
index 0e1bc822b5..04ef928464 100644
--- a/xen/include/public/io/fsif.h
+++ b/xen/include/public/io/fsif.h
@@ -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);