Stefano Stabellini
2009-Mar-16 11:25 UTC
[Xen-devel] [PATCH] [UPDATE] fs-backend fixes and improvements
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 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Keir Fraser
2009-Mar-17 10:51 UTC
Re: [Xen-devel] [PATCH] [UPDATE] fs-backend fixes and improvements
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 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Stefano Stabellini
2009-Mar-17 10:55 UTC
Re: [Xen-devel] [PATCH] [UPDATE] fs-backend fixes and improvements
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? _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Keith Coleman
2009-Mar-17 23:32 UTC
Re: [Xen-devel] [PATCH] [UPDATE] fs-backend fixes and improvements
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 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Stefano Stabellini
2009-Mar-18 11:22 UTC
Re: [Xen-devel] [PATCH] [UPDATE] fs-backend fixes and improvements
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. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel