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