xm_internal.c 45.0 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 142 143

/* Release memory associated with a cached config object */
static void xenXMConfigFree(void *payload, const char *key ATTRIBUTE_UNUSED) {
    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 154
/* Remove any configs which were not refreshed recently */
static int xenXMConfigReaper(const void *payload, const char *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 361 362 363 364 365 366 367
        return (-1);
    }

    while ((ent = readdir(dh))) {
        struct stat st;
        char path[PATH_MAX];

        /*
         * 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
        if ((strlen(priv->configDir) + 1 + strlen(ent->d_name) + 1) > PATH_MAX)
391
            continue;
392
        strcpy(path, priv->configDir);
393 394 395 396 397 398 399 400 401 402 403
        strcat(path, "/");
        strcat(path, ent->d_name);

        /* Skip anything which isn't a file (takes care of scripts/ subdir */
        if ((stat(path, &st) < 0) ||
            (!S_ISREG(st.st_mode))) {
            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 409 410 411 412
    }

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

418
    closedir(dh);
419 420 421 422 423 424

    return (ret);
}


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

    priv->configDir = XM_CONFIG_DIR;

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

    return (0);
}

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

463 464
    virHashFree(priv->nameConfigMap);
    virHashFree(priv->configCache);
465

466 467 468 469 470
    return (0);
}

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

482
    if (domain->id != -1)
483 484
        return (-1);

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

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

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

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

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

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


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

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

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

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

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

536
    ret = virDomainDefFormat(entry->def, flags);
537

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


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

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

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

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

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

573 574 575
    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;
576 577 578 579

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

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

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

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

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

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

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

616 617 618
    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;
619 620 621 622

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

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

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

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

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

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

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

657
    ret = entry->def->mem.max_balloon;
658

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

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

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

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

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

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

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

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

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

854 855
                if (comma)
                    virBufferAddLit (&mapbuf, ",");
856 857
                comma = 1;

858
                virBufferVSprintf (&mapbuf, "%d", n);
859 860
            }

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

    mapstr = virBufferContentAndReset(&mapbuf);
868
    mapsave = mapstr;
869

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

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

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

    ret = 0;

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

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

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

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

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

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

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

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

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

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


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

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

    return (0);
}

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

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

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

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

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

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

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

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


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

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

1003
    if (domain->id != -1)
1004 1005
        return (-1);

D
Daniel P. Berrange 已提交
1006 1007
    xenUnifiedLock(priv);

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

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

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

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

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

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

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

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

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

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

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

D
Daniel P. Berrange 已提交
1068 1069
    xenUnifiedLock(priv);

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

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

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

1101
    if (virHashLookup(priv->nameConfigMap, def->name)) {
1102 1103
        /* domain exists, we will overwrite it */

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

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

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

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

        entry = NULL;
1131
    }
1132

1133
    if ((strlen(priv->configDir) + 1 + strlen(def->name) + 1) > PATH_MAX) {
1134
        xenXMError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1135
                   "%s", _("config file name is too long"));
1136
        goto error;
1137
    }
1138

1139
    strcpy(filename, priv->configDir);
1140
    strcat(filename, "/");
1141
    strcat(filename, def->name);
1142

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1332

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

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

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

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

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

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

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

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

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

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

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

    ret = 0;

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


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

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


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

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

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

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

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

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

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

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

    ret = 0;

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

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

1550 1551 1552 1553

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

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

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

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

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

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

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

    return ret;
}