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 {
#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
/* 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 */
- struct rb_root nm_remote_to_local_uidmap;
+ struct rb_root nm_client_to_fs_uidmap;
/* 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 */
- 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 */
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_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);
-
-#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 */
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 fs_idstr[16];
int rc = 0;
+ __u32 client_id;
+ __u32 fs_id;
__u32 cmd;
+ int idtype;
ENTRY;
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)
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_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);
param = lustre_cfg_string(lcfg, 3);
rc = mgs_nodemap_cmd(env, mgs, cmd, nodemap_name, param);
break;
-
default:
rc = -ENOTTY;
}
const char *param)
{
lnet_nid_t nid[2];
+ __u32 idmap[2];
bool bool_switch;
__u32 int_id;
int rc = 0;
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;
}
-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@
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
range_delete(range);
}
+ idmap_delete_tree(nodemap);
+
lprocfs_remove(&nodemap->nm_proc_entry);
OBD_FREE_PTR(nodemap);
}
}
EXPORT_SYMBOL(nodemap_classify_nid);
-/*
+/**
* simple check for default nodemap
*/
static bool is_default_nodemap(const struct lu_nodemap *nodemap)
return nodemap->nm_id == 0;
}
-/*
+/**
* parse a nodemap range string into two nids
*
* \param range_str string to parse
}
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
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;
return rc;
}
-/*
+/**
* update flag to turn on or off nodemap functions
* \param name nodemap name
* \param admin_string string containing updated value
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)
--- /dev/null
+/*
+ * 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);
+ }
+}
/* 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 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 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);
+
+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 */
#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;
+ bool cont = 0;
-
+ seq_printf(m, "[\n");
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;
}
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
active_string[count] = '\0';
active = simple_strtoul(active_string, NULL, 10);
- nodemap_idmap_active = active;
+ nodemap_active = active;
return rc;
}
.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",
.fops = &nodemap_ranges_fops,
},
{
+ .name = "idmap",
+ .fops = &nodemap_idmap_fops,
+ },
+ {
NULL
}
};
--- /dev/null
+/*
+ * 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);
+}
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
}
add_range() {
- local i
local j
local cmd="$LCTL nodemap_add_range"
local range
return $rc
}
-del_range() {
- local i
+delete_range() {
local j
local cmd="$LCTL nodemap_del_range"
local range
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 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
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=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
}
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: ======================================================"
/* 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"
- "usage: nodemap_activate_idmap"},
+ "usage: nodemap_activate"},
{"nodemap_add", jt_nodemap_add, 0,
"add a new nodemap\n"
"usage: nodemap_add <nodemap_name>"},
{"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_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"},
{
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);
}
{
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;
}
/**
+ * 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
*/
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[] = {
{
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
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);