21ab4e
From c4b8c629f738a8d9e020adccd70a4893c9e42fb8 Mon Sep 17 00:00:00 2001
21ab4e
From: Poornima G <pgurusid@redhat.com>
21ab4e
Date: Wed, 12 Apr 2017 15:24:14 +0530
21ab4e
Subject: [PATCH 392/393] Implement negative lookup cache
21ab4e
21ab4e
Before creating any file negative lookups(1 in Fuse, 4 in SMB etc.)
21ab4e
are sent to verify if the file already exists. By serving these
21ab4e
lookups from the cache when possible, increases the create
21ab4e
performance by multiple folds in SMB access and some percentage
21ab4e
in Fuse/NFS access.
21ab4e
21ab4e
Feature page: https://review.gluster.org/#/c/16436
21ab4e
21ab4e
>Signed-off-by: Poornima G <pgurusid@redhat.com>
21ab4e
>Reviewed-on: https://review.gluster.org/16952
21ab4e
>Reviewed-by: Pranith Kumar Karampuri <pkarampu@redhat.com>
21ab4e
>Tested-by: Pranith Kumar Karampuri <pkarampu@redhat.com>
21ab4e
>Smoke: Gluster Build System <jenkins@build.gluster.org>
21ab4e
>NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org>
21ab4e
>CentOS-regression: Gluster Build System <jenkins@build.gluster.org>
21ab4e
21ab4e
Updates #82
21ab4e
Change-Id: Ib1c0e7ac7a386f943d84f6398c27f9a03665b2a4
21ab4e
BUG: 1427099
21ab4e
Signed-off-by: Poornima G <pgurusid@redhat.com>
21ab4e
Reviewed-on: https://code.engineering.redhat.com/gerrit/103884
21ab4e
Reviewed-by: Milind Changire <mchangir@redhat.com>
21ab4e
Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
21ab4e
---
21ab4e
 configure.ac                                       |    2 +
21ab4e
 glusterfs.spec.in                                  |    1 +
21ab4e
 libglusterfs/src/glfs-message-id.h                 |    4 +
21ab4e
 libglusterfs/src/globals.h                         |    4 +-
21ab4e
 tests/basic/nl-cache.t                             |   64 ++
21ab4e
 xlators/mgmt/glusterd/src/glusterd-volume-set.c    |   31 +
21ab4e
 xlators/performance/Makefile.am                    |    2 +-
21ab4e
 xlators/performance/nl-cache/Makefile.am           |    3 +
21ab4e
 xlators/performance/nl-cache/src/Makefile.am       |   12 +
21ab4e
 xlators/performance/nl-cache/src/nl-cache-helper.c | 1142 ++++++++++++++++++++
21ab4e
 .../performance/nl-cache/src/nl-cache-mem-types.h  |   29 +
21ab4e
 .../performance/nl-cache/src/nl-cache-messages.h   |   34 +
21ab4e
 xlators/performance/nl-cache/src/nl-cache.c        |  775 +++++++++++++
21ab4e
 xlators/performance/nl-cache/src/nl-cache.h        |  173 +++
21ab4e
 14 files changed, 2274 insertions(+), 2 deletions(-)
21ab4e
 create mode 100755 tests/basic/nl-cache.t
21ab4e
 create mode 100644 xlators/performance/nl-cache/Makefile.am
21ab4e
 create mode 100644 xlators/performance/nl-cache/src/Makefile.am
21ab4e
 create mode 100644 xlators/performance/nl-cache/src/nl-cache-helper.c
21ab4e
 create mode 100644 xlators/performance/nl-cache/src/nl-cache-mem-types.h
21ab4e
 create mode 100644 xlators/performance/nl-cache/src/nl-cache-messages.h
21ab4e
 create mode 100644 xlators/performance/nl-cache/src/nl-cache.c
21ab4e
 create mode 100644 xlators/performance/nl-cache/src/nl-cache.h
21ab4e
21ab4e
diff --git a/configure.ac b/configure.ac
21ab4e
index 2c25be6..b5357dc 100644
21ab4e
--- a/configure.ac
21ab4e
+++ b/configure.ac
21ab4e
@@ -101,6 +101,8 @@ AC_CONFIG_FILES([Makefile
21ab4e
                 xlators/performance/md-cache/src/Makefile
21ab4e
                 xlators/performance/decompounder/Makefile
21ab4e
                 xlators/performance/decompounder/src/Makefile
21ab4e
+                xlators/performance/nl-cache/Makefile
21ab4e
+                xlators/performance/nl-cache/src/Makefile
21ab4e
                 xlators/debug/Makefile
21ab4e
                 xlators/debug/trace/Makefile
21ab4e
                 xlators/debug/trace/src/Makefile
21ab4e
diff --git a/glusterfs.spec.in b/glusterfs.spec.in
21ab4e
index c313d2f..da334d5 100644
21ab4e
--- a/glusterfs.spec.in
21ab4e
+++ b/glusterfs.spec.in
21ab4e
@@ -1128,6 +1128,7 @@ exit 0
21ab4e
 %{_libdir}/glusterfs/%{version}%{?prereltag}/xlator/performance/readdir-ahead.so
21ab4e
 %{_libdir}/glusterfs/%{version}%{?prereltag}/xlator/performance/stat-prefetch.so
21ab4e
 %{_libdir}/glusterfs/%{version}%{?prereltag}/xlator/performance/write-behind.so
21ab4e
+%{_libdir}/glusterfs/%{version}%{?prereltag}/xlator/performance/nl-cache.so
21ab4e
 %{_libdir}/glusterfs/%{version}%{?prereltag}/xlator/system/posix-acl.so
21ab4e
 %dir %{_localstatedir}/run/gluster
21ab4e
 %if 0%{?_tmpfilesdir:1}
21ab4e
diff --git a/libglusterfs/src/glfs-message-id.h b/libglusterfs/src/glfs-message-id.h
21ab4e
index de7c494..a511f0d 100644
21ab4e
--- a/libglusterfs/src/glfs-message-id.h
21ab4e
+++ b/libglusterfs/src/glfs-message-id.h
21ab4e
@@ -179,6 +179,10 @@ GLFS_MSGID_COMP_SYMLINK_CACHE_END
21ab4e
 #define GLFS_MSGID_COMP_LEASES_END         (GLFS_MSGID_COMP_LEASES +\
21ab4e
                                            GLFS_MSGID_SEGMENT)
21ab4e
 
21ab4e
+#define GLFS_MSGID_COMP_NLC                GLFS_MSGID_COMP_LEASES_END
21ab4e
+#define GLFS_MSGID_COMP_NLC_END            (GLFS_MSGID_COMP_NLC +\
21ab4e
+                                           GLFS_MSGID_SEGMENT)
21ab4e
+
21ab4e
 /* --- new segments for messages goes above this line --- */
21ab4e
 
21ab4e
 #endif /* !_GLFS_MESSAGE_ID_H_ */
21ab4e
diff --git a/libglusterfs/src/globals.h b/libglusterfs/src/globals.h
21ab4e
index 5d57a42..a1ec8f0 100644
21ab4e
--- a/libglusterfs/src/globals.h
21ab4e
+++ b/libglusterfs/src/globals.h
21ab4e
@@ -43,7 +43,7 @@
21ab4e
  */
21ab4e
 #define GD_OP_VERSION_MIN  1 /* MIN is the fresh start op-version, mostly
21ab4e
                                 should not change */
21ab4e
-#define GD_OP_VERSION_MAX  GD_OP_VERSION_3_10_1 /* MAX VERSION is the maximum
21ab4e
+#define GD_OP_VERSION_MAX  GD_OP_VERSION_3_11_0 /* MAX VERSION is the maximum
21ab4e
                                                   count in VME table, should
21ab4e
                                                   keep changing with
21ab4e
                                                   introduction of newer
21ab4e
@@ -89,6 +89,8 @@
21ab4e
 
21ab4e
 #define GD_OP_VERSION_3_10_1   31001 /* Op-version for GlusterFS 3.10.1 */
21ab4e
 
21ab4e
+#define GD_OP_VERSION_3_11_0   31100 /* Op-version for GlusterFS 3.11.0 */
21ab4e
+
21ab4e
 #include "xlator.h"
21ab4e
 
21ab4e
 /* THIS */
21ab4e
diff --git a/tests/basic/nl-cache.t b/tests/basic/nl-cache.t
21ab4e
new file mode 100755
21ab4e
index 0000000..ddd4e25
21ab4e
--- /dev/null
21ab4e
+++ b/tests/basic/nl-cache.t
21ab4e
@@ -0,0 +1,64 @@
21ab4e
+#!/bin/bash
21ab4e
+
21ab4e
+. $(dirname $0)/../include.rc
21ab4e
+. $(dirname $0)/../volume.rc
21ab4e
+
21ab4e
+cleanup;
21ab4e
+
21ab4e
+TEST glusterd
21ab4e
+
21ab4e
+TEST $CLI volume create $V0 $H0:$B0/${V0}{0..4}
21ab4e
+EXPECT 'Created' volinfo_field $V0 'Status'
21ab4e
+
21ab4e
+TEST $CLI volume set $V0 performance.nl-cache on
21ab4e
+TEST $CLI volume set $V0 features.cache-invalidation on
21ab4e
+TEST $CLI volume set $V0 features.cache-invalidation-timeout 600
21ab4e
+
21ab4e
+TEST $CLI volume start $V0;
21ab4e
+EXPECT 'Started' volinfo_field $V0 'Status';
21ab4e
+
21ab4e
+TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0
21ab4e
+TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M1
21ab4e
+
21ab4e
+TEST ! ls $M0/file2
21ab4e
+TEST touch $M0/file1
21ab4e
+TEST ! ls $M0/file2
21ab4e
+TEST touch $M0/file2
21ab4e
+TEST ls $M0/file2
21ab4e
+TEST rm $M0/file2
21ab4e
+TEST rm $M0/file1
21ab4e
+
21ab4e
+TEST mkdir $M0/dir1
21ab4e
+TEST ! ls -l $M0/dir1/file
21ab4e
+TEST mkdir $M0/dir1/dir2
21ab4e
+TEST ! ls -l $M0/dir1/file
21ab4e
+TEST ! ls -l $M0/dir1/dir2/file
21ab4e
+TEST ls -l $M0/dir1/dir2
21ab4e
+TEST rmdir $M0/dir1/dir2
21ab4e
+TEST rmdir $M0/dir1
21ab4e
+
21ab4e
+TEST ! ls -l $M0/file2
21ab4e
+TEST touch $M1/file2
21ab4e
+TEST ls -l $M0/file2
21ab4e
+TEST rm $M1/file2
21ab4e
+
21ab4e
+TEST ! ls -l $M0/dir1
21ab4e
+TEST mkdir $M1/dir1
21ab4e
+TEST ls -l $M0/dir1
21ab4e
+TEST ! ls -l $M0/dir1/file1
21ab4e
+TEST mkdir $M1/dir1/dir2
21ab4e
+TEST ! ls -l $M0/dir1/file1
21ab4e
+TEST ls -l $M0/dir1/dir2
21ab4e
+TEST ! ls -l $M1/dir1/file1
21ab4e
+
21ab4e
+TEST touch $M0/dir1/file
21ab4e
+TEST ln $M0/dir1/file $M0/dir1/file_link
21ab4e
+TEST ls -l $M1/dir1/file
21ab4e
+TEST ls -l $M1/dir1/file_link
21ab4e
+TEST rm $M0/dir1/file
21ab4e
+TEST rm $M0/dir1/file_link
21ab4e
+TEST rmdir $M0/dir1/dir2
21ab4e
+TEST rmdir $M0/dir1
21ab4e
+
21ab4e
+cleanup;
21ab4e
+#G_TESTDEF_TEST_STATUS_NETBSD7=BAD_TEST,BUG=000000
21ab4e
diff --git a/xlators/mgmt/glusterd/src/glusterd-volume-set.c b/xlators/mgmt/glusterd/src/glusterd-volume-set.c
21ab4e
index bbb07b0..4ee27b4 100644
21ab4e
--- a/xlators/mgmt/glusterd/src/glusterd-volume-set.c
21ab4e
+++ b/xlators/mgmt/glusterd/src/glusterd-volume-set.c
21ab4e
@@ -1941,6 +1941,16 @@ struct volopt_map_entry glusterd_volopt_map[] = {
21ab4e
           .flags       = OPT_FLAG_CLIENT_OPT | OPT_FLAG_XLATOR_OPT
21ab4e
 
21ab4e
         },
21ab4e
+        { .key         = "performance.nl-cache",
21ab4e
+          .voltype     = "performance/nl-cache",
21ab4e
+          .option      = "!perf",
21ab4e
+          .value       = "off",
21ab4e
+          .op_version  = GD_OP_VERSION_3_11_0,
21ab4e
+          .description = "enable/disable negative entry caching translator in "
21ab4e
+                         "the volume. Enabling this option improves performance"
21ab4e
+                         " of 'create file/directory' workload",
21ab4e
+          .flags       = OPT_FLAG_CLIENT_OPT | OPT_FLAG_XLATOR_OPT
21ab4e
+        },
21ab4e
         { .key         = "performance.stat-prefetch",
21ab4e
           .voltype     = "performance/md-cache",
21ab4e
           .option      = "!perf",
21ab4e
@@ -3104,6 +3114,27 @@ struct volopt_map_entry glusterd_volopt_map[] = {
21ab4e
           .flags       = OPT_FLAG_CLIENT_OPT,
21ab4e
           .op_version  = GD_OP_VERSION_3_9_1,
21ab4e
         },
21ab4e
+        { .key         = "performance.nl-cache-positive-entry",
21ab4e
+          .voltype     = "performance/nl-cache",
21ab4e
+          .value       = "on",
21ab4e
+          .type        = DOC,
21ab4e
+          .flags       = OPT_FLAG_CLIENT_OPT,
21ab4e
+          .op_version  = GD_OP_VERSION_3_11_0,
21ab4e
+          .description = "enable/disable storing of entries that were lookedup"
21ab4e
+                         " and found to be present in the volume, thus lookup"
21ab4e
+                         " on non existant file is served from the cache",
21ab4e
+        },
21ab4e
+        { .key         = "performance.nl-cache-limit",
21ab4e
+          .voltype     = "performance/nl-cache",
21ab4e
+          .value       = "10MB",
21ab4e
+          .flags       = OPT_FLAG_CLIENT_OPT,
21ab4e
+          .op_version  = GD_OP_VERSION_3_11_0,
21ab4e
+        },
21ab4e
+        { .key         = "performance.nl-cache-timeout",
21ab4e
+          .voltype     = "performance/nl-cache",
21ab4e
+          .flags       = OPT_FLAG_CLIENT_OPT,
21ab4e
+          .op_version  = GD_OP_VERSION_3_11_0,
21ab4e
+        },
21ab4e
         { .key        = "disperse.optimistic-change-log",
21ab4e
           .voltype    = "cluster/disperse",
21ab4e
           .type       = NO_DOC,
21ab4e
diff --git a/xlators/performance/Makefile.am b/xlators/performance/Makefile.am
21ab4e
index eb4e32c..e162734 100644
21ab4e
--- a/xlators/performance/Makefile.am
21ab4e
+++ b/xlators/performance/Makefile.am
21ab4e
@@ -1,3 +1,3 @@
21ab4e
-SUBDIRS = write-behind read-ahead readdir-ahead io-threads io-cache symlink-cache quick-read md-cache open-behind decompounder
21ab4e
+SUBDIRS = write-behind read-ahead readdir-ahead io-threads io-cache symlink-cache quick-read md-cache open-behind decompounder nl-cache
21ab4e
 
21ab4e
 CLEANFILES = 
21ab4e
diff --git a/xlators/performance/nl-cache/Makefile.am b/xlators/performance/nl-cache/Makefile.am
21ab4e
new file mode 100644
21ab4e
index 0000000..a985f42
21ab4e
--- /dev/null
21ab4e
+++ b/xlators/performance/nl-cache/Makefile.am
21ab4e
@@ -0,0 +1,3 @@
21ab4e
+SUBDIRS = src
21ab4e
+
21ab4e
+CLEANFILES =
21ab4e
diff --git a/xlators/performance/nl-cache/src/Makefile.am b/xlators/performance/nl-cache/src/Makefile.am
21ab4e
new file mode 100644
21ab4e
index 0000000..f45e8be
21ab4e
--- /dev/null
21ab4e
+++ b/xlators/performance/nl-cache/src/Makefile.am
21ab4e
@@ -0,0 +1,12 @@
21ab4e
+xlator_LTLIBRARIES = nl-cache.la
21ab4e
+xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/performance
21ab4e
+nl_cache_la_LDFLAGS = -module -avoid-version
21ab4e
+nl_cache_la_SOURCES = nl-cache.c nl-cache-helper.c
21ab4e
+nl_cache_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la
21ab4e
+noinst_HEADERS = nl-cache.h nl-cache-mem-types.h nl-cache-messages.h
21ab4e
+AM_CPPFLAGS = $(GF_CPPFLAGS) -I$(top_srcdir)/libglusterfs/src \
21ab4e
+        -I$(top_srcdir)/rpc/xdr/src -I$(top_builddir)/rpc/xdr/src \
21ab4e
+        -I$(CONTRIBDIR)/timer-wheel
21ab4e
+
21ab4e
+AM_CFLAGS = -Wall -fno-strict-aliasing $(GF_CFLAGS)
21ab4e
+CLEANFILES =
21ab4e
diff --git a/xlators/performance/nl-cache/src/nl-cache-helper.c b/xlators/performance/nl-cache/src/nl-cache-helper.c
21ab4e
new file mode 100644
21ab4e
index 0000000..34438ed
21ab4e
--- /dev/null
21ab4e
+++ b/xlators/performance/nl-cache/src/nl-cache-helper.c
21ab4e
@@ -0,0 +1,1142 @@
21ab4e
+/*
21ab4e
+ *   Copyright (c) 2017 Red Hat, Inc. <http://www.redhat.com>
21ab4e
+ *   This file is part of GlusterFS.
21ab4e
+ *
21ab4e
+ *   This file is licensed to you under your choice of the GNU Lesser
21ab4e
+ *   General Public License, version 3 or any later version (LGPLv3 or
21ab4e
+ *   later), or the GNU General Public License, version 2 (GPLv2), in all
21ab4e
+ *   cases as published by the Free Software Foundation.
21ab4e
+ */
21ab4e
+
21ab4e
+#include "nl-cache.h"
21ab4e
+#include "timer-wheel.h"
21ab4e
+#include "statedump.h"
21ab4e
+
21ab4e
+/* Caching guidelines:
21ab4e
+ * This xlator serves negative lookup(ENOENT lookups) from the cache,
21ab4e
+ * there by making create faster.
21ab4e
+ *   What is cached?
21ab4e
+ *      Negative lookup cache is stored for each directory, and has 2 entries:
21ab4e
+ *      - Negative entries: Populated only when lookup/stat returns ENOENT.
21ab4e
+ *        Fuse mostly sends only one lookup before create, hence negative entry
21ab4e
+ *        cache is almost useless. But for SMB access, multiple lookups/stats
21ab4e
+ *        are sent before creating the file. Hence the negative entry cache.
21ab4e
+ *        It can exist even when the positive entry cache is invalid. It also
21ab4e
+ *        has the entries that were deleted from this directory.
21ab4e
+ *        Freed on recieving upcall(with dentry change flag) or on expiring
21ab4e
+ *        timeout of the cache.
21ab4e
+ *
21ab4e
+ *      - Positive entries: Populated as a part of readdirp, and as a part of
21ab4e
+ *        mkdir followed by creates inside that directory. Lookups and other
21ab4e
+ *        fops do not populate the positive entry (as it can grow long and is
21ab4e
+ *        of no value add)
21ab4e
+ *        Freed on recieving upcall(with dentry change flag) or on expiring
21ab4e
+ *        timeout of the cache.
21ab4e
+ *
21ab4e
+ *   Data structures to store cache?
21ab4e
+ *      The cache of any directory is stored in the inode_ctx of the directory.
21ab4e
+ *      Negative entries are stored as list of strings.
21ab4e
+ *             Search - O(n)
21ab4e
+ *             Add    - O(1)
21ab4e
+ *             Delete - O(n) - as it has to be searched before deleting
21ab4e
+ *      Positive entries are stored as a list, each list node has a pointer
21ab4e
+ *          to the inode of the positive entry or the name of the entry.
21ab4e
+ *          Since the client side inode table already will have inodes for
21ab4e
+ *          positive entries, we just take a ref of that inode and store as
21ab4e
+ *          positive entry cache. In cases like hardlinks and readdirp where
21ab4e
+ *          inode is NULL, we store the names.
21ab4e
+ *          Name Search - O(n)
21ab4e
+ *          Inode Search - O(1) - Actually complexity of inode_find()
21ab4e
+ *          Name/inode Add - O(1)
21ab4e
+ *          Name Delete - O(n)
21ab4e
+ *          Inode Delete - O(1)
21ab4e
+ *
21ab4e
+ * Locking order:
21ab4e
+ *
21ab4e
+ * TODO:
21ab4e
+ * - Fill Positive entries on readdir/p, after which in lookup_cbk check if the
21ab4e
+ *   name is in PE and replace it with inode.
21ab4e
+ * - fini, PARENET_DOWN, disable caching
21ab4e
+ * - Virtual setxattr to dump the inode_ctx, to ease debugging
21ab4e
+ * - Handle dht_nuke xattr: clear all cache
21ab4e
+ * - Special handling for .meta and .trashcan?
21ab4e
+ */
21ab4e
+
21ab4e
+int __nlc_inode_ctx_timer_start (xlator_t *this, inode_t *inode, nlc_ctx_t *nlc_ctx);
21ab4e
+int __nlc_add_to_lru (xlator_t *this, inode_t *inode, nlc_ctx_t *nlc_ctx);
21ab4e
+void nlc_remove_from_lru (xlator_t *this, inode_t *inode);
21ab4e
+void __nlc_inode_ctx_timer_delete (xlator_t *this, nlc_ctx_t *nlc_ctx);
21ab4e
+gf_boolean_t __nlc_search_ne (nlc_ctx_t *nlc_ctx, const char *name);
21ab4e
+
21ab4e
+static int32_t
21ab4e
+nlc_get_cache_timeout (xlator_t *this)
21ab4e
+{
21ab4e
+        nlc_conf_t *conf = NULL;
21ab4e
+
21ab4e
+        conf = this->private;
21ab4e
+
21ab4e
+        /* Cache timeout is generally not meant to be changed often,
21ab4e
+         * once set, hence not within locks */
21ab4e
+        return conf->cache_timeout;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static gf_boolean_t
21ab4e
+__nlc_is_cache_valid (xlator_t *this, nlc_ctx_t *nlc_ctx)
21ab4e
+{
21ab4e
+        nlc_conf_t   *conf         = NULL;
21ab4e
+        time_t       last_val_time;
21ab4e
+        gf_boolean_t ret           = _gf_false;
21ab4e
+
21ab4e
+        GF_VALIDATE_OR_GOTO (this->name, nlc_ctx, out);
21ab4e
+
21ab4e
+        conf = this->private;
21ab4e
+
21ab4e
+        LOCK (&conf->lock);
21ab4e
+        {
21ab4e
+                last_val_time = conf->last_child_down;
21ab4e
+        }
21ab4e
+        UNLOCK (&conf->lock);
21ab4e
+
21ab4e
+        if (last_val_time <= nlc_ctx->cache_time)
21ab4e
+                ret = _gf_true;
21ab4e
+out:
21ab4e
+        return ret;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+void
21ab4e
+nlc_update_child_down_time (xlator_t *this, time_t *now)
21ab4e
+{
21ab4e
+        nlc_conf_t *conf = NULL;
21ab4e
+
21ab4e
+        conf = this->private;
21ab4e
+
21ab4e
+        LOCK (&conf->lock);
21ab4e
+        {
21ab4e
+                conf->last_child_down = *now;
21ab4e
+        }
21ab4e
+        UNLOCK (&conf->lock);
21ab4e
+
21ab4e
+        return;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+void
21ab4e
+nlc_disable_cache (xlator_t *this)
21ab4e
+{
21ab4e
+        nlc_conf_t *conf = NULL;
21ab4e
+
21ab4e
+        conf = this->private;
21ab4e
+
21ab4e
+        LOCK (&conf->lock);
21ab4e
+        {
21ab4e
+                conf->disable_cache = _gf_true;
21ab4e
+        }
21ab4e
+        UNLOCK (&conf->lock);
21ab4e
+
21ab4e
+        return;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static int
21ab4e
+__nlc_inode_ctx_get (xlator_t *this, inode_t *inode, nlc_ctx_t **nlc_ctx_p,
21ab4e
+                     nlc_pe_t **nlc_pe_p)
21ab4e
+{
21ab4e
+        int              ret = 0;
21ab4e
+        nlc_ctx_t        *nlc_ctx = NULL;
21ab4e
+        nlc_pe_t         *nlc_pe = NULL;
21ab4e
+        uint64_t         nlc_ctx_int = 0;
21ab4e
+        uint64_t         nlc_pe_int = 0;
21ab4e
+
21ab4e
+        ret = __inode_ctx_get2 (inode, this, &nlc_ctx_int, &nlc_pe_int);
21ab4e
+        if (ret == 0 && nlc_ctx_p) {
21ab4e
+                nlc_ctx = (void *) (long) (nlc_ctx_int);
21ab4e
+                *nlc_ctx_p = nlc_ctx;
21ab4e
+        }
21ab4e
+        if (ret == 0 && nlc_pe_p) {
21ab4e
+                nlc_pe = (void *) (long) (&nlc_pe_int);
21ab4e
+                *nlc_pe_p = nlc_pe;
21ab4e
+        }
21ab4e
+        return ret;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static int
21ab4e
+nlc_inode_ctx_set (xlator_t *this, inode_t *inode, nlc_ctx_t *nlc_ctx,
21ab4e
+                   nlc_pe_t *nlc_pe_p)
21ab4e
+{
21ab4e
+        int   ret = -1;
21ab4e
+
21ab4e
+        /* The caller may choose to set one of the ctxs, hence check
21ab4e
+         * if the ctx1/2 is non zero and then send the adress. If we
21ab4e
+         * blindly send the address of both the ctxs, it may reset the
21ab4e
+         * ctx the caller had sent NULL(intended as leave untouched) for.*/
21ab4e
+        LOCK(&inode->lock);
21ab4e
+        {
21ab4e
+                ret = __inode_ctx_set2 (inode, this,
21ab4e
+                                        nlc_ctx ? (uint64_t *) &nlc_ctx : 0,
21ab4e
+                                        nlc_pe_p ? (uint64_t *) &nlc_pe_p : 0);
21ab4e
+        }
21ab4e
+        UNLOCK(&inode->lock);
21ab4e
+        return ret;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static void
21ab4e
+nlc_inode_ctx_get (xlator_t *this, inode_t *inode, nlc_ctx_t **nlc_ctx_p,
21ab4e
+                   nlc_pe_t **nlc_pe_p)
21ab4e
+{
21ab4e
+        int ret = 0;
21ab4e
+
21ab4e
+        LOCK (&inode->lock);
21ab4e
+        {
21ab4e
+                ret = __nlc_inode_ctx_get (this, inode, nlc_ctx_p, nlc_pe_p);
21ab4e
+                if (ret < 0)
21ab4e
+                        gf_msg_debug (this->name, 0, "inode ctx get failed for "
21ab4e
+                                      "inode:%p", inode);
21ab4e
+        }
21ab4e
+        UNLOCK (&inode->lock);
21ab4e
+
21ab4e
+        return;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static nlc_ctx_t *
21ab4e
+nlc_inode_ctx_get_set (xlator_t *this, inode_t *inode, nlc_ctx_t **nlc_ctx_p,
21ab4e
+                       nlc_pe_t **nlc_pe_p)
21ab4e
+{
21ab4e
+        int                         ret    = 0;
21ab4e
+        nlc_ctx_t                  *nlc_ctx = NULL;
21ab4e
+        nlc_conf_t                 *conf   = NULL;
21ab4e
+
21ab4e
+        conf = this->private;
21ab4e
+
21ab4e
+        LOCK (&inode->lock);
21ab4e
+        {
21ab4e
+                ret = __nlc_inode_ctx_get (this, inode, &nlc_ctx, nlc_pe_p);
21ab4e
+                if (nlc_ctx)
21ab4e
+                        goto unlock;
21ab4e
+
21ab4e
+                nlc_ctx = GF_CALLOC (sizeof (*nlc_ctx), 1, gf_nlc_mt_nlc_ctx_t);
21ab4e
+                if (!nlc_ctx)
21ab4e
+                        goto unlock;
21ab4e
+
21ab4e
+                LOCK_INIT (&nlc_ctx->lock);
21ab4e
+                INIT_LIST_HEAD (&nlc_ctx->pe);
21ab4e
+                INIT_LIST_HEAD (&nlc_ctx->ne);
21ab4e
+
21ab4e
+                ret = __nlc_inode_ctx_timer_start (this, inode, nlc_ctx);
21ab4e
+                if (ret < 0)
21ab4e
+                        goto unlock;
21ab4e
+
21ab4e
+                ret = __nlc_add_to_lru (this, inode, nlc_ctx);
21ab4e
+                if (ret < 0) {
21ab4e
+                        __nlc_inode_ctx_timer_delete (this, nlc_ctx);
21ab4e
+                        goto unlock;
21ab4e
+                }
21ab4e
+
21ab4e
+                ret = __inode_ctx_set2 (inode, this, (uint64_t *) &nlc_ctx, NULL);
21ab4e
+                if (ret) {
21ab4e
+                        gf_msg (this->name, GF_LOG_ERROR, ENOMEM,
21ab4e
+                                NLC_MSG_NO_MEMORY, "inode ctx set failed");
21ab4e
+                        __nlc_inode_ctx_timer_delete (this, nlc_ctx);
21ab4e
+                        nlc_remove_from_lru (this, inode);
21ab4e
+                        goto unlock;
21ab4e
+                }
21ab4e
+
21ab4e
+                /*TODO: also sizeof (gf_tw_timer_list) + nlc_timer_data_t ?*/
21ab4e
+                nlc_ctx->cache_size = sizeof (*nlc_ctx);
21ab4e
+                GF_ATOMIC_ADD (conf->current_cache_size, nlc_ctx->cache_size);
21ab4e
+        }
21ab4e
+unlock:
21ab4e
+        UNLOCK (&inode->lock);
21ab4e
+
21ab4e
+        if (ret == 0 && nlc_ctx_p)
21ab4e
+                *nlc_ctx_p = nlc_ctx;
21ab4e
+
21ab4e
+        if (ret < 0 && nlc_ctx) {
21ab4e
+                LOCK_DESTROY (&nlc_ctx->lock);
21ab4e
+                GF_FREE (nlc_ctx);
21ab4e
+                nlc_ctx = NULL;
21ab4e
+                goto out;
21ab4e
+        }
21ab4e
+out:
21ab4e
+        return nlc_ctx;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+nlc_local_t *
21ab4e
+nlc_local_init (call_frame_t *frame, xlator_t *this, glusterfs_fop_t fop,
21ab4e
+                loc_t *loc, loc_t *loc2)
21ab4e
+{
21ab4e
+        nlc_local_t *local = NULL;
21ab4e
+
21ab4e
+        local = GF_CALLOC (sizeof (*local), 1, gf_nlc_mt_nlc_local_t);
21ab4e
+        if (!local)
21ab4e
+                goto out;
21ab4e
+
21ab4e
+        if (loc)
21ab4e
+                loc_copy (&local->loc, loc);
21ab4e
+        if (loc2)
21ab4e
+                loc_copy (&local->loc2, loc2);
21ab4e
+
21ab4e
+        local->fop = fop;
21ab4e
+        frame->local = local;
21ab4e
+out:
21ab4e
+        return local;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+void
21ab4e
+nlc_local_wipe (xlator_t *this, nlc_local_t *local)
21ab4e
+{
21ab4e
+        if (!local)
21ab4e
+                goto out;
21ab4e
+
21ab4e
+        loc_wipe (&local->loc);
21ab4e
+
21ab4e
+        loc_wipe (&local->loc2);
21ab4e
+
21ab4e
+        GF_FREE (local);
21ab4e
+out:
21ab4e
+        return;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static void
21ab4e
+__nlc_set_dir_state (nlc_ctx_t *nlc_ctx, uint64_t new_state)
21ab4e
+{
21ab4e
+        nlc_ctx->state |= new_state;
21ab4e
+
21ab4e
+        return;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+void
21ab4e
+nlc_set_dir_state (xlator_t *this, inode_t *inode, uint64_t state)
21ab4e
+{
21ab4e
+        nlc_ctx_t        *nlc_ctx = NULL;
21ab4e
+
21ab4e
+        if (inode->ia_type != IA_IFDIR) {
21ab4e
+                gf_msg_callingfn (this->name, GF_LOG_ERROR, EINVAL,
21ab4e
+                                  NLC_MSG_EINVAL, "inode is not of type dir");
21ab4e
+                goto out;
21ab4e
+        }
21ab4e
+
21ab4e
+        nlc_inode_ctx_get_set (this, inode, &nlc_ctx, NULL);
21ab4e
+        if (!nlc_ctx)
21ab4e
+                goto out;
21ab4e
+
21ab4e
+        LOCK (&nlc_ctx->lock);
21ab4e
+        {
21ab4e
+                __nlc_set_dir_state (nlc_ctx, state);
21ab4e
+        }
21ab4e
+        UNLOCK (&nlc_ctx->lock);
21ab4e
+out:
21ab4e
+        return;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static void
21ab4e
+nlc_cache_timeout_handler (struct gf_tw_timer_list *timer,
21ab4e
+                           void *data, unsigned long calltime)
21ab4e
+{
21ab4e
+        nlc_timer_data_t *tmp = data;
21ab4e
+
21ab4e
+        nlc_inode_clear_cache (tmp->this, tmp->inode, NLC_TIMER_EXPIRED);
21ab4e
+        inode_unref (tmp->inode);
21ab4e
+
21ab4e
+        GF_FREE (tmp);
21ab4e
+        GF_FREE (timer);
21ab4e
+
21ab4e
+        return;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+void
21ab4e
+__nlc_inode_ctx_timer_delete (xlator_t *this, nlc_ctx_t *nlc_ctx)
21ab4e
+{
21ab4e
+        nlc_conf_t                  *conf   = NULL;
21ab4e
+
21ab4e
+        conf = this->private;
21ab4e
+
21ab4e
+        gf_tw_del_timer (conf->timer_wheel, nlc_ctx->timer);
21ab4e
+
21ab4e
+        inode_unref (nlc_ctx->timer_data->inode);
21ab4e
+        GF_FREE (nlc_ctx->timer_data);
21ab4e
+
21ab4e
+        GF_FREE (nlc_ctx->timer);
21ab4e
+        nlc_ctx->timer = NULL;
21ab4e
+
21ab4e
+        return;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+int
21ab4e
+__nlc_inode_ctx_timer_start (xlator_t *this, inode_t *inode, nlc_ctx_t *nlc_ctx)
21ab4e
+{
21ab4e
+        struct gf_tw_timer_list    *timer  = NULL;
21ab4e
+        nlc_timer_data_t           *tmp    = NULL;
21ab4e
+        nlc_conf_t                 *conf   = NULL;
21ab4e
+        int                         ret    = -1;
21ab4e
+
21ab4e
+        conf = this->private;
21ab4e
+
21ab4e
+        /* We are taking inode_table->lock within inode->lock
21ab4e
+         * as the only other caller which takes inode->lock within
21ab4e
+         * inode_table->lock and cause deadlock is inode_table_destroy.
21ab4e
+         * Hopefully, there can be no fop when inode_table_destroy is
21ab4e
+         * being called. */
21ab4e
+        tmp = GF_CALLOC (1, sizeof (*tmp), gf_nlc_mt_nlc_timer_data_t);
21ab4e
+        if (!tmp)
21ab4e
+                goto out;
21ab4e
+        tmp->inode = inode_ref (inode);
21ab4e
+        tmp->this = this;
21ab4e
+
21ab4e
+        timer = GF_CALLOC (1, sizeof (*timer),
21ab4e
+                           gf_common_mt_tw_timer_list);
21ab4e
+        if (!timer)
21ab4e
+                goto out;
21ab4e
+
21ab4e
+        INIT_LIST_HEAD (&timer->entry);
21ab4e
+        timer->expires = nlc_get_cache_timeout (this);
21ab4e
+        timer->function = nlc_cache_timeout_handler;
21ab4e
+        timer->data = tmp;
21ab4e
+        nlc_ctx->timer = timer;
21ab4e
+        nlc_ctx->timer_data = tmp;
21ab4e
+        gf_tw_add_timer (conf->timer_wheel, timer);
21ab4e
+
21ab4e
+        time (&nlc_ctx->cache_time);
21ab4e
+        gf_msg_trace (this->name, 0, "Registering timer:%p, inode:%p, "
21ab4e
+                      "gfid:%s", timer, inode, uuid_utoa (inode->gfid));
21ab4e
+
21ab4e
+        ret = 0;
21ab4e
+
21ab4e
+out:
21ab4e
+        if (ret < 0) {
21ab4e
+                if (tmp && tmp->inode)
21ab4e
+                        inode_unref (tmp->inode);
21ab4e
+                GF_FREE (tmp);
21ab4e
+                GF_FREE (timer);
21ab4e
+        }
21ab4e
+
21ab4e
+        return ret;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+int
21ab4e
+__nlc_add_to_lru (xlator_t *this, inode_t *inode, nlc_ctx_t *nlc_ctx)
21ab4e
+{
21ab4e
+        nlc_lru_node_t              *lru_ino   = NULL;
21ab4e
+        uint64_t                    nlc_pe_int = 0;
21ab4e
+        nlc_conf_t                  *conf      = NULL;
21ab4e
+        int                          ret       = -1;
21ab4e
+
21ab4e
+        conf = this->private;
21ab4e
+
21ab4e
+        lru_ino = GF_CALLOC (1, sizeof (*lru_ino), gf_nlc_mt_nlc_lru_node);
21ab4e
+        if (!lru_ino)
21ab4e
+                goto out;
21ab4e
+
21ab4e
+        INIT_LIST_HEAD (&lru_ino->list);
21ab4e
+        lru_ino->inode = inode_ref (inode);
21ab4e
+        LOCK (&conf->lock);
21ab4e
+        {
21ab4e
+                list_add_tail (&lru_ino->list, &conf->lru);
21ab4e
+        }
21ab4e
+        UNLOCK (&conf->lock);
21ab4e
+
21ab4e
+        nlc_ctx->refd_inodes = 0;
21ab4e
+        ret = __inode_ctx_get2 (inode, this, NULL, &nlc_pe_int);
21ab4e
+        if (nlc_pe_int == 0)
21ab4e
+                GF_ATOMIC_ADD (conf->refd_inodes, 1);
21ab4e
+
21ab4e
+        ret = 0;
21ab4e
+
21ab4e
+out:
21ab4e
+        return ret;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+void
21ab4e
+nlc_remove_from_lru (xlator_t *this, inode_t *inode)
21ab4e
+{
21ab4e
+        nlc_lru_node_t              *lru_node   = NULL;
21ab4e
+        nlc_lru_node_t              *tmp        = NULL;
21ab4e
+        nlc_lru_node_t              *tmp1       = NULL;
21ab4e
+        nlc_conf_t                  *conf       = NULL;
21ab4e
+
21ab4e
+        conf = this->private;
21ab4e
+
21ab4e
+        LOCK (&conf->lock);
21ab4e
+        {
21ab4e
+                list_for_each_entry_safe (lru_node, tmp, &conf->lru, list) {
21ab4e
+                        if (inode == lru_node->inode) {
21ab4e
+                                list_del (&lru_node->list);
21ab4e
+                                tmp1 = lru_node;
21ab4e
+                                break;
21ab4e
+                        }
21ab4e
+                }
21ab4e
+        }
21ab4e
+        UNLOCK (&conf->lock);
21ab4e
+
21ab4e
+        if (tmp1) {
21ab4e
+                inode_unref (tmp1->inode);
21ab4e
+                GF_FREE (tmp1);
21ab4e
+        }
21ab4e
+
21ab4e
+        return;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+void
21ab4e
+nlc_lru_prune (xlator_t *this, inode_t *inode)
21ab4e
+{
21ab4e
+        nlc_lru_node_t              *lru_node   = NULL;
21ab4e
+        nlc_lru_node_t              *prune_node = NULL;
21ab4e
+        nlc_lru_node_t              *tmp        = NULL;
21ab4e
+        nlc_conf_t                  *conf       = NULL;
21ab4e
+
21ab4e
+        conf = this->private;
21ab4e
+
21ab4e
+        LOCK (&conf->lock);
21ab4e
+        {
21ab4e
+                if ((conf->current_cache_size.cnt < conf->cache_size) &&
21ab4e
+                    (conf->refd_inodes.cnt < conf->inode_limit))
21ab4e
+                        goto unlock;
21ab4e
+
21ab4e
+                list_for_each_entry_safe (lru_node, tmp, &conf->lru, list) {
21ab4e
+                        list_del (&lru_node->list);
21ab4e
+                        prune_node = lru_node;
21ab4e
+                        goto unlock;
21ab4e
+                }
21ab4e
+        }
21ab4e
+unlock:
21ab4e
+        UNLOCK (&conf->lock);
21ab4e
+
21ab4e
+        if (prune_node) {
21ab4e
+                nlc_inode_clear_cache (this, prune_node->inode, NLC_LRU_PRUNE);
21ab4e
+                inode_unref (prune_node->inode);
21ab4e
+                GF_FREE (prune_node);
21ab4e
+        }
21ab4e
+        return;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+void
21ab4e
+nlc_clear_all_cache (xlator_t *this)
21ab4e
+{
21ab4e
+        nlc_conf_t                  *conf       = NULL;
21ab4e
+        struct list_head            clear_list;
21ab4e
+        nlc_lru_node_t              *prune_node = NULL;
21ab4e
+        nlc_lru_node_t              *tmp        = NULL;
21ab4e
+
21ab4e
+        conf = this->private;
21ab4e
+
21ab4e
+        INIT_LIST_HEAD (&clear_list);
21ab4e
+
21ab4e
+        LOCK (&conf->lock);
21ab4e
+        {
21ab4e
+                list_replace_init (&conf->lru, &clear_list);
21ab4e
+        }
21ab4e
+        UNLOCK (&conf->lock);
21ab4e
+
21ab4e
+        list_for_each_entry_safe (prune_node, tmp, &clear_list, list) {
21ab4e
+                list_del (&prune_node->list);
21ab4e
+                nlc_inode_clear_cache (this, prune_node->inode, NLC_LRU_PRUNE);
21ab4e
+                inode_unref (prune_node->inode);
21ab4e
+                GF_FREE (prune_node);
21ab4e
+        }
21ab4e
+
21ab4e
+        return;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static void
21ab4e
+__nlc_free_pe (xlator_t *this, nlc_ctx_t *nlc_ctx, nlc_pe_t *pe)
21ab4e
+{
21ab4e
+        uint64_t          pe_int      = 0;
21ab4e
+        nlc_conf_t       *conf        = NULL;
21ab4e
+        uint64_t         *nlc_ctx_int = NULL;
21ab4e
+
21ab4e
+        conf = this->private;
21ab4e
+
21ab4e
+        if (pe->inode) {
21ab4e
+                inode_ctx_reset1 (pe->inode, this, &pe_int);
21ab4e
+                inode_ctx_get2 (pe->inode, this, nlc_ctx_int, NULL);
21ab4e
+                inode_unref (pe->inode);
21ab4e
+        }
21ab4e
+        list_del (&pe->list);
21ab4e
+
21ab4e
+        nlc_ctx->cache_size -= sizeof (*pe) + sizeof (pe->name);
21ab4e
+        GF_ATOMIC_SUB (conf->current_cache_size,
21ab4e
+                       (sizeof (*pe) + sizeof (pe->name)));
21ab4e
+
21ab4e
+        nlc_ctx->refd_inodes -= 1;
21ab4e
+        if (nlc_ctx_int == 0)
21ab4e
+                GF_ATOMIC_SUB (conf->refd_inodes, 1);
21ab4e
+
21ab4e
+        GF_FREE (pe->name);
21ab4e
+        GF_FREE (pe);
21ab4e
+
21ab4e
+        return;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static void
21ab4e
+__nlc_free_ne (xlator_t *this, nlc_ctx_t *nlc_ctx, nlc_ne_t *ne)
21ab4e
+{
21ab4e
+        nlc_conf_t                  *conf   = NULL;
21ab4e
+
21ab4e
+        conf = this->private;
21ab4e
+
21ab4e
+        list_del (&ne->list);
21ab4e
+        GF_FREE (ne->name);
21ab4e
+        GF_FREE (ne);
21ab4e
+
21ab4e
+        nlc_ctx->cache_size -= sizeof (*ne) + sizeof (ne->name);
21ab4e
+        GF_ATOMIC_SUB (conf->current_cache_size,
21ab4e
+                       (sizeof (*ne) + sizeof (ne->name)));
21ab4e
+
21ab4e
+        return;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+void
21ab4e
+nlc_inode_clear_cache (xlator_t *this, inode_t *inode, int reason)
21ab4e
+{
21ab4e
+        uint64_t         nlc_ctx_int = 0;
21ab4e
+        nlc_ctx_t        *nlc_ctx    = NULL;
21ab4e
+        nlc_pe_t         *pe         = NULL;
21ab4e
+        nlc_pe_t         *tmp        = NULL;
21ab4e
+        nlc_ne_t         *ne         = NULL;
21ab4e
+        nlc_ne_t         *tmp1       = NULL;
21ab4e
+        nlc_conf_t       *conf       = NULL;
21ab4e
+
21ab4e
+        conf = this->private;
21ab4e
+
21ab4e
+        inode_ctx_reset0 (inode, this, &nlc_ctx_int);
21ab4e
+        if (nlc_ctx_int == 0)
21ab4e
+                goto out;
21ab4e
+
21ab4e
+        nlc_ctx = (void *) (long) nlc_ctx_int;
21ab4e
+
21ab4e
+        if (reason != NLC_LRU_PRUNE)
21ab4e
+                nlc_remove_from_lru (this, inode);
21ab4e
+
21ab4e
+        LOCK (&nlc_ctx->lock);
21ab4e
+        {
21ab4e
+                if (reason != NLC_TIMER_EXPIRED)
21ab4e
+                        __nlc_inode_ctx_timer_delete (this, nlc_ctx);
21ab4e
+
21ab4e
+                if (IS_PE_VALID (nlc_ctx->state))
21ab4e
+                        list_for_each_entry_safe (pe, tmp, &nlc_ctx->pe, list) {
21ab4e
+                                __nlc_free_pe (this, nlc_ctx, pe);
21ab4e
+                        }
21ab4e
+
21ab4e
+                if (IS_NE_VALID (nlc_ctx->state))
21ab4e
+                        list_for_each_entry_safe (ne, tmp1, &nlc_ctx->ne, list) {
21ab4e
+                                __nlc_free_ne (this, nlc_ctx, ne);
21ab4e
+                        }
21ab4e
+        }
21ab4e
+        UNLOCK (&nlc_ctx->lock);
21ab4e
+
21ab4e
+        LOCK_DESTROY (&nlc_ctx->lock);
21ab4e
+
21ab4e
+        nlc_ctx->cache_size -= sizeof (*nlc_ctx);
21ab4e
+        GF_ASSERT (nlc_ctx->cache_size == 0);
21ab4e
+        GF_FREE (nlc_ctx);
21ab4e
+
21ab4e
+        GF_ATOMIC_SUB (conf->current_cache_size, sizeof (*nlc_ctx));
21ab4e
+
21ab4e
+out:
21ab4e
+        return;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static void
21ab4e
+__nlc_del_pe (xlator_t *this, nlc_ctx_t *nlc_ctx, inode_t *entry_ino,
21ab4e
+              const char *name, gf_boolean_t multilink)
21ab4e
+{
21ab4e
+        nlc_pe_t         *pe     = NULL;
21ab4e
+        nlc_pe_t         *tmp    = NULL;
21ab4e
+        gf_boolean_t     found  = _gf_false;
21ab4e
+        uint64_t         pe_int = 0;
21ab4e
+
21ab4e
+        if (!IS_PE_VALID (nlc_ctx->state))
21ab4e
+                goto out;
21ab4e
+
21ab4e
+        if (!entry_ino)
21ab4e
+                goto name_search;
21ab4e
+
21ab4e
+        /* If there are hardlinks first search names, followed by inodes */
21ab4e
+        if (multilink) {
21ab4e
+                list_for_each_entry_safe (pe, tmp, &nlc_ctx->pe, list) {
21ab4e
+                        if (pe->name && (strcmp (pe->name, name) == 0)) {
21ab4e
+                                found = _gf_true;
21ab4e
+                                goto out;
21ab4e
+                        }
21ab4e
+                }
21ab4e
+                inode_ctx_reset1 (entry_ino, this, &pe_int);
21ab4e
+                if (pe_int) {
21ab4e
+                        pe = (void *) (long) (pe_int);
21ab4e
+                        found = _gf_true;
21ab4e
+                        goto out;
21ab4e
+                }
21ab4e
+                goto out;
21ab4e
+        }
21ab4e
+
21ab4e
+        inode_ctx_reset1 (entry_ino, this, &pe_int);
21ab4e
+        if (pe_int) {
21ab4e
+                pe = (void *) (long) (pe_int);
21ab4e
+                found = _gf_true;
21ab4e
+                goto out;
21ab4e
+        }
21ab4e
+
21ab4e
+name_search:
21ab4e
+        list_for_each_entry_safe (pe, tmp, &nlc_ctx->pe, list) {
21ab4e
+                if (pe->name && (strcmp (pe->name, name) == 0)) {
21ab4e
+                        found = _gf_true;
21ab4e
+                        break;
21ab4e
+                        /* TODO: can there be duplicates? */
21ab4e
+                }
21ab4e
+        }
21ab4e
+
21ab4e
+out:
21ab4e
+        if (found)
21ab4e
+                __nlc_free_pe (this, nlc_ctx, pe);
21ab4e
+
21ab4e
+        return;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static void
21ab4e
+__nlc_del_ne (xlator_t *this, nlc_ctx_t *nlc_ctx, const char *name)
21ab4e
+{
21ab4e
+        nlc_ne_t  *ne     = NULL;
21ab4e
+        nlc_ne_t  *tmp    = NULL;
21ab4e
+
21ab4e
+        if (!IS_NE_VALID (nlc_ctx->state))
21ab4e
+                goto out;
21ab4e
+
21ab4e
+        list_for_each_entry_safe (ne, tmp, &nlc_ctx->ne, list) {
21ab4e
+                if (strcmp (ne->name, name) == 0) {
21ab4e
+                        __nlc_free_ne (this, nlc_ctx, ne);
21ab4e
+                        break;
21ab4e
+                }
21ab4e
+        }
21ab4e
+out:
21ab4e
+        return;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static void
21ab4e
+__nlc_add_pe (xlator_t *this, nlc_ctx_t *nlc_ctx, inode_t *entry_ino,
21ab4e
+              const char *name)
21ab4e
+{
21ab4e
+        nlc_pe_t             *pe         = NULL;
21ab4e
+        int                  ret         = -1;
21ab4e
+        nlc_conf_t           *conf       = NULL;
21ab4e
+        uint64_t             nlc_ctx_int = 0;
21ab4e
+
21ab4e
+        conf = this->private;
21ab4e
+
21ab4e
+        /* TODO: There can be no duplicate entries, as it is added only
21ab4e
+        during create. In case there arises duplicate entries, search PE
21ab4e
+        found = __nlc_search (entries, name, _gf_false);
21ab4e
+        can use bit vector to have simple search than sequential search */
21ab4e
+
21ab4e
+        pe = GF_CALLOC (sizeof (*pe), 1, gf_nlc_mt_nlc_pe_t);
21ab4e
+        if (!pe)
21ab4e
+                goto out;
21ab4e
+
21ab4e
+        if (entry_ino) {
21ab4e
+                pe->inode = inode_ref (entry_ino);
21ab4e
+                nlc_inode_ctx_set (this, entry_ino, NULL, pe);
21ab4e
+        } else if (name) {
21ab4e
+                pe->name = gf_strdup (name);
21ab4e
+                if (!pe->name)
21ab4e
+                        goto out;
21ab4e
+        }
21ab4e
+
21ab4e
+        list_add (&pe->list, &nlc_ctx->pe);
21ab4e
+
21ab4e
+        nlc_ctx->cache_size += sizeof (*pe) + sizeof (pe->name);
21ab4e
+        GF_ATOMIC_ADD (conf->current_cache_size,
21ab4e
+                       (sizeof (*pe) + sizeof (pe->name)));
21ab4e
+
21ab4e
+        nlc_ctx->refd_inodes += 1;
21ab4e
+        inode_ctx_get2 (entry_ino, this, &nlc_ctx_int, NULL);
21ab4e
+        if (nlc_ctx_int == 0)
21ab4e
+                GF_ATOMIC_ADD (conf->refd_inodes, 1);
21ab4e
+
21ab4e
+        ret = 0;
21ab4e
+out:
21ab4e
+        if (ret)
21ab4e
+                GF_FREE (pe);
21ab4e
+
21ab4e
+        return;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static void
21ab4e
+__nlc_add_ne (xlator_t *this, nlc_ctx_t *nlc_ctx, const char *name)
21ab4e
+{
21ab4e
+        nlc_ne_t                    *ne     = NULL;
21ab4e
+        int                         ret     = -1;
21ab4e
+        nlc_conf_t                  *conf   = NULL;
21ab4e
+
21ab4e
+        conf = this->private;
21ab4e
+
21ab4e
+        /* TODO: search ne before adding to get rid of duplicate entries
21ab4e
+        found = __nlc_search (entries, name, _gf_false);
21ab4e
+        can use bit vector to have faster search than sequential search */
21ab4e
+
21ab4e
+        ne = GF_CALLOC (sizeof (*ne), 1, gf_nlc_mt_nlc_ne_t);
21ab4e
+        if (!ne)
21ab4e
+                goto out;
21ab4e
+
21ab4e
+        ne->name = gf_strdup (name);
21ab4e
+        if (!ne->name)
21ab4e
+                goto out;
21ab4e
+
21ab4e
+        list_add (&ne->list, &nlc_ctx->ne);
21ab4e
+
21ab4e
+        nlc_ctx->cache_size += sizeof (*ne) + sizeof (ne->name);
21ab4e
+        GF_ATOMIC_ADD (conf->current_cache_size,
21ab4e
+                       (sizeof (*ne) + sizeof (ne->name)));
21ab4e
+        ret = 0;
21ab4e
+out:
21ab4e
+        if (ret)
21ab4e
+                GF_FREE (ne);
21ab4e
+
21ab4e
+        return;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+void
21ab4e
+nlc_dir_add_ne (xlator_t *this, inode_t *inode, const char *name)
21ab4e
+{
21ab4e
+        nlc_ctx_t        *nlc_ctx = NULL;
21ab4e
+
21ab4e
+        if (inode->ia_type != IA_IFDIR) {
21ab4e
+                gf_msg_callingfn (this->name, GF_LOG_ERROR, EINVAL,
21ab4e
+                                  NLC_MSG_EINVAL, "inode is not of type dir");
21ab4e
+                goto out;
21ab4e
+        }
21ab4e
+
21ab4e
+        nlc_inode_ctx_get_set (this, inode, &nlc_ctx, NULL);
21ab4e
+        if (!nlc_ctx)
21ab4e
+                goto out;
21ab4e
+
21ab4e
+        LOCK (&nlc_ctx->lock);
21ab4e
+        {
21ab4e
+                /* There is one possiblility where we need to search before
21ab4e
+                 * adding NE: when there are two parallel lookups on a non
21ab4e
+                 * existant file */
21ab4e
+                if (!__nlc_search_ne (nlc_ctx, name)) {
21ab4e
+                        __nlc_add_ne (this, nlc_ctx, name);
21ab4e
+                        __nlc_set_dir_state (nlc_ctx, NLC_NE_VALID);
21ab4e
+                }
21ab4e
+        }
21ab4e
+        UNLOCK (&nlc_ctx->lock);
21ab4e
+out:
21ab4e
+        return;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+void
21ab4e
+nlc_dir_remove_pe (xlator_t *this, inode_t *parent, inode_t *entry_ino,
21ab4e
+                   const char *name, gf_boolean_t multilink)
21ab4e
+{
21ab4e
+        nlc_ctx_t        *nlc_ctx = NULL;
21ab4e
+
21ab4e
+        if (parent->ia_type != IA_IFDIR) {
21ab4e
+                gf_msg_callingfn (this->name, GF_LOG_ERROR, EINVAL,
21ab4e
+                                  NLC_MSG_EINVAL, "inode is not of type dir");
21ab4e
+                goto out;
21ab4e
+        }
21ab4e
+
21ab4e
+        nlc_inode_ctx_get (this, parent, &nlc_ctx, NULL);
21ab4e
+        if (!nlc_ctx)
21ab4e
+                goto out;
21ab4e
+
21ab4e
+        LOCK (&nlc_ctx->lock);
21ab4e
+        {
21ab4e
+                __nlc_del_pe (this, nlc_ctx, entry_ino, name, multilink);
21ab4e
+                __nlc_add_ne (this, nlc_ctx, name);
21ab4e
+                __nlc_set_dir_state (nlc_ctx, NLC_NE_VALID);
21ab4e
+        }
21ab4e
+        UNLOCK (&nlc_ctx->lock);
21ab4e
+out:
21ab4e
+        return;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+void
21ab4e
+nlc_dir_add_pe (xlator_t *this, inode_t *inode, inode_t *entry_ino,
21ab4e
+                const char *name)
21ab4e
+{
21ab4e
+        nlc_ctx_t        *nlc_ctx = NULL;
21ab4e
+
21ab4e
+        if (inode->ia_type != IA_IFDIR) {
21ab4e
+                gf_msg_callingfn (this->name, GF_LOG_ERROR, EINVAL,
21ab4e
+                                  NLC_MSG_EINVAL, "inode is not of type dir");
21ab4e
+                goto out;
21ab4e
+        }
21ab4e
+
21ab4e
+        nlc_inode_ctx_get_set (this, inode, &nlc_ctx, NULL);
21ab4e
+        if (!nlc_ctx)
21ab4e
+                goto out;
21ab4e
+
21ab4e
+        LOCK (&nlc_ctx->lock);
21ab4e
+        {
21ab4e
+                __nlc_del_ne (this, nlc_ctx, name);
21ab4e
+                __nlc_add_pe (this, nlc_ctx, entry_ino, name);
21ab4e
+                if (!IS_PE_VALID (nlc_ctx->state))
21ab4e
+                        __nlc_set_dir_state (nlc_ctx, NLC_PE_PARTIAL);
21ab4e
+        }
21ab4e
+        UNLOCK (&nlc_ctx->lock);
21ab4e
+out:
21ab4e
+        return;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+gf_boolean_t
21ab4e
+__nlc_search_ne (nlc_ctx_t *nlc_ctx, const char *name)
21ab4e
+{
21ab4e
+        gf_boolean_t  found = _gf_false;
21ab4e
+        nlc_ne_t     *ne    = NULL;
21ab4e
+        nlc_ne_t     *tmp   = NULL;
21ab4e
+
21ab4e
+        if (!IS_NE_VALID (nlc_ctx->state))
21ab4e
+                goto out;
21ab4e
+
21ab4e
+        list_for_each_entry_safe (ne, tmp, &nlc_ctx->ne, list) {
21ab4e
+                if (strcmp (ne->name, name) == 0) {
21ab4e
+                        found = _gf_true;
21ab4e
+                        break;
21ab4e
+                }
21ab4e
+        }
21ab4e
+out:
21ab4e
+        return found;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static gf_boolean_t
21ab4e
+__nlc_search_pe (nlc_ctx_t *nlc_ctx, const char *name)
21ab4e
+{
21ab4e
+        gf_boolean_t   found = _gf_false;
21ab4e
+        nlc_pe_t      *pe    = NULL;
21ab4e
+        nlc_pe_t      *tmp   = NULL;
21ab4e
+
21ab4e
+        if (!IS_PE_VALID (nlc_ctx->state))
21ab4e
+                goto out;
21ab4e
+
21ab4e
+        list_for_each_entry_safe (pe, tmp, &nlc_ctx->pe, list) {
21ab4e
+               if (pe->name && (strcmp (pe->name, name) == 0)) {
21ab4e
+                        found = _gf_true;
21ab4e
+                        break;
21ab4e
+               }
21ab4e
+        }
21ab4e
+out:
21ab4e
+        return found;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static char *
21ab4e
+__nlc_get_pe (nlc_ctx_t *nlc_ctx, const char *name, gf_boolean_t case_insensitive)
21ab4e
+{
21ab4e
+        char          *found = NULL;
21ab4e
+        nlc_pe_t      *pe    = NULL;
21ab4e
+        nlc_pe_t      *tmp   = NULL;
21ab4e
+
21ab4e
+        if (!IS_PE_VALID (nlc_ctx->state))
21ab4e
+                goto out;
21ab4e
+
21ab4e
+        if (case_insensitive) {
21ab4e
+                list_for_each_entry_safe (pe, tmp, &nlc_ctx->pe, list) {
21ab4e
+                        if (pe->name &&
21ab4e
+                            (strcasecmp (pe->name, name) == 0)) {
21ab4e
+                                found = pe->name;
21ab4e
+                                break;
21ab4e
+                        }
21ab4e
+                }
21ab4e
+        } else {
21ab4e
+                list_for_each_entry_safe (pe, tmp, &nlc_ctx->pe, list) {
21ab4e
+                        if (pe->name &&
21ab4e
+                            (strcmp (pe->name, name) == 0)) {
21ab4e
+                                found = pe->name;
21ab4e
+                                break;
21ab4e
+                        }
21ab4e
+               }
21ab4e
+        }
21ab4e
+out:
21ab4e
+        return found;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+gf_boolean_t
21ab4e
+nlc_is_negative_lookup (xlator_t *this, loc_t *loc)
21ab4e
+{
21ab4e
+        nlc_ctx_t       *nlc_ctx   = NULL;
21ab4e
+        inode_t         *inode     = NULL;
21ab4e
+        gf_boolean_t     neg_entry = _gf_false;
21ab4e
+
21ab4e
+        inode = loc->parent;
21ab4e
+        GF_VALIDATE_OR_GOTO (this->name, inode, out);
21ab4e
+
21ab4e
+        if (inode->ia_type != IA_IFDIR) {
21ab4e
+                gf_msg_callingfn (this->name, GF_LOG_ERROR, EINVAL,
21ab4e
+                                  NLC_MSG_EINVAL, "inode is not of type dir");
21ab4e
+                goto out;
21ab4e
+        }
21ab4e
+
21ab4e
+        nlc_inode_ctx_get (this, inode, &nlc_ctx, NULL);
21ab4e
+        if (!nlc_ctx)
21ab4e
+                goto out;
21ab4e
+
21ab4e
+        LOCK (&nlc_ctx->lock);
21ab4e
+        {
21ab4e
+                if (!__nlc_is_cache_valid (this, nlc_ctx))
21ab4e
+                        goto unlock;
21ab4e
+
21ab4e
+                if (__nlc_search_ne (nlc_ctx, loc->name)) {
21ab4e
+                        neg_entry = _gf_true;
21ab4e
+                        goto unlock;
21ab4e
+                }
21ab4e
+                if ((nlc_ctx->state & NLC_PE_FULL) &&
21ab4e
+                    !__nlc_search_pe (nlc_ctx, loc->name)) {
21ab4e
+                        neg_entry = _gf_true;
21ab4e
+                        goto unlock;
21ab4e
+                }
21ab4e
+        }
21ab4e
+unlock:
21ab4e
+        UNLOCK (&nlc_ctx->lock);
21ab4e
+
21ab4e
+out:
21ab4e
+        return neg_entry;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+gf_boolean_t
21ab4e
+nlc_get_real_file_name (xlator_t *this, loc_t *loc, const char *fname,
21ab4e
+                        int32_t *op_ret, int32_t *op_errno, dict_t *dict)
21ab4e
+{
21ab4e
+        nlc_ctx_t        *nlc_ctx     = NULL;
21ab4e
+        inode_t         *inode      = NULL;
21ab4e
+        gf_boolean_t     hit        = _gf_false;
21ab4e
+        char            *found_file = NULL;
21ab4e
+        int              ret        = 0;
21ab4e
+
21ab4e
+        GF_VALIDATE_OR_GOTO (this->name, loc, out);
21ab4e
+        GF_VALIDATE_OR_GOTO (this->name, fname, out);
21ab4e
+        GF_VALIDATE_OR_GOTO (this->name, op_ret, out);
21ab4e
+        GF_VALIDATE_OR_GOTO (this->name, op_errno, out);
21ab4e
+        GF_VALIDATE_OR_GOTO (this->name, dict, out);
21ab4e
+
21ab4e
+        inode = loc->inode;
21ab4e
+        GF_VALIDATE_OR_GOTO (this->name, inode, out);
21ab4e
+
21ab4e
+        if (inode->ia_type != IA_IFDIR) {
21ab4e
+                gf_msg_callingfn (this->name, GF_LOG_ERROR, EINVAL,
21ab4e
+                                  NLC_MSG_EINVAL, "inode is not of type dir");
21ab4e
+                goto out;
21ab4e
+        }
21ab4e
+
21ab4e
+        nlc_inode_ctx_get (this, inode, &nlc_ctx, NULL);
21ab4e
+        if (!nlc_ctx)
21ab4e
+                goto out;
21ab4e
+
21ab4e
+        LOCK (&nlc_ctx->lock);
21ab4e
+        {
21ab4e
+                if (!__nlc_is_cache_valid (this, nlc_ctx))
21ab4e
+                        goto unlock;
21ab4e
+
21ab4e
+                found_file = __nlc_get_pe (nlc_ctx, fname, _gf_true);
21ab4e
+                if (found_file) {
21ab4e
+                        ret = dict_set_dynstr (dict, GF_XATTR_GET_REAL_FILENAME_KEY,
21ab4e
+                                               gf_strdup (found_file));
21ab4e
+                        if (ret < 0)
21ab4e
+                                goto unlock;
21ab4e
+                        *op_ret = strlen (found_file) + 1;
21ab4e
+                        hit = _gf_true;
21ab4e
+                        goto unlock;
21ab4e
+                }
21ab4e
+                if (!found_file && (nlc_ctx->state & NLC_PE_FULL)) {
21ab4e
+                        *op_ret = -1;
21ab4e
+                        *op_errno = ENOENT;
21ab4e
+                        hit = _gf_true;
21ab4e
+                        goto unlock;
21ab4e
+                }
21ab4e
+        }
21ab4e
+unlock:
21ab4e
+        UNLOCK (&nlc_ctx->lock);
21ab4e
+
21ab4e
+out:
21ab4e
+        return hit;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+void
21ab4e
+nlc_dump_inodectx (xlator_t *this, inode_t *inode)
21ab4e
+{
21ab4e
+        int32_t     ret                            = -1;
21ab4e
+        char       *path                           = NULL;
21ab4e
+        char       key_prefix[GF_DUMP_MAX_BUF_LEN] = {0, };
21ab4e
+        char       uuid_str[64]                    = {0,};
21ab4e
+        nlc_ctx_t   *nlc_ctx                         = NULL;
21ab4e
+        nlc_pe_t    *pe                             = NULL;
21ab4e
+        nlc_pe_t    *tmp                            = NULL;
21ab4e
+        nlc_ne_t    *ne                             = NULL;
21ab4e
+        nlc_ne_t    *tmp1                           = NULL;
21ab4e
+
21ab4e
+        nlc_inode_ctx_get (this, inode, &nlc_ctx, NULL);
21ab4e
+
21ab4e
+        if (!nlc_ctx)
21ab4e
+                goto out;
21ab4e
+
21ab4e
+        ret = TRY_LOCK (&nlc_ctx->lock);
21ab4e
+        if (!ret) {
21ab4e
+                gf_proc_dump_build_key (key_prefix,
21ab4e
+                                        "xlator.performance.nl-cache",
21ab4e
+                                        "nlc_inode");
21ab4e
+                gf_proc_dump_add_section (key_prefix);
21ab4e
+
21ab4e
+                __inode_path (inode, NULL, &path);
21ab4e
+                if (path != NULL) {
21ab4e
+                        gf_proc_dump_write ("path", "%s", path);
21ab4e
+                        GF_FREE (path);
21ab4e
+                }
21ab4e
+
21ab4e
+                uuid_utoa_r (inode->gfid, uuid_str);
21ab4e
+
21ab4e
+                gf_proc_dump_write ("inode", "%p", inode);
21ab4e
+                gf_proc_dump_write ("gfid", "%s", uuid_str);
21ab4e
+
21ab4e
+                gf_proc_dump_write ("state", "%"PRIu64, nlc_ctx->state);
21ab4e
+                gf_proc_dump_write ("timer", "%p", nlc_ctx->timer);
21ab4e
+                gf_proc_dump_write ("cache-time", "%lld", nlc_ctx->cache_time);
21ab4e
+
21ab4e
+                if (IS_PE_VALID (nlc_ctx->state))
21ab4e
+                        list_for_each_entry_safe (pe, tmp, &nlc_ctx->pe, list) {
21ab4e
+                                gf_proc_dump_write ("pe", "%p, %s", pe,
21ab4e
+                                                    pe->inode, pe->name);
21ab4e
+                        }
21ab4e
+
21ab4e
+                if (IS_NE_VALID (nlc_ctx->state))
21ab4e
+                        list_for_each_entry_safe (ne, tmp1, &nlc_ctx->ne, list) {
21ab4e
+                                gf_proc_dump_write ("ne", "%s", ne->name);
21ab4e
+                        }
21ab4e
+
21ab4e
+                 UNLOCK (&nlc_ctx->lock);
21ab4e
+        }
21ab4e
+
21ab4e
+        if (ret && nlc_ctx)
21ab4e
+                gf_proc_dump_write ("Unable to dump the inode information",
21ab4e
+                                    "(Lock acquisition failed) %p (gfid: %s)",
21ab4e
+                                    nlc_ctx, uuid_str);
21ab4e
+out:
21ab4e
+        return;
21ab4e
+}
21ab4e
diff --git a/xlators/performance/nl-cache/src/nl-cache-mem-types.h b/xlators/performance/nl-cache/src/nl-cache-mem-types.h
21ab4e
new file mode 100644
21ab4e
index 0000000..20fc030
21ab4e
--- /dev/null
21ab4e
+++ b/xlators/performance/nl-cache/src/nl-cache-mem-types.h
21ab4e
@@ -0,0 +1,29 @@
21ab4e
+/*
21ab4e
+ *   Copyright (c) 2016 Red Hat, Inc. <http://www.redhat.com>
21ab4e
+ *   This file is part of GlusterFS.
21ab4e
+ *
21ab4e
+ *   This file is licensed to you under your choice of the GNU Lesser
21ab4e
+ *   General Public License, version 3 or any later version (LGPLv3 or
21ab4e
+ *   later), or the GNU General Public License, version 2 (GPLv2), in all
21ab4e
+ *   cases as published by the Free Software Foundation.
21ab4e
+ */
21ab4e
+
21ab4e
+
21ab4e
+#ifndef __NL_CACHe_MEM_TYPES_H__
21ab4e
+#define __NL_CACHE_MEM_TYPES_H__
21ab4e
+
21ab4e
+#include "mem-types.h"
21ab4e
+
21ab4e
+enum gf_nlc_mem_types_ {
21ab4e
+        gf_nlc_mt_conf_t = gf_common_mt_end + 1,
21ab4e
+        gf_nlc_mt_nlc_conf_t,
21ab4e
+        gf_nlc_mt_nlc_ctx_t,
21ab4e
+        gf_nlc_mt_nlc_local_t,
21ab4e
+        gf_nlc_mt_nlc_pe_t,
21ab4e
+        gf_nlc_mt_nlc_ne_t,
21ab4e
+        gf_nlc_mt_nlc_timer_data_t,
21ab4e
+        gf_nlc_mt_nlc_lru_node,
21ab4e
+        gf_nlc_mt_end
21ab4e
+};
21ab4e
+
21ab4e
+#endif /* __NL_CACHE_MEM_TYPES_H__ */
21ab4e
diff --git a/xlators/performance/nl-cache/src/nl-cache-messages.h b/xlators/performance/nl-cache/src/nl-cache-messages.h
21ab4e
new file mode 100644
21ab4e
index 0000000..2e3b894
21ab4e
--- /dev/null
21ab4e
+++ b/xlators/performance/nl-cache/src/nl-cache-messages.h
21ab4e
@@ -0,0 +1,34 @@
21ab4e
+/*
21ab4e
+ *   Copyright (c) 2016 Red Hat, Inc. <http://www.redhat.com>
21ab4e
+ *   This file is part of GlusterFS.
21ab4e
+ *
21ab4e
+ *   This file is licensed to you under your choice of the GNU Lesser
21ab4e
+ *   General Public License, version 3 or any later version (LGPLv3 or
21ab4e
+ *   later), or the GNU General Public License, version 2 (GPLv2), in all
21ab4e
+ *   cases as published by the Free Software Foundation.
21ab4e
+ */
21ab4e
+
21ab4e
+
21ab4e
+#ifndef __NL_CACHE_MESSAGES_H__
21ab4e
+#define __NL_CACHE_MESSAGES_H__
21ab4e
+
21ab4e
+
21ab4e
+#define GLFS_COMP_BASE_NLC GLFS_MSGID_COMP_NLC
21ab4e
+#define GLFS_NUM_MESSAGES 4
21ab4e
+#define GLFS_MSGID_END (GLFS_COMP_BASE_NLC + GLFS_NUM_MESSAGES + 1)
21ab4e
+
21ab4e
+#define glfs_msg_start_x GLFS_COMP_BASE_NLC, "Invalid: Start of messages"
21ab4e
+
21ab4e
+/*!
21ab4e
+ * @messageid 110001
21ab4e
+ * @diagnosis Out of Memory
21ab4e
+ * @recommendedaction None
21ab4e
+ */
21ab4e
+#define NLC_MSG_NO_MEMORY             (GLFS_COMP_BASE_NLC + 1)
21ab4e
+#define NLC_MSG_EINVAL                (GLFS_COMP_BASE_NLC + 2)
21ab4e
+#define NLC_MSG_NO_TIMER_WHEEL        (GLFS_COMP_BASE_NLC + 3)
21ab4e
+#define NLC_MSG_DICT_FAILURE          (GLFS_COMP_BASE_NLC + 4)
21ab4e
+#define glfs_msg_end_x GLFS_MSGID_END, "Invalid: End of messages"
21ab4e
+
21ab4e
+
21ab4e
+#endif /* __NL_CACHE_MESSAGES_H__ */
21ab4e
diff --git a/xlators/performance/nl-cache/src/nl-cache.c b/xlators/performance/nl-cache/src/nl-cache.c
21ab4e
new file mode 100644
21ab4e
index 0000000..a34b752
21ab4e
--- /dev/null
21ab4e
+++ b/xlators/performance/nl-cache/src/nl-cache.c
21ab4e
@@ -0,0 +1,775 @@
21ab4e
+/*
21ab4e
+ *   Copyright (c) 2016 Red Hat, Inc. <http://www.redhat.com>
21ab4e
+ *   This file is part of GlusterFS.
21ab4e
+ *
21ab4e
+ *   This file is licensed to you under your choice of the GNU Lesser
21ab4e
+ *   General Public License, version 3 or any later version (LGPLv3 or
21ab4e
+ *   later), or the GNU General Public License, version 2 (GPLv2), in all
21ab4e
+ *   cases as published by the Free Software Foundation.
21ab4e
+ */
21ab4e
+
21ab4e
+
21ab4e
+#include "nl-cache.h"
21ab4e
+#include "statedump.h"
21ab4e
+#include "upcall-utils.h"
21ab4e
+#include "tw.h"
21ab4e
+
21ab4e
+static void
21ab4e
+nlc_dentry_op (call_frame_t *frame, xlator_t *this, gf_boolean_t multilink)
21ab4e
+{
21ab4e
+        nlc_local_t *local = frame->local;
21ab4e
+
21ab4e
+        GF_VALIDATE_OR_GOTO (this->name, local, out);
21ab4e
+
21ab4e
+        switch (local->fop) {
21ab4e
+        case GF_FOP_MKDIR:
21ab4e
+                nlc_set_dir_state (this, local->loc.inode, NLC_PE_FULL);
21ab4e
+                /*fall-through*/
21ab4e
+        case GF_FOP_MKNOD:
21ab4e
+        case GF_FOP_CREATE:
21ab4e
+        case GF_FOP_SYMLINK:
21ab4e
+                nlc_dir_add_pe (this, local->loc.parent, local->loc.inode,
21ab4e
+                                local->loc.name);
21ab4e
+                break;
21ab4e
+        case GF_FOP_LINK:
21ab4e
+                nlc_dir_add_pe (this, local->loc2.parent, NULL,
21ab4e
+                                local->loc2.name);
21ab4e
+                break;
21ab4e
+        case GF_FOP_RMDIR:
21ab4e
+                nlc_inode_clear_cache (this, local->loc.inode, _gf_false);
21ab4e
+                /*fall-through*/
21ab4e
+        case GF_FOP_UNLINK:
21ab4e
+                nlc_dir_remove_pe (this, local->loc.parent, local->loc.inode,
21ab4e
+                                   local->loc.name, multilink);
21ab4e
+                break;
21ab4e
+        case GF_FOP_RENAME:
21ab4e
+                /* TBD: Should these be atomic ?  In case of rename, the
21ab4e
+                 * newloc->inode can be NULL, and hence use oldloc->inode */
21ab4e
+                nlc_dir_remove_pe (this, local->loc2.parent, local->loc2.inode,
21ab4e
+                                   local->loc2.name, _gf_false);
21ab4e
+
21ab4e
+                /*TODO: Remove old dentry from destination before adding this pe*/
21ab4e
+                nlc_dir_add_pe (this, local->loc.parent, local->loc2.inode,
21ab4e
+                                local->loc.name);
21ab4e
+
21ab4e
+        default:
21ab4e
+                return;
21ab4e
+        }
21ab4e
+out:
21ab4e
+        return;
21ab4e
+}
21ab4e
+
21ab4e
+#define NLC_FOP(_name, _op, loc1, loc2, frame, this, args ...)  do {    \
21ab4e
+        nlc_local_t      *__local   = NULL;                             \
21ab4e
+        nlc_conf_t       *conf      = NULL;                             \
21ab4e
+                                                                        \
21ab4e
+        conf = this->private;                                           \
21ab4e
+                                                                        \
21ab4e
+        if (!IS_PEC_ENABLED (conf))                                     \
21ab4e
+                goto disabled;                                          \
21ab4e
+                                                                        \
21ab4e
+        __local = nlc_local_init (frame, this, _op, loc1, loc2);        \
21ab4e
+        GF_VALIDATE_OR_GOTO (this->name, __local, err);                 \
21ab4e
+                                                                        \
21ab4e
+        STACK_WIND (frame, nlc_##_name##_cbk,                           \
21ab4e
+                    FIRST_CHILD(this), FIRST_CHILD(this)->fops->_name,  \
21ab4e
+                    args);                                              \
21ab4e
+        break;                                                          \
21ab4e
+disabled:                                                               \
21ab4e
+        default_##_name##_resume (frame, this, args);                   \
21ab4e
+        break;                                                          \
21ab4e
+err:                                                                    \
21ab4e
+        default_##_name##_failure_cbk (frame, ENOMEM);                  \
21ab4e
+        break;                                                          \
21ab4e
+} while (0)
21ab4e
+
21ab4e
+#define NLC_FOP_CBK(_name, multilink, frame, cookie, this, op_ret, op_errno, \
21ab4e
+                    args ...) do {                                      \
21ab4e
+        nlc_conf_t  *conf  = NULL;                                      \
21ab4e
+                                                                        \
21ab4e
+        if (op_ret != 0)                                                \
21ab4e
+                goto out;                                               \
21ab4e
+                                                                        \
21ab4e
+        conf = this->private;                                           \
21ab4e
+                                                                        \
21ab4e
+        if (op_ret < 0 || !IS_PEC_ENABLED (conf))                       \
21ab4e
+                goto out;                                               \
21ab4e
+        nlc_dentry_op (frame, this, multilink);                         \
21ab4e
+out:                                                                    \
21ab4e
+        NLC_STACK_UNWIND (_name, frame, op_ret, op_errno, args);        \
21ab4e
+} while (0)
21ab4e
+
21ab4e
+static int32_t
21ab4e
+nlc_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
21ab4e
+                int32_t op_ret, int32_t op_errno, struct iatt *buf,
21ab4e
+                struct iatt *preoldparent, struct iatt *postoldparent,
21ab4e
+                struct iatt *prenewparent, struct iatt *postnewparent,
21ab4e
+                dict_t *xdata)
21ab4e
+{
21ab4e
+        NLC_FOP_CBK (rename, _gf_false, frame, cookie, this, op_ret, op_errno,
21ab4e
+                     buf, preoldparent, postoldparent, prenewparent,
21ab4e
+                     postnewparent, xdata);
21ab4e
+        return 0;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static int32_t
21ab4e
+nlc_rename (call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc,
21ab4e
+            dict_t *xdata)
21ab4e
+{
21ab4e
+        NLC_FOP (rename, GF_FOP_RENAME, newloc, oldloc, frame, this, oldloc,
21ab4e
+                 newloc, xdata);
21ab4e
+        return 0;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static int32_t
21ab4e
+nlc_mknod_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret,
21ab4e
+               int32_t op_errno, inode_t *inode, struct iatt *buf,
21ab4e
+               struct iatt *preparent, struct iatt *postparent, dict_t *xdata)
21ab4e
+{
21ab4e
+        NLC_FOP_CBK(mknod, _gf_false, frame, cookie, this, op_ret, op_errno,
21ab4e
+                    inode, buf, preparent, postparent, xdata);
21ab4e
+        return 0;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static int32_t
21ab4e
+nlc_mknod (call_frame_t *frame, xlator_t *this, loc_t *loc,
21ab4e
+           mode_t mode, dev_t rdev, mode_t umask,
21ab4e
+           dict_t *xdata)
21ab4e
+{
21ab4e
+        NLC_FOP(mknod, GF_FOP_MKNOD, loc, NULL, frame, this, loc, mode, rdev,
21ab4e
+                umask, xdata);
21ab4e
+        return 0;
21ab4e
+}
21ab4e
+
21ab4e
+static int32_t
21ab4e
+nlc_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
21ab4e
+                int32_t op_ret, int32_t op_errno, fd_t *fd, inode_t *inode,
21ab4e
+                struct iatt *buf, struct iatt *preparent,
21ab4e
+                struct iatt *postparent, dict_t *xdata)
21ab4e
+{
21ab4e
+        NLC_FOP_CBK (create, _gf_false, frame, cookie, this, op_ret, op_errno,
21ab4e
+                     fd, inode, buf, preparent, postparent, xdata);
21ab4e
+        return 0;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static int32_t
21ab4e
+nlc_create (call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags,
21ab4e
+            mode_t mode, mode_t umask, fd_t *fd, dict_t *xdata)
21ab4e
+{
21ab4e
+        NLC_FOP (create, GF_FOP_CREATE, loc, NULL, frame, this, loc, flags,
21ab4e
+                 mode, umask, fd, xdata);
21ab4e
+        return 0;
21ab4e
+}
21ab4e
+
21ab4e
+static int32_t
21ab4e
+nlc_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret,
21ab4e
+               int32_t op_errno, inode_t *inode, struct iatt *buf,
21ab4e
+               struct iatt *preparent, struct iatt *postparent, dict_t *xdata)
21ab4e
+{
21ab4e
+        NLC_FOP_CBK (mkdir, _gf_false, frame, cookie, this, op_ret, op_errno,
21ab4e
+                     inode, buf, preparent, postparent, xdata);
21ab4e
+        return 0;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static int32_t
21ab4e
+nlc_mkdir (call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode,
21ab4e
+           mode_t umask, dict_t *xdata)
21ab4e
+{
21ab4e
+        NLC_FOP (mkdir, GF_FOP_MKDIR, loc, NULL, frame, this, loc, mode,
21ab4e
+                 umask, xdata);
21ab4e
+        return 0;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static int32_t
21ab4e
+nlc_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
21ab4e
+                int32_t op_ret, int32_t op_errno, inode_t *inode,
21ab4e
+                struct iatt *buf, dict_t *xdata, struct iatt *postparent)
21ab4e
+{
21ab4e
+        nlc_local_t *local = NULL;
21ab4e
+        nlc_conf_t  *conf  = NULL;
21ab4e
+
21ab4e
+        local = frame->local;
21ab4e
+        conf = this->private;
21ab4e
+
21ab4e
+        /* Donot add to pe, this may lead to duplicate entry and
21ab4e
+         * requires search before adding if list of strings */
21ab4e
+        if (op_ret < 0 && op_errno == ENOENT) {
21ab4e
+                nlc_dir_add_ne (this, local->loc.parent, local->loc.name);
21ab4e
+                GF_ATOMIC_INC (conf->nlc_counter.nlc_miss);
21ab4e
+        }
21ab4e
+
21ab4e
+        NLC_STACK_UNWIND (lookup, frame, op_ret, op_errno, inode, buf, xdata,
21ab4e
+                         postparent);
21ab4e
+        return 0;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static int32_t
21ab4e
+nlc_lookup (call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata)
21ab4e
+{
21ab4e
+        nlc_local_t *local = NULL;
21ab4e
+        nlc_conf_t  *conf  = NULL;
21ab4e
+        inode_t     *inode = NULL;
21ab4e
+
21ab4e
+        local = nlc_local_init (frame, this, GF_FOP_LOOKUP, loc, NULL);
21ab4e
+        if (!local)
21ab4e
+                goto err;
21ab4e
+
21ab4e
+        conf = this->private;
21ab4e
+
21ab4e
+        if ((!loc->parent && gf_uuid_is_null (loc->pargfid)) || !loc->name)
21ab4e
+                goto wind;
21ab4e
+
21ab4e
+        inode = inode_grep (loc->inode->table, loc->parent, loc->name);
21ab4e
+        if (inode) {
21ab4e
+                inode_unref (inode);
21ab4e
+                goto wind;
21ab4e
+        }
21ab4e
+
21ab4e
+        if (nlc_is_negative_lookup (this, loc)) {
21ab4e
+                GF_ATOMIC_INC (conf->nlc_counter.nlc_hit);
21ab4e
+                gf_msg_trace (this->name, 0, "Serving negative lookup from "
21ab4e
+                              "cache:%s", loc->name);
21ab4e
+                goto unwind;
21ab4e
+        }
21ab4e
+
21ab4e
+wind:
21ab4e
+        STACK_WIND (frame, nlc_lookup_cbk,
21ab4e
+                    FIRST_CHILD(this), FIRST_CHILD(this)->fops->lookup,
21ab4e
+                    loc, xdata);
21ab4e
+        return 0;
21ab4e
+unwind:
21ab4e
+        NLC_STACK_UNWIND (lookup, frame, -1, ENOENT, NULL, NULL, NULL, NULL);
21ab4e
+        return 0;
21ab4e
+err:
21ab4e
+        NLC_STACK_UNWIND (lookup, frame, -1, ENOMEM, NULL, NULL, NULL, NULL);
21ab4e
+        return 0;
21ab4e
+}
21ab4e
+
21ab4e
+static int32_t
21ab4e
+nlc_rmdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
21ab4e
+               int32_t op_ret, int32_t op_errno, struct iatt *preparent,
21ab4e
+               struct iatt *postparent, dict_t *xdata)
21ab4e
+{
21ab4e
+        NLC_FOP_CBK (rmdir, _gf_false, frame, cookie, this, op_ret, op_errno,
21ab4e
+                     preparent, postparent, xdata);
21ab4e
+        return 0;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static int32_t
21ab4e
+nlc_rmdir (call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags,
21ab4e
+           dict_t *xdata)
21ab4e
+{
21ab4e
+        NLC_FOP (rmdir, GF_FOP_RMDIR, loc, NULL, frame, this, loc, flags,
21ab4e
+                 xdata);
21ab4e
+        return 0;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static int32_t
21ab4e
+nlc_getxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
21ab4e
+                  int32_t op_ret, int32_t op_errno, dict_t *dict,
21ab4e
+                  dict_t *xdata)
21ab4e
+{
21ab4e
+        nlc_conf_t  *conf  = NULL;
21ab4e
+
21ab4e
+        conf = this->private;
21ab4e
+        GF_VALIDATE_OR_GOTO (this->name, conf, out);
21ab4e
+
21ab4e
+        if (!IS_PEC_ENABLED (conf))
21ab4e
+                goto out;
21ab4e
+
21ab4e
+        if (op_ret < 0 && op_errno == ENOENT) {
21ab4e
+                GF_ATOMIC_INC (conf->nlc_counter.getrealfilename_miss);
21ab4e
+        }
21ab4e
+
21ab4e
+out:
21ab4e
+        NLC_STACK_UNWIND (getxattr, frame, op_ret, op_errno, dict, xdata);
21ab4e
+        return 0;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static int32_t
21ab4e
+nlc_getxattr (call_frame_t *frame, xlator_t *this, loc_t *loc, const char *key,
21ab4e
+              dict_t *xdata)
21ab4e
+{
21ab4e
+        int32_t               op_ret                = -1;
21ab4e
+        int32_t               op_errno              = 0;
21ab4e
+        dict_t               *dict                  = NULL;
21ab4e
+        nlc_local_t           *local                 = NULL;
21ab4e
+        gf_boolean_t          hit                   = _gf_false;
21ab4e
+        const char           *fname                 = NULL;
21ab4e
+        nlc_conf_t            *conf                  = NULL;
21ab4e
+
21ab4e
+        conf = this->private;
21ab4e
+
21ab4e
+        if (!IS_PEC_ENABLED (conf))
21ab4e
+                goto wind;
21ab4e
+
21ab4e
+        if (!key || (strncmp (key, GF_XATTR_GET_REAL_FILENAME_KEY,
21ab4e
+                     strlen (GF_XATTR_GET_REAL_FILENAME_KEY)) != 0))
21ab4e
+                goto wind;
21ab4e
+
21ab4e
+        local = nlc_local_init (frame, this, GF_FOP_GETXATTR, loc, NULL);
21ab4e
+        if (!local)
21ab4e
+                goto err;
21ab4e
+
21ab4e
+        if (loc->inode && key) {
21ab4e
+                dict = dict_new ();
21ab4e
+                if (!dict)
21ab4e
+                        goto err;
21ab4e
+
21ab4e
+                fname = key + strlen (GF_XATTR_GET_REAL_FILENAME_KEY);
21ab4e
+                hit = nlc_get_real_file_name (this, loc, fname, &op_ret,
21ab4e
+                                             &op_errno, dict);
21ab4e
+                if (hit)
21ab4e
+                        goto unwind;
21ab4e
+                else
21ab4e
+                        dict_unref (dict);
21ab4e
+        }
21ab4e
+
21ab4e
+        STACK_WIND (frame, nlc_getxattr_cbk,
21ab4e
+                    FIRST_CHILD(this), FIRST_CHILD(this)->fops->getxattr,
21ab4e
+                    loc, key, xdata);
21ab4e
+        return 0;
21ab4e
+wind:
21ab4e
+        STACK_WIND (frame, default_getxattr_cbk,
21ab4e
+                    FIRST_CHILD(this), FIRST_CHILD(this)->fops->getxattr,
21ab4e
+                    loc, key, xdata);
21ab4e
+        return 0;
21ab4e
+unwind:
21ab4e
+        GF_ATOMIC_INC (conf->nlc_counter.getrealfilename_hit);
21ab4e
+        NLC_STACK_UNWIND (getxattr, frame, op_ret, op_errno, dict, NULL);
21ab4e
+        dict_unref (dict);
21ab4e
+        return 0;
21ab4e
+err:
21ab4e
+        NLC_STACK_UNWIND (getxattr, frame, -1, ENOMEM, NULL, NULL);
21ab4e
+        return 0;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static int32_t
21ab4e
+nlc_symlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
21ab4e
+                 int32_t op_ret, int32_t op_errno, inode_t *inode,
21ab4e
+                 struct iatt *buf, struct iatt *preparent,
21ab4e
+                 struct iatt *postparent, dict_t *xdata)
21ab4e
+{
21ab4e
+        NLC_FOP_CBK (symlink, _gf_false, frame, cookie, this, op_ret, op_errno,
21ab4e
+                     inode, buf, preparent, postparent, xdata);
21ab4e
+        return 0;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static int32_t
21ab4e
+nlc_symlink (call_frame_t *frame, xlator_t *this, const char *linkpath,
21ab4e
+             loc_t *loc, mode_t umask, dict_t *xdata)
21ab4e
+{
21ab4e
+        NLC_FOP (symlink, GF_FOP_SYMLINK, loc, NULL, frame, this, linkpath,
21ab4e
+                 loc, umask, xdata);
21ab4e
+        return 0;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static int32_t
21ab4e
+nlc_link_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret,
21ab4e
+              int32_t op_errno, inode_t *inode, struct iatt *buf,
21ab4e
+              struct iatt *preparent, struct iatt *postparent, dict_t *xdata)
21ab4e
+{
21ab4e
+        NLC_FOP_CBK (link, _gf_false, frame, cookie, this, op_ret, op_errno,
21ab4e
+                     inode, buf, preparent, postparent, xdata);
21ab4e
+        return 0;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static int32_t
21ab4e
+nlc_link (call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc,
21ab4e
+          dict_t *xdata)
21ab4e
+{
21ab4e
+        NLC_FOP (link, GF_FOP_LINK, oldloc, newloc, frame, this, oldloc,
21ab4e
+                 newloc, xdata);
21ab4e
+        return 0;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static int32_t
21ab4e
+nlc_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
21ab4e
+                int32_t op_ret, int32_t op_errno, struct iatt *preparent,
21ab4e
+                struct iatt *postparent, dict_t *xdata)
21ab4e
+{
21ab4e
+        uint32_t    link_count = 0;
21ab4e
+        gf_boolean_t multilink = _gf_false;
21ab4e
+
21ab4e
+        if (xdata && !dict_get_uint32 (xdata, GET_LINK_COUNT, &link_count)) {
21ab4e
+                if (link_count > 1)
21ab4e
+                        multilink = _gf_true;
21ab4e
+        } else {
21ab4e
+                /* Don't touch cache if we don't know enough */
21ab4e
+                gf_msg (this->name, GF_LOG_WARNING, 0, NLC_MSG_DICT_FAILURE,
21ab4e
+                        "Failed to get GET_LINK_COUNT from dict");
21ab4e
+                NLC_STACK_UNWIND (unlink, frame, op_ret, op_errno, preparent,
21ab4e
+                                  postparent, xdata);
21ab4e
+                return 0;
21ab4e
+        }
21ab4e
+
21ab4e
+        NLC_FOP_CBK (unlink, multilink, frame, cookie, this, op_ret, op_errno,
21ab4e
+                     preparent, postparent, xdata);
21ab4e
+        return 0;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static int32_t
21ab4e
+nlc_unlink (call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags,
21ab4e
+            dict_t *xdata)
21ab4e
+{
21ab4e
+        nlc_conf_t   *conf     = NULL;
21ab4e
+        gf_boolean_t new_dict = _gf_false;
21ab4e
+
21ab4e
+        conf = this->private;
21ab4e
+
21ab4e
+        if (!IS_PEC_ENABLED (conf))
21ab4e
+                goto do_fop;
21ab4e
+
21ab4e
+        if (!xdata) {
21ab4e
+                xdata = dict_new ();
21ab4e
+                if (xdata)
21ab4e
+                        new_dict = _gf_true;
21ab4e
+        }
21ab4e
+
21ab4e
+        if (xdata && dict_set_uint32 (xdata, GET_LINK_COUNT, 0)) {
21ab4e
+                gf_msg (this->name, GF_LOG_WARNING, 0, NLC_MSG_DICT_FAILURE,
21ab4e
+                        "Failed to set GET_LINK_COUNT in dict");
21ab4e
+                goto err;
21ab4e
+        }
21ab4e
+
21ab4e
+do_fop:
21ab4e
+        NLC_FOP (unlink, GF_FOP_UNLINK, loc, NULL, frame, this, loc, flags,
21ab4e
+                 xdata);
21ab4e
+
21ab4e
+        if (new_dict)
21ab4e
+                dict_unref (xdata);
21ab4e
+        return 0;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static int32_t
21ab4e
+nlc_invalidate (xlator_t *this, void *data)
21ab4e
+{
21ab4e
+        struct gf_upcall                    *up_data    = NULL;
21ab4e
+        struct gf_upcall_cache_invalidation *up_ci      = NULL;
21ab4e
+        inode_t                             *inode      = NULL;
21ab4e
+        inode_t                             *parent1    = NULL;
21ab4e
+        inode_t                             *parent2    = NULL;
21ab4e
+        int                                  ret        = 0;
21ab4e
+        inode_table_t                       *itable     = NULL;
21ab4e
+
21ab4e
+        up_data = (struct gf_upcall *)data;
21ab4e
+
21ab4e
+        if (up_data->event_type != GF_UPCALL_CACHE_INVALIDATION)
21ab4e
+                goto out;
21ab4e
+
21ab4e
+        up_ci = (struct gf_upcall_cache_invalidation *)up_data->data;
21ab4e
+
21ab4e
+        /*TODO: Add he inodes found as a member in gf_upcall_cache_invalidation
21ab4e
+         * so that it prevents subsequent xlators from doing inode_find again
21ab4e
+         */
21ab4e
+        itable = ((xlator_t *)this->graph->top)->itable;
21ab4e
+        inode = inode_find (itable, up_data->gfid);
21ab4e
+        if (!inode) {
21ab4e
+                ret = -1;
21ab4e
+                goto out;
21ab4e
+        }
21ab4e
+
21ab4e
+        if ((!((up_ci->flags & UP_TIMES) && inode->ia_type == IA_IFDIR)) &&
21ab4e
+            (!(up_ci->flags & UP_PARENT_DENTRY_FLAGS))) {
21ab4e
+                goto out;
21ab4e
+        }
21ab4e
+
21ab4e
+        if (!gf_uuid_is_null (up_ci->p_stat.ia_gfid)) {
21ab4e
+                parent1 = inode_find (itable, up_ci->p_stat.ia_gfid);
21ab4e
+                if (!parent1) {
21ab4e
+                        ret = -1;
21ab4e
+                        goto out;
21ab4e
+                }
21ab4e
+        }
21ab4e
+
21ab4e
+        if (!gf_uuid_is_null (up_ci->oldp_stat.ia_gfid)) {
21ab4e
+                parent2 = inode_find (itable, up_ci->oldp_stat.ia_gfid);
21ab4e
+                if (!parent2) {
21ab4e
+                        ret = -1;
21ab4e
+                        goto out;
21ab4e
+                }
21ab4e
+        }
21ab4e
+
21ab4e
+        /* TODO: get enough data in upcall so that we do not invalidate but
21ab4e
+         * update */
21ab4e
+        if (inode && inode->ia_type == IA_IFDIR)
21ab4e
+                nlc_inode_clear_cache (this, inode, NLC_NONE);
21ab4e
+        if (parent1)
21ab4e
+                nlc_inode_clear_cache (this, parent1, NLC_NONE);
21ab4e
+        if (parent2)
21ab4e
+                nlc_inode_clear_cache (this, parent2, NLC_NONE);
21ab4e
+out:
21ab4e
+        if (inode)
21ab4e
+                inode_unref (inode);
21ab4e
+        if (parent1)
21ab4e
+                inode_unref (parent1);
21ab4e
+        if (parent2)
21ab4e
+                inode_unref (parent2);
21ab4e
+
21ab4e
+        return ret;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+int
21ab4e
+notify (xlator_t *this, int event, void *data, ...)
21ab4e
+{
21ab4e
+        int        ret  = 0;
21ab4e
+        time_t     now  = 0;
21ab4e
+
21ab4e
+        switch (event) {
21ab4e
+        case GF_EVENT_CHILD_DOWN:
21ab4e
+        case GF_EVENT_SOME_DESCENDENT_DOWN:
21ab4e
+        case GF_EVENT_CHILD_UP:
21ab4e
+        case GF_EVENT_SOME_DESCENDENT_UP:
21ab4e
+                time (&now;;
21ab4e
+                nlc_update_child_down_time (this, &now;;
21ab4e
+                /* TODO: nlc_clear_all_cache (this); else
21ab4e
+                 lru prune will lazily clear it*/
21ab4e
+                break;
21ab4e
+        case GF_EVENT_UPCALL:
21ab4e
+                ret = nlc_invalidate (this, data);
21ab4e
+                break;
21ab4e
+        case GF_EVENT_PARENT_DOWN:
21ab4e
+                nlc_disable_cache (this);
21ab4e
+                nlc_clear_all_cache (this);
21ab4e
+        default:
21ab4e
+                break;
21ab4e
+        }
21ab4e
+
21ab4e
+        if (default_notify (this, event, data) != 0)
21ab4e
+                ret = -1;
21ab4e
+
21ab4e
+        return ret;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static int32_t
21ab4e
+nlc_forget (xlator_t *this, inode_t *inode)
21ab4e
+{
21ab4e
+        uint64_t pe_int = 0;
21ab4e
+
21ab4e
+        inode_ctx_reset1 (inode, this, &pe_int);
21ab4e
+        GF_ASSERT (pe_int == 0);
21ab4e
+
21ab4e
+        nlc_inode_clear_cache (this, inode, NLC_NONE);
21ab4e
+
21ab4e
+        return 0;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static int32_t
21ab4e
+nlc_inodectx (xlator_t *this, inode_t *inode)
21ab4e
+{
21ab4e
+        nlc_dump_inodectx (this, inode);
21ab4e
+        return 0;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+static int32_t
21ab4e
+nlc_priv_dump (xlator_t *this)
21ab4e
+{
21ab4e
+        nlc_conf_t *conf = NULL;
21ab4e
+        char  key_prefix[GF_DUMP_MAX_BUF_LEN];
21ab4e
+
21ab4e
+        conf = this->private;
21ab4e
+
21ab4e
+        snprintf(key_prefix, GF_DUMP_MAX_BUF_LEN, "%s.%s", this->type, this->name);
21ab4e
+        gf_proc_dump_add_section(key_prefix);
21ab4e
+
21ab4e
+        gf_proc_dump_write("negative_lookup_hit_count", "%"PRId64,
21ab4e
+                           conf->nlc_counter.nlc_hit.cnt);
21ab4e
+        gf_proc_dump_write("negative_lookup_miss_count", "%"PRId64,
21ab4e
+                           conf->nlc_counter.nlc_miss.cnt);
21ab4e
+        gf_proc_dump_write("get_real_filename_hit_count", "%"PRId64,
21ab4e
+                           conf->nlc_counter.getrealfilename_hit.cnt);
21ab4e
+        gf_proc_dump_write("get_real_filename_miss_count", "%"PRId64,
21ab4e
+                           conf->nlc_counter.getrealfilename_miss.cnt);
21ab4e
+        gf_proc_dump_write("nameless_lookup_count", "%"PRId64,
21ab4e
+                           conf->nlc_counter.nameless_lookup.cnt);
21ab4e
+        gf_proc_dump_write("inodes_with_positive_dentry_cache", "%"PRId64,
21ab4e
+                           conf->nlc_counter.pe_inode_cnt.cnt);
21ab4e
+        gf_proc_dump_write("inodes_with_negative_dentry_cache", "%"PRId64,
21ab4e
+                           conf->nlc_counter.ne_inode_cnt.cnt);
21ab4e
+        gf_proc_dump_write("dentry_invalidations_recieved", "%"PRId64,
21ab4e
+                           conf->nlc_counter.nlc_invals.cnt);
21ab4e
+        gf_proc_dump_write("cache_limit", "%"PRIu64,
21ab4e
+                           conf->cache_size);
21ab4e
+        gf_proc_dump_write("consumed_cache_size", "%"PRId64,
21ab4e
+                           conf->current_cache_size.cnt);
21ab4e
+        gf_proc_dump_write("inode_limit", "%"PRIu64,
21ab4e
+                           conf->inode_limit);
21ab4e
+        gf_proc_dump_write("consumed_inodes", "%"PRId64,
21ab4e
+                           conf->refd_inodes.cnt);
21ab4e
+
21ab4e
+        return 0;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+void
21ab4e
+fini (xlator_t *this)
21ab4e
+{
21ab4e
+        return;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+int32_t
21ab4e
+mem_acct_init (xlator_t *this)
21ab4e
+{
21ab4e
+        int     ret = -1;
21ab4e
+
21ab4e
+        ret = xlator_mem_acct_init (this, gf_nlc_mt_end + 1);
21ab4e
+        return ret;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+int32_t
21ab4e
+reconfigure (xlator_t *this, dict_t *options)
21ab4e
+{
21ab4e
+        nlc_conf_t *conf = NULL;
21ab4e
+
21ab4e
+        conf = this->private;
21ab4e
+
21ab4e
+        GF_OPTION_RECONF ("nl-cache-timeout", conf->cache_timeout, options,
21ab4e
+                          int32, out);
21ab4e
+        GF_OPTION_RECONF ("nl-cache-positive-entry", conf->positive_entry_cache,
21ab4e
+                          options, bool, out);
21ab4e
+        GF_OPTION_RECONF ("nl-cache-limit", conf->cache_size, options,
21ab4e
+                          size_uint64, out);
21ab4e
+
21ab4e
+out:
21ab4e
+        return 0;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+int32_t
21ab4e
+init (xlator_t *this)
21ab4e
+{
21ab4e
+        nlc_conf_t      *conf       = NULL;
21ab4e
+        int              ret        = -1;
21ab4e
+        inode_table_t   *itable     = NULL;
21ab4e
+
21ab4e
+        conf = GF_CALLOC (sizeof (*conf), 1, gf_nlc_mt_nlc_conf_t);
21ab4e
+        if (!conf)
21ab4e
+                goto out;
21ab4e
+
21ab4e
+        GF_OPTION_INIT ("nl-cache-timeout", conf->cache_timeout, int32, out);
21ab4e
+        GF_OPTION_INIT ("nl-cache-positive-entry", conf->positive_entry_cache,
21ab4e
+                        bool, out);
21ab4e
+        GF_OPTION_INIT ("nl-cache-limit", conf->cache_size, size_uint64, out);
21ab4e
+
21ab4e
+        /* Since the positive entries are stored as list of refs on
21ab4e
+         * existing inodes, we should not overflow the inode lru_limit.
21ab4e
+         * Hence keep the limit of inodes that are refed by this xlator,
21ab4e
+         * to 80% of inode_table->lru_limit. In fuse where the limit is
21ab4e
+         * infinite, take 131072 as lru limit (as in gfapi). */
21ab4e
+        itable = ((xlator_t *)this->graph->top)->itable;
21ab4e
+        if (itable && itable->lru_limit)
21ab4e
+                conf->inode_limit = itable->lru_limit * 80 / 100;
21ab4e
+        else
21ab4e
+                conf->inode_limit = 131072 * 80 / 100;
21ab4e
+
21ab4e
+        LOCK_INIT (&conf->lock);
21ab4e
+        GF_ATOMIC_INIT (conf->current_cache_size, 0);
21ab4e
+        GF_ATOMIC_INIT (conf->refd_inodes, 0);
21ab4e
+        GF_ATOMIC_INIT (conf->nlc_counter.nlc_hit, 0);
21ab4e
+        GF_ATOMIC_INIT (conf->nlc_counter.nlc_miss, 0);
21ab4e
+        GF_ATOMIC_INIT (conf->nlc_counter.nameless_lookup, 0);
21ab4e
+        GF_ATOMIC_INIT (conf->nlc_counter.getrealfilename_hit, 0);
21ab4e
+        GF_ATOMIC_INIT (conf->nlc_counter.getrealfilename_miss, 0);
21ab4e
+        GF_ATOMIC_INIT (conf->nlc_counter.pe_inode_cnt, 0);
21ab4e
+        GF_ATOMIC_INIT (conf->nlc_counter.ne_inode_cnt, 0);
21ab4e
+        GF_ATOMIC_INIT (conf->nlc_counter.nlc_invals, 0);
21ab4e
+
21ab4e
+        INIT_LIST_HEAD (&conf->lru);
21ab4e
+        time (&conf->last_child_down);
21ab4e
+
21ab4e
+        if (!glusterfs_global_timer_wheel (this)) {
21ab4e
+                gf_msg_debug (this->name, 0, "Initing the global timer wheel");
21ab4e
+                ret = glusterfs_global_timer_wheel_init (this->ctx);
21ab4e
+                if (ret) {
21ab4e
+                        gf_msg (this->name, GF_LOG_ERROR, 0,
21ab4e
+                                NLC_MSG_NO_TIMER_WHEEL,
21ab4e
+                                "Initing the global timer wheel failed");
21ab4e
+                                goto out;
21ab4e
+                }
21ab4e
+        }
21ab4e
+        conf->timer_wheel = glusterfs_global_timer_wheel (this);
21ab4e
+
21ab4e
+        this->private = conf;
21ab4e
+
21ab4e
+        ret = 0;
21ab4e
+out:
21ab4e
+        return ret;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
+struct xlator_fops fops = {
21ab4e
+        .rename               = nlc_rename,
21ab4e
+        .mknod                = nlc_mknod,
21ab4e
+        .create               = nlc_create,
21ab4e
+        .mkdir                = nlc_mkdir,
21ab4e
+        .lookup               = nlc_lookup,
21ab4e
+        .rmdir                = nlc_rmdir,
21ab4e
+        .getxattr             = nlc_getxattr,
21ab4e
+        .symlink              = nlc_symlink,
21ab4e
+        .link                 = nlc_link,
21ab4e
+        .unlink               = nlc_unlink,
21ab4e
+        /* TODO:
21ab4e
+        .readdir              = nlc_readdir,
21ab4e
+        .readdirp             = nlc_readdirp,
21ab4e
+        .seek                 = nlc_seek,
21ab4e
+        .opendir              = nlc_opendir, */
21ab4e
+};
21ab4e
+
21ab4e
+
21ab4e
+struct xlator_cbks cbks = {
21ab4e
+        .forget               = nlc_forget,
21ab4e
+};
21ab4e
+
21ab4e
+
21ab4e
+struct xlator_dumpops dumpops = {
21ab4e
+        .inodectx             = nlc_inodectx,
21ab4e
+        .priv                 = nlc_priv_dump,
21ab4e
+};
21ab4e
+
21ab4e
+struct volume_options options[] = {
21ab4e
+        { .key = {"nl-cache-positive-entry"},
21ab4e
+          .type = GF_OPTION_TYPE_BOOL,
21ab4e
+          .default_value = "false",
21ab4e
+          .description = "Cache the name of the files/directories that was"
21ab4e
+                         " looked up and are present in a directory",
21ab4e
+        },
21ab4e
+        { .key = {"nl-cache-limit"},
21ab4e
+          .type = GF_OPTION_TYPE_SIZET,
21ab4e
+          .min = 0,
21ab4e
+          .max = 100 * GF_UNIT_MB,
21ab4e
+          .default_value = "131072",
21ab4e
+          .description = "the value over which caching will be disabled for"
21ab4e
+                         "a while and the cache is cleared based on LRU",
21ab4e
+        },
21ab4e
+        { .key = {"nl-cache-timeout"},
21ab4e
+          .type = GF_OPTION_TYPE_INT,
21ab4e
+          .min = 0,
21ab4e
+          .max = 600,
21ab4e
+          .default_value = "600",
21ab4e
+          .description = "Time period after which cache has to be refreshed",
21ab4e
+        },
21ab4e
+        { .key = {NULL} },
21ab4e
+};
21ab4e
diff --git a/xlators/performance/nl-cache/src/nl-cache.h b/xlators/performance/nl-cache/src/nl-cache.h
21ab4e
new file mode 100644
21ab4e
index 0000000..e94641c
21ab4e
--- /dev/null
21ab4e
+++ b/xlators/performance/nl-cache/src/nl-cache.h
21ab4e
@@ -0,0 +1,173 @@
21ab4e
+/*
21ab4e
+ *   Copyright (c) 2016 Red Hat, Inc. <http://www.redhat.com>
21ab4e
+ *   This file is part of GlusterFS.
21ab4e
+ *
21ab4e
+ *   This file is licensed to you under your choice of the GNU Lesser
21ab4e
+ *   General Public License, version 3 or any later version (LGPLv3 or
21ab4e
+ *   later), or the GNU General Public License, version 2 (GPLv2), in all
21ab4e
+ *   cases as published by the Free Software Foundation.
21ab4e
+ */
21ab4e
+
21ab4e
+#ifndef __NL_CACHE_H__
21ab4e
+#define __NL_CACHE_H__
21ab4e
+
21ab4e
+#include "nl-cache-mem-types.h"
21ab4e
+#include "nl-cache-messages.h"
21ab4e
+#include "glusterfs.h"
21ab4e
+#include "xlator.h"
21ab4e
+#include "defaults.h"
21ab4e
+#include "atomic.h"
21ab4e
+
21ab4e
+#define NLC_INVALID 0x0000
21ab4e
+#define NLC_PE_FULL 0x0001
21ab4e
+#define NLC_PE_PARTIAL 0x0002
21ab4e
+#define NLC_NE_VALID 0x0004
21ab4e
+
21ab4e
+#define IS_PE_VALID(state) ((state != NLC_INVALID) && \
21ab4e
+                            (state & (NLC_PE_FULL | NLC_PE_PARTIAL)))
21ab4e
+#define IS_NE_VALID(state) ((state != NLC_INVALID) && (state & NLC_NE_VALID))
21ab4e
+
21ab4e
+#define IS_PEC_ENABLED(conf) (conf->positive_entry_cache)
21ab4e
+#define IS_CACHE_ENABLED(conf) ((!conf->cache_disabled))
21ab4e
+
21ab4e
+#define NLC_STACK_UNWIND(fop, frame, params ...) do {       \
21ab4e
+        nlc_local_t *__local = NULL;                        \
21ab4e
+        xlator_t *__xl      = NULL;                         \
21ab4e
+        if (frame) {                                        \
21ab4e
+                __xl = frame->this;                         \
21ab4e
+                __local = frame->local;                     \
21ab4e
+                frame->local = NULL;                        \
21ab4e
+        }                                                   \
21ab4e
+        STACK_UNWIND_STRICT (fop, frame, params);           \
21ab4e
+        nlc_local_wipe (__xl, __local);                     \
21ab4e
+} while (0)
21ab4e
+
21ab4e
+enum nlc_cache_clear_reason {
21ab4e
+        NLC_NONE = 0,
21ab4e
+        NLC_TIMER_EXPIRED,
21ab4e
+        NLC_LRU_PRUNE,
21ab4e
+};
21ab4e
+
21ab4e
+struct nlc_ne {
21ab4e
+        struct list_head  list;
21ab4e
+        char             *name;
21ab4e
+};
21ab4e
+typedef struct nlc_ne nlc_ne_t;
21ab4e
+
21ab4e
+struct nlc_pe {
21ab4e
+        struct list_head  list;
21ab4e
+        inode_t          *inode;
21ab4e
+        char             *name;
21ab4e
+};
21ab4e
+typedef struct nlc_pe nlc_pe_t;
21ab4e
+
21ab4e
+struct nlc_timer_data {
21ab4e
+        inode_t          *inode;
21ab4e
+        xlator_t         *this;
21ab4e
+};
21ab4e
+typedef struct nlc_timer_data nlc_timer_data_t;
21ab4e
+
21ab4e
+struct nlc_lru_node {
21ab4e
+        inode_t          *inode;
21ab4e
+        struct list_head  list;
21ab4e
+};
21ab4e
+typedef struct nlc_lru_node nlc_lru_node_t;
21ab4e
+
21ab4e
+struct nlc_ctx {
21ab4e
+        struct list_head         pe;   /* list of positive entries */
21ab4e
+        struct list_head         ne;   /* list of negative entries */
21ab4e
+        uint64_t                 state;
21ab4e
+        time_t                   cache_time;
21ab4e
+        struct gf_tw_timer_list *timer;
21ab4e
+        nlc_timer_data_t         *timer_data;
21ab4e
+        size_t                   cache_size;
21ab4e
+        uint64_t                 refd_inodes;
21ab4e
+        gf_lock_t                lock;
21ab4e
+};
21ab4e
+typedef struct nlc_ctx nlc_ctx_t;
21ab4e
+
21ab4e
+struct nlc_local {
21ab4e
+        loc_t    loc;
21ab4e
+        loc_t    loc2;
21ab4e
+        inode_t *inode;
21ab4e
+        inode_t *parent;
21ab4e
+        fd_t    *fd;
21ab4e
+        char    *linkname;
21ab4e
+        glusterfs_fop_t fop;
21ab4e
+};
21ab4e
+typedef struct nlc_local nlc_local_t;
21ab4e
+
21ab4e
+struct nlc_statistics {
21ab4e
+        gf_atomic_t nlc_hit; /* No. of times lookup/stat was served from this xl */
21ab4e
+        gf_atomic_t nlc_miss; /* No. of times negative lookups were sent to disk */
21ab4e
+        /* More granular counters */
21ab4e
+        gf_atomic_t nameless_lookup;
21ab4e
+        gf_atomic_t getrealfilename_hit;
21ab4e
+        gf_atomic_t getrealfilename_miss;
21ab4e
+        gf_atomic_t pe_inode_cnt;
21ab4e
+        gf_atomic_t ne_inode_cnt;
21ab4e
+        gf_atomic_t nlc_invals; /* No. of invalidates recieved from upcall*/
21ab4e
+};
21ab4e
+
21ab4e
+struct nlc_conf {
21ab4e
+        int32_t              cache_timeout;
21ab4e
+        gf_boolean_t         positive_entry_cache;
21ab4e
+        gf_boolean_t         negative_entry_cache;
21ab4e
+        gf_boolean_t         disable_cache;
21ab4e
+        uint64_t             cache_size;
21ab4e
+        gf_atomic_t          current_cache_size;
21ab4e
+        uint64_t             inode_limit;
21ab4e
+        gf_atomic_t          refd_inodes;
21ab4e
+        struct tvec_base    *timer_wheel;
21ab4e
+        time_t               last_child_down;
21ab4e
+        struct list_head     lru;
21ab4e
+        gf_lock_t            lock;
21ab4e
+        struct nlc_statistics nlc_counter;
21ab4e
+};
21ab4e
+typedef struct nlc_conf nlc_conf_t;
21ab4e
+
21ab4e
+gf_boolean_t
21ab4e
+nlc_get_real_file_name (xlator_t *this, loc_t *loc, const char *fname,
21ab4e
+                        int32_t *op_ret, int32_t *op_errno, dict_t *dict);
21ab4e
+
21ab4e
+gf_boolean_t
21ab4e
+nlc_is_negative_lookup (xlator_t *this, loc_t *loc);
21ab4e
+
21ab4e
+void
21ab4e
+nlc_set_dir_state (xlator_t *this, inode_t *inode, uint64_t state);
21ab4e
+
21ab4e
+void
21ab4e
+nlc_dir_add_pe (xlator_t *this, inode_t *inode, inode_t *entry_ino,
21ab4e
+                const char *name);
21ab4e
+
21ab4e
+void
21ab4e
+nlc_dir_remove_pe (xlator_t *this, inode_t *inode, inode_t *entry_ino,
21ab4e
+                   const char *name, gf_boolean_t multilink);
21ab4e
+
21ab4e
+void
21ab4e
+nlc_dir_add_ne (xlator_t *this, inode_t *inode, const char *name);
21ab4e
+
21ab4e
+void
21ab4e
+nlc_local_wipe (xlator_t *this, nlc_local_t *local);
21ab4e
+
21ab4e
+nlc_local_t *
21ab4e
+nlc_local_init (call_frame_t *frame, xlator_t *this, glusterfs_fop_t fop,
21ab4e
+                loc_t *loc, loc_t *loc2);
21ab4e
+
21ab4e
+void
21ab4e
+nlc_update_child_down_time (xlator_t *this, time_t *now);
21ab4e
+
21ab4e
+void
21ab4e
+nlc_inode_clear_cache (xlator_t *this, inode_t *inode,
21ab4e
+                      int reason);
21ab4e
+
21ab4e
+void
21ab4e
+nlc_dump_inodectx (xlator_t *this, inode_t *inode);
21ab4e
+
21ab4e
+void
21ab4e
+nlc_clear_all_cache (xlator_t *this);
21ab4e
+
21ab4e
+void
21ab4e
+nlc_disable_cache (xlator_t *this);
21ab4e
+
21ab4e
+#endif /* __NL_CACHE_H__ */
21ab4e
-- 
21ab4e
1.8.3.1
21ab4e