/* 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. */ /* rpc related syncops */ #include "rpc-clnt.h" #include "protocol-common.h" #include "xdr-generic.h" #include "glusterd1-xdr.h" #include "glusterd-syncop.h" #include "glusterd.h" #include "glusterd-utils.h" #include "glusterd-locks.h" #include "glusterd-jarvis.h" static int glusterd_jarvis_null (rpcsvc_request_t *req) { return 0; } static int glusterd_jarvis_vol_lock_send_resp (rpcsvc_request_t *req, int32_t status) { gd1_jarvis_vol_lock_rsp rsp = {{0},}; int ret = -1; GF_ASSERT (req); rsp.op_ret = status; if (rsp.op_ret) rsp.op_errno = errno; glusterd_get_uuid (&rsp.uuid); ret = glusterd_submit_reply (req, &rsp, NULL, 0, NULL, (xdrproc_t)xdr_gd1_jarvis_vol_lock_rsp); gf_log (THIS->name, GF_LOG_DEBUG, "Responded to volume lock, ret: %d", ret); return ret; } static int glusterd_handle_vol_lock_fn (rpcsvc_request_t *req) { gd1_jarvis_vol_lock_req lock_req = {{0},}; int32_t ret = -1; glusterd_peerinfo_t *peerinfo = NULL; xlator_t *this = NULL; dict_t *dict = NULL; char *volname = NULL; this = THIS; GF_ASSERT (this); GF_ASSERT (req); ret = xdr_to_generic (req->msg[0], &lock_req, (xdrproc_t)xdr_gd1_jarvis_vol_lock_req); if (ret < 0) { gf_log (this->name, GF_LOG_ERROR, "Failed to decode lock " "request received from peer"); req->rpc_err = GARBAGE_ARGS; goto out; } gf_log (this->name, GF_LOG_DEBUG, "Received volume lock req " "from uuid: %s", uuid_utoa (lock_req.uuid)); if (glusterd_friend_find_by_uuid (lock_req.uuid, &peerinfo)) { gf_log (this->name, GF_LOG_WARNING, "%s doesn't " "belong to the cluster. Ignoring request.", uuid_utoa (lock_req.uuid)); ret = -1; goto out; } dict = dict_new (); if (!dict) { ret = -1; goto out; } ret = dict_unserialize (lock_req.dict.dict_val, lock_req.dict.dict_len, &dict); if (ret) { gf_log (this->name, GF_LOG_WARNING, "failed to unserialize the dictionary"); goto out; } ret = dict_get_str (dict, "volname", &volname); if (ret) { /* Trying to acquire volume locks on multiple volumes */ ret = glusterd_multiple_volumes_lock (dict, MY_UUID); if (ret) gf_log ("", GF_LOG_ERROR, "Failed to acquire volume locks on localhost"); } else { ret = glusterd_volume_lock (volname, MY_UUID); if (ret) gf_log (this->name, GF_LOG_ERROR, "Unable to acquire local lock for %s", volname); } glusterd_jarvis_vol_lock_send_resp (req, ret); out: if (dict) dict_unref (dict); gf_log (this->name, GF_LOG_DEBUG, "Returning %d", ret); return ret; } static int glusterd_jarvis_pre_validate_send_resp (rpcsvc_request_t *req, int32_t op, int32_t status, char *op_errstr, dict_t *rsp_dict) { gd1_jarvis_pre_val_rsp rsp = {{0},}; int ret = -1; xlator_t *this = NULL; this = THIS; GF_ASSERT (this); GF_ASSERT (req); rsp.op_ret = status; glusterd_get_uuid (&rsp.uuid); rsp.op = op; if (op_errstr) rsp.op_errstr = op_errstr; else rsp.op_errstr = ""; ret = dict_allocate_and_serialize (rsp_dict, &rsp.dict.dict_val, &rsp.dict.dict_len); if (ret < 0) { gf_log (this->name, GF_LOG_ERROR, "failed to get serialized length of dict"); goto out; } ret = glusterd_submit_reply (req, &rsp, NULL, 0, NULL, (xdrproc_t)xdr_gd1_jarvis_pre_val_rsp); GF_FREE (rsp.dict.dict_val); out: gf_log (this->name, GF_LOG_DEBUG, "Responded to pre validation, ret: %d", ret); return ret; } static int glusterd_handle_pre_validate_fn (rpcsvc_request_t *req) { int32_t ret = -1; gd1_jarvis_pre_val_req op_req = {{0},}; glusterd_peerinfo_t *peerinfo = NULL; xlator_t *this = NULL; char *op_errstr = NULL; dict_t *dict = NULL; dict_t *rsp_dict = NULL; this = THIS; GF_ASSERT (this); GF_ASSERT (req); ret = xdr_to_generic (req->msg[0], &op_req, (xdrproc_t)xdr_gd1_jarvis_pre_val_req); if (ret < 0) { gf_log (this->name, GF_LOG_ERROR, "Failed to decode pre validation " "request received from peer"); req->rpc_err = GARBAGE_ARGS; goto out; } if (glusterd_friend_find_by_uuid (op_req.uuid, &peerinfo)) { gf_log (this->name, GF_LOG_WARNING, "%s doesn't " "belong to the cluster. Ignoring request.", uuid_utoa (op_req.uuid)); ret = -1; goto out; } dict = dict_new (); if (!dict) goto out; ret = dict_unserialize (op_req.dict.dict_val, op_req.dict.dict_len, &dict); if (ret) { gf_log (this->name, GF_LOG_WARNING, "failed to unserialize the dictionary"); goto out; } rsp_dict = dict_new (); if (!rsp_dict) { gf_log (this->name, GF_LOG_ERROR, "Failed to get new dictionary"); return -1; } ret = gd_jarvis_pre_validate_fn (op_req.op, dict, &op_errstr, rsp_dict); if (ret) { gf_log (this->name, GF_LOG_ERROR, "Pre Validation failed on operation %s", gd_op_list[op_req.op]); goto out; } ret = glusterd_jarvis_pre_validate_send_resp (req, op_req.op, ret, op_errstr, rsp_dict); if (ret) { gf_log (this->name, GF_LOG_ERROR, "Failed to send Pre Validation " "response for operation %s", gd_op_list[op_req.op]); goto out; } out: if (op_errstr && (strcmp (op_errstr, ""))) GF_FREE (op_errstr); free (op_req.dict.dict_val); if (rsp_dict) dict_unref (rsp_dict); gf_log (this->name, GF_LOG_DEBUG, "Returning %d", ret); return ret; } static int glusterd_jarvis_brick_op_send_resp (rpcsvc_request_t *req, int32_t op, int32_t status, char *op_errstr, dict_t *rsp_dict) { gd1_jarvis_brick_op_rsp rsp = {{0},}; int ret = -1; xlator_t *this = NULL; this = THIS; GF_ASSERT (this); GF_ASSERT (req); rsp.op_ret = status; glusterd_get_uuid (&rsp.uuid); rsp.op = op; if (op_errstr) rsp.op_errstr = op_errstr; else rsp.op_errstr = ""; ret = dict_allocate_and_serialize (rsp_dict, &rsp.dict.dict_val, &rsp.dict.dict_len); if (ret < 0) { gf_log (this->name, GF_LOG_ERROR, "failed to get serialized length of dict"); goto out; } ret = glusterd_submit_reply (req, &rsp, NULL, 0, NULL, (xdrproc_t)xdr_gd1_jarvis_brick_op_rsp); GF_FREE (rsp.dict.dict_val); out: gf_log (this->name, GF_LOG_DEBUG, "Responded to brick op, ret: %d", ret); return ret; } static int glusterd_handle_brick_op_fn (rpcsvc_request_t *req) { int32_t ret = -1; gd1_jarvis_brick_op_req op_req = {{0},}; glusterd_peerinfo_t *peerinfo = NULL; xlator_t *this = NULL; char *op_errstr = NULL; dict_t *dict = NULL; dict_t *rsp_dict = NULL; this = THIS; GF_ASSERT (this); GF_ASSERT (req); ret = xdr_to_generic (req->msg[0], &op_req, (xdrproc_t)xdr_gd1_jarvis_brick_op_req); if (ret < 0) { gf_log (this->name, GF_LOG_ERROR, "Failed to decode brick op " "request received from peer"); req->rpc_err = GARBAGE_ARGS; goto out; } if (glusterd_friend_find_by_uuid (op_req.uuid, &peerinfo)) { gf_log (this->name, GF_LOG_WARNING, "%s doesn't " "belong to the cluster. Ignoring request.", uuid_utoa (op_req.uuid)); ret = -1; goto out; } dict = dict_new (); if (!dict) goto out; ret = dict_unserialize (op_req.dict.dict_val, op_req.dict.dict_len, &dict); if (ret) { gf_log (this->name, GF_LOG_WARNING, "failed to unserialize the dictionary"); goto out; } rsp_dict = dict_new (); if (!rsp_dict) { gf_log (this->name, GF_LOG_ERROR, "Failed to get new dictionary"); return -1; } ret = gd_jarvis_brick_op_fn (op_req.op, dict, &op_errstr, rsp_dict); if (ret) { gf_log (this->name, GF_LOG_ERROR, "Brick Op failed on operation %s", gd_op_list[op_req.op]); goto out; } ret = glusterd_jarvis_brick_op_send_resp (req, op_req.op, ret, op_errstr, rsp_dict); if (ret) { gf_log (this->name, GF_LOG_ERROR, "Failed to send brick op " "response for operation %s", gd_op_list[op_req.op]); goto out; } out: if (op_errstr && (strcmp (op_errstr, ""))) GF_FREE (op_errstr); free (op_req.dict.dict_val); if (rsp_dict) dict_unref (rsp_dict); gf_log (this->name, GF_LOG_DEBUG, "Returning %d", ret); return ret; } static int glusterd_jarvis_commit_send_resp (rpcsvc_request_t *req, int32_t op, int32_t status, char *op_errstr, dict_t *rsp_dict) { gd1_jarvis_commit_rsp rsp = {{0},}; int ret = -1; xlator_t *this = NULL; this = THIS; GF_ASSERT (this); GF_ASSERT (req); rsp.op_ret = status; glusterd_get_uuid (&rsp.uuid); rsp.op = op; if (op_errstr) rsp.op_errstr = op_errstr; else rsp.op_errstr = ""; ret = dict_allocate_and_serialize (rsp_dict, &rsp.dict.dict_val, &rsp.dict.dict_len); if (ret < 0) { gf_log (this->name, GF_LOG_ERROR, "failed to get serialized length of dict"); goto out; } ret = glusterd_submit_reply (req, &rsp, NULL, 0, NULL, (xdrproc_t)xdr_gd1_jarvis_commit_rsp); GF_FREE (rsp.dict.dict_val); out: gf_log (this->name, GF_LOG_DEBUG, "Responded to commit, ret: %d", ret); return ret; } static int glusterd_handle_commit_fn (rpcsvc_request_t *req) { int32_t ret = -1; gd1_jarvis_commit_req op_req = {{0},}; glusterd_peerinfo_t *peerinfo = NULL; xlator_t *this = NULL; char *op_errstr = NULL; dict_t *dict = NULL; dict_t *rsp_dict = NULL; this = THIS; GF_ASSERT (this); GF_ASSERT (req); ret = xdr_to_generic (req->msg[0], &op_req, (xdrproc_t)xdr_gd1_jarvis_commit_req); if (ret < 0) { gf_log (this->name, GF_LOG_ERROR, "Failed to decode commit " "request received from peer"); req->rpc_err = GARBAGE_ARGS; goto out; } if (glusterd_friend_find_by_uuid (op_req.uuid, &peerinfo)) { gf_log (this->name, GF_LOG_WARNING, "%s doesn't " "belong to the cluster. Ignoring request.", uuid_utoa (op_req.uuid)); ret = -1; goto out; } dict = dict_new (); if (!dict) goto out; ret = dict_unserialize (op_req.dict.dict_val, op_req.dict.dict_len, &dict); if (ret) { gf_log (this->name, GF_LOG_WARNING, "failed to unserialize the dictionary"); goto out; } rsp_dict = dict_new (); if (!rsp_dict) { gf_log (this->name, GF_LOG_ERROR, "Failed to get new dictionary"); return -1; } ret = gd_jarvis_commit_fn (op_req.op, dict, &op_errstr, rsp_dict); if (ret) { gf_log (this->name, GF_LOG_ERROR, "commit failed on operation %s", gd_op_list[op_req.op]); goto out; } ret = glusterd_jarvis_commit_send_resp (req, op_req.op, ret, op_errstr, rsp_dict); if (ret) { gf_log (this->name, GF_LOG_ERROR, "Failed to send commit " "response for operation %s", gd_op_list[op_req.op]); goto out; } out: if (op_errstr && (strcmp (op_errstr, ""))) GF_FREE (op_errstr); free (op_req.dict.dict_val); if (rsp_dict) dict_unref (rsp_dict); gf_log (this->name, GF_LOG_DEBUG, "Returning %d", ret); return ret; } static int glusterd_jarvis_post_validate_send_resp (rpcsvc_request_t *req, int32_t op, int32_t status, char *op_errstr, dict_t *rsp_dict) { gd1_jarvis_post_val_rsp rsp = {{0},}; int ret = -1; xlator_t *this = NULL; this = THIS; GF_ASSERT (this); GF_ASSERT (req); rsp.op_ret = status; glusterd_get_uuid (&rsp.uuid); rsp.op = op; if (op_errstr) rsp.op_errstr = op_errstr; else rsp.op_errstr = ""; ret = dict_allocate_and_serialize (rsp_dict, &rsp.dict.dict_val, &rsp.dict.dict_len); if (ret < 0) { gf_log (this->name, GF_LOG_ERROR, "failed to get serialized length of dict"); goto out; } ret = glusterd_submit_reply (req, &rsp, NULL, 0, NULL, (xdrproc_t)xdr_gd1_jarvis_post_val_rsp); GF_FREE (rsp.dict.dict_val); out: gf_log (this->name, GF_LOG_DEBUG, "Responded to post validation, ret: %d", ret); return ret; } static int glusterd_handle_post_validate_fn (rpcsvc_request_t *req) { int32_t ret = -1; gd1_jarvis_post_val_req op_req = {{0},}; glusterd_peerinfo_t *peerinfo = NULL; xlator_t *this = NULL; char *op_errstr = NULL; dict_t *dict = NULL; dict_t *rsp_dict = NULL; this = THIS; GF_ASSERT (this); GF_ASSERT (req); ret = xdr_to_generic (req->msg[0], &op_req, (xdrproc_t)xdr_gd1_jarvis_post_val_req); if (ret < 0) { gf_log (this->name, GF_LOG_ERROR, "Failed to decode post validation " "request received from peer"); req->rpc_err = GARBAGE_ARGS; goto out; } if (glusterd_friend_find_by_uuid (op_req.uuid, &peerinfo)) { gf_log (this->name, GF_LOG_WARNING, "%s doesn't " "belong to the cluster. Ignoring request.", uuid_utoa (op_req.uuid)); ret = -1; goto out; } dict = dict_new (); if (!dict) goto out; ret = dict_unserialize (op_req.dict.dict_val, op_req.dict.dict_len, &dict); if (ret) { gf_log (this->name, GF_LOG_WARNING, "failed to unserialize the dictionary"); goto out; } rsp_dict = dict_new (); if (!rsp_dict) { gf_log (this->name, GF_LOG_ERROR, "Failed to get new dictionary"); return -1; } ret = gd_jarvis_post_validate_fn (op_req.op, dict, &op_errstr, rsp_dict); if (ret) { gf_log (this->name, GF_LOG_ERROR, "Post Validation failed on operation %s", gd_op_list[op_req.op]); goto out; } ret = glusterd_jarvis_post_validate_send_resp (req, op_req.op, ret, op_errstr, rsp_dict); if (ret) { gf_log (this->name, GF_LOG_ERROR, "Failed to send Post Validation " "response for operation %s", gd_op_list[op_req.op]); goto out; } out: if (op_errstr && (strcmp (op_errstr, ""))) GF_FREE (op_errstr); free (op_req.dict.dict_val); if (rsp_dict) dict_unref (rsp_dict); gf_log (this->name, GF_LOG_DEBUG, "Returning %d", ret); return ret; } static int glusterd_jarvis_vol_unlock_send_resp (rpcsvc_request_t *req, int32_t status) { gd1_jarvis_vol_unlock_rsp rsp = {{0},}; int ret = -1; GF_ASSERT (req); rsp.op_ret = status; if (rsp.op_ret) rsp.op_errno = errno; glusterd_get_uuid (&rsp.uuid); ret = glusterd_submit_reply (req, &rsp, NULL, 0, NULL, (xdrproc_t)xdr_gd1_jarvis_vol_unlock_rsp); gf_log (THIS->name, GF_LOG_DEBUG, "Responded to volume unlock, ret: %d", ret); return ret; } static int glusterd_handle_vol_unlock_fn (rpcsvc_request_t *req) { gd1_jarvis_vol_unlock_req unlock_req = {{0},}; int32_t ret = -1; glusterd_peerinfo_t *peerinfo = NULL; xlator_t *this = NULL; dict_t *dict = NULL; char *volname = NULL; this = THIS; GF_ASSERT (this); GF_ASSERT (req); ret = xdr_to_generic (req->msg[0], &unlock_req, (xdrproc_t)xdr_gd1_jarvis_vol_unlock_req); if (ret < 0) { gf_log (this->name, GF_LOG_ERROR, "Failed to decode unlock " "request received from peer"); req->rpc_err = GARBAGE_ARGS; goto out; } gf_log (this->name, GF_LOG_DEBUG, "Received volume unlock req " "from uuid: %s", uuid_utoa (unlock_req.uuid)); if (glusterd_friend_find_by_uuid (unlock_req.uuid, &peerinfo)) { gf_log (this->name, GF_LOG_WARNING, "%s doesn't " "belong to the cluster. Ignoring request.", uuid_utoa (unlock_req.uuid)); ret = -1; goto out; } dict = dict_new (); if (!dict) { ret = -1; goto out; } ret = dict_unserialize (unlock_req.dict.dict_val, unlock_req.dict.dict_len, &dict); if (ret) { gf_log (this->name, GF_LOG_WARNING, "failed to unserialize the dictionary"); goto out; } ret = dict_get_str (dict, "volname", &volname); if (ret) { /* Trying to release volume locks on multiple volumes */ ret = glusterd_multiple_volumes_unlock (dict, MY_UUID); if (ret) gf_log ("", GF_LOG_ERROR, "Failed to release volume locks on localhost"); } else { ret = glusterd_volume_unlock (volname, MY_UUID); if (ret) gf_log (this->name, GF_LOG_ERROR, "Unable to acquire local lock for %s", volname); } glusterd_jarvis_vol_unlock_send_resp (req, ret); out: if (dict) dict_unref (dict); gf_log (this->name, GF_LOG_DEBUG, "Returning %d", ret); return ret; } static int glusterd_handle_vol_lock (rpcsvc_request_t *req) { return glusterd_big_locked_handler (req, glusterd_handle_vol_lock_fn); } static int glusterd_handle_pre_validate (rpcsvc_request_t *req) { return glusterd_big_locked_handler (req, glusterd_handle_pre_validate_fn); } static int glusterd_handle_brick_op (rpcsvc_request_t *req) { return glusterd_big_locked_handler (req, glusterd_handle_brick_op_fn); } static int glusterd_handle_commit (rpcsvc_request_t *req) { return glusterd_big_locked_handler (req, glusterd_handle_commit_fn); } static int glusterd_handle_post_validate (rpcsvc_request_t *req) { return glusterd_big_locked_handler (req, glusterd_handle_post_validate_fn); } static int glusterd_handle_vol_unlock (rpcsvc_request_t *req) { return glusterd_big_locked_handler (req, glusterd_handle_vol_unlock_fn); } rpcsvc_actor_t gd_jarvis_mgmt_actors[] = { [GLUSTERD_JARVIS_NULL] = { "NULL", GLUSTERD_JARVIS_NULL, glusterd_jarvis_null, NULL, 0, DRC_NA}, [GLUSTERD_JARVIS_VOLUME_LOCK] = { "VOL_LOCK", GLUSTERD_JARVIS_VOLUME_LOCK, glusterd_handle_vol_lock, NULL, 0, DRC_NA}, [GLUSTERD_JARVIS_PRE_VALIDATE] = { "PRE_VAL", GLUSTERD_JARVIS_PRE_VALIDATE, glusterd_handle_pre_validate, NULL, 0, DRC_NA}, [GLUSTERD_JARVIS_BRICK_OP] = { "BRCK_OP", GLUSTERD_JARVIS_BRICK_OP, glusterd_handle_brick_op, NULL, 0, DRC_NA}, [GLUSTERD_JARVIS_COMMIT] = { "COMMIT", GLUSTERD_JARVIS_COMMIT, glusterd_handle_commit, NULL, 0, DRC_NA}, [GLUSTERD_JARVIS_POST_VALIDATE] = { "POST_VAL", GLUSTERD_JARVIS_POST_VALIDATE, glusterd_handle_post_validate, NULL, 0, DRC_NA}, [GLUSTERD_JARVIS_VOLUME_UNLOCK] = { "VOL_UNLOCK", GLUSTERD_JARVIS_VOLUME_LOCK, glusterd_handle_vol_unlock, NULL, 0, DRC_NA}, }; struct rpcsvc_program gd_jarvis_mgmt_prog = { .progname = "Glusterd Jarvis Mgmt", .prognum = GD_JARVIS_MGMT_PROGRAM, .progver = GD_JARVIS_MGMT_VERSION, .numactors = GLUSTERD_JARVIS_MAXVALUE, .actors = gd_jarvis_mgmt_actors, .synctask = _gf_true, };