4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 021110-1307, USA
24 * Copyright (c) 2012 Intel, Inc.
25 * Use is subject to license terms.
27 * Author: Johann Lombardi <johann.lombardi@intel.com>
28 * Author: Niu Yawei <yawei.niu@intel.com>
32 # define EXPORT_SYMTAB
35 #define DEBUG_SUBSYSTEM S_LQUOTA
37 #include <obd_class.h>
38 #include "qmt_internal.h"
41 * Fetch grace time for either inode or block.
43 * \param env - is the environment passed by the caller
44 * \param qmt - is the quota master target
45 * \param pool_id - is the 16-bit pool identifier
46 * \param restype - is the pool type, either block (i.e. LQUOTA_RES_DT) or inode
47 * (i.e. LQUOTA_RES_MD)
48 * \param qtype - is the quota type
49 * \param time - is the output variable where to copy the grace time
51 static int qmt_getinfo(const struct lu_env *env, struct qmt_device *qmt,
52 __u16 pool_id, __u8 restype, __u8 qtype, __u64 *time)
54 struct qmt_thread_info *qti = qmt_info(env);
55 union lquota_id *id = &qti->qti_id_bis;
56 struct lquota_entry *lqe;
59 /* Global grace time is stored in quota settings of ID 0. */
62 /* look-up quota entry storing grace time */
63 lqe = qmt_pool_lqe_lookup(env, qmt, pool_id, restype, qtype, id);
68 LQUOTA_DEBUG(lqe, "getinfo");
70 *time = lqe->lqe_gracetime;
78 * Update grace time for either inode or block.
79 * Global grace time is stored in quota settings of ID 0.
81 * \param env - is the environment passed by the caller
82 * \param qmt - is the quota master target
83 * \param pool_id - is the 16-bit pool identifier
84 * \param restype - is the pool type, either block (i.e. LQUOTA_RES_DT) or inode
85 * (i.e. LQUOTA_RES_MD)
86 * \param qtype - is the quota type
87 * \param time - is the new grace time
89 static int qmt_setinfo(const struct lu_env *env, struct qmt_device *qmt,
90 __u16 pool_id, __u8 restype, __u8 qtype, __u64 time)
92 struct qmt_thread_info *qti = qmt_info(env);
93 union lquota_id *id = &qti->qti_id_bis;
94 struct lquota_entry *lqe;
95 struct thandle *th = NULL;
99 /* Global grace time is stored in quota settings of ID 0. */
102 /* look-up quota entry storing the global grace time */
103 lqe = qmt_pool_lqe_lookup(env, qmt, pool_id, restype, qtype, id);
105 RETURN(PTR_ERR(lqe));
107 /* allocate & start transaction with enough credits to update grace
108 * time in the global index file */
109 th = qmt_trans_start(env, lqe, &qti->qti_restore);
111 GOTO(out_nolock, rc = PTR_ERR(th));
113 /* write lock quota entry storing the grace time */
115 if (lqe->lqe_gracetime == time)
116 /* grace time is the same */
119 LQUOTA_DEBUG(lqe, "setinfo time:"LPU64, time);
121 /* set new grace time */
122 lqe->lqe_gracetime = time;
123 /* always set enforced bit for ID 0 to make sure it does not go away */
124 lqe->lqe_enforced = true;
126 /* write new grace time to disk, no need for version bump */
127 rc = qmt_glb_write(env, th, lqe, 0, NULL);
129 /* restore initial grace time */
130 qmt_restore(lqe, &qti->qti_restore);
135 lqe_write_unlock(lqe);
138 if (th != NULL && !IS_ERR(th))
139 dt_trans_stop(env, qmt->qmt_child, th);
144 * Retrieve quota settings for a given identifier.
146 * \param env - is the environment passed by the caller
147 * \param qmt - is the quota master target
148 * \param pool_id - is the 16-bit pool identifier
149 * \param restype - is the pool type, either block (i.e. LQUOTA_RES_DT) or inode
150 * (i.e. LQUOTA_RES_MD)
151 * \param qtype - is the quota type
152 * \param id - is the quota indentifier for which we want to acces quota
154 * \param hard - is the output variable where to copy the hard limit
155 * \param soft - is the output variable where to copy the soft limit
156 * \param time - is the output variable where to copy the grace time
158 static int qmt_getquota(const struct lu_env *env, struct qmt_device *qmt,
159 __u16 pool_id, __u8 restype, __u8 qtype,
160 union lquota_id *id, __u64 *hard, __u64 *soft,
163 struct lquota_entry *lqe;
166 /* look-up lqe structure containing quota settings */
167 lqe = qmt_pool_lqe_lookup(env, qmt, pool_id, restype, qtype, id);
169 RETURN(PTR_ERR(lqe));
171 /* copy quota settings */
173 LQUOTA_DEBUG(lqe, "getquota");
174 *hard = lqe->lqe_hardlimit;
175 *soft = lqe->lqe_softlimit;
176 *time = lqe->lqe_gracetime;
177 lqe_read_unlock(lqe);
184 * Update quota settings for a given identifier.
186 * \param env - is the environment passed by the caller
187 * \param qmt - is the quota master target
188 * \param pool_id - is the 16-bit pool identifier
189 * \param restype - is the pool type, either block (i.e. LQUOTA_RES_DT) or inode
190 * (i.e. LQUOTA_RES_MD)
191 * \param qtype - is the quota type
192 * \param id - is the quota indentifier for which we want to modify quota
194 * \param hard - is the new hard limit
195 * \param soft - is the new soft limit
196 * \param time - is the new grace time
197 * \param valid - is the list of settings to change
199 static int qmt_setquota(const struct lu_env *env, struct qmt_device *qmt,
200 __u16 pool_id, __u8 restype, __u8 qtype,
201 union lquota_id *id, __u64 hard, __u64 soft, __u64 time,
204 struct qmt_thread_info *qti = qmt_info(env);
205 struct lquota_entry *lqe;
206 struct thandle *th = NULL;
208 bool dirtied = false, bump_version = false;
212 /* fetch global grace time */
213 rc = qmt_getinfo(env, qmt, pool_id, restype, qtype, &grace);
217 /* look-up quota entry associated with this ID */
218 lqe = qmt_pool_lqe_lookup(env, qmt, pool_id, restype, qtype, id);
220 RETURN(PTR_ERR(lqe));
222 /* allocate & start transaction with enough credits to update quota
223 * settings in the global index file */
224 th = qmt_trans_start(env, lqe, &qti->qti_restore);
226 GOTO(out_nolock, rc = PTR_ERR(th));
229 LQUOTA_DEBUG(lqe, "setquota valid:%x hard:"LPU64" soft:"LPU64
230 " time:"LPU64, valid, hard, soft, time);
232 if ((valid & QIF_TIMES) != 0 && lqe->lqe_gracetime != time) {
233 /* change time settings */
234 lqe->lqe_gracetime = time;
238 if ((valid & QIF_LIMITS) != 0 &&
239 (lqe->lqe_hardlimit != hard || lqe->lqe_softlimit != soft)) {
240 bool enforced = lqe->lqe_enforced;
242 rc = qmt_validate_limits(lqe, hard, soft);
246 /* change quota limits */
247 lqe->lqe_hardlimit = hard;
248 lqe->lqe_softlimit = soft;
250 /* clear grace time */
251 if (lqe->lqe_softlimit == 0 ||
252 lqe->lqe_granted <= lqe->lqe_softlimit)
253 /* no soft limit or below soft limit, let's clear grace
255 lqe->lqe_gracetime = 0;
256 else if ((valid & QIF_TIMES) == 0)
257 /* set grace only if user hasn't provided his own */
258 lqe->lqe_gracetime = cfs_time_current_sec() + grace;
260 /* change enforced status based on new parameters */
261 if (lqe->lqe_hardlimit == 0 && lqe->lqe_softlimit == 0)
262 lqe->lqe_enforced = false;
264 lqe->lqe_enforced = true;
266 if ((enforced && !lqe->lqe_enforced) ||
267 (!enforced && lqe->lqe_enforced))
268 /* if enforced status has changed, we need to inform
269 * slave, therefore we need to bump the version */
276 /* write new quota settings to disk */
277 rc = qmt_glb_write(env, th, lqe,
278 bump_version ? LQUOTA_BUMP_VER : 0, &ver);
280 /* restore initial quota settings */
281 qmt_restore(lqe, &qti->qti_restore);
287 lqe_write_unlock(lqe);
291 if (th != NULL && !IS_ERR(th))
292 dt_trans_stop(env, qmt->qmt_child, th);
294 if (rc == 0 && bump_version)
295 qmt_glb_lock_notify(env, lqe, ver);
301 * Handle quotactl request.
303 * \param env - is the environment passed by the caller
304 * \param ld - is the lu device associated with the qmt
305 * \param oqctl - is the quotactl request
307 static int qmt_quotactl(const struct lu_env *env, struct lu_device *ld,
308 struct obd_quotactl *oqctl)
310 struct qmt_thread_info *qti = qmt_info(env);
311 union lquota_id *id = &qti->qti_id;
312 struct qmt_device *qmt = lu2qmt_dev(ld);
313 struct obd_dqblk *dqb = &oqctl->qc_dqblk;
317 LASSERT(qmt != NULL);
319 if (oqctl->qc_type >= MAXQUOTAS)
320 /* invalid quota type */
323 switch (oqctl->qc_cmd) {
325 case Q_GETINFO: /* read grace times */
326 /* read inode grace time */
327 rc = qmt_getinfo(env, qmt, 0, LQUOTA_RES_MD, oqctl->qc_type,
328 &oqctl->qc_dqinfo.dqi_igrace);
332 /* read block grace time */
333 rc = qmt_getinfo(env, qmt, 0, LQUOTA_RES_DT, oqctl->qc_type,
334 &oqctl->qc_dqinfo.dqi_bgrace);
337 case Q_SETINFO: /* modify grace times */
338 /* setinfo should be using dqi->dqi_valid, but lfs incorrectly
339 * sets the valid flags in dqb->dqb_valid instead, try to live
341 if ((dqb->dqb_valid & QIF_ITIME) != 0) {
342 /* set inode grace time */
343 rc = qmt_setinfo(env, qmt, 0, LQUOTA_RES_MD,
345 oqctl->qc_dqinfo.dqi_igrace);
350 if ((dqb->dqb_valid & QIF_BTIME) != 0)
351 /* set block grace time */
352 rc = qmt_setinfo(env, qmt, 0, LQUOTA_RES_DT,
354 oqctl->qc_dqinfo.dqi_bgrace);
357 case Q_GETQUOTA: /* consult quota limit */
358 /* There is no quota limit for root user & group */
359 if (oqctl->qc_id == 0) {
360 memset(dqb, 0, sizeof(*dqb));
361 dqb->dqb_valid = QIF_LIMITS | QIF_TIMES;
364 /* extract quota ID from quotactl request */
365 id->qid_uid = oqctl->qc_id;
367 /* look-up inode quota settings */
368 rc = qmt_getquota(env, qmt, 0, LQUOTA_RES_MD, oqctl->qc_type,
369 id, &dqb->dqb_ihardlimit,
370 &dqb->dqb_isoftlimit, &dqb->dqb_itime);
374 dqb->dqb_valid |= QIF_ILIMITS | QIF_ITIME;
375 /* master isn't aware of actual inode usage */
376 dqb->dqb_curinodes = 0;
378 /* look-up block quota settings */
379 rc = qmt_getquota(env, qmt, 0, LQUOTA_RES_DT, oqctl->qc_type,
380 id, &dqb->dqb_bhardlimit,
381 &dqb->dqb_bsoftlimit, &dqb->dqb_btime);
385 dqb->dqb_valid |= QIF_BLIMITS | QIF_BTIME;
386 /* master doesn't know the actual block usage */
387 dqb->dqb_curspace = 0;
390 case Q_SETQUOTA: /* change quota limits */
391 if (oqctl->qc_id == 0)
392 /* can't enforce a quota limit for root user & group */
394 /* extract quota ID from quotactl request */
395 id->qid_uid = oqctl->qc_id;
397 if ((dqb->dqb_valid & QIF_IFLAGS) != 0) {
398 /* update inode quota settings */
399 rc = qmt_setquota(env, qmt, 0, LQUOTA_RES_MD,
402 dqb->dqb_isoftlimit, dqb->dqb_itime,
403 dqb->dqb_valid & QIF_IFLAGS);
408 if ((dqb->dqb_valid & QIF_BFLAGS) != 0)
409 /* update block quota settings */
410 rc = qmt_setquota(env, qmt, 0, LQUOTA_RES_DT,
413 dqb->dqb_bsoftlimit, dqb->dqb_btime,
414 dqb->dqb_valid & QIF_BFLAGS);
418 case Q_QUOTAOFF: /* quota is always turned on on the master */
421 case LUSTRE_Q_INVALIDATE: /* not supported any more */
425 CERROR("%s: unsupported quotactl command: %d\n",
426 qmt->qmt_svname, oqctl->qc_cmd);
434 * Handle quota request from slave.
436 * \param env - is the environment passed by the caller
437 * \param ld - is the lu device associated with the qmt
438 * \param req - is the quota acquire request
440 static int qmt_dqacq(const struct lu_env *env, struct lu_device *ld,
441 struct ptlrpc_request *req)
443 struct quota_body *qbody, *repbody;
446 qbody = req_capsule_client_get(&req->rq_pill, &RMF_QUOTA_BODY);
448 RETURN(err_serious(-EPROTO));
450 repbody = req_capsule_server_get(&req->rq_pill, &RMF_QUOTA_BODY);
452 RETURN(err_serious(-EFAULT));
454 /* XXX: to be implemented */
459 /* Vector of quota request handlers. This vector is used by the MDT to forward
460 * requests to the quota master. */
461 struct qmt_handlers qmt_hdls = {
462 /* quota request handlers */
463 .qmth_quotactl = qmt_quotactl,
464 .qmth_dqacq = qmt_dqacq,
467 .qmth_intent_policy = qmt_intent_policy,
468 .qmth_lvbo_init = qmt_lvbo_init,
469 .qmth_lvbo_update = qmt_lvbo_update,
470 .qmth_lvbo_size = qmt_lvbo_size,
471 .qmth_lvbo_fill = qmt_lvbo_fill,
472 .qmth_lvbo_free = qmt_lvbo_free,
474 EXPORT_SYMBOL(qmt_hdls);