lxc_driver.c 136.3 KB
Newer Older
D
Daniel Veillard 已提交
1
/*
2
 * Copyright (C) 2010-2013 Red Hat, Inc.
D
Daniel Veillard 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 * Copyright IBM Corp. 2008
 *
 * lxc_driver.c: linux container driver functions
 *
 * Authors:
 *  David L. Leskovec <dlesko at linux.vnet.ibm.com>
 *
 * 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
21
 * License along with this library.  If not, see
O
Osier Yang 已提交
22
 * <http://www.gnu.org/licenses/>.
D
Daniel Veillard 已提交
23 24 25 26
 */

#include <config.h>

27
#include <fcntl.h>
D
Daniel Veillard 已提交
28 29 30 31
#include <sched.h>
#include <sys/utsname.h>
#include <string.h>
#include <sys/types.h>
32
#include <sys/socket.h>
33
#include <sys/stat.h>
34 35
#include <sys/un.h>
#include <sys/poll.h>
D
Daniel Veillard 已提交
36 37 38
#include <unistd.h>
#include <wait.h>

39
#include "virerror.h"
40
#include "virlog.h"
41
#include "datatypes.h"
42
#include "lxc_cgroup.h"
D
Daniel Veillard 已提交
43
#include "lxc_conf.h"
44
#include "lxc_container.h"
45
#include "lxc_domain.h"
D
Daniel Veillard 已提交
46
#include "lxc_driver.h"
47
#include "lxc_process.h"
48
#include "viralloc.h"
49
#include "virnetdevbridge.h"
50
#include "virnetdevveth.h"
51
#include "nodeinfo.h"
52
#include "viruuid.h"
53
#include "virstatslinux.h"
54
#include "virhook.h"
E
Eric Blake 已提交
55
#include "virfile.h"
56
#include "virpidfile.h"
57
#include "fdstream.h"
58
#include "domain_audit.h"
59
#include "domain_nwfilter.h"
60
#include "nwfilter_conf.h"
61
#include "network/bridge_driver.h"
62
#include "virinitctl.h"
63
#include "virnetdev.h"
A
Ansis Atteka 已提交
64
#include "virnetdevtap.h"
65
#include "virnodesuspend.h"
66
#include "virprocess.h"
67
#include "virtime.h"
68
#include "virtypedparam.h"
M
Martin Kletzander 已提交
69
#include "viruri.h"
70
#include "virstring.h"
71 72
#include "viraccessapicheck.h"
#include "viraccessapichecklxc.h"
D
Daniel Veillard 已提交
73

74 75
#define VIR_FROM_THIS VIR_FROM_LXC

76

77 78
#define LXC_NB_MEM_PARAM  3

79 80 81 82
static int lxcStateInitialize(bool privileged,
                              virStateInhibitCallback callback,
                              void *opaque);
static int lxcStateCleanup(void);
83
virLXCDriverPtr lxc_driver = NULL;
D
Daniel Veillard 已提交
84

85 86
/* callbacks for nwfilter */
static int
87
lxcVMFilterRebuild(virDomainObjListIterator iter, void *data)
88
{
89
    return virDomainObjListForEach(lxc_driver->domains, iter, data);
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
}

static void
lxcVMDriverLock(void)
{
    lxcDriverLock(lxc_driver);
}

static void
lxcVMDriverUnlock(void)
{
    lxcDriverUnlock(lxc_driver);
}

static virNWFilterCallbackDriver lxcCallbackDriver = {
    .name = "LXC",
    .vmFilterRebuild = lxcVMFilterRebuild,
    .vmDriverLock = lxcVMDriverLock,
    .vmDriverUnlock = lxcVMDriverUnlock,
};

M
Michal Privoznik 已提交
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
/**
 * lxcDomObjFromDomain:
 * @domain: Domain pointer that has to be looked up
 *
 * This function looks up @domain and returns the appropriate
 * virDomainObjPtr.
 *
 * Returns the domain object which is locked on success, NULL
 * otherwise.
 */
static virDomainObjPtr
lxcDomObjFromDomain(virDomainPtr domain)
{
    virDomainObjPtr vm;
    virLXCDriverPtr driver = domain->conn->privateData;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

    vm = virDomainObjListFindByUUID(driver->domains, domain->uuid);
    if (!vm) {
        virUUIDFormat(domain->uuid, uuidstr);
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s' (%s)"),
                       uuidstr, domain->name);
        return NULL;
    }

    return vm;
}

D
Daniel Veillard 已提交
140 141
/* Functions */

142 143 144
static virDrvOpenStatus lxcConnectOpen(virConnectPtr conn,
                                       virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                       unsigned int flags)
D
Daniel Veillard 已提交
145
{
E
Eric Blake 已提交
146 147
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

D
Daniel Veillard 已提交
148
    /* Verify uri was specified */
149
    if (conn->uri == NULL) {
150 151
        if (lxc_driver == NULL)
            return VIR_DRV_OPEN_DECLINED;
152

153
        if (!(conn->uri = virURIParse("lxc:///")))
154
            return VIR_DRV_OPEN_ERROR;
155 156 157 158 159 160 161 162 163 164
    } else {
        if (conn->uri->scheme == NULL ||
            STRNEQ(conn->uri->scheme, "lxc"))
            return VIR_DRV_OPEN_DECLINED;

        /* Leave for remote driver */
        if (conn->uri->server != NULL)
            return VIR_DRV_OPEN_DECLINED;

        /* If path isn't '/' then they typoed, tell them correct path */
165 166
        if (conn->uri->path != NULL &&
            STRNEQ(conn->uri->path, "/")) {
167 168 169
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unexpected LXC URI path '%s', try lxc:///"),
                           conn->uri->path);
170 171
            return VIR_DRV_OPEN_ERROR;
        }
D
Daniel Veillard 已提交
172

173 174
        /* URI was good, but driver isn't active */
        if (lxc_driver == NULL) {
175 176
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("lxc state driver is not active"));
177 178 179
            return VIR_DRV_OPEN_ERROR;
        }
    }
180

181 182 183
    if (virConnectOpenEnsureACL(conn) < 0)
        return VIR_DRV_OPEN_ERROR;

184
    conn->privateData = lxc_driver;
D
Daniel Veillard 已提交
185 186 187 188

    return VIR_DRV_OPEN_SUCCESS;
}

189
static int lxcConnectClose(virConnectPtr conn)
D
Daniel Veillard 已提交
190
{
191
    virLXCDriverPtr driver = conn->privateData;
192

193
    virCloseCallbacksRun(driver->closeCallbacks, conn, driver->domains, driver);
194 195
    conn->privateData = NULL;
    return 0;
D
Daniel Veillard 已提交
196 197
}

198

199
static int lxcConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
200 201 202 203 204 205
{
    /* Trivially secure, since always inside the daemon */
    return 1;
}


206
static int lxcConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
207 208 209 210 211 212
{
    /* Not encrypted, but remote driver takes care of that */
    return 0;
}


213
static int lxcConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
214 215 216 217 218
{
    return 1;
}


219
static char *lxcConnectGetCapabilities(virConnectPtr conn) {
220
    virLXCDriverPtr driver = conn->privateData;
221
    virCapsPtr caps;
222 223
    char *xml;

224 225 226
    if (virConnectGetCapabilitiesEnsureACL(conn) < 0)
        return NULL;

227
    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
228 229 230
        return NULL;

    if ((xml = virCapabilitiesFormatXML(caps)) == NULL)
231
        virReportOOMError();
232

233
    virObjectUnref(caps);
234 235 236 237
    return xml;
}


D
Daniel Veillard 已提交
238 239 240
static virDomainPtr lxcDomainLookupByID(virConnectPtr conn,
                                        int id)
{
241
    virLXCDriverPtr driver = conn->privateData;
242 243
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
244

245
    vm = virDomainObjListFindByID(driver->domains, id);
246

D
Daniel Veillard 已提交
247
    if (!vm) {
248 249
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching id %d"), id);
250
        goto cleanup;
D
Daniel Veillard 已提交
251 252
    }

253 254 255
    if (virDomainLookupByIDEnsureACL(conn, vm->def) < 0)
        goto cleanup;

D
Daniel Veillard 已提交
256
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
257
    if (dom)
D
Daniel Veillard 已提交
258 259
        dom->id = vm->def->id;

260
cleanup:
261
    if (vm)
262
        virObjectUnlock(vm);
D
Daniel Veillard 已提交
263 264 265 266 267 268
    return dom;
}

static virDomainPtr lxcDomainLookupByUUID(virConnectPtr conn,
                                          const unsigned char *uuid)
{
269
    virLXCDriverPtr driver = conn->privateData;
270 271
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
272

273
    vm = virDomainObjListFindByUUID(driver->domains, uuid);
274

D
Daniel Veillard 已提交
275
    if (!vm) {
276 277
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
278 279
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching uuid '%s'"), uuidstr);
280
        goto cleanup;
D
Daniel Veillard 已提交
281 282
    }

283 284 285
    if (virDomainLookupByUUIDEnsureACL(conn, vm->def) < 0)
        goto cleanup;

D
Daniel Veillard 已提交
286
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
287
    if (dom)
D
Daniel Veillard 已提交
288 289
        dom->id = vm->def->id;

290
cleanup:
291
    if (vm)
292
        virObjectUnlock(vm);
D
Daniel Veillard 已提交
293 294 295 296 297 298
    return dom;
}

static virDomainPtr lxcDomainLookupByName(virConnectPtr conn,
                                          const char *name)
{
299
    virLXCDriverPtr driver = conn->privateData;
300 301
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
302

303
    vm = virDomainObjListFindByName(driver->domains, name);
D
Daniel Veillard 已提交
304
    if (!vm) {
305 306
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching name '%s'"), name);
307
        goto cleanup;
D
Daniel Veillard 已提交
308 309
    }

310 311 312
    if (virDomainLookupByNameEnsureACL(conn, vm->def) < 0)
        goto cleanup;

D
Daniel Veillard 已提交
313
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
314
    if (dom)
D
Daniel Veillard 已提交
315 316
        dom->id = vm->def->id;

317
cleanup:
318
    if (vm)
319
        virObjectUnlock(vm);
D
Daniel Veillard 已提交
320 321 322
    return dom;
}

323 324 325 326 327 328

static int lxcDomainIsActive(virDomainPtr dom)
{
    virDomainObjPtr obj;
    int ret = -1;

M
Michal Privoznik 已提交
329
    if (!(obj = lxcDomObjFromDomain(dom)))
330
        goto cleanup;
331 332 333 334

    if (virDomainIsActiveEnsureACL(dom->conn, obj->def) < 0)
        goto cleanup;

335 336 337 338
    ret = virDomainObjIsActive(obj);

cleanup:
    if (obj)
339
        virObjectUnlock(obj);
340 341 342 343 344 345 346 347 348
    return ret;
}


static int lxcDomainIsPersistent(virDomainPtr dom)
{
    virDomainObjPtr obj;
    int ret = -1;

M
Michal Privoznik 已提交
349
    if (!(obj = lxcDomObjFromDomain(dom)))
350
        goto cleanup;
351 352 353 354

    if (virDomainIsPersistentEnsureACL(dom->conn, obj->def) < 0)
        goto cleanup;

355 356 357 358
    ret = obj->persistent;

cleanup:
    if (obj)
359
        virObjectUnlock(obj);
360 361 362
    return ret;
}

363 364 365 366 367
static int lxcDomainIsUpdated(virDomainPtr dom)
{
    virDomainObjPtr obj;
    int ret = -1;

M
Michal Privoznik 已提交
368
    if (!(obj = lxcDomObjFromDomain(dom)))
369
        goto cleanup;
370 371 372 373

    if (virDomainIsUpdatedEnsureACL(dom->conn, obj->def) < 0)
        goto cleanup;

374 375 376 377
    ret = obj->updated;

cleanup:
    if (obj)
378
        virObjectUnlock(obj);
379 380
    return ret;
}
381

382
static int lxcConnectListDomains(virConnectPtr conn, int *ids, int nids) {
383
    virLXCDriverPtr driver = conn->privateData;
384
    int n;
385

386 387 388
    if (virConnectListDomainsEnsureACL(conn) < 0)
        return -1;

389 390
    n = virDomainObjListGetActiveIDs(driver->domains, ids, nids,
                                     virConnectListDomainsCheckACL, conn);
391

392
    return n;
D
Daniel Veillard 已提交
393
}
394

395
static int lxcConnectNumOfDomains(virConnectPtr conn) {
396
    virLXCDriverPtr driver = conn->privateData;
397
    int n;
398

399 400 401
    if (virConnectNumOfDomainsEnsureACL(conn) < 0)
        return -1;

402 403
    n = virDomainObjListNumOfDomains(driver->domains, true,
                                     virConnectNumOfDomainsCheckACL, conn);
404

405
    return n;
D
Daniel Veillard 已提交
406 407
}

408 409
static int lxcConnectListDefinedDomains(virConnectPtr conn,
                                        char **const names, int nnames) {
410
    virLXCDriverPtr driver = conn->privateData;
411
    int n;
412

413 414 415
    if (virConnectListDefinedDomainsEnsureACL(conn) < 0)
        return -1;

416 417
    n = virDomainObjListGetInactiveNames(driver->domains, names, nnames,
                                         virConnectListDefinedDomainsCheckACL, conn);
418

419
    return n;
D
Daniel Veillard 已提交
420 421 422
}


423
static int lxcConnectNumOfDefinedDomains(virConnectPtr conn) {
424
    virLXCDriverPtr driver = conn->privateData;
425
    int n;
426

427 428 429
    if (virConnectNumOfDefinedDomainsEnsureACL(conn) < 0)
        return -1;

430 431
    n = virDomainObjListNumOfDomains(driver->domains, false,
                                     virConnectNumOfDefinedDomainsCheckACL, conn);
432

433
    return n;
D
Daniel Veillard 已提交
434 435
}

436 437


438
static virDomainPtr lxcDomainDefineXML(virConnectPtr conn, const char *xml)
D
Daniel Veillard 已提交
439
{
440
    virLXCDriverPtr driver = conn->privateData;
441
    virDomainDefPtr def = NULL;
442
    virDomainObjPtr vm = NULL;
443
    virDomainPtr dom = NULL;
444
    virDomainEventPtr event = NULL;
445
    virDomainDefPtr oldDef = NULL;
446
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
447
    virCapsPtr caps = NULL;
D
Daniel Veillard 已提交
448

449 450 451 452
    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
        goto cleanup;

    if (!(def = virDomainDefParseString(xml, caps, driver->xmlopt,
M
Matthias Bolte 已提交
453
                                        1 << VIR_DOMAIN_VIRT_LXC,
454
                                        VIR_DOMAIN_XML_INACTIVE)))
455
        goto cleanup;
D
Daniel Veillard 已提交
456

457 458 459
    if (virDomainDefineXMLEnsureACL(conn, def) < 0)
        goto cleanup;

460 461 462
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
        goto cleanup;

463
    if ((def->nets != NULL) && !(cfg->have_netns)) {
464 465
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("System lacks NETNS support"));
466
        goto cleanup;
467 468
    }

469
    if (!(vm = virDomainObjListAdd(driver->domains, def,
470
                                   driver->xmlopt,
471
                                   0, &oldDef)))
472 473
        goto cleanup;
    def = NULL;
474
    vm->persistent = 1;
D
Daniel Veillard 已提交
475

476
    if (virDomainSaveConfig(cfg->configDir,
477
                            vm->newDef ? vm->newDef : vm->def) < 0) {
478
        virDomainObjListRemove(driver->domains, vm);
479
        vm = NULL;
480
        goto cleanup;
D
Daniel Veillard 已提交
481 482
    }

483 484
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
485
                                     !oldDef ?
486 487 488
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);

D
Daniel Veillard 已提交
489
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
490
    if (dom)
D
Daniel Veillard 已提交
491 492
        dom->id = vm->def->id;

493 494
cleanup:
    virDomainDefFree(def);
495
    virDomainDefFree(oldDef);
496
    if (vm)
497
        virObjectUnlock(vm);
498
    if (event)
499
        virDomainEventStateQueue(driver->domainEventState, event);
500
    virObjectUnref(caps);
501
    virObjectUnref(cfg);
D
Daniel Veillard 已提交
502 503 504
    return dom;
}

505 506
static int lxcDomainUndefineFlags(virDomainPtr dom,
                                  unsigned int flags)
D
Daniel Veillard 已提交
507
{
508
    virLXCDriverPtr driver = dom->conn->privateData;
509
    virDomainObjPtr vm;
510
    virDomainEventPtr event = NULL;
511
    int ret = -1;
512
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
D
Daniel Veillard 已提交
513

514 515
    virCheckFlags(0, -1);

M
Michal Privoznik 已提交
516
    if (!(vm = lxcDomObjFromDomain(dom)))
517
        goto cleanup;
D
Daniel Veillard 已提交
518

519 520 521
    if (virDomainUndefineFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

522
    if (!vm->persistent) {
523 524
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Cannot undefine transient domain"));
525
        goto cleanup;
526
    }
D
Daniel Veillard 已提交
527

528 529
    if (virDomainDeleteConfig(cfg->configDir,
                              cfg->autostartDir,
530 531
                              vm) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
532

533 534 535 536
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_UNDEFINED,
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);

537 538 539
    if (virDomainObjIsActive(vm)) {
        vm->persistent = 0;
    } else {
540
        virDomainObjListRemove(driver->domains, vm);
541 542 543
        vm = NULL;
    }

544
    ret = 0;
D
Daniel Veillard 已提交
545

546
cleanup:
547
    if (vm)
548
        virObjectUnlock(vm);
549
    if (event)
550
        virDomainEventStateQueue(driver->domainEventState, event);
551
    virObjectUnref(cfg);
552
    return ret;
D
Daniel Veillard 已提交
553 554
}

555 556 557 558 559
static int lxcDomainUndefine(virDomainPtr dom)
{
    return lxcDomainUndefineFlags(dom, 0);
}

D
Daniel Veillard 已提交
560 561 562
static int lxcDomainGetInfo(virDomainPtr dom,
                            virDomainInfoPtr info)
{
563
    virDomainObjPtr vm;
564
    int ret = -1;
565
    virLXCDomainObjPrivatePtr priv;
D
Daniel Veillard 已提交
566

M
Michal Privoznik 已提交
567
    if (!(vm = lxcDomObjFromDomain(dom)))
568
        goto cleanup;
D
Daniel Veillard 已提交
569

570 571
    priv = vm->privateData;

572 573 574
    if (virDomainGetInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
575
    info->state = virDomainObjGetState(vm, NULL);
D
Daniel Veillard 已提交
576

577
    if (!virDomainObjIsActive(vm)) {
D
Daniel Veillard 已提交
578
        info->cpuTime = 0;
579
        info->memory = vm->def->mem.cur_balloon;
D
Daniel Veillard 已提交
580
    } else {
581
        if (virCgroupGetCpuacctUsage(priv->cgroup, &(info->cpuTime)) < 0) {
582 583
            virReportError(VIR_ERR_OPERATION_FAILED,
                           "%s", _("Cannot read cputime for domain"));
R
Ryota Ozaki 已提交
584 585
            goto cleanup;
        }
586 587 588 589 590
        if (virCgroupGetMemoryUsage(priv->cgroup, &(info->memory)) < 0) {
            /* Don't fail if we can't read memory usage due to a lack of
             * kernel support */
            if (virLastErrorIsSystemErrno(ENOENT)) {
                virResetLastError();
591
                info->memory = 0;
592
            } else {
593
                goto cleanup;
594
            }
595
        }
D
Daniel Veillard 已提交
596 597
    }

598
    info->maxMem = vm->def->mem.max_balloon;
599
    info->nrVirtCpu = vm->def->vcpus;
600
    ret = 0;
D
Daniel Veillard 已提交
601

602
cleanup:
603
    if (vm)
604
        virObjectUnlock(vm);
605
    return ret;
D
Daniel Veillard 已提交
606 607
}

608 609 610 611 612 613 614 615 616 617 618
static int
lxcDomainGetState(virDomainPtr dom,
                  int *state,
                  int *reason,
                  unsigned int flags)
{
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

M
Michal Privoznik 已提交
619
    if (!(vm = lxcDomObjFromDomain(dom)))
620 621
        goto cleanup;

622 623 624
    if (virDomainGetStateEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
625
    *state = virDomainObjGetState(vm, reason);
626 627 628 629
    ret = 0;

cleanup:
    if (vm)
630
        virObjectUnlock(vm);
631 632 633
    return ret;
}

634
static char *lxcDomainGetOSType(virDomainPtr dom)
D
Daniel Veillard 已提交
635
{
636 637
    virDomainObjPtr vm;
    char *ret = NULL;
638

M
Michal Privoznik 已提交
639
    if (!(vm = lxcDomObjFromDomain(dom)))
640
        goto cleanup;
641

642 643 644 645 646
    if (virDomainGetOSTypeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

    if (VIR_STRDUP(ret, vm->def->os.type) < 0)
        goto cleanup;
647

648
cleanup:
649
    if (vm)
650
        virObjectUnlock(vm);
651
    return ret;
D
Daniel Veillard 已提交
652 653
}

R
Ryota Ozaki 已提交
654
/* Returns max memory in kb, 0 if error */
655 656 657
static unsigned long long
lxcDomainGetMaxMemory(virDomainPtr dom)
{
R
Ryota Ozaki 已提交
658
    virDomainObjPtr vm;
659
    unsigned long long ret = 0;
R
Ryota Ozaki 已提交
660

M
Michal Privoznik 已提交
661
    if (!(vm = lxcDomObjFromDomain(dom)))
R
Ryota Ozaki 已提交
662 663
        goto cleanup;

664 665 666
    if (virDomainGetMaxMemoryEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

667
    ret = vm->def->mem.max_balloon;
R
Ryota Ozaki 已提交
668 669 670

cleanup:
    if (vm)
671
        virObjectUnlock(vm);
R
Ryota Ozaki 已提交
672 673 674 675 676 677 678
    return ret;
}

static int lxcDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax) {
    virDomainObjPtr vm;
    int ret = -1;

M
Michal Privoznik 已提交
679
    if (!(vm = lxcDomObjFromDomain(dom)))
R
Ryota Ozaki 已提交
680 681
        goto cleanup;

682 683 684
    if (virDomainSetMaxMemoryEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

685
    if (newmax < vm->def->mem.cur_balloon) {
686 687
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("Cannot set max memory lower than current memory"));
R
Ryota Ozaki 已提交
688 689 690
        goto cleanup;
    }

691
    vm->def->mem.max_balloon = newmax;
R
Ryota Ozaki 已提交
692 693 694 695
    ret = 0;

cleanup:
    if (vm)
696
        virObjectUnlock(vm);
R
Ryota Ozaki 已提交
697 698 699 700 701 702
    return ret;
}

static int lxcDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
    virDomainObjPtr vm;
    int ret = -1;
703
    virLXCDomainObjPrivatePtr priv;
R
Ryota Ozaki 已提交
704

M
Michal Privoznik 已提交
705
    if (!(vm = lxcDomObjFromDomain(dom)))
R
Ryota Ozaki 已提交
706
        goto cleanup;
M
Michal Privoznik 已提交
707

708
    priv = vm->privateData;
R
Ryota Ozaki 已提交
709

710 711 712
    if (virDomainSetMemoryEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

713
    if (newmem > vm->def->mem.max_balloon) {
714 715
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("Cannot set memory higher than max memory"));
R
Ryota Ozaki 已提交
716 717 718
        goto cleanup;
    }

719
    if (!virDomainObjIsActive(vm)) {
720 721
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not running"));
722 723
        goto cleanup;
    }
724

725
    if (virCgroupSetMemory(priv->cgroup, newmem) < 0) {
726 727
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("Failed to set memory for domain"));
728 729 730
        goto cleanup;
    }

R
Ryota Ozaki 已提交
731 732 733 734
    ret = 0;

cleanup:
    if (vm)
735
        virObjectUnlock(vm);
R
Ryota Ozaki 已提交
736 737 738
    return ret;
}

739 740 741 742 743
static int
lxcDomainSetMemoryParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int nparams,
                             unsigned int flags)
744
{
745
    size_t i;
746 747
    virDomainObjPtr vm = NULL;
    int ret = -1;
748
    virLXCDomainObjPrivatePtr priv;
749

E
Eric Blake 已提交
750
    virCheckFlags(0, -1);
751 752 753 754 755 756 757 758
    if (virTypedParamsValidate(params, nparams,
                               VIR_DOMAIN_MEMORY_HARD_LIMIT,
                               VIR_TYPED_PARAM_ULLONG,
                               VIR_DOMAIN_MEMORY_SOFT_LIMIT,
                               VIR_TYPED_PARAM_ULLONG,
                               VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
                               VIR_TYPED_PARAM_ULLONG,
                               NULL) < 0)
759
        return -1;
E
Eric Blake 已提交
760

M
Michal Privoznik 已提交
761
    if (!(vm = lxcDomObjFromDomain(dom)))
762
        goto cleanup;
M
Michal Privoznik 已提交
763

764
    priv = vm->privateData;
765

766 767 768
    if (virDomainSetMemoryParametersEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

769 770
    ret = 0;
    for (i = 0; i < nparams; i++) {
771
        virTypedParameterPtr param = &params[i];
772 773

        if (STREQ(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT)) {
774
            if (virCgroupSetMemoryHardLimit(priv->cgroup, params[i].value.ul) < 0)
775 776
                ret = -1;
        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT)) {
777
            if (virCgroupSetMemorySoftLimit(priv->cgroup, params[i].value.ul) < 0)
778
                ret = -1;
779
        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT)) {
780
            if (virCgroupSetMemSwapHardLimit(priv->cgroup, params[i].value.ul) < 0)
781 782 783 784 785 786
                ret = -1;
        }
    }

cleanup:
    if (vm)
787
        virObjectUnlock(vm);
788 789 790
    return ret;
}

791 792 793 794 795
static int
lxcDomainGetMemoryParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int *nparams,
                             unsigned int flags)
796
{
797
    size_t i;
798
    virDomainObjPtr vm = NULL;
799
    unsigned long long val;
800
    int ret = -1;
801
    virLXCDomainObjPrivatePtr priv;
802

E
Eric Blake 已提交
803 804
    virCheckFlags(0, -1);

M
Michal Privoznik 已提交
805
    if (!(vm = lxcDomObjFromDomain(dom)))
806
        goto cleanup;
M
Michal Privoznik 已提交
807

808
    priv = vm->privateData;
809

810 811 812
    if (virDomainGetMemoryParametersEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

813 814 815 816 817 818 819
    if ((*nparams) == 0) {
        /* Current number of memory parameters supported by cgroups */
        *nparams = LXC_NB_MEM_PARAM;
        ret = 0;
        goto cleanup;
    }

820
    for (i = 0; i < LXC_NB_MEM_PARAM && i < *nparams; i++) {
821
        virTypedParameterPtr param = &params[i];
822 823
        val = 0;

824
        switch (i) {
825
        case 0: /* fill memory hard limit here */
826
            if (virCgroupGetMemoryHardLimit(priv->cgroup, &val) < 0)
827
                goto cleanup;
828 829
            if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_HARD_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
830
                goto cleanup;
831 832
            break;
        case 1: /* fill memory soft limit here */
833
            if (virCgroupGetMemorySoftLimit(priv->cgroup, &val) < 0)
834
                goto cleanup;
835 836
            if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_SOFT_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
837
                goto cleanup;
838 839
            break;
        case 2: /* fill swap hard limit here */
840
            if (virCgroupGetMemSwapHardLimit(priv->cgroup, &val) < 0)
841
                goto cleanup;
842 843 844
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
845
                goto cleanup;
846 847
            break;

848
        /* coverity[dead_error_begin] */
849 850 851 852 853 854
        default:
            break;
            /* should not hit here */
        }
    }

855 856
    if (*nparams > LXC_NB_MEM_PARAM)
        *nparams = LXC_NB_MEM_PARAM;
857 858
    ret = 0;

859 860
cleanup:
    if (vm)
861
        virObjectUnlock(vm);
862 863 864
    return ret;
}

865
static char *lxcDomainGetXMLDesc(virDomainPtr dom,
866
                                 unsigned int flags)
D
Daniel Veillard 已提交
867
{
868 869
    virDomainObjPtr vm;
    char *ret = NULL;
D
Daniel Veillard 已提交
870

871 872
    /* Flags checked by virDomainDefFormat */

M
Michal Privoznik 已提交
873
    if (!(vm = lxcDomObjFromDomain(dom)))
874
        goto cleanup;
D
Daniel Veillard 已提交
875

876 877 878
    if (virDomainGetXMLDescEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

879
    ret = virDomainDefFormat((flags & VIR_DOMAIN_XML_INACTIVE) &&
880 881 882 883
                             vm->newDef ? vm->newDef : vm->def,
                             flags);

cleanup:
884
    if (vm)
885
        virObjectUnlock(vm);
886
    return ret;
D
Daniel Veillard 已提交
887 888
}

889
/**
890
 * lxcDomainCreateWithFiles:
891
 * @dom: domain to start
892
 * @flags: Must be 0 for now
893 894 895 896 897
 *
 * Looks up domain and starts it.
 *
 * Returns 0 on success or -1 in case of error
 */
898 899 900 901
static int lxcDomainCreateWithFiles(virDomainPtr dom,
                                    unsigned int nfiles,
                                    int *files,
                                    unsigned int flags)
902
{
903
    virLXCDriverPtr driver = dom->conn->privateData;
904
    virDomainObjPtr vm;
905
    virDomainEventPtr event = NULL;
906
    int ret = -1;
907
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
908

909
    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, -1);
910

M
Michal Privoznik 已提交
911
    if (!(vm = lxcDomObjFromDomain(dom)))
912 913
        goto cleanup;

914
    if (virDomainCreateWithFilesEnsureACL(dom->conn, vm->def) < 0)
915 916
        goto cleanup;

917
    if ((vm->def->nets != NULL) && !(cfg->have_netns)) {
918 919
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("System lacks NETNS support"));
920 921 922
        goto cleanup;
    }

923
    if (virDomainObjIsActive(vm)) {
924 925
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is already running"));
926 927 928
        goto cleanup;
    }

929
    ret = virLXCProcessStart(dom->conn, driver, vm,
930
                             nfiles, files,
931 932
                             (flags & VIR_DOMAIN_START_AUTODESTROY),
                             VIR_DOMAIN_RUNNING_BOOTED);
933

934
    if (ret == 0) {
935 936 937
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STARTED,
                                         VIR_DOMAIN_EVENT_STARTED_BOOTED);
938 939 940 941
        virDomainAuditStart(vm, "booted", true);
    } else {
        virDomainAuditStart(vm, "booted", false);
    }
942

943
cleanup:
944
    if (vm)
945
        virObjectUnlock(vm);
946
    if (event)
947
        virDomainEventStateQueue(driver->domainEventState, event);
948
    virObjectUnref(cfg);
949
    return ret;
950 951
}

952
/**
953
 * lxcDomainCreate:
954 955 956 957 958 959
 * @dom: domain to start
 *
 * Looks up domain and starts it.
 *
 * Returns 0 on success or -1 in case of error
 */
960
static int lxcDomainCreate(virDomainPtr dom)
961
{
962 963 964 965 966 967 968 969 970 971 972 973 974 975 976
    return lxcDomainCreateWithFiles(dom, 0, NULL, 0);
}

/**
 * lxcDomainCreateWithFlags:
 * @dom: domain to start
 *
 * Looks up domain and starts it.
 *
 * Returns 0 on success or -1 in case of error
 */
static int lxcDomainCreateWithFlags(virDomainPtr dom,
                                    unsigned int flags)
{
    return lxcDomainCreateWithFiles(dom, 0, NULL, flags);
977 978
}

979
/**
980
 * lxcDomainCreateXML:
981 982
 * @conn: pointer to connection
 * @xml: XML definition of domain
983
 * @flags: Must be 0 for now
984 985 986 987 988 989
 *
 * Creates a domain based on xml and starts it
 *
 * Returns 0 on success or -1 in case of error
 */
static virDomainPtr
990 991 992 993 994
lxcDomainCreateXMLWithFiles(virConnectPtr conn,
                            const char *xml,
                            unsigned int nfiles,
                            int *files,
                            unsigned int flags) {
995
    virLXCDriverPtr driver = conn->privateData;
996
    virDomainObjPtr vm = NULL;
997
    virDomainDefPtr def = NULL;
998
    virDomainPtr dom = NULL;
999
    virDomainEventPtr event = NULL;
1000
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
1001
    virCapsPtr caps = NULL;
1002

1003
    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, NULL);
1004

1005 1006 1007 1008
    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
        goto cleanup;

    if (!(def = virDomainDefParseString(xml, caps, driver->xmlopt,
M
Matthias Bolte 已提交
1009
                                        1 << VIR_DOMAIN_VIRT_LXC,
1010
                                        VIR_DOMAIN_XML_INACTIVE)))
1011
        goto cleanup;
1012

1013
    if (virDomainCreateXMLWithFilesEnsureACL(conn, def) < 0)
1014 1015
        goto cleanup;

1016 1017 1018
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
        goto cleanup;

1019
    if ((def->nets != NULL) && !(cfg->have_netns)) {
1020 1021
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       "%s", _("System lacks NETNS support"));
1022
        goto cleanup;
1023 1024
    }

1025

1026
    if (!(vm = virDomainObjListAdd(driver->domains, def,
1027
                                   driver->xmlopt,
1028 1029
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
1030 1031
        goto cleanup;
    def = NULL;
1032

1033
    if (virLXCProcessStart(conn, driver, vm,
1034
                           nfiles, files,
1035 1036
                           (flags & VIR_DOMAIN_START_AUTODESTROY),
                           VIR_DOMAIN_RUNNING_BOOTED) < 0) {
1037
        virDomainAuditStart(vm, "booted", false);
1038
        virDomainObjListRemove(driver->domains, vm);
1039
        vm = NULL;
1040
        goto cleanup;
1041 1042
    }

1043 1044 1045
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
1046
    virDomainAuditStart(vm, "booted", true);
1047

1048
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1049
    if (dom)
1050 1051
        dom->id = vm->def->id;

1052 1053
cleanup:
    virDomainDefFree(def);
1054
    if (vm)
1055
        virObjectUnlock(vm);
1056
    if (event)
1057
        virDomainEventStateQueue(driver->domainEventState, event);
1058
    virObjectUnref(caps);
1059
    virObjectUnref(cfg);
1060 1061 1062
    return dom;
}

1063

1064 1065 1066 1067 1068 1069 1070 1071
static virDomainPtr
lxcDomainCreateXML(virConnectPtr conn,
                   const char *xml,
                   unsigned int flags) {
    return lxcDomainCreateXMLWithFiles(conn, xml, 0, NULL,  flags);
}


1072 1073
static int lxcDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr seclabel)
{
1074
    virLXCDriverPtr driver = dom->conn->privateData;
1075 1076 1077 1078 1079
    virDomainObjPtr vm;
    int ret = -1;

    memset(seclabel, 0, sizeof(*seclabel));

M
Michal Privoznik 已提交
1080
    if (!(vm = lxcDomObjFromDomain(dom)))
1081 1082
        goto cleanup;

1083 1084 1085
    if (virDomainGetSecurityLabelEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1086
    if (!virDomainVirtTypeToString(vm->def->virtType)) {
1087 1088 1089
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown virt type in domain definition '%d'"),
                       vm->def->virtType);
1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107
        goto cleanup;
    }

    /*
     * Theoretically, the pid can be replaced during this operation and
     * return the label of a different process.  If atomicity is needed,
     * further validation will be required.
     *
     * Comment from Dan Berrange:
     *
     *   Well the PID as stored in the virDomainObjPtr can't be changed
     *   because you've got a locked object.  The OS level PID could have
     *   exited, though and in extreme circumstances have cycled through all
     *   PIDs back to ours. We could sanity check that our PID still exists
     *   after reading the label, by checking that our FD connecting to the
     *   LXC monitor hasn't seen SIGHUP/ERR on poll().
     */
    if (virDomainObjIsActive(vm)) {
1108 1109 1110 1111 1112 1113 1114 1115
        virLXCDomainObjPrivatePtr priv = vm->privateData;

        if (!priv->initpid) {
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Init pid is not yet available"));
            goto cleanup;
        }

1116
        if (virSecurityManagerGetProcessLabel(driver->securityManager,
1117
                                              vm->def, priv->initpid, seclabel) < 0) {
1118 1119
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("Failed to get security label"));
1120 1121 1122 1123 1124 1125 1126 1127
            goto cleanup;
        }
    }

    ret = 0;

cleanup:
    if (vm)
1128
        virObjectUnlock(vm);
1129 1130 1131 1132 1133 1134
    return ret;
}

static int lxcNodeGetSecurityModel(virConnectPtr conn,
                                   virSecurityModelPtr secmodel)
{
1135
    virLXCDriverPtr driver = conn->privateData;
1136
    virCapsPtr caps = NULL;
1137 1138 1139 1140
    int ret = 0;

    memset(secmodel, 0, sizeof(*secmodel));

1141 1142 1143
    if (virNodeGetSecurityModelEnsureACL(conn) < 0)
        goto cleanup;

1144 1145 1146
    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
        goto cleanup;

1147
    /* we treat no driver as success, but simply return no data in *secmodel */
1148 1149
    if (caps->host.nsecModels == 0
        || caps->host.secModels[0].model == NULL)
1150 1151
        goto cleanup;

1152
    if (!virStrcpy(secmodel->model, caps->host.secModels[0].model,
1153
                   VIR_SECURITY_MODEL_BUFLEN)) {
1154 1155 1156
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security model string exceeds max %d bytes"),
                       VIR_SECURITY_MODEL_BUFLEN - 1);
1157 1158 1159 1160
        ret = -1;
        goto cleanup;
    }

1161
    if (!virStrcpy(secmodel->doi, caps->host.secModels[0].doi,
1162
                   VIR_SECURITY_DOI_BUFLEN)) {
1163 1164 1165
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security DOI string exceeds max %d bytes"),
                       VIR_SECURITY_DOI_BUFLEN-1);
1166 1167 1168 1169 1170
        ret = -1;
        goto cleanup;
    }

cleanup:
1171
    virObjectUnref(caps);
1172 1173 1174 1175
    return ret;
}


1176
static int
1177 1178 1179 1180
lxcConnectDomainEventRegister(virConnectPtr conn,
                              virConnectDomainEventCallback callback,
                              void *opaque,
                              virFreeCallback freecb)
1181
{
1182
    virLXCDriverPtr driver = conn->privateData;
1183 1184
    int ret;

1185 1186 1187
    if (virConnectDomainEventRegisterEnsureACL(conn) < 0)
        return -1;

1188 1189 1190
    ret = virDomainEventStateRegister(conn,
                                      driver->domainEventState,
                                      callback, opaque, freecb);
1191

1192
    return ret;
1193 1194
}

1195

1196
static int
1197 1198
lxcConnectDomainEventDeregister(virConnectPtr conn,
                                virConnectDomainEventCallback callback)
1199
{
1200
    virLXCDriverPtr driver = conn->privateData;
1201 1202
    int ret;

1203 1204 1205
    if (virConnectDomainEventDeregisterEnsureACL(conn) < 0)
        return -1;

1206 1207 1208
    ret = virDomainEventStateDeregister(conn,
                                        driver->domainEventState,
                                        callback);
1209 1210 1211 1212

    return ret;
}

1213 1214

static int
1215 1216 1217 1218 1219 1220
lxcConnectDomainEventRegisterAny(virConnectPtr conn,
                                 virDomainPtr dom,
                                 int eventID,
                                 virConnectDomainEventGenericCallback callback,
                                 void *opaque,
                                 virFreeCallback freecb)
1221
{
1222
    virLXCDriverPtr driver = conn->privateData;
1223 1224
    int ret;

1225 1226 1227
    if (virConnectDomainEventRegisterAnyEnsureACL(conn) < 0)
        return -1;

1228 1229 1230 1231
    if (virDomainEventStateRegisterID(conn,
                                      driver->domainEventState,
                                      dom, eventID,
                                      callback, opaque, freecb, &ret) < 0)
1232
        ret = -1;
1233 1234 1235 1236 1237 1238

    return ret;
}


static int
1239 1240
lxcConnectDomainEventDeregisterAny(virConnectPtr conn,
                                   int callbackID)
1241
{
1242
    virLXCDriverPtr driver = conn->privateData;
1243 1244
    int ret;

1245 1246 1247
    if (virConnectDomainEventDeregisterAnyEnsureACL(conn) < 0)
        return -1;

1248 1249 1250
    ret = virDomainEventStateDeregisterID(conn,
                                          driver->domainEventState,
                                          callbackID);
1251 1252 1253 1254 1255

    return ret;
}


1256
/**
1257
 * lxcDomainDestroyFlags:
1258
 * @dom: pointer to domain to destroy
1259
 * @flags: an OR'ed set of virDomainDestroyFlags
1260 1261 1262 1263 1264
 *
 * Sends SIGKILL to container root process to terminate the container
 *
 * Returns 0 on success or -1 in case of error
 */
1265 1266 1267
static int
lxcDomainDestroyFlags(virDomainPtr dom,
                      unsigned int flags)
1268
{
1269
    virLXCDriverPtr driver = dom->conn->privateData;
1270
    virDomainObjPtr vm;
1271
    virDomainEventPtr event = NULL;
1272
    int ret = -1;
1273
    virLXCDomainObjPrivatePtr priv;
1274

1275 1276
    virCheckFlags(0, -1);

M
Michal Privoznik 已提交
1277
    if (!(vm = lxcDomObjFromDomain(dom)))
1278
        goto cleanup;
1279

1280 1281 1282
    if (virDomainDestroyFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1283
    if (!virDomainObjIsActive(vm)) {
1284 1285
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not running"));
1286 1287 1288
        goto cleanup;
    }

1289
    priv = vm->privateData;
1290
    ret = virLXCProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED);
1291 1292 1293
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
1294
    priv->doneStopEvent = true;
1295
    virDomainAuditStop(vm, "destroyed");
1296
    if (!vm->persistent) {
1297
        virDomainObjListRemove(driver->domains, vm);
1298 1299
        vm = NULL;
    }
1300 1301

cleanup:
1302
    if (vm)
1303
        virObjectUnlock(vm);
1304
    if (event)
1305
        virDomainEventStateQueue(driver->domainEventState, event);
1306
    return ret;
1307
}
1308

1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322
/**
 * lxcDomainDestroy:
 * @dom: pointer to domain to destroy
 *
 * Sends SIGKILL to container root process to terminate the container
 *
 * Returns 0 on success or -1 in case of error
 */
static int
lxcDomainDestroy(virDomainPtr dom)
{
    return lxcDomainDestroyFlags(dom, 0);
}

1323 1324 1325 1326 1327
static int lxcCheckNetNsSupport(void)
{
    const char *argv[] = {"ip", "link", "set", "lo", "netns", "-1", NULL};
    int ip_rc;

1328
    if (virRun(argv, &ip_rc) < 0 ||
1329 1330
        !(WIFEXITED(ip_rc) && (WEXITSTATUS(ip_rc) != 255)))
        return 0;
1331

1332 1333
    if (lxcContainerAvailable(LXC_CONTAINER_FEATURE_NET) < 0)
        return 0;
1334

1335
    return 1;
1336 1337
}

1338

1339 1340
static virSecurityManagerPtr
lxcSecurityInit(virLXCDriverConfigPtr cfg)
1341
{
1342 1343
    VIR_INFO("lxcSecurityInit %s", cfg->securityDriverName);
    virSecurityManagerPtr mgr = virSecurityManagerNew(cfg->securityDriverName,
1344
                                                      LXC_DRIVER_NAME,
1345
                                                      false,
1346 1347
                                                      cfg->securityDefaultConfined,
                                                      cfg->securityRequireConfined);
1348 1349 1350
    if (!mgr)
        goto error;

1351
    return mgr;
1352 1353 1354

error:
    VIR_ERROR(_("Failed to initialize security drivers"));
1355
    virObjectUnref(mgr);
1356
    return NULL;
1357 1358 1359
}


1360 1361 1362
static int lxcStateInitialize(bool privileged,
                              virStateInhibitCallback callback ATTRIBUTE_UNUSED,
                              void *opaque ATTRIBUTE_UNUSED)
D
Daniel Veillard 已提交
1363
{
1364
    virCapsPtr caps = NULL;
1365
    char *ld;
1366
    virLXCDriverConfigPtr cfg = NULL;
1367 1368 1369 1370 1371 1372

    /* Valgrind gets very annoyed when we clone containers, so
     * disable LXC when under valgrind
     * XXX remove this when valgrind is fixed
     */
    ld = getenv("LD_PRELOAD");
1373
    if (ld && strstr(ld, "vgpreload")) {
1374
        VIR_INFO("Running under valgrind, disabling driver");
1375 1376
        return 0;
    }
1377

1378
    /* Check that the user is root, silently disable if not */
1379
    if (!privileged) {
1380
        VIR_INFO("Not running privileged, disabling driver");
1381 1382 1383 1384 1385
        return 0;
    }

    /* Check that this is a container enabled kernel */
    if (lxcContainerAvailable(0) < 0) {
1386
        VIR_INFO("LXC support not available in this kernel, disabling driver");
1387
        return 0;
1388 1389
    }

1390
    if (VIR_ALLOC(lxc_driver) < 0) {
1391 1392
        return -1;
    }
1393 1394 1395 1396
    if (virMutexInit(&lxc_driver->lock) < 0) {
        VIR_FREE(lxc_driver);
        return -1;
    }
D
Daniel Veillard 已提交
1397

1398
    if (!(lxc_driver->domains = virDomainObjListNew()))
1399 1400
        goto cleanup;

1401
    lxc_driver->domainEventState = virDomainEventStateNew();
1402
    if (!lxc_driver->domainEventState)
1403 1404
        goto cleanup;

1405 1406
    lxc_driver->hostsysinfo = virSysinfoRead();

1407 1408 1409 1410 1411
    if (!(lxc_driver->config = cfg = virLXCDriverConfigNew()))
        goto cleanup;

    cfg->log_libvirtd = 0; /* by default log to container logfile */
    cfg->have_netns = lxcCheckNetNsSupport();
D
Daniel Veillard 已提交
1412 1413

    /* Call function to load lxc driver configuration information */
1414
    if (virLXCLoadDriverConfig(cfg, SYSCONFDIR "/libvirt/lxc.conf") < 0)
1415
        goto cleanup;
D
Daniel Veillard 已提交
1416

1417
    if (!(lxc_driver->securityManager = lxcSecurityInit(cfg)))
1418 1419
        goto cleanup;

G
Guido Günther 已提交
1420 1421 1422
    if ((lxc_driver->activeUsbHostdevs = virUSBDeviceListNew()) == NULL)
        goto cleanup;

1423
    if ((virLXCDriverGetCapabilities(lxc_driver, true)) == NULL)
1424
        goto cleanup;
D
Daniel Veillard 已提交
1425

1426
    if (!(lxc_driver->xmlopt = lxcDomainXMLConfInit()))
1427
        goto cleanup;
1428

1429
    if (!(lxc_driver->closeCallbacks = virCloseCallbacksNew()))
1430 1431
        goto cleanup;

1432 1433 1434
    if (!(caps = virLXCDriverGetCapabilities(lxc_driver, false)))
        goto cleanup;

O
Osier Yang 已提交
1435
    /* Get all the running persistent or transient configs first */
1436
    if (virDomainObjListLoadAllConfigs(lxc_driver->domains,
1437
                                       cfg->stateDir,
1438
                                       NULL, 1,
1439
                                       caps,
1440
                                       lxc_driver->xmlopt,
1441
                                       1 << VIR_DOMAIN_VIRT_LXC,
1442
                                       NULL, NULL) < 0)
O
Osier Yang 已提交
1443 1444
        goto cleanup;

1445
    virLXCProcessReconnectAll(lxc_driver, lxc_driver->domains);
O
Osier Yang 已提交
1446 1447

    /* Then inactive persistent configs */
1448
    if (virDomainObjListLoadAllConfigs(lxc_driver->domains,
1449 1450
                                       cfg->configDir,
                                       cfg->autostartDir, 0,
1451
                                       caps,
1452
                                       lxc_driver->xmlopt,
1453
                                       1 << VIR_DOMAIN_VIRT_LXC,
1454
                                       NULL, NULL) < 0)
1455
        goto cleanup;
1456

1457
    virNWFilterRegisterCallbackDriver(&lxcCallbackDriver);
D
Daniel Veillard 已提交
1458 1459
    return 0;

1460
cleanup:
1461
    virObjectUnref(caps);
1462
    lxcStateCleanup();
1463
    return -1;
D
Daniel Veillard 已提交
1464 1465
}

1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478
/**
 * lxcStateAutoStart:
 *
 * Function to autostart the LXC daemons
 */
static void lxcStateAutoStart(void)
{
    if (!lxc_driver)
        return;

    virLXCProcessAutostartAll(lxc_driver);
}

1479 1480
static void lxcNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
{
1481
    virLXCDriverPtr driver = opaque;
1482 1483 1484 1485 1486 1487 1488

    if (newVM) {
        virDomainEventPtr event =
            virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED);
        if (event)
1489
            virDomainEventStateQueue(driver->domainEventState, event);
1490 1491 1492 1493
    }
}

/**
1494
 * lxcStateReload:
1495 1496 1497 1498 1499
 *
 * Function to restart the LXC driver, it will recheck the configuration
 * files and perform autostart
 */
static int
1500
lxcStateReload(void) {
1501
    virLXCDriverConfigPtr cfg = NULL;
1502
    virCapsPtr caps = NULL;
1503

1504 1505 1506
    if (!lxc_driver)
        return 0;

1507
    if (!(caps = virLXCDriverGetCapabilities(lxc_driver, false)))
1508 1509
        return -1;

1510 1511
    cfg = virLXCDriverGetConfig(lxc_driver);

1512
    virDomainObjListLoadAllConfigs(lxc_driver->domains,
1513 1514
                                   cfg->configDir,
                                   cfg->autostartDir, 0,
1515
                                   caps,
1516
                                   lxc_driver->xmlopt,
1517
                                   1 << VIR_DOMAIN_VIRT_LXC,
1518
                                   lxcNotifyLoadDomain, lxc_driver);
1519
    virObjectUnref(caps);
1520
    virObjectUnref(cfg);
1521 1522 1523
    return 0;
}

1524
static int lxcStateCleanup(void)
D
Daniel Veillard 已提交
1525
{
1526
    if (lxc_driver == NULL)
1527
        return -1;
1528

1529
    virNWFilterUnRegisterCallbackDriver(&lxcCallbackDriver);
1530
    virObjectUnref(lxc_driver->domains);
1531
    virDomainEventStateFree(lxc_driver->domainEventState);
1532

1533
    virObjectUnref(lxc_driver->closeCallbacks);
1534

1535 1536
    virSysinfoDefFree(lxc_driver->hostsysinfo);

G
Guido Günther 已提交
1537
    virObjectUnref(lxc_driver->activeUsbHostdevs);
1538
    virObjectUnref(lxc_driver->caps);
1539
    virObjectUnref(lxc_driver->securityManager);
1540
    virObjectUnref(lxc_driver->xmlopt);
1541
    virObjectUnref(lxc_driver->config);
1542
    virMutexDestroy(&lxc_driver->lock);
1543
    VIR_FREE(lxc_driver);
1544 1545 1546

    return 0;
}
D
Daniel Veillard 已提交
1547 1548


1549
static int lxcConnectGetVersion(virConnectPtr conn, unsigned long *version)
D
Dan Smith 已提交
1550 1551 1552
{
    struct utsname ver;

1553
    uname(&ver);
D
Dan Smith 已提交
1554

1555 1556 1557
    if (virConnectGetVersionEnsureACL(conn) < 0)
        return -1;

1558
    if (virParseVersionString(ver.release, version, true) < 0) {
1559
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Unknown release: %s"), ver.release);
D
Dan Smith 已提交
1560 1561 1562 1563 1564
        return -1;
    }

    return 0;
}
1565

1566

1567
static char *lxcConnectGetHostname(virConnectPtr conn)
1568
{
1569 1570 1571
    if (virConnectGetHostnameEnsureACL(conn) < 0)
        return NULL;

1572 1573 1574 1575
    return virGetHostname();
}


1576 1577
static char *lxcDomainGetSchedulerType(virDomainPtr dom,
                                       int *nparams)
1578
{
1579
    char *ret = NULL;
1580 1581
    virDomainObjPtr vm;
    virLXCDomainObjPrivatePtr priv;
1582

M
Michal Privoznik 已提交
1583
    if (!(vm = lxcDomObjFromDomain(dom)))
1584
        goto cleanup;
M
Michal Privoznik 已提交
1585

1586 1587
    priv = vm->privateData;

1588 1589 1590
    if (virDomainGetSchedulerTypeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1591 1592 1593 1594 1595 1596 1597 1598
    /* Domain not running, thus no cgroups - return defaults */
    if (!virDomainObjIsActive(vm)) {
        if (nparams)
            *nparams = 3;
        ignore_value(VIR_STRDUP(ret, "posix"));
        goto cleanup;
    }

1599
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
1600 1601
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPU controller is not mounted"));
1602 1603
        goto cleanup;
    }
1604

1605
    if (nparams) {
1606
        if (virCgroupSupportsCpuBW(priv->cgroup))
1607
            *nparams = 3;
1608 1609
        else
            *nparams = 1;
1610
    }
1611

1612
    ignore_value(VIR_STRDUP(ret, "posix"));
1613

1614
cleanup:
1615 1616
    if (vm)
        virObjectUnlock(vm);
1617 1618 1619 1620 1621 1622 1623 1624
    return ret;
}


static int
lxcGetVcpuBWLive(virCgroupPtr cgroup, unsigned long long *period,
                 long long *quota)
{
1625
    if (virCgroupGetCpuCfsPeriod(cgroup, period) < 0)
1626 1627
        return -1;

1628
    if (virCgroupGetCpuCfsQuota(cgroup, quota) < 0)
1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644
        return -1;

    return 0;
}


static int lxcSetVcpuBWLive(virCgroupPtr cgroup, unsigned long long period,
                            long long quota)
{
    unsigned long long old_period;

    if (period == 0 && quota == 0)
        return 0;

    if (period) {
        /* get old period, and we can rollback if set quota failed */
1645
        if (virCgroupGetCpuCfsPeriod(cgroup, &old_period) < 0)
1646 1647
            return -1;

1648
        if (virCgroupSetCpuCfsPeriod(cgroup, period) < 0)
1649 1650 1651 1652
            return -1;
    }

    if (quota) {
1653 1654
        if (virCgroupSetCpuCfsQuota(cgroup, quota) < 0)
            goto error;
1655 1656 1657 1658
    }

    return 0;

1659
error:
1660
    if (period) {
1661 1662 1663 1664 1665 1666
        virErrorPtr saved = virSaveLastError();
        virCgroupSetCpuCfsPeriod(cgroup, old_period);
        if (saved) {
            virSetError(saved);
            virFreeError(saved);
        }
1667 1668 1669
    }

    return -1;
1670 1671
}

1672

1673
static int
1674 1675 1676 1677
lxcDomainSetSchedulerParametersFlags(virDomainPtr dom,
                                     virTypedParameterPtr params,
                                     int nparams,
                                     unsigned int flags)
1678
{
1679
    virLXCDriverPtr driver = dom->conn->privateData;
1680
    virCapsPtr caps = NULL;
1681
    size_t i;
1682
    virDomainObjPtr vm = NULL;
1683
    virDomainDefPtr vmdef = NULL;
1684
    int ret = -1;
1685
    int rc;
1686
    virLXCDomainObjPrivatePtr priv;
1687
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
1688

1689 1690
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
1691 1692 1693 1694 1695 1696 1697 1698
    if (virTypedParamsValidate(params, nparams,
                               VIR_DOMAIN_SCHEDULER_CPU_SHARES,
                               VIR_TYPED_PARAM_ULLONG,
                               VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
                               VIR_TYPED_PARAM_ULLONG,
                               VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
                               VIR_TYPED_PARAM_LLONG,
                               NULL) < 0)
1699
        return -1;
1700

M
Michal Privoznik 已提交
1701
    if (!(vm = lxcDomObjFromDomain(dom)))
1702
        goto cleanup;
M
Michal Privoznik 已提交
1703

1704
    priv = vm->privateData;
1705

1706 1707 1708
    if (virDomainSetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

1709 1710 1711 1712
    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
        goto cleanup;

    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt,
1713
                                        vm, &flags, &vmdef) < 0)
E
Eric Blake 已提交
1714
        goto cleanup;
1715 1716 1717

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        /* Make a copy for updated domain. */
1718
        vmdef = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt);
1719 1720 1721 1722 1723
        if (!vmdef)
            goto cleanup;
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
1724
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
1725 1726
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup CPU controller is not mounted"));
1727 1728 1729
            goto cleanup;
        }
    }
1730 1731

    for (i = 0; i < nparams; i++) {
1732
        virTypedParameterPtr param = &params[i];
1733

1734 1735
        if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_CPU_SHARES)) {
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
1736
                if (virCgroupSetCpuShares(priv->cgroup, params[i].value.ul) < 0)
1737 1738 1739 1740 1741 1742 1743 1744 1745 1746
                    goto cleanup;

                vm->def->cputune.shares = params[i].value.ul;
            }

            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
                vmdef->cputune.shares = params[i].value.ul;
            }
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_PERIOD)) {
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
1747
                rc = lxcSetVcpuBWLive(priv->cgroup, params[i].value.ul, 0);
1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759
                if (rc != 0)
                    goto cleanup;

                if (params[i].value.ul)
                    vm->def->cputune.period = params[i].value.ul;
            }

            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
                vmdef->cputune.period = params[i].value.ul;
            }
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_QUOTA)) {
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
1760
                rc = lxcSetVcpuBWLive(priv->cgroup, 0, params[i].value.l);
1761 1762 1763 1764 1765 1766 1767 1768 1769 1770
                if (rc != 0)
                    goto cleanup;

                if (params[i].value.l)
                    vm->def->cputune.quota = params[i].value.l;
            }

            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
                vmdef->cputune.quota = params[i].value.l;
            }
1771
        }
1772
    }
1773

1774
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
1775
        goto cleanup;
1776

1777 1778

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
1779
        rc = virDomainSaveConfig(cfg->configDir, vmdef);
1780
        if (rc < 0)
1781
            goto cleanup;
1782

1783
        virDomainObjAssignDef(vm, vmdef, false, NULL);
1784
        vmdef = NULL;
1785
    }
1786

1787
    ret = 0;
1788

1789
cleanup:
1790
    virDomainDefFree(vmdef);
1791
    if (vm)
1792
        virObjectUnlock(vm);
1793
    virObjectUnref(caps);
1794
    virObjectUnref(cfg);
1795
    return ret;
1796 1797
}

1798
static int
1799 1800 1801
lxcDomainSetSchedulerParameters(virDomainPtr domain,
                                virTypedParameterPtr params,
                                int nparams)
1802
{
1803
    return lxcDomainSetSchedulerParametersFlags(domain, params, nparams, 0);
1804 1805 1806
}

static int
1807 1808 1809 1810
lxcDomainGetSchedulerParametersFlags(virDomainPtr dom,
                                     virTypedParameterPtr params,
                                     int *nparams,
                                     unsigned int flags)
1811
{
1812
    virLXCDriverPtr driver = dom->conn->privateData;
1813
    virCapsPtr caps = NULL;
1814
    virDomainObjPtr vm = NULL;
E
Eric Blake 已提交
1815
    virDomainDefPtr persistentDef;
1816 1817 1818
    unsigned long long shares = 0;
    unsigned long long period = 0;
    long long quota = 0;
1819
    int ret = -1;
1820 1821 1822
    int rc;
    bool cpu_bw_status = false;
    int saved_nparams = 0;
1823
    virLXCDomainObjPrivatePtr priv;
1824

1825 1826
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
1827

M
Michal Privoznik 已提交
1828
    if (!(vm = lxcDomObjFromDomain(dom)))
1829
        goto cleanup;
M
Michal Privoznik 已提交
1830

1831 1832
    priv = vm->privateData;

1833 1834 1835
    if (virDomainGetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1836 1837
    if (*nparams > 1)
        cpu_bw_status = virCgroupSupportsCpuBW(priv->cgroup);
1838

1839 1840 1841 1842
    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
        goto cleanup;

    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt,
1843
                                        vm, &flags, &persistentDef) < 0)
E
Eric Blake 已提交
1844
        goto cleanup;
1845 1846

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
E
Eric Blake 已提交
1847
        shares = persistentDef->cputune.shares;
1848
        if (*nparams > 1) {
E
Eric Blake 已提交
1849 1850
            period = persistentDef->cputune.period;
            quota = persistentDef->cputune.quota;
1851
            cpu_bw_status = true; /* Allow copy of data to params[] */
1852 1853 1854 1855
        }
        goto out;
    }

1856
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
1857 1858
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPU controller is not mounted"));
1859
        goto cleanup;
1860 1861
    }

1862
    if (virCgroupGetCpuShares(priv->cgroup, &shares) < 0)
1863
        goto cleanup;
1864 1865

    if (*nparams > 1 && cpu_bw_status) {
1866
        rc = lxcGetVcpuBWLive(priv->cgroup, &period, &quota);
1867 1868 1869 1870
        if (rc != 0)
            goto cleanup;
    }
out:
1871 1872
    if (virTypedParameterAssign(&params[0], VIR_DOMAIN_SCHEDULER_CPU_SHARES,
                                VIR_TYPED_PARAM_ULLONG, shares) < 0)
C
Chris Lalancette 已提交
1873
        goto cleanup;
1874 1875 1876 1877
    saved_nparams++;

    if (cpu_bw_status) {
        if (*nparams > saved_nparams) {
1878 1879 1880
            if (virTypedParameterAssign(&params[1],
                                        VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
                                        VIR_TYPED_PARAM_ULLONG, period) < 0)
1881 1882 1883 1884 1885
                goto cleanup;
            saved_nparams++;
        }

        if (*nparams > saved_nparams) {
1886 1887 1888
            if (virTypedParameterAssign(&params[2],
                                        VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
                                        VIR_TYPED_PARAM_LLONG, quota) < 0)
1889 1890 1891 1892 1893 1894 1895
                goto cleanup;
            saved_nparams++;
        }
    }

    *nparams = saved_nparams;

1896
    ret = 0;
1897

1898
cleanup:
1899
    if (vm)
1900
        virObjectUnlock(vm);
1901
    virObjectUnref(caps);
1902
    return ret;
1903 1904
}

1905
static int
1906 1907 1908
lxcDomainGetSchedulerParameters(virDomainPtr domain,
                                virTypedParameterPtr params,
                                int *nparams)
1909
{
1910
    return lxcDomainGetSchedulerParametersFlags(domain, params, nparams, 0);
1911 1912
}

1913

1914 1915 1916 1917 1918
static int
lxcDomainSetBlkioParameters(virDomainPtr dom,
                            virTypedParameterPtr params,
                            int nparams,
                            unsigned int flags)
1919
{
1920
    virLXCDriverPtr driver = dom->conn->privateData;
1921
    virCapsPtr caps = NULL;
1922
    size_t i;
1923 1924 1925
    virDomainObjPtr vm = NULL;
    virDomainDefPtr persistentDef = NULL;
    int ret = -1;
1926
    virLXCDomainObjPrivatePtr priv;
1927
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
1928 1929 1930

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
1931 1932 1933 1934
    if (virTypedParamsValidate(params, nparams,
                               VIR_DOMAIN_BLKIO_WEIGHT,
                               VIR_TYPED_PARAM_UINT,
                               NULL) < 0)
1935 1936
        return -1;

M
Michal Privoznik 已提交
1937
    if (!(vm = lxcDomObjFromDomain(dom)))
1938
        goto cleanup;
M
Michal Privoznik 已提交
1939

1940
    priv = vm->privateData;
1941

1942 1943 1944
    if (virDomainSetBlkioParametersEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

1945 1946 1947 1948
    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
        goto cleanup;

    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt,
1949
                                        vm, &flags, &persistentDef) < 0)
E
Eric Blake 已提交
1950
        goto cleanup;
1951 1952

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
1953
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) {
1954 1955
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("blkio cgroup isn't mounted"));
1956 1957 1958 1959 1960 1961 1962 1963
            goto cleanup;
        }

        for (i = 0; i < nparams; i++) {
            virTypedParameterPtr param = &params[i];

            if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
                if (params[i].value.ui > 1000 || params[i].value.ui < 100) {
1964 1965
                    virReportError(VIR_ERR_INVALID_ARG, "%s",
                                   _("out of blkio weight range."));
E
Eric Blake 已提交
1966
                    goto cleanup;
1967 1968
                }

1969
                if (virCgroupSetBlkioWeight(priv->cgroup, params[i].value.ui) < 0)
E
Eric Blake 已提交
1970
                    goto cleanup;
1971 1972
            }
        }
E
Eric Blake 已提交
1973 1974
    }
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
1975 1976 1977 1978 1979 1980 1981 1982
        /* Clang can't see that if we get here, persistentDef was set.  */
        sa_assert(persistentDef);

        for (i = 0; i < nparams; i++) {
            virTypedParameterPtr param = &params[i];

            if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
                if (params[i].value.ui > 1000 || params[i].value.ui < 100) {
1983 1984
                    virReportError(VIR_ERR_INVALID_ARG, "%s",
                                   _("out of blkio weight range."));
E
Eric Blake 已提交
1985
                    goto cleanup;
1986 1987 1988 1989 1990 1991
                }

                persistentDef->blkio.weight = params[i].value.ui;
            }
        }

1992
        if (virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
E
Eric Blake 已提交
1993
            goto cleanup;
1994 1995
    }

E
Eric Blake 已提交
1996
    ret = 0;
1997 1998
cleanup:
    if (vm)
1999
        virObjectUnlock(vm);
2000
    virObjectUnref(caps);
2001
    virObjectUnref(cfg);
2002 2003 2004 2005 2006
    return ret;
}


#define LXC_NB_BLKIO_PARAM  1
2007 2008 2009 2010 2011
static int
lxcDomainGetBlkioParameters(virDomainPtr dom,
                            virTypedParameterPtr params,
                            int *nparams,
                            unsigned int flags)
2012
{
2013
    virLXCDriverPtr driver = dom->conn->privateData;
2014
    virCapsPtr caps = NULL;
2015
    size_t i;
2016 2017 2018 2019
    virDomainObjPtr vm = NULL;
    virDomainDefPtr persistentDef = NULL;
    unsigned int val;
    int ret = -1;
2020
    virLXCDomainObjPrivatePtr priv;
2021 2022 2023 2024

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

M
Michal Privoznik 已提交
2025
    if (!(vm = lxcDomObjFromDomain(dom)))
2026
        goto cleanup;
M
Michal Privoznik 已提交
2027

2028
    priv = vm->privateData;
2029

2030 2031 2032
    if (virDomainGetBlkioParametersEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2033 2034 2035 2036 2037 2038 2039
    if ((*nparams) == 0) {
        /* Current number of blkio parameters supported by cgroups */
        *nparams = LXC_NB_BLKIO_PARAM;
        ret = 0;
        goto cleanup;
    }

2040 2041 2042 2043
    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
        goto cleanup;

    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt,
2044
                                        vm, &flags, &persistentDef) < 0)
E
Eric Blake 已提交
2045
        goto cleanup;
2046 2047

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
2048
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) {
2049 2050
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("blkio cgroup isn't mounted"));
2051 2052 2053 2054 2055 2056 2057 2058 2059
            goto cleanup;
        }

        for (i = 0; i < *nparams && i < LXC_NB_BLKIO_PARAM; i++) {
            virTypedParameterPtr param = &params[i];
            val = 0;

            switch (i) {
            case 0: /* fill blkio weight here */
2060
                if (virCgroupGetBlkioWeight(priv->cgroup, &val) < 0)
2061
                    goto cleanup;
2062 2063
                if (virTypedParameterAssign(param, VIR_DOMAIN_BLKIO_WEIGHT,
                                            VIR_TYPED_PARAM_UINT, val) < 0)
2064 2065 2066
                    goto cleanup;
                break;

2067
            /* coverity[dead_error_begin] */
2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078
            default:
                break;
                /* should not hit here */
            }
        }
    } else if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        for (i = 0; i < *nparams && i < LXC_NB_BLKIO_PARAM; i++) {
            virTypedParameterPtr param = &params[i];

            switch (i) {
            case 0: /* fill blkio weight here */
2079 2080 2081
                if (virTypedParameterAssign(param, VIR_DOMAIN_BLKIO_WEIGHT,
                                            VIR_TYPED_PARAM_UINT,
                                            persistentDef->blkio.weight) < 0)
2082 2083 2084
                    goto cleanup;
                break;

2085
            /* coverity[dead_error_begin] */
2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098
            default:
                break;
                /* should not hit here */
            }
        }
    }

    if (LXC_NB_BLKIO_PARAM < *nparams)
        *nparams = LXC_NB_BLKIO_PARAM;
    ret = 0;

cleanup:
    if (vm)
2099
        virObjectUnlock(vm);
2100
    virObjectUnref(caps);
2101 2102 2103 2104
    return ret;
}


2105 2106 2107 2108 2109 2110 2111
#ifdef __linux__
static int
lxcDomainInterfaceStats(virDomainPtr dom,
                        const char *path,
                        struct _virDomainInterfaceStats *stats)
{
    virDomainObjPtr vm;
2112
    size_t i;
2113 2114
    int ret = -1;

M
Michal Privoznik 已提交
2115
    if (!(vm = lxcDomObjFromDomain(dom)))
2116 2117
        goto cleanup;

2118 2119 2120
    if (virDomainInterfaceStatsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2121
    if (!virDomainObjIsActive(vm)) {
2122 2123
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not running"));
2124 2125 2126 2127
        goto cleanup;
    }

    /* Check the path is one of the domain's network interfaces. */
2128
    for (i = 0; i < vm->def->nnets; i++) {
2129 2130 2131 2132 2133 2134 2135 2136
        if (vm->def->nets[i]->ifname &&
            STREQ(vm->def->nets[i]->ifname, path)) {
            ret = 0;
            break;
        }
    }

    if (ret == 0)
2137
        ret = linuxDomainInterfaceStats(path, stats);
2138
    else
2139 2140
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Invalid path, '%s' is not a known interface"), path);
2141 2142 2143

cleanup:
    if (vm)
2144
        virObjectUnlock(vm);
2145 2146 2147 2148 2149 2150 2151
    return ret;
}
#else
static int
lxcDomainInterfaceStats(virDomainPtr dom,
                        const char *path ATTRIBUTE_UNUSED,
                        struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED)
A
Alex Jia 已提交
2152
{
2153
    virReportError(VIR_ERR_NO_SUPPORT, "%s", __FUNCTION__);
2154 2155 2156 2157
    return -1;
}
#endif

2158 2159 2160 2161 2162
static int lxcDomainGetAutostart(virDomainPtr dom,
                                   int *autostart) {
    virDomainObjPtr vm;
    int ret = -1;

M
Michal Privoznik 已提交
2163
    if (!(vm = lxcDomObjFromDomain(dom)))
2164 2165
        goto cleanup;

2166 2167 2168
    if (virDomainGetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2169 2170 2171 2172 2173
    *autostart = vm->autostart;
    ret = 0;

cleanup:
    if (vm)
2174
        virObjectUnlock(vm);
2175 2176 2177 2178
    return ret;
}

static int lxcDomainSetAutostart(virDomainPtr dom,
2179 2180
                                   int autostart)
{
2181
    virLXCDriverPtr driver = dom->conn->privateData;
2182 2183 2184
    virDomainObjPtr vm;
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;
2185
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
2186

M
Michal Privoznik 已提交
2187
    if (!(vm = lxcDomObjFromDomain(dom)))
2188 2189
        goto cleanup;

2190 2191 2192
    if (virDomainSetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2193
    if (!vm->persistent) {
2194 2195
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Cannot set autostart for transient domain"));
2196 2197 2198 2199 2200
        goto cleanup;
    }

    autostart = (autostart != 0);

2201 2202 2203 2204
    if (vm->autostart == autostart) {
        ret = 0;
        goto cleanup;
    }
2205

2206
    configFile = virDomainConfigFile(cfg->configDir,
2207 2208 2209
                                     vm->def->name);
    if (configFile == NULL)
        goto cleanup;
2210
    autostartLink = virDomainConfigFile(cfg->autostartDir,
2211 2212 2213
                                        vm->def->name);
    if (autostartLink == NULL)
        goto cleanup;
2214

2215
    if (autostart) {
2216
        if (virFileMakePath(cfg->autostartDir) < 0) {
2217
            virReportSystemError(errno,
2218
                                 _("Cannot create autostart directory %s"),
2219
                                 cfg->autostartDir);
2220
            goto cleanup;
2221 2222
        }

2223
        if (symlink(configFile, autostartLink) < 0) {
2224
            virReportSystemError(errno,
2225 2226 2227 2228 2229 2230
                                 _("Failed to create symlink '%s to '%s'"),
                                 autostartLink, configFile);
            goto cleanup;
        }
    } else {
        if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
2231
            virReportSystemError(errno,
2232 2233 2234 2235
                                 _("Failed to delete symlink '%s'"),
                                 autostartLink);
            goto cleanup;
        }
2236
    }
2237 2238

    vm->autostart = autostart;
2239 2240 2241 2242 2243 2244
    ret = 0;

cleanup:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
    if (vm)
2245
        virObjectUnlock(vm);
2246
    virObjectUnref(cfg);
2247 2248 2249
    return ret;
}

2250
static int lxcFreezeContainer(virDomainObjPtr vm)
R
Ryota Ozaki 已提交
2251 2252 2253 2254 2255 2256 2257
{
    int timeout = 1000; /* In milliseconds */
    int check_interval = 1; /* In milliseconds */
    int exp = 10;
    int waited_time = 0;
    int ret = -1;
    char *state = NULL;
2258
    virLXCDomainObjPrivatePtr priv = vm->privateData;
2259

R
Ryota Ozaki 已提交
2260 2261 2262 2263 2264 2265 2266 2267 2268
    while (waited_time < timeout) {
        int r;
        /*
         * Writing "FROZEN" to the "freezer.state" freezes the group,
         * i.e., the container, temporarily transiting "FREEZING" state.
         * Once the freezing is completed, the state of the group transits
         * to "FROZEN".
         * (see linux-2.6/Documentation/cgroups/freezer-subsystem.txt)
         */
2269
        r = virCgroupSetFreezerState(priv->cgroup, "FROZEN");
R
Ryota Ozaki 已提交
2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280

        /*
         * Returning EBUSY explicitly indicates that the group is
         * being freezed but incomplete and other errors are true
         * errors.
         */
        if (r < 0 && r != -EBUSY) {
            VIR_DEBUG("Writing freezer.state failed with errno: %d", r);
            goto error;
        }
        if (r == -EBUSY)
2281
            VIR_DEBUG("Writing freezer.state gets EBUSY");
R
Ryota Ozaki 已提交
2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295

        /*
         * Unfortunately, returning 0 (success) is likely to happen
         * even when the freezing has not been completed. Sometimes
         * the state of the group remains "FREEZING" like when
         * returning -EBUSY and even worse may never transit to
         * "FROZEN" even if writing "FROZEN" again.
         *
         * So we don't trust the return value anyway and always
         * decide that the freezing has been complete only with
         * the state actually transit to "FROZEN".
         */
        usleep(check_interval * 1000);

2296
        r = virCgroupGetFreezerState(priv->cgroup, &state);
R
Ryota Ozaki 已提交
2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320

        if (r < 0) {
            VIR_DEBUG("Reading freezer.state failed with errno: %d", r);
            goto error;
        }
        VIR_DEBUG("Read freezer.state: %s", state);

        if (STREQ(state, "FROZEN")) {
            ret = 0;
            goto cleanup;
        }

        waited_time += check_interval;
        /*
         * Increasing check_interval exponentially starting with
         * small initial value treats nicely two cases; One is
         * a container is under no load and waiting for long period
         * makes no sense. The other is under heavy load. The container
         * may stay longer time in FREEZING or never transit to FROZEN.
         * In that case, eager polling will just waste CPU time.
         */
        check_interval *= exp;
        VIR_FREE(state);
    }
2321
    VIR_DEBUG("lxcFreezeContainer timeout");
R
Ryota Ozaki 已提交
2322 2323 2324 2325 2326 2327
error:
    /*
     * If timeout or an error on reading the state occurs,
     * activate the group again and return an error.
     * This is likely to fall the group back again gracefully.
     */
2328
    virCgroupSetFreezerState(priv->cgroup, "THAWED");
R
Ryota Ozaki 已提交
2329 2330 2331 2332 2333 2334 2335 2336 2337
    ret = -1;

cleanup:
    VIR_FREE(state);
    return ret;
}

static int lxcDomainSuspend(virDomainPtr dom)
{
2338
    virLXCDriverPtr driver = dom->conn->privateData;
R
Ryota Ozaki 已提交
2339 2340 2341
    virDomainObjPtr vm;
    virDomainEventPtr event = NULL;
    int ret = -1;
2342
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
2343

M
Michal Privoznik 已提交
2344
    if (!(vm = lxcDomObjFromDomain(dom)))
R
Ryota Ozaki 已提交
2345 2346
        goto cleanup;

2347 2348 2349
    if (virDomainSuspendEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
2350
    if (!virDomainObjIsActive(vm)) {
2351 2352
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not running"));
R
Ryota Ozaki 已提交
2353 2354 2355
        goto cleanup;
    }

J
Jiri Denemark 已提交
2356
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) {
2357
        if (lxcFreezeContainer(vm) < 0) {
2358 2359
            virReportError(VIR_ERR_OPERATION_FAILED,
                           "%s", _("Suspend operation failed"));
R
Ryota Ozaki 已提交
2360 2361
            goto cleanup;
        }
J
Jiri Denemark 已提交
2362
        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
R
Ryota Ozaki 已提交
2363 2364 2365 2366 2367 2368

        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
    }

2369
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
R
Ryota Ozaki 已提交
2370 2371 2372 2373 2374
        goto cleanup;
    ret = 0;

cleanup:
    if (event)
2375
        virDomainEventStateQueue(driver->domainEventState, event);
R
Ryota Ozaki 已提交
2376
    if (vm)
2377
        virObjectUnlock(vm);
2378
    virObjectUnref(cfg);
R
Ryota Ozaki 已提交
2379 2380 2381 2382 2383
    return ret;
}

static int lxcDomainResume(virDomainPtr dom)
{
2384
    virLXCDriverPtr driver = dom->conn->privateData;
R
Ryota Ozaki 已提交
2385 2386 2387
    virDomainObjPtr vm;
    virDomainEventPtr event = NULL;
    int ret = -1;
2388
    virLXCDomainObjPrivatePtr priv;
2389
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
2390

M
Michal Privoznik 已提交
2391
    if (!(vm = lxcDomObjFromDomain(dom)))
R
Ryota Ozaki 已提交
2392 2393
        goto cleanup;

2394 2395
    priv = vm->privateData;

2396 2397 2398
    if (virDomainResumeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
2399
    if (!virDomainObjIsActive(vm)) {
2400 2401
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not running"));
R
Ryota Ozaki 已提交
2402 2403 2404
        goto cleanup;
    }

J
Jiri Denemark 已提交
2405
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
2406
        if (virCgroupSetFreezerState(priv->cgroup, "THAWED") < 0) {
2407 2408
            virReportError(VIR_ERR_OPERATION_FAILED,
                           "%s", _("Resume operation failed"));
R
Ryota Ozaki 已提交
2409 2410
            goto cleanup;
        }
J
Jiri Denemark 已提交
2411 2412
        virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
                             VIR_DOMAIN_RUNNING_UNPAUSED);
R
Ryota Ozaki 已提交
2413 2414 2415 2416 2417 2418

        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
    }

2419
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
R
Ryota Ozaki 已提交
2420 2421 2422 2423 2424
        goto cleanup;
    ret = 0;

cleanup:
    if (event)
2425
        virDomainEventStateQueue(driver->domainEventState, event);
R
Ryota Ozaki 已提交
2426
    if (vm)
2427
        virObjectUnlock(vm);
2428
    virObjectUnref(cfg);
R
Ryota Ozaki 已提交
2429 2430 2431
    return ret;
}

2432 2433
static int
lxcDomainOpenConsole(virDomainPtr dom,
2434
                      const char *dev_name,
2435 2436 2437 2438 2439 2440
                      virStreamPtr st,
                      unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainChrDefPtr chr = NULL;
2441
    size_t i;
2442 2443 2444

    virCheckFlags(0, -1);

M
Michal Privoznik 已提交
2445
    if (!(vm = lxcDomObjFromDomain(dom)))
2446 2447
        goto cleanup;

2448 2449 2450
    if (virDomainOpenConsoleEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2451
    if (!virDomainObjIsActive(vm)) {
2452 2453
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
2454 2455 2456
        goto cleanup;
    }

2457
    if (dev_name) {
2458
        for (i = 0; i < vm->def->nconsoles; i++) {
2459 2460 2461 2462 2463 2464
            if (vm->def->consoles[i]->info.alias &&
                STREQ(vm->def->consoles[i]->info.alias, dev_name)) {
                chr = vm->def->consoles[i];
                break;
            }
        }
2465
    } else {
2466 2467
        if (vm->def->nconsoles)
            chr = vm->def->consoles[0];
2468 2469 2470 2471 2472
        else if (vm->def->nserials)
            chr = vm->def->serials[0];
    }

    if (!chr) {
2473 2474 2475
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot find console device '%s'"),
                       dev_name ? dev_name : _("default"));
2476 2477 2478
        goto cleanup;
    }

2479
    if (chr->source.type != VIR_DOMAIN_CHR_TYPE_PTY) {
2480 2481
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("character device %s is not using a PTY"), dev_name);
2482 2483 2484
        goto cleanup;
    }

2485
    if (virFDStreamOpenFile(st, chr->source.data.file.path,
E
Eric Blake 已提交
2486
                            0, 0, O_RDWR) < 0)
2487 2488 2489 2490 2491
        goto cleanup;

    ret = 0;
cleanup:
    if (vm)
2492
        virObjectUnlock(vm);
2493 2494 2495
    return ret;
}

2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516

static int
lxcDomainSendProcessSignal(virDomainPtr dom,
                           long long pid_value,
                           unsigned int signum,
                           unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    virLXCDomainObjPrivatePtr priv;
    pid_t victim;
    int ret = -1;

    virCheckFlags(0, -1);

    if (signum >= VIR_DOMAIN_PROCESS_SIGNAL_LAST) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("signum value %d is out of range"),
                       signum);
        return -1;
    }

M
Michal Privoznik 已提交
2517
    if (!(vm = lxcDomObjFromDomain(dom)))
2518
        goto cleanup;
M
Michal Privoznik 已提交
2519

2520 2521
    priv = vm->privateData;

2522 2523 2524
    if (virDomainSendProcessSignalEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
        goto cleanup;
    }

    /*
     * XXX if the kernel has /proc/$PID/ns/pid we can
     * switch into container namespace & that way be
     * able to kill any PID. Alternatively if there
     * is a way to find a mapping of guest<->host PIDs
     * we can kill that way.
     */
    if (pid_value != 1) {
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("Only the init process may be killed"));
        goto cleanup;
    }

    if (!priv->initpid) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Init pid is not yet available"));
        goto cleanup;
    }
    victim = priv->initpid;

    /* We're relying on fact libvirt header signal numbers
     * are taken from Linux, to avoid mapping
     */
    if (kill(victim, signum) < 0) {
        virReportSystemError(errno,
                             _("Unable to send %d signal to process %d"),
                             signum, victim);
        goto cleanup;
    }

    ret = 0;

cleanup:
    if (vm)
2565
        virObjectUnlock(vm);
2566 2567 2568 2569
    return ret;
}


2570
static int
2571 2572
lxcConnectListAllDomains(virConnectPtr conn,
                         virDomainPtr **domains,
2573 2574
                  unsigned int flags)
{
2575
    virLXCDriverPtr driver = conn->privateData;
2576 2577
    int ret = -1;

O
Osier Yang 已提交
2578
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
2579

2580 2581 2582
    if (virConnectListAllDomainsEnsureACL(conn) < 0)
        return -1;

2583 2584
    ret = virDomainObjListExport(driver->domains, conn, domains,
                                 virConnectListAllDomainsCheckACL, flags);
2585 2586 2587
    return ret;
}

2588

2589 2590 2591 2592 2593 2594 2595 2596
static int
lxcDomainShutdownFlags(virDomainPtr dom,
                       unsigned int flags)
{
    virLXCDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
    char *vroot = NULL;
    int ret = -1;
2597
    int rc;
2598 2599 2600 2601

    virCheckFlags(VIR_DOMAIN_SHUTDOWN_INITCTL |
                  VIR_DOMAIN_SHUTDOWN_SIGNAL, -1);

M
Michal Privoznik 已提交
2602
    if (!(vm = lxcDomObjFromDomain(dom)))
2603 2604 2605 2606
        goto cleanup;

    priv = vm->privateData;

2607 2608 2609
    if (virDomainShutdownFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not running"));
        goto cleanup;
    }

    if (priv->initpid == 0) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Init process ID is not yet known"));
        goto cleanup;
    }

    if (virAsprintf(&vroot, "/proc/%llu/root",
2623
                    (unsigned long long)priv->initpid) < 0)
2624 2625
        goto cleanup;

2626 2627 2628 2629
    if (flags == 0 ||
        (flags & VIR_DOMAIN_SHUTDOWN_INITCTL)) {
        if ((rc = virInitctlSetRunLevel(VIR_INITCTL_RUNLEVEL_POWEROFF,
                                        vroot)) < 0) {
2630
            goto cleanup;
2631 2632 2633
        }
        if (rc == 0 && flags != 0 &&
            ((flags & ~VIR_DOMAIN_SHUTDOWN_INITCTL) == 0)) {
2634 2635 2636 2637
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                           _("Container does not provide an initctl pipe"));
            goto cleanup;
        }
2638 2639
    } else {
        rc = 0;
2640
    }
2641 2642 2643 2644 2645 2646

    if (rc == 0 &&
        (flags == 0 ||
         (flags & VIR_DOMAIN_SHUTDOWN_SIGNAL))) {
        if (kill(priv->initpid, SIGTERM) < 0 &&
            errno != ESRCH) {
2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658
            virReportSystemError(errno,
                                 _("Unable to send SIGTERM to init pid %llu"),
                                 (unsigned long long)priv->initpid);
            goto cleanup;
        }
    }

    ret = 0;

cleanup:
    VIR_FREE(vroot);
    if (vm)
2659
        virObjectUnlock(vm);
2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681
    return ret;
}

static int
lxcDomainShutdown(virDomainPtr dom)
{
    return lxcDomainShutdownFlags(dom, 0);
}

static int
lxcDomainReboot(virDomainPtr dom,
                unsigned int flags)
{
    virLXCDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
    char *vroot = NULL;
    int ret = -1;
    int rc;

    virCheckFlags(VIR_DOMAIN_REBOOT_INITCTL |
                  VIR_DOMAIN_REBOOT_SIGNAL, -1);

M
Michal Privoznik 已提交
2682
    if (!(vm = lxcDomObjFromDomain(dom)))
2683 2684 2685 2686
        goto cleanup;

    priv = vm->privateData;

2687 2688 2689
    if (virDomainRebootEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not running"));
        goto cleanup;
    }

    if (priv->initpid == 0) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Init process ID is not yet known"));
        goto cleanup;
    }

    if (virAsprintf(&vroot, "/proc/%llu/root",
2703
                    (unsigned long long)priv->initpid) < 0)
2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738
        goto cleanup;

    if (flags == 0 ||
        (flags & VIR_DOMAIN_REBOOT_INITCTL)) {
        if ((rc = virInitctlSetRunLevel(VIR_INITCTL_RUNLEVEL_REBOOT,
                                        vroot)) < 0) {
            goto cleanup;
        }
        if (rc == 0 && flags != 0 &&
            ((flags & ~VIR_DOMAIN_SHUTDOWN_INITCTL) == 0)) {
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                           _("Container does not provide an initctl pipe"));
            goto cleanup;
        }
    } else {
        rc = 0;
    }

    if (rc == 0 &&
        (flags == 0 ||
         (flags & VIR_DOMAIN_REBOOT_SIGNAL))) {
        if (kill(priv->initpid, SIGHUP) < 0 &&
            errno != ESRCH) {
            virReportSystemError(errno,
                                 _("Unable to send SIGTERM to init pid %llu"),
                                 (unsigned long long)priv->initpid);
            goto cleanup;
        }
    }

    ret = 0;

cleanup:
    VIR_FREE(vroot);
    if (vm)
2739
        virObjectUnlock(vm);
2740 2741 2742 2743
    return ret;
}


2744
static int
2745
lxcDomainAttachDeviceConfig(virDomainDefPtr vmdef,
2746 2747 2748
                            virDomainDeviceDefPtr dev)
{
    int ret = -1;
2749
    virDomainDiskDefPtr disk;
2750
    virDomainNetDefPtr net;
2751
    virDomainHostdevDefPtr hostdev;
2752 2753

    switch (dev->type) {
2754 2755 2756 2757 2758 2759 2760
    case VIR_DOMAIN_DEVICE_DISK:
        disk = dev->data.disk;
        if (virDomainDiskIndexByName(vmdef, disk->dst, true) >= 0) {
            virReportError(VIR_ERR_INVALID_ARG,
                           _("target %s already exists."), disk->dst);
            return -1;
        }
2761
        if (virDomainDiskInsert(vmdef, disk))
2762 2763 2764 2765 2766 2767
            return -1;
        /* vmdef has the pointer. Generic codes for vmdef will do all jobs */
        dev->data.disk = NULL;
        ret = 0;
        break;

2768 2769
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
2770
        if (virDomainNetInsert(vmdef, net) < 0)
2771 2772 2773 2774 2775
            goto cleanup;
        dev->data.net = NULL;
        ret = 0;
        break;

2776 2777 2778 2779 2780 2781 2782
    case VIR_DOMAIN_DEVICE_HOSTDEV:
        hostdev = dev->data.hostdev;
        if (virDomainHostdevFind(vmdef, hostdev, NULL) >= 0) {
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("device is already in the domain configuration"));
            return -1;
        }
2783
        if (virDomainHostdevInsert(vmdef, hostdev) < 0)
2784 2785 2786 2787 2788
            return -1;
        dev->data.hostdev = NULL;
        ret = 0;
        break;

2789 2790 2791 2792 2793 2794
    default:
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                        _("persistent attach of device is not supported"));
         break;
    }

2795
cleanup:
2796 2797 2798 2799 2800
    return ret;
}


static int
2801
lxcDomainUpdateDeviceConfig(virDomainDefPtr vmdef,
2802 2803 2804
                            virDomainDeviceDefPtr dev)
{
    int ret = -1;
2805 2806 2807
    virDomainNetDefPtr net;
    int idx;
    char mac[VIR_MAC_STRING_BUFLEN];
2808 2809

    switch (dev->type) {
2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
        idx = virDomainNetFindIdx(vmdef, net);
        if (idx == -2) {
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("multiple devices matching mac address %s found"),
                           virMacAddrFormat(&net->mac, mac));
            goto cleanup;
        } else if (idx < 0) {
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("no matching network device was found"));
            goto cleanup;
        }

        virDomainNetDefFree(vmdef->nets[idx]);

        vmdef->nets[idx] = net;
        dev->data.net = NULL;
        ret = 0;

        break;

2832 2833 2834 2835 2836 2837
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("persistent update of device is not supported"));
        break;
    }

2838
cleanup:
2839 2840 2841 2842 2843
    return ret;
}


static int
2844
lxcDomainDetachDeviceConfig(virDomainDefPtr vmdef,
2845 2846 2847
                            virDomainDeviceDefPtr dev)
{
    int ret = -1;
2848
    virDomainDiskDefPtr disk, det_disk;
2849
    virDomainNetDefPtr net;
2850
    virDomainHostdevDefPtr hostdev, det_hostdev;
2851 2852
    int idx;
    char mac[VIR_MAC_STRING_BUFLEN];
2853 2854

    switch (dev->type) {
2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865
    case VIR_DOMAIN_DEVICE_DISK:
        disk = dev->data.disk;
        if (!(det_disk = virDomainDiskRemoveByName(vmdef, disk->dst))) {
            virReportError(VIR_ERR_INVALID_ARG,
                           _("no target device %s"), disk->dst);
            return -1;
        }
        virDomainDiskDefFree(det_disk);
        ret = 0;
        break;

2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
        idx = virDomainNetFindIdx(vmdef, net);
        if (idx == -2) {
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("multiple devices matching mac address %s found"),
                           virMacAddrFormat(&net->mac, mac));
            goto cleanup;
        } else if (idx < 0) {
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("no matching network device was found"));
            goto cleanup;
        }
        /* this is guaranteed to succeed */
        virDomainNetDefFree(virDomainNetRemove(vmdef, idx));
        ret = 0;
        break;

2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896
    case VIR_DOMAIN_DEVICE_HOSTDEV: {
        hostdev = dev->data.hostdev;
        if ((idx = virDomainHostdevFind(vmdef, hostdev, &det_hostdev)) < 0) {
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("device not present in domain configuration"));
            return -1;
        }
        virDomainHostdevRemove(vmdef, idx);
        virDomainHostdevDefFree(det_hostdev);
        ret = 0;
        break;
    }

2897 2898 2899 2900 2901 2902
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("persistent detach of device is not supported"));
        break;
    }

2903
cleanup:
2904 2905 2906 2907
    return ret;
}


2908 2909 2910 2911 2912 2913 2914 2915
static int
lxcDomainAttachDeviceDiskLive(virLXCDriverPtr driver,
                              virDomainObjPtr vm,
                              virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainDiskDefPtr def = dev->data.disk;
    int ret = -1;
2916
    char *dst = NULL;
2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958
    struct stat sb;
    bool created = false;
    mode_t mode = 0;
    char *tmpsrc = def->src;

    if (!priv->initpid) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Cannot attach disk until init PID is known"));
        goto cleanup;
    }

    if (def->type != VIR_DOMAIN_DISK_TYPE_BLOCK) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Can't setup disk for non-block device"));
        goto cleanup;
    }
    if (def->src == NULL) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Can't setup disk without media"));
        goto cleanup;
    }

    if (virDomainDiskIndexByName(vm->def, def->dst, true) >= 0) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("target %s already exists"), def->dst);
        goto cleanup;
    }

    if (stat(def->src, &sb) < 0) {
        virReportSystemError(errno,
                             _("Unable to access %s"), def->src);
        goto cleanup;
    }

    if (!S_ISCHR(sb.st_mode) && !S_ISBLK(sb.st_mode)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Disk source %s must be a character/block device"),
                       def->src);
        goto cleanup;
    }

    if (virAsprintf(&dst, "/proc/%llu/root/dev/%s",
2959
                    (unsigned long long)priv->initpid, def->dst) < 0)
2960 2961
        goto cleanup;

2962
    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0)
2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985
        goto cleanup;

    mode = 0700;
    if (S_ISCHR(sb.st_mode))
        mode |= S_IFCHR;
    else
        mode |= S_IFBLK;

    /* Yes, the device name we're creating may not
     * actually correspond to the major:minor number
     * we're using, but we've no other option at this
     * time. Just have to hope that containerized apps
     * don't get upset that the major:minor is different
     * to that normally implied by the device name
     */
    VIR_DEBUG("Creating dev %s (%d,%d) from %s",
              dst, major(sb.st_rdev), minor(sb.st_rdev), def->src);
    if (mknod(dst, mode, sb.st_rdev) < 0) {
        virReportSystemError(errno,
                             _("Unable to create device %s"),
                             dst);
        goto cleanup;
    }
2986 2987 2988 2989

    if (lxcContainerChown(vm->def, dst) < 0)
        goto cleanup;

2990 2991 2992
    created = true;

    /* Labelling normally operates on src, but we need
E
Eric Blake 已提交
2993
     * to actually label the dst here, so hack the config */
2994 2995 2996 2997 2998
    def->src = dst;
    if (virSecurityManagerSetImageLabel(driver->securityManager,
                                        vm->def, def) < 0)
        goto cleanup;

2999
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
3000 3001 3002 3003 3004
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        goto cleanup;
    }

3005
    if (virCgroupAllowDevicePath(priv->cgroup, def->src,
3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024
                                 (def->readonly ?
                                  VIR_CGROUP_DEVICE_READ :
                                  VIR_CGROUP_DEVICE_RW) |
                                 VIR_CGROUP_DEVICE_MKNOD) != 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot allow device %s for domain %s"),
                       def->src, vm->def->name);
        goto cleanup;
    }

    virDomainDiskInsertPreAlloced(vm->def, def);

    ret = 0;

cleanup:
    def->src = tmpsrc;
    virDomainAuditDisk(vm, NULL, def->src, "attach", ret == 0);
    if (dst && created && ret < 0)
        unlink(dst);
3025
    VIR_FREE(dst);
3026 3027 3028 3029
    return ret;
}


3030
/* XXX conn required for network -> bridge resolution */
3031
static int
3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047
lxcDomainAttachDeviceNetLive(virConnectPtr conn,
                             virDomainObjPtr vm,
                             virDomainNetDefPtr net)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    int ret = -1;
    int actualType;
    char *veth = NULL;

    if (!priv->initpid) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Cannot attach disk until init PID is known"));
        goto cleanup;
    }

    /* preallocate new slot for device */
3048
    if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets+1) < 0)
3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158
        return -1;

    /* If appropriate, grab a physical device from the configured
     * network's pool of devices, or resolve bridge device name
     * to the one defined in the network definition.
     */
    if (networkAllocateActualDevice(net) < 0)
        return -1;

    actualType = virDomainNetGetActualType(net);

    switch (actualType) {
    case VIR_DOMAIN_NET_TYPE_BRIDGE: {
        const char *brname = virDomainNetGetActualBridgeName(net);
        if (!brname) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No bridge name specified"));
            goto cleanup;
        }
        if (!(veth = virLXCProcessSetupInterfaceBridged(conn,
                                                        vm->def,
                                                        net,
                                                        brname)))
            goto cleanup;
    }   break;
    case VIR_DOMAIN_NET_TYPE_NETWORK: {
        virNetworkPtr network;
        char *brname = NULL;
        bool fail = false;
        int active;
        virErrorPtr errobj;

        if (!(network = virNetworkLookupByName(conn,
                                               net->data.network.name)))
            goto cleanup;

        active = virNetworkIsActive(network);
        if (active != 1) {
            fail = true;
            if (active == 0)
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Network '%s' is not active."),
                               net->data.network.name);
        }

        if (!fail) {
            brname = virNetworkGetBridgeName(network);
            if (brname == NULL)
                fail = true;
        }

        /* Make sure any above failure is preserved */
        errobj = virSaveLastError();
        virNetworkFree(network);
        virSetError(errobj);
        virFreeError(errobj);

        if (fail)
            goto cleanup;

        if (!(veth = virLXCProcessSetupInterfaceBridged(conn,
                                                        vm->def,
                                                        net,
                                                        brname))) {
            VIR_FREE(brname);
            goto cleanup;
        }
        VIR_FREE(brname);
    }   break;
    case VIR_DOMAIN_NET_TYPE_DIRECT: {
        if (!(veth = virLXCProcessSetupInterfaceDirect(conn,
                                                       vm->def,
                                                       net)))
            goto cleanup;
    }   break;
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Network device type is not supported"));
        goto cleanup;
    }

    if (virNetDevSetNamespace(veth, priv->initpid) < 0) {
        virDomainAuditNet(vm, NULL, net, "attach", false);
        goto cleanup;
    }

    virDomainAuditNet(vm, NULL, net, "attach", true);

    ret = 0;

cleanup:
    if (!ret) {
        vm->def->nets[vm->def->nnets++] = net;
    } else if (veth) {
        switch (actualType) {
        case VIR_DOMAIN_NET_TYPE_BRIDGE:
        case VIR_DOMAIN_NET_TYPE_NETWORK:
            ignore_value(virNetDevVethDelete(veth));
            break;

        case VIR_DOMAIN_NET_TYPE_DIRECT:
            ignore_value(virNetDevMacVLanDelete(veth));
            break;
        }
    }

    return ret;
}


3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173
static int
lxcDomainAttachDeviceHostdevSubsysUSBLive(virLXCDriverPtr driver,
                                          virDomainObjPtr vm,
                                          virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainHostdevDefPtr def = dev->data.hostdev;
    int ret = -1;
    char *vroot = NULL;
    char *src = NULL;
    char *dstdir = NULL;
    char *dstfile = NULL;
    struct stat sb;
    mode_t mode;
    bool created = false;
3174
    virUSBDevicePtr usb = NULL;
3175 3176 3177 3178 3179 3180 3181 3182

    if (virDomainHostdevFind(vm->def, def, NULL) >= 0) {
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("host USB device already exists"));
        return -1;
    }

    if (virAsprintf(&vroot, "/proc/%llu/root",
3183
                    (unsigned long long)priv->initpid) < 0)
3184 3185 3186 3187
        goto cleanup;

    if (virAsprintf(&dstdir, "%s/dev/bus/%03d",
                    vroot,
3188
                    def->source.subsys.u.usb.bus) < 0)
3189 3190 3191 3192
        goto cleanup;

    if (virAsprintf(&dstfile, "%s/%03d",
                    dstdir,
3193
                    def->source.subsys.u.usb.device) < 0)
3194 3195 3196 3197
        goto cleanup;

    if (virAsprintf(&src, "/dev/bus/usb/%03d/%03d",
                    def->source.subsys.u.usb.bus,
3198
                    def->source.subsys.u.usb.device) < 0)
3199 3200
        goto cleanup;

3201
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
3202 3203 3204 3205 3206
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        goto cleanup;
    }

3207 3208
    if (!(usb = virUSBDeviceNew(def->source.subsys.u.usb.bus,
                                def->source.subsys.u.usb.device, vroot)))
3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241
        goto cleanup;

    if (stat(src, &sb) < 0) {
        virReportSystemError(errno,
                             _("Unable to access %s"), src);
        goto cleanup;
    }

    if (!S_ISCHR(sb.st_mode)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("USB source %s was not a character device"),
                       src);
        goto cleanup;
    }

    mode = 0700 | S_IFCHR;

    if (virFileMakePath(dstdir) < 0) {
        virReportSystemError(errno,
                             _("Unable to create %s"), dstdir);
        goto cleanup;
    }

    VIR_DEBUG("Creating dev %s (%d,%d)",
              dstfile, major(sb.st_rdev), minor(sb.st_rdev));
    if (mknod(dstfile, mode, sb.st_rdev) < 0) {
        virReportSystemError(errno,
                             _("Unable to create device %s"),
                             dstfile);
        goto cleanup;
    }
    created = true;

3242 3243 3244
    if (lxcContainerChown(vm->def, dstfile) < 0)
        goto cleanup;

3245 3246 3247 3248
    if (virSecurityManagerSetHostdevLabel(driver->securityManager,
                                          vm->def, def, vroot) < 0)
        goto cleanup;

3249
    if (virUSBDeviceFileIterate(usb,
3250 3251
                                virLXCSetupHostUsbDeviceCgroup,
                                &priv->cgroup) < 0)
3252 3253 3254 3255 3256 3257 3258 3259 3260
        goto cleanup;

    ret = 0;

cleanup:
    virDomainAuditHostdev(vm, def, "attach", ret == 0);
    if (ret < 0 && created)
        unlink(dstfile);

3261
    virUSBDeviceFree(usb);
3262 3263 3264 3265 3266 3267 3268 3269
    VIR_FREE(src);
    VIR_FREE(dstfile);
    VIR_FREE(dstdir);
    VIR_FREE(vroot);
    return ret;
}


3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310
static int
lxcDomainAttachDeviceHostdevStorageLive(virLXCDriverPtr driver,
                                        virDomainObjPtr vm,
                                        virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainHostdevDefPtr def = dev->data.hostdev;
    int ret = -1;
    char *dst = NULL;
    char *vroot = NULL;
    struct stat sb;
    bool created = false;
    mode_t mode = 0;

    if (!def->source.caps.u.storage.block) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Missing storage block path"));
        goto cleanup;
    }

    if (virDomainHostdevFind(vm->def, def, NULL) >= 0) {
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("host device already exists"));
        return -1;
    }

    if (stat(def->source.caps.u.storage.block, &sb) < 0) {
        virReportSystemError(errno,
                             _("Unable to access %s"),
                             def->source.caps.u.storage.block);
        goto cleanup;
    }

    if (!S_ISBLK(sb.st_mode)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Hostdev source %s must be a block device"),
                       def->source.caps.u.storage.block);
        goto cleanup;
    }

    if (virAsprintf(&vroot, "/proc/%llu/root",
3311
                    (unsigned long long)priv->initpid) < 0)
3312 3313 3314 3315
        goto cleanup;

    if (virAsprintf(&dst, "%s/%s",
                    vroot,
3316
                    def->source.caps.u.storage.block) < 0)
3317 3318
        goto cleanup;

3319
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0)
3320 3321
        goto cleanup;

3322 3323
    if (lxcContainerSetupHostdevCapsMakePath(dst) < 0) {
        virReportSystemError(errno,
3324
                             _("Unable to create directory for device %s"),
3325 3326 3327 3328
                             dst);
        goto cleanup;
    }

3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341
    mode = 0700 | S_IFBLK;

    VIR_DEBUG("Creating dev %s (%d,%d)",
              def->source.caps.u.storage.block,
              major(sb.st_rdev), minor(sb.st_rdev));
    if (mknod(dst, mode, sb.st_rdev) < 0) {
        virReportSystemError(errno,
                             _("Unable to create device %s"),
                             dst);
        goto cleanup;
    }
    created = true;

3342 3343 3344
    if (lxcContainerChown(vm->def, dst) < 0)
        goto cleanup;

3345 3346 3347 3348
    if (virSecurityManagerSetHostdevLabel(driver->securityManager,
                                          vm->def, def, vroot) < 0)
        goto cleanup;

3349
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
3350 3351 3352 3353 3354
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        goto cleanup;
    }

3355
    if (virCgroupAllowDevicePath(priv->cgroup, def->source.caps.u.storage.block,
3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377
                                 VIR_CGROUP_DEVICE_RW |
                                 VIR_CGROUP_DEVICE_MKNOD) != 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot allow device %s for domain %s"),
                       def->source.caps.u.storage.block, vm->def->name);
        goto cleanup;
    }

    vm->def->hostdevs[vm->def->nhostdevs++] = def;

    ret = 0;

cleanup:
    virDomainAuditHostdev(vm, def, "attach", ret == 0);
    if (dst && created && ret < 0)
        unlink(dst);
    VIR_FREE(dst);
    VIR_FREE(vroot);
    return ret;
}


3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418
static int
lxcDomainAttachDeviceHostdevMiscLive(virLXCDriverPtr driver,
                                     virDomainObjPtr vm,
                                     virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainHostdevDefPtr def = dev->data.hostdev;
    int ret = -1;
    char *dst = NULL;
    char *vroot = NULL;
    struct stat sb;
    bool created = false;
    mode_t mode = 0;

    if (!def->source.caps.u.misc.chardev) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Missing storage block path"));
        goto cleanup;
    }

    if (virDomainHostdevFind(vm->def, def, NULL) >= 0) {
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("host device already exists"));
        return -1;
    }

    if (stat(def->source.caps.u.misc.chardev, &sb) < 0) {
        virReportSystemError(errno,
                             _("Unable to access %s"),
                             def->source.caps.u.misc.chardev);
        goto cleanup;
    }

    if (!S_ISCHR(sb.st_mode)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Hostdev source %s must be a block device"),
                       def->source.caps.u.misc.chardev);
        goto cleanup;
    }

    if (virAsprintf(&vroot, "/proc/%llu/root",
3419
                    (unsigned long long)priv->initpid) < 0)
3420 3421 3422 3423
        goto cleanup;

    if (virAsprintf(&dst, "%s/%s",
                    vroot,
3424
                    def->source.caps.u.misc.chardev) < 0)
3425 3426
        goto cleanup;

3427
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0)
3428 3429
        goto cleanup;

3430 3431
    if (lxcContainerSetupHostdevCapsMakePath(dst) < 0) {
        virReportSystemError(errno,
3432
                             _("Unable to create directory for device %s"),
3433 3434 3435 3436
                             dst);
        goto cleanup;
    }

3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449
    mode = 0700 | S_IFCHR;

    VIR_DEBUG("Creating dev %s (%d,%d)",
              def->source.caps.u.misc.chardev,
              major(sb.st_rdev), minor(sb.st_rdev));
    if (mknod(dst, mode, sb.st_rdev) < 0) {
        virReportSystemError(errno,
                             _("Unable to create device %s"),
                             dst);
        goto cleanup;
    }
    created = true;

3450 3451 3452
    if (lxcContainerChown(vm->def, dst) < 0)
        goto cleanup;

3453 3454 3455 3456
    if (virSecurityManagerSetHostdevLabel(driver->securityManager,
                                          vm->def, def, vroot) < 0)
        goto cleanup;

3457
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
3458 3459 3460 3461 3462
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        goto cleanup;
    }

3463
    if (virCgroupAllowDevicePath(priv->cgroup, def->source.caps.u.misc.chardev,
3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485
                                 VIR_CGROUP_DEVICE_RW |
                                 VIR_CGROUP_DEVICE_MKNOD) != 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot allow device %s for domain %s"),
                       def->source.caps.u.misc.chardev, vm->def->name);
        goto cleanup;
    }

    vm->def->hostdevs[vm->def->nhostdevs++] = def;

    ret = 0;

cleanup:
    virDomainAuditHostdev(vm, def, "attach", ret == 0);
    if (dst && created && ret < 0)
        unlink(dst);
    VIR_FREE(dst);
    VIR_FREE(vroot);
    return ret;
}


3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503
static int
lxcDomainAttachDeviceHostdevSubsysLive(virLXCDriverPtr driver,
                                       virDomainObjPtr vm,
                                       virDomainDeviceDefPtr dev)
{
    switch (dev->data.hostdev->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
        return lxcDomainAttachDeviceHostdevSubsysUSBLive(driver, vm, dev);

    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported host device type %s"),
                       virDomainHostdevSubsysTypeToString(dev->data.hostdev->source.subsys.type));
        return -1;
    }
}


3504 3505 3506 3507 3508 3509 3510 3511 3512
static int
lxcDomainAttachDeviceHostdevCapsLive(virLXCDriverPtr driver,
                                     virDomainObjPtr vm,
                                     virDomainDeviceDefPtr dev)
{
    switch (dev->data.hostdev->source.caps.type) {
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
        return lxcDomainAttachDeviceHostdevStorageLive(driver, vm, dev);

3513 3514 3515
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC:
        return lxcDomainAttachDeviceHostdevMiscLive(driver, vm, dev);

3516 3517 3518 3519 3520 3521 3522 3523 3524
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported host device type %s"),
                       virDomainHostdevCapsTypeToString(dev->data.hostdev->source.caps.type));
        return -1;
    }
}


3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541
static int
lxcDomainAttachDeviceHostdevLive(virLXCDriverPtr driver,
                                 virDomainObjPtr vm,
                                 virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;

    if (!priv->initpid) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Cannot attach hostdev until init PID is known"));
        return -1;
    }

    switch (dev->data.hostdev->mode) {
    case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
        return lxcDomainAttachDeviceHostdevSubsysLive(driver, vm, dev);

3542 3543 3544
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
        return lxcDomainAttachDeviceHostdevCapsLive(driver, vm, dev);

3545 3546 3547 3548 3549 3550 3551 3552 3553
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported host device mode %s"),
                       virDomainHostdevModeTypeToString(dev->data.hostdev->mode));
        return -1;
    }
}


3554 3555 3556 3557
static int
lxcDomainAttachDeviceLive(virConnectPtr conn,
                          virLXCDriverPtr driver,
                          virDomainObjPtr vm,
3558 3559 3560 3561 3562
                          virDomainDeviceDefPtr dev)
{
    int ret = -1;

    switch (dev->type) {
3563 3564 3565 3566 3567 3568
    case VIR_DOMAIN_DEVICE_DISK:
        ret = lxcDomainAttachDeviceDiskLive(driver, vm, dev);
        if (!ret)
            dev->data.disk = NULL;
        break;

3569 3570 3571 3572 3573 3574 3575
    case VIR_DOMAIN_DEVICE_NET:
        ret = lxcDomainAttachDeviceNetLive(conn, vm,
                                           dev->data.net);
        if (!ret)
            dev->data.net = NULL;
        break;

3576 3577 3578 3579 3580 3581
    case VIR_DOMAIN_DEVICE_HOSTDEV:
        ret = lxcDomainAttachDeviceHostdevLive(driver, vm, dev);
        if (!ret)
            dev->data.disk = NULL;
        break;

3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("device type '%s' cannot be attached"),
                       virDomainDeviceTypeToString(dev->type));
        break;
    }

    return ret;
}


3593
static int
3594
lxcDomainDetachDeviceDiskLive(virDomainObjPtr vm,
3595 3596 3597 3598
                              virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainDiskDefPtr def = NULL;
3599
    int idx, ret = -1;
J
John Ferlan 已提交
3600
    char *dst = NULL;
3601 3602 3603 3604 3605 3606 3607

    if (!priv->initpid) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Cannot attach disk until init PID is known"));
        goto cleanup;
    }

3608 3609 3610
    if ((idx = virDomainDiskIndexByName(vm->def,
                                        dev->data.disk->dst,
                                        false)) < 0) {
3611 3612 3613 3614 3615
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("disk %s not found"), dev->data.disk->dst);
        goto cleanup;
    }

3616
    def = vm->def->disks[idx];
3617 3618

    if (virAsprintf(&dst, "/proc/%llu/root/dev/%s",
3619
                    (unsigned long long)priv->initpid, def->dst) < 0)
3620 3621
        goto cleanup;

3622
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        goto cleanup;
    }

    VIR_DEBUG("Unlinking %s (backed by %s)", dst, def->src);
    if (unlink(dst) < 0 && errno != ENOENT) {
        virDomainAuditDisk(vm, def->src, NULL, "detach", false);
        virReportSystemError(errno,
                             _("Unable to remove device %s"), dst);
        goto cleanup;
    }
    virDomainAuditDisk(vm, def->src, NULL, "detach", true);

3637
    if (virCgroupDenyDevicePath(priv->cgroup, def->src, VIR_CGROUP_DEVICE_RWM) != 0)
3638 3639 3640
        VIR_WARN("cannot deny device %s for domain %s",
                 def->src, vm->def->name);

3641
    virDomainDiskRemove(vm->def, idx);
3642 3643 3644 3645 3646 3647 3648 3649 3650 3651
    virDomainDiskDefFree(def);

    ret = 0;

cleanup:
    VIR_FREE(dst);
    return ret;
}


3652
static int
3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717
lxcDomainDetachDeviceNetLive(virDomainObjPtr vm,
                             virDomainDeviceDefPtr dev)
{
    int detachidx, ret = -1;
    virDomainNetDefPtr detach = NULL;
    char mac[VIR_MAC_STRING_BUFLEN];
    virNetDevVPortProfilePtr vport = NULL;

    detachidx = virDomainNetFindIdx(vm->def, dev->data.net);
    if (detachidx == -2) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("multiple devices matching mac address %s found"),
                       virMacAddrFormat(&dev->data.net->mac, mac));
        goto cleanup;
    } else if (detachidx < 0) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("network device %s not found"),
                       virMacAddrFormat(&dev->data.net->mac, mac));
        goto cleanup;
    }
    detach = vm->def->nets[detachidx];

    switch (virDomainNetGetActualType(detach)) {
    case VIR_DOMAIN_NET_TYPE_BRIDGE:
    case VIR_DOMAIN_NET_TYPE_NETWORK:
        if (virNetDevVethDelete(detach->ifname) < 0) {
            virDomainAuditNet(vm, detach, NULL, "detach", false);
            goto cleanup;
        }
        break;

        /* It'd be nice to support this, but with macvlan
         * once assigned to a container nothing exists on
         * the host side. Further the container can change
         * the mac address of NIC name, so we can't easily
         * find out which guest NIC it maps to
    case VIR_DOMAIN_NET_TYPE_DIRECT:
        */

    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Only bridged veth devices can be detached"));
        goto cleanup;
    }

    virDomainAuditNet(vm, detach, NULL, "detach", true);

    virDomainConfNWFilterTeardown(detach);

    vport = virDomainNetGetActualVirtPortProfile(detach);
    if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH)
        ignore_value(virNetDevOpenvswitchRemovePort(
                        virDomainNetGetActualBridgeName(detach),
                        detach->ifname));
    ret = 0;
cleanup:
    if (!ret) {
        networkReleaseActualDevice(detach);
        virDomainNetRemove(vm->def, detachidx);
        virDomainNetDefFree(detach);
    }
    return ret;
}


3718 3719 3720 3721 3722 3723 3724 3725
static int
lxcDomainDetachDeviceHostdevUSBLive(virLXCDriverPtr driver,
                                    virDomainObjPtr vm,
                                    virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainHostdevDefPtr def = NULL;
    int idx, ret = -1;
J
John Ferlan 已提交
3726
    char *dst = NULL;
3727
    char *vroot = NULL;
3728
    virUSBDevicePtr usb = NULL;
3729 3730 3731 3732 3733 3734 3735 3736 3737 3738

    if ((idx = virDomainHostdevFind(vm->def,
                                    dev->data.hostdev,
                                    &def)) < 0) {
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("usb device not found"));
        goto cleanup;
    }

    if (virAsprintf(&vroot, "/proc/%llu/root",
3739
                    (unsigned long long)priv->initpid) < 0)
3740 3741 3742 3743 3744
        goto cleanup;

    if (virAsprintf(&dst, "%s/dev/bus/usb/%03d/%03d",
                    vroot,
                    def->source.subsys.u.usb.bus,
3745
                    def->source.subsys.u.usb.device) < 0)
3746 3747
        goto cleanup;

3748
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
3749 3750 3751 3752 3753
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        goto cleanup;
    }

3754 3755
    if (!(usb = virUSBDeviceNew(def->source.subsys.u.usb.bus,
                                def->source.subsys.u.usb.device, vroot)))
3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766
        goto cleanup;

    VIR_DEBUG("Unlinking %s", dst);
    if (unlink(dst) < 0 && errno != ENOENT) {
        virDomainAuditHostdev(vm, def, "detach", false);
        virReportSystemError(errno,
                             _("Unable to remove device %s"), dst);
        goto cleanup;
    }
    virDomainAuditHostdev(vm, def, "detach", true);

3767
    if (virUSBDeviceFileIterate(usb,
3768 3769
                                virLXCTeardownHostUsbDeviceCgroup,
                                &priv->cgroup) < 0)
3770 3771 3772
        VIR_WARN("cannot deny device %s for domain %s",
                 dst, vm->def->name);

3773
    virObjectLock(driver->activeUsbHostdevs);
3774
    virUSBDeviceListDel(driver->activeUsbHostdevs, usb);
3775
    virObjectUnlock(driver->activeUsbHostdevs);
3776 3777 3778 3779 3780 3781 3782

    virDomainHostdevRemove(vm->def, idx);
    virDomainHostdevDefFree(def);

    ret = 0;

cleanup:
3783
    virUSBDeviceFree(usb);
3784
    VIR_FREE(dst);
3785
    VIR_FREE(vroot);
3786 3787 3788
    return ret;
}

3789 3790

static int
3791
lxcDomainDetachDeviceHostdevStorageLive(virDomainObjPtr vm,
3792 3793 3794 3795
                                        virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainHostdevDefPtr def = NULL;
3796
    int idx, ret = -1;
3797 3798 3799 3800 3801 3802 3803 3804
    char *dst = NULL;

    if (!priv->initpid) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Cannot attach disk until init PID is known"));
        goto cleanup;
    }

3805 3806 3807
    if ((idx = virDomainHostdevFind(vm->def,
                                    dev->data.hostdev,
                                    &def)) < 0) {
3808 3809 3810 3811 3812 3813 3814 3815
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("hostdev %s not found"),
                       dev->data.hostdev->source.caps.u.storage.block);
        goto cleanup;
    }

    if (virAsprintf(&dst, "/proc/%llu/root/%s",
                    (unsigned long long)priv->initpid,
3816
                    def->source.caps.u.storage.block) < 0)
3817 3818
        goto cleanup;

3819
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        goto cleanup;
    }

    VIR_DEBUG("Unlinking %s", dst);
    if (unlink(dst) < 0 && errno != ENOENT) {
        virDomainAuditHostdev(vm, def, "detach", false);
        virReportSystemError(errno,
                             _("Unable to remove device %s"), dst);
        goto cleanup;
    }
    virDomainAuditHostdev(vm, def, "detach", true);

3834
    if (virCgroupDenyDevicePath(priv->cgroup, def->source.caps.u.storage.block, VIR_CGROUP_DEVICE_RWM) != 0)
3835 3836 3837
        VIR_WARN("cannot deny device %s for domain %s",
                 def->source.caps.u.storage.block, vm->def->name);

3838
    virDomainHostdevRemove(vm->def, idx);
3839 3840 3841 3842 3843 3844 3845 3846 3847 3848
    virDomainHostdevDefFree(def);

    ret = 0;

cleanup:
    VIR_FREE(dst);
    return ret;
}


3849
static int
3850
lxcDomainDetachDeviceHostdevMiscLive(virDomainObjPtr vm,
3851 3852 3853 3854
                                     virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainHostdevDefPtr def = NULL;
3855
    int idx, ret = -1;
3856 3857 3858 3859 3860 3861 3862 3863
    char *dst = NULL;

    if (!priv->initpid) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Cannot attach disk until init PID is known"));
        goto cleanup;
    }

3864 3865 3866
    if ((idx = virDomainHostdevFind(vm->def,
                                    dev->data.hostdev,
                                    &def)) < 0) {
3867 3868 3869 3870 3871 3872 3873 3874
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("hostdev %s not found"),
                       dev->data.hostdev->source.caps.u.misc.chardev);
        goto cleanup;
    }

    if (virAsprintf(&dst, "/proc/%llu/root/%s",
                    (unsigned long long)priv->initpid,
3875
                    def->source.caps.u.misc.chardev) < 0)
3876 3877
        goto cleanup;

3878
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        goto cleanup;
    }

    VIR_DEBUG("Unlinking %s", dst);
    if (unlink(dst) < 0 && errno != ENOENT) {
        virDomainAuditHostdev(vm, def, "detach", false);
        virReportSystemError(errno,
                             _("Unable to remove device %s"), dst);
        goto cleanup;
    }
    virDomainAuditHostdev(vm, def, "detach", true);

3893
    if (virCgroupDenyDevicePath(priv->cgroup, def->source.caps.u.misc.chardev, VIR_CGROUP_DEVICE_RWM) != 0)
3894 3895 3896
        VIR_WARN("cannot deny device %s for domain %s",
                 def->source.caps.u.misc.chardev, vm->def->name);

3897
    virDomainHostdevRemove(vm->def, idx);
3898 3899 3900 3901 3902 3903 3904 3905 3906 3907
    virDomainHostdevDefFree(def);

    ret = 0;

cleanup:
    VIR_FREE(dst);
    return ret;
}


3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925
static int
lxcDomainDetachDeviceHostdevSubsysLive(virLXCDriverPtr driver,
                                       virDomainObjPtr vm,
                                       virDomainDeviceDefPtr dev)
{
    switch (dev->data.hostdev->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
        return lxcDomainDetachDeviceHostdevUSBLive(driver, vm, dev);

    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported host device type %s"),
                       virDomainHostdevSubsysTypeToString(dev->data.hostdev->source.subsys.type));
        return -1;
    }
}


3926
static int
3927 3928
lxcDomainDetachDeviceHostdevCapsLive(virDomainObjPtr vm,
                                     virDomainDeviceDefPtr dev)
3929 3930 3931
{
    switch (dev->data.hostdev->source.caps.type) {
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
3932
        return lxcDomainDetachDeviceHostdevStorageLive(vm, dev);
3933

3934
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC:
3935
        return lxcDomainDetachDeviceHostdevMiscLive(vm, dev);
3936

3937 3938 3939 3940 3941 3942 3943 3944 3945
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported host device type %s"),
                       virDomainHostdevCapsTypeToString(dev->data.hostdev->source.caps.type));
        return -1;
    }
}


3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962
static int
lxcDomainDetachDeviceHostdevLive(virLXCDriverPtr driver,
                                 virDomainObjPtr vm,
                                 virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;

    if (!priv->initpid) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Cannot attach hostdev until init PID is known"));
        return -1;
    }

    switch (dev->data.hostdev->mode) {
    case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
        return lxcDomainDetachDeviceHostdevSubsysLive(driver, vm, dev);

3963
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
3964
        return lxcDomainDetachDeviceHostdevCapsLive(vm, dev);
3965

3966 3967 3968 3969 3970 3971 3972 3973 3974
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported host device mode %s"),
                       virDomainHostdevModeTypeToString(dev->data.hostdev->mode));
        return -1;
    }
}


3975 3976 3977
static int
lxcDomainDetachDeviceLive(virLXCDriverPtr driver,
                          virDomainObjPtr vm,
3978 3979 3980 3981 3982
                          virDomainDeviceDefPtr dev)
{
    int ret = -1;

    switch (dev->type) {
3983
    case VIR_DOMAIN_DEVICE_DISK:
3984
        ret = lxcDomainDetachDeviceDiskLive(vm, dev);
3985 3986
        break;

3987 3988 3989 3990
    case VIR_DOMAIN_DEVICE_NET:
        ret = lxcDomainDetachDeviceNetLive(vm, dev);
        break;

3991 3992 3993 3994
    case VIR_DOMAIN_DEVICE_HOSTDEV:
        ret = lxcDomainDetachDeviceHostdevLive(driver, vm, dev);
        break;

3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("device type '%s' cannot be detached"),
                       virDomainDeviceTypeToString(dev->type));
        break;
    }

    return ret;
}


4006 4007 4008
static int lxcDomainAttachDeviceFlags(virDomainPtr dom,
                                      const char *xml,
                                      unsigned int flags)
4009 4010
{
    virLXCDriverPtr driver = dom->conn->privateData;
4011
    virCapsPtr caps = NULL;
4012 4013 4014 4015 4016
    virDomainObjPtr vm = NULL;
    virDomainDefPtr vmdef = NULL;
    virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
    int ret = -1;
    unsigned int affect;
4017
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
4018 4019

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
4020
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
4021 4022 4023

    affect = flags & (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG);

M
Michal Privoznik 已提交
4024
    if (!(vm = lxcDomObjFromDomain(dom)))
4025 4026
        goto cleanup;

4027 4028 4029
    if (virDomainAttachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044
    if (virDomainObjIsActive(vm)) {
        if (affect == VIR_DOMAIN_AFFECT_CURRENT)
            flags |= VIR_DOMAIN_AFFECT_LIVE;
    } else {
        if (affect == VIR_DOMAIN_AFFECT_CURRENT)
            flags |= VIR_DOMAIN_AFFECT_CONFIG;
        /* check consistency between flags and the vm state */
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot do live update a device on "
                             "inactive domain"));
            goto cleanup;
        }
    }

4045 4046 4047
    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
        goto cleanup;

4048 4049 4050 4051 4052 4053
    if ((flags & VIR_DOMAIN_AFFECT_CONFIG) && !vm->persistent) {
         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                        _("cannot modify device on transient domain"));
         goto cleanup;
    }

4054
    dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
4055
                                             caps, driver->xmlopt,
4056 4057 4058 4059 4060 4061 4062 4063 4064 4065
                                             VIR_DOMAIN_XML_INACTIVE);
    if (dev == NULL)
        goto cleanup;

    if (flags & VIR_DOMAIN_AFFECT_CONFIG &&
        flags & VIR_DOMAIN_AFFECT_LIVE) {
        /* If we are affecting both CONFIG and LIVE
         * create a deep copy of device as adding
         * to CONFIG takes one instance.
         */
4066
        dev_copy = virDomainDeviceDefCopy(dev, vm->def,
4067
                                          caps, driver->xmlopt);
4068 4069 4070 4071 4072 4073 4074 4075 4076
        if (!dev_copy)
            goto cleanup;
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        if (virDomainDefCompatibleDevice(vm->def, dev) < 0)
            goto cleanup;

        /* Make a copy for updated domain. */
4077
        vmdef = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt);
4078 4079
        if (!vmdef)
            goto cleanup;
4080
        if ((ret = lxcDomainAttachDeviceConfig(vmdef, dev)) < 0)
4081 4082 4083 4084 4085 4086 4087
            goto cleanup;
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (virDomainDefCompatibleDevice(vm->def, dev_copy) < 0)
            goto cleanup;

4088
        if ((ret = lxcDomainAttachDeviceLive(dom->conn, driver, vm, dev_copy)) < 0)
4089 4090 4091 4092 4093 4094
            goto cleanup;
        /*
         * update domain status forcibly because the domain status may be
         * changed even if we failed to attach the device. For example,
         * a new controller may be created.
         */
4095
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
4096 4097 4098 4099 4100 4101 4102
            ret = -1;
            goto cleanup;
        }
    }

    /* Finally, if no error until here, we can save config. */
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
4103
        ret = virDomainSaveConfig(cfg->configDir, vmdef);
4104
        if (!ret) {
4105
            virDomainObjAssignDef(vm, vmdef, false, NULL);
4106 4107 4108 4109 4110 4111 4112 4113 4114 4115
            vmdef = NULL;
        }
    }

cleanup:
    virDomainDefFree(vmdef);
    if (dev != dev_copy)
        virDomainDeviceDefFree(dev_copy);
    virDomainDeviceDefFree(dev);
    if (vm)
4116
        virObjectUnlock(vm);
4117
    virObjectUnref(caps);
4118
    virObjectUnref(cfg);
4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134
    return ret;
}


static int lxcDomainAttachDevice(virDomainPtr dom,
                                 const char *xml)
{
    return lxcDomainAttachDeviceFlags(dom, xml,
                                       VIR_DOMAIN_AFFECT_LIVE);
}


static int lxcDomainUpdateDeviceFlags(virDomainPtr dom,
                                      const char *xml,
                                      unsigned int flags)
{
4135
    virLXCDriverPtr driver = dom->conn->privateData;
4136
    virCapsPtr caps = NULL;
4137 4138 4139 4140 4141
    virDomainObjPtr vm = NULL;
    virDomainDefPtr vmdef = NULL;
    virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
    int ret = -1;
    unsigned int affect;
4142
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
4143 4144 4145 4146 4147 4148 4149

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_DOMAIN_DEVICE_MODIFY_FORCE, -1);

    affect = flags & (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG);

M
Michal Privoznik 已提交
4150
    if (!(vm = lxcDomObjFromDomain(dom)))
4151 4152
        goto cleanup;

4153 4154 4155
    if (virDomainUpdateDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176
    if (virDomainObjIsActive(vm)) {
        if (affect == VIR_DOMAIN_AFFECT_CURRENT)
            flags |= VIR_DOMAIN_AFFECT_LIVE;
    } else {
        if (affect == VIR_DOMAIN_AFFECT_CURRENT)
            flags |= VIR_DOMAIN_AFFECT_CONFIG;
        /* check consistency between flags and the vm state */
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot do live update a device on "
                             "inactive domain"));
            goto cleanup;
        }
    }

    if ((flags & VIR_DOMAIN_AFFECT_CONFIG) && !vm->persistent) {
         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                        _("cannot modify device on transient domain"));
         goto cleanup;
    }

4177 4178 4179
    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
        goto cleanup;

4180
    dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
4181
                                             caps, driver->xmlopt,
4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192
                                             VIR_DOMAIN_XML_INACTIVE);
    if (dev == NULL)
        goto cleanup;

    if (flags & VIR_DOMAIN_AFFECT_CONFIG &&
        flags & VIR_DOMAIN_AFFECT_LIVE) {
        /* If we are affecting both CONFIG and LIVE
         * create a deep copy of device as adding
         * to CONFIG takes one instance.
         */
        dev_copy = virDomainDeviceDefCopy(dev, vm->def,
4193
                                          caps, driver->xmlopt);
4194 4195 4196 4197 4198 4199 4200 4201 4202
        if (!dev_copy)
            goto cleanup;
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        if (virDomainDefCompatibleDevice(vm->def, dev) < 0)
            goto cleanup;

        /* Make a copy for updated domain. */
4203
        vmdef = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt);
4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221
        if (!vmdef)
            goto cleanup;
        if ((ret = lxcDomainUpdateDeviceConfig(vmdef, dev)) < 0)
            goto cleanup;
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (virDomainDefCompatibleDevice(vm->def, dev_copy) < 0)
            goto cleanup;

        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("Unable to modify live devices"));

        goto cleanup;
    }

    /* Finally, if no error until here, we can save config. */
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
4222
        ret = virDomainSaveConfig(cfg->configDir, vmdef);
4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235
        if (!ret) {
            virDomainObjAssignDef(vm, vmdef, false, NULL);
            vmdef = NULL;
        }
    }

cleanup:
    virDomainDefFree(vmdef);
    if (dev != dev_copy)
        virDomainDeviceDefFree(dev_copy);
    virDomainDeviceDefFree(dev);
    if (vm)
        virObjectUnlock(vm);
4236
    virObjectUnref(caps);
4237
    virObjectUnref(cfg);
4238
    return ret;
4239 4240 4241 4242 4243 4244 4245
}


static int lxcDomainDetachDeviceFlags(virDomainPtr dom,
                                      const char *xml,
                                      unsigned int flags)
{
4246
    virLXCDriverPtr driver = dom->conn->privateData;
4247
    virCapsPtr caps = NULL;
4248 4249 4250 4251 4252
    virDomainObjPtr vm = NULL;
    virDomainDefPtr vmdef = NULL;
    virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
    int ret = -1;
    unsigned int affect;
4253
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
4254 4255 4256 4257 4258 4259

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

    affect = flags & (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG);

M
Michal Privoznik 已提交
4260
    if (!(vm = lxcDomObjFromDomain(dom)))
4261 4262
        goto cleanup;

4263 4264 4265
    if (virDomainDetachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286
    if (virDomainObjIsActive(vm)) {
        if (affect == VIR_DOMAIN_AFFECT_CURRENT)
            flags |= VIR_DOMAIN_AFFECT_LIVE;
    } else {
        if (affect == VIR_DOMAIN_AFFECT_CURRENT)
            flags |= VIR_DOMAIN_AFFECT_CONFIG;
        /* check consistency between flags and the vm state */
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot do live update a device on "
                             "inactive domain"));
            goto cleanup;
        }
    }

    if ((flags & VIR_DOMAIN_AFFECT_CONFIG) && !vm->persistent) {
         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                        _("cannot modify device on transient domain"));
         goto cleanup;
    }

4287 4288 4289
    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
        goto cleanup;

4290
    dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
4291
                                             caps, driver->xmlopt,
4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302
                                             VIR_DOMAIN_XML_INACTIVE);
    if (dev == NULL)
        goto cleanup;

    if (flags & VIR_DOMAIN_AFFECT_CONFIG &&
        flags & VIR_DOMAIN_AFFECT_LIVE) {
        /* If we are affecting both CONFIG and LIVE
         * create a deep copy of device as adding
         * to CONFIG takes one instance.
         */
        dev_copy = virDomainDeviceDefCopy(dev, vm->def,
4303
                                          caps, driver->xmlopt);
4304 4305 4306 4307 4308 4309 4310 4311 4312
        if (!dev_copy)
            goto cleanup;
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        if (virDomainDefCompatibleDevice(vm->def, dev) < 0)
            goto cleanup;

        /* Make a copy for updated domain. */
4313
        vmdef = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt);
4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331
        if (!vmdef)
            goto cleanup;

        if ((ret = lxcDomainDetachDeviceConfig(vmdef, dev)) < 0)
            goto cleanup;
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (virDomainDefCompatibleDevice(vm->def, dev_copy) < 0)
            goto cleanup;

        if ((ret = lxcDomainDetachDeviceLive(driver, vm, dev_copy)) < 0)
            goto cleanup;
        /*
         * update domain status forcibly because the domain status may be
         * changed even if we failed to attach the device. For example,
         * a new controller may be created.
         */
4332
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
4333 4334 4335 4336 4337 4338 4339
            ret = -1;
            goto cleanup;
        }
    }

    /* Finally, if no error until here, we can save config. */
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
4340
        ret = virDomainSaveConfig(cfg->configDir, vmdef);
4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353
        if (!ret) {
            virDomainObjAssignDef(vm, vmdef, false, NULL);
            vmdef = NULL;
        }
    }

cleanup:
    virDomainDefFree(vmdef);
    if (dev != dev_copy)
        virDomainDeviceDefFree(dev_copy);
    virDomainDeviceDefFree(dev);
    if (vm)
        virObjectUnlock(vm);
4354
    virObjectUnref(caps);
4355
    virObjectUnref(cfg);
4356
    return ret;
4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367
}


static int lxcDomainDetachDevice(virDomainPtr dom,
                                 const char *xml)
{
    return lxcDomainDetachDeviceFlags(dom, xml,
                                      VIR_DOMAIN_AFFECT_LIVE);
}


4368 4369 4370
static int lxcDomainLxcOpenNamespace(virDomainPtr dom,
                                     int **fdlist,
                                     unsigned int flags)
4371 4372 4373 4374 4375 4376 4377 4378 4379
{
    virDomainObjPtr vm;
    virLXCDomainObjPrivatePtr priv;
    int ret = -1;
    size_t nfds = 0;

    *fdlist = NULL;
    virCheckFlags(0, -1);

M
Michal Privoznik 已提交
4380
    if (!(vm = lxcDomObjFromDomain(dom)))
4381
        goto cleanup;
M
Michal Privoznik 已提交
4382

4383 4384
    priv = vm->privateData;

4385 4386 4387
    if (virDomainLxcOpenNamespaceEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not running"));
        goto cleanup;
    }

    if (!priv->initpid) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Init pid is not yet available"));
        goto cleanup;
    }

    if (virProcessGetNamespaces(priv->initpid, &nfds, fdlist) < 0)
        goto cleanup;

    ret = nfds;
cleanup:
4405 4406
    if (vm)
        virObjectUnlock(vm);
4407 4408 4409 4410
    return ret;
}


4411
static char *
4412
lxcConnectGetSysinfo(virConnectPtr conn, unsigned int flags)
4413 4414 4415 4416 4417 4418
{
    virLXCDriverPtr driver = conn->privateData;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    virCheckFlags(0, NULL);

4419 4420 4421
    if (virConnectGetSysinfoEnsureACL(conn) < 0)
        return NULL;

4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437
    if (!driver->hostsysinfo) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Host SMBIOS information is not available"));
        return NULL;
    }

    if (virSysinfoFormat(&buf, driver->hostsysinfo) < 0)
        return NULL;
    if (virBufferError(&buf)) {
        virReportOOMError();
        return NULL;
    }
    return virBufferContentAndReset(&buf);
}


4438
static int
4439
lxcNodeGetInfo(virConnectPtr conn,
4440 4441
               virNodeInfoPtr nodeinfo)
{
4442 4443 4444
    if (virNodeGetInfoEnsureACL(conn) < 0)
        return -1;

4445 4446 4447 4448 4449
    return nodeGetInfo(nodeinfo);
}


static int
4450
lxcNodeGetCPUStats(virConnectPtr conn,
4451 4452 4453 4454 4455
                   int cpuNum,
                   virNodeCPUStatsPtr params,
                   int *nparams,
                   unsigned int flags)
{
4456 4457 4458
    if (virNodeGetCPUStatsEnsureACL(conn) < 0)
        return -1;

4459 4460 4461 4462 4463
    return nodeGetCPUStats(cpuNum, params, nparams, flags);
}


static int
4464
lxcNodeGetMemoryStats(virConnectPtr conn,
4465 4466 4467 4468 4469
                      int cellNum,
                      virNodeMemoryStatsPtr params,
                      int *nparams,
                      unsigned int flags)
{
4470 4471 4472
    if (virNodeGetMemoryStatsEnsureACL(conn) < 0)
        return -1;

4473 4474 4475 4476 4477
    return nodeGetMemoryStats(cellNum, params, nparams, flags);
}


static int
4478
lxcNodeGetCellsFreeMemory(virConnectPtr conn,
4479 4480 4481 4482
                          unsigned long long *freeMems,
                          int startCell,
                          int maxCells)
{
4483 4484 4485
    if (virNodeGetCellsFreeMemoryEnsureACL(conn) < 0)
        return -1;

4486 4487 4488 4489 4490
    return nodeGetCellsFreeMemory(freeMems, startCell, maxCells);
}


static unsigned long long
4491
lxcNodeGetFreeMemory(virConnectPtr conn)
4492
{
4493 4494 4495
    if (virNodeGetFreeMemoryEnsureACL(conn) < 0)
        return 0;

4496 4497 4498 4499 4500
    return nodeGetFreeMemory();
}


static int
4501
lxcNodeGetMemoryParameters(virConnectPtr conn,
4502 4503 4504 4505
                           virTypedParameterPtr params,
                           int *nparams,
                           unsigned int flags)
{
4506 4507 4508
    if (virNodeGetMemoryParametersEnsureACL(conn) < 0)
        return -1;

4509 4510 4511 4512 4513
    return nodeGetMemoryParameters(params, nparams, flags);
}


static int
4514
lxcNodeSetMemoryParameters(virConnectPtr conn,
4515 4516 4517 4518
                           virTypedParameterPtr params,
                           int nparams,
                           unsigned int flags)
{
4519 4520 4521
    if (virNodeSetMemoryParametersEnsureACL(conn) < 0)
        return -1;

4522 4523 4524 4525 4526
    return nodeSetMemoryParameters(params, nparams, flags);
}


static int
4527
lxcNodeGetCPUMap(virConnectPtr conn,
4528 4529 4530 4531
                 unsigned char **cpumap,
                 unsigned int *online,
                 unsigned int flags)
{
4532 4533 4534
    if (virNodeGetCPUMapEnsureACL(conn) < 0)
        return -1;

4535 4536 4537
    return nodeGetCPUMap(cpumap, online, flags);
}

4538 4539

static int
4540
lxcNodeSuspendForDuration(virConnectPtr conn,
4541 4542 4543 4544
                          unsigned int target,
                          unsigned long long duration,
                          unsigned int flags)
{
4545 4546 4547
    if (virNodeSuspendForDurationEnsureACL(conn) < 0)
        return -1;

4548 4549 4550 4551
    return nodeSuspendForDuration(target, duration, flags);
}


4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619
static int
lxcDomainSetMetadata(virDomainPtr dom,
                      int type,
                      const char *metadata,
                      const char *key,
                      const char *uri,
                      unsigned int flags)
{
    virLXCDriverPtr driver = dom->conn->privateData;
    virDomainObjPtr vm;
    virLXCDriverConfigPtr cfg = NULL;
    virCapsPtr caps = NULL;
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

    if (!(vm = lxcDomObjFromDomain(dom)))
        return -1;

    cfg = virLXCDriverGetConfig(driver);

    if (virDomainSetMetadataEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
        goto cleanup;

    ret = virDomainObjSetMetadata(vm, type, metadata, key, uri, caps,
                                  driver->xmlopt, cfg->configDir, flags);

cleanup:
    virObjectUnlock(vm);
    virObjectUnref(caps);
    virObjectUnref(cfg);
    return ret;
}


static char *
lxcDomainGetMetadata(virDomainPtr dom,
                      int type,
                      const char *uri,
                      unsigned int flags)
{
    virLXCDriverPtr driver = dom->conn->privateData;
    virCapsPtr caps = NULL;
    virDomainObjPtr vm;
    char *ret = NULL;

    if (!(vm = lxcDomObjFromDomain(dom)))
        return NULL;

    if (virDomainGetMetadataEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
        goto cleanup;

    ret = virDomainObjGetMetadata(vm, type, uri, caps, driver->xmlopt, flags);

cleanup:
    virObjectUnlock(vm);
    virObjectUnref(caps);
    return ret;
}


D
Daniel Veillard 已提交
4620 4621
/* Function Tables */
static virDriver lxcDriver = {
4622
    .no = VIR_DRV_LXC,
4623
    .name = LXC_DRIVER_NAME,
4624 4625 4626
    .connectOpen = lxcConnectOpen, /* 0.4.2 */
    .connectClose = lxcConnectClose, /* 0.4.2 */
    .connectGetVersion = lxcConnectGetVersion, /* 0.4.6 */
4627
    .connectGetHostname = lxcConnectGetHostname, /* 0.6.3 */
4628
    .connectGetSysinfo = lxcConnectGetSysinfo, /* 1.0.5 */
4629
    .nodeGetInfo = lxcNodeGetInfo, /* 0.6.5 */
4630 4631 4632 4633 4634
    .connectGetCapabilities = lxcConnectGetCapabilities, /* 0.6.5 */
    .connectListDomains = lxcConnectListDomains, /* 0.4.2 */
    .connectNumOfDomains = lxcConnectNumOfDomains, /* 0.4.2 */
    .connectListAllDomains = lxcConnectListAllDomains, /* 0.9.13 */
    .domainCreateXML = lxcDomainCreateXML, /* 0.4.4 */
4635
    .domainCreateXMLWithFiles = lxcDomainCreateXMLWithFiles, /* 1.1.1 */
4636 4637 4638 4639 4640 4641
    .domainLookupByID = lxcDomainLookupByID, /* 0.4.2 */
    .domainLookupByUUID = lxcDomainLookupByUUID, /* 0.4.2 */
    .domainLookupByName = lxcDomainLookupByName, /* 0.4.2 */
    .domainSuspend = lxcDomainSuspend, /* 0.7.2 */
    .domainResume = lxcDomainResume, /* 0.7.2 */
    .domainDestroy = lxcDomainDestroy, /* 0.4.4 */
4642
    .domainDestroyFlags = lxcDomainDestroyFlags, /* 0.9.4 */
4643
    .domainGetOSType = lxcDomainGetOSType, /* 0.4.2 */
4644 4645 4646 4647 4648
    .domainGetMaxMemory = lxcDomainGetMaxMemory, /* 0.7.2 */
    .domainSetMaxMemory = lxcDomainSetMaxMemory, /* 0.7.2 */
    .domainSetMemory = lxcDomainSetMemory, /* 0.7.2 */
    .domainSetMemoryParameters = lxcDomainSetMemoryParameters, /* 0.8.5 */
    .domainGetMemoryParameters = lxcDomainGetMemoryParameters, /* 0.8.5 */
4649 4650
    .domainSetBlkioParameters = lxcDomainSetBlkioParameters, /* 0.9.8 */
    .domainGetBlkioParameters = lxcDomainGetBlkioParameters, /* 0.9.8 */
4651 4652
    .domainGetInfo = lxcDomainGetInfo, /* 0.4.2 */
    .domainGetState = lxcDomainGetState, /* 0.9.2 */
4653 4654
    .domainGetSecurityLabel = lxcDomainGetSecurityLabel, /* 0.9.10 */
    .nodeGetSecurityModel = lxcNodeGetSecurityModel, /* 0.9.10 */
4655
    .domainGetXMLDesc = lxcDomainGetXMLDesc, /* 0.4.2 */
4656 4657 4658 4659
    .connectListDefinedDomains = lxcConnectListDefinedDomains, /* 0.4.2 */
    .connectNumOfDefinedDomains = lxcConnectNumOfDefinedDomains, /* 0.4.2 */
    .domainCreate = lxcDomainCreate, /* 0.4.4 */
    .domainCreateWithFlags = lxcDomainCreateWithFlags, /* 0.8.2 */
4660
    .domainCreateWithFiles = lxcDomainCreateWithFiles, /* 1.1.1 */
4661
    .domainDefineXML = lxcDomainDefineXML, /* 0.4.2 */
4662
    .domainUndefine = lxcDomainUndefine, /* 0.4.2 */
4663
    .domainUndefineFlags = lxcDomainUndefineFlags, /* 0.9.4 */
4664 4665 4666 4667 4668
    .domainAttachDevice = lxcDomainAttachDevice, /* 1.0.1 */
    .domainAttachDeviceFlags = lxcDomainAttachDeviceFlags, /* 1.0.1 */
    .domainDetachDevice = lxcDomainDetachDevice, /* 1.0.1 */
    .domainDetachDeviceFlags = lxcDomainDetachDeviceFlags, /* 1.0.1 */
    .domainUpdateDeviceFlags = lxcDomainUpdateDeviceFlags, /* 1.0.1 */
4669 4670
    .domainGetAutostart = lxcDomainGetAutostart, /* 0.7.0 */
    .domainSetAutostart = lxcDomainSetAutostart, /* 0.7.0 */
4671 4672 4673 4674 4675
    .domainGetSchedulerType = lxcDomainGetSchedulerType, /* 0.5.0 */
    .domainGetSchedulerParameters = lxcDomainGetSchedulerParameters, /* 0.5.0 */
    .domainGetSchedulerParametersFlags = lxcDomainGetSchedulerParametersFlags, /* 0.9.2 */
    .domainSetSchedulerParameters = lxcDomainSetSchedulerParameters, /* 0.5.0 */
    .domainSetSchedulerParametersFlags = lxcDomainSetSchedulerParametersFlags, /* 0.9.2 */
4676
    .domainInterfaceStats = lxcDomainInterfaceStats, /* 0.7.3 */
4677 4678 4679 4680 4681
    .nodeGetCPUStats = lxcNodeGetCPUStats, /* 0.9.3 */
    .nodeGetMemoryStats = lxcNodeGetMemoryStats, /* 0.9.3 */
    .nodeGetCellsFreeMemory = lxcNodeGetCellsFreeMemory, /* 0.6.5 */
    .nodeGetFreeMemory = lxcNodeGetFreeMemory, /* 0.6.5 */
    .nodeGetCPUMap = lxcNodeGetCPUMap, /* 1.0.0 */
4682 4683 4684 4685
    .connectDomainEventRegister = lxcConnectDomainEventRegister, /* 0.7.0 */
    .connectDomainEventDeregister = lxcConnectDomainEventDeregister, /* 0.7.0 */
    .connectIsEncrypted = lxcConnectIsEncrypted, /* 0.7.3 */
    .connectIsSecure = lxcConnectIsSecure, /* 0.7.3 */
4686 4687 4688
    .domainIsActive = lxcDomainIsActive, /* 0.7.3 */
    .domainIsPersistent = lxcDomainIsPersistent, /* 0.7.3 */
    .domainIsUpdated = lxcDomainIsUpdated, /* 0.8.6 */
4689 4690
    .connectDomainEventRegisterAny = lxcConnectDomainEventRegisterAny, /* 0.8.0 */
    .connectDomainEventDeregisterAny = lxcConnectDomainEventDeregisterAny, /* 0.8.0 */
4691
    .domainOpenConsole = lxcDomainOpenConsole, /* 0.8.6 */
4692
    .connectIsAlive = lxcConnectIsAlive, /* 0.9.8 */
4693
    .nodeSuspendForDuration = lxcNodeSuspendForDuration, /* 0.9.8 */
4694 4695
    .domainSetMetadata = lxcDomainSetMetadata, /* 1.1.3 */
    .domainGetMetadata = lxcDomainGetMetadata, /* 1.1.3 */
4696 4697
    .nodeGetMemoryParameters = lxcNodeGetMemoryParameters, /* 0.10.2 */
    .nodeSetMemoryParameters = lxcNodeSetMemoryParameters, /* 0.10.2 */
4698
    .domainSendProcessSignal = lxcDomainSendProcessSignal, /* 1.0.1 */
4699 4700 4701
    .domainShutdown = lxcDomainShutdown, /* 1.0.1 */
    .domainShutdownFlags = lxcDomainShutdownFlags, /* 1.0.1 */
    .domainReboot = lxcDomainReboot, /* 1.0.1 */
4702
    .domainLxcOpenNamespace = lxcDomainLxcOpenNamespace, /* 1.0.2 */
D
Daniel Veillard 已提交
4703 4704
};

4705
static virStateDriver lxcStateDriver = {
4706
    .name = LXC_DRIVER_NAME,
4707
    .stateInitialize = lxcStateInitialize,
4708
    .stateAutoStart = lxcStateAutoStart,
4709 4710
    .stateCleanup = lxcStateCleanup,
    .stateReload = lxcStateReload,
4711 4712
};

D
Daniel Veillard 已提交
4713 4714 4715
int lxcRegister(void)
{
    virRegisterDriver(&lxcDriver);
4716
    virRegisterStateDriver(&lxcStateDriver);
D
Daniel Veillard 已提交
4717 4718
    return 0;
}