diff options
| author | Anand Avati <avati@redhat.com> | 2012-07-12 15:37:38 -0700 | 
|---|---|---|
| committer | Anand Avati <avati@redhat.com> | 2012-07-18 12:10:44 -0700 | 
| commit | 2475e0193c4b4a37028bd8168113d6cd6949fe0e (patch) | |
| tree | cc11b8a64601a94ac9c0603e3bc12eee9c796b56 /api/src/glfs-mgmt.c | |
| parent | 162505c019934c13aadf63ed82d4532d5cf5ca82 (diff) | |
gfapi: API/library for accessing gluster volumes
Change-Id: Ie4cbcf91b58218bebf23cf951c313aceeb29f311
BUG: 839950
Signed-off-by: Anand Avati <avati@redhat.com>
Reviewed-on: http://review.gluster.com/3664
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Jeff Darcy <jdarcy@redhat.com>
Reviewed-by: Kaleb KEITHLEY <kkeithle@redhat.com>
Reviewed-by: Bharata B Rao <bharata.rao@gmail.com>
Diffstat (limited to 'api/src/glfs-mgmt.c')
| -rw-r--r-- | api/src/glfs-mgmt.c | 629 | 
1 files changed, 629 insertions, 0 deletions
diff --git a/api/src/glfs-mgmt.c b/api/src/glfs-mgmt.c new file mode 100644 index 00000000000..526d1ae4d7d --- /dev/null +++ b/api/src/glfs-mgmt.c @@ -0,0 +1,629 @@ +/* +  Copyright (c) 2012 Red Hat, Inc. <http://www.redhat.com> +  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. +*/ + + +#include <stdio.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <stdlib.h> +#include <signal.h> +#include <pthread.h> + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif /* _CONFIG_H */ + +#include "glusterfs.h" +#include "stack.h" +#include "dict.h" +#include "event.h" +#include "defaults.h" + +#include "rpc-clnt.h" +#include "protocol-common.h" +#include "glusterfs3.h" +#include "portmap-xdr.h" +#include "xdr-generic.h" + +#include "syncop.h" +#include "xlator.h" + +#include "glfs-internal.h" + + +int glfs_volfile_fetch (struct glfs *fs); + +int +glfs_process_volfp (struct glfs *fs, FILE *fp) +{ +	glusterfs_graph_t  *graph = NULL; +	int		    ret = -1; +	xlator_t	   *trav = NULL; +	glusterfs_ctx_t	   *ctx = NULL; + +	ctx = fs->ctx; +	graph = glusterfs_graph_construct (fp); +	if (!graph) { +		gf_log ("glfs", GF_LOG_ERROR, "failed to construct the graph"); +		goto out; +	} + +	for (trav = graph->first; trav; trav = trav->next) { +		if (strcmp (trav->type, "mount/fuse") == 0) { +			gf_log ("glfs", GF_LOG_ERROR, +				"fuse xlator cannot be specified " +				"in volume file"); +			goto out; +		} +	} + +	ret = glusterfs_graph_prepare (graph, ctx); +	if (ret) { +		glusterfs_graph_destroy (graph); +		goto out; +	} + +	ret = glusterfs_graph_activate (graph, ctx); + +	if (ret) { +		glusterfs_graph_destroy (graph); +		goto out; +	} + +	ret = 0; +out: +	if (fp) +		fclose (fp); + +	if (!ctx->active) { +		ret = -1; +	} + +	return ret; +} + + +int +mgmt_cbk_spec (struct rpc_clnt *rpc, void *mydata, void *data) +{ +	struct glfs *fs = NULL; +	xlator_t    *this = NULL; + +	this = mydata; +	fs = this->private; + +	glfs_volfile_fetch (fs); + +	return 0; +} + + +int +mgmt_cbk_event (struct rpc_clnt *rpc, void *mydata, void *data) +{ +	return 0; +} + + +rpcclnt_cb_actor_t gluster_cbk_actors[] = { +	[GF_CBK_FETCHSPEC] = {"FETCHSPEC", GF_CBK_FETCHSPEC, mgmt_cbk_spec }, +	[GF_CBK_EVENT_NOTIFY] = {"EVENTNOTIFY", GF_CBK_EVENT_NOTIFY, +				 mgmt_cbk_event}, +}; + + +struct rpcclnt_cb_program mgmt_cbk_prog = { +	.progname  = "GlusterFS Callback", +	.prognum   = GLUSTER_CBK_PROGRAM, +	.progver   = GLUSTER_CBK_VERSION, +	.actors	   = gluster_cbk_actors, +	.numactors = GF_CBK_MAXVALUE, +}; + +char *clnt_handshake_procs[GF_HNDSK_MAXVALUE] = { +	[GF_HNDSK_NULL]		= "NULL", +	[GF_HNDSK_SETVOLUME]	= "SETVOLUME", +	[GF_HNDSK_GETSPEC]	= "GETSPEC", +	[GF_HNDSK_PING]		= "PING", +	[GF_HNDSK_EVENT_NOTIFY] = "EVENTNOTIFY", +}; + +rpc_clnt_prog_t clnt_handshake_prog = { +	.progname  = "GlusterFS Handshake", +	.prognum   = GLUSTER_HNDSK_PROGRAM, +	.progver   = GLUSTER_HNDSK_VERSION, +	.procnames = clnt_handshake_procs, +}; + + +int +mgmt_submit_request (void *req, call_frame_t *frame, +		     glusterfs_ctx_t *ctx, +		     rpc_clnt_prog_t *prog, int procnum, +		     fop_cbk_fn_t cbkfn, xdrproc_t xdrproc) +{ +	int			ret	    = -1; +	int			count	   = 0; +	struct iovec		iov	    = {0, }; +	struct iobuf		*iobuf = NULL; +	struct iobref		*iobref = NULL; +	ssize_t			xdr_size = 0; + +	iobref = iobref_new (); +	if (!iobref) { +		goto out; +	} + +	if (req) { +		xdr_size = xdr_sizeof (xdrproc, req); + +		iobuf = iobuf_get2 (ctx->iobuf_pool, xdr_size); +		if (!iobuf) { +			goto out; +		}; + +		iobref_add (iobref, iobuf); + +		iov.iov_base = iobuf->ptr; +		iov.iov_len  = iobuf_pagesize (iobuf); + +		/* Create the xdr payload */ +		ret = xdr_serialize_generic (iov, req, xdrproc); +		if (ret == -1) { +			gf_log (THIS->name, GF_LOG_WARNING, +				"failed to create XDR payload"); +			goto out; +		} +		iov.iov_len = ret; +		count = 1; +	} + +	/* Send the msg */ +	ret = rpc_clnt_submit (ctx->mgmt, prog, procnum, cbkfn, +			       &iov, count, +			       NULL, 0, iobref, frame, NULL, 0, NULL, 0, NULL); + +out: +	if (iobref) +		iobref_unref (iobref); + +	if (iobuf) +		iobuf_unref (iobuf); +	return ret; +} + + +/* XXX: move these into @ctx */ +static char oldvolfile[131072]; +static int oldvollen = 0; + +static int +xlator_equal_rec (xlator_t *xl1, xlator_t *xl2) +{ +	xlator_list_t *trav1 = NULL; +	xlator_list_t *trav2 = NULL; +	int	       ret   = 0; + +	if (xl1 == NULL || xl2 == NULL) { +		gf_log ("xlator", GF_LOG_DEBUG, "invalid argument"); +		return -1; +	} + +	trav1 = xl1->children; +	trav2 = xl2->children; + +	while (trav1 && trav2) { +		ret = xlator_equal_rec (trav1->xlator, trav2->xlator); +		if (ret) { +			gf_log ("glfs-mgmt", GF_LOG_DEBUG, +				"xlators children not equal"); +			goto out; +		} + +		trav1 = trav1->next; +		trav2 = trav2->next; +	} + +	if (trav1 || trav2) { +		ret = -1; +		goto out; +	} + +	if (strcmp (xl1->name, xl2->name)) { +		ret = -1; +		goto out; +	} +out : +	return ret; +} + + +static gf_boolean_t +is_graph_topology_equal (glusterfs_graph_t *graph1, +			 glusterfs_graph_t *graph2) +{ +	xlator_t    *trav1    = NULL; +	xlator_t    *trav2    = NULL; +	gf_boolean_t ret      = _gf_true; + +	trav1 = graph1->first; +	trav2 = graph2->first; + +	ret = xlator_equal_rec (trav1, trav2); + +	if (ret) { +		gf_log ("glfs-mgmt", GF_LOG_DEBUG, +			"graphs are not equal"); +		ret = _gf_false; +		goto out; +	} + +	ret = _gf_true; +	gf_log ("glfs-mgmt", GF_LOG_DEBUG, +		"graphs are equal"); + +out: +	return ret; +} + + +/* Function has 3types of return value 0, -ve , 1 + *   return 0	       =======> reconfiguration of options has succeeded + *   return 1	       =======> the graph has to be reconstructed and all the xlators should be inited + *   return -1(or -ve) =======> Some Internal Error occurred during the operation + */ +static int +glusterfs_volfile_reconfigure (struct glfs *fs, FILE *newvolfile_fp) +{ +	glusterfs_graph_t *oldvolfile_graph = NULL; +	glusterfs_graph_t *newvolfile_graph = NULL; +	FILE		  *oldvolfile_fp    = NULL; +	glusterfs_ctx_t	  *ctx		    = NULL; + +	int ret = -1; + +	oldvolfile_fp = tmpfile (); +	if (!oldvolfile_fp) +		goto out; + +	if (!oldvollen) { +		ret = 1; // Has to call INIT for the whole graph +		goto out; +	} +	fwrite (oldvolfile, oldvollen, 1, oldvolfile_fp); +	fflush (oldvolfile_fp); +	if (ferror (oldvolfile_fp)) { +		goto out; +	} + +	oldvolfile_graph = glusterfs_graph_construct (oldvolfile_fp); +	if (!oldvolfile_graph) { +		goto out; +	} + +	newvolfile_graph = glusterfs_graph_construct (newvolfile_fp); +	if (!newvolfile_graph) { +		goto out; +	} + +	if (!is_graph_topology_equal (oldvolfile_graph, +				      newvolfile_graph)) { + +		ret = 1; +		gf_log ("glfs-mgmt", GF_LOG_DEBUG, +			"Graph topology not equal(should call INIT)"); +		goto out; +	} + +	gf_log ("glfs-mgmt", GF_LOG_DEBUG, +		"Only options have changed in the new " +		"graph"); + +	ctx = fs->ctx; + +	if (!ctx) { +		gf_log ("glfs-mgmt", GF_LOG_ERROR, +			"glusterfs_ctx_get() returned NULL"); +		goto out; +	} + +	oldvolfile_graph = ctx->active; + +	if (!oldvolfile_graph) { +		gf_log ("glfs-mgmt", GF_LOG_ERROR, +			"glusterfs_ctx->active is NULL"); +		goto out; +	} + +	/* */ +	ret = glusterfs_graph_reconfigure (oldvolfile_graph, +					   newvolfile_graph); +	if (ret) { +		gf_log ("glfs-mgmt", GF_LOG_DEBUG, +			"Could not reconfigure new options in old graph"); +		goto out; +	} + +	ret = 0; +out: +	if (oldvolfile_fp) +		fclose (oldvolfile_fp); + +	return ret; +} + + +int +mgmt_getspec_cbk (struct rpc_req *req, struct iovec *iov, int count, +		  void *myframe) +{ +	gf_getspec_rsp		 rsp   = {0,}; +	call_frame_t		*frame = NULL; +	glusterfs_ctx_t		*ctx = NULL; +	int			 ret   = 0; +	ssize_t			 size = 0; +	FILE			*tmpfp = NULL; +	struct glfs		*fs = NULL; + +	frame = myframe; +	ctx = frame->this->ctx; +	fs = ((xlator_t *)ctx->master)->private; + +	if (-1 == req->rpc_status) { +		ret = -1; +		goto out; +	} + +	ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_getspec_rsp); +	if (ret < 0) { +		gf_log (frame->this->name, GF_LOG_ERROR, "XDR decoding error"); +		ret   = -1; +		goto out; +	} + +	if (-1 == rsp.op_ret) { +		gf_log (frame->this->name, GF_LOG_ERROR, +			"failed to get the 'volume file' from server"); +		ret = -1; +		goto out; +	} + +	ret = 0; +	size = rsp.op_ret; + +	if (size == oldvollen && (memcmp (oldvolfile, rsp.spec, size) == 0)) { +		gf_log (frame->this->name, GF_LOG_INFO, +			"No change in volfile, continuing"); +		goto out; +	} + +	tmpfp = tmpfile (); +	if (!tmpfp) { +		ret = -1; +		goto out; +	} + +	fwrite (rsp.spec, size, 1, tmpfp); +	fflush (tmpfp); +	if (ferror (tmpfp)) { +		ret = -1; +		goto out; +	} + +	/*  Check if only options have changed. No need to reload the +	*  volfile if topology hasn't changed. +	*  glusterfs_volfile_reconfigure returns 3 possible return states +	*  return 0	     =======> reconfiguration of options has succeeded +	*  return 1	     =======> the graph has to be reconstructed and all the xlators should be inited +	*  return -1(or -ve) =======> Some Internal Error occurred during the operation +	*/ + +	ret = glusterfs_volfile_reconfigure (fs, tmpfp); +	if (ret == 0) { +		gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG, +			"No need to re-load volfile, reconfigure done"); +		oldvollen = size; +		memcpy (oldvolfile, rsp.spec, size); +		goto out; +	} + +	if (ret < 0) { +		gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG, +			"Reconfigure failed !!"); +		goto out; +	} + +	ret = glfs_process_volfp (fs, tmpfp); +	/* tmpfp closed */ +	tmpfp = NULL; +	if (ret) +		goto out; + +	oldvollen = size; +	memcpy (oldvolfile, rsp.spec, size); + +out: +	STACK_DESTROY (frame->root); + +	if (rsp.spec) +		free (rsp.spec); + +	if (ret && ctx && !ctx->active) { +		/* Do it only for the first time */ +		/* Failed to get the volume file, something wrong, +		   restart the process */ +		gf_log ("glfs-mgmt", GF_LOG_ERROR, +			"failed to fetch volume file (key:%s)", +			ctx->cmd_args.volfile_id); +	} + +	if (tmpfp) +		fclose (tmpfp); + +	return 0; +} + + +int +glfs_volfile_fetch (struct glfs *fs) +{ +	cmd_args_t	 *cmd_args = NULL; +	gf_getspec_req	  req = {0, }; +	int		  ret = 0; +	call_frame_t	 *frame = NULL; +	glusterfs_ctx_t	 *ctx = NULL; + +	ctx = fs->ctx; +	cmd_args = &ctx->cmd_args; + +	frame = create_frame (THIS, ctx->pool); + +	req.key = cmd_args->volfile_id; +	req.flags = 0; + +	ret = mgmt_submit_request (&req, frame, ctx, &clnt_handshake_prog, +				   GF_HNDSK_GETSPEC, mgmt_getspec_cbk, +				   (xdrproc_t)xdr_gf_getspec_req); +	return ret; +} + + +static int +mgmt_rpc_notify (struct rpc_clnt *rpc, void *mydata, rpc_clnt_event_t event, +		 void *data) +{ +	xlator_t	*this = NULL; +	cmd_args_t	*cmd_args = NULL; +	glusterfs_ctx_t *ctx = NULL; +	struct glfs	 *fs = NULL; +	int		 ret = 0; + +	this = mydata; +	ctx = this->ctx; +	fs = ((xlator_t *)ctx->master)->private; +	cmd_args = &ctx->cmd_args; + +	switch (event) { +	case RPC_CLNT_DISCONNECT: +		if (!ctx->active) { +			cmd_args->max_connect_attempts--; +			gf_log ("glfs-mgmt", GF_LOG_ERROR, +				"failed to connect with remote-host: %s", +				strerror (errno)); +			gf_log ("glfs-mgmt", GF_LOG_INFO, +				"%d connect attempts left", +				cmd_args->max_connect_attempts); +			if (0 >= cmd_args->max_connect_attempts) +				glfs_init_done (fs, -1); +				break; +		} +		break; +	case RPC_CLNT_CONNECT: +		rpc_clnt_set_connected (&((struct rpc_clnt*)ctx->mgmt)->conn); + +		ret = glfs_volfile_fetch (fs); +		if (ret && ctx && (ctx->active == NULL)) { +			/* Do it only for the first time */ +			/* Exit the process.. there is some wrong options */ +			gf_log ("glfs-mgmt", GF_LOG_ERROR, +				"failed to fetch volume file (key:%s)", +				ctx->cmd_args.volfile_id); +			glfs_init_done (fs, -1); +		} + +		break; +	default: +		break; +	} + +	return 0; +} + + +int +glusterfs_mgmt_notify (int32_t op, void *data, ...) +{ +	int ret = 0; + +	switch (op) +	{ +		case GF_EN_DEFRAG_STATUS: +			break; + +		default: +			break; +	} + +	return ret; +} + + +int +glfs_mgmt_init (struct glfs *fs) +{ +	cmd_args_t		*cmd_args = NULL; +	struct rpc_clnt		*rpc = NULL; +	dict_t			*options = NULL; +	int			ret = -1; +	int			port = GF_DEFAULT_BASE_PORT; +	char			*host = NULL; +	glusterfs_ctx_t		*ctx = NULL; + +	ctx = fs->ctx; +	cmd_args = &ctx->cmd_args; + +	if (ctx->mgmt) +		return 0; + +	if (cmd_args->volfile_server_port) +		port = cmd_args->volfile_server_port; + +	host = "localhost"; +	if (cmd_args->volfile_server) +		host = cmd_args->volfile_server; + +	ret = rpc_transport_inet_options_build (&options, host, port); +	if (ret) +		goto out; + +	rpc = rpc_clnt_new (options, THIS->ctx, THIS->name, 8); +	if (!rpc) { +		ret = -1; +		gf_log (THIS->name, GF_LOG_WARNING, +			"failed to create rpc clnt"); +		goto out; +	} + +	ret = rpc_clnt_register_notify (rpc, mgmt_rpc_notify, THIS); +	if (ret) { +		gf_log (THIS->name, GF_LOG_WARNING, +			"failed to register notify function"); +		goto out; +	} + +	ret = rpcclnt_cbk_program_register (rpc, &mgmt_cbk_prog, THIS); +	if (ret) { +		gf_log (THIS->name, GF_LOG_WARNING, +			"failed to register callback function"); +		goto out; +	} + +	ctx->notify = glusterfs_mgmt_notify; + +	/* This value should be set before doing the 'rpc_clnt_start()' as +	   the notify function uses this variable */ +	ctx->mgmt = rpc; + +	ret = rpc_clnt_start (rpc); +out: +	return ret; +} +  | 
