Introduce a new rn_subtree field in struct lu_nid_range.
This allows to have NID ranges included into other NID ranges,
hence creating a NID range hierarchy. NID ranges are created in
a subtree only if there is already a range in the parent tree
that includes it. Overlapping NID ranges remain forbidden.
Introduce new fields nm_subnodemaps, nm_parent_entry in struct
lu_nodemap to keep track of the sub-nodemaps attached to a given
nodemap. Also use a new nm_parent_nm field that points to the parent
nodemap. This allows to create a nodemap hierarchy, based on the
NID ranges.
Introduce a new -p|--parent option to lctl nodemap_add to specify
the parent nodemap of a dynamic nodemap at creation time. The NID
ranges of the child nodemap must be included in the ranges of the
parent nodemap. A dynamic nodemap can have only one parent.
Make a sub-nodemap inherit all the parent nodemap's properties,
and the id mapping as well. And expose parent name as part of nodemap
properties. This is valid for dynamic nodemaps only.
Signed-off-by: Sebastien Buisson <sbuisson@ddn.com>
Change-Id: I04a14db92c068f3cb5b6b39e75feb802cebacd8a
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/54739
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Marc Vef <mvef@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
or
.SY "lctl nodemap add"
.RB [ -d | --dynamic ]
+.RB [ -p |
+.BI --parent " PARENT_NAME"
+]
.BI --name " NODEMAP_NAME"
.YS
.SH DESCRIPTION
Adds a temporary in-memory nodemap on the local node instead of a persistent
one.
.TP
+.BI -p ", " --parent " PARENT_NAME"
+Mandatory for dynamic nodemap. Specifies the parent nodemap to inherit
+properties from. This can be "default".
+.TP
.BI --name " NODEMAP_NAME"
The name to give the new nodemap. It can be any alphanumeric string of maximum
length 16, except
unsigned int nm_offset_start_projid;
/* number of values allocated to PROJID offset */
unsigned int nm_offset_limit_projid;
+ /* list of sub-nodemaps */
+ struct list_head nm_subnodemaps;
+ /* list entry for parent nodemap */
+ struct list_head nm_parent_entry;
+ /* link to parent nodemap */
+ struct lu_nodemap *nm_parent_nm;
};
/* Store handles to local MGC storage to save config locally. In future
DEFINE_MUTEX(active_config_lock);
struct nodemap_config *active_config;
+static int nodemap_copy_fileset(struct lu_nodemap *dst, struct lu_nodemap *src);
+
/**
* Nodemap destructor
*
mutex_unlock(&active_config_lock);
+ if (nodemap->nm_parent_nm) {
+ list_del(&nodemap->nm_parent_entry);
+ nodemap_putref(nodemap->nm_parent_nm);
+ }
+
if (!list_empty(&nodemap->nm_member_list))
CWARN("nodemap_destroy failed to reclassify all members\n");
+ if (!list_empty(&nodemap->nm_subnodemaps))
+ CWARN("nodemap_destroy failed to reclassify all subnodemaps\n");
+
nm_member_delete_list(nodemap);
OBD_FREE_PTR(nodemap);
}
EXPORT_SYMBOL(nodemap_map_acl);
-static void nodemap_inherit_properties(struct lu_nodemap *dst,
- struct lu_nodemap *src,
- bool is_new)
+static int nodemap_inherit_properties(struct lu_nodemap *dst,
+ struct lu_nodemap *src)
{
+ int rc = 0;
+
if (!src) {
dst->nmf_trust_client_ids = 0;
dst->nmf_allow_root_access = 0;
dst->nm_squash_uid = src->nm_squash_uid;
dst->nm_squash_gid = src->nm_squash_gid;
dst->nm_squash_projid = src->nm_squash_projid;
- if (is_new) {
- dst->nm_sepol[0] = '\0';
- }
dst->nm_offset_start_uid = src->nm_offset_start_uid;
dst->nm_offset_limit_uid = src->nm_offset_limit_uid;
dst->nm_offset_start_gid = src->nm_offset_start_gid;
dst->nm_offset_limit_gid = src->nm_offset_limit_gid;
dst->nm_offset_start_projid = src->nm_offset_start_projid;
dst->nm_offset_limit_projid = src->nm_offset_limit_projid;
- /* filesets cannot yet be inherited */
- dst->nm_prim_fileset = NULL;
- dst->nm_prim_fileset_size = 0;
+ if (src->nm_id == LUSTRE_NODEMAP_DEFAULT_ID) {
+ dst->nm_sepol[0] = '\0';
+ } else {
+ /* because we are copying from an existing nodemap,
+ * we already know this string is well formatted
+ */
+ strcpy(dst->nm_sepol, src->nm_sepol);
+ rc = idmap_copy_tree(dst, src);
+ if (rc)
+ goto out;
+ }
+ /* only dynamic nodemap inherits fileset from parent */
+ if (dst->nm_dyn) {
+ rc = nodemap_copy_fileset(dst, src);
+ if (rc)
+ goto out;
+ } else {
+ dst->nm_prim_fileset = NULL;
+ dst->nm_prim_fileset_size = 0;
+ }
}
+
+out:
+ return rc;
}
/*
const struct lnet_nid nid[2],
u8 netmask, unsigned int range_id)
{
+ struct lu_nid_range *prange = NULL;
struct lu_nid_range *range;
int rc;
GOTO(out, rc = -ENOMEM);
}
- rc = range_insert(config, range);
+ rc = range_insert(config, range, &prange, nodemap->nm_dyn);
if (rc) {
CDEBUG_LIMIT(rc == -EEXIST ? D_INFO : D_ERROR,
"cannot insert nodemap range into '%s': rc = %d\n",
GOTO(out, rc);
}
+ if (nodemap->nm_dyn) {
+ /* Verify that the parent already associated with the nodemap
+ * is the one the prange belongs to.
+ */
+ struct lu_nodemap *parent;
+
+ if (!nodemap->nm_parent_nm ||
+ list_empty(&nodemap->nm_parent_entry)) {
+ CDEBUG(D_INFO, "dynamic nodemap %s has no parent\n",
+ nodemap->nm_name);
+ GOTO(err_parent, rc = -EINVAL);
+ }
+ parent = prange ?
+ prange->rn_nodemap : config->nmc_default_nodemap;
+ if (nodemap->nm_parent_nm != parent) {
+ CDEBUG(D_INFO,
+ "%s: range [%s-%s] is not included in range of parent nodemap %s\n",
+ nodemap->nm_name,
+ libcfs_nidstr(&nid[0]), libcfs_nidstr(&nid[1]),
+ nodemap->nm_parent_nm->nm_name);
+err_parent:
+ range_delete(config, range);
+ up_write(&config->nmc_range_tree_lock);
+ GOTO(out, rc = -EINVAL);
+ }
+ }
list_add(&range->rn_list, &nodemap->nm_ranges);
/* nodemaps have no members if they aren't on the active config */
}
/**
+ * Copy a fileset from a source to a destination nodemap. This is a local,
+ * non-persistent operation made for dynamic nodemaps.
+ * *
+ * \param dst the nodemap to set fileset on
+ * \param src the nodemap to fetch fileset from
+ * \retval 0 on success
+ * \retval < 0 on error
+ */
+static int nodemap_copy_fileset(struct lu_nodemap *dst, struct lu_nodemap *src)
+{
+ char *fileset;
+ int rc = 0;
+
+ fileset = nodemap_get_fileset(src);
+ if (!fileset) {
+ dst->nm_prim_fileset = NULL;
+ dst->nm_prim_fileset_size = 0;
+ } else {
+ /* nodemap_set_fileset_iam() knows how to
+ * handle a dynamic nodemap
+ */
+ rc = nodemap_set_fileset_iam(dst, fileset);
+ }
+
+ return rc;
+}
+
+/**
* Set fileset on a named nodemap
*
* \param name name of the nodemap to set fileset on
RETURN(PTR_ERR(nodemap));
}
+ /* FIXME: for now the fileset on a dynamic nodemap can just be
+ * inherited from the parent, not set explicitly
+ */
+ if (nodemap->nm_dyn)
+ GOTO(out_unlock, rc = -EPERM);
+
if (checkperm && !allow_op_on_nm(nodemap))
GOTO(out_unlock, rc = -EPERM);
*/
struct lu_nodemap *nodemap_create(const char *name,
struct nodemap_config *config,
- bool is_default)
+ bool is_default, bool dynamic)
{
struct lu_nodemap *nodemap = NULL;
struct lu_nodemap *default_nodemap;
- struct lu_nodemap *parent_nodemap;
+ struct lu_nodemap *parent_nodemap = NULL;
struct cfs_hash *hash = config->nmc_nodemap_hash;
+ char newname[LUSTRE_NODEMAP_NAME_LENGTH + 1];
int rc = 0;
ENTRY;
default_nodemap = config->nmc_default_nodemap;
- if (!nodemap_name_is_valid(name))
+ if (dynamic) {
+ char pname[LUSTRE_NODEMAP_NAME_LENGTH + 1];
+ char format[32];
+
+ /* for a dynamic nodemap, nodemap_name is in the form:
+ * parent_name/new_name
+ */
+ if (!strchr(name, '/'))
+ GOTO(out, rc = -EINVAL);
+ rc = snprintf(format, sizeof(format), "%%%zu[^/]/%%%zus",
+ sizeof(pname) - 1, sizeof(newname) - 1);
+ if (rc >= sizeof(format))
+ GOTO(out, rc = -ENAMETOOLONG);
+ rc = sscanf(name, format, pname, newname);
+ if (rc != 2)
+ GOTO(out, rc = -EINVAL);
+
+ if (!nodemap_name_is_valid(pname))
+ GOTO(out, rc = -EINVAL);
+
+ /* the call to nodemap_create for a dynamic nodemap comes from
+ * nodemap_add, which holds the active_config_lock
+ */
+ parent_nodemap = nodemap_lookup(pname);
+ if (IS_ERR(parent_nodemap))
+ GOTO(out, rc = PTR_ERR(parent_nodemap));
+ } else {
+ rc = snprintf(newname, sizeof(newname), "%s", name);
+ if (rc >= sizeof(newname))
+ GOTO(out, rc = -ENAMETOOLONG);
+ }
+
+ if (!nodemap_name_is_valid(newname))
GOTO(out, rc = -EINVAL);
if (hash == NULL) {
}
OBD_ALLOC_PTR(nodemap);
- if (nodemap == NULL) {
+ if (!nodemap) {
CERROR("cannot allocate memory (%zu bytes) for nodemap '%s'\n",
sizeof(*nodemap), name);
GOTO(out, rc = -ENOMEM);
* while it's being created.
*/
refcount_set(&nodemap->nm_refcount, 2);
- snprintf(nodemap->nm_name, sizeof(nodemap->nm_name), "%s", name);
- rc = cfs_hash_add_unique(hash, name, &nodemap->nm_hash);
- if (rc != 0) {
- OBD_FREE_PTR(nodemap);
+ snprintf(nodemap->nm_name, sizeof(nodemap->nm_name), "%s", newname);
+
+ 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;
+ nodemap->nm_fs_to_client_projidmap = RB_ROOT;
+ nodemap->nm_client_to_fs_projidmap = RB_ROOT;
+
+ nodemap->nm_dyn = dynamic;
+ if (!parent_nodemap)
+ rc = nodemap_inherit_properties(nodemap,
+ is_default ? NULL : default_nodemap);
+ else
+ rc = nodemap_inherit_properties(nodemap, parent_nodemap);
+ if (rc)
+ GOTO(out, rc);
+
+ rc = cfs_hash_add_unique(hash, newname, &nodemap->nm_hash);
+ if (rc)
GOTO(out, rc = -EEXIST);
- }
INIT_LIST_HEAD(&nodemap->nm_ranges);
INIT_LIST_HEAD(&nodemap->nm_list);
INIT_LIST_HEAD(&nodemap->nm_member_list);
+ INIT_LIST_HEAD(&nodemap->nm_subnodemaps);
+ INIT_LIST_HEAD(&nodemap->nm_parent_entry);
+ nodemap->nm_parent_nm = parent_nodemap;
+ if (parent_nodemap)
+ list_add(&nodemap->nm_parent_entry,
+ &parent_nodemap->nm_subnodemaps);
mutex_init(&nodemap->nm_member_list_lock);
init_rwsem(&nodemap->nm_idmap_lock);
- 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;
- nodemap->nm_fs_to_client_projidmap = RB_ROOT;
- nodemap->nm_client_to_fs_projidmap = RB_ROOT;
if (is_default) {
nodemap->nm_id = LUSTRE_NODEMAP_DEFAULT_ID;
CWARN("adding nodemap '%s' to config without default nodemap\n",
nodemap->nm_name);
- parent_nodemap = is_default ? NULL : default_nodemap;
- nodemap_inherit_properties(nodemap, parent_nodemap, true);
-
RETURN(nodemap);
out:
+ OBD_FREE_PTR(nodemap);
+ if (!IS_ERR_OR_NULL(parent_nodemap))
+ nodemap_putref(parent_nodemap);
CERROR("cannot add nodemap: '%s': rc = %d\n", name, rc);
RETURN(ERR_PTR(rc));
}
int rc;
mutex_lock(&active_config_lock);
- nodemap = nodemap_create(nodemap_name, active_config, 0);
+ nodemap = nodemap_create(nodemap_name, active_config, 0, dynamic);
if (IS_ERR(nodemap)) {
mutex_unlock(&active_config_lock);
return PTR_ERR(nodemap);
}
- nodemap->nm_dyn = dynamic;
rc = nodemap_idx_nodemap_add(nodemap);
if (rc == 0)
nodemap_putref(nodemap);
GOTO(out, rc = -EPERM);
}
+
+ /* delete sub-nodemaps first */
+ if (!list_empty(&nodemap->nm_subnodemaps)) {
+ struct lu_nodemap *nm, *nm_temp;
+
+ list_for_each_entry_safe(nm, nm_temp, &nodemap->nm_subnodemaps,
+ nm_parent_entry) {
+ /* do our best and report any error on sub-nodemaps
+ * but do not forward rc
+ */
+ rc2 = nodemap_del(nm->nm_name);
+ CDEBUG_LIMIT(D_INFO,
+ "cannot del sub-nodemap %s: rc = %d\n",
+ nm->nm_name, rc2);
+ }
+ }
nodemap_putref(nodemap);
/* we had dropped lock, so fetch nodemap again */
lprocfs_nodemap_remove(nodemap->nm_pde_data);
nodemap->nm_pde_data = NULL;
+ if (!list_empty(&nodemap->nm_subnodemaps))
+ CWARN("%s: nodemap_del failed to remove all subnodemaps\n",
+ nodemap_name);
+
/* reclassify all member exports from nodemap, so they put their refs */
down_read(&active_config->nmc_range_tree_lock);
nm_member_reclassify_nodemap(nodemap);
up_read(&active_config->nmc_range_tree_lock);
if (!list_empty(&nodemap->nm_member_list))
- CWARN("nodemap_del failed to reclassify all members\n");
+ CWARN("%s: nodemap_del failed to reclassify all members\n",
+ nodemap_name);
mutex_unlock(&active_config_lock);
nodemap_putref(nodemap);
GOTO(out, rc = PTR_ERR(new_config));
}
- nodemap = nodemap_create(DEFAULT_NODEMAP, new_config, 1);
+ nodemap = nodemap_create(DEFAULT_NODEMAP, new_config, 1, false);
if (IS_ERR(nodemap)) {
nodemap_config_dealloc(new_config);
nodemap_procfs_exit();
/**
* Insert idmap into the proper trees
*
- * \param id_type NODEMAP_UID or NODEMAP_GID
+ * \param id_type NODEMAP_UID or NODEMAP_GID or NODEMAP_PROJID
* \param idmap lu_idmap structure to insert
* \param nodemap nodemap to associate with the map
*
idmap_destroy(idmap);
}
}
+
+/*
+ * copy all idmap trees from a source nodemap to a dest nodemap
+ *
+ * \param dst nodemap to copy trees to
+ * \param src nodemap to copy trees from
+ *
+ * \retval 0 on success, error code otherwise
+ *
+ * This uses the postorder safe traversal code that is committed
+ * in a later kernel. Each lu_idmap structure is copied.
+ * No need for this function to hold nm_idmap_lock, as it is called
+ * only when a sub-nodemap is first attached to a parent.
+ */
+int idmap_copy_tree(struct lu_nodemap *dst, struct lu_nodemap *src)
+{
+ struct lu_idmap *idmap, *temp, *idmap_new, *err;
+ struct rb_root root;
+ int rc = 0;
+
+ root = src->nm_fs_to_client_uidmap;
+ rbtree_postorder_for_each_entry_safe(idmap, temp, &root,
+ id_fs_to_client) {
+ idmap_new = idmap_create(idmap->id_client, idmap->id_fs);
+ if (!idmap_new)
+ GOTO(out_copy_tree, rc = -ENOMEM);
+
+ err = idmap_insert(NODEMAP_UID, idmap_new, dst);
+ if (err) {
+ OBD_FREE_PTR(idmap);
+ GOTO(out_copy_tree,
+ rc = IS_ERR(err) ? PTR_ERR(err) : -EEXIST);
+ }
+ }
+
+ root = src->nm_client_to_fs_gidmap;
+ rbtree_postorder_for_each_entry_safe(idmap, temp, &root,
+ id_client_to_fs) {
+ idmap_new = idmap_create(idmap->id_client, idmap->id_fs);
+ if (!idmap_new)
+ GOTO(out_copy_tree, rc = -ENOMEM);
+
+ err = idmap_insert(NODEMAP_GID, idmap_new, dst);
+ if (err) {
+ OBD_FREE_PTR(idmap);
+ GOTO(out_copy_tree,
+ rc = IS_ERR(err) ? PTR_ERR(err) : -EEXIST);
+ }
+ }
+
+ root = src->nm_client_to_fs_projidmap;
+ rbtree_postorder_for_each_entry_safe(idmap, temp, &root,
+ id_client_to_fs) {
+ idmap_new = idmap_create(idmap->id_client, idmap->id_fs);
+ if (!idmap_new)
+ GOTO(out_copy_tree, rc = -ENOMEM);
+
+ err = idmap_insert(NODEMAP_PROJID, idmap_new, dst);
+ if (err) {
+ OBD_FREE_PTR(idmap);
+ GOTO(out_copy_tree,
+ rc = IS_ERR(err) ? PTR_ERR(err) : -EEXIST);
+ }
+ }
+
+out_copy_tree:
+ if (rc)
+ CDEBUG(D_INFO,
+ "Copying idmap %d:%d from %s to %s failed: rc=%d\n",
+ idmap->id_client, idmap->id_fs,
+ src->nm_name, dst->nm_name, rc);
+ return rc;
+}
*/
struct list_head rn_nidlist;
struct rb_node rn_rb;
+ /* sub ranges included in this NID range */
+ struct nodemap_range_tree rn_subtree;
};
struct lu_idmap {
void nodemap_config_set_active(struct nodemap_config *config);
struct lu_nodemap *nodemap_create(const char *name,
struct nodemap_config *config,
- bool is_default);
+ bool is_default, bool dynamic);
void nodemap_putref(struct lu_nodemap *nodemap);
struct lu_nodemap *nodemap_lookup(const char *name);
u8 netmask, struct lu_nodemap *nodemap,
unsigned int range_id);
void range_destroy(struct lu_nid_range *range);
-int range_insert(struct nodemap_config *config, struct lu_nid_range *data);
+int range_insert(struct nodemap_config *config, struct lu_nid_range *range,
+ struct lu_nid_range **parent_range, bool dynamic);
void range_delete(struct nodemap_config *config, struct lu_nid_range *data);
struct lu_nid_range *range_search(struct nodemap_config *config,
struct lnet_nid *nid);
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);
+int idmap_copy_tree(struct lu_nodemap *dst, struct lu_nodemap *src);
struct lu_idmap *idmap_search(struct lu_nodemap *nodemap,
enum nodemap_tree_type,
enum nodemap_id_type id_type,
return 0;
}
+/**
+ * Reads and prints the name of the parent nodemap for the given nodemap.
+ *
+ * \param seq seq file in proc fs
+ * \param data unused
+ * \retval 0 success
+ */
+static int nodemap_parent_seq_show(struct seq_file *seq, void *data)
+{
+ struct lu_nodemap *nodemap;
+ char *pname;
+ int rc;
+
+ mutex_lock(&active_config_lock);
+ nodemap = nodemap_lookup(seq->private);
+ mutex_unlock(&active_config_lock);
+ if (IS_ERR(nodemap)) {
+ rc = PTR_ERR(nodemap);
+ CERROR("cannot find nodemap '%s': rc = %d\n",
+ (char *)seq->private, rc);
+ return rc;
+ }
+
+ if (nodemap->nm_dyn) {
+ if (nodemap->nm_parent_nm)
+ pname = nodemap->nm_parent_nm->nm_name;
+ else
+ pname = DEFAULT_NODEMAP;
+ } else {
+ pname = "";
+ }
+
+ seq_printf(seq, "%s\n", pname);
+ nodemap_putref(nodemap);
+ return 0;
+}
+
static struct ldebugfs_vars lprocfs_nm_module_vars[] = {
{
.name = "active",
LDEBUGFS_SEQ_FOPS_RO(nodemap_forbid_encryption);
LDEBUGFS_SEQ_FOPS_RO(nodemap_readonly_mount);
LDEBUGFS_SEQ_FOPS_RO(nodemap_deny_mount);
+LDEBUGFS_SEQ_FOPS_RO(nodemap_parent);
static const struct file_operations nodemap_ranges_fops = {
.open = nodemap_ranges_open,
.fops = &nodemap_map_mode_fops,
},
{
+ .name = "parent",
+ .fops = &nodemap_parent_fops,
+ },
+ {
.name = "ranges",
.fops = &nodemap_ranges_fops,
},
INTERVAL_TREE_DEFINE(struct lu_nid_range, rn_rb, lnet_nid_t, rn_subtree_last,
START, LAST, static, nm_range)
+static int __range_is_included(lnet_nid_t needle_start, lnet_nid_t needle_end,
+ struct lu_nid_range *haystack)
+{
+ return LNET_NIDADDR(START(haystack)) <= LNET_NIDADDR(needle_start) &&
+ LNET_NIDADDR(LAST(haystack)) >= LNET_NIDADDR(needle_end);
+}
+
+static int range_is_included(struct lu_nid_range *needle,
+ struct lu_nid_range *haystack)
+{
+ return __range_is_included(START(needle), LAST(needle), haystack);
+}
+
/*
* range constructor
*
INIT_LIST_HEAD(&range->rn_nidlist);
if (!list_empty(&tmp_nidlist))
list_splice(&tmp_nidlist, &range->rn_nidlist);
+ range->rn_subtree.nmrt_range_interval_root = INTERVAL_TREE_ROOT;
return range;
}
range = nm_range_iter_first(&nm_range_tree->nmrt_range_interval_root,
nid4[0], nid4[1]);
- while (range &&
- (!nid_same(&range->rn_start, start_nid) ||
- !nid_same(&range->rn_end, end_nid)))
+ while (range) {
+ if (nid_same(&range->rn_start, start_nid) &&
+ nid_same(&range->rn_end, end_nid))
+ break;
+ if (__range_is_included(nid4[0], nid4[1], range))
+ return __range_find(&range->rn_subtree,
+ start_nid, end_nid);
range = nm_range_iter_next(range, nid4[0], nid4[1]);
+ }
return range;
}
* to exactly one range
*/
static int __range_insert(struct nodemap_range_tree *nm_range_tree,
- struct lu_nid_range *range)
+ struct lu_nid_range *range,
+ struct lu_nid_range **parent_range, bool dynamic)
{
- if (nm_range_iter_first(&nm_range_tree->nmrt_range_interval_root,
- lnet_nid_to_nid4(&range->rn_start),
- lnet_nid_to_nid4(&range->rn_end)))
- return -EEXIST;
+ struct lu_nid_range *found = NULL;
+ int rc = 0;
+
+ found = nm_range_iter_first(&nm_range_tree->nmrt_range_interval_root,
+ lnet_nid_to_nid4(&range->rn_start),
+ lnet_nid_to_nid4(&range->rn_end));
+ if (found) {
+ if (dynamic && range_is_included(range, found)) {
+ rc = __range_insert(&found->rn_subtree,
+ range, parent_range, dynamic);
+ if (!rc) {
+ if (parent_range && !*parent_range)
+ *parent_range = found;
+ }
+ } else {
+ rc = -EEXIST;
+ }
+ GOTO(out_insert, rc);
+ }
nm_range_insert(range,
&nm_range_tree->nmrt_range_interval_root);
- return 0;
+
+out_insert:
+ return rc;
}
-int range_insert(struct nodemap_config *config, struct lu_nid_range *range)
+int range_insert(struct nodemap_config *config, struct lu_nid_range *range,
+ struct lu_nid_range **parent_range, bool dynamic)
{
int rc = 0;
if (!range->rn_netmask) {
- rc = __range_insert(&config->nmc_range_tree, range);
+ rc = __range_insert(&config->nmc_range_tree,
+ range, parent_range, dynamic);
} else {
if (range_find(config, &range->rn_start, &range->rn_end,
range->rn_netmask))
static void __range_delete(struct nodemap_range_tree *nm_range_tree,
struct lu_nid_range *range)
{
- nm_range_remove(range,
- &nm_range_tree->nmrt_range_interval_root);
+ struct lu_nid_range *found;
+ lnet_nid_t nid4[2];
+
+ nid4[0] = lnet_nid_to_nid4(&range->rn_start);
+ nid4[1] = lnet_nid_to_nid4(&range->rn_end);
+
+ found = nm_range_iter_first(&nm_range_tree->nmrt_range_interval_root,
+ nid4[0], nid4[1]);
+ while (found) {
+ if (nid_same(&found->rn_start, &range->rn_start) &&
+ nid_same(&found->rn_end, &range->rn_end))
+ break;
+ if (__range_is_included(nid4[0], nid4[1], found)) {
+ __range_delete(&found->rn_subtree, range);
+ return;
+ }
+ found = nm_range_iter_next(found, nid4[0], nid4[1]);
+ }
+
+ if (found)
+ nm_range_remove(found,
+ &nm_range_tree->nmrt_range_interval_root);
}
void range_delete(struct nodemap_config *config, struct lu_nid_range *range)
struct lu_nid_range *__range_search(struct nodemap_range_tree *nm_range_tree,
struct lnet_nid *nid)
{
- return nm_range_iter_first(&nm_range_tree->nmrt_range_interval_root,
- lnet_nid_to_nid4(nid),
- lnet_nid_to_nid4(nid));
+ struct lu_nid_range *range, *subrange;
+
+ range = nm_range_iter_first(&nm_range_tree->nmrt_range_interval_root,
+ lnet_nid_to_nid4(nid),
+ lnet_nid_to_nid4(nid));
+ if (range) {
+ subrange = __range_search(&range->rn_subtree, nid);
+ if (subrange)
+ range = subrange;
+ }
+
+ return range;
}
struct lu_nid_range *range_search(struct nodemap_config *config,
ENTRY;
- if (!nodemap_mgs()) {
- if (nodemap->nm_dyn)
- return 0;
+ if (nodemap->nm_dyn)
+ return 0;
+ if (!nodemap_mgs()) {
rc = -EINVAL;
CERROR("%s: cannot add nodemap config to non-existing MGS: rc = %d\n",
nodemap->nm_name, rc);
ENTRY;
- if (!nodemap_mgs()) {
- if (nodemap->nm_dyn)
- return 0;
+ if (nodemap->nm_dyn)
+ return 0;
+ if (!nodemap_mgs()) {
rc = -EINVAL;
CERROR("%s: cannot add nodemap config to non-existing MGS: rc = %d\n",
nodemap->nm_name, rc);
ENTRY;
- if (!nodemap_mgs()) {
- if (nodemap->nm_dyn)
- return 0;
+ if (nodemap->nm_dyn)
+ return 0;
+ if (!nodemap_mgs()) {
rc = -EINVAL;
CERROR("%s: cannot add nodemap config to non-existing MGS: rc = %d\n",
nodemap->nm_name, rc);
ENTRY;
- if (!nodemap_mgs()) {
- if (nodemap->nm_dyn)
- return 0;
+ if (nodemap->nm_dyn)
+ return 0;
+ if (!nodemap_mgs()) {
rc = -EINVAL;
CERROR("%s: cannot add nodemap config to non-existing MGS: rc = %d\n",
nodemap->nm_name, rc);
nodemap = cfs_hash_lookup(config->nmc_nodemap_hash, rec->ncr.ncr_name);
if (nodemap == NULL) {
if (nodemap_id == LUSTRE_NODEMAP_DEFAULT_ID)
- nodemap = nodemap_create(rec->ncr.ncr_name, config, 1);
+ nodemap = nodemap_create(rec->ncr.ncr_name, config, 1,
+ false);
else
- nodemap = nodemap_create(rec->ncr.ncr_name, config, 0);
+ nodemap = nodemap_create(rec->ncr.ncr_name, config, 0,
+ false);
if (IS_ERR(nodemap))
return PTR_ERR(nodemap);
if (new_config->nmc_default_nodemap == NULL) {
/* new MGS won't have a default nm on disk, so create it here */
struct lu_nodemap *nodemap =
- nodemap_create(DEFAULT_NODEMAP, new_config, 1);
+ nodemap_create(DEFAULT_NODEMAP, new_config, 1, false);
if (IS_ERR(nodemap)) {
rc = PTR_ERR(nodemap);
} else {
local nids=1.1.1.[1-100]@tcp
local startnid=1.1.1.1@tcp
local endnid=1.1.1.100@tcp
+ local subnids1=1.1.1.[2-50]@tcp
+ local subnids2=1.1.1.[51-100]@tcp
+ local subnids3=1.1.1.[2-25]@tcp
+ local subnids4=1.1.1.[51-52]@tcp
+ local subnids5=1.1.1.[26-60]@tcp
+ local subnids6=1.1.1.[1-60]@tcp
local clid=500
local fsid=1000
local properties="audit_mode deny_unknown forbid_encryption \
stack_trap cleanup_active EXIT
fi
+ do_facet mgs $LCTL nodemap_set_fileset --name default \
+ --fileset "/deffset" ||
+ error "setting fileset on default failed"
do_facet mgs $LCTL nodemap_add $mgsnm ||
error "adding $mgsnm on MGS failed"
stack_trap "do_facet mgs $LCTL nodemap_del $mgsnm" EXIT
stack_trap "do_facet ost1 $LCTL nodemap_del $nm || true" EXIT
do_facet ost1 $LCTL nodemap_add $nm &&
error "static nodemap on server should fail"
- do_facet ost1 $LCTL nodemap_add -d $nm ||
+ do_facet ost1 $LCTL nodemap_add -d $nm &&
+ error "dynamic nodemap without parent should fail"
+ do_facet ost1 $LCTL nodemap_add -d -p default $nm ||
error "dynamic nodemap on server failed"
val=$(do_facet ost1 $LCTL get_param -n nodemap.$nm.id)
- if [[ "x$val" == "x" ]] || [[ "x$val" == "x0" ]]; then
+ if [[ -z "$val" || "$val" == "0" ]]; then
error "dynamic nodemap wrong id $val"
fi
error "dynamic add_range on server failed"
val=$(do_facet ost1 $LCTL get_param nodemap.$nm.ranges |
awk 'BEGIN{RS=", "} $1=="start_nid:"{print $2 ; exit}')
- if [[ "x$val" != "x$startnid" ]]; then
+ [[ "$val" == "$startnid" ]] ||
error "dynamic nodemap wrong start nid range $val"
- fi
val=$(do_facet ost1 $LCTL get_param nodemap.$nm.ranges |
awk 'BEGIN{RS=", "} $1=="end_nid:"{print $2 ; exit}')
- if [[ "x$val" != "x$endnid" ]]; then
+ [[ "$val" == "$endnid" ]] ||
error "dynamic nodemap wrong end nid range $val"
- fi
do_facet ost1 $LCTL nodemap_add_idmap --name $nm --idtype uid \
--idmap $clid:$fsid ||
error "dynamic add_idmap on server failed"
val=$(do_facet ost1 $LCTL get_param nodemap.$nm.idmap |
awk 'BEGIN{RS=", "} $1=="client_id:"{print $2 ; exit}')
- if [[ "x$val" != "x$clid" ]]; then
- error "dynamic nodemap wrong client id $val"
- fi
+ (( val == clid )) || error "dynamic nodemap wrong client id $val"
val=$(do_facet ost1 $LCTL get_param nodemap.$nm.idmap |
awk 'BEGIN{RS=", "} $1=="fs_id:"{print $2 ; exit}')
- if [[ "x$val" != "x$fsid" ]]; then
- error "dynamic nodemap wrong fs id $val"
- fi
+ (( val == fsid )) || error "dynamic nodemap wrong fs id $val"
for prop in $properties; do
do_facet ost1 $LCTL nodemap_modify --name $nm \
--property $prop --value 1 ||
error "dynamic modify of $prop failed"
val=$(do_facet ost1 $LCTL get_param -n nodemap.$nm.$prop)
- [[ "x$val" == "x1" ]] || error "incorrect $prop $val"
+ (( val == 1 )) || error "incorrect $prop $val"
done
prop=admin
do_facet ost1 $LCTL nodemap_modify --name $nm \
--property $prop --value 1 ||
error "dynamic modify of $prop failed"
val=$(do_facet ost1 $LCTL get_param -n nodemap.$nm.admin_nodemap)
- [[ "x$val" == "x1" ]] || error "incorrect $prop $val"
+ (( val == 1 )) || error "incorrect $prop $val"
prop=trusted
do_facet ost1 $LCTL nodemap_modify --name $nm \
--property $prop --value 0 ||
error "dynamic modify of $prop failed"
val=$(do_facet ost1 $LCTL get_param -n nodemap.$nm.trusted_nodemap)
- [[ "x$val" == "x0" ]] || error "incorrect $prop $val"
+ (( val == 0 )) || error "incorrect $prop $val"
prop=map_mode
do_facet ost1 $LCTL nodemap_modify --name $nm \
--property $prop --value uid ||
error "dynamic modify of $prop failed"
val=$(do_facet ost1 $LCTL get_param -n nodemap.$nm.$prop)
- [[ "x$val" == "xuid" ]] || error "incorrect $prop $val"
+ [[ "$val" == "uid" ]] || error "incorrect $prop $val"
prop=rbac
do_facet ost1 $LCTL nodemap_modify --name $nm \
--property $prop --value file_perms ||
error "dynamic modify of $prop failed"
val=$(do_facet ost1 $LCTL get_param -n nodemap.$nm.$prop)
- [[ "x$val" == "xfile_perms" ]] || error "incorrect $prop $val"
+ [[ "$val" == "file_perms" ]] || error "incorrect $prop $val"
do_facet ost1 $LCTL nodemap_modify --name $nm \
--property $prop --value all ||
error "dynamic modify of $prop failed"
val=$(do_facet ost1 $LCTL get_param -n nodemap.$nm.$prop)
- [[ "x$val" == "x$rbac_val" ]] || error "incorrect $prop $val"
+ [[ "$val" == "$rbac_val" ]] || error "incorrect $prop $val"
prop=squash_uid
do_facet ost1 $LCTL nodemap_modify --name $nm \
--property $prop --value 77 ||
error "dynamic modify of $prop failed"
val=$(do_facet ost1 $LCTL get_param -n nodemap.$nm.$prop)
- [[ "x$val" == "x77" ]] || error "incorrect $prop $val"
+ (( val == 77 )) || error "incorrect $prop $val"
prop=squash_gid
do_facet ost1 $LCTL nodemap_modify --name $nm \
--property $prop --value 77 ||
error "dynamic modify of $prop failed"
val=$(do_facet ost1 $LCTL get_param -n nodemap.$nm.$prop)
- [[ "x$val" == "x77" ]] || error "incorrect $prop $val"
+ (( val == 77 )) || error "incorrect $prop $val"
prop=squash_projid
do_facet ost1 $LCTL nodemap_modify --name $nm \
--property $prop --value 77 ||
error "dynamic modify of $prop failed"
val=$(do_facet ost1 $LCTL get_param -n nodemap.$nm.$prop)
- [[ "x$val" == "x77" ]] || error "incorrect $prop $val"
+ (( val == 77 )) || error "incorrect $prop $val"
prop=fileset
do_facet ost1 $LCTL nodemap_set_fileset --name $nm \
- --fileset "/tmp" ||
- error "dynamic modify of $prop failed"
+ --fileset "/tmp" &&
+ error "dynamic modify of $prop should fail"
val=$(do_facet ost1 $LCTL get_param -n nodemap.$nm.$prop)
- [[ "x$val" == "x/tmp" ]] || error "incorrect $prop $val"
+ [[ "$val" == "/deffset" ]] || error "incorrect $prop $val"
prop=sepol
do_facet ost1 $LCTL nodemap_set_sepol --name $nm \
--sepol $sepol ||
error "dynamic modify of $prop failed"
val=$(do_facet ost1 $LCTL get_param -n nodemap.$nm.$prop)
- [[ "x$val" == "x$sepol" ]] || error "incorrect $prop $val"
+ [[ "$val" == "$sepol" ]] || error "incorrect $prop $val"
+
prop=offset
do_facet ost1 $LCTL nodemap_add_offset --name $nm \
--offset 100000 --limit 200000 ||
error "dynamic modify of $prop failed"
val=$(do_facet ost1 $LCTL get_param -n nodemap.$nm.$prop |
awk '$1 == "start_uid:" {print $2}' | sed s+,++)
- [[ "x$val" == "x100000" ]] || error "incorrect $prop start_uid $val"
+ (( val == 100000 )) || error "incorrect $prop start_uid $val"
val=$(do_facet ost1 $LCTL get_param -n nodemap.$nm.$prop |
awk '$1 == "limit_uid:" {print $2}' | sed s+,++)
- [[ "x$val" == "x200000" ]] || error "incorrect $prop limit_uid $val"
+ (( val == 200000 )) || error "incorrect $prop limit_uid $val"
do_facet ost1 $LCTL nodemap_del_offset --name $nm ||
error "dynamic del of $prop failed"
val=$(do_facet ost1 $LCTL get_param -n nodemap.$nm.$prop |
awk '$1 == "start_uid:" {print $2}' | sed s+,++)
- [[ "x$val" == "x0" ]] || error "incorrect $prop start_uid $val"
+ (( val == 0 )) || error "incorrect $prop start_uid $val"
val=$(do_facet ost1 $LCTL get_param -n nodemap.$nm.$prop |
awk '$1 == "limit_uid:" {print $2}' | sed s+,++)
- [[ "x$val" == "x0" ]] || error "incorrect $prop limit_uid $val"
+ (( val == 0 )) || error "incorrect $prop limit_uid $val"
val=$(do_facet ost1 $LCTL nodemap_test_id --nid $startnid \
--idtype uid --id $clid)
- if [[ "x$val" != "x$fsid" ]]; then
- error "dynamic test_id on server failed"
- fi
+ (( val == fsid )) || error "dynamic test_id on server failed"
do_facet ost1 $LCTL nodemap_del_idmap --name $nm --idtype uid \
--idmap $clid:$fsid ||
error "dynamic del_idmap on server failed"
val=$(do_facet ost1 $LCTL get_param nodemap.$nm.idmap |
awk 'BEGIN{RS=", "} $1=="client_id:"{print $2 ; exit}')
- if [[ "x$val" != "x" ]]; then
- error "idmap should be empty, got $val"
- fi
+ [[ -z "$val" ]] || error "idmap should be empty, got $val"
val=$(do_facet ost1 $LCTL nodemap_test_nid $startnid)
- if [[ "x$val" != "x$nm" ]]; then
- error "dynamic test_nid on server failed"
- fi
+ [[ "$val" == "$nm" ]] || error "dynamic test_nid on server failed"
+
+ do_facet ost1 $LCTL nodemap_add -d -p $nm ${nm}_1 ||
+ error "nodemap add ${nm}_1 on server failed"
+ stack_trap "do_facet ost1 $LCTL nodemap_del ${nm}_1 || true" EXIT
+ do_facet ost1 $LCTL nodemap_add_range --name ${nm}_1 \
+ --range $subnids1 ||
+ error "add_range for ${nm}_1 failed"
+ val=$(do_facet ost1 $LCTL get_param -n nodemap.${nm}_1.parent)
+ [[ "$val" == "$nm" ]] ||
+ error "parent of ${nm}_1 should be $nm, got $val"
+
+ do_facet ost1 $LCTL nodemap_add -d -p $nm ${nm}_2 ||
+ error "nodemap add ${nm}_2 on server failed"
+ stack_trap "do_facet ost1 $LCTL nodemap_del ${nm}_2 || true" EXIT
+ do_facet ost1 $LCTL nodemap_add_range --name ${nm}_2 \
+ --range $subnids2 ||
+ error "add_range for ${nm}_2 failed"
+ val=$(do_facet ost1 $LCTL get_param -n nodemap.${nm}_2.parent)
+ [[ "$val" == "$nm" ]] ||
+ error "parent of ${nm}_2 should be $nm, got $val"
+
+ do_facet ost1 $LCTL nodemap_add -d -p ${nm}_1 ${nm}_3 ||
+ error "nodemap add ${nm}_3 on server failed"
+ stack_trap "do_facet ost1 $LCTL nodemap_del ${nm}_3 || true" EXIT
+ do_facet ost1 $LCTL nodemap_add_range --name ${nm}_3 \
+ --range $subnids4 &&
+ error "nodemap ${nm}_3 should not accept range $subnids4"
+ do_facet ost1 $LCTL nodemap_add_range --name ${nm}_3 \
+ --range $subnids5 &&
+ error "nodemap ${nm}_3 should not accept range $subnids5"
+ do_facet ost1 $LCTL nodemap_add_range --name ${nm}_3 \
+ --range $subnids6 &&
+ error "nodemap ${nm}_3 should not accept range $subnids6"
+ do_facet ost1 $LCTL nodemap_add_range --name ${nm}_3 \
+ --range $subnids3 ||
+ error "add_range $subnids3 for ${nm}_3 failed"
+ val=$(do_facet ost1 $LCTL get_param -n nodemap.${nm}_3.parent)
+ [[ "$val" == "${nm}_1" ]] ||
+ error "parent of ${nm}_3 should be ${nm}_1, got $val"
+ val=$(do_facet ost1 $LCTL get_param -n nodemap.${nm}_3.squash_projid)
+ (( val == 77 )) || error "squash_projid should be inherited, got $val"
do_facet ost1 $LCTL nodemap_del_range --name $nm --range $nids ||
error "dynamic del_range on server failed"
val=$(do_facet ost1 $LCTL get_param nodemap.$nm.ranges |
awk 'BEGIN{RS=", "} $1=="start_nid:"{print $2 ; exit}')
- if [[ "x$val" != "x" ]]; then
- error "nid range should be empty, got $val"
- fi
+ [[ -z "$val" ]] || error "nid range should be empty, got $val"
do_facet ost1 $LCTL nodemap_del $nm ||
error "dynamic nodemap del on server failed"
val=$(do_facet ost1 $LCTL get_param nodemap.$nm.id)
- if [[ "x$val" != "x" ]]; then
- error "nodemap should be gone, got $val"
- fi
+ [[ -z "$val" ]] || error "nodemap should be gone, got $val"
do_facet ost1 $LCTL nodemap_add_range --name $mgsnm --range $mgsnids2 &&
error "add_range $mgsnm on server should fail"
"usage: nodemap activate {0|1}"},
{.pc_name = "add", .pc_func = jt_nodemap_add,
.pc_help = "add a new nodemap\n"
- "usage: nodemap add [-d|--dynamic] --name NODEMAP_NAME"},
+ "usage: nodemap add [-d|--dynamic] [-p|--parent PARENT_NAME] --name NODEMAP_NAME"},
{.pc_name = "del", .pc_func = jt_nodemap_del,
.pc_help = "remove a nodemap\n"
"usage: nodemap del --name NODEMAP_NAME"},
"usage: nodemap_activate {0|1}"},
{"nodemap_add", jt_nodemap_add, 0,
"add a new nodemap\n"
- "usage: nodemap_add [-d|--dynamic] --name NODEMAP_NAME"},
+ "usage: nodemap_add [-d|--dynamic] [-p|--parent PARENT_NAME] --name NODEMAP_NAME"},
{"nodemap_del", jt_nodemap_del, 0,
"remove a nodemap\n"
"usage: nodemap_del --name NODEMAP_NAME"},
#include <linux/lustre/lustre_ver.h>
#include <lustre/lustreapi.h>
+#include <uapi/linux/lustre/lustre_disk.h>
#define MAX_STRING_SIZE 128
*/
int jt_nodemap_add(int argc, char **argv)
{
- char *nodemap_name = NULL;
+ char nm_to_send[LUSTRE_NODEMAP_NAME_LENGTH*2 + 2];
+ char *nodemap_name = NULL, *parent_nm = NULL;
bool dynamic = false;
int c, rc = EXIT_SUCCESS;
{ .val = 'd', .name = "dynamic", .has_arg = no_argument },
{ .val = 'h', .name = "help", .has_arg = no_argument },
{ .val = 'n', .name = "name", .has_arg = required_argument },
+ { .val = 'p', .name = "parent", .has_arg = required_argument },
{ .name = NULL } };
- while ((c = getopt_long(argc, argv, "dhn:",
+ while ((c = getopt_long(argc, argv, "dhn:p:",
long_opts, NULL)) != -1) {
switch (c) {
case 'd':
case 'n':
nodemap_name = optarg;
break;
+ case 'p':
+ parent_nm = optarg;
+ break;
case 'h':
default:
return CMD_HELP;
nodemap_name = argv[optind];
}
- if (!dynamic && !is_mgs()) {
+ if (dynamic && !parent_nm) {
fprintf(stderr,
- "nodemap_add: non-dynamic nodemap only allowed on MGS node\n");
+ "nodemap_add: missing parent for dynamic nodemap\n");
return CMD_HELP;
}
- if (llapi_nodemap_exists(nodemap_name) == 0) {
+ if (!dynamic) {
+ if (!is_mgs()) {
+ fprintf(stderr,
+ "nodemap_add: non-dynamic nodemap only allowed on MGS node\n");
+ return CMD_HELP;
+ }
+ if (parent_nm) {
+ fprintf(stderr,
+ "nodemap_add: invalid parent for non-dynamic nodemap\n");
+ return CMD_HELP;
+ }
+ }
+
+ if (!llapi_nodemap_exists(nodemap_name)) {
fprintf(stderr, "error: nodemap '%s' already exists\n",
nodemap_name);
errno = EINVAL;
goto out;
}
+ if (parent_nm) {
+ if (llapi_nodemap_exists(parent_nm)) {
+ fprintf(stderr, "error: parent '%s' does not exist\n",
+ parent_nm);
+ errno = EINVAL;
+ goto out;
+ }
+ }
+
+ if (snprintf(nm_to_send, sizeof(nm_to_send), "%s%s%s",
+ parent_nm ? parent_nm : "",
+ parent_nm ? "/" : "", nodemap_name) >=
+ sizeof(nm_to_send)) {
+ fprintf(stderr, "error: nodemap names %s%s%s too long\n",
+ parent_nm ? parent_nm : "", parent_nm ? "/" : "",
+ nodemap_name);
+ errno = EINVAL;
+ goto out;
+ }
+
errno = -nodemap_cmd(LCFG_NODEMAP_ADD, dynamic, NULL, 0, argv[0],
- nodemap_name, NULL);
+ nm_to_send, NULL);
out:
if (errno) {