Whamcloud - gitweb
038abf680f8316bf4391b7e3022fbfc4b4738bb6
[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, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 021110-1307, USA
20  *
21  * GPL HEADER END
22  */
23 /*
24  * Copyright (c) 2011, 2012, Intel Corporation.
25  * Use is subject to license terms.
26  *
27  * Author: Johann Lombardi <johann.lombardi@intel.com>
28  * Author: Niu    Yawei    <yawei.niu@intel.com>
29  */
30
31 #define DEBUG_SUBSYSTEM S_LQUOTA
32
33 #include <linux/version.h>
34 #include <lprocfs_status.h>
35 #include <obd.h>
36 #include <linux/seq_file.h>
37 #include <lustre_fsfilt.h>
38
39 #include "lquota_internal.h"
40
41 #ifdef LPROCFS
42 /* structure allocated at seq_open time and release when seq_release is called.
43  * It is passed to seq_start/stop/next/show which can thus use the same lu_env
44  * to be used with the iterator API */
45 struct lquota_procfs {
46         struct dt_object        *lqp_obj;
47         struct lu_env            lqp_env;
48 };
49
50 /* global shared environment */
51 static void *lprocfs_quota_seq_start(struct seq_file *p, loff_t *pos)
52 {
53         struct lquota_procfs    *lqp = p->private;
54         const struct dt_it_ops  *iops;
55         struct dt_it            *it;
56         loff_t                   offset = *pos;
57         int                      rc;
58
59         LASSERT(lqp);
60
61         if (offset == 0)
62                 return SEQ_START_TOKEN;
63         offset--;
64
65         if (lqp->lqp_obj == NULL)
66                 /* accounting not enabled. */
67                 return NULL;
68
69         /* initialize iterator */
70         iops = &lqp->lqp_obj->do_index_ops->dio_it;
71         it = iops->init(&lqp->lqp_env, lqp->lqp_obj, 0, BYPASS_CAPA);
72         if (IS_ERR(it)) {
73                 CERROR("%s: failed to initialize iterator: rc = %ld\n",
74                        lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name,
75                        PTR_ERR(it));
76                 return NULL;
77         }
78
79         /* move on to the first valid record */
80         rc = iops->load(&lqp->lqp_env, it, 0);
81         if (rc < 0) { /* Error */
82                 goto not_found;
83         } else if (rc == 0) {
84                 /*
85                  * Iterator didn't find record with exactly the key requested.
86                  *
87                  * It is currently either
88                  *
89                  *     - positioned above record with key less than
90                  *       requested - skip it.
91                  *     - or not positioned at all (is in IAM_IT_SKEWED
92                  *       state) - position it on the next item.
93                  */
94                 rc = iops->next(&lqp->lqp_env, it);
95                 if (rc != 0)
96                         goto not_found;
97         }
98         while (offset--) {
99                 rc = iops->next(&lqp->lqp_env, it);
100                 if (rc != 0) /* Error or reach the end */
101                         goto not_found;
102         }
103         return it;
104
105 not_found:
106         iops->put(&lqp->lqp_env, it);
107         iops->fini(&lqp->lqp_env, it);
108         return NULL;
109 }
110
111 static void lprocfs_quota_seq_stop(struct seq_file *p, void *v)
112 {
113         struct lquota_procfs    *lqp = p->private;
114         const struct dt_it_ops  *iops;
115         struct dt_it            *it;
116
117         if (lqp->lqp_obj == NULL || v == NULL || v == SEQ_START_TOKEN)
118                 return;
119
120         iops = &lqp->lqp_obj->do_index_ops->dio_it;
121         it = (struct dt_it *)v;
122         /* if something wrong happened during ->seq_show, we need to release
123          * the iterator here */
124         iops->put(&lqp->lqp_env, it);
125         iops->fini(&lqp->lqp_env, it);
126 }
127
128 static void *lprocfs_quota_seq_next(struct seq_file *p, void *v, loff_t *pos)
129 {
130         struct lquota_procfs    *lqp = p->private;
131         const struct dt_it_ops  *iops;
132         struct dt_it            *it;
133         int                      rc;
134
135         LASSERT(lqp);
136
137         ++*pos;
138         if (lqp->lqp_obj == NULL)
139                 return NULL;
140
141         if (v == SEQ_START_TOKEN)
142                 return lprocfs_quota_seq_start(p, pos);
143
144         iops = &lqp->lqp_obj->do_index_ops->dio_it;
145         it = (struct dt_it *)v;
146
147         rc = iops->next(&lqp->lqp_env, it);
148         if (rc == 0)
149                 return it;
150
151         if (rc < 0)
152                 CERROR("%s: seq_next failed: rc = %d\n",
153                        lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name, rc);
154
155         /* Reach the end or error */
156         iops->put(&lqp->lqp_env, it);
157         iops->fini(&lqp->lqp_env, it);
158         return NULL;
159 }
160
161 /*
162  * Output example:
163  *
164  * usr_accounting:
165  * - id:      0
166  *   usage:   { inodes:                  209, kbytes:             2616 }
167  * - id:      840000038
168  *   usage:   { inodes:                    1, kbytes:             1048 }
169  */
170 static int lprocfs_quota_seq_show(struct seq_file *p, void *v)
171 {
172         struct lquota_procfs            *lqp = p->private;
173         struct lquota_thread_info       *qti = lquota_info(&lqp->lqp_env);
174         const struct dt_it_ops          *iops;
175         struct dt_it                    *it;
176         struct dt_key                   *key;
177         struct dt_rec                   *rec = (struct dt_rec *)&qti->qti_rec;
178         const struct lu_fid             *fid;
179         int                              rc;
180
181         LASSERT(lqp);
182         if (lqp->lqp_obj == NULL) {
183                 seq_printf(p, "not supported\n");
184                 return 0;
185         }
186
187         fid = lu_object_fid(&lqp->lqp_obj->do_lu);
188
189         if (v == SEQ_START_TOKEN) {
190                 if (fid_is_acct(fid)) {
191                         if (fid_oid(fid) == ACCT_USER_OID)
192                                 seq_printf(p, "usr_accounting:\n");
193                         else
194                                 seq_printf(p, "grp_accounting:\n");
195                 } else if (fid_seq(fid) == FID_SEQ_QUOTA_GLB) {
196                         int     poolid, rtype, qtype;
197
198                         rc = lquota_extract_fid(fid, &poolid, &rtype, &qtype);
199                         if (rc)
200                                 return rc;
201
202                         seq_printf(p, "global_pool%d_%s_%s\n", poolid,
203                                    RES_NAME(rtype), QTYPE_NAME(qtype));
204                 } else if (fid_seq(fid) == FID_SEQ_LOCAL_NAME) {
205                         /* global index copy object */
206                         seq_printf(p, "global_index_copy:\n");
207                 } else {
208                         return -ENOTSUPP;
209                 }
210                 return 0;
211         }
212
213         iops = &lqp->lqp_obj->do_index_ops->dio_it;
214         it = (struct dt_it *)v;
215
216         key = iops->key(&lqp->lqp_env, it);
217         if (IS_ERR(key)) {
218                 CERROR("%s: failed to get key: rc = %ld\n",
219                        lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name,
220                        PTR_ERR(key));
221                 return PTR_ERR(key);
222         }
223
224         rc = iops->rec(&lqp->lqp_env, it, rec, 0);
225         if (rc) {
226                 CERROR("%s: failed to get rec: rc = %d\n",
227                        lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name, rc);
228                 return rc;
229         }
230
231         seq_printf(p, "- %-8s %llu\n", "id:", *((__u64 *)key));
232         if (fid_is_acct(fid))
233                 seq_printf(p, "  %-8s { inodes: %20"LPF64"u, kbytes: %20"LPF64
234                            "u }\n", "usage:",
235                            ((struct lquota_acct_rec *)rec)->ispace,
236                            toqb(((struct lquota_acct_rec *)rec)->bspace));
237         else if (fid_seq(fid) == FID_SEQ_QUOTA_GLB ||
238                  fid_seq(fid) == FID_SEQ_LOCAL_NAME)
239                 seq_printf(p, "  %-8s { hard: %20"LPF64"u, soft: %20"LPF64
240                            "u, granted: %20"LPF64"u, time: %20"LPF64"u }\n",
241                            "limits:",
242                            ((struct lquota_glb_rec *)rec)->qbr_hardlimit,
243                            ((struct lquota_glb_rec *)rec)->qbr_softlimit,
244                            ((struct lquota_glb_rec *)rec)->qbr_granted,
245                            ((struct lquota_glb_rec *)rec)->qbr_time);
246         return 0;
247 }
248
249 struct seq_operations lprocfs_quota_seq_sops = {
250         .start  = lprocfs_quota_seq_start,
251         .stop   = lprocfs_quota_seq_stop,
252         .next   = lprocfs_quota_seq_next,
253         .show   = lprocfs_quota_seq_show,
254 };
255
256 static int lprocfs_quota_seq_open(struct inode *inode, struct file *file)
257 {
258         struct proc_dir_entry   *dp = PDE(inode);
259         struct seq_file         *seq;
260         int                      rc;
261         struct lquota_procfs    *lqp;
262
263         /* Allocate quota procfs data. This structure will be passed to
264          * seq_start/stop/next/show via seq->private */
265         OBD_ALLOC_PTR(lqp);
266         if (lqp == NULL)
267                 return -ENOMEM;
268
269         /* store pointer to object we would like to iterate over */
270         lqp->lqp_obj = (struct dt_object *)dp->data;
271
272         /* Initialize the common environment to be used in the seq operations */
273         rc = lu_env_init(&lqp->lqp_env, LCT_LOCAL);
274         if (rc) {
275                 CERROR("%s: error initializing procfs quota env: rc = %d\n",
276                        lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name, rc);
277                 goto out_lqp;
278         }
279
280         if (LPROCFS_ENTRY_AND_CHECK(dp)) {
281                 rc = -ENOENT;
282                 goto out_env;
283         }
284
285         rc = seq_open(file, &lprocfs_quota_seq_sops);
286         if (rc)
287                 goto out_lprocfs;
288
289         seq = file->private_data;
290         seq->private = lqp;
291         return 0;
292
293 out_lprocfs:
294         LPROCFS_EXIT();
295 out_env:
296         lu_env_fini(&lqp->lqp_env);
297 out_lqp:
298         OBD_FREE_PTR(lqp);
299         return rc;
300 }
301
302 static int lprocfs_quota_seq_release(struct inode *inode, struct file *file)
303 {
304         struct seq_file         *seq = file->private_data;
305         struct lquota_procfs    *lqp = seq->private;
306
307         LPROCFS_EXIT();
308
309         LASSERT(lqp);
310         lu_env_fini(&lqp->lqp_env);
311         OBD_FREE_PTR(lqp);
312
313         return seq_release(inode, file);
314 }
315
316 struct file_operations lprocfs_quota_seq_fops = {
317         .owner          = THIS_MODULE,
318         .open           = lprocfs_quota_seq_open,
319         .read           = seq_read,
320         .llseek         = seq_lseek,
321         .release        = lprocfs_quota_seq_release,
322 };
323 #endif  /* LPROCFS */