summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cli/src/cli-cmd-parser.c64
-rw-r--r--cli/src/cli-cmd-volume.c60
-rw-r--r--cli/src/cli-rpc-ops.c113
-rw-r--r--cli/src/cli.h3
-rw-r--r--rpc/rpc-lib/src/protocol-common.h1
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-handler.c68
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-mem-types.h3
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-op-sm.c22
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-rpc-ops.c1
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-utils.c20
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-utils.h3
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-volgen.c21
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-volume-ops.c393
-rw-r--r--xlators/mgmt/glusterd/src/glusterd.h5
14 files changed, 754 insertions, 23 deletions
diff --git a/cli/src/cli-cmd-parser.c b/cli/src/cli-cmd-parser.c
index 090a7246913..b4c86bf1abd 100644
--- a/cli/src/cli-cmd-parser.c
+++ b/cli/src/cli-cmd-parser.c
@@ -2032,3 +2032,67 @@ out:
gf_log ("cli", GF_LOG_ERROR, "Error parsing dumpoptions");
return ret;
}
+
+int
+cli_cmd_volume_clrlks_opts_parse (const char **words, int wordcount,
+ dict_t **options)
+{
+ int ret = -1;
+ int i = 0;
+ dict_t *dict = NULL;
+ char *kind_opts[4] = {"blocked", "granted", "all", NULL};
+ char *types[4] = {"inode", "entry", "posix", NULL};
+ char *free_ptr = NULL;
+
+ dict = dict_new ();
+ if (!dict)
+ goto out;
+
+ if (strcmp (words[4], "kind"))
+ goto out;
+
+ for (i = 0; kind_opts[i]; i++) {
+ if (!strcmp (words[5], kind_opts[i])) {
+ free_ptr = gf_strdup (words[5]);
+ ret = dict_set_dynstr (dict, "kind", free_ptr);
+ if (ret)
+ goto out;
+ free_ptr = NULL;
+ break;
+ }
+ }
+ if (i == 3)
+ goto out;
+
+ ret = -1;
+ for (i = 0; types[i]; i++) {
+ if (!strcmp (words[6], types[i])) {
+ free_ptr = gf_strdup (words[6]);
+ ret = dict_set_dynstr (dict, "type", free_ptr);
+ if (ret)
+ goto out;
+ free_ptr = NULL;
+ break;
+ }
+ }
+ if (i == 3)
+ goto out;
+
+ if (wordcount == 8) {
+ free_ptr = gf_strdup (words[7]);
+ ret = dict_set_dynstr (dict, "opts", free_ptr);
+ if (ret)
+ goto out;
+ free_ptr = NULL;
+ }
+
+ ret = 0;
+ *options = dict;
+out:
+ if (ret) {
+ GF_FREE (free_ptr);
+ dict_unref (dict);
+ }
+
+ return ret;
+}
diff --git a/cli/src/cli-cmd-volume.c b/cli/src/cli-cmd-volume.c
index 9c7a43b9f85..41007cb7b2d 100644
--- a/cli/src/cli-cmd-volume.c
+++ b/cli/src/cli-cmd-volume.c
@@ -1681,6 +1681,60 @@ out:
return ret;
}
+int
+cli_cmd_volume_clearlocks_cbk (struct cli_state *state,
+ struct cli_cmd_word *word,
+ const char **words, int wordcount)
+{
+ int ret = -1;
+ rpc_clnt_procedure_t *proc = NULL;
+ call_frame_t *frame = NULL;
+ dict_t *options = NULL;
+ int sent = 0;
+ int parse_error = 0;
+
+ frame = create_frame (THIS, THIS->ctx->pool);
+ if (!frame)
+ goto out;
+
+ if (wordcount < 7 || wordcount > 8) {
+ cli_usage_out (word->pattern);
+ parse_error = 1;
+ goto out;
+ }
+
+ ret = cli_cmd_volume_clrlks_opts_parse (words, wordcount, &options);
+ if (ret) {
+ parse_error = 1;
+ gf_log ("cli", GF_LOG_ERROR, "Error parsing "
+ "clear-locks options");
+ cli_out ("Error parsing options");
+ cli_usage_out (word->pattern);
+ }
+
+ ret = dict_set_str (options, "volname", (char *)words[2]);
+ if (ret)
+ goto out;
+
+ ret = dict_set_str (options, "path", (char *)words[3]);
+ if (ret)
+ goto out;
+
+ proc = &cli_rpc_prog->proctable[GLUSTER_CLI_CLRLOCKS_VOLUME];
+ if (proc->fn) {
+ ret = proc->fn (frame, THIS, options);
+ }
+
+out:
+ if (ret) {
+ cli_cmd_sent_status_get (&sent);
+ if ((sent == 0) && (parse_error = 0))
+ cli_out ("Volume clear-locks failed");
+ }
+
+ return ret;
+}
+
struct cli_cmd volume_cmds[] = {
{ "volume info [all|<VOLNAME>]",
cli_cmd_volume_info_cbk,
@@ -1785,6 +1839,12 @@ struct cli_cmd volume_cmds[] = {
cli_cmd_volume_list_cbk,
"list all volumes in cluster"},
+ {"volume clear-locks <VOLNAME> <path> kind {blocked|granted|all}"
+ "{inode [range]|entry [basename]|posix [range]}",
+ cli_cmd_volume_clearlocks_cbk,
+ "Clear locks held on path"
+ },
+
{ NULL, NULL, NULL }
};
diff --git a/cli/src/cli-rpc-ops.c b/cli/src/cli-rpc-ops.c
index 8d22f1b1d58..07a2f9fc7be 100644
--- a/cli/src/cli-rpc-ops.c
+++ b/cli/src/cli-rpc-ops.c
@@ -5640,6 +5640,118 @@ out:
return ret;
}
+int32_t
+gf_cli3_1_clearlocks_volume_cbk (struct rpc_req *req, struct iovec *iov,
+ int count, void *myframe)
+{
+ gf_cli_rsp rsp = {0,};
+ int ret = -1;
+ char *lk_summary = NULL;
+ char *volname = NULL;
+ dict_t *dict = NULL;
+
+ if (-1 == req->rpc_status)
+ goto out;
+ ret = xdr_to_generic (*iov, &rsp,
+ (xdrproc_t)xdr_gf_cli_rsp);
+ if (ret < 0) {
+
+ gf_log ("cli", GF_LOG_ERROR, "XDR decoding failed");
+ goto out;
+ }
+ gf_log ("cli", GF_LOG_DEBUG, "Received response to clear-locks");
+
+ if (rsp.op_ret) {
+ cli_out ("Volume clear-locks unsuccessful");
+ cli_out ("%s", rsp.op_errstr);
+
+ } else {
+ if (!rsp.dict.dict_len) {
+ cli_out ("Possibly no locks cleared");
+ ret = 0;
+ goto out;
+ }
+
+ dict = dict_new ();
+
+ if (!dict) {
+ ret = -1;
+ goto out;
+ }
+
+ ret = dict_unserialize (rsp.dict.dict_val,
+ rsp.dict.dict_len,
+ &dict);
+
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR,
+ "Unable to serialize response dictionary");
+ goto out;
+ }
+
+ ret = dict_get_str (dict, "volname", &volname);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Unable to get volname "
+ "from dictionary");
+ goto out;
+ }
+
+ ret = dict_get_str (dict, "lk-summary", &lk_summary);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Unable to get lock "
+ "summary from dictionary");
+ goto out;
+ }
+ cli_out ("Volume clear-locks successful");
+ cli_out ("%s", lk_summary);
+
+ }
+
+ ret = rsp.op_ret;
+
+out:
+ cli_cmd_broadcast_response (ret);
+ return ret;
+}
+
+int32_t
+gf_cli3_1_clearlocks_volume (call_frame_t *frame, xlator_t *this,
+ void *data)
+{
+ gf_cli_req req = {{0,}};
+ dict_t *options = NULL;
+ int ret = -1;
+
+ if (!frame || !this || !data)
+ goto out;
+
+ options = data;
+
+ ret = dict_allocate_and_serialize (options,
+ &req.dict.dict_val,
+ (size_t *)&req.dict.dict_len);
+ if (ret < 0) {
+ gf_log ("cli", GF_LOG_ERROR,
+ "failed to serialize the data");
+
+ goto out;
+ }
+
+ ret = cli_cmd_submit (&req, frame, cli_rpc_prog,
+ GLUSTER_CLI_CLRLOCKS_VOLUME, NULL,
+ this, gf_cli3_1_clearlocks_volume_cbk,
+ (xdrproc_t)xdr_gf_cli_req);
+
+out:
+ if (options)
+ dict_destroy (options);
+ gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret);
+
+ if (req.dict.dict_val)
+ GF_FREE (req.dict.dict_val);
+ return ret;
+}
+
struct rpc_clnt_procedure gluster_cli_actors[GLUSTER_CLI_MAXVALUE] = {
[GLUSTER_CLI_NULL] = {"NULL", NULL },
[GLUSTER_CLI_PROBE] = {"PROBE_QUERY", gf_cli3_1_probe},
@@ -5675,6 +5787,7 @@ struct rpc_clnt_procedure gluster_cli_actors[GLUSTER_CLI_MAXVALUE] = {
[GLUSTER_CLI_HEAL_VOLUME] = {"HEAL_VOLUME", gf_cli3_1_heal_volume},
[GLUSTER_CLI_STATEDUMP_VOLUME] = {"STATEDUMP_VOLUME", gf_cli3_1_statedump_volume},
[GLUSTER_CLI_LIST_VOLUME] = {"LIST_VOLUME", gf_cli3_1_list_volume},
+ [GLUSTER_CLI_CLRLOCKS_VOLUME] = {"CLEARLOCKS_VOLUME", gf_cli3_1_clearlocks_volume},
};
struct rpc_clnt_program cli_prog = {
diff --git a/cli/src/cli.h b/cli/src/cli.h
index 0814065a0fd..25b17da4968 100644
--- a/cli/src/cli.h
+++ b/cli/src/cli.h
@@ -219,6 +219,9 @@ cli_cmd_log_filename_parse (const char **words, int wordcount, dict_t **options)
int32_t
cli_cmd_volume_statedump_options_parse (const char **words, int wordcount,
dict_t **options);
+int32_t
+cli_cmd_volume_clrlks_opts_parse (const char **words, int wordcount,
+ dict_t **options);
cli_local_t * cli_local_get ();
diff --git a/rpc/rpc-lib/src/protocol-common.h b/rpc/rpc-lib/src/protocol-common.h
index 08f6194a926..6ef4cb702c3 100644
--- a/rpc/rpc-lib/src/protocol-common.h
+++ b/rpc/rpc-lib/src/protocol-common.h
@@ -155,6 +155,7 @@ enum gluster_cli_procnum {
GLUSTER_CLI_HEAL_VOLUME,
GLUSTER_CLI_STATEDUMP_VOLUME,
GLUSTER_CLI_LIST_VOLUME,
+ GLUSTER_CLI_CLRLOCKS_VOLUME,
GLUSTER_CLI_MAXVALUE,
};
diff --git a/xlators/mgmt/glusterd/src/glusterd-handler.c b/xlators/mgmt/glusterd/src/glusterd-handler.c
index 257930720a4..b80164e8d0e 100644
--- a/xlators/mgmt/glusterd/src/glusterd-handler.c
+++ b/xlators/mgmt/glusterd/src/glusterd-handler.c
@@ -2622,6 +2622,73 @@ out:
}
int
+glusterd_handle_cli_clearlocks_volume (rpcsvc_request_t *req)
+{
+ int32_t ret = -1;
+ gf_cli_req cli_req = {{0,}};
+ glusterd_op_t cli_op = GD_OP_CLEARLOCKS_VOLUME;
+ char *volname = NULL;
+ dict_t *dict = NULL;
+
+ GF_ASSERT (req);
+
+ ret = -1;
+ if (!xdr_to_generic (req->msg[0], &cli_req,
+ (xdrproc_t)xdr_gf_cli_req)) {
+ req->rpc_err = GARBAGE_ARGS;
+ goto out;
+ }
+
+ if (cli_req.dict.dict_len) {
+ dict = dict_new ();
+
+ 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");
+ goto out;
+ }
+
+ } else {
+ ret = -1;
+ gf_log (THIS->name, GF_LOG_ERROR, "Empty cli request.");
+ goto out;
+ }
+
+ ret = dict_get_str (dict, "volname", &volname);
+ if (ret) {
+ gf_log (THIS->name, GF_LOG_ERROR, "failed to get volname");
+ goto out;
+ }
+
+ gf_log (THIS->name, GF_LOG_INFO, "Received clear-locks volume req "
+ "for volume %s", volname);
+
+ ret = glusterd_op_begin (req, cli_op, dict);
+
+ gf_cmd_log ("clear-locks", "on volume %s %s", volname,
+ ((0 == ret) ? "SUCCEEDED" : "FAILED"));
+
+out:
+ if (ret && dict)
+ dict_unref (dict);
+
+ glusterd_friend_sm ();
+ glusterd_op_sm ();
+
+ if (ret)
+ ret = glusterd_op_send_cli_response (cli_op, ret, 0, req,
+ NULL, "operation failed");
+ if (cli_req.dict.dict_val)
+ free (cli_req.dict.dict_val);
+
+ return ret;
+}
+
+int
glusterd_brick_rpc_notify (struct rpc_clnt *rpc, void *mydata,
rpc_clnt_event_t event,
void *data)
@@ -2898,6 +2965,7 @@ rpcsvc_actor_t gd_svc_cli_actors[] = {
[GLUSTER_CLI_HEAL_VOLUME] = { "HEAL_VOLUME", GLUSTER_CLI_HEAL_VOLUME, glusterd_handle_cli_heal_volume, NULL, NULL, 0},
[GLUSTER_CLI_STATEDUMP_VOLUME] = {"STATEDUMP_VOLUME", GLUSTER_CLI_STATEDUMP_VOLUME, glusterd_handle_cli_statedump_volume, NULL, NULL, 0},
[GLUSTER_CLI_LIST_VOLUME] = {"LIST_VOLUME", GLUSTER_CLI_LIST_VOLUME, glusterd_handle_cli_list_volume, NULL, NULL, 0},
+ [GLUSTER_CLI_CLRLOCKS_VOLUME] = {"CLEARLOCKS_VOLUME", GLUSTER_CLI_CLRLOCKS_VOLUME, glusterd_handle_cli_clearlocks_volume, NULL, NULL, 0},
};
struct rpcsvc_program gd_svc_cli_prog = {
diff --git a/xlators/mgmt/glusterd/src/glusterd-mem-types.h b/xlators/mgmt/glusterd/src/glusterd-mem-types.h
index 196f5f50bd8..3bb446d1a90 100644
--- a/xlators/mgmt/glusterd/src/glusterd-mem-types.h
+++ b/xlators/mgmt/glusterd/src/glusterd-mem-types.h
@@ -71,7 +71,8 @@ typedef enum gf_gld_mem_types_ {
gf_gld_mt_mount_component = gf_common_mt_end + 45,
gf_gld_mt_mount_spec = gf_common_mt_end + 46,
gf_gld_mt_nodesrv_t = gf_common_mt_end + 47,
- gf_gld_mt_end = gf_common_mt_end + 48,
+ gf_gld_mt_charptr = gf_common_mt_end + 48,
+ gf_gld_mt_end = gf_common_mt_end + 49,
} gf_gld_mem_types_t;
#endif
diff --git a/xlators/mgmt/glusterd/src/glusterd-op-sm.c b/xlators/mgmt/glusterd/src/glusterd-op-sm.c
index d0d280a0923..4a0561d1e6e 100644
--- a/xlators/mgmt/glusterd/src/glusterd-op-sm.c
+++ b/xlators/mgmt/glusterd/src/glusterd-op-sm.c
@@ -1616,6 +1616,7 @@ glusterd_op_build_payload (dict_t **req)
case GD_OP_REBALANCE:
case GD_OP_HEAL_VOLUME:
case GD_OP_STATEDUMP_VOLUME:
+ case GD_OP_CLEARLOCKS_VOLUME:
{
dict_t *dict = ctx;
dict_copy (dict, req_dict);
@@ -2219,8 +2220,16 @@ glusterd_op_ac_commit_op (glusterd_op_sm_event_t *event, void *ctx)
rsp_dict = glusterd_op_init_commit_rsp_dict (req_ctx->op);
if (NULL == rsp_dict)
return -1;
- status = glusterd_op_commit_perform (req_ctx->op, dict, &op_errstr,
- rsp_dict);
+
+ if (GD_OP_CLEARLOCKS_VOLUME == req_ctx->op) {
+ /*clear locks should be run only on
+ * originator glusterd*/
+ status = 0;
+
+ } else {
+ status = glusterd_op_commit_perform (req_ctx->op, dict,
+ &op_errstr, rsp_dict);
+ }
if (status) {
gf_log (THIS->name, GF_LOG_ERROR, "Commit failed: %d", status);
@@ -2370,6 +2379,10 @@ glusterd_op_stage_validate (glusterd_op_t op, dict_t *dict, char **op_errstr,
ret = glusterd_op_stage_statedump_volume (dict,
op_errstr);
break;
+ case GD_OP_CLEARLOCKS_VOLUME:
+ ret = glusterd_op_stage_clearlocks_volume (dict,
+ op_errstr);
+ break;
default:
gf_log ("", GF_LOG_ERROR, "Unknown op %d",
@@ -2462,6 +2475,10 @@ glusterd_op_commit_perform (glusterd_op_t op, dict_t *dict, char **op_errstr,
ret = glusterd_op_statedump_volume (dict, op_errstr);
break;
+ case GD_OP_CLEARLOCKS_VOLUME:
+ ret = glusterd_op_clearlocks_volume (dict, op_errstr);
+ break;
+
default:
gf_log ("", GF_LOG_ERROR, "Unknown op %d",
op);
@@ -3740,6 +3757,7 @@ glusterd_op_free_ctx (glusterd_op_t op, void *ctx)
case GD_OP_REBALANCE:
case GD_OP_HEAL_VOLUME:
case GD_OP_STATEDUMP_VOLUME:
+ case GD_OP_CLEARLOCKS_VOLUME:
dict_unref (ctx);
break;
default:
diff --git a/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c b/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c
index 275e1ccffba..2cf17b3f730 100644
--- a/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c
+++ b/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c
@@ -147,6 +147,7 @@ glusterd_op_send_cli_response (glusterd_op_t op, int32_t op_ret,
case GD_OP_STATUS_VOLUME:
case GD_OP_SET_VOLUME:
case GD_OP_LIST_VOLUME:
+ case GD_OP_CLEARLOCKS_VOLUME:
{
/*nothing specific to be done*/
break;
diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c
index a7125825072..864467fd304 100644
--- a/xlators/mgmt/glusterd/src/glusterd-utils.c
+++ b/xlators/mgmt/glusterd/src/glusterd-utils.c
@@ -4798,3 +4798,23 @@ glusterd_chk_peers_connected_befriended (uuid_t skip_uuid)
(ret?"TRUE":"FALSE"));
return ret;
}
+
+void
+glusterd_get_client_filepath (char *filepath, glusterd_volinfo_t *volinfo,
+ gf_transport_type type)
+{
+ char path[PATH_MAX] = {0,};
+ glusterd_conf_t *priv = NULL;
+
+ priv = THIS->private;
+
+ GLUSTERD_GET_VOLUME_DIR (path, volinfo, priv);
+
+ if ((volinfo->transport_type == GF_TRANSPORT_BOTH_TCP_RDMA) &&
+ (type == GF_TRANSPORT_RDMA))
+ snprintf (filepath, PATH_MAX, "%s/%s.rdma-fuse.vol",
+ path, volinfo->volname);
+ else
+ snprintf (filepath, PATH_MAX, "%s/%s-fuse.vol",
+ path, volinfo->volname);
+}
diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.h b/xlators/mgmt/glusterd/src/glusterd-utils.h
index e6a655ca780..b8c65cbb073 100644
--- a/xlators/mgmt/glusterd/src/glusterd-utils.h
+++ b/xlators/mgmt/glusterd/src/glusterd-utils.h
@@ -386,4 +386,7 @@ glusterd_friend_remove_cleanup_vols (uuid_t uuid);
gf_boolean_t
glusterd_chk_peers_connected_befriended (uuid_t skip_uuid);
+void
+glusterd_get_client_filepath (char *filepath, glusterd_volinfo_t *volinfo,
+ gf_transport_type type);
#endif
diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.c b/xlators/mgmt/glusterd/src/glusterd-volgen.c
index 798ff05650e..fe79ea487b3 100644
--- a/xlators/mgmt/glusterd/src/glusterd-volgen.c
+++ b/xlators/mgmt/glusterd/src/glusterd-volgen.c
@@ -2871,25 +2871,6 @@ generate_single_transport_client_volfile (glusterd_volinfo_t *volinfo,
return ret;
}
-void
-get_client_filepath (char *filepath, glusterd_volinfo_t *volinfo, gf_transport_type type)
-{
- char path[PATH_MAX] = {0,};
- glusterd_conf_t *priv = NULL;
-
- priv = THIS->private;
-
- GLUSTERD_GET_VOLUME_DIR (path, volinfo, priv);
-
- if ((volinfo->transport_type == GF_TRANSPORT_BOTH_TCP_RDMA) &&
- (type == GF_TRANSPORT_RDMA))
- snprintf (filepath, PATH_MAX, "%s/%s.rdma-fuse.vol",
- path, volinfo->volname);
- else
- snprintf (filepath, PATH_MAX, "%s/%s-fuse.vol",
- path, volinfo->volname);
-}
-
static void
enumerate_transport_reqs (gf_transport_type type, char **types)
{
@@ -2927,7 +2908,7 @@ generate_client_volfiles (glusterd_volinfo_t *volinfo)
if (ret)
goto out;
type = transport_str_to_type (types[i]);
- get_client_filepath (filepath, volinfo, type);
+ glusterd_get_client_filepath (filepath, volinfo, type);
ret = generate_single_transport_client_volfile (volinfo,
filepath,
dict);
diff --git a/xlators/mgmt/glusterd/src/glusterd-volume-ops.c b/xlators/mgmt/glusterd/src/glusterd-volume-ops.c
index 3208ad35537..1ce0faf17ee 100644
--- a/xlators/mgmt/glusterd/src/glusterd-volume-ops.c
+++ b/xlators/mgmt/glusterd/src/glusterd-volume-ops.c
@@ -23,6 +23,7 @@
#endif
#include "common-utils.h"
+#include "syscall.h"
#include "cli1-xdr.h"
#include "xdr-generic.h"
#include "glusterd.h"
@@ -1098,6 +1099,73 @@ out:
}
int
+glusterd_op_stage_clearlocks_volume (dict_t *dict, char **op_errstr)
+{
+ int ret = -1;
+ char *volname = NULL;
+ char *path = NULL;
+ char *type = NULL;
+ char *kind = NULL;
+ glusterd_volinfo_t *volinfo = NULL;
+ char msg[2048] = {0,};
+
+ ret = dict_get_str (dict, "volname", &volname);
+ if (ret) {
+ snprintf (msg, sizeof(msg), "Failed to get volume name");
+ gf_log (THIS->name, GF_LOG_ERROR, "%s", msg);
+ *op_errstr = gf_strdup (msg);
+ goto out;
+ }
+
+ ret = dict_get_str (dict, "path", &path);
+ if (ret) {
+ snprintf (msg, sizeof(msg), "Failed to get path");
+ gf_log (THIS->name, GF_LOG_ERROR, "%s", msg);
+ *op_errstr = gf_strdup (msg);
+ goto out;
+ }
+
+ ret = dict_get_str (dict, "kind", &kind);
+ if (ret) {
+ snprintf (msg, sizeof(msg), "Failed to get kind");
+ gf_log ("", GF_LOG_ERROR, "%s", msg);
+ *op_errstr = gf_strdup (msg);
+ goto out;
+ }
+
+ ret = dict_get_str (dict, "type", &type);
+ if (ret) {
+ snprintf (msg, sizeof(msg), "Failed to get type");
+ gf_log ("", GF_LOG_ERROR, "%s", msg);
+ *op_errstr = gf_strdup (msg);
+ goto out;
+ }
+
+ ret = glusterd_volinfo_find (volname, &volinfo);
+ if (ret) {
+ snprintf (msg, sizeof(msg), "Volume %s does not exist",
+ volname);
+ gf_log ("", GF_LOG_ERROR, "%s", msg);
+ *op_errstr = gf_strdup (msg);
+ goto out;
+ }
+
+ if (!glusterd_is_volume_started (volinfo)) {
+ snprintf (msg, sizeof(msg), "Volume %s is not started",
+ volname);
+ gf_log ("", GF_LOG_ERROR, "%s", msg);
+ *op_errstr = gf_strdup (msg);
+ goto out;
+ }
+
+ ret = 0;
+out:
+ gf_log ("", GF_LOG_DEBUG, "Returning %d", ret);
+ return ret;
+}
+
+
+int
glusterd_op_create_volume (dict_t *dict, char **op_errstr)
{
int ret = 0;
@@ -1431,3 +1499,328 @@ out:
return ret;
}
+int
+glusterd_clearlocks_send_cmd (glusterd_volinfo_t *volinfo, char *cmd,
+ char *path, char *result, char *errstr,
+ int err_len, char *mntpt)
+{
+ int ret = -1;
+ glusterd_conf_t *priv = NULL;
+
+ priv = THIS->private;
+
+ ret = sys_lgetxattr (mntpt, cmd, result, PATH_MAX);
+ if (ret < 0) {
+ snprintf (errstr, err_len, "clear-locks getxattr command "
+ "failed. Reason: %s", strerror (errno));
+ gf_log (THIS->name, GF_LOG_DEBUG, "%s", errstr);
+ goto out;
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
+int
+glusterd_clearlocks_rmdir_mount (glusterd_volinfo_t *volinfo, char *mntpt)
+{
+ int ret = -1;
+ glusterd_conf_t *priv = NULL;
+
+ priv = THIS->private;
+
+ ret = rmdir (mntpt);
+ if (ret) {
+ gf_log (THIS->name, GF_LOG_DEBUG, "rmdir failed");
+ goto out;
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
+void
+glusterd_clearlocks_unmount (glusterd_volinfo_t *volinfo, char *mntpt)
+{
+ glusterd_conf_t *priv = NULL;
+ runner_t runner = {0,};
+ int ret = 0;
+
+ priv = THIS->private;
+
+ /*umount failures are ignored. Using stat we could have avoided
+ * attempting to unmount a non-existent filesystem. But a failure of
+ * stat() on mount can be due to network failures.*/
+
+ runinit (&runner);
+ runner_add_args (&runner, "/bin/umount", "-f", NULL);
+ runner_argprintf (&runner, "%s", mntpt);
+
+ ret = runner_run (&runner);
+ if (ret) {
+ ret = 0;
+ gf_log ("", GF_LOG_DEBUG,
+ "umount failed on maintenance client");
+ }
+
+ return;
+}
+
+int
+glusterd_clearlocks_create_mount (glusterd_volinfo_t *volinfo, char **mntpt)
+{
+ int ret = -1;
+ glusterd_conf_t *priv = NULL;
+ char template[PATH_MAX] = {0,};
+ char *tmpl = NULL;
+
+ priv = THIS->private;
+
+ snprintf (template, sizeof (template), "/tmp/%s.XXXXXX",
+ volinfo->volname);
+ tmpl = mkdtemp (template);
+ if (!tmpl) {
+ gf_log (THIS->name, GF_LOG_DEBUG, "Couldn't create temporary "
+ "mount directory. Reason %s", strerror (errno));
+ goto out;
+ }
+
+ *mntpt = gf_strdup (tmpl);
+ ret = 0;
+out:
+ return ret;
+}
+
+int
+glusterd_clearlocks_mount (glusterd_volinfo_t *volinfo, char **xl_opts,
+ char *mntpt)
+{
+ int ret = -1;
+ int i = 0;
+ glusterd_conf_t *priv = NULL;
+ runner_t runner = {0,};
+ char client_volfpath[PATH_MAX] = {0,};
+
+ priv = THIS->private;
+
+ runinit (&runner);
+ glusterd_get_client_filepath (client_volfpath, volinfo,
+ volinfo->transport_type);
+ runner_add_args (&runner, SBIN_DIR"/glusterfs", "-f", NULL);
+ runner_argprintf (&runner, "%s", client_volfpath);
+
+ for (i = 0; i < volinfo->brick_count && xl_opts[i]; i++) {
+ runner_add_arg (&runner, "--xlator-option");
+ runner_argprintf (&runner, "%s", xl_opts[i]);
+ }
+
+ runner_argprintf (&runner, "%s", mntpt);
+ ret = runner_run (&runner);
+ if (ret) {
+ gf_log (THIS->name, GF_LOG_DEBUG,
+ "Could not start glusterfs");
+ goto out;
+ }
+ gf_log (THIS->name, GF_LOG_DEBUG,
+ "Started glusterfs successfully");
+
+out:
+ return ret;
+}
+
+int
+glusterd_clearlocks_get_local_client_ports (glusterd_volinfo_t *volinfo,
+ char **xl_opts)
+{
+ glusterd_brickinfo_t *brickinfo = NULL;
+ glusterd_conf_t *priv = NULL;
+ int index = 0;
+ int ret = -1;
+ int i = 0;
+ int port = 0;
+
+ GF_ASSERT (xl_opts);
+ if (!xl_opts) {
+ gf_log (THIS->name, GF_LOG_DEBUG, "Should pass non-NULL "
+ "xl_opts");
+ goto out;
+ }
+
+ priv = THIS->private;
+
+ index = -1;
+ list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) {
+ index++;
+ if (uuid_compare (brickinfo->uuid, priv->uuid))
+ continue;
+
+ port = pmap_registry_search (THIS, brickinfo->path,
+ GF_PMAP_PORT_BRICKSERVER);
+ if (!port) {
+ ret = -1;
+ gf_log (THIS->name, GF_LOG_DEBUG, "Couldn't get port "
+ " for brick %s:%s", brickinfo->hostname,
+ brickinfo->path);
+ goto out;
+ }
+
+ ret = gf_asprintf (&xl_opts[i], "%s-client-%d.remote-port=%d",
+ volinfo->volname, index, port);
+ if (ret == -1) {
+ xl_opts[i] = NULL;
+ goto out;
+ }
+ i++;
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
+int
+glusterd_op_clearlocks_volume (dict_t *dict, char **op_errstr)
+{
+ int32_t ret = -1;
+ int i = 0;
+ char *volname = NULL;
+ char *path = NULL;
+ char *kind = NULL;
+ char *type = NULL;
+ char *opts = NULL;
+ char *cmd_str = NULL;
+ char *free_ptr = NULL;
+ char msg[PATH_MAX] = {0,};
+ char result[PATH_MAX] = {0,};
+ char *mntpt = NULL;
+ char **xl_opts = NULL;
+ dict_t *ctx = NULL;
+ glusterd_volinfo_t *volinfo = NULL;
+
+ ret = dict_get_str (dict, "volname", &volname);
+ if (ret) {
+ gf_log (THIS->name, GF_LOG_ERROR, "Failed to get volume name");
+ goto out;
+ }
+ gf_log ("", GF_LOG_DEBUG, "Performing clearlocks on volume %s", volname);
+
+ ret = dict_get_str (dict, "path", &path);
+ if (ret) {
+ gf_log (THIS->name, GF_LOG_ERROR, "Failed to get path");
+ goto out;
+ }
+
+ ret = dict_get_str (dict, "kind", &kind);
+ if (ret) {
+ gf_log (THIS->name, GF_LOG_ERROR, "Failed to get kind");
+ goto out;
+ }
+
+ ret = dict_get_str (dict, "type", &type);
+ if (ret) {
+ gf_log (THIS->name, GF_LOG_ERROR, "Failed to get type");
+ goto out;
+ }
+
+ ret = dict_get_str (dict, "opts", &opts);
+ if (ret)
+ ret = 0;
+
+ gf_log (THIS->name, GF_LOG_INFO, "Received clear-locks request for "
+ "volume %s with kind %s type %s and options %s", volname,
+ kind, type, opts);
+
+ if (opts)
+ ret = gf_asprintf (&cmd_str, GF_XATTR_CLRLK_CMD".t%s.k%s.%s",
+ type, kind, opts);
+ else
+ ret = gf_asprintf (&cmd_str, GF_XATTR_CLRLK_CMD".t%s.k%s",
+ type, kind);
+ if (ret == -1)
+ goto out;
+
+ ret = glusterd_volinfo_find (volname, &volinfo);
+ if (ret) {
+ snprintf (msg, sizeof (msg), "Volume %s doesn't exist.",
+ volname);
+ gf_log (THIS->name, GF_LOG_ERROR, "%s", msg);
+ goto out;
+ }
+
+ xl_opts = GF_CALLOC (volinfo->brick_count+1, sizeof (char*),
+ gf_gld_mt_charptr);
+ if (!xl_opts)
+ goto out;
+
+ ret = glusterd_clearlocks_get_local_client_ports (volinfo, xl_opts);
+ if (ret) {
+ snprintf (msg, sizeof (msg), "Couldn't get port numbers of "
+ "local bricks");
+ gf_log (THIS->name, GF_LOG_ERROR, "%s", msg);
+ goto out;
+ }
+
+ ret = glusterd_clearlocks_create_mount (volinfo, &mntpt);
+ if (ret) {
+ snprintf (msg, sizeof (msg), "Creating mount directory "
+ "for clear-locks failed.");
+ gf_log (THIS->name, GF_LOG_ERROR, "%s", msg);
+ goto out;
+ }
+
+ ret = glusterd_clearlocks_mount (volinfo, xl_opts, mntpt);
+ if (ret) {
+ snprintf (msg, sizeof (msg), "Failed to mount clear-locks "
+ "maintenance client.");
+ gf_log (THIS->name, GF_LOG_ERROR, "%s", msg);
+ goto out;
+ }
+
+ ret = glusterd_clearlocks_send_cmd (volinfo, cmd_str, path, result,
+ msg, sizeof (msg), mntpt);
+ if (ret) {
+ gf_log (THIS->name, GF_LOG_ERROR, "%s", msg);
+ goto umount;
+ }
+
+ ctx = glusterd_op_get_ctx ();
+ if (!ctx)
+ /*Impossible. Only originator glusterd can
+ * come here. */
+ goto umount;
+
+ free_ptr = gf_strdup(result);
+ if (dict_set_dynstr (ctx, "lk-summary", free_ptr)) {
+ GF_FREE (free_ptr);
+ snprintf (msg, sizeof (msg), "Failed to set clear-locks "
+ "result");
+ gf_log (THIS->name, GF_LOG_ERROR, "%s", msg);
+ }
+
+umount:
+ glusterd_clearlocks_unmount (volinfo, mntpt);
+
+ if (glusterd_clearlocks_rmdir_mount (volinfo, mntpt))
+ gf_log (THIS->name, GF_LOG_WARNING, "Couldn't unmount "
+ "clear-locks mount point");
+
+out:
+ if (ret)
+ *op_errstr = gf_strdup (msg);
+
+ if (xl_opts) {
+ for (i = 0; i < volinfo->brick_count && xl_opts[i]; i++)
+ GF_FREE (xl_opts[i]);
+ GF_FREE (xl_opts);
+ }
+
+ if (cmd_str)
+ GF_FREE (cmd_str);
+
+ if (mntpt)
+ GF_FREE (mntpt);
+
+ return ret;
+}
diff --git a/xlators/mgmt/glusterd/src/glusterd.h b/xlators/mgmt/glusterd/src/glusterd.h
index bea15689bc2..60dbe61e04a 100644
--- a/xlators/mgmt/glusterd/src/glusterd.h
+++ b/xlators/mgmt/glusterd/src/glusterd.h
@@ -78,6 +78,7 @@ typedef enum glusterd_op_ {
GD_OP_HEAL_VOLUME,
GD_OP_STATEDUMP_VOLUME,
GD_OP_LIST_VOLUME,
+ GD_OP_CLEARLOCKS_VOLUME,
GD_OP_MAX,
} glusterd_op_t;
@@ -537,6 +538,7 @@ int32_t glusterd_op_begin (rpcsvc_request_t *req, glusterd_op_t op, void *ctx);
/* removed other definitions as they have been defined elsewhere in this file*/
int glusterd_handle_cli_statedump_volume (rpcsvc_request_t *req);
+int glusterd_handle_cli_clearlocks_volume (rpcsvc_request_t *req);
int glusterd_handle_defrag_start (glusterd_volinfo_t *volinfo, char *op_errstr,
size_t len, int cmd, defrag_cbk_fn_t cbk);
@@ -576,6 +578,9 @@ int glusterd_op_rebalance (dict_t *dict, char **op_errstr, dict_t *rsp_dict);
int glusterd_op_stage_statedump_volume (dict_t *dict, char **op_errstr);
int glusterd_op_statedump_volume (dict_t *dict, char **op_errstr);
+int glusterd_op_stage_clearlocks_volume (dict_t *dict, char **op_errstr);
+int glusterd_op_clearlocks_volume (dict_t *dict, char **op_errstr);
+
/* misc */
void glusterd_do_replace_brick (void *data);
int glusterd_op_perform_remove_brick (glusterd_volinfo_t *volinfo, char *brick,