Whamcloud - gitweb
LU-1842 quota: define quota records for glb/slv indexes
[fs/lustre-release.git] / lustre / quota / lproc_quota.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
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.
9  *
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).
15  *
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
19  *
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
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2011, Whamcloud, Inc.
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 "lquota_internal.h"
46 #include "quota_internal.h"
47
48 #ifdef LPROCFS
49 /* structure allocated at seq_open time and release when seq_release is called.
50  * It is passed to seq_start/stop/next/show which can thus use the same lu_env
51  * to be used with the iterator API */
52 struct lquota_procfs {
53         struct dt_object        *lqp_obj;
54         struct lu_env            lqp_env;
55 };
56
57 /* global shared environment */
58 static void *lprocfs_quota_seq_start(struct seq_file *p, loff_t *pos)
59 {
60         struct lquota_procfs    *lqp = p->private;
61         const struct dt_it_ops  *iops;
62         struct dt_it            *it;
63         loff_t                   offset = *pos;
64         int                      rc;
65
66         LASSERT(lqp);
67
68         if (offset == 0)
69                 return SEQ_START_TOKEN;
70         offset--;
71
72         if (lqp->lqp_obj == NULL)
73                 /* accounting not enabled. */
74                 return NULL;
75
76         /* initialize iterator */
77         iops = &lqp->lqp_obj->do_index_ops->dio_it;
78         it = iops->init(&lqp->lqp_env, lqp->lqp_obj, 0, BYPASS_CAPA);
79         if (IS_ERR(it)) {
80                 CERROR("%s: failed to initialize iterator: rc = %ld\n",
81                        lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name,
82                        PTR_ERR(it));
83                 return NULL;
84         }
85
86         /* move on to the first valid record */
87         rc = iops->load(&lqp->lqp_env, it, 0);
88         if (rc < 0) { /* Error */
89                 goto not_found;
90         } else if (rc == 0) {
91                 /*
92                  * Iterator didn't find record with exactly the key requested.
93                  *
94                  * It is currently either
95                  *
96                  *     - positioned above record with key less than
97                  *       requested - skip it.
98                  *     - or not positioned at all (is in IAM_IT_SKEWED
99                  *       state) - position it on the next item.
100                  */
101                 rc = iops->next(&lqp->lqp_env, it);
102                 if (rc != 0)
103                         goto not_found;
104         }
105         while (offset--) {
106                 rc = iops->next(&lqp->lqp_env, it);
107                 if (rc != 0) /* Error or reach the end */
108                         goto not_found;
109         }
110         return it;
111
112 not_found:
113         iops->put(&lqp->lqp_env, it);
114         iops->fini(&lqp->lqp_env, it);
115         return NULL;
116 }
117
118 static void lprocfs_quota_seq_stop(struct seq_file *p, void *v)
119 {
120         struct lquota_procfs    *lqp = p->private;
121         const struct dt_it_ops  *iops;
122         struct dt_it            *it;
123
124         if (lqp->lqp_obj == NULL || v == NULL || v == SEQ_START_TOKEN)
125                 return;
126
127         iops = &lqp->lqp_obj->do_index_ops->dio_it;
128         it = (struct dt_it *)v;
129         /* if something wrong happened during ->seq_show, we need to release
130          * the iterator here */
131         iops->put(&lqp->lqp_env, it);
132         iops->fini(&lqp->lqp_env, it);
133 }
134
135 static void *lprocfs_quota_seq_next(struct seq_file *p, void *v, loff_t *pos)
136 {
137         struct lquota_procfs    *lqp = p->private;
138         const struct dt_it_ops  *iops;
139         struct dt_it            *it;
140         int                      rc;
141
142         LASSERT(lqp);
143
144         ++*pos;
145         if (lqp->lqp_obj == NULL)
146                 return NULL;
147
148         if (v == SEQ_START_TOKEN)
149                 return lprocfs_quota_seq_start(p, pos);
150
151         iops = &lqp->lqp_obj->do_index_ops->dio_it;
152         it = (struct dt_it *)v;
153
154         rc = iops->next(&lqp->lqp_env, it);
155         if (rc == 0)
156                 return it;
157
158         if (rc < 0)
159                 CERROR("%s: seq_next failed: rc = %d\n",
160                        lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name, rc);
161
162         /* Reach the end or error */
163         iops->put(&lqp->lqp_env, it);
164         iops->fini(&lqp->lqp_env, it);
165         return NULL;
166 }
167
168 /*
169  * Output example:
170  *
171  * user_accounting:
172  * - id:      0
173  *   usage:   { inodes:                  209, bytes:             26161152 }
174  * - id:      840000038
175  *   usage:   { inodes:                    1, bytes:             10485760 }
176  */
177 static int lprocfs_quota_seq_show(struct seq_file *p, void *v)
178 {
179         struct lquota_procfs    *lqp = p->private;
180         const struct dt_it_ops  *iops;
181         struct dt_it            *it;
182         struct dt_key           *key;
183         struct lquota_acct_rec   rec;
184         int                      rc;
185
186         LASSERT(lqp);
187         if (lqp->lqp_obj == NULL) {
188                 seq_printf(p, "not supported\n");
189                 return 0;
190         }
191
192         if (v == SEQ_START_TOKEN) {
193                 const struct lu_fid *fid = lu_object_fid(&lqp->lqp_obj->do_lu);
194
195                 LASSERT(fid_is_acct(fid));
196                 if (fid_oid(fid) == ACCT_USER_OID)
197                         seq_printf(p, "user_accounting:\n");
198                 else
199                         seq_printf(p, "group_accounting:\n");
200                 return 0;
201         }
202
203         iops = &lqp->lqp_obj->do_index_ops->dio_it;
204         it = (struct dt_it *)v;
205
206         key = iops->key(&lqp->lqp_env, it);
207         if (IS_ERR(key)) {
208                 CERROR("%s: failed to get key: rc = %ld\n",
209                        lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name,
210                        PTR_ERR(key));
211                 return PTR_ERR(key);
212         }
213
214         rc = iops->rec(&lqp->lqp_env, it, (struct dt_rec *)&rec, 0);
215         if (rc) {
216                 CERROR("%s: failed to get rec: rc = %d\n",
217                        lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name, rc);
218                 return rc;
219         }
220
221         seq_printf(p, "- %-8s %llu\n", "id:", *((__u64 *)key));
222         seq_printf(p, "  %-8s { inodes: %20"LPF64"u, bytes: %20"LPF64"u }\n",
223                    "usage:", rec.ispace, rec.bspace);
224         return 0;
225 }
226
227 struct seq_operations lprocfs_quota_seq_sops = {
228         .start  = lprocfs_quota_seq_start,
229         .stop   = lprocfs_quota_seq_stop,
230         .next   = lprocfs_quota_seq_next,
231         .show   = lprocfs_quota_seq_show,
232 };
233
234 static int lprocfs_quota_seq_open(struct inode *inode, struct file *file)
235 {
236         struct proc_dir_entry   *dp = PDE(inode);
237         struct seq_file         *seq;
238         int                      rc;
239         struct lquota_procfs    *lqp;
240
241         /* Allocate quota procfs data. This structure will be passed to
242          * seq_start/stop/next/show via seq->private */
243         OBD_ALLOC_PTR(lqp);
244         if (lqp == NULL)
245                 return -ENOMEM;
246
247         /* store pointer to object we would like to iterate over */
248         lqp->lqp_obj = (struct dt_object *)dp->data;
249
250         /* Initialize the common environment to be used in the seq operations */
251         rc = lu_env_init(&lqp->lqp_env, LCT_LOCAL);
252         if (rc) {
253                 CERROR("%s: error initializing procfs quota env: rc = %d\n",
254                        lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name, rc);
255                 goto out_lqp;
256         }
257
258         if (LPROCFS_ENTRY_AND_CHECK(dp)) {
259                 rc = -ENOENT;
260                 goto out_env;
261         }
262
263         rc = seq_open(file, &lprocfs_quota_seq_sops);
264         if (rc)
265                 goto out_lprocfs;
266
267         seq = file->private_data;
268         seq->private = lqp;
269         return 0;
270
271 out_lprocfs:
272         LPROCFS_EXIT();
273 out_env:
274         lu_env_fini(&lqp->lqp_env);
275 out_lqp:
276         OBD_FREE_PTR(lqp);
277         return rc;
278 }
279
280 static int lprocfs_quota_seq_release(struct inode *inode, struct file *file)
281 {
282         struct seq_file         *seq = file->private_data;
283         struct lquota_procfs    *lqp = seq->private;
284
285         LPROCFS_EXIT();
286
287         LASSERT(lqp);
288         lu_env_fini(&lqp->lqp_env);
289         OBD_FREE_PTR(lqp);
290
291         return seq_release(inode, file);
292 }
293
294 struct file_operations lprocfs_quota_seq_fops = {
295         .owner          = THIS_MODULE,
296         .open           = lprocfs_quota_seq_open,
297         .read           = seq_read,
298         .llseek         = seq_lseek,
299         .release        = lprocfs_quota_seq_release,
300 };
301
302 int lprocfs_quota_rd_type_dumb(char *page, char **start, off_t off, int count,
303                                int *eof, void *data)
304 {
305         return 0;
306 }
307 EXPORT_SYMBOL(lprocfs_quota_rd_type_dumb);
308
309 int lprocfs_quota_wr_type_dumb(struct file *file, const char *buffer,
310                                unsigned long count, void *data)
311 {
312         return count;
313 }
314 EXPORT_SYMBOL(lprocfs_quota_wr_type_dumb);
315
316 int lprocfs_quota_rd_bunit(char *page, char **start, off_t off, int count,
317                            int *eof, void *data)
318 {
319         struct obd_device *obd = (struct obd_device *)data;
320         LASSERT(obd != NULL);
321
322         return snprintf(page, count, "%lu\n",
323                         obd->u.obt.obt_qctxt.lqc_bunit_sz);
324 }
325 EXPORT_SYMBOL(lprocfs_quota_rd_bunit);
326
327 int lprocfs_quota_wr_bunit(struct file *file, const char *buffer,
328                            unsigned long count, void *data)
329 {
330         struct obd_device *obd = (struct obd_device *)data;
331         int val, rc;
332         LASSERT(obd != NULL);
333
334         rc = lprocfs_write_helper(buffer, count, &val);
335         if (rc)
336                 return rc;
337
338         if (val % QUOTABLOCK_SIZE ||
339             val <= obd->u.obt.obt_qctxt.lqc_btune_sz)
340                 return -EINVAL;
341
342         obd->u.obt.obt_qctxt.lqc_bunit_sz = val;
343         return count;
344 }
345 EXPORT_SYMBOL(lprocfs_quota_wr_bunit);
346
347 int lprocfs_quota_rd_btune(char *page, char **start, off_t off, int count,
348                            int *eof, void *data)
349 {
350         struct obd_device *obd = (struct obd_device *)data;
351         LASSERT(obd != NULL);
352
353         return snprintf(page, count, "%lu\n",
354                         obd->u.obt.obt_qctxt.lqc_btune_sz);
355 }
356 EXPORT_SYMBOL(lprocfs_quota_rd_btune);
357
358 int lprocfs_quota_wr_btune(struct file *file, const char *buffer,
359                            unsigned long count, void *data)
360 {
361         struct obd_device *obd = (struct obd_device *)data;
362         int val, rc;
363         LASSERT(obd != NULL);
364
365         rc = lprocfs_write_helper(buffer, count, &val);
366         if (rc)
367                 return rc;
368
369         if (val <= QUOTABLOCK_SIZE * MIN_QLIMIT || val % QUOTABLOCK_SIZE ||
370             val >= obd->u.obt.obt_qctxt.lqc_bunit_sz)
371                 return -EINVAL;
372
373         obd->u.obt.obt_qctxt.lqc_btune_sz = val;
374         return count;
375 }
376 EXPORT_SYMBOL(lprocfs_quota_wr_btune);
377
378 int lprocfs_quota_rd_iunit(char *page, char **start, off_t off, int count,
379                            int *eof, void *data)
380 {
381         struct obd_device *obd = (struct obd_device *)data;
382         LASSERT(obd != NULL);
383
384         return snprintf(page, count, "%lu\n",
385                         obd->u.obt.obt_qctxt.lqc_iunit_sz);
386 }
387 EXPORT_SYMBOL(lprocfs_quota_rd_iunit);
388
389 int lprocfs_quota_wr_iunit(struct file *file, const char *buffer,
390                            unsigned long count, void *data)
391 {
392         struct obd_device *obd = (struct obd_device *)data;
393         int val, rc;
394         LASSERT(obd != NULL);
395
396         rc = lprocfs_write_helper(buffer, count, &val);
397         if (rc)
398                 return rc;
399
400         if (val <= obd->u.obt.obt_qctxt.lqc_itune_sz)
401                 return -EINVAL;
402
403         obd->u.obt.obt_qctxt.lqc_iunit_sz = val;
404         return count;
405 }
406 EXPORT_SYMBOL(lprocfs_quota_wr_iunit);
407
408 int lprocfs_quota_rd_itune(char *page, char **start, off_t off, int count,
409                            int *eof, void *data)
410 {
411         struct obd_device *obd = (struct obd_device *)data;
412         LASSERT(obd != NULL);
413
414         return snprintf(page, count, "%lu\n",
415                         obd->u.obt.obt_qctxt.lqc_itune_sz);
416 }
417 EXPORT_SYMBOL(lprocfs_quota_rd_itune);
418
419 int lprocfs_quota_wr_itune(struct file *file, const char *buffer,
420                            unsigned long count, void *data)
421 {
422         struct obd_device *obd = (struct obd_device *)data;
423         int val, rc;
424         LASSERT(obd != NULL);
425
426         rc = lprocfs_write_helper(buffer, count, &val);
427         if (rc)
428                 return rc;
429
430         if (val <= MIN_QLIMIT ||
431             val >= obd->u.obt.obt_qctxt.lqc_iunit_sz)
432                 return -EINVAL;
433
434         obd->u.obt.obt_qctxt.lqc_itune_sz = val;
435         return count;
436 }
437 EXPORT_SYMBOL(lprocfs_quota_wr_itune);
438
439 #define USER_QUOTA      1
440 #define GROUP_QUOTA     2
441
442 #define MAX_STYPE_SIZE  5
443
444 int lprocfs_quota_rd_type(char *page, char **start, off_t off, int count,
445                           int *eof, void *data)
446 {
447         struct obd_device *obd = (struct obd_device *)data;
448         char stype[MAX_STYPE_SIZE + 1] = "";
449         int oq_type;
450
451         LASSERT(obd != NULL);
452
453         /* Collect the needed information */
454         oq_type = obd->u.obt.obt_qctxt.lqc_flags;
455
456         /* Transform the collected data into a user-readable string */
457         if (oq_type & LQC_USRQUOTA_FLAG)
458                 strcat(stype, "u");
459         if (oq_type & LQC_GRPQUOTA_FLAG)
460                 strcat(stype, "g");
461
462         strcat(stype, "3");
463
464         return snprintf(page, count, "%s\n", stype);
465 }
466 EXPORT_SYMBOL(lprocfs_quota_rd_type);
467
468 /*
469  * generic_quota_on is very lazy and tolerant about current quota settings
470  * @global means to turn on quotas on each OST additionally to local quotas;
471  * should not be called from filter_quota_ctl on MDS nodes (as it starts
472  * admin quotas on MDS nodes).
473  */
474 int generic_quota_on(struct obd_device *obd, struct obd_quotactl *oqctl, int global)
475 {
476         struct obd_device_target *obt = &obd->u.obt;
477         struct lvfs_run_ctxt saved;
478         int id, is_master, rc = 0, local; /* means we need a local quotaon */
479
480         cfs_down(&obt->obt_quotachecking);
481         push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
482         id = UGQUOTA2LQC(oqctl->qc_type);
483         local = (obt->obt_qctxt.lqc_flags & id) != id;
484
485         oqctl->qc_cmd = Q_QUOTAON;
486         oqctl->qc_id = obt->obt_qfmt;
487
488         is_master = !strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME);
489         if (is_master) {
490                 cfs_down_write(&obd->u.mds.mds_qonoff_sem);
491                 if (local) {
492                         /* turn on cluster wide quota */
493                         rc = mds_admin_quota_on(obd, oqctl);
494                         if (rc && rc != -ENOENT)
495                                 CERROR("%s: %s admin quotaon failed. rc=%d\n",
496                                        obd->obd_name, global ? "global":"local",
497                                        rc);
498                 }
499         }
500
501         if (rc == 0) {
502                 if (local) {
503                         rc = fsfilt_quotactl(obd, obt->obt_sb, oqctl);
504                         if (rc) {
505                                 if (rc != -ENOENT)
506                                         CERROR("%s: %s quotaon failed with"
507                                                " rc=%d\n", obd->obd_name,
508                                                global ? "global" : "local", rc);
509                         } else {
510                                 obt->obt_qctxt.lqc_flags |= UGQUOTA2LQC(oqctl->qc_type);
511                                 build_lqs(obd);
512                         }
513                 }
514
515                 if (rc == 0 && global && is_master)
516                         rc = obd_quotactl(obd->u.mds.mds_lov_exp, oqctl);
517         }
518
519         if (is_master)
520                 cfs_up_write(&obd->u.mds.mds_qonoff_sem);
521
522         pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
523         cfs_up(&obt->obt_quotachecking);
524
525         CDEBUG(D_QUOTA, "%s: quotaon type:master:global:local:flags:rc "
526                "%u:%d:%d:%d:%lu:%d\n",
527                obd->obd_name, oqctl->qc_type, is_master, global, local,
528                obt->obt_qctxt.lqc_flags, rc);
529
530         return rc;
531 }
532
533 static int auto_quota_on(struct obd_device *obd, int type)
534 {
535         struct obd_quotactl *oqctl;
536         int rc;
537         ENTRY;
538
539         LASSERT(type == USRQUOTA || type == GRPQUOTA || type == UGQUOTA);
540
541         OBD_ALLOC_PTR(oqctl);
542         if (!oqctl)
543                 RETURN(-ENOMEM);
544
545         oqctl->qc_type = type;
546
547         rc = generic_quota_on(obd, oqctl, 0);
548
549         OBD_FREE_PTR(oqctl);
550         RETURN(rc);
551 }
552
553 int lprocfs_quota_wr_type(struct file *file, const char *buffer,
554                           unsigned long count, void *data)
555 {
556         struct obd_device *obd = (struct obd_device *)data;
557         int type = 0;
558         unsigned long i;
559         char stype[MAX_STYPE_SIZE + 1] = "";
560
561         LASSERT(obd != NULL);
562
563         if (count > MAX_STYPE_SIZE)
564                 return -EINVAL;
565
566         if (cfs_copy_from_user(stype, buffer, count))
567                 return -EFAULT;
568
569         for (i = 0 ; i < count ; i++) {
570                 switch (stype[i]) {
571                 case 'u' :
572                         type |= USER_QUOTA;
573                         break;
574                 case 'g' :
575                         type |= GROUP_QUOTA;
576                         break;
577                 case '1' :
578                 case '2' :
579                         CWARN("quota_type options 1 and 2 are obsolete, "
580                               "they will be ignored\n");
581                         break;
582                 case '3' : /* the only valid version spec, do nothing */
583                 default  : /* just skip stray symbols like \n */
584                         break;
585                 }
586         }
587
588         if (type != 0) {
589                 int rc = auto_quota_on(obd, type - 1);
590
591                 if (rc && rc != -EALREADY && rc != -ENOENT)
592                         return rc;
593         }
594
595         return count;
596 }
597 EXPORT_SYMBOL(lprocfs_quota_wr_type);
598
599 int lprocfs_quota_rd_switch_seconds(char *page, char **start, off_t off,
600                                     int count, int *eof, void *data)
601 {
602         struct obd_device *obd = (struct obd_device *)data;
603         LASSERT(obd != NULL);
604
605         return snprintf(page, count, "%d\n",
606                         obd->u.obt.obt_qctxt.lqc_switch_seconds);
607 }
608 EXPORT_SYMBOL(lprocfs_quota_rd_switch_seconds);
609
610 int lprocfs_quota_wr_switch_seconds(struct file *file, const char *buffer,
611                                     unsigned long count, void *data)
612 {
613         struct obd_device *obd = (struct obd_device *)data;
614         int val, rc;
615         LASSERT(obd != NULL);
616
617         rc = lprocfs_write_helper(buffer, count, &val);
618         if (rc)
619                 return rc;
620
621         if (val <= 10)
622                 return -EINVAL;
623
624         obd->u.obt.obt_qctxt.lqc_switch_seconds = val;
625         return count;
626 }
627 EXPORT_SYMBOL(lprocfs_quota_wr_switch_seconds);
628
629 int lprocfs_quota_rd_sync_blk(char *page, char **start, off_t off,
630                               int count, int *eof, void *data)
631 {
632         struct obd_device *obd = (struct obd_device *)data;
633         LASSERT(obd != NULL);
634
635         return snprintf(page, count, "%d\n",
636                         obd->u.obt.obt_qctxt.lqc_sync_blk);
637 }
638 EXPORT_SYMBOL(lprocfs_quota_rd_sync_blk);
639
640 int lprocfs_quota_wr_sync_blk(struct file *file, const char *buffer,
641                               unsigned long count, void *data)
642 {
643         struct obd_device *obd = (struct obd_device *)data;
644         int val, rc;
645         LASSERT(obd != NULL);
646
647         rc = lprocfs_write_helper(buffer, count, &val);
648         if (rc)
649                 return rc;
650
651         if (val < 0)
652                 return -EINVAL;
653
654         obd->u.obt.obt_qctxt.lqc_sync_blk = val;
655         return count;
656 }
657 EXPORT_SYMBOL(lprocfs_quota_wr_sync_blk);
658
659 int lprocfs_quota_rd_switch_qs(char *page, char **start, off_t off,
660                                int count, int *eof, void *data)
661 {
662         struct obd_device *obd = (struct obd_device *)data;
663         LASSERT(obd != NULL);
664
665         return snprintf(page, count, "changing qunit size is %s\n",
666                         obd->u.obt.obt_qctxt.lqc_switch_qs ?
667                         "enabled" : "disabled");
668 }
669 EXPORT_SYMBOL(lprocfs_quota_rd_switch_qs);
670
671 int lprocfs_quota_wr_switch_qs(struct file *file, const char *buffer,
672                                unsigned long count, void *data)
673 {
674         struct obd_device *obd = (struct obd_device *)data;
675         int val, rc;
676         LASSERT(obd != NULL);
677
678         rc = lprocfs_write_helper(buffer, count, &val);
679         if (rc)
680                 return rc;
681
682         if (val)
683             obd->u.obt.obt_qctxt.lqc_switch_qs = 1;
684         else
685             obd->u.obt.obt_qctxt.lqc_switch_qs = 0;
686
687         return count;
688 }
689 EXPORT_SYMBOL(lprocfs_quota_wr_switch_qs);
690
691 int lprocfs_quota_rd_boundary_factor(char *page, char **start, off_t off,
692                                      int count, int *eof, void *data)
693 {
694         struct obd_device *obd = (struct obd_device *)data;
695         LASSERT(obd != NULL);
696
697
698         return snprintf(page, count, "%lu\n",
699                         obd->u.obt.obt_qctxt.lqc_cqs_boundary_factor);
700 }
701 EXPORT_SYMBOL(lprocfs_quota_rd_boundary_factor);
702
703 int lprocfs_quota_wr_boundary_factor(struct file *file, const char *buffer,
704                                      unsigned long count, void *data)
705 {
706         struct obd_device *obd = (struct obd_device *)data;
707         int val, rc;
708         LASSERT(obd != NULL);
709
710         rc = lprocfs_write_helper(buffer, count, &val);
711         if (rc)
712                 return rc;
713
714         if (val < 2)
715                 return -EINVAL;
716
717         obd->u.obt.obt_qctxt.lqc_cqs_boundary_factor = val;
718         return count;
719 }
720 EXPORT_SYMBOL(lprocfs_quota_wr_boundary_factor);
721
722 int lprocfs_quota_rd_least_bunit(char *page, char **start, off_t off,
723                                  int count, int *eof, void *data)
724 {
725         struct obd_device *obd = (struct obd_device *)data;
726         LASSERT(obd != NULL);
727
728
729         return snprintf(page, count, "%lu\n",
730                         obd->u.obt.obt_qctxt.lqc_cqs_least_bunit);
731 }
732 EXPORT_SYMBOL(lprocfs_quota_rd_least_bunit);
733
734 int lprocfs_quota_wr_least_bunit(struct file *file, const char *buffer,
735                                  unsigned long count, void *data)
736 {
737         struct obd_device *obd = (struct obd_device *)data;
738         int val, rc;
739         LASSERT(obd != NULL);
740
741         rc = lprocfs_write_helper(buffer, count, &val);
742         if (rc)
743                 return rc;
744
745         if (val < PTLRPC_MAX_BRW_SIZE ||
746             val >= obd->u.obt.obt_qctxt.lqc_bunit_sz)
747                 return -EINVAL;
748
749         obd->u.obt.obt_qctxt.lqc_cqs_least_bunit = val;
750         return count;
751 }
752 EXPORT_SYMBOL(lprocfs_quota_wr_least_bunit);
753
754 int lprocfs_quota_rd_least_iunit(char *page, char **start, off_t off,
755                                  int count, int *eof, void *data)
756 {
757         struct obd_device *obd = (struct obd_device *)data;
758         LASSERT(obd != NULL);
759
760
761         return snprintf(page, count, "%lu\n",
762                         obd->u.obt.obt_qctxt.lqc_cqs_least_iunit);
763 }
764 EXPORT_SYMBOL(lprocfs_quota_rd_least_iunit);
765
766 int lprocfs_quota_wr_least_iunit(struct file *file, const char *buffer,
767                                  unsigned long count, void *data)
768 {
769         struct obd_device *obd = (struct obd_device *)data;
770         int val, rc;
771         LASSERT(obd != NULL);
772
773         rc = lprocfs_write_helper(buffer, count, &val);
774         if (rc)
775                 return rc;
776
777         if (val < 1 || val >= obd->u.obt.obt_qctxt.lqc_iunit_sz)
778                 return -EINVAL;
779
780         obd->u.obt.obt_qctxt.lqc_cqs_least_iunit = val;
781         return count;
782 }
783 EXPORT_SYMBOL(lprocfs_quota_wr_least_iunit);
784
785 int lprocfs_quota_rd_qs_factor(char *page, char **start, off_t off,
786                                int count, int *eof, void *data)
787 {
788         struct obd_device *obd = (struct obd_device *)data;
789         LASSERT(obd != NULL);
790
791
792         return snprintf(page, count, "%lu\n",
793                         obd->u.obt.obt_qctxt.lqc_cqs_qs_factor);
794 }
795 EXPORT_SYMBOL(lprocfs_quota_rd_qs_factor);
796
797 int lprocfs_quota_wr_qs_factor(struct file *file, const char *buffer,
798                                unsigned long count, void *data)
799 {
800         struct obd_device *obd = (struct obd_device *)data;
801         int val, rc;
802         LASSERT(obd != NULL);
803
804         rc = lprocfs_write_helper(buffer, count, &val);
805         if (rc)
806                 return rc;
807
808         if (val < 2)
809                 return -EINVAL;
810
811         obd->u.obt.obt_qctxt.lqc_cqs_qs_factor = val;
812         return count;
813 }
814 EXPORT_SYMBOL(lprocfs_quota_wr_qs_factor);
815
816 struct lprocfs_vars lprocfs_quota_common_vars[] = {
817         { "quota_bunit_sz", lprocfs_quota_rd_bunit,
818                             lprocfs_quota_wr_bunit, 0},
819         { "quota_btune_sz", lprocfs_quota_rd_btune,
820                             lprocfs_quota_wr_btune, 0},
821         { "quota_iunit_sz", lprocfs_quota_rd_iunit,
822                             lprocfs_quota_wr_iunit, 0},
823         { "quota_itune_sz", lprocfs_quota_rd_itune,
824                             lprocfs_quota_wr_itune, 0},
825         { "quota_type",     lprocfs_quota_rd_type,
826                             lprocfs_quota_wr_type, 0},
827         { "quota_switch_seconds",  lprocfs_quota_rd_switch_seconds,
828                                    lprocfs_quota_wr_switch_seconds, 0 },
829         { "quota_sync_blk", lprocfs_quota_rd_sync_blk,
830                             lprocfs_quota_wr_sync_blk, 0},
831         { NULL }
832 };
833
834 struct lprocfs_vars lprocfs_quota_master_vars[] = {
835         { "quota_switch_qs", lprocfs_quota_rd_switch_qs,
836                              lprocfs_quota_wr_switch_qs, 0 },
837         { "quota_boundary_factor", lprocfs_quota_rd_boundary_factor,
838                                    lprocfs_quota_wr_boundary_factor, 0 },
839         { "quota_least_bunit", lprocfs_quota_rd_least_bunit,
840                                lprocfs_quota_wr_least_bunit, 0 },
841         { "quota_least_iunit", lprocfs_quota_rd_least_iunit,
842                                lprocfs_quota_wr_least_iunit, 0 },
843         { "quota_qs_factor",   lprocfs_quota_rd_qs_factor,
844                                lprocfs_quota_wr_qs_factor, 0 },
845         { NULL }
846 };
847
848 int lquota_proc_setup(struct obd_device *obd, int is_master)
849 {
850         struct lustre_quota_ctxt *qctxt = &obd->u.obt.obt_qctxt;
851         int rc = 0;
852         ENTRY;
853
854         LASSERT(lquota_type_proc_dir && obd);
855         qctxt->lqc_proc_dir = lprocfs_register(obd->obd_name,
856                                                lquota_type_proc_dir,
857                                                lprocfs_quota_common_vars, obd);
858         if (IS_ERR(qctxt->lqc_proc_dir)) {
859                 rc = PTR_ERR(qctxt->lqc_proc_dir);
860                 CERROR("%s: error %d setting up lprocfs\n",
861                        obd->obd_name, rc);
862                 qctxt->lqc_proc_dir = NULL;
863                 GOTO(out, rc);
864         }
865
866         if (is_master) {
867                 rc = lprocfs_add_vars(qctxt->lqc_proc_dir,
868                                       lprocfs_quota_master_vars, obd);
869                 if (rc) {
870                         CERROR("%s: error %d setting up lprocfs for "
871                                "quota master\n", obd->obd_name, rc);
872                         GOTO(out_free_proc, rc);
873                 }
874         }
875
876         qctxt->lqc_stats = lprocfs_alloc_stats(LQUOTA_LAST_STAT -
877                                                LQUOTA_FIRST_STAT, 0);
878         if (!qctxt->lqc_stats)
879                 GOTO(out_free_proc, rc = -ENOMEM);
880
881         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_SYNC_ACQ,
882                              LPROCFS_CNTR_AVGMINMAX, "sync_acq_req", "us");
883         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_SYNC_REL,
884                              LPROCFS_CNTR_AVGMINMAX, "sync_rel_req", "us");
885         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_ASYNC_ACQ,
886                              LPROCFS_CNTR_AVGMINMAX, "async_acq_req", "us");
887         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_ASYNC_REL,
888                              LPROCFS_CNTR_AVGMINMAX, "async_rel_req", "us");
889
890         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_FOR_CHK_BLK,
891                              LPROCFS_CNTR_AVGMINMAX,
892                              "wait_for_blk_quota(lquota_chkquota)", "us");
893         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_FOR_CHK_INO,
894                              LPROCFS_CNTR_AVGMINMAX,
895                              "wait_for_ino_quota(lquota_chkquota)", "us");
896         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_FOR_COMMIT_BLK,
897                              LPROCFS_CNTR_AVGMINMAX,
898                              "wait_for_blk_quota(lquota_pending_commit)",
899                              "us");
900         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_FOR_COMMIT_INO,
901                              LPROCFS_CNTR_AVGMINMAX,
902                              "wait_for_ino_quota(lquota_pending_commit)",
903                              "us");
904
905         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_PENDING_BLK_QUOTA,
906                              LPROCFS_CNTR_AVGMINMAX,
907                              "wait_for_pending_blk_quota_req"
908                              "(qctxt_wait_pending_dqacq)", "us");
909         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_PENDING_INO_QUOTA,
910                              LPROCFS_CNTR_AVGMINMAX,
911                              "wait_for_pending_ino_quota_req"
912                              "(qctxt_wait_pending_dqacq)", "us");
913         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_NOWAIT_PENDING_BLK_QUOTA,
914                              LPROCFS_CNTR_AVGMINMAX,
915                              "nowait_for_pending_blk_quota_req"
916                              "(qctxt_wait_pending_dqacq)", "us");
917         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_NOWAIT_PENDING_INO_QUOTA,
918                              LPROCFS_CNTR_AVGMINMAX,
919                              "nowait_for_pending_ino_quota_req"
920                              "(qctxt_wait_pending_dqacq)", "us");
921
922         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_QUOTA_CTL,
923                              LPROCFS_CNTR_AVGMINMAX, "quota_ctl", "us");
924         lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_ADJUST_QUNIT,
925                              LPROCFS_CNTR_AVGMINMAX, "adjust_qunit", "us");
926
927         lprocfs_register_stats(qctxt->lqc_proc_dir, "stats", qctxt->lqc_stats);
928
929         RETURN(rc);
930
931 out_free_proc:
932         lprocfs_remove(&qctxt->lqc_proc_dir);
933 out:
934         RETURN(rc);
935 }
936
937 int lquota_proc_cleanup(struct lustre_quota_ctxt *qctxt)
938 {
939         if (!qctxt || !qctxt->lqc_proc_dir)
940                 return -EINVAL;
941
942         if (qctxt->lqc_stats != NULL)
943                  lprocfs_free_stats(&qctxt->lqc_stats);
944
945         lprocfs_remove(&qctxt->lqc_proc_dir);
946         return 0;
947 }
948
949 #endif  /* LPROCFS */