From 83f5544d8518ad12ea49e27829fff8f2739b86e2 Mon Sep 17 00:00:00 2001 From: Hongchao Zhang Date: Fri, 2 Apr 2021 14:53:59 +0800 Subject: [PATCH] LU-11303 quota: enforce block quota for chgrp In patch https://review.whamcloud.com/30146 "LU-5152 quota: enforce block quota for chgrp", problems were introduced due to synchronous requests from the MDS to the OSS to change the quota assignment of files during chgrp operations. However, in some cases, the OSTs are themselves out of grant and may send a quota request to the MDS, which may result in a deadlock. Another issue is the slow performance caused by the synchronous operation between MDT and OSTs. This patch drops the synchronous RPC requirement of the original patch #30146 to avoid this problem. Previously, problems in quota tracking related to chgrp were introduced due to synchronous RPCs from the MDS to the OSS when changing the group ownership of objects for quota tracking since Fixes: 8a71fd5061b ("LU-5152 quota: enforce block quota for chgrp") Signed-off-by: Hongchao Zhang Change-Id: I40556b9e8a0628eb18aa806d2f6b3dfb9b53e874 Reviewed-on: https://review.whamcloud.com/33996 Reviewed-by: Andreas Dilger Reviewed-by: Wang Shilong Tested-by: jenkins Tested-by: Maloo Reviewed-by: Oleg Drokin --- lustre/include/dt_object.h | 50 ++++++++++++++++++++- lustre/include/lustre_quota.h | 27 ++++++++++++ lustre/llite/llite_lib.c | 32 +++++++++----- lustre/mdd/mdd_object.c | 53 +++++++++++++++++++--- lustre/osd-ldiskfs/osd_handler.c | 74 ++++++++++++++++++------------- lustre/osd-ldiskfs/osd_quota.c | 1 + lustre/osd-zfs/osd_handler.c | 42 +++++++++++++----- lustre/osd-zfs/osd_object.c | 14 +++--- lustre/osd-zfs/osd_quota.c | 1 + lustre/quota/qsd_handler.c | 95 ++++++++++++++++++++++++++++++++++++++++ lustre/target/out_lib.c | 4 -- lustre/target/tgt_lastrcvd.c | 24 ++++++++++ lustre/tests/sanity-quota.sh | 4 +- 13 files changed, 350 insertions(+), 71 deletions(-) diff --git a/lustre/include/dt_object.h b/lustre/include/dt_object.h index d36e1c7..f24d7d3 100644 --- a/lustre/include/dt_object.h +++ b/lustre/include/dt_object.h @@ -312,8 +312,33 @@ struct dt_device_operations { * \retval 0 on success * \retval negative negated errno on error */ - int (*dt_commit_async)(const struct lu_env *env, - struct dt_device *dev); + int (*dt_commit_async)(const struct lu_env *env, + 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 + * a directory with a different group ID. + * + * If \a count < 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 + * + * \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 dt_index_features { @@ -1961,6 +1986,12 @@ static inline struct dt_object *dt_object_child(struct dt_object *o) 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 @@ -1987,6 +2018,9 @@ struct thandle { * callback mechanism */ struct thandle *th_top; + /* reserved quota for this handle */ + struct dt_quota_reserve_rec th_reserved_quota; + /** the last operation result in this transaction. * this value is used in recovery */ __s32 th_result; @@ -2902,6 +2936,18 @@ static inline int dt_commit_async(const struct lu_env *env, return dev->dd_ops->dt_commit_async(env, dev); } +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) +{ + 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); +} + static inline int dt_lookup(const struct lu_env *env, struct dt_object *dt, struct dt_rec *rec, diff --git a/lustre/include/lustre_quota.h b/lustre/include/lustre_quota.h index 59406ee..53b6312 100644 --- a/lustre/include/lustre_quota.h +++ b/lustre/include/lustre_quota.h @@ -196,6 +196,9 @@ void qsd_op_end(const struct lu_env *, struct qsd_instance *, struct lquota_trans *); void qsd_op_adjust(const struct lu_env *, struct qsd_instance *, union lquota_id *, int); +int qsd_reserve_or_free_quota(const struct lu_env *env, + struct qsd_instance *qsd, + struct lquota_id_info *qi); /* * Quota information attached to a transaction @@ -244,5 +247,29 @@ struct lquota_trans { * 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 */ diff --git a/lustre/llite/llite_lib.c b/lustre/llite/llite_lib.c index 2f9cf59..fec9d10 100644 --- a/lustre/llite/llite_lib.c +++ b/lustre/llite/llite_lib.c @@ -1794,17 +1794,29 @@ void ll_clear_inode(struct inode *inode) static int ll_md_setattr(struct dentry *dentry, struct md_op_data *op_data) { - struct lustre_md md; - struct inode *inode = dentry->d_inode; - struct ll_sb_info *sbi = ll_i2sbi(inode); - struct ptlrpc_request *request = NULL; - int rc, ia_valid; - ENTRY; + struct lustre_md md; + struct inode *inode = dentry->d_inode; + struct ll_sb_info *sbi = ll_i2sbi(inode); + struct ptlrpc_request *request = NULL; + int rc, ia_valid; + + ENTRY; + + op_data = ll_prep_md_op_data(op_data, inode, NULL, NULL, 0, 0, + LUSTRE_OPC_ANY, NULL); + if (IS_ERR(op_data)) + RETURN(PTR_ERR(op_data)); + + /* If this is a chgrp of a regular file, we want to reserve enough + * quota to cover the entire file size. + */ + if (S_ISREG(inode->i_mode) && op_data->op_attr.ia_valid & ATTR_GID && + from_kgid(&init_user_ns, op_data->op_attr.ia_gid) != + from_kgid(&init_user_ns, inode->i_gid)) { + op_data->op_xvalid |= OP_XVALID_BLOCKS; + op_data->op_attr_blocks = inode->i_blocks; + } - op_data = ll_prep_md_op_data(op_data, inode, NULL, NULL, 0, 0, - LUSTRE_OPC_ANY, NULL); - if (IS_ERR(op_data)) - RETURN(PTR_ERR(op_data)); rc = md_setattr(sbi->ll_md_exp, op_data, NULL, 0, &request); if (rc) { diff --git a/lustre/mdd/mdd_object.c b/lustre/mdd/mdd_object.c index 3a74d17..3742191 100644 --- a/lustre/mdd/mdd_object.c +++ b/lustre/mdd/mdd_object.c @@ -1217,7 +1217,9 @@ int mdd_attr_set(const struct lu_env *env, struct md_object *obj, struct lu_attr *attr = MDD_ENV_VAR(env, cattr); const struct lu_attr *la = &ma->ma_attr; struct lu_ucred *uc; + bool quota_reserved = false; bool chrgrp_by_unprivileged_user = false; + __s64 quota_size = 0; int rc; ENTRY; @@ -1250,11 +1252,37 @@ int mdd_attr_set(const struct lu_env *env, struct md_object *obj, uc = lu_ucred_check(env); if (S_ISREG(attr->la_mode) && la->la_valid & LA_GID && la->la_gid != attr->la_gid && uc != NULL && uc->uc_fsuid != 0) { - /* LU-10048: disable synchronous chgrp operation for it will - * cause deadlock between MDT and OST. - la_copy->la_valid |= LA_FLAGS; - la_copy->la_flags |= LUSTRE_SET_SYNC_FL; - */ + 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; + else if (la->la_valid & LA_SIZE) + quota_size = la->la_size; + /* use local attr gotten above */ + else if (attr->la_valid & LA_BLOCKS) + quota_size = attr->la_blocks << 9; + else if (attr->la_valid & LA_SIZE) + quota_size = attr->la_size; + + if (quota_size > 0) { + rc = dt_reserve_or_free_quota(env, mdd->mdd_bottom, + GRPQUOTA, attr->la_uid, + la->la_gid, quota_size, + false); + + 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); + + GOTO(out, rc); + } + + quota_reserved = true; + la_copy->la_valid |= LA_FLAGS; + } + chrgrp_by_unprivileged_user = true; /* Flush the possible existing client setattr requests to OSTs @@ -1330,6 +1358,21 @@ out: rc = mdd_attr_set_changelog(env, obj, handle, &ma->ma_pfid, la_copy->la_valid); + if (rc == 0 && quota_reserved) { + struct thandle *sub_th; + + 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); + } 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; + } + } + if (handle != NULL) rc = mdd_trans_stop(env, mdd, rc, handle); diff --git a/lustre/osd-ldiskfs/osd_handler.c b/lustre/osd-ldiskfs/osd_handler.c index f2fedaa..05dc11b 100644 --- a/lustre/osd-ldiskfs/osd_handler.c +++ b/lustre/osd-ldiskfs/osd_handler.c @@ -2572,18 +2572,42 @@ const int osd_dto_credits_noquota[DTO_NR] = { [DTO_ATTR_SET_CHOWN] = 0 }; +/* 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) +{ + 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; + + ENTRY; + + if (is_md) + qsd = osd->od_quota_slave_md; + else + qsd = osd->od_quota_slave_dt; + + rc = quota_reserve_or_free(env, qsd, qi, type, uid, gid, count, is_md); + RETURN(rc); +} + static const struct dt_device_operations osd_dt_ops = { - .dt_root_get = osd_root_get, - .dt_statfs = osd_statfs, - .dt_trans_create = osd_trans_create, - .dt_trans_start = osd_trans_start, - .dt_trans_stop = osd_trans_stop, - .dt_trans_cb_add = osd_trans_cb_add, - .dt_conf_get = osd_conf_get, - .dt_mnt_sb_get = osd_mnt_sb_get, - .dt_sync = osd_sync, - .dt_ro = osd_ro, - .dt_commit_async = osd_commit_async, + .dt_root_get = osd_root_get, + .dt_statfs = osd_statfs, + .dt_trans_create = osd_trans_create, + .dt_trans_start = osd_trans_start, + .dt_trans_stop = osd_trans_stop, + .dt_trans_cb_add = osd_trans_cb_add, + .dt_conf_get = osd_conf_get, + .dt_mnt_sb_get = osd_mnt_sb_get, + .dt_sync = osd_sync, + .dt_ro = osd_ro, + .dt_commit_async = osd_commit_async, + .dt_reserve_or_free_quota = osd_reserve_or_free_quota, }; static void osd_read_lock(const struct lu_env *env, struct dt_object *dt, @@ -2781,7 +2805,7 @@ static int osd_declare_attr_qid(const struct lu_env *env, struct osd_object *obj, struct osd_thandle *oh, long long bspace, qid_t old_id, qid_t new_id, bool enforce, - unsigned int type, bool ignore_edquot) + unsigned int type) { int rc; struct osd_thread_info *info = osd_oti_get(env); @@ -2796,7 +2820,7 @@ static int osd_declare_attr_qid(const struct lu_env *env, qi->lqi_space = 1; /* Reserve credits for the new id */ rc = osd_declare_qid(env, oh, qi, NULL, enforce, NULL); - if (ignore_edquot && (rc == -EDQUOT || rc == -EINPROGRESS)) + if (rc == -EDQUOT || rc == -EINPROGRESS) rc = 0; if (rc) RETURN(rc); @@ -2805,7 +2829,7 @@ static int osd_declare_attr_qid(const struct lu_env *env, qi->lqi_id.qid_uid = old_id; qi->lqi_space = -1; rc = osd_declare_qid(env, oh, qi, obj, enforce, NULL); - if (ignore_edquot && (rc == -EDQUOT || rc == -EINPROGRESS)) + if (rc == -EDQUOT || rc == -EINPROGRESS) rc = 0; if (rc) RETURN(rc); @@ -2821,7 +2845,7 @@ static int osd_declare_attr_qid(const struct lu_env *env, * to save credit reservation. */ rc = osd_declare_qid(env, oh, qi, obj, enforce, NULL); - if (ignore_edquot && (rc == -EDQUOT || rc == -EINPROGRESS)) + if (rc == -EDQUOT || rc == -EINPROGRESS) rc = 0; if (rc) RETURN(rc); @@ -2830,7 +2854,7 @@ static int osd_declare_attr_qid(const struct lu_env *env, qi->lqi_id.qid_uid = old_id; qi->lqi_space = -bspace; rc = osd_declare_qid(env, oh, qi, obj, enforce, NULL); - if (ignore_edquot && (rc == -EDQUOT || rc == -EINPROGRESS)) + if (rc == -EDQUOT || rc == -EINPROGRESS) rc = 0; RETURN(rc); @@ -2881,20 +2905,11 @@ static int osd_declare_attr_set(const struct lu_env *env, * space adjustment once the operation is completed. */ if (attr->la_valid & LA_UID || attr->la_valid & LA_GID) { - bool ignore_edquot = !(attr->la_flags & LUSTRE_SET_SYNC_FL); - - if (!ignore_edquot) - CDEBUG(D_QUOTA, - "%s: enforce quota on UID %u, GID %u (quota space is %lld)\n", - osd_ino2name(obj->oo_inode), attr->la_uid, - attr->la_gid, bspace); - /* USERQUOTA */ uid = i_uid_read(obj->oo_inode); enforce = (attr->la_valid & LA_UID) && (attr->la_uid != uid); rc = osd_declare_attr_qid(env, obj, oh, bspace, uid, - attr->la_uid, enforce, USRQUOTA, - true); + attr->la_uid, enforce, USRQUOTA); if (rc) RETURN(rc); @@ -2903,8 +2918,7 @@ static int osd_declare_attr_set(const struct lu_env *env, attr->la_uid, gid, attr->la_gid); enforce = (attr->la_valid & LA_GID) && (attr->la_gid != gid); rc = osd_declare_attr_qid(env, obj, oh, bspace, gid, - attr->la_gid, enforce, GRPQUOTA, - ignore_edquot); + attr->la_gid, enforce, GRPQUOTA); if (rc) RETURN(rc); @@ -2917,7 +2931,7 @@ static int osd_declare_attr_set(const struct lu_env *env, (attr->la_projid != projid); rc = osd_declare_attr_qid(env, obj, oh, bspace, (qid_t)projid, (qid_t)attr->la_projid, - enforce, PRJQUOTA, true); + enforce, PRJQUOTA); if (rc) RETURN(rc); } @@ -6213,7 +6227,7 @@ static int osd_index_declare_ea_insert(const struct lu_env *env, i_projid_read(inode) != 0) rc = osd_declare_attr_qid(env, osd_dt_obj(dt), oh, 0, i_projid_read(inode), - 0, false, PRJQUOTA, true); + 0, false, PRJQUOTA); #endif } diff --git a/lustre/osd-ldiskfs/osd_quota.c b/lustre/osd-ldiskfs/osd_quota.c index b3dc66a..530e6fc 100644 --- a/lustre/osd-ldiskfs/osd_quota.c +++ b/lustre/osd-ldiskfs/osd_quota.c @@ -28,6 +28,7 @@ * Author: Niu Yawei */ +#include #include #include "osd_internal.h" diff --git a/lustre/osd-zfs/osd_handler.c b/lustre/osd-zfs/osd_handler.c index 942d088..92146d6 100644 --- a/lustre/osd-zfs/osd_handler.c +++ b/lustre/osd-zfs/osd_handler.c @@ -698,17 +698,39 @@ static int osd_ro(const struct lu_env *env, struct dt_device *d) RETURN(0); } +/* 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) +{ + 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; + + if (is_md) + qsd = osd->od_quota_slave_md; + else + qsd = osd->od_quota_slave_dt; + + rc = quota_reserve_or_free(env, qsd, qi, type, uid, gid, count, is_md); + RETURN(rc); +} + static const struct dt_device_operations osd_dt_ops = { - .dt_root_get = osd_root_get, - .dt_statfs = osd_statfs, - .dt_trans_create = osd_trans_create, - .dt_trans_start = osd_trans_start, - .dt_trans_stop = osd_trans_stop, - .dt_trans_cb_add = osd_trans_cb_add, - .dt_conf_get = osd_conf_get, - .dt_sync = osd_sync, - .dt_commit_async = osd_commit_async, - .dt_ro = osd_ro, + .dt_root_get = osd_root_get, + .dt_statfs = osd_statfs, + .dt_trans_create = osd_trans_create, + .dt_trans_start = osd_trans_start, + .dt_trans_stop = osd_trans_stop, + .dt_trans_cb_add = osd_trans_cb_add, + .dt_conf_get = osd_conf_get, + .dt_sync = osd_sync, + .dt_commit_async = osd_commit_async, + .dt_ro = osd_ro, + .dt_reserve_or_free_quota = osd_reserve_or_free_quota, }; /* diff --git a/lustre/osd-zfs/osd_object.c b/lustre/osd-zfs/osd_object.c index a81358b..3ba6522 100644 --- a/lustre/osd-zfs/osd_object.c +++ b/lustre/osd-zfs/osd_object.c @@ -1055,7 +1055,7 @@ static inline int qsd_transfer(const struct lu_env *env, struct qsd_instance *qsd, struct lquota_trans *trans, int qtype, __u64 orig_id, __u64 new_id, __u64 bspace, - struct lquota_id_info *qi, bool ignore_edquot) + struct lquota_id_info *qi) { int rc; @@ -1072,7 +1072,7 @@ static inline int qsd_transfer(const struct lu_env *env, qi->lqi_id.qid_uid = new_id; qi->lqi_space = 1; rc = qsd_op_begin(env, qsd, trans, qi, NULL); - if (ignore_edquot && (rc == -EDQUOT || rc == -EINPROGRESS)) + if (rc == -EDQUOT || rc == -EINPROGRESS) rc = 0; if (rc) return rc; @@ -1094,7 +1094,7 @@ static inline int qsd_transfer(const struct lu_env *env, qi->lqi_id.qid_uid = new_id; qi->lqi_space = bspace; rc = qsd_op_begin(env, qsd, trans, qi, NULL); - if (ignore_edquot && (rc == -EDQUOT || rc == -EINPROGRESS)) + if (rc == -EDQUOT || rc == -EINPROGRESS) rc = 0; if (rc) return rc; @@ -1181,7 +1181,7 @@ static int osd_declare_attr_set(const struct lu_env *env, rc = qsd_transfer(env, osd_def_qsd(osd), &oh->ot_quota_trans, USRQUOTA, obj->oo_attr.la_uid, attr->la_uid, - bspace, &info->oti_qi, true); + bspace, &info->oti_qi); if (rc) GOTO(out, rc); } @@ -1192,9 +1192,7 @@ static int osd_declare_attr_set(const struct lu_env *env, rc = qsd_transfer(env, osd_def_qsd(osd), &oh->ot_quota_trans, GRPQUOTA, obj->oo_attr.la_gid, attr->la_gid, - bspace, &info->oti_qi, - !(attr->la_flags & - LUSTRE_SET_SYNC_FL)); + bspace, &info->oti_qi); if (rc) GOTO(out, rc); } @@ -1230,7 +1228,7 @@ static int osd_declare_attr_set(const struct lu_env *env, &oh->ot_quota_trans, PRJQUOTA, obj->oo_attr.la_projid, attr->la_projid, bspace, - &info->oti_qi, true); + &info->oti_qi); if (rc) GOTO(out, rc); } diff --git a/lustre/osd-zfs/osd_quota.c b/lustre/osd-zfs/osd_quota.c index 243e3e2..2e75b8c 100644 --- a/lustre/osd-zfs/osd_quota.c +++ b/lustre/osd-zfs/osd_quota.c @@ -27,6 +27,7 @@ * Author: Johann Lombardi */ +#include #include #include #include "osd_internal.h" diff --git a/lustre/quota/qsd_handler.c b/lustre/quota/qsd_handler.c index d40251d..ea75142 100644 --- a/lustre/quota/qsd_handler.c +++ b/lustre/quota/qsd_handler.c @@ -1203,3 +1203,98 @@ void qsd_op_adjust(const struct lu_env *env, struct qsd_instance *qsd, EXIT; } EXPORT_SYMBOL(qsd_op_adjust); + +/** + * Reserve or free quota. + * + * Currently, It's used to reserve quota space before changing the file's group + * for normal user and free the reserved quota after the group change. + * + * \param env - the environment passed by the caller + * \param qsd - is the qsd instance associated with the device in charge of + * the operation. + * \param qi - qid & space required by current operation + * + * \retval 0 - success + * \retval -EDQUOT - out of quota + * \retval -EINPROGRESS - inform client to retry write + * \retval -ve - other appropriate errors + */ +int qsd_reserve_or_free_quota(const struct lu_env *env, + 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; + + ENTRY; + + if (unlikely(qsd == NULL)) + RETURN(0); + + if (qsd->qsd_dev->dd_rdonly) + RETURN(0); + + if (is_free) + qi->lqi_space *= -1; + + /* We don't enforce quota until the qsd_instance is started */ + read_lock(&qsd->qsd_lock); + if (!qsd->qsd_started) { + read_unlock(&qsd->qsd_lock); + RETURN(0); + } + read_unlock(&qsd->qsd_lock); + + qqi = qsd->qsd_type_array[qi->lqi_type]; + LASSERT(qqi); + + CDEBUG(D_QUOTA, "type %s, acct %s, free %d, count %llu\n", + qsd_type_enabled(qsd, qi->lqi_type) ? "enabled" : "disabled", + (qsd->qsd_type_array[qi->lqi_type])->qqi_acct_failed ? "failed" : + "succeed", is_free, qi->lqi_space); + + /* ignore quota enforcement request when: + * - quota isn't enforced for this quota type + * 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) + 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); + + if (qi->lqi_qentry != NULL) { + lqe_putref(qi->lqi_qentry); + qi->lqi_qentry = NULL; + } + } + + CDEBUG(D_QUOTA, "%s quota: type %i, uid %llu, gid %llu, space %llu\n", + is_free ? "Free" : "Reserve", qi->lqi_type, qi->lqi_id.qid_uid, + qi->lqi_id.qid_gid, qi->lqi_space); + + RETURN(rc); +} +EXPORT_SYMBOL(qsd_reserve_or_free_quota); diff --git a/lustre/target/out_lib.c b/lustre/target/out_lib.c index ee6eeb4..5a0c0da 100644 --- a/lustre/target/out_lib.c +++ b/lustre/target/out_lib.c @@ -670,10 +670,6 @@ int out_attr_set_add_exec(const struct lu_env *env, struct dt_object *dt_obj, if (rc != 0) return rc; - if (attr->la_valid & LA_FLAGS && - attr->la_flags & LUSTRE_SET_SYNC_FL) - th->th_sync |= 1; - arg = tx_add_exec(ta, out_tx_attr_set_exec, out_tx_attr_set_undo, file, line); if (IS_ERR(arg)) diff --git a/lustre/target/tgt_lastrcvd.c b/lustre/target/tgt_lastrcvd.c index cbd9258..42d553d 100644 --- a/lustre/target/tgt_lastrcvd.c +++ b/lustre/target/tgt_lastrcvd.c @@ -872,6 +872,30 @@ static void tgt_cb_last_committed(struct lu_env *env, struct thandle *th, 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; + + 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; + } + + 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); + } + /* error hit, don't update last committed to provide chance to * replay data after fail */ if (err != 0) diff --git a/lustre/tests/sanity-quota.sh b/lustre/tests/sanity-quota.sh index 2fcf058..af8df2e 100755 --- a/lustre/tests/sanity-quota.sh +++ b/lustre/tests/sanity-quota.sh @@ -13,8 +13,8 @@ init_test_env $@ init_logging ALWAYS_EXCEPT="$SANITY_QUOTA_EXCEPT " -# Bug number for skipped test: LU-5152 -ALWAYS_EXCEPT+=" 55" +# Bug number for skipped test: +ALWAYS_EXCEPT+="" # UPDATE THE COMMENT ABOVE WITH BUG NUMBERS WHEN CHANGING ALWAYS_EXCEPT! # Test duration: 30 min -- 1.8.3.1