/* * Called when the MDS is fully configured. We use it to set up local objects * associated with the quota master target. * * \param env - is the environment passed by the caller * \param parent - is the lu_device of the parent, that's to say the mdt * \param ld - is the lu_device associated with the master target * * \retval - 0 on success, appropriate error on failure */ static int qmt_device_prepare(const struct lu_env *env, struct lu_device *parent, struct lu_device *ld) { struct qmt_device *qmt = lu2qmt_dev(ld); struct dt_object *qmt_root; int rc; ENTRY; /* initialize quota master root directory where all index files will be * stored */ qmt_root = lquota_disk_dir_find_create(env, qmt->qmt_child, NULL, QMT_DIR); if (IS_ERR(qmt_root)) { rc = PTR_ERR(qmt_root); CERROR("%s: failed to create master quota directory (%d)\n", qmt->qmt_svname, rc); RETURN(rc); } /* initialize on-disk indexes associated with each pool */ rc = qmt_pool_prepare(env, qmt, qmt_root); lu_object_put(env, &qmt_root->do_lu); RETURN(rc); }
/* * Free quota master target device. Companion of qmt_device_alloc() * * \param env - is the environment passed by the caller * \param ld - is the lu_device associated with the qmt dev to be freed * * \retval - NULL on success (backend OSD device is managed by the main stack), * appropriate error on failure */ static struct lu_device *qmt_device_free(const struct lu_env *env, struct lu_device *ld) { struct qmt_device *qmt = lu2qmt_dev(ld); ENTRY; LASSERT(qmt != NULL); lu_device_fini(ld); OBD_FREE_PTR(qmt); RETURN(NULL); }
/* * Release quota master target and all data structure associated with this * target. * Called on MDT0 cleanup. * * \param env - is the environment passed by the caller * \param ld - is the lu_device associated with the qmt device to be released * * \retval - NULL on success (backend OSD device is managed by the main stack), * appropriate error on failure */ static struct lu_device *qmt_device_fini(const struct lu_env *env, struct lu_device *ld) { struct qmt_device *qmt = lu2qmt_dev(ld); ENTRY; LASSERT(qmt != NULL); CDEBUG(D_QUOTA, "%s: initiating QMT shutdown\n", qmt->qmt_svname); qmt->qmt_stopping = true; /* kill pool instances, if any */ qmt_pool_fini(env, qmt); /* remove qmt proc entry */ if (qmt->qmt_proc != NULL && !IS_ERR(qmt->qmt_proc)) { lprocfs_remove(&qmt->qmt_proc); qmt->qmt_proc = NULL; } /* stop rebalance thread */ qmt_stop_reba_thread(qmt); /* disconnect from OSD */ if (qmt->qmt_child_exp != NULL) { obd_disconnect(qmt->qmt_child_exp); qmt->qmt_child_exp = NULL; qmt->qmt_child = NULL; } /* clear references to MDT namespace */ ld->ld_obd->obd_namespace = NULL; qmt->qmt_ns = NULL; RETURN(NULL); }
/* * Handle quota request from slave. * * \param env - is the environment passed by the caller * \param ld - is the lu device associated with the qmt * \param req - is the quota acquire request */ static int qmt_dqacq(const struct lu_env *env, struct lu_device *ld, struct ptlrpc_request *req) { struct qmt_device *qmt = lu2qmt_dev(ld); struct quota_body *qbody, *repbody; struct obd_uuid *uuid; struct ldlm_lock *lock; struct lquota_entry *lqe; int pool_id, pool_type, qtype; int rc; ENTRY; qbody = req_capsule_client_get(&req->rq_pill, &RMF_QUOTA_BODY); if (qbody == NULL) RETURN(err_serious(-EPROTO)); repbody = req_capsule_server_get(&req->rq_pill, &RMF_QUOTA_BODY); if (repbody == NULL) RETURN(err_serious(-EFAULT)); /* verify if global lock is stale */ if (!lustre_handle_is_used(&qbody->qb_glb_lockh)) RETURN(-ENOLCK); lock = ldlm_handle2lock(&qbody->qb_glb_lockh); if (lock == NULL) RETURN(-ENOLCK); LDLM_LOCK_PUT(lock); uuid = &req->rq_export->exp_client_uuid; if (req_is_rel(qbody->qb_flags) + req_is_acq(qbody->qb_flags) + req_is_preacq(qbody->qb_flags) > 1) { CERROR("%s: malformed quota request with conflicting flags set " "(%x) from slave %s\n", qmt->qmt_svname, qbody->qb_flags, obd_uuid2str(uuid)); RETURN(-EPROTO); } if (req_is_acq(qbody->qb_flags) || req_is_preacq(qbody->qb_flags)) { /* acquire and pre-acquire should use a valid ID lock */ if (!lustre_handle_is_used(&qbody->qb_lockh)) RETURN(-ENOLCK); lock = ldlm_handle2lock(&qbody->qb_lockh); if (lock == NULL) /* no lock associated with this handle */ RETURN(-ENOLCK); LDLM_DEBUG(lock, "%sacquire request", req_is_preacq(qbody->qb_flags) ? "pre" : ""); if (!obd_uuid_equals(&lock->l_export->exp_client_uuid, uuid)) { /* sorry, no way to cheat ... */ LDLM_LOCK_PUT(lock); RETURN(-ENOLCK); } if ((lock->l_flags & LDLM_FL_AST_SENT) != 0) { struct ptlrpc_service_part *svc; unsigned int timeout; svc = req->rq_rqbd->rqbd_svcpt; timeout = at_est2timeout(at_get(&svc->scp_at_estimate)); timeout = max(timeout, ldlm_timeout); /* lock is being cancelled, prolong timeout */ ldlm_refresh_waiting_lock(lock, timeout); } LDLM_LOCK_PUT(lock); } /* extract pool & quota information from global index FID packed in the * request */ rc = lquota_extract_fid(&qbody->qb_fid, &pool_id, &pool_type, &qtype); if (rc) RETURN(-EINVAL); /* Find the quota entry associated with the quota id */ lqe = qmt_pool_lqe_lookup(env, qmt, pool_id, pool_type, qtype, &qbody->qb_id); if (IS_ERR(lqe)) RETURN(PTR_ERR(lqe)); /* process quota request */ rc = qmt_dqacq0(env, lqe, qmt, uuid, qbody->qb_flags, qbody->qb_count, qbody->qb_usage, repbody); if (lustre_handle_is_used(&qbody->qb_lockh)) /* return current qunit value only to slaves owning an per-ID * quota lock. For enqueue, the qunit value will be returned in * the LVB */ repbody->qb_qunit = lqe->lqe_qunit; lqe_putref(lqe); RETURN(rc); }
/* * Handle quotactl request. * * \param env - is the environment passed by the caller * \param ld - is the lu device associated with the qmt * \param oqctl - is the quotactl request */ static int qmt_quotactl(const struct lu_env *env, struct lu_device *ld, struct obd_quotactl *oqctl) { struct qmt_thread_info *qti = qmt_info(env); union lquota_id *id = &qti->qti_id; struct qmt_device *qmt = lu2qmt_dev(ld); struct obd_dqblk *dqb = &oqctl->qc_dqblk; int rc = 0; ENTRY; LASSERT(qmt != NULL); if (oqctl->qc_type >= MAXQUOTAS) /* invalid quota type */ RETURN(-EINVAL); switch (oqctl->qc_cmd) { case Q_GETINFO: /* read grace times */ /* Global grace time is stored in quota settings of ID 0. */ id->qid_uid = 0; /* read inode grace time */ rc = qmt_get(env, qmt, 0, LQUOTA_RES_MD, oqctl->qc_type, id, NULL, NULL, &oqctl->qc_dqinfo.dqi_igrace); if (rc) break; /* read block grace time */ rc = qmt_get(env, qmt, 0, LQUOTA_RES_DT, oqctl->qc_type, id, NULL, NULL, &oqctl->qc_dqinfo.dqi_bgrace); break; case Q_SETINFO: /* modify grace times */ /* setinfo should be using dqi->dqi_valid, but lfs incorrectly * sets the valid flags in dqb->dqb_valid instead, try to live * with that ... */ /* Global grace time is stored in quota settings of ID 0. */ id->qid_uid = 0; if ((dqb->dqb_valid & QIF_ITIME) != 0) { /* set inode grace time */ rc = qmt_set(env, qmt, 0, LQUOTA_RES_MD, oqctl->qc_type, id, 0, 0, oqctl->qc_dqinfo.dqi_igrace, QIF_TIMES); if (rc) break; } if ((dqb->dqb_valid & QIF_BTIME) != 0) /* set block grace time */ rc = qmt_set(env, qmt, 0, LQUOTA_RES_DT, oqctl->qc_type, id, 0, 0, oqctl->qc_dqinfo.dqi_bgrace, QIF_TIMES); break; case Q_GETQUOTA: /* consult quota limit */ /* There is no quota limit for root user & group */ if (oqctl->qc_id == 0) { memset(dqb, 0, sizeof(*dqb)); dqb->dqb_valid = QIF_LIMITS | QIF_TIMES; break; } /* extract quota ID from quotactl request */ id->qid_uid = oqctl->qc_id; /* look-up inode quota settings */ rc = qmt_get(env, qmt, 0, LQUOTA_RES_MD, oqctl->qc_type, id, &dqb->dqb_ihardlimit, &dqb->dqb_isoftlimit, &dqb->dqb_itime); if (rc) break; dqb->dqb_valid |= QIF_ILIMITS | QIF_ITIME; /* master isn't aware of actual inode usage */ dqb->dqb_curinodes = 0; /* look-up block quota settings */ rc = qmt_get(env, qmt, 0, LQUOTA_RES_DT, oqctl->qc_type, id, &dqb->dqb_bhardlimit, &dqb->dqb_bsoftlimit, &dqb->dqb_btime); if (rc) break; dqb->dqb_valid |= QIF_BLIMITS | QIF_BTIME; /* master doesn't know the actual block usage */ dqb->dqb_curspace = 0; break; case Q_SETQUOTA: /* change quota limits */ if (oqctl->qc_id == 0) /* can't enforce a quota limit for root user & group */ RETURN(-EPERM); /* extract quota ID from quotactl request */ id->qid_uid = oqctl->qc_id; if ((dqb->dqb_valid & QIF_IFLAGS) != 0) { /* update inode quota settings */ rc = qmt_set(env, qmt, 0, LQUOTA_RES_MD, oqctl->qc_type, id, dqb->dqb_ihardlimit, dqb->dqb_isoftlimit, dqb->dqb_itime, dqb->dqb_valid & QIF_IFLAGS); if (rc) break; } if ((dqb->dqb_valid & QIF_BFLAGS) != 0) /* update block quota settings */ rc = qmt_set(env, qmt, 0, LQUOTA_RES_DT, oqctl->qc_type, id, dqb->dqb_bhardlimit, dqb->dqb_bsoftlimit, dqb->dqb_btime, dqb->dqb_valid & QIF_BFLAGS); break; case Q_QUOTAON: case Q_QUOTAOFF: /* quota is always turned on on the master */ RETURN(0); case LUSTRE_Q_INVALIDATE: /* not supported any more */ RETURN(-ENOTSUPP); default: CERROR("%s: unsupported quotactl command: %d\n", qmt->qmt_svname, oqctl->qc_cmd); RETURN(-ENOTSUPP); } RETURN(rc); }