WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

Re: [Xen-devel] [PATCH] [UPDATE] fs-backend fixes and improvements

To: Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>
Subject: Re: [Xen-devel] [PATCH] [UPDATE] fs-backend fixes and improvements
From: Keith Coleman <list.keith@xxxxxxxxxxx>
Date: Tue, 17 Mar 2009 19:32:29 -0400
Cc: xen-devel <xen-devel@xxxxxxxxxxxxxxxxxxx>, Keir Fraser <Keir.Fraser@xxxxxxxxxxxxx>
Delivery-date: Tue, 17 Mar 2009 16:33:44 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
In-reply-to: <49BF8188.2050301@xxxxxxxxxxxxx>
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
References: <C5E5312C.55FF%keir.fraser@xxxxxxxxxxxxx> <49BF8188.2050301@xxxxxxxxxxxxx>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
2009/3/17 Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>:
> Keir Fraser wrote:
>
>> On 16/03/2009 11:25, "Stefano Stabellini" <stefano.stabellini@xxxxxxxxxxxxx>
>> 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@xxxxxxxxxxxxx>
>>
>> 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@xxxxxxxxxxxxxxxxxxx
> 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@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel