summaryrefslogtreecommitdiff
path: root/0541-glusterd-volgen-Add-functionality-to-accept-any-cust.patch
diff options
context:
space:
mode:
Diffstat (limited to '0541-glusterd-volgen-Add-functionality-to-accept-any-cust.patch')
-rw-r--r--0541-glusterd-volgen-Add-functionality-to-accept-any-cust.patch545
1 files changed, 545 insertions, 0 deletions
diff --git a/0541-glusterd-volgen-Add-functionality-to-accept-any-cust.patch b/0541-glusterd-volgen-Add-functionality-to-accept-any-cust.patch
new file mode 100644
index 0000000..29135df
--- /dev/null
+++ b/0541-glusterd-volgen-Add-functionality-to-accept-any-cust.patch
@@ -0,0 +1,545 @@
+From 23ab7175e64ab4d75fbcb6874008843cc78b65b8 Mon Sep 17 00:00:00 2001
+From: Ashish Pandey <aspandey@redhat.com>
+Date: Fri, 16 Apr 2021 18:48:56 +0530
+Subject: [PATCH 541/542] glusterd-volgen: Add functionality to accept any
+ custom xlator
+
+Add new function which allow users to insert any custom xlators.
+It makes to provide a way to add any processing into file operations.
+
+Users can deploy the plugin(xlator shared object) and integrate it to glusterfsd.
+
+If users want to enable a custom xlator, do the follows:
+
+1. put xlator object(.so file) into "XLATOR_DIR/user/"
+2. set the option user.xlator.<xlator> to the existing xlator-name to specify of the position in graph
+3. restart gluster volume
+
+Options for custom xlator are able to set in "user.xlator.<xlator>.<optkey>".
+
+Backport of :
+>https://github.com/gluster/glusterfs/commit/ea86b664f3b1f54901ce1b7d7fba7d80456f2089
+>Fixes: https://github.com/gluster/glusterfs/issues/1943
+>Change-Id: Ife3ae1514ea474f5dae2897223012f9d04b64674
+>Signed-off-by:Ryo Furuhashi <ryo.furuhashi.nh@hitachi.com>
+>Co-authored-by: Yaniv Kaul <ykaul@redhat.com>
+>Co-authored-by: Xavi Hernandez <xhernandez@users.noreply.github.com>
+
+Change-Id: Ic8f28bfcfde67213eb1092b0ebf4822c874d37bb
+BUG: 1927235
+Signed-off-by: Ashish Pandey <aspandey@redhat.com>
+Reviewed-on: https://code.engineering.redhat.com/gerrit/236830
+Tested-by: RHGS Build Bot <nigelb@redhat.com>
+Reviewed-by: Ravishankar Narayanankutty <ravishankar@redhat.com>
+Reviewed-by: Xavi Hernandez Juan <xhernandez@redhat.com>
+---
+ cli/src/cli-rpc-ops.c | 148 ++++++++++++++++++++------
+ cli/src/cli.h | 2 -
+ tests/basic/user-xlator.t | 65 ++++++++++++
+ tests/env.rc.in | 3 +
+ xlators/mgmt/glusterd/src/glusterd-volgen.c | 155 ++++++++++++++++++++++++++++
+ 5 files changed, 342 insertions(+), 31 deletions(-)
+ create mode 100755 tests/basic/user-xlator.t
+
+diff --git a/cli/src/cli-rpc-ops.c b/cli/src/cli-rpc-ops.c
+index 4e91265..51b5447 100644
+--- a/cli/src/cli-rpc-ops.c
++++ b/cli/src/cli-rpc-ops.c
+@@ -2269,49 +2269,131 @@ out:
+ return ret;
+ }
+
+-char *
+-is_server_debug_xlator(void *myframe)
++/*
++ * returns
++ * 1 : is server debug xlator
++ * 0 : is not server debug xlator
++ * <0 : error
++ */
++static int
++is_server_debug_xlator(char *key, char *value)
++{
++ if (!key || !value)
++ return -1;
++
++ if (strcmp("debug.trace", key) == 0 ||
++ strcmp("debug.error-gen", key) == 0) {
++ if (strcmp("client", value) == 0)
++ return 0;
++ else
++ return 1;
++ }
++
++ return 0;
++}
++
++/*
++ * returns
++ * 1 : is user xlator
++ * 0 : is not user xlator
++ * <0 : error
++ */
++static int
++is_server_user_xlator(char *key, char *value)
++{
++ int ret = 0;
++
++ if (!key || !value)
++ return -1;
++
++ ret = fnmatch("user.xlator.*", key, 0);
++ if (ret < 0) {
++ ret = -1;
++ goto out;
++ } else if (ret == FNM_NOMATCH) {
++ ret = 0;
++ goto out;
++ }
++
++ ret = fnmatch("user.xlator.*.*", key, 0);
++ if (ret < 0) {
++ ret = -1;
++ goto out;
++ } else if (ret != FNM_NOMATCH) { // this is user xlator's option key
++ ret = 0;
++ goto out;
++ }
++
++ ret = 1;
++
++out:
++ return ret;
++}
++
++static int
++added_server_xlator(void *myframe, char **added_xlator)
+ {
+ call_frame_t *frame = NULL;
+ cli_local_t *local = NULL;
+ char **words = NULL;
+ char *key = NULL;
+ char *value = NULL;
+- char *debug_xlator = NULL;
++ int ret = 0;
+
+ frame = myframe;
+ local = frame->local;
+ words = (char **)local->words;
+
+ while (*words != NULL) {
+- if (strstr(*words, "trace") == NULL &&
+- strstr(*words, "error-gen") == NULL) {
+- words++;
+- continue;
+- }
+-
+ key = *words;
+ words++;
+ value = *words;
+- if (value == NULL)
++
++ if (!value) {
+ break;
+- if (strstr(value, "client")) {
+- words++;
+- continue;
+- } else {
+- if (!(strstr(value, "posix") || strstr(value, "acl") ||
+- strstr(value, "locks") || strstr(value, "io-threads") ||
+- strstr(value, "marker") || strstr(value, "index"))) {
+- words++;
+- continue;
+- } else {
+- debug_xlator = gf_strdup(key);
+- break;
++ }
++
++ ret = is_server_debug_xlator(key, value);
++ if (ret < 0) {
++ gf_log(((call_frame_t *)myframe)->this->name, GF_LOG_ERROR,
++ "failed to check that debug xlator was added");
++ ret = -1;
++ goto out;
++ }
++
++ if (ret) {
++ *added_xlator = gf_strdup(key);
++ if (!*added_xlator) {
++ gf_log(((call_frame_t *)myframe)->this->name, GF_LOG_ERROR,
++ "Out of memory");
++ ret = -1;
++ goto out;
++ }
++ break;
++ }
++
++ ret = is_server_user_xlator(key, value);
++ if (ret < 0) {
++ gf_log(((call_frame_t *)myframe)->this->name, GF_LOG_ERROR,
++ "failed to check that user xlator was added");
++ ret = -1;
++ goto out;
++ }
++
++ if (ret) {
++ *added_xlator = gf_strdup(key);
++ if (!*added_xlator) {
++ gf_log(((call_frame_t *)myframe)->this->name, GF_LOG_ERROR,
++ "Out of memory");
++ ret = -1;
++ goto out;
+ }
++ break;
+ }
+ }
+
+- return debug_xlator;
++out:
++ return ret;
+ }
+
+ int
+@@ -2327,7 +2409,7 @@ gf_cli_set_volume_cbk(struct rpc_req *req, struct iovec *iov, int count,
+ char msg[1024] = {
+ 0,
+ };
+- char *debug_xlator = NULL;
++ char *added_xlator = NULL;
+ char tmp_str[512] = {
+ 0,
+ };
+@@ -2365,18 +2447,26 @@ gf_cli_set_volume_cbk(struct rpc_req *req, struct iovec *iov, int count,
+ * The process has to be restarted. So this is a check from the
+ * volume set option such that if debug xlators such as trace/errorgen
+ * are provided in the set command, warn the user.
++ * volume set option such that if user custom xlators or debug
++ * xlators such as trace/errorgen are provided in the set command,
++ * warn the user.
+ */
+- debug_xlator = is_server_debug_xlator(myframe);
++ ret = added_server_xlator(myframe, &added_xlator);
++ if (ret < 0) {
++ gf_log("cli", GF_LOG_ERROR,
++ "failed to check that server graph has been changed");
++ goto out;
++ }
+
+ if (dict_get_str(dict, "help-str", &help_str) && !msg[0])
+ snprintf(msg, sizeof(msg), "Set volume %s",
+ (rsp.op_ret) ? "unsuccessful" : "successful");
+- if (rsp.op_ret == 0 && debug_xlator) {
++ if (rsp.op_ret == 0 && added_xlator) {
+ snprintf(tmp_str, sizeof(tmp_str),
+ "\n%s translator has been "
+ "added to the server volume file. Please restart the"
+ " volume for enabling the translator",
+- debug_xlator);
++ added_xlator);
+ }
+
+ if ((global_state->mode & GLUSTER_MODE_XML) && (help_str == NULL)) {
+@@ -2394,7 +2484,7 @@ gf_cli_set_volume_cbk(struct rpc_req *req, struct iovec *iov, int count,
+ cli_err("volume set: failed");
+ } else {
+ if (help_str == NULL) {
+- if (debug_xlator == NULL)
++ if (added_xlator == NULL)
+ cli_out("volume set: success");
+ else
+ cli_out("volume set: success%s", tmp_str);
+@@ -2408,7 +2498,7 @@ gf_cli_set_volume_cbk(struct rpc_req *req, struct iovec *iov, int count,
+ out:
+ if (dict)
+ dict_unref(dict);
+- GF_FREE(debug_xlator);
++ GF_FREE(added_xlator);
+ cli_cmd_broadcast_response(ret);
+ gf_free_xdr_cli_rsp(rsp);
+ return ret;
+diff --git a/cli/src/cli.h b/cli/src/cli.h
+index 7b4f446..b5b69ea 100644
+--- a/cli/src/cli.h
++++ b/cli/src/cli.h
+@@ -502,8 +502,6 @@ cli_xml_output_snapshot(int cmd_type, dict_t *dict, int op_ret, int op_errno,
+ int
+ cli_xml_snapshot_status_single_snap(cli_local_t *local, dict_t *dict,
+ char *key);
+-char *
+-is_server_debug_xlator(void *myframe);
+
+ int32_t
+ cli_cmd_snapshot_parse(const char **words, int wordcount, dict_t **options,
+diff --git a/tests/basic/user-xlator.t b/tests/basic/user-xlator.t
+new file mode 100755
+index 0000000..a711f9f
+--- /dev/null
++++ b/tests/basic/user-xlator.t
+@@ -0,0 +1,65 @@
++#!/bin/bash
++
++. $(dirname $0)/../include.rc
++. $(dirname $0)/../volume.rc
++
++#### patchy.dev.d-backends-patchy1.vol
++brick=${B0//\//-}
++SERVER_VOLFILE="/var/lib/glusterd/vols/${V0}/${V0}.${H0}.${brick:1}-${V0}1.vol"
++
++cleanup;
++
++TEST mkdir -p $B0/single-brick
++TEST mkdir -p ${GLUSTER_XLATOR_DIR}/user
++
++## deploy dummy user xlator
++TEST cp ${GLUSTER_XLATOR_DIR}/playground/template.so ${GLUSTER_XLATOR_DIR}/user/hoge.so
++
++TEST glusterd
++TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{1,2,3,4,5,6};
++TEST $CLI volume set $V0 user.xlator.hoge posix
++TEST grep -q 'user/hoge' ${SERVER_VOLFILE}
++
++TEST $CLI volume set $V0 user.xlator.hoge.opt1 10
++TEST grep -q '"option opt1 10"' ${SERVER_VOLFILE}
++TEST $CLI volume set $V0 user.xlator.hoge.opt2 hogehoge
++TEST grep -q '"option opt2 hogehoge"' ${SERVER_VOLFILE}
++TEST $CLI volume set $V0 user.xlator.hoge.opt3 true
++TEST grep -q '"option opt3 true"' ${SERVER_VOLFILE}
++
++TEST $CLI volume start $V0
++EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}1
++EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}2
++EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}3
++EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}4
++EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}5
++EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}6
++
++TEST $CLI volume set $V0 user.xlator.hoge trash
++TEST grep -q 'user/hoge' ${SERVER_VOLFILE}
++
++TEST $CLI volume stop $V0
++TEST $CLI volume start $V0
++EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}1
++EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}2
++EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}3
++EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}4
++EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}5
++EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}6
++
++TEST ! $CLI volume set $V0 user.xlator.hoge unknown
++TEST grep -q 'user/hoge' ${SERVER_VOLFILE} # When the CLI fails, the volfile is not modified.
++
++TEST $CLI volume stop $V0
++TEST $CLI volume start $V0
++EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}1
++EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}2
++EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}3
++EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}4
++EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}5
++EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}6
++
++#### teardown
++
++TEST rm -f ${GLUSTER_XLATOR_DIR}/user/hoge.so
++cleanup;
+diff --git a/tests/env.rc.in b/tests/env.rc.in
+index c7472a7..1f0ca88 100644
+--- a/tests/env.rc.in
++++ b/tests/env.rc.in
+@@ -40,3 +40,6 @@ export GLUSTER_LIBEXECDIR
+
+ RUN_NFS_TESTS=@BUILD_GNFS@
+ export RUN_NFS_TESTS
++
++GLUSTER_XLATOR_DIR=@libdir@/glusterfs/@PACKAGE_VERSION@/xlator
++export GLUSTER_XLATOR_DIR
+\ No newline at end of file
+diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.c b/xlators/mgmt/glusterd/src/glusterd-volgen.c
+index 1920284..a242b5c 100644
+--- a/xlators/mgmt/glusterd/src/glusterd-volgen.c
++++ b/xlators/mgmt/glusterd/src/glusterd-volgen.c
+@@ -45,6 +45,11 @@ struct gd_validate_reconf_opts {
+
+ extern struct volopt_map_entry glusterd_volopt_map[];
+
++struct check_and_add_user_xlator_t {
++ volgen_graph_t *graph;
++ char *volname;
++};
++
+ #define RPC_SET_OPT(XL, CLI_OPT, XLATOR_OPT, ERROR_CMD) \
+ do { \
+ char *_value = NULL; \
+@@ -2822,6 +2827,145 @@ out:
+ return ret;
+ }
+
++static gf_boolean_t
++check_user_xlator_position(dict_t *dict, char *key, data_t *value,
++ void *prev_xlname)
++{
++ if (strncmp(key, "user.xlator.", SLEN("user.xlator.")) != 0) {
++ return false;
++ }
++
++ if (fnmatch("user.xlator.*.*", key, 0) == 0) {
++ return false;
++ }
++
++ char *value_str = data_to_str(value);
++ if (!value_str) {
++ return false;
++ }
++
++ if (strcmp(value_str, prev_xlname) == 0) {
++ gf_log("glusterd", GF_LOG_INFO,
++ "found insert position of user-xlator(%s)", key);
++ return true;
++ }
++
++ return false;
++}
++
++static int
++set_user_xlator_option(dict_t *set_dict, char *key, data_t *value, void *data)
++{
++ xlator_t *xl = data;
++ char *optname = strrchr(key, '.') + 1;
++
++ gf_log("glusterd", GF_LOG_DEBUG, "set user xlator option %s = %s", key,
++ value->data);
++
++ return xlator_set_option(xl, optname, strlen(optname), data_to_str(value));
++}
++
++static int
++insert_user_xlator_to_graph(dict_t *set_dict, char *key, data_t *value,
++ void *action_data)
++{
++ int ret = -1;
++
++ struct check_and_add_user_xlator_t *data = action_data;
++
++ char *xlator_name = strrchr(key, '.') + 1; // user.xlator.<xlator_name>
++ char *xlator_option_matcher = NULL;
++ char *type = NULL;
++ xlator_t *xl = NULL;
++
++ // convert optkey to xlator type
++ if (gf_asprintf(&type, "user/%s", xlator_name) < 0) {
++ gf_log("glusterd", GF_LOG_ERROR, "failed to generate user-xlator type");
++ goto out;
++ }
++
++ gf_log("glusterd", GF_LOG_INFO, "add user xlator=%s to graph", type);
++
++ xl = volgen_graph_add(data->graph, type, data->volname);
++ if (!xl) {
++ goto out;
++ }
++
++ ret = gf_asprintf(&xlator_option_matcher, "user.xlator.%s.*", xlator_name);
++ if (ret < 0) {
++ gf_log("glusterd", GF_LOG_ERROR,
++ "failed to generate user-xlator option matcher");
++ goto out;
++ }
++
++ dict_foreach_fnmatch(set_dict, xlator_option_matcher,
++ set_user_xlator_option, xl);
++
++out:
++ if (type)
++ GF_FREE(type);
++ if (xlator_option_matcher)
++ GF_FREE(xlator_option_matcher);
++
++ return ret;
++}
++
++static int
++validate_user_xlator_position(dict_t *this, char *key, data_t *value,
++ void *unused)
++{
++ int ret = -1;
++ int i = 0;
++
++ if (!value)
++ goto out;
++
++ if (fnmatch("user.xlator.*.*", key, 0) == 0) {
++ ret = 0;
++ goto out;
++ }
++
++ char *value_str = data_to_str(value);
++ if (!value_str)
++ goto out;
++
++ int num_xlators = sizeof(server_graph_table) /
++ sizeof(server_graph_table[0]);
++ for (i = 0; i < num_xlators; i++) {
++ if (server_graph_table[i].dbg_key &&
++ strcmp(value_str, server_graph_table[i].dbg_key) == 0) {
++ ret = 0;
++ goto out;
++ }
++ }
++
++out:
++ if (ret == -1)
++ gf_log("glusterd", GF_LOG_ERROR, "invalid user xlator position %s = %s",
++ key, value->data);
++
++ return ret;
++}
++
++static int
++check_and_add_user_xl(volgen_graph_t *graph, dict_t *set_dict, char *volname,
++ char *prev_xlname)
++{
++ if (!prev_xlname)
++ goto out;
++
++ struct check_and_add_user_xlator_t data = {.graph = graph,
++ .volname = volname};
++
++ if (dict_foreach_match(set_dict, check_user_xlator_position, prev_xlname,
++ insert_user_xlator_to_graph, &data) < 0) {
++ return -1;
++ }
++
++out:
++ return 0;
++}
++
+ static int
+ server_graph_builder(volgen_graph_t *graph, glusterd_volinfo_t *volinfo,
+ dict_t *set_dict, void *param)
+@@ -2831,6 +2975,12 @@ server_graph_builder(volgen_graph_t *graph, glusterd_volinfo_t *volinfo,
+ char *loglevel = NULL;
+ int i = 0;
+
++ if (dict_foreach_fnmatch(set_dict, "user.xlator.*",
++ validate_user_xlator_position, NULL) < 0) {
++ ret = -EINVAL;
++ goto out;
++ }
++
+ i = sizeof(server_graph_table) / sizeof(server_graph_table[0]) - 1;
+
+ while (i >= 0) {
+@@ -2848,6 +2998,11 @@ server_graph_builder(volgen_graph_t *graph, glusterd_volinfo_t *volinfo,
+ if (ret)
+ goto out;
+
++ ret = check_and_add_user_xl(graph, set_dict, volinfo->volname,
++ server_graph_table[i].dbg_key);
++ if (ret)
++ goto out;
++
+ i--;
+ }
+
+--
+1.8.3.1
+