Whamcloud - gitweb
LU-3527 nodemap: add nodemap kernel module
[fs/lustre-release.git] / lustre / nodemap / nodemap_handler.c
diff --git a/lustre/nodemap/nodemap_handler.c b/lustre/nodemap/nodemap_handler.c
new file mode 100644 (file)
index 0000000..d261d65
--- /dev/null
@@ -0,0 +1,400 @@
+/*
+ * GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * GPL HEADER END
+ */
+/*
+ * Copyright (C) 2013, Trustees of Indiana University
+ * Author: Joshua Walgenbach <jjw@iu.edu>
+ */
+#include <linux/module.h>
+#include <lustre_net.h>
+#include "nodemap_internal.h"
+
+#define HASH_NODEMAP_BKT_BITS 3
+#define HASH_NODEMAP_CUR_BITS 3
+#define HASH_NODEMAP_MAX_BITS 7
+
+#define DEFAULT_NODEMAP "default"
+
+/* nodemap proc root proc directory under fs/lustre */
+struct proc_dir_entry *proc_lustre_nodemap_root;
+
+/* Highest numerical lu_nodemap.nm_id defined */
+static atomic_t nodemap_highest_id;
+
+/* Simple flag to determine if nodemaps are active */
+bool nodemap_idmap_active;
+
+/**
+ * pointer to default nodemap kept to keep from
+ * lookup it up in the hash since it is needed
+ * more often
+ */
+static struct lu_nodemap *default_nodemap;
+
+/**
+ * Hash keyed on nodemap name containing all
+ * nodemaps
+ */
+static cfs_hash_t *nodemap_hash;
+
+/**
+ * Nodemap destructor
+ *
+ * \param      nodemap         nodemap to destroy
+ */
+static void nodemap_destroy(struct lu_nodemap *nodemap)
+{
+       lprocfs_remove(&(nodemap->nm_proc_entry));
+       OBD_FREE_PTR(nodemap);
+}
+
+/**
+ * Functions used for the cfs_hash
+ */
+static void nodemap_getref(struct lu_nodemap *nodemap)
+{
+       CDEBUG(D_INFO, "nodemap %p\n", nodemap);
+       atomic_inc(&nodemap->nm_refcount);
+}
+
+void nodemap_putref(struct lu_nodemap *nodemap)
+{
+       LASSERT(nodemap != NULL);
+       LASSERT(cfs_atomic_read(&nodemap->nm_refcount) > 0);
+
+       if (atomic_dec_and_test(&nodemap->nm_refcount))
+               nodemap_destroy(nodemap);
+}
+
+static __u32 nodemap_hashfn(cfs_hash_t *hash_body,
+                           const void *key, unsigned mask)
+{
+       const struct lu_nodemap *nodemap = key;
+
+       return cfs_hash_djb2_hash(nodemap->nm_name, strlen(nodemap->nm_name),
+                                 mask);
+}
+
+static void *nodemap_hs_key(cfs_hlist_node_t *hnode)
+{
+       struct lu_nodemap *nodemap;
+
+       nodemap = cfs_hlist_entry(hnode, struct lu_nodemap, nm_hash);
+       return nodemap->nm_name;
+}
+
+static int nodemap_hs_keycmp(const void *key,
+                            cfs_hlist_node_t *compared_hnode)
+{
+       struct lu_nodemap *nodemap;
+
+       nodemap = nodemap_hs_key(compared_hnode);
+       return !strcmp(key, nodemap->nm_name);
+}
+
+static void *nodemap_hs_hashobject(cfs_hlist_node_t *hnode)
+{
+       return cfs_hlist_entry(hnode, struct lu_nodemap, nm_hash);
+}
+
+static void nodemap_hs_get(cfs_hash_t *hs, cfs_hlist_node_t *hnode)
+{
+       struct lu_nodemap *nodemap;
+
+       nodemap = cfs_hlist_entry(hnode, struct lu_nodemap, nm_hash);
+       nodemap_getref(nodemap);
+}
+
+static void nodemap_hs_put_locked(cfs_hash_t *hs,
+                                 cfs_hlist_node_t *hnode)
+{
+       struct lu_nodemap *nodemap;
+
+       nodemap = cfs_hlist_entry(hnode, struct lu_nodemap, nm_hash);
+       nodemap_putref(nodemap);
+}
+
+static cfs_hash_ops_t nodemap_hash_operations = {
+       .hs_hash        = nodemap_hashfn,
+       .hs_key         = nodemap_hs_key,
+       .hs_keycmp      = nodemap_hs_keycmp,
+       .hs_object      = nodemap_hs_hashobject,
+       .hs_get         = nodemap_hs_get,
+       .hs_put_locked  = nodemap_hs_put_locked,
+};
+
+/* end of cfs_hash functions */
+
+/**
+ * Helper iterator to clean up nodemap on module exit.
+ *
+ * \param      hs              hash structure
+ * \param      bd              bucket descriptor
+ * \param      hnode           hash node
+ * \param      data            not used here
+ */
+static int nodemap_cleanup_iter_cb(cfs_hash_t *hs, cfs_hash_bd_t *bd,
+                                  cfs_hlist_node_t *hnode, void *data)
+{
+       struct lu_nodemap *nodemap;
+
+       nodemap = cfs_hlist_entry(hnode, struct lu_nodemap, nm_hash);
+       nodemap_putref(nodemap);
+
+       return 0;
+}
+
+/**
+ * Walk the nodemap_hash and remove all nodemaps.
+ */
+void nodemap_cleanup_all(void)
+{
+       cfs_hash_for_each_safe(nodemap_hash, nodemap_cleanup_iter_cb, NULL);
+       cfs_hash_putref(nodemap_hash);
+}
+
+/**
+ * Initialize nodemap_hash
+ *
+ * \retval     0               success
+ * \retval     -ENOMEM         cannot create hash
+ */
+static int nodemap_init_hash(void)
+{
+       nodemap_hash = cfs_hash_create("NODEMAP", HASH_NODEMAP_CUR_BITS,
+                                      HASH_NODEMAP_MAX_BITS,
+                                      HASH_NODEMAP_BKT_BITS, 0,
+                                      CFS_HASH_MIN_THETA,
+                                      CFS_HASH_MAX_THETA,
+                                      &nodemap_hash_operations,
+                                      CFS_HASH_DEFAULT);
+
+       if (nodemap_hash == NULL) {
+               CERROR("cannot create nodemap_hash table\n");
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+/**
+ * Check for valid nodemap name
+ *
+ * \param      name            nodemap name
+ * \retval     true            valid
+ * \retval     false           invalid
+ */
+static bool nodemap_name_is_valid(const char *name)
+{
+       for (; *name != '\0'; name++) {
+               if (!isalnum(*name) && *name != '_')
+                       return false;
+       }
+       return true;
+}
+
+/**
+ * Nodemap lookup
+ *
+ * Look nodemap up in the nodemap hash
+ *
+ * \param      name            name of nodemap
+ * \paramA     nodemap         found nodemap or NULL
+ * \retval     lu_nodemap      named nodemap
+ * \retval     NULL            nodemap doesn't exist
+ */
+static int nodemap_lookup(const char *name, struct lu_nodemap **nodemap)
+{
+       int rc = 0;
+
+       if (!nodemap_name_is_valid(name))
+               GOTO(out, rc = -EINVAL);
+
+       *nodemap = cfs_hash_lookup(nodemap_hash, name);
+
+out:
+       return rc;
+}
+
+/**
+ * Nodemap constructor
+ *
+ * Creates an lu_nodemap structure and assigns sane default
+ * member values. If this is the default nodemap, the defaults
+ * are the most restictive in xterms of mapping behavior. Otherwise
+ * the default flags should be inherited from the default nodemap.
+ * The adds nodemap to nodemap_hash.
+ *
+ * \param      name            name of nodemap
+ * \param      is_default      true if default nodemap
+ * \retval     0               success
+ * \retval     -EINVAL         invalid nodemap name
+ * \retval     -EEXIST         nodemap already exists
+ * \retval     -ENOMEM         cannot allocate memory for nodemap
+ */
+static int nodemap_create(const char *name, bool is_default)
+{
+       struct  lu_nodemap *nodemap = NULL;
+       int     rc = 0;
+
+       rc = nodemap_lookup(name, &nodemap);
+       if (rc < 0)
+               goto out;
+
+       if (nodemap != NULL) {
+               nodemap_putref(nodemap);
+               GOTO(out, rc = -EEXIST);
+       }
+
+       OBD_ALLOC_PTR(nodemap);
+
+       if (nodemap == NULL) {
+               CERROR("cannot allocate memory (%zu bytes)"
+                      "for nodemap '%s'\n", sizeof(*nodemap),
+                      name);
+               GOTO(out, rc = -ENOMEM);
+       }
+
+       snprintf(nodemap->nm_name, sizeof(nodemap->nm_name), "%s", name);
+
+       INIT_LIST_HEAD(&(nodemap->nm_ranges));
+       nodemap->nm_local_to_remote_uidmap = RB_ROOT;
+       nodemap->nm_remote_to_local_uidmap = RB_ROOT;
+       nodemap->nm_local_to_remote_gidmap = RB_ROOT;
+       nodemap->nm_remote_to_local_gidmap = RB_ROOT;
+
+       if (is_default) {
+               nodemap->nm_id = LUSTRE_NODEMAP_DEFAULT_ID;
+               nodemap->nmf_trust_client_ids = 0;
+               nodemap->nmf_allow_root_access = 0;
+               nodemap->nmf_block_lookups = 0;
+
+               nodemap->nm_squash_uid = NODEMAP_NOBODY_UID;
+               nodemap->nm_squash_gid = NODEMAP_NOBODY_GID;
+
+               lprocfs_nodemap_register(name, is_default, nodemap);
+
+               default_nodemap = nodemap;
+       } else {
+               nodemap->nm_id = atomic_inc_return(&nodemap_highest_id);
+               nodemap->nmf_trust_client_ids =
+                               default_nodemap->nmf_trust_client_ids;
+               nodemap->nmf_allow_root_access =
+                               default_nodemap->nmf_allow_root_access;
+               nodemap->nmf_block_lookups =
+                               default_nodemap->nmf_block_lookups;
+
+               nodemap->nm_squash_uid = default_nodemap->nm_squash_uid;
+               nodemap->nm_squash_gid = default_nodemap->nm_squash_gid;
+
+               lprocfs_nodemap_register(name, is_default, nodemap);
+       }
+
+       atomic_set(&nodemap->nm_refcount, 1);
+       rc = cfs_hash_add_unique(nodemap_hash, name, &nodemap->nm_hash);
+
+       if (rc == 0)
+               goto out;
+
+       CERROR("cannot add nodemap: '%s': rc = %d\n", name, rc);
+       nodemap_destroy(nodemap);
+
+out:
+       return rc;
+}
+
+/**
+ * Add a nodemap
+ *
+ * \param      name            name of nodemap
+ * \retval     0               success
+ * \retval     -EINVAL         invalid nodemap name
+ * \retval     -EEXIST         nodemap already exists
+ * \retval     -ENOMEM         cannot allocate memory for nodemap
+ */
+int nodemap_add(const char *name)
+{
+       return nodemap_create(name, 0);
+}
+EXPORT_SYMBOL(nodemap_add);
+
+/**
+ * Delete a nodemap
+ *
+ * \param      name            name of nodemmap
+ * \retval     0               success
+ * \retval     -EINVAL         invalid input
+ * \retval     -ENOENT         no existing nodemap
+ */
+int nodemap_del(const char *name)
+{
+       struct  lu_nodemap *nodemap;
+       int     rc = 0;
+
+       if (strcmp(name, DEFAULT_NODEMAP) == 0)
+               GOTO(out, rc = -EINVAL);
+
+       nodemap = cfs_hash_del_key(nodemap_hash, name);
+       if (nodemap == NULL)
+               GOTO(out, rc = -ENOENT);
+
+       nodemap_putref(nodemap);
+out:
+       return rc;
+}
+EXPORT_SYMBOL(nodemap_del);
+
+/**
+ * Cleanup nodemap module on exit
+ */
+static void nodemap_mod_exit(void)
+{
+       nodemap_cleanup_all();
+       lprocfs_remove(&proc_lustre_nodemap_root);
+}
+
+/**
+ * Initialize the nodemap module
+ */
+static int __init nodemap_mod_init(void)
+{
+       int rc = 0;
+
+       rc = nodemap_init_hash();
+       if (rc != 0)
+               goto cleanup;
+
+       nodemap_procfs_init();
+       rc = nodemap_create(DEFAULT_NODEMAP, 1);
+
+cleanup:
+       if (rc != 0)
+               nodemap_mod_exit();
+
+       return rc;
+}
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Lustre Client Nodemap Management Module");
+MODULE_AUTHOR("Joshua Walgenbach <jjw@iu.edu>");
+
+module_init(nodemap_mod_init);
+module_exit(nodemap_mod_exit);