4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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
24 * Copyright (c) 2011, 2015, Intel Corporation.
25 * Use is subject to license terms.
27 * Author: Johann Lombardi <johann.lombardi@intel.com>
28 * Author: Niu Yawei <yawei.niu@intel.com>
31 #define DEBUG_SUBSYSTEM S_LQUOTA
33 #include <linux/version.h>
34 #include <lprocfs_status.h>
36 #include <linux/seq_file.h>
37 #include "lquota_internal.h"
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;
48 __u64 lqp_first_cookie;
51 /* global shared environment */
52 static void *lprocfs_quota_seq_start(struct seq_file *p, loff_t *pos)
54 struct lquota_procfs *lqp = p->private;
55 const struct dt_it_ops *iops;
63 return SEQ_START_TOKEN;
65 if (lqp->lqp_obj == NULL)
66 /* accounting not enabled. */
69 if (lqp->lqp_it == NULL) /* reach the end */
73 /* move on to the the last processed entry */
74 iops = &lqp->lqp_obj->do_index_ops->dio_it;
76 rc = iops->load(&lqp->lqp_env, it, lqp->lqp_cookie);
77 if (rc == 0 && offset == 0) {
79 * Iterator didn't find record with exactly the key requested.
81 * It is currently either
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.
88 rc = iops->next(&lqp->lqp_env, it);
91 lqp->lqp_cookie = iops->store(&lqp->lqp_env, it);
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. */
100 lqp->lqp_first_cookie = lqp->lqp_cookie;
101 else if (lqp->lqp_cookie == lqp->lqp_first_cookie)
107 iops->put(&lqp->lqp_env, it);
108 iops->fini(&lqp->lqp_env, it);
113 static void lprocfs_quota_seq_stop(struct seq_file *p, void *v)
115 struct lquota_procfs *lqp = p->private;
116 const struct dt_it_ops *iops;
119 if (lqp->lqp_obj == NULL || v == NULL || v == SEQ_START_TOKEN)
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);
129 static void *lprocfs_quota_seq_next(struct seq_file *p, void *v, loff_t *pos)
131 struct lquota_procfs *lqp = p->private;
132 const struct dt_it_ops *iops;
139 if (lqp->lqp_obj == NULL)
142 if (v == SEQ_START_TOKEN)
143 return lprocfs_quota_seq_start(p, pos);
145 if (lqp->lqp_it == NULL) /* reach the end */
148 iops = &lqp->lqp_obj->do_index_ops->dio_it;
149 it = (struct dt_it *)v;
151 rc = iops->next(&lqp->lqp_env, it);
153 lqp->lqp_cookie = iops->store(&lqp->lqp_env, it);
158 CERROR("%s: seq_next failed: rc = %d\n",
159 lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name, rc);
161 /* Reach the end or error */
162 iops->put(&lqp->lqp_env, it);
163 iops->fini(&lqp->lqp_env, it);
168 static inline const char *oid2name(__u32 oid)
172 return "usr_accounting";
174 return "grp_accounting";
176 return "unknown_accounting";
185 * usage: { inodes: 209, kbytes: 2616 }
187 * usage: { inodes: 1, kbytes: 1048 }
189 static int lprocfs_quota_seq_show(struct seq_file *p, void *v)
191 struct lquota_procfs *lqp = p->private;
192 struct lquota_thread_info *qti = lquota_info(&lqp->lqp_env);
193 const struct dt_it_ops *iops;
196 struct dt_rec *rec = (struct dt_rec *)&qti->qti_rec;
197 const struct lu_fid *fid;
201 if (lqp->lqp_obj == NULL) {
202 seq_printf(p, "not supported\n");
206 fid = lu_object_fid(&lqp->lqp_obj->do_lu);
208 if (v == SEQ_START_TOKEN) {
209 if (fid_is_acct(fid)) {
210 seq_printf(p, "%s:\n", oid2name(fid_oid(fid)));
211 } else if (fid_seq(fid) == FID_SEQ_QUOTA_GLB) {
212 int poolid, rtype, qtype;
214 rc = lquota_extract_fid(fid, &poolid, &rtype, &qtype);
218 seq_printf(p, "global_pool%d_%s_%s\n", poolid,
219 RES_NAME(rtype), qtype_name(qtype));
220 } else if (fid_seq(fid) == FID_SEQ_LOCAL_NAME) {
221 /* global index copy object */
222 seq_printf(p, "global_index_copy:\n");
229 iops = &lqp->lqp_obj->do_index_ops->dio_it;
230 it = (struct dt_it *)v;
232 key = iops->key(&lqp->lqp_env, it);
234 CERROR("%s: failed to get key: rc = %ld\n",
235 lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name,
240 rc = iops->rec(&lqp->lqp_env, it, rec, 0);
242 CERROR("%s: failed to get rec: rc = %d\n",
243 lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name, rc);
247 seq_printf(p, "- %-8s %llu\n", "id:", *((__u64 *)key));
248 if (fid_is_acct(fid))
249 seq_printf(p, " %-8s { inodes: %20llu, kbytes: %20llu }\n", "usage:",
250 ((struct lquota_acct_rec *)rec)->ispace,
251 toqb(((struct lquota_acct_rec *)rec)->bspace));
252 else if (fid_seq(fid) == FID_SEQ_QUOTA_GLB ||
253 fid_seq(fid) == FID_SEQ_LOCAL_NAME)
254 seq_printf(p, " %-8s { hard: %20llu, soft: %20llu, granted: %20llu, time: %20llu }\n",
256 ((struct lquota_glb_rec *)rec)->qbr_hardlimit,
257 ((struct lquota_glb_rec *)rec)->qbr_softlimit,
258 ((struct lquota_glb_rec *)rec)->qbr_granted,
259 ((struct lquota_glb_rec *)rec)->qbr_time);
263 struct seq_operations lprocfs_quota_seq_sops = {
264 .start = lprocfs_quota_seq_start,
265 .stop = lprocfs_quota_seq_stop,
266 .next = lprocfs_quota_seq_next,
267 .show = lprocfs_quota_seq_show,
270 static int lprocfs_quota_seq_open(struct inode *inode, struct file *file)
272 struct seq_file *seq;
274 struct lquota_procfs *lqp;
275 const struct dt_it_ops *iops;
278 /* Allocate quota procfs data. This structure will be passed to
279 * seq_start/stop/next/show via seq->private */
284 /* store pointer to object we would like to iterate over */
285 lqp->lqp_obj = (struct dt_object *)PDE_DATA(inode);
287 /* Initialize the common environment to be used in the seq operations */
288 rc = lu_env_init(&lqp->lqp_env, LCT_LOCAL);
290 char *obd_name = "quota";
292 if (lqp->lqp_obj != NULL)
293 obd_name = lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name;
295 CERROR("%s: error initializing procfs quota env: rc = %d\n",
300 rc = LPROCFS_ENTRY_CHECK(inode);
304 rc = seq_open(file, &lprocfs_quota_seq_sops);
308 /* initialize iterator */
309 iops = &lqp->lqp_obj->do_index_ops->dio_it;
310 it = iops->init(&lqp->lqp_env, lqp->lqp_obj, 0);
313 CERROR("%s: failed to initialize iterator: rc = %ld\n",
314 lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name,
316 seq_release(inode, file);
322 seq = file->private_data;
327 lu_env_fini(&lqp->lqp_env);
333 static int lprocfs_quota_seq_release(struct inode *inode, struct file *file)
335 struct seq_file *seq = file->private_data;
336 struct lquota_procfs *lqp = seq->private;
337 const struct dt_it_ops *iops;
340 iops = &lqp->lqp_obj->do_index_ops->dio_it;
341 if (lqp->lqp_it != NULL)
342 iops->fini(&lqp->lqp_env, lqp->lqp_it);
343 lu_env_fini(&lqp->lqp_env);
346 return seq_release(inode, file);
349 struct file_operations lprocfs_quota_seq_fops = {
350 .owner = THIS_MODULE,
351 .open = lprocfs_quota_seq_open,
354 .release = lprocfs_quota_seq_release,
356 #endif /* CONFIG_PROC_FS */