.TP
.BR "lfs setquota " { -u | --user | -g | --group | -p | --projid "} " \fIUID\fR|\fIGID\fR|\fIPROJID\fR
[\fB--delete\fR] <\fIfilesystem\fR>
+.BR "lfs setquota " { -u | --user | -g | --group | -p | --projid "} " \fIUID\fR|\fIGID\fR|\fIPROJID\fR
+ [\fB-r\fR] <\fIfilesystem\fR>
.TP
.SH DESCRIPTION
.TP
.B --pool \fIPOOL_NAME\fR
Set quota per OST pool \fIPOOL_NAME\fR.
.TP
+.BR -r
+Reset the internal quota data of the user|group|project quota. It can be used
+to fix the quota containing corrupted internal data (such as, the quota grant).
+.TP
.BR -u | --user \fIUSERNAME\fR|\fBUID
Set user quota for \fIUNAME\fR or \fIUID\fR.
.PP
.TP
.B $ lfs setquota -u bob --delete /mnt/lustre
Delete unused user 'bob'.
+.TP
+.B $ lfs setquota -u bob -r /mnt/lustre
+Reset the user 'bob'.
.SH SEE ALSO
.BR lfs (1),
.BR lfs-quota(1)
#define OBD_FAIL_QUOTA_INIT 0xA05
#define OBD_FAIL_QUOTA_PREACQ 0xA06
#define OBD_FAIL_QUOTA_RECALC 0xA07
+#define OBD_FAIL_QUOTA_GRANT 0xA08
#define OBD_FAIL_LPROC_REMOVE 0xB00
#define LUSTRE_Q_GETDEFAULT_POOL 0x800013 /* get default pool quota*/
#define LUSTRE_Q_SETDEFAULT_POOL 0x800014 /* set default pool quota */
#define LUSTRE_Q_DELETEQID 0x800015 /* delete quota ID */
+#define LUSTRE_Q_RESETQID 0x800016 /* reset quota ID */
/* In the current Lustre implementation, the grace time is either the time
* or the timestamp to be used after some quota ID exceeds the soft limt,
* 48 bits should be enough, its high 16 bits can be used as quota flags.
* */
#define LQUOTA_FLAG_DEFAULT 0x0001
#define LQUOTA_FLAG_DELETED 0x0002
+#define LQUOTA_FLAG_RESET 0x0004
#define LUSTRE_Q_CMD_IS_POOL(cmd) \
(cmd == LUSTRE_Q_GETQUOTAPOOL || \
case LUSTRE_Q_SETINFOPOOL:
case LUSTRE_Q_SETDEFAULT_POOL:
case LUSTRE_Q_DELETEQID:
+ case LUSTRE_Q_RESETQID:
if (!capable(CAP_SYS_ADMIN))
RETURN(-EPERM);
case LUSTRE_Q_SETINFOPOOL:
case LUSTRE_Q_SETDEFAULT_POOL:
case LUSTRE_Q_DELETEQID:
+ case LUSTRE_Q_RESETQID:
if (!nodemap_can_setquota(nodemap, oqctl->qc_type,
oqctl->qc_id))
GOTO(out_nodemap, rc = -EPERM);
case LUSTRE_Q_SETDEFAULT_POOL:
case LUSTRE_Q_GETDEFAULT_POOL:
case LUSTRE_Q_DELETEQID:
+ case LUSTRE_Q_RESETQID:
/* forward quotactl request to QMT */
rc = qmt_hdls.qmth_quotactl(tsi->tsi_env, qmt, oqctl);
break;
lqe_nopreacq:1, /* pre-acquire disabled */
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_deleted:1, /* lqe will be deleted soon */
+ lqe_is_reset:1; /* lqe has been reset */
/* the lock to protect lqe_glbl_data */
struct mutex lqe_glbl_data_lock;
(LQUOTA_FLAG(qti->qti_glb_rec.qbr_time) &
LQUOTA_FLAG_DEFAULT))
qmt_lqe_set_default(env, pool, lqe, false);
+ else if (LQUOTA_FLAG(qti->qti_glb_rec.qbr_time) &
+ LQUOTA_FLAG_RESET)
+ lqe->lqe_is_reset = true;
break;
default:
LQUOTA_ERROR(lqe, "failed to read quota entry from disk, rc:%d",
rec->qbr_softlimit = 0;
rec->qbr_time = LQUOTA_GRACE_FLAG(lqe->lqe_gracetime,
LQUOTA_FLAG_DEFAULT);
+ } else if (lqe->lqe_is_reset) {
+ rec->qbr_hardlimit = 0;
+ rec->qbr_softlimit = 0;
+ rec->qbr_granted = 0;
+ rec->qbr_time = LQUOTA_GRACE_FLAG(lqe->lqe_gracetime,
+ LQUOTA_FLAG_RESET);
} else {
rec->qbr_hardlimit = lqe->lqe_hardlimit;
rec->qbr_softlimit = lqe->lqe_softlimit;
RETURN(PTR_ERR(lqe));
lqe->lqe_is_deleted = 0;
+ lqe->lqe_is_reset = 0;
rc = qmt_set_with_lqe(env, qmt, lqe, hard, soft, time, valid,
is_default, is_updated);
if (rc == 0)
RETURN(rc);
}
+static int qmt_reset_slv_cb(const struct lu_env *env, struct lu_fid *glb_fid,
+ char *slv_name, struct lu_fid *slv_fid, void *arg)
+{
+ struct qmt_device *qmt = (struct qmt_device *)arg;
+ struct qmt_thread_info *qti = qmt_info(env);
+ struct dt_object *slv_obj = NULL;
+ struct lquota_slv_rec rec;
+ struct thandle *th = NULL;
+ int rc;
+
+ slv_obj = dt_locate(env, qmt->qmt_child, slv_fid);
+ if (IS_ERR(slv_obj))
+ GOTO(out, rc = PTR_ERR(slv_obj));
+
+ if (slv_obj->do_index_ops == NULL) {
+ rc = slv_obj->do_ops->do_index_try(env, slv_obj,
+ &dt_quota_slv_features);
+ if (rc) {
+ CERROR("%s: fail to setup slave idx for %s: rc = %d\n",
+ qmt->qmt_child->dd_lu_dev.ld_obd->obd_name,
+ slv_name, rc);
+ GOTO(out, rc);
+ }
+ }
+
+ th = qmt_trans_start(env, qti_lqes(env)[0]);
+ if (IS_ERR(th))
+ GOTO(out, rc = PTR_ERR(th));
+
+ rec.qsr_granted = 0;
+ rc = lquota_disk_write(env, th, slv_obj, &qti->qti_id,
+ (struct dt_rec *)&rec, 0, NULL);
+ if (rc)
+ CERROR("%s: failed to reset slave grant for %s: rc = %d\n",
+ qmt->qmt_child->dd_lu_dev.ld_obd->obd_name, slv_name,
+ rc);
+out:
+ if (!IS_ERR_OR_NULL(th))
+ dt_trans_stop(env, qmt->qmt_child, th);
+
+ if (slv_obj != NULL)
+ dt_object_put(env, slv_obj);
+ return 0;
+}
+
+/*
+ * Reset the quota of the quota ID, it will reset the soft/hard limit and grant
+ *
+ * \param env - is the environment passed by the caller
+ * \param qmt - is the quota master target
+ * \param restype - is the pool type, either block (i.e. LQUOTA_RES_DT) or
+ * inode (i.e. LQUOTA_RES_MD)
+ * \param qtype - is the quota type
+ * \param qid - is the quota indentifier for which we want to delete its
+ * quota settings.
+ */
+static int qmt_reset_qid(const struct lu_env *env, struct qmt_device *qmt,
+ __u8 restype, __u8 qtype, __u64 qid)
+{
+ struct qmt_thread_info *qti = qmt_info(env);
+ union lquota_id *quota_id = &qti->qti_id;
+ struct qmt_pool_info *qpi = NULL;
+ struct lquota_entry *lqe = NULL;
+ struct thandle *th = NULL;
+ __u64 softlimit = 0, hardlimit = 0;
+ __u64 ver = 0;
+ int rc;
+
+ ENTRY;
+
+ quota_id->qid_uid = qid;
+ lqe = qmt_pool_lqe_lookup(env, qmt, restype, qtype, quota_id, NULL);
+ if (IS_ERR(lqe))
+ RETURN(PTR_ERR(lqe));
+
+ lqe_write_lock(lqe);
+
+ qpi = qmt_pool_lookup_glb(env, qmt, restype);
+ if (IS_ERR(qpi))
+ GOTO(out, rc = -ENOMEM);
+
+ th = qmt_trans_start(env, lqe);
+ if (IS_ERR(th))
+ GOTO(out, rc = PTR_ERR(th));
+
+ softlimit = lqe->lqe_softlimit;
+ hardlimit = lqe->lqe_hardlimit;
+
+ lqe->lqe_softlimit = 0;
+ lqe->lqe_hardlimit = 0;
+ lqe->lqe_granted = 0;
+ lqe->lqe_edquot = 0;
+ lqe->lqe_qunit = 0;
+ lqe->lqe_is_default = 0;
+ lqe->lqe_is_deleted = 0;
+ lqe->lqe_is_reset = 1;
+ rc = qmt_glb_write(env, th, lqe, LQUOTA_BUMP_VER, &ver);
+ if (rc)
+ LQUOTA_ERROR(lqe, "failed to write quota global rec\n");
+ dt_trans_stop(env, qmt->qmt_child, th);
+ if (rc)
+ GOTO(out, rc);
+
+ lquota_generate_fid(&qti->qti_fid, restype, qtype);
+ qti_lqes(env)[0] = lqe;
+ lquota_disk_for_each_slv(env, qpi->qpi_root, &qti->qti_fid,
+ qmt_reset_slv_cb, qmt);
+
+ qmt_glb_lock_notify(env, lqe, ver);
+
+out:
+ if (rc) {
+ if (softlimit != 0)
+ lqe->lqe_softlimit = softlimit;
+ if (hardlimit != 0)
+ lqe->lqe_hardlimit = hardlimit;
+ lqe->lqe_is_reset = 0;
+ }
+
+ if (!IS_ERR_OR_NULL(qpi))
+ qpi_putref(env, qpi);
+
+ lqe_write_unlock(lqe);
+ lqe_putref(lqe);
+
+ RETURN(rc);
+}
/*
* Handle quotactl request.
*
oqctl->qc_id);
break;
+ case LUSTRE_Q_RESETQID:
+ if (oqctl->qc_id == 0)
+ RETURN(-EINVAL);
+
+ id->qid_uid = oqctl->qc_id;
+ /* save the quota setting before resetting */
+ rc = qmt_get(env, qmt, LQUOTA_RES_MD, oqctl->qc_type, id,
+ &dqb->dqb_ihardlimit, &dqb->dqb_isoftlimit,
+ &dqb->dqb_itime, false, NULL);
+ if (rc)
+ break;
+ else
+ dqb->dqb_valid |= QIF_ILIMITS | QIF_ITIME;
+
+ rc = qmt_get(env, qmt, LQUOTA_RES_DT, oqctl->qc_type, id,
+ &dqb->dqb_bhardlimit, &dqb->dqb_bsoftlimit,
+ &dqb->dqb_btime, false, NULL);
+ if (rc)
+ break;
+
+ dqb->dqb_valid |= QIF_BLIMITS | QIF_BTIME;
+ dqb->dqb_curinodes = 0;
+ dqb->dqb_curspace = 0;
+
+ /* reset the corresponding quota ID */
+ rc = qmt_reset_qid(env, qmt, LQUOTA_RES_MD, oqctl->qc_type,
+ oqctl->qc_id);
+ if (rc)
+ break;
+
+ rc = qmt_reset_qid(env, qmt, LQUOTA_RES_DT, oqctl->qc_type,
+ oqctl->qc_id);
+ break;
+
+
default:
CERROR("%s: unsupported quotactl command: %d\n",
qmt->qmt_svname, oqctl->qc_cmd);
return can_release;
}
-static inline void qmt_rel_lqes(const struct lu_env *env, __u64 *slv, __u64 cnt)
+static inline void qmt_rel_lqes(const struct lu_env *env, __u64 *slv, __u64 cnt,
+ bool reset)
{
int i;
- for (i = 0; i < qti_lqes_cnt(env); i++)
- qti_lqe_granted(env, i) -= cnt;
+ for (i = 0; i < qti_lqes_cnt(env); i++) {
+ if (reset)
+ qti_lqe_granted(env, i) = 0;
+ else
+ qti_lqe_granted(env, i) -= cnt;
+ }
- *slv -= cnt;
+ if (reset)
+ *slv = 0;
+ else
+ *slv -= cnt;
}
static inline bool qmt_lqes_cannot_grant(const struct lu_env *env, __u64 cnt)
struct obd_uuid *uuid, __u32 qb_flags, __u64 qb_count,
__u64 qb_usage, struct quota_body *repbody)
{
- __u64 now, count;
+ __u64 now, count = 0;
struct dt_object *slv_obj = NULL;
__u64 slv_granted, slv_granted_bck;
struct thandle *th = NULL;
if (req_is_acq(qb_flags) && qb_count == 0)
GOTO(out_locked, rc = 0);
+ if (lqe->lqe_is_reset) {
+ lqe->lqe_granted = 0;
+ repbody->qb_count = qb_count;
+ qmt_rel_lqes(env, &slv_granted, qb_count, lqe->lqe_is_reset);
+ GOTO(out_locked, rc = 0);
+ }
+
/* fetch how much quota space is already granted to this slave */
rc = qmt_slv_read(env, &lqe->lqe_id, slv_obj, &slv_granted);
if (rc) {
repbody->qb_count = qb_count;
/* put released space back to global pool */
- qmt_rel_lqes(env, &slv_granted, qb_count);
+ qmt_rel_lqes(env, &slv_granted, qb_count, lqe->lqe_is_reset);
GOTO(out_write, rc = 0);
}
/* start/stop grace timer if required */
qmt_lqes_tune_grace(env, now);
+ if (OBD_FAIL_CHECK(OBD_FAIL_QUOTA_GRANT))
+ slv_granted = 0xFFFFFFFFFFF00000;
+
/* Update slave index first since it is easier to roll back */
ret = qmt_slv_write(env, th, lqe, slv_obj, LQUOTA_BUMP_VER,
&repbody->qb_slv_ver, slv_granted);
qti->qti_gl_desc.lquota_desc.gl_softlimit = 0;
qti->qti_gl_desc.lquota_desc.gl_time = LQUOTA_GRACE_FLAG(0,
LQUOTA_FLAG_DELETED);
+ } else if (lqe->lqe_is_reset) {
+ 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_RESET);
} else {
qti->qti_gl_desc.lquota_desc.gl_hardlimit = lqe->lqe_hardlimit;
qti->qti_gl_desc.lquota_desc.gl_softlimit = lqe->lqe_softlimit;
}
if (lqe->lqe_id.qid_uid != 0 &&
+ (LQUOTA_FLAG(qti->qti_glb_rec.qbr_time) &
+ LQUOTA_FLAG_RESET))
+ lqe->lqe_is_reset = true;
+
+ if (lqe->lqe_id.qid_uid != 0 &&
(qti->qti_glb_rec.qbr_hardlimit != 0 ||
qti->qti_glb_rec.qbr_softlimit != 0))
lqe->lqe_enforced = true;
if (repbody != NULL && repbody->qb_count != 0) {
LQUOTA_DEBUG(lqe, "DQACQ qb_count:%llu", repbody->qb_count);
- if (req_is_rel(reqbody->qb_flags)) {
+ if (lqe->lqe_is_reset) {
+ lqe->lqe_granted = 0;
+ } else if (req_is_rel(reqbody->qb_flags)) {
if (lqe->lqe_granted < repbody->qb_count) {
LQUOTA_ERROR(lqe, "can't release more space "
"than owned %llu<%llu",
* We don't update the version of slave index copy on DQACQ.
* No locking is necessary since nobody can change
* lqe->lqe_granted while lqe->lqe_pending_req > 0 */
+ if (OBD_FAIL_CHECK(OBD_FAIL_QUOTA_GRANT))
+ qti->qti_rec.lqr_slv_rec.qsr_granted =
+ 0xFFFFFFFFFFDEC80CULL;
qsd_upd_schedule(qqi, lqe, &lqe->lqe_id, &qti->qti_rec, 0,
false);
lqe_write_lock(lqe);
GOTO(out, rc = PTR_ERR(lqe));
}
+ lqe->lqe_is_reset = false;
lqe->lqe_is_deleted = 0;
/* The in-memory lqe update for slave index copy isn't deferred,
LQUOTA_DEBUG(lqe, "update to use default quota");
}
+ if (upd->qur_global && rc == 0 &&
+ (LQUOTA_FLAG(upd->qur_rec.lqr_glb_rec.qbr_time) &
+ LQUOTA_FLAG_RESET)) {
+ struct lquota_slv_rec srec;
+
+ lqe->lqe_granted = 0;
+ lqe->lqe_softlimit = 0;
+ lqe->lqe_hardlimit = 0;
+ lqe->lqe_is_default = false;
+ lqe->lqe_is_reset = true;
+
+ memset(&srec, 0, sizeof(srec));
+ rc = qsd_update_index(env, qqi, &upd->qur_qid, false, 0, &srec);
+ }
if (lqe && !IS_ERR(lqe)) {
lqe_putref(lqe);
}
run_test 83 "Setting default quota shouldn't affect grace time"
+test_84()
+{
+ (( $MDS1_VERSION >= $(version_code 2.15.53) )) ||
+ skip "need MDS 2.15.53 or later"
+
+ local dir1="$DIR/$tdir/dir1"
+ local TESTFILE1="$dir1/$tfile-1"
+ local waited=0
+ local grant=0
+ local grant2=0
+ local qp="qpool1"
+
+ mds_supports_qp
+
+ setup_quota_test || error "setup quota failed with $?"
+ quota_init
+ set_ost_qtype $QTYPE || error "enable ost quota failed"
+
+ pool_add $qp || error "pool_add failed"
+ pool_add_targets $qp 0 $(($OSTCOUNT - 1)) ||
+ error "pool_add_targets failed"
+
+ $LFS setquota -g $TSTUSR -B 10G $DIR ||
+ error "failed to set group quota for $TSTUSR"
+ $LFS setquota -g $TSTUSR -B 5G --pool $qp $DIR ||
+ error "set user quota failed"
+ $LFS quota -gv $TSTUSR $DIR
+
+ mkdir -p $dir1 || error "failed to mkdir"
+ chown $TSTUSR.$TSTUSR $dir1 || error "chown $dir1 failed"
+
+ $LFS setstripe -c 1 -i 0 $TESTFILE1
+ $LFS getstripe $TESTFILE1
+ chown $TSTUSR.$TSTUSR $TESTFILE1
+
+ $RUNAS $DD of=$TESTFILE1 count=60 conv=nocreat oflag=direct ||
+ quota_error g $TSTUSR "write failed"
+
+ sync
+ sleep 3
+ $LFS quota -gv $TSTUSR $DIR
+
+#define OBD_FAIL_QUOTA_GRANT 0xA08
+ lustre_fail mds 0xa08
+ lustre_fail ost 0xa08
+ sleep 1
+
+ # clear quota limits to trigger updating grant quota
+ $LFS setquota -g $TSTUSR -b 0 -B 0 $DIR ||
+ error "failed to clear the group quota for $TSTUSR"
+ $LFS quota -gv $TSTUSR $DIR
+
+ # the grant quota should be set as insane value
+ waited=0
+ while (( $waited < 60 )); do
+ grant=$(getquota -g $TSTUSR lustre-OST0000_UUID bhardlimit $qp)
+ grant2=$(getquota -g $TSTUSR lustre-OST0000_UUID bhardlimit)
+ (( ${#grant} == 20 && ${#grant2} == 20 )) && break
+
+ sleep 1
+ waited=$((waited + 1))
+ done
+
+ (( ${#grant} == 20 )) || error "pool grant is not set as insane value"
+ (( ${#grant2} == 20 )) || error "grant is not set as insane value"
+
+ lustre_fail mds_ost 0
+ sleep 1
+
+ # reset the quota
+ $LFS setquota -g $TSTUSR -r $DIR ||
+ error "failed to reset group quota for $TSTUSR"
+
+ sleep 3
+ $LFS quota -gv $TSTUSR $DIR
+
+ # the grant quota should be reset
+ grant=$(getquota -g $TSTUSR lustre-OST0000_UUID bhardlimit)
+ (( ${#grant} == 20 )) && error "grant is not cleared"
+ grant=$(getquota -g $TSTUSR lustre-OST0000_UUID bhardlimit $qp)
+ (( ${#grant} == 20 )) && error "pool grant is not cleared"
+
+ $LFS quota -gv $TSTUSR --pool $qp $DIR
+ local hlimit=$(getquota -g $TSTUSR global bhardlimit $qp)
+ [ $hlimit -eq 5242880 ] || error "pool limit is changed"
+
+ # test whether the quota still works
+ $LFS setquota -g $TSTUSR -B 100M $DIR ||
+ error "failed to set group quota for $TSTUSR"
+ $LFS quota -gv $TSTUSR $DIR
+
+ $RUNAS $DD of=$TESTFILE1 count=200 conv=nocreat oflag=direct &&
+ quota_error g $TSTUSR "dd succeed, expect EDQUOT"
+
+ $LFS setquota -g $TSTUSR -B 300M $DIR ||
+ error "failed to set group quota for $TSTUSR"
+ $LFS quota -gv $TSTUSR $DIR
+
+ $RUNAS $DD of=$TESTFILE1 count=200 conv=nocreat oflag=direct ||
+ quota_error g $TSTUSR "dd failed, expect succeed"
+}
+run_test 84 "Reset quota should fix the insane granted quota"
+
quota_fini()
{
do_nodes $(comma_list $(nodes_list)) \
return 0;
}
+static int lfs_reset_quota(char *mnt, struct if_quotactl *qctl)
+{
+ struct if_quotactl tmp_qctl;
+ int index, md_count, dt_count;
+ int wait_phase = 0, wait_index = 0, wait_count = 0;
+ int rc, rc2;
+
+ /* reset the quota ID, the existing quota setting will be returned */
+ rc = llapi_quotactl(mnt, qctl);
+ if (rc)
+ return rc;
+
+ /* sanity check */
+ if ((qctl->qc_dqblk.dqb_valid & QIF_LIMITS) != QIF_LIMITS) {
+ fprintf(stderr,
+ "the existing quota settings are not returned!\n");
+ return -EINVAL;
+ }
+
+ rc = llapi_get_obd_count(mnt, &md_count, 1);
+ if (rc) {
+ fprintf(stderr, "can not get mdt count: %s\n", strerror(-rc));
+ return rc;
+ }
+
+ rc = llapi_get_obd_count(mnt, &dt_count, 0);
+ if (rc) {
+ fprintf(stderr, "can not get ost count: %s\n", strerror(-rc));
+ return rc;
+ }
+
+ memset(&tmp_qctl, 0, sizeof(tmp_qctl));
+ tmp_qctl.qc_type = qctl->qc_type;
+ tmp_qctl.qc_id = qctl->qc_id;
+ tmp_qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
+
+retry:
+ if (wait_phase == 0) {
+ for (index = wait_index; index < md_count; index++) {
+ tmp_qctl.qc_idx = index;
+ tmp_qctl.qc_valid = QC_MDTIDX;
+ rc = llapi_quotactl(mnt, &tmp_qctl);
+ if (rc == -ENODEV || rc == -ENODATA)
+ continue;
+ if (rc) {
+ fprintf(stderr, "quotactl mdt%d failed: %s\n",
+ index, strerror(-rc));
+ break;
+ }
+ /* check whether the md quota grant is reset */
+ if (tmp_qctl.qc_dqblk.dqb_valid & QIF_LIMITS &&
+ tmp_qctl.qc_dqblk.dqb_ihardlimit != 0)
+ break;
+ }
+
+ if (index < md_count) {
+ wait_phase = 0;
+ wait_index = index;
+ goto wait;
+ }
+ } else {
+ for (index = wait_index; index < dt_count; index++) {
+ tmp_qctl.qc_idx = index;
+ tmp_qctl.qc_valid = QC_OSTIDX;
+ rc = llapi_quotactl(mnt, &tmp_qctl);
+ if (rc == -ENODEV || rc == -ENODATA)
+ continue;
+ if (rc) {
+ fprintf(stderr, "quotactl mdt%d failed: %s\n",
+ index, strerror(-rc));
+ break;
+ }
+ /* check whether the dt quota grant is reset */
+ if (tmp_qctl.qc_dqblk.dqb_valid & QIF_LIMITS &&
+ tmp_qctl.qc_dqblk.dqb_bhardlimit != 0)
+ break;
+ }
+
+ if (index < dt_count) {
+ wait_phase = 1;
+ wait_index = index;
+ goto wait;
+ }
+ }
+
+ if (wait_phase == 0) {
+ wait_phase = 1;
+ goto retry;
+ }
+
+ goto out;
+
+wait:
+ if (rc || wait_count > 30) {
+ fprintf(stderr, "fail to reset the quota ID %d on OBDs\n",
+ qctl->qc_id);
+ goto out;
+ }
+
+ wait_count++;
+ sleep(1);
+ fprintf(stdout, "wait %d seconds for OBDs to reset the quota ID %u\n",
+ wait_count, qctl->qc_id);
+ goto retry;
+
+
+out:
+ /* restore the quota setting */
+ if (qctl->qc_dqblk.dqb_isoftlimit == 0 &&
+ qctl->qc_dqblk.dqb_ihardlimit == 0 &&
+ qctl->qc_dqblk.dqb_bsoftlimit == 0 &&
+ qctl->qc_dqblk.dqb_bhardlimit == 0)
+ return rc;
+
+ memcpy(&tmp_qctl, qctl, sizeof(tmp_qctl));
+ tmp_qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
+ rc2 = llapi_quotactl(mnt, &tmp_qctl);
+ if (!rc2)
+ return rc;
+
+ fprintf(stderr,
+ "fail to restore the quota setting: %s, please restore it manually by\n lfs setquota %s %d",
+ strerror(-rc2),
+ qctl->qc_type == USRQUOTA ? "-u" :
+ (qctl->qc_type == GRPQUOTA ? "-g" : "-p"),
+ qctl->qc_id);
+
+ if (qctl->qc_dqblk.dqb_isoftlimit != 0)
+ fprintf(stderr, " -i %llu",
+ (unsigned long long)qctl->qc_dqblk.dqb_isoftlimit);
+ if (qctl->qc_dqblk.dqb_ihardlimit != 0)
+ fprintf(stderr, " -I %llu",
+ (unsigned long long)qctl->qc_dqblk.dqb_ihardlimit);
+ if (qctl->qc_dqblk.dqb_bsoftlimit != 0)
+ fprintf(stderr, " -b %llu",
+ (unsigned long long)qctl->qc_dqblk.dqb_bsoftlimit);
+ if (qctl->qc_dqblk.dqb_bhardlimit != 0)
+ fprintf(stderr, " -B %llu",
+ (unsigned long long)qctl->qc_dqblk.dqb_bhardlimit);
+
+ fprintf(stderr, " %s\n", mnt);
+ if (!rc)
+ rc = rc2;
+
+ return rc;
+}
+
#define BSLIMIT (1 << 0)
#define BHLIMIT (1 << 1)
#define ISLIMIT (1 << 2)
.has_arg = required_argument },
{ .val = 'p', .name = "projid", .has_arg = required_argument },
{ .val = 'P', .name = "default-prj", .has_arg = no_argument },
+ { .val = 'r', .name = "reset", .has_arg = no_argument },
{ .val = 'u', .name = "user", .has_arg = required_argument },
{ .val = 'U', .name = "default-usr", .has_arg = no_argument },
{ .val = LFS_POOL_OPT,
* so it can be used as a marker that qc_type
* isn't reinitialized from command line
*/
- while ((c = getopt_long(argc, argv, "b:B:dDg:Ghi:I:p:Pu:U",
+ while ((c = getopt_long(argc, argv, "b:B:dDg:Ghi:I:p:Pru:U",
long_opts, NULL)) != -1) {
switch (c) {
case 'U':
LUSTRE_Q_SETDEFAULT_POOL :
LUSTRE_Q_SETQUOTAPOOL;
break;
+ case 'r':
+ qctl->qc_cmd = LUSTRE_Q_RESETQID;
+ break;
default:
fprintf(stderr,
"%s setquota: unrecognized option '%s'\n",
}
if (!use_default && qctl->qc_cmd != LUSTRE_Q_DELETEQID &&
- limit_mask == 0) {
+ qctl->qc_cmd != LUSTRE_Q_RESETQID && limit_mask == 0) {
fprintf(stderr,
"%s setquota: at least one limit must be specified\n",
progname);
goto out;
}
- if ((use_default || qctl->qc_cmd == LUSTRE_Q_DELETEQID) &&
- limit_mask != 0) {
+ if ((use_default || qctl->qc_cmd == LUSTRE_Q_DELETEQID ||
+ qctl->qc_cmd == LUSTRE_Q_RESETQID) && limit_mask != 0) {
fprintf(stderr,
- "%s setquota: limits should not be specified when using default quota or deleting quota ID\n",
+ "%s setquota: limits should not be specified when using default quota, deleting or resetting quota ID\n",
progname);
rc = CMD_HELP;
goto out;
goto out;
}
- if (qctl->qc_cmd == LUSTRE_Q_DELETEQID && qctl->qc_id == 0) {
+ if ((qctl->qc_cmd == LUSTRE_Q_DELETEQID ||
+ qctl->qc_cmd == LUSTRE_Q_RESETQID) && qctl->qc_id == 0) {
fprintf(stderr,
- "%s setquota: can not delete root user/group/project\n",
+ "%s setquota: can not delete or reset root user/group/project\n",
progname);
rc = CMD_HELP;
goto out;
dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
- rc = llapi_quotactl(mnt, qctl);
+ if (qctl->qc_cmd == LUSTRE_Q_RESETQID)
+ rc = lfs_reset_quota(mnt, qctl);
+ else
+ rc = llapi_quotactl(mnt, qctl);
+
if (rc) {
if (*obd_type)
fprintf(stderr,