lock_driver_lockd.c 29.0 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 375
    if (configFile &&
        virLockManagerLockDaemonLoadConfig(configFile) < 0) {
376
        goto error;
377
    }
378

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

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

        if (driver->scsiLockSpaceDir &&
            virLockManagerLockDaemonSetupLockspace(driver->scsiLockSpaceDir) < 0)
            goto error;
391
    }
392

393 394
    return 0;

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

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

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

    return 0;
}

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

    if (!priv)
        return;

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

427 428 429 430 431 432 433 434 435 436 437 438
    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;
    }
439 440 441
    VIR_FREE(priv);
}

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

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

451 452 453 454 455 456 457

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

462
    virCheckFlags(VIR_LOCK_MANAGER_NEW_STARTED, -1);
463

464
    if (VIR_ALLOC(priv) < 0)
465 466
        return -1;

467 468 469
    priv->type = type;

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

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 541 542
    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;

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

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


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

    virCheckFlags(VIR_LOCK_MANAGER_RESOURCE_READONLY |
                  VIR_LOCK_MANAGER_RESOURCE_SHARED, -1);

    if (flags & VIR_LOCK_MANAGER_RESOURCE_READONLY)
        return 0;

577 578
    switch (priv->type) {
    case VIR_LOCK_MANAGER_OBJECT_TYPE_DOMAIN:
579

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

594 595 596 597 598 599 600
            /* 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)
601
                    goto cleanup;
602 603 604 605 606

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

614 615 616 617 618 619 620 621 622 623
            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;
624
                    newFlags |= VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_AUTOCREATE;
625 626 627 628 629
                    break;
                }
                virResetLastError();
                /* Fallback to generic non-block code */
            }
630

631 632 633 634
            if (driver->fileLockSpaceDir) {
                if (VIR_STRDUP(newLockspace, driver->fileLockSpaceDir) < 0)
                    goto cleanup;
                if (virCryptoHashString(VIR_CRYPTO_HASH_SHA256, name, &newName) < 0)
635
                    goto cleanup;
636
                newFlags |= VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_AUTOCREATE;
637 638 639 640 641 642 643
                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);
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 670 671
            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"));
672
                goto cleanup;
673 674 675
            }
            if (virAsprintf(&newLockspace, "%s/%s",
                            path, lockspace) < 0)
676
                goto cleanup;
677
            if (VIR_STRDUP(newName, name) < 0)
678
                goto cleanup;
679

680
        }   break;
681 682

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

691
    case VIR_LOCK_MANAGER_OBJECT_TYPE_DAEMON:
692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714
        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;

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

722 723 724
    if (flags & VIR_LOCK_MANAGER_RESOURCE_SHARED)
        newFlags |= VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_SHARED;

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

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

732 733
    ret = 0;
 cleanup:
734
    VIR_FREE(newLockspace);
735
    VIR_FREE(newName);
736
    return ret;
737 738 739
}


740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767
static int virLockManagerLockDaemonReleaseImpl(virNetClientPtr client,
                                               virNetClientProgramPtr program,
                                               int counter,
                                               virLockManagerLockDaemonResourcePtr res)
{
    virLockSpaceProtocolReleaseResourceArgs args;

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

    args.path = res->lockspace;
    args.name = res->name;
    args.flags = res->flags;

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

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


768 769 770 771 772 773 774 775 776 777
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;
778 779
    ssize_t i;
    ssize_t lastGood = -1;
780 781 782
    virLockManagerLockDaemonPrivatePtr priv = lock->privateData;

    virCheckFlags(VIR_LOCK_MANAGER_ACQUIRE_REGISTER_ONLY |
783 784
                  VIR_LOCK_MANAGER_ACQUIRE_RESTRICT |
                  VIR_LOCK_MANAGER_ACQUIRE_ROLLBACK, -1);
785

786 787
    if (priv->type == VIR_LOCK_MANAGER_OBJECT_TYPE_DOMAIN &&
        priv->nresources == 0 &&
788
        priv->t.dom.hasRWDisks &&
789 790 791 792 793 794 795 796 797 798 799 800 801 802
        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)) {
803
        for (i = 0; i < priv->nresources; i++) {
804 805 806 807
            virLockSpaceProtocolAcquireResourceArgs args;

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

808
            args.path = priv->resources[i].lockspace;
809 810 811 812 813 814 815 816 817 818 819
            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;
820
            lastGood = i;
821 822 823 824 825 826 827 828 829
        }
    }

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

    rv = 0;

830
 cleanup:
831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852
    if (rv < 0) {
        int saved_errno = errno;
        virErrorPtr origerr;

        virErrorPreserveLast(&origerr);
        if (fd)
            VIR_FORCE_CLOSE(*fd);

        if (flags & VIR_LOCK_MANAGER_ACQUIRE_ROLLBACK) {
            for (i = lastGood; i >= 0; i--) {
                virLockManagerLockDaemonResourcePtr res = &priv->resources[i];

                if (virLockManagerLockDaemonReleaseImpl(client, program,
                                                        counter++, res) < 0)
                    VIR_WARN("Unable to release resource lockspace=%s name=%s",
                             res->lockspace, res->name);
            }
        }

        virErrorRestore(&origerr);
        errno = saved_errno;
    }
853 854 855 856 857 858 859 860 861 862 863 864 865 866 867
    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;
868 869
    size_t i;
    virLockManagerLockDaemonPrivatePtr priv = lock->privateData;
870

871
    virCheckFlags(0, -1);
872 873 874 875 876 877 878

    if (state)
        *state = NULL;

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

879
    for (i = 0; i < priv->nresources; i++) {
880
        virLockManagerLockDaemonResourcePtr res = &priv->resources[i];
881

882 883
        if (virLockManagerLockDaemonReleaseImpl(client, program,
                                                counter++, res) < 0)
884 885
            goto cleanup;
    }
886 887 888

    rv = 0;

889
 cleanup:
890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927
    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,
};