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 (c) 2008, 2010, Oracle and/or its affiliates. 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] = "";
185 LASSERT(obd != NULL);
187 /* Collect the needed information */
188 oq_type = obd->u.obt.obt_qctxt.lqc_flags;
190 /* Transform the collected data into a user-readable string */
191 if (oq_type & LQC_USRQUOTA_FLAG)
193 if (oq_type & LQC_GRPQUOTA_FLAG)
198 return snprintf(page, count, "%s\n", stype);
200 EXPORT_SYMBOL(lprocfs_quota_rd_type);
203 * generic_quota_on is very lazy and tolerant about current quota settings
204 * @global means to turn on quotas on each OST additionally to local quotas;
205 * should not be called from filter_quota_ctl on MDS nodes (as it starts
206 * admin quotas on MDS nodes).
208 int generic_quota_on(struct obd_device *obd, struct obd_quotactl *oqctl, int global)
210 struct obd_device_target *obt = &obd->u.obt;
211 struct lvfs_run_ctxt saved;
212 int id, is_master, rc = 0, local; /* means we need a local quotaon */
214 cfs_down(&obt->obt_quotachecking);
215 push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
216 id = UGQUOTA2LQC(oqctl->qc_type);
217 local = (obt->obt_qctxt.lqc_flags & id) != id;
219 oqctl->qc_cmd = Q_QUOTAON;
220 oqctl->qc_id = obt->obt_qfmt;
222 is_master = !strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME);
224 cfs_down_write(&obd->u.mds.mds_qonoff_sem);
226 /* turn on cluster wide quota */
227 rc = mds_admin_quota_on(obd, oqctl);
228 if (rc && rc != -ENOENT)
229 CERROR("%s: %s admin quotaon failed. rc=%d\n",
230 obd->obd_name, global ? "global":"local",
237 rc = fsfilt_quotactl(obd, obt->obt_sb, oqctl);
240 CERROR("%s: %s quotaon failed with"
241 " rc=%d\n", obd->obd_name,
242 global ? "global" : "local", rc);
244 obt->obt_qctxt.lqc_flags |= UGQUOTA2LQC(oqctl->qc_type);
249 if (rc == 0 && global && is_master)
250 rc = obd_quotactl(obd->u.mds.mds_lov_exp, oqctl);
254 cfs_up_write(&obd->u.mds.mds_qonoff_sem);
256 pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
257 cfs_up(&obt->obt_quotachecking);
259 CDEBUG(D_QUOTA, "%s: quotaon type:master:global:local:flags:rc "
260 "%u:%d:%d:%d:%lu:%d\n",
261 obd->obd_name, oqctl->qc_type, is_master, global, local,
262 obt->obt_qctxt.lqc_flags, rc);
267 static int auto_quota_on(struct obd_device *obd, int type)
269 struct obd_quotactl *oqctl;
273 LASSERT(type == USRQUOTA || type == GRPQUOTA || type == UGQUOTA);
275 OBD_ALLOC_PTR(oqctl);
279 oqctl->qc_type = type;
281 rc = generic_quota_on(obd, oqctl, 0);
287 int lprocfs_quota_wr_type(struct file *file, const char *buffer,
288 unsigned long count, void *data)
290 struct obd_device *obd = (struct obd_device *)data;
293 char stype[MAX_STYPE_SIZE + 1] = "";
295 LASSERT(obd != NULL);
297 if (count > MAX_STYPE_SIZE)
300 if (cfs_copy_from_user(stype, buffer, count))
303 for (i = 0 ; i < count ; i++) {
313 CWARN("quota_type options 1 and 2 are obsolete, "
314 "they will be ignored\n");
316 case '3' : /* the only valid version spec, do nothing */
317 default : /* just skip stray symbols like \n */
323 int rc = auto_quota_on(obd, type - 1);
325 if (rc && rc != -EALREADY && rc != -ENOENT)
331 EXPORT_SYMBOL(lprocfs_quota_wr_type);
333 int lprocfs_quota_rd_switch_seconds(char *page, char **start, off_t off,
334 int count, int *eof, void *data)
336 struct obd_device *obd = (struct obd_device *)data;
337 LASSERT(obd != NULL);
339 return snprintf(page, count, "%d\n",
340 obd->u.obt.obt_qctxt.lqc_switch_seconds);
342 EXPORT_SYMBOL(lprocfs_quota_rd_switch_seconds);
344 int lprocfs_quota_wr_switch_seconds(struct file *file, const char *buffer,
345 unsigned long count, void *data)
347 struct obd_device *obd = (struct obd_device *)data;
349 LASSERT(obd != NULL);
351 rc = lprocfs_write_helper(buffer, count, &val);
358 obd->u.obt.obt_qctxt.lqc_switch_seconds = val;
361 EXPORT_SYMBOL(lprocfs_quota_wr_switch_seconds);
363 int lprocfs_quota_rd_sync_blk(char *page, char **start, off_t off,
364 int count, int *eof, void *data)
366 struct obd_device *obd = (struct obd_device *)data;
367 LASSERT(obd != NULL);
369 return snprintf(page, count, "%d\n",
370 obd->u.obt.obt_qctxt.lqc_sync_blk);
372 EXPORT_SYMBOL(lprocfs_quota_rd_sync_blk);
374 int lprocfs_quota_wr_sync_blk(struct file *file, const char *buffer,
375 unsigned long count, void *data)
377 struct obd_device *obd = (struct obd_device *)data;
379 LASSERT(obd != NULL);
381 rc = lprocfs_write_helper(buffer, count, &val);
388 obd->u.obt.obt_qctxt.lqc_sync_blk = val;
391 EXPORT_SYMBOL(lprocfs_quota_wr_sync_blk);
393 int lprocfs_quota_rd_switch_qs(char *page, char **start, off_t off,
394 int count, int *eof, void *data)
396 struct obd_device *obd = (struct obd_device *)data;
397 LASSERT(obd != NULL);
399 return snprintf(page, count, "changing qunit size is %s\n",
400 obd->u.obt.obt_qctxt.lqc_switch_qs ?
401 "enabled" : "disabled");
403 EXPORT_SYMBOL(lprocfs_quota_rd_switch_qs);
405 int lprocfs_quota_wr_switch_qs(struct file *file, const char *buffer,
406 unsigned long count, void *data)
408 struct obd_device *obd = (struct obd_device *)data;
410 LASSERT(obd != NULL);
412 rc = lprocfs_write_helper(buffer, count, &val);
417 obd->u.obt.obt_qctxt.lqc_switch_qs = 1;
419 obd->u.obt.obt_qctxt.lqc_switch_qs = 0;
423 EXPORT_SYMBOL(lprocfs_quota_wr_switch_qs);
425 int lprocfs_quota_rd_boundary_factor(char *page, char **start, off_t off,
426 int count, int *eof, void *data)
428 struct obd_device *obd = (struct obd_device *)data;
429 LASSERT(obd != NULL);
432 return snprintf(page, count, "%lu\n",
433 obd->u.obt.obt_qctxt.lqc_cqs_boundary_factor);
435 EXPORT_SYMBOL(lprocfs_quota_rd_boundary_factor);
437 int lprocfs_quota_wr_boundary_factor(struct file *file, const char *buffer,
438 unsigned long count, void *data)
440 struct obd_device *obd = (struct obd_device *)data;
442 LASSERT(obd != NULL);
444 rc = lprocfs_write_helper(buffer, count, &val);
451 obd->u.obt.obt_qctxt.lqc_cqs_boundary_factor = val;
454 EXPORT_SYMBOL(lprocfs_quota_wr_boundary_factor);
456 int lprocfs_quota_rd_least_bunit(char *page, char **start, off_t off,
457 int count, int *eof, void *data)
459 struct obd_device *obd = (struct obd_device *)data;
460 LASSERT(obd != NULL);
463 return snprintf(page, count, "%lu\n",
464 obd->u.obt.obt_qctxt.lqc_cqs_least_bunit);
466 EXPORT_SYMBOL(lprocfs_quota_rd_least_bunit);
468 int lprocfs_quota_wr_least_bunit(struct file *file, const char *buffer,
469 unsigned long count, void *data)
471 struct obd_device *obd = (struct obd_device *)data;
473 LASSERT(obd != NULL);
475 rc = lprocfs_write_helper(buffer, count, &val);
479 if (val < PTLRPC_MAX_BRW_SIZE ||
480 val >= obd->u.obt.obt_qctxt.lqc_bunit_sz)
483 obd->u.obt.obt_qctxt.lqc_cqs_least_bunit = val;
486 EXPORT_SYMBOL(lprocfs_quota_wr_least_bunit);
488 int lprocfs_quota_rd_least_iunit(char *page, char **start, off_t off,
489 int count, int *eof, void *data)
491 struct obd_device *obd = (struct obd_device *)data;
492 LASSERT(obd != NULL);
495 return snprintf(page, count, "%lu\n",
496 obd->u.obt.obt_qctxt.lqc_cqs_least_iunit);
498 EXPORT_SYMBOL(lprocfs_quota_rd_least_iunit);
500 int lprocfs_quota_wr_least_iunit(struct file *file, const char *buffer,
501 unsigned long count, void *data)
503 struct obd_device *obd = (struct obd_device *)data;
505 LASSERT(obd != NULL);
507 rc = lprocfs_write_helper(buffer, count, &val);
511 if (val < 1 || val >= obd->u.obt.obt_qctxt.lqc_iunit_sz)
514 obd->u.obt.obt_qctxt.lqc_cqs_least_iunit = val;
517 EXPORT_SYMBOL(lprocfs_quota_wr_least_iunit);
519 int lprocfs_quota_rd_qs_factor(char *page, char **start, off_t off,
520 int count, int *eof, void *data)
522 struct obd_device *obd = (struct obd_device *)data;
523 LASSERT(obd != NULL);
526 return snprintf(page, count, "%lu\n",
527 obd->u.obt.obt_qctxt.lqc_cqs_qs_factor);
529 EXPORT_SYMBOL(lprocfs_quota_rd_qs_factor);
531 int lprocfs_quota_wr_qs_factor(struct file *file, const char *buffer,
532 unsigned long count, void *data)
534 struct obd_device *obd = (struct obd_device *)data;
536 LASSERT(obd != NULL);
538 rc = lprocfs_write_helper(buffer, count, &val);
545 obd->u.obt.obt_qctxt.lqc_cqs_qs_factor = val;
548 EXPORT_SYMBOL(lprocfs_quota_wr_qs_factor);
550 struct lprocfs_vars lprocfs_quota_common_vars[] = {
551 { "quota_bunit_sz", lprocfs_quota_rd_bunit,
552 lprocfs_quota_wr_bunit, 0},
553 { "quota_btune_sz", lprocfs_quota_rd_btune,
554 lprocfs_quota_wr_btune, 0},
555 { "quota_iunit_sz", lprocfs_quota_rd_iunit,
556 lprocfs_quota_wr_iunit, 0},
557 { "quota_itune_sz", lprocfs_quota_rd_itune,
558 lprocfs_quota_wr_itune, 0},
559 { "quota_type", lprocfs_quota_rd_type,
560 lprocfs_quota_wr_type, 0},
561 { "quota_switch_seconds", lprocfs_quota_rd_switch_seconds,
562 lprocfs_quota_wr_switch_seconds, 0 },
563 { "quota_sync_blk", lprocfs_quota_rd_sync_blk,
564 lprocfs_quota_wr_sync_blk, 0},
568 struct lprocfs_vars lprocfs_quota_master_vars[] = {
569 { "quota_switch_qs", lprocfs_quota_rd_switch_qs,
570 lprocfs_quota_wr_switch_qs, 0 },
571 { "quota_boundary_factor", lprocfs_quota_rd_boundary_factor,
572 lprocfs_quota_wr_boundary_factor, 0 },
573 { "quota_least_bunit", lprocfs_quota_rd_least_bunit,
574 lprocfs_quota_wr_least_bunit, 0 },
575 { "quota_least_iunit", lprocfs_quota_rd_least_iunit,
576 lprocfs_quota_wr_least_iunit, 0 },
577 { "quota_qs_factor", lprocfs_quota_rd_qs_factor,
578 lprocfs_quota_wr_qs_factor, 0 },
582 int lquota_proc_setup(struct obd_device *obd, int is_master)
584 struct lustre_quota_ctxt *qctxt = &obd->u.obt.obt_qctxt;
588 LASSERT(lquota_type_proc_dir && obd);
589 qctxt->lqc_proc_dir = lprocfs_register(obd->obd_name,
590 lquota_type_proc_dir,
591 lprocfs_quota_common_vars, obd);
592 if (IS_ERR(qctxt->lqc_proc_dir)) {
593 rc = PTR_ERR(qctxt->lqc_proc_dir);
594 CERROR("%s: error %d setting up lprocfs\n",
596 qctxt->lqc_proc_dir = NULL;
601 rc = lprocfs_add_vars(qctxt->lqc_proc_dir,
602 lprocfs_quota_master_vars, obd);
604 CERROR("%s: error %d setting up lprocfs for "
605 "quota master\n", obd->obd_name, rc);
606 GOTO(out_free_proc, rc);
610 qctxt->lqc_stats = lprocfs_alloc_stats(LQUOTA_LAST_STAT -
611 LQUOTA_FIRST_STAT, 0);
612 if (!qctxt->lqc_stats)
613 GOTO(out_free_proc, rc = -ENOMEM);
615 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_SYNC_ACQ,
616 LPROCFS_CNTR_AVGMINMAX, "sync_acq_req", "us");
617 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_SYNC_REL,
618 LPROCFS_CNTR_AVGMINMAX, "sync_rel_req", "us");
619 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_ASYNC_ACQ,
620 LPROCFS_CNTR_AVGMINMAX, "async_acq_req", "us");
621 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_ASYNC_REL,
622 LPROCFS_CNTR_AVGMINMAX, "async_rel_req", "us");
624 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_FOR_CHK_BLK,
625 LPROCFS_CNTR_AVGMINMAX,
626 "wait_for_blk_quota(lquota_chkquota)", "us");
627 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_FOR_CHK_INO,
628 LPROCFS_CNTR_AVGMINMAX,
629 "wait_for_ino_quota(lquota_chkquota)", "us");
630 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_FOR_COMMIT_BLK,
631 LPROCFS_CNTR_AVGMINMAX,
632 "wait_for_blk_quota(lquota_pending_commit)",
634 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_FOR_COMMIT_INO,
635 LPROCFS_CNTR_AVGMINMAX,
636 "wait_for_ino_quota(lquota_pending_commit)",
639 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_PENDING_BLK_QUOTA,
640 LPROCFS_CNTR_AVGMINMAX,
641 "wait_for_pending_blk_quota_req"
642 "(qctxt_wait_pending_dqacq)", "us");
643 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_PENDING_INO_QUOTA,
644 LPROCFS_CNTR_AVGMINMAX,
645 "wait_for_pending_ino_quota_req"
646 "(qctxt_wait_pending_dqacq)", "us");
647 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_NOWAIT_PENDING_BLK_QUOTA,
648 LPROCFS_CNTR_AVGMINMAX,
649 "nowait_for_pending_blk_quota_req"
650 "(qctxt_wait_pending_dqacq)", "us");
651 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_NOWAIT_PENDING_INO_QUOTA,
652 LPROCFS_CNTR_AVGMINMAX,
653 "nowait_for_pending_ino_quota_req"
654 "(qctxt_wait_pending_dqacq)", "us");
656 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_QUOTA_CTL,
657 LPROCFS_CNTR_AVGMINMAX, "quota_ctl", "us");
658 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_ADJUST_QUNIT,
659 LPROCFS_CNTR_AVGMINMAX, "adjust_qunit", "us");
661 lprocfs_register_stats(qctxt->lqc_proc_dir, "stats", qctxt->lqc_stats);
666 lprocfs_remove(&qctxt->lqc_proc_dir);
671 int lquota_proc_cleanup(struct lustre_quota_ctxt *qctxt)
673 if (!qctxt || !qctxt->lqc_proc_dir)
676 if (qctxt->lqc_stats != NULL)
677 lprocfs_free_stats(&qctxt->lqc_stats);
679 lprocfs_remove(&qctxt->lqc_proc_dir);