/* Copyright (c) 2010-2012 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 #include #include #include #include #include "globals.h" #include "compat.h" #include "protocol-common.h" #include "xlator.h" #include "logging.h" #include "timer.h" #include "glusterd-mem-types.h" #include "glusterd.h" #include "glusterd-sm.h" #include "glusterd-op-sm.h" #include "glusterd-utils.h" #include "glusterd-store.h" #include "run.h" #include "glusterd-volgen.h" #include "glusterd-mgmt.h" #include "syscall.h" #include "cli1-xdr.h" #include "xdr-generic.h" glusterd_snap_t* glusterd_new_snap_object() { glusterd_snap_t *snap = NULL; snap = GF_CALLOC (1, sizeof (*snap), gf_gld_mt_snap_t); if (snap) { LOCK_INIT (&snap->lock); INIT_LIST_HEAD (&snap->snap_list); snap->snap_status = GD_SNAP_STATUS_INIT; } return snap; }; glusterd_snap_cg_t* glusterd_new_snap_cg_object(int64_t volume_count) { glusterd_snap_cg_t *cg = NULL; glusterd_volinfo_t *volinfo = NULL; if (volume_count < 0) { gf_log (THIS->name, GF_LOG_ERROR, "Volume count < 0"); return NULL; } cg = GF_CALLOC (1, (sizeof (*cg) + (volume_count * sizeof (*volinfo))), gf_gld_mt_snap_cg_t); if (cg) { LOCK_INIT (&cg->lock); INIT_LIST_HEAD (&cg->cg_list); cg->cg_status = GD_SNAP_STATUS_INIT; cg->volume_count = volume_count; } return cg; } int32_t glusterd_add_snap (glusterd_volinfo_t *volinfo, glusterd_snap_t *snap) { int ret = -1; uint64_t count = -1; glusterd_snap_t *entry = NULL; glusterd_snap_t *last = NULL; glusterd_snap_t *tmp = NULL; GF_VALIDATE_OR_GOTO ("glusterd", volinfo, out); GF_VALIDATE_OR_GOTO ("glusterd", snap, out); LOCK (&volinfo->lock); { list_for_each_entry_safe (entry, tmp, &volinfo->snaps, snap_list) { count++; if (!strcmp (entry->snap_name, snap->snap_name) || !uuid_compare (entry->snap_id, snap->snap_id)) { gf_log (THIS->name, GF_LOG_ERROR, "Found " "duplicate snap %s (%s)", entry->snap_name, uuid_utoa (entry->snap_id)); goto unlock; } last = entry; } list_add (&snap->snap_list, &last->snap_list); gf_log (THIS->name, GF_LOG_DEBUG, "Snap %s added @ %"PRIu64, snap->snap_name, count); ret = 0; } unlock: UNLOCK (&volinfo->lock); out: return ret; } glusterd_snap_t* glusterd_find_snap_by_name (glusterd_volinfo_t *volinfo, char *snap_name) { uint64_t count = -1; glusterd_snap_t *entry = NULL; glusterd_snap_t *dup = NULL; glusterd_snap_t *tmp = NULL; GF_VALIDATE_OR_GOTO ("glusterd", volinfo, out); GF_VALIDATE_OR_GOTO ("glusterd", snap_name, out); LOCK (&volinfo->lock); { list_for_each_entry_safe (entry, tmp, &volinfo->snaps, snap_list) { count++; if (!strcmp (entry->snap_name, snap_name)) { gf_log (THIS->name, GF_LOG_DEBUG, "Found " "snap %s (%s)", entry->snap_name, uuid_utoa (entry->snap_id)); dup = entry; break; } } } UNLOCK (&volinfo->lock); out: return dup; } glusterd_snap_t* glusterd_find_snap_by_id (glusterd_volinfo_t *volinfo, uuid_t snap_id) { uint64_t count = -1; glusterd_snap_t *entry = NULL; glusterd_snap_t *dup = NULL; glusterd_snap_t *tmp = NULL; GF_VALIDATE_OR_GOTO ("glusterd", volinfo, out); if (uuid_is_null(snap_id)) goto out; LOCK (&volinfo->lock); { list_for_each_entry_safe (entry, tmp, &volinfo->snaps, snap_list) { count++; if (!uuid_compare (entry->snap_id, snap_id)) { gf_log (THIS->name, GF_LOG_DEBUG, "Found " "snap %s (%s)", entry->snap_name, uuid_utoa (entry->snap_id)); dup = entry; break; } } } UNLOCK (&volinfo->lock); out: return dup; } glusterd_snap_t* glusterd_remove_snap_by_id (glusterd_volinfo_t *volinfo, uuid_t snap_id) { glusterd_snap_t *entry = NULL; GF_VALIDATE_OR_GOTO ("glusterd", volinfo, out); if (uuid_is_null(snap_id)) goto out; entry = glusterd_find_snap_by_id (volinfo, snap_id); if (entry) { LOCK (&volinfo->lock); { entry->snap_status = GD_SNAP_STATUS_DECOMMISSION; list_del_init (&entry->snap_list); } UNLOCK (&volinfo->lock); } out: return entry; } glusterd_snap_t* glusterd_remove_snap_by_name (glusterd_volinfo_t *volinfo, char *snap_name) { glusterd_snap_t *entry = NULL; GF_VALIDATE_OR_GOTO ("glusterd", volinfo, out); GF_VALIDATE_OR_GOTO ("glusterd", snap_name, out); entry = glusterd_find_snap_by_name (volinfo, snap_name); if (entry) { LOCK (&volinfo->lock); { entry->snap_status = GD_SNAP_STATUS_DECOMMISSION; list_del_init (&entry->snap_list); } UNLOCK (&volinfo->lock); } out: return entry; } // Big lock should already acquired before this is called int32_t glusterd_add_snap_cg (glusterd_conf_t *conf, glusterd_snap_cg_t *cg) { int ret = -1; uint64_t count = -1; glusterd_snap_cg_t *entry = NULL; glusterd_snap_cg_t *last = NULL; glusterd_snap_cg_t *tmp = NULL; GF_VALIDATE_OR_GOTO (THIS->name, conf, out); GF_VALIDATE_OR_GOTO (THIS->name, cg, out); list_for_each_entry_safe (entry, tmp, &conf->snap_cg, cg_list) { count++; if (!strcmp (entry->cg_name, cg->cg_name) || !uuid_compare (entry->cg_id, cg->cg_id)) { gf_log (THIS->name, GF_LOG_ERROR, "Found duplicate " "CG %s(%s)", entry->cg_name, uuid_utoa(entry->cg_id)); goto out; } last = entry; } list_add (&cg->cg_list, &last->cg_list); gf_log (THIS->name, GF_LOG_DEBUG, "Added CG %s (%s) @ %"PRIu64, cg->cg_name, uuid_utoa(cg->cg_id), count); ret = 0; out: return ret; } glusterd_snap_cg_t* glusterd_find_snap_cg_by_name (glusterd_conf_t *conf, char *cg_name) { glusterd_snap_cg_t *entry = NULL; glusterd_snap_cg_t *dup = NULL; glusterd_snap_cg_t *tmp = NULL; GF_VALIDATE_OR_GOTO (THIS->name, conf, out); GF_VALIDATE_OR_GOTO (THIS->name, cg_name, out); list_for_each_entry_safe (entry, tmp, &conf->snap_cg, cg_list) { if (!strcmp (entry->cg_name, cg_name)) { gf_log (THIS->name, GF_LOG_DEBUG, "Found CG %s(%s)", entry->cg_name, uuid_utoa(entry->cg_id)); dup = entry; break; } } out: return dup; } glusterd_snap_cg_t* glusterd_find_snap_cg_by_id (glusterd_conf_t *conf, uuid_t cg_id) { glusterd_snap_cg_t *entry = NULL; glusterd_snap_cg_t *dup = NULL; glusterd_snap_cg_t *tmp = NULL; GF_VALIDATE_OR_GOTO (THIS->name, conf, out); if (uuid_is_null (cg_id)) goto out; list_for_each_entry_safe (entry, tmp, &conf->snap_cg, cg_list) { if (!uuid_compare (entry->cg_id, cg_id)) { gf_log (THIS->name, GF_LOG_DEBUG, "Found CG %s(%s)", entry->cg_name, uuid_utoa(entry->cg_id)); dup = entry; break; } } out: return dup; } glusterd_snap_cg_t* glusterd_remove_snap_cg_by_name (glusterd_conf_t *conf, char *cg_name) { glusterd_snap_cg_t *entry = NULL; GF_VALIDATE_OR_GOTO (THIS->name, conf, out); GF_VALIDATE_OR_GOTO (THIS->name, cg_name, out); entry = glusterd_find_snap_cg_by_name(conf, cg_name); if (entry) { entry->cg_status = GD_SNAP_STATUS_DECOMMISSION; list_del_init (&entry->cg_list); } out: return entry; } glusterd_snap_cg_t* glusterd_remove_snap_cg_by_id (glusterd_conf_t *conf, uuid_t cg_id) { glusterd_snap_cg_t *entry = NULL; GF_VALIDATE_OR_GOTO (THIS->name, conf, out); if (uuid_is_null (cg_id)) goto out; entry = glusterd_find_snap_cg_by_id (conf, cg_id); if (entry) { entry->cg_status = GD_SNAP_STATUS_DECOMMISSION; list_del_init (&entry->cg_list); } out: return entry; } int glusterd_handle_snapshot_fn (rpcsvc_request_t *req) { int32_t ret = 0; dict_t *dict = NULL; gf_cli_req cli_req = {{0},}; glusterd_op_t cli_op = GD_OP_SNAP; int type = 0; glusterd_conf_t *priv = NULL; char *host_uuid = NULL; char err_str[2048] = {0,}; xlator_t *this = NULL; GF_ASSERT (req); this = THIS; GF_ASSERT (this); priv = this->private; GF_ASSERT (priv); ret = xdr_to_generic (req->msg[0], &cli_req, (xdrproc_t)xdr_gf_cli_req); if (ret < 0) { req->rpc_err = GARBAGE_ARGS; goto out; } if (cli_req.dict.dict_len) { dict = dict_new (); if (!dict) goto out; ret = dict_unserialize (cli_req.dict.dict_val, cli_req.dict.dict_len, &dict); if (ret < 0) { gf_log (this->name, GF_LOG_ERROR, "failed to " "unserialize req-buffer to dictionary"); snprintf (err_str, sizeof (err_str), "Unable to decode " "the command"); goto out; } else { dict->extra_stdfree = cli_req.dict.dict_val; } host_uuid = gf_strdup (uuid_utoa(MY_UUID)); if (host_uuid == NULL) { snprintf (err_str, sizeof (err_str), "Failed to get " "the uuid of local glusterd"); ret = -1; goto out; } ret = dict_set_dynstr (dict, "host-uuid", host_uuid); if (ret) goto out; } ret = dict_get_int32 (dict, "type", &type); if (ret < 0) { snprintf (err_str, sizeof (err_str), "Command type not found"); gf_log (this->name, GF_LOG_ERROR, "%s", err_str); goto out; } switch (type) { case GF_SNAP_OPTION_TYPE_CREATE: ret = glusterd_mgmt_v3_initiate_all_phases (req, cli_op, dict); break; } out: if (ret) { if (err_str[0] == '\0') snprintf (err_str, sizeof (err_str), "Operation failed"); ret = glusterd_op_send_cli_response (cli_op, ret, 0, req, dict, err_str); } return ret; } int glusterd_handle_snapshot (rpcsvc_request_t *req) { return glusterd_big_locked_handler (req, glusterd_handle_snapshot_fn); }