aboutsummaryrefslogtreecommitdiffstats
path: root/extras
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2008-01-18 13:33:37 +0000
committerKeir Fraser <keir.fraser@citrix.com>2008-01-18 13:33:37 +0000
commitbe33e2333ab84639e7e4277b5a9bf59a605ed870 (patch)
tree13eecb9faffefe28653d41552d105a8ebbe2c570 /extras
parent9d220744e67413bc17df9fbfcebe33ad663207a6 (diff)
downloadxen-be33e2333ab84639e7e4277b5a9bf59a605ed870.tar.gz
xen-be33e2333ab84639e7e4277b5a9bf59a605ed870.tar.bz2
xen-be33e2333ab84639e7e4277b5a9bf59a605ed870.zip
Add FS backend/frontend drivers (frontend in minios only).
Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com> Signed-off-by: Grzegorz Milos <gm281@cam.ac.uk>
Diffstat (limited to 'extras')
-rw-r--r--extras/mini-os/fs-front.c1129
-rw-r--r--extras/mini-os/include/fs.h51
-rw-r--r--extras/mini-os/include/types.h3
-rw-r--r--extras/mini-os/kernel.c7
4 files changed, 1190 insertions, 0 deletions
diff --git a/extras/mini-os/fs-front.c b/extras/mini-os/fs-front.c
new file mode 100644
index 0000000000..fcef1de2fb
--- /dev/null
+++ b/extras/mini-os/fs-front.c
@@ -0,0 +1,1129 @@
+/******************************************************************************
+ * fs-front.c
+ *
+ * Frontend driver for FS split device driver.
+ *
+ * Copyright (c) 2007, Grzegorz Milos, Sun Microsystems, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#undef NDEBUG
+#include <os.h>
+#include <list.h>
+#include <xmalloc.h>
+#include <xenbus.h>
+#include <gnttab.h>
+#include <events.h>
+#include <xen/io/fsif.h>
+#include <fs.h>
+#include <sched.h>
+
+#define preempt_disable()
+#define preempt_enable()
+#define cmpxchg(p,o,n) synch_cmpxchg(p,o,n)
+
+
+#ifdef FS_DEBUG
+#define DEBUG(_f, _a...) \
+ printk("MINI_OS(file=fs-front.c, line=%d) " _f "\n", __LINE__, ## _a)
+#else
+#define DEBUG(_f, _a...) ((void)0)
+#endif
+
+
+struct fs_request;
+struct fs_import *fs_import;
+
+/******************************************************************************/
+/* RING REQUEST/RESPONSES HANDLING */
+/******************************************************************************/
+
+struct fs_request
+{
+ void *page;
+ grant_ref_t gref;
+ struct thread *thread; /* Thread blocked on this request */
+ struct fsif_response shadow_rsp; /* Response copy writen by the
+ interrupt handler */
+};
+
+/* 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
+ * defined in ring.h is not allowed, in particular:
+ * RING_PUSH_REQUESTS_AND_CHECK_NOTIFY cannot be used.
+ *
+ * The protocol used for FSIF ring is described below:
+ *
+ * In order to reserve a request the frontend:
+ * a) saves current frontend_ring->req_prod_pvt into a local variable
+ * b) checks that there are free request using the local req_prod_pvt
+ * c) tries to reserve the request using cmpxchg on frontend_ring->req_prod_pvt
+ * if cmpxchg fails, it means that someone reserved the request, start from
+ * a)
+ *
+ * In order to commit a request to the shared ring:
+ * a) cmpxchg shared_ring->req_prod from local req_prod_pvt to req_prod_pvt+1
+ * Loop if unsuccessful.
+ * NOTE: Request should be commited to the shared ring as quickly as possible,
+ * because otherwise other threads might busy loop trying to commit next
+ * requests. It also follows that preemption should be disabled, if
+ * possible, for the duration of the request construction.
+ */
+
+/* Number of free requests (for use on front side only). */
+#define FS_RING_FREE_REQUESTS(_r, _req_prod_pvt) \
+ (RING_SIZE(_r) - (_req_prod_pvt - (_r)->rsp_cons))
+
+
+
+static RING_IDX reserve_fsif_request(struct fs_import *import)
+{
+ RING_IDX idx;
+
+ down(&import->reqs_sem);
+ preempt_disable();
+again:
+ /* We will attempt to reserve slot idx */
+ idx = import->ring.req_prod_pvt;
+ ASSERT (FS_RING_FREE_REQUESTS(&import->ring, idx));
+ /* Attempt to reserve */
+ if(cmpxchg(&import->ring.req_prod_pvt, idx, idx+1) != idx)
+ goto again;
+
+ return idx;
+}
+
+static void commit_fsif_request(struct fs_import *import, RING_IDX idx)
+{
+ while(cmpxchg(&import->ring.sring->req_prod, idx, idx+1) != idx)
+ {
+ printk("Failed to commit a request: req_prod=%d, idx=%d\n",
+ import->ring.sring->req_prod, idx);
+ }
+ preempt_enable();
+
+ /* NOTE: we cannot do anything clever about rsp_event, to hold off
+ * notifications, because we don't know if we are a single request (in which
+ * case we have to notify always), or a part of a larger request group
+ * (when, in some cases, notification isn't required) */
+ notify_remote_via_evtchn(import->local_port);
+}
+
+
+
+static inline void add_id_to_freelist(unsigned int id,unsigned short* freelist)
+{
+ unsigned int old_id, new_id;
+
+again:
+ old_id = freelist[0];
+ /* Note: temporal inconsistency, since freelist[0] can be changed by someone
+ * else, but we are a sole owner of freelist[id], it's OK. */
+ freelist[id] = old_id;
+ new_id = id;
+ if(cmpxchg(&freelist[0], old_id, new_id) != old_id)
+ {
+ printk("Cmpxchg on freelist add failed.\n");
+ goto again;
+ }
+}
+
+/* always call reserve_fsif_request(import) before this, to protect from
+ * depletion. */
+static inline unsigned short get_id_from_freelist(unsigned short* freelist)
+{
+ unsigned int old_id, new_id;
+
+again:
+ old_id = freelist[0];
+ new_id = freelist[old_id];
+ if(cmpxchg(&freelist[0], old_id, new_id) != old_id)
+ {
+ printk("Cmpxchg on freelist remove failed.\n");
+ goto again;
+ }
+
+ return old_id;
+}
+
+/******************************************************************************/
+/* END OF RING REQUEST/RESPONSES HANDLING */
+/******************************************************************************/
+
+
+
+/******************************************************************************/
+/* INDIVIDUAL FILE OPERATIONS */
+/******************************************************************************/
+int fs_open(struct fs_import *import, char *file)
+{
+ struct fs_request *fsr;
+ unsigned short priv_req_id;
+ RING_IDX back_req_id;
+ struct fsif_request *req;
+ int fd;
+
+ /* Prepare request for the backend */
+ back_req_id = reserve_fsif_request(import);
+ DEBUG("Backend request id=%d, gref=%d\n", back_req_id, fsr->gref);
+
+ /* Prepare our private request structure */
+ 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];
+ fsr->thread = current;
+ sprintf(fsr->page, "%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;
+
+ /* Set blocked flag before commiting the request, thus avoiding missed
+ * response race */
+ block(current);
+ commit_fsif_request(import, back_req_id);
+ schedule();
+
+ /* Read the response */
+ fd = (int)fsr->shadow_rsp.ret_val;
+ DEBUG("The following FD returned: %d\n", fd);
+ add_id_to_freelist(priv_req_id, import->freelist);
+
+ return fd;
+}
+
+int fs_close(struct fs_import *import, int fd)
+{
+ struct fs_request *fsr;
+ unsigned short priv_req_id;
+ RING_IDX back_req_id;
+ struct fsif_request *req;
+ int ret;
+
+ /* Prepare request for the backend */
+ back_req_id = reserve_fsif_request(import);
+ DEBUG("Backend request id=%d, gref=%d\n", back_req_id, fsr->gref);
+
+ /* Prepare our private request structure */
+ priv_req_id = get_id_from_freelist(import->freelist);
+ DEBUG("Request id for fs_close call is: %d\n", priv_req_id);
+ fsr = &import->requests[priv_req_id];
+ fsr->thread = current;
+
+ req = RING_GET_REQUEST(&import->ring, back_req_id);
+ req->type = REQ_FILE_CLOSE;
+ req->id = priv_req_id;
+ req->u.fclose.fd = fd;
+
+ /* Set blocked flag before commiting the request, thus avoiding missed
+ * response race */
+ block(current);
+ commit_fsif_request(import, back_req_id);
+ schedule();
+
+ /* Read the response */
+ ret = (int)fsr->shadow_rsp.ret_val;
+ DEBUG("Close returned: %d\n", ret);
+ add_id_to_freelist(priv_req_id, import->freelist);
+
+ return ret;
+}
+
+ssize_t fs_read(struct fs_import *import, int fd, void *buf,
+ ssize_t len, ssize_t offset)
+{
+ struct fs_request *fsr;
+ unsigned short priv_req_id;
+ RING_IDX back_req_id;
+ struct fsif_request *req;
+ ssize_t ret;
+
+ BUG_ON(len > PAGE_SIZE);
+
+ /* Prepare request for the backend */
+ back_req_id = reserve_fsif_request(import);
+ DEBUG("Backend request id=%d, gref=%d\n", back_req_id, fsr->gref);
+
+ /* Prepare our private request structure */
+ 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];
+ 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;
+
+ /* Set blocked flag before commiting the request, thus avoiding missed
+ * response race */
+ block(current);
+ commit_fsif_request(import, back_req_id);
+ schedule();
+
+ /* Read the response */
+ 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);
+ add_id_to_freelist(priv_req_id, import->freelist);
+
+ return ret;
+}
+
+ssize_t fs_write(struct fs_import *import, int fd, void *buf,
+ ssize_t len, ssize_t offset)
+{
+ struct fs_request *fsr;
+ unsigned short priv_req_id;
+ RING_IDX back_req_id;
+ struct fsif_request *req;
+ ssize_t ret;
+
+ BUG_ON(len > PAGE_SIZE);
+
+ /* Prepare request for the backend */
+ back_req_id = reserve_fsif_request(import);
+ DEBUG("Backend request id=%d, gref=%d\n", back_req_id, fsr->gref);
+
+ /* Prepare our private request structure */
+ 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];
+ 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;
+
+ /* Set blocked flag before commiting the request, thus avoiding missed
+ * response race */
+ block(current);
+ commit_fsif_request(import, back_req_id);
+ schedule();
+
+ /* Read the response */
+ ret = (ssize_t)fsr->shadow_rsp.ret_val;
+ DEBUG("The following ret value returned %d\n", ret);
+ add_id_to_freelist(priv_req_id, import->freelist);
+
+ return ret;
+}
+
+int fs_stat(struct fs_import *import,
+ int fd,
+ struct fsif_stat_response *stat)
+{
+ struct fs_request *fsr;
+ unsigned short priv_req_id;
+ RING_IDX back_req_id;
+ struct fsif_request *req;
+ int ret;
+
+ /* Prepare request for the backend */
+ back_req_id = reserve_fsif_request(import);
+ DEBUG("Backend request id=%d, gref=%d\n", back_req_id, fsr->gref);
+
+ /* Prepare our private request structure */
+ 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];
+ 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 */
+ block(current);
+ commit_fsif_request(import, back_req_id);
+ schedule();
+
+ /* 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));
+ add_id_to_freelist(priv_req_id, import->freelist);
+
+ return ret;
+}
+
+int fs_truncate(struct fs_import *import,
+ int fd,
+ int64_t length)
+{
+ struct fs_request *fsr;
+ unsigned short priv_req_id;
+ RING_IDX back_req_id;
+ struct fsif_request *req;
+ int ret;
+
+ /* Prepare request for the backend */
+ back_req_id = reserve_fsif_request(import);
+ DEBUG("Backend request id=%d, gref=%d\n", back_req_id, fsr->gref);
+
+ /* Prepare our private request structure */
+ priv_req_id = get_id_from_freelist(import->freelist);
+ DEBUG("Request id for fs_truncate call is: %d\n", priv_req_id);
+ fsr = &import->requests[priv_req_id];
+ fsr->thread = current;
+
+ req = RING_GET_REQUEST(&import->ring, back_req_id);
+ req->type = REQ_FILE_TRUNCATE;
+ req->id = priv_req_id;
+ req->u.ftruncate.fd = fd;
+ req->u.ftruncate.length = length;
+
+ /* Set blocked flag before commiting the request, thus avoiding missed
+ * response race */
+ block(current);
+ commit_fsif_request(import, back_req_id);
+ schedule();
+
+ /* Read the response */
+ ret = (int)fsr->shadow_rsp.ret_val;
+ DEBUG("Following ret from ftruncate: %d\n", ret);
+ add_id_to_freelist(priv_req_id, import->freelist);
+
+ return ret;
+}
+
+int fs_remove(struct fs_import *import, char *file)
+{
+ struct fs_request *fsr;
+ unsigned short priv_req_id;
+ RING_IDX back_req_id;
+ struct fsif_request *req;
+ int ret;
+
+ /* Prepare request for the backend */
+ back_req_id = reserve_fsif_request(import);
+ DEBUG("Backend request id=%d, gref=%d\n", back_req_id, fsr->gref);
+
+ /* Prepare our private request structure */
+ 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];
+ fsr->thread = current;
+ sprintf(fsr->page, "%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;
+
+ /* Set blocked flag before commiting the request, thus avoiding missed
+ * response race */
+ block(current);
+ commit_fsif_request(import, back_req_id);
+ schedule();
+
+ /* Read the response */
+ ret = (int)fsr->shadow_rsp.ret_val;
+ DEBUG("The following ret: %d\n", ret);
+ add_id_to_freelist(priv_req_id, import->freelist);
+
+ return ret;
+}
+
+
+int fs_rename(struct fs_import *import,
+ char *old_file_name,
+ char *new_file_name)
+{
+ struct fs_request *fsr;
+ unsigned short priv_req_id;
+ RING_IDX back_req_id;
+ struct fsif_request *req;
+ int ret;
+ char old_header[] = "old: ";
+ char new_header[] = "new: ";
+
+ /* Prepare request for the backend */
+ back_req_id = reserve_fsif_request(import);
+ DEBUG("Backend request id=%d, gref=%d\n", back_req_id, fsr->gref);
+
+ /* Prepare our private request structure */
+ 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];
+ fsr->thread = current;
+ sprintf(fsr->page, "%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.old_name_offset = strlen(old_header);
+ req->u.frename.new_name_offset = strlen(old_header) +
+ strlen(old_file_name) +
+ strlen(new_header) +
+ 1 /* Accouning for the additional
+ end of string character */;
+
+ /* Set blocked flag before commiting the request, thus avoiding missed
+ * response race */
+ block(current);
+ commit_fsif_request(import, back_req_id);
+ schedule();
+
+ /* Read the response */
+ ret = (int)fsr->shadow_rsp.ret_val;
+ DEBUG("The following ret: %d\n", ret);
+ add_id_to_freelist(priv_req_id, import->freelist);
+
+ return ret;
+}
+
+int fs_create(struct fs_import *import, char *name,
+ int8_t directory, int32_t mode)
+{
+ struct fs_request *fsr;
+ unsigned short priv_req_id;
+ RING_IDX back_req_id;
+ struct fsif_request *req;
+ int ret;
+
+ /* Prepare request for the backend */
+ back_req_id = reserve_fsif_request(import);
+ DEBUG("Backend request id=%d, gref=%d\n", back_req_id, fsr->gref);
+
+ /* Prepare our private request structure */
+ 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];
+ fsr->thread = current;
+ sprintf(fsr->page, "%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.directory = directory;
+ req->u.fcreate.mode = mode;
+
+ /* Set blocked flag before commiting the request, thus avoiding missed
+ * response race */
+ block(current);
+ commit_fsif_request(import, back_req_id);
+ schedule();
+
+ /* Read the response */
+ ret = (int)fsr->shadow_rsp.ret_val;
+ DEBUG("The following ret: %d\n", ret);
+ add_id_to_freelist(priv_req_id, import->freelist);
+
+ return ret;
+}
+
+char** fs_list(struct fs_import *import, char *name,
+ int32_t offset, int32_t *nr_files, int *has_more)
+{
+ struct fs_request *fsr;
+ unsigned short priv_req_id;
+ RING_IDX back_req_id;
+ struct fsif_request *req;
+ char **files, *current_file;
+ int i;
+
+ DEBUG("Different masks: NR_FILES=(%llx, %d), ERROR=(%llx, %d), HAS_MORE(%llx, %d)\n",
+ NR_FILES_MASK, NR_FILES_SHIFT, ERROR_MASK, ERROR_SHIFT, HAS_MORE_FLAG, HAS_MORE_SHIFT);
+
+ /* Prepare request for the backend */
+ back_req_id = reserve_fsif_request(import);
+ DEBUG("Backend request id=%d, gref=%d\n", back_req_id, fsr->gref);
+
+ /* Prepare our private request structure */
+ 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];
+ fsr->thread = current;
+ sprintf(fsr->page, "%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.offset = offset;
+
+ /* Set blocked flag before commiting the request, thus avoiding missed
+ * response race */
+ block(current);
+ commit_fsif_request(import, back_req_id);
+ schedule();
+
+ /* Read the response */
+ *nr_files = (fsr->shadow_rsp.ret_val & NR_FILES_MASK) >> NR_FILES_SHIFT;
+ files = NULL;
+ if(*nr_files <= 0) goto exit;
+ files = malloc(sizeof(char*) * (*nr_files));
+ current_file = fsr->page;
+ for(i=0; i<*nr_files; i++)
+ {
+ files[i] = strdup(current_file);
+ current_file += strlen(current_file) + 1;
+ }
+ if(has_more != NULL)
+ *has_more = fsr->shadow_rsp.ret_val & HAS_MORE_FLAG;
+ add_id_to_freelist(priv_req_id, import->freelist);
+exit:
+ return files;
+}
+
+int fs_chmod(struct fs_import *import, int fd, int32_t mode)
+{
+ struct fs_request *fsr;
+ unsigned short priv_req_id;
+ RING_IDX back_req_id;
+ struct fsif_request *req;
+ int ret;
+
+ /* Prepare request for the backend */
+ back_req_id = reserve_fsif_request(import);
+ DEBUG("Backend request id=%d, gref=%d\n", back_req_id, fsr->gref);
+
+ /* Prepare our private request structure */
+ priv_req_id = get_id_from_freelist(import->freelist);
+ DEBUG("Request id for fs_chmod call is: %d\n", priv_req_id);
+ fsr = &import->requests[priv_req_id];
+ fsr->thread = current;
+
+ req = RING_GET_REQUEST(&import->ring, back_req_id);
+ req->type = REQ_CHMOD;
+ req->id = priv_req_id;
+ req->u.fchmod.fd = fd;
+ req->u.fchmod.mode = mode;
+
+ /* Set blocked flag before commiting the request, thus avoiding missed
+ * response race */
+ block(current);
+ commit_fsif_request(import, back_req_id);
+ schedule();
+
+ /* Read the response */
+ ret = (int)fsr->shadow_rsp.ret_val;
+ DEBUG("The following returned: %d\n", ret);
+ add_id_to_freelist(priv_req_id, import->freelist);
+
+ return ret;
+}
+
+int64_t fs_space(struct fs_import *import, char *location)
+{
+ struct fs_request *fsr;
+ unsigned short priv_req_id;
+ RING_IDX back_req_id;
+ struct fsif_request *req;
+ int64_t ret;
+
+ /* Prepare request for the backend */
+ back_req_id = reserve_fsif_request(import);
+ DEBUG("Backend request id=%d, gref=%d\n", back_req_id, fsr->gref);
+
+ /* Prepare our private request structure */
+ 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];
+ fsr->thread = current;
+ sprintf(fsr->page, "%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;
+
+ /* Set blocked flag before commiting the request, thus avoiding missed
+ * response race */
+ block(current);
+ commit_fsif_request(import, back_req_id);
+ schedule();
+
+ /* Read the response */
+ ret = (int64_t)fsr->shadow_rsp.ret_val;
+ DEBUG("The following returned: %lld\n", ret);
+ add_id_to_freelist(priv_req_id, import->freelist);
+
+ return ret;
+}
+
+int fs_sync(struct fs_import *import, int fd)
+{
+ struct fs_request *fsr;
+ unsigned short priv_req_id;
+ RING_IDX back_req_id;
+ struct fsif_request *req;
+ int ret;
+
+ /* Prepare request for the backend */
+ back_req_id = reserve_fsif_request(import);
+ DEBUG("Backend request id=%d, gref=%d\n", back_req_id, fsr->gref);
+
+ /* Prepare our private request structure */
+ priv_req_id = get_id_from_freelist(import->freelist);
+ DEBUG("Request id for fs_sync call is: %d\n", priv_req_id);
+ fsr = &import->requests[priv_req_id];
+ fsr->thread = current;
+
+ req = RING_GET_REQUEST(&import->ring, back_req_id);
+ req->type = REQ_FILE_SYNC;
+ req->id = priv_req_id;
+ req->u.fsync.fd = fd;
+
+ /* Set blocked flag before commiting the request, thus avoiding missed
+ * response race */
+ block(current);
+ commit_fsif_request(import, back_req_id);
+ schedule();
+
+ /* Read the response */
+ ret = (int)fsr->shadow_rsp.ret_val;
+ DEBUG("Close returned: %d\n", ret);
+ add_id_to_freelist(priv_req_id, import->freelist);
+
+ return ret;
+}
+
+
+/******************************************************************************/
+/* END OF INDIVIDUAL FILE OPERATIONS */
+/******************************************************************************/
+
+
+static void fsfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
+{
+ struct fs_import *import = (struct fs_import*)data;
+ static int in_irq = 0;
+ RING_IDX cons, rp;
+ int more;
+
+ /* Check for non-reentrance */
+ BUG_ON(in_irq);
+ in_irq = 1;
+
+ DEBUG("Event from import [%d:%d].\n", import->dom_id, import->export_id);
+moretodo:
+ rp = import->ring.sring->req_prod;
+ rmb(); /* Ensure we see queued responses up to 'rp'. */
+ cons = import->ring.rsp_cons;
+ while (cons != rp)
+ {
+ struct fsif_response *rsp;
+ struct fs_request *req;
+
+ rsp = RING_GET_RESPONSE(&import->ring, cons);
+ DEBUG("Response at idx=%d to request id=%d, ret_val=%lx\n",
+ import->ring.rsp_cons, rsp->id, rsp->ret_val);
+ req = &import->requests[rsp->id];
+ memcpy(&req->shadow_rsp, rsp, sizeof(struct fsif_response));
+ DEBUG("Waking up: %s\n", req->thread->name);
+ wake(req->thread);
+
+ cons++;
+ up(&import->reqs_sem);
+ }
+
+ import->ring.rsp_cons = rp;
+ RING_FINAL_CHECK_FOR_RESPONSES(&import->ring, more);
+ if(more) goto moretodo;
+
+ in_irq = 0;
+}
+
+/* Small utility function to figure out our domain id */
+static domid_t get_self_id(void)
+{
+ char *dom_id;
+ domid_t ret;
+
+ BUG_ON(xenbus_read(XBT_NIL, "domid", &dom_id));
+ sscanf(dom_id, "%d", &ret);
+
+ return ret;
+}
+
+static void alloc_request_table(struct fs_import *import)
+{
+ struct fs_request *requests;
+ int i;
+
+ BUG_ON(import->nr_entries <= 0);
+ printk("Allocating request array for import %d, nr_entries = %d.\n",
+ import->import_id, import->nr_entries);
+ requests = xmalloc_array(struct fs_request, import->nr_entries);
+ import->freelist = xmalloc_array(unsigned short, import->nr_entries);
+ memset(import->freelist, 0, sizeof(unsigned short) * import->nr_entries);
+ 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;
+}
+
+
+/******************************************************************************/
+/* FS TESTS */
+/******************************************************************************/
+
+
+void test_fs_import(void *data)
+{
+ struct fs_import *import = (struct fs_import *)data;
+ int ret, fd, i;
+ int32_t nr_files;
+ char buffer[1024];
+ ssize_t offset;
+ char **files;
+ long ret64;
+
+ /* Sleep for 1s and then try to open a file */
+ sleep(1000);
+ 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);
+ printk("File create: %d\n", ret);
+
+ fd = fs_open(import, "mini-os-created-directory/mini-os-created-file");
+ printk("File descriptor: %d\n", fd);
+ if(fd < 0) return;
+
+ offset = 0;
+ for(i=0; i<10; i++)
+ {
+ sprintf(buffer, "Current time is: %lld\n", NOW());
+ ret = fs_write(import, fd, buffer, strlen(buffer), offset);
+ printk("Writen current time (%d)\n", ret);
+ if(ret < 0)
+ return;
+ offset += ret;
+ }
+
+ ret = fs_close(import, fd);
+ printk("Closed fd: %d, ret=%d\n", fd, ret);
+
+ printk("Listing files in /\n");
+ files = fs_list(import, "/", 0, &nr_files, NULL);
+ for(i=0; i<nr_files; i++)
+ printk(" files[%d] = %s\n", i, files[i]);
+
+ ret64 = fs_space(import, "/");
+ printk("Free space: %lld (=%lld Mb)\n", ret64, (ret64 >> 20));
+
+}
+
+#if 0
+// char *content = (char *)alloc_page();
+ int fd, ret;
+// int read;
+ char write_string[] = "\"test data written from minios\"";
+ struct fsif_stat_response stat;
+ char **files;
+ int32_t nr_files, i;
+ int64_t ret64;
+
+
+ fd = fs_open(import, "test-export-file");
+// read = fs_read(import, fd, content, PAGE_SIZE, 0);
+// printk("Read: %d bytes\n", read);
+// content[read] = '\0';
+// printk("Value: %s\n", content);
+ ret = fs_write(import, fd, write_string, strlen(write_string), 0);
+ printk("Ret after write: %d\n", 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_truncate(import, fd, 30);
+ printk("Ret after truncate: %d\n", ret);
+ ret = fs_remove(import, "test-to-remove/test-file");
+ printk("Ret after remove: %d\n", ret);
+ ret = fs_remove(import, "test-to-remove");
+ printk("Ret after remove: %d\n", ret);
+ ret = fs_chmod(import, fd, 0700);
+ printk("Ret after chmod: %d\n", ret);
+ ret = fs_sync(import, fd);
+ printk("Ret after sync: %d\n", ret);
+ ret = fs_close(import, fd);
+ //ret = fs_rename(import, "test-export-file", "renamed-test-export-file");
+ //printk("Ret after rename: %d\n", ret);
+ ret = fs_create(import, "created-dir", 1, 0777);
+ printk("Ret after dir create: %d\n", ret);
+ ret = fs_create(import, "created-dir/created-file", 0, 0777);
+ printk("Ret after file create: %d\n", ret);
+ files = fs_list(import, "/", 15, &nr_files, NULL);
+ for(i=0; i<nr_files; i++)
+ printk(" files[%d] = %s\n", i, files[i]);
+ ret64 = fs_space(import, "created-dir");
+ printk("Ret after space: %lld\n", ret64);
+
+#endif
+
+
+/******************************************************************************/
+/* END OF FS TESTS */
+/******************************************************************************/
+
+static int init_fs_import(struct fs_import *import)
+{
+ char *err;
+ xenbus_transaction_t xbt;
+ char nodename[1024], r_nodename[1024], token[128], *message = NULL;
+ struct fsif_sring *sring;
+ int retry = 0;
+ domid_t self_id;
+
+ 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);
+
+ /* Init the shared ring */
+ SHARED_RING_INIT(sring);
+
+ /* Init private frontend ring */
+ FRONT_RING_INIT(&import->ring, sring, PAGE_SIZE);
+ import->nr_entries = import->ring.nr_ents;
+
+ /* Allocate table of requests */
+ alloc_request_table(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);
+
+ /* Allocate event channel */
+ BUG_ON(evtchn_alloc_unbound(import->dom_id,
+ fsfront_handler,
+ //ANY_CPU,
+ import,
+ &import->local_port));
+
+
+ self_id = get_self_id();
+ /* Write the frontend info to a node in our Xenbus */
+ sprintf(nodename, "/local/domain/%d/device/vfs/%d",
+ self_id, import->import_id);
+
+again:
+ err = xenbus_transaction_start(&xbt);
+ if (err) {
+ printk("starting transaction\n");
+ }
+
+ err = xenbus_printf(xbt,
+ nodename,
+ "ring-ref",
+ "%u",
+ import->gnt_ref);
+ if (err) {
+ message = "writing ring-ref";
+ goto abort_transaction;
+ }
+
+ err = xenbus_printf(xbt,
+ nodename,
+ "event-channel",
+ "%u",
+ import->local_port);
+ if (err) {
+ message = "writing event-channel";
+ goto abort_transaction;
+ }
+
+ err = xenbus_printf(xbt, nodename, "state", STATE_READY, 0xdeadbeef);
+
+
+ err = xenbus_transaction_end(xbt, 0, &retry);
+ if (retry) {
+ goto again;
+ printk("completing transaction\n");
+ }
+
+ /* Now, when our node is prepared we write request in the exporting domain
+ * */
+ printk("Our own id is %d\n", self_id);
+ sprintf(r_nodename,
+ "/local/domain/%d/backend/vfs/exports/requests/%d/%d/frontend",
+ import->dom_id, self_id, import->export_id);
+ BUG_ON(xenbus_write(XBT_NIL, r_nodename, nodename));
+
+ goto done;
+
+abort_transaction:
+ xenbus_transaction_end(xbt, 1, &retry);
+
+done:
+
+#define WAIT_PERIOD 10 /* Wait period in ms */
+#define MAX_WAIT 10 /* Max number of WAIT_PERIODs */
+ import->backend = NULL;
+ sprintf(r_nodename, "%s/backend", nodename);
+
+ for(retry = MAX_WAIT; retry > 0; retry--)
+ {
+ xenbus_read(XBT_NIL, r_nodename, &import->backend);
+ if(import->backend)
+ {
+ printk("Backend found at %s\n", import->backend);
+ break;
+ }
+ sleep(WAIT_PERIOD);
+ }
+
+ if(!import->backend)
+ {
+ printk("No backend available.\n");
+ /* TODO - cleanup datastructures/xenbus */
+ return 0;
+ }
+ sprintf(r_nodename, "%s/state", import->backend);
+ sprintf(token, "fs-front-%d", import->import_id);
+ /* The token will not be unique if multiple imports are inited */
+ xenbus_watch_path(XBT_NIL, r_nodename/*, token*/);
+ xenbus_wait_for_value(/*token,*/ r_nodename, STATE_READY);
+ printk("Backend ready.\n");
+
+ //create_thread("fs-tester", test_fs_import, import);
+
+ return 1;
+}
+
+static void add_export(struct list_head *exports, unsigned int domid)
+{
+ char node[1024], **exports_list = NULL, *ret_msg;
+ int j = 0;
+ static int import_id = 0;
+
+ sprintf(node, "/local/domain/%d/backend/vfs/exports", domid);
+ ret_msg = xenbus_ls(XBT_NIL, node, &exports_list);
+ if (ret_msg && strcmp(ret_msg, "ENOENT"))
+ printk("couldn't read %s: %s\n", node, ret_msg);
+ while(exports_list && exports_list[j])
+ {
+ struct fs_import *import;
+ int export_id = -1;
+
+ sscanf(exports_list[j], "%d", &export_id);
+ if(export_id >= 0)
+ {
+ import = xmalloc(struct fs_import);
+ import->dom_id = domid;
+ import->export_id = export_id;
+ import->import_id = import_id++;
+ INIT_LIST_HEAD(&import->list);
+ list_add(&import->list, exports);
+ }
+ free(exports_list[j]);
+ j++;
+ }
+ if(exports_list)
+ free(exports_list);
+ if(ret_msg)
+ free(ret_msg);
+}
+
+#if 0
+static struct list_head* probe_exports(void)
+{
+ struct list_head *exports;
+ char **node_list = NULL, *msg = NULL;
+ int i = 0;
+
+ exports = xmalloc(struct list_head);
+ INIT_LIST_HEAD(exports);
+
+ msg = xenbus_ls(XBT_NIL, "/local/domain", &node_list);
+ if(msg)
+ {
+ printk("Could not list VFS exports (%s).\n", msg);
+ goto exit;
+ }
+
+ while(node_list[i])
+ {
+ add_export(exports, atoi(node_list[i]));
+ free(node_list[i]);
+ i++;
+ }
+
+exit:
+ if(msg)
+ free(msg);
+ if(node_list)
+ free(node_list);
+ return exports;
+}
+#endif
+
+LIST_HEAD(exports);
+
+void init_fs_frontend(void)
+{
+ struct list_head *entry;
+ struct fs_import *import = NULL;
+ printk("Initing FS fronend(s).\n");
+
+ //exports = probe_exports();
+ add_export(&exports, 0);
+ list_for_each(entry, &exports)
+ {
+ import = list_entry(entry, struct fs_import, list);
+ printk("FS export [dom=%d, id=%d] found\n",
+ import->dom_id, import->export_id);
+ init_fs_import(import);
+ }
+
+ fs_import = import;
+
+ if (!fs_import) {
+ printk("No FS import\n");
+ sleep(1000);
+ do_exit();
+ }
+}
diff --git a/extras/mini-os/include/fs.h b/extras/mini-os/include/fs.h
new file mode 100644
index 0000000000..1e144b4e6d
--- /dev/null
+++ b/extras/mini-os/include/fs.h
@@ -0,0 +1,51 @@
+#ifndef __FS_H__
+#define __FS_H__
+
+#include <xen/io/fsif.h>
+#include <semaphore.h>
+
+struct fs_import
+{
+ domid_t dom_id; /* dom id of the exporting domain */
+ u16 export_id; /* export id (exporting dom specific) */
+ u16 import_id; /* import id (specific to this domain) */
+ struct list_head list; /* list of all imports */
+ 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 */
+ evtchn_port_t local_port; /* local event channel port */
+ char *backend; /* XenBus location of the backend */
+ struct fs_request *requests; /* Table of requests */
+ unsigned short *freelist; /* List of free request ids */
+ struct semaphore reqs_sem; /* Accounts requests resource */
+};
+
+
+void init_fs_frontend(void);
+
+int fs_open(struct fs_import *import, char *file);
+int fs_close(struct fs_import *import, int fd);
+ssize_t fs_read(struct fs_import *import, int fd, void *buf,
+ ssize_t len, ssize_t offset);
+ssize_t fs_write(struct fs_import *import, int fd, void *buf,
+ ssize_t len, ssize_t offset);
+int fs_stat(struct fs_import *import,
+ int fd,
+ struct fsif_stat_response *stat);
+int fs_truncate(struct fs_import *import,
+ int fd,
+ int64_t length);
+int fs_remove(struct fs_import *import, char *file);
+int fs_rename(struct fs_import *import,
+ char *old_file_name,
+ char *new_file_name);
+int fs_create(struct fs_import *import, char *name,
+ int8_t directory, int32_t mode);
+char** fs_list(struct fs_import *import, char *name,
+ int32_t offset, int32_t *nr_files, int *has_more);
+int fs_chmod(struct fs_import *import, int fd, int32_t mode);
+int64_t fs_space(struct fs_import *import, char *location);
+int fs_sync(struct fs_import *import, int fd);
+
+#endif
diff --git a/extras/mini-os/include/types.h b/extras/mini-os/include/types.h
index f0b67607c3..d1b23c3a64 100644
--- a/extras/mini-os/include/types.h
+++ b/extras/mini-os/include/types.h
@@ -69,4 +69,7 @@ typedef s64 int64_t;
#define INT_MAX ((int)(~0U>>1))
#define UINT_MAX (~0U)
+
+typedef long ssize_t;
+typedef unsigned long size_t;
#endif /* _TYPES_H_ */
diff --git a/extras/mini-os/kernel.c b/extras/mini-os/kernel.c
index 095f38cd6a..9d18b22e1b 100644
--- a/extras/mini-os/kernel.c
+++ b/extras/mini-os/kernel.c
@@ -38,6 +38,7 @@
#include <xenbus.h>
#include <gnttab.h>
#include <netfront.h>
+#include <fs.h>
#include <xen/features.h>
#include <xen/version.h>
@@ -85,6 +86,11 @@ static void netfront_thread(void *p)
init_netfront(NULL, NULL, NULL);
}
+static void fs_thread(void *p)
+{
+ init_fs_frontend();
+}
+
/* This should be overridden by the application we are linked against. */
__attribute__((weak)) int app_main(start_info_t *si)
{
@@ -92,6 +98,7 @@ __attribute__((weak)) int app_main(start_info_t *si)
create_thread("xenbus_tester", xenbus_tester, si);
create_thread("periodic_thread", periodic_thread, si);
create_thread("netfront", netfront_thread, si);
+ create_thread("fs-frontend", fs_thread, si);
return 0;
}