Whamcloud - gitweb
LU-1303 lod: transfer default striping from parent/fs
[fs/lustre-release.git] / lustre / quota / lproc_quota.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
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.
9  *
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).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2011, Whamcloud, Inc.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  */
36
37 #define DEBUG_SUBSYSTEM S_LQUOTA
38
39 #include <linux/version.h>
40 #include <lprocfs_status.h>
41 #include <obd.h>
42 #include <linux/seq_file.h>
43 #include <lustre_fsfilt.h>
44
45 #include "lquota_internal.h"
46
47 #ifdef LPROCFS
48 /* structure allocated at seq_open time and release when seq_release is called.
49  * It is passed to seq_start/stop/next/show which can thus use the same lu_env
50  * to be used with the iterator API */
51 struct lquota_procfs {
52         struct dt_object        *lqp_obj;
53         struct lu_env            lqp_env;
54 };
55
56 /* global shared environment */
57 static void *lprocfs_quota_seq_start(struct seq_file *p, loff_t *pos)
58 {
59         struct lquota_procfs    *lqp = p->private;
60         const struct dt_it_ops  *iops;
61         struct dt_it            *it;
62         loff_t                   offset = *pos;
63         int                      rc;
64
65         LASSERT(lqp);
66
67         if (offset == 0)
68                 return SEQ_START_TOKEN;
69         offset--;
70
71         if (lqp->lqp_obj == NULL)
72                 /* accounting not enabled. */
73                 return NULL;
74
75         /* initialize iterator */
76         iops = &lqp->lqp_obj->do_index_ops->dio_it;
77         it = iops->init(&lqp->lqp_env, lqp->lqp_obj, 0, BYPASS_CAPA);
78         if (IS_ERR(it)) {
79                 CERROR("%s: failed to initialize iterator: rc = %ld\n",
80                        lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name,
81                        PTR_ERR(it));
82                 return NULL;
83         }
84
85         /* move on to the first valid record */
86         rc = iops->load(&lqp->lqp_env, it, 0);
87         if (rc < 0) { /* Error */
88                 goto not_found;
89         } else if (rc == 0) {
90                 /*
91                  * Iterator didn't find record with exactly the key requested.
92                  *
93                  * It is currently either
94                  *
95                  *     - positioned above record with key less than
96                  *       requested - skip it.
97                  *     - or not positioned at all (is in IAM_IT_SKEWED
98                  *       state) - position it on the next item.
99                  */
100                 rc = iops->next(&lqp->lqp_env, it);
101                 if (rc != 0)
102                         goto not_found;
103         }
104         while (offset--) {
105                 rc = iops->next(&lqp->lqp_env, it);
106                 if (rc != 0) /* Error or reach the end */
107                         goto not_found;
108         }
109         return it;
110
111 not_found:
112         iops->put(&lqp->lqp_env, it);
113         iops->fini(&lqp->lqp_env, it);
114         return NULL;
115 }
116
117 static void lprocfs_quota_seq_stop(struct seq_file *p, void *v)
118 {
119         struct lquota_procfs    *lqp = p->private;
120         const struct dt_it_ops  *iops;
121         struct dt_it            *it;
122
123         if (lqp->lqp_obj == NULL || v == NULL || v == SEQ_START_TOKEN)
124                 return;
125
126         iops = &lqp->lqp_obj->do_index_ops->dio_it;
127         it = (struct dt_it *)v;
128         /* if something wrong happened during ->seq_show, we need to release
129          * the iterator here */
130         iops->put(&lqp->lqp_env, it);
131         iops->fini(&lqp->lqp_env, it);
132 }
133
134 static void *lprocfs_quota_seq_next(struct seq_file *p, void *v, loff_t *pos)
135 {
136         struct lquota_procfs    *lqp = p->private;
137         const struct dt_it_ops  *iops;
138         struct dt_it            *it;
139         int                      rc;
140
141         LASSERT(lqp);
142
143         ++*pos;
144         if (lqp->lqp_obj == NULL)
145                 return NULL;
146
147         if (v == SEQ_START_TOKEN)
148                 return lprocfs_quota_seq_start(p, pos);
149
150         iops = &lqp->lqp_obj->do_index_ops->dio_it;
151         it = (struct dt_it *)v;
152
153         rc = iops->next(&lqp->lqp_env, it);
154         if (rc == 0)
155                 return it;
156
157         if (rc < 0)
158                 CERROR("%s: seq_next failed: rc = %d\n",
159                        lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name, rc);
160
161         /* Reach the end or error */
162         iops->put(&lqp->lqp_env, it);
163         iops->fini(&lqp->lqp_env, it);
164         return NULL;
165 }
166
167 /*
168  * Output example:
169  *
170  * user_accounting:
171  * - id:      0
172  *   usage:   { inodes:                  209, bytes:             26161152 }
173  * - id:      840000038
174  *   usage:   { inodes:                    1, bytes:             10485760 }
175  */
176 static int lprocfs_quota_seq_show(struct seq_file *p, void *v)
177 {
178         struct lquota_procfs    *lqp = p->private;
179         const struct dt_it_ops  *iops;
180         struct dt_it            *it;
181         struct dt_key           *key;
182         struct lquota_acct_rec   rec;
183         int                      rc;
184
185         LASSERT(lqp);
186         if (lqp->lqp_obj == NULL) {
187                 seq_printf(p, "not supported\n");
188                 return 0;
189         }
190
191         if (v == SEQ_START_TOKEN) {
192                 const struct lu_fid *fid = lu_object_fid(&lqp->lqp_obj->do_lu);
193
194                 LASSERT(fid_is_acct(fid));
195                 if (fid_oid(fid) == ACCT_USER_OID)
196                         seq_printf(p, "user_accounting:\n");
197                 else
198                         seq_printf(p, "group_accounting:\n");
199                 return 0;
200         }
201
202         iops = &lqp->lqp_obj->do_index_ops->dio_it;
203         it = (struct dt_it *)v;
204
205         key = iops->key(&lqp->lqp_env, it);
206         if (IS_ERR(key)) {
207                 CERROR("%s: failed to get key: rc = %ld\n",
208                        lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name,
209                        PTR_ERR(key));
210                 return PTR_ERR(key);
211         }
212
213         rc = iops->rec(&lqp->lqp_env, it, (struct dt_rec *)&rec, 0);
214         if (rc) {
215                 CERROR("%s: failed to get rec: rc = %d\n",
216                        lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name, rc);
217                 return rc;
218         }
219
220         seq_printf(p, "- %-8s %llu\n", "id:", *((__u64 *)key));
221         seq_printf(p, "  %-8s { inodes: %20"LPF64"u, bytes: %20"LPF64"u }\n",
222                    "usage:", rec.ispace, rec.bspace);
223         return 0;
224 }
225
226 struct seq_operations lprocfs_quota_seq_sops = {
227         .start  = lprocfs_quota_seq_start,
228         .stop   = lprocfs_quota_seq_stop,
229         .next   = lprocfs_quota_seq_next,
230         .show   = lprocfs_quota_seq_show,
231 };
232
233 static int lprocfs_quota_seq_open(struct inode *inode, struct file *file)
234 {
235         struct proc_dir_entry   *dp = PDE(inode);
236         struct seq_file         *seq;
237         int                      rc;
238         struct lquota_procfs    *lqp;
239
240         /* Allocate quota procfs data. This structure will be passed to
241          * seq_start/stop/next/show via seq->private */
242         OBD_ALLOC_PTR(lqp);
243         if (lqp == NULL)
244                 return -ENOMEM;
245
246         /* store pointer to object we would like to iterate over */
247         lqp->lqp_obj = (struct dt_object *)dp->data;
248
249         /* Initialize the common environment to be used in the seq operations */
250         rc = lu_env_init(&lqp->lqp_env, LCT_LOCAL);
251         if (rc) {
252                 CERROR("%s: error initializing procfs quota env: rc = %d\n",
253                        lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name, rc);
254                 goto out_lqp;
255         }
256
257         if (LPROCFS_ENTRY_AND_CHECK(dp)) {
258                 rc = -ENOENT;
259                 goto out_env;
260         }
261
262         rc = seq_open(file, &lprocfs_quota_seq_sops);
263         if (rc)
264                 goto out_lprocfs;
265
266         seq = file->private_data;
267         seq->private = lqp;
268         return 0;
269
270 out_lprocfs:
271         LPROCFS_EXIT();
272 out_env:
273         lu_env_fini(&lqp->lqp_env);
274 out_lqp:
275         OBD_FREE_PTR(lqp);
276         return rc;
277 }
278
279 static int lprocfs_quota_seq_release(struct inode *inode, struct file *file)
280 {
281         struct seq_file         *seq = file->private_data;
282         struct lquota_procfs    *lqp = seq->private;
283
284         LPROCFS_EXIT();
285
286         LASSERT(lqp);
287         lu_env_fini(&lqp->lqp_env);
288         OBD_FREE_PTR(lqp);
289
290         return seq_release(inode, file);
291 }
292
293 struct file_operations lprocfs_quota_seq_fops = {
294         .owner          = THIS_MODULE,
295         .open           = lprocfs_quota_seq_open,
296         .read           = seq_read,
297         .llseek         = seq_lseek,
298         .release        = lprocfs_quota_seq_release,
299 };
300 #endif  /* LPROCFS */