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, see
18 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21 * CA 95054 USA or visit www.sun.com if you need additional information or
27 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28 * Use is subject to license terms.
30 * Copyright (c) 2011, Whamcloud, Inc.
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"
48 int lprocfs_quota_rd_bunit(char *page, char **start, off_t off, int count,
51 struct obd_device *obd = (struct obd_device *)data;
54 return snprintf(page, count, "%lu\n",
55 obd->u.obt.obt_qctxt.lqc_bunit_sz);
57 EXPORT_SYMBOL(lprocfs_quota_rd_bunit);
59 int lprocfs_quota_wr_bunit(struct file *file, const char *buffer,
60 unsigned long count, void *data)
62 struct obd_device *obd = (struct obd_device *)data;
66 rc = lprocfs_write_helper(buffer, count, &val);
70 if (val % QUOTABLOCK_SIZE ||
71 val <= obd->u.obt.obt_qctxt.lqc_btune_sz)
74 obd->u.obt.obt_qctxt.lqc_bunit_sz = val;
77 EXPORT_SYMBOL(lprocfs_quota_wr_bunit);
79 int lprocfs_quota_rd_btune(char *page, char **start, off_t off, int count,
82 struct obd_device *obd = (struct obd_device *)data;
85 return snprintf(page, count, "%lu\n",
86 obd->u.obt.obt_qctxt.lqc_btune_sz);
88 EXPORT_SYMBOL(lprocfs_quota_rd_btune);
90 int lprocfs_quota_wr_btune(struct file *file, const char *buffer,
91 unsigned long count, void *data)
93 struct obd_device *obd = (struct obd_device *)data;
97 rc = lprocfs_write_helper(buffer, count, &val);
101 if (val <= QUOTABLOCK_SIZE * MIN_QLIMIT || val % QUOTABLOCK_SIZE ||
102 val >= obd->u.obt.obt_qctxt.lqc_bunit_sz)
105 obd->u.obt.obt_qctxt.lqc_btune_sz = val;
108 EXPORT_SYMBOL(lprocfs_quota_wr_btune);
110 int lprocfs_quota_rd_iunit(char *page, char **start, off_t off, int count,
111 int *eof, void *data)
113 struct obd_device *obd = (struct obd_device *)data;
114 LASSERT(obd != NULL);
116 return snprintf(page, count, "%lu\n",
117 obd->u.obt.obt_qctxt.lqc_iunit_sz);
119 EXPORT_SYMBOL(lprocfs_quota_rd_iunit);
121 int lprocfs_quota_wr_iunit(struct file *file, const char *buffer,
122 unsigned long count, void *data)
124 struct obd_device *obd = (struct obd_device *)data;
126 LASSERT(obd != NULL);
128 rc = lprocfs_write_helper(buffer, count, &val);
132 if (val <= obd->u.obt.obt_qctxt.lqc_itune_sz)
135 obd->u.obt.obt_qctxt.lqc_iunit_sz = val;
138 EXPORT_SYMBOL(lprocfs_quota_wr_iunit);
140 int lprocfs_quota_rd_itune(char *page, char **start, off_t off, int count,
141 int *eof, void *data)
143 struct obd_device *obd = (struct obd_device *)data;
144 LASSERT(obd != NULL);
146 return snprintf(page, count, "%lu\n",
147 obd->u.obt.obt_qctxt.lqc_itune_sz);
149 EXPORT_SYMBOL(lprocfs_quota_rd_itune);
151 int lprocfs_quota_wr_itune(struct file *file, const char *buffer,
152 unsigned long count, void *data)
154 struct obd_device *obd = (struct obd_device *)data;
156 LASSERT(obd != NULL);
158 rc = lprocfs_write_helper(buffer, count, &val);
162 if (val <= MIN_QLIMIT ||
163 val >= obd->u.obt.obt_qctxt.lqc_iunit_sz)
166 obd->u.obt.obt_qctxt.lqc_itune_sz = val;
169 EXPORT_SYMBOL(lprocfs_quota_wr_itune);
172 #define GROUP_QUOTA 2
174 #define MAX_STYPE_SIZE 5
176 int lprocfs_quota_rd_type(char *page, char **start, off_t off, int count,
177 int *eof, void *data)
179 struct obd_device *obd = (struct obd_device *)data;
180 char stype[MAX_STYPE_SIZE + 1] = "";
183 LASSERT(obd != NULL);
185 /* Collect the needed information */
186 oq_type = obd->u.obt.obt_qctxt.lqc_flags;
188 /* Transform the collected data into a user-readable string */
189 if (oq_type & LQC_USRQUOTA_FLAG)
191 if (oq_type & LQC_GRPQUOTA_FLAG)
196 return snprintf(page, count, "%s\n", stype);
198 EXPORT_SYMBOL(lprocfs_quota_rd_type);
201 * generic_quota_on is very lazy and tolerant about current quota settings
202 * @global means to turn on quotas on each OST additionally to local quotas;
203 * should not be called from filter_quota_ctl on MDS nodes (as it starts
204 * admin quotas on MDS nodes).
206 int generic_quota_on(struct obd_device *obd, struct obd_quotactl *oqctl, int global)
208 struct obd_device_target *obt = &obd->u.obt;
209 struct lvfs_run_ctxt saved;
210 int id, is_master, rc = 0, local; /* means we need a local quotaon */
212 cfs_down(&obt->obt_quotachecking);
213 push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
214 id = UGQUOTA2LQC(oqctl->qc_type);
215 local = (obt->obt_qctxt.lqc_flags & id) != id;
217 oqctl->qc_cmd = Q_QUOTAON;
218 oqctl->qc_id = obt->obt_qfmt;
220 is_master = !strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME);
222 cfs_down_write(&obd->u.mds.mds_qonoff_sem);
224 /* turn on cluster wide quota */
225 rc = mds_admin_quota_on(obd, oqctl);
226 if (rc && rc != -ENOENT)
227 CERROR("%s: %s admin quotaon failed. rc=%d\n",
228 obd->obd_name, global ? "global":"local",
235 rc = fsfilt_quotactl(obd, obt->obt_sb, oqctl);
238 CERROR("%s: %s quotaon failed with"
239 " rc=%d\n", obd->obd_name,
240 global ? "global" : "local", rc);
242 obt->obt_qctxt.lqc_flags |= UGQUOTA2LQC(oqctl->qc_type);
247 if (rc == 0 && global && is_master)
248 rc = obd_quotactl(obd->u.mds.mds_lov_exp, oqctl);
252 cfs_up_write(&obd->u.mds.mds_qonoff_sem);
254 pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
255 cfs_up(&obt->obt_quotachecking);
257 CDEBUG(D_QUOTA, "%s: quotaon type:master:global:local:flags:rc "
258 "%u:%d:%d:%d:%lu:%d\n",
259 obd->obd_name, oqctl->qc_type, is_master, global, local,
260 obt->obt_qctxt.lqc_flags, rc);
265 static int auto_quota_on(struct obd_device *obd, int type)
267 struct obd_quotactl *oqctl;
271 LASSERT(type == USRQUOTA || type == GRPQUOTA || type == UGQUOTA);
273 OBD_ALLOC_PTR(oqctl);
277 oqctl->qc_type = type;
279 rc = generic_quota_on(obd, oqctl, 0);
285 int lprocfs_quota_wr_type(struct file *file, const char *buffer,
286 unsigned long count, void *data)
288 struct obd_device *obd = (struct obd_device *)data;
291 char stype[MAX_STYPE_SIZE + 1] = "";
293 LASSERT(obd != NULL);
295 if (count > MAX_STYPE_SIZE)
298 if (cfs_copy_from_user(stype, buffer, count))
301 for (i = 0 ; i < count ; i++) {
311 CWARN("quota_type options 1 and 2 are obsolete, "
312 "they will be ignored\n");
314 case '3' : /* the only valid version spec, do nothing */
315 default : /* just skip stray symbols like \n */
321 int rc = auto_quota_on(obd, type - 1);
323 if (rc && rc != -EALREADY && rc != -ENOENT)
329 EXPORT_SYMBOL(lprocfs_quota_wr_type);
331 int lprocfs_quota_rd_switch_seconds(char *page, char **start, off_t off,
332 int count, int *eof, void *data)
334 struct obd_device *obd = (struct obd_device *)data;
335 LASSERT(obd != NULL);
337 return snprintf(page, count, "%d\n",
338 obd->u.obt.obt_qctxt.lqc_switch_seconds);
340 EXPORT_SYMBOL(lprocfs_quota_rd_switch_seconds);
342 int lprocfs_quota_wr_switch_seconds(struct file *file, const char *buffer,
343 unsigned long count, void *data)
345 struct obd_device *obd = (struct obd_device *)data;
347 LASSERT(obd != NULL);
349 rc = lprocfs_write_helper(buffer, count, &val);
356 obd->u.obt.obt_qctxt.lqc_switch_seconds = val;
359 EXPORT_SYMBOL(lprocfs_quota_wr_switch_seconds);
361 int lprocfs_quota_rd_sync_blk(char *page, char **start, off_t off,
362 int count, int *eof, void *data)
364 struct obd_device *obd = (struct obd_device *)data;
365 LASSERT(obd != NULL);
367 return snprintf(page, count, "%d\n",
368 obd->u.obt.obt_qctxt.lqc_sync_blk);
370 EXPORT_SYMBOL(lprocfs_quota_rd_sync_blk);
372 int lprocfs_quota_wr_sync_blk(struct file *file, const char *buffer,
373 unsigned long count, void *data)
375 struct obd_device *obd = (struct obd_device *)data;
377 LASSERT(obd != NULL);
379 rc = lprocfs_write_helper(buffer, count, &val);
386 obd->u.obt.obt_qctxt.lqc_sync_blk = val;
389 EXPORT_SYMBOL(lprocfs_quota_wr_sync_blk);
391 int lprocfs_quota_rd_switch_qs(char *page, char **start, off_t off,
392 int count, int *eof, void *data)
394 struct obd_device *obd = (struct obd_device *)data;
395 LASSERT(obd != NULL);
397 return snprintf(page, count, "changing qunit size is %s\n",
398 obd->u.obt.obt_qctxt.lqc_switch_qs ?
399 "enabled" : "disabled");
401 EXPORT_SYMBOL(lprocfs_quota_rd_switch_qs);
403 int lprocfs_quota_wr_switch_qs(struct file *file, const char *buffer,
404 unsigned long count, void *data)
406 struct obd_device *obd = (struct obd_device *)data;
408 LASSERT(obd != NULL);
410 rc = lprocfs_write_helper(buffer, count, &val);
415 obd->u.obt.obt_qctxt.lqc_switch_qs = 1;
417 obd->u.obt.obt_qctxt.lqc_switch_qs = 0;
421 EXPORT_SYMBOL(lprocfs_quota_wr_switch_qs);
423 int lprocfs_quota_rd_boundary_factor(char *page, char **start, off_t off,
424 int count, int *eof, void *data)
426 struct obd_device *obd = (struct obd_device *)data;
427 LASSERT(obd != NULL);
430 return snprintf(page, count, "%lu\n",
431 obd->u.obt.obt_qctxt.lqc_cqs_boundary_factor);
433 EXPORT_SYMBOL(lprocfs_quota_rd_boundary_factor);
435 int lprocfs_quota_wr_boundary_factor(struct file *file, const char *buffer,
436 unsigned long count, void *data)
438 struct obd_device *obd = (struct obd_device *)data;
440 LASSERT(obd != NULL);
442 rc = lprocfs_write_helper(buffer, count, &val);
449 obd->u.obt.obt_qctxt.lqc_cqs_boundary_factor = val;
452 EXPORT_SYMBOL(lprocfs_quota_wr_boundary_factor);
454 int lprocfs_quota_rd_least_bunit(char *page, char **start, off_t off,
455 int count, int *eof, void *data)
457 struct obd_device *obd = (struct obd_device *)data;
458 LASSERT(obd != NULL);
461 return snprintf(page, count, "%lu\n",
462 obd->u.obt.obt_qctxt.lqc_cqs_least_bunit);
464 EXPORT_SYMBOL(lprocfs_quota_rd_least_bunit);
466 int lprocfs_quota_wr_least_bunit(struct file *file, const char *buffer,
467 unsigned long count, void *data)
469 struct obd_device *obd = (struct obd_device *)data;
471 LASSERT(obd != NULL);
473 rc = lprocfs_write_helper(buffer, count, &val);
477 if (val < PTLRPC_MAX_BRW_SIZE ||
478 val >= obd->u.obt.obt_qctxt.lqc_bunit_sz)
481 obd->u.obt.obt_qctxt.lqc_cqs_least_bunit = val;
484 EXPORT_SYMBOL(lprocfs_quota_wr_least_bunit);
486 int lprocfs_quota_rd_least_iunit(char *page, char **start, off_t off,
487 int count, int *eof, void *data)
489 struct obd_device *obd = (struct obd_device *)data;
490 LASSERT(obd != NULL);
493 return snprintf(page, count, "%lu\n",
494 obd->u.obt.obt_qctxt.lqc_cqs_least_iunit);
496 EXPORT_SYMBOL(lprocfs_quota_rd_least_iunit);
498 int lprocfs_quota_wr_least_iunit(struct file *file, const char *buffer,
499 unsigned long count, void *data)
501 struct obd_device *obd = (struct obd_device *)data;
503 LASSERT(obd != NULL);
505 rc = lprocfs_write_helper(buffer, count, &val);
509 if (val < 1 || val >= obd->u.obt.obt_qctxt.lqc_iunit_sz)
512 obd->u.obt.obt_qctxt.lqc_cqs_least_iunit = val;
515 EXPORT_SYMBOL(lprocfs_quota_wr_least_iunit);
517 int lprocfs_quota_rd_qs_factor(char *page, char **start, off_t off,
518 int count, int *eof, void *data)
520 struct obd_device *obd = (struct obd_device *)data;
521 LASSERT(obd != NULL);
524 return snprintf(page, count, "%lu\n",
525 obd->u.obt.obt_qctxt.lqc_cqs_qs_factor);
527 EXPORT_SYMBOL(lprocfs_quota_rd_qs_factor);
529 int lprocfs_quota_wr_qs_factor(struct file *file, const char *buffer,
530 unsigned long count, void *data)
532 struct obd_device *obd = (struct obd_device *)data;
534 LASSERT(obd != NULL);
536 rc = lprocfs_write_helper(buffer, count, &val);
543 obd->u.obt.obt_qctxt.lqc_cqs_qs_factor = val;
546 EXPORT_SYMBOL(lprocfs_quota_wr_qs_factor);
548 struct lprocfs_vars lprocfs_quota_common_vars[] = {
549 { "quota_bunit_sz", lprocfs_quota_rd_bunit,
550 lprocfs_quota_wr_bunit, 0},
551 { "quota_btune_sz", lprocfs_quota_rd_btune,
552 lprocfs_quota_wr_btune, 0},
553 { "quota_iunit_sz", lprocfs_quota_rd_iunit,
554 lprocfs_quota_wr_iunit, 0},
555 { "quota_itune_sz", lprocfs_quota_rd_itune,
556 lprocfs_quota_wr_itune, 0},
557 { "quota_type", lprocfs_quota_rd_type,
558 lprocfs_quota_wr_type, 0},
559 { "quota_switch_seconds", lprocfs_quota_rd_switch_seconds,
560 lprocfs_quota_wr_switch_seconds, 0 },
561 { "quota_sync_blk", lprocfs_quota_rd_sync_blk,
562 lprocfs_quota_wr_sync_blk, 0},
566 struct lprocfs_vars lprocfs_quota_master_vars[] = {
567 { "quota_switch_qs", lprocfs_quota_rd_switch_qs,
568 lprocfs_quota_wr_switch_qs, 0 },
569 { "quota_boundary_factor", lprocfs_quota_rd_boundary_factor,
570 lprocfs_quota_wr_boundary_factor, 0 },
571 { "quota_least_bunit", lprocfs_quota_rd_least_bunit,
572 lprocfs_quota_wr_least_bunit, 0 },
573 { "quota_least_iunit", lprocfs_quota_rd_least_iunit,
574 lprocfs_quota_wr_least_iunit, 0 },
575 { "quota_qs_factor", lprocfs_quota_rd_qs_factor,
576 lprocfs_quota_wr_qs_factor, 0 },
580 int lquota_proc_setup(struct obd_device *obd, int is_master)
582 struct lustre_quota_ctxt *qctxt = &obd->u.obt.obt_qctxt;
586 LASSERT(lquota_type_proc_dir && obd);
587 qctxt->lqc_proc_dir = lprocfs_register(obd->obd_name,
588 lquota_type_proc_dir,
589 lprocfs_quota_common_vars, obd);
590 if (IS_ERR(qctxt->lqc_proc_dir)) {
591 rc = PTR_ERR(qctxt->lqc_proc_dir);
592 CERROR("%s: error %d setting up lprocfs\n",
594 qctxt->lqc_proc_dir = NULL;
599 rc = lprocfs_add_vars(qctxt->lqc_proc_dir,
600 lprocfs_quota_master_vars, obd);
602 CERROR("%s: error %d setting up lprocfs for "
603 "quota master\n", obd->obd_name, rc);
604 GOTO(out_free_proc, rc);
608 qctxt->lqc_stats = lprocfs_alloc_stats(LQUOTA_LAST_STAT -
609 LQUOTA_FIRST_STAT, 0);
610 if (!qctxt->lqc_stats)
611 GOTO(out_free_proc, rc = -ENOMEM);
613 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_SYNC_ACQ,
614 LPROCFS_CNTR_AVGMINMAX, "sync_acq_req", "us");
615 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_SYNC_REL,
616 LPROCFS_CNTR_AVGMINMAX, "sync_rel_req", "us");
617 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_ASYNC_ACQ,
618 LPROCFS_CNTR_AVGMINMAX, "async_acq_req", "us");
619 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_ASYNC_REL,
620 LPROCFS_CNTR_AVGMINMAX, "async_rel_req", "us");
622 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_FOR_CHK_BLK,
623 LPROCFS_CNTR_AVGMINMAX,
624 "wait_for_blk_quota(lquota_chkquota)", "us");
625 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_FOR_CHK_INO,
626 LPROCFS_CNTR_AVGMINMAX,
627 "wait_for_ino_quota(lquota_chkquota)", "us");
628 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_FOR_COMMIT_BLK,
629 LPROCFS_CNTR_AVGMINMAX,
630 "wait_for_blk_quota(lquota_pending_commit)",
632 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_FOR_COMMIT_INO,
633 LPROCFS_CNTR_AVGMINMAX,
634 "wait_for_ino_quota(lquota_pending_commit)",
637 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_PENDING_BLK_QUOTA,
638 LPROCFS_CNTR_AVGMINMAX,
639 "wait_for_pending_blk_quota_req"
640 "(qctxt_wait_pending_dqacq)", "us");
641 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_PENDING_INO_QUOTA,
642 LPROCFS_CNTR_AVGMINMAX,
643 "wait_for_pending_ino_quota_req"
644 "(qctxt_wait_pending_dqacq)", "us");
645 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_NOWAIT_PENDING_BLK_QUOTA,
646 LPROCFS_CNTR_AVGMINMAX,
647 "nowait_for_pending_blk_quota_req"
648 "(qctxt_wait_pending_dqacq)", "us");
649 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_NOWAIT_PENDING_INO_QUOTA,
650 LPROCFS_CNTR_AVGMINMAX,
651 "nowait_for_pending_ino_quota_req"
652 "(qctxt_wait_pending_dqacq)", "us");
654 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_QUOTA_CTL,
655 LPROCFS_CNTR_AVGMINMAX, "quota_ctl", "us");
656 lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_ADJUST_QUNIT,
657 LPROCFS_CNTR_AVGMINMAX, "adjust_qunit", "us");
659 lprocfs_register_stats(qctxt->lqc_proc_dir, "stats", qctxt->lqc_stats);
664 lprocfs_remove(&qctxt->lqc_proc_dir);
669 int lquota_proc_cleanup(struct lustre_quota_ctxt *qctxt)
671 if (!qctxt || !qctxt->lqc_proc_dir)
674 if (qctxt->lqc_stats != NULL)
675 lprocfs_free_stats(&qctxt->lqc_stats);
677 lprocfs_remove(&qctxt->lqc_proc_dir);