From 8445f7b92f067346919069bcf9a268d41c52c5b3 Mon Sep 17 00:00:00 2001 From: Maximilian Dilger Date: Thu, 20 Jun 2024 16:09:15 -0400 Subject: [PATCH] LU-17922 utils: added idmap range functionality Added the ability to a declare a range when adding idmaps to a nodemap. The syntax is: -:[-] The uid_end value is optional. In practice this looks like: nodemap_add_idmap --name test --idtype uid --idmap 500-510:10000 It is also now possible to delete idmap ranges with the nodemap_del_idmap command as well with the same syntax. Signed-off-by: Maximilian Dilger Change-Id: If6a2b9ab11f7d435a6854055001e6102aac43115 Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/55502 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Oleg Drokin Reviewed-by: Andreas Dilger Reviewed-by: Sebastien Buisson --- lustre/include/lustre_nodemap.h | 7 ++- lustre/ptlrpc/nodemap_handler.c | 130 +++++++++++++++++++++++++++++++--------- lustre/tests/sanity-sec.sh | 55 +++++++++++++++++ 3 files changed, 161 insertions(+), 31 deletions(-) diff --git a/lustre/include/lustre_nodemap.h b/lustre/include/lustre_nodemap.h index 0df134b..10338fd3 100644 --- a/lustre/include/lustre_nodemap.h +++ b/lustre/include/lustre_nodemap.h @@ -132,7 +132,8 @@ int nodemap_add_member(struct lnet_nid *nid, struct obd_export *exp); void nodemap_del_member(struct obd_export *exp); int nodemap_parse_range(const char *range_string, struct lnet_nid range[2], u8 *netmask); -int nodemap_parse_idmap(char *idmap_string, __u32 idmap[2]); +int nodemap_parse_idmap(const char *nodemap_name, char *idmap_str, + __u32 idmap[2], u32 *range_count); int nodemap_add_range(const char *name, const struct lnet_nid nid[2], u8 netmask); int nodemap_del_range(const char *name, const struct lnet_nid nid[2], @@ -150,9 +151,9 @@ int nodemap_set_audit_mode(const char *name, bool enable_audit); int nodemap_set_forbid_encryption(const char *name, bool forbid_encryption); int nodemap_set_readonly_mount(const char *name, bool readonly_mount); bool nodemap_can_setquota(struct lu_nodemap *nodemap, __u32 qc_type, __u32 id); -int nodemap_add_idmap(const char *name, enum nodemap_id_type id_type, +int nodemap_add_idmap(const char *nodemap_name, enum nodemap_id_type id_type, const __u32 map[2]); -int nodemap_del_idmap(const char *name, enum nodemap_id_type id_type, +int nodemap_del_idmap(const char *nodemap_name, enum nodemap_id_type id_type, const __u32 map[2]); int nodemap_set_fileset(const char *name, const char *fileset); char *nodemap_get_fileset(const struct lu_nodemap *nodemap); diff --git a/lustre/ptlrpc/nodemap_handler.c b/lustre/ptlrpc/nodemap_handler.c index feaf1aa..1d3b97c 100644 --- a/lustre/ptlrpc/nodemap_handler.c +++ b/lustre/ptlrpc/nodemap_handler.c @@ -353,17 +353,25 @@ 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 * + * the string can also be a range of "ci_start-ci_end:fs_start[-fs_end]" + * + * \param nodemap_name nodemap name string * \param idmap_str map string * \param idmap array[2] of __u32 + * \param range_count potential idmap range u32 * * \retval 0 on success * \retval -EINVAL if idmap cannot be parsed */ -int nodemap_parse_idmap(char *idmap_str, __u32 idmap[2]) +int nodemap_parse_idmap(const char *nodemap_name, char *idmap_str, + __u32 idmap[2], u32 *range_count) { - char *sep; - long unsigned int idmap_buf; - int rc; + char *sep; + char *sep_range; + char *potential_range; + unsigned long id; + int rc; + int range = 1; if (idmap_str == NULL) return -EINVAL; @@ -374,15 +382,52 @@ int nodemap_parse_idmap(char *idmap_str, __u32 idmap[2]) *sep = '\0'; sep++; - rc = kstrtoul(idmap_str, 10, &idmap_buf); - if (rc != 0) + /* see if range is passed in idmap_str */ + sep_range = strchr(idmap_str, '-'); + if (sep_range) + *sep_range++ = '\0'; + + rc = kstrtoul(idmap_str, 10, &id); + if (rc) return -EINVAL; - idmap[0] = idmap_buf; + idmap[0] = id; - rc = kstrtoul(sep, 10, &idmap_buf); - if (rc != 0) + /* parse cid range end if it is supplied */ + if (sep_range) { + rc = kstrtoul(sep_range, 10, &id); + if (rc) + return -EINVAL; + + range = id - idmap[0] + 1; + if (range <= 0) + return -ERANGE; + } + + potential_range = strchr(sep, '-'); + if (potential_range) + *potential_range++ = '\0'; + + rc = kstrtoul(sep, 10, &id); + if (rc) return -EINVAL; - idmap[1] = idmap_buf; + idmap[1] = id; + + /* parse fsid range end if it is supplied */ + if (potential_range) { + rc = kstrtoul(potential_range, 10, &id); + if (rc) + return -ERANGE; + + /* make sure fsid range is equal to cid range */ + if (id - idmap[1] + 1 != range) { + rc = -EINVAL; + CERROR("%s: range length mismatch between client id %s-%s and fs id %s-%s: rc = %d\n", + nodemap_name, idmap_str, sep_range, sep, + potential_range, rc); + return rc; + } + } + *range_count = range; return 0; } @@ -522,7 +567,21 @@ out: return rc; } -int nodemap_add_idmap(const char *name, enum nodemap_id_type id_type, +int nodemap_add_idmap_range(const char *nodemap_name, enum nodemap_id_type id_type, + const __u32 map[2], const u32 range_count) +{ + int rc = 0; + int i; + + for (i = 0; i < range_count && !rc; i++) { + rc = nodemap_add_idmap(nodemap_name, id_type, + (int[2]){map[0] + i, map[1] + i}); + } + + return rc; +} + +int nodemap_add_idmap(const char *nodemap_name, enum nodemap_id_type id_type, const __u32 map[2]) { struct lu_nodemap *nodemap = NULL; @@ -531,7 +590,7 @@ int nodemap_add_idmap(const char *name, enum nodemap_id_type id_type, ENTRY; mutex_lock(&active_config_lock); - nodemap = nodemap_lookup(name); + nodemap = nodemap_lookup(nodemap_name); if (IS_ERR(nodemap)) { mutex_unlock(&active_config_lock); GOTO(out, rc = PTR_ERR(nodemap)); @@ -563,7 +622,7 @@ EXPORT_SYMBOL(nodemap_add_idmap); * * \retval 0 on success */ -int nodemap_del_idmap(const char *name, enum nodemap_id_type id_type, +int nodemap_del_idmap(const char *nodemap_name, enum nodemap_id_type id_type, const __u32 map[2]) { struct lu_nodemap *nodemap = NULL; @@ -573,7 +632,7 @@ int nodemap_del_idmap(const char *name, enum nodemap_id_type id_type, ENTRY; mutex_lock(&active_config_lock); - nodemap = nodemap_lookup(name); + nodemap = nodemap_lookup(nodemap_name); if (IS_ERR(nodemap)) { mutex_unlock(&active_config_lock); GOTO(out, rc = PTR_ERR(nodemap)); @@ -604,6 +663,20 @@ out: } EXPORT_SYMBOL(nodemap_del_idmap); +int nodemap_del_idmap_range(const char *nodemap_name, enum nodemap_id_type id_type, + const __u32 map[2], const u32 range_count) +{ + int rc = 0; + int i; + + for (i = 0; i < range_count && !rc; i++) { + rc = nodemap_del_idmap(nodemap_name, id_type, + (int[2]) {map[0] + i, map[1] + i}); + } + + return rc; +} + /** * Get nodemap assigned to given export. Takes a reference on the nodemap. * @@ -2023,6 +2096,7 @@ static int cfg_nodemap_cmd(enum lcfg_command_type cmd, const char *nodemap_name, bool bool_switch; u8 netmask = 0; u32 idmap[2]; + u32 range_count; u32 int_id; int rc = 0; @@ -2182,36 +2256,36 @@ static int cfg_nodemap_cmd(enum lcfg_command_type cmd, const char *nodemap_name, case LCFG_NODEMAP_ADD_UIDMAP: case LCFG_NODEMAP_ADD_GIDMAP: case LCFG_NODEMAP_ADD_PROJIDMAP: - rc = nodemap_parse_idmap(param, idmap); + rc = nodemap_parse_idmap(nodemap_name, param, idmap, &range_count); if (rc != 0) break; if (cmd == LCFG_NODEMAP_ADD_UIDMAP) - rc = nodemap_add_idmap(nodemap_name, NODEMAP_UID, - idmap); + rc = nodemap_add_idmap_range(nodemap_name, NODEMAP_UID, + idmap, range_count); else if (cmd == LCFG_NODEMAP_ADD_GIDMAP) - rc = nodemap_add_idmap(nodemap_name, NODEMAP_GID, - idmap); + rc = nodemap_add_idmap_range(nodemap_name, NODEMAP_GID, + idmap, range_count); else if (cmd == LCFG_NODEMAP_ADD_PROJIDMAP) - rc = nodemap_add_idmap(nodemap_name, NODEMAP_PROJID, - idmap); + rc = nodemap_add_idmap_range(nodemap_name, NODEMAP_PROJID, + idmap, range_count); else rc = -EINVAL; break; case LCFG_NODEMAP_DEL_UIDMAP: case LCFG_NODEMAP_DEL_GIDMAP: case LCFG_NODEMAP_DEL_PROJIDMAP: - rc = nodemap_parse_idmap(param, idmap); + rc = nodemap_parse_idmap(nodemap_name, param, idmap, &range_count); if (rc != 0) break; if (cmd == LCFG_NODEMAP_DEL_UIDMAP) - rc = nodemap_del_idmap(nodemap_name, NODEMAP_UID, - idmap); + rc = nodemap_del_idmap_range(nodemap_name, NODEMAP_UID, + idmap, range_count); else if (cmd == LCFG_NODEMAP_DEL_GIDMAP) - rc = nodemap_del_idmap(nodemap_name, NODEMAP_GID, - idmap); + rc = nodemap_del_idmap_range(nodemap_name, NODEMAP_GID, + idmap, range_count); else if (cmd == LCFG_NODEMAP_DEL_PROJIDMAP) - rc = nodemap_del_idmap(nodemap_name, NODEMAP_PROJID, - idmap); + rc = nodemap_del_idmap_range(nodemap_name, NODEMAP_PROJID, + idmap, range_count); else rc = -EINVAL; break; diff --git a/lustre/tests/sanity-sec.sh b/lustre/tests/sanity-sec.sh index 3e2bb9b..f540ace 100755 --- a/lustre/tests/sanity-sec.sh +++ b/lustre/tests/sanity-sec.sh @@ -2264,6 +2264,61 @@ test_27a() { } run_test 27a "test fileset in various nodemaps" +test_27aa() { #LU-17922 + local idmap + local id=500 + + do_facet mgs $LCTL nodemap_add Test17922 || + error "unable to add Test17922 as nodemap" + stack_trap "do_facet mgs $LCTL nodemap_del Test17922 || true" + + do_facet mgs $LCTL nodemap_add_idmap --name Test17922 \ + --idtype uid --idmap 500-509:10000-10009 || + error "unable to add idmap range 500-509:10000-10009" + + idmap=$(do_facet mgs $LCTL get_param nodemap.Test17922.idmap | grep idtype) + while IFS= read -r idmap; do + if (( $id <= 509 )); then + [[ "$idmap" == *"client_id: $id"* ]] || + error "could not find 'client_id: ${id}' inside of ${idmap}" + fi + ((id++)) + done < <(echo "$idmap") + + do_facet mgs $LCTL nodemap_del_idmap --name Test17922 \ + --idtype uid --idmap 505-509:10005 || + error "cannot delete idmap range 505-509:10005" + + id=500 + idmap=$(do_facet mgs $LCTL get_param nodemap.Test17922.idmap | grep idtype) + while IFS= read -r idmap; do + if (( $id <= 504 )); then + [[ "$idmap" == *"client_id: $id"* ]] || + error "could not find 'client_id: ${id}' inside of ${idmap}" + else + [[ "$idmap" =~ "client_id: $id" ]] && + error "found 'client_id: $id' in $idmap" + fi + ((id++)) + done < <(echo "$idmap") + + do_facet mgs $LCTL nodemap_del_idmap --name Test17922 \ + --idtype uid --idmap 500-504:10000 + + #expected error, invalid secondary range supplied + do_facet mgs $LCTL nodemap_add --name Test17922 \ + --idtype uid --idmap 500-509:10000-10010 && + error "Invalid range 10000-10010 was added" + + (( $(do_facet mgs $LCTL get_param nodemap.Test17922.idmap | + grep -c idtype) == 0 )) || + error "invalid range 10000-10010 supplied and passed" + + do_facet mgs $LCTL nodemap_del Test17922 || + error "failed to remove nodemap Test17922" +} +run_test 27aa "test nodemap idmap range" + test_27b() { #LU-10703 [ "$MDS1_VERSION" -lt $(version_code 2.11.50) ] && skip "Need MDS >= 2.11.50" -- 1.8.3.1