X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fquota%2Fqmt_handler.c;h=9d2a4cca6fd61f2cbd639076dc330f5c57dceeae;hb=3812c54b9ca3cc08be947f893bdf55a41aa876ed;hp=7ae6a0cb3ad8d97f120edb53a41495ebc4e7621a;hpb=5522990660248930108e84c89bc7e5807bda9ea0;p=fs%2Flustre-release.git diff --git a/lustre/quota/qmt_handler.c b/lustre/quota/qmt_handler.c index 7ae6a0c..9d2a4cc 100644 --- a/lustre/quota/qmt_handler.c +++ b/lustre/quota/qmt_handler.c @@ -21,7 +21,7 @@ * GPL HEADER END */ /* - * Copyright (c) 2012, Intel Corporation. + * Copyright (c) 2012, 2017, Intel Corporation. * Use is subject to license terms. * * Author: Johann Lombardi @@ -38,7 +38,6 @@ * * \param env - is the environment passed by the caller * \param qmt - is the quota master target - * \param pool_id - is the 16-bit pool identifier * \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 @@ -49,14 +48,16 @@ * \param time - is the output variable where to copy the grace time */ static int qmt_get(const struct lu_env *env, struct qmt_device *qmt, - __u16 pool_id, __u8 restype, __u8 qtype, union lquota_id *id, - __u64 *hard, __u64 *soft, __u64 *time) + __u8 restype, __u8 qtype, union lquota_id *id, + __u64 *hard, __u64 *soft, __u64 *time, bool is_default) { struct lquota_entry *lqe; ENTRY; + LASSERT(!is_default || id->qid_uid == 0); + /* look-up lqe structure containing quota settings */ - lqe = qmt_pool_lqe_lookup(env, qmt, pool_id, restype, qtype, id); + lqe = qmt_pool_lqe_lookup(env, qmt, restype, qtype, id); if (IS_ERR(lqe)) RETURN(PTR_ERR(lqe)); @@ -67,59 +68,88 @@ static int qmt_get(const struct lu_env *env, struct qmt_device *qmt, *hard = lqe->lqe_hardlimit; if (soft != NULL) *soft = lqe->lqe_softlimit; - if (time != NULL) + if (time != NULL) { *time = lqe->lqe_gracetime; + if (lqe->lqe_is_default) + *time |= (__u64)LQUOTA_FLAG_DEFAULT << + LQUOTA_GRACE_BITS; + } lqe_read_unlock(lqe); lqe_putref(lqe); RETURN(0); } +struct qmt_entry_iter_data { + const struct lu_env *qeid_env; + struct qmt_device *qeid_qmt; +}; + +static int qmt_entry_iter_cb(struct cfs_hash *hs, struct cfs_hash_bd *bd, + struct hlist_node *hnode, void *d) +{ + struct qmt_entry_iter_data *iter = (struct qmt_entry_iter_data *)d; + struct lquota_entry *lqe; + + lqe = hlist_entry(hnode, struct lquota_entry, lqe_hash); + LASSERT(atomic_read(&lqe->lqe_ref) > 0); + + if (lqe->lqe_id.qid_uid == 0 || !lqe->lqe_is_default) + return 0; + + return qmt_set_with_lqe(iter->qeid_env, iter->qeid_qmt, lqe, 0, 0, 0, 0, + true, true); +} + /* - * Update quota settings for a given identifier. + * Update quota settings for a given lqe. * - * \param env - is the environment passed by the caller - * \param qmt - is the quota master target - * \param pool_id - is the 16-bit pool identifier - * \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 id - is the quota indentifier for which we want to modify quota - * settings. - * \param hard - is the new hard limit - * \param soft - is the new soft limit - * \param time - is the new grace time - * \param valid - is the list of settings to change + * \param env - is the environment passed by the caller + * \param qmt - is the quota master target + * \param lqe - is the lquota_entry for which we want to modify quota + * settings. + * \param hard - is the new hard limit + * \param soft - is the new soft limit + * \param time - is the new grace time + * \param valid - is the list of settings to change + * \param is_default - true for default quota setting + * \param is_updated - true if the lqe is updated and no need to write back */ -static int qmt_set(const struct lu_env *env, struct qmt_device *qmt, - __u16 pool_id, __u8 restype, __u8 qtype, - union lquota_id *id, __u64 hard, __u64 soft, __u64 time, - __u32 valid) + +int qmt_set_with_lqe(const struct lu_env *env, struct qmt_device *qmt, + struct lquota_entry *lqe, __u64 hard, __u64 soft, + __u64 time, __u32 valid, bool is_default, bool is_updated) { struct qmt_thread_info *qti = qmt_info(env); - struct lquota_entry *lqe; struct thandle *th = NULL; - __u64 ver, now; + time64_t now; + __u64 ver; bool dirtied = false; int rc = 0; ENTRY; - /* look-up quota entry associated with this ID */ - lqe = qmt_pool_lqe_lookup(env, qmt, pool_id, restype, qtype, id); - if (IS_ERR(lqe)) - RETURN(PTR_ERR(lqe)); - - /* allocate & start transaction with enough credits to update quota - * settings in the global index file */ - th = qmt_trans_start(env, lqe, &qti->qti_restore); - if (IS_ERR(th)) - GOTO(out_nolock, rc = PTR_ERR(th)); + /* need to write back to global quota file? */ + if (!is_updated) { + /* allocate & start transaction with enough credits to update + * quota settings in the global index file */ + th = qmt_trans_start(env, lqe, &qti->qti_restore); + if (IS_ERR(th)) + GOTO(out_nolock, rc = PTR_ERR(th)); + } - now = cfs_time_current_sec(); + now = ktime_get_real_seconds(); lqe_write_lock(lqe); - LQUOTA_DEBUG(lqe, "changing quota settings valid:%x hard:"LPU64" soft:" - LPU64" time:"LPU64, valid, hard, soft, time); + LQUOTA_DEBUG(lqe, "changing quota settings valid:%x hard:%llu soft:" + "%llu time:%llu", valid, hard, soft, time); + + if (is_default && lqe->lqe_id.qid_uid != 0) { + LQUOTA_DEBUG(lqe, "set qid %llu to use default quota setting", + lqe->lqe_id.qid_uid); + + qmt_lqe_set_default(env, lqe->lqe_site->lqs_parent, lqe, false); + GOTO(quota_set, 0); + } if ((valid & QIF_TIMES) != 0 && lqe->lqe_gracetime != time) { /* change time settings */ @@ -133,13 +163,14 @@ static int qmt_set(const struct lu_env *env, struct qmt_device *qmt, if (rc) GOTO(out, rc); - /* recompute qunit in case it was never initialized */ - qmt_revalidate(env, lqe); - /* change quota limits */ lqe->lqe_hardlimit = hard; lqe->lqe_softlimit = soft; +quota_set: + /* recompute qunit in case it was never initialized */ + qmt_revalidate(env, lqe); + /* clear grace time */ if (lqe->lqe_softlimit == 0 || lqe->lqe_granted <= lqe->lqe_softlimit) @@ -151,7 +182,8 @@ static int qmt_set(const struct lu_env *env, struct qmt_device *qmt, lqe->lqe_gracetime = now + qmt_lqe_grace(lqe); /* change enforced status based on new parameters */ - if (lqe->lqe_hardlimit == 0 && lqe->lqe_softlimit == 0) + if (lqe->lqe_id.qid_uid == 0 || (lqe->lqe_hardlimit == 0 && + lqe->lqe_softlimit == 0)) lqe->lqe_enforced = false; else lqe->lqe_enforced = true; @@ -159,13 +191,26 @@ static int qmt_set(const struct lu_env *env, struct qmt_device *qmt, dirtied = true; } + if (!is_default && lqe->lqe_is_default) { + LQUOTA_DEBUG(lqe, "the qid %llu has been set quota" + " explicitly, clear the default flag", + lqe->lqe_id.qid_uid); + + qmt_lqe_clear_default(lqe); + dirtied = true; + } + if (dirtied) { - /* write new quota settings to disk */ - rc = qmt_glb_write(env, th, lqe, LQUOTA_BUMP_VER, &ver); - if (rc) { - /* restore initial quota settings */ - qmt_restore(lqe, &qti->qti_restore); - GOTO(out, rc); + if (!is_updated) { + /* write new quota settings to disk */ + rc = qmt_glb_write(env, th, lqe, LQUOTA_BUMP_VER, &ver); + if (rc) { + /* restore initial quota settings */ + qmt_restore(lqe, &qti->qti_restore); + GOTO(out, rc); + } + } else { + ver = dt_version_get(env, LQE_GLB_OBJ(lqe)); } /* compute new qunit value now that we have modified the quota @@ -178,19 +223,66 @@ static int qmt_set(const struct lu_env *env, struct qmt_device *qmt, EXIT; out: lqe_write_unlock(lqe); -out_nolock: - lqe_putref(lqe); +out_nolock: if (th != NULL && !IS_ERR(th)) dt_trans_stop(env, qmt->qmt_child, th); - if (rc == 0 && dirtied) + if (rc == 0 && dirtied) { qmt_glb_lock_notify(env, lqe, ver); + if (lqe->lqe_id.qid_uid == 0) { + struct qmt_entry_iter_data iter_data; + + LQUOTA_DEBUG(lqe, "notify all lqe with default quota"); + iter_data.qeid_env = env; + iter_data.qeid_qmt = qmt; + cfs_hash_for_each_safe(lqe->lqe_site->lqs_hash, + qmt_entry_iter_cb, &iter_data); + } + } return rc; } /* + * Update quota settings for a given identifier. + * + * \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 id - is the quota indentifier for which we want to modify + * quota settings. + * \param hard - is the new hard limit + * \param soft - is the new soft limit + * \param time - is the new grace time + * \param valid - is the list of settings to change + * \param is_default - true for default quota setting + * \param is_updated - true if the lqe is updated and no need to write back + */ +static int qmt_set(const struct lu_env *env, struct qmt_device *qmt, + __u8 restype, __u8 qtype, union lquota_id *id, + __u64 hard, __u64 soft, __u64 time, __u32 valid, + bool is_default, bool is_updated) +{ + struct lquota_entry *lqe; + int rc; + ENTRY; + + /* look-up quota entry associated with this ID */ + lqe = qmt_pool_lqe_lookup(env, qmt, restype, qtype, id); + if (IS_ERR(lqe)) + RETURN(PTR_ERR(lqe)); + + rc = qmt_set_with_lqe(env, qmt, lqe, hard, soft, time, valid, + is_default, is_updated); + + lqe_putref(lqe); + RETURN(rc); +} + +/* * Handle quotactl request. * * \param env - is the environment passed by the caller @@ -205,6 +297,7 @@ static int qmt_quotactl(const struct lu_env *env, struct lu_device *ld, struct qmt_device *qmt = lu2qmt_dev(ld); struct obd_dqblk *dqb = &oqctl->qc_dqblk; int rc = 0; + bool is_default = false; ENTRY; LASSERT(qmt != NULL); @@ -220,14 +313,14 @@ static int qmt_quotactl(const struct lu_env *env, struct lu_device *ld, id->qid_uid = 0; /* read inode grace time */ - rc = qmt_get(env, qmt, 0, LQUOTA_RES_MD, oqctl->qc_type, id, - NULL, NULL, &oqctl->qc_dqinfo.dqi_igrace); + rc = qmt_get(env, qmt, LQUOTA_RES_MD, oqctl->qc_type, id, + NULL, NULL, &oqctl->qc_dqinfo.dqi_igrace, false); if (rc) break; /* read block grace time */ - rc = qmt_get(env, qmt, 0, LQUOTA_RES_DT, oqctl->qc_type, id, - NULL, NULL, &oqctl->qc_dqinfo.dqi_bgrace); + rc = qmt_get(env, qmt, LQUOTA_RES_DT, oqctl->qc_type, id, + NULL, NULL, &oqctl->qc_dqinfo.dqi_bgrace, false); break; case Q_SETINFO: /* modify grace times */ @@ -240,34 +333,32 @@ static int qmt_quotactl(const struct lu_env *env, struct lu_device *ld, if ((dqb->dqb_valid & QIF_ITIME) != 0) { /* set inode grace time */ - rc = qmt_set(env, qmt, 0, LQUOTA_RES_MD, oqctl->qc_type, + rc = qmt_set(env, qmt, LQUOTA_RES_MD, oqctl->qc_type, id, 0, 0, oqctl->qc_dqinfo.dqi_igrace, - QIF_TIMES); + QIF_TIMES, false, false); if (rc) break; } if ((dqb->dqb_valid & QIF_BTIME) != 0) /* set block grace time */ - rc = qmt_set(env, qmt, 0, LQUOTA_RES_DT, oqctl->qc_type, + rc = qmt_set(env, qmt, LQUOTA_RES_DT, oqctl->qc_type, id, 0, 0, oqctl->qc_dqinfo.dqi_bgrace, - QIF_TIMES); + QIF_TIMES, false, false); break; + case LUSTRE_Q_GETDEFAULT: + is_default = true; + /* fallthrough */ + case Q_GETQUOTA: /* consult quota limit */ - /* There is no quota limit for root user & group */ - if (oqctl->qc_id == 0) { - memset(dqb, 0, sizeof(*dqb)); - dqb->dqb_valid = QIF_LIMITS | QIF_TIMES; - break; - } /* extract quota ID from quotactl request */ id->qid_uid = oqctl->qc_id; /* look-up inode quota settings */ - rc = qmt_get(env, qmt, 0, LQUOTA_RES_MD, oqctl->qc_type, id, + rc = qmt_get(env, qmt, LQUOTA_RES_MD, oqctl->qc_type, id, &dqb->dqb_ihardlimit, &dqb->dqb_isoftlimit, - &dqb->dqb_itime); + &dqb->dqb_itime, is_default); if (rc) break; @@ -276,9 +367,9 @@ static int qmt_quotactl(const struct lu_env *env, struct lu_device *ld, dqb->dqb_curinodes = 0; /* look-up block quota settings */ - rc = qmt_get(env, qmt, 0, LQUOTA_RES_DT, oqctl->qc_type, id, + rc = qmt_get(env, qmt, LQUOTA_RES_DT, oqctl->qc_type, id, &dqb->dqb_bhardlimit, &dqb->dqb_bsoftlimit, - &dqb->dqb_btime); + &dqb->dqb_btime, is_default); if (rc) break; @@ -287,29 +378,32 @@ static int qmt_quotactl(const struct lu_env *env, struct lu_device *ld, dqb->dqb_curspace = 0; break; + case LUSTRE_Q_SETDEFAULT: + is_default = true; + /* fallthrough */ + case Q_SETQUOTA: /* change quota limits */ - if (oqctl->qc_id == 0) - /* can't enforce a quota limit for root user & group */ - RETURN(-EPERM); /* extract quota ID from quotactl request */ id->qid_uid = oqctl->qc_id; if ((dqb->dqb_valid & QIF_IFLAGS) != 0) { /* update inode quota settings */ - rc = qmt_set(env, qmt, 0, LQUOTA_RES_MD, oqctl->qc_type, + rc = qmt_set(env, qmt, LQUOTA_RES_MD, oqctl->qc_type, id, dqb->dqb_ihardlimit, dqb->dqb_isoftlimit, dqb->dqb_itime, - dqb->dqb_valid & QIF_IFLAGS); + dqb->dqb_valid & QIF_IFLAGS, is_default, + false); if (rc) break; } if ((dqb->dqb_valid & QIF_BFLAGS) != 0) /* update block quota settings */ - rc = qmt_set(env, qmt, 0, LQUOTA_RES_DT, oqctl->qc_type, + rc = qmt_set(env, qmt, LQUOTA_RES_DT, oqctl->qc_type, id, dqb->dqb_bhardlimit, dqb->dqb_bsoftlimit, dqb->dqb_btime, - dqb->dqb_valid & QIF_BFLAGS); + dqb->dqb_valid & QIF_BFLAGS, is_default, + false); break; default: @@ -378,8 +472,8 @@ int qmt_dqacq0(const struct lu_env *env, struct lquota_entry *lqe, GOTO(out, rc = PTR_ERR(th)); lqe_write_lock(lqe); - LQUOTA_DEBUG(lqe, "dqacq starts uuid:%s flags:0x%x wanted:"LPU64 - " usage:"LPU64, obd_uuid2str(uuid), qb_flags, qb_count, + LQUOTA_DEBUG(lqe, "dqacq starts uuid:%s flags:0x%x wanted:%llu" + " usage:%llu", obd_uuid2str(uuid), qb_flags, qb_count, qb_usage); /* Legal race, limits have been removed on master, but slave didn't @@ -407,7 +501,7 @@ int qmt_dqacq0(const struct lu_env *env, struct lquota_entry *lqe, slv_granted_bck = slv_granted; /* record current time for soft limit & grace time management */ - now = (__u64)cfs_time_current_sec(); + now = ktime_get_real_seconds(); if (req_is_rel(qb_flags)) { /* Slave would like to release quota space */ @@ -415,7 +509,7 @@ int qmt_dqacq0(const struct lu_env *env, struct lquota_entry *lqe, lqe->lqe_granted < qb_count) { /* can't release more than granted */ LQUOTA_ERROR(lqe, "Release too much! uuid:%s release:" - LPU64" granted:"LPU64", total:"LPU64, + "%llu granted:%llu, total:%llu", obd_uuid2str(uuid), qb_count, slv_granted, lqe->lqe_granted); GOTO(out_locked, rc = -EINVAL); @@ -549,7 +643,7 @@ out_write: /* clear/set edquot flag and notify slaves via glimpse if needed */ qmt_adjust_edquot(lqe, now); out_locked: - LQUOTA_DEBUG(lqe, "dqacq ends count:"LPU64" ver:"LPU64" rc:%d", + LQUOTA_DEBUG(lqe, "dqacq ends count:%llu ver:%llu rc:%d", repbody->qb_count, repbody->qb_slv_ver, rc); lqe_write_unlock(lqe); out: @@ -557,7 +651,7 @@ out: dt_trans_stop(env, qmt->qmt_child, th); if (slv_obj != NULL && !IS_ERR(slv_obj)) - lu_object_put(env, &slv_obj->do_lu); + dt_object_put(env, slv_obj); if ((req_is_acq(qb_flags) || req_is_preacq(qb_flags)) && OBD_FAIL_CHECK(OBD_FAIL_QUOTA_EDQUOT)) { @@ -585,7 +679,7 @@ static int qmt_dqacq(const struct lu_env *env, struct lu_device *ld, struct obd_uuid *uuid; struct ldlm_lock *lock; struct lquota_entry *lqe; - int pool_id, pool_type, qtype; + int pool_type, qtype; int rc; ENTRY; @@ -637,8 +731,8 @@ static int qmt_dqacq(const struct lu_env *env, struct lu_device *ld, } if (ldlm_is_ast_sent(lock)) { - struct ptlrpc_service_part *svc; - unsigned int timeout; + struct ptlrpc_service_part *svc; + time64_t timeout; svc = req->rq_rqbd->rqbd_svcpt; timeout = at_est2timeout(at_get(&svc->scp_at_estimate)); @@ -650,14 +744,14 @@ static int qmt_dqacq(const struct lu_env *env, struct lu_device *ld, LDLM_LOCK_PUT(lock); } - /* extract pool & quota information from global index FID packed in the + /* extract quota information from global index FID packed in the * request */ - rc = lquota_extract_fid(&qbody->qb_fid, &pool_id, &pool_type, &qtype); + rc = lquota_extract_fid(&qbody->qb_fid, &pool_type, &qtype); if (rc) RETURN(-EINVAL); /* Find the quota entry associated with the quota id */ - lqe = qmt_pool_lqe_lookup(env, qmt, pool_id, pool_type, qtype, + lqe = qmt_pool_lqe_lookup(env, qmt, pool_type, qtype, &qbody->qb_id); if (IS_ERR(lqe)) RETURN(PTR_ERR(lqe));