xm_internal.c 44.9 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 124
#define xenXMError(code, ...)                                              \
        virReportErrorHelper(NULL, 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 394
        if (!(path = virFileBuildPath(priv->configDir, ent->d_name, NULL))) {
            virReportOOMError();
            closedir(dh);
            return -1;
        }
395 396 397 398

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

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

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

    /* 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 */
416 417
    args.now = now;
    args.priv = priv;
418
    virHashRemoveSet(priv->configCache, xenXMConfigReaper, &args);
419 420
    ret = 0;

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

    return (ret);
}


/*
428 429 430 431
 * 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
432
 */
433
virDrvOpenStatus
434
xenXMOpen (virConnectPtr conn,
435 436
           virConnectAuthPtr auth ATTRIBUTE_UNUSED,
           int flags ATTRIBUTE_UNUSED)
437
{
438 439 440 441
    xenUnifiedPrivatePtr priv = conn->privateData;

    priv->configDir = XM_CONFIG_DIR;

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

    return (0);
}

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

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

469 470 471 472 473
    return (0);
}

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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


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

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

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

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

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

576 577 578
    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;
579 580 581 582

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

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

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

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

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

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

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

619 620 621
    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;
622 623 624 625

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

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

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

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

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

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

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

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

D
Daniel P. Berrange 已提交
662 663 664
cleanup:
    xenUnifiedUnlock(priv);
    return ret;
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 738
/*
 * 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
739 740
     * in-memory representation of the config file. I say not!
     */
741
    if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
D
Daniel P. Berrange 已提交
742 743
        goto cleanup;
    ret = 0;
744

D
Daniel P. Berrange 已提交
745 746 747
cleanup:
    xenUnifiedUnlock(priv);
    return ret;
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 796
/**
 * 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;
}

797 798 799 800 801 802 803 804 805 806 807 808 809 810 811
/**
 * 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)
{
812
    xenUnifiedPrivatePtr priv;
813 814
    const char *filename;
    xenXMConfCachePtr entry;
815
    virBuffer mapbuf = VIR_BUFFER_INITIALIZER;
816
    char *mapstr = NULL, *mapsave = NULL;
817 818
    int i, j, n, comma = 0;
    int ret = -1;
819 820
    char *cpuset = NULL;
    int maxcpu = XEN_MAX_PHYSICAL_CPU;
821 822 823

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

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

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

    /* 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;

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

861
                virBufferVSprintf (&mapbuf, "%d", n);
862 863
            }

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

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

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

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

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

    ret = 0;

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

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

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

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

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

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

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

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

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

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


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

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

    return (0);
}

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095
    /*
     * 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);
1096
            xenXMError(VIR_ERR_OPERATION_FAILED,
1097 1098 1099 1100 1101 1102 1103 1104
                       _("domain '%s' is already defined with uuid %s"),
                       entry->def->name, uuidstr);
            entry = NULL;
            goto error;
        }
        entry = NULL;
    }

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

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

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

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

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

        entry = NULL;
1135
    }
1136

1137 1138
    if (!(filename = virFileBuildPath(priv->configDir, def->name, NULL))) {
        virReportOOMError();
1139
        goto error;
1140
    }
1141

1142
    if (xenXMConfigSaveFile(conn, filename, def) < 0)
1143 1144
        goto error;

1145
    if (VIR_ALLOC(entry) < 0) {
1146
        virReportOOMError();
1147
        goto error;
1148
    }
1149

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

    memmove(entry->filename, filename, PATH_MAX);
1157
    entry->def = def;
1158

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

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

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

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

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

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

1199
    if (domain->id != -1)
1200 1201 1202 1203
        return (-1);
    if (domain->conn->flags & VIR_CONNECT_RO)
        return (-1);

1204
    priv = domain->conn->privateData;
D
Daniel P. Berrange 已提交
1205
    xenUnifiedLock(priv);
1206 1207

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

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

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

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

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

D
Daniel P. Berrange 已提交
1224 1225 1226 1227 1228
    ret = 0;

cleanup:
    xenUnifiedUnlock(priv);
    return ret;
1229 1230 1231 1232
}

struct xenXMListIteratorContext {
    virConnectPtr conn;
1233
    int oom;
1234 1235
    int max;
    int count;
1236
    char ** names;
1237 1238
};

1239
static void xenXMListIterator(void *payload ATTRIBUTE_UNUSED, const void *name, void *data) {
1240
    struct xenXMListIteratorContext *ctx = data;
1241 1242
    virDomainPtr dom = NULL;

1243 1244 1245
    if (ctx->oom)
        return;

1246 1247 1248
    if (ctx->count == ctx->max)
        return;

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


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

    if (!VIR_IS_CONNECT(conn)) {
1271
        xenXMError(VIR_ERR_INVALID_CONN, __FUNCTION__);
1272 1273 1274
        return (-1);
    }

1275
    priv = conn->privateData;
D
Daniel P. Berrange 已提交
1276
    xenUnifiedLock(priv);
1277

1278
    if (!xenInotifyActive(conn) && xenXMConfigCacheRefresh (conn) < 0)
D
Daniel P. Berrange 已提交
1279
        goto cleanup;
1280

1281 1282
    if (maxnames > virHashSize(priv->configCache))
        maxnames = virHashSize(priv->configCache);
1283 1284

    ctx.conn = conn;
1285
    ctx.oom = 0;
1286 1287 1288 1289
    ctx.count = 0;
    ctx.max = maxnames;
    ctx.names = names;

1290
    virHashForEach(priv->nameConfigMap, xenXMListIterator, &ctx);
1291 1292 1293 1294 1295

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

1296
        virReportOOMError();
1297 1298 1299
        goto cleanup;
    }

D
Daniel P. Berrange 已提交
1300 1301 1302 1303 1304
    ret = ctx.count;

cleanup:
    xenUnifiedUnlock(priv);
    return ret;
1305 1306 1307 1308 1309 1310 1311
}

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

1315
    if (!VIR_IS_CONNECT(conn)) {
1316
        xenXMError(VIR_ERR_INVALID_CONN, __FUNCTION__);
1317 1318 1319
        return (-1);
    }

1320
    priv = conn->privateData;
D
Daniel P. Berrange 已提交
1321
    xenUnifiedLock(priv);
1322

1323
    if (!xenInotifyActive(conn) && xenXMConfigCacheRefresh (conn) < 0)
D
Daniel P. Berrange 已提交
1324
        goto cleanup;
1325

D
Daniel P. Berrange 已提交
1326 1327 1328 1329 1330
    ret = virHashSize(priv->nameConfigMap);

cleanup:
    xenUnifiedUnlock(priv);
    return ret;
1331 1332
}

1333

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

    if ((!domain) || (!domain->conn) || (!domain->name) || (!xml)) {
1358
        xenXMError(VIR_ERR_INVALID_ARG, __FUNCTION__);
1359
        return -1;
1360
    }
1361

1362
    if (domain->conn->flags & VIR_CONNECT_RO)
1363
        return -1;
1364 1365 1366 1367 1368

    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"));
1369
        return -1;
1370
    }
1371

D
Daniel P. Berrange 已提交
1372 1373 1374
    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
    xenUnifiedLock(priv);

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

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

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

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

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

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

    ret = 0;

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


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

    if ((!domain) || (!domain->conn) || (!domain->name) || (!xml)) {
1453
        xenXMError(VIR_ERR_INVALID_ARG, __FUNCTION__);
1454
        return -1;
1455
    }
1456 1457


1458
    if (domain->conn->flags & VIR_CONNECT_RO)
1459
        return -1;
1460 1461 1462 1463 1464

    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"));
1465
        return -1;
1466
    }
D
Daniel P. Berrange 已提交
1467 1468 1469 1470

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

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

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

1482 1483 1484
    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
    {
1485 1486
        for (i = 0 ; i < def->ndisks ; i++) {
            if (def->disks[i]->dst &&
1487
                dev->data.disk->dst &&
1488 1489 1490 1491 1492
                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,
1493 1494
                            sizeof(*def->disks) *
                            (def->ndisks - (i + 1)));
1495
                def->ndisks--;
1496
                break;
1497 1498
            }
        }
1499 1500 1501 1502 1503
        break;
    }

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

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

    ret = 0;

 cleanup:
1535
    virDomainDeviceDefFree(dev);
D
Daniel P. Berrange 已提交
1536
    xenUnifiedUnlock(priv);
1537 1538 1539
    return (ret);
}

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

1551 1552 1553 1554

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

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

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

    if (!linkname || !config) {
1575
        virReportOOMError();
1576 1577 1578 1579 1580
        goto cleanup;
    }

    *autostart = virFileLinkPointsTo(linkname, config);
    if (*autostart < 0) {
1581
        virReportSystemError(errno,
1582 1583
                             _("cannot check link %s points to config %s"),
                             linkname, config);
1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602
        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) {
1603
        virReportOOMError();
1604 1605 1606 1607 1608 1609
        goto cleanup;
    }

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

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

    return ret;
}