lock_driver_lockd.c 27.9 KB
Newer Older
1 2 3
/*
 * lock_driver_lockd.c: A lock driver which locks nothing
 *
4
 * Copyright (C) 2010-2011, 2014 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * 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
 * License along with this library;  If not, see
 * <http://www.gnu.org/licenses/>.
 *
 */

#include <config.h>

#include "lock_driver.h"
25
#include "virconf.h"
26
#include "viralloc.h"
27
#include "vircrypto.h"
28
#include "virlog.h"
29
#include "viruuid.h"
30
#include "virfile.h"
31
#include "virerror.h"
32 33 34
#include "rpc/virnetclient.h"
#include "lock_protocol.h"
#include "configmake.h"
35
#include "virstring.h"
36

37 38
#include "lock_driver_lockd.h"

39 40
#define VIR_FROM_THIS VIR_FROM_LOCKING

41 42
VIR_LOG_INIT("locking.lock_driver_lockd");

43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
typedef struct _virLockManagerLockDaemonPrivate virLockManagerLockDaemonPrivate;
typedef virLockManagerLockDaemonPrivate *virLockManagerLockDaemonPrivatePtr;

typedef struct _virLockManagerLockDaemonResource virLockManagerLockDaemonResource;
typedef virLockManagerLockDaemonResource *virLockManagerLockDaemonResourcePtr;

typedef struct _virLockManagerLockDaemonDriver virLockManagerLockDaemonDriver;
typedef virLockManagerLockDaemonDriver *virLockManagerLockDaemonDriverPtr;

struct _virLockManagerLockDaemonResource {
    char *lockspace;
    char *name;
    unsigned int flags;
};

struct _virLockManagerLockDaemonPrivate {
59 60 61 62 63 64 65
    virLockManagerObjectType type;
    union {
        struct {
            unsigned char uuid[VIR_UUID_BUFLEN];
            char *name;
            int id;
            pid_t pid;
66 67

            bool hasRWDisks;
68 69 70 71 72 73 74 75
        } dom;

        struct {
            unsigned char uuid[VIR_UUID_BUFLEN];
            char *name;
            pid_t pid;
        } daemon;
    } t;
76 77 78 79 80 81 82 83 84

    size_t nresources;
    virLockManagerLockDaemonResourcePtr resources;
};


struct _virLockManagerLockDaemonDriver {
    bool autoDiskLease;
    bool requireLeaseForDisks;
85 86

    char *fileLockSpaceDir;
87
    char *lvmLockSpaceDir;
88
    char *scsiLockSpaceDir;
89 90
};

91
static virLockManagerLockDaemonDriverPtr driver;
92 93 94 95

static int virLockManagerLockDaemonLoadConfig(const char *configFile)
{
    virConfPtr conf;
96
    int ret = -1;
97 98 99 100 101 102 103 104 105 106 107 108 109 110

    if (access(configFile, R_OK) == -1) {
        if (errno != ENOENT) {
            virReportSystemError(errno,
                                 _("Unable to access config file %s"),
                                 configFile);
            return -1;
        }
        return 0;
    }

    if (!(conf = virConfReadFile(configFile, 0)))
        return -1;

111 112
    if (virConfGetValueBool(conf, "auto_disk_leases", &driver->autoDiskLease) < 0)
        goto cleanup;
113

114 115
    if (virConfGetValueString(conf, "file_lockspace_dir", &driver->fileLockSpaceDir) < 0)
        goto cleanup;
116

117 118
    if (virConfGetValueString(conf, "lvm_lockspace_dir", &driver->lvmLockSpaceDir) < 0)
        goto cleanup;
119

120 121
    if (virConfGetValueString(conf, "scsi_lockspace_dir", &driver->scsiLockSpaceDir) < 0)
        goto cleanup;
122

123 124 125
    driver->requireLeaseForDisks = !driver->autoDiskLease;
    if (virConfGetValueBool(conf, "require_lease_for_disks", &driver->requireLeaseForDisks) < 0)
        goto cleanup;
126

127 128
    ret = 0;
 cleanup:
129
    virConfFree(conf);
130
    return ret;
131 132 133 134 135 136 137
}


static char *virLockManagerLockDaemonPath(bool privileged)
{
    char *path;
    if (privileged) {
138
        if (VIR_STRDUP(path, LOCALSTATEDIR "/run/libvirt/virtlockd-sock") < 0)
139 140 141 142 143 144 145 146 147 148 149 150
            return NULL;
    } else {
        char *rundir = NULL;

        if (!(rundir = virGetUserRuntimeDirectory()))
            return NULL;

        if (virAsprintf(&path, "%s/virtlockd-sock", rundir) < 0) {
            VIR_FREE(rundir);
            return NULL;
        }

151
        VIR_FREE(rundir);
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
    }
    return path;
}


static int
virLockManagerLockDaemonConnectionRegister(virLockManagerPtr lock,
                                           virNetClientPtr client,
                                           virNetClientProgramPtr program,
                                           int *counter)
{
    virLockManagerLockDaemonPrivatePtr priv = lock->privateData;
    virLockSpaceProtocolRegisterArgs args;
    int rv = -1;

    memset(&args, 0, sizeof(args));

    args.flags = 0;
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193

    switch (priv->type) {
    case VIR_LOCK_MANAGER_OBJECT_TYPE_DOMAIN:
        memcpy(args.owner.uuid, priv->t.dom.uuid, VIR_UUID_BUFLEN);
        args.owner.name = priv->t.dom.name;
        args.owner.id = priv->t.dom.id;
        args.owner.pid = priv->t.dom.pid;
        break;

    case VIR_LOCK_MANAGER_OBJECT_TYPE_DAEMON:
        memcpy(args.owner.uuid, priv->t.daemon.uuid, VIR_UUID_BUFLEN);
        args.owner.name = priv->t.daemon.name;
        args.owner.pid = priv->t.daemon.pid;
        /* This one should not be needed. However, virtlockd
         * checks for ID because not every domain has a PID. */
        args.owner.id = priv->t.daemon.pid;
        break;

    default:
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unknown lock manager object type %d"),
                       priv->type);
        return -1;
    }
194 195 196 197 198 199 200 201 202 203 204 205

    if (virNetClientProgramCall(program,
                                client,
                                (*counter)++,
                                VIR_LOCK_SPACE_PROTOCOL_PROC_REGISTER,
                                0, NULL, NULL, NULL,
                                (xdrproc_t)xdr_virLockSpaceProtocolRegisterArgs, (char*)&args,
                                (xdrproc_t)xdr_void, NULL) < 0)
        goto cleanup;

    rv = 0;

206
 cleanup:
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
    return rv;
}


static int
virLockManagerLockDaemonConnectionRestrict(virLockManagerPtr lock ATTRIBUTE_UNUSED,
                                           virNetClientPtr client,
                                           virNetClientProgramPtr program,
                                           int *counter)
{
    virLockSpaceProtocolRestrictArgs args;
    int rv = -1;

    memset(&args, 0, sizeof(args));

    args.flags = 0;

    if (virNetClientProgramCall(program,
                                client,
                                (*counter)++,
                                VIR_LOCK_SPACE_PROTOCOL_PROC_RESTRICT,
                                0, NULL, NULL, NULL,
                                (xdrproc_t)xdr_virLockSpaceProtocolRestrictArgs, (char*)&args,
                                (xdrproc_t)xdr_void, NULL) < 0)
        goto cleanup;

    rv = 0;

235
 cleanup:
236 237 238 239 240 241 242 243 244
    return rv;
}


static virNetClientPtr virLockManagerLockDaemonConnectionNew(bool privileged,
                                                             virNetClientProgramPtr *prog)
{
    virNetClientPtr client = NULL;
    char *lockdpath;
M
Michal Privoznik 已提交
245
    char *daemonPath = NULL;
246 247 248 249 250 251

    *prog = NULL;

    if (!(lockdpath = virLockManagerLockDaemonPath(privileged)))
        goto error;

252 253 254
    if (!privileged &&
        !(daemonPath = virFileFindResourceFull("virtlockd",
                                               NULL, NULL,
255
                                               abs_topbuilddir "/src",
256 257 258
                                               SBINDIR,
                                               "VIRTLOCKD_PATH")))
        goto error;
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274

    if (!(client = virNetClientNewUNIX(lockdpath,
                                       daemonPath != NULL,
                                       daemonPath)))
        goto error;

    if (!(*prog = virNetClientProgramNew(VIR_LOCK_SPACE_PROTOCOL_PROGRAM,
                                         VIR_LOCK_SPACE_PROTOCOL_PROGRAM_VERSION,
                                         NULL,
                                         0,
                                         NULL)))
        goto error;

    if (virNetClientAddProgram(client, *prog) < 0)
        goto error;

275
    VIR_FREE(daemonPath);
276 277 278 279
    VIR_FREE(lockdpath);

    return client;

280
 error:
281
    VIR_FREE(daemonPath);
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
    VIR_FREE(lockdpath);
    virNetClientClose(client);
    virObjectUnref(client);
    virObjectUnref(*prog);
    return NULL;
}


static virNetClientPtr
virLockManagerLockDaemonConnect(virLockManagerPtr lock,
                                virNetClientProgramPtr *program,
                                int *counter)
{
    virNetClientPtr client;

297
    if (!(client = virLockManagerLockDaemonConnectionNew(geteuid() == 0, program)))
298 299 300 301 302 303 304 305 306 307
        return NULL;

    if (virLockManagerLockDaemonConnectionRegister(lock,
                                                   client,
                                                   *program,
                                                   counter) < 0)
        goto error;

    return client;

308
 error:
309 310 311 312 313 314
    virNetClientClose(client);
    virObjectUnref(client);
    return NULL;
}


315 316 317 318 319 320 321 322 323 324 325
static int virLockManagerLockDaemonSetupLockspace(const char *path)
{
    virNetClientPtr client;
    virNetClientProgramPtr program = NULL;
    virLockSpaceProtocolCreateLockSpaceArgs args;
    int rv = -1;
    int counter = 0;

    memset(&args, 0, sizeof(args));
    args.path = (char*)path;

326
    if (!(client = virLockManagerLockDaemonConnectionNew(geteuid() == 0, &program)))
327 328 329 330 331 332 333 334 335
        return -1;

    if (virNetClientProgramCall(program,
                                client,
                                counter++,
                                VIR_LOCK_SPACE_PROTOCOL_PROC_CREATE_LOCKSPACE,
                                0, NULL, NULL, NULL,
                                (xdrproc_t)xdr_virLockSpaceProtocolCreateLockSpaceArgs, (char*)&args,
                                (xdrproc_t)xdr_void, NULL) < 0) {
336
        if (virGetLastErrorCode() == VIR_ERR_OPERATION_INVALID) {
337 338 339 340 341 342 343 344 345 346
            /* The lockspace already exists */
            virResetLastError();
            rv = 0;
        } else {
            goto cleanup;
        }
    }

    rv = 0;

347
 cleanup:
348 349 350 351 352 353 354
    virObjectUnref(program);
    virNetClientClose(client);
    virObjectUnref(client);
    return rv;
}


355 356 357 358 359 360
static int virLockManagerLockDaemonDeinit(void);

static int virLockManagerLockDaemonInit(unsigned int version,
                                        const char *configFile,
                                        unsigned int flags)
{
361
    VIR_DEBUG("version=%u configFile=%s flags=0x%x", version, NULLSTR(configFile), flags);
362 363 364 365 366 367

    virCheckFlags(0, -1);

    if (driver)
        return 0;

368
    if (VIR_ALLOC(driver) < 0)
369 370 371 372 373
        return -1;

    driver->requireLeaseForDisks = true;
    driver->autoDiskLease = true;

374
    if (virLockManagerLockDaemonLoadConfig(configFile) < 0)
375 376
        goto error;

377 378 379 380 381
    if (driver->autoDiskLease) {
        if (driver->fileLockSpaceDir &&
            virLockManagerLockDaemonSetupLockspace(driver->fileLockSpaceDir) < 0)
            goto error;

382 383 384
        if (driver->lvmLockSpaceDir &&
            virLockManagerLockDaemonSetupLockspace(driver->lvmLockSpaceDir) < 0)
            goto error;
385 386 387 388

        if (driver->scsiLockSpaceDir &&
            virLockManagerLockDaemonSetupLockspace(driver->scsiLockSpaceDir) < 0)
            goto error;
389
    }
390

391 392
    return 0;

393
 error:
394 395 396 397 398 399 400 401 402
    virLockManagerLockDaemonDeinit();
    return -1;
}

static int virLockManagerLockDaemonDeinit(void)
{
    if (!driver)
        return 0;

403 404
    VIR_FREE(driver->scsiLockSpaceDir);
    VIR_FREE(driver->lvmLockSpaceDir);
405
    VIR_FREE(driver->fileLockSpaceDir);
406 407 408 409 410
    VIR_FREE(driver);

    return 0;
}

411 412
static void
virLockManagerLockDaemonPrivateFree(virLockManagerLockDaemonPrivatePtr priv)
413 414 415 416 417 418
{
    size_t i;

    if (!priv)
        return;

419
    for (i = 0; i < priv->nresources; i++) {
420 421 422 423 424
        VIR_FREE(priv->resources[i].lockspace);
        VIR_FREE(priv->resources[i].name);
    }
    VIR_FREE(priv->resources);

425 426 427 428 429 430 431 432 433 434 435 436
    switch (priv->type) {
    case VIR_LOCK_MANAGER_OBJECT_TYPE_DOMAIN:
        VIR_FREE(priv->t.dom.name);
        break;

    case VIR_LOCK_MANAGER_OBJECT_TYPE_DAEMON:
        VIR_FREE(priv->t.daemon.name);
        break;

    default:
        break;
    }
437 438 439
    VIR_FREE(priv);
}

440 441 442 443 444 445 446 447 448
static void virLockManagerLockDaemonFree(virLockManagerPtr lock)
{
    if (!lock)
        return;

    virLockManagerLockDaemonPrivateFree(lock->privateData);
    lock->privateData = NULL;
}

449 450 451 452 453 454 455

static int virLockManagerLockDaemonNew(virLockManagerPtr lock,
                                       unsigned int type,
                                       size_t nparams,
                                       virLockManagerParamPtr params,
                                       unsigned int flags)
{
456
    virLockManagerLockDaemonPrivatePtr priv = NULL;
457
    size_t i;
458
    int ret = -1;
459

460
    virCheckFlags(VIR_LOCK_MANAGER_NEW_STARTED, -1);
461

462
    if (VIR_ALLOC(priv) < 0)
463 464
        return -1;

465 466 467
    priv->type = type;

    switch ((virLockManagerObjectType) type) {
468
    case VIR_LOCK_MANAGER_OBJECT_TYPE_DOMAIN:
469
        for (i = 0; i < nparams; i++) {
470
            if (STREQ(params[i].key, "uuid")) {
471
                memcpy(priv->t.dom.uuid, params[i].value.uuid, VIR_UUID_BUFLEN);
472
            } else if (STREQ(params[i].key, "name")) {
473
                if (VIR_STRDUP(priv->t.dom.name, params[i].value.str) < 0)
474
                    goto cleanup;
475
            } else if (STREQ(params[i].key, "id")) {
476
                priv->t.dom.id = params[i].value.iv;
477
            } else if (STREQ(params[i].key, "pid")) {
478
                priv->t.dom.pid = params[i].value.iv;
479 480
            } else if (STREQ(params[i].key, "uri")) {
                /* ignored */
481 482
            } else {
                virReportError(VIR_ERR_INTERNAL_ERROR,
483
                               _("Unexpected parameter %s for domain object"),
484
                               params[i].key);
485
                goto cleanup;
486 487
            }
        }
488
        if (priv->t.dom.id == 0) {
489 490
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing ID parameter for domain object"));
491
            goto cleanup;
492
        }
493
        if (priv->t.dom.pid == 0)
J
Jim Fehlig 已提交
494
            VIR_DEBUG("Missing PID parameter for domain object");
495
        if (!priv->t.dom.name) {
496 497
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing name parameter for domain object"));
498
            goto cleanup;
499
        }
500
        if (!virUUIDIsValid(priv->t.dom.uuid)) {
501 502
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing UUID parameter for domain object"));
503
            goto cleanup;
504 505 506
        }
        break;

507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
    case VIR_LOCK_MANAGER_OBJECT_TYPE_DAEMON:
        for (i = 0; i < nparams; i++) {
            if (STREQ(params[i].key, "uuid")) {
                memcpy(priv->t.daemon.uuid, params[i].value.uuid, VIR_UUID_BUFLEN);
            } else if (STREQ(params[i].key, "name")) {
                if (VIR_STRDUP(priv->t.daemon.name, params[i].value.str) < 0)
                    goto cleanup;
            } else if (STREQ(params[i].key, "pid")) {
                priv->t.daemon.pid = params[i].value.iv;
            } else {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unexpected parameter %s for daemon object"),
                               params[i].key);
                goto cleanup;
            }
        }

        if (!virUUIDIsValid(priv->t.daemon.uuid)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing UUID parameter for daemon object"));
            goto cleanup;
        }
        if (!priv->t.daemon.name) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing name parameter for daemon object"));
            goto cleanup;
        }
        if (priv->t.daemon.pid == 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing PID parameter for daemon object"));
            goto cleanup;
        }
        break;

541 542 543 544
    default:
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unknown lock manager object type %d"),
                       type);
545
        goto cleanup;
546 547
    }

548 549 550 551 552
    VIR_STEAL_PTR(lock->privateData, priv);
    ret = 0;
 cleanup:
    virLockManagerLockDaemonPrivateFree(priv);
    return ret;
553 554 555 556 557 558 559 560 561 562 563
}


static int virLockManagerLockDaemonAddResource(virLockManagerPtr lock,
                                               unsigned int type,
                                               const char *name,
                                               size_t nparams,
                                               virLockManagerParamPtr params,
                                               unsigned int flags)
{
    virLockManagerLockDaemonPrivatePtr priv = lock->privateData;
564
    char *newName = NULL;
565
    char *newLockspace = NULL;
566
    int newFlags = 0;
567
    int ret = -1;
568 569 570 571 572 573 574

    virCheckFlags(VIR_LOCK_MANAGER_RESOURCE_READONLY |
                  VIR_LOCK_MANAGER_RESOURCE_SHARED, -1);

    if (flags & VIR_LOCK_MANAGER_RESOURCE_READONLY)
        return 0;

575 576
    switch (priv->type) {
    case VIR_LOCK_MANAGER_OBJECT_TYPE_DOMAIN:
577

578
        switch ((virLockManagerResourceType) type) {
579 580 581 582
        case VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK:
            if (params || nparams) {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Unexpected parameters for disk resource"));
583
                goto cleanup;
584 585 586 587
            }
            if (!driver->autoDiskLease) {
                if (!(flags & (VIR_LOCK_MANAGER_RESOURCE_SHARED |
                               VIR_LOCK_MANAGER_RESOURCE_READONLY)))
588
                    priv->t.dom.hasRWDisks = true;
589 590
                return 0;
            }
591

592 593 594 595 596 597 598
            /* XXX we should somehow pass in TYPE=BLOCK info
             * from the domain_lock code, instead of assuming /dev
             */
            if (STRPREFIX(name, "/dev") &&
                driver->lvmLockSpaceDir) {
                VIR_DEBUG("Trying to find an LVM UUID for %s", name);
                if (virStorageFileGetLVMKey(name, &newName) < 0)
599
                    goto cleanup;
600 601 602 603 604

                if (newName) {
                    VIR_DEBUG("Got an LVM UUID %s for %s", newName, name);
                    if (VIR_STRDUP(newLockspace, driver->lvmLockSpaceDir) < 0)
                        goto cleanup;
605
                    newFlags |= VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_AUTOCREATE;
606 607 608 609
                    break;
                }
                virResetLastError();
                /* Fallback to generic non-block code */
610
            }
611

612 613 614 615 616 617 618 619 620 621
            if (STRPREFIX(name, "/dev") &&
                driver->scsiLockSpaceDir) {
                VIR_DEBUG("Trying to find an SCSI ID for %s", name);
                if (virStorageFileGetSCSIKey(name, &newName) < 0)
                    goto cleanup;

                if (newName) {
                    VIR_DEBUG("Got an SCSI ID %s for %s", newName, name);
                    if (VIR_STRDUP(newLockspace, driver->scsiLockSpaceDir) < 0)
                        goto cleanup;
622
                    newFlags |= VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_AUTOCREATE;
623 624 625 626 627
                    break;
                }
                virResetLastError();
                /* Fallback to generic non-block code */
            }
628

629 630 631 632
            if (driver->fileLockSpaceDir) {
                if (VIR_STRDUP(newLockspace, driver->fileLockSpaceDir) < 0)
                    goto cleanup;
                if (virCryptoHashString(VIR_CRYPTO_HASH_SHA256, name, &newName) < 0)
633
                    goto cleanup;
634
                newFlags |= VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_AUTOCREATE;
635 636 637 638 639 640 641
                VIR_DEBUG("Using indirect lease %s for %s", newName, name);
            } else {
                if (VIR_STRDUP(newLockspace, "") < 0)
                    goto cleanup;
                if (VIR_STRDUP(newName, name) < 0)
                    goto cleanup;
                VIR_DEBUG("Using direct lease for %s", name);
642
            }
643

644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669
            break;
        case VIR_LOCK_MANAGER_RESOURCE_TYPE_LEASE: {
            size_t i;
            char *path = NULL;
            char *lockspace = NULL;
            for (i = 0; i < nparams; i++) {
                if (STREQ(params[i].key, "offset")) {
                    if (params[i].value.ul != 0) {
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("Offset must be zero for this lock manager"));
                        goto cleanup;
                    }
                } else if (STREQ(params[i].key, "lockspace")) {
                    lockspace = params[i].value.str;
                } else if (STREQ(params[i].key, "path")) {
                    path = params[i].value.str;
                } else {
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Unexpected parameter %s for lease resource"),
                                   params[i].key);
                    goto cleanup;
                }
            }
            if (!path || !lockspace) {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Missing path or lockspace for lease resource"));
670
                goto cleanup;
671 672 673
            }
            if (virAsprintf(&newLockspace, "%s/%s",
                            path, lockspace) < 0)
674
                goto cleanup;
675
            if (VIR_STRDUP(newName, name) < 0)
676
                goto cleanup;
677

678
        }   break;
679 680

        case VIR_LOCK_MANAGER_RESOURCE_TYPE_METADATA:
681 682 683 684
        default:
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown lock manager object type %d for domain lock object"),
                           type);
685
            goto cleanup;
686
        }
687
        break;
688

689
    case VIR_LOCK_MANAGER_OBJECT_TYPE_DAEMON:
690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
        switch ((virLockManagerResourceType) type) {
        case VIR_LOCK_MANAGER_RESOURCE_TYPE_METADATA:
            if (params || nparams) {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Unexpected parameters for metadata resource"));
                goto cleanup;
            }
            if (VIR_STRDUP(newLockspace, "") < 0 ||
                VIR_STRDUP(newName, name) < 0)
                goto cleanup;
            newFlags |= VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_METADATA;
            break;

        case VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK:
        case VIR_LOCK_MANAGER_RESOURCE_TYPE_LEASE:
        default:
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown lock manager object type %d for daemon lock object"),
                           type);
            goto cleanup;
        }
        break;

713 714 715 716
    default:
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unknown lock manager object type %d"),
                       type);
717
        goto cleanup;
718 719
    }

720 721 722
    if (flags & VIR_LOCK_MANAGER_RESOURCE_SHARED)
        newFlags |= VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_SHARED;

723
    if (VIR_EXPAND_N(priv->resources, priv->nresources, 1) < 0)
724
        goto cleanup;
725

726 727
    VIR_STEAL_PTR(priv->resources[priv->nresources-1].lockspace, newLockspace);
    VIR_STEAL_PTR(priv->resources[priv->nresources-1].name, newName);
728
    priv->resources[priv->nresources-1].flags = newFlags;
729

730 731
    ret = 0;
 cleanup:
732
    VIR_FREE(newLockspace);
733
    VIR_FREE(newName);
734
    return ret;
735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750
}


static int virLockManagerLockDaemonAcquire(virLockManagerPtr lock,
                                           const char *state ATTRIBUTE_UNUSED,
                                           unsigned int flags,
                                           virDomainLockFailureAction action ATTRIBUTE_UNUSED,
                                           int *fd)
{
    virNetClientPtr client = NULL;
    virNetClientProgramPtr program = NULL;
    int counter = 0;
    int rv = -1;
    virLockManagerLockDaemonPrivatePtr priv = lock->privateData;

    virCheckFlags(VIR_LOCK_MANAGER_ACQUIRE_REGISTER_ONLY |
751
                  VIR_LOCK_MANAGER_ACQUIRE_RESTRICT, -1);
752

753 754
    if (priv->type == VIR_LOCK_MANAGER_OBJECT_TYPE_DOMAIN &&
        priv->nresources == 0 &&
755
        priv->t.dom.hasRWDisks &&
756 757 758 759 760 761 762 763 764 765 766 767 768 769
        driver->requireLeaseForDisks) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Read/write, exclusive access, disks were present, but no leases specified"));
        return -1;
    }

    if (!(client = virLockManagerLockDaemonConnect(lock, &program, &counter)))
        goto cleanup;

    if (fd &&
        (*fd = virNetClientDupFD(client, false)) < 0)
        goto cleanup;

    if (!(flags & VIR_LOCK_MANAGER_ACQUIRE_REGISTER_ONLY)) {
770
        size_t i;
771
        for (i = 0; i < priv->nresources; i++) {
772 773 774 775
            virLockSpaceProtocolAcquireResourceArgs args;

            memset(&args, 0, sizeof(args));

776
            args.path = priv->resources[i].lockspace;
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796
            args.name = priv->resources[i].name;
            args.flags = priv->resources[i].flags;

            if (virNetClientProgramCall(program,
                                        client,
                                        counter++,
                                        VIR_LOCK_SPACE_PROTOCOL_PROC_ACQUIRE_RESOURCE,
                                        0, NULL, NULL, NULL,
                                        (xdrproc_t)xdr_virLockSpaceProtocolAcquireResourceArgs, &args,
                                        (xdrproc_t)xdr_void, NULL) < 0)
                goto cleanup;
        }
    }

    if ((flags & VIR_LOCK_MANAGER_ACQUIRE_RESTRICT) &&
        virLockManagerLockDaemonConnectionRestrict(lock, client, program, &counter) < 0)
        goto cleanup;

    rv = 0;

797
 cleanup:
798 799
    if (rv != 0 && fd)
        VIR_FORCE_CLOSE(*fd);
800 801 802 803 804 805 806 807 808 809 810 811 812 813 814
    virNetClientClose(client);
    virObjectUnref(client);
    virObjectUnref(program);

    return rv;
}

static int virLockManagerLockDaemonRelease(virLockManagerPtr lock,
                                           char **state,
                                           unsigned int flags)
{
    virNetClientPtr client = NULL;
    virNetClientProgramPtr program = NULL;
    int counter = 0;
    int rv = -1;
815 816
    size_t i;
    virLockManagerLockDaemonPrivatePtr priv = lock->privateData;
817

818
    virCheckFlags(0, -1);
819 820 821 822 823 824 825

    if (state)
        *state = NULL;

    if (!(client = virLockManagerLockDaemonConnect(lock, &program, &counter)))
        goto cleanup;

826
    for (i = 0; i < priv->nresources; i++) {
827 828 829
        virLockSpaceProtocolReleaseResourceArgs args;

        memset(&args, 0, sizeof(args));
830

831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847
        if (priv->resources[i].lockspace)
            args.path = priv->resources[i].lockspace;
        args.name = priv->resources[i].name;
        args.flags = priv->resources[i].flags;

        args.flags &=
            ~(VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_SHARED |
              VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_AUTOCREATE |
              VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_METADATA);

        if (virNetClientProgramCall(program,
                                    client,
                                    counter++,
                                    VIR_LOCK_SPACE_PROTOCOL_PROC_RELEASE_RESOURCE,
                                    0, NULL, NULL, NULL,
                                    (xdrproc_t)xdr_virLockSpaceProtocolReleaseResourceArgs, &args,
                                    (xdrproc_t)xdr_void, NULL) < 0)
848 849
            goto cleanup;
    }
850 851 852

    rv = 0;

853
 cleanup:
854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891
    virNetClientClose(client);
    virObjectUnref(client);
    virObjectUnref(program);

    return rv;
}


static int virLockManagerLockDaemonInquire(virLockManagerPtr lock ATTRIBUTE_UNUSED,
                                           char **state,
                                           unsigned int flags)
{
    virCheckFlags(0, -1);

    if (state)
        *state = NULL;

    return 0;
}

virLockDriver virLockDriverImpl =
{
    .version = VIR_LOCK_MANAGER_VERSION,
    .flags = 0,

    .drvInit = virLockManagerLockDaemonInit,
    .drvDeinit = virLockManagerLockDaemonDeinit,

    .drvNew = virLockManagerLockDaemonNew,
    .drvFree = virLockManagerLockDaemonFree,

    .drvAddResource = virLockManagerLockDaemonAddResource,

    .drvAcquire = virLockManagerLockDaemonAcquire,
    .drvRelease = virLockManagerLockDaemonRelease,

    .drvInquire = virLockManagerLockDaemonInquire,
};