From e3051ad0f1c8c3399c33eaf7cb0cc906177f7891 Mon Sep 17 00:00:00 2001 From: Maximilian Dilger Date: Tue, 6 Aug 2024 13:49:28 -0600 Subject: [PATCH] LU-18109 utils: adding nodemap offset capability nodemap offset: the ability to add an offset range to nodemaps. When an offset is defined, idmaps can only be set inside of their given range. This is defined as: lctl nodemap_add_offset --name nodemap --offset 100000 --limit 99999 And removed as: lctl nodemap_del_offset --name nodemap Test sanity-sec 27ab is added to exercise this new feature. Signed-off-by: Maximilian Dilger Change-Id: Iba2116d21bc7de1ba03111b0313427301e4b0b50 Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/55943 Reviewed-by: Sebastien Buisson Reviewed-by: Andreas Dilger Reviewed-by: Oleg Drokin Tested-by: jenkins Tested-by: Maloo --- lustre/doc/Makefile.am | 2 + lustre/doc/lctl-nodemap-add-offset.8 | 79 +++++++ lustre/doc/lctl-nodemap-del-offset.8 | 51 +++++ lustre/doc/lctl.8 | 10 +- lustre/include/lustre_nodemap.h | 14 ++ lustre/include/uapi/linux/lustre/lustre_cfg.h | 2 + lustre/include/uapi/linux/lustre/lustre_disk.h | 13 ++ lustre/include/uapi/linux/lustre/lustre_idl.h | 10 +- lustre/ptlrpc/nodemap_handler.c | 279 +++++++++++++++++++++++-- lustre/ptlrpc/nodemap_internal.h | 5 + lustre/ptlrpc/nodemap_lproc.c | 38 ++++ lustre/ptlrpc/nodemap_storage.c | 72 ++++++- lustre/ptlrpc/wiretest.c | 42 ++++ lustre/tests/sanity-sec.sh | 106 ++++++++++ lustre/utils/lctl.c | 6 + lustre/utils/obd.c | 145 +++++++++++++ lustre/utils/obdctl.h | 2 + lustre/utils/wirecheck.c | 18 ++ lustre/utils/wiretest.c | 42 ++++ 19 files changed, 914 insertions(+), 22 deletions(-) create mode 100644 lustre/doc/lctl-nodemap-add-offset.8 create mode 100644 lustre/doc/lctl-nodemap-del-offset.8 diff --git a/lustre/doc/Makefile.am b/lustre/doc/Makefile.am index 61f4f7b..889c0d3 100644 --- a/lustre/doc/Makefile.am +++ b/lustre/doc/Makefile.am @@ -242,6 +242,8 @@ SERVER_MANFILES = \ lctl-nodemap-modify.8 \ lctl-nodemap-set-fileset.8 \ lctl-nodemap-set-sepol.8 \ + lctl-nodemap-add-offset.8 \ + lctl-nodemap-del-offset.8 \ lctl-snapshot-create.8 \ lctl-snapshot-destroy.8 \ lctl-snapshot-list.8 \ diff --git a/lustre/doc/lctl-nodemap-add-offset.8 b/lustre/doc/lctl-nodemap-add-offset.8 new file mode 100644 index 0000000..3a2e338 --- /dev/null +++ b/lustre/doc/lctl-nodemap-add-offset.8 @@ -0,0 +1,79 @@ +.TH LCTL-NODEMAP_ADD_OFFSET 8 2024-08-21 Lustre "Lustre Configuration Utilities" +.SH NAME +lctl-nodemap_add_offset \- define ID mapping offset for a nodemap +.SH SYNOPSIS +.SY "lctl nodemap_add_offset" +.BI --name " NAME" +.BI --offset " OFFSET" +.BI --limit " FSID_COUNT" +.YS +.SH DESCRIPTION +.B nodemap_add_offset +adds an identity mapping offset to a nodemap for the UID, GID and PROJID types. +This command allows admins to create offset ranges for client systems to avoid +overlapping assignments in multi-tenant systems. The +.I FSID_COUNT +is used to specify the number of IDs mapped by the range, starting with the +.BR root (0) +user/group/project ID and extending through +.BR FSID_COUNT-1 . +.PP +An offset range cannot overlap into another's offset range. +.PP +A nodemap can only have one offset defined. To modify the offset already +defined, remove it first and recreate it with new values. +Any existing files will +.B not +automatically be remapped to the new +.I OFFSET +range. IDs must be manually changed on all files for that nodemap with +.BR chown (1) +and +.BR lfs-project (1) +on a trusted client that has access to the unmapped, canonical file system IDs. +So modifying a nodemap offset should be avoided if possible. +.SH OPTIONS +.TP +.BI --name " NAME" +The name of the nodemap that the offset will be applied to. +.TP +.BI --offset " OFFSET" +The given start value for the offset. +.TP +.BI --limit " FSID_COUNT" +The number of IDs in the offset range. +.SH EXAMPLES +Map the client UID, GID, and PROJID values from the range 0-99999 to the +filesystem UID, GID, and PROJID values to the range 100000-199999: +.RS +.EX +.B # lctl nodemap_add_offset --name remotesite --offset 100000 --limit 100000 +.EE +.RE +.PP +This map the "-2" user ID used by some systems for the +.B nobody +user to the user ID 65534, which will then be offset by OFFSET to a final UID of +165534 in this example: +.RS +.EX +.B # lctl nodemap_add_idmap --name remotesite --idtype uid --idmap 4294967294:65534 +.EE +.RE +.SH AVAILABILITY +.B lctl nodemap_add_offset +is part of the +.BR lustre (7) +filesystem package since release 2.16.0 +.\" Added in commit v2.15.99~ +.SH SEE ALSO +.BR lustre (7), +.BR lctl-nodemap-del-offset (8), +.BR lctl-nodemap-activate (8), +.BR lctl-nodemap-add (8), +.BR lctl-nodemap-add-idmap (8), +.BR lctl-nodemap-add-range (8), +.BR lctl-nodemap-del (8), +.BR lctl-nodemap-del-idmap (8), +.BR lctl-nodemap-del-range (8), +.BR lctl-nodemap-modify (8) diff --git a/lustre/doc/lctl-nodemap-del-offset.8 b/lustre/doc/lctl-nodemap-del-offset.8 new file mode 100644 index 0000000..d670f64 --- /dev/null +++ b/lustre/doc/lctl-nodemap-del-offset.8 @@ -0,0 +1,51 @@ +.TH LCTL-NODEMAP_DEL_OFFSET 8 2024-08-21 Lustre "Lustre Configuration Utilities" +.SH NAME +lctl-nodemap_del_offset \- remove ID mapping offset from a nodemap +.SH SYNOPSIS +.SY "lctl nodemap_del_offset" +.BI --name " NAME" +.YS +.SH DESCRIPTION +.B nodemap_del_offset +removes an identity mapping offset from a nodemap for the UID, GID and PROJID types. +.SH OPTIONS +.TP +.BI --name " NAME" +The name of the nodemap to remove the offset from. +.SH NOTES +Removing an offset from a nodemap does +.B not +affect the UID, GID, or PROJID of any files that were previously created under +this nodemap. If these files are mapped into a different nodemap, then their +UID, GID, and PROJID must be changed on a trusted client with access to the +unmapped, canonical file system IDs using +.BR chown (1), +.BR chgrp (1), +and +.BR "lfs project" (1) +from the old offset range to the new offset. As such, removing an offset from a +nodemap should be avoided whenever possible. +.SH EXAMPLES +Remove the already existing offset from nodemap remotesite: +.RS +.EX +.B # lctl nodemap_del_offset --name remotesite +.EE +.RE +.SH AVAILABILITY +.B lctl nodemap_del_offset +is part of the +.BR lustre (7) +filesystem package since release 2.16.0 +.\" Added in commit v2.15.99~ +.SH SEE ALSO +.BR lustre (7), +.BR lctl-nodemap-add-offset (8), +.BR lctl-nodemap-activate (8), +.BR lctl-nodemap-add (8), +.BR lctl-nodemap-add-idmap (8), +.BR lctl-nodemap-add-range (8), +.BR lctl-nodemap-del (8), +.BR lctl-nodemap-del-idmap (8), +.BR lctl-nodemap-del-range (8), +.BR lctl-nodemap-modify (8) diff --git a/lustre/doc/lctl.8 b/lustre/doc/lctl.8 index bcb6d28..15ae282 100644 --- a/lustre/doc/lctl.8 +++ b/lustre/doc/lctl.8 @@ -233,9 +233,15 @@ Delete an existing UID or GID mapping from a nodemap. .BR lctl-nodemap-modify (8) Modify a nodemap property. .TP -.BR lctl-nodemap-set-fileset(8) +.BR lctl-nodemap-set-fileset (8) Add a fileset to a nodemap. .TP +.BR lctl-nodemap-add-offset (8) +Set a UID/GID/PROJID offset value +.TP +.BR lctl-nodemap-del-offset (8) +Remove a UID/GID/PROJID offset from a nodemap. +.TP .BR lctl-nodemap-set-sepol (8) Set SELinux policy info on a nodemap. .SS Configuration logs @@ -435,6 +441,8 @@ filesystem package since release 0.5.0 .BR lctl-nodemap-del-idmap (8), .BR lctl-nodemap-del-range (8), .BR lctl-nodemap-modify (8), +.BR lctl-nodemap-add-offset (8), +.BR lctl-nodemap-del-offset (8), .BR lctl-pcc (8), .BR lctl-set_param (8), .BR lctl-snapshot-create (8), diff --git a/lustre/include/lustre_nodemap.h b/lustre/include/lustre_nodemap.h index f335931..087019e 100644 --- a/lustre/include/lustre_nodemap.h +++ b/lustre/include/lustre_nodemap.h @@ -101,6 +101,18 @@ struct lu_nodemap { struct list_head nm_list; /* is a dynamic nodemap */ bool nm_dyn; + /* value to start UID offset */ + unsigned int nm_offset_start_uid; + /* number of values allocated to UID offset */ + unsigned int nm_offset_limit_uid; + /* value to start GID offset */ + unsigned int nm_offset_start_gid; + /* number of values allocated to GID offset */ + unsigned int nm_offset_limit_gid; + /* value to start PROJID offset */ + unsigned int nm_offset_start_projid; + /* number of values allocated to PROJID offset */ + unsigned int nm_offset_limit_projid; }; /* Store handles to local MGC storage to save config locally. In future @@ -132,6 +144,8 @@ int nodemap_set_deny_unknown(const char *name, bool deny_unknown); int nodemap_set_mapping_mode(const char *name, enum nodemap_mapping_modes map_mode); int nodemap_set_rbac(const char *name, enum nodemap_rbac_roles rbac); +int nodemap_add_offset(const char *nodemap_name, char *offset); +int nodemap_del_offset(const char *nodemap_name); int nodemap_set_squash_uid(const char *name, uid_t uid); int nodemap_set_squash_gid(const char *name, gid_t gid); int nodemap_set_squash_projid(const char *name, projid_t projid); diff --git a/lustre/include/uapi/linux/lustre/lustre_cfg.h b/lustre/include/uapi/linux/lustre/lustre_cfg.h index 6408735..7bf7687 100644 --- a/lustre/include/uapi/linux/lustre/lustre_cfg.h +++ b/lustre/include/uapi/linux/lustre/lustre_cfg.h @@ -102,6 +102,8 @@ enum lcfg_command_type { LCFG_NODEMAP_ADMIN = 0x00ce049, /**< allow cluster to use id 0 */ LCFG_NODEMAP_ADD_PROJIDMAP = 0x00ce04a, /**< add a projidmap */ LCFG_NODEMAP_DEL_PROJIDMAP = 0x00ce04b, /**< delete projidmap */ + LCFG_NODEMAP_ADD_OFFSET = 0x00ce04c, /**< UID/GID/PROJID add offset */ + LCFG_NODEMAP_DEL_OFFSET = 0x00ce04d, /**< UID/GID/PROJID del offset */ LCFG_NODEMAP_TRUSTED = 0x00ce050, /**< trust a clusters ids */ LCFG_NODEMAP_SQUASH_UID = 0x00ce051, /**< default map uid */ LCFG_NODEMAP_SQUASH_GID = 0x00ce052, /**< default map gid */ diff --git a/lustre/include/uapi/linux/lustre/lustre_disk.h b/lustre/include/uapi/linux/lustre/lustre_disk.h index e1124e5..8d406b8 100644 --- a/lustre/include/uapi/linux/lustre/lustre_disk.h +++ b/lustre/include/uapi/linux/lustre/lustre_disk.h @@ -319,6 +319,17 @@ struct nodemap_cluster_roles_rec { __u64 ncrr_padding3; /* zeroed since 2.16 (always) */ }; +struct nodemap_offset_rec { + __u32 nor_start_uid; + __u32 nor_limit_uid; + __u32 nor_start_gid; + __u32 nor_limit_gid; + __u32 nor_start_projid; + __u32 nor_limit_projid; + __u32 nor_padding1; + __u32 nor_padding2; +}; + union nodemap_rec { struct nodemap_cluster_rec ncr; struct nodemap_range_rec nrr; @@ -326,12 +337,14 @@ union nodemap_rec { struct nodemap_id_rec nir; struct nodemap_global_rec ngr; struct nodemap_cluster_roles_rec ncrr; + struct nodemap_offset_rec nor; }; /* sub-keys for records of type NODEMAP_CLUSTER_IDX */ enum nodemap_cluster_rec_subid { NODEMAP_CLUSTER_REC = 0, /* nodemap_cluster_rec */ NODEMAP_CLUSTER_ROLES = 1, /* nodemap_cluster_roles_rec */ + NODEMAP_CLUSTER_OFFSET = 2, /* UID/GID/PROJID offset for a nm cluster */ }; /* first 4 bits of the nodemap_id is the index type */ diff --git a/lustre/include/uapi/linux/lustre/lustre_idl.h b/lustre/include/uapi/linux/lustre/lustre_idl.h index 8b61084..4aa3e50 100644 --- a/lustre/include/uapi/linux/lustre/lustre_idl.h +++ b/lustre/include/uapi/linux/lustre/lustre_idl.h @@ -3796,14 +3796,14 @@ struct llog_update_record { * of search easily */ enum nodemap_id_type { - NODEMAP_UID, - NODEMAP_GID, - NODEMAP_PROJID, + NODEMAP_UID = 0, + NODEMAP_GID = 1, + NODEMAP_PROJID = 2, }; enum nodemap_tree_type { - NODEMAP_FS_TO_CLIENT, - NODEMAP_CLIENT_TO_FS, + NODEMAP_FS_TO_CLIENT = 0, + NODEMAP_CLIENT_TO_FS = 1, }; enum nodemap_mapping_modes { diff --git a/lustre/ptlrpc/nodemap_handler.c b/lustre/ptlrpc/nodemap_handler.c index c9c43ed..7869ae3 100644 --- a/lustre/ptlrpc/nodemap_handler.c +++ b/lustre/ptlrpc/nodemap_handler.c @@ -26,6 +26,7 @@ * * Author: Joshua Walgenbach */ + #include #include #include @@ -782,8 +783,11 @@ __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; - __u32 found_id; + struct lu_idmap *idmap = NULL; + __u32 offset_start; + __u32 offset_limit; + __u32 found_id = id; + bool attempted_squash = false; ENTRY; @@ -801,18 +805,18 @@ __u32 nodemap_map_id(struct lu_nodemap *nodemap, if (id_type == NODEMAP_UID && !(nodemap->nmf_map_mode & NODEMAP_MAP_UID)) - goto out; + goto offset; if (id_type == NODEMAP_GID && !(nodemap->nmf_map_mode & NODEMAP_MAP_GID)) - goto out; + goto offset; if (id_type == NODEMAP_PROJID && !(nodemap->nmf_map_mode & NODEMAP_MAP_PROJID)) - goto out; + goto offset; if (nodemap->nmf_trust_client_ids) - goto out; + goto offset; map: if (is_default_nodemap(nodemap)) @@ -830,17 +834,51 @@ map: else found_id = idmap->id_fs; up_read(&nodemap->nm_idmap_lock); - RETURN(found_id); + GOTO(offset, found_id); squash: if (id_type == NODEMAP_UID) - RETURN(nodemap->nm_squash_uid); - if (id_type == NODEMAP_GID) - RETURN(nodemap->nm_squash_gid); - if (id_type == NODEMAP_PROJID) - RETURN(nodemap->nm_squash_projid); + found_id = nodemap->nm_squash_uid; + else if (id_type == NODEMAP_GID) + found_id = nodemap->nm_squash_gid; + else if (id_type == NODEMAP_PROJID) + found_id = nodemap->nm_squash_projid; + attempted_squash = true; +offset: + if (id_type == NODEMAP_UID) { + offset_start = nodemap->nm_offset_start_uid; + offset_limit = nodemap->nm_offset_limit_uid; + } else if (id_type == NODEMAP_GID) { + offset_start = nodemap->nm_offset_start_uid; + offset_limit = nodemap->nm_offset_limit_gid; + } else if (id_type == NODEMAP_PROJID) { + offset_start = nodemap->nm_offset_start_projid; + offset_limit = nodemap->nm_offset_limit_projid; + } else { + CERROR("%s: nodemap invalid id_type provided\n", + nodemap->nm_name); + GOTO(out, id); + } + + if (offset_start == 0 && offset_limit == 0) + GOTO(out, found_id); + + if (tree_type == NODEMAP_FS_TO_CLIENT) { + found_id -= offset_start; + } else { + if (found_id >= offset_limit && !attempted_squash) + GOTO(squash, found_id); + + if (attempted_squash) { + CERROR("%s: squash_id for type %u is outside nodemap limit %u, use unmapped value %u\n", + nodemap->nm_name, id_type, offset_limit, + found_id); + GOTO(out, found_id); + } + found_id += offset_start; + } out: - RETURN(id); + RETURN(found_id); } EXPORT_SYMBOL(nodemap_map_id); @@ -1333,6 +1371,12 @@ struct lu_nodemap *nodemap_create(const char *name, nodemap->nm_squash_projid = NODEMAP_NOBODY_PROJID; nodemap->nm_fileset[0] = '\0'; nodemap->nm_sepol[0] = '\0'; + nodemap->nm_offset_start_uid = 0; + nodemap->nm_offset_limit_uid = 0; + nodemap->nm_offset_start_gid = 0; + nodemap->nm_offset_limit_gid = 0; + nodemap->nm_offset_start_projid = 0; + nodemap->nm_offset_limit_projid = 0; if (!is_default) CWARN("adding nodemap '%s' to config without" " default nodemap\n", nodemap->nm_name); @@ -1355,6 +1399,12 @@ struct lu_nodemap *nodemap_create(const char *name, nodemap->nm_squash_projid = default_nodemap->nm_squash_projid; nodemap->nm_fileset[0] = '\0'; nodemap->nm_sepol[0] = '\0'; + nodemap->nm_offset_start_uid = 0; + nodemap->nm_offset_limit_uid = 0; + nodemap->nm_offset_start_gid = 0; + nodemap->nm_offset_limit_gid = 0; + nodemap->nm_offset_start_projid = 0; + nodemap->nm_offset_limit_projid = 0; } RETURN(nodemap); @@ -1877,6 +1927,201 @@ out: } EXPORT_SYMBOL(nodemap_del); +/* Do not call this method directly unless the ranges and nodemap have been + * previously verified. + * Store separate offset+limit in case this needs to be changed + * in the future, but for now there is no good reason to expose + * this complexity to userspace. + * TODO allow individual setting of values + */ +int nodemap_add_offset_helper(struct lu_nodemap *nodemap, __u32 offset_start, + __u32 offset_limit) +{ + if (IS_ERR_OR_NULL(nodemap)) + return -ENOENT; + + nodemap->nm_offset_start_uid = offset_start; + nodemap->nm_offset_limit_uid = offset_limit; + nodemap->nm_offset_start_gid = offset_start; + nodemap->nm_offset_limit_gid = offset_limit; + nodemap->nm_offset_start_projid = offset_start; + nodemap->nm_offset_limit_projid = offset_limit; + return 0; +} + +/** + * The nodemap offset shifts client UID/GID/PROJIDs from the range [0,limit) + * to a new range [offset,offset+limit). This is useful for clusters that share + * a single filesystem among several tenants that administer their IDs + * independently. The offsets provide non-overlapping spaces with "limit" + * IDs each without having to configure individual idmaps for each ID. + * + * \param name name of nodemmap + * \param offset offset+limit + * \retval 0 success + * \retval -EINVAL invalid input + * \retval -ENOENT no existing nodemap + */ +int nodemap_add_offset(const char *nodemap_name, char *offset) +{ + struct lu_nodemap *nodemap; + struct lu_nodemap *nm_iterating; + struct lu_nodemap *nm_tmp; + unsigned long offset_start, offset_limit; + unsigned long min, max; + bool overlap = false; + LIST_HEAD(nodemap_list_head); + char *offset_max; + int rc = 0; + + offset_max = strchr(offset, '+'); + if (offset_max == NULL) + GOTO(out, rc = -EINVAL); + *offset_max = '\0'; + offset_max++; + + rc = kstrtoul(offset, 10, &offset_start); + if (rc) { + CERROR("%s: nodemap offset_start '%lu' not valid: rc = %d\n", + nodemap_name, offset_start, rc); + GOTO(out, rc); + } + rc = kstrtoul(offset_max, 10, &offset_limit); + if (rc) { + CERROR("%s: nodemap offset_limit '%lu' not valid: rc = %d\n", + nodemap_name, offset_limit, rc); + GOTO(out, rc); + } + if (offset_start == 0 || offset_start >= UINT_MAX) { + rc = -EINVAL; + CERROR("%s: nodemap offset_start '%lu' is invalid: rc = %d\n", + nodemap_name, offset_start, rc); + GOTO(out, rc); + } + if (offset_limit == 0 || offset_limit >= UINT_MAX) { + rc = -EINVAL; + CERROR("%s: nodemap offset_limit '%lu' is invalid: rc = %d\n", + nodemap_name, offset_limit, rc); + GOTO(out, rc); + } + if (offset_start + offset_limit >= UINT_MAX) { + rc = -EINVAL; + CERROR("%s: nodemap offset_start+offset_limit '%s+%s' would overflow: rc = %d\n", + nodemap_name, offset, offset_max, rc); + GOTO(out, rc); + } + + mutex_lock(&active_config_lock); + nodemap = nodemap_lookup(nodemap_name); + if (IS_ERR(nodemap)) { + mutex_unlock(&active_config_lock); + GOTO(out, rc = -ENOENT); + } + + if (is_default_nodemap(nodemap)) + GOTO(out_putref, rc = -EINVAL); + + if (nodemap->nm_offset_start_uid) { + /* nodemap has already offset */ + nm_iterating = nodemap; + GOTO(overlap, rc = -ERANGE); + } + + cfs_hash_for_each_safe(active_config->nmc_nodemap_hash, + nm_hash_list_cb, &nodemap_list_head); + + list_for_each_entry_safe(nm_iterating, nm_tmp, &nodemap_list_head, + nm_list) { + if (nodemap_name == nm_iterating->nm_name) + continue; + min = nm_iterating->nm_offset_start_uid; + max = nm_iterating->nm_offset_start_uid + + nm_iterating->nm_offset_limit_uid; + if (min == 0 && max == 0) /* nodemaps with no set offset */ + continue; + /* seeing if new offset / offset_max overlaps with other + * existing nodemap offsets + */ + if (offset_start <= max - 1 && + offset_start + offset_limit - 1 >= min) { + overlap = true; + break; + } + } + + if (overlap) { +overlap: + rc = -ERANGE; + CERROR("%s: new offset %lu+%lu overlaps with existing nodemap %s offset %u+%u: rc = %d\n", + nodemap_name, offset_start, offset_limit, + nm_iterating->nm_name, nm_iterating->nm_offset_start_uid, + nm_iterating->nm_offset_limit_uid, rc); + GOTO(out_putref, rc); + } + + rc = nodemap_add_offset_helper(nodemap, offset_start, offset_limit); + if (rc == 0) + rc = nodemap_idx_offset_add(nodemap); + if (rc == 0) + nm_member_revoke_locks(nodemap); + +out_putref: + mutex_unlock(&active_config_lock); + nodemap_putref(nodemap); +out: + return rc; +} + +int nodemap_del_offset_helper(struct lu_nodemap *nodemap) +{ + if (IS_ERR_OR_NULL(nodemap)) + return -ENOENT; + + nodemap->nm_offset_start_uid = 0; + nodemap->nm_offset_limit_uid = 0; + nodemap->nm_offset_start_gid = 0; + nodemap->nm_offset_limit_gid = 0; + nodemap->nm_offset_start_projid = 0; + nodemap->nm_offset_limit_projid = 0; + return 0; +} + +/** + * Delete mapping offset. + * + * \param name name of nodemmap + * \retval 0 success + * \retval -EINVAL invalid input + * \retval -ENOENT no existing nodemap + */ +int nodemap_del_offset(const char *nodemap_name) +{ + struct lu_nodemap *nodemap; + int rc = 0; + + mutex_lock(&active_config_lock); + nodemap = nodemap_lookup(nodemap_name); + if (IS_ERR(nodemap)) { + mutex_unlock(&active_config_lock); + GOTO(out, rc = -ENOENT); + } + + if (is_default_nodemap(nodemap)) + GOTO(out_putref, rc = -EINVAL); + + rc = nodemap_del_offset_helper(nodemap); + if (rc == 0) + rc = nodemap_idx_offset_del(nodemap); + if (rc == 0) + nm_member_revoke_locks(nodemap); + +out_putref: + mutex_unlock(&active_config_lock); + nodemap_putref(nodemap); +out: + return rc; +} + /** * activate nodemap functions * @@ -2345,6 +2590,12 @@ static int cfg_nodemap_cmd(enum lcfg_command_type cmd, const char *nodemap_name, break; rc = nodemap_set_squash_projid(nodemap_name, int_id); break; + case LCFG_NODEMAP_ADD_OFFSET: + rc = nodemap_add_offset(nodemap_name, param); + break; + case LCFG_NODEMAP_DEL_OFFSET: + rc = nodemap_del_offset(nodemap_name); + break; case LCFG_NODEMAP_ADD_UIDMAP: case LCFG_NODEMAP_ADD_GIDMAP: case LCFG_NODEMAP_ADD_PROJIDMAP: @@ -2439,6 +2690,7 @@ int server_iocontrol_nodemap(struct obd_device *obd, break; case LCFG_NODEMAP_ADD: case LCFG_NODEMAP_DEL: + case LCFG_NODEMAP_DEL_OFFSET: if (lcfg->lcfg_bufcount != 2) GOTO(out_lcfg, rc = -EINVAL); nodemap_name = lustre_cfg_string(lcfg, 1); @@ -2495,6 +2747,7 @@ int server_iocontrol_nodemap(struct obd_device *obd, sizeof(fs_idstr)) != 0) GOTO(out_lcfg, rc = -EINVAL); break; + case LCFG_NODEMAP_ADD_OFFSET: case LCFG_NODEMAP_ADD_RANGE: case LCFG_NODEMAP_DEL_RANGE: case LCFG_NODEMAP_ADD_UIDMAP: diff --git a/lustre/ptlrpc/nodemap_internal.h b/lustre/ptlrpc/nodemap_internal.h index a3be687..07837cd 100644 --- a/lustre/ptlrpc/nodemap_internal.h +++ b/lustre/ptlrpc/nodemap_internal.h @@ -148,6 +148,9 @@ int nodemap_add_range_helper(struct nodemap_config *config, struct lu_nodemap *nodemap, const struct lnet_nid nid[2], u8 netmask, unsigned int range_id); +int nodemap_add_offset_helper(struct lu_nodemap *nodemap, __u32 offset_start, + __u32 offset_limit); +int nodemap_del_offset_helper(struct lu_nodemap *nodemap); void nodemap_getref(struct lu_nodemap *nodemap); void nodemap_putref(struct lu_nodemap *nodemap); @@ -163,6 +166,8 @@ int nodemap_idx_nodemap_del(const struct lu_nodemap *nodemap); int nodemap_idx_cluster_roles_add(const struct lu_nodemap *nodemap); int nodemap_idx_cluster_roles_update(const struct lu_nodemap *nodemap); int nodemap_idx_cluster_roles_del(const struct lu_nodemap *nodemap); +int nodemap_idx_offset_add(const struct lu_nodemap *nodemap); +int nodemap_idx_offset_del(const struct lu_nodemap *nodemap); int nodemap_idx_idmap_add(const struct lu_nodemap *nodemap, enum nodemap_id_type id_type, const __u32 map[2]); diff --git a/lustre/ptlrpc/nodemap_lproc.c b/lustre/ptlrpc/nodemap_lproc.c index 5d9af1f..28881f2 100644 --- a/lustre/ptlrpc/nodemap_lproc.c +++ b/lustre/ptlrpc/nodemap_lproc.c @@ -118,6 +118,39 @@ static int nodemap_idmap_open(struct inode *inode, struct file *file) } /** + * Reads and prints the UID/GID/PROJID offsets for the given nodemap. + * + * \param m seq file in proc fs + * \param data unused + * \retval 0 success + */ +static int nodemap_offset_seq_show(struct seq_file *m, void *data) +{ + struct lu_nodemap *nodemap; + int rc; + + mutex_lock(&active_config_lock); + nodemap = nodemap_lookup(m->private); + mutex_unlock(&active_config_lock); + if (IS_ERR(nodemap)) { + rc = PTR_ERR(nodemap); + CERROR("%s: nodemap not found: rc = %d\n", + (char *)m->private, rc); + return rc; + } + + seq_printf(m, "start_uid: %u\n", nodemap->nm_offset_start_uid); + seq_printf(m, "limit_uid: %u\n", nodemap->nm_offset_limit_uid); + seq_printf(m, "start_gid: %u\n", nodemap->nm_offset_start_gid); + seq_printf(m, "limit_gid: %u\n", nodemap->nm_offset_limit_gid); + seq_printf(m, "start_projid: %u\n", nodemap->nm_offset_start_projid); + seq_printf(m, "limit_projid: %u\n", nodemap->nm_offset_limit_projid); + + nodemap_putref(nodemap); + return 0; +} + +/** * Reads and prints the NID ranges for the given nodemap. * * \param m seq file in proc fs @@ -800,6 +833,7 @@ LPROC_SEQ_FOPS_RO(nodemap_squash_projid); LPROC_SEQ_FOPS_RO(nodemap_deny_unknown); LPROC_SEQ_FOPS_RO(nodemap_map_mode); +LPROC_SEQ_FOPS_RO(nodemap_offset); LPROC_SEQ_FOPS_RO(nodemap_rbac); LPROC_SEQ_FOPS_RO(nodemap_audit_mode); LPROC_SEQ_FOPS_RO(nodemap_forbid_encryption); @@ -861,6 +895,10 @@ static struct lprocfs_vars lprocfs_nodemap_vars[] = { .fops = &nodemap_idmap_fops, }, { + .name = "offset", + .fops = &nodemap_offset_fops, + }, + { .name = "map_mode", .fops = &nodemap_map_mode_fops, }, diff --git a/lustre/ptlrpc/nodemap_storage.c b/lustre/ptlrpc/nodemap_storage.c index 23469c9..b7c5ddb 100644 --- a/lustre/ptlrpc/nodemap_storage.c +++ b/lustre/ptlrpc/nodemap_storage.c @@ -125,6 +125,20 @@ static void nodemap_cluster_roles_rec_init(union nodemap_rec *nr, ncrr->ncrr_padding3 = 0; } +static void nodemap_offset_rec_init(union nodemap_rec *nr, + const struct lu_nodemap *nodemap) +{ + struct nodemap_offset_rec *nor = &nr->nor; + + memset(nor, 0, sizeof(struct nodemap_offset_rec)); + nor->nor_start_uid = cpu_to_le32(nodemap->nm_offset_start_uid); + nor->nor_limit_uid = cpu_to_le32(nodemap->nm_offset_limit_uid); + nor->nor_start_gid = cpu_to_le32(nodemap->nm_offset_start_gid); + nor->nor_limit_gid = cpu_to_le32(nodemap->nm_offset_limit_gid); + nor->nor_start_projid = cpu_to_le32(nodemap->nm_offset_start_projid); + nor->nor_limit_projid = cpu_to_le32(nodemap->nm_offset_limit_projid); +} + static void nodemap_idmap_key_init(struct nodemap_key *nk, unsigned int nm_id, enum nodemap_id_type id_type, u32 id_client) @@ -479,6 +493,9 @@ static int nodemap_idx_cluster_add_update(const struct lu_nodemap *nodemap, case NODEMAP_CLUSTER_ROLES: nodemap_cluster_roles_rec_init(&nr, nodemap); break; + case NODEMAP_CLUSTER_OFFSET: + nodemap_offset_rec_init(&nr, nodemap); + break; default: CWARN("%s: unknown subtype %u\n", nodemap->nm_name, subid); GOTO(fini, rc = -EINVAL); @@ -534,6 +551,11 @@ int nodemap_idx_nodemap_del(const struct lu_nodemap *nodemap) if (rc2 < 0 && rc2 != -ENOENT) rc = rc2; + nodemap_cluster_key_init(&nk, nodemap->nm_id, NODEMAP_CLUSTER_OFFSET); + rc2 = nodemap_idx_delete(&env, nodemap_mgs_ncf->ncf_obj, &nk, NULL); + if (rc2 < 0 && rc2 != -ENOENT) + rc = rc2; + root = nodemap->nm_fs_to_client_uidmap; rbtree_postorder_for_each_entry_safe(idmap, temp, &root, id_fs_to_client) { @@ -626,6 +648,36 @@ int nodemap_idx_cluster_roles_del(const struct lu_nodemap *nodemap) RETURN(rc); } +int nodemap_idx_offset_add(const struct lu_nodemap *nodemap) +{ + return nodemap_idx_cluster_add_update(nodemap, NULL, NM_ADD, + NODEMAP_CLUSTER_OFFSET); +} + +int nodemap_idx_offset_del(const struct lu_nodemap *nodemap) +{ + struct nodemap_key nk; + struct lu_env env; + int rc = 0; + + ENTRY; + + if (!nodemap_mgs()) { + CERROR("cannot add nodemap config to non-existing MGS.\n"); + return -EINVAL; + } + + rc = lu_env_init(&env, LCT_LOCAL); + if (rc != 0) + RETURN(rc); + + nodemap_cluster_key_init(&nk, nodemap->nm_id, NODEMAP_CLUSTER_OFFSET); + rc = nodemap_idx_delete(&env, nodemap_mgs_ncf->ncf_obj, &nk, NULL); + + lu_env_fini(&env); + RETURN(rc); +} + int nodemap_idx_range_add(const struct lu_nid_range *range) { struct nodemap_key nk; @@ -938,9 +990,8 @@ static int nodemap_process_keyrec(struct nodemap_config *config, switch (type) { case NODEMAP_EMPTY_IDX: if (nodemap_id != 0) - CWARN("Found nodemap config record without type field, " - " nodemap_id=%d. nodemap config file corrupt?\n", - nodemap_id); + CWARN("%s: Found nodemap config record without type field, nodemap_id=%d. nodemap config file corrupt?\n", + nodemap->nm_name, nodemap_id); break; case NODEMAP_CLUSTER_IDX: switch (nodemap_get_key_subtype(key)) { @@ -955,6 +1006,14 @@ static int nodemap_process_keyrec(struct nodemap_config *config, if (rc != 0) GOTO(out, rc); break; + case NODEMAP_CLUSTER_OFFSET: + /* only works for offset UID = GID = PROJID */ + rc = nodemap_add_offset_helper(nodemap, + le32_to_cpu(rec->nor.nor_start_uid), + le32_to_cpu(rec->nor.nor_limit_uid)); + if (rc != 0) + GOTO(out, rc); + break; default: CWARN("%s: ignoring keyrec of type %d with subtype %u\n", nodemap->nm_name, NODEMAP_CLUSTER_IDX, @@ -1236,6 +1295,13 @@ nodemap_save_config_cache(const struct lu_env *env, rc = rc2; } + nodemap_cluster_key_init(&nk, nodemap->nm_id, + NODEMAP_CLUSTER_OFFSET); + nodemap_offset_rec_init(&nr, nodemap); + rc2 = nodemap_idx_insert(env, o, &nk, &nr); + if (rc2 < 0) + rc = rc2; + down_read(&active_config->nmc_range_tree_lock); list_for_each_entry_safe(range, range_temp, &nodemap->nm_ranges, rn_list) { diff --git a/lustre/ptlrpc/wiretest.c b/lustre/ptlrpc/wiretest.c index cfbed5a..eb05529 100644 --- a/lustre/ptlrpc/wiretest.c +++ b/lustre/ptlrpc/wiretest.c @@ -6356,6 +6356,42 @@ void lustre_assert_wire_constants(void) LASSERTF((int)sizeof(((struct nodemap_cluster_roles_rec *)0)->ncrr_padding3) == 8, "found %lld\n", (long long)(int)sizeof(((struct nodemap_cluster_roles_rec *)0)->ncrr_padding3)); + /* Checks for struct nodemap_offset_rec */ + LASSERTF((int)sizeof(struct nodemap_offset_rec) == 32, "found %lld\n", + (long long)(int)sizeof(struct nodemap_offset_rec)); + LASSERTF((int)offsetof(struct nodemap_offset_rec, nor_start_uid) == 0, "found %lld\n", + (long long)(int)offsetof(struct nodemap_offset_rec, nor_start_uid)); + LASSERTF((int)sizeof(((struct nodemap_offset_rec *)0)->nor_start_uid) == 4, "found %lld\n", + (long long)(int)sizeof(((struct nodemap_offset_rec *)0)->nor_start_uid)); + LASSERTF((int)offsetof(struct nodemap_offset_rec, nor_limit_uid) == 4, "found %lld\n", + (long long)(int)offsetof(struct nodemap_offset_rec, nor_limit_uid)); + LASSERTF((int)sizeof(((struct nodemap_offset_rec *)0)->nor_limit_uid) == 4, "found %lld\n", + (long long)(int)sizeof(((struct nodemap_offset_rec *)0)->nor_limit_uid)); + LASSERTF((int)offsetof(struct nodemap_offset_rec, nor_start_gid) == 8, "found %lld\n", + (long long)(int)offsetof(struct nodemap_offset_rec, nor_start_gid)); + LASSERTF((int)sizeof(((struct nodemap_offset_rec *)0)->nor_start_gid) == 4, "found %lld\n", + (long long)(int)sizeof(((struct nodemap_offset_rec *)0)->nor_start_gid)); + LASSERTF((int)offsetof(struct nodemap_offset_rec, nor_limit_gid) == 12, "found %lld\n", + (long long)(int)offsetof(struct nodemap_offset_rec, nor_limit_gid)); + LASSERTF((int)sizeof(((struct nodemap_offset_rec *)0)->nor_limit_gid) == 4, "found %lld\n", + (long long)(int)sizeof(((struct nodemap_offset_rec *)0)->nor_limit_gid)); + LASSERTF((int)offsetof(struct nodemap_offset_rec, nor_start_projid) == 16, "found %lld\n", + (long long)(int)offsetof(struct nodemap_offset_rec, nor_start_projid)); + LASSERTF((int)sizeof(((struct nodemap_offset_rec *)0)->nor_start_projid) == 4, "found %lld\n", + (long long)(int)sizeof(((struct nodemap_offset_rec *)0)->nor_start_projid)); + LASSERTF((int)offsetof(struct nodemap_offset_rec, nor_limit_projid) == 20, "found %lld\n", + (long long)(int)offsetof(struct nodemap_offset_rec, nor_limit_projid)); + LASSERTF((int)sizeof(((struct nodemap_offset_rec *)0)->nor_limit_projid) == 4, "found %lld\n", + (long long)(int)sizeof(((struct nodemap_offset_rec *)0)->nor_limit_projid)); + LASSERTF((int)offsetof(struct nodemap_offset_rec, nor_padding1) == 24, "found %lld\n", + (long long)(int)offsetof(struct nodemap_offset_rec, nor_padding1)); + LASSERTF((int)sizeof(((struct nodemap_offset_rec *)0)->nor_padding1) == 4, "found %lld\n", + (long long)(int)sizeof(((struct nodemap_offset_rec *)0)->nor_padding1)); + LASSERTF((int)offsetof(struct nodemap_offset_rec, nor_padding2) == 28, "found %lld\n", + (long long)(int)offsetof(struct nodemap_offset_rec, nor_padding2)); + LASSERTF((int)sizeof(((struct nodemap_offset_rec *)0)->nor_padding2) == 4, "found %lld\n", + (long long)(int)sizeof(((struct nodemap_offset_rec *)0)->nor_padding2)); + /* Checks for union nodemap_rec */ LASSERTF((int)sizeof(union nodemap_rec) == 32, "found %lld\n", (long long)(int)sizeof(union nodemap_rec)); @@ -6401,6 +6437,8 @@ void lustre_assert_wire_constants(void) (long long)NODEMAP_CLUSTER_REC); LASSERTF(NODEMAP_CLUSTER_ROLES == 1, "found %lld\n", (long long)NODEMAP_CLUSTER_ROLES); + LASSERTF(NODEMAP_CLUSTER_OFFSET == 2, "found %lld\n", + (long long)NODEMAP_CLUSTER_OFFSET); LASSERTF(NM_TYPE_MASK == 0x0fffffffUL, "found 0x%.8xUL\n", (unsigned)NM_TYPE_MASK); LASSERTF(NM_TYPE_SHIFT == 28, "found %lld\n", @@ -6999,6 +7037,10 @@ void lustre_assert_wire_constants(void) (unsigned)LCFG_NODEMAP_ADD_PROJIDMAP); LASSERTF(LCFG_NODEMAP_DEL_PROJIDMAP == 0x000ce04bUL, "found 0x%.8xUL\n", (unsigned)LCFG_NODEMAP_DEL_PROJIDMAP); + LASSERTF(LCFG_NODEMAP_ADD_OFFSET == 0x000ce04cUL, "found 0x%.8xUL\n", + (unsigned)LCFG_NODEMAP_ADD_OFFSET); + LASSERTF(LCFG_NODEMAP_DEL_OFFSET == 0x000ce04dUL, "found 0x%.8xUL\n", + (unsigned)LCFG_NODEMAP_DEL_OFFSET); LASSERTF(LCFG_NODEMAP_TRUSTED == 0x000ce050UL, "found 0x%.8xUL\n", (unsigned)LCFG_NODEMAP_TRUSTED); LASSERTF(LCFG_NODEMAP_SQUASH_UID == 0x000ce051UL, "found 0x%.8xUL\n", diff --git a/lustre/tests/sanity-sec.sh b/lustre/tests/sanity-sec.sh index eb65976..e7a59e1 100755 --- a/lustre/tests/sanity-sec.sh +++ b/lustre/tests/sanity-sec.sh @@ -2331,6 +2331,112 @@ test_27aa() { #LU-17922 } run_test 27aa "test nodemap idmap range" +test_27ab() { #LU-18109 + local idmap + local id=500 + local offset + + do_facet mgs $LCTL nodemap_add Test18109 || + error "unable to add Test18109 as nodemap" + stack_trap "do_facet mgs $LCTL nodemap_del Test18109 || true" + + do_facet mgs $LCTL nodemap_add OffsetTest || + error "unable to add OffsetTest as nodemap" + stack_trap "do_facet mgs $LCTL nodemap_del OffsetTest || true" + + do_facet mgs $LCTL nodemap_add_offset --name Test18109 \ + --offset 100000 --limit 200000 || + error "cannot set offset 100000-299999 for Test18109" + + #expected error, invalid offset range supplied + do_facet mgs $LCTL nodemap_add_offset --name OffsetTest \ + --offset 150000 --limit 100000 && + error "cannot set offset 150000-249999 for OffsetTest" + + do_facet mgs $LCTL nodemap_add_idmap --name Test18109 \ + --idtype uid --idmap 500-509:0-9 || + error "unable to add idmap range 500-509:0-9" + + idmap=$(do_facet mgs $LCTL get_param nodemap.Test18109.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 Test18109 \ + --idtype uid --idmap 500-509:0 || + error "cannot delete idmap range 500-509:0" + + #expected error, invalid secondary range supplied + do_facet mgs $LCTL nodemap_add --name Test18109 \ + --idtype uid --idmap 500-509:200000-200010 && + error "Invalid range 200000-200010 was supplied" + + (( $(do_facet mgs $LCTL get_param nodemap.Test18109.idmap | + grep -c idtype) == 0 )) || + error "invalid range 200000-200010 supplied and passed" + + offset=$(do_facet mgs $LCTL get_param nodemap.Test18109.offset | + grep start_uid) + [[ "$offset" == *"start_uid: 100000"* ]] || + error "expected start_uid of 100000 not found before remounting" + + offset=$(do_facet mgs $LCTL get_param nodemap.Test18109.offset | + grep limit_uid) + [[ "$offset" == *"limit_uid: 200000"* ]] || + error "expected limit_uid of 200000 not found before remounting" + + stopall || error "failed to unmount servers" + setupall || error "failed to remount servers" + + offset=$(do_facet mgs $LCTL get_param nodemap.Test18109.offset | + grep start_uid) + [[ "$offset" == *"start_uid: 100000"* ]] || + error "expected start_uid of 100000 not found after remounting" + + offset=$(do_facet mgs $LCTL get_param nodemap.Test18109.offset | + grep limit_uid) + [[ "$offset" == *"limit_uid: 200000"* ]] || + error "expected limit_uid of 200000 not found after remounting" + + do_facet mgs $LCTL nodemap_del_offset --name Test18109 || + error "cannot del offset from Test18109" + + offset=$(do_facet mgs $LCTL get_param nodemap.Test18109.offset | + grep start_uid) + [[ "$offset" == *"start_uid: 0"* ]] || + error "expected start_uid 0, found $offset" + + offset=$(do_facet mgs $LCTL get_param nodemap.Test18109.offset | + grep limit_uid) + [[ "$offset" == *"limit_uid: 0"* ]] || + error "expected limit_uid 0, found $offset" + + stopall || error "failed to unmount servers" + setupall || error "failed to remount servers" + + offset=$(do_facet mgs $LCTL get_param nodemap.Test18109.offset | + grep start_uid) + [[ "$offset" == *"start_uid: 0"* ]] || + error "expected start_uid 0, found $offset after remounting" + + offset=$(do_facet mgs $LCTL get_param nodemap.Test18109.offset | + grep limit_uid) + [[ "$offset" == *"limit_uid: 0"* ]] || + error "expected limit_uid 0, found $offset after remounting" + + do_facet mgs $LCTL nodemap_del Test18109 || + error "failed to remove nodemap Test18109" + + do_facet mgs $LCTL nodemap_del OffsetTest || + error "failed to remove nodemap OffsetTest" +} +run_test 27ab "test nodemap idmap offset" + test_27b() { #LU-10703 [ "$MDS1_VERSION" -lt $(version_code 2.11.50) ] && skip "Need MDS >= 2.11.50" diff --git a/lustre/utils/lctl.c b/lustre/utils/lctl.c index ec12fd4..867ee55 100644 --- a/lustre/utils/lctl.c +++ b/lustre/utils/lctl.c @@ -517,6 +517,12 @@ command_t cmdlist[] = { {"nodemap_modify", jt_nodemap_modify, 0, "modify a nodemap parameters\n" "usage: nodemap_modify nodemap_name param value"}, + {"nodemap_add_offset", jt_nodemap_add_offset, 0, + "add an offset for UID/GID/PROJID mappings\n" + "usage: nodemap_add_offset --name NODEMAP_NAME --offset OFFSET --limit LIMIT\n"}, + {"nodemap_del_offset", jt_nodemap_del_offset, 0, + "delete an offset for UID/GID/PROJID mappings\n" + "usage: nodemap_del_offset --name NODEMAP_NAME --offset OFFSET\n"}, {"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, diff --git a/lustre/utils/obd.c b/lustre/utils/obd.c index 92ab07b..d8fe19e 100644 --- a/lustre/utils/obd.c +++ b/lustre/utils/obd.c @@ -4598,6 +4598,137 @@ int jt_nodemap_modify(int argc, char **argv) return rc; } +/** + * Add a nodemap's UID/GID/PROJID offset + * + * \param argc number of args + * \param argv[] variable string arguments + * + * --name nodemap name + * --offset UID/GID/PROJID offset + * --limit number of maximum entries + * + * \retval 0 on success + */ +int jt_nodemap_add_offset(int argc, char **argv) +{ + char *nodemap_name = NULL; + __u32 offset = 0; + __u32 limit = 0; + char param[24]; + int rc = 0; + int c; + + static struct option long_opts[] = { + { .val = 'l', .name = "limit", .has_arg = required_argument }, + { .val = 'n', .name = "name", .has_arg = required_argument }, + { .val = 'o', .name = "offset", .has_arg = required_argument }, + { .name = NULL } }; + + while ((c = getopt_long(argc, argv, "l:n:o:", + long_opts, NULL)) != -1) { + switch (c) { + case 'l': + limit = strtol(optarg, NULL, 10); + if (errno == ERANGE) { + fprintf(stderr, + "Invalid limit value input: %u\n", + limit); + return -1; + } + break; + case 'n': + nodemap_name = optarg; + break; + case 'o': + offset = strtol(optarg, NULL, 10); + if (errno == ERANGE) { + fprintf(stderr, + "Invalid offset value input: %u\n", + offset); + return -1; + } + break; + } + } + + if (!nodemap_name || !offset || !limit || + offset <= 0 || offset >= UINT_MAX || errno != 0) { + fprintf(stderr, "%s: invalid nodemap '%s' offset '%s'\n", + jt_cmdname(argv[0]), nodemap_name, optarg); + return CMD_HELP; + } + + /* user warnings for setting offset to 0 or less than 65536 */ + if (offset < 65536) + fprintf(stderr, + "It is not recomended to have an offset before 65536 as the nobody/squash id's will not be mapped properly.\n"); + + snprintf(param, sizeof(param), "%u+%u", offset, limit); + + rc = nodemap_cmd(LCFG_NODEMAP_ADD_OFFSET, false, NULL, 0, + argv[0], nodemap_name, param, NULL); + + if (rc == -ERANGE) { + fprintf(stderr, + "%s: cannot set offset %s to nodemap '%s' because it overlaps with existing offset: %s\n", + *argv, param, nodemap_name, strerror(-rc)); + } else if (rc != 0) { + fprintf(stderr, + "%s: cannot set offset %s to nodemap '%s': %s\n", + *argv, param, nodemap_name, strerror(-rc)); + } + + return rc; +} + +/** + * Delete a nodemap's UID/GID/PROJID offset + * + * \param argc number of args + * \param argv[] variable string arguments + * + * --name nodemap name + * + * \retval 0 on success + */ +int jt_nodemap_del_offset(int argc, char **argv) +{ + char *nodemap_name = NULL; + int rc = 0; + int c; + + static struct option long_opts[] = { + { .val = 'n', .name = "name", .has_arg = required_argument }, + { .name = NULL } }; + + while ((c = getopt_long(argc, argv, "n:", + long_opts, NULL)) != -1) { + switch (c) { + case 'n': + nodemap_name = optarg; + break; + } + } + + if (!nodemap_name || errno != 0) { + fprintf(stderr, "%s: invalid nodemap '%s' offset '%s'\n", + jt_cmdname(argv[0]), nodemap_name, optarg); + return CMD_HELP; + } + + rc = nodemap_cmd(LCFG_NODEMAP_DEL_OFFSET, false, NULL, 0, + argv[0], nodemap_name, NULL); + + if (rc != 0) { + fprintf(stderr, + "%s: cannot del offset from nodemap '%s': %s\n", + *argv, nodemap_name, strerror(-rc)); + } + + return rc; +} + int jt_nodemap_add_idmap(int argc, char **argv) { int c; @@ -4748,6 +4879,20 @@ int jt_nodemap_modify(int argc, char **argv) return -EOPNOTSUPP; } +int jt_nodemap_add_offset(int argc, char **argv) +{ + fprintf(stderr, "error: %s: invalid ioctl\n", + jt_cmdname(argv[0])); + return -EOPNOTSUPP; +} + +int jt_nodemap_del_offset(int argc, char **argv) +{ + fprintf(stderr, "error: %s: invalid ioctl\n", + jt_cmdname(argv[0])); + return -EOPNOTSUPP; +} + int jt_nodemap_add_range(int argc, char **argv) { fprintf(stderr, "error: %s: invalid ioctl\n", diff --git a/lustre/utils/obdctl.h b/lustre/utils/obdctl.h index 16b089f..1c497c9 100644 --- a/lustre/utils/obdctl.h +++ b/lustre/utils/obdctl.h @@ -180,6 +180,8 @@ int jt_nodemap_activate(int argc, char **argv); int jt_nodemap_add(int argc, char **argv); int jt_nodemap_del(int argc, char **argv); int jt_nodemap_modify(int argc, char **argv); +int jt_nodemap_add_offset(int argc, char **argv); +int jt_nodemap_del_offset(int argc, char **argv); int jt_nodemap_add_range(int argc, char **argv); int jt_nodemap_test_nid(int argc, char **argv); int jt_nodemap_del_range(int argc, char **argv); diff --git a/lustre/utils/wirecheck.c b/lustre/utils/wirecheck.c index 9661947..f6bef37 100644 --- a/lustre/utils/wirecheck.c +++ b/lustre/utils/wirecheck.c @@ -2959,6 +2959,20 @@ static void check_nodemap_id_rec(void) CHECK_MEMBER(nodemap_id_rec, nir_padding4); } +static void check_nodemap_offset_rec(void) +{ + BLANK_LINE(); + CHECK_STRUCT(nodemap_offset_rec); + CHECK_MEMBER(nodemap_offset_rec, nor_start_uid); + CHECK_MEMBER(nodemap_offset_rec, nor_limit_uid); + CHECK_MEMBER(nodemap_offset_rec, nor_start_gid); + CHECK_MEMBER(nodemap_offset_rec, nor_limit_gid); + CHECK_MEMBER(nodemap_offset_rec, nor_start_projid); + CHECK_MEMBER(nodemap_offset_rec, nor_limit_projid); + CHECK_MEMBER(nodemap_offset_rec, nor_padding1); + CHECK_MEMBER(nodemap_offset_rec, nor_padding2); +} + static void check_nodemap_global_rec(void) { BLANK_LINE(); @@ -3008,6 +3022,7 @@ static void check_nodemap_key(void) CHECK_VALUE(NODEMAP_CLUSTER_REC); CHECK_VALUE(NODEMAP_CLUSTER_ROLES); + CHECK_VALUE(NODEMAP_CLUSTER_OFFSET); CHECK_VALUE_X(NM_TYPE_MASK); CHECK_VALUE(NM_TYPE_SHIFT); @@ -3287,6 +3302,8 @@ check_lustre_cfg(void) CHECK_VALUE_X(LCFG_NODEMAP_ADMIN); CHECK_VALUE_X(LCFG_NODEMAP_ADD_PROJIDMAP); CHECK_VALUE_X(LCFG_NODEMAP_DEL_PROJIDMAP); + CHECK_VALUE_X(LCFG_NODEMAP_ADD_OFFSET); + CHECK_VALUE_X(LCFG_NODEMAP_DEL_OFFSET); CHECK_VALUE_X(LCFG_NODEMAP_TRUSTED); CHECK_VALUE_X(LCFG_NODEMAP_SQUASH_UID); CHECK_VALUE_X(LCFG_NODEMAP_SQUASH_GID); @@ -3753,6 +3770,7 @@ main(int argc, char **argv) check_nodemap_range_rec(); check_nodemap_range2_rec(); check_nodemap_id_rec(); + check_nodemap_offset_rec(); check_nodemap_global_rec(); check_nodemap_cluster_roles_rec(); check_nodemap_rec(); diff --git a/lustre/utils/wiretest.c b/lustre/utils/wiretest.c index cc51138..fde6012 100644 --- a/lustre/utils/wiretest.c +++ b/lustre/utils/wiretest.c @@ -6381,6 +6381,42 @@ void lustre_assert_wire_constants(void) LASSERTF((int)sizeof(((struct nodemap_cluster_roles_rec *)0)->ncrr_padding3) == 8, "found %lld\n", (long long)(int)sizeof(((struct nodemap_cluster_roles_rec *)0)->ncrr_padding3)); + /* Checks for struct nodemap_offset_rec */ + LASSERTF((int)sizeof(struct nodemap_offset_rec) == 32, "found %lld\n", + (long long)(int)sizeof(struct nodemap_offset_rec)); + LASSERTF((int)offsetof(struct nodemap_offset_rec, nor_start_uid) == 0, "found %lld\n", + (long long)(int)offsetof(struct nodemap_offset_rec, nor_start_uid)); + LASSERTF((int)sizeof(((struct nodemap_offset_rec *)0)->nor_start_uid) == 4, "found %lld\n", + (long long)(int)sizeof(((struct nodemap_offset_rec *)0)->nor_start_uid)); + LASSERTF((int)offsetof(struct nodemap_offset_rec, nor_limit_uid) == 4, "found %lld\n", + (long long)(int)offsetof(struct nodemap_offset_rec, nor_limit_uid)); + LASSERTF((int)sizeof(((struct nodemap_offset_rec *)0)->nor_limit_uid) == 4, "found %lld\n", + (long long)(int)sizeof(((struct nodemap_offset_rec *)0)->nor_limit_uid)); + LASSERTF((int)offsetof(struct nodemap_offset_rec, nor_start_gid) == 8, "found %lld\n", + (long long)(int)offsetof(struct nodemap_offset_rec, nor_start_gid)); + LASSERTF((int)sizeof(((struct nodemap_offset_rec *)0)->nor_start_gid) == 4, "found %lld\n", + (long long)(int)sizeof(((struct nodemap_offset_rec *)0)->nor_start_gid)); + LASSERTF((int)offsetof(struct nodemap_offset_rec, nor_limit_gid) == 12, "found %lld\n", + (long long)(int)offsetof(struct nodemap_offset_rec, nor_limit_gid)); + LASSERTF((int)sizeof(((struct nodemap_offset_rec *)0)->nor_limit_gid) == 4, "found %lld\n", + (long long)(int)sizeof(((struct nodemap_offset_rec *)0)->nor_limit_gid)); + LASSERTF((int)offsetof(struct nodemap_offset_rec, nor_start_projid) == 16, "found %lld\n", + (long long)(int)offsetof(struct nodemap_offset_rec, nor_start_projid)); + LASSERTF((int)sizeof(((struct nodemap_offset_rec *)0)->nor_start_projid) == 4, "found %lld\n", + (long long)(int)sizeof(((struct nodemap_offset_rec *)0)->nor_start_projid)); + LASSERTF((int)offsetof(struct nodemap_offset_rec, nor_limit_projid) == 20, "found %lld\n", + (long long)(int)offsetof(struct nodemap_offset_rec, nor_limit_projid)); + LASSERTF((int)sizeof(((struct nodemap_offset_rec *)0)->nor_limit_projid) == 4, "found %lld\n", + (long long)(int)sizeof(((struct nodemap_offset_rec *)0)->nor_limit_projid)); + LASSERTF((int)offsetof(struct nodemap_offset_rec, nor_padding1) == 24, "found %lld\n", + (long long)(int)offsetof(struct nodemap_offset_rec, nor_padding1)); + LASSERTF((int)sizeof(((struct nodemap_offset_rec *)0)->nor_padding1) == 4, "found %lld\n", + (long long)(int)sizeof(((struct nodemap_offset_rec *)0)->nor_padding1)); + LASSERTF((int)offsetof(struct nodemap_offset_rec, nor_padding2) == 28, "found %lld\n", + (long long)(int)offsetof(struct nodemap_offset_rec, nor_padding2)); + LASSERTF((int)sizeof(((struct nodemap_offset_rec *)0)->nor_padding2) == 4, "found %lld\n", + (long long)(int)sizeof(((struct nodemap_offset_rec *)0)->nor_padding2)); + /* Checks for union nodemap_rec */ LASSERTF((int)sizeof(union nodemap_rec) == 32, "found %lld\n", (long long)(int)sizeof(union nodemap_rec)); @@ -6426,6 +6462,8 @@ void lustre_assert_wire_constants(void) (long long)NODEMAP_CLUSTER_REC); LASSERTF(NODEMAP_CLUSTER_ROLES == 1, "found %lld\n", (long long)NODEMAP_CLUSTER_ROLES); + LASSERTF(NODEMAP_CLUSTER_OFFSET == 2, "found %lld\n", + (long long)NODEMAP_CLUSTER_OFFSET); LASSERTF(NM_TYPE_MASK == 0x0fffffffUL, "found 0x%.8xUL\n", (unsigned)NM_TYPE_MASK); LASSERTF(NM_TYPE_SHIFT == 28, "found %lld\n", @@ -7024,6 +7062,10 @@ void lustre_assert_wire_constants(void) (unsigned)LCFG_NODEMAP_ADD_PROJIDMAP); LASSERTF(LCFG_NODEMAP_DEL_PROJIDMAP == 0x000ce04bUL, "found 0x%.8xUL\n", (unsigned)LCFG_NODEMAP_DEL_PROJIDMAP); + LASSERTF(LCFG_NODEMAP_ADD_OFFSET == 0x000ce04cUL, "found 0x%.8xUL\n", + (unsigned)LCFG_NODEMAP_ADD_OFFSET); + LASSERTF(LCFG_NODEMAP_DEL_OFFSET == 0x000ce04dUL, "found 0x%.8xUL\n", + (unsigned)LCFG_NODEMAP_DEL_OFFSET); LASSERTF(LCFG_NODEMAP_TRUSTED == 0x000ce050UL, "found 0x%.8xUL\n", (unsigned)LCFG_NODEMAP_TRUSTED); LASSERTF(LCFG_NODEMAP_SQUASH_UID == 0x000ce051UL, "found 0x%.8xUL\n", -- 1.8.3.1