Whamcloud - gitweb
LU-11303 quota: enforce block quota for chgrp 96/33996/17
authorHongchao Zhang <hongchao@whamcloud.com>
Fri, 2 Apr 2021 06:53:59 +0000 (14:53 +0800)
committerOleg Drokin <green@whamcloud.com>
Wed, 25 Aug 2021 06:22:42 +0000 (06:22 +0000)
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 <hongchao@whamcloud.com>
Change-Id: I40556b9e8a0628eb18aa806d2f6b3dfb9b53e874
Reviewed-on: https://review.whamcloud.com/33996
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Wang Shilong <wangshilong1991@gmail.com>
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
13 files changed:
lustre/include/dt_object.h
lustre/include/lustre_quota.h
lustre/llite/llite_lib.c
lustre/mdd/mdd_object.c
lustre/osd-ldiskfs/osd_handler.c
lustre/osd-ldiskfs/osd_quota.c
lustre/osd-zfs/osd_handler.c
lustre/osd-zfs/osd_object.c
lustre/osd-zfs/osd_quota.c
lustre/quota/qsd_handler.c
lustre/target/out_lib.c
lustre/target/tgt_lastrcvd.c
lustre/tests/sanity-quota.sh

index d36e1c7..f24d7d3 100644 (file)
@@ -312,8 +312,33 @@ struct dt_device_operations {
         * \retval 0            on success
         * \retval negative     negated errno on error
         */
         * \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 {
 };
 
 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_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
 /**
  * This is the general purpose transaction handle.
  * 1. Transaction Life Cycle
@@ -1987,6 +2018,9 @@ struct thandle {
         * callback mechanism */
        struct thandle  *th_top;
 
         * 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;
        /** 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);
 }
 
         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,
 static inline int dt_lookup(const struct lu_env *env,
                            struct dt_object *dt,
                            struct dt_rec *rec,
index 59406ee..53b6312 100644 (file)
@@ -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);
                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
 
 /*
  * 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 *);
  * 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 */
 /** @} quota */
 #endif /* _LUSTRE_QUOTA_H */
index 2f9cf59..fec9d10 100644 (file)
@@ -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)
 {
 
 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) {
 
        rc = md_setattr(sbi->ll_md_exp, op_data, NULL, 0, &request);
        if (rc) {
index 3a74d17..3742191 100644 (file)
@@ -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;
        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;
        bool chrgrp_by_unprivileged_user = false;
+       __s64 quota_size = 0;
        int rc;
        ENTRY;
 
        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) {
        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
                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);
 
                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);
 
        if (handle != NULL)
                rc = mdd_trans_stop(env, mdd, rc, handle);
 
index f2fedaa..05dc11b 100644 (file)
@@ -2572,18 +2572,42 @@ const int osd_dto_credits_noquota[DTO_NR] = {
        [DTO_ATTR_SET_CHOWN] = 0
 };
 
        [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 = {
 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,
 };
 
 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,
                                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);
 {
        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);
        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);
                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);
        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);
                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);
         * 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);
                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);
        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);
                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) {
         * 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,
                /* 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);
 
                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_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);
 
                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,
                                        (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);
        }
                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),
                    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
        }
 
 #endif
        }
 
index b3dc66a..530e6fc 100644 (file)
@@ -28,6 +28,7 @@
  * Author: Niu    Yawei    <niu@whamcloud.com>
  */
 
  * Author: Niu    Yawei    <niu@whamcloud.com>
  */
 
+#include <dt_object.h>
 #include <lustre_quota.h>
 #include "osd_internal.h"
 
 #include <lustre_quota.h>
 #include "osd_internal.h"
 
index 942d088..92146d6 100644 (file)
@@ -698,17 +698,39 @@ static int osd_ro(const struct lu_env *env, struct dt_device *d)
        RETURN(0);
 }
 
        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 = {
 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,
 };
 
 /*
 };
 
 /*
index a81358b..3ba6522 100644 (file)
@@ -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 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;
 
 {
        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);
        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;
                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);
        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;
                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,
                        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);
                }
                        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,
                        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);
                }
                        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,
                                          &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);
                }
                        if (rc)
                                GOTO(out, rc);
                }
index 243e3e2..2e75b8c 100644 (file)
@@ -27,6 +27,7 @@
  * Author: Johann Lombardi <johann@whamcloud.com>
  */
 
  * Author: Johann Lombardi <johann@whamcloud.com>
  */
 
+#include <dt_object.h>
 #include <lustre_quota.h>
 #include <obd.h>
 #include "osd_internal.h"
 #include <lustre_quota.h>
 #include <obd.h>
 #include "osd_internal.h"
index d40251d..ea75142 100644 (file)
@@ -1203,3 +1203,98 @@ void qsd_op_adjust(const struct lu_env *env, struct qsd_instance *qsd,
        EXIT;
 }
 EXPORT_SYMBOL(qsd_op_adjust);
        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);
index ee6eeb4..5a0c0da 100644 (file)
@@ -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 (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))
        arg = tx_add_exec(ta, out_tx_attr_set_exec, out_tx_attr_set_undo,
                          file, line);
        if (IS_ERR(arg))
index cbd9258..42d553d 100644 (file)
@@ -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);
 
        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)
        /* error hit, don't update last committed to provide chance to
         * replay data after fail */
        if (err != 0)
index 2fcf058..af8df2e 100755 (executable)
@@ -13,8 +13,8 @@ init_test_env $@
 init_logging
 
 ALWAYS_EXCEPT="$SANITY_QUOTA_EXCEPT "
 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
 # UPDATE THE COMMENT ABOVE WITH BUG NUMBERS WHEN CHANGING ALWAYS_EXCEPT!
 
 # Test duration:                   30 min