Whamcloud - gitweb
LU-18109 utils: adding nodemap offset capability 43/55943/20
authorMaximilian Dilger <mdilger@whamcloud.com>
Tue, 6 Aug 2024 19:49:28 +0000 (13:49 -0600)
committerOleg Drokin <green@whamcloud.com>
Thu, 2 Jan 2025 20:47:23 +0000 (20:47 +0000)
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 <mdilger@whamcloud.com>
Change-Id: Iba2116d21bc7de1ba03111b0313427301e4b0b50
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/55943
Reviewed-by: Sebastien Buisson <sbuisson@ddn.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
19 files changed:
lustre/doc/Makefile.am
lustre/doc/lctl-nodemap-add-offset.8 [new file with mode: 0644]
lustre/doc/lctl-nodemap-del-offset.8 [new file with mode: 0644]
lustre/doc/lctl.8
lustre/include/lustre_nodemap.h
lustre/include/uapi/linux/lustre/lustre_cfg.h
lustre/include/uapi/linux/lustre/lustre_disk.h
lustre/include/uapi/linux/lustre/lustre_idl.h
lustre/ptlrpc/nodemap_handler.c
lustre/ptlrpc/nodemap_internal.h
lustre/ptlrpc/nodemap_lproc.c
lustre/ptlrpc/nodemap_storage.c
lustre/ptlrpc/wiretest.c
lustre/tests/sanity-sec.sh
lustre/utils/lctl.c
lustre/utils/obd.c
lustre/utils/obdctl.h
lustre/utils/wirecheck.c
lustre/utils/wiretest.c

index 61f4f7b..889c0d3 100644 (file)
@@ -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 (file)
index 0000000..3a2e338
--- /dev/null
@@ -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 (file)
index 0000000..d670f64
--- /dev/null
@@ -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)
index bcb6d28..15ae282 100644 (file)
@@ -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),
index f335931..087019e 100644 (file)
@@ -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);
index 6408735..7bf7687 100644 (file)
@@ -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 */
index e1124e5..8d406b8 100644 (file)
@@ -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 */
index 8b61084..4aa3e50 100644 (file)
@@ -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 {
index c9c43ed..7869ae3 100644 (file)
@@ -26,6 +26,7 @@
  *
  * Author: Joshua Walgenbach <jjw@iu.edu>
  */
+
 #include <linux/module.h>
 #include <linux/sort.h>
 #include <uapi/linux/lnet/nidstr.h>
@@ -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:
index a3be687..07837cd 100644 (file)
@@ -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]);
index 5d9af1f..28881f2 100644 (file)
@@ -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,
        },
index 23469c9..b7c5ddb 100644 (file)
@@ -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) {
index cfbed5a..eb05529 100644 (file)
@@ -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",
index eb65976..e7a59e1 100755 (executable)
@@ -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"
index ec12fd4..867ee55 100644 (file)
@@ -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,
index 92ab07b..d8fe19e 100644 (file)
@@ -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",
index 16b089f..1c497c9 100644 (file)
@@ -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);
index 9661947..f6bef37 100644 (file)
@@ -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();
index cc51138..fde6012 100644 (file)
@@ -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",