[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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



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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.