From e9278b8da16338db30ac34abff1f6bc3489352b0 Mon Sep 17 00:00:00 2001 From: Sebastien Buisson Date: Wed, 20 Mar 2024 15:40:56 +0100 Subject: [PATCH] LU-17431 nodemap: make dynamic nodemaps hierarchical 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 Change-Id: I04a14db92c068f3cb5b6b39e75feb802cebacd8a Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/54739 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Marc Vef Reviewed-by: Andreas Dilger Reviewed-by: Oleg Drokin --- lustre/doc/lctl-nodemap-add.8 | 7 ++ lustre/include/lustre_nodemap.h | 6 ++ lustre/ptlrpc/nodemap_handler.c | 221 +++++++++++++++++++++++++++++++++------ lustre/ptlrpc/nodemap_idmap.c | 75 ++++++++++++- lustre/ptlrpc/nodemap_internal.h | 8 +- lustre/ptlrpc/nodemap_lproc.c | 42 ++++++++ lustre/ptlrpc/nodemap_range.c | 100 +++++++++++++++--- lustre/ptlrpc/nodemap_storage.c | 32 +++--- lustre/tests/sanity-sec.sh | 125 ++++++++++++++-------- lustre/utils/lctl.c | 4 +- lustre/utils/obd.c | 51 +++++++-- 11 files changed, 553 insertions(+), 118 deletions(-) diff --git a/lustre/doc/lctl-nodemap-add.8 b/lustre/doc/lctl-nodemap-add.8 index 102f3f9..73e1b20 100644 --- a/lustre/doc/lctl-nodemap-add.8 +++ b/lustre/doc/lctl-nodemap-add.8 @@ -6,6 +6,9 @@ lctl-nodemap_add \- create a new nodemap to define client behavior or .SY "lctl nodemap add" .RB [ -d | --dynamic ] +.RB [ -p | +.BI --parent " PARENT_NAME" +] .BI --name " NODEMAP_NAME" .YS .SH DESCRIPTION @@ -19,6 +22,10 @@ and filesystem access permission of those NID(s). 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 diff --git a/lustre/include/lustre_nodemap.h b/lustre/include/lustre_nodemap.h index 643fa085a..7a59954 100644 --- a/lustre/include/lustre_nodemap.h +++ b/lustre/include/lustre_nodemap.h @@ -123,6 +123,12 @@ struct lu_nodemap { 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 diff --git a/lustre/ptlrpc/nodemap_handler.c b/lustre/ptlrpc/nodemap_handler.c index adf474d..dcefca2 100644 --- a/lustre/ptlrpc/nodemap_handler.c +++ b/lustre/ptlrpc/nodemap_handler.c @@ -35,6 +35,8 @@ bool nodemap_active; 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 * @@ -60,9 +62,17 @@ static void nodemap_destroy(struct lu_nodemap *nodemap) 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); @@ -950,10 +960,11 @@ ssize_t nodemap_map_acl(struct lu_nodemap *nodemap, void *buf, size_t size, } 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; @@ -993,19 +1004,36 @@ static void nodemap_inherit_properties(struct lu_nodemap *dst, 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; } /* @@ -1024,6 +1052,7 @@ int nodemap_add_range_helper(struct nodemap_config *config, 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; @@ -1035,7 +1064,7 @@ int nodemap_add_range_helper(struct nodemap_config *config, 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", @@ -1046,6 +1075,32 @@ int nodemap_add_range_helper(struct nodemap_config *config, 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 */ @@ -1281,6 +1336,34 @@ static int nodemap_set_fileset_local(struct lu_nodemap *nodemap, } /** + * 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 @@ -1312,6 +1395,12 @@ int nodemap_set_fileset(const char *name, const char *fileset, bool checkperm, 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); @@ -1483,18 +1572,51 @@ EXPORT_SYMBOL(nodemap_get_sepol); */ 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) { @@ -1503,7 +1625,7 @@ struct lu_nodemap *nodemap_create(const char *name, } 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); @@ -1514,25 +1636,40 @@ struct lu_nodemap *nodemap_create(const char *name, * 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; @@ -1546,12 +1683,12 @@ struct lu_nodemap *nodemap_create(const char *name, 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)); } @@ -2006,12 +2143,11 @@ int nodemap_add(const char *nodemap_name, bool dynamic) 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) @@ -2052,6 +2188,22 @@ int nodemap_del(const char *nodemap_name) 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 */ @@ -2094,13 +2246,18 @@ int nodemap_del(const char *nodemap_name) 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); @@ -2524,7 +2681,7 @@ int nodemap_mod_init(void) 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(); diff --git a/lustre/ptlrpc/nodemap_idmap.c b/lustre/ptlrpc/nodemap_idmap.c index afcfedf..b31fc8c 100644 --- a/lustre/ptlrpc/nodemap_idmap.c +++ b/lustre/ptlrpc/nodemap_idmap.c @@ -49,7 +49,7 @@ static void idmap_destroy(struct lu_idmap *idmap) /** * 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 * @@ -278,3 +278,76 @@ void idmap_delete_tree(struct lu_nodemap *nodemap) 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; +} diff --git a/lustre/ptlrpc/nodemap_internal.h b/lustre/ptlrpc/nodemap_internal.h index 65b5d8c..2abb180 100644 --- a/lustre/ptlrpc/nodemap_internal.h +++ b/lustre/ptlrpc/nodemap_internal.h @@ -53,6 +53,8 @@ struct lu_nid_range { */ 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 { @@ -101,7 +103,7 @@ static inline __u32 nm_idx_set_type(unsigned int id, enum nodemap_idx_type t) 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); @@ -116,7 +118,8 @@ struct lu_nid_range *range_create(struct nodemap_config *config, 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); @@ -132,6 +135,7 @@ struct lu_idmap *idmap_insert(enum nodemap_id_type id_type, 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, diff --git a/lustre/ptlrpc/nodemap_lproc.c b/lustre/ptlrpc/nodemap_lproc.c index 33a89bc..138a6b3 100644 --- a/lustre/ptlrpc/nodemap_lproc.c +++ b/lustre/ptlrpc/nodemap_lproc.c @@ -844,6 +844,43 @@ static int nodemap_deny_mount_seq_show(struct seq_file *m, void *data) 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", @@ -868,6 +905,7 @@ LDEBUGFS_SEQ_FOPS_RO(nodemap_audit_mode); 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, @@ -933,6 +971,10 @@ static struct ldebugfs_vars lprocfs_nodemap_vars[] = { .fops = &nodemap_map_mode_fops, }, { + .name = "parent", + .fops = &nodemap_parent_fops, + }, + { .name = "ranges", .fops = &nodemap_ranges_fops, }, diff --git a/lustre/ptlrpc/nodemap_range.c b/lustre/ptlrpc/nodemap_range.c index 647bc31..5fb1477 100644 --- a/lustre/ptlrpc/nodemap_range.c +++ b/lustre/ptlrpc/nodemap_range.c @@ -28,6 +28,19 @@ 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 * @@ -145,6 +158,7 @@ struct lu_nid_range *range_create(struct nodemap_config *config, 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; } @@ -172,10 +186,15 @@ struct lu_nid_range *__range_find(struct nodemap_range_tree *nm_range_tree, 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; } @@ -233,24 +252,44 @@ void range_destroy(struct lu_nid_range *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)) @@ -271,8 +310,28 @@ int range_insert(struct nodemap_config *config, struct lu_nid_range *range) 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) @@ -296,9 +355,18 @@ static 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, diff --git a/lustre/ptlrpc/nodemap_storage.c b/lustre/ptlrpc/nodemap_storage.c index 906600e..e88bd27 100644 --- a/lustre/ptlrpc/nodemap_storage.c +++ b/lustre/ptlrpc/nodemap_storage.c @@ -966,10 +966,10 @@ int nodemap_idx_fileset_add(const struct lu_nodemap *nodemap, 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); @@ -1038,10 +1038,10 @@ int nodemap_idx_fileset_update(const struct lu_nodemap *nodemap, 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); @@ -1089,10 +1089,10 @@ int nodemap_idx_fileset_del(const struct lu_nodemap *nodemap, 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); @@ -1154,10 +1154,10 @@ int nodemap_idx_fileset_clear(const struct lu_nodemap *nodemap) 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); @@ -1370,9 +1370,11 @@ static int nodemap_cluster_rec_helper(struct nodemap_config *config, 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); @@ -1831,7 +1833,7 @@ out: 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 { diff --git a/lustre/tests/sanity-sec.sh b/lustre/tests/sanity-sec.sh index 98d18c8..7e4f145 100755 --- a/lustre/tests/sanity-sec.sh +++ b/lustre/tests/sanity-sec.sh @@ -7109,6 +7109,12 @@ test_72() { 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 \ @@ -7130,6 +7136,9 @@ test_72() { 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 @@ -7145,10 +7154,12 @@ test_72() { 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 @@ -7156,148 +7167,174 @@ test_72() { 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" diff --git a/lustre/utils/lctl.c b/lustre/utils/lctl.c index 7551f77..79beba7 100644 --- a/lustre/utils/lctl.c +++ b/lustre/utils/lctl.c @@ -166,7 +166,7 @@ command_t nodemap_cmdlist[] = { "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"}, @@ -591,7 +591,7 @@ command_t cmdlist[] = { "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"}, diff --git a/lustre/utils/obd.c b/lustre/utils/obd.c index f131f81..aed7f26 100644 --- a/lustre/utils/obd.c +++ b/lustre/utils/obd.c @@ -78,6 +78,7 @@ #include #include +#include #define MAX_STRING_SIZE 128 @@ -4023,7 +4024,8 @@ int jt_nodemap_activate(int argc, char **argv) */ 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; @@ -4031,9 +4033,10 @@ int jt_nodemap_add(int argc, char **argv) { .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': @@ -4042,6 +4045,9 @@ int jt_nodemap_add(int argc, char **argv) case 'n': nodemap_name = optarg; break; + case 'p': + parent_nm = optarg; + break; case 'h': default: return CMD_HELP; @@ -4056,21 +4062,54 @@ int jt_nodemap_add(int argc, char **argv) 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) { -- 1.8.3.1