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);
173 * usage: { inodes: 209, kbytes: 2616 }
175 * usage: { inodes: 1, kbytes: 1048 }
177 static int lprocfs_quota_seq_show(struct seq_file *p, void *v)
179 struct lquota_procfs *lqp = p->private;
180 struct lquota_thread_info *qti = lquota_info(&lqp->lqp_env);
181 const struct dt_it_ops *iops;
184 struct dt_rec *rec = (struct dt_rec *)&qti->qti_rec;
185 const struct lu_fid *fid;
189 if (lqp->lqp_obj == NULL) {
190 seq_printf(p, "not supported\n");
194 fid = lu_object_fid(&lqp->lqp_obj->do_lu);
196 if (v == SEQ_START_TOKEN) {
197 if (fid_is_acct(fid)) {
198 if (fid_oid(fid) == ACCT_USER_OID)
199 seq_printf(p, "usr_accounting:\n");
201 seq_printf(p, "grp_accounting:\n");
202 } else if (fid_seq(fid) == FID_SEQ_QUOTA_GLB) {
203 int poolid, rtype, qtype;
205 rc = lquota_extract_fid(fid, &poolid, &rtype, &qtype);
209 seq_printf(p, "global_pool%d_%s_%s\n", poolid,
210 RES_NAME(rtype), QTYPE_NAME(qtype));
211 } else if (fid_seq(fid) == FID_SEQ_LOCAL_NAME) {
212 /* global index copy object */
213 seq_printf(p, "global_index_copy:\n");
220 iops = &lqp->lqp_obj->do_index_ops->dio_it;
221 it = (struct dt_it *)v;
223 key = iops->key(&lqp->lqp_env, it);
225 CERROR("%s: failed to get key: rc = %ld\n",
226 lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name,
231 rc = iops->rec(&lqp->lqp_env, it, rec, 0);
233 CERROR("%s: failed to get rec: rc = %d\n",
234 lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name, rc);
238 seq_printf(p, "- %-8s %llu\n", "id:", *((__u64 *)key));
239 if (fid_is_acct(fid))
240 seq_printf(p, " %-8s { inodes: %20llu, kbytes: %20llu }\n", "usage:",
241 ((struct lquota_acct_rec *)rec)->ispace,
242 toqb(((struct lquota_acct_rec *)rec)->bspace));
243 else if (fid_seq(fid) == FID_SEQ_QUOTA_GLB ||
244 fid_seq(fid) == FID_SEQ_LOCAL_NAME)
245 seq_printf(p, " %-8s { hard: %20llu, soft: %20llu, granted: %20llu, time: %20llu }\n",
247 ((struct lquota_glb_rec *)rec)->qbr_hardlimit,
248 ((struct lquota_glb_rec *)rec)->qbr_softlimit,
249 ((struct lquota_glb_rec *)rec)->qbr_granted,
250 ((struct lquota_glb_rec *)rec)->qbr_time);
254 struct seq_operations lprocfs_quota_seq_sops = {
255 .start = lprocfs_quota_seq_start,
256 .stop = lprocfs_quota_seq_stop,
257 .next = lprocfs_quota_seq_next,
258 .show = lprocfs_quota_seq_show,
261 static int lprocfs_quota_seq_open(struct inode *inode, struct file *file)
263 struct seq_file *seq;
265 struct lquota_procfs *lqp;
266 const struct dt_it_ops *iops;
269 /* Allocate quota procfs data. This structure will be passed to
270 * seq_start/stop/next/show via seq->private */
275 /* store pointer to object we would like to iterate over */
276 lqp->lqp_obj = (struct dt_object *)PDE_DATA(inode);
278 /* Initialize the common environment to be used in the seq operations */
279 rc = lu_env_init(&lqp->lqp_env, LCT_LOCAL);
281 char *obd_name = "quota";
283 if (lqp->lqp_obj != NULL)
284 obd_name = lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name;
286 CERROR("%s: error initializing procfs quota env: rc = %d\n",
291 rc = LPROCFS_ENTRY_CHECK(inode);
295 rc = seq_open(file, &lprocfs_quota_seq_sops);
299 /* initialize iterator */
300 iops = &lqp->lqp_obj->do_index_ops->dio_it;
301 it = iops->init(&lqp->lqp_env, lqp->lqp_obj, 0);
304 CERROR("%s: failed to initialize iterator: rc = %ld\n",
305 lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name,
307 seq_release(inode, file);
313 seq = file->private_data;
318 lu_env_fini(&lqp->lqp_env);
324 static int lprocfs_quota_seq_release(struct inode *inode, struct file *file)
326 struct seq_file *seq = file->private_data;
327 struct lquota_procfs *lqp = seq->private;
328 const struct dt_it_ops *iops;
331 iops = &lqp->lqp_obj->do_index_ops->dio_it;
332 if (lqp->lqp_it != NULL)
333 iops->fini(&lqp->lqp_env, lqp->lqp_it);
334 lu_env_fini(&lqp->lqp_env);
337 return seq_release(inode, file);
340 struct file_operations lprocfs_quota_seq_fops = {
341 .owner = THIS_MODULE,
342 .open = lprocfs_quota_seq_open,
345 .release = lprocfs_quota_seq_release,
347 #endif /* CONFIG_PROC_FS */