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