qid_t gid;
long long bspace;
int rc = 0;
- bool allocated;
+ bool enforce;
ENTRY;
LASSERT(dt != NULL);
* We still need to call the osd_declare_qid() to calculate the journal
* credits for updating quota accounting files and to trigger quota
* space adjustment once the operation is completed.*/
- if ((attr->la_valid & LA_UID) != 0 &&
- attr->la_uid != (uid = i_uid_read(obj->oo_inode))) {
+ if (attr->la_valid & LA_UID || attr->la_valid & LA_GID) {
+ /* USERQUOTA */
+ uid = i_uid_read(obj->oo_inode);
qi->lqi_type = USRQUOTA;
-
+ enforce = (attr->la_valid & LA_UID) && (attr->la_uid != uid);
/* inode accounting */
qi->lqi_is_blk = false;
- /* one more inode for the new owner ... */
+ /* one more inode for the new uid ... */
qi->lqi_id.qid_uid = attr->la_uid;
qi->lqi_space = 1;
- allocated = (attr->la_uid == 0) ? true : false;
- rc = osd_declare_qid(env, oh, qi, allocated, NULL);
+ /* Reserve credits for the new uid */
+ rc = osd_declare_qid(env, oh, qi, NULL, enforce, NULL);
if (rc == -EDQUOT || rc == -EINPROGRESS)
rc = 0;
if (rc)
/* and one less inode for the current uid */
qi->lqi_id.qid_uid = uid;
qi->lqi_space = -1;
- rc = osd_declare_qid(env, oh, qi, true, NULL);
+ rc = osd_declare_qid(env, oh, qi, obj, enforce, NULL);
if (rc == -EDQUOT || rc == -EINPROGRESS)
rc = 0;
if (rc)
/* block accounting */
qi->lqi_is_blk = true;
- /* more blocks for the new owner ... */
+ /* more blocks for the new uid ... */
qi->lqi_id.qid_uid = attr->la_uid;
qi->lqi_space = bspace;
- allocated = (attr->la_uid == 0) ? true : false;
- rc = osd_declare_qid(env, oh, qi, allocated, NULL);
+ /*
+ * Credits for the new uid has been reserved, re-use "obj"
+ * to save credit reservation.
+ */
+ rc = osd_declare_qid(env, oh, qi, obj, enforce, NULL);
if (rc == -EDQUOT || rc == -EINPROGRESS)
rc = 0;
if (rc)
RETURN(rc);
- /* and finally less blocks for the current owner */
+ /* and finally less blocks for the current uid */
qi->lqi_id.qid_uid = uid;
qi->lqi_space = -bspace;
- rc = osd_declare_qid(env, oh, qi, true, NULL);
+ rc = osd_declare_qid(env, oh, qi, obj, enforce, NULL);
if (rc == -EDQUOT || rc == -EINPROGRESS)
rc = 0;
if (rc)
RETURN(rc);
- }
- if (attr->la_valid & LA_GID &&
- attr->la_gid != (gid = i_gid_read(obj->oo_inode))) {
+ /* GROUP QUOTA */
+ gid = i_gid_read(obj->oo_inode);
qi->lqi_type = GRPQUOTA;
+ enforce = (attr->la_valid & LA_GID) && (attr->la_gid != gid);
/* inode accounting */
qi->lqi_is_blk = false;
- /* one more inode for the new group owner ... */
+ /* one more inode for the new gid ... */
qi->lqi_id.qid_gid = attr->la_gid;
qi->lqi_space = 1;
- allocated = (attr->la_gid == 0) ? true : false;
- rc = osd_declare_qid(env, oh, qi, allocated, NULL);
+ rc = osd_declare_qid(env, oh, qi, NULL, enforce, NULL);
if (rc == -EDQUOT || rc == -EINPROGRESS)
rc = 0;
if (rc)
/* and one less inode for the current gid */
qi->lqi_id.qid_gid = gid;
qi->lqi_space = -1;
- rc = osd_declare_qid(env, oh, qi, true, NULL);
+ rc = osd_declare_qid(env, oh, qi, obj, enforce, NULL);
if (rc == -EDQUOT || rc == -EINPROGRESS)
rc = 0;
if (rc)
/* block accounting */
qi->lqi_is_blk = true;
- /* more blocks for the new owner ... */
+ /* more blocks for the new gid ... */
qi->lqi_id.qid_gid = attr->la_gid;
qi->lqi_space = bspace;
- allocated = (attr->la_gid == 0) ? true : false;
- rc = osd_declare_qid(env, oh, qi, allocated, NULL);
+ rc = osd_declare_qid(env, oh, qi, obj, enforce, NULL);
if (rc == -EDQUOT || rc == -EINPROGRESS)
rc = 0;
if (rc)
RETURN(rc);
- /* and finally less blocks for the current owner */
+ /* and finally less blocks for the current gid */
qi->lqi_id.qid_gid = gid;
qi->lqi_space = -bspace;
- rc = osd_declare_qid(env, oh, qi, true, NULL);
+ rc = osd_declare_qid(env, oh, qi, obj, enforce, NULL);
if (rc == -EDQUOT || rc == -EINPROGRESS)
rc = 0;
if (rc)
struct iattr iattr;
int rc;
+ ll_vfs_dq_init(inode);
iattr.ia_valid = 0;
if (attr->la_valid & LA_UID)
iattr.ia_valid |= ATTR_UID;
}
inode = obj->oo_inode;
- ll_vfs_dq_init(inode);
rc = osd_quota_transfer(inode, attr);
if (rc)
RETURN(0);
rc = osd_declare_inode_qid(env, attr->la_uid, attr->la_gid, 1, oh,
- false, false, NULL, false);
+ osd_dt_obj(dt), false, NULL, false);
if (rc != 0)
RETURN(rc);
osd_dto_credits_noquota[DTO_INDEX_DELETE] + 3);
/* one less inode */
rc = osd_declare_inode_qid(env, i_uid_read(inode), i_gid_read(inode),
- -1, oh, false, true, NULL, false);
+ -1, oh, obj, false, NULL, false);
if (rc)
RETURN(rc);
/* data to be truncated */
rc = osd_declare_inode_qid(env, i_uid_read(inode), i_gid_read(inode),
- 0, oh, true, true, NULL, false);
+ 0, oh, obj, true, NULL, false);
RETURN(rc);
}
{
struct osd_thandle *oh;
int credits;
+ struct super_block *sb = osd_sb(osd_dev(dt->do_lu.lo_dev));
LASSERT(handle != NULL);
} else if (strcmp(name, XATTR_NAME_VERSION) == 0) {
credits = 1;
} else {
- struct osd_device *osd = osd_dev(dt->do_lu.lo_dev);
- struct super_block *sb = osd_sb(osd);
credits = osd_dto_credits_noquota[DTO_XATTR_SET];
if (buf && buf->lb_len > sb->s_blocksize) {
credits *= (buf->lb_len + sb->s_blocksize - 1) >>
sb->s_blocksize_bits;
}
+ /*
+ * xattr set may involve inode quota change, reserve credits for
+ * dquot_initialize()
+ */
+ oh->ot_credits += LDISKFS_MAXQUOTAS_INIT_BLOCKS(sb);
}
osd_trans_declare_op(env, oh, OSD_OT_XATTR_SET, credits);
struct thandle *handle)
{
struct osd_thandle *oh;
+ struct super_block *sb = osd_sb(osd_dev(dt->do_lu.lo_dev));
LASSERT(dt_object_exists(dt) && !dt_object_remote(dt));
LASSERT(handle != NULL);
osd_trans_declare_op(env, oh, OSD_OT_XATTR_SET,
osd_dto_credits_noquota[DTO_XATTR_SET]);
+ /*
+ * xattr del may involve inode quota change, reserve credits for
+ * dquot_initialize()
+ */
+ oh->ot_credits += LDISKFS_MAXQUOTAS_INIT_BLOCKS(sb);
return 0;
}
LASSERT(inode);
rc = osd_declare_inode_qid(env, i_uid_read(inode), i_gid_read(inode),
- 0, oh, true, true, NULL, false);
+ 0, oh, osd_dt_obj(dt), true, NULL, false);
RETURN(rc);
}
* calculate how many blocks will be consumed by this index
* insert */
rc = osd_declare_inode_qid(env, i_uid_read(inode),
- i_gid_read(inode), 0,
- oh, true, true, NULL, false);
+ i_gid_read(inode), 0, oh,
+ osd_dt_obj(dt), true, NULL, false);
}
if (fid == NULL)
* Reserve journal credits for quota files update first, then call
* ->op_begin() to perform quota enforcement.
*
- * \param env - the environment passed by the caller
- * \param oh - osd transaction handle
- * \param qi - quota id & space required for this operation
- * \param allocated - dquot entry in quota accounting file has been allocated
- * \param flags - if the operation is write, return no user quota, no
- * group quota, or sync commit flags to the caller
+ * \param env - the environment passed by the caller
+ * \param oh - osd transaction handle
+ * \param qi - quota id & space required for this operation
+ * \param obj - osd object, could be NULL when it's under create
+ * \param enforce - whether to perform quota enforcement
+ * \param flags - if the operation is write, return no user quota, no
+ * group quota, or sync commit flags to the caller
*
- * \retval 0 - success
- * \retval -ve - failure
+ * \retval 0 - success
+ * \retval -ve - failure
*/
int osd_declare_qid(const struct lu_env *env, struct osd_thandle *oh,
- struct lquota_id_info *qi, bool allocated, int *flags)
+ struct lquota_id_info *qi, struct osd_object *obj,
+ bool enforce, int *flags)
{
struct osd_thread_info *info = osd_oti_get(env);
struct osd_device *dev = info->oti_dev;
struct qsd_instance *qsd = dev->od_quota_slave;
- int i, rc;
+ struct inode *inode = NULL;
+ int i, rc = 0;
bool found = false;
ENTRY;
RETURN(-EOVERFLOW);
}
+ if (obj != NULL)
+ inode = obj->oo_inode;
osd_trans_declare_op(env, oh, OSD_OT_QUOTA,
- (allocated || qi->lqi_id.qid_uid == 0) ?
+ (qi->lqi_id.qid_uid == 0 ||
+ (inode != NULL &&
+ inode->i_dquot[qi->lqi_type] != NULL)) ?
1: LDISKFS_QUOTA_INIT_BLOCKS(osd_sb(dev)));
oh->ot_id_array[i] = qi->lqi_id.qid_uid;
RETURN(0);
/* check quota */
- rc = qsd_op_begin(env, qsd, oh->ot_quota_trans, qi, flags);
+ if (enforce)
+ rc = qsd_op_begin(env, qsd, oh->ot_quota_trans, qi, flags);
RETURN(rc);
}
* \param gid - group id of the inode
* \param space - how many blocks/inodes will be consumed/released
* \param oh - osd transaction handle
+ * \param obj - osd object, could be NULL when it's under create
* \param is_blk - block quota or inode quota?
- * \param allocated - dquot entry in quota accounting file has been allocated
* \param flags - if the operation is write, return no user quota, no
* group quota, or sync commit flags to the caller
* \param force - set to 1 when changes are performed by root user and thus
*/
int osd_declare_inode_qid(const struct lu_env *env, qid_t uid, qid_t gid,
long long space, struct osd_thandle *oh,
- bool is_blk, bool allocated, int *flags, bool force)
+ struct osd_object *obj, bool is_blk, int *flags,
+ bool force)
{
struct osd_thread_info *info = osd_oti_get(env);
struct lquota_id_info *qi = &info->oti_qi;
qi->lqi_type = USRQUOTA;
qi->lqi_space = space;
qi->lqi_is_blk = is_blk;
- rcu = osd_declare_qid(env, oh, qi, allocated, flags);
+ rcu = osd_declare_qid(env, oh, qi, obj, true, flags);
if (force && (rcu == -EDQUOT || rcu == -EINPROGRESS))
/* ignore EDQUOT & EINPROGRESS when changes are done by root */
/* and now group quota */
qi->lqi_id.qid_gid = gid;
qi->lqi_type = GRPQUOTA;
- rcg = osd_declare_qid(env, oh, qi, allocated, flags);
+ rcg = osd_declare_qid(env, oh, qi, obj, true, flags);
if (force && (rcg == -EDQUOT || rcg == -EINPROGRESS))
/* as before, ignore EDQUOT & EINPROGRESS for root */