/** * 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; }
/** * 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; }
/** * 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); }