lxc_driver.c 162.8 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
 * Copyright IBM Corp. 2008
 *
 * lxc_driver.c: linux container driver functions
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library.  If not, see
O
Osier Yang 已提交
19
 * <http://www.gnu.org/licenses/>.
D
Daniel Veillard 已提交
20 21 22 23
 */

#include <config.h>

24
#include <fcntl.h>
D
Daniel Veillard 已提交
25 26
#include <sched.h>
#include <sys/utsname.h>
27 28 29 30 31 32 33

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

34
#include <sys/types.h>
35
#include <sys/socket.h>
36
#include <sys/stat.h>
37 38
#include <sys/un.h>
#include <sys/poll.h>
D
Daniel Veillard 已提交
39 40 41
#include <unistd.h>
#include <wait.h>

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

79 80
#define VIR_FROM_THIS VIR_FROM_LXC

81
VIR_LOG_INIT("lxc.lxc_driver");
82

83
#define LXC_NB_MEM_PARAM  3
84
#define LXC_NB_DOMAIN_BLOCK_STAT_PARAM 4
85

86

87 88 89 90
static int lxcStateInitialize(bool privileged,
                              virStateInhibitCallback callback,
                              void *opaque);
static int lxcStateCleanup(void);
91
virLXCDriverPtr lxc_driver = NULL;
D
Daniel Veillard 已提交
92

93

M
Michal Privoznik 已提交
94 95 96 97
/**
 * lxcDomObjFromDomain:
 * @domain: Domain pointer that has to be looked up
 *
98 99
 * This function looks up @domain and returns the appropriate virDomainObjPtr
 * that has to be released by calling virDomainObjEndAPI.
M
Michal Privoznik 已提交
100
 *
101 102
 * Returns the domain object with incremented reference counter which is locked
 * on success, NULL otherwise.
M
Michal Privoznik 已提交
103 104 105 106 107 108 109 110
 */
static virDomainObjPtr
lxcDomObjFromDomain(virDomainPtr domain)
{
    virDomainObjPtr vm;
    virLXCDriverPtr driver = domain->conn->privateData;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

111
    vm = virDomainObjListFindByUUID(driver->domains, domain->uuid);
M
Michal Privoznik 已提交
112 113 114 115 116 117 118 119 120 121 122
    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 已提交
123 124
/* Functions */

125 126 127 128 129 130 131 132 133 134
static int
lxcConnectURIProbe(char **uri)
{
    if (lxc_driver == NULL)
        return 0;

    return VIR_STRDUP(*uri, "lxc:///system");
}


135 136
static virDrvOpenStatus lxcConnectOpen(virConnectPtr conn,
                                       virConnectAuthPtr auth ATTRIBUTE_UNUSED,
137
                                       virConfPtr conf ATTRIBUTE_UNUSED,
138
                                       unsigned int flags)
D
Daniel Veillard 已提交
139
{
E
Eric Blake 已提交
140 141
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

142
    /* If path isn't '/' then they typoed, tell them correct path */
143 144
    if (STRNEQ(conn->uri->path, "") &&
        STRNEQ(conn->uri->path, "/") &&
145 146 147 148 149 150 151 152 153 154 155 156
        STRNEQ(conn->uri->path, "/system")) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unexpected LXC URI path '%s', try lxc:///system"),
                       conn->uri->path);
        return VIR_DRV_OPEN_ERROR;
    }

    /* URI was good, but driver isn't active */
    if (lxc_driver == NULL) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("lxc state driver is not active"));
        return VIR_DRV_OPEN_ERROR;
157
    }
158

159 160 161
    if (virConnectOpenEnsureACL(conn) < 0)
        return VIR_DRV_OPEN_ERROR;

162
    conn->privateData = lxc_driver;
D
Daniel Veillard 已提交
163 164 165 166

    return VIR_DRV_OPEN_SUCCESS;
}

167
static int lxcConnectClose(virConnectPtr conn)
D
Daniel Veillard 已提交
168
{
169
    virLXCDriverPtr driver = conn->privateData;
170

171
    virCloseCallbacksRun(driver->closeCallbacks, conn, driver->domains, driver);
172 173
    conn->privateData = NULL;
    return 0;
D
Daniel Veillard 已提交
174 175
}

176

177
static int lxcConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
178 179 180 181 182 183
{
    /* Trivially secure, since always inside the daemon */
    return 1;
}


184
static int lxcConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
185 186 187 188 189 190
{
    /* Not encrypted, but remote driver takes care of that */
    return 0;
}


191
static int lxcConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
192 193 194 195 196
{
    return 1;
}


197
static char *lxcConnectGetCapabilities(virConnectPtr conn) {
198
    virLXCDriverPtr driver = conn->privateData;
199
    virCapsPtr caps;
200 201
    char *xml;

202 203 204
    if (virConnectGetCapabilitiesEnsureACL(conn) < 0)
        return NULL;

205
    if (!(caps = virLXCDriverGetCapabilities(driver, true)))
206 207
        return NULL;

208
    xml = virCapabilitiesFormatXML(caps);
209

210
    virObjectUnref(caps);
211 212 213 214
    return xml;
}


D
Daniel Veillard 已提交
215 216 217
static virDomainPtr lxcDomainLookupByID(virConnectPtr conn,
                                        int id)
{
218
    virLXCDriverPtr driver = conn->privateData;
219 220
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
221

222
    vm = virDomainObjListFindByID(driver->domains, id);
223

D
Daniel Veillard 已提交
224
    if (!vm) {
225 226
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching id %d"), id);
227
        goto cleanup;
D
Daniel Veillard 已提交
228 229
    }

230 231 232
    if (virDomainLookupByIDEnsureACL(conn, vm->def) < 0)
        goto cleanup;

233
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
D
Daniel Veillard 已提交
234

235
 cleanup:
236
    virDomainObjEndAPI(&vm);
D
Daniel Veillard 已提交
237 238 239 240 241 242
    return dom;
}

static virDomainPtr lxcDomainLookupByUUID(virConnectPtr conn,
                                          const unsigned char *uuid)
{
243
    virLXCDriverPtr driver = conn->privateData;
244 245
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
246

247
    vm = virDomainObjListFindByUUID(driver->domains, uuid);
248

D
Daniel Veillard 已提交
249
    if (!vm) {
250 251
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
252 253
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching uuid '%s'"), uuidstr);
254
        goto cleanup;
D
Daniel Veillard 已提交
255 256
    }

257 258 259
    if (virDomainLookupByUUIDEnsureACL(conn, vm->def) < 0)
        goto cleanup;

260
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
D
Daniel Veillard 已提交
261

262
 cleanup:
263
    virDomainObjEndAPI(&vm);
D
Daniel Veillard 已提交
264 265 266 267 268 269
    return dom;
}

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

274
    vm = virDomainObjListFindByName(driver->domains, name);
D
Daniel Veillard 已提交
275
    if (!vm) {
276 277
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching name '%s'"), name);
278
        goto cleanup;
D
Daniel Veillard 已提交
279 280
    }

281 282 283
    if (virDomainLookupByNameEnsureACL(conn, vm->def) < 0)
        goto cleanup;

284
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
D
Daniel Veillard 已提交
285

286
 cleanup:
287
    virDomainObjEndAPI(&vm);
D
Daniel Veillard 已提交
288 289 290
    return dom;
}

291 292 293 294 295 296

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

M
Michal Privoznik 已提交
297
    if (!(obj = lxcDomObjFromDomain(dom)))
298
        goto cleanup;
299 300 301 302

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

303 304
    ret = virDomainObjIsActive(obj);

305
 cleanup:
306
    virDomainObjEndAPI(&obj);
307 308 309 310 311 312 313 314 315
    return ret;
}


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

M
Michal Privoznik 已提交
316
    if (!(obj = lxcDomObjFromDomain(dom)))
317
        goto cleanup;
318 319 320 321

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

322 323
    ret = obj->persistent;

324
 cleanup:
325
    virDomainObjEndAPI(&obj);
326 327 328
    return ret;
}

329 330 331 332 333
static int lxcDomainIsUpdated(virDomainPtr dom)
{
    virDomainObjPtr obj;
    int ret = -1;

M
Michal Privoznik 已提交
334
    if (!(obj = lxcDomObjFromDomain(dom)))
335
        goto cleanup;
336 337 338 339

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

340 341
    ret = obj->updated;

342
 cleanup:
343
    virDomainObjEndAPI(&obj);
344 345
    return ret;
}
346

347 348
static int lxcConnectListDomains(virConnectPtr conn, int *ids, int nids)
{
349
    virLXCDriverPtr driver = conn->privateData;
350
    int n;
351

352 353 354
    if (virConnectListDomainsEnsureACL(conn) < 0)
        return -1;

355 356
    n = virDomainObjListGetActiveIDs(driver->domains, ids, nids,
                                     virConnectListDomainsCheckACL, conn);
357

358
    return n;
D
Daniel Veillard 已提交
359
}
360

361 362
static int lxcConnectNumOfDomains(virConnectPtr conn)
{
363
    virLXCDriverPtr driver = conn->privateData;
364
    int n;
365

366 367 368
    if (virConnectNumOfDomainsEnsureACL(conn) < 0)
        return -1;

369 370
    n = virDomainObjListNumOfDomains(driver->domains, true,
                                     virConnectNumOfDomainsCheckACL, conn);
371

372
    return n;
D
Daniel Veillard 已提交
373 374
}

375
static int lxcConnectListDefinedDomains(virConnectPtr conn,
376 377
                                        char **const names, int nnames)
{
378
    virLXCDriverPtr driver = conn->privateData;
379
    int n;
380

381 382 383
    if (virConnectListDefinedDomainsEnsureACL(conn) < 0)
        return -1;

384 385
    n = virDomainObjListGetInactiveNames(driver->domains, names, nnames,
                                         virConnectListDefinedDomainsCheckACL, conn);
386

387
    return n;
D
Daniel Veillard 已提交
388 389 390
}


391 392
static int lxcConnectNumOfDefinedDomains(virConnectPtr conn)
{
393
    virLXCDriverPtr driver = conn->privateData;
394
    int n;
395

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

399 400
    n = virDomainObjListNumOfDomains(driver->domains, false,
                                     virConnectNumOfDefinedDomainsCheckACL, conn);
401

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

405 406


407 408
static virDomainPtr
lxcDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags)
D
Daniel Veillard 已提交
409
{
410
    virLXCDriverPtr driver = conn->privateData;
411
    virDomainDefPtr def = NULL;
412
    virDomainObjPtr vm = NULL;
413
    virDomainPtr dom = NULL;
414
    virObjectEventPtr event = NULL;
415
    virDomainDefPtr oldDef = NULL;
416
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
417
    virCapsPtr caps = NULL;
418
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
D
Daniel Veillard 已提交
419

420 421 422
    virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);

    if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
423
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
424

425 426 427 428
    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
        goto cleanup;

    if (!(def = virDomainDefParseString(xml, caps, driver->xmlopt,
429
                                        NULL, parse_flags)))
430
        goto cleanup;
D
Daniel Veillard 已提交
431

432 433 434
    if (virXMLCheckIllegalChars("name", def->name, "\n") < 0)
        goto cleanup;

435
    if (virDomainDefineXMLFlagsEnsureACL(conn, def) < 0)
436 437
        goto cleanup;

438 439 440
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
        goto cleanup;

441
    if ((def->nets != NULL) && !(cfg->have_netns)) {
442 443
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("System lacks NETNS support"));
444
        goto cleanup;
445 446
    }

447
    if (!(vm = virDomainObjListAdd(driver->domains, def,
448
                                   driver->xmlopt,
449
                                   0, &oldDef)))
450
        goto cleanup;
451

452
    def = NULL;
453
    vm->persistent = 1;
D
Daniel Veillard 已提交
454

455
    if (virDomainSaveConfig(cfg->configDir, driver->caps,
456
                            vm->newDef ? vm->newDef : vm->def) < 0) {
457
        virDomainObjListRemove(driver->domains, vm);
458
        goto cleanup;
D
Daniel Veillard 已提交
459 460
    }

461
    event = virDomainEventLifecycleNewFromObj(vm,
462
                                     VIR_DOMAIN_EVENT_DEFINED,
463
                                     !oldDef ?
464 465 466
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);

467
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
D
Daniel Veillard 已提交
468

469
 cleanup:
470
    virDomainDefFree(def);
471
    virDomainDefFree(oldDef);
472
    virDomainObjEndAPI(&vm);
473
    virObjectEventStateQueue(driver->domainEventState, event);
474
    virObjectUnref(caps);
475
    virObjectUnref(cfg);
D
Daniel Veillard 已提交
476 477 478
    return dom;
}

479 480 481 482 483 484
static virDomainPtr
lxcDomainDefineXML(virConnectPtr conn, const char *xml)
{
    return lxcDomainDefineXMLFlags(conn, xml, 0);
}

485 486
static int lxcDomainUndefineFlags(virDomainPtr dom,
                                  unsigned int flags)
D
Daniel Veillard 已提交
487
{
488
    virLXCDriverPtr driver = dom->conn->privateData;
489
    virDomainObjPtr vm;
490
    virObjectEventPtr event = NULL;
491
    int ret = -1;
492
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
D
Daniel Veillard 已提交
493

494 495
    virCheckFlags(0, -1);

M
Michal Privoznik 已提交
496
    if (!(vm = lxcDomObjFromDomain(dom)))
497
        goto cleanup;
D
Daniel Veillard 已提交
498

499 500 501
    if (virDomainUndefineFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

502
    if (!vm->persistent) {
503 504
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Cannot undefine transient domain"));
505
        goto cleanup;
506
    }
D
Daniel Veillard 已提交
507

508 509
    if (virDomainDeleteConfig(cfg->configDir,
                              cfg->autostartDir,
510 511
                              vm) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
512

513
    event = virDomainEventLifecycleNewFromObj(vm,
514 515 516
                                     VIR_DOMAIN_EVENT_UNDEFINED,
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);

517
    if (virDomainObjIsActive(vm))
518
        vm->persistent = 0;
519
    else
520
        virDomainObjListRemove(driver->domains, vm);
521

522
    ret = 0;
D
Daniel Veillard 已提交
523

524
 cleanup:
525
    virDomainObjEndAPI(&vm);
526
    virObjectEventStateQueue(driver->domainEventState, event);
527
    virObjectUnref(cfg);
528
    return ret;
D
Daniel Veillard 已提交
529 530
}

531 532 533 534 535
static int lxcDomainUndefine(virDomainPtr dom)
{
    return lxcDomainUndefineFlags(dom, 0);
}

D
Daniel Veillard 已提交
536 537 538
static int lxcDomainGetInfo(virDomainPtr dom,
                            virDomainInfoPtr info)
{
539
    virDomainObjPtr vm;
540
    int ret = -1;
541
    virLXCDomainObjPrivatePtr priv;
D
Daniel Veillard 已提交
542

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

546 547
    priv = vm->privateData;

548 549 550
    if (virDomainGetInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

553
    if (!virDomainObjIsActive(vm)) {
D
Daniel Veillard 已提交
554
        info->cpuTime = 0;
555
        info->memory = vm->def->mem.cur_balloon;
D
Daniel Veillard 已提交
556
    } else {
557
        if (virCgroupGetCpuacctUsage(priv->cgroup, &(info->cpuTime)) < 0) {
558 559
            virReportError(VIR_ERR_OPERATION_FAILED,
                           "%s", _("Cannot read cputime for domain"));
R
Ryota Ozaki 已提交
560 561
            goto cleanup;
        }
562 563 564 565 566
        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();
567
                info->memory = 0;
568
            } else {
569
                goto cleanup;
570
            }
571
        }
D
Daniel Veillard 已提交
572 573
    }

574
    info->maxMem = virDomainDefGetMemoryTotal(vm->def);
575
    info->nrVirtCpu = virDomainDefGetVcpus(vm->def);
576
    ret = 0;
D
Daniel Veillard 已提交
577

578
 cleanup:
579
    virDomainObjEndAPI(&vm);
580
    return ret;
D
Daniel Veillard 已提交
581 582
}

583 584 585 586 587 588 589 590 591 592 593
static int
lxcDomainGetState(virDomainPtr dom,
                  int *state,
                  int *reason,
                  unsigned int flags)
{
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

M
Michal Privoznik 已提交
594
    if (!(vm = lxcDomObjFromDomain(dom)))
595 596
        goto cleanup;

597 598 599
    if (virDomainGetStateEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
600
    *state = virDomainObjGetState(vm, reason);
601 602
    ret = 0;

603
 cleanup:
604
    virDomainObjEndAPI(&vm);
605 606 607
    return ret;
}

608
static char *lxcDomainGetOSType(virDomainPtr dom)
D
Daniel Veillard 已提交
609
{
610 611
    virDomainObjPtr vm;
    char *ret = NULL;
612

M
Michal Privoznik 已提交
613
    if (!(vm = lxcDomObjFromDomain(dom)))
614
        goto cleanup;
615

616 617 618
    if (virDomainGetOSTypeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

619
    if (VIR_STRDUP(ret, virDomainOSTypeToString(vm->def->os.type)) < 0)
620
        goto cleanup;
621

622
 cleanup:
623
    virDomainObjEndAPI(&vm);
624
    return ret;
D
Daniel Veillard 已提交
625 626
}

R
Ryota Ozaki 已提交
627
/* Returns max memory in kb, 0 if error */
628 629 630
static unsigned long long
lxcDomainGetMaxMemory(virDomainPtr dom)
{
R
Ryota Ozaki 已提交
631
    virDomainObjPtr vm;
632
    unsigned long long ret = 0;
R
Ryota Ozaki 已提交
633

M
Michal Privoznik 已提交
634
    if (!(vm = lxcDomObjFromDomain(dom)))
R
Ryota Ozaki 已提交
635 636
        goto cleanup;

637 638 639
    if (virDomainGetMaxMemoryEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

640
    ret = virDomainDefGetMemoryTotal(vm->def);
R
Ryota Ozaki 已提交
641

642
 cleanup:
643
    virDomainObjEndAPI(&vm);
R
Ryota Ozaki 已提交
644 645 646
    return ret;
}

647 648
static int lxcDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem,
                                   unsigned int flags)
649
{
R
Ryota Ozaki 已提交
650
    virDomainObjPtr vm;
651
    virDomainDefPtr def = NULL;
652
    virDomainDefPtr persistentDef = NULL;
R
Ryota Ozaki 已提交
653
    int ret = -1;
654
    virLXCDomainObjPrivatePtr priv;
655 656 657 658
    virLXCDriverPtr driver = dom->conn->privateData;
    virLXCDriverConfigPtr cfg = NULL;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
659 660
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_DOMAIN_MEM_MAXIMUM, -1);
R
Ryota Ozaki 已提交
661

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

665 666
    cfg = virLXCDriverGetConfig(driver);

667
    priv = vm->privateData;
R
Ryota Ozaki 已提交
668

669
    if (virDomainSetMemoryFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
670 671
        goto cleanup;

672
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
673 674
        goto cleanup;

675
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
676
        goto endjob;
677

678
    if (flags & VIR_DOMAIN_MEM_MAXIMUM) {
679
        if (def) {
680 681 682
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Cannot resize the max memory "
                             "on an active domain"));
683
            goto endjob;
684
        }
685

686
        if (persistentDef) {
687
            virDomainDefSetMemoryTotal(persistentDef, newmem);
688 689
            if (persistentDef->mem.cur_balloon > newmem)
                persistentDef->mem.cur_balloon = newmem;
690 691
            if (virDomainSaveConfig(cfg->configDir, driver->caps,
                                    persistentDef) < 0)
692
                goto endjob;
693 694 695
        }
    } else {
        unsigned long oldmax = 0;
R
Ryota Ozaki 已提交
696

697
        if (def)
698
            oldmax = virDomainDefGetMemoryTotal(def);
699
        if (persistentDef) {
700 701
            if (!oldmax || oldmax > virDomainDefGetMemoryTotal(persistentDef))
                oldmax = virDomainDefGetMemoryTotal(persistentDef);
702
        }
703

704 705 706
        if (newmem > oldmax) {
            virReportError(VIR_ERR_INVALID_ARG,
                           "%s", _("Cannot set memory higher than max memory"));
707
            goto endjob;
708 709
        }

710
        if (def) {
711 712 713
            if (virCgroupSetMemory(priv->cgroup, newmem) < 0) {
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("Failed to set memory for domain"));
714
                goto endjob;
715
            }
716

717
            def->mem.cur_balloon = newmem;
718
            if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
719
                goto endjob;
720 721
        }

722
        if (persistentDef) {
723
            persistentDef->mem.cur_balloon = newmem;
724 725
            if (virDomainSaveConfig(cfg->configDir, driver->caps,
                                    persistentDef) < 0)
726
                goto endjob;
727
        }
728 729
    }

R
Ryota Ozaki 已提交
730 731
    ret = 0;

732
 endjob:
733
    virLXCDomainObjEndJob(driver, vm);
734

735
 cleanup:
736
    virDomainObjEndAPI(&vm);
737
    virObjectUnref(cfg);
R
Ryota Ozaki 已提交
738 739 740
    return ret;
}

741 742 743 744 745
static int lxcDomainSetMemory(virDomainPtr dom, unsigned long newmem)
{
    return lxcDomainSetMemoryFlags(dom, newmem, VIR_DOMAIN_AFFECT_LIVE);
}

746 747 748 749 750
static int lxcDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax)
{
    return lxcDomainSetMemoryFlags(dom, newmax, VIR_DOMAIN_MEM_MAXIMUM);
}

751 752 753 754 755
static int
lxcDomainSetMemoryParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int nparams,
                             unsigned int flags)
756
{
757
    virDomainDefPtr def = NULL;
J
Ján Tomko 已提交
758
    virDomainDefPtr persistentDef = NULL;
759
    virDomainObjPtr vm = NULL;
760 761 762 763 764 765 766 767 768 769
    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;
770 771
    int ret = -1;

772 773 774
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

775 776 777 778 779 780 781 782
    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)
783
        return -1;
E
Eric Blake 已提交
784

M
Michal Privoznik 已提交
785
    if (!(vm = lxcDomObjFromDomain(dom)))
786
        goto cleanup;
M
Michal Privoznik 已提交
787

788
    priv = vm->privateData;
789
    cfg = virLXCDriverGetConfig(driver);
790

791
    if (virDomainSetMemoryParametersEnsureACL(dom->conn, vm->def, flags) < 0)
792 793
        goto cleanup;

794 795 796
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

797 798
    /* QEMU and LXC implementation are identical */
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
799 800
        goto endjob;

801
    if (def &&
802
        !virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_MEMORY)) {
803 804
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cgroup memory controller is not mounted"));
805
        goto endjob;
806 807
    }

808 809 810 811 812
#define VIR_GET_LIMIT_PARAMETER(PARAM, VALUE) \
    if ((rc = virTypedParamsGetULLong(params, nparams, PARAM, &VALUE)) < 0) \
        goto endjob; \
 \
    if (rc == 1) \
813 814 815 816 817 818 819 820
        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

821
    /* Swap hard limit must be greater than hard limit. */
822 823 824 825 826 827 828 829 830 831
    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;

832
        if (mem_limit > swap_limit) {
833 834 835
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("memory hard_limit tunable value must be lower "
                             "than or equal to swap_hard_limit"));
836
            goto endjob;
837 838 839
        }
    }

840 841 842 843 844 845 846 847 848 849
#define VIR_SET_MEM_PARAMETER(FUNC, VALUE) \
    if (set_ ## VALUE) { \
        if (def) { \
            if ((rc = FUNC(priv->cgroup, VALUE)) < 0) \
                goto endjob; \
            def->mem.VALUE = VALUE; \
        } \
 \
        if (persistentDef) \
            persistentDef->mem.VALUE = VALUE; \
850 851 852
    }

    /* Soft limit doesn't clash with the others */
853
    VIR_SET_MEM_PARAMETER(virCgroupSetMemorySoftLimit, soft_limit);
854 855

    /* set hard limit before swap hard limit if decreasing it */
856 857
    if (def && def->mem.hard_limit > hard_limit) {
        VIR_SET_MEM_PARAMETER(virCgroupSetMemoryHardLimit, hard_limit);
858 859 860 861
        /* inhibit changing the limit a second time */
        set_hard_limit = false;
    }

862
    VIR_SET_MEM_PARAMETER(virCgroupSetMemSwapHardLimit, swap_hard_limit);
863 864

    /* otherwise increase it after swap hard limit */
865 866 867
    VIR_SET_MEM_PARAMETER(virCgroupSetMemoryHardLimit, hard_limit);

#undef VIR_SET_MEM_PARAMETER
868

869 870 871
    if (def &&
        virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
        goto endjob;
872

873
    if (persistentDef &&
J
Ján Tomko 已提交
874
        virDomainSaveConfig(cfg->configDir, driver->caps, persistentDef) < 0)
875
        goto endjob;
876
    /* QEMU and LXC implementations are identical */
877 878

    ret = 0;
879 880

 endjob:
881
    virLXCDomainObjEndJob(driver, vm);
882

883
 cleanup:
884
    virDomainObjEndAPI(&vm);
885
    virObjectUnref(cfg);
886 887 888
    return ret;
}

889 890 891 892 893
static int
lxcDomainGetMemoryParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int *nparams,
                             unsigned int flags)
894
{
J
Ján Tomko 已提交
895
    virDomainDefPtr persistentDef = NULL;
896
    virDomainDefPtr def = NULL;
897
    virDomainObjPtr vm = NULL;
898
    virLXCDomainObjPrivatePtr priv = NULL;
899
    unsigned long long val;
900
    int ret = -1;
901
    size_t i;
902

903
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
904 905 906 907 908
                  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 已提交
909

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

913
    priv = vm->privateData;
914

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

918 919 920 921
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
        goto cleanup;

    if (def &&
922 923 924
        !virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_MEMORY)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup memory controller is not mounted"));
925
        goto cleanup;
926
    }
927

928 929 930 931 932 933 934
    if ((*nparams) == 0) {
        /* Current number of memory parameters supported by cgroups */
        *nparams = LXC_NB_MEM_PARAM;
        ret = 0;
        goto cleanup;
    }

935
    for (i = 0; i < LXC_NB_MEM_PARAM && i < *nparams; i++) {
936
        virTypedParameterPtr param = &params[i];
937 938
        val = 0;

939
        switch (i) {
940
        case 0: /* fill memory hard limit here */
941
            if (persistentDef) {
J
Ján Tomko 已提交
942
                val = persistentDef->mem.hard_limit;
943
            } else if (virCgroupGetMemoryHardLimit(priv->cgroup, &val) < 0) {
944
                goto cleanup;
945
            }
946 947
            if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_HARD_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
948
                goto cleanup;
949 950
            break;
        case 1: /* fill memory soft limit here */
951
            if (persistentDef) {
J
Ján Tomko 已提交
952
                val = persistentDef->mem.soft_limit;
953
            } else if (virCgroupGetMemorySoftLimit(priv->cgroup, &val) < 0) {
954
                goto cleanup;
955
            }
956 957
            if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_SOFT_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
958
                goto cleanup;
959 960
            break;
        case 2: /* fill swap hard limit here */
961
            if (persistentDef) {
J
Ján Tomko 已提交
962
                val = persistentDef->mem.swap_hard_limit;
963
            } else if (virCgroupGetMemSwapHardLimit(priv->cgroup, &val) < 0) {
964
                goto cleanup;
965
            }
966 967 968
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
969
                goto cleanup;
970 971 972 973
            break;
        }
    }

974 975
    if (*nparams > LXC_NB_MEM_PARAM)
        *nparams = LXC_NB_MEM_PARAM;
976 977
    ret = 0;

978
 cleanup:
979
    virDomainObjEndAPI(&vm);
980 981 982
    return ret;
}

983
static char *lxcDomainGetXMLDesc(virDomainPtr dom,
984
                                 unsigned int flags)
D
Daniel Veillard 已提交
985
{
986
    virLXCDriverPtr driver = dom->conn->privateData;
987 988
    virDomainObjPtr vm;
    char *ret = NULL;
D
Daniel Veillard 已提交
989

990
    virCheckFlags(VIR_DOMAIN_XML_COMMON_FLAGS, NULL);
991

M
Michal Privoznik 已提交
992
    if (!(vm = lxcDomObjFromDomain(dom)))
993
        goto cleanup;
D
Daniel Veillard 已提交
994

995 996 997
    if (virDomainGetXMLDescEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

998
    ret = virDomainDefFormat((flags & VIR_DOMAIN_XML_INACTIVE) &&
999
                             vm->newDef ? vm->newDef : vm->def,
1000
                             driver->caps,
1001
                             virDomainDefFormatConvertXMLFlags(flags));
1002

1003
 cleanup:
1004
    virDomainObjEndAPI(&vm);
1005
    return ret;
D
Daniel Veillard 已提交
1006 1007
}

1008 1009 1010 1011 1012 1013 1014
static char *lxcConnectDomainXMLFromNative(virConnectPtr conn,
                                           const char *nativeFormat,
                                           const char *nativeConfig,
                                           unsigned int flags)
{
    char *xml = NULL;
    virDomainDefPtr def = NULL;
1015 1016
    virLXCDriverPtr driver = conn->privateData;
    virCapsPtr caps = virLXCDriverGetCapabilities(driver, false);
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028

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

1029
    if (!(def = lxcParseConfigString(nativeConfig, caps, driver->xmlopt)))
1030 1031
        goto cleanup;

1032
    xml = virDomainDefFormat(def, caps, 0);
1033

1034
 cleanup:
1035
    virObjectUnref(caps);
1036 1037 1038 1039
    virDomainDefFree(def);
    return xml;
}

1040
/**
1041
 * lxcDomainCreateWithFiles:
1042
 * @dom: domain to start
1043
 * @flags: Must be 0 for now
1044 1045 1046 1047 1048
 *
 * Looks up domain and starts it.
 *
 * Returns 0 on success or -1 in case of error
 */
1049 1050 1051 1052
static int lxcDomainCreateWithFiles(virDomainPtr dom,
                                    unsigned int nfiles,
                                    int *files,
                                    unsigned int flags)
1053
{
1054
    virLXCDriverPtr driver = dom->conn->privateData;
1055
    virDomainObjPtr vm;
1056
    virObjectEventPtr event = NULL;
1057
    int ret = -1;
1058
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
1059

1060
    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, -1);
1061

1062 1063
    virNWFilterReadLockFilterUpdates();

M
Michal Privoznik 已提交
1064
    if (!(vm = lxcDomObjFromDomain(dom)))
1065 1066
        goto cleanup;

1067
    if (virDomainCreateWithFilesEnsureACL(dom->conn, vm->def) < 0)
1068 1069
        goto cleanup;

1070
    if ((vm->def->nets != NULL) && !(cfg->have_netns)) {
1071 1072
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("System lacks NETNS support"));
1073 1074 1075
        goto cleanup;
    }

1076 1077 1078
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

1079
    if (virDomainObjIsActive(vm)) {
1080 1081
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is already running"));
1082
        goto endjob;
1083 1084
    }

1085
    ret = virLXCProcessStart(dom->conn, driver, vm,
1086
                             nfiles, files,
1087 1088
                             (flags & VIR_DOMAIN_START_AUTODESTROY),
                             VIR_DOMAIN_RUNNING_BOOTED);
1089

1090
    if (ret == 0) {
1091
        event = virDomainEventLifecycleNewFromObj(vm,
1092 1093
                                         VIR_DOMAIN_EVENT_STARTED,
                                         VIR_DOMAIN_EVENT_STARTED_BOOTED);
1094 1095 1096 1097
        virDomainAuditStart(vm, "booted", true);
    } else {
        virDomainAuditStart(vm, "booted", false);
    }
1098

1099
 endjob:
1100
    virLXCDomainObjEndJob(driver, vm);
1101

1102
 cleanup:
1103
    virDomainObjEndAPI(&vm);
1104
    virObjectEventStateQueue(driver->domainEventState, event);
1105
    virObjectUnref(cfg);
1106
    virNWFilterUnlockFilterUpdates();
1107
    return ret;
1108 1109
}

1110
/**
1111
 * lxcDomainCreate:
1112 1113 1114 1115 1116 1117
 * @dom: domain to start
 *
 * Looks up domain and starts it.
 *
 * Returns 0 on success or -1 in case of error
 */
1118
static int lxcDomainCreate(virDomainPtr dom)
1119
{
1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134
    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);
1135 1136
}

1137
/**
1138
 * lxcDomainCreateXMLWithFiles:
1139 1140
 * @conn: pointer to connection
 * @xml: XML definition of domain
1141 1142 1143
 * @nfiles: number of file descriptors passed
 * @files: list of file descriptors passed
 * @flags: bitwise-OR of supported virDomainCreateFlags
1144 1145 1146
 *
 * Creates a domain based on xml and starts it
 *
1147
 * Returns a new domain object or NULL in case of failure.
1148 1149
 */
static virDomainPtr
1150 1151 1152 1153
lxcDomainCreateXMLWithFiles(virConnectPtr conn,
                            const char *xml,
                            unsigned int nfiles,
                            int *files,
1154 1155
                            unsigned int flags)
{
1156
    virLXCDriverPtr driver = conn->privateData;
1157
    virDomainObjPtr vm = NULL;
1158
    virDomainDefPtr def = NULL;
1159
    virDomainPtr dom = NULL;
1160
    virObjectEventPtr event = NULL;
1161
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
1162
    virCapsPtr caps = NULL;
1163 1164 1165 1166 1167
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;

    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY |
                  VIR_DOMAIN_START_VALIDATE, NULL);

1168

1169
    if (flags & VIR_DOMAIN_START_VALIDATE)
1170
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
1171

1172 1173
    virNWFilterReadLockFilterUpdates();

1174 1175 1176 1177
    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
        goto cleanup;

    if (!(def = virDomainDefParseString(xml, caps, driver->xmlopt,
1178
                                        NULL, parse_flags)))
1179
        goto cleanup;
1180

1181
    if (virDomainCreateXMLWithFilesEnsureACL(conn, def) < 0)
1182 1183
        goto cleanup;

1184 1185 1186
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
        goto cleanup;

1187
    if ((def->nets != NULL) && !(cfg->have_netns)) {
1188 1189
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       "%s", _("System lacks NETNS support"));
1190
        goto cleanup;
1191 1192
    }

1193

1194
    if (!(vm = virDomainObjListAdd(driver->domains, def,
1195
                                   driver->xmlopt,
1196
                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
1197 1198
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
1199 1200
        goto cleanup;
    def = NULL;
1201

1202
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0) {
1203
        if (!vm->persistent)
1204 1205 1206 1207
            virDomainObjListRemove(driver->domains, vm);
        goto cleanup;
    }

1208
    if (virLXCProcessStart(conn, driver, vm,
1209
                           nfiles, files,
1210 1211
                           (flags & VIR_DOMAIN_START_AUTODESTROY),
                           VIR_DOMAIN_RUNNING_BOOTED) < 0) {
1212
        virDomainAuditStart(vm, "booted", false);
1213
        virLXCDomainObjEndJob(driver, vm);
1214
        if (!vm->persistent)
1215
            virDomainObjListRemove(driver->domains, vm);
1216
        goto cleanup;
1217 1218
    }

1219
    event = virDomainEventLifecycleNewFromObj(vm,
1220 1221
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
1222
    virDomainAuditStart(vm, "booted", true);
1223

1224
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
1225

1226
    virLXCDomainObjEndJob(driver, vm);
1227

1228
 cleanup:
1229
    virDomainDefFree(def);
1230
    virDomainObjEndAPI(&vm);
1231
    virObjectEventStateQueue(driver->domainEventState, event);
1232
    virObjectUnref(caps);
1233
    virObjectUnref(cfg);
1234
    virNWFilterUnlockFilterUpdates();
1235 1236 1237
    return dom;
}

1238 1239 1240 1241 1242 1243 1244 1245 1246 1247
/**
 * 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.
 */
1248 1249 1250
static virDomainPtr
lxcDomainCreateXML(virConnectPtr conn,
                   const char *xml,
1251 1252
                   unsigned int flags)
{
1253 1254 1255 1256
    return lxcDomainCreateXMLWithFiles(conn, xml, 0, NULL,  flags);
}


1257 1258
static int lxcDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr seclabel)
{
1259
    virLXCDriverPtr driver = dom->conn->privateData;
1260 1261 1262 1263 1264
    virDomainObjPtr vm;
    int ret = -1;

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

M
Michal Privoznik 已提交
1265
    if (!(vm = lxcDomObjFromDomain(dom)))
1266 1267
        goto cleanup;

1268 1269 1270
    if (virDomainGetSecurityLabelEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1271
    if (!virDomainVirtTypeToString(vm->def->virtType)) {
1272 1273 1274
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown virt type in domain definition '%d'"),
                       vm->def->virtType);
1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292
        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)) {
1293 1294 1295 1296 1297 1298 1299 1300
        virLXCDomainObjPrivatePtr priv = vm->privateData;

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

1301
        if (virSecurityManagerGetProcessLabel(driver->securityManager,
1302 1303
                                              vm->def, priv->initpid,
                                              seclabel) < 0)
1304 1305 1306 1307 1308
            goto cleanup;
    }

    ret = 0;

1309
 cleanup:
1310
    virDomainObjEndAPI(&vm);
1311 1312 1313 1314 1315 1316
    return ret;
}

static int lxcNodeGetSecurityModel(virConnectPtr conn,
                                   virSecurityModelPtr secmodel)
{
1317
    virLXCDriverPtr driver = conn->privateData;
1318
    virCapsPtr caps = NULL;
1319 1320 1321 1322
    int ret = 0;

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

1323 1324 1325
    if (virNodeGetSecurityModelEnsureACL(conn) < 0)
        goto cleanup;

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

1329
    /* we treat no driver as success, but simply return no data in *secmodel */
1330 1331
    if (caps->host.nsecModels == 0
        || caps->host.secModels[0].model == NULL)
1332 1333
        goto cleanup;

1334 1335
    if (virStrcpy(secmodel->model, caps->host.secModels[0].model,
                  VIR_SECURITY_MODEL_BUFLEN) < 0) {
1336 1337 1338
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security model string exceeds max %d bytes"),
                       VIR_SECURITY_MODEL_BUFLEN - 1);
1339 1340 1341 1342
        ret = -1;
        goto cleanup;
    }

1343 1344
    if (virStrcpy(secmodel->doi, caps->host.secModels[0].doi,
                  VIR_SECURITY_DOI_BUFLEN) < 0) {
1345 1346 1347
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security DOI string exceeds max %d bytes"),
                       VIR_SECURITY_DOI_BUFLEN-1);
1348 1349 1350 1351
        ret = -1;
        goto cleanup;
    }

1352
 cleanup:
1353
    virObjectUnref(caps);
1354 1355 1356 1357
    return ret;
}


1358
static int
1359 1360 1361 1362
lxcConnectDomainEventRegister(virConnectPtr conn,
                              virConnectDomainEventCallback callback,
                              void *opaque,
                              virFreeCallback freecb)
1363
{
1364
    virLXCDriverPtr driver = conn->privateData;
1365

1366 1367 1368
    if (virConnectDomainEventRegisterEnsureACL(conn) < 0)
        return -1;

1369 1370 1371 1372
    if (virDomainEventStateRegister(conn,
                                    driver->domainEventState,
                                    callback, opaque, freecb) < 0)
        return -1;
1373

1374
    return 0;
1375 1376
}

1377

1378
static int
1379 1380
lxcConnectDomainEventDeregister(virConnectPtr conn,
                                virConnectDomainEventCallback callback)
1381
{
1382
    virLXCDriverPtr driver = conn->privateData;
1383

1384 1385 1386
    if (virConnectDomainEventDeregisterEnsureACL(conn) < 0)
        return -1;

1387 1388 1389 1390
    if (virDomainEventStateDeregister(conn,
                                      driver->domainEventState,
                                      callback) < 0)
        return -1;
1391

1392
    return 0;
1393 1394
}

1395 1396

static int
1397 1398 1399 1400 1401 1402
lxcConnectDomainEventRegisterAny(virConnectPtr conn,
                                 virDomainPtr dom,
                                 int eventID,
                                 virConnectDomainEventGenericCallback callback,
                                 void *opaque,
                                 virFreeCallback freecb)
1403
{
1404
    virLXCDriverPtr driver = conn->privateData;
1405 1406
    int ret;

1407 1408 1409
    if (virConnectDomainEventRegisterAnyEnsureACL(conn) < 0)
        return -1;

1410 1411 1412 1413
    if (virDomainEventStateRegisterID(conn,
                                      driver->domainEventState,
                                      dom, eventID,
                                      callback, opaque, freecb, &ret) < 0)
1414
        ret = -1;
1415 1416 1417 1418 1419 1420

    return ret;
}


static int
1421 1422
lxcConnectDomainEventDeregisterAny(virConnectPtr conn,
                                   int callbackID)
1423
{
1424
    virLXCDriverPtr driver = conn->privateData;
1425

1426 1427 1428
    if (virConnectDomainEventDeregisterAnyEnsureACL(conn) < 0)
        return -1;

1429 1430
    if (virObjectEventStateDeregisterID(conn,
                                        driver->domainEventState,
1431
                                        callbackID, true) < 0)
1432
        return -1;
1433

1434
    return 0;
1435 1436 1437
}


1438
/**
1439
 * lxcDomainDestroyFlags:
1440
 * @dom: pointer to domain to destroy
1441
 * @flags: extra flags; not used yet.
1442 1443 1444 1445 1446
 *
 * Sends SIGKILL to container root process to terminate the container
 *
 * Returns 0 on success or -1 in case of error
 */
1447 1448 1449
static int
lxcDomainDestroyFlags(virDomainPtr dom,
                      unsigned int flags)
1450
{
1451
    virLXCDriverPtr driver = dom->conn->privateData;
1452
    virDomainObjPtr vm;
1453
    virObjectEventPtr event = NULL;
1454
    int ret = -1;
1455
    virLXCDomainObjPrivatePtr priv;
1456

1457 1458
    virCheckFlags(0, -1);

M
Michal Privoznik 已提交
1459
    if (!(vm = lxcDomObjFromDomain(dom)))
1460
        goto cleanup;
1461

1462 1463 1464
    if (virDomainDestroyFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1465
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_DESTROY) < 0)
1466 1467
        goto cleanup;

1468
    if (virDomainObjCheckActive(vm) < 0)
1469
        goto endjob;
1470

1471
    priv = vm->privateData;
1472
    ret = virLXCProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED);
1473
    event = virDomainEventLifecycleNewFromObj(vm,
1474 1475
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
1476
    priv->doneStopEvent = true;
1477
    virDomainAuditStop(vm, "destroyed");
1478

1479
 endjob:
1480
    virLXCDomainObjEndJob(driver, vm);
1481
    if (!vm->persistent)
1482
        virDomainObjListRemove(driver->domains, vm);
1483

1484
 cleanup:
1485
    virDomainObjEndAPI(&vm);
1486
    virObjectEventStateQueue(driver->domainEventState, event);
1487
    return ret;
1488
}
1489

1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503
/**
 * 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);
}

1504 1505 1506 1507 1508
static int lxcCheckNetNsSupport(void)
{
    const char *argv[] = {"ip", "link", "set", "lo", "netns", "-1", NULL};
    int ip_rc;

1509
    if (virRun(argv, &ip_rc) < 0 || ip_rc == 255)
1510
        return 0;
1511

1512
    if (virProcessNamespaceAvailable(VIR_PROCESS_NAMESPACE_NET) < 0)
1513
        return 0;
1514

1515
    return 1;
1516 1517
}

1518

1519 1520
static virSecurityManagerPtr
lxcSecurityInit(virLXCDriverConfigPtr cfg)
1521
{
1522 1523
    unsigned int flags = VIR_SECURITY_MANAGER_PRIVILEGED;

1524
    VIR_INFO("lxcSecurityInit %s", cfg->securityDriverName);
1525 1526 1527 1528 1529 1530

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

1531
    virSecurityManagerPtr mgr = virSecurityManagerNew(cfg->securityDriverName,
1532
                                                      LXC_DRIVER_NAME, flags);
1533 1534 1535
    if (!mgr)
        goto error;

1536
    return mgr;
1537

1538
 error:
1539
    VIR_ERROR(_("Failed to initialize security drivers"));
1540
    virObjectUnref(mgr);
1541
    return NULL;
1542 1543 1544
}


1545 1546 1547
static int lxcStateInitialize(bool privileged,
                              virStateInhibitCallback callback ATTRIBUTE_UNUSED,
                              void *opaque ATTRIBUTE_UNUSED)
D
Daniel Veillard 已提交
1548
{
1549
    virCapsPtr caps = NULL;
1550
    virLXCDriverConfigPtr cfg = NULL;
1551

1552
    /* Check that the user is root, silently disable if not */
1553
    if (!privileged) {
1554
        VIR_INFO("Not running privileged, disabling driver");
1555 1556 1557 1558
        return 0;
    }

    /* Check that this is a container enabled kernel */
1559 1560 1561 1562
    if (virProcessNamespaceAvailable(VIR_PROCESS_NAMESPACE_MNT |
                                     VIR_PROCESS_NAMESPACE_PID |
                                     VIR_PROCESS_NAMESPACE_UTS |
                                     VIR_PROCESS_NAMESPACE_IPC) < 0) {
1563
        VIR_INFO("LXC support not available in this kernel, disabling driver");
1564
        return 0;
1565 1566
    }

1567
    if (VIR_ALLOC(lxc_driver) < 0)
1568
        return -1;
1569 1570 1571 1572
    if (virMutexInit(&lxc_driver->lock) < 0) {
        VIR_FREE(lxc_driver);
        return -1;
    }
D
Daniel Veillard 已提交
1573

1574
    if (!(lxc_driver->domains = virDomainObjListNew()))
1575 1576
        goto cleanup;

1577
    lxc_driver->domainEventState = virObjectEventStateNew();
1578
    if (!lxc_driver->domainEventState)
1579 1580
        goto cleanup;

1581 1582
    lxc_driver->hostsysinfo = virSysinfoRead();

1583 1584 1585 1586 1587
    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 已提交
1588 1589

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

1593
    if (!(lxc_driver->securityManager = lxcSecurityInit(cfg)))
1594 1595
        goto cleanup;

1596
    if (!(lxc_driver->hostdevMgr = virHostdevManagerGetDefault()))
G
Guido Günther 已提交
1597 1598
        goto cleanup;

1599
    if (!(caps = virLXCDriverGetCapabilities(lxc_driver, true)))
1600
        goto cleanup;
D
Daniel Veillard 已提交
1601

1602
    if (!(lxc_driver->xmlopt = lxcDomainXMLConfInit()))
1603
        goto cleanup;
1604

1605
    if (!(lxc_driver->closeCallbacks = virCloseCallbacksNew()))
1606 1607
        goto cleanup;

1608 1609 1610 1611 1612 1613 1614
    if (virFileMakePath(cfg->stateDir) < 0) {
        virReportSystemError(errno,
                             _("Failed to mkdir %s"),
                             cfg->stateDir);
        goto cleanup;
    }

O
Osier Yang 已提交
1615
    /* Get all the running persistent or transient configs first */
1616
    if (virDomainObjListLoadAllConfigs(lxc_driver->domains,
1617
                                       cfg->stateDir,
1618
                                       NULL, true,
1619
                                       caps,
1620
                                       lxc_driver->xmlopt,
1621
                                       NULL, NULL) < 0)
O
Osier Yang 已提交
1622 1623
        goto cleanup;

1624
    virLXCProcessReconnectAll(lxc_driver, lxc_driver->domains);
O
Osier Yang 已提交
1625 1626

    /* Then inactive persistent configs */
1627
    if (virDomainObjListLoadAllConfigs(lxc_driver->domains,
1628
                                       cfg->configDir,
1629
                                       cfg->autostartDir, false,
1630
                                       caps,
1631
                                       lxc_driver->xmlopt,
1632
                                       NULL, NULL) < 0)
1633
        goto cleanup;
1634

1635 1636
    virLXCProcessAutostartAll(lxc_driver);

1637
    virObjectUnref(caps);
D
Daniel Veillard 已提交
1638 1639
    return 0;

1640
 cleanup:
1641
    virObjectUnref(caps);
1642
    lxcStateCleanup();
1643
    return -1;
D
Daniel Veillard 已提交
1644 1645
}

1646 1647
static void lxcNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
{
1648
    virLXCDriverPtr driver = opaque;
1649 1650

    if (newVM) {
1651
        virObjectEventPtr event =
1652
            virDomainEventLifecycleNewFromObj(vm,
1653 1654
                                     VIR_DOMAIN_EVENT_DEFINED,
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED);
1655
        virObjectEventStateQueue(driver->domainEventState, event);
1656 1657 1658 1659
    }
}

/**
1660
 * lxcStateReload:
1661 1662 1663 1664 1665
 *
 * Function to restart the LXC driver, it will recheck the configuration
 * files and perform autostart
 */
static int
1666 1667
lxcStateReload(void)
{
1668
    virLXCDriverConfigPtr cfg = NULL;
1669
    virCapsPtr caps = NULL;
1670

1671 1672 1673
    if (!lxc_driver)
        return 0;

1674
    if (!(caps = virLXCDriverGetCapabilities(lxc_driver, false)))
1675 1676
        return -1;

1677 1678
    cfg = virLXCDriverGetConfig(lxc_driver);

1679
    virDomainObjListLoadAllConfigs(lxc_driver->domains,
1680
                                   cfg->configDir,
1681
                                   cfg->autostartDir, false,
1682
                                   caps,
1683
                                   lxc_driver->xmlopt,
1684
                                   lxcNotifyLoadDomain, lxc_driver);
1685
    virObjectUnref(caps);
1686
    virObjectUnref(cfg);
1687 1688 1689
    return 0;
}

1690
static int lxcStateCleanup(void)
D
Daniel Veillard 已提交
1691
{
1692
    if (lxc_driver == NULL)
1693
        return -1;
1694

1695
    virObjectUnref(lxc_driver->domains);
1696
    virObjectUnref(lxc_driver->domainEventState);
1697

1698
    virObjectUnref(lxc_driver->closeCallbacks);
1699

1700 1701
    virSysinfoDefFree(lxc_driver->hostsysinfo);

1702
    virObjectUnref(lxc_driver->hostdevMgr);
1703
    virObjectUnref(lxc_driver->caps);
1704
    virObjectUnref(lxc_driver->securityManager);
1705
    virObjectUnref(lxc_driver->xmlopt);
1706
    virObjectUnref(lxc_driver->config);
1707
    virMutexDestroy(&lxc_driver->lock);
1708
    VIR_FREE(lxc_driver);
1709 1710 1711

    return 0;
}
D
Daniel Veillard 已提交
1712

1713 1714 1715 1716 1717 1718
static int
lxcConnectSupportsFeature(virConnectPtr conn, int feature)
{
    if (virConnectSupportsFeatureEnsureACL(conn) < 0)
        return -1;

1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737
    switch ((virDrvFeature) feature) {
    case VIR_DRV_FEATURE_TYPED_PARAM_STRING:
        return 1;
    case VIR_DRV_FEATURE_FD_PASSING:
    case VIR_DRV_FEATURE_MIGRATE_CHANGE_PROTECTION:
    case VIR_DRV_FEATURE_MIGRATION_DIRECT:
    case VIR_DRV_FEATURE_MIGRATION_OFFLINE:
    case VIR_DRV_FEATURE_MIGRATION_P2P:
    case VIR_DRV_FEATURE_MIGRATION_PARAMS:
    case VIR_DRV_FEATURE_MIGRATION_V1:
    case VIR_DRV_FEATURE_MIGRATION_V2:
    case VIR_DRV_FEATURE_MIGRATION_V3:
    case VIR_DRV_FEATURE_PROGRAM_KEEPALIVE:
    case VIR_DRV_FEATURE_REMOTE:
    case VIR_DRV_FEATURE_REMOTE_CLOSE_CALLBACK:
    case VIR_DRV_FEATURE_REMOTE_EVENT_CALLBACK:
    case VIR_DRV_FEATURE_XML_MIGRATABLE:
    default:
        return 0;
1738 1739 1740
    }
}

D
Daniel Veillard 已提交
1741

1742
static int lxcConnectGetVersion(virConnectPtr conn, unsigned long *version)
D
Dan Smith 已提交
1743 1744 1745
{
    struct utsname ver;

1746
    uname(&ver);
D
Dan Smith 已提交
1747

1748 1749 1750
    if (virConnectGetVersionEnsureACL(conn) < 0)
        return -1;

1751
    if (virParseVersionString(ver.release, version, true) < 0) {
1752
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Unknown release: %s"), ver.release);
D
Dan Smith 已提交
1753 1754 1755 1756 1757
        return -1;
    }

    return 0;
}
1758

1759

1760
static char *lxcConnectGetHostname(virConnectPtr conn)
1761
{
1762 1763 1764
    if (virConnectGetHostnameEnsureACL(conn) < 0)
        return NULL;

1765 1766 1767 1768
    return virGetHostname();
}


1769 1770
static char *lxcDomainGetSchedulerType(virDomainPtr dom,
                                       int *nparams)
1771
{
1772
    char *ret = NULL;
1773 1774
    virDomainObjPtr vm;
    virLXCDomainObjPrivatePtr priv;
1775

M
Michal Privoznik 已提交
1776
    if (!(vm = lxcDomObjFromDomain(dom)))
1777
        goto cleanup;
M
Michal Privoznik 已提交
1778

1779 1780
    priv = vm->privateData;

1781 1782 1783
    if (virDomainGetSchedulerTypeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1784 1785 1786 1787 1788 1789 1790 1791
    /* Domain not running, thus no cgroups - return defaults */
    if (!virDomainObjIsActive(vm)) {
        if (nparams)
            *nparams = 3;
        ignore_value(VIR_STRDUP(ret, "posix"));
        goto cleanup;
    }

1792
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
1793 1794
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPU controller is not mounted"));
1795 1796
        goto cleanup;
    }
1797

1798
    if (nparams) {
1799
        if (virCgroupSupportsCpuBW(priv->cgroup))
1800
            *nparams = 3;
1801 1802
        else
            *nparams = 1;
1803
    }
1804

1805
    ignore_value(VIR_STRDUP(ret, "posix"));
1806

1807
 cleanup:
1808
    virDomainObjEndAPI(&vm);
1809 1810 1811 1812 1813 1814 1815 1816
    return ret;
}


static int
lxcGetVcpuBWLive(virCgroupPtr cgroup, unsigned long long *period,
                 long long *quota)
{
1817
    if (virCgroupGetCpuCfsPeriod(cgroup, period) < 0)
1818 1819
        return -1;

1820
    if (virCgroupGetCpuCfsQuota(cgroup, quota) < 0)
1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836
        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 */
1837
        if (virCgroupGetCpuCfsPeriod(cgroup, &old_period) < 0)
1838 1839
            return -1;

1840
        if (virCgroupSetCpuCfsPeriod(cgroup, period) < 0)
1841 1842 1843 1844
            return -1;
    }

    if (quota) {
1845 1846
        if (virCgroupSetCpuCfsQuota(cgroup, quota) < 0)
            goto error;
1847 1848 1849 1850
    }

    return 0;

1851
 error:
1852
    if (period) {
1853 1854 1855 1856 1857 1858
        virErrorPtr saved = virSaveLastError();
        virCgroupSetCpuCfsPeriod(cgroup, old_period);
        if (saved) {
            virSetError(saved);
            virFreeError(saved);
        }
1859 1860 1861
    }

    return -1;
1862 1863
}

1864

1865
static int
1866 1867 1868 1869
lxcDomainSetSchedulerParametersFlags(virDomainPtr dom,
                                     virTypedParameterPtr params,
                                     int nparams,
                                     unsigned int flags)
1870
{
1871
    virLXCDriverPtr driver = dom->conn->privateData;
1872
    virCapsPtr caps = NULL;
1873
    size_t i;
1874
    virDomainObjPtr vm = NULL;
1875
    virDomainDefPtr def = NULL;
J
Ján Tomko 已提交
1876 1877
    virDomainDefPtr persistentDefCopy = NULL;
    virDomainDefPtr persistentDef = NULL;
1878
    int ret = -1;
1879
    int rc;
1880
    virLXCDomainObjPrivatePtr priv;
1881
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
1882

1883 1884
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
1885 1886 1887 1888 1889 1890 1891 1892
    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)
1893
        return -1;
1894

M
Michal Privoznik 已提交
1895
    if (!(vm = lxcDomObjFromDomain(dom)))
1896
        goto cleanup;
M
Michal Privoznik 已提交
1897

1898
    priv = vm->privateData;
1899

1900 1901 1902
    if (virDomainSetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

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

1906 1907 1908
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

1909
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
1910
        goto endjob;
1911

1912
    if (persistentDef) {
1913
        /* Make a copy for updated domain. */
J
Ján Tomko 已提交
1914 1915
        persistentDefCopy = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt);
        if (!persistentDefCopy)
1916
            goto endjob;
1917 1918
    }

1919
    if (def) {
1920
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
1921 1922
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup CPU controller is not mounted"));
1923
            goto endjob;
1924 1925
        }
    }
1926 1927

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

1930
        if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_CPU_SHARES)) {
1931
            if (def) {
1932
                unsigned long long val;
1933
                if (virCgroupSetCpuShares(priv->cgroup, params[i].value.ul) < 0)
1934
                    goto endjob;
1935

1936
                if (virCgroupGetCpuShares(priv->cgroup, &val) < 0)
1937
                    goto endjob;
1938

1939 1940
                def->cputune.shares = val;
                def->cputune.sharesSpecified = true;
1941 1942
            }

1943
            if (persistentDef) {
J
Ján Tomko 已提交
1944 1945
                persistentDefCopy->cputune.shares = params[i].value.ul;
                persistentDefCopy->cputune.sharesSpecified = true;
1946 1947
            }
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_PERIOD)) {
1948
            if (def) {
1949
                rc = lxcSetVcpuBWLive(priv->cgroup, params[i].value.ul, 0);
1950
                if (rc != 0)
1951
                    goto endjob;
1952 1953

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

1957
            if (persistentDef)
J
Ján Tomko 已提交
1958
                persistentDefCopy->cputune.period = params[i].value.ul;
1959
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_QUOTA)) {
1960
            if (def) {
1961
                rc = lxcSetVcpuBWLive(priv->cgroup, 0, params[i].value.l);
1962
                if (rc != 0)
1963
                    goto endjob;
1964 1965

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

1969
            if (persistentDef)
J
Ján Tomko 已提交
1970
                persistentDefCopy->cputune.quota = params[i].value.l;
1971
        }
1972
    }
1973

1974
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
1975
        goto endjob;
1976

1977

1978
    if (persistentDef) {
J
Ján Tomko 已提交
1979
        rc = virDomainSaveConfig(cfg->configDir, driver->caps, persistentDefCopy);
1980
        if (rc < 0)
1981
            goto endjob;
1982

J
Ján Tomko 已提交
1983 1984
        virDomainObjAssignDef(vm, persistentDefCopy, false, NULL);
        persistentDefCopy = NULL;
1985
    }
1986

1987
    ret = 0;
1988

1989
 endjob:
1990
    virLXCDomainObjEndJob(driver, vm);
1991

1992
 cleanup:
J
Ján Tomko 已提交
1993
    virDomainDefFree(persistentDefCopy);
1994
    virDomainObjEndAPI(&vm);
1995
    virObjectUnref(caps);
1996
    virObjectUnref(cfg);
1997
    return ret;
1998 1999
}

2000
static int
2001 2002 2003
lxcDomainSetSchedulerParameters(virDomainPtr domain,
                                virTypedParameterPtr params,
                                int nparams)
2004
{
2005
    return lxcDomainSetSchedulerParametersFlags(domain, params, nparams, 0);
2006 2007 2008
}

static int
2009 2010 2011 2012
lxcDomainGetSchedulerParametersFlags(virDomainPtr dom,
                                     virTypedParameterPtr params,
                                     int *nparams,
                                     unsigned int flags)
2013
{
2014
    virDomainObjPtr vm = NULL;
2015
    virDomainDefPtr def;
E
Eric Blake 已提交
2016
    virDomainDefPtr persistentDef;
2017 2018 2019
    unsigned long long shares = 0;
    unsigned long long period = 0;
    long long quota = 0;
2020
    int ret = -1;
2021 2022 2023
    int rc;
    bool cpu_bw_status = false;
    int saved_nparams = 0;
2024
    virLXCDomainObjPrivatePtr priv;
2025

2026
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
2027 2028 2029 2030 2031
                  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;
2032

M
Michal Privoznik 已提交
2033
    if (!(vm = lxcDomObjFromDomain(dom)))
2034
        goto cleanup;
M
Michal Privoznik 已提交
2035

2036 2037
    priv = vm->privateData;

2038 2039 2040
    if (virDomainGetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2041 2042
    if (*nparams > 1)
        cpu_bw_status = virCgroupSupportsCpuBW(priv->cgroup);
2043

2044
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
E
Eric Blake 已提交
2045
        goto cleanup;
2046

2047
    if (persistentDef) {
E
Eric Blake 已提交
2048
        shares = persistentDef->cputune.shares;
2049
        if (*nparams > 1) {
E
Eric Blake 已提交
2050 2051
            period = persistentDef->cputune.period;
            quota = persistentDef->cputune.quota;
2052
            cpu_bw_status = true; /* Allow copy of data to params[] */
2053 2054 2055 2056
        }
        goto out;
    }

2057
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
2058 2059
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPU controller is not mounted"));
2060
        goto cleanup;
2061 2062
    }

2063
    if (virCgroupGetCpuShares(priv->cgroup, &shares) < 0)
2064
        goto cleanup;
2065 2066

    if (*nparams > 1 && cpu_bw_status) {
2067
        rc = lxcGetVcpuBWLive(priv->cgroup, &period, &quota);
2068 2069 2070
        if (rc != 0)
            goto cleanup;
    }
2071
 out:
2072 2073
    if (virTypedParameterAssign(&params[0], VIR_DOMAIN_SCHEDULER_CPU_SHARES,
                                VIR_TYPED_PARAM_ULLONG, shares) < 0)
C
Chris Lalancette 已提交
2074
        goto cleanup;
2075 2076 2077 2078
    saved_nparams++;

    if (cpu_bw_status) {
        if (*nparams > saved_nparams) {
2079 2080 2081
            if (virTypedParameterAssign(&params[1],
                                        VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
                                        VIR_TYPED_PARAM_ULLONG, period) < 0)
2082 2083 2084 2085 2086
                goto cleanup;
            saved_nparams++;
        }

        if (*nparams > saved_nparams) {
2087 2088 2089
            if (virTypedParameterAssign(&params[2],
                                        VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
                                        VIR_TYPED_PARAM_LLONG, quota) < 0)
2090 2091 2092 2093 2094 2095 2096
                goto cleanup;
            saved_nparams++;
        }
    }

    *nparams = saved_nparams;

2097
    ret = 0;
2098

2099
 cleanup:
2100
    virDomainObjEndAPI(&vm);
2101
    return ret;
2102 2103
}

2104
static int
2105 2106 2107
lxcDomainGetSchedulerParameters(virDomainPtr domain,
                                virTypedParameterPtr params,
                                int *nparams)
2108
{
2109
    return lxcDomainGetSchedulerParametersFlags(domain, params, nparams, 0);
2110 2111
}

2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139
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))
2140
        goto parse_error;
2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154

    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)
2155
            goto parse_error;
2156 2157 2158 2159 2160 2161 2162 2163

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

        /* value */
        temp = p + 1;

        if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
2164
            if (virStrToLong_uip(temp, &p, 10, &result[i].weight) < 0)
2165
                goto number_error;
2166
        } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS)) {
2167
            if (virStrToLong_uip(temp, &p, 10, &result[i].riops) < 0)
2168
                goto number_error;
2169
        } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS)) {
2170
            if (virStrToLong_uip(temp, &p, 10, &result[i].wiops) < 0)
2171
                goto number_error;
2172
        } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS)) {
2173
            if (virStrToLong_ullp(temp, &p, 10, &result[i].rbps) < 0)
2174
                goto number_error;
2175
        } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
2176
            if (virStrToLong_ullp(temp, &p, 10, &result[i].wbps) < 0)
2177
                goto number_error;
2178
        } else {
2179 2180 2181
            virReportError(VIR_ERR_INVALID_ARG,
                           _("unknown parameter '%s'"), type);
            goto cleanup;
2182 2183 2184 2185 2186 2187 2188
        }

        i++;

        if (*p == '\0')
            break;
        else if (*p != ',')
2189
            goto parse_error;
2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200
        temp = p + 1;
    }

    if (!i)
        VIR_FREE(result);

    *dev = result;
    *size = i;

    return 0;

2201
 parse_error:
2202 2203 2204
    virReportError(VIR_ERR_INVALID_ARG,
                   _("unable to parse blkio device '%s' '%s'"),
                   type, blkioDeviceStr);
2205 2206 2207 2208 2209 2210 2211
    goto cleanup;

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

2212
 cleanup:
J
John Ferlan 已提交
2213 2214 2215 2216
    if (result) {
        virBlkioDeviceArrayClear(result, ndevices);
        VIR_FREE(result);
    }
2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238
    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;

2239
                if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
2240
                    dest->weight = src->weight;
2241
                } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS)) {
2242
                    dest->riops = src->riops;
2243
                } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS)) {
2244
                    dest->wiops = src->wiops;
2245
                } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS)) {
2246
                    dest->rbps = src->rbps;
2247
                } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
2248
                    dest->wbps = src->wbps;
2249
                } else {
2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264
                    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];

2265
            if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
2266
                dest->weight = src->weight;
2267
            } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS)) {
2268
                dest->riops = src->riops;
2269
            } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS)) {
2270
                dest->wiops = src->wiops;
2271
            } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS)) {
2272
                dest->rbps = src->rbps;
2273
            } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
2274
                dest->wbps = src->wbps;
2275
            } else {
2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287
                *dest_size = *dest_size - 1;
                return -1;
            }

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

    return 0;
}

2288

2289 2290 2291
static int
lxcDomainBlockStats(virDomainPtr dom,
                    const char *path,
2292
                    virDomainBlockStatsPtr stats)
2293
{
2294
    virLXCDriverPtr driver = dom->conn->privateData;
2295
    int ret = -1;
2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307
    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;

2308 2309 2310
   if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_QUERY) < 0)
        goto cleanup;

2311
    if (virDomainObjCheckActive(vm) < 0)
2312
        goto endjob;
2313 2314 2315 2316

    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("blkio cgroup isn't mounted"));
2317
        goto endjob;
2318 2319 2320 2321 2322 2323 2324 2325 2326
    }

    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);
2327
        goto endjob;
2328 2329
    }

2330
    if (!(disk = virDomainDiskByName(vm->def, path, false))) {
2331 2332
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path: %s"), path);
2333
        goto endjob;
2334 2335 2336 2337 2338
    }

    if (!disk->info.alias) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("missing disk device alias name for %s"), disk->dst);
2339
        goto endjob;
2340 2341 2342 2343 2344 2345 2346 2347
    }

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

 endjob:
2350
    virLXCDomainObjEndJob(driver, vm);
2351

2352
 cleanup:
2353
    virDomainObjEndAPI(&vm);
2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364
    return ret;
}


static int
lxcDomainBlockStatsFlags(virDomainPtr dom,
                         const char * path,
                         virTypedParameterPtr params,
                         int * nparams,
                         unsigned int flags)
{
2365
    virLXCDriverPtr driver = dom->conn->privateData;
2366
    int tmp, ret = -1;
2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377
    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;

2378
    if (!*nparams) {
2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390
        *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;

2391 2392 2393
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_QUERY) < 0)
        goto cleanup;

2394
    if (virDomainObjCheckActive(vm) < 0)
2395
        goto endjob;
2396 2397 2398 2399

    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("blkio cgroup isn't mounted"));
2400
        goto endjob;
2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411
    }

    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"));
2412
            goto endjob;
2413 2414
        }
    } else {
2415
        if (!(disk = virDomainDiskByName(vm->def, path, false))) {
2416 2417
            virReportError(VIR_ERR_INVALID_ARG,
                           _("invalid path: %s"), path);
2418
            goto endjob;
2419 2420 2421 2422 2423
        }

        if (!disk->info.alias) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("missing disk device alias name for %s"), disk->dst);
2424
            goto endjob;
2425 2426 2427 2428 2429 2430 2431 2432 2433 2434
        }

        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"));
2435
            goto endjob;
2436 2437 2438 2439 2440 2441 2442 2443 2444 2445
        }
    }

    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)
2446
            goto endjob;
2447 2448 2449 2450 2451 2452 2453
        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)
2454
            goto endjob;
2455 2456 2457 2458 2459 2460 2461
        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)
2462
            goto endjob;
2463 2464 2465 2466 2467 2468 2469
        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)
2470
            goto endjob;
2471 2472 2473 2474 2475 2476
        tmp++;
    }

    ret = 0;
    *nparams = tmp;

2477
 endjob:
2478
    virLXCDomainObjEndJob(driver, vm);
2479

2480
 cleanup:
2481
    virDomainObjEndAPI(&vm);
2482 2483 2484 2485
    return ret;
}


2486 2487 2488 2489 2490
static int
lxcDomainSetBlkioParameters(virDomainPtr dom,
                            virTypedParameterPtr params,
                            int nparams,
                            unsigned int flags)
2491
{
2492
    virLXCDriverPtr driver = dom->conn->privateData;
2493
    size_t i;
2494
    virDomainObjPtr vm = NULL;
2495
    virDomainDefPtr def = NULL;
2496 2497
    virDomainDefPtr persistentDef = NULL;
    int ret = -1;
2498
    virLXCDriverConfigPtr cfg = NULL;
2499
    virLXCDomainObjPrivatePtr priv;
2500 2501 2502

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
2503 2504 2505
    if (virTypedParamsValidate(params, nparams,
                               VIR_DOMAIN_BLKIO_WEIGHT,
                               VIR_TYPED_PARAM_UINT,
2506 2507 2508 2509 2510 2511 2512 2513 2514 2515
                               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,
2516
                               NULL) < 0)
2517 2518
        return -1;

M
Michal Privoznik 已提交
2519
    if (!(vm = lxcDomObjFromDomain(dom)))
2520
        return -1;
M
Michal Privoznik 已提交
2521

2522
    priv = vm->privateData;
2523
    cfg = virLXCDriverGetConfig(driver);
2524

2525 2526 2527
    if (virDomainSetBlkioParametersEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

2528 2529 2530
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

2531
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
2532
        goto endjob;
2533

2534
    if (def) {
2535
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) {
2536 2537
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("blkio cgroup isn't mounted"));
2538
            goto endjob;
2539
        }
2540
    }
2541

2542
    ret = 0;
2543
    if (def) {
2544 2545 2546 2547
        for (i = 0; i < nparams; i++) {
            virTypedParameterPtr param = &params[i];

            if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
2548
                if (virCgroupSetBlkioWeight(priv->cgroup, params[i].value.ui) < 0)
2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570
                    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,
2571 2572 2573 2574
                                                          devices[j].weight) < 0 ||
                            virCgroupGetBlkioDeviceWeight(priv->cgroup,
                                                          devices[j].path,
                                                          &devices[j].weight) < 0) {
2575 2576 2577 2578 2579 2580 2581 2582
                            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,
2583 2584 2585 2586
                                                            devices[j].riops) < 0 ||
                            virCgroupGetBlkioDeviceReadIops(priv->cgroup,
                                                            devices[j].path,
                                                            &devices[j].riops) < 0) {
2587 2588 2589 2590 2591 2592 2593 2594
                            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,
2595 2596 2597 2598
                                                             devices[j].wiops) < 0 ||
                            virCgroupGetBlkioDeviceWriteIops(priv->cgroup,
                                                             devices[j].path,
                                                             &devices[j].wiops) < 0) {
2599 2600 2601 2602 2603 2604 2605 2606
                            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,
2607 2608 2609 2610
                                                           devices[j].rbps) < 0 ||
                            virCgroupGetBlkioDeviceReadBps(priv->cgroup,
                                                           devices[j].path,
                                                           &devices[j].rbps) < 0) {
2611 2612 2613 2614
                            ret = -1;
                            break;
                        }
                    }
2615
                } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
2616 2617 2618
                    for (j = 0; j < ndevices; j++) {
                        if (virCgroupSetBlkioDeviceWriteBps(priv->cgroup,
                                                            devices[j].path,
2619 2620 2621 2622
                                                            devices[j].wbps) < 0 ||
                            virCgroupGetBlkioDeviceWriteBps(priv->cgroup,
                                                            devices[j].path,
                                                            &devices[j].wbps) < 0) {
2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637
                            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 ||
2638 2639
                    lxcDomainMergeBlkioDevice(&def->blkio.devices,
                                              &def->blkio.ndevices,
2640 2641 2642 2643
                                              devices, ndevices, param->field) < 0)
                    ret = -1;
                virBlkioDeviceArrayClear(devices, ndevices);
                VIR_FREE(devices);
2644 2645
            }
        }
E
Eric Blake 已提交
2646
    }
2647
    if (ret < 0)
2648
        goto endjob;
2649
    if (persistentDef) {
2650 2651 2652 2653 2654
        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;
2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675
            } 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);
2676 2677 2678
            }
        }

2679
        if (virDomainSaveConfig(cfg->configDir, driver->caps, persistentDef) < 0)
2680
            ret = -1;
2681 2682
    }

2683
 endjob:
2684
    virLXCDomainObjEndJob(driver, vm);
2685

2686
 cleanup:
2687
    virDomainObjEndAPI(&vm);
2688
    virObjectUnref(cfg);
2689 2690 2691 2692
    return ret;
}


2693 2694
#define LXC_NB_BLKIO_PARAM  6

2695 2696 2697 2698 2699
static int
lxcDomainGetBlkioParameters(virDomainPtr dom,
                            virTypedParameterPtr params,
                            int *nparams,
                            unsigned int flags)
2700 2701
{
    virDomainObjPtr vm = NULL;
2702
    virDomainDefPtr def = NULL;
2703
    virDomainDefPtr persistentDef = NULL;
2704
    int maxparams = LXC_NB_BLKIO_PARAM;
2705 2706
    unsigned int val;
    int ret = -1;
2707
    virLXCDomainObjPrivatePtr priv;
2708 2709

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
2710 2711 2712 2713 2714 2715 2716
                  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;
2717

M
Michal Privoznik 已提交
2718
    if (!(vm = lxcDomObjFromDomain(dom)))
2719
        return -1;
M
Michal Privoznik 已提交
2720

2721
    priv = vm->privateData;
2722

2723 2724 2725
    if (virDomainGetBlkioParametersEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2726 2727 2728 2729 2730
    if ((*nparams) == 0) {
        /* Current number of blkio parameters supported by cgroups */
        *nparams = LXC_NB_BLKIO_PARAM;
        ret = 0;
        goto cleanup;
2731 2732
    } else if (*nparams < maxparams) {
        maxparams = *nparams;
2733 2734
    }

2735 2736
    *nparams = 0;

2737
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
E
Eric Blake 已提交
2738
        goto cleanup;
2739

2740
    if (def) {
2741
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) {
2742 2743
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("blkio cgroup isn't mounted"));
2744 2745 2746
            goto cleanup;
        }

2747 2748 2749 2750 2751 2752 2753
        /* 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;
2754

2755 2756 2757
        if (virDomainGetBlkioParametersAssignFromDef(def, params, nparams,
                                                     maxparams) < 0)
            goto cleanup;
2758

2759
    } else if (persistentDef) {
2760 2761 2762 2763 2764 2765
        /* fill blkio weight here */
        if (virTypedParameterAssign(&(params[(*nparams)++]),
                                    VIR_DOMAIN_BLKIO_WEIGHT,
                                    VIR_TYPED_PARAM_UINT,
                                    persistentDef->blkio.weight) < 0)
            goto cleanup;
2766

2767 2768 2769
        if (virDomainGetBlkioParametersAssignFromDef(persistentDef, params,
                                                     nparams, maxparams) < 0)
            goto cleanup;
2770 2771 2772 2773
    }

    ret = 0;

2774
 cleanup:
2775
    virDomainObjEndAPI(&vm);
2776 2777 2778 2779
    return ret;
}


2780 2781
static int
lxcDomainInterfaceStats(virDomainPtr dom,
2782
                        const char *device,
2783
                        virDomainInterfaceStatsPtr stats)
2784 2785 2786
{
    virDomainObjPtr vm;
    int ret = -1;
2787
    virLXCDriverPtr driver = dom->conn->privateData;
M
Michal Privoznik 已提交
2788
    virDomainNetDefPtr net = NULL;
2789

M
Michal Privoznik 已提交
2790
    if (!(vm = lxcDomObjFromDomain(dom)))
2791 2792
        goto cleanup;

2793 2794 2795
    if (virDomainInterfaceStatsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2796 2797 2798
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_QUERY) < 0)
        goto cleanup;

2799
    if (virDomainObjCheckActive(vm) < 0)
2800
        goto endjob;
2801

2802
    if (!(net = virDomainNetFind(vm->def, device)))
M
Michal Privoznik 已提交
2803 2804
        goto endjob;

2805
    if (virNetDevTapInterfaceStats(net->ifname, stats,
2806
                                   !virDomainNetTypeSharesHostView(net)) < 0)
M
Michal Privoznik 已提交
2807 2808 2809
        goto endjob;

    ret = 0;
2810

2811
 endjob:
2812
    virLXCDomainObjEndJob(driver, vm);
2813

2814
 cleanup:
2815
    virDomainObjEndAPI(&vm);
2816 2817
    return ret;
}
2818

2819

2820
static int lxcDomainGetAutostart(virDomainPtr dom,
2821 2822
                                   int *autostart)
{
2823 2824 2825
    virDomainObjPtr vm;
    int ret = -1;

M
Michal Privoznik 已提交
2826
    if (!(vm = lxcDomObjFromDomain(dom)))
2827 2828
        goto cleanup;

2829 2830 2831
    if (virDomainGetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2832 2833 2834
    *autostart = vm->autostart;
    ret = 0;

2835
 cleanup:
2836
    virDomainObjEndAPI(&vm);
2837 2838 2839 2840
    return ret;
}

static int lxcDomainSetAutostart(virDomainPtr dom,
2841 2842
                                   int autostart)
{
2843
    virLXCDriverPtr driver = dom->conn->privateData;
2844 2845 2846
    virDomainObjPtr vm;
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;
2847
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
2848

M
Michal Privoznik 已提交
2849
    if (!(vm = lxcDomObjFromDomain(dom)))
2850 2851
        goto cleanup;

2852 2853 2854
    if (virDomainSetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2855 2856 2857
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

2858
    if (!vm->persistent) {
2859 2860
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Cannot set autostart for transient domain"));
2861
        goto endjob;
2862 2863 2864 2865
    }

    autostart = (autostart != 0);

2866 2867
    if (vm->autostart == autostart) {
        ret = 0;
2868
        goto endjob;
2869
    }
2870

2871
    configFile = virDomainConfigFile(cfg->configDir,
2872 2873
                                     vm->def->name);
    if (configFile == NULL)
2874
        goto endjob;
2875
    autostartLink = virDomainConfigFile(cfg->autostartDir,
2876 2877
                                        vm->def->name);
    if (autostartLink == NULL)
2878
        goto endjob;
2879

2880
    if (autostart) {
2881
        if (virFileMakePath(cfg->autostartDir) < 0) {
2882
            virReportSystemError(errno,
2883
                                 _("Cannot create autostart directory %s"),
2884
                                 cfg->autostartDir);
2885
            goto endjob;
2886 2887
        }

2888
        if (symlink(configFile, autostartLink) < 0) {
2889
            virReportSystemError(errno,
2890 2891
                                 _("Failed to create symlink '%s to '%s'"),
                                 autostartLink, configFile);
2892
            goto endjob;
2893 2894 2895
        }
    } else {
        if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
2896
            virReportSystemError(errno,
2897 2898
                                 _("Failed to delete symlink '%s'"),
                                 autostartLink);
2899
            goto endjob;
2900
        }
2901
    }
2902 2903

    vm->autostart = autostart;
2904 2905
    ret = 0;

2906
 endjob:
2907 2908
    virLXCDomainObjEndJob(driver, vm);

2909
 cleanup:
2910 2911
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
2912
    virDomainObjEndAPI(&vm);
2913
    virObjectUnref(cfg);
2914 2915 2916
    return ret;
}

2917
static int lxcFreezeContainer(virDomainObjPtr vm)
R
Ryota Ozaki 已提交
2918 2919 2920 2921 2922 2923 2924
{
    int timeout = 1000; /* In milliseconds */
    int check_interval = 1; /* In milliseconds */
    int exp = 10;
    int waited_time = 0;
    int ret = -1;
    char *state = NULL;
2925
    virLXCDomainObjPrivatePtr priv = vm->privateData;
2926

R
Ryota Ozaki 已提交
2927 2928 2929 2930 2931 2932 2933 2934 2935
    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)
         */
2936
        r = virCgroupSetFreezerState(priv->cgroup, "FROZEN");
R
Ryota Ozaki 已提交
2937 2938 2939

        /*
         * Returning EBUSY explicitly indicates that the group is
2940
         * being frozen but incomplete, and other errors are true
R
Ryota Ozaki 已提交
2941 2942 2943 2944 2945 2946 2947
         * errors.
         */
        if (r < 0 && r != -EBUSY) {
            VIR_DEBUG("Writing freezer.state failed with errno: %d", r);
            goto error;
        }
        if (r == -EBUSY)
2948
            VIR_DEBUG("Writing freezer.state gets EBUSY");
R
Ryota Ozaki 已提交
2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962

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

2963
        r = virCgroupGetFreezerState(priv->cgroup, &state);
R
Ryota Ozaki 已提交
2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987

        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);
    }
2988
    VIR_DEBUG("lxcFreezeContainer timeout");
2989
 error:
R
Ryota Ozaki 已提交
2990 2991 2992 2993 2994
    /*
     * 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.
     */
2995
    virCgroupSetFreezerState(priv->cgroup, "THAWED");
R
Ryota Ozaki 已提交
2996 2997
    ret = -1;

2998
 cleanup:
R
Ryota Ozaki 已提交
2999 3000 3001 3002 3003 3004
    VIR_FREE(state);
    return ret;
}

static int lxcDomainSuspend(virDomainPtr dom)
{
3005
    virLXCDriverPtr driver = dom->conn->privateData;
R
Ryota Ozaki 已提交
3006
    virDomainObjPtr vm;
3007
    virObjectEventPtr event = NULL;
R
Ryota Ozaki 已提交
3008
    int ret = -1;
3009
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
3010

M
Michal Privoznik 已提交
3011
    if (!(vm = lxcDomObjFromDomain(dom)))
R
Ryota Ozaki 已提交
3012 3013
        goto cleanup;

3014 3015 3016
    if (virDomainSuspendEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3017 3018 3019
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

3020
    if (virDomainObjCheckActive(vm) < 0)
3021
        goto endjob;
R
Ryota Ozaki 已提交
3022

J
Jiri Denemark 已提交
3023
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) {
3024
        if (lxcFreezeContainer(vm) < 0) {
3025 3026
            virReportError(VIR_ERR_OPERATION_FAILED,
                           "%s", _("Suspend operation failed"));
3027
            goto endjob;
R
Ryota Ozaki 已提交
3028
        }
J
Jiri Denemark 已提交
3029
        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
R
Ryota Ozaki 已提交
3030

3031
        event = virDomainEventLifecycleNewFromObj(vm,
R
Ryota Ozaki 已提交
3032 3033 3034 3035
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
    }

3036
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
3037
        goto endjob;
R
Ryota Ozaki 已提交
3038 3039
    ret = 0;

3040
 endjob:
3041 3042
    virLXCDomainObjEndJob(driver, vm);

3043
 cleanup:
3044
    virObjectEventStateQueue(driver->domainEventState, event);
3045
    virDomainObjEndAPI(&vm);
3046
    virObjectUnref(cfg);
R
Ryota Ozaki 已提交
3047 3048 3049 3050 3051
    return ret;
}

static int lxcDomainResume(virDomainPtr dom)
{
3052
    virLXCDriverPtr driver = dom->conn->privateData;
R
Ryota Ozaki 已提交
3053
    virDomainObjPtr vm;
3054
    virObjectEventPtr event = NULL;
R
Ryota Ozaki 已提交
3055
    int ret = -1;
3056
    int state;
3057
    virLXCDomainObjPrivatePtr priv;
3058
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
3059

M
Michal Privoznik 已提交
3060
    if (!(vm = lxcDomObjFromDomain(dom)))
R
Ryota Ozaki 已提交
3061 3062
        goto cleanup;

3063 3064
    priv = vm->privateData;

3065 3066 3067
    if (virDomainResumeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3068 3069 3070
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

3071
    if (virDomainObjCheckActive(vm) < 0)
3072
        goto endjob;
R
Ryota Ozaki 已提交
3073

3074 3075 3076 3077 3078 3079
    state = virDomainObjGetState(vm, NULL);
    if (state == VIR_DOMAIN_RUNNING) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is already running"));
        goto endjob;
    } else if (state == VIR_DOMAIN_PAUSED) {
3080
        if (virCgroupSetFreezerState(priv->cgroup, "THAWED") < 0) {
3081 3082
            virReportError(VIR_ERR_OPERATION_FAILED,
                           "%s", _("Resume operation failed"));
3083
            goto endjob;
R
Ryota Ozaki 已提交
3084
        }
J
Jiri Denemark 已提交
3085 3086
        virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
                             VIR_DOMAIN_RUNNING_UNPAUSED);
R
Ryota Ozaki 已提交
3087

3088
        event = virDomainEventLifecycleNewFromObj(vm,
R
Ryota Ozaki 已提交
3089 3090 3091 3092
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
    }

3093
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
3094
        goto endjob;
R
Ryota Ozaki 已提交
3095 3096
    ret = 0;

3097
 endjob:
3098 3099
    virLXCDomainObjEndJob(driver, vm);

3100
 cleanup:
3101
    virObjectEventStateQueue(driver->domainEventState, event);
3102
    virDomainObjEndAPI(&vm);
3103
    virObjectUnref(cfg);
R
Ryota Ozaki 已提交
3104 3105 3106
    return ret;
}

3107 3108
static int
lxcDomainOpenConsole(virDomainPtr dom,
3109
                      const char *dev_name,
3110 3111 3112 3113 3114 3115
                      virStreamPtr st,
                      unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainChrDefPtr chr = NULL;
3116
    size_t i;
3117 3118 3119

    virCheckFlags(0, -1);

M
Michal Privoznik 已提交
3120
    if (!(vm = lxcDomObjFromDomain(dom)))
3121 3122
        goto cleanup;

3123 3124 3125
    if (virDomainOpenConsoleEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3126
    if (virDomainObjCheckActive(vm) < 0)
3127 3128
        goto cleanup;

3129
    if (dev_name) {
3130
        for (i = 0; i < vm->def->nconsoles; i++) {
3131 3132 3133 3134 3135 3136
            if (vm->def->consoles[i]->info.alias &&
                STREQ(vm->def->consoles[i]->info.alias, dev_name)) {
                chr = vm->def->consoles[i];
                break;
            }
        }
3137
    } else {
3138 3139
        if (vm->def->nconsoles)
            chr = vm->def->consoles[0];
3140 3141 3142 3143 3144
        else if (vm->def->nserials)
            chr = vm->def->serials[0];
    }

    if (!chr) {
3145 3146 3147
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot find console device '%s'"),
                       dev_name ? dev_name : _("default"));
3148 3149 3150
        goto cleanup;
    }

3151
    if (chr->source->type != VIR_DOMAIN_CHR_TYPE_PTY) {
3152
        virReportError(VIR_ERR_INTERNAL_ERROR,
3153 3154
                       _("character device %s is not using a PTY"),
                       dev_name ? dev_name : NULLSTR(chr->info.alias));
3155 3156 3157
        goto cleanup;
    }

3158
    if (virFDStreamOpenFile(st, chr->source->data.file.path,
E
Eric Blake 已提交
3159
                            0, 0, O_RDWR) < 0)
3160 3161 3162
        goto cleanup;

    ret = 0;
3163
 cleanup:
3164
    virDomainObjEndAPI(&vm);
3165 3166 3167
    return ret;
}

3168 3169 3170 3171 3172 3173 3174

static int
lxcDomainSendProcessSignal(virDomainPtr dom,
                           long long pid_value,
                           unsigned int signum,
                           unsigned int flags)
{
3175
    virLXCDriverPtr driver = dom->conn->privateData;
3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189
    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 已提交
3190
    if (!(vm = lxcDomObjFromDomain(dom)))
3191
        goto cleanup;
M
Michal Privoznik 已提交
3192

3193 3194
    priv = vm->privateData;

3195 3196 3197
    if (virDomainSendProcessSignalEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3198 3199 3200
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

3201
    if (virDomainObjCheckActive(vm) < 0)
3202
        goto endjob;
3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213

    /*
     * 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"));
3214
        goto endjob;
3215 3216 3217 3218 3219
    }

    if (!priv->initpid) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Init pid is not yet available"));
3220
        goto endjob;
3221 3222 3223 3224 3225 3226 3227 3228 3229 3230
    }
    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);
3231
        goto endjob;
3232 3233 3234 3235
    }

    ret = 0;

3236
 endjob:
3237
    virLXCDomainObjEndJob(driver, vm);
3238

3239
 cleanup:
3240
    virDomainObjEndAPI(&vm);
3241 3242 3243 3244
    return ret;
}


3245
static int
3246 3247
lxcConnectListAllDomains(virConnectPtr conn,
                         virDomainPtr **domains,
3248 3249
                  unsigned int flags)
{
3250
    virLXCDriverPtr driver = conn->privateData;
3251 3252
    int ret = -1;

O
Osier Yang 已提交
3253
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
3254

3255 3256 3257
    if (virConnectListAllDomainsEnsureACL(conn) < 0)
        return -1;

3258 3259
    ret = virDomainObjListExport(driver->domains, conn, domains,
                                 virConnectListAllDomainsCheckACL, flags);
3260 3261 3262
    return ret;
}

3263

3264 3265 3266 3267
static int
lxcDomainShutdownFlags(virDomainPtr dom,
                       unsigned int flags)
{
3268
    virLXCDriverPtr driver = dom->conn->privateData;
3269 3270 3271
    virLXCDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
    int ret = -1;
3272
    int rc;
3273 3274 3275 3276

    virCheckFlags(VIR_DOMAIN_SHUTDOWN_INITCTL |
                  VIR_DOMAIN_SHUTDOWN_SIGNAL, -1);

M
Michal Privoznik 已提交
3277
    if (!(vm = lxcDomObjFromDomain(dom)))
3278 3279 3280 3281
        goto cleanup;

    priv = vm->privateData;

3282
    if (virDomainShutdownFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
3283 3284
        goto cleanup;

3285 3286 3287
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

3288
    if (virDomainObjCheckActive(vm) < 0)
3289
        goto endjob;
3290 3291 3292 3293

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

3297 3298
    if (flags == 0 ||
        (flags & VIR_DOMAIN_SHUTDOWN_INITCTL)) {
3299 3300
        int command = VIR_INITCTL_RUNLEVEL_POWEROFF;

3301
        if ((rc = virLXCDomainSetRunlevel(vm, command)) < 0)
3302
            goto endjob;
3303 3304
        if (rc == 0 && flags != 0 &&
            ((flags & ~VIR_DOMAIN_SHUTDOWN_INITCTL) == 0)) {
3305 3306
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                           _("Container does not provide an initctl pipe"));
3307
            goto endjob;
3308
        }
3309 3310
    } else {
        rc = 0;
3311
    }
3312

3313 3314 3315
    if (rc == 0 &&
        (flags == 0 ||
         (flags & VIR_DOMAIN_SHUTDOWN_SIGNAL))) {
3316 3317
        if (kill(priv->initpid, SIGTERM) < 0 &&
            errno != ESRCH) {
3318 3319
            virReportSystemError(errno,
                                 _("Unable to send SIGTERM to init pid %llu"),
3320
                                 (long long)priv->initpid);
3321
            goto endjob;
3322 3323 3324 3325 3326
        }
    }

    ret = 0;

3327
 endjob:
3328
    virLXCDomainObjEndJob(driver, vm);
3329

3330
 cleanup:
3331
    virDomainObjEndAPI(&vm);
3332 3333 3334 3335 3336 3337 3338 3339 3340
    return ret;
}

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

3341

3342 3343 3344 3345
static int
lxcDomainReboot(virDomainPtr dom,
                unsigned int flags)
{
3346
    virLXCDriverPtr driver = dom->conn->privateData;
3347 3348 3349 3350 3351 3352 3353 3354
    virLXCDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
    int ret = -1;
    int rc;

    virCheckFlags(VIR_DOMAIN_REBOOT_INITCTL |
                  VIR_DOMAIN_REBOOT_SIGNAL, -1);

M
Michal Privoznik 已提交
3355
    if (!(vm = lxcDomObjFromDomain(dom)))
3356 3357 3358 3359
        goto cleanup;

    priv = vm->privateData;

3360
    if (virDomainRebootEnsureACL(dom->conn, vm->def, flags) < 0)
3361 3362
        goto cleanup;

3363 3364 3365
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

3366
    if (virDomainObjCheckActive(vm) < 0)
3367
        goto endjob;
3368 3369 3370 3371

    if (priv->initpid == 0) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Init process ID is not yet known"));
3372
        goto endjob;
3373 3374 3375 3376
    }

    if (flags == 0 ||
        (flags & VIR_DOMAIN_REBOOT_INITCTL)) {
3377 3378
        int command = VIR_INITCTL_RUNLEVEL_REBOOT;

3379
        if ((rc = virLXCDomainSetRunlevel(vm, command)) < 0)
3380
            goto endjob;
3381 3382 3383 3384
        if (rc == 0 && flags != 0 &&
            ((flags & ~VIR_DOMAIN_SHUTDOWN_INITCTL) == 0)) {
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                           _("Container does not provide an initctl pipe"));
3385
            goto endjob;
3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397
        }
    } 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"),
3398
                                 (long long)priv->initpid);
3399
            goto endjob;
3400 3401 3402 3403 3404
        }
    }

    ret = 0;

3405
 endjob:
3406
    virLXCDomainObjEndJob(driver, vm);
3407

3408
 cleanup:
3409
    virDomainObjEndAPI(&vm);
3410 3411 3412 3413
    return ret;
}


3414
static int
3415
lxcDomainAttachDeviceConfig(virDomainDefPtr vmdef,
3416 3417 3418
                            virDomainDeviceDefPtr dev)
{
    int ret = -1;
3419
    virDomainDiskDefPtr disk;
3420
    virDomainNetDefPtr net;
3421
    virDomainHostdevDefPtr hostdev;
3422 3423

    switch (dev->type) {
3424 3425 3426 3427 3428 3429 3430
    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;
        }
3431
        if (virDomainDiskInsert(vmdef, disk))
3432 3433 3434 3435 3436 3437
            return -1;
        /* vmdef has the pointer. Generic codes for vmdef will do all jobs */
        dev->data.disk = NULL;
        ret = 0;
        break;

3438 3439
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
3440
        if (virDomainNetInsert(vmdef, net) < 0)
3441 3442 3443 3444 3445
            goto cleanup;
        dev->data.net = NULL;
        ret = 0;
        break;

3446 3447 3448 3449 3450 3451 3452
    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;
        }
3453
        if (virDomainHostdevInsert(vmdef, hostdev) < 0)
3454 3455 3456 3457 3458
            return -1;
        dev->data.hostdev = NULL;
        ret = 0;
        break;

3459 3460 3461 3462 3463 3464
    default:
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                        _("persistent attach of device is not supported"));
         break;
    }

3465
 cleanup:
3466 3467 3468 3469 3470
    return ret;
}


static int
3471
lxcDomainUpdateDeviceConfig(virDomainDefPtr vmdef,
3472 3473 3474
                            virDomainDeviceDefPtr dev)
{
    int ret = -1;
3475
    virDomainNetDefPtr net;
3476
    virDomainDeviceDef oldDev = { .type = dev->type };
3477
    int idx;
3478 3479

    switch (dev->type) {
3480 3481
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
3482
        if ((idx = virDomainNetFindIdx(vmdef, net)) < 0)
3483 3484
            goto cleanup;

3485
        oldDev.data.net = vmdef->nets[idx];
3486
        if (virDomainDefCompatibleDevice(vmdef, dev, &oldDev,
3487 3488
                                         VIR_DOMAIN_DEVICE_ACTION_UPDATE,
                                         false) < 0)
3489
            return -1;
3490

3491
        virDomainNetDefFree(vmdef->nets[idx]);
3492 3493 3494 3495 3496 3497
        vmdef->nets[idx] = net;
        dev->data.net = NULL;
        ret = 0;

        break;

3498 3499 3500 3501 3502 3503
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("persistent update of device is not supported"));
        break;
    }

3504
 cleanup:
3505 3506 3507 3508 3509
    return ret;
}


static int
3510
lxcDomainDetachDeviceConfig(virDomainDefPtr vmdef,
3511 3512 3513
                            virDomainDeviceDefPtr dev)
{
    int ret = -1;
3514
    virDomainDiskDefPtr disk, det_disk;
3515
    virDomainNetDefPtr net;
3516
    virDomainHostdevDefPtr hostdev, det_hostdev;
3517
    int idx;
3518 3519

    switch (dev->type) {
3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530
    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;

3531 3532
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
3533
        if ((idx = virDomainNetFindIdx(vmdef, net)) < 0)
3534
            goto cleanup;
3535

3536 3537 3538 3539 3540
        /* this is guaranteed to succeed */
        virDomainNetDefFree(virDomainNetRemove(vmdef, idx));
        ret = 0;
        break;

3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553
    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;
    }

3554 3555 3556 3557 3558 3559
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("persistent detach of device is not supported"));
        break;
    }

3560
 cleanup:
3561 3562 3563 3564
    return ret;
}


3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612
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;
3613 3614
        char *tmpsrc = def->src->path;
        def->src->path = data->file;
3615 3616 3617
        if (virSecurityManagerSetImageLabel(data->driver->securityManager,
                                            data->vm->def, def->src,
                                            VIR_SECURITY_DOMAIN_IMAGE_LABEL_BACKING_CHAIN) < 0) {
3618
            def->src->path = tmpsrc;
3619 3620
            goto cleanup;
        }
3621
        def->src->path = tmpsrc;
3622 3623
    }   break;

3624 3625 3626 3627 3628 3629 3630
    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;

3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681
    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;
}


3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714
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;
}


3715 3716 3717 3718 3719 3720 3721 3722 3723
static int
lxcDomainAttachDeviceDiskLive(virLXCDriverPtr driver,
                              virDomainObjPtr vm,
                              virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainDiskDefPtr def = dev->data.disk;
    int ret = -1;
    struct stat sb;
3724 3725
    char *file = NULL;
    int perms;
3726
    const char *src = NULL;
3727 3728 3729 3730 3731 3732 3733

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

3734 3735 3736 3737 3738 3739
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        goto cleanup;
    }

3740 3741
    src = virDomainDiskGetSource(def);
    if (src == NULL) {
3742 3743 3744 3745 3746
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Can't setup disk without media"));
        goto cleanup;
    }

3747 3748 3749 3750 3751 3752
    if (!virStorageSourceIsBlockLocal(def->src)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Can't setup disk for non-block device"));
        goto cleanup;
    }

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

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

3765
    if (!S_ISBLK(sb.st_mode)) {
3766
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3767
                       _("Disk source %s must be a block device"),
3768
                       src);
3769 3770 3771
        goto cleanup;
    }

3772
    perms = (def->src->readonly ?
3773 3774 3775
             VIR_CGROUP_DEVICE_READ :
             VIR_CGROUP_DEVICE_RW) |
        VIR_CGROUP_DEVICE_MKNOD;
3776

3777 3778 3779 3780 3781
    if (virCgroupAllowDevice(priv->cgroup,
                             'b',
                             major(sb.st_rdev),
                             minor(sb.st_rdev),
                             perms) < 0)
3782
        goto cleanup;
3783

3784
    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks + 1) < 0)
3785 3786
        goto cleanup;

3787 3788
    if (virAsprintf(&file,
                    "/dev/%s", def->dst) < 0)
3789 3790
        goto cleanup;

3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801
    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)
3802 3803
            VIR_WARN("cannot deny device %s for domain %s: %s",
                     src, vm->def->name, virGetLastErrorMessage());
3804 3805 3806 3807 3808 3809 3810
        goto cleanup;
    }

    virDomainDiskInsertPreAlloced(vm->def, def);

    ret = 0;

3811
 cleanup:
3812
    if (src)
3813
        virDomainAuditDisk(vm, NULL, def->src, "attach", ret == 0);
3814
    VIR_FREE(file);
3815 3816 3817 3818
    return ret;
}


3819
/* XXX conn required for network -> bridge resolution */
3820
static int
3821 3822 3823 3824 3825 3826
lxcDomainAttachDeviceNetLive(virConnectPtr conn,
                             virDomainObjPtr vm,
                             virDomainNetDefPtr net)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    int ret = -1;
3827
    virDomainNetType actualType;
3828
    virNetDevBandwidthPtr actualBandwidth;
3829 3830 3831 3832 3833
    char *veth = NULL;

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

3837 3838 3839
    if (virLXCProcessValidateInterface(net) < 0)
       return -1;

3840
    /* preallocate new slot for device */
3841
    if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets+1) < 0)
3842 3843 3844 3845 3846 3847
        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.
     */
3848
    if (virDomainNetAllocateActualDevice(vm->def, net) < 0)
3849 3850 3851 3852 3853
        return -1;

    actualType = virDomainNetGetActualType(net);

    switch (actualType) {
3854 3855
    case VIR_DOMAIN_NET_TYPE_BRIDGE:
    case VIR_DOMAIN_NET_TYPE_NETWORK: {
3856 3857 3858 3859 3860 3861
        const char *brname = virDomainNetGetActualBridgeName(net);
        if (!brname) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No bridge name specified"));
            goto cleanup;
        }
3862
        if (!(veth = virLXCProcessSetupInterfaceTap(vm->def, net, brname)))
3863 3864
            goto cleanup;
    }   break;
3865 3866 3867 3868
    case VIR_DOMAIN_NET_TYPE_ETHERNET:
        if (!(veth = virLXCProcessSetupInterfaceTap(vm->def, net, NULL)))
            goto cleanup;
        break;
3869
    case VIR_DOMAIN_NET_TYPE_DIRECT: {
3870
        if (!(veth = virLXCProcessSetupInterfaceDirect(conn, vm->def, net)))
3871 3872
            goto cleanup;
    }   break;
3873 3874 3875 3876 3877 3878 3879 3880
    case VIR_DOMAIN_NET_TYPE_USER:
    case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
    case VIR_DOMAIN_NET_TYPE_SERVER:
    case VIR_DOMAIN_NET_TYPE_CLIENT:
    case VIR_DOMAIN_NET_TYPE_MCAST:
    case VIR_DOMAIN_NET_TYPE_INTERNAL:
    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
    case VIR_DOMAIN_NET_TYPE_UDP:
3881 3882 3883
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Network device type is not supported"));
        goto cleanup;
3884 3885 3886 3887
    case VIR_DOMAIN_NET_TYPE_LAST:
    default:
        virReportEnumRangeError(virDomainNetType, actualType);
        goto cleanup;
3888
    }
3889 3890 3891 3892
    /* Set bandwidth or warn if requested and not supported. */
    actualBandwidth = virDomainNetGetActualBandwidth(net);
    if (actualBandwidth) {
        if (virNetDevSupportBandwidth(actualType)) {
3893 3894
            if (virNetDevBandwidthSet(net->ifname, actualBandwidth, false,
                                      !virDomainNetTypeSharesHostView(net)) < 0)
3895 3896 3897
                goto cleanup;
        } else {
            VIR_WARN("setting bandwidth on interfaces of "
3898 3899
                     "type '%s' is not implemented yet: %s",
                     virDomainNetTypeToString(actualType), virGetLastErrorMessage());
3900 3901
        }
    }
3902 3903 3904 3905 3906 3907 3908 3909 3910 3911

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

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

    ret = 0;

3912
 cleanup:
3913 3914 3915 3916 3917 3918
    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:
3919
        case VIR_DOMAIN_NET_TYPE_ETHERNET:
3920 3921 3922 3923 3924 3925
            ignore_value(virNetDevVethDelete(veth));
            break;

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

3927 3928 3929 3930 3931 3932 3933 3934 3935
        case VIR_DOMAIN_NET_TYPE_USER:
        case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
        case VIR_DOMAIN_NET_TYPE_SERVER:
        case VIR_DOMAIN_NET_TYPE_CLIENT:
        case VIR_DOMAIN_NET_TYPE_MCAST:
        case VIR_DOMAIN_NET_TYPE_INTERNAL:
        case VIR_DOMAIN_NET_TYPE_HOSTDEV:
        case VIR_DOMAIN_NET_TYPE_UDP:
        case VIR_DOMAIN_NET_TYPE_LAST:
3936 3937 3938
        default:
            /* no-op */
            break;
3939 3940 3941 3942 3943 3944 3945
        }
    }

    return ret;
}


3946 3947 3948 3949 3950 3951 3952 3953 3954 3955
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;
3956
    virUSBDevicePtr usb = NULL;
3957
    virDomainHostdevSubsysUSBPtr usbsrc;
3958 3959 3960 3961 3962 3963 3964

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

3965
    usbsrc = &def->source.subsys.u.usb;
3966
    if (virAsprintf(&src, "/dev/bus/usb/%03d/%03d",
3967
                    usbsrc->bus, usbsrc->device) < 0)
3968 3969
        goto cleanup;

3970
    if (!(usb = virUSBDeviceNew(usbsrc->bus, usbsrc->device, NULL)))
3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985
        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;
    }

3986 3987 3988
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0)
        goto cleanup;

3989
    if (virUSBDeviceFileIterate(usb,
3990
                                virLXCSetupHostUSBDeviceCgroup,
3991
                                priv->cgroup) < 0)
3992 3993
        goto cleanup;

3994 3995 3996 3997 3998 3999 4000
    if (lxcDomainAttachDeviceMknod(driver,
                                   0700 | S_IFCHR,
                                   sb.st_rdev,
                                   vm,
                                   dev,
                                   src) < 0) {
        if (virUSBDeviceFileIterate(usb,
4001
                                    virLXCTeardownHostUSBDeviceCgroup,
4002
                                    priv->cgroup) < 0)
4003 4004
            VIR_WARN("cannot deny device %s for domain %s: %s",
                     src, vm->def->name, virGetLastErrorMessage());
4005 4006 4007
        goto cleanup;
    }

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

4010 4011
    ret = 0;

4012
 cleanup:
4013
    virDomainAuditHostdev(vm, def, "attach", ret == 0);
4014
    virUSBDeviceFree(usb);
4015 4016 4017 4018 4019
    VIR_FREE(src);
    return ret;
}


4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055
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;
    }

4056
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0)
4057 4058
        goto cleanup;

4059 4060 4061 4062 4063
    if (virCgroupAllowDevice(priv->cgroup,
                             'b',
                             major(sb.st_rdev),
                             minor(sb.st_rdev),
                             VIR_CGROUP_DEVICE_RWM) < 0)
4064 4065
        goto cleanup;

4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076
    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)
4077 4078
            VIR_WARN("cannot deny device %s for domain %s: %s",
                     def->source.caps.u.storage.block, vm->def->name, virGetLastErrorMessage());
4079 4080 4081 4082 4083 4084 4085
        goto cleanup;
    }

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

    ret = 0;

4086
 cleanup:
4087 4088 4089 4090 4091
    virDomainAuditHostdev(vm, def, "attach", ret == 0);
    return ret;
}


4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127
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;
    }

4128 4129 4130 4131 4132
    if (virCgroupAllowDevice(priv->cgroup,
                             'c',
                             major(sb.st_rdev),
                             minor(sb.st_rdev),
                             VIR_CGROUP_DEVICE_RWM) < 0)
4133 4134
        goto cleanup;

4135
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0)
4136 4137
        goto cleanup;

4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148
    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)
4149 4150
            VIR_WARN("cannot deny device %s for domain %s: %s",
                     def->source.caps.u.storage.block, vm->def->name, virGetLastErrorMessage());
4151 4152 4153 4154 4155 4156 4157
        goto cleanup;
    }

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

    ret = 0;

4158
 cleanup:
4159 4160 4161 4162 4163
    virDomainAuditHostdev(vm, def, "attach", ret == 0);
    return ret;
}


4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181
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;
    }
}


4182 4183 4184 4185 4186 4187 4188 4189 4190
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);

4191 4192 4193
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC:
        return lxcDomainAttachDeviceHostdevMiscLive(driver, vm, dev);

4194 4195 4196 4197 4198 4199 4200 4201 4202
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported host device type %s"),
                       virDomainHostdevCapsTypeToString(dev->data.hostdev->source.caps.type));
        return -1;
    }
}


4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215
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;
    }

4216 4217 4218 4219 4220 4221
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        return -1;
    }

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

4226 4227 4228
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
        return lxcDomainAttachDeviceHostdevCapsLive(driver, vm, dev);

4229 4230 4231 4232 4233 4234 4235 4236 4237
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported host device mode %s"),
                       virDomainHostdevModeTypeToString(dev->data.hostdev->mode));
        return -1;
    }
}


4238 4239 4240 4241
static int
lxcDomainAttachDeviceLive(virConnectPtr conn,
                          virLXCDriverPtr driver,
                          virDomainObjPtr vm,
4242 4243 4244 4245 4246
                          virDomainDeviceDefPtr dev)
{
    int ret = -1;

    switch (dev->type) {
4247 4248 4249 4250 4251 4252
    case VIR_DOMAIN_DEVICE_DISK:
        ret = lxcDomainAttachDeviceDiskLive(driver, vm, dev);
        if (!ret)
            dev->data.disk = NULL;
        break;

4253 4254 4255 4256 4257 4258 4259
    case VIR_DOMAIN_DEVICE_NET:
        ret = lxcDomainAttachDeviceNetLive(conn, vm,
                                           dev->data.net);
        if (!ret)
            dev->data.net = NULL;
        break;

4260 4261 4262
    case VIR_DOMAIN_DEVICE_HOSTDEV:
        ret = lxcDomainAttachDeviceHostdevLive(driver, vm, dev);
        if (!ret)
C
Chen Hanxiao 已提交
4263
            dev->data.hostdev = NULL;
4264 4265
        break;

4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("device type '%s' cannot be attached"),
                       virDomainDeviceTypeToString(dev->type));
        break;
    }

    return ret;
}


4277
static int
4278
lxcDomainDetachDeviceDiskLive(virDomainObjPtr vm,
4279 4280 4281 4282
                              virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainDiskDefPtr def = NULL;
4283
    int idx, ret = -1;
J
John Ferlan 已提交
4284
    char *dst = NULL;
4285
    const char *src;
4286 4287 4288 4289 4290 4291 4292

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

4293 4294 4295
    if ((idx = virDomainDiskIndexByName(vm->def,
                                        dev->data.disk->dst,
                                        false)) < 0) {
4296 4297 4298 4299 4300
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("disk %s not found"), dev->data.disk->dst);
        goto cleanup;
    }

4301
    def = vm->def->disks[idx];
4302
    src = virDomainDiskGetSource(def);
4303

4304
    if (virAsprintf(&dst, "/dev/%s", def->dst) < 0)
4305 4306
        goto cleanup;

4307
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
4308 4309 4310 4311 4312
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        goto cleanup;
    }

4313
    if (lxcDomainAttachDeviceUnlink(vm, dst) < 0) {
4314
        virDomainAuditDisk(vm, def->src, NULL, "detach", false);
4315 4316
        goto cleanup;
    }
4317
    virDomainAuditDisk(vm, def->src, NULL, "detach", true);
4318

4319 4320
    if (virCgroupDenyDevicePath(priv->cgroup, src,
                                VIR_CGROUP_DEVICE_RWM, false) != 0)
4321 4322
        VIR_WARN("cannot deny device %s for domain %s: %s",
                 src, vm->def->name, virGetLastErrorMessage());
4323

4324
    virDomainDiskRemove(vm->def, idx);
4325 4326 4327 4328
    virDomainDiskDefFree(def);

    ret = 0;

4329
 cleanup:
4330 4331 4332 4333 4334
    VIR_FREE(dst);
    return ret;
}


4335
static int
4336 4337 4338
lxcDomainDetachDeviceNetLive(virDomainObjPtr vm,
                             virDomainDeviceDefPtr dev)
{
4339 4340
    int detachidx, ret = -1;
    virDomainNetType actualType;
4341 4342 4343
    virDomainNetDefPtr detach = NULL;
    virNetDevVPortProfilePtr vport = NULL;

4344
    if ((detachidx = virDomainNetFindIdx(vm->def, dev->data.net)) < 0)
4345
        goto cleanup;
4346

4347
    detach = vm->def->nets[detachidx];
4348 4349 4350
    actualType = virDomainNetGetActualType(detach);

    /* clear network bandwidth */
4351 4352
    if (virDomainNetGetActualBandwidth(detach) &&
        virNetDevSupportBandwidth(actualType) &&
4353 4354
        virNetDevBandwidthClear(detach->ifname))
        goto cleanup;
4355

4356
    switch (actualType) {
4357 4358
    case VIR_DOMAIN_NET_TYPE_BRIDGE:
    case VIR_DOMAIN_NET_TYPE_NETWORK:
4359
    case VIR_DOMAIN_NET_TYPE_ETHERNET:
4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370
        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
4371
         */
4372
    case VIR_DOMAIN_NET_TYPE_DIRECT:
4373 4374 4375 4376 4377 4378 4379 4380
    case VIR_DOMAIN_NET_TYPE_USER:
    case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
    case VIR_DOMAIN_NET_TYPE_SERVER:
    case VIR_DOMAIN_NET_TYPE_CLIENT:
    case VIR_DOMAIN_NET_TYPE_MCAST:
    case VIR_DOMAIN_NET_TYPE_INTERNAL:
    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
    case VIR_DOMAIN_NET_TYPE_UDP:
4381 4382 4383
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Only bridged veth devices can be detached"));
        goto cleanup;
4384 4385 4386 4387
    case VIR_DOMAIN_NET_TYPE_LAST:
    default:
        virReportEnumRangeError(virDomainNetType, actualType);
        goto cleanup;
4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399
    }

    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;
4400
 cleanup:
4401
    if (!ret) {
4402
        virDomainNetReleaseActualDevice(vm->def, detach);
4403 4404 4405 4406 4407 4408 4409
        virDomainNetRemove(vm->def, detachidx);
        virDomainNetDefFree(detach);
    }
    return ret;
}


4410 4411 4412 4413 4414 4415 4416 4417
static int
lxcDomainDetachDeviceHostdevUSBLive(virLXCDriverPtr driver,
                                    virDomainObjPtr vm,
                                    virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainHostdevDefPtr def = NULL;
    int idx, ret = -1;
J
John Ferlan 已提交
4418
    char *dst = NULL;
4419
    virUSBDevicePtr usb = NULL;
4420
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
4421
    virDomainHostdevSubsysUSBPtr usbsrc;
4422 4423 4424 4425 4426 4427 4428 4429 4430

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

4431
    usbsrc = &def->source.subsys.u.usb;
4432
    if (virAsprintf(&dst, "/dev/bus/usb/%03d/%03d",
4433
                    usbsrc->bus, usbsrc->device) < 0)
4434 4435
        goto cleanup;

4436
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
4437 4438 4439 4440 4441
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        goto cleanup;
    }

4442
    if (!(usb = virUSBDeviceNew(usbsrc->bus, usbsrc->device, NULL)))
4443 4444
        goto cleanup;

4445
    if (lxcDomainAttachDeviceUnlink(vm, dst) < 0) {
4446 4447 4448 4449 4450
        virDomainAuditHostdev(vm, def, "detach", false);
        goto cleanup;
    }
    virDomainAuditHostdev(vm, def, "detach", true);

4451
    if (virUSBDeviceFileIterate(usb,
4452
                                virLXCTeardownHostUSBDeviceCgroup,
4453
                                priv->cgroup) < 0)
4454 4455
        VIR_WARN("cannot deny device %s for domain %s: %s",
                 dst, vm->def->name, virGetLastErrorMessage());
4456

4457 4458 4459
    virObjectLock(hostdev_mgr->activeUSBHostdevs);
    virUSBDeviceListDel(hostdev_mgr->activeUSBHostdevs, usb);
    virObjectUnlock(hostdev_mgr->activeUSBHostdevs);
4460 4461 4462 4463 4464 4465

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

    ret = 0;

4466
 cleanup:
4467
    virUSBDeviceFree(usb);
4468 4469 4470 4471
    VIR_FREE(dst);
    return ret;
}

4472 4473

static int
4474
lxcDomainDetachDeviceHostdevStorageLive(virDomainObjPtr vm,
4475 4476 4477 4478
                                        virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainHostdevDefPtr def = NULL;
4479
    int idx, ret = -1;
4480 4481 4482 4483 4484 4485 4486

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

4487 4488 4489
    if ((idx = virDomainHostdevFind(vm->def,
                                    dev->data.hostdev,
                                    &def)) < 0) {
4490 4491 4492 4493 4494 4495
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("hostdev %s not found"),
                       dev->data.hostdev->source.caps.u.storage.block);
        goto cleanup;
    }

4496
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
4497 4498 4499 4500 4501
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        goto cleanup;
    }

4502
    if (lxcDomainAttachDeviceUnlink(vm, def->source.caps.u.storage.block) < 0) {
4503 4504 4505 4506 4507
        virDomainAuditHostdev(vm, def, "detach", false);
        goto cleanup;
    }
    virDomainAuditHostdev(vm, def, "detach", true);

4508 4509
    if (virCgroupDenyDevicePath(priv->cgroup, def->source.caps.u.storage.block,
                                VIR_CGROUP_DEVICE_RWM, false) != 0)
4510 4511
        VIR_WARN("cannot deny device %s for domain %s: %s",
                 def->source.caps.u.storage.block, vm->def->name, virGetLastErrorMessage());
4512

4513
    virDomainHostdevRemove(vm->def, idx);
4514 4515 4516 4517
    virDomainHostdevDefFree(def);

    ret = 0;

4518
 cleanup:
4519 4520 4521 4522
    return ret;
}


4523
static int
4524
lxcDomainDetachDeviceHostdevMiscLive(virDomainObjPtr vm,
4525 4526 4527 4528
                                     virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainHostdevDefPtr def = NULL;
4529
    int idx, ret = -1;
4530 4531 4532 4533 4534 4535 4536

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

4537 4538 4539
    if ((idx = virDomainHostdevFind(vm->def,
                                    dev->data.hostdev,
                                    &def)) < 0) {
4540 4541 4542 4543 4544 4545
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("hostdev %s not found"),
                       dev->data.hostdev->source.caps.u.misc.chardev);
        goto cleanup;
    }

4546
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
4547 4548 4549 4550 4551
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        goto cleanup;
    }

4552
    if (lxcDomainAttachDeviceUnlink(vm, def->source.caps.u.misc.chardev) < 0) {
4553 4554 4555 4556 4557
        virDomainAuditHostdev(vm, def, "detach", false);
        goto cleanup;
    }
    virDomainAuditHostdev(vm, def, "detach", true);

4558 4559
    if (virCgroupDenyDevicePath(priv->cgroup, def->source.caps.u.misc.chardev,
                                VIR_CGROUP_DEVICE_RWM, false) != 0)
4560 4561
        VIR_WARN("cannot deny device %s for domain %s: %s",
                 def->source.caps.u.misc.chardev, vm->def->name, virGetLastErrorMessage());
4562

4563
    virDomainHostdevRemove(vm->def, idx);
4564 4565 4566 4567
    virDomainHostdevDefFree(def);

    ret = 0;

4568
 cleanup:
4569 4570 4571 4572
    return ret;
}


4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590
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;
    }
}


4591
static int
4592 4593
lxcDomainDetachDeviceHostdevCapsLive(virDomainObjPtr vm,
                                     virDomainDeviceDefPtr dev)
4594 4595 4596
{
    switch (dev->data.hostdev->source.caps.type) {
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
4597
        return lxcDomainDetachDeviceHostdevStorageLive(vm, dev);
4598

4599
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC:
4600
        return lxcDomainDetachDeviceHostdevMiscLive(vm, dev);
4601

4602 4603 4604 4605 4606 4607 4608 4609 4610
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported host device type %s"),
                       virDomainHostdevCapsTypeToString(dev->data.hostdev->source.caps.type));
        return -1;
    }
}


4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627
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);

4628
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
4629
        return lxcDomainDetachDeviceHostdevCapsLive(vm, dev);
4630

4631 4632 4633 4634 4635 4636 4637 4638 4639
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported host device mode %s"),
                       virDomainHostdevModeTypeToString(dev->data.hostdev->mode));
        return -1;
    }
}


4640 4641 4642
static int
lxcDomainDetachDeviceLive(virLXCDriverPtr driver,
                          virDomainObjPtr vm,
4643 4644 4645 4646 4647
                          virDomainDeviceDefPtr dev)
{
    int ret = -1;

    switch (dev->type) {
4648
    case VIR_DOMAIN_DEVICE_DISK:
4649
        ret = lxcDomainDetachDeviceDiskLive(vm, dev);
4650 4651
        break;

4652 4653 4654 4655
    case VIR_DOMAIN_DEVICE_NET:
        ret = lxcDomainDetachDeviceNetLive(vm, dev);
        break;

4656 4657 4658 4659
    case VIR_DOMAIN_DEVICE_HOSTDEV:
        ret = lxcDomainDetachDeviceHostdevLive(driver, vm, dev);
        break;

4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("device type '%s' cannot be detached"),
                       virDomainDeviceTypeToString(dev->type));
        break;
    }

    return ret;
}


4671 4672 4673
static int lxcDomainAttachDeviceFlags(virDomainPtr dom,
                                      const char *xml,
                                      unsigned int flags)
4674 4675
{
    virLXCDriverPtr driver = dom->conn->privateData;
4676
    virCapsPtr caps = NULL;
4677 4678 4679 4680
    virDomainObjPtr vm = NULL;
    virDomainDefPtr vmdef = NULL;
    virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
    int ret = -1;
4681
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
4682 4683

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
4684
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
4685

M
Michal Privoznik 已提交
4686
    if (!(vm = lxcDomObjFromDomain(dom)))
4687 4688
        goto cleanup;

4689 4690 4691
    if (virDomainAttachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4692
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
4693 4694
        goto cleanup;

4695 4696 4697
    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
        goto endjob;

4698
    if (virDomainObjUpdateModificationImpact(vm, &flags) < 0)
4699
        goto endjob;
4700

4701
    dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
4702
                                             caps, driver->xmlopt,
4703
                                             VIR_DOMAIN_DEF_PARSE_INACTIVE);
4704
    if (dev == NULL)
4705
        goto endjob;
4706 4707 4708 4709 4710 4711 4712

    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.
         */
4713
        dev_copy = virDomainDeviceDefCopy(dev, vm->def,
4714
                                          caps, driver->xmlopt);
4715
        if (!dev_copy)
4716
            goto endjob;
4717 4718 4719 4720
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        /* Make a copy for updated domain. */
4721
        vmdef = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt);
4722
        if (!vmdef)
4723
            goto endjob;
4724

4725
        if (virDomainDefCompatibleDevice(vmdef, dev, NULL,
4726 4727
                                         VIR_DOMAIN_DEVICE_ACTION_ATTACH,
                                         false) < 0)
4728
            goto endjob;
4729

4730
        if ((ret = lxcDomainAttachDeviceConfig(vmdef, dev)) < 0)
4731
            goto endjob;
4732 4733 4734
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
4735
        if (virDomainDefCompatibleDevice(vm->def, dev_copy, NULL,
4736 4737
                                         VIR_DOMAIN_DEVICE_ACTION_ATTACH,
                                         true) < 0)
4738
            goto endjob;
4739

4740
        if ((ret = lxcDomainAttachDeviceLive(dom->conn, driver, vm, dev_copy)) < 0)
4741
            goto endjob;
4742 4743 4744 4745 4746
        /*
         * 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.
         */
4747
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0) {
4748
            ret = -1;
4749
            goto endjob;
4750 4751 4752 4753 4754
        }
    }

    /* Finally, if no error until here, we can save config. */
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
4755
        ret = virDomainSaveConfig(cfg->configDir, driver->caps, vmdef);
4756
        if (!ret) {
4757
            virDomainObjAssignDef(vm, vmdef, false, NULL);
4758 4759 4760 4761
            vmdef = NULL;
        }
    }

4762
 endjob:
4763 4764
    virLXCDomainObjEndJob(driver, vm);

4765
 cleanup:
4766 4767 4768 4769
    virDomainDefFree(vmdef);
    if (dev != dev_copy)
        virDomainDeviceDefFree(dev_copy);
    virDomainDeviceDefFree(dev);
4770
    virDomainObjEndAPI(&vm);
4771
    virObjectUnref(caps);
4772
    virObjectUnref(cfg);
4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788
    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)
{
4789
    virLXCDriverPtr driver = dom->conn->privateData;
4790
    virCapsPtr caps = NULL;
4791 4792
    virDomainObjPtr vm = NULL;
    virDomainDefPtr vmdef = NULL;
4793
    virDomainDeviceDefPtr dev = NULL;
4794
    int ret = -1;
4795
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
4796 4797

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
4798
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
4799

M
Michal Privoznik 已提交
4800
    if (!(vm = lxcDomObjFromDomain(dom)))
4801 4802
        goto cleanup;

4803 4804 4805
    if (virDomainUpdateDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4806
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
4807
        goto cleanup;
4808

4809 4810 4811
    if (virDomainObjUpdateModificationImpact(vm, &flags) < 0)
        goto endjob;

4812 4813 4814
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("Unable to modify live devices"));
4815
        goto endjob;
4816
    }
4817

4818
    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
4819
        goto endjob;
4820

4821 4822 4823
    if (!(dev = virDomainDeviceDefParse(xml, vm->def, caps, driver->xmlopt,
                                        VIR_DOMAIN_DEF_PARSE_INACTIVE)))
        goto endjob;
4824

4825 4826 4827
    /* Make a copy for updated domain. */
    if (!(vmdef = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt)))
        goto endjob;
4828

4829 4830 4831 4832
    /* virDomainDefCompatibleDevice call is delayed until we know the
     * device we're going to update. */
    if (lxcDomainUpdateDeviceConfig(vmdef, dev) < 0)
        goto endjob;
4833

4834
    if (virDomainSaveConfig(cfg->configDir, driver->caps, vmdef) < 0)
4835
        goto endjob;
4836

4837 4838 4839 4840
    virDomainObjAssignDef(vm, vmdef, false, NULL);
    vmdef = NULL;
    ret = 0;

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

4844
 cleanup:
4845 4846
    virDomainDefFree(vmdef);
    virDomainDeviceDefFree(dev);
4847
    virDomainObjEndAPI(&vm);
4848
    virObjectUnref(caps);
4849
    virObjectUnref(cfg);
4850
    return ret;
4851 4852 4853 4854 4855 4856 4857
}


static int lxcDomainDetachDeviceFlags(virDomainPtr dom,
                                      const char *xml,
                                      unsigned int flags)
{
4858
    virLXCDriverPtr driver = dom->conn->privateData;
4859
    virCapsPtr caps = NULL;
4860 4861 4862 4863
    virDomainObjPtr vm = NULL;
    virDomainDefPtr vmdef = NULL;
    virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
    int ret = -1;
4864
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
4865 4866 4867 4868

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

M
Michal Privoznik 已提交
4869
    if (!(vm = lxcDomObjFromDomain(dom)))
4870 4871
        goto cleanup;

4872 4873 4874
    if (virDomainDetachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4875
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
4876
        goto cleanup;
4877

4878 4879 4880
    if (virDomainObjUpdateModificationImpact(vm, &flags) < 0)
        goto endjob;

4881
    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
4882
        goto endjob;
4883

4884
    dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
4885
                                             caps, driver->xmlopt,
4886 4887
                                             VIR_DOMAIN_DEF_PARSE_INACTIVE |
                                             VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE);
4888
    if (dev == NULL)
4889
        goto endjob;
4890 4891 4892 4893 4894 4895 4896 4897

    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,
4898
                                          caps, driver->xmlopt);
4899
        if (!dev_copy)
4900
            goto endjob;
4901 4902 4903 4904
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        /* Make a copy for updated domain. */
4905
        vmdef = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt);
4906
        if (!vmdef)
4907
            goto endjob;
4908 4909

        if ((ret = lxcDomainDetachDeviceConfig(vmdef, dev)) < 0)
4910
            goto endjob;
4911 4912 4913 4914
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if ((ret = lxcDomainDetachDeviceLive(driver, vm, dev_copy)) < 0)
4915
            goto endjob;
4916 4917 4918 4919 4920
        /*
         * 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.
         */
4921
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0) {
4922
            ret = -1;
4923
            goto endjob;
4924 4925 4926 4927 4928
        }
    }

    /* Finally, if no error until here, we can save config. */
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
4929
        ret = virDomainSaveConfig(cfg->configDir, driver->caps, vmdef);
4930 4931 4932 4933 4934 4935
        if (!ret) {
            virDomainObjAssignDef(vm, vmdef, false, NULL);
            vmdef = NULL;
        }
    }

4936
 endjob:
4937 4938
    virLXCDomainObjEndJob(driver, vm);

4939
 cleanup:
4940 4941 4942 4943
    virDomainDefFree(vmdef);
    if (dev != dev_copy)
        virDomainDeviceDefFree(dev_copy);
    virDomainDeviceDefFree(dev);
4944
    virDomainObjEndAPI(&vm);
4945
    virObjectUnref(caps);
4946
    virObjectUnref(cfg);
4947
    return ret;
4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958
}


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


4959 4960 4961
static int lxcDomainLxcOpenNamespace(virDomainPtr dom,
                                     int **fdlist,
                                     unsigned int flags)
4962
{
4963
    virLXCDriverPtr driver = dom->conn->privateData;
4964 4965 4966 4967 4968 4969 4970 4971
    virDomainObjPtr vm;
    virLXCDomainObjPrivatePtr priv;
    int ret = -1;
    size_t nfds = 0;

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

M
Michal Privoznik 已提交
4972
    if (!(vm = lxcDomObjFromDomain(dom)))
4973
        goto cleanup;
M
Michal Privoznik 已提交
4974

4975 4976
    priv = vm->privateData;

4977 4978 4979
    if (virDomainLxcOpenNamespaceEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

4980 4981 4982
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_QUERY) < 0)
        goto cleanup;

4983
    if (virDomainObjCheckActive(vm) < 0)
4984
        goto endjob;
4985 4986 4987 4988

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

    if (virProcessGetNamespaces(priv->initpid, &nfds, fdlist) < 0)
4993
        goto endjob;
4994 4995

    ret = nfds;
4996 4997

 endjob:
4998
    virLXCDomainObjEndJob(driver, vm);
4999

5000
 cleanup:
5001
    virDomainObjEndAPI(&vm);
5002 5003 5004 5005
    return ret;
}


5006
static char *
5007
lxcConnectGetSysinfo(virConnectPtr conn, unsigned int flags)
5008 5009 5010 5011 5012 5013
{
    virLXCDriverPtr driver = conn->privateData;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    virCheckFlags(0, NULL);

5014 5015 5016
    if (virConnectGetSysinfoEnsureACL(conn) < 0)
        return NULL;

5017 5018 5019 5020 5021 5022 5023 5024
    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;
5025
    if (virBufferCheckError(&buf) < 0)
5026 5027 5028 5029 5030
        return NULL;
    return virBufferContentAndReset(&buf);
}


5031
static int
5032
lxcNodeGetInfo(virConnectPtr conn,
5033 5034
               virNodeInfoPtr nodeinfo)
{
5035 5036 5037
    if (virNodeGetInfoEnsureACL(conn) < 0)
        return -1;

M
Martin Kletzander 已提交
5038
    return virCapabilitiesGetNodeInfo(nodeinfo);
5039 5040 5041
}


5042 5043
static int
lxcDomainMemoryStats(virDomainPtr dom,
5044
                     virDomainMemoryStatPtr stats,
5045 5046 5047 5048 5049 5050 5051 5052
                     unsigned int nr_stats,
                     unsigned int flags)
{
    virDomainObjPtr vm;
    int ret = -1;
    virLXCDomainObjPrivatePtr priv;
    unsigned long long swap_usage;
    unsigned long mem_usage;
5053
    virLXCDriverPtr driver = dom->conn->privateData;
5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064

    virCheckFlags(0, -1);

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

    priv = vm->privateData;

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

5065 5066 5067
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_QUERY) < 0)
        goto cleanup;

5068
    if (virDomainObjCheckActive(vm) < 0)
5069
        goto endjob;
5070

5071
    if (virCgroupGetMemSwapUsage(priv->cgroup, &swap_usage) < 0)
5072
        goto endjob;
5073

5074
    if (virCgroupGetMemoryUsage(priv->cgroup, &mem_usage) < 0)
5075
        goto endjob;
5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093

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

5094
 endjob:
5095 5096
    virLXCDomainObjEndJob(driver, vm);

5097
 cleanup:
5098
    virDomainObjEndAPI(&vm);
5099 5100 5101 5102
    return ret;
}


5103
static int
5104
lxcNodeGetCPUStats(virConnectPtr conn,
5105 5106 5107 5108 5109
                   int cpuNum,
                   virNodeCPUStatsPtr params,
                   int *nparams,
                   unsigned int flags)
{
5110 5111 5112
    if (virNodeGetCPUStatsEnsureACL(conn) < 0)
        return -1;

5113
    return virHostCPUGetStats(cpuNum, params, nparams, flags);
5114 5115 5116 5117
}


static int
5118
lxcNodeGetMemoryStats(virConnectPtr conn,
5119 5120 5121 5122 5123
                      int cellNum,
                      virNodeMemoryStatsPtr params,
                      int *nparams,
                      unsigned int flags)
{
5124 5125 5126
    if (virNodeGetMemoryStatsEnsureACL(conn) < 0)
        return -1;

5127
    return virHostMemGetStats(cellNum, params, nparams, flags);
5128 5129 5130 5131
}


static int
5132
lxcNodeGetCellsFreeMemory(virConnectPtr conn,
5133 5134 5135 5136
                          unsigned long long *freeMems,
                          int startCell,
                          int maxCells)
{
5137 5138 5139
    if (virNodeGetCellsFreeMemoryEnsureACL(conn) < 0)
        return -1;

5140
    return virHostMemGetCellsFree(freeMems, startCell, maxCells);
5141 5142 5143 5144
}


static unsigned long long
5145
lxcNodeGetFreeMemory(virConnectPtr conn)
5146
{
5147 5148
    unsigned long long freeMem;

5149 5150 5151
    if (virNodeGetFreeMemoryEnsureACL(conn) < 0)
        return 0;

5152
    if (virHostMemGetInfo(NULL, &freeMem) < 0)
5153 5154 5155
        return 0;

    return freeMem;
5156 5157 5158 5159
}


static int
5160
lxcNodeGetMemoryParameters(virConnectPtr conn,
5161 5162 5163 5164
                           virTypedParameterPtr params,
                           int *nparams,
                           unsigned int flags)
{
5165 5166 5167
    if (virNodeGetMemoryParametersEnsureACL(conn) < 0)
        return -1;

5168
    return virHostMemGetParameters(params, nparams, flags);
5169 5170 5171 5172
}


static int
5173
lxcNodeSetMemoryParameters(virConnectPtr conn,
5174 5175 5176 5177
                           virTypedParameterPtr params,
                           int nparams,
                           unsigned int flags)
{
5178 5179 5180
    if (virNodeSetMemoryParametersEnsureACL(conn) < 0)
        return -1;

5181
    return virHostMemSetParameters(params, nparams, flags);
5182 5183 5184 5185
}


static int
5186
lxcNodeGetCPUMap(virConnectPtr conn,
5187 5188 5189 5190
                 unsigned char **cpumap,
                 unsigned int *online,
                 unsigned int flags)
{
5191 5192 5193
    if (virNodeGetCPUMapEnsureACL(conn) < 0)
        return -1;

5194
    return virHostCPUGetMap(cpumap, online, flags);
5195 5196
}

5197 5198

static int
5199
lxcNodeSuspendForDuration(virConnectPtr conn,
5200 5201 5202 5203
                          unsigned int target,
                          unsigned long long duration,
                          unsigned int flags)
{
5204 5205 5206
    if (virNodeSuspendForDurationEnsureACL(conn) < 0)
        return -1;

5207
    return virNodeSuspend(target, duration, flags);
5208 5209 5210
}


5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238
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;

5239 5240 5241
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

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

5246 5247 5248 5249 5250 5251
    if (ret == 0) {
        virObjectEventPtr ev = NULL;
        ev = virDomainEventMetadataChangeNewFromObj(vm, type, uri);
        virObjectEventStateQueue(driver->domainEventState, ev);
    }

5252
    virLXCDomainObjEndJob(driver, vm);
5253

5254
 cleanup:
5255
    virDomainObjEndAPI(&vm);
5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276
    virObjectUnref(caps);
    virObjectUnref(cfg);
    return ret;
}


static char *
lxcDomainGetMetadata(virDomainPtr dom,
                      int type,
                      const char *uri,
                      unsigned int flags)
{
    virDomainObjPtr vm;
    char *ret = NULL;

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

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

5277
    ret = virDomainObjGetMetadata(vm, type, uri, flags);
5278

5279
 cleanup:
5280
    virDomainObjEndAPI(&vm);
5281 5282 5283 5284
    return ret;
}


5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306
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;

5307
    if (virDomainObjCheckActive(vm) < 0)
5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320
        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,
5321
                                      nparams, start_cpu, ncpus, NULL);
5322
 cleanup:
5323
    virDomainObjEndAPI(&vm);
5324 5325 5326 5327
    return ret;
}


5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341
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;

5342
    return virHostMemGetFreePages(npages, pages, startCell, cellCount, counts);
5343 5344 5345
}


5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361
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;

5362 5363
    return virHostMemAllocPages(npages, pageSizes, pageCounts,
                                startCell, cellCount, add);
5364 5365 5366
}


5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383
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:
5384
    virDomainObjEndAPI(&vm);
5385 5386 5387 5388
    return ret;
}


D
Daniel Veillard 已提交
5389
/* Function Tables */
5390
static virHypervisorDriver lxcHypervisorDriver = {
5391
    .name = LXC_DRIVER_NAME,
5392
    .connectURIProbe = lxcConnectURIProbe,
5393 5394
    .connectOpen = lxcConnectOpen, /* 0.4.2 */
    .connectClose = lxcConnectClose, /* 0.4.2 */
5395
    .connectSupportsFeature = lxcConnectSupportsFeature, /* 1.2.2 */
5396
    .connectGetVersion = lxcConnectGetVersion, /* 0.4.6 */
5397
    .connectGetHostname = lxcConnectGetHostname, /* 0.6.3 */
5398
    .connectGetSysinfo = lxcConnectGetSysinfo, /* 1.0.5 */
5399
    .nodeGetInfo = lxcNodeGetInfo, /* 0.6.5 */
5400 5401 5402 5403 5404
    .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 */
5405
    .domainCreateXMLWithFiles = lxcDomainCreateXMLWithFiles, /* 1.1.1 */
5406 5407 5408 5409 5410 5411
    .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 */
5412
    .domainDestroyFlags = lxcDomainDestroyFlags, /* 0.9.4 */
5413
    .domainGetOSType = lxcDomainGetOSType, /* 0.4.2 */
5414 5415 5416
    .domainGetMaxMemory = lxcDomainGetMaxMemory, /* 0.7.2 */
    .domainSetMaxMemory = lxcDomainSetMaxMemory, /* 0.7.2 */
    .domainSetMemory = lxcDomainSetMemory, /* 0.7.2 */
5417
    .domainSetMemoryFlags = lxcDomainSetMemoryFlags, /* 1.2.7 */
5418 5419
    .domainSetMemoryParameters = lxcDomainSetMemoryParameters, /* 0.8.5 */
    .domainGetMemoryParameters = lxcDomainGetMemoryParameters, /* 0.8.5 */
5420 5421
    .domainSetBlkioParameters = lxcDomainSetBlkioParameters, /* 0.9.8 */
    .domainGetBlkioParameters = lxcDomainGetBlkioParameters, /* 0.9.8 */
5422 5423
    .domainGetInfo = lxcDomainGetInfo, /* 0.4.2 */
    .domainGetState = lxcDomainGetState, /* 0.9.2 */
5424 5425
    .domainGetSecurityLabel = lxcDomainGetSecurityLabel, /* 0.9.10 */
    .nodeGetSecurityModel = lxcNodeGetSecurityModel, /* 0.9.10 */
5426
    .domainGetXMLDesc = lxcDomainGetXMLDesc, /* 0.4.2 */
5427
    .connectDomainXMLFromNative = lxcConnectDomainXMLFromNative, /* 1.2.2 */
5428 5429 5430 5431
    .connectListDefinedDomains = lxcConnectListDefinedDomains, /* 0.4.2 */
    .connectNumOfDefinedDomains = lxcConnectNumOfDefinedDomains, /* 0.4.2 */
    .domainCreate = lxcDomainCreate, /* 0.4.4 */
    .domainCreateWithFlags = lxcDomainCreateWithFlags, /* 0.8.2 */
5432
    .domainCreateWithFiles = lxcDomainCreateWithFiles, /* 1.1.1 */
5433
    .domainDefineXML = lxcDomainDefineXML, /* 0.4.2 */
5434
    .domainDefineXMLFlags = lxcDomainDefineXMLFlags, /* 1.2.12 */
5435
    .domainUndefine = lxcDomainUndefine, /* 0.4.2 */
5436
    .domainUndefineFlags = lxcDomainUndefineFlags, /* 0.9.4 */
5437 5438 5439 5440 5441
    .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 */
5442 5443
    .domainGetAutostart = lxcDomainGetAutostart, /* 0.7.0 */
    .domainSetAutostart = lxcDomainSetAutostart, /* 0.7.0 */
5444 5445 5446 5447 5448
    .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 */
5449 5450
    .domainBlockStats = lxcDomainBlockStats, /* 1.2.2 */
    .domainBlockStatsFlags = lxcDomainBlockStatsFlags, /* 1.2.2 */
5451
    .domainInterfaceStats = lxcDomainInterfaceStats, /* 0.7.3 */
5452
    .domainMemoryStats = lxcDomainMemoryStats, /* 1.2.2 */
5453 5454 5455 5456 5457
    .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 */
5458 5459 5460 5461
    .connectDomainEventRegister = lxcConnectDomainEventRegister, /* 0.7.0 */
    .connectDomainEventDeregister = lxcConnectDomainEventDeregister, /* 0.7.0 */
    .connectIsEncrypted = lxcConnectIsEncrypted, /* 0.7.3 */
    .connectIsSecure = lxcConnectIsSecure, /* 0.7.3 */
5462 5463 5464
    .domainIsActive = lxcDomainIsActive, /* 0.7.3 */
    .domainIsPersistent = lxcDomainIsPersistent, /* 0.7.3 */
    .domainIsUpdated = lxcDomainIsUpdated, /* 0.8.6 */
5465 5466
    .connectDomainEventRegisterAny = lxcConnectDomainEventRegisterAny, /* 0.8.0 */
    .connectDomainEventDeregisterAny = lxcConnectDomainEventDeregisterAny, /* 0.8.0 */
5467
    .domainOpenConsole = lxcDomainOpenConsole, /* 0.8.6 */
5468
    .connectIsAlive = lxcConnectIsAlive, /* 0.9.8 */
5469
    .nodeSuspendForDuration = lxcNodeSuspendForDuration, /* 0.9.8 */
5470 5471
    .domainSetMetadata = lxcDomainSetMetadata, /* 1.1.3 */
    .domainGetMetadata = lxcDomainGetMetadata, /* 1.1.3 */
5472
    .domainGetCPUStats = lxcDomainGetCPUStats, /* 1.2.2 */
5473 5474
    .nodeGetMemoryParameters = lxcNodeGetMemoryParameters, /* 0.10.2 */
    .nodeSetMemoryParameters = lxcNodeSetMemoryParameters, /* 0.10.2 */
5475
    .domainSendProcessSignal = lxcDomainSendProcessSignal, /* 1.0.1 */
5476 5477 5478
    .domainShutdown = lxcDomainShutdown, /* 1.0.1 */
    .domainShutdownFlags = lxcDomainShutdownFlags, /* 1.0.1 */
    .domainReboot = lxcDomainReboot, /* 1.0.1 */
5479
    .domainLxcOpenNamespace = lxcDomainLxcOpenNamespace, /* 1.0.2 */
5480
    .nodeGetFreePages = lxcNodeGetFreePages, /* 1.2.6 */
5481
    .nodeAllocPages = lxcNodeAllocPages, /* 1.2.9 */
5482
    .domainHasManagedSaveImage = lxcDomainHasManagedSaveImage, /* 1.2.13 */
D
Daniel Veillard 已提交
5483 5484
};

5485
static virConnectDriver lxcConnectDriver = {
5486
    .localOnly = true,
5487
    .uriSchemes = (const char *[]){ "lxc", NULL },
5488 5489 5490
    .hypervisorDriver = &lxcHypervisorDriver,
};

5491
static virStateDriver lxcStateDriver = {
5492
    .name = LXC_DRIVER_NAME,
5493 5494 5495
    .stateInitialize = lxcStateInitialize,
    .stateCleanup = lxcStateCleanup,
    .stateReload = lxcStateReload,
5496 5497
};

D
Daniel Veillard 已提交
5498 5499
int lxcRegister(void)
{
5500 5501
    if (virRegisterConnectDriver(&lxcConnectDriver,
                                 true) < 0)
5502 5503 5504
        return -1;
    if (virRegisterStateDriver(&lxcStateDriver) < 0)
        return -1;
D
Daniel Veillard 已提交
5505 5506
    return 0;
}