summaryrefslogtreecommitdiffstats
path: root/libglusterfs/src/xlator.c
diff options
context:
space:
mode:
Diffstat (limited to 'libglusterfs/src/xlator.c')
-rw-r--r--libglusterfs/src/xlator.c432
1 files changed, 234 insertions, 198 deletions
diff --git a/libglusterfs/src/xlator.c b/libglusterfs/src/xlator.c
index cbbe8cf7f12..9a2582d45d5 100644
--- a/libglusterfs/src/xlator.c
+++ b/libglusterfs/src/xlator.c
@@ -8,12 +8,12 @@
cases as published by the Free Software Foundation.
*/
-#include "xlator.h"
+#include "glusterfs/xlator.h"
#include <dlfcn.h>
#include <netdb.h>
#include <fnmatch.h>
-#include "defaults.h"
-#include "libglusterfs-messages.h"
+#include "glusterfs/defaults.h"
+#include "glusterfs/libglusterfs-messages.h"
#define SET_DEFAULT_FOP(fn) \
do { \
@@ -143,6 +143,7 @@ fill_defaults(xlator_t *xl)
SET_DEFAULT_FOP(getspec);
SET_DEFAULT_FOP(icreate);
SET_DEFAULT_FOP(namelink);
+ SET_DEFAULT_FOP(copy_file_range);
if (!xl->cbks)
xl->cbks = &default_cbks;
@@ -183,9 +184,11 @@ xlator_volopt_dynload(char *xlator_type, void **dl_handle,
volume_opt_list_t *opt_list)
{
int ret = -1;
+ int flag = 0;
char *name = NULL;
void *handle = NULL;
xlator_api_t *xlapi = NULL;
+ volume_option_t *opt = NULL;
GF_VALIDATE_OR_GOTO("xlator", xlator_type, out);
@@ -193,8 +196,10 @@ xlator_volopt_dynload(char *xlator_type, void **dl_handle,
* need this check */
if (!strstr(xlator_type, "rpc-transport"))
ret = gf_asprintf(&name, "%s/%s.so", XLATORDIR, xlator_type);
- else
+ else {
+ flag = 1;
ret = gf_asprintf(&name, "%s/%s.so", XLATORPARENTDIR, xlator_type);
+ }
if (-1 == ret) {
goto out;
}
@@ -205,34 +210,34 @@ xlator_volopt_dynload(char *xlator_type, void **dl_handle,
handle = dlopen(name, RTLD_NOW);
if (!handle) {
- gf_msg("xlator", GF_LOG_WARNING, 0, LG_MSG_DLOPEN_FAILED, "%s",
- dlerror());
+ gf_smsg("xlator", GF_LOG_WARNING, 0, LG_MSG_DLOPEN_FAILED, "error=%s",
+ dlerror(), NULL);
goto out;
}
- /* check new struct first, and then check this */
- xlapi = dlsym(handle, "xlator_api");
- if (!xlapi) {
- gf_msg("xlator", GF_LOG_DEBUG, 0, LG_MSG_DLSYM_ERROR,
- "dlsym(xlator_api) on %s. "
- "Fall back to old symbols",
- dlerror());
- /* This case is not an error for now, so allow it
- to fall back to old methods. */
- opt_list->given_opt = dlsym(handle, "options");
- if (!opt_list->given_opt) {
- dlerror();
- gf_msg("xlator", GF_LOG_ERROR, 0, LG_MSG_LOAD_FAILED,
- "Failed to load xlator opt table");
+ if (flag == 0) {
+ /* check new struct first, and then check this */
+ xlapi = dlsym(handle, "xlator_api");
+ if (!xlapi) {
+ gf_smsg("xlator", GF_LOG_ERROR, 0, LG_MSG_DLSYM_ERROR, "error=%s",
+ dlerror(), NULL);
goto out;
}
- } else {
+
opt_list->given_opt = xlapi->options;
if (!opt_list->given_opt) {
- gf_msg("xlator", GF_LOG_ERROR, 0, LG_MSG_LOAD_FAILED,
- "Failed to load xlator options table");
+ gf_smsg("xlator", GF_LOG_ERROR, 0, LG_MSG_LOAD_FAILED, NULL);
goto out;
}
+ } else {
+ opt = dlsym(handle, "options");
+ if (!opt) {
+ gf_smsg("xlator", GF_LOG_ERROR, 0, LG_MSG_DLSYM_ERROR, "error=%s",
+ dlerror(), NULL);
+ goto out;
+ }
+
+ opt_list->given_opt = opt;
}
*dl_handle = handle;
@@ -248,134 +253,29 @@ out:
return ret;
}
-int
-xlator_dynload_oldway(xlator_t *xl)
-{
- int i = 0;
- int ret = -1;
- void *handle = NULL;
- volume_opt_list_t *vol_opt = NULL;
- class_methods_t *vtbl = NULL;
-
- handle = xl->dlhandle;
-
- xl->fops = dlsym(handle, "fops");
- if (!xl->fops) {
- gf_msg("xlator", GF_LOG_WARNING, 0, LG_MSG_DLSYM_ERROR,
- "dlsym(fops) on %s", dlerror());
- goto out;
- }
-
- xl->cbks = dlsym(handle, "cbks");
- if (!xl->cbks) {
- gf_msg("xlator", GF_LOG_WARNING, 0, LG_MSG_DLSYM_ERROR,
- "dlsym(cbks) on %s", dlerror());
- goto out;
- }
-
- /*
- * If class_methods exists, its contents override any definitions of
- * init or fini for that translator. Otherwise, we fall back to the
- * older method of looking for init and fini directly.
- */
- vtbl = dlsym(handle, "class_methods");
- if (vtbl) {
- xl->init = vtbl->init;
- xl->fini = vtbl->fini;
- xl->reconfigure = vtbl->reconfigure;
- xl->notify = vtbl->notify;
- } else {
- if (!(*VOID(&xl->init) = dlsym(handle, "init"))) {
- gf_msg("xlator", GF_LOG_WARNING, 0, LG_MSG_DLSYM_ERROR,
- "dlsym(init) on %s", dlerror());
- goto out;
- }
-
- if (!(*VOID(&(xl->fini)) = dlsym(handle, "fini"))) {
- gf_msg("xlator", GF_LOG_WARNING, 0, LG_MSG_DLSYM_ERROR,
- "dlsym(fini) on %s", dlerror());
- goto out;
- }
- if (!(*VOID(&(xl->reconfigure)) = dlsym(handle, "reconfigure"))) {
- gf_msg_trace("xlator", 0,
- "dlsym(reconfigure) on %s "
- "-- neglecting",
- dlerror());
- }
- if (!(*VOID(&(xl->notify)) = dlsym(handle, "notify"))) {
- gf_msg_trace("xlator", 0,
- "dlsym(notify) on %s -- "
- "neglecting",
- dlerror());
- }
- }
-
- if (!(xl->dumpops = dlsym(handle, "dumpops"))) {
- gf_msg_trace("xlator", 0,
- "dlsym(dumpops) on %s -- "
- "neglecting",
- dlerror());
- }
-
- if (!(*VOID(&(xl->mem_acct_init)) = dlsym(handle, "mem_acct_init"))) {
- gf_msg_trace(xl->name, 0,
- "dlsym(mem_acct_init) on %s -- "
- "neglecting",
- dlerror());
- }
-
- vol_opt = GF_CALLOC(1, sizeof(volume_opt_list_t),
- gf_common_mt_volume_opt_list_t);
-
- if (!vol_opt) {
- goto out;
- }
-
- INIT_LIST_HEAD(&vol_opt->list);
- vol_opt->given_opt = dlsym(handle, "options");
- if (!vol_opt->given_opt) {
- vol_opt->given_opt = default_options;
- }
- list_add_tail(&vol_opt->list, &xl->volume_options);
-
- /* make sure 'min' is set to high value, so it would be
- properly set later */
- for (i = 0; i < GF_FOP_MAXVALUE; i++) {
- xl->stats.interval.latencies[i].min = 0xffffffff;
- }
-
- ret = 0;
-
-out:
- return ret;
-}
-
-int
-xlator_dynload_newway(xlator_t *xl)
+static int
+xlator_dynload_apis(xlator_t *xl)
{
int ret = -1;
void *handle = NULL;
volume_opt_list_t *vol_opt = NULL;
xlator_api_t *xlapi = NULL;
+ int i = 0;
handle = xl->dlhandle;
xlapi = dlsym(handle, "xlator_api");
if (!xlapi) {
- gf_msg("xlator", GF_LOG_INFO, 0, LG_MSG_DLSYM_ERROR,
- "dlsym(xlator_api) on %s. "
- "Fall back to old symbols",
- dlerror());
- /* This case is not an error for now, so allow it
- to fall back to old methods. */
- ret = 1;
+ gf_smsg("xlator", GF_LOG_ERROR, 0, LG_MSG_DLSYM_ERROR, "dlsym=%s",
+ dlerror(), NULL);
+ ret = -1;
goto out;
}
xl->fops = xlapi->fops;
if (!xl->fops) {
- gf_msg("xlator", GF_LOG_WARNING, 0, LG_MSG_DLSYM_ERROR,
- "%s: struct missing (fops)", xl->name);
+ gf_smsg("xlator", GF_LOG_WARNING, 0, LG_MSG_STRUCT_MISS, "name=%s",
+ xl->name, NULL);
goto out;
}
@@ -386,8 +286,8 @@ xlator_dynload_newway(xlator_t *xl)
xl->init = xlapi->init;
if (!xl->init) {
- gf_msg("xlator", GF_LOG_WARNING, 0, LG_MSG_DLSYM_ERROR,
- "%s: method missing (init)", xl->name);
+ gf_smsg("xlator", GF_LOG_WARNING, 0, LG_MSG_METHOD_MISS, "name=%s",
+ xl->name, NULL);
goto out;
}
@@ -458,6 +358,10 @@ xlator_dynload_newway(xlator_t *xl)
memcpy(xl->op_version, xlapi->op_version,
sizeof(uint32_t) * GF_MAX_RELEASES);
+ for (i = 0; i < GF_FOP_MAXVALUE; i++) {
+ gf_latency_reset(&xl->stats.interval.latencies[i]);
+ }
+
ret = 0;
out:
return ret;
@@ -485,21 +389,15 @@ xlator_dynload(xlator_t *xl)
handle = dlopen(name, RTLD_NOW);
if (!handle) {
- gf_msg("xlator", GF_LOG_WARNING, 0, LG_MSG_DLOPEN_FAILED, "%s",
- dlerror());
+ gf_smsg("xlator", GF_LOG_WARNING, 0, LG_MSG_DLOPEN_FAILED, "error=%s",
+ dlerror(), NULL);
goto out;
}
xl->dlhandle = handle;
- ret = xlator_dynload_newway(xl);
+ ret = xlator_dynload_apis(xl);
if (-1 == ret)
goto out;
- if (1 == ret) {
- /* it means we don't find the new symbol in xlator code */
- ret = xlator_dynload_oldway(xl);
- if (-1 == ret)
- goto out;
- }
fill_defaults(xl);
@@ -559,10 +457,8 @@ xlator_set_inode_lru_limit(xlator_t *this, void *data)
if (this->itable) {
if (!data) {
- gf_msg(this->name, GF_LOG_WARNING, 0, LG_MSG_INVALID_ENTRY,
- "input data is NULL. "
- "Cannot update the lru limit of the inode"
- " table. Continuing with older value");
+ gf_smsg(this->name, GF_LOG_WARNING, 0, LG_MSG_INPUT_DATA_NULL,
+ NULL);
goto out;
}
inode_lru_limit = *(int *)data;
@@ -735,20 +631,16 @@ xlator_init(xlator_t *xl)
xl->instance_name = NULL;
GF_ATOMIC_INIT(xl->xprtrefcnt, 0);
- GF_ATOMIC_INIT(xl->fd_cnt, 0);
if (!xl->init) {
- gf_msg(xl->name, GF_LOG_WARNING, 0, LG_MSG_INIT_FAILED,
- "No init() found");
+ gf_smsg(xl->name, GF_LOG_WARNING, 0, LG_MSG_INIT_FAILED, NULL);
goto out;
}
ret = __xlator_init(xl);
if (ret) {
- gf_msg(xl->name, GF_LOG_ERROR, 0, LG_MSG_VOLUME_ERROR,
- "Initialization of volume '%s' failed,"
- " review your volfile again",
- xl->name);
+ gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_VOLUME_ERROR, "name=%s",
+ xl->name, NULL);
goto out;
}
@@ -781,6 +673,7 @@ xlator_fini_rec(xlator_t *xl)
trav = trav->next;
}
+ xl->cleanup_starting = 1;
if (xl->init_succeeded) {
if (xl->fini) {
old_THIS = THIS;
@@ -788,8 +681,14 @@ xlator_fini_rec(xlator_t *xl)
xl->fini(xl);
- if (xl->local_pool)
+ if (xl->local_pool) {
mem_pool_destroy(xl->local_pool);
+ xl->local_pool = NULL;
+ }
+ if (xl->itable) {
+ inode_table_destroy(xl->itable);
+ xl->itable = NULL;
+ }
THIS = old_THIS;
} else {
@@ -858,6 +757,19 @@ xlator_mem_acct_init(xlator_t *xl, int num_types)
}
void
+xlator_mem_acct_unref(struct mem_acct *mem_acct)
+{
+ uint32_t i;
+
+ if (GF_ATOMIC_DEC(mem_acct->refcnt) == 0) {
+ for (i = 0; i < mem_acct->num_types; i++) {
+ LOCK_DESTROY(&(mem_acct->rec[i].lock));
+ }
+ FREE(mem_acct);
+ }
+}
+
+void
xlator_tree_fini(xlator_t *xl)
{
xlator_t *top = NULL;
@@ -888,7 +800,6 @@ xlator_list_destroy(xlator_list_t *list)
int
xlator_memrec_free(xlator_t *xl)
{
- uint32_t i = 0;
struct mem_acct *mem_acct = NULL;
if (!xl) {
@@ -897,13 +808,8 @@ xlator_memrec_free(xlator_t *xl)
mem_acct = xl->mem_acct;
if (mem_acct) {
- for (i = 0; i < mem_acct->num_types; i++) {
- LOCK_DESTROY(&(mem_acct->rec[i].lock));
- }
- if (GF_ATOMIC_DEC(mem_acct->refcnt) == 0) {
- FREE(mem_acct);
- xl->mem_acct = NULL;
- }
+ xlator_mem_acct_unref(mem_acct);
+ xl->mem_acct = NULL;
}
return 0;
@@ -920,7 +826,7 @@ xlator_members_free(xlator_t *xl)
GF_FREE(xl->name);
GF_FREE(xl->type);
- if (!(xl->ctx && xl->ctx->cmd_args.valgrind) && xl->dlhandle)
+ if (!(xl->ctx && xl->ctx->cmd_args.vgtool != _gf_none) && xl->dlhandle)
dlclose(xl->dlhandle);
if (xl->options)
dict_unref(xl->options);
@@ -970,8 +876,7 @@ xlator_tree_free_members(xlator_t *tree)
xlator_t *prev = tree;
if (!tree) {
- gf_msg("parser", GF_LOG_ERROR, 0, LG_MSG_TREE_NOT_FOUND,
- "Translator tree not found");
+ gf_smsg("parser", GF_LOG_ERROR, 0, LG_MSG_TREE_NOT_FOUND, NULL);
return -1;
}
@@ -991,8 +896,7 @@ xlator_tree_free_memacct(xlator_t *tree)
xlator_t *prev = tree;
if (!tree) {
- gf_msg("parser", GF_LOG_ERROR, 0, LG_MSG_TREE_NOT_FOUND,
- "Translator tree not found");
+ gf_smsg("parser", GF_LOG_ERROR, 0, LG_MSG_TREE_NOT_FOUND, NULL);
return -1;
}
@@ -1016,7 +920,6 @@ xlator_mem_free(xlator_t *xl)
return 0;
if (xl->options) {
- dict_ref(xl->options);
dict_unref(xl->options);
xl->options = NULL;
}
@@ -1035,7 +938,7 @@ xlator_mem_free(xlator_t *xl)
static void
xlator_call_fini(xlator_t *this)
{
- if (!this || this->cleanup_starting)
+ if (!this || this->call_cleanup)
return;
this->cleanup_starting = 1;
this->call_cleanup = 1;
@@ -1054,6 +957,8 @@ xlator_mem_cleanup(xlator_t *this)
xlator_list_t **trav_p = NULL;
xlator_t *top = NULL;
xlator_t *victim = NULL;
+ glusterfs_graph_t *graph = NULL;
+ gf_boolean_t graph_cleanup = _gf_false;
if (this->call_cleanup || !this->ctx)
return;
@@ -1061,6 +966,12 @@ xlator_mem_cleanup(xlator_t *this)
this->call_cleanup = 1;
ctx = this->ctx;
+ inode_table = this->itable;
+ if (inode_table) {
+ inode_table_destroy(inode_table);
+ this->itable = NULL;
+ }
+
xlator_call_fini(trav);
while (prev) {
@@ -1069,12 +980,6 @@ xlator_mem_cleanup(xlator_t *this)
prev = trav;
}
- inode_table = this->itable;
- if (inode_table) {
- inode_table_destroy(inode_table);
- this->itable = NULL;
- }
-
if (this->fini) {
this->fini(this);
}
@@ -1084,17 +989,28 @@ xlator_mem_cleanup(xlator_t *this)
if (ctx->active) {
top = ctx->active->first;
LOCK(&ctx->volfile_lock);
- /* TODO here we have leak for xlator node in a graph */
- /* Need to move only top xlator from a graph */
for (trav_p = &top->children; *trav_p; trav_p = &(*trav_p)->next) {
victim = (*trav_p)->xlator;
if (victim->call_cleanup && !strcmp(victim->name, this->name)) {
+ graph_cleanup = _gf_true;
(*trav_p) = (*trav_p)->next;
break;
}
}
UNLOCK(&ctx->volfile_lock);
}
+
+ if (graph_cleanup) {
+ prev = this;
+ graph = ctx->active;
+ pthread_mutex_lock(&graph->mutex);
+ while (prev) {
+ trav = prev->next;
+ GF_FREE(prev);
+ prev = trav;
+ }
+ pthread_mutex_unlock(&graph->mutex);
+ }
}
void
@@ -1394,8 +1310,21 @@ xlator_destroy(xlator_t *xl)
return 0;
}
+static int32_t
+gf_bin_to_string(char *dst, size_t size, void *src, size_t len)
+{
+ if (len >= size) {
+ return EINVAL;
+ }
+
+ memcpy(dst, src, len);
+ dst[len] = 0;
+
+ return 0;
+}
+
int
-is_gf_log_command(xlator_t *this, const char *name, char *value)
+is_gf_log_command(xlator_t *this, const char *name, char *value, size_t size)
{
xlator_t *trav = NULL;
char key[1024] = {
@@ -1407,7 +1336,11 @@ is_gf_log_command(xlator_t *this, const char *name, char *value)
glusterfs_ctx_t *ctx = NULL;
if (!strcmp("trusted.glusterfs.syslog", name)) {
- ret = gf_string2boolean(value, &syslog_flag);
+ ret = gf_bin_to_string(key, sizeof(key), value, size);
+ if (ret != 0) {
+ goto out;
+ }
+ ret = gf_string2boolean(key, &syslog_flag);
if (ret) {
ret = EOPNOTSUPP;
goto out;
@@ -1423,7 +1356,12 @@ is_gf_log_command(xlator_t *this, const char *name, char *value)
if (fnmatch("trusted.glusterfs*set-log-level", name, FNM_NOESCAPE))
goto out;
- log_level = glusterd_check_log_level(value);
+ ret = gf_bin_to_string(key, sizeof(key), value, size);
+ if (ret != 0) {
+ goto out;
+ }
+
+ log_level = glusterd_check_log_level(key);
if (log_level == -1) {
ret = EOPNOTSUPP;
goto out;
@@ -1431,9 +1369,9 @@ is_gf_log_command(xlator_t *this, const char *name, char *value)
/* Some crude way to change the log-level of process */
if (!strcmp(name, "trusted.glusterfs.set-log-level")) {
- gf_msg("glusterfs", gf_log_get_loglevel(), 0, LG_MSG_SET_LOG_LEVEL,
- "setting log level to %d (old-value=%d)", log_level,
- gf_log_get_loglevel());
+ gf_smsg("glusterfs", gf_log_get_loglevel(), 0, LG_MSG_SET_LOG_LEVEL,
+ "new-value=%d", log_level, "old-value=%d",
+ gf_log_get_loglevel(), NULL);
gf_log_set_loglevel(this->ctx, log_level);
ret = 0;
goto out;
@@ -1441,9 +1379,9 @@ is_gf_log_command(xlator_t *this, const char *name, char *value)
if (!strcmp(name, "trusted.glusterfs.fuse.set-log-level")) {
/* */
- gf_msg(this->name, gf_log_get_xl_loglevel(this), 0,
- LG_MSG_SET_LOG_LEVEL, "setting log level to %d (old-value=%d)",
- log_level, gf_log_get_xl_loglevel(this));
+ gf_smsg(this->name, gf_log_get_xl_loglevel(this), 0,
+ LG_MSG_SET_LOG_LEVEL, "new-value=%d", log_level, "old-value=%d",
+ gf_log_get_xl_loglevel(this), NULL);
gf_log_set_xl_loglevel(this, log_level);
ret = 0;
goto out;
@@ -1459,10 +1397,9 @@ is_gf_log_command(xlator_t *this, const char *name, char *value)
while (trav) {
snprintf(key, 1024, "trusted.glusterfs.%s.set-log-level", trav->name);
if (fnmatch(name, key, FNM_NOESCAPE) == 0) {
- gf_msg(trav->name, gf_log_get_xl_loglevel(trav), 0,
- LG_MSG_SET_LOG_LEVEL,
- "setting log level to %d (old-value=%d)", log_level,
- gf_log_get_xl_loglevel(trav));
+ gf_smsg(trav->name, gf_log_get_xl_loglevel(trav), 0,
+ LG_MSG_SET_LOG_LEVEL, "new-value%d", log_level,
+ "old-value=%d", gf_log_get_xl_loglevel(trav), NULL);
gf_log_set_xl_loglevel(trav, log_level);
ret = 0;
}
@@ -1494,9 +1431,7 @@ glusterd_check_log_level(const char *value)
}
if (log_level == -1)
- gf_msg(THIS->name, GF_LOG_ERROR, 0, LG_MSG_INIT_FAILED,
- "Invalid log-level. possible values are "
- "DEBUG|WARNING|ERROR|CRITICAL|NONE|TRACE");
+ gf_smsg(THIS->name, GF_LOG_ERROR, 0, LG_MSG_INVALID_INIT, NULL);
return log_level;
}
@@ -1555,3 +1490,104 @@ glusterfs_delete_volfile_checksum(glusterfs_ctx_t *ctx, const char *volfile_id)
return 0;
}
+
+/*
+ The function is required to take dict ref for every xlator at graph.
+ At the time of compare graph topology create a graph and populate
+ key values in the dictionary, after finished graph comparison we do destroy
+ the new graph.At the time of construct graph we don't take any reference
+ so to avoid dict leak at the of destroying graph due to ref counter underflow
+ we need to call dict_ref here.
+
+*/
+
+void
+gluster_graph_take_reference(xlator_t *tree)
+{
+ xlator_t *trav = tree;
+ xlator_t *prev = tree;
+
+ if (!tree) {
+ gf_smsg("parser", GF_LOG_ERROR, 0, LG_MSG_TREE_NOT_FOUND, NULL);
+ return;
+ }
+
+ while (prev) {
+ trav = prev->next;
+ if (prev->options)
+ dict_ref(prev->options);
+ prev = trav;
+ }
+ return;
+}
+
+gf_boolean_t
+mgmt_is_multiplexed_daemon(char *name)
+{
+ const char *mux_daemons[] = {"glustershd", NULL};
+ int i;
+
+ if (!name)
+ return _gf_false;
+
+ for (i = 0; mux_daemons[i]; i++) {
+ if (!strcmp(name, mux_daemons[i]))
+ return _gf_true;
+ }
+ return _gf_false;
+}
+
+gf_boolean_t
+xlator_is_cleanup_starting(xlator_t *this)
+{
+ gf_boolean_t cleanup = _gf_false;
+ glusterfs_graph_t *graph = NULL;
+ xlator_t *xl = NULL;
+
+ if (!this) {
+ gf_smsg("xlator", GF_LOG_WARNING, EINVAL, LG_MSG_OBJECT_NULL, "xlator",
+ NULL);
+ goto out;
+ }
+
+ graph = this->graph;
+ if (!graph) {
+ gf_smsg("xlator", GF_LOG_WARNING, EINVAL, LG_MSG_GRAPH_NOT_SET,
+ "name=%s", this->name, NULL);
+ goto out;
+ }
+
+ xl = graph->first;
+ if (xl && xl->cleanup_starting)
+ cleanup = _gf_true;
+out:
+ return cleanup;
+}
+
+int
+graph_total_client_xlator(glusterfs_graph_t *graph)
+{
+ xlator_t *xl = NULL;
+ int count = 0;
+
+ if (!graph) {
+ gf_smsg("xlator", GF_LOG_WARNING, EINVAL, LG_MSG_OBJECT_NULL, "graph",
+ NULL);
+ goto out;
+ }
+
+ xl = graph->first;
+ if (!strcmp(xl->type, "protocol/server")) {
+ gf_msg_debug(xl->name, 0, "Return because it is a server graph");
+ return 0;
+ }
+
+ while (xl) {
+ if (strcmp(xl->type, "protocol/client") == 0) {
+ count++;
+ }
+ xl = xl->next;
+ }
+out:
+ return count;
+}