Whamcloud - gitweb
LU-3527 nodemap: idmap management functions 25/8125/10
authorJoshua Walgenbach <jjw@iu.edu>
Tue, 11 Feb 2014 00:36:53 +0000 (01:36 +0100)
committerOleg Drokin <oleg.drokin@intel.com>
Fri, 28 Feb 2014 23:13:17 +0000 (23:13 +0000)
This adds support for uid/gid mapping management to the nodemap
module. This mapping is added as four rbtrees in the nodemap
structure for forward and reverse mapping of UIDs and GIDs.
Postorder traversal for rbtrees have been added for cleanup
upon nodemap removal.

lctl commands have been added for adding, removing, and testing
maps.

Unit tests have been added to test the maps in all the relevant
modes (allow root access, trust client ids).

Signed-off-by: Joshua Walgenbach <jjw@iu.edu>
Change-Id: I9a8672f2883185a35d3553e5c2e91ae1d2cb094d
Reviewed-on: http://review.whamcloud.com/8125
Reviewed-by: Andreas Dilger <andreas.dilger@intel.com>
Tested-by: Jenkins
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: John L. Hammond <john.hammond@intel.com>
Reviewed-by: Andrew Perepechko <andrew_perepechko@xyratex.com>
Reviewed-by: Ken Hornstein <kenh@cmf.nrl.navy.mil>
15 files changed:
lustre/include/lustre_cfg.h
lustre/include/lustre_nodemap.h
lustre/mgs/mgs_handler.c
lustre/mgs/mgs_llog.c
lustre/nodemap/Makefile.in
lustre/nodemap/nodemap_handler.c
lustre/nodemap/nodemap_idmap.c [new file with mode: 0644]
lustre/nodemap/nodemap_internal.h
lustre/nodemap/nodemap_lproc.c
lustre/nodemap/nodemap_rbtree.c [new file with mode: 0644]
lustre/tests/sanity-sec.sh
lustre/utils/lctl.c
lustre/utils/liblustreapi_nodemap.c
lustre/utils/obd.c
lustre/utils/obdctl.h

index 2d8b83e..b1a7561 100644 (file)
@@ -106,6 +106,7 @@ enum lcfg_command_type {
        LCFG_NODEMAP_ADD_SHKEY  = 0x00ce053, /**< add shared key to cluster */
        LCFG_NODEMAP_DEL_SHKEY  = 0x00ce054, /**< delete shared key from cluster */
        LCFG_NODEMAP_TEST_NID   = 0x00ce055, /**< test for nodemap membership */
        LCFG_NODEMAP_ADD_SHKEY  = 0x00ce053, /**< add shared key to cluster */
        LCFG_NODEMAP_DEL_SHKEY  = 0x00ce054, /**< delete shared key from cluster */
        LCFG_NODEMAP_TEST_NID   = 0x00ce055, /**< test for nodemap membership */
+       LCFG_NODEMAP_TEST_ID    = 0x00ce056, /**< test uid/gid mapping */
 };
 
 struct lustre_cfg_bufs {
 };
 
 struct lustre_cfg_bufs {
index 94bb0d7..61e9dc8 100644 (file)
 
 #define LUSTRE_NODEMAP_DEFAULT_ID 0
 
 
 #define LUSTRE_NODEMAP_DEFAULT_ID 0
 
+/** enums containing the types of ids contained in a nodemap
+ * kept so other modules (mgs, mdt, etc) can define the type
+ * of search easily
+ */
+
+enum nodemap_id_type {
+       NODEMAP_UID,
+       NODEMAP_GID,
+};
+
+enum nodemap_tree_type {
+       NODEMAP_FS_TO_CLIENT,
+       NODEMAP_CLIENT_TO_FS,
+};
+
 /** 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
 /** 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
@@ -57,13 +72,13 @@ struct lu_nodemap {
        /* NID range list */
        struct list_head        nm_ranges;
        /* UID map keyed by local UID */
        /* NID range list */
        struct list_head        nm_ranges;
        /* UID map keyed by local UID */
-       struct rb_root          nm_local_to_remote_uidmap;
+       struct rb_root          nm_fs_to_client_uidmap;
        /* UID map keyed by remote UID */
        /* UID map keyed by remote UID */
-       struct rb_root          nm_remote_to_local_uidmap;
+       struct rb_root          nm_client_to_fs_uidmap;
        /* GID map keyed by local UID */
        /* GID map keyed by local UID */
-       struct rb_root          nm_local_to_remote_gidmap;
+       struct rb_root          nm_fs_to_client_gidmap;
        /* GID map keyed by remote UID */
        /* GID map keyed by remote UID */
-       struct rb_root          nm_remote_to_local_gidmap;
+       struct rb_root          nm_client_to_fs_gidmap;
        /* proc directory entry */
        struct proc_dir_entry   *nm_proc_entry;
        /* attached client members of this nodemap */
        /* proc directory entry */
        struct proc_dir_entry   *nm_proc_entry;
        /* attached client members of this nodemap */
@@ -72,15 +87,23 @@ struct lu_nodemap {
        cfs_hlist_node_t        nm_hash;
 };
 
        cfs_hlist_node_t        nm_hash;
 };
 
+void nodemap_activate(const bool value);
 int nodemap_add(const char *nodemap_name);
 int nodemap_del(const char *nodemap_name);
 struct lu_nodemap *nodemap_classify_nid(lnet_nid_t nid);
 int nodemap_parse_range(const char *range_string, lnet_nid_t range[2]);
 int nodemap_add(const char *nodemap_name);
 int nodemap_del(const char *nodemap_name);
 struct lu_nodemap *nodemap_classify_nid(lnet_nid_t nid);
 int nodemap_parse_range(const char *range_string, lnet_nid_t range[2]);
+int nodemap_parse_idmap(const char *idmap_string, __u32 idmap[2]);
 int nodemap_add_range(const char *name, const lnet_nid_t nid[2]);
 int nodemap_del_range(const char *name, const lnet_nid_t nid[2]);
 int nodemap_set_allow_root(const char *name, bool allow_root);
 int nodemap_set_trust_client_ids(const char *name, bool trust_client_ids);
 int nodemap_set_squash_uid(const char *name, uid_t uid);
 int nodemap_set_squash_gid(const char *name, gid_t gid);
 int nodemap_add_range(const char *name, const lnet_nid_t nid[2]);
 int nodemap_del_range(const char *name, const lnet_nid_t nid[2]);
 int nodemap_set_allow_root(const char *name, bool allow_root);
 int nodemap_set_trust_client_ids(const char *name, bool trust_client_ids);
 int nodemap_set_squash_uid(const char *name, uid_t uid);
 int nodemap_set_squash_gid(const char *name, gid_t gid);
-
-#endif
+int nodemap_add_idmap(const char *name, enum nodemap_id_type id_type,
+                     const __u32 map[2]);
+int nodemap_del_idmap(const char *name, enum nodemap_id_type id_type,
+                     const __u32 map[2]);
+__u32 nodemap_map_id(struct lu_nodemap *nodemap,
+                    enum nodemap_id_type id_type,
+                    enum nodemap_tree_type tree_type, __u32 id);
+#endif /* _LUSTRE_NODEMAP_H */
index 7c6b315..8961fc3 100644 (file)
@@ -629,9 +629,15 @@ static int mgs_iocontrol_nodemap(const struct lu_env *env,
        lnet_nid_t              nid;
        const char              *nodemap_name = NULL;
        const char              *nidstr = NULL;
        lnet_nid_t              nid;
        const char              *nodemap_name = NULL;
        const char              *nidstr = NULL;
+       const char              *client_idstr = NULL;
+       const char              *idtype_str = NULL;
        char                    *param = NULL;
        char                    *param = NULL;
+       char                    fs_idstr[16];
        int                     rc = 0;
        int                     rc = 0;
+       __u32                   client_id;
+       __u32                   fs_id;
        __u32                   cmd;
        __u32                   cmd;
+       int                     idtype;
 
        ENTRY;
 
 
        ENTRY;
 
@@ -654,6 +660,15 @@ static int mgs_iocontrol_nodemap(const struct lu_env *env,
        cmd = lcfg->lcfg_command;
 
        switch (cmd) {
        cmd = lcfg->lcfg_command;
 
        switch (cmd) {
+       case LCFG_NODEMAP_ACTIVATE:
+               if (lcfg->lcfg_bufcount != 2)
+                       GOTO(out_lcfg, rc = -EINVAL);
+               param = lustre_cfg_string(lcfg, 1);
+               if (strcmp(param, "1") == 0)
+                               nodemap_activate(1);
+               else
+                               nodemap_activate(0);
+               break;
        case LCFG_NODEMAP_ADD:
        case LCFG_NODEMAP_DEL:
                if (lcfg->lcfg_bufcount != 2)
        case LCFG_NODEMAP_ADD:
        case LCFG_NODEMAP_DEL:
                if (lcfg->lcfg_bufcount != 2)
@@ -672,8 +687,39 @@ static int mgs_iocontrol_nodemap(const struct lu_env *env,
                                 strlen(nodemap->nm_name)) != 0)
                        GOTO(out_lcfg, rc = -EFAULT);
                break;
                                 strlen(nodemap->nm_name)) != 0)
                        GOTO(out_lcfg, rc = -EFAULT);
                break;
+       case LCFG_NODEMAP_TEST_ID:
+               if (lcfg->lcfg_bufcount != 4)
+                       GOTO(out_lcfg, rc = -EINVAL);
+               nidstr = lustre_cfg_string(lcfg, 1);
+               idtype_str = lustre_cfg_string(lcfg, 2);
+               client_idstr = lustre_cfg_string(lcfg, 3);
+
+               nid = libcfs_str2nid(nidstr);
+               nodemap = nodemap_classify_nid(nid);
+               client_id = simple_strtoul(client_idstr, NULL, 10);
+
+               if (strcmp(idtype_str, "uid") == 0)
+                       idtype = NODEMAP_UID;
+               else
+                       idtype = NODEMAP_GID;
+
+               fs_id = nodemap_map_id(nodemap, idtype, NODEMAP_CLIENT_TO_FS,
+                                      client_id);
+
+               if (data->ioc_plen1 < sizeof(fs_idstr))
+                       GOTO(out_lcfg, rc = -EINVAL);
+
+               snprintf(fs_idstr, sizeof(fs_idstr), "%u", fs_id);
+               if (copy_to_user(data->ioc_pbuf1, fs_idstr,
+                                sizeof(fs_idstr)) != 0)
+                       GOTO(out_lcfg, rc = -EINVAL);
+               break;
        case LCFG_NODEMAP_ADD_RANGE:
        case LCFG_NODEMAP_DEL_RANGE:
        case LCFG_NODEMAP_ADD_RANGE:
        case LCFG_NODEMAP_DEL_RANGE:
+       case LCFG_NODEMAP_ADD_UIDMAP:
+       case LCFG_NODEMAP_DEL_UIDMAP:
+       case LCFG_NODEMAP_ADD_GIDMAP:
+       case LCFG_NODEMAP_DEL_GIDMAP:
                if (lcfg->lcfg_bufcount != 3)
                        GOTO(out_lcfg, rc = -EINVAL);
                nodemap_name = lustre_cfg_string(lcfg, 1);
                if (lcfg->lcfg_bufcount != 3)
                        GOTO(out_lcfg, rc = -EINVAL);
                nodemap_name = lustre_cfg_string(lcfg, 1);
@@ -690,7 +736,6 @@ static int mgs_iocontrol_nodemap(const struct lu_env *env,
                param = lustre_cfg_string(lcfg, 3);
                rc = mgs_nodemap_cmd(env, mgs, cmd, nodemap_name, param);
                break;
                param = lustre_cfg_string(lcfg, 3);
                rc = mgs_nodemap_cmd(env, mgs, cmd, nodemap_name, param);
                break;
-
        default:
                rc = -ENOTTY;
        }
        default:
                rc = -ENOTTY;
        }
index 945dca5..00e2fbc 100644 (file)
@@ -3897,6 +3897,7 @@ int mgs_nodemap_cmd(const struct lu_env *env, struct mgs_device *mgs,
                    const char *param)
 {
        lnet_nid_t      nid[2];
                    const char *param)
 {
        lnet_nid_t      nid[2];
+       __u32           idmap[2];
        bool            bool_switch;
        __u32           int_id;
        int             rc = 0;
        bool            bool_switch;
        __u32           int_id;
        int             rc = 0;
@@ -3937,6 +3938,30 @@ int mgs_nodemap_cmd(const struct lu_env *env, struct mgs_device *mgs,
                int_id = simple_strtoul(param, NULL, 10);
                rc = nodemap_set_squash_gid(nodemap_name, int_id);
                break;
                int_id = simple_strtoul(param, NULL, 10);
                rc = nodemap_set_squash_gid(nodemap_name, int_id);
                break;
+       case LCFG_NODEMAP_ADD_UIDMAP:
+       case LCFG_NODEMAP_ADD_GIDMAP:
+               rc = nodemap_parse_idmap(param, idmap);
+               if (rc != 0)
+                       break;
+               if (cmd == LCFG_NODEMAP_ADD_UIDMAP)
+                       rc = nodemap_add_idmap(nodemap_name, NODEMAP_UID,
+                                              idmap);
+               else
+                       rc = nodemap_add_idmap(nodemap_name, NODEMAP_GID,
+                                              idmap);
+               break;
+       case LCFG_NODEMAP_DEL_UIDMAP:
+       case LCFG_NODEMAP_DEL_GIDMAP:
+               rc = nodemap_parse_idmap(param, idmap);
+               if (rc != 0)
+                       break;
+               if (cmd == LCFG_NODEMAP_DEL_UIDMAP)
+                       rc = nodemap_del_idmap(nodemap_name, NODEMAP_UID,
+                                              idmap);
+               else
+                       rc = nodemap_del_idmap(nodemap_name, NODEMAP_GID,
+                                              idmap);
+               break;
        default:
                rc = -EINVAL;
        }
        default:
                rc = -EINVAL;
        }
index e6c9b53..f43aed7 100644 (file)
@@ -1,4 +1,5 @@
-MODULES := nodemap
-nodemap-objs := nodemap_handler.o nodemap_lproc.o nodemap_range.o
+MODULES = nodemap
+nodemap-objs = nodemap_handler.o nodemap_lproc.o nodemap_range.o
+nodemap-objs += nodemap_idmap.o nodemap_rbtree.o
 
 @INCLUDE_RULES@
 
 @INCLUDE_RULES@
index 89e7aec..ae814d4 100644 (file)
@@ -40,7 +40,7 @@ struct proc_dir_entry *proc_lustre_nodemap_root;
 static atomic_t nodemap_highest_id;
 
 /* Simple flag to determine if nodemaps are active */
 static atomic_t nodemap_highest_id;
 
 /* Simple flag to determine if nodemaps are active */
-bool nodemap_idmap_active;
+bool nodemap_active;
 
 /**
  * pointer to default nodemap kept to keep from
 
 /**
  * pointer to default nodemap kept to keep from
@@ -70,6 +70,8 @@ static void nodemap_destroy(struct lu_nodemap *nodemap)
                range_delete(range);
        }
 
                range_delete(range);
        }
 
+       idmap_delete_tree(nodemap);
+
        lprocfs_remove(&nodemap->nm_proc_entry);
        OBD_FREE_PTR(nodemap);
 }
        lprocfs_remove(&nodemap->nm_proc_entry);
        OBD_FREE_PTR(nodemap);
 }
@@ -271,7 +273,7 @@ struct lu_nodemap *nodemap_classify_nid(lnet_nid_t nid)
 }
 EXPORT_SYMBOL(nodemap_classify_nid);
 
 }
 EXPORT_SYMBOL(nodemap_classify_nid);
 
-/*
+/**
  * simple check for default nodemap
  */
 static bool is_default_nodemap(const struct lu_nodemap *nodemap)
  * simple check for default nodemap
  */
 static bool is_default_nodemap(const struct lu_nodemap *nodemap)
@@ -279,7 +281,7 @@ static bool is_default_nodemap(const struct lu_nodemap *nodemap)
        return nodemap->nm_id == 0;
 }
 
        return nodemap->nm_id == 0;
 }
 
-/*
+/**
  * parse a nodemap range string into two nids
  *
  * \param      range_str               string to parse
  * parse a nodemap range string into two nids
  *
  * \param      range_str               string to parse
@@ -311,6 +313,172 @@ out:
 }
 EXPORT_SYMBOL(nodemap_parse_range);
 
 }
 EXPORT_SYMBOL(nodemap_parse_range);
 
+/**
+ * parse a string containing an id map of form "client_id:filesystem_id"
+ * into an array of __u32 * for use in mapping functions
+ *
+ * \param      idmap_str               map string
+ * \param      idmap                   array[2] of __u32
+ *
+ * \retval     0 on success
+ */
+int nodemap_parse_idmap(const char *idmap_str, __u32 idmap[2])
+{
+       char    *end;
+
+       if (idmap_str == NULL)
+               return -EINVAL;
+
+       idmap[0] = simple_strtoul(idmap_str, &end, 10);
+       if (end == idmap_str || *end != ':')
+               return -EINVAL;
+
+       idmap_str = end + 1;
+       idmap[1] = simple_strtoul(idmap_str, &end, 10);
+       if (end == idmap_str)
+               return -EINVAL;
+
+       return 0;
+}
+EXPORT_SYMBOL(nodemap_parse_idmap);
+
+/**
+ * add an idmap to the proper nodemap trees
+ *
+ * \param      name            name of nodemap
+ * \param      id_type         NODEMAP_UID or NODEMAP_GID
+ * \param      map             array[2] __u32 containing the mapA values
+ *                             map[0] is client id
+ *                             map[1] is the filesystem id
+ *
+ * \retval     0 on success
+ */
+int nodemap_add_idmap(const char *name, enum nodemap_id_type id_type,
+                     const __u32 map[2])
+{
+       struct lu_nodemap       *nodemap = NULL;
+       struct lu_idmap         *idmap;
+       int                     rc = 0;
+
+       rc = nodemap_lookup(name, &nodemap);
+       if (nodemap == NULL || is_default_nodemap(nodemap))
+               GOTO(out, rc = -EINVAL);
+
+       idmap = idmap_create(map[0], map[1]);
+       if (idmap == NULL)
+               GOTO(out_putref, rc = -ENOMEM);
+
+       idmap_insert(id_type, idmap, nodemap);
+
+out_putref:
+       nodemap_putref(nodemap);
+out:
+       return rc;
+}
+EXPORT_SYMBOL(nodemap_add_idmap);
+
+/**
+ * delete idmap from proper nodemap tree
+ *
+ * \param      name            name of nodemap
+ * \param      id_type         NODEMAP_UID or NODEMAP_GID
+ * \param      map             array[2] __u32 containing the mapA values
+ *                             map[0] is client id
+ *                             map[1] is the filesystem id
+ *
+ * \retval     0 on success
+ */
+int nodemap_del_idmap(const char *name, enum nodemap_id_type id_type,
+                     const __u32 map[2])
+{
+       struct lu_nodemap       *nodemap = NULL;
+       struct lu_idmap         *idmap = NULL;
+       int                     rc = 0;
+
+       rc = nodemap_lookup(name, &nodemap);
+       if (nodemap == NULL || is_default_nodemap(nodemap))
+               GOTO(out, rc = -EINVAL);
+
+       idmap = idmap_search(nodemap, NODEMAP_CLIENT_TO_FS, id_type,
+                            map[0]);
+       if (idmap == NULL)
+               GOTO(out_putref, rc = -EINVAL);
+
+       idmap_delete(id_type, idmap, nodemap);
+
+out_putref:
+       nodemap_putref(nodemap);
+out:
+       return rc;
+}
+EXPORT_SYMBOL(nodemap_del_idmap);
+
+/**
+ * mapping function for nodemap idmaps
+ *
+ * \param      nodemap         lu_nodemap structure defining nodemap
+ * \param      node_type       NODEMAP_UID or NODEMAP_GID
+ * \param      tree_type       NODEMAP_CLIENT_TO_FS or
+ *                             NODEMAP_FS_TO_CLIENT
+ * \param      id              id to map
+ *
+ * \retval     mapped id according to the rules below.
+ *
+ * if the nodemap_active is false, just return the passed id without mapping
+ *
+ * if the id to be looked up in 0, check that root access is allowed and if it
+ * is, return 0. Otherwise, return the squash uid or gid.
+ *
+ * if the nodemap is configured to trusted the ids from the client system, just
+ * return the passwd id without mapping.
+ *
+ * if by this point, we haven't returned and the nodemap in question is the
+ * default nodemap, return the dquash uid or gid.
+ *
+ * after these checks, search the proper tree for the mapping, and if found
+ * return the mapped value, otherwise return the squash uid or gid.
+ */
+__u32 nodemap_map_id(struct lu_nodemap *nodemap,
+                    enum nodemap_id_type id_type,
+                    enum nodemap_tree_type tree_type, __u32 id)
+{
+       struct lu_idmap         *idmap = NULL;
+
+       if (!nodemap_active)
+               goto out;
+
+       if (id == 0) {
+               if (nodemap->nmf_allow_root_access)
+                       goto out;
+               else
+                       goto squash;
+       }
+
+       if (nodemap->nmf_trust_client_ids)
+               goto out;
+
+       if (is_default_nodemap(nodemap))
+               goto squash;
+
+       idmap = idmap_search(nodemap, tree_type, id_type, id);
+       if (idmap == NULL)
+               goto squash;
+
+       if (tree_type == NODEMAP_FS_TO_CLIENT)
+               return idmap->id_client;
+
+       return idmap->id_fs;
+
+squash:
+       if (id_type == NODEMAP_UID)
+               return nodemap->nm_squash_uid;
+       else
+               return nodemap->nm_squash_gid;
+out:
+       return id;
+}
+EXPORT_SYMBOL(nodemap_map_id);
+
 /*
  * add nid range to nodemap
  * \param      name            nodemap name
 /*
  * add nid range to nodemap
  * \param      name            nodemap name
@@ -425,10 +593,10 @@ static int nodemap_create(const char *name, bool is_default)
        snprintf(nodemap->nm_name, sizeof(nodemap->nm_name), "%s", name);
 
        INIT_LIST_HEAD(&(nodemap->nm_ranges));
        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;
+       nodemap->nm_fs_to_client_uidmap = RB_ROOT;
+       nodemap->nm_client_to_fs_uidmap = RB_ROOT;
+       nodemap->nm_fs_to_client_gidmap = RB_ROOT;
+       nodemap->nm_client_to_fs_gidmap = RB_ROOT;
 
        if (is_default) {
                nodemap->nm_id = LUSTRE_NODEMAP_DEFAULT_ID;
 
        if (is_default) {
                nodemap->nm_id = LUSTRE_NODEMAP_DEFAULT_ID;
@@ -470,7 +638,7 @@ out:
        return rc;
 }
 
        return rc;
 }
 
-/*
+/**
  * update flag to turn on or off nodemap functions
  * \param      name            nodemap name
  * \param      admin_string    string containing updated value
  * update flag to turn on or off nodemap functions
  * \param      name            nodemap name
  * \param      admin_string    string containing updated value
@@ -617,6 +785,17 @@ out:
 EXPORT_SYMBOL(nodemap_del);
 
 /**
 EXPORT_SYMBOL(nodemap_del);
 
 /**
+ * activate nodemap functions
+ *
+ * \param      value           1 for on, 0 for off
+ */
+void nodemap_activate(const bool value)
+{
+       nodemap_active = value;
+}
+EXPORT_SYMBOL(nodemap_activate);
+
+/**
  * Cleanup nodemap module on exit
  */
 static void nodemap_mod_exit(void)
  * Cleanup nodemap module on exit
  */
 static void nodemap_mod_exit(void)
diff --git a/lustre/nodemap/nodemap_idmap.c b/lustre/nodemap/nodemap_idmap.c
new file mode 100644 (file)
index 0000000..44382ff
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * 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/rbtree.h>
+#include <lustre_net.h>
+#include "nodemap_internal.h"
+
+/**
+ * allocate the lu_idmap structure
+ *
+ * \param      client_id               client uid or gid
+ * \param      fs_id                   filesystem uid or gid
+ *
+ * \retval     alloated lu_idmap structure on success, NULL otherwise
+ */
+struct lu_idmap *idmap_create(__u32 client_id, __u32 fs_id)
+{
+       struct lu_idmap *idmap;
+
+       OBD_ALLOC_PTR(idmap);
+       if (idmap == NULL) {
+               CERROR("cannot allocate lu_idmap of size %zu bytes\n",
+                      sizeof(idmap));
+               return NULL;
+       }
+
+       idmap->id_client = client_id;
+       idmap->id_fs = fs_id;
+       RB_CLEAR_NODE(&idmap->id_client_to_fs);
+       RB_CLEAR_NODE(&idmap->id_fs_to_client);
+       return idmap;
+}
+
+static void idmap_destroy(struct lu_idmap *idmap)
+
+{
+       LASSERT(RB_EMPTY_NODE(&idmap->id_fs_to_client) == 0);
+       LASSERT(RB_EMPTY_NODE(&idmap->id_client_to_fs) == 0);
+       OBD_FREE_PTR(idmap);
+}
+
+/**
+ * insert idmap into the proper trees
+ *
+ * \param      node_type               0 for UID
+ *                                     1 for GID
+ * \param      idmap                   lu_idmap structure to insert
+ * \param      nodemap                 nodemap to associate with the map
+ *
+ * \retval     0 on success
+ *
+ * if the mapping exists, this function will delete it and replace
+ * it with the new idmap structure
+ */
+void idmap_insert(enum nodemap_id_type id_type, struct lu_idmap *idmap,
+                struct lu_nodemap *nodemap)
+{
+       struct lu_idmap         *cur = NULL;
+       struct rb_node          *fwd_parent = NULL;
+       struct rb_node          *bck_parent = NULL;
+       struct rb_node          **fwd_node;
+       struct rb_node          **bck_node;
+       struct rb_root          *fwd_root;
+       struct rb_root          *bck_root;
+       bool                    replace = false;
+
+       /* for purposes in idmap client to fs is forward
+        * mapping, fs to client is backward mapping
+        */
+       if (id_type == NODEMAP_UID) {
+               fwd_root = &nodemap->nm_client_to_fs_uidmap;
+               bck_root = &nodemap->nm_fs_to_client_uidmap;
+       } else {
+               fwd_root = &nodemap->nm_client_to_fs_gidmap;
+               bck_root = &nodemap->nm_fs_to_client_gidmap;
+       }
+
+       fwd_node = &fwd_root->rb_node;
+       bck_node = &bck_root->rb_node;
+
+       /* find fwd and bck idmap nodes before insertion or
+        * replacing to precent split brain idmaps
+        */
+       while (*fwd_node) {
+               cur = rb_entry(*fwd_node, struct lu_idmap,
+                              id_client_to_fs);
+
+               if (idmap->id_client < cur->id_client) {
+                       fwd_node = &((*fwd_node)->rb_left);
+               } else if (idmap->id_client > cur->id_client) {
+                       fwd_node = &((*fwd_node)->rb_right);
+               } else {
+                       replace = true;
+                       break;
+               }
+
+               fwd_parent = *fwd_node;
+       }
+
+       if (!replace) {
+               while (*bck_node) {
+                       cur = rb_entry(*bck_node, struct lu_idmap,
+                                      id_fs_to_client);
+
+                       if (idmap->id_fs < cur->id_fs) {
+                               bck_node = &((*bck_node)->rb_left);
+                       } else if (idmap->id_fs > cur->id_fs) {
+                               bck_node = &((*bck_node)->rb_right);
+                       } else {
+                               replace = true;
+                               break;
+                       }
+
+                       bck_parent = *bck_node;
+               }
+       }
+
+       if (!replace) {
+               rb_link_node(&idmap->id_client_to_fs, fwd_parent, fwd_node);
+               rb_insert_color(&idmap->id_client_to_fs, fwd_root);
+               rb_link_node(&idmap->id_fs_to_client, bck_parent, bck_node);
+               rb_insert_color(&idmap->id_fs_to_client, bck_root);
+       } else {
+               rb_replace_node(&cur->id_client_to_fs,
+                               &idmap->id_client_to_fs,
+                               fwd_root);
+               rb_replace_node(&cur->id_fs_to_client,
+                               &idmap->id_fs_to_client,
+                               bck_root);
+
+               idmap_destroy(cur);
+       }
+}
+
+/**
+ * delete idmap from the correct nodemap tree
+ *
+ * \param      node_type               0 for UID
+ *                                     1 for GID
+ * \param      idmap                   idmap to delete
+ * \param      nodemap                 assoicated idmap
+ */
+void idmap_delete(enum nodemap_id_type id_type, struct lu_idmap *idmap,
+                 struct lu_nodemap *nodemap)
+{
+       struct rb_root  *fwd_root;
+       struct rb_root  *bck_root;
+
+       if (id_type == NODEMAP_UID) {
+               fwd_root = &nodemap->nm_client_to_fs_uidmap;
+               bck_root = &nodemap->nm_fs_to_client_uidmap;
+       } else {
+               fwd_root = &nodemap->nm_client_to_fs_gidmap;
+               bck_root = &nodemap->nm_fs_to_client_gidmap;
+       }
+
+       rb_erase(&idmap->id_client_to_fs, fwd_root);
+       rb_erase(&idmap->id_fs_to_client, bck_root);
+
+       idmap_destroy(idmap);
+}
+
+/**
+ * search for an existing id in the nodemap trees
+ *
+ * \param      nodemap         nodemap trees to search
+ * \param      tree_type       0 for filesystem to client maps
+ *                             1 for client to filesystem maps
+ * \param      id_type         0 for UID
+ *                             1 for GID
+ * \param      id              numeric id for which to search
+ *
+ * \retval     lu_idmap structure with the map on success
+ */
+struct lu_idmap *idmap_search(struct lu_nodemap *nodemap,
+                             enum nodemap_tree_type tree_type,
+                             enum nodemap_id_type id_type,
+                             const __u32 id)
+{
+       struct rb_node  *node;
+       struct rb_root  *root = NULL;
+       struct lu_idmap *idmap;
+
+       if (id_type == NODEMAP_UID && tree_type == NODEMAP_FS_TO_CLIENT)
+               root = &nodemap->nm_fs_to_client_uidmap;
+       else if (id_type == NODEMAP_UID && tree_type == NODEMAP_CLIENT_TO_FS)
+               root = &nodemap->nm_client_to_fs_uidmap;
+       else if (id_type == NODEMAP_GID && tree_type == NODEMAP_FS_TO_CLIENT)
+               root = &nodemap->nm_fs_to_client_gidmap;
+       else if (id_type == NODEMAP_GID && tree_type == NODEMAP_CLIENT_TO_FS)
+               root = &nodemap->nm_client_to_fs_gidmap;
+
+       node = root->rb_node;
+
+       if (tree_type == NODEMAP_FS_TO_CLIENT) {
+               while (node) {
+                       idmap = rb_entry(node, struct lu_idmap,
+                                        id_fs_to_client);
+                       if (id < idmap->id_fs)
+                               node = node->rb_left;
+                       else if (id > idmap->id_fs)
+                               node = node->rb_right;
+                       else
+                               return idmap;
+               }
+       } else {
+               while (node) {
+                       idmap = rb_entry(node, struct lu_idmap,
+                                        id_client_to_fs);
+                       if (id < idmap->id_client)
+                               node = node->rb_left;
+                       else if (id > idmap->id_client)
+                               node = node->rb_right;
+                       else
+                               return idmap;
+               }
+       }
+
+       return NULL;
+}
+
+/*
+ * delete all idmap trees from a nodemap
+ *
+ * \param      nodemap         nodemap to delete trees from
+ *
+ * This uses the postorder safe traversal code that is commited
+ * in a later kernel. Each lu_idmap strucuture is destroyed.
+ */
+void idmap_delete_tree(struct lu_nodemap *nodemap)
+{
+       struct lu_idmap         *idmap;
+       struct lu_idmap         *temp;
+       struct rb_root          root;
+
+       root = nodemap->nm_fs_to_client_uidmap;
+       nm_rbtree_postorder_for_each_entry_safe(idmap, temp, &root,
+                                               id_fs_to_client) {
+               idmap_destroy(idmap);
+       }
+
+       root = nodemap->nm_client_to_fs_gidmap;
+       nm_rbtree_postorder_for_each_entry_safe(idmap, temp, &root,
+                                               id_client_to_fs) {
+               idmap_destroy(idmap);
+       }
+}
index 7e55136..af3836e 100644 (file)
@@ -42,7 +42,7 @@ 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 */
 /* 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;
+extern bool nodemap_active;
 
 struct lu_nid_range {
        /* unique id set my mgs */
 
 struct lu_nid_range {
        /* unique id set my mgs */
@@ -55,6 +55,17 @@ struct lu_nid_range {
        struct interval_node     rn_node;
 };
 
        struct interval_node     rn_node;
 };
 
+struct lu_idmap {
+       /* uid/gid of client */
+       __u32           id_client;
+       /* uid/gid on filesystem */
+       __u32           id_fs;
+       /* tree mapping client ids to filesystem ids */
+       struct rb_node  id_client_to_fs;
+       /* tree mappung filesystem to client */
+       struct rb_node  id_fs_to_client;
+};
+
 int nodemap_procfs_init(void);
 int lprocfs_nodemap_register(const char *name, bool is_default_nodemap,
                             struct lu_nodemap *nodemap);
 int nodemap_procfs_init(void);
 int lprocfs_nodemap_register(const char *name, bool is_default_nodemap,
                             struct lu_nodemap *nodemap);
@@ -68,5 +79,29 @@ struct lu_nid_range *range_find(lnet_nid_t start_nid, lnet_nid_t end_nid);
 int range_parse_nidstring(char *range_string, lnet_nid_t *start_nid,
                          lnet_nid_t *end_nid);
 void range_init_tree(void);
 int range_parse_nidstring(char *range_string, lnet_nid_t *start_nid,
                          lnet_nid_t *end_nid);
 void range_init_tree(void);
+struct lu_idmap *idmap_create(__u32 client_id, __u32 fs_id);
+void idmap_insert(enum nodemap_id_type id_type, struct lu_idmap *idmap,
+                struct lu_nodemap *nodemap);
+void idmap_delete(enum nodemap_id_type id_type,  struct lu_idmap *idmap,
+                 struct lu_nodemap *nodemap);
+void idmap_delete_tree(struct lu_nodemap *nodemap);
+struct lu_idmap *idmap_search(struct lu_nodemap *nodemap,
+                             enum nodemap_tree_type,
+                             enum nodemap_id_type id_type,
+                             __u32 id);
 int nodemap_cleanup_nodemaps(void);
 int nodemap_cleanup_nodemaps(void);
+
+struct rb_node *nm_rb_next_postorder(const struct rb_node *node);
+struct rb_node *nm_rb_first_postorder(const struct rb_root *root);
+
+#define nm_rbtree_postorder_for_each_entry_safe(pos, n,                        \
+                                               root, field)            \
+       for (pos = rb_entry(nm_rb_first_postorder(root), typeof(*pos),  \
+                           field),                                     \
+               n = rb_entry(nm_rb_next_postorder(&pos->field),         \
+               typeof(*pos), field);                                   \
+               &pos->field;                                            \
+               pos = n,                                                \
+               n = rb_entry(nm_rb_next_postorder(&pos->field),         \
+                            typeof(*pos), field))
 #endif  /* _NODEMAP_INTERNAL_H */
 #endif  /* _NODEMAP_INTERNAL_H */
index 397b0d9..2f5efa1 100644 (file)
 #include <interval_tree.h>
 #include "nodemap_internal.h"
 
 #include <interval_tree.h>
 #include "nodemap_internal.h"
 
+static int nodemap_idmap_show(struct seq_file *m, void *data)
+{
+       struct lu_nodemap       *nodemap = m->private;
+       struct lu_idmap         *idmap;
+       struct rb_node          *node;
+       bool                    cont = 0;
+
+       seq_printf(m, "[\n");
+       for (node = rb_first(&nodemap->nm_client_to_fs_uidmap); node;
+                               node = rb_next(node)) {
+               if (cont)
+                       seq_printf(m, ",\n");
+               cont = 1;
+               idmap = rb_entry(node, struct lu_idmap, id_client_to_fs);
+               if (idmap != NULL)
+                       seq_printf(m, " { idtype: uid, client_id: %u, "
+                                  "fs_id: %u }", idmap->id_client,
+                                  idmap->id_fs);
+       }
+       for (node = rb_first(&nodemap->nm_client_to_fs_gidmap);
+                               node; node = rb_next(node)) {
+               if (cont)
+                       seq_printf(m, ",\n");
+               idmap = rb_entry(node, struct lu_idmap, id_client_to_fs);
+               if (idmap != NULL)
+                       seq_printf(m, " { idtype: gid, client_id: %u, "
+                                  "fs_id: %u }", idmap->id_client,
+                                  idmap->id_fs);
+       }
+       seq_printf(m, "\n");
+       seq_printf(m, "]\n");
+
+       return 0;
+}
+
+static int nodemap_idmap_open(struct inode *inode, struct file *file)
+{
+       struct proc_dir_entry   *dir;
+       struct lu_nodemap       *nodemap;
+
+       dir = PDE(inode);
+       nodemap = dir->data;
+
+       return single_open(file, nodemap_idmap_show, nodemap);
+}
+
 static int nodemap_ranges_show(struct seq_file *m, void *data)
 {
        struct lu_nodemap               *nodemap = m->private;
        struct lu_nid_range             *range;
        struct interval_node_extent     ext;
 static int nodemap_ranges_show(struct seq_file *m, void *data)
 {
        struct lu_nodemap               *nodemap = m->private;
        struct lu_nid_range             *range;
        struct interval_node_extent     ext;
+       bool                            cont = 0;
 
 
-
+       seq_printf(m, "[\n");
        list_for_each_entry(range, &nodemap->nm_ranges, rn_list) {
        list_for_each_entry(range, &nodemap->nm_ranges, rn_list) {
-                       ext = range->rn_node.in_extent;
-                       seq_printf(m, "id: %u: { start_nid: %s, "
-                                       "end_nid: %s }\n",
-                                  range->rn_id, libcfs_nid2str(ext.start),
-                                  libcfs_nid2str(ext.end));
+               if (cont)
+                       seq_printf(m, ",\n");
+               cont = 1;
+               ext = range->rn_node.in_extent;
+               seq_printf(m, " { id: %u, start_nid: %s, "
+                               "end_nid: %s }",
+                          range->rn_id, libcfs_nid2str(ext.start),
+                          libcfs_nid2str(ext.end));
        }
        }
+       seq_printf(m, "\n");
+       seq_printf(m, "]\n");
 
        return 0;
 }
 
        return 0;
 }
@@ -63,7 +115,7 @@ static int nodemap_ranges_open(struct inode *inode, struct file *file)
 
 static int nodemap_active_seq_show(struct seq_file *m, void *data)
 {
 
 static int nodemap_active_seq_show(struct seq_file *m, void *data)
 {
-       return seq_printf(m, "%u\n", (unsigned int)nodemap_idmap_active);
+       return seq_printf(m, "%u\n", (unsigned int)nodemap_active);
 }
 
 static ssize_t
 }
 
 static ssize_t
@@ -85,7 +137,7 @@ nodemap_active_seq_write(struct file *file, const char __user *buffer,
 
        active_string[count] = '\0';
        active = simple_strtoul(active_string, NULL, 10);
 
        active_string[count] = '\0';
        active = simple_strtoul(active_string, NULL, 10);
-       nodemap_idmap_active = active;
+       nodemap_active = active;
 
        return rc;
 }
 
        return rc;
 }
@@ -348,6 +400,13 @@ const struct file_operations nodemap_ranges_fops = {
        .release                = single_release
 };
 
        .release                = single_release
 };
 
+const struct file_operations nodemap_idmap_fops = {
+       .open                   = nodemap_idmap_open,
+       .read                   = seq_read,
+       .llseek                 = seq_lseek,
+       .release                = single_release
+};
+
 static struct lprocfs_seq_vars lprocfs_nodemap_vars[] = {
        {
                .name           = "id",
 static struct lprocfs_seq_vars lprocfs_nodemap_vars[] = {
        {
                .name           = "id",
@@ -374,6 +433,10 @@ static struct lprocfs_seq_vars lprocfs_nodemap_vars[] = {
                .fops           = &nodemap_ranges_fops,
        },
        {
                .fops           = &nodemap_ranges_fops,
        },
        {
+               .name           = "idmap",
+               .fops           = &nodemap_idmap_fops,
+       },
+       {
                NULL
        }
 };
                NULL
        }
 };
diff --git a/lustre/nodemap/nodemap_rbtree.c b/lustre/nodemap/nodemap_rbtree.c
new file mode 100644 (file)
index 0000000..68993fb
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * 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 <lustre_net.h>
+#include <linux/rbtree.h>
+#include "nodemap_internal.h"
+
+/* This code is from a patch submitted by
+ * Cody P Schafer <cody@linux.vnet.ibm.com> linux kernel
+ * rbtree. When the supported kernel catches up to
+ * the kernel where it is landed. To remove the
+ * entire tree, it has to be done in postorder.
+ *
+ * I didn't write this other than to change the
+ * function names to prevent collisions later.
+ */
+
+static struct rb_node *nm_rb_left_deepest_node(const struct rb_node *node);
+
+static struct rb_node *nm_rb_left_deepest_node(const struct rb_node *node)
+{
+       while (true) {
+               if (node->rb_left)
+                       node = node->rb_left;
+               else if (node->rb_right)
+                       node = node->rb_right;
+               else
+                       return (struct rb_node *) node;
+       }
+}
+
+struct rb_node *nm_rb_next_postorder(const struct rb_node *node)
+{
+       const struct rb_node *parent;
+       if (!node)
+               return NULL;
+       parent = rb_parent(node);
+
+       if (parent && node == parent->rb_left && parent->rb_right)
+               return nm_rb_left_deepest_node(parent->rb_right);
+       else
+               return (struct rb_node *) parent;
+}
+
+struct rb_node *nm_rb_first_postorder(const struct rb_root *root)
+{
+       if (!root->rb_node)
+               return NULL;
+
+       return nm_rb_left_deepest_node(root->rb_node);
+}
index 4050bd3..b1a68a5 100644 (file)
@@ -37,7 +37,7 @@ SUBNET_CHECKSUM=$(expr $HOSTNAME_CHECKSUM % 250 + 1)
 NODEMAP_COUNT=10
 NODEMAP_RANGE_COUNT=3
 NODEMAP_IPADDR_COUNT=30
 NODEMAP_COUNT=10
 NODEMAP_RANGE_COUNT=3
 NODEMAP_IPADDR_COUNT=30
-NODEMAP_ID_COUNT=200
+NODEMAP_MAX_ID=600
 
 require_dsh_mds || exit 0
 require_dsh_ost || exit 0
 
 require_dsh_mds || exit 0
 require_dsh_ost || exit 0
@@ -604,7 +604,6 @@ delete_nodemaps() {
 }
 
 add_range() {
 }
 
 add_range() {
-       local i
        local j
        local cmd="$LCTL nodemap_add_range"
        local range
        local j
        local cmd="$LCTL nodemap_add_range"
        local range
@@ -620,8 +619,7 @@ add_range() {
        return $rc
 }
 
        return $rc
 }
 
-del_range() {
-       local i
+delete_range() {
        local j
        local cmd="$LCTL nodemap_del_range"
        local range
        local j
        local cmd="$LCTL nodemap_del_range"
        local range
@@ -634,6 +632,63 @@ del_range() {
                        rc=$(($rc + 1))
                fi
        done
                        rc=$(($rc + 1))
                fi
        done
+
+       return $rc
+}
+
+add_idmaps() {
+       local i
+       local j
+       local client_id
+       local fs_id
+       local cmd="$LCTL nodemap_add_idmap"
+       local rc=0
+
+       for ((i = 0; i < NODEMAP_COUNT; i++)); do
+               for ((j = 500; j < NODEMAP_MAX_ID; j++)); do
+                       client_id=$j
+                       fs_id=$(($j + 1))
+                       if ! do_facet mgs $cmd                          \
+                       --name ${HOSTNAME_CHECKSUM}_${i}                \
+                       --idtype uid --idmap $client_id:$fs_id; then
+                               rc=$(($rc + 1))
+                       fi
+                       if ! do_facet mgs $cmd                          \
+                       --name ${HOSTNAME_CHECKSUM}_${i}                \
+                       --idtype gid --idmap $client_id:$fs_id; then
+                               rc=$(($rc + 1))
+                       fi
+               done
+       done
+
+       return $rc
+}
+
+delete_idmaps() {
+       local i
+       local j
+       local client_id
+       local fs_id
+       local cmd="$LCTL nodemap_del_idmap"
+       local rc=0
+
+       for ((i = 0; i < NODEMAP_COUNT; i++)); do
+               for ((j = 500; j < NODEMAP_MAX_ID; j++)); do
+                       client_id=$j
+                       fs_id=$(($j + 1))
+                       if ! do_facet mgs $cmd                          \
+                       --name ${HOSTNAME_CHECKSUM}_${i}                \
+                       --idtype uid --idmap $client_id:$fs_id; then
+                               rc=$(($rc + 1))
+                       fi
+                       if ! do_facet mgs $cmd                          \
+                       --name ${HOSTNAME_CHECKSUM}_${i}                \
+                       --idtype gid --idmap $client_id:$fs_id; then
+                               rc=$(($rc + 1))
+                       fi
+               done
+       done
+
        return $rc
 }
 
        return $rc
 }
 
@@ -691,6 +746,124 @@ test_nid() {
        return 1
 }
 
        return 1
 }
 
+test_idmap() {
+       local i
+       local j
+       local fs_id
+       local cmd="$LCTL nodemap_test_id"
+       local rc=0
+
+       ## nodemap deactivated
+       if ! do_facet mgs lctl nodemap_activate 0; then
+               return 1
+       fi
+       for ((id = 500; id < NODEMAP_MAX_ID; id++)); do
+               for ((j = 0; j < NODEMAP_RANGE_COUNT; j++)); do
+                       nid="$SUBNET_CHECKSUM.0.${j}.100@tcp"
+                       fs_id=$(do_facet mgs $cmd --nid $nid    \
+                               --idtype uid --id $id)
+                       if [ $fs_id != $id ]; then
+                               rc=$((rc + 1))
+                       fi
+               done
+       done
+
+       ## nodemap activated
+       if ! do_facet mgs lctl nodemap_activate 1; then
+               return 2
+       fi
+
+       for ((id = 500; id < NODEMAP_MAX_ID; id++)); do
+               for ((j = 0; j < NODEMAP_RANGE_COUNT; j++)); do
+                       nid="$SUBNET_CHECKSUM.0.${j}.100@tcp"
+                       fs_id=$(do_facet mgs $cmd --nid $nid    \
+                               --idtype uid --id $id)
+                       expected_id=$((id + 1))
+                       if [ $fs_id != $expected_id ]; then
+                               rc=$((rc + 1))
+                       fi
+               done
+       done
+
+       ## trust client ids
+       for ((i = 0; i < NODEMAP_COUNT; i++)); do
+               if ! do_facet mgs $LCTL nodemap_modify                  \
+                               --name ${HOSTNAME_CHECKSUM}_${i}        \
+                               --property trusted --value 1; then
+                       error "nodemap_modify ${HOSTNAME_CHECKSUM}_${i} "
+                               "failed with $rc"
+                       return 3
+               fi
+       done
+
+       for ((id = 500; id < NODEMAP_MAX_ID; id++)); do
+               for ((j = 0; j < NODEMAP_RANGE_COUNT; j++)); do
+                       nid="$SUBNET_CHECKSUM.0.${j}.100@tcp"
+                       fs_id=$(do_facet mgs $cmd --nid $nid    \
+                               --idtype uid --id $id)
+                       expected_id=$((id + 1))
+                       if [ $fs_id != $id ]; then
+                               rc=$((rc + 1))
+                       fi
+               done
+       done
+
+       ## ensure allow_root_access is enabled
+       for ((i = 0; i < NODEMAP_COUNT; i++)); do
+               if ! do_facet mgs $LCTL nodemap_modify          \
+                       --name ${HOSTNAME_CHECKSUM}_${i}        \
+                       --property admin --value 1; then
+                       error "nodemap_modify ${HOSTNAME_CHECKSUM}_${i} "
+                               "failed with $rc"
+                       return 3
+               fi
+       done
+
+       ## check that root is mapped to 99
+       for ((j = 0; j < NODEMAP_RANGE_COUNT; j++)); do
+               nid="$SUBNET_CHECKSUM.0.${j}.100@tcp"
+               fs_id=$(do_facet mgs $cmd --nid $nid --idtype uid --id 0)
+               expected_id=$((id + 1))
+               if [ $fs_id != 0 ]; then
+                       rc=$((rc + 1))
+               fi
+       done
+
+       ## ensure allow_root_access is disabled
+       for ((i = 0; i < NODEMAP_COUNT; i++)); do
+               if ! do_facet mgs $LCTL nodemap_modify          \
+                               --name ${HOSTNAME_CHECKSUM}_${i}        \
+                               --property admin --value 0; then
+                       error "nodemap_modify ${HOSTNAME_CHECKSUM}_${i} "
+                               "failed with $rc"
+                       return 3
+               fi
+       done
+
+       ## check that root allowed
+       for ((j = 0; j < NODEMAP_RANGE_COUNT; j++)); do
+               nid="$SUBNET_CHECKSUM.0.${j}.100@tcp"
+               fs_id=$(do_facet mgs $cmd --nid $nid --idtype uid --id 0)
+               expected_id=$((id + 1))
+               if [ $fs_id != 99 ]; then
+                       rc=$((rc + 1))
+               fi
+       done
+
+       ## reset client trust to 0
+       for ((i = 0; i < NODEMAP_COUNT; i++)); do
+               if ! do_facet mgs $LCTL nodemap_modify          \
+                       --name ${HOSTNAME_CHECKSUM}_${i}        \
+                       --property trusted --value 0; then
+                       error "nodemap_modify ${HOSTNAME_CHECKSUM}_${i} "
+                               "failed with $rc"
+                       return 3
+               fi
+       done
+
+       return $rc
+}
+
 test_7() {
        local rc
 
 test_7() {
        local rc
 
@@ -765,7 +938,7 @@ test_9() {
 
        rc=0
        for ((i = 0; i < NODEMAP_COUNT; i++)); do
 
        rc=0
        for ((i = 0; i < NODEMAP_COUNT; i++)); do
-               if ! del_range ${HOSTNAME_CHECKSUM}_${i} $i; then
+               if ! delete_range ${HOSTNAME_CHECKSUM}_${i} $i; then
                        rc=$((rc + 1))
                fi
        done
                        rc=$((rc + 1))
                fi
        done
@@ -813,7 +986,7 @@ test_10() {
 
        rc=0
        for ((i = 0; i < NODEMAP_COUNT; i++)); do
 
        rc=0
        for ((i = 0; i < NODEMAP_COUNT; i++)); do
-               if ! del_range ${HOSTNAME_CHECKSUM}_${i} $i; then
+               if ! delete_range ${HOSTNAME_CHECKSUM}_${i} $i; then
                        rc=$((rc + 1))
                fi
        done
                        rc=$((rc + 1))
                fi
        done
@@ -973,6 +1146,50 @@ test_14() {
 }
 run_test 14 "test default nodemap nid lookup"
 
 }
 run_test 14 "test default nodemap nid lookup"
 
+test_15() {
+       local rc
+
+       remote_mgs_nodsh && skip "remote MGS with nodsh" && return
+       [ $(lustre_version_code $SINGLEMGS) -lt $(version_code 2.5.53) ] &&
+               skip "No nodemap on $(get_lustre_version) MGS, need 2.5.53+" &&
+               return
+
+       rc=0
+       create_nodemaps
+       rc=$?
+       [[ $rc != 0 ]] && error "nodemap_add failed with $rc" && return 1
+
+       rc=0
+       for ((i = 0; i < NODEMAP_COUNT; i++)); do
+               if ! add_range ${HOSTNAME_CHECKSUM}_${i} $i; then
+                       rc=$((rc + 1))
+               fi
+       done
+       [[ $rc != 0 ]] && error "nodemap_add_range failed with $rc" && return 2
+
+       rc=0
+       add_idmaps
+       rc=$?
+       [[ $rc != 0 ]] && error "nodemap_add_idmap failed with $rc" && return 3
+
+       rc=0
+       test_idmap
+       rc=$?
+       [[ $rc != 0 ]] && error "nodemap_test_id failed with $rc" && return 4
+
+       rc=0
+       delete_idmaps
+       rc=$?
+       [[ $rc != 0 ]] && error "nodemap_del_idmap failed with $rc" && return 5
+
+       rc=0
+       delete_nodemaps
+       rc=$?
+       [[ $rc != 0 ]] && error "nodemap_delete failed with $rc" && return 6
+
+       return 0
+}
+run_test 15 "test id mapping"
 
 log "cleanup: ======================================================"
 
 
 log "cleanup: ======================================================"
 
index a85a13f..8f47168 100644 (file)
@@ -230,9 +230,9 @@ command_t cmdlist[] = {
 
        /* Nodemap commands */
        {"=== Nodemap ===", jt_noop, 0, "nodemap management"},
 
        /* Nodemap commands */
        {"=== Nodemap ===", jt_noop, 0, "nodemap management"},
-       {"nodemap_activate_idmap", jt_nodemap_activate, 0,
+       {"nodemap_activate", jt_nodemap_activate, 0,
         "activate nodemap idmapping functions\n"
         "activate nodemap idmapping functions\n"
-        "usage: nodemap_activate_idmap"},
+        "usage: nodemap_activate"},
        {"nodemap_add", jt_nodemap_add, 0,
         "add a new nodemap\n"
         "usage: nodemap_add <nodemap_name>"},
        {"nodemap_add", jt_nodemap_add, 0,
         "add a new nodemap\n"
         "usage: nodemap_add <nodemap_name>"},
@@ -248,8 +248,14 @@ command_t cmdlist[] = {
        {"nodemap_modify", jt_nodemap_modify, 0,
         "modify a nodemap parameters"
         "usage: nodemap_modify nodemap_name param value"},
        {"nodemap_modify", jt_nodemap_modify, 0,
         "modify a nodemap parameters"
         "usage: nodemap_modify nodemap_name param value"},
+       {"nodemap_add_idmap", jt_nodemap_add_idmap, 0,
+        "add a UID or GID mapping to a nodemap"},
+       {"nodemap_del_idmap", jt_nodemap_del_idmap, 0,
+        "delete a UID or GID mapping from a nodemap"},
        {"nodemap_test_nid", jt_nodemap_test_nid, 0,
         "usage: nodemap_test_nid <nid>"},
        {"nodemap_test_nid", jt_nodemap_test_nid, 0,
         "usage: nodemap_test_nid <nid>"},
+       {"nodemap_test_id", jt_nodemap_test_id, 0,
+        "Usage: nodemap_test_id --nid <nid> --idtype [uid|gid] --id <id>"},
 
         /* Changelog commands */
         {"===  Changelogs ==", jt_noop, 0, "changelog user management"},
 
         /* Changelog commands */
         {"===  Changelogs ==", jt_noop, 0, "changelog user management"},
index 3a9bd09..acd66e3 100644 (file)
@@ -32,7 +32,7 @@ int llapi_nodemap_exists(const char *nodemap)
 {
        char mapname[PATH_MAX + 1];
 
 {
        char mapname[PATH_MAX + 1];
 
-       snprintf(mapname, sizeof(mapname) - 1, "nodemap/%s", nodemap);
+       snprintf(mapname, sizeof(mapname), "nodemap/%s", nodemap);
 
        return get_param(mapname, NULL, 0);
 }
 
        return get_param(mapname, NULL, 0);
 }
index 9964131..f0091de 100644 (file)
@@ -3506,7 +3506,8 @@ int jt_nodemap_activate(int argc, char **argv)
 {
        int rc;
 
 {
        int rc;
 
-       rc = nodemap_cmd(LCFG_NODEMAP_ACTIVATE, NULL, 0, argv[0], NULL);
+       rc = nodemap_cmd(LCFG_NODEMAP_ACTIVATE, NULL, 0, argv[0], argv[1],
+                        NULL);
 
        if (rc != 0) {
                errno = -rc;
 
        if (rc != 0) {
                errno = -rc;
@@ -3601,6 +3602,80 @@ int jt_nodemap_test_nid(int argc, char **argv)
 }
 
 /**
 }
 
 /**
+ * test a nodemap id pair for mapping
+ *
+ * \param      argc            number of args
+ * \param      argv[[]         variable string arguments
+ *
+ * \retval                     0 on success
+ *
+ * The argv array should contain the nodemap name, the id
+ * to checking the mapping on, and the id type (UID or GID)
+ *
+ */
+int jt_nodemap_test_id(int argc, char **argv)
+{
+       char    rawbuf[MAX_IOC_BUFLEN];
+       char    *nidstr = NULL;
+       char    *idstr = NULL;
+       char    *typestr = NULL;
+       int     rc = 0;
+       int     c;
+
+       static struct option long_options[] = {
+               {
+                       .name           = "nid",
+                       .has_arg        = required_argument,
+                       .flag           = 0,
+                       .val            = 'n',
+               },
+               {
+                       .name           = "idtype",
+                       .has_arg        = required_argument,
+                       .flag           = 0,
+                       .val            = 't',
+               },
+               {
+                       .name           = "id",
+                       .has_arg        = required_argument,
+                       .flag           = 0,
+                       .val            = 'i',
+               },
+               {
+                       NULL
+               }
+       };
+
+       while ((c = getopt_long(argc, argv, "n:t:i:",
+                               long_options, NULL)) != -1) {
+               switch (c) {
+               case 'n':
+                       nidstr = optarg;
+                       break;
+               case 't':
+                       typestr = optarg;
+                       break;
+               case 'i':
+                       idstr = optarg;
+                       break;
+               }
+       }
+
+       if (nidstr == NULL || typestr == NULL || idstr == NULL) {
+               fprintf(stderr, "usage: nodemap_test_id --nid <nid> "
+                               "--idtype [uid|gid] --id <id>\n");
+               return -1;
+       }
+
+       rc = nodemap_cmd(LCFG_NODEMAP_TEST_ID, &rawbuf, sizeof(rawbuf),
+                        argv[0], nidstr, typestr, idstr);
+       if (rc == 0)
+               printf("%s\n", (char *)rawbuf);
+
+       return rc;
+}
+
+/**
  * add an nid range to a nodemap
  *
  * \param      argc            number of args
  * add an nid range to a nodemap
  *
  * \param      argc            number of args
@@ -3793,10 +3868,12 @@ int jt_nodemap_del_range(int argc, char **argv)
  */
 int jt_nodemap_modify(int argc, char **argv)
 {
  */
 int jt_nodemap_modify(int argc, char **argv)
 {
-       int c;
-       int rc = 0;
-       enum lcfg_command_type cmd = 0;
-       char *nodemap_name = NULL, *param = NULL, *value = NULL;
+       int                     c;
+       int                     rc = 0;
+       enum lcfg_command_type  cmd = 0;
+       char                    *nodemap_name = NULL;
+       char                    *param = NULL;
+       char                    *value = NULL;
 
        static struct option long_options[] = {
                {
 
        static struct option long_options[] = {
                {
@@ -3870,6 +3947,149 @@ int jt_nodemap_modify(int argc, char **argv)
        return rc;
 }
 
        return rc;
 }
 
+int jt_nodemap_add_idmap(int argc, char **argv)
+{
+       int                     c;
+       enum                    lcfg_command_type cmd = 0;
+       char                    *nodemap_name = NULL;
+       char                    *idmap = NULL;
+       char                    *idtype = NULL;
+       int                     rc = 0;
+
+       static struct option long_options[] = {
+               {
+                       .name           = "name",
+                       .has_arg        = required_argument,
+                       .flag           = 0,
+                       .val            = 'n',
+               },
+               {
+                       .name           = "idmap",
+                       .has_arg        = required_argument,
+                       .flag           = 0,
+                       .val            = 'm',
+               },
+               {
+                       .name           = "idtype",
+                       .has_arg        = required_argument,
+                       .flag           = 0,
+                       .val            = 'i',
+               },
+               {
+                       NULL
+               }
+       };
+
+       while ((c = getopt_long(argc, argv, "n:m:i:",
+                               long_options, NULL)) != -1) {
+               switch (c) {
+               case 'n':
+                       nodemap_name = optarg;
+                       break;
+               case 'm':
+                       idmap = optarg;
+                       break;
+               case 'i':
+                       idtype = optarg;
+                       break;
+               }
+       }
+
+       if (nodemap_name == NULL || idmap == NULL || idtype == NULL) {
+               fprintf(stderr, "usage: %s --name <name> --idtype [uid | gid]"
+                       " --idmap <client id>:<filesystem id>\n", argv[0]);
+               return -1;
+       }
+
+       if (strcmp("uid", idtype) == 0) {
+               cmd = LCFG_NODEMAP_ADD_UIDMAP;
+       } else if (strcmp("gid", idtype) == 0) {
+               cmd = LCFG_NODEMAP_ADD_GIDMAP;
+       } else {
+               fprintf(stderr, "usage: %s --name <name> --idtype [uid | gid]"
+                       " --idmap <client id>:<filesystem id>\n", argv[0]);
+               return -1;
+       }
+
+       rc = nodemap_cmd(cmd, NULL, 0, argv[0], nodemap_name, idmap, NULL);
+       if (rc != 0) {
+               errno = -rc;
+               fprintf(stderr, "cannot add %smap '%s' to nodemap '%s'"
+                       ": rc = %d\n", idtype, idmap, nodemap_name, rc);
+       }
+
+       return rc;
+}
+
+int jt_nodemap_del_idmap(int argc, char **argv)
+{
+       int                     c;
+       enum                    lcfg_command_type cmd = 0;
+       char                    *nodemap_name = NULL;
+       char                    *idmap = NULL;
+       char                    *idtype = NULL;
+       int                     rc = 0;
+
+       static struct option long_options[] = {
+               {
+                       .name           = "name",
+                       .has_arg        = required_argument,
+                       .flag           = 0,
+                       .val            = 'n',
+               },
+               {
+                       .name           = "idmap",
+                       .has_arg        = required_argument,
+                       .flag           = 0,
+                       .val            = 'm',
+               },
+               {
+                       .name           = "idtype",
+                       .has_arg        = required_argument,
+                       .flag           = 0,
+                       .val            = 'i',
+               },
+               {
+                       NULL
+               }
+       };
+
+       while ((c = getopt_long(argc, argv, "n:m:i:",
+                               long_options, NULL)) != -1) {
+               switch (c) {
+               case 'n':
+                       nodemap_name = optarg;
+                       break;
+               case 'm':
+                       idmap = optarg;
+                       break;
+               case 'i':
+                       idtype = optarg;
+                       break;
+               }
+       }
+
+       if (nodemap_name == NULL || idmap == NULL || idtype == NULL) {
+               fprintf(stderr, "usage: %s --name <name> --idtype [uid | gid]"
+                       " --idmap <client id>:<filesystem id>\n", argv[0]);
+               return -1;
+       }
+
+       if (strcmp("uid", idtype) == 0)
+               cmd = LCFG_NODEMAP_DEL_UIDMAP;
+       else
+               cmd = LCFG_NODEMAP_DEL_GIDMAP;
+
+       rc = nodemap_cmd(cmd, NULL, 0, argv[0], nodemap_name, idmap, NULL);
+       if (rc != 0) {
+               errno = -rc;
+               fprintf(stderr, "cannot add %smap '%s' to nodemap '%s'"
+                       ": rc = %d\n", idtype, idmap, nodemap_name, rc);
+       }
+
+       return rc;
+}
+
 /*
  * this function tranforms a rule [start-end/step] into an array
  * of matching numbers
 /*
  * this function tranforms a rule [start-end/step] into an array
  * of matching numbers
index 49d5d40..b384e8a 100644 (file)
@@ -140,6 +140,9 @@ int jt_nodemap_modify(int argc, char **argv);
 int jt_nodemap_add_range(int argc, char **argv);
 int jt_nodemap_test_nid(int argc, char **argv);
 int jt_nodemap_del_range(int argc, char **argv);
 int jt_nodemap_add_range(int argc, char **argv);
 int jt_nodemap_test_nid(int argc, char **argv);
 int jt_nodemap_del_range(int argc, char **argv);
+int jt_nodemap_add_idmap(int argc, char **argv);
+int jt_nodemap_del_idmap(int argc, char **argv);
+int jt_nodemap_test_id(int argc, char **argv);
 int jt_changelog_register(int argc, char **argv);
 int jt_changelog_deregister(int argc, char **argv);
 
 int jt_changelog_register(int argc, char **argv);
 int jt_changelog_deregister(int argc, char **argv);