From bb2525b0ddf9190ae340552fa615833b735b61d3 Mon Sep 17 00:00:00 2001 From: Hongchao Zhang Date: Mon, 14 Aug 2023 15:28:17 +0800 Subject: [PATCH] LU-16988 mdd: update projid when merging layout When creating mirrors by the special directory ".lustre/fid", the project ID could not be set correctly, which causes wrong quota calculation for the projid. Signed-off-by: Hongchao Zhang Change-Id: Ia4c3a8973b8c467642e12629d36fa42d64162084 Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/51859 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Sergey Cheremencev Reviewed-by: Andreas Dilger Reviewed-by: Oleg Drokin --- lustre/mdd/mdd_object.c | 26 ++++++++++++ lustre/tests/sanity-quota.sh | 99 ++++++++++++++++++++++++++++++++++++++++++++ lustre/utils/lfs.c | 8 ++-- 3 files changed, 130 insertions(+), 3 deletions(-) diff --git a/lustre/mdd/mdd_object.c b/lustre/mdd/mdd_object.c index ec44594..698b27b 100644 --- a/lustre/mdd/mdd_object.c +++ b/lustre/mdd/mdd_object.c @@ -1618,9 +1618,22 @@ static int mdd_xattr_merge(const struct lu_env *env, struct md_object *md_obj, struct lu_buf *buf_vic = &mdd_env_info(env)->mdi_buf[1]; struct lov_mds_md *lmm; struct thandle *handle; + struct lu_attr *cattr = MDD_ENV_VAR(env, cattr); + struct lu_attr *tattr = MDD_ENV_VAR(env, tattr); + bool is_same_projid; int rc, lock_order; ENTRY; + rc = mdd_la_get(env, obj, cattr); + if (rc) + RETURN(rc); + + rc = mdd_la_get(env, vic, tattr); + if (rc) + RETURN(rc); + + is_same_projid = cattr->la_projid == tattr->la_projid; + lock_order = lu_fid_cmp(mdd_object_fid(obj), mdd_object_fid(vic)); if (lock_order == 0) /* same fid */ RETURN(-EPERM); @@ -1629,6 +1642,12 @@ static int mdd_xattr_merge(const struct lu_env *env, struct md_object *md_obj, if (IS_ERR(handle)) RETURN(PTR_ERR(handle)); + if (!is_same_projid) { + rc = mdd_declare_attr_set(env, mdd, vic, cattr, handle); + if (rc) + GOTO(stop, rc); + } + /* get EA of victim file */ memset(buf_vic, 0, sizeof(*buf_vic)); rc = mdd_stripe_get(env, vic, buf_vic, XATTR_NAME_LOV); @@ -1671,6 +1690,13 @@ static int mdd_xattr_merge(const struct lu_env *env, struct md_object *md_obj, mdd_write_lock(env, obj, DT_TGT_CHILD); } + if (!is_same_projid) { + cattr->la_valid = LA_PROJID; + rc = mdd_attr_set_internal(env, vic, cattr, handle, 0); + if (rc) + GOTO(out, rc); + } + rc = mdo_xattr_set(env, obj, buf_vic, XATTR_NAME_LOV, LU_XATTR_MERGE, handle); if (rc) diff --git a/lustre/tests/sanity-quota.sh b/lustre/tests/sanity-quota.sh index 7433943..c2a903a 100755 --- a/lustre/tests/sanity-quota.sh +++ b/lustre/tests/sanity-quota.sh @@ -4211,6 +4211,105 @@ test_57() { } run_test 57 "lfs project could tolerate errors" +# LU-16988 +test_mirror() +{ + local projid=$1 + local testfile=$2 + local mirrorfile=$3 + + # create mirror + $LFS mirror extend -N2 $mirrorfile || error "failed to create mirror" + + local mirrors=$($LFS getstripe -N $testfile) + [[ $mirrors == 3 ]] || error "mirror count $mirrors is wrong" + + cancel_lru_locks osc + cancel_lru_locks mdc + sync; sync_all_data || true + + local prev_usage=$(getquota -p $projid global curspace) + + $RUNAS $DD of=$testfile count=50 conv=nocreat oflag=direct || + quota_error p $projid "write failed, expect succeed" + + cancel_lru_locks osc + cancel_lru_locks mdc + sync; sync_all_data || true + + $RUNAS $LFS mirror resync $testfile || error "failed to resync mirror" + + local usage=$(getquota -p $projid global curspace) + (( usage >= prev_usage + 150*1024 )) || + error "project quota $usage is wrong" + + $RUNAS $DD of=$testfile count=30 conv=nocreat seek=50 oflag=direct || + quota_error p $projid "write failed, expect succeed" + + $RUNAS $LFS mirror resync $testfile && + error "resync mirror succeed, expect EDQUOT" + + $LFS mirror delete --mirror-id 2 $testfile || + error "failed to delete the second mirror" + $LFS mirror delete --mirror-id 3 $testfile || + error "failed to delete the third mirror" +} + +test_58() { + (( $MDS1_VERSION >= $(version_code 2.15.56) )) || + skip "need MDS 2.15.56 or later" + + is_project_quota_supported || skip "Project quota is not supported" + + local testdir="$DIR/$tdir" + local testfile="$DIR/$tdir/$tfile" + local projid=1000 + local projid2=1001 + + setup_quota_test || error "setup quota failed with $?" + + USED=$(getquota -p $projid global curspace) + [ $USED -ne 0 ] && error "Used space ($USED) for proj $projid isn't 0" + + USED=$(getquota -p $projid2 global curspace) + [ $USED -ne 0 ] && error "Used space ($USED) for proj $projid2 isn't 0" + + chown $TSTUSR.$TSTUSR $testdir || error "chown $testdir failed" + quota_init + set_ost_qtype ugp || error "enable ost quota failed" + + $LFS project -sp $projid $testdir || error "failed to set project ID" + $LFS setquota -p $projid -B 200M $DIR || + error "failed to to set prj $projid quota" + + $RUNAS touch $testfile + + local id=$(lfs project -d $testfile | awk '{print $1}') + [ "$id" != "$projid" ] && error "projid $projid is not inherited $id" + + echo "test by mirror created with normal file" + test_mirror $projid $testfile $testfile + + $TRUNCATE $testfile 0 + wait_delete_completed || error "wait_delete_completed failed" + sync_all_data || true + + $LFS project -sp $projid2 $testdir || + error "failed to set directory project ID" + $LFS project -p $projid2 $testfile || + error "failed to set file project ID" + $LFS setquota -p $projid -b 0 -B 0 $DIR || + error "failed to to reset prj quota" + $LFS setquota -p $projid2 -B 200M $DIR || + error "failed to to set prj $projid2 quota" + + local fid=$($LFS path2fid $testfile) + + echo "test by mirror created with FID" + test_mirror $projid2 $testfile $MOUNT/.lustre/fid/$fid +} +run_test 58 "project ID should be kept for new mirrors created by FID" + test_59() { [ "$mds1_FSTYPE" != ldiskfs ] && skip "ldiskfs only test" diff --git a/lustre/utils/lfs.c b/lustre/utils/lfs.c index 92de965..f3f8101 100644 --- a/lustre/utils/lfs.c +++ b/lustre/utils/lfs.c @@ -11470,10 +11470,12 @@ int lfs_mirror_resync_file(const char *fname, struct ll_ioc_lease *ioc, fprintf(stderr, "%s: '%s' llapi_mirror_resync_many: %s.\n", progname, fname, strerror(-rc)); - rc = migrate_set_timestamps(fd, &stbuf); - if (rc < 0) { + rc2 = migrate_set_timestamps(fd, &stbuf); + if (rc2 < 0) { fprintf(stderr, "%s: '%s' cannot set timestamps: %s\n", - progname, fname, strerror(-rc)); + progname, fname, strerror(-rc2)); + if (!rc) + rc = rc2; goto free_layout; } -- 1.8.3.1