Whamcloud - gitweb
Branch HEAD
[fs/lustre-release.git] / lustre / quota / quota_master.c
index 512fc49..7753bff 100644 (file)
@@ -141,7 +141,7 @@ static struct lustre_dquot *alloc_dquot(struct lustre_quota_info *lqi,
         struct lustre_dquot *dquot = NULL;
         ENTRY;
 
-        OBD_SLAB_ALLOC(dquot, lustre_dquot_cachep, CFS_ALLOC_IO, sizeof(*dquot));
+        OBD_SLAB_ALLOC_PTR_GFP(dquot, lustre_dquot_cachep, CFS_ALLOC_IO);
         if (dquot == NULL)
                 RETURN(NULL);
 
@@ -235,8 +235,8 @@ static void init_oqaq(struct quota_adjust_qunit *oqaq,
 
         oqaq->qaq_id = id;
         oqaq->qaq_flags = type;
-        quota_search_lqs(NULL, oqaq, qctxt, &lqs);
-        if (lqs) {
+        lqs = quota_search_lqs(LQS_KEY(type, id), qctxt, 0);
+        if (lqs && !IS_ERR(lqs)) {
                 spin_lock(&lqs->lqs_lock);
                 oqaq->qaq_bunit_sz = lqs->lqs_bunit_sz;
                 oqaq->qaq_iunit_sz = lqs->lqs_iunit_sz;
@@ -259,7 +259,7 @@ int dqacq_adjust_qunit_sz(struct obd_device *obd, qid_t id, int type,
         struct lov_obd *lov = &lov_mds_obd->u.lov;
         __u32 ost_num = lov->desc.ld_tgt_count, mdt_num = 1;
         struct quota_adjust_qunit *oqaq = NULL;
-        unsigned int uid = 0, gid = 0;
+        unsigned int qid[MAXQUOTAS] = { 0, 0 };
         struct lustre_quota_info *info = &mds->mds_quota_info;
         struct lustre_dquot *dquot = NULL;
         int adjust_res = 0;
@@ -305,13 +305,13 @@ int dqacq_adjust_qunit_sz(struct obd_device *obd, qid_t id, int type,
         }
 
         if (type)
-                gid = dquot->dq_id;
+                qid[GRPQUOTA] = dquot->dq_id;
         else
-                uid = dquot->dq_id;
+                qid[USRQUOTA] = dquot->dq_id;
 
         up(&dquot->dq_sem);
 
-        rc = qctxt_adjust_qunit(obd, qctxt, uid, gid, is_blk, 0, NULL);
+        rc = qctxt_adjust_qunit(obd, qctxt, qid, is_blk, 0, NULL);
         if (rc == -EDQUOT || rc == -EBUSY) {
                 CDEBUG(D_QUOTA, "rc: %d.\n", rc);
                 rc = 0;
@@ -441,29 +441,24 @@ out:
                 dqacq_adjust_qunit_sz(obd, qdata->qd_id, QDATA_IS_GRP(qdata),
                                       QDATA_IS_BLK(qdata));
 
-        quota_search_lqs(qdata, NULL, qctxt, &lqs);
-        if (QDATA_IS_BLK(qdata)) {
-                if (!lqs) {
-                        CDEBUG(D_INFO, "Can't find the lustre qunit size!\n");
-                        qdata->qd_qunit  = qctxt->lqc_bunit_sz;
-                } else {
-                        spin_lock(&lqs->lqs_lock);
-                        qdata->qd_qunit  = lqs->lqs_bunit_sz;
-                        spin_unlock(&lqs->lqs_lock);
-                }
-                QDATA_SET_ADJBLK(qdata);
+        lqs = quota_search_lqs(LQS_KEY(QDATA_IS_GRP(qdata), qdata->qd_id),
+                               qctxt, 0);
+        if (lqs == NULL || IS_ERR(lqs)) {
+                CDEBUG(D_INFO, "Can't find the lustre qunit size!\n");
+                qdata->qd_qunit  = QDATA_IS_BLK(qdata) ? qctxt->lqc_bunit_sz :
+                                                         qctxt->lqc_iunit_sz;
         } else {
-                if (!lqs) {
-                        CDEBUG(D_INFO, "Can't find the lustre qunit size!\n");
-                        qdata->qd_qunit  = qctxt->lqc_iunit_sz;
-                } else {
-                        spin_lock(&lqs->lqs_lock);
-                        qdata->qd_qunit  = lqs->lqs_iunit_sz;
-                        spin_unlock(&lqs->lqs_lock);
-                }
-                QDATA_SET_ADJINO(qdata);
+                spin_lock(&lqs->lqs_lock);
+                qdata->qd_qunit  = QDATA_IS_BLK(qdata) ? lqs->lqs_bunit_sz :
+                                                         lqs->lqs_iunit_sz;
+                spin_unlock(&lqs->lqs_lock);
         }
 
+        if (QDATA_IS_BLK(qdata))
+                QDATA_SET_ADJBLK(qdata);
+        else
+                QDATA_SET_ADJINO(qdata);
+
         QDATA_DEBUG(qdata, "alloc/release qunit in dqacq_handler\n");
         if (lqs)
                 lqs_putref(lqs);
@@ -471,8 +466,8 @@ out:
         return rc;
 }
 
-int mds_quota_adjust(struct obd_device *obd, unsigned int qcids[],
-                     unsigned int qpids[], int rc, int opc)
+int mds_quota_adjust(struct obd_device *obd, const unsigned int qcids[],
+                     const unsigned int qpids[], int rc, int opc)
 {
         struct lustre_quota_ctxt *qctxt = &obd->u.obt.obt_qctxt;
         int rc2 = 0;
@@ -484,67 +479,53 @@ int mds_quota_adjust(struct obd_device *obd, unsigned int qcids[],
         switch (opc) {
         case FSFILT_OP_SETATTR:
                 /* release file quota on original owner */
-                rc2 |= qctxt_adjust_qunit(obd, qctxt, qpids[0], qpids[1], 0, 0,
-                                          NULL);
+                rc2 |= qctxt_adjust_qunit(obd, qctxt, qpids, 0, 0, NULL);
                 /* release block quota on original owner */
-                rc2 |= qctxt_adjust_qunit(obd, qctxt, qpids[0], qpids[1], 1, 0,
-                                          NULL);
+                rc2 |= qctxt_adjust_qunit(obd, qctxt, qpids, 1, 0, NULL);
                 /* acquire file quota on current owner */
-                rc2 |= qctxt_adjust_qunit(obd, qctxt, qcids[0], qcids[1], 0, 0,
-                                          NULL);
+                rc2 |= qctxt_adjust_qunit(obd, qctxt, qcids, 0, 0, NULL);
                 /* acquire block quota on current owner */
-                rc2 |= qctxt_adjust_qunit(obd, qctxt, qcids[0], qcids[1], 1, 0,
-                                          NULL);
+                rc2 |= qctxt_adjust_qunit(obd, qctxt, qcids, 1, 0, NULL);
                 break;
         case FSFILT_OP_UNLINK_PARTIAL_CHILD:
                 /* release file quota on child */
-                rc2 |= qctxt_adjust_qunit(obd, qctxt, qcids[0], qcids[1], 0, 0,
-                                          NULL);
+                rc2 |= qctxt_adjust_qunit(obd, qctxt, qcids, 0, 0, NULL);
                 /* rlease block quota on child */
-                rc2 |= qctxt_adjust_qunit(obd, qctxt, qcids[0], qcids[1], 1, 0,
-                                          NULL);
+                rc2 |= qctxt_adjust_qunit(obd, qctxt, qcids, 1, 0, NULL);
                 break;
         case FSFILT_OP_CREATE_PARTIAL_CHILD:
                 /* acquire file quota on child */
-                rc2 |= qctxt_adjust_qunit(obd, qctxt, qcids[0], qcids[1], 0, 0,
-                                          NULL);
+                rc2 |= qctxt_adjust_qunit(obd, qctxt, qcids, 0, 0, NULL);
                 /* acquire block quota on child */
-                rc2 |= qctxt_adjust_qunit(obd, qctxt, qcids[0], qcids[1], 1, 0,
-                                          NULL);
+                rc2 |= qctxt_adjust_qunit(obd, qctxt, qcids, 1, 0, NULL);
                 break;
         case FSFILT_OP_LINK:
                 /* acquire block quota on parent */
-                rc2 |= qctxt_adjust_qunit(obd, qctxt, qpids[0], qpids[1], 1, 0,
-                                          NULL);
+                rc2 |= qctxt_adjust_qunit(obd, qctxt, qpids, 1, 0, NULL);
                 break;
         case FSFILT_OP_UNLINK:
                 /* release block quota on parent */
-                rc2 |= qctxt_adjust_qunit(obd, qctxt, qpids[0], qpids[1], 1, 0,
-                                          NULL);
+                rc2 |= qctxt_adjust_qunit(obd, qctxt, qpids, 1, 0, NULL);
                 /* release file quota on child */
-                rc2 |= qctxt_adjust_qunit(obd, qctxt, qcids[0], qcids[1], 0, 0,
-                                          NULL);
+                rc2 |= qctxt_adjust_qunit(obd, qctxt, qcids, 0, 0, NULL);
                 if (qpids[0] != qcids[0] || qpids[1] != qcids[1])
                         /* release block quota on child */
-                        rc2 |= qctxt_adjust_qunit(obd, qctxt, qcids[0],
-                                                  qcids[1], 1, 0, NULL);
+                        rc2 |= qctxt_adjust_qunit(obd, qctxt, qcids, 1, 0,
+                                                  NULL);
                 break;
         case FSFILT_OP_UNLINK_PARTIAL_PARENT:
                 /* release block quota on parent */
-                rc2 |= qctxt_adjust_qunit(obd, qctxt, qpids[0], qpids[1], 1, 0,
-                                          NULL);
+                rc2 |= qctxt_adjust_qunit(obd, qctxt, qpids, 1, 0, NULL);
                 break;
         case FSFILT_OP_CREATE:
                 /* acquire block quota on parent */
-                rc2 |= qctxt_adjust_qunit(obd, qctxt, qpids[0], qpids[1], 1, 0,
-                                          NULL);
+                rc2 |= qctxt_adjust_qunit(obd, qctxt, qpids, 1, 0, NULL);
                 /* acquire file quota on child */
-                rc2 |= qctxt_adjust_qunit(obd, qctxt, qcids[0], qcids[1], 0, 0,
-                                          NULL);
+                rc2 |= qctxt_adjust_qunit(obd, qctxt, qcids, 0, 0, NULL);
                 if (qpids[0] != qcids[0] || qpids[1] != qcids[1])
                         /* acquire block quota on child */
-                        rc2 |= qctxt_adjust_qunit(obd, qctxt, qcids[0],
-                                                  qcids[1], 1, 0, NULL);
+                        rc2 |= qctxt_adjust_qunit(obd, qctxt, qcids, 1, 0,
+                                                  NULL);
                 break;
         default:
                 LBUG();
@@ -552,13 +533,14 @@ int mds_quota_adjust(struct obd_device *obd, unsigned int qcids[],
         }
 
         if (rc2)
-                CDEBUG(rc2 == -EAGAIN ? D_QUOTA: D_ERROR,
-                       "mds adjust qunit failed! (opc:%d rc:%d)\n", opc, rc2);
+                CDEBUG(rc2 == QUOTA_REQ_RETURNED ? D_QUOTA: D_ERROR,
+                       "mds adjust qunit %ssuccessfully! (opc:%d rc:%d)\n",
+                       rc2 == QUOTA_REQ_RETURNED ? "" : "un", opc, rc2);
         RETURN(0);
 }
 
-int filter_quota_adjust(struct obd_device *obd, unsigned int qcids[],
-                        unsigned int qpids[], int rc, int opc)
+int filter_quota_adjust(struct obd_device *obd, const unsigned int qcids[],
+                        const unsigned int qpids[], int rc, int opc)
 {
         struct lustre_quota_ctxt *qctxt = &obd->u.obt.obt_qctxt;
         int rc2 = 0;
@@ -570,17 +552,14 @@ int filter_quota_adjust(struct obd_device *obd, unsigned int qcids[],
         switch (opc) {
         case FSFILT_OP_SETATTR:
                 /* acquire/release block quota on original & current owner */
-                rc = qctxt_adjust_qunit(obd, qctxt, qcids[0], qcids[1], 1, 0,
-                                        NULL);
-                rc2 = qctxt_adjust_qunit(obd, qctxt, qpids[0], qpids[1], 1, 0,
-                                         NULL);
+                rc = qctxt_adjust_qunit(obd, qctxt, qcids, 1, 0, NULL);
+                rc2 = qctxt_adjust_qunit(obd, qctxt, qpids, 1, 0, NULL);
                 break;
         case FSFILT_OP_UNLINK:
                 /* release block quota on this owner */
         case FSFILT_OP_CREATE: /* XXX for write operation on obdfilter */
                 /* acquire block quota on this owner */
-                rc = qctxt_adjust_qunit(obd, qctxt, qcids[0], qcids[1], 1, 0,
-                                        NULL);
+                rc = qctxt_adjust_qunit(obd, qctxt, qcids, 1, 0, NULL);
                 break;
         default:
                 LBUG();
@@ -590,9 +569,9 @@ int filter_quota_adjust(struct obd_device *obd, unsigned int qcids[],
         if (rc || rc2) {
                 if (!rc)
                         rc = rc2;
-                CDEBUG(rc == -EAGAIN ? D_QUOTA: D_ERROR,
-                       "filter adjust qunit failed! (opc:%d rc%d)\n",
-                       opc, rc);
+                CDEBUG(rc == QUOTA_REQ_RETURNED ? D_QUOTA: D_ERROR,
+                       "filter adjust qunit %ssuccessfully! (opc:%d rc%d)\n",
+                       QUOTA_REQ_RETURNED ? "" : "un", opc, rc);
         }
 
         RETURN(0);
@@ -611,6 +590,11 @@ int mds_quota_invalidate(struct obd_device *obd, struct obd_quotactl *oqctl)
 
         LASSERT(qinfo->qi_version == LUSTRE_QUOTA_V2);
 
+        if (oqctl->qc_type != USRQUOTA &&
+            oqctl->qc_type != GRPQUOTA &&
+            oqctl->qc_type != UGQUOTA)
+                return -EINVAL;
+
         push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
 
         down(&mds->mds_qonoff_sem);
@@ -654,11 +638,15 @@ int mds_quota_finvalidate(struct obd_device *obd, struct obd_quotactl *oqctl)
         int rc;
         struct lvfs_run_ctxt saved;
 
+        if (oqctl->qc_type != USRQUOTA &&
+            oqctl->qc_type != GRPQUOTA &&
+            oqctl->qc_type != UGQUOTA)
+                RETURN(-EINVAL);
+
         push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
         down(&mds->mds_qonoff_sem);
 
         oqctl->qc_cmd = Q_FINVALIDATE;
-        oqctl->qc_id = obd->u.obt.obt_qfmt;
         rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl);
         if (!rc)
                 rc = obd_quotactl(mds->mds_osc_exp, oqctl);
@@ -853,25 +841,32 @@ int mds_quota_on(struct obd_device *obd, struct obd_quotactl *oqctl)
         int rc;
         ENTRY;
 
+        if (oqctl->qc_type != USRQUOTA &&
+            oqctl->qc_type != GRPQUOTA &&
+            oqctl->qc_type != UGQUOTA)
+                RETURN(-EINVAL);
+
         if (!atomic_dec_and_test(&obt->obt_quotachecking)) {
                 CDEBUG(D_INFO, "other people are doing quotacheck\n");
                 atomic_inc(&obt->obt_quotachecking);
                 RETURN(-EBUSY);
         }
 
+        LASSERT(!obt->obt_qctxt.lqc_immutable);
         down(&mds->mds_qonoff_sem);
         push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
         rc = mds_admin_quota_on(obd, oqctl);
         if (rc)
-                goto out;
-
-        rc = obd_quotactl(mds->mds_osc_exp, oqctl);
-        if (rc)
-                goto out;
+                GOTO(out, rc);
 
         rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl);
         if (!rc)
                 obt->obt_qctxt.lqc_flags |= UGQUOTA2LQC(oqctl->qc_type);
+        else
+                GOTO(out, rc);
+
+        rc = obd_quotactl(mds->mds_osc_exp, oqctl);
+
 out:
         pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
         up(&mds->mds_qonoff_sem);
@@ -884,9 +879,17 @@ int mds_quota_off(struct obd_device *obd, struct obd_quotactl *oqctl)
         struct mds_obd *mds = &obd->u.mds;
         struct obd_device_target *obt = &obd->u.obt;
         struct lvfs_run_ctxt saved;
-        int rc, rc2;
+        int rc, rc2, imm;
         ENTRY;
 
+        imm = oqctl->qc_type & IMMQUOTA;
+        oqctl->qc_type &= ~IMMQUOTA;
+
+        if (oqctl->qc_type != USRQUOTA &&
+            oqctl->qc_type != GRPQUOTA &&
+            oqctl->qc_type != UGQUOTA)
+                RETURN(-EINVAL);
+
         if (!atomic_dec_and_test(&obt->obt_quotachecking)) {
                 CDEBUG(D_INFO, "other people are doing quotacheck\n");
                 atomic_inc(&obt->obt_quotachecking);
@@ -900,9 +903,11 @@ int mds_quota_off(struct obd_device *obd, struct obd_quotactl *oqctl)
 
         rc = obd_quotactl(mds->mds_osc_exp, oqctl);
         rc2 = fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl);
-        if (!rc2)
+        if (!rc2) {
+                if (imm)
+                        obt->obt_qctxt.lqc_immutable = 1;
                 obt->obt_qctxt.lqc_flags &= ~UGQUOTA2LQC(oqctl->qc_type);
-
+        }
         pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
         up(&mds->mds_qonoff_sem);
         atomic_inc(&obt->obt_quotachecking);
@@ -918,6 +923,10 @@ int mds_set_dqinfo(struct obd_device *obd, struct obd_quotactl *oqctl)
         int rc;
         ENTRY;
 
+        if (oqctl->qc_type != USRQUOTA &&
+            oqctl->qc_type != GRPQUOTA)
+                RETURN(-EINVAL);
+
         down(&mds->mds_qonoff_sem);
         if (qinfo->qi_files[oqctl->qc_type] == NULL) {
                 rc = -ESRCH;
@@ -943,6 +952,10 @@ int mds_get_dqinfo(struct obd_device *obd, struct obd_quotactl *oqctl)
         int rc = 0;
         ENTRY;
 
+        if (oqctl->qc_type != USRQUOTA &&
+            oqctl->qc_type != GRPQUOTA)
+                RETURN(-EINVAL);
+
         down(&mds->mds_qonoff_sem);
         if (qinfo->qi_files[oqctl->qc_type] == NULL) {
                 rc = -ESRCH;
@@ -990,14 +1003,14 @@ int dquot_create_oqaq(struct lustre_quota_ctxt *qctxt,
 
         if ((type & LQUOTA_FLAGS_ADJBLK) && blimit) {
                 __u64 b_limitation =
-                        oqaq->qaq_bunit_sz * ost_num * shrink_qunit_limit;
+                        oqaq->qaq_bunit_sz * (ost_num + 1) * shrink_qunit_limit;
                 /* enlarge block qunit size */
                 while (blimit >
                        QUSG(dquot->dq_dqb.dqb_curspace + 2 * b_limitation, 1)) {
                         oqaq->qaq_bunit_sz =
                                 QUSG(oqaq->qaq_bunit_sz * cqs_factor, 1)
                                 << QUOTABLOCK_BITS;
-                        b_limitation = oqaq->qaq_bunit_sz * ost_num *
+                        b_limitation = oqaq->qaq_bunit_sz * (ost_num + 1) *
                                 shrink_qunit_limit;
                 }
 
@@ -1010,7 +1023,7 @@ int dquot_create_oqaq(struct lustre_quota_ctxt *qctxt,
                         do_div(oqaq->qaq_bunit_sz , cqs_factor);
                         oqaq->qaq_bunit_sz = QUSG(oqaq->qaq_bunit_sz, 1) <<
                                 QUOTABLOCK_BITS;
-                        b_limitation = oqaq->qaq_bunit_sz * ost_num *
+                        b_limitation = oqaq->qaq_bunit_sz * (ost_num + 1) *
                                 shrink_qunit_limit;
                         if (oqaq->qaq_bunit_sz <  qctxt->lqc_cqs_least_bunit)
                                 break;
@@ -1076,7 +1089,7 @@ static int mds_init_slave_ilimits(struct obd_device *obd,
         /* XXX: for file limits only adjust local now */
         struct obd_device_target *obt = &obd->u.obt;
         struct lustre_quota_ctxt *qctxt = &obt->obt_qctxt;
-        unsigned int uid = 0, gid = 0;
+        unsigned int id[MAXQUOTAS] = { 0, 0 };
         struct obd_quotactl *ioqc = NULL;
         int flag;
         int rc;
@@ -1114,12 +1127,11 @@ static int mds_init_slave_ilimits(struct obd_device *obd,
 
         /* trigger local qunit pre-acquire */
         if (oqctl->qc_type == USRQUOTA)
-                uid = oqctl->qc_id;
+                id[USRQUOTA] = oqctl->qc_id;
         else
-                gid = oqctl->qc_id;
+                id[GRPQUOTA] = oqctl->qc_id;
 
-        rc = qctxt_adjust_qunit(obd, &obd->u.obt.obt_qctxt, uid, gid, 0, 0,
-                                NULL);
+        rc = qctxt_adjust_qunit(obd, &obd->u.obt.obt_qctxt, id, 0, 0, NULL);
         if (rc == -EDQUOT || rc == -EBUSY) {
                 CDEBUG(D_QUOTA, "rc: %d.\n", rc);
                 rc = 0;
@@ -1145,7 +1157,7 @@ static int mds_init_slave_blimits(struct obd_device *obd,
         struct lustre_quota_ctxt *qctxt = &obt->obt_qctxt;
         struct mds_obd *mds = &obd->u.mds;
         struct obd_quotactl *ioqc;
-        unsigned int uid = 0, gid = 0;
+        unsigned int id[MAXQUOTAS] = { 0, 0 };
         int rc, rc1 = 0;
         int flag;
         ENTRY;
@@ -1180,15 +1192,14 @@ static int mds_init_slave_blimits(struct obd_device *obd,
 
         /* trigger local qunit pre-acquire */
         if (oqctl->qc_type == USRQUOTA)
-                uid = oqctl->qc_id;
+                id[USRQUOTA] = oqctl->qc_id;
         else
-                gid = oqctl->qc_id;
+                id[GRPQUOTA] = oqctl->qc_id;
 
         /* initialize all slave's limit */
         rc = obd_quotactl(mds->mds_osc_exp, ioqc);
 
-        rc = qctxt_adjust_qunit(obd, &obd->u.obt.obt_qctxt, uid, gid, 1, 0,
-                                NULL);
+        rc = qctxt_adjust_qunit(obd, &obd->u.obt.obt_qctxt, id, 1, 0, NULL);
         if (rc == -EDQUOT || rc == -EBUSY) {
                 CDEBUG(D_QUOTA, "rc: %d.\n", rc);
                 rc = 0;
@@ -1228,6 +1239,10 @@ int mds_set_dqblk(struct obd_device *obd, struct obd_quotactl *oqctl)
         int rc, rc2 = 0, flag = 0;
         ENTRY;
 
+        if (oqctl->qc_type != USRQUOTA &&
+            oqctl->qc_type != GRPQUOTA)
+                RETURN(-EINVAL);
+
         OBD_ALLOC_PTR(oqaq);
         if (!oqaq)
                 RETURN(-ENOMEM);
@@ -1393,7 +1408,7 @@ static int mds_get_space(struct obd_device *obd, struct obd_quotactl *oqctl)
         /* get block usage from OSS */
         soqc->qc_dqblk.dqb_curspace = 0;
         rc = obd_quotactl(obd->u.mds.mds_osc_exp, soqc);
-        if (!rc) {
+        if (!rc || rc == -EREMOTEIO) {
                 oqctl->qc_dqblk.dqb_curspace = soqc->qc_dqblk.dqb_curspace;
                 oqctl->qc_dqblk.dqb_valid |= QIF_SPACE;
         }
@@ -1424,6 +1439,10 @@ int mds_get_dqblk(struct obd_device *obd, struct obd_quotactl *oqctl)
         int rc;
         ENTRY;
 
+        if (oqctl->qc_type != USRQUOTA &&
+            oqctl->qc_type != GRPQUOTA)
+                RETURN(-EINVAL);
+
         down(&mds->mds_qonoff_sem);
         dqblk->dqb_valid = 0;
         if (qinfo->qi_files[oqctl->qc_type] == NULL)
@@ -1552,17 +1571,22 @@ static int qmaster_recovery_main(void *arg)
 {
         struct qmaster_recov_thread_data *data = arg;
         struct obd_device *obd = data->obd;
+        struct mds_obd *mds = &obd->u.mds;
+        struct lustre_quota_info *qinfo = &mds->mds_quota_info;
         int rc = 0;
         unsigned short type;
         ENTRY;
 
         ptlrpc_daemonize("qmaster_recovd");
 
+        /* for mds */
+        class_incref(obd, "qmaster_recovd_mds", obd);
+        /* for lov */
+        class_incref(mds->mds_osc_obd, "qmaster_recovd_lov", mds->mds_osc_obd);
+
         complete(&data->comp);
 
         for (type = USRQUOTA; type < MAXQUOTAS; type++) {
-                struct mds_obd *mds = &obd->u.mds;
-                struct lustre_quota_info *qinfo = &mds->mds_quota_info;
                 struct list_head id_list;
                 struct dquot_id *dqid, *tmp;
 
@@ -1592,23 +1616,30 @@ free:
                         kfree(dqid);
                 }
         }
+        class_decref(mds->mds_osc_obd, "qmaster_recovd_lov", mds->mds_osc_obd);
+        class_decref(obd, "qmaster_recovd_mds", obd);
         RETURN(rc);
 }
 
 int mds_quota_recovery(struct obd_device *obd)
 {
-        struct lov_obd *lov = &obd->u.mds.mds_osc_obd->u.lov;
+        struct mds_obd *mds = &obd->u.mds;
         struct qmaster_recov_thread_data data;
         int rc = 0;
         ENTRY;
 
-        mutex_down(&lov->lov_lock);
-        if (lov->desc.ld_tgt_count != lov->desc.ld_active_tgt_count) {
-                CWARN("Not all osts are active, abort quota recovery\n");
-                mutex_up(&lov->lov_lock);
+        if (unlikely(!mds->mds_quota || obd->obd_stopping))
+                RETURN(rc);
+
+        mutex_down(&obd->obd_dev_sem);
+        if (mds->mds_lov_desc.ld_active_tgt_count != mds->mds_lov_objid_count) {
+                CWARN("Only %u/%u OSTs are active, abort quota recovery\n",
+                      mds->mds_lov_desc.ld_active_tgt_count,
+                      mds->mds_lov_objid_count);
+                mutex_up(&obd->obd_dev_sem);
                 RETURN(rc);
         }
-        mutex_up(&lov->lov_lock);
+        mutex_up(&obd->obd_dev_sem);
 
         data.obd = obd;
         init_completion(&data.comp);