diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /fs/debugfs | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'fs/debugfs')
-rw-r--r-- | fs/debugfs/file.c | 237 | ||||
-rw-r--r-- | fs/debugfs/inode.c | 267 |
2 files changed, 79 insertions, 425 deletions
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index c5ca6ae5a30..90f76575c05 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c | |||
@@ -15,12 +15,9 @@ | |||
15 | 15 | ||
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
18 | #include <linux/seq_file.h> | ||
19 | #include <linux/pagemap.h> | 18 | #include <linux/pagemap.h> |
20 | #include <linux/namei.h> | 19 | #include <linux/namei.h> |
21 | #include <linux/debugfs.h> | 20 | #include <linux/debugfs.h> |
22 | #include <linux/io.h> | ||
23 | #include <linux/slab.h> | ||
24 | 21 | ||
25 | static ssize_t default_read_file(struct file *file, char __user *buf, | 22 | static ssize_t default_read_file(struct file *file, char __user *buf, |
26 | size_t count, loff_t *ppos) | 23 | size_t count, loff_t *ppos) |
@@ -34,10 +31,18 @@ static ssize_t default_write_file(struct file *file, const char __user *buf, | |||
34 | return count; | 31 | return count; |
35 | } | 32 | } |
36 | 33 | ||
34 | static int default_open(struct inode *inode, struct file *file) | ||
35 | { | ||
36 | if (inode->i_private) | ||
37 | file->private_data = inode->i_private; | ||
38 | |||
39 | return 0; | ||
40 | } | ||
41 | |||
37 | const struct file_operations debugfs_file_operations = { | 42 | const struct file_operations debugfs_file_operations = { |
38 | .read = default_read_file, | 43 | .read = default_read_file, |
39 | .write = default_write_file, | 44 | .write = default_write_file, |
40 | .open = simple_open, | 45 | .open = default_open, |
41 | .llseek = noop_llseek, | 46 | .llseek = noop_llseek, |
42 | }; | 47 | }; |
43 | 48 | ||
@@ -90,7 +95,7 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u8_wo, NULL, debugfs_u8_set, "%llu\n"); | |||
90 | * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling | 95 | * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling |
91 | * code. | 96 | * code. |
92 | */ | 97 | */ |
93 | struct dentry *debugfs_create_u8(const char *name, umode_t mode, | 98 | struct dentry *debugfs_create_u8(const char *name, mode_t mode, |
94 | struct dentry *parent, u8 *value) | 99 | struct dentry *parent, u8 *value) |
95 | { | 100 | { |
96 | /* if there are no write bits set, make read only */ | 101 | /* if there are no write bits set, make read only */ |
@@ -142,7 +147,7 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u16_wo, NULL, debugfs_u16_set, "%llu\n"); | |||
142 | * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling | 147 | * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling |
143 | * code. | 148 | * code. |
144 | */ | 149 | */ |
145 | struct dentry *debugfs_create_u16(const char *name, umode_t mode, | 150 | struct dentry *debugfs_create_u16(const char *name, mode_t mode, |
146 | struct dentry *parent, u16 *value) | 151 | struct dentry *parent, u16 *value) |
147 | { | 152 | { |
148 | /* if there are no write bits set, make read only */ | 153 | /* if there are no write bits set, make read only */ |
@@ -194,7 +199,7 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u32_wo, NULL, debugfs_u32_set, "%llu\n"); | |||
194 | * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling | 199 | * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling |
195 | * code. | 200 | * code. |
196 | */ | 201 | */ |
197 | struct dentry *debugfs_create_u32(const char *name, umode_t mode, | 202 | struct dentry *debugfs_create_u32(const char *name, mode_t mode, |
198 | struct dentry *parent, u32 *value) | 203 | struct dentry *parent, u32 *value) |
199 | { | 204 | { |
200 | /* if there are no write bits set, make read only */ | 205 | /* if there are no write bits set, make read only */ |
@@ -247,7 +252,7 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%llu\n"); | |||
247 | * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling | 252 | * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling |
248 | * code. | 253 | * code. |
249 | */ | 254 | */ |
250 | struct dentry *debugfs_create_u64(const char *name, umode_t mode, | 255 | struct dentry *debugfs_create_u64(const char *name, mode_t mode, |
251 | struct dentry *parent, u64 *value) | 256 | struct dentry *parent, u64 *value) |
252 | { | 257 | { |
253 | /* if there are no write bits set, make read only */ | 258 | /* if there are no write bits set, make read only */ |
@@ -293,7 +298,7 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_x64, debugfs_u64_get, debugfs_u64_set, "0x%016llx\n | |||
293 | * @value: a pointer to the variable that the file should read to and write | 298 | * @value: a pointer to the variable that the file should read to and write |
294 | * from. | 299 | * from. |
295 | */ | 300 | */ |
296 | struct dentry *debugfs_create_x8(const char *name, umode_t mode, | 301 | struct dentry *debugfs_create_x8(const char *name, mode_t mode, |
297 | struct dentry *parent, u8 *value) | 302 | struct dentry *parent, u8 *value) |
298 | { | 303 | { |
299 | /* if there are no write bits set, make read only */ | 304 | /* if there are no write bits set, make read only */ |
@@ -317,7 +322,7 @@ EXPORT_SYMBOL_GPL(debugfs_create_x8); | |||
317 | * @value: a pointer to the variable that the file should read to and write | 322 | * @value: a pointer to the variable that the file should read to and write |
318 | * from. | 323 | * from. |
319 | */ | 324 | */ |
320 | struct dentry *debugfs_create_x16(const char *name, umode_t mode, | 325 | struct dentry *debugfs_create_x16(const char *name, mode_t mode, |
321 | struct dentry *parent, u16 *value) | 326 | struct dentry *parent, u16 *value) |
322 | { | 327 | { |
323 | /* if there are no write bits set, make read only */ | 328 | /* if there are no write bits set, make read only */ |
@@ -341,7 +346,7 @@ EXPORT_SYMBOL_GPL(debugfs_create_x16); | |||
341 | * @value: a pointer to the variable that the file should read to and write | 346 | * @value: a pointer to the variable that the file should read to and write |
342 | * from. | 347 | * from. |
343 | */ | 348 | */ |
344 | struct dentry *debugfs_create_x32(const char *name, umode_t mode, | 349 | struct dentry *debugfs_create_x32(const char *name, mode_t mode, |
345 | struct dentry *parent, u32 *value) | 350 | struct dentry *parent, u32 *value) |
346 | { | 351 | { |
347 | /* if there are no write bits set, make read only */ | 352 | /* if there are no write bits set, make read only */ |
@@ -365,7 +370,7 @@ EXPORT_SYMBOL_GPL(debugfs_create_x32); | |||
365 | * @value: a pointer to the variable that the file should read to and write | 370 | * @value: a pointer to the variable that the file should read to and write |
366 | * from. | 371 | * from. |
367 | */ | 372 | */ |
368 | struct dentry *debugfs_create_x64(const char *name, umode_t mode, | 373 | struct dentry *debugfs_create_x64(const char *name, mode_t mode, |
369 | struct dentry *parent, u64 *value) | 374 | struct dentry *parent, u64 *value) |
370 | { | 375 | { |
371 | return debugfs_create_file(name, mode, parent, value, &fops_x64); | 376 | return debugfs_create_file(name, mode, parent, value, &fops_x64); |
@@ -396,7 +401,7 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_size_t, debugfs_size_t_get, debugfs_size_t_set, | |||
396 | * @value: a pointer to the variable that the file should read to and write | 401 | * @value: a pointer to the variable that the file should read to and write |
397 | * from. | 402 | * from. |
398 | */ | 403 | */ |
399 | struct dentry *debugfs_create_size_t(const char *name, umode_t mode, | 404 | struct dentry *debugfs_create_size_t(const char *name, mode_t mode, |
400 | struct dentry *parent, size_t *value) | 405 | struct dentry *parent, size_t *value) |
401 | { | 406 | { |
402 | return debugfs_create_file(name, mode, parent, value, &fops_size_t); | 407 | return debugfs_create_file(name, mode, parent, value, &fops_size_t); |
@@ -440,7 +445,7 @@ static ssize_t write_file_bool(struct file *file, const char __user *user_buf, | |||
440 | static const struct file_operations fops_bool = { | 445 | static const struct file_operations fops_bool = { |
441 | .read = read_file_bool, | 446 | .read = read_file_bool, |
442 | .write = write_file_bool, | 447 | .write = write_file_bool, |
443 | .open = simple_open, | 448 | .open = default_open, |
444 | .llseek = default_llseek, | 449 | .llseek = default_llseek, |
445 | }; | 450 | }; |
446 | 451 | ||
@@ -468,7 +473,7 @@ static const struct file_operations fops_bool = { | |||
468 | * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling | 473 | * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling |
469 | * code. | 474 | * code. |
470 | */ | 475 | */ |
471 | struct dentry *debugfs_create_bool(const char *name, umode_t mode, | 476 | struct dentry *debugfs_create_bool(const char *name, mode_t mode, |
472 | struct dentry *parent, u32 *value) | 477 | struct dentry *parent, u32 *value) |
473 | { | 478 | { |
474 | return debugfs_create_file(name, mode, parent, value, &fops_bool); | 479 | return debugfs_create_file(name, mode, parent, value, &fops_bool); |
@@ -485,7 +490,7 @@ static ssize_t read_file_blob(struct file *file, char __user *user_buf, | |||
485 | 490 | ||
486 | static const struct file_operations fops_blob = { | 491 | static const struct file_operations fops_blob = { |
487 | .read = read_file_blob, | 492 | .read = read_file_blob, |
488 | .open = simple_open, | 493 | .open = default_open, |
489 | .llseek = default_llseek, | 494 | .llseek = default_llseek, |
490 | }; | 495 | }; |
491 | 496 | ||
@@ -513,208 +518,10 @@ static const struct file_operations fops_blob = { | |||
513 | * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling | 518 | * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling |
514 | * code. | 519 | * code. |
515 | */ | 520 | */ |
516 | struct dentry *debugfs_create_blob(const char *name, umode_t mode, | 521 | struct dentry *debugfs_create_blob(const char *name, mode_t mode, |
517 | struct dentry *parent, | 522 | struct dentry *parent, |
518 | struct debugfs_blob_wrapper *blob) | 523 | struct debugfs_blob_wrapper *blob) |
519 | { | 524 | { |
520 | return debugfs_create_file(name, mode, parent, blob, &fops_blob); | 525 | return debugfs_create_file(name, mode, parent, blob, &fops_blob); |
521 | } | 526 | } |
522 | EXPORT_SYMBOL_GPL(debugfs_create_blob); | 527 | EXPORT_SYMBOL_GPL(debugfs_create_blob); |
523 | |||
524 | struct array_data { | ||
525 | void *array; | ||
526 | u32 elements; | ||
527 | }; | ||
528 | |||
529 | static size_t u32_format_array(char *buf, size_t bufsize, | ||
530 | u32 *array, int array_size) | ||
531 | { | ||
532 | size_t ret = 0; | ||
533 | |||
534 | while (--array_size >= 0) { | ||
535 | size_t len; | ||
536 | char term = array_size ? ' ' : '\n'; | ||
537 | |||
538 | len = snprintf(buf, bufsize, "%u%c", *array++, term); | ||
539 | ret += len; | ||
540 | |||
541 | buf += len; | ||
542 | bufsize -= len; | ||
543 | } | ||
544 | return ret; | ||
545 | } | ||
546 | |||
547 | static int u32_array_open(struct inode *inode, struct file *file) | ||
548 | { | ||
549 | struct array_data *data = inode->i_private; | ||
550 | int size, elements = data->elements; | ||
551 | char *buf; | ||
552 | |||
553 | /* | ||
554 | * Max size: | ||
555 | * - 10 digits + ' '/'\n' = 11 bytes per number | ||
556 | * - terminating NUL character | ||
557 | */ | ||
558 | size = elements*11; | ||
559 | buf = kmalloc(size+1, GFP_KERNEL); | ||
560 | if (!buf) | ||
561 | return -ENOMEM; | ||
562 | buf[size] = 0; | ||
563 | |||
564 | file->private_data = buf; | ||
565 | u32_format_array(buf, size, data->array, data->elements); | ||
566 | |||
567 | return nonseekable_open(inode, file); | ||
568 | } | ||
569 | |||
570 | static ssize_t u32_array_read(struct file *file, char __user *buf, size_t len, | ||
571 | loff_t *ppos) | ||
572 | { | ||
573 | size_t size = strlen(file->private_data); | ||
574 | |||
575 | return simple_read_from_buffer(buf, len, ppos, | ||
576 | file->private_data, size); | ||
577 | } | ||
578 | |||
579 | static int u32_array_release(struct inode *inode, struct file *file) | ||
580 | { | ||
581 | kfree(file->private_data); | ||
582 | |||
583 | return 0; | ||
584 | } | ||
585 | |||
586 | static const struct file_operations u32_array_fops = { | ||
587 | .owner = THIS_MODULE, | ||
588 | .open = u32_array_open, | ||
589 | .release = u32_array_release, | ||
590 | .read = u32_array_read, | ||
591 | .llseek = no_llseek, | ||
592 | }; | ||
593 | |||
594 | /** | ||
595 | * debugfs_create_u32_array - create a debugfs file that is used to read u32 | ||
596 | * array. | ||
597 | * @name: a pointer to a string containing the name of the file to create. | ||
598 | * @mode: the permission that the file should have. | ||
599 | * @parent: a pointer to the parent dentry for this file. This should be a | ||
600 | * directory dentry if set. If this parameter is %NULL, then the | ||
601 | * file will be created in the root of the debugfs filesystem. | ||
602 | * @array: u32 array that provides data. | ||
603 | * @elements: total number of elements in the array. | ||
604 | * | ||
605 | * This function creates a file in debugfs with the given name that exports | ||
606 | * @array as data. If the @mode variable is so set it can be read from. | ||
607 | * Writing is not supported. Seek within the file is also not supported. | ||
608 | * Once array is created its size can not be changed. | ||
609 | * | ||
610 | * The function returns a pointer to dentry on success. If debugfs is not | ||
611 | * enabled in the kernel, the value -%ENODEV will be returned. | ||
612 | */ | ||
613 | struct dentry *debugfs_create_u32_array(const char *name, umode_t mode, | ||
614 | struct dentry *parent, | ||
615 | u32 *array, u32 elements) | ||
616 | { | ||
617 | struct array_data *data = kmalloc(sizeof(*data), GFP_KERNEL); | ||
618 | |||
619 | if (data == NULL) | ||
620 | return NULL; | ||
621 | |||
622 | data->array = array; | ||
623 | data->elements = elements; | ||
624 | |||
625 | return debugfs_create_file(name, mode, parent, data, &u32_array_fops); | ||
626 | } | ||
627 | EXPORT_SYMBOL_GPL(debugfs_create_u32_array); | ||
628 | |||
629 | #ifdef CONFIG_HAS_IOMEM | ||
630 | |||
631 | /* | ||
632 | * The regset32 stuff is used to print 32-bit registers using the | ||
633 | * seq_file utilities. We offer printing a register set in an already-opened | ||
634 | * sequential file or create a debugfs file that only prints a regset32. | ||
635 | */ | ||
636 | |||
637 | /** | ||
638 | * debugfs_print_regs32 - use seq_print to describe a set of registers | ||
639 | * @s: the seq_file structure being used to generate output | ||
640 | * @regs: an array if struct debugfs_reg32 structures | ||
641 | * @nregs: the length of the above array | ||
642 | * @base: the base address to be used in reading the registers | ||
643 | * @prefix: a string to be prefixed to every output line | ||
644 | * | ||
645 | * This function outputs a text block describing the current values of | ||
646 | * some 32-bit hardware registers. It is meant to be used within debugfs | ||
647 | * files based on seq_file that need to show registers, intermixed with other | ||
648 | * information. The prefix argument may be used to specify a leading string, | ||
649 | * because some peripherals have several blocks of identical registers, | ||
650 | * for example configuration of dma channels | ||
651 | */ | ||
652 | int debugfs_print_regs32(struct seq_file *s, const struct debugfs_reg32 *regs, | ||
653 | int nregs, void __iomem *base, char *prefix) | ||
654 | { | ||
655 | int i, ret = 0; | ||
656 | |||
657 | for (i = 0; i < nregs; i++, regs++) { | ||
658 | if (prefix) | ||
659 | ret += seq_printf(s, "%s", prefix); | ||
660 | ret += seq_printf(s, "%s = 0x%08x\n", regs->name, | ||
661 | readl(base + regs->offset)); | ||
662 | } | ||
663 | return ret; | ||
664 | } | ||
665 | EXPORT_SYMBOL_GPL(debugfs_print_regs32); | ||
666 | |||
667 | static int debugfs_show_regset32(struct seq_file *s, void *data) | ||
668 | { | ||
669 | struct debugfs_regset32 *regset = s->private; | ||
670 | |||
671 | debugfs_print_regs32(s, regset->regs, regset->nregs, regset->base, ""); | ||
672 | return 0; | ||
673 | } | ||
674 | |||
675 | static int debugfs_open_regset32(struct inode *inode, struct file *file) | ||
676 | { | ||
677 | return single_open(file, debugfs_show_regset32, inode->i_private); | ||
678 | } | ||
679 | |||
680 | static const struct file_operations fops_regset32 = { | ||
681 | .open = debugfs_open_regset32, | ||
682 | .read = seq_read, | ||
683 | .llseek = seq_lseek, | ||
684 | .release = single_release, | ||
685 | }; | ||
686 | |||
687 | /** | ||
688 | * debugfs_create_regset32 - create a debugfs file that returns register values | ||
689 | * @name: a pointer to a string containing the name of the file to create. | ||
690 | * @mode: the permission that the file should have | ||
691 | * @parent: a pointer to the parent dentry for this file. This should be a | ||
692 | * directory dentry if set. If this parameter is %NULL, then the | ||
693 | * file will be created in the root of the debugfs filesystem. | ||
694 | * @regset: a pointer to a struct debugfs_regset32, which contains a pointer | ||
695 | * to an array of register definitions, the array size and the base | ||
696 | * address where the register bank is to be found. | ||
697 | * | ||
698 | * This function creates a file in debugfs with the given name that reports | ||
699 | * the names and values of a set of 32-bit registers. If the @mode variable | ||
700 | * is so set it can be read from. Writing is not supported. | ||
701 | * | ||
702 | * This function will return a pointer to a dentry if it succeeds. This | ||
703 | * pointer must be passed to the debugfs_remove() function when the file is | ||
704 | * to be removed (no automatic cleanup happens if your module is unloaded, | ||
705 | * you are responsible here.) If an error occurs, %NULL will be returned. | ||
706 | * | ||
707 | * If debugfs is not enabled in the kernel, the value -%ENODEV will be | ||
708 | * returned. It is not wise to check for this value, but rather, check for | ||
709 | * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling | ||
710 | * code. | ||
711 | */ | ||
712 | struct dentry *debugfs_create_regset32(const char *name, umode_t mode, | ||
713 | struct dentry *parent, | ||
714 | struct debugfs_regset32 *regset) | ||
715 | { | ||
716 | return debugfs_create_file(name, mode, parent, regset, &fops_regset32); | ||
717 | } | ||
718 | EXPORT_SYMBOL_GPL(debugfs_create_regset32); | ||
719 | |||
720 | #endif /* CONFIG_HAS_IOMEM */ | ||
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index a5f12b7e228..e7a7a2f0732 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * inode.c - part of debugfs, a tiny little debug file system | 2 | * file.c - part of debugfs, a tiny little debug file system |
3 | * | 3 | * |
4 | * Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com> | 4 | * Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com> |
5 | * Copyright (C) 2004 IBM Inc. | 5 | * Copyright (C) 2004 IBM Inc. |
@@ -23,18 +23,14 @@ | |||
23 | #include <linux/debugfs.h> | 23 | #include <linux/debugfs.h> |
24 | #include <linux/fsnotify.h> | 24 | #include <linux/fsnotify.h> |
25 | #include <linux/string.h> | 25 | #include <linux/string.h> |
26 | #include <linux/seq_file.h> | ||
27 | #include <linux/parser.h> | ||
28 | #include <linux/magic.h> | 26 | #include <linux/magic.h> |
29 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
30 | 28 | ||
31 | #define DEBUGFS_DEFAULT_MODE 0700 | ||
32 | |||
33 | static struct vfsmount *debugfs_mount; | 29 | static struct vfsmount *debugfs_mount; |
34 | static int debugfs_mount_count; | 30 | static int debugfs_mount_count; |
35 | static bool debugfs_registered; | 31 | static bool debugfs_registered; |
36 | 32 | ||
37 | static struct inode *debugfs_get_inode(struct super_block *sb, umode_t mode, dev_t dev, | 33 | static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t dev, |
38 | void *data, const struct file_operations *fops) | 34 | void *data, const struct file_operations *fops) |
39 | 35 | ||
40 | { | 36 | { |
@@ -54,11 +50,13 @@ static struct inode *debugfs_get_inode(struct super_block *sb, umode_t mode, dev | |||
54 | break; | 50 | break; |
55 | case S_IFLNK: | 51 | case S_IFLNK: |
56 | inode->i_op = &debugfs_link_operations; | 52 | inode->i_op = &debugfs_link_operations; |
53 | inode->i_fop = fops; | ||
57 | inode->i_private = data; | 54 | inode->i_private = data; |
58 | break; | 55 | break; |
59 | case S_IFDIR: | 56 | case S_IFDIR: |
60 | inode->i_op = &simple_dir_inode_operations; | 57 | inode->i_op = &simple_dir_inode_operations; |
61 | inode->i_fop = &simple_dir_operations; | 58 | inode->i_fop = fops ? fops : &simple_dir_operations; |
59 | inode->i_private = data; | ||
62 | 60 | ||
63 | /* directory inodes start off with i_nlink == 2 | 61 | /* directory inodes start off with i_nlink == 2 |
64 | * (for "." entry) */ | 62 | * (for "." entry) */ |
@@ -71,7 +69,7 @@ static struct inode *debugfs_get_inode(struct super_block *sb, umode_t mode, dev | |||
71 | 69 | ||
72 | /* SMP-safe */ | 70 | /* SMP-safe */ |
73 | static int debugfs_mknod(struct inode *dir, struct dentry *dentry, | 71 | static int debugfs_mknod(struct inode *dir, struct dentry *dentry, |
74 | umode_t mode, dev_t dev, void *data, | 72 | int mode, dev_t dev, void *data, |
75 | const struct file_operations *fops) | 73 | const struct file_operations *fops) |
76 | { | 74 | { |
77 | struct inode *inode; | 75 | struct inode *inode; |
@@ -89,12 +87,13 @@ static int debugfs_mknod(struct inode *dir, struct dentry *dentry, | |||
89 | return error; | 87 | return error; |
90 | } | 88 | } |
91 | 89 | ||
92 | static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | 90 | static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, int mode, |
91 | void *data, const struct file_operations *fops) | ||
93 | { | 92 | { |
94 | int res; | 93 | int res; |
95 | 94 | ||
96 | mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR; | 95 | mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR; |
97 | res = debugfs_mknod(dir, dentry, mode, 0, NULL, NULL); | 96 | res = debugfs_mknod(dir, dentry, mode, 0, data, fops); |
98 | if (!res) { | 97 | if (!res) { |
99 | inc_nlink(dir); | 98 | inc_nlink(dir); |
100 | fsnotify_mkdir(dir, dentry); | 99 | fsnotify_mkdir(dir, dentry); |
@@ -102,14 +101,14 @@ static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | |||
102 | return res; | 101 | return res; |
103 | } | 102 | } |
104 | 103 | ||
105 | static int debugfs_link(struct inode *dir, struct dentry *dentry, umode_t mode, | 104 | static int debugfs_link(struct inode *dir, struct dentry *dentry, int mode, |
106 | void *data) | 105 | void *data, const struct file_operations *fops) |
107 | { | 106 | { |
108 | mode = (mode & S_IALLUGO) | S_IFLNK; | 107 | mode = (mode & S_IALLUGO) | S_IFLNK; |
109 | return debugfs_mknod(dir, dentry, mode, 0, data, NULL); | 108 | return debugfs_mknod(dir, dentry, mode, 0, data, fops); |
110 | } | 109 | } |
111 | 110 | ||
112 | static int debugfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, | 111 | static int debugfs_create(struct inode *dir, struct dentry *dentry, int mode, |
113 | void *data, const struct file_operations *fops) | 112 | void *data, const struct file_operations *fops) |
114 | { | 113 | { |
115 | int res; | 114 | int res; |
@@ -126,164 +125,11 @@ static inline int debugfs_positive(struct dentry *dentry) | |||
126 | return dentry->d_inode && !d_unhashed(dentry); | 125 | return dentry->d_inode && !d_unhashed(dentry); |
127 | } | 126 | } |
128 | 127 | ||
129 | struct debugfs_mount_opts { | ||
130 | kuid_t uid; | ||
131 | kgid_t gid; | ||
132 | umode_t mode; | ||
133 | }; | ||
134 | |||
135 | enum { | ||
136 | Opt_uid, | ||
137 | Opt_gid, | ||
138 | Opt_mode, | ||
139 | Opt_err | ||
140 | }; | ||
141 | |||
142 | static const match_table_t tokens = { | ||
143 | {Opt_uid, "uid=%u"}, | ||
144 | {Opt_gid, "gid=%u"}, | ||
145 | {Opt_mode, "mode=%o"}, | ||
146 | {Opt_err, NULL} | ||
147 | }; | ||
148 | |||
149 | struct debugfs_fs_info { | ||
150 | struct debugfs_mount_opts mount_opts; | ||
151 | }; | ||
152 | |||
153 | static int debugfs_parse_options(char *data, struct debugfs_mount_opts *opts) | ||
154 | { | ||
155 | substring_t args[MAX_OPT_ARGS]; | ||
156 | int option; | ||
157 | int token; | ||
158 | kuid_t uid; | ||
159 | kgid_t gid; | ||
160 | char *p; | ||
161 | |||
162 | opts->mode = DEBUGFS_DEFAULT_MODE; | ||
163 | |||
164 | while ((p = strsep(&data, ",")) != NULL) { | ||
165 | if (!*p) | ||
166 | continue; | ||
167 | |||
168 | token = match_token(p, tokens, args); | ||
169 | switch (token) { | ||
170 | case Opt_uid: | ||
171 | if (match_int(&args[0], &option)) | ||
172 | return -EINVAL; | ||
173 | uid = make_kuid(current_user_ns(), option); | ||
174 | if (!uid_valid(uid)) | ||
175 | return -EINVAL; | ||
176 | opts->uid = uid; | ||
177 | break; | ||
178 | case Opt_gid: | ||
179 | if (match_int(&args[0], &option)) | ||
180 | return -EINVAL; | ||
181 | gid = make_kgid(current_user_ns(), option); | ||
182 | if (!gid_valid(gid)) | ||
183 | return -EINVAL; | ||
184 | opts->gid = gid; | ||
185 | break; | ||
186 | case Opt_mode: | ||
187 | if (match_octal(&args[0], &option)) | ||
188 | return -EINVAL; | ||
189 | opts->mode = option & S_IALLUGO; | ||
190 | break; | ||
191 | /* | ||
192 | * We might like to report bad mount options here; | ||
193 | * but traditionally debugfs has ignored all mount options | ||
194 | */ | ||
195 | } | ||
196 | } | ||
197 | |||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static int debugfs_apply_options(struct super_block *sb) | ||
202 | { | ||
203 | struct debugfs_fs_info *fsi = sb->s_fs_info; | ||
204 | struct inode *inode = sb->s_root->d_inode; | ||
205 | struct debugfs_mount_opts *opts = &fsi->mount_opts; | ||
206 | |||
207 | inode->i_mode &= ~S_IALLUGO; | ||
208 | inode->i_mode |= opts->mode; | ||
209 | |||
210 | inode->i_uid = opts->uid; | ||
211 | inode->i_gid = opts->gid; | ||
212 | |||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static int debugfs_remount(struct super_block *sb, int *flags, char *data) | ||
217 | { | ||
218 | int err; | ||
219 | struct debugfs_fs_info *fsi = sb->s_fs_info; | ||
220 | |||
221 | err = debugfs_parse_options(data, &fsi->mount_opts); | ||
222 | if (err) | ||
223 | goto fail; | ||
224 | |||
225 | debugfs_apply_options(sb); | ||
226 | |||
227 | fail: | ||
228 | return err; | ||
229 | } | ||
230 | |||
231 | static int debugfs_show_options(struct seq_file *m, struct dentry *root) | ||
232 | { | ||
233 | struct debugfs_fs_info *fsi = root->d_sb->s_fs_info; | ||
234 | struct debugfs_mount_opts *opts = &fsi->mount_opts; | ||
235 | |||
236 | if (!uid_eq(opts->uid, GLOBAL_ROOT_UID)) | ||
237 | seq_printf(m, ",uid=%u", | ||
238 | from_kuid_munged(&init_user_ns, opts->uid)); | ||
239 | if (!gid_eq(opts->gid, GLOBAL_ROOT_GID)) | ||
240 | seq_printf(m, ",gid=%u", | ||
241 | from_kgid_munged(&init_user_ns, opts->gid)); | ||
242 | if (opts->mode != DEBUGFS_DEFAULT_MODE) | ||
243 | seq_printf(m, ",mode=%o", opts->mode); | ||
244 | |||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | static const struct super_operations debugfs_super_operations = { | ||
249 | .statfs = simple_statfs, | ||
250 | .remount_fs = debugfs_remount, | ||
251 | .show_options = debugfs_show_options, | ||
252 | }; | ||
253 | |||
254 | static int debug_fill_super(struct super_block *sb, void *data, int silent) | 128 | static int debug_fill_super(struct super_block *sb, void *data, int silent) |
255 | { | 129 | { |
256 | static struct tree_descr debug_files[] = {{""}}; | 130 | static struct tree_descr debug_files[] = {{""}}; |
257 | struct debugfs_fs_info *fsi; | ||
258 | int err; | ||
259 | |||
260 | save_mount_options(sb, data); | ||
261 | |||
262 | fsi = kzalloc(sizeof(struct debugfs_fs_info), GFP_KERNEL); | ||
263 | sb->s_fs_info = fsi; | ||
264 | if (!fsi) { | ||
265 | err = -ENOMEM; | ||
266 | goto fail; | ||
267 | } | ||
268 | |||
269 | err = debugfs_parse_options(data, &fsi->mount_opts); | ||
270 | if (err) | ||
271 | goto fail; | ||
272 | |||
273 | err = simple_fill_super(sb, DEBUGFS_MAGIC, debug_files); | ||
274 | if (err) | ||
275 | goto fail; | ||
276 | 131 | ||
277 | sb->s_op = &debugfs_super_operations; | 132 | return simple_fill_super(sb, DEBUGFS_MAGIC, debug_files); |
278 | |||
279 | debugfs_apply_options(sb); | ||
280 | |||
281 | return 0; | ||
282 | |||
283 | fail: | ||
284 | kfree(fsi); | ||
285 | sb->s_fs_info = NULL; | ||
286 | return err; | ||
287 | } | 133 | } |
288 | 134 | ||
289 | static struct dentry *debug_mount(struct file_system_type *fs_type, | 135 | static struct dentry *debug_mount(struct file_system_type *fs_type, |
@@ -300,19 +146,13 @@ static struct file_system_type debug_fs_type = { | |||
300 | .kill_sb = kill_litter_super, | 146 | .kill_sb = kill_litter_super, |
301 | }; | 147 | }; |
302 | 148 | ||
303 | static struct dentry *__create_file(const char *name, umode_t mode, | 149 | static int debugfs_create_by_name(const char *name, mode_t mode, |
304 | struct dentry *parent, void *data, | 150 | struct dentry *parent, |
305 | const struct file_operations *fops) | 151 | struct dentry **dentry, |
152 | void *data, | ||
153 | const struct file_operations *fops) | ||
306 | { | 154 | { |
307 | struct dentry *dentry = NULL; | 155 | int error = 0; |
308 | int error; | ||
309 | |||
310 | pr_debug("debugfs: creating file '%s'\n",name); | ||
311 | |||
312 | error = simple_pin_fs(&debug_fs_type, &debugfs_mount, | ||
313 | &debugfs_mount_count); | ||
314 | if (error) | ||
315 | goto exit; | ||
316 | 156 | ||
317 | /* If the parent is not specified, we create it in the root. | 157 | /* If the parent is not specified, we create it in the root. |
318 | * We need the root dentry to do this, which is in the super | 158 | * We need the root dentry to do this, which is in the super |
@@ -320,37 +160,32 @@ static struct dentry *__create_file(const char *name, umode_t mode, | |||
320 | * have around. | 160 | * have around. |
321 | */ | 161 | */ |
322 | if (!parent) | 162 | if (!parent) |
323 | parent = debugfs_mount->mnt_root; | 163 | parent = debugfs_mount->mnt_sb->s_root; |
324 | 164 | ||
325 | dentry = NULL; | 165 | *dentry = NULL; |
326 | mutex_lock(&parent->d_inode->i_mutex); | 166 | mutex_lock(&parent->d_inode->i_mutex); |
327 | dentry = lookup_one_len(name, parent, strlen(name)); | 167 | *dentry = lookup_one_len(name, parent, strlen(name)); |
328 | if (!IS_ERR(dentry)) { | 168 | if (!IS_ERR(*dentry)) { |
329 | switch (mode & S_IFMT) { | 169 | switch (mode & S_IFMT) { |
330 | case S_IFDIR: | 170 | case S_IFDIR: |
331 | error = debugfs_mkdir(parent->d_inode, dentry, mode); | 171 | error = debugfs_mkdir(parent->d_inode, *dentry, mode, |
332 | 172 | data, fops); | |
333 | break; | 173 | break; |
334 | case S_IFLNK: | 174 | case S_IFLNK: |
335 | error = debugfs_link(parent->d_inode, dentry, mode, | 175 | error = debugfs_link(parent->d_inode, *dentry, mode, |
336 | data); | 176 | data, fops); |
337 | break; | 177 | break; |
338 | default: | 178 | default: |
339 | error = debugfs_create(parent->d_inode, dentry, mode, | 179 | error = debugfs_create(parent->d_inode, *dentry, mode, |
340 | data, fops); | 180 | data, fops); |
341 | break; | 181 | break; |
342 | } | 182 | } |
343 | dput(dentry); | 183 | dput(*dentry); |
344 | } else | 184 | } else |
345 | error = PTR_ERR(dentry); | 185 | error = PTR_ERR(*dentry); |
346 | mutex_unlock(&parent->d_inode->i_mutex); | 186 | mutex_unlock(&parent->d_inode->i_mutex); |
347 | 187 | ||
348 | if (error) { | 188 | return error; |
349 | dentry = NULL; | ||
350 | simple_release_fs(&debugfs_mount, &debugfs_mount_count); | ||
351 | } | ||
352 | exit: | ||
353 | return dentry; | ||
354 | } | 189 | } |
355 | 190 | ||
356 | /** | 191 | /** |
@@ -379,19 +214,29 @@ exit: | |||
379 | * If debugfs is not enabled in the kernel, the value -%ENODEV will be | 214 | * If debugfs is not enabled in the kernel, the value -%ENODEV will be |
380 | * returned. | 215 | * returned. |
381 | */ | 216 | */ |
382 | struct dentry *debugfs_create_file(const char *name, umode_t mode, | 217 | struct dentry *debugfs_create_file(const char *name, mode_t mode, |
383 | struct dentry *parent, void *data, | 218 | struct dentry *parent, void *data, |
384 | const struct file_operations *fops) | 219 | const struct file_operations *fops) |
385 | { | 220 | { |
386 | switch (mode & S_IFMT) { | 221 | struct dentry *dentry = NULL; |
387 | case S_IFREG: | 222 | int error; |
388 | case 0: | 223 | |
389 | break; | 224 | pr_debug("debugfs: creating file '%s'\n",name); |
390 | default: | ||
391 | BUG(); | ||
392 | } | ||
393 | 225 | ||
394 | return __create_file(name, mode, parent, data, fops); | 226 | error = simple_pin_fs(&debug_fs_type, &debugfs_mount, |
227 | &debugfs_mount_count); | ||
228 | if (error) | ||
229 | goto exit; | ||
230 | |||
231 | error = debugfs_create_by_name(name, mode, parent, &dentry, | ||
232 | data, fops); | ||
233 | if (error) { | ||
234 | dentry = NULL; | ||
235 | simple_release_fs(&debugfs_mount, &debugfs_mount_count); | ||
236 | goto exit; | ||
237 | } | ||
238 | exit: | ||
239 | return dentry; | ||
395 | } | 240 | } |
396 | EXPORT_SYMBOL_GPL(debugfs_create_file); | 241 | EXPORT_SYMBOL_GPL(debugfs_create_file); |
397 | 242 | ||
@@ -415,7 +260,8 @@ EXPORT_SYMBOL_GPL(debugfs_create_file); | |||
415 | */ | 260 | */ |
416 | struct dentry *debugfs_create_dir(const char *name, struct dentry *parent) | 261 | struct dentry *debugfs_create_dir(const char *name, struct dentry *parent) |
417 | { | 262 | { |
418 | return __create_file(name, S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, | 263 | return debugfs_create_file(name, |
264 | S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, | ||
419 | parent, NULL, NULL); | 265 | parent, NULL, NULL); |
420 | } | 266 | } |
421 | EXPORT_SYMBOL_GPL(debugfs_create_dir); | 267 | EXPORT_SYMBOL_GPL(debugfs_create_dir); |
@@ -453,7 +299,8 @@ struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent, | |||
453 | if (!link) | 299 | if (!link) |
454 | return NULL; | 300 | return NULL; |
455 | 301 | ||
456 | result = __create_file(name, S_IFLNK | S_IRWXUGO, parent, link, NULL); | 302 | result = debugfs_create_file(name, S_IFLNK | S_IRWXUGO, parent, link, |
303 | NULL); | ||
457 | if (!result) | 304 | if (!result) |
458 | kfree(link); | 305 | kfree(link); |
459 | return result; | 306 | return result; |
@@ -504,7 +351,7 @@ void debugfs_remove(struct dentry *dentry) | |||
504 | struct dentry *parent; | 351 | struct dentry *parent; |
505 | int ret; | 352 | int ret; |
506 | 353 | ||
507 | if (IS_ERR_OR_NULL(dentry)) | 354 | if (!dentry) |
508 | return; | 355 | return; |
509 | 356 | ||
510 | parent = dentry->d_parent; | 357 | parent = dentry->d_parent; |
@@ -536,7 +383,7 @@ void debugfs_remove_recursive(struct dentry *dentry) | |||
536 | struct dentry *child; | 383 | struct dentry *child; |
537 | struct dentry *parent; | 384 | struct dentry *parent; |
538 | 385 | ||
539 | if (IS_ERR_OR_NULL(dentry)) | 386 | if (!dentry) |
540 | return; | 387 | return; |
541 | 388 | ||
542 | parent = dentry->d_parent; | 389 | parent = dentry->d_parent; |