From db818bd0401038cbfac65bfd2f6f7a006d7fa150 Mon Sep 17 00:00:00 2001 From: Sebastien Buisson Date: Thu, 21 Mar 2024 10:13:43 +0100 Subject: [PATCH] LU-17431 nodemap: allow modifying properties of a dynamic nm Modify properties of a dynamic nodemap, by sending the appropriate ioctl to the MDS or OSS device. On kernel side, we need to allow handling a nodemap even if the nodemap config file is not accessible (i.e. we are not on the MGS). This dynamic nodemap is not stored on disk. Signed-off-by: Sebastien Buisson Change-Id: I7253e51ecb8869c2d2ac268926c1c907005ec4a7 Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/54513 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Andreas Dilger Reviewed-by: Marc Vef Reviewed-by: Oleg Drokin --- lustre/tests/sanity-sec.sh | 88 ++++++++++++++++++++++++- lustre/utils/lctl.c | 12 ++-- lustre/utils/obd.c | 161 +++++++++++++++++++++++++++++++++------------ 3 files changed, 211 insertions(+), 50 deletions(-) diff --git a/lustre/tests/sanity-sec.sh b/lustre/tests/sanity-sec.sh index 3b83ea1..16cfad7 100755 --- a/lustre/tests/sanity-sec.sh +++ b/lustre/tests/sanity-sec.sh @@ -6794,6 +6794,9 @@ test_72() { local endnid=1.1.1.100@tcp local clid=500 local fsid=1000 + local properties="audit_mode deny_unknown forbid_encryption \ + readonly_mount" + local sepol="1:mls:31:40afb76d077c441b69af58cccaaa2ca63641ed6e21b0a887dc21a684f508b78f" local val (( OST1_VERSION >= $(version_code 2.15.64) )) || @@ -6802,6 +6805,13 @@ test_72() { [[ "$(facet_active_host mgs)" != "$(facet_active_host ost1)" ]] || skip "Need servers on different hosts" + activedefault=$(do_facet mgs $LCTL get_param -n nodemap.active) + if [[ "$activedefault" != "1" ]]; then + do_facet mgs $LCTL nodemap_activate 1 + wait_nm_sync active + stack_trap cleanup_active EXIT + fi + do_facet mgs $LCTL nodemap_add $mgsnm || error "adding $mgsnm on MGS failed" stack_trap "do_facet mgs $LCTL nodemap_del $mgsnm" EXIT @@ -6810,7 +6820,7 @@ test_72() { do_facet mgs $LCTL nodemap_add_idmap --name $mgsnm --idtype uid \ --idmap $mgsclid:$mgsfsid || error "add_idmap for $mgsnm on MGS failed" - wait_nm_sync $mgsnm idmap '' inactive + wait_nm_sync $mgsnm idmap stack_trap "do_facet ost1 $LCTL nodemap_del $nm || true" EXIT do_facet ost1 $LCTL nodemap_add $nm && @@ -6849,6 +6859,74 @@ test_72() { error "dynamic nodemap wrong fs id $val" fi + for prop in $properties; do + do_facet ost1 $LCTL nodemap_modify --name $nm \ + --property $prop --value 1 || + error "dynamic modify of $prop failed" + val=$(do_facet ost1 $LCTL get_param -n nodemap.$nm.$prop) + [[ "x$val" == "x1" ]] || error "incorrect $prop $val" + done + prop=admin + do_facet ost1 $LCTL nodemap_modify --name $nm \ + --property $prop --value 1 || + error "dynamic modify of $prop failed" + val=$(do_facet ost1 $LCTL get_param -n nodemap.$nm.admin_nodemap) + [[ "x$val" == "x1" ]] || error "incorrect $prop $val" + prop=trusted + do_facet ost1 $LCTL nodemap_modify --name $nm \ + --property $prop --value 0 || + error "dynamic modify of $prop failed" + val=$(do_facet ost1 $LCTL get_param -n nodemap.$nm.trusted_nodemap) + [[ "x$val" == "x0" ]] || error "incorrect $prop $val" + prop=map_mode + do_facet ost1 $LCTL nodemap_modify --name $nm \ + --property $prop --value uid || + error "dynamic modify of $prop failed" + val=$(do_facet ost1 $LCTL get_param -n nodemap.$nm.$prop) + [[ "x$val" == "xuid" ]] || error "incorrect $prop $val" + prop=rbac + do_facet ost1 $LCTL nodemap_modify --name $nm \ + --property $prop --value file_perms || + error "dynamic modify of $prop failed" + val=$(do_facet ost1 $LCTL get_param -n nodemap.$nm.$prop) + [[ "x$val" == "xfile_perms" ]] || error "incorrect $prop $val" + prop=squash_uid + do_facet ost1 $LCTL nodemap_modify --name $nm \ + --property $prop --value 77 || + error "dynamic modify of $prop failed" + val=$(do_facet ost1 $LCTL get_param -n nodemap.$nm.$prop) + [[ "x$val" == "x77" ]] || error "incorrect $prop $val" + prop=squash_gid + do_facet ost1 $LCTL nodemap_modify --name $nm \ + --property $prop --value 77 || + error "dynamic modify of $prop failed" + val=$(do_facet ost1 $LCTL get_param -n nodemap.$nm.$prop) + [[ "x$val" == "x77" ]] || error "incorrect $prop $val" + prop=squash_projid + do_facet ost1 $LCTL nodemap_modify --name $nm \ + --property $prop --value 77 || + error "dynamic modify of $prop failed" + val=$(do_facet ost1 $LCTL get_param -n nodemap.$nm.$prop) + [[ "x$val" == "x77" ]] || error "incorrect $prop $val" + prop=fileset + do_facet ost1 $LCTL nodemap_set_fileset --name $nm \ + --fileset "/tmp" || + error "dynamic modify of $prop failed" + val=$(do_facet ost1 $LCTL get_param -n nodemap.$nm.$prop) + [[ "x$val" == "x/tmp" ]] || error "incorrect $prop $val" + prop=sepol + do_facet ost1 $LCTL nodemap_set_sepol --name $nm \ + --sepol $sepol || + error "dynamic modify of $prop failed" + val=$(do_facet ost1 $LCTL get_param -n nodemap.$nm.$prop) + [[ "x$val" == "x$sepol" ]] || error "incorrect $prop $val" + + val=$(do_facet ost1 $LCTL nodemap_test_id --nid $startnid \ + --idtype uid --id $clid) + if [[ "x$val" != "x$fsid" ]]; then + error "dynamic test_id on server failed" + fi + do_facet ost1 $LCTL nodemap_del_idmap --name $nm --idtype uid \ --idmap $clid:$fsid || error "dynamic del_idmap on server failed" @@ -6858,6 +6936,11 @@ test_72() { error "idmap should be empty, got $val" fi + val=$(do_facet ost1 $LCTL nodemap_test_nid $startnid) + if [[ "x$val" != "x$nm" ]]; then + error "dynamic test_nid on server failed" + fi + do_facet ost1 $LCTL nodemap_del_range --name $nm --range $nids || error "dynamic del_range on server failed" val=$(do_facet ost1 $LCTL get_param nodemap.$nm.ranges | @@ -6883,6 +6966,9 @@ test_72() { do_facet ost1 $LCTL nodemap_del_idmap --name $mgsnm --idtype uid \ --idmap $mgsclid:$mgsfsid && error "del_idmap $mgsnm on server should fail" + do_facet ost1 $LCTL nodemap_modify --name $mgsnm \ + --property squash_projid --value 77 && + error "modify $mgsnm on server should fail" do_facet ost1 $LCTL nodemap_del $mgsnm && error "nodemap del $mgsnm on server should fail" do_facet ost1 $LCTL get_param -R 'nodemap.*' diff --git a/lustre/utils/lctl.c b/lustre/utils/lctl.c index 9e6c43f..b3277ad 100644 --- a/lustre/utils/lctl.c +++ b/lustre/utils/lctl.c @@ -515,8 +515,8 @@ command_t cmdlist[] = { "delete a range from a nodemap\n" "usage: nodemap_del_range --name NODEMAP_NAME --range NID_RANGE"}, {"nodemap_modify", jt_nodemap_modify, 0, - "modify a nodemap parameters\n" - "usage: nodemap_modify nodemap_name param value"}, + "modify a nodemap parameter\n" + "usage: nodemap_modify --name NODEMAP_NAME --property PROPERTY_NAME --value 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"}, @@ -531,14 +531,14 @@ command_t cmdlist[] = { "usage: nodemap_del_idmap --name NODEMAP_NAME --idtype ID_TYPE --idmap CLIENTID:FSID"}, {"nodemap_set_fileset", jt_nodemap_set_fileset, 0, "set a fileset on a nodemap\n" - "usage: nodemap_set_fileset "}, + "usage: nodemap_set_fileset --name NODEMAP_NAME --fileset FILESET"}, {"nodemap_set_sepol", jt_nodemap_set_sepol, 0, "set SELinux policy info on a nodemap\n" - "usage: nodemap_set_sepol "}, + "usage: nodemap_set_sepol --name NODEMAP_NAME --sepol SEPOL"}, {"nodemap_test_nid", jt_nodemap_test_nid, 0, - "usage: nodemap_test_nid "}, + "usage: nodemap_test_nid NID"}, {"nodemap_test_id", jt_nodemap_test_id, 0, - "Usage: nodemap_test_id --nid --idtype [uid|gid] --id "}, + "Usage: nodemap_test_id --nid NID --idtype ID_TYPE --id ID"}, {"nodemap_info", jt_nodemap_info, 0, "Usage: nodemap_info [list|nodemap_name|all]"}, diff --git a/lustre/utils/obd.c b/lustre/utils/obd.c index d7cfa0a..ccfb210 100644 --- a/lustre/utils/obd.c +++ b/lustre/utils/obd.c @@ -4138,11 +4138,36 @@ del_usage: */ int jt_nodemap_test_nid(int argc, char **argv) { - char rawbuf[MAX_IOC_BUFLEN]; - int rc; + char rawbuf[MAX_IOC_BUFLEN]; + char *nid = NULL; + int c, rc; - rc = nodemap_cmd(LCFG_NODEMAP_TEST_NID, false, &rawbuf, sizeof(rawbuf), - argv[0], argv[1], NULL); + static struct option long_opts[] = { + { .val = 'h', .name = "help", .has_arg = no_argument }, + { .name = NULL } }; + + while ((c = getopt_long(argc, argv, "dh", + long_opts, NULL)) != -1) { + switch (c) { + case 'h': + default: + goto test_nid_usage; + } + } + + if (optind < argc) + nid = argv[optind]; + + if (!nid) { + fprintf(stderr, "nodemap_test_nid: missing NID\n"); +test_nid_usage: + fprintf(stderr, + "usage: nodemap_test_nid NID\n"); + return -EINVAL; + } + + rc = nodemap_cmd(LCFG_NODEMAP_TEST_NID, false, &rawbuf, + sizeof(rawbuf), argv[0], nid, NULL); if (rc == 0) printf("%s\n", (char *)rawbuf); @@ -4163,39 +4188,53 @@ int jt_nodemap_test_nid(int argc, char **argv) */ int jt_nodemap_test_id(int argc, char **argv) { - char rawbuf[MAX_IOC_BUFLEN]; - char *nidstr = NULL; - char *idstr = NULL; - char *typestr = NULL; - int rc = 0; - int c; + char rawbuf[MAX_IOC_BUFLEN]; + char *nidstr = NULL; + char *idstr = NULL; + char *typestr = NULL; + int c, rc = 0; static struct option long_opts[] = { + { .val = 'h', .name = "help", .has_arg = no_argument }, { .val = 'i', .name = "id", .has_arg = required_argument }, { .val = 'n', .name = "nid", .has_arg = required_argument }, { .val = 't', .name = "idtype", .has_arg = required_argument }, { .name = NULL } }; - while ((c = getopt_long(argc, argv, "n:t:i:", + while ((c = getopt_long(argc, argv, "hi:n:t:", long_opts, NULL)) != -1) { switch (c) { + case 'i': + idstr = optarg; + break; case 'n': nidstr = optarg; break; case 't': typestr = optarg; break; - case 'i': - idstr = optarg; - break; + case 'h': + default: + goto test_id_usage; } } - if (!nidstr || !typestr || !idstr) { + if (!nidstr) { + fprintf(stderr, "nodemap_test_id: missing NID\n"); +test_id_usage: fprintf(stderr, - "usage: nodemap_test_id --nid --idtype [uid|gid] --id \n"); - return -1; + "usage: nodemap_test_id --nid NID --idtype IDTYPE --id ID\n"); + return -EINVAL; + } + if (!typestr) { + fprintf(stderr, + "nodemap_test_id: missing idtype, must be one of uid, gid, projid\n"); + goto test_id_usage; + } + if (!idstr) { + fprintf(stderr, "nodemap_test_id: missing id\n"); + goto test_id_usage; } rc = nodemap_cmd(LCFG_NODEMAP_TEST_ID, false, &rawbuf, sizeof(rawbuf), @@ -4404,30 +4443,39 @@ int jt_nodemap_set_fileset(int argc, char **argv) { char *nodemap_name = NULL; char *fileset_name = NULL; - int rc = 0; - int c; + int c, rc = 0; static struct option long_opts[] = { { .val = 'f', .name = "fileset", .has_arg = required_argument }, + { .val = 'h', .name = "help", .has_arg = no_argument }, { .val = 'n', .name = "name", .has_arg = required_argument }, { .name = NULL } }; - while ((c = getopt_long(argc, argv, "n:f:", + while ((c = getopt_long(argc, argv, "f:hn:", long_opts, NULL)) != -1) { switch (c) { - case 'n': - nodemap_name = optarg; - break; case 'f': fileset_name = optarg; break; + case 'n': + nodemap_name = optarg; + break; + case 'h': + default: + goto set_fileset_usage; } } - if (!nodemap_name || !fileset_name) { + if (!nodemap_name) { + fprintf(stderr, "nodemap_set_fileset: missing nodemap name\n"); +set_fileset_usage: fprintf(stderr, - "usage: nodemap_set_fileset --name --fileset \n"); - return -1; + "usage: nodemap_set_fileset --name NODEMAP_NAME --fileset FILESET\n"); + return -EINVAL; + } + if (!fileset_name) { + fprintf(stderr, "nodemap_set_fileset: missing NID range\n"); + goto set_fileset_usage; } rc = nodemap_cmd(LCFG_NODEMAP_SET_FILESET, false, NULL, 0, argv[0], @@ -4457,11 +4505,15 @@ int jt_nodemap_set_sepol(int argc, char **argv) { char *nodemap_name = NULL; char *sepol = NULL; - int rc = 0; - int c; + int c, rc = 0; static struct option long_options[] = { { + .name = "help", + .has_arg = no_argument, + .val = 'h', + }, + { .name = "name", .has_arg = required_argument, .val = 'n', @@ -4476,7 +4528,7 @@ int jt_nodemap_set_sepol(int argc, char **argv) } }; - while ((c = getopt_long(argc, argv, "n:s:", + while ((c = getopt_long(argc, argv, "hn:s:", long_options, NULL)) != -1) { switch (c) { case 'n': @@ -4485,13 +4537,22 @@ int jt_nodemap_set_sepol(int argc, char **argv) case 's': sepol = optarg; break; + case 'h': + default: + goto set_sepol_usage; } } - if (!nodemap_name || !sepol) { + if (!nodemap_name) { + fprintf(stderr, "nodemap_set_sepol: missing nodemap name\n"); +set_sepol_usage: fprintf(stderr, - "usage: nodemap_set_sepol --name --sepol \n"); - return -1; + "usage: nodemap_set_sepol --name NODEMAP_NAME --sepol SEPOL\n"); + return -EINVAL; + } + if (!sepol) { + fprintf(stderr, "nodemap_set_sepol: missing sepol\n"); + goto set_sepol_usage; } rc = nodemap_cmd(LCFG_NODEMAP_SET_SEPOL, false, NULL, 0, argv[0], @@ -4521,20 +4582,20 @@ int jt_nodemap_set_sepol(int argc, char **argv) */ int jt_nodemap_modify(int argc, char **argv) { - int c; - int rc = 0; enum lcfg_command_type cmd = 0; - char *nodemap_name = NULL; - char *param = NULL; - char *value = NULL; + char *nodemap_name = NULL; + char *param = NULL; + char *value = NULL; + int c, rc = 0; static struct option long_opts[] = { + { .val = 'h', .name = "help", .has_arg = no_argument }, { .val = 'n', .name = "name", .has_arg = required_argument }, { .val = 'p', .name = "property", .has_arg = required_argument }, { .val = 'v', .name = "value", .has_arg = required_argument }, { .name = NULL } }; - while ((c = getopt_long(argc, argv, "n:p:v:", + while ((c = getopt_long(argc, argv, "hn:p:v:", long_opts, NULL)) != -1) { switch (c) { case 'n': @@ -4546,15 +4607,29 @@ int jt_nodemap_modify(int argc, char **argv) case 'v': value = optarg; break; + case 'h': + default: + goto modify_usage; } } - if (!nodemap_name || !param || !value) { + if (!nodemap_name) { + fprintf(stderr, "nodemap_modify: missing nodemap name\n"); +modify_usage: fprintf(stderr, - "usage: nodemap_modify --name --property --value \n"); + "usage: %s --name NODEMAP_NAME --property PROPERTY_NAME --value VALUE\n", + argv[0]); fprintf(stderr, "valid properties: admin trusted map_mode squash_uid squash_gid squash_projid deny_unknown audit_mode forbid_encryption readonly_mount rbac\n"); - return -1; + return -EINVAL; + } + if (!param) { + fprintf(stderr, "nodemap_modify: missing property name\n"); + goto modify_usage; + } + if (!value) { + fprintf(stderr, "nodemap_modify: missing value for property\n"); + goto modify_usage; } if (strcmp("admin", param) == 0) { @@ -4581,9 +4656,9 @@ int jt_nodemap_modify(int argc, char **argv) cmd = LCFG_NODEMAP_RBAC; } else { fprintf(stderr, - "error: %s: nodemap_modify invalid subcommand: %s\n", + "error: %s: nodemap_modify invalid property: %s\n", jt_cmdname(argv[0]), param); - return -1; + goto modify_usage; } rc = nodemap_cmd(cmd, false, NULL, 0, argv[0], nodemap_name, param, -- 1.8.3.1