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, 2012, 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 <lustre_fsfilt.h>
39 #include "lquota_internal.h"
42 /* structure allocated at seq_open time and release when seq_release is called.
43 * It is passed to seq_start/stop/next/show which can thus use the same lu_env
44 * to be used with the iterator API */
45 struct lquota_procfs {
46 struct dt_object *lqp_obj;
47 struct lu_env lqp_env;
50 /* global shared environment */
51 static void *lprocfs_quota_seq_start(struct seq_file *p, loff_t *pos)
53 struct lquota_procfs *lqp = p->private;
54 const struct dt_it_ops *iops;
62 return SEQ_START_TOKEN;
65 if (lqp->lqp_obj == NULL)
66 /* accounting not enabled. */
69 /* initialize iterator */
70 iops = &lqp->lqp_obj->do_index_ops->dio_it;
71 it = iops->init(&lqp->lqp_env, lqp->lqp_obj, 0, BYPASS_CAPA);
73 CERROR("%s: failed to initialize iterator: rc = %ld\n",
74 lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name,
79 /* move on to the first valid record */
80 rc = iops->load(&lqp->lqp_env, it, 0);
81 if (rc < 0) { /* Error */
85 * Iterator didn't find record with exactly the key requested.
87 * It is currently either
89 * - positioned above record with key less than
90 * requested - skip it.
91 * - or not positioned at all (is in IAM_IT_SKEWED
92 * state) - position it on the next item.
94 rc = iops->next(&lqp->lqp_env, it);
99 rc = iops->next(&lqp->lqp_env, it);
100 if (rc != 0) /* Error or reach the end */
106 iops->put(&lqp->lqp_env, it);
107 iops->fini(&lqp->lqp_env, it);
111 static void lprocfs_quota_seq_stop(struct seq_file *p, void *v)
113 struct lquota_procfs *lqp = p->private;
114 const struct dt_it_ops *iops;
117 if (lqp->lqp_obj == NULL || v == NULL || v == SEQ_START_TOKEN)
120 iops = &lqp->lqp_obj->do_index_ops->dio_it;
121 it = (struct dt_it *)v;
122 /* if something wrong happened during ->seq_show, we need to release
123 * the iterator here */
124 iops->put(&lqp->lqp_env, it);
125 iops->fini(&lqp->lqp_env, it);
128 static void *lprocfs_quota_seq_next(struct seq_file *p, void *v, loff_t *pos)
130 struct lquota_procfs *lqp = p->private;
131 const struct dt_it_ops *iops;
138 if (lqp->lqp_obj == NULL)
141 if (v == SEQ_START_TOKEN)
142 return lprocfs_quota_seq_start(p, pos);
144 iops = &lqp->lqp_obj->do_index_ops->dio_it;
145 it = (struct dt_it *)v;
147 rc = iops->next(&lqp->lqp_env, it);
152 CERROR("%s: seq_next failed: rc = %d\n",
153 lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name, rc);
155 /* Reach the end or error */
156 iops->put(&lqp->lqp_env, it);
157 iops->fini(&lqp->lqp_env, it);
166 * usage: { inodes: 209, kbytes: 2616 }
168 * usage: { inodes: 1, kbytes: 1048 }
170 static int lprocfs_quota_seq_show(struct seq_file *p, void *v)
172 struct lquota_procfs *lqp = p->private;
173 struct lquota_thread_info *qti = lquota_info(&lqp->lqp_env);
174 const struct dt_it_ops *iops;
177 struct dt_rec *rec = (struct dt_rec *)&qti->qti_rec;
178 const struct lu_fid *fid;
182 if (lqp->lqp_obj == NULL) {
183 seq_printf(p, "not supported\n");
187 fid = lu_object_fid(&lqp->lqp_obj->do_lu);
189 if (v == SEQ_START_TOKEN) {
190 if (fid_is_acct(fid)) {
191 if (fid_oid(fid) == ACCT_USER_OID)
192 seq_printf(p, "usr_accounting:\n");
194 seq_printf(p, "grp_accounting:\n");
195 } else if (fid_seq(fid) == FID_SEQ_QUOTA_GLB) {
196 int poolid, rtype, qtype;
198 rc = lquota_extract_fid(fid, &poolid, &rtype, &qtype);
202 seq_printf(p, "global_pool%d_%s_%s\n", poolid,
203 RES_NAME(rtype), QTYPE_NAME(qtype));
204 } else if (fid_seq(fid) == FID_SEQ_LOCAL_NAME) {
205 /* global index copy object */
206 seq_printf(p, "global_index_copy:\n");
213 iops = &lqp->lqp_obj->do_index_ops->dio_it;
214 it = (struct dt_it *)v;
216 key = iops->key(&lqp->lqp_env, it);
218 CERROR("%s: failed to get key: rc = %ld\n",
219 lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name,
224 rc = iops->rec(&lqp->lqp_env, it, rec, 0);
226 CERROR("%s: failed to get rec: rc = %d\n",
227 lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name, rc);
231 seq_printf(p, "- %-8s %llu\n", "id:", *((__u64 *)key));
232 if (fid_is_acct(fid))
233 seq_printf(p, " %-8s { inodes: %20"LPF64"u, kbytes: %20"LPF64
235 ((struct lquota_acct_rec *)rec)->ispace,
236 toqb(((struct lquota_acct_rec *)rec)->bspace));
237 else if (fid_seq(fid) == FID_SEQ_QUOTA_GLB ||
238 fid_seq(fid) == FID_SEQ_LOCAL_NAME)
239 seq_printf(p, " %-8s { hard: %20"LPF64"u, soft: %20"LPF64
240 "u, granted: %20"LPF64"u, time: %20"LPF64"u }\n",
242 ((struct lquota_glb_rec *)rec)->qbr_hardlimit,
243 ((struct lquota_glb_rec *)rec)->qbr_softlimit,
244 ((struct lquota_glb_rec *)rec)->qbr_granted,
245 ((struct lquota_glb_rec *)rec)->qbr_time);
249 struct seq_operations lprocfs_quota_seq_sops = {
250 .start = lprocfs_quota_seq_start,
251 .stop = lprocfs_quota_seq_stop,
252 .next = lprocfs_quota_seq_next,
253 .show = lprocfs_quota_seq_show,
256 static int lprocfs_quota_seq_open(struct inode *inode, struct file *file)
258 struct proc_dir_entry *dp = PDE(inode);
259 struct seq_file *seq;
261 struct lquota_procfs *lqp;
263 /* Allocate quota procfs data. This structure will be passed to
264 * seq_start/stop/next/show via seq->private */
269 /* store pointer to object we would like to iterate over */
270 lqp->lqp_obj = (struct dt_object *)dp->data;
272 /* Initialize the common environment to be used in the seq operations */
273 rc = lu_env_init(&lqp->lqp_env, LCT_LOCAL);
275 char *obd_name = "quota";
277 if (lqp->lqp_obj != NULL)
278 obd_name = lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name;
280 CERROR("%s: error initializing procfs quota env: rc = %d\n",
285 if (LPROCFS_ENTRY_AND_CHECK(dp)) {
290 rc = seq_open(file, &lprocfs_quota_seq_sops);
294 seq = file->private_data;
301 lu_env_fini(&lqp->lqp_env);
307 static int lprocfs_quota_seq_release(struct inode *inode, struct file *file)
309 struct seq_file *seq = file->private_data;
310 struct lquota_procfs *lqp = seq->private;
315 lu_env_fini(&lqp->lqp_env);
318 return seq_release(inode, file);
321 struct file_operations lprocfs_quota_seq_fops = {
322 .owner = THIS_MODULE,
323 .open = lprocfs_quota_seq_open,
326 .release = lprocfs_quota_seq_release,