summaryrefslogtreecommitdiffstats
path: root/xlators/nfs
diff options
context:
space:
mode:
authorNiels de Vos <ndevos@redhat.com>2015-01-01 13:15:45 +0100
committerVijay Bellur <vbellur@redhat.com>2015-03-15 06:40:22 -0700
commitaac1ec0a61d9267b6ae7a280b368dfd357b7dcdc (patch)
treec25aafc656e401f552a222d50e97942cea1a337a /xlators/nfs
parent1cb3b1abeda53bb430bbe1490fac154337ac9994 (diff)
nfs: add auth-cache for the MOUNT protocol
Authentication cache for the new fine grained contol for the MOUNT protocol. The extended authentication (see Change-Id Ic060aac) benefits from caching the access/permission checks that are done when an NFS-client mounts an export. This auth-cache will be used by Change-Id I181e8c1. BUG: 1143880 Change-Id: I1379116572c8a4d1bf0c7ca4f826e51a79d91444 Original-author: Shreyas Siravara <shreyas.siravara@gmail.com> CC: Richard Wareing <rwareing@fb.com> CC: Jiffin Tony Thottan <jthottan@redhat.com> Signed-off-by: Niels de Vos <ndevos@redhat.com> Reviewed-on: http://review.gluster.org/9363 Tested-by: Gluster Build System <jenkins@build.gluster.com> Reviewed-by: Vijay Bellur <vbellur@redhat.com>
Diffstat (limited to 'xlators/nfs')
-rw-r--r--xlators/nfs/server/src/Makefile.am4
-rw-r--r--xlators/nfs/server/src/auth-cache.c311
-rw-r--r--xlators/nfs/server/src/auth-cache.h53
-rw-r--r--xlators/nfs/server/src/nfs-mem-types.h2
-rw-r--r--xlators/nfs/server/src/nfs.h3
5 files changed, 371 insertions, 2 deletions
diff --git a/xlators/nfs/server/src/Makefile.am b/xlators/nfs/server/src/Makefile.am
index 2b0badc4fdd..d7051eff9b8 100644
--- a/xlators/nfs/server/src/Makefile.am
+++ b/xlators/nfs/server/src/Makefile.am
@@ -5,13 +5,13 @@ server_la_LDFLAGS = -module -avoid-version
server_la_SOURCES = nfs.c nfs-common.c nfs-fops.c nfs-inodes.c \
nfs-generics.c mount3.c nfs3-fh.c nfs3.c nfs3-helpers.c nlm4.c \
nlmcbk_svc.c mount3udp_svc.c acl3.c netgroups.c exports.c \
- mount3-auth.c
+ mount3-auth.c auth-cache.c
server_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la \
$(top_builddir)/api/src/libgfapi.la
noinst_HEADERS = nfs.h nfs-common.h nfs-fops.h nfs-inodes.h nfs-generics.h \
mount3.h nfs3-fh.h nfs3.h nfs3-helpers.h nfs-mem-types.h nlm4.h \
- acl3.h netgroups.h exports.h mount3-auth.h
+ acl3.h netgroups.h exports.h mount3-auth.h auth-cache.h
AM_CPPFLAGS = $(GF_CPPFLAGS) \
-DLIBDIR=\"$(libdir)/glusterfs/$(PACKAGE_VERSION)/auth\" \
diff --git a/xlators/nfs/server/src/auth-cache.c b/xlators/nfs/server/src/auth-cache.c
new file mode 100644
index 00000000000..85d9056cd61
--- /dev/null
+++ b/xlators/nfs/server/src/auth-cache.c
@@ -0,0 +1,311 @@
+/*
+ Copyright 2014-present Facebook. All Rights Reserved
+ This file is part of GlusterFS.
+
+ Author :
+ Shreyas Siravara <shreyas.siravara@gmail.com>
+
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+*/
+
+#include "auth-cache.h"
+#include "nfs3.h"
+#include "exports.h"
+
+enum auth_cache_lookup_results {
+ ENTRY_FOUND = 0,
+ ENTRY_NOT_FOUND = -1,
+ ENTRY_EXPIRED = -2,
+};
+
+struct auth_cache_entry {
+ time_t timestamp;
+ struct export_item *item;
+};
+
+/* Given a filehandle and an ip, creates a colon delimited hashkey that is
+ * allocated on the stack.
+ */
+static inline void
+make_hashkey(char *hashkey, struct nfs3_fh *fh, const char *host)
+{
+ char exportid[256] = {0, };
+ char gfid[256] = {0, };
+ char mountid[256] = {0, };
+ size_t nbytes = 0;
+
+ uuid_unparse (fh->exportid, exportid);
+ uuid_unparse (fh->gfid, gfid);
+ uuid_unparse (fh->mountid, mountid);
+ nbytes = strlen (exportid) + strlen (gfid) + strlen (host)
+ + strlen (mountid) + 5;
+ hashkey = alloca (nbytes);
+ snprintf (hashkey, nbytes, "%s:%s:%s:%s", exportid, gfid,
+ mountid, host);
+}
+
+/**
+ * auth_cache_init -- Initialize an auth cache and set the ttl_sec
+ *
+ * @ttl_sec : The TTL to set in seconds
+ *
+ * @return : allocated auth cache struct, NULL if allocation failed.
+ */
+struct auth_cache *
+auth_cache_init (time_t ttl_sec)
+{
+ struct auth_cache *cache = GF_CALLOC (1, sizeof (*cache),
+ gf_nfs_mt_auth_cache);
+
+ GF_VALIDATE_OR_GOTO ("auth-cache", cache, out);
+
+ cache->ttl_sec = ttl_sec;
+out:
+ return cache;
+}
+
+/**
+ * auth_cache_entry_init -- Initialize an auth cache entry
+ *
+ * @return: Pointer to an allocated auth cache entry, NULL if allocation
+ * failed.
+ */
+struct auth_cache_entry *
+auth_cache_entry_init ()
+{
+ struct auth_cache_entry *entry = NULL;
+
+ entry = GF_CALLOC (1, sizeof (*entry), gf_nfs_mt_auth_cache_entry);
+ if (!entry)
+ gf_log (GF_NFS, GF_LOG_WARNING, "failed to allocate entry");
+
+ return entry;
+}
+
+/**
+ * auth_cache_lookup -- Lookup an item from the cache
+ *
+ * @cache: cache to lookup from
+ * @fh : FH to use in lookup
+ * @host_addr: Address to use in lookup
+ * @timestamp: The timestamp to set when lookup succeeds
+ * @can_write: Is the host authorized to write to the filehandle?
+ *
+ * If the current time - entry time of the cache entry > ttl_sec,
+ * we remove the element from the dict and return ENTRY_EXPIRED.
+ *
+ * @return: ENTRY_EXPIRED if entry expired
+ * ENTRY_NOT_FOUND if entry not found in dict
+ * 0 if found
+ */
+enum auth_cache_lookup_results
+auth_cache_lookup (struct auth_cache *cache, struct nfs3_fh *fh,
+ const char *host_addr, time_t *timestamp,
+ gf_boolean_t *can_write)
+{
+ char *hashkey = NULL;
+ data_t *entry_data = NULL;
+ struct auth_cache_entry *lookup_res = NULL;
+ int ret = ENTRY_NOT_FOUND;
+
+ GF_VALIDATE_OR_GOTO (GF_NFS, cache, out);
+ GF_VALIDATE_OR_GOTO (GF_NFS, cache->cache_dict, out);
+ GF_VALIDATE_OR_GOTO (GF_NFS, fh, out);
+ GF_VALIDATE_OR_GOTO (GF_NFS, host_addr, out);
+ GF_VALIDATE_OR_GOTO (GF_NFS, timestamp, out);
+ GF_VALIDATE_OR_GOTO (GF_NFS, can_write, out);
+
+ make_hashkey (hashkey, fh, host_addr);
+
+ entry_data = dict_get (cache->cache_dict, hashkey);
+ if (!entry_data) {
+ gf_log (GF_NFS, GF_LOG_DEBUG, "could not find entry for %s",
+ host_addr);
+ goto out;
+ }
+
+ lookup_res = (struct auth_cache_entry *)(entry_data->data);
+
+ if ((time (NULL) - lookup_res->timestamp) > cache->ttl_sec) {
+ gf_log (GF_NFS, GF_LOG_DEBUG, "entry for host %s has expired",
+ host_addr);
+ GF_FREE (lookup_res);
+ entry_data->data = NULL;
+ /* Remove from the cache */
+ dict_del (cache->cache_dict, hashkey);
+
+ ret = ENTRY_EXPIRED;
+ goto out;
+ }
+
+ *timestamp = lookup_res->timestamp;
+ *can_write = lookup_res->item->opts->rw;
+
+ ret = ENTRY_FOUND;
+out:
+ return ret;
+}
+
+/**
+ * auth_cache_purge -- Purge the dict in the cache and set
+ * the dict pointer to NULL. It will be allocated
+ * on the first insert into the dict.
+ *
+ * @cache: Cache to purge
+ *
+ */
+void
+auth_cache_purge (struct auth_cache *cache)
+{
+ dict_t *new_cache_dict = NULL;
+ dict_t *old_cache_dict = cache->cache_dict;
+
+ if (!cache || !cache->cache_dict)
+ goto out;
+
+ (void)__sync_lock_test_and_set (&cache->cache_dict, new_cache_dict);
+
+ dict_unref (old_cache_dict);
+out:
+ return;
+}
+
+/**
+ * is_nfs_fh_cached_and_writeable -- Checks if an NFS FH is cached for the given
+ * host
+ * @cache: The fh cache
+ * @host_addr: Address to use in lookup
+ * @fh: The fh to use in lookup
+ *
+ *
+ * @return: TRUE if cached, FALSE otherwise
+ *
+ */
+gf_boolean_t
+is_nfs_fh_cached (struct auth_cache *cache, struct nfs3_fh *fh,
+ const char *host_addr)
+{
+ int ret = 0;
+ time_t timestamp = 0;
+ gf_boolean_t cached = _gf_false;
+ gf_boolean_t can_write = _gf_false;
+
+ if (!fh)
+ goto out;
+
+ ret = auth_cache_lookup (cache, fh, host_addr, &timestamp, &can_write);
+ cached = (ret == ENTRY_FOUND);
+
+out:
+ return cached;
+}
+
+
+/**
+ * is_nfs_fh_cached_and_writeable -- Checks if an NFS FH is cached for the given
+ * host and writable
+ * @cache: The fh cache
+ * @host_addr: Address to use in lookup
+ * @fh: The fh to use in lookup
+ *
+ *
+ * @return: TRUE if cached & writable, FALSE otherwise
+ *
+ */
+gf_boolean_t
+is_nfs_fh_cached_and_writeable (struct auth_cache *cache, struct nfs3_fh *fh,
+ const char *host_addr)
+{
+ int ret = 0;
+ time_t timestamp = 0;
+ gf_boolean_t cached = _gf_false;
+ gf_boolean_t writable = _gf_false;
+
+ if (!fh)
+ goto out;
+
+ ret = auth_cache_lookup (cache, fh, host_addr, &timestamp, &writable);
+ cached = ((ret == ENTRY_FOUND) && writable);
+
+out:
+ return cached;
+}
+
+/**
+ * cache_nfs_fh -- Places the nfs file handle in the underlying dict as we are
+ * using as our cache. The key is "exportid:gfid:host_addr", the
+ * value is an entry struct containing the export item that
+ * was authorized for the operation and the file handle that was
+ * authorized.
+ *
+ * @cache: The cache to place fh's in
+ * @fh : The fh to cache
+ * @host_addr: The address of the host
+ * @export_item: The export item that was authorized
+ *
+ */
+int
+cache_nfs_fh (struct auth_cache *cache, struct nfs3_fh *fh,
+ const char *host_addr, struct export_item *export_item)
+{
+ int ret = -EINVAL;
+ char *hashkey = NULL;
+ data_t *entry_data = NULL;
+ time_t timestamp = 0;
+ gf_boolean_t can_write = _gf_false;
+ struct auth_cache_entry *entry = NULL;
+
+ GF_VALIDATE_OR_GOTO (GF_NFS, host_addr, out);
+ GF_VALIDATE_OR_GOTO (GF_NFS, cache, out);
+ GF_VALIDATE_OR_GOTO (GF_NFS, fh, out);
+
+ /* If a dict has not been allocated already, allocate it. */
+ if (!cache->cache_dict) {
+ cache->cache_dict = dict_new ();
+ if (!cache->cache_dict) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ }
+
+ /* If we could already find it in the cache, just return */
+ ret = auth_cache_lookup (cache, fh, host_addr, &timestamp, &can_write);
+ if (ret == 0) {
+ gf_log (GF_NFS, GF_LOG_TRACE, "found cached auth/fh for host "
+ "%s", host_addr);
+ goto out;
+ }
+
+ make_hashkey (hashkey, fh, host_addr);
+
+ entry = auth_cache_entry_init ();
+ if (!entry) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ entry->timestamp = time (NULL);
+ entry->item = export_item;
+
+ /* The cache entry will simply be the time that the entry
+ * was cached.
+ */
+ entry_data = bin_to_data (entry, sizeof (*entry));
+ if (!entry_data) {
+ GF_FREE (entry);
+ goto out;
+ }
+
+ ret = dict_set (cache->cache_dict, hashkey, entry_data);
+ if (ret == -1) {
+ GF_FREE (entry);
+ goto out;
+ }
+ gf_log (GF_NFS, GF_LOG_TRACE, "Caching file-handle (%s)", host_addr);
+ ret = 0;
+out:
+ return ret;
+}
diff --git a/xlators/nfs/server/src/auth-cache.h b/xlators/nfs/server/src/auth-cache.h
new file mode 100644
index 00000000000..5f2f03c1cb8
--- /dev/null
+++ b/xlators/nfs/server/src/auth-cache.h
@@ -0,0 +1,53 @@
+/*
+ Copyright 2014-present Facebook. All Rights Reserved
+
+ This file is part of GlusterFS.
+
+ Author :
+ Shreyas Siravara <shreyas.siravara@gmail.com>
+
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+*/
+
+#ifndef _AUTH_CACHE_H_
+#define _AUTH_CACHE_H_
+
+#include "nfs-mem-types.h"
+#include "mount3.h"
+#include "exports.h"
+#include "dict.h"
+#include "nfs3.h"
+
+struct auth_cache {
+ dict_t *cache_dict; /* Dict holding fh -> authcache_entry */
+ time_t ttl_sec; /* TTL of the auth cache in seconds */
+};
+
+
+/* Initializes the cache */
+struct auth_cache *
+auth_cache_init (time_t ttl_sec);
+
+/* Inserts FH into cache */
+int
+cache_nfs_fh (struct auth_cache *cache, struct nfs3_fh *fh,
+ const char *host_addr, struct export_item *export_item);
+
+/* Checks if the filehandle cached & writable */
+gf_boolean_t
+is_nfs_fh_cached_and_writeable (struct auth_cache *cache, struct nfs3_fh *fh,
+ const char *host_addr);
+
+/* Checks if the filehandle is cached */
+gf_boolean_t
+is_nfs_fh_cached (struct auth_cache *cache, struct nfs3_fh *fh,
+ const char *host_addr);
+
+/* Purge the cache */
+void
+auth_cache_purge (struct auth_cache *cache);
+
+#endif /* _AUTH_CACHE_H_ */
diff --git a/xlators/nfs/server/src/nfs-mem-types.h b/xlators/nfs/server/src/nfs-mem-types.h
index 79737633d24..6d4a2ed9cc2 100644
--- a/xlators/nfs/server/src/nfs-mem-types.h
+++ b/xlators/nfs/server/src/nfs-mem-types.h
@@ -50,6 +50,8 @@ enum gf_nfs_mem_types_ {
gf_nfs_mt_netgroups,
gf_nfs_mt_exports,
gf_nfs_mt_arr,
+ gf_nfs_mt_auth_cache,
+ gf_nfs_mt_auth_cache_entry,
gf_nfs_mt_end
};
#endif
diff --git a/xlators/nfs/server/src/nfs.h b/xlators/nfs/server/src/nfs.h
index 4c51d11d49c..7d5dfa63acb 100644
--- a/xlators/nfs/server/src/nfs.h
+++ b/xlators/nfs/server/src/nfs.h
@@ -41,6 +41,9 @@
/* Disable using the exports file by default */
#define GF_NFS_DEFAULT_EXPORT_AUTH 0
+#define GF_NFS_DEFAULT_AUTH_REFRESH_INTERVAL_SEC 2
+#define GF_NFS_DEFAULT_AUTH_CACHE_TTL_SEC 300 /* 5 min */
+
/* This corresponds to the max 16 number of group IDs that are sent through an
* RPC request. Since NFS is the only one going to set this, we can be safe
* in keeping this size hardcoded.