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