Whamcloud - gitweb
Branch b1_8
[fs/lustre-release.git] / lustre / quota / lproc_quota.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
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.
11  *
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).
17  *
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
21  *
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
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
30  * Use is subject to license terms.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  */
36
37 #define DEBUG_SUBSYSTEM S_LQUOTA
38
39 #include <linux/version.h>
40 #include <lprocfs_status.h>
41 #include <obd.h>
42 #include <linux/seq_file.h>
43 #include <lustre_fsfilt.h>
44
45 #include "quota_internal.h"
46
47 #ifdef HAVE_QUOTA_SUPPORT
48
49 #ifdef LPROCFS
50 int lprocfs_quota_rd_bunit(char *page, char **start, off_t off, int count,
51                            int *eof, void *data)
52 {
53         struct obd_device *obd = (struct obd_device *)data;
54         LASSERT(obd != NULL);
55
56         return snprintf(page, count, "%lu\n",
57                         obd->u.obt.obt_qctxt.lqc_bunit_sz);
58 }
59 EXPORT_SYMBOL(lprocfs_quota_rd_bunit);
60
61 int lprocfs_quota_wr_bunit(struct file *file, const char *buffer,
62                            unsigned long count, void *data)
63 {
64         struct obd_device *obd = (struct obd_device *)data;
65         int val, rc;
66         LASSERT(obd != NULL);
67
68         rc = lprocfs_write_helper(buffer, count, &val);
69         if (rc)
70                 return rc;
71
72         if (val % QUOTABLOCK_SIZE ||
73             val <= obd->u.obt.obt_qctxt.lqc_btune_sz)
74                 return -EINVAL;
75
76         obd->u.obt.obt_qctxt.lqc_bunit_sz = val;
77         return count;
78 }
79 EXPORT_SYMBOL(lprocfs_quota_wr_bunit);
80
81 int lprocfs_quota_rd_btune(char *page, char **start, off_t off, int count,
82                            int *eof, void *data)
83 {
84         struct obd_device *obd = (struct obd_device *)data;
85         LASSERT(obd != NULL);
86
87         return snprintf(page, count, "%lu\n",
88                         obd->u.obt.obt_qctxt.lqc_btune_sz);
89 }
90 EXPORT_SYMBOL(lprocfs_quota_rd_btune);
91
92 int lprocfs_quota_wr_btune(struct file *file, const char *buffer,
93                            unsigned long count, void *data)
94 {
95         struct obd_device *obd = (struct obd_device *)data;
96         int val, rc;
97         LASSERT(obd != NULL);
98
99         rc = lprocfs_write_helper(buffer, count, &val);
100         if (rc)
101                 return rc;
102
103         if (val <= QUOTABLOCK_SIZE * MIN_QLIMIT || val % QUOTABLOCK_SIZE ||
104             val >= obd->u.obt.obt_qctxt.lqc_bunit_sz)
105                 return -EINVAL;
106
107         obd->u.obt.obt_qctxt.lqc_btune_sz = val;
108         return count;
109 }
110 EXPORT_SYMBOL(lprocfs_quota_wr_btune);
111
112 int lprocfs_quota_rd_iunit(char *page, char **start, off_t off, int count,
113                            int *eof, void *data)
114 {
115         struct obd_device *obd = (struct obd_device *)data;
116         LASSERT(obd != NULL);
117
118         return snprintf(page, count, "%lu\n",
119                         obd->u.obt.obt_qctxt.lqc_iunit_sz);
120 }
121 EXPORT_SYMBOL(lprocfs_quota_rd_iunit);
122
123 int lprocfs_quota_wr_iunit(struct file *file, const char *buffer,
124                            unsigned long count, void *data)
125 {
126         struct obd_device *obd = (struct obd_device *)data;
127         int val, rc;
128         LASSERT(obd != NULL);
129
130         rc = lprocfs_write_helper(buffer, count, &val);
131         if (rc)
132                 return rc;
133
134         if (val <= obd->u.obt.obt_qctxt.lqc_itune_sz)
135                 return -EINVAL;
136
137         obd->u.obt.obt_qctxt.lqc_iunit_sz = val;
138         return count;
139 }
140 EXPORT_SYMBOL(lprocfs_quota_wr_iunit);
141
142 int lprocfs_quota_rd_itune(char *page, char **start, off_t off, int count,
143                            int *eof, void *data)
144 {
145         struct obd_device *obd = (struct obd_device *)data;
146         LASSERT(obd != NULL);
147
148         return snprintf(page, count, "%lu\n",
149                         obd->u.obt.obt_qctxt.lqc_itune_sz);
150 }
151 EXPORT_SYMBOL(lprocfs_quota_rd_itune);
152
153 int lprocfs_quota_wr_itune(struct file *file, const char *buffer,
154                            unsigned long count, void *data)
155 {
156         struct obd_device *obd = (struct obd_device *)data;
157         int val, rc;
158         LASSERT(obd != NULL);
159
160         rc = lprocfs_write_helper(buffer, count, &val);
161         if (rc)
162                 return rc;
163
164         if (val <= MIN_QLIMIT ||
165             val >= obd->u.obt.obt_qctxt.lqc_iunit_sz)
166                 return -EINVAL;
167
168         obd->u.obt.obt_qctxt.lqc_itune_sz = val;
169         return count;
170 }
171 EXPORT_SYMBOL(lprocfs_quota_wr_itune);
172
173 #define USER_QUOTA      1
174 #define GROUP_QUOTA     2
175
176 #define MAX_STYPE_SIZE  5
177
178 /* The following information about CURRENT quotas is expected on the output:
179  * MDS: u for user quotas (administrative+operational) turned on,
180  *      g for group quotas (administrative+operational) turned on,
181  *      1 for 32-bit operational quotas and 32-bit administrative quotas,
182  *      2 for 32-bit operational quotas and 64-bit administrative quotas,
183  *      3 for 64-bit operational quotas and 64-bit administrative quotas
184  * OST: u for user quotas (operational) turned on,
185  *      g for group quotas (operational) turned on,
186  *      1 for 32-bit local operational quotas,
187  *      3 for 64-bit local operational quotas,
188  * Permanent parameters can be read with lctl (?)
189  */
190 int lprocfs_quota_rd_type(char *page, char **start, off_t off, int count,
191                           int *eof, void *data)
192 {
193         struct obd_device *obd = (struct obd_device *)data;
194         char stype[MAX_STYPE_SIZE + 1] = "";
195         int oq_type, rc, is_mds;
196         lustre_quota_version_t aq_version, oq_version;
197         struct obd_device_target *obt;
198
199         LASSERT(obd != NULL);
200
201         obt = &obd->u.obt;
202         is_mds = !strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME);
203
204         /* Collect the needed information */
205         oq_type = obd->u.obt.obt_qctxt.lqc_flags;
206         oq_version = obt->obt_qfmt;
207         if (is_mds) {
208                 rc = mds_quota_get_version(obd, &aq_version);
209                 if (rc)
210                         return -EPROTO;
211                 /* Here we can also assert that aq_type == oq_type
212                  * except for quota startup/shutdown states     */
213         }
214
215         /* Transform the collected data into a user-readable string */
216         if (oq_type & LQC_USRQUOTA_FLAG)
217                 strcat(stype, "u");
218         if (oq_type & LQC_GRPQUOTA_FLAG)
219                 strcat(stype, "g");
220
221         if ((!is_mds || aq_version == LUSTRE_QUOTA_V1) &&
222             oq_version == LUSTRE_QUOTA_V1)
223                 strcat(stype, "1");
224 #ifdef HAVE_QUOTA64
225         else if ((!is_mds || aq_version == LUSTRE_QUOTA_V2) &&
226                  oq_version == LUSTRE_QUOTA_V2)
227                 strcat(stype, "3");
228 #endif
229         else if (is_mds && aq_version == LUSTRE_QUOTA_V2 &&
230                  oq_version == LUSTRE_QUOTA_V1)
231                 strcat(stype, "2");
232         else
233                 return -EPROTO;
234
235         return snprintf(page, count, "%s\n", stype);
236 }
237 EXPORT_SYMBOL(lprocfs_quota_rd_type);
238
239 static int auto_quota_on(struct obd_device *obd, int type,
240                          struct super_block *sb, int is_master)
241 {
242         struct obd_quotactl *oqctl;
243         struct lvfs_run_ctxt saved;
244         int rc = 0, id;
245         struct obd_device_target *obt;
246         ENTRY;
247
248         LASSERT(type == USRQUOTA || type == GRPQUOTA || type == UGQUOTA);
249
250         obt = &obd->u.obt;
251
252         OBD_ALLOC_PTR(oqctl);
253         if (!oqctl)
254                 RETURN(-ENOMEM);
255
256         if (!atomic_dec_and_test(&obt->obt_quotachecking)) {
257                 CDEBUG(D_INFO, "other people are doing quotacheck\n");
258                 atomic_inc(&obt->obt_quotachecking);
259                 RETURN(-EBUSY);
260         }
261
262         id = UGQUOTA2LQC(type);
263         /* quota already turned on */
264         if ((obt->obt_qctxt.lqc_flags & id) == id) {
265                 rc = 0;
266                 goto out;
267         }
268
269         oqctl->qc_type = type;
270         oqctl->qc_cmd = Q_QUOTAON;
271         oqctl->qc_id = obt->obt_qfmt;
272
273         push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
274         if (is_master) {
275                 struct mds_obd *mds = &obd->u.mds;
276
277                 down(&mds->mds_qonoff_sem);
278                 /* turn on cluster wide quota */
279                 rc = mds_admin_quota_on(obd, oqctl);
280                 if (rc)
281                         CDEBUG(rc == -ENOENT ? D_QUOTA : D_ERROR,
282                                "auto-enable admin quota failed. rc=%d\n", rc);
283                 up(&mds->mds_qonoff_sem);
284
285         }
286         if (!rc) {
287                 /* turn on local quota */
288                 rc = fsfilt_quotactl(obd, sb, oqctl);
289                 if (rc)
290                         CDEBUG(rc == -ENOENT ? D_QUOTA : D_ERROR,
291                                "auto-enable local quota failed. rc=%d\n", rc);
292                 else
293                         obt->obt_qctxt.lqc_flags |= UGQUOTA2LQC(type);
294         }
295
296         pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
297
298 out:
299         atomic_inc(&obt->obt_quotachecking);
300
301         OBD_FREE_PTR(oqctl);
302         RETURN(rc);
303 }
304
305 static int filter_quota_set_version(struct obd_device *obd,
306                                     lustre_quota_version_t version)
307 {
308         struct obd_device_target *obt = &obd->u.obt;
309
310         if (version != LUSTRE_QUOTA_V1) {
311 #ifdef HAVE_QUOTA64
312                 if (version != LUSTRE_QUOTA_V2)
313 #endif
314                         return -EINVAL;
315         }
316
317         if (!atomic_dec_and_test(&obt->obt_quotachecking)) {
318                 CDEBUG(D_INFO, "other people are doing quotacheck\n");
319                 atomic_inc(&obt->obt_quotachecking);
320                 return -EBUSY;
321         }
322
323         if (obt->obt_qctxt.lqc_flags & (LQC_USRQUOTA_FLAG | LQC_GRPQUOTA_FLAG)) {
324                 atomic_inc(&obt->obt_quotachecking);
325                 return -EBUSY;
326         }
327
328         obt->obt_qfmt = version;
329
330         atomic_inc(&obt->obt_quotachecking);
331
332         return 0;
333 }
334
335 /* The following settings of CURRENT quotas is expected on the input:
336  * MDS: u for user quotas (administrative+operational) turned on,
337  *      g for group quotas (administrative+operational) turned on,
338  *      1 for 32-bit operational quotas and 32-bit administrative quotas,
339  *      2 for 32-bit operational quotas and 64-bit administrative quotas,
340  *      3 for 64-bit operational quotas and 64-bit administrative quotas
341  * OST: u for user quotas (operational) turned on,
342  *      g for group quotas (operational) turned on,
343  *      1 for 32-bit local operational quotas,
344  *      2 for 32-bit local operational quotas,
345  *      3 for 64-bit local operational quotas,
346  * Permanent parameters can be set with lctl/tunefs
347  */
348 int lprocfs_quota_wr_type(struct file *file, const char *buffer,
349                           unsigned long count, void *data)
350 {
351         struct obd_device *obd = (struct obd_device *)data;
352         struct obd_device_target *obt;
353         int type = 0, is_mds, idx;
354         unsigned long i;
355         char stype[MAX_STYPE_SIZE + 1] = "";
356         static const lustre_quota_version_t s2av[3] = {LUSTRE_QUOTA_V1,
357                                                        LUSTRE_QUOTA_V2,
358                                                        LUSTRE_QUOTA_V2},
359                                             s2ov[3] = {LUSTRE_QUOTA_V1,
360                                                        LUSTRE_QUOTA_V1,
361                                                        LUSTRE_QUOTA_V2};
362         LASSERT(obd != NULL);
363
364         obt = &obd->u.obt;
365
366         is_mds = !strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME);
367
368         if (count > MAX_STYPE_SIZE)
369                 return -EINVAL;
370
371         if (copy_from_user(stype, buffer, count))
372                 return -EFAULT;
373
374         for (i = 0 ; i < count ; i++) {
375                 int rc;
376
377                 switch (stype[i]) {
378                 case 'u' :
379                         type |= USER_QUOTA;
380                         break;
381                 case 'g' :
382                         type |= GROUP_QUOTA;
383                         break;
384                 /* quota version specifiers */
385                 case '1' :
386                 case '2' :
387                 case '3' :
388                         idx = stype[i] - '1';
389 #ifndef HAVE_QUOTA64
390                         if (s2ov[idx] == LUSTRE_QUOTA_V2)
391                                 return -EINVAL;
392 #endif
393                         if (is_mds) {
394                                 rc = mds_quota_set_version(obd, s2av[idx]);
395                                 if (rc) {
396                                         CDEBUG(D_QUOTA, "failed to set admin "
397                                                "quota to spec %c! %d\n",
398                                                stype[i], rc);
399                                         return rc;
400                                 }
401                         }
402                         rc = filter_quota_set_version(obd, s2ov[idx]);
403                         if (rc) {
404                                 CDEBUG(D_QUOTA, "failed to set operational quota"
405                                        " to spec %c! %d\n", stype[i], rc);
406                                 return rc;
407                         }
408                         break;
409                 default  : /* just skip stray symbols like \n */
410                         break;
411                 }
412         }
413
414         if (type != 0) {
415                 auto_quota_on(obd, type - 1, obt->obt_sb, is_mds);
416                 build_lqs(obd);
417         }
418
419         return count;
420 }
421 EXPORT_SYMBOL(lprocfs_quota_wr_type);
422
423 int lprocfs_quota_rd_switch_seconds(char *page, char **start, off_t off,
424                                     int count, int *eof, void *data)
425 {
426         struct obd_device *obd = (struct obd_device *)data;
427         LASSERT(obd != NULL);
428
429         return snprintf(page, count, "%d\n",
430                         obd->u.obt.obt_qctxt.lqc_switch_seconds);
431 }
432 EXPORT_SYMBOL(lprocfs_quota_rd_switch_seconds);
433
434 int lprocfs_quota_wr_switch_seconds(struct file *file, const char *buffer,
435                                     unsigned long count, void *data)
436 {
437         struct obd_device *obd = (struct obd_device *)data;
438         int val, rc;
439         LASSERT(obd != NULL);
440
441         rc = lprocfs_write_helper(buffer, count, &val);
442         if (rc)
443                 return rc;
444
445         if (val <= 10)
446                 return -EINVAL;
447
448         obd->u.obt.obt_qctxt.lqc_switch_seconds = val;
449         return count;
450 }
451 EXPORT_SYMBOL(lprocfs_quota_wr_switch_seconds);
452
453 int lprocfs_quota_rd_sync_blk(char *page, char **start, off_t off,
454                               int count, int *eof, void *data)
455 {
456         struct obd_device *obd = (struct obd_device *)data;
457         LASSERT(obd != NULL);
458
459         return snprintf(page, count, "%d\n",
460                         obd->u.obt.obt_qctxt.lqc_sync_blk);
461 }
462 EXPORT_SYMBOL(lprocfs_quota_rd_sync_blk);
463
464 int lprocfs_quota_wr_sync_blk(struct file *file, const char *buffer,
465                               unsigned long count, void *data)
466 {
467         struct obd_device *obd = (struct obd_device *)data;
468         int val, rc;
469         LASSERT(obd != NULL);
470
471         rc = lprocfs_write_helper(buffer, count, &val);
472         if (rc)
473                 return rc;
474
475         if (val < 0)
476                 return -EINVAL;
477
478         obd->u.obt.obt_qctxt.lqc_sync_blk = val;
479         return count;
480 }
481 EXPORT_SYMBOL(lprocfs_quota_wr_sync_blk);
482
483 int lprocfs_quota_rd_switch_qs(char *page, char **start, off_t off,
484                                int count, int *eof, void *data)
485 {
486         struct obd_device *obd = (struct obd_device *)data;
487         LASSERT(obd != NULL);
488
489         return snprintf(page, count, "changing qunit size is %s\n",
490                         obd->u.obt.obt_qctxt.lqc_switch_qs ?
491                         "enabled" : "disabled");
492 }
493 EXPORT_SYMBOL(lprocfs_quota_rd_switch_qs);
494
495 int lprocfs_quota_wr_switch_qs(struct file *file, const char *buffer,
496                                unsigned long count, void *data)
497 {
498         struct obd_device *obd = (struct obd_device *)data;
499         int val, rc;
500         LASSERT(obd != NULL);
501
502         rc = lprocfs_write_helper(buffer, count, &val);
503         if (rc)
504                 return rc;
505
506         if (val)
507             obd->u.obt.obt_qctxt.lqc_switch_qs = 1;
508         else
509             obd->u.obt.obt_qctxt.lqc_switch_qs = 0;
510
511         return count;
512 }
513 EXPORT_SYMBOL(lprocfs_quota_wr_switch_qs);
514
515 int lprocfs_quota_rd_boundary_factor(char *page, char **start, off_t off,
516                                      int count, int *eof, void *data)
517 {
518         struct obd_device *obd = (struct obd_device *)data;
519         LASSERT(obd != NULL);
520
521
522         return snprintf(page, count, "%lu\n",
523                         obd->u.obt.obt_qctxt.lqc_cqs_boundary_factor);
524 }
525 EXPORT_SYMBOL(lprocfs_quota_rd_boundary_factor);
526
527 int lprocfs_quota_wr_boundary_factor(struct file *file, const char *buffer,
528                                      unsigned long count, void *data)
529 {
530         struct obd_device *obd = (struct obd_device *)data;
531         int val, rc;
532         LASSERT(obd != NULL);
533
534         rc = lprocfs_write_helper(buffer, count, &val);
535         if (rc)
536                 return rc;
537
538         if (val < 2)
539                 return -EINVAL;
540
541         obd->u.obt.obt_qctxt.lqc_cqs_boundary_factor = val;
542         return count;
543 }
544 EXPORT_SYMBOL(lprocfs_quota_wr_boundary_factor);
545
546 int lprocfs_quota_rd_least_bunit(char *page, char **start, off_t off,
547                                  int count, int *eof, void *data)
548 {
549         struct obd_device *obd = (struct obd_device *)data;
550         LASSERT(obd != NULL);
551
552
553         return snprintf(page, count, "%lu\n",
554                         obd->u.obt.obt_qctxt.lqc_cqs_least_bunit);
555 }
556 EXPORT_SYMBOL(lprocfs_quota_rd_least_bunit);
557
558 int lprocfs_quota_wr_least_bunit(struct file *file, const char *buffer,
559                                  unsigned long count, void *data)
560 {
561         struct obd_device *obd = (struct obd_device *)data;
562         int val, rc;
563         LASSERT(obd != NULL);
564
565         rc = lprocfs_write_helper(buffer, count, &val);
566         if (rc)
567                 return rc;
568
569         if (val < PTLRPC_MAX_BRW_SIZE ||
570             val >= obd->u.obt.obt_qctxt.lqc_bunit_sz)
571                 return -EINVAL;
572
573         obd->u.obt.obt_qctxt.lqc_cqs_least_bunit = val;
574         return count;
575 }
576 EXPORT_SYMBOL(lprocfs_quota_wr_least_bunit);
577
578 int lprocfs_quota_rd_least_iunit(char *page, char **start, off_t off,
579                                  int count, int *eof, void *data)
580 {
581         struct obd_device *obd = (struct obd_device *)data;
582         LASSERT(obd != NULL);
583
584
585         return snprintf(page, count, "%lu\n",
586                         obd->u.obt.obt_qctxt.lqc_cqs_least_iunit);
587 }
588 EXPORT_SYMBOL(lprocfs_quota_rd_least_iunit);
589
590 int lprocfs_quota_wr_least_iunit(struct file *file, const char *buffer,
591                                  unsigned long count, void *data)
592 {
593         struct obd_device *obd = (struct obd_device *)data;
594         int val, rc;
595         LASSERT(obd != NULL);
596
597         rc = lprocfs_write_helper(buffer, count, &val);
598         if (rc)
599                 return rc;
600
601         if (val < 1 || val >= obd->u.obt.obt_qctxt.lqc_iunit_sz)
602                 return -EINVAL;
603
604         obd->u.obt.obt_qctxt.lqc_cqs_least_iunit = val;
605         return count;
606 }
607 EXPORT_SYMBOL(lprocfs_quota_wr_least_iunit);
608
609 int lprocfs_quota_rd_qs_factor(char *page, char **start, off_t off,
610                                int count, int *eof, void *data)
611 {
612         struct obd_device *obd = (struct obd_device *)data;
613         LASSERT(obd != NULL);
614
615
616         return snprintf(page, count, "%lu\n",
617                         obd->u.obt.obt_qctxt.lqc_cqs_qs_factor);
618 }
619 EXPORT_SYMBOL(lprocfs_quota_rd_qs_factor);
620
621 int lprocfs_quota_wr_qs_factor(struct file *file, const char *buffer,
622                                unsigned long count, void *data)
623 {
624         struct obd_device *obd = (struct obd_device *)data;
625         int val, rc;
626         LASSERT(obd != NULL);
627
628         rc = lprocfs_write_helper(buffer, count, &val);
629         if (rc)
630                 return rc;
631
632         if (val < 2)
633                 return -EINVAL;
634
635         obd->u.obt.obt_qctxt.lqc_cqs_qs_factor = val;
636         return count;
637 }
638 EXPORT_SYMBOL(lprocfs_quota_wr_qs_factor);
639
640 struct lprocfs_vars lprocfs_quota_common_vars[] = {
641         { "quota_bunit_sz", lprocfs_quota_rd_bunit,
642                             lprocfs_quota_wr_bunit, 0},
643         { "quota_btune_sz", lprocfs_quota_rd_btune,
644                             lprocfs_quota_wr_btune, 0},
645         { "quota_iunit_sz", lprocfs_quota_rd_iunit,
646                             lprocfs_quota_wr_iunit, 0},
647         { "quota_itune_sz", lprocfs_quota_rd_itune,
648                             lprocfs_quota_wr_itune, 0},
649         { "quota_type",     lprocfs_quota_rd_type,
650                             lprocfs_quota_wr_type, 0},
651         { "quota_switch_seconds",  lprocfs_quota_rd_switch_seconds,
652                                    lprocfs_quota_wr_switch_seconds, 0 },
653         { "quota_sync_blk", lprocfs_quota_rd_sync_blk,
654                             lprocfs_quota_wr_sync_blk, 0},
655         { NULL }
656 };
657
658 struct lprocfs_vars lprocfs_quota_master_vars[] = {
659         { "quota_switch_qs", lprocfs_quota_rd_switch_qs,
660                              lprocfs_quota_wr_switch_qs, 0 },
661         { "quota_boundary_factor", lprocfs_quota_rd_boundary_factor,
662                                    lprocfs_quota_wr_boundary_factor, 0 },
663         { "quota_least_bunit", lprocfs_quota_rd_least_bunit,
664                                lprocfs_quota_wr_least_bunit, 0 },
665         { "quota_least_iunit", lprocfs_quota_rd_least_iunit,
666                                lprocfs_quota_wr_least_iunit, 0 },
667         { "quota_qs_factor",   lprocfs_quota_rd_qs_factor,
668                                lprocfs_quota_wr_qs_factor, 0 },
669         { NULL }
670 };
671
672 int lquota_proc_setup(struct obd_device *obd, int is_master)
673 {
674         struct lustre_quota_ctxt *qctxt = &obd->u.obt.obt_qctxt;
675         int rc = 0;
676         ENTRY;
677
678         LASSERT(lquota_type_proc_dir && obd);
679         qctxt->lqc_proc_dir = lprocfs_register(obd->obd_name,
680                                                lquota_type_proc_dir,
681                                                lprocfs_quota_common_vars, obd);
682         if (IS_ERR(qctxt->lqc_proc_dir)) {
683                 rc = PTR_ERR(qctxt->lqc_proc_dir);
684                 CERROR("error %d setting up lprocfs for %s\n", rc,
685                        obd->obd_name);
686                 qctxt->lqc_proc_dir = NULL;
687                 GOTO(out, rc);
688         }
689
690         if (is_master) {
691                 rc = lprocfs_add_vars(qctxt->lqc_proc_dir,
692                                       lprocfs_quota_master_vars, obd);
693                 if (rc) {
694                         CERROR("error %d setting up lprocfs for %s"
695                                "(quota master)\n", rc, obd->obd_name);
696                         GOTO(out_free_proc, rc);
697                 }
698         }
699
700         qctxt->lqc_stats = lprocfs_alloc_stats(LQUOTA_LAST_STAT -
701                                                LQUOTA_FIRST_STAT, 0);
702         if (!qctxt->lqc_stats)
703                 GOTO(out_free_proc, rc = -ENOMEM);
704
705         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_SYNC_ACQ,
706                              LPROCFS_CNTR_AVGMINMAX, "sync_acq_req", "us");
707         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_SYNC_REL,
708                              LPROCFS_CNTR_AVGMINMAX, "sync_rel_req", "us");
709         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_ASYNC_ACQ,
710                              LPROCFS_CNTR_AVGMINMAX, "async_acq_req", "us");
711         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_ASYNC_REL,
712                              LPROCFS_CNTR_AVGMINMAX, "async_rel_req", "us");
713
714         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_FOR_CHK_BLK,
715                              LPROCFS_CNTR_AVGMINMAX,
716                              "wait_for_blk_quota(lquota_chkquota)", "us");
717         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_FOR_CHK_INO,
718                              LPROCFS_CNTR_AVGMINMAX,
719                              "wait_for_ino_quota(lquota_chkquota)", "us");
720         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_FOR_COMMIT_BLK,
721                              LPROCFS_CNTR_AVGMINMAX,
722                              "wait_for_blk_quota(lquota_pending_commit)",
723                              "us");
724         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_FOR_COMMIT_INO,
725                              LPROCFS_CNTR_AVGMINMAX,
726                              "wait_for_ino_quota(lquota_pending_commit)",
727                              "us");
728
729         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_PENDING_BLK_QUOTA,
730                              LPROCFS_CNTR_AVGMINMAX,
731                              "wait_for_pending_blk_quota_req"
732                              "(qctxt_wait_pending_dqacq)", "us");
733         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_PENDING_INO_QUOTA,
734                              LPROCFS_CNTR_AVGMINMAX,
735                              "wait_for_pending_ino_quota_req"
736                              "(qctxt_wait_pending_dqacq)", "us");
737         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_NOWAIT_PENDING_BLK_QUOTA,
738                              LPROCFS_CNTR_AVGMINMAX,
739                              "nowait_for_pending_blk_quota_req"
740                              "(qctxt_wait_pending_dqacq)", "us");
741         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_NOWAIT_PENDING_INO_QUOTA,
742                              LPROCFS_CNTR_AVGMINMAX,
743                              "nowait_for_pending_ino_quota_req"
744                              "(qctxt_wait_pending_dqacq)", "us");
745
746         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_QUOTA_CTL,
747                              LPROCFS_CNTR_AVGMINMAX, "quota_ctl", "us");
748         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_ADJUST_QUNIT,
749                              LPROCFS_CNTR_AVGMINMAX, "adjust_qunit", "us");
750
751         lprocfs_register_stats(qctxt->lqc_proc_dir, "stats", qctxt->lqc_stats);
752
753         RETURN(rc);
754
755 out_free_proc:
756         lprocfs_remove(&qctxt->lqc_proc_dir);
757 out:
758         RETURN(rc);
759 }
760
761 int lquota_proc_cleanup(struct lustre_quota_ctxt *qctxt)
762 {
763         if (!qctxt || !qctxt->lqc_proc_dir)
764                 return -EINVAL;
765
766         if (qctxt->lqc_stats != NULL)
767                 lprocfs_free_stats(&qctxt->lqc_stats);
768
769         lprocfs_remove(&qctxt->lqc_proc_dir);
770         return 0;
771 }
772
773 #endif  /* LPROCFS */
774 #endif