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);
298 * Handle quotactl request.
300 * \param env - is the environment passed by the caller
301 * \param ld - is the lu device associated with the qmt
302 * \param oqctl - is the quotactl request
304 static int qmt_quotactl(const struct lu_env *env, struct lu_device *ld,
305 struct obd_quotactl *oqctl)
307 struct qmt_thread_info *qti = qmt_info(env);
308 union lquota_id *id = &qti->qti_id;
309 struct qmt_device *qmt = lu2qmt_dev(ld);
310 struct obd_dqblk *dqb = &oqctl->qc_dqblk;
314 LASSERT(qmt != NULL);
316 if (oqctl->qc_type >= MAXQUOTAS)
317 /* invalid quota type */
320 switch (oqctl->qc_cmd) {
322 case Q_GETINFO: /* read grace times */
323 /* read inode grace time */
324 rc = qmt_getinfo(env, qmt, 0, LQUOTA_RES_MD, oqctl->qc_type,
325 &oqctl->qc_dqinfo.dqi_igrace);
329 /* read block grace time */
330 rc = qmt_getinfo(env, qmt, 0, LQUOTA_RES_DT, oqctl->qc_type,
331 &oqctl->qc_dqinfo.dqi_bgrace);
334 case Q_SETINFO: /* modify grace times */
335 /* setinfo should be using dqi->dqi_valid, but lfs incorrectly
336 * sets the valid flags in dqb->dqb_valid instead, try to live
338 if ((dqb->dqb_valid & QIF_ITIME) != 0) {
339 /* set inode grace time */
340 rc = qmt_setinfo(env, qmt, 0, LQUOTA_RES_MD,
342 oqctl->qc_dqinfo.dqi_igrace);
347 if ((dqb->dqb_valid & QIF_BTIME) != 0)
348 /* set block grace time */
349 rc = qmt_setinfo(env, qmt, 0, LQUOTA_RES_DT,
351 oqctl->qc_dqinfo.dqi_bgrace);
354 case Q_GETQUOTA: /* consult quota limit */
355 /* There is no quota limit for root user & group */
356 if (oqctl->qc_id == 0) {
357 memset(dqb, 0, sizeof(*dqb));
358 dqb->dqb_valid = QIF_LIMITS | QIF_TIMES;
361 /* extract quota ID from quotactl request */
362 id->qid_uid = oqctl->qc_id;
364 /* look-up inode quota settings */
365 rc = qmt_getquota(env, qmt, 0, LQUOTA_RES_MD, oqctl->qc_type,
366 id, &dqb->dqb_ihardlimit,
367 &dqb->dqb_isoftlimit, &dqb->dqb_itime);
371 dqb->dqb_valid |= QIF_ILIMITS | QIF_ITIME;
372 /* master isn't aware of actual inode usage */
373 dqb->dqb_curinodes = 0;
375 /* look-up block quota settings */
376 rc = qmt_getquota(env, qmt, 0, LQUOTA_RES_DT, oqctl->qc_type,
377 id, &dqb->dqb_bhardlimit,
378 &dqb->dqb_bsoftlimit, &dqb->dqb_btime);
382 dqb->dqb_valid |= QIF_BLIMITS | QIF_BTIME;
383 /* master doesn't know the actual block usage */
384 dqb->dqb_curspace = 0;
387 case Q_SETQUOTA: /* change quota limits */
388 if (oqctl->qc_id == 0)
389 /* can't enforce a quota limit for root user & group */
391 /* extract quota ID from quotactl request */
392 id->qid_uid = oqctl->qc_id;
394 if ((dqb->dqb_valid & QIF_IFLAGS) != 0) {
395 /* update inode quota settings */
396 rc = qmt_setquota(env, qmt, 0, LQUOTA_RES_MD,
399 dqb->dqb_isoftlimit, dqb->dqb_itime,
400 dqb->dqb_valid & QIF_IFLAGS);
405 if ((dqb->dqb_valid & QIF_BFLAGS) != 0)
406 /* update block quota settings */
407 rc = qmt_setquota(env, qmt, 0, LQUOTA_RES_DT,
410 dqb->dqb_bsoftlimit, dqb->dqb_btime,
411 dqb->dqb_valid & QIF_BFLAGS);
415 case Q_QUOTAOFF: /* quota is always turned on on the master */
418 case LUSTRE_Q_INVALIDATE: /* not supported any more */
422 CERROR("%s: unsupported quotactl command: %d\n",
423 qmt->qmt_svname, oqctl->qc_cmd);
431 * Handle quota request from slave.
433 * \param env - is the environment passed by the caller
434 * \param ld - is the lu device associated with the qmt
435 * \param req - is the quota acquire request
437 static int qmt_dqacq(const struct lu_env *env, struct lu_device *ld,
438 struct ptlrpc_request *req)
440 struct quota_body *qbody, *repbody;
443 qbody = req_capsule_client_get(&req->rq_pill, &RMF_QUOTA_BODY);
445 RETURN(err_serious(-EPROTO));
447 repbody = req_capsule_server_get(&req->rq_pill, &RMF_QUOTA_BODY);
449 RETURN(err_serious(-EFAULT));
451 /* XXX: to be implemented */
456 /* Vector of quota request handlers. This vector is used by the MDT to forward
457 * requests to the quota master. */
458 struct qmt_handlers qmt_hdls = {
459 /* quota request handlers */
460 .qmth_quotactl = qmt_quotactl,
461 .qmth_dqacq = qmt_dqacq,
464 .qmth_intent_policy = qmt_intent_policy,
465 .qmth_lvbo_init = qmt_lvbo_init,
466 .qmth_lvbo_update = qmt_lvbo_update,
467 .qmth_lvbo_size = qmt_lvbo_size,
468 .qmth_lvbo_fill = qmt_lvbo_fill,
469 .qmth_lvbo_free = qmt_lvbo_free,
471 EXPORT_SYMBOL(qmt_hdls);