diff options
-rw-r--r-- | api/src/glfs-internal.h | 22 | ||||
-rw-r--r-- | libglusterfs/src/dict.c | 20 | ||||
-rw-r--r-- | libglusterfs/src/dict.h | 2 | ||||
-rw-r--r-- | libglusterfs/src/syncop.h | 23 | ||||
-rw-r--r-- | xlators/features/upcall/src/upcall-internal.c | 12 | ||||
-rw-r--r-- | xlators/features/upcall/src/upcall.c | 117 | ||||
-rw-r--r-- | xlators/features/upcall/src/upcall.h | 6 | ||||
-rw-r--r-- | xlators/performance/md-cache/src/md-cache-mem-types.h | 1 | ||||
-rw-r--r-- | xlators/performance/md-cache/src/md-cache-messages.h | 27 | ||||
-rw-r--r-- | xlators/performance/md-cache/src/md-cache.c | 148 |
10 files changed, 340 insertions, 38 deletions
diff --git a/api/src/glfs-internal.h b/api/src/glfs-internal.h index 471fa5fffc1..a10c7289115 100644 --- a/api/src/glfs-internal.h +++ b/api/src/glfs-internal.h @@ -103,28 +103,6 @@ #define GFAPI_SYMVER_PRIVATE(fn1, fn2, dotver) /**/ #endif -/* - * syncop_xxx() calls are executed in two ways, one is inside a synctask where - * the executing function will do 'swapcontext' and the other is without - * synctask where the executing thread is made to wait using pthread_cond_wait. - * Executing thread may change when syncop_xxx() is executed inside a synctask. - * This leads to errno_location change i.e. errno may give errno of - * non-executing thread. So errno is not touched inside a synctask execution. - * All gfapi calls are executed using the second way of executing syncop_xxx() - * where the executing thread waits using pthread_cond_wait so it is ok to set - * errno in these cases. The following macro makes syncop_xxx() behave just - * like a system call, where -1 is returned and errno is set when a failure - * occurs. - */ -#define DECODE_SYNCOP_ERR(ret) do { \ - if (ret < 0) { \ - errno = -ret; \ - ret = -1; \ - } else { \ - errno = 0; \ - } \ - } while (0) - #define ESTALE_RETRY(ret,errno,reval,loc,label) do { \ if (ret == -1 && errno == ESTALE) { \ if (reval < DEFAULT_REVAL_COUNT) { \ diff --git a/libglusterfs/src/dict.c b/libglusterfs/src/dict.c index 6f7adb51589..96cb9e94bda 100644 --- a/libglusterfs/src/dict.c +++ b/libglusterfs/src/dict.c @@ -473,6 +473,26 @@ dict_get (dict_t *this, char *key) return NULL; } +int +dict_key_count (dict_t *this) +{ + int ret = -1; + + if (!this) { + gf_msg_callingfn ("dict", GF_LOG_WARNING, EINVAL, + LG_MSG_INVALID_ARG, "dict passed is NULL"); + return ret; + } + + LOCK (&this->lock); + { + ret = this->count; + } + UNLOCK (&this->lock); + + return ret; +} + void dict_del (dict_t *this, char *key) { diff --git a/libglusterfs/src/dict.h b/libglusterfs/src/dict.h index 04f0ed9b164..a7fb6c78425 100644 --- a/libglusterfs/src/dict.h +++ b/libglusterfs/src/dict.h @@ -107,6 +107,8 @@ data_t *dict_get (dict_t *this, char *key); void dict_del (dict_t *this, char *key); int dict_reset (dict_t *dict); +int dict_key_count (dict_t *this); + int32_t dict_serialized_length (dict_t *dict); int32_t dict_serialize (dict_t *dict, char *buf); int32_t dict_unserialize (char *buf, int32_t size, dict_t **fill); diff --git a/libglusterfs/src/syncop.h b/libglusterfs/src/syncop.h index c2387e62cd2..0d0da58f4cf 100644 --- a/libglusterfs/src/syncop.h +++ b/libglusterfs/src/syncop.h @@ -258,6 +258,29 @@ struct syncopctx { } while (0) +/* + * syncop_xxx() calls are executed in two ways, one is inside a synctask where + * the executing function will do 'swapcontext' and the other is without + * synctask where the executing thread is made to wait using pthread_cond_wait. + * Executing thread may change when syncop_xxx() is executed inside a synctask. + * This leads to errno_location change i.e. errno may give errno of + * non-executing thread. So errno is not touched inside a synctask execution. + * All gfapi calls are executed using the second way of executing syncop_xxx() + * where the executing thread waits using pthread_cond_wait so it is ok to set + * errno in these cases. The following macro makes syncop_xxx() behave just + * like a system call, where -1 is returned and errno is set when a failure + * occurs. + */ +#define DECODE_SYNCOP_ERR(ret) do { \ + if (ret < 0) { \ + errno = -ret; \ + ret = -1; \ + } else { \ + errno = 0; \ + } \ + } while (0) + + #define SYNCENV_DEFAULT_STACKSIZE (2 * 1024 * 1024) struct syncenv * syncenv_new (size_t stacksize, int procmin, int procmax); diff --git a/xlators/features/upcall/src/upcall-internal.c b/xlators/features/upcall/src/upcall-internal.c index 3cde56a7ce8..0f07ae8df03 100644 --- a/xlators/features/upcall/src/upcall-internal.c +++ b/xlators/features/upcall/src/upcall-internal.c @@ -435,10 +435,16 @@ upcall_reaper_thread_init (xlator_t *this) } int -up_filter_virtual_xattr (dict_t *d, char *k, data_t *v, void *tmp) +up_filter_unregd_xattr (dict_t *xattrs, char *xattr, data_t *v, + void *regd_xattrs) { - if (is_virtual_xattr (k) == _gf_true) { - dict_del (d, k); + int ret = 0; + + if (dict_get ((dict_t *)regd_xattrs, xattr) == NULL) { + /* xattr was not found in the registered xattr, hence do not + * send notification for its change + */ + dict_del (xattrs, xattr); } return 0; diff --git a/xlators/features/upcall/src/upcall.c b/xlators/features/upcall/src/upcall.c index c49a3fd8796..c7b74ed3c29 100644 --- a/xlators/features/upcall/src/upcall.c +++ b/xlators/features/upcall/src/upcall.c @@ -1596,9 +1596,13 @@ up_setxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, upcall_local_t *local = NULL; int ret = 0; struct iatt stbuf = {0, }; + upcall_private_t *priv = NULL; EXIT_IF_UPCALL_OFF (this, out); + priv = this->private; + GF_VALIDATE_OR_GOTO (this->name, priv, out); + client = frame->root->client; local = frame->local; @@ -1607,13 +1611,21 @@ up_setxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, } flags = UP_XATTR; - /* Remove the virtual xattrs from the dict */ - ret = dict_foreach (local->xattr, up_filter_virtual_xattr, NULL); + /* Remove the xattrs from the dict, if they are not registered for + * cache invalidation */ + ret = dict_foreach (local->xattr, up_filter_unregd_xattr, priv->xattrs); if (ret < 0) { op_ret = ret; goto out; } + if (dict_key_count(local->xattr) == 0) { + gf_msg_trace (this->name, 0, "None of xattrs requested for" + " invalidation, were changed. Nothing to " + "invalidate"); + goto out; /* nothing to invalidate */ + } + ret = syncop_stat (FIRST_CHILD(frame->this), &local->loc, &stbuf, NULL, NULL); if (ret == 0) @@ -1677,9 +1689,13 @@ up_fsetxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, upcall_local_t *local = NULL; int ret = 0; struct iatt stbuf = {0,}; + upcall_private_t *priv = NULL; EXIT_IF_UPCALL_OFF (this, out); + priv = this->private; + GF_VALIDATE_OR_GOTO (this->name, priv, out); + client = frame->root->client; local = frame->local; @@ -1688,13 +1704,21 @@ up_fsetxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, } flags = UP_XATTR; - /* Remove the virtual xattrs from the dict */ - ret = dict_foreach (local->xattr, up_filter_virtual_xattr, NULL); + /* Remove the xattrs from the dict, if they are not registered for + * cache invalidation */ + ret = dict_foreach (local->xattr, up_filter_unregd_xattr, priv->xattrs); if (ret < 0) { op_ret = ret; goto out; } + if (dict_key_count(local->xattr) == 0) { + gf_msg_trace (this->name, 0, "None of xattrs requested for" + " invalidation, were changed. Nothing to " + "invalidate"); + goto out; /* nothing to invalidate */ + } + ret = syncop_fstat (FIRST_CHILD(frame->this), local->fd, &stbuf, NULL, NULL); if (ret == 0) @@ -1758,9 +1782,13 @@ up_fremovexattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, upcall_local_t *local = NULL; struct iatt stbuf = {0,}; int ret = 0; + upcall_private_t *priv = NULL; EXIT_IF_UPCALL_OFF (this, out); + priv = this->private; + GF_VALIDATE_OR_GOTO (this->name, priv, out); + client = frame->root->client; local = frame->local; @@ -1769,6 +1797,21 @@ up_fremovexattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, } flags = UP_XATTR_RM; + /* Remove the xattrs from the dict, if they are not registered for + * cache invalidation */ + ret = dict_foreach (local->xattr, up_filter_unregd_xattr, priv->xattrs); + if (ret < 0) { + op_ret = ret; + goto out; + } + + if (dict_key_count(local->xattr) == 0) { + gf_msg_trace (this->name, 0, "None of xattrs requested for" + " invalidation, were changed. Nothing to " + "invalidate"); + goto out; /* nothing to invalidate */ + } + ret = syncop_fstat (FIRST_CHILD(frame->this), local->fd, &stbuf, NULL, NULL); if (ret == 0) @@ -1828,9 +1871,13 @@ up_removexattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, upcall_local_t *local = NULL; struct iatt stbuf = {0,}; int ret = 0; + upcall_private_t *priv = NULL; EXIT_IF_UPCALL_OFF (this, out); + priv = this->private; + GF_VALIDATE_OR_GOTO (this->name, priv, out); + client = frame->root->client; local = frame->local; @@ -1839,6 +1886,21 @@ up_removexattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, } flags = UP_XATTR_RM; + /* Remove the xattrs from the dict, if they are not registered for + * cache invalidation */ + ret = dict_foreach (local->xattr, up_filter_unregd_xattr, priv->xattrs); + if (ret < 0) { + op_ret = ret; + goto out; + } + + if (dict_key_count(local->xattr) == 0) { + gf_msg_trace (this->name, 0, "None of xattrs requested for" + " invalidation, were changed. Nothing to " + "invalidate"); + goto out; /* nothing to invalidate */ + } + ret = syncop_stat (FIRST_CHILD(frame->this), &local->loc, &stbuf, NULL, NULL); if (ret == 0) @@ -2064,6 +2126,47 @@ out: return local; } +static int32_t +update_xattrs (dict_t *dict, char *key, data_t *value, void *data) +{ + dict_t *xattrs = data; + int ret = 0; + + ret = dict_set_int8 (xattrs, key, 0); + return ret; +} + +int32_t +up_ipc (call_frame_t *frame, xlator_t *this, int32_t op, dict_t *xdata) +{ + upcall_private_t *priv = NULL; + int ret = 0; + + priv = this->private; + GF_VALIDATE_OR_GOTO (this->name, priv, out); + + if (op != GF_IPC_TARGET_UPCALL) + goto wind; + + /* TODO: Bz-1371622 Along with the xattrs also store list of clients + * that are interested in notifications, so that the notification + * can be sent to the clients that have registered. + * Once this implemented there can be unregister of xattrs for + * notifications. Until then there is no unregister of xattrs*/ + if (xdata && priv->xattrs) { + ret = dict_foreach (xdata, update_xattrs, priv->xattrs); + } + +out: + STACK_UNWIND_STRICT (ipc, frame, ret, 0, NULL); + return 0; + +wind: + STACK_WIND (frame, default_ipc_cbk, FIRST_CHILD (this), + FIRST_CHILD (this)->fops->ipc, op, xdata); + return 0; +} + int reconfigure (xlator_t *this, dict_t *options) { @@ -2071,7 +2174,7 @@ reconfigure (xlator_t *this, dict_t *options) int ret = -1; priv = this->private; - GF_ASSERT (priv); + GF_VALIDATE_OR_GOTO (this->name, priv, out); GF_OPTION_RECONF ("cache-invalidation", priv->cache_invalidation_enabled, options, bool, out); @@ -2120,6 +2223,7 @@ init (xlator_t *this) LOCK_INIT (&priv->inode_ctx_lk); INIT_LIST_HEAD (&priv->inode_ctx_list); + priv->xattrs = dict_new (); this->private = priv; priv->fini = 0; @@ -2142,6 +2246,7 @@ init (xlator_t *this) } out: if (ret) { + dict_unref (priv->xattrs); GF_FREE (priv); } @@ -2164,6 +2269,7 @@ fini (xlator_t *this) if (priv->reaper_init_done) pthread_join (priv->reaper_thr, NULL); + dict_unref (priv->xattrs); LOCK_DESTROY (&priv->inode_ctx_lk); /* Do we need to cleanup the inode_ctxs? IMO not required @@ -2226,6 +2332,7 @@ out: } struct xlator_fops fops = { + .ipc = up_ipc, /* fops which change only "ATIME" do not result * in any cache invalidation. Hence upcall * notifications are not sent in this case. diff --git a/xlators/features/upcall/src/upcall.h b/xlators/features/upcall/src/upcall.h index f86849341ec..852f5511726 100644 --- a/xlators/features/upcall/src/upcall.h +++ b/xlators/features/upcall/src/upcall.h @@ -52,6 +52,8 @@ struct _upcall_private_t { gf_boolean_t reaper_init_done; pthread_t reaper_thr; int32_t fini; + dict_t *xattrs; /* list of xattrs registered by clients + for receiving invalidation */ }; typedef struct _upcall_private_t upcall_private_t; @@ -130,6 +132,6 @@ void upcall_client_cache_invalidate (xlator_t *xl, uuid_t gfid, struct iatt *p_stbuf, struct iatt *oldp_stbuf, dict_t *xattr); -int up_filter_virtual_xattr (dict_t *d, char *k, data_t *v, void *tmp); - +int up_filter_unregd_xattr (dict_t *xattrs, char *xattr, data_t *v, + void *regd_xattrs); #endif /* __UPCALL_H__ */ diff --git a/xlators/performance/md-cache/src/md-cache-mem-types.h b/xlators/performance/md-cache/src/md-cache-mem-types.h index 6634cf962a5..5cfc68e13c1 100644 --- a/xlators/performance/md-cache/src/md-cache-mem-types.h +++ b/xlators/performance/md-cache/src/md-cache-mem-types.h @@ -18,6 +18,7 @@ enum gf_mdc_mem_types_ { gf_mdc_mt_mdc_local_t = gf_common_mt_end + 1, gf_mdc_mt_md_cache_t, gf_mdc_mt_mdc_conf_t, + gf_mdc_mt_mdc_ipc, gf_mdc_mt_end }; #endif diff --git a/xlators/performance/md-cache/src/md-cache-messages.h b/xlators/performance/md-cache/src/md-cache-messages.h index 1fe26ccc8b2..4aea7cd0a9d 100644 --- a/xlators/performance/md-cache/src/md-cache-messages.h +++ b/xlators/performance/md-cache/src/md-cache-messages.h @@ -40,7 +40,7 @@ */ #define GLFS_MD_CACHE_BASE GLFS_MSGID_COMP_MD_CACHE -#define GLFS_MD_CACHE_NUM_MESSAGES 3 +#define GLFS_MD_CACHE_NUM_MESSAGES 5 #define GLFS_MSGID_END (GLFS_MD_CACHE_BASE + GLFS_MD_CACHE_NUM_MESSAGES + 1) /* Messages with message IDs */ @@ -67,8 +67,33 @@ #define MD_CACHE_MSG_DISCARD_UPDATE (GLFS_MD_CACHE_BASE + 2) +/*! + * @messageid + * @diagnosis + * @recommendedaction None + * + */ + #define MD_CACHE_MSG_CACHE_UPDATE (GLFS_MD_CACHE_BASE + 3) +/*! + * @messageid + * @diagnosis + * @recommendedaction None + * + */ + +#define MD_CACHE_MSG_IPC_UPCALL_FAILED (GLFS_MD_CACHE_BASE + 4) + +/*! + * @messageid + * @diagnosis + * @recommendedaction None + * + */ + +#define MD_CACHE_MSG_NO_XATTR_CACHE (GLFS_MD_CACHE_BASE + 5) + /*------------*/ #define glfs_msg_end_x GLFS_MSGID_END, "Invalid: End of messages" diff --git a/xlators/performance/md-cache/src/md-cache.c b/xlators/performance/md-cache/src/md-cache.c index bb2310e8c82..e0e7ee68e3b 100644 --- a/xlators/performance/md-cache/src/md-cache.c +++ b/xlators/performance/md-cache/src/md-cache.c @@ -13,6 +13,7 @@ #include "logging.h" #include "dict.h" #include "xlator.h" +#include "syncop.h" #include "md-cache-mem-types.h" #include "compat-errno.h" #include "glusterfs-acl.h" @@ -2455,6 +2456,18 @@ is_strpfx (const char *str1, const char *str2) } +static int +mdc_key_unload_all (struct mdc_key *keys) +{ + struct mdc_key *key = NULL; + + for (key = keys; key->name; key++) { + key->load = 0; + } + + return 0; +} + int mdc_key_load_set (struct mdc_key *keys, char *pattern, gf_boolean_t val) { @@ -2545,12 +2558,129 @@ out: return ret; } +struct mdc_ipc { + xlator_t *this; + dict_t *xattr; +}; + +static int +mdc_send_xattrs_cbk (int ret, call_frame_t *frame, void *data) +{ + struct mdc_ipc *tmp = data; + + if (ret < 0) { + mdc_key_unload_all (mdc_keys); + gf_msg ("md-cache", GF_LOG_INFO, 0, MD_CACHE_MSG_NO_XATTR_CACHE, + "Disabled cache for all xattrs, as registering for " + "xattr cache invalidation failed"); + } + STACK_DESTROY (frame->root); + dict_unref (tmp->xattr); + GF_FREE (tmp); + + return 0; +} + +static int +mdc_send_xattrs (void *data) +{ + int ret = 0; + struct mdc_ipc *tmp = data; + + ret = syncop_ipc (FIRST_CHILD (tmp->this), GF_IPC_TARGET_UPCALL, + tmp->xattr, NULL); + DECODE_SYNCOP_ERR (ret); + if (ret < 0) { + gf_msg (tmp->this->name, GF_LOG_WARNING, errno, + MD_CACHE_MSG_IPC_UPCALL_FAILED, "Registering the list " + "of xattrs that needs invalidaton, with upcall, failed"); + } + + return ret; +} + + +static int +mdc_register_xattr_inval (xlator_t *this) +{ + dict_t *xattr = NULL; + int ret = 0; + struct mdc_conf *conf = NULL; + call_frame_t *frame = NULL; + struct mdc_ipc *data = NULL; + + conf = this->private; + + LOCK (&conf->lock); + { + if (!conf->mdc_invalidation) { + UNLOCK (&conf->lock); + goto out; + } + } + UNLOCK (&conf->lock); + + xattr = dict_new (); + if (!xattr) { + gf_msg (this->name, GF_LOG_WARNING, ENOMEM, + MD_CACHE_MSG_NO_MEMORY, "dict_new failed"); + ret = -1; + goto out; + } + + mdc_load_reqs (this, xattr); + + frame = create_frame (this, this->ctx->pool); + if (!frame) { + gf_msg (this->name, GF_LOG_ERROR, ENOMEM, + MD_CACHE_MSG_NO_MEMORY, + "failed to create the frame"); + ret = -1; + goto out; + } + + data = GF_CALLOC (1, sizeof (struct mdc_ipc), gf_mdc_mt_mdc_ipc); + if (!data) { + gf_msg (this->name, GF_LOG_ERROR, ENOMEM, + MD_CACHE_MSG_NO_MEMORY, + "failed to allocate memory"); + ret = -1; + goto out; + } + + data->this = this; + data->xattr = xattr; + ret = synctask_new (this->ctx->env, mdc_send_xattrs, mdc_send_xattrs_cbk, + frame, data); + if (ret < 0) { + gf_msg (this->name, GF_LOG_WARNING, errno, + MD_CACHE_MSG_IPC_UPCALL_FAILED, "Registering the list " + "of xattrs that needs invalidaton, with upcall, failed"); + } + +out: + if (ret < 0) { + mdc_key_unload_all (mdc_keys); + if (xattr) + dict_unref (xattr); + if (frame) + STACK_DESTROY (frame->root); + GF_FREE (data); + gf_msg (this->name, GF_LOG_INFO, 0, MD_CACHE_MSG_NO_XATTR_CACHE, + "Disabled cache for all xattrs, as registering for " + "xattr cache invalidation failed"); + } + + return ret; +} + int reconfigure (xlator_t *this, dict_t *options) { struct mdc_conf *conf = NULL; int timeout = 0; + int ret = 0; conf = this->private; @@ -2589,6 +2719,8 @@ reconfigure (xlator_t *this, dict_t *options) goto out; } conf->timeout = timeout; + + ret = mdc_register_xattr_inval (this); out: return 0; } @@ -2686,22 +2818,28 @@ notify (xlator_t *this, int event, void *data, ...) switch (event) { case GF_EVENT_CHILD_DOWN: case GF_EVENT_SOME_CHILD_DOWN: - case GF_EVENT_CHILD_MODIFIED: time (&now); mdc_update_child_down_time (this, &now); - ret = default_notify (this, event, data); break; case GF_EVENT_UPCALL: if (conf->mdc_invalidation) ret = mdc_invalidate (this, data); - if (default_notify (this, event, data) != 0) - ret = -1; + break; + case GF_EVENT_CHILD_MODIFIED: + time (&now); + mdc_update_child_down_time (this, &now); + ret = mdc_register_xattr_inval (this); + break; + case GF_EVENT_CHILD_UP: + ret = mdc_register_xattr_inval (this); break; default: - ret = default_notify (this, event, data); break; } + if (default_notify (this, event, data) != 0) + ret = -1; + return ret; } |