X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fquota%2Fqmt_handler.c;h=455652c372a15c48b371b66ff2e4ff74e23e0a3a;hb=c3a836364892cacbc4737645893b094971c6ec49;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..455652c 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 @@ -50,11 +50,13 @@ */ 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) + __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); if (IS_ERR(lqe)) @@ -67,59 +69,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 +164,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 +183,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; @@ -160,12 +193,24 @@ static int qmt_set(const struct lu_env *env, struct qmt_device *qmt, } 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_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); + } + + 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,67 @@ 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 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 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, 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, pool_id, 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 +298,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); @@ -221,13 +315,13 @@ static int qmt_quotactl(const struct lu_env *env, struct lu_device *ld, /* read inode grace time */ rc = qmt_get(env, qmt, 0, LQUOTA_RES_MD, oqctl->qc_type, id, - NULL, NULL, &oqctl->qc_dqinfo.dqi_igrace); + 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); + NULL, NULL, &oqctl->qc_dqinfo.dqi_bgrace, false); break; case Q_SETINFO: /* modify grace times */ @@ -242,7 +336,7 @@ static int qmt_quotactl(const struct lu_env *env, struct lu_device *ld, /* set inode grace time */ rc = qmt_set(env, qmt, 0, LQUOTA_RES_MD, oqctl->qc_type, id, 0, 0, oqctl->qc_dqinfo.dqi_igrace, - QIF_TIMES); + QIF_TIMES, false, false); if (rc) break; } @@ -251,23 +345,20 @@ static int qmt_quotactl(const struct lu_env *env, struct lu_device *ld, /* set block grace time */ rc = qmt_set(env, qmt, 0, 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; + 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, &dqb->dqb_ihardlimit, &dqb->dqb_isoftlimit, - &dqb->dqb_itime); + &dqb->dqb_itime, is_default); if (rc) break; @@ -278,7 +369,7 @@ static int qmt_quotactl(const struct lu_env *env, struct lu_device *ld, /* look-up block quota settings */ rc = qmt_get(env, qmt, 0, 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,10 +378,10 @@ 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; + 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; @@ -299,7 +390,8 @@ static int qmt_quotactl(const struct lu_env *env, struct lu_device *ld, rc = qmt_set(env, qmt, 0, 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; } @@ -309,7 +401,8 @@ static int qmt_quotactl(const struct lu_env *env, struct lu_device *ld, rc = qmt_set(env, qmt, 0, 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 +471,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 +500,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 +508,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 +642,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 +650,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)) { @@ -637,8 +730,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));