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

#include <config.h>

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

38
#include "virterror_internal.h"
39
#include "logging.h"
40
#include "datatypes.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_process.h"
46
#include "memory.h"
47
#include "util.h"
48
#include "virnetdevbridge.h"
49
#include "virnetdevveth.h"
50
#include "nodeinfo.h"
51
#include "uuid.h"
52
#include "stats_linux.h"
53
#include "hooks.h"
E
Eric Blake 已提交
54
#include "virfile.h"
55
#include "virpidfile.h"
56
#include "fdstream.h"
57
#include "domain_audit.h"
58
#include "domain_nwfilter.h"
59
#include "network/bridge_driver.h"
60
#include "virnetdev.h"
A
Ansis Atteka 已提交
61
#include "virnetdevtap.h"
62
#include "virnodesuspend.h"
63
#include "virtime.h"
64
#include "virtypedparam.h"
M
Martin Kletzander 已提交
65
#include "viruri.h"
66
#include "virdomainlist.h"
D
Daniel Veillard 已提交
67

68 69
#define VIR_FROM_THIS VIR_FROM_LXC

70

71 72
#define LXC_NB_MEM_PARAM  3

73
static int lxcStartup(int privileged);
74
static int lxcShutdown(void);
75
virLXCDriverPtr lxc_driver = NULL;
D
Daniel Veillard 已提交
76 77 78 79 80

/* Functions */

static virDrvOpenStatus lxcOpen(virConnectPtr conn,
                                virConnectAuthPtr auth ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
81
                                unsigned int flags)
D
Daniel Veillard 已提交
82
{
E
Eric Blake 已提交
83 84
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

D
Daniel Veillard 已提交
85
    /* Verify uri was specified */
86
    if (conn->uri == NULL) {
87 88
        if (lxc_driver == NULL)
            return VIR_DRV_OPEN_DECLINED;
89

90
        if (!(conn->uri = virURIParse("lxc:///")))
91
            return VIR_DRV_OPEN_ERROR;
92 93 94 95 96 97 98 99 100 101
    } else {
        if (conn->uri->scheme == NULL ||
            STRNEQ(conn->uri->scheme, "lxc"))
            return VIR_DRV_OPEN_DECLINED;

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

        /* If path isn't '/' then they typoed, tell them correct path */
102 103
        if (conn->uri->path != NULL &&
            STRNEQ(conn->uri->path, "/")) {
104
            lxcError(VIR_ERR_INTERNAL_ERROR,
105
                     _("Unexpected LXC URI path '%s', try lxc:///"),
106 107 108
                     conn->uri->path);
            return VIR_DRV_OPEN_ERROR;
        }
D
Daniel Veillard 已提交
109

110 111
        /* URI was good, but driver isn't active */
        if (lxc_driver == NULL) {
112
            lxcError(VIR_ERR_INTERNAL_ERROR,
113
                     "%s", _("lxc state driver is not active"));
114 115 116
            return VIR_DRV_OPEN_ERROR;
        }
    }
117

118
    conn->privateData = lxc_driver;
D
Daniel Veillard 已提交
119 120 121 122 123 124

    return VIR_DRV_OPEN_SUCCESS;
}

static int lxcClose(virConnectPtr conn)
{
125
    virLXCDriverPtr driver = conn->privateData;
126 127

    lxcDriverLock(driver);
128
    virLXCProcessAutoDestroyRun(driver, conn);
129 130
    lxcDriverUnlock(driver);

131 132
    conn->privateData = NULL;
    return 0;
D
Daniel Veillard 已提交
133 134
}

135 136 137 138 139 140 141 142 143 144 145 146 147 148 149

static int lxcIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    /* Trivially secure, since always inside the daemon */
    return 1;
}


static int lxcIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    /* Not encrypted, but remote driver takes care of that */
    return 0;
}


150 151 152 153 154 155
static int lxcIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    return 1;
}


156
static char *lxcGetCapabilities(virConnectPtr conn) {
157
    virLXCDriverPtr driver = conn->privateData;
158 159 160 161
    char *xml;

    lxcDriverLock(driver);
    if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
162
        virReportOOMError();
163 164 165 166 167 168
    lxcDriverUnlock(driver);

    return xml;
}


D
Daniel Veillard 已提交
169 170 171
static virDomainPtr lxcDomainLookupByID(virConnectPtr conn,
                                        int id)
{
172
    virLXCDriverPtr driver = conn->privateData;
173 174
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
175

176
    lxcDriverLock(driver);
177
    vm = virDomainFindByID(&driver->domains, id);
178 179
    lxcDriverUnlock(driver);

D
Daniel Veillard 已提交
180
    if (!vm) {
181 182
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching id %d"), id);
183
        goto cleanup;
D
Daniel Veillard 已提交
184 185 186
    }

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
187
    if (dom)
D
Daniel Veillard 已提交
188 189
        dom->id = vm->def->id;

190
cleanup:
191 192
    if (vm)
        virDomainObjUnlock(vm);
D
Daniel Veillard 已提交
193 194 195 196 197 198
    return dom;
}

static virDomainPtr lxcDomainLookupByUUID(virConnectPtr conn,
                                          const unsigned char *uuid)
{
199
    virLXCDriverPtr driver = conn->privateData;
200 201
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
202

203
    lxcDriverLock(driver);
204
    vm = virDomainFindByUUID(&driver->domains, uuid);
205 206
    lxcDriverUnlock(driver);

D
Daniel Veillard 已提交
207
    if (!vm) {
208 209 210 211
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
212
        goto cleanup;
D
Daniel Veillard 已提交
213 214 215
    }

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
216
    if (dom)
D
Daniel Veillard 已提交
217 218
        dom->id = vm->def->id;

219
cleanup:
220 221
    if (vm)
        virDomainObjUnlock(vm);
D
Daniel Veillard 已提交
222 223 224 225 226 227
    return dom;
}

static virDomainPtr lxcDomainLookupByName(virConnectPtr conn,
                                          const char *name)
{
228
    virLXCDriverPtr driver = conn->privateData;
229 230
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
231

232
    lxcDriverLock(driver);
233
    vm = virDomainFindByName(&driver->domains, name);
234
    lxcDriverUnlock(driver);
D
Daniel Veillard 已提交
235
    if (!vm) {
236 237
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching name '%s'"), name);
238
        goto cleanup;
D
Daniel Veillard 已提交
239 240 241
    }

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
242
    if (dom)
D
Daniel Veillard 已提交
243 244
        dom->id = vm->def->id;

245
cleanup:
246 247
    if (vm)
        virDomainObjUnlock(vm);
D
Daniel Veillard 已提交
248 249 250
    return dom;
}

251 252 253

static int lxcDomainIsActive(virDomainPtr dom)
{
254
    virLXCDriverPtr driver = dom->conn->privateData;
255 256 257 258 259 260 261
    virDomainObjPtr obj;
    int ret = -1;

    lxcDriverLock(driver);
    obj = virDomainFindByUUID(&driver->domains, dom->uuid);
    lxcDriverUnlock(driver);
    if (!obj) {
262 263 264 265
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
266 267 268 269 270 271 272 273 274 275 276 277 278
        goto cleanup;
    }
    ret = virDomainObjIsActive(obj);

cleanup:
    if (obj)
        virDomainObjUnlock(obj);
    return ret;
}


static int lxcDomainIsPersistent(virDomainPtr dom)
{
279
    virLXCDriverPtr driver = dom->conn->privateData;
280 281 282 283 284 285 286
    virDomainObjPtr obj;
    int ret = -1;

    lxcDriverLock(driver);
    obj = virDomainFindByUUID(&driver->domains, dom->uuid);
    lxcDriverUnlock(driver);
    if (!obj) {
287 288 289 290
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
291 292 293 294 295 296 297 298 299 300
        goto cleanup;
    }
    ret = obj->persistent;

cleanup:
    if (obj)
        virDomainObjUnlock(obj);
    return ret;
}

301 302
static int lxcDomainIsUpdated(virDomainPtr dom)
{
303
    virLXCDriverPtr driver = dom->conn->privateData;
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
    virDomainObjPtr obj;
    int ret = -1;

    lxcDriverLock(driver);
    obj = virDomainFindByUUID(&driver->domains, dom->uuid);
    lxcDriverUnlock(driver);
    if (!obj) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }
    ret = obj->updated;

cleanup:
    if (obj)
        virDomainObjUnlock(obj);
    return ret;
}
324

325
static int lxcListDomains(virConnectPtr conn, int *ids, int nids) {
326
    virLXCDriverPtr driver = conn->privateData;
327
    int n;
328

329
    lxcDriverLock(driver);
330
    n = virDomainObjListGetActiveIDs(&driver->domains, ids, nids);
331
    lxcDriverUnlock(driver);
332

333
    return n;
D
Daniel Veillard 已提交
334
}
335

336
static int lxcNumDomains(virConnectPtr conn) {
337
    virLXCDriverPtr driver = conn->privateData;
338
    int n;
339

340
    lxcDriverLock(driver);
341
    n = virDomainObjListNumOfDomains(&driver->domains, 1);
342
    lxcDriverUnlock(driver);
343

344
    return n;
D
Daniel Veillard 已提交
345 346 347
}

static int lxcListDefinedDomains(virConnectPtr conn,
348
                                 char **const names, int nnames) {
349
    virLXCDriverPtr driver = conn->privateData;
350
    int n;
351

352
    lxcDriverLock(driver);
353
    n = virDomainObjListGetInactiveNames(&driver->domains, names, nnames);
354
    lxcDriverUnlock(driver);
355

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


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

364
    lxcDriverLock(driver);
365
    n = virDomainObjListNumOfDomains(&driver->domains, 0);
366
    lxcDriverUnlock(driver);
367

368
    return n;
D
Daniel Veillard 已提交
369 370
}

371 372


D
Daniel Veillard 已提交
373 374
static virDomainPtr lxcDomainDefine(virConnectPtr conn, const char *xml)
{
375
    virLXCDriverPtr driver = conn->privateData;
376
    virDomainDefPtr def = NULL;
377
    virDomainObjPtr vm = NULL;
378
    virDomainPtr dom = NULL;
379
    virDomainEventPtr event = NULL;
380
    int dupVM;
D
Daniel Veillard 已提交
381

382
    lxcDriverLock(driver);
383
    if (!(def = virDomainDefParseString(driver->caps, xml,
M
Matthias Bolte 已提交
384
                                        1 << VIR_DOMAIN_VIRT_LXC,
385
                                        VIR_DOMAIN_XML_INACTIVE)))
386
        goto cleanup;
D
Daniel Veillard 已提交
387

388 389 390
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
        goto cleanup;

M
Matthias Bolte 已提交
391
    if ((dupVM = virDomainObjIsDuplicate(&driver->domains, def, 0)) < 0)
392
        goto cleanup;
393

394
    if ((def->nets != NULL) && !(driver->have_netns)) {
395
        lxcError(VIR_ERR_OPERATION_INVALID,
J
Jim Meyering 已提交
396
                 "%s", _("System lacks NETNS support"));
397
        goto cleanup;
398 399
    }

400
    if (!(vm = virDomainAssignDef(driver->caps,
401
                                  &driver->domains, def, false)))
402 403
        goto cleanup;
    def = NULL;
404
    vm->persistent = 1;
D
Daniel Veillard 已提交
405

406
    if (virDomainSaveConfig(driver->configDir,
407
                            vm->newDef ? vm->newDef : vm->def) < 0) {
408
        virDomainRemoveInactive(&driver->domains, vm);
409
        vm = NULL;
410
        goto cleanup;
D
Daniel Veillard 已提交
411 412
    }

413 414
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
415
                                     !dupVM ?
416 417 418
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);

D
Daniel Veillard 已提交
419
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
420
    if (dom)
D
Daniel Veillard 已提交
421 422
        dom->id = vm->def->id;

423 424
cleanup:
    virDomainDefFree(def);
425 426
    if (vm)
        virDomainObjUnlock(vm);
427
    if (event)
428
        virDomainEventStateQueue(driver->domainEventState, event);
429
    lxcDriverUnlock(driver);
D
Daniel Veillard 已提交
430 431 432
    return dom;
}

433 434
static int lxcDomainUndefineFlags(virDomainPtr dom,
                                  unsigned int flags)
D
Daniel Veillard 已提交
435
{
436
    virLXCDriverPtr driver = dom->conn->privateData;
437
    virDomainObjPtr vm;
438
    virDomainEventPtr event = NULL;
439
    int ret = -1;
D
Daniel Veillard 已提交
440

441 442
    virCheckFlags(0, -1);

443
    lxcDriverLock(driver);
444
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
D
Daniel Veillard 已提交
445
    if (!vm) {
446 447 448 449
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
450
        goto cleanup;
D
Daniel Veillard 已提交
451 452
    }

453
    if (!vm->persistent) {
454
        lxcError(VIR_ERR_OPERATION_INVALID,
455
                 "%s", _("Cannot undefine transient domain"));
456
        goto cleanup;
457
    }
D
Daniel Veillard 已提交
458

459
    if (virDomainDeleteConfig(driver->configDir,
460
                              driver->autostartDir,
461 462
                              vm) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
463

464 465 466 467
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_UNDEFINED,
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);

468 469 470 471 472 473 474
    if (virDomainObjIsActive(vm)) {
        vm->persistent = 0;
    } else {
        virDomainRemoveInactive(&driver->domains, vm);
        vm = NULL;
    }

475
    ret = 0;
D
Daniel Veillard 已提交
476

477
cleanup:
478 479
    if (vm)
        virDomainObjUnlock(vm);
480
    if (event)
481
        virDomainEventStateQueue(driver->domainEventState, event);
482
    lxcDriverUnlock(driver);
483
    return ret;
D
Daniel Veillard 已提交
484 485
}

486 487 488 489 490
static int lxcDomainUndefine(virDomainPtr dom)
{
    return lxcDomainUndefineFlags(dom, 0);
}

D
Daniel Veillard 已提交
491 492 493
static int lxcDomainGetInfo(virDomainPtr dom,
                            virDomainInfoPtr info)
{
494
    virLXCDriverPtr driver = dom->conn->privateData;
495
    virDomainObjPtr vm;
496
    virCgroupPtr cgroup = NULL;
497
    int ret = -1, rc;
D
Daniel Veillard 已提交
498

499
    lxcDriverLock(driver);
500
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
501

D
Daniel Veillard 已提交
502
    if (!vm) {
503 504 505 506
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
507
        goto cleanup;
D
Daniel Veillard 已提交
508 509
    }

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

D
Daniel P. Berrange 已提交
512
    if (!virDomainObjIsActive(vm) || driver->cgroup == NULL) {
D
Daniel Veillard 已提交
513
        info->cpuTime = 0;
514
        info->memory = vm->def->mem.cur_balloon;
D
Daniel Veillard 已提交
515
    } else {
516
        if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) {
517
            lxcError(VIR_ERR_INTERNAL_ERROR,
518
                     _("Unable to get cgroup for %s"), vm->def->name);
519 520 521 522
            goto cleanup;
        }

        if (virCgroupGetCpuacctUsage(cgroup, &(info->cpuTime)) < 0) {
523
            lxcError(VIR_ERR_OPERATION_FAILED,
524
                     "%s", _("Cannot read cputime for domain"));
R
Ryota Ozaki 已提交
525 526
            goto cleanup;
        }
527
        if ((rc = virCgroupGetMemoryUsage(cgroup, &(info->memory))) < 0) {
528
            lxcError(VIR_ERR_OPERATION_FAILED,
529
                     "%s", _("Cannot read memory usage for domain"));
530 531 532 533 534 535
            if (rc == -ENOENT) {
                /* Don't fail if we can't read memory usage due to a lack of
                 * kernel support */
                info->memory = 0;
            } else
                goto cleanup;
536
        }
D
Daniel Veillard 已提交
537 538
    }

539
    info->maxMem = vm->def->mem.max_balloon;
540
    info->nrVirtCpu = vm->def->vcpus;
541
    ret = 0;
D
Daniel Veillard 已提交
542

543
cleanup:
544
    lxcDriverUnlock(driver);
545 546
    if (cgroup)
        virCgroupFree(&cgroup);
547 548
    if (vm)
        virDomainObjUnlock(vm);
549
    return ret;
D
Daniel Veillard 已提交
550 551
}

552 553 554 555 556 557
static int
lxcDomainGetState(virDomainPtr dom,
                  int *state,
                  int *reason,
                  unsigned int flags)
{
558
    virLXCDriverPtr driver = dom->conn->privateData;
559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    lxcDriverUnlock(driver);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

J
Jiri Denemark 已提交
576
    *state = virDomainObjGetState(vm, reason);
577 578 579 580 581 582 583 584
    ret = 0;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

585
static char *lxcGetOSType(virDomainPtr dom)
D
Daniel Veillard 已提交
586
{
587
    virLXCDriverPtr driver = dom->conn->privateData;
588 589
    virDomainObjPtr vm;
    char *ret = NULL;
590

591
    lxcDriverLock(driver);
592
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
593 594
    lxcDriverUnlock(driver);

595
    if (!vm) {
596 597 598 599
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
600
        goto cleanup;
601 602
    }

603 604
    ret = strdup(vm->def->os.type);

605
    if (ret == NULL)
606
        virReportOOMError();
607

608
cleanup:
609 610
    if (vm)
        virDomainObjUnlock(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)
{
618
    virLXCDriverPtr driver = dom->conn->privateData;
R
Ryota Ozaki 已提交
619
    virDomainObjPtr vm;
620
    unsigned long long ret = 0;
R
Ryota Ozaki 已提交
621 622 623 624 625 626 627 628

    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    lxcDriverUnlock(driver);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
629
        lxcError(VIR_ERR_NO_DOMAIN,
630
                         _("No domain with matching uuid '%s'"), uuidstr);
R
Ryota Ozaki 已提交
631 632 633
        goto cleanup;
    }

634
    ret = vm->def->mem.max_balloon;
R
Ryota Ozaki 已提交
635 636 637 638 639 640 641 642

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

static int lxcDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax) {
643
    virLXCDriverPtr driver = dom->conn->privateData;
R
Ryota Ozaki 已提交
644 645 646 647 648 649 650 651 652 653
    virDomainObjPtr vm;
    int ret = -1;

    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    lxcDriverUnlock(driver);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
654
        lxcError(VIR_ERR_NO_DOMAIN,
655
                         _("No domain with matching uuid '%s'"), uuidstr);
R
Ryota Ozaki 已提交
656 657 658
        goto cleanup;
    }

659
    if (newmax < vm->def->mem.cur_balloon) {
660
        lxcError(VIR_ERR_INVALID_ARG,
661
                         "%s", _("Cannot set max memory lower than current memory"));
R
Ryota Ozaki 已提交
662 663 664
        goto cleanup;
    }

665
    vm->def->mem.max_balloon = newmax;
R
Ryota Ozaki 已提交
666 667 668 669 670 671 672 673 674
    ret = 0;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

static int lxcDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
675
    virLXCDriverPtr driver = dom->conn->privateData;
R
Ryota Ozaki 已提交
676 677 678 679 680 681 682 683 684 685
    virDomainObjPtr vm;
    virCgroupPtr cgroup = NULL;
    int ret = -1;

    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    lxcDriverUnlock(driver);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
686
        lxcError(VIR_ERR_NO_DOMAIN,
687
                 _("No domain with matching uuid '%s'"), uuidstr);
R
Ryota Ozaki 已提交
688 689 690
        goto cleanup;
    }

691
    if (newmem > vm->def->mem.max_balloon) {
692
        lxcError(VIR_ERR_INVALID_ARG,
693
                 "%s", _("Cannot set memory higher than max memory"));
R
Ryota Ozaki 已提交
694 695 696
        goto cleanup;
    }

697 698 699 700 701
    if (!virDomainObjIsActive(vm)) {
        lxcError(VIR_ERR_OPERATION_INVALID,
                 "%s", _("Domain is not running"));
        goto cleanup;
    }
702

703
    if (driver->cgroup == NULL) {
704
        lxcError(VIR_ERR_OPERATION_INVALID,
705 706 707
                 "%s", _("cgroups must be configured on the host"));
        goto cleanup;
    }
R
Ryota Ozaki 已提交
708

709 710 711 712
    if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) {
        lxcError(VIR_ERR_INTERNAL_ERROR,
                 _("Unable to get cgroup for %s"), vm->def->name);
        goto cleanup;
R
Ryota Ozaki 已提交
713
    }
714 715 716 717 718 719 720

    if (virCgroupSetMemory(cgroup, newmem) < 0) {
        lxcError(VIR_ERR_OPERATION_FAILED,
                 "%s", _("Failed to set memory for domain"));
        goto cleanup;
    }

R
Ryota Ozaki 已提交
721 722 723 724 725 726 727 728 729 730
    ret = 0;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    if (cgroup)
        virCgroupFree(&cgroup);
    return ret;
}

731 732 733 734 735
static int
lxcDomainSetMemoryParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int nparams,
                             unsigned int flags)
736
{
737
    virLXCDriverPtr driver = dom->conn->privateData;
738 739 740 741
    int i;
    virCgroupPtr cgroup = NULL;
    virDomainObjPtr vm = NULL;
    int ret = -1;
742
    int rc;
743

E
Eric Blake 已提交
744
    virCheckFlags(0, -1);
745 746 747 748 749 750 751 752 753
    if (virTypedParameterArrayValidate(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)
        return -1;
E
Eric Blake 已提交
754

755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773
    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) {
        lxcError(VIR_ERR_INTERNAL_ERROR,
                 _("cannot find cgroup for domain %s"), vm->def->name);
        goto cleanup;
    }

    ret = 0;
    for (i = 0; i < nparams; i++) {
774
        virTypedParameterPtr param = &params[i];
775 776 777 778 779 780 781 782 783 784 785 786 787 788 789

        if (STREQ(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT)) {
            rc = virCgroupSetMemoryHardLimit(cgroup, params[i].value.ul);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to set memory hard_limit tunable"));
                ret = -1;
            }
        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT)) {
            rc = virCgroupSetMemorySoftLimit(cgroup, params[i].value.ul);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to set memory soft_limit tunable"));
                ret = -1;
            }
790
        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT)) {
791
            rc = virCgroupSetMemSwapHardLimit(cgroup, params[i].value.ul);
792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to set swap_hard_limit tunable"));
                ret = -1;
            }
        }
    }

cleanup:
    if (cgroup)
        virCgroupFree(&cgroup);
    if (vm)
        virDomainObjUnlock(vm);
    lxcDriverUnlock(driver);
    return ret;
}

809 810 811 812 813
static int
lxcDomainGetMemoryParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int *nparams,
                             unsigned int flags)
814
{
815
    virLXCDriverPtr driver = dom->conn->privateData;
816 817 818
    int i;
    virCgroupPtr cgroup = NULL;
    virDomainObjPtr vm = NULL;
819
    unsigned long long val;
820 821 822
    int ret = -1;
    int rc;

E
Eric Blake 已提交
823 824
    virCheckFlags(0, -1);

825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848
    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    if ((*nparams) == 0) {
        /* Current number of memory parameters supported by cgroups */
        *nparams = LXC_NB_MEM_PARAM;
        ret = 0;
        goto cleanup;
    }

    if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) {
        lxcError(VIR_ERR_INTERNAL_ERROR,
                 _("Unable to get cgroup for %s"), vm->def->name);
        goto cleanup;
    }

849
    for (i = 0; i < LXC_NB_MEM_PARAM && i < *nparams; i++) {
850
        virTypedParameterPtr param = &params[i];
851 852 853 854 855 856 857 858
        val = 0;

        switch(i) {
        case 0: /* fill memory hard limit here */
            rc = virCgroupGetMemoryHardLimit(cgroup, &val);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get memory hard limit"));
859
                goto cleanup;
860
            }
861 862
            if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_HARD_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
863
                goto cleanup;
864 865 866 867 868 869
            break;
        case 1: /* fill memory soft limit here */
            rc = virCgroupGetMemorySoftLimit(cgroup, &val);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get memory soft limit"));
870
                goto cleanup;
871
            }
872 873
            if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_SOFT_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
874
                goto cleanup;
875 876
            break;
        case 2: /* fill swap hard limit here */
877
            rc = virCgroupGetMemSwapHardLimit(cgroup, &val);
878 879 880
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get swap hard limit"));
881
                goto cleanup;
882
            }
883 884 885
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
886
                goto cleanup;
887 888 889 890 891 892 893 894
            break;

        default:
            break;
            /* should not hit here */
        }
    }

895 896
    if (*nparams > LXC_NB_MEM_PARAM)
        *nparams = LXC_NB_MEM_PARAM;
897 898
    ret = 0;

899 900 901 902 903 904 905 906 907
cleanup:
    if (cgroup)
        virCgroupFree(&cgroup);
    if (vm)
        virDomainObjUnlock(vm);
    lxcDriverUnlock(driver);
    return ret;
}

908
static char *lxcDomainGetXMLDesc(virDomainPtr dom,
909
                                 unsigned int flags)
D
Daniel Veillard 已提交
910
{
911
    virLXCDriverPtr driver = dom->conn->privateData;
912 913
    virDomainObjPtr vm;
    char *ret = NULL;
D
Daniel Veillard 已提交
914

915 916
    /* Flags checked by virDomainDefFormat */

917
    lxcDriverLock(driver);
918
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
919 920
    lxcDriverUnlock(driver);

D
Daniel Veillard 已提交
921
    if (!vm) {
922 923 924 925
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
926
        goto cleanup;
D
Daniel Veillard 已提交
927 928
    }

929
    ret = virDomainDefFormat((flags & VIR_DOMAIN_XML_INACTIVE) &&
930 931 932 933
                             vm->newDef ? vm->newDef : vm->def,
                             flags);

cleanup:
934 935
    if (vm)
        virDomainObjUnlock(vm);
936
    return ret;
D
Daniel Veillard 已提交
937 938
}

939

940
/**
941
 * lxcDomainStartWithFlags:
942
 * @dom: domain to start
943
 * @flags: Must be 0 for now
944 945 946 947 948
 *
 * Looks up domain and starts it.
 *
 * Returns 0 on success or -1 in case of error
 */
949
static int lxcDomainStartWithFlags(virDomainPtr dom, unsigned int flags)
950
{
951
    virLXCDriverPtr driver = dom->conn->privateData;
952
    virDomainObjPtr vm;
953
    virDomainEventPtr event = NULL;
954
    int ret = -1;
955

956
    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, -1);
957

958
    lxcDriverLock(driver);
959
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
960
    if (!vm) {
961 962 963 964
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
965 966 967
        goto cleanup;
    }

968
    if ((vm->def->nets != NULL) && !(driver->have_netns)) {
969
        lxcError(VIR_ERR_OPERATION_INVALID,
J
Jim Meyering 已提交
970
                 "%s", _("System lacks NETNS support"));
971 972 973
        goto cleanup;
    }

974 975 976 977 978 979
    if (virDomainObjIsActive(vm)) {
        lxcError(VIR_ERR_OPERATION_INVALID,
                 "%s", _("Domain is already running"));
        goto cleanup;
    }

980 981 982
    ret = virLXCProcessStart(dom->conn, driver, vm,
                             (flags & VIR_DOMAIN_START_AUTODESTROY),
                             VIR_DOMAIN_RUNNING_BOOTED);
983

984
    if (ret == 0) {
985 986 987
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STARTED,
                                         VIR_DOMAIN_EVENT_STARTED_BOOTED);
988 989 990 991
        virDomainAuditStart(vm, "booted", true);
    } else {
        virDomainAuditStart(vm, "booted", false);
    }
992

993
cleanup:
994 995
    if (vm)
        virDomainObjUnlock(vm);
996
    if (event)
997
        virDomainEventStateQueue(driver->domainEventState, event);
998
    lxcDriverUnlock(driver);
999
    return ret;
1000 1001
}

1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014
/**
 * lxcDomainStart:
 * @dom: domain to start
 *
 * Looks up domain and starts it.
 *
 * Returns 0 on success or -1 in case of error
 */
static int lxcDomainStart(virDomainPtr dom)
{
    return lxcDomainStartWithFlags(dom, 0);
}

1015 1016 1017 1018
/**
 * lxcDomainCreateAndStart:
 * @conn: pointer to connection
 * @xml: XML definition of domain
1019
 * @flags: Must be 0 for now
1020 1021 1022 1023 1024 1025 1026 1027
 *
 * Creates a domain based on xml and starts it
 *
 * Returns 0 on success or -1 in case of error
 */
static virDomainPtr
lxcDomainCreateAndStart(virConnectPtr conn,
                        const char *xml,
1028
                        unsigned int flags) {
1029
    virLXCDriverPtr driver = conn->privateData;
1030
    virDomainObjPtr vm = NULL;
1031
    virDomainDefPtr def;
1032
    virDomainPtr dom = NULL;
1033
    virDomainEventPtr event = NULL;
1034

1035
    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, NULL);
1036

1037
    lxcDriverLock(driver);
1038
    if (!(def = virDomainDefParseString(driver->caps, xml,
M
Matthias Bolte 已提交
1039
                                        1 << VIR_DOMAIN_VIRT_LXC,
1040
                                        VIR_DOMAIN_XML_INACTIVE)))
1041
        goto cleanup;
1042

1043 1044 1045
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
        goto cleanup;

1046 1047
    if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
        goto cleanup;
1048

1049
    if ((def->nets != NULL) && !(driver->have_netns)) {
1050
        lxcError(VIR_ERR_CONFIG_UNSUPPORTED,
J
Jim Meyering 已提交
1051
                 "%s", _("System lacks NETNS support"));
1052
        goto cleanup;
1053 1054
    }

1055

1056
    if (!(vm = virDomainAssignDef(driver->caps,
1057
                                  &driver->domains, def, false)))
1058 1059
        goto cleanup;
    def = NULL;
1060

1061 1062 1063
    if (virLXCProcessStart(conn, driver, vm,
                           (flags & VIR_DOMAIN_START_AUTODESTROY),
                           VIR_DOMAIN_RUNNING_BOOTED) < 0) {
1064
        virDomainAuditStart(vm, "booted", false);
1065
        virDomainRemoveInactive(&driver->domains, vm);
1066
        vm = NULL;
1067
        goto cleanup;
1068 1069
    }

1070 1071 1072
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
1073
    virDomainAuditStart(vm, "booted", true);
1074

1075
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1076
    if (dom)
1077 1078
        dom->id = vm->def->id;

1079 1080
cleanup:
    virDomainDefFree(def);
1081 1082
    if (vm)
        virDomainObjUnlock(vm);
1083
    if (event)
1084
        virDomainEventStateQueue(driver->domainEventState, event);
1085
    lxcDriverUnlock(driver);
1086 1087 1088
    return dom;
}

1089

1090 1091
static int lxcDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr seclabel)
{
1092
    virLXCDriverPtr driver = dom->conn->privateData;
1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150
    virDomainObjPtr vm;
    int ret = -1;

    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

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

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    if (!virDomainVirtTypeToString(vm->def->virtType)) {
        lxcError(VIR_ERR_INTERNAL_ERROR,
                 _("unknown virt type in domain definition '%d'"),
                 vm->def->virtType);
        goto cleanup;
    }

    /*
     * Theoretically, the pid can be replaced during this operation and
     * return the label of a different process.  If atomicity is needed,
     * further validation will be required.
     *
     * Comment from Dan Berrange:
     *
     *   Well the PID as stored in the virDomainObjPtr can't be changed
     *   because you've got a locked object.  The OS level PID could have
     *   exited, though and in extreme circumstances have cycled through all
     *   PIDs back to ours. We could sanity check that our PID still exists
     *   after reading the label, by checking that our FD connecting to the
     *   LXC monitor hasn't seen SIGHUP/ERR on poll().
     */
    if (virDomainObjIsActive(vm)) {
        if (virSecurityManagerGetProcessLabel(driver->securityManager,
                                              vm->def, vm->pid, seclabel) < 0) {
            lxcError(VIR_ERR_INTERNAL_ERROR,
                     "%s", _("Failed to get security label"));
            goto cleanup;
        }
    }

    ret = 0;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    lxcDriverUnlock(driver);
    return ret;
}

static int lxcNodeGetSecurityModel(virConnectPtr conn,
                                   virSecurityModelPtr secmodel)
{
1151
    virLXCDriverPtr driver = conn->privateData;
1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185
    int ret = 0;

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

    /* NULL indicates no driver, which we treat as
     * success, but simply return no data in *secmodel */
    if (driver->caps->host.secModel.model == NULL)
        goto cleanup;

    if (!virStrcpy(secmodel->model, driver->caps->host.secModel.model,
                   VIR_SECURITY_MODEL_BUFLEN)) {
        lxcError(VIR_ERR_INTERNAL_ERROR,
                 _("security model string exceeds max %d bytes"),
                 VIR_SECURITY_MODEL_BUFLEN - 1);
        ret = -1;
        goto cleanup;
    }

    if (!virStrcpy(secmodel->doi, driver->caps->host.secModel.doi,
                   VIR_SECURITY_DOI_BUFLEN)) {
        lxcError(VIR_ERR_INTERNAL_ERROR,
                 _("security DOI string exceeds max %d bytes"),
                 VIR_SECURITY_DOI_BUFLEN-1);
        ret = -1;
        goto cleanup;
    }

cleanup:
    lxcDriverUnlock(driver);
    return ret;
}


1186
static int
1187 1188 1189 1190
lxcDomainEventRegister(virConnectPtr conn,
                       virConnectDomainEventCallback callback,
                       void *opaque,
                       virFreeCallback freecb)
1191
{
1192
    virLXCDriverPtr driver = conn->privateData;
1193 1194 1195
    int ret;

    lxcDriverLock(driver);
1196 1197 1198
    ret = virDomainEventStateRegister(conn,
                                      driver->domainEventState,
                                      callback, opaque, freecb);
1199
    lxcDriverUnlock(driver);
1200

1201
    return ret;
1202 1203
}

1204

1205
static int
1206 1207
lxcDomainEventDeregister(virConnectPtr conn,
                         virConnectDomainEventCallback callback)
1208
{
1209
    virLXCDriverPtr driver = conn->privateData;
1210 1211 1212
    int ret;

    lxcDriverLock(driver);
1213 1214 1215
    ret = virDomainEventStateDeregister(conn,
                                        driver->domainEventState,
                                        callback);
1216 1217 1218 1219 1220
    lxcDriverUnlock(driver);

    return ret;
}

1221 1222 1223 1224 1225 1226 1227 1228 1229

static int
lxcDomainEventRegisterAny(virConnectPtr conn,
                          virDomainPtr dom,
                          int eventID,
                          virConnectDomainEventGenericCallback callback,
                          void *opaque,
                          virFreeCallback freecb)
{
1230
    virLXCDriverPtr driver = conn->privateData;
1231 1232 1233
    int ret;

    lxcDriverLock(driver);
1234 1235 1236 1237
    if (virDomainEventStateRegisterID(conn,
                                      driver->domainEventState,
                                      dom, eventID,
                                      callback, opaque, freecb, &ret) < 0)
1238
        ret = -1;
1239 1240 1241 1242 1243 1244 1245 1246 1247 1248
    lxcDriverUnlock(driver);

    return ret;
}


static int
lxcDomainEventDeregisterAny(virConnectPtr conn,
                            int callbackID)
{
1249
    virLXCDriverPtr driver = conn->privateData;
1250 1251 1252
    int ret;

    lxcDriverLock(driver);
1253 1254 1255
    ret = virDomainEventStateDeregisterID(conn,
                                          driver->domainEventState,
                                          callbackID);
1256 1257 1258 1259 1260 1261
    lxcDriverUnlock(driver);

    return ret;
}


1262
/**
1263
 * lxcDomainDestroyFlags:
1264
 * @dom: pointer to domain to destroy
1265
 * @flags: an OR'ed set of virDomainDestroyFlags
1266 1267 1268 1269 1270
 *
 * Sends SIGKILL to container root process to terminate the container
 *
 * Returns 0 on success or -1 in case of error
 */
1271 1272 1273
static int
lxcDomainDestroyFlags(virDomainPtr dom,
                      unsigned int flags)
1274
{
1275
    virLXCDriverPtr driver = dom->conn->privateData;
1276
    virDomainObjPtr vm;
1277
    virDomainEventPtr event = NULL;
1278
    int ret = -1;
1279

1280 1281
    virCheckFlags(0, -1);

1282
    lxcDriverLock(driver);
1283
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1284
    if (!vm) {
1285 1286 1287 1288
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
1289
        goto cleanup;
1290 1291
    }

1292 1293 1294 1295 1296 1297
    if (!virDomainObjIsActive(vm)) {
        lxcError(VIR_ERR_OPERATION_INVALID,
                 "%s", _("Domain is not running"));
        goto cleanup;
    }

1298
    ret = virLXCProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED);
1299 1300 1301
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
1302
    virDomainAuditStop(vm, "destroyed");
1303 1304 1305 1306
    if (!vm->persistent) {
        virDomainRemoveInactive(&driver->domains, vm);
        vm = NULL;
    }
1307 1308

cleanup:
1309 1310
    if (vm)
        virDomainObjUnlock(vm);
1311
    if (event)
1312
        virDomainEventStateQueue(driver->domainEventState, event);
1313
    lxcDriverUnlock(driver);
1314
    return ret;
1315
}
1316

1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330
/**
 * 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);
}

1331 1332 1333 1334 1335
static int lxcCheckNetNsSupport(void)
{
    const char *argv[] = {"ip", "link", "set", "lo", "netns", "-1", NULL};
    int ip_rc;

1336
    if (virRun(argv, &ip_rc) < 0 ||
1337 1338
        !(WIFEXITED(ip_rc) && (WEXITSTATUS(ip_rc) != 255)))
        return 0;
1339

1340 1341
    if (lxcContainerAvailable(LXC_CONTAINER_FEATURE_NET) < 0)
        return 0;
1342

1343
    return 1;
1344 1345
}

1346

1347
static int
1348
lxcSecurityInit(virLXCDriverPtr driver)
1349
{
1350
    VIR_INFO("lxcSecurityInit %s", driver->securityDriverName);
1351
    virSecurityManagerPtr mgr = virSecurityManagerNew(driver->securityDriverName,
1352
                                                      LXC_DRIVER_NAME,
1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369
                                                      false,
                                                      driver->securityDefaultConfined,
                                                      driver->securityRequireConfined);
    if (!mgr)
        goto error;

    driver->securityManager = mgr;

    return 0;

error:
    VIR_ERROR(_("Failed to initialize security drivers"));
    virSecurityManagerFree(mgr);
    return -1;
}


1370
static int lxcStartup(int privileged)
D
Daniel Veillard 已提交
1371
{
1372
    char *ld;
1373
    int rc;
1374 1375 1376 1377 1378 1379

    /* Valgrind gets very annoyed when we clone containers, so
     * disable LXC when under valgrind
     * XXX remove this when valgrind is fixed
     */
    ld = getenv("LD_PRELOAD");
1380
    if (ld && strstr(ld, "vgpreload")) {
1381
        VIR_INFO("Running under valgrind, disabling driver");
1382 1383
        return 0;
    }
1384

1385
    /* Check that the user is root, silently disable if not */
1386
    if (!privileged) {
1387
        VIR_INFO("Not running privileged, disabling driver");
1388 1389 1390 1391 1392
        return 0;
    }

    /* Check that this is a container enabled kernel */
    if (lxcContainerAvailable(0) < 0) {
1393
        VIR_INFO("LXC support not available in this kernel, disabling driver");
1394
        return 0;
1395 1396
    }

1397
    if (VIR_ALLOC(lxc_driver) < 0) {
1398 1399
        return -1;
    }
1400 1401 1402 1403
    if (virMutexInit(&lxc_driver->lock) < 0) {
        VIR_FREE(lxc_driver);
        return -1;
    }
1404
    lxcDriverLock(lxc_driver);
D
Daniel Veillard 已提交
1405

1406 1407 1408
    if (virDomainObjListInit(&lxc_driver->domains) < 0)
        goto cleanup;

1409
    lxc_driver->domainEventState = virDomainEventStateNew();
1410
    if (!lxc_driver->domainEventState)
1411 1412
        goto cleanup;

A
Amy Griffis 已提交
1413
    lxc_driver->log_libvirtd = 0; /* by default log to container logfile */
1414
    lxc_driver->have_netns = lxcCheckNetNsSupport();
D
Daniel Veillard 已提交
1415

1416 1417
    rc = virCgroupForDriver("lxc", &lxc_driver->cgroup, privileged, 1);
    if (rc < 0) {
1418
        char buf[1024] ATTRIBUTE_UNUSED;
1419 1420 1421 1422 1423
        VIR_DEBUG("Unable to create cgroup for LXC driver: %s",
                  virStrerror(-rc, buf, sizeof(buf)));
        /* Don't abort startup. We will explicitly report to
         * the user when they try to start a VM
         */
1424 1425
    }

D
Daniel Veillard 已提交
1426
    /* Call function to load lxc driver configuration information */
1427 1428
    if (lxcLoadDriverConfig(lxc_driver) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
1429

1430 1431 1432 1433
    if (lxcSecurityInit(lxc_driver) < 0)
        goto cleanup;

    if ((lxc_driver->caps = lxcCapsInit(lxc_driver)) == NULL)
1434
        goto cleanup;
D
Daniel Veillard 已提交
1435

1436
    virLXCDomainSetPrivateDataHooks(lxc_driver->caps);
1437

1438
    if (virLXCProcessAutoDestroyInit(lxc_driver) < 0)
1439 1440
        goto cleanup;

O
Osier Yang 已提交
1441 1442 1443 1444 1445
    /* Get all the running persistent or transient configs first */
    if (virDomainLoadAllConfigs(lxc_driver->caps,
                                &lxc_driver->domains,
                                lxc_driver->stateDir,
                                NULL,
M
Matthias Bolte 已提交
1446 1447
                                1, 1 << VIR_DOMAIN_VIRT_LXC,
                                NULL, NULL) < 0)
O
Osier Yang 已提交
1448 1449
        goto cleanup;

1450
    virLXCProcessReconnectAll(lxc_driver, &lxc_driver->domains);
O
Osier Yang 已提交
1451 1452

    /* Then inactive persistent configs */
1453
    if (virDomainLoadAllConfigs(lxc_driver->caps,
1454 1455
                                &lxc_driver->domains,
                                lxc_driver->configDir,
1456
                                lxc_driver->autostartDir,
M
Matthias Bolte 已提交
1457 1458
                                0, 1 << VIR_DOMAIN_VIRT_LXC,
                                NULL, NULL) < 0)
1459
        goto cleanup;
1460

1461
    lxcDriverUnlock(lxc_driver);
1462

1463
    virLXCProcessAutostartAll(lxc_driver);
1464

D
Daniel Veillard 已提交
1465 1466
    return 0;

1467 1468 1469 1470
cleanup:
    lxcDriverUnlock(lxc_driver);
    lxcShutdown();
    return -1;
D
Daniel Veillard 已提交
1471 1472
}

1473 1474
static void lxcNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
{
1475
    virLXCDriverPtr driver = opaque;
1476 1477 1478 1479 1480 1481 1482

    if (newVM) {
        virDomainEventPtr event =
            virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED);
        if (event)
1483
            virDomainEventStateQueue(driver->domainEventState, event);
1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498
    }
}

/**
 * lxcReload:
 *
 * Function to restart the LXC driver, it will recheck the configuration
 * files and perform autostart
 */
static int
lxcReload(void) {
    if (!lxc_driver)
        return 0;

    lxcDriverLock(lxc_driver);
1499
    virDomainLoadAllConfigs(lxc_driver->caps,
1500 1501 1502
                            &lxc_driver->domains,
                            lxc_driver->configDir,
                            lxc_driver->autostartDir,
M
Matthias Bolte 已提交
1503 1504
                            0, 1 << VIR_DOMAIN_VIRT_LXC,
                            lxcNotifyLoadDomain, lxc_driver);
1505 1506 1507 1508 1509
    lxcDriverUnlock(lxc_driver);

    return 0;
}

1510
static int lxcShutdown(void)
D
Daniel Veillard 已提交
1511
{
1512
    if (lxc_driver == NULL)
1513
        return -1;
1514

1515
    lxcDriverLock(lxc_driver);
1516
    virDomainObjListDeinit(&lxc_driver->domains);
1517
    virDomainEventStateFree(lxc_driver->domainEventState);
1518

1519
    virLXCProcessAutoDestroyShutdown(lxc_driver);
1520

1521
    virCapabilitiesFree(lxc_driver->caps);
1522
    virSecurityManagerFree(lxc_driver->securityManager);
1523 1524 1525 1526 1527
    VIR_FREE(lxc_driver->configDir);
    VIR_FREE(lxc_driver->autostartDir);
    VIR_FREE(lxc_driver->stateDir);
    VIR_FREE(lxc_driver->logDir);
    lxcDriverUnlock(lxc_driver);
1528
    virMutexDestroy(&lxc_driver->lock);
1529
    VIR_FREE(lxc_driver);
1530 1531 1532

    return 0;
}
D
Daniel Veillard 已提交
1533

1534 1535 1536 1537 1538 1539 1540 1541 1542
/**
 * lxcActive:
 *
 * Checks if the LXC daemon is active, i.e. has an active domain
 *
 * Returns 1 if active, 0 otherwise
 */
static int
lxcActive(void) {
1543
    int active;
1544

1545
    if (lxc_driver == NULL)
1546
        return 0;
1547

1548
    lxcDriverLock(lxc_driver);
1549
    active = virDomainObjListNumOfDomains(&lxc_driver->domains, 1);
1550
    lxcDriverUnlock(lxc_driver);
1551

1552
    return active;
D
Daniel Veillard 已提交
1553 1554
}

1555
static int lxcVersion(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *version)
D
Dan Smith 已提交
1556 1557 1558
{
    struct utsname ver;

1559
    uname(&ver);
D
Dan Smith 已提交
1560

1561
    if (virParseVersionString(ver.release, version, true) < 0) {
1562
        lxcError(VIR_ERR_INTERNAL_ERROR, _("Unknown release: %s"), ver.release);
D
Dan Smith 已提交
1563 1564 1565 1566 1567
        return -1;
    }

    return 0;
}
1568

1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602

/*
 * check whether the host supports CFS bandwidth
 *
 * Return 1 when CFS bandwidth is supported, 0 when CFS bandwidth is not
 * supported, -1 on error.
 */
static int lxcGetCpuBWStatus(virCgroupPtr cgroup)
{
    char *cfs_period_path = NULL;
    int ret = -1;

    if (!cgroup)
        return 0;

    if (virCgroupPathOfController(cgroup, VIR_CGROUP_CONTROLLER_CPU,
                                  "cpu.cfs_period_us", &cfs_period_path) < 0) {
        VIR_INFO("cannot get the path of cgroup CPU controller");
        ret = 0;
        goto cleanup;
    }

    if (access(cfs_period_path, F_OK) < 0) {
        ret = 0;
    } else {
        ret = 1;
    }

cleanup:
    VIR_FREE(cfs_period_path);
    return ret;
}


1603
static bool lxcCgroupControllerActive(virLXCDriverPtr driver,
1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621
                                      int controller)
{
    if (driver->cgroup == NULL)
        return false;
    if (controller < 0 || controller >= VIR_CGROUP_CONTROLLER_LAST)
        return false;
    if (!virCgroupMounted(driver->cgroup, controller))
        return false;
#if 0
    if (driver->cgroupControllers & (1 << controller))
        return true;
#endif
    return false;
}



static char *lxcGetSchedulerType(virDomainPtr domain,
1622
                                 int *nparams)
1623
{
1624
    virLXCDriverPtr driver = domain->conn->privateData;
1625 1626
    char *ret = NULL;
    int rc;
1627

1628 1629 1630 1631 1632 1633
    lxcDriverLock(driver);
    if (!lxcCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
        lxcError(VIR_ERR_OPERATION_INVALID,
                 "%s", _("cgroup CPU controller is not mounted"));
        goto cleanup;
    }
1634

1635 1636 1637 1638 1639 1640 1641 1642 1643
    if (nparams) {
        rc = lxcGetCpuBWStatus(driver->cgroup);
        if (rc < 0)
            goto cleanup;
        else if (rc == 0)
            *nparams = 1;
        else
            *nparams = 3;
    }
1644

1645 1646
    ret = strdup("posix");
    if (!ret)
1647
        virReportOOMError();
1648

1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719
cleanup:
    lxcDriverUnlock(driver);
    return ret;
}


static int
lxcGetVcpuBWLive(virCgroupPtr cgroup, unsigned long long *period,
                 long long *quota)
{
    int rc;

    rc = virCgroupGetCpuCfsPeriod(cgroup, period);
    if (rc < 0) {
        virReportSystemError(-rc, "%s",
                             _("unable to get cpu bandwidth period tunable"));
        return -1;
    }

    rc = virCgroupGetCpuCfsQuota(cgroup, quota);
    if (rc < 0) {
        virReportSystemError(-rc, "%s",
                             _("unable to get cpu bandwidth tunable"));
        return -1;
    }

    return 0;
}


static int lxcSetVcpuBWLive(virCgroupPtr cgroup, unsigned long long period,
                            long long quota)
{
    int rc;
    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 */
        rc = virCgroupGetCpuCfsPeriod(cgroup, &old_period);
        if (rc < 0) {
            virReportSystemError(-rc,
                                 "%s", _("Unable to get cpu bandwidth period"));
            return -1;
        }

        rc = virCgroupSetCpuCfsPeriod(cgroup, period);
        if (rc < 0) {
            virReportSystemError(-rc,
                                 "%s", _("Unable to set cpu bandwidth period"));
            return -1;
        }
    }

    if (quota) {
        rc = virCgroupSetCpuCfsQuota(cgroup, quota);
        if (rc < 0) {
            virReportSystemError(-rc,
                                 "%s", _("Unable to set cpu bandwidth quota"));
            goto cleanup;
        }
    }

    return 0;

cleanup:
    if (period) {
        rc = virCgroupSetCpuCfsPeriod(cgroup, old_period);
        if (rc < 0)
1720 1721
            virReportSystemError(-rc, "%s",
                                 _("Unable to rollback cpu bandwidth period"));
1722 1723 1724
    }

    return -1;
1725 1726
}

1727

1728
static int
1729
lxcSetSchedulerParametersFlags(virDomainPtr dom,
1730 1731 1732
                               virTypedParameterPtr params,
                               int nparams,
                               unsigned int flags)
1733
{
1734
    virLXCDriverPtr driver = dom->conn->privateData;
1735
    int i;
1736 1737
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
1738
    virDomainDefPtr vmdef = NULL;
1739
    int ret = -1;
1740
    int rc;
1741

1742 1743
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
1744 1745 1746 1747 1748 1749 1750 1751 1752
    if (virTypedParameterArrayValidate(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)
        return -1;
1753 1754

    lxcDriverLock(driver);
1755 1756

    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1757

1758
    if (vm == NULL) {
1759 1760
        lxcError(VIR_ERR_INTERNAL_ERROR,
                 _("No such domain %s"), dom->uuid);
1761
        goto cleanup;
1762 1763
    }

E
Eric Blake 已提交
1764 1765 1766
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &vmdef) < 0)
        goto cleanup;
1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        /* Make a copy for updated domain. */
        vmdef = virDomainObjCopyPersistentDef(driver->caps, vm);
        if (!vmdef)
            goto cleanup;
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (!lxcCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
            lxcError(VIR_ERR_OPERATION_INVALID,
                     "%s", _("cgroup CPU controller is not mounted"));
            goto cleanup;
        }
        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
            lxcError(VIR_ERR_INTERNAL_ERROR,
                     _("cannot find cgroup for domain %s"),
                     vm->def->name);
            goto cleanup;
        }
    }
1788 1789

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

1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832
        if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_CPU_SHARES)) {
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
                rc = virCgroupSetCpuShares(group, params[i].value.ul);
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to set cpu shares tunable"));
                    goto cleanup;
                }

                vm->def->cputune.shares = params[i].value.ul;
            }

            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
                vmdef->cputune.shares = params[i].value.ul;
            }
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_PERIOD)) {
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
                rc = lxcSetVcpuBWLive(group, params[i].value.ul, 0);
                if (rc != 0)
                    goto cleanup;

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

            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
                vmdef->cputune.period = params[i].value.ul;
            }
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_QUOTA)) {
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
                rc = lxcSetVcpuBWLive(group, 0, params[i].value.l);
                if (rc != 0)
                    goto cleanup;

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

            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
                vmdef->cputune.quota = params[i].value.l;
            }
1833
        }
1834
    }
1835

1836 1837
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
        goto cleanup;
1838

1839 1840 1841 1842

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        rc = virDomainSaveConfig(driver->configDir, vmdef);
        if (rc < 0)
1843
            goto cleanup;
1844

1845 1846
        virDomainObjAssignDef(vm, vmdef, false);
        vmdef = NULL;
1847
    }
1848

1849
    ret = 0;
1850

1851
cleanup:
1852
    virDomainDefFree(vmdef);
1853
    virCgroupFree(&group);
1854 1855
    if (vm)
        virDomainObjUnlock(vm);
1856
    lxcDriverUnlock(driver);
1857
    return ret;
1858 1859
}

1860 1861 1862 1863 1864 1865 1866 1867 1868
static int
lxcSetSchedulerParameters(virDomainPtr domain,
                          virTypedParameterPtr params,
                          int nparams)
{
    return lxcSetSchedulerParametersFlags(domain, params, nparams, 0);
}

static int
1869
lxcGetSchedulerParametersFlags(virDomainPtr dom,
1870 1871 1872
                               virTypedParameterPtr params,
                               int *nparams,
                               unsigned int flags)
1873
{
1874
    virLXCDriverPtr driver = dom->conn->privateData;
1875 1876
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
E
Eric Blake 已提交
1877
    virDomainDefPtr persistentDef;
1878 1879 1880
    unsigned long long shares = 0;
    unsigned long long period = 0;
    long long quota = 0;
1881
    int ret = -1;
1882 1883 1884
    int rc;
    bool cpu_bw_status = false;
    int saved_nparams = 0;
1885

1886 1887
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
1888

1889
    lxcDriverLock(driver);
1890 1891 1892 1893 1894 1895 1896 1897 1898

    if (*nparams > 1) {
        rc = lxcGetCpuBWStatus(driver->cgroup);
        if (rc < 0)
            goto cleanup;
        cpu_bw_status = !!rc;
    }

    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1899

1900
    if (vm == NULL) {
1901 1902 1903 1904 1905
        lxcError(VIR_ERR_INTERNAL_ERROR,
                 _("No such domain %s"), dom->uuid);
        goto cleanup;
    }

E
Eric Blake 已提交
1906 1907 1908
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
        goto cleanup;
1909 1910

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
E
Eric Blake 已提交
1911 1912 1913 1914
        shares = persistentDef->cputune.shares;
        if (*nparams > 1 && cpu_bw_status) {
            period = persistentDef->cputune.period;
            quota = persistentDef->cputune.quota;
1915 1916 1917 1918 1919 1920 1921
        }
        goto out;
    }

    if (!lxcCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
        lxcError(VIR_ERR_OPERATION_INVALID,
                 "%s", _("cgroup CPU controller is not mounted"));
1922
        goto cleanup;
1923 1924
    }

1925 1926 1927
    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
        lxcError(VIR_ERR_INTERNAL_ERROR,
                 _("cannot find cgroup for domain %s"), vm->def->name);
1928
        goto cleanup;
1929
    }
1930

1931 1932 1933 1934
    rc = virCgroupGetCpuShares(group, &shares);
    if (rc != 0) {
        virReportSystemError(-rc, "%s",
                             _("unable to get cpu shares tunable"));
1935
        goto cleanup;
1936 1937 1938 1939 1940 1941 1942 1943
    }

    if (*nparams > 1 && cpu_bw_status) {
        rc = lxcGetVcpuBWLive(group, &period, &quota);
        if (rc != 0)
            goto cleanup;
    }
out:
1944 1945
    if (virTypedParameterAssign(&params[0], VIR_DOMAIN_SCHEDULER_CPU_SHARES,
                                VIR_TYPED_PARAM_ULLONG, shares) < 0)
C
Chris Lalancette 已提交
1946
        goto cleanup;
1947 1948 1949 1950
    saved_nparams++;

    if (cpu_bw_status) {
        if (*nparams > saved_nparams) {
1951 1952 1953
            if (virTypedParameterAssign(&params[1],
                                        VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
                                        VIR_TYPED_PARAM_ULLONG, period) < 0)
1954 1955 1956 1957 1958
                goto cleanup;
            saved_nparams++;
        }

        if (*nparams > saved_nparams) {
1959 1960 1961
            if (virTypedParameterAssign(&params[2],
                                        VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
                                        VIR_TYPED_PARAM_LLONG, quota) < 0)
1962 1963 1964 1965 1966 1967 1968
                goto cleanup;
            saved_nparams++;
        }
    }

    *nparams = saved_nparams;

1969
    ret = 0;
1970

1971 1972
cleanup:
    virCgroupFree(&group);
1973 1974
    if (vm)
        virDomainObjUnlock(vm);
1975
    lxcDriverUnlock(driver);
1976
    return ret;
1977 1978
}

1979 1980 1981 1982 1983 1984 1985 1986
static int
lxcGetSchedulerParameters(virDomainPtr domain,
                          virTypedParameterPtr params,
                          int *nparams)
{
    return lxcGetSchedulerParametersFlags(domain, params, nparams, 0);
}

1987

1988 1989 1990 1991 1992
static int
lxcDomainSetBlkioParameters(virDomainPtr dom,
                            virTypedParameterPtr params,
                            int nparams,
                            unsigned int flags)
1993
{
1994
    virLXCDriverPtr driver = dom->conn->privateData;
1995 1996 1997 1998 1999 2000 2001 2002
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr persistentDef = NULL;
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
2003 2004 2005 2006 2007 2008
    if (virTypedParameterArrayValidate(params, nparams,
                                       VIR_DOMAIN_BLKIO_WEIGHT,
                                       VIR_TYPED_PARAM_UINT,
                                       NULL) < 0)
        return -1;

2009 2010 2011 2012 2013 2014 2015 2016 2017 2018
    lxcDriverLock(driver);

    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
        lxcError(VIR_ERR_INTERNAL_ERROR,
                        _("No such domain %s"), dom->uuid);
        goto cleanup;
    }

E
Eric Blake 已提交
2019 2020 2021
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
        goto cleanup;
2022 2023 2024

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (!lxcCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_BLKIO)) {
2025 2026
            lxcError(VIR_ERR_OPERATION_INVALID, "%s",
                     _("blkio cgroup isn't mounted"));
2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
            lxcError(VIR_ERR_INTERNAL_ERROR,
                     _("cannot find cgroup for domain %s"), vm->def->name);
            goto cleanup;
        }

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

            if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
                int rc;

                if (params[i].value.ui > 1000 || params[i].value.ui < 100) {
                    lxcError(VIR_ERR_INVALID_ARG, "%s",
                             _("out of blkio weight range."));
E
Eric Blake 已提交
2045
                    goto cleanup;
2046 2047 2048 2049 2050 2051
                }

                rc = virCgroupSetBlkioWeight(group, params[i].value.ui);
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to set blkio weight tunable"));
E
Eric Blake 已提交
2052
                    goto cleanup;
2053 2054 2055
                }
            }
        }
E
Eric Blake 已提交
2056 2057
    }
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
2058 2059 2060 2061 2062 2063 2064 2065 2066 2067
        /* Clang can't see that if we get here, persistentDef was set.  */
        sa_assert(persistentDef);

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

            if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
                if (params[i].value.ui > 1000 || params[i].value.ui < 100) {
                    lxcError(VIR_ERR_INVALID_ARG, "%s",
                             _("out of blkio weight range."));
E
Eric Blake 已提交
2068
                    goto cleanup;
2069 2070 2071 2072 2073 2074 2075
                }

                persistentDef->blkio.weight = params[i].value.ui;
            }
        }

        if (virDomainSaveConfig(driver->configDir, persistentDef) < 0)
E
Eric Blake 已提交
2076
            goto cleanup;
2077 2078
    }

E
Eric Blake 已提交
2079
    ret = 0;
2080 2081 2082 2083 2084 2085 2086 2087 2088 2089
cleanup:
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
    lxcDriverUnlock(driver);
    return ret;
}


#define LXC_NB_BLKIO_PARAM  1
2090 2091 2092 2093 2094
static int
lxcDomainGetBlkioParameters(virDomainPtr dom,
                            virTypedParameterPtr params,
                            int *nparams,
                            unsigned int flags)
2095
{
2096
    virLXCDriverPtr driver = dom->conn->privateData;
2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr persistentDef = NULL;
    unsigned int val;
    int ret = -1;
    int rc;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
    lxcDriverLock(driver);

    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
        lxcError(VIR_ERR_INTERNAL_ERROR,
                 _("No such domain %s"), dom->uuid);
        goto cleanup;
    }

    if ((*nparams) == 0) {
        /* Current number of blkio parameters supported by cgroups */
        *nparams = LXC_NB_BLKIO_PARAM;
        ret = 0;
        goto cleanup;
    }

E
Eric Blake 已提交
2124 2125 2126
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
        goto cleanup;
2127 2128 2129

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (!lxcCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_BLKIO)) {
2130 2131
            lxcError(VIR_ERR_OPERATION_INVALID, "%s",
                     _("blkio cgroup isn't mounted"));
2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
            lxcError(VIR_ERR_INTERNAL_ERROR,
                     _("cannot find cgroup for domain %s"), vm->def->name);
            goto cleanup;
        }

        for (i = 0; i < *nparams && i < LXC_NB_BLKIO_PARAM; i++) {
            virTypedParameterPtr param = &params[i];
            val = 0;

            switch (i) {
            case 0: /* fill blkio weight here */
                rc = virCgroupGetBlkioWeight(group, &val);
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to get blkio weight"));
                    goto cleanup;
                }
2153 2154
                if (virTypedParameterAssign(param, VIR_DOMAIN_BLKIO_WEIGHT,
                                            VIR_TYPED_PARAM_UINT, val) < 0)
2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168
                    goto cleanup;
                break;

            default:
                break;
                /* should not hit here */
            }
        }
    } else if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        for (i = 0; i < *nparams && i < LXC_NB_BLKIO_PARAM; i++) {
            virTypedParameterPtr param = &params[i];

            switch (i) {
            case 0: /* fill blkio weight here */
2169 2170 2171
                if (virTypedParameterAssign(param, VIR_DOMAIN_BLKIO_WEIGHT,
                                            VIR_TYPED_PARAM_UINT,
                                            persistentDef->blkio.weight) < 0)
2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195
                    goto cleanup;
                break;

            default:
                break;
                /* should not hit here */
            }
        }
    }

    if (LXC_NB_BLKIO_PARAM < *nparams)
        *nparams = LXC_NB_BLKIO_PARAM;
    ret = 0;

cleanup:
    if (group)
        virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
    lxcDriverUnlock(driver);
    return ret;
}


2196 2197 2198 2199 2200 2201
#ifdef __linux__
static int
lxcDomainInterfaceStats(virDomainPtr dom,
                        const char *path,
                        struct _virDomainInterfaceStats *stats)
{
2202
    virLXCDriverPtr driver = dom->conn->privateData;
2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213
    virDomainObjPtr vm;
    int i;
    int ret = -1;

    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    lxcDriverUnlock(driver);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2214
        lxcError(VIR_ERR_NO_DOMAIN,
2215 2216 2217 2218 2219
                 _("No domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    if (!virDomainObjIsActive(vm)) {
2220
        lxcError(VIR_ERR_OPERATION_INVALID,
2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234
                 "%s", _("Domain is not running"));
        goto cleanup;
    }

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

    if (ret == 0)
2235
        ret = linuxDomainInterfaceStats(path, stats);
2236
    else
2237
        lxcError(VIR_ERR_INVALID_ARG,
2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249
                 _("Invalid path, '%s' is not a known interface"), path);

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}
#else
static int
lxcDomainInterfaceStats(virDomainPtr dom,
                        const char *path ATTRIBUTE_UNUSED,
                        struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED)
A
Alex Jia 已提交
2250
{
2251
    lxcError(VIR_ERR_NO_SUPPORT, "%s", __FUNCTION__);
2252 2253 2254 2255
    return -1;
}
#endif

2256 2257
static int lxcDomainGetAutostart(virDomainPtr dom,
                                   int *autostart) {
2258
    virLXCDriverPtr driver = dom->conn->privateData;
2259 2260 2261 2262 2263 2264 2265 2266 2267 2268
    virDomainObjPtr vm;
    int ret = -1;

    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    lxcDriverUnlock(driver);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2269
        lxcError(VIR_ERR_NO_DOMAIN,
2270
                 _("No domain with matching uuid '%s'"), uuidstr);
2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284
        goto cleanup;
    }

    *autostart = vm->autostart;
    ret = 0;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

static int lxcDomainSetAutostart(virDomainPtr dom,
                                   int autostart) {
2285
    virLXCDriverPtr driver = dom->conn->privateData;
2286 2287 2288 2289 2290 2291 2292 2293 2294 2295
    virDomainObjPtr vm;
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;

    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2296
        lxcError(VIR_ERR_NO_DOMAIN,
2297
                 _("No domain with matching uuid '%s'"), uuidstr);
2298 2299 2300 2301
        goto cleanup;
    }

    if (!vm->persistent) {
2302
        lxcError(VIR_ERR_OPERATION_INVALID,
2303
                 "%s", _("Cannot set autostart for transient domain"));
2304 2305 2306 2307 2308
        goto cleanup;
    }

    autostart = (autostart != 0);

2309 2310 2311 2312
    if (vm->autostart == autostart) {
        ret = 0;
        goto cleanup;
    }
2313

2314
    configFile = virDomainConfigFile(driver->configDir,
2315 2316 2317
                                     vm->def->name);
    if (configFile == NULL)
        goto cleanup;
2318
    autostartLink = virDomainConfigFile(driver->autostartDir,
2319 2320 2321
                                        vm->def->name);
    if (autostartLink == NULL)
        goto cleanup;
2322

2323
    if (autostart) {
2324 2325
        if (virFileMakePath(driver->autostartDir) < 0) {
            virReportSystemError(errno,
2326 2327 2328
                                 _("Cannot create autostart directory %s"),
                                 driver->autostartDir);
            goto cleanup;
2329 2330
        }

2331
        if (symlink(configFile, autostartLink) < 0) {
2332
            virReportSystemError(errno,
2333 2334 2335 2336 2337 2338
                                 _("Failed to create symlink '%s to '%s'"),
                                 autostartLink, configFile);
            goto cleanup;
        }
    } else {
        if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
2339
            virReportSystemError(errno,
2340 2341 2342 2343
                                 _("Failed to delete symlink '%s'"),
                                 autostartLink);
            goto cleanup;
        }
2344
    }
2345 2346

    vm->autostart = autostart;
2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357
    ret = 0;

cleanup:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
    if (vm)
        virDomainObjUnlock(vm);
    lxcDriverUnlock(driver);
    return ret;
}

2358
static int lxcFreezeContainer(virLXCDriverPtr driver, virDomainObjPtr vm)
R
Ryota Ozaki 已提交
2359 2360 2361 2362 2363 2364 2365 2366 2367 2368
{
    int timeout = 1000; /* In milliseconds */
    int check_interval = 1; /* In milliseconds */
    int exp = 10;
    int waited_time = 0;
    int ret = -1;
    char *state = NULL;
    virCgroupPtr cgroup = NULL;

    if (!(driver->cgroup &&
2369
          virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) == 0))
R
Ryota Ozaki 已提交
2370 2371
        return -1;

2372 2373
    /* From here on, we know that cgroup != NULL.  */

R
Ryota Ozaki 已提交
2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394
    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)
         */
        r = virCgroupSetFreezerState(cgroup, "FROZEN");

        /*
         * Returning EBUSY explicitly indicates that the group is
         * being freezed but incomplete and other errors are true
         * errors.
         */
        if (r < 0 && r != -EBUSY) {
            VIR_DEBUG("Writing freezer.state failed with errno: %d", r);
            goto error;
        }
        if (r == -EBUSY)
2395
            VIR_DEBUG("Writing freezer.state gets EBUSY");
R
Ryota Ozaki 已提交
2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434

        /*
         * Unfortunately, returning 0 (success) is likely to happen
         * even when the freezing has not been completed. Sometimes
         * the state of the group remains "FREEZING" like when
         * returning -EBUSY and even worse may never transit to
         * "FROZEN" even if writing "FROZEN" again.
         *
         * So we don't trust the return value anyway and always
         * decide that the freezing has been complete only with
         * the state actually transit to "FROZEN".
         */
        usleep(check_interval * 1000);

        r = virCgroupGetFreezerState(cgroup, &state);

        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);
    }
2435
    VIR_DEBUG("lxcFreezeContainer timeout");
R
Ryota Ozaki 已提交
2436 2437 2438 2439 2440 2441 2442 2443 2444 2445
error:
    /*
     * 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.
     */
    virCgroupSetFreezerState(cgroup, "THAWED");
    ret = -1;

cleanup:
2446
    virCgroupFree(&cgroup);
R
Ryota Ozaki 已提交
2447 2448 2449 2450 2451 2452
    VIR_FREE(state);
    return ret;
}

static int lxcDomainSuspend(virDomainPtr dom)
{
2453
    virLXCDriverPtr driver = dom->conn->privateData;
R
Ryota Ozaki 已提交
2454 2455 2456 2457 2458 2459 2460 2461 2462 2463
    virDomainObjPtr vm;
    virDomainEventPtr event = NULL;
    int ret = -1;

    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2464
        lxcError(VIR_ERR_NO_DOMAIN,
2465
                 _("No domain with matching uuid '%s'"), uuidstr);
R
Ryota Ozaki 已提交
2466 2467 2468
        goto cleanup;
    }

D
Daniel P. Berrange 已提交
2469
    if (!virDomainObjIsActive(vm)) {
2470
        lxcError(VIR_ERR_OPERATION_INVALID,
2471
                 "%s", _("Domain is not running"));
R
Ryota Ozaki 已提交
2472 2473 2474
        goto cleanup;
    }

J
Jiri Denemark 已提交
2475
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) {
R
Ryota Ozaki 已提交
2476
        if (lxcFreezeContainer(driver, vm) < 0) {
2477
            lxcError(VIR_ERR_OPERATION_FAILED,
2478
                     "%s", _("Suspend operation failed"));
R
Ryota Ozaki 已提交
2479 2480
            goto cleanup;
        }
J
Jiri Denemark 已提交
2481
        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
R
Ryota Ozaki 已提交
2482 2483 2484 2485 2486 2487

        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
    }

2488
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
R
Ryota Ozaki 已提交
2489 2490 2491 2492 2493
        goto cleanup;
    ret = 0;

cleanup:
    if (event)
2494
        virDomainEventStateQueue(driver->domainEventState, event);
R
Ryota Ozaki 已提交
2495 2496 2497 2498 2499 2500
    if (vm)
        virDomainObjUnlock(vm);
    lxcDriverUnlock(driver);
    return ret;
}

2501
static int lxcUnfreezeContainer(virLXCDriverPtr driver, virDomainObjPtr vm)
R
Ryota Ozaki 已提交
2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517
{
    int ret;
    virCgroupPtr cgroup = NULL;

    if (!(driver->cgroup &&
        virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) == 0))
        return -1;

    ret = virCgroupSetFreezerState(cgroup, "THAWED");

    virCgroupFree(&cgroup);
    return ret;
}

static int lxcDomainResume(virDomainPtr dom)
{
2518
    virLXCDriverPtr driver = dom->conn->privateData;
R
Ryota Ozaki 已提交
2519 2520 2521 2522 2523 2524 2525 2526 2527 2528
    virDomainObjPtr vm;
    virDomainEventPtr event = NULL;
    int ret = -1;

    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2529
        lxcError(VIR_ERR_NO_DOMAIN,
2530
                 _("No domain with matching uuid '%s'"), uuidstr);
R
Ryota Ozaki 已提交
2531 2532 2533
        goto cleanup;
    }

D
Daniel P. Berrange 已提交
2534
    if (!virDomainObjIsActive(vm)) {
2535
        lxcError(VIR_ERR_OPERATION_INVALID,
2536
                 "%s", _("Domain is not running"));
R
Ryota Ozaki 已提交
2537 2538 2539
        goto cleanup;
    }

J
Jiri Denemark 已提交
2540
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
R
Ryota Ozaki 已提交
2541
        if (lxcUnfreezeContainer(driver, vm) < 0) {
2542
            lxcError(VIR_ERR_OPERATION_FAILED,
2543
                     "%s", _("Resume operation failed"));
R
Ryota Ozaki 已提交
2544 2545
            goto cleanup;
        }
J
Jiri Denemark 已提交
2546 2547
        virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
                             VIR_DOMAIN_RUNNING_UNPAUSED);
R
Ryota Ozaki 已提交
2548 2549 2550 2551 2552 2553

        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
    }

2554
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
R
Ryota Ozaki 已提交
2555 2556 2557 2558 2559
        goto cleanup;
    ret = 0;

cleanup:
    if (event)
2560
        virDomainEventStateQueue(driver->domainEventState, event);
R
Ryota Ozaki 已提交
2561 2562 2563 2564 2565 2566
    if (vm)
        virDomainObjUnlock(vm);
    lxcDriverUnlock(driver);
    return ret;
}

2567 2568
static int
lxcDomainOpenConsole(virDomainPtr dom,
2569
                      const char *dev_name,
2570 2571 2572
                      virStreamPtr st,
                      unsigned int flags)
{
2573
    virLXCDriverPtr driver = dom->conn->privateData;
2574 2575 2576 2577
    virDomainObjPtr vm = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    int ret = -1;
    virDomainChrDefPtr chr = NULL;
2578
    size_t i;
2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596

    virCheckFlags(0, -1);

    lxcDriverLock(driver);
    virUUIDFormat(dom->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

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

2597
    if (dev_name) {
2598 2599 2600 2601 2602 2603 2604
        for (i = 0 ; i < vm->def->nconsoles ; i++) {
            if (vm->def->consoles[i]->info.alias &&
                STREQ(vm->def->consoles[i]->info.alias, dev_name)) {
                chr = vm->def->consoles[i];
                break;
            }
        }
2605
    } else {
2606 2607
        if (vm->def->nconsoles)
            chr = vm->def->consoles[0];
2608 2609 2610 2611 2612
        else if (vm->def->nserials)
            chr = vm->def->serials[0];
    }

    if (!chr) {
2613 2614 2615
        lxcError(VIR_ERR_INTERNAL_ERROR,
                 _("cannot find console device '%s'"),
                 dev_name ? dev_name : _("default"));
2616 2617 2618
        goto cleanup;
    }

2619
    if (chr->source.type != VIR_DOMAIN_CHR_TYPE_PTY) {
2620
        lxcError(VIR_ERR_INTERNAL_ERROR,
2621
                 _("character device %s is not using a PTY"), dev_name);
2622 2623 2624
        goto cleanup;
    }

2625
    if (virFDStreamOpenFile(st, chr->source.data.file.path,
E
Eric Blake 已提交
2626
                            0, 0, O_RDWR) < 0)
2627 2628 2629 2630 2631 2632 2633 2634 2635 2636
        goto cleanup;

    ret = 0;
cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    lxcDriverUnlock(driver);
    return ret;
}

2637 2638 2639 2640 2641
static int
lxcListAllDomains(virConnectPtr conn,
                  virDomainPtr **domains,
                  unsigned int flags)
{
2642
    virLXCDriverPtr driver = conn->privateData;
2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653
    int ret = -1;

    virCheckFlags(VIR_CONNECT_LIST_FILTERS_ALL, -1);

    lxcDriverLock(driver);
    ret = virDomainList(conn, driver->domains.objs, domains, flags);
    lxcDriverUnlock(driver);

    return ret;
}

2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680
static int
lxcVMFilterRebuild(virConnectPtr conn ATTRIBUTE_UNUSED,
                   virHashIterator iter, void *data)
{
    virHashForEach(lxc_driver->domains.objs, iter, data);

    return 0;
}

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

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

static virNWFilterCallbackDriver lxcCallbackDriver = {
    .name = "LXC",
    .vmFilterRebuild = lxcVMFilterRebuild,
    .vmDriverLock = lxcVMDriverLock,
    .vmDriverUnlock = lxcVMDriverUnlock,
};
R
Ryota Ozaki 已提交
2681

D
Daniel Veillard 已提交
2682 2683
/* Function Tables */
static virDriver lxcDriver = {
2684
    .no = VIR_DRV_LXC,
2685
    .name = LXC_DRIVER_NAME,
2686 2687 2688 2689 2690 2691 2692 2693
    .open = lxcOpen, /* 0.4.2 */
    .close = lxcClose, /* 0.4.2 */
    .version = lxcVersion, /* 0.4.6 */
    .getHostname = virGetHostname, /* 0.6.3 */
    .nodeGetInfo = nodeGetInfo, /* 0.6.5 */
    .getCapabilities = lxcGetCapabilities, /* 0.6.5 */
    .listDomains = lxcListDomains, /* 0.4.2 */
    .numOfDomains = lxcNumDomains, /* 0.4.2 */
2694
    .listAllDomains = lxcListAllDomains, /* 0.9.13 */
2695 2696 2697 2698 2699 2700 2701
    .domainCreateXML = lxcDomainCreateAndStart, /* 0.4.4 */
    .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 */
2702
    .domainDestroyFlags = lxcDomainDestroyFlags, /* 0.9.4 */
2703 2704 2705 2706 2707 2708
    .domainGetOSType = lxcGetOSType, /* 0.4.2 */
    .domainGetMaxMemory = lxcDomainGetMaxMemory, /* 0.7.2 */
    .domainSetMaxMemory = lxcDomainSetMaxMemory, /* 0.7.2 */
    .domainSetMemory = lxcDomainSetMemory, /* 0.7.2 */
    .domainSetMemoryParameters = lxcDomainSetMemoryParameters, /* 0.8.5 */
    .domainGetMemoryParameters = lxcDomainGetMemoryParameters, /* 0.8.5 */
2709 2710
    .domainSetBlkioParameters = lxcDomainSetBlkioParameters, /* 0.9.8 */
    .domainGetBlkioParameters = lxcDomainGetBlkioParameters, /* 0.9.8 */
2711 2712
    .domainGetInfo = lxcDomainGetInfo, /* 0.4.2 */
    .domainGetState = lxcDomainGetState, /* 0.9.2 */
2713 2714
    .domainGetSecurityLabel = lxcDomainGetSecurityLabel, /* 0.9.10 */
    .nodeGetSecurityModel = lxcNodeGetSecurityModel, /* 0.9.10 */
2715 2716 2717 2718 2719 2720 2721
    .domainGetXMLDesc = lxcDomainGetXMLDesc, /* 0.4.2 */
    .listDefinedDomains = lxcListDefinedDomains, /* 0.4.2 */
    .numOfDefinedDomains = lxcNumDefinedDomains, /* 0.4.2 */
    .domainCreate = lxcDomainStart, /* 0.4.4 */
    .domainCreateWithFlags = lxcDomainStartWithFlags, /* 0.8.2 */
    .domainDefineXML = lxcDomainDefine, /* 0.4.2 */
    .domainUndefine = lxcDomainUndefine, /* 0.4.2 */
2722
    .domainUndefineFlags = lxcDomainUndefineFlags, /* 0.9.4 */
2723 2724 2725 2726
    .domainGetAutostart = lxcDomainGetAutostart, /* 0.7.0 */
    .domainSetAutostart = lxcDomainSetAutostart, /* 0.7.0 */
    .domainGetSchedulerType = lxcGetSchedulerType, /* 0.5.0 */
    .domainGetSchedulerParameters = lxcGetSchedulerParameters, /* 0.5.0 */
2727
    .domainGetSchedulerParametersFlags = lxcGetSchedulerParametersFlags, /* 0.9.2 */
2728
    .domainSetSchedulerParameters = lxcSetSchedulerParameters, /* 0.5.0 */
2729
    .domainSetSchedulerParametersFlags = lxcSetSchedulerParametersFlags, /* 0.9.2 */
2730
    .domainInterfaceStats = lxcDomainInterfaceStats, /* 0.7.3 */
2731
    .nodeGetCPUStats = nodeGetCPUStats, /* 0.9.3 */
2732
    .nodeGetMemoryStats = nodeGetMemoryStats, /* 0.9.3 */
2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744
    .nodeGetCellsFreeMemory = nodeGetCellsFreeMemory, /* 0.6.5 */
    .nodeGetFreeMemory = nodeGetFreeMemory, /* 0.6.5 */
    .domainEventRegister = lxcDomainEventRegister, /* 0.7.0 */
    .domainEventDeregister = lxcDomainEventDeregister, /* 0.7.0 */
    .isEncrypted = lxcIsEncrypted, /* 0.7.3 */
    .isSecure = lxcIsSecure, /* 0.7.3 */
    .domainIsActive = lxcDomainIsActive, /* 0.7.3 */
    .domainIsPersistent = lxcDomainIsPersistent, /* 0.7.3 */
    .domainIsUpdated = lxcDomainIsUpdated, /* 0.8.6 */
    .domainEventRegisterAny = lxcDomainEventRegisterAny, /* 0.8.0 */
    .domainEventDeregisterAny = lxcDomainEventDeregisterAny, /* 0.8.0 */
    .domainOpenConsole = lxcDomainOpenConsole, /* 0.8.6 */
2745
    .isAlive = lxcIsAlive, /* 0.9.8 */
2746
    .nodeSuspendForDuration = nodeSuspendForDuration, /* 0.9.8 */
D
Daniel Veillard 已提交
2747 2748
};

2749
static virStateDriver lxcStateDriver = {
2750
    .name = LXC_DRIVER_NAME,
2751 2752 2753
    .initialize = lxcStartup,
    .cleanup = lxcShutdown,
    .active = lxcActive,
2754
    .reload = lxcReload,
2755 2756
};

D
Daniel Veillard 已提交
2757 2758 2759
int lxcRegister(void)
{
    virRegisterDriver(&lxcDriver);
2760
    virRegisterStateDriver(&lxcStateDriver);
2761
    virNWFilterRegisterCallbackDriver(&lxcCallbackDriver);
D
Daniel Veillard 已提交
2762 2763
    return 0;
}