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

[Xen-changelog] Update vtpm driver following the recent changes to the



# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID cb215a84d1af0aa0143e52a459607f54503a51a7
# Parent  b0338759544e116337f25d5cdebc59c38a6d40c5
Update vtpm driver following the recent changes to the 
xenbus driver and its semantics.

Signed-off-by: Stefan Berger <stefanb@xxxxxxxxxx>

diff -r b0338759544e -r cb215a84d1af docs/misc/vtpm.txt
--- a/docs/misc/vtpm.txt        Thu Nov 24 22:21:48 2005
+++ b/docs/misc/vtpm.txt        Fri Nov 25 08:14:01 2005
@@ -73,7 +73,14 @@
 where the TPM backend has been compiled into - this has to be 
 domain 0  at the moment - and which TPM instance the user domain
 is supposed to talk to. Note that each running VM must use a 
-different instance and that using instance 0 is NOT allowed.
+different instance and that using instance 0 is NOT allowed. The
+instance parameter is taken as the desired instance number, but
+the actual instance number that is assigned to the virtual machine
+can be different. This is the case if for example that particular
+instance is already used by another virtual machine. The association
+of which TPM instance number is used by which virtual machine is
+kept in the file /etc/xen/vtpm.db. Associations are maintained by
+domain name and instance number.
 
 Note: If you do not want TPM functionality for your user domain simply
 leave out the 'vtpm' line in the configuration file.
diff -r b0338759544e -r cb215a84d1af 
linux-2.6-xen-sparse/drivers/char/tpm/Kconfig
--- a/linux-2.6-xen-sparse/drivers/char/tpm/Kconfig     Thu Nov 24 22:21:48 2005
+++ b/linux-2.6-xen-sparse/drivers/char/tpm/Kconfig     Fri Nov 25 08:14:01 2005
@@ -17,15 +17,6 @@
          obtained at: <http://sourceforge.net/projects/trousers>.  To 
          compile this driver as a module, choose M here; the module 
          will be called tpm. If unsure, say N.
-
-config TCG_TIS
-       tristate "TPM Interface Specification 1.2 Interface"
-       depends on TCG_TPM
-       ---help---
-         If you have a TPM security chip that is compliant with the
-         TCG TIS 1.2 TPM specification say Yes and it will be accessible
-         from within Linux.  To compile this driver as a module, choose
-         M here; the module will be called tpm_tis.
 
 config TCG_NSC
        tristate "National Semiconductor TPM Interface"
diff -r b0338759544e -r cb215a84d1af 
linux-2.6-xen-sparse/drivers/xen/tpmback/common.h
--- a/linux-2.6-xen-sparse/drivers/xen/tpmback/common.h Thu Nov 24 22:21:48 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/tpmback/common.h Fri Nov 25 08:14:01 2005
@@ -28,7 +28,7 @@
 #endif
 
 typedef struct tpmif_st {
-        struct list_head tpmif_list;
+       struct list_head tpmif_list;
        /* Unique identifier for this interface. */
        domid_t domid;
        unsigned int handle;
@@ -83,6 +83,11 @@
 
 #define MMAP_VADDR(t,_req) ((t)->mmap_vstart + ((_req) * PAGE_SIZE))
 
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
 #endif /* __TPMIF__BACKEND__COMMON_H__ */
 
 /*
diff -r b0338759544e -r cb215a84d1af 
linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c
--- a/linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c      Thu Nov 24 
22:21:48 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c      Fri Nov 25 
08:14:01 2005
@@ -127,6 +127,10 @@
                .u.bind_interdomain.remote_dom = tpmif->domid,
                .u.bind_interdomain.remote_port = evtchn };
 
+        if (tpmif->irq) {
+                return 0;
+        }
+
        if ((tpmif->tx_area = alloc_vm_area(PAGE_SIZE)) == NULL)
                return -ENOMEM;
 
@@ -149,7 +153,6 @@
 
        tpmif->irq = bind_evtchn_to_irqhandler(
                tpmif->evtchn, tpmif_be_int, 0, "tpmif-backend", tpmif);
-       tpmif->status = CONNECTED;
        tpmif->shmem_ref = shared_page;
        tpmif->active = 1;
 
diff -r b0338759544e -r cb215a84d1af 
linux-2.6-xen-sparse/drivers/xen/tpmback/xenbus.c
--- a/linux-2.6-xen-sparse/drivers/xen/tpmback/xenbus.c Thu Nov 24 22:21:48 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/tpmback/xenbus.c Fri Nov 25 08:14:01 2005
@@ -1,4 +1,5 @@
 /*  Xenbus code for tpmif backend
+    Copyright (C) 2005 IBM Corporation
     Copyright (C) 2005 Rusty Russell <rusty@xxxxxxxxxxxxxxx>
 
     This program is free software; you can redistribute it and/or modify
@@ -29,72 +30,189 @@
 
        long int frontend_id;
        long int instance; // instance of TPM
+       u8 is_instance_set;// whether instance number has been set
 
        /* watch front end for changes */
        struct xenbus_watch backend_watch;
-
-       struct xenbus_watch watch;
-       char * frontpath;
+       XenbusState frontend_state;
 };
 
+static void maybe_connect(struct backend_info *be);
+static void connect(struct backend_info *be);
+static int connect_ring(struct backend_info *be);
+static void backend_changed(struct xenbus_watch *watch,
+                            const char **vec, unsigned int len);
+static void frontend_changed(struct xenbus_device *dev,
+                             XenbusState frontend_state);
+
 static int tpmback_remove(struct xenbus_device *dev)
 {
        struct backend_info *be = dev->data;
 
-       if (be->watch.node)
-               unregister_xenbus_watch(&be->watch);
-       unregister_xenbus_watch(&be->backend_watch);
-
-       tpmif_vtpm_close(be->instance);
-
-       if (be->tpmif)
+       if (be->backend_watch.node) {
+               unregister_xenbus_watch(&be->backend_watch);
+               kfree(be->backend_watch.node);
+               be->backend_watch.node = NULL;
+       }
+       if (be->tpmif) {
                tpmif_put(be->tpmif);
-
-       kfree(be->frontpath);
+               be->tpmif = NULL;
+       }
        kfree(be);
+       dev->data = NULL;
        return 0;
 }
 
-
-static void frontend_changed(struct xenbus_watch *watch,
-                            const char **vec, unsigned int len)
-{
-       unsigned long ringref;
-       unsigned int evtchn;
-       unsigned long ready = 1;
-       int err;
-       struct xenbus_transaction *xbt;
+static int tpmback_probe(struct xenbus_device *dev,
+                         const struct xenbus_device_id *id)
+{
+       int err;
+       struct backend_info *be = kmalloc(sizeof(struct backend_info),
+                                         GFP_KERNEL);
+
+       if (!be) {
+               xenbus_dev_fatal(dev, -ENOMEM,
+                                "allocating backend structure");
+               return -ENOMEM;
+       }
+
+       memset(be, 0, sizeof(*be));
+
+       be->is_instance_set = FALSE;
+       be->dev = dev;
+       dev->data = be;
+
+       err = xenbus_watch_path2(dev, dev->nodename,
+                               "instance", &be->backend_watch,
+                               backend_changed);
+       if (err) {
+               goto fail;
+       }
+
+       err = xenbus_switch_state(dev, NULL, XenbusStateInitWait);
+       if (err) {
+               goto fail;
+       }
+       return 0;
+fail:
+       tpmback_remove(dev);
+       return err;
+}
+
+
+static void backend_changed(struct xenbus_watch *watch,
+                            const char **vec, unsigned int len)
+{
+       int err;
+       long instance;
        struct backend_info *be
-               = container_of(watch, struct backend_info, watch);
-
-       /* If other end is gone, delete ourself. */
-       if (vec && !xenbus_exists(NULL, be->frontpath, "")) {
-               xenbus_rm(NULL, be->dev->nodename, "");
+               = container_of(watch, struct backend_info, backend_watch);
+       struct xenbus_device *dev = be->dev;
+
+       err = xenbus_scanf(NULL, dev->nodename,
+                          "instance","%li", &instance);
+       if (XENBUS_EXIST_ERR(err)) {
+               return;
+       }
+
+       if (err != 1) {
+               xenbus_dev_fatal(dev, err, "reading instance");
+               return;
+       }
+
+       if (be->is_instance_set != FALSE && be->instance != instance) {
+               printk(KERN_WARNING
+                      "tpmback: changing instance (from %ld to %ld) "
+                      "not allowed.\n",
+                      be->instance, instance);
+               return;
+       }
+
+       if (be->is_instance_set == FALSE) {
+               be->tpmif = tpmif_find(dev->otherend_id,
+                                      instance);
+               if (IS_ERR(be->tpmif)) {
+                       err = PTR_ERR(be->tpmif);
+                       be->tpmif = NULL;
+                       xenbus_dev_fatal(dev,err,"creating block interface");
+                       return;
+               }
+               be->instance = instance;
+               be->is_instance_set = TRUE;
+
+               /*
+                * There's an unfortunate problem:
+                * Sometimes after a suspend/resume the
+                * state switch to XenbusStateInitialised happens
+                * *before* I get to this point here. Since then
+                * the connect_ring() must have failed (be->tpmif is
+                * still NULL), I just call it here again indirectly.
+                */
+               if (be->frontend_state == XenbusStateInitialised) {
+                       frontend_changed(dev, be->frontend_state);
+               }
+       }
+}
+
+
+static void frontend_changed(struct xenbus_device *dev,
+                             XenbusState frontend_state)
+{
+       struct backend_info *be = dev->data;
+       int err;
+
+       be->frontend_state = frontend_state;
+
+       switch (frontend_state) {
+       case XenbusStateInitialising:
+       case XenbusStateConnected:
+               break;
+
+       case XenbusStateInitialised:
+               err = connect_ring(be);
+               if (err) {
+                       return;
+               }
+               maybe_connect(be);
+               break;
+
+       case XenbusStateClosing:
+               xenbus_switch_state(dev, NULL, XenbusStateClosing);
+               break;
+
+       case XenbusStateClosed:
+               /*
+                * Notify the vTPM manager about the front-end
+                * having left.
+                */
+               tpmif_vtpm_close(be->instance);
                device_unregister(&be->dev->dev);
-               return;
-       }
+               break;
+
+       case XenbusStateUnknown:
+       case XenbusStateInitWait:
+       default:
+               xenbus_dev_fatal(dev, -EINVAL,
+                                "saw state %d at frontend",
+                                frontend_state);
+               break;
+       }
+}
+
+
+
+static void maybe_connect(struct backend_info *be)
+{
+       int err;
 
        if (be->tpmif == NULL || be->tpmif->status == CONNECTED)
                return;
 
-       err = xenbus_gather(NULL, be->frontpath,
-                           "ring-ref", "%lu", &ringref,
-                           "event-channel", "%u", &evtchn, NULL);
-       if (err) {
-               xenbus_dev_error(be->dev, err,
-                                "reading %s/ring-ref and event-channel",
-                                be->frontpath);
-               return;
-       }
-
-       err = tpmif_map(be->tpmif, ringref, evtchn);
-       if (err) {
-               xenbus_dev_error(be->dev, err,
-                                "mapping shared-frame %lu port %u",
-                                ringref, evtchn);
-               return;
-       }
-
+       connect(be);
+
+       /*
+        * Notify the vTPM manager about a new front-end.
+        */
        err = tpmif_vtpm_open(be->tpmif,
                              be->frontend_id,
                              be->instance);
@@ -107,157 +225,75 @@
                 */
                return;
        }
-
-       /*
-        * Tell the front-end that we are ready to go -
-        * unless something bad happens
-        */
+}
+
+
+static void connect(struct backend_info *be)
+{
+       struct xenbus_transaction *xbt;
+       int err;
+       struct xenbus_device *dev = be->dev;
+       unsigned long ready = 1;
+
 again:
        xbt = xenbus_transaction_start();
        if (IS_ERR(xbt)) {
-               xenbus_dev_error(be->dev, err, "starting transaction");
+               err = PTR_ERR(xbt);
+               xenbus_dev_fatal(be->dev, err, "starting transaction");
                return;
        }
 
        err = xenbus_printf(xbt, be->dev->nodename,
                            "ready", "%lu", ready);
        if (err) {
-               xenbus_dev_error(be->dev, err, "writing 'ready'");
+               xenbus_dev_fatal(be->dev, err, "writing 'ready'");
                goto abort;
        }
+
+       err = xenbus_switch_state(dev, xbt, XenbusStateConnected);
+       if (err)
+               goto abort;
+
+       be->tpmif->status = CONNECTED;
 
        err = xenbus_transaction_end(xbt, 0);
        if (err == -EAGAIN)
                goto again;
        if (err) {
-               xenbus_dev_error(be->dev, err, "end of transaction");
-               goto abort;
-       }
-
-       xenbus_dev_ok(be->dev);
+               xenbus_dev_fatal(be->dev, err, "end of transaction");
+       }
        return;
 abort:
        xenbus_transaction_end(xbt, 1);
 }
 
 
-static void backend_changed(struct xenbus_watch *watch,
-                           const char **vec, unsigned int len)
-{
-       int err;
-       long int instance;
-       struct backend_info *be
-               = container_of(watch, struct backend_info, backend_watch);
+static int connect_ring(struct backend_info *be)
+{
        struct xenbus_device *dev = be->dev;
-
-       err = xenbus_scanf(NULL, dev->nodename, "instance", "%li", &instance);
-       if (XENBUS_EXIST_ERR(err))
-               return;
-       if (err < 0) {
-               xenbus_dev_error(dev, err, "reading 'instance' variable");
-               return;
-       }
-
-       if (be->instance != -1 && be->instance != instance) {
-               printk(KERN_WARNING
-                      "cannot change the instance\n");
-               return;
-       }
-       be->instance = instance;
-
-       if (be->tpmif == NULL) {
-               unsigned int len = max(XS_WATCH_PATH, XS_WATCH_TOKEN) + 1;
-               const char *vec[len];
-
-               be->tpmif = tpmif_find(be->frontend_id,
-                                      instance);
-               if (IS_ERR(be->tpmif)) {
-                       err = PTR_ERR(be->tpmif);
-                       be->tpmif = NULL;
-                       xenbus_dev_error(dev, err, "creating interface");
-                       return;
+       unsigned long ring_ref;
+       unsigned int evtchn;
+       int err;
+
+       err = xenbus_gather(NULL, dev->otherend,
+                           "ring-ref", "%lu", &ring_ref,
+                           "event-channel", "%u", &evtchn, NULL);
+       if (err) {
+               xenbus_dev_error(dev, err,
+                                "reading %s/ring-ref and event-channel",
+                                dev->otherend);
+               return err;
+       }
+       if (be->tpmif != NULL) {
+               err = tpmif_map(be->tpmif, ring_ref, evtchn);
+               if (err) {
+                       xenbus_dev_error(dev, err,
+                                        "mapping shared-frame %lu port %u",
+                                        ring_ref, evtchn);
+                       return err;
                }
-
-               vec[XS_WATCH_PATH] = be->frontpath;
-               vec[XS_WATCH_TOKEN] = NULL;
-
-               /* Pass in NULL node to skip exist test. */
-               frontend_changed(&be->watch, vec, len);
-       }
-}
-
-
-static int tpmback_probe(struct xenbus_device *dev,
-                        const struct xenbus_device_id *id)
-{
-       struct backend_info *be;
-       char *frontend;
-       int err;
-
-       be = kmalloc(sizeof(*be), GFP_KERNEL);
-       if (!be) {
-               xenbus_dev_error(dev, -ENOMEM, "allocating backend structure");
-               err = -ENOMEM;
-       }
-
-       memset(be, 0, sizeof(*be));
-
-       frontend = NULL;
-       err = xenbus_gather(NULL, dev->nodename,
-                           "frontend-id", "%li", &be->frontend_id,
-                           "frontend", NULL, &frontend,
-                           NULL);
-       if (XENBUS_EXIST_ERR(err))
-               goto free_be;
-       if (err < 0) {
-               xenbus_dev_error(dev, err,
-                                "reading %s/frontend or frontend-id",
-                                dev->nodename);
-               goto free_be;
-       }
-       if (strlen(frontend) == 0 || !xenbus_exists(NULL, frontend, "")) {
-               /* If we can't get a frontend path and a frontend-id,
-                * then our bus-id is no longer valid and we need to
-                * destroy the backend device.
-                */
-               err = -ENOENT;
-               goto free_be;
-       }
-
-       be->dev = dev;
-       be->backend_watch.node     = dev->nodename;
-       /* Implicitly calls backend_changed() once. */
-       be->backend_watch.callback = backend_changed;
-       be->instance = -1;
-       err = register_xenbus_watch(&be->backend_watch);
-       if (err) {
-               be->backend_watch.node = NULL;
-               xenbus_dev_error(dev, err, "adding backend watch on %s",
-                                dev->nodename);
-               goto free_be;
-       }
-
-       be->frontpath = frontend;
-       be->watch.node = be->frontpath;
-       be->watch.callback = frontend_changed;
-       err = register_xenbus_watch(&be->watch);
-       if (err) {
-               be->watch.node = NULL;
-               xenbus_dev_error(dev, err,
-                                "adding frontend watch on %s",
-                                be->frontpath);
-               goto free_be;
-       }
-
-       dev->data = be;
-       return err;
-
-free_be:
-       if (be->backend_watch.node)
-               unregister_xenbus_watch(&be->backend_watch);
-       kfree(frontend);
-       kfree(be);
-       return err;
+       }
+       return 0;
 }
 
 
@@ -273,6 +309,7 @@
        .ids = tpmback_ids,
        .probe = tpmback_probe,
        .remove = tpmback_remove,
+       .otherend_changed = frontend_changed,
 };
 
 
diff -r b0338759544e -r cb215a84d1af 
linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c
--- a/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c      Thu Nov 24 
22:21:48 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c      Fri Nov 25 
08:14:01 2005
@@ -73,7 +73,8 @@
 static void tpmif_connect(u16 evtchn, domid_t domid);
 static DECLARE_TASKLET(tpmif_rx_tasklet, tpmif_rx_action, 0);
 static int tpm_allocate_buffers(struct tpm_private *tp);
-static void tpmif_set_connected_state(struct tpm_private *tp, int newstate);
+static void tpmif_set_connected_state(struct tpm_private *tp,
+                                      u8 newstate);
 static int tpm_xmit(struct tpm_private *tp,
                     const u8 * buf, size_t count, int userbuffer,
                     void *remember);
@@ -212,87 +213,46 @@
  XENBUS support code
 **************************************************************/
 
-static void watch_for_status(struct xenbus_watch *watch,
-                            const char **vec, unsigned int len)
-{
-       struct tpmfront_info *info;
-       int err;
-       unsigned long ready;
-       struct tpm_private *tp = &my_private;
-       const char *node = vec[XS_WATCH_PATH];
-
-       info = container_of(watch, struct tpmfront_info, watch);
-       node += strlen(watch->node);
-
-       if (tp->connected)
-               return;
-
-       err = xenbus_gather(NULL, watch->node,
-                           "ready", "%lu", &ready,
-                           NULL);
-       if (err) {
-               xenbus_dev_error(info->dev, err, "reading 'ready' field");
-               return;
-       }
-
-       tpmif_set_connected_state(tp, 1);
-
-       xenbus_dev_ok(info->dev);
-}
-
-
 static int setup_tpmring(struct xenbus_device *dev,
-                         struct tpmfront_info * info,
-                         domid_t backend_id)
+                         struct tpmfront_info * info)
 {
        tpmif_tx_interface_t *sring;
        struct tpm_private *tp = &my_private;
        int err;
-       evtchn_op_t op = {
-               .cmd = EVTCHNOP_alloc_unbound,
-               .u.alloc_unbound.dom = DOMID_SELF,
-               .u.alloc_unbound.remote_dom = backend_id } ;
 
        sring = (void *)__get_free_page(GFP_KERNEL);
        if (!sring) {
-               xenbus_dev_error(dev, -ENOMEM, "allocating shared ring");
+               xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
                return -ENOMEM;
        }
        tp->tx = sring;
 
        tpm_allocate_buffers(tp);
 
-       err = gnttab_grant_foreign_access(backend_id,
-                                         (virt_to_machine(tp->tx) >> 
PAGE_SHIFT),
-                                         0);
-
-       if (err == -ENOSPC) {
+       err = xenbus_grant_ring(dev, virt_to_mfn(tp->tx));
+       if (err < 0) {
                free_page((unsigned long)sring);
                tp->tx = NULL;
-               xenbus_dev_error(dev, err, "allocating grant reference");
-               return err;
+               xenbus_dev_fatal(dev, err, "allocating grant reference");
+               goto fail;
        }
        info->ring_ref = err;
 
-       err = HYPERVISOR_event_channel_op(&op);
-       if (err) {
-               gnttab_end_foreign_access(info->ring_ref, 0,
-                                         (unsigned long)sring);
-               tp->tx = NULL;
-               xenbus_dev_error(dev, err, "allocating event channel");
-               return err;
-       }
-
-       tpmif_connect(op.u.alloc_unbound.port, backend_id);
+       err = xenbus_alloc_evtchn(dev, &tp->evtchn);
+       if (err)
+               goto fail;
+
+       tpmif_connect(tp->evtchn, dev->otherend_id);
 
        return 0;
+fail:
+       return err;
 }
 
 
 static void destroy_tpmring(struct tpmfront_info *info, struct tpm_private *tp)
 {
-       tpmif_set_connected_state(tp,0);
-
+       tpmif_set_connected_state(tp, FALSE);
        if ( tp->tx != NULL ) {
                gnttab_end_foreign_access(info->ring_ref, 0,
                                          (unsigned long)tp->tx);
@@ -308,42 +268,20 @@
 static int talk_to_backend(struct xenbus_device *dev,
                            struct tpmfront_info *info)
 {
-       char *backend;
-       const char *message;
+       const char *message = NULL;
        int err;
-       int backend_id;
        struct xenbus_transaction *xbt;
 
-       backend = NULL;
-       err = xenbus_gather(NULL, dev->nodename,
-                           "backend-id", "%i", &backend_id,
-                           "backend", NULL, &backend,
-                           NULL);
-       if (XENBUS_EXIST_ERR(err))
-               goto out;
-       if (backend && strlen(backend) == 0) {
-               err = -ENOENT;
-               goto out;
-       }
-       if (err < 0) {
-               xenbus_dev_error(dev, err, "reading %s/backend or backend-id",
-                                dev->nodename);
-               goto out;
-       }
-
-       info->backend_id      = backend_id;
-       my_private.backend_id = backend_id;
-
-       err = setup_tpmring(dev, info, backend_id);
+       err = setup_tpmring(dev, info);
        if (err) {
-               xenbus_dev_error(dev, err, "setting up ring");
+               xenbus_dev_fatal(dev, err, "setting up ring");
                goto out;
        }
 
 again:
        xbt = xenbus_transaction_start();
        if (IS_ERR(xbt)) {
-               xenbus_dev_error(dev, err, "starting transaction");
+               xenbus_dev_fatal(dev, err, "starting transaction");
                goto destroy_tpmring;
        }
 
@@ -361,34 +299,60 @@
                goto abort_transaction;
        }
 
+       err = xenbus_switch_state(dev, xbt, XenbusStateInitialised);
+       if (err) {
+               goto abort_transaction;
+       }
+
        err = xenbus_transaction_end(xbt, 0);
        if (err == -EAGAIN)
                goto again;
        if (err) {
-               xenbus_dev_error(dev, err, "completing transaction");
+               xenbus_dev_fatal(dev, err, "completing transaction");
                goto destroy_tpmring;
        }
-
-       info->watch.node = backend;
-       info->watch.callback = watch_for_status;
-       err = register_xenbus_watch(&info->watch);
-       if (err) {
-               xenbus_dev_error(dev, err, "registering watch on backend");
-               goto destroy_tpmring;
-       }
-
-       info->backend = backend;
-
        return 0;
 
 abort_transaction:
        xenbus_transaction_end(xbt, 1);
-       xenbus_dev_error(dev, err, "%s", message);
+       if (message)
+               xenbus_dev_error(dev, err, "%s", message);
 destroy_tpmring:
        destroy_tpmring(info, &my_private);
 out:
-       kfree(backend);
        return err;
+}
+
+/**
+ * Callback received when the backend's state changes.
+ */
+static void backend_changed(struct xenbus_device *dev,
+                           XenbusState backend_state)
+{
+       struct tpm_private *tp = &my_private;
+       DPRINTK("\n");
+
+       switch (backend_state) {
+       case XenbusStateInitialising:
+       case XenbusStateInitWait:
+       case XenbusStateInitialised:
+       case XenbusStateUnknown:
+               break;
+
+       case XenbusStateConnected:
+               tpmif_set_connected_state(tp, TRUE);
+               break;
+
+       case XenbusStateClosing:
+               tpmif_set_connected_state(tp, FALSE);
+               break;
+
+       case XenbusStateClosed:
+               if (tp->is_suspended == FALSE) {
+                       device_unregister(&dev->dev);
+               }
+               break;
+       }
 }
 
 
@@ -398,8 +362,6 @@
        int err;
        struct tpmfront_info *info;
        int handle;
-       int len = max(XS_WATCH_PATH, XS_WATCH_TOKEN) + 1;
-       const char *vec[len];
 
        err = xenbus_scanf(NULL, dev->nodename,
                           "handle", "%i", &handle);
@@ -407,19 +369,19 @@
                return err;
 
        if (err < 0) {
-               xenbus_dev_error(dev,err,"reading virtual-device");
+               xenbus_dev_fatal(dev,err,"reading virtual-device");
                return err;
        }
 
        info = kmalloc(sizeof(*info), GFP_KERNEL);
        if (!info) {
-               xenbus_dev_error(dev,err,"allocating info structure");
+               err = -ENOMEM;
+               xenbus_dev_fatal(dev,err,"allocating info structure");
                return err;
        }
        memset(info, 0x0, sizeof(*info));
 
        info->dev = dev;
-       info->handle = handle;
        dev->data = info;
 
        err = talk_to_backend(dev, info);
@@ -428,41 +390,33 @@
                dev->data = NULL;
                return err;
        }
-
-       vec[XS_WATCH_PATH]  = info->watch.node;
-       vec[XS_WATCH_TOKEN] = NULL;
-       watch_for_status(&info->watch, vec, len);
-
        return 0;
 }
 
+
 static int tpmfront_remove(struct xenbus_device *dev)
 {
        struct tpmfront_info *info = dev->data;
-       if (info->backend)
-               unregister_xenbus_watch(&info->watch);
 
        destroy_tpmring(info, &my_private);
 
-       kfree(info->backend);
        kfree(info);
-
        return 0;
 }
 
 static int
 tpmfront_suspend(struct xenbus_device *dev)
 {
-       struct tpmfront_info *info = dev->data;
        struct tpm_private *tp = &my_private;
        u32 ctr = 0;
 
        /* lock, so no app can send */
        down(&suspend_lock);
+       tp->is_suspended = TRUE;
 
        while (atomic_read(&tp->tx_busy) && ctr <= 25) {
-               if ((ctr % 10) == 0)
-                       printk("INFO: Waiting for outstanding request.\n");
+               if ((ctr % 10) == 0)
+                       printk("TPM-FE [INFO]: Waiting for outstanding 
request.\n");
                /*
                 * Wait for a request to be responded to.
                 */
@@ -474,14 +428,9 @@
                /*
                 * A temporary work-around.
                 */
-               printk("WARNING: Resetting busy flag.");
+               printk("TPM-FE [WARNING]: Resetting busy flag.");
                atomic_set(&tp->tx_busy, 0);
        }
-
-       unregister_xenbus_watch(&info->watch);
-
-       kfree(info->backend);
-       info->backend = NULL;
 
        return 0;
 }
@@ -492,8 +441,6 @@
        struct tpmfront_info *info = dev->data;
        int err = talk_to_backend(dev, info);
 
-       /* unlock, so apps can resume sending */
-       up(&suspend_lock);
 
        return err;
 }
@@ -530,12 +477,13 @@
        .probe = tpmfront_probe,
        .remove =  tpmfront_remove,
        .resume = tpmfront_resume,
+       .otherend_changed = backend_changed,
        .suspend = tpmfront_suspend,
 };
 
 static void __init init_tpm_xenbus(void)
 {
-       xenbus_register_driver(&tpmfront);
+       xenbus_register_frontend(&tpmfront);
 }
 
 
@@ -628,12 +576,13 @@
        spin_lock_irq(&tp->tx_lock);
 
        if (unlikely(atomic_read(&tp->tx_busy))) {
-               printk("There's an outstanding request/response on the way!\n");
+               printk("tpm_xmit: There's an outstanding request/response "
+                      "on the way!\n");
                spin_unlock_irq(&tp->tx_lock);
                return -EBUSY;
        }
 
-       if (tp->connected != 1) {
+       if (tp->is_connected != TRUE) {
                spin_unlock_irq(&tp->tx_lock);
                return -EIO;
        }
@@ -705,24 +654,40 @@
        down(&upperlayer_lock);
 
        if (upperlayer_tpmfe != NULL) {
-               switch (tp->connected) {
-                       case 1:
-                               
upperlayer_tpmfe->status(TPMFE_STATUS_CONNECTED);
-                       break;
-
-                       default:
-                               upperlayer_tpmfe->status(0);
-                       break;
+               if (tp->is_connected) {
+                       upperlayer_tpmfe->status(TPMFE_STATUS_CONNECTED);
+               } else {
+                       upperlayer_tpmfe->status(0);
                }
        }
        up(&upperlayer_lock);
 }
 
 
-static void tpmif_set_connected_state(struct tpm_private *tp, int newstate)
-{
-       if (newstate != tp->connected) {
-               tp->connected = newstate;
+static void tpmif_set_connected_state(struct tpm_private *tp, u8 is_connected)
+{
+       /*
+        * Don't notify upper layer if we are in suspend mode and
+        * should disconnect - assumption is that we will resume
+        * The semaphore keeps apps from sending.
+        */
+       if (is_connected == FALSE && tp->is_suspended == TRUE) {
+               return;
+       }
+
+       /*
+        * Unlock the semaphore if we are connected again
+        * after being suspended - now resuming.
+        * This also removes the suspend state.
+        */
+       if (is_connected == TRUE && tp->is_suspended == TRUE) {
+               tp->is_suspended = FALSE;
+               /* unlock, so apps can resume sending */
+               up(&suspend_lock);
+       }
+
+       if (is_connected != tp->is_connected) {
+               tp->is_connected = is_connected;
                tpmif_notify_upperlayer(tp);
        }
 }
diff -r b0338759544e -r cb215a84d1af 
linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.h
--- a/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.h      Thu Nov 24 
22:21:48 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.h      Fri Nov 25 
08:14:01 2005
@@ -1,12 +1,17 @@
 #ifndef TPM_FRONT_H
 #define TPM_FRONT_H
 
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
 
-struct tpm_private
-{
+struct tpm_private {
        tpmif_tx_interface_t *tx;
-       unsigned int evtchn, irq;
-       int connected;
+       unsigned int evtchn;
+       unsigned int irq;
+       u8 is_connected;
+       u8 is_suspended;
 
        spinlock_t tx_lock;
 
@@ -16,25 +21,18 @@
        void *tx_remember;
        domid_t backend_id;
        wait_queue_head_t wait_q;
+
 };
 
-
-struct tpmfront_info
-{
-       struct xenbus_watch watch;
-       int handle;
+struct tpmfront_info {
        struct xenbus_device *dev;
-       char *backend;
        int ring_ref;
-       domid_t backend_id;
 };
 
-
-struct tx_buffer
-{
+struct tx_buffer {
        unsigned int size;      // available space in data
        unsigned int len;       // used space in data
-       unsigned char *data;    // pointer to a page
+       unsigned char *data;    // pointer to a page
 };
 
 #endif
diff -r b0338759544e -r cb215a84d1af tools/examples/Makefile
--- a/tools/examples/Makefile   Thu Nov 24 22:21:48 2005
+++ b/tools/examples/Makefile   Fri Nov 25 08:14:01 2005
@@ -26,9 +26,10 @@
 XEN_SCRIPTS += network-nat vif-nat
 XEN_SCRIPTS += block
 XEN_SCRIPTS += block-enbd block-nbd
+XEN_SCRIPTS += vtpm
 XEN_SCRIPT_DATA = xen-script-common.sh
 XEN_SCRIPT_DATA += xen-hotplug-common.sh xen-network-common.sh vif-common.sh
-XEN_SCRIPT_DATA += block-common.sh
+XEN_SCRIPT_DATA += block-common.sh vtpm-common.sh
 
 XEN_HOTPLUG_DIR = /etc/hotplug
 XEN_HOTPLUG_SCRIPTS = xen-backend.agent
diff -r b0338759544e -r cb215a84d1af tools/examples/xen-backend.agent
--- a/tools/examples/xen-backend.agent  Thu Nov 24 22:21:48 2005
+++ b/tools/examples/xen-backend.agent  Fri Nov 25 08:14:01 2005
@@ -5,6 +5,9 @@
 case "$XENBUS_TYPE" in
   vbd)
     /etc/xen/scripts/block "$ACTION"
+    ;;
+  vtpm)
+    /etc/xen/scripts/vtpm "$ACTION"
     ;;
   vif)
     [ -n "$script" ] && $script "$ACTION"
diff -r b0338759544e -r cb215a84d1af tools/examples/xen-backend.rules
--- a/tools/examples/xen-backend.rules  Thu Nov 24 22:21:48 2005
+++ b/tools/examples/xen-backend.rules  Fri Nov 25 08:14:01 2005
@@ -1,4 +1,5 @@
 SUBSYSTEM=="xen-backend", KERNEL=="vbd*", RUN+="/etc/xen/scripts/block 
$env{ACTION}"
+SUBSYSTEM=="xen-backend", KERNEL=="vtpm*", RUN+="/etc/xen/scripts/vtpm 
$env{ACTION}"
 SUBSYSTEM=="xen-backend", KERNEL=="vif*", ACTION=="online", RUN+="$env{script} 
online"
 SUBSYSTEM=="xen-backend", KERNEL=="vif*", ACTION=="offline", 
RUN+="$env{script} offline"
 SUBSYSTEM=="xen-backend", ACTION=="remove", RUN+="/bin/bash -c 
'/usr/bin/xenstore-rm -t $$(/usr/bin/xenstore-read $env{XENBUS_PATH}/frontend)'"
diff -r b0338759544e -r cb215a84d1af tools/python/xen/xend/image.py
--- a/tools/python/xen/xend/image.py    Thu Nov 24 22:21:48 2005
+++ b/tools/python/xen/xend/image.py    Fri Nov 25 08:14:01 2005
@@ -293,7 +293,7 @@
                ret.append("-bridge")
                ret.append("%s" % bridge)
             if name == 'vtpm':
-               instance = sxp.child_value(info, 'instance')
+               instance = sxp.child_value(info, 'pref_instance')
                ret.append("-instance")
                ret.append("%s" % instance)
         return ret
diff -r b0338759544e -r cb215a84d1af tools/python/xen/xend/server/tpmif.py
--- a/tools/python/xen/xend/server/tpmif.py     Thu Nov 24 22:21:48 2005
+++ b/tools/python/xen/xend/server/tpmif.py     Fri Nov 25 08:14:01 2005
@@ -38,10 +38,10 @@
     def getDeviceDetails(self, config):
         """@see DevController.getDeviceDetails"""
 
-        devid = int(sxp.child_value(config, 'instance', '0'))
+        devid = int(sxp.child_value(config, 'pref_instance', '0'))
         log.info("The domain has a TPM with instance %d." % devid)
 
-        back  = { 'instance' : "%i" % devid }
+        back  = { 'pref_instance' : "%i" % devid }
         front = { 'handle' : "%i" % devid }
 
         return (devid, back, front)
diff -r b0338759544e -r cb215a84d1af tools/python/xen/xm/create.py
--- a/tools/python/xen/xm/create.py     Thu Nov 24 22:21:48 2005
+++ b/tools/python/xen/xm/create.py     Fri Nov 25 08:14:01 2005
@@ -220,11 +220,9 @@
           fn=set_bool, default=0,
           use="Make the domain a network interface backend.")
 
-gopts.var('tpmif', val='frontend=DOM',
-          fn=append_value, default=[],
-          use="""Make the domain a TPM interface backend. If frontend is given,
-          the frontend in that domain is connected to this backend (not
-          completely implemented, yet)""")
+gopts.var('tpmif', val='no|yes',
+          fn=append_value, default=0,
+          use="Make the domain a TPM interface backend.")
 
 gopts.var('disk', val='phy:DEV,VDEV,MODE[,DOM]',
           fn=append_value, default=[],
@@ -273,9 +271,13 @@
 
 gopts.var('vtpm', val="instance=INSTANCE,backend=DOM",
           fn=append_value, default=[],
-          use="""Add a tpm interface. On the backend side us the the given
-          instance as virtual TPM instance. Use the backend in the given
-          domain.""")
+          use="""Add a TPM interface. On the backend side use the given
+          instance as virtual TPM instance. The given number is merely the
+          preferred instance number. The hotplug script will determine
+          which instance number will actually be assigned to the domain.
+          The associtation between virtual machine and the TPM instance
+          number can be found in /etc/xen/vtpm.db. Use the backend in the
+          given domain.""")
 
 gopts.var('nics', val="NUM",
           fn=set_int, default=1,
@@ -465,33 +467,19 @@
             if instance == "VTPMD":
                 instance = "0"
             else:
-                try:
-                    if int(instance) == 0:
-                        err('VM config error: vTPM instance must not be 0.')
-                except ValueError:
-                    err('Vm config error: could not parse instance number.')
+                if instance != None:
+                    try:
+                        if int(instance) == 0:
+                            err('VM config error: vTPM instance must not be 
0.')
+                    except ValueError:
+                        err('Vm config error: could not parse instance 
number.')
             backend = d.get('backend')
             config_vtpm = ['vtpm']
             if instance:
-                config_vtpm.append(['instance', instance])
+                config_vtpm.append(['pref_instance', instance])
             if backend:
                 config_vtpm.append(['backend', backend])
             config_devs.append(['device', config_vtpm])
-
-def configure_tpmif(config_devs, vals):
-    """Create the config for virtual TPM interfaces.
-    """
-    tpmif = vals.tpmif
-    tpmif_n = 1
-    for idx in range(0, tpmif_n):
-        if idx < len(tpmif):
-            d = tpmif[idx]
-            frontend = d.get('frontend')
-            config_tpmif = ['tpmif']
-            if frontend:
-                config_tpmif.append(['frontend', frontend])
-            config_devs.append(['device', config_tpmif])
-
 
 def configure_vifs(config_devs, vals):
     """Create the config for virtual network interfaces.
@@ -685,22 +673,6 @@
         vtpms.append(d)
     vals.vtpm = vtpms
 
-def preprocess_tpmif(vals):
-    if not vals.tpmif: return
-    tpmifs = []
-    for tpmif in vals.tpmif:
-        d = {}
-        a = tpmif.split(',')
-        for b in a:
-            (k, v) = b.strip().split('=', 1)
-            k = k.strip()
-            v = v.strip()
-            if k not in ['frontend']:
-                err('Invalid tpmif specifier: ' + vtpm)
-            d[k] = v
-        tpmifs.append(d)
-    vals.tpmif = tpmifs
-
 def preprocess_ip(vals):
     if vals.ip or vals.dhcp != 'off':
         dummy_nfs_server = '1.2.3.4'
@@ -791,7 +763,6 @@
     preprocess_nfs(vals)
     preprocess_vnc(vals)
     preprocess_vtpm(vals)
-    preprocess_tpmif(vals)
          
 def make_domain(opts, config):
     """Create, build and start a domain.
diff -r b0338759544e -r cb215a84d1af tools/examples/vtpm
--- /dev/null   Thu Nov 24 22:21:48 2005
+++ b/tools/examples/vtpm       Fri Nov 25 08:14:01 2005
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+dir=$(dirname "$0")
+. "$dir/vtpm-common.sh"
+
+
+case "$command" in
+    online | offline)
+        exit 0
+        ;;
+esac
+
+case "$command" in
+  add)
+    vtpm_create_instance
+  ;;
+  remove)
+    vtpm_remove_instance
+  ;;
+esac
+
+log debug "Successful vTPM operation '$command'."
+success
diff -r b0338759544e -r cb215a84d1af tools/examples/vtpm-common.sh
--- /dev/null   Thu Nov 24 22:21:48 2005
+++ b/tools/examples/vtpm-common.sh     Fri Nov 25 08:14:01 2005
@@ -0,0 +1,281 @@
+#
+# Copyright (c) 2005 IBM Corporation
+# Copyright (c) 2005 XenSource Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+dir=$(dirname "$0")
+. "$dir/xen-hotplug-common.sh"
+
+findCommand "$@"
+if [ "$command" != "online" ]  &&
+   [ "$command" != "offline" ] &&
+   [ "$command" != "add" ]     &&
+   [ "$command" != "remove" ]
+then
+       log err "Invalid command: $command"
+       exit 1
+fi
+
+
+XENBUS_PATH="${XENBUS_PATH:?}"
+
+
+VTPMDB="/etc/xen/vtpm.db"
+
+#In the vtpm-impl file some commands should be defined:
+#      vtpm_create, vtpm_setup, vtpm_reset, etc. (see below)
+#This should be indicated by setting VTPM_IMPL_DEFINED.
+if [ -r "$dir/vtpm-impl" ]; then
+       . "$dir/vtpm-impl"
+fi
+
+if [ -z "$VTPM_IMPL_DEFINED" ]; then
+       function vtpm_create () {
+               true
+       }
+       function vtpm_setup() {
+               true
+       }
+       function vtpm_reset() {
+               true
+       }
+       function vtpm_suspend() {
+               true
+       }
+       function vtpm_resume() {
+               true
+       }
+fi
+
+#Find the instance number for the vtpm given the name of the domain
+# Parameters
+# - vmname : the name of the vm
+# Return value
+#  Returns '0' if instance number could not be found, otherwise
+#  it returns the instance number in the variable 'instance'
+function find_instance () {
+       local vmname=$1
+       local ret=0
+       instance=`cat $VTPMDB |                    \
+                 awk -vvmname=$vmname             \
+                 '{                               \
+                    if ( 1 != index($1,"#")) {    \
+                      if ( $1 == vmname ) {       \
+                        print $2;                 \
+                        exit;                     \
+                      }                           \
+                    }                             \
+                  }'`
+       if [ "$instance" != "" ]; then
+               ret=1
+       fi
+       return $ret
+}
+
+
+# Check whether a particular instance number is still available
+# returns '1' if it is available
+function is_free_instancenum () {
+       local instance=$1
+       local avail=1
+
+       #Allowed instance number range: 1-255
+       if [ $instance -eq 0 -o $instance -gt 255 ]; then
+               avail=0
+       else
+               instances=`cat $VTPMDB |                 \
+                          gawk                          \
+                          '{                            \
+                              if (1 != index($1,"#")) { \
+                                printf("%s ",$2);       \
+                              }                         \
+                           }'`
+               for i in $instances; do
+                       if [ $i -eq $instance ]; then
+                               avail=0
+                               break
+                       fi
+               done
+       fi
+       return $avail
+}
+
+
+# Get an available instance number given the database
+# Returns an unused instance number
+function get_free_instancenum () {
+       local ctr
+       local instances
+       local don
+       instances=`cat $VTPMDB |                 \
+                  gawk                          \
+                  '{                            \
+                      if (1 != index($1,"#")) { \
+                        printf("%s ",$2);       \
+                      }                         \
+                   }'`
+       ctr=1
+       don=0
+       while [ $don -eq 0 ]; do
+               local found
+               found=0
+               for i in $instances; do
+                       if [ $i -eq $ctr ]; then
+                               found=1;
+                               break;
+                       fi
+               done
+
+               if [ $found -eq 0 ]; then
+                       don=1
+                       break
+               fi
+               let ctr=ctr+1
+       done
+       let instance=$ctr
+}
+
+
+# Add a domain name and instance number to the DB file
+function add_instance () {
+       local vmname=$1
+       local inst=$2
+
+       if [ ! -f $VTPMDB ]; then
+               echo "#Database for VM to vTPM association" > $VTPMDB
+               echo "#1st column: domain name" >> $VTPMDB
+               echo "#2nd column: TPM instance number" >> $VTPMDB
+       fi
+       validate_entry $vmname $inst
+       if [ $? -eq 0 ]; then
+               echo "$vmname $inst" >> $VTPMDB
+       fi
+}
+
+
+#Validate whether an entry is the same as passed to this
+#function
+function validate_entry () {
+       local rc=0
+       local vmname=$1
+       local inst=$2
+       local res
+       res=`cat $VTPMDB |             \
+            gawk -vvmname=$vmname     \
+                 -vinst=$inst         \
+            '{                        \
+                if ( 1 == index($1,"#")) {\
+                } else                \
+                if ( $1 == vmname &&  \
+                     $2 == inst) {    \
+                   printf("1");       \
+                   exit;              \
+                } else                \
+                if ( $1 == vmname ||  \
+                     $2 == inst) {    \
+                   printf("2");       \
+                   exit;              \
+                }                     \
+            }'`
+
+       if [ "$res" == "1" ]; then
+               let rc=1
+       elif [ "$res" == "2" ]; then
+               let rc=2
+       fi
+       return $rc
+}
+
+
+#Remove an entry from the vTPM database given its domain name
+function remove_entry () {
+       local vmname=$1
+       local VTPMDB_TMP="$VTPMDB".tmp
+       `cat $VTPMDB |             \
+        gawk -vvmname=$vmname     \
+        '{                        \
+           if ( $1 != vmname ) {  \
+             print $0;            \
+           }                      \
+        '} > $VTPMDB_TMP`
+       if [ -e $VTPMDB_TMP ]; then
+               mv -f $VTPMDB_TMP $VTPMDB
+       else
+               log err "Error creating temporary file '$VTPMDB_TMP'."
+       fi
+}
+
+
+#Create a vTPM instance
+# If no entry in the TPM database is found, the instance is
+# created and an entry added to the database.
+function vtpm_create_instance () {
+       local domname=$(xenstore_read "$XENBUS_PATH"/domain)
+       local res
+       set +e
+       find_instance $domname
+       res=$?
+       if [ $res -eq 0 ]; then
+               #Try to give the preferred instance to the domain
+               instance=$(xenstore_read "$XENBUS_PATH"/pref_instance)
+               if [ "$instance" != "" ]; then
+                       is_free_instancenum $instance
+                       res=$?
+                       if [ $res -eq 0 ]; then
+                               get_free_instancenum
+                       fi
+               else
+                       get_free_instancenum
+               fi
+               add_instance $domname $instance
+               if [ "$REASON" == "create" ]; then
+                       vtpm_create $instance
+               elif [ "$REASON" == "hibernate" ]; then
+                       vtpm_resume $instance $domname
+               else
+                       #default case for 'now'
+                       vtpm_create $instance
+               fi
+       fi
+       if [ "$REASON" == "create" ]; then
+               vtpm_reset $instance
+       elif [ "$REASON" == "hibernate" ]; then
+               vtpm_setup $instance
+       else
+               #default case for 'now'
+               vtpm_reset $instance
+       fi
+       xenstore_write $XENBUS_PATH/instance $instance
+       set -e
+}
+
+
+#Remove an instance
+function vtpm_remove_instance () {
+       local domname=$(xenstore_read "$XENBUS_PATH"/domain)
+       set +e
+       find_instance $domname
+       res=$?
+       if [ $res -eq 0 ]; then
+               #Something is really wrong with the DB
+               log err "vTPM DB file $VTPMDB has no entry for '$domname'"
+       else
+               if [ "$REASON" == "hibernate" ]; then
+                       vtpm_suspend $instance
+               fi
+       fi
+       set -e
+}

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

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