Whamcloud - gitweb
LU-18109 nodemap: map back root with offset 95/58895/5
authorSebastien Buisson <sbuisson@ddn.com>
Tue, 22 Apr 2025 13:08:17 +0000 (15:08 +0200)
committerOleg Drokin <green@whamcloud.com>
Tue, 27 May 2025 04:05:50 +0000 (04:05 +0000)
When a nodemap is defined with admin=1 and an offset, root should be
mapped back to id 0, independently from the map_mode property.

sanity-sec test_77 is added to exercise this.

Fixes: e3051ad0f1c8 ("LU-18109 utils: adding nodemap offset capability")
Signed-off-by: Sebastien Buisson <sbuisson@ddn.com>
Change-Id: I5b220dc90104ceab5c874dfbee41d3e85aefeb5b
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/58895
Reviewed-by: Marc Vef <mvef@whamcloud.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>
lustre/ptlrpc/nodemap_handler.c
lustre/tests/sanity-sec.sh

index 2f7d5e8..897d595 100644 (file)
@@ -866,44 +866,74 @@ __u32 nodemap_map_id(struct lu_nodemap *nodemap,
        ENTRY;
 
        if (!nodemap_active)
-               goto out;
+               GOTO(out, found_id);
 
        if (unlikely(nodemap == NULL))
-               goto out;
+               GOTO(out, found_id);
 
-       if (id_type != NODEMAP_PROJID && id == 0) {
+       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, found_id);
+       }
+
+       /* if mapping from fs to client id space, start by un-offsetting */
+       if ((offset_start != 0 || offset_limit != 0) &&
+           tree_type == NODEMAP_FS_TO_CLIENT) {
+               if (found_id < offset_start ||
+                   found_id >= offset_start + offset_limit) {
+                       /* If we are outside boundaries, squash id */
+                       CDEBUG(D_SEC,
+                              "%s: id %d for type %u is below nodemap start %u, squash\n",
+                              nodemap->nm_name, found_id, id_type,
+                              offset_start);
+                       GOTO(squash, found_id);
+               }
+               found_id -= offset_start;
+       }
+
+       if (id_type != NODEMAP_PROJID && found_id == 0) {
                /* root id is mapped and offset just as the other ids. This
                 * means root cannot remain root as soon as offset is defined.
                 */
                if (nodemap->nmf_allow_root_access)
-                       goto offset;
-               goto map;
+                       GOTO(offset, found_id);
+               GOTO(map, found_id);
        }
 
        if (id_type == NODEMAP_UID &&
            !(nodemap->nmf_map_mode & NODEMAP_MAP_UID))
-               goto offset;
+               GOTO(offset, found_id);
 
        if (id_type == NODEMAP_GID &&
            !(nodemap->nmf_map_mode & NODEMAP_MAP_GID))
-               goto offset;
+               GOTO(offset, found_id);
 
        if (id_type == NODEMAP_PROJID &&
            !(nodemap->nmf_map_mode & NODEMAP_MAP_PROJID))
-               goto offset;
+               GOTO(offset, found_id);
 
        if (nodemap->nmf_trust_client_ids)
-               goto offset;
+               GOTO(offset, found_id);
 
 map:
        if (is_default_nodemap(nodemap))
-               goto squash;
+               GOTO(squash, found_id);
 
        down_read(&nodemap->nm_idmap_lock);
-       idmap = idmap_search(nodemap, tree_type, id_type, id);
+       idmap = idmap_search(nodemap, tree_type, id_type, found_id);
        if (idmap == NULL) {
                up_read(&nodemap->nm_idmap_lock);
-               goto squash;
+               GOTO(squash, found_id);
        }
 
        if (tree_type == NODEMAP_FS_TO_CLIENT)
@@ -921,47 +951,22 @@ squash:
        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) {
-               if (found_id < offset_start) {
-                       /* If we are outside boundaries, try to squash before
-                        * offsetting, and return unmapped otherwise.
-                        */
-                       if (!attempted_squash)
-                               GOTO(squash, found_id);
-
-                       CDEBUG(D_SEC,
-                              "%s: squash_id for type %u is below nodemap start %u, use unmapped value %u\n",
-                              nodemap->nm_name, id_type, offset_start,
-                              found_id);
-                       GOTO(out, found_id);
-               }
-               found_id -= offset_start;
-       } else {
+offset:
+       /* if mapping from client to fs id space, end with offsetting */
+       if ((offset_start != 0 || offset_limit != 0) &&
+           tree_type == NODEMAP_CLIENT_TO_FS) {
                if (found_id >= offset_limit) {
                        /* If we are outside boundaries, try to squash before
                         * offsetting, and return unmapped otherwise.
                         */
-                       if (!attempted_squash)
+                       if (!attempted_squash) {
+                               CDEBUG(D_SEC,
+                                      "%s: id %d for type %u is outside nodemap limit %u, squash\n",
+                                      nodemap->nm_name, found_id, id_type,
+                                      offset_limit);
                                GOTO(squash, found_id);
+                       }
 
                        CDEBUG(D_SEC,
                               "%s: squash_id for type %u is outside nodemap limit %u, use unmapped value %u\n",
index 5b1eb4c..4c773b5 100755 (executable)
@@ -5516,7 +5516,7 @@ cleanup_local_client_nodemap() {
        fi
 }
 
-cleanup_55() {
+cleanup_local_client_nodemap_with_mounts() {
        # unmount client
        if is_mounted $MOUNT; then
                umount_client $MOUNT || error "umount $MOUNT failed"
@@ -5556,7 +5556,7 @@ test_55() {
        do_nodes $(comma_list $(all_mdts_nodes)) \
                $LCTL set_param mdt.*.identity_upcall=NONE
 
-       stack_trap cleanup_55 EXIT
+       stack_trap cleanup_local_client_nodemap_with_mounts EXIT
 
        setup_local_client_nodemap "c0" 0 1
 
@@ -8037,6 +8037,57 @@ test_76() {
 }
 run_test 76 "suppgroups and gid mapping"
 
+test_77() {
+       local squash=100
+       local nm=c0
+
+       (( $MDS1_VERSION >= $(version_code 2.16.54) )) ||
+               skip "Need MDS version >= 2.16.54 for proper root offsetting"
+
+       do_nodes $(comma_list $(all_mdts_nodes)) \
+               $LCTL set_param mdt.*.identity_upcall=NONE
+
+       stack_trap cleanup_local_client_nodemap_with_mounts EXIT
+
+       # create dir before nodemap create
+       $LFS mkdir -i 0 -c 1 $DIR/$tdir || error "mkdir $DIR/$tdir failed"
+
+       # unmount client completely
+       umount_client $MOUNT || error "umount $MOUNT failed"
+       if is_mounted $MOUNT2; then
+               umount_client $MOUNT2 || error "umount $MOUNT2 failed"
+       fi
+
+       # setup nodemap with offset
+       setup_local_client_nodemap $nm 1 0
+       do_facet mgs $LCTL nodemap_modify --name $nm \
+               --property squash_uid --value $squash ||
+               error "Setting squash_uid=$squash on $nm failed"
+       do_facet mgs $LCTL nodemap_modify --name $nm \
+               --property squash_gid --value $squash ||
+               error "Setting squash_gid=$squash on $nm failed"
+       do_facet mgs $LCTL nodemap_modify --name $nm \
+               --property squash_projid --value $squash ||
+               error "Setting squash_projid=$squash on $nm failed"
+       do_facet mgs $LCTL nodemap_add_offset --name $nm \
+               --offset 100000 --limit 200000 ||
+                       error "nodemap_add_offset failed"
+       wait_nm_sync $nm offset
+
+       # remount client to take nodemap into account
+       zconf_mount_clients $HOSTNAME $MOUNT $MOUNT_OPTS ||
+               error "remount failed"
+       wait_ssk
+
+       # create a file as root...
+       touch $DIR/$tdir/fileA
+       # the owner:group ids read back should be 0:0
+       ls -ln $DIR/$tdir/fileA
+       [[ $(stat -c "%u:%g" $DIR/$tdir/fileA) == "0:0" ]] ||
+               error "bad owner/group for root file"
+}
+run_test 77 "root offsetting"
+
 log "cleanup: ======================================================"
 
 sec_unsetup() {