3604df
From 66ea04f631a46c12fe1e40d1bb710d64e34764b2 Mon Sep 17 00:00:00 2001
3604df
From: Poornima G <pgurusid@redhat.com>
3604df
Date: Fri, 11 Dec 2015 05:12:07 -0500
3604df
Subject: [PATCH 116/141] md-cache: Add cache invalidation support for metadata cache
3604df
3604df
Problem:
3604df
md-cache currently updates its stat in cbks of selected fops.
3604df
The default cache time is 1 second, if this is increasd to reap the
3604df
benefits of caching, we may end up with stale cache for long time,
3604df
as there is no logic yet to notify md-cache of backend changes by
3604df
another client.
3604df
3604df
Solution:
3604df
Use the existing upcall mechanism to invalidate the cache.
3604df
For this feature to work, "features.cache-invalidation" volume
3604df
option should be enabled.
3604df
3604df
This patch as is doesn't improve any performance, the benifit of the
3604df
patch is that it provides coherency for stat cache, hence the cache
3604df
timeout can be quite longer which in turn can improve the performance.
3604df
3604df
Change-Id: I2dbb0afa7b5e4a5a248f910188e0918e02f18692
3604df
BUG: 1284873
3604df
Signed-off-by: Poornima G <pgurusid@redhat.com>
3604df
Reviewed-on: http://review.gluster.org/12951
3604df
Smoke: Gluster Build System <jenkins@build.gluster.org>
3604df
CentOS-regression: Gluster Build System <jenkins@build.gluster.org>
3604df
NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org>
3604df
Reviewed-by: Raghavendra G <rgowdapp@redhat.com>
3604df
Reviewed-on: https://code.engineering.redhat.com/gerrit/87029
3604df
Reviewed-by: Rajesh Joseph <rjoseph@redhat.com>
3604df
Tested-by: Rajesh Joseph <rjoseph@redhat.com>
3604df
---
3604df
 tests/bugs/md-cache/bug-1211863.t                  |   60 ++++-
3604df
 xlators/mgmt/glusterd/src/glusterd-volume-set.c    |    6 +
3604df
 .../performance/md-cache/src/md-cache-messages.h   |   10 +-
3604df
 xlators/performance/md-cache/src/md-cache.c        |  258 ++++++++++++++++++--
3604df
 4 files changed, 304 insertions(+), 30 deletions(-)
3604df
3604df
diff --git a/tests/bugs/md-cache/bug-1211863.t b/tests/bugs/md-cache/bug-1211863.t
3604df
index b969fbb..4fa9e33 100644
3604df
--- a/tests/bugs/md-cache/bug-1211863.t
3604df
+++ b/tests/bugs/md-cache/bug-1211863.t
3604df
@@ -5,18 +5,64 @@
3604df
 
3604df
 cleanup;
3604df
 
3604df
-TEST glusterd
3604df
+## 1. Start glusterd
3604df
+TEST glusterd;
3604df
 
3604df
-TEST $CLI volume create $V0 $H0:$B0/$V0
3604df
+## 2. Lets create volume
3604df
+TEST $CLI volume create $V0 $H0:$B0/${V0}{1,2,3};
3604df
+
3604df
+## 3. Start the volume
3604df
 TEST $CLI volume start $V0
3604df
 
3604df
-TEST $CLI volume set $V0 cache-samba-metadata on
3604df
-EXPECT 'on' volinfo_field $V0 'performance.cache-samba-metadata'
3604df
+## 4. Enable the upcall xlator, and increase the md-cache timeout to max
3604df
+TEST $CLI volume set $V0 performance.md-cache-timeout 600
3604df
+TEST $CLI volume set $V0 performance.cache-samba-metadata on
3604df
 
3604df
-TEST $CLI volume set $V0 cache-samba-metadata off
3604df
-EXPECT 'off' volinfo_field $V0 'performance.cache-samba-metadata'
3604df
+## 6. Create two gluster mounts
3604df
+TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0
3604df
+TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M1
3604df
+
3604df
+## 8. Create a file
3604df
+TEST touch $M0/file1
3604df
+
3604df
+## 9. Setxattr from mount-0
3604df
+TEST "setfattr -n user.DOSATTRIB -v "abc" $M0/file1"
3604df
+## 10. Getxattr from mount-1, this should return the correct value as it is a fresh getxattr
3604df
+TEST "getfattr -n user.DOSATTRIB $M1/file1 | grep -q abc"
3604df
+
3604df
+## 11. Now modify the same xattr from mount-0 again
3604df
+TEST "setfattr -n user.DOSATTRIB -v "xyz" $M0/file1"
3604df
+## 12. Since the xattr is already cached in mount-1 it returns the old xattr
3604df
+       #value, until the timeout (600)
3604df
+TEST "getfattr -n user.DOSATTRIB $M1/file1 | grep -q abc"
3604df
+
3604df
+## 13. Unmount to clean all the cache
3604df
+EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0
3604df
+EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M1
3604df
 
3604df
+TEST $CLI volume set $V0 features.cache-invalidation on
3604df
+TEST $CLI volume set $V0 features.cache-invalidation-timeout 600
3604df
+
3604df
+## 18. Restart the volume to restart the bick process
3604df
 TEST $CLI volume stop $V0
3604df
-TEST $CLI volume delete $V0
3604df
+TEST $CLI volume start $V0
3604df
+
3604df
+## 20. Create two gluster mounts
3604df
+TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0
3604df
+TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M1
3604df
+
3604df
+## 22. Repeat the tests 11-14, but this time since cache invalidation is on,
3604df
+       #the getxattr will reflect the new value
3604df
+TEST "setfattr -n user.DOSATTRIB -v "abc" $M0/file1"
3604df
+TEST "getfattr -n user.DOSATTRIB $M1/file1 | grep -q abc"
3604df
+TEST "setfattr -n user.DOSATTRIB -v "xyz" $M0/file1"
3604df
+sleep 2; #There can be a very very small window where the next getxattr
3604df
+         #reaches md-cache, before the cache-invalidation caused by previous
3604df
+         #setxattr, reaches md-cache. Hence sleeping for 2 sec.
3604df
+         #Also it should not be > 600.
3604df
+TEST "getfattr -n user.DOSATTRIB $M1/file1 | grep -q xyz"
3604df
+
3604df
+TEST $CLI volume set $V0 cache-samba-metadata off
3604df
+EXPECT 'off' volinfo_field $V0 'performance.cache-samba-metadata'
3604df
 
3604df
 cleanup;
3604df
diff --git a/xlators/mgmt/glusterd/src/glusterd-volume-set.c b/xlators/mgmt/glusterd/src/glusterd-volume-set.c
3604df
index 100e032..de7bcb4 100644
3604df
--- a/xlators/mgmt/glusterd/src/glusterd-volume-set.c
3604df
+++ b/xlators/mgmt/glusterd/src/glusterd-volume-set.c
3604df
@@ -1967,6 +1967,12 @@ struct volopt_map_entry glusterd_volopt_map[] = {
3604df
           .op_version = 2,
3604df
           .flags      = OPT_FLAG_CLIENT_OPT
3604df
         },
3604df
+        { .key        = "features.cache-invalidation",
3604df
+          .voltype    = "performance/md-cache",
3604df
+          .option     = "cache-invalidation",
3604df
+          .op_version = GD_OP_VERSION_3_9_0,
3604df
+          .flags      = OPT_FLAG_CLIENT_OPT
3604df
+        },
3604df
 
3604df
 	/* Feature translators */
3604df
         { .key         = "features.uss",
3604df
diff --git a/xlators/performance/md-cache/src/md-cache-messages.h b/xlators/performance/md-cache/src/md-cache-messages.h
3604df
index 2fe8d45..a4259ba 100644
3604df
--- a/xlators/performance/md-cache/src/md-cache-messages.h
3604df
+++ b/xlators/performance/md-cache/src/md-cache-messages.h
3604df
@@ -40,7 +40,7 @@
3604df
  */
3604df
 
3604df
 #define GLFS_MD_CACHE_BASE                   GLFS_MSGID_COMP_MD_CACHE
3604df
-#define GLFS_MD_CACHE_NUM_MESSAGES           1
3604df
+#define GLFS_MD_CACHE_NUM_MESSAGES           2
3604df
 #define GLFS_MSGID_END  (GLFS_MD_CACHE_BASE + GLFS_MD_CACHE_NUM_MESSAGES + 1)
3604df
 
3604df
 /* Messages with message IDs */
3604df
@@ -58,6 +58,14 @@
3604df
 
3604df
 #define MD_CACHE_MSG_NO_MEMORY        (GLFS_MD_CACHE_BASE + 1)
3604df
 
3604df
+/*!
3604df
+ * @messageid
3604df
+ * @diagnosis
3604df
+ * @recommendedaction  None
3604df
+ *
3604df
+ */
3604df
+
3604df
+#define MD_CACHE_MSG_DISCARD_UPDATE    (GLFS_MD_CACHE_BASE + 2)
3604df
 
3604df
 /*------------*/
3604df
 #define glfs_msg_end_x GLFS_MSGID_END, "Invalid: End of messages"
3604df
diff --git a/xlators/performance/md-cache/src/md-cache.c b/xlators/performance/md-cache/src/md-cache.c
3604df
index 1ad9e8e..fd2b366 100644
3604df
--- a/xlators/performance/md-cache/src/md-cache.c
3604df
+++ b/xlators/performance/md-cache/src/md-cache.c
3604df
@@ -16,6 +16,8 @@
3604df
 #include "md-cache-mem-types.h"
3604df
 #include "compat-errno.h"
3604df
 #include "glusterfs-acl.h"
3604df
+#include "defaults.h"
3604df
+#include "upcall-utils.h"
3604df
 #include <assert.h>
3604df
 #include <sys/time.h>
3604df
 #include "md-cache-messages.h"
3604df
@@ -34,6 +36,9 @@ struct mdc_conf {
3604df
 	gf_boolean_t force_readdirp;
3604df
         gf_boolean_t cache_swift_metadata;
3604df
         gf_boolean_t cache_samba_metadata;
3604df
+        gf_boolean_t mdc_invalidation;
3604df
+        time_t last_child_down;
3604df
+        gf_lock_t lock;
3604df
 };
3604df
 
3604df
 
3604df
@@ -328,20 +333,58 @@ unlock:
3604df
 }
3604df
 
3604df
 
3604df
+/* Cache is valid if:
3604df
+ * - It is not cached before any brick was down. Brick down case is handled by
3604df
+ *   invalidating all the cache when any brick went down.
3604df
+ * - The cache time is not expired
3604df
+ */
3604df
+static gf_boolean_t
3604df
+__is_cache_valid (xlator_t *this, time_t mdc_time)
3604df
+{
3604df
+        time_t           now             = 0;
3604df
+        gf_boolean_t     ret             = _gf_true;
3604df
+        struct mdc_conf *conf            = NULL;
3604df
+        int              timeout         = 0;
3604df
+        time_t           last_child_down = 0;
3604df
+
3604df
+        conf = this->private;
3604df
+
3604df
+        /* conf->lock here is not taken deliberately, so that the multi
3604df
+         * threaded IO doesn't contend on a global lock. While updating
3604df
+         * the variable, the lock is taken, so that atleast the writes are
3604df
+         * intact. The read of last_child_down may return junk, but that
3604df
+         * is for a very short period of time.
3604df
+         */
3604df
+        last_child_down = conf->last_child_down;
3604df
+        timeout = conf->timeout;
3604df
+
3604df
+        time (&now;;
3604df
+
3604df
+        if ((mdc_time == 0) ||
3604df
+            ((last_child_down != 0) && (mdc_time < last_child_down))) {
3604df
+                ret = _gf_false;
3604df
+                goto out;
3604df
+        }
3604df
+
3604df
+        if (now >= (mdc_time + timeout)) {
3604df
+                ret = _gf_false;
3604df
+        }
3604df
+
3604df
+out:
3604df
+        return ret;
3604df
+}
3604df
+
3604df
+
3604df
 static gf_boolean_t
3604df
 is_md_cache_iatt_valid (xlator_t *this, struct md_cache *mdc)
3604df
 {
3604df
-	struct mdc_conf *conf = NULL;
3604df
-	time_t           now = 0;
3604df
         gf_boolean_t     ret = _gf_true;
3604df
-	conf = this->private;
3604df
-
3604df
-	time (&now;;
3604df
 
3604df
         LOCK (&mdc->lock);
3604df
         {
3604df
-                if (now >= (mdc->ia_time + conf->timeout))
3604df
-                        ret = _gf_false;
3604df
+                ret = __is_cache_valid (this, mdc->ia_time);
3604df
+                if (ret == _gf_false)
3604df
+                        mdc->ia_time = 0;
3604df
         }
3604df
         UNLOCK (&mdc->lock);
3604df
 
3604df
@@ -352,18 +395,13 @@ is_md_cache_iatt_valid (xlator_t *this, struct md_cache *mdc)
3604df
 static gf_boolean_t
3604df
 is_md_cache_xatt_valid (xlator_t *this, struct md_cache *mdc)
3604df
 {
3604df
-	struct mdc_conf *conf = NULL;
3604df
-	time_t           now = 0;
3604df
         gf_boolean_t     ret = _gf_true;
3604df
 
3604df
-	conf = this->private;
3604df
-
3604df
-	time (&now;;
3604df
-
3604df
         LOCK (&mdc->lock);
3604df
         {
3604df
-                if (now >= (mdc->xa_time + conf->timeout))
3604df
-                        ret = _gf_false;
3604df
+                ret = __is_cache_valid (this, mdc->xa_time);
3604df
+                if (ret == _gf_false)
3604df
+                        mdc->xa_time = 0;
3604df
         }
3604df
         UNLOCK (&mdc->lock);
3604df
 
3604df
@@ -413,12 +451,14 @@ int
3604df
 mdc_inode_iatt_set_validate(xlator_t *this, inode_t *inode, struct iatt *prebuf,
3604df
 			    struct iatt *iatt)
3604df
 {
3604df
-        int              ret = -1;
3604df
+        int              ret = 0;
3604df
         struct md_cache *mdc = NULL;
3604df
 
3604df
         mdc = mdc_inode_prep (this, inode);
3604df
-        if (!mdc)
3604df
+        if (!mdc) {
3604df
+                ret = -1;
3604df
                 goto out;
3604df
+        }
3604df
 
3604df
         LOCK (&mdc->lock);
3604df
         {
3604df
@@ -427,6 +467,33 @@ mdc_inode_iatt_set_validate(xlator_t *this, inode_t *inode, struct iatt *prebuf,
3604df
                         goto unlock;
3604df
                 }
3604df
 
3604df
+                /* There could be a race in invalidation, where the
3604df
+                 * invalidations in order A, B reaches md-cache in the order
3604df
+                 * B, A. Hence, make sure the invalidation A is discarded if
3604df
+                 * it comes after B. ctime of a file is always in ascending
3604df
+                 * order unlike atime and mtime(which can be changed by user
3604df
+                 * to any date), also ctime gets updates when atime/mtime
3604df
+                 * changes, hence check for ctime only.
3604df
+                 */
3604df
+                if (mdc->md_ctime > iatt->ia_ctime) {
3604df
+                        gf_msg_callingfn (this->name, GF_LOG_DEBUG, EINVAL,
3604df
+                                          MD_CACHE_MSG_DISCARD_UPDATE,
3604df
+                                          "discarding the iatt validate "
3604df
+                                          "request");
3604df
+                        ret = -1;
3604df
+                        goto unlock;
3604df
+
3604df
+                }
3604df
+                if ((mdc->md_ctime == iatt->ia_ctime) &&
3604df
+                    (mdc->md_ctime_nsec > iatt->ia_ctime_nsec)) {
3604df
+                        gf_msg_callingfn (this->name, GF_LOG_DEBUG, EINVAL,
3604df
+                                          MD_CACHE_MSG_DISCARD_UPDATE,
3604df
+                                          "discarding the iatt validate "
3604df
+                                          "request(ctime_nsec)");
3604df
+                        ret = -1;
3604df
+                        goto unlock;
3604df
+                }
3604df
+
3604df
 		/*
3604df
 		 * Invalidate the inode if the mtime or ctime has changed
3604df
 		 * and the prebuf doesn't match the value we have cached.
3604df
@@ -450,7 +517,7 @@ mdc_inode_iatt_set_validate(xlator_t *this, inode_t *inode, struct iatt *prebuf,
3604df
         }
3604df
 unlock:
3604df
         UNLOCK (&mdc->lock);
3604df
-        ret = 0;
3604df
+
3604df
 out:
3604df
         return ret;
3604df
 }
3604df
@@ -2300,15 +2367,81 @@ mdc_key_load_set (struct mdc_key *keys, char *pattern, gf_boolean_t val)
3604df
 	return 0;
3604df
 }
3604df
 
3604df
+struct set {
3604df
+       inode_t *inode;
3604df
+       xlator_t *this;
3604df
+};
3604df
+
3604df
+static int
3604df
+mdc_inval_xatt (dict_t *d, char *k, data_t *v, void *tmp)
3604df
+{
3604df
+        struct set *tmp1 = NULL;
3604df
+        int         ret  = 0;
3604df
+
3604df
+        tmp1 = (struct set *)tmp;
3604df
+        ret = mdc_inode_xatt_unset (tmp1->this, tmp1->inode, k);
3604df
+        return ret;
3604df
+}
3604df
+
3604df
+static int
3604df
+mdc_invalidate (xlator_t *this, void *data)
3604df
+{
3604df
+        struct gf_upcall                    *up_data    = NULL;
3604df
+        struct gf_upcall_cache_invalidation *up_ci      = NULL;
3604df
+        inode_t                             *inode      = NULL;
3604df
+        int                                  ret        = 0;
3604df
+        struct set                           tmp        = {0, };
3604df
+        inode_table_t                       *itable     = NULL;
3604df
+
3604df
+        up_data = (struct gf_upcall *)data;
3604df
+
3604df
+        if (up_data->event_type != GF_UPCALL_CACHE_INVALIDATION)
3604df
+                goto out;
3604df
+
3604df
+        up_ci = (struct gf_upcall_cache_invalidation *)up_data->data;
3604df
+
3604df
+        itable = ((xlator_t *)this->graph->top)->itable;
3604df
+        inode = inode_find (itable, up_data->gfid);
3604df
+        if (!inode) {
3604df
+                ret = -1;
3604df
+                goto out;
3604df
+        }
3604df
+
3604df
+        if (up_ci->flags & IATT_UPDATE_FLAGS) {
3604df
+                ret = mdc_inode_iatt_set_validate (this, inode, NULL,
3604df
+                                                   &up_ci->stat);
3604df
+                /* one of the scenarios where ret < 0 is when this invalidate
3604df
+                 * is older than the current stat, in that case do not
3604df
+                 * update the xattrs as well
3604df
+                 */
3604df
+                if (ret < 0)
3604df
+                        goto out;
3604df
+        }
3604df
+        if (up_ci->flags & UP_XATTR) {
3604df
+                ret = mdc_inode_xatt_update (this, inode, up_ci->dict);
3604df
+        } else if (up_ci->flags & UP_XATTR_RM) {
3604df
+                tmp.inode = inode;
3604df
+                tmp.this = this;
3604df
+                ret = dict_foreach (up_ci->dict, mdc_inval_xatt, &tmp);
3604df
+        }
3604df
+
3604df
+out:
3604df
+        if (inode)
3604df
+                inode_unref (inode);
3604df
+
3604df
+        return ret;
3604df
+}
3604df
+
3604df
 
3604df
 int
3604df
 reconfigure (xlator_t *this, dict_t *options)
3604df
 {
3604df
 	struct mdc_conf *conf = NULL;
3604df
+        int    timeout = 0;
3604df
 
3604df
 	conf = this->private;
3604df
 
3604df
-	GF_OPTION_RECONF ("md-cache-timeout", conf->timeout, options, int32, out);
3604df
+	GF_OPTION_RECONF ("md-cache-timeout", timeout, options, int32, out);
3604df
 
3604df
 	GF_OPTION_RECONF ("cache-selinux", conf->cache_selinux, options, bool, out);
3604df
 	mdc_key_load_set (mdc_keys, "security.", conf->cache_selinux);
3604df
@@ -2330,7 +2463,19 @@ reconfigure (xlator_t *this, dict_t *options)
3604df
                           conf->cache_samba_metadata);
3604df
 
3604df
 	GF_OPTION_RECONF("force-readdirp", conf->force_readdirp, options, bool, out);
3604df
-
3604df
+        GF_OPTION_RECONF("cache-invalidation", conf->mdc_invalidation, options,
3604df
+                         bool, out);
3604df
+
3604df
+        /* If timeout is greater than 60s (default before the patch that added
3604df
+         * cache invalidation support was added) then, cache invalidation
3604df
+         * feature for md-cache needs to be enabled, if not set timeout to the
3604df
+         * previous max which is 60s
3604df
+         */
3604df
+        if ((timeout > 60) && (!conf->mdc_invalidation)) {
3604df
+                        conf->timeout = 60;
3604df
+                        goto out;
3604df
+        }
3604df
+        conf->timeout = timeout;
3604df
 out:
3604df
 	return 0;
3604df
 }
3604df
@@ -2348,6 +2493,7 @@ int
3604df
 init (xlator_t *this)
3604df
 {
3604df
 	struct mdc_conf *conf = NULL;
3604df
+        int    timeout = 0;
3604df
 
3604df
 	conf = GF_CALLOC (sizeof (*conf), 1, gf_mdc_mt_mdc_conf_t);
3604df
 	if (!conf) {
3604df
@@ -2356,7 +2502,7 @@ init (xlator_t *this)
3604df
 		return -1;
3604df
 	}
3604df
 
3604df
-        GF_OPTION_INIT ("md-cache-timeout", conf->timeout, int32, out);
3604df
+        GF_OPTION_INIT ("md-cache-timeout", timeout, int32, out);
3604df
 
3604df
 	GF_OPTION_INIT ("cache-selinux", conf->cache_selinux, bool, out);
3604df
 	mdc_key_load_set (mdc_keys, "security.", conf->cache_selinux);
3604df
@@ -2378,6 +2524,22 @@ init (xlator_t *this)
3604df
                           conf->cache_samba_metadata);
3604df
 
3604df
 	GF_OPTION_INIT("force-readdirp", conf->force_readdirp, bool, out);
3604df
+        GF_OPTION_INIT("cache-invalidation", conf->mdc_invalidation, bool, out);
3604df
+
3604df
+        LOCK_INIT (&conf->lock);
3604df
+        time (&conf->last_child_down);
3604df
+
3604df
+        /* If timeout is greater than 60s (default before the patch that added
3604df
+         * cache invalidation support was added) then, cache invalidation
3604df
+         * feature for md-cache needs to be enabled, if not set timeout to the
3604df
+         * previous max which is 60s
3604df
+         */
3604df
+        if ((timeout > 60) && (!conf->mdc_invalidation)) {
3604df
+                        conf->timeout = 60;
3604df
+                        goto out;
3604df
+        }
3604df
+        conf->timeout = timeout;
3604df
+
3604df
 out:
3604df
 	this->private = conf;
3604df
 
3604df
@@ -2386,6 +2548,52 @@ out:
3604df
 
3604df
 
3604df
 void
3604df
+mdc_update_child_down_time (xlator_t *this, time_t *now)
3604df
+{
3604df
+        struct mdc_conf *conf = NULL;
3604df
+
3604df
+        conf = this->private;
3604df
+
3604df
+        LOCK (&conf->lock);
3604df
+        {
3604df
+                conf->last_child_down = *now;
3604df
+        }
3604df
+        UNLOCK (&conf->lock);
3604df
+}
3604df
+
3604df
+
3604df
+int
3604df
+notify (xlator_t *this, int event, void *data, ...)
3604df
+{
3604df
+        int ret = 0;
3604df
+        struct mdc_conf *conf = NULL;
3604df
+        time_t           now = 0;
3604df
+
3604df
+        conf = this->private;
3604df
+        switch (event) {
3604df
+        case GF_EVENT_CHILD_DOWN:
3604df
+        case GF_EVENT_SOME_CHILD_DOWN:
3604df
+        case GF_EVENT_CHILD_MODIFIED:
3604df
+                time (&now;;
3604df
+                mdc_update_child_down_time (this, &now;;
3604df
+                ret = default_notify (this, event, data);
3604df
+                break;
3604df
+        case GF_EVENT_UPCALL:
3604df
+                if (conf->mdc_invalidation)
3604df
+                        ret = mdc_invalidate (this, data);
3604df
+                        if (default_notify (this, event, data) != 0)
3604df
+                                ret = -1;
3604df
+                break;
3604df
+        default:
3604df
+                ret = default_notify (this, event, data);
3604df
+                break;
3604df
+        }
3604df
+
3604df
+        return ret;
3604df
+}
3604df
+
3604df
+
3604df
+void
3604df
 fini (xlator_t *this)
3604df
 {
3604df
         return;
3604df
@@ -2453,7 +2661,7 @@ struct volume_options options[] = {
3604df
         { .key = {"md-cache-timeout"},
3604df
           .type = GF_OPTION_TYPE_INT,
3604df
           .min = 0,
3604df
-          .max = 60,
3604df
+          .max = 600,
3604df
           .default_value = "1",
3604df
           .description = "Time period after which cache has to be refreshed",
3604df
         },
3604df
@@ -2463,5 +2671,11 @@ struct volume_options options[] = {
3604df
 	  .description = "Convert all readdir requests to readdirplus to "
3604df
 			 "collect stat info on each entry.",
3604df
 	},
3604df
+        { .key = {"cache-invalidation"},
3604df
+          .type = GF_OPTION_TYPE_BOOL,
3604df
+          .default_value = "false",
3604df
+          .description = "When \"on\", invalidates/updates the metadata cache "
3604df
+                         "on receiving of the cache-invalidation notifications",
3604df
+        },
3604df
     { .key = {NULL} },
3604df
 };
3604df
-- 
3604df
1.7.1
3604df