Whamcloud - gitweb
LU-3527 nodemap: add nodemap kernel module 34/8034/16
authorJoshua Walgenbach <jjw@iu.edu>
Thu, 28 Nov 2013 20:18:53 +0000 (21:18 +0100)
committerOleg Drokin <oleg.drokin@intel.com>
Fri, 10 Jan 2014 21:06:26 +0000 (21:06 +0000)
The nodemap kernel module manages groups of mounted clients
and allows policies to be applied to them. A nodemap will be
defined as a nodemap name, and id, a tree of NID ranges that
represents the clients that are included in the nodemap, and
values that represent a policy for the behavior of the
filesystem with respect to those clients.

Initially, the policies implemented for nodemap will be static
UID/GID mapping from client IDs to a canonical filesystem IDs.
Additional flags are provided to allow the filesystem to trust
the IDs from the client (apply no mapping) and allow UID 0
(rootsquash applied to an entire nodemap).

A default nodemap is automatically provided which implicitly
contains all the clients not otherwise specified by an NID
range.

Nodemap will allow the unmapped UID/GIDs to be specified on a
case by case basis.

Nodemaps will be managed on the MGS, and configurations pushed
out the the other servers in the filesystem.

This patch adds nodemap to the build system, and defines the
basic operation for managing the addition and deletion of
the nodemap definitions.

The ioctl for management of the nodemaps from userspace was
added. The commands for adding and removing nodemaps were
added to lctl, and the handlers in the mgs.

The data structures for the module were added in
lustre/include/lustre_nodemap.

Additions were made to the make system and the m4 macros
to build nodemap with the rest of lustre.

Unit tests for adding and removing nodemaps were added
to sanity-sec.sh.

Range and idmap management functions will be added in the
two subsquent patches.

Signed-off-by: Joshua Walgenbach <jjw@iu.edu>
Change-Id: I2d34fde7aae3c2b4af512ff2c1ace5115ed40a6a
Reviewed-on: http://review.whamcloud.com/8034
Tested-by: Jenkins
Reviewed-by: Andreas Dilger <andreas.dilger@intel.com>
Reviewed-by: Andrew Perepechko <andrew_perepechko@xyratex.com>
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: John L. Hammond <john.hammond@intel.com>
Reviewed-by: James Simmons <uja.ornl@gmail.com>
27 files changed:
config/lustre-build.m4
lustre/Makefile.in
lustre/autoMakefile.am
lustre/autoconf/lustre-core.m4
lustre/include/Makefile.am
lustre/include/lustre/lustreapi.h
lustre/include/lustre_cfg.h
lustre/include/lustre_export.h
lustre/include/lustre_lib.h
lustre/include/lustre_nodemap.h [new file with mode: 0644]
lustre/mgs/mgs_handler.c
lustre/mgs/mgs_internal.h
lustre/mgs/mgs_llog.c
lustre/nodemap/Makefile.in [new file with mode: 0644]
lustre/nodemap/autoMakefile.am [new file with mode: 0644]
lustre/nodemap/nodemap_handler.c [new file with mode: 0644]
lustre/nodemap/nodemap_internal.h [new file with mode: 0644]
lustre/nodemap/nodemap_lproc.c [new file with mode: 0644]
lustre/tests/sanity-sec.sh
lustre/tests/test-framework.sh
lustre/utils/Makefile.am
lustre/utils/lctl.c
lustre/utils/liblustreapi.c
lustre/utils/liblustreapi_nodemap.c [new file with mode: 0644]
lustre/utils/lustreapi_internal.h
lustre/utils/obd.c
lustre/utils/obdctl.h

index 78fe111..d5d9220 100644 (file)
@@ -660,6 +660,7 @@ LB_CONFIG_SERVERS
 
 # two macros for cmd3
 m4_ifdef([LC_CONFIG_SPLIT], [LC_CONFIG_SPLIT])
+m4_ifdef([LC_NODEMAP_PROC_DEBUG], [LC_NODEMAP_PROC_DEBUG])
 LN_CONFIG_CDEBUG
 LC_QUOTA
 
index 2794a62..bbe0232 100644 (file)
@@ -3,8 +3,9 @@ subdir-m += obdclass
 subdir-m += ptlrpc
 subdir-m += obdecho
 subdir-m += mgc
+subdir-m += nodemap
 
-@SERVER_TRUE@subdir-m += ost mgs mdt mdd ofd quota osp lod lfsck
+@SERVER_TRUE@subdir-m += ost mgs mdt mdd ofd quota osp lod lfsck nodemap
 @CLIENT_TRUE@subdir-m += lov osc mdc lmv llite fld
 @LDISKFS_ENABLED_TRUE@subdir-m += osd-ldiskfs
 @ZFS_ENABLED_TRUE@subdir-m += osd-zfs
index 039bcc6..ede719e 100644 (file)
@@ -43,7 +43,7 @@ ALWAYS_SUBDIRS = include obdclass ldlm ptlrpc obdecho \
        mgc fid fld doc utils tests scripts autoconf contrib conf
 
 SERVER_SUBDIRS = ost mgs mdt mdd ofd osd-zfs osd-ldiskfs \
-       quota osp lod target lfsck
+       quota osp lod target lfsck nodemap
 
 CLIENT_SUBDIRS = mdc lmv llite lclient lov osc
 
index 87cadc7..962d0b7 100644 (file)
@@ -1595,6 +1595,23 @@ fi
 ])
 
 #
+# LC_CONFIG_NODEMAP_PROC_DEBUG
+#
+# enable nodemap proc file debugging
+#
+AC_DEFUN([LC_NODEMAP_PROC_DEBUG],
+[AC_MSG_CHECKING([whether to enable nodemap proc debug])
+AC_ARG_ENABLE([nodemap_proc_debug],
+        AC_HELP_STRING([--enable-nodemap-proc-debug],
+                        [enable nodemap proc debug]),
+        [],[enable_nodemap_proc_debug='no'])
+AC_MSG_RESULT([$enable_nodemap_proc_debug])
+if test x$enable_nodemap_proc_debug != xno; then
+   AC_DEFINE(NODEMAP_PROC_DEBUG, 1, [enable nodemap proc debug support])
+fi
+])
+
+#
 # LC_LLITE_LLOOP_MODULE
 # lloop_llite.ko does not currently work with page sizes
 # of 64k or larger.
@@ -1844,6 +1861,8 @@ lustre/lfsck/Makefile
 lustre/lfsck/autoMakefile
 lustre/mdt/Makefile
 lustre/mdt/autoMakefile
+lustre/nodemap/Makefile
+lustre/nodemap/autoMakefile
 lustre/mdd/Makefile
 lustre/mdd/autoMakefile
 lustre/fld/Makefile
index 2312a20..125669d 100644 (file)
@@ -74,6 +74,7 @@ EXTRA_DIST = \
        lustre_mdc.h \
        lustre_mds.h \
        lustre_net.h \
+       lustre_nodemap.h \
        lustre_param.h \
        lustre_quota.h \
        lustre_req_layout.h \
index 3eb04a5..f4e92c2 100644 (file)
@@ -242,6 +242,7 @@ extern void llapi_ping_target(char *obd_type, char *obd_name,
                               char *obd_uuid, void *args);
 
 extern int llapi_search_rootpath(char *pathname, const char *fsname);
+extern int llapi_nodemap_exists(const char *name);
 
 struct mntent;
 #define HAVE_LLAPI_IS_LUSTRE_MNT
index bde93b6..1aebf8b 100644 (file)
@@ -90,6 +90,21 @@ enum lcfg_command_type {
                                              * cleanup cleanup */
        LCFG_SET_PARAM          = 0x00ce032, /**< use set_param syntax to set
                                              *a proc parameters */
+       LCFG_NODEMAP_ADD        = 0x00ce040, /**< create a cluster */
+       LCFG_NODEMAP_DEL        = 0x00ce041, /**< destroy a cluster */
+       LCFG_NODEMAP_ADD_RANGE  = 0x00ce042, /**< add a nid range */
+       LCFG_NODEMAP_DEL_RANGE  = 0x00ce043, /**< delete an nid range */
+       LCFG_NODEMAP_ADD_UIDMAP = 0x00ce044, /**< add a uidmap */
+       LCFG_NODEMAP_DEL_UIDMAP = 0x00ce045, /**< delete a uidmap */
+       LCFG_NODEMAP_ADD_GIDMAP = 0x00ce046, /**< add a gidmap */
+       LCFG_NODEMAP_DEL_GIDMAP = 0x00ce047, /**< delete a gidmap */
+       LCFG_NODEMAP_ACTIVATE   = 0x00ce048, /**< activate cluster id mapping */
+       LCFG_NODEMAP_ADMIN      = 0x00ce049, /**< allow cluster to use id 0 */
+       LCFG_NODEMAP_TRUSTED    = 0x00ce050, /**< trust a clusters ids */
+       LCFG_NODEMAP_SQUASH_UID = 0x00ce051, /**< default map uid */
+       LCFG_NODEMAP_SQUASH_GID = 0x00ce052, /**< default map gid */
+       LCFG_NODEMAP_ADD_SHKEY  = 0x00ce053, /**< add shared key to cluster */
+       LCFG_NODEMAP_DEL_SHKEY  = 0x00ce054, /**< delete shared key from cluster */
 };
 
 struct lustre_cfg_bufs {
index 4377963..44f18f3 100644 (file)
@@ -261,6 +261,8 @@ struct obd_export {
                 struct ec_export_data     eu_ec_data;
                 struct mgs_export_data    eu_mgs_data;
         } u;
+
+       struct nodemap            *exp_nodemap;
 };
 
 #define exp_target_data u.eu_target_data
index f0e6f37..9ba7cd8 100644 (file)
@@ -546,6 +546,7 @@ static inline void obd_ioctl_freedata(char *buf, int len)
 #define OBD_IOC_LLOG_CHECK             _IOWR('f', 195, OBD_IOC_DATA_TYPE)
 /* OBD_IOC_LLOG_CATINFO is deprecated */
 #define OBD_IOC_LLOG_CATINFO           _IOWR('f', 196, OBD_IOC_DATA_TYPE)
+#define OBD_IOC_NODEMAP                        _IOWR('f', 197, OBD_IOC_DATA_TYPE)
 
 #define ECHO_IOC_GET_STRIPE            _IOWR('f', 200, OBD_IOC_DATA_TYPE)
 #define ECHO_IOC_SET_STRIPE            _IOWR('f', 201, OBD_IOC_DATA_TYPE)
diff --git a/lustre/include/lustre_nodemap.h b/lustre/include/lustre_nodemap.h
new file mode 100644 (file)
index 0000000..a9ebad3
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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.sun.com/software/products/lustre/docs/GPLv2.pdf
+ *
+ * GPL HEADER END
+ */
+/*
+ * Copyright (C) 2013, Trustees of Indiana University
+ * Author: Joshua Walgenbach <jjw@iu.edu>
+ */
+
+#ifndef _LUSTRE_NODEMAP_H
+#define _LUSTRE_NODEMAP_H
+
+#define LUSTRE_NODEMAP_NAME "nodemap"
+#define LUSTRE_NODEMAP_NAME_LENGTH 16
+
+#define LUSTRE_NODEMAP_DEFAULT_ID 0
+
+/** The nodemap id 0 will be the default nodemap. It will have a configuration
+ * set by the MGS, but no ranges will be allowed as all NIDs that do not map
+ * will be added to the default nodemap
+ */
+
+struct lu_nodemap {
+       /* human readable ID */
+       char                    nm_name[LUSTRE_NODEMAP_NAME_LENGTH + 1];
+       /* flags to govern nodemap behavior */
+       bool                    nmf_trust_client_ids:1,
+                               nmf_allow_root_access:1,
+                               nmf_block_lookups:1,
+                               nmf_hmac_required:1,
+                               nmf_encryption_required:1;
+       /* unique ID set by MGS */
+       int                     nm_id;
+       /* nodemap ref counter */
+       atomic_t                nm_refcount;
+       /* UID to squash unmapped UIDs */
+       uid_t                   nm_squash_uid;
+       /* GID to squash unmapped GIDs */
+       gid_t                   nm_squash_gid;
+       /* NID range list */
+       struct list_head        nm_ranges;
+       /* UID map keyed by local UID */
+       struct rb_root          nm_local_to_remote_uidmap;
+       /* UID map keyed by remote UID */
+       struct rb_root          nm_remote_to_local_uidmap;
+       /* GID map keyed by local UID */
+       struct rb_root          nm_local_to_remote_gidmap;
+       /* GID map keyed by remote UID */
+       struct rb_root          nm_remote_to_local_gidmap;
+       /* proc directory entry */
+       struct proc_dir_entry   *nm_proc_entry;
+       /* attached client members of this nodemap */
+       struct list_head        nm_exports;
+       /* access by nodemap name */
+       cfs_hlist_node_t        nm_hash;
+};
+
+int nodemap_add(const char *nodemap_name);
+int nodemap_del(const char *nodemap_name);
+
+#endif
index 560dd19..5be9040 100644 (file)
@@ -620,6 +620,60 @@ static int mgs_extract_fs_pool(char * arg, char *fsname, char *poolname)
         RETURN(0);
 }
 
+static int mgs_iocontrol_nodemap(const struct lu_env *env,
+                                struct mgs_device *mgs,
+                                struct obd_ioctl_data *data)
+{
+       struct lustre_cfg *lcfg = NULL;
+       const char *nodemap_name;
+       char *param = NULL;
+       __u32 cmd;
+       int rc = 0;
+       ENTRY;
+
+       if (data->ioc_type != LUSTRE_CFG_TYPE) {
+               CERROR("%s: unknown cfg record type: %d\n",
+                      mgs->mgs_obd->obd_name, data->ioc_type);
+               GOTO(out, rc = -EINVAL);
+       }
+
+       if (data->ioc_plen1 > PAGE_CACHE_SIZE)
+               GOTO(out, rc = -E2BIG);
+
+       OBD_ALLOC(lcfg, data->ioc_plen1);
+       if (lcfg == NULL)
+               GOTO(out, rc = -ENOMEM);
+
+       if (copy_from_user(lcfg, data->ioc_pbuf1, data->ioc_plen1))
+               GOTO(out_lcfg, rc = -EFAULT);
+
+       nodemap_name = lustre_cfg_string(lcfg, 1);
+       cmd = lcfg->lcfg_command;
+
+       switch (cmd) {
+       case LCFG_NODEMAP_ADD:
+       case LCFG_NODEMAP_DEL:
+               if (lcfg->lcfg_bufcount != 2)
+                       GOTO(out_lcfg, rc = -EINVAL);
+               rc = mgs_nodemap_cmd(env, mgs, cmd, nodemap_name, param);
+               break;
+       default:
+               rc = -ENOTTY;
+       }
+
+       if (rc != 0) {
+               CERROR("%s: OBD_IOC_NODEMAP command %X for %s: rc = %d\n",
+                      mgs->mgs_obd->obd_name, lcfg->lcfg_command,
+                      nodemap_name, rc);
+               GOTO(out_lcfg, rc);
+       }
+
+out_lcfg:
+       OBD_FREE(lcfg, data->ioc_plen1);
+out:
+       RETURN(rc);
+}
+
 static int mgs_iocontrol_pool(const struct lu_env *env,
                              struct mgs_device *mgs,
                               struct obd_ioctl_data *data)
@@ -792,8 +846,12 @@ out_free:
                rc = mgs_iocontrol_pool(&env, mgs, data);
                break;
 
-        case OBD_IOC_DUMP_LOG: {
-                struct llog_ctxt *ctxt;
+       case OBD_IOC_NODEMAP:
+               rc = mgs_iocontrol_nodemap(&env, mgs, data);
+               break;
+
+       case OBD_IOC_DUMP_LOG: {
+               struct llog_ctxt *ctxt;
 
                ctxt = llog_get_context(mgs->mgs_obd, LLOG_CONFIG_ORIG_CTXT);
                rc = class_config_dump_llog(&env, ctxt, data->ioc_inlbuf1,
index 514dc23..7f004e7 100644 (file)
@@ -40,6 +40,7 @@
 #include <libcfs/libcfs.h>
 #include <lustre_log.h>
 #include <lustre_export.h>
+#include <lustre_nodemap.h>
 #include <dt_object.h>
 
 #define MGSSELF_NAME    "_mgs"
@@ -207,6 +208,9 @@ int mgs_list_logs(const struct lu_env *env, struct mgs_device *mgs,
 int mgs_pool_cmd(const struct lu_env *env, struct mgs_device *mgs,
                 enum lcfg_command_type cmd, char *poolname, char *fsname,
                 char *ostname);
+int mgs_nodemap_cmd(const struct lu_env *env, struct mgs_device *mgs,
+                   enum lcfg_command_type cmd, const char *nodemap_name,
+                   const char *param);
 
 /* mgs_handler.c */
 int  mgs_get_lock(struct obd_device *obd, struct ldlm_res_id *res,
index 9b0201f..3133b24 100644 (file)
@@ -3892,6 +3892,27 @@ out:
         return rc;
 }
 
+int mgs_nodemap_cmd(const struct lu_env *env, struct mgs_device *mgs,
+                   enum lcfg_command_type cmd, const char *nodemap_name,
+                   const char *param)
+{
+       int rc = 0;
+       ENTRY;
+
+       switch (cmd) {
+       case LCFG_NODEMAP_ADD:
+               rc = nodemap_add(nodemap_name);
+               break;
+       case LCFG_NODEMAP_DEL:
+               rc = nodemap_del(nodemap_name);
+               break;
+       default:
+               rc = -EINVAL;
+       }
+
+       RETURN(rc);
+}
+
 int mgs_pool_cmd(const struct lu_env *env, struct mgs_device *mgs,
                 enum lcfg_command_type cmd, char *fsname,
                 char *poolname, char *ostname)
diff --git a/lustre/nodemap/Makefile.in b/lustre/nodemap/Makefile.in
new file mode 100644 (file)
index 0000000..fb34169
--- /dev/null
@@ -0,0 +1,4 @@
+MODULES := nodemap
+nodemap-objs := nodemap_handler.o nodemap_lproc.o
+
+@INCLUDE_RULES@
diff --git a/lustre/nodemap/autoMakefile.am b/lustre/nodemap/autoMakefile.am
new file mode 100644 (file)
index 0000000..ec793f6
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# 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
+
+if MODULES
+modulefs_DATA = nodemap$(KMODEXT)
+endif
+
+MOSTLYCLEANFILES := @MOSTLYCLEANFILES@
+EXTRA_DIST := $(nodemap-objs:%.o=%.c) nodemap_internal.h
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);
diff --git a/lustre/nodemap/nodemap_internal.h b/lustre/nodemap/nodemap_internal.h
new file mode 100644 (file)
index 0000000..77dbb27
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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>
+ */
+
+#ifndef _NODEMAP_INTERNAL_H
+#define _NODEMAP_INTERNAL_H
+
+#include <lustre_nodemap.h>
+
+#define MODULE_STRING "nodemap"
+
+/* Default nobody uid and gid values */
+
+#define NODEMAP_NOBODY_UID 99
+#define NODEMAP_NOBODY_GID 99
+
+struct lprocfs_static_vars;
+
+/* nodemap root proc directory under fs/lustre */
+extern struct proc_dir_entry *proc_lustre_nodemap_root;
+/* flag if nodemap is active */
+extern bool nodemap_idmap_active;
+
+int nodemap_procfs_init(void);
+int lprocfs_nodemap_register(const char *name, bool is_default_nodemap,
+                            struct lu_nodemap *nodemap);
+int nodemap_cleanup_nodemaps(void);
+#endif  /* _NODEMAP_INTERNAL_H */
diff --git a/lustre/nodemap/nodemap_lproc.c b/lustre/nodemap/nodemap_lproc.c
new file mode 100644 (file)
index 0000000..540adad
--- /dev/null
@@ -0,0 +1,472 @@
+/*
+ * 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>
+ */
+
+#define NODEMAP_LPROC_ID_LEN 16
+#define NODEMAP_LPROC_FLAG_LEN 2
+
+#include <lprocfs_status.h>
+#include <lustre_net.h>
+#include "nodemap_internal.h"
+
+static int nodemap_rd_active(char *page, char **start, off_t off, int count,
+                            int *eof, void *data)
+{
+       int rc;
+
+       rc = snprintf(page, count, "%u\n", (unsigned int)nodemap_idmap_active);
+
+       if (count == 0)
+               return 0;
+
+       return rc;
+}
+
+static int nodemap_wr_active(struct file *file, const char __user *buffer,
+                            unsigned long count, void *data)
+{
+       char    active_string[NODEMAP_LPROC_FLAG_LEN + 1];
+       __u32   active;
+       int     rc = count;
+
+       if (count == 0)
+               return 0;
+
+       if (count > NODEMAP_LPROC_FLAG_LEN)
+               return -EINVAL;
+
+       if (copy_from_user(active_string, buffer, count))
+               return -EFAULT;
+
+       active_string[count] = '\0';
+       active = simple_strtoul(active_string, NULL, 10);
+       nodemap_idmap_active = active;
+
+       return rc;
+}
+
+static int nodemap_rd_id(char *page, char **start, off_t off, int count,
+                        int *eof, void *data)
+{
+       struct lu_nodemap *nodemap = data;
+
+       return snprintf(page, count, "%u\n", nodemap->nm_id);
+}
+
+static int nodemap_rd_squash_uid(char *page, char **start, off_t off,
+                                int count, int *eof, void *data)
+{
+       struct lu_nodemap *nodemap = data;
+
+       return snprintf(page, count, "%u\n", nodemap->nm_squash_uid);
+}
+
+static int nodemap_rd_squash_gid(char *page, char **start, off_t off,
+                                int count, int *eof, void *data)
+{
+       struct lu_nodemap *nodemap = data;
+
+       return snprintf(page, count, "%u\n", nodemap->nm_squash_gid);
+}
+
+static int nodemap_rd_trusted(char *page, char **start, off_t off,
+                             int count, int *eof, void *data)
+{
+       struct lu_nodemap *nodemap = data;
+
+       return snprintf(page, count, "%d\n",
+                       (int)nodemap->nmf_trust_client_ids);
+}
+
+static int nodemap_rd_admin(char *page, char **start, off_t off, int count,
+                           int *eof, void *data)
+{
+       struct lu_nodemap *nodemap = data;
+
+       return snprintf(page, count, "%d\n",
+                       (int)nodemap->nmf_allow_root_access);
+}
+
+#ifdef NODEMAP_PROC_DEBUG
+static int nodemap_proc_read_flag(const char __user *buffer,
+                                 unsigned long count, unsigned int *flag_p)
+{
+       char scratch[NODEMAP_LPROC_FLAG_LEN + 1];
+
+       if (count == 0)
+               return 0;
+
+       if (count > NODEMAP_LPROC_FLAG_LEN)
+               return -EINVAL;
+
+       if (copy_from_user(scratch, buffer, count))
+               return -EFAULT;
+
+       scratch[count] = '\0';
+       *flag_p = simple_strtoul(scratch, NULL, 10);
+
+       return 0;
+}
+
+static int nodemap_wr_squash_uid(struct file *file, const char __user *buffer,
+                                unsigned long count, void *data)
+{
+       char                    squash[NODEMAP_LPROC_ID_LEN + 1];
+       struct lu_nodemap       *nodemap = data;
+       uid_t                   squash_uid;
+       int                     rc = count;
+
+       if (count == 0)
+               return 0;
+
+       if (count > NODEMAP_LPROC_FLAG_LEN)
+               return -EINVAL;
+
+       if (copy_from_user(squash, buffer, count))
+               return -EFAULT;
+
+       squash[count] = '\0';
+       squash_uid = simple_strtoul(squash, NULL, 10);
+       nodemap->nm_squash_uid = squash_uid;
+
+       return rc;
+}
+
+static int nodemap_wr_squash_gid(struct file *file, const char __user *buffer,
+                                unsigned long count, void *data)
+{
+       char                    squash[NODEMAP_LPROC_ID_LEN + 1];
+       struct lu_nodemap       *nodemap = data;
+       gid_t                   squash_gid;
+       int                     rc = count;
+
+       if (count == 0)
+               return 0;
+
+       if (count > NODEMAP_LPROC_FLAG_LEN)
+               return -EINVAL;
+
+       if (copy_from_user(squash, buffer, count))
+               return -EFAULT;
+
+       squash[count] = '\0';
+       squash_gid = simple_strtoul(squash, NULL, 10);
+       nodemap->nm_squash_gid = squash_gid;
+
+       return rc;
+}
+
+static int nodemap_wr_trusted(struct file *file, const char __user *buffer,
+                             unsigned long count, void *data)
+{
+       struct lu_nodemap       *nodemap = data;
+       int                     flags;
+       int                     rc;
+
+       rc = nodemap_proc_read_flag(buffer, count, &flags);
+       if (rc == 0)
+               nodemap->nmf_trust_client_ids = !!flags;
+
+       return rc;
+}
+
+static int nodemap_wr_admin(struct file *file, const char __user *buffer,
+                           unsigned long count, void *data)
+{
+       struct lu_nodemap       *nodemap = data;
+       int                     flags;
+       int                     rc;
+
+       rc = nodemap_proc_read_flag(buffer, count, &flags);
+       if (rc == 0)
+               nodemap->nmf_allow_root_access = !!flags;
+
+       return rc;
+}
+
+static int nodemap_proc_add_nodemap(struct file *file,
+                                   const char __user *buffer,
+                                   unsigned long count, void *data)
+{
+       char    buf[LUSTRE_NODEMAP_NAME_LENGTH + 1];
+       char    *cpybuf = NULL;
+       char    *name;
+       char    *pos;
+       int     rc = count;
+
+       if (count == 0)
+               return 0;
+
+       if (count > LUSTRE_NODEMAP_NAME_LENGTH)
+               return -EINVAL;
+
+       if (copy_from_user(buf, buffer, count))
+               return -EFAULT;
+
+       buf[count] = '\0';
+       pos = strchr(buf, '\n');
+       if (pos != NULL)
+               *pos = '\0';
+
+       cpybuf = buf;
+       name = strsep(&cpybuf, " ");
+       if (name == NULL)
+               return -EINVAL;
+
+       rc = nodemap_add(name);
+       if (rc == 0)
+               rc = count;
+
+       return rc;
+}
+
+static int nodemap_proc_del_nodemap(struct file *file,
+                                   const char __user *buffer,
+                                   unsigned long count, void *data)
+{
+       char    buf[LUSTRE_NODEMAP_NAME_LENGTH + 1];
+       char    *cpybuf = NULL;
+       char    *name;
+       char    *pos;
+       int     rc = count;
+
+       if (count == 0)
+               return 0;
+
+       if (count > LUSTRE_NODEMAP_NAME_LENGTH)
+               return -EINVAL;
+
+       if (copy_from_user(buf, buffer, count))
+               return -EFAULT;
+
+       buf[count] = '\0';
+       pos = strchr(buf, '\n');
+       if (pos != NULL)
+               *pos = '\0';
+
+       cpybuf = buf;
+       name = strsep(&cpybuf, " ");
+       if (name == NULL)
+               return -EINVAL;
+
+       rc = nodemap_del(name);
+       if (rc == 0)
+               rc = count;
+
+       return rc;
+
+}
+#endif /* NODEMAP_PROC_DEBUG */
+
+static struct lprocfs_vars lprocfs_nodemap_module_vars[] = {
+       {
+               .name           = "active",
+               .read_fptr      = nodemap_rd_active,
+               .write_fptr     = nodemap_wr_active,
+       },
+#ifdef NODEMAP_PROC_DEBUG
+       {
+               .name           = "add_nodemap",
+               .write_fptr     = nodemap_proc_add_nodemap,
+       },
+       {
+               .name           = "remove_nodemap",
+               .write_fptr     = nodemap_proc_del_nodemap,
+       },
+#endif /* NODEMAP_PROC_DEBUG */
+       {
+               NULL
+       }
+};
+
+#ifdef NODEMAP_PROC_DEBUG
+static struct lprocfs_vars lprocfs_nodemap_vars[] = {
+       {
+               .name           = "id",
+               .read_fptr      = nodemap_rd_id,
+       },
+       {
+               .name           = "trusted_nodemap",
+               .read_fptr      = nodemap_rd_trusted,
+               .write_fptr     = nodemap_wr_trusted,
+       },
+       {
+               .name           = "admin_nodemap",
+               .read_fptr      = nodemap_rd_admin,
+               .write_fptr     = nodemap_wr_admin,
+       },
+       {
+               .name           = "squash_uid",
+               .read_fptr      = nodemap_rd_squash_uid,
+               .write_fptr     = nodemap_wr_squash_uid,
+       },
+       {
+               .name           = "squash_gid",
+               .read_fptr      = nodemap_rd_squash_gid,
+               .write_fptr     = nodemap_wr_squash_gid,
+       },
+       {
+               NULL
+       }
+};
+
+static struct lprocfs_vars lprocfs_default_nodemap_vars[] = {
+       {
+               .name           = "id",
+               .read_fptr      = nodemap_rd_id,
+       },
+       {
+               .name           = "trusted_nodemap",
+               .read_fptr      = nodemap_rd_trusted,
+               .write_fptr     = nodemap_wr_trusted,
+       },
+       {
+               .name           = "admin_nodemap",
+               .read_fptr      = nodemap_rd_admin,
+               .write_fptr     = nodemap_wr_admin,
+       },
+       {
+               .name           = "squash_uid",
+               .read_fptr      = nodemap_rd_squash_uid,
+               .write_fptr     = nodemap_wr_squash_uid,
+       },
+       {
+               .name           = "squash_gid",
+               .read_fptr      = nodemap_rd_squash_gid,
+               .write_fptr     = nodemap_wr_squash_gid,
+       },
+       {
+               NULL
+       }
+};
+#else
+static struct lprocfs_vars lprocfs_nodemap_vars[] = {
+       {
+               .name           = "id",
+               .read_fptr      = nodemap_rd_id,
+       },
+       {
+               .name           = "trusted_nodemap",
+               .read_fptr      = nodemap_rd_trusted,
+       },
+       {
+               .name           = "admin_nodemap",
+               .read_fptr      = nodemap_rd_admin,
+       },
+       {
+               .name           = "squash_uid",
+               .read_fptr      = nodemap_rd_squash_uid,
+       },
+       {
+               .name           = "squash_gid",
+               .read_fptr      = nodemap_rd_squash_gid,
+       },
+       {
+               NULL
+       }
+};
+
+static struct lprocfs_vars lprocfs_default_nodemap_vars[] = {
+       {
+               .name           = "id",
+               .read_fptr      = nodemap_rd_id,
+       },
+       {
+               .name           = "trusted_nodemap",
+               .read_fptr      = nodemap_rd_trusted,
+       },
+       {
+               .name           = "admin_nodemap",
+               .read_fptr      = nodemap_rd_admin,
+       },
+       {
+               .name           = "squash_uid",
+               .read_fptr      = nodemap_rd_squash_uid,
+       },
+       {
+               .name           = "squash_gid",
+               .read_fptr      = nodemap_rd_squash_gid,
+       },
+       {
+               NULL
+       }
+};
+#endif /* NODEMAP_PROC_DEBUG */
+
+int nodemap_procfs_init(void)
+{
+       int rc = 0;
+
+       proc_lustre_nodemap_root = lprocfs_register(LUSTRE_NODEMAP_NAME,
+                                                   proc_lustre_root,
+                                                   lprocfs_nodemap_module_vars,
+                                                   NULL);
+
+       if (IS_ERR(proc_lustre_nodemap_root)) {
+               rc = PTR_ERR(proc_lustre_nodemap_root);
+               CERROR("cannot create 'nodemap' directory: rc = %d\n",
+                      rc);
+               proc_lustre_nodemap_root = NULL;
+       }
+
+       return rc;
+}
+
+/**
+ * Register the proc directory for a nodemap
+ *
+ * \param      name            name of nodemap
+ * \param      is_default:     1 if default nodemap
+ * \retval     0               success
+ */
+int lprocfs_nodemap_register(const char *name,
+                            bool is_default,
+                            struct lu_nodemap *nodemap)
+{
+       struct proc_dir_entry   *nodemap_proc_entry;
+       int                     rc = 0;
+
+       if (is_default)
+               nodemap_proc_entry =
+                       lprocfs_register(name,
+                                        proc_lustre_nodemap_root,
+                                        lprocfs_default_nodemap_vars,
+                                        nodemap);
+       else
+               nodemap_proc_entry = lprocfs_register(name,
+                                                     proc_lustre_nodemap_root,
+                                                     lprocfs_nodemap_vars,
+                                                     nodemap);
+
+       if (IS_ERR(nodemap_proc_entry)) {
+               rc = PTR_ERR(nodemap_proc_entry);
+               CERROR("cannot create 'nodemap/%s': rc = %d\n", name, rc);
+               nodemap_proc_entry = NULL;
+       }
+
+       nodemap->nm_proc_entry = nodemap_proc_entry;
+
+       return rc;
+}
index 03ac2cc..58eb783 100644 (file)
@@ -32,6 +32,12 @@ CONFDIR=/etc/lustre
 PERM_CONF=$CONFDIR/perm.conf
 FAIL_ON_ERROR=false
 
+HN=$(hostname | sum | awk '{ print $1 }')
+NODEMAP_COUNT=10
+NODEMAP_RANGE_COUNT=3
+NODEMAP_IPADDR_COUNT=30
+NODEMAP_ID_COUNT=200
+
 require_dsh_mds || exit 0
 require_dsh_ost || exit 0
 
@@ -557,6 +563,80 @@ test_6() {
 }
 run_test 6 "capa expiry ========================="
 
+create_nodemaps() {
+       local i
+       local out
+       local rc
+
+       for (( i = 0; i < NODEMAP_COUNT; i++ )); do
+               if ! do_facet mgs $LCTL nodemap_add ${HN}_${i}; then
+                       return 1
+               fi
+               out=$(do_facet mgs $LCTL get_param nodemap.${HN}_${i}.id)
+               ## This needs to return zero if the following statement is 1
+               rc=$(echo $out | grep -c ${HN}_${i})
+               [[ $rc == 0 ]] && return 1
+       done
+       return 0
+}
+
+delete_nodemaps() {
+       local i
+       local out
+       local rc
+
+       for ((i = 0; i < NODEMAP_COUNT; i++)); do
+               if ! do_facet mgs $LCTL nodemap_del ${HN}_${i}; then
+                       error "nodemap_del ${HN}_${i} failed with $rc"
+                       return 3
+               fi
+               out=$(do_facet mgs $LCTL get_param nodemap.${HN}_${i}.id)
+               rc=$(echo $out | grep -c ${HN}_${i})
+               [[ $rc != 0 ]] && return 1
+       done
+       return 0
+}
+
+test_7() {
+       local rc
+
+       create_nodemaps
+       rc=$?
+       [[ $rc != 0 ]] && error "nodemap_add failed with $rc" && return 1
+
+       delete_nodemaps
+       rc=$?
+       [[ $rc != 0 ]] && error "nodemap_add failed with $rc" && return 2
+
+       return 0
+}
+run_test 7 "nodemap create and delete"
+
+test_8() {
+       local rc
+
+       # Set up nodemaps
+
+       create_nodemaps
+       rc=$?
+       [[ $rc != 0 ]] && error "nodemap_add failed with $rc" && return 1
+
+       # Try duplicates
+
+       create_nodemaps
+       rc=$?
+       [[ $rc == 0 ]] && error "duplicate nodemap_add allowed with $rc" &&
+       return 2
+
+       # Clean up
+       delete_nodemaps
+       rc=$?
+       [[ $rc != 0 ]] && error "nodemap_add failed with $rc" && return 3
+
+       return 0
+}
+run_test 8 "nodemap reject duplicates"
+
 log "cleanup: ======================================================"
 
 sec_unsetup() {
index 6b05b83..898cebe 100644 (file)
@@ -514,6 +514,7 @@ load_modules_local() {
                        load_module ../ldiskfs/ldiskfs
                        load_module osd-ldiskfs/osd_ldiskfs
                fi
+               load_module nodemap/nodemap
                load_module mgs/mgs
                load_module mdd/mdd
                load_module mdt/mdt
index 964e7be..c3059c4 100644 (file)
@@ -83,7 +83,7 @@ llverdev_LDADD := $(EXT2FSLIB) $(BLKIDLIB)
 L_IOCTL := $(top_builddir)/libcfs/libcfs/util/l_ioctl.c
 L_KERNELCOMM := $(top_builddir)/libcfs/libcfs/kernel_user_comm.c
 liblustreapitmp_a_SOURCES = liblustreapi.c liblustreapi_hsm.c \
-                           lustreapi_internal.h \
+                           liblustreapi_nodemap.c lustreapi_internal.h \
                            $(L_IOCTL) $(L_KERNELCOMM)
 
 # build static and shared lib lustreapi
index 3a696c0..7d7d0a1 100644 (file)
@@ -216,19 +216,31 @@ command_t cmdlist[] = {
         {"===  Pools ==", jt_noop, 0, "pool management"},
         {"pool_new", jt_pool_cmd, 0,
          "add a new pool\n"
-         "usage pool_new <fsname>.<poolname>"},
-        {"pool_add", jt_pool_cmd, 0,
+        "usage: pool_new <fsname>.<poolname>"},
+       {"pool_add", jt_pool_cmd, 0,
          "add the named OSTs to the pool\n"
-         "usage pool_add <fsname>.<poolname> <ostname indexed list>"},
+        "usage: pool_add <fsname>.<poolname> <ostname indexed list>"},
         {"pool_remove", jt_pool_cmd, 0,
          "remove the named OST from the pool\n"
-         "usage pool_remove <fsname>.<poolname> <ostname indexed list>"},
+        "usage: pool_remove <fsname>.<poolname> <ostname indexed list>"},
         {"pool_destroy", jt_pool_cmd, 0,
          "destroy a pool\n"
-         "usage pool_destroy <fsname>.<poolname>"},
+        "usage: pool_destroy <fsname>.<poolname>"},
         {"pool_list", jt_pool_cmd, 0,
          "list pools and pools members\n"
-         "usage pool_list  <fsname>[.<poolname>] | <pathname>"},
+        "usage: pool_list  <fsname>[.<poolname>] | <pathname>"},
+
+       /* Nodemap commands */
+       {"=== Nodemap ===", jt_noop, 0, "nodemap management"},
+       {"nodemap_activate_idmap", jt_nodemap_activate, 0,
+        "activate nodemap idmapping functions\n"
+        "usage: nodemap_activate_idmap"},
+       {"nodemap_add", jt_nodemap_add, 0,
+        "add a new nodemap\n"
+        "usage: nodemap_add <nodemap_name>"},
+       {"nodemap_del", jt_nodemap_del, 0,
+        "remove a nodemap\n"
+        "usage: nodemap_del <nodemap_name>"},
 
         /* Changelog commands */
         {"===  Changelogs ==", jt_noop, 0, "changelog user management"},
index 461af1e..0a9f684 100644 (file)
@@ -397,7 +397,7 @@ static int find_poolpath(char *fsname, char *poolname, char *poolpath)
   * Return 0 for success, with a NUL-terminated string in \param result.
   * Return -ve value for error.
   */
-static int get_param(const char *param_path, char *result,
+int get_param(const char *param_path, char *result,
                      unsigned int result_size)
 {
         char file[PATH_MAX + 1], pattern[PATH_MAX + 1], buf[result_size];
@@ -407,7 +407,7 @@ static int get_param(const char *param_path, char *result,
         snprintf(pattern, PATH_MAX, "/proc/{fs,sys}/{lnet,lustre}/%s",
                  param_path);
         rc = first_match(pattern, file);
-        if (rc)
+       if (rc != 0 || result == NULL)
                 return rc;
 
         fp = fopen(file, "r");
diff --git a/lustre/utils/liblustreapi_nodemap.c b/lustre/utils/liblustreapi_nodemap.c
new file mode 100644 (file)
index 0000000..3a9bd09
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * LGPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Lesser General Public License
+ * (LGPL) version 2.1 or (at your discretion) any later version.
+ * (LGPL) version 2.1 accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/lgpl-2.1.html
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * LGPL HEADER END
+ */
+/*
+ * Copyright (C) 2013, Trustees of Indiana University
+ * Author: Joshua Walgenbach <jjw@iu.edu>
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <liblustre.h>
+#include <lustre/lustreapi.h>
+#include "lustreapi_internal.h"
+
+int llapi_nodemap_exists(const char *nodemap)
+{
+       char mapname[PATH_MAX + 1];
+
+       snprintf(mapname, sizeof(mapname) - 1, "nodemap/%s", nodemap);
+
+       return get_param(mapname, NULL, 0);
+}
index 3ae67e9..207a5a0 100644 (file)
@@ -43,6 +43,7 @@
 int get_root_path(int want, char *fsname, int *outfd, char *path, int index);
 int root_ioctl(const char *mdtname, int opc, void *data, int *mdtidxp,
               int want_error);
-
+int get_param(const char *param_path, char *result,
+             unsigned int result_size);
 
 #endif /* _LUSTREAPI_INTERNAL_H_ */
index a0c45b5..ced869b 100644 (file)
@@ -3408,6 +3408,123 @@ out:
         return rc;
 }
 
+static int nodemap_cmd(enum lcfg_command_type cmd, int num_args, ...)
+{
+       va_list arguments;
+       int i;
+       const char *args;
+       char *arg;
+       struct lustre_cfg_bufs bufs;
+       struct obd_ioctl_data data;
+       struct lustre_cfg *lcfg;
+       char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
+       int rc = 0;
+
+       lustre_cfg_bufs_reset(&bufs, NULL);
+
+       va_start(arguments, num_args);
+
+       for (i = 0; i < num_args; i++) {
+               args = va_arg(arguments, char *);
+               arg = (char *)args;
+               lustre_cfg_bufs_set_string(&bufs, i, arg);
+       }
+
+       va_end(arguments);
+
+       lcfg = lustre_cfg_new(cmd, &bufs);
+
+       if (IS_ERR(lcfg)) {
+               rc = PTR_ERR(lcfg);
+               return rc;
+       }
+
+       memset(&data, 0, sizeof(data));
+       rc = data.ioc_dev = get_mgs_device();
+       if (rc < 0)
+               goto out;
+
+       data.ioc_type = LUSTRE_CFG_TYPE;
+       data.ioc_plen1 = lustre_cfg_len(lcfg->lcfg_bufcount,
+                        lcfg->lcfg_buflens);
+       data.ioc_pbuf1 = (void *)lcfg;
+
+       memset(buf, 0, sizeof(rawbuf));
+       rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
+       if (rc) {
+               fprintf(stderr, "error: invalid ioctl\n");
+               return rc;
+       }
+       rc = l_ioctl(OBD_DEV_ID, OBD_IOC_NODEMAP, buf);
+out:
+       if (rc)
+               rc = -errno;
+
+       lustre_cfg_free(lcfg);
+       return rc;
+}
+
+int jt_nodemap_activate(int argc, char **argv)
+{
+       enum lcfg_command_type cmd;
+       int rc = 0;
+
+       cmd = LCFG_NODEMAP_ACTIVATE;
+       rc = nodemap_cmd(cmd, 1, argv[0]);
+
+       if (rc != 0) {
+               errno = -rc;
+               perror(argv[0]);
+       }
+
+       return rc;
+}
+
+int jt_nodemap_add(int argc, char **argv)
+{
+       enum lcfg_command_type cmd;
+       int rc = 0;
+
+       cmd = LCFG_NODEMAP_ADD;
+       rc = llapi_nodemap_exists(argv[1]);
+       if (rc == 0) {
+               fprintf(stderr, "error: %s existing nodemap name\n", argv[1]);
+               return 1;
+       }
+
+       rc = nodemap_cmd(cmd, 2, argv[0], argv[1]);
+
+       if (rc != 0) {
+               errno = -rc;
+               perror(argv[0]);
+       }
+
+       return rc;
+}
+
+int jt_nodemap_del(int argc, char **argv)
+{
+       enum lcfg_command_type cmd;
+       int rc = 0;
+
+       cmd = LCFG_NODEMAP_DEL;
+       rc = llapi_nodemap_exists(argv[1]);
+
+       if (rc != 0) {
+               fprintf(stderr, "error: %s not existing nodemap name\n",
+                       argv[1]);
+               return rc;
+       }
+       rc = nodemap_cmd(cmd, 2, argv[0], argv[1]);
+
+       if (rc != 0) {
+               errno = -rc;
+               perror(argv[0]);
+       }
+
+       return rc;
+}
+
 /*
  * this function tranforms a rule [start-end/step] into an array
  * of matching numbers
index 70741f0..c30db68 100644 (file)
@@ -133,6 +133,9 @@ int jt_blockdev_detach(int argc, char **argv);
 int jt_blockdev_info(int argc, char **argv);
 
 int jt_pool_cmd(int argc, char **argv);
+int jt_nodemap_activate(int argc, char **argv);
+int jt_nodemap_add(int argc, char **argv);
+int jt_nodemap_del(int argc, char **argv);
 int jt_changelog_register(int argc, char **argv);
 int jt_changelog_deregister(int argc, char **argv);