+ CDEBUG(D_QUOTA, "check quota for %s\n", obd->obd_name);
+ *pending = 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 */
+ do_gettimeofday(&work_start);
+ while ((rc = quota_check_common(obd, uid, gid, count, cycle, isblk,
+ inode, frags, pending)) &
+ QUOTA_RET_ACQUOTA) {
+
+ spin_lock(&qctxt->lqc_lock);
+ if (!qctxt->lqc_import && oti) {
+ 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);
+ } else {
+ 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, uid, gid, 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;
+ }
+
+ /* -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);
+ CDEBUG(D_QUOTA, "rc: %d, count_err: %d\n", rc,
+ count_err++);
+
+ init_waitqueue_head(&waitq);
+ lwi = LWI_TIMEOUT(cfs_time_seconds(min(cycle, 10)), NULL,
+ NULL);
+ l_wait_event(waitq, 0, &lwi);
+ }
+
+ if (rc < 0 || cycle % 10 == 2) {
+ 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();
+ 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 {
+ spin_unlock(&last_print_lock);
+ }
+ }
+
+ CDEBUG(D_QUOTA, "recheck quota with rc: %d, cycle: %d\n", rc,
+ cycle);
+ }
+ do_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);
+
+ RETURN(rc);
+}
+
+/**
+ * when a block_write or inode_create rpc is finished, adjust the record for
+ * pending blocks and inodes
+ */
+static int quota_pending_commit(struct obd_device *obd, unsigned int uid,
+ unsigned int gid, int pending, int isblk)
+{
+ struct lustre_quota_ctxt *qctxt = &obd->u.obt.obt_qctxt;
+ struct timeval work_start;
+ struct timeval work_end;
+ long timediff;
+ int i;
+ __u32 id[MAXQUOTAS] = { uid, gid };
+ struct qunit_data qdata[MAXQUOTAS];
+ ENTRY;
+
+ CDEBUG(D_QUOTA, "commit pending quota for %s\n", obd->obd_name);
+ CLASSERT(MAXQUOTAS < 4);
+ if (!sb_any_quota_enabled(qctxt->lqc_sb))
+ RETURN(0);
+
+ do_gettimeofday(&work_start);
+ for (i = 0; i < MAXQUOTAS; i++) {
+ struct lustre_qunit_size *lqs = NULL;
+
+ qdata[i].qd_id = id[i];
+ qdata[i].qd_flags = i;
+ if (isblk)
+ QDATA_SET_BLK(&qdata[i]);
+ qdata[i].qd_count = 0;
+
+ if (qdata[i].qd_id == 0 && !QDATA_IS_GRP(&qdata[i]))
+ continue;
+
+ quota_search_lqs(&qdata[i], NULL, qctxt, &lqs);
+ if (lqs) {
+ int flag = 0;
+ spin_lock(&lqs->lqs_lock);
+ if (isblk) {
+ if (lqs->lqs_bwrite_pending >= pending) {
+ lqs->lqs_bwrite_pending -= pending;
+ spin_unlock(&lqs->lqs_lock);
+ flag = 1;
+ } else {
+ spin_unlock(&lqs->lqs_lock);
+ CDEBUG(D_ERROR,
+ "there are too many blocks!\n");
+ }
+ } else {
+ if (lqs->lqs_iwrite_pending >= pending) {
+ lqs->lqs_iwrite_pending -= pending;
+ spin_unlock(&lqs->lqs_lock);
+ flag = 1;
+ } else {
+ spin_unlock(&lqs->lqs_lock);
+ CDEBUG(D_ERROR,
+ "there are too many files!\n");
+ }
+ }
+ CDEBUG(D_QUOTA, "lqs pending: %lu, pending: %d, "
+ "isblk: %d.\n",
+ isblk ? lqs->lqs_bwrite_pending :
+ lqs->lqs_iwrite_pending, pending, isblk);
+
+ lqs_putref(lqs);
+ /* When lqs_*_pening is changed back, we'll putref lqs
+ * here b=14784 */
+ if (flag)
+ lqs_putref(lqs);
+ }
+ }
+ do_gettimeofday(&work_end);
+ timediff = cfs_timeval_sub(&work_end, &work_start, NULL);
+ lprocfs_counter_add(qctxt->lqc_stats,
+ isblk ? LQUOTA_WAIT_FOR_COMMIT_BLK :
+ LQUOTA_WAIT_FOR_COMMIT_INO,
+ timediff);
+
+ RETURN(0);