Merge branch 'stable-3.2' into pandora-3.2
[pandora-kernel.git] / fs / aufs / dbgaufs.c
1 /*
2  * Copyright (C) 2005-2013 Junjiro R. Okajima
3  *
4  * This program, aufs is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 /*
20  * debugfs interface
21  */
22
23 #include <linux/debugfs.h>
24 #include "aufs.h"
25
26 #ifndef CONFIG_SYSFS
27 #error DEBUG_FS depends upon SYSFS
28 #endif
29
30 static struct dentry *dbgaufs;
31 static const mode_t dbgaufs_mode = S_IRUSR | S_IRGRP | S_IROTH;
32
33 /* 20 is max digits length of ulong 64 */
34 struct dbgaufs_arg {
35         int n;
36         char a[20 * 4];
37 };
38
39 /*
40  * common function for all XINO files
41  */
42 static int dbgaufs_xi_release(struct inode *inode __maybe_unused,
43                               struct file *file)
44 {
45         kfree(file->private_data);
46         return 0;
47 }
48
49 static int dbgaufs_xi_open(struct file *xf, struct file *file, int do_fcnt)
50 {
51         int err;
52         struct kstat st;
53         struct dbgaufs_arg *p;
54
55         err = -ENOMEM;
56         p = kmalloc(sizeof(*p), GFP_NOFS);
57         if (unlikely(!p))
58                 goto out;
59
60         err = 0;
61         p->n = 0;
62         file->private_data = p;
63         if (!xf)
64                 goto out;
65
66         err = vfs_getattr(xf->f_vfsmnt, xf->f_dentry, &st);
67         if (!err) {
68                 if (do_fcnt)
69                         p->n = snprintf
70                                 (p->a, sizeof(p->a), "%ld, %llux%lu %lld\n",
71                                  (long)file_count(xf), st.blocks, st.blksize,
72                                  (long long)st.size);
73                 else
74                         p->n = snprintf(p->a, sizeof(p->a), "%llux%lu %lld\n",
75                                         st.blocks, st.blksize,
76                                         (long long)st.size);
77                 AuDebugOn(p->n >= sizeof(p->a));
78         } else {
79                 p->n = snprintf(p->a, sizeof(p->a), "err %d\n", err);
80                 err = 0;
81         }
82
83 out:
84         return err;
85
86 }
87
88 static ssize_t dbgaufs_xi_read(struct file *file, char __user *buf,
89                                size_t count, loff_t *ppos)
90 {
91         struct dbgaufs_arg *p;
92
93         p = file->private_data;
94         return simple_read_from_buffer(buf, count, ppos, p->a, p->n);
95 }
96
97 /* ---------------------------------------------------------------------- */
98
99 struct dbgaufs_plink_arg {
100         int n;
101         char a[];
102 };
103
104 static int dbgaufs_plink_release(struct inode *inode __maybe_unused,
105                                  struct file *file)
106 {
107         free_page((unsigned long)file->private_data);
108         return 0;
109 }
110
111 static int dbgaufs_plink_open(struct inode *inode, struct file *file)
112 {
113         int err, i, limit;
114         unsigned long n, sum;
115         struct dbgaufs_plink_arg *p;
116         struct au_sbinfo *sbinfo;
117         struct super_block *sb;
118         struct au_sphlhead *sphl;
119
120         err = -ENOMEM;
121         p = (void *)get_zeroed_page(GFP_NOFS);
122         if (unlikely(!p))
123                 goto out;
124
125         err = -EFBIG;
126         sbinfo = inode->i_private;
127         sb = sbinfo->si_sb;
128         si_noflush_read_lock(sb);
129         if (au_opt_test(au_mntflags(sb), PLINK)) {
130                 limit = PAGE_SIZE - sizeof(p->n);
131
132                 /* the number of buckets */
133                 n = snprintf(p->a + p->n, limit, "%d\n", AuPlink_NHASH);
134                 p->n += n;
135                 limit -= n;
136
137                 sum = 0;
138                 for (i = 0, sphl = sbinfo->si_plink;
139                      i < AuPlink_NHASH;
140                      i++, sphl++) {
141                         n = au_sphl_count(sphl);
142                         sum += n;
143
144                         n = snprintf(p->a + p->n, limit, "%lu ", n);
145                         p->n += n;
146                         limit -= n;
147                         if (unlikely(limit <= 0))
148                                 goto out_free;
149                 }
150                 p->a[p->n - 1] = '\n';
151
152                 /* the sum of plinks */
153                 n = snprintf(p->a + p->n, limit, "%lu\n", sum);
154                 p->n += n;
155                 limit -= n;
156                 if (unlikely(limit <= 0))
157                         goto out_free;
158         } else {
159 #define str "1\n0\n0\n"
160                 p->n = sizeof(str) - 1;
161                 strcpy(p->a, str);
162 #undef str
163         }
164         si_read_unlock(sb);
165
166         err = 0;
167         file->private_data = p;
168         goto out; /* success */
169
170 out_free:
171         free_page((unsigned long)p);
172 out:
173         return err;
174 }
175
176 static ssize_t dbgaufs_plink_read(struct file *file, char __user *buf,
177                                   size_t count, loff_t *ppos)
178 {
179         struct dbgaufs_plink_arg *p;
180
181         p = file->private_data;
182         return simple_read_from_buffer(buf, count, ppos, p->a, p->n);
183 }
184
185 static const struct file_operations dbgaufs_plink_fop = {
186         .owner          = THIS_MODULE,
187         .open           = dbgaufs_plink_open,
188         .release        = dbgaufs_plink_release,
189         .read           = dbgaufs_plink_read
190 };
191
192 /* ---------------------------------------------------------------------- */
193
194 static int dbgaufs_xib_open(struct inode *inode, struct file *file)
195 {
196         int err;
197         struct au_sbinfo *sbinfo;
198         struct super_block *sb;
199
200         sbinfo = inode->i_private;
201         sb = sbinfo->si_sb;
202         si_noflush_read_lock(sb);
203         err = dbgaufs_xi_open(sbinfo->si_xib, file, /*do_fcnt*/0);
204         si_read_unlock(sb);
205         return err;
206 }
207
208 static const struct file_operations dbgaufs_xib_fop = {
209         .owner          = THIS_MODULE,
210         .open           = dbgaufs_xib_open,
211         .release        = dbgaufs_xi_release,
212         .read           = dbgaufs_xi_read
213 };
214
215 /* ---------------------------------------------------------------------- */
216
217 #define DbgaufsXi_PREFIX "xi"
218
219 static int dbgaufs_xino_open(struct inode *inode, struct file *file)
220 {
221         int err;
222         long l;
223         struct au_sbinfo *sbinfo;
224         struct super_block *sb;
225         struct file *xf;
226         struct qstr *name;
227
228         err = -ENOENT;
229         xf = NULL;
230         name = &file->f_dentry->d_name;
231         if (unlikely(name->len < sizeof(DbgaufsXi_PREFIX)
232                      || memcmp(name->name, DbgaufsXi_PREFIX,
233                                sizeof(DbgaufsXi_PREFIX) - 1)))
234                 goto out;
235         err = kstrtol(name->name + sizeof(DbgaufsXi_PREFIX) - 1, 10, &l);
236         if (unlikely(err))
237                 goto out;
238
239         sbinfo = inode->i_private;
240         sb = sbinfo->si_sb;
241         si_noflush_read_lock(sb);
242         if (l <= au_sbend(sb)) {
243                 xf = au_sbr(sb, (aufs_bindex_t)l)->br_xino.xi_file;
244                 err = dbgaufs_xi_open(xf, file, /*do_fcnt*/1);
245         } else
246                 err = -ENOENT;
247         si_read_unlock(sb);
248
249 out:
250         return err;
251 }
252
253 static const struct file_operations dbgaufs_xino_fop = {
254         .owner          = THIS_MODULE,
255         .open           = dbgaufs_xino_open,
256         .release        = dbgaufs_xi_release,
257         .read           = dbgaufs_xi_read
258 };
259
260 void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex)
261 {
262         aufs_bindex_t bend;
263         struct au_branch *br;
264         struct au_xino_file *xi;
265
266         if (!au_sbi(sb)->si_dbgaufs)
267                 return;
268
269         bend = au_sbend(sb);
270         for (; bindex <= bend; bindex++) {
271                 br = au_sbr(sb, bindex);
272                 xi = &br->br_xino;
273                 debugfs_remove(xi->xi_dbgaufs);
274                 xi->xi_dbgaufs = NULL;
275         }
276 }
277
278 void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex)
279 {
280         struct au_sbinfo *sbinfo;
281         struct dentry *parent;
282         struct au_branch *br;
283         struct au_xino_file *xi;
284         aufs_bindex_t bend;
285         char name[sizeof(DbgaufsXi_PREFIX) + 5]; /* "xi" bindex NULL */
286
287         sbinfo = au_sbi(sb);
288         parent = sbinfo->si_dbgaufs;
289         if (!parent)
290                 return;
291
292         bend = au_sbend(sb);
293         for (; bindex <= bend; bindex++) {
294                 snprintf(name, sizeof(name), DbgaufsXi_PREFIX "%d", bindex);
295                 br = au_sbr(sb, bindex);
296                 xi = &br->br_xino;
297                 AuDebugOn(xi->xi_dbgaufs);
298                 xi->xi_dbgaufs = debugfs_create_file(name, dbgaufs_mode, parent,
299                                                      sbinfo, &dbgaufs_xino_fop);
300                 /* ignore an error */
301                 if (unlikely(!xi->xi_dbgaufs))
302                         AuWarn1("failed %s under debugfs\n", name);
303         }
304 }
305
306 /* ---------------------------------------------------------------------- */
307
308 #ifdef CONFIG_AUFS_EXPORT
309 static int dbgaufs_xigen_open(struct inode *inode, struct file *file)
310 {
311         int err;
312         struct au_sbinfo *sbinfo;
313         struct super_block *sb;
314
315         sbinfo = inode->i_private;
316         sb = sbinfo->si_sb;
317         si_noflush_read_lock(sb);
318         err = dbgaufs_xi_open(sbinfo->si_xigen, file, /*do_fcnt*/0);
319         si_read_unlock(sb);
320         return err;
321 }
322
323 static const struct file_operations dbgaufs_xigen_fop = {
324         .owner          = THIS_MODULE,
325         .open           = dbgaufs_xigen_open,
326         .release        = dbgaufs_xi_release,
327         .read           = dbgaufs_xi_read
328 };
329
330 static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo)
331 {
332         int err;
333
334         /*
335          * This function is a dynamic '__init' fucntion actually,
336          * so the tiny check for si_rwsem is unnecessary.
337          */
338         /* AuRwMustWriteLock(&sbinfo->si_rwsem); */
339
340         err = -EIO;
341         sbinfo->si_dbgaufs_xigen = debugfs_create_file
342                 ("xigen", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo,
343                  &dbgaufs_xigen_fop);
344         if (sbinfo->si_dbgaufs_xigen)
345                 err = 0;
346
347         return err;
348 }
349 #else
350 static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo)
351 {
352         return 0;
353 }
354 #endif /* CONFIG_AUFS_EXPORT */
355
356 /* ---------------------------------------------------------------------- */
357
358 void dbgaufs_si_fin(struct au_sbinfo *sbinfo)
359 {
360         /*
361          * This function is a dynamic '__init' fucntion actually,
362          * so the tiny check for si_rwsem is unnecessary.
363          */
364         /* AuRwMustWriteLock(&sbinfo->si_rwsem); */
365
366         debugfs_remove_recursive(sbinfo->si_dbgaufs);
367         sbinfo->si_dbgaufs = NULL;
368         kobject_put(&sbinfo->si_kobj);
369 }
370
371 int dbgaufs_si_init(struct au_sbinfo *sbinfo)
372 {
373         int err;
374         char name[SysaufsSiNameLen];
375
376         /*
377          * This function is a dynamic '__init' fucntion actually,
378          * so the tiny check for si_rwsem is unnecessary.
379          */
380         /* AuRwMustWriteLock(&sbinfo->si_rwsem); */
381
382         err = -ENOENT;
383         if (!dbgaufs) {
384                 AuErr1("/debug/aufs is uninitialized\n");
385                 goto out;
386         }
387
388         err = -EIO;
389         sysaufs_name(sbinfo, name);
390         sbinfo->si_dbgaufs = debugfs_create_dir(name, dbgaufs);
391         if (unlikely(!sbinfo->si_dbgaufs))
392                 goto out;
393         kobject_get(&sbinfo->si_kobj);
394
395         sbinfo->si_dbgaufs_xib = debugfs_create_file
396                 ("xib", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo,
397                  &dbgaufs_xib_fop);
398         if (unlikely(!sbinfo->si_dbgaufs_xib))
399                 goto out_dir;
400
401         sbinfo->si_dbgaufs_plink = debugfs_create_file
402                 ("plink", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo,
403                  &dbgaufs_plink_fop);
404         if (unlikely(!sbinfo->si_dbgaufs_plink))
405                 goto out_dir;
406
407         err = dbgaufs_xigen_init(sbinfo);
408         if (!err)
409                 goto out; /* success */
410
411 out_dir:
412         dbgaufs_si_fin(sbinfo);
413 out:
414         return err;
415 }
416
417 /* ---------------------------------------------------------------------- */
418
419 void dbgaufs_fin(void)
420 {
421         debugfs_remove(dbgaufs);
422 }
423
424 int __init dbgaufs_init(void)
425 {
426         int err;
427
428         err = -EIO;
429         dbgaufs = debugfs_create_dir(AUFS_NAME, NULL);
430         if (dbgaufs)
431                 err = 0;
432         return err;
433 }