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