Patchwork [08/15] xen: Read and write the state of the VM in xenstore

login
register
mail settings
Submitter Stefano Stabellini
Date Aug. 12, 2010, 2:09 p.m.
Message ID <1281622202-3453-8-git-send-email-stefano.stabellini@eu.citrix.com>
Download mbox | patch
Permalink /patch/61609/
State New
Headers show

Comments

Stefano Stabellini - Aug. 12, 2010, 2:09 p.m.
From: Anthony PERARD <anthony.perard@citrix.com>

Introduce functions to read and write the state of the VM in xenstore.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 hw/xen_machine_fv.c   |    9 ++++
 target-xen/helper.c   |    7 +++
 target-xen/qemu-xen.h |    3 +
 target-xen/xenstore.c |  128 +++++++++++++++++++++++++++++++++++++++++++++++++
 target-xen/xenstore.h |    6 ++
 5 files changed, 153 insertions(+), 0 deletions(-)
Anthony Liguori - Aug. 13, 2010, 6:53 p.m.
On 08/12/2010 09:09 AM, stefano.stabellini@eu.citrix.com wrote:
> From: Anthony PERARD<anthony.perard@citrix.com>
>
> Introduce functions to read and write the state of the VM in xenstore.
>    

This basically creates a new management interface for QEMU via the xenstore.

Our management interface is QMP.  If you want to maintain compatibility, 
you'll need to write a QMP -> xenstore daemon that maps events 
appropriately.

Regards,

Anthony Liguori

> Signed-off-by: Anthony PERARD<anthony.perard@citrix.com>
> Signed-off-by: Stefano Stabellini<stefano.stabellini@eu.citrix.com>
> ---
>   hw/xen_machine_fv.c   |    9 ++++
>   target-xen/helper.c   |    7 +++
>   target-xen/qemu-xen.h |    3 +
>   target-xen/xenstore.c |  128 +++++++++++++++++++++++++++++++++++++++++++++++++
>   target-xen/xenstore.h |    6 ++
>   5 files changed, 153 insertions(+), 0 deletions(-)
>
> diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
> index ec826e7..a6e778a 100644
> --- a/hw/xen_machine_fv.c
> +++ b/hw/xen_machine_fv.c
> @@ -36,10 +36,17 @@
>   #include "xen_backend.h"
>   #include "xenstore.h"
>   #include "xen_platform.h"
> +#include "qemu-xen.h"
>   #include "xen/hvm/hvm_info_table.h"
>
>   #define MAX_IDE_BUS 2
>
> +static void xen_vm_change_state_handler(void *opaque, int running, int reason)
> +{
> +    if (running)
> +        xen_main_loop_prepare();
> +}
> +
>   static void xen_init_fv(ram_addr_t ram_size,
>                           const char *boot_device,
>                           const char *kernel_filename,
> @@ -150,6 +157,8 @@ static void xen_init_fv(ram_addr_t ram_size,
>       }
>
>       pc_pci_device_init(pci_bus);
> +
> +    qemu_add_vm_change_state_handler(xen_vm_change_state_handler, NULL);
>   }
>
>   static QEMUMachine xenfv_machine = {
> diff --git a/target-xen/helper.c b/target-xen/helper.c
> index d588e64..8cb7771 100644
> --- a/target-xen/helper.c
> +++ b/target-xen/helper.c
> @@ -19,6 +19,8 @@
>    */
>
>   #include "cpu.h"
> +#include "qemu-xen.h"
> +#include "xenstore.h"
>
>   CPUXenState *cpu_xen_init(const char *cpu_model)
>   {
> @@ -67,3 +69,8 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
>   {
>       return addr;
>   }
> +
> +void xen_main_loop_prepare(void)
> +{
> +    xenstore_record_dm_state("running");
> +}
> diff --git a/target-xen/qemu-xen.h b/target-xen/qemu-xen.h
> index d1910d6..091ae07 100644
> --- a/target-xen/qemu-xen.h
> +++ b/target-xen/qemu-xen.h
> @@ -27,4 +27,7 @@ int cpu_register_io_memory_fixed(int io_index,
>                              CPUWriteMemoryFunc * const *mem_write,
>                              void *opaque);
>
> +/* target-xen/helper.c */
> +void xen_main_loop_prepare(void);
> +
>   #endif /*QEMU_XEN_H*/
> diff --git a/target-xen/xenstore.c b/target-xen/xenstore.c
> index 9f2e1ea..6eb6a30 100644
> --- a/target-xen/xenstore.c
> +++ b/target-xen/xenstore.c
> @@ -13,6 +13,60 @@ static void xenstore_process_event(void *opaque)
>       free(vec);
>   }
>
> +static const char *xenstore_get_guest_uuid(void)
> +{
> +    static char *already_computed = NULL;
> +
> +    char *domain_path = NULL, *vm_path = NULL, *vm_value = NULL, *p = NULL;
> +    unsigned int len;
> +
> +    if (already_computed)
> +        return already_computed;
> +
> +    if (xen_xc == NULL)
> +        return NULL;
> +
> +    domain_path = xs_get_domain_path(xenstore, xen_domid);
> +    if (domain_path == NULL) {
> +        fprintf(stderr, "xs_get_domain_path() error. domid %d.\n", xen_domid);
> +        goto out;
> +    }
> +
> +    if (asprintf(&vm_path, "%s/vm", domain_path) == -1) {
> +        fprintf(stderr, "xenstore_get_guest_uuid(): out of memory.\n");
> +        goto out;
> +    }
> +    vm_value = xs_read(xenstore, XBT_NULL, vm_path,&len);
> +    if (vm_value == NULL) {
> +        fprintf(stderr, "xs_read(): uuid get error. %s.\n", vm_path);
> +        goto out;
> +    }
> +
> +    if (strtok(vm_value, "/") == NULL) {
> +        fprintf(stderr, "failed to parse guest uuid\n");
> +        goto out;
> +    }
> +    p = strtok(NULL, "/");
> +    if (p == NULL) {
> +        fprintf(stderr, "failed to parse guest uuid\n");
> +        goto out;
> +    }
> +
> +    if (asprintf(&already_computed, "%s", p) == -1) {
> +        fprintf(stderr, "xenstore_get_guest_uuid(): out of memory.\n");
> +        goto out;
> +    }
> +
> +    fprintf(stderr, "Guest uuid = %s\n", already_computed);
> +
> +out:
> +    free(domain_path);
> +    free(vm_path);
> +    free(vm_value);
> +
> +    return already_computed;
> +}
> +
>   int xen_dm_init(void)
>   {
>       xenstore = xs_daemon_open();
> @@ -29,6 +83,7 @@ int xen_dm_init(void)
>           xen_be_printf(NULL, 0, "can't open xen interface\n");
>           goto err;
>       }
> +
>       return 0;
>
>   err:
> @@ -38,3 +93,76 @@ err:
>
>       return -1;
>   }
> +
> +static char *xenstore_vm_key_path(int domid, const char *key) {
> +    const char *uuid;
> +    char *buf = NULL;
> +
> +    if (xenstore == NULL)
> +        return NULL;
> +
> +    uuid = xenstore_get_guest_uuid();
> +    if (!uuid)
> +        return NULL;
> +
> +    if (asprintf(&buf, "/vm/%s/%s", uuid, key) == -1)
> +        return NULL;
> +
> +    return buf;
> +}
> +
> +char *xenstore_vm_read(int domid, const char *key, unsigned int *len)
> +{
> +    char *path = NULL, *value = NULL;
> +
> +    path = xenstore_vm_key_path(domid, key);
> +    if (!path)
> +        return NULL;
> +
> +    value = xs_read(xenstore, XBT_NULL, path, len);
> +    if (value == NULL) {
> +        fprintf(stderr, "xs_read(%s): read error\n", path);
> +    }
> +
> +    free(path);
> +    return value;
> +}
> +
> +int xenstore_vm_write(int domid, const char *key, const char *value)
> +{
> +    char *path = NULL;
> +    int rc = -1;
> +
> +    path = xenstore_vm_key_path(domid, key);
> +    if (!path)
> +        return 0;
> +
> +    rc = xs_write(xenstore, XBT_NULL, path, value, strlen(value));
> +    if (rc == 0) {
> +        fprintf(stderr, "xs_write(%s, %s): write error\n", path, key);
> +    }
> +
> +    free(path);
> +    return rc;
> +}
> +
> +void xenstore_record_dm(const char *subpath, const char *state)
> +{
> +    char *path = NULL;
> +
> +    if (asprintf(&path,
> +                 "/local/domain/0/device-model/%u/%s", xen_domid, subpath) == -1) {
> +        fprintf(stderr, "out of memory recording dm\n");
> +        goto out;
> +    }
> +    if (!xs_write(xenstore, XBT_NULL, path, state, strlen(state)))
> +        fprintf(stderr, "error recording dm\n");
> +
> +out:
> +    free(path);
> +}
> +
> +void xenstore_record_dm_state(const char *state)
> +{
> +    xenstore_record_dm("state", state);
> +}
> diff --git a/target-xen/xenstore.h b/target-xen/xenstore.h
> index 90baf79..c8144ea 100644
> --- a/target-xen/xenstore.h
> +++ b/target-xen/xenstore.h
> @@ -3,4 +3,10 @@
>
>   int xen_dm_init(void);
>
> +char *xenstore_vm_read(int domid, const char *key, unsigned int *len);
> +int xenstore_vm_write(int domid, const char *key, const char *value);
> +
> +void xenstore_record_dm(const char *subpath, const char *state);
> +void xenstore_record_dm_state(const char *state);
> +
>   #endif /* !XENSTORE_H_ */
>
Paolo Bonzini - Aug. 15, 2010, 2:12 p.m.
On 08/13/2010 02:53 PM, Anthony Liguori wrote:
> On 08/12/2010 09:09 AM, stefano.stabellini@eu.citrix.com wrote:
>> From: Anthony PERARD<anthony.perard@citrix.com>
>>
>> Introduce functions to read and write the state of the VM in xenstore.
>
> This basically creates a new management interface for QEMU via the
> xenstore.
>
> Our management interface is QMP. If you want to maintain compatibility,
> you'll need to write a QMP -> xenstore daemon that maps events
> appropriately.

This would belong in xl/libxl.

Paolo
Stefano Stabellini - Aug. 16, 2010, 11:15 a.m.
On Sun, 15 Aug 2010, Paolo Bonzini wrote:
> On 08/13/2010 02:53 PM, Anthony Liguori wrote:
> > On 08/12/2010 09:09 AM, stefano.stabellini@eu.citrix.com wrote:
> >> From: Anthony PERARD<anthony.perard@citrix.com>
> >>
> >> Introduce functions to read and write the state of the VM in xenstore.
> >
> > This basically creates a new management interface for QEMU via the
> > xenstore.
> >
> > Our management interface is QMP. If you want to maintain compatibility,
> > you'll need to write a QMP -> xenstore daemon that maps events
> > appropriately.
> 
> This would belong in xl/libxl.
 
Yes, but considering that we don't want a xenstore-based management
interface I would gladly do without the compatibility daemon.
We'll try to reduce all the xenstore interaction to the bare minimum,
and use QMP everywhere else.
Paolo Bonzini - Aug. 16, 2010, 12:13 p.m.
On 08/16/2010 01:15 PM, Stefano Stabellini wrote:
> On Sun, 15 Aug 2010, Paolo Bonzini wrote:
>> On 08/13/2010 02:53 PM, Anthony Liguori wrote:
>>> On 08/12/2010 09:09 AM, stefano.stabellini@eu.citrix.com wrote:
>>>> From: Anthony PERARD<anthony.perard@citrix.com>
>>>>
>>>> Introduce functions to read and write the state of the VM in xenstore.
>>>
>>> This basically creates a new management interface for QEMU via the
>>> xenstore.
>>>
>>> Our management interface is QMP. If you want to maintain compatibility,
>>> you'll need to write a QMP ->  xenstore daemon that maps events
>>> appropriately.
>>
>> This would belong in xl/libxl.
>
> Yes, but considering that we don't want a xenstore-based management
> interface I would gladly do without the compatibility daemon.
> We'll try to reduce all the xenstore interaction to the bare minimum,
> and use QMP everywhere else.

Yes, I was just pointing out that you don't need a new compatibility 
daemon.  Since xl is already daemonizing itself to handle on_crash and 
friends, it could also set up all the watches it cares about, and 
convert them to QMP commands.  It's all more code that needs to be 
written of course, and boring stuff even. :)

Paolo
Stefano Stabellini - Aug. 16, 2010, 12:59 p.m.
On Mon, 16 Aug 2010, Paolo Bonzini wrote:
> On 08/16/2010 01:15 PM, Stefano Stabellini wrote:
> > On Sun, 15 Aug 2010, Paolo Bonzini wrote:
> >> On 08/13/2010 02:53 PM, Anthony Liguori wrote:
> >>> On 08/12/2010 09:09 AM, stefano.stabellini@eu.citrix.com wrote:
> >>>> From: Anthony PERARD<anthony.perard@citrix.com>
> >>>>
> >>>> Introduce functions to read and write the state of the VM in xenstore.
> >>>
> >>> This basically creates a new management interface for QEMU via the
> >>> xenstore.
> >>>
> >>> Our management interface is QMP. If you want to maintain compatibility,
> >>> you'll need to write a QMP ->  xenstore daemon that maps events
> >>> appropriately.
> >>
> >> This would belong in xl/libxl.
> >
> > Yes, but considering that we don't want a xenstore-based management
> > interface I would gladly do without the compatibility daemon.
> > We'll try to reduce all the xenstore interaction to the bare minimum,
> > and use QMP everywhere else.
> 
> Yes, I was just pointing out that you don't need a new compatibility 
> daemon.  Since xl is already daemonizing itself to handle on_crash and 
> friends, it could also set up all the watches it cares about, and 
> convert them to QMP commands.  It's all more code that needs to be 
> written of course, and boring stuff even. :)

Well yes, but after all you cannot write interesting code all the time
:)

Patch

diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index ec826e7..a6e778a 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -36,10 +36,17 @@ 
 #include "xen_backend.h"
 #include "xenstore.h"
 #include "xen_platform.h"
+#include "qemu-xen.h"
 #include "xen/hvm/hvm_info_table.h"
 
 #define MAX_IDE_BUS 2
 
+static void xen_vm_change_state_handler(void *opaque, int running, int reason)
+{
+    if (running)
+        xen_main_loop_prepare();
+}
+
 static void xen_init_fv(ram_addr_t ram_size,
                         const char *boot_device,
                         const char *kernel_filename,
@@ -150,6 +157,8 @@  static void xen_init_fv(ram_addr_t ram_size,
     }
 
     pc_pci_device_init(pci_bus);
+
+    qemu_add_vm_change_state_handler(xen_vm_change_state_handler, NULL);
 }
 
 static QEMUMachine xenfv_machine = {
diff --git a/target-xen/helper.c b/target-xen/helper.c
index d588e64..8cb7771 100644
--- a/target-xen/helper.c
+++ b/target-xen/helper.c
@@ -19,6 +19,8 @@ 
  */
 
 #include "cpu.h"
+#include "qemu-xen.h"
+#include "xenstore.h"
 
 CPUXenState *cpu_xen_init(const char *cpu_model)
 {
@@ -67,3 +69,8 @@  target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
 {
     return addr;
 }
+
+void xen_main_loop_prepare(void)
+{
+    xenstore_record_dm_state("running");
+}
diff --git a/target-xen/qemu-xen.h b/target-xen/qemu-xen.h
index d1910d6..091ae07 100644
--- a/target-xen/qemu-xen.h
+++ b/target-xen/qemu-xen.h
@@ -27,4 +27,7 @@  int cpu_register_io_memory_fixed(int io_index,
                            CPUWriteMemoryFunc * const *mem_write,
                            void *opaque);
 
+/* target-xen/helper.c */
+void xen_main_loop_prepare(void);
+
 #endif /*QEMU_XEN_H*/
diff --git a/target-xen/xenstore.c b/target-xen/xenstore.c
index 9f2e1ea..6eb6a30 100644
--- a/target-xen/xenstore.c
+++ b/target-xen/xenstore.c
@@ -13,6 +13,60 @@  static void xenstore_process_event(void *opaque)
     free(vec);
 }
 
+static const char *xenstore_get_guest_uuid(void)
+{
+    static char *already_computed = NULL;
+
+    char *domain_path = NULL, *vm_path = NULL, *vm_value = NULL, *p = NULL;
+    unsigned int len;
+
+    if (already_computed)
+        return already_computed;
+
+    if (xen_xc == NULL)
+        return NULL;
+
+    domain_path = xs_get_domain_path(xenstore, xen_domid);
+    if (domain_path == NULL) {
+        fprintf(stderr, "xs_get_domain_path() error. domid %d.\n", xen_domid);
+        goto out;
+    }
+
+    if (asprintf(&vm_path, "%s/vm", domain_path) == -1) {
+        fprintf(stderr, "xenstore_get_guest_uuid(): out of memory.\n");
+        goto out;
+    }
+    vm_value = xs_read(xenstore, XBT_NULL, vm_path, &len);
+    if (vm_value == NULL) {
+        fprintf(stderr, "xs_read(): uuid get error. %s.\n", vm_path);
+        goto out;
+    }
+
+    if (strtok(vm_value, "/") == NULL) {
+        fprintf(stderr, "failed to parse guest uuid\n");
+        goto out;
+    }
+    p = strtok(NULL, "/");
+    if (p == NULL) {
+        fprintf(stderr, "failed to parse guest uuid\n");
+        goto out;
+    }
+
+    if (asprintf(&already_computed, "%s", p) == -1) {
+        fprintf(stderr, "xenstore_get_guest_uuid(): out of memory.\n");
+        goto out;
+    }
+
+    fprintf(stderr, "Guest uuid = %s\n", already_computed);
+
+out:
+    free(domain_path);
+    free(vm_path);
+    free(vm_value);
+
+    return already_computed;
+}
+
 int xen_dm_init(void)
 {
     xenstore = xs_daemon_open();
@@ -29,6 +83,7 @@  int xen_dm_init(void)
         xen_be_printf(NULL, 0, "can't open xen interface\n");
         goto err;
     }
+
     return 0;
 
 err:
@@ -38,3 +93,76 @@  err:
 
     return -1;
 }
+
+static char *xenstore_vm_key_path(int domid, const char *key) {
+    const char *uuid;
+    char *buf = NULL;
+
+    if (xenstore == NULL)
+        return NULL;
+
+    uuid = xenstore_get_guest_uuid();
+    if (!uuid)
+        return NULL;
+
+    if (asprintf(&buf, "/vm/%s/%s", uuid, key) == -1)
+        return NULL;
+
+    return buf;
+}
+
+char *xenstore_vm_read(int domid, const char *key, unsigned int *len)
+{
+    char *path = NULL, *value = NULL;
+
+    path = xenstore_vm_key_path(domid, key);
+    if (!path)
+        return NULL;
+
+    value = xs_read(xenstore, XBT_NULL, path, len);
+    if (value == NULL) {
+        fprintf(stderr, "xs_read(%s): read error\n", path);
+    }
+
+    free(path);
+    return value;
+}
+
+int xenstore_vm_write(int domid, const char *key, const char *value)
+{
+    char *path = NULL;
+    int rc = -1;
+
+    path = xenstore_vm_key_path(domid, key);
+    if (!path)
+        return 0;
+
+    rc = xs_write(xenstore, XBT_NULL, path, value, strlen(value));
+    if (rc == 0) {
+        fprintf(stderr, "xs_write(%s, %s): write error\n", path, key);
+    }
+
+    free(path);
+    return rc;
+}
+
+void xenstore_record_dm(const char *subpath, const char *state)
+{
+    char *path = NULL;
+
+    if (asprintf(&path,
+                 "/local/domain/0/device-model/%u/%s", xen_domid, subpath) == -1) {
+        fprintf(stderr, "out of memory recording dm\n");
+        goto out;
+    }
+    if (!xs_write(xenstore, XBT_NULL, path, state, strlen(state)))
+        fprintf(stderr, "error recording dm\n");
+
+out:
+    free(path);
+}
+
+void xenstore_record_dm_state(const char *state)
+{
+    xenstore_record_dm("state", state);
+}
diff --git a/target-xen/xenstore.h b/target-xen/xenstore.h
index 90baf79..c8144ea 100644
--- a/target-xen/xenstore.h
+++ b/target-xen/xenstore.h
@@ -3,4 +3,10 @@ 
 
 int xen_dm_init(void);
 
+char *xenstore_vm_read(int domid, const char *key, unsigned int *len);
+int xenstore_vm_write(int domid, const char *key, const char *value);
+
+void xenstore_record_dm(const char *subpath, const char *state);
+void xenstore_record_dm_state(const char *state);
+
 #endif /* !XENSTORE_H_ */