1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
6 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 only,
10 * as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License version 2 for more details (a copy is included
16 * in the LICENSE file that accompanied this code).
18 * You should have received a copy of the GNU General Public License
19 * version 2 along with this program; If not, see
20 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
22 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23 * CA 95054 USA or visit www.sun.com if you need additional information or
29 * Copyright 2008 Sun Microsystems, Inc. All rights reserved
30 * Use is subject to license terms.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
37 #define DEBUG_SUBSYSTEM S_LQUOTA
39 #include <linux/version.h>
40 #include <lprocfs_status.h>
42 #include <linux/seq_file.h>
43 #include <lustre_fsfilt.h>
45 #include "quota_internal.h"
47 #ifdef HAVE_QUOTA_SUPPORT
50 int lprocfs_quota_rd_bunit(char *page, char **start, off_t off, int count,
53 struct obd_device *obd = (struct obd_device *)data;
56 return snprintf(page, count, "%lu\n",
57 obd->u.obt.obt_qctxt.lqc_bunit_sz);
59 EXPORT_SYMBOL(lprocfs_quota_rd_bunit);
61 int lprocfs_quota_wr_bunit(struct file *file, const char *buffer,
62 unsigned long count, void *data)
64 struct obd_device *obd = (struct obd_device *)data;
68 rc = lprocfs_write_helper(buffer, count, &val);
72 if (val % QUOTABLOCK_SIZE ||
73 val <= obd->u.obt.obt_qctxt.lqc_btune_sz)
76 obd->u.obt.obt_qctxt.lqc_bunit_sz = val;
79 EXPORT_SYMBOL(lprocfs_quota_wr_bunit);
81 int lprocfs_quota_rd_btune(char *page, char **start, off_t off, int count,
84 struct obd_device *obd = (struct obd_device *)data;
87 return snprintf(page, count, "%lu\n",
88 obd->u.obt.obt_qctxt.lqc_btune_sz);
90 EXPORT_SYMBOL(lprocfs_quota_rd_btune);
92 int lprocfs_quota_wr_btune(struct file *file, const char *buffer,
93 unsigned long count, void *data)
95 struct obd_device *obd = (struct obd_device *)data;
99 rc = lprocfs_write_helper(buffer, count, &val);
103 if (val <= QUOTABLOCK_SIZE * MIN_QLIMIT || val % QUOTABLOCK_SIZE ||
104 val >= obd->u.obt.obt_qctxt.lqc_bunit_sz)
107 obd->u.obt.obt_qctxt.lqc_btune_sz = val;
110 EXPORT_SYMBOL(lprocfs_quota_wr_btune);
112 int lprocfs_quota_rd_iunit(char *page, char **start, off_t off, int count,
113 int *eof, void *data)
115 struct obd_device *obd = (struct obd_device *)data;
116 LASSERT(obd != NULL);
118 return snprintf(page, count, "%lu\n",
119 obd->u.obt.obt_qctxt.lqc_iunit_sz);
121 EXPORT_SYMBOL(lprocfs_quota_rd_iunit);
123 int lprocfs_quota_wr_iunit(struct file *file, const char *buffer,
124 unsigned long count, void *data)
126 struct obd_device *obd = (struct obd_device *)data;
128 LASSERT(obd != NULL);
130 rc = lprocfs_write_helper(buffer, count, &val);
134 if (val <= obd->u.obt.obt_qctxt.lqc_itune_sz)
137 obd->u.obt.obt_qctxt.lqc_iunit_sz = val;
140 EXPORT_SYMBOL(lprocfs_quota_wr_iunit);
142 int lprocfs_quota_rd_itune(char *page, char **start, off_t off, int count,
143 int *eof, void *data)
145 struct obd_device *obd = (struct obd_device *)data;
146 LASSERT(obd != NULL);
148 return snprintf(page, count, "%lu\n",
149 obd->u.obt.obt_qctxt.lqc_itune_sz);
151 EXPORT_SYMBOL(lprocfs_quota_rd_itune);
153 int lprocfs_quota_wr_itune(struct file *file, const char *buffer,
154 unsigned long count, void *data)
156 struct obd_device *obd = (struct obd_device *)data;
158 LASSERT(obd != NULL);
160 rc = lprocfs_write_helper(buffer, count, &val);
164 if (val <= MIN_QLIMIT ||
165 val >= obd->u.obt.obt_qctxt.lqc_iunit_sz)
168 obd->u.obt.obt_qctxt.lqc_itune_sz = val;
171 EXPORT_SYMBOL(lprocfs_quota_wr_itune);
174 #define GROUP_QUOTA 2
176 #define MAX_STYPE_SIZE 5
178 int lprocfs_quota_rd_type(char *page, char **start, off_t off, int count,
179 int *eof, void *data)
181 struct obd_device *obd = (struct obd_device *)data;
182 char stype[MAX_STYPE_SIZE + 1] = "";
184 struct obd_device_target *obt;
186 LASSERT(obd != NULL);
190 /* Collect the needed information */
191 oq_type = obd->u.obt.obt_qctxt.lqc_flags;
193 /* Transform the collected data into a user-readable string */
194 if (oq_type & LQC_USRQUOTA_FLAG)
196 if (oq_type & LQC_GRPQUOTA_FLAG)
201 return snprintf(page, count, "%s\n", stype);
203 EXPORT_SYMBOL(lprocfs_quota_rd_type);
205 static int auto_quota_on(struct obd_device *obd, int type,
206 struct super_block *sb, int is_master)
208 struct obd_quotactl *oqctl;
209 struct lvfs_run_ctxt saved;
210 int rc = 0, rc1 = 0, id;
211 struct obd_device_target *obt = &obd->u.obt;
212 struct lustre_quota_ctxt *qctxt = &obt->obt_qctxt;
213 struct mds_obd *mds = NULL;
216 LASSERT(type == USRQUOTA || type == GRPQUOTA || type == UGQUOTA);
218 OBD_ALLOC_PTR(oqctl);
222 down(&obt->obt_quotachecking);
223 id = UGQUOTA2LQC(type);
224 /* quota already turned on */
225 if ((obt->obt_qctxt.lqc_flags & id) == id)
228 if (obt->obt_qctxt.lqc_immutable) {
229 LCONSOLE_ERROR("Failed to turn Quota on, immutable mode "
230 "(is SOM enabled?)\n");
231 GOTO(out, rc = -ECANCELED);
234 oqctl->qc_type = type;
235 oqctl->qc_cmd = Q_QUOTAON;
236 oqctl->qc_id = obt->obt_qfmt;
238 push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
242 down(&mds->mds_qonoff_sem);
243 /* turn on cluster wide quota */
244 rc1 = mds_admin_quota_on(obd, oqctl);
245 if (rc1 && rc1 != -EALREADY) {
246 CDEBUG(rc1 == -ENOENT ? D_QUOTA : D_ERROR,
247 "auto-enable admin quota failed. rc=%d\n", rc1);
252 /* turn on local quota */
253 rc = fsfilt_quotactl(obd, sb, oqctl);
255 obt->obt_qctxt.lqc_flags |= UGQUOTA2LQC(type);
257 } else if (rc == -EBUSY && quota_is_on(qctxt, oqctl)) {
258 CWARN("%s: mds local quota[%d] is on already\n",
259 obd->obd_name, oqctl->qc_type);
262 CDEBUG(rc == -ENOENT ? D_QUOTA : D_ERROR,
263 "auto-enable local quota failed. rc=%d\n", rc);
264 if (rc1 == -EALREADY) {
265 oqctl->qc_cmd = Q_QUOTAOFF;
266 mds_admin_quota_off(obd, oqctl);
269 CWARN("%s: quotaon failed because quota files don't "
270 "exist, please run quotacheck firstly\n",
280 up(&mds->mds_qonoff_sem);
281 pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
284 up(&obt->obt_quotachecking);
289 int lprocfs_quota_wr_type(struct file *file, const char *buffer,
290 unsigned long count, void *data)
292 struct obd_device *obd = (struct obd_device *)data;
293 struct obd_device_target *obt;
294 int type = 0, is_mds;
296 char stype[MAX_STYPE_SIZE + 1] = "";
298 LASSERT(obd != NULL);
302 is_mds = !strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME);
304 if (count > MAX_STYPE_SIZE)
307 if (copy_from_user(stype, buffer, count))
310 for (i = 0 ; i < count ; i++) {
320 CWARN("quota_type options 1 and 2 are obsolete, "
321 "they will be ignored\n");
323 case '3' : /* the only valid version spec, do nothing */
324 default : /* just skip stray symbols like \n */
330 int rc = auto_quota_on(obd, type - 1, obt->obt_sb, is_mds);
332 if (rc && rc != -EALREADY && rc != -ENOENT)
338 EXPORT_SYMBOL(lprocfs_quota_wr_type);
340 int lprocfs_quota_rd_switch_seconds(char *page, char **start, off_t off,
341 int count, int *eof, void *data)
343 struct obd_device *obd = (struct obd_device *)data;
344 LASSERT(obd != NULL);
346 return snprintf(page, count, "%d\n",
347 obd->u.obt.obt_qctxt.lqc_switch_seconds);
349 EXPORT_SYMBOL(lprocfs_quota_rd_switch_seconds);
351 int lprocfs_quota_wr_switch_seconds(struct file *file, const char *buffer,
352 unsigned long count, void *data)
354 struct obd_device *obd = (struct obd_device *)data;
356 LASSERT(obd != NULL);
358 rc = lprocfs_write_helper(buffer, count, &val);
365 obd->u.obt.obt_qctxt.lqc_switch_seconds = val;
368 EXPORT_SYMBOL(lprocfs_quota_wr_switch_seconds);
370 int lprocfs_quota_rd_sync_blk(char *page, char **start, off_t off,
371 int count, int *eof, void *data)
373 struct obd_device *obd = (struct obd_device *)data;
374 LASSERT(obd != NULL);
376 return snprintf(page, count, "%d\n",
377 obd->u.obt.obt_qctxt.lqc_sync_blk);
379 EXPORT_SYMBOL(lprocfs_quota_rd_sync_blk);
381 int lprocfs_quota_wr_sync_blk(struct file *file, const char *buffer,
382 unsigned long count, void *data)
384 struct obd_device *obd = (struct obd_device *)data;
386 LASSERT(obd != NULL);
388 rc = lprocfs_write_helper(buffer, count, &val);
395 obd->u.obt.obt_qctxt.lqc_sync_blk = val;
398 EXPORT_SYMBOL(lprocfs_quota_wr_sync_blk);
400 int lprocfs_quota_rd_switch_qs(char *page, char **start, off_t off,
401 int count, int *eof, void *data)
403 struct obd_device *obd = (struct obd_device *)data;
404 LASSERT(obd != NULL);
406 return snprintf(page, count, "changing qunit size is %s\n",
407 obd->u.obt.obt_qctxt.lqc_switch_qs ?
408 "enabled" : "disabled");
410 EXPORT_SYMBOL(lprocfs_quota_rd_switch_qs);
412 int lprocfs_quota_wr_switch_qs(struct file *file, const char *buffer,
413 unsigned long count, void *data)
415 struct obd_device *obd = (struct obd_device *)data;
417 LASSERT(obd != NULL);
419 rc = lprocfs_write_helper(buffer, count, &val);
424 obd->u.obt.obt_qctxt.lqc_switch_qs = 1;
426 obd->u.obt.obt_qctxt.lqc_switch_qs = 0;
430 EXPORT_SYMBOL(lprocfs_quota_wr_switch_qs);
432 int lprocfs_quota_rd_boundary_factor(char *page, char **start, off_t off,
433 int count, int *eof, void *data)
435 struct obd_device *obd = (struct obd_device *)data;
436 LASSERT(obd != NULL);
439 return snprintf(page, count, "%lu\n",
440 obd->u.obt.obt_qctxt.lqc_cqs_boundary_factor);
442 EXPORT_SYMBOL(lprocfs_quota_rd_boundary_factor);
444 int lprocfs_quota_wr_boundary_factor(struct file *file, const char *buffer,
445 unsigned long count, void *data)
447 struct obd_device *obd = (struct obd_device *)data;
449 LASSERT(obd != NULL);
451 rc = lprocfs_write_helper(buffer, count, &val);
458 obd->u.obt.obt_qctxt.lqc_cqs_boundary_factor = val;
461 EXPORT_SYMBOL(lprocfs_quota_wr_boundary_factor);
463 int lprocfs_quota_rd_least_bunit(char *page, char **start, off_t off,
464 int count, int *eof, void *data)
466 struct obd_device *obd = (struct obd_device *)data;
467 LASSERT(obd != NULL);
470 return snprintf(page, count, "%lu\n",
471 obd->u.obt.obt_qctxt.lqc_cqs_least_bunit);
473 EXPORT_SYMBOL(lprocfs_quota_rd_least_bunit);
475 int lprocfs_quota_wr_least_bunit(struct file *file, const char *buffer,
476 unsigned long count, void *data)
478 struct obd_device *obd = (struct obd_device *)data;
480 LASSERT(obd != NULL);
482 rc = lprocfs_write_helper(buffer, count, &val);
486 if (val < PTLRPC_MAX_BRW_SIZE ||
487 val >= obd->u.obt.obt_qctxt.lqc_bunit_sz)
490 obd->u.obt.obt_qctxt.lqc_cqs_least_bunit = val;
493 EXPORT_SYMBOL(lprocfs_quota_wr_least_bunit);
495 int lprocfs_quota_rd_least_iunit(char *page, char **start, off_t off,
496 int count, int *eof, void *data)
498 struct obd_device *obd = (struct obd_device *)data;
499 LASSERT(obd != NULL);
502 return snprintf(page, count, "%lu\n",
503 obd->u.obt.obt_qctxt.lqc_cqs_least_iunit);
505 EXPORT_SYMBOL(lprocfs_quota_rd_least_iunit);
507 int lprocfs_quota_wr_least_iunit(struct file *file, const char *buffer,
508 unsigned long count, void *data)
510 struct obd_device *obd = (struct obd_device *)data;
512 LASSERT(obd != NULL);
514 rc = lprocfs_write_helper(buffer, count, &val);
518 if (val < 1 || val >= obd->u.obt.obt_qctxt.lqc_iunit_sz)
521 obd->u.obt.obt_qctxt.lqc_cqs_least_iunit = val;
524 EXPORT_SYMBOL(lprocfs_quota_wr_least_iunit);
526 int lprocfs_quota_rd_qs_factor(char *page, char **start, off_t off,
527 int count, int *eof, void *data)
529 struct obd_device *obd = (struct obd_device *)data;
530 LASSERT(obd != NULL);
533 return snprintf(page, count, "%lu\n",
534 obd->u.obt.obt_qctxt.lqc_cqs_qs_factor);
536 EXPORT_SYMBOL(lprocfs_quota_rd_qs_factor);
538 int lprocfs_quota_wr_qs_factor(struct file *file, const char *buffer,
539 unsigned long count, void *data)
541 struct obd_device *obd = (struct obd_device *)data;
543 LASSERT(obd != NULL);
545 rc = lprocfs_write_helper(buffer, count, &val);
552 obd->u.obt.obt_qctxt.lqc_cqs_qs_factor = val;
555 EXPORT_SYMBOL(lprocfs_quota_wr_qs_factor);
557 struct lprocfs_vars lprocfs_quota_common_vars[] = {
558 { "quota_bunit_sz", lprocfs_quota_rd_bunit,
559 lprocfs_quota_wr_bunit, 0},
560 { "quota_btune_sz", lprocfs_quota_rd_btune,
561 lprocfs_quota_wr_btune, 0},
562 { "quota_iunit_sz", lprocfs_quota_rd_iunit,
563 lprocfs_quota_wr_iunit, 0},
564 { "quota_itune_sz", lprocfs_quota_rd_itune,
565 lprocfs_quota_wr_itune, 0},
566 { "quota_type", lprocfs_quota_rd_type,
567 lprocfs_quota_wr_type, 0},
568 { "quota_switch_seconds", lprocfs_quota_rd_switch_seconds,
569 lprocfs_quota_wr_switch_seconds, 0 },
570 { "quota_sync_blk", lprocfs_quota_rd_sync_blk,
571 lprocfs_quota_wr_sync_blk, 0},
575 struct lprocfs_vars lprocfs_quota_master_vars[] = {
576 { "quota_switch_qs", lprocfs_quota_rd_switch_qs,
577 lprocfs_quota_wr_switch_qs, 0 },
578 { "quota_boundary_factor", lprocfs_quota_rd_boundary_factor,
579 lprocfs_quota_wr_boundary_factor, 0 },
580 { "quota_least_bunit", lprocfs_quota_rd_least_bunit,
581 lprocfs_quota_wr_least_bunit, 0 },
582 { "quota_least_iunit", lprocfs_quota_rd_least_iunit,
583 lprocfs_quota_wr_least_iunit, 0 },
584 { "quota_qs_factor", lprocfs_quota_rd_qs_factor,
585 lprocfs_quota_wr_qs_factor, 0 },
589 int lquota_proc_setup(struct obd_device *obd, int is_master)
591 struct lustre_quota_ctxt *qctxt = &obd->u.obt.obt_qctxt;
595 LASSERT(lquota_type_proc_dir && obd);
596 qctxt->lqc_proc_dir = lprocfs_register(obd->obd_name,
597 lquota_type_proc_dir,
598 lprocfs_quota_common_vars, obd);
599 if (IS_ERR(qctxt->lqc_proc_dir)) {
600 rc = PTR_ERR(qctxt->lqc_proc_dir);
601 CERROR("error %d setting up lprocfs for %s\n", rc,
603 qctxt->lqc_proc_dir = NULL;
608 rc = lprocfs_add_vars(qctxt->lqc_proc_dir,
609 lprocfs_quota_master_vars, obd);
611 CERROR("error %d setting up lprocfs for %s"
612 "(quota master)\n", rc, obd->obd_name);
613 GOTO(out_free_proc, rc);
617 qctxt->lqc_stats = lprocfs_alloc_stats(LQUOTA_LAST_STAT -
618 LQUOTA_FIRST_STAT, 0);
619 if (!qctxt->lqc_stats)
620 GOTO(out_free_proc, rc = -ENOMEM);
622 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_SYNC_ACQ,
623 LPROCFS_CNTR_AVGMINMAX, "sync_acq_req", "us");
624 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_SYNC_REL,
625 LPROCFS_CNTR_AVGMINMAX, "sync_rel_req", "us");
626 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_ASYNC_ACQ,
627 LPROCFS_CNTR_AVGMINMAX, "async_acq_req", "us");
628 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_ASYNC_REL,
629 LPROCFS_CNTR_AVGMINMAX, "async_rel_req", "us");
631 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_FOR_CHK_BLK,
632 LPROCFS_CNTR_AVGMINMAX,
633 "wait_for_blk_quota(lquota_chkquota)", "us");
634 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_FOR_CHK_INO,
635 LPROCFS_CNTR_AVGMINMAX,
636 "wait_for_ino_quota(lquota_chkquota)", "us");
637 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_FOR_COMMIT_BLK,
638 LPROCFS_CNTR_AVGMINMAX,
639 "wait_for_blk_quota(lquota_pending_commit)",
641 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_FOR_COMMIT_INO,
642 LPROCFS_CNTR_AVGMINMAX,
643 "wait_for_ino_quota(lquota_pending_commit)",
646 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_PENDING_BLK_QUOTA,
647 LPROCFS_CNTR_AVGMINMAX,
648 "wait_for_pending_blk_quota_req"
649 "(qctxt_wait_pending_dqacq)", "us");
650 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_PENDING_INO_QUOTA,
651 LPROCFS_CNTR_AVGMINMAX,
652 "wait_for_pending_ino_quota_req"
653 "(qctxt_wait_pending_dqacq)", "us");
654 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_NOWAIT_PENDING_BLK_QUOTA,
655 LPROCFS_CNTR_AVGMINMAX,
656 "nowait_for_pending_blk_quota_req"
657 "(qctxt_wait_pending_dqacq)", "us");
658 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_NOWAIT_PENDING_INO_QUOTA,
659 LPROCFS_CNTR_AVGMINMAX,
660 "nowait_for_pending_ino_quota_req"
661 "(qctxt_wait_pending_dqacq)", "us");
663 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_QUOTA_CTL,
664 LPROCFS_CNTR_AVGMINMAX, "quota_ctl", "us");
665 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_ADJUST_QUNIT,
666 LPROCFS_CNTR_AVGMINMAX, "adjust_qunit", "us");
668 lprocfs_register_stats(qctxt->lqc_proc_dir, "stats", qctxt->lqc_stats);
673 lprocfs_remove(&qctxt->lqc_proc_dir);
678 int lquota_proc_cleanup(struct lustre_quota_ctxt *qctxt)
680 if (!qctxt || !qctxt->lqc_proc_dir)
683 if (qctxt->lqc_stats != NULL)
684 lprocfs_free_stats(&qctxt->lqc_stats);
686 lprocfs_remove(&qctxt->lqc_proc_dir);