Example #1
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;
}
Example #2
0
/**
 * Post quota operation, pre-acquire/release quota from master.
 *
 * \param  env  - the environment passed by the caller
 * \param  qsd  - is the qsd instance attached to the OSD device which
 *                is handling the operation.
 * \param  qqi  - is the qsd_qtype_info structure associated with the quota ID
 *                subject to the operation
 * \param  qid  - stores information related to his ID for the operation
 *                which has just completed
 *
 * \retval 0    - success
 * \retval -ve  - failure
 */
static void qsd_op_end0(const struct lu_env *env, struct qsd_qtype_info *qqi,
			struct lquota_id_info *qid)
{
	struct lquota_entry	*lqe;
	bool			 adjust;
	ENTRY;

	lqe = qid->lqi_qentry;
	if (lqe == NULL)
		RETURN_EXIT;
	qid->lqi_qentry = NULL;

	/* refresh cached usage if a suitable environment is passed */
	if (env != NULL)
		qsd_refresh_usage(env, lqe);

	lqe_write_lock(lqe);
	if (qid->lqi_space > 0)
		lqe->lqe_pending_write -= qid->lqi_space;
	if (env != NULL)
		adjust = qsd_adjust_needed(lqe);
	else
		adjust = true;
	lqe_write_unlock(lqe);

	if (adjust) {
		/* pre-acquire/release quota space is needed */
		if (env != NULL)
			qsd_adjust(env, lqe);
		else
			/* no suitable environment, handle adjustment in
			 * separate thread context */
			qsd_adjust_schedule(lqe, false, false);
	}
	lqe_putref(lqe);
	EXIT;
}
Example #3
0
/**
 * Blocking callback handler for per-ID lock
 *
 * \param lock - is the lock for which ast occurred.
 * \param desc - is the description of a conflicting lock in case of blocking
 *               ast.
 * \param data - is the value of lock->l_ast_data
 * \param flag - LDLM_CB_BLOCKING or LDLM_CB_CANCELING. Used to distinguish
 *               cancellation and blocking ast's.
 */
static int qsd_id_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc,
			       void *data, int flag)
{
	struct lustre_handle	lockh;
	int			rc = 0;
	ENTRY;

	switch(flag) {
	case LDLM_CB_BLOCKING: {

		LDLM_DEBUG(lock, "blocking AST on ID quota lock");
		ldlm_lock2handle(lock, &lockh);
		rc = ldlm_cli_cancel(&lockh, LCF_ASYNC);
		break;
	}
	case LDLM_CB_CANCELING: {
		struct lu_env           *env;
		struct lquota_entry	*lqe;
		bool			 rel = false;

		LDLM_DEBUG(lock, "canceling global quota lock");
		lqe = qsd_id_ast_data_get(lock, true);
		if (lqe == NULL)
			break;

		LQUOTA_DEBUG(lqe, "losing ID lock");

		/* just local cancel (for stack clean up or eviction), don't
		 * release quota space in this case */
		if (ldlm_is_local_only(lock)) {
			lqe_putref(lqe);
			break;
		}

		/* allocate environment */
		OBD_ALLOC_PTR(env);
		if (env == NULL) {
			lqe_putref(lqe);
			rc = -ENOMEM;
			break;
		}

		/* initialize environment */
		rc = lu_env_init(env, LCT_DT_THREAD);
		if (rc) {
			OBD_FREE_PTR(env);
			lqe_putref(lqe);
			break;
		}

		ldlm_lock2handle(lock, &lockh);
		lqe_write_lock(lqe);
		if (lustre_handle_equal(&lockh, &lqe->lqe_lockh)) {
			/* Clear lqe_lockh & reset qunit to 0 */
			qsd_set_qunit(lqe, 0);
			memset(&lqe->lqe_lockh, 0, sizeof(lqe->lqe_lockh));
			lqe->lqe_edquot = false;
			rel = true;
		}
		lqe_write_unlock(lqe);

		/* If there is qqacq inflight, the release will be skipped
		 * at this time, and triggered on dqacq completion later,
		 * which means there could be a short window that slave is
		 * holding spare grant wihtout per-ID lock. */
		if (rel)
			rc = qsd_adjust(env, lqe);

		/* release lqe reference grabbed by qsd_id_ast_data_get() */
		lqe_putref(lqe);
		lu_env_fini(env);
		OBD_FREE_PTR(env);
		break;
	}
	default:
		LASSERTF(0, "invalid flags for blocking ast %d", flag);
	}

	RETURN(rc);
}