Esempio n. 1
0
/*
 * 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);
}
Esempio n. 2
0
/*
 * 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);
}
Esempio n. 3
0
/*
 * 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);
}
Esempio n. 4
0
/*
 * 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);
}
Esempio n. 5
0
/*
 * 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);
}