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";
175 case ACCT_PROJECT_OID:
176 return "prj_accounting";
179 return "unknown_accounting";
188 * usage: { inodes: 209, kbytes: 2616 }
190 * usage: { inodes: 1, kbytes: 1048 }
192 static int lprocfs_quota_seq_show(struct seq_file *p, void *v)
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;
199 struct dt_rec *rec = (struct dt_rec *)&qti->qti_rec;
200 const struct lu_fid *fid;
204 if (lqp->lqp_obj == NULL) {
205 seq_printf(p, "not supported\n");
209 fid = lu_object_fid(&lqp->lqp_obj->do_lu);
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 poolid, rtype, qtype;
217 rc = lquota_extract_fid(fid, &poolid, &rtype, &qtype);
221 seq_printf(p, "global_pool%d_%s_%s\n", poolid,
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");
232 iops = &lqp->lqp_obj->do_index_ops->dio_it;
233 it = (struct dt_it *)v;
235 key = iops->key(&lqp->lqp_env, it);
237 CERROR("%s: failed to get key: rc = %ld\n",
238 lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name,
243 rc = iops->rec(&lqp->lqp_env, it, rec, 0);
245 CERROR("%s: failed to get rec: rc = %d\n",
246 lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name, rc);
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",
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);
266 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,
273 static int lprocfs_quota_seq_open(struct inode *inode, struct file *file)
275 struct seq_file *seq;
277 struct lquota_procfs *lqp;
278 const struct dt_it_ops *iops;
281 /* Allocate quota procfs data. This structure will be passed to
282 * seq_start/stop/next/show via seq->private */
287 /* store pointer to object we would like to iterate over */
288 lqp->lqp_obj = (struct dt_object *)PDE_DATA(inode);
290 /* Initialize the common environment to be used in the seq operations */
291 rc = lu_env_init(&lqp->lqp_env, LCT_LOCAL);
293 char *obd_name = "quota";
295 if (lqp->lqp_obj != NULL)
296 obd_name = lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name;
298 CERROR("%s: error initializing procfs quota env: rc = %d\n",
303 rc = LPROCFS_ENTRY_CHECK(inode);
307 rc = seq_open(file, &lprocfs_quota_seq_sops);
316 /* initialize iterator */
317 iops = &lqp->lqp_obj->do_index_ops->dio_it;
318 it = iops->init(&lqp->lqp_env, lqp->lqp_obj, 0);
321 CERROR("%s: failed to initialize iterator: rc = %ld\n",
322 lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name,
324 seq_release(inode, file);
331 seq = file->private_data;
336 lu_env_fini(&lqp->lqp_env);
342 static int lprocfs_quota_seq_release(struct inode *inode, struct file *file)
344 struct seq_file *seq = file->private_data;
345 struct lquota_procfs *lqp = seq->private;
346 const struct dt_it_ops *iops;
349 if (lqp->lqp_it != NULL) {
350 iops = &lqp->lqp_obj->do_index_ops->dio_it;
351 iops->fini(&lqp->lqp_env, lqp->lqp_it);
353 lu_env_fini(&lqp->lqp_env);
356 return seq_release(inode, file);
359 struct file_operations lprocfs_quota_seq_fops = {
360 .owner = THIS_MODULE,
361 .open = lprocfs_quota_seq_open,
364 .release = lprocfs_quota_seq_release,
366 #endif /* CONFIG_PROC_FS */