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, 2013, 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 /* global shared environment */
49 static void *lprocfs_quota_seq_start(struct seq_file *p, loff_t *pos)
51 struct lquota_procfs *lqp = p->private;
52 const struct dt_it_ops *iops;
60 return SEQ_START_TOKEN;
63 if (lqp->lqp_obj == NULL)
64 /* accounting not enabled. */
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);
71 CERROR("%s: failed to initialize iterator: rc = %ld\n",
72 lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name,
77 /* move on to the first valid record */
78 rc = iops->load(&lqp->lqp_env, it, 0);
79 if (rc < 0) { /* Error */
83 * Iterator didn't find record with exactly the key requested.
85 * It is currently either
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.
92 rc = iops->next(&lqp->lqp_env, it);
97 rc = iops->next(&lqp->lqp_env, it);
98 if (rc != 0) /* Error or reach the end */
104 iops->put(&lqp->lqp_env, it);
105 iops->fini(&lqp->lqp_env, it);
109 static void lprocfs_quota_seq_stop(struct seq_file *p, void *v)
111 struct lquota_procfs *lqp = p->private;
112 const struct dt_it_ops *iops;
115 if (lqp->lqp_obj == NULL || v == NULL || v == SEQ_START_TOKEN)
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);
126 static void *lprocfs_quota_seq_next(struct seq_file *p, void *v, loff_t *pos)
128 struct lquota_procfs *lqp = p->private;
129 const struct dt_it_ops *iops;
136 if (lqp->lqp_obj == NULL)
139 if (v == SEQ_START_TOKEN)
140 return lprocfs_quota_seq_start(p, pos);
142 iops = &lqp->lqp_obj->do_index_ops->dio_it;
143 it = (struct dt_it *)v;
145 rc = iops->next(&lqp->lqp_env, it);
150 CERROR("%s: seq_next failed: rc = %d\n",
151 lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name, rc);
153 /* Reach the end or error */
154 iops->put(&lqp->lqp_env, it);
155 iops->fini(&lqp->lqp_env, it);
164 * usage: { inodes: 209, kbytes: 2616 }
166 * usage: { inodes: 1, kbytes: 1048 }
168 static int lprocfs_quota_seq_show(struct seq_file *p, void *v)
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;
175 struct dt_rec *rec = (struct dt_rec *)&qti->qti_rec;
176 const struct lu_fid *fid;
180 if (lqp->lqp_obj == NULL) {
181 seq_printf(p, "not supported\n");
185 fid = lu_object_fid(&lqp->lqp_obj->do_lu);
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");
192 seq_printf(p, "grp_accounting:\n");
193 } else if (fid_seq(fid) == FID_SEQ_QUOTA_GLB) {
194 int poolid, rtype, qtype;
196 rc = lquota_extract_fid(fid, &poolid, &rtype, &qtype);
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");
211 iops = &lqp->lqp_obj->do_index_ops->dio_it;
212 it = (struct dt_it *)v;
214 key = iops->key(&lqp->lqp_env, it);
216 CERROR("%s: failed to get key: rc = %ld\n",
217 lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name,
222 rc = iops->rec(&lqp->lqp_env, it, rec, 0);
224 CERROR("%s: failed to get rec: rc = %d\n",
225 lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name, rc);
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
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",
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);
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,
254 static int lprocfs_quota_seq_open(struct inode *inode, struct file *file)
256 struct seq_file *seq;
258 struct lquota_procfs *lqp;
260 /* Allocate quota procfs data. This structure will be passed to
261 * seq_start/stop/next/show via seq->private */
266 /* store pointer to object we would like to iterate over */
267 lqp->lqp_obj = (struct dt_object *)PDE_DATA(inode);
269 /* Initialize the common environment to be used in the seq operations */
270 rc = lu_env_init(&lqp->lqp_env, LCT_LOCAL);
272 char *obd_name = "quota";
274 if (lqp->lqp_obj != NULL)
275 obd_name = lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name;
277 CERROR("%s: error initializing procfs quota env: rc = %d\n",
282 if (LPROCFS_ENTRY_CHECK(PDE(inode))) {
287 rc = seq_open(file, &lprocfs_quota_seq_sops);
291 seq = file->private_data;
296 lu_env_fini(&lqp->lqp_env);
302 static int lprocfs_quota_seq_release(struct inode *inode, struct file *file)
304 struct seq_file *seq = file->private_data;
305 struct lquota_procfs *lqp = seq->private;
308 lu_env_fini(&lqp->lqp_env);
311 return seq_release(inode, file);
314 struct file_operations lprocfs_quota_seq_fops = {
315 .owner = THIS_MODULE,
316 .open = lprocfs_quota_seq_open,
319 .release = lprocfs_quota_seq_release,