xm_internal.c 44.5 KB
Newer Older
1 2 3
/*
 * xm_internal.h: helper routines for dealing with inactive domains
 *
4
 * Copyright (C) 2006-2007, 2009-2012 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 "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 "virhash.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 = {
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 107 108
static int xenInotifyActive(virConnectPtr conn)
{
   xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
   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
static int xenXMConfigReaper(const void *payload, const void *key ATTRIBUTE_UNUSED, const void *data) {
128
    const struct xenXMConfigReaperData *args = data;
129 130
    xenXMConfCachePtr entry = (xenXMConfCachePtr)payload;

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

144 145 146 147 148

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

151
    if (!(conf = virConfReadFile(filename, 0)))
152 153
        return NULL;

M
Markus Groß 已提交
154
    def = xenParseXM(conf, priv->xendConfigVersion, priv->caps);
155 156 157 158 159 160 161 162
    virConfFree(conf);

    return def;
}

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

M
Markus Groß 已提交
166
    if (!(conf = xenFormatXM(conn, def, priv->xendConfigVersion)))
167 168 169 170 171 172 173
        return -1;

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

D
Daniel P. Berrange 已提交
174 175 176 177 178

/*
 * Caller must hold the lock on 'conn->privateData' before
 * calling this funtion
 */
179
int
180
xenXMConfigCacheRemoveFile(virConnectPtr conn,
181 182
                           const char *filename)
{
183
    xenUnifiedPrivatePtr priv = conn->privateData;
184 185
    xenXMConfCachePtr entry;

186
    entry = virHashLookup(priv->configCache, filename);
187
    if (!entry) {
188
        VIR_DEBUG("No config entry for %s", filename);
189 190 191
        return 0;
    }

192 193
    virHashRemoveEntry(priv->nameConfigMap, entry->def->name);
    virHashRemoveEntry(priv->configCache, filename);
194
    VIR_DEBUG("Removed %s %s", entry->def->name, filename);
195 196 197 198
    return 0;
}


D
Daniel P. Berrange 已提交
199 200 201 202
/*
 * Caller must hold the lock on 'conn->privateData' before
 * calling this funtion
 */
203 204 205
int
xenXMConfigCacheAddFile(virConnectPtr conn, const char *filename)
{
206
    xenUnifiedPrivatePtr priv = conn->privateData;
207 208 209 210 211
    xenXMConfCachePtr entry;
    struct stat st;
    int newborn = 0;
    time_t now = time(NULL);

212
    VIR_DEBUG("Adding file %s", filename);
213 214 215

    /* Get modified time */
    if ((stat(filename, &st) < 0)) {
216
        virReportSystemError(errno,
217 218
                             _("cannot stat: %s"),
                             filename);
219 220 221 222 223 224
        return -1;
    }

    /* Ignore zero length files, because inotify fires before
       any content has actually been created */
    if (st.st_size == 0) {
225
        VIR_DEBUG("Ignoring zero length file %s", filename);
226 227 228 229 230
        return -1;
    }

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

        /* Clear existing config entry which needs refresh */
        virDomainDefFree(entry->def);
        entry->def = NULL;
    } else { /* Completely new entry */
        newborn = 1;
        if (VIR_ALLOC(entry) < 0) {
253
            virReportOOMError();
254 255
            return -1;
        }
E
Eric Blake 已提交
256 257 258 259 260
        if ((entry->filename = strdup(filename)) == NULL) {
            virReportOOMError();
            VIR_FREE(entry);
            return -1;
        }
261 262 263 264
    }
    entry->refreshedAt = now;

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

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

    return 0;
}
302

303
/* This method is called by various methods to scan /etc/xen
D
Daniel P. Berrange 已提交
304 305 306 307 308 309 310 311
 * (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
 */
312
int xenXMConfigCacheRefresh (virConnectPtr conn) {
313
    xenUnifiedPrivatePtr priv = conn->privateData;
314 315 316 317
    DIR *dh;
    struct dirent *ent;
    time_t now = time(NULL);
    int ret = -1;
318
    struct xenXMConfigReaperData args;
319 320

    if (now == ((time_t)-1)) {
321
        virReportSystemError(errno,
322
                             "%s", _("cannot get time of day"));
323
        return -1;
324 325 326
    }

    /* Rate limit re-scans */
327
    if ((now - priv->lastRefresh) < XM_REFRESH_INTERVAL)
328
        return 0;
329

330
    priv->lastRefresh = now;
331 332

    /* Process the files in the config dir */
333
    if (!(dh = opendir(priv->configDir))) {
334
        virReportSystemError(errno,
335
                             _("cannot read directory %s"),
336
                             priv->configDir);
337
        return -1;
338 339 340 341
    }

    while ((ent = readdir(dh))) {
        struct stat st;
342
        char *path;
343 344 345 346 347 348

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

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

        /* Skip anything which isn't a file (takes care of scripts/ subdir */
        if ((stat(path, &st) < 0) ||
            (!S_ISREG(st.st_mode))) {
379
            VIR_FREE(path);
380 381 382 383 384
            continue;
        }

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

        VIR_FREE(path);
390 391 392 393 394 395
    }

    /* 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 */
396 397
    args.now = now;
    args.priv = priv;
398
    virHashRemoveSet(priv->configCache, xenXMConfigReaper, &args);
399 400
    ret = 0;

401
    closedir(dh);
402

403
    return ret;
404 405 406 407
}


/*
408 409 410 411
 * 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
412
 */
413
virDrvOpenStatus
414
xenXMOpen (virConnectPtr conn,
415
           virConnectAuthPtr auth ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
416
           unsigned int flags)
417
{
418 419
    xenUnifiedPrivatePtr priv = conn->privateData;

E
Eric Blake 已提交
420 421
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

422 423
    priv->configDir = XM_CONFIG_DIR;

424
    priv->configCache = virHashCreate(50, xenXMConfigFree);
425
    if (!priv->configCache)
426
        return -1;
427
    priv->nameConfigMap = virHashCreate(50, NULL);
428
    if (!priv->nameConfigMap) {
429
        virHashFree(priv->configCache);
430
        priv->configCache = NULL;
431
        return -1;
432
    }
433 434 435 436
    /* Force the cache to be reloaded next time that
     * xenXMConfigCacheRefresh is called.
     */
    priv->lastRefresh = 0;
437

438
    return 0;
439 440 441
}

/*
442 443
 * Free the cached config files associated with this
 * connection
444
 */
445 446 447
int xenXMClose(virConnectPtr conn) {
    xenUnifiedPrivatePtr priv = conn->privateData;

448 449
    virHashFree(priv->nameConfigMap);
    virHashFree(priv->configCache);
450

451
    return 0;
452 453
}

454 455 456 457 458 459 460
/*
 * Since these are all offline domains, the state is always SHUTOFF.
 */
int
xenXMDomainGetState(virDomainPtr domain,
                    int *state,
                    int *reason,
E
Eric Blake 已提交
461
                    unsigned int flags)
462
{
E
Eric Blake 已提交
463 464
    virCheckFlags(0, -1);

465 466 467 468 469 470 471 472 473 474 475
    if (domain->id != -1)
        return -1;

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

    return 0;
}


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

489
    if (domain->id != -1)
490
        return -1;
491

492
    priv = domain->conn->privateData;
D
Daniel P. Berrange 已提交
493
    xenUnifiedLock(priv);
494 495

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

498
    if (!(entry = virHashLookup(priv->configCache, filename)))
D
Daniel P. Berrange 已提交
499
        goto error;
500 501

    memset(info, 0, sizeof(virDomainInfo));
502 503
    info->maxMem = entry->def->mem.max_balloon;
    info->memory = entry->def->mem.cur_balloon;
504
    info->nrVirtCpu = entry->def->vcpus;
505 506 507
    info->state = VIR_DOMAIN_SHUTOFF;
    info->cpuTime = 0;

D
Daniel P. Berrange 已提交
508
    xenUnifiedUnlock(priv);
509
    return 0;
510

D
Daniel P. Berrange 已提交
511 512 513
error:
    xenUnifiedUnlock(priv);
    return -1;
514 515 516
}


517 518
/*
 * Turn a config record into a lump of XML describing the
519
 * domain, suitable for later feeding for virDomainCreateXML
520
 */
E
Eric Blake 已提交
521 522
char *xenXMDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
{
523
    xenUnifiedPrivatePtr priv;
524 525
    const char *filename;
    xenXMConfCachePtr entry;
D
Daniel P. Berrange 已提交
526
    char *ret = NULL;
527

E
Eric Blake 已提交
528 529
    /* Flags checked by virDomainDefFormat */

530
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
531
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
532
        return NULL;
533
    }
534
    if (domain->id != -1)
535
        return NULL;
536

537
    priv = domain->conn->privateData;
D
Daniel P. Berrange 已提交
538
    xenUnifiedLock(priv);
539 540

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

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

546
    ret = virDomainDefFormat(entry->def, flags);
547

D
Daniel P. Berrange 已提交
548 549 550
cleanup:
    xenUnifiedUnlock(priv);
    return ret;
551 552 553
}


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

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
564
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
565
        return -1;
566 567
    }
    if (domain->conn->flags & VIR_CONNECT_RO)
568
        return -1;
569
    if (domain->id != -1)
570
        return -1;
571
    if (memory < 1024 * MIN_XEN_GUEST_SIZE)
572
        return -1;
573

574
    priv = domain->conn->privateData;
D
Daniel P. Berrange 已提交
575
    xenUnifiedLock(priv);
576 577

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

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

583 584 585
    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;
586 587 588 589

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

D
Daniel P. Berrange 已提交
594 595 596
cleanup:
    xenUnifiedUnlock(priv);
    return ret;
597 598 599 600 601 602
}

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

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
609
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
610
        return -1;
611 612
    }
    if (domain->conn->flags & VIR_CONNECT_RO)
613
        return -1;
614
    if (domain->id != -1)
615
        return -1;
616

617
    priv = domain->conn->privateData;
D
Daniel P. Berrange 已提交
618
    xenUnifiedLock(priv);
619 620

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

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

626 627 628
    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;
629 630 631 632

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

D
Daniel P. Berrange 已提交
637 638 639
cleanup:
    xenUnifiedUnlock(priv);
    return ret;
640 641 642 643 644
}

/*
 * Get max memory limit from config
 */
645
unsigned long long xenXMDomainGetMaxMemory(virDomainPtr domain) {
646
    xenUnifiedPrivatePtr priv;
647
    const char *filename;
648
    xenXMConfCachePtr entry;
649
    unsigned long long ret = 0;
650 651

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
652
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
653
        return 0;
654
    }
655
    if (domain->id != -1)
656
        return 0;
657

658
    priv = domain->conn->privateData;
D
Daniel P. Berrange 已提交
659
    xenUnifiedLock(priv);
660 661

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

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

667
    ret = entry->def->mem.max_balloon;
668

D
Daniel P. Berrange 已提交
669 670 671
cleanup:
    xenUnifiedUnlock(priv);
    return ret;
672 673
}

674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694
/*
 * 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;

E
Eric Blake 已提交
695 696 697 698
    virCheckFlags(VIR_DOMAIN_VCPU_LIVE |
                  VIR_DOMAIN_VCPU_CONFIG |
                  VIR_DOMAIN_VCPU_MAXIMUM, -1);

699
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
700
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
701 702 703
        return -1;
    }
    if (domain->conn->flags & VIR_CONNECT_RO) {
704
        virReportError(VIR_ERR_OPERATION_DENIED, __FUNCTION__);
705 706 707 708 709
        return -1;
    }
    if (domain->id != -1)
        return -2;
    if (flags & VIR_DOMAIN_VCPU_LIVE) {
710 711
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not running"));
712 713 714 715 716 717 718 719 720 721 722 723 724 725
        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) {
726 727
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not determine max vcpus for the domain"));
728 729 730 731 732 733 734
        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) {
735 736 737
        virReportError(VIR_ERR_INVALID_ARG,
                       _("requested vcpus is greater than max allowable"
                         " vcpus for the domain: %d > %d"), vcpus, max);
738 739 740 741 742 743 744 745 746 747 748 749
        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
750 751
     * in-memory representation of the config file. I say not!
     */
752
    if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
D
Daniel P. Berrange 已提交
753 754
        goto cleanup;
    ret = 0;
755

D
Daniel P. Berrange 已提交
756 757 758
cleanup:
    xenUnifiedUnlock(priv);
    return ret;
759 760
}

761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778
/**
 * 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;

E
Eric Blake 已提交
779 780 781 782
    virCheckFlags(VIR_DOMAIN_VCPU_LIVE |
                  VIR_DOMAIN_VCPU_CONFIG |
                  VIR_DOMAIN_VCPU_MAXIMUM, -1);

783
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
784
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
785 786 787 788 789 790
        return -1;
    }

    if (domain->id != -1)
        return -2;
    if (flags & VIR_DOMAIN_VCPU_LIVE) {
791
        virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("domain not active"));
792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811
        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;
}

812 813 814 815 816 817 818 819 820 821 822 823 824 825 826
/**
 * 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)
{
827
    xenUnifiedPrivatePtr priv;
828 829 830 831 832 833
    const char *filename;
    xenXMConfCachePtr entry;
    int ret = -1;

    if (domain == NULL || domain->conn == NULL || domain->name == NULL
        || cpumap == NULL || maplen < 1 || maplen > (int)sizeof(cpumap_t)) {
834
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
835 836 837
        return -1;
    }
    if (domain->conn->flags & VIR_CONNECT_RO) {
838 839
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("read only connection"));
840 841 842
        return -1;
    }
    if (domain->id != -1) {
843 844
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("not inactive domain"));
845 846 847
        return -1;
    }

848
    priv = domain->conn->privateData;
D
Daniel P. Berrange 已提交
849
    xenUnifiedLock(priv);
850 851

    if (!(filename = virHashLookup(priv->nameConfigMap, domain->name))) {
852
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("virHashLookup"));
D
Daniel P. Berrange 已提交
853
        goto cleanup;
854
    }
855
    if (!(entry = virHashLookup(priv->configCache, filename))) {
856 857
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("can't retrieve config file for domain"));
D
Daniel P. Berrange 已提交
858
        goto cleanup;
859 860
    }

H
Hu Tao 已提交
861
    virBitmapFree(entry->def->cpumask);
L
liguang 已提交
862 863 864
    entry->def->cpumask = virBitmapNewData(cpumap, maplen);
    if (!entry->def->cpumask)
        goto cleanup;
865
    if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
866 867 868 869 870
        goto cleanup;

    ret = 0;

 cleanup:
D
Daniel P. Berrange 已提交
871
    xenUnifiedUnlock(priv);
872
    return ret;
873 874
}

875 876 877 878
/*
 * Find an inactive domain based on its name
 */
virDomainPtr xenXMDomainLookupByName(virConnectPtr conn, const char *domname) {
879
    xenUnifiedPrivatePtr priv;
880
    const char *filename;
881
    xenXMConfCachePtr entry;
D
Daniel P. Berrange 已提交
882
    virDomainPtr ret = NULL;
883

884
    if (!VIR_IS_CONNECT(conn)) {
885
        virReportError(VIR_ERR_INVALID_CONN, __FUNCTION__);
886
        return NULL;
887 888
    }
    if (domname == NULL) {
889
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
890
        return NULL;
891 892
    }

893
    priv = conn->privateData;
D
Daniel P. Berrange 已提交
894
    xenUnifiedLock(priv);
895

896
    if (!xenInotifyActive(conn) && xenXMConfigCacheRefresh (conn) < 0)
D
Daniel P. Berrange 已提交
897
        goto cleanup;
898

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

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

D
Daniel P. Berrange 已提交
905 906
    if (!(ret = virGetDomain(conn, domname, entry->def->uuid)))
        goto cleanup;
907 908 909

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

D
Daniel P. Berrange 已提交
912 913
cleanup:
    xenUnifiedUnlock(priv);
914
    return ret;
915 916 917 918 919 920
}


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

925
    if (!memcmp(entry->def->uuid, wantuuid, VIR_UUID_BUFLEN))
926
        return 1;
927

928
    return 0;
929 930 931 932 933 934 935
}

/*
 * Find an inactive domain based on its UUID
 */
virDomainPtr xenXMDomainLookupByUUID(virConnectPtr conn,
                                     const unsigned char *uuid) {
936
    xenUnifiedPrivatePtr priv;
937
    xenXMConfCachePtr entry;
D
Daniel P. Berrange 已提交
938
    virDomainPtr ret = NULL;
939 940

    if (!VIR_IS_CONNECT(conn)) {
941
        virReportError(VIR_ERR_INVALID_CONN, __FUNCTION__);
942
        return NULL;
943 944
    }
    if (uuid == NULL) {
945
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
946
        return NULL;
947 948
    }

949
    priv = conn->privateData;
D
Daniel P. Berrange 已提交
950
    xenUnifiedLock(priv);
951

952
    if (!xenInotifyActive(conn) && xenXMConfigCacheRefresh (conn) < 0)
D
Daniel P. Berrange 已提交
953
        goto cleanup;
954

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

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

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

D
Daniel P. Berrange 已提交
965 966
cleanup:
    xenUnifiedUnlock(priv);
967
    return ret;
968 969 970 971 972 973 974 975
}


/*
 * Start a domain from an existing defined config file
 */
int xenXMDomainCreate(virDomainPtr domain) {
    char *sexpr;
D
Daniel P. Berrange 已提交
976
    int ret = -1;
977
    xenUnifiedPrivatePtr priv;
978 979 980 981
    const char *filename;
    xenXMConfCachePtr entry;

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

983
    if (domain->id != -1)
984
        return -1;
985

D
Daniel P. Berrange 已提交
986 987
    xenUnifiedLock(priv);

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

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

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

997
    ret = xenDaemonDomainCreateXML(domain->conn, sexpr);
998
    VIR_FREE(sexpr);
D
Daniel P. Berrange 已提交
999 1000
    if (ret != 0)
        goto error;
1001

1002
    if ((ret = xenDaemonDomainLookupByName_ids(domain->conn, domain->name,
D
Daniel P. Berrange 已提交
1003 1004
                                               entry->def->uuid)) < 0)
        goto error;
1005
    domain->id = ret;
1006

1007
    if (xend_wait_for_devices(domain->conn, domain->name) < 0)
D
Daniel P. Berrange 已提交
1008
        goto error;
1009

1010
    if (xenDaemonDomainResume(domain) < 0)
D
Daniel P. Berrange 已提交
1011
        goto error;
1012

D
Daniel P. Berrange 已提交
1013
    xenUnifiedUnlock(priv);
1014
    return 0;
1015

D
Daniel P. Berrange 已提交
1016
 error:
1017
    if (domain->id != -1) {
1018
        xenDaemonDomainDestroyFlags(domain, 0);
1019
        domain->id = -1;
1020
    }
D
Daniel P. Berrange 已提交
1021
    xenUnifiedUnlock(priv);
1022
    return -1;
1023 1024
}

1025 1026 1027 1028
/*
 * Create a config file for a domain, based on an XML
 * document describing its config
 */
1029 1030
virDomainPtr xenXMDomainDefineXML(virConnectPtr conn, const char *xml)
{
1031
    virDomainPtr ret;
1032
    char *filename = NULL;
1033
    const char *oldfilename;
1034
    virDomainDefPtr def = NULL;
1035
    virConfPtr conf = NULL;
1036
    xenXMConfCachePtr entry = NULL;
1037
    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
1038 1039

    if (!VIR_IS_CONNECT(conn)) {
1040
        virReportError(VIR_ERR_INVALID_CONN, __FUNCTION__);
1041
        return NULL;
1042 1043
    }
    if (xml == NULL) {
1044
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
1045
        return NULL;
1046 1047
    }
    if (conn->flags & VIR_CONNECT_RO)
1048
        return NULL;
1049

D
Daniel P. Berrange 已提交
1050 1051
    xenUnifiedLock(priv);

1052
    if (!xenInotifyActive(conn) && xenXMConfigCacheRefresh (conn) < 0) {
D
Daniel P. Berrange 已提交
1053
        xenUnifiedUnlock(priv);
1054
        return NULL;
D
Daniel P. Berrange 已提交
1055
    }
1056

1057
    if (!(def = virDomainDefParseString(priv->caps, xml,
M
Matthias Bolte 已提交
1058
                                        1 << VIR_DOMAIN_VIRT_XEN,
D
Daniel P. Berrange 已提交
1059
                                        VIR_DOMAIN_XML_INACTIVE))) {
1060
        xenUnifiedUnlock(priv);
1061
        return NULL;
D
Daniel P. Berrange 已提交
1062
    }
1063

1064 1065 1066
    if (!(conf = xenFormatXM(conn, def, priv->xendConfigVersion)))
        goto error;

1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077
    /*
     * 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);
1078 1079 1080
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("domain '%s' is already defined with uuid %s"),
                           entry->def->name, uuidstr);
1081 1082 1083 1084 1085 1086
            entry = NULL;
            goto error;
        }
        entry = NULL;
    }

1087
    if (virHashLookup(priv->nameConfigMap, def->name)) {
1088 1089
        /* domain exists, we will overwrite it */

1090
        if (!(oldfilename = (char *)virHashLookup(priv->nameConfigMap, def->name))) {
1091 1092
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("can't retrieve config filename for domain to overwrite"));
1093 1094 1095
            goto error;
        }

1096
        if (!(entry = virHashLookup(priv->configCache, oldfilename))) {
1097 1098
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("can't retrieve config entry for domain to overwrite"));
1099 1100 1101 1102
            goto error;
        }

        /* Remove the name -> filename mapping */
1103
        if (virHashRemoveEntry(priv->nameConfigMap, def->name) < 0) {
1104 1105
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("failed to remove old domain from config map"));
1106 1107 1108 1109
            goto error;
        }

        /* Remove the config record itself */
1110
        if (virHashRemoveEntry(priv->configCache, oldfilename) < 0) {
1111 1112
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("failed to remove old domain from config map"));
1113 1114 1115 1116
            goto error;
        }

        entry = NULL;
1117
    }
1118

1119
    if (!(filename = virFileBuildPath(priv->configDir, def->name, NULL)))
1120 1121
        goto error;

1122
    if (virConfWriteFile(filename, conf) < 0)
1123 1124
        goto error;

1125
    if (VIR_ALLOC(entry) < 0) {
1126
        virReportOOMError();
1127
        goto error;
1128
    }
1129

1130
    if ((entry->refreshedAt = time(NULL)) == ((time_t)-1)) {
1131 1132
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("unable to get current time"));
1133
        goto error;
1134
    }
1135

E
Eric Blake 已提交
1136 1137 1138 1139
    if ((entry->filename = strdup(filename)) == NULL) {
        virReportOOMError();
        goto error;
    }
1140
    entry->def = def;
1141

1142
    if (virHashAddEntry(priv->configCache, filename, entry) < 0) {
1143 1144
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("unable to store config file handle"));
1145
        goto error;
1146
    }
1147

1148
    if (virHashAddEntry(priv->nameConfigMap, def->name, entry->filename) < 0) {
1149
        virHashSteal(priv->configCache, filename);
1150 1151
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("unable to store config file handle"));
1152
        goto error;
1153 1154
    }

1155
    ret = virGetDomain(conn, def->name, def->uuid);
D
Daniel P. Berrange 已提交
1156
    xenUnifiedUnlock(priv);
1157
    VIR_FREE(filename);
1158
    return ret;
1159 1160

 error:
1161
    VIR_FREE(filename);
1162 1163
    if (entry)
        VIR_FREE(entry->filename);
1164
    VIR_FREE(entry);
1165
    virConfFree(conf);
1166
    virDomainDefFree(def);
D
Daniel P. Berrange 已提交
1167
    xenUnifiedUnlock(priv);
1168
    return NULL;
1169 1170 1171 1172 1173 1174
}

/*
 * Delete a domain from disk
 */
int xenXMDomainUndefine(virDomainPtr domain) {
1175
    xenUnifiedPrivatePtr priv;
1176
    const char *filename;
1177
    xenXMConfCachePtr entry;
D
Daniel P. Berrange 已提交
1178 1179
    int ret = -1;

1180
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
1181
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
1182
        return -1;
1183 1184
    }

1185
    if (domain->id != -1)
1186
        return -1;
1187
    if (domain->conn->flags & VIR_CONNECT_RO)
1188
        return -1;
1189

1190
    priv = domain->conn->privateData;
D
Daniel P. Berrange 已提交
1191
    xenUnifiedLock(priv);
1192 1193

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

1196
    if (!(entry = virHashLookup(priv->configCache, filename)))
D
Daniel P. Berrange 已提交
1197
        goto cleanup;
1198 1199

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

1202 1203 1204
    /* Remove the name -> filename mapping */
    if (virHashRemoveEntry(priv->nameConfigMap, domain->name) < 0)
        goto cleanup;
1205

1206 1207 1208
    /* Remove the config record itself */
    if (virHashRemoveEntry(priv->configCache, entry->filename) < 0)
        goto cleanup;
1209

D
Daniel P. Berrange 已提交
1210 1211 1212 1213 1214
    ret = 0;

cleanup:
    xenUnifiedUnlock(priv);
    return ret;
1215 1216 1217 1218
}

struct xenXMListIteratorContext {
    virConnectPtr conn;
1219
    int oom;
1220 1221
    int max;
    int count;
1222
    char ** names;
1223 1224
};

1225
static void xenXMListIterator(void *payload ATTRIBUTE_UNUSED, const void *name, void *data) {
1226
    struct xenXMListIteratorContext *ctx = data;
1227 1228
    virDomainPtr dom = NULL;

1229 1230 1231
    if (ctx->oom)
        return;

1232 1233 1234
    if (ctx->count == ctx->max)
        return;

1235
    dom = xenDaemonLookupByName(ctx->conn, name);
1236
    if (!dom) {
1237 1238 1239 1240
        if (!(ctx->names[ctx->count] = strdup(name)))
            ctx->oom = 1;
        else
            ctx->count++;
1241 1242 1243 1244 1245 1246 1247 1248 1249 1250
    } else {
        virDomainFree(dom);
    }
}


/*
 * List all defined domains, filtered to remove any which
 * are currently running
 */
1251
int xenXMListDefinedDomains(virConnectPtr conn, char **const names, int maxnames) {
1252
    xenUnifiedPrivatePtr priv;
1253
    struct xenXMListIteratorContext ctx;
1254
    int i, ret = -1;
1255 1256

    if (!VIR_IS_CONNECT(conn)) {
1257
        virReportError(VIR_ERR_INVALID_CONN, __FUNCTION__);
1258
        return -1;
1259 1260
    }

1261
    priv = conn->privateData;
D
Daniel P. Berrange 已提交
1262
    xenUnifiedLock(priv);
1263

1264
    if (!xenInotifyActive(conn) && xenXMConfigCacheRefresh (conn) < 0)
D
Daniel P. Berrange 已提交
1265
        goto cleanup;
1266

1267 1268
    if (maxnames > virHashSize(priv->configCache))
        maxnames = virHashSize(priv->configCache);
1269 1270

    ctx.conn = conn;
1271
    ctx.oom = 0;
1272 1273 1274 1275
    ctx.count = 0;
    ctx.max = maxnames;
    ctx.names = names;

1276
    virHashForEach(priv->nameConfigMap, xenXMListIterator, &ctx);
1277 1278 1279 1280 1281

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

1282
        virReportOOMError();
1283 1284 1285
        goto cleanup;
    }

D
Daniel P. Berrange 已提交
1286 1287 1288 1289 1290
    ret = ctx.count;

cleanup:
    xenUnifiedUnlock(priv);
    return ret;
1291 1292 1293 1294 1295 1296 1297
}

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

1301
    if (!VIR_IS_CONNECT(conn)) {
1302
        virReportError(VIR_ERR_INVALID_CONN, __FUNCTION__);
1303
        return -1;
1304 1305
    }

1306
    priv = conn->privateData;
D
Daniel P. Berrange 已提交
1307
    xenUnifiedLock(priv);
1308

1309
    if (!xenInotifyActive(conn) && xenXMConfigCacheRefresh (conn) < 0)
D
Daniel P. Berrange 已提交
1310
        goto cleanup;
1311

D
Daniel P. Berrange 已提交
1312 1313 1314 1315 1316
    ret = virHashSize(priv->nameConfigMap);

cleanup:
    xenUnifiedUnlock(priv);
    return ret;
1317 1318
}

1319

1320
/**
1321
 * xenXMDomainAttachDeviceFlags:
1322 1323
 * @domain: pointer to domain object
 * @xml: pointer to XML description of device
1324
 * @flags: an OR'ed set of virDomainDeviceModifyFlags
J
Jim Meyering 已提交
1325
 *
1326 1327
 * Create a virtual device attachment to backend.
 * XML description is translated into config file.
1328 1329
 * This driver only supports device allocation to
 * persisted config.
J
Jim Meyering 已提交
1330
 *
1331 1332 1333
 * Returns 0 in case of success, -1 in case of failure.
 */
static int
1334
xenXMDomainAttachDeviceFlags(virDomainPtr domain, const char *xml,
E
Eric Blake 已提交
1335 1336
                             unsigned int flags)
{
1337 1338
    const char *filename = NULL;
    xenXMConfCachePtr entry = NULL;
1339 1340
    int ret = -1;
    virDomainDeviceDefPtr dev = NULL;
1341
    virDomainDefPtr def;
1342
    xenUnifiedPrivatePtr priv;
1343

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

1346
    if ((!domain) || (!domain->conn) || (!domain->name) || (!xml)) {
1347
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
1348
        return -1;
1349
    }
1350

1351
    if (domain->conn->flags & VIR_CONNECT_RO)
1352
        return -1;
1353 1354

    if ((flags & VIR_DOMAIN_DEVICE_MODIFY_LIVE) ||
E
Eric Blake 已提交
1355
        (domain->id != -1 && flags == VIR_DOMAIN_DEVICE_MODIFY_CURRENT)) {
1356 1357
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Xm driver only supports modifying persistent config"));
1358
        return -1;
1359
    }
1360

D
Daniel P. Berrange 已提交
1361 1362 1363
    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
    xenUnifiedLock(priv);

1364
    if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
D
Daniel P. Berrange 已提交
1365
        goto cleanup;
1366
    if (!(entry = virHashLookup(priv->configCache, filename)))
D
Daniel P. Berrange 已提交
1367
        goto cleanup;
1368
    def = entry->def;
1369

1370
    if (!(dev = virDomainDeviceDefParse(priv->caps,
1371
                                        entry->def,
G
Guido Günther 已提交
1372
                                        xml, VIR_DOMAIN_XML_INACTIVE)))
D
Daniel P. Berrange 已提交
1373
        goto cleanup;
1374

1375 1376 1377
    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
    {
1378
        if (virDomainDiskInsert(def, dev->data.disk) < 0) {
1379
            virReportOOMError();
1380
            goto cleanup;
1381 1382
        }
        dev->data.disk = NULL;
1383
    }
1384
    break;
1385

1386 1387
    case VIR_DOMAIN_DEVICE_NET:
    {
1388
        if (VIR_REALLOC_N(def->nets, def->nnets+1) < 0) {
1389
            virReportOOMError();
1390 1391 1392
            goto cleanup;
        }
        def->nets[def->nnets++] = dev->data.net;
1393 1394
        dev->data.net = NULL;
        break;
1395 1396
    }

1397
    default:
1398 1399
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Xm driver only supports adding disk or network devices"));
1400 1401 1402 1403 1404 1405
        goto cleanup;
    }

    /* If this fails, should we try to undo our changes to the
     * in-memory representation of the config file. I say not!
     */
1406
    if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
1407 1408 1409 1410 1411
        goto cleanup;

    ret = 0;

 cleanup:
1412
    virDomainDeviceDefFree(dev);
D
Daniel P. Berrange 已提交
1413
    xenUnifiedUnlock(priv);
1414 1415 1416 1417 1418
    return ret;
}


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

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

1443
    if ((!domain) || (!domain->conn) || (!domain->name) || (!xml)) {
1444
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
1445
        return -1;
1446
    }
1447

1448
    if (domain->conn->flags & VIR_CONNECT_RO)
1449
        return -1;
1450 1451

    if ((flags & VIR_DOMAIN_DEVICE_MODIFY_LIVE) ||
E
Eric Blake 已提交
1452
        (domain->id != -1 && flags == VIR_DOMAIN_DEVICE_MODIFY_CURRENT)) {
1453 1454
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Xm driver only supports modifying persistent config"));
1455
        return -1;
1456
    }
D
Daniel P. Berrange 已提交
1457 1458 1459 1460

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

1461
    if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
D
Daniel P. Berrange 已提交
1462
        goto cleanup;
1463
    if (!(entry = virHashLookup(priv->configCache, filename)))
D
Daniel P. Berrange 已提交
1464
        goto cleanup;
1465
    def = entry->def;
1466

1467
    if (!(dev = virDomainDeviceDefParse(priv->caps,
1468
                                        entry->def,
G
Guido Günther 已提交
1469
                                        xml, VIR_DOMAIN_XML_INACTIVE)))
D
Daniel P. Berrange 已提交
1470
        goto cleanup;
1471

1472 1473 1474
    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
    {
1475 1476
        for (i = 0 ; i < def->ndisks ; i++) {
            if (def->disks[i]->dst &&
1477
                dev->data.disk->dst &&
1478 1479 1480 1481 1482
                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,
1483 1484
                            sizeof(*def->disks) *
                            (def->ndisks - (i + 1)));
1485
                def->ndisks--;
1486
                break;
1487 1488
            }
        }
1489 1490 1491 1492 1493
        break;
    }

    case VIR_DOMAIN_DEVICE_NET:
    {
1494
        for (i = 0 ; i < def->nnets ; i++) {
1495
            if (!virMacAddrCmp(&def->nets[i]->mac, &dev->data.net->mac)) {
1496 1497 1498 1499
                virDomainNetDefFree(def->nets[i]);
                if (i < (def->nnets - 1))
                    memmove(def->nets + i,
                            def->nets + i + 1,
1500 1501
                            sizeof(*def->nets) *
                            (def->nnets - (i + 1)));
1502
                def->nnets--;
1503 1504 1505 1506
                break;
            }
        }
        break;
1507
    }
1508
    default:
1509 1510 1511
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("device type '%s' cannot be detached"),
                       virDomainDeviceTypeToString(dev->type));
1512 1513 1514 1515 1516 1517
        goto cleanup;
    }

    /* If this fails, should we try to undo our changes to the
     * in-memory representation of the config file. I say not!
     */
1518
    if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
1519 1520 1521 1522 1523
        goto cleanup;

    ret = 0;

 cleanup:
1524
    virDomainDeviceDefFree(dev);
D
Daniel P. Berrange 已提交
1525
    xenUnifiedUnlock(priv);
1526
    return ret;
1527 1528
}

R
Richard W.M. Jones 已提交
1529
int
1530
xenXMDomainBlockPeek (virDomainPtr dom ATTRIBUTE_UNUSED,
R
Richard W.M. Jones 已提交
1531 1532 1533 1534 1535
                      const char *path ATTRIBUTE_UNUSED,
                      unsigned long long offset ATTRIBUTE_UNUSED,
                      size_t size ATTRIBUTE_UNUSED,
                      void *buffer ATTRIBUTE_UNUSED)
{
1536 1537
    virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                   _("block peeking not implemented"));
R
Richard W.M. Jones 已提交
1538 1539 1540
    return -1;
}

1541 1542 1543 1544

static char *xenXMAutostartLinkName(virDomainPtr dom)
{
    char *ret;
1545 1546
    if (virAsprintf(&ret, "/etc/xen/auto/%s", dom->name) < 0)
        return NULL;
1547 1548 1549 1550 1551 1552
    return ret;
}

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

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

    if (!linkname || !config) {
1565
        virReportOOMError();
1566 1567 1568 1569 1570
        goto cleanup;
    }

    *autostart = virFileLinkPointsTo(linkname, config);
    if (*autostart < 0) {
1571
        virReportSystemError(errno,
1572 1573
                             _("cannot check link %s points to config %s"),
                             linkname, config);
1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592
        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) {
1593
        virReportOOMError();
1594 1595 1596 1597 1598 1599
        goto cleanup;
    }

    if (autostart) {
        if (symlink(config, linkname) < 0 &&
            errno != EEXIST) {
1600
            virReportSystemError(errno,
1601 1602
                                 _("failed to create link %s to %s"),
                                 config, linkname);
1603 1604 1605 1606 1607
            goto cleanup;
        }
    } else {
        if (unlink(linkname)  < 0 &&
            errno != ENOENT) {
1608
            virReportSystemError(errno,
1609 1610
                                 _("failed to remove link %s"),
                                 linkname);
1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621
            goto cleanup;
        }
    }
    ret = 0;

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

    return ret;
}