xm_internal.c 41.8 KB
Newer Older
1 2 3
/*
 * xm_internal.h: helper routines for dealing with inactive domains
 *
4
 * Copyright (C) 2006-2007, 2009-2013 Red Hat, Inc.
5
 * Copyright (C) 2006 Daniel P. Berrange
6
 *
7 8 9 10 11 12 13 14 15 16 17
 * 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
18
 * License along with this library.  If not, see
O
Osier Yang 已提交
19
 * <http://www.gnu.org/licenses/>.
20 21
 *
 * 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 "virerror.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 "virhash.h"
46
#include "virbuffer.h"
47
#include "viruuid.h"
48
#include "virutil.h"
49
#include "viralloc.h"
50
#include "virlog.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 = {
E
Eric Blake 已提交
84 85 86 87 88 89 90 91 92 93 94 95 96
    .xenClose = xenXMClose,
    .xenDomainGetMaxMemory = xenXMDomainGetMaxMemory,
    .xenDomainSetMaxMemory = xenXMDomainSetMaxMemory,
    .xenDomainSetMemory = xenXMDomainSetMemory,
    .xenDomainGetInfo = xenXMDomainGetInfo,
    .xenDomainPinVcpu = xenXMDomainPinVcpu,
    .xenListDefinedDomains = xenXMListDefinedDomains,
    .xenNumOfDefinedDomains = xenXMNumOfDefinedDomains,
    .xenDomainCreate = xenXMDomainCreate,
    .xenDomainDefineXML = xenXMDomainDefineXML,
    .xenDomainUndefine = xenXMDomainUndefine,
    .xenDomainAttachDeviceFlags = xenXMDomainAttachDeviceFlags,
    .xenDomainDetachDeviceFlags = xenXMDomainDetachDeviceFlags,
97 98
};

99
#ifndef WITH_XEN_INOTIFY
100 101 102 103
static int xenInotifyActive(virConnectPtr conn ATTRIBUTE_UNUSED)
{
   return 0;
}
104
#else
105 106
static int xenInotifyActive(virConnectPtr conn)
{
107
   xenUnifiedPrivatePtr priv = conn->privateData;
108
   return priv->inotifyWatch > 0;
109
}
110
#endif
111

112 113

/* Release memory associated with a cached config object */
114
static void xenXMConfigFree(void *payload, const void *key ATTRIBUTE_UNUSED) {
115
    xenXMConfCachePtr entry = (xenXMConfCachePtr)payload;
116
    virDomainDefFree(entry->def);
E
Eric Blake 已提交
117
    VIR_FREE(entry->filename);
118
    VIR_FREE(entry);
119 120
}

121 122 123 124
struct xenXMConfigReaperData {
    xenUnifiedPrivatePtr priv;
    time_t now;
};
125

126
/* Remove any configs which were not refreshed recently */
127 128 129 130 131
static int
xenXMConfigReaper(const void *payload,
                  const void *key ATTRIBUTE_UNUSED,
                  const void *data)
{
132
    const struct xenXMConfigReaperData *args = data;
133 134
    xenXMConfCachePtr entry = (xenXMConfCachePtr)payload;

135 136
    /* We're going to purge this config file, so check if it
       is currently mapped as owner of a named domain. */
137
    if (entry->refreshedAt != args->now) {
138
        const char *olddomname = entry->def->name;
139
        char *nameowner = (char *)virHashLookup(args->priv->nameConfigMap, olddomname);
140
        if (nameowner && STREQ(nameowner, key)) {
141
            virHashRemoveEntry(args->priv->nameConfigMap, olddomname);
142
        }
143
        return 1;
144
    }
145
    return 0;
146 147
}

148 149

static virDomainDefPtr
150 151
xenXMConfigReadFile(virConnectPtr conn, const char *filename)
{
152 153
    virConfPtr conf;
    virDomainDefPtr def;
154
    xenUnifiedPrivatePtr priv = conn->privateData;
155

156
    if (!(conf = virConfReadFile(filename, 0)))
157 158
        return NULL;

M
Markus Groß 已提交
159
    def = xenParseXM(conf, priv->xendConfigVersion, priv->caps);
160 161 162 163 164 165
    virConfFree(conf);

    return def;
}

static int
166 167 168 169
xenXMConfigSaveFile(virConnectPtr conn,
                    const char *filename,
                    virDomainDefPtr def)
{
170
    virConfPtr conf;
171
    xenUnifiedPrivatePtr priv = conn->privateData;
172 173
    int ret;

M
Markus Groß 已提交
174
    if (!(conf = xenFormatXM(conn, def, priv->xendConfigVersion)))
175 176 177 178 179 180 181
        return -1;

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

D
Daniel P. Berrange 已提交
182 183 184

/*
 * Caller must hold the lock on 'conn->privateData' before
J
Ján Tomko 已提交
185
 * calling this function
D
Daniel P. Berrange 已提交
186
 */
187
int
188
xenXMConfigCacheRemoveFile(virConnectPtr conn, const char *filename)
189
{
190
    xenUnifiedPrivatePtr priv = conn->privateData;
191 192
    xenXMConfCachePtr entry;

193
    entry = virHashLookup(priv->configCache, filename);
194
    if (!entry) {
195
        VIR_DEBUG("No config entry for %s", filename);
196 197 198
        return 0;
    }

199 200
    virHashRemoveEntry(priv->nameConfigMap, entry->def->name);
    virHashRemoveEntry(priv->configCache, filename);
201
    VIR_DEBUG("Removed %s %s", entry->def->name, filename);
202 203 204 205
    return 0;
}


D
Daniel P. Berrange 已提交
206 207
/*
 * Caller must hold the lock on 'conn->privateData' before
J
Ján Tomko 已提交
208
 * calling this function
D
Daniel P. Berrange 已提交
209
 */
210 211 212
int
xenXMConfigCacheAddFile(virConnectPtr conn, const char *filename)
{
213
    xenUnifiedPrivatePtr priv = conn->privateData;
214 215 216 217 218
    xenXMConfCachePtr entry;
    struct stat st;
    int newborn = 0;
    time_t now = time(NULL);

219
    VIR_DEBUG("Adding file %s", filename);
220 221 222

    /* Get modified time */
    if ((stat(filename, &st) < 0)) {
223
        virReportSystemError(errno,
224 225
                             _("cannot stat: %s"),
                             filename);
226 227 228 229 230 231
        return -1;
    }

    /* Ignore zero length files, because inotify fires before
       any content has actually been created */
    if (st.st_size == 0) {
232
        VIR_DEBUG("Ignoring zero length file %s", filename);
233 234 235 236 237
        return -1;
    }

    /* If we already have a matching entry and it is not
    modified, then carry on to next one*/
238
    if ((entry = virHashLookup(priv->configCache, filename))) {
239 240 241 242 243 244 245 246 247 248
        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 */
249
        nameowner = (char *)virHashLookup(priv->nameConfigMap, entry->def->name);
250
        if (nameowner && STREQ(nameowner, filename)) {
251
            virHashRemoveEntry(priv->nameConfigMap, entry->def->name);
252 253 254 255 256 257 258 259
        }

        /* Clear existing config entry which needs refresh */
        virDomainDefFree(entry->def);
        entry->def = NULL;
    } else { /* Completely new entry */
        newborn = 1;
        if (VIR_ALLOC(entry) < 0) {
260
            virReportOOMError();
261 262
            return -1;
        }
E
Eric Blake 已提交
263 264 265 266 267
        if ((entry->filename = strdup(filename)) == NULL) {
            virReportOOMError();
            VIR_FREE(entry);
            return -1;
        }
268 269 270 271
    }
    entry->refreshedAt = now;

    if (!(entry->def = xenXMConfigReadFile(conn, entry->filename))) {
272
        VIR_DEBUG("Failed to read %s", entry->filename);
273
        if (!newborn)
274
            virHashSteal(priv->configCache, filename);
E
Eric Blake 已提交
275
        VIR_FREE(entry->filename);
276 277 278 279 280 281 282
        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) {
283
        if (virHashAddEntry(priv->configCache, entry->filename, entry) < 0) {
284
            virDomainDefFree(entry->def);
E
Eric Blake 已提交
285
            VIR_FREE(entry->filename);
286
            VIR_FREE(entry);
287 288
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("xenXMConfigCacheRefresh: virHashAddEntry"));
289 290 291 292 293 294 295
            return -1;
        }
    }

    /* See if we need to map this config file in as the primary owner
        * of the domain in question
        */
296
    if (!virHashLookup(priv->nameConfigMap, entry->def->name)) {
E
Eric Blake 已提交
297 298
        if (virHashAddEntry(priv->nameConfigMap, entry->def->name,
                            entry->filename) < 0) {
299
            virHashSteal(priv->configCache, filename);
300
            virDomainDefFree(entry->def);
E
Eric Blake 已提交
301
            VIR_FREE(entry->filename);
302 303 304
            VIR_FREE(entry);
        }
    }
305
    VIR_DEBUG("Added config %s %s", entry->def->name, filename);
306 307 308

    return 0;
}
309

310
/* This method is called by various methods to scan /etc/xen
D
Daniel P. Berrange 已提交
311 312 313 314 315 316
 * (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
J
Ján Tomko 已提交
317
 * calling this function
D
Daniel P. Berrange 已提交
318
 */
319 320 321
int
xenXMConfigCacheRefresh(virConnectPtr conn)
{
322
    xenUnifiedPrivatePtr priv = conn->privateData;
323 324 325 326
    DIR *dh;
    struct dirent *ent;
    time_t now = time(NULL);
    int ret = -1;
327
    struct xenXMConfigReaperData args;
328 329

    if (now == ((time_t)-1)) {
330
        virReportSystemError(errno,
331
                             "%s", _("cannot get time of day"));
332
        return -1;
333 334 335
    }

    /* Rate limit re-scans */
336
    if ((now - priv->lastRefresh) < XM_REFRESH_INTERVAL)
337
        return 0;
338

339
    priv->lastRefresh = now;
340 341

    /* Process the files in the config dir */
342
    if (!(dh = opendir(priv->configDir))) {
343
        virReportSystemError(errno,
344
                             _("cannot read directory %s"),
345
                             priv->configDir);
346
        return -1;
347 348 349 350
    }

    while ((ent = readdir(dh))) {
        struct stat st;
351
        char *path;
352 353 354 355 356 357

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

        /* Like 'dot' files... */
358
        if (STRPREFIX(ent->d_name, "."))
359 360
            continue;
        /* ...and the XenD server config file */
361
        if (STRPREFIX(ent->d_name, XEND_CONFIG_FILE))
362 363
            continue;
        /* ...and random PCI config cruft */
364
        if (STRPREFIX(ent->d_name, XEND_PCI_CONFIG_PREFIX))
365 366
            continue;
        /* ...and the example domain configs */
367
        if (STRPREFIX(ent->d_name, XM_EXAMPLE_PREFIX))
368 369
            continue;
        /* ...and the QEMU networking script */
370
        if (STRPREFIX(ent->d_name, QEMU_IF_SCRIPT))
371 372 373 374 375 376 377 378 379
            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 */
380 381 382 383
        if (!(path = virFileBuildPath(priv->configDir, ent->d_name, NULL))) {
            closedir(dh);
            return -1;
        }
384 385 386 387

        /* Skip anything which isn't a file (takes care of scripts/ subdir */
        if ((stat(path, &st) < 0) ||
            (!S_ISREG(st.st_mode))) {
388
            VIR_FREE(path);
389 390 391 392 393
            continue;
        }

        /* If we already have a matching entry and it is not
           modified, then carry on to next one*/
394
        if (xenXMConfigCacheAddFile(conn, path) < 0) {
J
Ján Tomko 已提交
395
            /* Ignoring errors, since a lot of stuff goes wrong in /etc/xen */
396
        }
397 398

        VIR_FREE(path);
399 400 401 402 403 404
    }

    /* 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 */
405 406
    args.now = now;
    args.priv = priv;
407
    virHashRemoveSet(priv->configCache, xenXMConfigReaper, &args);
408 409
    ret = 0;

410
    closedir(dh);
411

412
    return ret;
413 414 415 416
}


/*
417 418 419 420
 * 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
421
 */
422
virDrvOpenStatus
423 424 425
xenXMOpen(virConnectPtr conn,
          virConnectAuthPtr auth ATTRIBUTE_UNUSED,
          unsigned int flags)
426
{
427 428
    xenUnifiedPrivatePtr priv = conn->privateData;

E
Eric Blake 已提交
429 430
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

431 432
    priv->configDir = XM_CONFIG_DIR;

433
    priv->configCache = virHashCreate(50, xenXMConfigFree);
434
    if (!priv->configCache)
435
        return -1;
436
    priv->nameConfigMap = virHashCreate(50, NULL);
437
    if (!priv->nameConfigMap) {
438
        virHashFree(priv->configCache);
439
        priv->configCache = NULL;
440
        return -1;
441
    }
442 443 444 445
    /* Force the cache to be reloaded next time that
     * xenXMConfigCacheRefresh is called.
     */
    priv->lastRefresh = 0;
446

447
    return 0;
448 449 450
}

/*
451 452
 * Free the cached config files associated with this
 * connection
453
 */
454 455 456
int
xenXMClose(virConnectPtr conn)
{
457 458
    xenUnifiedPrivatePtr priv = conn->privateData;

459 460
    virHashFree(priv->nameConfigMap);
    virHashFree(priv->configCache);
461

462
    return 0;
463 464
}

465 466 467 468 469
/*
 * Since these are all offline domains, the state is always SHUTOFF.
 */
int
xenXMDomainGetState(virDomainPtr domain,
470
                    int *state, int *reason,
E
Eric Blake 已提交
471
                    unsigned int flags)
472
{
E
Eric Blake 已提交
473 474
    virCheckFlags(0, -1);

475 476 477 478 479 480 481 482 483 484 485
    if (domain->id != -1)
        return -1;

    *state = VIR_DOMAIN_SHUTOFF;
    if (reason)
        *reason = 0;

    return 0;
}


486 487
/*
 * Since these are all offline domains, we only return info about
488
 * VCPUs and memory.
489
 */
490 491 492 493
int
xenXMDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
{
    xenUnifiedPrivatePtr priv = domain->conn->privateData;
494
    const char *filename;
495 496
    xenXMConfCachePtr entry;

497
    if (domain->id != -1)
498
        return -1;
499

D
Daniel P. Berrange 已提交
500
    xenUnifiedLock(priv);
501 502

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

505
    if (!(entry = virHashLookup(priv->configCache, filename)))
D
Daniel P. Berrange 已提交
506
        goto error;
507 508

    memset(info, 0, sizeof(virDomainInfo));
509 510
    info->maxMem = entry->def->mem.max_balloon;
    info->memory = entry->def->mem.cur_balloon;
511
    info->nrVirtCpu = entry->def->vcpus;
512 513 514
    info->state = VIR_DOMAIN_SHUTOFF;
    info->cpuTime = 0;

D
Daniel P. Berrange 已提交
515
    xenUnifiedUnlock(priv);
516
    return 0;
517

D
Daniel P. Berrange 已提交
518 519 520
error:
    xenUnifiedUnlock(priv);
    return -1;
521 522 523
}


524 525
/*
 * Turn a config record into a lump of XML describing the
526
 * domain, suitable for later feeding for virDomainCreateXML
527
 */
528 529
char *
xenXMDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
E
Eric Blake 已提交
530
{
531
    xenUnifiedPrivatePtr priv = domain->conn->privateData;
532 533
    const char *filename;
    xenXMConfCachePtr entry;
D
Daniel P. Berrange 已提交
534
    char *ret = NULL;
535

E
Eric Blake 已提交
536 537
    /* Flags checked by virDomainDefFormat */

538
    if (domain->id != -1)
539
        return NULL;
540

D
Daniel P. Berrange 已提交
541
    xenUnifiedLock(priv);
542 543

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

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

549
    ret = virDomainDefFormat(entry->def, flags);
550

D
Daniel P. Berrange 已提交
551 552 553
cleanup:
    xenUnifiedUnlock(priv);
    return ret;
554 555 556
}


557 558 559
/*
 * Update amount of memory in the config file
 */
560 561 562 563
int
xenXMDomainSetMemory(virDomainPtr domain, unsigned long memory)
{
    xenUnifiedPrivatePtr priv = domain->conn->privateData;
564
    const char *filename;
565
    xenXMConfCachePtr entry;
D
Daniel P. Berrange 已提交
566
    int ret = -1;
567

568 569
    if (domain->conn->flags & VIR_CONNECT_RO || domain->id != -1 ||
        memory < 1024 * MIN_XEN_GUEST_SIZE)
570
        return -1;
571

D
Daniel P. Berrange 已提交
572
    xenUnifiedLock(priv);
573 574

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

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

580 581 582
    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;
583 584 585 586

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

D
Daniel P. Berrange 已提交
591 592 593
cleanup:
    xenUnifiedUnlock(priv);
    return ret;
594 595 596 597 598
}

/*
 * Update maximum memory limit in config
 */
599 600 601 602
int
xenXMDomainSetMaxMemory(virDomainPtr domain, unsigned long memory)
{
    xenUnifiedPrivatePtr priv = domain->conn->privateData;
603
    const char *filename;
604
    xenXMConfCachePtr entry;
D
Daniel P. Berrange 已提交
605
    int ret = -1;
606

607
    if (domain->conn->flags & VIR_CONNECT_RO || domain->id != -1)
608
        return -1;
609

D
Daniel P. Berrange 已提交
610
    xenUnifiedLock(priv);
611 612

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

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

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

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

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

/*
 * Get max memory limit from config
 */
637 638 639 640
unsigned long long
xenXMDomainGetMaxMemory(virDomainPtr domain)
{
    xenUnifiedPrivatePtr priv = domain->conn->privateData;
641
    const char *filename;
642
    xenXMConfCachePtr entry;
643
    unsigned long long ret = 0;
644

645
    if (domain->id != -1)
646
        return 0;
647

D
Daniel P. Berrange 已提交
648
    xenUnifiedLock(priv);
649 650

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

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

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

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

663 664 665 666 667 668 669 670 671 672 673 674
/*
 * 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
675 676
xenXMDomainSetVcpusFlags(virDomainPtr domain,
                         unsigned int vcpus,
677 678
                         unsigned int flags)
{
679
    xenUnifiedPrivatePtr priv = domain->conn->privateData;
680 681 682 683 684
    const char *filename;
    xenXMConfCachePtr entry;
    int ret = -1;
    int max;

E
Eric Blake 已提交
685 686 687 688
    virCheckFlags(VIR_DOMAIN_VCPU_LIVE |
                  VIR_DOMAIN_VCPU_CONFIG |
                  VIR_DOMAIN_VCPU_MAXIMUM, -1);

689
    if (domain->conn->flags & VIR_CONNECT_RO) {
690
        virReportError(VIR_ERR_OPERATION_DENIED, __FUNCTION__);
691 692 693 694 695
        return -1;
    }
    if (domain->id != -1)
        return -2;
    if (flags & VIR_DOMAIN_VCPU_LIVE) {
696 697
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not running"));
698 699 700 701 702 703 704 705 706 707 708 709
        return -1;
    }

    xenUnifiedLock(priv);

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

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

    /* Hypervisor maximum. */
710
    if ((max = xenUnifiedConnectGetMaxVcpus(domain->conn, NULL)) < 0) {
711 712
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not determine max vcpus for the domain"));
713 714 715 716 717 718 719
        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) {
720 721 722
        virReportError(VIR_ERR_INVALID_ARG,
                       _("requested vcpus is greater than max allowable"
                         " vcpus for the domain: %d > %d"), vcpus, max);
723 724 725 726 727 728 729 730 731 732 733 734
        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
735 736
     * in-memory representation of the config file. I say not!
     */
737
    if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
D
Daniel P. Berrange 已提交
738 739
        goto cleanup;
    ret = 0;
740

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

746 747 748 749 750 751 752 753 754 755 756 757 758
/**
 * 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)
{
759
    xenUnifiedPrivatePtr priv = domain->conn->privateData;
760 761 762 763
    const char *filename;
    xenXMConfCachePtr entry;
    int ret = -2;

E
Eric Blake 已提交
764 765 766 767
    virCheckFlags(VIR_DOMAIN_VCPU_LIVE |
                  VIR_DOMAIN_VCPU_CONFIG |
                  VIR_DOMAIN_VCPU_MAXIMUM, -1);

768 769 770
    if (domain->id != -1)
        return -2;
    if (flags & VIR_DOMAIN_VCPU_LIVE) {
771
        virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("domain not active"));
772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790
        return -1;
    }

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

791 792 793 794 795 796 797 798 799 800 801
/**
 * 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
 */
802 803 804 805 806
int
xenXMDomainPinVcpu(virDomainPtr domain,
                   unsigned int vcpu ATTRIBUTE_UNUSED,
                   unsigned char *cpumap,
                   int maplen)
807
{
808
    xenUnifiedPrivatePtr priv = domain->conn->privateData;
809 810 811 812
    const char *filename;
    xenXMConfCachePtr entry;
    int ret = -1;

813
    if (maplen > (int)sizeof(cpumap_t)) {
814
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
815 816 817
        return -1;
    }
    if (domain->conn->flags & VIR_CONNECT_RO) {
818 819
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("read only connection"));
820 821 822
        return -1;
    }
    if (domain->id != -1) {
823 824
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("not inactive domain"));
825 826 827
        return -1;
    }

D
Daniel P. Berrange 已提交
828
    xenUnifiedLock(priv);
829 830

    if (!(filename = virHashLookup(priv->nameConfigMap, domain->name))) {
831
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("virHashLookup"));
D
Daniel P. Berrange 已提交
832
        goto cleanup;
833
    }
834
    if (!(entry = virHashLookup(priv->configCache, filename))) {
835 836
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("can't retrieve config file for domain"));
D
Daniel P. Berrange 已提交
837
        goto cleanup;
838 839
    }

H
Hu Tao 已提交
840
    virBitmapFree(entry->def->cpumask);
L
liguang 已提交
841 842 843
    entry->def->cpumask = virBitmapNewData(cpumap, maplen);
    if (!entry->def->cpumask)
        goto cleanup;
844
    if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
845 846 847 848 849
        goto cleanup;

    ret = 0;

 cleanup:
D
Daniel P. Berrange 已提交
850
    xenUnifiedUnlock(priv);
851
    return ret;
852 853
}

854 855 856
/*
 * Find an inactive domain based on its name
 */
857 858 859 860
virDomainPtr
xenXMDomainLookupByName(virConnectPtr conn, const char *domname)
{
    xenUnifiedPrivatePtr priv = conn->privateData;
861
    const char *filename;
862
    xenXMConfCachePtr entry;
D
Daniel P. Berrange 已提交
863
    virDomainPtr ret = NULL;
864

D
Daniel P. Berrange 已提交
865
    xenUnifiedLock(priv);
866

867
    if (!xenInotifyActive(conn) && xenXMConfigCacheRefresh(conn) < 0)
D
Daniel P. Berrange 已提交
868
        goto cleanup;
869

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

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

D
Daniel P. Berrange 已提交
876 877
    if (!(ret = virGetDomain(conn, domname, entry->def->uuid)))
        goto cleanup;
878 879 880

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

D
Daniel P. Berrange 已提交
883 884
cleanup:
    xenUnifiedUnlock(priv);
885
    return ret;
886 887 888 889 890 891
}


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

900
    if (!memcmp(entry->def->uuid, wantuuid, VIR_UUID_BUFLEN))
901
        return 1;
902

903
    return 0;
904 905 906 907 908
}

/*
 * Find an inactive domain based on its UUID
 */
909 910 911 912
virDomainPtr
xenXMDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
    xenUnifiedPrivatePtr priv = conn->privateData;
913
    xenXMConfCachePtr entry;
D
Daniel P. Berrange 已提交
914
    virDomainPtr ret = NULL;
915

D
Daniel P. Berrange 已提交
916
    xenUnifiedLock(priv);
917

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

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

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

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

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


/*
 * Start a domain from an existing defined config file
 */
940 941 942
int
xenXMDomainCreate(virDomainPtr domain)
{
943
    char *sexpr;
D
Daniel P. Berrange 已提交
944
    int ret = -1;
945
    xenUnifiedPrivatePtr priv= domain->conn->privateData;
946 947 948
    const char *filename;
    xenXMConfCachePtr entry;

949
    if (domain->id != -1)
950
        return -1;
951

D
Daniel P. Berrange 已提交
952 953
    xenUnifiedLock(priv);

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

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

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

963
    ret = xenDaemonDomainCreateXML(domain->conn, sexpr);
964
    VIR_FREE(sexpr);
D
Daniel P. Berrange 已提交
965 966
    if (ret != 0)
        goto error;
967

968
    if ((ret = xenDaemonDomainLookupByName_ids(domain->conn, domain->name,
D
Daniel P. Berrange 已提交
969 970
                                               entry->def->uuid)) < 0)
        goto error;
971
    domain->id = ret;
972

973
    if (xend_wait_for_devices(domain->conn, domain->name) < 0)
D
Daniel P. Berrange 已提交
974
        goto error;
975

976
    if (xenDaemonDomainResume(domain) < 0)
D
Daniel P. Berrange 已提交
977
        goto error;
978

D
Daniel P. Berrange 已提交
979
    xenUnifiedUnlock(priv);
980
    return 0;
981

D
Daniel P. Berrange 已提交
982
 error:
983
    if (domain->id != -1) {
984
        xenDaemonDomainDestroyFlags(domain, 0);
985
        domain->id = -1;
986
    }
D
Daniel P. Berrange 已提交
987
    xenUnifiedUnlock(priv);
988
    return -1;
989 990
}

991 992 993 994
/*
 * Create a config file for a domain, based on an XML
 * document describing its config
 */
995 996
virDomainPtr
xenXMDomainDefineXML(virConnectPtr conn, const char *xml)
997
{
998
    virDomainPtr ret;
999
    char *filename = NULL;
1000
    const char *oldfilename;
1001
    virDomainDefPtr def = NULL;
1002
    virConfPtr conf = NULL;
1003
    xenXMConfCachePtr entry = NULL;
1004
    xenUnifiedPrivatePtr priv = conn->privateData;
1005 1006

    if (conn->flags & VIR_CONNECT_RO)
1007
        return NULL;
1008

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

1011
    if (!xenInotifyActive(conn) && xenXMConfigCacheRefresh(conn) < 0) {
D
Daniel P. Berrange 已提交
1012
        xenUnifiedUnlock(priv);
1013
        return NULL;
D
Daniel P. Berrange 已提交
1014
    }
1015

1016
    if (!(def = virDomainDefParseString(xml, priv->caps, priv->xmlopt,
M
Matthias Bolte 已提交
1017
                                        1 << VIR_DOMAIN_VIRT_XEN,
D
Daniel P. Berrange 已提交
1018
                                        VIR_DOMAIN_XML_INACTIVE))) {
1019
        xenUnifiedUnlock(priv);
1020
        return NULL;
D
Daniel P. Berrange 已提交
1021
    }
1022

1023 1024 1025
    if (!(conf = xenFormatXM(conn, def, priv->xendConfigVersion)))
        goto error;

1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036
    /*
     * 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);
1037 1038 1039
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("domain '%s' is already defined with uuid %s"),
                           entry->def->name, uuidstr);
1040 1041 1042 1043 1044 1045
            entry = NULL;
            goto error;
        }
        entry = NULL;
    }

1046
    if (virHashLookup(priv->nameConfigMap, def->name)) {
1047 1048
        /* domain exists, we will overwrite it */

1049
        if (!(oldfilename = (char *)virHashLookup(priv->nameConfigMap, def->name))) {
1050 1051
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("can't retrieve config filename for domain to overwrite"));
1052 1053 1054
            goto error;
        }

1055
        if (!(entry = virHashLookup(priv->configCache, oldfilename))) {
1056 1057
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("can't retrieve config entry for domain to overwrite"));
1058 1059 1060 1061
            goto error;
        }

        /* Remove the name -> filename mapping */
1062
        if (virHashRemoveEntry(priv->nameConfigMap, def->name) < 0) {
1063 1064
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("failed to remove old domain from config map"));
1065 1066 1067 1068
            goto error;
        }

        /* Remove the config record itself */
1069
        if (virHashRemoveEntry(priv->configCache, oldfilename) < 0) {
1070 1071
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("failed to remove old domain from config map"));
1072 1073 1074 1075
            goto error;
        }

        entry = NULL;
1076
    }
1077

1078
    if (!(filename = virFileBuildPath(priv->configDir, def->name, NULL)))
1079 1080
        goto error;

1081
    if (virConfWriteFile(filename, conf) < 0)
1082 1083
        goto error;

1084
    if (VIR_ALLOC(entry) < 0) {
1085
        virReportOOMError();
1086
        goto error;
1087
    }
1088

1089
    if ((entry->refreshedAt = time(NULL)) == ((time_t)-1)) {
1090 1091
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("unable to get current time"));
1092
        goto error;
1093
    }
1094

E
Eric Blake 已提交
1095 1096 1097 1098
    if ((entry->filename = strdup(filename)) == NULL) {
        virReportOOMError();
        goto error;
    }
1099
    entry->def = def;
1100

1101
    if (virHashAddEntry(priv->configCache, filename, entry) < 0) {
1102 1103
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("unable to store config file handle"));
1104
        goto error;
1105
    }
1106

1107
    if (virHashAddEntry(priv->nameConfigMap, def->name, entry->filename) < 0) {
1108
        virHashSteal(priv->configCache, filename);
1109 1110
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("unable to store config file handle"));
1111
        goto error;
1112 1113
    }

1114
    ret = virGetDomain(conn, def->name, def->uuid);
D
Daniel P. Berrange 已提交
1115
    xenUnifiedUnlock(priv);
1116
    VIR_FREE(filename);
1117
    return ret;
1118 1119

 error:
1120
    VIR_FREE(filename);
1121 1122
    if (entry)
        VIR_FREE(entry->filename);
1123
    VIR_FREE(entry);
1124
    virConfFree(conf);
1125
    virDomainDefFree(def);
D
Daniel P. Berrange 已提交
1126
    xenUnifiedUnlock(priv);
1127
    return NULL;
1128 1129 1130 1131 1132
}

/*
 * Delete a domain from disk
 */
1133 1134 1135 1136
int
xenXMDomainUndefine(virDomainPtr domain)
{
    xenUnifiedPrivatePtr priv = domain->conn->privateData;
1137
    const char *filename;
1138
    xenXMConfCachePtr entry;
D
Daniel P. Berrange 已提交
1139 1140
    int ret = -1;

1141
    if (domain->id != -1)
1142
        return -1;
1143
    if (domain->conn->flags & VIR_CONNECT_RO)
1144
        return -1;
1145

D
Daniel P. Berrange 已提交
1146
    xenUnifiedLock(priv);
1147 1148

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

1151
    if (!(entry = virHashLookup(priv->configCache, filename)))
D
Daniel P. Berrange 已提交
1152
        goto cleanup;
1153 1154

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

1157 1158 1159
    /* Remove the name -> filename mapping */
    if (virHashRemoveEntry(priv->nameConfigMap, domain->name) < 0)
        goto cleanup;
1160

1161 1162 1163
    /* Remove the config record itself */
    if (virHashRemoveEntry(priv->configCache, entry->filename) < 0)
        goto cleanup;
1164

D
Daniel P. Berrange 已提交
1165 1166 1167 1168 1169
    ret = 0;

cleanup:
    xenUnifiedUnlock(priv);
    return ret;
1170 1171 1172 1173
}

struct xenXMListIteratorContext {
    virConnectPtr conn;
1174
    int oom;
1175 1176
    int max;
    int count;
1177
    char ** names;
1178 1179
};

1180 1181
static void
xenXMListIterator(void *payload ATTRIBUTE_UNUSED, const void *name, void *data) {
1182
    struct xenXMListIteratorContext *ctx = data;
1183 1184
    virDomainPtr dom = NULL;

1185 1186 1187
    if (ctx->oom)
        return;

1188 1189 1190
    if (ctx->count == ctx->max)
        return;

1191
    dom = xenDaemonLookupByName(ctx->conn, name);
1192
    if (!dom) {
1193 1194 1195 1196
        if (!(ctx->names[ctx->count] = strdup(name)))
            ctx->oom = 1;
        else
            ctx->count++;
1197 1198 1199 1200 1201 1202 1203 1204 1205 1206
    } else {
        virDomainFree(dom);
    }
}


/*
 * List all defined domains, filtered to remove any which
 * are currently running
 */
1207 1208 1209 1210
int
xenXMListDefinedDomains(virConnectPtr conn, char **const names, int maxnames)
{
    xenUnifiedPrivatePtr priv = conn->privateData;
1211
    struct xenXMListIteratorContext ctx;
1212
    int i, ret = -1;
1213

D
Daniel P. Berrange 已提交
1214
    xenUnifiedLock(priv);
1215

1216
    if (!xenInotifyActive(conn) && xenXMConfigCacheRefresh(conn) < 0)
D
Daniel P. Berrange 已提交
1217
        goto cleanup;
1218

1219 1220
    if (maxnames > virHashSize(priv->configCache))
        maxnames = virHashSize(priv->configCache);
1221 1222

    ctx.conn = conn;
1223
    ctx.oom = 0;
1224 1225 1226 1227
    ctx.count = 0;
    ctx.max = maxnames;
    ctx.names = names;

1228
    virHashForEach(priv->nameConfigMap, xenXMListIterator, &ctx);
1229 1230 1231 1232 1233

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

1234
        virReportOOMError();
1235 1236 1237
        goto cleanup;
    }

D
Daniel P. Berrange 已提交
1238 1239 1240 1241 1242
    ret = ctx.count;

cleanup:
    xenUnifiedUnlock(priv);
    return ret;
1243 1244 1245 1246 1247 1248
}

/*
 * Return the maximum number of defined domains - not filtered
 * based on number running
 */
1249 1250 1251 1252
int
xenXMNumOfDefinedDomains(virConnectPtr conn)
{
    xenUnifiedPrivatePtr priv = conn->privateData;
D
Daniel P. Berrange 已提交
1253
    int ret = -1;
1254

D
Daniel P. Berrange 已提交
1255
    xenUnifiedLock(priv);
1256

1257
    if (!xenInotifyActive(conn) && xenXMConfigCacheRefresh(conn) < 0)
D
Daniel P. Berrange 已提交
1258
        goto cleanup;
1259

D
Daniel P. Berrange 已提交
1260 1261 1262 1263 1264
    ret = virHashSize(priv->nameConfigMap);

cleanup:
    xenUnifiedUnlock(priv);
    return ret;
1265 1266
}

1267

1268
/**
1269
 * xenXMDomainAttachDeviceFlags:
1270 1271
 * @domain: pointer to domain object
 * @xml: pointer to XML description of device
1272
 * @flags: an OR'ed set of virDomainDeviceModifyFlags
J
Jim Meyering 已提交
1273
 *
1274 1275
 * Create a virtual device attachment to backend.
 * XML description is translated into config file.
1276 1277
 * This driver only supports device allocation to
 * persisted config.
J
Jim Meyering 已提交
1278
 *
1279 1280 1281
 * Returns 0 in case of success, -1 in case of failure.
 */
static int
1282 1283
xenXMDomainAttachDeviceFlags(virDomainPtr domain,
                             const char *xml,
E
Eric Blake 已提交
1284 1285
                             unsigned int flags)
{
1286 1287
    const char *filename = NULL;
    xenXMConfCachePtr entry = NULL;
1288 1289
    int ret = -1;
    virDomainDeviceDefPtr dev = NULL;
1290
    virDomainDefPtr def;
1291
    xenUnifiedPrivatePtr priv = domain->conn->privateData;
1292

E
Eric Blake 已提交
1293 1294
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);

1295
    if (domain->conn->flags & VIR_CONNECT_RO)
1296
        return -1;
1297 1298

    if ((flags & VIR_DOMAIN_DEVICE_MODIFY_LIVE) ||
E
Eric Blake 已提交
1299
        (domain->id != -1 && flags == VIR_DOMAIN_DEVICE_MODIFY_CURRENT)) {
1300 1301
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Xm driver only supports modifying persistent config"));
1302
        return -1;
1303
    }
1304

D
Daniel P. Berrange 已提交
1305 1306
    xenUnifiedLock(priv);

1307
    if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
D
Daniel P. Berrange 已提交
1308
        goto cleanup;
1309
    if (!(entry = virHashLookup(priv->configCache, filename)))
D
Daniel P. Berrange 已提交
1310
        goto cleanup;
1311
    def = entry->def;
1312

1313 1314
    if (!(dev = virDomainDeviceDefParse(xml, entry->def,
                                        priv->caps,
1315
                                        priv->xmlopt,
1316
                                        VIR_DOMAIN_XML_INACTIVE)))
D
Daniel P. Berrange 已提交
1317
        goto cleanup;
1318

1319 1320 1321
    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
    {
1322
        if (virDomainDiskInsert(def, dev->data.disk) < 0) {
1323
            virReportOOMError();
1324
            goto cleanup;
1325 1326
        }
        dev->data.disk = NULL;
1327
    }
1328
    break;
1329

1330 1331
    case VIR_DOMAIN_DEVICE_NET:
    {
1332
        if (VIR_REALLOC_N(def->nets, def->nnets+1) < 0) {
1333
            virReportOOMError();
1334 1335 1336
            goto cleanup;
        }
        def->nets[def->nnets++] = dev->data.net;
1337 1338
        dev->data.net = NULL;
        break;
1339 1340
    }

1341
    default:
1342 1343
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Xm driver only supports adding disk or network devices"));
1344 1345 1346 1347 1348 1349
        goto cleanup;
    }

    /* If this fails, should we try to undo our changes to the
     * in-memory representation of the config file. I say not!
     */
1350
    if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
1351 1352 1353 1354 1355
        goto cleanup;

    ret = 0;

 cleanup:
1356
    virDomainDeviceDefFree(dev);
D
Daniel P. Berrange 已提交
1357
    xenUnifiedUnlock(priv);
1358 1359 1360 1361 1362
    return ret;
}


/**
1363
 * xenXMDomainDetachDeviceFlags:
1364 1365
 * @domain: pointer to domain object
 * @xml: pointer to XML description of device
1366
 * @flags: an OR'ed set of virDomainDeviceModifyFlags
J
Jim Meyering 已提交
1367
 *
1368
 * Destroy a virtual device attachment to backend.
1369 1370
 * This driver only supports device deallocation from
 * persisted config.
1371 1372 1373 1374
 *
 * Returns 0 in case of success, -1 in case of failure.
 */
static int
1375 1376 1377 1378
xenXMDomainDetachDeviceFlags(virDomainPtr domain,
                             const char *xml,
                             unsigned int flags)
{
1379 1380
    const char *filename = NULL;
    xenXMConfCachePtr entry = NULL;
1381
    virDomainDeviceDefPtr dev = NULL;
1382
    virDomainDefPtr def;
1383
    int ret = -1;
1384
    int i;
1385
    xenUnifiedPrivatePtr priv = domain->conn->privateData;
1386

E
Eric Blake 已提交
1387 1388
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);

1389
    if (domain->conn->flags & VIR_CONNECT_RO)
1390
        return -1;
1391 1392

    if ((flags & VIR_DOMAIN_DEVICE_MODIFY_LIVE) ||
E
Eric Blake 已提交
1393
        (domain->id != -1 && flags == VIR_DOMAIN_DEVICE_MODIFY_CURRENT)) {
1394 1395
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Xm driver only supports modifying persistent config"));
1396
        return -1;
1397
    }
D
Daniel P. Berrange 已提交
1398 1399 1400

    xenUnifiedLock(priv);

1401
    if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
D
Daniel P. Berrange 已提交
1402
        goto cleanup;
1403
    if (!(entry = virHashLookup(priv->configCache, filename)))
D
Daniel P. Berrange 已提交
1404
        goto cleanup;
1405
    def = entry->def;
1406

1407 1408
    if (!(dev = virDomainDeviceDefParse(xml, entry->def,
                                        priv->caps,
1409
                                        priv->xmlopt,
1410
                                        VIR_DOMAIN_XML_INACTIVE)))
D
Daniel P. Berrange 已提交
1411
        goto cleanup;
1412

1413 1414 1415
    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
    {
1416 1417
        for (i = 0 ; i < def->ndisks ; i++) {
            if (def->disks[i]->dst &&
1418
                dev->data.disk->dst &&
1419 1420 1421 1422 1423
                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,
1424 1425
                            sizeof(*def->disks) *
                            (def->ndisks - (i + 1)));
1426
                def->ndisks--;
1427
                break;
1428 1429
            }
        }
1430 1431 1432 1433 1434
        break;
    }

    case VIR_DOMAIN_DEVICE_NET:
    {
1435
        for (i = 0 ; i < def->nnets ; i++) {
1436
            if (!virMacAddrCmp(&def->nets[i]->mac, &dev->data.net->mac)) {
1437 1438 1439 1440
                virDomainNetDefFree(def->nets[i]);
                if (i < (def->nnets - 1))
                    memmove(def->nets + i,
                            def->nets + i + 1,
1441 1442
                            sizeof(*def->nets) *
                            (def->nnets - (i + 1)));
1443
                def->nnets--;
1444 1445 1446 1447
                break;
            }
        }
        break;
1448
    }
1449
    default:
1450 1451 1452
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("device type '%s' cannot be detached"),
                       virDomainDeviceTypeToString(dev->type));
1453 1454 1455 1456 1457 1458
        goto cleanup;
    }

    /* If this fails, should we try to undo our changes to the
     * in-memory representation of the config file. I say not!
     */
1459
    if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
1460 1461 1462 1463 1464
        goto cleanup;

    ret = 0;

 cleanup:
1465
    virDomainDeviceDefFree(dev);
D
Daniel P. Berrange 已提交
1466
    xenUnifiedUnlock(priv);
1467
    return ret;
1468 1469
}

R
Richard W.M. Jones 已提交
1470
int
1471 1472 1473 1474 1475
xenXMDomainBlockPeek(virDomainPtr dom ATTRIBUTE_UNUSED,
                     const char *path ATTRIBUTE_UNUSED,
                     unsigned long long offset ATTRIBUTE_UNUSED,
                     size_t size ATTRIBUTE_UNUSED,
                     void *buffer ATTRIBUTE_UNUSED)
R
Richard W.M. Jones 已提交
1476
{
1477 1478
    virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                   _("block peeking not implemented"));
R
Richard W.M. Jones 已提交
1479 1480 1481
    return -1;
}

1482

1483 1484
static char *
xenXMAutostartLinkName(virDomainPtr dom)
1485 1486
{
    char *ret;
1487 1488
    if (virAsprintf(&ret, "/etc/xen/auto/%s", dom->name) < 0)
        return NULL;
1489 1490 1491
    return ret;
}

1492 1493
static char *
xenXMDomainConfigName(virDomainPtr dom)
1494 1495
{
    char *ret;
1496 1497
    if (virAsprintf(&ret, "/etc/xen/%s", dom->name) < 0)
        return NULL;
1498 1499 1500
    return ret;
}

1501 1502
int
xenXMDomainGetAutostart(virDomainPtr dom, int *autostart)
1503 1504 1505 1506 1507 1508
{
    char *linkname = xenXMAutostartLinkName(dom);
    char *config = xenXMDomainConfigName(dom);
    int ret = -1;

    if (!linkname || !config) {
1509
        virReportOOMError();
1510 1511 1512 1513 1514
        goto cleanup;
    }

    *autostart = virFileLinkPointsTo(linkname, config);
    if (*autostart < 0) {
1515
        virReportSystemError(errno,
1516 1517
                             _("cannot check link %s points to config %s"),
                             linkname, config);
1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529
        goto cleanup;
    }

    ret = 0;

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


1530 1531
int
xenXMDomainSetAutostart(virDomainPtr dom, int autostart)
1532 1533 1534 1535 1536 1537
{
    char *linkname = xenXMAutostartLinkName(dom);
    char *config = xenXMDomainConfigName(dom);
    int ret = -1;

    if (!linkname || !config) {
1538
        virReportOOMError();
1539 1540 1541 1542 1543 1544
        goto cleanup;
    }

    if (autostart) {
        if (symlink(config, linkname) < 0 &&
            errno != EEXIST) {
1545
            virReportSystemError(errno,
1546 1547
                                 _("failed to create link %s to %s"),
                                 config, linkname);
1548 1549 1550 1551 1552
            goto cleanup;
        }
    } else {
        if (unlink(linkname)  < 0 &&
            errno != ENOENT) {
1553
            virReportSystemError(errno,
1554 1555
                                 _("failed to remove link %s"),
                                 linkname);
1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566
            goto cleanup;
        }
    }
    ret = 0;

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

    return ret;
}