Blob Blame History Raw
From 90a30273c923cc3ee422030a962ce26aa406fd34 Mon Sep 17 00:00:00 2001
From: Poornima G <pgurusid@redhat.com>
Date: Mon, 11 Jul 2016 15:04:55 +0530
Subject: [PATCH 127/141] md-cache: Register the list of xattrs with cache-invalidation

Issue:
md-cache caches a specified list of xattrs, and when cache invalidation
is enabled, it makes sense to recieve invalidation only when those xattrs
are modified by other clients. But the current implementation of upcall
is that, it will send invalidation when any of the on-disk xattrs is modified.

Solution:
md-cache sends a list of xattrs that it is interested in, to upcall by
issuing an ipc(). The challenge here is to make sure everytime a brick
goes offline and comes back up, the ipc() needs to be issued to the
bricks. Hence ipc() is sent from md-cache every time there is a
CHILD_UP/CHILD_MODIFIED event.

TODO:
There will be patches following, in cluster xlators, to implement ipc fop.

Change-Id: I6efcf3df474f5ce6eabd3d6694c00c7bd89bc25d
BUG: 1284873
Signed-off-by: Poornima G <pgurusid@redhat.com>
Reviewed-on: http://review.gluster.org/15002
Smoke: Gluster Build System <jenkins@build.gluster.org>
CentOS-regression: Gluster Build System <jenkins@build.gluster.org>
Reviewed-by: Rajesh Joseph <rjoseph@redhat.com>
NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org>
Reviewed-by: Prashanth Pai <ppai@redhat.com>
Reviewed-by: Raghavendra G <rgowdapp@redhat.com>
Reviewed-on: https://code.engineering.redhat.com/gerrit/87040
Tested-by: Rajesh Joseph <rjoseph@redhat.com>
---
 api/src/glfs-internal.h                            |   22 ---
 libglusterfs/src/dict.c                            |   20 +++
 libglusterfs/src/dict.h                            |    2 +
 libglusterfs/src/syncop.h                          |   23 +++
 xlators/features/upcall/src/upcall-internal.c      |   12 ++-
 xlators/features/upcall/src/upcall.c               |  117 +++++++++++++++-
 xlators/features/upcall/src/upcall.h               |    6 +-
 .../performance/md-cache/src/md-cache-mem-types.h  |    1 +
 .../performance/md-cache/src/md-cache-messages.h   |   27 ++++-
 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 19958d8..458702e 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 25ddff0..d0c56d5 100644
--- a/libglusterfs/src/dict.c
+++ b/libglusterfs/src/dict.c
@@ -475,6 +475,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 c5b8267..b0efad7 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 c2387e6..0d0da58 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 f3c81af..d3c9b91 100644
--- a/xlators/features/upcall/src/upcall-internal.c
+++ b/xlators/features/upcall/src/upcall-internal.c
@@ -436,10 +436,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 912d222..41189c9 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)
@@ -1674,9 +1686,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;
 
@@ -1685,13 +1701,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)
@@ -1752,9 +1776,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;
 
@@ -1763,6 +1791,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)
@@ -1822,9 +1865,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;
 
@@ -1833,6 +1880,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)
@@ -2063,6 +2125,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)
 {
@@ -2070,7 +2173,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);
@@ -2119,6 +2222,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;
@@ -2141,6 +2245,7 @@ init (xlator_t *this)
         }
 out:
         if (ret) {
+                dict_unref (priv->xattrs);
                 GF_FREE (priv);
         }
 
@@ -2163,6 +2268,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 f868493..852f551 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 6634cf9..5cfc68e 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 1fe26cc..4aea7cd 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 a8fabb5..a3f13ff 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"
@@ -2471,6 +2472,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)
 {
@@ -2561,12 +2574,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;
 
@@ -2605,6 +2735,8 @@ reconfigure (xlator_t *this, dict_t *options)
                         goto out;
         }
         conf->timeout = timeout;
+
+        ret = mdc_register_xattr_inval (this);
 out:
 	return 0;
 }
@@ -2702,22 +2834,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;
 }
 
-- 
1.7.1