From 5adb10b9ac1c634334f29732e062b12d747ae8c5 Mon Sep 17 00:00:00 2001 From: Soumya Koduri Date: Wed, 7 May 2014 14:05:31 +0530 Subject: libgfapi: Added support to fetch volume info from glusterd and store in glfs object. Defined new APIs in the libgfapi module, given a glfs object, * to send handshake RPC call to glusterd process to fetch UUID of the volume * store it in the glusterfs_context linked to the glfs object. * to parse UUID from its cannonical string format into 16-byte array before sending it to the libgfapi users. Defined a RPC call in glusterd which can be used to query volume related info by other processes using 'clnt_handshake_procs'. Note - Currently this RPC call to glusterd process is used only to fetch UUID. But it can be extended to get other volume related structures as well. In addition to the above, defined a new variable to keep track of such handshake RPCs still in progress to make sure all the corresponding RPC callbacks have been processed before libgfapi returns the glfs object initialized. Also bumping up the GFAPI current version number since there is a new API "glfs_get_volume_id" defined and exposed by libgfapi as part of these changes. Change-Id: I303f76d7177d32d25bdb301b1dbcf5cd73f42807 BUG: 1090363 Signed-off-by: Soumya Koduri Reviewed-on: http://review.gluster.org/7218 Reviewed-by: Anand Avati Reviewed-by: Harshavardhana Tested-by: Gluster Build System Reviewed-by: Vijay Bellur --- api/src/glfs-internal.h | 4 + api/src/glfs-mgmt.c | 258 ++++++++++++++++++++++++- api/src/glfs.h | 32 +++ configure.ac | 4 +- rpc/rpc-lib/src/protocol-common.h | 8 + rpc/xdr/src/glusterfs3-xdr.x | 10 + xlators/mgmt/glusterd/src/glusterd-handshake.c | 137 +++++++++++++ 7 files changed, 445 insertions(+), 8 deletions(-) diff --git a/api/src/glfs-internal.h b/api/src/glfs-internal.h index 14e94e2116f..6fdec961a1c 100644 --- a/api/src/glfs-internal.h +++ b/api/src/glfs-internal.h @@ -80,6 +80,7 @@ typedef int (*glfs_init_cbk) (struct glfs *fs, int ret); struct glfs { char *volname; + uuid_t vol_uuid; glusterfs_ctx_t *ctx; @@ -222,4 +223,7 @@ dict_t * dict_for_key_value (const char *name, const char *value, size_t size); int glfs_getxattr_process (void *value, size_t size, dict_t *xattr, const char *name); +/* Sends RPC call to glusterd to fetch required volume info */ +int glfs_get_volume_info (struct glfs *fs); + #endif /* !_GLFS_INTERNAL_H */ diff --git a/api/src/glfs-mgmt.c b/api/src/glfs-mgmt.c index 5c7e8b2fc2a..bb82dc9a188 100644 --- a/api/src/glfs-mgmt.c +++ b/api/src/glfs-mgmt.c @@ -22,6 +22,7 @@ #endif /* _CONFIG_H */ #include "glusterfs.h" +#include "glfs.h" #include "stack.h" #include "dict.h" #include "event.h" @@ -40,8 +41,9 @@ #include "glfs-internal.h" #include "glfs-mem-types.h" - int glfs_volfile_fetch (struct glfs *fs); +int32_t glfs_get_volume_info_rpc (call_frame_t *frame, xlator_t *this, + struct glfs *fs); int glfs_process_volfp (struct glfs *fs, FILE *fp) @@ -136,6 +138,7 @@ char *clnt_handshake_procs[GF_HNDSK_MAXVALUE] = { [GF_HNDSK_GETSPEC] = "GETSPEC", [GF_HNDSK_PING] = "PING", [GF_HNDSK_EVENT_NOTIFY] = "EVENTNOTIFY", + [GF_HNDSK_GET_VOLUME_INFO] = "GETVOLUMEINFO", }; rpc_clnt_prog_t clnt_handshake_prog = { @@ -202,6 +205,249 @@ out: return ret; } +/* + * Callback routine for 'GF_HNDSK_GET_VOLUME_INFO' rpc request + */ +int +mgmt_get_volinfo_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + int ret = 0; + char *volume_id_str = NULL; + dict_t *dict = NULL; + char key[1024] = {0}; + gf_get_volume_info_rsp rsp = {0,}; + call_frame_t *frame = NULL; + glusterfs_ctx_t *ctx = NULL; + struct glfs *fs = NULL; + struct syncargs *args; + + frame = myframe; + ctx = frame->this->ctx; + args = frame->local; + + if (!ctx) { + gf_log (frame->this->name, GF_LOG_ERROR, "NULL context"); + errno = EINVAL; + ret = -1; + goto out; + } + + fs = ((xlator_t *)ctx->master)->private; + + if (-1 == req->rpc_status) { + gf_log (frame->this->name, GF_LOG_ERROR, + "GET_VOLUME_INFO RPC call is not successfull"); + errno = EINVAL; + ret = -1; + goto out; + } + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_get_volume_info_rsp); + + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, + "Failed to decode xdr response for GET_VOLUME_INFO"); + goto out; + } + + gf_log (frame->this->name, GF_LOG_DEBUG, + "Received resp to GET_VOLUME_INFO RPC: %d", rsp.op_ret); + + if (rsp.op_ret == -1) { + errno = rsp.op_errno; + ret = -1; + goto out; + } + + if (!rsp.dict.dict_len) { + gf_log (frame->this->name, GF_LOG_ERROR, + "Response received for GET_VOLUME_INFO RPC call is not valid"); + ret = -1; + errno = EINVAL; + goto out; + } + + dict = dict_new (); + + if (!dict) { + ret = -1; + errno = ENOMEM; + goto out; + } + + ret = dict_unserialize (rsp.dict.dict_val, + rsp.dict.dict_len, + &dict); + + if (ret) { + errno = ENOMEM; + goto out; + } + + snprintf (key, sizeof (key), "volume_id"); + ret = dict_get_str (dict, key, &volume_id_str); + if (ret) { + errno = EINVAL; + goto out; + } + + ret = 0; +out: + if (volume_id_str) { + gf_log (frame->this->name, GF_LOG_DEBUG, + "Volume Id: %s", volume_id_str); + pthread_mutex_lock (&fs->mutex); + uuid_parse (volume_id_str, fs->vol_uuid); + pthread_mutex_unlock (&fs->mutex); + } + + if (ret) { + gf_log (frame->this->name, GF_LOG_ERROR, + "In GET_VOLUME_INFO cbk, received error: %s", + strerror(errno)); + } + + if (dict) + dict_destroy (dict); + + if (rsp.dict.dict_val) + free (rsp.dict.dict_val); + + if (rsp.op_errstr && *rsp.op_errstr) + free (rsp.op_errstr); + + gf_log (frame->this->name, GF_LOG_DEBUG, "Returning: %d", ret); + + __wake (args); + + return ret; +} + +int +glfs_get_volumeid (struct glfs *fs, char *volid, size_t size) +{ + /* TODO: Define a global macro to store UUID size */ + size_t uuid_size = 16; + + pthread_mutex_lock (&fs->mutex); + { + /* check if the volume uuid is initialized */ + if (!uuid_is_null (fs->vol_uuid)) { + pthread_mutex_unlock (&fs->mutex); + goto done; + } + } + pthread_mutex_unlock (&fs->mutex); + + /* Need to fetch volume_uuid */ + glfs_get_volume_info (fs); + + if (uuid_is_null (fs->vol_uuid)) { + gf_log (THIS->name, GF_LOG_ERROR, "Unable to fetch volume UUID"); + return -1; + } + +done: + if (!volid || !size) { + gf_log (THIS->name, GF_LOG_DEBUG, "volumeid/size is null"); + return uuid_size; + } + + if (size < uuid_size) { + gf_log (THIS->name, GF_LOG_ERROR, "Insufficient size passed"); + errno = ERANGE; + return -1; + } + + memcpy (volid, fs->vol_uuid, uuid_size); + + gf_log (THIS->name, GF_LOG_INFO, "volume uuid: %s", volid); + + return uuid_size; +} + +int +glfs_get_volume_info (struct glfs *fs) +{ + call_frame_t *frame = NULL; + glusterfs_ctx_t *ctx = NULL; + struct syncargs args = {0, }; + int ret = 0; + + ctx = fs->ctx; + frame = create_frame (THIS, ctx->pool); + frame->local = &args; + + __yawn ((&args)); + + ret = glfs_get_volume_info_rpc (frame, THIS, fs); + if (ret) + goto out; + + __yield ((&args)); + + frame->local = NULL; + STACK_DESTROY (frame->root); + +out: + return ret; +} + +int32_t +glfs_get_volume_info_rpc (call_frame_t *frame, xlator_t *this, + struct glfs *fs) +{ + gf_get_volume_info_req req = {{0,}}; + int ret = 0; + glusterfs_ctx_t *ctx = NULL; + dict_t *dict = NULL; + int32_t flags = 0; + + if (!frame || !this || !fs) { + ret = -1; + goto out; + } + + ctx = fs->ctx; + + dict = dict_new (); + if (!dict) { + ret = -1; + goto out; + } + + if (fs->volname) { + ret = dict_set_str (dict, "volname", fs->volname); + if (ret) + goto out; + } + + // Set the flags for the fields which we are interested in + flags = (int32_t)GF_GET_VOLUME_UUID; //ctx->flags; + ret = dict_set_int32 (dict, "flags", flags); + if (ret) { + gf_log (frame->this->name, GF_LOG_ERROR, "failed to set flags"); + goto out; + } + + ret = dict_allocate_and_serialize (dict, &req.dict.dict_val, + &req.dict.dict_len); + + + ret = mgmt_submit_request (&req, frame, ctx, &clnt_handshake_prog, + GF_HNDSK_GET_VOLUME_INFO, + mgmt_get_volinfo_cbk, + (xdrproc_t)xdr_gf_get_volume_info_req); +out: + if (dict) { + dict_unref (dict); + } + + GF_FREE (req.dict.dict_val); + + return ret; +} static int glusterfs_oldvolfile_update (struct glfs *fs, char *volfile, ssize_t size) @@ -514,12 +760,12 @@ mgmt_rpc_notify (struct rpc_clnt *rpc, void *mydata, rpc_clnt_event_t event, /* Exit the process.. there are some wrong options */ gf_log ("glfs-mgmt", GF_LOG_ERROR, "failed to fetch volume file (key:%s)", - ctx->cmd_args.volfile_id); - errno = EINVAL; - glfs_init_done (fs, -1); - } + ctx->cmd_args.volfile_id); + errno = EINVAL; + glfs_init_done (fs, -1); + } - break; + break; default: break; } diff --git a/api/src/glfs.h b/api/src/glfs.h index 4344df24dc7..8f1d09d1094 100644 --- a/api/src/glfs.h +++ b/api/src/glfs.h @@ -285,6 +285,38 @@ int glfs_fini (glfs_t *fs) __THROW; ssize_t glfs_get_volfile (glfs_t *fs, void *buf, size_t len) __THROW; + +/* + SYNOPSIS + + glfs_get_volumeid: Copy the Volume UUID stored in the glfs object fs. + + DESCRIPTION + + This function when invoked for the first time sends RPC call to the + the management server (glusterd) to fetch volume uuid and stores it + in the glusterfs_context linked to the glfs object fs which can be used + in the subsequent calls. Later it parses that UUID to convert it from + cannonical string format into an opaque byte array and copy it into + the volid array. Incase if either of the input parameters, volid or size, + is NULL, number of bytes required to copy the volume UUID is returned. + + PARAMETERS + + @fs: The 'virtual mount' object to be used to retrieve and store + volume's UUID. + @volid: Pointer to a place for the volume UUID to be stored + @size: Length of @volid + + RETURN VALUES + + -1 : Failure. @errno will be set with the type of failure. + Others : length of the volume UUID stored. +*/ + +int glfs_get_volumeid (struct glfs *fs, char *volid, size_t size); + + /* * FILE OPERATION * diff --git a/configure.ac b/configure.ac index b824cf92178..d16bcb12363 100644 --- a/configure.ac +++ b/configure.ac @@ -995,7 +995,7 @@ AM_CONDITIONAL([GF_DARWIN_HOST_OS], test "${GF_HOST_OS}" = "GF_DARWIN_HOST_OS") AM_CONDITIONAL([GF_INSTALL_VAR_LIB_GLUSTERD], test ! -d ${localstatedir}/lib/glusterd && test -d ${sysconfdir}/glusterd ) dnl pkg-config versioning -GFAPI_VERSION="6.0.0" +GFAPI_VERSION="7.0.0" LIBGFCHANGELOG_VERSION="0.0.1" AC_SUBST(GFAPI_VERSION) AC_SUBST(LIBGFCHANGELOG_VERSION) @@ -1005,7 +1005,7 @@ LIBGFXDR_LT_VERSION="0:1:0" LIBGFRPC_LT_VERSION="0:1:0" LIBGLUSTERFS_LT_VERSION="0:1:0" LIBGFCHANGELOG_LT_VERSION="0:1:0" -GFAPI_LT_VERSION="6:0:0" +GFAPI_LT_VERSION="7:0:0" AC_SUBST(LIBGFXDR_LT_VERSION) AC_SUBST(LIBGFRPC_LT_VERSION) AC_SUBST(LIBGLUSTERFS_LT_VERSION) diff --git a/rpc/rpc-lib/src/protocol-common.h b/rpc/rpc-lib/src/protocol-common.h index 02e0d244a4f..00ba2d1fc95 100644 --- a/rpc/rpc-lib/src/protocol-common.h +++ b/rpc/rpc-lib/src/protocol-common.h @@ -69,6 +69,7 @@ enum gf_handshake_procnum { GF_HNDSK_PING, GF_HNDSK_SET_LK_VER, GF_HNDSK_EVENT_NOTIFY, + GF_HNDSK_GET_VOLUME_INFO, GF_HNDSK_MAXVALUE, }; @@ -255,6 +256,13 @@ enum glusterd_mgmt_v3_procnum { typedef struct gf_gsync_detailed_status_ gf_gsync_status_t; +enum gf_get_volume_info_type { + GF_GET_VOLUME_NONE, /* 0 */ + GF_GET_VOLUME_UUID +}; + +typedef enum gf_get_volume_info_type gf_get_volume_info_type; + #define GLUSTER_HNDSK_PROGRAM 14398633 /* Completely random */ #define GLUSTER_HNDSK_VERSION 2 /* 0.0.2 */ diff --git a/rpc/xdr/src/glusterfs3-xdr.x b/rpc/xdr/src/glusterfs3-xdr.x index 72f528e0a1c..b2fa4de9737 100644 --- a/rpc/xdr/src/glusterfs3-xdr.x +++ b/rpc/xdr/src/glusterfs3-xdr.x @@ -653,6 +653,16 @@ struct gfs3_fstat_req { opaque xdata<>; /* Extra data */ } ; + struct gf_get_volume_info_req { + opaque dict<>; /* Extra data */ +} ; + struct gf_get_volume_info_rsp { + int op_ret; + int op_errno; + string op_errstr<>; + opaque dict<>; /* Extra data */ +} ; + struct gf_mgmt_hndsk_req { opaque hndsk<>; } ; diff --git a/xlators/mgmt/glusterd/src/glusterd-handshake.c b/xlators/mgmt/glusterd/src/glusterd-handshake.c index 2b89545c80d..dbaa972937b 100644 --- a/xlators/mgmt/glusterd/src/glusterd-handshake.c +++ b/xlators/mgmt/glusterd/src/glusterd-handshake.c @@ -1001,10 +1001,147 @@ glusterd_mgmt_hndsk_versions_ack (rpcsvc_request_t *req) __glusterd_mgmt_hndsk_versions_ack); } +int +__server_get_volume_info (rpcsvc_request_t *req) +{ + int ret = -1; + int32_t op_errno = ENOENT; + gf_get_volume_info_req vol_info_req = {{0,}}; + gf_get_volume_info_rsp vol_info_rsp = {0,}; + char *volname = NULL; + glusterd_volinfo_t *volinfo = NULL; + dict_t *dict = NULL; + dict_t *dict_rsp = NULL; + char *volume_id_str = NULL; + int32_t flags = 0; + + ret = xdr_to_generic (req->msg[0], &vol_info_req, + (xdrproc_t)xdr_gf_get_volume_info_req); + if (ret < 0) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + gf_log ("glusterd", GF_LOG_INFO, "Received get volume info req"); + + if (vol_info_req.dict.dict_len) { + /* Unserialize the dictionary */ + dict = dict_new (); + if (!dict) { + gf_log ("", GF_LOG_WARNING, "Out of Memory"); + op_errno = ENOMEM; + ret = -1; + goto out; + } + + ret = dict_unserialize (vol_info_req.dict.dict_val, + vol_info_req.dict.dict_len, + &dict); + if (ret < 0) { + gf_log ("glusterd", GF_LOG_ERROR, + "failed to " + "unserialize req-buffer to dictionary"); + op_errno = -ret; + ret = -1; + goto out; + } else { + dict->extra_stdfree = vol_info_req.dict.dict_val; + } + } + + ret = dict_get_int32 (dict, "flags", &flags); + if (ret) { + gf_log (THIS->name, GF_LOG_ERROR, "failed to get flags"); + op_errno = -ret; + ret = -1; + goto out; + } + + if (!flags) { + //Nothing to query about. Just return success + gf_log (THIS->name, GF_LOG_ERROR, "No flags set"); + ret = 0; + goto out; + } + + ret = dict_get_str (dict, "volname", &volname); + if (ret) { + op_errno = EINVAL; + ret = -1; + goto out; + } + + ret = glusterd_volinfo_find (volname, &volinfo); + if (ret) { + op_errno = EINVAL; + ret = -1; + goto out; + } + + if (flags | (int32_t)GF_GET_VOLUME_UUID) { + volume_id_str = gf_strdup (uuid_utoa (volinfo->volume_id)); + if (!volume_id_str) { + op_errno = ENOMEM; + ret = -1; + goto out; + } + + dict_rsp = dict_new (); + if (!dict_rsp) { + gf_log ("", GF_LOG_WARNING, "Out of Memory"); + op_errno = ENOMEM; + ret = -1; + goto out; + } + ret = dict_set_dynstr (dict_rsp, "volume_id", volume_id_str); + if (ret) { + op_errno = -ret; + ret = -1; + goto out; + } + } + ret = dict_allocate_and_serialize (dict_rsp, &vol_info_rsp.dict.dict_val, + &vol_info_rsp.dict.dict_len); + if (ret) { + op_errno = -ret; + ret = -1; + goto out; + } + +out: + vol_info_rsp.op_ret = ret; + vol_info_rsp.op_errno = op_errno; + vol_info_rsp.op_errstr = ""; + glusterd_submit_reply (req, &vol_info_rsp, NULL, 0, NULL, + (xdrproc_t)xdr_gf_get_volume_info_rsp); + ret = 0; + + if (dict) { + dict_unref (dict); + } + + if (dict_rsp) { + dict_unref (dict_rsp); + } + + if (vol_info_rsp.dict.dict_val) { + GF_FREE (vol_info_rsp.dict.dict_val); + } + return ret; +} + +int +server_get_volume_info (rpcsvc_request_t *req) +{ + return glusterd_big_locked_handler (req, + __server_get_volume_info); +} + rpcsvc_actor_t gluster_handshake_actors[] = { [GF_HNDSK_NULL] = {"NULL", GF_HNDSK_NULL, NULL, NULL, 0, DRC_NA}, [GF_HNDSK_GETSPEC] = {"GETSPEC", GF_HNDSK_GETSPEC, server_getspec, NULL, 0, DRC_NA}, [GF_HNDSK_EVENT_NOTIFY] = {"EVENTNOTIFY", GF_HNDSK_EVENT_NOTIFY, server_event_notify, NULL, 0, DRC_NA}, + [GF_HNDSK_GET_VOLUME_INFO] = {"GETVOLUMEINFO", GF_HNDSK_GET_VOLUME_INFO, server_get_volume_info, NULL, 0, DRC_NA}, }; -- cgit