From 719f6763fe19d208833040a36d47ad360da465f2 Mon Sep 17 00:00:00 2001 From: Marc Vef Date: Tue, 13 May 2025 13:27:31 +0200 Subject: [PATCH] LU-18756 sec: add resource id check to oss and mds This patch includes the resource id check into the relevant code paths on the oss and mds side. It is therefore included for the following operations. On the MDT-side: - open - create (file and directory) - unlink (file and directory) - setattr - setxattr - getxattr - rename - link On the OST-side and on the MDT-side for Data on MDT (DoM) files: - write - read - truncate - fallocate Some caveats: The resource id check is not included for MDS_GETATTR RPCs due to functional and usability concerns. Specifically for the latter, the "struct stat" would no longer be filled resulting in "?" when running "ls -l", which can be misunderstood. Also, if the check is only enabled on the OST-side, writes are only denied for "sync"/"fsync"-type operations on a file as the check is at the server-side. If the check is enabled on the MDT-side, write-access is denied before the OST_WRITE RPC is sent, i.e., immediately returning the access denied error code. If a file is still in the page cache before the check is enabled, a client can still read the local copy of the file, which is expected. Sanity-sec test 75a was added to exercise the ID check for the above cases in several disciplines further testing that access to neighboring nodemap offset ranges work as expected. Test-Parameters: trivial testlist=sanity-sec Signed-off-by: Marc Vef Change-Id: I040ddb1b934707baa84b492337139f45b856692e Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/59208 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Andreas Dilger Reviewed-by: Oleg Drokin Reviewed-by: Sebastien Buisson --- lustre/mdt/mdt_io.c | 21 ++ lustre/mdt/mdt_open.c | 19 +- lustre/mdt/mdt_reint.c | 37 ++++ lustre/mdt/mdt_xattr.c | 8 + lustre/ofd/ofd_io.c | 8 + lustre/ofd/ofd_objects.c | 17 ++ lustre/tests/sanity-sec.sh | 477 +++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 586 insertions(+), 1 deletion(-) diff --git a/lustre/mdt/mdt_io.c b/lustre/mdt/mdt_io.c index 7ba9109..5a9d12b 100644 --- a/lustre/mdt/mdt_io.c +++ b/lustre/mdt/mdt_io.c @@ -322,6 +322,7 @@ static int mdt_preprw_read(const struct lu_env *env, struct obd_export *exp, struct niobuf_remote *rnb, int *nr_local, struct niobuf_local *lnb) { + struct mdt_thread_info *info = mdt_th_info(env); struct dt_object *dob; int i, j, rc; int maxlnb = *nr_local; @@ -348,6 +349,11 @@ static int mdt_preprw_read(const struct lu_env *env, struct obd_export *exp, */ RETURN(0); } + + rc = mdt_check_resource_ids(info, mo); + if (unlikely(rc)) + GOTO(out_sem, rc); + if (lu_object_is_dying(&mo->mot_header)) { CDEBUG_LIMIT(level, "%s: READ IO to stale obj "DFID": rc = %d\n", @@ -382,6 +388,7 @@ static int mdt_preprw_read(const struct lu_env *env, struct obd_export *exp, RETURN(0); buf_put: dt_bufs_put(env, dob, lnb, *nr_local); +out_sem: up_read(&mo->mot_dom_sem); return rc; } @@ -393,6 +400,7 @@ static int mdt_preprw_write(const struct lu_env *env, struct obd_export *exp, struct niobuf_remote *rnb, int *nr_local, struct niobuf_local *lnb) { + struct mdt_thread_info *info = mdt_th_info(env); struct dt_object *dob; int i, j, k, rc = 0; int maxlnb = *nr_local; @@ -417,6 +425,11 @@ static int mdt_preprw_write(const struct lu_env *env, struct obd_export *exp, /* exit with no data written, note nr_local = 0 above */ GOTO(unlock, rc); } + + rc = mdt_check_resource_ids(info, mo); + if (unlikely(rc)) + GOTO(unlock, rc); + if (lu_object_is_dying(&mo->mot_header)) { /* This is possible race between object destroy followed by * discard BL AST and client cache flushing. Object is @@ -1101,6 +1114,10 @@ int mdt_fallocate_hdl(struct tgt_session_info *tsi) GOTO(out_put, rc); } + rc = mdt_check_resource_ids(info, mo); + if (unlikely(rc)) + GOTO(out_put, rc); + la_from_obdo(la, oa, OBD_MD_FLMTIME | OBD_MD_FLATIME | OBD_MD_FLCTIME); down_write(&mo->mot_dom_sem); @@ -1374,6 +1391,10 @@ int mdt_punch_hdl(struct tgt_session_info *tsi) GOTO(out_put, rc); } + rc = mdt_check_resource_ids(info, mo); + if (unlikely(rc)) + GOTO(out_put, rc); + down_write(&mo->mot_dom_sem); dob = mdt_obj2dt(mo); diff --git a/lustre/mdt/mdt_open.c b/lustre/mdt/mdt_open.c index 58d3077..bf08042 100644 --- a/lustre/mdt/mdt_open.c +++ b/lustre/mdt/mdt_open.c @@ -744,6 +744,10 @@ static int mdt_open_by_fid(struct mdt_thread_info *info, struct ldlm_reply *rep, if (IS_ERR(o)) RETURN(rc = PTR_ERR(o)); + rc = mdt_check_resource_ids(info, o); + if (unlikely(rc)) + GOTO(out, rc); + rc = mdt_check_enc(info, o); if (rc) GOTO(out, rc); @@ -1158,8 +1162,12 @@ static int mdt_open_by_fid_lock(struct mdt_thread_info *info, GOTO(out, rc = -ENOENT); } - /* do not check enc for directory: always allow open */ + /* do not check enc or id for directory: always allow open */ if (!S_ISDIR(lu_object_attr(&o->mot_obj))) { + rc = mdt_check_resource_ids(info, o); + if (unlikely(rc)) + GOTO(out, rc); + rc = mdt_check_enc(info, o); if (rc) GOTO(out, rc); @@ -1249,10 +1257,15 @@ static int mdt_cross_open(struct mdt_thread_info *info, int rc; ENTRY; + o = mdt_object_find(info->mti_env, info->mti_mdt, fid); if (IS_ERR(o)) RETURN(rc = PTR_ERR(o)); + rc = mdt_check_resource_ids(info, o); + if (unlikely(rc)) + GOTO(out, rc); + rc = mdt_check_enc(info, o); if (rc) GOTO(out, rc); @@ -1530,6 +1543,10 @@ int mdt_reint_open(struct mdt_thread_info *info, struct mdt_lock_handle *lhc) open_flags & MDS_OPEN_CREAT) GOTO(out_parent, result = -EPERM); + result = mdt_check_resource_ids(info, parent); + if (unlikely(result)) + GOTO(out_parent, result); + result = mdt_check_enc(info, parent); if (result) GOTO(out_parent, result); diff --git a/lustre/mdt/mdt_reint.c b/lustre/mdt/mdt_reint.c index 6d59544..35883f9 100644 --- a/lustre/mdt/mdt_reint.c +++ b/lustre/mdt/mdt_reint.c @@ -558,6 +558,10 @@ static int mdt_create(struct mdt_thread_info *info, struct mdt_lock_handle *lhc) if (!mdt_object_exists(parent)) GOTO(put_parent, rc = -ENOENT); + rc = mdt_check_resource_ids(info, parent); + if (unlikely(rc)) + GOTO(put_parent, rc); + rc = mdt_check_enc(info, parent); if (rc) GOTO(put_parent, rc); @@ -926,6 +930,10 @@ static int mdt_reint_setattr(struct mdt_thread_info *info, if (!mdt_object_exists(mo)) GOTO(out_put, rc = -ENOENT); + rc = mdt_check_resource_ids(info, mo); + if (unlikely(rc)) + GOTO(out_put, rc); + if (mdt_object_remote(mo)) GOTO(out_put, rc = -EREMOTE); @@ -1288,6 +1296,10 @@ static int mdt_reint_unlink(struct mdt_thread_info *info, GOTO(put_child, rc = -ENOENT); } + rc = mdt_check_resource_ids(info, mc); + if (unlikely(rc)) + GOTO(put_child, rc); + child_lh = &info->mti_lh[MDT_LH_CHILD]; if (mdt_object_remote(mc)) { struct mdt_body *repbody; @@ -1464,6 +1476,10 @@ static int mdt_reint_link(struct mdt_thread_info *info, GOTO(put_source, rc = -ENOENT); } + rc = mdt_check_resource_ids(info, ms); + if (unlikely(rc)) + GOTO(put_source, rc); + CFS_RACE(OBD_FAIL_MDS_LINK_RENAME_RACE); lhp = &info->mti_lh[MDT_LH_PARENT]; @@ -1475,6 +1491,10 @@ static int mdt_reint_link(struct mdt_thread_info *info, if (rc) GOTO(unlock_parent, rc); + rc = mdt_check_resource_ids(info, mp); + if (unlikely(rc)) + GOTO(unlock_parent, rc); + rc = mdt_check_enc(info, mp); if (rc) GOTO(unlock_parent, rc); @@ -2288,6 +2308,10 @@ int mdt_reint_migrate(struct mdt_thread_info *info, if (!S_ISDIR(lu_object_attr(&pobj->mot_obj))) GOTO(put_parent, rc = -ENOTDIR); + rc = mdt_check_resource_ids(info, pobj); + if (unlikely(rc)) + GOTO(put_parent, rc); + rc = mdt_check_enc(info, pobj); if (rc) GOTO(put_parent, rc); @@ -2739,6 +2763,10 @@ lock_bfl: if (IS_ERR(msrcdir)) RETURN(PTR_ERR(msrcdir)); + rc = mdt_check_resource_ids(info, msrcdir); + if (unlikely(rc)) + GOTO(out_put_srcdir, rc); + rc = mdt_check_enc(info, msrcdir); if (rc) GOTO(out_put_srcdir, rc); @@ -2755,6 +2783,11 @@ lock_bfl: GOTO(out_put_srcdir, rc = PTR_ERR(mtgtdir)); } + /* if this succeeds we do not need to check "mnew" later again */ + rc = mdt_check_resource_ids(info, mtgtdir); + if (unlikely(rc)) + GOTO(out_put_tgtdir, rc); + rc = mdt_check_enc(info, mtgtdir); if (rc) GOTO(out_put_tgtdir, rc); @@ -2878,6 +2911,10 @@ lock_bfl: GOTO(out_put_old, rc = -ENOENT); } + rc = mdt_check_resource_ids(info, mold); + if (unlikely(rc)) + GOTO(out_put_old, rc); + if (mdt_object_remote(mold) && !mdt->mdt_enable_remote_rename) GOTO(out_put_old, rc = -EXDEV); diff --git a/lustre/mdt/mdt_xattr.c b/lustre/mdt/mdt_xattr.c index 87a5438..fced635 100644 --- a/lustre/mdt/mdt_xattr.c +++ b/lustre/mdt/mdt_xattr.c @@ -246,6 +246,10 @@ int mdt_getxattr(struct mdt_thread_info *info) if (rc) RETURN(err_serious(rc)); + rc = mdt_check_resource_ids(info, info->mti_object); + if (unlikely(rc)) + RETURN(err_serious(rc)); + next = mdt_object_child(info->mti_object); easize = mdt_getxattr_pack_reply(info); if (easize == -ENODATA) @@ -617,6 +621,10 @@ int mdt_reint_setxattr(struct mdt_thread_info *info, if (IS_ERR(obj)) GOTO(out, rc = PTR_ERR(obj)); + rc = mdt_check_resource_ids(info, obj); + if (unlikely(rc)) + GOTO(out_unlock, rc); + tgt_vbr_obj_set(env, mdt_obj2dt(obj)); rc = mdt_version_get_check_save(info, obj, 0); if (rc) diff --git a/lustre/ofd/ofd_io.c b/lustre/ofd/ofd_io.c index ca7b89a..d3938ad 100644 --- a/lustre/ofd/ofd_io.c +++ b/lustre/ofd/ofd_io.c @@ -605,6 +605,10 @@ static int ofd_preprw_read(const struct lu_env *env, struct obd_export *exp, if (!ofd_object_exists(fo)) GOTO(obj_put, rc = -ENOENT); + rc = ofd_check_resource_ids(env, exp); + if (unlikely(rc)) + GOTO(obj_put, rc); + if (ptlrpc_connection_is_local(exp->exp_connection)) dbt |= DT_BUFS_TYPE_LOCAL; @@ -1251,6 +1255,10 @@ ofd_commitrw_write(const struct lu_env *env, struct obd_export *exp, if (!ofd_object_exists(fo)) GOTO(out, rc = -ENOENT); + rc = ofd_check_resource_ids(env, exp); + if (unlikely(rc)) + GOTO(out, rc); + /* * The first write to each object must set some attributes. It is * important to set the uid/gid before calling diff --git a/lustre/ofd/ofd_objects.c b/lustre/ofd/ofd_objects.c index 5a5a6d8..c42b050 100644 --- a/lustre/ofd/ofd_objects.c +++ b/lustre/ofd/ofd_objects.c @@ -684,6 +684,11 @@ int ofd_attr_set(const struct lu_env *env, struct ofd_object *fo, if (!ofd_object_exists(fo)) GOTO(out, rc = -ENOENT); + ofd_info(env)->fti_obj = fo; + + rc = ofd_check_resource_ids(env, ofd_info(env)->fti_exp); + if (unlikely(rc)) + GOTO(out, rc); if (la->la_valid & LA_PROJID && CFS_FAIL_CHECK(OBD_FAIL_OUT_DROP_PROJID_SET)) @@ -799,6 +804,12 @@ int ofd_object_fallocate(const struct lu_env *env, struct ofd_object *fo, if (!ofd_object_exists(fo)) RETURN(-ENOENT); + ofd_info(env)->fti_obj = fo; + + rc = ofd_check_resource_ids(env, ofd_info(env)->fti_exp); + if (unlikely(rc)) + RETURN(rc); + /* VBR: version recovery check */ rc = ofd_version_get_check(info, fo); if (rc != 0) @@ -932,6 +943,12 @@ int ofd_object_punch(const struct lu_env *env, struct ofd_object *fo, GOTO(out, rc); } + ofd_info(env)->fti_obj = fo; + + rc = ofd_check_resource_ids(env, ofd_info(env)->fti_exp); + if (unlikely(rc)) + GOTO(out, rc); + /* VBR: version recovery check */ rc = ofd_version_get_check(info, fo); if (rc) diff --git a/lustre/tests/sanity-sec.sh b/lustre/tests/sanity-sec.sh index f6cb642..be7d518 100755 --- a/lustre/tests/sanity-sec.sh +++ b/lustre/tests/sanity-sec.sh @@ -8047,6 +8047,483 @@ test_75() { } run_test 75 "check uid/gid/projid are set on OST and MDT for various RPCs" +setup_75a() { + # Assumes that variables from test_75a are set + # Setup c0 (trusted) and c1 (tenant) nodemaps used by the clients + nodemap_test_setup + trap cleanup_75a EXIT + + # configure tentant nodemap + do_facet mgs $LCTL nodemap_set_fileset --name $nm_tenant \ + --fileset "/$fileset_nm" || error "Setting fileset failed" + do_facet mgs $LCTL nodemap_add_offset --name $nm_tenant \ + --offset $offset_start --limit $offset_limit || + error "cannot set offset for $nm_tenant" + do_facet mgs $LCTL nodemap_modify --name $nm_tenant \ + --property map_mode=projid || + error "cannot set offset for $nm_tenant" + + # configure trusted nodemap + do_facet mgs $LCTL nodemap_modify --name $nm_trusted \ + --property admin --value 1 || error "Setting admin=1 failed" + do_facet mgs $LCTL nodemap_modify --name $nm_trusted \ + --property trusted --value 1 || error "Setting trusted=1 failed" + + wait_nm_sync $nm_trusted trusted_nodemap + + # create and set ownership for fileset dir of "nm_tenant" + $run_as_trusted mkdir -p $fileset_subdir || + error "mkdir $fileset_subdir failed" + $run_as_trusted chown $((offset_start+ID0)) $fileset_subdir + + # remount clients for nodemap changes to take effect. + # This mounts the trusted nodemap (c0) and tenant nodemap (c1) + export FILESET=/ + for client in "${clients_arr[@]}"; do + zconf_umount_clients $client $MOUNT || + error "unable to umount client ${clients_arr[0]}" + zconf_mount_clients $client $MOUNT $MOUNT_OPTS || + error "unable to umount client ${clients_arr[0]}" + done + unset FILESET + wait_ssk +} + +setup_namespace_75a() { + # Assumes that variables from test_75a are set + setup_tfiles_75a() { + local tenant_file=$1 + local tenant_dir=$2 + local offset=$3 + $run_as_trusted echo "abc" > ${fileset_subdir}/$tenant_file || + error "echo $tenant_file failed" + $run_as_trusted mkdir -p ${fileset_subdir}/$tenant_dir || + error "mkdir $tenant_dir failed" + $run_as_trusted chmod 777 ${fileset_subdir}/$tenant_file \ + ${fileset_subdir}/$tenant_dir || + error "chmod 777 $tenant_file and $tenant_dir failed" + $run_as_trusted chown \ + $((offset+ID0)):$((offset+ID0)) \ + ${fileset_subdir}/$tenant_file \ + ${fileset_subdir}/$tenant_dir || + error "chown $tenant_file and $tenant_dir failed" + } + + # setup testfiles and testdirectories. *_trusted files/dirs are + # world-accessible, but become inaccessible once the id_check is enabled + $run_as_trusted echo "abc" > ${fileset_subdir}/$tfile_trusted || + error "echo $tfile_trusted failed" + $run_as_trusted mkdir ${fileset_subdir}/$tdir_trusted || + error "mkdir $tdir_trusted failed" + $run_as_trusted chmod 777 ${fileset_subdir}/$tdir_trusted \ + ${fileset_subdir}/$tfile_trusted || + error "chmod 777 $tdir_trusted failed" + + setup_tfiles_75a $tfile_tl $tdir_tl 100000 + setup_tfiles_75a $tfile_tenant $tdir_tenant $offset_start + setup_tfiles_75a $tfile_tr $tdir_tr 300000 + + # DoM files + $run_as_trusted $LFS setstripe -E 1M -L mdt \ + ${fileset_subdir}/${tfile_trusted}_dom || + error "setstripe ${tfile_trusted}_dom failed" + $run_as_trusted chmod 777 ${fileset_subdir}/${tfile_trusted}_dom || + error "chmod 777 ${tfile_trusted}_dom failed" + $run_as_trusted $LFS setstripe -E 1M -L mdt \ + ${fileset_subdir}/${tfile_tenant}_dom || + error "setstripe ${tfile_tenant}_dom failed" + $run_as_trusted chown \ + $((offset_start+ID0)):$((offset_start+ID0)) \ + ${fileset_subdir}/${tfile_tenant}_dom || + error "chown ${tfile_tenant}_dom failed" + + # create a file used in write tests + $run_as_trusted echo "def" > ${fileset_subdir}/$tf_write || + error "echo $tf_write failed" + $run_as_trusted chown \ + $((offset_start+ID0)):$((offset_start+ID0)) \ + ${fileset_subdir}/$tf_write || + error "chown $tf_write failed" +} + +cleanup_75a() { + do_nodes $(all_mdts_nodes) \ + $LCTL set_param mdt.*.enable_resource_id_check=0 || + error "disabling resource id check on MDTs failed" + + do_nodes $(all_osts_nodes) \ + $LCTL set_param obdfilter.*.enable_resource_id_check=0 || + error "disabling resource id check on OSTs failed" + + nodemap_test_cleanup + + for client in "${clients_arr[@]}"; do + zconf_umount_clients $client $MOUNT || + error "unable to umount client $client" + zconf_mount_clients $client $MOUNT $MOUNT_OPTS || + error "unable to umount client $client" + done + wait_ssk +} + +test_75a() { + local offset_start=200000 + local offset_limit=100000 + local nm_trusted="c0" + local nm_tenant="c1" + local fileset_nm="${tdir}/${nm_tenant}_dir" + local fileset_subdir="${DIR}/${fileset_nm}" + local tfile_trusted="testfile_trusted" + local tfile_tenant="testfile_tenant" + local tdir_trusted="testdir_trusted" + local tdir_tenant="testdir_tenant" + # *_tl and *_tr files/dirs are set up such that their fs_ids are to the + # left and right of the tenant's offset range, respectively. This is to + # exercise both cases of nodemap_map_id() when mapping FS to client IDs. + local tfile_tl="testfile_tenant_left" + local tdir_tl="testdir_tenant_left" + local tfile_tr="testfile_tenant_right" + local tdir_tr="testdir_tenant_right" + local tf_write="testf_write" + local tf="testfile" + local client_trusted + local run_as_tenant + local out + + # This test checks that the enable_resource_id_check flag works + # correctly by having a tenant accessing squashed files. + # Without this check, tenants are able to access such files + # that have world-accessible permissions. + # With the flag enabled, this is no longer possible. + + # check that enable_resource_id_check flag exists + do_facet mds $LCTL get_param -n mdt.*.enable_resource_id_check || + skip "MDS does not have the enable_resource_id_check flag" + do_facet ost $LCTL get_param -n obdfilter.*.enable_resource_id_check || + skip "OSS does not have the enable_resource_id_check flag" + + # need two clients to continue + (( $CLIENTCOUNT >= 2 )) || skip "need at least two clients" + + if $SHARED_KEY; then + skip "need non-shared key for this test" + fi + + # assign clients and helper routines + client_trusted=${clients_arr[0]} + client_tenant=${clients_arr[1]} + run_as_tenant="do_node $client_tenant $RUNAS_CMD -u $ID0" + run_as_trusted="do_node $client_trusted" + + setup_75a + + do_nodes $(all_mdts_nodes) \ + $LCTL set_param mdt.*.enable_resource_id_check=0 || + error "disabling resource id check on MDTs failed" + + do_nodes $(all_osts_nodes) \ + $LCTL set_param obdfilter.*.enable_resource_id_check=0 || + error "disabling resource id check on OSTs failed" + + report_client_view_75a() { + echo "Trusted view:" + $run_as_trusted ls -al $fileset_subdir + echo "------------------------------" + echo "Tenant view:" + $run_as_tenant ls -al $MOUNT + } + + 75a_drop_tenant_cache() { + do_node $client_tenant \ + "sync ; echo 3 > /proc/sys/vm/drop_caches" + } + + 75a_op_test() { + local test_cmd="$run_as_tenant $1" + local test_success=${2:-true} + if $test_success; then + $test_cmd || error "$1 failed" + else + $test_cmd && error "$1 should've failed" + fi + } + + 75a_read_test() { + local test_cmd="$run_as_tenant $1" + local test_success=${2:-true} + local expected=${3:-"def"} + local out + if $test_success; then + out=$($test_cmd) || error "$1 failed" + echo $out + [[ $out == $expected ]] || + error "read $expected for $1 incorrect" + else + $test_cmd && error "$1 should've failed" + fi + } + + 75a_getxattr_test() { + local test_cmd="$run_as_tenant getfattr -n user.abc $1" + local test_success=${2:-true} + local expected=${3:-"\"def\""} + local out + if $test_success; then + out=$($test_cmd | awk -F'=' '/user.abc/ {print $2}') || + error "$1 failed" + echo $out + [[ $out == $expected ]] || + error "getxattr $expected for $1 incorrect" + else + $test_cmd && error "$1 should've failed" + fi + } + + # Setup testrun 1 + setup_namespace_75a + report_client_view_75a + # Testrun 1 begins (check disabled) + # 1. write to files + 75a_op_test "cp ${MOUNT}/$tf_write ${MOUNT}/$tfile_trusted" true + 75a_op_test "cp ${MOUNT}/$tf_write ${MOUNT}/$tfile_tl" true + 75a_op_test "cp ${MOUNT}/$tf_write ${MOUNT}/$tfile_tenant" true + 75a_op_test "cp ${MOUNT}/$tf_write ${MOUNT}/$tfile_tr" true + 75a_drop_tenant_cache + # 2. read from files + 75a_read_test "cat ${MOUNT}/$tfile_trusted" true + 75a_read_test "cat ${MOUNT}/$tfile_tl" true + 75a_read_test "cat ${MOUNT}/$tfile_tenant" true + 75a_read_test "cat ${MOUNT}/$tfile_tr" true + 75a_drop_tenant_cache + # 3. create files in various dirs + 75a_op_test "touch ${MOUNT}/${tdir_trusted}/$tf" true + 75a_op_test "touch ${MOUNT}/${tdir_tl}/$tf" true + 75a_op_test "touch ${MOUNT}/${tdir_tenant}/$tf" true + 75a_op_test "touch ${MOUNT}/${tdir_tr}/$tf" true + # 4. soft and hard links + 75a_op_test "ln ${MOUNT}/$tfile_trusted \ + ${MOUNT}/${tfile_trusted}_hlink" true + 75a_op_test "ln -s ${MOUNT}/$tfile_trusted \ + ${MOUNT}/${tfile_trusted}_slink" true + 75a_op_test "ln ${MOUNT}/$tfile_tl \ + ${MOUNT}/${tfile_tl}_hlink" true + 75a_op_test "ln -s ${MOUNT}/$tfile_tl \ + ${MOUNT}/${tfile_tl}_slink" true + 75a_op_test "ln ${MOUNT}/$tfile_tenant \ + ${MOUNT}/${tfile_tenant}_hlink" true + 75a_op_test "ln -s ${MOUNT}/$tfile_tenant \ + ${MOUNT}/${tfile_tenant}_slink" true + 75a_op_test "ln ${MOUNT}/$tfile_tr \ + ${MOUNT}/${tfile_tr}_hlink" true + 75a_op_test "ln -s ${MOUNT}/$tfile_tr \ + ${MOUNT}/${tfile_tr}_slink" true + 75a_read_test "cat ${MOUNT}/${tfile_trusted}_hlink" true + 75a_read_test "cat ${MOUNT}/${tfile_trusted}_slink" true + 75a_read_test "cat ${MOUNT}/${tfile_tl}_hlink" true + 75a_read_test "cat ${MOUNT}/${tfile_tl}_slink" true + 75a_read_test "cat ${MOUNT}/${tfile_tenant}_hlink" true + 75a_read_test "cat ${MOUNT}/${tfile_tenant}_slink" true + 75a_read_test "cat ${MOUNT}/${tfile_tr}_hlink" true + 75a_read_test "cat ${MOUNT}/${tfile_tr}_slink" true + 75a_op_test "rm ${MOUNT}/*_hlink" true + 75a_op_test "rm ${MOUNT}/*_slink" true + # 5. fallocate (zfs does not support pre-allocation via fallocate(2)) + if [[ "$ost1_FSTYPE" == "ldiskfs" ]]; then + 75a_op_test "fallocate -l 1M ${MOUNT}/$tfile_trusted" true + 75a_op_test "fallocate -l 1M ${MOUNT}/$tfile_tl" true + 75a_op_test "fallocate -l 1M ${MOUNT}/$tfile_tenant" true + 75a_op_test "fallocate -l 1M ${MOUNT}/$tfile_tr" true + fi + # 6. truncate + 75a_op_test "$TRUNCATE ${MOUNT}/$tfile_trusted 524288" true + 75a_op_test "$TRUNCATE ${MOUNT}/$tfile_tl 524288" true + 75a_op_test "$TRUNCATE ${MOUNT}/$tfile_tenant 524288" true + 75a_op_test "$TRUNCATE ${MOUNT}/$tfile_tr 524288" true + # 7. rename files (and back) + 75a_op_test "mv ${MOUNT}/$tfile_trusted ${MOUNT}/${tfile_trusted}_" true + 75a_op_test "mv ${MOUNT}/${tfile_trusted}_ ${MOUNT}/$tfile_trusted" true + 75a_op_test "mv ${MOUNT}/$tfile_tl ${MOUNT}/${tfile_tl}_" true + 75a_op_test "mv ${MOUNT}/${tfile_tl}_ ${MOUNT}/$tfile_tl" true + 75a_op_test "mv ${MOUNT}/$tfile_tenant ${MOUNT}/${tfile_tenant}_" true + 75a_op_test "mv ${MOUNT}/${tfile_tenant}_ ${MOUNT}/$tfile_tenant" true + 75a_op_test "mv ${MOUNT}/$tfile_tr ${MOUNT}/${tfile_tr}_" true + 75a_op_test "mv ${MOUNT}/${tfile_tr}_ ${MOUNT}/$tfile_tr" true + # 8. trigger setattr operation with "touch" (timestamp update) + 75a_op_test "touch ${MOUNT}/$tfile_trusted" true + 75a_op_test "touch ${MOUNT}/$tfile_tl" true + 75a_op_test "touch ${MOUNT}/$tfile_tenant" true + 75a_op_test "touch ${MOUNT}/$tfile_tr" true + # 9. xattr, set and get + 75a_op_test "setfattr -n user.abc -v def ${MOUNT}/$tfile_trusted" true + 75a_op_test "setfattr -n user.abc -v def ${MOUNT}/$tfile_tl" true + 75a_op_test "setfattr -n user.abc -v def ${MOUNT}/$tfile_tenant" true + 75a_op_test "setfattr -n user.abc -v def ${MOUNT}/$tfile_tr" true + 75a_getxattr_test ${MOUNT}/$tfile_trusted true + 75a_getxattr_test ${MOUNT}/$tfile_tl true + 75a_getxattr_test ${MOUNT}/$tfile_tenant true + 75a_getxattr_test ${MOUNT}/$tfile_tr true + # 10. remove create files from tenant dirs + 75a_op_test "rm ${MOUNT}/${tdir_trusted}/$tf" true + 75a_op_test "rm ${MOUNT}/${tdir_tl}/$tf" true + 75a_op_test "rm ${MOUNT}/${tdir_tenant}/$tf" true + 75a_op_test "rm ${MOUNT}/${tdir_tr}/$tf" true + # 11. remove all tenant dirs + 75a_op_test "rmdir ${MOUNT}/$tdir_trusted" true + 75a_op_test "rmdir ${MOUNT}/$tdir_tl" true + 75a_op_test "rmdir ${MOUNT}/$tdir_tenant" true + 75a_op_test "rmdir ${MOUNT}/$tdir_tr" true + # 12. remove remaining tenant files from root + 75a_op_test "rm ${MOUNT}/$tfile_trusted" true + 75a_op_test "rm ${MOUNT}/$tfile_tl" true + 75a_op_test "rm ${MOUNT}/$tfile_tenant" true + 75a_op_test "rm ${MOUNT}/$tfile_tr" true + # 13. Data on MDT cases + if [[ "$mds1_FSTYPE" == "ldiskfs" ]]; then + 75a_op_test "fallocate -l 1M ${MOUNT}/${tfile_trusted}_dom" true + fi + 75a_op_test "$TRUNCATE ${MOUNT}/${tfile_trusted}_dom 524288" true + 75a_op_test "cp ${MOUNT}/$tf_write ${MOUNT}/${tfile_trusted}_dom" true + 75a_drop_tenant_cache + 75a_read_test "cat ${MOUNT}/${tfile_trusted}_dom" true + 75a_op_test "rm ${MOUNT}/${tfile_trusted}_dom" true + + if [[ "$mds1_FSTYPE" == "ldiskfs" ]]; then + 75a_op_test "fallocate -l 1M ${MOUNT}/${tfile_tenant}_dom" true + fi + 75a_op_test "$TRUNCATE ${MOUNT}/${tfile_tenant}_dom 524288" true + 75a_op_test "cp ${MOUNT}/$tf_write ${MOUNT}/${tfile_tenant}_dom" true + 75a_drop_tenant_cache + 75a_read_test "cat ${MOUNT}/${tfile_tenant}_dom" true + 75a_op_test "rm ${MOUNT}/${tfile_tenant}_dom" true + + report_client_view_75a + + do_nodes $(all_mdts_nodes) \ + $LCTL set_param mdt.*.enable_resource_id_check=1 || + error "enabling resource id check on MDTs failed" + + do_nodes $(all_osts_nodes) \ + $LCTL set_param obdfilter.*.enable_resource_id_check=1 || + error "enabling resource id check on OSTs failed" + + # Setup testrun 2 + setup_namespace_75a + report_client_view_75a + + # Testrun 2 begins (check enabled) + # 1. write to files + 75a_op_test "cp ${MOUNT}/$tf_write ${MOUNT}/$tfile_trusted" false + 75a_op_test "cp ${MOUNT}/$tf_write ${MOUNT}/$tfile_tl" false + 75a_op_test "cp ${MOUNT}/$tf_write ${MOUNT}/$tfile_tenant" true + 75a_op_test "cp ${MOUNT}/$tf_write ${MOUNT}/$tfile_tr" false + 75a_drop_tenant_cache + # 2. read from files + 75a_read_test "cat ${MOUNT}/$tfile_trusted" false + 75a_read_test "cat ${MOUNT}/$tfile_tl" false + 75a_read_test "cat ${MOUNT}/$tfile_tenant" true + 75a_read_test "cat ${MOUNT}/$tfile_tr" false + 75a_drop_tenant_cache + # 3. create files + 75a_op_test "touch ${MOUNT}/${tdir_trusted}/$tf" false + 75a_op_test "touch ${MOUNT}/${tdir_tl}/$tf" false + 75a_op_test "touch ${MOUNT}/${tdir_tenant}/$tf" true + 75a_op_test "touch ${MOUNT}/${tdir_tr}/$tf" false + # 4. soft and hard links (cannot create hard links but soft links) + 75a_op_test "ln ${MOUNT}/$tfile_trusted \ + ${MOUNT}/${tfile_trusted}_hlink" false + 75a_op_test "ln -s ${MOUNT}/$tfile_trusted \ + ${MOUNT}/${tfile_trusted}_slink" true + 75a_op_test "ln ${MOUNT}/$tfile_tl \ + ${MOUNT}/${tfile_tl}_hlink" false + 75a_op_test "ln -s ${MOUNT}/$tfile_tl \ + ${MOUNT}/${tfile_tl}_slink" true + 75a_op_test "ln ${MOUNT}/$tfile_tenant \ + ${MOUNT}/${tfile_tenant}_hlink" true + 75a_op_test "ln -s ${MOUNT}/$tfile_tenant \ + ${MOUNT}/${tfile_tenant}_slink" true + 75a_op_test "ln ${MOUNT}/$tfile_tr \ + ${MOUNT}/${tfile_tr}_hlink" false + 75a_op_test "ln -s ${MOUNT}/$tfile_tr \ + ${MOUNT}/${tfile_tr}_slink" true + # can only read soft-links pointing to permitted files + 75a_read_test "cat ${MOUNT}/${tfile_trusted}_slink" false + 75a_read_test "cat ${MOUNT}/${tfile_tl}_slink" false + 75a_read_test "cat ${MOUNT}/${tfile_tenant}_slink" true + 75a_read_test "cat ${MOUNT}/${tfile_tr}_slink" false + # can remove all links created by tenant + 75a_op_test "rm ${MOUNT}/${tfile_trusted}_slink" true + 75a_op_test "rm ${MOUNT}/${tfile_tl}_slink" true + 75a_op_test "rm ${MOUNT}/${tfile_tenant}_slink" true + 75a_op_test "rm ${MOUNT}/${tfile_tr}_slink" true + 75a_op_test "rm ${MOUNT}/${tfile_tenant}_hlink" true + # 5. fallocate (only on ldiskfs, zfs does not support pre-allocation) + if [[ "$ost1_FSTYPE" == "ldiskfs" ]]; then + 75a_op_test "fallocate -l 1M ${MOUNT}/$tfile_trusted" false + 75a_op_test "fallocate -l 1M ${MOUNT}/$tfile_tl" false + 75a_op_test "fallocate -l 1M ${MOUNT}/$tfile_tenant" true + 75a_op_test "fallocate -l 1M ${MOUNT}/$tfile_tr" false + fi + # 6. truncate + 75a_op_test "$TRUNCATE ${MOUNT}/$tfile_trusted 524288" false + 75a_op_test "$TRUNCATE ${MOUNT}/$tfile_tl 524288" false + 75a_op_test "$TRUNCATE ${MOUNT}/$tfile_tenant 524288" true + 75a_op_test "$TRUNCATE ${MOUNT}/$tfile_tr 524288" false + # 7. rename files (and back) + 75a_op_test "mv ${MOUNT}/$tfile_trusted \ + ${MOUNT}/${tfile_trusted}_" false + 75a_op_test "mv ${MOUNT}/$tfile_tl ${MOUNT}/${tfile_tl}_" false + 75a_op_test "mv ${MOUNT}/$tfile_tenant ${MOUNT}/${tfile_tenant}_" true + 75a_op_test "mv ${MOUNT}/${tfile_tenant}_ ${MOUNT}/$tfile_tenant" true + 75a_op_test "mv ${MOUNT}/$tfile_tr ${MOUNT}/${tfile_tr}_" false + # 8. trigger setattr operation with "touch" (timestamp update) + 75a_op_test "touch ${MOUNT}/$tfile_trusted" false + 75a_op_test "touch ${MOUNT}/$tfile_tl" false + 75a_op_test "touch ${MOUNT}/$tfile_tenant" true + 75a_op_test "touch ${MOUNT}/$tfile_tr" false + # 9. xattr, set and get + 75a_op_test "setfattr -n user.abc -v def ${MOUNT}/$tfile_trusted" false + 75a_op_test "setfattr -n user.abc -v def ${MOUNT}/$tfile_tl" false + 75a_op_test "setfattr -n user.abc -v def ${MOUNT}/$tfile_tenant" true + 75a_op_test "setfattr -n user.abc -v def ${MOUNT}/$tfile_tr" false + 75a_getxattr_test ${MOUNT}/$tfile_trusted false + 75a_getxattr_test ${MOUNT}/$tfile_tl false + 75a_getxattr_test ${MOUNT}/$tfile_tenant true + 75a_getxattr_test ${MOUNT}/$tfile_tr false + # 10. remove create files from tenant dirs + 75a_op_test "rm ${MOUNT}/${tdir_tenant}/$tf" true + # 11. attempt to remove all tenant dirs + 75a_op_test "rmdir ${MOUNT}/$tdir_trusted" false + 75a_op_test "rmdir ${MOUNT}/$tdir_tl" false + 75a_op_test "rmdir ${MOUNT}/$tdir_tenant" true + 75a_op_test "rmdir ${MOUNT}/$tdir_tr" false + # 12. attempt to remove remaining tenant files from root + 75a_op_test "rm ${MOUNT}/$tfile_trusted" false + 75a_op_test "rm ${MOUNT}/$tfile_tl" false + 75a_op_test "rm ${MOUNT}/$tfile_tenant" true + 75a_op_test "rm ${MOUNT}/$tfile_tr" false + # 13. Data on MDT cases + if [[ "$mds1_FSTYPE" == "ldiskfs" ]]; then + 75a_op_test "fallocate -l 1M ${MOUNT}/${tfile_trusted}_dom" \ + false + fi + 75a_op_test "$TRUNCATE ${MOUNT}/${tfile_trusted}_dom 524288" false + 75a_op_test "cp ${MOUNT}/$tf_write ${MOUNT}/${tfile_trusted}_dom" false + 75a_read_test "cat ${MOUNT}/${tfile_trusted}_dom" false + 75a_op_test "rm ${MOUNT}/${tfile_trusted}_dom" false + + if [[ "$mds1_FSTYPE" == "ldiskfs" ]]; then + 75a_op_test "fallocate -l 1M ${MOUNT}/${tfile_tenant}_dom" true + fi + 75a_op_test "$TRUNCATE ${MOUNT}/${tfile_tenant}_dom 524288" true + 75a_op_test "cp ${MOUNT}/$tf_write ${MOUNT}/${tfile_tenant}_dom" true + 75a_drop_tenant_cache + 75a_read_test "cat ${MOUNT}/${tfile_tenant}_dom" true + 75a_op_test "rm ${MOUNT}/${tfile_tenant}_dom" true + + report_client_view_75a +} +run_test 75a "test resource fs IDs against nodemap offset" + cleanup_76() { # unmount client if is_mounted $MOUNT; then -- 1.8.3.1