#define LQUOTA_FLAG_DEFAULT 0x0001
#define LQUOTA_FLAG_DELETED 0x0002
#define LQUOTA_FLAG_RESET 0x0004
+#define LQUOTA_FLAG_REVOKE 0x0008
#define LUSTRE_Q_CMD_IS_POOL(cmd) \
(cmd == LUSTRE_Q_GETQUOTAPOOL || \
lqe_is_default:1, /* the default quota is used */
lqe_is_global:1, /* lqe belongs to global pool "0x0"*/
lqe_is_deleted:1, /* lqe will be deleted soon */
- lqe_is_reset:1; /* lqe has been reset */
+ lqe_is_reset:1, /* lqe has been reset */
+ lqe_revoke:1; /* all extra grant will be revoked */
/* the lock to protect lqe_glbl_data */
struct mutex lqe_glbl_data_lock;
qti->qti_gl_desc.lquota_desc.gl_softlimit = lqe->lqe_softlimit;
qti->qti_gl_desc.lquota_desc.gl_time = LQUOTA_GRACE_FLAG(0,
LQUOTA_FLAG_RESET);
+ } else if (lqe->lqe_granted > lqe->lqe_hardlimit) {
+ qti->qti_gl_desc.lquota_desc.gl_hardlimit = lqe->lqe_hardlimit;
+ qti->qti_gl_desc.lquota_desc.gl_softlimit = lqe->lqe_softlimit;
+ qti->qti_gl_desc.lquota_desc.gl_time = LQUOTA_GRACE_FLAG(0,
+ LQUOTA_FLAG_REVOKE);
} else {
qti->qti_gl_desc.lquota_desc.gl_hardlimit = lqe->lqe_hardlimit;
qti->qti_gl_desc.lquota_desc.gl_softlimit = lqe->lqe_softlimit;
struct qsd_qtype_info *qqi = (struct qsd_qtype_info *)arg;
libcfs_debug_msg(msgdata,
- "%pV qsd:%s qtype:%s id:%llu enforced:%d granted: %llu pending:%llu waiting:%llu req:%d usage: %llu qunit:%llu qtune:%llu edquot:%d default:%s\n",
+ "%pV qsd:%s qtype:%s id:%llu enforced:%d granted: %llu pending:%llu waiting:%llu req:%d usage: %llu qunit:%llu qtune:%llu edquot:%d default:%s revoke:%d\n",
vaf,
qqi->qqi_qsd->qsd_svname, qtype_name(qqi->qqi_qtype),
lqe->lqe_id.qid_uid, lqe->lqe_enforced,
lqe->lqe_granted, lqe->lqe_pending_write,
lqe->lqe_waiting_write, lqe->lqe_pending_req,
lqe->lqe_usage, lqe->lqe_qunit, lqe->lqe_qtune,
- lqe->lqe_edquot, lqe->lqe_is_default ? "yes" : "no");
+ lqe->lqe_edquot, lqe->lqe_is_default ? "yes" : "no",
+ lqe->lqe_revoke);
}
/*
/* valid per-ID lock
* Apply good old quota qunit adjustment logic which has been around
* since lustre 1.4:
- * 1. release spare quota space? */
+ * 1. revoke all extra grant
+ */
+ if (lqe->lqe_revoke) {
+ lqe->lqe_revoke = 0;
+
+ LQUOTA_DEBUG(lqe, "revoke pre-acquired quota: %llu - %llu\n",
+ granted, usage);
+ qbody->qb_count = granted - usage;
+ qbody->qb_flags = QUOTA_DQACQ_FL_REL;
+ RETURN(true);
+ }
+
+ /* 2. release spare quota space? */
if (granted > usage + lqe->lqe_qunit) {
/* pre-release quota space */
if (qbody == NULL)
RETURN(true);
}
- /* 2. Any quota overrun? */
+ /* 3. Any quota overrun? */
if (lqe->lqe_usage > lqe->lqe_granted) {
/* we overconsumed quota space, we report usage in request so
* that master can adjust it unconditionally */
qbody->qb_flags = QUOTA_DQACQ_FL_REPORT;
}
- /* 3. Time to pre-acquire? */
+ /* 4. Time to pre-acquire? */
if (!lqe->lqe_edquot && !lqe->lqe_nopreacq && usage > 0 &&
lqe->lqe_qunit != 0 && granted < usage + lqe->lqe_qtune) {
/* To pre-acquire quota space, we report how much spare quota
qsd_set_edquot(lqe, !!(desc->gl_flags & LQUOTA_FL_EDQUOT));
lqe_write_unlock(lqe);
+ if (!!(desc->gl_flags & LQUOTA_FL_EDQUOT))
+ qsd_adjust_schedule(lqe, false, false);
+
if (wakeup)
wake_up(&lqe->lqe_waiters);
lqe_putref(lqe);
lqe->lqe_adjust_time = 0;
spin_unlock(&qsd->qsd_adjust_lock);
+ if (LQUOTA_FLAG(upd->qur_rec.lqr_glb_rec.qbr_time) &
+ LQUOTA_FLAG_REVOKE)
+ lqe->lqe_revoke = 1;
+
/* Report usage asynchronously */
rc = qsd_adjust(env, lqe);
+ lqe->lqe_revoke = 0;
if (rc)
LQUOTA_ERROR(lqe, "failed to report usage, rc:%d", rc);
}
get_quota_on_qsd() {
local facet
+ local device
local spec
local qid
local qtype
local output
facet=$1
- case "$2" in
+ device=$2
+ case "$3" in
usr) qtype="limit_user";;
grp) qtype="limit_group";;
- *) error "unknown quota parameter $2";;
+ prj) qtype="limit_project";;
+ *) error "unknown quota parameter $3";;
esac
- qid=$3
- case "$4" in
+ qid=$4
+ case "$5" in
hardlimit) spec=4;;
softlimit) spec=6;;
- *) error "unknown quota parameter $4";;
+ *) error "unknown quota parameter $5";;
esac
- do_facet $facet $LCTL get_param osd-*.*-OST0000.quota_slave.$qtype |
+ do_facet $facet $LCTL get_param osd-*.*-${device}.quota_slave.$qtype |
awk '($3 == '$qid') {getline; print $'$spec'; exit;}' | tr -d ,
}
-wait_quota_setting_synced() {
+wait_quota_synced() {
local value
- local qtype=$1
- local qid=$2
- local limit_type=$3
- local limit_val=$4
+ local facet=$1
+ local device=$2
+ local qtype=$3
+ local qid=$4
+ local limit_type=$5
+ local limit_val=$6
local interval=0
- value=$(get_quota_on_qsd ost1 $qtype $qid $limit_type)
+ value=$(get_quota_on_qsd $facet $device $qtype $qid $limit_type)
while [[ $value != $limit_val ]]; do
(( interval != 0 )) ||
- do_facet ost1 $LCTL set_param \
- osd-*.*-OST0000.quota_slave.force_reint=1
+ do_facet $facet $LCTL set_param \
+ osd-*.*-${device}.quota_slave.force_reint=1
+ echo $value
(( interval <= 20 )) ||
error "quota ($value) don't update on QSD, $limit_val"
interval=$((interval + 1))
sleep 1
- value=$(get_quota_on_qsd ost1 $qtype $qid $limit_type)
+ value=$(get_quota_on_qsd $facet $device $qtype $qid $limit_type)
done
}
error "set user quota failed"
$LFS quota -gv $TSTUSR $DIR
- wait_quota_setting_synced "grp" $TSTID "hardlimit" $((10*1024*1024))
+ wait_quota_synced "ost1" "OST0000" "grp" $TSTID "hardlimit" "10485760"
mkdir -p $dir1 || error "failed to mkdir"
chown $TSTUSR.$TSTUSR $dir1 || error "chown $dir1 failed"
}
run_test 85 "do not hung at write with the least_qunit"
+test_preacquired_quota()
+{
+ local test_dir=$1
+ local qtype=$2
+ local qtype_name=$3
+ local qid=$4
+
+ [[ "$qtype" == "-p" ]] && change_project -sp $qid $DIR/$tdir
+
+ $LFS setquota $qtype $qid -i 100K -I 100K $DIR ||
+ error "failed to set file [$qtype] quota"
+
+ $RUNAS createmany -m $test_dir/tfile- 5000 ||
+ error "failed to create files, expect succeed"
+
+ wait_zfs_commit $SINGLEMDS
+ $LFS setquota $qtype $qid -i 2K -I 2K $DIR ||
+ error "failed to decrease file [$qtype] quota"
+
+ wait_quota_synced "mds1" "MDT0000" $qtype_name $qid "hardlimit" "2048"
+
+ # make sure the lqe->lqe_edquot is set
+ $RUNAS createmany -m $test_dir/tfile2- 10
+ sleep 5
+
+ $RUNAS createmany -m $test_dir/tfile3- 30 &&
+ error "succeed to create files, expect failed"
+
+ rm -f $test_dir/tfile*
+ $LFS setquota $qtype $qid -i 0 -I 0 $DIR ||
+ error "failed to reset file user quota"
+}
+
+test_86()
+{
+ (( $MDS1_VERSION >= $(version_code 2.15.57.41) )) ||
+ skip "need MDS >= 2.15.57.41 for quota over limit release fix"
+
+ local test_dir="$DIR/$tdir/test_dir"
+
+ setup_quota_test || error "setup quota failed with %?"
+ set_mdt_qtype $QTYPE || error "enable mdt quota failed"
+
+ $LFS setdirstripe -c 1 -i 0 $test_dir || error "setdirstripe failed"
+ chmod 777 $test_dir
+
+ test_preacquired_quota "$test_dir" "-u" "usr" "$TSTID"
+ test_preacquired_quota "$test_dir" "-g" "grp" "$TSTID"
+
+ is_project_quota_supported || return 0
+ test_preacquired_quota "$test_dir" "-p" "prj" "1000"
+}
+run_test 86 "Pre-acquired quota should be released if quota is over limit"
+
quota_fini()
{
do_nodes $(comma_list $(nodes_list)) \