Пример #1
0
/*
 * Return lquota entry structure associated with a per-ID lock
 *
 * \param lock - is the per-ID lock from which we should extract the lquota
 *               entry
 * \param reset - whether lock->l_ast_data should be cleared
 */
static struct lquota_entry *qsd_id_ast_data_get(struct ldlm_lock *lock,
						bool reset) {
	struct lquota_entry *lqe;
	ENTRY;

	lock_res_and_lock(lock);
	lqe = lock->l_ast_data;
	if (lqe != NULL) {
		lqe_getref(lqe);
		if (reset)
			lock->l_ast_data = NULL;
	}
	unlock_res_and_lock(lock);

	if (reset && lqe != NULL)
		/* release lqe reference hold for the lock */
		lqe_putref(lqe);
	RETURN(lqe);
}
Пример #2
0
/*
 * Get intent per-ID lock or global-index lock from master.
 *
 * \param env    - the environment passed by the caller
 * \param exp    - is the export to use to send the intent RPC
 * \param qbody  - quota body to be packed in request
 * \param sync   - synchronous or asynchronous (pre-acquire)
 * \param it_op  - IT_QUOTA_DQACQ or IT_QUOTA_CONN
 * \param completion - completion callback
 * \param qqi    - is the qsd_qtype_info structure to pass to the completion
 *                 function
 * \param lvb    - is the lvb associated with the lock and returned by the
 *                 server
 * \param arg    - is an opaq argument passed to the completion callback
 *
 * \retval 0     - success
 * \retval -ve   - appropriate errors
 */
int qsd_intent_lock(const struct lu_env *env, struct obd_export *exp,
		    struct quota_body *qbody, bool sync, int it_op,
		    qsd_req_completion_t completion, struct qsd_qtype_info *qqi,
		    struct lquota_lvb *lvb, void *arg)
{
	struct qsd_thread_info	*qti = qsd_info(env);
	struct ptlrpc_request	*req;
	struct qsd_async_args	*aa = NULL;
	struct ldlm_intent	*lit;
	struct quota_body	*req_qbody;
	__u64			 flags = LDLM_FL_HAS_INTENT;
	int			 rc;
	ENTRY;

	LASSERT(exp != NULL);
	LASSERT(!lustre_handle_is_used(&qbody->qb_lockh));

	memset(&qti->qti_lockh, 0, sizeof(qti->qti_lockh));

	req = ptlrpc_request_alloc(class_exp2cliimp(exp),
				   &RQF_LDLM_INTENT_QUOTA);
	if (req == NULL)
		GOTO(out, rc = -ENOMEM);

	req->rq_no_retry_einprogress = 1;
	rc = ldlm_prep_enqueue_req(exp, req, NULL, 0);
	if (rc) {
		ptlrpc_request_free(req);
		GOTO(out, rc);
	}

	lit = req_capsule_client_get(&req->rq_pill, &RMF_LDLM_INTENT);
	lit->opc = (__u64)it_op;

	req_qbody = req_capsule_client_get(&req->rq_pill, &RMF_QUOTA_BODY);
	*req_qbody = *qbody;

	req_capsule_set_size(&req->rq_pill, &RMF_DLM_LVB, RCL_SERVER,
			     sizeof(*lvb));
	ptlrpc_request_set_replen(req);

	switch(it_op) {
	case IT_QUOTA_CONN:
		/* build resource name associated with global index */
		fid_build_reg_res_name(&qbody->qb_fid, &qti->qti_resid);

		/* copy einfo template and fill ei_cbdata with qqi pointer */
		memcpy(&qti->qti_einfo, &qsd_glb_einfo, sizeof(qti->qti_einfo));
		qti->qti_einfo.ei_cbdata = qqi;

		/* don't cancel global lock on memory pressure */
		flags |= LDLM_FL_NO_LRU;
		break;
	case IT_QUOTA_DQACQ:
		/* build resource name associated for per-ID quota lock */
		fid_build_quota_res_name(&qbody->qb_fid, &qbody->qb_id,
					 &qti->qti_resid);

		/* copy einfo template and fill ei_cbdata with lqe pointer */
		memcpy(&qti->qti_einfo, &qsd_id_einfo, sizeof(qti->qti_einfo));
		qti->qti_einfo.ei_cbdata = arg;
		break;
	default:
		LASSERTF(0, "invalid it_op %d", it_op);
	}

	/* build lock enqueue request */
	rc = ldlm_cli_enqueue(exp, &req, &qti->qti_einfo, &qti->qti_resid, NULL,
			      &flags, (void *)lvb, sizeof(*lvb), LVB_T_LQUOTA,
			      &qti->qti_lockh, 1);
	if (rc < 0) {
		ptlrpc_req_finished(req);
		GOTO(out, rc);
	}

	/* grab reference on backend structure for the new lock */
	switch(it_op) {
	case IT_QUOTA_CONN:
		/* grab reference on qqi for new lock */
#ifdef USE_LU_REF
	{
		struct ldlm_lock	*lock;

		lock = ldlm_handle2lock(&qti->qti_lockh);
		if (lock == NULL) {
			ptlrpc_req_finished(req);
			GOTO(out, rc = -ENOLCK);
		}
		lu_ref_add(&qqi->qqi_reference, "glb_lock", lock);
		LDLM_LOCK_PUT(lock);
	}
#endif
		qqi_getref(qqi);
		break;
	case IT_QUOTA_DQACQ:
		/* grab reference on lqe for new lock */
		lqe_getref((struct lquota_entry *)arg);
		/* all acquire/release request are sent with no_resend and
		 * no_delay flag */
		req->rq_no_resend = req->rq_no_delay = 1;
		break;
	default:
		break;
	}

	CLASSERT(sizeof(*aa) <= sizeof(req->rq_async_args));
	aa = ptlrpc_req_async_args(req);
	aa->aa_exp = exp;
	aa->aa_qqi = qqi;
	aa->aa_arg = arg;
	aa->aa_lvb = lvb;
	aa->aa_completion = completion;
	lustre_handle_copy(&aa->aa_lockh, &qti->qti_lockh);

	if (sync) {
		/* send lock enqueue request and wait for completion */
		rc = ptlrpc_queue_wait(req);
		rc = qsd_intent_interpret(env, req, aa, rc);
		ptlrpc_req_finished(req);
	} else {
		/* queue lock request and return */
		req->rq_interpret_reply = qsd_intent_interpret;
		ptlrpcd_add_req(req, PDL_POLICY_LOCAL, -1);
	}

	RETURN(rc);
out:
	completion(env, qqi, qbody, NULL, &qti->qti_lockh, lvb, arg, rc);
	return rc;
}
Пример #3
0
/**
 * Adjust quota space (by acquiring or releasing) hold by the quota slave.
 * This function is called after each quota request completion and during
 * reintegration in order to report usage or re-acquire quota locks.
 * Space adjustment is aborted if there is already a quota request in flight
 * for this ID.
 *
 * \param env    - the environment passed by the caller
 * \param lqe    - is the qid entry to be processed
 *
 * \retval 0 on success, appropriate errors on failure
 */
int qsd_adjust(const struct lu_env *env, struct lquota_entry *lqe)
{
	struct qsd_thread_info	*qti = qsd_info(env);
	struct quota_body	*qbody = &qti->qti_body;
	struct qsd_instance	*qsd;
	struct qsd_qtype_info	*qqi;
	int			 rc;
	bool			 intent = false;
	ENTRY;

	memset(qbody, 0, sizeof(*qbody));
	rc = qsd_ready(lqe, &qbody->qb_glb_lockh);
	if (rc) {
		/* add to adjust list again to trigger adjustment later when
		 * slave is ready */
		LQUOTA_DEBUG(lqe, "delaying adjustment since qsd isn't ready");
		qsd_adjust_schedule(lqe, true, false);
		RETURN(0);
	}

	qqi = lqe2qqi(lqe);
	qsd = qqi->qqi_qsd;

	lqe_write_lock(lqe);

	/* fill qb_count & qb_flags */
	if (!qsd_calc_adjust(lqe, qbody)) {
		lqe_write_unlock(lqe);
		LQUOTA_DEBUG(lqe, "no adjustment required");
		RETURN(0);
	}

	/* only 1 quota request in flight for a given ID is allowed */
	rc = qsd_request_enter(lqe);
	if (rc) {
		/* already a request in flight, space adjustment will be run
		 * again on request completion */
		lqe_write_unlock(lqe);
		RETURN(0);
	}

	if (req_is_rel(qbody->qb_flags))
		lqe->lqe_pending_rel = qbody->qb_count;
	lustre_handle_copy(&qti->qti_lockh, &lqe->lqe_lockh);
	lqe_write_unlock(lqe);

	/* hold a refcount until completion */
	lqe_getref(lqe);

	/* fill other quota body fields */
	qbody->qb_fid = qqi->qqi_fid;
	qbody->qb_id  = lqe->lqe_id;

	if (req_is_acq(qbody->qb_flags) || req_is_preacq(qbody->qb_flags)) {
		/* check whether we own a valid lock for this ID */
		rc = qsd_id_lock_match(&qti->qti_lockh, &qbody->qb_lockh);
		if (rc) {
			memset(&qti->qti_lockh, 0, sizeof(qti->qti_lockh));
			if (req_is_preacq(qbody->qb_flags)) {
				if (req_has_rep(qbody->qb_flags))
					/* still want to report usage */
					qbody->qb_flags = QUOTA_DQACQ_FL_REPORT;
				else
					/* no pre-acquire if no per-ID lock */
					GOTO(out, rc = -ENOLCK);
			} else {
				/* no lock found, should use intent */
				intent = true;
			}
		} else if (req_is_acq(qbody->qb_flags) &&
			   qbody->qb_count == 0) {
			/* found cached lock, no need to acquire */
			GOTO(out, rc = 0);
		}
	} else {
		/* release and report don't need a per-ID lock */
		memset(&qti->qti_lockh, 0, sizeof(qti->qti_lockh));
	}

	if (!intent) {
		rc = qsd_send_dqacq(env, qsd->qsd_exp, qbody, false,
				    qsd_req_completion, qqi, &qti->qti_lockh,
				    lqe);
	} else {
		struct lquota_lvb *lvb;

		OBD_ALLOC_PTR(lvb);
		if (lvb == NULL)
			GOTO(out, rc = -ENOMEM);

		rc = qsd_intent_lock(env, qsd->qsd_exp, qbody, false,
				     IT_QUOTA_DQACQ, qsd_req_completion,
				     qqi, lvb, (void *)lqe);
	}
	/* the completion function will be called by qsd_send_dqacq or
	 * qsd_intent_lock */
	RETURN(rc);
out:
	qsd_req_completion(env, qqi, qbody, NULL, &qti->qti_lockh, NULL, lqe,
			   rc);
	return rc;
}
Пример #4
0
static void lqe_hash_get(cfs_hash_t *hs, cfs_hlist_node_t *hnode)
{
	struct lquota_entry *lqe;
	lqe = cfs_hlist_entry(hnode, struct lquota_entry, lqe_hash);
	lqe_getref(lqe);
}
Пример #5
0
/**
 * Acquire quota space from master.
 * There are at most 1 in-flight dqacq/dqrel.
 *
 * \param env    - the environment passed by the caller
 * \param lqe    - is the qid entry to be processed
 *
 * \retval 0            - success
 * \retval -EDQUOT      - out of quota
 * \retval -EINPROGRESS - inform client to retry write/create
 * \retval -EBUSY       - already a quota request in flight
 * \retval -ve          - other appropriate errors
 */
static int qsd_acquire_remote(const struct lu_env *env,
			      struct lquota_entry *lqe)
{
	struct qsd_thread_info	*qti = qsd_info(env);
	struct quota_body	*qbody = &qti->qti_body;
	struct qsd_instance	*qsd;
	struct qsd_qtype_info	*qqi;
	int			 rc;
	ENTRY;

	memset(qbody, 0, sizeof(*qbody));
	rc = qsd_ready(lqe, &qbody->qb_glb_lockh);
	if (rc)
		RETURN(rc);

	qqi = lqe2qqi(lqe);
	qsd = qqi->qqi_qsd;

	lqe_write_lock(lqe);

	/* is quota really enforced for this id? */
	if (!lqe->lqe_enforced) {
		lqe_write_unlock(lqe);
		LQUOTA_DEBUG(lqe, "quota not enforced any more");
		RETURN(0);
	}

	/* fill qb_count & qb_flags */
	if (!qsd_calc_acquire(lqe, qbody)) {
		lqe_write_unlock(lqe);
		LQUOTA_DEBUG(lqe, "No acquire required");
		RETURN(0);
	}

	/* check whether an acquire request completed recently */
	if (lqe->lqe_acq_rc != 0 &&
	    cfs_time_before_64(cfs_time_shift_64(-1), lqe->lqe_acq_time)) {
		lqe_write_unlock(lqe);
		LQUOTA_DEBUG(lqe, "using cached return code %d", lqe->lqe_acq_rc);
		RETURN(lqe->lqe_acq_rc);
	}

	/* only 1 quota request in flight for a given ID is allowed */
	rc = qsd_request_enter(lqe);
	if (rc) {
		lqe_write_unlock(lqe);
		RETURN(rc);
	}

	lustre_handle_copy(&qti->qti_lockh, &lqe->lqe_lockh);
	lqe_write_unlock(lqe);

	/* hold a refcount until completion */
	lqe_getref(lqe);

	/* fill other quota body fields */
	qbody->qb_fid = qqi->qqi_fid;
	qbody->qb_id  = lqe->lqe_id;

	/* check whether we already own a valid lock for this ID */
	rc = qsd_id_lock_match(&qti->qti_lockh, &qbody->qb_lockh);
	if (rc) {
		struct lquota_lvb *lvb;

		OBD_ALLOC_PTR(lvb);
		if (lvb == NULL) {
			rc = -ENOMEM;
			qsd_req_completion(env, qqi, qbody, NULL,
					   &qti->qti_lockh, NULL, lqe, rc);
			RETURN(rc);
		}
		/* no lock found, should use intent */
		rc = qsd_intent_lock(env, qsd->qsd_exp, qbody, true,
				     IT_QUOTA_DQACQ, qsd_req_completion,
				     qqi, lvb, (void *)lqe);
	} else {
		/* lock found, should use regular dqacq */
		rc = qsd_send_dqacq(env, qsd->qsd_exp, qbody, true,
				    qsd_req_completion, qqi, &qti->qti_lockh,
				    lqe);
	}

	/* the completion function will be called by qsd_send_dqacq or
	 * qsd_intent_lock */
	RETURN(rc);
}