1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * lustre/quota/quota_interface.c
6 * Copyright (c) 2001-2005 Cluster File Systems, Inc.
8 * This file is part of Lustre, http://www.lustre.org.
10 * No redistribution or use is permitted outside of Cluster File Systems, Inc.
14 # define EXPORT_SYMTAB
16 #define DEBUG_SUBSYSTEM S_MDS
19 # include <linux/version.h>
20 # include <linux/module.h>
21 # include <linux/init.h>
22 # include <linux/fs.h>
23 # include <linux/jbd.h>
24 # include <linux/ext3_fs.h>
25 # include <linux/parser.h>
26 # if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
27 # include <linux/smp_lock.h>
28 # include <linux/buffer_head.h>
29 # include <linux/workqueue.h>
30 # include <linux/mount.h>
32 # include <linux/locks.h>
34 #else /* __KERNEL__ */
35 # include <liblustre.h>
38 #include <obd_class.h>
39 #include <lustre_mds.h>
40 #include <lustre_dlm.h>
41 #include <lustre_cfg.h>
43 #include <lustre_fsfilt.h>
44 #include <lustre_quota.h>
45 #include "quota_internal.h"
49 extern unsigned long default_bunit_sz;
50 extern unsigned long default_btune_ratio;
51 extern unsigned long default_iunit_sz;
52 extern unsigned long default_itune_ratio;
55 Opt_quotaon, Opt_iunit_sz, Opt_bunit_sz,
56 Opt_itune_ratio, Opt_btune_ratio, Opt_err,
59 static match_table_t tokens = {
60 {Opt_quotaon, "quotaon=%10s"},
61 {Opt_iunit_sz, "iunit=%u"},
62 {Opt_bunit_sz, "bunit=%u"},
63 {Opt_itune_ratio, "itune=%u"},
64 {Opt_btune_ratio, "btune=%u"},
69 quota_parse_config_args(char *options, int *quotaon, int *type,
70 struct lustre_quota_ctxt *qctxt)
73 substring_t args[MAX_OPT_ARGS];
76 unsigned long iunit = 0, bunit = 0, itune = 0, btune = 0;
79 while ((opt = strsep (&options, ",")) != NULL) {
84 token = match_token(opt, tokens, args);
87 char *quota_type = match_strdup(&args[0]);
89 GOTO(out, rc = -EINVAL);
92 if (strchr(quota_type, 'u') && strchr(quota_type, 'g'))
94 else if (strchr(quota_type, 'u'))
96 else if (strchr(quota_type, 'g'))
105 if (match_int(&args[0], &option))
110 if (match_int(&args[0], &option))
114 case Opt_itune_ratio:
115 if (match_int(&args[0], &option) ||
116 option <= 0 || option >= 100)
120 case Opt_btune_ratio:
121 if (match_int(&args[0], &option) ||
122 option <= 0 || option >= 100)
134 /* adjust the tunables of qunits based on quota config args */
136 qctxt->lqc_iunit_sz = iunit;
138 qctxt->lqc_itune_sz = qctxt->lqc_iunit_sz *
141 qctxt->lqc_itune_sz = qctxt->lqc_iunit_sz *
142 default_itune_ratio / 100;
144 qctxt->lqc_bunit_sz = bunit << 20;
146 qctxt->lqc_btune_sz = ((qctxt->lqc_bunit_sz >> 20) *
149 qctxt->lqc_btune_sz = ((qctxt->lqc_bunit_sz >> 20) *
150 default_btune_ratio / 100) << 20;
152 CDEBUG(D_INFO, "iunit=%lu bunit=%lu itune=%lu btune=%lu\n",
153 qctxt->lqc_iunit_sz, qctxt->lqc_bunit_sz,
154 qctxt->lqc_itune_sz, qctxt->lqc_btune_sz);
159 CERROR("quota config args parse error!(rc = %d) usage: "
160 "--quota quotaon=u|g|ug,iunit=100,bunit=100,itune=50,btune=50\n",
166 static int auto_quota_on(struct obd_device *obd, int type,
167 struct super_block *sb, int is_master)
169 struct obd_quotactl *oqctl;
170 struct lvfs_run_ctxt saved;
174 LASSERT(type == USRQUOTA || type == GRPQUOTA || type == UGQUOTA);
176 OBD_ALLOC_PTR(oqctl);
180 oqctl->qc_type = type;
181 oqctl->qc_cmd = Q_QUOTAON;
182 oqctl->qc_id = QFMT_LDISKFS;
184 push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
189 /* turn on cluster wide quota */
190 rc = mds_admin_quota_on(obd, oqctl);
192 CERROR("auto enable admin quota error! err = %d\n", rc);
196 /* turn on local quota */
197 rc = fsfilt_quotactl(obd, sb, oqctl);
198 CDEBUG_EX(rc ? D_ERROR : D_INFO, "auto-enable quota. rc=%d\n", rc);
200 mds_quota_off(obd, oqctl);
202 pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
208 static int mds_auto_quota_on(struct obd_device *obd, int type)
212 rc = auto_quota_on(obd, type, obd->u.obt.obt_sb, 1);
216 static int filter_auto_quota_on(struct obd_device *obd, int type)
220 rc = auto_quota_on(obd, type, obd->u.obt.obt_sb, 0);
224 static int filter_quota_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
227 struct obd_device_target *obt = &obd->u.obt;
230 atomic_set(&obt->obt_quotachecking, 1);
231 rc = qctxt_init(&obt->obt_qctxt, obt->obt_sb, NULL);
233 CERROR("initialize quota context failed! (rc:%d)\n", rc);
237 /* Based on quota config args, set qunit sizes and enable quota */
238 if (LUSTRE_CFG_BUFLEN(lcfg, 5) > 0 && lustre_cfg_buf(lcfg, 5)) {
239 char *args = lustre_cfg_string(lcfg, 5);
240 int quotaon = 0, type;
243 err = quota_parse_config_args(args, "aon, &type,
244 &obd->u.obt.obt_qctxt);
246 filter_auto_quota_on(obd, type);
252 static int filter_quota_cleanup(struct obd_device *obd)
254 qctxt_cleanup(&obd->u.obt.obt_qctxt, 0);
258 static int filter_quota_setinfo(struct obd_export *exp, struct obd_device *obd)
260 /* setup the quota context import */
261 obd->u.obt.obt_qctxt.lqc_import = exp->exp_imp_reverse;
262 /* start quota slave recovery thread. (release high limits) */
263 qslave_start_recovery(obd, &obd->u.obt.obt_qctxt);
266 static int filter_quota_enforce(struct obd_device *obd, unsigned int ignore)
270 if (!sb_any_quota_enabled(obd->u.obt.obt_sb))
274 cap_raise(current->cap_effective, CAP_SYS_RESOURCE);
276 cap_lower(current->cap_effective, CAP_SYS_RESOURCE);
281 static int filter_quota_getflag(struct obd_device *obd, struct obdo *oa)
283 struct obd_device_target *obt = &obd->u.obt;
284 int err, cnt, rc = 0;
285 struct obd_quotactl *oqctl;
288 if (!sb_any_quota_enabled(obt->obt_sb))
291 oa->o_flags &= ~(OBD_FL_NO_USRQUOTA | OBD_FL_NO_GRPQUOTA);
293 OBD_ALLOC_PTR(oqctl);
295 CERROR("Not enough memory!");
299 for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
300 memset(oqctl, 0, sizeof(*oqctl));
302 oqctl->qc_cmd = Q_GETQUOTA;
303 oqctl->qc_type = cnt;
304 oqctl->qc_id = (cnt == USRQUOTA) ? oa->o_uid : oa->o_gid;
305 err = fsfilt_quotactl(obd, obt->obt_sb, oqctl);
312 /* set over quota flags for a uid/gid */
313 oa->o_valid |= (cnt == USRQUOTA) ?
314 OBD_MD_FLUSRQUOTA : OBD_MD_FLGRPQUOTA;
315 if (oqctl->qc_dqblk.dqb_bhardlimit &&
316 (toqb(oqctl->qc_dqblk.dqb_curspace) >
317 oqctl->qc_dqblk.dqb_bhardlimit))
318 oa->o_flags |= (cnt == USRQUOTA) ?
319 OBD_FL_NO_USRQUOTA : OBD_FL_NO_GRPQUOTA;
325 static int filter_quota_acquire(struct obd_device *obd, unsigned int uid,
328 struct lustre_quota_ctxt *qctxt = &obd->u.obt.obt_qctxt;
332 rc = qctxt_adjust_qunit(obd, qctxt, uid, gid, 1, 1);
333 RETURN(rc == -EAGAIN);
336 static int mds_quota_init(void)
338 return lustre_dquot_init();
341 static int mds_quota_exit(void)
347 static int mds_quota_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
349 struct obd_device_target *obt = &obd->u.obt;
350 struct mds_obd *mds = &obd->u.mds;
354 atomic_set(&obt->obt_quotachecking, 1);
355 /* initialize quota master and quota context */
356 sema_init(&mds->mds_qonoff_sem, 1);
357 rc = qctxt_init(&obt->obt_qctxt, obt->obt_sb, dqacq_handler);
359 CERROR("initialize quota context failed! (rc:%d)\n", rc);
363 /* Based on quota config args, set qunit sizes and enable quota */
364 if (LUSTRE_CFG_BUFLEN(lcfg, 5) > 0 && lustre_cfg_buf(lcfg, 5)) {
365 char *args = lustre_cfg_string(lcfg, 5);
366 int quotaon = 0, type;
369 err = quota_parse_config_args(args, "aon, &type,
372 mds_auto_quota_on(obd, type);
377 static int mds_quota_cleanup(struct obd_device *obd)
379 qctxt_cleanup(&obd->u.obt.obt_qctxt, 0);
383 static int mds_quota_fs_cleanup(struct obd_device *obd)
385 struct mds_obd *mds = &obd->u.mds;
389 /* close admin quota files */
390 down(&mds->mds_qonoff_sem);
391 for (i = 0; i < MAXQUOTAS; i++) {
392 if (mds->mds_quota_info.qi_files[i]) {
393 filp_close(mds->mds_quota_info.qi_files[i], 0);
394 mds->mds_quota_info.qi_files[i] = NULL;
397 up(&mds->mds_qonoff_sem);
400 #endif /* __KERNEL__ */
402 struct osc_quota_info {
403 struct list_head oqi_hash; /* hash list */
404 struct client_obd *oqi_cli; /* osc obd */
405 unsigned int oqi_id; /* uid/gid of a file */
406 short oqi_type; /* quota type */
409 spinlock_t qinfo_list_lock = SPIN_LOCK_UNLOCKED;
411 static struct list_head qinfo_hash[NR_DQHASH];
412 /* SLAB cache for client quota context */
413 cfs_mem_cache_t *qinfo_cachep = NULL;
415 static inline int const hashfn(struct client_obd *cli,
419 unsigned long tmp = ((unsigned long)cli>>6) ^ id;
420 tmp = (tmp * (MAXQUOTAS - type)) % NR_DQHASH;
424 /* caller must hold qinfo_list_lock */
425 static inline void insert_qinfo_hash(struct osc_quota_info *oqi)
427 struct list_head *head = qinfo_hash +
428 hashfn(oqi->oqi_cli, oqi->oqi_id, oqi->oqi_type);
430 LASSERT_SPIN_LOCKED(&qinfo_list_lock);
431 list_add(&oqi->oqi_hash, head);
434 /* caller must hold qinfo_list_lock */
435 static inline void remove_qinfo_hash(struct osc_quota_info *oqi)
437 LASSERT_SPIN_LOCKED(&qinfo_list_lock);
438 list_del_init(&oqi->oqi_hash);
441 /* caller must hold qinfo_list_lock */
442 static inline struct osc_quota_info *find_qinfo(struct client_obd *cli,
443 unsigned int id, int type)
445 unsigned int hashent = hashfn(cli, id, type);
446 struct osc_quota_info *oqi;
448 LASSERT_SPIN_LOCKED(&qinfo_list_lock);
449 list_for_each_entry(oqi, &qinfo_hash[hashent], oqi_hash) {
450 if (oqi->oqi_cli == cli &&
451 oqi->oqi_id == id && oqi->oqi_type == type)
457 static struct osc_quota_info *alloc_qinfo(struct client_obd *cli,
458 unsigned int id, int type)
460 struct osc_quota_info *oqi;
463 OBD_SLAB_ALLOC(oqi, qinfo_cachep, CFS_ALLOC_STD, sizeof(*oqi));
467 INIT_LIST_HEAD(&oqi->oqi_hash);
470 oqi->oqi_type = type;
475 static void free_qinfo(struct osc_quota_info *oqi)
477 OBD_SLAB_FREE(oqi, qinfo_cachep, sizeof(*oqi));
480 int osc_quota_chkdq(struct client_obd *cli,
481 unsigned int uid, unsigned int gid)
484 int cnt, rc = QUOTA_OK;
487 spin_lock(&qinfo_list_lock);
488 for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
489 struct osc_quota_info *oqi = NULL;
491 id = (cnt == USRQUOTA) ? uid : gid;
492 oqi = find_qinfo(cli, id, cnt);
498 spin_unlock(&qinfo_list_lock);
503 int osc_quota_setdq(struct client_obd *cli,
504 unsigned int uid, unsigned int gid,
505 obd_flag valid, obd_flag flags)
513 for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
514 struct osc_quota_info *oqi, *old;
516 if (!(valid & ((cnt == USRQUOTA) ?
517 OBD_MD_FLUSRQUOTA : OBD_MD_FLGRPQUOTA)))
520 id = (cnt == USRQUOTA) ? uid : gid;
521 noquota = (cnt == USRQUOTA) ?
522 (flags & OBD_FL_NO_USRQUOTA) : (flags & OBD_FL_NO_GRPQUOTA);
524 oqi = alloc_qinfo(cli, id, cnt);
526 spin_lock(&qinfo_list_lock);
528 old = find_qinfo(cli, id, cnt);
530 remove_qinfo_hash(old);
531 else if (!old && noquota)
532 insert_qinfo_hash(oqi);
534 spin_unlock(&qinfo_list_lock);
541 CERROR("not enough mem!\n");
550 int osc_quota_cleanup(struct obd_device *obd)
552 struct client_obd *cli = &obd->u.cli;
553 struct osc_quota_info *oqi, *n;
557 spin_lock(&qinfo_list_lock);
558 for (i = 0; i < NR_DQHASH; i++) {
559 list_for_each_entry_safe(oqi, n, &qinfo_hash[i], oqi_hash) {
560 if (oqi->oqi_cli != cli)
562 remove_qinfo_hash(oqi);
566 spin_unlock(&qinfo_list_lock);
571 int osc_quota_init(void)
576 LASSERT(qinfo_cachep == NULL);
577 qinfo_cachep = cfs_mem_cache_create("osc_quota_info",
578 sizeof(struct osc_quota_info),
583 for (i = 0; i < NR_DQHASH; i++)
584 INIT_LIST_HEAD(qinfo_hash + i);
589 int osc_quota_exit(void)
591 struct osc_quota_info *oqi, *n;
595 spin_lock(&qinfo_list_lock);
596 for (i = 0; i < NR_DQHASH; i++) {
597 list_for_each_entry_safe(oqi, n, &qinfo_hash[i], oqi_hash) {
598 remove_qinfo_hash(oqi);
602 spin_unlock(&qinfo_list_lock);
604 rc = cfs_mem_cache_destroy(qinfo_cachep);
605 LASSERTF(rc == 0, "couldn't destory qinfo_cachep slab\n");
612 quota_interface_t mds_quota_interface = {
613 .quota_init = mds_quota_init,
614 .quota_exit = mds_quota_exit,
615 .quota_setup = mds_quota_setup,
616 .quota_cleanup = mds_quota_cleanup,
617 .quota_check = target_quota_check,
618 .quota_ctl = mds_quota_ctl,
619 .quota_fs_cleanup =mds_quota_fs_cleanup,
620 .quota_recovery = mds_quota_recovery,
621 .quota_adjust = mds_quota_adjust,
624 quota_interface_t filter_quota_interface = {
625 .quota_setup = filter_quota_setup,
626 .quota_cleanup = filter_quota_cleanup,
627 .quota_check = target_quota_check,
628 .quota_ctl = filter_quota_ctl,
629 .quota_setinfo = filter_quota_setinfo,
630 .quota_enforce = filter_quota_enforce,
631 .quota_getflag = filter_quota_getflag,
632 .quota_acquire = filter_quota_acquire,
633 .quota_adjust = filter_quota_adjust,
635 #endif /* __KERNEL__ */
637 quota_interface_t mdc_quota_interface = {
638 .quota_ctl = client_quota_ctl,
639 .quota_check = client_quota_check,
640 .quota_poll_check = client_quota_poll_check,
643 quota_interface_t osc_quota_interface = {
644 .quota_ctl = client_quota_ctl,
645 .quota_check = client_quota_check,
646 .quota_poll_check = client_quota_poll_check,
647 .quota_init = osc_quota_init,
648 .quota_exit = osc_quota_exit,
649 .quota_chkdq = osc_quota_chkdq,
650 .quota_setdq = osc_quota_setdq,
651 .quota_cleanup = osc_quota_cleanup,
654 quota_interface_t lov_quota_interface = {
655 .quota_check = lov_quota_check,
656 .quota_ctl = lov_quota_ctl,
660 static int __init init_lustre_quota(void)
662 int rc = qunit_cache_init();
665 PORTAL_SYMBOL_REGISTER(filter_quota_interface);
666 PORTAL_SYMBOL_REGISTER(mds_quota_interface);
667 PORTAL_SYMBOL_REGISTER(mdc_quota_interface);
668 PORTAL_SYMBOL_REGISTER(osc_quota_interface);
669 PORTAL_SYMBOL_REGISTER(lov_quota_interface);
673 static void /*__exit*/ exit_lustre_quota(void)
675 PORTAL_SYMBOL_UNREGISTER(filter_quota_interface);
676 PORTAL_SYMBOL_UNREGISTER(mds_quota_interface);
677 PORTAL_SYMBOL_UNREGISTER(mdc_quota_interface);
678 PORTAL_SYMBOL_UNREGISTER(osc_quota_interface);
679 PORTAL_SYMBOL_UNREGISTER(lov_quota_interface);
681 qunit_cache_cleanup();
684 MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
685 MODULE_DESCRIPTION("Lustre Quota");
686 MODULE_LICENSE("GPL");
688 cfs_module(lquota, "1.0.0", init_lustre_quota, exit_lustre_quota);
690 EXPORT_SYMBOL(mds_quota_interface);
691 EXPORT_SYMBOL(filter_quota_interface);
692 EXPORT_SYMBOL(mdc_quota_interface);
693 EXPORT_SYMBOL(osc_quota_interface);
694 EXPORT_SYMBOL(lov_quota_interface);
695 #endif /* __KERNEL */