/* Simple wrapper on top of qsd API which implement quota transfer for osd * setattr needs. As a reminder, only the root user can change ownership of * a file, that's why EDQUOT & EINPROGRESS errors are discarded */ 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) { int rc; if (unlikely(qsd == NULL)) return 0; LASSERT(qtype >= 0 && qtype < MAXQUOTAS); qi->lqi_type = qtype; /* inode accounting */ qi->lqi_is_blk = false; /* one more inode for the new owner ... */ qi->lqi_id.qid_uid = new_id; qi->lqi_space = 1; rc = qsd_op_begin(env, qsd, trans, qi, NULL); if (rc == -EDQUOT || rc == -EINPROGRESS) rc = 0; if (rc) return rc; /* and one less inode for the current id */ qi->lqi_id.qid_uid = orig_id;; qi->lqi_space = -1; /* can't get EDQUOT when reducing usage */ rc = qsd_op_begin(env, qsd, trans, qi, NULL); if (rc == -EINPROGRESS) rc = 0; if (rc) return rc; /* block accounting */ qi->lqi_is_blk = true; /* more blocks for the new owner ... */ qi->lqi_id.qid_uid = new_id; qi->lqi_space = bspace; rc = qsd_op_begin(env, qsd, trans, qi, NULL); if (rc == -EDQUOT || rc == -EINPROGRESS) rc = 0; if (rc) return rc; /* and finally less blocks for the current owner */ qi->lqi_id.qid_uid = orig_id; qi->lqi_space = -bspace; rc = qsd_op_begin(env, qsd, trans, qi, NULL); /* can't get EDQUOT when reducing usage */ if (rc == -EINPROGRESS) rc = 0; return rc; }
/* * Wrapper for qsd_op_begin(). * * \param env - the environment passed by the caller * \param osd - is the osd_device * \param uid - user id of the inode * \param gid - group id of the inode * \param space - how many blocks/inodes will be consumed/released * \param oh - osd transaction handle * \param is_blk - block quota or inode quota? * \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 * can't failed with EDQUOT * * \retval 0 - success * \retval -ve - failure */ int osd_declare_quota(const struct lu_env *env, struct osd_device *osd, qid_t uid, qid_t gid, long long space, struct osd_thandle *oh, bool is_blk, int *flags, bool force) { struct osd_thread_info *info = osd_oti_get(env); struct lquota_id_info *qi = &info->oti_qi; struct qsd_instance *qsd = osd->od_quota_slave; int rcu, rcg; /* user & group rc */ ENTRY; if (unlikely(qsd == NULL)) /* quota slave instance hasn't been allocated yet */ RETURN(0); /* let's start with user quota */ qi->lqi_id.qid_uid = uid; qi->lqi_type = USRQUOTA; qi->lqi_space = space; qi->lqi_is_blk = is_blk; rcu = qsd_op_begin(env, qsd, &oh->ot_quota_trans, qi, flags); if (force && (rcu == -EDQUOT || rcu == -EINPROGRESS)) /* ignore EDQUOT & EINPROGRESS when changes are done by root */ rcu = 0; /* For non-fatal error, we want to continue to get the noquota flags * for group id. This is only for commit write, which has @flags passed * in. See osd_declare_write_commit(). * When force is set to true, we also want to proceed with the gid */ if (rcu && (rcu != -EDQUOT || flags == NULL)) RETURN(rcu); /* and now group quota */ qi->lqi_id.qid_gid = gid; qi->lqi_type = GRPQUOTA; rcg = qsd_op_begin(env, qsd, &oh->ot_quota_trans, qi, flags); if (force && (rcg == -EDQUOT || rcg == -EINPROGRESS)) /* as before, ignore EDQUOT & EINPROGRESS for root */ rcg = 0; RETURN(rcu ? rcu : rcg); }