From 5b4b25c697f93d3dfe352013a442f2ec73fd3b8b Mon Sep 17 00:00:00 2001 From: Amar Tumballi Date: Tue, 28 Nov 2017 14:44:46 +0530 Subject: xlator: provide a xlator_api_t structure to include all exported options each translator from now on can have just 1 symbol exported called 'xlator_api', which has all the required fields in it. Updates: #164 Change-Id: I48d54f5ec59fee842b1d55877e3ac5e9ec9b6bdd Signed-off-by: Amar Tumballi --- libglusterfs/src/defaults-tmpl.c | 7 ++ libglusterfs/src/defaults.h | 4 + libglusterfs/src/xlator.c | 220 ++++++++++++++++++++++++++++++++------- libglusterfs/src/xlator.h | 74 +++++++++++++ 4 files changed, 268 insertions(+), 37 deletions(-) (limited to 'libglusterfs') diff --git a/libglusterfs/src/defaults-tmpl.c b/libglusterfs/src/defaults-tmpl.c index 0ef14d5c68e..d311972f0c0 100644 --- a/libglusterfs/src/defaults-tmpl.c +++ b/libglusterfs/src/defaults-tmpl.c @@ -223,3 +223,10 @@ default_mem_acct_init (xlator_t *this) return ret; } + +void +default_fini (xlator_t *this) +{ + if (this && this->private) + GF_FREE (this->private); +} diff --git a/libglusterfs/src/defaults.h b/libglusterfs/src/defaults.h index 50f1909b90b..9b4f4828e91 100644 --- a/libglusterfs/src/defaults.h +++ b/libglusterfs/src/defaults.h @@ -1297,4 +1297,8 @@ default_setactivelk_failure_cbk (call_frame_t *frame, int32_t op_errno); int32_t default_mem_acct_init (xlator_t *this); + +void +default_fini (xlator_t *this); + #endif /* _DEFAULTS_H */ diff --git a/libglusterfs/src/xlator.c b/libglusterfs/src/xlator.c index e371038f2c7..ed1d95d01e1 100644 --- a/libglusterfs/src/xlator.c +++ b/libglusterfs/src/xlator.c @@ -40,6 +40,10 @@ xlator_init_unlock (void) (void) pthread_mutex_unlock (&xlator_init_mutex); } +static struct xlator_cbks default_cbks = { }; +struct volume_options default_options[] = { + { .key = {NULL} }, +}; static void fill_defaults (xlator_t *xl) @@ -102,10 +106,16 @@ fill_defaults (xlator_t *xl) SET_DEFAULT_FOP (getspec); + if (!xl->cbks) + xl->cbks = &default_cbks; + SET_DEFAULT_CBK (release); SET_DEFAULT_CBK (releasedir); SET_DEFAULT_CBK (forget); + if (!xl->fini) + xl->fini = default_fini; + if (!xl->notify) xl->notify = default_notify; @@ -136,9 +146,10 @@ int xlator_volopt_dynload (char *xlator_type, void **dl_handle, volume_opt_list_t *opt_list) { - int ret = -1; - char *name = NULL; - void *handle = NULL; + int ret = -1; + char *name = NULL; + void *handle = NULL; + xlator_api_t *xlapi = NULL; GF_VALIDATE_OR_GOTO ("xlator", xlator_type, out); @@ -163,11 +174,28 @@ xlator_volopt_dynload (char *xlator_type, void **dl_handle, goto out; } - if (!(opt_list->given_opt = dlsym (handle, "options"))) { - dlerror (); - gf_msg ("xlator", GF_LOG_ERROR, 0, LG_MSG_LOAD_FAILED, - "Failed to load xlator opt table"); - 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"); + 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"); + goto out; + } } *dl_handle = handle; @@ -184,44 +212,24 @@ xlator_volopt_dynload (char *xlator_type, void **dl_handle, } - -int -xlator_dynload (xlator_t *xl) +int xlator_dynload_oldway (xlator_t *xl) { int ret = -1; - char *name = NULL; void *handle = NULL; volume_opt_list_t *vol_opt = NULL; class_methods_t *vtbl = NULL; - GF_VALIDATE_OR_GOTO ("xlator", xl, out); - - INIT_LIST_HEAD (&xl->volume_options); - - ret = gf_asprintf (&name, "%s/%s.so", XLATORDIR, xl->type); - if (-1 == ret) { - goto out; - } - - ret = -1; - - gf_msg_trace ("xlator", 0, "attempt to load file %s", name); - - handle = dlopen (name, RTLD_NOW|RTLD_GLOBAL); - if (!handle) { - gf_msg ("xlator", GF_LOG_WARNING, 0, LG_MSG_DLOPEN_FAILED, - "%s", dlerror ()); - goto out; - } - xl->dlhandle = handle; + handle = xl->dlhandle; - if (!(xl->fops = dlsym (handle, "fops"))) { + 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; } - if (!(xl->cbks = dlsym (handle, "cbks"))) { + 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; @@ -276,20 +284,158 @@ xlator_dynload (xlator_t *xl) } vol_opt = GF_CALLOC (1, sizeof (volume_opt_list_t), - gf_common_mt_volume_opt_list_t); + gf_common_mt_volume_opt_list_t); if (!vol_opt) { goto out; } if (!(vol_opt->given_opt = dlsym (handle, "options"))) { - dlerror (); gf_msg_trace (xl->name, 0, "Strict option validation not " - "enforced -- neglecting"); + "enforced -- neglecting (%s)", dlerror ()); + } + INIT_LIST_HEAD (&vol_opt->list); + list_add_tail (&vol_opt->list, &xl->volume_options); + + ret = 0; + +out: + return ret; +} + +int xlator_dynload_newway (xlator_t *xl) +{ + int ret = -1; + void *handle = NULL; + volume_opt_list_t *vol_opt = NULL; + xlator_api_t *xlapi = NULL; + + 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; + 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); + goto out; + } + + xl->cbks = xlapi->cbks; + if (!xl->cbks) { + gf_msg_trace ("xlator", 0, "%s: struct missing (cbks)", + xl->name); + } + + xl->init = xlapi->init; + if (!xl->init) { + gf_msg ("xlator", GF_LOG_WARNING, 0, LG_MSG_DLSYM_ERROR, + "%s: method missing (init)", xl->name); + goto out; + } + + xl->fini = xlapi->fini; + if (!xl->fini) { + gf_msg_trace ("xlator", 0, "%s: method missing (fini)", + xl->name); + } + + xl->reconfigure = xlapi->reconfigure; + if (!xl->reconfigure) { + gf_msg_trace ("xlator", 0, "%s: method missing (reconfigure)", + xl->name); + } + xl->notify = xlapi->notify; + if (!xl->notify) { + gf_msg_trace ("xlator", 0, "%s: method missing (notify)", + xl->name); + } + xl->dumpops = xlapi->dumpops; + if (!xl->dumpops) { + gf_msg_trace ("xlator", 0, "%s: method missing (dumpops)", + xl->name); + } + xl->mem_acct_init = xlapi->mem_acct_init; + if (!xl->mem_acct_init) { + gf_msg_trace ("xlator", 0, "%s: method missing (mem_acct_init)", + xl->name); + } + + vol_opt = GF_CALLOC (1, sizeof (volume_opt_list_t), + gf_common_mt_volume_opt_list_t); + if (!vol_opt) { + goto out; } + + vol_opt->given_opt = xlapi->options; + if (!vol_opt->given_opt) { + gf_msg ("xlator", GF_LOG_INFO, 0, LG_MSG_DLSYM_ERROR, + "%s: options not provided, using default", xl->name); + vol_opt->given_opt = default_options; + } + INIT_LIST_HEAD (&vol_opt->list); list_add_tail (&vol_opt->list, &xl->volume_options); + xl->id = xlapi->xlator_id; + xl->flags = xlapi->flags; + xl->identifier = xlapi->identifier; + memcpy (xl->op_version, xlapi->op_version, + sizeof (uint32_t) * GF_MAX_RELEASES); + + ret = 0; +out: + return ret; +} + + +int +xlator_dynload (xlator_t *xl) +{ + int ret = -1; + char *name = NULL; + void *handle = NULL; + + GF_VALIDATE_OR_GOTO ("xlator", xl, out); + + INIT_LIST_HEAD (&xl->volume_options); + + ret = gf_asprintf (&name, "%s/%s.so", XLATORDIR, xl->type); + if (-1 == ret) { + goto out; + } + + ret = -1; + + gf_msg_trace ("xlator", 0, "attempt to load file %s", name); + + handle = dlopen (name, RTLD_NOW|RTLD_GLOBAL); + if (!handle) { + gf_msg ("xlator", GF_LOG_WARNING, 0, LG_MSG_DLOPEN_FAILED, + "%s", dlerror ()); + goto out; + } + xl->dlhandle = handle; + + ret = xlator_dynload_newway (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); ret = 0; diff --git a/libglusterfs/src/xlator.h b/libglusterfs/src/xlator.h index 7f9d483ccb3..de353fe702d 100644 --- a/libglusterfs/src/xlator.h +++ b/libglusterfs/src/xlator.h @@ -991,6 +991,18 @@ struct _xlator { /* Its used as an index to inode_ctx*/ uint32_t xl_id; + + /* op_version: initialized in xlator code itself */ + uint32_t op_version[GF_MAX_RELEASES]; + + /* flags: initialized in xlator code itself */ + uint32_t flags; + + /* id: unique, initialized in xlator code itself */ + uint32_t id; + + /* identifier: a full string which can unique identify the xlator */ + char *identifier; }; typedef struct { @@ -1001,6 +1013,68 @@ typedef struct { event_notify_fn_t notify; } class_methods_t; +/* This would be the only structure which needs to be exported by + the translators. For the backward compatibility, in 4.x series + even the old exported fields will be supported */ +typedef struct { + /* init(): mandatory method, will be called during the + graph initialization */ + int32_t (*init) (xlator_t *this); + + /* fini(): optional method, will be initialized to default + method which would just free the 'xlator->private' variable. + This method is called when the graph is no more in use, and + is being destroyed. Also when SIGTERM is received */ + void (*fini) (xlator_t *this); + + /* reconfigure(): optional method, will be initialized to default + method in case not provided by xlator. This method is called + when there are only option changes in xlator, and no graph change. + eg., a 'gluster volume set' command */ + int32_t (*reconfigure) (xlator_t *this, dict_t *options); + + /* mem_acct_init(): used for memory accounting inside of the xlator. + optional. called during translator initialization */ + int32_t (*mem_acct_init) (xlator_t *this); + + /* notify(): used for handling the notification of events from either + the parent or child in the graph. optional. */ + event_notify_fn_t notify; + + /* struct fops: mandatory. provides all the filesystem operations + methods of the xlator */ + struct xlator_fops *fops; + /* struct cbks: optional. provides methods to handle + inode forgets, and fd releases */ + struct xlator_cbks *cbks; + + /* dumpops: a structure again, with methods to dump the details. + optional. */ + struct xlator_dumpops *dumpops; + + /* struct options: if the translator takes any 'options' from the + volume file, then that should be defined here. optional. */ + volume_option_t *options; + + /* op_version: will be used by volume generation logic to figure + out whether to insert it in graph or no, based on cluster's + operating version. + default value: 0, which means good to insert always */ + uint32_t op_version[GF_MAX_RELEASES]; + + /* flags: will be used by volume generation logic to optimize the + placements etc. + default value: 0, which means don't treat it specially */ + uint32_t flags; + + /* xlator_id: unique per xlator. make sure to have no collission + in this ID */ + uint32_t xlator_id; + + /* identifier: a string constant */ + char *identifier; +} xlator_api_t; + #define xlator_has_parent(xl) (xl->parents != NULL) #define XLATOR_NOTIFY(_xl, params ...) \ -- cgit