lock_manager.c 11.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * lock_manager.c: Implements the internal lock manager API
 *
 * Copyright (C) 2010-2011 Red Hat, Inc.
 *
 * 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
17
 * License along with this library.  If not, see
O
Osier Yang 已提交
18
 * <http://www.gnu.org/licenses/>.
19 20 21 22 23 24
 *
 */

#include <config.h>

#include "lock_manager.h"
25
#include "lock_driver_nop.h"
26 27 28 29 30 31
#include "virterror_internal.h"
#include "logging.h"
#include "util.h"
#include "memory.h"
#include "uuid.h"

32 33 34
#if HAVE_DLFCN_H
# include <dlfcn.h>
#endif
35 36 37 38 39 40 41
#include <stdlib.h>
#include <unistd.h>

#include "configmake.h"

#define VIR_FROM_THIS VIR_FROM_LOCKING

42 43 44 45 46
#define CHECK_DRIVER(field, errret)                                  \
    if (!driver->field) {                                            \
        virReportError(VIR_ERR_INTERNAL_ERROR,                       \
                     _("Missing '%s' field in lock manager driver"), \
                     #field);                                        \
47 48 49 50 51
        return errret;                                               \
    }

#define CHECK_MANAGER(field, errret)                                 \
    if (!lock->driver->field) {                                      \
52 53 54
        virReportError(VIR_ERR_INTERNAL_ERROR,                         \
                       _("Missing '%s' field in lock manager driver"), \
                       #field);                                        \
55 56 57 58 59 60 61 62 63 64 65 66
        return errret;                                               \
    }

struct _virLockManagerPlugin {
    char *name;
    virLockDriverPtr driver;
    void *handle;
    int refs;
};

#define DEFAULT_LOCK_MANAGER_PLUGIN_DIR LIBDIR "/libvirt/lock-driver"

67 68 69 70 71 72 73 74 75 76
static const char *virLockManagerPluginDir = DEFAULT_LOCK_MANAGER_PLUGIN_DIR;

void
virLockManagerSetPluginDir(const char *dir)
{
    if (dir)
        virLockManagerPluginDir = dir;
}


77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
static void virLockManagerLogParams(size_t nparams,
                                    virLockManagerParamPtr params)
{
    int i;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    for (i = 0 ; i < nparams ; i++) {
        switch (params[i].type) {
        case VIR_LOCK_MANAGER_PARAM_TYPE_INT:
            VIR_DEBUG("  key=%s type=int value=%d", params[i].key, params[i].value.i);
            break;
        case VIR_LOCK_MANAGER_PARAM_TYPE_UINT:
            VIR_DEBUG("  key=%s type=uint value=%u", params[i].key, params[i].value.ui);
            break;
        case VIR_LOCK_MANAGER_PARAM_TYPE_LONG:
            VIR_DEBUG("  key=%s type=long value=%lld", params[i].key, params[i].value.l);
            break;
        case VIR_LOCK_MANAGER_PARAM_TYPE_ULONG:
            VIR_DEBUG("  key=%s type=ulong value=%llu", params[i].key, params[i].value.ul);
            break;
        case VIR_LOCK_MANAGER_PARAM_TYPE_DOUBLE:
            VIR_DEBUG("  key=%s type=double value=%lf", params[i].key, params[i].value.d);
            break;
        case VIR_LOCK_MANAGER_PARAM_TYPE_STRING:
            VIR_DEBUG("  key=%s type=string value=%s", params[i].key, params[i].value.str);
            break;
102 103 104
        case VIR_LOCK_MANAGER_PARAM_TYPE_CSTRING:
            VIR_DEBUG("  key=%s type=cstring value=%s", params[i].key, params[i].value.cstr);
            break;
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
        case VIR_LOCK_MANAGER_PARAM_TYPE_UUID:
            virUUIDFormat(params[i].value.uuid, uuidstr);
            VIR_DEBUG("  key=%s type=uuid value=%s", params[i].key, uuidstr);
            break;
        }
    }
}


/**
 * virLockManagerPluginNew:
 * @name: the name of the plugin
 * @flag: optional plugin flags
 *
 * Attempt to load the plugin $(libdir)/libvirt/lock-driver/@name.so
 * The plugin driver entry point will be resolved & invoked to obtain
 * the lock manager driver.
 *
 * Even if the loading of the plugin succeeded, this may still
 * return NULL if the plugin impl decided that we (libvirtd)
 * are too old to support a feature it requires
 *
 * Returns a plugin object, or NULL if loading failed.
 */
129
#if HAVE_DLFCN_H
130
virLockManagerPluginPtr virLockManagerPluginNew(const char *name,
131
                                                const char *configFile,
132 133 134 135
                                                unsigned int flags)
{
    void *handle = NULL;
    virLockDriverPtr driver;
E
Eric Blake 已提交
136
    virLockManagerPluginPtr plugin = NULL;
137 138 139
    const char *moddir = getenv("LIBVIRT_LOCK_MANAGER_PLUGIN_DIR");
    char *modfile = NULL;

140 141 142 143
    if (STREQ(name, "nop")) {
        driver = &virLockDriverNop;
    } else {
        if (moddir == NULL)
144
            moddir = virLockManagerPluginDir;
145

146
        VIR_DEBUG("Module load %s from %s", name, moddir);
147

148 149 150 151
        if (virAsprintf(&modfile, "%s/%s.so", moddir, name) < 0) {
            virReportOOMError();
            return NULL;
        }
152

153 154 155 156 157 158
        if (access(modfile, R_OK) < 0) {
            virReportSystemError(errno,
                                 _("Plugin %s not accessible"),
                                 modfile);
            goto cleanup;
        }
159

160 161
        handle = dlopen(modfile, RTLD_NOW | RTLD_LOCAL);
        if (!handle) {
162 163 164
            virReportError(VIR_ERR_SYSTEM_ERROR,
                           _("Failed to load plugin %s: %s"),
                           modfile, dlerror());
165 166
            goto cleanup;
        }
167

168
        if (!(driver = dlsym(handle, "virLockDriverImpl"))) {
169 170
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing plugin initialization symbol 'virLockDriverImpl'"));
171 172
            goto cleanup;
        }
173 174
    }

175
    if (driver->drvInit(VIR_LOCK_MANAGER_VERSION, configFile, flags) < 0)
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
        goto cleanup;

    if (VIR_ALLOC(plugin) < 0) {
        virReportOOMError();
        goto cleanup;
    }

    plugin->driver = driver;
    plugin->handle = handle;
    plugin->refs = 1;
    if (!(plugin->name = strdup(name))) {
        virReportOOMError();
        goto cleanup;
    }

    VIR_FREE(modfile);
    return plugin;

cleanup:
E
Eric Blake 已提交
195
    VIR_FREE(plugin);
196 197 198 199 200
    VIR_FREE(modfile);
    if (handle)
        dlclose(handle);
    return NULL;
}
201
#else /* !HAVE_DLFCN_H */
202 203 204 205
virLockManagerPluginPtr
virLockManagerPluginNew(const char *name ATTRIBUTE_UNUSED,
                        const char *configFile ATTRIBUTE_UNUSED,
                        unsigned int flags_unused ATTRIBUTE_UNUSED)
206
{
207 208
    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                   _("this platform is missing dlopen"));
209 210 211
    return NULL;
}
#endif /* !HAVE_DLFCN_H */
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235


/**
 * virLockManagerPluginRef:
 * @plugin: the plugin implementation to ref
 *
 * Acquires an additional reference on the plugin.
 */
void virLockManagerPluginRef(virLockManagerPluginPtr plugin)
{
    plugin->refs++;
}


/**
 * virLockManagerPluginUnref:
 * @plugin: the plugin implementation to unref
 *
 * Releases a reference on the plugin. When the last reference
 * is released, it will attempt to unload the plugin from memory.
 * The plugin may refuse to allow unloading if this would
 * result in an unsafe scenario.
 *
 */
236
#if HAVE_DLFCN_H
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
void virLockManagerPluginUnref(virLockManagerPluginPtr plugin)
{
    if (!plugin)
        return;

    plugin->refs--;

    if (plugin->refs > 0)
        return;

    if (plugin->driver->drvDeinit() >= 0) {
        if (plugin->handle)
            dlclose(plugin->handle);
    } else {
        VIR_WARN("Unable to unload lock maanger plugin from memory");
        return;
    }

    VIR_FREE(plugin->name);
    VIR_FREE(plugin);
}
258 259 260 261 262
#else /* !HAVE_DLFCN_H */
void virLockManagerPluginUnref(virLockManagerPluginPtr plugin ATTRIBUTE_UNUSED)
{
}
#endif /* !HAVE_DLFCN_H */
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280


const char *virLockManagerPluginGetName(virLockManagerPluginPtr plugin)
{
    VIR_DEBUG("plugin=%p", plugin);

    return plugin->name;
}


bool virLockManagerPluginUsesState(virLockManagerPluginPtr plugin)
{
    VIR_DEBUG("plugin=%p", plugin);

    return plugin->driver->flags & VIR_LOCK_MANAGER_USES_STATE;
}


281 282 283 284 285 286 287
virLockDriverPtr virLockManagerPluginGetDriver(virLockManagerPluginPtr plugin)
{
    VIR_DEBUG("plugin=%p", plugin);

    return plugin->driver;
}

288 289
/**
 * virLockManagerNew:
290
 * @driver: the lock manager implementation to use
291 292 293 294 295 296 297 298
 * @type: the type of process to be supervised
 * @flags: optional flags, currently unused
 *
 * Create a new context to supervise a process, usually
 * a virtual machine.
 *
 * Returns a new lock manager context
 */
299
virLockManagerPtr virLockManagerNew(virLockDriverPtr driver,
300 301 302 303 304 305
                                    unsigned int type,
                                    size_t nparams,
                                    virLockManagerParamPtr params,
                                    unsigned int flags)
{
    virLockManagerPtr lock;
306 307
    VIR_DEBUG("driver=%p type=%u nparams=%zu params=%p flags=%x",
              driver, type, nparams, params, flags);
308 309
    virLockManagerLogParams(nparams, params);

310
    CHECK_DRIVER(drvNew, NULL);
311 312 313 314 315 316

    if (VIR_ALLOC(lock) < 0) {
        virReportOOMError();
        return NULL;
    }

317
    lock->driver = driver;
318

319
    if (driver->drvNew(lock, type, nparams, params, flags) < 0) {
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
        VIR_FREE(lock);
        return NULL;
    }

    return lock;
}


int virLockManagerAddResource(virLockManagerPtr lock,
                              unsigned int type,
                              const char *name,
                              size_t nparams,
                              virLockManagerParamPtr params,
                              unsigned int flags)
{
335
    VIR_DEBUG("lock=%p type=%u name=%s nparams=%zu params=%p flags=%x",
336 337 338 339 340 341 342 343 344 345 346 347 348
              lock, type, name, nparams, params, flags);
    virLockManagerLogParams(nparams, params);

    CHECK_MANAGER(drvAddResource, -1);

    return lock->driver->drvAddResource(lock,
                                        type, name,
                                        nparams, params,
                                        flags);
}

int virLockManagerAcquire(virLockManagerPtr lock,
                          const char *state,
349
                          unsigned int flags,
350
                          virDomainLockFailureAction action,
351
                          int *fd)
352
{
353 354
    VIR_DEBUG("lock=%p state='%s' flags=%x action=%d fd=%p",
              lock, NULLSTR(state), flags, action, fd);
355 356 357

    CHECK_MANAGER(drvAcquire, -1);

358 359 360
    if (fd)
        *fd = -1;

361
    return lock->driver->drvAcquire(lock, state, flags, action, fd);
362 363 364 365 366 367 368
}


int virLockManagerRelease(virLockManagerPtr lock,
                          char **state,
                          unsigned int flags)
{
369
    VIR_DEBUG("lock=%p state=%p flags=%x", lock, state, flags);
370 371 372 373 374 375 376 377 378 379 380

    CHECK_MANAGER(drvRelease, -1);

    return lock->driver->drvRelease(lock, state, flags);
}


int virLockManagerInquire(virLockManagerPtr lock,
                          char **state,
                          unsigned int flags)
{
381
    VIR_DEBUG("lock=%p state=%p flags=%x", lock, state, flags);
382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403

    CHECK_MANAGER(drvInquire, -1);

    return lock->driver->drvInquire(lock, state, flags);
}


int virLockManagerFree(virLockManagerPtr lock)
{
    VIR_DEBUG("lock=%p", lock);

    if (!lock)
        return 0;

    CHECK_MANAGER(drvFree, -1);

    lock->driver->drvFree(lock);

    VIR_FREE(lock);

    return 0;
}