/* Copyright (c) 2013-2014 Red Hat, Inc. This file is part of GlusterFS. This file is licensed to you under your choice of the GNU Lesser General Public License, version 3 or any later version (LGPLv3 or later), or the GNU General Public License, version 2 (GPLv2), in all cases as published by the Free Software Foundation. */ #ifndef _CONFIG_H #define _CONFIG_H #include "config.h" #endif #include "common-utils.h" #include "cli1-xdr.h" #include "xdr-generic.h" #include "glusterd.h" #include "glusterd-op-sm.h" #include "glusterd-store.h" #include "glusterd-utils.h" #include "glusterd-volgen.h" #include "glusterd-locks.h" #include "run.h" #include "syscall.h" #include /* Valid entities that the mgt_v3 lock can hold locks upon */ char *valid_types[] = { "vol", "snap", NULL }; static dict_t *mgmt_v3_lock; /* Checks if the lock request is for a valid entity */ gf_boolean_t glusterd_mgmt_v3_is_type_valid (char *type) { int32_t i = 0; gf_boolean_t ret = _gf_false; GF_ASSERT (type); for (i = 0; valid_types[i]; i++) { if (!strcmp (type, valid_types[i])) { ret = _gf_true; break; } } return ret; } /* Initialize the global mgmt_v3 lock list(dict) when * glusterd is spawned */ int32_t glusterd_mgmt_v3_lock_init () { int32_t ret = -1; mgmt_v3_lock = dict_new (); if (!mgmt_v3_lock) { ret = -1; goto out; } ret = 0; out: return ret; } /* Destroy the global mgmt_v3 lock list(dict) when * glusterd cleanup is performed */ void glusterd_mgmt_v3_lock_fini () { if (mgmt_v3_lock) dict_destroy (mgmt_v3_lock); } int32_t glusterd_get_mgmt_v3_lock_owner (char *key, uuid_t *uuid) { int32_t ret = -1; mgmt_v3_lock_obj *lock_obj = NULL; uuid_t no_owner = {"\0"}; if (!key || !uuid) { gf_log ("", GF_LOG_ERROR, "key or uuid is null."); ret = -1; goto out; } ret = dict_get_bin(mgmt_v3_lock, key, (void **) &lock_obj); if (!ret) uuid_copy (*uuid, lock_obj->lock_owner); else uuid_copy (*uuid, no_owner); ret = 0; out: gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } int32_t glusterd_multiple_mgmt_v3_unlock (dict_t *dict, uuid_t uuid) { int32_t ret = -1; int32_t op_ret = 0; int32_t i = -1; int32_t volcount = -1; char volname_buf[PATH_MAX] = ""; char *volname = NULL; if (!dict) { gf_log ("", GF_LOG_ERROR, "dict is null."); ret = -1; goto out; } ret = dict_get_int32 (dict, "volcount", &volcount); if (ret) { gf_log ("", GF_LOG_DEBUG, "Failed to get volcount" "name"); goto out; } /* Unlocking one volume after other */ for (i = 1; i <= volcount; i++) { ret = snprintf (volname_buf, sizeof(volname_buf) - 1, "volname%d", i); volname_buf[ret] = '\0'; ret = dict_get_str (dict, volname_buf, &volname); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to get %s Volcount = %d", volname_buf, volcount); goto out; } ret = glusterd_mgmt_v3_unlock (volname, uuid, "vol"); if (ret) { gf_log ("", GF_LOG_ERROR, "Failed to release lock for %s. ", volname); op_ret = ret; } } ret = op_ret; out: gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } int32_t glusterd_multiple_mgmt_v3_lock (dict_t *dict, uuid_t uuid) { int32_t ret = -1; int32_t i = -1; int32_t volcount = -1; char volname_buf[PATH_MAX] = ""; char *volname = NULL; int32_t locked_volcount = 0; if (!dict) { gf_log ("", GF_LOG_ERROR, "dict is null."); ret = -1; goto out; } ret = dict_get_int32 (dict, "volcount", &volcount); if (ret) { gf_log ("", GF_LOG_ERROR, "Failed to get volcount" "name"); goto out; } /* Locking one volume after other */ for (i = 1; i <= volcount; i++) { ret = snprintf (volname_buf, sizeof(volname_buf) - 1, "volname%d", i); volname_buf[ret] = '\0'; ret = dict_get_str (dict, volname_buf, &volname); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to get %s Volcount = %d", volname_buf, volcount); goto out; } ret = glusterd_mgmt_v3_lock (volname, uuid, "vol"); if (ret) { gf_log ("", GF_LOG_ERROR, "Failed to acquire lock for %s " "on behalf of %s. Reversing " "this transaction", volname, uuid_utoa(uuid)); break; } locked_volcount ++; } /* If we failed to lock one volume, unlock others and return failure */ if (volcount != locked_volcount) { for (i = 1; i <= locked_volcount; i++) { ret = snprintf (volname_buf, sizeof(volname_buf) - 1, "volname%d", i); volname_buf[ret] = '\0'; ret = dict_get_str (dict, volname_buf, &volname); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to get %s lockd_volcount = %d", volname_buf, volcount); goto out; } ret = glusterd_mgmt_v3_unlock (volname, uuid, "vol"); if (ret) gf_log ("", GF_LOG_ERROR, "Failed to release lock for %s.", volname); } ret = -1; } out: gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } int32_t glusterd_mgmt_v3_lock (const char *name, uuid_t uuid, char *type) { char key[PATH_MAX] = ""; int32_t ret = -1; mgmt_v3_lock_obj *lock_obj = NULL; gf_boolean_t is_valid = _gf_true; uuid_t owner = {0}; if (!name || !type) { gf_log (THIS->name, GF_LOG_ERROR, "name or type is null."); ret = -1; goto out; } is_valid = glusterd_mgmt_v3_is_type_valid (type); if (is_valid != _gf_true) { gf_log ("", GF_LOG_ERROR, "Invalid entity. Cannot perform locking " "operation on %s types", type); ret = -1; goto out; } ret = snprintf (key, sizeof(key), "%s_%s", name, type); if (ret != strlen(name) + 1 + strlen(type)) { ret = -1; gf_log (THIS->name, GF_LOG_ERROR, "Unable to create key"); goto out; } gf_log (THIS->name, GF_LOG_DEBUG, "Trying to acquire lock of %s %s for %s as %s", type, name, uuid_utoa (uuid), key); ret = glusterd_get_mgmt_v3_lock_owner (key, &owner); if (ret) { gf_log (THIS->name, GF_LOG_DEBUG, "Unable to get mgmt_v3 lock owner"); goto out; } /* If the lock has already been held for the given volume * we fail */ if (!uuid_is_null (owner)) { gf_log (THIS->name, GF_LOG_ERROR, "Lock for %s held by %s", name, uuid_utoa (owner)); ret = -1; goto out; } lock_obj = GF_CALLOC (1, sizeof(mgmt_v3_lock_obj), gf_common_mt_mgmt_v3_lock_obj_t); if (!lock_obj) { ret = -1; goto out; } uuid_copy (lock_obj->lock_owner, uuid); ret = dict_set_bin (mgmt_v3_lock, key, lock_obj, sizeof(*lock_obj)); if (ret) { gf_log (THIS->name, GF_LOG_ERROR, "Unable to set lock owner in mgmt_v3 lock"); if (lock_obj) GF_FREE (lock_obj); goto out; } gf_log (THIS->name, GF_LOG_DEBUG, "Lock for %s %s successfully held by %s", type, name, uuid_utoa (uuid)); ret = 0; out: gf_log (THIS->name, GF_LOG_TRACE, "Returning %d", ret); return ret; } int32_t glusterd_mgmt_v3_unlock (const char *name, uuid_t uuid, char *type) { char key[PATH_MAX] = ""; int32_t ret = -1; gf_boolean_t is_valid = _gf_true; uuid_t owner = {0}; if (!name || !type) { gf_log (THIS->name, GF_LOG_ERROR, "name is null."); ret = -1; goto out; } is_valid = glusterd_mgmt_v3_is_type_valid (type); if (is_valid != _gf_true) { gf_log ("", GF_LOG_ERROR, "Invalid entity. Cannot perform unlocking " "operation on %s types", type); ret = -1; goto out; } ret = snprintf (key, sizeof(key), "%s_%s", name, type); if (ret != strlen(name) + 1 + strlen(type)) { gf_log (THIS->name, GF_LOG_ERROR, "Unable to create key"); ret = -1; goto out; } gf_log (THIS->name, GF_LOG_DEBUG, "Trying to release lock of %s %s for %s as %s", type, name, uuid_utoa (uuid), key); ret = glusterd_get_mgmt_v3_lock_owner (key, &owner); if (ret) { gf_log (THIS->name, GF_LOG_DEBUG, "Unable to get mgmt_v3 lock owner"); goto out; } if (uuid_is_null (owner)) { gf_log (THIS->name, GF_LOG_ERROR, "Lock for %s %s not held", type, name); ret = -1; goto out; } ret = uuid_compare (uuid, owner); if (ret) { gf_log (THIS->name, GF_LOG_ERROR, "Lock owner mismatch. " "Lock for %s %s held by %s", type, name, uuid_utoa (owner)); goto out; } /* Removing the mgmt_v3 lock from the global list */ dict_del (mgmt_v3_lock, key); gf_log (THIS->name, GF_LOG_DEBUG, "Lock for %s %s successfully released", type, name); ret = 0; out: gf_log (THIS->name, GF_LOG_TRACE, "Returning %d", ret); return ret; }