"Fossies" - the Fresh Open Source Software Archive

Member "glusterfs-7.6/xlators/performance/md-cache/src/md-cache.c" (18 May 2020, 105758 Bytes) of package /linux/misc/glusterfs-7.6.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "md-cache.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 7.5_vs_7.6.

    1 /*
    2   Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
    3   This file is part of GlusterFS.
    4 
    5   This file is licensed to you under your choice of the GNU Lesser
    6   General Public License, version 3 or any later version (LGPLv3 or
    7   later), or the GNU General Public License, version 2 (GPLv2), in all
    8   cases as published by the Free Software Foundation.
    9 */
   10 
   11 #include <glusterfs/timespec.h>
   12 #include <glusterfs/glusterfs.h>
   13 #include <glusterfs/defaults.h>
   14 #include <glusterfs/logging.h>
   15 #include <glusterfs/dict.h>
   16 #include <glusterfs/xlator.h>
   17 #include <glusterfs/syncop.h>
   18 #include "md-cache-mem-types.h"
   19 #include <glusterfs/compat-errno.h>
   20 #include <glusterfs/glusterfs-acl.h>
   21 #include <glusterfs/defaults.h>
   22 #include <glusterfs/upcall-utils.h>
   23 #include <assert.h>
   24 #include <sys/time.h>
   25 #include "md-cache-messages.h"
   26 #include <glusterfs/statedump.h>
   27 #include <glusterfs/atomic.h>
   28 
   29 /* TODO:
   30    - cache symlink() link names and nuke symlink-cache
   31    - send proper postbuf in setattr_cbk even when op_ret = -1
   32 */
   33 
   34 struct mdc_statfs_cache {
   35     pthread_mutex_t lock;
   36     gf_boolean_t initialized;
   37     struct timespec last_refreshed;
   38     struct statvfs buf;
   39 };
   40 
   41 struct mdc_statistics {
   42     gf_atomic_t stat_hit; /* No. of times lookup/stat was served from
   43                              mdc */
   44 
   45     gf_atomic_t stat_miss; /* No. of times valid stat wasn't present in
   46                               mdc */
   47 
   48     gf_atomic_t xattr_hit; /* No. of times getxattr was served from mdc,
   49                               Note: this doesn't count the xattr served
   50                               from lookup */
   51 
   52     gf_atomic_t xattr_miss;      /* No. of times xattr req was WIND from mdc */
   53     gf_atomic_t negative_lookup; /* No. of negative lookups */
   54     gf_atomic_t nameless_lookup; /* No. of negative lookups that were sent
   55                                     to bricks */
   56 
   57     gf_atomic_t stat_invals;  /* No. of invalidates received from upcall */
   58     gf_atomic_t xattr_invals; /* No. of invalidates received from upcall */
   59     gf_atomic_t need_lookup;  /* No. of lookups issued, because other
   60                                  xlators requested for explicit lookup */
   61 };
   62 
   63 struct mdc_conf {
   64     int timeout;
   65     gf_boolean_t cache_posix_acl;
   66     gf_boolean_t cache_glusterfs_acl;
   67     gf_boolean_t cache_selinux;
   68     gf_boolean_t cache_capability;
   69     gf_boolean_t cache_ima;
   70     gf_boolean_t force_readdirp;
   71     gf_boolean_t cache_swift_metadata;
   72     gf_boolean_t cache_samba_metadata;
   73     gf_boolean_t mdc_invalidation;
   74     gf_boolean_t global_invalidation;
   75 
   76     time_t last_child_down;
   77     gf_lock_t lock;
   78     struct mdc_statistics mdc_counter;
   79     gf_boolean_t cache_statfs;
   80     struct mdc_statfs_cache statfs_cache;
   81     char *mdc_xattr_str;
   82     gf_atomic_int32_t generation;
   83 };
   84 
   85 struct mdc_local;
   86 typedef struct mdc_local mdc_local_t;
   87 
   88 #define MDC_STACK_UNWIND(fop, frame, params...)                                \
   89     do {                                                                       \
   90         mdc_local_t *__local = NULL;                                           \
   91         xlator_t *__xl = NULL;                                                 \
   92         if (frame) {                                                           \
   93             __xl = frame->this;                                                \
   94             __local = frame->local;                                            \
   95             frame->local = NULL;                                               \
   96         }                                                                      \
   97         STACK_UNWIND_STRICT(fop, frame, params);                               \
   98         mdc_local_wipe(__xl, __local);                                         \
   99     } while (0)
  100 
  101 struct md_cache {
  102     ia_prot_t md_prot;
  103     uint32_t md_nlink;
  104     uint32_t md_uid;
  105     uint32_t md_gid;
  106     uint32_t md_atime_nsec;
  107     uint32_t md_mtime_nsec;
  108     uint32_t md_ctime_nsec;
  109     int64_t md_atime;
  110     int64_t md_mtime;
  111     int64_t md_ctime;
  112     uint64_t md_rdev;
  113     uint64_t md_size;
  114     uint64_t md_blocks;
  115     uint64_t generation;
  116     dict_t *xattr;
  117     char *linkname;
  118     time_t ia_time;
  119     time_t xa_time;
  120     gf_boolean_t need_lookup;
  121     gf_boolean_t valid;
  122     gf_boolean_t gen_rollover;
  123     gf_boolean_t invalidation_rollover;
  124     gf_lock_t lock;
  125 };
  126 
  127 struct mdc_local {
  128     loc_t loc;
  129     loc_t loc2;
  130     fd_t *fd;
  131     char *linkname;
  132     char *key;
  133     dict_t *xattr;
  134     uint64_t incident_time;
  135     bool update_cache;
  136 };
  137 
  138 int
  139 __mdc_inode_ctx_get(xlator_t *this, inode_t *inode, struct md_cache **mdc_p)
  140 {
  141     int ret = 0;
  142     struct md_cache *mdc = NULL;
  143     uint64_t mdc_int = 0;
  144 
  145     ret = __inode_ctx_get(inode, this, &mdc_int);
  146     mdc = (void *)(long)(mdc_int);
  147     if (ret == 0 && mdc_p)
  148         *mdc_p = mdc;
  149 
  150     return ret;
  151 }
  152 
  153 int
  154 mdc_inode_ctx_get(xlator_t *this, inode_t *inode, struct md_cache **mdc_p)
  155 {
  156     int ret = -1;
  157 
  158     if (!inode)
  159         goto out;
  160 
  161     LOCK(&inode->lock);
  162     {
  163         ret = __mdc_inode_ctx_get(this, inode, mdc_p);
  164     }
  165     UNLOCK(&inode->lock);
  166 
  167 out:
  168     return ret;
  169 }
  170 
  171 uint64_t
  172 __mdc_inc_generation(xlator_t *this, struct md_cache *mdc)
  173 {
  174     uint64_t gen = 0, rollover;
  175     struct mdc_conf *conf = NULL;
  176 
  177     conf = this->private;
  178 
  179     gen = GF_ATOMIC_INC(conf->generation);
  180     if (gen == 0) {
  181         mdc->gen_rollover = !mdc->gen_rollover;
  182         gen = GF_ATOMIC_INC(conf->generation);
  183         mdc->ia_time = 0;
  184         mdc->generation = 0;
  185     }
  186 
  187     rollover = mdc->gen_rollover;
  188     gen |= (rollover << 32);
  189     return gen;
  190 }
  191 
  192 uint64_t
  193 mdc_inc_generation(xlator_t *this, inode_t *inode)
  194 {
  195     struct mdc_conf *conf = NULL;
  196     uint64_t gen = 0;
  197     struct md_cache *mdc = NULL;
  198 
  199     conf = this->private;
  200 
  201     mdc_inode_ctx_get(this, inode, &mdc);
  202 
  203     if (mdc) {
  204         LOCK(&mdc->lock);
  205         {
  206             gen = __mdc_inc_generation(this, mdc);
  207         }
  208         UNLOCK(&mdc->lock);
  209     } else {
  210         gen = GF_ATOMIC_INC(conf->generation);
  211         if (gen == 0) {
  212             gen = GF_ATOMIC_INC(conf->generation);
  213         }
  214     }
  215 
  216     return gen;
  217 }
  218 
  219 uint64_t
  220 mdc_get_generation(xlator_t *this, inode_t *inode)
  221 {
  222     struct mdc_conf *conf = NULL;
  223     uint64_t gen = 0;
  224     struct md_cache *mdc = NULL;
  225 
  226     conf = this->private;
  227 
  228     mdc_inode_ctx_get(this, inode, &mdc);
  229 
  230     if (mdc) {
  231         LOCK(&mdc->lock);
  232         {
  233             gen = mdc->generation;
  234         }
  235         UNLOCK(&mdc->lock);
  236     } else
  237         gen = GF_ATOMIC_GET(conf->generation);
  238 
  239     return gen;
  240 }
  241 
  242 int
  243 __mdc_inode_ctx_set(xlator_t *this, inode_t *inode, struct md_cache *mdc)
  244 {
  245     int ret = 0;
  246     uint64_t mdc_int = 0;
  247 
  248     mdc_int = (long)mdc;
  249     ret = __inode_ctx_set(inode, this, &mdc_int);
  250 
  251     return ret;
  252 }
  253 
  254 int
  255 mdc_inode_ctx_set(xlator_t *this, inode_t *inode, struct md_cache *mdc)
  256 {
  257     int ret;
  258 
  259     LOCK(&inode->lock);
  260     {
  261         ret = __mdc_inode_ctx_set(this, inode, mdc);
  262     }
  263     UNLOCK(&inode->lock);
  264 
  265     return ret;
  266 }
  267 
  268 mdc_local_t *
  269 mdc_local_get(call_frame_t *frame, inode_t *inode)
  270 {
  271     mdc_local_t *local = NULL;
  272 
  273     local = frame->local;
  274     if (local)
  275         goto out;
  276 
  277     local = GF_CALLOC(sizeof(*local), 1, gf_mdc_mt_mdc_local_t);
  278     if (!local)
  279         goto out;
  280 
  281     local->incident_time = mdc_get_generation(frame->this, inode);
  282     frame->local = local;
  283 out:
  284     return local;
  285 }
  286 
  287 void
  288 mdc_local_wipe(xlator_t *this, mdc_local_t *local)
  289 {
  290     if (!local)
  291         return;
  292 
  293     loc_wipe(&local->loc);
  294 
  295     loc_wipe(&local->loc2);
  296 
  297     if (local->fd)
  298         fd_unref(local->fd);
  299 
  300     GF_FREE(local->linkname);
  301 
  302     GF_FREE(local->key);
  303 
  304     if (local->xattr)
  305         dict_unref(local->xattr);
  306 
  307     GF_FREE(local);
  308     return;
  309 }
  310 
  311 int
  312 mdc_inode_wipe(xlator_t *this, inode_t *inode)
  313 {
  314     int ret = 0;
  315     uint64_t mdc_int = 0;
  316     struct md_cache *mdc = NULL;
  317 
  318     ret = inode_ctx_del(inode, this, &mdc_int);
  319     if (ret != 0)
  320         goto out;
  321 
  322     mdc = (void *)(long)mdc_int;
  323 
  324     if (mdc->xattr)
  325         dict_unref(mdc->xattr);
  326 
  327     GF_FREE(mdc->linkname);
  328 
  329     GF_FREE(mdc);
  330 
  331     ret = 0;
  332 out:
  333     return ret;
  334 }
  335 
  336 struct md_cache *
  337 mdc_inode_prep(xlator_t *this, inode_t *inode)
  338 {
  339     int ret = 0;
  340     struct md_cache *mdc = NULL;
  341 
  342     LOCK(&inode->lock);
  343     {
  344         ret = __mdc_inode_ctx_get(this, inode, &mdc);
  345         if (ret == 0)
  346             goto unlock;
  347 
  348         mdc = GF_CALLOC(sizeof(*mdc), 1, gf_mdc_mt_md_cache_t);
  349         if (!mdc) {
  350             gf_msg(this->name, GF_LOG_ERROR, ENOMEM, MD_CACHE_MSG_NO_MEMORY,
  351                    "out of memory");
  352             goto unlock;
  353         }
  354 
  355         LOCK_INIT(&mdc->lock);
  356 
  357         ret = __mdc_inode_ctx_set(this, inode, mdc);
  358         if (ret) {
  359             gf_msg(this->name, GF_LOG_ERROR, ENOMEM, MD_CACHE_MSG_NO_MEMORY,
  360                    "out of memory");
  361             GF_FREE(mdc);
  362             mdc = NULL;
  363         }
  364     }
  365 unlock:
  366     UNLOCK(&inode->lock);
  367 
  368     return mdc;
  369 }
  370 
  371 /* Cache is valid if:
  372  * - It is not cached before any brick was down. Brick down case is handled by
  373  *   invalidating all the cache when any brick went down.
  374  * - The cache time is not expired
  375  */
  376 static gf_boolean_t
  377 __is_cache_valid(xlator_t *this, time_t mdc_time)
  378 {
  379     time_t now = 0;
  380     gf_boolean_t ret = _gf_true;
  381     struct mdc_conf *conf = NULL;
  382     int timeout = 0;
  383     time_t last_child_down = 0;
  384 
  385     conf = this->private;
  386 
  387     /* conf->lock here is not taken deliberately, so that the multi
  388      * threaded IO doesn't contend on a global lock. While updating
  389      * the variable, the lock is taken, so that at least the writes are
  390      * intact. The read of last_child_down may return junk, but that
  391      * is for a very short period of time.
  392      */
  393     last_child_down = conf->last_child_down;
  394     timeout = conf->timeout;
  395 
  396     time(&now);
  397 
  398     if ((mdc_time == 0) ||
  399         ((last_child_down != 0) && (mdc_time < last_child_down))) {
  400         ret = _gf_false;
  401         goto out;
  402     }
  403 
  404     if (now >= (mdc_time + timeout)) {
  405         ret = _gf_false;
  406     }
  407 
  408 out:
  409     return ret;
  410 }
  411 
  412 static gf_boolean_t
  413 is_md_cache_iatt_valid(xlator_t *this, struct md_cache *mdc)
  414 {
  415     gf_boolean_t ret = _gf_true;
  416 
  417     LOCK(&mdc->lock);
  418     {
  419         if (mdc->valid == _gf_false) {
  420             ret = mdc->valid;
  421         } else {
  422             ret = __is_cache_valid(this, mdc->ia_time);
  423             if (ret == _gf_false) {
  424                 mdc->ia_time = 0;
  425                 mdc->generation = 0;
  426             }
  427         }
  428     }
  429     UNLOCK(&mdc->lock);
  430 
  431     return ret;
  432 }
  433 
  434 static gf_boolean_t
  435 is_md_cache_xatt_valid(xlator_t *this, struct md_cache *mdc)
  436 {
  437     gf_boolean_t ret = _gf_true;
  438 
  439     LOCK(&mdc->lock);
  440     {
  441         ret = __is_cache_valid(this, mdc->xa_time);
  442         if (ret == _gf_false)
  443             mdc->xa_time = 0;
  444     }
  445     UNLOCK(&mdc->lock);
  446 
  447     return ret;
  448 }
  449 
  450 void
  451 mdc_from_iatt(struct md_cache *mdc, struct iatt *iatt)
  452 {
  453     mdc->md_prot = iatt->ia_prot;
  454     mdc->md_nlink = iatt->ia_nlink;
  455     mdc->md_uid = iatt->ia_uid;
  456     mdc->md_gid = iatt->ia_gid;
  457     mdc->md_atime = iatt->ia_atime;
  458     mdc->md_atime_nsec = iatt->ia_atime_nsec;
  459     mdc->md_mtime = iatt->ia_mtime;
  460     mdc->md_mtime_nsec = iatt->ia_mtime_nsec;
  461     mdc->md_ctime = iatt->ia_ctime;
  462     mdc->md_ctime_nsec = iatt->ia_ctime_nsec;
  463     mdc->md_rdev = iatt->ia_rdev;
  464     mdc->md_size = iatt->ia_size;
  465     mdc->md_blocks = iatt->ia_blocks;
  466 }
  467 
  468 void
  469 mdc_to_iatt(struct md_cache *mdc, struct iatt *iatt)
  470 {
  471     iatt->ia_prot = mdc->md_prot;
  472     iatt->ia_nlink = mdc->md_nlink;
  473     iatt->ia_uid = mdc->md_uid;
  474     iatt->ia_gid = mdc->md_gid;
  475     iatt->ia_atime = mdc->md_atime;
  476     iatt->ia_atime_nsec = mdc->md_atime_nsec;
  477     iatt->ia_mtime = mdc->md_mtime;
  478     iatt->ia_mtime_nsec = mdc->md_mtime_nsec;
  479     iatt->ia_ctime = mdc->md_ctime;
  480     iatt->ia_ctime_nsec = mdc->md_ctime_nsec;
  481     iatt->ia_rdev = mdc->md_rdev;
  482     iatt->ia_size = mdc->md_size;
  483     iatt->ia_blocks = mdc->md_blocks;
  484 }
  485 
  486 int
  487 mdc_inode_iatt_set_validate(xlator_t *this, inode_t *inode, struct iatt *prebuf,
  488                             struct iatt *iatt, gf_boolean_t update_time,
  489                             uint64_t incident_time)
  490 {
  491     int ret = 0;
  492     struct md_cache *mdc = NULL;
  493     uint32_t rollover = 0;
  494     uint64_t gen = 0;
  495     gf_boolean_t update_xa_time = _gf_false;
  496     struct mdc_conf *conf = this->private;
  497 
  498     mdc = mdc_inode_prep(this, inode);
  499     if (!mdc) {
  500         ret = -1;
  501         goto out;
  502     }
  503 
  504     rollover = incident_time >> 32;
  505     incident_time = (incident_time & 0xffffffff);
  506 
  507     LOCK(&mdc->lock);
  508     {
  509         if (!iatt || !iatt->ia_ctime) {
  510             gf_msg_callingfn("md-cache", GF_LOG_TRACE, 0, 0,
  511                              "invalidating iatt(NULL)"
  512                              "(%s)",
  513                              uuid_utoa(inode->gfid));
  514             mdc->ia_time = 0;
  515             mdc->valid = 0;
  516 
  517             gen = __mdc_inc_generation(this, mdc);
  518             mdc->generation = (gen & 0xffffffff);
  519             goto unlock;
  520         }
  521 
  522         /* There could be a race in invalidation, where the
  523          * invalidations in order A, B reaches md-cache in the order
  524          * B, A. Hence, make sure the invalidation A is discarded if
  525          * it comes after B. ctime of a file is always in ascending
  526          * order unlike atime and mtime(which can be changed by user
  527          * to any date), also ctime gets updates when atime/mtime
  528          * changes, hence check for ctime only.
  529          */
  530         if (mdc->md_ctime > iatt->ia_ctime) {
  531             gf_msg_callingfn(this->name, GF_LOG_DEBUG, EINVAL,
  532                              MD_CACHE_MSG_DISCARD_UPDATE,
  533                              "discarding the iatt validate "
  534                              "request (%s)",
  535                              uuid_utoa(inode->gfid));
  536             ret = -1;
  537             goto unlock;
  538         }
  539         if ((mdc->md_ctime == iatt->ia_ctime) &&
  540             (mdc->md_ctime_nsec > iatt->ia_ctime_nsec)) {
  541             gf_msg_callingfn(this->name, GF_LOG_DEBUG, EINVAL,
  542                              MD_CACHE_MSG_DISCARD_UPDATE,
  543                              "discarding the iatt validate "
  544                              "request(ctime_nsec) (%s)",
  545                              uuid_utoa(inode->gfid));
  546             ret = -1;
  547             goto unlock;
  548         }
  549 
  550         /*
  551          * Invalidate the inode if the mtime or ctime has changed
  552          * and the prebuf doesn't match the value we have cached.
  553          * TODO: writev returns with a NULL iatt due to
  554          * performance/write-behind, causing invalidation on writes.
  555          */
  556         if ((iatt->ia_mtime != mdc->md_mtime) ||
  557             (iatt->ia_mtime_nsec != mdc->md_mtime_nsec) ||
  558             (iatt->ia_ctime != mdc->md_ctime) ||
  559             (iatt->ia_ctime_nsec != mdc->md_ctime_nsec)) {
  560             if (conf->global_invalidation &&
  561                 (!prebuf || (prebuf->ia_mtime != mdc->md_mtime) ||
  562                  (prebuf->ia_mtime_nsec != mdc->md_mtime_nsec) ||
  563                  (prebuf->ia_ctime != mdc->md_ctime) ||
  564                  (prebuf->ia_ctime_nsec != mdc->md_ctime_nsec))) {
  565                 if (IA_ISREG(inode->ia_type)) {
  566                     gf_msg("md-cache", GF_LOG_TRACE, 0,
  567                            MD_CACHE_MSG_DISCARD_UPDATE,
  568                            "prebuf doesn't match the value we have cached,"
  569                            " invalidate the inode(%s)",
  570                            uuid_utoa(inode->gfid));
  571 
  572                     inode_invalidate(inode);
  573                 }
  574             } else {
  575                 update_xa_time = _gf_true;
  576             }
  577         }
  578 
  579         if ((mdc->gen_rollover == rollover) &&
  580             (incident_time >= mdc->generation)) {
  581             mdc_from_iatt(mdc, iatt);
  582             mdc->valid = _gf_true;
  583             if (update_time) {
  584                 time(&mdc->ia_time);
  585 
  586                 if (mdc->xa_time && update_xa_time)
  587                     time(&mdc->xa_time);
  588             }
  589 
  590             gf_msg_callingfn(
  591                 "md-cache", GF_LOG_TRACE, 0, MD_CACHE_MSG_CACHE_UPDATE,
  592                 "Updated iatt(%s)"
  593                 " time:%lld generation=%lld",
  594                 uuid_utoa(iatt->ia_gfid), (unsigned long long)mdc->ia_time,
  595                 (unsigned long long)mdc->generation);
  596         } else {
  597             gf_msg_callingfn("md-cache", GF_LOG_TRACE, 0, 0,
  598                              "not updating cache (%s)"
  599                              "mdc-rollover=%u rollover=%u "
  600                              "mdc-generation=%llu "
  601                              "mdc-ia_time=%llu incident_time=%llu ",
  602                              uuid_utoa(iatt->ia_gfid), mdc->gen_rollover,
  603                              rollover, (unsigned long long)mdc->generation,
  604                              (unsigned long long)mdc->ia_time,
  605                              (unsigned long long)incident_time);
  606         }
  607     }
  608 unlock:
  609     UNLOCK(&mdc->lock);
  610 
  611 out:
  612     return ret;
  613 }
  614 
  615 int
  616 mdc_inode_iatt_set(xlator_t *this, inode_t *inode, struct iatt *iatt,
  617                    uint64_t incident_time)
  618 {
  619     return mdc_inode_iatt_set_validate(this, inode, NULL, iatt, _gf_true,
  620                                        incident_time);
  621 }
  622 
  623 int
  624 mdc_inode_iatt_get(xlator_t *this, inode_t *inode, struct iatt *iatt)
  625 {
  626     int ret = -1;
  627     struct md_cache *mdc = NULL;
  628 
  629     if (mdc_inode_ctx_get(this, inode, &mdc) != 0) {
  630         gf_msg_trace("md-cache", 0, "mdc_inode_ctx_get failed (%s)",
  631                      uuid_utoa(inode->gfid));
  632         goto out;
  633     }
  634 
  635     if (!is_md_cache_iatt_valid(this, mdc)) {
  636         gf_msg_trace("md-cache", 0, "iatt cache not valid for (%s)",
  637                      uuid_utoa(inode->gfid));
  638         goto out;
  639     }
  640 
  641     LOCK(&mdc->lock);
  642     {
  643         mdc_to_iatt(mdc, iatt);
  644     }
  645     UNLOCK(&mdc->lock);
  646 
  647     gf_uuid_copy(iatt->ia_gfid, inode->gfid);
  648     iatt->ia_ino = gfid_to_ino(inode->gfid);
  649     iatt->ia_dev = 42;
  650     iatt->ia_type = inode->ia_type;
  651 
  652     ret = 0;
  653 out:
  654     return ret;
  655 }
  656 
  657 struct updatedict {
  658     dict_t *dict;
  659     int ret;
  660 };
  661 
  662 static int
  663 is_mdc_key_satisfied(xlator_t *this, const char *key)
  664 {
  665     int ret = 0;
  666     char *pattern = NULL;
  667     struct mdc_conf *conf = this->private;
  668     char *mdc_xattr_str = NULL;
  669     char *tmp = NULL;
  670     char *tmp1 = NULL;
  671 
  672     if (!key)
  673         goto out;
  674 
  675     /* conf->mdc_xattr_str, is never freed and is hence safely used outside
  676      * of lock*/
  677     tmp1 = conf->mdc_xattr_str;
  678     if (!tmp1)
  679         goto out;
  680 
  681     mdc_xattr_str = gf_strdup(tmp1);
  682     if (!mdc_xattr_str)
  683         goto out;
  684 
  685     pattern = strtok_r(mdc_xattr_str, ",", &tmp);
  686     while (pattern) {
  687         gf_strTrim(&pattern);
  688         if (fnmatch(pattern, key, 0) == 0) {
  689             ret = 1;
  690             break;
  691         } else {
  692             gf_msg_trace("md-cache", 0,
  693                          "xattr key %s doesn't satisfy "
  694                          "caching requirements",
  695                          key);
  696         }
  697         pattern = strtok_r(NULL, ",", &tmp);
  698     }
  699     GF_FREE(mdc_xattr_str);
  700 out:
  701     return ret;
  702 }
  703 
  704 static int
  705 updatefn(dict_t *dict, char *key, data_t *value, void *data)
  706 {
  707     struct updatedict *u = data;
  708 
  709     if (is_mdc_key_satisfied(THIS, key)) {
  710         if (!u->dict) {
  711             u->dict = dict_new();
  712             if (!u->dict) {
  713                 u->ret = -1;
  714                 return -1;
  715             }
  716         }
  717 
  718         if (dict_set(u->dict, key, value) < 0) {
  719             u->ret = -1;
  720             return -1;
  721         }
  722     }
  723     return 0;
  724 }
  725 
  726 static int
  727 mdc_dict_update(dict_t **tgt, dict_t *src)
  728 {
  729     struct updatedict u = {
  730         .dict = *tgt,
  731         .ret = 0,
  732     };
  733 
  734     dict_foreach(src, updatefn, &u);
  735 
  736     if (*tgt)
  737         return u.ret;
  738 
  739     if ((u.ret < 0) && u.dict) {
  740         dict_unref(u.dict);
  741         return u.ret;
  742     }
  743 
  744     *tgt = u.dict;
  745 
  746     return u.ret;
  747 }
  748 
  749 int
  750 mdc_inode_xatt_set(xlator_t *this, inode_t *inode, dict_t *dict)
  751 {
  752     int ret = -1;
  753     struct md_cache *mdc = NULL;
  754     dict_t *newdict = NULL;
  755 
  756     mdc = mdc_inode_prep(this, inode);
  757     if (!mdc)
  758         goto out;
  759 
  760     if (!dict) {
  761         gf_msg_trace("md-cache", 0,
  762                      "mdc_inode_xatt_set failed (%s) "
  763                      "dict NULL",
  764                      uuid_utoa(inode->gfid));
  765         goto out;
  766     }
  767 
  768     LOCK(&mdc->lock);
  769     {
  770         if (mdc->xattr) {
  771             gf_msg_trace("md-cache", 0,
  772                          "deleting the old xattr "
  773                          "cache (%s)",
  774                          uuid_utoa(inode->gfid));
  775             dict_unref(mdc->xattr);
  776             mdc->xattr = NULL;
  777         }
  778 
  779         ret = mdc_dict_update(&newdict, dict);
  780         if (ret < 0) {
  781             UNLOCK(&mdc->lock);
  782             goto out;
  783         }
  784 
  785         if (newdict)
  786             mdc->xattr = newdict;
  787 
  788         time(&mdc->xa_time);
  789         gf_msg_trace("md-cache", 0, "xatt cache set for (%s) time:%lld",
  790                      uuid_utoa(inode->gfid), (long long)mdc->xa_time);
  791     }
  792     UNLOCK(&mdc->lock);
  793     ret = 0;
  794 out:
  795     return ret;
  796 }
  797 
  798 int
  799 mdc_inode_xatt_update(xlator_t *this, inode_t *inode, dict_t *dict)
  800 {
  801     int ret = -1;
  802     struct md_cache *mdc = NULL;
  803 
  804     mdc = mdc_inode_prep(this, inode);
  805     if (!mdc)
  806         goto out;
  807 
  808     if (!dict)
  809         goto out;
  810 
  811     LOCK(&mdc->lock);
  812     {
  813         ret = mdc_dict_update(&mdc->xattr, dict);
  814         if (ret < 0) {
  815             UNLOCK(&mdc->lock);
  816             goto out;
  817         }
  818     }
  819     UNLOCK(&mdc->lock);
  820 
  821     ret = 0;
  822 out:
  823     return ret;
  824 }
  825 
  826 int
  827 mdc_inode_xatt_unset(xlator_t *this, inode_t *inode, char *name)
  828 {
  829     int ret = -1;
  830     struct md_cache *mdc = NULL;
  831 
  832     mdc = mdc_inode_prep(this, inode);
  833     if (!mdc)
  834         goto out;
  835 
  836     if (!name || !mdc->xattr)
  837         goto out;
  838 
  839     LOCK(&mdc->lock);
  840     {
  841         dict_del(mdc->xattr, name);
  842     }
  843     UNLOCK(&mdc->lock);
  844 
  845     ret = 0;
  846 out:
  847     return ret;
  848 }
  849 
  850 int
  851 mdc_inode_xatt_get(xlator_t *this, inode_t *inode, dict_t **dict)
  852 {
  853     int ret = -1;
  854     struct md_cache *mdc = NULL;
  855 
  856     if (mdc_inode_ctx_get(this, inode, &mdc) != 0) {
  857         gf_msg_trace("md-cache", 0, "mdc_inode_ctx_get failed (%s)",
  858                      uuid_utoa(inode->gfid));
  859         goto out;
  860     }
  861 
  862     if (!is_md_cache_xatt_valid(this, mdc)) {
  863         gf_msg_trace("md-cache", 0, "xattr cache not valid for (%s)",
  864                      uuid_utoa(inode->gfid));
  865         goto out;
  866     }
  867 
  868     LOCK(&mdc->lock);
  869     {
  870         ret = 0;
  871         /* Missing xattr only means no keys were there, i.e
  872            a negative cache for the "loaded" keys
  873         */
  874         if (!mdc->xattr) {
  875             gf_msg_trace("md-cache", 0, "xattr not present (%s)",
  876                          uuid_utoa(inode->gfid));
  877             goto unlock;
  878         }
  879 
  880         if (dict)
  881             *dict = dict_ref(mdc->xattr);
  882     }
  883 unlock:
  884     UNLOCK(&mdc->lock);
  885 
  886 out:
  887     return ret;
  888 }
  889 
  890 gf_boolean_t
  891 mdc_inode_reset_need_lookup(xlator_t *this, inode_t *inode)
  892 {
  893     struct md_cache *mdc = NULL;
  894     gf_boolean_t need = _gf_false;
  895 
  896     if (mdc_inode_ctx_get(this, inode, &mdc) != 0)
  897         goto out;
  898 
  899     LOCK(&mdc->lock);
  900     {
  901         need = mdc->need_lookup;
  902         mdc->need_lookup = _gf_false;
  903     }
  904     UNLOCK(&mdc->lock);
  905 
  906 out:
  907     return need;
  908 }
  909 
  910 void
  911 mdc_inode_set_need_lookup(xlator_t *this, inode_t *inode, gf_boolean_t need)
  912 {
  913     struct md_cache *mdc = NULL;
  914 
  915     if (mdc_inode_ctx_get(this, inode, &mdc) != 0)
  916         goto out;
  917 
  918     LOCK(&mdc->lock);
  919     {
  920         mdc->need_lookup = need;
  921     }
  922     UNLOCK(&mdc->lock);
  923 
  924 out:
  925     return;
  926 }
  927 
  928 void
  929 mdc_inode_iatt_invalidate(xlator_t *this, inode_t *inode)
  930 {
  931     struct md_cache *mdc = NULL;
  932     uint32_t gen = 0;
  933 
  934     if (mdc_inode_ctx_get(this, inode, &mdc) != 0)
  935         goto out;
  936 
  937     gen = mdc_inc_generation(this, inode) & 0xffffffff;
  938 
  939     LOCK(&mdc->lock);
  940     {
  941         mdc->ia_time = 0;
  942         mdc->valid = _gf_false;
  943         mdc->generation = gen;
  944     }
  945     UNLOCK(&mdc->lock);
  946 
  947 out:
  948     return;
  949 }
  950 
  951 int
  952 mdc_inode_xatt_invalidate(xlator_t *this, inode_t *inode)
  953 {
  954     int ret = -1;
  955     struct md_cache *mdc = NULL;
  956 
  957     if (mdc_inode_ctx_get(this, inode, &mdc) != 0)
  958         goto out;
  959 
  960     LOCK(&mdc->lock);
  961     {
  962         mdc->xa_time = 0;
  963     }
  964     UNLOCK(&mdc->lock);
  965 
  966 out:
  967     return ret;
  968 }
  969 
  970 static int
  971 mdc_update_gfid_stat(xlator_t *this, struct iatt *iatt)
  972 {
  973     int ret = 0;
  974     inode_table_t *itable = NULL;
  975     inode_t *inode = NULL;
  976 
  977     itable = ((xlator_t *)this->graph->top)->itable;
  978     inode = inode_find(itable, iatt->ia_gfid);
  979     if (!inode) {
  980         ret = -1;
  981         goto out;
  982     }
  983     ret = mdc_inode_iatt_set_validate(this, inode, NULL, iatt, _gf_true,
  984                                       mdc_inc_generation(this, inode));
  985 out:
  986     return ret;
  987 }
  988 
  989 static bool
  990 mdc_load_reqs(xlator_t *this, dict_t *dict)
  991 {
  992     struct mdc_conf *conf = this->private;
  993     char *pattern = NULL;
  994     char *mdc_xattr_str = NULL;
  995     char *tmp = NULL;
  996     char *tmp1 = NULL;
  997     int ret = 0;
  998     bool loaded = false;
  999 
 1000     tmp1 = conf->mdc_xattr_str;
 1001     if (!tmp1)
 1002         goto out;
 1003 
 1004     mdc_xattr_str = gf_strdup(tmp1);
 1005     if (!mdc_xattr_str)
 1006         goto out;
 1007 
 1008     pattern = strtok_r(mdc_xattr_str, ",", &tmp);
 1009     while (pattern) {
 1010         gf_strTrim(&pattern);
 1011         ret = dict_set_int8(dict, pattern, 0);
 1012         if (ret) {
 1013             conf->mdc_xattr_str = NULL;
 1014             gf_msg("md-cache", GF_LOG_ERROR, 0, MD_CACHE_MSG_NO_XATTR_CACHE,
 1015                    "Disabled cache for xattrs, dict_set failed");
 1016             goto out;
 1017         }
 1018         pattern = strtok_r(NULL, ",", &tmp);
 1019     }
 1020 
 1021     loaded = true;
 1022 
 1023 out:
 1024     GF_FREE(mdc_xattr_str);
 1025 
 1026     return loaded;
 1027 }
 1028 
 1029 struct checkpair {
 1030     int ret;
 1031     dict_t *rsp;
 1032 };
 1033 
 1034 static int
 1035 checkfn(dict_t *this, char *key, data_t *value, void *data)
 1036 {
 1037     struct checkpair *pair = data;
 1038 
 1039     if (!is_mdc_key_satisfied(THIS, key))
 1040         pair->ret = 0;
 1041 
 1042     return 0;
 1043 }
 1044 
 1045 int
 1046 mdc_xattr_satisfied(xlator_t *this, dict_t *req, dict_t *rsp)
 1047 {
 1048     struct checkpair pair = {
 1049         .ret = 1,
 1050         .rsp = rsp,
 1051     };
 1052 
 1053     dict_foreach(req, checkfn, &pair);
 1054 
 1055     return pair.ret;
 1056 }
 1057 
 1058 static void
 1059 mdc_cache_statfs(xlator_t *this, struct statvfs *buf)
 1060 {
 1061     struct mdc_conf *conf = this->private;
 1062 
 1063     pthread_mutex_lock(&conf->statfs_cache.lock);
 1064     {
 1065         memcpy(&conf->statfs_cache.buf, buf, sizeof(struct statvfs));
 1066         clock_gettime(CLOCK_MONOTONIC, &conf->statfs_cache.last_refreshed);
 1067         conf->statfs_cache.initialized = _gf_true;
 1068     }
 1069     pthread_mutex_unlock(&conf->statfs_cache.lock);
 1070 }
 1071 
 1072 int
 1073 mdc_load_statfs_info_from_cache(xlator_t *this, struct statvfs **buf)
 1074 {
 1075     struct mdc_conf *conf = this->private;
 1076     struct timespec now;
 1077     double cache_age = 0.0;
 1078     int ret = 0;
 1079 
 1080     if (!buf || !conf) {
 1081         ret = -1;
 1082         goto err;
 1083     }
 1084 
 1085     *buf = NULL;
 1086     timespec_now(&now);
 1087 
 1088     pthread_mutex_lock(&conf->statfs_cache.lock);
 1089     {
 1090         /* Skip if the cache is not initialized */
 1091         if (!conf->statfs_cache.initialized) {
 1092             ret = -1;
 1093             goto unlock;
 1094         }
 1095 
 1096         cache_age = (now.tv_sec - conf->statfs_cache.last_refreshed.tv_sec);
 1097 
 1098         gf_log(this->name, GF_LOG_DEBUG, "STATFS cache age = %lf", cache_age);
 1099         if (cache_age > conf->timeout) {
 1100             /* Expire the cache */
 1101             gf_log(this->name, GF_LOG_DEBUG,
 1102                    "Cache age %lf exceeded timeout %d", cache_age,
 1103                    conf->timeout);
 1104             ret = -1;
 1105             goto unlock;
 1106         }
 1107 
 1108         *buf = &conf->statfs_cache.buf;
 1109     }
 1110 unlock:
 1111     pthread_mutex_unlock(&conf->statfs_cache.lock);
 1112 err:
 1113     return ret;
 1114 }
 1115 
 1116 static dict_t *
 1117 mdc_prepare_request(xlator_t *this, mdc_local_t *local, dict_t *xdata)
 1118 {
 1119     if (xdata != NULL) {
 1120         dict_ref(xdata);
 1121     }
 1122 
 1123     if (local == NULL) {
 1124         return xdata;
 1125     }
 1126 
 1127     if (xdata == NULL) {
 1128         xdata = dict_new();
 1129         if (xdata == NULL) {
 1130             local->update_cache = false;
 1131 
 1132             return NULL;
 1133         }
 1134     }
 1135 
 1136     local->update_cache = mdc_load_reqs(this, xdata);
 1137 
 1138     return xdata;
 1139 }
 1140 
 1141 int
 1142 mdc_statfs_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 1143                int32_t op_ret, int32_t op_errno, struct statvfs *buf,
 1144                dict_t *xdata)
 1145 {
 1146     struct mdc_conf *conf = this->private;
 1147     mdc_local_t *local = NULL;
 1148 
 1149     local = frame->local;
 1150     if (!local)
 1151         goto out;
 1152 
 1153     if (op_ret != 0) {
 1154         if ((op_errno == ENOENT) || (op_errno == ESTALE)) {
 1155             mdc_inode_iatt_invalidate(this, local->loc.inode);
 1156         }
 1157 
 1158         goto out;
 1159     }
 1160 
 1161     if (conf && conf->cache_statfs) {
 1162         mdc_cache_statfs(this, buf);
 1163     }
 1164 
 1165 out:
 1166     MDC_STACK_UNWIND(statfs, frame, op_ret, op_errno, buf, xdata);
 1167 
 1168     return 0;
 1169 }
 1170 
 1171 int
 1172 mdc_statfs(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata)
 1173 {
 1174     int ret = 0, op_ret = 0, op_errno = 0;
 1175     struct statvfs *buf = NULL;
 1176     mdc_local_t *local = NULL;
 1177     struct mdc_conf *conf = this->private;
 1178 
 1179     local = mdc_local_get(frame, loc->inode);
 1180     if (!local) {
 1181         op_ret = -1;
 1182         op_errno = ENOMEM;
 1183         goto out;
 1184     }
 1185 
 1186     loc_copy(&local->loc, loc);
 1187 
 1188     if (!conf) {
 1189         goto uncached;
 1190     }
 1191 
 1192     if (!conf->cache_statfs) {
 1193         goto uncached;
 1194     }
 1195 
 1196     ret = mdc_load_statfs_info_from_cache(this, &buf);
 1197     if (ret == 0 && buf) {
 1198         op_ret = 0;
 1199         op_errno = 0;
 1200         goto out;
 1201     }
 1202 
 1203 uncached:
 1204     STACK_WIND(frame, mdc_statfs_cbk, FIRST_CHILD(this),
 1205                FIRST_CHILD(this)->fops->statfs, loc, xdata);
 1206     return 0;
 1207 
 1208 out:
 1209     MDC_STACK_UNWIND(statfs, frame, op_ret, op_errno, buf, xdata);
 1210     return 0;
 1211 }
 1212 
 1213 int
 1214 mdc_lookup_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 1215                int32_t op_ret, int32_t op_errno, inode_t *inode,
 1216                struct iatt *stbuf, dict_t *dict, struct iatt *postparent)
 1217 {
 1218     mdc_local_t *local = NULL;
 1219     struct mdc_conf *conf = this->private;
 1220 
 1221     local = frame->local;
 1222 
 1223     if (!local)
 1224         goto out;
 1225 
 1226     if (op_ret != 0) {
 1227         if (op_errno == ENOENT)
 1228             GF_ATOMIC_INC(conf->mdc_counter.negative_lookup);
 1229 
 1230         if (op_errno == ESTALE) {
 1231             /* if op_errno is ENOENT, fuse-bridge will unlink the
 1232              * dentry
 1233              */
 1234             if (local->loc.parent)
 1235                 mdc_inode_iatt_invalidate(this, local->loc.parent);
 1236             else
 1237                 mdc_inode_iatt_invalidate(this, local->loc.inode);
 1238         }
 1239 
 1240         goto out;
 1241     }
 1242 
 1243     if (local->loc.parent) {
 1244         mdc_inode_iatt_set(this, local->loc.parent, postparent,
 1245                            local->incident_time);
 1246     }
 1247 
 1248     if (local->loc.inode) {
 1249         mdc_inode_iatt_set(this, local->loc.inode, stbuf, local->incident_time);
 1250         if (local->update_cache) {
 1251             mdc_inode_xatt_set(this, local->loc.inode, dict);
 1252         }
 1253     }
 1254 out:
 1255     MDC_STACK_UNWIND(lookup, frame, op_ret, op_errno, inode, stbuf, dict,
 1256                      postparent);
 1257     return 0;
 1258 }
 1259 
 1260 int
 1261 mdc_lookup(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata)
 1262 {
 1263     int ret = 0;
 1264     struct iatt stbuf = {
 1265         0,
 1266     };
 1267     struct iatt postparent = {
 1268         0,
 1269     };
 1270     dict_t *xattr_rsp = NULL;
 1271     mdc_local_t *local = NULL;
 1272     struct mdc_conf *conf = this->private;
 1273 
 1274     local = mdc_local_get(frame, loc->inode);
 1275     if (!local) {
 1276         GF_ATOMIC_INC(conf->mdc_counter.stat_miss);
 1277         goto uncached;
 1278     }
 1279 
 1280     loc_copy(&local->loc, loc);
 1281 
 1282     if (!inode_is_linked(loc->inode)) {
 1283         GF_ATOMIC_INC(conf->mdc_counter.stat_miss);
 1284         goto uncached;
 1285     }
 1286 
 1287     if (mdc_inode_reset_need_lookup(this, loc->inode)) {
 1288         GF_ATOMIC_INC(conf->mdc_counter.need_lookup);
 1289         goto uncached;
 1290     }
 1291 
 1292     ret = mdc_inode_iatt_get(this, loc->inode, &stbuf);
 1293     if (ret != 0) {
 1294         GF_ATOMIC_INC(conf->mdc_counter.stat_miss);
 1295         goto uncached;
 1296     }
 1297 
 1298     if (xdata) {
 1299         ret = mdc_inode_xatt_get(this, loc->inode, &xattr_rsp);
 1300         if (ret != 0) {
 1301             GF_ATOMIC_INC(conf->mdc_counter.xattr_miss);
 1302             goto uncached;
 1303         }
 1304 
 1305         if (!mdc_xattr_satisfied(this, xdata, xattr_rsp)) {
 1306             GF_ATOMIC_INC(conf->mdc_counter.xattr_miss);
 1307             goto uncached;
 1308         }
 1309     }
 1310 
 1311     GF_ATOMIC_INC(conf->mdc_counter.stat_hit);
 1312     MDC_STACK_UNWIND(lookup, frame, 0, 0, loc->inode, &stbuf, xattr_rsp,
 1313                      &postparent);
 1314 
 1315     if (xattr_rsp)
 1316         dict_unref(xattr_rsp);
 1317 
 1318     return 0;
 1319 
 1320 uncached:
 1321     xdata = mdc_prepare_request(this, local, xdata);
 1322 
 1323     STACK_WIND(frame, mdc_lookup_cbk, FIRST_CHILD(this),
 1324                FIRST_CHILD(this)->fops->lookup, loc, xdata);
 1325 
 1326     if (xattr_rsp)
 1327         dict_unref(xattr_rsp);
 1328 
 1329     if (xdata != NULL) {
 1330         dict_unref(xdata);
 1331     }
 1332 
 1333     return 0;
 1334 }
 1335 
 1336 int
 1337 mdc_stat_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret,
 1338              int32_t op_errno, struct iatt *buf, dict_t *xdata)
 1339 {
 1340     mdc_local_t *local = NULL;
 1341 
 1342     local = frame->local;
 1343     if (!local)
 1344         goto out;
 1345 
 1346     if (op_ret != 0) {
 1347         if ((op_errno == ESTALE) || (op_errno == ENOENT)) {
 1348             mdc_inode_iatt_invalidate(this, local->loc.inode);
 1349         }
 1350 
 1351         goto out;
 1352     }
 1353 
 1354     mdc_inode_iatt_set(this, local->loc.inode, buf, local->incident_time);
 1355     if (local->update_cache) {
 1356         mdc_inode_xatt_set(this, local->loc.inode, xdata);
 1357     }
 1358 
 1359 out:
 1360     MDC_STACK_UNWIND(stat, frame, op_ret, op_errno, buf, xdata);
 1361 
 1362     return 0;
 1363 }
 1364 
 1365 int
 1366 mdc_stat(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata)
 1367 {
 1368     int ret;
 1369     struct iatt stbuf;
 1370     mdc_local_t *local = NULL;
 1371     struct mdc_conf *conf = this->private;
 1372 
 1373     local = mdc_local_get(frame, loc->inode);
 1374     if (!local)
 1375         goto uncached;
 1376 
 1377     loc_copy(&local->loc, loc);
 1378 
 1379     if (!inode_is_linked(loc->inode)) {
 1380         GF_ATOMIC_INC(conf->mdc_counter.stat_miss);
 1381         goto uncached;
 1382     }
 1383 
 1384     ret = mdc_inode_iatt_get(this, loc->inode, &stbuf);
 1385     if (ret != 0)
 1386         goto uncached;
 1387 
 1388     GF_ATOMIC_INC(conf->mdc_counter.stat_hit);
 1389     MDC_STACK_UNWIND(stat, frame, 0, 0, &stbuf, xdata);
 1390 
 1391     return 0;
 1392 
 1393 uncached:
 1394     xdata = mdc_prepare_request(this, local, xdata);
 1395 
 1396     GF_ATOMIC_INC(conf->mdc_counter.stat_miss);
 1397     STACK_WIND(frame, mdc_stat_cbk, FIRST_CHILD(this),
 1398                FIRST_CHILD(this)->fops->stat, loc, xdata);
 1399 
 1400     if (xdata != NULL) {
 1401         dict_unref(xdata);
 1402     }
 1403 
 1404     return 0;
 1405 }
 1406 
 1407 int
 1408 mdc_fstat_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret,
 1409               int32_t op_errno, struct iatt *buf, dict_t *xdata)
 1410 {
 1411     mdc_local_t *local = NULL;
 1412 
 1413     local = frame->local;
 1414     if (!local)
 1415         goto out;
 1416 
 1417     if (op_ret != 0) {
 1418         if ((op_errno == ENOENT) || (op_errno == ESTALE)) {
 1419             mdc_inode_iatt_invalidate(this, local->fd->inode);
 1420         }
 1421 
 1422         goto out;
 1423     }
 1424 
 1425     mdc_inode_iatt_set(this, local->fd->inode, buf, local->incident_time);
 1426     if (local->update_cache) {
 1427         mdc_inode_xatt_set(this, local->fd->inode, xdata);
 1428     }
 1429 
 1430 out:
 1431     MDC_STACK_UNWIND(fstat, frame, op_ret, op_errno, buf, xdata);
 1432 
 1433     return 0;
 1434 }
 1435 
 1436 int
 1437 mdc_fstat(call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *xdata)
 1438 {
 1439     int ret;
 1440     struct iatt stbuf;
 1441     mdc_local_t *local = NULL;
 1442     struct mdc_conf *conf = this->private;
 1443 
 1444     local = mdc_local_get(frame, fd->inode);
 1445     if (!local)
 1446         goto uncached;
 1447 
 1448     local->fd = __fd_ref(fd);
 1449 
 1450     ret = mdc_inode_iatt_get(this, fd->inode, &stbuf);
 1451     if (ret != 0)
 1452         goto uncached;
 1453 
 1454     GF_ATOMIC_INC(conf->mdc_counter.stat_hit);
 1455     MDC_STACK_UNWIND(fstat, frame, 0, 0, &stbuf, xdata);
 1456 
 1457     return 0;
 1458 
 1459 uncached:
 1460     xdata = mdc_prepare_request(this, local, xdata);
 1461 
 1462     GF_ATOMIC_INC(conf->mdc_counter.stat_miss);
 1463     STACK_WIND(frame, mdc_fstat_cbk, FIRST_CHILD(this),
 1464                FIRST_CHILD(this)->fops->fstat, fd, xdata);
 1465 
 1466     if (xdata != NULL) {
 1467         dict_unref(xdata);
 1468     }
 1469 
 1470     return 0;
 1471 }
 1472 
 1473 int
 1474 mdc_truncate_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 1475                  int32_t op_ret, int32_t op_errno, struct iatt *prebuf,
 1476                  struct iatt *postbuf, dict_t *xdata)
 1477 {
 1478     mdc_local_t *local = NULL;
 1479 
 1480     local = frame->local;
 1481 
 1482     if (!local)
 1483         goto out;
 1484 
 1485     if (op_ret != 0) {
 1486         if ((op_errno == ESTALE) || (op_errno == ENOENT))
 1487             mdc_inode_iatt_invalidate(this, local->loc.inode);
 1488 
 1489         goto out;
 1490     }
 1491 
 1492     mdc_inode_iatt_set_validate(this, local->loc.inode, prebuf, postbuf,
 1493                                 _gf_true, local->incident_time);
 1494 
 1495 out:
 1496     MDC_STACK_UNWIND(truncate, frame, op_ret, op_errno, prebuf, postbuf, xdata);
 1497 
 1498     return 0;
 1499 }
 1500 
 1501 int
 1502 mdc_truncate(call_frame_t *frame, xlator_t *this, loc_t *loc, off_t offset,
 1503              dict_t *xdata)
 1504 {
 1505     mdc_local_t *local = NULL;
 1506 
 1507     local = mdc_local_get(frame, loc->inode);
 1508     if (local != NULL) {
 1509         local->loc.inode = inode_ref(loc->inode);
 1510     }
 1511 
 1512     STACK_WIND(frame, mdc_truncate_cbk, FIRST_CHILD(this),
 1513                FIRST_CHILD(this)->fops->truncate, loc, offset, xdata);
 1514     return 0;
 1515 }
 1516 
 1517 int
 1518 mdc_ftruncate_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 1519                   int32_t op_ret, int32_t op_errno, struct iatt *prebuf,
 1520                   struct iatt *postbuf, dict_t *xdata)
 1521 {
 1522     mdc_local_t *local = NULL;
 1523 
 1524     local = frame->local;
 1525 
 1526     if (!local)
 1527         goto out;
 1528 
 1529     if (op_ret != 0) {
 1530         if ((op_errno == ENOENT) || (op_errno == ESTALE))
 1531             mdc_inode_iatt_invalidate(this, local->fd->inode);
 1532 
 1533         goto out;
 1534     }
 1535 
 1536     mdc_inode_iatt_set_validate(this, local->fd->inode, prebuf, postbuf,
 1537                                 _gf_true, local->incident_time);
 1538 
 1539 out:
 1540     MDC_STACK_UNWIND(ftruncate, frame, op_ret, op_errno, prebuf, postbuf,
 1541                      xdata);
 1542 
 1543     return 0;
 1544 }
 1545 
 1546 int
 1547 mdc_ftruncate(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset,
 1548               dict_t *xdata)
 1549 {
 1550     mdc_local_t *local = NULL;
 1551 
 1552     local = mdc_local_get(frame, fd->inode);
 1553     if (local != NULL) {
 1554         local->fd = __fd_ref(fd);
 1555     }
 1556 
 1557     STACK_WIND(frame, mdc_ftruncate_cbk, FIRST_CHILD(this),
 1558                FIRST_CHILD(this)->fops->ftruncate, fd, offset, xdata);
 1559     return 0;
 1560 }
 1561 
 1562 int
 1563 mdc_mknod_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret,
 1564               int32_t op_errno, inode_t *inode, struct iatt *buf,
 1565               struct iatt *preparent, struct iatt *postparent, dict_t *xdata)
 1566 {
 1567     mdc_local_t *local = NULL;
 1568 
 1569     local = frame->local;
 1570 
 1571     if (!local)
 1572         goto out;
 1573 
 1574     if (op_ret != 0) {
 1575         if ((op_errno == ESTALE) || (op_errno == ENOENT)) {
 1576             mdc_inode_iatt_invalidate(this, local->loc.parent);
 1577         }
 1578 
 1579         goto out;
 1580     }
 1581 
 1582     if (local->loc.parent) {
 1583         mdc_inode_iatt_set(this, local->loc.parent, postparent,
 1584                            local->incident_time);
 1585     }
 1586 
 1587     if (local->loc.inode) {
 1588         mdc_inode_iatt_set(this, local->loc.inode, buf, local->incident_time);
 1589     }
 1590 out:
 1591     MDC_STACK_UNWIND(mknod, frame, op_ret, op_errno, inode, buf, preparent,
 1592                      postparent, xdata);
 1593     return 0;
 1594 }
 1595 
 1596 int
 1597 mdc_mknod(call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode,
 1598           dev_t rdev, mode_t umask, dict_t *xdata)
 1599 {
 1600     mdc_local_t *local = NULL;
 1601 
 1602     local = mdc_local_get(frame, loc->inode);
 1603     if (local != NULL) {
 1604         loc_copy(&local->loc, loc);
 1605         local->xattr = dict_ref(xdata);
 1606     }
 1607 
 1608     STACK_WIND(frame, mdc_mknod_cbk, FIRST_CHILD(this),
 1609                FIRST_CHILD(this)->fops->mknod, loc, mode, rdev, umask, xdata);
 1610     return 0;
 1611 }
 1612 
 1613 int
 1614 mdc_mkdir_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret,
 1615               int32_t op_errno, inode_t *inode, struct iatt *buf,
 1616               struct iatt *preparent, struct iatt *postparent, dict_t *xdata)
 1617 {
 1618     mdc_local_t *local = NULL;
 1619 
 1620     local = frame->local;
 1621 
 1622     if (!local)
 1623         goto out;
 1624 
 1625     if (op_ret != 0) {
 1626         if ((op_errno == ESTALE) || (op_errno == ENOENT)) {
 1627             mdc_inode_iatt_invalidate(this, local->loc.parent);
 1628         }
 1629 
 1630         goto out;
 1631     }
 1632 
 1633     if (local->loc.parent) {
 1634         mdc_inode_iatt_set(this, local->loc.parent, postparent,
 1635                            local->incident_time);
 1636     }
 1637 
 1638     if (local->loc.inode) {
 1639         mdc_inode_iatt_set(this, local->loc.inode, buf, local->incident_time);
 1640     }
 1641 out:
 1642     MDC_STACK_UNWIND(mkdir, frame, op_ret, op_errno, inode, buf, preparent,
 1643                      postparent, xdata);
 1644     return 0;
 1645 }
 1646 
 1647 int
 1648 mdc_mkdir(call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode,
 1649           mode_t umask, dict_t *xdata)
 1650 {
 1651     mdc_local_t *local = NULL;
 1652 
 1653     local = mdc_local_get(frame, loc->inode);
 1654     if (local != NULL) {
 1655         loc_copy(&local->loc, loc);
 1656         local->xattr = dict_ref(xdata);
 1657     }
 1658 
 1659     STACK_WIND(frame, mdc_mkdir_cbk, FIRST_CHILD(this),
 1660                FIRST_CHILD(this)->fops->mkdir, loc, mode, umask, xdata);
 1661     return 0;
 1662 }
 1663 
 1664 int
 1665 mdc_unlink_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 1666                int32_t op_ret, int32_t op_errno, struct iatt *preparent,
 1667                struct iatt *postparent, dict_t *xdata)
 1668 {
 1669     mdc_local_t *local = NULL;
 1670 
 1671     local = frame->local;
 1672 
 1673     if (!local)
 1674         goto out;
 1675 
 1676     if (op_ret != 0) {
 1677         /* if errno is ESTALE, parent is not present, which implies even
 1678          * child is not present. Also, man 2 unlink states unlink can
 1679          * return ENOENT if a component in pathname does not
 1680          * exist or is a dangling symbolic link. So, invalidate both
 1681          * parent and child for both errno
 1682          */
 1683 
 1684         if ((op_errno == ENOENT) || (op_errno == ESTALE)) {
 1685             mdc_inode_iatt_invalidate(this, local->loc.inode);
 1686             mdc_inode_iatt_invalidate(this, local->loc.parent);
 1687         }
 1688 
 1689         goto out;
 1690     }
 1691 
 1692     if (local->loc.parent) {
 1693         mdc_inode_iatt_set(this, local->loc.parent, postparent,
 1694                            local->incident_time);
 1695     }
 1696 
 1697     if (local->loc.inode) {
 1698         mdc_inode_iatt_set(this, local->loc.inode, NULL, local->incident_time);
 1699     }
 1700 
 1701 out:
 1702     MDC_STACK_UNWIND(unlink, frame, op_ret, op_errno, preparent, postparent,
 1703                      xdata);
 1704     return 0;
 1705 }
 1706 
 1707 int
 1708 mdc_unlink(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t xflag,
 1709            dict_t *xdata)
 1710 {
 1711     mdc_local_t *local = NULL;
 1712 
 1713     local = mdc_local_get(frame, loc->inode);
 1714     if (local != NULL) {
 1715         loc_copy(&local->loc, loc);
 1716     }
 1717 
 1718     STACK_WIND(frame, mdc_unlink_cbk, FIRST_CHILD(this),
 1719                FIRST_CHILD(this)->fops->unlink, loc, xflag, xdata);
 1720     return 0;
 1721 }
 1722 
 1723 int
 1724 mdc_rmdir_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret,
 1725               int32_t op_errno, struct iatt *preparent, struct iatt *postparent,
 1726               dict_t *xdata)
 1727 {
 1728     mdc_local_t *local = NULL;
 1729 
 1730     local = frame->local;
 1731 
 1732     if (!local)
 1733         goto out;
 1734 
 1735     if (op_ret != 0) {
 1736         /* if errno is ESTALE, parent is not present, which implies even
 1737          * child is not present. Also, man 2 rmdir states rmdir can
 1738          * return ENOENT if a directory component in pathname does not
 1739          * exist or is a dangling symbolic link. So, invalidate both
 1740          * parent and child for both errno
 1741          */
 1742 
 1743         if ((op_errno == ESTALE) || (op_errno == ENOENT)) {
 1744             mdc_inode_iatt_invalidate(this, local->loc.inode);
 1745             mdc_inode_iatt_invalidate(this, local->loc.parent);
 1746         }
 1747 
 1748         goto out;
 1749     }
 1750 
 1751     if (local->loc.parent) {
 1752         mdc_inode_iatt_set(this, local->loc.parent, postparent,
 1753                            local->incident_time);
 1754     }
 1755 
 1756 out:
 1757     MDC_STACK_UNWIND(rmdir, frame, op_ret, op_errno, preparent, postparent,
 1758                      xdata);
 1759     return 0;
 1760 }
 1761 
 1762 int
 1763 mdc_rmdir(call_frame_t *frame, xlator_t *this, loc_t *loc, int flag,
 1764           dict_t *xdata)
 1765 {
 1766     mdc_local_t *local = NULL;
 1767 
 1768     local = mdc_local_get(frame, loc->inode);
 1769     if (local != NULL) {
 1770         loc_copy(&local->loc, loc);
 1771     }
 1772 
 1773     STACK_WIND(frame, mdc_rmdir_cbk, FIRST_CHILD(this),
 1774                FIRST_CHILD(this)->fops->rmdir, loc, flag, xdata);
 1775     return 0;
 1776 }
 1777 
 1778 int
 1779 mdc_symlink_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 1780                 int32_t op_ret, int32_t op_errno, inode_t *inode,
 1781                 struct iatt *buf, struct iatt *preparent,
 1782                 struct iatt *postparent, dict_t *xdata)
 1783 {
 1784     mdc_local_t *local = NULL;
 1785 
 1786     local = frame->local;
 1787 
 1788     if (!local)
 1789         goto out;
 1790 
 1791     if (op_ret != 0) {
 1792         if ((op_errno == ESTALE) || (op_errno == ENOENT)) {
 1793             mdc_inode_iatt_invalidate(this, local->loc.parent);
 1794         }
 1795 
 1796         goto out;
 1797     }
 1798 
 1799     if (local->loc.parent) {
 1800         mdc_inode_iatt_set(this, local->loc.parent, postparent,
 1801                            local->incident_time);
 1802     }
 1803 
 1804     if (local->loc.inode) {
 1805         mdc_inode_iatt_set(this, local->loc.inode, buf, local->incident_time);
 1806     }
 1807 out:
 1808     MDC_STACK_UNWIND(symlink, frame, op_ret, op_errno, inode, buf, preparent,
 1809                      postparent, xdata);
 1810     return 0;
 1811 }
 1812 
 1813 int
 1814 mdc_symlink(call_frame_t *frame, xlator_t *this, const char *linkname,
 1815             loc_t *loc, mode_t umask, dict_t *xdata)
 1816 {
 1817     mdc_local_t *local = NULL;
 1818     char *name;
 1819 
 1820     name = gf_strdup(linkname);
 1821     if (name == NULL) {
 1822         goto wind;
 1823     }
 1824     local = mdc_local_get(frame, loc->inode);
 1825     if (local == NULL) {
 1826         GF_FREE(name);
 1827         goto wind;
 1828     }
 1829 
 1830     loc_copy(&local->loc, loc);
 1831     local->linkname = name;
 1832 
 1833 wind:
 1834     STACK_WIND(frame, mdc_symlink_cbk, FIRST_CHILD(this),
 1835                FIRST_CHILD(this)->fops->symlink, linkname, loc, umask, xdata);
 1836     return 0;
 1837 }
 1838 
 1839 int
 1840 mdc_rename_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 1841                int32_t op_ret, int32_t op_errno, struct iatt *buf,
 1842                struct iatt *preoldparent, struct iatt *postoldparent,
 1843                struct iatt *prenewparent, struct iatt *postnewparent,
 1844                dict_t *xdata)
 1845 {
 1846     mdc_local_t *local = NULL;
 1847 
 1848     local = frame->local;
 1849     if (!local)
 1850         goto out;
 1851 
 1852     if (op_ret != 0) {
 1853         if ((op_errno == ESTALE) || (op_errno == ENOENT)) {
 1854             mdc_inode_iatt_invalidate(this, local->loc.inode);
 1855             mdc_inode_iatt_invalidate(this, local->loc2.parent);
 1856         }
 1857 
 1858         goto out;
 1859     }
 1860 
 1861     if (local->loc.parent) {
 1862         mdc_inode_iatt_set(this, local->loc.parent, postoldparent,
 1863                            local->incident_time);
 1864     }
 1865 
 1866     if (local->loc.inode) {
 1867         /* TODO: fix dht_rename() not to return linkfile
 1868            attributes before setting attributes here
 1869         */
 1870 
 1871         mdc_inode_iatt_set(this, local->loc.inode, NULL, local->incident_time);
 1872     }
 1873 
 1874     if (local->loc2.parent) {
 1875         mdc_inode_iatt_set(this, local->loc2.parent, postnewparent,
 1876                            local->incident_time);
 1877     }
 1878 out:
 1879     MDC_STACK_UNWIND(rename, frame, op_ret, op_errno, buf, preoldparent,
 1880                      postoldparent, prenewparent, postnewparent, xdata);
 1881     return 0;
 1882 }
 1883 
 1884 int
 1885 mdc_rename(call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc,
 1886            dict_t *xdata)
 1887 {
 1888     mdc_local_t *local = NULL;
 1889 
 1890     local = mdc_local_get(frame, oldloc->inode);
 1891     if (local != NULL) {
 1892         loc_copy(&local->loc, oldloc);
 1893         loc_copy(&local->loc2, newloc);
 1894     }
 1895 
 1896     STACK_WIND(frame, mdc_rename_cbk, FIRST_CHILD(this),
 1897                FIRST_CHILD(this)->fops->rename, oldloc, newloc, xdata);
 1898     return 0;
 1899 }
 1900 
 1901 int
 1902 mdc_link_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret,
 1903              int32_t op_errno, inode_t *inode, struct iatt *buf,
 1904              struct iatt *preparent, struct iatt *postparent, dict_t *xdata)
 1905 {
 1906     mdc_local_t *local = NULL;
 1907 
 1908     local = frame->local;
 1909 
 1910     if (!local)
 1911         goto out;
 1912 
 1913     if (op_ret != 0) {
 1914         if ((op_errno == ENOENT) || (op_errno == ESTALE)) {
 1915             mdc_inode_iatt_invalidate(this, local->loc.inode);
 1916             mdc_inode_iatt_invalidate(this, local->loc2.parent);
 1917         }
 1918 
 1919         goto out;
 1920     }
 1921 
 1922     if (local->loc.inode) {
 1923         mdc_inode_iatt_set(this, local->loc.inode, buf, local->incident_time);
 1924     }
 1925 
 1926     if (local->loc2.parent) {
 1927         mdc_inode_iatt_set(this, local->loc2.parent, postparent,
 1928                            local->incident_time);
 1929     }
 1930 out:
 1931     MDC_STACK_UNWIND(link, frame, op_ret, op_errno, inode, buf, preparent,
 1932                      postparent, xdata);
 1933     return 0;
 1934 }
 1935 
 1936 int
 1937 mdc_link(call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc,
 1938          dict_t *xdata)
 1939 {
 1940     mdc_local_t *local = NULL;
 1941 
 1942     local = mdc_local_get(frame, oldloc->inode);
 1943     if (local != NULL) {
 1944         loc_copy(&local->loc, oldloc);
 1945         loc_copy(&local->loc2, newloc);
 1946     }
 1947 
 1948     STACK_WIND(frame, mdc_link_cbk, FIRST_CHILD(this),
 1949                FIRST_CHILD(this)->fops->link, oldloc, newloc, xdata);
 1950     return 0;
 1951 }
 1952 
 1953 int
 1954 mdc_create_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 1955                int32_t op_ret, int32_t op_errno, fd_t *fd, inode_t *inode,
 1956                struct iatt *buf, struct iatt *preparent,
 1957                struct iatt *postparent, dict_t *xdata)
 1958 {
 1959     mdc_local_t *local = NULL;
 1960 
 1961     local = frame->local;
 1962 
 1963     if (!local)
 1964         goto out;
 1965 
 1966     if (op_ret != 0) {
 1967         if ((op_errno == ESTALE) || (op_errno == ENOENT)) {
 1968             mdc_inode_iatt_invalidate(this, local->loc.parent);
 1969         }
 1970 
 1971         goto out;
 1972     }
 1973 
 1974     if (local->loc.parent) {
 1975         mdc_inode_iatt_set(this, local->loc.parent, postparent,
 1976                            local->incident_time);
 1977     }
 1978 
 1979     if (local->loc.inode) {
 1980         mdc_inode_iatt_set(this, inode, buf, local->incident_time);
 1981     }
 1982 out:
 1983     MDC_STACK_UNWIND(create, frame, op_ret, op_errno, fd, inode, buf, preparent,
 1984                      postparent, xdata);
 1985     return 0;
 1986 }
 1987 
 1988 int
 1989 mdc_create(call_frame_t *frame, xlator_t *this, loc_t *loc, int flags,
 1990            mode_t mode, mode_t umask, fd_t *fd, dict_t *xdata)
 1991 {
 1992     mdc_local_t *local = NULL;
 1993 
 1994     local = mdc_local_get(frame, loc->inode);
 1995     if (local != NULL) {
 1996         loc_copy(&local->loc, loc);
 1997         local->xattr = dict_ref(xdata);
 1998     }
 1999 
 2000     STACK_WIND(frame, mdc_create_cbk, FIRST_CHILD(this),
 2001                FIRST_CHILD(this)->fops->create, loc, flags, mode, umask, fd,
 2002                xdata);
 2003     return 0;
 2004 }
 2005 
 2006 static int
 2007 mdc_open_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret,
 2008              int32_t op_errno, fd_t *fd, dict_t *xdata)
 2009 {
 2010     mdc_local_t *local = NULL;
 2011 
 2012     local = frame->local;
 2013 
 2014     if (!local)
 2015         goto out;
 2016 
 2017     if (op_ret != 0) {
 2018         if ((op_errno == ESTALE) || (op_errno == ENOENT))
 2019             mdc_inode_iatt_invalidate(this, local->loc.inode);
 2020         goto out;
 2021     }
 2022 
 2023     if (local->fd->flags & O_TRUNC) {
 2024         /* O_TRUNC modifies file size. Hence invalidate the
 2025          * cache entry to fetch latest attributes. */
 2026         mdc_inode_iatt_invalidate(this, local->fd->inode);
 2027     }
 2028 
 2029 out:
 2030     MDC_STACK_UNWIND(open, frame, op_ret, op_errno, fd, xdata);
 2031     return 0;
 2032 }
 2033 
 2034 static int
 2035 mdc_open(call_frame_t *frame, xlator_t *this, loc_t *loc, int flags, fd_t *fd,
 2036          dict_t *xdata)
 2037 {
 2038     mdc_local_t *local = NULL;
 2039 
 2040     if (!fd || !IA_ISREG(fd->inode->ia_type) || !(fd->flags & O_TRUNC)) {
 2041         goto out;
 2042     }
 2043 
 2044     local = mdc_local_get(frame, loc->inode);
 2045     if (local != NULL) {
 2046         local->fd = __fd_ref(fd);
 2047     }
 2048 
 2049 out:
 2050     STACK_WIND(frame, mdc_open_cbk, FIRST_CHILD(this),
 2051                FIRST_CHILD(this)->fops->open, loc, flags, fd, xdata);
 2052     return 0;
 2053 }
 2054 
 2055 int
 2056 mdc_readv_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret,
 2057               int32_t op_errno, struct iovec *vector, int32_t count,
 2058               struct iatt *stbuf, struct iobref *iobref, dict_t *xdata)
 2059 {
 2060     mdc_local_t *local = NULL;
 2061 
 2062     local = frame->local;
 2063     if (!local)
 2064         goto out;
 2065 
 2066     if (op_ret < 0) {
 2067         if ((op_errno == ENOENT) || (op_errno == ESTALE))
 2068             mdc_inode_iatt_invalidate(this, local->fd->inode);
 2069         goto out;
 2070     }
 2071 
 2072     mdc_inode_iatt_set(this, local->fd->inode, stbuf, local->incident_time);
 2073 
 2074 out:
 2075     MDC_STACK_UNWIND(readv, frame, op_ret, op_errno, vector, count, stbuf,
 2076                      iobref, xdata);
 2077 
 2078     return 0;
 2079 }
 2080 
 2081 int
 2082 mdc_readv(call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size,
 2083           off_t offset, uint32_t flags, dict_t *xdata)
 2084 {
 2085     mdc_local_t *local = NULL;
 2086 
 2087     local = mdc_local_get(frame, fd->inode);
 2088     if (local != NULL) {
 2089         local->fd = __fd_ref(fd);
 2090     }
 2091 
 2092     STACK_WIND(frame, mdc_readv_cbk, FIRST_CHILD(this),
 2093                FIRST_CHILD(this)->fops->readv, fd, size, offset, flags, xdata);
 2094     return 0;
 2095 }
 2096 
 2097 int
 2098 mdc_writev_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 2099                int32_t op_ret, int32_t op_errno, struct iatt *prebuf,
 2100                struct iatt *postbuf, dict_t *xdata)
 2101 {
 2102     mdc_local_t *local = NULL;
 2103 
 2104     local = frame->local;
 2105     if (!local)
 2106         goto out;
 2107 
 2108     if (op_ret == -1) {
 2109         if ((op_errno == ENOENT) || (op_errno == ESTALE))
 2110             mdc_inode_iatt_invalidate(this, local->fd->inode);
 2111         goto out;
 2112     }
 2113 
 2114     mdc_inode_iatt_set_validate(this, local->fd->inode, prebuf, postbuf,
 2115                                 _gf_true, local->incident_time);
 2116 
 2117 out:
 2118     MDC_STACK_UNWIND(writev, frame, op_ret, op_errno, prebuf, postbuf, xdata);
 2119 
 2120     return 0;
 2121 }
 2122 
 2123 int
 2124 mdc_writev(call_frame_t *frame, xlator_t *this, fd_t *fd, struct iovec *vector,
 2125            int count, off_t offset, uint32_t flags, struct iobref *iobref,
 2126            dict_t *xdata)
 2127 {
 2128     mdc_local_t *local = NULL;
 2129 
 2130     local = mdc_local_get(frame, fd->inode);
 2131     if (local != NULL) {
 2132         local->fd = __fd_ref(fd);
 2133     }
 2134 
 2135     STACK_WIND(frame, mdc_writev_cbk, FIRST_CHILD(this),
 2136                FIRST_CHILD(this)->fops->writev, fd, vector, count, offset,
 2137                flags, iobref, xdata);
 2138     return 0;
 2139 }
 2140 
 2141 int
 2142 mdc_setattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 2143                 int32_t op_ret, int32_t op_errno, struct iatt *prebuf,
 2144                 struct iatt *postbuf, dict_t *xdata)
 2145 {
 2146     mdc_local_t *local = NULL;
 2147 
 2148     local = frame->local;
 2149     if (!local)
 2150         goto out;
 2151 
 2152     if (op_ret != 0) {
 2153         mdc_inode_iatt_set(this, local->loc.inode, NULL, local->incident_time);
 2154         goto out;
 2155     }
 2156 
 2157     mdc_inode_iatt_set_validate(this, local->loc.inode, prebuf, postbuf,
 2158                                 _gf_true, local->incident_time);
 2159     mdc_inode_xatt_update(this, local->loc.inode, xdata);
 2160 
 2161 out:
 2162     MDC_STACK_UNWIND(setattr, frame, op_ret, op_errno, prebuf, postbuf, xdata);
 2163 
 2164     return 0;
 2165 }
 2166 
 2167 int
 2168 mdc_setattr(call_frame_t *frame, xlator_t *this, loc_t *loc, struct iatt *stbuf,
 2169             int valid, dict_t *xdata)
 2170 {
 2171     mdc_local_t *local = NULL;
 2172     dict_t *xattr_alloc = NULL;
 2173     int ret = 0;
 2174     struct mdc_conf *conf = this->private;
 2175 
 2176     local = mdc_local_get(frame, loc->inode);
 2177     if (local == NULL) {
 2178         goto wind;
 2179     }
 2180 
 2181     loc_copy(&local->loc, loc);
 2182 
 2183     if ((valid & GF_SET_ATTR_MODE) && conf->cache_glusterfs_acl) {
 2184         if (!xdata)
 2185             xdata = xattr_alloc = dict_new();
 2186         if (xdata) {
 2187             ret = dict_set_int8(xdata, GF_POSIX_ACL_ACCESS, 0);
 2188             if (!ret)
 2189                 ret = dict_set_int8(xdata, GF_POSIX_ACL_DEFAULT, 0);
 2190             if (ret)
 2191                 mdc_inode_xatt_invalidate(this, local->loc.inode);
 2192         }
 2193     }
 2194 
 2195     if ((valid & GF_SET_ATTR_MODE) && conf->cache_posix_acl) {
 2196         if (!xdata)
 2197             xdata = xattr_alloc = dict_new();
 2198         if (xdata) {
 2199             ret = dict_set_int8(xdata, POSIX_ACL_ACCESS_XATTR, 0);
 2200             if (!ret)
 2201                 ret = dict_set_int8(xdata, POSIX_ACL_DEFAULT_XATTR, 0);
 2202             if (ret)
 2203                 mdc_inode_xatt_invalidate(this, local->loc.inode);
 2204         }
 2205     }
 2206 
 2207 wind:
 2208     STACK_WIND(frame, mdc_setattr_cbk, FIRST_CHILD(this),
 2209                FIRST_CHILD(this)->fops->setattr, loc, stbuf, valid, xdata);
 2210 
 2211     if (xattr_alloc)
 2212         dict_unref(xattr_alloc);
 2213     return 0;
 2214 }
 2215 
 2216 int
 2217 mdc_fsetattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 2218                  int32_t op_ret, int32_t op_errno, struct iatt *prebuf,
 2219                  struct iatt *postbuf, dict_t *xdata)
 2220 {
 2221     mdc_local_t *local = NULL;
 2222 
 2223     local = frame->local;
 2224     if (!local)
 2225         goto out;
 2226 
 2227     if (op_ret != 0) {
 2228         if ((op_errno == ESTALE) || (op_errno == ENOENT))
 2229             mdc_inode_iatt_invalidate(this, local->fd->inode);
 2230         goto out;
 2231     }
 2232 
 2233     mdc_inode_iatt_set_validate(this, local->fd->inode, prebuf, postbuf,
 2234                                 _gf_true, local->incident_time);
 2235     mdc_inode_xatt_update(this, local->fd->inode, xdata);
 2236 
 2237 out:
 2238     MDC_STACK_UNWIND(fsetattr, frame, op_ret, op_errno, prebuf, postbuf, xdata);
 2239 
 2240     return 0;
 2241 }
 2242 
 2243 int
 2244 mdc_fsetattr(call_frame_t *frame, xlator_t *this, fd_t *fd, struct iatt *stbuf,
 2245              int valid, dict_t *xdata)
 2246 {
 2247     mdc_local_t *local = NULL;
 2248     dict_t *xattr_alloc = NULL;
 2249     int ret = 0;
 2250     struct mdc_conf *conf = this->private;
 2251 
 2252     local = mdc_local_get(frame, fd->inode);
 2253     if (local == NULL) {
 2254         goto wind;
 2255     }
 2256 
 2257     local->fd = __fd_ref(fd);
 2258 
 2259     if ((valid & GF_SET_ATTR_MODE) && conf->cache_glusterfs_acl) {
 2260         if (!xdata)
 2261             xdata = xattr_alloc = dict_new();
 2262         if (xdata) {
 2263             ret = dict_set_int8(xdata, GF_POSIX_ACL_ACCESS, 0);
 2264             if (!ret)
 2265                 ret = dict_set_int8(xdata, GF_POSIX_ACL_DEFAULT, 0);
 2266             if (ret)
 2267                 mdc_inode_xatt_invalidate(this, local->fd->inode);
 2268         }
 2269     }
 2270 
 2271     if ((valid & GF_SET_ATTR_MODE) && conf->cache_posix_acl) {
 2272         if (!xdata)
 2273             xdata = xattr_alloc = dict_new();
 2274         if (xdata) {
 2275             ret = dict_set_int8(xdata, POSIX_ACL_ACCESS_XATTR, 0);
 2276             if (!ret)
 2277                 ret = dict_set_int8(xdata, POSIX_ACL_DEFAULT_XATTR, 0);
 2278             if (ret)
 2279                 mdc_inode_xatt_invalidate(this, local->fd->inode);
 2280         }
 2281     }
 2282 
 2283 wind:
 2284     STACK_WIND(frame, mdc_fsetattr_cbk, FIRST_CHILD(this),
 2285                FIRST_CHILD(this)->fops->fsetattr, fd, stbuf, valid, xdata);
 2286 
 2287     if (xattr_alloc)
 2288         dict_unref(xattr_alloc);
 2289     return 0;
 2290 }
 2291 
 2292 int
 2293 mdc_fsync_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret,
 2294               int32_t op_errno, struct iatt *prebuf, struct iatt *postbuf,
 2295               dict_t *xdata)
 2296 {
 2297     mdc_local_t *local = NULL;
 2298 
 2299     local = frame->local;
 2300     if (!local)
 2301         goto out;
 2302 
 2303     if (op_ret != 0) {
 2304         if ((op_errno == ENOENT) || (op_errno == ESTALE))
 2305             mdc_inode_iatt_invalidate(this, local->fd->inode);
 2306         goto out;
 2307     }
 2308 
 2309     mdc_inode_iatt_set_validate(this, local->fd->inode, prebuf, postbuf,
 2310                                 _gf_true, local->incident_time);
 2311 
 2312 out:
 2313     MDC_STACK_UNWIND(fsync, frame, op_ret, op_errno, prebuf, postbuf, xdata);
 2314 
 2315     return 0;
 2316 }
 2317 
 2318 int
 2319 mdc_fsync(call_frame_t *frame, xlator_t *this, fd_t *fd, int datasync,
 2320           dict_t *xdata)
 2321 {
 2322     mdc_local_t *local = NULL;
 2323 
 2324     local = mdc_local_get(frame, fd->inode);
 2325     if (local != NULL) {
 2326         local->fd = __fd_ref(fd);
 2327     }
 2328 
 2329     STACK_WIND(frame, mdc_fsync_cbk, FIRST_CHILD(this),
 2330                FIRST_CHILD(this)->fops->fsync, fd, datasync, xdata);
 2331     return 0;
 2332 }
 2333 
 2334 int
 2335 mdc_setxattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 2336                  int32_t op_ret, int32_t op_errno, dict_t *xdata)
 2337 {
 2338     mdc_local_t *local = NULL;
 2339     struct iatt prestat = {
 2340         0,
 2341     };
 2342     struct iatt poststat = {
 2343         0,
 2344     };
 2345     int ret = 0;
 2346 
 2347     local = frame->local;
 2348     if (!local)
 2349         goto out;
 2350 
 2351     if (op_ret != 0) {
 2352         if ((op_errno == ENOENT) || (op_errno == ESTALE))
 2353             mdc_inode_iatt_invalidate(this, local->loc.inode);
 2354         goto out;
 2355     }
 2356 
 2357     mdc_inode_xatt_update(this, local->loc.inode, local->xattr);
 2358 
 2359     ret = dict_get_iatt(xdata, GF_PRESTAT, &prestat);
 2360     if (ret >= 0) {
 2361         ret = dict_get_iatt(xdata, GF_POSTSTAT, &poststat);
 2362         mdc_inode_iatt_set_validate(this, local->loc.inode, &prestat, &poststat,
 2363                                     _gf_true, local->incident_time);
 2364     }
 2365 
 2366     if (ret < 0)
 2367         mdc_inode_iatt_invalidate(this, local->loc.inode);
 2368 
 2369 out:
 2370     MDC_STACK_UNWIND(setxattr, frame, op_ret, op_errno, xdata);
 2371 
 2372     return 0;
 2373 }
 2374 
 2375 int
 2376 mdc_setxattr(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xattr,
 2377              int flags, dict_t *xdata)
 2378 {
 2379     mdc_local_t *local = NULL;
 2380 
 2381     local = mdc_local_get(frame, loc->inode);
 2382     if (local != NULL) {
 2383         loc_copy(&local->loc, loc);
 2384         local->xattr = dict_ref(xattr);
 2385     }
 2386 
 2387     STACK_WIND(frame, mdc_setxattr_cbk, FIRST_CHILD(this),
 2388                FIRST_CHILD(this)->fops->setxattr, loc, xattr, flags, xdata);
 2389 
 2390     return 0;
 2391 }
 2392 
 2393 int
 2394 mdc_fsetxattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 2395                   int32_t op_ret, int32_t op_errno, dict_t *xdata)
 2396 {
 2397     mdc_local_t *local = NULL;
 2398     struct iatt prestat = {
 2399         0,
 2400     };
 2401     struct iatt poststat = {
 2402         0,
 2403     };
 2404     int ret = 0;
 2405 
 2406     local = frame->local;
 2407     if (!local)
 2408         goto out;
 2409 
 2410     if (op_ret != 0) {
 2411         if ((op_errno == ESTALE) || (op_errno == ENOENT))
 2412             mdc_inode_iatt_invalidate(this, local->fd->inode);
 2413         goto out;
 2414     }
 2415 
 2416     mdc_inode_xatt_update(this, local->fd->inode, local->xattr);
 2417 
 2418     ret = dict_get_iatt(xdata, GF_PRESTAT, &prestat);
 2419     if (ret >= 0) {
 2420         ret = dict_get_iatt(xdata, GF_POSTSTAT, &poststat);
 2421         mdc_inode_iatt_set_validate(this, local->fd->inode, &prestat, &poststat,
 2422                                     _gf_true, local->incident_time);
 2423     }
 2424 
 2425     if (ret < 0)
 2426         mdc_inode_iatt_invalidate(this, local->fd->inode);
 2427 
 2428 out:
 2429     MDC_STACK_UNWIND(fsetxattr, frame, op_ret, op_errno, xdata);
 2430 
 2431     return 0;
 2432 }
 2433 
 2434 int
 2435 mdc_fsetxattr(call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *xattr,
 2436               int flags, dict_t *xdata)
 2437 {
 2438     mdc_local_t *local = NULL;
 2439 
 2440     local = mdc_local_get(frame, fd->inode);
 2441     if (local != NULL) {
 2442         local->fd = __fd_ref(fd);
 2443         local->xattr = dict_ref(xattr);
 2444     }
 2445 
 2446     STACK_WIND(frame, mdc_fsetxattr_cbk, FIRST_CHILD(this),
 2447                FIRST_CHILD(this)->fops->fsetxattr, fd, xattr, flags, xdata);
 2448 
 2449     return 0;
 2450 }
 2451 
 2452 int
 2453 mdc_getxattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 2454                  int32_t op_ret, int32_t op_errno, dict_t *xattr, dict_t *xdata)
 2455 {
 2456     mdc_local_t *local = NULL;
 2457 
 2458     local = frame->local;
 2459     if (!local)
 2460         goto out;
 2461 
 2462     if (op_ret < 0) {
 2463         if ((op_errno == ENOENT) || (op_errno == ESTALE))
 2464             mdc_inode_iatt_invalidate(this, local->loc.inode);
 2465         goto out;
 2466     }
 2467 
 2468     if (dict_get(xattr, "glusterfs.skip-cache")) {
 2469         gf_msg(this->name, GF_LOG_DEBUG, 0, 0,
 2470                "Skipping xattr update due to empty value");
 2471         goto out;
 2472     }
 2473 
 2474     if (local->update_cache) {
 2475         mdc_inode_xatt_set(this, local->loc.inode, xdata);
 2476     }
 2477 
 2478 out:
 2479     MDC_STACK_UNWIND(getxattr, frame, op_ret, op_errno, xattr, xdata);
 2480 
 2481     return 0;
 2482 }
 2483 
 2484 int
 2485 mdc_getxattr(call_frame_t *frame, xlator_t *this, loc_t *loc, const char *key,
 2486              dict_t *xdata)
 2487 {
 2488     int ret;
 2489     int op_errno = ENODATA;
 2490     mdc_local_t *local = NULL;
 2491     dict_t *xattr = NULL;
 2492     struct mdc_conf *conf = this->private;
 2493     gf_boolean_t key_satisfied = _gf_false;
 2494 
 2495     local = mdc_local_get(frame, loc->inode);
 2496     if (!local) {
 2497         goto uncached;
 2498     }
 2499 
 2500     loc_copy(&local->loc, loc);
 2501 
 2502     if (!is_mdc_key_satisfied(this, key)) {
 2503         goto uncached;
 2504     }
 2505     key_satisfied = _gf_true;
 2506 
 2507     ret = mdc_inode_xatt_get(this, loc->inode, &xattr);
 2508     if (ret != 0)
 2509         goto uncached;
 2510 
 2511     if (!xattr || !dict_get(xattr, (char *)key)) {
 2512         ret = -1;
 2513         op_errno = ENODATA;
 2514     }
 2515 
 2516     GF_ATOMIC_INC(conf->mdc_counter.xattr_hit);
 2517     MDC_STACK_UNWIND(getxattr, frame, ret, op_errno, xattr, xdata);
 2518 
 2519     if (xattr)
 2520         dict_unref(xattr);
 2521 
 2522     return 0;
 2523 
 2524 uncached:
 2525     if (key_satisfied) {
 2526         xdata = mdc_prepare_request(this, local, xdata);
 2527     }
 2528 
 2529     GF_ATOMIC_INC(conf->mdc_counter.xattr_miss);
 2530     STACK_WIND(frame, mdc_getxattr_cbk, FIRST_CHILD(this),
 2531                FIRST_CHILD(this)->fops->getxattr, loc, key, xdata);
 2532 
 2533     if (key_satisfied && (xdata != NULL)) {
 2534         dict_unref(xdata);
 2535     }
 2536 
 2537     return 0;
 2538 }
 2539 
 2540 int
 2541 mdc_fgetxattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 2542                   int32_t op_ret, int32_t op_errno, dict_t *xattr,
 2543                   dict_t *xdata)
 2544 {
 2545     mdc_local_t *local = NULL;
 2546 
 2547     local = frame->local;
 2548     if (!local)
 2549         goto out;
 2550 
 2551     if (op_ret < 0) {
 2552         if ((op_errno == ENOENT) || (op_errno == ESTALE))
 2553             mdc_inode_iatt_invalidate(this, local->fd->inode);
 2554         goto out;
 2555     }
 2556 
 2557     if (dict_get(xattr, "glusterfs.skip-cache")) {
 2558         gf_msg(this->name, GF_LOG_DEBUG, 0, 0,
 2559                "Skipping xattr update due to empty value");
 2560         goto out;
 2561     }
 2562 
 2563     if (local->update_cache) {
 2564         mdc_inode_xatt_set(this, local->fd->inode, xdata);
 2565     }
 2566 
 2567 out:
 2568     MDC_STACK_UNWIND(fgetxattr, frame, op_ret, op_errno, xattr, xdata);
 2569 
 2570     return 0;
 2571 }
 2572 
 2573 int
 2574 mdc_fgetxattr(call_frame_t *frame, xlator_t *this, fd_t *fd, const char *key,
 2575               dict_t *xdata)
 2576 {
 2577     int ret;
 2578     mdc_local_t *local = NULL;
 2579     dict_t *xattr = NULL;
 2580     int op_errno = ENODATA;
 2581     struct mdc_conf *conf = this->private;
 2582     gf_boolean_t key_satisfied = _gf_true;
 2583 
 2584     local = mdc_local_get(frame, fd->inode);
 2585     if (!local)
 2586         goto uncached;
 2587 
 2588     local->fd = __fd_ref(fd);
 2589 
 2590     if (!is_mdc_key_satisfied(this, key)) {
 2591         key_satisfied = _gf_false;
 2592         goto uncached;
 2593     }
 2594 
 2595     ret = mdc_inode_xatt_get(this, fd->inode, &xattr);
 2596     if (ret != 0)
 2597         goto uncached;
 2598 
 2599     if (!xattr || !dict_get(xattr, (char *)key)) {
 2600         ret = -1;
 2601         op_errno = ENODATA;
 2602     }
 2603 
 2604     GF_ATOMIC_INC(conf->mdc_counter.xattr_hit);
 2605     MDC_STACK_UNWIND(fgetxattr, frame, ret, op_errno, xattr, xdata);
 2606 
 2607     if (xattr)
 2608         dict_unref(xattr);
 2609 
 2610     return 0;
 2611 
 2612 uncached:
 2613     if (key_satisfied) {
 2614         xdata = mdc_prepare_request(this, local, xdata);
 2615     }
 2616 
 2617     GF_ATOMIC_INC(conf->mdc_counter.xattr_miss);
 2618     STACK_WIND(frame, mdc_fgetxattr_cbk, FIRST_CHILD(this),
 2619                FIRST_CHILD(this)->fops->fgetxattr, fd, key, xdata);
 2620 
 2621     if (key_satisfied && (xdata != NULL)) {
 2622         dict_unref(xdata);
 2623     }
 2624 
 2625     return 0;
 2626 }
 2627 
 2628 int
 2629 mdc_removexattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 2630                     int32_t op_ret, int32_t op_errno, dict_t *xdata)
 2631 {
 2632     mdc_local_t *local = NULL;
 2633     struct iatt prestat = {
 2634         0,
 2635     };
 2636     struct iatt poststat = {
 2637         0,
 2638     };
 2639     int ret = 0;
 2640 
 2641     local = frame->local;
 2642     if (!local)
 2643         goto out;
 2644 
 2645     if (op_ret != 0) {
 2646         if ((op_errno == ENOENT) || (op_errno == ESTALE))
 2647             mdc_inode_iatt_invalidate(this, local->loc.inode);
 2648         goto out;
 2649     }
 2650 
 2651     if (local->key)
 2652         mdc_inode_xatt_unset(this, local->loc.inode, local->key);
 2653     else
 2654         mdc_inode_xatt_invalidate(this, local->loc.inode);
 2655 
 2656     ret = dict_get_iatt(xdata, GF_PRESTAT, &prestat);
 2657     if (ret >= 0) {
 2658         ret = dict_get_iatt(xdata, GF_POSTSTAT, &poststat);
 2659         mdc_inode_iatt_set_validate(this, local->loc.inode, &prestat, &poststat,
 2660                                     _gf_true, local->incident_time);
 2661     }
 2662 
 2663     if (ret < 0)
 2664         mdc_inode_iatt_invalidate(this, local->loc.inode);
 2665 out:
 2666     MDC_STACK_UNWIND(removexattr, frame, op_ret, op_errno, xdata);
 2667 
 2668     return 0;
 2669 }
 2670 
 2671 int
 2672 mdc_removexattr(call_frame_t *frame, xlator_t *this, loc_t *loc,
 2673                 const char *name, dict_t *xdata)
 2674 {
 2675     mdc_local_t *local = NULL;
 2676     int op_errno = ENODATA;
 2677     int ret = 0;
 2678     dict_t *xattr = NULL;
 2679     struct mdc_conf *conf = this->private;
 2680     char *name2;
 2681 
 2682     name2 = gf_strdup(name);
 2683     if (name2 == NULL) {
 2684         goto uncached;
 2685     }
 2686 
 2687     local = mdc_local_get(frame, loc->inode);
 2688     if (local == NULL) {
 2689         GF_FREE(name2);
 2690         goto uncached;
 2691     }
 2692 
 2693     loc_copy(&local->loc, loc);
 2694     local->key = name2;
 2695 
 2696     if (!is_mdc_key_satisfied(this, name))
 2697         goto uncached;
 2698 
 2699     ret = mdc_inode_xatt_get(this, loc->inode, &xattr);
 2700     if (ret != 0)
 2701         goto uncached;
 2702 
 2703     GF_ATOMIC_INC(conf->mdc_counter.xattr_hit);
 2704 
 2705     if (!xattr || !dict_get(xattr, (char *)name)) {
 2706         ret = -1;
 2707         op_errno = ENODATA;
 2708 
 2709         MDC_STACK_UNWIND(removexattr, frame, ret, op_errno, xdata);
 2710     } else {
 2711         STACK_WIND(frame, mdc_removexattr_cbk, FIRST_CHILD(this),
 2712                    FIRST_CHILD(this)->fops->removexattr, loc, name, xdata);
 2713     }
 2714 
 2715     if (xattr)
 2716         dict_unref(xattr);
 2717 
 2718     return 0;
 2719 
 2720 uncached:
 2721     GF_ATOMIC_INC(conf->mdc_counter.xattr_miss);
 2722     STACK_WIND(frame, mdc_removexattr_cbk, FIRST_CHILD(this),
 2723                FIRST_CHILD(this)->fops->removexattr, loc, name, xdata);
 2724     return 0;
 2725 }
 2726 
 2727 int
 2728 mdc_fremovexattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 2729                      int32_t op_ret, int32_t op_errno, dict_t *xdata)
 2730 {
 2731     mdc_local_t *local = NULL;
 2732     struct iatt prestat = {
 2733         0,
 2734     };
 2735     struct iatt poststat = {
 2736         0,
 2737     };
 2738     int ret = 0;
 2739 
 2740     local = frame->local;
 2741     if (!local)
 2742         goto out;
 2743 
 2744     if (op_ret != 0) {
 2745         if ((op_errno == ENOENT) || (op_errno == ESTALE))
 2746             mdc_inode_iatt_invalidate(this, local->fd->inode);
 2747         goto out;
 2748     }
 2749 
 2750     if (local->key)
 2751         mdc_inode_xatt_unset(this, local->fd->inode, local->key);
 2752     else
 2753         mdc_inode_xatt_invalidate(this, local->fd->inode);
 2754 
 2755     ret = dict_get_iatt(xdata, GF_PRESTAT, &prestat);
 2756     if (ret >= 0) {
 2757         ret = dict_get_iatt(xdata, GF_POSTSTAT, &poststat);
 2758         mdc_inode_iatt_set_validate(this, local->fd->inode, &prestat, &poststat,
 2759                                     _gf_true, local->incident_time);
 2760     }
 2761 
 2762     if (ret < 0)
 2763         mdc_inode_iatt_invalidate(this, local->fd->inode);
 2764 
 2765 out:
 2766     MDC_STACK_UNWIND(fremovexattr, frame, op_ret, op_errno, xdata);
 2767 
 2768     return 0;
 2769 }
 2770 
 2771 int
 2772 mdc_fremovexattr(call_frame_t *frame, xlator_t *this, fd_t *fd,
 2773                  const char *name, dict_t *xdata)
 2774 {
 2775     mdc_local_t *local = NULL;
 2776     int op_errno = ENODATA;
 2777     int ret = 0;
 2778     dict_t *xattr = NULL;
 2779     struct mdc_conf *conf = this->private;
 2780     char *name2;
 2781 
 2782     name2 = gf_strdup(name);
 2783     if (name2 == NULL) {
 2784         goto uncached;
 2785     }
 2786 
 2787     local = mdc_local_get(frame, fd->inode);
 2788     if (local == NULL) {
 2789         GF_FREE(name2);
 2790         goto uncached;
 2791     }
 2792 
 2793     local->fd = __fd_ref(fd);
 2794     local->key = name2;
 2795 
 2796     if (!is_mdc_key_satisfied(this, name))
 2797         goto uncached;
 2798 
 2799     ret = mdc_inode_xatt_get(this, fd->inode, &xattr);
 2800     if (ret != 0)
 2801         goto uncached;
 2802 
 2803     GF_ATOMIC_INC(conf->mdc_counter.xattr_hit);
 2804 
 2805     if (!xattr || !dict_get(xattr, (char *)name)) {
 2806         ret = -1;
 2807         op_errno = ENODATA;
 2808 
 2809         MDC_STACK_UNWIND(fremovexattr, frame, ret, op_errno, xdata);
 2810     } else {
 2811         STACK_WIND(frame, mdc_fremovexattr_cbk, FIRST_CHILD(this),
 2812                    FIRST_CHILD(this)->fops->fremovexattr, fd, name, xdata);
 2813     }
 2814 
 2815     if (xattr)
 2816         dict_unref(xattr);
 2817 
 2818     return 0;
 2819 
 2820 uncached:
 2821     GF_ATOMIC_INC(conf->mdc_counter.xattr_miss);
 2822     STACK_WIND(frame, mdc_fremovexattr_cbk, FIRST_CHILD(this),
 2823                FIRST_CHILD(this)->fops->fremovexattr, fd, name, xdata);
 2824     return 0;
 2825 }
 2826 
 2827 int32_t
 2828 mdc_opendir_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 2829                 int32_t op_ret, int32_t op_errno, fd_t *fd, dict_t *xdata)
 2830 {
 2831     mdc_local_t *local = NULL;
 2832 
 2833     local = frame->local;
 2834     if (!local)
 2835         goto out;
 2836 
 2837     if (op_ret == 0)
 2838         goto out;
 2839 
 2840     if ((op_errno == ESTALE) || (op_errno == ENOENT))
 2841         mdc_inode_iatt_invalidate(this, local->loc.inode);
 2842 
 2843 out:
 2844     MDC_STACK_UNWIND(opendir, frame, op_ret, op_errno, fd, xdata);
 2845     return 0;
 2846 }
 2847 
 2848 int
 2849 mdc_opendir(call_frame_t *frame, xlator_t *this, loc_t *loc, fd_t *fd,
 2850             dict_t *xdata)
 2851 {
 2852     mdc_local_t *local = NULL;
 2853 
 2854     local = mdc_local_get(frame, loc->inode);
 2855     if (local != NULL) {
 2856         loc_copy(&local->loc, loc);
 2857     }
 2858 
 2859     /* Tell readdir-ahead to include these keys in xdata when it
 2860      * internally issues readdirp() in it's opendir_cbk */
 2861     xdata = mdc_prepare_request(this, local, xdata);
 2862 
 2863     STACK_WIND(frame, mdc_opendir_cbk, FIRST_CHILD(this),
 2864                FIRST_CHILD(this)->fops->opendir, loc, fd, xdata);
 2865 
 2866     if (xdata != NULL) {
 2867         dict_unref(xdata);
 2868     }
 2869 
 2870     return 0;
 2871 }
 2872 
 2873 int
 2874 mdc_readdirp_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int op_ret,
 2875                  int op_errno, gf_dirent_t *entries, dict_t *xdata)
 2876 {
 2877     gf_dirent_t *entry = NULL;
 2878     mdc_local_t *local = NULL;
 2879 
 2880     local = frame->local;
 2881     if (!local)
 2882         goto unwind;
 2883 
 2884     if (op_ret <= 0) {
 2885         if ((op_ret == -1) && ((op_errno == ENOENT) || (op_errno == ESTALE)))
 2886             mdc_inode_iatt_invalidate(this, local->fd->inode);
 2887         goto unwind;
 2888     }
 2889 
 2890     list_for_each_entry(entry, &entries->list, list)
 2891     {
 2892         if (!entry->inode)
 2893             continue;
 2894         mdc_inode_iatt_set(this, entry->inode, &entry->d_stat,
 2895                            local->incident_time);
 2896         if (local->update_cache) {
 2897             mdc_inode_xatt_set(this, entry->inode, entry->dict);
 2898         }
 2899     }
 2900 
 2901 unwind:
 2902     MDC_STACK_UNWIND(readdirp, frame, op_ret, op_errno, entries, xdata);
 2903     return 0;
 2904 }
 2905 
 2906 int
 2907 mdc_readdirp(call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size,
 2908              off_t offset, dict_t *xdata)
 2909 {
 2910     mdc_local_t *local = NULL;
 2911 
 2912     local = mdc_local_get(frame, fd->inode);
 2913     if (!local)
 2914         goto out;
 2915 
 2916     local->fd = __fd_ref(fd);
 2917 
 2918     xdata = mdc_prepare_request(this, local, xdata);
 2919 
 2920     STACK_WIND(frame, mdc_readdirp_cbk, FIRST_CHILD(this),
 2921                FIRST_CHILD(this)->fops->readdirp, fd, size, offset, xdata);
 2922 
 2923     if (xdata != NULL) {
 2924         dict_unref(xdata);
 2925     }
 2926 
 2927     return 0;
 2928 out:
 2929     MDC_STACK_UNWIND(readdirp, frame, -1, ENOMEM, NULL, NULL);
 2930     return 0;
 2931 }
 2932 
 2933 int
 2934 mdc_readdir_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int op_ret,
 2935                 int op_errno, gf_dirent_t *entries, dict_t *xdata)
 2936 {
 2937     mdc_local_t *local = NULL;
 2938 
 2939     local = frame->local;
 2940     if (!local)
 2941         goto out;
 2942 
 2943     if (op_ret == 0)
 2944         goto out;
 2945 
 2946     if ((op_errno == ESTALE) || (op_errno == ENOENT))
 2947         mdc_inode_iatt_invalidate(this, local->fd->inode);
 2948 out:
 2949     MDC_STACK_UNWIND(readdir, frame, op_ret, op_errno, entries, xdata);
 2950     return 0;
 2951 }
 2952 
 2953 int
 2954 mdc_readdir(call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size,
 2955             off_t offset, dict_t *xdata)
 2956 {
 2957     mdc_local_t *local = NULL;
 2958     struct mdc_conf *conf = this->private;
 2959 
 2960     local = mdc_local_get(frame, fd->inode);
 2961     if (!local)
 2962         goto unwind;
 2963 
 2964     local->fd = __fd_ref(fd);
 2965 
 2966     if (!conf->force_readdirp) {
 2967         STACK_WIND(frame, mdc_readdir_cbk, FIRST_CHILD(this),
 2968                    FIRST_CHILD(this)->fops->readdir, fd, size, offset, xdata);
 2969         return 0;
 2970     }
 2971 
 2972     xdata = mdc_prepare_request(this, local, xdata);
 2973 
 2974     STACK_WIND(frame, mdc_readdirp_cbk, FIRST_CHILD(this),
 2975                FIRST_CHILD(this)->fops->readdirp, fd, size, offset, xdata);
 2976 
 2977     if (xdata != NULL) {
 2978         dict_unref(xdata);
 2979     }
 2980 
 2981     return 0;
 2982 unwind:
 2983     MDC_STACK_UNWIND(readdir, frame, -1, ENOMEM, NULL, NULL);
 2984     return 0;
 2985 }
 2986 
 2987 int
 2988 mdc_fallocate_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 2989                   int32_t op_ret, int32_t op_errno, struct iatt *prebuf,
 2990                   struct iatt *postbuf, dict_t *xdata)
 2991 {
 2992     mdc_local_t *local = NULL;
 2993 
 2994     local = frame->local;
 2995     if (!local)
 2996         goto out;
 2997 
 2998     if (op_ret != 0) {
 2999         if ((op_errno == ENOENT) || (op_errno == ESTALE))
 3000             mdc_inode_iatt_invalidate(this, local->fd->inode);
 3001         goto out;
 3002     }
 3003 
 3004     mdc_inode_iatt_set_validate(this, local->fd->inode, prebuf, postbuf,
 3005                                 _gf_true, local->incident_time);
 3006 
 3007 out:
 3008     MDC_STACK_UNWIND(fallocate, frame, op_ret, op_errno, prebuf, postbuf,
 3009                      xdata);
 3010 
 3011     return 0;
 3012 }
 3013 
 3014 int
 3015 mdc_fallocate(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t mode,
 3016               off_t offset, size_t len, dict_t *xdata)
 3017 {
 3018     mdc_local_t *local;
 3019 
 3020     local = mdc_local_get(frame, fd->inode);
 3021     if (local != NULL) {
 3022         local->fd = __fd_ref(fd);
 3023     }
 3024 
 3025     STACK_WIND(frame, mdc_fallocate_cbk, FIRST_CHILD(this),
 3026                FIRST_CHILD(this)->fops->fallocate, fd, mode, offset, len,
 3027                xdata);
 3028 
 3029     return 0;
 3030 }
 3031 
 3032 int
 3033 mdc_discard_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 3034                 int32_t op_ret, int32_t op_errno, struct iatt *prebuf,
 3035                 struct iatt *postbuf, dict_t *xdata)
 3036 {
 3037     mdc_local_t *local = NULL;
 3038 
 3039     local = frame->local;
 3040     if (!local)
 3041         goto out;
 3042 
 3043     if (op_ret != 0) {
 3044         if ((op_errno == ENOENT) || (op_errno == ESTALE))
 3045             mdc_inode_iatt_invalidate(this, local->fd->inode);
 3046         goto out;
 3047     }
 3048 
 3049     mdc_inode_iatt_set_validate(this, local->fd->inode, prebuf, postbuf,
 3050                                 _gf_true, local->incident_time);
 3051 
 3052 out:
 3053     MDC_STACK_UNWIND(discard, frame, op_ret, op_errno, prebuf, postbuf, xdata);
 3054 
 3055     return 0;
 3056 }
 3057 
 3058 int
 3059 mdc_discard(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset,
 3060             size_t len, dict_t *xdata)
 3061 {
 3062     mdc_local_t *local;
 3063 
 3064     local = mdc_local_get(frame, fd->inode);
 3065     if (local != NULL) {
 3066         local->fd = __fd_ref(fd);
 3067     }
 3068 
 3069     STACK_WIND(frame, mdc_discard_cbk, FIRST_CHILD(this),
 3070                FIRST_CHILD(this)->fops->discard, fd, offset, len, xdata);
 3071 
 3072     return 0;
 3073 }
 3074 
 3075 int
 3076 mdc_zerofill_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 3077                  int32_t op_ret, int32_t op_errno, struct iatt *prebuf,
 3078                  struct iatt *postbuf, dict_t *xdata)
 3079 {
 3080     mdc_local_t *local = NULL;
 3081 
 3082     local = frame->local;
 3083     if (!local)
 3084         goto out;
 3085 
 3086     if (op_ret != 0) {
 3087         if ((op_errno == ENOENT) || (op_errno == ESTALE))
 3088             mdc_inode_iatt_invalidate(this, local->fd->inode);
 3089         goto out;
 3090     }
 3091 
 3092     mdc_inode_iatt_set_validate(this, local->fd->inode, prebuf, postbuf,
 3093                                 _gf_true, local->incident_time);
 3094 
 3095 out:
 3096     MDC_STACK_UNWIND(zerofill, frame, op_ret, op_errno, prebuf, postbuf, xdata);
 3097 
 3098     return 0;
 3099 }
 3100 
 3101 int
 3102 mdc_zerofill(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset,
 3103              off_t len, dict_t *xdata)
 3104 {
 3105     mdc_local_t *local;
 3106 
 3107     local = mdc_local_get(frame, fd->inode);
 3108     if (local != NULL) {
 3109         local->fd = __fd_ref(fd);
 3110     }
 3111 
 3112     STACK_WIND(frame, mdc_zerofill_cbk, FIRST_CHILD(this),
 3113                FIRST_CHILD(this)->fops->zerofill, fd, offset, len, xdata);
 3114 
 3115     return 0;
 3116 }
 3117 
 3118 int32_t
 3119 mdc_readlink_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 3120                  int32_t op_ret, int32_t op_errno, const char *path,
 3121                  struct iatt *buf, dict_t *xdata)
 3122 {
 3123     mdc_local_t *local = NULL;
 3124 
 3125     local = frame->local;
 3126     if (!local)
 3127         goto out;
 3128 
 3129     if (op_ret == 0)
 3130         goto out;
 3131 
 3132     if ((op_errno == ENOENT) || (op_errno == ESTALE))
 3133         mdc_inode_iatt_invalidate(this, local->loc.inode);
 3134 
 3135 out:
 3136     MDC_STACK_UNWIND(readlink, frame, op_ret, op_errno, path, buf, xdata);
 3137     return 0;
 3138 }
 3139 
 3140 int32_t
 3141 mdc_readlink(call_frame_t *frame, xlator_t *this, loc_t *loc, size_t size,
 3142              dict_t *xdata)
 3143 {
 3144     mdc_local_t *local = NULL;
 3145 
 3146     local = mdc_local_get(frame, loc->inode);
 3147     if (!local)
 3148         goto unwind;
 3149 
 3150     loc_copy(&local->loc, loc);
 3151 
 3152     STACK_WIND(frame, mdc_readlink_cbk, FIRST_CHILD(this),
 3153                FIRST_CHILD(this)->fops->readlink, loc, size, xdata);
 3154     return 0;
 3155 
 3156 unwind:
 3157     MDC_STACK_UNWIND(readlink, frame, -1, ENOMEM, NULL, NULL, NULL);
 3158     return 0;
 3159 }
 3160 
 3161 int32_t
 3162 mdc_fsyncdir_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 3163                  int32_t op_ret, int32_t op_errno, dict_t *xdata)
 3164 {
 3165     mdc_local_t *local = NULL;
 3166 
 3167     local = frame->local;
 3168     if (!local)
 3169         goto out;
 3170 
 3171     if (op_ret == 0)
 3172         goto out;
 3173 
 3174     if ((op_errno == ESTALE) || (op_errno == ENOENT))
 3175         mdc_inode_iatt_invalidate(this, local->fd->inode);
 3176 
 3177 out:
 3178     MDC_STACK_UNWIND(fsyncdir, frame, op_ret, op_errno, xdata);
 3179     return 0;
 3180 }
 3181 
 3182 int32_t
 3183 mdc_fsyncdir(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t flags,
 3184              dict_t *xdata)
 3185 {
 3186     mdc_local_t *local = NULL;
 3187 
 3188     local = mdc_local_get(frame, fd->inode);
 3189     if (!local)
 3190         goto unwind;
 3191 
 3192     local->fd = __fd_ref(fd);
 3193 
 3194     STACK_WIND(frame, mdc_fsyncdir_cbk, FIRST_CHILD(this),
 3195                FIRST_CHILD(this)->fops->fsyncdir, fd, flags, xdata);
 3196     return 0;
 3197 
 3198 unwind:
 3199     MDC_STACK_UNWIND(fsyncdir, frame, -1, ENOMEM, NULL);
 3200     return 0;
 3201 }
 3202 
 3203 int32_t
 3204 mdc_access_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 3205                int32_t op_ret, int32_t op_errno, dict_t *xdata)
 3206 {
 3207     mdc_local_t *local = NULL;
 3208 
 3209     local = frame->local;
 3210     if (!local)
 3211         goto out;
 3212 
 3213     if (op_ret == 0)
 3214         goto out;
 3215 
 3216     if ((op_errno == ESTALE) || (op_errno == ENOENT))
 3217         mdc_inode_iatt_invalidate(this, local->loc.inode);
 3218 
 3219 out:
 3220     MDC_STACK_UNWIND(access, frame, op_ret, op_errno, xdata);
 3221     return 0;
 3222 }
 3223 
 3224 int32_t
 3225 mdc_access(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t mask,
 3226            dict_t *xdata)
 3227 {
 3228     mdc_local_t *local = NULL;
 3229 
 3230     local = mdc_local_get(frame, loc->inode);
 3231     if (!local)
 3232         goto unwind;
 3233 
 3234     loc_copy(&local->loc, loc);
 3235 
 3236     STACK_WIND(frame, mdc_access_cbk, FIRST_CHILD(this),
 3237                FIRST_CHILD(this)->fops->access, loc, mask, xdata);
 3238     return 0;
 3239 
 3240 unwind:
 3241     MDC_STACK_UNWIND(access, frame, -1, ENOMEM, NULL);
 3242     return 0;
 3243 }
 3244 
 3245 int
 3246 mdc_priv_dump(xlator_t *this)
 3247 {
 3248     struct mdc_conf *conf = NULL;
 3249     char key_prefix[GF_DUMP_MAX_BUF_LEN];
 3250 
 3251     conf = this->private;
 3252 
 3253     snprintf(key_prefix, GF_DUMP_MAX_BUF_LEN, "%s.%s", this->type, this->name);
 3254     gf_proc_dump_add_section("%s", key_prefix);
 3255 
 3256     gf_proc_dump_write("stat_hit_count", "%" PRId64,
 3257                        GF_ATOMIC_GET(conf->mdc_counter.stat_hit));
 3258     gf_proc_dump_write("stat_miss_count", "%" PRId64,
 3259                        GF_ATOMIC_GET(conf->mdc_counter.stat_miss));
 3260     gf_proc_dump_write("xattr_hit_count", "%" PRId64,
 3261                        GF_ATOMIC_GET(conf->mdc_counter.xattr_hit));
 3262     gf_proc_dump_write("xattr_miss_count", "%" PRId64,
 3263                        GF_ATOMIC_GET(conf->mdc_counter.xattr_miss));
 3264     gf_proc_dump_write("nameless_lookup_count", "%" PRId64,
 3265                        GF_ATOMIC_GET(conf->mdc_counter.nameless_lookup));
 3266     gf_proc_dump_write("negative_lookup_count", "%" PRId64,
 3267                        GF_ATOMIC_GET(conf->mdc_counter.negative_lookup));
 3268     gf_proc_dump_write("stat_invalidations_received", "%" PRId64,
 3269                        GF_ATOMIC_GET(conf->mdc_counter.stat_invals));
 3270     gf_proc_dump_write("xattr_invalidations_received", "%" PRId64,
 3271                        GF_ATOMIC_GET(conf->mdc_counter.xattr_invals));
 3272 
 3273     return 0;
 3274 }
 3275 
 3276 static int32_t
 3277 mdc_dump_metrics(xlator_t *this, int fd)
 3278 {
 3279     struct mdc_conf *conf = NULL;
 3280 
 3281     conf = this->private;
 3282     if (!conf)
 3283         goto out;
 3284 
 3285     dprintf(fd, "%s.stat_cache_hit_count %" PRId64 "\n", this->name,
 3286             GF_ATOMIC_GET(conf->mdc_counter.stat_hit));
 3287     dprintf(fd, "%s.stat_cache_miss_count %" PRId64 "\n", this->name,
 3288             GF_ATOMIC_GET(conf->mdc_counter.stat_miss));
 3289     dprintf(fd, "%s.xattr_cache_hit_count %" PRId64 "\n", this->name,
 3290             GF_ATOMIC_GET(conf->mdc_counter.xattr_hit));
 3291     dprintf(fd, "%s.xattr_cache_miss_count %" PRId64 "\n", this->name,
 3292             GF_ATOMIC_GET(conf->mdc_counter.xattr_miss));
 3293     dprintf(fd, "%s.nameless_lookup_count %" PRId64 "\n", this->name,
 3294             GF_ATOMIC_GET(conf->mdc_counter.nameless_lookup));
 3295     dprintf(fd, "%s.negative_lookup_count %" PRId64 "\n", this->name,
 3296             GF_ATOMIC_GET(conf->mdc_counter.negative_lookup));
 3297     dprintf(fd, "%s.stat_cache_invalidations_received %" PRId64 "\n",
 3298             this->name, GF_ATOMIC_GET(conf->mdc_counter.stat_invals));
 3299     dprintf(fd, "%s.xattr_cache_invalidations_received %" PRId64 "\n",
 3300             this->name, GF_ATOMIC_GET(conf->mdc_counter.xattr_invals));
 3301 out:
 3302     return 0;
 3303 }
 3304 
 3305 int
 3306 mdc_forget(xlator_t *this, inode_t *inode)
 3307 {
 3308     mdc_inode_wipe(this, inode);
 3309 
 3310     return 0;
 3311 }
 3312 
 3313 int
 3314 is_strpfx(const char *str1, const char *str2)
 3315 {
 3316     /* is one of the string a prefix of the other? */
 3317     int i;
 3318 
 3319     for (i = 0; str1[i] == str2[i]; i++) {
 3320         if (!str1[i] || !str2[i])
 3321             break;
 3322     }
 3323 
 3324     return !(str1[i] && str2[i]);
 3325 }
 3326 
 3327 static int
 3328 mdc_key_unload_all(struct mdc_conf *conf)
 3329 {
 3330     conf->mdc_xattr_str = NULL;
 3331 
 3332     return 0;
 3333 }
 3334 
 3335 int
 3336 mdc_xattr_list_populate(struct mdc_conf *conf, char *tmp_str)
 3337 {
 3338     char *mdc_xattr_str = NULL;
 3339     size_t max_size = 0;
 3340     int ret = 0;
 3341 
 3342     max_size = SLEN(
 3343                    "security.capability,security.selinux,security."
 3344                    "ima," POSIX_ACL_ACCESS_XATTR "," POSIX_ACL_DEFAULT_XATTR
 3345                    "," GF_POSIX_ACL_ACCESS "," GF_POSIX_ACL_DEFAULT
 3346                    ","
 3347                    "user.swift.metadata,user.DOSATTRIB,user.DosStream.*"
 3348                    ",user.org.netatalk.Metadata,security.NTACL,"
 3349                    "user.org.netatalk.ResourceFork") +
 3350                strlen(tmp_str) + 5; /*Some buffer bytes*/
 3351 
 3352     mdc_xattr_str = GF_MALLOC(max_size, gf_common_mt_char);
 3353     GF_CHECK_ALLOC(mdc_xattr_str, ret, out);
 3354     mdc_xattr_str[0] = '\0';
 3355 
 3356     if (conf->cache_capability)
 3357         strcat(mdc_xattr_str, "security.capability,");
 3358 
 3359     if (conf->cache_selinux)
 3360         strcat(mdc_xattr_str, "security.selinux,");
 3361 
 3362     if (conf->cache_ima)
 3363         strcat(mdc_xattr_str, "security.ima,");
 3364 
 3365     if (conf->cache_posix_acl)
 3366         strcat(mdc_xattr_str,
 3367                POSIX_ACL_ACCESS_XATTR "," POSIX_ACL_DEFAULT_XATTR ",");
 3368 
 3369     if (conf->cache_glusterfs_acl)
 3370         strcat(mdc_xattr_str, GF_POSIX_ACL_ACCESS "," GF_POSIX_ACL_DEFAULT ",");
 3371 
 3372     if (conf->cache_swift_metadata)
 3373         strcat(mdc_xattr_str, "user.swift.metadata,");
 3374 
 3375     if (conf->cache_samba_metadata)
 3376         strcat(mdc_xattr_str,
 3377                "user.DOSATTRIB,user.DosStream.*,"
 3378                "user.org.netatalk.Metadata,user.org.netatalk."
 3379                "ResourceFork,security.NTACL,");
 3380 
 3381     strcat(mdc_xattr_str, tmp_str);
 3382 
 3383     LOCK(&conf->lock);
 3384     {
 3385         /* This is not freed, else is_mdc_key_satisfied, which is
 3386          * called by every fop has to take lock, and will lead to
 3387          * lock contention
 3388          */
 3389         conf->mdc_xattr_str = mdc_xattr_str;
 3390     }
 3391     UNLOCK(&conf->lock);
 3392 
 3393 out:
 3394     return ret;
 3395 }
 3396 
 3397 struct set {
 3398     inode_t *inode;
 3399     xlator_t *this;
 3400 };
 3401 
 3402 static int
 3403 mdc_inval_xatt(dict_t *d, char *k, data_t *v, void *tmp)
 3404 {
 3405     struct set *tmp1 = NULL;
 3406     int ret = 0;
 3407 
 3408     tmp1 = (struct set *)tmp;
 3409     ret = mdc_inode_xatt_unset(tmp1->this, tmp1->inode, k);
 3410     return ret;
 3411 }
 3412 
 3413 static int
 3414 mdc_invalidate(xlator_t *this, void *data)
 3415 {
 3416     struct gf_upcall *up_data = NULL;
 3417     struct gf_upcall_cache_invalidation *up_ci = NULL;
 3418     inode_t *inode = NULL;
 3419     int ret = 0;
 3420     struct set tmp = {
 3421         0,
 3422     };
 3423     inode_table_t *itable = NULL;
 3424     struct mdc_conf *conf = this->private;
 3425     uint64_t gen = 0;
 3426 
 3427     up_data = (struct gf_upcall *)data;
 3428 
 3429     if (up_data->event_type != GF_UPCALL_CACHE_INVALIDATION)
 3430         goto out;
 3431 
 3432     up_ci = (struct gf_upcall_cache_invalidation *)up_data->data;
 3433 
 3434     itable = ((xlator_t *)this->graph->top)->itable;
 3435     inode = inode_find(itable, up_data->gfid);
 3436     if (!inode) {
 3437         ret = -1;
 3438         goto out;
 3439     }
 3440 
 3441     if (up_ci->flags & UP_PARENT_DENTRY_FLAGS) {
 3442         mdc_update_gfid_stat(this, &up_ci->p_stat);
 3443         if (up_ci->flags & UP_RENAME_FLAGS)
 3444             mdc_update_gfid_stat(this, &up_ci->oldp_stat);
 3445     }
 3446 
 3447     if (up_ci->flags & UP_EXPLICIT_LOOKUP) {
 3448         mdc_inode_set_need_lookup(this, inode, _gf_true);
 3449         goto out;
 3450     }
 3451 
 3452     if (up_ci->flags &
 3453         (UP_NLINK | UP_RENAME_FLAGS | UP_FORGET | UP_INVAL_ATTR)) {
 3454         mdc_inode_iatt_invalidate(this, inode);
 3455         mdc_inode_xatt_invalidate(this, inode);
 3456         GF_ATOMIC_INC(conf->mdc_counter.stat_invals);
 3457         goto out;
 3458     }
 3459 
 3460     if (up_ci->flags & IATT_UPDATE_FLAGS) {
 3461         gen = mdc_inc_generation(this, inode);
 3462         ret = mdc_inode_iatt_set_validate(this, inode, NULL, &up_ci->stat,
 3463                                           _gf_false, gen);
 3464         /* one of the scenarios where ret < 0 is when this invalidate
 3465          * is older than the current stat, in that case do not
 3466          * update the xattrs as well
 3467          */
 3468         if (ret < 0)
 3469             goto out;
 3470         GF_ATOMIC_INC(conf->mdc_counter.stat_invals);
 3471     }
 3472 
 3473     if (up_ci->flags & UP_XATTR) {
 3474         if (up_ci->dict)
 3475             ret = mdc_inode_xatt_update(this, inode, up_ci->dict);
 3476         else
 3477             ret = mdc_inode_xatt_invalidate(this, inode);
 3478 
 3479         GF_ATOMIC_INC(conf->mdc_counter.xattr_invals);
 3480     } else if (up_ci->flags & UP_XATTR_RM) {
 3481         tmp.inode = inode;
 3482         tmp.this = this;
 3483         ret = dict_foreach(up_ci->dict, mdc_inval_xatt, &tmp);
 3484 
 3485         GF_ATOMIC_INC(conf->mdc_counter.xattr_invals);
 3486     }
 3487 
 3488 out:
 3489     if (inode)
 3490         inode_unref(inode);
 3491 
 3492     return ret;
 3493 }
 3494 
 3495 struct mdc_ipc {
 3496     xlator_t *this;
 3497     dict_t *xattr;
 3498 };
 3499 
 3500 static int
 3501 mdc_send_xattrs_cbk(int ret, call_frame_t *frame, void *data)
 3502 {
 3503     struct mdc_ipc *tmp = data;
 3504 
 3505     if (ret < 0) {
 3506         mdc_key_unload_all(THIS->private);
 3507         gf_msg("md-cache", GF_LOG_INFO, 0, MD_CACHE_MSG_NO_XATTR_CACHE,
 3508                "Disabled cache for all xattrs, as registering for "
 3509                "xattr cache invalidation failed");
 3510     }
 3511     STACK_DESTROY(frame->root);
 3512     dict_unref(tmp->xattr);
 3513     GF_FREE(tmp);
 3514 
 3515     return 0;
 3516 }
 3517 
 3518 static int
 3519 mdc_send_xattrs(void *data)
 3520 {
 3521     int ret = 0;
 3522     struct mdc_ipc *tmp = data;
 3523 
 3524     ret = syncop_ipc(FIRST_CHILD(tmp->this), GF_IPC_TARGET_UPCALL, tmp->xattr,
 3525                      NULL);
 3526     DECODE_SYNCOP_ERR(ret);
 3527     if (ret < 0) {
 3528         gf_msg(tmp->this->name, GF_LOG_WARNING, errno,
 3529                MD_CACHE_MSG_IPC_UPCALL_FAILED,
 3530                "Registering the list "
 3531                "of xattrs that needs invalidaton, with upcall, failed");
 3532     }
 3533 
 3534     return ret;
 3535 }
 3536 
 3537 static int
 3538 mdc_register_xattr_inval(xlator_t *this)
 3539 {
 3540     dict_t *xattr = NULL;
 3541     int ret = 0;
 3542     struct mdc_conf *conf = NULL;
 3543     call_frame_t *frame = NULL;
 3544     struct mdc_ipc *data = NULL;
 3545 
 3546     conf = this->private;
 3547 
 3548     LOCK(&conf->lock);
 3549     {
 3550         if (!conf->mdc_invalidation) {
 3551             UNLOCK(&conf->lock);
 3552             goto out;
 3553         }
 3554     }
 3555     UNLOCK(&conf->lock);
 3556 
 3557     xattr = dict_new();
 3558     if (!xattr) {
 3559         gf_msg(this->name, GF_LOG_WARNING, ENOMEM, MD_CACHE_MSG_NO_MEMORY,
 3560                "dict_new failed");
 3561         ret = -1;
 3562         goto out;
 3563     }
 3564 
 3565     if (!mdc_load_reqs(this, xattr)) {
 3566         gf_msg(this->name, GF_LOG_WARNING, ENOMEM, MD_CACHE_MSG_NO_MEMORY,
 3567                "failed to populate cache entries");
 3568         ret = -1;
 3569         goto out;
 3570     }
 3571 
 3572     frame = create_frame(this, this->ctx->pool);
 3573     if (!frame) {
 3574         gf_msg(this->name, GF_LOG_ERROR, ENOMEM, MD_CACHE_MSG_NO_MEMORY,
 3575                "failed to create the frame");
 3576         ret = -1;
 3577         goto out;
 3578     }
 3579 
 3580     data = GF_CALLOC(1, sizeof(struct mdc_ipc), gf_mdc_mt_mdc_ipc);
 3581     if (!data) {
 3582         gf_msg(this->name, GF_LOG_ERROR, ENOMEM, MD_CACHE_MSG_NO_MEMORY,
 3583                "failed to allocate memory");
 3584         ret = -1;
 3585         goto out;
 3586     }
 3587 
 3588     data->this = this;
 3589     data->xattr = xattr;
 3590     ret = synctask_new(this->ctx->env, mdc_send_xattrs, mdc_send_xattrs_cbk,
 3591                        frame, data);
 3592     if (ret < 0) {
 3593         gf_msg(this->name, GF_LOG_WARNING, errno,
 3594                MD_CACHE_MSG_IPC_UPCALL_FAILED,
 3595                "Registering the list "
 3596                "of xattrs that needs invalidaton, with upcall, failed");
 3597     }
 3598 
 3599 out:
 3600     if (ret < 0) {
 3601         mdc_key_unload_all(conf);
 3602         if (xattr)
 3603             dict_unref(xattr);
 3604         if (frame)
 3605             STACK_DESTROY(frame->root);
 3606         GF_FREE(data);
 3607         gf_msg(this->name, GF_LOG_INFO, 0, MD_CACHE_MSG_NO_XATTR_CACHE,
 3608                "Disabled cache for all xattrs, as registering for "
 3609                "xattr cache invalidation failed");
 3610     }
 3611 
 3612     return ret;
 3613 }
 3614 
 3615 int
 3616 mdc_reconfigure(xlator_t *this, dict_t *options)
 3617 {
 3618     struct mdc_conf *conf = NULL;
 3619     int timeout = 0;
 3620     char *tmp_str = NULL;
 3621 
 3622     conf = this->private;
 3623 
 3624     GF_OPTION_RECONF("md-cache-timeout", timeout, options, int32, out);
 3625 
 3626     GF_OPTION_RECONF("cache-selinux", conf->cache_selinux, options, bool, out);
 3627 
 3628     GF_OPTION_RECONF("cache-capability-xattrs", conf->cache_capability, options,
 3629                      bool, out);
 3630 
 3631     GF_OPTION_RECONF("cache-ima-xattrs", conf->cache_ima, options, bool, out);
 3632 
 3633     GF_OPTION_RECONF("cache-posix-acl", conf->cache_posix_acl, options, bool,
 3634                      out);
 3635 
 3636     GF_OPTION_RECONF("cache-glusterfs-acl", conf->cache_glusterfs_acl, options,
 3637                      bool, out);
 3638 
 3639     GF_OPTION_RECONF("cache-swift-metadata", conf->cache_swift_metadata,
 3640                      options, bool, out);
 3641 
 3642     GF_OPTION_RECONF("cache-samba-metadata", conf->cache_samba_metadata,
 3643                      options, bool, out);
 3644 
 3645     GF_OPTION_RECONF("force-readdirp", conf->force_readdirp, options, bool,
 3646                      out);
 3647 
 3648     GF_OPTION_RECONF("cache-invalidation", conf->mdc_invalidation, options,
 3649                      bool, out);
 3650 
 3651     GF_OPTION_RECONF("global-cache-invalidation", conf->global_invalidation,
 3652                      options, bool, out);
 3653 
 3654     GF_OPTION_RECONF("pass-through", this->pass_through, options, bool, out);
 3655 
 3656     GF_OPTION_RECONF("md-cache-statfs", conf->cache_statfs, options, bool, out);
 3657 
 3658     GF_OPTION_RECONF("xattr-cache-list", tmp_str, options, str, out);
 3659     mdc_xattr_list_populate(conf, tmp_str);
 3660 
 3661     /* If timeout is greater than 60s (default before the patch that added
 3662      * cache invalidation support was added) then, cache invalidation
 3663      * feature for md-cache needs to be enabled, if not set timeout to the
 3664      * previous max which is 60s
 3665      */
 3666     if ((timeout > 60) && (!conf->mdc_invalidation)) {
 3667         conf->timeout = 60;
 3668         goto out;
 3669     }
 3670     conf->timeout = timeout;
 3671 
 3672     (void)mdc_register_xattr_inval(this);
 3673 out:
 3674     return 0;
 3675 }
 3676 
 3677 int32_t
 3678 mdc_mem_acct_init(xlator_t *this)
 3679 {
 3680     int ret = -1;
 3681 
 3682     ret = xlator_mem_acct_init(this, gf_mdc_mt_end + 1);
 3683     return ret;
 3684 }
 3685 
 3686 int
 3687 mdc_init(xlator_t *this)
 3688 {
 3689     struct mdc_conf *conf = NULL;
 3690     int timeout = 0;
 3691     char *tmp_str = NULL;
 3692 
 3693     conf = GF_CALLOC(sizeof(*conf), 1, gf_mdc_mt_mdc_conf_t);
 3694     if (!conf) {
 3695         gf_msg(this->name, GF_LOG_ERROR, ENOMEM, MD_CACHE_MSG_NO_MEMORY,
 3696                "out of memory");
 3697         return -1;
 3698     }
 3699 
 3700     LOCK_INIT(&conf->lock);
 3701 
 3702     GF_OPTION_INIT("md-cache-timeout", timeout, int32, out);
 3703 
 3704     GF_OPTION_INIT("cache-selinux", conf->cache_selinux, bool, out);
 3705 
 3706     GF_OPTION_INIT("cache-capability-xattrs", conf->cache_capability, bool,
 3707                    out);
 3708 
 3709     GF_OPTION_INIT("cache-ima-xattrs", conf->cache_ima, bool, out);
 3710 
 3711     GF_OPTION_INIT("cache-posix-acl", conf->cache_posix_acl, bool, out);
 3712 
 3713     GF_OPTION_INIT("cache-glusterfs-acl", conf->cache_glusterfs_acl, bool, out);
 3714 
 3715     GF_OPTION_INIT("cache-swift-metadata", conf->cache_swift_metadata, bool,
 3716                    out);
 3717 
 3718     GF_OPTION_INIT("cache-samba-metadata", conf->cache_samba_metadata, bool,
 3719                    out);
 3720 
 3721     GF_OPTION_INIT("force-readdirp", conf->force_readdirp, bool, out);
 3722 
 3723     GF_OPTION_INIT("cache-invalidation", conf->mdc_invalidation, bool, out);
 3724 
 3725     GF_OPTION_INIT("global-cache-invalidation", conf->global_invalidation, bool,
 3726                    out);
 3727 
 3728     GF_OPTION_INIT("pass-through", this->pass_through, bool, out);
 3729 
 3730     pthread_mutex_init(&conf->statfs_cache.lock, NULL);
 3731     GF_OPTION_INIT("md-cache-statfs", conf->cache_statfs, bool, out);
 3732 
 3733     GF_OPTION_INIT("xattr-cache-list", tmp_str, str, out);
 3734     mdc_xattr_list_populate(conf, tmp_str);
 3735 
 3736     time(&conf->last_child_down);
 3737     /* initialize gf_atomic_t counters */
 3738     GF_ATOMIC_INIT(conf->mdc_counter.stat_hit, 0);
 3739     GF_ATOMIC_INIT(conf->mdc_counter.stat_miss, 0);
 3740     GF_ATOMIC_INIT(conf->mdc_counter.xattr_hit, 0);
 3741     GF_ATOMIC_INIT(conf->mdc_counter.xattr_miss, 0);
 3742     GF_ATOMIC_INIT(conf->mdc_counter.negative_lookup, 0);
 3743     GF_ATOMIC_INIT(conf->mdc_counter.nameless_lookup, 0);
 3744     GF_ATOMIC_INIT(conf->mdc_counter.stat_invals, 0);
 3745     GF_ATOMIC_INIT(conf->mdc_counter.xattr_invals, 0);
 3746     GF_ATOMIC_INIT(conf->mdc_counter.need_lookup, 0);
 3747     GF_ATOMIC_INIT(conf->generation, 0);
 3748 
 3749     /* If timeout is greater than 60s (default before the patch that added
 3750      * cache invalidation support was added) then, cache invalidation
 3751      * feature for md-cache needs to be enabled, if not set timeout to the
 3752      * previous max which is 60s
 3753      */
 3754     if ((timeout > 60) && (!conf->mdc_invalidation)) {
 3755         conf->timeout = 60;
 3756         goto out;
 3757     }
 3758     conf->timeout = timeout;
 3759 
 3760 out:
 3761     this->private = conf;
 3762 
 3763     return 0;
 3764 }
 3765 
 3766 void
 3767 mdc_update_child_down_time(xlator_t *this, time_t *now)
 3768 {
 3769     struct mdc_conf *conf = NULL;
 3770 
 3771     conf = this->private;
 3772 
 3773     LOCK(&conf->lock);
 3774     {
 3775         conf->last_child_down = *now;
 3776     }
 3777     UNLOCK(&conf->lock);
 3778 }
 3779 
 3780 int
 3781 mdc_notify(xlator_t *this, int event, void *data, ...)
 3782 {
 3783     int ret = 0;
 3784     struct mdc_conf *conf = NULL;
 3785     time_t now = 0;
 3786 
 3787     conf = this->private;
 3788     switch (event) {
 3789         case GF_EVENT_CHILD_DOWN:
 3790         case GF_EVENT_SOME_DESCENDENT_DOWN:
 3791             time(&now);
 3792             mdc_update_child_down_time(this, &now);
 3793             break;
 3794         case GF_EVENT_UPCALL:
 3795             if (conf->mdc_invalidation)
 3796                 ret = mdc_invalidate(this, data);
 3797             break;
 3798         case GF_EVENT_CHILD_UP:
 3799         case GF_EVENT_SOME_DESCENDENT_UP:
 3800             ret = mdc_register_xattr_inval(this);
 3801             break;
 3802         default:
 3803             break;
 3804     }
 3805 
 3806     if (default_notify(this, event, data) != 0)
 3807         ret = -1;
 3808 
 3809     return ret;
 3810 }
 3811 
 3812 void
 3813 mdc_fini(xlator_t *this)
 3814 {
 3815     GF_FREE(this->private);
 3816 }
 3817 
 3818 struct xlator_fops mdc_fops = {
 3819     .lookup = mdc_lookup,
 3820     .stat = mdc_stat,
 3821     .fstat = mdc_fstat,
 3822     .truncate = mdc_truncate,
 3823     .ftruncate = mdc_ftruncate,
 3824     .mknod = mdc_mknod,
 3825     .mkdir = mdc_mkdir,
 3826     .unlink = mdc_unlink,
 3827     .rmdir = mdc_rmdir,
 3828     .symlink = mdc_symlink,
 3829     .rename = mdc_rename,
 3830     .link = mdc_link,
 3831     .create = mdc_create,
 3832     .open = mdc_open,
 3833     .readv = mdc_readv,
 3834     .writev = mdc_writev,
 3835     .setattr = mdc_setattr,
 3836     .fsetattr = mdc_fsetattr,
 3837     .fsync = mdc_fsync,
 3838     .setxattr = mdc_setxattr,
 3839     .fsetxattr = mdc_fsetxattr,
 3840     .getxattr = mdc_getxattr,
 3841     .fgetxattr = mdc_fgetxattr,
 3842     .removexattr = mdc_removexattr,
 3843     .fremovexattr = mdc_fremovexattr,
 3844     .opendir = mdc_opendir,
 3845     .readdirp = mdc_readdirp,
 3846     .readdir = mdc_readdir,
 3847     .fallocate = mdc_fallocate,
 3848     .discard = mdc_discard,
 3849     .zerofill = mdc_zerofill,
 3850     .statfs = mdc_statfs,
 3851     .readlink = mdc_readlink,
 3852     .fsyncdir = mdc_fsyncdir,
 3853     .access = mdc_access,
 3854 };
 3855 
 3856 struct xlator_cbks mdc_cbks = {
 3857     .forget = mdc_forget,
 3858 };
 3859 
 3860 struct xlator_dumpops mdc_dumpops = {
 3861     .priv = mdc_priv_dump,
 3862 };
 3863 
 3864 struct volume_options mdc_options[] = {
 3865     {
 3866         .key = {"md-cache"},
 3867         .type = GF_OPTION_TYPE_BOOL,
 3868         .default_value = "off",
 3869         .description = "enable/disable md-cache",
 3870         .op_version = {GD_OP_VERSION_6_0},
 3871         .flags = OPT_FLAG_SETTABLE,
 3872     },
 3873     {
 3874         .key = {"cache-selinux"},
 3875         .type = GF_OPTION_TYPE_BOOL,
 3876         .default_value = "false",
 3877         .op_version = {2},
 3878         .flags = OPT_FLAG_SETTABLE | OPT_FLAG_CLIENT_OPT | OPT_FLAG_DOC,
 3879         .description = "Cache selinux xattr(security.selinux) on client side",
 3880     },
 3881     {
 3882         .key = {"cache-capability-xattrs"},
 3883         .type = GF_OPTION_TYPE_BOOL,
 3884         .default_value = "true",
 3885         .op_version = {GD_OP_VERSION_3_10_0},
 3886         .flags = OPT_FLAG_SETTABLE | OPT_FLAG_CLIENT_OPT | OPT_FLAG_DOC,
 3887         .description = "Cache capability xattr(security.capability) on "
 3888                        "client side",
 3889     },
 3890     {
 3891         .key = {"cache-ima-xattrs"},
 3892         .type = GF_OPTION_TYPE_BOOL,
 3893         .default_value = "true",
 3894         .op_version = {GD_OP_VERSION_3_10_0},
 3895         .flags = OPT_FLAG_SETTABLE | OPT_FLAG_CLIENT_OPT | OPT_FLAG_DOC,
 3896         .description = "Cache Linux integrity subsystem xattr(security.ima) "
 3897                        "on client side",
 3898     },
 3899     {
 3900         .key = {"cache-swift-metadata"},
 3901         .type = GF_OPTION_TYPE_BOOL,
 3902         .default_value = "true",
 3903         .op_version = {GD_OP_VERSION_3_7_10},
 3904         .flags = OPT_FLAG_SETTABLE | OPT_FLAG_CLIENT_OPT | OPT_FLAG_DOC,
 3905         .description = "Cache swift metadata (user.swift.metadata xattr)",
 3906     },
 3907     {
 3908         .key = {"cache-samba-metadata"},
 3909         .type = GF_OPTION_TYPE_BOOL,
 3910         .default_value = "false",
 3911         .op_version = {GD_OP_VERSION_3_9_0},
 3912         .flags = OPT_FLAG_SETTABLE | OPT_FLAG_CLIENT_OPT | OPT_FLAG_DOC,
 3913         .description = "Cache samba metadata (user.DOSATTRIB, security.NTACL,"
 3914                        " org.netatalk.Metadata, org.netatalk.ResourceFork, "
 3915                        "and user.DosStream. xattrs)",
 3916     },
 3917     {
 3918         .key = {"cache-posix-acl"},
 3919         .type = GF_OPTION_TYPE_BOOL,
 3920         .default_value = "false",
 3921         .op_version = {2},
 3922         .flags = OPT_FLAG_SETTABLE | OPT_FLAG_CLIENT_OPT | OPT_FLAG_DOC,
 3923         .description = "Cache posix ACL xattrs (system.posix_acl_access, "
 3924                        "system.posix_acl_default) on client side",
 3925     },
 3926     {
 3927         .key = {"cache-glusterfs-acl"},
 3928         .type = GF_OPTION_TYPE_BOOL,
 3929         .default_value = "false",
 3930         .op_version = {GD_OP_VERSION_6_0},
 3931         .flags = OPT_FLAG_SETTABLE | OPT_FLAG_CLIENT_OPT | OPT_FLAG_DOC,
 3932         .description = "Cache virtual glusterfs ACL xattrs "
 3933                        "(glusterfs.posix.acl, glusterfs.posix.default_acl) "
 3934                        "on client side",
 3935     },
 3936     {
 3937         .key = {"md-cache-timeout"},
 3938         .type = GF_OPTION_TYPE_INT,
 3939         .min = 0,
 3940         .max = 600,
 3941         .default_value = SITE_H_MD_CACHE_TIMEOUT,
 3942         .op_version = {2},
 3943         .flags = OPT_FLAG_SETTABLE | OPT_FLAG_CLIENT_OPT | OPT_FLAG_DOC,
 3944         .description = "Time period after which cache has to be refreshed",
 3945     },
 3946     {
 3947         .key = {"force-readdirp"},
 3948         .type = GF_OPTION_TYPE_BOOL,
 3949         .default_value = "true",
 3950         .op_version = {2},
 3951         .flags = OPT_FLAG_SETTABLE | OPT_FLAG_CLIENT_OPT | OPT_FLAG_DOC,
 3952         .description = "Convert all readdir requests to readdirplus to "
 3953                        "collect stat info on each entry.",
 3954     },
 3955     {
 3956         .key = {"cache-invalidation"},
 3957         .type = GF_OPTION_TYPE_BOOL,
 3958         .default_value = "false",
 3959         .op_version = {GD_OP_VERSION_3_9_0},
 3960         .flags = OPT_FLAG_SETTABLE | OPT_FLAG_CLIENT_OPT | OPT_FLAG_DOC,
 3961         .description = "When \"on\", invalidates/updates the metadata cache,"
 3962                        " on receiving the cache-invalidation notifications",
 3963     },
 3964     {
 3965         .key = {"global-cache-invalidation"},
 3966         .type = GF_OPTION_TYPE_BOOL,
 3967         .default_value = "true",
 3968         .op_version = {GD_OP_VERSION_6_0},
 3969         .flags = OPT_FLAG_SETTABLE | OPT_FLAG_CLIENT_OPT | OPT_FLAG_DOC,
 3970         .description =
 3971             "When \"on\", purges all read caches in kernel and glusterfs stack "
 3972             "whenever a stat change is detected. Stat changes can be detected "
 3973             "while processing responses to file operations (fop) or through "
 3974             "upcall notifications. Since purging caches can be an expensive "
 3975             "operation, it's advised to have this option \"on\" only when a "
 3976             "file "
 3977             "can be accessed from multiple different Glusterfs mounts and "
 3978             "caches across these different mounts are required to be coherent. "
 3979             "If a file is not accessed across different mounts "
 3980             "(simple example is having only one mount for a volume), its "
 3981             "advised to keep "
 3982             "this option \"off\" as all file modifications go through caches "
 3983             "keeping them "
 3984             "coherent. This option overrides value of "
 3985             "performance.cache-invalidation.",
 3986     },
 3987     {
 3988         .key = {"md-cache-statfs"},
 3989         .type = GF_OPTION_TYPE_BOOL,
 3990         .default_value = "off",
 3991         .op_version = {GD_OP_VERSION_4_0_0},
 3992         .flags = OPT_FLAG_SETTABLE | OPT_FLAG_CLIENT_OPT | OPT_FLAG_DOC,
 3993         .description = "Cache statfs information of filesystem on the client",
 3994     },
 3995     {
 3996         .key = {"xattr-cache-list"},
 3997         .type = GF_OPTION_TYPE_STR,
 3998         .default_value = "",
 3999         .op_version = {GD_OP_VERSION_4_0_0},
 4000         .flags = OPT_FLAG_SETTABLE | OPT_FLAG_CLIENT_OPT | OPT_FLAG_DOC,
 4001         .description = "A comma separated list of xattrs that shall be "
 4002                        "cached by md-cache. The only wildcard allowed is '*'",
 4003     },
 4004     {.key = {"pass-through"},
 4005      .type = GF_OPTION_TYPE_BOOL,
 4006      .default_value = "false",
 4007      .op_version = {GD_OP_VERSION_4_1_0},
 4008      .flags = OPT_FLAG_SETTABLE | OPT_FLAG_DOC | OPT_FLAG_CLIENT_OPT,
 4009      .tags = {"md-cache"},
 4010      .description = "Enable/Disable md cache translator"},
 4011     {.key = {NULL}},
 4012 };
 4013 
 4014 xlator_api_t xlator_api = {
 4015     .init = mdc_init,
 4016     .fini = mdc_fini,
 4017     .notify = mdc_notify,
 4018     .reconfigure = mdc_reconfigure,
 4019     .mem_acct_init = mdc_mem_acct_init,
 4020     .dump_metrics = mdc_dump_metrics,
 4021     .op_version = {1}, /* Present from the initial version */
 4022     .dumpops = &mdc_dumpops,
 4023     .fops = &mdc_fops,
 4024     .cbks = &mdc_cbks,
 4025     .options = mdc_options,
 4026     .identifier = "md-cache",
 4027     .category = GF_MAINTAINED,
 4028 };