Whamcloud - gitweb
b=21251 Add lustre/tests/ha.sh
[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         if (is_mds) {
207                 rc = mds_quota_get_version(obd, &aq_version, &oq_version);
208                 if (rc)
209                         return -EPROTO;
210         } else {
211                 oq_version = obt->obt_qfmt;
212         }
213
214         /* Transform the collected data into a user-readable string */
215         if (oq_type & LQC_USRQUOTA_FLAG)
216                 strcat(stype, "u");
217         if (oq_type & LQC_GRPQUOTA_FLAG)
218                 strcat(stype, "g");
219
220         if ((!is_mds || aq_version == LUSTRE_QUOTA_V1) &&
221             oq_version == LUSTRE_QUOTA_V1)
222                 strcat(stype, "1");
223 #ifdef HAVE_QUOTA64
224         else if ((!is_mds || aq_version == LUSTRE_QUOTA_V2) &&
225                  oq_version == LUSTRE_QUOTA_V2)
226                 strcat(stype, "3");
227 #endif
228         else if (is_mds && aq_version == LUSTRE_QUOTA_V2 &&
229                  oq_version == LUSTRE_QUOTA_V1)
230                 strcat(stype, "2");
231         else
232                 return -EPROTO;
233
234         return snprintf(page, count, "%s\n", stype);
235 }
236 EXPORT_SYMBOL(lprocfs_quota_rd_type);
237
238 /*
239  * generic_quota_on is very lazy and tolerant about current quota settings
240  * @global means to turn on quotas on each OST additionally to local quotas;
241  * should not be called from filter_quota_ctl on MDS nodes (as it starts
242  * admin quotas on MDS nodes).
243  */
244 int generic_quota_on(struct obd_device *obd, struct obd_quotactl *oqctl, int global)
245 {
246         struct obd_device_target *obt = &obd->u.obt;
247         struct lvfs_run_ctxt saved;
248         int id, is_master, rc = 0, local; /* means we need a local quotaon */
249
250         if (!atomic_dec_and_test(&obt->obt_quotachecking)) {
251                 CDEBUG(D_INFO, "other people are doing quotacheck\n");
252                 atomic_inc(&obt->obt_quotachecking);
253                 RETURN(-EBUSY);
254         }
255
256         id = UGQUOTA2LQC(oqctl->qc_type);
257         local = (obt->obt_qctxt.lqc_flags & id) != id;
258
259         oqctl->qc_cmd = Q_QUOTAON;
260         oqctl->qc_id = obt->obt_qfmt;
261
262         is_master = !strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME);
263         if (is_master) {
264                 down(&obd->u.mds.mds_qonoff_sem);
265                 if (local) {
266                         push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
267                         /* turn on cluster wide quota */
268                         rc = mds_admin_quota_on(obd, oqctl);
269                         pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
270                         if (rc && rc != -ENOENT)
271                                 CERROR("%s: %s admin quotaon failed. rc=%d\n",
272                                        obd->obd_name, global? "global":"local",
273                                        rc);
274                 }
275         }
276
277         if (rc == 0) {
278                 if (local) {
279                         push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
280                         /* turn on local quota */
281                         rc = fsfilt_quotactl(obd, obt->obt_sb, oqctl);
282                         if (rc) {
283                                 if (rc != -ENOENT)
284                                         CERROR("%s: %s quotaon failed with"
285                                                " rc=%d\n", obd->obd_name,
286                                                global ? "global" : "local", rc);
287                         } else {
288                                 obt->obt_qctxt.lqc_flags |= UGQUOTA2LQC(oqctl->qc_type);
289                                 /* when quotaon, create lqs for every
290                                  * quota uid/gid b=18574 */
291                                 build_lqs(obd);
292                         }
293                         pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
294                 }
295
296                 if (rc == 0 && global && is_master)
297                         rc = obd_quotactl(obd->u.mds.mds_lov_exp, oqctl);
298         }
299
300         if (is_master)
301                 up(&obd->u.mds.mds_qonoff_sem);
302
303         atomic_inc(&obt->obt_quotachecking);
304
305         return rc;
306 }
307
308 static int auto_quota_on(struct obd_device *obd, int type)
309 {
310         struct obd_quotactl *oqctl;
311         int rc;
312         ENTRY;
313
314         LASSERT(type == USRQUOTA || type == GRPQUOTA || type == UGQUOTA);
315
316         OBD_ALLOC_PTR(oqctl);
317         if (!oqctl)
318                 RETURN(-ENOMEM);
319
320         oqctl->qc_type = type;
321
322         rc = generic_quota_on(obd, oqctl, 0);
323
324         OBD_FREE_PTR(oqctl);
325         RETURN(rc);
326 }
327
328 static int filter_quota_set_version(struct obd_device *obd,
329                                     lustre_quota_version_t version)
330 {
331         struct obd_device_target *obt = &obd->u.obt;
332
333         if (version != LUSTRE_QUOTA_V1) {
334 #ifdef HAVE_QUOTA64
335                 if (version != LUSTRE_QUOTA_V2)
336 #endif
337                         return -EINVAL;
338         }
339
340         if (!atomic_dec_and_test(&obt->obt_quotachecking)) {
341                 CDEBUG(D_INFO, "other people are doing quotacheck\n");
342                 atomic_inc(&obt->obt_quotachecking);
343                 return -EBUSY;
344         }
345
346         /* do not complain of being busy if we actually have nothing to do */
347         if (obt->obt_qfmt != version) {
348                 if (obt->obt_qctxt.lqc_flags&(LQC_USRQUOTA_FLAG|LQC_GRPQUOTA_FLAG)){
349                         atomic_inc(&obt->obt_quotachecking);
350                         return -EBUSY;
351                 }
352                 obt->obt_qfmt = version;
353         }
354
355         atomic_inc(&obt->obt_quotachecking);
356
357         return 0;
358 }
359
360 /* The following settings of CURRENT quotas is expected on the input:
361  * MDS: u for user quotas (administrative+operational) turned on,
362  *      g for group quotas (administrative+operational) turned on,
363  *      1 for 32-bit operational quotas and 32-bit administrative quotas,
364  *      2 for 32-bit operational quotas and 64-bit administrative quotas,
365  *      3 for 64-bit operational quotas and 64-bit administrative quotas
366  * OST: u for user quotas (operational) turned on,
367  *      g for group quotas (operational) turned on,
368  *      1 for 32-bit local operational quotas,
369  *      2 for 32-bit local operational quotas,
370  *      3 for 64-bit local operational quotas,
371  * Permanent parameters can be set with lctl/tunefs
372  */
373 int lprocfs_quota_wr_type(struct file *file, const char *buffer,
374                           unsigned long count, void *data)
375 {
376         struct obd_device *obd = (struct obd_device *)data;
377         struct obd_device_target *obt;
378         int type = 0, is_mds, idx;
379         unsigned long i;
380         char stype[MAX_STYPE_SIZE + 1] = "";
381         static const lustre_quota_version_t s2av[3] = {LUSTRE_QUOTA_V1,
382                                                        LUSTRE_QUOTA_V2,
383                                                        LUSTRE_QUOTA_V2},
384                                             s2ov[3] = {LUSTRE_QUOTA_V1,
385                                                        LUSTRE_QUOTA_V1,
386                                                        LUSTRE_QUOTA_V2};
387         LASSERT(obd != NULL);
388
389         obt = &obd->u.obt;
390
391         is_mds = !strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME);
392
393         if (count > MAX_STYPE_SIZE)
394                 return -EINVAL;
395
396         if (copy_from_user(stype, buffer, count))
397                 return -EFAULT;
398
399         for (i = 0 ; i < count ; i++) {
400                 int rc;
401
402                 switch (stype[i]) {
403                 case 'u' :
404                         type |= USER_QUOTA;
405                         break;
406                 case 'g' :
407                         type |= GROUP_QUOTA;
408                         break;
409                 /* quota version specifiers */
410                 case '1' :
411                 case '2' :
412                 case '3' :
413                         idx = stype[i] - '1';
414 #ifndef HAVE_QUOTA64
415                         if (s2ov[idx] == LUSTRE_QUOTA_V2)
416                                 return -EINVAL;
417 #endif
418                         if (is_mds) {
419                                 rc = mds_quota_set_version(obd, s2av[idx],
420                                                            s2ov[idx]);
421                                 if (rc) {
422                                         CDEBUG(D_QUOTA, "failed to set admin "
423                                                "quota to spec %c! %d\n",
424                                                stype[i], rc);
425                                         return rc;
426                                 }
427                         } else {
428                                 rc = filter_quota_set_version(obd, s2ov[idx]);
429                                 if (rc) {
430                                         CDEBUG(D_QUOTA, "failed to set op"
431                                                " quota to spec %c! %d\n",
432                                                stype[i], rc);
433                                         return rc;
434                                 }
435                         }
436                         break;
437                 default  : /* just skip stray symbols like \n */
438                         break;
439                 }
440         }
441
442         if (type != 0) {
443                 int rc = auto_quota_on(obd, type - 1);
444
445                 if (rc == -ENOENT)
446                         CWARN("%s: quotaon failed because quota files don't "
447                               "exist, please run quotacheck firstly\n",
448                               obd->obd_name);
449                 else if (rc == -EALREADY)
450                         CWARN("%s: quota is on already!\n", obd->obd_name);
451                 else if (rc != 0)
452                         return rc;
453         }
454
455         return count;
456 }
457 EXPORT_SYMBOL(lprocfs_quota_wr_type);
458
459 int lprocfs_quota_rd_switch_seconds(char *page, char **start, off_t off,
460                                     int count, int *eof, void *data)
461 {
462         struct obd_device *obd = (struct obd_device *)data;
463         LASSERT(obd != NULL);
464
465         return snprintf(page, count, "%d\n",
466                         obd->u.obt.obt_qctxt.lqc_switch_seconds);
467 }
468 EXPORT_SYMBOL(lprocfs_quota_rd_switch_seconds);
469
470 int lprocfs_quota_wr_switch_seconds(struct file *file, const char *buffer,
471                                     unsigned long count, void *data)
472 {
473         struct obd_device *obd = (struct obd_device *)data;
474         int val, rc;
475         LASSERT(obd != NULL);
476
477         rc = lprocfs_write_helper(buffer, count, &val);
478         if (rc)
479                 return rc;
480
481         if (val <= 10)
482                 return -EINVAL;
483
484         obd->u.obt.obt_qctxt.lqc_switch_seconds = val;
485         return count;
486 }
487 EXPORT_SYMBOL(lprocfs_quota_wr_switch_seconds);
488
489 int lprocfs_quota_rd_sync_blk(char *page, char **start, off_t off,
490                               int count, int *eof, void *data)
491 {
492         struct obd_device *obd = (struct obd_device *)data;
493         LASSERT(obd != NULL);
494
495         return snprintf(page, count, "%d\n",
496                         obd->u.obt.obt_qctxt.lqc_sync_blk);
497 }
498 EXPORT_SYMBOL(lprocfs_quota_rd_sync_blk);
499
500 int lprocfs_quota_wr_sync_blk(struct file *file, const char *buffer,
501                               unsigned long count, void *data)
502 {
503         struct obd_device *obd = (struct obd_device *)data;
504         int val, rc;
505         LASSERT(obd != NULL);
506
507         rc = lprocfs_write_helper(buffer, count, &val);
508         if (rc)
509                 return rc;
510
511         if (val < 0)
512                 return -EINVAL;
513
514         obd->u.obt.obt_qctxt.lqc_sync_blk = val;
515         return count;
516 }
517 EXPORT_SYMBOL(lprocfs_quota_wr_sync_blk);
518
519 int lprocfs_quota_rd_switch_qs(char *page, char **start, off_t off,
520                                int count, int *eof, void *data)
521 {
522         struct obd_device *obd = (struct obd_device *)data;
523         LASSERT(obd != NULL);
524
525         return snprintf(page, count, "changing qunit size is %s\n",
526                         obd->u.obt.obt_qctxt.lqc_switch_qs ?
527                         "enabled" : "disabled");
528 }
529 EXPORT_SYMBOL(lprocfs_quota_rd_switch_qs);
530
531 int lprocfs_quota_wr_switch_qs(struct file *file, const char *buffer,
532                                unsigned long count, void *data)
533 {
534         struct obd_device *obd = (struct obd_device *)data;
535         int val, rc;
536         LASSERT(obd != NULL);
537
538         rc = lprocfs_write_helper(buffer, count, &val);
539         if (rc)
540                 return rc;
541
542         if (val)
543             obd->u.obt.obt_qctxt.lqc_switch_qs = 1;
544         else
545             obd->u.obt.obt_qctxt.lqc_switch_qs = 0;
546
547         return count;
548 }
549 EXPORT_SYMBOL(lprocfs_quota_wr_switch_qs);
550
551 int lprocfs_quota_rd_boundary_factor(char *page, char **start, off_t off,
552                                      int count, int *eof, void *data)
553 {
554         struct obd_device *obd = (struct obd_device *)data;
555         LASSERT(obd != NULL);
556
557
558         return snprintf(page, count, "%lu\n",
559                         obd->u.obt.obt_qctxt.lqc_cqs_boundary_factor);
560 }
561 EXPORT_SYMBOL(lprocfs_quota_rd_boundary_factor);
562
563 int lprocfs_quota_wr_boundary_factor(struct file *file, const char *buffer,
564                                      unsigned long count, void *data)
565 {
566         struct obd_device *obd = (struct obd_device *)data;
567         int val, rc;
568         LASSERT(obd != NULL);
569
570         rc = lprocfs_write_helper(buffer, count, &val);
571         if (rc)
572                 return rc;
573
574         if (val < 2)
575                 return -EINVAL;
576
577         obd->u.obt.obt_qctxt.lqc_cqs_boundary_factor = val;
578         return count;
579 }
580 EXPORT_SYMBOL(lprocfs_quota_wr_boundary_factor);
581
582 int lprocfs_quota_rd_least_bunit(char *page, char **start, off_t off,
583                                  int count, int *eof, void *data)
584 {
585         struct obd_device *obd = (struct obd_device *)data;
586         LASSERT(obd != NULL);
587
588
589         return snprintf(page, count, "%lu\n",
590                         obd->u.obt.obt_qctxt.lqc_cqs_least_bunit);
591 }
592 EXPORT_SYMBOL(lprocfs_quota_rd_least_bunit);
593
594 int lprocfs_quota_wr_least_bunit(struct file *file, const char *buffer,
595                                  unsigned long count, void *data)
596 {
597         struct obd_device *obd = (struct obd_device *)data;
598         int val, rc;
599         LASSERT(obd != NULL);
600
601         rc = lprocfs_write_helper(buffer, count, &val);
602         if (rc)
603                 return rc;
604
605         if (val < PTLRPC_MAX_BRW_SIZE ||
606             val >= obd->u.obt.obt_qctxt.lqc_bunit_sz)
607                 return -EINVAL;
608
609         obd->u.obt.obt_qctxt.lqc_cqs_least_bunit = val;
610         return count;
611 }
612 EXPORT_SYMBOL(lprocfs_quota_wr_least_bunit);
613
614 int lprocfs_quota_rd_least_iunit(char *page, char **start, off_t off,
615                                  int count, int *eof, void *data)
616 {
617         struct obd_device *obd = (struct obd_device *)data;
618         LASSERT(obd != NULL);
619
620
621         return snprintf(page, count, "%lu\n",
622                         obd->u.obt.obt_qctxt.lqc_cqs_least_iunit);
623 }
624 EXPORT_SYMBOL(lprocfs_quota_rd_least_iunit);
625
626 int lprocfs_quota_wr_least_iunit(struct file *file, const char *buffer,
627                                  unsigned long count, void *data)
628 {
629         struct obd_device *obd = (struct obd_device *)data;
630         int val, rc;
631         LASSERT(obd != NULL);
632
633         rc = lprocfs_write_helper(buffer, count, &val);
634         if (rc)
635                 return rc;
636
637         if (val < 1 || val >= obd->u.obt.obt_qctxt.lqc_iunit_sz)
638                 return -EINVAL;
639
640         obd->u.obt.obt_qctxt.lqc_cqs_least_iunit = val;
641         return count;
642 }
643 EXPORT_SYMBOL(lprocfs_quota_wr_least_iunit);
644
645 int lprocfs_quota_rd_qs_factor(char *page, char **start, off_t off,
646                                int count, int *eof, void *data)
647 {
648         struct obd_device *obd = (struct obd_device *)data;
649         LASSERT(obd != NULL);
650
651
652         return snprintf(page, count, "%lu\n",
653                         obd->u.obt.obt_qctxt.lqc_cqs_qs_factor);
654 }
655 EXPORT_SYMBOL(lprocfs_quota_rd_qs_factor);
656
657 int lprocfs_quota_wr_qs_factor(struct file *file, const char *buffer,
658                                unsigned long count, void *data)
659 {
660         struct obd_device *obd = (struct obd_device *)data;
661         int val, rc;
662         LASSERT(obd != NULL);
663
664         rc = lprocfs_write_helper(buffer, count, &val);
665         if (rc)
666                 return rc;
667
668         if (val < 2)
669                 return -EINVAL;
670
671         obd->u.obt.obt_qctxt.lqc_cqs_qs_factor = val;
672         return count;
673 }
674 EXPORT_SYMBOL(lprocfs_quota_wr_qs_factor);
675
676 struct lprocfs_vars lprocfs_quota_common_vars[] = {
677         { "quota_bunit_sz", lprocfs_quota_rd_bunit,
678                             lprocfs_quota_wr_bunit, 0},
679         { "quota_btune_sz", lprocfs_quota_rd_btune,
680                             lprocfs_quota_wr_btune, 0},
681         { "quota_iunit_sz", lprocfs_quota_rd_iunit,
682                             lprocfs_quota_wr_iunit, 0},
683         { "quota_itune_sz", lprocfs_quota_rd_itune,
684                             lprocfs_quota_wr_itune, 0},
685         { "quota_type",     lprocfs_quota_rd_type,
686                             lprocfs_quota_wr_type, 0},
687         { "quota_switch_seconds",  lprocfs_quota_rd_switch_seconds,
688                                    lprocfs_quota_wr_switch_seconds, 0 },
689         { "quota_sync_blk", lprocfs_quota_rd_sync_blk,
690                             lprocfs_quota_wr_sync_blk, 0},
691         { NULL }
692 };
693
694 struct lprocfs_vars lprocfs_quota_master_vars[] = {
695         { "quota_switch_qs", lprocfs_quota_rd_switch_qs,
696                              lprocfs_quota_wr_switch_qs, 0 },
697         { "quota_boundary_factor", lprocfs_quota_rd_boundary_factor,
698                                    lprocfs_quota_wr_boundary_factor, 0 },
699         { "quota_least_bunit", lprocfs_quota_rd_least_bunit,
700                                lprocfs_quota_wr_least_bunit, 0 },
701         { "quota_least_iunit", lprocfs_quota_rd_least_iunit,
702                                lprocfs_quota_wr_least_iunit, 0 },
703         { "quota_qs_factor",   lprocfs_quota_rd_qs_factor,
704                                lprocfs_quota_wr_qs_factor, 0 },
705         { NULL }
706 };
707
708 int lquota_proc_setup(struct obd_device *obd, int is_master)
709 {
710         struct lustre_quota_ctxt *qctxt = &obd->u.obt.obt_qctxt;
711         int rc = 0;
712         ENTRY;
713
714         LASSERT(lquota_type_proc_dir && obd);
715         qctxt->lqc_proc_dir = lprocfs_register(obd->obd_name,
716                                                lquota_type_proc_dir,
717                                                lprocfs_quota_common_vars, obd);
718         if (IS_ERR(qctxt->lqc_proc_dir)) {
719                 rc = PTR_ERR(qctxt->lqc_proc_dir);
720                 CERROR("%s: error %d setting up lprocfs\n",
721                        obd->obd_name, rc);
722                 qctxt->lqc_proc_dir = NULL;
723                 GOTO(out, rc);
724         }
725
726         if (is_master) {
727                 rc = lprocfs_add_vars(qctxt->lqc_proc_dir,
728                                       lprocfs_quota_master_vars, obd);
729                 if (rc) {
730                         CERROR("%s: error %d setting up lprocfs for "
731                                "quota master\n", obd->obd_name, rc);
732                         GOTO(out_free_proc, rc);
733                 }
734         }
735
736         qctxt->lqc_stats = lprocfs_alloc_stats(LQUOTA_LAST_STAT -
737                                                LQUOTA_FIRST_STAT, 0);
738         if (!qctxt->lqc_stats)
739                 GOTO(out_free_proc, rc = -ENOMEM);
740
741         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_SYNC_ACQ,
742                              LPROCFS_CNTR_AVGMINMAX, "sync_acq_req", "us");
743         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_SYNC_REL,
744                              LPROCFS_CNTR_AVGMINMAX, "sync_rel_req", "us");
745         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_ASYNC_ACQ,
746                              LPROCFS_CNTR_AVGMINMAX, "async_acq_req", "us");
747         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_ASYNC_REL,
748                              LPROCFS_CNTR_AVGMINMAX, "async_rel_req", "us");
749
750         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_FOR_CHK_BLK,
751                              LPROCFS_CNTR_AVGMINMAX,
752                              "wait_for_blk_quota(lquota_chkquota)", "us");
753         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_FOR_CHK_INO,
754                              LPROCFS_CNTR_AVGMINMAX,
755                              "wait_for_ino_quota(lquota_chkquota)", "us");
756         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_FOR_COMMIT_BLK,
757                              LPROCFS_CNTR_AVGMINMAX,
758                              "wait_for_blk_quota(lquota_pending_commit)",
759                              "us");
760         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_FOR_COMMIT_INO,
761                              LPROCFS_CNTR_AVGMINMAX,
762                              "wait_for_ino_quota(lquota_pending_commit)",
763                              "us");
764
765         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_PENDING_BLK_QUOTA,
766                              LPROCFS_CNTR_AVGMINMAX,
767                              "wait_for_pending_blk_quota_req"
768                              "(qctxt_wait_pending_dqacq)", "us");
769         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_PENDING_INO_QUOTA,
770                              LPROCFS_CNTR_AVGMINMAX,
771                              "wait_for_pending_ino_quota_req"
772                              "(qctxt_wait_pending_dqacq)", "us");
773         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_NOWAIT_PENDING_BLK_QUOTA,
774                              LPROCFS_CNTR_AVGMINMAX,
775                              "nowait_for_pending_blk_quota_req"
776                              "(qctxt_wait_pending_dqacq)", "us");
777         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_NOWAIT_PENDING_INO_QUOTA,
778                              LPROCFS_CNTR_AVGMINMAX,
779                              "nowait_for_pending_ino_quota_req"
780                              "(qctxt_wait_pending_dqacq)", "us");
781
782         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_QUOTA_CTL,
783                              LPROCFS_CNTR_AVGMINMAX, "quota_ctl", "us");
784         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_ADJUST_QUNIT,
785                              LPROCFS_CNTR_AVGMINMAX, "adjust_qunit", "us");
786
787         lprocfs_register_stats(qctxt->lqc_proc_dir, "stats", qctxt->lqc_stats);
788
789         RETURN(rc);
790
791 out_free_proc:
792         lprocfs_remove(&qctxt->lqc_proc_dir);
793 out:
794         RETURN(rc);
795 }
796
797 int lquota_proc_cleanup(struct lustre_quota_ctxt *qctxt)
798 {
799         if (!qctxt || !qctxt->lqc_proc_dir)
800                 return -EINVAL;
801
802         if (qctxt->lqc_stats != NULL)
803                 lprocfs_free_stats(&qctxt->lqc_stats);
804
805         lprocfs_remove(&qctxt->lqc_proc_dir);
806         return 0;
807 }
808
809 #endif  /* LPROCFS */
810 #endif