lxc_driver.c 166.3 KB
Newer Older
D
Daniel Veillard 已提交
1
/*
2
 * Copyright (C) 2010-2016 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 33 34 35 36 37 38

#ifdef MAJOR_IN_MKDEV
# include <sys/mkdev.h>
#elif MAJOR_IN_SYSMACROS
# include <sys/sysmacros.h>
#endif

39
#include <sys/socket.h>
40
#include <sys/stat.h>
41 42
#include <sys/un.h>
#include <sys/poll.h>
D
Daniel Veillard 已提交
43 44 45
#include <unistd.h>
#include <wait.h>

46
#include "virerror.h"
47
#include "virlog.h"
48
#include "datatypes.h"
49
#include "lxc_cgroup.h"
D
Daniel Veillard 已提交
50
#include "lxc_conf.h"
51
#include "lxc_container.h"
52
#include "lxc_domain.h"
D
Daniel Veillard 已提交
53
#include "lxc_driver.h"
54
#include "lxc_native.h"
55
#include "lxc_process.h"
56
#include "viralloc.h"
57
#include "virnetdevbridge.h"
58
#include "virnetdevveth.h"
59
#include "virnetdevopenvswitch.h"
60
#include "nodeinfo.h"
61
#include "viruuid.h"
62
#include "virstats.h"
63
#include "virhook.h"
E
Eric Blake 已提交
64
#include "virfile.h"
65
#include "virpidfile.h"
66
#include "fdstream.h"
67
#include "domain_audit.h"
68
#include "domain_nwfilter.h"
69
#include "nwfilter_conf.h"
70
#include "network/bridge_driver.h"
71
#include "virinitctl.h"
72
#include "virnetdev.h"
A
Ansis Atteka 已提交
73
#include "virnetdevtap.h"
74
#include "virnodesuspend.h"
75
#include "virprocess.h"
76
#include "virtime.h"
77
#include "virtypedparam.h"
M
Martin Kletzander 已提交
78
#include "viruri.h"
79
#include "virstring.h"
80 81
#include "viraccessapicheck.h"
#include "viraccessapichecklxc.h"
82
#include "virhostdev.h"
83
#include "netdev_bandwidth_conf.h"
D
Daniel Veillard 已提交
84

85 86
#define VIR_FROM_THIS VIR_FROM_LXC

87
VIR_LOG_INIT("lxc.lxc_driver");
88

89
#define LXC_NB_MEM_PARAM  3
90
#define LXC_NB_DOMAIN_BLOCK_STAT_PARAM 4
91

92

93 94 95 96
static int lxcStateInitialize(bool privileged,
                              virStateInhibitCallback callback,
                              void *opaque);
static int lxcStateCleanup(void);
97
virLXCDriverPtr lxc_driver = NULL;
D
Daniel Veillard 已提交
98

99 100
/* callbacks for nwfilter */
static int
101
lxcVMFilterRebuild(virDomainObjListIterator iter, void *data)
102
{
103
    return virDomainObjListForEach(lxc_driver->domains, iter, data);
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
}

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 已提交
125 126 127 128
/**
 * lxcDomObjFromDomain:
 * @domain: Domain pointer that has to be looked up
 *
129 130
 * This function looks up @domain and returns the appropriate virDomainObjPtr
 * that has to be released by calling virDomainObjEndAPI.
M
Michal Privoznik 已提交
131
 *
132 133
 * Returns the domain object with incremented reference counter which is locked
 * on success, NULL otherwise.
M
Michal Privoznik 已提交
134 135 136 137 138 139 140 141
 */
static virDomainObjPtr
lxcDomObjFromDomain(virDomainPtr domain)
{
    virDomainObjPtr vm;
    virLXCDriverPtr driver = domain->conn->privateData;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

142
    vm = virDomainObjListFindByUUIDRef(driver->domains, domain->uuid);
M
Michal Privoznik 已提交
143 144 145 146 147 148 149 150 151 152 153
    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 已提交
154 155
/* Functions */

156 157
static virDrvOpenStatus lxcConnectOpen(virConnectPtr conn,
                                       virConnectAuthPtr auth ATTRIBUTE_UNUSED,
158
                                       virConfPtr conf ATTRIBUTE_UNUSED,
159
                                       unsigned int flags)
D
Daniel Veillard 已提交
160
{
E
Eric Blake 已提交
161 162
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

D
Daniel Veillard 已提交
163
    /* Verify uri was specified */
164
    if (conn->uri == NULL) {
165 166
        if (lxc_driver == NULL)
            return VIR_DRV_OPEN_DECLINED;
167

168
        if (!(conn->uri = virURIParse("lxc:///")))
169
            return VIR_DRV_OPEN_ERROR;
170 171 172 173 174 175 176 177 178 179
    } 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 */
180 181
        if (conn->uri->path != NULL &&
            STRNEQ(conn->uri->path, "/")) {
182 183 184
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unexpected LXC URI path '%s', try lxc:///"),
                           conn->uri->path);
185 186
            return VIR_DRV_OPEN_ERROR;
        }
D
Daniel Veillard 已提交
187

188 189
        /* URI was good, but driver isn't active */
        if (lxc_driver == NULL) {
190 191
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("lxc state driver is not active"));
192 193 194
            return VIR_DRV_OPEN_ERROR;
        }
    }
195

196 197 198
    if (virConnectOpenEnsureACL(conn) < 0)
        return VIR_DRV_OPEN_ERROR;

199
    conn->privateData = lxc_driver;
D
Daniel Veillard 已提交
200 201 202 203

    return VIR_DRV_OPEN_SUCCESS;
}

204
static int lxcConnectClose(virConnectPtr conn)
D
Daniel Veillard 已提交
205
{
206
    virLXCDriverPtr driver = conn->privateData;
207

208
    virCloseCallbacksRun(driver->closeCallbacks, conn, driver->domains, driver);
209 210
    conn->privateData = NULL;
    return 0;
D
Daniel Veillard 已提交
211 212
}

213

214
static int lxcConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
215 216 217 218 219 220
{
    /* Trivially secure, since always inside the daemon */
    return 1;
}


221
static int lxcConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
222 223 224 225 226 227
{
    /* Not encrypted, but remote driver takes care of that */
    return 0;
}


228
static int lxcConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
229 230 231 232 233
{
    return 1;
}


234
static char *lxcConnectGetCapabilities(virConnectPtr conn) {
235
    virLXCDriverPtr driver = conn->privateData;
236
    virCapsPtr caps;
237 238
    char *xml;

239 240 241
    if (virConnectGetCapabilitiesEnsureACL(conn) < 0)
        return NULL;

242
    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
243 244
        return NULL;

245
    xml = virCapabilitiesFormatXML(caps);
246

247
    virObjectUnref(caps);
248 249 250 251
    return xml;
}


D
Daniel Veillard 已提交
252 253 254
static virDomainPtr lxcDomainLookupByID(virConnectPtr conn,
                                        int id)
{
255
    virLXCDriverPtr driver = conn->privateData;
256 257
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
258

259
    vm = virDomainObjListFindByID(driver->domains, id);
260

D
Daniel Veillard 已提交
261
    if (!vm) {
262 263
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching id %d"), id);
264
        goto cleanup;
D
Daniel Veillard 已提交
265 266
    }

267 268 269
    if (virDomainLookupByIDEnsureACL(conn, vm->def) < 0)
        goto cleanup;

D
Daniel Veillard 已提交
270
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
271
    if (dom)
D
Daniel Veillard 已提交
272 273
        dom->id = vm->def->id;

274
 cleanup:
275
    if (vm)
276
        virObjectUnlock(vm);
D
Daniel Veillard 已提交
277 278 279 280 281 282
    return dom;
}

static virDomainPtr lxcDomainLookupByUUID(virConnectPtr conn,
                                          const unsigned char *uuid)
{
283
    virLXCDriverPtr driver = conn->privateData;
284 285
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
286

287
    vm = virDomainObjListFindByUUIDRef(driver->domains, uuid);
288

D
Daniel Veillard 已提交
289
    if (!vm) {
290 291
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
292 293
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching uuid '%s'"), uuidstr);
294
        goto cleanup;
D
Daniel Veillard 已提交
295 296
    }

297 298 299
    if (virDomainLookupByUUIDEnsureACL(conn, vm->def) < 0)
        goto cleanup;

D
Daniel Veillard 已提交
300
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
301
    if (dom)
D
Daniel Veillard 已提交
302 303
        dom->id = vm->def->id;

304
 cleanup:
305
    virDomainObjEndAPI(&vm);
D
Daniel Veillard 已提交
306 307 308 309 310 311
    return dom;
}

static virDomainPtr lxcDomainLookupByName(virConnectPtr conn,
                                          const char *name)
{
312
    virLXCDriverPtr driver = conn->privateData;
313 314
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
315

316
    vm = virDomainObjListFindByName(driver->domains, name);
D
Daniel Veillard 已提交
317
    if (!vm) {
318 319
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching name '%s'"), name);
320
        goto cleanup;
D
Daniel Veillard 已提交
321 322
    }

323 324 325
    if (virDomainLookupByNameEnsureACL(conn, vm->def) < 0)
        goto cleanup;

D
Daniel Veillard 已提交
326
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
327
    if (dom)
D
Daniel Veillard 已提交
328 329
        dom->id = vm->def->id;

330
 cleanup:
331
    virDomainObjEndAPI(&vm);
D
Daniel Veillard 已提交
332 333 334
    return dom;
}

335 336 337 338 339 340

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

M
Michal Privoznik 已提交
341
    if (!(obj = lxcDomObjFromDomain(dom)))
342
        goto cleanup;
343 344 345 346

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

347 348
    ret = virDomainObjIsActive(obj);

349
 cleanup:
350
    virDomainObjEndAPI(&obj);
351 352 353 354 355 356 357 358 359
    return ret;
}


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

M
Michal Privoznik 已提交
360
    if (!(obj = lxcDomObjFromDomain(dom)))
361
        goto cleanup;
362 363 364 365

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

366 367
    ret = obj->persistent;

368
 cleanup:
369
    virDomainObjEndAPI(&obj);
370 371 372
    return ret;
}

373 374 375 376 377
static int lxcDomainIsUpdated(virDomainPtr dom)
{
    virDomainObjPtr obj;
    int ret = -1;

M
Michal Privoznik 已提交
378
    if (!(obj = lxcDomObjFromDomain(dom)))
379
        goto cleanup;
380 381 382 383

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

384 385
    ret = obj->updated;

386
 cleanup:
387
    virDomainObjEndAPI(&obj);
388 389
    return ret;
}
390

391 392
static int lxcConnectListDomains(virConnectPtr conn, int *ids, int nids)
{
393
    virLXCDriverPtr driver = conn->privateData;
394
    int n;
395

396 397 398
    if (virConnectListDomainsEnsureACL(conn) < 0)
        return -1;

399 400
    n = virDomainObjListGetActiveIDs(driver->domains, ids, nids,
                                     virConnectListDomainsCheckACL, conn);
401

402
    return n;
D
Daniel Veillard 已提交
403
}
404

405 406
static int lxcConnectNumOfDomains(virConnectPtr conn)
{
407
    virLXCDriverPtr driver = conn->privateData;
408
    int n;
409

410 411 412
    if (virConnectNumOfDomainsEnsureACL(conn) < 0)
        return -1;

413 414
    n = virDomainObjListNumOfDomains(driver->domains, true,
                                     virConnectNumOfDomainsCheckACL, conn);
415

416
    return n;
D
Daniel Veillard 已提交
417 418
}

419
static int lxcConnectListDefinedDomains(virConnectPtr conn,
420 421
                                        char **const names, int nnames)
{
422
    virLXCDriverPtr driver = conn->privateData;
423
    int n;
424

425 426 427
    if (virConnectListDefinedDomainsEnsureACL(conn) < 0)
        return -1;

428 429
    n = virDomainObjListGetInactiveNames(driver->domains, names, nnames,
                                         virConnectListDefinedDomainsCheckACL, conn);
430

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


435 436
static int lxcConnectNumOfDefinedDomains(virConnectPtr conn)
{
437
    virLXCDriverPtr driver = conn->privateData;
438
    int n;
439

440 441 442
    if (virConnectNumOfDefinedDomainsEnsureACL(conn) < 0)
        return -1;

443 444
    n = virDomainObjListNumOfDomains(driver->domains, false,
                                     virConnectNumOfDefinedDomainsCheckACL, conn);
445

446
    return n;
D
Daniel Veillard 已提交
447 448
}

449 450


451 452
static virDomainPtr
lxcDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags)
D
Daniel Veillard 已提交
453
{
454
    virLXCDriverPtr driver = conn->privateData;
455
    virDomainDefPtr def = NULL;
456
    virDomainObjPtr vm = NULL;
457
    virDomainPtr dom = NULL;
458
    virObjectEventPtr event = NULL;
459
    virDomainDefPtr oldDef = NULL;
460
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
461
    virCapsPtr caps = NULL;
462
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
D
Daniel Veillard 已提交
463

464 465 466
    virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);

    if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
467
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
468

469 470 471 472
    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
        goto cleanup;

    if (!(def = virDomainDefParseString(xml, caps, driver->xmlopt,
473
                                        parse_flags)))
474
        goto cleanup;
D
Daniel Veillard 已提交
475

476
    if (virDomainDefineXMLFlagsEnsureACL(conn, def) < 0)
477 478
        goto cleanup;

479 480 481
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
        goto cleanup;

482
    if ((def->nets != NULL) && !(cfg->have_netns)) {
483 484
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("System lacks NETNS support"));
485
        goto cleanup;
486 487
    }

488
    if (!(vm = virDomainObjListAdd(driver->domains, def,
489
                                   driver->xmlopt,
490
                                   0, &oldDef)))
491
        goto cleanup;
492 493

    virObjectRef(vm);
494
    def = NULL;
495
    vm->persistent = 1;
D
Daniel Veillard 已提交
496

497
    if (virDomainSaveConfig(cfg->configDir, driver->caps,
498
                            vm->newDef ? vm->newDef : vm->def) < 0) {
499
        virDomainObjListRemove(driver->domains, vm);
500
        goto cleanup;
D
Daniel Veillard 已提交
501 502
    }

503
    event = virDomainEventLifecycleNewFromObj(vm,
504
                                     VIR_DOMAIN_EVENT_DEFINED,
505
                                     !oldDef ?
506 507 508
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);

D
Daniel Veillard 已提交
509
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
510
    if (dom)
D
Daniel Veillard 已提交
511 512
        dom->id = vm->def->id;

513
 cleanup:
514
    virDomainDefFree(def);
515
    virDomainDefFree(oldDef);
516
    virDomainObjEndAPI(&vm);
517
    if (event)
518
        virObjectEventStateQueue(driver->domainEventState, event);
519
    virObjectUnref(caps);
520
    virObjectUnref(cfg);
D
Daniel Veillard 已提交
521 522 523
    return dom;
}

524 525 526 527 528 529
static virDomainPtr
lxcDomainDefineXML(virConnectPtr conn, const char *xml)
{
    return lxcDomainDefineXMLFlags(conn, xml, 0);
}

530 531
static int lxcDomainUndefineFlags(virDomainPtr dom,
                                  unsigned int flags)
D
Daniel Veillard 已提交
532
{
533
    virLXCDriverPtr driver = dom->conn->privateData;
534
    virDomainObjPtr vm;
535
    virObjectEventPtr event = NULL;
536
    int ret = -1;
537
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
D
Daniel Veillard 已提交
538

539 540
    virCheckFlags(0, -1);

M
Michal Privoznik 已提交
541
    if (!(vm = lxcDomObjFromDomain(dom)))
542
        goto cleanup;
D
Daniel Veillard 已提交
543

544 545 546
    if (virDomainUndefineFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

547
    if (!vm->persistent) {
548 549
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Cannot undefine transient domain"));
550
        goto cleanup;
551
    }
D
Daniel Veillard 已提交
552

553 554
    if (virDomainDeleteConfig(cfg->configDir,
                              cfg->autostartDir,
555 556
                              vm) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
557

558
    event = virDomainEventLifecycleNewFromObj(vm,
559 560 561
                                     VIR_DOMAIN_EVENT_UNDEFINED,
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);

562 563 564
    if (virDomainObjIsActive(vm)) {
        vm->persistent = 0;
    } else {
565
        virDomainObjListRemove(driver->domains, vm);
566 567
    }

568
    ret = 0;
D
Daniel Veillard 已提交
569

570
 cleanup:
571
    virDomainObjEndAPI(&vm);
572
    if (event)
573
        virObjectEventStateQueue(driver->domainEventState, event);
574
    virObjectUnref(cfg);
575
    return ret;
D
Daniel Veillard 已提交
576 577
}

578 579 580 581 582
static int lxcDomainUndefine(virDomainPtr dom)
{
    return lxcDomainUndefineFlags(dom, 0);
}

D
Daniel Veillard 已提交
583 584 585
static int lxcDomainGetInfo(virDomainPtr dom,
                            virDomainInfoPtr info)
{
586
    virDomainObjPtr vm;
587
    int ret = -1;
588
    virLXCDomainObjPrivatePtr priv;
D
Daniel Veillard 已提交
589

M
Michal Privoznik 已提交
590
    if (!(vm = lxcDomObjFromDomain(dom)))
591
        goto cleanup;
D
Daniel Veillard 已提交
592

593 594
    priv = vm->privateData;

595 596 597
    if (virDomainGetInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

600
    if (!virDomainObjIsActive(vm)) {
D
Daniel Veillard 已提交
601
        info->cpuTime = 0;
602
        info->memory = vm->def->mem.cur_balloon;
D
Daniel Veillard 已提交
603
    } else {
604
        if (virCgroupGetCpuacctUsage(priv->cgroup, &(info->cpuTime)) < 0) {
605 606
            virReportError(VIR_ERR_OPERATION_FAILED,
                           "%s", _("Cannot read cputime for domain"));
R
Ryota Ozaki 已提交
607 608
            goto cleanup;
        }
609 610 611 612 613
        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();
614
                info->memory = 0;
615
            } else {
616
                goto cleanup;
617
            }
618
        }
D
Daniel Veillard 已提交
619 620
    }

621
    info->maxMem = virDomainDefGetMemoryActual(vm->def);
622
    info->nrVirtCpu = virDomainDefGetVcpus(vm->def);
623
    ret = 0;
D
Daniel Veillard 已提交
624

625
 cleanup:
626
    virDomainObjEndAPI(&vm);
627
    return ret;
D
Daniel Veillard 已提交
628 629
}

630 631 632 633 634 635 636 637 638 639 640
static int
lxcDomainGetState(virDomainPtr dom,
                  int *state,
                  int *reason,
                  unsigned int flags)
{
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

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

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

J
Jiri Denemark 已提交
647
    *state = virDomainObjGetState(vm, reason);
648 649
    ret = 0;

650
 cleanup:
651
    virDomainObjEndAPI(&vm);
652 653 654
    return ret;
}

655
static char *lxcDomainGetOSType(virDomainPtr dom)
D
Daniel Veillard 已提交
656
{
657 658
    virDomainObjPtr vm;
    char *ret = NULL;
659

M
Michal Privoznik 已提交
660
    if (!(vm = lxcDomObjFromDomain(dom)))
661
        goto cleanup;
662

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

666
    if (VIR_STRDUP(ret, virDomainOSTypeToString(vm->def->os.type)) < 0)
667
        goto cleanup;
668

669
 cleanup:
670
    virDomainObjEndAPI(&vm);
671
    return ret;
D
Daniel Veillard 已提交
672 673
}

R
Ryota Ozaki 已提交
674
/* Returns max memory in kb, 0 if error */
675 676 677
static unsigned long long
lxcDomainGetMaxMemory(virDomainPtr dom)
{
R
Ryota Ozaki 已提交
678
    virDomainObjPtr vm;
679
    unsigned long long ret = 0;
R
Ryota Ozaki 已提交
680

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

684 685 686
    if (virDomainGetMaxMemoryEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

687
    ret = virDomainDefGetMemoryActual(vm->def);
R
Ryota Ozaki 已提交
688

689
 cleanup:
690
    virDomainObjEndAPI(&vm);
R
Ryota Ozaki 已提交
691 692 693
    return ret;
}

694 695
static int lxcDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem,
                                   unsigned int flags)
696
{
R
Ryota Ozaki 已提交
697
    virDomainObjPtr vm;
698
    virDomainDefPtr def = NULL;
699
    virDomainDefPtr persistentDef = NULL;
R
Ryota Ozaki 已提交
700
    int ret = -1;
701
    virLXCDomainObjPrivatePtr priv;
702 703 704 705
    virLXCDriverPtr driver = dom->conn->privateData;
    virLXCDriverConfigPtr cfg = NULL;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
706 707
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_DOMAIN_MEM_MAXIMUM, -1);
R
Ryota Ozaki 已提交
708

M
Michal Privoznik 已提交
709
    if (!(vm = lxcDomObjFromDomain(dom)))
R
Ryota Ozaki 已提交
710
        goto cleanup;
M
Michal Privoznik 已提交
711

712 713
    cfg = virLXCDriverGetConfig(driver);

714
    priv = vm->privateData;
R
Ryota Ozaki 已提交
715

716
    if (virDomainSetMemoryFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
717 718
        goto cleanup;

719
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
720 721
        goto cleanup;

722
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
723
        goto endjob;
724

725
    if (flags & VIR_DOMAIN_MEM_MAXIMUM) {
726
        if (def) {
727 728 729
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Cannot resize the max memory "
                             "on an active domain"));
730
            goto endjob;
731
        }
732

733
        if (persistentDef) {
734
            virDomainDefSetMemoryTotal(persistentDef, newmem);
735 736
            if (persistentDef->mem.cur_balloon > newmem)
                persistentDef->mem.cur_balloon = newmem;
737 738
            if (virDomainSaveConfig(cfg->configDir, driver->caps,
                                    persistentDef) < 0)
739
                goto endjob;
740 741 742
        }
    } else {
        unsigned long oldmax = 0;
R
Ryota Ozaki 已提交
743

744 745 746
        if (def)
            oldmax = virDomainDefGetMemoryActual(def);
        if (persistentDef) {
747 748
            if (!oldmax || oldmax > virDomainDefGetMemoryActual(persistentDef))
                oldmax = virDomainDefGetMemoryActual(persistentDef);
749
        }
750

751 752 753
        if (newmem > oldmax) {
            virReportError(VIR_ERR_INVALID_ARG,
                           "%s", _("Cannot set memory higher than max memory"));
754
            goto endjob;
755 756
        }

757
        if (def) {
758 759 760
            if (virCgroupSetMemory(priv->cgroup, newmem) < 0) {
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("Failed to set memory for domain"));
761
                goto endjob;
762
            }
763

764
            def->mem.cur_balloon = newmem;
765
            if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
766
                goto endjob;
767 768
        }

769
        if (persistentDef) {
770
            persistentDef->mem.cur_balloon = newmem;
771 772
            if (virDomainSaveConfig(cfg->configDir, driver->caps,
                                    persistentDef) < 0)
773
                goto endjob;
774
        }
775 776
    }

R
Ryota Ozaki 已提交
777 778
    ret = 0;

779
 endjob:
780
    virLXCDomainObjEndJob(driver, vm);
781

782
 cleanup:
783
    virDomainObjEndAPI(&vm);
784
    virObjectUnref(cfg);
R
Ryota Ozaki 已提交
785 786 787
    return ret;
}

788 789 790 791 792
static int lxcDomainSetMemory(virDomainPtr dom, unsigned long newmem)
{
    return lxcDomainSetMemoryFlags(dom, newmem, VIR_DOMAIN_AFFECT_LIVE);
}

793 794 795 796 797
static int lxcDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax)
{
    return lxcDomainSetMemoryFlags(dom, newmax, VIR_DOMAIN_MEM_MAXIMUM);
}

798 799 800 801 802
static int
lxcDomainSetMemoryParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int nparams,
                             unsigned int flags)
803
{
804
    virCapsPtr caps = NULL;
J
Ján Tomko 已提交
805
    virDomainDefPtr persistentDef = NULL;
806
    virDomainObjPtr vm = NULL;
807 808 809 810 811 812 813 814 815 816
    virLXCDomainObjPrivatePtr priv = NULL;
    virLXCDriverConfigPtr cfg = NULL;
    virLXCDriverPtr driver = dom->conn->privateData;
    unsigned long long hard_limit;
    unsigned long long soft_limit;
    unsigned long long swap_hard_limit;
    bool set_hard_limit = false;
    bool set_soft_limit = false;
    bool set_swap_hard_limit = false;
    int rc;
817 818
    int ret = -1;

819 820 821
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

822 823 824 825 826 827 828 829
    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)
830
        return -1;
E
Eric Blake 已提交
831

M
Michal Privoznik 已提交
832
    if (!(vm = lxcDomObjFromDomain(dom)))
833
        goto cleanup;
M
Michal Privoznik 已提交
834

835
    priv = vm->privateData;
836
    cfg = virLXCDriverGetConfig(driver);
837

838
    if (virDomainSetMemoryParametersEnsureACL(dom->conn, vm->def, flags) < 0 ||
839
        !(caps = virLXCDriverGetCapabilities(driver, false)))
840 841
        goto cleanup;

842 843 844
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

845
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt,
J
Ján Tomko 已提交
846
                                        vm, &flags, &persistentDef) < 0)
847 848
        goto endjob;

849 850 851 852
    if (flags & VIR_DOMAIN_AFFECT_LIVE &&
        !virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_MEMORY)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup memory controller is not mounted"));
853
        goto endjob;
854 855 856 857
    }

#define VIR_GET_LIMIT_PARAMETER(PARAM, VALUE)                                \
    if ((rc = virTypedParamsGetULLong(params, nparams, PARAM, &VALUE)) < 0)  \
858
        goto endjob;                                                         \
859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880
                                                                             \
    if (rc == 1)                                                             \
        set_ ## VALUE = true;

    VIR_GET_LIMIT_PARAMETER(VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT, swap_hard_limit)
    VIR_GET_LIMIT_PARAMETER(VIR_DOMAIN_MEMORY_HARD_LIMIT, hard_limit)
    VIR_GET_LIMIT_PARAMETER(VIR_DOMAIN_MEMORY_SOFT_LIMIT, soft_limit)

#undef VIR_GET_LIMIT_PARAMETER

    /* Swap hard limit must be greater than hard limit.
     * Note that limit of 0 denotes unlimited */
    if (set_swap_hard_limit || set_hard_limit) {
        unsigned long long mem_limit = vm->def->mem.hard_limit;
        unsigned long long swap_limit = vm->def->mem.swap_hard_limit;

        if (set_swap_hard_limit)
            swap_limit = swap_hard_limit;

        if (set_hard_limit)
            mem_limit = hard_limit;

881
        if (mem_limit > swap_limit) {
882 883 884
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("memory hard_limit tunable value must be lower "
                             "than or equal to swap_hard_limit"));
885
            goto endjob;
886 887 888
        }
    }

889
#define LXC_SET_MEM_PARAMETER(FUNC, VALUE)                                      \
890 891 892 893 894 895
    if (set_ ## VALUE) {                                                        \
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {                                   \
            if ((rc = FUNC(priv->cgroup, VALUE)) < 0) {                         \
                virReportSystemError(-rc, _("unable to set memory %s tunable"), \
                                     #VALUE);                                   \
                                                                                \
896
                goto endjob;                                                    \
897 898 899 900 901
            }                                                                   \
            vm->def->mem.VALUE = VALUE;                                         \
        }                                                                       \
                                                                                \
        if (flags & VIR_DOMAIN_AFFECT_CONFIG)                                   \
J
Ján Tomko 已提交
902
            persistentDef->mem.VALUE = VALUE;                                   \
903 904 905 906 907 908
    }

    /* Soft limit doesn't clash with the others */
    LXC_SET_MEM_PARAMETER(virCgroupSetMemorySoftLimit, soft_limit);

    /* set hard limit before swap hard limit if decreasing it */
909
    if (vm->def->mem.hard_limit > hard_limit) {
910 911 912 913 914 915 916 917 918 919 920 921 922
        LXC_SET_MEM_PARAMETER(virCgroupSetMemoryHardLimit, hard_limit);
        /* inhibit changing the limit a second time */
        set_hard_limit = false;
    }

    LXC_SET_MEM_PARAMETER(virCgroupSetMemSwapHardLimit, swap_hard_limit);

    /* otherwise increase it after swap hard limit */
    LXC_SET_MEM_PARAMETER(virCgroupSetMemoryHardLimit, hard_limit);

#undef LXC_SET_MEM_PARAMETER

    if (flags & VIR_DOMAIN_AFFECT_CONFIG &&
J
Ján Tomko 已提交
923
        virDomainSaveConfig(cfg->configDir, driver->caps, persistentDef) < 0)
924
        goto endjob;
925 926

    ret = 0;
927 928

 endjob:
929
    virLXCDomainObjEndJob(driver, vm);
930

931
 cleanup:
932
    virDomainObjEndAPI(&vm);
933 934
    virObjectUnref(caps);
    virObjectUnref(cfg);
935 936 937
    return ret;
}

938 939 940 941 942
static int
lxcDomainGetMemoryParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int *nparams,
                             unsigned int flags)
943
{
J
Ján Tomko 已提交
944
    virDomainDefPtr persistentDef = NULL;
945
    virDomainDefPtr def = NULL;
946
    virDomainObjPtr vm = NULL;
947
    virLXCDomainObjPrivatePtr priv = NULL;
948
    unsigned long long val;
949
    int ret = -1;
950
    size_t i;
951

952
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
953 954 955 956 957
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);

    /* We don't return strings, and thus trivially support this flag.  */
    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;
E
Eric Blake 已提交
958

M
Michal Privoznik 已提交
959
    if (!(vm = lxcDomObjFromDomain(dom)))
960
        goto cleanup;
M
Michal Privoznik 已提交
961

962
    priv = vm->privateData;
963

964
    if (virDomainGetMemoryParametersEnsureACL(dom->conn, vm->def) < 0)
965 966
        goto cleanup;

967 968 969 970
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
        goto cleanup;

    if (def &&
971 972 973
        !virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_MEMORY)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup memory controller is not mounted"));
974
        goto cleanup;
975
    }
976

977 978 979 980 981 982 983
    if ((*nparams) == 0) {
        /* Current number of memory parameters supported by cgroups */
        *nparams = LXC_NB_MEM_PARAM;
        ret = 0;
        goto cleanup;
    }

984
    for (i = 0; i < LXC_NB_MEM_PARAM && i < *nparams; i++) {
985
        virTypedParameterPtr param = &params[i];
986 987
        val = 0;

988
        switch (i) {
989
        case 0: /* fill memory hard limit here */
990
            if (persistentDef) {
J
Ján Tomko 已提交
991
                val = persistentDef->mem.hard_limit;
992
            } else if (virCgroupGetMemoryHardLimit(priv->cgroup, &val) < 0) {
993
                goto cleanup;
994
            }
995 996
            if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_HARD_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
997
                goto cleanup;
998 999
            break;
        case 1: /* fill memory soft limit here */
1000
            if (persistentDef) {
J
Ján Tomko 已提交
1001
                val = persistentDef->mem.soft_limit;
1002
            } else if (virCgroupGetMemorySoftLimit(priv->cgroup, &val) < 0) {
1003
                goto cleanup;
1004
            }
1005 1006
            if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_SOFT_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
1007
                goto cleanup;
1008 1009
            break;
        case 2: /* fill swap hard limit here */
1010
            if (persistentDef) {
J
Ján Tomko 已提交
1011
                val = persistentDef->mem.swap_hard_limit;
1012
            } else if (virCgroupGetMemSwapHardLimit(priv->cgroup, &val) < 0) {
1013
                goto cleanup;
1014
            }
1015 1016 1017
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
1018
                goto cleanup;
1019 1020 1021 1022
            break;
        }
    }

1023 1024
    if (*nparams > LXC_NB_MEM_PARAM)
        *nparams = LXC_NB_MEM_PARAM;
1025 1026
    ret = 0;

1027
 cleanup:
1028
    virDomainObjEndAPI(&vm);
1029 1030 1031
    return ret;
}

1032
static char *lxcDomainGetXMLDesc(virDomainPtr dom,
1033
                                 unsigned int flags)
D
Daniel Veillard 已提交
1034
{
1035
    virLXCDriverPtr driver = dom->conn->privateData;
1036 1037
    virDomainObjPtr vm;
    char *ret = NULL;
D
Daniel Veillard 已提交
1038

1039 1040
    /* Flags checked by virDomainDefFormat */

M
Michal Privoznik 已提交
1041
    if (!(vm = lxcDomObjFromDomain(dom)))
1042
        goto cleanup;
D
Daniel Veillard 已提交
1043

1044 1045 1046
    if (virDomainGetXMLDescEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

1047
    ret = virDomainDefFormat((flags & VIR_DOMAIN_XML_INACTIVE) &&
1048
                             vm->newDef ? vm->newDef : vm->def,
1049
                             driver->caps,
1050
                             virDomainDefFormatConvertXMLFlags(flags));
1051

1052
 cleanup:
1053
    virDomainObjEndAPI(&vm);
1054
    return ret;
D
Daniel Veillard 已提交
1055 1056
}

1057 1058 1059 1060 1061 1062 1063
static char *lxcConnectDomainXMLFromNative(virConnectPtr conn,
                                           const char *nativeFormat,
                                           const char *nativeConfig,
                                           unsigned int flags)
{
    char *xml = NULL;
    virDomainDefPtr def = NULL;
1064 1065
    virLXCDriverPtr driver = conn->privateData;
    virCapsPtr caps = virLXCDriverGetCapabilities(driver, false);
1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077

    virCheckFlags(0, NULL);

    if (virConnectDomainXMLFromNativeEnsureACL(conn) < 0)
        goto cleanup;

    if (STRNEQ(nativeFormat, LXC_CONFIG_FORMAT)) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unsupported config type %s"), nativeFormat);
        goto cleanup;
    }

1078
    if (!(def = lxcParseConfigString(nativeConfig, caps, driver->xmlopt)))
1079 1080
        goto cleanup;

1081
    xml = virDomainDefFormat(def, caps, 0);
1082

1083
 cleanup:
1084
    virObjectUnref(caps);
1085 1086 1087 1088
    virDomainDefFree(def);
    return xml;
}

1089
/**
1090
 * lxcDomainCreateWithFiles:
1091
 * @dom: domain to start
1092
 * @flags: Must be 0 for now
1093 1094 1095 1096 1097
 *
 * Looks up domain and starts it.
 *
 * Returns 0 on success or -1 in case of error
 */
1098 1099 1100 1101
static int lxcDomainCreateWithFiles(virDomainPtr dom,
                                    unsigned int nfiles,
                                    int *files,
                                    unsigned int flags)
1102
{
1103
    virLXCDriverPtr driver = dom->conn->privateData;
1104
    virDomainObjPtr vm;
1105
    virObjectEventPtr event = NULL;
1106
    int ret = -1;
1107
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
1108

1109
    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, -1);
1110

1111 1112
    virNWFilterReadLockFilterUpdates();

M
Michal Privoznik 已提交
1113
    if (!(vm = lxcDomObjFromDomain(dom)))
1114 1115
        goto cleanup;

1116
    if (virDomainCreateWithFilesEnsureACL(dom->conn, vm->def) < 0)
1117 1118
        goto cleanup;

1119
    if ((vm->def->nets != NULL) && !(cfg->have_netns)) {
1120 1121
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("System lacks NETNS support"));
1122 1123 1124
        goto cleanup;
    }

1125 1126 1127
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

1128
    if (virDomainObjIsActive(vm)) {
1129 1130
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is already running"));
1131
        goto endjob;
1132 1133
    }

1134
    ret = virLXCProcessStart(dom->conn, driver, vm,
1135
                             nfiles, files,
1136 1137
                             (flags & VIR_DOMAIN_START_AUTODESTROY),
                             VIR_DOMAIN_RUNNING_BOOTED);
1138

1139
    if (ret == 0) {
1140
        event = virDomainEventLifecycleNewFromObj(vm,
1141 1142
                                         VIR_DOMAIN_EVENT_STARTED,
                                         VIR_DOMAIN_EVENT_STARTED_BOOTED);
1143 1144 1145 1146
        virDomainAuditStart(vm, "booted", true);
    } else {
        virDomainAuditStart(vm, "booted", false);
    }
1147

1148
 endjob:
1149
    virLXCDomainObjEndJob(driver, vm);
1150

1151
 cleanup:
1152
    virDomainObjEndAPI(&vm);
1153
    if (event)
1154
        virObjectEventStateQueue(driver->domainEventState, event);
1155
    virObjectUnref(cfg);
1156
    virNWFilterUnlockFilterUpdates();
1157
    return ret;
1158 1159
}

1160
/**
1161
 * lxcDomainCreate:
1162 1163 1164 1165 1166 1167
 * @dom: domain to start
 *
 * Looks up domain and starts it.
 *
 * Returns 0 on success or -1 in case of error
 */
1168
static int lxcDomainCreate(virDomainPtr dom)
1169
{
1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184
    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);
1185 1186
}

1187
/**
1188
 * lxcDomainCreateXMLWithFiles:
1189 1190
 * @conn: pointer to connection
 * @xml: XML definition of domain
1191 1192 1193
 * @nfiles: number of file descriptors passed
 * @files: list of file descriptors passed
 * @flags: bitwise-OR of supported virDomainCreateFlags
1194 1195 1196
 *
 * Creates a domain based on xml and starts it
 *
1197
 * Returns a new domain object or NULL in case of failure.
1198 1199
 */
static virDomainPtr
1200 1201 1202 1203
lxcDomainCreateXMLWithFiles(virConnectPtr conn,
                            const char *xml,
                            unsigned int nfiles,
                            int *files,
1204 1205
                            unsigned int flags)
{
1206
    virLXCDriverPtr driver = conn->privateData;
1207
    virDomainObjPtr vm = NULL;
1208
    virDomainDefPtr def = NULL;
1209
    virDomainPtr dom = NULL;
1210
    virObjectEventPtr event = NULL;
1211
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
1212
    virCapsPtr caps = NULL;
1213 1214 1215 1216 1217
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;

    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY |
                  VIR_DOMAIN_START_VALIDATE, NULL);

1218

1219
    if (flags & VIR_DOMAIN_START_VALIDATE)
1220
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
1221

1222 1223
    virNWFilterReadLockFilterUpdates();

1224 1225 1226 1227
    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
        goto cleanup;

    if (!(def = virDomainDefParseString(xml, caps, driver->xmlopt,
1228
                                        parse_flags)))
1229
        goto cleanup;
1230

1231
    if (virDomainCreateXMLWithFilesEnsureACL(conn, def) < 0)
1232 1233
        goto cleanup;

1234 1235 1236
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
        goto cleanup;

1237
    if ((def->nets != NULL) && !(cfg->have_netns)) {
1238 1239
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       "%s", _("System lacks NETNS support"));
1240
        goto cleanup;
1241 1242
    }

1243

1244
    if (!(vm = virDomainObjListAdd(driver->domains, def,
1245
                                   driver->xmlopt,
1246
                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
1247 1248
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
1249 1250
        goto cleanup;
    def = NULL;
1251

1252 1253 1254 1255 1256 1257 1258 1259
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0) {
        if (!vm->persistent) {
            virDomainObjListRemove(driver->domains, vm);
            vm = NULL;
        }
        goto cleanup;
    }

1260
    if (virLXCProcessStart(conn, driver, vm,
1261
                           nfiles, files,
1262 1263
                           (flags & VIR_DOMAIN_START_AUTODESTROY),
                           VIR_DOMAIN_RUNNING_BOOTED) < 0) {
1264
        virDomainAuditStart(vm, "booted", false);
1265 1266 1267 1268
        if (!vm->persistent) {
            virDomainObjListRemove(driver->domains, vm);
            vm = NULL;
        }
1269
        goto endjob;
1270 1271
    }

1272
    event = virDomainEventLifecycleNewFromObj(vm,
1273 1274
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
1275
    virDomainAuditStart(vm, "booted", true);
1276

1277
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1278
    if (dom)
1279 1280
        dom->id = vm->def->id;

1281
 endjob:
1282
    virLXCDomainObjEndJob(driver, vm);
1283

1284
 cleanup:
1285
    virDomainDefFree(def);
1286
    virDomainObjEndAPI(&vm);
1287
    if (event)
1288
        virObjectEventStateQueue(driver->domainEventState, event);
1289
    virObjectUnref(caps);
1290
    virObjectUnref(cfg);
1291
    virNWFilterUnlockFilterUpdates();
1292 1293 1294
    return dom;
}

1295 1296 1297 1298 1299 1300 1301 1302 1303 1304
/**
 * lxcDomainCreateXML:
 * @conn: pointer to connection
 * @xml: XML definition of domain
 * @flags: bitwise-OR of supported virDomainCreateFlags
 *
 * Creates a domain based on xml and starts it
 *
 * Returns a new domain object or NULL in case of failure.
 */
1305 1306 1307
static virDomainPtr
lxcDomainCreateXML(virConnectPtr conn,
                   const char *xml,
1308 1309
                   unsigned int flags)
{
1310 1311 1312 1313
    return lxcDomainCreateXMLWithFiles(conn, xml, 0, NULL,  flags);
}


1314 1315
static int lxcDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr seclabel)
{
1316
    virLXCDriverPtr driver = dom->conn->privateData;
1317 1318 1319 1320 1321
    virDomainObjPtr vm;
    int ret = -1;

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

M
Michal Privoznik 已提交
1322
    if (!(vm = lxcDomObjFromDomain(dom)))
1323 1324
        goto cleanup;

1325 1326 1327
    if (virDomainGetSecurityLabelEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1328
    if (!virDomainVirtTypeToString(vm->def->virtType)) {
1329 1330 1331
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown virt type in domain definition '%d'"),
                       vm->def->virtType);
1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349
        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)) {
1350 1351 1352 1353 1354 1355 1356 1357
        virLXCDomainObjPrivatePtr priv = vm->privateData;

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

1358
        if (virSecurityManagerGetProcessLabel(driver->securityManager,
1359
                                              vm->def, priv->initpid, seclabel) < 0) {
1360 1361
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("Failed to get security label"));
1362 1363 1364 1365 1366 1367
            goto cleanup;
        }
    }

    ret = 0;

1368
 cleanup:
1369
    virDomainObjEndAPI(&vm);
1370 1371 1372 1373 1374 1375
    return ret;
}

static int lxcNodeGetSecurityModel(virConnectPtr conn,
                                   virSecurityModelPtr secmodel)
{
1376
    virLXCDriverPtr driver = conn->privateData;
1377
    virCapsPtr caps = NULL;
1378 1379 1380 1381
    int ret = 0;

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

1382 1383 1384
    if (virNodeGetSecurityModelEnsureACL(conn) < 0)
        goto cleanup;

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

1388
    /* we treat no driver as success, but simply return no data in *secmodel */
1389 1390
    if (caps->host.nsecModels == 0
        || caps->host.secModels[0].model == NULL)
1391 1392
        goto cleanup;

1393
    if (!virStrcpy(secmodel->model, caps->host.secModels[0].model,
1394
                   VIR_SECURITY_MODEL_BUFLEN)) {
1395 1396 1397
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security model string exceeds max %d bytes"),
                       VIR_SECURITY_MODEL_BUFLEN - 1);
1398 1399 1400 1401
        ret = -1;
        goto cleanup;
    }

1402
    if (!virStrcpy(secmodel->doi, caps->host.secModels[0].doi,
1403
                   VIR_SECURITY_DOI_BUFLEN)) {
1404 1405 1406
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security DOI string exceeds max %d bytes"),
                       VIR_SECURITY_DOI_BUFLEN-1);
1407 1408 1409 1410
        ret = -1;
        goto cleanup;
    }

1411
 cleanup:
1412
    virObjectUnref(caps);
1413 1414 1415 1416
    return ret;
}


1417
static int
1418 1419 1420 1421
lxcConnectDomainEventRegister(virConnectPtr conn,
                              virConnectDomainEventCallback callback,
                              void *opaque,
                              virFreeCallback freecb)
1422
{
1423
    virLXCDriverPtr driver = conn->privateData;
1424

1425 1426 1427
    if (virConnectDomainEventRegisterEnsureACL(conn) < 0)
        return -1;

1428 1429 1430 1431
    if (virDomainEventStateRegister(conn,
                                    driver->domainEventState,
                                    callback, opaque, freecb) < 0)
        return -1;
1432

1433
    return 0;
1434 1435
}

1436

1437
static int
1438 1439
lxcConnectDomainEventDeregister(virConnectPtr conn,
                                virConnectDomainEventCallback callback)
1440
{
1441
    virLXCDriverPtr driver = conn->privateData;
1442

1443 1444 1445
    if (virConnectDomainEventDeregisterEnsureACL(conn) < 0)
        return -1;

1446 1447 1448 1449
    if (virDomainEventStateDeregister(conn,
                                      driver->domainEventState,
                                      callback) < 0)
        return -1;
1450

1451
    return 0;
1452 1453
}

1454 1455

static int
1456 1457 1458 1459 1460 1461
lxcConnectDomainEventRegisterAny(virConnectPtr conn,
                                 virDomainPtr dom,
                                 int eventID,
                                 virConnectDomainEventGenericCallback callback,
                                 void *opaque,
                                 virFreeCallback freecb)
1462
{
1463
    virLXCDriverPtr driver = conn->privateData;
1464 1465
    int ret;

1466 1467 1468
    if (virConnectDomainEventRegisterAnyEnsureACL(conn) < 0)
        return -1;

1469 1470 1471 1472
    if (virDomainEventStateRegisterID(conn,
                                      driver->domainEventState,
                                      dom, eventID,
                                      callback, opaque, freecb, &ret) < 0)
1473
        ret = -1;
1474 1475 1476 1477 1478 1479

    return ret;
}


static int
1480 1481
lxcConnectDomainEventDeregisterAny(virConnectPtr conn,
                                   int callbackID)
1482
{
1483
    virLXCDriverPtr driver = conn->privateData;
1484

1485 1486 1487
    if (virConnectDomainEventDeregisterAnyEnsureACL(conn) < 0)
        return -1;

1488 1489 1490 1491
    if (virObjectEventStateDeregisterID(conn,
                                        driver->domainEventState,
                                        callbackID) < 0)
        return -1;
1492

1493
    return 0;
1494 1495 1496
}


1497
/**
1498
 * lxcDomainDestroyFlags:
1499
 * @dom: pointer to domain to destroy
1500
 * @flags: extra flags; not used yet.
1501 1502 1503 1504 1505
 *
 * Sends SIGKILL to container root process to terminate the container
 *
 * Returns 0 on success or -1 in case of error
 */
1506 1507 1508
static int
lxcDomainDestroyFlags(virDomainPtr dom,
                      unsigned int flags)
1509
{
1510
    virLXCDriverPtr driver = dom->conn->privateData;
1511
    virDomainObjPtr vm;
1512
    virObjectEventPtr event = NULL;
1513
    int ret = -1;
1514
    virLXCDomainObjPrivatePtr priv;
1515

1516 1517
    virCheckFlags(0, -1);

M
Michal Privoznik 已提交
1518
    if (!(vm = lxcDomObjFromDomain(dom)))
1519
        goto cleanup;
1520

1521 1522 1523
    if (virDomainDestroyFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1524 1525 1526
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

1527
    if (!virDomainObjIsActive(vm)) {
1528 1529
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not running"));
1530
        goto endjob;
1531 1532
    }

1533
    priv = vm->privateData;
1534
    ret = virLXCProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED);
1535
    event = virDomainEventLifecycleNewFromObj(vm,
1536 1537
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
1538
    priv->doneStopEvent = true;
1539
    virDomainAuditStop(vm, "destroyed");
1540

1541
 endjob:
1542
    virLXCDomainObjEndJob(driver, vm);
1543 1544
    if (!vm->persistent)
        virDomainObjListRemove(driver->domains, vm);
1545

1546
 cleanup:
1547
    virDomainObjEndAPI(&vm);
1548
    if (event)
1549
        virObjectEventStateQueue(driver->domainEventState, event);
1550
    return ret;
1551
}
1552

1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566
/**
 * 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);
}

1567 1568 1569 1570 1571
static int lxcCheckNetNsSupport(void)
{
    const char *argv[] = {"ip", "link", "set", "lo", "netns", "-1", NULL};
    int ip_rc;

1572
    if (virRun(argv, &ip_rc) < 0 || ip_rc == 255)
1573
        return 0;
1574

1575 1576
    if (lxcContainerAvailable(LXC_CONTAINER_FEATURE_NET) < 0)
        return 0;
1577

1578
    return 1;
1579 1580
}

1581

1582 1583
static virSecurityManagerPtr
lxcSecurityInit(virLXCDriverConfigPtr cfg)
1584
{
1585 1586
    unsigned int flags = VIR_SECURITY_MANAGER_PRIVILEGED;

1587
    VIR_INFO("lxcSecurityInit %s", cfg->securityDriverName);
1588 1589 1590 1591 1592 1593

    if (cfg->securityDefaultConfined)
        flags |= VIR_SECURITY_MANAGER_DEFAULT_CONFINED;
    if (cfg->securityRequireConfined)
        flags |= VIR_SECURITY_MANAGER_REQUIRE_CONFINED;

1594
    virSecurityManagerPtr mgr = virSecurityManagerNew(cfg->securityDriverName,
1595
                                                      LXC_DRIVER_NAME, flags);
1596 1597 1598
    if (!mgr)
        goto error;

1599
    return mgr;
1600

1601
 error:
1602
    VIR_ERROR(_("Failed to initialize security drivers"));
1603
    virObjectUnref(mgr);
1604
    return NULL;
1605 1606 1607
}


1608 1609 1610
static int lxcStateInitialize(bool privileged,
                              virStateInhibitCallback callback ATTRIBUTE_UNUSED,
                              void *opaque ATTRIBUTE_UNUSED)
D
Daniel Veillard 已提交
1611
{
1612
    virCapsPtr caps = NULL;
1613
    const char *ld;
1614
    virLXCDriverConfigPtr cfg = NULL;
1615 1616 1617 1618 1619

    /* Valgrind gets very annoyed when we clone containers, so
     * disable LXC when under valgrind
     * XXX remove this when valgrind is fixed
     */
1620
    ld = virGetEnvBlockSUID("LD_PRELOAD");
1621
    if (ld && strstr(ld, "vgpreload")) {
1622
        VIR_INFO("Running under valgrind, disabling driver");
1623 1624
        return 0;
    }
1625

1626
    /* Check that the user is root, silently disable if not */
1627
    if (!privileged) {
1628
        VIR_INFO("Not running privileged, disabling driver");
1629 1630 1631 1632 1633
        return 0;
    }

    /* Check that this is a container enabled kernel */
    if (lxcContainerAvailable(0) < 0) {
1634
        VIR_INFO("LXC support not available in this kernel, disabling driver");
1635
        return 0;
1636 1637
    }

1638
    if (VIR_ALLOC(lxc_driver) < 0)
1639
        return -1;
1640 1641 1642 1643
    if (virMutexInit(&lxc_driver->lock) < 0) {
        VIR_FREE(lxc_driver);
        return -1;
    }
D
Daniel Veillard 已提交
1644

1645
    if (!(lxc_driver->domains = virDomainObjListNew()))
1646 1647
        goto cleanup;

1648
    lxc_driver->domainEventState = virObjectEventStateNew();
1649
    if (!lxc_driver->domainEventState)
1650 1651
        goto cleanup;

1652 1653
    lxc_driver->hostsysinfo = virSysinfoRead();

1654 1655 1656 1657 1658
    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 已提交
1659 1660

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

1664
    if (!(lxc_driver->securityManager = lxcSecurityInit(cfg)))
1665 1666
        goto cleanup;

1667
    if (!(lxc_driver->hostdevMgr = virHostdevManagerGetDefault()))
G
Guido Günther 已提交
1668 1669
        goto cleanup;

1670
    if ((virLXCDriverGetCapabilities(lxc_driver, true)) == NULL)
1671
        goto cleanup;
D
Daniel Veillard 已提交
1672

1673
    if (!(lxc_driver->xmlopt = lxcDomainXMLConfInit()))
1674
        goto cleanup;
1675

1676
    if (!(lxc_driver->closeCallbacks = virCloseCallbacksNew()))
1677 1678
        goto cleanup;

1679 1680 1681
    if (!(caps = virLXCDriverGetCapabilities(lxc_driver, false)))
        goto cleanup;

1682 1683 1684 1685 1686 1687 1688
    if (virFileMakePath(cfg->stateDir) < 0) {
        virReportSystemError(errno,
                             _("Failed to mkdir %s"),
                             cfg->stateDir);
        goto cleanup;
    }

O
Osier Yang 已提交
1689
    /* Get all the running persistent or transient configs first */
1690
    if (virDomainObjListLoadAllConfigs(lxc_driver->domains,
1691
                                       cfg->stateDir,
1692
                                       NULL, 1,
1693
                                       caps,
1694
                                       lxc_driver->xmlopt,
1695
                                       NULL, NULL) < 0)
O
Osier Yang 已提交
1696 1697
        goto cleanup;

1698
    virLXCProcessReconnectAll(lxc_driver, lxc_driver->domains);
O
Osier Yang 已提交
1699 1700

    /* Then inactive persistent configs */
1701
    if (virDomainObjListLoadAllConfigs(lxc_driver->domains,
1702 1703
                                       cfg->configDir,
                                       cfg->autostartDir, 0,
1704
                                       caps,
1705
                                       lxc_driver->xmlopt,
1706
                                       NULL, NULL) < 0)
1707
        goto cleanup;
1708

1709
    virNWFilterRegisterCallbackDriver(&lxcCallbackDriver);
D
Daniel Veillard 已提交
1710 1711
    return 0;

1712
 cleanup:
1713
    virObjectUnref(caps);
1714
    lxcStateCleanup();
1715
    return -1;
D
Daniel Veillard 已提交
1716 1717
}

1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730
/**
 * lxcStateAutoStart:
 *
 * Function to autostart the LXC daemons
 */
static void lxcStateAutoStart(void)
{
    if (!lxc_driver)
        return;

    virLXCProcessAutostartAll(lxc_driver);
}

1731 1732
static void lxcNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
{
1733
    virLXCDriverPtr driver = opaque;
1734 1735

    if (newVM) {
1736
        virObjectEventPtr event =
1737
            virDomainEventLifecycleNewFromObj(vm,
1738 1739 1740
                                     VIR_DOMAIN_EVENT_DEFINED,
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED);
        if (event)
1741
            virObjectEventStateQueue(driver->domainEventState, event);
1742 1743 1744 1745
    }
}

/**
1746
 * lxcStateReload:
1747 1748 1749 1750 1751
 *
 * Function to restart the LXC driver, it will recheck the configuration
 * files and perform autostart
 */
static int
1752 1753
lxcStateReload(void)
{
1754
    virLXCDriverConfigPtr cfg = NULL;
1755
    virCapsPtr caps = NULL;
1756

1757 1758 1759
    if (!lxc_driver)
        return 0;

1760
    if (!(caps = virLXCDriverGetCapabilities(lxc_driver, false)))
1761 1762
        return -1;

1763 1764
    cfg = virLXCDriverGetConfig(lxc_driver);

1765
    virDomainObjListLoadAllConfigs(lxc_driver->domains,
1766 1767
                                   cfg->configDir,
                                   cfg->autostartDir, 0,
1768
                                   caps,
1769
                                   lxc_driver->xmlopt,
1770
                                   lxcNotifyLoadDomain, lxc_driver);
1771
    virObjectUnref(caps);
1772
    virObjectUnref(cfg);
1773 1774 1775
    return 0;
}

1776
static int lxcStateCleanup(void)
D
Daniel Veillard 已提交
1777
{
1778
    if (lxc_driver == NULL)
1779
        return -1;
1780

1781
    virNWFilterUnRegisterCallbackDriver(&lxcCallbackDriver);
1782
    virObjectUnref(lxc_driver->domains);
1783
    virObjectEventStateFree(lxc_driver->domainEventState);
1784

1785
    virObjectUnref(lxc_driver->closeCallbacks);
1786

1787 1788
    virSysinfoDefFree(lxc_driver->hostsysinfo);

1789
    virObjectUnref(lxc_driver->hostdevMgr);
1790
    virObjectUnref(lxc_driver->caps);
1791
    virObjectUnref(lxc_driver->securityManager);
1792
    virObjectUnref(lxc_driver->xmlopt);
1793
    virObjectUnref(lxc_driver->config);
1794
    virMutexDestroy(&lxc_driver->lock);
1795
    VIR_FREE(lxc_driver);
1796 1797 1798

    return 0;
}
D
Daniel Veillard 已提交
1799

1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813
static int
lxcConnectSupportsFeature(virConnectPtr conn, int feature)
{
    if (virConnectSupportsFeatureEnsureACL(conn) < 0)
        return -1;

    switch (feature) {
        case VIR_DRV_FEATURE_TYPED_PARAM_STRING:
            return 1;
        default:
            return 0;
    }
}

D
Daniel Veillard 已提交
1814

1815
static int lxcConnectGetVersion(virConnectPtr conn, unsigned long *version)
D
Dan Smith 已提交
1816 1817 1818
{
    struct utsname ver;

1819
    uname(&ver);
D
Dan Smith 已提交
1820

1821 1822 1823
    if (virConnectGetVersionEnsureACL(conn) < 0)
        return -1;

1824
    if (virParseVersionString(ver.release, version, true) < 0) {
1825
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Unknown release: %s"), ver.release);
D
Dan Smith 已提交
1826 1827 1828 1829 1830
        return -1;
    }

    return 0;
}
1831

1832

1833
static char *lxcConnectGetHostname(virConnectPtr conn)
1834
{
1835 1836 1837
    if (virConnectGetHostnameEnsureACL(conn) < 0)
        return NULL;

1838 1839 1840 1841
    return virGetHostname();
}


1842 1843
static char *lxcDomainGetSchedulerType(virDomainPtr dom,
                                       int *nparams)
1844
{
1845
    char *ret = NULL;
1846 1847
    virDomainObjPtr vm;
    virLXCDomainObjPrivatePtr priv;
1848

M
Michal Privoznik 已提交
1849
    if (!(vm = lxcDomObjFromDomain(dom)))
1850
        goto cleanup;
M
Michal Privoznik 已提交
1851

1852 1853
    priv = vm->privateData;

1854 1855 1856
    if (virDomainGetSchedulerTypeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1857 1858 1859 1860 1861 1862 1863 1864
    /* Domain not running, thus no cgroups - return defaults */
    if (!virDomainObjIsActive(vm)) {
        if (nparams)
            *nparams = 3;
        ignore_value(VIR_STRDUP(ret, "posix"));
        goto cleanup;
    }

1865
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
1866 1867
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPU controller is not mounted"));
1868 1869
        goto cleanup;
    }
1870

1871
    if (nparams) {
1872
        if (virCgroupSupportsCpuBW(priv->cgroup))
1873
            *nparams = 3;
1874 1875
        else
            *nparams = 1;
1876
    }
1877

1878
    ignore_value(VIR_STRDUP(ret, "posix"));
1879

1880
 cleanup:
1881
    virDomainObjEndAPI(&vm);
1882 1883 1884 1885 1886 1887 1888 1889
    return ret;
}


static int
lxcGetVcpuBWLive(virCgroupPtr cgroup, unsigned long long *period,
                 long long *quota)
{
1890
    if (virCgroupGetCpuCfsPeriod(cgroup, period) < 0)
1891 1892
        return -1;

1893
    if (virCgroupGetCpuCfsQuota(cgroup, quota) < 0)
1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909
        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 */
1910
        if (virCgroupGetCpuCfsPeriod(cgroup, &old_period) < 0)
1911 1912
            return -1;

1913
        if (virCgroupSetCpuCfsPeriod(cgroup, period) < 0)
1914 1915 1916 1917
            return -1;
    }

    if (quota) {
1918 1919
        if (virCgroupSetCpuCfsQuota(cgroup, quota) < 0)
            goto error;
1920 1921 1922 1923
    }

    return 0;

1924
 error:
1925
    if (period) {
1926 1927 1928 1929 1930 1931
        virErrorPtr saved = virSaveLastError();
        virCgroupSetCpuCfsPeriod(cgroup, old_period);
        if (saved) {
            virSetError(saved);
            virFreeError(saved);
        }
1932 1933 1934
    }

    return -1;
1935 1936
}

1937

1938
static int
1939 1940 1941 1942
lxcDomainSetSchedulerParametersFlags(virDomainPtr dom,
                                     virTypedParameterPtr params,
                                     int nparams,
                                     unsigned int flags)
1943
{
1944
    virLXCDriverPtr driver = dom->conn->privateData;
1945
    virCapsPtr caps = NULL;
1946
    size_t i;
1947
    virDomainObjPtr vm = NULL;
1948
    virDomainDefPtr def = NULL;
J
Ján Tomko 已提交
1949 1950
    virDomainDefPtr persistentDefCopy = NULL;
    virDomainDefPtr persistentDef = NULL;
1951
    int ret = -1;
1952
    int rc;
1953
    virLXCDomainObjPrivatePtr priv;
1954
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
1955

1956 1957
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
1958 1959 1960 1961 1962 1963 1964 1965
    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)
1966
        return -1;
1967

M
Michal Privoznik 已提交
1968
    if (!(vm = lxcDomObjFromDomain(dom)))
1969
        goto cleanup;
M
Michal Privoznik 已提交
1970

1971
    priv = vm->privateData;
1972

1973 1974 1975
    if (virDomainSetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

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

1979 1980 1981
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

1982
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
1983
        goto endjob;
1984

1985
    if (persistentDef) {
1986
        /* Make a copy for updated domain. */
J
Ján Tomko 已提交
1987 1988
        persistentDefCopy = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt);
        if (!persistentDefCopy)
1989
            goto endjob;
1990 1991
    }

1992
    if (def) {
1993
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
1994 1995
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup CPU controller is not mounted"));
1996
            goto endjob;
1997 1998
        }
    }
1999 2000

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

2003
        if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_CPU_SHARES)) {
2004
            if (def) {
2005
                unsigned long long val;
2006
                if (virCgroupSetCpuShares(priv->cgroup, params[i].value.ul) < 0)
2007
                    goto endjob;
2008

2009
                if (virCgroupGetCpuShares(priv->cgroup, &val) < 0)
2010
                    goto endjob;
2011

2012 2013
                def->cputune.shares = val;
                def->cputune.sharesSpecified = true;
2014 2015
            }

2016
            if (persistentDef) {
J
Ján Tomko 已提交
2017 2018
                persistentDefCopy->cputune.shares = params[i].value.ul;
                persistentDefCopy->cputune.sharesSpecified = true;
2019 2020
            }
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_PERIOD)) {
2021
            if (def) {
2022
                rc = lxcSetVcpuBWLive(priv->cgroup, params[i].value.ul, 0);
2023
                if (rc != 0)
2024
                    goto endjob;
2025 2026

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

2030
            if (persistentDef)
J
Ján Tomko 已提交
2031
                persistentDefCopy->cputune.period = params[i].value.ul;
2032
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_QUOTA)) {
2033
            if (def) {
2034
                rc = lxcSetVcpuBWLive(priv->cgroup, 0, params[i].value.l);
2035
                if (rc != 0)
2036
                    goto endjob;
2037 2038

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

2042
            if (persistentDef)
J
Ján Tomko 已提交
2043
                persistentDefCopy->cputune.quota = params[i].value.l;
2044
        }
2045
    }
2046

2047
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
2048
        goto endjob;
2049

2050

2051
    if (persistentDef) {
J
Ján Tomko 已提交
2052
        rc = virDomainSaveConfig(cfg->configDir, driver->caps, persistentDefCopy);
2053
        if (rc < 0)
2054
            goto endjob;
2055

J
Ján Tomko 已提交
2056 2057
        virDomainObjAssignDef(vm, persistentDefCopy, false, NULL);
        persistentDefCopy = NULL;
2058
    }
2059

2060
    ret = 0;
2061

2062
 endjob:
2063
    virLXCDomainObjEndJob(driver, vm);
2064

2065
 cleanup:
J
Ján Tomko 已提交
2066
    virDomainDefFree(persistentDefCopy);
2067
    virDomainObjEndAPI(&vm);
2068
    virObjectUnref(caps);
2069
    virObjectUnref(cfg);
2070
    return ret;
2071 2072
}

2073
static int
2074 2075 2076
lxcDomainSetSchedulerParameters(virDomainPtr domain,
                                virTypedParameterPtr params,
                                int nparams)
2077
{
2078
    return lxcDomainSetSchedulerParametersFlags(domain, params, nparams, 0);
2079 2080 2081
}

static int
2082 2083 2084 2085
lxcDomainGetSchedulerParametersFlags(virDomainPtr dom,
                                     virTypedParameterPtr params,
                                     int *nparams,
                                     unsigned int flags)
2086
{
2087
    virDomainObjPtr vm = NULL;
2088
    virDomainDefPtr def;
E
Eric Blake 已提交
2089
    virDomainDefPtr persistentDef;
2090 2091 2092
    unsigned long long shares = 0;
    unsigned long long period = 0;
    long long quota = 0;
2093
    int ret = -1;
2094 2095 2096
    int rc;
    bool cpu_bw_status = false;
    int saved_nparams = 0;
2097
    virLXCDomainObjPrivatePtr priv;
2098

2099
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
2100 2101 2102 2103 2104
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);

    /* We don't return strings, and thus trivially support this flag.  */
    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;
2105

M
Michal Privoznik 已提交
2106
    if (!(vm = lxcDomObjFromDomain(dom)))
2107
        goto cleanup;
M
Michal Privoznik 已提交
2108

2109 2110
    priv = vm->privateData;

2111 2112 2113
    if (virDomainGetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2114 2115
    if (*nparams > 1)
        cpu_bw_status = virCgroupSupportsCpuBW(priv->cgroup);
2116

2117
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
E
Eric Blake 已提交
2118
        goto cleanup;
2119

2120
    if (persistentDef) {
E
Eric Blake 已提交
2121
        shares = persistentDef->cputune.shares;
2122
        if (*nparams > 1) {
E
Eric Blake 已提交
2123 2124
            period = persistentDef->cputune.period;
            quota = persistentDef->cputune.quota;
2125
            cpu_bw_status = true; /* Allow copy of data to params[] */
2126 2127 2128 2129
        }
        goto out;
    }

2130
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
2131 2132
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPU controller is not mounted"));
2133
        goto cleanup;
2134 2135
    }

2136
    if (virCgroupGetCpuShares(priv->cgroup, &shares) < 0)
2137
        goto cleanup;
2138 2139

    if (*nparams > 1 && cpu_bw_status) {
2140
        rc = lxcGetVcpuBWLive(priv->cgroup, &period, &quota);
2141 2142 2143
        if (rc != 0)
            goto cleanup;
    }
2144
 out:
2145 2146
    if (virTypedParameterAssign(&params[0], VIR_DOMAIN_SCHEDULER_CPU_SHARES,
                                VIR_TYPED_PARAM_ULLONG, shares) < 0)
C
Chris Lalancette 已提交
2147
        goto cleanup;
2148 2149 2150 2151
    saved_nparams++;

    if (cpu_bw_status) {
        if (*nparams > saved_nparams) {
2152 2153 2154
            if (virTypedParameterAssign(&params[1],
                                        VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
                                        VIR_TYPED_PARAM_ULLONG, period) < 0)
2155 2156 2157 2158 2159
                goto cleanup;
            saved_nparams++;
        }

        if (*nparams > saved_nparams) {
2160 2161 2162
            if (virTypedParameterAssign(&params[2],
                                        VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
                                        VIR_TYPED_PARAM_LLONG, quota) < 0)
2163 2164 2165 2166 2167 2168 2169
                goto cleanup;
            saved_nparams++;
        }
    }

    *nparams = saved_nparams;

2170
    ret = 0;
2171

2172
 cleanup:
2173
    virDomainObjEndAPI(&vm);
2174
    return ret;
2175 2176
}

2177
static int
2178 2179 2180
lxcDomainGetSchedulerParameters(virDomainPtr domain,
                                virTypedParameterPtr params,
                                int *nparams)
2181
{
2182
    return lxcDomainGetSchedulerParametersFlags(domain, params, nparams, 0);
2183 2184
}

2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212
static int
lxcDomainParseBlkioDeviceStr(char *blkioDeviceStr, const char *type,
                             virBlkioDevicePtr *dev, size_t *size)
{
    char *temp;
    int ndevices = 0;
    int nsep = 0;
    size_t i;
    virBlkioDevicePtr result = NULL;

    *dev = NULL;
    *size = 0;

    if (STREQ(blkioDeviceStr, ""))
        return 0;

    temp = blkioDeviceStr;
    while (temp) {
        temp = strchr(temp, ',');
        if (temp) {
            temp++;
            nsep++;
        }
    }

    /* A valid string must have even number of fields, hence an odd
     * number of commas.  */
    if (!(nsep & 1))
2213
        goto parse_error;
2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227

    ndevices = (nsep + 1) / 2;

    if (VIR_ALLOC_N(result, ndevices) < 0)
        return -1;

    i = 0;
    temp = blkioDeviceStr;
    while (temp) {
        char *p = temp;

        /* device path */
        p = strchr(p, ',');
        if (!p)
2228
            goto parse_error;
2229 2230 2231 2232 2233 2234 2235 2236

        if (VIR_STRNDUP(result[i].path, temp, p - temp) < 0)
            goto cleanup;

        /* value */
        temp = p + 1;

        if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
2237
            if (virStrToLong_uip(temp, &p, 10, &result[i].weight) < 0)
2238
                goto number_error;
2239
        } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS)) {
2240
            if (virStrToLong_uip(temp, &p, 10, &result[i].riops) < 0)
2241
                goto number_error;
2242
        } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS)) {
2243
            if (virStrToLong_uip(temp, &p, 10, &result[i].wiops) < 0)
2244
                goto number_error;
2245
        } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS)) {
2246
            if (virStrToLong_ullp(temp, &p, 10, &result[i].rbps) < 0)
2247
                goto number_error;
2248
        } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
2249
            if (virStrToLong_ullp(temp, &p, 10, &result[i].wbps) < 0)
2250
                goto number_error;
2251
        } else {
2252 2253 2254
            virReportError(VIR_ERR_INVALID_ARG,
                           _("unknown parameter '%s'"), type);
            goto cleanup;
2255 2256 2257 2258 2259 2260 2261
        }

        i++;

        if (*p == '\0')
            break;
        else if (*p != ',')
2262
            goto parse_error;
2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273
        temp = p + 1;
    }

    if (!i)
        VIR_FREE(result);

    *dev = result;
    *size = i;

    return 0;

2274
 parse_error:
2275 2276 2277
    virReportError(VIR_ERR_INVALID_ARG,
                   _("unable to parse blkio device '%s' '%s'"),
                   type, blkioDeviceStr);
2278 2279 2280 2281 2282 2283 2284
    goto cleanup;

 number_error:
    virReportError(VIR_ERR_INVALID_ARG,
                   _("invalid value '%s' for parameter '%s' of device '%s'"),
                   temp, type, result[i].path);

2285
 cleanup:
J
John Ferlan 已提交
2286 2287 2288 2289
    if (result) {
        virBlkioDeviceArrayClear(result, ndevices);
        VIR_FREE(result);
    }
2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311
    return -1;
}

static int
lxcDomainMergeBlkioDevice(virBlkioDevicePtr *dest_array,
                          size_t *dest_size,
                          virBlkioDevicePtr src_array,
                          size_t src_size,
                          const char *type)
{
    size_t i, j;
    virBlkioDevicePtr dest, src;

    for (i = 0; i < src_size; i++) {
        bool found = false;

        src = &src_array[i];
        for (j = 0; j < *dest_size; j++) {
            dest = &(*dest_array)[j];
            if (STREQ(src->path, dest->path)) {
                found = true;

2312
                if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
2313
                    dest->weight = src->weight;
2314
                } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS)) {
2315
                    dest->riops = src->riops;
2316
                } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS)) {
2317
                    dest->wiops = src->wiops;
2318
                } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS)) {
2319
                    dest->rbps = src->rbps;
2320
                } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
2321
                    dest->wbps = src->wbps;
2322
                } else {
2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337
                    virReportError(VIR_ERR_INVALID_ARG, _("Unknown parameter %s"),
                                   type);
                    return -1;
                }

                break;
            }
        }
        if (!found) {
            if (!src->weight && !src->riops && !src->wiops && !src->rbps && !src->wbps)
                continue;
            if (VIR_EXPAND_N(*dest_array, *dest_size, 1) < 0)
                return -1;
            dest = &(*dest_array)[*dest_size - 1];

2338
            if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
2339
                dest->weight = src->weight;
2340
            } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS)) {
2341
                dest->riops = src->riops;
2342
            } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS)) {
2343
                dest->wiops = src->wiops;
2344
            } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS)) {
2345
                dest->rbps = src->rbps;
2346
            } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
2347
                dest->wbps = src->wbps;
2348
            } else {
2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360
                *dest_size = *dest_size - 1;
                return -1;
            }

            dest->path = src->path;
            src->path = NULL;
        }
    }

    return 0;
}

2361

2362 2363 2364
static int
lxcDomainBlockStats(virDomainPtr dom,
                    const char *path,
2365
                    virDomainBlockStatsPtr stats)
2366
{
2367
    virLXCDriverPtr driver = dom->conn->privateData;
2368
    int ret = -1;
2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380
    virDomainObjPtr vm;
    virDomainDiskDefPtr disk = NULL;
    virLXCDomainObjPrivatePtr priv;

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

    priv = vm->privateData;

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

2381 2382 2383
   if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_QUERY) < 0)
        goto cleanup;

2384 2385 2386
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
2387
        goto endjob;
2388 2389 2390 2391 2392
    }

    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("blkio cgroup isn't mounted"));
2393
        goto endjob;
2394 2395 2396 2397 2398 2399 2400 2401 2402
    }

    if (!*path) {
        /* empty path - return entire domain blkstats instead */
        ret = virCgroupGetBlkioIoServiced(priv->cgroup,
                                          &stats->rd_bytes,
                                          &stats->wr_bytes,
                                          &stats->rd_req,
                                          &stats->wr_req);
2403
        goto endjob;
2404 2405
    }

2406
    if (!(disk = virDomainDiskByName(vm->def, path, false))) {
2407 2408
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path: %s"), path);
2409
        goto endjob;
2410 2411 2412 2413 2414
    }

    if (!disk->info.alias) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("missing disk device alias name for %s"), disk->dst);
2415
        goto endjob;
2416 2417 2418 2419 2420 2421 2422 2423
    }

    ret = virCgroupGetBlkioIoDeviceServiced(priv->cgroup,
                                            disk->info.alias,
                                            &stats->rd_bytes,
                                            &stats->wr_bytes,
                                            &stats->rd_req,
                                            &stats->wr_req);
2424 2425

 endjob:
2426
    virLXCDomainObjEndJob(driver, vm);
2427

2428
 cleanup:
2429
    virDomainObjEndAPI(&vm);
2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440
    return ret;
}


static int
lxcDomainBlockStatsFlags(virDomainPtr dom,
                         const char * path,
                         virTypedParameterPtr params,
                         int * nparams,
                         unsigned int flags)
{
2441
    virLXCDriverPtr driver = dom->conn->privateData;
2442
    int tmp, ret = -1;
2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466
    virDomainObjPtr vm;
    virDomainDiskDefPtr disk = NULL;
    virLXCDomainObjPrivatePtr priv;
    long long rd_req, rd_bytes, wr_req, wr_bytes;
    virTypedParameterPtr param;

    virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);

    /* We don't return strings, and thus trivially support this flag.  */
    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;

    if (!params && !*nparams) {
        *nparams = LXC_NB_DOMAIN_BLOCK_STAT_PARAM;
        return 0;
    }

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

    priv = vm->privateData;

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

2467 2468 2469
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_QUERY) < 0)
        goto cleanup;

2470 2471 2472
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
2473
        goto endjob;
2474 2475 2476 2477 2478
    }

    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("blkio cgroup isn't mounted"));
2479
        goto endjob;
2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490
    }

    if (!*path) {
        /* empty path - return entire domain blkstats instead */
        if (virCgroupGetBlkioIoServiced(priv->cgroup,
                                        &rd_bytes,
                                        &wr_bytes,
                                        &rd_req,
                                        &wr_req) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("domain stats query failed"));
2491
            goto endjob;
2492 2493
        }
    } else {
2494
        if (!(disk = virDomainDiskByName(vm->def, path, false))) {
2495 2496
            virReportError(VIR_ERR_INVALID_ARG,
                           _("invalid path: %s"), path);
2497
            goto endjob;
2498 2499 2500 2501 2502
        }

        if (!disk->info.alias) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("missing disk device alias name for %s"), disk->dst);
2503
            goto endjob;
2504 2505 2506 2507 2508 2509 2510 2511 2512 2513
        }

        if (virCgroupGetBlkioIoDeviceServiced(priv->cgroup,
                                              disk->info.alias,
                                              &rd_bytes,
                                              &wr_bytes,
                                              &rd_req,
                                              &wr_req) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("domain stats query failed"));
2514
            goto endjob;
2515 2516 2517 2518 2519 2520 2521 2522 2523 2524
        }
    }

    tmp = 0;
    ret = -1;

    if (tmp < *nparams && wr_bytes != -1) {
        param = &params[tmp];
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_WRITE_BYTES,
                                    VIR_TYPED_PARAM_LLONG, wr_bytes) < 0)
2525
            goto endjob;
2526 2527 2528 2529 2530 2531 2532
        tmp++;
    }

    if (tmp < *nparams && wr_req != -1) {
        param = &params[tmp];
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_WRITE_REQ,
                                    VIR_TYPED_PARAM_LLONG, wr_req) < 0)
2533
            goto endjob;
2534 2535 2536 2537 2538 2539 2540
        tmp++;
    }

    if (tmp < *nparams && rd_bytes != -1) {
        param = &params[tmp];
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_READ_BYTES,
                                    VIR_TYPED_PARAM_LLONG, rd_bytes) < 0)
2541
            goto endjob;
2542 2543 2544 2545 2546 2547 2548
        tmp++;
    }

    if (tmp < *nparams && rd_req != -1) {
        param = &params[tmp];
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_READ_REQ,
                                    VIR_TYPED_PARAM_LLONG, rd_req) < 0)
2549
            goto endjob;
2550 2551 2552 2553 2554 2555
        tmp++;
    }

    ret = 0;
    *nparams = tmp;

2556
 endjob:
2557
    virLXCDomainObjEndJob(driver, vm);
2558

2559
 cleanup:
2560
    virDomainObjEndAPI(&vm);
2561 2562 2563 2564
    return ret;
}


2565 2566 2567 2568 2569
static int
lxcDomainSetBlkioParameters(virDomainPtr dom,
                            virTypedParameterPtr params,
                            int nparams,
                            unsigned int flags)
2570
{
2571
    virLXCDriverPtr driver = dom->conn->privateData;
2572
    size_t i;
2573
    virDomainObjPtr vm = NULL;
2574
    virDomainDefPtr def = NULL;
2575 2576
    virDomainDefPtr persistentDef = NULL;
    int ret = -1;
2577
    virLXCDriverConfigPtr cfg = NULL;
2578
    virLXCDomainObjPrivatePtr priv;
2579 2580 2581

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
2582 2583 2584
    if (virTypedParamsValidate(params, nparams,
                               VIR_DOMAIN_BLKIO_WEIGHT,
                               VIR_TYPED_PARAM_UINT,
2585 2586 2587 2588 2589 2590 2591 2592 2593 2594
                               VIR_DOMAIN_BLKIO_DEVICE_WEIGHT,
                               VIR_TYPED_PARAM_STRING,
                               VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS,
                               VIR_TYPED_PARAM_STRING,
                               VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS,
                               VIR_TYPED_PARAM_STRING,
                               VIR_DOMAIN_BLKIO_DEVICE_READ_BPS,
                               VIR_TYPED_PARAM_STRING,
                               VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS,
                               VIR_TYPED_PARAM_STRING,
2595
                               NULL) < 0)
2596 2597
        return -1;

M
Michal Privoznik 已提交
2598
    if (!(vm = lxcDomObjFromDomain(dom)))
2599
        return -1;
M
Michal Privoznik 已提交
2600

2601
    priv = vm->privateData;
2602
    cfg = virLXCDriverGetConfig(driver);
2603

2604 2605 2606
    if (virDomainSetBlkioParametersEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

2607 2608 2609
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

2610
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
2611
        goto endjob;
2612

2613
    if (def) {
2614
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) {
2615 2616
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("blkio cgroup isn't mounted"));
2617
            goto endjob;
2618
        }
2619
    }
2620

2621
    ret = 0;
2622
    if (def) {
2623 2624 2625 2626
        for (i = 0; i < nparams; i++) {
            virTypedParameterPtr param = &params[i];

            if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
2627
                if (virCgroupSetBlkioWeight(priv->cgroup, params[i].value.ui) < 0)
2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649
                    ret = -1;
            } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT) ||
                       STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS) ||
                       STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS) ||
                       STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS) ||
                       STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
                size_t ndevices;
                virBlkioDevicePtr devices = NULL;
                size_t j;

                if (lxcDomainParseBlkioDeviceStr(params[i].value.s,
                                                 param->field,
                                                 &devices,
                                                 &ndevices) < 0) {
                    ret = -1;
                    continue;
                }

                if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
                    for (j = 0; j < ndevices; j++) {
                        if (virCgroupSetBlkioDeviceWeight(priv->cgroup,
                                                          devices[j].path,
2650 2651 2652 2653
                                                          devices[j].weight) < 0 ||
                            virCgroupGetBlkioDeviceWeight(priv->cgroup,
                                                          devices[j].path,
                                                          &devices[j].weight) < 0) {
2654 2655 2656 2657 2658 2659 2660 2661
                            ret = -1;
                            break;
                        }
                    }
                } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS)) {
                    for (j = 0; j < ndevices; j++) {
                        if (virCgroupSetBlkioDeviceReadIops(priv->cgroup,
                                                            devices[j].path,
2662 2663 2664 2665
                                                            devices[j].riops) < 0 ||
                            virCgroupGetBlkioDeviceReadIops(priv->cgroup,
                                                            devices[j].path,
                                                            &devices[j].riops) < 0) {
2666 2667 2668 2669 2670 2671 2672 2673
                            ret = -1;
                            break;
                        }
                    }
                } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS)) {
                    for (j = 0; j < ndevices; j++) {
                        if (virCgroupSetBlkioDeviceWriteIops(priv->cgroup,
                                                             devices[j].path,
2674 2675 2676 2677
                                                             devices[j].wiops) < 0 ||
                            virCgroupGetBlkioDeviceWriteIops(priv->cgroup,
                                                             devices[j].path,
                                                             &devices[j].wiops) < 0) {
2678 2679 2680 2681 2682 2683 2684 2685
                            ret = -1;
                            break;
                        }
                    }
                } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS)) {
                    for (j = 0; j < ndevices; j++) {
                        if (virCgroupSetBlkioDeviceReadBps(priv->cgroup,
                                                           devices[j].path,
2686 2687 2688 2689
                                                           devices[j].rbps) < 0 ||
                            virCgroupGetBlkioDeviceReadBps(priv->cgroup,
                                                           devices[j].path,
                                                           &devices[j].rbps) < 0) {
2690 2691 2692 2693
                            ret = -1;
                            break;
                        }
                    }
2694
                } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
2695 2696 2697
                    for (j = 0; j < ndevices; j++) {
                        if (virCgroupSetBlkioDeviceWriteBps(priv->cgroup,
                                                            devices[j].path,
2698 2699 2700 2701
                                                            devices[j].wbps) < 0 ||
                            virCgroupGetBlkioDeviceWriteBps(priv->cgroup,
                                                            devices[j].path,
                                                            &devices[j].wbps) < 0) {
2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716
                            ret = -1;
                            break;
                        }
                    }
                } else {
                    virReportError(VIR_ERR_INVALID_ARG, _("Unknown blkio parameter %s"),
                                   param->field);
                    ret = -1;
                    virBlkioDeviceArrayClear(devices, ndevices);
                    VIR_FREE(devices);

                    continue;
                }

                if (j != ndevices ||
2717 2718
                    lxcDomainMergeBlkioDevice(&def->blkio.devices,
                                              &def->blkio.ndevices,
2719 2720 2721 2722
                                              devices, ndevices, param->field) < 0)
                    ret = -1;
                virBlkioDeviceArrayClear(devices, ndevices);
                VIR_FREE(devices);
2723 2724
            }
        }
E
Eric Blake 已提交
2725
    }
2726
    if (ret < 0)
2727
        goto endjob;
2728
    if (persistentDef) {
2729 2730 2731 2732 2733
        for (i = 0; i < nparams; i++) {
            virTypedParameterPtr param = &params[i];

            if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
                persistentDef->blkio.weight = params[i].value.ui;
2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754
            } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT) ||
                       STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS) ||
                       STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS) ||
                       STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS) ||
                       STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
                virBlkioDevicePtr devices = NULL;
                size_t ndevices;

                if (lxcDomainParseBlkioDeviceStr(params[i].value.s,
                                                 param->field,
                                                 &devices,
                                                 &ndevices) < 0) {
                    ret = -1;
                    continue;
                }
                if (lxcDomainMergeBlkioDevice(&persistentDef->blkio.devices,
                                              &persistentDef->blkio.ndevices,
                                              devices, ndevices, param->field) < 0)
                    ret = -1;
                virBlkioDeviceArrayClear(devices, ndevices);
                VIR_FREE(devices);
2755 2756 2757
            }
        }

2758
        if (virDomainSaveConfig(cfg->configDir, driver->caps, persistentDef) < 0)
2759
            ret = -1;
2760 2761
    }

2762
 endjob:
2763
    virLXCDomainObjEndJob(driver, vm);
2764

2765
 cleanup:
2766
    virDomainObjEndAPI(&vm);
2767
    virObjectUnref(cfg);
2768 2769 2770 2771
    return ret;
}


2772 2773
#define LXC_NB_BLKIO_PARAM  6

2774 2775 2776 2777 2778
static int
lxcDomainGetBlkioParameters(virDomainPtr dom,
                            virTypedParameterPtr params,
                            int *nparams,
                            unsigned int flags)
2779 2780
{
    virDomainObjPtr vm = NULL;
2781
    virDomainDefPtr def = NULL;
2782
    virDomainDefPtr persistentDef = NULL;
2783
    int maxparams = LXC_NB_BLKIO_PARAM;
2784 2785
    unsigned int val;
    int ret = -1;
2786
    virLXCDomainObjPrivatePtr priv;
2787 2788

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
2789 2790 2791 2792 2793 2794 2795
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);

    /* We blindly return a string, and let libvirt.c and
     * remote_driver.c do the filtering on behalf of older clients
     * that can't parse it.  */
    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;
2796

M
Michal Privoznik 已提交
2797
    if (!(vm = lxcDomObjFromDomain(dom)))
2798
        return -1;
M
Michal Privoznik 已提交
2799

2800
    priv = vm->privateData;
2801

2802 2803 2804
    if (virDomainGetBlkioParametersEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2805 2806 2807 2808 2809
    if ((*nparams) == 0) {
        /* Current number of blkio parameters supported by cgroups */
        *nparams = LXC_NB_BLKIO_PARAM;
        ret = 0;
        goto cleanup;
2810 2811
    } else if (*nparams < maxparams) {
        maxparams = *nparams;
2812 2813
    }

2814 2815
    *nparams = 0;

2816
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
E
Eric Blake 已提交
2817
        goto cleanup;
2818

2819
    if (def) {
2820
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) {
2821 2822
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("blkio cgroup isn't mounted"));
2823 2824 2825
            goto cleanup;
        }

2826 2827 2828 2829 2830 2831 2832
        /* fill blkio weight here */
        if (virCgroupGetBlkioWeight(priv->cgroup, &val) < 0)
            goto cleanup;
        if (virTypedParameterAssign(&(params[(*nparams)++]),
                                    VIR_DOMAIN_BLKIO_WEIGHT,
                                    VIR_TYPED_PARAM_UINT, val) < 0)
            goto cleanup;
2833

2834 2835 2836
        if (virDomainGetBlkioParametersAssignFromDef(def, params, nparams,
                                                     maxparams) < 0)
            goto cleanup;
2837

2838
    } else if (persistentDef) {
2839 2840 2841 2842 2843 2844
        /* fill blkio weight here */
        if (virTypedParameterAssign(&(params[(*nparams)++]),
                                    VIR_DOMAIN_BLKIO_WEIGHT,
                                    VIR_TYPED_PARAM_UINT,
                                    persistentDef->blkio.weight) < 0)
            goto cleanup;
2845

2846 2847 2848
        if (virDomainGetBlkioParametersAssignFromDef(persistentDef, params,
                                                     nparams, maxparams) < 0)
            goto cleanup;
2849 2850 2851 2852
    }

    ret = 0;

2853
 cleanup:
2854
    virDomainObjEndAPI(&vm);
2855 2856 2857 2858
    return ret;
}


2859 2860 2861 2862
#ifdef __linux__
static int
lxcDomainInterfaceStats(virDomainPtr dom,
                        const char *path,
2863
                        virDomainInterfaceStatsPtr stats)
2864 2865
{
    virDomainObjPtr vm;
2866
    size_t i;
2867
    int ret = -1;
2868
    virLXCDriverPtr driver = dom->conn->privateData;
2869

M
Michal Privoznik 已提交
2870
    if (!(vm = lxcDomObjFromDomain(dom)))
2871 2872
        goto cleanup;

2873 2874 2875
    if (virDomainInterfaceStatsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2876 2877 2878
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_QUERY) < 0)
        goto cleanup;

2879
    if (!virDomainObjIsActive(vm)) {
2880 2881
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not running"));
2882
        goto endjob;
2883 2884 2885
    }

    /* Check the path is one of the domain's network interfaces. */
2886
    for (i = 0; i < vm->def->nnets; i++) {
2887 2888 2889 2890 2891 2892 2893 2894
        if (vm->def->nets[i]->ifname &&
            STREQ(vm->def->nets[i]->ifname, path)) {
            ret = 0;
            break;
        }
    }

    if (ret == 0)
2895
        ret = virNetInterfaceStats(path, stats);
2896
    else
2897 2898
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Invalid path, '%s' is not a known interface"), path);
2899

2900
 endjob:
2901
    virLXCDomainObjEndJob(driver, vm);
2902

2903
 cleanup:
2904
    virDomainObjEndAPI(&vm);
2905 2906 2907 2908 2909 2910
    return ret;
}
#else
static int
lxcDomainInterfaceStats(virDomainPtr dom,
                        const char *path ATTRIBUTE_UNUSED,
2911
                        virDomainInterfaceStatsPtr stats ATTRIBUTE_UNUSED)
A
Alex Jia 已提交
2912
{
2913
    virReportUnsupportedError();
2914 2915 2916 2917
    return -1;
}
#endif

2918
static int lxcDomainGetAutostart(virDomainPtr dom,
2919 2920
                                   int *autostart)
{
2921 2922 2923
    virDomainObjPtr vm;
    int ret = -1;

M
Michal Privoznik 已提交
2924
    if (!(vm = lxcDomObjFromDomain(dom)))
2925 2926
        goto cleanup;

2927 2928 2929
    if (virDomainGetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2930 2931 2932
    *autostart = vm->autostart;
    ret = 0;

2933
 cleanup:
2934
    virDomainObjEndAPI(&vm);
2935 2936 2937 2938
    return ret;
}

static int lxcDomainSetAutostart(virDomainPtr dom,
2939 2940
                                   int autostart)
{
2941
    virLXCDriverPtr driver = dom->conn->privateData;
2942 2943 2944
    virDomainObjPtr vm;
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;
2945
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
2946

M
Michal Privoznik 已提交
2947
    if (!(vm = lxcDomObjFromDomain(dom)))
2948 2949
        goto cleanup;

2950 2951 2952
    if (virDomainSetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2953 2954 2955
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

2956
    if (!vm->persistent) {
2957 2958
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Cannot set autostart for transient domain"));
2959
        goto endjob;
2960 2961 2962 2963
    }

    autostart = (autostart != 0);

2964 2965
    if (vm->autostart == autostart) {
        ret = 0;
2966
        goto endjob;
2967
    }
2968

2969
    configFile = virDomainConfigFile(cfg->configDir,
2970 2971
                                     vm->def->name);
    if (configFile == NULL)
2972
        goto endjob;
2973
    autostartLink = virDomainConfigFile(cfg->autostartDir,
2974 2975
                                        vm->def->name);
    if (autostartLink == NULL)
2976
        goto endjob;
2977

2978
    if (autostart) {
2979
        if (virFileMakePath(cfg->autostartDir) < 0) {
2980
            virReportSystemError(errno,
2981
                                 _("Cannot create autostart directory %s"),
2982
                                 cfg->autostartDir);
2983
            goto endjob;
2984 2985
        }

2986
        if (symlink(configFile, autostartLink) < 0) {
2987
            virReportSystemError(errno,
2988 2989
                                 _("Failed to create symlink '%s to '%s'"),
                                 autostartLink, configFile);
2990
            goto endjob;
2991 2992 2993
        }
    } else {
        if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
2994
            virReportSystemError(errno,
2995 2996
                                 _("Failed to delete symlink '%s'"),
                                 autostartLink);
2997
            goto endjob;
2998
        }
2999
    }
3000 3001

    vm->autostart = autostart;
3002 3003
    ret = 0;

3004
 endjob:
3005 3006
    virLXCDomainObjEndJob(driver, vm);

3007
 cleanup:
3008 3009
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
3010
    virDomainObjEndAPI(&vm);
3011
    virObjectUnref(cfg);
3012 3013 3014
    return ret;
}

3015
static int lxcFreezeContainer(virDomainObjPtr vm)
R
Ryota Ozaki 已提交
3016 3017 3018 3019 3020 3021 3022
{
    int timeout = 1000; /* In milliseconds */
    int check_interval = 1; /* In milliseconds */
    int exp = 10;
    int waited_time = 0;
    int ret = -1;
    char *state = NULL;
3023
    virLXCDomainObjPrivatePtr priv = vm->privateData;
3024

R
Ryota Ozaki 已提交
3025 3026 3027 3028 3029 3030 3031 3032 3033
    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)
         */
3034
        r = virCgroupSetFreezerState(priv->cgroup, "FROZEN");
R
Ryota Ozaki 已提交
3035 3036 3037

        /*
         * Returning EBUSY explicitly indicates that the group is
3038
         * being frozen but incomplete, and other errors are true
R
Ryota Ozaki 已提交
3039 3040 3041 3042 3043 3044 3045
         * errors.
         */
        if (r < 0 && r != -EBUSY) {
            VIR_DEBUG("Writing freezer.state failed with errno: %d", r);
            goto error;
        }
        if (r == -EBUSY)
3046
            VIR_DEBUG("Writing freezer.state gets EBUSY");
R
Ryota Ozaki 已提交
3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060

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

3061
        r = virCgroupGetFreezerState(priv->cgroup, &state);
R
Ryota Ozaki 已提交
3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085

        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);
    }
3086
    VIR_DEBUG("lxcFreezeContainer timeout");
3087
 error:
R
Ryota Ozaki 已提交
3088 3089 3090 3091 3092
    /*
     * 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.
     */
3093
    virCgroupSetFreezerState(priv->cgroup, "THAWED");
R
Ryota Ozaki 已提交
3094 3095
    ret = -1;

3096
 cleanup:
R
Ryota Ozaki 已提交
3097 3098 3099 3100 3101 3102
    VIR_FREE(state);
    return ret;
}

static int lxcDomainSuspend(virDomainPtr dom)
{
3103
    virLXCDriverPtr driver = dom->conn->privateData;
R
Ryota Ozaki 已提交
3104
    virDomainObjPtr vm;
3105
    virObjectEventPtr event = NULL;
R
Ryota Ozaki 已提交
3106
    int ret = -1;
3107
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
3108

M
Michal Privoznik 已提交
3109
    if (!(vm = lxcDomObjFromDomain(dom)))
R
Ryota Ozaki 已提交
3110 3111
        goto cleanup;

3112 3113 3114
    if (virDomainSuspendEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3115 3116 3117
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
3118
    if (!virDomainObjIsActive(vm)) {
3119 3120
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not running"));
3121
        goto endjob;
R
Ryota Ozaki 已提交
3122 3123
    }

J
Jiri Denemark 已提交
3124
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) {
3125
        if (lxcFreezeContainer(vm) < 0) {
3126 3127
            virReportError(VIR_ERR_OPERATION_FAILED,
                           "%s", _("Suspend operation failed"));
3128
            goto endjob;
R
Ryota Ozaki 已提交
3129
        }
J
Jiri Denemark 已提交
3130
        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
R
Ryota Ozaki 已提交
3131

3132
        event = virDomainEventLifecycleNewFromObj(vm,
R
Ryota Ozaki 已提交
3133 3134 3135 3136
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
    }

3137
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
3138
        goto endjob;
R
Ryota Ozaki 已提交
3139 3140
    ret = 0;

3141
 endjob:
3142 3143
    virLXCDomainObjEndJob(driver, vm);

3144
 cleanup:
R
Ryota Ozaki 已提交
3145
    if (event)
3146
        virObjectEventStateQueue(driver->domainEventState, event);
3147
    virDomainObjEndAPI(&vm);
3148
    virObjectUnref(cfg);
R
Ryota Ozaki 已提交
3149 3150 3151 3152 3153
    return ret;
}

static int lxcDomainResume(virDomainPtr dom)
{
3154
    virLXCDriverPtr driver = dom->conn->privateData;
R
Ryota Ozaki 已提交
3155
    virDomainObjPtr vm;
3156
    virObjectEventPtr event = NULL;
R
Ryota Ozaki 已提交
3157
    int ret = -1;
3158
    virLXCDomainObjPrivatePtr priv;
3159
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
3160

M
Michal Privoznik 已提交
3161
    if (!(vm = lxcDomObjFromDomain(dom)))
R
Ryota Ozaki 已提交
3162 3163
        goto cleanup;

3164 3165
    priv = vm->privateData;

3166 3167 3168
    if (virDomainResumeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3169 3170 3171
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
3172
    if (!virDomainObjIsActive(vm)) {
3173 3174
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not running"));
3175
        goto endjob;
R
Ryota Ozaki 已提交
3176 3177
    }

J
Jiri Denemark 已提交
3178
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
3179
        if (virCgroupSetFreezerState(priv->cgroup, "THAWED") < 0) {
3180 3181
            virReportError(VIR_ERR_OPERATION_FAILED,
                           "%s", _("Resume operation failed"));
3182
            goto endjob;
R
Ryota Ozaki 已提交
3183
        }
J
Jiri Denemark 已提交
3184 3185
        virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
                             VIR_DOMAIN_RUNNING_UNPAUSED);
R
Ryota Ozaki 已提交
3186

3187
        event = virDomainEventLifecycleNewFromObj(vm,
R
Ryota Ozaki 已提交
3188 3189 3190 3191
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
    }

3192
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
3193
        goto endjob;
R
Ryota Ozaki 已提交
3194 3195
    ret = 0;

3196
 endjob:
3197 3198
    virLXCDomainObjEndJob(driver, vm);

3199
 cleanup:
R
Ryota Ozaki 已提交
3200
    if (event)
3201
        virObjectEventStateQueue(driver->domainEventState, event);
3202
    virDomainObjEndAPI(&vm);
3203
    virObjectUnref(cfg);
R
Ryota Ozaki 已提交
3204 3205 3206
    return ret;
}

3207 3208
static int
lxcDomainOpenConsole(virDomainPtr dom,
3209
                      const char *dev_name,
3210 3211 3212 3213 3214 3215
                      virStreamPtr st,
                      unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainChrDefPtr chr = NULL;
3216
    size_t i;
3217 3218 3219

    virCheckFlags(0, -1);

M
Michal Privoznik 已提交
3220
    if (!(vm = lxcDomObjFromDomain(dom)))
3221 3222
        goto cleanup;

3223 3224 3225
    if (virDomainOpenConsoleEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3226
    if (!virDomainObjIsActive(vm)) {
3227 3228
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
3229 3230 3231
        goto cleanup;
    }

3232
    if (dev_name) {
3233
        for (i = 0; i < vm->def->nconsoles; i++) {
3234 3235 3236 3237 3238 3239
            if (vm->def->consoles[i]->info.alias &&
                STREQ(vm->def->consoles[i]->info.alias, dev_name)) {
                chr = vm->def->consoles[i];
                break;
            }
        }
3240
    } else {
3241 3242
        if (vm->def->nconsoles)
            chr = vm->def->consoles[0];
3243 3244 3245 3246 3247
        else if (vm->def->nserials)
            chr = vm->def->serials[0];
    }

    if (!chr) {
3248 3249 3250
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot find console device '%s'"),
                       dev_name ? dev_name : _("default"));
3251 3252 3253
        goto cleanup;
    }

3254
    if (chr->source.type != VIR_DOMAIN_CHR_TYPE_PTY) {
3255
        virReportError(VIR_ERR_INTERNAL_ERROR,
3256 3257
                       _("character device %s is not using a PTY"),
                       dev_name ? dev_name : NULLSTR(chr->info.alias));
3258 3259 3260
        goto cleanup;
    }

3261
    if (virFDStreamOpenFile(st, chr->source.data.file.path,
E
Eric Blake 已提交
3262
                            0, 0, O_RDWR) < 0)
3263 3264 3265
        goto cleanup;

    ret = 0;
3266
 cleanup:
3267
    virDomainObjEndAPI(&vm);
3268 3269 3270
    return ret;
}

3271 3272 3273 3274 3275 3276 3277

static int
lxcDomainSendProcessSignal(virDomainPtr dom,
                           long long pid_value,
                           unsigned int signum,
                           unsigned int flags)
{
3278
    virLXCDriverPtr driver = dom->conn->privateData;
3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292
    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 已提交
3293
    if (!(vm = lxcDomObjFromDomain(dom)))
3294
        goto cleanup;
M
Michal Privoznik 已提交
3295

3296 3297
    priv = vm->privateData;

3298 3299 3300
    if (virDomainSendProcessSignalEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3301 3302 3303
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

3304 3305 3306
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
3307
        goto endjob;
3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319
    }

    /*
     * 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"));
3320
        goto endjob;
3321 3322 3323 3324 3325
    }

    if (!priv->initpid) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Init pid is not yet available"));
3326
        goto endjob;
3327 3328 3329 3330 3331 3332 3333 3334 3335 3336
    }
    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);
3337
        goto endjob;
3338 3339 3340 3341
    }

    ret = 0;

3342
 endjob:
3343
    virLXCDomainObjEndJob(driver, vm);
3344

3345
 cleanup:
3346
    virDomainObjEndAPI(&vm);
3347 3348 3349 3350
    return ret;
}


3351
static int
3352 3353
lxcConnectListAllDomains(virConnectPtr conn,
                         virDomainPtr **domains,
3354 3355
                  unsigned int flags)
{
3356
    virLXCDriverPtr driver = conn->privateData;
3357 3358
    int ret = -1;

O
Osier Yang 已提交
3359
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
3360

3361 3362 3363
    if (virConnectListAllDomainsEnsureACL(conn) < 0)
        return -1;

3364 3365
    ret = virDomainObjListExport(driver->domains, conn, domains,
                                 virConnectListAllDomainsCheckACL, flags);
3366 3367 3368
    return ret;
}

3369

3370 3371 3372 3373 3374 3375 3376 3377 3378
static int
lxcDomainInitctlCallback(pid_t pid ATTRIBUTE_UNUSED,
                         void *opaque)
{
    int *command = opaque;
    return virInitctlSetRunLevel(*command);
}


3379 3380 3381 3382
static int
lxcDomainShutdownFlags(virDomainPtr dom,
                       unsigned int flags)
{
3383
    virLXCDriverPtr driver = dom->conn->privateData;
3384 3385 3386
    virLXCDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
    int ret = -1;
3387
    int rc;
3388 3389 3390 3391

    virCheckFlags(VIR_DOMAIN_SHUTDOWN_INITCTL |
                  VIR_DOMAIN_SHUTDOWN_SIGNAL, -1);

M
Michal Privoznik 已提交
3392
    if (!(vm = lxcDomObjFromDomain(dom)))
3393 3394 3395 3396
        goto cleanup;

    priv = vm->privateData;

3397
    if (virDomainShutdownFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
3398 3399
        goto cleanup;

3400 3401 3402
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

3403 3404 3405
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not running"));
3406
        goto endjob;
3407 3408 3409 3410 3411
    }

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

3415 3416
    if (flags == 0 ||
        (flags & VIR_DOMAIN_SHUTDOWN_INITCTL)) {
3417 3418 3419 3420 3421
        int command = VIR_INITCTL_RUNLEVEL_POWEROFF;

        if ((rc = virProcessRunInMountNamespace(priv->initpid,
                                                lxcDomainInitctlCallback,
                                                &command)) < 0)
3422
            goto endjob;
3423 3424
        if (rc == 0 && flags != 0 &&
            ((flags & ~VIR_DOMAIN_SHUTDOWN_INITCTL) == 0)) {
3425 3426
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                           _("Container does not provide an initctl pipe"));
3427
            goto endjob;
3428
        }
3429 3430
    } else {
        rc = 0;
3431
    }
3432

3433 3434 3435
    if (rc == 0 &&
        (flags == 0 ||
         (flags & VIR_DOMAIN_SHUTDOWN_SIGNAL))) {
3436 3437
        if (kill(priv->initpid, SIGTERM) < 0 &&
            errno != ESRCH) {
3438 3439 3440
            virReportSystemError(errno,
                                 _("Unable to send SIGTERM to init pid %llu"),
                                 (unsigned long long)priv->initpid);
3441
            goto endjob;
3442 3443 3444 3445 3446
        }
    }

    ret = 0;

3447
 endjob:
3448
    virLXCDomainObjEndJob(driver, vm);
3449

3450
 cleanup:
3451
    virDomainObjEndAPI(&vm);
3452 3453 3454 3455 3456 3457 3458 3459 3460
    return ret;
}

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

3461

3462 3463 3464 3465
static int
lxcDomainReboot(virDomainPtr dom,
                unsigned int flags)
{
3466
    virLXCDriverPtr driver = dom->conn->privateData;
3467 3468 3469 3470 3471 3472 3473 3474
    virLXCDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
    int ret = -1;
    int rc;

    virCheckFlags(VIR_DOMAIN_REBOOT_INITCTL |
                  VIR_DOMAIN_REBOOT_SIGNAL, -1);

M
Michal Privoznik 已提交
3475
    if (!(vm = lxcDomObjFromDomain(dom)))
3476 3477 3478 3479
        goto cleanup;

    priv = vm->privateData;

3480
    if (virDomainRebootEnsureACL(dom->conn, vm->def, flags) < 0)
3481 3482
        goto cleanup;

3483 3484 3485
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

3486 3487 3488
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not running"));
3489
        goto endjob;
3490 3491 3492 3493 3494
    }

    if (priv->initpid == 0) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Init process ID is not yet known"));
3495
        goto endjob;
3496 3497 3498 3499
    }

    if (flags == 0 ||
        (flags & VIR_DOMAIN_REBOOT_INITCTL)) {
3500 3501 3502 3503 3504
        int command = VIR_INITCTL_RUNLEVEL_REBOOT;

        if ((rc = virProcessRunInMountNamespace(priv->initpid,
                                                lxcDomainInitctlCallback,
                                                &command)) < 0)
3505
            goto endjob;
3506 3507 3508 3509
        if (rc == 0 && flags != 0 &&
            ((flags & ~VIR_DOMAIN_SHUTDOWN_INITCTL) == 0)) {
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                           _("Container does not provide an initctl pipe"));
3510
            goto endjob;
3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523
        }
    } 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);
3524
            goto endjob;
3525 3526 3527 3528 3529
        }
    }

    ret = 0;

3530
 endjob:
3531
    virLXCDomainObjEndJob(driver, vm);
3532

3533
 cleanup:
3534
    virDomainObjEndAPI(&vm);
3535 3536 3537 3538
    return ret;
}


3539
static int
3540
lxcDomainAttachDeviceConfig(virDomainDefPtr vmdef,
3541 3542 3543
                            virDomainDeviceDefPtr dev)
{
    int ret = -1;
3544
    virDomainDiskDefPtr disk;
3545
    virDomainNetDefPtr net;
3546
    virDomainHostdevDefPtr hostdev;
3547 3548

    switch (dev->type) {
3549 3550 3551 3552 3553 3554 3555
    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;
        }
3556
        if (virDomainDiskInsert(vmdef, disk))
3557 3558 3559 3560 3561 3562
            return -1;
        /* vmdef has the pointer. Generic codes for vmdef will do all jobs */
        dev->data.disk = NULL;
        ret = 0;
        break;

3563 3564
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
3565
        if (virDomainNetInsert(vmdef, net) < 0)
3566 3567 3568 3569 3570
            goto cleanup;
        dev->data.net = NULL;
        ret = 0;
        break;

3571 3572 3573 3574 3575 3576 3577
    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;
        }
3578
        if (virDomainHostdevInsert(vmdef, hostdev) < 0)
3579 3580 3581 3582 3583
            return -1;
        dev->data.hostdev = NULL;
        ret = 0;
        break;

3584 3585 3586 3587 3588 3589
    default:
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                        _("persistent attach of device is not supported"));
         break;
    }

3590
 cleanup:
3591 3592 3593 3594 3595
    return ret;
}


static int
3596
lxcDomainUpdateDeviceConfig(virDomainDefPtr vmdef,
3597 3598 3599
                            virDomainDeviceDefPtr dev)
{
    int ret = -1;
3600 3601
    virDomainNetDefPtr net;
    int idx;
3602 3603

    switch (dev->type) {
3604 3605
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
3606
        if ((idx = virDomainNetFindIdx(vmdef, net)) < 0)
3607 3608 3609 3610 3611 3612 3613 3614 3615 3616
            goto cleanup;

        virDomainNetDefFree(vmdef->nets[idx]);

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

        break;

3617 3618 3619 3620 3621 3622
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("persistent update of device is not supported"));
        break;
    }

3623
 cleanup:
3624 3625 3626 3627 3628
    return ret;
}


static int
3629
lxcDomainDetachDeviceConfig(virDomainDefPtr vmdef,
3630 3631 3632
                            virDomainDeviceDefPtr dev)
{
    int ret = -1;
3633
    virDomainDiskDefPtr disk, det_disk;
3634
    virDomainNetDefPtr net;
3635
    virDomainHostdevDefPtr hostdev, det_hostdev;
3636
    int idx;
3637 3638

    switch (dev->type) {
3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649
    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;

3650 3651
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
3652
        if ((idx = virDomainNetFindIdx(vmdef, net)) < 0)
3653
            goto cleanup;
3654

3655 3656 3657 3658 3659
        /* this is guaranteed to succeed */
        virDomainNetDefFree(virDomainNetRemove(vmdef, idx));
        ret = 0;
        break;

3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672
    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;
    }

3673 3674 3675 3676 3677 3678
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("persistent detach of device is not supported"));
        break;
    }

3679
 cleanup:
3680 3681 3682 3683
    return ret;
}


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 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731
struct lxcDomainAttachDeviceMknodData {
    virLXCDriverPtr driver;
    mode_t mode;
    dev_t dev;
    virDomainObjPtr vm;
    virDomainDeviceDefPtr def;
    char *file;
};

static int
lxcDomainAttachDeviceMknodHelper(pid_t pid ATTRIBUTE_UNUSED,
                                 void *opaque)
{
    struct lxcDomainAttachDeviceMknodData *data = opaque;
    int ret = -1;

    virSecurityManagerPostFork(data->driver->securityManager);

    if (virFileMakeParentPath(data->file) < 0) {
        virReportSystemError(errno,
                             _("Unable to create %s"), data->file);
        goto cleanup;
    }

    /* 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)",
              data->file, major(data->dev), minor(data->dev));
    if (mknod(data->file, data->mode, data->dev) < 0) {
        virReportSystemError(errno,
                             _("Unable to create device %s"),
                             data->file);
        goto cleanup;
    }

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

    /* Labelling normally operates on src, but we need
     * to actually label the dst here, so hack the config */
    switch (data->def->type) {
    case VIR_DOMAIN_DEVICE_DISK: {
        virDomainDiskDefPtr def = data->def->data.disk;
3732 3733
        char *tmpsrc = def->src->path;
        def->src->path = data->file;
3734 3735
        if (virSecurityManagerSetDiskLabel(data->driver->securityManager,
                                           data->vm->def, def) < 0) {
3736
            def->src->path = tmpsrc;
3737 3738
            goto cleanup;
        }
3739
        def->src->path = tmpsrc;
3740 3741
    }   break;

3742 3743 3744 3745 3746 3747 3748
    case VIR_DOMAIN_DEVICE_HOSTDEV: {
        virDomainHostdevDefPtr def = data->def->data.hostdev;
        if (virSecurityManagerSetHostdevLabel(data->driver->securityManager,
                                              data->vm->def, def, NULL) < 0)
            goto cleanup;
    }   break;

3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799
    default:
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unexpected device type %d"),
                       data->def->type);
        goto cleanup;
    }

    ret = 0;

 cleanup:
    if (ret < 0)
        unlink(data->file);
    return ret;
}


static int
lxcDomainAttachDeviceMknod(virLXCDriverPtr driver,
                           mode_t mode,
                           dev_t dev,
                           virDomainObjPtr vm,
                           virDomainDeviceDefPtr def,
                           char *file)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    struct lxcDomainAttachDeviceMknodData data;

    memset(&data, 0, sizeof(data));

    data.driver = driver;
    data.mode = mode;
    data.dev = dev;
    data.vm = vm;
    data.def = def;
    data.file = file;

    if (virSecurityManagerPreFork(driver->securityManager) < 0)
        return -1;

    if (virProcessRunInMountNamespace(priv->initpid,
                                      lxcDomainAttachDeviceMknodHelper,
                                      &data) < 0) {
        virSecurityManagerPostFork(driver->securityManager);
        return -1;
    }

    virSecurityManagerPostFork(driver->securityManager);
    return 0;
}


3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832
static int
lxcDomainAttachDeviceUnlinkHelper(pid_t pid ATTRIBUTE_UNUSED,
                                  void *opaque)
{
    const char *path = opaque;

    VIR_DEBUG("Unlinking %s", path);
    if (unlink(path) < 0 && errno != ENOENT) {
        virReportSystemError(errno,
                             _("Unable to remove device %s"), path);
        return -1;
    }

    return 0;
}


static int
lxcDomainAttachDeviceUnlink(virDomainObjPtr vm,
                            char *file)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;

    if (virProcessRunInMountNamespace(priv->initpid,
                                      lxcDomainAttachDeviceUnlinkHelper,
                                      file) < 0) {
        return -1;
    }

    return 0;
}


3833 3834 3835 3836 3837 3838 3839 3840 3841
static int
lxcDomainAttachDeviceDiskLive(virLXCDriverPtr driver,
                              virDomainObjPtr vm,
                              virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainDiskDefPtr def = dev->data.disk;
    int ret = -1;
    struct stat sb;
3842 3843
    char *file = NULL;
    int perms;
3844
    const char *src = NULL;
3845 3846 3847 3848 3849 3850 3851

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

3852 3853 3854 3855 3856 3857
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        goto cleanup;
    }

3858 3859
    src = virDomainDiskGetSource(def);
    if (src == NULL) {
3860 3861 3862 3863 3864
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Can't setup disk without media"));
        goto cleanup;
    }

3865 3866 3867 3868 3869 3870
    if (!virStorageSourceIsBlockLocal(def->src)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Can't setup disk for non-block device"));
        goto cleanup;
    }

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

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

3883
    if (!S_ISBLK(sb.st_mode)) {
3884
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3885
                       _("Disk source %s must be a block device"),
3886
                       src);
3887 3888 3889
        goto cleanup;
    }

3890
    perms = (def->src->readonly ?
3891 3892 3893
             VIR_CGROUP_DEVICE_READ :
             VIR_CGROUP_DEVICE_RW) |
        VIR_CGROUP_DEVICE_MKNOD;
3894

3895 3896 3897 3898 3899
    if (virCgroupAllowDevice(priv->cgroup,
                             'b',
                             major(sb.st_rdev),
                             minor(sb.st_rdev),
                             perms) < 0)
3900
        goto cleanup;
3901

3902
    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks + 1) < 0)
3903 3904
        goto cleanup;

3905 3906
    if (virAsprintf(&file,
                    "/dev/%s", def->dst) < 0)
3907 3908
        goto cleanup;

3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920
    if (lxcDomainAttachDeviceMknod(driver,
                                   0700 | S_IFBLK,
                                   sb.st_rdev,
                                   vm,
                                   dev,
                                   file) < 0) {
        if (virCgroupDenyDevice(priv->cgroup,
                                'b',
                                major(sb.st_rdev),
                                minor(sb.st_rdev),
                                perms) < 0)
            VIR_WARN("cannot deny device %s for domain %s",
3921
                     src, vm->def->name);
3922 3923 3924 3925 3926 3927 3928
        goto cleanup;
    }

    virDomainDiskInsertPreAlloced(vm->def, def);

    ret = 0;

3929
 cleanup:
3930
    if (src)
3931
        virDomainAuditDisk(vm, NULL, def->src, "attach", ret == 0);
3932
    VIR_FREE(file);
3933 3934 3935 3936
    return ret;
}


3937
/* XXX conn required for network -> bridge resolution */
3938
static int
3939 3940 3941 3942 3943 3944 3945
lxcDomainAttachDeviceNetLive(virConnectPtr conn,
                             virDomainObjPtr vm,
                             virDomainNetDefPtr net)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    int ret = -1;
    int actualType;
3946
    virNetDevBandwidthPtr actualBandwidth;
3947 3948 3949 3950 3951
    char *veth = NULL;

    if (!priv->initpid) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Cannot attach disk until init PID is known"));
M
Martin Kletzander 已提交
3952
        return -1;
3953 3954
    }

3955 3956 3957
    if (virLXCProcessValidateInterface(net) < 0)
       return -1;

3958
    /* preallocate new slot for device */
3959
    if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets+1) < 0)
3960 3961 3962 3963 3964 3965
        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.
     */
3966
    if (networkAllocateActualDevice(vm->def, net) < 0)
3967 3968 3969 3970 3971
        return -1;

    actualType = virDomainNetGetActualType(net);

    switch (actualType) {
3972 3973
    case VIR_DOMAIN_NET_TYPE_BRIDGE:
    case VIR_DOMAIN_NET_TYPE_NETWORK: {
3974 3975 3976 3977 3978 3979
        const char *brname = virDomainNetGetActualBridgeName(net);
        if (!brname) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No bridge name specified"));
            goto cleanup;
        }
3980
        if (!(veth = virLXCProcessSetupInterfaceTap(vm->def, net, brname)))
3981 3982
            goto cleanup;
    }   break;
3983 3984 3985 3986
    case VIR_DOMAIN_NET_TYPE_ETHERNET:
        if (!(veth = virLXCProcessSetupInterfaceTap(vm->def, net, NULL)))
            goto cleanup;
        break;
3987
    case VIR_DOMAIN_NET_TYPE_DIRECT: {
3988
        if (!(veth = virLXCProcessSetupInterfaceDirect(conn, vm->def, net)))
3989 3990 3991 3992 3993 3994 3995
            goto cleanup;
    }   break;
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Network device type is not supported"));
        goto cleanup;
    }
3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007
    /* Set bandwidth or warn if requested and not supported. */
    actualBandwidth = virDomainNetGetActualBandwidth(net);
    if (actualBandwidth) {
        if (virNetDevSupportBandwidth(actualType)) {
            if (virNetDevBandwidthSet(net->ifname, actualBandwidth, false) < 0)
                goto cleanup;
        } else {
            VIR_WARN("setting bandwidth on interfaces of "
                     "type '%s' is not implemented yet",
                     virDomainNetTypeToString(actualType));
        }
    }
4008 4009 4010 4011 4012 4013 4014 4015 4016 4017

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

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

    ret = 0;

4018
 cleanup:
4019 4020 4021 4022 4023 4024
    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:
4025
        case VIR_DOMAIN_NET_TYPE_ETHERNET:
4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038
            ignore_value(virNetDevVethDelete(veth));
            break;

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

    return ret;
}


4039 4040 4041 4042 4043 4044 4045 4046 4047 4048
static int
lxcDomainAttachDeviceHostdevSubsysUSBLive(virLXCDriverPtr driver,
                                          virDomainObjPtr vm,
                                          virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainHostdevDefPtr def = dev->data.hostdev;
    int ret = -1;
    char *src = NULL;
    struct stat sb;
4049
    virUSBDevicePtr usb = NULL;
4050
    virDomainHostdevSubsysUSBPtr usbsrc;
4051 4052 4053 4054 4055 4056 4057

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

4058
    usbsrc = &def->source.subsys.u.usb;
4059
    if (virAsprintf(&src, "/dev/bus/usb/%03d/%03d",
4060
                    usbsrc->bus, usbsrc->device) < 0)
4061 4062
        goto cleanup;

4063
    if (!(usb = virUSBDeviceNew(usbsrc->bus, usbsrc->device, NULL)))
4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078
        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;
    }

4079 4080 4081
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0)
        goto cleanup;

4082
    if (virUSBDeviceFileIterate(usb,
4083
                                virLXCSetupHostUSBDeviceCgroup,
4084
                                priv->cgroup) < 0)
4085 4086
        goto cleanup;

4087 4088 4089 4090 4091 4092 4093
    if (lxcDomainAttachDeviceMknod(driver,
                                   0700 | S_IFCHR,
                                   sb.st_rdev,
                                   vm,
                                   dev,
                                   src) < 0) {
        if (virUSBDeviceFileIterate(usb,
4094
                                    virLXCTeardownHostUSBDeviceCgroup,
4095 4096 4097 4098 4099 4100
                                    priv->cgroup) < 0)
            VIR_WARN("cannot deny device %s for domain %s",
                     src, vm->def->name);
        goto cleanup;
    }

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

4103 4104
    ret = 0;

4105
 cleanup:
4106
    virDomainAuditHostdev(vm, def, "attach", ret == 0);
4107
    virUSBDeviceFree(usb);
4108 4109 4110 4111 4112
    VIR_FREE(src);
    return ret;
}


4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148
static int
lxcDomainAttachDeviceHostdevStorageLive(virLXCDriverPtr driver,
                                        virDomainObjPtr vm,
                                        virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainHostdevDefPtr def = dev->data.hostdev;
    int ret = -1;
    struct stat sb;

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

4149
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0)
4150 4151
        goto cleanup;

4152 4153 4154 4155 4156
    if (virCgroupAllowDevice(priv->cgroup,
                             'b',
                             major(sb.st_rdev),
                             minor(sb.st_rdev),
                             VIR_CGROUP_DEVICE_RWM) < 0)
4157 4158
        goto cleanup;

4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171
    if (lxcDomainAttachDeviceMknod(driver,
                                   0700 | S_IFBLK,
                                   sb.st_rdev,
                                   vm,
                                   dev,
                                   def->source.caps.u.storage.block) < 0) {
        if (virCgroupDenyDevice(priv->cgroup,
                                'b',
                                major(sb.st_rdev),
                                minor(sb.st_rdev),
                                VIR_CGROUP_DEVICE_RWM) < 0)
            VIR_WARN("cannot deny device %s for domain %s",
                     def->source.caps.u.storage.block, vm->def->name);
4172 4173 4174 4175 4176 4177 4178
        goto cleanup;
    }

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

    ret = 0;

4179
 cleanup:
4180 4181 4182 4183 4184
    virDomainAuditHostdev(vm, def, "attach", ret == 0);
    return ret;
}


4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220
static int
lxcDomainAttachDeviceHostdevMiscLive(virLXCDriverPtr driver,
                                     virDomainObjPtr vm,
                                     virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainHostdevDefPtr def = dev->data.hostdev;
    int ret = -1;
    struct stat sb;

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

4221 4222 4223 4224 4225
    if (virCgroupAllowDevice(priv->cgroup,
                             'c',
                             major(sb.st_rdev),
                             minor(sb.st_rdev),
                             VIR_CGROUP_DEVICE_RWM) < 0)
4226 4227
        goto cleanup;

4228
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0)
4229 4230
        goto cleanup;

4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243
    if (lxcDomainAttachDeviceMknod(driver,
                                   0700 | S_IFBLK,
                                   sb.st_rdev,
                                   vm,
                                   dev,
                                   def->source.caps.u.misc.chardev) < 0) {
        if (virCgroupDenyDevice(priv->cgroup,
                                'c',
                                major(sb.st_rdev),
                                minor(sb.st_rdev),
                                VIR_CGROUP_DEVICE_RWM) < 0)
            VIR_WARN("cannot deny device %s for domain %s",
                     def->source.caps.u.storage.block, vm->def->name);
4244 4245 4246 4247 4248 4249 4250
        goto cleanup;
    }

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

    ret = 0;

4251
 cleanup:
4252 4253 4254 4255 4256
    virDomainAuditHostdev(vm, def, "attach", ret == 0);
    return ret;
}


4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274
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;
    }
}


4275 4276 4277 4278 4279 4280 4281 4282 4283
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);

4284 4285 4286
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC:
        return lxcDomainAttachDeviceHostdevMiscLive(driver, vm, dev);

4287 4288 4289 4290 4291 4292 4293 4294 4295
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported host device type %s"),
                       virDomainHostdevCapsTypeToString(dev->data.hostdev->source.caps.type));
        return -1;
    }
}


4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308
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;
    }

4309 4310 4311 4312 4313 4314
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        return -1;
    }

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

4319 4320 4321
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
        return lxcDomainAttachDeviceHostdevCapsLive(driver, vm, dev);

4322 4323 4324 4325 4326 4327 4328 4329 4330
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported host device mode %s"),
                       virDomainHostdevModeTypeToString(dev->data.hostdev->mode));
        return -1;
    }
}


4331 4332 4333 4334
static int
lxcDomainAttachDeviceLive(virConnectPtr conn,
                          virLXCDriverPtr driver,
                          virDomainObjPtr vm,
4335 4336 4337 4338 4339
                          virDomainDeviceDefPtr dev)
{
    int ret = -1;

    switch (dev->type) {
4340 4341 4342 4343 4344 4345
    case VIR_DOMAIN_DEVICE_DISK:
        ret = lxcDomainAttachDeviceDiskLive(driver, vm, dev);
        if (!ret)
            dev->data.disk = NULL;
        break;

4346 4347 4348 4349 4350 4351 4352
    case VIR_DOMAIN_DEVICE_NET:
        ret = lxcDomainAttachDeviceNetLive(conn, vm,
                                           dev->data.net);
        if (!ret)
            dev->data.net = NULL;
        break;

4353 4354 4355 4356 4357 4358
    case VIR_DOMAIN_DEVICE_HOSTDEV:
        ret = lxcDomainAttachDeviceHostdevLive(driver, vm, dev);
        if (!ret)
            dev->data.disk = NULL;
        break;

4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("device type '%s' cannot be attached"),
                       virDomainDeviceTypeToString(dev->type));
        break;
    }

    return ret;
}


4370
static int
4371
lxcDomainDetachDeviceDiskLive(virDomainObjPtr vm,
4372 4373 4374 4375
                              virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainDiskDefPtr def = NULL;
4376
    int idx, ret = -1;
J
John Ferlan 已提交
4377
    char *dst = NULL;
4378
    const char *src;
4379 4380 4381 4382 4383 4384 4385

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

4386 4387 4388
    if ((idx = virDomainDiskIndexByName(vm->def,
                                        dev->data.disk->dst,
                                        false)) < 0) {
4389 4390 4391 4392 4393
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("disk %s not found"), dev->data.disk->dst);
        goto cleanup;
    }

4394
    def = vm->def->disks[idx];
4395
    src = virDomainDiskGetSource(def);
4396

4397
    if (virAsprintf(&dst, "/dev/%s", def->dst) < 0)
4398 4399
        goto cleanup;

4400
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
4401 4402 4403 4404 4405
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        goto cleanup;
    }

4406
    if (lxcDomainAttachDeviceUnlink(vm, dst) < 0) {
4407
        virDomainAuditDisk(vm, def->src, NULL, "detach", false);
4408 4409
        goto cleanup;
    }
4410
    virDomainAuditDisk(vm, def->src, NULL, "detach", true);
4411

4412 4413
    if (virCgroupDenyDevicePath(priv->cgroup, src,
                                VIR_CGROUP_DEVICE_RWM, false) != 0)
4414
        VIR_WARN("cannot deny device %s for domain %s",
4415
                 src, vm->def->name);
4416

4417
    virDomainDiskRemove(vm->def, idx);
4418 4419 4420 4421
    virDomainDiskDefFree(def);

    ret = 0;

4422
 cleanup:
4423 4424 4425 4426 4427
    VIR_FREE(dst);
    return ret;
}


4428
static int
4429 4430 4431
lxcDomainDetachDeviceNetLive(virDomainObjPtr vm,
                             virDomainDeviceDefPtr dev)
{
4432
    int detachidx, actualType, ret = -1;
4433 4434 4435
    virDomainNetDefPtr detach = NULL;
    virNetDevVPortProfilePtr vport = NULL;

4436
    if ((detachidx = virDomainNetFindIdx(vm->def, dev->data.net)) < 0)
4437
        goto cleanup;
4438

4439
    detach = vm->def->nets[detachidx];
4440 4441 4442
    actualType = virDomainNetGetActualType(detach);

    /* clear network bandwidth */
4443 4444
    if (virDomainNetGetActualBandwidth(detach) &&
        virNetDevSupportBandwidth(actualType) &&
4445 4446
        virNetDevBandwidthClear(detach->ifname))
        goto cleanup;
4447

4448
    switch (actualType) {
4449 4450
    case VIR_DOMAIN_NET_TYPE_BRIDGE:
    case VIR_DOMAIN_NET_TYPE_NETWORK:
4451
    case VIR_DOMAIN_NET_TYPE_ETHERNET:
4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481
        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;
4482
 cleanup:
4483
    if (!ret) {
4484
        networkReleaseActualDevice(vm->def, detach);
4485 4486 4487 4488 4489 4490 4491
        virDomainNetRemove(vm->def, detachidx);
        virDomainNetDefFree(detach);
    }
    return ret;
}


4492 4493 4494 4495 4496 4497 4498 4499
static int
lxcDomainDetachDeviceHostdevUSBLive(virLXCDriverPtr driver,
                                    virDomainObjPtr vm,
                                    virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainHostdevDefPtr def = NULL;
    int idx, ret = -1;
J
John Ferlan 已提交
4500
    char *dst = NULL;
4501
    virUSBDevicePtr usb = NULL;
4502
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
4503
    virDomainHostdevSubsysUSBPtr usbsrc;
4504 4505 4506 4507 4508 4509 4510 4511 4512

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

4513
    usbsrc = &def->source.subsys.u.usb;
4514
    if (virAsprintf(&dst, "/dev/bus/usb/%03d/%03d",
4515
                    usbsrc->bus, usbsrc->device) < 0)
4516 4517
        goto cleanup;

4518
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
4519 4520 4521 4522 4523
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        goto cleanup;
    }

4524
    if (!(usb = virUSBDeviceNew(usbsrc->bus, usbsrc->device, NULL)))
4525 4526
        goto cleanup;

4527
    if (lxcDomainAttachDeviceUnlink(vm, dst) < 0) {
4528 4529 4530 4531 4532
        virDomainAuditHostdev(vm, def, "detach", false);
        goto cleanup;
    }
    virDomainAuditHostdev(vm, def, "detach", true);

4533
    if (virUSBDeviceFileIterate(usb,
4534
                                virLXCTeardownHostUSBDeviceCgroup,
4535
                                priv->cgroup) < 0)
4536 4537 4538
        VIR_WARN("cannot deny device %s for domain %s",
                 dst, vm->def->name);

4539 4540 4541
    virObjectLock(hostdev_mgr->activeUSBHostdevs);
    virUSBDeviceListDel(hostdev_mgr->activeUSBHostdevs, usb);
    virObjectUnlock(hostdev_mgr->activeUSBHostdevs);
4542 4543 4544 4545 4546 4547

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

    ret = 0;

4548
 cleanup:
4549
    virUSBDeviceFree(usb);
4550 4551 4552 4553
    VIR_FREE(dst);
    return ret;
}

4554 4555

static int
4556
lxcDomainDetachDeviceHostdevStorageLive(virDomainObjPtr vm,
4557 4558 4559 4560
                                        virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainHostdevDefPtr def = NULL;
4561
    int idx, ret = -1;
4562 4563 4564 4565 4566 4567 4568

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

4569 4570 4571
    if ((idx = virDomainHostdevFind(vm->def,
                                    dev->data.hostdev,
                                    &def)) < 0) {
4572 4573 4574 4575 4576 4577
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("hostdev %s not found"),
                       dev->data.hostdev->source.caps.u.storage.block);
        goto cleanup;
    }

4578
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
4579 4580 4581 4582 4583
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        goto cleanup;
    }

4584
    if (lxcDomainAttachDeviceUnlink(vm, def->source.caps.u.storage.block) < 0) {
4585 4586 4587 4588 4589
        virDomainAuditHostdev(vm, def, "detach", false);
        goto cleanup;
    }
    virDomainAuditHostdev(vm, def, "detach", true);

4590 4591
    if (virCgroupDenyDevicePath(priv->cgroup, def->source.caps.u.storage.block,
                                VIR_CGROUP_DEVICE_RWM, false) != 0)
4592 4593 4594
        VIR_WARN("cannot deny device %s for domain %s",
                 def->source.caps.u.storage.block, vm->def->name);

4595
    virDomainHostdevRemove(vm->def, idx);
4596 4597 4598 4599
    virDomainHostdevDefFree(def);

    ret = 0;

4600
 cleanup:
4601 4602 4603 4604
    return ret;
}


4605
static int
4606
lxcDomainDetachDeviceHostdevMiscLive(virDomainObjPtr vm,
4607 4608 4609 4610
                                     virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainHostdevDefPtr def = NULL;
4611
    int idx, ret = -1;
4612 4613 4614 4615 4616 4617 4618

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

4619 4620 4621
    if ((idx = virDomainHostdevFind(vm->def,
                                    dev->data.hostdev,
                                    &def)) < 0) {
4622 4623 4624 4625 4626 4627
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("hostdev %s not found"),
                       dev->data.hostdev->source.caps.u.misc.chardev);
        goto cleanup;
    }

4628
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
4629 4630 4631 4632 4633
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        goto cleanup;
    }

4634
    if (lxcDomainAttachDeviceUnlink(vm, def->source.caps.u.misc.chardev) < 0) {
4635 4636 4637 4638 4639
        virDomainAuditHostdev(vm, def, "detach", false);
        goto cleanup;
    }
    virDomainAuditHostdev(vm, def, "detach", true);

4640 4641
    if (virCgroupDenyDevicePath(priv->cgroup, def->source.caps.u.misc.chardev,
                                VIR_CGROUP_DEVICE_RWM, false) != 0)
4642 4643 4644
        VIR_WARN("cannot deny device %s for domain %s",
                 def->source.caps.u.misc.chardev, vm->def->name);

4645
    virDomainHostdevRemove(vm->def, idx);
4646 4647 4648 4649
    virDomainHostdevDefFree(def);

    ret = 0;

4650
 cleanup:
4651 4652 4653 4654
    return ret;
}


4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672
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;
    }
}


4673
static int
4674 4675
lxcDomainDetachDeviceHostdevCapsLive(virDomainObjPtr vm,
                                     virDomainDeviceDefPtr dev)
4676 4677 4678
{
    switch (dev->data.hostdev->source.caps.type) {
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
4679
        return lxcDomainDetachDeviceHostdevStorageLive(vm, dev);
4680

4681
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC:
4682
        return lxcDomainDetachDeviceHostdevMiscLive(vm, dev);
4683

4684 4685 4686 4687 4688 4689 4690 4691 4692
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported host device type %s"),
                       virDomainHostdevCapsTypeToString(dev->data.hostdev->source.caps.type));
        return -1;
    }
}


4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709
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);

4710
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
4711
        return lxcDomainDetachDeviceHostdevCapsLive(vm, dev);
4712

4713 4714 4715 4716 4717 4718 4719 4720 4721
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported host device mode %s"),
                       virDomainHostdevModeTypeToString(dev->data.hostdev->mode));
        return -1;
    }
}


4722 4723 4724
static int
lxcDomainDetachDeviceLive(virLXCDriverPtr driver,
                          virDomainObjPtr vm,
4725 4726 4727 4728 4729
                          virDomainDeviceDefPtr dev)
{
    int ret = -1;

    switch (dev->type) {
4730
    case VIR_DOMAIN_DEVICE_DISK:
4731
        ret = lxcDomainDetachDeviceDiskLive(vm, dev);
4732 4733
        break;

4734 4735 4736 4737
    case VIR_DOMAIN_DEVICE_NET:
        ret = lxcDomainDetachDeviceNetLive(vm, dev);
        break;

4738 4739 4740 4741
    case VIR_DOMAIN_DEVICE_HOSTDEV:
        ret = lxcDomainDetachDeviceHostdevLive(driver, vm, dev);
        break;

4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("device type '%s' cannot be detached"),
                       virDomainDeviceTypeToString(dev->type));
        break;
    }

    return ret;
}


4753 4754 4755
static int lxcDomainAttachDeviceFlags(virDomainPtr dom,
                                      const char *xml,
                                      unsigned int flags)
4756 4757
{
    virLXCDriverPtr driver = dom->conn->privateData;
4758
    virCapsPtr caps = NULL;
4759 4760 4761 4762
    virDomainObjPtr vm = NULL;
    virDomainDefPtr vmdef = NULL;
    virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
    int ret = -1;
4763
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
4764 4765

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
4766
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
4767

M
Michal Privoznik 已提交
4768
    if (!(vm = lxcDomObjFromDomain(dom)))
4769 4770
        goto cleanup;

4771 4772 4773
    if (virDomainAttachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4774
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
4775 4776
        goto cleanup;

4777 4778 4779
    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
        goto endjob;

4780
    if (virDomainObjUpdateModificationImpact(vm, &flags) < 0)
4781
        goto endjob;
4782

4783
    dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
4784
                                             caps, driver->xmlopt,
4785
                                             VIR_DOMAIN_DEF_PARSE_INACTIVE);
4786
    if (dev == NULL)
4787
        goto endjob;
4788 4789 4790 4791 4792 4793 4794

    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.
         */
4795
        dev_copy = virDomainDeviceDefCopy(dev, vm->def,
4796
                                          caps, driver->xmlopt);
4797
        if (!dev_copy)
4798
            goto endjob;
4799 4800 4801 4802
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        /* Make a copy for updated domain. */
4803
        vmdef = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt);
4804
        if (!vmdef)
4805
            goto endjob;
4806

4807 4808
        if (virDomainDefCompatibleDevice(vmdef, dev,
                                         VIR_DOMAIN_DEVICE_ACTION_ATTACH) < 0)
4809
            goto endjob;
4810

4811
        if ((ret = lxcDomainAttachDeviceConfig(vmdef, dev)) < 0)
4812
            goto endjob;
4813 4814 4815
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
4816 4817
        if (virDomainDefCompatibleDevice(vm->def, dev_copy,
                                         VIR_DOMAIN_DEVICE_ACTION_ATTACH) < 0)
4818
            goto endjob;
4819

4820
        if ((ret = lxcDomainAttachDeviceLive(dom->conn, driver, vm, dev_copy)) < 0)
4821
            goto endjob;
4822 4823 4824 4825 4826
        /*
         * 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.
         */
4827
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0) {
4828
            ret = -1;
4829
            goto endjob;
4830 4831 4832 4833 4834
        }
    }

    /* Finally, if no error until here, we can save config. */
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
4835
        ret = virDomainSaveConfig(cfg->configDir, driver->caps, vmdef);
4836
        if (!ret) {
4837
            virDomainObjAssignDef(vm, vmdef, false, NULL);
4838 4839 4840 4841
            vmdef = NULL;
        }
    }

4842
 endjob:
4843 4844
    virLXCDomainObjEndJob(driver, vm);

4845
 cleanup:
4846 4847 4848 4849
    virDomainDefFree(vmdef);
    if (dev != dev_copy)
        virDomainDeviceDefFree(dev_copy);
    virDomainDeviceDefFree(dev);
4850
    virDomainObjEndAPI(&vm);
4851
    virObjectUnref(caps);
4852
    virObjectUnref(cfg);
4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868
    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)
{
4869
    virLXCDriverPtr driver = dom->conn->privateData;
4870
    virCapsPtr caps = NULL;
4871 4872 4873 4874
    virDomainObjPtr vm = NULL;
    virDomainDefPtr vmdef = NULL;
    virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
    int ret = -1;
4875
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
4876 4877 4878 4879 4880

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

M
Michal Privoznik 已提交
4881
    if (!(vm = lxcDomObjFromDomain(dom)))
4882 4883
        goto cleanup;

4884 4885 4886
    if (virDomainUpdateDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4887
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
4888
        goto cleanup;
4889

4890 4891 4892
    if (virDomainObjUpdateModificationImpact(vm, &flags) < 0)
        goto endjob;

4893
    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
4894
        goto endjob;
4895

4896
    dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
4897
                                             caps, driver->xmlopt,
4898
                                             VIR_DOMAIN_DEF_PARSE_INACTIVE);
4899
    if (dev == NULL)
4900
        goto endjob;
4901 4902 4903 4904 4905 4906 4907 4908

    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,
4909
                                          caps, driver->xmlopt);
4910
        if (!dev_copy)
4911
            goto endjob;
4912 4913 4914 4915
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        /* Make a copy for updated domain. */
4916
        vmdef = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt);
4917
        if (!vmdef)
4918
            goto endjob;
4919

4920 4921
        if (virDomainDefCompatibleDevice(vmdef, dev,
                                         VIR_DOMAIN_DEVICE_ACTION_UPDATE) < 0)
4922
            goto endjob;
4923

4924
        if ((ret = lxcDomainUpdateDeviceConfig(vmdef, dev)) < 0)
4925
            goto endjob;
4926 4927 4928
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
4929 4930
        if (virDomainDefCompatibleDevice(vm->def, dev_copy,
                                         VIR_DOMAIN_DEVICE_ACTION_UPDATE) < 0)
4931
            goto endjob;
4932 4933 4934 4935

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

4936
        goto endjob;
4937 4938 4939 4940
    }

    /* Finally, if no error until here, we can save config. */
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
4941
        ret = virDomainSaveConfig(cfg->configDir, driver->caps, vmdef);
4942 4943 4944 4945 4946
        if (!ret) {
            virDomainObjAssignDef(vm, vmdef, false, NULL);
            vmdef = NULL;
        }
    }
4947
 endjob:
4948 4949
    virLXCDomainObjEndJob(driver, vm);

4950
 cleanup:
4951 4952 4953 4954
    virDomainDefFree(vmdef);
    if (dev != dev_copy)
        virDomainDeviceDefFree(dev_copy);
    virDomainDeviceDefFree(dev);
4955
    virDomainObjEndAPI(&vm);
4956
    virObjectUnref(caps);
4957
    virObjectUnref(cfg);
4958
    return ret;
4959 4960 4961 4962 4963 4964 4965
}


static int lxcDomainDetachDeviceFlags(virDomainPtr dom,
                                      const char *xml,
                                      unsigned int flags)
{
4966
    virLXCDriverPtr driver = dom->conn->privateData;
4967
    virCapsPtr caps = NULL;
4968 4969 4970 4971
    virDomainObjPtr vm = NULL;
    virDomainDefPtr vmdef = NULL;
    virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
    int ret = -1;
4972
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
4973 4974 4975 4976

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

M
Michal Privoznik 已提交
4977
    if (!(vm = lxcDomObjFromDomain(dom)))
4978 4979
        goto cleanup;

4980 4981 4982
    if (virDomainDetachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4983
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
4984
        goto cleanup;
4985

4986 4987 4988
    if (virDomainObjUpdateModificationImpact(vm, &flags) < 0)
        goto endjob;

4989
    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
4990
        goto endjob;
4991

4992
    dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
4993
                                             caps, driver->xmlopt,
4994 4995
                                             VIR_DOMAIN_DEF_PARSE_INACTIVE |
                                             VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE);
4996
    if (dev == NULL)
4997
        goto endjob;
4998 4999 5000 5001 5002 5003 5004 5005

    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,
5006
                                          caps, driver->xmlopt);
5007
        if (!dev_copy)
5008
            goto endjob;
5009 5010 5011 5012
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        /* Make a copy for updated domain. */
5013
        vmdef = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt);
5014
        if (!vmdef)
5015
            goto endjob;
5016

5017 5018
        if (virDomainDefCompatibleDevice(vmdef, dev,
                                         VIR_DOMAIN_DEVICE_ACTION_DETACH) < 0)
5019
            goto endjob;
5020

5021
        if ((ret = lxcDomainDetachDeviceConfig(vmdef, dev)) < 0)
5022
            goto endjob;
5023 5024 5025
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
5026 5027
        if (virDomainDefCompatibleDevice(vm->def, dev_copy,
                                         VIR_DOMAIN_DEVICE_ACTION_DETACH) < 0)
5028
            goto endjob;
5029 5030

        if ((ret = lxcDomainDetachDeviceLive(driver, vm, dev_copy)) < 0)
5031
            goto endjob;
5032 5033 5034 5035 5036
        /*
         * 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.
         */
5037
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0) {
5038
            ret = -1;
5039
            goto endjob;
5040 5041 5042 5043 5044
        }
    }

    /* Finally, if no error until here, we can save config. */
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5045
        ret = virDomainSaveConfig(cfg->configDir, driver->caps, vmdef);
5046 5047 5048 5049 5050 5051
        if (!ret) {
            virDomainObjAssignDef(vm, vmdef, false, NULL);
            vmdef = NULL;
        }
    }

5052
 endjob:
5053 5054
    virLXCDomainObjEndJob(driver, vm);

5055
 cleanup:
5056 5057 5058 5059
    virDomainDefFree(vmdef);
    if (dev != dev_copy)
        virDomainDeviceDefFree(dev_copy);
    virDomainDeviceDefFree(dev);
5060
    virDomainObjEndAPI(&vm);
5061
    virObjectUnref(caps);
5062
    virObjectUnref(cfg);
5063
    return ret;
5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074
}


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


5075 5076 5077
static int lxcDomainLxcOpenNamespace(virDomainPtr dom,
                                     int **fdlist,
                                     unsigned int flags)
5078
{
5079
    virLXCDriverPtr driver = dom->conn->privateData;
5080 5081 5082 5083 5084 5085 5086 5087
    virDomainObjPtr vm;
    virLXCDomainObjPrivatePtr priv;
    int ret = -1;
    size_t nfds = 0;

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

M
Michal Privoznik 已提交
5088
    if (!(vm = lxcDomObjFromDomain(dom)))
5089
        goto cleanup;
M
Michal Privoznik 已提交
5090

5091 5092
    priv = vm->privateData;

5093 5094 5095
    if (virDomainLxcOpenNamespaceEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

5096 5097 5098
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_QUERY) < 0)
        goto cleanup;

5099 5100 5101
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not running"));
5102
        goto endjob;
5103 5104 5105 5106 5107
    }

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

    if (virProcessGetNamespaces(priv->initpid, &nfds, fdlist) < 0)
5112
        goto endjob;
5113 5114

    ret = nfds;
5115 5116

 endjob:
5117
    virLXCDomainObjEndJob(driver, vm);
5118

5119
 cleanup:
5120
    virDomainObjEndAPI(&vm);
5121 5122 5123 5124
    return ret;
}


5125
static char *
5126
lxcConnectGetSysinfo(virConnectPtr conn, unsigned int flags)
5127 5128 5129 5130 5131 5132
{
    virLXCDriverPtr driver = conn->privateData;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    virCheckFlags(0, NULL);

5133 5134 5135
    if (virConnectGetSysinfoEnsureACL(conn) < 0)
        return NULL;

5136 5137 5138 5139 5140 5141 5142 5143
    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;
5144
    if (virBufferCheckError(&buf) < 0)
5145 5146 5147 5148 5149
        return NULL;
    return virBufferContentAndReset(&buf);
}


5150
static int
5151
lxcNodeGetInfo(virConnectPtr conn,
5152 5153
               virNodeInfoPtr nodeinfo)
{
5154 5155 5156
    if (virNodeGetInfoEnsureACL(conn) < 0)
        return -1;

5157
    return nodeGetInfo(nodeinfo);
5158 5159 5160
}


5161 5162
static int
lxcDomainMemoryStats(virDomainPtr dom,
5163
                     virDomainMemoryStatPtr stats,
5164 5165 5166 5167 5168 5169 5170 5171
                     unsigned int nr_stats,
                     unsigned int flags)
{
    virDomainObjPtr vm;
    int ret = -1;
    virLXCDomainObjPrivatePtr priv;
    unsigned long long swap_usage;
    unsigned long mem_usage;
5172
    virLXCDriverPtr driver = dom->conn->privateData;
5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183

    virCheckFlags(0, -1);

    if (!(vm = lxcDomObjFromDomain(dom)))
        goto cleanup;

    priv = vm->privateData;

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

5184 5185 5186
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_QUERY) < 0)
        goto cleanup;

5187 5188 5189
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not active"));
5190
        goto endjob;
5191
    }
5192

5193
    if (virCgroupGetMemSwapUsage(priv->cgroup, &swap_usage) < 0)
5194
        goto endjob;
5195

5196
    if (virCgroupGetMemoryUsage(priv->cgroup, &mem_usage) < 0)
5197
        goto endjob;
5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215

    ret = 0;
    if (ret < nr_stats) {
        stats[ret].tag = VIR_DOMAIN_MEMORY_STAT_ACTUAL_BALLOON;
        stats[ret].val = vm->def->mem.cur_balloon;
        ret++;
    }
    if (ret < nr_stats) {
        stats[ret].tag = VIR_DOMAIN_MEMORY_STAT_SWAP_IN;
        stats[ret].val = swap_usage;
        ret++;
    }
    if (ret < nr_stats) {
        stats[ret].tag = VIR_DOMAIN_MEMORY_STAT_RSS;
        stats[ret].val = mem_usage;
        ret++;
    }

5216
 endjob:
5217 5218
    virLXCDomainObjEndJob(driver, vm);

5219
 cleanup:
5220
    virDomainObjEndAPI(&vm);
5221 5222 5223 5224
    return ret;
}


5225
static int
5226
lxcNodeGetCPUStats(virConnectPtr conn,
5227 5228 5229 5230 5231
                   int cpuNum,
                   virNodeCPUStatsPtr params,
                   int *nparams,
                   unsigned int flags)
{
5232 5233 5234
    if (virNodeGetCPUStatsEnsureACL(conn) < 0)
        return -1;

5235 5236 5237 5238 5239
    return nodeGetCPUStats(cpuNum, params, nparams, flags);
}


static int
5240
lxcNodeGetMemoryStats(virConnectPtr conn,
5241 5242 5243 5244 5245
                      int cellNum,
                      virNodeMemoryStatsPtr params,
                      int *nparams,
                      unsigned int flags)
{
5246 5247 5248
    if (virNodeGetMemoryStatsEnsureACL(conn) < 0)
        return -1;

5249
    return nodeGetMemoryStats(cellNum, params, nparams, flags);
5250 5251 5252 5253
}


static int
5254
lxcNodeGetCellsFreeMemory(virConnectPtr conn,
5255 5256 5257 5258
                          unsigned long long *freeMems,
                          int startCell,
                          int maxCells)
{
5259 5260 5261
    if (virNodeGetCellsFreeMemoryEnsureACL(conn) < 0)
        return -1;

5262 5263 5264 5265 5266
    return nodeGetCellsFreeMemory(freeMems, startCell, maxCells);
}


static unsigned long long
5267
lxcNodeGetFreeMemory(virConnectPtr conn)
5268
{
5269 5270
    unsigned long long freeMem;

5271 5272 5273
    if (virNodeGetFreeMemoryEnsureACL(conn) < 0)
        return 0;

5274 5275 5276 5277
    if (nodeGetMemory(NULL, &freeMem) < 0)
        return 0;

    return freeMem;
5278 5279 5280 5281
}


static int
5282
lxcNodeGetMemoryParameters(virConnectPtr conn,
5283 5284 5285 5286
                           virTypedParameterPtr params,
                           int *nparams,
                           unsigned int flags)
{
5287 5288 5289
    if (virNodeGetMemoryParametersEnsureACL(conn) < 0)
        return -1;

5290 5291 5292 5293 5294
    return nodeGetMemoryParameters(params, nparams, flags);
}


static int
5295
lxcNodeSetMemoryParameters(virConnectPtr conn,
5296 5297 5298 5299
                           virTypedParameterPtr params,
                           int nparams,
                           unsigned int flags)
{
5300 5301 5302
    if (virNodeSetMemoryParametersEnsureACL(conn) < 0)
        return -1;

5303 5304 5305 5306 5307
    return nodeSetMemoryParameters(params, nparams, flags);
}


static int
5308
lxcNodeGetCPUMap(virConnectPtr conn,
5309 5310 5311 5312
                 unsigned char **cpumap,
                 unsigned int *online,
                 unsigned int flags)
{
5313 5314 5315
    if (virNodeGetCPUMapEnsureACL(conn) < 0)
        return -1;

5316
    return nodeGetCPUMap(cpumap, online, flags);
5317 5318
}

5319 5320

static int
5321
lxcNodeSuspendForDuration(virConnectPtr conn,
5322 5323 5324 5325
                          unsigned int target,
                          unsigned long long duration,
                          unsigned int flags)
{
5326 5327 5328
    if (virNodeSuspendForDurationEnsureACL(conn) < 0)
        return -1;

5329 5330 5331 5332
    return nodeSuspendForDuration(target, duration, flags);
}


5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360
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;

5361 5362 5363
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

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

5368
    virLXCDomainObjEndJob(driver, vm);
5369

5370
 cleanup:
5371
    virDomainObjEndAPI(&vm);
5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399
    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);

5400
 cleanup:
5401
    virDomainObjEndAPI(&vm);
5402 5403 5404 5405 5406
    virObjectUnref(caps);
    return ret;
}


5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445
static int
lxcDomainGetCPUStats(virDomainPtr dom,
                     virTypedParameterPtr params,
                     unsigned int nparams,
                     int start_cpu,
                     unsigned int ncpus,
                     unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virLXCDomainObjPrivatePtr priv;

    virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);

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

    priv = vm->privateData;

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

    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not running"));
        goto cleanup;
    }

    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUACCT)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPUACCT controller is not mounted"));
        goto cleanup;
    }

    if (start_cpu == -1)
        ret = virCgroupGetDomainTotalCpuStats(priv->cgroup,
                                              params, nparams);
    else
        ret = virCgroupGetPercpuStats(priv->cgroup, params,
5446
                                      nparams, start_cpu, ncpus, NULL);
5447
 cleanup:
5448
    virDomainObjEndAPI(&vm);
5449 5450 5451 5452
    return ret;
}


5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470
static int
lxcNodeGetFreePages(virConnectPtr conn,
                    unsigned int npages,
                    unsigned int *pages,
                    int startCell,
                    unsigned int cellCount,
                    unsigned long long *counts,
                    unsigned int flags)
{
    virCheckFlags(0, -1);

    if (virNodeGetFreePagesEnsureACL(conn) < 0)
        return -1;

    return nodeGetFreePages(npages, pages, startCell, cellCount, counts);
}


5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491
static int
lxcNodeAllocPages(virConnectPtr conn,
                  unsigned int npages,
                  unsigned int *pageSizes,
                  unsigned long long *pageCounts,
                  int startCell,
                  unsigned int cellCount,
                  unsigned int flags)
{
    bool add = !(flags & VIR_NODE_ALLOC_PAGES_SET);

    virCheckFlags(VIR_NODE_ALLOC_PAGES_SET, -1);

    if (virNodeAllocPagesEnsureACL(conn) < 0)
        return -1;

    return nodeAllocPages(npages, pageSizes, pageCounts,
                          startCell, cellCount, add);
}


5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508
static int
lxcDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;

    virCheckFlags(0, -1);

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

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

    ret = 0;

 cleanup:
5509
    virDomainObjEndAPI(&vm);
5510 5511 5512 5513
    return ret;
}


D
Daniel Veillard 已提交
5514
/* Function Tables */
5515
static virHypervisorDriver lxcHypervisorDriver = {
5516
    .name = LXC_DRIVER_NAME,
5517 5518
    .connectOpen = lxcConnectOpen, /* 0.4.2 */
    .connectClose = lxcConnectClose, /* 0.4.2 */
5519
    .connectSupportsFeature = lxcConnectSupportsFeature, /* 1.2.2 */
5520
    .connectGetVersion = lxcConnectGetVersion, /* 0.4.6 */
5521
    .connectGetHostname = lxcConnectGetHostname, /* 0.6.3 */
5522
    .connectGetSysinfo = lxcConnectGetSysinfo, /* 1.0.5 */
5523
    .nodeGetInfo = lxcNodeGetInfo, /* 0.6.5 */
5524 5525 5526 5527 5528
    .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 */
5529
    .domainCreateXMLWithFiles = lxcDomainCreateXMLWithFiles, /* 1.1.1 */
5530 5531 5532 5533 5534 5535
    .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 */
5536
    .domainDestroyFlags = lxcDomainDestroyFlags, /* 0.9.4 */
5537
    .domainGetOSType = lxcDomainGetOSType, /* 0.4.2 */
5538 5539 5540
    .domainGetMaxMemory = lxcDomainGetMaxMemory, /* 0.7.2 */
    .domainSetMaxMemory = lxcDomainSetMaxMemory, /* 0.7.2 */
    .domainSetMemory = lxcDomainSetMemory, /* 0.7.2 */
5541
    .domainSetMemoryFlags = lxcDomainSetMemoryFlags, /* 1.2.7 */
5542 5543
    .domainSetMemoryParameters = lxcDomainSetMemoryParameters, /* 0.8.5 */
    .domainGetMemoryParameters = lxcDomainGetMemoryParameters, /* 0.8.5 */
5544 5545
    .domainSetBlkioParameters = lxcDomainSetBlkioParameters, /* 0.9.8 */
    .domainGetBlkioParameters = lxcDomainGetBlkioParameters, /* 0.9.8 */
5546 5547
    .domainGetInfo = lxcDomainGetInfo, /* 0.4.2 */
    .domainGetState = lxcDomainGetState, /* 0.9.2 */
5548 5549
    .domainGetSecurityLabel = lxcDomainGetSecurityLabel, /* 0.9.10 */
    .nodeGetSecurityModel = lxcNodeGetSecurityModel, /* 0.9.10 */
5550
    .domainGetXMLDesc = lxcDomainGetXMLDesc, /* 0.4.2 */
5551
    .connectDomainXMLFromNative = lxcConnectDomainXMLFromNative, /* 1.2.2 */
5552 5553 5554 5555
    .connectListDefinedDomains = lxcConnectListDefinedDomains, /* 0.4.2 */
    .connectNumOfDefinedDomains = lxcConnectNumOfDefinedDomains, /* 0.4.2 */
    .domainCreate = lxcDomainCreate, /* 0.4.4 */
    .domainCreateWithFlags = lxcDomainCreateWithFlags, /* 0.8.2 */
5556
    .domainCreateWithFiles = lxcDomainCreateWithFiles, /* 1.1.1 */
5557
    .domainDefineXML = lxcDomainDefineXML, /* 0.4.2 */
5558
    .domainDefineXMLFlags = lxcDomainDefineXMLFlags, /* 1.2.12 */
5559
    .domainUndefine = lxcDomainUndefine, /* 0.4.2 */
5560
    .domainUndefineFlags = lxcDomainUndefineFlags, /* 0.9.4 */
5561 5562 5563 5564 5565
    .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 */
5566 5567
    .domainGetAutostart = lxcDomainGetAutostart, /* 0.7.0 */
    .domainSetAutostart = lxcDomainSetAutostart, /* 0.7.0 */
5568 5569 5570 5571 5572
    .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 */
5573 5574
    .domainBlockStats = lxcDomainBlockStats, /* 1.2.2 */
    .domainBlockStatsFlags = lxcDomainBlockStatsFlags, /* 1.2.2 */
5575
    .domainInterfaceStats = lxcDomainInterfaceStats, /* 0.7.3 */
5576
    .domainMemoryStats = lxcDomainMemoryStats, /* 1.2.2 */
5577 5578 5579 5580 5581
    .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 */
5582 5583 5584 5585
    .connectDomainEventRegister = lxcConnectDomainEventRegister, /* 0.7.0 */
    .connectDomainEventDeregister = lxcConnectDomainEventDeregister, /* 0.7.0 */
    .connectIsEncrypted = lxcConnectIsEncrypted, /* 0.7.3 */
    .connectIsSecure = lxcConnectIsSecure, /* 0.7.3 */
5586 5587 5588
    .domainIsActive = lxcDomainIsActive, /* 0.7.3 */
    .domainIsPersistent = lxcDomainIsPersistent, /* 0.7.3 */
    .domainIsUpdated = lxcDomainIsUpdated, /* 0.8.6 */
5589 5590
    .connectDomainEventRegisterAny = lxcConnectDomainEventRegisterAny, /* 0.8.0 */
    .connectDomainEventDeregisterAny = lxcConnectDomainEventDeregisterAny, /* 0.8.0 */
5591
    .domainOpenConsole = lxcDomainOpenConsole, /* 0.8.6 */
5592
    .connectIsAlive = lxcConnectIsAlive, /* 0.9.8 */
5593
    .nodeSuspendForDuration = lxcNodeSuspendForDuration, /* 0.9.8 */
5594 5595
    .domainSetMetadata = lxcDomainSetMetadata, /* 1.1.3 */
    .domainGetMetadata = lxcDomainGetMetadata, /* 1.1.3 */
5596
    .domainGetCPUStats = lxcDomainGetCPUStats, /* 1.2.2 */
5597 5598
    .nodeGetMemoryParameters = lxcNodeGetMemoryParameters, /* 0.10.2 */
    .nodeSetMemoryParameters = lxcNodeSetMemoryParameters, /* 0.10.2 */
5599
    .domainSendProcessSignal = lxcDomainSendProcessSignal, /* 1.0.1 */
5600 5601 5602
    .domainShutdown = lxcDomainShutdown, /* 1.0.1 */
    .domainShutdownFlags = lxcDomainShutdownFlags, /* 1.0.1 */
    .domainReboot = lxcDomainReboot, /* 1.0.1 */
5603
    .domainLxcOpenNamespace = lxcDomainLxcOpenNamespace, /* 1.0.2 */
5604
    .nodeGetFreePages = lxcNodeGetFreePages, /* 1.2.6 */
5605
    .nodeAllocPages = lxcNodeAllocPages, /* 1.2.9 */
5606
    .domainHasManagedSaveImage = lxcDomainHasManagedSaveImage, /* 1.2.13 */
D
Daniel Veillard 已提交
5607 5608
};

5609 5610 5611 5612
static virConnectDriver lxcConnectDriver = {
    .hypervisorDriver = &lxcHypervisorDriver,
};

5613
static virStateDriver lxcStateDriver = {
5614
    .name = LXC_DRIVER_NAME,
5615
    .stateInitialize = lxcStateInitialize,
5616
    .stateAutoStart = lxcStateAutoStart,
5617 5618
    .stateCleanup = lxcStateCleanup,
    .stateReload = lxcStateReload,
5619 5620
};

D
Daniel Veillard 已提交
5621 5622
int lxcRegister(void)
{
5623 5624
    if (virRegisterConnectDriver(&lxcConnectDriver,
                                 true) < 0)
5625 5626 5627
        return -1;
    if (virRegisterStateDriver(&lxcStateDriver) < 0)
        return -1;
D
Daniel Veillard 已提交
5628 5629
    return 0;
}