2 * Copyright (C) 2005-2017 Junjiro R. Okajima
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.
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.
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/>.
22 #include <linux/debugfs.h>
26 #error DEBUG_FS depends upon SYSFS
29 static struct dentry
*dbgaufs
;
30 static const mode_t dbgaufs_mode
= S_IRUSR
| S_IRGRP
| S_IROTH
;
32 /* 20 is max digits length of ulong 64 */
39 * common function for all XINO files
41 static int dbgaufs_xi_release(struct inode
*inode __maybe_unused
,
44 kfree(file
->private_data
);
48 static int dbgaufs_xi_open(struct file
*xf
, struct file
*file
, int do_fcnt
)
52 struct dbgaufs_arg
*p
;
55 p
= kmalloc(sizeof(*p
), GFP_NOFS
);
61 file
->private_data
= p
;
65 err
= vfsub_getattr(&xf
->f_path
, &st
);
69 (p
->a
, sizeof(p
->a
), "%ld, %llux%u %lld\n",
70 (long)file_count(xf
), st
.blocks
, st
.blksize
,
73 p
->n
= snprintf(p
->a
, sizeof(p
->a
), "%llux%u %lld\n",
74 st
.blocks
, st
.blksize
,
76 AuDebugOn(p
->n
>= sizeof(p
->a
));
78 p
->n
= snprintf(p
->a
, sizeof(p
->a
), "err %d\n", err
);
87 static ssize_t
dbgaufs_xi_read(struct file
*file
, char __user
*buf
,
88 size_t count
, loff_t
*ppos
)
90 struct dbgaufs_arg
*p
;
92 p
= file
->private_data
;
93 return simple_read_from_buffer(buf
, count
, ppos
, p
->a
, p
->n
);
96 /* ---------------------------------------------------------------------- */
98 struct dbgaufs_plink_arg
{
103 static int dbgaufs_plink_release(struct inode
*inode __maybe_unused
,
106 free_page((unsigned long)file
->private_data
);
110 static int dbgaufs_plink_open(struct inode
*inode
, struct file
*file
)
113 unsigned long n
, sum
;
114 struct dbgaufs_plink_arg
*p
;
115 struct au_sbinfo
*sbinfo
;
116 struct super_block
*sb
;
117 struct hlist_bl_head
*hbl
;
120 p
= (void *)get_zeroed_page(GFP_NOFS
);
125 sbinfo
= inode
->i_private
;
127 si_noflush_read_lock(sb
);
128 if (au_opt_test(au_mntflags(sb
), PLINK
)) {
129 limit
= PAGE_SIZE
- sizeof(p
->n
);
131 /* the number of buckets */
132 n
= snprintf(p
->a
+ p
->n
, limit
, "%d\n", AuPlink_NHASH
);
137 for (i
= 0, hbl
= sbinfo
->si_plink
; i
< AuPlink_NHASH
;
139 n
= au_hbl_count(hbl
);
142 n
= snprintf(p
->a
+ p
->n
, limit
, "%lu ", n
);
145 if (unlikely(limit
<= 0))
148 p
->a
[p
->n
- 1] = '\n';
150 /* the sum of plinks */
151 n
= snprintf(p
->a
+ p
->n
, limit
, "%lu\n", sum
);
154 if (unlikely(limit
<= 0))
157 #define str "1\n0\n0\n"
158 p
->n
= sizeof(str
) - 1;
165 file
->private_data
= p
;
166 goto out
; /* success */
169 free_page((unsigned long)p
);
174 static ssize_t
dbgaufs_plink_read(struct file
*file
, char __user
*buf
,
175 size_t count
, loff_t
*ppos
)
177 struct dbgaufs_plink_arg
*p
;
179 p
= file
->private_data
;
180 return simple_read_from_buffer(buf
, count
, ppos
, p
->a
, p
->n
);
183 static const struct file_operations dbgaufs_plink_fop
= {
184 .owner
= THIS_MODULE
,
185 .open
= dbgaufs_plink_open
,
186 .release
= dbgaufs_plink_release
,
187 .read
= dbgaufs_plink_read
190 /* ---------------------------------------------------------------------- */
192 static int dbgaufs_xib_open(struct inode
*inode
, struct file
*file
)
195 struct au_sbinfo
*sbinfo
;
196 struct super_block
*sb
;
198 sbinfo
= inode
->i_private
;
200 si_noflush_read_lock(sb
);
201 err
= dbgaufs_xi_open(sbinfo
->si_xib
, file
, /*do_fcnt*/0);
206 static const struct file_operations dbgaufs_xib_fop
= {
207 .owner
= THIS_MODULE
,
208 .open
= dbgaufs_xib_open
,
209 .release
= dbgaufs_xi_release
,
210 .read
= dbgaufs_xi_read
213 /* ---------------------------------------------------------------------- */
215 #define DbgaufsXi_PREFIX "xi"
217 static int dbgaufs_xino_open(struct inode
*inode
, struct file
*file
)
221 struct au_sbinfo
*sbinfo
;
222 struct super_block
*sb
;
228 name
= &file
->f_path
.dentry
->d_name
;
229 if (unlikely(name
->len
< sizeof(DbgaufsXi_PREFIX
)
230 || memcmp(name
->name
, DbgaufsXi_PREFIX
,
231 sizeof(DbgaufsXi_PREFIX
) - 1)))
233 err
= kstrtol(name
->name
+ sizeof(DbgaufsXi_PREFIX
) - 1, 10, &l
);
237 sbinfo
= inode
->i_private
;
239 si_noflush_read_lock(sb
);
240 if (l
<= au_sbbot(sb
)) {
241 xf
= au_sbr(sb
, (aufs_bindex_t
)l
)->br_xino
.xi_file
;
242 err
= dbgaufs_xi_open(xf
, file
, /*do_fcnt*/1);
251 static const struct file_operations dbgaufs_xino_fop
= {
252 .owner
= THIS_MODULE
,
253 .open
= dbgaufs_xino_open
,
254 .release
= dbgaufs_xi_release
,
255 .read
= dbgaufs_xi_read
258 void dbgaufs_brs_del(struct super_block
*sb
, aufs_bindex_t bindex
)
261 struct au_branch
*br
;
262 struct au_xino_file
*xi
;
264 if (!au_sbi(sb
)->si_dbgaufs
)
268 for (; bindex
<= bbot
; bindex
++) {
269 br
= au_sbr(sb
, bindex
);
271 /* debugfs acquires the parent i_mutex */
273 debugfs_remove(xi
->xi_dbgaufs
);
275 xi
->xi_dbgaufs
= NULL
;
279 void dbgaufs_brs_add(struct super_block
*sb
, aufs_bindex_t bindex
)
281 struct au_sbinfo
*sbinfo
;
282 struct dentry
*parent
;
283 struct au_branch
*br
;
284 struct au_xino_file
*xi
;
286 char name
[sizeof(DbgaufsXi_PREFIX
) + 5]; /* "xi" bindex NULL */
289 parent
= sbinfo
->si_dbgaufs
;
294 for (; bindex
<= bbot
; bindex
++) {
295 snprintf(name
, sizeof(name
), DbgaufsXi_PREFIX
"%d", bindex
);
296 br
= au_sbr(sb
, bindex
);
298 AuDebugOn(xi
->xi_dbgaufs
);
299 /* debugfs acquires the parent i_mutex */
301 xi
->xi_dbgaufs
= debugfs_create_file(name
, dbgaufs_mode
, parent
,
302 sbinfo
, &dbgaufs_xino_fop
);
304 /* ignore an error */
305 if (unlikely(!xi
->xi_dbgaufs
))
306 AuWarn1("failed %s under debugfs\n", name
);
310 /* ---------------------------------------------------------------------- */
312 #ifdef CONFIG_AUFS_EXPORT
313 static int dbgaufs_xigen_open(struct inode
*inode
, struct file
*file
)
316 struct au_sbinfo
*sbinfo
;
317 struct super_block
*sb
;
319 sbinfo
= inode
->i_private
;
321 si_noflush_read_lock(sb
);
322 err
= dbgaufs_xi_open(sbinfo
->si_xigen
, file
, /*do_fcnt*/0);
327 static const struct file_operations dbgaufs_xigen_fop
= {
328 .owner
= THIS_MODULE
,
329 .open
= dbgaufs_xigen_open
,
330 .release
= dbgaufs_xi_release
,
331 .read
= dbgaufs_xi_read
334 static int dbgaufs_xigen_init(struct au_sbinfo
*sbinfo
)
339 * This function is a dynamic '__init' function actually,
340 * so the tiny check for si_rwsem is unnecessary.
342 /* AuRwMustWriteLock(&sbinfo->si_rwsem); */
345 sbinfo
->si_dbgaufs_xigen
= debugfs_create_file
346 ("xigen", dbgaufs_mode
, sbinfo
->si_dbgaufs
, sbinfo
,
348 if (sbinfo
->si_dbgaufs_xigen
)
354 static int dbgaufs_xigen_init(struct au_sbinfo
*sbinfo
)
358 #endif /* CONFIG_AUFS_EXPORT */
360 /* ---------------------------------------------------------------------- */
362 void dbgaufs_si_fin(struct au_sbinfo
*sbinfo
)
365 * This function is a dynamic '__fin' function actually,
366 * so the tiny check for si_rwsem is unnecessary.
368 /* AuRwMustWriteLock(&sbinfo->si_rwsem); */
370 debugfs_remove_recursive(sbinfo
->si_dbgaufs
);
371 sbinfo
->si_dbgaufs
= NULL
;
372 kobject_put(&sbinfo
->si_kobj
);
375 int dbgaufs_si_init(struct au_sbinfo
*sbinfo
)
378 char name
[SysaufsSiNameLen
];
381 * This function is a dynamic '__init' function actually,
382 * so the tiny check for si_rwsem is unnecessary.
384 /* AuRwMustWriteLock(&sbinfo->si_rwsem); */
388 AuErr1("/debug/aufs is uninitialized\n");
393 sysaufs_name(sbinfo
, name
);
394 sbinfo
->si_dbgaufs
= debugfs_create_dir(name
, dbgaufs
);
395 if (unlikely(!sbinfo
->si_dbgaufs
))
397 kobject_get(&sbinfo
->si_kobj
);
399 sbinfo
->si_dbgaufs_xib
= debugfs_create_file
400 ("xib", dbgaufs_mode
, sbinfo
->si_dbgaufs
, sbinfo
,
402 if (unlikely(!sbinfo
->si_dbgaufs_xib
))
405 sbinfo
->si_dbgaufs_plink
= debugfs_create_file
406 ("plink", dbgaufs_mode
, sbinfo
->si_dbgaufs
, sbinfo
,
408 if (unlikely(!sbinfo
->si_dbgaufs_plink
))
411 err
= dbgaufs_xigen_init(sbinfo
);
413 goto out
; /* success */
416 dbgaufs_si_fin(sbinfo
);
421 /* ---------------------------------------------------------------------- */
423 void dbgaufs_fin(void)
425 debugfs_remove(dbgaufs
);
428 int __init
dbgaufs_init(void)
433 dbgaufs
= debugfs_create_dir(AUFS_NAME
, NULL
);