Exemple #1
0
/*
 * Retrieve quota settings for a given identifier.
 *
 * \param env     - is the environment passed by the caller
 * \param qmt     - is the quota master target
 * \param pool_id - is the 16-bit pool identifier
 * \param restype - is the pool type, either block (i.e. LQUOTA_RES_DT) or inode
 *                  (i.e. LQUOTA_RES_MD)
 * \param qtype   - is the quota type
 * \param id      - is the quota indentifier for which we want to acces quota
 *                  settings.
 * \param hard    - is the output variable where to copy the hard limit
 * \param soft    - is the output variable where to copy the soft limit
 * \param time    - is the output variable where to copy the grace time
 */
static int qmt_get(const struct lu_env *env, struct qmt_device *qmt,
		   __u16 pool_id, __u8 restype, __u8 qtype, union lquota_id *id,
		   __u64 *hard, __u64 *soft, __u64 *time)
{
	struct lquota_entry	*lqe;
	ENTRY;

	/* look-up lqe structure containing quota settings */
	lqe = qmt_pool_lqe_lookup(env, qmt, pool_id, restype, qtype, id);
	if (IS_ERR(lqe))
		RETURN(PTR_ERR(lqe));

	/* copy quota settings */
	lqe_read_lock(lqe);
	LQUOTA_DEBUG(lqe, "fetch settings");
	if (hard != NULL)
		*hard = lqe->lqe_hardlimit;
	if (soft != NULL)
		*soft = lqe->lqe_softlimit;
	if (time != NULL)
		*time = lqe->lqe_gracetime;
	lqe_read_unlock(lqe);

	lqe_putref(lqe);
	RETURN(0);
}
Exemple #2
0
/**
 * Trigger pre-acquire/release if necessary.
 * It's only used by ldiskfs osd so far. When unlink a file in ldiskfs, the
 * quota accounting isn't updated when the transaction stopped. Instead, it'll
 * be updated on the final iput, so qsd_op_adjust() will be called then (in
 * osd_object_delete()) to trigger quota release if necessary.
 *
 * \param env - the environment passed by the caller
 * \param qsd - is the qsd instance associated with the device in charge
 *              of the operation.
 * \param qid - is the lquota ID of the user/group for which to trigger
 *              quota space adjustment
 * \param qtype - is the quota type (USRQUOTA or GRPQUOTA)
 */
void qsd_op_adjust(const struct lu_env *env, struct qsd_instance *qsd,
		   union lquota_id *qid, int qtype)
{
	struct lquota_entry    *lqe;
	struct qsd_qtype_info  *qqi;
	bool			adjust;
	ENTRY;

	if (unlikely(qsd == NULL))
		RETURN_EXIT;

	/* 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_EXIT;
	}
	read_unlock(&qsd->qsd_lock);

	qqi = qsd->qsd_type_array[qtype];
	LASSERT(qqi);

	if (!qsd_type_enabled(qsd, qtype) || qqi->qqi_acct_obj == NULL ||
	    qid->qid_uid == 0)
		RETURN_EXIT;

	read_lock(&qsd->qsd_lock);
	if (!qsd->qsd_started) {
		read_unlock(&qsd->qsd_lock);
		RETURN_EXIT;
	}
	read_unlock(&qsd->qsd_lock);

	lqe = lqe_locate(env, qqi->qqi_site, qid);
	if (IS_ERR(lqe)) {
		CERROR("%s: fail to locate lqe for id:"LPU64", type:%d\n",
		       qsd->qsd_svname, qid->qid_uid, qtype);
		RETURN_EXIT;
	}

	qsd_refresh_usage(env, lqe);

	lqe_read_lock(lqe);
	adjust = qsd_adjust_needed(lqe);
	lqe_read_unlock(lqe);

	if (adjust)
		qsd_adjust(env, lqe);

	lqe_putref(lqe);
	EXIT;
}
Exemple #3
0
/**
 * Quota enforcement handler. If local quota can satisfy this operation,
 * return success, otherwise, acquire more quota from master.
 * (for write operation, if master isn't available at this moment, return
 * -EINPROGRESS to inform client to retry the write)
 *
 * \param env   - the environment passed by the caller
 * \param qsd   - is the qsd instance associated with the device in charge
 *                of the operation.
 * \param qid   - is the qid information attached in the transaction handle
 * \param space - is the space required by the operation
 * \param flags - if the operation is write, return caller no user/group
 *                and sync commit flags
 *
 * \retval 0            - success
 * \retval -EDQUOT      - out of quota
 * \retval -EINPROGRESS - inform client to retry write
 * \retval -ve          - other appropriate errors
 */
static int qsd_op_begin0(const struct lu_env *env, struct qsd_qtype_info *qqi,
			 struct lquota_id_info *qid, long long space,
			 int *flags)
{
	struct lquota_entry	*lqe;
	int			 rc, ret = -EINPROGRESS;
	struct l_wait_info	 lwi;
	ENTRY;

	if (qid->lqi_qentry != NULL) {
		/* we already had to deal with this id for this transaction */
		lqe = qid->lqi_qentry;
		if (!lqe->lqe_enforced)
			RETURN(0);
	} else {
		/* look up lquota entry associated with qid */
		lqe = lqe_locate(env, qqi->qqi_site, &qid->lqi_id);
		if (IS_ERR(lqe))
			RETURN(PTR_ERR(lqe));
		if (!lqe->lqe_enforced) {
			lqe_putref(lqe);
			RETURN(0);
		}
		qid->lqi_qentry = lqe;
		/* lqe will be released in qsd_op_end() */
	}

	if (space <= 0) {
		/* when space is negative or null, we don't need to consume
		 * quota space. That said, we still want to perform space
		 * adjustments in qsd_op_end, so we return here, but with
		 * a reference on the lqe */
		if (flags != NULL) {
			rc = qsd_refresh_usage(env, lqe);
			GOTO(out_flags, rc);
		}
		RETURN(0);
	}

	LQUOTA_DEBUG(lqe, "op_begin space:"LPD64, space);

	lqe_write_lock(lqe);
	lqe->lqe_waiting_write += space;
	lqe_write_unlock(lqe);

	/* acquire quota space for the operation, cap overall wait time to
	 * prevent a service thread from being stuck for too long */
	lwi = LWI_TIMEOUT(cfs_time_seconds(qsd_wait_timeout(qqi->qqi_qsd)),
			  NULL, NULL);
	rc = l_wait_event(lqe->lqe_waiters, qsd_acquire(env, lqe, space, &ret),
			  &lwi);

	if (rc == 0 && ret == 0) {
		qid->lqi_space += space;
	} else {
		if (rc == 0)
			rc = ret;

		LQUOTA_DEBUG(lqe, "acquire quota failed:%d", rc);

		lqe_write_lock(lqe);
		lqe->lqe_waiting_write -= space;

		if (flags && lqe->lqe_pending_write != 0)
			/* Inform OSD layer that there are pending writes.
			 * It might want to retry after a sync if appropriate */
			 *flags |= QUOTA_FL_SYNC;
		lqe_write_unlock(lqe);

		/* convert recoverable error into -EINPROGRESS, client will
		 * retry */
		if (rc == -ETIMEDOUT || rc == -ENOTCONN || rc == -ENOLCK ||
		    rc == -EAGAIN || rc == -EINTR) {
			rc = -EINPROGRESS;
		} else if (rc == -ESRCH) {
			rc = 0;
			LQUOTA_ERROR(lqe, "ID isn't enforced on master, it "
				     "probably due to a legeal race, if this "
				     "message is showing up constantly, there "
				     "could be some inconsistence between "
				     "master & slave, and quota reintegration "
				     "needs be re-triggered.");
		}
	}

	if (flags != NULL) {
out_flags:
		LASSERT(qid->lqi_is_blk);
		if (rc != 0) {
			*flags |= LQUOTA_OVER_FL(qqi->qqi_qtype);
		} else {
			__u64	usage;

			lqe_read_lock(lqe);
			usage  = lqe->lqe_usage;
			usage += lqe->lqe_pending_write;
			usage += lqe->lqe_waiting_write;
			usage += qqi->qqi_qsd->qsd_sync_threshold;

			/* if we should notify client to start sync write */
			if (usage >= lqe->lqe_granted - lqe->lqe_pending_rel)
				*flags |= LQUOTA_OVER_FL(qqi->qqi_qtype);
			else
				*flags &= ~LQUOTA_OVER_FL(qqi->qqi_qtype);
			lqe_read_unlock(lqe);
		}
	}
	RETURN(rc);
}