From 0daeebcbdc4e89d59221299f2687cfd3c4f00b5b Mon Sep 17 00:00:00 2001 From: Sebastien Buisson Date: Wed, 30 Jun 2021 18:30:57 +0200 Subject: [PATCH] LU-14797 nodemap: map project id Add calls to nodemap_map_id() in order to map project IDs from client ID to server ID and conversely. Also extend nodemap_can_setquota() to allow setquota on project only if ID is not squashed or deny_unknown is not set. Update sanity-sec test_27a to exercise the feature. Signed-off-by: Sebastien Buisson Change-Id: Id66458550d312404b1993ead8940c3d12eaadccd Reviewed-on: https://review.whamcloud.com/44119 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Patrick Farrell Reviewed-by: Andreas Dilger Reviewed-by: Oleg Drokin --- lustre/include/lustre_nodemap.h | 2 +- lustre/mdt/mdt_handler.c | 14 ++++++++------ lustre/mdt/mdt_io.c | 6 +++++- lustre/mdt/mdt_lib.c | 11 ++++++----- lustre/ofd/ofd_dev.c | 4 ++++ lustre/ofd/ofd_io.c | 6 +++++- lustre/ptlrpc/nodemap_handler.c | 30 +++++++++++++++++++++++++---- lustre/target/tgt_handler.c | 3 +++ lustre/tests/sanity-sec.sh | 42 +++++++++++++++++++++++++++++++++++++++++ lustre/utils/lfs.c | 6 +++++- lustre/utils/obd.c | 2 +- 11 files changed, 106 insertions(+), 20 deletions(-) diff --git a/lustre/include/lustre_nodemap.h b/lustre/include/lustre_nodemap.h index 7ac2c14..8754a97 100644 --- a/lustre/include/lustre_nodemap.h +++ b/lustre/include/lustre_nodemap.h @@ -155,7 +155,7 @@ int nodemap_set_squash_gid(const char *name, gid_t gid); int nodemap_set_squash_projid(const char *name, projid_t projid); int nodemap_set_audit_mode(const char *name, bool enable_audit); int nodemap_set_forbid_encryption(const char *name, bool forbid_encryption); -bool nodemap_can_setquota(const struct lu_nodemap *nodemap); +bool nodemap_can_setquota(struct lu_nodemap *nodemap, __u32 qc_type, __u32 id); int nodemap_add_idmap(const char *name, enum nodemap_id_type id_type, const __u32 map[2]); int nodemap_del_idmap(const char *name, enum nodemap_id_type id_type, diff --git a/lustre/mdt/mdt_handler.c b/lustre/mdt/mdt_handler.c index 9181c9a..82c7bee 100644 --- a/lustre/mdt/mdt_handler.c +++ b/lustre/mdt/mdt_handler.c @@ -831,7 +831,7 @@ void mdt_pack_attr2body(struct mdt_thread_info *info, struct mdt_body *b, b->mbo_nlink = attr->la_nlink; b->mbo_valid |= OBD_MD_FLNLINK; } - if (attr->la_valid & (LA_UID|LA_GID)) { + if (attr->la_valid & (LA_UID|LA_GID|LA_PROJID)) { nodemap = nodemap_get_from_exp(exp); if (IS_ERR(nodemap)) goto out; @@ -850,8 +850,9 @@ void mdt_pack_attr2body(struct mdt_thread_info *info, struct mdt_body *b, } if (attr->la_valid & LA_PROJID) { - /* TODO, nodemap for project id */ - b->mbo_projid = attr->la_projid; + b->mbo_projid = nodemap_map_id(nodemap, NODEMAP_PROJID, + NODEMAP_FS_TO_CLIENT, + attr->la_projid); b->mbo_valid |= OBD_MD_FLPROJID; } @@ -3143,7 +3144,8 @@ static int mdt_quotactl(struct tgt_session_info *tsi) case LUSTRE_Q_SETQUOTAPOOL: case LUSTRE_Q_SETINFOPOOL: case LUSTRE_Q_SETDEFAULT_POOL: - if (!nodemap_can_setquota(nodemap)) + if (!nodemap_can_setquota(nodemap, oqctl->qc_type, + oqctl->qc_id)) GOTO(out_nodemap, rc = -EPERM); /* fallthrough */ case Q_GETINFO: @@ -3177,8 +3179,8 @@ static int mdt_quotactl(struct tgt_session_info *tsi) NODEMAP_CLIENT_TO_FS, id); break; case PRJQUOTA: - /* todo: check/map project id */ - id = oqctl->qc_id; + id = nodemap_map_id(nodemap, NODEMAP_PROJID, + NODEMAP_CLIENT_TO_FS, id); break; default: GOTO(out_nodemap, rc = -EOPNOTSUPP); diff --git a/lustre/mdt/mdt_io.c b/lustre/mdt/mdt_io.c index 2984d57..a0ae1b5 100644 --- a/lustre/mdt/mdt_io.c +++ b/lustre/mdt/mdt_io.c @@ -767,7 +767,7 @@ int mdt_obd_commitrw(const struct lu_env *env, int cmd, struct obd_export *exp, if (cmd == OBD_BRW_WRITE) { struct lu_nodemap *nodemap; - __u32 mapped_uid, mapped_gid; + __u32 mapped_uid, mapped_gid, mapped_projid; nodemap = nodemap_get_from_exp(exp); if (IS_ERR(nodemap)) @@ -778,6 +778,9 @@ int mdt_obd_commitrw(const struct lu_env *env, int cmd, struct obd_export *exp, mapped_gid = nodemap_map_id(nodemap, NODEMAP_GID, NODEMAP_FS_TO_CLIENT, oa->o_gid); + mapped_projid = nodemap_map_id(nodemap, NODEMAP_PROJID, + NODEMAP_FS_TO_CLIENT, + oa->o_projid); if (!IS_ERR_OR_NULL(nodemap)) { /* do not bypass quota enforcement if squashed uid */ if (unlikely(mapped_uid == nodemap->nm_squash_uid)) { @@ -850,6 +853,7 @@ int mdt_obd_commitrw(const struct lu_env *env, int cmd, struct obd_export *exp, */ oa->o_uid = mapped_uid; oa->o_gid = mapped_gid; + oa->o_projid = mapped_projid; } else if (cmd == OBD_BRW_READ) { /* If oa != NULL then mdt_preprw_read updated the inode * atime and we should update the lvb so that other glimpses diff --git a/lustre/mdt/mdt_lib.c b/lustre/mdt/mdt_lib.c index b5c75e9..9b5693d 100644 --- a/lustre/mdt/mdt_lib.c +++ b/lustre/mdt/mdt_lib.c @@ -1134,11 +1134,12 @@ static int mdt_setattr_unpack_rec(struct mdt_thread_info *info) if (IS_ERR(nodemap)) RETURN(PTR_ERR(nodemap)); - la->la_uid = nodemap_map_id(nodemap, NODEMAP_UID, - NODEMAP_CLIENT_TO_FS, rec->sa_uid); - la->la_gid = nodemap_map_id(nodemap, NODEMAP_GID, - NODEMAP_CLIENT_TO_FS, rec->sa_gid); - la->la_projid = rec->sa_projid; + la->la_uid = nodemap_map_id(nodemap, NODEMAP_UID, + NODEMAP_CLIENT_TO_FS, rec->sa_uid); + la->la_gid = nodemap_map_id(nodemap, NODEMAP_GID, + NODEMAP_CLIENT_TO_FS, rec->sa_gid); + la->la_projid = nodemap_map_id(nodemap, NODEMAP_PROJID, + NODEMAP_CLIENT_TO_FS, rec->sa_projid); nodemap_putref(nodemap); la->la_size = rec->sa_size; diff --git a/lustre/ofd/ofd_dev.c b/lustre/ofd/ofd_dev.c index 8b66c31..1261963 100644 --- a/lustre/ofd/ofd_dev.c +++ b/lustre/ofd/ofd_dev.c @@ -2388,6 +2388,10 @@ static int ofd_quotactl(struct tgt_session_info *tsi) id = nodemap_map_id(nodemap, NODEMAP_GID, NODEMAP_CLIENT_TO_FS, repoqc->qc_id); + else if (oqctl->qc_type == PRJQUOTA) + id = nodemap_map_id(nodemap, NODEMAP_PROJID, + NODEMAP_CLIENT_TO_FS, + repoqc->qc_id); nodemap_putref(nodemap); diff --git a/lustre/ofd/ofd_io.c b/lustre/ofd/ofd_io.c index ffb8a26..3b96d63 100644 --- a/lustre/ofd/ofd_io.c +++ b/lustre/ofd/ofd_io.c @@ -1462,7 +1462,7 @@ int ofd_commitrw(const struct lu_env *env, int cmd, struct obd_export *exp, if (cmd == OBD_BRW_WRITE) { struct lu_nodemap *nodemap; - __u32 mapped_uid, mapped_gid; + __u32 mapped_uid, mapped_gid, mapped_projid; nodemap = nodemap_get_from_exp(exp); if (IS_ERR(nodemap)) @@ -1473,6 +1473,9 @@ int ofd_commitrw(const struct lu_env *env, int cmd, struct obd_export *exp, mapped_gid = nodemap_map_id(nodemap, NODEMAP_GID, NODEMAP_FS_TO_CLIENT, oa->o_gid); + mapped_projid = nodemap_map_id(nodemap, NODEMAP_PROJID, + NODEMAP_FS_TO_CLIENT, + oa->o_projid); if (!IS_ERR_OR_NULL(nodemap)) { /* do not bypass quota enforcement if squashed uid */ @@ -1555,6 +1558,7 @@ int ofd_commitrw(const struct lu_env *env, int cmd, struct obd_export *exp, * server ID will be returned back to client in that case. */ oa->o_uid = mapped_uid; oa->o_gid = mapped_gid; + oa->o_projid = mapped_projid; } else if (cmd == OBD_BRW_READ) { rc = ofd_commitrw_read(env, ofd, fid, objcount, npages, lnb); diff --git a/lustre/ptlrpc/nodemap_handler.c b/lustre/ptlrpc/nodemap_handler.c index 34d04b8..7fe568e 100644 --- a/lustre/ptlrpc/nodemap_handler.c +++ b/lustre/ptlrpc/nodemap_handler.c @@ -1423,14 +1423,36 @@ out: EXPORT_SYMBOL(nodemap_set_squash_projid); /** - * Returns true if this nodemap has root user access. Always returns true if - * nodemaps are not active. + * Check if nodemap allows setting quota. + * + * If nodemap is not active, always allow. + * For user and group quota, allow if the nodemap allows root access. + * For project quota, allow if project id is not squashed or deny_unknown + * is not set. * * \param nodemap nodemap to check access for + * \param qc_type quota type + * \param id client id to map + * \retval true is setquota is allowed, false otherwise */ -bool nodemap_can_setquota(const struct lu_nodemap *nodemap) +bool nodemap_can_setquota(struct lu_nodemap *nodemap, __u32 qc_type, __u32 id) { - return !nodemap_active || (nodemap && nodemap->nmf_allow_root_access); + if (!nodemap_active) + return true; + + if (!nodemap || !nodemap->nmf_allow_root_access) + return false; + + if (qc_type == PRJQUOTA) { + id = nodemap_map_id(nodemap, NODEMAP_PROJID, + NODEMAP_CLIENT_TO_FS, id); + + if (id == nodemap->nm_squash_projid && + nodemap->nmf_deny_unknown) + return false; + } + + return true; } EXPORT_SYMBOL(nodemap_can_setquota); diff --git a/lustre/target/tgt_handler.c b/lustre/target/tgt_handler.c index 62e6f2e8..5a53c4c 100644 --- a/lustre/target/tgt_handler.c +++ b/lustre/target/tgt_handler.c @@ -265,6 +265,9 @@ static int tgt_ost_body_unpack(struct tgt_session_info *tsi, __u32 flags) body->oa.o_gid = nodemap_map_id(nodemap, NODEMAP_GID, NODEMAP_CLIENT_TO_FS, body->oa.o_gid); + body->oa.o_projid = nodemap_map_id(nodemap, NODEMAP_PROJID, + NODEMAP_CLIENT_TO_FS, + body->oa.o_projid); nodemap_putref(nodemap); tsi->tsi_ost_body = body; diff --git a/lustre/tests/sanity-sec.sh b/lustre/tests/sanity-sec.sh index f0f26e2..c2987e0 100755 --- a/lustre/tests/sanity-sec.sh +++ b/lustre/tests/sanity-sec.sh @@ -1032,6 +1032,20 @@ test_15() { rc=$? [[ $rc != 0 ]] && error "nodemap_add failed with $rc" && return 1 + for (( i = 0; i < NODEMAP_COUNT; i++ )); do + local csum=${HOSTNAME_CHECKSUM}_${i} + + if ! do_facet mgs $LCTL nodemap_modify --name $csum \ + --property admin --value 0; then + rc=$((rc + 1)) + fi + if ! do_facet mgs $LCTL nodemap_modify --name $csum \ + --property trusted --value 0; then + rc=$((rc + 1)) + fi + done + [[ $rc != 0 ]] && error "nodemap_modify failed with $rc" && return 1 + rc=0 for ((i = 0; i < NODEMAP_COUNT; i++)); do if ! add_range ${HOSTNAME_CHECKSUM}_${i} $i; then @@ -1940,11 +1954,15 @@ run_test 26 "test transferring very large nodemap" nodemap_exercise_fileset() { local nm="$1" local loop=0 + local check_proj=true + + (( $MDS1_VERSION >= $(version_code 2.14.52) )) || check_proj=false # setup if [ "$nm" == "default" ]; then do_facet mgs $LCTL nodemap_activate 1 wait_nm_sync active + check_proj=false else nodemap_test_setup fi @@ -1965,6 +1983,23 @@ nodemap_exercise_fileset() { error "unable to add fileset info to $nm nodemap for servers" wait_nm_sync $nm fileset "nodemap.${nm}.fileset=/$subdir" + if $check_proj; then + do_facet mgs $LCTL nodemap_modify --name $nm \ + --property admin --value 1 + wait_nm_sync $nm admin_nodemap + do_facet mgs $LCTL nodemap_modify --name $nm \ + --property trusted --value 0 + wait_nm_sync $nm trusted_nodemap + do_facet mgs $LCTL nodemap_modify --name $nm \ + --property map_mode --value projid + wait_nm_sync $nm map_mode + do_facet mgs $LCTL nodemap_add_idmap --name $nm \ + --idtype projid --idmap 1:1 + do_facet mgs $LCTL nodemap_modify --name $nm \ + --property deny_unknown --value 1 + wait_nm_sync $nm deny_unknown + fi + # re-mount client zconf_umount_clients ${clients_arr[0]} $MOUNT || error "unable to umount client ${clients_arr[0]}" @@ -1978,6 +2013,13 @@ nodemap_exercise_fileset() { do_node ${clients_arr[0]} test -f $MOUNT/this_is_$subdir || error "fileset not taken into account" + if $check_proj; then + $LFS setquota -p 1 -b 10000 -B 11000 -i 0 -I 0 $MOUNT || + error "setquota -p 1 failed" + $LFS setquota -p 2 -b 10000 -B 11000 -i 0 -I 0 $MOUNT && + error "setquota -p 2 should have failed" + fi + # re-mount client with sub-subdir zconf_umount_clients ${clients_arr[0]} $MOUNT || error "unable to umount client ${clients_arr[0]}" diff --git a/lustre/utils/lfs.c b/lustre/utils/lfs.c index c68eb66..d160fa2 100644 --- a/lustre/utils/lfs.c +++ b/lustre/utils/lfs.c @@ -8010,9 +8010,13 @@ quota_type_def: if (rc) { if (*obd_type) fprintf(stderr, - "%s setquota: cannot quotactl '%s' '%s': %s", + "%s setquota: cannot quotactl '%s' '%s': %s\n", progname, obd_type, obd_uuid2str(&qctl->obd_uuid), strerror(-rc)); + else + fprintf(stderr, + "%s setquota: quotactl failed: %s\n", + progname, strerror(-rc)); } out: if (rc) diff --git a/lustre/utils/obd.c b/lustre/utils/obd.c index 416c4df..5a4ee67 100644 --- a/lustre/utils/obd.c +++ b/lustre/utils/obd.c @@ -4155,7 +4155,7 @@ int jt_nodemap_test_id(int argc, char **argv) } rc = nodemap_cmd(LCFG_NODEMAP_TEST_ID, &rawbuf, sizeof(rawbuf), - argv[0], nidstr, typestr, idstr); + argv[0], nidstr, typestr, idstr, NULL); if (rc == 0) printf("%s\n", (char *)rawbuf); -- 1.8.3.1