コード例 #1
0
ファイル: lproc_quota.c プロジェクト: DCteam/lustre
/*
 * generic_quota_on is very lazy and tolerant about current quota settings
 * @global means to turn on quotas on each OST additionally to local quotas;
 * should not be called from filter_quota_ctl on MDS nodes (as it starts
 * admin quotas on MDS nodes).
 */
int generic_quota_on(struct obd_device *obd, struct obd_quotactl *oqctl, int global)
{
        struct obd_device_target *obt = &obd->u.obt;
        struct lvfs_run_ctxt saved;
        int id, is_master, rc = 0, local; /* means we need a local quotaon */

        cfs_down(&obt->obt_quotachecking);
        push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
        id = UGQUOTA2LQC(oqctl->qc_type);
        local = (obt->obt_qctxt.lqc_flags & id) != id;

        oqctl->qc_cmd = Q_QUOTAON;
        oqctl->qc_id = obt->obt_qfmt;

        is_master = !strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME);
        if (is_master) {
                cfs_down_write(&obd->u.mds.mds_qonoff_sem);
                if (local) {
                        /* turn on cluster wide quota */
                        rc = mds_admin_quota_on(obd, oqctl);
                        if (rc && rc != -ENOENT)
                                CERROR("%s: %s admin quotaon failed. rc=%d\n",
                                       obd->obd_name, global ? "global":"local",
                                       rc);
                }
        }

        if (rc == 0) {
                if (local) {
                        rc = fsfilt_quotactl(obd, obt->obt_sb, oqctl);
                        if (rc) {
                                if (rc != -ENOENT)
                                        CERROR("%s: %s quotaon failed with"
                                               " rc=%d\n", obd->obd_name,
                                               global ? "global" : "local", rc);
                        } else {
                                obt->obt_qctxt.lqc_flags |= UGQUOTA2LQC(oqctl->qc_type);
                                build_lqs(obd);
                        }
                }

                if (rc == 0 && global && is_master)
                        rc = obd_quotactl(obd->u.mds.mds_lov_exp, oqctl);
        }

        if (is_master)
                cfs_up_write(&obd->u.mds.mds_qonoff_sem);

        pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
        cfs_up(&obt->obt_quotachecking);

        return rc;
}
コード例 #2
0
ファイル: quota_ctl.c プロジェクト: LLNL/lustre
int filter_quota_ctl(struct obd_device *unused, struct obd_export *exp,
                     struct obd_quotactl *oqctl)
{
        struct obd_device *obd = exp->exp_obd;
        struct obd_device_target *obt = &obd->u.obt;
        struct lvfs_run_ctxt saved;
        struct lustre_quota_ctxt *qctxt = &obt->obt_qctxt;
        struct lustre_qunit_size *lqs;
        void *handle = NULL;
        struct timeval work_start;
        struct timeval work_end;
        long timediff;
        int rc = 0;
        ENTRY;

        cfs_gettimeofday(&work_start);
        switch (oqctl->qc_cmd) {
        case Q_QUOTAON:
                oqctl->qc_id = obt->obt_qfmt;
                rc = generic_quota_on(obd, oqctl, 0);
                break;
        case Q_FINVALIDATE:
        case Q_QUOTAOFF:
                cfs_down(&obt->obt_quotachecking);
                if (oqctl->qc_cmd == Q_FINVALIDATE &&
                    (obt->obt_qctxt.lqc_flags & UGQUOTA2LQC(oqctl->qc_type))) {
                        CWARN("quota[%u] is on yet\n", oqctl->qc_type);
                        cfs_up(&obt->obt_quotachecking);
                        rc = -EBUSY;
                        break;
                }
                oqctl->qc_id = obt->obt_qfmt; /* override qfmt version */
        case Q_GETOINFO:
        case Q_GETOQUOTA:
        case Q_GETQUOTA:
                /* In recovery scenario, this pending dqacq/dqrel might have
                 * been processed by master successfully before it's dquot
                 * on master enter recovery mode. We must wait for this
                 * dqacq/dqrel done then return the correct limits to master */
                if (oqctl->qc_stat == QUOTA_RECOVERING)
                        handle = quota_barrier(&obd->u.obt.obt_qctxt, oqctl, 1);

                push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
                rc = fsfilt_quotactl(obd, obt->obt_sb, oqctl);
                pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);

                if (oqctl->qc_stat == QUOTA_RECOVERING)
                        quota_unbarrier(handle);

                if (oqctl->qc_cmd == Q_QUOTAOFF ||
                    oqctl->qc_cmd == Q_FINVALIDATE) {
                        if (oqctl->qc_cmd == Q_QUOTAOFF) {
                                if (!rc)
                                        obt->obt_qctxt.lqc_flags &=
                                                ~UGQUOTA2LQC(oqctl->qc_type);
                                else if (quota_is_off(qctxt, oqctl))
                                                rc = -EALREADY;
                                CDEBUG(D_QUOTA, "%s: quotaoff type:flags:rc "
                                       "%u:%lu:%d\n", obd->obd_name,
                                       oqctl->qc_type, qctxt->lqc_flags, rc);
                        }
                        cfs_up(&obt->obt_quotachecking);
                }

                break;
        case Q_SETQUOTA:
                /* currently, it is only used for nullifying the quota */
                handle = quota_barrier(&obd->u.obt.obt_qctxt, oqctl, 1);

                push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
                rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl);

                if (!rc) {
                        oqctl->qc_cmd = Q_SYNC;
                        fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl);
                        oqctl->qc_cmd = Q_SETQUOTA;
                }
                pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
                quota_unbarrier(handle);

                lqs = quota_search_lqs(LQS_KEY(oqctl->qc_type, oqctl->qc_id),
                                       qctxt, 0);
                if (lqs == NULL || IS_ERR(lqs)){
                        CERROR("fail to create lqs during setquota operation "
                               "for %sid %u\n", oqctl->qc_type ? "g" : "u",
                               oqctl->qc_id);
                } else {
                        lqs->lqs_flags &= ~QB_SET;
                        lqs_putref(lqs);
                }

                break;
        case Q_INITQUOTA:
                {
                unsigned int id[MAXQUOTAS] = { 0, 0 };

                /* Initialize quota limit to MIN_QLIMIT */
                LASSERT(oqctl->qc_dqblk.dqb_valid == QIF_BLIMITS);
                LASSERT(oqctl->qc_dqblk.dqb_bsoftlimit == 0);

                if (!oqctl->qc_dqblk.dqb_bhardlimit)
                        goto adjust;

               /* There might be a pending dqacq/dqrel (which is going to
                 * clear stale limits on slave). we should wait for it's
                 * completion then initialize limits */
                handle = quota_barrier(&obd->u.obt.obt_qctxt, oqctl, 1);
                LASSERT(oqctl->qc_dqblk.dqb_bhardlimit == MIN_QLIMIT);
                push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
                rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl);

                /* Update on-disk quota, in case of lose the changed limits
                 * (MIN_QLIMIT) on crash, which cannot be recovered.*/
                if (!rc) {
                        oqctl->qc_cmd = Q_SYNC;
                        fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl);
                        oqctl->qc_cmd = Q_INITQUOTA;
                }
                pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
                quota_unbarrier(handle);

                if (rc)
                        RETURN(rc);
adjust:
                lqs = quota_search_lqs(LQS_KEY(oqctl->qc_type, oqctl->qc_id),
                                       qctxt, 1);
                if (lqs == NULL || IS_ERR(lqs)){
                        CERROR("fail to create lqs during setquota operation "
                               "for %sid %u\n", oqctl->qc_type ? "g" : "u",
                               oqctl->qc_id);
                        break;
                } else {
                        lqs->lqs_flags |= QB_SET;
                        lqs_putref(lqs);
                }

                /* Trigger qunit pre-acquire */
                if (oqctl->qc_type == USRQUOTA)
                        id[USRQUOTA] = oqctl->qc_id;
                else
                        id[GRPQUOTA] = oqctl->qc_id;

                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;
                }

                break;
                }
        default:
                CERROR("%s: unsupported filter_quotactl command: %d\n",
                       obd->obd_name, oqctl->qc_cmd);
                RETURN(-EFAULT);
        }
        cfs_gettimeofday(&work_end);
        timediff = cfs_timeval_sub(&work_end, &work_start, NULL);
        lprocfs_counter_add(qctxt->lqc_stats, LQUOTA_QUOTA_CTL, timediff);

        RETURN(rc);
}
コード例 #3
0
ファイル: quota_interface.c プロジェクト: DCteam/lustre
static int filter_quota_getflag(struct obd_device *obd, struct obdo *oa)
{
        struct obd_device_target *obt = &obd->u.obt;
        struct lustre_quota_ctxt *qctxt = &obt->obt_qctxt;
        int err, cnt, rc = 0;
        struct obd_quotactl *oqctl;
        ENTRY;

        if (!ll_sb_any_quota_active(obt->obt_sb))
                RETURN(0);

        OBD_ALLOC_PTR(oqctl);
        if (!oqctl)
                RETURN(-ENOMEM);

        /* set over quota flags for a uid/gid */
        oa->o_valid |= OBD_MD_FLUSRQUOTA | OBD_MD_FLGRPQUOTA;
        oa->o_flags &= ~(OBD_FL_NO_USRQUOTA | OBD_FL_NO_GRPQUOTA);

        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                struct lustre_qunit_size *lqs = NULL;

                lqs = quota_search_lqs(LQS_KEY(cnt, GET_OA_ID(cnt, oa)),
                                       qctxt, 0);
                if (lqs == NULL || IS_ERR(lqs)) {
                        rc = PTR_ERR(lqs);
                        if (rc)
                                CDEBUG(D_QUOTA, "search lqs for %s %d failed, "
                                       "(rc = %d)\n",
                                       cnt == USRQUOTA ? "user" : "group",
                                       cnt == USRQUOTA ? oa->o_uid : oa->o_gid,
                                       rc);
                        break;
                } else {
                        cfs_spin_lock(&lqs->lqs_lock);
                        if (lqs->lqs_bunit_sz <= qctxt->lqc_sync_blk) {
                                oa->o_flags |= (cnt == USRQUOTA) ?
                                        OBD_FL_NO_USRQUOTA : OBD_FL_NO_GRPQUOTA;
                                cfs_spin_unlock(&lqs->lqs_lock);
                                CDEBUG(D_QUOTA, "set sync flag: bunit(%lu), "
                                       "sync_blk(%d)\n", lqs->lqs_bunit_sz,
                                       qctxt->lqc_sync_blk);
                                /* this is for quota_search_lqs */
                                lqs_putref(lqs);
                                continue;
                        }
                        cfs_spin_unlock(&lqs->lqs_lock);
                        /* this is for quota_search_lqs */
                        lqs_putref(lqs);
                }

                memset(oqctl, 0, sizeof(*oqctl));

                oqctl->qc_cmd = Q_GETQUOTA;
                oqctl->qc_type = cnt;
                oqctl->qc_id = (cnt == USRQUOTA) ? oa->o_uid : oa->o_gid;
                err = fsfilt_quotactl(obd, obt->obt_sb, oqctl);
                if (err) {
                        if (!rc)
                                rc = err;
                        oa->o_valid &= ~((cnt == USRQUOTA) ? OBD_MD_FLUSRQUOTA :
                                                             OBD_MD_FLGRPQUOTA);
                        CDEBUG(D_QUOTA, "fsfilt getquota for %s %d failed, "
                               "(rc = %d)\n",
                               cnt == USRQUOTA ? "user" : "group",
                               cnt == USRQUOTA ? oa->o_uid : oa->o_gid, err);
                        continue;
                }

                if (oqctl->qc_dqblk.dqb_bhardlimit &&
                   (toqb(oqctl->qc_dqblk.dqb_curspace) >=
                    oqctl->qc_dqblk.dqb_bhardlimit)) {
                        oa->o_flags |= (cnt == USRQUOTA) ?
                                OBD_FL_NO_USRQUOTA : OBD_FL_NO_GRPQUOTA;
                        CDEBUG(D_QUOTA, "out of quota for %s %d\n",
                               cnt == USRQUOTA ? "user" : "group",
                               cnt == USRQUOTA ? oa->o_uid : oa->o_gid);
                }
        }
        OBD_FREE_PTR(oqctl);
        RETURN(rc);
}
コード例 #4
0
ファイル: quota_check.c プロジェクト: DCteam/lustre
int target_quota_check(struct obd_device *obd, struct obd_export *exp,
                       struct obd_quotactl *oqctl)
{
        struct obd_device_target *obt = &obd->u.obt;
        struct quotacheck_thread_args *qta;
        int rc = 0;
        ENTRY;

        OBD_ALLOC_PTR(qta);
        if (!qta)
                RETURN(ENOMEM);

        cfs_down(&obt->obt_quotachecking);

        qta->qta_exp = exp;
        qta->qta_obd = obd;
        qta->qta_oqctl = *oqctl;
        qta->qta_oqctl.qc_id = obt->obt_qfmt; /* override qfmt version */
        qta->qta_sb = obt->obt_sb;
        qta->qta_sem = &obt->obt_quotachecking;

        /* quotaoff firstly */
        oqctl->qc_cmd = Q_QUOTAOFF;
        if (!strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME)) {
                rc = do_mds_quota_off(obd, oqctl);
                if (rc && rc != -EALREADY) {
                        CERROR("off quota on MDS failed: %d\n", rc);
                        GOTO(out, rc);
                }

                /* quota master */
                rc = init_admin_quotafiles(obd, &qta->qta_oqctl);
                if (rc) {
                        CERROR("init_admin_quotafiles failed: %d\n", rc);
                        GOTO(out, rc);
                }
        } else {
                struct lvfs_run_ctxt saved;
                struct lustre_quota_ctxt *qctxt = &obt->obt_qctxt;

                push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
                rc = fsfilt_quotactl(obd, obt->obt_sb, oqctl);
                pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
                if (!rc) {
                        qctxt->lqc_flags &= ~UGQUOTA2LQC(oqctl->qc_type);
                } else if (!quota_is_off(qctxt, oqctl)) {
                        CERROR("off quota on OSS failed: %d\n", rc);
                        GOTO(out, rc);
                }
        }

        /* we get ref for exp because target_quotacheck_callback() will use this
         * export later b=18126 */
        class_export_get(exp);
        rc = cfs_kernel_thread(target_quotacheck_thread, qta,
                               CLONE_VM|CLONE_FILES);
        if (rc >= 0) {
                /* target_quotacheck_thread will drop the ref on exp and release
                 * obt_quotachecking */
                CDEBUG(D_INFO, "%s: target_quotacheck_thread: %d\n",
                       obd->obd_name, rc);
                RETURN(0);
        } else {
                CERROR("%s: error starting quotacheck_thread: %d\n",
                       obd->obd_name, rc);
                class_export_put(exp);
                EXIT;
        }

out:
        cfs_up(&obt->obt_quotachecking);
        OBD_FREE_PTR(qta);
        return rc;
}