* super-class definitions.
*/
#include <lu_object.h>
-
+#include <lustre_quota.h>
#include <libcfs/libcfs.h>
struct seq_file;
struct dt_device *dev);
/**
- * The unit of \a count is byte for block or inodes for metadata.
- *
- * If \a count > 0, reserve quota in advance of an operation that
- * changes the quota assignment, such as chgrp() or rename() into
+ * If \a qi->lqi_space > 0, reserve quota in advance of an operation
+ * that changes the quota assignment, such as chgrp() or rename() into
* a directory with a different group ID.
*
- * If \a count < 0, free the reserved quota previously.
+ * If \a qi->lqi_space < 0, free the reserved quota previously.
*
* \param[in] env execution environment for this thread
* \param[in] dev the bottom OSD device to reserve quota
- * \param[in] type quota type (LQUOTA_RES_DT or LQUOTA_RES_MD)
- * \param[in] uid quota uid
- * \param[in] gid quota gid
- * \param[in] count space (bytes or inodes) to reserve or free
- * \param[in] md true for inode, false for block
+ * \param[in] qi quota id & space required to reserve
*
* \retval 0 on success
* \retval negative negated errno on error
*/
int (*dt_reserve_or_free_quota)(const struct lu_env *env,
struct dt_device *dev,
- enum quota_type type, __u64 uid,
- __u64 gid, __s64 count, bool md);
+ struct lquota_id_info *qi);
};
struct dt_index_features {
struct dt_object, do_lu);
}
-struct dt_quota_reserve_rec {
- enum quota_type qrr_type;
- union lquota_id qrr_id;
- __u64 qrr_count;
-};
-
/**
* This is the general purpose transaction handle.
* 1. Transaction Life Cycle
struct thandle *th_top;
/* reserved quota for this handle */
- struct dt_quota_reserve_rec th_reserved_quota;
+ struct lquota_id_info th_reserved_quota;
/** the last operation result in this transaction.
* this value is used in recovery */
static inline int dt_reserve_or_free_quota(const struct lu_env *env,
struct dt_device *dev,
- enum quota_type type, __u64 uid,
- __u64 gid, int count, bool is_md)
+ struct lquota_id_info *qi)
{
LASSERT(dev);
LASSERT(dev->dd_ops);
LASSERT(dev->dd_ops->dt_reserve_or_free_quota);
- return dev->dd_ops->dt_reserve_or_free_quota(env, dev, type, uid, gid,
- count, is_md);
+ return dev->dd_ops->dt_reserve_or_free_quota(env, dev, qi);
}
static inline int dt_lookup(const struct lu_env *env,
* on slave */
int lquotactl_slv(const struct lu_env *, struct dt_device *,
struct obd_quotactl *);
-
-static inline int quota_reserve_or_free(const struct lu_env *env,
- struct qsd_instance *qsd,
- struct lquota_id_info *qi,
- enum quota_type type, __u64 uid,
- __u64 gid, __s64 count, bool is_md)
-{
- qi->lqi_type = type;
- if (count > 0)
- qi->lqi_space = toqb(count);
- else
- qi->lqi_space = -toqb(-count);
-
- if (is_md)
- qi->lqi_is_blk = false;
- else
- qi->lqi_is_blk = true;
-
- qi->lqi_id.qid_uid = uid;
- qi->lqi_id.qid_gid = gid;
-
- return qsd_reserve_or_free_quota(env, qsd, qi);
-}
-
/** @} quota */
#endif /* _LUSTRE_QUOTA_H */
struct lu_attr *attr = MDD_ENV_VAR(env, cattr);
const struct lu_attr *la = &ma->ma_attr;
struct lu_ucred *uc;
+ struct lquota_id_info qi;
bool quota_reserved = false;
bool chrgrp_by_unprivileged_user = false;
- __s64 quota_size = 0;
int rc;
ENTRY;
* the setattr operation will be processed synchronously to
* honor the quota limit of the corresponding group. see LU-5152 */
uc = lu_ucred_check(env);
+ memset(&qi, 0, sizeof(qi));
if (S_ISREG(attr->la_mode) && la->la_valid & LA_GID &&
la->la_gid != attr->la_gid && uc != NULL && uc->uc_fsuid != 0) {
CDEBUG(D_QUOTA, "%s: reserve quota for changing group: gid=%u size=%llu\n",
mdd2obd_dev(mdd)->obd_name, la->la_gid, la->la_size);
if (la->la_valid & LA_BLOCKS)
- quota_size = la->la_blocks << 9;
+ qi.lqi_space = la->la_blocks << 9;
else if (la->la_valid & LA_SIZE)
- quota_size = la->la_size;
+ qi.lqi_space = la->la_size;
/* use local attr gotten above */
else if (attr->la_valid & LA_BLOCKS)
- quota_size = attr->la_blocks << 9;
+ qi.lqi_space = attr->la_blocks << 9;
else if (attr->la_valid & LA_SIZE)
- quota_size = attr->la_size;
+ qi.lqi_space = attr->la_size;
- if (quota_size > 0) {
+ if (qi.lqi_space > 0) {
+ qi.lqi_id.qid_gid = la->la_gid;
+ qi.lqi_type = GRPQUOTA;
+ qi.lqi_space = toqb(qi.lqi_space);
+ qi.lqi_is_blk = true;
rc = dt_reserve_or_free_quota(env, mdd->mdd_bottom,
- GRPQUOTA, attr->la_uid,
- la->la_gid, quota_size,
- false);
+ &qi);
if (rc) {
CDEBUG(D_QUOTA, "%s: failed to reserve quota for gid %d size %llu\n",
mdd2obd_dev(mdd)->obd_name,
- la->la_gid, quota_size);
+ la->la_gid, qi.lqi_space);
GOTO(out, rc);
}
sub_th = thandle_get_sub_by_dt(env, handle, mdd->mdd_bottom);
if (unlikely(IS_ERR(sub_th))) {
- dt_reserve_or_free_quota(env, mdd->mdd_bottom, GRPQUOTA,
- attr->la_uid, la->la_gid,
- -quota_size, false);
+ qi.lqi_space *= -1;
+ dt_reserve_or_free_quota(env, mdd->mdd_bottom, &qi);
} else {
- sub_th->th_reserved_quota.qrr_type = GRPQUOTA;
- sub_th->th_reserved_quota.qrr_id.qid_gid = la->la_gid;
- sub_th->th_reserved_quota.qrr_count = quota_size;
+ sub_th->th_reserved_quota = qi;
}
+ } else if (quota_reserved) {
+ qi.lqi_space *= -1;
+ dt_reserve_or_free_quota(env, mdd->mdd_bottom, &qi);
}
if (handle != NULL)
/* reserve or free quota for some operation */
static int osd_reserve_or_free_quota(const struct lu_env *env,
struct dt_device *dev,
- enum quota_type type, __u64 uid,
- __u64 gid, __s64 count, bool is_md)
+ struct lquota_id_info *qi)
{
- int rc;
struct osd_device *osd = osd_dt_dev(dev);
- struct osd_thread_info *info = osd_oti_get(env);
- struct lquota_id_info *qi = &info->oti_qi;
struct qsd_instance *qsd = NULL;
+ int rc;
ENTRY;
- if (is_md)
- qsd = osd->od_quota_slave_md;
- else
+ if (qi->lqi_is_blk)
qsd = osd->od_quota_slave_dt;
+ else
+ qsd = osd->od_quota_slave_md;
- rc = quota_reserve_or_free(env, qsd, qi, type, uid, gid, count, is_md);
+ rc = qsd_reserve_or_free_quota(env, qsd, qi);
RETURN(rc);
}
/* reserve or free quota for some operation */
static int osd_reserve_or_free_quota(const struct lu_env *env,
struct dt_device *dev,
- enum quota_type type, __u64 uid,
- __u64 gid, __s64 count, bool is_md)
+ struct lquota_id_info *qi)
{
- int rc;
struct osd_device *osd = osd_dt_dev(dev);
- struct osd_thread_info *info = osd_oti_get(env);
- struct lquota_id_info *qi = &info->oti_qi;
struct qsd_instance *qsd = NULL;
+ int rc;
- if (is_md)
- qsd = osd->od_quota_slave_md;
- else
+ ENTRY;
+
+ if (qi->lqi_is_blk)
qsd = osd->od_quota_slave_dt;
+ else
+ qsd = osd->od_quota_slave_md;
- rc = quota_reserve_or_free(env, qsd, qi, type, uid, gid, count, is_md);
+ rc = qsd_reserve_or_free_quota(env, qsd, qi);
RETURN(rc);
}
qsd_refresh_usage(env, lqe);
lqe_write_lock(lqe);
- if (qid->lqi_space > 0)
- lqe->lqe_pending_write -= qid->lqi_space;
+ if (qid->lqi_space > 0) {
+ if (lqe->lqe_pending_write < qid->lqi_space) {
+ LQUOTA_ERROR(lqe,
+ "More pending write quota to reduce (pending %llu, space %lld)\n",
+ lqe->lqe_pending_write, qid->lqi_space);
+ lqe->lqe_pending_write = 0;
+ } else {
+ lqe->lqe_pending_write -= qid->lqi_space;
+ }
+ }
if (env != NULL)
adjust = qsd_adjust_needed(lqe);
else
struct qsd_instance *qsd,
struct lquota_id_info *qi)
{
- struct lquota_entry *lqe;
struct qsd_qtype_info *qqi;
- int rc = 0;
bool is_free = qi->lqi_space < 0;
+ int rc = 0;
ENTRY;
* or - the user/group is root
* or - quota accounting isn't enabled
*/
- if (!qsd_type_enabled(qsd, qi->lqi_type) || qi->lqi_id.qid_uid == 0 ||
- (qsd->qsd_type_array[qi->lqi_type])->qqi_acct_failed)
+ if (!is_free &&
+ (!qsd_type_enabled(qsd, qi->lqi_type) || qi->lqi_id.qid_uid == 0 ||
+ (qsd->qsd_type_array[qi->lqi_type])->qqi_acct_failed))
RETURN(0);
if (is_free) {
- /* look up lquota entry associated with qid */
- lqe = lqe_locate(env, qqi->qqi_site, &qi->lqi_id);
- if (IS_ERR(lqe))
- RETURN(PTR_ERR(lqe));
- if (!lqe->lqe_enforced) {
- lqe_putref(lqe);
- RETURN(0);
- }
-
- qi->lqi_qentry = lqe;
-
- /* lqe will be put in qsd_op_end0 */
qsd_op_end0(env, qsd->qsd_type_array[qi->lqi_type], qi);
- qi->lqi_qentry = NULL;
} else {
- /* manage quota enforcement for this ID */
- rc = qsd_op_begin0(env, qsd->qsd_type_array[qi->lqi_type], qi,
- qi->lqi_space, NULL);
+ long long qspace = qi->lqi_space;
- if (qi->lqi_qentry != NULL) {
+ /* the acquired quota will add to lqi_space in qsd_op_begin0 */
+ qi->lqi_space = 0;
+ rc = qsd_op_begin0(env, qsd->qsd_type_array[qi->lqi_type], qi,
+ qspace, NULL);
+ if (rc && qi->lqi_qentry) {
lqe_putref(qi->lqi_qentry);
qi->lqi_qentry = NULL;
}
LASSERT(ccb->llcc_tgt != NULL);
LASSERT(ccb->llcc_exp->exp_obd == ccb->llcc_tgt->lut_obd);
- if (th->th_reserved_quota.qrr_count > 0) {
- struct lu_env temp_env;
- int rc;
-
+ if (th->th_reserved_quota.lqi_space > 0) {
CDEBUG(D_QUOTA, "free quota %llu %llu\n",
- th->th_reserved_quota.qrr_id.qid_gid,
- th->th_reserved_quota.qrr_count);
-
- rc = lu_env_init(&temp_env, LCT_DT_THREAD);
- if (rc) {
- CERROR("%s: can't initialize environment: rc = %d\n",
- ccb->llcc_tgt->lut_obd->obd_name, rc);
- goto out;
- }
+ th->th_reserved_quota.lqi_id.qid_gid,
+ th->th_reserved_quota.lqi_space);
- dt_reserve_or_free_quota(&temp_env, th->th_dev,
- th->th_reserved_quota.qrr_type,
- th->th_reserved_quota.qrr_id.qid_uid,
- th->th_reserved_quota.qrr_id.qid_gid,
- -th->th_reserved_quota.qrr_count,
- false);
- lu_env_fini(&temp_env);
+ /* env can be NULL for freeing reserved quota */
+ th->th_reserved_quota.lqi_space *= -1;
+ dt_reserve_or_free_quota(NULL, th->th_dev,
+ &th->th_reserved_quota);
}
/* error hit, don't update last committed to provide chance to