xm_internal.c 44.8 KB
Newer Older
1 2 3
/*
 * xm_internal.h: helper routines for dealing with inactive domains
 *
4
 * Copyright (C) 2006-2007, 2009-2011 Red Hat, Inc.
5
 * Copyright (C) 2006 Daniel P. Berrange
6
 *
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
22 23 24
 *
 */

25
#include <config.h>
26

27 28 29
#include <dirent.h>
#include <time.h>
#include <sys/stat.h>
30
#include <limits.h>
31 32
#include <string.h>
#include <errno.h>
33 34 35 36 37

#include <unistd.h>
#include <stdint.h>
#include <xen/dom0_ops.h>

38
#include "virterror_internal.h"
39
#include "datatypes.h"
40
#include "xm_internal.h"
41
#include "xen_driver.h"
42
#include "xend_internal.h"
43
#include "xen_sxpr.h"
44
#include "xen_xm.h"
45
#include "hash.h"
46
#include "buf.h"
47
#include "uuid.h"
48
#include "util.h"
49
#include "memory.h"
50
#include "logging.h"
51
#include "count-one-bits.h"
52

53
#define VIR_FROM_THIS VIR_FROM_XENXM
54

55
#ifdef WITH_RHEL5_API
56 57
# define XEND_CONFIG_MAX_VERS_NET_TYPE_IOEMU 0
# define XEND_CONFIG_MIN_VERS_PVFB_NEWCONF 2
58
#else
59 60
# define XEND_CONFIG_MAX_VERS_NET_TYPE_IOEMU 3
# define XEND_CONFIG_MIN_VERS_PVFB_NEWCONF 3
61 62
#endif

63 64 65 66 67
/* The true Xen limit varies but so far is always way
   less than 1024, which is the Linux kernel limit according
   to sched.h, so we'll match that for now */
#define XEN_MAX_PHYSICAL_CPU 1024

68
char * xenXMAutoAssignMac(void);
69 70 71 72
static int xenXMDomainAttachDeviceFlags(virDomainPtr domain, const char *xml,
                                        unsigned int flags);
static int xenXMDomainDetachDeviceFlags(virDomainPtr domain, const char *xml,
                                        unsigned int flags);
73

74 75 76 77 78 79 80
#define XM_REFRESH_INTERVAL 10

#define XM_CONFIG_DIR "/etc/xen"
#define XM_EXAMPLE_PREFIX "xmexample"
#define XEND_CONFIG_FILE "xend-config.sxp"
#define XEND_PCI_CONFIG_PREFIX "xend-pci-"
#define QEMU_IF_SCRIPT "qemu-ifup"
81
#define XM_XML_ERROR "Invalid xml"
82

83
struct xenUnifiedDriver xenXMDriver = {
84 85 86
    xenXMOpen, /* open */
    xenXMClose, /* close */
    NULL, /* version */
87
    NULL, /* hostname */
88
    NULL, /* nodeGetInfo */
89
    NULL, /* getCapabilities */
90 91
    NULL, /* listDomains */
    NULL, /* numOfDomains */
92
    NULL, /* domainCreateXML */
93 94 95 96 97 98 99 100 101 102 103 104
    NULL, /* domainSuspend */
    NULL, /* domainResume */
    NULL, /* domainShutdown */
    NULL, /* domainReboot */
    NULL, /* domainDestroy */
    NULL, /* domainGetOSType */
    xenXMDomainGetMaxMemory, /* domainGetMaxMemory */
    xenXMDomainSetMaxMemory, /* domainSetMaxMemory */
    xenXMDomainSetMemory, /* domainMaxMemory */
    xenXMDomainGetInfo, /* domainGetInfo */
    NULL, /* domainSave */
    NULL, /* domainRestore */
D
Daniel Veillard 已提交
105
    NULL, /* domainCoreDump */
106
    xenXMDomainPinVcpu, /* domainPinVcpu */
107 108 109 110 111 112
    NULL, /* domainGetVcpus */
    xenXMListDefinedDomains, /* listDefinedDomains */
    xenXMNumOfDefinedDomains, /* numOfDefinedDomains */
    xenXMDomainCreate, /* domainCreate */
    xenXMDomainDefineXML, /* domainDefineXML */
    xenXMDomainUndefine, /* domainUndefine */
113 114
    xenXMDomainAttachDeviceFlags, /* domainAttachDeviceFlags */
    xenXMDomainDetachDeviceFlags, /* domainDetachDeviceFlags */
115
    NULL, /* domainUpdateDeviceFlags */
116 117
    NULL, /* domainGetAutostart */
    NULL, /* domainSetAutostart */
118 119 120
    NULL, /* domainGetSchedulerType */
    NULL, /* domainGetSchedulerParameters */
    NULL, /* domainSetSchedulerParameters */
121 122
};

123
#define xenXMError(code, ...)                                              \
124
        virReportErrorHelper(VIR_FROM_XENXM, code, __FILE__,               \
125
                             __FUNCTION__, __LINE__, __VA_ARGS__)
126

127
#ifndef WITH_XEN_INOTIFY
128 129 130 131
static int xenInotifyActive(virConnectPtr conn ATTRIBUTE_UNUSED)
{
   return 0;
}
132
#else
133 134 135 136
static int xenInotifyActive(virConnectPtr conn)
{
   xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
   return priv->inotifyWatch > 0;
137
}
138
#endif
139

140 141

/* Release memory associated with a cached config object */
142
static void xenXMConfigFree(void *payload, const void *key ATTRIBUTE_UNUSED) {
143
    xenXMConfCachePtr entry = (xenXMConfCachePtr)payload;
144
    virDomainDefFree(entry->def);
145
    VIR_FREE(entry);
146 147
}

148 149 150 151
struct xenXMConfigReaperData {
    xenUnifiedPrivatePtr priv;
    time_t now;
};
152

153
/* Remove any configs which were not refreshed recently */
154
static int xenXMConfigReaper(const void *payload, const void *key ATTRIBUTE_UNUSED, const void *data) {
155
    const struct xenXMConfigReaperData *args = data;
156 157
    xenXMConfCachePtr entry = (xenXMConfCachePtr)payload;

158 159
    /* We're going to purge this config file, so check if it
       is currently mapped as owner of a named domain. */
160
    if (entry->refreshedAt != args->now) {
161
        const char *olddomname = entry->def->name;
162
        char *nameowner = (char *)virHashLookup(args->priv->nameConfigMap, olddomname);
163
        if (nameowner && STREQ(nameowner, key)) {
164
            virHashRemoveEntry(args->priv->nameConfigMap, olddomname);
165 166 167 168 169 170
        }
        return (1);
    }
    return (0);
}

171 172 173 174 175

static virDomainDefPtr
xenXMConfigReadFile(virConnectPtr conn, const char *filename) {
    virConfPtr conf;
    virDomainDefPtr def;
176
    xenUnifiedPrivatePtr priv = conn->privateData;
177

178
    if (!(conf = virConfReadFile(filename, 0)))
179 180
        return NULL;

M
Markus Groß 已提交
181
    def = xenParseXM(conf, priv->xendConfigVersion, priv->caps);
182 183 184 185 186 187 188 189
    virConfFree(conf);

    return def;
}

static int
xenXMConfigSaveFile(virConnectPtr conn, const char *filename, virDomainDefPtr def) {
    virConfPtr conf;
190
    xenUnifiedPrivatePtr priv = conn->privateData;
191 192
    int ret;

M
Markus Groß 已提交
193
    if (!(conf = xenFormatXM(conn, def, priv->xendConfigVersion)))
194 195 196 197 198 199 200
        return -1;

    ret = virConfWriteFile(filename, conf);
    virConfFree(conf);
    return ret;
}

D
Daniel P. Berrange 已提交
201 202 203 204 205

/*
 * Caller must hold the lock on 'conn->privateData' before
 * calling this funtion
 */
206
int
207
xenXMConfigCacheRemoveFile(virConnectPtr conn,
208 209
                           const char *filename)
{
210
    xenUnifiedPrivatePtr priv = conn->privateData;
211 212
    xenXMConfCachePtr entry;

213
    entry = virHashLookup(priv->configCache, filename);
214
    if (!entry) {
215
        VIR_DEBUG("No config entry for %s", filename);
216 217 218
        return 0;
    }

219 220
    virHashRemoveEntry(priv->nameConfigMap, entry->def->name);
    virHashRemoveEntry(priv->configCache, filename);
221
    VIR_DEBUG("Removed %s %s", entry->def->name, filename);
222 223 224 225
    return 0;
}


D
Daniel P. Berrange 已提交
226 227 228 229
/*
 * Caller must hold the lock on 'conn->privateData' before
 * calling this funtion
 */
230 231 232
int
xenXMConfigCacheAddFile(virConnectPtr conn, const char *filename)
{
233
    xenUnifiedPrivatePtr priv = conn->privateData;
234 235 236 237 238
    xenXMConfCachePtr entry;
    struct stat st;
    int newborn = 0;
    time_t now = time(NULL);

239
    VIR_DEBUG("Adding file %s", filename);
240 241 242

    /* Get modified time */
    if ((stat(filename, &st) < 0)) {
243
        virReportSystemError(errno,
244 245
                             _("cannot stat: %s"),
                             filename);
246 247 248 249 250 251
        return -1;
    }

    /* Ignore zero length files, because inotify fires before
       any content has actually been created */
    if (st.st_size == 0) {
252
        VIR_DEBUG("Ignoring zero length file %s", filename);
253 254 255 256 257
        return -1;
    }

    /* If we already have a matching entry and it is not
    modified, then carry on to next one*/
258
    if ((entry = virHashLookup(priv->configCache, filename))) {
259 260 261 262 263 264 265 266 267 268
        char *nameowner;

        if (entry->refreshedAt >= st.st_mtime) {
            entry->refreshedAt = now;
            /* return success if up-to-date */
            return 0;
        }

        /* If we currently own the name, then release it and
            re-acquire it later - just in case it was renamed */
269
        nameowner = (char *)virHashLookup(priv->nameConfigMap, entry->def->name);
270
        if (nameowner && STREQ(nameowner, filename)) {
271
            virHashRemoveEntry(priv->nameConfigMap, entry->def->name);
272 273 274 275 276 277 278 279
        }

        /* Clear existing config entry which needs refresh */
        virDomainDefFree(entry->def);
        entry->def = NULL;
    } else { /* Completely new entry */
        newborn = 1;
        if (VIR_ALLOC(entry) < 0) {
280
            virReportOOMError();
281 282 283 284 285 286 287
            return -1;
        }
        memcpy(entry->filename, filename, PATH_MAX);
    }
    entry->refreshedAt = now;

    if (!(entry->def = xenXMConfigReadFile(conn, entry->filename))) {
288
        VIR_DEBUG("Failed to read %s", entry->filename);
289
        if (!newborn)
290
            virHashSteal(priv->configCache, filename);
291 292 293 294 295 296 297
        VIR_FREE(entry);
        return -1;
    }

    /* If its a completely new entry, it must be stuck into
        the cache (refresh'd entries are already registered) */
    if (newborn) {
298
        if (virHashAddEntry(priv->configCache, entry->filename, entry) < 0) {
299 300
            virDomainDefFree(entry->def);
            VIR_FREE(entry);
301
            xenXMError(VIR_ERR_INTERNAL_ERROR,
302 303 304 305 306 307 308 309
                        "%s", _("xenXMConfigCacheRefresh: virHashAddEntry"));
            return -1;
        }
    }

    /* See if we need to map this config file in as the primary owner
        * of the domain in question
        */
310 311
    if (!virHashLookup(priv->nameConfigMap, entry->def->name)) {
        if (virHashAddEntry(priv->nameConfigMap, entry->def->name, entry->filename) < 0) {
312
            virHashSteal(priv->configCache, filename);
313 314 315 316
            virDomainDefFree(entry->def);
            VIR_FREE(entry);
        }
    }
317
    VIR_DEBUG("Added config %s %s", entry->def->name, filename);
318 319 320

    return 0;
}
321

322
/* This method is called by various methods to scan /etc/xen
D
Daniel P. Berrange 已提交
323 324 325 326 327 328 329 330
 * (or whatever directory was set by  LIBVIRT_XM_CONFIG_DIR
 * environment variable) and process any domain configs. It
 * has rate-limited so never rescans more frequently than
 * once every X seconds
 *
 * Caller must hold the lock on 'conn->privateData' before
 * calling this funtion
 */
331
int xenXMConfigCacheRefresh (virConnectPtr conn) {
332
    xenUnifiedPrivatePtr priv = conn->privateData;
333 334 335 336
    DIR *dh;
    struct dirent *ent;
    time_t now = time(NULL);
    int ret = -1;
337
    struct xenXMConfigReaperData args;
338 339

    if (now == ((time_t)-1)) {
340
        virReportSystemError(errno,
341
                             "%s", _("cannot get time of day"));
342 343 344 345
        return (-1);
    }

    /* Rate limit re-scans */
346
    if ((now - priv->lastRefresh) < XM_REFRESH_INTERVAL)
347 348
        return (0);

349
    priv->lastRefresh = now;
350 351

    /* Process the files in the config dir */
352
    if (!(dh = opendir(priv->configDir))) {
353
        virReportSystemError(errno,
354
                             _("cannot read directory %s"),
355
                             priv->configDir);
356 357 358 359 360
        return (-1);
    }

    while ((ent = readdir(dh))) {
        struct stat st;
361
        char *path;
362 363 364 365 366 367

        /*
         * Skip a bunch of crufty files that clearly aren't config files
         */

        /* Like 'dot' files... */
368
        if (STRPREFIX(ent->d_name, "."))
369 370
            continue;
        /* ...and the XenD server config file */
371
        if (STRPREFIX(ent->d_name, XEND_CONFIG_FILE))
372 373
            continue;
        /* ...and random PCI config cruft */
374
        if (STRPREFIX(ent->d_name, XEND_PCI_CONFIG_PREFIX))
375 376
            continue;
        /* ...and the example domain configs */
377
        if (STRPREFIX(ent->d_name, XM_EXAMPLE_PREFIX))
378 379
            continue;
        /* ...and the QEMU networking script */
380
        if (STRPREFIX(ent->d_name, QEMU_IF_SCRIPT))
381 382 383 384 385 386 387 388 389
            continue;

        /* ...and editor backups */
        if (ent->d_name[0] == '#')
            continue;
        if (ent->d_name[strlen(ent->d_name)-1] == '~')
            continue;

        /* Build the full file path */
390 391 392 393
        if (!(path = virFileBuildPath(priv->configDir, ent->d_name, NULL))) {
            closedir(dh);
            return -1;
        }
394 395 396 397

        /* Skip anything which isn't a file (takes care of scripts/ subdir */
        if ((stat(path, &st) < 0) ||
            (!S_ISREG(st.st_mode))) {
398
            VIR_FREE(path);
399 400 401 402 403
            continue;
        }

        /* If we already have a matching entry and it is not
           modified, then carry on to next one*/
404 405
        if (xenXMConfigCacheAddFile(conn, path) < 0) {
            /* Ignoring errors, since alot of stuff goes wrong in /etc/xen */
406
        }
407 408

        VIR_FREE(path);
409 410 411 412 413 414
    }

    /* Reap all entries which were not changed, by comparing
       their refresh timestamp - the timestamp should match
       'now' if they were refreshed. If timestamp doesn't match
       then the config is no longer on disk */
415 416
    args.now = now;
    args.priv = priv;
417
    virHashRemoveSet(priv->configCache, xenXMConfigReaper, &args);
418 419
    ret = 0;

420
    closedir(dh);
421 422 423 424 425 426

    return (ret);
}


/*
427 428 429 430
 * The XM driver keeps a cache of config files as virDomainDefPtr
 * objects in the xenUnifiedPrivatePtr. Optionally inotify lets
 * us watch for changes (see separate driver), otherwise we poll
 * every few seconds
431
 */
432
virDrvOpenStatus
433
xenXMOpen (virConnectPtr conn,
434 435
           virConnectAuthPtr auth ATTRIBUTE_UNUSED,
           int flags ATTRIBUTE_UNUSED)
436
{
437 438 439 440
    xenUnifiedPrivatePtr priv = conn->privateData;

    priv->configDir = XM_CONFIG_DIR;

441
    priv->configCache = virHashCreate(50, xenXMConfigFree);
442 443
    if (!priv->configCache)
        return (-1);
444
    priv->nameConfigMap = virHashCreate(50, NULL);
445
    if (!priv->nameConfigMap) {
446
        virHashFree(priv->configCache);
447 448
        priv->configCache = NULL;
        return (-1);
449
    }
450 451 452 453
    /* Force the cache to be reloaded next time that
     * xenXMConfigCacheRefresh is called.
     */
    priv->lastRefresh = 0;
454 455 456 457 458

    return (0);
}

/*
459 460
 * Free the cached config files associated with this
 * connection
461
 */
462 463 464
int xenXMClose(virConnectPtr conn) {
    xenUnifiedPrivatePtr priv = conn->privateData;

465 466
    virHashFree(priv->nameConfigMap);
    virHashFree(priv->configCache);
467

468 469 470 471 472
    return (0);
}

/*
 * Since these are all offline domains, we only return info about
473
 * VCPUs and memory.
474 475
 */
int xenXMDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info) {
476
    xenUnifiedPrivatePtr priv;
477
    const char *filename;
478 479
    xenXMConfCachePtr entry;
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
480
        xenXMError(VIR_ERR_INVALID_ARG, __FUNCTION__);
481 482 483
        return(-1);
    }

484
    if (domain->id != -1)
485 486
        return (-1);

487
    priv = domain->conn->privateData;
D
Daniel P. Berrange 已提交
488
    xenUnifiedLock(priv);
489 490

    if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
D
Daniel P. Berrange 已提交
491
        goto error;
492

493
    if (!(entry = virHashLookup(priv->configCache, filename)))
D
Daniel P. Berrange 已提交
494
        goto error;
495 496

    memset(info, 0, sizeof(virDomainInfo));
497 498
    info->maxMem = entry->def->mem.max_balloon;
    info->memory = entry->def->mem.cur_balloon;
499
    info->nrVirtCpu = entry->def->vcpus;
500 501 502
    info->state = VIR_DOMAIN_SHUTOFF;
    info->cpuTime = 0;

D
Daniel P. Berrange 已提交
503
    xenUnifiedUnlock(priv);
504 505
    return (0);

D
Daniel P. Berrange 已提交
506 507 508
error:
    xenUnifiedUnlock(priv);
    return -1;
509 510 511
}


512 513
/*
 * Turn a config record into a lump of XML describing the
514
 * domain, suitable for later feeding for virDomainCreateXML
515
 */
516
char *xenXMDomainDumpXML(virDomainPtr domain, int flags) {
517
    xenUnifiedPrivatePtr priv;
518 519
    const char *filename;
    xenXMConfCachePtr entry;
D
Daniel P. Berrange 已提交
520
    char *ret = NULL;
521 522

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
523
        xenXMError(VIR_ERR_INVALID_ARG, __FUNCTION__);
524 525
        return(NULL);
    }
526
    if (domain->id != -1)
527 528
        return (NULL);

529
    priv = domain->conn->privateData;
D
Daniel P. Berrange 已提交
530
    xenUnifiedLock(priv);
531 532

    if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
D
Daniel P. Berrange 已提交
533
        goto cleanup;
534

535
    if (!(entry = virHashLookup(priv->configCache, filename)))
D
Daniel P. Berrange 已提交
536 537
        goto cleanup;

538
    ret = virDomainDefFormat(entry->def, flags);
539

D
Daniel P. Berrange 已提交
540 541 542
cleanup:
    xenUnifiedUnlock(priv);
    return ret;
543 544 545
}


546 547 548 549
/*
 * Update amount of memory in the config file
 */
int xenXMDomainSetMemory(virDomainPtr domain, unsigned long memory) {
550
    xenUnifiedPrivatePtr priv;
551
    const char *filename;
552
    xenXMConfCachePtr entry;
D
Daniel P. Berrange 已提交
553
    int ret = -1;
554 555

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
556
        xenXMError(VIR_ERR_INVALID_ARG, __FUNCTION__);
557 558 559 560
        return (-1);
    }
    if (domain->conn->flags & VIR_CONNECT_RO)
        return (-1);
561
    if (domain->id != -1)
562
        return (-1);
563 564
    if (memory < 1024 * MIN_XEN_GUEST_SIZE)
        return (-1);
565

566
    priv = domain->conn->privateData;
D
Daniel P. Berrange 已提交
567
    xenUnifiedLock(priv);
568 569

    if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
D
Daniel P. Berrange 已提交
570
        goto cleanup;
571

572
    if (!(entry = virHashLookup(priv->configCache, filename)))
D
Daniel P. Berrange 已提交
573
        goto cleanup;
574

575 576 577
    entry->def->mem.cur_balloon = memory;
    if (entry->def->mem.cur_balloon > entry->def->mem.max_balloon)
        entry->def->mem.cur_balloon = entry->def->mem.max_balloon;
578 579 580 581

    /* If this fails, should we try to undo our changes to the
     * in-memory representation of the config file. I say not!
     */
582
    if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
D
Daniel P. Berrange 已提交
583 584
        goto cleanup;
    ret = 0;
585

D
Daniel P. Berrange 已提交
586 587 588
cleanup:
    xenUnifiedUnlock(priv);
    return ret;
589 590 591 592 593 594
}

/*
 * Update maximum memory limit in config
 */
int xenXMDomainSetMaxMemory(virDomainPtr domain, unsigned long memory) {
595
    xenUnifiedPrivatePtr priv;
596
    const char *filename;
597
    xenXMConfCachePtr entry;
D
Daniel P. Berrange 已提交
598
    int ret = -1;
599 600

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
601
        xenXMError(VIR_ERR_INVALID_ARG, __FUNCTION__);
602 603 604 605
        return (-1);
    }
    if (domain->conn->flags & VIR_CONNECT_RO)
        return (-1);
606
    if (domain->id != -1)
607 608
        return (-1);

609
    priv = domain->conn->privateData;
D
Daniel P. Berrange 已提交
610
    xenUnifiedLock(priv);
611 612

    if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
D
Daniel P. Berrange 已提交
613
        goto cleanup;
614

615
    if (!(entry = virHashLookup(priv->configCache, filename)))
D
Daniel P. Berrange 已提交
616
        goto cleanup;
617

618 619 620
    entry->def->mem.max_balloon = memory;
    if (entry->def->mem.cur_balloon > entry->def->mem.max_balloon)
        entry->def->mem.cur_balloon = entry->def->mem.max_balloon;
621 622 623 624

    /* If this fails, should we try to undo our changes to the
     * in-memory representation of the config file. I say not!
     */
625
    if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
D
Daniel P. Berrange 已提交
626 627
        goto cleanup;
    ret = 0;
628

D
Daniel P. Berrange 已提交
629 630 631
cleanup:
    xenUnifiedUnlock(priv);
    return ret;
632 633 634 635 636 637
}

/*
 * Get max memory limit from config
 */
unsigned long xenXMDomainGetMaxMemory(virDomainPtr domain) {
638
    xenUnifiedPrivatePtr priv;
639
    const char *filename;
640
    xenXMConfCachePtr entry;
D
Daniel P. Berrange 已提交
641
    unsigned long ret = 0;
642 643

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
644
        xenXMError(VIR_ERR_INVALID_ARG, __FUNCTION__);
D
Daniel P. Berrange 已提交
645
        return (0);
646
    }
647
    if (domain->id != -1)
D
Daniel P. Berrange 已提交
648
        return (0);
649

650
    priv = domain->conn->privateData;
D
Daniel P. Berrange 已提交
651
    xenUnifiedLock(priv);
652 653

    if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
D
Daniel P. Berrange 已提交
654
        goto cleanup;
655

656
    if (!(entry = virHashLookup(priv->configCache, filename)))
D
Daniel P. Berrange 已提交
657 658
        goto cleanup;

659
    ret = entry->def->mem.max_balloon;
660

D
Daniel P. Berrange 已提交
661 662 663
cleanup:
    xenUnifiedUnlock(priv);
    return ret;
664 665
}

666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737
/*
 * xenXMDomainSetVcpusFlags:
 * @domain: pointer to domain object
 * @nvcpus: number of vcpus
 * @flags: bitwise-ORd from virDomainVcpuFlags
 *
 * Change virtual CPUs allocation of domain according to flags.
 *
 * Returns 0 on success, -1 if an error message was issued, and -2 if
 * the unified driver should keep trying.
 */
int
xenXMDomainSetVcpusFlags(virDomainPtr domain, unsigned int vcpus,
                         unsigned int flags)
{
    xenUnifiedPrivatePtr priv;
    const char *filename;
    xenXMConfCachePtr entry;
    int ret = -1;
    int max;

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
        xenXMError(VIR_ERR_INVALID_ARG, __FUNCTION__);
        return -1;
    }
    if (domain->conn->flags & VIR_CONNECT_RO) {
        xenXMError(VIR_ERR_OPERATION_DENIED, __FUNCTION__);
        return -1;
    }
    if (domain->id != -1)
        return -2;
    if (flags & VIR_DOMAIN_VCPU_LIVE) {
        xenXMError(VIR_ERR_OPERATION_INVALID, "%s",
                   _("domain is not running"));
        return -1;
    }

    priv = domain->conn->privateData;
    xenUnifiedLock(priv);

    if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
        goto cleanup;

    if (!(entry = virHashLookup(priv->configCache, filename)))
        goto cleanup;

    /* Hypervisor maximum. */
    if ((max = xenUnifiedGetMaxVcpus(domain->conn, NULL)) < 0) {
        xenXMError(VIR_ERR_INTERNAL_ERROR, "%s",
                   _("could not determin max vcpus for the domain"));
        goto cleanup;
    }
    /* Can't specify a current larger than stored maximum; but
     * reducing maximum can silently reduce current.  */
    if (!(flags & VIR_DOMAIN_VCPU_MAXIMUM))
        max = entry->def->maxvcpus;
    if (vcpus > max) {
        xenXMError(VIR_ERR_INVALID_ARG,
                   _("requested vcpus is greater than max allowable"
                     " vcpus for the domain: %d > %d"), vcpus, max);
        goto cleanup;
    }

    if (flags & VIR_DOMAIN_VCPU_MAXIMUM) {
        entry->def->maxvcpus = vcpus;
        if (entry->def->vcpus > vcpus)
            entry->def->vcpus = vcpus;
    } else {
        entry->def->vcpus = vcpus;
    }

    /* If this fails, should we try to undo our changes to the
738 739
     * in-memory representation of the config file. I say not!
     */
740
    if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
D
Daniel P. Berrange 已提交
741 742
        goto cleanup;
    ret = 0;
743

D
Daniel P. Berrange 已提交
744 745 746
cleanup:
    xenUnifiedUnlock(priv);
    return ret;
747 748
}

749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795
/**
 * xenXMDomainGetVcpusFlags:
 * @domain: pointer to domain object
 * @flags: bitwise-ORd from virDomainVcpuFlags
 *
 * Extract information about virtual CPUs of domain according to flags.
 *
 * Returns the number of vcpus on success, -1 if an error message was
 * issued, and -2 if the unified driver should keep trying.
 */
int
xenXMDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags)
{
    xenUnifiedPrivatePtr priv;
    const char *filename;
    xenXMConfCachePtr entry;
    int ret = -2;

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
        xenXMError(VIR_ERR_INVALID_ARG, __FUNCTION__);
        return -1;
    }

    if (domain->id != -1)
        return -2;
    if (flags & VIR_DOMAIN_VCPU_LIVE) {
        xenXMError(VIR_ERR_OPERATION_FAILED, "%s", _("domain not active"));
        return -1;
    }

    priv = domain->conn->privateData;
    xenUnifiedLock(priv);

    if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
        goto cleanup;

    if (!(entry = virHashLookup(priv->configCache, filename)))
        goto cleanup;

    ret = ((flags & VIR_DOMAIN_VCPU_MAXIMUM) ? entry->def->maxvcpus
           : entry->def->vcpus);

cleanup:
    xenUnifiedUnlock(priv);
    return ret;
}

796 797 798 799 800 801 802 803 804 805 806 807 808 809 810
/**
 * xenXMDomainPinVcpu:
 * @domain: pointer to domain object
 * @vcpu: virtual CPU number (reserved)
 * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes)
 * @maplen: length of cpumap in bytes
 *
 * Set the vcpu affinity in config
 *
 * Returns 0 for success; -1 (with errno) on error
 */
int xenXMDomainPinVcpu(virDomainPtr domain,
                       unsigned int vcpu ATTRIBUTE_UNUSED,
                       unsigned char *cpumap, int maplen)
{
811
    xenUnifiedPrivatePtr priv;
812 813
    const char *filename;
    xenXMConfCachePtr entry;
814
    virBuffer mapbuf = VIR_BUFFER_INITIALIZER;
815
    char *mapstr = NULL, *mapsave = NULL;
816 817
    int i, j, n, comma = 0;
    int ret = -1;
818 819
    char *cpuset = NULL;
    int maxcpu = XEN_MAX_PHYSICAL_CPU;
820 821 822

    if (domain == NULL || domain->conn == NULL || domain->name == NULL
        || cpumap == NULL || maplen < 1 || maplen > (int)sizeof(cpumap_t)) {
823
        xenXMError(VIR_ERR_INVALID_ARG, __FUNCTION__);
824 825 826
        return -1;
    }
    if (domain->conn->flags & VIR_CONNECT_RO) {
827
        xenXMError(VIR_ERR_INVALID_ARG,
J
Jim Meyering 已提交
828
                    "%s", _("read only connection"));
829 830 831
        return -1;
    }
    if (domain->id != -1) {
832
        xenXMError(VIR_ERR_INVALID_ARG,
J
Jim Meyering 已提交
833
                    "%s", _("not inactive domain"));
834 835 836
        return -1;
    }

837
    priv = domain->conn->privateData;
D
Daniel P. Berrange 已提交
838
    xenUnifiedLock(priv);
839 840

    if (!(filename = virHashLookup(priv->nameConfigMap, domain->name))) {
841
        xenXMError(VIR_ERR_INTERNAL_ERROR, "%s", _("virHashLookup"));
D
Daniel P. Berrange 已提交
842
        goto cleanup;
843
    }
844
    if (!(entry = virHashLookup(priv->configCache, filename))) {
845
        xenXMError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
846
                    "%s", _("can't retrieve config file for domain"));
D
Daniel P. Berrange 已提交
847
        goto cleanup;
848 849 850 851 852 853 854 855
    }

    /* from bit map, build character string of mapped CPU numbers */
    for (i = 0; i < maplen; i++)
        for (j = 0; j < 8; j++)
            if ((cpumap[i] & (1 << j))) {
                n = i*8 + j;

856 857
                if (comma)
                    virBufferAddLit (&mapbuf, ",");
858 859
                comma = 1;

860
                virBufferAsprintf (&mapbuf, "%d", n);
861 862
            }

863
    if (virBufferError(&mapbuf)) {
864
        virBufferFreeAndReset(&mapbuf);
865
        virReportOOMError();
D
Daniel P. Berrange 已提交
866
        goto cleanup;
867 868 869
    }

    mapstr = virBufferContentAndReset(&mapbuf);
870
    mapsave = mapstr;
871

872
    if (VIR_ALLOC_N(cpuset, maxcpu) < 0) {
873
        virReportOOMError();
874 875
        goto cleanup;
    }
876
    if (virDomainCpuSetParse((const char **)&mapstr, 0,
877 878
                             cpuset, maxcpu) < 0)
        goto cleanup;
879

880 881 882 883
    VIR_FREE(entry->def->cpumask);
    entry->def->cpumask = cpuset;
    entry->def->cpumasklen = maxcpu;
    cpuset = NULL;
884

885
    if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
886 887 888 889 890
        goto cleanup;

    ret = 0;

 cleanup:
891
    VIR_FREE(mapsave);
892
    VIR_FREE(cpuset);
D
Daniel P. Berrange 已提交
893
    xenUnifiedUnlock(priv);
894 895 896
    return (ret);
}

897 898 899 900
/*
 * Find an inactive domain based on its name
 */
virDomainPtr xenXMDomainLookupByName(virConnectPtr conn, const char *domname) {
901
    xenUnifiedPrivatePtr priv;
902
    const char *filename;
903
    xenXMConfCachePtr entry;
D
Daniel P. Berrange 已提交
904
    virDomainPtr ret = NULL;
905

906
    if (!VIR_IS_CONNECT(conn)) {
907
        xenXMError(VIR_ERR_INVALID_CONN, __FUNCTION__);
908 909 910
        return (NULL);
    }
    if (domname == NULL) {
911
        xenXMError(VIR_ERR_INVALID_ARG, __FUNCTION__);
912 913 914
        return (NULL);
    }

915
    priv = conn->privateData;
D
Daniel P. Berrange 已提交
916
    xenUnifiedLock(priv);
917

918
    if (!xenInotifyActive(conn) && xenXMConfigCacheRefresh (conn) < 0)
D
Daniel P. Berrange 已提交
919
        goto cleanup;
920

921
    if (!(filename = virHashLookup(priv->nameConfigMap, domname)))
D
Daniel P. Berrange 已提交
922
        goto cleanup;
923

D
Daniel P. Berrange 已提交
924 925
    if (!(entry = virHashLookup(priv->configCache, filename)))
        goto cleanup;
926

D
Daniel P. Berrange 已提交
927 928
    if (!(ret = virGetDomain(conn, domname, entry->def->uuid)))
        goto cleanup;
929 930 931

    /* Ensure its marked inactive, because may be cached
       handle to a previously active domain */
932
    ret->id = -1;
933

D
Daniel P. Berrange 已提交
934 935
cleanup:
    xenUnifiedUnlock(priv);
936 937 938 939 940 941 942
    return (ret);
}


/*
 * Hash table iterator to search for a domain based on UUID
 */
943
static int xenXMDomainSearchForUUID(const void *payload, const void *name ATTRIBUTE_UNUSED, const void *data) {
944 945 946
    const unsigned char *wantuuid = (const unsigned char *)data;
    const xenXMConfCachePtr entry = (const xenXMConfCachePtr)payload;

947
    if (!memcmp(entry->def->uuid, wantuuid, VIR_UUID_BUFLEN))
948 949 950 951 952 953 954 955 956 957
        return (1);

    return (0);
}

/*
 * Find an inactive domain based on its UUID
 */
virDomainPtr xenXMDomainLookupByUUID(virConnectPtr conn,
                                     const unsigned char *uuid) {
958
    xenUnifiedPrivatePtr priv;
959
    xenXMConfCachePtr entry;
D
Daniel P. Berrange 已提交
960
    virDomainPtr ret = NULL;
961 962

    if (!VIR_IS_CONNECT(conn)) {
963
        xenXMError(VIR_ERR_INVALID_CONN, __FUNCTION__);
964 965 966
        return (NULL);
    }
    if (uuid == NULL) {
967
        xenXMError(VIR_ERR_INVALID_ARG, __FUNCTION__);
968 969 970
        return (NULL);
    }

971
    priv = conn->privateData;
D
Daniel P. Berrange 已提交
972
    xenUnifiedLock(priv);
973

974
    if (!xenInotifyActive(conn) && xenXMConfigCacheRefresh (conn) < 0)
D
Daniel P. Berrange 已提交
975
        goto cleanup;
976

D
Daniel P. Berrange 已提交
977 978
    if (!(entry = virHashSearch(priv->configCache, xenXMDomainSearchForUUID, (const void *)uuid)))
        goto cleanup;
979

D
Daniel P. Berrange 已提交
980 981
    if (!(ret = virGetDomain(conn, entry->def->name, uuid)))
        goto cleanup;
982

983 984
    /* Ensure its marked inactive, because may be cached
       handle to a previously active domain */
985
    ret->id = -1;
986

D
Daniel P. Berrange 已提交
987 988
cleanup:
    xenUnifiedUnlock(priv);
989 990 991 992 993 994 995 996 997
    return (ret);
}


/*
 * Start a domain from an existing defined config file
 */
int xenXMDomainCreate(virDomainPtr domain) {
    char *sexpr;
D
Daniel P. Berrange 已提交
998
    int ret = -1;
999
    xenUnifiedPrivatePtr priv;
1000 1001 1002 1003
    const char *filename;
    xenXMConfCachePtr entry;

    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
1004

1005
    if (domain->id != -1)
1006 1007
        return (-1);

D
Daniel P. Berrange 已提交
1008 1009
    xenUnifiedLock(priv);

1010
    if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
D
Daniel P. Berrange 已提交
1011
        goto error;
1012

1013
    if (!(entry = virHashLookup(priv->configCache, filename)))
D
Daniel P. Berrange 已提交
1014
        goto error;
1015

M
Markus Groß 已提交
1016
    if (!(sexpr = xenFormatSxpr(domain->conn, entry->def, priv->xendConfigVersion)))
D
Daniel P. Berrange 已提交
1017
        goto error;
1018

1019
    ret = xenDaemonDomainCreateXML(domain->conn, sexpr);
1020
    VIR_FREE(sexpr);
D
Daniel P. Berrange 已提交
1021 1022
    if (ret != 0)
        goto error;
1023

1024
    if ((ret = xenDaemonDomainLookupByName_ids(domain->conn, domain->name,
D
Daniel P. Berrange 已提交
1025 1026
                                               entry->def->uuid)) < 0)
        goto error;
1027
    domain->id = ret;
1028

1029
    if (xend_wait_for_devices(domain->conn, domain->name) < 0)
D
Daniel P. Berrange 已提交
1030
        goto error;
1031

1032
    if (xenDaemonDomainResume(domain) < 0)
D
Daniel P. Berrange 已提交
1033
        goto error;
1034

D
Daniel P. Berrange 已提交
1035
    xenUnifiedUnlock(priv);
1036 1037
    return (0);

D
Daniel P. Berrange 已提交
1038
 error:
1039
    if (domain->id != -1) {
1040
        xenDaemonDomainDestroy(domain);
1041
        domain->id = -1;
1042
    }
D
Daniel P. Berrange 已提交
1043
    xenUnifiedUnlock(priv);
1044
    return (-1);
1045 1046
}

1047 1048 1049 1050
/*
 * Create a config file for a domain, based on an XML
 * document describing its config
 */
1051 1052
virDomainPtr xenXMDomainDefineXML(virConnectPtr conn, const char *xml)
{
1053
    virDomainPtr ret;
1054 1055
    char *filename;
    const char *oldfilename;
1056
    virDomainDefPtr def = NULL;
1057
    xenXMConfCachePtr entry = NULL;
1058
    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
1059 1060

    if (!VIR_IS_CONNECT(conn)) {
1061
        xenXMError(VIR_ERR_INVALID_CONN, __FUNCTION__);
1062 1063 1064
        return (NULL);
    }
    if (xml == NULL) {
1065
        xenXMError(VIR_ERR_INVALID_ARG, __FUNCTION__);
1066 1067 1068 1069 1070
        return (NULL);
    }
    if (conn->flags & VIR_CONNECT_RO)
        return (NULL);

D
Daniel P. Berrange 已提交
1071 1072
    xenUnifiedLock(priv);

1073
    if (!xenInotifyActive(conn) && xenXMConfigCacheRefresh (conn) < 0) {
D
Daniel P. Berrange 已提交
1074
        xenUnifiedUnlock(priv);
1075
        return (NULL);
D
Daniel P. Berrange 已提交
1076
    }
1077

1078
    if (!(def = virDomainDefParseString(priv->caps, xml,
D
Daniel P. Berrange 已提交
1079
                                        VIR_DOMAIN_XML_INACTIVE))) {
1080
        xenUnifiedUnlock(priv);
1081
        return (NULL);
D
Daniel P. Berrange 已提交
1082
    }
1083

1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094
    /*
     * check that if there is another domain defined with the same uuid
     * it has the same name
     */
    if ((entry = virHashSearch(priv->configCache, xenXMDomainSearchForUUID,
                               (const void *)&(def->uuid))) != NULL) {
        if ((entry->def != NULL) && (entry->def->name != NULL) &&
            (STRNEQ(def->name, entry->def->name))) {
            char uuidstr[VIR_UUID_STRING_BUFLEN];

            virUUIDFormat(entry->def->uuid, uuidstr);
1095
            xenXMError(VIR_ERR_OPERATION_FAILED,
1096 1097 1098 1099 1100 1101 1102 1103
                       _("domain '%s' is already defined with uuid %s"),
                       entry->def->name, uuidstr);
            entry = NULL;
            goto error;
        }
        entry = NULL;
    }

1104
    if (virHashLookup(priv->nameConfigMap, def->name)) {
1105 1106
        /* domain exists, we will overwrite it */

1107
        if (!(oldfilename = (char *)virHashLookup(priv->nameConfigMap, def->name))) {
1108
            xenXMError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1109
                       "%s", _("can't retrieve config filename for domain to overwrite"));
1110 1111 1112
            goto error;
        }

1113
        if (!(entry = virHashLookup(priv->configCache, oldfilename))) {
1114
            xenXMError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1115
                       "%s", _("can't retrieve config entry for domain to overwrite"));
1116 1117 1118 1119
            goto error;
        }

        /* Remove the name -> filename mapping */
1120
        if (virHashRemoveEntry(priv->nameConfigMap, def->name) < 0) {
1121
            xenXMError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1122
                       "%s", _("failed to remove old domain from config map"));
1123 1124 1125 1126
            goto error;
        }

        /* Remove the config record itself */
1127
        if (virHashRemoveEntry(priv->configCache, oldfilename) < 0) {
1128
            xenXMError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1129
                       "%s", _("failed to remove old domain from config map"));
1130 1131 1132 1133
            goto error;
        }

        entry = NULL;
1134
    }
1135

1136
    if (!(filename = virFileBuildPath(priv->configDir, def->name, NULL)))
1137 1138
        goto error;

1139
    if (xenXMConfigSaveFile(conn, filename, def) < 0)
1140 1141
        goto error;

1142
    if (VIR_ALLOC(entry) < 0) {
1143
        virReportOOMError();
1144
        goto error;
1145
    }
1146

1147
    if ((entry->refreshedAt = time(NULL)) == ((time_t)-1)) {
1148
        xenXMError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1149
                   "%s", _("unable to get current time"));
1150
        goto error;
1151
    }
1152 1153

    memmove(entry->filename, filename, PATH_MAX);
1154
    entry->def = def;
1155

1156
    if (virHashAddEntry(priv->configCache, filename, entry) < 0) {
1157
        xenXMError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1158
                   "%s", _("unable to store config file handle"));
1159
        goto error;
1160
    }
1161

1162
    if (virHashAddEntry(priv->nameConfigMap, def->name, entry->filename) < 0) {
1163
        virHashSteal(priv->configCache, filename);
1164
        xenXMError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1165
                   "%s", _("unable to store config file handle"));
1166
        goto error;
1167 1168
    }

1169
    ret = virGetDomain(conn, def->name, def->uuid);
D
Daniel P. Berrange 已提交
1170
    xenUnifiedUnlock(priv);
1171
    VIR_FREE(filename);
1172 1173 1174
    return (ret);

 error:
1175
    VIR_FREE(filename);
1176
    VIR_FREE(entry);
1177
    virDomainDefFree(def);
D
Daniel P. Berrange 已提交
1178
    xenUnifiedUnlock(priv);
1179 1180 1181 1182 1183 1184 1185
    return (NULL);
}

/*
 * Delete a domain from disk
 */
int xenXMDomainUndefine(virDomainPtr domain) {
1186
    xenUnifiedPrivatePtr priv;
1187
    const char *filename;
1188
    xenXMConfCachePtr entry;
D
Daniel P. Berrange 已提交
1189 1190
    int ret = -1;

1191
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
1192
        xenXMError(VIR_ERR_INVALID_ARG, __FUNCTION__);
1193 1194 1195
        return (-1);
    }

1196
    if (domain->id != -1)
1197 1198 1199 1200
        return (-1);
    if (domain->conn->flags & VIR_CONNECT_RO)
        return (-1);

1201
    priv = domain->conn->privateData;
D
Daniel P. Berrange 已提交
1202
    xenUnifiedLock(priv);
1203 1204

    if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
D
Daniel P. Berrange 已提交
1205
        goto cleanup;
1206

1207
    if (!(entry = virHashLookup(priv->configCache, filename)))
D
Daniel P. Berrange 已提交
1208
        goto cleanup;
1209 1210

    if (unlink(entry->filename) < 0)
D
Daniel P. Berrange 已提交
1211
        goto cleanup;
1212

1213
    /* Remove the name -> filename mapping */
1214
    if (virHashRemoveEntry(priv->nameConfigMap, domain->name) < 0)
D
Daniel P. Berrange 已提交
1215
        goto cleanup;
1216

1217
    /* Remove the config record itself */
1218
    if (virHashRemoveEntry(priv->configCache, entry->filename) < 0)
D
Daniel P. Berrange 已提交
1219
        goto cleanup;
1220

D
Daniel P. Berrange 已提交
1221 1222 1223 1224 1225
    ret = 0;

cleanup:
    xenUnifiedUnlock(priv);
    return ret;
1226 1227 1228 1229
}

struct xenXMListIteratorContext {
    virConnectPtr conn;
1230
    int oom;
1231 1232
    int max;
    int count;
1233
    char ** names;
1234 1235
};

1236
static void xenXMListIterator(void *payload ATTRIBUTE_UNUSED, const void *name, void *data) {
1237
    struct xenXMListIteratorContext *ctx = data;
1238 1239
    virDomainPtr dom = NULL;

1240 1241 1242
    if (ctx->oom)
        return;

1243 1244 1245
    if (ctx->count == ctx->max)
        return;

1246
    dom = xenDaemonLookupByName(ctx->conn, name);
1247
    if (!dom) {
1248 1249 1250 1251
        if (!(ctx->names[ctx->count] = strdup(name)))
            ctx->oom = 1;
        else
            ctx->count++;
1252 1253 1254 1255 1256 1257 1258 1259 1260 1261
    } else {
        virDomainFree(dom);
    }
}


/*
 * List all defined domains, filtered to remove any which
 * are currently running
 */
1262
int xenXMListDefinedDomains(virConnectPtr conn, char **const names, int maxnames) {
1263
    xenUnifiedPrivatePtr priv;
1264
    struct xenXMListIteratorContext ctx;
1265
    int i, ret = -1;
1266 1267

    if (!VIR_IS_CONNECT(conn)) {
1268
        xenXMError(VIR_ERR_INVALID_CONN, __FUNCTION__);
1269 1270 1271
        return (-1);
    }

1272
    priv = conn->privateData;
D
Daniel P. Berrange 已提交
1273
    xenUnifiedLock(priv);
1274

1275
    if (!xenInotifyActive(conn) && xenXMConfigCacheRefresh (conn) < 0)
D
Daniel P. Berrange 已提交
1276
        goto cleanup;
1277

1278 1279
    if (maxnames > virHashSize(priv->configCache))
        maxnames = virHashSize(priv->configCache);
1280 1281

    ctx.conn = conn;
1282
    ctx.oom = 0;
1283 1284 1285 1286
    ctx.count = 0;
    ctx.max = maxnames;
    ctx.names = names;

1287
    virHashForEach(priv->nameConfigMap, xenXMListIterator, &ctx);
1288 1289 1290 1291 1292

    if (ctx.oom) {
        for (i = 0; i < ctx.count; i++)
            VIR_FREE(ctx.names[i]);

1293
        virReportOOMError();
1294 1295 1296
        goto cleanup;
    }

D
Daniel P. Berrange 已提交
1297 1298 1299 1300 1301
    ret = ctx.count;

cleanup:
    xenUnifiedUnlock(priv);
    return ret;
1302 1303 1304 1305 1306 1307 1308
}

/*
 * Return the maximum number of defined domains - not filtered
 * based on number running
 */
int xenXMNumOfDefinedDomains(virConnectPtr conn) {
1309
    xenUnifiedPrivatePtr priv;
D
Daniel P. Berrange 已提交
1310
    int ret = -1;
1311

1312
    if (!VIR_IS_CONNECT(conn)) {
1313
        xenXMError(VIR_ERR_INVALID_CONN, __FUNCTION__);
1314 1315 1316
        return (-1);
    }

1317
    priv = conn->privateData;
D
Daniel P. Berrange 已提交
1318
    xenUnifiedLock(priv);
1319

1320
    if (!xenInotifyActive(conn) && xenXMConfigCacheRefresh (conn) < 0)
D
Daniel P. Berrange 已提交
1321
        goto cleanup;
1322

D
Daniel P. Berrange 已提交
1323 1324 1325 1326 1327
    ret = virHashSize(priv->nameConfigMap);

cleanup:
    xenUnifiedUnlock(priv);
    return ret;
1328 1329
}

1330

1331
/**
1332
 * xenXMDomainAttachDeviceFlags:
1333 1334
 * @domain: pointer to domain object
 * @xml: pointer to XML description of device
1335
 * @flags: an OR'ed set of virDomainDeviceModifyFlags
J
Jim Meyering 已提交
1336
 *
1337 1338
 * Create a virtual device attachment to backend.
 * XML description is translated into config file.
1339 1340
 * This driver only supports device allocation to
 * persisted config.
J
Jim Meyering 已提交
1341
 *
1342 1343 1344
 * Returns 0 in case of success, -1 in case of failure.
 */
static int
1345 1346
xenXMDomainAttachDeviceFlags(virDomainPtr domain, const char *xml,
                             unsigned int flags) {
1347 1348
    const char *filename = NULL;
    xenXMConfCachePtr entry = NULL;
1349 1350
    int ret = -1;
    virDomainDeviceDefPtr dev = NULL;
1351
    virDomainDefPtr def;
1352
    xenUnifiedPrivatePtr priv;
1353 1354

    if ((!domain) || (!domain->conn) || (!domain->name) || (!xml)) {
1355
        xenXMError(VIR_ERR_INVALID_ARG, __FUNCTION__);
1356
        return -1;
1357
    }
1358

1359
    if (domain->conn->flags & VIR_CONNECT_RO)
1360
        return -1;
1361 1362 1363 1364 1365

    if ((flags & VIR_DOMAIN_DEVICE_MODIFY_LIVE) ||
        (domain->id != -1 && (flags & VIR_DOMAIN_DEVICE_MODIFY_CURRENT))) {
        xenXMError(VIR_ERR_OPERATION_INVALID, "%s",
                   _("Xm driver only supports modifying persistent config"));
1366
        return -1;
1367
    }
1368

D
Daniel P. Berrange 已提交
1369 1370 1371
    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
    xenUnifiedLock(priv);

1372
    if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
D
Daniel P. Berrange 已提交
1373
        goto cleanup;
1374
    if (!(entry = virHashLookup(priv->configCache, filename)))
D
Daniel P. Berrange 已提交
1375
        goto cleanup;
1376
    def = entry->def;
1377

1378
    if (!(dev = virDomainDeviceDefParse(priv->caps,
1379
                                        entry->def,
G
Guido Günther 已提交
1380
                                        xml, VIR_DOMAIN_XML_INACTIVE)))
D
Daniel P. Berrange 已提交
1381
        goto cleanup;
1382

1383 1384 1385
    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
    {
1386
        if (virDomainDiskInsert(def, dev->data.disk) < 0) {
1387
            virReportOOMError();
1388
            goto cleanup;
1389 1390
        }
        dev->data.disk = NULL;
1391
    }
1392
    break;
1393

1394 1395
    case VIR_DOMAIN_DEVICE_NET:
    {
1396
        if (VIR_REALLOC_N(def->nets, def->nnets+1) < 0) {
1397
            virReportOOMError();
1398 1399 1400
            goto cleanup;
        }
        def->nets[def->nnets++] = dev->data.net;
1401 1402
        dev->data.net = NULL;
        break;
1403 1404
    }

1405
    default:
1406 1407
        xenXMError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                   _("Xm driver only supports adding disk or network devices"));
1408 1409 1410 1411 1412 1413
        goto cleanup;
    }

    /* If this fails, should we try to undo our changes to the
     * in-memory representation of the config file. I say not!
     */
1414
    if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
1415 1416 1417 1418 1419
        goto cleanup;

    ret = 0;

 cleanup:
1420
    virDomainDeviceDefFree(dev);
D
Daniel P. Berrange 已提交
1421
    xenUnifiedUnlock(priv);
1422 1423 1424 1425 1426
    return ret;
}


/**
1427
 * xenXMDomainDetachDeviceFlags:
1428 1429
 * @domain: pointer to domain object
 * @xml: pointer to XML description of device
1430
 * @flags: an OR'ed set of virDomainDeviceModifyFlags
J
Jim Meyering 已提交
1431
 *
1432
 * Destroy a virtual device attachment to backend.
1433 1434
 * This driver only supports device deallocation from
 * persisted config.
1435 1436 1437 1438
 *
 * Returns 0 in case of success, -1 in case of failure.
 */
static int
1439 1440
xenXMDomainDetachDeviceFlags(virDomainPtr domain, const char *xml,
                             unsigned int flags) {
1441 1442
    const char *filename = NULL;
    xenXMConfCachePtr entry = NULL;
1443
    virDomainDeviceDefPtr dev = NULL;
1444
    virDomainDefPtr def;
1445
    int ret = -1;
1446
    int i;
1447
    xenUnifiedPrivatePtr priv;
1448 1449

    if ((!domain) || (!domain->conn) || (!domain->name) || (!xml)) {
1450
        xenXMError(VIR_ERR_INVALID_ARG, __FUNCTION__);
1451
        return -1;
1452
    }
1453 1454


1455
    if (domain->conn->flags & VIR_CONNECT_RO)
1456
        return -1;
1457 1458 1459 1460 1461

    if ((flags & VIR_DOMAIN_DEVICE_MODIFY_LIVE) ||
        (domain->id != -1 && (flags & VIR_DOMAIN_DEVICE_MODIFY_CURRENT))) {
        xenXMError(VIR_ERR_OPERATION_INVALID, "%s",
                   _("Xm driver only supports modifying persistent config"));
1462
        return -1;
1463
    }
D
Daniel P. Berrange 已提交
1464 1465 1466 1467

    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
    xenUnifiedLock(priv);

1468
    if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
D
Daniel P. Berrange 已提交
1469
        goto cleanup;
1470
    if (!(entry = virHashLookup(priv->configCache, filename)))
D
Daniel P. Berrange 已提交
1471
        goto cleanup;
1472
    def = entry->def;
1473

1474
    if (!(dev = virDomainDeviceDefParse(priv->caps,
1475
                                        entry->def,
G
Guido Günther 已提交
1476
                                        xml, VIR_DOMAIN_XML_INACTIVE)))
D
Daniel P. Berrange 已提交
1477
        goto cleanup;
1478

1479 1480 1481
    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
    {
1482 1483
        for (i = 0 ; i < def->ndisks ; i++) {
            if (def->disks[i]->dst &&
1484
                dev->data.disk->dst &&
1485 1486 1487 1488 1489
                STREQ(def->disks[i]->dst, dev->data.disk->dst)) {
                virDomainDiskDefFree(def->disks[i]);
                if (i < (def->ndisks - 1))
                    memmove(def->disks + i,
                            def->disks + i + 1,
1490 1491
                            sizeof(*def->disks) *
                            (def->ndisks - (i + 1)));
1492
                def->ndisks--;
1493
                break;
1494 1495
            }
        }
1496 1497 1498 1499 1500
        break;
    }

    case VIR_DOMAIN_DEVICE_NET:
    {
1501 1502 1503
        for (i = 0 ; i < def->nnets ; i++) {
            if (!memcmp(def->nets[i]->mac,
                        dev->data.net->mac,
1504
                        sizeof(def->nets[i]->mac))) {
1505 1506 1507 1508
                virDomainNetDefFree(def->nets[i]);
                if (i < (def->nnets - 1))
                    memmove(def->nets + i,
                            def->nets + i + 1,
1509 1510
                            sizeof(*def->nets) *
                            (def->nnets - (i + 1)));
1511
                def->nnets--;
1512 1513 1514 1515
                break;
            }
        }
        break;
1516
    }
1517
    default:
1518
        xenXMError(VIR_ERR_XML_ERROR,
J
Jim Meyering 已提交
1519
                   "%s", _("unknown device"));
1520 1521 1522 1523 1524 1525
        goto cleanup;
    }

    /* If this fails, should we try to undo our changes to the
     * in-memory representation of the config file. I say not!
     */
1526
    if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
1527 1528 1529 1530 1531
        goto cleanup;

    ret = 0;

 cleanup:
1532
    virDomainDeviceDefFree(dev);
D
Daniel P. Berrange 已提交
1533
    xenUnifiedUnlock(priv);
1534 1535 1536
    return (ret);
}

R
Richard W.M. Jones 已提交
1537
int
1538
xenXMDomainBlockPeek (virDomainPtr dom ATTRIBUTE_UNUSED,
R
Richard W.M. Jones 已提交
1539 1540 1541 1542 1543
                      const char *path ATTRIBUTE_UNUSED,
                      unsigned long long offset ATTRIBUTE_UNUSED,
                      size_t size ATTRIBUTE_UNUSED,
                      void *buffer ATTRIBUTE_UNUSED)
{
1544
    xenXMError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
R
Richard W.M. Jones 已提交
1545 1546 1547
    return -1;
}

1548 1549 1550 1551

static char *xenXMAutostartLinkName(virDomainPtr dom)
{
    char *ret;
1552 1553
    if (virAsprintf(&ret, "/etc/xen/auto/%s", dom->name) < 0)
        return NULL;
1554 1555 1556 1557 1558 1559
    return ret;
}

static char *xenXMDomainConfigName(virDomainPtr dom)
{
    char *ret;
1560 1561
    if (virAsprintf(&ret, "/etc/xen/%s", dom->name) < 0)
        return NULL;
1562 1563 1564 1565 1566 1567 1568 1569 1570 1571
    return ret;
}

int xenXMDomainGetAutostart(virDomainPtr dom, int *autostart)
{
    char *linkname = xenXMAutostartLinkName(dom);
    char *config = xenXMDomainConfigName(dom);
    int ret = -1;

    if (!linkname || !config) {
1572
        virReportOOMError();
1573 1574 1575 1576 1577
        goto cleanup;
    }

    *autostart = virFileLinkPointsTo(linkname, config);
    if (*autostart < 0) {
1578
        virReportSystemError(errno,
1579 1580
                             _("cannot check link %s points to config %s"),
                             linkname, config);
1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599
        goto cleanup;
    }

    ret = 0;

cleanup:
    VIR_FREE(linkname);
    VIR_FREE(config);
    return ret;
}


int xenXMDomainSetAutostart(virDomainPtr dom, int autostart)
{
    char *linkname = xenXMAutostartLinkName(dom);
    char *config = xenXMDomainConfigName(dom);
    int ret = -1;

    if (!linkname || !config) {
1600
        virReportOOMError();
1601 1602 1603 1604 1605 1606
        goto cleanup;
    }

    if (autostart) {
        if (symlink(config, linkname) < 0 &&
            errno != EEXIST) {
1607
            virReportSystemError(errno,
1608 1609
                                 _("failed to create link %s to %s"),
                                 config, linkname);
1610 1611 1612 1613 1614
            goto cleanup;
        }
    } else {
        if (unlink(linkname)  < 0 &&
            errno != ENOENT) {
1615
            virReportSystemError(errno,
1616 1617
                                 _("failed to remove link %s"),
                                 linkname);
1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628
            goto cleanup;
        }
    }
    ret = 0;

cleanup:
    VIR_FREE(linkname);
    VIR_FREE(config);

    return ret;
}