lxc_driver.c 165.5 KB
Newer Older
D
Daniel Veillard 已提交
1
/*
2
 * Copyright (C) 2010-2016 Red Hat, Inc.
D
Daniel Veillard 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
 * 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
#ifdef __linux__
29 30 31
# include <sys/sysmacros.h>
#endif

32
#include <sys/stat.h>
33
#include <sys/poll.h>
D
Daniel Veillard 已提交
34 35 36
#include <unistd.h>
#include <wait.h>

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

75 76
#define VIR_FROM_THIS VIR_FROM_LXC

77
VIR_LOG_INIT("lxc.lxc_driver");
78

79
#define LXC_NB_MEM_PARAM  3
80
#define LXC_NB_DOMAIN_BLOCK_STAT_PARAM 4
81

82

83
static int lxcStateInitialize(bool privileged,
84
                              const char *root,
85 86 87
                              virStateInhibitCallback callback,
                              void *opaque);
static int lxcStateCleanup(void);
88
virLXCDriverPtr lxc_driver = NULL;
D
Daniel Veillard 已提交
89

90

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

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

122 123 124 125 126 127
static int
lxcConnectURIProbe(char **uri)
{
    if (lxc_driver == NULL)
        return 0;

128 129
    *uri = g_strdup("lxc:///system");
    return 1;
130 131 132
}


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

140
    /* If path isn't '/' then they typoed, tell them correct path */
141 142
    if (STRNEQ(conn->uri->path, "") &&
        STRNEQ(conn->uri->path, "/") &&
143 144 145 146 147 148 149 150 151 152 153 154
        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;
155
    }
156

157 158 159
    if (virConnectOpenEnsureACL(conn) < 0)
        return VIR_DRV_OPEN_ERROR;

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

    return VIR_DRV_OPEN_SUCCESS;
}

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

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

174

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


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


J
Ján Tomko 已提交
189
static int lxcConnectIsAlive(virConnectPtr conn G_GNUC_UNUSED)
190 191 192 193 194
{
    return 1;
}


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

200 201 202
    if (virConnectGetCapabilitiesEnsureACL(conn) < 0)
        return NULL;

203
    if (!(caps = virLXCDriverGetCapabilities(driver, true)))
204 205
        return NULL;

206
    xml = virCapabilitiesFormatXML(caps);
207

208
    virObjectUnref(caps);
209 210 211 212
    return xml;
}


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

220
    vm = virDomainObjListFindByID(driver->domains, id);
221

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

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

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

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

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

245
    vm = virDomainObjListFindByUUID(driver->domains, uuid);
246

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

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

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

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

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

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

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

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

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

289 290 291 292 293 294

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

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

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

301 302
    ret = virDomainObjIsActive(obj);

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


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

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

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

320 321
    ret = obj->persistent;

322
 cleanup:
323
    virDomainObjEndAPI(&obj);
324 325 326
    return ret;
}

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

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

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

338 339
    ret = obj->updated;

340
 cleanup:
341
    virDomainObjEndAPI(&obj);
342 343
    return ret;
}
344

345 346
static int lxcConnectListDomains(virConnectPtr conn, int *ids, int nids)
{
347
    virLXCDriverPtr driver = conn->privateData;
348

349 350 351
    if (virConnectListDomainsEnsureACL(conn) < 0)
        return -1;

M
Michal Privoznik 已提交
352 353
    return virDomainObjListGetActiveIDs(driver->domains, ids, nids,
                                        virConnectListDomainsCheckACL, conn);
D
Daniel Veillard 已提交
354
}
355

356 357
static int lxcConnectNumOfDomains(virConnectPtr conn)
{
358
    virLXCDriverPtr driver = conn->privateData;
359

360 361 362
    if (virConnectNumOfDomainsEnsureACL(conn) < 0)
        return -1;

M
Michal Privoznik 已提交
363 364
    return virDomainObjListNumOfDomains(driver->domains, true,
                                        virConnectNumOfDomainsCheckACL, conn);
D
Daniel Veillard 已提交
365 366
}

367
static int lxcConnectListDefinedDomains(virConnectPtr conn,
368 369
                                        char **const names, int nnames)
{
370
    virLXCDriverPtr driver = conn->privateData;
371

372 373 374
    if (virConnectListDefinedDomainsEnsureACL(conn) < 0)
        return -1;

M
Michal Privoznik 已提交
375 376 377
    return virDomainObjListGetInactiveNames(driver->domains, names, nnames,
                                            virConnectListDefinedDomainsCheckACL,
                                            conn);
D
Daniel Veillard 已提交
378 379 380
}


381 382
static int lxcConnectNumOfDefinedDomains(virConnectPtr conn)
{
383
    virLXCDriverPtr driver = conn->privateData;
384

385 386 387
    if (virConnectNumOfDefinedDomainsEnsureACL(conn) < 0)
        return -1;

M
Michal Privoznik 已提交
388 389 390
    return virDomainObjListNumOfDomains(driver->domains, false,
                                        virConnectNumOfDefinedDomainsCheckACL,
                                        conn);
D
Daniel Veillard 已提交
391 392
}

393 394


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

408 409 410
    virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);

    if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
411
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
412

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

416
    if (!(def = virDomainDefParseString(xml, driver->xmlopt,
417
                                        NULL, parse_flags)))
418
        goto cleanup;
D
Daniel Veillard 已提交
419

420 421 422
    if (virXMLCheckIllegalChars("name", def->name, "\n") < 0)
        goto cleanup;

423
    if (virDomainDefineXMLFlagsEnsureACL(conn, def) < 0)
424 425
        goto cleanup;

426 427 428
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
        goto cleanup;

429
    if ((def->nets != NULL) && !(cfg->have_netns)) {
430 431
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("System lacks NETNS support"));
432
        goto cleanup;
433 434
    }

435
    if (!(vm = virDomainObjListAdd(driver->domains, def,
436
                                   driver->xmlopt,
437
                                   0, &oldDef)))
438
        goto cleanup;
439

440
    def = NULL;
441
    vm->persistent = 1;
D
Daniel Veillard 已提交
442

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

449
    event = virDomainEventLifecycleNewFromObj(vm,
450
                                     VIR_DOMAIN_EVENT_DEFINED,
451
                                     !oldDef ?
452 453 454
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);

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

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

467 468 469 470 471 472
static virDomainPtr
lxcDomainDefineXML(virConnectPtr conn, const char *xml)
{
    return lxcDomainDefineXMLFlags(conn, xml, 0);
}

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

482 483
    virCheckFlags(0, -1);

M
Michal Privoznik 已提交
484
    if (!(vm = lxcDomObjFromDomain(dom)))
485
        goto cleanup;
D
Daniel Veillard 已提交
486

487 488 489
    if (virDomainUndefineFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

496 497
    if (virDomainDeleteConfig(cfg->configDir,
                              cfg->autostartDir,
498 499
                              vm) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
500

501
    event = virDomainEventLifecycleNewFromObj(vm,
502 503 504
                                     VIR_DOMAIN_EVENT_UNDEFINED,
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);

505
    if (virDomainObjIsActive(vm))
506
        vm->persistent = 0;
507
    else
508
        virDomainObjListRemove(driver->domains, vm);
509

510
    ret = 0;
D
Daniel Veillard 已提交
511

512
 cleanup:
513
    virDomainObjEndAPI(&vm);
514
    virObjectEventStateQueue(driver->domainEventState, event);
515
    virObjectUnref(cfg);
516
    return ret;
D
Daniel Veillard 已提交
517 518
}

519 520 521 522 523
static int lxcDomainUndefine(virDomainPtr dom)
{
    return lxcDomainUndefineFlags(dom, 0);
}

D
Daniel Veillard 已提交
524 525 526
static int lxcDomainGetInfo(virDomainPtr dom,
                            virDomainInfoPtr info)
{
527
    virDomainObjPtr vm;
528
    int ret = -1;
529
    virLXCDomainObjPrivatePtr priv;
D
Daniel Veillard 已提交
530

M
Michal Privoznik 已提交
531
    if (!(vm = lxcDomObjFromDomain(dom)))
532
        goto cleanup;
D
Daniel Veillard 已提交
533

534 535
    priv = vm->privateData;

536 537 538
    if (virDomainGetInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

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

562
    info->maxMem = virDomainDefGetMemoryTotal(vm->def);
563
    info->nrVirtCpu = virDomainDefGetVcpus(vm->def);
564
    ret = 0;
D
Daniel Veillard 已提交
565

566
 cleanup:
567
    virDomainObjEndAPI(&vm);
568
    return ret;
D
Daniel Veillard 已提交
569 570
}

571 572 573 574 575 576 577 578 579 580 581
static int
lxcDomainGetState(virDomainPtr dom,
                  int *state,
                  int *reason,
                  unsigned int flags)
{
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

M
Michal Privoznik 已提交
582
    if (!(vm = lxcDomObjFromDomain(dom)))
583 584
        goto cleanup;

585 586 587
    if (virDomainGetStateEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
588
    *state = virDomainObjGetState(vm, reason);
589 590
    ret = 0;

591
 cleanup:
592
    virDomainObjEndAPI(&vm);
593 594 595
    return ret;
}

596
static char *lxcDomainGetOSType(virDomainPtr dom)
D
Daniel Veillard 已提交
597
{
598 599
    virDomainObjPtr vm;
    char *ret = NULL;
600

M
Michal Privoznik 已提交
601
    if (!(vm = lxcDomObjFromDomain(dom)))
602
        goto cleanup;
603

604 605 606
    if (virDomainGetOSTypeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

607
    ret = g_strdup(virDomainOSTypeToString(vm->def->os.type));
608

609
 cleanup:
610
    virDomainObjEndAPI(&vm);
611
    return ret;
D
Daniel Veillard 已提交
612 613
}

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

M
Michal Privoznik 已提交
621
    if (!(vm = lxcDomObjFromDomain(dom)))
R
Ryota Ozaki 已提交
622 623
        goto cleanup;

624 625 626
    if (virDomainGetMaxMemoryEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

629
 cleanup:
630
    virDomainObjEndAPI(&vm);
R
Ryota Ozaki 已提交
631 632 633
    return ret;
}

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

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
646 647
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_DOMAIN_MEM_MAXIMUM, -1);
R
Ryota Ozaki 已提交
648

M
Michal Privoznik 已提交
649
    if (!(vm = lxcDomObjFromDomain(dom)))
R
Ryota Ozaki 已提交
650
        goto cleanup;
M
Michal Privoznik 已提交
651

652 653
    cfg = virLXCDriverGetConfig(driver);

654
    priv = vm->privateData;
R
Ryota Ozaki 已提交
655

656
    if (virDomainSetMemoryFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
657 658
        goto cleanup;

659
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
660 661
        goto cleanup;

662
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
663
        goto endjob;
664

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

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

684
        if (def)
685
            oldmax = virDomainDefGetMemoryTotal(def);
686
        if (persistentDef) {
687 688
            if (!oldmax || oldmax > virDomainDefGetMemoryTotal(persistentDef))
                oldmax = virDomainDefGetMemoryTotal(persistentDef);
689
        }
690

691 692 693
        if (newmem > oldmax) {
            virReportError(VIR_ERR_INVALID_ARG,
                           "%s", _("Cannot set memory higher than max memory"));
694
            goto endjob;
695 696
        }

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

704
            def->mem.cur_balloon = newmem;
705
            if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0)
706
                goto endjob;
707 708
        }

709
        if (persistentDef) {
710
            persistentDef->mem.cur_balloon = newmem;
711
            if (virDomainDefSave(persistentDef,
712
                                 driver->xmlopt, cfg->configDir) < 0)
713
                goto endjob;
714
        }
715 716
    }

R
Ryota Ozaki 已提交
717 718
    ret = 0;

719
 endjob:
720
    virLXCDomainObjEndJob(driver, vm);
721

722
 cleanup:
723
    virDomainObjEndAPI(&vm);
724
    virObjectUnref(cfg);
R
Ryota Ozaki 已提交
725 726 727
    return ret;
}

728 729 730 731 732
static int lxcDomainSetMemory(virDomainPtr dom, unsigned long newmem)
{
    return lxcDomainSetMemoryFlags(dom, newmem, VIR_DOMAIN_AFFECT_LIVE);
}

733 734 735 736 737
static int lxcDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax)
{
    return lxcDomainSetMemoryFlags(dom, newmax, VIR_DOMAIN_MEM_MAXIMUM);
}

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

759 760 761
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

762 763 764 765 766 767 768 769
    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)
770
        return -1;
E
Eric Blake 已提交
771

M
Michal Privoznik 已提交
772
    if (!(vm = lxcDomObjFromDomain(dom)))
773
        goto cleanup;
M
Michal Privoznik 已提交
774

775
    priv = vm->privateData;
776
    cfg = virLXCDriverGetConfig(driver);
777

778
    if (virDomainSetMemoryParametersEnsureACL(dom->conn, vm->def, flags) < 0)
779 780
        goto cleanup;

781 782 783
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

784 785
    /* QEMU and LXC implementation are identical */
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
786 787
        goto endjob;

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

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

808
    /* Swap hard limit must be greater than hard limit. */
809 810 811 812 813 814 815 816 817 818
    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;

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

827 828 829 830 831 832 833 834 835 836
#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; \
837 838 839
    }

    /* Soft limit doesn't clash with the others */
840
    VIR_SET_MEM_PARAMETER(virCgroupSetMemorySoftLimit, soft_limit);
841 842

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

849
    VIR_SET_MEM_PARAMETER(virCgroupSetMemSwapHardLimit, swap_hard_limit);
850 851

    /* otherwise increase it after swap hard limit */
852 853 854
    VIR_SET_MEM_PARAMETER(virCgroupSetMemoryHardLimit, hard_limit);

#undef VIR_SET_MEM_PARAMETER
855

856
    if (def &&
857
        virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0)
858
        goto endjob;
859

860
    if (persistentDef &&
861
        virDomainDefSave(persistentDef, driver->xmlopt, cfg->configDir) < 0)
862
        goto endjob;
863
    /* QEMU and LXC implementations are identical */
864 865

    ret = 0;
866 867

 endjob:
868
    virLXCDomainObjEndJob(driver, vm);
869

870
 cleanup:
871
    virDomainObjEndAPI(&vm);
872
    virObjectUnref(cfg);
873 874 875
    return ret;
}

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

890
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
891 892 893 894 895
                  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 已提交
896

M
Michal Privoznik 已提交
897
    if (!(vm = lxcDomObjFromDomain(dom)))
898
        goto cleanup;
M
Michal Privoznik 已提交
899

900
    priv = vm->privateData;
901

902
    if (virDomainGetMemoryParametersEnsureACL(dom->conn, vm->def) < 0)
903 904
        goto cleanup;

905 906 907 908
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
        goto cleanup;

    if (def &&
909 910 911
        !virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_MEMORY)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup memory controller is not mounted"));
912
        goto cleanup;
913
    }
914

915 916 917 918 919 920 921
    if ((*nparams) == 0) {
        /* Current number of memory parameters supported by cgroups */
        *nparams = LXC_NB_MEM_PARAM;
        ret = 0;
        goto cleanup;
    }

922
    for (i = 0; i < LXC_NB_MEM_PARAM && i < *nparams; i++) {
923
        virTypedParameterPtr param = &params[i];
924 925
        val = 0;

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

961 962
    if (*nparams > LXC_NB_MEM_PARAM)
        *nparams = LXC_NB_MEM_PARAM;
963 964
    ret = 0;

965
 cleanup:
966
    virDomainObjEndAPI(&vm);
967 968 969
    return ret;
}

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

977
    virCheckFlags(VIR_DOMAIN_XML_COMMON_FLAGS, NULL);
978

M
Michal Privoznik 已提交
979
    if (!(vm = lxcDomObjFromDomain(dom)))
980
        goto cleanup;
D
Daniel Veillard 已提交
981

982 983 984
    if (virDomainGetXMLDescEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

985
    ret = virDomainDefFormat((flags & VIR_DOMAIN_XML_INACTIVE) &&
986
                             vm->newDef ? vm->newDef : vm->def,
987
                             driver->xmlopt,
988
                             virDomainDefFormatConvertXMLFlags(flags));
989

990
 cleanup:
991
    virDomainObjEndAPI(&vm);
992
    return ret;
D
Daniel Veillard 已提交
993 994
}

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

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

1016
    if (!(def = lxcParseConfigString(nativeConfig, caps, driver->xmlopt)))
1017 1018
        goto cleanup;

1019
    xml = virDomainDefFormat(def, driver->xmlopt, 0);
1020

1021
 cleanup:
1022
    virObjectUnref(caps);
1023 1024 1025 1026
    virDomainDefFree(def);
    return xml;
}

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

1047
    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, -1);
1048

1049 1050
    virNWFilterReadLockFilterUpdates();

M
Michal Privoznik 已提交
1051
    if (!(vm = lxcDomObjFromDomain(dom)))
1052 1053
        goto cleanup;

1054
    if (virDomainCreateWithFilesEnsureACL(dom->conn, vm->def) < 0)
1055 1056
        goto cleanup;

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

1063 1064 1065
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

1066
    if (virDomainObjIsActive(vm)) {
1067 1068
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is already running"));
1069
        goto endjob;
1070 1071
    }

1072
    ret = virLXCProcessStart(dom->conn, driver, vm,
1073
                             nfiles, files,
1074 1075
                             (flags & VIR_DOMAIN_START_AUTODESTROY),
                             VIR_DOMAIN_RUNNING_BOOTED);
1076

1077
    if (ret == 0) {
1078
        event = virDomainEventLifecycleNewFromObj(vm,
1079 1080
                                         VIR_DOMAIN_EVENT_STARTED,
                                         VIR_DOMAIN_EVENT_STARTED_BOOTED);
1081 1082 1083 1084
        virDomainAuditStart(vm, "booted", true);
    } else {
        virDomainAuditStart(vm, "booted", false);
    }
1085

1086
 endjob:
1087
    virLXCDomainObjEndJob(driver, vm);
1088

1089
 cleanup:
1090
    virDomainObjEndAPI(&vm);
1091
    virObjectEventStateQueue(driver->domainEventState, event);
1092
    virObjectUnref(cfg);
1093
    virNWFilterUnlockFilterUpdates();
1094
    return ret;
1095 1096
}

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

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

    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY |
                  VIR_DOMAIN_START_VALIDATE, NULL);

1155

1156
    if (flags & VIR_DOMAIN_START_VALIDATE)
1157
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
1158

1159 1160
    virNWFilterReadLockFilterUpdates();

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

1164
    if (!(def = virDomainDefParseString(xml, driver->xmlopt,
1165
                                        NULL, parse_flags)))
1166
        goto cleanup;
1167

1168
    if (virDomainCreateXMLWithFilesEnsureACL(conn, def) < 0)
1169 1170
        goto cleanup;

1171 1172 1173
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
        goto cleanup;

1174
    if ((def->nets != NULL) && !(cfg->have_netns)) {
1175 1176
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       "%s", _("System lacks NETNS support"));
1177
        goto cleanup;
1178 1179
    }

1180

1181
    if (!(vm = virDomainObjListAdd(driver->domains, def,
1182
                                   driver->xmlopt,
1183
                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
1184 1185
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
1186 1187
        goto cleanup;
    def = NULL;
1188

1189
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0) {
1190
        if (!vm->persistent)
1191 1192 1193 1194
            virDomainObjListRemove(driver->domains, vm);
        goto cleanup;
    }

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

1206
    event = virDomainEventLifecycleNewFromObj(vm,
1207 1208
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
1209
    virDomainAuditStart(vm, "booted", true);
1210

1211
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
1212

1213
    virLXCDomainObjEndJob(driver, vm);
1214

1215
 cleanup:
1216
    virDomainDefFree(def);
1217
    virDomainObjEndAPI(&vm);
1218
    virObjectEventStateQueue(driver->domainEventState, event);
1219
    virObjectUnref(caps);
1220
    virObjectUnref(cfg);
1221
    virNWFilterUnlockFilterUpdates();
1222 1223 1224
    return dom;
}

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


1244 1245
static int lxcDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr seclabel)
{
1246
    virLXCDriverPtr driver = dom->conn->privateData;
1247 1248 1249 1250 1251
    virDomainObjPtr vm;
    int ret = -1;

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

M
Michal Privoznik 已提交
1252
    if (!(vm = lxcDomObjFromDomain(dom)))
1253 1254
        goto cleanup;

1255 1256 1257
    if (virDomainGetSecurityLabelEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

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

1281
        if (virSecurityManagerGetProcessLabel(driver->securityManager,
1282 1283
                                              vm->def, priv->initpid,
                                              seclabel) < 0)
1284 1285 1286 1287 1288
            goto cleanup;
    }

    ret = 0;

1289
 cleanup:
1290
    virDomainObjEndAPI(&vm);
1291 1292 1293 1294 1295 1296
    return ret;
}

static int lxcNodeGetSecurityModel(virConnectPtr conn,
                                   virSecurityModelPtr secmodel)
{
1297
    virLXCDriverPtr driver = conn->privateData;
1298
    virCapsPtr caps = NULL;
1299 1300 1301 1302
    int ret = 0;

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

1303 1304 1305
    if (virNodeGetSecurityModelEnsureACL(conn) < 0)
        goto cleanup;

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

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

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

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

1332
 cleanup:
1333
    virObjectUnref(caps);
1334 1335 1336 1337
    return ret;
}


1338
static int
1339 1340 1341 1342
lxcConnectDomainEventRegister(virConnectPtr conn,
                              virConnectDomainEventCallback callback,
                              void *opaque,
                              virFreeCallback freecb)
1343
{
1344
    virLXCDriverPtr driver = conn->privateData;
1345

1346 1347 1348
    if (virConnectDomainEventRegisterEnsureACL(conn) < 0)
        return -1;

1349 1350 1351 1352
    if (virDomainEventStateRegister(conn,
                                    driver->domainEventState,
                                    callback, opaque, freecb) < 0)
        return -1;
1353

1354
    return 0;
1355 1356
}

1357

1358
static int
1359 1360
lxcConnectDomainEventDeregister(virConnectPtr conn,
                                virConnectDomainEventCallback callback)
1361
{
1362
    virLXCDriverPtr driver = conn->privateData;
1363

1364 1365 1366
    if (virConnectDomainEventDeregisterEnsureACL(conn) < 0)
        return -1;

1367 1368 1369 1370
    if (virDomainEventStateDeregister(conn,
                                      driver->domainEventState,
                                      callback) < 0)
        return -1;
1371

1372
    return 0;
1373 1374
}

1375 1376

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

1387 1388 1389
    if (virConnectDomainEventRegisterAnyEnsureACL(conn) < 0)
        return -1;

1390 1391 1392 1393
    if (virDomainEventStateRegisterID(conn,
                                      driver->domainEventState,
                                      dom, eventID,
                                      callback, opaque, freecb, &ret) < 0)
1394
        ret = -1;
1395 1396 1397 1398 1399 1400

    return ret;
}


static int
1401 1402
lxcConnectDomainEventDeregisterAny(virConnectPtr conn,
                                   int callbackID)
1403
{
1404
    virLXCDriverPtr driver = conn->privateData;
1405

1406 1407 1408
    if (virConnectDomainEventDeregisterAnyEnsureACL(conn) < 0)
        return -1;

1409 1410
    if (virObjectEventStateDeregisterID(conn,
                                        driver->domainEventState,
1411
                                        callbackID, true) < 0)
1412
        return -1;
1413

1414
    return 0;
1415 1416 1417
}


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

1437 1438
    virCheckFlags(0, -1);

M
Michal Privoznik 已提交
1439
    if (!(vm = lxcDomObjFromDomain(dom)))
1440
        goto cleanup;
1441

1442 1443 1444
    if (virDomainDestroyFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1445
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_DESTROY) < 0)
1446 1447
        goto cleanup;

1448
    if (virDomainObjCheckActive(vm) < 0)
1449
        goto endjob;
1450

1451
    priv = vm->privateData;
1452
    ret = virLXCProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED);
1453
    event = virDomainEventLifecycleNewFromObj(vm,
1454 1455
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
1456
    priv->doneStopEvent = true;
1457
    virDomainAuditStop(vm, "destroyed");
1458

1459
 endjob:
1460
    virLXCDomainObjEndJob(driver, vm);
1461
    if (!vm->persistent)
1462
        virDomainObjListRemove(driver->domains, vm);
1463

1464
 cleanup:
1465
    virDomainObjEndAPI(&vm);
1466
    virObjectEventStateQueue(driver->domainEventState, event);
1467
    return ret;
1468
}
1469

1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483
/**
 * 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);
}

1484 1485 1486 1487 1488
static int lxcCheckNetNsSupport(void)
{
    const char *argv[] = {"ip", "link", "set", "lo", "netns", "-1", NULL};
    int ip_rc;

1489
    if (virRun(argv, &ip_rc) < 0 || ip_rc == 255)
1490
        return 0;
1491

1492
    if (virProcessNamespaceAvailable(VIR_PROCESS_NAMESPACE_NET) < 0)
1493
        return 0;
1494

1495
    return 1;
1496 1497
}

1498

1499 1500
static virSecurityManagerPtr
lxcSecurityInit(virLXCDriverConfigPtr cfg)
1501
{
1502 1503
    unsigned int flags = VIR_SECURITY_MANAGER_PRIVILEGED;

1504
    VIR_INFO("lxcSecurityInit %s", cfg->securityDriverName);
1505 1506 1507 1508 1509 1510

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

1511
    virSecurityManagerPtr mgr = virSecurityManagerNew(cfg->securityDriverName,
1512
                                                      LXC_DRIVER_NAME, flags);
1513 1514 1515
    if (!mgr)
        goto error;

1516
    return mgr;
1517

1518
 error:
1519
    VIR_ERROR(_("Failed to initialize security drivers"));
1520
    virObjectUnref(mgr);
1521
    return NULL;
1522 1523 1524
}


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

1533 1534 1535 1536 1537 1538
    if (root != NULL) {
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Driver does not support embedded mode"));
        return -1;
    }

1539
    /* Check that the user is root, silently disable if not */
1540
    if (!privileged) {
1541
        VIR_INFO("Not running privileged, disabling driver");
1542
        return VIR_DRV_STATE_INIT_SKIPPED;
1543 1544 1545
    }

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

1554
    if (VIR_ALLOC(lxc_driver) < 0)
1555
        return VIR_DRV_STATE_INIT_ERROR;
1556
    lxc_driver->lockFD = -1;
1557 1558
    if (virMutexInit(&lxc_driver->lock) < 0) {
        VIR_FREE(lxc_driver);
1559
        return VIR_DRV_STATE_INIT_ERROR;
1560
    }
D
Daniel Veillard 已提交
1561

1562
    if (!(lxc_driver->domains = virDomainObjListNew()))
1563 1564
        goto cleanup;

1565
    lxc_driver->domainEventState = virObjectEventStateNew();
1566
    if (!lxc_driver->domainEventState)
1567 1568
        goto cleanup;

1569 1570
    lxc_driver->hostsysinfo = virSysinfoRead();

1571 1572 1573 1574 1575
    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 已提交
1576 1577

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

1581
    if (!(lxc_driver->securityManager = lxcSecurityInit(cfg)))
1582 1583
        goto cleanup;

1584
    if (!(lxc_driver->hostdevMgr = virHostdevManagerGetDefault()))
G
Guido Günther 已提交
1585 1586
        goto cleanup;

1587
    if (!(lxc_driver->xmlopt = lxcDomainXMLConfInit(lxc_driver)))
1588
        goto cleanup;
1589

1590
    if (!(lxc_driver->closeCallbacks = virCloseCallbacksNew()))
1591 1592
        goto cleanup;

1593 1594 1595 1596 1597 1598 1599
    if (virFileMakePath(cfg->stateDir) < 0) {
        virReportSystemError(errno,
                             _("Failed to mkdir %s"),
                             cfg->stateDir);
        goto cleanup;
    }

1600
    if ((lxc_driver->lockFD =
1601
         virPidFileAcquire(cfg->stateDir, "driver", false, getpid())) < 0)
1602 1603
        goto cleanup;

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

1612
    virLXCProcessReconnectAll(lxc_driver, lxc_driver->domains);
O
Osier Yang 已提交
1613 1614

    /* Then inactive persistent configs */
1615
    if (virDomainObjListLoadAllConfigs(lxc_driver->domains,
1616
                                       cfg->configDir,
1617
                                       cfg->autostartDir, false,
1618
                                       lxc_driver->xmlopt,
1619
                                       NULL, NULL) < 0)
1620
        goto cleanup;
1621

1622 1623 1624 1625 1626
    if (virDriverShouldAutostart(cfg->stateDir, &autostart) < 0)
        goto cleanup;

    if (autostart)
        virLXCProcessAutostartAll(lxc_driver);
1627

1628
    return VIR_DRV_STATE_INIT_COMPLETE;
D
Daniel Veillard 已提交
1629

1630
 cleanup:
1631
    lxcStateCleanup();
1632
    return VIR_DRV_STATE_INIT_ERROR;
D
Daniel Veillard 已提交
1633 1634
}

1635 1636
static void lxcNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
{
1637
    virLXCDriverPtr driver = opaque;
1638 1639

    if (newVM) {
1640
        virObjectEventPtr event =
1641
            virDomainEventLifecycleNewFromObj(vm,
1642 1643
                                     VIR_DOMAIN_EVENT_DEFINED,
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED);
1644
        virObjectEventStateQueue(driver->domainEventState, event);
1645 1646 1647 1648
    }
}

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

1659 1660 1661
    if (!lxc_driver)
        return 0;

1662 1663
    cfg = virLXCDriverGetConfig(lxc_driver);

1664
    virDomainObjListLoadAllConfigs(lxc_driver->domains,
1665
                                   cfg->configDir,
1666
                                   cfg->autostartDir, false,
1667
                                   lxc_driver->xmlopt,
1668
                                   lxcNotifyLoadDomain, lxc_driver);
1669
    virObjectUnref(cfg);
1670 1671 1672
    return 0;
}

1673
static int lxcStateCleanup(void)
D
Daniel Veillard 已提交
1674
{
1675
    if (lxc_driver == NULL)
1676
        return -1;
1677

1678
    virObjectUnref(lxc_driver->domains);
1679
    virObjectUnref(lxc_driver->domainEventState);
1680

1681
    virObjectUnref(lxc_driver->closeCallbacks);
1682

1683 1684
    virSysinfoDefFree(lxc_driver->hostsysinfo);

1685
    virObjectUnref(lxc_driver->hostdevMgr);
1686
    virObjectUnref(lxc_driver->caps);
1687
    virObjectUnref(lxc_driver->securityManager);
1688
    virObjectUnref(lxc_driver->xmlopt);
1689 1690 1691 1692

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

1693
    virObjectUnref(lxc_driver->config);
1694
    virMutexDestroy(&lxc_driver->lock);
1695
    VIR_FREE(lxc_driver);
1696 1697 1698

    return 0;
}
D
Daniel Veillard 已提交
1699

1700 1701 1702 1703 1704 1705
static int
lxcConnectSupportsFeature(virConnectPtr conn, int feature)
{
    if (virConnectSupportsFeatureEnsureACL(conn) < 0)
        return -1;

1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724
    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;
1725 1726 1727
    }
}

D
Daniel Veillard 已提交
1728

1729
static int lxcConnectGetVersion(virConnectPtr conn, unsigned long *version)
D
Dan Smith 已提交
1730 1731 1732
{
    struct utsname ver;

1733
    uname(&ver);
D
Dan Smith 已提交
1734

1735 1736 1737
    if (virConnectGetVersionEnsureACL(conn) < 0)
        return -1;

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

    return 0;
}
1745

1746

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



1790
static char *lxcConnectGetHostname(virConnectPtr conn)
1791
{
1792 1793 1794
    if (virConnectGetHostnameEnsureACL(conn) < 0)
        return NULL;

1795 1796 1797 1798
    return virGetHostname();
}


1799 1800
static char *lxcDomainGetSchedulerType(virDomainPtr dom,
                                       int *nparams)
1801
{
1802
    char *ret = NULL;
1803 1804
    virDomainObjPtr vm;
    virLXCDomainObjPrivatePtr priv;
1805

M
Michal Privoznik 已提交
1806
    if (!(vm = lxcDomObjFromDomain(dom)))
1807
        goto cleanup;
M
Michal Privoznik 已提交
1808

1809 1810
    priv = vm->privateData;

1811 1812 1813
    if (virDomainGetSchedulerTypeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

1822
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
1823 1824
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPU controller is not mounted"));
1825 1826
        goto cleanup;
    }
1827

1828
    if (nparams) {
1829
        if (virCgroupSupportsCpuBW(priv->cgroup))
1830
            *nparams = 3;
1831 1832
        else
            *nparams = 1;
1833
    }
1834

1835
    ret = g_strdup("posix");
1836

1837
 cleanup:
1838
    virDomainObjEndAPI(&vm);
1839 1840 1841 1842 1843 1844 1845 1846
    return ret;
}


static int
lxcGetVcpuBWLive(virCgroupPtr cgroup, unsigned long long *period,
                 long long *quota)
{
1847
    if (virCgroupGetCpuCfsPeriod(cgroup, period) < 0)
1848 1849
        return -1;

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

1870
        if (virCgroupSetCpuCfsPeriod(cgroup, period) < 0)
1871 1872 1873 1874
            return -1;
    }

    if (quota) {
1875 1876
        if (virCgroupSetCpuCfsQuota(cgroup, quota) < 0)
            goto error;
1877 1878 1879 1880
    }

    return 0;

1881
 error:
1882
    if (period) {
1883 1884 1885
        virErrorPtr saved;

        virErrorPreserveLast(&saved);
1886
        virCgroupSetCpuCfsPeriod(cgroup, old_period);
1887
        virErrorRestore(&saved);
1888 1889 1890
    }

    return -1;
1891 1892
}

1893

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

1912 1913
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
1914 1915 1916 1917 1918 1919 1920 1921
    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)
1922
        return -1;
1923

M
Michal Privoznik 已提交
1924
    if (!(vm = lxcDomObjFromDomain(dom)))
1925
        goto cleanup;
M
Michal Privoznik 已提交
1926

1927
    priv = vm->privateData;
1928

1929 1930 1931
    if (virDomainSetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

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

1935 1936 1937
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

1938
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
1939
        goto endjob;
1940

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

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

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

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

1965
                if (virCgroupGetCpuShares(priv->cgroup, &val) < 0)
1966
                    goto endjob;
1967

1968 1969
                def->cputune.shares = val;
                def->cputune.sharesSpecified = true;
1970 1971
            }

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

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

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

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

1998
            if (persistentDef)
J
Ján Tomko 已提交
1999
                persistentDefCopy->cputune.quota = params[i].value.l;
2000
        }
2001
    }
2002

2003
    if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0)
2004
        goto endjob;
2005

2006

2007
    if (persistentDef) {
2008
        rc = virDomainDefSave(persistentDefCopy, driver->xmlopt,
2009
                              cfg->configDir);
2010
        if (rc < 0)
2011
            goto endjob;
2012

J
Ján Tomko 已提交
2013 2014
        virDomainObjAssignDef(vm, persistentDefCopy, false, NULL);
        persistentDefCopy = NULL;
2015
    }
2016

2017
    ret = 0;
2018

2019
 endjob:
2020
    virLXCDomainObjEndJob(driver, vm);
2021

2022
 cleanup:
J
Ján Tomko 已提交
2023
    virDomainDefFree(persistentDefCopy);
2024
    virDomainObjEndAPI(&vm);
2025
    virObjectUnref(caps);
2026
    virObjectUnref(cfg);
2027
    return ret;
2028 2029
}

2030
static int
2031 2032 2033
lxcDomainSetSchedulerParameters(virDomainPtr domain,
                                virTypedParameterPtr params,
                                int nparams)
2034
{
2035
    return lxcDomainSetSchedulerParametersFlags(domain, params, nparams, 0);
2036 2037 2038
}

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

2056
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
2057 2058 2059 2060 2061
                  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;
2062

M
Michal Privoznik 已提交
2063
    if (!(vm = lxcDomObjFromDomain(dom)))
2064
        goto cleanup;
M
Michal Privoznik 已提交
2065

2066 2067
    priv = vm->privateData;

2068 2069 2070
    if (virDomainGetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2071 2072
    if (*nparams > 1)
        cpu_bw_status = virCgroupSupportsCpuBW(priv->cgroup);
2073

2074
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
E
Eric Blake 已提交
2075
        goto cleanup;
2076

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

2087
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
2088 2089
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPU controller is not mounted"));
2090
        goto cleanup;
2091 2092
    }

2093
    if (virCgroupGetCpuShares(priv->cgroup, &shares) < 0)
2094
        goto cleanup;
2095 2096

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

    if (cpu_bw_status) {
        if (*nparams > saved_nparams) {
2109 2110 2111
            if (virTypedParameterAssign(&params[1],
                                        VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
                                        VIR_TYPED_PARAM_ULLONG, period) < 0)
2112 2113 2114 2115 2116
                goto cleanup;
            saved_nparams++;
        }

        if (*nparams > saved_nparams) {
2117 2118 2119
            if (virTypedParameterAssign(&params[2],
                                        VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
                                        VIR_TYPED_PARAM_LLONG, quota) < 0)
2120 2121 2122 2123 2124 2125 2126
                goto cleanup;
            saved_nparams++;
        }
    }

    *nparams = saved_nparams;

2127
    ret = 0;
2128

2129
 cleanup:
2130
    virDomainObjEndAPI(&vm);
2131
    return ret;
2132 2133
}

2134
static int
2135 2136 2137
lxcDomainGetSchedulerParameters(virDomainPtr domain,
                                virTypedParameterPtr params,
                                int *nparams)
2138
{
2139
    return lxcDomainGetSchedulerParametersFlags(domain, params, nparams, 0);
2140 2141
}

2142 2143 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
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))
2170
        goto parse_error;
2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184

    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)
2185
            goto parse_error;
2186

2187
        result[i].path = g_strndup(temp, p - temp);
2188 2189 2190 2191 2192

        /* value */
        temp = p + 1;

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

        i++;

        if (*p == '\0')
            break;
        else if (*p != ',')
2218
            goto parse_error;
2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229
        temp = p + 1;
    }

    if (!i)
        VIR_FREE(result);

    *dev = result;
    *size = i;

    return 0;

2230
 parse_error:
2231 2232 2233
    virReportError(VIR_ERR_INVALID_ARG,
                   _("unable to parse blkio device '%s' '%s'"),
                   type, blkioDeviceStr);
2234 2235 2236 2237 2238 2239 2240
    goto cleanup;

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

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

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

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

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

    return 0;
}

2317

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

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

2340
    if (virDomainObjCheckActive(vm) < 0)
2341
        goto endjob;
2342 2343 2344 2345

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

    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);
2356
        goto endjob;
2357 2358
    }

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

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

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

 endjob:
2379
    virLXCDomainObjEndJob(driver, vm);
2380

2381
 cleanup:
2382
    virDomainObjEndAPI(&vm);
2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393
    return ret;
}


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

2407
    if (!*nparams) {
2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419
        *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;

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

2423
    if (virDomainObjCheckActive(vm) < 0)
2424
        goto endjob;
2425 2426 2427 2428

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

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

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

        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"));
2464
            goto endjob;
2465 2466 2467 2468 2469 2470 2471 2472 2473 2474
        }
    }

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

    ret = 0;
    *nparams = tmp;

2506
 endjob:
2507
    virLXCDomainObjEndJob(driver, vm);
2508

2509
 cleanup:
2510
    virDomainObjEndAPI(&vm);
2511 2512 2513 2514
    return ret;
}


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

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

M
Michal Privoznik 已提交
2548
    if (!(vm = lxcDomObjFromDomain(dom)))
2549
        return -1;
M
Michal Privoznik 已提交
2550

2551
    priv = vm->privateData;
2552
    cfg = virLXCDriverGetConfig(driver);
2553

2554 2555 2556
    if (virDomainSetBlkioParametersEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

2557 2558 2559
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

2560
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
2561
        goto endjob;
2562

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

2571
    ret = 0;
2572
    if (def) {
2573 2574 2575 2576
        for (i = 0; i < nparams; i++) {
            virTypedParameterPtr param = &params[i];

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

2708
        if (virDomainDefSave(persistentDef, driver->xmlopt, cfg->configDir) < 0)
2709
            ret = -1;
2710 2711
    }

2712
 endjob:
2713
    virLXCDomainObjEndJob(driver, vm);
2714

2715
 cleanup:
2716
    virDomainObjEndAPI(&vm);
2717
    virObjectUnref(cfg);
2718 2719 2720 2721
    return ret;
}


2722 2723
#define LXC_NB_BLKIO_PARAM  6

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

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
2739 2740 2741 2742 2743 2744 2745
                  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;
2746

M
Michal Privoznik 已提交
2747
    if (!(vm = lxcDomObjFromDomain(dom)))
2748
        return -1;
M
Michal Privoznik 已提交
2749

2750
    priv = vm->privateData;
2751

2752 2753 2754
    if (virDomainGetBlkioParametersEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2755 2756 2757 2758 2759
    if ((*nparams) == 0) {
        /* Current number of blkio parameters supported by cgroups */
        *nparams = LXC_NB_BLKIO_PARAM;
        ret = 0;
        goto cleanup;
2760 2761
    } else if (*nparams < maxparams) {
        maxparams = *nparams;
2762 2763
    }

2764 2765
    *nparams = 0;

2766
    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
E
Eric Blake 已提交
2767
        goto cleanup;
2768

2769
    if (def) {
2770
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) {
2771 2772
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("blkio cgroup isn't mounted"));
2773 2774 2775
            goto cleanup;
        }

2776 2777 2778 2779 2780 2781 2782
        /* 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;
2783

2784 2785 2786
        if (virDomainGetBlkioParametersAssignFromDef(def, params, nparams,
                                                     maxparams) < 0)
            goto cleanup;
2787

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

2796 2797 2798
        if (virDomainGetBlkioParametersAssignFromDef(persistentDef, params,
                                                     nparams, maxparams) < 0)
            goto cleanup;
2799 2800 2801 2802
    }

    ret = 0;

2803
 cleanup:
2804
    virDomainObjEndAPI(&vm);
2805 2806 2807 2808
    return ret;
}


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

M
Michal Privoznik 已提交
2819
    if (!(vm = lxcDomObjFromDomain(dom)))
2820 2821
        goto cleanup;

2822 2823 2824
    if (virDomainInterfaceStatsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

2828
    if (virDomainObjCheckActive(vm) < 0)
2829
        goto endjob;
2830

2831
    if (!(net = virDomainNetFind(vm->def, device)))
M
Michal Privoznik 已提交
2832 2833
        goto endjob;

2834
    if (virNetDevTapInterfaceStats(net->ifname, stats,
2835
                                   !virDomainNetTypeSharesHostView(net)) < 0)
M
Michal Privoznik 已提交
2836 2837 2838
        goto endjob;

    ret = 0;
2839

2840
 endjob:
2841
    virLXCDomainObjEndJob(driver, vm);
2842

2843
 cleanup:
2844
    virDomainObjEndAPI(&vm);
2845 2846
    return ret;
}
2847

2848

2849
static int lxcDomainGetAutostart(virDomainPtr dom,
2850 2851
                                   int *autostart)
{
2852 2853 2854
    virDomainObjPtr vm;
    int ret = -1;

M
Michal Privoznik 已提交
2855
    if (!(vm = lxcDomObjFromDomain(dom)))
2856 2857
        goto cleanup;

2858 2859 2860
    if (virDomainGetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2861 2862 2863
    *autostart = vm->autostart;
    ret = 0;

2864
 cleanup:
2865
    virDomainObjEndAPI(&vm);
2866 2867 2868 2869
    return ret;
}

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

M
Michal Privoznik 已提交
2878
    if (!(vm = lxcDomObjFromDomain(dom)))
2879 2880
        goto cleanup;

2881 2882 2883
    if (virDomainSetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2884 2885 2886
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

2887
    if (!vm->persistent) {
2888 2889
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Cannot set autostart for transient domain"));
2890
        goto endjob;
2891 2892 2893 2894
    }

    autostart = (autostart != 0);

2895 2896
    if (vm->autostart == autostart) {
        ret = 0;
2897
        goto endjob;
2898
    }
2899

2900
    configFile = virDomainConfigFile(cfg->configDir,
2901 2902
                                     vm->def->name);
    if (configFile == NULL)
2903
        goto endjob;
2904
    autostartLink = virDomainConfigFile(cfg->autostartDir,
2905 2906
                                        vm->def->name);
    if (autostartLink == NULL)
2907
        goto endjob;
2908

2909
    if (autostart) {
2910
        if (virFileMakePath(cfg->autostartDir) < 0) {
2911
            virReportSystemError(errno,
2912
                                 _("Cannot create autostart directory %s"),
2913
                                 cfg->autostartDir);
2914
            goto endjob;
2915 2916
        }

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

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

2935
 endjob:
2936 2937
    virLXCDomainObjEndJob(driver, vm);

2938
 cleanup:
2939 2940
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
2941
    virDomainObjEndAPI(&vm);
2942
    virObjectUnref(cfg);
2943 2944 2945
    return ret;
}

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

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

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

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

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

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

3027
 cleanup:
R
Ryota Ozaki 已提交
3028 3029 3030 3031 3032 3033
    VIR_FREE(state);
    return ret;
}

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

M
Michal Privoznik 已提交
3040
    if (!(vm = lxcDomObjFromDomain(dom)))
R
Ryota Ozaki 已提交
3041 3042
        goto cleanup;

3043 3044 3045
    if (virDomainSuspendEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3046 3047 3048
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

3049
    if (virDomainObjCheckActive(vm) < 0)
3050
        goto endjob;
R
Ryota Ozaki 已提交
3051

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

3060
        event = virDomainEventLifecycleNewFromObj(vm,
R
Ryota Ozaki 已提交
3061 3062 3063 3064
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
    }

3065
    if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0)
3066
        goto endjob;
R
Ryota Ozaki 已提交
3067 3068
    ret = 0;

3069
 endjob:
3070 3071
    virLXCDomainObjEndJob(driver, vm);

3072
 cleanup:
3073
    virObjectEventStateQueue(driver->domainEventState, event);
3074
    virDomainObjEndAPI(&vm);
3075
    virObjectUnref(cfg);
R
Ryota Ozaki 已提交
3076 3077 3078 3079 3080
    return ret;
}

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

M
Michal Privoznik 已提交
3089
    if (!(vm = lxcDomObjFromDomain(dom)))
R
Ryota Ozaki 已提交
3090 3091
        goto cleanup;

3092 3093
    priv = vm->privateData;

3094 3095 3096
    if (virDomainResumeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3097 3098 3099
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

3100
    if (virDomainObjCheckActive(vm) < 0)
3101
        goto endjob;
R
Ryota Ozaki 已提交
3102

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

3117
        event = virDomainEventLifecycleNewFromObj(vm,
R
Ryota Ozaki 已提交
3118 3119 3120 3121
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
    }

3122
    if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0)
3123
        goto endjob;
R
Ryota Ozaki 已提交
3124 3125
    ret = 0;

3126
 endjob:
3127 3128
    virLXCDomainObjEndJob(driver, vm);

3129
 cleanup:
3130
    virObjectEventStateQueue(driver->domainEventState, event);
3131
    virDomainObjEndAPI(&vm);
3132
    virObjectUnref(cfg);
R
Ryota Ozaki 已提交
3133 3134 3135
    return ret;
}

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

    virCheckFlags(0, -1);

M
Michal Privoznik 已提交
3149
    if (!(vm = lxcDomObjFromDomain(dom)))
3150 3151
        goto cleanup;

3152 3153 3154
    if (virDomainOpenConsoleEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3155
    if (virDomainObjCheckActive(vm) < 0)
3156 3157
        goto cleanup;

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

    if (!chr) {
3174 3175 3176
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot find console device '%s'"),
                       dev_name ? dev_name : _("default"));
3177 3178 3179
        goto cleanup;
    }

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

3187
    if (virFDStreamOpenFile(st, chr->source->data.file.path,
E
Eric Blake 已提交
3188
                            0, 0, O_RDWR) < 0)
3189 3190 3191
        goto cleanup;

    ret = 0;
3192
 cleanup:
3193
    virDomainObjEndAPI(&vm);
3194 3195 3196
    return ret;
}

3197 3198 3199 3200 3201 3202 3203

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

3222 3223
    priv = vm->privateData;

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

3227 3228 3229
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

3230
    if (virDomainObjCheckActive(vm) < 0)
3231
        goto endjob;
3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242

    /*
     * 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"));
3243
        goto endjob;
3244 3245 3246 3247 3248
    }

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

    ret = 0;

3265
 endjob:
3266
    virLXCDomainObjEndJob(driver, vm);
3267

3268
 cleanup:
3269
    virDomainObjEndAPI(&vm);
3270 3271 3272 3273
    return ret;
}


3274
static int
3275 3276
lxcConnectListAllDomains(virConnectPtr conn,
                         virDomainPtr **domains,
3277 3278
                  unsigned int flags)
{
3279
    virLXCDriverPtr driver = conn->privateData;
3280

O
Osier Yang 已提交
3281
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
3282

3283 3284 3285
    if (virConnectListAllDomainsEnsureACL(conn) < 0)
        return -1;

M
Michal Privoznik 已提交
3286 3287
    return virDomainObjListExport(driver->domains, conn, domains,
                                  virConnectListAllDomainsCheckACL, flags);
3288 3289
}

3290

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

    virCheckFlags(VIR_DOMAIN_SHUTDOWN_INITCTL |
                  VIR_DOMAIN_SHUTDOWN_SIGNAL, -1);

M
Michal Privoznik 已提交
3304
    if (!(vm = lxcDomObjFromDomain(dom)))
3305 3306 3307 3308
        goto cleanup;

    priv = vm->privateData;

3309
    if (virDomainShutdownFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
3310 3311
        goto cleanup;

3312 3313 3314
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

3315
    if (virDomainObjCheckActive(vm) < 0)
3316
        goto endjob;
3317 3318 3319 3320

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

3324 3325
    if (flags == 0 ||
        (flags & VIR_DOMAIN_SHUTDOWN_INITCTL)) {
3326 3327
        int command = VIR_INITCTL_RUNLEVEL_POWEROFF;

3328 3329 3330 3331 3332 3333 3334
        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;
            }
3335 3336
        }
    }
3337

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

    ret = 0;

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

3355
 cleanup:
3356
    virDomainObjEndAPI(&vm);
3357 3358 3359 3360 3361 3362 3363 3364 3365
    return ret;
}

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

3366

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

    virCheckFlags(VIR_DOMAIN_REBOOT_INITCTL |
                  VIR_DOMAIN_REBOOT_SIGNAL, -1);

M
Michal Privoznik 已提交
3380
    if (!(vm = lxcDomObjFromDomain(dom)))
3381 3382 3383 3384
        goto cleanup;

    priv = vm->privateData;

3385
    if (virDomainRebootEnsureACL(dom->conn, vm->def, flags) < 0)
3386 3387
        goto cleanup;

3388 3389 3390
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

3391
    if (virDomainObjCheckActive(vm) < 0)
3392
        goto endjob;
3393 3394 3395 3396

    if (priv->initpid == 0) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Init process ID is not yet known"));
3397
        goto endjob;
3398 3399 3400 3401
    }

    if (flags == 0 ||
        (flags & VIR_DOMAIN_REBOOT_INITCTL)) {
3402 3403
        int command = VIR_INITCTL_RUNLEVEL_REBOOT;

3404 3405 3406 3407 3408 3409 3410
        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;
            }
3411 3412 3413
        }
    }

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

    ret = 0;

3428
 endjob:
3429
    virLXCDomainObjEndJob(driver, vm);
3430

3431
 cleanup:
3432
    virDomainObjEndAPI(&vm);
3433 3434 3435 3436
    return ret;
}


3437
static int
3438
lxcDomainAttachDeviceConfig(virDomainDefPtr vmdef,
3439 3440 3441
                            virDomainDeviceDefPtr dev)
{
    int ret = -1;
3442
    virDomainDiskDefPtr disk;
3443
    virDomainNetDefPtr net;
3444
    virDomainHostdevDefPtr hostdev;
3445 3446

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

3461 3462
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
3463
        if (virDomainNetInsert(vmdef, net) < 0)
3464
            return -1;
3465 3466 3467 3468
        dev->data.net = NULL;
        ret = 0;
        break;

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

3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492
    default:
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                        _("persistent attach of device is not supported"));
         break;
    }

    return ret;
}


static int
3493
lxcDomainUpdateDeviceConfig(virDomainDefPtr vmdef,
3494 3495 3496
                            virDomainDeviceDefPtr dev)
{
    int ret = -1;
3497
    virDomainNetDefPtr net;
3498
    virDomainDeviceDef oldDev = { .type = dev->type };
3499
    int idx;
3500 3501

    switch (dev->type) {
3502 3503
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
3504
        if ((idx = virDomainNetFindIdx(vmdef, net)) < 0)
3505
            return -1;
3506

3507
        oldDev.data.net = vmdef->nets[idx];
3508
        if (virDomainDefCompatibleDevice(vmdef, dev, &oldDev,
3509 3510
                                         VIR_DOMAIN_DEVICE_ACTION_UPDATE,
                                         false) < 0)
3511
            return -1;
3512

3513 3514 3515 3516
        if (virDomainNetUpdate(vmdef, idx, net) < 0)
            return -1;

        virDomainNetDefFree(oldDev.data.net);
3517 3518 3519 3520 3521
        dev->data.net = NULL;
        ret = 0;

        break;

3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("persistent update of device is not supported"));
        break;
    }

    return ret;
}


static int
3533
lxcDomainDetachDeviceConfig(virDomainDefPtr vmdef,
3534 3535 3536
                            virDomainDeviceDefPtr dev)
{
    int ret = -1;
3537
    virDomainDiskDefPtr disk, det_disk;
3538
    virDomainNetDefPtr net;
3539
    virDomainHostdevDefPtr hostdev, det_hostdev;
3540
    int idx;
3541 3542

    switch (dev->type) {
3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553
    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;

3554 3555
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
3556
        if ((idx = virDomainNetFindIdx(vmdef, net)) < 0)
3557
            return -1;
3558

3559 3560 3561 3562 3563
        /* this is guaranteed to succeed */
        virDomainNetDefFree(virDomainNetRemove(vmdef, idx));
        ret = 0;
        break;

3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576
    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;
    }

3577 3578 3579 3580 3581 3582 3583 3584 3585 3586
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("persistent detach of device is not supported"));
        break;
    }

    return ret;
}


3587 3588 3589 3590 3591 3592 3593 3594 3595 3596
struct lxcDomainAttachDeviceMknodData {
    virLXCDriverPtr driver;
    mode_t mode;
    dev_t dev;
    virDomainObjPtr vm;
    virDomainDeviceDefPtr def;
    char *file;
};

static int
J
Ján Tomko 已提交
3597
lxcDomainAttachDeviceMknodHelper(pid_t pid G_GNUC_UNUSED,
3598 3599 3600 3601 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
                                 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;
3635 3636
        char *tmpsrc = def->src->path;
        def->src->path = data->file;
3637 3638 3639
        if (virSecurityManagerSetImageLabel(data->driver->securityManager,
                                            data->vm->def, def->src,
                                            VIR_SECURITY_DOMAIN_IMAGE_LABEL_BACKING_CHAIN) < 0) {
3640
            def->src->path = tmpsrc;
3641 3642
            goto cleanup;
        }
3643
        def->src->path = tmpsrc;
3644 3645
    }   break;

3646 3647 3648 3649 3650 3651 3652
    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;

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


3704
static int
J
Ján Tomko 已提交
3705
lxcDomainAttachDeviceUnlinkHelper(pid_t pid G_GNUC_UNUSED,
3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736
                                  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;
}


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

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

3756 3757 3758 3759 3760 3761
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        goto cleanup;
    }

3762 3763
    src = virDomainDiskGetSource(def);
    if (src == NULL) {
3764 3765 3766 3767 3768
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Can't setup disk without media"));
        goto cleanup;
    }

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

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

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

3787
    if (!S_ISBLK(sb.st_mode)) {
3788
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3789
                       _("Disk source %s must be a block device"),
3790
                       src);
3791 3792 3793
        goto cleanup;
    }

3794
    perms = (def->src->readonly ?
3795 3796 3797
             VIR_CGROUP_DEVICE_READ :
             VIR_CGROUP_DEVICE_RW) |
        VIR_CGROUP_DEVICE_MKNOD;
3798

3799 3800 3801 3802 3803
    if (virCgroupAllowDevice(priv->cgroup,
                             'b',
                             major(sb.st_rdev),
                             minor(sb.st_rdev),
                             perms) < 0)
3804
        goto cleanup;
3805

3806
    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks + 1) < 0)
3807 3808
        goto cleanup;

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

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

    virDomainDiskInsertPreAlloced(vm->def, def);

    ret = 0;

3831
 cleanup:
3832
    if (src)
3833
        virDomainAuditDisk(vm, NULL, def->src, "attach", ret == 0);
3834
    VIR_FREE(file);
3835 3836 3837 3838
    return ret;
}


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

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

3856 3857 3858
    if (virLXCProcessValidateInterface(net) < 0)
       return -1;

3859
    /* preallocate new slot for device */
3860
    if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets+1) < 0)
3861 3862 3863 3864 3865 3866
        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.
     */
3867 3868 3869 3870 3871 3872 3873 3874 3875 3876
    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);
    }
3877

3878 3879 3880 3881
    /* final validation now that actual type is known */
    if (virDomainActualNetDefValidate(net) < 0)
        return -1;

3882 3883 3884
    actualType = virDomainNetGetActualType(net);

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

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

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

    ret = 0;

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

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

3958 3959 3960 3961 3962 3963 3964 3965 3966
        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:
3967 3968 3969
        default:
            /* no-op */
            break;
3970 3971 3972 3973 3974 3975 3976
        }
    }

    return ret;
}


3977 3978 3979 3980 3981 3982 3983 3984 3985 3986
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;
3987
    virUSBDevicePtr usb = NULL;
3988
    virDomainHostdevSubsysUSBPtr usbsrc;
3989 3990 3991 3992 3993 3994 3995

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

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

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

4015 4016 4017
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0)
        goto cleanup;

4018
    if (virUSBDeviceFileIterate(usb,
4019
                                virLXCSetupHostUSBDeviceCgroup,
4020
                                priv->cgroup) < 0)
4021 4022
        goto cleanup;

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

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

4039 4040
    ret = 0;

4041
 cleanup:
4042
    virDomainAuditHostdev(vm, def, "attach", ret == 0);
4043
    virUSBDeviceFree(usb);
4044 4045 4046 4047 4048
    VIR_FREE(src);
    return ret;
}


4049 4050 4051 4052 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
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;
    }

4085
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0)
4086 4087
        goto cleanup;

4088 4089 4090 4091 4092
    if (virCgroupAllowDevice(priv->cgroup,
                             'b',
                             major(sb.st_rdev),
                             minor(sb.st_rdev),
                             VIR_CGROUP_DEVICE_RWM) < 0)
4093 4094
        goto cleanup;

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

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

    ret = 0;

4115
 cleanup:
4116 4117 4118 4119 4120
    virDomainAuditHostdev(vm, def, "attach", ret == 0);
    return ret;
}


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

4157 4158 4159 4160 4161
    if (virCgroupAllowDevice(priv->cgroup,
                             'c',
                             major(sb.st_rdev),
                             minor(sb.st_rdev),
                             VIR_CGROUP_DEVICE_RWM) < 0)
4162 4163
        goto cleanup;

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

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

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

    ret = 0;

4187
 cleanup:
4188 4189 4190 4191 4192
    virDomainAuditHostdev(vm, def, "attach", ret == 0);
    return ret;
}


4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210
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;
    }
}


4211 4212 4213 4214 4215 4216 4217 4218 4219
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);

4220 4221 4222
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC:
        return lxcDomainAttachDeviceHostdevMiscLive(driver, vm, dev);

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


4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244
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;
    }

4245 4246 4247 4248 4249 4250
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        return -1;
    }

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

4255 4256 4257
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
        return lxcDomainAttachDeviceHostdevCapsLive(driver, vm, dev);

4258 4259 4260 4261 4262 4263 4264 4265 4266
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported host device mode %s"),
                       virDomainHostdevModeTypeToString(dev->data.hostdev->mode));
        return -1;
    }
}


4267
static int
4268
lxcDomainAttachDeviceLive(virLXCDriverPtr driver,
4269
                          virDomainObjPtr vm,
4270 4271 4272 4273 4274
                          virDomainDeviceDefPtr dev)
{
    int ret = -1;

    switch (dev->type) {
4275 4276 4277 4278 4279 4280
    case VIR_DOMAIN_DEVICE_DISK:
        ret = lxcDomainAttachDeviceDiskLive(driver, vm, dev);
        if (!ret)
            dev->data.disk = NULL;
        break;

4281
    case VIR_DOMAIN_DEVICE_NET:
4282
        ret = lxcDomainAttachDeviceNetLive(driver, vm,
4283 4284 4285 4286 4287
                                           dev->data.net);
        if (!ret)
            dev->data.net = NULL;
        break;

4288 4289 4290
    case VIR_DOMAIN_DEVICE_HOSTDEV:
        ret = lxcDomainAttachDeviceHostdevLive(driver, vm, dev);
        if (!ret)
C
Chen Hanxiao 已提交
4291
            dev->data.hostdev = NULL;
4292 4293
        break;

4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("device type '%s' cannot be attached"),
                       virDomainDeviceTypeToString(dev->type));
        break;
    }

    return ret;
}


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

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

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

4329
    def = vm->def->disks[idx];
4330
    src = virDomainDiskGetSource(def);
4331

4332
    dst = g_strdup_printf("/dev/%s", def->dst);
4333

4334
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
4335 4336 4337 4338 4339
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        goto cleanup;
    }

4340
    if (lxcDomainAttachDeviceUnlink(vm, dst) < 0) {
4341
        virDomainAuditDisk(vm, def->src, NULL, "detach", false);
4342 4343
        goto cleanup;
    }
4344
    virDomainAuditDisk(vm, def->src, NULL, "detach", true);
4345

4346 4347
    if (virCgroupDenyDevicePath(priv->cgroup, src,
                                VIR_CGROUP_DEVICE_RWM, false) != 0)
4348 4349
        VIR_WARN("cannot deny device %s for domain %s: %s",
                 src, vm->def->name, virGetLastErrorMessage());
4350

4351
    virDomainDiskRemove(vm->def, idx);
4352 4353 4354 4355
    virDomainDiskDefFree(def);

    ret = 0;

4356
 cleanup:
4357 4358 4359 4360 4361
    VIR_FREE(dst);
    return ret;
}


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

4372
    if ((detachidx = virDomainNetFindIdx(vm->def, dev->data.net)) < 0)
4373
        goto cleanup;
4374

4375
    detach = vm->def->nets[detachidx];
4376 4377 4378
    actualType = virDomainNetGetActualType(detach);

    /* clear network bandwidth */
4379 4380
    if (virDomainNetGetActualBandwidth(detach) &&
        virNetDevSupportBandwidth(actualType) &&
4381 4382
        virNetDevBandwidthClear(detach->ifname))
        goto cleanup;
4383

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

    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;
4428
 cleanup:
4429
    if (!ret) {
4430
        virErrorPreserveLast(&save_err);
4431 4432 4433 4434 4435 4436 4437 4438 4439
        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));
            }
        }
4440 4441
        virDomainNetRemove(vm->def, detachidx);
        virDomainNetDefFree(detach);
4442
        virErrorRestore(&save_err);
4443 4444 4445 4446 4447
    }
    return ret;
}


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

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

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

4472
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
4473 4474 4475 4476 4477
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("devices cgroup isn't mounted"));
        goto cleanup;
    }

4478
    if (!(usb = virUSBDeviceNew(usbsrc->bus, usbsrc->device, NULL)))
4479 4480
        goto cleanup;

4481
    if (lxcDomainAttachDeviceUnlink(vm, dst) < 0) {
4482 4483 4484 4485 4486
        virDomainAuditHostdev(vm, def, "detach", false);
        goto cleanup;
    }
    virDomainAuditHostdev(vm, def, "detach", true);

4487
    if (virUSBDeviceFileIterate(usb,
4488
                                virLXCTeardownHostUSBDeviceCgroup,
4489
                                priv->cgroup) < 0)
4490 4491
        VIR_WARN("cannot deny device %s for domain %s: %s",
                 dst, vm->def->name, virGetLastErrorMessage());
4492

4493 4494 4495
    virObjectLock(hostdev_mgr->activeUSBHostdevs);
    virUSBDeviceListDel(hostdev_mgr->activeUSBHostdevs, usb);
    virObjectUnlock(hostdev_mgr->activeUSBHostdevs);
4496 4497 4498 4499 4500 4501

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

    ret = 0;

4502
 cleanup:
4503
    virUSBDeviceFree(usb);
4504 4505 4506 4507
    VIR_FREE(dst);
    return ret;
}

4508 4509

static int
4510
lxcDomainDetachDeviceHostdevStorageLive(virDomainObjPtr vm,
4511 4512 4513 4514
                                        virDomainDeviceDefPtr dev)
{
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virDomainHostdevDefPtr def = NULL;
4515
    int idx;
4516 4517 4518 4519

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

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

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

4538
    if (lxcDomainAttachDeviceUnlink(vm, def->source.caps.u.storage.block) < 0) {
4539
        virDomainAuditHostdev(vm, def, "detach", false);
4540
        return -1;
4541 4542 4543
    }
    virDomainAuditHostdev(vm, def, "detach", true);

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

4549
    virDomainHostdevRemove(vm->def, idx);
4550 4551
    virDomainHostdevDefFree(def);

4552
    return 0;
4553 4554 4555
}


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

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

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

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

4585
    if (lxcDomainAttachDeviceUnlink(vm, def->source.caps.u.misc.chardev) < 0) {
4586
        virDomainAuditHostdev(vm, def, "detach", false);
4587
        return -1;
4588 4589 4590
    }
    virDomainAuditHostdev(vm, def, "detach", true);

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

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

4599
    return 0;
4600 4601 4602
}


4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620
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;
    }
}


4621
static int
4622 4623
lxcDomainDetachDeviceHostdevCapsLive(virDomainObjPtr vm,
                                     virDomainDeviceDefPtr dev)
4624 4625 4626
{
    switch (dev->data.hostdev->source.caps.type) {
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
4627
        return lxcDomainDetachDeviceHostdevStorageLive(vm, dev);
4628

4629
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC:
4630
        return lxcDomainDetachDeviceHostdevMiscLive(vm, dev);
4631

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


4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657
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);

4658
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
4659
        return lxcDomainDetachDeviceHostdevCapsLive(vm, dev);
4660

4661 4662 4663 4664 4665 4666 4667 4668 4669
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported host device mode %s"),
                       virDomainHostdevModeTypeToString(dev->data.hostdev->mode));
        return -1;
    }
}


4670 4671 4672
static int
lxcDomainDetachDeviceLive(virLXCDriverPtr driver,
                          virDomainObjPtr vm,
4673 4674 4675 4676 4677
                          virDomainDeviceDefPtr dev)
{
    int ret = -1;

    switch (dev->type) {
4678
    case VIR_DOMAIN_DEVICE_DISK:
4679
        ret = lxcDomainDetachDeviceDiskLive(vm, dev);
4680 4681
        break;

4682 4683 4684 4685
    case VIR_DOMAIN_DEVICE_NET:
        ret = lxcDomainDetachDeviceNetLive(vm, dev);
        break;

4686 4687 4688 4689
    case VIR_DOMAIN_DEVICE_HOSTDEV:
        ret = lxcDomainDetachDeviceHostdevLive(driver, vm, dev);
        break;

4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("device type '%s' cannot be detached"),
                       virDomainDeviceTypeToString(dev->type));
        break;
    }

    return ret;
}


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

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
4713
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
4714

M
Michal Privoznik 已提交
4715
    if (!(vm = lxcDomObjFromDomain(dom)))
4716 4717
        goto cleanup;

4718 4719 4720
    if (virDomainAttachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4721
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
4722 4723
        goto cleanup;

4724
    if (virDomainObjUpdateModificationImpact(vm, &flags) < 0)
4725
        goto endjob;
4726

4727
    dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
4728
                                             driver->xmlopt, NULL,
4729
                                             VIR_DOMAIN_DEF_PARSE_INACTIVE);
4730
    if (dev == NULL)
4731
        goto endjob;
4732 4733 4734 4735 4736 4737 4738

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

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        /* Make a copy for updated domain. */
4747
        vmdef = virDomainObjCopyPersistentDef(vm, driver->xmlopt, NULL);
4748
        if (!vmdef)
4749
            goto endjob;
4750

4751
        if (virDomainDefCompatibleDevice(vmdef, dev, NULL,
4752 4753
                                         VIR_DOMAIN_DEVICE_ACTION_ATTACH,
                                         false) < 0)
4754
            goto endjob;
4755

4756
        if ((ret = lxcDomainAttachDeviceConfig(vmdef, dev)) < 0)
4757
            goto endjob;
4758 4759 4760
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
4761
        if (virDomainDefCompatibleDevice(vm->def, dev_copy, NULL,
4762 4763
                                         VIR_DOMAIN_DEVICE_ACTION_ATTACH,
                                         true) < 0)
4764
            goto endjob;
4765

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

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

4788
 endjob:
4789 4790
    virLXCDomainObjEndJob(driver, vm);

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

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
4822
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
4823

M
Michal Privoznik 已提交
4824
    if (!(vm = lxcDomObjFromDomain(dom)))
4825 4826
        goto cleanup;

4827 4828 4829
    if (virDomainUpdateDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4830
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
4831
        goto cleanup;
4832

4833 4834 4835
    if (virDomainObjUpdateModificationImpact(vm, &flags) < 0)
        goto endjob;

4836 4837 4838
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("Unable to modify live devices"));
4839
        goto endjob;
4840
    }
4841

4842
    if (!(dev = virDomainDeviceDefParse(xml, vm->def, driver->xmlopt, NULL,
4843 4844
                                        VIR_DOMAIN_DEF_PARSE_INACTIVE)))
        goto endjob;
4845

4846
    /* Make a copy for updated domain. */
4847
    if (!(vmdef = virDomainObjCopyPersistentDef(vm, driver->xmlopt, NULL)))
4848
        goto endjob;
4849

4850 4851 4852 4853
    /* virDomainDefCompatibleDevice call is delayed until we know the
     * device we're going to update. */
    if (lxcDomainUpdateDeviceConfig(vmdef, dev) < 0)
        goto endjob;
4854

4855
    if (virDomainDefSave(vmdef, driver->xmlopt, cfg->configDir) < 0)
4856
        goto endjob;
4857

4858 4859 4860 4861
    virDomainObjAssignDef(vm, vmdef, false, NULL);
    vmdef = NULL;
    ret = 0;

4862
 endjob:
4863 4864
    virLXCDomainObjEndJob(driver, vm);

4865
 cleanup:
4866 4867
    virDomainDefFree(vmdef);
    virDomainDeviceDefFree(dev);
4868
    virDomainObjEndAPI(&vm);
4869
    virObjectUnref(cfg);
4870
    return ret;
4871 4872 4873 4874 4875 4876 4877
}


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

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

M
Michal Privoznik 已提交
4889
    if (!(vm = lxcDomObjFromDomain(dom)))
4890 4891
        goto cleanup;

4892 4893 4894
    if (virDomainDetachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4895
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
4896
        goto cleanup;
4897

4898 4899 4900
    if (virDomainObjUpdateModificationImpact(vm, &flags) < 0)
        goto endjob;

4901
    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
4902
        goto endjob;
4903

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

    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,
4918
                                          driver->xmlopt, NULL);
4919
        if (!dev_copy)
4920
            goto endjob;
4921 4922 4923 4924
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        /* Make a copy for updated domain. */
4925
        vmdef = virDomainObjCopyPersistentDef(vm, driver->xmlopt, NULL);
4926
        if (!vmdef)
4927
            goto endjob;
4928 4929

        if ((ret = lxcDomainDetachDeviceConfig(vmdef, dev)) < 0)
4930
            goto endjob;
4931 4932 4933 4934
    }

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

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

4956
 endjob:
4957 4958
    virLXCDomainObjEndJob(driver, vm);

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


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


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

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

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

4995 4996
    priv = vm->privateData;

4997 4998 4999
    if (virDomainLxcOpenNamespaceEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

5003
    if (virDomainObjCheckActive(vm) < 0)
5004
        goto endjob;
5005 5006 5007 5008

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

    if (virProcessGetNamespaces(priv->initpid, &nfds, fdlist) < 0)
5013
        goto endjob;
5014 5015

    ret = nfds;
5016 5017

 endjob:
5018
    virLXCDomainObjEndJob(driver, vm);
5019

5020
 cleanup:
5021
    virDomainObjEndAPI(&vm);
5022 5023 5024 5025
    return ret;
}


5026
static char *
5027
lxcConnectGetSysinfo(virConnectPtr conn, unsigned int flags)
5028 5029 5030 5031 5032 5033
{
    virLXCDriverPtr driver = conn->privateData;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    virCheckFlags(0, NULL);

5034 5035 5036
    if (virConnectGetSysinfoEnsureACL(conn) < 0)
        return NULL;

5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048
    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);
}


5049
static int
5050
lxcNodeGetInfo(virConnectPtr conn,
5051 5052
               virNodeInfoPtr nodeinfo)
{
5053 5054 5055
    if (virNodeGetInfoEnsureACL(conn) < 0)
        return -1;

M
Martin Kletzander 已提交
5056
    return virCapabilitiesGetNodeInfo(nodeinfo);
5057 5058 5059
}


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

    virCheckFlags(0, -1);

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

    priv = vm->privateData;

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

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

5086
    if (virDomainObjCheckActive(vm) < 0)
5087
        goto endjob;
5088

5089
    if (virCgroupGetMemSwapUsage(priv->cgroup, &swap_usage) < 0)
5090
        goto endjob;
5091

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

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

5112
 endjob:
5113 5114
    virLXCDomainObjEndJob(driver, vm);

5115
 cleanup:
5116
    virDomainObjEndAPI(&vm);
5117 5118 5119 5120
    return ret;
}


5121
static int
5122
lxcNodeGetCPUStats(virConnectPtr conn,
5123 5124 5125 5126 5127
                   int cpuNum,
                   virNodeCPUStatsPtr params,
                   int *nparams,
                   unsigned int flags)
{
5128 5129 5130
    if (virNodeGetCPUStatsEnsureACL(conn) < 0)
        return -1;

5131
    return virHostCPUGetStats(cpuNum, params, nparams, flags);
5132 5133 5134 5135
}


static int
5136
lxcNodeGetMemoryStats(virConnectPtr conn,
5137 5138 5139 5140 5141
                      int cellNum,
                      virNodeMemoryStatsPtr params,
                      int *nparams,
                      unsigned int flags)
{
5142 5143 5144
    if (virNodeGetMemoryStatsEnsureACL(conn) < 0)
        return -1;

5145
    return virHostMemGetStats(cellNum, params, nparams, flags);
5146 5147 5148 5149
}


static int
5150
lxcNodeGetCellsFreeMemory(virConnectPtr conn,
5151 5152 5153 5154
                          unsigned long long *freeMems,
                          int startCell,
                          int maxCells)
{
5155 5156 5157
    if (virNodeGetCellsFreeMemoryEnsureACL(conn) < 0)
        return -1;

5158
    return virHostMemGetCellsFree(freeMems, startCell, maxCells);
5159 5160 5161 5162
}


static unsigned long long
5163
lxcNodeGetFreeMemory(virConnectPtr conn)
5164
{
5165 5166
    unsigned long long freeMem;

5167 5168 5169
    if (virNodeGetFreeMemoryEnsureACL(conn) < 0)
        return 0;

5170
    if (virHostMemGetInfo(NULL, &freeMem) < 0)
5171 5172 5173
        return 0;

    return freeMem;
5174 5175 5176 5177
}


static int
5178
lxcNodeGetMemoryParameters(virConnectPtr conn,
5179 5180 5181 5182
                           virTypedParameterPtr params,
                           int *nparams,
                           unsigned int flags)
{
5183 5184 5185
    if (virNodeGetMemoryParametersEnsureACL(conn) < 0)
        return -1;

5186
    return virHostMemGetParameters(params, nparams, flags);
5187 5188 5189 5190
}


static int
5191
lxcNodeSetMemoryParameters(virConnectPtr conn,
5192 5193 5194 5195
                           virTypedParameterPtr params,
                           int nparams,
                           unsigned int flags)
{
5196 5197 5198
    if (virNodeSetMemoryParametersEnsureACL(conn) < 0)
        return -1;

5199
    return virHostMemSetParameters(params, nparams, flags);
5200 5201 5202 5203
}


static int
5204
lxcNodeGetCPUMap(virConnectPtr conn,
5205 5206 5207 5208
                 unsigned char **cpumap,
                 unsigned int *online,
                 unsigned int flags)
{
5209 5210 5211
    if (virNodeGetCPUMapEnsureACL(conn) < 0)
        return -1;

5212
    return virHostCPUGetMap(cpumap, online, flags);
5213 5214
}

5215 5216

static int
5217
lxcNodeSuspendForDuration(virConnectPtr conn,
5218 5219 5220 5221
                          unsigned int target,
                          unsigned long long duration,
                          unsigned int flags)
{
5222 5223 5224
    if (virNodeSuspendForDurationEnsureACL(conn) < 0)
        return -1;

5225
    return virNodeSuspend(target, duration, flags);
5226 5227 5228
}


5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252
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;

5253 5254 5255
    if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
        goto cleanup;

5256
    ret = virDomainObjSetMetadata(vm, type, metadata, key, uri,
5257 5258
                                  driver->xmlopt, cfg->stateDir,
                                  cfg->configDir, flags);
5259

5260 5261 5262 5263 5264 5265
    if (ret == 0) {
        virObjectEventPtr ev = NULL;
        ev = virDomainEventMetadataChangeNewFromObj(vm, type, uri);
        virObjectEventStateQueue(driver->domainEventState, ev);
    }

5266
    virLXCDomainObjEndJob(driver, vm);
5267

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

5290
    ret = virDomainObjGetMetadata(vm, type, uri, flags);
5291

5292
 cleanup:
5293
    virDomainObjEndAPI(&vm);
5294 5295 5296 5297
    return ret;
}


5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319
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;

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


5341 5342 5343 5344 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
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;
}


5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432
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;

5433
    return virHostMemGetFreePages(npages, pages, startCell, cellCount, counts);
5434 5435 5436
}


5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452
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;

5453 5454
    return virHostMemAllocPages(npages, pageSizes, pageCounts,
                                startCell, cellCount, add);
5455 5456 5457
}


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


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

5578
static virConnectDriver lxcConnectDriver = {
5579
    .localOnly = true,
5580
    .uriSchemes = (const char *[]){ "lxc", NULL },
5581 5582 5583
    .hypervisorDriver = &lxcHypervisorDriver,
};

5584
static virStateDriver lxcStateDriver = {
5585
    .name = LXC_DRIVER_NAME,
5586 5587 5588
    .stateInitialize = lxcStateInitialize,
    .stateCleanup = lxcStateCleanup,
    .stateReload = lxcStateReload,
5589 5590
};

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