Whamcloud - gitweb
LU-16988 mdd: update projid when merging layout
authorHongchao Zhang <hongchao@whamcloud.com>
Mon, 14 Aug 2023 07:28:17 +0000 (15:28 +0800)
committerAndreas Dilger <adilger@whamcloud.com>
Mon, 11 Sep 2023 00:22:38 +0000 (00:22 +0000)
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.

Lustre-change: https://review.whamcloud.com/51859
Lustre-commit: bb2525b0ddf9190ae340552fa615833b735b61d3

Signed-off-by: Hongchao Zhang <hongchao@whamcloud.com>
Change-Id: Ia4c3a8973b8c467642e12629d36fa42d64162084
Reviewed-by: Sergey Cheremencev <scherementsev@ddn.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-on: https://review.whamcloud.com/c/ex/lustre-release/+/52303
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
lustre/mdd/mdd_object.c
lustre/tests/sanity-quota.sh
lustre/utils/lfs.c

index 81d8131..e3c0b29 100644 (file)
@@ -1614,9 +1614,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);
@@ -1625,6 +1638,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);
@@ -1667,6 +1686,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_LUSTRE_LOV, LU_XATTR_MERGE,
                           handle);
        if (rc)
index 5e26d3f..57e0777 100755 (executable)
@@ -4117,6 +4117,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.14.0.101) )) ||
+               skip "need MDS 2.14.0.101 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"
index 7c8f5f7..91069da 100644 (file)
@@ -11240,10 +11240,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;
        }