lxc_driver.c 166.5 KB
Newer Older
D
Daniel Veillard 已提交
1
/*
2
 * Copyright (C) 2010-2016 Red Hat, Inc.
D
Daniel Veillard 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 * Copyright IBM Corp. 2008
 *
 * lxc_driver.c: linux container driver functions
 *
 * Authors:
 *  David L. Leskovec <dlesko at linux.vnet.ibm.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
21
 * License along with this library.  If not, see
O
Osier Yang 已提交
22
 * <http://www.gnu.org/licenses/>.
D
Daniel Veillard 已提交
23 24 25 26
 */

#include <config.h>

27
#include <fcntl.h>
D
Daniel Veillard 已提交
28 29 30
#include <sched.h>
#include <sys/utsname.h>
#include <string.h>
31 32 33 34 35 36 37

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

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

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

86 87
#define VIR_FROM_THIS VIR_FROM_LXC

88
VIR_LOG_INIT("lxc.lxc_driver");
89

90
#define LXC_NB_MEM_PARAM  3
91
#define LXC_NB_DOMAIN_BLOCK_STAT_PARAM 4
92

93

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

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

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

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

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

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

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

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

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

169
        if (!(conn->uri = virURIParse("lxc:///")))
170
            return VIR_DRV_OPEN_ERROR;
171 172 173 174 175 176 177 178 179 180
    } else {
        if (conn->uri->scheme == NULL ||
            STRNEQ(conn->uri->scheme, "lxc"))
            return VIR_DRV_OPEN_DECLINED;

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

        /* If path isn't '/' then they typoed, tell them correct path */
181 182
        if (conn->uri->path != NULL &&
            STRNEQ(conn->uri->path, "/")) {
183 184 185
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unexpected LXC URI path '%s', try lxc:///"),
                           conn->uri->path);
186 187
            return VIR_DRV_OPEN_ERROR;
        }
D
Daniel Veillard 已提交
188

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

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

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

    return VIR_DRV_OPEN_SUCCESS;
}

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

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

214

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


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


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


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

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

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

246
    xml = virCapabilitiesFormatXML(caps);
247

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

336 337 338 339 340 341

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

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

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

348 349
    ret = virDomainObjIsActive(obj);

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


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

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

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

367 368
    ret = obj->persistent;

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

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

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

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

385 386
    ret = obj->updated;

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

450 451


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

465 466 467
    virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);

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

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

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

477 478 479
    if (virXMLCheckIllegalChars("name", def->name, "\n") < 0)
        goto cleanup;

480
    if (virDomainDefineXMLFlagsEnsureACL(conn, def) < 0)
481 482
        goto cleanup;

483 484 485
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
        goto cleanup;

486
    if ((def->nets != NULL) && !(cfg->have_netns)) {
487 488
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("System lacks NETNS support"));
489
        goto cleanup;
490 491
    }

492
    if (!(vm = virDomainObjListAdd(driver->domains, def,
493
                                   driver->xmlopt,
494
                                   0, &oldDef)))
495
        goto cleanup;
496 497

    virObjectRef(vm);
498
    def = NULL;
499
    vm->persistent = 1;
D
Daniel Veillard 已提交
500

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

507
    event = virDomainEventLifecycleNewFromObj(vm,
508
                                     VIR_DOMAIN_EVENT_DEFINED,
509
                                     !oldDef ?
510 511 512
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);

D
Daniel Veillard 已提交
513
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
514
    if (dom)
D
Daniel Veillard 已提交
515 516
        dom->id = vm->def->id;

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

528 529 530 531 532 533
static virDomainPtr
lxcDomainDefineXML(virConnectPtr conn, const char *xml)
{
    return lxcDomainDefineXMLFlags(conn, xml, 0);
}

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

543 544
    virCheckFlags(0, -1);

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

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

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

557 558
    if (virDomainDeleteConfig(cfg->configDir,
                              cfg->autostartDir,
559 560
                              vm) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
561

562
    event = virDomainEventLifecycleNewFromObj(vm,
563 564 565
                                     VIR_DOMAIN_EVENT_UNDEFINED,
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);

566 567 568
    if (virDomainObjIsActive(vm)) {
        vm->persistent = 0;
    } else {
569
        virDomainObjListRemove(driver->domains, vm);
570 571
    }

572
    ret = 0;
D
Daniel Veillard 已提交
573

574
 cleanup:
575
    virDomainObjEndAPI(&vm);
576
    if (event)
577
        virObjectEventStateQueue(driver->domainEventState, event);
578
    virObjectUnref(cfg);
579
    return ret;
D
Daniel Veillard 已提交
580 581
}

582 583 584 585 586
static int lxcDomainUndefine(virDomainPtr dom)
{
    return lxcDomainUndefineFlags(dom, 0);
}

D
Daniel Veillard 已提交
587 588 589
static int lxcDomainGetInfo(virDomainPtr dom,
                            virDomainInfoPtr info)
{
590
    virDomainObjPtr vm;
591
    int ret = -1;
592
    virLXCDomainObjPrivatePtr priv;
D
Daniel Veillard 已提交
593

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

597 598
    priv = vm->privateData;

599 600 601
    if (virDomainGetInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

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

625
    info->maxMem = virDomainDefGetMemoryTotal(vm->def);
626
    info->nrVirtCpu = virDomainDefGetVcpus(vm->def);
627
    ret = 0;
D
Daniel Veillard 已提交
628

629
 cleanup:
630
    virDomainObjEndAPI(&vm);
631
    return ret;
D
Daniel Veillard 已提交
632 633
}

634 635 636 637 638 639 640 641 642 643 644
static int
lxcDomainGetState(virDomainPtr dom,
                  int *state,
                  int *reason,
                  unsigned int flags)
{
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

M
Michal Privoznik 已提交
645
    if (!(vm = lxcDomObjFromDomain(dom)))
646 647
        goto cleanup;

648 649 650
    if (virDomainGetStateEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
651
    *state = virDomainObjGetState(vm, reason);
652 653
    ret = 0;

654
 cleanup:
655
    virDomainObjEndAPI(&vm);
656 657 658
    return ret;
}

659
static char *lxcDomainGetOSType(virDomainPtr dom)
D
Daniel Veillard 已提交
660
{
661 662
    virDomainObjPtr vm;
    char *ret = NULL;
663

M
Michal Privoznik 已提交
664
    if (!(vm = lxcDomObjFromDomain(dom)))
665
        goto cleanup;
666

667 668 669
    if (virDomainGetOSTypeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

670
    if (VIR_STRDUP(ret, virDomainOSTypeToString(vm->def->os.type)) < 0)
671
        goto cleanup;
672

673
 cleanup:
674
    virDomainObjEndAPI(&vm);
675
    return ret;
D
Daniel Veillard 已提交
676 677
}

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

M
Michal Privoznik 已提交
685
    if (!(vm = lxcDomObjFromDomain(dom)))
R
Ryota Ozaki 已提交
686 687
        goto cleanup;

688 689 690
    if (virDomainGetMaxMemoryEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

693
 cleanup:
694
    virDomainObjEndAPI(&vm);
R
Ryota Ozaki 已提交
695 696 697
    return ret;
}

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

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
710 711
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_DOMAIN_MEM_MAXIMUM, -1);
R
Ryota Ozaki 已提交
712

M
Michal Privoznik 已提交
713
    if (!(vm = lxcDomObjFromDomain(dom)))
R
Ryota Ozaki 已提交
714
        goto cleanup;
M
Michal Privoznik 已提交
715

716 717
    cfg = virLXCDriverGetConfig(driver);

718
    priv = vm->privateData;
R
Ryota Ozaki 已提交
719

720
    if (virDomainSetMemoryFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
721 722
        goto cleanup;

723
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
724 725
        goto cleanup;

726
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
727
        goto endjob;
728

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

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

748
        if (def)
749
            oldmax = virDomainDefGetMemoryTotal(def);
750
        if (persistentDef) {
751 752
            if (!oldmax || oldmax > virDomainDefGetMemoryTotal(persistentDef))
                oldmax = virDomainDefGetMemoryTotal(persistentDef);
753
        }
754

755 756 757
        if (newmem > oldmax) {
            virReportError(VIR_ERR_INVALID_ARG,
                           "%s", _("Cannot set memory higher than max memory"));
758
            goto endjob;
759 760
        }

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

768
            def->mem.cur_balloon = newmem;
769
            if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
770
                goto endjob;
771 772
        }

773
        if (persistentDef) {
774
            persistentDef->mem.cur_balloon = newmem;
775 776
            if (virDomainSaveConfig(cfg->configDir, driver->caps,
                                    persistentDef) < 0)
777
                goto endjob;
778
        }
779 780
    }

R
Ryota Ozaki 已提交
781 782
    ret = 0;

783
 endjob:
784
    virLXCDomainObjEndJob(driver, vm);
785

786
 cleanup:
787
    virDomainObjEndAPI(&vm);
788
    virObjectUnref(cfg);
R
Ryota Ozaki 已提交
789 790 791
    return ret;
}

792 793 794 795 796
static int lxcDomainSetMemory(virDomainPtr dom, unsigned long newmem)
{
    return lxcDomainSetMemoryFlags(dom, newmem, VIR_DOMAIN_AFFECT_LIVE);
}

797 798 799 800 801
static int lxcDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax)
{
    return lxcDomainSetMemoryFlags(dom, newmax, VIR_DOMAIN_MEM_MAXIMUM);
}

802 803 804 805 806
static int
lxcDomainSetMemoryParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int nparams,
                             unsigned int flags)
807
{
808
    virDomainDefPtr def = NULL;
J
Ján Tomko 已提交
809
    virDomainDefPtr persistentDef = NULL;
810
    virDomainObjPtr vm = NULL;
811 812 813 814 815 816 817 818 819 820
    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;
821 822
    int ret = -1;

823 824 825
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

826 827 828 829 830 831 832 833
    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)
834
        return -1;
E
Eric Blake 已提交
835

M
Michal Privoznik 已提交
836
    if (!(vm = lxcDomObjFromDomain(dom)))
837
        goto cleanup;
M
Michal Privoznik 已提交
838

839
    priv = vm->privateData;
840
    cfg = virLXCDriverGetConfig(driver);
841

842
    if (virDomainSetMemoryParametersEnsureACL(dom->conn, vm->def, flags) < 0)
843 844
        goto cleanup;

845 846 847
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

848 849
    /* QEMU and LXC implementation are identical */
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
850 851
        goto endjob;

852
    if (def &&
853
        !virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_MEMORY)) {
854 855
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cgroup memory controller is not mounted"));
856
        goto endjob;
857 858 859 860
    }

#define VIR_GET_LIMIT_PARAMETER(PARAM, VALUE)                                \
    if ((rc = virTypedParamsGetULLong(params, nparams, PARAM, &VALUE)) < 0)  \
861
        goto endjob;                                                         \
862 863 864 865 866 867 868 869 870 871
                                                                             \
    if (rc == 1)                                                             \
        set_ ## VALUE = true;

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

#undef VIR_GET_LIMIT_PARAMETER

872
    /* Swap hard limit must be greater than hard limit. */
873 874 875 876 877 878 879 880 881 882
    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;

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

891
#define VIR_SET_MEM_PARAMETER(FUNC, VALUE)                                      \
892
    if (set_ ## VALUE) {                                                        \
893 894
        if (def) {                                                              \
            if ((rc = FUNC(priv->cgroup, VALUE)) < 0)                           \
895
                goto endjob;                                                    \
896
            def->mem.VALUE = VALUE;                                             \
897 898
        }                                                                       \
                                                                                \
899
        if (persistentDef)                                                      \
J
Ján Tomko 已提交
900
            persistentDef->mem.VALUE = VALUE;                                   \
901 902 903
    }

    /* Soft limit doesn't clash with the others */
904
    VIR_SET_MEM_PARAMETER(virCgroupSetMemorySoftLimit, soft_limit);
905 906

    /* set hard limit before swap hard limit if decreasing it */
907 908
    if (def && def->mem.hard_limit > hard_limit) {
        VIR_SET_MEM_PARAMETER(virCgroupSetMemoryHardLimit, hard_limit);
909 910 911 912
        /* inhibit changing the limit a second time */
        set_hard_limit = false;
    }

913
    VIR_SET_MEM_PARAMETER(virCgroupSetMemSwapHardLimit, swap_hard_limit);
914 915

    /* otherwise increase it after swap hard limit */
916 917 918
    VIR_SET_MEM_PARAMETER(virCgroupSetMemoryHardLimit, hard_limit);

#undef VIR_SET_MEM_PARAMETER
919

920 921 922
    if (def &&
        virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
        goto endjob;
923

924
    if (persistentDef &&
J
Ján Tomko 已提交
925
        virDomainSaveConfig(cfg->configDir, driver->caps, persistentDef) < 0)
926
        goto endjob;
927
    /* QEMU and LXC implementations are identical */
928 929

    ret = 0;
930 931

 endjob:
932
    virLXCDomainObjEndJob(driver, vm);
933

934
 cleanup:
935
    virDomainObjEndAPI(&vm);
936
    virObjectUnref(cfg);
937 938 939
    return ret;
}

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

954
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
955 956 957 958 959
                  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 已提交
960

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

964
    priv = vm->privateData;
965

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

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

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

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

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

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

1025 1026
    if (*nparams > LXC_NB_MEM_PARAM)
        *nparams = LXC_NB_MEM_PARAM;
1027 1028
    ret = 0;

1029
 cleanup:
1030
    virDomainObjEndAPI(&vm);
1031 1032 1033
    return ret;
}

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

1041 1042
    /* Flags checked by virDomainDefFormat */

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

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

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

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

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

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

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

1083
    xml = virDomainDefFormat(def, caps, 0);
1084

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

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

1111
    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, -1);
1112

1113 1114
    virNWFilterReadLockFilterUpdates();

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

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

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

1127 1128 1129
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

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

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

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

1150
 endjob:
1151
    virLXCDomainObjEndJob(driver, vm);
1152

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

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

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

    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY |
                  VIR_DOMAIN_START_VALIDATE, NULL);

1220

1221
    if (flags & VIR_DOMAIN_START_VALIDATE)
1222
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
1223

1224 1225
    virNWFilterReadLockFilterUpdates();

1226 1227 1228 1229
    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
        goto cleanup;

    if (!(def = virDomainDefParseString(xml, caps, driver->xmlopt,
1230
                                        NULL, parse_flags)))
1231
        goto cleanup;
1232

1233
    if (virDomainCreateXMLWithFilesEnsureACL(conn, def) < 0)
1234 1235
        goto cleanup;

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

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

1245

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

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

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

1276
    event = virDomainEventLifecycleNewFromObj(vm,
1277 1278
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
1279
    virDomainAuditStart(vm, "booted", true);
1280

1281
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1282
    if (dom)
1283 1284
        dom->id = vm->def->id;

1285
    virLXCDomainObjEndJob(driver, vm);
1286

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

1298 1299 1300 1301 1302 1303 1304 1305 1306 1307
/**
 * 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.
 */
1308 1309 1310
static virDomainPtr
lxcDomainCreateXML(virConnectPtr conn,
                   const char *xml,
1311 1312
                   unsigned int flags)
{
1313 1314 1315 1316
    return lxcDomainCreateXMLWithFiles(conn, xml, 0, NULL,  flags);
}


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

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

M
Michal Privoznik 已提交
1325
    if (!(vm = lxcDomObjFromDomain(dom)))
1326 1327
        goto cleanup;

1328 1329 1330
    if (virDomainGetSecurityLabelEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

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

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

    ret = 0;

1371
 cleanup:
1372
    virDomainObjEndAPI(&vm);
1373 1374 1375 1376 1377 1378
    return ret;
}

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

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

1385 1386 1387
    if (virNodeGetSecurityModelEnsureACL(conn) < 0)
        goto cleanup;

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

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

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

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

1414
 cleanup:
1415
    virObjectUnref(caps);
1416 1417 1418 1419
    return ret;
}


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

1428 1429 1430
    if (virConnectDomainEventRegisterEnsureACL(conn) < 0)
        return -1;

1431 1432 1433 1434
    if (virDomainEventStateRegister(conn,
                                    driver->domainEventState,
                                    callback, opaque, freecb) < 0)
        return -1;
1435

1436
    return 0;
1437 1438
}

1439

1440
static int
1441 1442
lxcConnectDomainEventDeregister(virConnectPtr conn,
                                virConnectDomainEventCallback callback)
1443
{
1444
    virLXCDriverPtr driver = conn->privateData;
1445

1446 1447 1448
    if (virConnectDomainEventDeregisterEnsureACL(conn) < 0)
        return -1;

1449 1450 1451 1452
    if (virDomainEventStateDeregister(conn,
                                      driver->domainEventState,
                                      callback) < 0)
        return -1;
1453

1454
    return 0;
1455 1456
}

1457 1458

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

1469 1470 1471
    if (virConnectDomainEventRegisterAnyEnsureACL(conn) < 0)
        return -1;

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

    return ret;
}


static int
1483 1484
lxcConnectDomainEventDeregisterAny(virConnectPtr conn,
                                   int callbackID)
1485
{
1486
    virLXCDriverPtr driver = conn->privateData;
1487

1488 1489 1490
    if (virConnectDomainEventDeregisterAnyEnsureACL(conn) < 0)
        return -1;

1491 1492 1493 1494
    if (virObjectEventStateDeregisterID(conn,
                                        driver->domainEventState,
                                        callbackID) < 0)
        return -1;
1495

1496
    return 0;
1497 1498 1499
}


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

1519 1520
    virCheckFlags(0, -1);

M
Michal Privoznik 已提交
1521
    if (!(vm = lxcDomObjFromDomain(dom)))
1522
        goto cleanup;
1523

1524 1525 1526
    if (virDomainDestroyFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1527 1528 1529
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

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

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

1544
 endjob:
1545
    virLXCDomainObjEndJob(driver, vm);
1546 1547
    if (!vm->persistent)
        virDomainObjListRemove(driver->domains, vm);
1548

1549
 cleanup:
1550
    virDomainObjEndAPI(&vm);
1551
    if (event)
1552
        virObjectEventStateQueue(driver->domainEventState, event);
1553
    return ret;
1554
}
1555

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

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

1575
    if (virRun(argv, &ip_rc) < 0 || ip_rc == 255)
1576
        return 0;
1577

1578 1579
    if (lxcContainerAvailable(LXC_CONTAINER_FEATURE_NET) < 0)
        return 0;
1580

1581
    return 1;
1582 1583
}

1584

1585 1586
static virSecurityManagerPtr
lxcSecurityInit(virLXCDriverConfigPtr cfg)
1587
{
1588 1589
    unsigned int flags = VIR_SECURITY_MANAGER_PRIVILEGED;

1590
    VIR_INFO("lxcSecurityInit %s", cfg->securityDriverName);
1591 1592 1593 1594 1595 1596

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

1597
    virSecurityManagerPtr mgr = virSecurityManagerNew(cfg->securityDriverName,
1598
                                                      LXC_DRIVER_NAME, flags);
1599 1600 1601
    if (!mgr)
        goto error;

1602
    return mgr;
1603

1604
 error:
1605
    VIR_ERROR(_("Failed to initialize security drivers"));
1606
    virObjectUnref(mgr);
1607
    return NULL;
1608 1609 1610
}


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

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

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

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

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

1648
    if (!(lxc_driver->domains = virDomainObjListNew()))
1649 1650
        goto cleanup;

1651
    lxc_driver->domainEventState = virObjectEventStateNew();
1652
    if (!lxc_driver->domainEventState)
1653 1654
        goto cleanup;

1655 1656
    lxc_driver->hostsysinfo = virSysinfoRead();

1657 1658 1659 1660 1661
    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 已提交
1662 1663

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

1667
    if (!(lxc_driver->securityManager = lxcSecurityInit(cfg)))
1668 1669
        goto cleanup;

1670
    if (!(lxc_driver->hostdevMgr = virHostdevManagerGetDefault()))
G
Guido Günther 已提交
1671 1672
        goto cleanup;

1673
    if ((virLXCDriverGetCapabilities(lxc_driver, true)) == NULL)
1674
        goto cleanup;
D
Daniel Veillard 已提交
1675

1676
    if (!(lxc_driver->xmlopt = lxcDomainXMLConfInit()))
1677
        goto cleanup;
1678

1679
    if (!(lxc_driver->closeCallbacks = virCloseCallbacksNew()))
1680 1681
        goto cleanup;

1682 1683 1684
    if (!(caps = virLXCDriverGetCapabilities(lxc_driver, false)))
        goto cleanup;

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

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

1701
    virLXCProcessReconnectAll(lxc_driver, lxc_driver->domains);
O
Osier Yang 已提交
1702 1703

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

1712
    virNWFilterRegisterCallbackDriver(&lxcCallbackDriver);
D
Daniel Veillard 已提交
1713 1714
    return 0;

1715
 cleanup:
1716
    virObjectUnref(caps);
1717
    lxcStateCleanup();
1718
    return -1;
D
Daniel Veillard 已提交
1719 1720
}

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

    virLXCProcessAutostartAll(lxc_driver);
}

1734 1735
static void lxcNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
{
1736
    virLXCDriverPtr driver = opaque;
1737 1738

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

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

1760 1761 1762
    if (!lxc_driver)
        return 0;

1763
    if (!(caps = virLXCDriverGetCapabilities(lxc_driver, false)))
1764 1765
        return -1;

1766 1767
    cfg = virLXCDriverGetConfig(lxc_driver);

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

1779
static int lxcStateCleanup(void)
D
Daniel Veillard 已提交
1780
{
1781
    if (lxc_driver == NULL)
1782
        return -1;
1783

1784
    virNWFilterUnRegisterCallbackDriver(&lxcCallbackDriver);
1785
    virObjectUnref(lxc_driver->domains);
1786
    virObjectUnref(lxc_driver->domainEventState);
1787

1788
    virObjectUnref(lxc_driver->closeCallbacks);
1789

1790 1791
    virSysinfoDefFree(lxc_driver->hostsysinfo);

1792
    virObjectUnref(lxc_driver->hostdevMgr);
1793
    virObjectUnref(lxc_driver->caps);
1794
    virObjectUnref(lxc_driver->securityManager);
1795
    virObjectUnref(lxc_driver->xmlopt);
1796
    virObjectUnref(lxc_driver->config);
1797
    virMutexDestroy(&lxc_driver->lock);
1798
    VIR_FREE(lxc_driver);
1799 1800 1801

    return 0;
}
D
Daniel Veillard 已提交
1802

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

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

D
Daniel Veillard 已提交
1817

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

1822
    uname(&ver);
D
Dan Smith 已提交
1823

1824 1825 1826
    if (virConnectGetVersionEnsureACL(conn) < 0)
        return -1;

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

    return 0;
}
1834

1835

1836
static char *lxcConnectGetHostname(virConnectPtr conn)
1837
{
1838 1839 1840
    if (virConnectGetHostnameEnsureACL(conn) < 0)
        return NULL;

1841 1842 1843 1844
    return virGetHostname();
}


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

M
Michal Privoznik 已提交
1852
    if (!(vm = lxcDomObjFromDomain(dom)))
1853
        goto cleanup;
M
Michal Privoznik 已提交
1854

1855 1856
    priv = vm->privateData;

1857 1858 1859
    if (virDomainGetSchedulerTypeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

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

1874
    if (nparams) {
1875
        if (virCgroupSupportsCpuBW(priv->cgroup))
1876
            *nparams = 3;
1877 1878
        else
            *nparams = 1;
1879
    }
1880

1881
    ignore_value(VIR_STRDUP(ret, "posix"));
1882

1883
 cleanup:
1884
    virDomainObjEndAPI(&vm);
1885 1886 1887 1888 1889 1890 1891 1892
    return ret;
}


static int
lxcGetVcpuBWLive(virCgroupPtr cgroup, unsigned long long *period,
                 long long *quota)
{
1893
    if (virCgroupGetCpuCfsPeriod(cgroup, period) < 0)
1894 1895
        return -1;

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

1916
        if (virCgroupSetCpuCfsPeriod(cgroup, period) < 0)
1917 1918 1919 1920
            return -1;
    }

    if (quota) {
1921 1922
        if (virCgroupSetCpuCfsQuota(cgroup, quota) < 0)
            goto error;
1923 1924 1925 1926
    }

    return 0;

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

    return -1;
1938 1939
}

1940

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

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

M
Michal Privoznik 已提交
1971
    if (!(vm = lxcDomObjFromDomain(dom)))
1972
        goto cleanup;
M
Michal Privoznik 已提交
1973

1974
    priv = vm->privateData;
1975

1976 1977 1978
    if (virDomainSetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

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

1982 1983 1984
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

1985
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
1986
        goto endjob;
1987

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

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

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

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

2012
                if (virCgroupGetCpuShares(priv->cgroup, &val) < 0)
2013
                    goto endjob;
2014

2015 2016
                def->cputune.shares = val;
                def->cputune.sharesSpecified = true;
2017 2018
            }

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

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

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

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

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

2050
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
2051
        goto endjob;
2052

2053

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

J
Ján Tomko 已提交
2059 2060
        virDomainObjAssignDef(vm, persistentDefCopy, false, NULL);
        persistentDefCopy = NULL;
2061
    }
2062

2063
    ret = 0;
2064

2065
 endjob:
2066
    virLXCDomainObjEndJob(driver, vm);
2067

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

2076
static int
2077 2078 2079
lxcDomainSetSchedulerParameters(virDomainPtr domain,
                                virTypedParameterPtr params,
                                int nparams)
2080
{
2081
    return lxcDomainSetSchedulerParametersFlags(domain, params, nparams, 0);
2082 2083 2084
}

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

2102
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
2103 2104 2105 2106 2107
                  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;
2108

M
Michal Privoznik 已提交
2109
    if (!(vm = lxcDomObjFromDomain(dom)))
2110
        goto cleanup;
M
Michal Privoznik 已提交
2111

2112 2113
    priv = vm->privateData;

2114 2115 2116
    if (virDomainGetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2117 2118
    if (*nparams > 1)
        cpu_bw_status = virCgroupSupportsCpuBW(priv->cgroup);
2119

2120
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
E
Eric Blake 已提交
2121
        goto cleanup;
2122

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

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

2139
    if (virCgroupGetCpuShares(priv->cgroup, &shares) < 0)
2140
        goto cleanup;
2141 2142

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

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

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

    *nparams = saved_nparams;

2173
    ret = 0;
2174

2175
 cleanup:
2176
    virDomainObjEndAPI(&vm);
2177
    return ret;
2178 2179
}

2180
static int
2181 2182 2183
lxcDomainGetSchedulerParameters(virDomainPtr domain,
                                virTypedParameterPtr params,
                                int *nparams)
2184
{
2185
    return lxcDomainGetSchedulerParametersFlags(domain, params, nparams, 0);
2186 2187
}

2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215
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))
2216
        goto parse_error;
2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230

    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)
2231
            goto parse_error;
2232 2233 2234 2235 2236 2237 2238 2239

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

        /* value */
        temp = p + 1;

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

        i++;

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

    if (!i)
        VIR_FREE(result);

    *dev = result;
    *size = i;

    return 0;

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

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

2288
 cleanup:
J
John Ferlan 已提交
2289 2290 2291 2292
    if (result) {
        virBlkioDeviceArrayClear(result, ndevices);
        VIR_FREE(result);
    }
2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314
    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;

2315
                if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
2316
                    dest->weight = src->weight;
2317
                } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS)) {
2318
                    dest->riops = src->riops;
2319
                } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS)) {
2320
                    dest->wiops = src->wiops;
2321
                } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS)) {
2322
                    dest->rbps = src->rbps;
2323
                } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
2324
                    dest->wbps = src->wbps;
2325
                } else {
2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340
                    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];

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

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

    return 0;
}

2364

2365 2366 2367
static int
lxcDomainBlockStats(virDomainPtr dom,
                    const char *path,
2368
                    virDomainBlockStatsPtr stats)
2369
{
2370
    virLXCDriverPtr driver = dom->conn->privateData;
2371
    int ret = -1;
2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383
    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;

2384 2385 2386
   if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_QUERY) < 0)
        goto cleanup;

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

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

    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);
2406
        goto endjob;
2407 2408
    }

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

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

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

 endjob:
2429
    virLXCDomainObjEndJob(driver, vm);
2430

2431
 cleanup:
2432
    virDomainObjEndAPI(&vm);
2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443
    return ret;
}


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

    virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);

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

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

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

    priv = vm->privateData;

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

2470 2471 2472
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_QUERY) < 0)
        goto cleanup;

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

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

    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"));
2494
            goto endjob;
2495 2496
        }
    } else {
2497
        if (!(disk = virDomainDiskByName(vm->def, path, false))) {
2498 2499
            virReportError(VIR_ERR_INVALID_ARG,
                           _("invalid path: %s"), path);
2500
            goto endjob;
2501 2502 2503 2504 2505
        }

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

        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"));
2517
            goto endjob;
2518 2519 2520 2521 2522 2523 2524 2525 2526 2527
        }
    }

    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)
2528
            goto endjob;
2529 2530 2531 2532 2533 2534 2535
        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)
2536
            goto endjob;
2537 2538 2539 2540 2541 2542 2543
        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)
2544
            goto endjob;
2545 2546 2547 2548 2549 2550 2551
        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)
2552
            goto endjob;
2553 2554 2555 2556 2557 2558
        tmp++;
    }

    ret = 0;
    *nparams = tmp;

2559
 endjob:
2560
    virLXCDomainObjEndJob(driver, vm);
2561

2562
 cleanup:
2563
    virDomainObjEndAPI(&vm);
2564 2565 2566 2567
    return ret;
}


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

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
2585 2586 2587
    if (virTypedParamsValidate(params, nparams,
                               VIR_DOMAIN_BLKIO_WEIGHT,
                               VIR_TYPED_PARAM_UINT,
2588 2589 2590 2591 2592 2593 2594 2595 2596 2597
                               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,
2598
                               NULL) < 0)
2599 2600
        return -1;

M
Michal Privoznik 已提交
2601
    if (!(vm = lxcDomObjFromDomain(dom)))
2602
        return -1;
M
Michal Privoznik 已提交
2603

2604
    priv = vm->privateData;
2605
    cfg = virLXCDriverGetConfig(driver);
2606

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

2610 2611 2612
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

2613
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
2614
        goto endjob;
2615

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

2624
    ret = 0;
2625
    if (def) {
2626 2627 2628 2629
        for (i = 0; i < nparams; i++) {
            virTypedParameterPtr param = &params[i];

            if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
2630
                if (virCgroupSetBlkioWeight(priv->cgroup, params[i].value.ui) < 0)
2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652
                    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,
2653 2654 2655 2656
                                                          devices[j].weight) < 0 ||
                            virCgroupGetBlkioDeviceWeight(priv->cgroup,
                                                          devices[j].path,
                                                          &devices[j].weight) < 0) {
2657 2658 2659 2660 2661 2662 2663 2664
                            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,
2665 2666 2667 2668
                                                            devices[j].riops) < 0 ||
                            virCgroupGetBlkioDeviceReadIops(priv->cgroup,
                                                            devices[j].path,
                                                            &devices[j].riops) < 0) {
2669 2670 2671 2672 2673 2674 2675 2676
                            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,
2677 2678 2679 2680
                                                             devices[j].wiops) < 0 ||
                            virCgroupGetBlkioDeviceWriteIops(priv->cgroup,
                                                             devices[j].path,
                                                             &devices[j].wiops) < 0) {
2681 2682 2683 2684 2685 2686 2687 2688
                            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,
2689 2690 2691 2692
                                                           devices[j].rbps) < 0 ||
                            virCgroupGetBlkioDeviceReadBps(priv->cgroup,
                                                           devices[j].path,
                                                           &devices[j].rbps) < 0) {
2693 2694 2695 2696
                            ret = -1;
                            break;
                        }
                    }
2697
                } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
2698 2699 2700
                    for (j = 0; j < ndevices; j++) {
                        if (virCgroupSetBlkioDeviceWriteBps(priv->cgroup,
                                                            devices[j].path,
2701 2702 2703 2704
                                                            devices[j].wbps) < 0 ||
                            virCgroupGetBlkioDeviceWriteBps(priv->cgroup,
                                                            devices[j].path,
                                                            &devices[j].wbps) < 0) {
2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719
                            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 ||
2720 2721
                    lxcDomainMergeBlkioDevice(&def->blkio.devices,
                                              &def->blkio.ndevices,
2722 2723 2724 2725
                                              devices, ndevices, param->field) < 0)
                    ret = -1;
                virBlkioDeviceArrayClear(devices, ndevices);
                VIR_FREE(devices);
2726 2727
            }
        }
E
Eric Blake 已提交
2728
    }
2729
    if (ret < 0)
2730
        goto endjob;
2731
    if (persistentDef) {
2732 2733 2734 2735 2736
        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;
2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757
            } 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);
2758 2759 2760
            }
        }

2761
        if (virDomainSaveConfig(cfg->configDir, driver->caps, persistentDef) < 0)
2762
            ret = -1;
2763 2764
    }

2765
 endjob:
2766
    virLXCDomainObjEndJob(driver, vm);
2767

2768
 cleanup:
2769
    virDomainObjEndAPI(&vm);
2770
    virObjectUnref(cfg);
2771 2772 2773 2774
    return ret;
}


2775 2776
#define LXC_NB_BLKIO_PARAM  6

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

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
2792 2793 2794 2795 2796 2797 2798
                  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;
2799

M
Michal Privoznik 已提交
2800
    if (!(vm = lxcDomObjFromDomain(dom)))
2801
        return -1;
M
Michal Privoznik 已提交
2802

2803
    priv = vm->privateData;
2804

2805 2806 2807
    if (virDomainGetBlkioParametersEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

2817 2818
    *nparams = 0;

2819
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
E
Eric Blake 已提交
2820
        goto cleanup;
2821

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

2829 2830 2831 2832 2833 2834 2835
        /* 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;
2836

2837 2838 2839
        if (virDomainGetBlkioParametersAssignFromDef(def, params, nparams,
                                                     maxparams) < 0)
            goto cleanup;
2840

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

2849 2850 2851
        if (virDomainGetBlkioParametersAssignFromDef(persistentDef, params,
                                                     nparams, maxparams) < 0)
            goto cleanup;
2852 2853 2854 2855
    }

    ret = 0;

2856
 cleanup:
2857
    virDomainObjEndAPI(&vm);
2858 2859 2860 2861
    return ret;
}


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

M
Michal Privoznik 已提交
2873
    if (!(vm = lxcDomObjFromDomain(dom)))
2874 2875
        goto cleanup;

2876 2877 2878
    if (virDomainInterfaceStatsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2879 2880 2881
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_QUERY) < 0)
        goto cleanup;

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

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

    if (ret == 0)
2898
        ret = virNetDevTapInterfaceStats(path, stats);
2899
    else
2900 2901
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Invalid path, '%s' is not a known interface"), path);
2902

2903
 endjob:
2904
    virLXCDomainObjEndJob(driver, vm);
2905

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

2921
static int lxcDomainGetAutostart(virDomainPtr dom,
2922 2923
                                   int *autostart)
{
2924 2925 2926
    virDomainObjPtr vm;
    int ret = -1;

M
Michal Privoznik 已提交
2927
    if (!(vm = lxcDomObjFromDomain(dom)))
2928 2929
        goto cleanup;

2930 2931 2932
    if (virDomainGetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2933 2934 2935
    *autostart = vm->autostart;
    ret = 0;

2936
 cleanup:
2937
    virDomainObjEndAPI(&vm);
2938 2939 2940 2941
    return ret;
}

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

M
Michal Privoznik 已提交
2950
    if (!(vm = lxcDomObjFromDomain(dom)))
2951 2952
        goto cleanup;

2953 2954 2955
    if (virDomainSetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2956 2957 2958
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

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

    autostart = (autostart != 0);

2967 2968
    if (vm->autostart == autostart) {
        ret = 0;
2969
        goto endjob;
2970
    }
2971

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

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

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

    vm->autostart = autostart;
3005 3006
    ret = 0;

3007
 endjob:
3008 3009
    virLXCDomainObjEndJob(driver, vm);

3010
 cleanup:
3011 3012
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
3013
    virDomainObjEndAPI(&vm);
3014
    virObjectUnref(cfg);
3015 3016 3017
    return ret;
}

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

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

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

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

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

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

3099
 cleanup:
R
Ryota Ozaki 已提交
3100 3101 3102 3103 3104 3105
    VIR_FREE(state);
    return ret;
}

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

M
Michal Privoznik 已提交
3112
    if (!(vm = lxcDomObjFromDomain(dom)))
R
Ryota Ozaki 已提交
3113 3114
        goto cleanup;

3115 3116 3117
    if (virDomainSuspendEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3118 3119 3120
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

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

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

3135
        event = virDomainEventLifecycleNewFromObj(vm,
R
Ryota Ozaki 已提交
3136 3137 3138 3139
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
    }

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

3144
 endjob:
3145 3146
    virLXCDomainObjEndJob(driver, vm);

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

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

M
Michal Privoznik 已提交
3165
    if (!(vm = lxcDomObjFromDomain(dom)))
R
Ryota Ozaki 已提交
3166 3167
        goto cleanup;

3168 3169
    priv = vm->privateData;

3170 3171 3172
    if (virDomainResumeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3173 3174 3175
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

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

3182 3183 3184 3185 3186 3187
    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) {
3188
        if (virCgroupSetFreezerState(priv->cgroup, "THAWED") < 0) {
3189 3190
            virReportError(VIR_ERR_OPERATION_FAILED,
                           "%s", _("Resume operation failed"));
3191
            goto endjob;
R
Ryota Ozaki 已提交
3192
        }
J
Jiri Denemark 已提交
3193 3194
        virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
                             VIR_DOMAIN_RUNNING_UNPAUSED);
R
Ryota Ozaki 已提交
3195

3196
        event = virDomainEventLifecycleNewFromObj(vm,
R
Ryota Ozaki 已提交
3197 3198 3199 3200
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
    }

3201
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
3202
        goto endjob;
R
Ryota Ozaki 已提交
3203 3204
    ret = 0;

3205
 endjob:
3206 3207
    virLXCDomainObjEndJob(driver, vm);

3208
 cleanup:
R
Ryota Ozaki 已提交
3209
    if (event)
3210
        virObjectEventStateQueue(driver->domainEventState, event);
3211
    virDomainObjEndAPI(&vm);
3212
    virObjectUnref(cfg);
R
Ryota Ozaki 已提交
3213 3214 3215
    return ret;
}

3216 3217
static int
lxcDomainOpenConsole(virDomainPtr dom,
3218
                      const char *dev_name,
3219 3220 3221 3222 3223 3224
                      virStreamPtr st,
                      unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainChrDefPtr chr = NULL;
3225
    size_t i;
3226 3227 3228

    virCheckFlags(0, -1);

M
Michal Privoznik 已提交
3229
    if (!(vm = lxcDomObjFromDomain(dom)))
3230 3231
        goto cleanup;

3232 3233 3234
    if (virDomainOpenConsoleEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3235
    if (!virDomainObjIsActive(vm)) {
3236 3237
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
3238 3239 3240
        goto cleanup;
    }

3241
    if (dev_name) {
3242
        for (i = 0; i < vm->def->nconsoles; i++) {
3243 3244 3245 3246 3247 3248
            if (vm->def->consoles[i]->info.alias &&
                STREQ(vm->def->consoles[i]->info.alias, dev_name)) {
                chr = vm->def->consoles[i];
                break;
            }
        }
3249
    } else {
3250 3251
        if (vm->def->nconsoles)
            chr = vm->def->consoles[0];
3252 3253 3254 3255 3256
        else if (vm->def->nserials)
            chr = vm->def->serials[0];
    }

    if (!chr) {
3257 3258 3259
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot find console device '%s'"),
                       dev_name ? dev_name : _("default"));
3260 3261 3262
        goto cleanup;
    }

3263
    if (chr->source->type != VIR_DOMAIN_CHR_TYPE_PTY) {
3264
        virReportError(VIR_ERR_INTERNAL_ERROR,
3265 3266
                       _("character device %s is not using a PTY"),
                       dev_name ? dev_name : NULLSTR(chr->info.alias));
3267 3268 3269
        goto cleanup;
    }

3270
    if (virFDStreamOpenFile(st, chr->source->data.file.path,
E
Eric Blake 已提交
3271
                            0, 0, O_RDWR) < 0)
3272 3273 3274
        goto cleanup;

    ret = 0;
3275
 cleanup:
3276
    virDomainObjEndAPI(&vm);
3277 3278 3279
    return ret;
}

3280 3281 3282 3283 3284 3285 3286

static int
lxcDomainSendProcessSignal(virDomainPtr dom,
                           long long pid_value,
                           unsigned int signum,
                           unsigned int flags)
{
3287
    virLXCDriverPtr driver = dom->conn->privateData;
3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301
    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 已提交
3302
    if (!(vm = lxcDomObjFromDomain(dom)))
3303
        goto cleanup;
M
Michal Privoznik 已提交
3304

3305 3306
    priv = vm->privateData;

3307 3308 3309
    if (virDomainSendProcessSignalEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3310 3311 3312
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

3313 3314 3315
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
3316
        goto endjob;
3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328
    }

    /*
     * 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"));
3329
        goto endjob;
3330 3331 3332 3333 3334
    }

    if (!priv->initpid) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Init pid is not yet available"));
3335
        goto endjob;
3336 3337 3338 3339 3340 3341 3342 3343 3344 3345
    }
    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);
3346
        goto endjob;
3347 3348 3349 3350
    }

    ret = 0;

3351
 endjob:
3352
    virLXCDomainObjEndJob(driver, vm);
3353

3354
 cleanup:
3355
    virDomainObjEndAPI(&vm);
3356 3357 3358 3359
    return ret;
}


3360
static int
3361 3362
lxcConnectListAllDomains(virConnectPtr conn,
                         virDomainPtr **domains,
3363 3364
                  unsigned int flags)
{
3365
    virLXCDriverPtr driver = conn->privateData;
3366 3367
    int ret = -1;

O
Osier Yang 已提交
3368
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
3369

3370 3371 3372
    if (virConnectListAllDomainsEnsureACL(conn) < 0)
        return -1;

3373 3374
    ret = virDomainObjListExport(driver->domains, conn, domains,
                                 virConnectListAllDomainsCheckACL, flags);
3375 3376 3377
    return ret;
}

3378

3379 3380 3381 3382 3383 3384 3385 3386 3387
static int
lxcDomainInitctlCallback(pid_t pid ATTRIBUTE_UNUSED,
                         void *opaque)
{
    int *command = opaque;
    return virInitctlSetRunLevel(*command);
}


3388 3389 3390 3391
static int
lxcDomainShutdownFlags(virDomainPtr dom,
                       unsigned int flags)
{
3392
    virLXCDriverPtr driver = dom->conn->privateData;
3393 3394 3395
    virLXCDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
    int ret = -1;
3396
    int rc;
3397 3398 3399 3400

    virCheckFlags(VIR_DOMAIN_SHUTDOWN_INITCTL |
                  VIR_DOMAIN_SHUTDOWN_SIGNAL, -1);

M
Michal Privoznik 已提交
3401
    if (!(vm = lxcDomObjFromDomain(dom)))
3402 3403 3404 3405
        goto cleanup;

    priv = vm->privateData;

3406
    if (virDomainShutdownFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
3407 3408
        goto cleanup;

3409 3410 3411
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

3412 3413 3414
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not running"));
3415
        goto endjob;
3416 3417 3418 3419 3420
    }

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

3424 3425
    if (flags == 0 ||
        (flags & VIR_DOMAIN_SHUTDOWN_INITCTL)) {
3426 3427 3428 3429 3430
        int command = VIR_INITCTL_RUNLEVEL_POWEROFF;

        if ((rc = virProcessRunInMountNamespace(priv->initpid,
                                                lxcDomainInitctlCallback,
                                                &command)) < 0)
3431
            goto endjob;
3432 3433
        if (rc == 0 && flags != 0 &&
            ((flags & ~VIR_DOMAIN_SHUTDOWN_INITCTL) == 0)) {
3434 3435
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                           _("Container does not provide an initctl pipe"));
3436
            goto endjob;
3437
        }
3438 3439
    } else {
        rc = 0;
3440
    }
3441

3442 3443 3444
    if (rc == 0 &&
        (flags == 0 ||
         (flags & VIR_DOMAIN_SHUTDOWN_SIGNAL))) {
3445 3446
        if (kill(priv->initpid, SIGTERM) < 0 &&
            errno != ESRCH) {
3447 3448
            virReportSystemError(errno,
                                 _("Unable to send SIGTERM to init pid %llu"),
M
Michal Privoznik 已提交
3449
                                 (long long) priv->initpid);
3450
            goto endjob;
3451 3452 3453 3454 3455
        }
    }

    ret = 0;

3456
 endjob:
3457
    virLXCDomainObjEndJob(driver, vm);
3458

3459
 cleanup:
3460
    virDomainObjEndAPI(&vm);
3461 3462 3463 3464 3465 3466 3467 3468 3469
    return ret;
}

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

3470

3471 3472 3473 3474
static int
lxcDomainReboot(virDomainPtr dom,
                unsigned int flags)
{
3475
    virLXCDriverPtr driver = dom->conn->privateData;
3476 3477 3478 3479 3480 3481 3482 3483
    virLXCDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
    int ret = -1;
    int rc;

    virCheckFlags(VIR_DOMAIN_REBOOT_INITCTL |
                  VIR_DOMAIN_REBOOT_SIGNAL, -1);

M
Michal Privoznik 已提交
3484
    if (!(vm = lxcDomObjFromDomain(dom)))
3485 3486 3487 3488
        goto cleanup;

    priv = vm->privateData;

3489
    if (virDomainRebootEnsureACL(dom->conn, vm->def, flags) < 0)
3490 3491
        goto cleanup;

3492 3493 3494
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

3495 3496 3497
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not running"));
3498
        goto endjob;
3499 3500 3501 3502 3503
    }

    if (priv->initpid == 0) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Init process ID is not yet known"));
3504
        goto endjob;
3505 3506 3507 3508
    }

    if (flags == 0 ||
        (flags & VIR_DOMAIN_REBOOT_INITCTL)) {
3509 3510 3511 3512 3513
        int command = VIR_INITCTL_RUNLEVEL_REBOOT;

        if ((rc = virProcessRunInMountNamespace(priv->initpid,
                                                lxcDomainInitctlCallback,
                                                &command)) < 0)
3514
            goto endjob;
3515 3516 3517 3518
        if (rc == 0 && flags != 0 &&
            ((flags & ~VIR_DOMAIN_SHUTDOWN_INITCTL) == 0)) {
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                           _("Container does not provide an initctl pipe"));
3519
            goto endjob;
3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531
        }
    } 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"),
M
Michal Privoznik 已提交
3532
                                 (long long) priv->initpid);
3533
            goto endjob;
3534 3535 3536 3537 3538
        }
    }

    ret = 0;

3539
 endjob:
3540
    virLXCDomainObjEndJob(driver, vm);
3541

3542
 cleanup:
3543
    virDomainObjEndAPI(&vm);
3544 3545 3546 3547
    return ret;
}


3548
static int
3549
lxcDomainAttachDeviceConfig(virDomainDefPtr vmdef,
3550 3551 3552
                            virDomainDeviceDefPtr dev)
{
    int ret = -1;
3553
    virDomainDiskDefPtr disk;
3554
    virDomainNetDefPtr net;
3555
    virDomainHostdevDefPtr hostdev;
3556 3557

    switch (dev->type) {
3558 3559 3560 3561 3562 3563 3564
    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;
        }
3565
        if (virDomainDiskInsert(vmdef, disk))
3566 3567 3568 3569 3570 3571
            return -1;
        /* vmdef has the pointer. Generic codes for vmdef will do all jobs */
        dev->data.disk = NULL;
        ret = 0;
        break;

3572 3573
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
3574
        if (virDomainNetInsert(vmdef, net) < 0)
3575 3576 3577 3578 3579
            goto cleanup;
        dev->data.net = NULL;
        ret = 0;
        break;

3580 3581 3582 3583 3584 3585 3586
    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;
        }
3587
        if (virDomainHostdevInsert(vmdef, hostdev) < 0)
3588 3589 3590 3591 3592
            return -1;
        dev->data.hostdev = NULL;
        ret = 0;
        break;

3593 3594 3595 3596 3597 3598
    default:
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                        _("persistent attach of device is not supported"));
         break;
    }

3599
 cleanup:
3600 3601 3602 3603 3604
    return ret;
}


static int
3605
lxcDomainUpdateDeviceConfig(virDomainDefPtr vmdef,
3606 3607 3608
                            virDomainDeviceDefPtr dev)
{
    int ret = -1;
3609 3610
    virDomainNetDefPtr net;
    int idx;
3611 3612

    switch (dev->type) {
3613 3614
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
3615
        if ((idx = virDomainNetFindIdx(vmdef, net)) < 0)
3616 3617 3618 3619 3620 3621 3622 3623 3624 3625
            goto cleanup;

        virDomainNetDefFree(vmdef->nets[idx]);

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

        break;

3626 3627 3628 3629 3630 3631
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("persistent update of device is not supported"));
        break;
    }

3632
 cleanup:
3633 3634 3635 3636 3637
    return ret;
}


static int
3638
lxcDomainDetachDeviceConfig(virDomainDefPtr vmdef,
3639 3640 3641
                            virDomainDeviceDefPtr dev)
{
    int ret = -1;
3642
    virDomainDiskDefPtr disk, det_disk;
3643
    virDomainNetDefPtr net;
3644
    virDomainHostdevDefPtr hostdev, det_hostdev;
3645
    int idx;
3646 3647

    switch (dev->type) {
3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658
    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;

3659 3660
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
3661
        if ((idx = virDomainNetFindIdx(vmdef, net)) < 0)
3662
            goto cleanup;
3663

3664 3665 3666 3667 3668
        /* this is guaranteed to succeed */
        virDomainNetDefFree(virDomainNetRemove(vmdef, idx));
        ret = 0;
        break;

3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681
    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;
    }

3682 3683 3684 3685 3686 3687
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("persistent detach of device is not supported"));
        break;
    }

3688
 cleanup:
3689 3690 3691 3692
    return ret;
}


3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740
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;
3741 3742
        char *tmpsrc = def->src->path;
        def->src->path = data->file;
3743 3744
        if (virSecurityManagerSetDiskLabel(data->driver->securityManager,
                                           data->vm->def, def) < 0) {
3745
            def->src->path = tmpsrc;
3746 3747
            goto cleanup;
        }
3748
        def->src->path = tmpsrc;
3749 3750
    }   break;

3751 3752 3753 3754 3755 3756 3757
    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;

3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808
    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;
}


3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841
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;
}


3842 3843 3844 3845 3846 3847 3848 3849 3850
static int
lxcDomainAttachDeviceDiskLive(virLXCDriverPtr driver,
                              virDomainObjPtr vm,
                              virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainDiskDefPtr def = dev->data.disk;
    int ret = -1;
    struct stat sb;
3851 3852
    char *file = NULL;
    int perms;
3853
    const char *src = NULL;
3854 3855 3856 3857 3858 3859 3860

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

3861 3862 3863 3864 3865 3866
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        goto cleanup;
    }

3867 3868
    src = virDomainDiskGetSource(def);
    if (src == NULL) {
3869 3870 3871 3872 3873
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Can't setup disk without media"));
        goto cleanup;
    }

3874 3875 3876 3877 3878 3879
    if (!virStorageSourceIsBlockLocal(def->src)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Can't setup disk for non-block device"));
        goto cleanup;
    }

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

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

3892
    if (!S_ISBLK(sb.st_mode)) {
3893
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3894
                       _("Disk source %s must be a block device"),
3895
                       src);
3896 3897 3898
        goto cleanup;
    }

3899
    perms = (def->src->readonly ?
3900 3901 3902
             VIR_CGROUP_DEVICE_READ :
             VIR_CGROUP_DEVICE_RW) |
        VIR_CGROUP_DEVICE_MKNOD;
3903

3904 3905 3906 3907 3908
    if (virCgroupAllowDevice(priv->cgroup,
                             'b',
                             major(sb.st_rdev),
                             minor(sb.st_rdev),
                             perms) < 0)
3909
        goto cleanup;
3910

3911
    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks + 1) < 0)
3912 3913
        goto cleanup;

3914 3915
    if (virAsprintf(&file,
                    "/dev/%s", def->dst) < 0)
3916 3917
        goto cleanup;

3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929
    if (lxcDomainAttachDeviceMknod(driver,
                                   0700 | S_IFBLK,
                                   sb.st_rdev,
                                   vm,
                                   dev,
                                   file) < 0) {
        if (virCgroupDenyDevice(priv->cgroup,
                                'b',
                                major(sb.st_rdev),
                                minor(sb.st_rdev),
                                perms) < 0)
            VIR_WARN("cannot deny device %s for domain %s",
3930
                     src, vm->def->name);
3931 3932 3933 3934 3935 3936 3937
        goto cleanup;
    }

    virDomainDiskInsertPreAlloced(vm->def, def);

    ret = 0;

3938
 cleanup:
3939
    if (src)
3940
        virDomainAuditDisk(vm, NULL, def->src, "attach", ret == 0);
3941
    VIR_FREE(file);
3942 3943 3944 3945
    return ret;
}


3946
/* XXX conn required for network -> bridge resolution */
3947
static int
3948 3949 3950 3951 3952 3953
lxcDomainAttachDeviceNetLive(virConnectPtr conn,
                             virDomainObjPtr vm,
                             virDomainNetDefPtr net)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    int ret = -1;
3954
    virDomainNetType actualType;
3955
    virNetDevBandwidthPtr actualBandwidth;
3956 3957 3958 3959 3960
    char *veth = NULL;

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

3964 3965 3966
    if (virLXCProcessValidateInterface(net) < 0)
       return -1;

3967
    /* preallocate new slot for device */
3968
    if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets+1) < 0)
3969 3970 3971 3972 3973 3974
        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.
     */
3975
    if (networkAllocateActualDevice(vm->def, net) < 0)
3976 3977 3978 3979 3980
        return -1;

    actualType = virDomainNetGetActualType(net);

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

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

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

    ret = 0;

4027
 cleanup:
4028 4029 4030 4031 4032 4033
    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:
4034
        case VIR_DOMAIN_NET_TYPE_ETHERNET:
4035 4036 4037 4038 4039 4040
            ignore_value(virNetDevVethDelete(veth));
            break;

        case VIR_DOMAIN_NET_TYPE_DIRECT:
            ignore_value(virNetDevMacVLanDelete(veth));
            break;
4041 4042 4043 4044

        default:
            /* no-op */
            break;
4045 4046 4047 4048 4049 4050 4051
        }
    }

    return ret;
}


4052 4053 4054 4055 4056 4057 4058 4059 4060 4061
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;
4062
    virUSBDevicePtr usb = NULL;
4063
    virDomainHostdevSubsysUSBPtr usbsrc;
4064 4065 4066 4067 4068 4069 4070

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

4071
    usbsrc = &def->source.subsys.u.usb;
4072
    if (virAsprintf(&src, "/dev/bus/usb/%03d/%03d",
4073
                    usbsrc->bus, usbsrc->device) < 0)
4074 4075
        goto cleanup;

4076
    if (!(usb = virUSBDeviceNew(usbsrc->bus, usbsrc->device, NULL)))
4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091
        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;
    }

4092 4093 4094
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0)
        goto cleanup;

4095
    if (virUSBDeviceFileIterate(usb,
4096
                                virLXCSetupHostUSBDeviceCgroup,
4097
                                priv->cgroup) < 0)
4098 4099
        goto cleanup;

4100 4101 4102 4103 4104 4105 4106
    if (lxcDomainAttachDeviceMknod(driver,
                                   0700 | S_IFCHR,
                                   sb.st_rdev,
                                   vm,
                                   dev,
                                   src) < 0) {
        if (virUSBDeviceFileIterate(usb,
4107
                                    virLXCTeardownHostUSBDeviceCgroup,
4108 4109 4110 4111 4112 4113
                                    priv->cgroup) < 0)
            VIR_WARN("cannot deny device %s for domain %s",
                     src, vm->def->name);
        goto cleanup;
    }

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

4116 4117
    ret = 0;

4118
 cleanup:
4119
    virDomainAuditHostdev(vm, def, "attach", ret == 0);
4120
    virUSBDeviceFree(usb);
4121 4122 4123 4124 4125
    VIR_FREE(src);
    return ret;
}


4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161
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;
    }

4162
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0)
4163 4164
        goto cleanup;

4165 4166 4167 4168 4169
    if (virCgroupAllowDevice(priv->cgroup,
                             'b',
                             major(sb.st_rdev),
                             minor(sb.st_rdev),
                             VIR_CGROUP_DEVICE_RWM) < 0)
4170 4171
        goto cleanup;

4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184
    if (lxcDomainAttachDeviceMknod(driver,
                                   0700 | S_IFBLK,
                                   sb.st_rdev,
                                   vm,
                                   dev,
                                   def->source.caps.u.storage.block) < 0) {
        if (virCgroupDenyDevice(priv->cgroup,
                                'b',
                                major(sb.st_rdev),
                                minor(sb.st_rdev),
                                VIR_CGROUP_DEVICE_RWM) < 0)
            VIR_WARN("cannot deny device %s for domain %s",
                     def->source.caps.u.storage.block, vm->def->name);
4185 4186 4187 4188 4189 4190 4191
        goto cleanup;
    }

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

    ret = 0;

4192
 cleanup:
4193 4194 4195 4196 4197
    virDomainAuditHostdev(vm, def, "attach", ret == 0);
    return ret;
}


4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233
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;
    }

4234 4235 4236 4237 4238
    if (virCgroupAllowDevice(priv->cgroup,
                             'c',
                             major(sb.st_rdev),
                             minor(sb.st_rdev),
                             VIR_CGROUP_DEVICE_RWM) < 0)
4239 4240
        goto cleanup;

4241
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0)
4242 4243
        goto cleanup;

4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256
    if (lxcDomainAttachDeviceMknod(driver,
                                   0700 | S_IFBLK,
                                   sb.st_rdev,
                                   vm,
                                   dev,
                                   def->source.caps.u.misc.chardev) < 0) {
        if (virCgroupDenyDevice(priv->cgroup,
                                'c',
                                major(sb.st_rdev),
                                minor(sb.st_rdev),
                                VIR_CGROUP_DEVICE_RWM) < 0)
            VIR_WARN("cannot deny device %s for domain %s",
                     def->source.caps.u.storage.block, vm->def->name);
4257 4258 4259 4260 4261 4262 4263
        goto cleanup;
    }

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

    ret = 0;

4264
 cleanup:
4265 4266 4267 4268 4269
    virDomainAuditHostdev(vm, def, "attach", ret == 0);
    return ret;
}


4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287
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;
    }
}


4288 4289 4290 4291 4292 4293 4294 4295 4296
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);

4297 4298 4299
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC:
        return lxcDomainAttachDeviceHostdevMiscLive(driver, vm, dev);

4300 4301 4302 4303 4304 4305 4306 4307 4308
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported host device type %s"),
                       virDomainHostdevCapsTypeToString(dev->data.hostdev->source.caps.type));
        return -1;
    }
}


4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321
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;
    }

4322 4323 4324 4325 4326 4327
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        return -1;
    }

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

4332 4333 4334
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
        return lxcDomainAttachDeviceHostdevCapsLive(driver, vm, dev);

4335 4336 4337 4338 4339 4340 4341 4342 4343
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported host device mode %s"),
                       virDomainHostdevModeTypeToString(dev->data.hostdev->mode));
        return -1;
    }
}


4344 4345 4346 4347
static int
lxcDomainAttachDeviceLive(virConnectPtr conn,
                          virLXCDriverPtr driver,
                          virDomainObjPtr vm,
4348 4349 4350 4351 4352
                          virDomainDeviceDefPtr dev)
{
    int ret = -1;

    switch (dev->type) {
4353 4354 4355 4356 4357 4358
    case VIR_DOMAIN_DEVICE_DISK:
        ret = lxcDomainAttachDeviceDiskLive(driver, vm, dev);
        if (!ret)
            dev->data.disk = NULL;
        break;

4359 4360 4361 4362 4363 4364 4365
    case VIR_DOMAIN_DEVICE_NET:
        ret = lxcDomainAttachDeviceNetLive(conn, vm,
                                           dev->data.net);
        if (!ret)
            dev->data.net = NULL;
        break;

4366 4367 4368 4369 4370 4371
    case VIR_DOMAIN_DEVICE_HOSTDEV:
        ret = lxcDomainAttachDeviceHostdevLive(driver, vm, dev);
        if (!ret)
            dev->data.disk = NULL;
        break;

4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("device type '%s' cannot be attached"),
                       virDomainDeviceTypeToString(dev->type));
        break;
    }

    return ret;
}


4383
static int
4384
lxcDomainDetachDeviceDiskLive(virDomainObjPtr vm,
4385 4386 4387 4388
                              virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainDiskDefPtr def = NULL;
4389
    int idx, ret = -1;
J
John Ferlan 已提交
4390
    char *dst = NULL;
4391
    const char *src;
4392 4393 4394 4395 4396 4397 4398

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

4399 4400 4401
    if ((idx = virDomainDiskIndexByName(vm->def,
                                        dev->data.disk->dst,
                                        false)) < 0) {
4402 4403 4404 4405 4406
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("disk %s not found"), dev->data.disk->dst);
        goto cleanup;
    }

4407
    def = vm->def->disks[idx];
4408
    src = virDomainDiskGetSource(def);
4409

4410
    if (virAsprintf(&dst, "/dev/%s", def->dst) < 0)
4411 4412
        goto cleanup;

4413
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
4414 4415 4416 4417 4418
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        goto cleanup;
    }

4419
    if (lxcDomainAttachDeviceUnlink(vm, dst) < 0) {
4420
        virDomainAuditDisk(vm, def->src, NULL, "detach", false);
4421 4422
        goto cleanup;
    }
4423
    virDomainAuditDisk(vm, def->src, NULL, "detach", true);
4424

4425 4426
    if (virCgroupDenyDevicePath(priv->cgroup, src,
                                VIR_CGROUP_DEVICE_RWM, false) != 0)
4427
        VIR_WARN("cannot deny device %s for domain %s",
4428
                 src, vm->def->name);
4429

4430
    virDomainDiskRemove(vm->def, idx);
4431 4432 4433 4434
    virDomainDiskDefFree(def);

    ret = 0;

4435
 cleanup:
4436 4437 4438 4439 4440
    VIR_FREE(dst);
    return ret;
}


4441
static int
4442 4443 4444
lxcDomainDetachDeviceNetLive(virDomainObjPtr vm,
                             virDomainDeviceDefPtr dev)
{
4445 4446
    int detachidx, ret = -1;
    virDomainNetType actualType;
4447 4448 4449
    virDomainNetDefPtr detach = NULL;
    virNetDevVPortProfilePtr vport = NULL;

4450
    if ((detachidx = virDomainNetFindIdx(vm->def, dev->data.net)) < 0)
4451
        goto cleanup;
4452

4453
    detach = vm->def->nets[detachidx];
4454 4455 4456
    actualType = virDomainNetGetActualType(detach);

    /* clear network bandwidth */
4457 4458
    if (virDomainNetGetActualBandwidth(detach) &&
        virNetDevSupportBandwidth(actualType) &&
4459 4460
        virNetDevBandwidthClear(detach->ifname))
        goto cleanup;
4461

4462
    switch (actualType) {
4463 4464
    case VIR_DOMAIN_NET_TYPE_BRIDGE:
    case VIR_DOMAIN_NET_TYPE_NETWORK:
4465
    case VIR_DOMAIN_NET_TYPE_ETHERNET:
4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495
        if (virNetDevVethDelete(detach->ifname) < 0) {
            virDomainAuditNet(vm, detach, NULL, "detach", false);
            goto cleanup;
        }
        break;

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

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

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

    virDomainConfNWFilterTeardown(detach);

    vport = virDomainNetGetActualVirtPortProfile(detach);
    if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH)
        ignore_value(virNetDevOpenvswitchRemovePort(
                        virDomainNetGetActualBridgeName(detach),
                        detach->ifname));
    ret = 0;
4496
 cleanup:
4497
    if (!ret) {
4498
        networkReleaseActualDevice(vm->def, detach);
4499 4500 4501 4502 4503 4504 4505
        virDomainNetRemove(vm->def, detachidx);
        virDomainNetDefFree(detach);
    }
    return ret;
}


4506 4507 4508 4509 4510 4511 4512 4513
static int
lxcDomainDetachDeviceHostdevUSBLive(virLXCDriverPtr driver,
                                    virDomainObjPtr vm,
                                    virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainHostdevDefPtr def = NULL;
    int idx, ret = -1;
J
John Ferlan 已提交
4514
    char *dst = NULL;
4515
    virUSBDevicePtr usb = NULL;
4516
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
4517
    virDomainHostdevSubsysUSBPtr usbsrc;
4518 4519 4520 4521 4522 4523 4524 4525 4526

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

4527
    usbsrc = &def->source.subsys.u.usb;
4528
    if (virAsprintf(&dst, "/dev/bus/usb/%03d/%03d",
4529
                    usbsrc->bus, usbsrc->device) < 0)
4530 4531
        goto cleanup;

4532
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
4533 4534 4535 4536 4537
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        goto cleanup;
    }

4538
    if (!(usb = virUSBDeviceNew(usbsrc->bus, usbsrc->device, NULL)))
4539 4540
        goto cleanup;

4541
    if (lxcDomainAttachDeviceUnlink(vm, dst) < 0) {
4542 4543 4544 4545 4546
        virDomainAuditHostdev(vm, def, "detach", false);
        goto cleanup;
    }
    virDomainAuditHostdev(vm, def, "detach", true);

4547
    if (virUSBDeviceFileIterate(usb,
4548
                                virLXCTeardownHostUSBDeviceCgroup,
4549
                                priv->cgroup) < 0)
4550 4551 4552
        VIR_WARN("cannot deny device %s for domain %s",
                 dst, vm->def->name);

4553 4554 4555
    virObjectLock(hostdev_mgr->activeUSBHostdevs);
    virUSBDeviceListDel(hostdev_mgr->activeUSBHostdevs, usb);
    virObjectUnlock(hostdev_mgr->activeUSBHostdevs);
4556 4557 4558 4559 4560 4561

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

    ret = 0;

4562
 cleanup:
4563
    virUSBDeviceFree(usb);
4564 4565 4566 4567
    VIR_FREE(dst);
    return ret;
}

4568 4569

static int
4570
lxcDomainDetachDeviceHostdevStorageLive(virDomainObjPtr vm,
4571 4572 4573 4574
                                        virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainHostdevDefPtr def = NULL;
4575
    int idx, ret = -1;
4576 4577 4578 4579 4580 4581 4582

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

4583 4584 4585
    if ((idx = virDomainHostdevFind(vm->def,
                                    dev->data.hostdev,
                                    &def)) < 0) {
4586 4587 4588 4589 4590 4591
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("hostdev %s not found"),
                       dev->data.hostdev->source.caps.u.storage.block);
        goto cleanup;
    }

4592
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
4593 4594 4595 4596 4597
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        goto cleanup;
    }

4598
    if (lxcDomainAttachDeviceUnlink(vm, def->source.caps.u.storage.block) < 0) {
4599 4600 4601 4602 4603
        virDomainAuditHostdev(vm, def, "detach", false);
        goto cleanup;
    }
    virDomainAuditHostdev(vm, def, "detach", true);

4604 4605
    if (virCgroupDenyDevicePath(priv->cgroup, def->source.caps.u.storage.block,
                                VIR_CGROUP_DEVICE_RWM, false) != 0)
4606 4607 4608
        VIR_WARN("cannot deny device %s for domain %s",
                 def->source.caps.u.storage.block, vm->def->name);

4609
    virDomainHostdevRemove(vm->def, idx);
4610 4611 4612 4613
    virDomainHostdevDefFree(def);

    ret = 0;

4614
 cleanup:
4615 4616 4617 4618
    return ret;
}


4619
static int
4620
lxcDomainDetachDeviceHostdevMiscLive(virDomainObjPtr vm,
4621 4622 4623 4624
                                     virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainHostdevDefPtr def = NULL;
4625
    int idx, ret = -1;
4626 4627 4628 4629 4630 4631 4632

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

4633 4634 4635
    if ((idx = virDomainHostdevFind(vm->def,
                                    dev->data.hostdev,
                                    &def)) < 0) {
4636 4637 4638 4639 4640 4641
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("hostdev %s not found"),
                       dev->data.hostdev->source.caps.u.misc.chardev);
        goto cleanup;
    }

4642
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
4643 4644 4645 4646 4647
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        goto cleanup;
    }

4648
    if (lxcDomainAttachDeviceUnlink(vm, def->source.caps.u.misc.chardev) < 0) {
4649 4650 4651 4652 4653
        virDomainAuditHostdev(vm, def, "detach", false);
        goto cleanup;
    }
    virDomainAuditHostdev(vm, def, "detach", true);

4654 4655
    if (virCgroupDenyDevicePath(priv->cgroup, def->source.caps.u.misc.chardev,
                                VIR_CGROUP_DEVICE_RWM, false) != 0)
4656 4657 4658
        VIR_WARN("cannot deny device %s for domain %s",
                 def->source.caps.u.misc.chardev, vm->def->name);

4659
    virDomainHostdevRemove(vm->def, idx);
4660 4661 4662 4663
    virDomainHostdevDefFree(def);

    ret = 0;

4664
 cleanup:
4665 4666 4667 4668
    return ret;
}


4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686
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;
    }
}


4687
static int
4688 4689
lxcDomainDetachDeviceHostdevCapsLive(virDomainObjPtr vm,
                                     virDomainDeviceDefPtr dev)
4690 4691 4692
{
    switch (dev->data.hostdev->source.caps.type) {
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
4693
        return lxcDomainDetachDeviceHostdevStorageLive(vm, dev);
4694

4695
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC:
4696
        return lxcDomainDetachDeviceHostdevMiscLive(vm, dev);
4697

4698 4699 4700 4701 4702 4703 4704 4705 4706
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported host device type %s"),
                       virDomainHostdevCapsTypeToString(dev->data.hostdev->source.caps.type));
        return -1;
    }
}


4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723
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);

4724
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
4725
        return lxcDomainDetachDeviceHostdevCapsLive(vm, dev);
4726

4727 4728 4729 4730 4731 4732 4733 4734 4735
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported host device mode %s"),
                       virDomainHostdevModeTypeToString(dev->data.hostdev->mode));
        return -1;
    }
}


4736 4737 4738
static int
lxcDomainDetachDeviceLive(virLXCDriverPtr driver,
                          virDomainObjPtr vm,
4739 4740 4741 4742 4743
                          virDomainDeviceDefPtr dev)
{
    int ret = -1;

    switch (dev->type) {
4744
    case VIR_DOMAIN_DEVICE_DISK:
4745
        ret = lxcDomainDetachDeviceDiskLive(vm, dev);
4746 4747
        break;

4748 4749 4750 4751
    case VIR_DOMAIN_DEVICE_NET:
        ret = lxcDomainDetachDeviceNetLive(vm, dev);
        break;

4752 4753 4754 4755
    case VIR_DOMAIN_DEVICE_HOSTDEV:
        ret = lxcDomainDetachDeviceHostdevLive(driver, vm, dev);
        break;

4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("device type '%s' cannot be detached"),
                       virDomainDeviceTypeToString(dev->type));
        break;
    }

    return ret;
}


4767 4768 4769
static int lxcDomainAttachDeviceFlags(virDomainPtr dom,
                                      const char *xml,
                                      unsigned int flags)
4770 4771
{
    virLXCDriverPtr driver = dom->conn->privateData;
4772
    virCapsPtr caps = NULL;
4773 4774 4775 4776
    virDomainObjPtr vm = NULL;
    virDomainDefPtr vmdef = NULL;
    virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
    int ret = -1;
4777
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
4778 4779

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
4780
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
4781

M
Michal Privoznik 已提交
4782
    if (!(vm = lxcDomObjFromDomain(dom)))
4783 4784
        goto cleanup;

4785 4786 4787
    if (virDomainAttachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4788
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
4789 4790
        goto cleanup;

4791 4792 4793
    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
        goto endjob;

4794
    if (virDomainObjUpdateModificationImpact(vm, &flags) < 0)
4795
        goto endjob;
4796

4797
    dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
4798
                                             caps, driver->xmlopt,
4799
                                             VIR_DOMAIN_DEF_PARSE_INACTIVE);
4800
    if (dev == NULL)
4801
        goto endjob;
4802 4803 4804 4805 4806 4807 4808

    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.
         */
4809
        dev_copy = virDomainDeviceDefCopy(dev, vm->def,
4810
                                          caps, driver->xmlopt);
4811
        if (!dev_copy)
4812
            goto endjob;
4813 4814 4815 4816
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        /* Make a copy for updated domain. */
4817
        vmdef = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt);
4818
        if (!vmdef)
4819
            goto endjob;
4820

4821 4822
        if (virDomainDefCompatibleDevice(vmdef, dev,
                                         VIR_DOMAIN_DEVICE_ACTION_ATTACH) < 0)
4823
            goto endjob;
4824

4825
        if ((ret = lxcDomainAttachDeviceConfig(vmdef, dev)) < 0)
4826
            goto endjob;
4827 4828 4829
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
4830 4831
        if (virDomainDefCompatibleDevice(vm->def, dev_copy,
                                         VIR_DOMAIN_DEVICE_ACTION_ATTACH) < 0)
4832
            goto endjob;
4833

4834
        if ((ret = lxcDomainAttachDeviceLive(dom->conn, driver, vm, dev_copy)) < 0)
4835
            goto endjob;
4836 4837 4838 4839 4840
        /*
         * 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.
         */
4841
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0) {
4842
            ret = -1;
4843
            goto endjob;
4844 4845 4846 4847 4848
        }
    }

    /* Finally, if no error until here, we can save config. */
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
4849
        ret = virDomainSaveConfig(cfg->configDir, driver->caps, vmdef);
4850
        if (!ret) {
4851
            virDomainObjAssignDef(vm, vmdef, false, NULL);
4852 4853 4854 4855
            vmdef = NULL;
        }
    }

4856
 endjob:
4857 4858
    virLXCDomainObjEndJob(driver, vm);

4859
 cleanup:
4860 4861 4862 4863
    virDomainDefFree(vmdef);
    if (dev != dev_copy)
        virDomainDeviceDefFree(dev_copy);
    virDomainDeviceDefFree(dev);
4864
    virDomainObjEndAPI(&vm);
4865
    virObjectUnref(caps);
4866
    virObjectUnref(cfg);
4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882
    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)
{
4883
    virLXCDriverPtr driver = dom->conn->privateData;
4884
    virCapsPtr caps = NULL;
4885 4886 4887 4888
    virDomainObjPtr vm = NULL;
    virDomainDefPtr vmdef = NULL;
    virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
    int ret = -1;
4889
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
4890 4891 4892 4893 4894

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

M
Michal Privoznik 已提交
4895
    if (!(vm = lxcDomObjFromDomain(dom)))
4896 4897
        goto cleanup;

4898 4899 4900
    if (virDomainUpdateDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4901
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
4902
        goto cleanup;
4903

4904 4905 4906
    if (virDomainObjUpdateModificationImpact(vm, &flags) < 0)
        goto endjob;

4907
    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
4908
        goto endjob;
4909

4910
    dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
4911
                                             caps, driver->xmlopt,
4912
                                             VIR_DOMAIN_DEF_PARSE_INACTIVE);
4913
    if (dev == NULL)
4914
        goto endjob;
4915 4916 4917 4918 4919 4920 4921 4922

    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,
4923
                                          caps, driver->xmlopt);
4924
        if (!dev_copy)
4925
            goto endjob;
4926 4927 4928 4929
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        /* Make a copy for updated domain. */
4930
        vmdef = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt);
4931
        if (!vmdef)
4932
            goto endjob;
4933

4934 4935
        if (virDomainDefCompatibleDevice(vmdef, dev,
                                         VIR_DOMAIN_DEVICE_ACTION_UPDATE) < 0)
4936
            goto endjob;
4937

4938
        if ((ret = lxcDomainUpdateDeviceConfig(vmdef, dev)) < 0)
4939
            goto endjob;
4940 4941 4942
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
4943 4944
        if (virDomainDefCompatibleDevice(vm->def, dev_copy,
                                         VIR_DOMAIN_DEVICE_ACTION_UPDATE) < 0)
4945
            goto endjob;
4946 4947 4948 4949

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

4950
        goto endjob;
4951 4952 4953 4954
    }

    /* Finally, if no error until here, we can save config. */
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
4955
        ret = virDomainSaveConfig(cfg->configDir, driver->caps, vmdef);
4956 4957 4958 4959 4960
        if (!ret) {
            virDomainObjAssignDef(vm, vmdef, false, NULL);
            vmdef = NULL;
        }
    }
4961
 endjob:
4962 4963
    virLXCDomainObjEndJob(driver, vm);

4964
 cleanup:
4965 4966 4967 4968
    virDomainDefFree(vmdef);
    if (dev != dev_copy)
        virDomainDeviceDefFree(dev_copy);
    virDomainDeviceDefFree(dev);
4969
    virDomainObjEndAPI(&vm);
4970
    virObjectUnref(caps);
4971
    virObjectUnref(cfg);
4972
    return ret;
4973 4974 4975 4976 4977 4978 4979
}


static int lxcDomainDetachDeviceFlags(virDomainPtr dom,
                                      const char *xml,
                                      unsigned int flags)
{
4980
    virLXCDriverPtr driver = dom->conn->privateData;
4981
    virCapsPtr caps = NULL;
4982 4983 4984 4985
    virDomainObjPtr vm = NULL;
    virDomainDefPtr vmdef = NULL;
    virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
    int ret = -1;
4986
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
4987 4988 4989 4990

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

M
Michal Privoznik 已提交
4991
    if (!(vm = lxcDomObjFromDomain(dom)))
4992 4993
        goto cleanup;

4994 4995 4996
    if (virDomainDetachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4997
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
4998
        goto cleanup;
4999

5000 5001 5002
    if (virDomainObjUpdateModificationImpact(vm, &flags) < 0)
        goto endjob;

5003
    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
5004
        goto endjob;
5005

5006
    dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
5007
                                             caps, driver->xmlopt,
5008 5009
                                             VIR_DOMAIN_DEF_PARSE_INACTIVE |
                                             VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE);
5010
    if (dev == NULL)
5011
        goto endjob;
5012 5013 5014 5015 5016 5017 5018 5019

    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,
5020
                                          caps, driver->xmlopt);
5021
        if (!dev_copy)
5022
            goto endjob;
5023 5024 5025 5026
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        /* Make a copy for updated domain. */
5027
        vmdef = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt);
5028
        if (!vmdef)
5029
            goto endjob;
5030

5031 5032
        if (virDomainDefCompatibleDevice(vmdef, dev,
                                         VIR_DOMAIN_DEVICE_ACTION_DETACH) < 0)
5033
            goto endjob;
5034

5035
        if ((ret = lxcDomainDetachDeviceConfig(vmdef, dev)) < 0)
5036
            goto endjob;
5037 5038 5039
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
5040 5041
        if (virDomainDefCompatibleDevice(vm->def, dev_copy,
                                         VIR_DOMAIN_DEVICE_ACTION_DETACH) < 0)
5042
            goto endjob;
5043 5044

        if ((ret = lxcDomainDetachDeviceLive(driver, vm, dev_copy)) < 0)
5045
            goto endjob;
5046 5047 5048 5049 5050
        /*
         * 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.
         */
5051
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0) {
5052
            ret = -1;
5053
            goto endjob;
5054 5055 5056 5057 5058
        }
    }

    /* Finally, if no error until here, we can save config. */
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5059
        ret = virDomainSaveConfig(cfg->configDir, driver->caps, vmdef);
5060 5061 5062 5063 5064 5065
        if (!ret) {
            virDomainObjAssignDef(vm, vmdef, false, NULL);
            vmdef = NULL;
        }
    }

5066
 endjob:
5067 5068
    virLXCDomainObjEndJob(driver, vm);

5069
 cleanup:
5070 5071 5072 5073
    virDomainDefFree(vmdef);
    if (dev != dev_copy)
        virDomainDeviceDefFree(dev_copy);
    virDomainDeviceDefFree(dev);
5074
    virDomainObjEndAPI(&vm);
5075
    virObjectUnref(caps);
5076
    virObjectUnref(cfg);
5077
    return ret;
5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088
}


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


5089 5090 5091
static int lxcDomainLxcOpenNamespace(virDomainPtr dom,
                                     int **fdlist,
                                     unsigned int flags)
5092
{
5093
    virLXCDriverPtr driver = dom->conn->privateData;
5094 5095 5096 5097 5098 5099 5100 5101
    virDomainObjPtr vm;
    virLXCDomainObjPrivatePtr priv;
    int ret = -1;
    size_t nfds = 0;

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

M
Michal Privoznik 已提交
5102
    if (!(vm = lxcDomObjFromDomain(dom)))
5103
        goto cleanup;
M
Michal Privoznik 已提交
5104

5105 5106
    priv = vm->privateData;

5107 5108 5109
    if (virDomainLxcOpenNamespaceEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

5110 5111 5112
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_QUERY) < 0)
        goto cleanup;

5113 5114 5115
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not running"));
5116
        goto endjob;
5117 5118 5119 5120 5121
    }

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

    if (virProcessGetNamespaces(priv->initpid, &nfds, fdlist) < 0)
5126
        goto endjob;
5127 5128

    ret = nfds;
5129 5130

 endjob:
5131
    virLXCDomainObjEndJob(driver, vm);
5132

5133
 cleanup:
5134
    virDomainObjEndAPI(&vm);
5135 5136 5137 5138
    return ret;
}


5139
static char *
5140
lxcConnectGetSysinfo(virConnectPtr conn, unsigned int flags)
5141 5142 5143 5144 5145 5146
{
    virLXCDriverPtr driver = conn->privateData;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    virCheckFlags(0, NULL);

5147 5148 5149
    if (virConnectGetSysinfoEnsureACL(conn) < 0)
        return NULL;

5150 5151 5152 5153 5154 5155 5156 5157
    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;
5158
    if (virBufferCheckError(&buf) < 0)
5159 5160 5161 5162 5163
        return NULL;
    return virBufferContentAndReset(&buf);
}


5164
static int
5165
lxcNodeGetInfo(virConnectPtr conn,
5166 5167
               virNodeInfoPtr nodeinfo)
{
5168 5169 5170
    if (virNodeGetInfoEnsureACL(conn) < 0)
        return -1;

5171
    return nodeGetInfo(nodeinfo);
5172 5173 5174
}


5175 5176
static int
lxcDomainMemoryStats(virDomainPtr dom,
5177
                     virDomainMemoryStatPtr stats,
5178 5179 5180 5181 5182 5183 5184 5185
                     unsigned int nr_stats,
                     unsigned int flags)
{
    virDomainObjPtr vm;
    int ret = -1;
    virLXCDomainObjPrivatePtr priv;
    unsigned long long swap_usage;
    unsigned long mem_usage;
5186
    virLXCDriverPtr driver = dom->conn->privateData;
5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197

    virCheckFlags(0, -1);

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

    priv = vm->privateData;

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

5198 5199 5200
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_QUERY) < 0)
        goto cleanup;

5201 5202 5203
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not active"));
5204
        goto endjob;
5205
    }
5206

5207
    if (virCgroupGetMemSwapUsage(priv->cgroup, &swap_usage) < 0)
5208
        goto endjob;
5209

5210
    if (virCgroupGetMemoryUsage(priv->cgroup, &mem_usage) < 0)
5211
        goto endjob;
5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229

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

5230
 endjob:
5231 5232
    virLXCDomainObjEndJob(driver, vm);

5233
 cleanup:
5234
    virDomainObjEndAPI(&vm);
5235 5236 5237 5238
    return ret;
}


5239
static int
5240
lxcNodeGetCPUStats(virConnectPtr conn,
5241 5242 5243 5244 5245
                   int cpuNum,
                   virNodeCPUStatsPtr params,
                   int *nparams,
                   unsigned int flags)
{
5246 5247 5248
    if (virNodeGetCPUStatsEnsureACL(conn) < 0)
        return -1;

5249
    return virHostCPUGetStats(cpuNum, params, nparams, flags);
5250 5251 5252 5253
}


static int
5254
lxcNodeGetMemoryStats(virConnectPtr conn,
5255 5256 5257 5258 5259
                      int cellNum,
                      virNodeMemoryStatsPtr params,
                      int *nparams,
                      unsigned int flags)
{
5260 5261 5262
    if (virNodeGetMemoryStatsEnsureACL(conn) < 0)
        return -1;

5263
    return virHostMemGetStats(cellNum, params, nparams, flags);
5264 5265 5266 5267
}


static int
5268
lxcNodeGetCellsFreeMemory(virConnectPtr conn,
5269 5270 5271 5272
                          unsigned long long *freeMems,
                          int startCell,
                          int maxCells)
{
5273 5274 5275
    if (virNodeGetCellsFreeMemoryEnsureACL(conn) < 0)
        return -1;

5276
    return virHostMemGetCellsFree(freeMems, startCell, maxCells);
5277 5278 5279 5280
}


static unsigned long long
5281
lxcNodeGetFreeMemory(virConnectPtr conn)
5282
{
5283 5284
    unsigned long long freeMem;

5285 5286 5287
    if (virNodeGetFreeMemoryEnsureACL(conn) < 0)
        return 0;

5288
    if (virHostMemGetInfo(NULL, &freeMem) < 0)
5289 5290 5291
        return 0;

    return freeMem;
5292 5293 5294 5295
}


static int
5296
lxcNodeGetMemoryParameters(virConnectPtr conn,
5297 5298 5299 5300
                           virTypedParameterPtr params,
                           int *nparams,
                           unsigned int flags)
{
5301 5302 5303
    if (virNodeGetMemoryParametersEnsureACL(conn) < 0)
        return -1;

5304
    return virHostMemGetParameters(params, nparams, flags);
5305 5306 5307 5308
}


static int
5309
lxcNodeSetMemoryParameters(virConnectPtr conn,
5310 5311 5312 5313
                           virTypedParameterPtr params,
                           int nparams,
                           unsigned int flags)
{
5314 5315 5316
    if (virNodeSetMemoryParametersEnsureACL(conn) < 0)
        return -1;

5317
    return virHostMemSetParameters(params, nparams, flags);
5318 5319 5320 5321
}


static int
5322
lxcNodeGetCPUMap(virConnectPtr conn,
5323 5324 5325 5326
                 unsigned char **cpumap,
                 unsigned int *online,
                 unsigned int flags)
{
5327 5328 5329
    if (virNodeGetCPUMapEnsureACL(conn) < 0)
        return -1;

5330
    return virHostCPUGetMap(cpumap, online, flags);
5331 5332
}

5333 5334

static int
5335
lxcNodeSuspendForDuration(virConnectPtr conn,
5336 5337 5338 5339
                          unsigned int target,
                          unsigned long long duration,
                          unsigned int flags)
{
5340 5341 5342
    if (virNodeSuspendForDurationEnsureACL(conn) < 0)
        return -1;

5343 5344 5345 5346
    return nodeSuspendForDuration(target, duration, flags);
}


5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374
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;

5375 5376 5377
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

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

5382 5383 5384 5385 5386 5387
    if (ret == 0) {
        virObjectEventPtr ev = NULL;
        ev = virDomainEventMetadataChangeNewFromObj(vm, type, uri);
        virObjectEventStateQueue(driver->domainEventState, ev);
    }

5388
    virLXCDomainObjEndJob(driver, vm);
5389

5390
 cleanup:
5391
    virDomainObjEndAPI(&vm);
5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412
    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;

5413
    ret = virDomainObjGetMetadata(vm, type, uri, flags);
5414

5415
 cleanup:
5416
    virDomainObjEndAPI(&vm);
5417 5418 5419 5420
    return ret;
}


5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459
static int
lxcDomainGetCPUStats(virDomainPtr dom,
                     virTypedParameterPtr params,
                     unsigned int nparams,
                     int start_cpu,
                     unsigned int ncpus,
                     unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virLXCDomainObjPrivatePtr priv;

    virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);

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

    priv = vm->privateData;

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

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

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

    if (start_cpu == -1)
        ret = virCgroupGetDomainTotalCpuStats(priv->cgroup,
                                              params, nparams);
    else
        ret = virCgroupGetPercpuStats(priv->cgroup, params,
5460
                                      nparams, start_cpu, ncpus, NULL);
5461
 cleanup:
5462
    virDomainObjEndAPI(&vm);
5463 5464 5465 5466
    return ret;
}


5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480
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;

5481
    return virHostMemGetFreePages(npages, pages, startCell, cellCount, counts);
5482 5483 5484
}


5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500
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;

5501 5502
    return virHostMemAllocPages(npages, pageSizes, pageCounts,
                                startCell, cellCount, add);
5503 5504 5505
}


5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522
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:
5523
    virDomainObjEndAPI(&vm);
5524 5525 5526 5527
    return ret;
}


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

5623 5624 5625 5626
static virConnectDriver lxcConnectDriver = {
    .hypervisorDriver = &lxcHypervisorDriver,
};

5627
static virStateDriver lxcStateDriver = {
5628
    .name = LXC_DRIVER_NAME,
5629
    .stateInitialize = lxcStateInitialize,
5630
    .stateAutoStart = lxcStateAutoStart,
5631 5632
    .stateCleanup = lxcStateCleanup,
    .stateReload = lxcStateReload,
5633 5634
};

D
Daniel Veillard 已提交
5635 5636
int lxcRegister(void)
{
5637 5638
    if (virRegisterConnectDriver(&lxcConnectDriver,
                                 true) < 0)
5639 5640 5641
        return -1;
    if (virRegisterStateDriver(&lxcStateDriver) < 0)
        return -1;
D
Daniel Veillard 已提交
5642 5643
    return 0;
}