+ struct lustre_quota_ctxt *qctxt = &obd->u.obt.obt_qctxt;
+ struct timeval work_start;
+ struct timeval work_end;
+ long timediff;
+ struct l_wait_info lwi = { 0 };
+ int rc = 0, cycle = 0, count_err = 1;
+ ENTRY;
+
+ if (!quota_is_set(obd, id, isblk ? QB_SET : QI_SET))
+ RETURN(0);
+
+ if (isblk && (exp->exp_failed || exp->exp_abort_active_req))
+ /* If the client has been evicted or if it
+ * timed out and tried to reconnect already,
+ * abort the request immediately */
+ RETURN(-ENOTCONN);
+
+ CDEBUG(D_QUOTA, "check quota for %s\n", obd->obd_name);
+ pending[USRQUOTA] = pending[GRPQUOTA] = 0;
+ /* Unfortunately, if quota master is too busy to handle the
+ * pre-dqacq in time and quota hash on ost is used up, we
+ * have to wait for the completion of in flight dqacq/dqrel,
+ * in order to get enough quota for write b=12588 */
+ cfs_gettimeofday(&work_start);
+ while ((rc = quota_check_common(obd, id, pending, count, cycle, isblk,
+ inode, frags)) &
+ QUOTA_RET_ACQUOTA) {
+
+ cfs_spin_lock(&qctxt->lqc_lock);
+ if (!qctxt->lqc_import && oti) {
+ cfs_spin_unlock(&qctxt->lqc_lock);
+
+ LASSERT(oti && oti->oti_thread &&
+ oti->oti_thread->t_watchdog);
+
+ lc_watchdog_disable(oti->oti_thread->t_watchdog);
+ CDEBUG(D_QUOTA, "sleep for quota master\n");
+ l_wait_event(qctxt->lqc_wait_for_qmaster, check_qm(qctxt),
+ &lwi);
+ CDEBUG(D_QUOTA, "wake up when quota master is back\n");
+ lc_watchdog_touch(oti->oti_thread->t_watchdog,
+ CFS_GET_TIMEOUT(oti->oti_thread->t_svc));
+ } else {
+ cfs_spin_unlock(&qctxt->lqc_lock);
+ }
+
+ cycle++;
+ if (isblk)
+ OBD_FAIL_TIMEOUT(OBD_FAIL_OST_HOLD_WRITE_RPC, 90);
+ /* after acquire(), we should run quota_check_common again
+ * so that we confirm there are enough quota to finish write */
+ rc = acquire(obd, id, oti, isblk);
+
+ /* please reference to dqacq_completion for the below */
+ /* a new request is finished, try again */
+ if (rc == QUOTA_REQ_RETURNED) {
+ CDEBUG(D_QUOTA, "finish a quota req, try again\n");
+ continue;
+ }
+
+ /* it is out of quota already */
+ if (rc == -EDQUOT) {
+ CDEBUG(D_QUOTA, "out of quota, return -EDQUOT\n");
+ break;
+ }
+
+ /* Related quota has been disabled by master, but enabled by
+ * slave, do not try again. */
+ if (unlikely(rc == -ESRCH)) {
+ CERROR("mismatched quota configuration, stop try.\n");
+ break;
+ }
+
+ if (isblk && (exp->exp_failed || exp->exp_abort_active_req))
+ /* The client has been evicted or tried to
+ * to reconnect already, abort the request */
+ RETURN(-ENOTCONN);
+
+ /* -EBUSY and others, wait a second and try again */
+ if (rc < 0) {
+ cfs_waitq_t waitq;
+ struct l_wait_info lwi;
+
+ if (oti && oti->oti_thread && oti->oti_thread->t_watchdog)
+ lc_watchdog_touch(oti->oti_thread->t_watchdog,
+ CFS_GET_TIMEOUT(oti->oti_thread->t_svc));
+ CDEBUG(D_QUOTA, "rc: %d, count_err: %d\n", rc,
+ count_err++);
+
+ cfs_waitq_init(&waitq);
+ lwi = LWI_TIMEOUT(cfs_time_seconds(min(cycle, 10)), NULL,
+ NULL);
+ l_wait_event(waitq, 0, &lwi);
+ }
+
+ if (rc < 0 || cycle % 10 == 0) {
+ cfs_spin_lock(&last_print_lock);
+ if (last_print == 0 ||
+ cfs_time_before((last_print + cfs_time_seconds(30)),
+ cfs_time_current())) {
+ last_print = cfs_time_current();
+ cfs_spin_unlock(&last_print_lock);
+ CWARN("still haven't managed to acquire quota "
+ "space from the quota master after %d "
+ "retries (err=%d, rc=%d)\n",
+ cycle, count_err - 1, rc);
+ } else {
+ cfs_spin_unlock(&last_print_lock);
+ }
+ }
+
+ CDEBUG(D_QUOTA, "recheck quota with rc: %d, cycle: %d\n", rc,
+ cycle);
+ }
+ cfs_gettimeofday(&work_end);
+ timediff = cfs_timeval_sub(&work_end, &work_start, NULL);
+ lprocfs_counter_add(qctxt->lqc_stats,
+ isblk ? LQUOTA_WAIT_FOR_CHK_BLK :
+ LQUOTA_WAIT_FOR_CHK_INO,
+ timediff);
+
+ if (rc > 0)
+ rc = 0;
+ RETURN(rc);