* [PATCH] [UPDATE] fs-backend fixes and improvements
@ 2009-03-16 11:25 Stefano Stabellini
2009-03-17 10:51 ` Keir Fraser
0 siblings, 1 reply; 5+ messages in thread
From: Stefano Stabellini @ 2009-03-16 11:25 UTC (permalink / raw)
To: xen-devel
Hi all,
this patch is an updated version of the previous patch I sent to fix
the issues that currently affect fs-backend.
Compared to the previous version this patch is more resilient to errors
because it is not using sigprocmask anymore to block SIGUSR2: blocking
signals doesn't get along very well with glibc's aio implementation.
Secondly I also introduced explicit error checking on the select return
value, trying to recover in case of errors.
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
diff -r 0e1449d6f231 tools/fs-back/Makefile
--- a/tools/fs-back/Makefile Fri Mar 13 10:09:25 2009 +0000
+++ b/tools/fs-back/Makefile Mon Mar 16 11:23:36 2009 +0000
@@ -16,7 +16,7 @@
LIBS := -L. -L.. -L../lib
LIBS += $(LDFLAGS_libxenctrl)
LIBS += $(LDFLAGS_libxenstore)
-LIBS += -lpthread -lrt
+LIBS += -lrt
OBJS := fs-xenbus.o fs-ops.o
diff -r 0e1449d6f231 tools/fs-back/fs-backend.c
--- a/tools/fs-back/fs-backend.c Fri Mar 13 10:09:25 2009 +0000
+++ b/tools/fs-back/fs-backend.c Mon Mar 16 11:23:36 2009 +0000
@@ -3,105 +3,71 @@
#include <string.h>
#include <assert.h>
#include <malloc.h>
-#include <pthread.h>
#include <xenctrl.h>
#include <aio.h>
#include <sys/mman.h>
#include <sys/select.h>
+#include <sys/socket.h>
#include <xen/io/ring.h>
+#include <err.h>
+#include "sys-queue.h"
#include "fs-backend.h"
+#include "fs-debug.h"
struct xs_handle *xsh = NULL;
static struct fs_export *fs_exports = NULL;
static int export_id = 0;
static int mount_id = 0;
+static int pipefds[2];
+static LIST_HEAD(mount_requests_head, fs_mount) mount_requests_head;
-static void dispatch_response(struct fs_mount *mount, int priv_req_id)
+static void free_mount_request(struct fs_mount *mount);
+
+static void dispatch_response(struct fs_request *request)
{
int i;
struct fs_op *op;
- struct fs_request *req = &mount->requests[priv_req_id];
for(i=0;;i++)
{
op = fsops[i];
/* We should dispatch a response before reaching the end of the array */
assert(op != NULL);
- if(op->type == req->req_shadow.type)
+ if(op->type == request->req_shadow.type)
{
- printf("Found op for type=%d\n", op->type);
+ FS_DEBUG("Found op for type=%d\n", op->type);
/* There needs to be a response handler */
assert(op->response_handler != NULL);
- op->response_handler(mount, req);
+ op->response_handler(request->mount, request);
break;
}
}
- req->active = 0;
- add_id_to_freelist(priv_req_id, mount->freelist);
+ request->active = 0;
+ add_id_to_freelist(request->id, request->mount->freelist);
}
-static void handle_aio_events(struct fs_mount *mount)
+static void handle_aio_event(struct fs_request *request)
{
- int fd, ret, count, i, notify;
- evtchn_port_t port;
- /* AIO control block for the evtchn file destriptor */
- struct aiocb evtchn_cb;
- const struct aiocb * cb_list[mount->nr_entries];
- int request_ids[mount->nr_entries];
+ int ret, notify;
- /* Prepare the AIO control block for evtchn */
- fd = xc_evtchn_fd(mount->evth);
- bzero(&evtchn_cb, sizeof(struct aiocb));
- evtchn_cb.aio_fildes = fd;
- evtchn_cb.aio_nbytes = sizeof(port);
- evtchn_cb.aio_buf = &port;
- assert(aio_read(&evtchn_cb) == 0);
+ FS_DEBUG("handle_aio_event: mount %s request %d\n", request->mount->frontend, request->id);
+ if (request->active < 0) {
+ request->mount->nr_entries++;
+ if (!request->mount->nr_entries)
+ free_mount_request(request->mount);
+ return;
+ }
-wait_again:
- /* Create list of active AIO requests */
- count = 0;
- for(i=0; i<mount->nr_entries; i++)
- if(mount->requests[i].active)
- {
- cb_list[count] = &mount->requests[i].aiocb;
- request_ids[count] = i;
- count++;
- }
- /* Add the event channel at the end of the list. Event channel needs to be
- * handled last as it exits this function. */
- cb_list[count] = &evtchn_cb;
- request_ids[count] = -1;
- count++;
+ ret = aio_error(&request->aiocb);
+ if(ret != EINPROGRESS && ret != ECANCELED)
+ dispatch_response(request);
- /* Block till an AIO requset finishes, or we get an event */
- while(1) {
- int ret = aio_suspend(cb_list, count, NULL);
- if (!ret)
- break;
- assert(errno == EINTR);
- }
- for(i=0; i<count; i++)
- if(aio_error(cb_list[i]) != EINPROGRESS)
- {
- if(request_ids[i] >= 0)
- dispatch_response(mount, request_ids[i]);
- else
- goto read_event_channel;
- }
-
- RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&mount->ring, notify);
- printf("Pushed responces and notify=%d\n", notify);
+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&request->mount->ring, notify);
+ FS_DEBUG("Pushed responces and notify=%d\n", notify);
if(notify)
- xc_evtchn_notify(mount->evth, mount->local_evtchn);
-
- goto wait_again;
-
-read_event_channel:
- assert(aio_return(&evtchn_cb) == sizeof(evtchn_port_t));
- assert(xc_evtchn_unmask(mount->evth, mount->local_evtchn) >= 0);
+ xc_evtchn_notify(request->mount->evth, request->mount->local_evtchn);
}
-
static void allocate_request_array(struct fs_mount *mount)
{
@@ -116,6 +82,7 @@
for(i=0; i< nr_entries; i++)
{
requests[i].active = 0;
+ requests[i].mount = mount;
add_id_to_freelist(i, freelist);
}
mount->requests = requests;
@@ -123,73 +90,91 @@
}
-static void *handle_mount(void *data)
+static void handle_mount(struct fs_mount *mount)
{
int more, notify;
- struct fs_mount *mount = (struct fs_mount *)data;
-
- printf("Starting a thread for mount: %d\n", mount->mount_id);
- allocate_request_array(mount);
+ int nr_consumed=0;
+ RING_IDX cons, rp;
+ struct fsif_request *req;
- for(;;)
+moretodo:
+ rp = mount->ring.sring->req_prod;
+ xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
+
+ while ((cons = mount->ring.req_cons) != rp)
{
- int nr_consumed=0;
- RING_IDX cons, rp;
- struct fsif_request *req;
+ int i;
+ struct fs_op *op;
- handle_aio_events(mount);
-moretodo:
- rp = mount->ring.sring->req_prod;
- xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
+ FS_DEBUG("Got a request at %d (of %d)\n",
+ cons, RING_SIZE(&mount->ring));
+ req = RING_GET_REQUEST(&mount->ring, cons);
+ FS_DEBUG("Request type=%d\n", req->type);
+ for(i=0;;i++)
+ {
+ op = fsops[i];
+ if(op == NULL)
+ {
+ /* We've reached the end of the array, no appropirate
+ * handler found. Warn, ignore and continue. */
+ FS_DEBUG("WARN: Unknown request type: %d\n", req->type);
+ mount->ring.req_cons++;
+ break;
+ }
+ if(op->type == req->type)
+ {
+ /* There needs to be a dispatch handler */
+ assert(op->dispatch_handler != NULL);
+ op->dispatch_handler(mount, req);
+ break;
+ }
+ }
- while ((cons = mount->ring.req_cons) != rp)
- {
- int i;
- struct fs_op *op;
+ nr_consumed++;
+ }
+ FS_DEBUG("Backend consumed: %d requests\n", nr_consumed);
+ RING_FINAL_CHECK_FOR_REQUESTS(&mount->ring, more);
+ if(more) goto moretodo;
- 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++)
- {
- op = fsops[i];
- if(op == NULL)
- {
- /* We've reached the end of the array, no appropirate
- * handler found. Warn, ignore and continue. */
- printf("WARN: Unknown request type: %d\n", req->type);
- mount->ring.req_cons++;
- break;
- }
- if(op->type == req->type)
- {
- /* There needs to be a dispatch handler */
- assert(op->dispatch_handler != NULL);
- op->dispatch_handler(mount, req);
- break;
- }
- }
+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&mount->ring, notify);
+ FS_DEBUG("Pushed responces and notify=%d\n", notify);
+ if(notify)
+ xc_evtchn_notify(mount->evth, mount->local_evtchn);
+}
- nr_consumed++;
+static void terminate_mount_request(struct fs_mount *mount) {
+ int count = 0, i;
+
+ FS_DEBUG("terminate_mount_request %s\n", mount->frontend);
+ xenbus_write_backend_state(mount, STATE_CLOSING);
+
+ for(i=0; i<mount->nr_entries; i++)
+ if(mount->requests[i].active) {
+ mount->requests[i].active = -1;
+ aio_cancel(mount->requests[i].aiocb.aio_fildes, &mount->requests[i].aiocb);
+ count--;
}
- printf("Backend consumed: %d requests\n", nr_consumed);
- RING_FINAL_CHECK_FOR_REQUESTS(&mount->ring, more);
- if(more) goto moretodo;
+ mount->nr_entries = count;
- RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&mount->ring, notify);
- printf("Pushed responces and notify=%d\n", notify);
- if(notify)
- xc_evtchn_notify(mount->evth, mount->local_evtchn);
- }
-
- printf("Destroying thread for mount: %d\n", mount->mount_id);
+ while (!xenbus_frontend_state_changed(mount, STATE_CLOSING));
+ xenbus_write_backend_state(mount, STATE_CLOSED);
+
xc_gnttab_munmap(mount->gnth, mount->ring.sring, 1);
xc_gnttab_close(mount->gnth);
xc_evtchn_unbind(mount->evth, mount->local_evtchn);
xc_evtchn_close(mount->evth);
+
+ if (!count)
+ free_mount_request(mount);
+}
+
+static void free_mount_request(struct fs_mount *mount) {
+ FS_DEBUG("free_mount_request %s\n", mount->frontend);
free(mount->frontend);
- pthread_exit(NULL);
+ free(mount->requests);
+ free(mount->freelist);
+ LIST_REMOVE (mount, entries);
+ free(mount);
}
static void handle_connection(int frontend_dom_id, int export_id, char *frontend)
@@ -197,12 +182,11 @@
struct fs_mount *mount;
struct fs_export *export;
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",
+ FS_DEBUG("Handling connection from dom=%d, for export=%d\n",
frontend_dom_id, export_id);
/* Try to find the export on the list */
export = fs_exports;
@@ -214,7 +198,7 @@
}
if(!export)
{
- printf("Could not find the export (the id is unknown).\n");
+ FS_DEBUG("Could not find the export (the id is unknown).\n");
return;
}
@@ -223,7 +207,7 @@
mount->export = export;
mount->mount_id = mount_id++;
xenbus_read_mount_request(mount, frontend);
- printf("Frontend found at: %s (gref=%d, evtchn=%d)\n",
+ FS_DEBUG("Frontend found at: %s (gref=%d, evtchn=%d)\n",
mount->frontend, mount->grefs[0], mount->remote_evtchn);
xenbus_write_backend_node(mount);
mount->evth = -1;
@@ -249,18 +233,24 @@
mount->nr_entries = mount->ring.nr_ents;
for (i = 0; i < MAX_FDS; i++)
mount->fds[i] = -1;
- xenbus_write_backend_ready(mount);
- pthread_create(&handling_thread, NULL, &handle_mount, mount);
+ LIST_INSERT_HEAD(&mount_requests_head, mount, entries);
+ xenbus_watch_frontend_state(mount);
+ xenbus_write_backend_state(mount, STATE_READY);
+
+ allocate_request_array(mount);
}
static void await_connections(void)
{
- int fd, ret, dom_id, export_id;
+ int fd, max_fd, ret, dom_id, export_id;
fd_set fds;
char **watch_paths;
unsigned int len;
char d;
+ struct fs_mount *pointer;
+
+ LIST_INIT (&mount_requests_head);
assert(xsh != NULL);
fd = xenbus_get_watch_fd();
@@ -268,28 +258,101 @@
do {
FD_ZERO(&fds);
FD_SET(fd, &fds);
- ret = select(fd+1, &fds, NULL, NULL, NULL);
- assert(ret == 1);
- watch_paths = xs_read_watch(xsh, &len);
- assert(len == 2);
- assert(strcmp(watch_paths[1], "conn-watch") == 0);
- dom_id = -1;
- export_id = -1;
- d = 0;
- printf("Path changed %s\n", watch_paths[0]);
- sscanf(watch_paths[0], WATCH_NODE"/%d/%d/fronten%c",
- &dom_id, &export_id, &d);
- if((dom_id >= 0) && (export_id >= 0) && d == 'd') {
- char *frontend = xs_read(xsh, XBT_NULL, watch_paths[0], NULL);
- if (frontend) {
- handle_connection(dom_id, export_id, frontend);
- xs_rm(xsh, XBT_NULL, watch_paths[0]);
- }
- }
-next_select:
- printf("Awaiting next connection.\n");
- /* TODO - we need to figure out what to free */
- free(watch_paths);
+ FD_SET(pipefds[0], &fds);
+ max_fd = fd > pipefds[0] ? fd : pipefds[0];
+ LIST_FOREACH(pointer, &mount_requests_head, entries) {
+ int tfd = xc_evtchn_fd(pointer->evth);
+ FD_SET(tfd, &fds);
+ if (tfd > max_fd) max_fd = tfd;
+ }
+ ret = select(max_fd+1, &fds, NULL, NULL, NULL);
+ if (ret < 0) {
+ if (errno == EINTR) continue;
+ /* try to recover */
+ else if (errno == EBADF) {
+ struct timeval timeout;
+ memset(&timeout, 0x00, sizeof(timeout));
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ FD_SET(pipefds[0], &fds);
+ max_fd = fd > pipefds[0] ? fd : pipefds[0];
+ ret = select(max_fd + 1, &fds, NULL, NULL, &timeout);
+ if (ret < 0)
+ err(1, "select: unrecoverable error occurred: %d\n", errno);
+
+ /* trying to find the bogus fd among the open event channels */
+ LIST_FOREACH(pointer, &mount_requests_head, entries) {
+ int tfd = xc_evtchn_fd(pointer->evth);
+ memset(&timeout, 0x00, sizeof(timeout));
+ FD_ZERO(&fds);
+ FD_SET(tfd, &fds);
+ ret = select(tfd + 1, &fds, NULL, NULL, &timeout);
+ if (ret < 0) {
+ FS_DEBUG("fd %d is bogus, closing the related connection\n", tfd);
+ pointer->evth = fd;
+ terminate_mount_request(pointer);
+ continue;
+ }
+ }
+ continue;
+ } else
+ err(1, "select: unrecoverable error occurred: %d\n", errno);
+ }
+ if (FD_ISSET(fd, &fds)) {
+ watch_paths = xs_read_watch(xsh, &len);
+ if (!strcmp(watch_paths[XS_WATCH_TOKEN], "conn-watch")) {
+ dom_id = -1;
+ export_id = -1;
+ d = 0;
+ FS_DEBUG("Path changed %s\n", watch_paths[0]);
+ sscanf(watch_paths[XS_WATCH_PATH], WATCH_NODE"/%d/%d/fronten%c",
+ &dom_id, &export_id, &d);
+ if((dom_id >= 0) && (export_id >= 0) && d == 'd') {
+ char *frontend = xs_read(xsh, XBT_NULL, watch_paths[XS_WATCH_PATH], NULL);
+ if (frontend) {
+ handle_connection(dom_id, export_id, frontend);
+ xs_rm(xsh, XBT_NULL, watch_paths[XS_WATCH_PATH]);
+ }
+ }
+ } else if (!strcmp(watch_paths[XS_WATCH_TOKEN], "frontend-state")) {
+ LIST_FOREACH(pointer, &mount_requests_head, entries) {
+ if (!strncmp(pointer->frontend, watch_paths[XS_WATCH_PATH], strlen(pointer->frontend))) {
+ char *state = xenbus_read_frontend_state(pointer);
+ if (!state || strcmp(state, STATE_READY)) {
+ xenbus_unwatch_frontend_state(pointer);
+ terminate_mount_request(pointer);
+ }
+ free(state);
+ break;
+ }
+ }
+ } else {
+ FS_DEBUG("xenstore watch event unrecognized\n");
+ }
+ FS_DEBUG("Awaiting next connection.\n");
+ /* TODO - we need to figure out what to free */
+ free(watch_paths);
+ }
+ if (FD_ISSET(pipefds[0], &fds)) {
+ struct fs_request *request;
+ int ret;
+ ret = read(pipefds[0], &request, sizeof(struct fs_request *));
+ if (ret != sizeof(struct fs_request *)) {
+ fprintf(stderr, "read request failed\n");
+ continue;
+ }
+ handle_aio_event(request);
+ }
+ LIST_FOREACH(pointer, &mount_requests_head, entries) {
+ if (FD_ISSET(xc_evtchn_fd(pointer->evth), &fds)) {
+ evtchn_port_t port;
+ port = xc_evtchn_pending(pointer->evth);
+ if (port != -1) {
+ handle_mount(pointer);
+ xc_evtchn_unmask(pointer->evth, port);
+ }
+ }
+ }
} while (1);
}
@@ -312,10 +375,28 @@
return curr_export;
}
+static void aio_signal_handler(int signo, siginfo_t *info, void *context)
+{
+ struct fs_request *request = (struct fs_request*) info->si_value.sival_ptr;
+ int saved_errno = errno;
+ write(pipefds[1], &request, sizeof(struct fs_request *));
+ errno = saved_errno;
+}
int main(void)
{
struct fs_export *export;
+ struct sigaction act;
+ sigset_t enable;
+
+ sigemptyset(&enable);
+ sigaddset(&enable, SIGUSR2);
+ pthread_sigmask(SIG_UNBLOCK, &enable, NULL);
+
+ sigfillset(&act.sa_mask);
+ act.sa_flags = SA_SIGINFO; /* do not restart syscalls to interrupt select(); use sa_sigaction */
+ act.sa_sigaction = aio_signal_handler;
+ sigaction(SIGUSR2, &act, NULL);
/* Open the connection to XenStore first */
xsh = xs_domain_open();
@@ -327,6 +408,9 @@
/* Create & register the default export */
export = create_export("default", "/exports");
xenbus_register_export(export);
+
+ if (socketpair(PF_UNIX,SOCK_STREAM, 0, pipefds) == -1)
+ err(1, "failed to create pipe\n");
await_connections();
/* Close the connection to XenStore when we are finished with everything */
diff -r 0e1449d6f231 tools/fs-back/fs-backend.h
--- a/tools/fs-back/fs-backend.h Fri Mar 13 10:09:25 2009 +0000
+++ b/tools/fs-back/fs-backend.h Mon Mar 16 11:23:36 2009 +0000
@@ -7,6 +7,7 @@
#include <xen/event_channel.h>
#include <xen/io/ring.h>
#include <xen/io/fsif.h>
+#include "sys-queue.h"
#define ROOT_NODE "backend/vfs"
#define EXPORTS_SUBNODE "exports"
@@ -25,6 +26,8 @@
struct fs_request
{
+ struct fs_mount *mount;
+ int id;
int active;
void *page; /* Pointer to mapped grant */
int count;
@@ -50,6 +53,7 @@
struct fs_request *requests;
unsigned short *freelist;
int fds[MAX_FDS];
+ LIST_ENTRY(fs_mount) entries;
};
@@ -61,7 +65,11 @@
int xenbus_get_watch_fd(void);
void xenbus_read_mount_request(struct fs_mount *mount, char *frontend);
void xenbus_write_backend_node(struct fs_mount *mount);
-void xenbus_write_backend_ready(struct fs_mount *mount);
+void xenbus_write_backend_state(struct fs_mount *mount, const char *state);
+int xenbus_frontend_state_changed(struct fs_mount *mount, const char *oldstate);
+void xenbus_watch_frontend_state(struct fs_mount *mount);
+void xenbus_unwatch_frontend_state(struct fs_mount *mount);
+char* xenbus_read_frontend_state(struct fs_mount *mount);
/* File operations, implemented in fs-ops.c */
struct fs_op
diff -r 0e1449d6f231 tools/fs-back/fs-debug.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/fs-back/fs-debug.h Mon Mar 16 11:23:36 2009 +0000
@@ -0,0 +1,12 @@
+#ifndef __FS_DEBUG__
+#define __FS_DEBUG__
+
+// #define DEBUG 1
+
+#ifdef DEBUG
+#define FS_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define FS_DEBUG(fmt, ...) do { } while (0)
+#endif
+
+#endif /*__FS_DEBUG__*/
diff -r 0e1449d6f231 tools/fs-back/fs-ops.c
--- a/tools/fs-back/fs-ops.c Fri Mar 13 10:09:25 2009 +0000
+++ b/tools/fs-back/fs-ops.c Mon Mar 16 11:23:36 2009 +0000
@@ -14,6 +14,7 @@
#include <sys/mount.h>
#include <unistd.h>
#include "fs-backend.h"
+#include "fs-debug.h"
/* For debugging only */
#include <sys/time.h>
@@ -22,12 +23,11 @@
#define BUFFER_SIZE 1024
-
static unsigned short get_request(struct fs_mount *mount, struct fsif_request *req)
{
unsigned short id = get_id_from_freelist(mount->freelist);
- printf("Private Request id: %d\n", id);
+ FS_DEBUG("Private Request id: %d\n", id);
memcpy(&mount->requests[id].req_shadow, req, sizeof(struct fsif_request));
mount->requests[id].active = 1;
@@ -54,7 +54,7 @@
fsif_response_t *rsp;
uint16_t req_id;
- printf("Dispatching file open operation (gref=%d).\n", req->u.fopen.gref);
+ FS_DEBUG("Dispatching file open operation (gref=%d).\n", req->u.fopen.gref);
/* Read the request, and open file */
file_name = xc_gnttab_map_grant_ref(mount->gnth,
mount->dom_id,
@@ -62,13 +62,13 @@
PROT_READ);
req_id = req->id;
- printf("File open issued for %s\n", file_name);
+ FS_DEBUG("File open issued for %s\n", file_name);
assert(BUFFER_SIZE >
strlen(file_name) + strlen(mount->export->export_path) + 1);
snprintf(full_path, sizeof(full_path), "%s/%s",
mount->export->export_path, file_name);
assert(xc_gnttab_munmap(mount->gnth, file_name, 1) == 0);
- printf("Issuing open for %s\n", full_path);
+ FS_DEBUG("Issuing open for %s\n", full_path);
fd = get_fd(mount);
if (fd >= 0) {
int real_fd = open(full_path, O_RDWR);
@@ -77,7 +77,7 @@
else
{
mount->fds[fd] = real_fd;
- printf("Got FD: %d for real %d\n", fd, real_fd);
+ FS_DEBUG("Got FD: %d for real %d\n", fd, real_fd);
}
}
/* We can advance the request consumer index, from here on, the request
@@ -87,7 +87,7 @@
/* 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);
+ FS_DEBUG("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)fd;
@@ -100,7 +100,7 @@
fsif_response_t *rsp;
uint16_t req_id;
- printf("Dispatching file close operation (fd=%d).\n", req->u.fclose.fd);
+ FS_DEBUG("Dispatching file close operation (fd=%d).\n", req->u.fclose.fd);
req_id = req->id;
if (req->u.fclose.fd < MAX_FDS) {
@@ -109,7 +109,7 @@
mount->fds[req->u.fclose.fd] = -1;
} else
ret = -1;
- printf("Got ret: %d\n", ret);
+ FS_DEBUG("Got ret: %d\n", ret);
/* We can advance the request consumer index, from here on, the request
* should not be used (it may be overrinden by a response) */
mount->ring.req_cons++;
@@ -117,7 +117,7 @@
/* 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);
+ FS_DEBUG("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;
@@ -143,7 +143,7 @@
PROT_WRITE);
req_id = req->id;
- printf("File read issued for FD=%d (len=%"PRIu64", offest=%"PRIu64")\n",
+ FS_DEBUG("File read issued for FD=%d (len=%"PRIu64", offest=%"PRIu64")\n",
req->u.fread.fd, req->u.fread.len, req->u.fread.offset);
if (req->u.fread.fd < MAX_FDS)
@@ -152,10 +152,11 @@
fd = -1;
priv_id = get_request(mount, req);
- printf("Private id is: %d\n", priv_id);
+ FS_DEBUG("Private id is: %d\n", priv_id);
priv_req = &mount->requests[priv_id];
priv_req->page = buf;
priv_req->count = count;
+ priv_req->id = priv_id;
/* Dispatch AIO read request */
bzero(&priv_req->aiocb, sizeof(struct aiocb));
@@ -163,6 +164,9 @@
priv_req->aiocb.aio_nbytes = req->u.fread.len;
priv_req->aiocb.aio_offset = req->u.fread.offset;
priv_req->aiocb.aio_buf = buf;
+ priv_req->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
+ priv_req->aiocb.aio_sigevent.sigev_signo = SIGUSR2;
+ priv_req->aiocb.aio_sigevent.sigev_value.sival_ptr = priv_req;
assert(aio_read(&priv_req->aiocb) >= 0);
out:
@@ -185,7 +189,7 @@
/* Get a response from the ring */
rsp_idx = mount->ring.rsp_prod_pvt++;
req_id = priv_req->req_shadow.id;
- printf("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
+ FS_DEBUG("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)aio_return(&priv_req->aiocb);
@@ -210,7 +214,7 @@
PROT_READ);
req_id = req->id;
- printf("File write issued for FD=%d (len=%"PRIu64", offest=%"PRIu64")\n",
+ FS_DEBUG("File write issued for FD=%d (len=%"PRIu64", offest=%"PRIu64")\n",
req->u.fwrite.fd, req->u.fwrite.len, req->u.fwrite.offset);
if (req->u.fwrite.fd < MAX_FDS)
@@ -219,10 +223,11 @@
fd = -1;
priv_id = get_request(mount, req);
- printf("Private id is: %d\n", priv_id);
+ FS_DEBUG("Private id is: %d\n", priv_id);
priv_req = &mount->requests[priv_id];
priv_req->page = buf;
priv_req->count = count;
+ priv_req->id = priv_id;
/* Dispatch AIO write request */
bzero(&priv_req->aiocb, sizeof(struct aiocb));
@@ -230,6 +235,9 @@
priv_req->aiocb.aio_nbytes = req->u.fwrite.len;
priv_req->aiocb.aio_offset = req->u.fwrite.offset;
priv_req->aiocb.aio_buf = buf;
+ priv_req->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
+ priv_req->aiocb.aio_sigevent.sigev_signo = SIGUSR2;
+ priv_req->aiocb.aio_sigevent.sigev_value.sival_ptr = priv_req;
assert(aio_write(&priv_req->aiocb) >= 0);
@@ -252,7 +260,7 @@
/* Get a response from the ring */
rsp_idx = mount->ring.rsp_prod_pvt++;
req_id = priv_req->req_shadow.id;
- printf("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
+ FS_DEBUG("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)aio_return(&priv_req->aiocb);
@@ -273,7 +281,7 @@
else
fd = -1;
- printf("File stat issued for FD=%d\n", req->u.fstat.fd);
+ FS_DEBUG("File stat issued for FD=%d\n", req->u.fstat.fd);
/* We can advance the request consumer index, from here on, the request
* should not be used (it may be overrinden by a response) */
@@ -281,12 +289,12 @@
/* Stat, and create the response */
ret = fstat(fd, &stat);
- printf("Mode=%o, uid=%d, a_time=%ld\n",
+ FS_DEBUG("Mode=%o, uid=%d, a_time=%ld\n",
stat.st_mode, stat.st_uid, (long)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);
+ FS_DEBUG("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;
@@ -320,7 +328,7 @@
req_id = req->id;
length = req->u.ftruncate.length;
- printf("File truncate issued for FD=%d, length=%"PRId64"\n", req->u.ftruncate.fd, length);
+ FS_DEBUG("File truncate issued for FD=%d, length=%"PRId64"\n", req->u.ftruncate.fd, length);
if (req->u.ftruncate.fd < MAX_FDS)
fd = mount->fds[req->u.ftruncate.fd];
@@ -336,7 +344,7 @@
/* 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);
+ FS_DEBUG("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;
@@ -350,7 +358,7 @@
fsif_response_t *rsp;
uint16_t req_id;
- printf("Dispatching remove operation (gref=%d).\n", req->u.fremove.gref);
+ FS_DEBUG("Dispatching remove operation (gref=%d).\n", req->u.fremove.gref);
/* Read the request, and open file */
file_name = xc_gnttab_map_grant_ref(mount->gnth,
mount->dom_id,
@@ -358,15 +366,15 @@
PROT_READ);
req_id = req->id;
- printf("File remove issued for %s\n", file_name);
+ FS_DEBUG("File remove issued for %s\n", file_name);
assert(BUFFER_SIZE >
strlen(file_name) + strlen(mount->export->export_path) + 1);
snprintf(full_path, sizeof(full_path), "%s/%s",
mount->export->export_path, file_name);
assert(xc_gnttab_munmap(mount->gnth, file_name, 1) == 0);
- printf("Issuing remove for %s\n", full_path);
+ FS_DEBUG("Issuing remove for %s\n", full_path);
ret = remove(full_path);
- printf("Got ret: %d\n", ret);
+ FS_DEBUG("Got ret: %d\n", ret);
/* We can advance the request consumer index, from here on, the request
* should not be used (it may be overrinden by a response) */
mount->ring.req_cons++;
@@ -374,7 +382,7 @@
/* 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);
+ FS_DEBUG("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;
@@ -390,7 +398,7 @@
fsif_response_t *rsp;
uint16_t req_id;
- printf("Dispatching rename operation (gref=%d).\n", req->u.fremove.gref);
+ FS_DEBUG("Dispatching rename operation (gref=%d).\n", req->u.fremove.gref);
/* Read the request, and open file */
buf = xc_gnttab_map_grant_ref(mount->gnth,
mount->dom_id,
@@ -400,7 +408,7 @@
req_id = req->id;
old_file_name = buf + req->u.frename.old_name_offset;
new_file_name = buf + req->u.frename.new_name_offset;
- printf("File rename issued for %s -> %s (buf=%s)\n",
+ FS_DEBUG("File rename issued for %s -> %s (buf=%s)\n",
old_file_name, new_file_name, buf);
assert(BUFFER_SIZE >
strlen(old_file_name) + strlen(mount->export->export_path) + 1);
@@ -411,9 +419,9 @@
snprintf(new_full_path, sizeof(new_full_path), "%s/%s",
mount->export->export_path, new_file_name);
assert(xc_gnttab_munmap(mount->gnth, buf, 1) == 0);
- printf("Issuing rename for %s -> %s\n", old_full_path, new_full_path);
+ FS_DEBUG("Issuing rename for %s -> %s\n", old_full_path, new_full_path);
ret = rename(old_full_path, new_full_path);
- printf("Got ret: %d\n", ret);
+ FS_DEBUG("Got ret: %d\n", ret);
/* We can advance the request consumer index, from here on, the request
* should not be used (it may be overrinden by a response) */
mount->ring.req_cons++;
@@ -421,7 +429,7 @@
/* 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);
+ FS_DEBUG("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;
@@ -438,7 +446,7 @@
fsif_response_t *rsp;
uint16_t req_id;
- printf("Dispatching file create operation (gref=%d).\n", req->u.fcreate.gref);
+ FS_DEBUG("Dispatching file create operation (gref=%d).\n", req->u.fcreate.gref);
/* Read the request, and create file/directory */
mode = req->u.fcreate.mode;
directory = req->u.fcreate.directory;
@@ -448,7 +456,7 @@
PROT_READ);
req_id = req->id;
- printf("File create issued for %s\n", file_name);
+ FS_DEBUG("File create issued for %s\n", file_name);
assert(BUFFER_SIZE >
strlen(file_name) + strlen(mount->export->export_path) + 1);
snprintf(full_path, sizeof(full_path), "%s/%s",
@@ -460,12 +468,12 @@
if(directory)
{
- printf("Issuing create for directory: %s\n", full_path);
+ FS_DEBUG("Issuing create for directory: %s\n", full_path);
ret = mkdir(full_path, mode);
}
else
{
- printf("Issuing create for file: %s\n", full_path);
+ FS_DEBUG("Issuing create for file: %s\n", full_path);
ret = get_fd(mount);
if (ret >= 0) {
int real_fd = creat(full_path, mode);
@@ -474,15 +482,15 @@
else
{
mount->fds[ret] = real_fd;
- printf("Got FD: %d for real %d\n", ret, real_fd);
+ FS_DEBUG("Got FD: %d for real %d\n", ret, real_fd);
}
}
}
- printf("Got ret %d (errno=%d)\n", ret, errno);
+ FS_DEBUG("Got ret %d (errno=%d)\n", ret, errno);
/* 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);
+ FS_DEBUG("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;
@@ -499,7 +507,7 @@
DIR *dir;
struct dirent *dirent = NULL;
- printf("Dispatching list operation (gref=%d).\n", req->u.flist.gref);
+ FS_DEBUG("Dispatching list operation (gref=%d).\n", req->u.flist.gref);
/* Read the request, and list directory */
offset = req->u.flist.offset;
buf = file_name = xc_gnttab_map_grant_ref(mount->gnth,
@@ -508,7 +516,7 @@
PROT_READ | PROT_WRITE);
req_id = req->id;
- printf("Dir list issued for %s\n", file_name);
+ FS_DEBUG("Dir list issued for %s\n", file_name);
assert(BUFFER_SIZE >
strlen(file_name) + strlen(mount->export->export_path) + 1);
snprintf(full_path, sizeof(full_path), "%s/%s",
@@ -552,7 +560,7 @@
/* 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);
+ FS_DEBUG("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 = ret_val;
@@ -566,7 +574,7 @@
uint16_t req_id;
int32_t mode;
- printf("Dispatching file chmod operation (fd=%d, mode=%o).\n",
+ FS_DEBUG("Dispatching file chmod operation (fd=%d, mode=%o).\n",
req->u.fchmod.fd, req->u.fchmod.mode);
req_id = req->id;
if (req->u.fchmod.fd < MAX_FDS)
@@ -583,7 +591,7 @@
/* 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);
+ FS_DEBUG("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;
@@ -598,7 +606,7 @@
struct statvfs stat;
int64_t ret;
- printf("Dispatching fs space operation (gref=%d).\n", req->u.fspace.gref);
+ FS_DEBUG("Dispatching fs space operation (gref=%d).\n", req->u.fspace.gref);
/* Read the request, and open file */
file_name = xc_gnttab_map_grant_ref(mount->gnth,
mount->dom_id,
@@ -606,13 +614,13 @@
PROT_READ);
req_id = req->id;
- printf("Fs space issued for %s\n", file_name);
+ FS_DEBUG("Fs space issued for %s\n", file_name);
assert(BUFFER_SIZE >
strlen(file_name) + strlen(mount->export->export_path) + 1);
snprintf(full_path, sizeof(full_path), "%s/%s",
mount->export->export_path, file_name);
assert(xc_gnttab_munmap(mount->gnth, file_name, 1) == 0);
- printf("Issuing fs space for %s\n", full_path);
+ FS_DEBUG("Issuing fs space for %s\n", full_path);
ret = statvfs(full_path, &stat);
if(ret >= 0)
ret = stat.f_bsize * stat.f_bfree;
@@ -624,7 +632,7 @@
/* 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);
+ FS_DEBUG("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;
@@ -643,15 +651,19 @@
else
fd = -1;
- printf("File sync issued for FD=%d\n", req->u.fsync.fd);
+ FS_DEBUG("File sync issued for FD=%d\n", req->u.fsync.fd);
priv_id = get_request(mount, req);
- printf("Private id is: %d\n", priv_id);
+ FS_DEBUG("Private id is: %d\n", priv_id);
priv_req = &mount->requests[priv_id];
+ priv_req->id = priv_id;
/* Dispatch AIO read request */
bzero(&priv_req->aiocb, sizeof(struct aiocb));
priv_req->aiocb.aio_fildes = fd;
+ priv_req->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
+ priv_req->aiocb.aio_sigevent.sigev_signo = SIGUSR2;
+ priv_req->aiocb.aio_sigevent.sigev_value.sival_ptr = priv_req;
assert(aio_fsync(O_SYNC, &priv_req->aiocb) >= 0);
@@ -669,7 +681,7 @@
/* Get a response from the ring */
rsp_idx = mount->ring.rsp_prod_pvt++;
req_id = priv_req->req_shadow.id;
- printf("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
+ FS_DEBUG("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)aio_return(&priv_req->aiocb);
diff -r 0e1449d6f231 tools/fs-back/fs-xenbus.c
--- a/tools/fs-back/fs-xenbus.c Fri Mar 13 10:09:25 2009 +0000
+++ b/tools/fs-back/fs-xenbus.c Mon Mar 16 11:23:36 2009 +0000
@@ -4,10 +4,12 @@
#include <stdarg.h>
#include <string.h>
#include <assert.h>
+#include <sys/select.h>
#include <xenctrl.h>
#include <xs.h>
#include <xen/io/fsif.h>
#include "fs-backend.h"
+#include "fs-debug.h"
static bool xenbus_printf(struct xs_handle *xsh,
@@ -25,7 +27,7 @@
snprintf(fullpath, sizeof(fullpath), "%s/%s", node, path);
vsnprintf(val, sizeof(val), fmt, args);
va_end(args);
- printf("xenbus_printf (%s) <= %s.\n", fullpath, val);
+ FS_DEBUG("xenbus_printf (%s) <= %s.\n", fullpath, val);
return xs_write(xsh, xbt, fullpath, val, strlen(val));
}
@@ -57,19 +59,19 @@
assert(xsh != NULL);
if(xsh == NULL)
{
- printf("Could not open connection to xenbus deamon.\n");
+ FS_DEBUG("Could not open connection to xenbus deamon.\n");
goto error_exit;
}
- printf("Connection to the xenbus deamon opened successfully.\n");
+ FS_DEBUG("Connection to the xenbus deamon opened successfully.\n");
/* Start transaction */
xst = xs_transaction_start(xsh);
if(xst == 0)
{
- printf("Could not start a transaction.\n");
+ FS_DEBUG("Could not start a transaction.\n");
goto error_exit;
}
- printf("XS transaction is %d\n", xst);
+ FS_DEBUG("XS transaction is %d\n", xst);
/* Create node string */
snprintf(node, sizeof(node), "%s/%d", EXPORTS_NODE, export->export_id);
@@ -78,7 +80,7 @@
if(!xenbus_printf(xsh, xst, node, "name", "%s", export->name))
{
- printf("Could not write the export node.\n");
+ FS_DEBUG("Could not write the export node.\n");
goto error_exit;
}
@@ -87,7 +89,7 @@
perms.perms = XS_PERM_READ;
if(!xs_set_permissions(xsh, xst, EXPORTS_NODE, &perms, 1))
{
- printf("Could not set permissions on the export node.\n");
+ FS_DEBUG("Could not set permissions on the export node.\n");
goto error_exit;
}
@@ -166,7 +168,7 @@
assert(xsh != NULL);
self_id = get_self_id();
- printf("Our own dom_id=%d\n", self_id);
+ FS_DEBUG("Our own dom_id=%d\n", self_id);
snprintf(node, sizeof(node), "%s/backend", mount->frontend);
snprintf(backend_node, sizeof(backend_node), "/local/domain/%d/"ROOT_NODE"/%d",
self_id, mount->mount_id);
@@ -176,7 +178,7 @@
xs_write(xsh, XBT_NULL, node, STATE_INITIALISED, strlen(STATE_INITIALISED));
}
-void xenbus_write_backend_ready(struct fs_mount *mount)
+void xenbus_write_backend_state(struct fs_mount *mount, const char *state)
{
char node[1024];
int self_id;
@@ -184,6 +186,59 @@
assert(xsh != NULL);
self_id = get_self_id();
snprintf(node, sizeof(node), ROOT_NODE"/%d/state", mount->mount_id);
- xs_write(xsh, XBT_NULL, node, STATE_READY, strlen(STATE_READY));
+ xs_write(xsh, XBT_NULL, node, state, strlen(state));
}
+void xenbus_watch_frontend_state(struct fs_mount *mount)
+{
+ int res;
+ char statepath[1024];
+
+ assert(xsh != NULL);
+ snprintf(statepath, sizeof(statepath), "%s/state", mount->frontend);
+ res = xs_watch(xsh, statepath, "frontend-state");
+ assert(res);
+}
+
+void xenbus_unwatch_frontend_state(struct fs_mount *mount)
+{
+ int res;
+ char statepath[1024];
+
+ assert(xsh != NULL);
+ snprintf(statepath, sizeof(statepath), "%s/state", mount->frontend);
+ res = xs_unwatch(xsh, statepath, "frontend-state");
+ assert(res);
+}
+
+int xenbus_frontend_state_changed(struct fs_mount *mount, const char *oldstate)
+{
+ unsigned int len;
+ char statepath[1024];
+ char *state = NULL;
+
+ assert(xsh != NULL);
+ snprintf(statepath, sizeof(statepath), "%s/state", mount->frontend);
+ state = xs_read(xsh, XBT_NULL, statepath, &len);
+ if (state && len > 0) {
+ if (strcmp(state, oldstate)) {
+ free(state);
+ return 1;
+ } else {
+ free(state);
+ return 0;
+ }
+ } else
+ return 1;
+}
+
+char* xenbus_read_frontend_state(struct fs_mount *mount)
+{
+ unsigned int len;
+ char statepath[1024];
+
+ assert(xsh != NULL);
+ snprintf(statepath, sizeof(statepath), "%s/state", mount->frontend);
+ return xs_read(xsh, XBT_NULL, statepath, &len);
+}
+
diff -r 0e1449d6f231 tools/fs-back/sys-queue.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/fs-back/sys-queue.h Mon Mar 16 11:23:36 2009 +0000
@@ -0,0 +1,338 @@
+/* $NetBSD: queue.h,v 1.45.14.1 2007/07/18 20:13:24 liamjfoy Exp $ */
+
+/*
+ * Qemu version: Copy from netbsd, removed debug code, removed some of
+ * the implementations. Left in lists, tail queues and circular queues.
+ */
+
+/*
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef _SYS_QUEUE_H_
+#define _SYS_QUEUE_H_
+
+/*
+ * This file defines three types of data structures:
+ * lists, tail queues, and circular queues.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+/*
+ * List definitions.
+ */
+#define LIST_HEAD(name, type) \
+struct name { \
+ struct type *lh_first; /* first element */ \
+}
+
+#define LIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define LIST_ENTRY(type) \
+struct { \
+ struct type *le_next; /* next element */ \
+ struct type **le_prev; /* address of previous next element */ \
+}
+
+/*
+ * List functions.
+ */
+#define LIST_INIT(head) do { \
+ (head)->lh_first = NULL; \
+} while (/*CONSTCOND*/0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) do { \
+ if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
+ (listelm)->field.le_next->field.le_prev = \
+ &(elm)->field.le_next; \
+ (listelm)->field.le_next = (elm); \
+ (elm)->field.le_prev = &(listelm)->field.le_next; \
+} while (/*CONSTCOND*/0)
+
+#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.le_prev = (listelm)->field.le_prev; \
+ (elm)->field.le_next = (listelm); \
+ *(listelm)->field.le_prev = (elm); \
+ (listelm)->field.le_prev = &(elm)->field.le_next; \
+} while (/*CONSTCOND*/0)
+
+#define LIST_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.le_next = (head)->lh_first) != NULL) \
+ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+ (head)->lh_first = (elm); \
+ (elm)->field.le_prev = &(head)->lh_first; \
+} while (/*CONSTCOND*/0)
+
+#define LIST_REMOVE(elm, field) do { \
+ if ((elm)->field.le_next != NULL) \
+ (elm)->field.le_next->field.le_prev = \
+ (elm)->field.le_prev; \
+ *(elm)->field.le_prev = (elm)->field.le_next; \
+} while (/*CONSTCOND*/0)
+
+#define LIST_FOREACH(var, head, field) \
+ for ((var) = ((head)->lh_first); \
+ (var); \
+ (var) = ((var)->field.le_next))
+
+/*
+ * List access methods.
+ */
+#define LIST_EMPTY(head) ((head)->lh_first == NULL)
+#define LIST_FIRST(head) ((head)->lh_first)
+#define LIST_NEXT(elm, field) ((elm)->field.le_next)
+
+
+/*
+ * Tail queue definitions.
+ */
+#define _TAILQ_HEAD(name, type, qual) \
+struct name { \
+ qual type *tqh_first; /* first element */ \
+ qual type *qual *tqh_last; /* addr of last next element */ \
+}
+#define TAILQ_HEAD(name, type) _TAILQ_HEAD(name, struct type,)
+
+#define TAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).tqh_first }
+
+#define _TAILQ_ENTRY(type, qual) \
+struct { \
+ qual type *tqe_next; /* next element */ \
+ qual type *qual *tqe_prev; /* address of previous next element */\
+}
+#define TAILQ_ENTRY(type) _TAILQ_ENTRY(struct type,)
+
+/*
+ * Tail queue functions.
+ */
+#define TAILQ_INIT(head) do { \
+ (head)->tqh_first = NULL; \
+ (head)->tqh_last = &(head)->tqh_first; \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
+ (head)->tqh_first->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (head)->tqh_first = (elm); \
+ (elm)->field.tqe_prev = &(head)->tqh_first; \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.tqe_next = NULL; \
+ (elm)->field.tqe_prev = (head)->tqh_last; \
+ *(head)->tqh_last = (elm); \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+ (elm)->field.tqe_next->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (listelm)->field.tqe_next = (elm); \
+ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
+ (elm)->field.tqe_next = (listelm); \
+ *(listelm)->field.tqe_prev = (elm); \
+ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_REMOVE(head, elm, field) do { \
+ if (((elm)->field.tqe_next) != NULL) \
+ (elm)->field.tqe_next->field.tqe_prev = \
+ (elm)->field.tqe_prev; \
+ else \
+ (head)->tqh_last = (elm)->field.tqe_prev; \
+ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_FOREACH(var, head, field) \
+ for ((var) = ((head)->tqh_first); \
+ (var); \
+ (var) = ((var)->field.tqe_next))
+
+#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
+ for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last)); \
+ (var); \
+ (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last)))
+
+/*
+ * Tail queue access methods.
+ */
+#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
+#define TAILQ_FIRST(head) ((head)->tqh_first)
+#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+
+#define TAILQ_LAST(head, headname) \
+ (*(((struct headname *)((head)->tqh_last))->tqh_last))
+#define TAILQ_PREV(elm, headname, field) \
+ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+
+
+/*
+ * Circular queue definitions.
+ */
+#define CIRCLEQ_HEAD(name, type) \
+struct name { \
+ struct type *cqh_first; /* first element */ \
+ struct type *cqh_last; /* last element */ \
+}
+
+#define CIRCLEQ_HEAD_INITIALIZER(head) \
+ { (void *)&head, (void *)&head }
+
+#define CIRCLEQ_ENTRY(type) \
+struct { \
+ struct type *cqe_next; /* next element */ \
+ struct type *cqe_prev; /* previous element */ \
+}
+
+/*
+ * Circular queue functions.
+ */
+#define CIRCLEQ_INIT(head) do { \
+ (head)->cqh_first = (void *)(head); \
+ (head)->cqh_last = (void *)(head); \
+} while (/*CONSTCOND*/0)
+
+#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ (elm)->field.cqe_next = (listelm)->field.cqe_next; \
+ (elm)->field.cqe_prev = (listelm); \
+ if ((listelm)->field.cqe_next == (void *)(head)) \
+ (head)->cqh_last = (elm); \
+ else \
+ (listelm)->field.cqe_next->field.cqe_prev = (elm); \
+ (listelm)->field.cqe_next = (elm); \
+} while (/*CONSTCOND*/0)
+
+#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
+ (elm)->field.cqe_next = (listelm); \
+ (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
+ if ((listelm)->field.cqe_prev == (void *)(head)) \
+ (head)->cqh_first = (elm); \
+ else \
+ (listelm)->field.cqe_prev->field.cqe_next = (elm); \
+ (listelm)->field.cqe_prev = (elm); \
+} while (/*CONSTCOND*/0)
+
+#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
+ (elm)->field.cqe_next = (head)->cqh_first; \
+ (elm)->field.cqe_prev = (void *)(head); \
+ if ((head)->cqh_last == (void *)(head)) \
+ (head)->cqh_last = (elm); \
+ else \
+ (head)->cqh_first->field.cqe_prev = (elm); \
+ (head)->cqh_first = (elm); \
+} while (/*CONSTCOND*/0)
+
+#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.cqe_next = (void *)(head); \
+ (elm)->field.cqe_prev = (head)->cqh_last; \
+ if ((head)->cqh_first == (void *)(head)) \
+ (head)->cqh_first = (elm); \
+ else \
+ (head)->cqh_last->field.cqe_next = (elm); \
+ (head)->cqh_last = (elm); \
+} while (/*CONSTCOND*/0)
+
+#define CIRCLEQ_REMOVE(head, elm, field) do { \
+ if ((elm)->field.cqe_next == (void *)(head)) \
+ (head)->cqh_last = (elm)->field.cqe_prev; \
+ else \
+ (elm)->field.cqe_next->field.cqe_prev = \
+ (elm)->field.cqe_prev; \
+ if ((elm)->field.cqe_prev == (void *)(head)) \
+ (head)->cqh_first = (elm)->field.cqe_next; \
+ else \
+ (elm)->field.cqe_prev->field.cqe_next = \
+ (elm)->field.cqe_next; \
+} while (/*CONSTCOND*/0)
+
+#define CIRCLEQ_FOREACH(var, head, field) \
+ for ((var) = ((head)->cqh_first); \
+ (var) != (const void *)(head); \
+ (var) = ((var)->field.cqe_next))
+
+#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
+ for ((var) = ((head)->cqh_last); \
+ (var) != (const void *)(head); \
+ (var) = ((var)->field.cqe_prev))
+
+/*
+ * Circular queue access methods.
+ */
+#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head))
+#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
+#define CIRCLEQ_LAST(head) ((head)->cqh_last)
+#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
+#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
+
+#define CIRCLEQ_LOOP_NEXT(head, elm, field) \
+ (((elm)->field.cqe_next == (void *)(head)) \
+ ? ((head)->cqh_first) \
+ : (elm->field.cqe_next))
+#define CIRCLEQ_LOOP_PREV(head, elm, field) \
+ (((elm)->field.cqe_prev == (void *)(head)) \
+ ? ((head)->cqh_last) \
+ : (elm->field.cqe_prev))
+
+#endif /* !_SYS_QUEUE_H_ */
diff -r 0e1449d6f231 xen/include/public/io/fsif.h
--- a/xen/include/public/io/fsif.h Fri Mar 13 10:09:25 2009 +0000
+++ b/xen/include/public/io/fsif.h Mon Mar 16 11:23:36 2009 +0000
@@ -185,7 +185,8 @@
#define STATE_INITIALISED "init"
#define STATE_READY "ready"
-
+#define STATE_CLOSING "closing"
+#define STATE_CLOSED "closed"
#endif
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] [UPDATE] fs-backend fixes and improvements
2009-03-16 11:25 [PATCH] [UPDATE] fs-backend fixes and improvements Stefano Stabellini
@ 2009-03-17 10:51 ` Keir Fraser
2009-03-17 10:55 ` Stefano Stabellini
0 siblings, 1 reply; 5+ messages in thread
From: Keir Fraser @ 2009-03-17 10:51 UTC (permalink / raw)
To: Stefano Stabellini, xen-devel
On 16/03/2009 11:25, "Stefano Stabellini" <stefano.stabellini@eu.citrix.com>
wrote:
> Hi all,
> this patch is an updated version of the previous patch I sent to fix
> the issues that currently affect fs-backend.
> Compared to the previous version this patch is more resilient to errors
> because it is not using sigprocmask anymore to block SIGUSR2: blocking
> signals doesn't get along very well with glibc's aio implementation.
> Secondly I also introduced explicit error checking on the select return
> value, trying to recover in case of errors.
>
> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
The patch fails to apply to xen-unstable. Perhaps it got eaten by your mail
client?
-- Keir
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] [UPDATE] fs-backend fixes and improvements
2009-03-17 10:51 ` Keir Fraser
@ 2009-03-17 10:55 ` Stefano Stabellini
2009-03-17 23:32 ` Keith Coleman
0 siblings, 1 reply; 5+ messages in thread
From: Stefano Stabellini @ 2009-03-17 10:55 UTC (permalink / raw)
To: Keir Fraser; +Cc: xen-devel
[-- Attachment #1: Type: text/plain, Size: 822 bytes --]
Keir Fraser wrote:
> On 16/03/2009 11:25, "Stefano Stabellini" <stefano.stabellini@eu.citrix.com>
> wrote:
>
>> Hi all,
>> this patch is an updated version of the previous patch I sent to fix
>> the issues that currently affect fs-backend.
>> Compared to the previous version this patch is more resilient to errors
>> because it is not using sigprocmask anymore to block SIGUSR2: blocking
>> signals doesn't get along very well with glibc's aio implementation.
>> Secondly I also introduced explicit error checking on the select return
>> value, trying to recover in case of errors.
>>
>> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
>
> The patch fails to apply to xen-unstable. Perhaps it got eaten by your mail
> client?
>
Maybe.
I am attaching the patch to this email, is this any better?
[-- Attachment #2: fsback --]
[-- Type: text/plain, Size: 60904 bytes --]
diff -r 0e1449d6f231 tools/fs-back/Makefile
--- a/tools/fs-back/Makefile Fri Mar 13 10:09:25 2009 +0000
+++ b/tools/fs-back/Makefile Mon Mar 16 11:23:36 2009 +0000
@@ -16,7 +16,7 @@
LIBS := -L. -L.. -L../lib
LIBS += $(LDFLAGS_libxenctrl)
LIBS += $(LDFLAGS_libxenstore)
-LIBS += -lpthread -lrt
+LIBS += -lrt
OBJS := fs-xenbus.o fs-ops.o
diff -r 0e1449d6f231 tools/fs-back/fs-backend.c
--- a/tools/fs-back/fs-backend.c Fri Mar 13 10:09:25 2009 +0000
+++ b/tools/fs-back/fs-backend.c Mon Mar 16 11:23:36 2009 +0000
@@ -3,105 +3,71 @@
#include <string.h>
#include <assert.h>
#include <malloc.h>
-#include <pthread.h>
#include <xenctrl.h>
#include <aio.h>
#include <sys/mman.h>
#include <sys/select.h>
+#include <sys/socket.h>
#include <xen/io/ring.h>
+#include <err.h>
+#include "sys-queue.h"
#include "fs-backend.h"
+#include "fs-debug.h"
struct xs_handle *xsh = NULL;
static struct fs_export *fs_exports = NULL;
static int export_id = 0;
static int mount_id = 0;
+static int pipefds[2];
+static LIST_HEAD(mount_requests_head, fs_mount) mount_requests_head;
-static void dispatch_response(struct fs_mount *mount, int priv_req_id)
+static void free_mount_request(struct fs_mount *mount);
+
+static void dispatch_response(struct fs_request *request)
{
int i;
struct fs_op *op;
- struct fs_request *req = &mount->requests[priv_req_id];
for(i=0;;i++)
{
op = fsops[i];
/* We should dispatch a response before reaching the end of the array */
assert(op != NULL);
- if(op->type == req->req_shadow.type)
+ if(op->type == request->req_shadow.type)
{
- printf("Found op for type=%d\n", op->type);
+ FS_DEBUG("Found op for type=%d\n", op->type);
/* There needs to be a response handler */
assert(op->response_handler != NULL);
- op->response_handler(mount, req);
+ op->response_handler(request->mount, request);
break;
}
}
- req->active = 0;
- add_id_to_freelist(priv_req_id, mount->freelist);
+ request->active = 0;
+ add_id_to_freelist(request->id, request->mount->freelist);
}
-static void handle_aio_events(struct fs_mount *mount)
+static void handle_aio_event(struct fs_request *request)
{
- int fd, ret, count, i, notify;
- evtchn_port_t port;
- /* AIO control block for the evtchn file destriptor */
- struct aiocb evtchn_cb;
- const struct aiocb * cb_list[mount->nr_entries];
- int request_ids[mount->nr_entries];
+ int ret, notify;
- /* Prepare the AIO control block for evtchn */
- fd = xc_evtchn_fd(mount->evth);
- bzero(&evtchn_cb, sizeof(struct aiocb));
- evtchn_cb.aio_fildes = fd;
- evtchn_cb.aio_nbytes = sizeof(port);
- evtchn_cb.aio_buf = &port;
- assert(aio_read(&evtchn_cb) == 0);
+ FS_DEBUG("handle_aio_event: mount %s request %d\n", request->mount->frontend, request->id);
+ if (request->active < 0) {
+ request->mount->nr_entries++;
+ if (!request->mount->nr_entries)
+ free_mount_request(request->mount);
+ return;
+ }
-wait_again:
- /* Create list of active AIO requests */
- count = 0;
- for(i=0; i<mount->nr_entries; i++)
- if(mount->requests[i].active)
- {
- cb_list[count] = &mount->requests[i].aiocb;
- request_ids[count] = i;
- count++;
- }
- /* Add the event channel at the end of the list. Event channel needs to be
- * handled last as it exits this function. */
- cb_list[count] = &evtchn_cb;
- request_ids[count] = -1;
- count++;
+ ret = aio_error(&request->aiocb);
+ if(ret != EINPROGRESS && ret != ECANCELED)
+ dispatch_response(request);
- /* Block till an AIO requset finishes, or we get an event */
- while(1) {
- int ret = aio_suspend(cb_list, count, NULL);
- if (!ret)
- break;
- assert(errno == EINTR);
- }
- for(i=0; i<count; i++)
- if(aio_error(cb_list[i]) != EINPROGRESS)
- {
- if(request_ids[i] >= 0)
- dispatch_response(mount, request_ids[i]);
- else
- goto read_event_channel;
- }
-
- RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&mount->ring, notify);
- printf("Pushed responces and notify=%d\n", notify);
+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&request->mount->ring, notify);
+ FS_DEBUG("Pushed responces and notify=%d\n", notify);
if(notify)
- xc_evtchn_notify(mount->evth, mount->local_evtchn);
-
- goto wait_again;
-
-read_event_channel:
- assert(aio_return(&evtchn_cb) == sizeof(evtchn_port_t));
- assert(xc_evtchn_unmask(mount->evth, mount->local_evtchn) >= 0);
+ xc_evtchn_notify(request->mount->evth, request->mount->local_evtchn);
}
-
static void allocate_request_array(struct fs_mount *mount)
{
@@ -116,6 +82,7 @@
for(i=0; i< nr_entries; i++)
{
requests[i].active = 0;
+ requests[i].mount = mount;
add_id_to_freelist(i, freelist);
}
mount->requests = requests;
@@ -123,73 +90,91 @@
}
-static void *handle_mount(void *data)
+static void handle_mount(struct fs_mount *mount)
{
int more, notify;
- struct fs_mount *mount = (struct fs_mount *)data;
-
- printf("Starting a thread for mount: %d\n", mount->mount_id);
- allocate_request_array(mount);
+ int nr_consumed=0;
+ RING_IDX cons, rp;
+ struct fsif_request *req;
- for(;;)
+moretodo:
+ rp = mount->ring.sring->req_prod;
+ xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
+
+ while ((cons = mount->ring.req_cons) != rp)
{
- int nr_consumed=0;
- RING_IDX cons, rp;
- struct fsif_request *req;
+ int i;
+ struct fs_op *op;
- handle_aio_events(mount);
-moretodo:
- rp = mount->ring.sring->req_prod;
- xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
+ FS_DEBUG("Got a request at %d (of %d)\n",
+ cons, RING_SIZE(&mount->ring));
+ req = RING_GET_REQUEST(&mount->ring, cons);
+ FS_DEBUG("Request type=%d\n", req->type);
+ for(i=0;;i++)
+ {
+ op = fsops[i];
+ if(op == NULL)
+ {
+ /* We've reached the end of the array, no appropirate
+ * handler found. Warn, ignore and continue. */
+ FS_DEBUG("WARN: Unknown request type: %d\n", req->type);
+ mount->ring.req_cons++;
+ break;
+ }
+ if(op->type == req->type)
+ {
+ /* There needs to be a dispatch handler */
+ assert(op->dispatch_handler != NULL);
+ op->dispatch_handler(mount, req);
+ break;
+ }
+ }
- while ((cons = mount->ring.req_cons) != rp)
- {
- int i;
- struct fs_op *op;
+ nr_consumed++;
+ }
+ FS_DEBUG("Backend consumed: %d requests\n", nr_consumed);
+ RING_FINAL_CHECK_FOR_REQUESTS(&mount->ring, more);
+ if(more) goto moretodo;
- 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++)
- {
- op = fsops[i];
- if(op == NULL)
- {
- /* We've reached the end of the array, no appropirate
- * handler found. Warn, ignore and continue. */
- printf("WARN: Unknown request type: %d\n", req->type);
- mount->ring.req_cons++;
- break;
- }
- if(op->type == req->type)
- {
- /* There needs to be a dispatch handler */
- assert(op->dispatch_handler != NULL);
- op->dispatch_handler(mount, req);
- break;
- }
- }
+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&mount->ring, notify);
+ FS_DEBUG("Pushed responces and notify=%d\n", notify);
+ if(notify)
+ xc_evtchn_notify(mount->evth, mount->local_evtchn);
+}
- nr_consumed++;
+static void terminate_mount_request(struct fs_mount *mount) {
+ int count = 0, i;
+
+ FS_DEBUG("terminate_mount_request %s\n", mount->frontend);
+ xenbus_write_backend_state(mount, STATE_CLOSING);
+
+ for(i=0; i<mount->nr_entries; i++)
+ if(mount->requests[i].active) {
+ mount->requests[i].active = -1;
+ aio_cancel(mount->requests[i].aiocb.aio_fildes, &mount->requests[i].aiocb);
+ count--;
}
- printf("Backend consumed: %d requests\n", nr_consumed);
- RING_FINAL_CHECK_FOR_REQUESTS(&mount->ring, more);
- if(more) goto moretodo;
+ mount->nr_entries = count;
- RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&mount->ring, notify);
- printf("Pushed responces and notify=%d\n", notify);
- if(notify)
- xc_evtchn_notify(mount->evth, mount->local_evtchn);
- }
-
- printf("Destroying thread for mount: %d\n", mount->mount_id);
+ while (!xenbus_frontend_state_changed(mount, STATE_CLOSING));
+ xenbus_write_backend_state(mount, STATE_CLOSED);
+
xc_gnttab_munmap(mount->gnth, mount->ring.sring, 1);
xc_gnttab_close(mount->gnth);
xc_evtchn_unbind(mount->evth, mount->local_evtchn);
xc_evtchn_close(mount->evth);
+
+ if (!count)
+ free_mount_request(mount);
+}
+
+static void free_mount_request(struct fs_mount *mount) {
+ FS_DEBUG("free_mount_request %s\n", mount->frontend);
free(mount->frontend);
- pthread_exit(NULL);
+ free(mount->requests);
+ free(mount->freelist);
+ LIST_REMOVE (mount, entries);
+ free(mount);
}
static void handle_connection(int frontend_dom_id, int export_id, char *frontend)
@@ -197,12 +182,11 @@
struct fs_mount *mount;
struct fs_export *export;
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",
+ FS_DEBUG("Handling connection from dom=%d, for export=%d\n",
frontend_dom_id, export_id);
/* Try to find the export on the list */
export = fs_exports;
@@ -214,7 +198,7 @@
}
if(!export)
{
- printf("Could not find the export (the id is unknown).\n");
+ FS_DEBUG("Could not find the export (the id is unknown).\n");
return;
}
@@ -223,7 +207,7 @@
mount->export = export;
mount->mount_id = mount_id++;
xenbus_read_mount_request(mount, frontend);
- printf("Frontend found at: %s (gref=%d, evtchn=%d)\n",
+ FS_DEBUG("Frontend found at: %s (gref=%d, evtchn=%d)\n",
mount->frontend, mount->grefs[0], mount->remote_evtchn);
xenbus_write_backend_node(mount);
mount->evth = -1;
@@ -249,18 +233,24 @@
mount->nr_entries = mount->ring.nr_ents;
for (i = 0; i < MAX_FDS; i++)
mount->fds[i] = -1;
- xenbus_write_backend_ready(mount);
- pthread_create(&handling_thread, NULL, &handle_mount, mount);
+ LIST_INSERT_HEAD(&mount_requests_head, mount, entries);
+ xenbus_watch_frontend_state(mount);
+ xenbus_write_backend_state(mount, STATE_READY);
+
+ allocate_request_array(mount);
}
static void await_connections(void)
{
- int fd, ret, dom_id, export_id;
+ int fd, max_fd, ret, dom_id, export_id;
fd_set fds;
char **watch_paths;
unsigned int len;
char d;
+ struct fs_mount *pointer;
+
+ LIST_INIT (&mount_requests_head);
assert(xsh != NULL);
fd = xenbus_get_watch_fd();
@@ -268,28 +258,101 @@
do {
FD_ZERO(&fds);
FD_SET(fd, &fds);
- ret = select(fd+1, &fds, NULL, NULL, NULL);
- assert(ret == 1);
- watch_paths = xs_read_watch(xsh, &len);
- assert(len == 2);
- assert(strcmp(watch_paths[1], "conn-watch") == 0);
- dom_id = -1;
- export_id = -1;
- d = 0;
- printf("Path changed %s\n", watch_paths[0]);
- sscanf(watch_paths[0], WATCH_NODE"/%d/%d/fronten%c",
- &dom_id, &export_id, &d);
- if((dom_id >= 0) && (export_id >= 0) && d == 'd') {
- char *frontend = xs_read(xsh, XBT_NULL, watch_paths[0], NULL);
- if (frontend) {
- handle_connection(dom_id, export_id, frontend);
- xs_rm(xsh, XBT_NULL, watch_paths[0]);
- }
- }
-next_select:
- printf("Awaiting next connection.\n");
- /* TODO - we need to figure out what to free */
- free(watch_paths);
+ FD_SET(pipefds[0], &fds);
+ max_fd = fd > pipefds[0] ? fd : pipefds[0];
+ LIST_FOREACH(pointer, &mount_requests_head, entries) {
+ int tfd = xc_evtchn_fd(pointer->evth);
+ FD_SET(tfd, &fds);
+ if (tfd > max_fd) max_fd = tfd;
+ }
+ ret = select(max_fd+1, &fds, NULL, NULL, NULL);
+ if (ret < 0) {
+ if (errno == EINTR) continue;
+ /* try to recover */
+ else if (errno == EBADF) {
+ struct timeval timeout;
+ memset(&timeout, 0x00, sizeof(timeout));
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ FD_SET(pipefds[0], &fds);
+ max_fd = fd > pipefds[0] ? fd : pipefds[0];
+ ret = select(max_fd + 1, &fds, NULL, NULL, &timeout);
+ if (ret < 0)
+ err(1, "select: unrecoverable error occurred: %d\n", errno);
+
+ /* trying to find the bogus fd among the open event channels */
+ LIST_FOREACH(pointer, &mount_requests_head, entries) {
+ int tfd = xc_evtchn_fd(pointer->evth);
+ memset(&timeout, 0x00, sizeof(timeout));
+ FD_ZERO(&fds);
+ FD_SET(tfd, &fds);
+ ret = select(tfd + 1, &fds, NULL, NULL, &timeout);
+ if (ret < 0) {
+ FS_DEBUG("fd %d is bogus, closing the related connection\n", tfd);
+ pointer->evth = fd;
+ terminate_mount_request(pointer);
+ continue;
+ }
+ }
+ continue;
+ } else
+ err(1, "select: unrecoverable error occurred: %d\n", errno);
+ }
+ if (FD_ISSET(fd, &fds)) {
+ watch_paths = xs_read_watch(xsh, &len);
+ if (!strcmp(watch_paths[XS_WATCH_TOKEN], "conn-watch")) {
+ dom_id = -1;
+ export_id = -1;
+ d = 0;
+ FS_DEBUG("Path changed %s\n", watch_paths[0]);
+ sscanf(watch_paths[XS_WATCH_PATH], WATCH_NODE"/%d/%d/fronten%c",
+ &dom_id, &export_id, &d);
+ if((dom_id >= 0) && (export_id >= 0) && d == 'd') {
+ char *frontend = xs_read(xsh, XBT_NULL, watch_paths[XS_WATCH_PATH], NULL);
+ if (frontend) {
+ handle_connection(dom_id, export_id, frontend);
+ xs_rm(xsh, XBT_NULL, watch_paths[XS_WATCH_PATH]);
+ }
+ }
+ } else if (!strcmp(watch_paths[XS_WATCH_TOKEN], "frontend-state")) {
+ LIST_FOREACH(pointer, &mount_requests_head, entries) {
+ if (!strncmp(pointer->frontend, watch_paths[XS_WATCH_PATH], strlen(pointer->frontend))) {
+ char *state = xenbus_read_frontend_state(pointer);
+ if (!state || strcmp(state, STATE_READY)) {
+ xenbus_unwatch_frontend_state(pointer);
+ terminate_mount_request(pointer);
+ }
+ free(state);
+ break;
+ }
+ }
+ } else {
+ FS_DEBUG("xenstore watch event unrecognized\n");
+ }
+ FS_DEBUG("Awaiting next connection.\n");
+ /* TODO - we need to figure out what to free */
+ free(watch_paths);
+ }
+ if (FD_ISSET(pipefds[0], &fds)) {
+ struct fs_request *request;
+ int ret;
+ ret = read(pipefds[0], &request, sizeof(struct fs_request *));
+ if (ret != sizeof(struct fs_request *)) {
+ fprintf(stderr, "read request failed\n");
+ continue;
+ }
+ handle_aio_event(request);
+ }
+ LIST_FOREACH(pointer, &mount_requests_head, entries) {
+ if (FD_ISSET(xc_evtchn_fd(pointer->evth), &fds)) {
+ evtchn_port_t port;
+ port = xc_evtchn_pending(pointer->evth);
+ if (port != -1) {
+ handle_mount(pointer);
+ xc_evtchn_unmask(pointer->evth, port);
+ }
+ }
+ }
} while (1);
}
@@ -312,10 +375,28 @@
return curr_export;
}
+static void aio_signal_handler(int signo, siginfo_t *info, void *context)
+{
+ struct fs_request *request = (struct fs_request*) info->si_value.sival_ptr;
+ int saved_errno = errno;
+ write(pipefds[1], &request, sizeof(struct fs_request *));
+ errno = saved_errno;
+}
int main(void)
{
struct fs_export *export;
+ struct sigaction act;
+ sigset_t enable;
+
+ sigemptyset(&enable);
+ sigaddset(&enable, SIGUSR2);
+ pthread_sigmask(SIG_UNBLOCK, &enable, NULL);
+
+ sigfillset(&act.sa_mask);
+ act.sa_flags = SA_SIGINFO; /* do not restart syscalls to interrupt select(); use sa_sigaction */
+ act.sa_sigaction = aio_signal_handler;
+ sigaction(SIGUSR2, &act, NULL);
/* Open the connection to XenStore first */
xsh = xs_domain_open();
@@ -327,6 +408,9 @@
/* Create & register the default export */
export = create_export("default", "/exports");
xenbus_register_export(export);
+
+ if (socketpair(PF_UNIX,SOCK_STREAM, 0, pipefds) == -1)
+ err(1, "failed to create pipe\n");
await_connections();
/* Close the connection to XenStore when we are finished with everything */
diff -r 0e1449d6f231 tools/fs-back/fs-backend.h
--- a/tools/fs-back/fs-backend.h Fri Mar 13 10:09:25 2009 +0000
+++ b/tools/fs-back/fs-backend.h Mon Mar 16 11:23:36 2009 +0000
@@ -7,6 +7,7 @@
#include <xen/event_channel.h>
#include <xen/io/ring.h>
#include <xen/io/fsif.h>
+#include "sys-queue.h"
#define ROOT_NODE "backend/vfs"
#define EXPORTS_SUBNODE "exports"
@@ -25,6 +26,8 @@
struct fs_request
{
+ struct fs_mount *mount;
+ int id;
int active;
void *page; /* Pointer to mapped grant */
int count;
@@ -50,6 +53,7 @@
struct fs_request *requests;
unsigned short *freelist;
int fds[MAX_FDS];
+ LIST_ENTRY(fs_mount) entries;
};
@@ -61,7 +65,11 @@
int xenbus_get_watch_fd(void);
void xenbus_read_mount_request(struct fs_mount *mount, char *frontend);
void xenbus_write_backend_node(struct fs_mount *mount);
-void xenbus_write_backend_ready(struct fs_mount *mount);
+void xenbus_write_backend_state(struct fs_mount *mount, const char *state);
+int xenbus_frontend_state_changed(struct fs_mount *mount, const char *oldstate);
+void xenbus_watch_frontend_state(struct fs_mount *mount);
+void xenbus_unwatch_frontend_state(struct fs_mount *mount);
+char* xenbus_read_frontend_state(struct fs_mount *mount);
/* File operations, implemented in fs-ops.c */
struct fs_op
diff -r 0e1449d6f231 tools/fs-back/fs-debug.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/fs-back/fs-debug.h Mon Mar 16 11:23:36 2009 +0000
@@ -0,0 +1,12 @@
+#ifndef __FS_DEBUG__
+#define __FS_DEBUG__
+
+// #define DEBUG 1
+
+#ifdef DEBUG
+#define FS_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define FS_DEBUG(fmt, ...) do { } while (0)
+#endif
+
+#endif /*__FS_DEBUG__*/
diff -r 0e1449d6f231 tools/fs-back/fs-ops.c
--- a/tools/fs-back/fs-ops.c Fri Mar 13 10:09:25 2009 +0000
+++ b/tools/fs-back/fs-ops.c Mon Mar 16 11:23:36 2009 +0000
@@ -14,6 +14,7 @@
#include <sys/mount.h>
#include <unistd.h>
#include "fs-backend.h"
+#include "fs-debug.h"
/* For debugging only */
#include <sys/time.h>
@@ -22,12 +23,11 @@
#define BUFFER_SIZE 1024
-
static unsigned short get_request(struct fs_mount *mount, struct fsif_request *req)
{
unsigned short id = get_id_from_freelist(mount->freelist);
- printf("Private Request id: %d\n", id);
+ FS_DEBUG("Private Request id: %d\n", id);
memcpy(&mount->requests[id].req_shadow, req, sizeof(struct fsif_request));
mount->requests[id].active = 1;
@@ -54,7 +54,7 @@
fsif_response_t *rsp;
uint16_t req_id;
- printf("Dispatching file open operation (gref=%d).\n", req->u.fopen.gref);
+ FS_DEBUG("Dispatching file open operation (gref=%d).\n", req->u.fopen.gref);
/* Read the request, and open file */
file_name = xc_gnttab_map_grant_ref(mount->gnth,
mount->dom_id,
@@ -62,13 +62,13 @@
PROT_READ);
req_id = req->id;
- printf("File open issued for %s\n", file_name);
+ FS_DEBUG("File open issued for %s\n", file_name);
assert(BUFFER_SIZE >
strlen(file_name) + strlen(mount->export->export_path) + 1);
snprintf(full_path, sizeof(full_path), "%s/%s",
mount->export->export_path, file_name);
assert(xc_gnttab_munmap(mount->gnth, file_name, 1) == 0);
- printf("Issuing open for %s\n", full_path);
+ FS_DEBUG("Issuing open for %s\n", full_path);
fd = get_fd(mount);
if (fd >= 0) {
int real_fd = open(full_path, O_RDWR);
@@ -77,7 +77,7 @@
else
{
mount->fds[fd] = real_fd;
- printf("Got FD: %d for real %d\n", fd, real_fd);
+ FS_DEBUG("Got FD: %d for real %d\n", fd, real_fd);
}
}
/* We can advance the request consumer index, from here on, the request
@@ -87,7 +87,7 @@
/* 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);
+ FS_DEBUG("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)fd;
@@ -100,7 +100,7 @@
fsif_response_t *rsp;
uint16_t req_id;
- printf("Dispatching file close operation (fd=%d).\n", req->u.fclose.fd);
+ FS_DEBUG("Dispatching file close operation (fd=%d).\n", req->u.fclose.fd);
req_id = req->id;
if (req->u.fclose.fd < MAX_FDS) {
@@ -109,7 +109,7 @@
mount->fds[req->u.fclose.fd] = -1;
} else
ret = -1;
- printf("Got ret: %d\n", ret);
+ FS_DEBUG("Got ret: %d\n", ret);
/* We can advance the request consumer index, from here on, the request
* should not be used (it may be overrinden by a response) */
mount->ring.req_cons++;
@@ -117,7 +117,7 @@
/* 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);
+ FS_DEBUG("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;
@@ -143,7 +143,7 @@
PROT_WRITE);
req_id = req->id;
- printf("File read issued for FD=%d (len=%"PRIu64", offest=%"PRIu64")\n",
+ FS_DEBUG("File read issued for FD=%d (len=%"PRIu64", offest=%"PRIu64")\n",
req->u.fread.fd, req->u.fread.len, req->u.fread.offset);
if (req->u.fread.fd < MAX_FDS)
@@ -152,10 +152,11 @@
fd = -1;
priv_id = get_request(mount, req);
- printf("Private id is: %d\n", priv_id);
+ FS_DEBUG("Private id is: %d\n", priv_id);
priv_req = &mount->requests[priv_id];
priv_req->page = buf;
priv_req->count = count;
+ priv_req->id = priv_id;
/* Dispatch AIO read request */
bzero(&priv_req->aiocb, sizeof(struct aiocb));
@@ -163,6 +164,9 @@
priv_req->aiocb.aio_nbytes = req->u.fread.len;
priv_req->aiocb.aio_offset = req->u.fread.offset;
priv_req->aiocb.aio_buf = buf;
+ priv_req->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
+ priv_req->aiocb.aio_sigevent.sigev_signo = SIGUSR2;
+ priv_req->aiocb.aio_sigevent.sigev_value.sival_ptr = priv_req;
assert(aio_read(&priv_req->aiocb) >= 0);
out:
@@ -185,7 +189,7 @@
/* Get a response from the ring */
rsp_idx = mount->ring.rsp_prod_pvt++;
req_id = priv_req->req_shadow.id;
- printf("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
+ FS_DEBUG("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)aio_return(&priv_req->aiocb);
@@ -210,7 +214,7 @@
PROT_READ);
req_id = req->id;
- printf("File write issued for FD=%d (len=%"PRIu64", offest=%"PRIu64")\n",
+ FS_DEBUG("File write issued for FD=%d (len=%"PRIu64", offest=%"PRIu64")\n",
req->u.fwrite.fd, req->u.fwrite.len, req->u.fwrite.offset);
if (req->u.fwrite.fd < MAX_FDS)
@@ -219,10 +223,11 @@
fd = -1;
priv_id = get_request(mount, req);
- printf("Private id is: %d\n", priv_id);
+ FS_DEBUG("Private id is: %d\n", priv_id);
priv_req = &mount->requests[priv_id];
priv_req->page = buf;
priv_req->count = count;
+ priv_req->id = priv_id;
/* Dispatch AIO write request */
bzero(&priv_req->aiocb, sizeof(struct aiocb));
@@ -230,6 +235,9 @@
priv_req->aiocb.aio_nbytes = req->u.fwrite.len;
priv_req->aiocb.aio_offset = req->u.fwrite.offset;
priv_req->aiocb.aio_buf = buf;
+ priv_req->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
+ priv_req->aiocb.aio_sigevent.sigev_signo = SIGUSR2;
+ priv_req->aiocb.aio_sigevent.sigev_value.sival_ptr = priv_req;
assert(aio_write(&priv_req->aiocb) >= 0);
@@ -252,7 +260,7 @@
/* Get a response from the ring */
rsp_idx = mount->ring.rsp_prod_pvt++;
req_id = priv_req->req_shadow.id;
- printf("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
+ FS_DEBUG("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)aio_return(&priv_req->aiocb);
@@ -273,7 +281,7 @@
else
fd = -1;
- printf("File stat issued for FD=%d\n", req->u.fstat.fd);
+ FS_DEBUG("File stat issued for FD=%d\n", req->u.fstat.fd);
/* We can advance the request consumer index, from here on, the request
* should not be used (it may be overrinden by a response) */
@@ -281,12 +289,12 @@
/* Stat, and create the response */
ret = fstat(fd, &stat);
- printf("Mode=%o, uid=%d, a_time=%ld\n",
+ FS_DEBUG("Mode=%o, uid=%d, a_time=%ld\n",
stat.st_mode, stat.st_uid, (long)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);
+ FS_DEBUG("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;
@@ -320,7 +328,7 @@
req_id = req->id;
length = req->u.ftruncate.length;
- printf("File truncate issued for FD=%d, length=%"PRId64"\n", req->u.ftruncate.fd, length);
+ FS_DEBUG("File truncate issued for FD=%d, length=%"PRId64"\n", req->u.ftruncate.fd, length);
if (req->u.ftruncate.fd < MAX_FDS)
fd = mount->fds[req->u.ftruncate.fd];
@@ -336,7 +344,7 @@
/* 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);
+ FS_DEBUG("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;
@@ -350,7 +358,7 @@
fsif_response_t *rsp;
uint16_t req_id;
- printf("Dispatching remove operation (gref=%d).\n", req->u.fremove.gref);
+ FS_DEBUG("Dispatching remove operation (gref=%d).\n", req->u.fremove.gref);
/* Read the request, and open file */
file_name = xc_gnttab_map_grant_ref(mount->gnth,
mount->dom_id,
@@ -358,15 +366,15 @@
PROT_READ);
req_id = req->id;
- printf("File remove issued for %s\n", file_name);
+ FS_DEBUG("File remove issued for %s\n", file_name);
assert(BUFFER_SIZE >
strlen(file_name) + strlen(mount->export->export_path) + 1);
snprintf(full_path, sizeof(full_path), "%s/%s",
mount->export->export_path, file_name);
assert(xc_gnttab_munmap(mount->gnth, file_name, 1) == 0);
- printf("Issuing remove for %s\n", full_path);
+ FS_DEBUG("Issuing remove for %s\n", full_path);
ret = remove(full_path);
- printf("Got ret: %d\n", ret);
+ FS_DEBUG("Got ret: %d\n", ret);
/* We can advance the request consumer index, from here on, the request
* should not be used (it may be overrinden by a response) */
mount->ring.req_cons++;
@@ -374,7 +382,7 @@
/* 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);
+ FS_DEBUG("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;
@@ -390,7 +398,7 @@
fsif_response_t *rsp;
uint16_t req_id;
- printf("Dispatching rename operation (gref=%d).\n", req->u.fremove.gref);
+ FS_DEBUG("Dispatching rename operation (gref=%d).\n", req->u.fremove.gref);
/* Read the request, and open file */
buf = xc_gnttab_map_grant_ref(mount->gnth,
mount->dom_id,
@@ -400,7 +408,7 @@
req_id = req->id;
old_file_name = buf + req->u.frename.old_name_offset;
new_file_name = buf + req->u.frename.new_name_offset;
- printf("File rename issued for %s -> %s (buf=%s)\n",
+ FS_DEBUG("File rename issued for %s -> %s (buf=%s)\n",
old_file_name, new_file_name, buf);
assert(BUFFER_SIZE >
strlen(old_file_name) + strlen(mount->export->export_path) + 1);
@@ -411,9 +419,9 @@
snprintf(new_full_path, sizeof(new_full_path), "%s/%s",
mount->export->export_path, new_file_name);
assert(xc_gnttab_munmap(mount->gnth, buf, 1) == 0);
- printf("Issuing rename for %s -> %s\n", old_full_path, new_full_path);
+ FS_DEBUG("Issuing rename for %s -> %s\n", old_full_path, new_full_path);
ret = rename(old_full_path, new_full_path);
- printf("Got ret: %d\n", ret);
+ FS_DEBUG("Got ret: %d\n", ret);
/* We can advance the request consumer index, from here on, the request
* should not be used (it may be overrinden by a response) */
mount->ring.req_cons++;
@@ -421,7 +429,7 @@
/* 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);
+ FS_DEBUG("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;
@@ -438,7 +446,7 @@
fsif_response_t *rsp;
uint16_t req_id;
- printf("Dispatching file create operation (gref=%d).\n", req->u.fcreate.gref);
+ FS_DEBUG("Dispatching file create operation (gref=%d).\n", req->u.fcreate.gref);
/* Read the request, and create file/directory */
mode = req->u.fcreate.mode;
directory = req->u.fcreate.directory;
@@ -448,7 +456,7 @@
PROT_READ);
req_id = req->id;
- printf("File create issued for %s\n", file_name);
+ FS_DEBUG("File create issued for %s\n", file_name);
assert(BUFFER_SIZE >
strlen(file_name) + strlen(mount->export->export_path) + 1);
snprintf(full_path, sizeof(full_path), "%s/%s",
@@ -460,12 +468,12 @@
if(directory)
{
- printf("Issuing create for directory: %s\n", full_path);
+ FS_DEBUG("Issuing create for directory: %s\n", full_path);
ret = mkdir(full_path, mode);
}
else
{
- printf("Issuing create for file: %s\n", full_path);
+ FS_DEBUG("Issuing create for file: %s\n", full_path);
ret = get_fd(mount);
if (ret >= 0) {
int real_fd = creat(full_path, mode);
@@ -474,15 +482,15 @@
else
{
mount->fds[ret] = real_fd;
- printf("Got FD: %d for real %d\n", ret, real_fd);
+ FS_DEBUG("Got FD: %d for real %d\n", ret, real_fd);
}
}
}
- printf("Got ret %d (errno=%d)\n", ret, errno);
+ FS_DEBUG("Got ret %d (errno=%d)\n", ret, errno);
/* 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);
+ FS_DEBUG("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;
@@ -499,7 +507,7 @@
DIR *dir;
struct dirent *dirent = NULL;
- printf("Dispatching list operation (gref=%d).\n", req->u.flist.gref);
+ FS_DEBUG("Dispatching list operation (gref=%d).\n", req->u.flist.gref);
/* Read the request, and list directory */
offset = req->u.flist.offset;
buf = file_name = xc_gnttab_map_grant_ref(mount->gnth,
@@ -508,7 +516,7 @@
PROT_READ | PROT_WRITE);
req_id = req->id;
- printf("Dir list issued for %s\n", file_name);
+ FS_DEBUG("Dir list issued for %s\n", file_name);
assert(BUFFER_SIZE >
strlen(file_name) + strlen(mount->export->export_path) + 1);
snprintf(full_path, sizeof(full_path), "%s/%s",
@@ -552,7 +560,7 @@
/* 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);
+ FS_DEBUG("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 = ret_val;
@@ -566,7 +574,7 @@
uint16_t req_id;
int32_t mode;
- printf("Dispatching file chmod operation (fd=%d, mode=%o).\n",
+ FS_DEBUG("Dispatching file chmod operation (fd=%d, mode=%o).\n",
req->u.fchmod.fd, req->u.fchmod.mode);
req_id = req->id;
if (req->u.fchmod.fd < MAX_FDS)
@@ -583,7 +591,7 @@
/* 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);
+ FS_DEBUG("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;
@@ -598,7 +606,7 @@
struct statvfs stat;
int64_t ret;
- printf("Dispatching fs space operation (gref=%d).\n", req->u.fspace.gref);
+ FS_DEBUG("Dispatching fs space operation (gref=%d).\n", req->u.fspace.gref);
/* Read the request, and open file */
file_name = xc_gnttab_map_grant_ref(mount->gnth,
mount->dom_id,
@@ -606,13 +614,13 @@
PROT_READ);
req_id = req->id;
- printf("Fs space issued for %s\n", file_name);
+ FS_DEBUG("Fs space issued for %s\n", file_name);
assert(BUFFER_SIZE >
strlen(file_name) + strlen(mount->export->export_path) + 1);
snprintf(full_path, sizeof(full_path), "%s/%s",
mount->export->export_path, file_name);
assert(xc_gnttab_munmap(mount->gnth, file_name, 1) == 0);
- printf("Issuing fs space for %s\n", full_path);
+ FS_DEBUG("Issuing fs space for %s\n", full_path);
ret = statvfs(full_path, &stat);
if(ret >= 0)
ret = stat.f_bsize * stat.f_bfree;
@@ -624,7 +632,7 @@
/* 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);
+ FS_DEBUG("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;
@@ -643,15 +651,19 @@
else
fd = -1;
- printf("File sync issued for FD=%d\n", req->u.fsync.fd);
+ FS_DEBUG("File sync issued for FD=%d\n", req->u.fsync.fd);
priv_id = get_request(mount, req);
- printf("Private id is: %d\n", priv_id);
+ FS_DEBUG("Private id is: %d\n", priv_id);
priv_req = &mount->requests[priv_id];
+ priv_req->id = priv_id;
/* Dispatch AIO read request */
bzero(&priv_req->aiocb, sizeof(struct aiocb));
priv_req->aiocb.aio_fildes = fd;
+ priv_req->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
+ priv_req->aiocb.aio_sigevent.sigev_signo = SIGUSR2;
+ priv_req->aiocb.aio_sigevent.sigev_value.sival_ptr = priv_req;
assert(aio_fsync(O_SYNC, &priv_req->aiocb) >= 0);
@@ -669,7 +681,7 @@
/* Get a response from the ring */
rsp_idx = mount->ring.rsp_prod_pvt++;
req_id = priv_req->req_shadow.id;
- printf("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
+ FS_DEBUG("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)aio_return(&priv_req->aiocb);
diff -r 0e1449d6f231 tools/fs-back/fs-xenbus.c
--- a/tools/fs-back/fs-xenbus.c Fri Mar 13 10:09:25 2009 +0000
+++ b/tools/fs-back/fs-xenbus.c Mon Mar 16 11:23:36 2009 +0000
@@ -4,10 +4,12 @@
#include <stdarg.h>
#include <string.h>
#include <assert.h>
+#include <sys/select.h>
#include <xenctrl.h>
#include <xs.h>
#include <xen/io/fsif.h>
#include "fs-backend.h"
+#include "fs-debug.h"
static bool xenbus_printf(struct xs_handle *xsh,
@@ -25,7 +27,7 @@
snprintf(fullpath, sizeof(fullpath), "%s/%s", node, path);
vsnprintf(val, sizeof(val), fmt, args);
va_end(args);
- printf("xenbus_printf (%s) <= %s.\n", fullpath, val);
+ FS_DEBUG("xenbus_printf (%s) <= %s.\n", fullpath, val);
return xs_write(xsh, xbt, fullpath, val, strlen(val));
}
@@ -57,19 +59,19 @@
assert(xsh != NULL);
if(xsh == NULL)
{
- printf("Could not open connection to xenbus deamon.\n");
+ FS_DEBUG("Could not open connection to xenbus deamon.\n");
goto error_exit;
}
- printf("Connection to the xenbus deamon opened successfully.\n");
+ FS_DEBUG("Connection to the xenbus deamon opened successfully.\n");
/* Start transaction */
xst = xs_transaction_start(xsh);
if(xst == 0)
{
- printf("Could not start a transaction.\n");
+ FS_DEBUG("Could not start a transaction.\n");
goto error_exit;
}
- printf("XS transaction is %d\n", xst);
+ FS_DEBUG("XS transaction is %d\n", xst);
/* Create node string */
snprintf(node, sizeof(node), "%s/%d", EXPORTS_NODE, export->export_id);
@@ -78,7 +80,7 @@
if(!xenbus_printf(xsh, xst, node, "name", "%s", export->name))
{
- printf("Could not write the export node.\n");
+ FS_DEBUG("Could not write the export node.\n");
goto error_exit;
}
@@ -87,7 +89,7 @@
perms.perms = XS_PERM_READ;
if(!xs_set_permissions(xsh, xst, EXPORTS_NODE, &perms, 1))
{
- printf("Could not set permissions on the export node.\n");
+ FS_DEBUG("Could not set permissions on the export node.\n");
goto error_exit;
}
@@ -166,7 +168,7 @@
assert(xsh != NULL);
self_id = get_self_id();
- printf("Our own dom_id=%d\n", self_id);
+ FS_DEBUG("Our own dom_id=%d\n", self_id);
snprintf(node, sizeof(node), "%s/backend", mount->frontend);
snprintf(backend_node, sizeof(backend_node), "/local/domain/%d/"ROOT_NODE"/%d",
self_id, mount->mount_id);
@@ -176,7 +178,7 @@
xs_write(xsh, XBT_NULL, node, STATE_INITIALISED, strlen(STATE_INITIALISED));
}
-void xenbus_write_backend_ready(struct fs_mount *mount)
+void xenbus_write_backend_state(struct fs_mount *mount, const char *state)
{
char node[1024];
int self_id;
@@ -184,6 +186,59 @@
assert(xsh != NULL);
self_id = get_self_id();
snprintf(node, sizeof(node), ROOT_NODE"/%d/state", mount->mount_id);
- xs_write(xsh, XBT_NULL, node, STATE_READY, strlen(STATE_READY));
+ xs_write(xsh, XBT_NULL, node, state, strlen(state));
}
+void xenbus_watch_frontend_state(struct fs_mount *mount)
+{
+ int res;
+ char statepath[1024];
+
+ assert(xsh != NULL);
+ snprintf(statepath, sizeof(statepath), "%s/state", mount->frontend);
+ res = xs_watch(xsh, statepath, "frontend-state");
+ assert(res);
+}
+
+void xenbus_unwatch_frontend_state(struct fs_mount *mount)
+{
+ int res;
+ char statepath[1024];
+
+ assert(xsh != NULL);
+ snprintf(statepath, sizeof(statepath), "%s/state", mount->frontend);
+ res = xs_unwatch(xsh, statepath, "frontend-state");
+ assert(res);
+}
+
+int xenbus_frontend_state_changed(struct fs_mount *mount, const char *oldstate)
+{
+ unsigned int len;
+ char statepath[1024];
+ char *state = NULL;
+
+ assert(xsh != NULL);
+ snprintf(statepath, sizeof(statepath), "%s/state", mount->frontend);
+ state = xs_read(xsh, XBT_NULL, statepath, &len);
+ if (state && len > 0) {
+ if (strcmp(state, oldstate)) {
+ free(state);
+ return 1;
+ } else {
+ free(state);
+ return 0;
+ }
+ } else
+ return 1;
+}
+
+char* xenbus_read_frontend_state(struct fs_mount *mount)
+{
+ unsigned int len;
+ char statepath[1024];
+
+ assert(xsh != NULL);
+ snprintf(statepath, sizeof(statepath), "%s/state", mount->frontend);
+ return xs_read(xsh, XBT_NULL, statepath, &len);
+}
+
diff -r 0e1449d6f231 tools/fs-back/sys-queue.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/fs-back/sys-queue.h Mon Mar 16 11:23:36 2009 +0000
@@ -0,0 +1,338 @@
+/* $NetBSD: queue.h,v 1.45.14.1 2007/07/18 20:13:24 liamjfoy Exp $ */
+
+/*
+ * Qemu version: Copy from netbsd, removed debug code, removed some of
+ * the implementations. Left in lists, tail queues and circular queues.
+ */
+
+/*
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef _SYS_QUEUE_H_
+#define _SYS_QUEUE_H_
+
+/*
+ * This file defines three types of data structures:
+ * lists, tail queues, and circular queues.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+/*
+ * List definitions.
+ */
+#define LIST_HEAD(name, type) \
+struct name { \
+ struct type *lh_first; /* first element */ \
+}
+
+#define LIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define LIST_ENTRY(type) \
+struct { \
+ struct type *le_next; /* next element */ \
+ struct type **le_prev; /* address of previous next element */ \
+}
+
+/*
+ * List functions.
+ */
+#define LIST_INIT(head) do { \
+ (head)->lh_first = NULL; \
+} while (/*CONSTCOND*/0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) do { \
+ if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
+ (listelm)->field.le_next->field.le_prev = \
+ &(elm)->field.le_next; \
+ (listelm)->field.le_next = (elm); \
+ (elm)->field.le_prev = &(listelm)->field.le_next; \
+} while (/*CONSTCOND*/0)
+
+#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.le_prev = (listelm)->field.le_prev; \
+ (elm)->field.le_next = (listelm); \
+ *(listelm)->field.le_prev = (elm); \
+ (listelm)->field.le_prev = &(elm)->field.le_next; \
+} while (/*CONSTCOND*/0)
+
+#define LIST_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.le_next = (head)->lh_first) != NULL) \
+ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+ (head)->lh_first = (elm); \
+ (elm)->field.le_prev = &(head)->lh_first; \
+} while (/*CONSTCOND*/0)
+
+#define LIST_REMOVE(elm, field) do { \
+ if ((elm)->field.le_next != NULL) \
+ (elm)->field.le_next->field.le_prev = \
+ (elm)->field.le_prev; \
+ *(elm)->field.le_prev = (elm)->field.le_next; \
+} while (/*CONSTCOND*/0)
+
+#define LIST_FOREACH(var, head, field) \
+ for ((var) = ((head)->lh_first); \
+ (var); \
+ (var) = ((var)->field.le_next))
+
+/*
+ * List access methods.
+ */
+#define LIST_EMPTY(head) ((head)->lh_first == NULL)
+#define LIST_FIRST(head) ((head)->lh_first)
+#define LIST_NEXT(elm, field) ((elm)->field.le_next)
+
+
+/*
+ * Tail queue definitions.
+ */
+#define _TAILQ_HEAD(name, type, qual) \
+struct name { \
+ qual type *tqh_first; /* first element */ \
+ qual type *qual *tqh_last; /* addr of last next element */ \
+}
+#define TAILQ_HEAD(name, type) _TAILQ_HEAD(name, struct type,)
+
+#define TAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).tqh_first }
+
+#define _TAILQ_ENTRY(type, qual) \
+struct { \
+ qual type *tqe_next; /* next element */ \
+ qual type *qual *tqe_prev; /* address of previous next element */\
+}
+#define TAILQ_ENTRY(type) _TAILQ_ENTRY(struct type,)
+
+/*
+ * Tail queue functions.
+ */
+#define TAILQ_INIT(head) do { \
+ (head)->tqh_first = NULL; \
+ (head)->tqh_last = &(head)->tqh_first; \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
+ (head)->tqh_first->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (head)->tqh_first = (elm); \
+ (elm)->field.tqe_prev = &(head)->tqh_first; \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.tqe_next = NULL; \
+ (elm)->field.tqe_prev = (head)->tqh_last; \
+ *(head)->tqh_last = (elm); \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+ (elm)->field.tqe_next->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (listelm)->field.tqe_next = (elm); \
+ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
+ (elm)->field.tqe_next = (listelm); \
+ *(listelm)->field.tqe_prev = (elm); \
+ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_REMOVE(head, elm, field) do { \
+ if (((elm)->field.tqe_next) != NULL) \
+ (elm)->field.tqe_next->field.tqe_prev = \
+ (elm)->field.tqe_prev; \
+ else \
+ (head)->tqh_last = (elm)->field.tqe_prev; \
+ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_FOREACH(var, head, field) \
+ for ((var) = ((head)->tqh_first); \
+ (var); \
+ (var) = ((var)->field.tqe_next))
+
+#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
+ for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last)); \
+ (var); \
+ (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last)))
+
+/*
+ * Tail queue access methods.
+ */
+#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
+#define TAILQ_FIRST(head) ((head)->tqh_first)
+#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+
+#define TAILQ_LAST(head, headname) \
+ (*(((struct headname *)((head)->tqh_last))->tqh_last))
+#define TAILQ_PREV(elm, headname, field) \
+ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+
+
+/*
+ * Circular queue definitions.
+ */
+#define CIRCLEQ_HEAD(name, type) \
+struct name { \
+ struct type *cqh_first; /* first element */ \
+ struct type *cqh_last; /* last element */ \
+}
+
+#define CIRCLEQ_HEAD_INITIALIZER(head) \
+ { (void *)&head, (void *)&head }
+
+#define CIRCLEQ_ENTRY(type) \
+struct { \
+ struct type *cqe_next; /* next element */ \
+ struct type *cqe_prev; /* previous element */ \
+}
+
+/*
+ * Circular queue functions.
+ */
+#define CIRCLEQ_INIT(head) do { \
+ (head)->cqh_first = (void *)(head); \
+ (head)->cqh_last = (void *)(head); \
+} while (/*CONSTCOND*/0)
+
+#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ (elm)->field.cqe_next = (listelm)->field.cqe_next; \
+ (elm)->field.cqe_prev = (listelm); \
+ if ((listelm)->field.cqe_next == (void *)(head)) \
+ (head)->cqh_last = (elm); \
+ else \
+ (listelm)->field.cqe_next->field.cqe_prev = (elm); \
+ (listelm)->field.cqe_next = (elm); \
+} while (/*CONSTCOND*/0)
+
+#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
+ (elm)->field.cqe_next = (listelm); \
+ (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
+ if ((listelm)->field.cqe_prev == (void *)(head)) \
+ (head)->cqh_first = (elm); \
+ else \
+ (listelm)->field.cqe_prev->field.cqe_next = (elm); \
+ (listelm)->field.cqe_prev = (elm); \
+} while (/*CONSTCOND*/0)
+
+#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
+ (elm)->field.cqe_next = (head)->cqh_first; \
+ (elm)->field.cqe_prev = (void *)(head); \
+ if ((head)->cqh_last == (void *)(head)) \
+ (head)->cqh_last = (elm); \
+ else \
+ (head)->cqh_first->field.cqe_prev = (elm); \
+ (head)->cqh_first = (elm); \
+} while (/*CONSTCOND*/0)
+
+#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.cqe_next = (void *)(head); \
+ (elm)->field.cqe_prev = (head)->cqh_last; \
+ if ((head)->cqh_first == (void *)(head)) \
+ (head)->cqh_first = (elm); \
+ else \
+ (head)->cqh_last->field.cqe_next = (elm); \
+ (head)->cqh_last = (elm); \
+} while (/*CONSTCOND*/0)
+
+#define CIRCLEQ_REMOVE(head, elm, field) do { \
+ if ((elm)->field.cqe_next == (void *)(head)) \
+ (head)->cqh_last = (elm)->field.cqe_prev; \
+ else \
+ (elm)->field.cqe_next->field.cqe_prev = \
+ (elm)->field.cqe_prev; \
+ if ((elm)->field.cqe_prev == (void *)(head)) \
+ (head)->cqh_first = (elm)->field.cqe_next; \
+ else \
+ (elm)->field.cqe_prev->field.cqe_next = \
+ (elm)->field.cqe_next; \
+} while (/*CONSTCOND*/0)
+
+#define CIRCLEQ_FOREACH(var, head, field) \
+ for ((var) = ((head)->cqh_first); \
+ (var) != (const void *)(head); \
+ (var) = ((var)->field.cqe_next))
+
+#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
+ for ((var) = ((head)->cqh_last); \
+ (var) != (const void *)(head); \
+ (var) = ((var)->field.cqe_prev))
+
+/*
+ * Circular queue access methods.
+ */
+#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head))
+#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
+#define CIRCLEQ_LAST(head) ((head)->cqh_last)
+#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
+#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
+
+#define CIRCLEQ_LOOP_NEXT(head, elm, field) \
+ (((elm)->field.cqe_next == (void *)(head)) \
+ ? ((head)->cqh_first) \
+ : (elm->field.cqe_next))
+#define CIRCLEQ_LOOP_PREV(head, elm, field) \
+ (((elm)->field.cqe_prev == (void *)(head)) \
+ ? ((head)->cqh_last) \
+ : (elm->field.cqe_prev))
+
+#endif /* !_SYS_QUEUE_H_ */
diff -r 0e1449d6f231 xen/include/public/io/fsif.h
--- a/xen/include/public/io/fsif.h Fri Mar 13 10:09:25 2009 +0000
+++ b/xen/include/public/io/fsif.h Mon Mar 16 11:23:36 2009 +0000
@@ -185,7 +185,8 @@
#define STATE_INITIALISED "init"
#define STATE_READY "ready"
-
+#define STATE_CLOSING "closing"
+#define STATE_CLOSED "closed"
#endif
[-- Attachment #3: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] [UPDATE] fs-backend fixes and improvements
2009-03-17 10:55 ` Stefano Stabellini
@ 2009-03-17 23:32 ` Keith Coleman
2009-03-18 11:22 ` Stefano Stabellini
0 siblings, 1 reply; 5+ messages in thread
From: Keith Coleman @ 2009-03-17 23:32 UTC (permalink / raw)
To: Stefano Stabellini; +Cc: xen-devel, Keir Fraser
2009/3/17 Stefano Stabellini <stefano.stabellini@eu.citrix.com>:
> Keir Fraser wrote:
>
>> On 16/03/2009 11:25, "Stefano Stabellini" <stefano.stabellini@eu.citrix.com>
>> wrote:
>>
>>> Hi all,
>>> this patch is an updated version of the previous patch I sent to fix
>>> the issues that currently affect fs-backend.
>>> Compared to the previous version this patch is more resilient to errors
>>> because it is not using sigprocmask anymore to block SIGUSR2: blocking
>>> signals doesn't get along very well with glibc's aio implementation.
>>> Secondly I also introduced explicit error checking on the select return
>>> value, trying to recover in case of errors.
>>>
>>> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
>>
>> The patch fails to apply to xen-unstable. Perhaps it got eaten by your mail
>> client?
>>
>
> Maybe.
> I am attaching the patch to this email, is this any better?
>
> diff -r 0e1449d6f231 tools/fs-back/Makefile
> --- a/tools/fs-back/Makefile Fri Mar 13 10:09:25 2009 +0000
> +++ b/tools/fs-back/Makefile Mon Mar 16 11:23:36 2009 +0000
> @@ -16,7 +16,7 @@
> LIBS := -L. -L.. -L../lib
> LIBS += $(LDFLAGS_libxenctrl)
> LIBS += $(LDFLAGS_libxenstore)
> -LIBS += -lpthread -lrt
> +LIBS += -lrt
>
> OBJS := fs-xenbus.o fs-ops.o
>
> diff -r 0e1449d6f231 tools/fs-back/fs-backend.c
> --- a/tools/fs-back/fs-backend.c Fri Mar 13 10:09:25 2009 +0000
> +++ b/tools/fs-back/fs-backend.c Mon Mar 16 11:23:36 2009 +0000
> @@ -3,105 +3,71 @@
> #include <string.h>
> #include <assert.h>
> #include <malloc.h>
> -#include <pthread.h>
> #include <xenctrl.h>
> #include <aio.h>
> #include <sys/mman.h>
> #include <sys/select.h>
> +#include <sys/socket.h>
> #include <xen/io/ring.h>
> +#include <err.h>
> +#include "sys-queue.h"
> #include "fs-backend.h"
> +#include "fs-debug.h"
>
> struct xs_handle *xsh = NULL;
> static struct fs_export *fs_exports = NULL;
> static int export_id = 0;
> static int mount_id = 0;
> +static int pipefds[2];
> +static LIST_HEAD(mount_requests_head, fs_mount) mount_requests_head;
>
> -static void dispatch_response(struct fs_mount *mount, int priv_req_id)
> +static void free_mount_request(struct fs_mount *mount);
> +
> +static void dispatch_response(struct fs_request *request)
> {
> int i;
> struct fs_op *op;
> - struct fs_request *req = &mount->requests[priv_req_id];
>
> for(i=0;;i++)
> {
> op = fsops[i];
> /* We should dispatch a response before reaching the end of the array */
> assert(op != NULL);
> - if(op->type == req->req_shadow.type)
> + if(op->type == request->req_shadow.type)
> {
> - printf("Found op for type=%d\n", op->type);
> + FS_DEBUG("Found op for type=%d\n", op->type);
> /* There needs to be a response handler */
> assert(op->response_handler != NULL);
> - op->response_handler(mount, req);
> + op->response_handler(request->mount, request);
> break;
> }
> }
>
> - req->active = 0;
> - add_id_to_freelist(priv_req_id, mount->freelist);
> + request->active = 0;
> + add_id_to_freelist(request->id, request->mount->freelist);
> }
>
> -static void handle_aio_events(struct fs_mount *mount)
> +static void handle_aio_event(struct fs_request *request)
> {
> - int fd, ret, count, i, notify;
> - evtchn_port_t port;
> - /* AIO control block for the evtchn file destriptor */
> - struct aiocb evtchn_cb;
> - const struct aiocb * cb_list[mount->nr_entries];
> - int request_ids[mount->nr_entries];
> + int ret, notify;
>
> - /* Prepare the AIO control block for evtchn */
> - fd = xc_evtchn_fd(mount->evth);
> - bzero(&evtchn_cb, sizeof(struct aiocb));
> - evtchn_cb.aio_fildes = fd;
> - evtchn_cb.aio_nbytes = sizeof(port);
> - evtchn_cb.aio_buf = &port;
> - assert(aio_read(&evtchn_cb) == 0);
> + FS_DEBUG("handle_aio_event: mount %s request %d\n", request->mount->frontend, request->id);
> + if (request->active < 0) {
> + request->mount->nr_entries++;
> + if (!request->mount->nr_entries)
> + free_mount_request(request->mount);
> + return;
> + }
>
> -wait_again:
> - /* Create list of active AIO requests */
> - count = 0;
> - for(i=0; i<mount->nr_entries; i++)
> - if(mount->requests[i].active)
> - {
> - cb_list[count] = &mount->requests[i].aiocb;
> - request_ids[count] = i;
> - count++;
> - }
> - /* Add the event channel at the end of the list. Event channel needs to be
> - * handled last as it exits this function. */
> - cb_list[count] = &evtchn_cb;
> - request_ids[count] = -1;
> - count++;
> + ret = aio_error(&request->aiocb);
> + if(ret != EINPROGRESS && ret != ECANCELED)
> + dispatch_response(request);
>
> - /* Block till an AIO requset finishes, or we get an event */
> - while(1) {
> - int ret = aio_suspend(cb_list, count, NULL);
> - if (!ret)
> - break;
> - assert(errno == EINTR);
> - }
> - for(i=0; i<count; i++)
> - if(aio_error(cb_list[i]) != EINPROGRESS)
> - {
> - if(request_ids[i] >= 0)
> - dispatch_response(mount, request_ids[i]);
> - else
> - goto read_event_channel;
> - }
> -
> - RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&mount->ring, notify);
> - printf("Pushed responces and notify=%d\n", notify);
> + RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&request->mount->ring, notify);
> + FS_DEBUG("Pushed responces and notify=%d\n", notify);
> if(notify)
> - xc_evtchn_notify(mount->evth, mount->local_evtchn);
> -
> - goto wait_again;
> -
> -read_event_channel:
> - assert(aio_return(&evtchn_cb) == sizeof(evtchn_port_t));
> - assert(xc_evtchn_unmask(mount->evth, mount->local_evtchn) >= 0);
> + xc_evtchn_notify(request->mount->evth, request->mount->local_evtchn);
> }
> -
>
> static void allocate_request_array(struct fs_mount *mount)
> {
> @@ -116,6 +82,7 @@
> for(i=0; i< nr_entries; i++)
> {
> requests[i].active = 0;
> + requests[i].mount = mount;
> add_id_to_freelist(i, freelist);
> }
> mount->requests = requests;
> @@ -123,73 +90,91 @@
> }
>
>
> -static void *handle_mount(void *data)
> +static void handle_mount(struct fs_mount *mount)
> {
> int more, notify;
> - struct fs_mount *mount = (struct fs_mount *)data;
> -
> - printf("Starting a thread for mount: %d\n", mount->mount_id);
> - allocate_request_array(mount);
> + int nr_consumed=0;
> + RING_IDX cons, rp;
> + struct fsif_request *req;
>
> - for(;;)
> +moretodo:
> + rp = mount->ring.sring->req_prod;
> + xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
> +
> + while ((cons = mount->ring.req_cons) != rp)
> {
> - int nr_consumed=0;
> - RING_IDX cons, rp;
> - struct fsif_request *req;
> + int i;
> + struct fs_op *op;
>
> - handle_aio_events(mount);
> -moretodo:
> - rp = mount->ring.sring->req_prod;
> - xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
> + FS_DEBUG("Got a request at %d (of %d)\n",
> + cons, RING_SIZE(&mount->ring));
> + req = RING_GET_REQUEST(&mount->ring, cons);
> + FS_DEBUG("Request type=%d\n", req->type);
> + for(i=0;;i++)
> + {
> + op = fsops[i];
> + if(op == NULL)
> + {
> + /* We've reached the end of the array, no appropirate
> + * handler found. Warn, ignore and continue. */
> + FS_DEBUG("WARN: Unknown request type: %d\n", req->type);
> + mount->ring.req_cons++;
> + break;
> + }
> + if(op->type == req->type)
> + {
> + /* There needs to be a dispatch handler */
> + assert(op->dispatch_handler != NULL);
> + op->dispatch_handler(mount, req);
> + break;
> + }
> + }
>
> - while ((cons = mount->ring.req_cons) != rp)
> - {
> - int i;
> - struct fs_op *op;
> + nr_consumed++;
> + }
> + FS_DEBUG("Backend consumed: %d requests\n", nr_consumed);
> + RING_FINAL_CHECK_FOR_REQUESTS(&mount->ring, more);
> + if(more) goto moretodo;
>
> - 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++)
> - {
> - op = fsops[i];
> - if(op == NULL)
> - {
> - /* We've reached the end of the array, no appropirate
> - * handler found. Warn, ignore and continue. */
> - printf("WARN: Unknown request type: %d\n", req->type);
> - mount->ring.req_cons++;
> - break;
> - }
> - if(op->type == req->type)
> - {
> - /* There needs to be a dispatch handler */
> - assert(op->dispatch_handler != NULL);
> - op->dispatch_handler(mount, req);
> - break;
> - }
> - }
> + RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&mount->ring, notify);
> + FS_DEBUG("Pushed responces and notify=%d\n", notify);
> + if(notify)
> + xc_evtchn_notify(mount->evth, mount->local_evtchn);
> +}
>
> - nr_consumed++;
> +static void terminate_mount_request(struct fs_mount *mount) {
> + int count = 0, i;
> +
> + FS_DEBUG("terminate_mount_request %s\n", mount->frontend);
> + xenbus_write_backend_state(mount, STATE_CLOSING);
> +
> + for(i=0; i<mount->nr_entries; i++)
> + if(mount->requests[i].active) {
> + mount->requests[i].active = -1;
> + aio_cancel(mount->requests[i].aiocb.aio_fildes, &mount->requests[i].aiocb);
> + count--;
> }
> - printf("Backend consumed: %d requests\n", nr_consumed);
> - RING_FINAL_CHECK_FOR_REQUESTS(&mount->ring, more);
> - if(more) goto moretodo;
> + mount->nr_entries = count;
>
> - RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&mount->ring, notify);
> - printf("Pushed responces and notify=%d\n", notify);
> - if(notify)
> - xc_evtchn_notify(mount->evth, mount->local_evtchn);
> - }
> -
> - printf("Destroying thread for mount: %d\n", mount->mount_id);
> + while (!xenbus_frontend_state_changed(mount, STATE_CLOSING));
> + xenbus_write_backend_state(mount, STATE_CLOSED);
> +
> xc_gnttab_munmap(mount->gnth, mount->ring.sring, 1);
> xc_gnttab_close(mount->gnth);
> xc_evtchn_unbind(mount->evth, mount->local_evtchn);
> xc_evtchn_close(mount->evth);
> +
> + if (!count)
> + free_mount_request(mount);
> +}
> +
> +static void free_mount_request(struct fs_mount *mount) {
> + FS_DEBUG("free_mount_request %s\n", mount->frontend);
> free(mount->frontend);
> - pthread_exit(NULL);
> + free(mount->requests);
> + free(mount->freelist);
> + LIST_REMOVE (mount, entries);
> + free(mount);
> }
>
> static void handle_connection(int frontend_dom_id, int export_id, char *frontend)
> @@ -197,12 +182,11 @@
> struct fs_mount *mount;
> struct fs_export *export;
> 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",
> + FS_DEBUG("Handling connection from dom=%d, for export=%d\n",
> frontend_dom_id, export_id);
> /* Try to find the export on the list */
> export = fs_exports;
> @@ -214,7 +198,7 @@
> }
> if(!export)
> {
> - printf("Could not find the export (the id is unknown).\n");
> + FS_DEBUG("Could not find the export (the id is unknown).\n");
> return;
> }
>
> @@ -223,7 +207,7 @@
> mount->export = export;
> mount->mount_id = mount_id++;
> xenbus_read_mount_request(mount, frontend);
> - printf("Frontend found at: %s (gref=%d, evtchn=%d)\n",
> + FS_DEBUG("Frontend found at: %s (gref=%d, evtchn=%d)\n",
> mount->frontend, mount->grefs[0], mount->remote_evtchn);
> xenbus_write_backend_node(mount);
> mount->evth = -1;
> @@ -249,18 +233,24 @@
> mount->nr_entries = mount->ring.nr_ents;
> for (i = 0; i < MAX_FDS; i++)
> mount->fds[i] = -1;
> - xenbus_write_backend_ready(mount);
>
> - pthread_create(&handling_thread, NULL, &handle_mount, mount);
> + LIST_INSERT_HEAD(&mount_requests_head, mount, entries);
> + xenbus_watch_frontend_state(mount);
> + xenbus_write_backend_state(mount, STATE_READY);
> +
> + allocate_request_array(mount);
> }
>
> static void await_connections(void)
> {
> - int fd, ret, dom_id, export_id;
> + int fd, max_fd, ret, dom_id, export_id;
> fd_set fds;
> char **watch_paths;
> unsigned int len;
> char d;
> + struct fs_mount *pointer;
> +
> + LIST_INIT (&mount_requests_head);
>
> assert(xsh != NULL);
> fd = xenbus_get_watch_fd();
> @@ -268,28 +258,101 @@
> do {
> FD_ZERO(&fds);
> FD_SET(fd, &fds);
> - ret = select(fd+1, &fds, NULL, NULL, NULL);
> - assert(ret == 1);
> - watch_paths = xs_read_watch(xsh, &len);
> - assert(len == 2);
> - assert(strcmp(watch_paths[1], "conn-watch") == 0);
> - dom_id = -1;
> - export_id = -1;
> - d = 0;
> - printf("Path changed %s\n", watch_paths[0]);
> - sscanf(watch_paths[0], WATCH_NODE"/%d/%d/fronten%c",
> - &dom_id, &export_id, &d);
> - if((dom_id >= 0) && (export_id >= 0) && d == 'd') {
> - char *frontend = xs_read(xsh, XBT_NULL, watch_paths[0], NULL);
> - if (frontend) {
> - handle_connection(dom_id, export_id, frontend);
> - xs_rm(xsh, XBT_NULL, watch_paths[0]);
> - }
> - }
> -next_select:
> - printf("Awaiting next connection.\n");
> - /* TODO - we need to figure out what to free */
> - free(watch_paths);
> + FD_SET(pipefds[0], &fds);
> + max_fd = fd > pipefds[0] ? fd : pipefds[0];
> + LIST_FOREACH(pointer, &mount_requests_head, entries) {
> + int tfd = xc_evtchn_fd(pointer->evth);
> + FD_SET(tfd, &fds);
> + if (tfd > max_fd) max_fd = tfd;
> + }
> + ret = select(max_fd+1, &fds, NULL, NULL, NULL);
> + if (ret < 0) {
> + if (errno == EINTR) continue;
> + /* try to recover */
> + else if (errno == EBADF) {
> + struct timeval timeout;
> + memset(&timeout, 0x00, sizeof(timeout));
> + FD_ZERO(&fds);
> + FD_SET(fd, &fds);
> + FD_SET(pipefds[0], &fds);
> + max_fd = fd > pipefds[0] ? fd : pipefds[0];
> + ret = select(max_fd + 1, &fds, NULL, NULL, &timeout);
> + if (ret < 0)
> + err(1, "select: unrecoverable error occurred: %d\n", errno);
> +
> + /* trying to find the bogus fd among the open event channels */
> + LIST_FOREACH(pointer, &mount_requests_head, entries) {
> + int tfd = xc_evtchn_fd(pointer->evth);
> + memset(&timeout, 0x00, sizeof(timeout));
> + FD_ZERO(&fds);
> + FD_SET(tfd, &fds);
> + ret = select(tfd + 1, &fds, NULL, NULL, &timeout);
> + if (ret < 0) {
> + FS_DEBUG("fd %d is bogus, closing the related connection\n", tfd);
> + pointer->evth = fd;
> + terminate_mount_request(pointer);
> + continue;
> + }
> + }
> + continue;
> + } else
> + err(1, "select: unrecoverable error occurred: %d\n", errno);
> + }
> + if (FD_ISSET(fd, &fds)) {
> + watch_paths = xs_read_watch(xsh, &len);
> + if (!strcmp(watch_paths[XS_WATCH_TOKEN], "conn-watch")) {
> + dom_id = -1;
> + export_id = -1;
> + d = 0;
> + FS_DEBUG("Path changed %s\n", watch_paths[0]);
> + sscanf(watch_paths[XS_WATCH_PATH], WATCH_NODE"/%d/%d/fronten%c",
> + &dom_id, &export_id, &d);
> + if((dom_id >= 0) && (export_id >= 0) && d == 'd') {
> + char *frontend = xs_read(xsh, XBT_NULL, watch_paths[XS_WATCH_PATH], NULL);
> + if (frontend) {
> + handle_connection(dom_id, export_id, frontend);
> + xs_rm(xsh, XBT_NULL, watch_paths[XS_WATCH_PATH]);
> + }
> + }
> + } else if (!strcmp(watch_paths[XS_WATCH_TOKEN], "frontend-state")) {
> + LIST_FOREACH(pointer, &mount_requests_head, entries) {
> + if (!strncmp(pointer->frontend, watch_paths[XS_WATCH_PATH], strlen(pointer->frontend))) {
> + char *state = xenbus_read_frontend_state(pointer);
> + if (!state || strcmp(state, STATE_READY)) {
> + xenbus_unwatch_frontend_state(pointer);
> + terminate_mount_request(pointer);
> + }
> + free(state);
> + break;
> + }
> + }
> + } else {
> + FS_DEBUG("xenstore watch event unrecognized\n");
> + }
> + FS_DEBUG("Awaiting next connection.\n");
> + /* TODO - we need to figure out what to free */
> + free(watch_paths);
> + }
> + if (FD_ISSET(pipefds[0], &fds)) {
> + struct fs_request *request;
> + int ret;
> + ret = read(pipefds[0], &request, sizeof(struct fs_request *));
> + if (ret != sizeof(struct fs_request *)) {
> + fprintf(stderr, "read request failed\n");
> + continue;
> + }
> + handle_aio_event(request);
> + }
> + LIST_FOREACH(pointer, &mount_requests_head, entries) {
> + if (FD_ISSET(xc_evtchn_fd(pointer->evth), &fds)) {
> + evtchn_port_t port;
> + port = xc_evtchn_pending(pointer->evth);
> + if (port != -1) {
> + handle_mount(pointer);
> + xc_evtchn_unmask(pointer->evth, port);
> + }
> + }
> + }
> } while (1);
> }
>
> @@ -312,10 +375,28 @@
> return curr_export;
> }
>
> +static void aio_signal_handler(int signo, siginfo_t *info, void *context)
> +{
> + struct fs_request *request = (struct fs_request*) info->si_value.sival_ptr;
> + int saved_errno = errno;
> + write(pipefds[1], &request, sizeof(struct fs_request *));
> + errno = saved_errno;
> +}
>
> int main(void)
> {
> struct fs_export *export;
> + struct sigaction act;
> + sigset_t enable;
> +
> + sigemptyset(&enable);
> + sigaddset(&enable, SIGUSR2);
> + pthread_sigmask(SIG_UNBLOCK, &enable, NULL);
> +
> + sigfillset(&act.sa_mask);
> + act.sa_flags = SA_SIGINFO; /* do not restart syscalls to interrupt select(); use sa_sigaction */
> + act.sa_sigaction = aio_signal_handler;
> + sigaction(SIGUSR2, &act, NULL);
>
> /* Open the connection to XenStore first */
> xsh = xs_domain_open();
> @@ -327,6 +408,9 @@
> /* Create & register the default export */
> export = create_export("default", "/exports");
> xenbus_register_export(export);
> +
> + if (socketpair(PF_UNIX,SOCK_STREAM, 0, pipefds) == -1)
> + err(1, "failed to create pipe\n");
>
> await_connections();
> /* Close the connection to XenStore when we are finished with everything */
> diff -r 0e1449d6f231 tools/fs-back/fs-backend.h
> --- a/tools/fs-back/fs-backend.h Fri Mar 13 10:09:25 2009 +0000
> +++ b/tools/fs-back/fs-backend.h Mon Mar 16 11:23:36 2009 +0000
> @@ -7,6 +7,7 @@
> #include <xen/event_channel.h>
> #include <xen/io/ring.h>
> #include <xen/io/fsif.h>
> +#include "sys-queue.h"
>
> #define ROOT_NODE "backend/vfs"
> #define EXPORTS_SUBNODE "exports"
> @@ -25,6 +26,8 @@
>
> struct fs_request
> {
> + struct fs_mount *mount;
> + int id;
> int active;
> void *page; /* Pointer to mapped grant */
> int count;
> @@ -50,6 +53,7 @@
> struct fs_request *requests;
> unsigned short *freelist;
> int fds[MAX_FDS];
> + LIST_ENTRY(fs_mount) entries;
> };
>
>
> @@ -61,7 +65,11 @@
> int xenbus_get_watch_fd(void);
> void xenbus_read_mount_request(struct fs_mount *mount, char *frontend);
> void xenbus_write_backend_node(struct fs_mount *mount);
> -void xenbus_write_backend_ready(struct fs_mount *mount);
> +void xenbus_write_backend_state(struct fs_mount *mount, const char *state);
> +int xenbus_frontend_state_changed(struct fs_mount *mount, const char *oldstate);
> +void xenbus_watch_frontend_state(struct fs_mount *mount);
> +void xenbus_unwatch_frontend_state(struct fs_mount *mount);
> +char* xenbus_read_frontend_state(struct fs_mount *mount);
>
> /* File operations, implemented in fs-ops.c */
> struct fs_op
> diff -r 0e1449d6f231 tools/fs-back/fs-debug.h
> --- /dev/null Thu Jan 01 00:00:00 1970 +0000
> +++ b/tools/fs-back/fs-debug.h Mon Mar 16 11:23:36 2009 +0000
> @@ -0,0 +1,12 @@
> +#ifndef __FS_DEBUG__
> +#define __FS_DEBUG__
> +
> +// #define DEBUG 1
> +
> +#ifdef DEBUG
> +#define FS_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
> +#else
> +#define FS_DEBUG(fmt, ...) do { } while (0)
> +#endif
> +
> +#endif /*__FS_DEBUG__*/
> diff -r 0e1449d6f231 tools/fs-back/fs-ops.c
> --- a/tools/fs-back/fs-ops.c Fri Mar 13 10:09:25 2009 +0000
> +++ b/tools/fs-back/fs-ops.c Mon Mar 16 11:23:36 2009 +0000
> @@ -14,6 +14,7 @@
> #include <sys/mount.h>
> #include <unistd.h>
> #include "fs-backend.h"
> +#include "fs-debug.h"
>
> /* For debugging only */
> #include <sys/time.h>
> @@ -22,12 +23,11 @@
>
> #define BUFFER_SIZE 1024
>
> -
> static unsigned short get_request(struct fs_mount *mount, struct fsif_request *req)
> {
> unsigned short id = get_id_from_freelist(mount->freelist);
>
> - printf("Private Request id: %d\n", id);
> + FS_DEBUG("Private Request id: %d\n", id);
> memcpy(&mount->requests[id].req_shadow, req, sizeof(struct fsif_request));
> mount->requests[id].active = 1;
>
> @@ -54,7 +54,7 @@
> fsif_response_t *rsp;
> uint16_t req_id;
>
> - printf("Dispatching file open operation (gref=%d).\n", req->u.fopen.gref);
> + FS_DEBUG("Dispatching file open operation (gref=%d).\n", req->u.fopen.gref);
> /* Read the request, and open file */
> file_name = xc_gnttab_map_grant_ref(mount->gnth,
> mount->dom_id,
> @@ -62,13 +62,13 @@
> PROT_READ);
>
> req_id = req->id;
> - printf("File open issued for %s\n", file_name);
> + FS_DEBUG("File open issued for %s\n", file_name);
> assert(BUFFER_SIZE >
> strlen(file_name) + strlen(mount->export->export_path) + 1);
> snprintf(full_path, sizeof(full_path), "%s/%s",
> mount->export->export_path, file_name);
> assert(xc_gnttab_munmap(mount->gnth, file_name, 1) == 0);
> - printf("Issuing open for %s\n", full_path);
> + FS_DEBUG("Issuing open for %s\n", full_path);
> fd = get_fd(mount);
> if (fd >= 0) {
> int real_fd = open(full_path, O_RDWR);
> @@ -77,7 +77,7 @@
> else
> {
> mount->fds[fd] = real_fd;
> - printf("Got FD: %d for real %d\n", fd, real_fd);
> + FS_DEBUG("Got FD: %d for real %d\n", fd, real_fd);
> }
> }
> /* We can advance the request consumer index, from here on, the request
> @@ -87,7 +87,7 @@
>
> /* 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);
> + FS_DEBUG("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)fd;
> @@ -100,7 +100,7 @@
> fsif_response_t *rsp;
> uint16_t req_id;
>
> - printf("Dispatching file close operation (fd=%d).\n", req->u.fclose.fd);
> + FS_DEBUG("Dispatching file close operation (fd=%d).\n", req->u.fclose.fd);
>
> req_id = req->id;
> if (req->u.fclose.fd < MAX_FDS) {
> @@ -109,7 +109,7 @@
> mount->fds[req->u.fclose.fd] = -1;
> } else
> ret = -1;
> - printf("Got ret: %d\n", ret);
> + FS_DEBUG("Got ret: %d\n", ret);
> /* We can advance the request consumer index, from here on, the request
> * should not be used (it may be overrinden by a response) */
> mount->ring.req_cons++;
> @@ -117,7 +117,7 @@
>
> /* 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);
> + FS_DEBUG("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;
> @@ -143,7 +143,7 @@
> PROT_WRITE);
>
> req_id = req->id;
> - printf("File read issued for FD=%d (len=%"PRIu64", offest=%"PRIu64")\n",
> + FS_DEBUG("File read issued for FD=%d (len=%"PRIu64", offest=%"PRIu64")\n",
> req->u.fread.fd, req->u.fread.len, req->u.fread.offset);
>
> if (req->u.fread.fd < MAX_FDS)
> @@ -152,10 +152,11 @@
> fd = -1;
>
> priv_id = get_request(mount, req);
> - printf("Private id is: %d\n", priv_id);
> + FS_DEBUG("Private id is: %d\n", priv_id);
> priv_req = &mount->requests[priv_id];
> priv_req->page = buf;
> priv_req->count = count;
> + priv_req->id = priv_id;
>
> /* Dispatch AIO read request */
> bzero(&priv_req->aiocb, sizeof(struct aiocb));
> @@ -163,6 +164,9 @@
> priv_req->aiocb.aio_nbytes = req->u.fread.len;
> priv_req->aiocb.aio_offset = req->u.fread.offset;
> priv_req->aiocb.aio_buf = buf;
> + priv_req->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
> + priv_req->aiocb.aio_sigevent.sigev_signo = SIGUSR2;
> + priv_req->aiocb.aio_sigevent.sigev_value.sival_ptr = priv_req;
> assert(aio_read(&priv_req->aiocb) >= 0);
>
> out:
> @@ -185,7 +189,7 @@
> /* Get a response from the ring */
> rsp_idx = mount->ring.rsp_prod_pvt++;
> req_id = priv_req->req_shadow.id;
> - printf("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
> + FS_DEBUG("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)aio_return(&priv_req->aiocb);
> @@ -210,7 +214,7 @@
> PROT_READ);
>
> req_id = req->id;
> - printf("File write issued for FD=%d (len=%"PRIu64", offest=%"PRIu64")\n",
> + FS_DEBUG("File write issued for FD=%d (len=%"PRIu64", offest=%"PRIu64")\n",
> req->u.fwrite.fd, req->u.fwrite.len, req->u.fwrite.offset);
>
> if (req->u.fwrite.fd < MAX_FDS)
> @@ -219,10 +223,11 @@
> fd = -1;
>
> priv_id = get_request(mount, req);
> - printf("Private id is: %d\n", priv_id);
> + FS_DEBUG("Private id is: %d\n", priv_id);
> priv_req = &mount->requests[priv_id];
> priv_req->page = buf;
> priv_req->count = count;
> + priv_req->id = priv_id;
>
> /* Dispatch AIO write request */
> bzero(&priv_req->aiocb, sizeof(struct aiocb));
> @@ -230,6 +235,9 @@
> priv_req->aiocb.aio_nbytes = req->u.fwrite.len;
> priv_req->aiocb.aio_offset = req->u.fwrite.offset;
> priv_req->aiocb.aio_buf = buf;
> + priv_req->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
> + priv_req->aiocb.aio_sigevent.sigev_signo = SIGUSR2;
> + priv_req->aiocb.aio_sigevent.sigev_value.sival_ptr = priv_req;
> assert(aio_write(&priv_req->aiocb) >= 0);
>
>
> @@ -252,7 +260,7 @@
> /* Get a response from the ring */
> rsp_idx = mount->ring.rsp_prod_pvt++;
> req_id = priv_req->req_shadow.id;
> - printf("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
> + FS_DEBUG("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)aio_return(&priv_req->aiocb);
> @@ -273,7 +281,7 @@
> else
> fd = -1;
>
> - printf("File stat issued for FD=%d\n", req->u.fstat.fd);
> + FS_DEBUG("File stat issued for FD=%d\n", req->u.fstat.fd);
>
> /* We can advance the request consumer index, from here on, the request
> * should not be used (it may be overrinden by a response) */
> @@ -281,12 +289,12 @@
>
> /* Stat, and create the response */
> ret = fstat(fd, &stat);
> - printf("Mode=%o, uid=%d, a_time=%ld\n",
> + FS_DEBUG("Mode=%o, uid=%d, a_time=%ld\n",
> stat.st_mode, stat.st_uid, (long)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);
> + FS_DEBUG("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;
> @@ -320,7 +328,7 @@
>
> req_id = req->id;
> length = req->u.ftruncate.length;
> - printf("File truncate issued for FD=%d, length=%"PRId64"\n", req->u.ftruncate.fd, length);
> + FS_DEBUG("File truncate issued for FD=%d, length=%"PRId64"\n", req->u.ftruncate.fd, length);
>
> if (req->u.ftruncate.fd < MAX_FDS)
> fd = mount->fds[req->u.ftruncate.fd];
> @@ -336,7 +344,7 @@
>
> /* 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);
> + FS_DEBUG("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;
> @@ -350,7 +358,7 @@
> fsif_response_t *rsp;
> uint16_t req_id;
>
> - printf("Dispatching remove operation (gref=%d).\n", req->u.fremove.gref);
> + FS_DEBUG("Dispatching remove operation (gref=%d).\n", req->u.fremove.gref);
> /* Read the request, and open file */
> file_name = xc_gnttab_map_grant_ref(mount->gnth,
> mount->dom_id,
> @@ -358,15 +366,15 @@
> PROT_READ);
>
> req_id = req->id;
> - printf("File remove issued for %s\n", file_name);
> + FS_DEBUG("File remove issued for %s\n", file_name);
> assert(BUFFER_SIZE >
> strlen(file_name) + strlen(mount->export->export_path) + 1);
> snprintf(full_path, sizeof(full_path), "%s/%s",
> mount->export->export_path, file_name);
> assert(xc_gnttab_munmap(mount->gnth, file_name, 1) == 0);
> - printf("Issuing remove for %s\n", full_path);
> + FS_DEBUG("Issuing remove for %s\n", full_path);
> ret = remove(full_path);
> - printf("Got ret: %d\n", ret);
> + FS_DEBUG("Got ret: %d\n", ret);
> /* We can advance the request consumer index, from here on, the request
> * should not be used (it may be overrinden by a response) */
> mount->ring.req_cons++;
> @@ -374,7 +382,7 @@
>
> /* 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);
> + FS_DEBUG("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;
> @@ -390,7 +398,7 @@
> fsif_response_t *rsp;
> uint16_t req_id;
>
> - printf("Dispatching rename operation (gref=%d).\n", req->u.fremove.gref);
> + FS_DEBUG("Dispatching rename operation (gref=%d).\n", req->u.fremove.gref);
> /* Read the request, and open file */
> buf = xc_gnttab_map_grant_ref(mount->gnth,
> mount->dom_id,
> @@ -400,7 +408,7 @@
> req_id = req->id;
> old_file_name = buf + req->u.frename.old_name_offset;
> new_file_name = buf + req->u.frename.new_name_offset;
> - printf("File rename issued for %s -> %s (buf=%s)\n",
> + FS_DEBUG("File rename issued for %s -> %s (buf=%s)\n",
> old_file_name, new_file_name, buf);
> assert(BUFFER_SIZE >
> strlen(old_file_name) + strlen(mount->export->export_path) + 1);
> @@ -411,9 +419,9 @@
> snprintf(new_full_path, sizeof(new_full_path), "%s/%s",
> mount->export->export_path, new_file_name);
> assert(xc_gnttab_munmap(mount->gnth, buf, 1) == 0);
> - printf("Issuing rename for %s -> %s\n", old_full_path, new_full_path);
> + FS_DEBUG("Issuing rename for %s -> %s\n", old_full_path, new_full_path);
> ret = rename(old_full_path, new_full_path);
> - printf("Got ret: %d\n", ret);
> + FS_DEBUG("Got ret: %d\n", ret);
> /* We can advance the request consumer index, from here on, the request
> * should not be used (it may be overrinden by a response) */
> mount->ring.req_cons++;
> @@ -421,7 +429,7 @@
>
> /* 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);
> + FS_DEBUG("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;
> @@ -438,7 +446,7 @@
> fsif_response_t *rsp;
> uint16_t req_id;
>
> - printf("Dispatching file create operation (gref=%d).\n", req->u.fcreate.gref);
> + FS_DEBUG("Dispatching file create operation (gref=%d).\n", req->u.fcreate.gref);
> /* Read the request, and create file/directory */
> mode = req->u.fcreate.mode;
> directory = req->u.fcreate.directory;
> @@ -448,7 +456,7 @@
> PROT_READ);
>
> req_id = req->id;
> - printf("File create issued for %s\n", file_name);
> + FS_DEBUG("File create issued for %s\n", file_name);
> assert(BUFFER_SIZE >
> strlen(file_name) + strlen(mount->export->export_path) + 1);
> snprintf(full_path, sizeof(full_path), "%s/%s",
> @@ -460,12 +468,12 @@
>
> if(directory)
> {
> - printf("Issuing create for directory: %s\n", full_path);
> + FS_DEBUG("Issuing create for directory: %s\n", full_path);
> ret = mkdir(full_path, mode);
> }
> else
> {
> - printf("Issuing create for file: %s\n", full_path);
> + FS_DEBUG("Issuing create for file: %s\n", full_path);
> ret = get_fd(mount);
> if (ret >= 0) {
> int real_fd = creat(full_path, mode);
> @@ -474,15 +482,15 @@
> else
> {
> mount->fds[ret] = real_fd;
> - printf("Got FD: %d for real %d\n", ret, real_fd);
> + FS_DEBUG("Got FD: %d for real %d\n", ret, real_fd);
> }
> }
> }
> - printf("Got ret %d (errno=%d)\n", ret, errno);
> + FS_DEBUG("Got ret %d (errno=%d)\n", ret, errno);
>
> /* 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);
> + FS_DEBUG("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;
> @@ -499,7 +507,7 @@
> DIR *dir;
> struct dirent *dirent = NULL;
>
> - printf("Dispatching list operation (gref=%d).\n", req->u.flist.gref);
> + FS_DEBUG("Dispatching list operation (gref=%d).\n", req->u.flist.gref);
> /* Read the request, and list directory */
> offset = req->u.flist.offset;
> buf = file_name = xc_gnttab_map_grant_ref(mount->gnth,
> @@ -508,7 +516,7 @@
> PROT_READ | PROT_WRITE);
>
> req_id = req->id;
> - printf("Dir list issued for %s\n", file_name);
> + FS_DEBUG("Dir list issued for %s\n", file_name);
> assert(BUFFER_SIZE >
> strlen(file_name) + strlen(mount->export->export_path) + 1);
> snprintf(full_path, sizeof(full_path), "%s/%s",
> @@ -552,7 +560,7 @@
>
> /* 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);
> + FS_DEBUG("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 = ret_val;
> @@ -566,7 +574,7 @@
> uint16_t req_id;
> int32_t mode;
>
> - printf("Dispatching file chmod operation (fd=%d, mode=%o).\n",
> + FS_DEBUG("Dispatching file chmod operation (fd=%d, mode=%o).\n",
> req->u.fchmod.fd, req->u.fchmod.mode);
> req_id = req->id;
> if (req->u.fchmod.fd < MAX_FDS)
> @@ -583,7 +591,7 @@
>
> /* 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);
> + FS_DEBUG("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;
> @@ -598,7 +606,7 @@
> struct statvfs stat;
> int64_t ret;
>
> - printf("Dispatching fs space operation (gref=%d).\n", req->u.fspace.gref);
> + FS_DEBUG("Dispatching fs space operation (gref=%d).\n", req->u.fspace.gref);
> /* Read the request, and open file */
> file_name = xc_gnttab_map_grant_ref(mount->gnth,
> mount->dom_id,
> @@ -606,13 +614,13 @@
> PROT_READ);
>
> req_id = req->id;
> - printf("Fs space issued for %s\n", file_name);
> + FS_DEBUG("Fs space issued for %s\n", file_name);
> assert(BUFFER_SIZE >
> strlen(file_name) + strlen(mount->export->export_path) + 1);
> snprintf(full_path, sizeof(full_path), "%s/%s",
> mount->export->export_path, file_name);
> assert(xc_gnttab_munmap(mount->gnth, file_name, 1) == 0);
> - printf("Issuing fs space for %s\n", full_path);
> + FS_DEBUG("Issuing fs space for %s\n", full_path);
> ret = statvfs(full_path, &stat);
> if(ret >= 0)
> ret = stat.f_bsize * stat.f_bfree;
> @@ -624,7 +632,7 @@
>
> /* 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);
> + FS_DEBUG("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;
> @@ -643,15 +651,19 @@
> else
> fd = -1;
>
> - printf("File sync issued for FD=%d\n", req->u.fsync.fd);
> + FS_DEBUG("File sync issued for FD=%d\n", req->u.fsync.fd);
>
> priv_id = get_request(mount, req);
> - printf("Private id is: %d\n", priv_id);
> + FS_DEBUG("Private id is: %d\n", priv_id);
> priv_req = &mount->requests[priv_id];
> + priv_req->id = priv_id;
>
> /* Dispatch AIO read request */
> bzero(&priv_req->aiocb, sizeof(struct aiocb));
> priv_req->aiocb.aio_fildes = fd;
> + priv_req->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
> + priv_req->aiocb.aio_sigevent.sigev_signo = SIGUSR2;
> + priv_req->aiocb.aio_sigevent.sigev_value.sival_ptr = priv_req;
> assert(aio_fsync(O_SYNC, &priv_req->aiocb) >= 0);
>
>
> @@ -669,7 +681,7 @@
> /* Get a response from the ring */
> rsp_idx = mount->ring.rsp_prod_pvt++;
> req_id = priv_req->req_shadow.id;
> - printf("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
> + FS_DEBUG("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)aio_return(&priv_req->aiocb);
> diff -r 0e1449d6f231 tools/fs-back/fs-xenbus.c
> --- a/tools/fs-back/fs-xenbus.c Fri Mar 13 10:09:25 2009 +0000
> +++ b/tools/fs-back/fs-xenbus.c Mon Mar 16 11:23:36 2009 +0000
> @@ -4,10 +4,12 @@
> #include <stdarg.h>
> #include <string.h>
> #include <assert.h>
> +#include <sys/select.h>
> #include <xenctrl.h>
> #include <xs.h>
> #include <xen/io/fsif.h>
> #include "fs-backend.h"
> +#include "fs-debug.h"
>
>
> static bool xenbus_printf(struct xs_handle *xsh,
> @@ -25,7 +27,7 @@
> snprintf(fullpath, sizeof(fullpath), "%s/%s", node, path);
> vsnprintf(val, sizeof(val), fmt, args);
> va_end(args);
> - printf("xenbus_printf (%s) <= %s.\n", fullpath, val);
> + FS_DEBUG("xenbus_printf (%s) <= %s.\n", fullpath, val);
>
> return xs_write(xsh, xbt, fullpath, val, strlen(val));
> }
> @@ -57,19 +59,19 @@
> assert(xsh != NULL);
> if(xsh == NULL)
> {
> - printf("Could not open connection to xenbus deamon.\n");
> + FS_DEBUG("Could not open connection to xenbus deamon.\n");
> goto error_exit;
> }
> - printf("Connection to the xenbus deamon opened successfully.\n");
> + FS_DEBUG("Connection to the xenbus deamon opened successfully.\n");
>
> /* Start transaction */
> xst = xs_transaction_start(xsh);
> if(xst == 0)
> {
> - printf("Could not start a transaction.\n");
> + FS_DEBUG("Could not start a transaction.\n");
> goto error_exit;
> }
> - printf("XS transaction is %d\n", xst);
> + FS_DEBUG("XS transaction is %d\n", xst);
>
> /* Create node string */
> snprintf(node, sizeof(node), "%s/%d", EXPORTS_NODE, export->export_id);
> @@ -78,7 +80,7 @@
>
> if(!xenbus_printf(xsh, xst, node, "name", "%s", export->name))
> {
> - printf("Could not write the export node.\n");
> + FS_DEBUG("Could not write the export node.\n");
> goto error_exit;
> }
>
> @@ -87,7 +89,7 @@
> perms.perms = XS_PERM_READ;
> if(!xs_set_permissions(xsh, xst, EXPORTS_NODE, &perms, 1))
> {
> - printf("Could not set permissions on the export node.\n");
> + FS_DEBUG("Could not set permissions on the export node.\n");
> goto error_exit;
> }
>
> @@ -166,7 +168,7 @@
>
> assert(xsh != NULL);
> self_id = get_self_id();
> - printf("Our own dom_id=%d\n", self_id);
> + FS_DEBUG("Our own dom_id=%d\n", self_id);
> snprintf(node, sizeof(node), "%s/backend", mount->frontend);
> snprintf(backend_node, sizeof(backend_node), "/local/domain/%d/"ROOT_NODE"/%d",
> self_id, mount->mount_id);
> @@ -176,7 +178,7 @@
> xs_write(xsh, XBT_NULL, node, STATE_INITIALISED, strlen(STATE_INITIALISED));
> }
>
> -void xenbus_write_backend_ready(struct fs_mount *mount)
> +void xenbus_write_backend_state(struct fs_mount *mount, const char *state)
> {
> char node[1024];
> int self_id;
> @@ -184,6 +186,59 @@
> assert(xsh != NULL);
> self_id = get_self_id();
> snprintf(node, sizeof(node), ROOT_NODE"/%d/state", mount->mount_id);
> - xs_write(xsh, XBT_NULL, node, STATE_READY, strlen(STATE_READY));
> + xs_write(xsh, XBT_NULL, node, state, strlen(state));
> }
>
> +void xenbus_watch_frontend_state(struct fs_mount *mount)
> +{
> + int res;
> + char statepath[1024];
> +
> + assert(xsh != NULL);
> + snprintf(statepath, sizeof(statepath), "%s/state", mount->frontend);
> + res = xs_watch(xsh, statepath, "frontend-state");
> + assert(res);
> +}
> +
> +void xenbus_unwatch_frontend_state(struct fs_mount *mount)
> +{
> + int res;
> + char statepath[1024];
> +
> + assert(xsh != NULL);
> + snprintf(statepath, sizeof(statepath), "%s/state", mount->frontend);
> + res = xs_unwatch(xsh, statepath, "frontend-state");
> + assert(res);
> +}
> +
> +int xenbus_frontend_state_changed(struct fs_mount *mount, const char *oldstate)
> +{
> + unsigned int len;
> + char statepath[1024];
> + char *state = NULL;
> +
> + assert(xsh != NULL);
> + snprintf(statepath, sizeof(statepath), "%s/state", mount->frontend);
> + state = xs_read(xsh, XBT_NULL, statepath, &len);
> + if (state && len > 0) {
> + if (strcmp(state, oldstate)) {
> + free(state);
> + return 1;
> + } else {
> + free(state);
> + return 0;
> + }
> + } else
> + return 1;
> +}
> +
> +char* xenbus_read_frontend_state(struct fs_mount *mount)
> +{
> + unsigned int len;
> + char statepath[1024];
> +
> + assert(xsh != NULL);
> + snprintf(statepath, sizeof(statepath), "%s/state", mount->frontend);
> + return xs_read(xsh, XBT_NULL, statepath, &len);
> +}
> +
> diff -r 0e1449d6f231 tools/fs-back/sys-queue.h
> --- /dev/null Thu Jan 01 00:00:00 1970 +0000
> +++ b/tools/fs-back/sys-queue.h Mon Mar 16 11:23:36 2009 +0000
> @@ -0,0 +1,338 @@
> +/* $NetBSD: queue.h,v 1.45.14.1 2007/07/18 20:13:24 liamjfoy Exp $ */
> +
> +/*
> + * Qemu version: Copy from netbsd, removed debug code, removed some of
> + * the implementations. Left in lists, tail queues and circular queues.
> + */
> +
> +/*
> + * Copyright (c) 1991, 1993
> + * The Regents of the University of California. All rights reserved.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + * notice, this list of conditions and the following disclaimer.
> + * 2. Redistributions in binary form must reproduce the above copyright
> + * notice, this list of conditions and the following disclaimer in the
> + * documentation and/or other materials provided with the distribution.
> + * 3. Neither the name of the University nor the names of its contributors
> + * may be used to endorse or promote products derived from this software
> + * without specific prior written permission.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
> + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
> + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
> + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
> + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
> + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
> + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
> + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + *
> + * @(#)queue.h 8.5 (Berkeley) 8/20/94
> + */
> +
> +#ifndef _SYS_QUEUE_H_
> +#define _SYS_QUEUE_H_
> +
> +/*
> + * This file defines three types of data structures:
> + * lists, tail queues, and circular queues.
> + *
> + * A list is headed by a single forward pointer (or an array of forward
> + * pointers for a hash table header). The elements are doubly linked
> + * so that an arbitrary element can be removed without a need to
> + * traverse the list. New elements can be added to the list before
> + * or after an existing element or at the head of the list. A list
> + * may only be traversed in the forward direction.
> + *
> + * A tail queue is headed by a pair of pointers, one to the head of the
> + * list and the other to the tail of the list. The elements are doubly
> + * linked so that an arbitrary element can be removed without a need to
> + * traverse the list. New elements can be added to the list before or
> + * after an existing element, at the head of the list, or at the end of
> + * the list. A tail queue may be traversed in either direction.
> + *
> + * A circle queue is headed by a pair of pointers, one to the head of the
> + * list and the other to the tail of the list. The elements are doubly
> + * linked so that an arbitrary element can be removed without a need to
> + * traverse the list. New elements can be added to the list before or after
> + * an existing element, at the head of the list, or at the end of the list.
> + * A circle queue may be traversed in either direction, but has a more
> + * complex end of list detection.
> + *
> + * For details on the use of these macros, see the queue(3) manual page.
> + */
> +
> +/*
> + * List definitions.
> + */
> +#define LIST_HEAD(name, type) \
> +struct name { \
> + struct type *lh_first; /* first element */ \
> +}
> +
> +#define LIST_HEAD_INITIALIZER(head) \
> + { NULL }
> +
> +#define LIST_ENTRY(type) \
> +struct { \
> + struct type *le_next; /* next element */ \
> + struct type **le_prev; /* address of previous next element */ \
> +}
> +
> +/*
> + * List functions.
> + */
> +#define LIST_INIT(head) do { \
> + (head)->lh_first = NULL; \
> +} while (/*CONSTCOND*/0)
> +
> +#define LIST_INSERT_AFTER(listelm, elm, field) do { \
> + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
> + (listelm)->field.le_next->field.le_prev = \
> + &(elm)->field.le_next; \
> + (listelm)->field.le_next = (elm); \
> + (elm)->field.le_prev = &(listelm)->field.le_next; \
> +} while (/*CONSTCOND*/0)
> +
> +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
> + (elm)->field.le_prev = (listelm)->field.le_prev; \
> + (elm)->field.le_next = (listelm); \
> + *(listelm)->field.le_prev = (elm); \
> + (listelm)->field.le_prev = &(elm)->field.le_next; \
> +} while (/*CONSTCOND*/0)
> +
> +#define LIST_INSERT_HEAD(head, elm, field) do { \
> + if (((elm)->field.le_next = (head)->lh_first) != NULL) \
> + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
> + (head)->lh_first = (elm); \
> + (elm)->field.le_prev = &(head)->lh_first; \
> +} while (/*CONSTCOND*/0)
> +
> +#define LIST_REMOVE(elm, field) do { \
> + if ((elm)->field.le_next != NULL) \
> + (elm)->field.le_next->field.le_prev = \
> + (elm)->field.le_prev; \
> + *(elm)->field.le_prev = (elm)->field.le_next; \
> +} while (/*CONSTCOND*/0)
> +
> +#define LIST_FOREACH(var, head, field) \
> + for ((var) = ((head)->lh_first); \
> + (var); \
> + (var) = ((var)->field.le_next))
> +
> +/*
> + * List access methods.
> + */
> +#define LIST_EMPTY(head) ((head)->lh_first == NULL)
> +#define LIST_FIRST(head) ((head)->lh_first)
> +#define LIST_NEXT(elm, field) ((elm)->field.le_next)
> +
> +
> +/*
> + * Tail queue definitions.
> + */
> +#define _TAILQ_HEAD(name, type, qual) \
> +struct name { \
> + qual type *tqh_first; /* first element */ \
> + qual type *qual *tqh_last; /* addr of last next element */ \
> +}
> +#define TAILQ_HEAD(name, type) _TAILQ_HEAD(name, struct type,)
> +
> +#define TAILQ_HEAD_INITIALIZER(head) \
> + { NULL, &(head).tqh_first }
> +
> +#define _TAILQ_ENTRY(type, qual) \
> +struct { \
> + qual type *tqe_next; /* next element */ \
> + qual type *qual *tqe_prev; /* address of previous next element */\
> +}
> +#define TAILQ_ENTRY(type) _TAILQ_ENTRY(struct type,)
> +
> +/*
> + * Tail queue functions.
> + */
> +#define TAILQ_INIT(head) do { \
> + (head)->tqh_first = NULL; \
> + (head)->tqh_last = &(head)->tqh_first; \
> +} while (/*CONSTCOND*/0)
> +
> +#define TAILQ_INSERT_HEAD(head, elm, field) do { \
> + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
> + (head)->tqh_first->field.tqe_prev = \
> + &(elm)->field.tqe_next; \
> + else \
> + (head)->tqh_last = &(elm)->field.tqe_next; \
> + (head)->tqh_first = (elm); \
> + (elm)->field.tqe_prev = &(head)->tqh_first; \
> +} while (/*CONSTCOND*/0)
> +
> +#define TAILQ_INSERT_TAIL(head, elm, field) do { \
> + (elm)->field.tqe_next = NULL; \
> + (elm)->field.tqe_prev = (head)->tqh_last; \
> + *(head)->tqh_last = (elm); \
> + (head)->tqh_last = &(elm)->field.tqe_next; \
> +} while (/*CONSTCOND*/0)
> +
> +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
> + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
> + (elm)->field.tqe_next->field.tqe_prev = \
> + &(elm)->field.tqe_next; \
> + else \
> + (head)->tqh_last = &(elm)->field.tqe_next; \
> + (listelm)->field.tqe_next = (elm); \
> + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
> +} while (/*CONSTCOND*/0)
> +
> +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
> + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
> + (elm)->field.tqe_next = (listelm); \
> + *(listelm)->field.tqe_prev = (elm); \
> + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
> +} while (/*CONSTCOND*/0)
> +
> +#define TAILQ_REMOVE(head, elm, field) do { \
> + if (((elm)->field.tqe_next) != NULL) \
> + (elm)->field.tqe_next->field.tqe_prev = \
> + (elm)->field.tqe_prev; \
> + else \
> + (head)->tqh_last = (elm)->field.tqe_prev; \
> + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
> +} while (/*CONSTCOND*/0)
> +
> +#define TAILQ_FOREACH(var, head, field) \
> + for ((var) = ((head)->tqh_first); \
> + (var); \
> + (var) = ((var)->field.tqe_next))
> +
> +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
> + for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last)); \
> + (var); \
> + (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last)))
> +
> +/*
> + * Tail queue access methods.
> + */
> +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
> +#define TAILQ_FIRST(head) ((head)->tqh_first)
> +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
> +
> +#define TAILQ_LAST(head, headname) \
> + (*(((struct headname *)((head)->tqh_last))->tqh_last))
> +#define TAILQ_PREV(elm, headname, field) \
> + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
> +
> +
> +/*
> + * Circular queue definitions.
> + */
> +#define CIRCLEQ_HEAD(name, type) \
> +struct name { \
> + struct type *cqh_first; /* first element */ \
> + struct type *cqh_last; /* last element */ \
> +}
> +
> +#define CIRCLEQ_HEAD_INITIALIZER(head) \
> + { (void *)&head, (void *)&head }
> +
> +#define CIRCLEQ_ENTRY(type) \
> +struct { \
> + struct type *cqe_next; /* next element */ \
> + struct type *cqe_prev; /* previous element */ \
> +}
> +
> +/*
> + * Circular queue functions.
> + */
> +#define CIRCLEQ_INIT(head) do { \
> + (head)->cqh_first = (void *)(head); \
> + (head)->cqh_last = (void *)(head); \
> +} while (/*CONSTCOND*/0)
> +
> +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
> + (elm)->field.cqe_next = (listelm)->field.cqe_next; \
> + (elm)->field.cqe_prev = (listelm); \
> + if ((listelm)->field.cqe_next == (void *)(head)) \
> + (head)->cqh_last = (elm); \
> + else \
> + (listelm)->field.cqe_next->field.cqe_prev = (elm); \
> + (listelm)->field.cqe_next = (elm); \
> +} while (/*CONSTCOND*/0)
> +
> +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
> + (elm)->field.cqe_next = (listelm); \
> + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
> + if ((listelm)->field.cqe_prev == (void *)(head)) \
> + (head)->cqh_first = (elm); \
> + else \
> + (listelm)->field.cqe_prev->field.cqe_next = (elm); \
> + (listelm)->field.cqe_prev = (elm); \
> +} while (/*CONSTCOND*/0)
> +
> +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
> + (elm)->field.cqe_next = (head)->cqh_first; \
> + (elm)->field.cqe_prev = (void *)(head); \
> + if ((head)->cqh_last == (void *)(head)) \
> + (head)->cqh_last = (elm); \
> + else \
> + (head)->cqh_first->field.cqe_prev = (elm); \
> + (head)->cqh_first = (elm); \
> +} while (/*CONSTCOND*/0)
> +
> +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
> + (elm)->field.cqe_next = (void *)(head); \
> + (elm)->field.cqe_prev = (head)->cqh_last; \
> + if ((head)->cqh_first == (void *)(head)) \
> + (head)->cqh_first = (elm); \
> + else \
> + (head)->cqh_last->field.cqe_next = (elm); \
> + (head)->cqh_last = (elm); \
> +} while (/*CONSTCOND*/0)
> +
> +#define CIRCLEQ_REMOVE(head, elm, field) do { \
> + if ((elm)->field.cqe_next == (void *)(head)) \
> + (head)->cqh_last = (elm)->field.cqe_prev; \
> + else \
> + (elm)->field.cqe_next->field.cqe_prev = \
> + (elm)->field.cqe_prev; \
> + if ((elm)->field.cqe_prev == (void *)(head)) \
> + (head)->cqh_first = (elm)->field.cqe_next; \
> + else \
> + (elm)->field.cqe_prev->field.cqe_next = \
> + (elm)->field.cqe_next; \
> +} while (/*CONSTCOND*/0)
> +
> +#define CIRCLEQ_FOREACH(var, head, field) \
> + for ((var) = ((head)->cqh_first); \
> + (var) != (const void *)(head); \
> + (var) = ((var)->field.cqe_next))
> +
> +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
> + for ((var) = ((head)->cqh_last); \
> + (var) != (const void *)(head); \
> + (var) = ((var)->field.cqe_prev))
> +
> +/*
> + * Circular queue access methods.
> + */
> +#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head))
> +#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
> +#define CIRCLEQ_LAST(head) ((head)->cqh_last)
> +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
> +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
> +
> +#define CIRCLEQ_LOOP_NEXT(head, elm, field) \
> + (((elm)->field.cqe_next == (void *)(head)) \
> + ? ((head)->cqh_first) \
> + : (elm->field.cqe_next))
> +#define CIRCLEQ_LOOP_PREV(head, elm, field) \
> + (((elm)->field.cqe_prev == (void *)(head)) \
> + ? ((head)->cqh_last) \
> + : (elm->field.cqe_prev))
> +
> +#endif /* !_SYS_QUEUE_H_ */
> diff -r 0e1449d6f231 xen/include/public/io/fsif.h
> --- a/xen/include/public/io/fsif.h Fri Mar 13 10:09:25 2009 +0000
> +++ b/xen/include/public/io/fsif.h Mon Mar 16 11:23:36 2009 +0000
> @@ -185,7 +185,8 @@
>
> #define STATE_INITIALISED "init"
> #define STATE_READY "ready"
> -
> +#define STATE_CLOSING "closing"
> +#define STATE_CLOSED "closed"
>
>
> #endif
>
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xensource.com
> http://lists.xensource.com/xen-devel
>
>
Using this patch fs-backend fails after 50 save/restore cycles. It
used to fail after 20 cycles so this is an improvement.
Keith Coleman
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] [UPDATE] fs-backend fixes and improvements
2009-03-17 23:32 ` Keith Coleman
@ 2009-03-18 11:22 ` Stefano Stabellini
0 siblings, 0 replies; 5+ messages in thread
From: Stefano Stabellini @ 2009-03-18 11:22 UTC (permalink / raw)
To: Keith Coleman; +Cc: xen-devel, Keir Fraser
Keith Coleman wrote:
>
> Using this patch fs-backend fails after 50 save/restore cycles. It
> used to fail after 20 cycles so this is an improvement.
>
still not ideal though.
Thanks for testing, I'll try to fix the 50 save/restore cycles too.
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2009-03-18 11:22 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-03-16 11:25 [PATCH] [UPDATE] fs-backend fixes and improvements Stefano Stabellini
2009-03-17 10:51 ` Keir Fraser
2009-03-17 10:55 ` Stefano Stabellini
2009-03-17 23:32 ` Keith Coleman
2009-03-18 11:22 ` Stefano Stabellini
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.