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

#include <config.h>

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

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

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

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

79 80
#define VIR_FROM_THIS VIR_FROM_LXC

81
VIR_LOG_INIT("lxc.lxc_driver");
82

83
#define LXC_NB_MEM_PARAM  3
84
#define LXC_NB_DOMAIN_BLOCK_STAT_PARAM 4
85

86

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

94

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

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

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

132 133
    *uri = g_strdup("lxc:///system");
    return 1;
134 135 136
}


137
static virDrvOpenStatus lxcConnectOpen(virConnectPtr conn,
J
Ján Tomko 已提交
138 139
                                       virConnectAuthPtr auth G_GNUC_UNUSED,
                                       virConfPtr conf G_GNUC_UNUSED,
140
                                       unsigned int flags)
D
Daniel Veillard 已提交
141
{
E
Eric Blake 已提交
142 143
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

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

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

161 162 163
    if (virConnectOpenEnsureACL(conn) < 0)
        return VIR_DRV_OPEN_ERROR;

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

    return VIR_DRV_OPEN_SUCCESS;
}

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

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

178

J
Ján Tomko 已提交
179
static int lxcConnectIsSecure(virConnectPtr conn G_GNUC_UNUSED)
180 181 182 183 184 185
{
    /* Trivially secure, since always inside the daemon */
    return 1;
}


J
Ján Tomko 已提交
186
static int lxcConnectIsEncrypted(virConnectPtr conn G_GNUC_UNUSED)
187 188 189 190 191 192
{
    /* Not encrypted, but remote driver takes care of that */
    return 0;
}


J
Ján Tomko 已提交
193
static int lxcConnectIsAlive(virConnectPtr conn G_GNUC_UNUSED)
194 195 196 197 198
{
    return 1;
}


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

204 205 206
    if (virConnectGetCapabilitiesEnsureACL(conn) < 0)
        return NULL;

207
    if (!(caps = virLXCDriverGetCapabilities(driver, true)))
208 209
        return NULL;

210
    xml = virCapabilitiesFormatXML(caps);
211

212
    virObjectUnref(caps);
213 214 215 216
    return xml;
}


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

224
    vm = virDomainObjListFindByID(driver->domains, id);
225

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

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

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

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

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

249
    vm = virDomainObjListFindByUUID(driver->domains, uuid);
250

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

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

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

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

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

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

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

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

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

293 294 295 296 297 298

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

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

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

305 306
    ret = virDomainObjIsActive(obj);

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


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

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

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

324 325
    ret = obj->persistent;

326
 cleanup:
327
    virDomainObjEndAPI(&obj);
328 329 330
    return ret;
}

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

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

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

342 343
    ret = obj->updated;

344
 cleanup:
345
    virDomainObjEndAPI(&obj);
346 347
    return ret;
}
348

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

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

M
Michal Privoznik 已提交
356 357
    return virDomainObjListGetActiveIDs(driver->domains, ids, nids,
                                        virConnectListDomainsCheckACL, conn);
D
Daniel Veillard 已提交
358
}
359

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

364 365 366
    if (virConnectNumOfDomainsEnsureACL(conn) < 0)
        return -1;

M
Michal Privoznik 已提交
367 368
    return virDomainObjListNumOfDomains(driver->domains, true,
                                        virConnectNumOfDomainsCheckACL, conn);
D
Daniel Veillard 已提交
369 370
}

371
static int lxcConnectListDefinedDomains(virConnectPtr conn,
372 373
                                        char **const names, int nnames)
{
374
    virLXCDriverPtr driver = conn->privateData;
375

376 377 378
    if (virConnectListDefinedDomainsEnsureACL(conn) < 0)
        return -1;

M
Michal Privoznik 已提交
379 380 381
    return virDomainObjListGetInactiveNames(driver->domains, names, nnames,
                                            virConnectListDefinedDomainsCheckACL,
                                            conn);
D
Daniel Veillard 已提交
382 383 384
}


385 386
static int lxcConnectNumOfDefinedDomains(virConnectPtr conn)
{
387
    virLXCDriverPtr driver = conn->privateData;
388

389 390 391
    if (virConnectNumOfDefinedDomainsEnsureACL(conn) < 0)
        return -1;

M
Michal Privoznik 已提交
392 393 394
    return virDomainObjListNumOfDomains(driver->domains, false,
                                        virConnectNumOfDefinedDomainsCheckACL,
                                        conn);
D
Daniel Veillard 已提交
395 396
}

397 398


399 400
static virDomainPtr
lxcDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags)
D
Daniel Veillard 已提交
401
{
402
    virLXCDriverPtr driver = conn->privateData;
403
    virDomainDefPtr def = NULL;
404
    virDomainObjPtr vm = NULL;
405
    virDomainPtr dom = NULL;
406
    virObjectEventPtr event = NULL;
407
    virDomainDefPtr oldDef = NULL;
408
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
409
    virCapsPtr caps = NULL;
410
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
D
Daniel Veillard 已提交
411

412 413 414
    virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);

    if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
415
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
416

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

420
    if (!(def = virDomainDefParseString(xml, driver->xmlopt,
421
                                        NULL, parse_flags)))
422
        goto cleanup;
D
Daniel Veillard 已提交
423

424 425 426
    if (virXMLCheckIllegalChars("name", def->name, "\n") < 0)
        goto cleanup;

427
    if (virDomainDefineXMLFlagsEnsureACL(conn, def) < 0)
428 429
        goto cleanup;

430 431 432
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
        goto cleanup;

433
    if ((def->nets != NULL) && !(cfg->have_netns)) {
434 435
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("System lacks NETNS support"));
436
        goto cleanup;
437 438
    }

439
    if (!(vm = virDomainObjListAdd(driver->domains, def,
440
                                   driver->xmlopt,
441
                                   0, &oldDef)))
442
        goto cleanup;
443

444
    def = NULL;
445
    vm->persistent = 1;
D
Daniel Veillard 已提交
446

447
    if (virDomainDefSave(vm->newDef ? vm->newDef : vm->def,
448
                         driver->xmlopt, cfg->configDir) < 0) {
449
        virDomainObjListRemove(driver->domains, vm);
450
        goto cleanup;
D
Daniel Veillard 已提交
451 452
    }

453
    event = virDomainEventLifecycleNewFromObj(vm,
454
                                     VIR_DOMAIN_EVENT_DEFINED,
455
                                     !oldDef ?
456 457 458
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);

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

461
 cleanup:
462
    virDomainDefFree(def);
463
    virDomainDefFree(oldDef);
464
    virDomainObjEndAPI(&vm);
465
    virObjectEventStateQueue(driver->domainEventState, event);
466
    virObjectUnref(caps);
467
    virObjectUnref(cfg);
D
Daniel Veillard 已提交
468 469 470
    return dom;
}

471 472 473 474 475 476
static virDomainPtr
lxcDomainDefineXML(virConnectPtr conn, const char *xml)
{
    return lxcDomainDefineXMLFlags(conn, xml, 0);
}

477 478
static int lxcDomainUndefineFlags(virDomainPtr dom,
                                  unsigned int flags)
D
Daniel Veillard 已提交
479
{
480
    virLXCDriverPtr driver = dom->conn->privateData;
481
    virDomainObjPtr vm;
482
    virObjectEventPtr event = NULL;
483
    int ret = -1;
484
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
D
Daniel Veillard 已提交
485

486 487
    virCheckFlags(0, -1);

M
Michal Privoznik 已提交
488
    if (!(vm = lxcDomObjFromDomain(dom)))
489
        goto cleanup;
D
Daniel Veillard 已提交
490

491 492 493
    if (virDomainUndefineFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

494
    if (!vm->persistent) {
495 496
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Cannot undefine transient domain"));
497
        goto cleanup;
498
    }
D
Daniel Veillard 已提交
499

500 501
    if (virDomainDeleteConfig(cfg->configDir,
                              cfg->autostartDir,
502 503
                              vm) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
504

505
    event = virDomainEventLifecycleNewFromObj(vm,
506 507 508
                                     VIR_DOMAIN_EVENT_UNDEFINED,
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);

509
    if (virDomainObjIsActive(vm))
510
        vm->persistent = 0;
511
    else
512
        virDomainObjListRemove(driver->domains, vm);
513

514
    ret = 0;
D
Daniel Veillard 已提交
515

516
 cleanup:
517
    virDomainObjEndAPI(&vm);
518
    virObjectEventStateQueue(driver->domainEventState, event);
519
    virObjectUnref(cfg);
520
    return ret;
D
Daniel Veillard 已提交
521 522
}

523 524 525 526 527
static int lxcDomainUndefine(virDomainPtr dom)
{
    return lxcDomainUndefineFlags(dom, 0);
}

D
Daniel Veillard 已提交
528 529 530
static int lxcDomainGetInfo(virDomainPtr dom,
                            virDomainInfoPtr info)
{
531
    virDomainObjPtr vm;
532
    int ret = -1;
533
    virLXCDomainObjPrivatePtr priv;
D
Daniel Veillard 已提交
534

M
Michal Privoznik 已提交
535
    if (!(vm = lxcDomObjFromDomain(dom)))
536
        goto cleanup;
D
Daniel Veillard 已提交
537

538 539
    priv = vm->privateData;

540 541 542
    if (virDomainGetInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

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

566
    info->maxMem = virDomainDefGetMemoryTotal(vm->def);
567
    info->nrVirtCpu = virDomainDefGetVcpus(vm->def);
568
    ret = 0;
D
Daniel Veillard 已提交
569

570
 cleanup:
571
    virDomainObjEndAPI(&vm);
572
    return ret;
D
Daniel Veillard 已提交
573 574
}

575 576 577 578 579 580 581 582 583 584 585
static int
lxcDomainGetState(virDomainPtr dom,
                  int *state,
                  int *reason,
                  unsigned int flags)
{
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

M
Michal Privoznik 已提交
586
    if (!(vm = lxcDomObjFromDomain(dom)))
587 588
        goto cleanup;

589 590 591
    if (virDomainGetStateEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
592
    *state = virDomainObjGetState(vm, reason);
593 594
    ret = 0;

595
 cleanup:
596
    virDomainObjEndAPI(&vm);
597 598 599
    return ret;
}

600
static char *lxcDomainGetOSType(virDomainPtr dom)
D
Daniel Veillard 已提交
601
{
602 603
    virDomainObjPtr vm;
    char *ret = NULL;
604

M
Michal Privoznik 已提交
605
    if (!(vm = lxcDomObjFromDomain(dom)))
606
        goto cleanup;
607

608 609 610
    if (virDomainGetOSTypeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

611
    ret = g_strdup(virDomainOSTypeToString(vm->def->os.type));
612

613
 cleanup:
614
    virDomainObjEndAPI(&vm);
615
    return ret;
D
Daniel Veillard 已提交
616 617
}

R
Ryota Ozaki 已提交
618
/* Returns max memory in kb, 0 if error */
619 620 621
static unsigned long long
lxcDomainGetMaxMemory(virDomainPtr dom)
{
R
Ryota Ozaki 已提交
622
    virDomainObjPtr vm;
623
    unsigned long long ret = 0;
R
Ryota Ozaki 已提交
624

M
Michal Privoznik 已提交
625
    if (!(vm = lxcDomObjFromDomain(dom)))
R
Ryota Ozaki 已提交
626 627
        goto cleanup;

628 629 630
    if (virDomainGetMaxMemoryEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

633
 cleanup:
634
    virDomainObjEndAPI(&vm);
R
Ryota Ozaki 已提交
635 636 637
    return ret;
}

638 639
static int lxcDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem,
                                   unsigned int flags)
640
{
R
Ryota Ozaki 已提交
641
    virDomainObjPtr vm;
642
    virDomainDefPtr def = NULL;
643
    virDomainDefPtr persistentDef = NULL;
R
Ryota Ozaki 已提交
644
    int ret = -1;
645
    virLXCDomainObjPrivatePtr priv;
646 647 648 649
    virLXCDriverPtr driver = dom->conn->privateData;
    virLXCDriverConfigPtr cfg = NULL;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
650 651
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_DOMAIN_MEM_MAXIMUM, -1);
R
Ryota Ozaki 已提交
652

M
Michal Privoznik 已提交
653
    if (!(vm = lxcDomObjFromDomain(dom)))
R
Ryota Ozaki 已提交
654
        goto cleanup;
M
Michal Privoznik 已提交
655

656 657
    cfg = virLXCDriverGetConfig(driver);

658
    priv = vm->privateData;
R
Ryota Ozaki 已提交
659

660
    if (virDomainSetMemoryFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
661 662
        goto cleanup;

663
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
664 665
        goto cleanup;

666
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
667
        goto endjob;
668

669
    if (flags & VIR_DOMAIN_MEM_MAXIMUM) {
670
        if (def) {
671 672 673
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Cannot resize the max memory "
                             "on an active domain"));
674
            goto endjob;
675
        }
676

677
        if (persistentDef) {
678
            virDomainDefSetMemoryTotal(persistentDef, newmem);
679 680
            if (persistentDef->mem.cur_balloon > newmem)
                persistentDef->mem.cur_balloon = newmem;
681
            if (virDomainDefSave(persistentDef,
682
                                 driver->xmlopt, cfg->configDir) < 0)
683
                goto endjob;
684 685 686
        }
    } else {
        unsigned long oldmax = 0;
R
Ryota Ozaki 已提交
687

688
        if (def)
689
            oldmax = virDomainDefGetMemoryTotal(def);
690
        if (persistentDef) {
691 692
            if (!oldmax || oldmax > virDomainDefGetMemoryTotal(persistentDef))
                oldmax = virDomainDefGetMemoryTotal(persistentDef);
693
        }
694

695 696 697
        if (newmem > oldmax) {
            virReportError(VIR_ERR_INVALID_ARG,
                           "%s", _("Cannot set memory higher than max memory"));
698
            goto endjob;
699 700
        }

701
        if (def) {
702 703 704
            if (virCgroupSetMemory(priv->cgroup, newmem) < 0) {
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("Failed to set memory for domain"));
705
                goto endjob;
706
            }
707

708
            def->mem.cur_balloon = newmem;
709
            if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0)
710
                goto endjob;
711 712
        }

713
        if (persistentDef) {
714
            persistentDef->mem.cur_balloon = newmem;
715
            if (virDomainDefSave(persistentDef,
716
                                 driver->xmlopt, cfg->configDir) < 0)
717
                goto endjob;
718
        }
719 720
    }

R
Ryota Ozaki 已提交
721 722
    ret = 0;

723
 endjob:
724
    virLXCDomainObjEndJob(driver, vm);
725

726
 cleanup:
727
    virDomainObjEndAPI(&vm);
728
    virObjectUnref(cfg);
R
Ryota Ozaki 已提交
729 730 731
    return ret;
}

732 733 734 735 736
static int lxcDomainSetMemory(virDomainPtr dom, unsigned long newmem)
{
    return lxcDomainSetMemoryFlags(dom, newmem, VIR_DOMAIN_AFFECT_LIVE);
}

737 738 739 740 741
static int lxcDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax)
{
    return lxcDomainSetMemoryFlags(dom, newmax, VIR_DOMAIN_MEM_MAXIMUM);
}

742 743 744 745 746
static int
lxcDomainSetMemoryParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int nparams,
                             unsigned int flags)
747
{
748
    virDomainDefPtr def = NULL;
J
Ján Tomko 已提交
749
    virDomainDefPtr persistentDef = NULL;
750
    virDomainObjPtr vm = NULL;
751 752 753 754 755 756 757 758 759 760
    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;
761 762
    int ret = -1;

763 764 765
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

766 767 768 769 770 771 772 773
    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)
774
        return -1;
E
Eric Blake 已提交
775

M
Michal Privoznik 已提交
776
    if (!(vm = lxcDomObjFromDomain(dom)))
777
        goto cleanup;
M
Michal Privoznik 已提交
778

779
    priv = vm->privateData;
780
    cfg = virLXCDriverGetConfig(driver);
781

782
    if (virDomainSetMemoryParametersEnsureACL(dom->conn, vm->def, flags) < 0)
783 784
        goto cleanup;

785 786 787
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

788 789
    /* QEMU and LXC implementation are identical */
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
790 791
        goto endjob;

792
    if (def &&
793
        !virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_MEMORY)) {
794 795
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cgroup memory controller is not mounted"));
796
        goto endjob;
797 798
    }

799 800 801 802 803
#define VIR_GET_LIMIT_PARAMETER(PARAM, VALUE) \
    if ((rc = virTypedParamsGetULLong(params, nparams, PARAM, &VALUE)) < 0) \
        goto endjob; \
 \
    if (rc == 1) \
804 805 806 807 808 809 810 811
        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

812
    /* Swap hard limit must be greater than hard limit. */
813 814 815 816 817 818 819 820 821 822
    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;

823
        if (mem_limit > swap_limit) {
824 825 826
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("memory hard_limit tunable value must be lower "
                             "than or equal to swap_hard_limit"));
827
            goto endjob;
828 829 830
        }
    }

831 832 833 834 835 836 837 838 839 840
#define VIR_SET_MEM_PARAMETER(FUNC, VALUE) \
    if (set_ ## VALUE) { \
        if (def) { \
            if ((rc = FUNC(priv->cgroup, VALUE)) < 0) \
                goto endjob; \
            def->mem.VALUE = VALUE; \
        } \
 \
        if (persistentDef) \
            persistentDef->mem.VALUE = VALUE; \
841 842 843
    }

    /* Soft limit doesn't clash with the others */
844
    VIR_SET_MEM_PARAMETER(virCgroupSetMemorySoftLimit, soft_limit);
845 846

    /* set hard limit before swap hard limit if decreasing it */
847 848
    if (def && def->mem.hard_limit > hard_limit) {
        VIR_SET_MEM_PARAMETER(virCgroupSetMemoryHardLimit, hard_limit);
849 850 851 852
        /* inhibit changing the limit a second time */
        set_hard_limit = false;
    }

853
    VIR_SET_MEM_PARAMETER(virCgroupSetMemSwapHardLimit, swap_hard_limit);
854 855

    /* otherwise increase it after swap hard limit */
856 857 858
    VIR_SET_MEM_PARAMETER(virCgroupSetMemoryHardLimit, hard_limit);

#undef VIR_SET_MEM_PARAMETER
859

860
    if (def &&
861
        virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0)
862
        goto endjob;
863

864
    if (persistentDef &&
865
        virDomainDefSave(persistentDef, driver->xmlopt, cfg->configDir) < 0)
866
        goto endjob;
867
    /* QEMU and LXC implementations are identical */
868 869

    ret = 0;
870 871

 endjob:
872
    virLXCDomainObjEndJob(driver, vm);
873

874
 cleanup:
875
    virDomainObjEndAPI(&vm);
876
    virObjectUnref(cfg);
877 878 879
    return ret;
}

880 881 882 883 884
static int
lxcDomainGetMemoryParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int *nparams,
                             unsigned int flags)
885
{
J
Ján Tomko 已提交
886
    virDomainDefPtr persistentDef = NULL;
887
    virDomainDefPtr def = NULL;
888
    virDomainObjPtr vm = NULL;
889
    virLXCDomainObjPrivatePtr priv = NULL;
890
    unsigned long long val;
891
    int ret = -1;
892
    size_t i;
893

894
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
895 896 897 898 899
                  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 已提交
900

M
Michal Privoznik 已提交
901
    if (!(vm = lxcDomObjFromDomain(dom)))
902
        goto cleanup;
M
Michal Privoznik 已提交
903

904
    priv = vm->privateData;
905

906
    if (virDomainGetMemoryParametersEnsureACL(dom->conn, vm->def) < 0)
907 908
        goto cleanup;

909 910 911 912
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
        goto cleanup;

    if (def &&
913 914 915
        !virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_MEMORY)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup memory controller is not mounted"));
916
        goto cleanup;
917
    }
918

919 920 921 922 923 924 925
    if ((*nparams) == 0) {
        /* Current number of memory parameters supported by cgroups */
        *nparams = LXC_NB_MEM_PARAM;
        ret = 0;
        goto cleanup;
    }

926
    for (i = 0; i < LXC_NB_MEM_PARAM && i < *nparams; i++) {
927
        virTypedParameterPtr param = &params[i];
928 929
        val = 0;

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

965 966
    if (*nparams > LXC_NB_MEM_PARAM)
        *nparams = LXC_NB_MEM_PARAM;
967 968
    ret = 0;

969
 cleanup:
970
    virDomainObjEndAPI(&vm);
971 972 973
    return ret;
}

974
static char *lxcDomainGetXMLDesc(virDomainPtr dom,
975
                                 unsigned int flags)
D
Daniel Veillard 已提交
976
{
977
    virLXCDriverPtr driver = dom->conn->privateData;
978 979
    virDomainObjPtr vm;
    char *ret = NULL;
D
Daniel Veillard 已提交
980

981
    virCheckFlags(VIR_DOMAIN_XML_COMMON_FLAGS, NULL);
982

M
Michal Privoznik 已提交
983
    if (!(vm = lxcDomObjFromDomain(dom)))
984
        goto cleanup;
D
Daniel Veillard 已提交
985

986 987 988
    if (virDomainGetXMLDescEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

989
    ret = virDomainDefFormat((flags & VIR_DOMAIN_XML_INACTIVE) &&
990
                             vm->newDef ? vm->newDef : vm->def,
991
                             driver->xmlopt,
992
                             virDomainDefFormatConvertXMLFlags(flags));
993

994
 cleanup:
995
    virDomainObjEndAPI(&vm);
996
    return ret;
D
Daniel Veillard 已提交
997 998
}

999 1000 1001 1002 1003 1004 1005
static char *lxcConnectDomainXMLFromNative(virConnectPtr conn,
                                           const char *nativeFormat,
                                           const char *nativeConfig,
                                           unsigned int flags)
{
    char *xml = NULL;
    virDomainDefPtr def = NULL;
1006 1007
    virLXCDriverPtr driver = conn->privateData;
    virCapsPtr caps = virLXCDriverGetCapabilities(driver, false);
1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019

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

1020
    if (!(def = lxcParseConfigString(nativeConfig, caps, driver->xmlopt)))
1021 1022
        goto cleanup;

1023
    xml = virDomainDefFormat(def, driver->xmlopt, 0);
1024

1025
 cleanup:
1026
    virObjectUnref(caps);
1027 1028 1029 1030
    virDomainDefFree(def);
    return xml;
}

1031
/**
1032
 * lxcDomainCreateWithFiles:
1033
 * @dom: domain to start
1034
 * @flags: Must be 0 for now
1035 1036 1037 1038 1039
 *
 * Looks up domain and starts it.
 *
 * Returns 0 on success or -1 in case of error
 */
1040 1041 1042 1043
static int lxcDomainCreateWithFiles(virDomainPtr dom,
                                    unsigned int nfiles,
                                    int *files,
                                    unsigned int flags)
1044
{
1045
    virLXCDriverPtr driver = dom->conn->privateData;
1046
    virDomainObjPtr vm;
1047
    virObjectEventPtr event = NULL;
1048
    int ret = -1;
1049
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
1050

1051
    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, -1);
1052

1053 1054
    virNWFilterReadLockFilterUpdates();

M
Michal Privoznik 已提交
1055
    if (!(vm = lxcDomObjFromDomain(dom)))
1056 1057
        goto cleanup;

1058
    if (virDomainCreateWithFilesEnsureACL(dom->conn, vm->def) < 0)
1059 1060
        goto cleanup;

1061
    if ((vm->def->nets != NULL) && !(cfg->have_netns)) {
1062 1063
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("System lacks NETNS support"));
1064 1065 1066
        goto cleanup;
    }

1067 1068 1069
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

1070
    if (virDomainObjIsActive(vm)) {
1071 1072
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is already running"));
1073
        goto endjob;
1074 1075
    }

1076
    ret = virLXCProcessStart(dom->conn, driver, vm,
1077
                             nfiles, files,
1078 1079
                             (flags & VIR_DOMAIN_START_AUTODESTROY),
                             VIR_DOMAIN_RUNNING_BOOTED);
1080

1081
    if (ret == 0) {
1082
        event = virDomainEventLifecycleNewFromObj(vm,
1083 1084
                                         VIR_DOMAIN_EVENT_STARTED,
                                         VIR_DOMAIN_EVENT_STARTED_BOOTED);
1085 1086 1087 1088
        virDomainAuditStart(vm, "booted", true);
    } else {
        virDomainAuditStart(vm, "booted", false);
    }
1089

1090
 endjob:
1091
    virLXCDomainObjEndJob(driver, vm);
1092

1093
 cleanup:
1094
    virDomainObjEndAPI(&vm);
1095
    virObjectEventStateQueue(driver->domainEventState, event);
1096
    virObjectUnref(cfg);
1097
    virNWFilterUnlockFilterUpdates();
1098
    return ret;
1099 1100
}

1101
/**
1102
 * lxcDomainCreate:
1103 1104 1105 1106 1107 1108
 * @dom: domain to start
 *
 * Looks up domain and starts it.
 *
 * Returns 0 on success or -1 in case of error
 */
1109
static int lxcDomainCreate(virDomainPtr dom)
1110
{
1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125
    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);
1126 1127
}

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

    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY |
                  VIR_DOMAIN_START_VALIDATE, NULL);

1159

1160
    if (flags & VIR_DOMAIN_START_VALIDATE)
1161
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
1162

1163 1164
    virNWFilterReadLockFilterUpdates();

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

1168
    if (!(def = virDomainDefParseString(xml, driver->xmlopt,
1169
                                        NULL, parse_flags)))
1170
        goto cleanup;
1171

1172
    if (virDomainCreateXMLWithFilesEnsureACL(conn, def) < 0)
1173 1174
        goto cleanup;

1175 1176 1177
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
        goto cleanup;

1178
    if ((def->nets != NULL) && !(cfg->have_netns)) {
1179 1180
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       "%s", _("System lacks NETNS support"));
1181
        goto cleanup;
1182 1183
    }

1184

1185
    if (!(vm = virDomainObjListAdd(driver->domains, def,
1186
                                   driver->xmlopt,
1187
                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
1188 1189
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
1190 1191
        goto cleanup;
    def = NULL;
1192

1193
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0) {
1194
        if (!vm->persistent)
1195 1196 1197 1198
            virDomainObjListRemove(driver->domains, vm);
        goto cleanup;
    }

1199
    if (virLXCProcessStart(conn, driver, vm,
1200
                           nfiles, files,
1201 1202
                           (flags & VIR_DOMAIN_START_AUTODESTROY),
                           VIR_DOMAIN_RUNNING_BOOTED) < 0) {
1203
        virDomainAuditStart(vm, "booted", false);
1204
        virLXCDomainObjEndJob(driver, vm);
1205
        if (!vm->persistent)
1206
            virDomainObjListRemove(driver->domains, vm);
1207
        goto cleanup;
1208 1209
    }

1210
    event = virDomainEventLifecycleNewFromObj(vm,
1211 1212
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
1213
    virDomainAuditStart(vm, "booted", true);
1214

1215
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
1216

1217
    virLXCDomainObjEndJob(driver, vm);
1218

1219
 cleanup:
1220
    virDomainDefFree(def);
1221
    virDomainObjEndAPI(&vm);
1222
    virObjectEventStateQueue(driver->domainEventState, event);
1223
    virObjectUnref(caps);
1224
    virObjectUnref(cfg);
1225
    virNWFilterUnlockFilterUpdates();
1226 1227 1228
    return dom;
}

1229 1230 1231 1232 1233 1234 1235 1236 1237 1238
/**
 * 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.
 */
1239 1240 1241
static virDomainPtr
lxcDomainCreateXML(virConnectPtr conn,
                   const char *xml,
1242 1243
                   unsigned int flags)
{
1244 1245 1246 1247
    return lxcDomainCreateXMLWithFiles(conn, xml, 0, NULL,  flags);
}


1248 1249
static int lxcDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr seclabel)
{
1250
    virLXCDriverPtr driver = dom->conn->privateData;
1251 1252 1253 1254 1255
    virDomainObjPtr vm;
    int ret = -1;

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

M
Michal Privoznik 已提交
1256
    if (!(vm = lxcDomObjFromDomain(dom)))
1257 1258
        goto cleanup;

1259 1260 1261
    if (virDomainGetSecurityLabelEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276
    /*
     * 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)) {
1277 1278 1279 1280 1281 1282 1283 1284
        virLXCDomainObjPrivatePtr priv = vm->privateData;

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

1285
        if (virSecurityManagerGetProcessLabel(driver->securityManager,
1286 1287
                                              vm->def, priv->initpid,
                                              seclabel) < 0)
1288 1289 1290 1291 1292
            goto cleanup;
    }

    ret = 0;

1293
 cleanup:
1294
    virDomainObjEndAPI(&vm);
1295 1296 1297 1298 1299 1300
    return ret;
}

static int lxcNodeGetSecurityModel(virConnectPtr conn,
                                   virSecurityModelPtr secmodel)
{
1301
    virLXCDriverPtr driver = conn->privateData;
1302
    virCapsPtr caps = NULL;
1303 1304 1305 1306
    int ret = 0;

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

1307 1308 1309
    if (virNodeGetSecurityModelEnsureACL(conn) < 0)
        goto cleanup;

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

1313
    /* we treat no driver as success, but simply return no data in *secmodel */
1314 1315
    if (caps->host.nsecModels == 0
        || caps->host.secModels[0].model == NULL)
1316 1317
        goto cleanup;

1318 1319
    if (virStrcpy(secmodel->model, caps->host.secModels[0].model,
                  VIR_SECURITY_MODEL_BUFLEN) < 0) {
1320 1321 1322
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security model string exceeds max %d bytes"),
                       VIR_SECURITY_MODEL_BUFLEN - 1);
1323 1324 1325 1326
        ret = -1;
        goto cleanup;
    }

1327 1328
    if (virStrcpy(secmodel->doi, caps->host.secModels[0].doi,
                  VIR_SECURITY_DOI_BUFLEN) < 0) {
1329 1330 1331
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security DOI string exceeds max %d bytes"),
                       VIR_SECURITY_DOI_BUFLEN-1);
1332 1333 1334 1335
        ret = -1;
        goto cleanup;
    }

1336
 cleanup:
1337
    virObjectUnref(caps);
1338 1339 1340 1341
    return ret;
}


1342
static int
1343 1344 1345 1346
lxcConnectDomainEventRegister(virConnectPtr conn,
                              virConnectDomainEventCallback callback,
                              void *opaque,
                              virFreeCallback freecb)
1347
{
1348
    virLXCDriverPtr driver = conn->privateData;
1349

1350 1351 1352
    if (virConnectDomainEventRegisterEnsureACL(conn) < 0)
        return -1;

1353 1354 1355 1356
    if (virDomainEventStateRegister(conn,
                                    driver->domainEventState,
                                    callback, opaque, freecb) < 0)
        return -1;
1357

1358
    return 0;
1359 1360
}

1361

1362
static int
1363 1364
lxcConnectDomainEventDeregister(virConnectPtr conn,
                                virConnectDomainEventCallback callback)
1365
{
1366
    virLXCDriverPtr driver = conn->privateData;
1367

1368 1369 1370
    if (virConnectDomainEventDeregisterEnsureACL(conn) < 0)
        return -1;

1371 1372 1373 1374
    if (virDomainEventStateDeregister(conn,
                                      driver->domainEventState,
                                      callback) < 0)
        return -1;
1375

1376
    return 0;
1377 1378
}

1379 1380

static int
1381 1382 1383 1384 1385 1386
lxcConnectDomainEventRegisterAny(virConnectPtr conn,
                                 virDomainPtr dom,
                                 int eventID,
                                 virConnectDomainEventGenericCallback callback,
                                 void *opaque,
                                 virFreeCallback freecb)
1387
{
1388
    virLXCDriverPtr driver = conn->privateData;
1389 1390
    int ret;

1391 1392 1393
    if (virConnectDomainEventRegisterAnyEnsureACL(conn) < 0)
        return -1;

1394 1395 1396 1397
    if (virDomainEventStateRegisterID(conn,
                                      driver->domainEventState,
                                      dom, eventID,
                                      callback, opaque, freecb, &ret) < 0)
1398
        ret = -1;
1399 1400 1401 1402 1403 1404

    return ret;
}


static int
1405 1406
lxcConnectDomainEventDeregisterAny(virConnectPtr conn,
                                   int callbackID)
1407
{
1408
    virLXCDriverPtr driver = conn->privateData;
1409

1410 1411 1412
    if (virConnectDomainEventDeregisterAnyEnsureACL(conn) < 0)
        return -1;

1413 1414
    if (virObjectEventStateDeregisterID(conn,
                                        driver->domainEventState,
1415
                                        callbackID, true) < 0)
1416
        return -1;
1417

1418
    return 0;
1419 1420 1421
}


1422
/**
1423
 * lxcDomainDestroyFlags:
1424
 * @dom: pointer to domain to destroy
1425
 * @flags: extra flags; not used yet.
1426 1427 1428 1429 1430
 *
 * Sends SIGKILL to container root process to terminate the container
 *
 * Returns 0 on success or -1 in case of error
 */
1431 1432 1433
static int
lxcDomainDestroyFlags(virDomainPtr dom,
                      unsigned int flags)
1434
{
1435
    virLXCDriverPtr driver = dom->conn->privateData;
1436
    virDomainObjPtr vm;
1437
    virObjectEventPtr event = NULL;
1438
    int ret = -1;
1439
    virLXCDomainObjPrivatePtr priv;
1440

1441 1442
    virCheckFlags(0, -1);

M
Michal Privoznik 已提交
1443
    if (!(vm = lxcDomObjFromDomain(dom)))
1444
        goto cleanup;
1445

1446 1447 1448
    if (virDomainDestroyFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1449
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_DESTROY) < 0)
1450 1451
        goto cleanup;

1452
    if (virDomainObjCheckActive(vm) < 0)
1453
        goto endjob;
1454

1455
    priv = vm->privateData;
1456
    ret = virLXCProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED);
1457
    event = virDomainEventLifecycleNewFromObj(vm,
1458 1459
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
1460
    priv->doneStopEvent = true;
1461
    virDomainAuditStop(vm, "destroyed");
1462

1463
 endjob:
1464
    virLXCDomainObjEndJob(driver, vm);
1465
    if (!vm->persistent)
1466
        virDomainObjListRemove(driver->domains, vm);
1467

1468
 cleanup:
1469
    virDomainObjEndAPI(&vm);
1470
    virObjectEventStateQueue(driver->domainEventState, event);
1471
    return ret;
1472
}
1473

1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487
/**
 * 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);
}

1488 1489 1490 1491 1492
static int lxcCheckNetNsSupport(void)
{
    const char *argv[] = {"ip", "link", "set", "lo", "netns", "-1", NULL};
    int ip_rc;

1493
    if (virRun(argv, &ip_rc) < 0 || ip_rc == 255)
1494
        return 0;
1495

1496
    if (virProcessNamespaceAvailable(VIR_PROCESS_NAMESPACE_NET) < 0)
1497
        return 0;
1498

1499
    return 1;
1500 1501
}

1502

1503 1504
static virSecurityManagerPtr
lxcSecurityInit(virLXCDriverConfigPtr cfg)
1505
{
1506 1507
    unsigned int flags = VIR_SECURITY_MANAGER_PRIVILEGED;

1508
    VIR_INFO("lxcSecurityInit %s", cfg->securityDriverName);
1509 1510 1511 1512 1513 1514

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

1515
    virSecurityManagerPtr mgr = virSecurityManagerNew(cfg->securityDriverName,
1516
                                                      LXC_DRIVER_NAME, flags);
1517 1518 1519
    if (!mgr)
        goto error;

1520
    return mgr;
1521

1522
 error:
1523
    VIR_ERROR(_("Failed to initialize security drivers"));
1524
    virObjectUnref(mgr);
1525
    return NULL;
1526 1527 1528
}


1529
static int lxcStateInitialize(bool privileged,
1530
                              const char *root,
J
Ján Tomko 已提交
1531 1532
                              virStateInhibitCallback callback G_GNUC_UNUSED,
                              void *opaque G_GNUC_UNUSED)
D
Daniel Veillard 已提交
1533
{
1534
    virLXCDriverConfigPtr cfg = NULL;
1535
    bool autostart = true;
1536

1537 1538 1539 1540 1541 1542
    if (root != NULL) {
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Driver does not support embedded mode"));
        return -1;
    }

1543
    /* Check that the user is root, silently disable if not */
1544
    if (!privileged) {
1545
        VIR_INFO("Not running privileged, disabling driver");
1546
        return VIR_DRV_STATE_INIT_SKIPPED;
1547 1548 1549
    }

    /* Check that this is a container enabled kernel */
1550 1551 1552 1553
    if (virProcessNamespaceAvailable(VIR_PROCESS_NAMESPACE_MNT |
                                     VIR_PROCESS_NAMESPACE_PID |
                                     VIR_PROCESS_NAMESPACE_UTS |
                                     VIR_PROCESS_NAMESPACE_IPC) < 0) {
1554
        VIR_INFO("LXC support not available in this kernel, disabling driver");
1555
        return VIR_DRV_STATE_INIT_SKIPPED;
1556 1557
    }

1558
    if (VIR_ALLOC(lxc_driver) < 0)
1559
        return VIR_DRV_STATE_INIT_ERROR;
1560
    lxc_driver->lockFD = -1;
1561 1562
    if (virMutexInit(&lxc_driver->lock) < 0) {
        VIR_FREE(lxc_driver);
1563
        return VIR_DRV_STATE_INIT_ERROR;
1564
    }
D
Daniel Veillard 已提交
1565

1566
    if (!(lxc_driver->domains = virDomainObjListNew()))
1567 1568
        goto cleanup;

1569
    lxc_driver->domainEventState = virObjectEventStateNew();
1570
    if (!lxc_driver->domainEventState)
1571 1572
        goto cleanup;

1573 1574
    lxc_driver->hostsysinfo = virSysinfoRead();

1575 1576 1577 1578 1579
    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 已提交
1580 1581

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

1585
    if (!(lxc_driver->securityManager = lxcSecurityInit(cfg)))
1586 1587
        goto cleanup;

1588
    if (!(lxc_driver->hostdevMgr = virHostdevManagerGetDefault()))
G
Guido Günther 已提交
1589 1590
        goto cleanup;

1591
    if (!(lxc_driver->xmlopt = lxcDomainXMLConfInit(lxc_driver)))
1592
        goto cleanup;
1593

1594
    if (!(lxc_driver->closeCallbacks = virCloseCallbacksNew()))
1595 1596
        goto cleanup;

1597 1598 1599 1600 1601 1602 1603
    if (virFileMakePath(cfg->stateDir) < 0) {
        virReportSystemError(errno,
                             _("Failed to mkdir %s"),
                             cfg->stateDir);
        goto cleanup;
    }

1604
    if ((lxc_driver->lockFD =
1605
         virPidFileAcquire(cfg->stateDir, "driver", false, getpid())) < 0)
1606 1607
        goto cleanup;

O
Osier Yang 已提交
1608
    /* Get all the running persistent or transient configs first */
1609
    if (virDomainObjListLoadAllConfigs(lxc_driver->domains,
1610
                                       cfg->stateDir,
1611
                                       NULL, true,
1612
                                       lxc_driver->xmlopt,
1613
                                       NULL, NULL) < 0)
O
Osier Yang 已提交
1614 1615
        goto cleanup;

1616
    virLXCProcessReconnectAll(lxc_driver, lxc_driver->domains);
O
Osier Yang 已提交
1617 1618

    /* Then inactive persistent configs */
1619
    if (virDomainObjListLoadAllConfigs(lxc_driver->domains,
1620
                                       cfg->configDir,
1621
                                       cfg->autostartDir, false,
1622
                                       lxc_driver->xmlopt,
1623
                                       NULL, NULL) < 0)
1624
        goto cleanup;
1625

1626 1627 1628 1629 1630
    if (virDriverShouldAutostart(cfg->stateDir, &autostart) < 0)
        goto cleanup;

    if (autostart)
        virLXCProcessAutostartAll(lxc_driver);
1631

1632
    return VIR_DRV_STATE_INIT_COMPLETE;
D
Daniel Veillard 已提交
1633

1634
 cleanup:
1635
    lxcStateCleanup();
1636
    return VIR_DRV_STATE_INIT_ERROR;
D
Daniel Veillard 已提交
1637 1638
}

1639 1640
static void lxcNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
{
1641
    virLXCDriverPtr driver = opaque;
1642 1643

    if (newVM) {
1644
        virObjectEventPtr event =
1645
            virDomainEventLifecycleNewFromObj(vm,
1646 1647
                                     VIR_DOMAIN_EVENT_DEFINED,
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED);
1648
        virObjectEventStateQueue(driver->domainEventState, event);
1649 1650 1651 1652
    }
}

/**
1653
 * lxcStateReload:
1654 1655 1656 1657 1658
 *
 * Function to restart the LXC driver, it will recheck the configuration
 * files and perform autostart
 */
static int
1659 1660
lxcStateReload(void)
{
1661 1662
    virLXCDriverConfigPtr cfg = NULL;

1663 1664 1665
    if (!lxc_driver)
        return 0;

1666 1667
    cfg = virLXCDriverGetConfig(lxc_driver);

1668
    virDomainObjListLoadAllConfigs(lxc_driver->domains,
1669
                                   cfg->configDir,
1670
                                   cfg->autostartDir, false,
1671
                                   lxc_driver->xmlopt,
1672
                                   lxcNotifyLoadDomain, lxc_driver);
1673
    virObjectUnref(cfg);
1674 1675 1676
    return 0;
}

1677
static int lxcStateCleanup(void)
D
Daniel Veillard 已提交
1678
{
1679
    if (lxc_driver == NULL)
1680
        return -1;
1681

1682
    virObjectUnref(lxc_driver->domains);
1683
    virObjectUnref(lxc_driver->domainEventState);
1684

1685
    virObjectUnref(lxc_driver->closeCallbacks);
1686

1687 1688
    virSysinfoDefFree(lxc_driver->hostsysinfo);

1689
    virObjectUnref(lxc_driver->hostdevMgr);
1690
    virObjectUnref(lxc_driver->caps);
1691
    virObjectUnref(lxc_driver->securityManager);
1692
    virObjectUnref(lxc_driver->xmlopt);
1693 1694 1695 1696

    if (lxc_driver->lockFD != -1)
        virPidFileRelease(lxc_driver->config->stateDir, "driver", lxc_driver->lockFD);

1697
    virObjectUnref(lxc_driver->config);
1698
    virMutexDestroy(&lxc_driver->lock);
1699
    VIR_FREE(lxc_driver);
1700 1701 1702

    return 0;
}
D
Daniel Veillard 已提交
1703

1704 1705 1706 1707 1708 1709
static int
lxcConnectSupportsFeature(virConnectPtr conn, int feature)
{
    if (virConnectSupportsFeatureEnsureACL(conn) < 0)
        return -1;

1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728
    switch ((virDrvFeature) feature) {
    case VIR_DRV_FEATURE_TYPED_PARAM_STRING:
        return 1;
    case VIR_DRV_FEATURE_FD_PASSING:
    case VIR_DRV_FEATURE_MIGRATE_CHANGE_PROTECTION:
    case VIR_DRV_FEATURE_MIGRATION_DIRECT:
    case VIR_DRV_FEATURE_MIGRATION_OFFLINE:
    case VIR_DRV_FEATURE_MIGRATION_P2P:
    case VIR_DRV_FEATURE_MIGRATION_PARAMS:
    case VIR_DRV_FEATURE_MIGRATION_V1:
    case VIR_DRV_FEATURE_MIGRATION_V2:
    case VIR_DRV_FEATURE_MIGRATION_V3:
    case VIR_DRV_FEATURE_PROGRAM_KEEPALIVE:
    case VIR_DRV_FEATURE_REMOTE:
    case VIR_DRV_FEATURE_REMOTE_CLOSE_CALLBACK:
    case VIR_DRV_FEATURE_REMOTE_EVENT_CALLBACK:
    case VIR_DRV_FEATURE_XML_MIGRATABLE:
    default:
        return 0;
1729 1730 1731
    }
}

D
Daniel Veillard 已提交
1732

1733
static int lxcConnectGetVersion(virConnectPtr conn, unsigned long *version)
D
Dan Smith 已提交
1734 1735 1736
{
    struct utsname ver;

1737
    uname(&ver);
D
Dan Smith 已提交
1738

1739 1740 1741
    if (virConnectGetVersionEnsureACL(conn) < 0)
        return -1;

1742
    if (virParseVersionString(ver.release, version, true) < 0) {
1743
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Unknown release: %s"), ver.release);
D
Dan Smith 已提交
1744 1745 1746 1747 1748
        return -1;
    }

    return 0;
}
1749

1750

1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793
static int
lxcDomainInterfaceAddresses(virDomainPtr dom,
                            virDomainInterfacePtr **ifaces,
                            unsigned int source,
                            unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;

    virCheckFlags(0, -1);

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

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

    if (virDomainObjCheckActive(vm) < 0)
        goto cleanup;

    switch (source) {
    case VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE:
        ret = virDomainNetDHCPInterfaces(vm->def, ifaces);
        break;

    case VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_ARP:
        ret = virDomainNetARPInterfaces(vm->def, ifaces);
        break;

    default:
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED,
                       _("Unknown IP address data source %d"),
                       source);
        break;
    }

 cleanup:
    virDomainObjEndAPI(&vm);
    return ret;
}



1794
static char *lxcConnectGetHostname(virConnectPtr conn)
1795
{
1796 1797 1798
    if (virConnectGetHostnameEnsureACL(conn) < 0)
        return NULL;

1799 1800 1801 1802
    return virGetHostname();
}


1803 1804
static char *lxcDomainGetSchedulerType(virDomainPtr dom,
                                       int *nparams)
1805
{
1806
    char *ret = NULL;
1807 1808
    virDomainObjPtr vm;
    virLXCDomainObjPrivatePtr priv;
1809

M
Michal Privoznik 已提交
1810
    if (!(vm = lxcDomObjFromDomain(dom)))
1811
        goto cleanup;
M
Michal Privoznik 已提交
1812

1813 1814
    priv = vm->privateData;

1815 1816 1817
    if (virDomainGetSchedulerTypeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1818 1819 1820 1821
    /* Domain not running, thus no cgroups - return defaults */
    if (!virDomainObjIsActive(vm)) {
        if (nparams)
            *nparams = 3;
1822
        ret = g_strdup("posix");
1823 1824 1825
        goto cleanup;
    }

1826
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
1827 1828
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPU controller is not mounted"));
1829 1830
        goto cleanup;
    }
1831

1832
    if (nparams) {
1833
        if (virCgroupSupportsCpuBW(priv->cgroup))
1834
            *nparams = 3;
1835 1836
        else
            *nparams = 1;
1837
    }
1838

1839
    ret = g_strdup("posix");
1840

1841
 cleanup:
1842
    virDomainObjEndAPI(&vm);
1843 1844 1845 1846 1847 1848 1849 1850
    return ret;
}


static int
lxcGetVcpuBWLive(virCgroupPtr cgroup, unsigned long long *period,
                 long long *quota)
{
1851
    if (virCgroupGetCpuCfsPeriod(cgroup, period) < 0)
1852 1853
        return -1;

1854
    if (virCgroupGetCpuCfsQuota(cgroup, quota) < 0)
1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870
        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 */
1871
        if (virCgroupGetCpuCfsPeriod(cgroup, &old_period) < 0)
1872 1873
            return -1;

1874
        if (virCgroupSetCpuCfsPeriod(cgroup, period) < 0)
1875 1876 1877 1878
            return -1;
    }

    if (quota) {
1879 1880
        if (virCgroupSetCpuCfsQuota(cgroup, quota) < 0)
            goto error;
1881 1882 1883 1884
    }

    return 0;

1885
 error:
1886
    if (period) {
1887 1888 1889
        virErrorPtr saved;

        virErrorPreserveLast(&saved);
1890
        virCgroupSetCpuCfsPeriod(cgroup, old_period);
1891
        virErrorRestore(&saved);
1892 1893 1894
    }

    return -1;
1895 1896
}

1897

1898
static int
1899 1900 1901 1902
lxcDomainSetSchedulerParametersFlags(virDomainPtr dom,
                                     virTypedParameterPtr params,
                                     int nparams,
                                     unsigned int flags)
1903
{
1904
    virLXCDriverPtr driver = dom->conn->privateData;
1905
    virCapsPtr caps = NULL;
1906
    size_t i;
1907
    virDomainObjPtr vm = NULL;
1908
    virDomainDefPtr def = NULL;
J
Ján Tomko 已提交
1909 1910
    virDomainDefPtr persistentDefCopy = NULL;
    virDomainDefPtr persistentDef = NULL;
1911
    int ret = -1;
1912
    int rc;
1913
    virLXCDomainObjPrivatePtr priv;
1914
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
1915

1916 1917
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
1918 1919 1920 1921 1922 1923 1924 1925
    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)
1926
        return -1;
1927

M
Michal Privoznik 已提交
1928
    if (!(vm = lxcDomObjFromDomain(dom)))
1929
        goto cleanup;
M
Michal Privoznik 已提交
1930

1931
    priv = vm->privateData;
1932

1933 1934 1935
    if (virDomainSetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

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

1939 1940 1941
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

1942
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
1943
        goto endjob;
1944

1945
    if (persistentDef) {
1946
        /* Make a copy for updated domain. */
1947
        persistentDefCopy = virDomainObjCopyPersistentDef(vm, driver->xmlopt, NULL);
J
Ján Tomko 已提交
1948
        if (!persistentDefCopy)
1949
            goto endjob;
1950 1951
    }

1952
    if (def) {
1953
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
1954 1955
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup CPU controller is not mounted"));
1956
            goto endjob;
1957 1958
        }
    }
1959 1960

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

1963
        if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_CPU_SHARES)) {
1964
            if (def) {
1965
                unsigned long long val;
1966
                if (virCgroupSetCpuShares(priv->cgroup, params[i].value.ul) < 0)
1967
                    goto endjob;
1968

1969
                if (virCgroupGetCpuShares(priv->cgroup, &val) < 0)
1970
                    goto endjob;
1971

1972 1973
                def->cputune.shares = val;
                def->cputune.sharesSpecified = true;
1974 1975
            }

1976
            if (persistentDef) {
J
Ján Tomko 已提交
1977 1978
                persistentDefCopy->cputune.shares = params[i].value.ul;
                persistentDefCopy->cputune.sharesSpecified = true;
1979 1980
            }
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_PERIOD)) {
1981
            if (def) {
1982
                rc = lxcSetVcpuBWLive(priv->cgroup, params[i].value.ul, 0);
1983
                if (rc != 0)
1984
                    goto endjob;
1985 1986

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

1990
            if (persistentDef)
J
Ján Tomko 已提交
1991
                persistentDefCopy->cputune.period = params[i].value.ul;
1992
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_QUOTA)) {
1993
            if (def) {
1994
                rc = lxcSetVcpuBWLive(priv->cgroup, 0, params[i].value.l);
1995
                if (rc != 0)
1996
                    goto endjob;
1997 1998

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

2002
            if (persistentDef)
J
Ján Tomko 已提交
2003
                persistentDefCopy->cputune.quota = params[i].value.l;
2004
        }
2005
    }
2006

2007
    if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0)
2008
        goto endjob;
2009

2010

2011
    if (persistentDef) {
2012
        rc = virDomainDefSave(persistentDefCopy, driver->xmlopt,
2013
                              cfg->configDir);
2014
        if (rc < 0)
2015
            goto endjob;
2016

J
Ján Tomko 已提交
2017 2018
        virDomainObjAssignDef(vm, persistentDefCopy, false, NULL);
        persistentDefCopy = NULL;
2019
    }
2020

2021
    ret = 0;
2022

2023
 endjob:
2024
    virLXCDomainObjEndJob(driver, vm);
2025

2026
 cleanup:
J
Ján Tomko 已提交
2027
    virDomainDefFree(persistentDefCopy);
2028
    virDomainObjEndAPI(&vm);
2029
    virObjectUnref(caps);
2030
    virObjectUnref(cfg);
2031
    return ret;
2032 2033
}

2034
static int
2035 2036 2037
lxcDomainSetSchedulerParameters(virDomainPtr domain,
                                virTypedParameterPtr params,
                                int nparams)
2038
{
2039
    return lxcDomainSetSchedulerParametersFlags(domain, params, nparams, 0);
2040 2041 2042
}

static int
2043 2044 2045 2046
lxcDomainGetSchedulerParametersFlags(virDomainPtr dom,
                                     virTypedParameterPtr params,
                                     int *nparams,
                                     unsigned int flags)
2047
{
2048
    virDomainObjPtr vm = NULL;
2049
    virDomainDefPtr def;
E
Eric Blake 已提交
2050
    virDomainDefPtr persistentDef;
2051 2052 2053
    unsigned long long shares = 0;
    unsigned long long period = 0;
    long long quota = 0;
2054
    int ret = -1;
2055 2056 2057
    int rc;
    bool cpu_bw_status = false;
    int saved_nparams = 0;
2058
    virLXCDomainObjPrivatePtr priv;
2059

2060
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
2061 2062 2063 2064 2065
                  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;
2066

M
Michal Privoznik 已提交
2067
    if (!(vm = lxcDomObjFromDomain(dom)))
2068
        goto cleanup;
M
Michal Privoznik 已提交
2069

2070 2071
    priv = vm->privateData;

2072 2073 2074
    if (virDomainGetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2075 2076
    if (*nparams > 1)
        cpu_bw_status = virCgroupSupportsCpuBW(priv->cgroup);
2077

2078
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
E
Eric Blake 已提交
2079
        goto cleanup;
2080

2081
    if (persistentDef) {
E
Eric Blake 已提交
2082
        shares = persistentDef->cputune.shares;
2083
        if (*nparams > 1) {
E
Eric Blake 已提交
2084 2085
            period = persistentDef->cputune.period;
            quota = persistentDef->cputune.quota;
2086
            cpu_bw_status = true; /* Allow copy of data to params[] */
2087 2088 2089 2090
        }
        goto out;
    }

2091
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
2092 2093
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPU controller is not mounted"));
2094
        goto cleanup;
2095 2096
    }

2097
    if (virCgroupGetCpuShares(priv->cgroup, &shares) < 0)
2098
        goto cleanup;
2099 2100

    if (*nparams > 1 && cpu_bw_status) {
2101
        rc = lxcGetVcpuBWLive(priv->cgroup, &period, &quota);
2102 2103 2104
        if (rc != 0)
            goto cleanup;
    }
2105
 out:
2106 2107
    if (virTypedParameterAssign(&params[0], VIR_DOMAIN_SCHEDULER_CPU_SHARES,
                                VIR_TYPED_PARAM_ULLONG, shares) < 0)
C
Chris Lalancette 已提交
2108
        goto cleanup;
2109 2110 2111 2112
    saved_nparams++;

    if (cpu_bw_status) {
        if (*nparams > saved_nparams) {
2113 2114 2115
            if (virTypedParameterAssign(&params[1],
                                        VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
                                        VIR_TYPED_PARAM_ULLONG, period) < 0)
2116 2117 2118 2119 2120
                goto cleanup;
            saved_nparams++;
        }

        if (*nparams > saved_nparams) {
2121 2122 2123
            if (virTypedParameterAssign(&params[2],
                                        VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
                                        VIR_TYPED_PARAM_LLONG, quota) < 0)
2124 2125 2126 2127 2128 2129 2130
                goto cleanup;
            saved_nparams++;
        }
    }

    *nparams = saved_nparams;

2131
    ret = 0;
2132

2133
 cleanup:
2134
    virDomainObjEndAPI(&vm);
2135
    return ret;
2136 2137
}

2138
static int
2139 2140 2141
lxcDomainGetSchedulerParameters(virDomainPtr domain,
                                virTypedParameterPtr params,
                                int *nparams)
2142
{
2143
    return lxcDomainGetSchedulerParametersFlags(domain, params, nparams, 0);
2144 2145
}

2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173
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))
2174
        goto parse_error;
2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188

    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)
2189
            goto parse_error;
2190

2191
        result[i].path = g_strndup(temp, p - temp);
2192 2193 2194 2195 2196

        /* value */
        temp = p + 1;

        if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
2197
            if (virStrToLong_uip(temp, &p, 10, &result[i].weight) < 0)
2198
                goto number_error;
2199
        } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS)) {
2200
            if (virStrToLong_uip(temp, &p, 10, &result[i].riops) < 0)
2201
                goto number_error;
2202
        } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS)) {
2203
            if (virStrToLong_uip(temp, &p, 10, &result[i].wiops) < 0)
2204
                goto number_error;
2205
        } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS)) {
2206
            if (virStrToLong_ullp(temp, &p, 10, &result[i].rbps) < 0)
2207
                goto number_error;
2208
        } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
2209
            if (virStrToLong_ullp(temp, &p, 10, &result[i].wbps) < 0)
2210
                goto number_error;
2211
        } else {
2212 2213 2214
            virReportError(VIR_ERR_INVALID_ARG,
                           _("unknown parameter '%s'"), type);
            goto cleanup;
2215 2216 2217 2218 2219 2220 2221
        }

        i++;

        if (*p == '\0')
            break;
        else if (*p != ',')
2222
            goto parse_error;
2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233
        temp = p + 1;
    }

    if (!i)
        VIR_FREE(result);

    *dev = result;
    *size = i;

    return 0;

2234
 parse_error:
2235 2236 2237
    virReportError(VIR_ERR_INVALID_ARG,
                   _("unable to parse blkio device '%s' '%s'"),
                   type, blkioDeviceStr);
2238 2239 2240 2241 2242 2243 2244
    goto cleanup;

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

2245
 cleanup:
J
John Ferlan 已提交
2246 2247 2248 2249
    if (result) {
        virBlkioDeviceArrayClear(result, ndevices);
        VIR_FREE(result);
    }
2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271
    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;

2272
                if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
2273
                    dest->weight = src->weight;
2274
                } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS)) {
2275
                    dest->riops = src->riops;
2276
                } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS)) {
2277
                    dest->wiops = src->wiops;
2278
                } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS)) {
2279
                    dest->rbps = src->rbps;
2280
                } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
2281
                    dest->wbps = src->wbps;
2282
                } else {
2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297
                    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];

2298
            if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
2299
                dest->weight = src->weight;
2300
            } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS)) {
2301
                dest->riops = src->riops;
2302
            } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS)) {
2303
                dest->wiops = src->wiops;
2304
            } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS)) {
2305
                dest->rbps = src->rbps;
2306
            } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
2307
                dest->wbps = src->wbps;
2308
            } else {
2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320
                *dest_size = *dest_size - 1;
                return -1;
            }

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

    return 0;
}

2321

2322 2323 2324
static int
lxcDomainBlockStats(virDomainPtr dom,
                    const char *path,
2325
                    virDomainBlockStatsPtr stats)
2326
{
2327
    virLXCDriverPtr driver = dom->conn->privateData;
2328
    int ret = -1;
2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340
    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;

2341 2342 2343
   if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_QUERY) < 0)
        goto cleanup;

2344
    if (virDomainObjCheckActive(vm) < 0)
2345
        goto endjob;
2346 2347 2348 2349

    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("blkio cgroup isn't mounted"));
2350
        goto endjob;
2351 2352 2353 2354 2355 2356 2357 2358 2359
    }

    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);
2360
        goto endjob;
2361 2362
    }

2363
    if (!(disk = virDomainDiskByName(vm->def, path, false))) {
2364 2365
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path: %s"), path);
2366
        goto endjob;
2367 2368 2369 2370 2371
    }

    if (!disk->info.alias) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("missing disk device alias name for %s"), disk->dst);
2372
        goto endjob;
2373 2374 2375 2376 2377 2378 2379 2380
    }

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

 endjob:
2383
    virLXCDomainObjEndJob(driver, vm);
2384

2385
 cleanup:
2386
    virDomainObjEndAPI(&vm);
2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397
    return ret;
}


static int
lxcDomainBlockStatsFlags(virDomainPtr dom,
                         const char * path,
                         virTypedParameterPtr params,
                         int * nparams,
                         unsigned int flags)
{
2398
    virLXCDriverPtr driver = dom->conn->privateData;
2399
    int tmp, ret = -1;
2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410
    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;

2411
    if (!*nparams) {
2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423
        *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;

2424 2425 2426
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_QUERY) < 0)
        goto cleanup;

2427
    if (virDomainObjCheckActive(vm) < 0)
2428
        goto endjob;
2429 2430 2431 2432

    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("blkio cgroup isn't mounted"));
2433
        goto endjob;
2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444
    }

    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"));
2445
            goto endjob;
2446 2447
        }
    } else {
2448
        if (!(disk = virDomainDiskByName(vm->def, path, false))) {
2449 2450
            virReportError(VIR_ERR_INVALID_ARG,
                           _("invalid path: %s"), path);
2451
            goto endjob;
2452 2453 2454 2455 2456
        }

        if (!disk->info.alias) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("missing disk device alias name for %s"), disk->dst);
2457
            goto endjob;
2458 2459 2460 2461 2462 2463 2464 2465 2466 2467
        }

        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"));
2468
            goto endjob;
2469 2470 2471 2472 2473 2474 2475 2476 2477 2478
        }
    }

    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)
2479
            goto endjob;
2480 2481 2482 2483 2484 2485 2486
        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)
2487
            goto endjob;
2488 2489 2490 2491 2492 2493 2494
        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)
2495
            goto endjob;
2496 2497 2498 2499 2500 2501 2502
        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)
2503
            goto endjob;
2504 2505 2506 2507 2508 2509
        tmp++;
    }

    ret = 0;
    *nparams = tmp;

2510
 endjob:
2511
    virLXCDomainObjEndJob(driver, vm);
2512

2513
 cleanup:
2514
    virDomainObjEndAPI(&vm);
2515 2516 2517 2518
    return ret;
}


2519 2520 2521 2522 2523
static int
lxcDomainSetBlkioParameters(virDomainPtr dom,
                            virTypedParameterPtr params,
                            int nparams,
                            unsigned int flags)
2524
{
2525
    virLXCDriverPtr driver = dom->conn->privateData;
2526
    size_t i;
2527
    virDomainObjPtr vm = NULL;
2528
    virDomainDefPtr def = NULL;
2529 2530
    virDomainDefPtr persistentDef = NULL;
    int ret = -1;
2531
    virLXCDriverConfigPtr cfg = NULL;
2532
    virLXCDomainObjPrivatePtr priv;
2533 2534 2535

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
2536 2537 2538
    if (virTypedParamsValidate(params, nparams,
                               VIR_DOMAIN_BLKIO_WEIGHT,
                               VIR_TYPED_PARAM_UINT,
2539 2540 2541 2542 2543 2544 2545 2546 2547 2548
                               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,
2549
                               NULL) < 0)
2550 2551
        return -1;

M
Michal Privoznik 已提交
2552
    if (!(vm = lxcDomObjFromDomain(dom)))
2553
        return -1;
M
Michal Privoznik 已提交
2554

2555
    priv = vm->privateData;
2556
    cfg = virLXCDriverGetConfig(driver);
2557

2558 2559 2560
    if (virDomainSetBlkioParametersEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

2561 2562 2563
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

2564
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
2565
        goto endjob;
2566

2567
    if (def) {
2568
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) {
2569 2570
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("blkio cgroup isn't mounted"));
2571
            goto endjob;
2572
        }
2573
    }
2574

2575
    ret = 0;
2576
    if (def) {
2577 2578 2579 2580
        for (i = 0; i < nparams; i++) {
            virTypedParameterPtr param = &params[i];

            if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
2581
                if (virCgroupSetBlkioWeight(priv->cgroup, params[i].value.ui) < 0)
2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603
                    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,
2604 2605 2606 2607
                                                          devices[j].weight) < 0 ||
                            virCgroupGetBlkioDeviceWeight(priv->cgroup,
                                                          devices[j].path,
                                                          &devices[j].weight) < 0) {
2608 2609 2610 2611 2612 2613 2614 2615
                            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,
2616 2617 2618 2619
                                                            devices[j].riops) < 0 ||
                            virCgroupGetBlkioDeviceReadIops(priv->cgroup,
                                                            devices[j].path,
                                                            &devices[j].riops) < 0) {
2620 2621 2622 2623 2624 2625 2626 2627
                            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,
2628 2629 2630 2631
                                                             devices[j].wiops) < 0 ||
                            virCgroupGetBlkioDeviceWriteIops(priv->cgroup,
                                                             devices[j].path,
                                                             &devices[j].wiops) < 0) {
2632 2633 2634 2635 2636 2637 2638 2639
                            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,
2640 2641 2642 2643
                                                           devices[j].rbps) < 0 ||
                            virCgroupGetBlkioDeviceReadBps(priv->cgroup,
                                                           devices[j].path,
                                                           &devices[j].rbps) < 0) {
2644 2645 2646 2647
                            ret = -1;
                            break;
                        }
                    }
2648
                } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
2649 2650 2651
                    for (j = 0; j < ndevices; j++) {
                        if (virCgroupSetBlkioDeviceWriteBps(priv->cgroup,
                                                            devices[j].path,
2652 2653 2654 2655
                                                            devices[j].wbps) < 0 ||
                            virCgroupGetBlkioDeviceWriteBps(priv->cgroup,
                                                            devices[j].path,
                                                            &devices[j].wbps) < 0) {
2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670
                            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 ||
2671 2672
                    lxcDomainMergeBlkioDevice(&def->blkio.devices,
                                              &def->blkio.ndevices,
2673 2674 2675 2676
                                              devices, ndevices, param->field) < 0)
                    ret = -1;
                virBlkioDeviceArrayClear(devices, ndevices);
                VIR_FREE(devices);
2677 2678
            }
        }
E
Eric Blake 已提交
2679
    }
2680
    if (ret < 0)
2681
        goto endjob;
2682
    if (persistentDef) {
2683 2684 2685 2686 2687
        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;
2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708
            } 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);
2709 2710 2711
            }
        }

2712
        if (virDomainDefSave(persistentDef, driver->xmlopt, cfg->configDir) < 0)
2713
            ret = -1;
2714 2715
    }

2716
 endjob:
2717
    virLXCDomainObjEndJob(driver, vm);
2718

2719
 cleanup:
2720
    virDomainObjEndAPI(&vm);
2721
    virObjectUnref(cfg);
2722 2723 2724 2725
    return ret;
}


2726 2727
#define LXC_NB_BLKIO_PARAM  6

2728 2729 2730 2731 2732
static int
lxcDomainGetBlkioParameters(virDomainPtr dom,
                            virTypedParameterPtr params,
                            int *nparams,
                            unsigned int flags)
2733 2734
{
    virDomainObjPtr vm = NULL;
2735
    virDomainDefPtr def = NULL;
2736
    virDomainDefPtr persistentDef = NULL;
2737
    int maxparams = LXC_NB_BLKIO_PARAM;
2738 2739
    unsigned int val;
    int ret = -1;
2740
    virLXCDomainObjPrivatePtr priv;
2741 2742

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
2743 2744 2745 2746 2747 2748 2749
                  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;
2750

M
Michal Privoznik 已提交
2751
    if (!(vm = lxcDomObjFromDomain(dom)))
2752
        return -1;
M
Michal Privoznik 已提交
2753

2754
    priv = vm->privateData;
2755

2756 2757 2758
    if (virDomainGetBlkioParametersEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2759 2760 2761 2762 2763
    if ((*nparams) == 0) {
        /* Current number of blkio parameters supported by cgroups */
        *nparams = LXC_NB_BLKIO_PARAM;
        ret = 0;
        goto cleanup;
2764 2765
    } else if (*nparams < maxparams) {
        maxparams = *nparams;
2766 2767
    }

2768 2769
    *nparams = 0;

2770
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
E
Eric Blake 已提交
2771
        goto cleanup;
2772

2773
    if (def) {
2774
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) {
2775 2776
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("blkio cgroup isn't mounted"));
2777 2778 2779
            goto cleanup;
        }

2780 2781 2782 2783 2784 2785 2786
        /* 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;
2787

2788 2789 2790
        if (virDomainGetBlkioParametersAssignFromDef(def, params, nparams,
                                                     maxparams) < 0)
            goto cleanup;
2791

2792
    } else if (persistentDef) {
2793 2794 2795 2796 2797 2798
        /* fill blkio weight here */
        if (virTypedParameterAssign(&(params[(*nparams)++]),
                                    VIR_DOMAIN_BLKIO_WEIGHT,
                                    VIR_TYPED_PARAM_UINT,
                                    persistentDef->blkio.weight) < 0)
            goto cleanup;
2799

2800 2801 2802
        if (virDomainGetBlkioParametersAssignFromDef(persistentDef, params,
                                                     nparams, maxparams) < 0)
            goto cleanup;
2803 2804 2805 2806
    }

    ret = 0;

2807
 cleanup:
2808
    virDomainObjEndAPI(&vm);
2809 2810 2811 2812
    return ret;
}


2813 2814
static int
lxcDomainInterfaceStats(virDomainPtr dom,
2815
                        const char *device,
2816
                        virDomainInterfaceStatsPtr stats)
2817 2818 2819
{
    virDomainObjPtr vm;
    int ret = -1;
2820
    virLXCDriverPtr driver = dom->conn->privateData;
M
Michal Privoznik 已提交
2821
    virDomainNetDefPtr net = NULL;
2822

M
Michal Privoznik 已提交
2823
    if (!(vm = lxcDomObjFromDomain(dom)))
2824 2825
        goto cleanup;

2826 2827 2828
    if (virDomainInterfaceStatsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2829 2830 2831
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_QUERY) < 0)
        goto cleanup;

2832
    if (virDomainObjCheckActive(vm) < 0)
2833
        goto endjob;
2834

2835
    if (!(net = virDomainNetFind(vm->def, device)))
M
Michal Privoznik 已提交
2836 2837
        goto endjob;

2838
    if (virNetDevTapInterfaceStats(net->ifname, stats,
2839
                                   !virDomainNetTypeSharesHostView(net)) < 0)
M
Michal Privoznik 已提交
2840 2841 2842
        goto endjob;

    ret = 0;
2843

2844
 endjob:
2845
    virLXCDomainObjEndJob(driver, vm);
2846

2847
 cleanup:
2848
    virDomainObjEndAPI(&vm);
2849 2850
    return ret;
}
2851

2852

2853
static int lxcDomainGetAutostart(virDomainPtr dom,
2854 2855
                                   int *autostart)
{
2856 2857 2858
    virDomainObjPtr vm;
    int ret = -1;

M
Michal Privoznik 已提交
2859
    if (!(vm = lxcDomObjFromDomain(dom)))
2860 2861
        goto cleanup;

2862 2863 2864
    if (virDomainGetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2865 2866 2867
    *autostart = vm->autostart;
    ret = 0;

2868
 cleanup:
2869
    virDomainObjEndAPI(&vm);
2870 2871 2872 2873
    return ret;
}

static int lxcDomainSetAutostart(virDomainPtr dom,
2874 2875
                                   int autostart)
{
2876
    virLXCDriverPtr driver = dom->conn->privateData;
2877 2878 2879
    virDomainObjPtr vm;
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;
2880
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
2881

M
Michal Privoznik 已提交
2882
    if (!(vm = lxcDomObjFromDomain(dom)))
2883 2884
        goto cleanup;

2885 2886 2887
    if (virDomainSetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2888 2889 2890
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

2891
    if (!vm->persistent) {
2892 2893
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Cannot set autostart for transient domain"));
2894
        goto endjob;
2895 2896 2897 2898
    }

    autostart = (autostart != 0);

2899 2900
    if (vm->autostart == autostart) {
        ret = 0;
2901
        goto endjob;
2902
    }
2903

2904
    configFile = virDomainConfigFile(cfg->configDir,
2905 2906
                                     vm->def->name);
    if (configFile == NULL)
2907
        goto endjob;
2908
    autostartLink = virDomainConfigFile(cfg->autostartDir,
2909 2910
                                        vm->def->name);
    if (autostartLink == NULL)
2911
        goto endjob;
2912

2913
    if (autostart) {
2914
        if (virFileMakePath(cfg->autostartDir) < 0) {
2915
            virReportSystemError(errno,
2916
                                 _("Cannot create autostart directory %s"),
2917
                                 cfg->autostartDir);
2918
            goto endjob;
2919 2920
        }

2921
        if (symlink(configFile, autostartLink) < 0) {
2922
            virReportSystemError(errno,
2923 2924
                                 _("Failed to create symlink '%s to '%s'"),
                                 autostartLink, configFile);
2925
            goto endjob;
2926 2927 2928
        }
    } else {
        if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
2929
            virReportSystemError(errno,
2930 2931
                                 _("Failed to delete symlink '%s'"),
                                 autostartLink);
2932
            goto endjob;
2933
        }
2934
    }
2935 2936

    vm->autostart = autostart;
2937 2938
    ret = 0;

2939
 endjob:
2940 2941
    virLXCDomainObjEndJob(driver, vm);

2942
 cleanup:
2943 2944
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
2945
    virDomainObjEndAPI(&vm);
2946
    virObjectUnref(cfg);
2947 2948 2949
    return ret;
}

2950
static int lxcFreezeContainer(virDomainObjPtr vm)
R
Ryota Ozaki 已提交
2951 2952 2953 2954 2955 2956 2957
{
    int timeout = 1000; /* In milliseconds */
    int check_interval = 1; /* In milliseconds */
    int exp = 10;
    int waited_time = 0;
    int ret = -1;
    char *state = NULL;
2958
    virLXCDomainObjPrivatePtr priv = vm->privateData;
2959

R
Ryota Ozaki 已提交
2960 2961 2962 2963 2964 2965 2966 2967 2968
    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)
         */
2969
        r = virCgroupSetFreezerState(priv->cgroup, "FROZEN");
R
Ryota Ozaki 已提交
2970 2971 2972

        /*
         * Returning EBUSY explicitly indicates that the group is
2973
         * being frozen but incomplete, and other errors are true
R
Ryota Ozaki 已提交
2974 2975 2976 2977 2978 2979 2980
         * errors.
         */
        if (r < 0 && r != -EBUSY) {
            VIR_DEBUG("Writing freezer.state failed with errno: %d", r);
            goto error;
        }
        if (r == -EBUSY)
2981
            VIR_DEBUG("Writing freezer.state gets EBUSY");
R
Ryota Ozaki 已提交
2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993

        /*
         * 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".
         */
2994
        g_usleep(check_interval * 1000);
R
Ryota Ozaki 已提交
2995

2996
        r = virCgroupGetFreezerState(priv->cgroup, &state);
R
Ryota Ozaki 已提交
2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020

        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);
    }
3021
    VIR_DEBUG("lxcFreezeContainer timeout");
3022
 error:
R
Ryota Ozaki 已提交
3023 3024 3025 3026 3027
    /*
     * 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.
     */
3028
    virCgroupSetFreezerState(priv->cgroup, "THAWED");
R
Ryota Ozaki 已提交
3029 3030
    ret = -1;

3031
 cleanup:
R
Ryota Ozaki 已提交
3032 3033 3034 3035 3036 3037
    VIR_FREE(state);
    return ret;
}

static int lxcDomainSuspend(virDomainPtr dom)
{
3038
    virLXCDriverPtr driver = dom->conn->privateData;
R
Ryota Ozaki 已提交
3039
    virDomainObjPtr vm;
3040
    virObjectEventPtr event = NULL;
R
Ryota Ozaki 已提交
3041
    int ret = -1;
3042
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
3043

M
Michal Privoznik 已提交
3044
    if (!(vm = lxcDomObjFromDomain(dom)))
R
Ryota Ozaki 已提交
3045 3046
        goto cleanup;

3047 3048 3049
    if (virDomainSuspendEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3050 3051 3052
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

3053
    if (virDomainObjCheckActive(vm) < 0)
3054
        goto endjob;
R
Ryota Ozaki 已提交
3055

J
Jiri Denemark 已提交
3056
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) {
3057
        if (lxcFreezeContainer(vm) < 0) {
3058 3059
            virReportError(VIR_ERR_OPERATION_FAILED,
                           "%s", _("Suspend operation failed"));
3060
            goto endjob;
R
Ryota Ozaki 已提交
3061
        }
J
Jiri Denemark 已提交
3062
        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
R
Ryota Ozaki 已提交
3063

3064
        event = virDomainEventLifecycleNewFromObj(vm,
R
Ryota Ozaki 已提交
3065 3066 3067 3068
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
    }

3069
    if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0)
3070
        goto endjob;
R
Ryota Ozaki 已提交
3071 3072
    ret = 0;

3073
 endjob:
3074 3075
    virLXCDomainObjEndJob(driver, vm);

3076
 cleanup:
3077
    virObjectEventStateQueue(driver->domainEventState, event);
3078
    virDomainObjEndAPI(&vm);
3079
    virObjectUnref(cfg);
R
Ryota Ozaki 已提交
3080 3081 3082 3083 3084
    return ret;
}

static int lxcDomainResume(virDomainPtr dom)
{
3085
    virLXCDriverPtr driver = dom->conn->privateData;
R
Ryota Ozaki 已提交
3086
    virDomainObjPtr vm;
3087
    virObjectEventPtr event = NULL;
R
Ryota Ozaki 已提交
3088
    int ret = -1;
3089
    int state;
3090
    virLXCDomainObjPrivatePtr priv;
3091
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
3092

M
Michal Privoznik 已提交
3093
    if (!(vm = lxcDomObjFromDomain(dom)))
R
Ryota Ozaki 已提交
3094 3095
        goto cleanup;

3096 3097
    priv = vm->privateData;

3098 3099 3100
    if (virDomainResumeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3101 3102 3103
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

3104
    if (virDomainObjCheckActive(vm) < 0)
3105
        goto endjob;
R
Ryota Ozaki 已提交
3106

3107 3108 3109 3110 3111 3112
    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) {
3113
        if (virCgroupSetFreezerState(priv->cgroup, "THAWED") < 0) {
3114 3115
            virReportError(VIR_ERR_OPERATION_FAILED,
                           "%s", _("Resume operation failed"));
3116
            goto endjob;
R
Ryota Ozaki 已提交
3117
        }
J
Jiri Denemark 已提交
3118 3119
        virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
                             VIR_DOMAIN_RUNNING_UNPAUSED);
R
Ryota Ozaki 已提交
3120

3121
        event = virDomainEventLifecycleNewFromObj(vm,
R
Ryota Ozaki 已提交
3122 3123 3124 3125
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
    }

3126
    if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0)
3127
        goto endjob;
R
Ryota Ozaki 已提交
3128 3129
    ret = 0;

3130
 endjob:
3131 3132
    virLXCDomainObjEndJob(driver, vm);

3133
 cleanup:
3134
    virObjectEventStateQueue(driver->domainEventState, event);
3135
    virDomainObjEndAPI(&vm);
3136
    virObjectUnref(cfg);
R
Ryota Ozaki 已提交
3137 3138 3139
    return ret;
}

3140 3141
static int
lxcDomainOpenConsole(virDomainPtr dom,
3142
                      const char *dev_name,
3143 3144 3145 3146 3147 3148
                      virStreamPtr st,
                      unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainChrDefPtr chr = NULL;
3149
    size_t i;
3150 3151 3152

    virCheckFlags(0, -1);

M
Michal Privoznik 已提交
3153
    if (!(vm = lxcDomObjFromDomain(dom)))
3154 3155
        goto cleanup;

3156 3157 3158
    if (virDomainOpenConsoleEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3159
    if (virDomainObjCheckActive(vm) < 0)
3160 3161
        goto cleanup;

3162
    if (dev_name) {
3163
        for (i = 0; i < vm->def->nconsoles; i++) {
3164 3165 3166 3167 3168 3169
            if (vm->def->consoles[i]->info.alias &&
                STREQ(vm->def->consoles[i]->info.alias, dev_name)) {
                chr = vm->def->consoles[i];
                break;
            }
        }
3170
    } else {
3171 3172
        if (vm->def->nconsoles)
            chr = vm->def->consoles[0];
3173 3174 3175 3176 3177
        else if (vm->def->nserials)
            chr = vm->def->serials[0];
    }

    if (!chr) {
3178 3179 3180
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot find console device '%s'"),
                       dev_name ? dev_name : _("default"));
3181 3182 3183
        goto cleanup;
    }

3184
    if (chr->source->type != VIR_DOMAIN_CHR_TYPE_PTY) {
3185
        virReportError(VIR_ERR_INTERNAL_ERROR,
3186 3187
                       _("character device %s is not using a PTY"),
                       dev_name ? dev_name : NULLSTR(chr->info.alias));
3188 3189 3190
        goto cleanup;
    }

3191
    if (virFDStreamOpenFile(st, chr->source->data.file.path,
E
Eric Blake 已提交
3192
                            0, 0, O_RDWR) < 0)
3193 3194 3195
        goto cleanup;

    ret = 0;
3196
 cleanup:
3197
    virDomainObjEndAPI(&vm);
3198 3199 3200
    return ret;
}

3201 3202 3203 3204 3205 3206 3207

static int
lxcDomainSendProcessSignal(virDomainPtr dom,
                           long long pid_value,
                           unsigned int signum,
                           unsigned int flags)
{
3208
    virLXCDriverPtr driver = dom->conn->privateData;
3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222
    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 已提交
3223
    if (!(vm = lxcDomObjFromDomain(dom)))
3224
        goto cleanup;
M
Michal Privoznik 已提交
3225

3226 3227
    priv = vm->privateData;

3228 3229 3230
    if (virDomainSendProcessSignalEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3231 3232 3233
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

3234
    if (virDomainObjCheckActive(vm) < 0)
3235
        goto endjob;
3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246

    /*
     * 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"));
3247
        goto endjob;
3248 3249 3250 3251 3252
    }

    if (!priv->initpid) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Init pid is not yet available"));
3253
        goto endjob;
3254 3255 3256 3257 3258 3259 3260 3261 3262 3263
    }
    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);
3264
        goto endjob;
3265 3266 3267 3268
    }

    ret = 0;

3269
 endjob:
3270
    virLXCDomainObjEndJob(driver, vm);
3271

3272
 cleanup:
3273
    virDomainObjEndAPI(&vm);
3274 3275 3276 3277
    return ret;
}


3278
static int
3279 3280
lxcConnectListAllDomains(virConnectPtr conn,
                         virDomainPtr **domains,
3281 3282
                  unsigned int flags)
{
3283
    virLXCDriverPtr driver = conn->privateData;
3284

O
Osier Yang 已提交
3285
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
3286

3287 3288 3289
    if (virConnectListAllDomainsEnsureACL(conn) < 0)
        return -1;

M
Michal Privoznik 已提交
3290 3291
    return virDomainObjListExport(driver->domains, conn, domains,
                                  virConnectListAllDomainsCheckACL, flags);
3292 3293
}

3294

3295 3296 3297 3298
static int
lxcDomainShutdownFlags(virDomainPtr dom,
                       unsigned int flags)
{
3299
    virLXCDriverPtr driver = dom->conn->privateData;
3300 3301 3302
    virLXCDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
    int ret = -1;
3303
    int rc = -1;
3304 3305 3306 3307

    virCheckFlags(VIR_DOMAIN_SHUTDOWN_INITCTL |
                  VIR_DOMAIN_SHUTDOWN_SIGNAL, -1);

M
Michal Privoznik 已提交
3308
    if (!(vm = lxcDomObjFromDomain(dom)))
3309 3310 3311 3312
        goto cleanup;

    priv = vm->privateData;

3313
    if (virDomainShutdownFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
3314 3315
        goto cleanup;

3316 3317 3318
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

3319
    if (virDomainObjCheckActive(vm) < 0)
3320
        goto endjob;
3321 3322 3323 3324

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

3328 3329
    if (flags == 0 ||
        (flags & VIR_DOMAIN_SHUTDOWN_INITCTL)) {
3330 3331
        int command = VIR_INITCTL_RUNLEVEL_POWEROFF;

3332 3333 3334 3335 3336 3337 3338
        if ((rc = virLXCDomainSetRunlevel(vm, command)) < 0) {
            if (flags != 0 &&
                (flags & VIR_DOMAIN_SHUTDOWN_INITCTL)) {
                virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                               _("Container does not provide an initctl pipe"));
                goto endjob;
            }
3339 3340
        }
    }
3341

3342
    if (rc < 0 &&
3343 3344
        (flags == 0 ||
         (flags & VIR_DOMAIN_SHUTDOWN_SIGNAL))) {
3345 3346
        if (kill(priv->initpid, SIGTERM) < 0 &&
            errno != ESRCH) {
3347 3348
            virReportSystemError(errno,
                                 _("Unable to send SIGTERM to init pid %llu"),
3349
                                 (long long)priv->initpid);
3350
            goto endjob;
3351 3352 3353 3354 3355
        }
    }

    ret = 0;

3356
 endjob:
3357
    virLXCDomainObjEndJob(driver, vm);
3358

3359
 cleanup:
3360
    virDomainObjEndAPI(&vm);
3361 3362 3363 3364 3365 3366 3367 3368 3369
    return ret;
}

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

3370

3371 3372 3373 3374
static int
lxcDomainReboot(virDomainPtr dom,
                unsigned int flags)
{
3375
    virLXCDriverPtr driver = dom->conn->privateData;
3376 3377 3378
    virLXCDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
    int ret = -1;
3379
    int rc = -1;
3380 3381 3382 3383

    virCheckFlags(VIR_DOMAIN_REBOOT_INITCTL |
                  VIR_DOMAIN_REBOOT_SIGNAL, -1);

M
Michal Privoznik 已提交
3384
    if (!(vm = lxcDomObjFromDomain(dom)))
3385 3386 3387 3388
        goto cleanup;

    priv = vm->privateData;

3389
    if (virDomainRebootEnsureACL(dom->conn, vm->def, flags) < 0)
3390 3391
        goto cleanup;

3392 3393 3394
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

3395
    if (virDomainObjCheckActive(vm) < 0)
3396
        goto endjob;
3397 3398 3399 3400

    if (priv->initpid == 0) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Init process ID is not yet known"));
3401
        goto endjob;
3402 3403 3404 3405
    }

    if (flags == 0 ||
        (flags & VIR_DOMAIN_REBOOT_INITCTL)) {
3406 3407
        int command = VIR_INITCTL_RUNLEVEL_REBOOT;

3408 3409 3410 3411 3412 3413 3414
        if ((rc = virLXCDomainSetRunlevel(vm, command)) < 0) {
            if (flags != 0 &&
                (flags & VIR_DOMAIN_REBOOT_INITCTL)) {
                virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                               _("Container does not provide an initctl pipe"));
                goto endjob;
            }
3415 3416 3417
        }
    }

3418
    if (rc < 0 &&
3419 3420 3421 3422 3423 3424
        (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"),
3425
                                 (long long)priv->initpid);
3426
            goto endjob;
3427 3428 3429 3430 3431
        }
    }

    ret = 0;

3432
 endjob:
3433
    virLXCDomainObjEndJob(driver, vm);
3434

3435
 cleanup:
3436
    virDomainObjEndAPI(&vm);
3437 3438 3439 3440
    return ret;
}


3441
static int
3442
lxcDomainAttachDeviceConfig(virDomainDefPtr vmdef,
3443 3444 3445
                            virDomainDeviceDefPtr dev)
{
    int ret = -1;
3446
    virDomainDiskDefPtr disk;
3447
    virDomainNetDefPtr net;
3448
    virDomainHostdevDefPtr hostdev;
3449 3450

    switch (dev->type) {
3451 3452 3453 3454 3455 3456 3457
    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;
        }
3458
        if (virDomainDiskInsert(vmdef, disk) < 0)
3459 3460 3461 3462 3463 3464
            return -1;
        /* vmdef has the pointer. Generic codes for vmdef will do all jobs */
        dev->data.disk = NULL;
        ret = 0;
        break;

3465 3466
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
3467
        if (virDomainNetInsert(vmdef, net) < 0)
3468
            return -1;
3469 3470 3471 3472
        dev->data.net = NULL;
        ret = 0;
        break;

3473 3474 3475 3476 3477 3478 3479
    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;
        }
3480
        if (virDomainHostdevInsert(vmdef, hostdev) < 0)
3481 3482 3483 3484 3485
            return -1;
        dev->data.hostdev = NULL;
        ret = 0;
        break;

3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496
    default:
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                        _("persistent attach of device is not supported"));
         break;
    }

    return ret;
}


static int
3497
lxcDomainUpdateDeviceConfig(virDomainDefPtr vmdef,
3498 3499 3500
                            virDomainDeviceDefPtr dev)
{
    int ret = -1;
3501
    virDomainNetDefPtr net;
3502
    virDomainDeviceDef oldDev = { .type = dev->type };
3503
    int idx;
3504 3505

    switch (dev->type) {
3506 3507
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
3508
        if ((idx = virDomainNetFindIdx(vmdef, net)) < 0)
3509
            return -1;
3510

3511
        oldDev.data.net = vmdef->nets[idx];
3512
        if (virDomainDefCompatibleDevice(vmdef, dev, &oldDev,
3513 3514
                                         VIR_DOMAIN_DEVICE_ACTION_UPDATE,
                                         false) < 0)
3515
            return -1;
3516

3517 3518 3519 3520
        if (virDomainNetUpdate(vmdef, idx, net) < 0)
            return -1;

        virDomainNetDefFree(oldDev.data.net);
3521 3522 3523 3524 3525
        dev->data.net = NULL;
        ret = 0;

        break;

3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("persistent update of device is not supported"));
        break;
    }

    return ret;
}


static int
3537
lxcDomainDetachDeviceConfig(virDomainDefPtr vmdef,
3538 3539 3540
                            virDomainDeviceDefPtr dev)
{
    int ret = -1;
3541
    virDomainDiskDefPtr disk, det_disk;
3542
    virDomainNetDefPtr net;
3543
    virDomainHostdevDefPtr hostdev, det_hostdev;
3544
    int idx;
3545 3546

    switch (dev->type) {
3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557
    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;

3558 3559
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
3560
        if ((idx = virDomainNetFindIdx(vmdef, net)) < 0)
3561
            return -1;
3562

3563 3564 3565 3566 3567
        /* this is guaranteed to succeed */
        virDomainNetDefFree(virDomainNetRemove(vmdef, idx));
        ret = 0;
        break;

3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580
    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;
    }

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

    return ret;
}


3591 3592 3593 3594 3595 3596 3597 3598 3599 3600
struct lxcDomainAttachDeviceMknodData {
    virLXCDriverPtr driver;
    mode_t mode;
    dev_t dev;
    virDomainObjPtr vm;
    virDomainDeviceDefPtr def;
    char *file;
};

static int
J
Ján Tomko 已提交
3601
lxcDomainAttachDeviceMknodHelper(pid_t pid G_GNUC_UNUSED,
3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638
                                 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;
3639 3640
        char *tmpsrc = def->src->path;
        def->src->path = data->file;
3641 3642 3643
        if (virSecurityManagerSetImageLabel(data->driver->securityManager,
                                            data->vm->def, def->src,
                                            VIR_SECURITY_DOMAIN_IMAGE_LABEL_BACKING_CHAIN) < 0) {
3644
            def->src->path = tmpsrc;
3645 3646
            goto cleanup;
        }
3647
        def->src->path = tmpsrc;
3648 3649
    }   break;

3650 3651 3652 3653 3654 3655 3656
    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;

3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707
    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;
}


3708
static int
J
Ján Tomko 已提交
3709
lxcDomainAttachDeviceUnlinkHelper(pid_t pid G_GNUC_UNUSED,
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
                                  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;
}


3741 3742 3743 3744 3745 3746 3747 3748 3749
static int
lxcDomainAttachDeviceDiskLive(virLXCDriverPtr driver,
                              virDomainObjPtr vm,
                              virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainDiskDefPtr def = dev->data.disk;
    int ret = -1;
    struct stat sb;
3750 3751
    char *file = NULL;
    int perms;
3752
    const char *src = NULL;
3753 3754 3755 3756 3757 3758 3759

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

3760 3761 3762 3763 3764 3765
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        goto cleanup;
    }

3766 3767
    src = virDomainDiskGetSource(def);
    if (src == NULL) {
3768 3769 3770 3771 3772
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Can't setup disk without media"));
        goto cleanup;
    }

3773 3774 3775 3776 3777 3778
    if (!virStorageSourceIsBlockLocal(def->src)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Can't setup disk for non-block device"));
        goto cleanup;
    }

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

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

3791
    if (!S_ISBLK(sb.st_mode)) {
3792
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3793
                       _("Disk source %s must be a block device"),
3794
                       src);
3795 3796 3797
        goto cleanup;
    }

3798
    perms = (def->src->readonly ?
3799 3800 3801
             VIR_CGROUP_DEVICE_READ :
             VIR_CGROUP_DEVICE_RW) |
        VIR_CGROUP_DEVICE_MKNOD;
3802

3803 3804 3805 3806 3807
    if (virCgroupAllowDevice(priv->cgroup,
                             'b',
                             major(sb.st_rdev),
                             minor(sb.st_rdev),
                             perms) < 0)
3808
        goto cleanup;
3809

3810
    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks + 1) < 0)
3811 3812
        goto cleanup;

3813
    file = g_strdup_printf("/dev/%s", def->dst);
3814

3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825
    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)
3826 3827
            VIR_WARN("cannot deny device %s for domain %s: %s",
                     src, vm->def->name, virGetLastErrorMessage());
3828 3829 3830 3831 3832 3833 3834
        goto cleanup;
    }

    virDomainDiskInsertPreAlloced(vm->def, def);

    ret = 0;

3835
 cleanup:
3836
    if (src)
3837
        virDomainAuditDisk(vm, NULL, def->src, "attach", ret == 0);
3838
    VIR_FREE(file);
3839 3840 3841 3842
    return ret;
}


3843
static int
3844
lxcDomainAttachDeviceNetLive(virLXCDriverPtr driver,
3845 3846 3847 3848 3849
                             virDomainObjPtr vm,
                             virDomainNetDefPtr net)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    int ret = -1;
3850
    virDomainNetType actualType;
3851
    const virNetDevBandwidth *actualBandwidth;
3852 3853 3854 3855 3856
    char *veth = NULL;

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

3860 3861 3862
    if (virLXCProcessValidateInterface(net) < 0)
       return -1;

3863
    /* preallocate new slot for device */
3864
    if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets+1) < 0)
3865 3866 3867 3868 3869 3870
        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.
     */
3871 3872 3873 3874 3875 3876 3877 3878 3879 3880
    if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
        virConnectPtr netconn = virGetConnectNetwork();
        if (!netconn)
            return -1;
        if (virDomainNetAllocateActualDevice(netconn, vm->def, net) < 0) {
            virObjectUnref(netconn);
            return -1;
        }
        virObjectUnref(netconn);
    }
3881

3882 3883 3884 3885
    /* final validation now that actual type is known */
    if (virDomainActualNetDefValidate(net) < 0)
        return -1;

3886 3887 3888
    actualType = virDomainNetGetActualType(net);

    switch (actualType) {
3889 3890
    case VIR_DOMAIN_NET_TYPE_BRIDGE:
    case VIR_DOMAIN_NET_TYPE_NETWORK: {
3891 3892 3893 3894 3895 3896
        const char *brname = virDomainNetGetActualBridgeName(net);
        if (!brname) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No bridge name specified"));
            goto cleanup;
        }
3897
        if (!(veth = virLXCProcessSetupInterfaceTap(vm->def, net, brname)))
3898 3899
            goto cleanup;
    }   break;
3900 3901 3902 3903
    case VIR_DOMAIN_NET_TYPE_ETHERNET:
        if (!(veth = virLXCProcessSetupInterfaceTap(vm->def, net, NULL)))
            goto cleanup;
        break;
3904
    case VIR_DOMAIN_NET_TYPE_DIRECT: {
3905
        if (!(veth = virLXCProcessSetupInterfaceDirect(driver, vm->def, net)))
3906 3907
            goto cleanup;
    }   break;
3908 3909 3910 3911 3912 3913 3914 3915
    case VIR_DOMAIN_NET_TYPE_USER:
    case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
    case VIR_DOMAIN_NET_TYPE_SERVER:
    case VIR_DOMAIN_NET_TYPE_CLIENT:
    case VIR_DOMAIN_NET_TYPE_MCAST:
    case VIR_DOMAIN_NET_TYPE_INTERNAL:
    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
    case VIR_DOMAIN_NET_TYPE_UDP:
3916 3917 3918
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Network device type is not supported"));
        goto cleanup;
3919 3920 3921 3922
    case VIR_DOMAIN_NET_TYPE_LAST:
    default:
        virReportEnumRangeError(virDomainNetType, actualType);
        goto cleanup;
3923
    }
3924 3925 3926 3927
    /* Set bandwidth or warn if requested and not supported. */
    actualBandwidth = virDomainNetGetActualBandwidth(net);
    if (actualBandwidth) {
        if (virNetDevSupportBandwidth(actualType)) {
3928 3929
            if (virNetDevBandwidthSet(net->ifname, actualBandwidth, false,
                                      !virDomainNetTypeSharesHostView(net)) < 0)
3930 3931 3932
                goto cleanup;
        } else {
            VIR_WARN("setting bandwidth on interfaces of "
3933 3934
                     "type '%s' is not implemented yet: %s",
                     virDomainNetTypeToString(actualType), virGetLastErrorMessage());
3935 3936
        }
    }
3937 3938 3939 3940 3941 3942 3943 3944 3945 3946

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

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

    ret = 0;

3947
 cleanup:
3948 3949 3950 3951 3952
    if (!ret) {
        vm->def->nets[vm->def->nnets++] = net;
    } else if (veth) {
        switch (actualType) {
        case VIR_DOMAIN_NET_TYPE_BRIDGE:
3953
        case VIR_DOMAIN_NET_TYPE_NETWORK:
3954
        case VIR_DOMAIN_NET_TYPE_ETHERNET:
3955 3956 3957 3958 3959 3960
            ignore_value(virNetDevVethDelete(veth));
            break;

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

3962 3963 3964 3965 3966 3967 3968 3969 3970
        case VIR_DOMAIN_NET_TYPE_USER:
        case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
        case VIR_DOMAIN_NET_TYPE_SERVER:
        case VIR_DOMAIN_NET_TYPE_CLIENT:
        case VIR_DOMAIN_NET_TYPE_MCAST:
        case VIR_DOMAIN_NET_TYPE_INTERNAL:
        case VIR_DOMAIN_NET_TYPE_HOSTDEV:
        case VIR_DOMAIN_NET_TYPE_UDP:
        case VIR_DOMAIN_NET_TYPE_LAST:
3971 3972 3973
        default:
            /* no-op */
            break;
3974 3975 3976 3977 3978 3979 3980
        }
    }

    return ret;
}


3981 3982 3983 3984 3985 3986 3987 3988 3989 3990
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;
3991
    virUSBDevicePtr usb = NULL;
3992
    virDomainHostdevSubsysUSBPtr usbsrc;
3993 3994 3995 3996 3997 3998 3999

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

4000
    usbsrc = &def->source.subsys.u.usb;
4001
    src = g_strdup_printf("/dev/bus/usb/%03d/%03d", usbsrc->bus, usbsrc->device);
4002

4003
    if (!(usb = virUSBDeviceNew(usbsrc->bus, usbsrc->device, NULL)))
4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018
        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;
    }

4019 4020 4021
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0)
        goto cleanup;

4022
    if (virUSBDeviceFileIterate(usb,
4023
                                virLXCSetupHostUSBDeviceCgroup,
4024
                                priv->cgroup) < 0)
4025 4026
        goto cleanup;

4027 4028 4029 4030 4031 4032 4033
    if (lxcDomainAttachDeviceMknod(driver,
                                   0700 | S_IFCHR,
                                   sb.st_rdev,
                                   vm,
                                   dev,
                                   src) < 0) {
        if (virUSBDeviceFileIterate(usb,
4034
                                    virLXCTeardownHostUSBDeviceCgroup,
4035
                                    priv->cgroup) < 0)
4036 4037
            VIR_WARN("cannot deny device %s for domain %s: %s",
                     src, vm->def->name, virGetLastErrorMessage());
4038 4039 4040
        goto cleanup;
    }

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

4043 4044
    ret = 0;

4045
 cleanup:
4046
    virDomainAuditHostdev(vm, def, "attach", ret == 0);
4047
    virUSBDeviceFree(usb);
4048 4049 4050 4051 4052
    VIR_FREE(src);
    return ret;
}


4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088
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;
    }

4089
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0)
4090 4091
        goto cleanup;

4092 4093 4094 4095 4096
    if (virCgroupAllowDevice(priv->cgroup,
                             'b',
                             major(sb.st_rdev),
                             minor(sb.st_rdev),
                             VIR_CGROUP_DEVICE_RWM) < 0)
4097 4098
        goto cleanup;

4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109
    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)
4110 4111
            VIR_WARN("cannot deny device %s for domain %s: %s",
                     def->source.caps.u.storage.block, vm->def->name, virGetLastErrorMessage());
4112 4113 4114 4115 4116 4117 4118
        goto cleanup;
    }

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

    ret = 0;

4119
 cleanup:
4120 4121 4122 4123 4124
    virDomainAuditHostdev(vm, def, "attach", ret == 0);
    return ret;
}


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

4161 4162 4163 4164 4165
    if (virCgroupAllowDevice(priv->cgroup,
                             'c',
                             major(sb.st_rdev),
                             minor(sb.st_rdev),
                             VIR_CGROUP_DEVICE_RWM) < 0)
4166 4167
        goto cleanup;

4168
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0)
4169 4170
        goto cleanup;

4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181
    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)
4182 4183
            VIR_WARN("cannot deny device %s for domain %s: %s",
                     def->source.caps.u.storage.block, vm->def->name, virGetLastErrorMessage());
4184 4185 4186 4187 4188 4189 4190
        goto cleanup;
    }

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

    ret = 0;

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


4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214
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;
    }
}


4215 4216 4217 4218 4219 4220 4221 4222 4223
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);

4224 4225 4226
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC:
        return lxcDomainAttachDeviceHostdevMiscLive(driver, vm, dev);

4227 4228 4229 4230 4231 4232 4233 4234 4235
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported host device type %s"),
                       virDomainHostdevCapsTypeToString(dev->data.hostdev->source.caps.type));
        return -1;
    }
}


4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248
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;
    }

4249 4250 4251 4252 4253 4254
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        return -1;
    }

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

4259 4260 4261
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
        return lxcDomainAttachDeviceHostdevCapsLive(driver, vm, dev);

4262 4263 4264 4265 4266 4267 4268 4269 4270
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported host device mode %s"),
                       virDomainHostdevModeTypeToString(dev->data.hostdev->mode));
        return -1;
    }
}


4271
static int
4272
lxcDomainAttachDeviceLive(virLXCDriverPtr driver,
4273
                          virDomainObjPtr vm,
4274 4275 4276 4277 4278
                          virDomainDeviceDefPtr dev)
{
    int ret = -1;

    switch (dev->type) {
4279 4280 4281 4282 4283 4284
    case VIR_DOMAIN_DEVICE_DISK:
        ret = lxcDomainAttachDeviceDiskLive(driver, vm, dev);
        if (!ret)
            dev->data.disk = NULL;
        break;

4285
    case VIR_DOMAIN_DEVICE_NET:
4286
        ret = lxcDomainAttachDeviceNetLive(driver, vm,
4287 4288 4289 4290 4291
                                           dev->data.net);
        if (!ret)
            dev->data.net = NULL;
        break;

4292 4293 4294
    case VIR_DOMAIN_DEVICE_HOSTDEV:
        ret = lxcDomainAttachDeviceHostdevLive(driver, vm, dev);
        if (!ret)
C
Chen Hanxiao 已提交
4295
            dev->data.hostdev = NULL;
4296 4297
        break;

4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("device type '%s' cannot be attached"),
                       virDomainDeviceTypeToString(dev->type));
        break;
    }

    return ret;
}


4309
static int
4310
lxcDomainDetachDeviceDiskLive(virDomainObjPtr vm,
4311 4312 4313 4314
                              virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainDiskDefPtr def = NULL;
4315
    int idx, ret = -1;
J
John Ferlan 已提交
4316
    char *dst = NULL;
4317
    const char *src;
4318 4319 4320 4321 4322 4323 4324

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

4325 4326 4327
    if ((idx = virDomainDiskIndexByName(vm->def,
                                        dev->data.disk->dst,
                                        false)) < 0) {
4328 4329 4330 4331 4332
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("disk %s not found"), dev->data.disk->dst);
        goto cleanup;
    }

4333
    def = vm->def->disks[idx];
4334
    src = virDomainDiskGetSource(def);
4335

4336
    dst = g_strdup_printf("/dev/%s", def->dst);
4337

4338
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
4339 4340 4341 4342 4343
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        goto cleanup;
    }

4344
    if (lxcDomainAttachDeviceUnlink(vm, dst) < 0) {
4345
        virDomainAuditDisk(vm, def->src, NULL, "detach", false);
4346 4347
        goto cleanup;
    }
4348
    virDomainAuditDisk(vm, def->src, NULL, "detach", true);
4349

4350 4351
    if (virCgroupDenyDevicePath(priv->cgroup, src,
                                VIR_CGROUP_DEVICE_RWM, false) != 0)
4352 4353
        VIR_WARN("cannot deny device %s for domain %s: %s",
                 src, vm->def->name, virGetLastErrorMessage());
4354

4355
    virDomainDiskRemove(vm->def, idx);
4356 4357 4358 4359
    virDomainDiskDefFree(def);

    ret = 0;

4360
 cleanup:
4361 4362 4363 4364 4365
    VIR_FREE(dst);
    return ret;
}


4366
static int
4367 4368 4369
lxcDomainDetachDeviceNetLive(virDomainObjPtr vm,
                             virDomainDeviceDefPtr dev)
{
4370 4371
    int detachidx, ret = -1;
    virDomainNetType actualType;
4372
    virDomainNetDefPtr detach = NULL;
4373
    const virNetDevVPortProfile *vport = NULL;
4374
    virErrorPtr save_err = NULL;
4375

4376
    if ((detachidx = virDomainNetFindIdx(vm->def, dev->data.net)) < 0)
4377
        goto cleanup;
4378

4379
    detach = vm->def->nets[detachidx];
4380 4381 4382
    actualType = virDomainNetGetActualType(detach);

    /* clear network bandwidth */
4383 4384
    if (virDomainNetGetActualBandwidth(detach) &&
        virNetDevSupportBandwidth(actualType) &&
4385 4386
        virNetDevBandwidthClear(detach->ifname))
        goto cleanup;
4387

4388
    switch (actualType) {
4389
    case VIR_DOMAIN_NET_TYPE_BRIDGE:
4390
    case VIR_DOMAIN_NET_TYPE_NETWORK:
4391
    case VIR_DOMAIN_NET_TYPE_ETHERNET:
4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402
        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
4403
         */
4404
    case VIR_DOMAIN_NET_TYPE_DIRECT:
4405 4406 4407 4408 4409 4410 4411 4412
    case VIR_DOMAIN_NET_TYPE_USER:
    case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
    case VIR_DOMAIN_NET_TYPE_SERVER:
    case VIR_DOMAIN_NET_TYPE_CLIENT:
    case VIR_DOMAIN_NET_TYPE_MCAST:
    case VIR_DOMAIN_NET_TYPE_INTERNAL:
    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
    case VIR_DOMAIN_NET_TYPE_UDP:
4413 4414 4415
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Only bridged veth devices can be detached"));
        goto cleanup;
4416 4417 4418 4419
    case VIR_DOMAIN_NET_TYPE_LAST:
    default:
        virReportEnumRangeError(virDomainNetType, actualType);
        goto cleanup;
4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431
    }

    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;
4432
 cleanup:
4433
    if (!ret) {
4434
        virErrorPreserveLast(&save_err);
4435 4436 4437 4438 4439 4440 4441 4442 4443
        if (detach->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
            virConnectPtr conn = virGetConnectNetwork();
            if (conn) {
                virDomainNetReleaseActualDevice(conn, vm->def, detach);
                virObjectUnref(conn);
            } else {
                VIR_WARN("Unable to release network device '%s'", NULLSTR(detach->ifname));
            }
        }
4444 4445
        virDomainNetRemove(vm->def, detachidx);
        virDomainNetDefFree(detach);
4446
        virErrorRestore(&save_err);
4447 4448 4449 4450 4451
    }
    return ret;
}


4452 4453 4454 4455 4456 4457 4458 4459
static int
lxcDomainDetachDeviceHostdevUSBLive(virLXCDriverPtr driver,
                                    virDomainObjPtr vm,
                                    virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainHostdevDefPtr def = NULL;
    int idx, ret = -1;
J
John Ferlan 已提交
4460
    char *dst = NULL;
4461
    virUSBDevicePtr usb = NULL;
4462
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
4463
    virDomainHostdevSubsysUSBPtr usbsrc;
4464 4465 4466 4467 4468 4469 4470 4471 4472

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

4473
    usbsrc = &def->source.subsys.u.usb;
4474
    dst = g_strdup_printf("/dev/bus/usb/%03d/%03d", usbsrc->bus, usbsrc->device);
4475

4476
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
4477 4478 4479 4480 4481
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        goto cleanup;
    }

4482
    if (!(usb = virUSBDeviceNew(usbsrc->bus, usbsrc->device, NULL)))
4483 4484
        goto cleanup;

4485
    if (lxcDomainAttachDeviceUnlink(vm, dst) < 0) {
4486 4487 4488 4489 4490
        virDomainAuditHostdev(vm, def, "detach", false);
        goto cleanup;
    }
    virDomainAuditHostdev(vm, def, "detach", true);

4491
    if (virUSBDeviceFileIterate(usb,
4492
                                virLXCTeardownHostUSBDeviceCgroup,
4493
                                priv->cgroup) < 0)
4494 4495
        VIR_WARN("cannot deny device %s for domain %s: %s",
                 dst, vm->def->name, virGetLastErrorMessage());
4496

4497 4498 4499
    virObjectLock(hostdev_mgr->activeUSBHostdevs);
    virUSBDeviceListDel(hostdev_mgr->activeUSBHostdevs, usb);
    virObjectUnlock(hostdev_mgr->activeUSBHostdevs);
4500 4501 4502 4503 4504 4505

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

    ret = 0;

4506
 cleanup:
4507
    virUSBDeviceFree(usb);
4508 4509 4510 4511
    VIR_FREE(dst);
    return ret;
}

4512 4513

static int
4514
lxcDomainDetachDeviceHostdevStorageLive(virDomainObjPtr vm,
4515 4516 4517 4518
                                        virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainHostdevDefPtr def = NULL;
4519
    int idx;
4520 4521 4522 4523

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

4527 4528 4529
    if ((idx = virDomainHostdevFind(vm->def,
                                    dev->data.hostdev,
                                    &def)) < 0) {
4530 4531 4532
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("hostdev %s not found"),
                       dev->data.hostdev->source.caps.u.storage.block);
4533
        return -1;
4534 4535
    }

4536
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
4537 4538
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
4539
        return -1;
4540 4541
    }

4542
    if (lxcDomainAttachDeviceUnlink(vm, def->source.caps.u.storage.block) < 0) {
4543
        virDomainAuditHostdev(vm, def, "detach", false);
4544
        return -1;
4545 4546 4547
    }
    virDomainAuditHostdev(vm, def, "detach", true);

4548 4549
    if (virCgroupDenyDevicePath(priv->cgroup, def->source.caps.u.storage.block,
                                VIR_CGROUP_DEVICE_RWM, false) != 0)
4550 4551
        VIR_WARN("cannot deny device %s for domain %s: %s",
                 def->source.caps.u.storage.block, vm->def->name, virGetLastErrorMessage());
4552

4553
    virDomainHostdevRemove(vm->def, idx);
4554 4555
    virDomainHostdevDefFree(def);

4556
    return 0;
4557 4558 4559
}


4560
static int
4561
lxcDomainDetachDeviceHostdevMiscLive(virDomainObjPtr vm,
4562 4563 4564 4565
                                     virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainHostdevDefPtr def = NULL;
4566
    int idx;
4567 4568 4569 4570

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

4574 4575 4576
    if ((idx = virDomainHostdevFind(vm->def,
                                    dev->data.hostdev,
                                    &def)) < 0) {
4577 4578 4579
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("hostdev %s not found"),
                       dev->data.hostdev->source.caps.u.misc.chardev);
4580
        return -1;
4581 4582
    }

4583
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
4584 4585
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
4586
        return -1;
4587 4588
    }

4589
    if (lxcDomainAttachDeviceUnlink(vm, def->source.caps.u.misc.chardev) < 0) {
4590
        virDomainAuditHostdev(vm, def, "detach", false);
4591
        return -1;
4592 4593 4594
    }
    virDomainAuditHostdev(vm, def, "detach", true);

4595 4596
    if (virCgroupDenyDevicePath(priv->cgroup, def->source.caps.u.misc.chardev,
                                VIR_CGROUP_DEVICE_RWM, false) != 0)
4597 4598
        VIR_WARN("cannot deny device %s for domain %s: %s",
                 def->source.caps.u.misc.chardev, vm->def->name, virGetLastErrorMessage());
4599

4600
    virDomainHostdevRemove(vm->def, idx);
4601 4602
    virDomainHostdevDefFree(def);

4603
    return 0;
4604 4605 4606
}


4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624
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;
    }
}


4625
static int
4626 4627
lxcDomainDetachDeviceHostdevCapsLive(virDomainObjPtr vm,
                                     virDomainDeviceDefPtr dev)
4628 4629 4630
{
    switch (dev->data.hostdev->source.caps.type) {
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
4631
        return lxcDomainDetachDeviceHostdevStorageLive(vm, dev);
4632

4633
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC:
4634
        return lxcDomainDetachDeviceHostdevMiscLive(vm, dev);
4635

4636 4637 4638 4639 4640 4641 4642 4643 4644
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported host device type %s"),
                       virDomainHostdevCapsTypeToString(dev->data.hostdev->source.caps.type));
        return -1;
    }
}


4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661
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);

4662
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
4663
        return lxcDomainDetachDeviceHostdevCapsLive(vm, dev);
4664

4665 4666 4667 4668 4669 4670 4671 4672 4673
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported host device mode %s"),
                       virDomainHostdevModeTypeToString(dev->data.hostdev->mode));
        return -1;
    }
}


4674 4675 4676
static int
lxcDomainDetachDeviceLive(virLXCDriverPtr driver,
                          virDomainObjPtr vm,
4677 4678 4679 4680 4681
                          virDomainDeviceDefPtr dev)
{
    int ret = -1;

    switch (dev->type) {
4682
    case VIR_DOMAIN_DEVICE_DISK:
4683
        ret = lxcDomainDetachDeviceDiskLive(vm, dev);
4684 4685
        break;

4686 4687 4688 4689
    case VIR_DOMAIN_DEVICE_NET:
        ret = lxcDomainDetachDeviceNetLive(vm, dev);
        break;

4690 4691 4692 4693
    case VIR_DOMAIN_DEVICE_HOSTDEV:
        ret = lxcDomainDetachDeviceHostdevLive(driver, vm, dev);
        break;

4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("device type '%s' cannot be detached"),
                       virDomainDeviceTypeToString(dev->type));
        break;
    }

    return ret;
}


4705 4706 4707
static int lxcDomainAttachDeviceFlags(virDomainPtr dom,
                                      const char *xml,
                                      unsigned int flags)
4708 4709 4710 4711 4712 4713
{
    virLXCDriverPtr driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr vmdef = NULL;
    virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
    int ret = -1;
4714
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
4715 4716

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
4717
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
4718

M
Michal Privoznik 已提交
4719
    if (!(vm = lxcDomObjFromDomain(dom)))
4720 4721
        goto cleanup;

4722 4723 4724
    if (virDomainAttachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4725
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
4726 4727
        goto cleanup;

4728
    if (virDomainObjUpdateModificationImpact(vm, &flags) < 0)
4729
        goto endjob;
4730

4731
    dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
4732
                                             driver->xmlopt, NULL,
4733
                                             VIR_DOMAIN_DEF_PARSE_INACTIVE);
4734
    if (dev == NULL)
4735
        goto endjob;
4736 4737 4738 4739 4740 4741 4742

    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.
         */
4743
        dev_copy = virDomainDeviceDefCopy(dev, vm->def,
4744
                                          driver->xmlopt, NULL);
4745
        if (!dev_copy)
4746
            goto endjob;
4747 4748 4749 4750
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        /* Make a copy for updated domain. */
4751
        vmdef = virDomainObjCopyPersistentDef(vm, driver->xmlopt, NULL);
4752
        if (!vmdef)
4753
            goto endjob;
4754

4755
        if (virDomainDefCompatibleDevice(vmdef, dev, NULL,
4756 4757
                                         VIR_DOMAIN_DEVICE_ACTION_ATTACH,
                                         false) < 0)
4758
            goto endjob;
4759

4760
        if ((ret = lxcDomainAttachDeviceConfig(vmdef, dev)) < 0)
4761
            goto endjob;
4762 4763 4764
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
4765
        if (virDomainDefCompatibleDevice(vm->def, dev_copy, NULL,
4766 4767
                                         VIR_DOMAIN_DEVICE_ACTION_ATTACH,
                                         true) < 0)
4768
            goto endjob;
4769

4770
        if ((ret = lxcDomainAttachDeviceLive(driver, vm, dev_copy)) < 0)
4771
            goto endjob;
4772 4773 4774 4775 4776
        /*
         * 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.
         */
4777
        if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0) {
4778
            ret = -1;
4779
            goto endjob;
4780 4781 4782 4783 4784
        }
    }

    /* Finally, if no error until here, we can save config. */
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
4785
        ret = virDomainDefSave(vmdef, driver->xmlopt, cfg->configDir);
4786
        if (!ret) {
4787
            virDomainObjAssignDef(vm, vmdef, false, NULL);
4788 4789 4790 4791
            vmdef = NULL;
        }
    }

4792
 endjob:
4793 4794
    virLXCDomainObjEndJob(driver, vm);

4795
 cleanup:
4796 4797 4798 4799
    virDomainDefFree(vmdef);
    if (dev != dev_copy)
        virDomainDeviceDefFree(dev_copy);
    virDomainDeviceDefFree(dev);
4800
    virDomainObjEndAPI(&vm);
4801
    virObjectUnref(cfg);
4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817
    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)
{
4818 4819 4820
    virLXCDriverPtr driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr vmdef = NULL;
4821
    virDomainDeviceDefPtr dev = NULL;
4822
    int ret = -1;
4823
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
4824 4825

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
4826
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
4827

M
Michal Privoznik 已提交
4828
    if (!(vm = lxcDomObjFromDomain(dom)))
4829 4830
        goto cleanup;

4831 4832 4833
    if (virDomainUpdateDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4834
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
4835
        goto cleanup;
4836

4837 4838 4839
    if (virDomainObjUpdateModificationImpact(vm, &flags) < 0)
        goto endjob;

4840 4841 4842
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("Unable to modify live devices"));
4843
        goto endjob;
4844
    }
4845

4846
    if (!(dev = virDomainDeviceDefParse(xml, vm->def, driver->xmlopt, NULL,
4847 4848
                                        VIR_DOMAIN_DEF_PARSE_INACTIVE)))
        goto endjob;
4849

4850
    /* Make a copy for updated domain. */
4851
    if (!(vmdef = virDomainObjCopyPersistentDef(vm, driver->xmlopt, NULL)))
4852
        goto endjob;
4853

4854 4855 4856 4857
    /* virDomainDefCompatibleDevice call is delayed until we know the
     * device we're going to update. */
    if (lxcDomainUpdateDeviceConfig(vmdef, dev) < 0)
        goto endjob;
4858

4859
    if (virDomainDefSave(vmdef, driver->xmlopt, cfg->configDir) < 0)
4860
        goto endjob;
4861

4862 4863 4864 4865
    virDomainObjAssignDef(vm, vmdef, false, NULL);
    vmdef = NULL;
    ret = 0;

4866
 endjob:
4867 4868
    virLXCDomainObjEndJob(driver, vm);

4869
 cleanup:
4870 4871
    virDomainDefFree(vmdef);
    virDomainDeviceDefFree(dev);
4872
    virDomainObjEndAPI(&vm);
4873
    virObjectUnref(cfg);
4874
    return ret;
4875 4876 4877 4878 4879 4880 4881
}


static int lxcDomainDetachDeviceFlags(virDomainPtr dom,
                                      const char *xml,
                                      unsigned int flags)
{
4882
    virLXCDriverPtr driver = dom->conn->privateData;
4883
    virCapsPtr caps = NULL;
4884 4885 4886 4887
    virDomainObjPtr vm = NULL;
    virDomainDefPtr vmdef = NULL;
    virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
    int ret = -1;
4888
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
4889 4890 4891 4892

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

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

4896 4897 4898
    if (virDomainDetachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4899
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
4900
        goto cleanup;
4901

4902 4903 4904
    if (virDomainObjUpdateModificationImpact(vm, &flags) < 0)
        goto endjob;

4905
    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
4906
        goto endjob;
4907

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

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

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

        if ((ret = lxcDomainDetachDeviceConfig(vmdef, dev)) < 0)
4934
            goto endjob;
4935 4936 4937 4938
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if ((ret = lxcDomainDetachDeviceLive(driver, vm, dev_copy)) < 0)
4939
            goto endjob;
4940 4941 4942 4943 4944
        /*
         * 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.
         */
4945
        if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0) {
4946
            ret = -1;
4947
            goto endjob;
4948 4949 4950 4951 4952
        }
    }

    /* Finally, if no error until here, we can save config. */
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
4953
        ret = virDomainDefSave(vmdef, driver->xmlopt, cfg->configDir);
4954 4955 4956 4957 4958 4959
        if (!ret) {
            virDomainObjAssignDef(vm, vmdef, false, NULL);
            vmdef = NULL;
        }
    }

4960
 endjob:
4961 4962
    virLXCDomainObjEndJob(driver, vm);

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


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


4983 4984 4985
static int lxcDomainLxcOpenNamespace(virDomainPtr dom,
                                     int **fdlist,
                                     unsigned int flags)
4986
{
4987
    virLXCDriverPtr driver = dom->conn->privateData;
4988 4989 4990 4991 4992 4993 4994 4995
    virDomainObjPtr vm;
    virLXCDomainObjPrivatePtr priv;
    int ret = -1;
    size_t nfds = 0;

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

M
Michal Privoznik 已提交
4996
    if (!(vm = lxcDomObjFromDomain(dom)))
4997
        goto cleanup;
M
Michal Privoznik 已提交
4998

4999 5000
    priv = vm->privateData;

5001 5002 5003
    if (virDomainLxcOpenNamespaceEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

5004 5005 5006
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_QUERY) < 0)
        goto cleanup;

5007
    if (virDomainObjCheckActive(vm) < 0)
5008
        goto endjob;
5009 5010 5011 5012

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

    if (virProcessGetNamespaces(priv->initpid, &nfds, fdlist) < 0)
5017
        goto endjob;
5018 5019

    ret = nfds;
5020 5021

 endjob:
5022
    virLXCDomainObjEndJob(driver, vm);
5023

5024
 cleanup:
5025
    virDomainObjEndAPI(&vm);
5026 5027 5028 5029
    return ret;
}


5030
static char *
5031
lxcConnectGetSysinfo(virConnectPtr conn, unsigned int flags)
5032 5033 5034 5035 5036 5037
{
    virLXCDriverPtr driver = conn->privateData;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    virCheckFlags(0, NULL);

5038 5039 5040
    if (virConnectGetSysinfoEnsureACL(conn) < 0)
        return NULL;

5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052
    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;
    return virBufferContentAndReset(&buf);
}


5053
static int
5054
lxcNodeGetInfo(virConnectPtr conn,
5055 5056
               virNodeInfoPtr nodeinfo)
{
5057 5058 5059
    if (virNodeGetInfoEnsureACL(conn) < 0)
        return -1;

M
Martin Kletzander 已提交
5060
    return virCapabilitiesGetNodeInfo(nodeinfo);
5061 5062 5063
}


5064 5065
static int
lxcDomainMemoryStats(virDomainPtr dom,
5066
                     virDomainMemoryStatPtr stats,
5067 5068 5069 5070 5071 5072 5073 5074
                     unsigned int nr_stats,
                     unsigned int flags)
{
    virDomainObjPtr vm;
    int ret = -1;
    virLXCDomainObjPrivatePtr priv;
    unsigned long long swap_usage;
    unsigned long mem_usage;
5075
    virLXCDriverPtr driver = dom->conn->privateData;
5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086

    virCheckFlags(0, -1);

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

    priv = vm->privateData;

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

5087 5088 5089
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_QUERY) < 0)
        goto cleanup;

5090
    if (virDomainObjCheckActive(vm) < 0)
5091
        goto endjob;
5092

5093
    if (virCgroupGetMemSwapUsage(priv->cgroup, &swap_usage) < 0)
5094
        goto endjob;
5095

5096
    if (virCgroupGetMemoryUsage(priv->cgroup, &mem_usage) < 0)
5097
        goto endjob;
5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115

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

5116
 endjob:
5117 5118
    virLXCDomainObjEndJob(driver, vm);

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


5125
static int
5126
lxcNodeGetCPUStats(virConnectPtr conn,
5127 5128 5129 5130 5131
                   int cpuNum,
                   virNodeCPUStatsPtr params,
                   int *nparams,
                   unsigned int flags)
{
5132 5133 5134
    if (virNodeGetCPUStatsEnsureACL(conn) < 0)
        return -1;

5135
    return virHostCPUGetStats(cpuNum, params, nparams, flags);
5136 5137 5138 5139
}


static int
5140
lxcNodeGetMemoryStats(virConnectPtr conn,
5141 5142 5143 5144 5145
                      int cellNum,
                      virNodeMemoryStatsPtr params,
                      int *nparams,
                      unsigned int flags)
{
5146 5147 5148
    if (virNodeGetMemoryStatsEnsureACL(conn) < 0)
        return -1;

5149
    return virHostMemGetStats(cellNum, params, nparams, flags);
5150 5151 5152 5153
}


static int
5154
lxcNodeGetCellsFreeMemory(virConnectPtr conn,
5155 5156 5157 5158
                          unsigned long long *freeMems,
                          int startCell,
                          int maxCells)
{
5159 5160 5161
    if (virNodeGetCellsFreeMemoryEnsureACL(conn) < 0)
        return -1;

5162
    return virHostMemGetCellsFree(freeMems, startCell, maxCells);
5163 5164 5165 5166
}


static unsigned long long
5167
lxcNodeGetFreeMemory(virConnectPtr conn)
5168
{
5169 5170
    unsigned long long freeMem;

5171 5172 5173
    if (virNodeGetFreeMemoryEnsureACL(conn) < 0)
        return 0;

5174
    if (virHostMemGetInfo(NULL, &freeMem) < 0)
5175 5176 5177
        return 0;

    return freeMem;
5178 5179 5180 5181
}


static int
5182
lxcNodeGetMemoryParameters(virConnectPtr conn,
5183 5184 5185 5186
                           virTypedParameterPtr params,
                           int *nparams,
                           unsigned int flags)
{
5187 5188 5189
    if (virNodeGetMemoryParametersEnsureACL(conn) < 0)
        return -1;

5190
    return virHostMemGetParameters(params, nparams, flags);
5191 5192 5193 5194
}


static int
5195
lxcNodeSetMemoryParameters(virConnectPtr conn,
5196 5197 5198 5199
                           virTypedParameterPtr params,
                           int nparams,
                           unsigned int flags)
{
5200 5201 5202
    if (virNodeSetMemoryParametersEnsureACL(conn) < 0)
        return -1;

5203
    return virHostMemSetParameters(params, nparams, flags);
5204 5205 5206 5207
}


static int
5208
lxcNodeGetCPUMap(virConnectPtr conn,
5209 5210 5211 5212
                 unsigned char **cpumap,
                 unsigned int *online,
                 unsigned int flags)
{
5213 5214 5215
    if (virNodeGetCPUMapEnsureACL(conn) < 0)
        return -1;

5216
    return virHostCPUGetMap(cpumap, online, flags);
5217 5218
}

5219 5220

static int
5221
lxcNodeSuspendForDuration(virConnectPtr conn,
5222 5223 5224 5225
                          unsigned int target,
                          unsigned long long duration,
                          unsigned int flags)
{
5226 5227 5228
    if (virNodeSuspendForDurationEnsureACL(conn) < 0)
        return -1;

5229
    return virNodeSuspend(target, duration, flags);
5230 5231 5232
}


5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256
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;
    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;

5257 5258 5259
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

5260
    ret = virDomainObjSetMetadata(vm, type, metadata, key, uri,
5261 5262
                                  driver->xmlopt, cfg->stateDir,
                                  cfg->configDir, flags);
5263

5264 5265 5266 5267 5268 5269
    if (ret == 0) {
        virObjectEventPtr ev = NULL;
        ev = virDomainEventMetadataChangeNewFromObj(vm, type, uri);
        virObjectEventStateQueue(driver->domainEventState, ev);
    }

5270
    virLXCDomainObjEndJob(driver, vm);
5271

5272
 cleanup:
5273
    virDomainObjEndAPI(&vm);
5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293
    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;

5294
    ret = virDomainObjGetMetadata(vm, type, uri, flags);
5295

5296
 cleanup:
5297
    virDomainObjEndAPI(&vm);
5298 5299 5300 5301
    return ret;
}


5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323
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;

5324
    if (virDomainObjCheckActive(vm) < 0)
5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337
        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,
5338
                                      nparams, start_cpu, ncpus, NULL);
5339
 cleanup:
5340
    virDomainObjEndAPI(&vm);
5341 5342 5343 5344
    return ret;
}


5345 5346 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 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422
static char *
lxcDomainGetHostname(virDomainPtr dom,
                     unsigned int flags)
{
    virLXCDriverPtr driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    char macaddr[VIR_MAC_STRING_BUFLEN];
    g_autoptr(virConnect) conn = NULL;
    virNetworkDHCPLeasePtr *leases = NULL;
    int n_leases;
    size_t i, j;
    char *hostname = NULL;

    virCheckFlags(VIR_DOMAIN_GET_HOSTNAME_LEASE, NULL);

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

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

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

    if (virDomainObjCheckActive(vm) < 0)
        goto endjob;

    if (!(conn = virGetConnectNetwork()))
        goto endjob;

    for (i = 0; i < vm->def->nnets; i++) {
        g_autoptr(virNetwork) network = NULL;
        virDomainNetDefPtr net = vm->def->nets[i];

        if (net->type != VIR_DOMAIN_NET_TYPE_NETWORK)
            continue;

        virMacAddrFormat(&net->mac, macaddr);
        network = virNetworkLookupByName(conn, net->data.network.name);

        if (!network)
            goto endjob;

        if ((n_leases = virNetworkGetDHCPLeases(network, macaddr,
                                                &leases, 0)) < 0)
            goto endjob;

        for (j = 0; j < n_leases; j++) {
            virNetworkDHCPLeasePtr lease = leases[j];

            if (lease->hostname && !hostname)
                hostname = g_strdup(lease->hostname);

            virNetworkDHCPLeaseFree(lease);
        }

        VIR_FREE(leases);

        if (hostname)
            goto endjob;
    }

    if (!hostname) {
        virReportError(VIR_ERR_NO_HOSTNAME,
                       _("no hostname found for domain %s"),
                       vm->def->name);
        goto endjob;
    }

 endjob:
    virLXCDomainObjEndJob(driver, vm);

 cleanup:
    virDomainObjEndAPI(&vm);
    return hostname;
}


5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436
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;

5437
    return virHostMemGetFreePages(npages, pages, startCell, cellCount, counts);
5438 5439 5440
}


5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456
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;

5457 5458
    return virHostMemAllocPages(npages, pageSizes, pageCounts,
                                startCell, cellCount, add);
5459 5460 5461
}


5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478
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:
5479
    virDomainObjEndAPI(&vm);
5480 5481 5482 5483
    return ret;
}


D
Daniel Veillard 已提交
5484
/* Function Tables */
5485
static virHypervisorDriver lxcHypervisorDriver = {
5486
    .name = LXC_DRIVER_NAME,
5487
    .connectURIProbe = lxcConnectURIProbe,
5488 5489
    .connectOpen = lxcConnectOpen, /* 0.4.2 */
    .connectClose = lxcConnectClose, /* 0.4.2 */
5490
    .connectSupportsFeature = lxcConnectSupportsFeature, /* 1.2.2 */
5491
    .connectGetVersion = lxcConnectGetVersion, /* 0.4.6 */
5492
    .connectGetHostname = lxcConnectGetHostname, /* 0.6.3 */
5493
    .connectGetSysinfo = lxcConnectGetSysinfo, /* 1.0.5 */
5494
    .nodeGetInfo = lxcNodeGetInfo, /* 0.6.5 */
5495 5496 5497 5498 5499
    .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 */
5500
    .domainCreateXMLWithFiles = lxcDomainCreateXMLWithFiles, /* 1.1.1 */
5501 5502 5503 5504 5505 5506
    .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 */
5507
    .domainDestroyFlags = lxcDomainDestroyFlags, /* 0.9.4 */
5508
    .domainGetOSType = lxcDomainGetOSType, /* 0.4.2 */
5509 5510 5511
    .domainGetMaxMemory = lxcDomainGetMaxMemory, /* 0.7.2 */
    .domainSetMaxMemory = lxcDomainSetMaxMemory, /* 0.7.2 */
    .domainSetMemory = lxcDomainSetMemory, /* 0.7.2 */
5512
    .domainSetMemoryFlags = lxcDomainSetMemoryFlags, /* 1.2.7 */
5513 5514
    .domainSetMemoryParameters = lxcDomainSetMemoryParameters, /* 0.8.5 */
    .domainGetMemoryParameters = lxcDomainGetMemoryParameters, /* 0.8.5 */
5515 5516
    .domainSetBlkioParameters = lxcDomainSetBlkioParameters, /* 0.9.8 */
    .domainGetBlkioParameters = lxcDomainGetBlkioParameters, /* 0.9.8 */
5517 5518
    .domainGetInfo = lxcDomainGetInfo, /* 0.4.2 */
    .domainGetState = lxcDomainGetState, /* 0.9.2 */
5519 5520
    .domainGetSecurityLabel = lxcDomainGetSecurityLabel, /* 0.9.10 */
    .nodeGetSecurityModel = lxcNodeGetSecurityModel, /* 0.9.10 */
5521
    .domainGetXMLDesc = lxcDomainGetXMLDesc, /* 0.4.2 */
5522
    .connectDomainXMLFromNative = lxcConnectDomainXMLFromNative, /* 1.2.2 */
5523 5524 5525 5526
    .connectListDefinedDomains = lxcConnectListDefinedDomains, /* 0.4.2 */
    .connectNumOfDefinedDomains = lxcConnectNumOfDefinedDomains, /* 0.4.2 */
    .domainCreate = lxcDomainCreate, /* 0.4.4 */
    .domainCreateWithFlags = lxcDomainCreateWithFlags, /* 0.8.2 */
5527
    .domainCreateWithFiles = lxcDomainCreateWithFiles, /* 1.1.1 */
5528
    .domainDefineXML = lxcDomainDefineXML, /* 0.4.2 */
5529
    .domainDefineXMLFlags = lxcDomainDefineXMLFlags, /* 1.2.12 */
5530
    .domainUndefine = lxcDomainUndefine, /* 0.4.2 */
5531
    .domainUndefineFlags = lxcDomainUndefineFlags, /* 0.9.4 */
5532 5533 5534 5535 5536
    .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 */
5537 5538
    .domainGetAutostart = lxcDomainGetAutostart, /* 0.7.0 */
    .domainSetAutostart = lxcDomainSetAutostart, /* 0.7.0 */
5539 5540 5541 5542 5543
    .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 */
5544 5545
    .domainBlockStats = lxcDomainBlockStats, /* 1.2.2 */
    .domainBlockStatsFlags = lxcDomainBlockStatsFlags, /* 1.2.2 */
5546
    .domainInterfaceStats = lxcDomainInterfaceStats, /* 0.7.3 */
5547
    .domainMemoryStats = lxcDomainMemoryStats, /* 1.2.2 */
5548 5549 5550 5551 5552
    .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 */
5553 5554 5555 5556
    .connectDomainEventRegister = lxcConnectDomainEventRegister, /* 0.7.0 */
    .connectDomainEventDeregister = lxcConnectDomainEventDeregister, /* 0.7.0 */
    .connectIsEncrypted = lxcConnectIsEncrypted, /* 0.7.3 */
    .connectIsSecure = lxcConnectIsSecure, /* 0.7.3 */
5557 5558 5559
    .domainIsActive = lxcDomainIsActive, /* 0.7.3 */
    .domainIsPersistent = lxcDomainIsPersistent, /* 0.7.3 */
    .domainIsUpdated = lxcDomainIsUpdated, /* 0.8.6 */
5560 5561
    .connectDomainEventRegisterAny = lxcConnectDomainEventRegisterAny, /* 0.8.0 */
    .connectDomainEventDeregisterAny = lxcConnectDomainEventDeregisterAny, /* 0.8.0 */
5562
    .domainOpenConsole = lxcDomainOpenConsole, /* 0.8.6 */
5563
    .connectIsAlive = lxcConnectIsAlive, /* 0.9.8 */
5564
    .nodeSuspendForDuration = lxcNodeSuspendForDuration, /* 0.9.8 */
5565 5566
    .domainSetMetadata = lxcDomainSetMetadata, /* 1.1.3 */
    .domainGetMetadata = lxcDomainGetMetadata, /* 1.1.3 */
5567
    .domainGetCPUStats = lxcDomainGetCPUStats, /* 1.2.2 */
5568
    .domainGetHostname = lxcDomainGetHostname, /* 6.0.0 */
5569
    .domainInterfaceAddresses = lxcDomainInterfaceAddresses, /* 6.1.0 */
5570 5571
    .nodeGetMemoryParameters = lxcNodeGetMemoryParameters, /* 0.10.2 */
    .nodeSetMemoryParameters = lxcNodeSetMemoryParameters, /* 0.10.2 */
5572
    .domainSendProcessSignal = lxcDomainSendProcessSignal, /* 1.0.1 */
5573 5574 5575
    .domainShutdown = lxcDomainShutdown, /* 1.0.1 */
    .domainShutdownFlags = lxcDomainShutdownFlags, /* 1.0.1 */
    .domainReboot = lxcDomainReboot, /* 1.0.1 */
5576
    .domainLxcOpenNamespace = lxcDomainLxcOpenNamespace, /* 1.0.2 */
5577
    .nodeGetFreePages = lxcNodeGetFreePages, /* 1.2.6 */
5578
    .nodeAllocPages = lxcNodeAllocPages, /* 1.2.9 */
5579
    .domainHasManagedSaveImage = lxcDomainHasManagedSaveImage, /* 1.2.13 */
D
Daniel Veillard 已提交
5580 5581
};

5582
static virConnectDriver lxcConnectDriver = {
5583
    .localOnly = true,
5584
    .uriSchemes = (const char *[]){ "lxc", NULL },
5585 5586 5587
    .hypervisorDriver = &lxcHypervisorDriver,
};

5588
static virStateDriver lxcStateDriver = {
5589
    .name = LXC_DRIVER_NAME,
5590 5591 5592
    .stateInitialize = lxcStateInitialize,
    .stateCleanup = lxcStateCleanup,
    .stateReload = lxcStateReload,
5593 5594
};

D
Daniel Veillard 已提交
5595 5596
int lxcRegister(void)
{
5597 5598
    if (virRegisterConnectDriver(&lxcConnectDriver,
                                 true) < 0)
5599 5600 5601
        return -1;
    if (virRegisterStateDriver(&lxcStateDriver) < 0)
        return -1;
D
Daniel Veillard 已提交
5602 5603
    return 0;
}