xs_internal.c 37.5 KB
Newer Older
1 2 3
/*
 * xs_internal.c: access to Xen Store
 *
4
 * Copyright (C) 2006, 2009-2012 Red Hat, Inc.
5 6 7 8 9 10
 *
 * See COPYING.LIB for the License of this software
 *
 * Daniel Veillard <veillard@redhat.com>
 */

11
#include <config.h>
J
Jim Meyering 已提交
12

13 14 15 16 17 18 19 20 21 22
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

#include <stdint.h>

23
#include <xen/dom0_ops.h>
24 25 26 27
#include <xen/version.h>

#include <xs.h>

28
#include "virterror_internal.h"
29
#include "datatypes.h"
30
#include "driver.h"
31 32 33
#include "memory.h"
#include "logging.h"
#include "uuid.h"
34
#include "xen_driver.h"
35
#include "xs_internal.h"
36
#include "xen_hypervisor.h"
37

38 39
#define VIR_FROM_THIS VIR_FROM_XEN

40
static char *xenStoreDomainGetOSType(virDomainPtr domain);
D
Daniel P. Berrange 已提交
41 42
static void xenStoreWatchEvent(int watch, int fd, int events, void *data);
static void xenStoreWatchListFree(xenStoreWatchListPtr list);
43

44
struct xenUnifiedDriver xenStoreDriver = {
E
Eric Blake 已提交
45 46 47 48 49 50 51
    .xenClose = xenStoreClose,
    .xenDomainShutdown = xenStoreDomainShutdown,
    .xenDomainReboot = xenStoreDomainReboot,
    .xenDomainGetOSType = xenStoreDomainGetOSType,
    .xenDomainGetMaxMemory = xenStoreDomainGetMaxMemory,
    .xenDomainSetMemory = xenStoreDomainSetMemory,
    .xenDomainGetInfo = xenStoreGetDomainInfo,
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
};

/************************************************************************
 *									*
 *		Helper internal APIs					*
 *									*
 ************************************************************************/
/**
 * virConnectDoStoreList:
 * @conn: pointer to the hypervisor connection
 * @path: the absolute path of the directory in the store to list
 * @nb: OUT pointer to the number of items found
 *
 * Internal API querying the Xenstore for a list
 *
 * Returns a string which must be freed by the caller or NULL in case of error
 */
static char **
virConnectDoStoreList(virConnectPtr conn, const char *path,
                      unsigned int *nb)
{
73 74 75 76 77 78 79
    xenUnifiedPrivatePtr priv;

    if (conn == NULL)
        return NULL;

    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL || path == NULL || nb == NULL)
80
        return NULL;
81

82
    return xs_directory (priv->xshandle, 0, path, nb);
83 84 85 86
}

/**
 * virDomainDoStoreQuery:
87 88
 * @conn: pointer to the hypervisor connection
 * @domid: id of the domain
89 90 91 92 93 94 95
 * @path: the relative path of the data in the store to retrieve
 *
 * Internal API querying the Xenstore for a string value.
 *
 * Returns a string which must be freed by the caller or NULL in case of error
 */
static char *
96
virDomainDoStoreQuery(virConnectPtr conn, int domid, const char *path)
97 98 99
{
    char s[256];
    unsigned int len = 0;
100 101 102 103
    xenUnifiedPrivatePtr priv;

    if (!conn)
        return NULL;
104

105 106
    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL)
107
        return NULL;
108

109
    snprintf(s, 255, "/local/domain/%d/%s", domid, path);
110 111
    s[255] = 0;

112
    return xs_read(priv->xshandle, 0, &s[0], &len);
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
}

/**
 * virDomainDoStoreWrite:
 * @domain: a domain object
 * @path: the relative path of the data in the store to retrieve
 *
 * Internal API setting up a string value in the Xenstore
 * Requires write access to the XenStore
 *
 * Returns 0 in case of success, -1 in case of failure
 */
static int
virDomainDoStoreWrite(virDomainPtr domain, const char *path,
                      const char *value)
{
    char s[256];
130
    xenUnifiedPrivatePtr priv;
131 132 133
    int ret = -1;

    if (!VIR_IS_CONNECTED_DOMAIN(domain))
134
        return -1;
135 136 137

    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
    if (priv->xshandle == NULL)
138
        return -1;
139
    if (domain->conn->flags & VIR_CONNECT_RO)
140
        return -1;
141

142
    snprintf(s, 255, "/local/domain/%d/%s", domain->id, path);
143 144
    s[255] = 0;

145
    if (xs_write(priv->xshandle, 0, &s[0], value, strlen(value)))
146 147
        ret = 0;

148
    return ret;
149 150 151 152 153 154 155 156 157 158
}

/**
 * virDomainGetVM:
 * @domain: a domain object
 *
 * Internal API extracting a xenstore vm path.
 *
 * Returns the new string or NULL in case of error
 */
159
static char *
160 161 162 163 164
virDomainGetVM(virDomainPtr domain)
{
    char *vm;
    char query[200];
    unsigned int len;
165
    xenUnifiedPrivatePtr priv;
166 167

    if (!VIR_IS_CONNECTED_DOMAIN(domain))
168
        return NULL;
169 170 171

    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
    if (priv->xshandle == NULL)
172
        return NULL;
173 174 175 176

    snprintf(query, 199, "/local/domain/%d/vm", virDomainGetID(domain));
    query[199] = 0;

177
    vm = xs_read(priv->xshandle, 0, &query[0], &len);
178

179
    return vm;
180 181 182 183 184 185 186 187
}

/**
 * virDomainGetVMInfo:
 * @domain: a domain object
 * @vm: the xenstore vm path
 * @name: the value's path
 *
188
 * Internal API extracting one information the device used
189 190 191 192
 * by the domain from xensttore
 *
 * Returns the new string or NULL in case of error
 */
193
static char *
194 195 196 197 198
virDomainGetVMInfo(virDomainPtr domain, const char *vm, const char *name)
{
    char s[256];
    char *ret = NULL;
    unsigned int len = 0;
199
    xenUnifiedPrivatePtr priv;
200 201

    if (!VIR_IS_CONNECTED_DOMAIN(domain))
202
        return NULL;
203 204 205

    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
    if (priv->xshandle == NULL)
206
        return NULL;
207 208 209 210

    snprintf(s, 255, "%s/%s", vm, name);
    s[255] = 0;

211
    ret = xs_read(priv->xshandle, 0, &s[0], &len);
212

213
    return ret;
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
}


/************************************************************************
 *									*
 *		Canonical internal APIs					*
 *									*
 ************************************************************************/
/**
 * xenStoreOpen:
 * @conn: pointer to the connection block
 * @name: URL for the target, NULL for local
 * @flags: combination of virDrvOpenFlag(s)
 *
 * Connects to the Xen hypervisor.
 *
 * Returns 0 or -1 in case of error.
 */
232
virDrvOpenStatus
233
xenStoreOpen(virConnectPtr conn,
234
             virConnectAuthPtr auth ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
235
             unsigned int flags)
236
{
237
    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
238

E
Eric Blake 已提交
239 240
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

241
    if (flags & VIR_CONNECT_RO)
242
        priv->xshandle = xs_daemon_open_readonly();
243
    else
244
        priv->xshandle = xs_daemon_open();
245

246
    if (priv->xshandle == NULL) {
247
        /*
J
John Levon 已提交
248 249
         * not being able to connect via the socket as an unprivileged
         * user is rather normal, this should fallback to the proxy (or
250
         * remote) mechanism.
251
         */
J
John Levon 已提交
252
        if (xenHavePrivilege()) {
253 254
            virReportError(VIR_ERR_NO_XEN,
                           "%s", _("failed to connect to Xen Store"));
255
        }
256
        return -1;
257
    }
258 259

    /* Init activeDomainList */
260
    if (VIR_ALLOC(priv->activeDomainList) < 0) {
261
        virReportOOMError();
262 263 264 265 266 267
        return -1;
    }

    /* Init watch list before filling in domInfoList,
       so we can know if it is the first time through
       when the callback fires */
268
    if (VIR_ALLOC(priv->xsWatchList) < 0) {
269
        virReportOOMError();
270 271 272 273 274 275 276
        return -1;
    }

    /* This will get called once at start */
    if ( xenStoreAddWatch(conn, "@releaseDomain",
                     "releaseDomain", xenStoreDomainReleased, priv) < 0 )
    {
277 278
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("adding watch @releaseDomain"));
279 280 281 282 283 284 285
        return -1;
    }

    /* The initial call of this will fill domInfoList */
    if( xenStoreAddWatch(conn, "@introduceDomain",
                     "introduceDomain", xenStoreDomainIntroduced, priv) < 0 )
    {
286 287
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("adding watch @introduceDomain"));
288 289 290 291 292 293 294 295 296
        return -1;
    }

    /* Add an event handle */
    if ((priv->xsWatch = virEventAddHandle(xs_fileno(priv->xshandle),
                                           VIR_EVENT_HANDLE_READABLE,
                                           xenStoreWatchEvent,
                                           conn,
                                           NULL)) < 0)
297
        VIR_DEBUG("Failed to add event handle, disabling events");
298 299

    return 0;
300 301 302 303 304 305 306 307 308 309 310 311 312
}

/**
 * xenStoreClose:
 * @conn: pointer to the connection block
 *
 * Close the connection to the Xen hypervisor.
 *
 * Returns 0 in case of success or -1 in case of error.
 */
int
xenStoreClose(virConnectPtr conn)
{
313 314
    xenUnifiedPrivatePtr priv;

315
    if (conn == NULL) {
316
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
317
        return -1;
318 319
    }

320
    priv = (xenUnifiedPrivatePtr) conn->privateData;
321 322

    if (xenStoreRemoveWatch(conn, "@introduceDomain", "introduceDomain") < 0) {
323
        VIR_DEBUG("Warning, could not remove @introduceDomain watch");
324 325 326 327
        /* not fatal */
    }

    if (xenStoreRemoveWatch(conn, "@releaseDomain", "releaseDomain") < 0) {
328
        VIR_DEBUG("Warning, could not remove @releaseDomain watch");
329 330 331 332
        /* not fatal */
    }

    xenStoreWatchListFree(priv->xsWatchList);
J
John Levon 已提交
333
    priv->xsWatchList = NULL;
334 335
    xenUnifiedDomainInfoListFree(priv->activeDomainList);
    priv->activeDomainList = NULL;
336

337
    if (priv->xshandle == NULL)
338
        return -1;
339

340 341
    if (priv->xsWatch != -1)
        virEventRemoveHandle(priv->xsWatch);
342

343
    xs_daemon_close(priv->xshandle);
344 345
    priv->xshandle = NULL;

346
    return 0;
347 348 349 350 351
}

/**
 * xenStoreGetDomainInfo:
 * @domain: pointer to the domain block
352
 * @info: the place where information should be stored
353
 *
E
Eric Blake 已提交
354
 * Do a hypervisor call to get the related set of domain information.
355 356 357 358 359 360 361 362 363
 *
 * Returns 0 in case of success, -1 in case of error.
 */
int
xenStoreGetDomainInfo(virDomainPtr domain, virDomainInfoPtr info)
{
    char *tmp, **tmp2;
    unsigned int nb_vcpus;
    char request[200];
364
    xenUnifiedPrivatePtr priv;
365

366
    if (!VIR_IS_CONNECTED_DOMAIN(domain))
367
        return -1;
368

369
    if ((domain == NULL) || (domain->conn == NULL) || (info == NULL)) {
370
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
371
        return -1;
372
    }
373 374 375

    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
    if (priv->xshandle == NULL)
376
        return -1;
377

378
    if (domain->id == -1)
379
        return -1;
380

381
    tmp = virDomainDoStoreQuery(domain->conn, domain->id, "running");
382 383 384
    if (tmp != NULL) {
        if (tmp[0] == '1')
            info->state = VIR_DOMAIN_RUNNING;
385
        VIR_FREE(tmp);
386
    } else {
387
        info->state = VIR_DOMAIN_NOSTATE;
388
    }
389
    tmp = virDomainDoStoreQuery(domain->conn, domain->id, "memory/target");
390 391 392
    if (tmp != NULL) {
        info->memory = atol(tmp);
        info->maxMem = atol(tmp);
393
        VIR_FREE(tmp);
394 395 396 397
    } else {
        info->memory = 0;
        info->maxMem = 0;
    }
398
#if 0
399
    /* doesn't seems to work */
400
    tmp = virDomainDoStoreQuery(domain->conn, domain->id, "cpu_time");
401 402
    if (tmp != NULL) {
        info->cpuTime = atol(tmp);
403
        VIR_FREE(tmp);
404 405 406
    } else {
        info->cpuTime = 0;
    }
407
#endif
408
    snprintf(request, 199, "/local/domain/%d/cpu", domain->id);
409 410 411 412
    request[199] = 0;
    tmp2 = virConnectDoStoreList(domain->conn, request, &nb_vcpus);
    if (tmp2 != NULL) {
        info->nrVirtCpu = nb_vcpus;
413
        VIR_FREE(tmp2);
414
    }
415
    return 0;
416 417
}

418 419 420 421 422 423 424 425 426 427 428 429 430
/**
 * xenStoreDomainGetState:
 * @domain: pointer to the domain block
 * @state: returned domain's state
 * @reason: returned state reason
 * @flags: additional flags, 0 for now
 *
 * Returns 0 in case of success, -1 in case of error.
 */
int
xenStoreDomainGetState(virDomainPtr domain,
                       int *state,
                       int *reason,
E
Eric Blake 已提交
431
                       unsigned int flags)
432 433 434
{
    char *running;

E
Eric Blake 已提交
435 436
    virCheckFlags(0, -1);

437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
    if (domain->id == -1)
        return -1;

    running = virDomainDoStoreQuery(domain->conn, domain->id, "running");

    if (running && *running == '1')
        *state = VIR_DOMAIN_RUNNING;
    else
        *state = VIR_DOMAIN_NOSTATE;
    if (reason)
        *reason = 0;

    VIR_FREE(running);

    return 0;
}

454
/**
455
 * xenStoreDomainSetMemory:
456 457 458 459 460 461 462 463
 * @domain: pointer to the domain block
 * @memory: the max memory size in kilobytes.
 *
 * Change the maximum amount of memory allowed in the xen store
 *
 * Returns 0 in case of success, -1 in case of error.
 */
int
464
xenStoreDomainSetMemory(virDomainPtr domain, unsigned long memory)
465 466 467 468
{
    int ret;
    char value[20];

D
Daniel Veillard 已提交
469 470
    if ((domain == NULL) || (domain->conn == NULL) ||
        (memory < 1024 * MIN_XEN_GUEST_SIZE)) {
471
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
472
        return -1;
473
    }
474
    if (domain->id == -1)
475
        return -1;
D
Daniel Veillard 已提交
476
    if ((domain->id == 0) && (memory < (2 * MIN_XEN_GUEST_SIZE * 1024)))
477
        return -1;
478 479 480 481
    snprintf(value, 19, "%lu", memory);
    value[19] = 0;
    ret = virDomainDoStoreWrite(domain, "memory/target", &value[0]);
    if (ret < 0)
482 483
        return -1;
    return 0;
484 485 486 487 488 489 490 491 492 493
}

/**
 * xenStoreDomainGetMaxMemory:
 * @domain: pointer to the domain block
 *
 * Ask the xenstore for the maximum memory allowed for a domain
 *
 * Returns the memory size in kilobytes or 0 in case of error.
 */
494
unsigned long long
495 496 497
xenStoreDomainGetMaxMemory(virDomainPtr domain)
{
    char *tmp;
498
    unsigned long long ret = 0;
D
Daniel P. Berrange 已提交
499
    xenUnifiedPrivatePtr priv;
500

501
    if (!VIR_IS_CONNECTED_DOMAIN(domain))
502
        return ret;
503
    if (domain->id == -1)
504
        return 0;
505

D
Daniel P. Berrange 已提交
506 507
    priv = domain->conn->privateData;
    xenUnifiedLock(priv);
508
    tmp = virDomainDoStoreQuery(domain->conn, domain->id, "memory/target");
509
    if (tmp != NULL) {
510
        ret = atol(tmp);
D
Daniel P. Berrange 已提交
511
        VIR_FREE(tmp);
512
    }
D
Daniel P. Berrange 已提交
513
    xenUnifiedUnlock(priv);
514
    return ret;
515 516 517 518 519 520 521 522 523 524 525 526 527 528
}

/**
 * xenStoreNumOfDomains:
 * @conn: pointer to the hypervisor connection
 *
 * Provides the number of active domains.
 *
 * Returns the number of domain found or -1 in case of error
 */
int
xenStoreNumOfDomains(virConnectPtr conn)
{
    unsigned int num;
529 530 531
    char **idlist = NULL, *endptr;
    int i, ret = -1, realnum = 0;
    long id;
532
    xenUnifiedPrivatePtr priv;
533

534
    if (conn == NULL) {
535
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
536
        return -1;
537
    }
538 539 540

    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL) {
541
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
542
        return -1;
543
    }
544

545
    idlist = xs_directory(priv->xshandle, 0, "/local/domain", &num);
546
    if (idlist) {
547 548 549 550 551 552 553 554 555 556 557 558 559
        for (i = 0; i < num; i++) {
            id = strtol(idlist[i], &endptr, 10);
            if ((endptr == idlist[i]) || (*endptr != 0))
                goto out;

            /* Sometimes xenstore has stale domain IDs, so filter
               against the hypervisor's info */
            if (xenHypervisorHasDomain(conn, (int)id))
                realnum++;
        }
out:
        VIR_FREE (idlist);
        ret = realnum;
560
    }
561
    return ret;
562 563 564
}

/**
565
 * xenStoreDoListDomains:
566 567 568 569
 * @conn: pointer to the hypervisor connection
 * @ids: array to collect the list of IDs of active domains
 * @maxids: size of @ids
 *
570 571
 * Internal API: collect the list of active domains, and store
 * their ID in @maxids. The driver lock must be held.
572 573 574
 *
 * Returns the number of domain found or -1 in case of error
 */
575
static int
576
xenStoreDoListDomains(virConnectPtr conn, xenUnifiedPrivatePtr priv, int *ids, int maxids)
577 578 579
{
    char **idlist = NULL, *endptr;
    unsigned int num, i;
580
    int ret = -1;
581
    long id;
D
Daniel P. Berrange 已提交
582

583
    if (priv->xshandle == NULL)
584
        goto out;
585

586
    idlist = xs_directory (priv->xshandle, 0, "/local/domain", &num);
587
    if (idlist == NULL)
588
        goto out;
589 590

    for (ret = 0, i = 0; (i < num) && (ret < maxids); i++) {
591
        id = strtol(idlist[i], &endptr, 10);
592 593
        if ((endptr == idlist[i]) || (*endptr != 0))
            goto out;
594 595 596 597 598

        /* Sometimes xenstore has stale domain IDs, so filter
           against the hypervisor's info */
        if (xenHypervisorHasDomain(conn, (int)id))
            ids[ret++] = (int) id;
599
    }
600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622

out:
    VIR_FREE (idlist);
    return ret;
}

/**
 * xenStoreListDomains:
 * @conn: pointer to the hypervisor connection
 * @ids: array to collect the list of IDs of active domains
 * @maxids: size of @ids
 *
 * Collect the list of active domains, and store their ID in @maxids
 *
 * Returns the number of domain found or -1 in case of error
 */
int
xenStoreListDomains(virConnectPtr conn, int *ids, int maxids)
{
    xenUnifiedPrivatePtr priv;
    int ret;

    if ((conn == NULL) || (ids == NULL)) {
623
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
624
        return -1;
625 626 627 628 629
    }

    priv = (xenUnifiedPrivatePtr) conn->privateData;

    xenUnifiedLock(priv);
630
    ret = xenStoreDoListDomains(conn, priv, ids, maxids);
D
Daniel P. Berrange 已提交
631
    xenUnifiedUnlock(priv);
632

633
    return ret;
634 635 636
}

/**
637
 * xenStoreLookupByName:
638 639 640 641 642 643 644 645
 * @conn: A xend instance
 * @name: The name of the domain
 *
 * Try to lookup a domain on the Xen Store based on its name.
 *
 * Returns a new domain object or NULL in case of failure
 */
virDomainPtr
646
xenStoreLookupByName(virConnectPtr conn, const char *name)
647 648 649 650 651
{
    virDomainPtr ret = NULL;
    unsigned int num, i, len;
    long id = -1;
    char **idlist = NULL, *endptr;
652
    char prop[200], *tmp;
653 654
    int found = 0;
    struct xend_domain *xenddomain = NULL;
655
    xenUnifiedPrivatePtr priv;
656 657

    if ((conn == NULL) || (name == NULL)) {
658
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
659
        return NULL;
660
    }
661 662 663

    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL)
664
        return NULL;
665

666
    idlist = xs_directory(priv->xshandle, 0, "/local/domain", &num);
667
    if (idlist == NULL)
668
        goto done;
669 670

    for (i = 0; i < num; i++) {
671 672 673 674
        id = strtol(idlist[i], &endptr, 10);
        if ((endptr == idlist[i]) || (*endptr != 0)) {
            goto done;
        }
675
#if 0
676 677
        if (virConnectCheckStoreID(conn, (int) id) < 0)
            continue;
678
#endif
679 680 681 682 683
        snprintf(prop, 199, "/local/domain/%s/name", idlist[i]);
        prop[199] = 0;
        tmp = xs_read(priv->xshandle, 0, prop, &len);
        if (tmp != NULL) {
            found = STREQ (name, tmp);
684
            VIR_FREE(tmp);
685 686 687
            if (found)
                break;
        }
688 689
    }
    if (!found)
690
        goto done;
691

692
    ret = virGetDomain(conn, name, NULL);
693
    if (ret == NULL)
694
        goto done;
695

696
    ret->id = id;
697 698

done:
699 700
    VIR_FREE(xenddomain);
    VIR_FREE(idlist);
701

702
    return ret;
703 704 705 706 707 708 709 710 711 712 713 714 715 716 717
}

/**
 * xenStoreDomainShutdown:
 * @domain: pointer to the Domain block
 *
 * Shutdown the domain, the OS is requested to properly shutdown
 * and the domain may ignore it.  It will return immediately
 * after queuing the request.
 *
 * Returns 0 in case of success, -1 in case of error.
 */
int
xenStoreDomainShutdown(virDomainPtr domain)
{
D
Daniel P. Berrange 已提交
718 719 720
    int ret;
    xenUnifiedPrivatePtr priv;

721
    if ((domain == NULL) || (domain->conn == NULL)) {
722
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
723
        return -1;
724
    }
725
    if (domain->id == -1 || domain->id == 0)
726
        return -1;
727
    /*
728
     * this is very hackish, the domU kernel probes for a special
729 730
     * node in the xenstore and launch the shutdown command if found.
     */
D
Daniel P. Berrange 已提交
731 732 733 734 735
    priv = domain->conn->privateData;
    xenUnifiedLock(priv);
    ret = virDomainDoStoreWrite(domain, "control/shutdown", "poweroff");
    xenUnifiedUnlock(priv);
    return ret;
736 737
}

738 739 740 741 742 743 744 745 746 747 748 749
/**
 * xenStoreDomainReboot:
 * @domain: pointer to the Domain block
 * @flags: extra flags for the reboot operation, not used yet
 *
 * Reboot the domain, the OS is requested to properly shutdown
 * and reboot but the domain may ignore it.  It will return immediately
 * after queuing the request.
 *
 * Returns 0 in case of success, -1 in case of error.
 */
int
E
Eric Blake 已提交
750
xenStoreDomainReboot(virDomainPtr domain, unsigned int flags)
751
{
D
Daniel P. Berrange 已提交
752 753 754
    int ret;
    xenUnifiedPrivatePtr priv;

E
Eric Blake 已提交
755 756
    virCheckFlags(0, -1);

757
    if ((domain == NULL) || (domain->conn == NULL)) {
758
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
759
        return -1;
760
    }
761
    if (domain->id == -1 || domain->id == 0)
762
        return -1;
763
    /*
764
     * this is very hackish, the domU kernel probes for a special
765 766
     * node in the xenstore and launch the shutdown command if found.
     */
D
Daniel P. Berrange 已提交
767 768 769 770 771
    priv = domain->conn->privateData;
    xenUnifiedLock(priv);
    ret = virDomainDoStoreWrite(domain, "control/shutdown", "reboot");
    xenUnifiedUnlock(priv);
    return ret;
772
}
773 774 775 776 777 778 779 780 781 782 783 784 785 786 787

/*
 * xenStoreDomainGetOSType:
 * @domain: a domain object
 *
 * Get the type of domain operation system.
 *
 * Returns the new string or NULL in case of error, the string must be
 *         freed by the caller.
 */
static char *
xenStoreDomainGetOSType(virDomainPtr domain) {
    char *vm, *str = NULL;

    if ((domain == NULL) || (domain->conn == NULL)) {
788
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
789
        return NULL;
790 791 792 793
    }

    vm = virDomainGetVM(domain);
    if (vm) {
D
Daniel P. Berrange 已提交
794 795
        xenUnifiedPrivatePtr priv = domain->conn->privateData;
        xenUnifiedLock(priv);
796
        str = virDomainGetVMInfo(domain, vm, "image/ostype");
D
Daniel P. Berrange 已提交
797 798
        xenUnifiedUnlock(priv);
        VIR_FREE(vm);
799 800
    }

801
    return str;
802
}
803

804 805
/**
 * xenStoreDomainGetVNCPort:
806 807
 * @conn: the hypervisor connection
 * @domid: id of the domain
808 809
 *
 * Return the port number on which the domain is listening for VNC
810
 * connections.
811
 *
D
Daniel P. Berrange 已提交
812 813 814
 * The caller must hold the lock on the privateData
 * associated with the 'conn' parameter.
 *
815 816
 * Returns the port number, -1 in case of error
 */
817
int             xenStoreDomainGetVNCPort(virConnectPtr conn, int domid) {
818 819 820
    char *tmp;
    int ret = -1;

821
    tmp = virDomainDoStoreQuery(conn, domid, "console/vnc-port");
822 823 824 825 826
    if (tmp != NULL) {
        char *end;
        ret = strtol(tmp, &end, 10);
        if (ret == 0 && end == tmp)
            ret = -1;
827
        VIR_FREE(tmp);
828
    }
829
    return ret;
830 831 832 833
}

/**
 * xenStoreDomainGetConsolePath:
834 835
 * @conn: the hypervisor connection
 * @domid: id of the domain
836
 *
837
 * Return the path to the pseudo TTY on which the guest domain's
838 839 840 841 842
 * serial console is attached.
 *
 * Returns the path to the serial console. It is the callers
 * responsibilty to free() the return string. Returns NULL
 * on error
D
Daniel P. Berrange 已提交
843 844 845
 *
 * The caller must hold the lock on the privateData
 * associated with the 'conn' parameter.
846
 */
847 848
char *          xenStoreDomainGetConsolePath(virConnectPtr conn, int domid) {
  return virDomainDoStoreQuery(conn, domid, "console/tty");
849
}
850

851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869
/**
 * xenStoreDomainGetSerailConsolePath:
 * @conn: the hypervisor connection
 * @domid: id of the domain
 *
 * Return the path to the pseudo TTY on which the guest domain's
 * serial console is attached.
 *
 * Returns the path to the serial console. It is the callers
 * responsibilty to free() the return string. Returns NULL
 * on error
 *
 * The caller must hold the lock on the privateData
 * associated with the 'conn' parameter.
 */
char * xenStoreDomainGetSerialConsolePath(virConnectPtr conn, int domid) {
    return virDomainDoStoreQuery(conn, domid, "serial/0/tty");
}

870 871 872 873 874 875 876 877 878 879

/*
 * xenStoreDomainGetNetworkID:
 * @conn: pointer to the connection.
 * @id: the domain id
 * @mac: the mac address
 *
 * Get the reference (i.e. the string number) for the device on that domain
 * which uses the given mac address
 *
D
Daniel P. Berrange 已提交
880 881 882
 * The caller must hold the lock on the privateData
 * associated with the 'conn' parameter.
 *
883 884 885 886 887 888
 * Returns the new string or NULL in case of error, the string must be
 *         freed by the caller.
 */
char *
xenStoreDomainGetNetworkID(virConnectPtr conn, int id, const char *mac) {
    char dir[80], path[128], **list = NULL, *val = NULL;
889
    unsigned int len, i, num;
890
    char *ret = NULL;
891
    xenUnifiedPrivatePtr priv;
892 893

    if (id < 0)
894
        return NULL;
895 896 897

    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL)
898
        return NULL;
899
    if (mac == NULL)
900
        return NULL;
901

902
    snprintf(dir, sizeof(dir), "/local/domain/0/backend/vif/%d", id);
903
    list = xs_directory(priv->xshandle, 0, dir, &num);
904
    if (list == NULL)
905
        return NULL;
906
    for (i = 0; i < num; i++) {
907
        snprintf(path, sizeof(path), "%s/%s/%s", dir, list[i], "mac");
908
        if ((val = xs_read(priv->xshandle, 0, path, &len)) == NULL)
909
            break;
910 911 912 913 914 915

        bool match = (virMacAddrCompare(val, mac) == 0);

        VIR_FREE(val);

        if (match) {
916
            ret = strdup(list[i]);
917 918

            if (ret == NULL)
919
                virReportOOMError();
920

921 922
            break;
        }
923
    }
924 925

    VIR_FREE(list);
926
    return ret;
927
}
928

929 930 931 932 933 934 935 936 937
/*
 * xenStoreDomainGetDiskID:
 * @conn: pointer to the connection.
 * @id: the domain id
 * @dev: the virtual block device name
 *
 * Get the reference (i.e. the string number) for the device on that domain
 * which uses the given virtual block device name
 *
D
Daniel P. Berrange 已提交
938 939 940
 * The caller must hold the lock on the privateData
 * associated with the 'conn' parameter.
 *
941 942 943 944 945 946 947 948 949 950 951
 * Returns the new string or NULL in case of error, the string must be
 *         freed by the caller.
 */
char *
xenStoreDomainGetDiskID(virConnectPtr conn, int id, const char *dev) {
    char dir[80], path[128], **list = NULL, *val = NULL;
    unsigned int devlen, len, i, num;
    char *ret = NULL;
    xenUnifiedPrivatePtr priv;

    if (id < 0)
952
        return NULL;
953 954 955

    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL)
956
        return NULL;
957
    if (dev == NULL)
958
        return NULL;
959 960
    devlen = strlen(dev);
    if (devlen <= 0)
961
        return NULL;
962 963 964

    snprintf(dir, sizeof(dir), "/local/domain/0/backend/vbd/%d", id);
    list = xs_directory(priv->xshandle, 0, dir, &num);
965 966 967 968 969 970 971
    if (list != NULL) {
        for (i = 0; i < num; i++) {
            snprintf(path, sizeof(path), "%s/%s/%s", dir, list[i], "dev");
            val = xs_read(priv->xshandle, 0, path, &len);
            if (val == NULL)
                break;
            if ((devlen != len) || memcmp(val, dev, len)) {
972
                VIR_FREE (val);
973 974
            } else {
                ret = strdup(list[i]);
975 976

                if (ret == NULL)
977
                    virReportOOMError();
978 979 980

                VIR_FREE (val);
                VIR_FREE (list);
981
                return ret;
982
            }
983
        }
984
        VIR_FREE (list);
985
    }
986 987 988 989 990 991 992 993 994
    snprintf(dir, sizeof(dir), "/local/domain/0/backend/tap/%d", id);
    list = xs_directory(priv->xshandle, 0, dir, &num);
    if (list != NULL) {
        for (i = 0; i < num; i++) {
            snprintf(path, sizeof(path), "%s/%s/%s", dir, list[i], "dev");
            val = xs_read(priv->xshandle, 0, path, &len);
            if (val == NULL)
                break;
            if ((devlen != len) || memcmp(val, dev, len)) {
995
                VIR_FREE (val);
996 997
            } else {
                ret = strdup(list[i]);
998 999

                if (ret == NULL)
1000
                    virReportOOMError();
1001 1002 1003

                VIR_FREE (val);
                VIR_FREE (list);
1004
                return ret;
1005 1006
            }
        }
1007
        VIR_FREE (list);
1008
    }
1009
    return NULL;
1010 1011
}

1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035
/*
 * xenStoreDomainGetPCIID:
 * @conn: pointer to the connection.
 * @id: the domain id
 * @bdf: the PCI BDF
 *
 * Get the reference (i.e. the string number) for the device on that domain
 * which uses the given PCI address
 *
 * The caller must hold the lock on the privateData
 * associated with the 'conn' parameter.
 *
 * Returns the new string or NULL in case of error, the string must be
 *         freed by the caller.
 */
char *
xenStoreDomainGetPCIID(virConnectPtr conn, int id, const char *bdf)
{
    char dir[80], path[128], **list = NULL, *val = NULL;
    unsigned int len, i, num;
    char *ret = NULL;
    xenUnifiedPrivatePtr priv;

    if (id < 0)
1036
        return NULL;
1037 1038 1039

    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL)
1040
        return NULL;
1041
    if (bdf == NULL)
1042
        return NULL;
1043 1044 1045 1046

    snprintf(dir, sizeof(dir), "/local/domain/0/backend/pci/%d", id);
    list = xs_directory(priv->xshandle, 0, dir, &num);
    if (list == NULL)
1047
        return NULL;
1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063
    for (i = 0; i < num; i++) {
        snprintf(path, sizeof(path), "%s/%s/%s", dir, list[i], "dev-0");
        if ((val = xs_read(priv->xshandle, 0, path, &len)) == NULL)
            break;

        bool match = STREQ(val, bdf);

        VIR_FREE(val);

        if (match) {
            ret = strdup(list[i]);
            break;
        }
    }

    VIR_FREE(list);
1064
    return ret;
1065 1066
}

D
Daniel P. Berrange 已提交
1067 1068 1069 1070
/*
 * The caller must hold the lock on the privateData
 * associated with the 'conn' parameter.
 */
1071 1072 1073 1074 1075 1076 1077 1078
char *xenStoreDomainGetName(virConnectPtr conn,
                            int id) {
    char prop[200];
    xenUnifiedPrivatePtr priv;
    unsigned int len;

    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL)
1079
        return NULL;
1080 1081 1082 1083 1084 1085

    snprintf(prop, 199, "/local/domain/%d/name", id);
    prop[199] = 0;
    return xs_read(priv->xshandle, 0, prop, &len);
}

D
Daniel P. Berrange 已提交
1086 1087 1088 1089
/*
 * The caller must hold the lock on the privateData
 * associated with the 'conn' parameter.
 */
1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104
int xenStoreDomainGetUUID(virConnectPtr conn,
                          int id,
                          unsigned char *uuid) {
    char prop[200];
    xenUnifiedPrivatePtr priv;
    unsigned int len;
    char *uuidstr;
    int ret = 0;

    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL)
        return -1;

    snprintf(prop, 199, "/local/domain/%d/vm", id);
    prop[199] = 0;
1105 1106
    /* This will return something like
     * /vm/00000000-0000-0000-0000-000000000000 */
1107 1108
    uuidstr = xs_read(priv->xshandle, 0, prop, &len);

1109
    /* remove "/vm/" */
1110 1111 1112 1113 1114 1115 1116
    ret = virUUIDParse(uuidstr + 4, uuid);

    VIR_FREE(uuidstr);

    return ret;
}

D
Daniel P. Berrange 已提交
1117 1118
static void
xenStoreWatchListFree(xenStoreWatchListPtr list)
1119 1120 1121 1122 1123 1124 1125 1126 1127 1128
{
    int i;
    for (i=0; i<list->count; i++) {
        VIR_FREE(list->watches[i]->path);
        VIR_FREE(list->watches[i]->token);
        VIR_FREE(list->watches[i]);
    }
    VIR_FREE(list);
}

D
Daniel P. Berrange 已提交
1129 1130 1131 1132
/*
 * The caller must hold the lock on the privateData
 * associated with the 'conn' parameter.
 */
1133 1134 1135 1136 1137 1138
int xenStoreAddWatch(virConnectPtr conn,
                     const char *path,
                     const char *token,
                     xenStoreWatchCallback cb,
                     void *opaque)
{
1139
    xenStoreWatchPtr watch = NULL;
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154
    int n;
    xenStoreWatchListPtr list;
    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;

    if (priv->xshandle == NULL)
        return -1;

    list = priv->xsWatchList;
    if(!list)
        return -1;

    /* check if we already have this callback on our list */
    for (n=0; n < list->count; n++) {
        if( STREQ(list->watches[n]->path, path) &&
            STREQ(list->watches[n]->token, token)) {
1155 1156
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("watch already tracked"));
1157 1158 1159 1160 1161
            return -1;
        }
    }

    if (VIR_ALLOC(watch) < 0)
1162 1163
        goto no_memory;

1164 1165 1166 1167 1168
    watch->path   = strdup(path);
    watch->token  = strdup(token);
    watch->cb     = cb;
    watch->opaque = opaque;

1169 1170 1171 1172
    if (watch->path == NULL || watch->token == NULL) {
        goto no_memory;
    }

1173 1174 1175
    /* Make space on list */
    n = list->count;
    if (VIR_REALLOC_N(list->watches, n + 1) < 0) {
1176
        goto no_memory;
1177 1178 1179 1180 1181 1182
    }

    list->watches[n] = watch;
    list->count++;

    return xs_watch(priv->xshandle, watch->path, watch->token);
1183 1184 1185 1186 1187 1188 1189 1190

  no_memory:
    if (watch) {
        VIR_FREE(watch->path);
        VIR_FREE(watch->token);
        VIR_FREE(watch);
    }

1191
    virReportOOMError();
1192 1193

    return -1;
1194 1195
}

D
Daniel P. Berrange 已提交
1196 1197 1198 1199
/*
 * The caller must hold the lock on the privateData
 * associated with the 'conn' parameter.
 */
1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220
int xenStoreRemoveWatch(virConnectPtr conn,
                        const char *path,
                        const char *token)
{
    int i;
    xenStoreWatchListPtr list;
    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;

    if (priv->xshandle == NULL)
        return -1;

    list = priv->xsWatchList;
    if(!list)
        return -1;

    for (i = 0 ; i < list->count ; i++) {
        if( STREQ(list->watches[i]->path, path) &&
            STREQ(list->watches[i]->token, token)) {

            if (!xs_unwatch(priv->xshandle,
                       list->watches[i]->path,
1221
                       list->watches[i]->token))
1222
            {
1223
                VIR_DEBUG("WARNING: Could not remove watch");
1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247
                /* Not fatal, continue */
            }

            VIR_FREE(list->watches[i]->path);
            VIR_FREE(list->watches[i]->token);
            VIR_FREE(list->watches[i]);

            if (i < (list->count - 1))
                memmove(list->watches + i,
                        list->watches + i + 1,
                        sizeof(*(list->watches)) *
                                (list->count - (i + 1)));

            if (VIR_REALLOC_N(list->watches,
                              list->count - 1) < 0) {
                ; /* Failure to reduce memory allocation isn't fatal */
            }
            list->count--;
            return 0;
        }
    }
    return -1;
}

D
Daniel P. Berrange 已提交
1248 1249 1250 1251
static xenStoreWatchPtr
xenStoreFindWatch(xenStoreWatchListPtr list,
                  const char *path,
                  const char *token)
1252 1253 1254 1255 1256 1257 1258 1259 1260 1261
{
    int i;
    for (i = 0 ; i < list->count ; i++)
        if( STREQ(path, list->watches[i]->path) &&
            STREQ(token, list->watches[i]->token) )
            return list->watches[i];

    return NULL;
}

D
Daniel P. Berrange 已提交
1262 1263 1264
static void
xenStoreWatchEvent(int watch ATTRIBUTE_UNUSED,
                   int fd ATTRIBUTE_UNUSED,
1265
                   int events,
D
Daniel P. Berrange 已提交
1266
                   void *data)
1267 1268 1269 1270 1271 1272 1273 1274 1275
{
    char		 **event;
    char		 *path;
    char		 *token;
    unsigned int	 stringCount;
    xenStoreWatchPtr     sw;

    virConnectPtr        conn = data;
    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
1276

1277
    if(!priv) return;
D
Daniel P. Berrange 已提交
1278

1279 1280 1281
    /* only set a watch on read and write events */
    if (events & (VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP)) return;

D
Daniel P. Berrange 已提交
1282 1283 1284 1285
    xenUnifiedLock(priv);

    if(!priv->xshandle)
        goto cleanup;
1286 1287 1288

    event = xs_read_watch(priv->xshandle, &stringCount);
    if (!event)
D
Daniel P. Berrange 已提交
1289
        goto cleanup;
1290 1291 1292 1293 1294 1295 1296 1297

    path  = event[XS_WATCH_PATH];
    token = event[XS_WATCH_TOKEN];

    sw = xenStoreFindWatch(priv->xsWatchList, path, token);
    if( sw )
        sw->cb(conn, path, token, sw->opaque);
    VIR_FREE(event);
D
Daniel P. Berrange 已提交
1298 1299 1300

cleanup:
    xenUnifiedUnlock(priv);
1301 1302
}

D
Daniel P. Berrange 已提交
1303 1304 1305 1306 1307 1308

/*
 * The domain callback for the @introduceDomain watch
 *
 * The lock on 'priv' is held when calling this
 */
1309 1310 1311 1312 1313 1314 1315 1316 1317 1318
int xenStoreDomainIntroduced(virConnectPtr conn,
                             const char *path ATTRIBUTE_UNUSED,
                             const char *token ATTRIBUTE_UNUSED,
                             void *opaque)
{
    int i, j, found, missing = 0, retries = 20;
    int new_domain_cnt;
    int *new_domids;
    int nread;

1319
    xenUnifiedPrivatePtr priv = opaque;
1320 1321 1322

retry:
    new_domain_cnt = xenStoreNumOfDomains(conn);
1323 1324 1325
    if (new_domain_cnt < 0)
        return -1;

1326
    if( VIR_ALLOC_N(new_domids,new_domain_cnt) < 0 ) {
1327
        virReportOOMError();
1328 1329
        return -1;
    }
1330
    nread = xenStoreDoListDomains(conn, priv, new_domids, new_domain_cnt);
1331
    if (nread != new_domain_cnt) {
1332
        /* mismatch. retry this read */
1333 1334 1335 1336 1337 1338 1339
        VIR_FREE(new_domids);
        goto retry;
    }

    missing = 0;
    for (i=0 ; i < new_domain_cnt ; i++) {
        found = 0;
1340 1341
        for (j = 0 ; j < priv->activeDomainList->count ; j++) {
            if (priv->activeDomainList->doms[j]->id == new_domids[i]) {
1342 1343 1344 1345 1346 1347
                found = 1;
                break;
            }
        }

        if (!found) {
1348
            virDomainEventPtr event;
1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361
            char *name;
            unsigned char uuid[VIR_UUID_BUFLEN];

            if (!(name = xenStoreDomainGetName(conn, new_domids[i]))) {
                missing = 1;
                continue;
            }
            if (xenStoreDomainGetUUID(conn, new_domids[i], uuid) < 0) {
                missing = 1;
                VIR_FREE(name);
                continue;
            }

1362 1363 1364 1365 1366
            event = virDomainEventNew(new_domids[i], name, uuid,
                                      VIR_DOMAIN_EVENT_STARTED,
                                      VIR_DOMAIN_EVENT_STARTED_BOOTED);
            if (event)
                xenUnifiedDomainEventDispatch(priv, event);
1367

1368
            /* Add to the list */
1369
            xenUnifiedAddDomainInfo(priv->activeDomainList,
1370
                                    new_domids[i], name, uuid);
1371 1372 1373 1374 1375 1376 1377

            VIR_FREE(name);
        }
    }
    VIR_FREE(new_domids);

    if (missing && retries--) {
1378
        VIR_DEBUG("Some domains were missing, trying again");
1379 1380 1381 1382 1383 1384
        usleep(100 * 1000);
        goto retry;
    }
    return 0;
}

D
Daniel P. Berrange 已提交
1385 1386 1387 1388 1389
/*
 * The domain callback for the @destroyDomain watch
 *
 * The lock on 'priv' is held when calling this
 */
1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401
int xenStoreDomainReleased(virConnectPtr conn,
                            const char *path  ATTRIBUTE_UNUSED,
                            const char *token ATTRIBUTE_UNUSED,
                            void *opaque)
{
    int i, j, found, removed, retries = 20;
    int new_domain_cnt;
    int *new_domids;
    int nread;

    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) opaque;

1402
    if(!priv->activeDomainList->count) return 0;
1403 1404 1405

retry:
    new_domain_cnt = xenStoreNumOfDomains(conn);
1406 1407
    if (new_domain_cnt < 0)
        return -1;
1408 1409

    if( VIR_ALLOC_N(new_domids,new_domain_cnt) < 0 ) {
1410
        virReportOOMError();
1411 1412
        return -1;
    }
1413
    nread = xenStoreDoListDomains(conn, priv, new_domids, new_domain_cnt);
1414
    if (nread != new_domain_cnt) {
1415
        /* mismatch. retry this read */
1416 1417 1418 1419 1420
        VIR_FREE(new_domids);
        goto retry;
    }

    removed = 0;
1421
    for (j=0 ; j < priv->activeDomainList->count ; j++) {
1422 1423
        found = 0;
        for (i=0 ; i < new_domain_cnt ; i++) {
1424
            if (priv->activeDomainList->doms[j]->id == new_domids[i]) {
1425 1426 1427 1428 1429 1430
                found = 1;
                break;
            }
        }

        if (!found) {
1431 1432
            virDomainEventPtr event =
                virDomainEventNew(-1,
1433 1434
                                  priv->activeDomainList->doms[j]->name,
                                  priv->activeDomainList->doms[j]->uuid,
1435 1436 1437 1438 1439 1440
                                  VIR_DOMAIN_EVENT_STOPPED,
                                  VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
            if (event)
                xenUnifiedDomainEventDispatch(priv, event);

            /* Remove from the list */
1441 1442 1443 1444
            xenUnifiedRemoveDomainInfo(priv->activeDomainList,
                                       priv->activeDomainList->doms[j]->id,
                                       priv->activeDomainList->doms[j]->name,
                                       priv->activeDomainList->doms[j]->uuid);
1445 1446

            removed = 1;
1447 1448 1449 1450 1451 1452
        }
    }

    VIR_FREE(new_domids);

    if (!removed && retries--) {
1453
        VIR_DEBUG("No domains removed, retrying");
1454 1455 1456 1457 1458
        usleep(100 * 1000);
        goto retry;
    }
    return 0;
}