| .. | .. |
|---|
| 18 | 18 | #include <linux/slab.h> |
|---|
| 19 | 19 | #include <linux/atomic.h> |
|---|
| 20 | 20 | #include <linux/device.h> |
|---|
| 21 | +#include <linux/pm_runtime.h> |
|---|
| 21 | 22 | #include <linux/poll.h> |
|---|
| 23 | +#include <linux/security.h> |
|---|
| 22 | 24 | |
|---|
| 23 | 25 | #include "internal.h" |
|---|
| 24 | 26 | |
|---|
| .. | .. |
|---|
| 136 | 138 | } |
|---|
| 137 | 139 | EXPORT_SYMBOL_GPL(debugfs_file_put); |
|---|
| 138 | 140 | |
|---|
| 141 | +/* |
|---|
| 142 | + * Only permit access to world-readable files when the kernel is locked down. |
|---|
| 143 | + * We also need to exclude any file that has ways to write or alter it as root |
|---|
| 144 | + * can bypass the permissions check. |
|---|
| 145 | + */ |
|---|
| 146 | +static int debugfs_locked_down(struct inode *inode, |
|---|
| 147 | + struct file *filp, |
|---|
| 148 | + const struct file_operations *real_fops) |
|---|
| 149 | +{ |
|---|
| 150 | + if ((inode->i_mode & 07777 & ~0444) == 0 && |
|---|
| 151 | + !(filp->f_mode & FMODE_WRITE) && |
|---|
| 152 | + !real_fops->unlocked_ioctl && |
|---|
| 153 | + !real_fops->compat_ioctl && |
|---|
| 154 | + !real_fops->mmap) |
|---|
| 155 | + return 0; |
|---|
| 156 | + |
|---|
| 157 | + if (security_locked_down(LOCKDOWN_DEBUGFS)) |
|---|
| 158 | + return -EPERM; |
|---|
| 159 | + |
|---|
| 160 | + return 0; |
|---|
| 161 | +} |
|---|
| 162 | + |
|---|
| 139 | 163 | static int open_proxy_open(struct inode *inode, struct file *filp) |
|---|
| 140 | 164 | { |
|---|
| 141 | 165 | struct dentry *dentry = F_DENTRY(filp); |
|---|
| .. | .. |
|---|
| 147 | 171 | return r == -EIO ? -ENOENT : r; |
|---|
| 148 | 172 | |
|---|
| 149 | 173 | real_fops = debugfs_real_fops(filp); |
|---|
| 150 | | - real_fops = fops_get(real_fops); |
|---|
| 151 | | - if (!real_fops) { |
|---|
| 174 | + |
|---|
| 175 | + r = debugfs_locked_down(inode, filp, real_fops); |
|---|
| 176 | + if (r) |
|---|
| 177 | + goto out; |
|---|
| 178 | + |
|---|
| 179 | + if (!fops_get(real_fops)) { |
|---|
| 180 | +#ifdef CONFIG_MODULES |
|---|
| 181 | + if (real_fops->owner && |
|---|
| 182 | + real_fops->owner->state == MODULE_STATE_GOING) { |
|---|
| 183 | + r = -ENXIO; |
|---|
| 184 | + goto out; |
|---|
| 185 | + } |
|---|
| 186 | +#endif |
|---|
| 187 | + |
|---|
| 152 | 188 | /* Huh? Module did not clean up after itself at exit? */ |
|---|
| 153 | 189 | WARN(1, "debugfs file owner did not clean up at exit: %pd", |
|---|
| 154 | 190 | dentry); |
|---|
| .. | .. |
|---|
| 239 | 275 | r = real_fops->release(inode, filp); |
|---|
| 240 | 276 | |
|---|
| 241 | 277 | replace_fops(filp, d_inode(dentry)->i_fop); |
|---|
| 242 | | - kfree((void *)proxy_fops); |
|---|
| 278 | + kfree(proxy_fops); |
|---|
| 243 | 279 | fops_put(real_fops); |
|---|
| 244 | 280 | return r; |
|---|
| 245 | 281 | } |
|---|
| .. | .. |
|---|
| 272 | 308 | return r == -EIO ? -ENOENT : r; |
|---|
| 273 | 309 | |
|---|
| 274 | 310 | real_fops = debugfs_real_fops(filp); |
|---|
| 275 | | - real_fops = fops_get(real_fops); |
|---|
| 276 | | - if (!real_fops) { |
|---|
| 311 | + |
|---|
| 312 | + r = debugfs_locked_down(inode, filp, real_fops); |
|---|
| 313 | + if (r) |
|---|
| 314 | + goto out; |
|---|
| 315 | + |
|---|
| 316 | + if (!fops_get(real_fops)) { |
|---|
| 317 | +#ifdef CONFIG_MODULES |
|---|
| 318 | + if (real_fops->owner && |
|---|
| 319 | + real_fops->owner->state == MODULE_STATE_GOING) { |
|---|
| 320 | + r = -ENXIO; |
|---|
| 321 | + goto out; |
|---|
| 322 | + } |
|---|
| 323 | +#endif |
|---|
| 324 | + |
|---|
| 277 | 325 | /* Huh? Module did not cleanup after itself at exit? */ |
|---|
| 278 | 326 | WARN(1, "debugfs file owner did not clean up at exit: %pd", |
|---|
| 279 | 327 | dentry); |
|---|
| .. | .. |
|---|
| 330 | 378 | } |
|---|
| 331 | 379 | EXPORT_SYMBOL_GPL(debugfs_attr_read); |
|---|
| 332 | 380 | |
|---|
| 333 | | -ssize_t debugfs_attr_write(struct file *file, const char __user *buf, |
|---|
| 334 | | - size_t len, loff_t *ppos) |
|---|
| 381 | +static ssize_t debugfs_attr_write_xsigned(struct file *file, const char __user *buf, |
|---|
| 382 | + size_t len, loff_t *ppos, bool is_signed) |
|---|
| 335 | 383 | { |
|---|
| 336 | 384 | struct dentry *dentry = F_DENTRY(file); |
|---|
| 337 | 385 | ssize_t ret; |
|---|
| .. | .. |
|---|
| 339 | 387 | ret = debugfs_file_get(dentry); |
|---|
| 340 | 388 | if (unlikely(ret)) |
|---|
| 341 | 389 | return ret; |
|---|
| 342 | | - ret = simple_attr_write(file, buf, len, ppos); |
|---|
| 390 | + if (is_signed) |
|---|
| 391 | + ret = simple_attr_write_signed(file, buf, len, ppos); |
|---|
| 392 | + else |
|---|
| 393 | + ret = simple_attr_write(file, buf, len, ppos); |
|---|
| 343 | 394 | debugfs_file_put(dentry); |
|---|
| 344 | 395 | return ret; |
|---|
| 345 | 396 | } |
|---|
| 397 | + |
|---|
| 398 | +ssize_t debugfs_attr_write(struct file *file, const char __user *buf, |
|---|
| 399 | + size_t len, loff_t *ppos) |
|---|
| 400 | +{ |
|---|
| 401 | + return debugfs_attr_write_xsigned(file, buf, len, ppos, false); |
|---|
| 402 | +} |
|---|
| 346 | 403 | EXPORT_SYMBOL_GPL(debugfs_attr_write); |
|---|
| 404 | + |
|---|
| 405 | +ssize_t debugfs_attr_write_signed(struct file *file, const char __user *buf, |
|---|
| 406 | + size_t len, loff_t *ppos) |
|---|
| 407 | +{ |
|---|
| 408 | + return debugfs_attr_write_xsigned(file, buf, len, ppos, true); |
|---|
| 409 | +} |
|---|
| 410 | +EXPORT_SYMBOL_GPL(debugfs_attr_write_signed); |
|---|
| 347 | 411 | |
|---|
| 348 | 412 | static struct dentry *debugfs_create_mode_unsafe(const char *name, umode_t mode, |
|---|
| 349 | 413 | struct dentry *parent, void *value, |
|---|
| .. | .. |
|---|
| 390 | 454 | * This function creates a file in debugfs with the given name that |
|---|
| 391 | 455 | * contains the value of the variable @value. If the @mode variable is so |
|---|
| 392 | 456 | * set, it can be read from, and written to. |
|---|
| 393 | | - * |
|---|
| 394 | | - * This function will return a pointer to a dentry if it succeeds. This |
|---|
| 395 | | - * pointer must be passed to the debugfs_remove() function when the file is |
|---|
| 396 | | - * to be removed (no automatic cleanup happens if your module is unloaded, |
|---|
| 397 | | - * you are responsible here.) If an error occurs, %NULL will be returned. |
|---|
| 398 | | - * |
|---|
| 399 | | - * If debugfs is not enabled in the kernel, the value -%ENODEV will be |
|---|
| 400 | | - * returned. It is not wise to check for this value, but rather, check for |
|---|
| 401 | | - * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling |
|---|
| 402 | | - * code. |
|---|
| 403 | 457 | */ |
|---|
| 404 | | -struct dentry *debugfs_create_u8(const char *name, umode_t mode, |
|---|
| 405 | | - struct dentry *parent, u8 *value) |
|---|
| 458 | +void debugfs_create_u8(const char *name, umode_t mode, struct dentry *parent, |
|---|
| 459 | + u8 *value) |
|---|
| 406 | 460 | { |
|---|
| 407 | | - return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u8, |
|---|
| 461 | + debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u8, |
|---|
| 408 | 462 | &fops_u8_ro, &fops_u8_wo); |
|---|
| 409 | 463 | } |
|---|
| 410 | 464 | EXPORT_SYMBOL_GPL(debugfs_create_u8); |
|---|
| .. | .. |
|---|
| 436 | 490 | * This function creates a file in debugfs with the given name that |
|---|
| 437 | 491 | * contains the value of the variable @value. If the @mode variable is so |
|---|
| 438 | 492 | * set, it can be read from, and written to. |
|---|
| 439 | | - * |
|---|
| 440 | | - * This function will return a pointer to a dentry if it succeeds. This |
|---|
| 441 | | - * pointer must be passed to the debugfs_remove() function when the file is |
|---|
| 442 | | - * to be removed (no automatic cleanup happens if your module is unloaded, |
|---|
| 443 | | - * you are responsible here.) If an error occurs, %NULL will be returned. |
|---|
| 444 | | - * |
|---|
| 445 | | - * If debugfs is not enabled in the kernel, the value -%ENODEV will be |
|---|
| 446 | | - * returned. It is not wise to check for this value, but rather, check for |
|---|
| 447 | | - * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling |
|---|
| 448 | | - * code. |
|---|
| 449 | 493 | */ |
|---|
| 450 | | -struct dentry *debugfs_create_u16(const char *name, umode_t mode, |
|---|
| 451 | | - struct dentry *parent, u16 *value) |
|---|
| 494 | +void debugfs_create_u16(const char *name, umode_t mode, struct dentry *parent, |
|---|
| 495 | + u16 *value) |
|---|
| 452 | 496 | { |
|---|
| 453 | | - return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u16, |
|---|
| 497 | + debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u16, |
|---|
| 454 | 498 | &fops_u16_ro, &fops_u16_wo); |
|---|
| 455 | 499 | } |
|---|
| 456 | 500 | EXPORT_SYMBOL_GPL(debugfs_create_u16); |
|---|
| .. | .. |
|---|
| 482 | 526 | * This function creates a file in debugfs with the given name that |
|---|
| 483 | 527 | * contains the value of the variable @value. If the @mode variable is so |
|---|
| 484 | 528 | * set, it can be read from, and written to. |
|---|
| 485 | | - * |
|---|
| 486 | | - * This function will return a pointer to a dentry if it succeeds. This |
|---|
| 487 | | - * pointer must be passed to the debugfs_remove() function when the file is |
|---|
| 488 | | - * to be removed (no automatic cleanup happens if your module is unloaded, |
|---|
| 489 | | - * you are responsible here.) If an error occurs, %NULL will be returned. |
|---|
| 490 | | - * |
|---|
| 491 | | - * If debugfs is not enabled in the kernel, the value -%ENODEV will be |
|---|
| 492 | | - * returned. It is not wise to check for this value, but rather, check for |
|---|
| 493 | | - * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling |
|---|
| 494 | | - * code. |
|---|
| 495 | 529 | */ |
|---|
| 496 | | -struct dentry *debugfs_create_u32(const char *name, umode_t mode, |
|---|
| 497 | | - struct dentry *parent, u32 *value) |
|---|
| 530 | +void debugfs_create_u32(const char *name, umode_t mode, struct dentry *parent, |
|---|
| 531 | + u32 *value) |
|---|
| 498 | 532 | { |
|---|
| 499 | | - return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u32, |
|---|
| 533 | + debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u32, |
|---|
| 500 | 534 | &fops_u32_ro, &fops_u32_wo); |
|---|
| 501 | 535 | } |
|---|
| 502 | 536 | EXPORT_SYMBOL_GPL(debugfs_create_u32); |
|---|
| .. | .. |
|---|
| 529 | 563 | * This function creates a file in debugfs with the given name that |
|---|
| 530 | 564 | * contains the value of the variable @value. If the @mode variable is so |
|---|
| 531 | 565 | * set, it can be read from, and written to. |
|---|
| 532 | | - * |
|---|
| 533 | | - * This function will return a pointer to a dentry if it succeeds. This |
|---|
| 534 | | - * pointer must be passed to the debugfs_remove() function when the file is |
|---|
| 535 | | - * to be removed (no automatic cleanup happens if your module is unloaded, |
|---|
| 536 | | - * you are responsible here.) If an error occurs, %NULL will be returned. |
|---|
| 537 | | - * |
|---|
| 538 | | - * If debugfs is not enabled in the kernel, the value -%ENODEV will be |
|---|
| 539 | | - * returned. It is not wise to check for this value, but rather, check for |
|---|
| 540 | | - * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling |
|---|
| 541 | | - * code. |
|---|
| 542 | 566 | */ |
|---|
| 543 | | -struct dentry *debugfs_create_u64(const char *name, umode_t mode, |
|---|
| 544 | | - struct dentry *parent, u64 *value) |
|---|
| 567 | +void debugfs_create_u64(const char *name, umode_t mode, struct dentry *parent, |
|---|
| 568 | + u64 *value) |
|---|
| 545 | 569 | { |
|---|
| 546 | | - return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u64, |
|---|
| 570 | + debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u64, |
|---|
| 547 | 571 | &fops_u64_ro, &fops_u64_wo); |
|---|
| 548 | 572 | } |
|---|
| 549 | 573 | EXPORT_SYMBOL_GPL(debugfs_create_u64); |
|---|
| .. | .. |
|---|
| 582 | 606 | * This function will return a pointer to a dentry if it succeeds. This |
|---|
| 583 | 607 | * pointer must be passed to the debugfs_remove() function when the file is |
|---|
| 584 | 608 | * to be removed (no automatic cleanup happens if your module is unloaded, |
|---|
| 585 | | - * you are responsible here.) If an error occurs, %NULL will be returned. |
|---|
| 609 | + * you are responsible here.) If an error occurs, ERR_PTR(-ERROR) will be |
|---|
| 610 | + * returned. |
|---|
| 586 | 611 | * |
|---|
| 587 | | - * If debugfs is not enabled in the kernel, the value -%ENODEV will be |
|---|
| 588 | | - * returned. It is not wise to check for this value, but rather, check for |
|---|
| 589 | | - * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling |
|---|
| 590 | | - * code. |
|---|
| 612 | + * If debugfs is not enabled in the kernel, the value ERR_PTR(-ENODEV) will |
|---|
| 613 | + * be returned. |
|---|
| 591 | 614 | */ |
|---|
| 592 | 615 | struct dentry *debugfs_create_ulong(const char *name, umode_t mode, |
|---|
| 593 | 616 | struct dentry *parent, unsigned long *value) |
|---|
| .. | .. |
|---|
| 635 | 658 | * @value: a pointer to the variable that the file should read to and write |
|---|
| 636 | 659 | * from. |
|---|
| 637 | 660 | */ |
|---|
| 638 | | -struct dentry *debugfs_create_x8(const char *name, umode_t mode, |
|---|
| 639 | | - struct dentry *parent, u8 *value) |
|---|
| 661 | +void debugfs_create_x8(const char *name, umode_t mode, struct dentry *parent, |
|---|
| 662 | + u8 *value) |
|---|
| 640 | 663 | { |
|---|
| 641 | | - return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x8, |
|---|
| 664 | + debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x8, |
|---|
| 642 | 665 | &fops_x8_ro, &fops_x8_wo); |
|---|
| 643 | 666 | } |
|---|
| 644 | 667 | EXPORT_SYMBOL_GPL(debugfs_create_x8); |
|---|
| .. | .. |
|---|
| 653 | 676 | * @value: a pointer to the variable that the file should read to and write |
|---|
| 654 | 677 | * from. |
|---|
| 655 | 678 | */ |
|---|
| 656 | | -struct dentry *debugfs_create_x16(const char *name, umode_t mode, |
|---|
| 657 | | - struct dentry *parent, u16 *value) |
|---|
| 679 | +void debugfs_create_x16(const char *name, umode_t mode, struct dentry *parent, |
|---|
| 680 | + u16 *value) |
|---|
| 658 | 681 | { |
|---|
| 659 | | - return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x16, |
|---|
| 682 | + debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x16, |
|---|
| 660 | 683 | &fops_x16_ro, &fops_x16_wo); |
|---|
| 661 | 684 | } |
|---|
| 662 | 685 | EXPORT_SYMBOL_GPL(debugfs_create_x16); |
|---|
| .. | .. |
|---|
| 671 | 694 | * @value: a pointer to the variable that the file should read to and write |
|---|
| 672 | 695 | * from. |
|---|
| 673 | 696 | */ |
|---|
| 674 | | -struct dentry *debugfs_create_x32(const char *name, umode_t mode, |
|---|
| 675 | | - struct dentry *parent, u32 *value) |
|---|
| 697 | +void debugfs_create_x32(const char *name, umode_t mode, struct dentry *parent, |
|---|
| 698 | + u32 *value) |
|---|
| 676 | 699 | { |
|---|
| 677 | | - return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x32, |
|---|
| 700 | + debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x32, |
|---|
| 678 | 701 | &fops_x32_ro, &fops_x32_wo); |
|---|
| 679 | 702 | } |
|---|
| 680 | 703 | EXPORT_SYMBOL_GPL(debugfs_create_x32); |
|---|
| .. | .. |
|---|
| 689 | 712 | * @value: a pointer to the variable that the file should read to and write |
|---|
| 690 | 713 | * from. |
|---|
| 691 | 714 | */ |
|---|
| 692 | | -struct dentry *debugfs_create_x64(const char *name, umode_t mode, |
|---|
| 693 | | - struct dentry *parent, u64 *value) |
|---|
| 715 | +void debugfs_create_x64(const char *name, umode_t mode, struct dentry *parent, |
|---|
| 716 | + u64 *value) |
|---|
| 694 | 717 | { |
|---|
| 695 | | - return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x64, |
|---|
| 718 | + debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x64, |
|---|
| 696 | 719 | &fops_x64_ro, &fops_x64_wo); |
|---|
| 697 | 720 | } |
|---|
| 698 | 721 | EXPORT_SYMBOL_GPL(debugfs_create_x64); |
|---|
| .. | .. |
|---|
| 723 | 746 | * @value: a pointer to the variable that the file should read to and write |
|---|
| 724 | 747 | * from. |
|---|
| 725 | 748 | */ |
|---|
| 726 | | -struct dentry *debugfs_create_size_t(const char *name, umode_t mode, |
|---|
| 727 | | - struct dentry *parent, size_t *value) |
|---|
| 749 | +void debugfs_create_size_t(const char *name, umode_t mode, |
|---|
| 750 | + struct dentry *parent, size_t *value) |
|---|
| 728 | 751 | { |
|---|
| 729 | | - return debugfs_create_mode_unsafe(name, mode, parent, value, |
|---|
| 730 | | - &fops_size_t, &fops_size_t_ro, |
|---|
| 731 | | - &fops_size_t_wo); |
|---|
| 752 | + debugfs_create_mode_unsafe(name, mode, parent, value, &fops_size_t, |
|---|
| 753 | + &fops_size_t_ro, &fops_size_t_wo); |
|---|
| 732 | 754 | } |
|---|
| 733 | 755 | EXPORT_SYMBOL_GPL(debugfs_create_size_t); |
|---|
| 734 | 756 | |
|---|
| .. | .. |
|---|
| 742 | 764 | *val = atomic_read((atomic_t *)data); |
|---|
| 743 | 765 | return 0; |
|---|
| 744 | 766 | } |
|---|
| 745 | | -DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t, debugfs_atomic_t_get, |
|---|
| 767 | +DEFINE_DEBUGFS_ATTRIBUTE_SIGNED(fops_atomic_t, debugfs_atomic_t_get, |
|---|
| 746 | 768 | debugfs_atomic_t_set, "%lld\n"); |
|---|
| 747 | | -DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t_ro, debugfs_atomic_t_get, NULL, |
|---|
| 769 | +DEFINE_DEBUGFS_ATTRIBUTE_SIGNED(fops_atomic_t_ro, debugfs_atomic_t_get, NULL, |
|---|
| 748 | 770 | "%lld\n"); |
|---|
| 749 | | -DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t_wo, NULL, debugfs_atomic_t_set, |
|---|
| 771 | +DEFINE_DEBUGFS_ATTRIBUTE_SIGNED(fops_atomic_t_wo, NULL, debugfs_atomic_t_set, |
|---|
| 750 | 772 | "%lld\n"); |
|---|
| 751 | 773 | |
|---|
| 752 | 774 | /** |
|---|
| .. | .. |
|---|
| 760 | 782 | * @value: a pointer to the variable that the file should read to and write |
|---|
| 761 | 783 | * from. |
|---|
| 762 | 784 | */ |
|---|
| 763 | | -struct dentry *debugfs_create_atomic_t(const char *name, umode_t mode, |
|---|
| 764 | | - struct dentry *parent, atomic_t *value) |
|---|
| 785 | +void debugfs_create_atomic_t(const char *name, umode_t mode, |
|---|
| 786 | + struct dentry *parent, atomic_t *value) |
|---|
| 765 | 787 | { |
|---|
| 766 | | - return debugfs_create_mode_unsafe(name, mode, parent, value, |
|---|
| 767 | | - &fops_atomic_t, &fops_atomic_t_ro, |
|---|
| 768 | | - &fops_atomic_t_wo); |
|---|
| 788 | + debugfs_create_mode_unsafe(name, mode, parent, value, &fops_atomic_t, |
|---|
| 789 | + &fops_atomic_t_ro, &fops_atomic_t_wo); |
|---|
| 769 | 790 | } |
|---|
| 770 | 791 | EXPORT_SYMBOL_GPL(debugfs_create_atomic_t); |
|---|
| 771 | 792 | |
|---|
| .. | .. |
|---|
| 850 | 871 | * This function will return a pointer to a dentry if it succeeds. This |
|---|
| 851 | 872 | * pointer must be passed to the debugfs_remove() function when the file is |
|---|
| 852 | 873 | * to be removed (no automatic cleanup happens if your module is unloaded, |
|---|
| 853 | | - * you are responsible here.) If an error occurs, %NULL will be returned. |
|---|
| 874 | + * you are responsible here.) If an error occurs, ERR_PTR(-ERROR) will be |
|---|
| 875 | + * returned. |
|---|
| 854 | 876 | * |
|---|
| 855 | | - * If debugfs is not enabled in the kernel, the value -%ENODEV will be |
|---|
| 856 | | - * returned. It is not wise to check for this value, but rather, check for |
|---|
| 857 | | - * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling |
|---|
| 858 | | - * code. |
|---|
| 877 | + * If debugfs is not enabled in the kernel, the value ERR_PTR(-ENODEV) will |
|---|
| 878 | + * be returned. |
|---|
| 859 | 879 | */ |
|---|
| 860 | 880 | struct dentry *debugfs_create_bool(const char *name, umode_t mode, |
|---|
| 861 | 881 | struct dentry *parent, bool *value) |
|---|
| .. | .. |
|---|
| 904 | 924 | * This function will return a pointer to a dentry if it succeeds. This |
|---|
| 905 | 925 | * pointer must be passed to the debugfs_remove() function when the file is |
|---|
| 906 | 926 | * to be removed (no automatic cleanup happens if your module is unloaded, |
|---|
| 907 | | - * you are responsible here.) If an error occurs, %NULL will be returned. |
|---|
| 927 | + * you are responsible here.) If an error occurs, ERR_PTR(-ERROR) will be |
|---|
| 928 | + * returned. |
|---|
| 908 | 929 | * |
|---|
| 909 | | - * If debugfs is not enabled in the kernel, the value -%ENODEV will be |
|---|
| 910 | | - * returned. It is not wise to check for this value, but rather, check for |
|---|
| 911 | | - * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling |
|---|
| 912 | | - * code. |
|---|
| 930 | + * If debugfs is not enabled in the kernel, the value ERR_PTR(-ENODEV) will |
|---|
| 931 | + * be returned. |
|---|
| 913 | 932 | */ |
|---|
| 914 | 933 | struct dentry *debugfs_create_blob(const char *name, umode_t mode, |
|---|
| 915 | 934 | struct dentry *parent, |
|---|
| .. | .. |
|---|
| 918 | 937 | return debugfs_create_file_unsafe(name, mode, parent, blob, &fops_blob); |
|---|
| 919 | 938 | } |
|---|
| 920 | 939 | EXPORT_SYMBOL_GPL(debugfs_create_blob); |
|---|
| 921 | | - |
|---|
| 922 | | -struct array_data { |
|---|
| 923 | | - void *array; |
|---|
| 924 | | - u32 elements; |
|---|
| 925 | | -}; |
|---|
| 926 | 940 | |
|---|
| 927 | 941 | static size_t u32_format_array(char *buf, size_t bufsize, |
|---|
| 928 | 942 | u32 *array, int array_size) |
|---|
| .. | .. |
|---|
| 944 | 958 | |
|---|
| 945 | 959 | static int u32_array_open(struct inode *inode, struct file *file) |
|---|
| 946 | 960 | { |
|---|
| 947 | | - struct array_data *data = inode->i_private; |
|---|
| 948 | | - int size, elements = data->elements; |
|---|
| 961 | + struct debugfs_u32_array *data = inode->i_private; |
|---|
| 962 | + int size, elements = data->n_elements; |
|---|
| 949 | 963 | char *buf; |
|---|
| 950 | 964 | |
|---|
| 951 | 965 | /* |
|---|
| .. | .. |
|---|
| 960 | 974 | buf[size] = 0; |
|---|
| 961 | 975 | |
|---|
| 962 | 976 | file->private_data = buf; |
|---|
| 963 | | - u32_format_array(buf, size, data->array, data->elements); |
|---|
| 964 | | - |
|---|
| 965 | | - return nonseekable_open(inode, file); |
|---|
| 966 | | -} |
|---|
| 967 | | - |
|---|
| 968 | | -static size_t u32_format_array_hex(char *buf, size_t bufsize, u32 *array, int array_size) |
|---|
| 969 | | -{ |
|---|
| 970 | | - int i = 0; |
|---|
| 971 | | - |
|---|
| 972 | | - while (--array_size >= 0) { |
|---|
| 973 | | - size_t len; |
|---|
| 974 | | - char term = (array_size && (++i % 8)) ? ' ' : '\n'; |
|---|
| 975 | | - |
|---|
| 976 | | - len = snprintf(buf, bufsize, "%08X%c", *array++, term); |
|---|
| 977 | | - buf += len; |
|---|
| 978 | | - bufsize -= len; |
|---|
| 979 | | - } |
|---|
| 980 | | - |
|---|
| 981 | | - return 0; |
|---|
| 982 | | -} |
|---|
| 983 | | - |
|---|
| 984 | | -static int u32_array_open_hex(struct inode *inode, struct file *file) |
|---|
| 985 | | -{ |
|---|
| 986 | | - struct array_data *data = inode->i_private; |
|---|
| 987 | | - int size, elements = data->elements; |
|---|
| 988 | | - char *buf; |
|---|
| 989 | | - |
|---|
| 990 | | - /* |
|---|
| 991 | | - * Max size: |
|---|
| 992 | | - * - 8 digits + ' '/'\n' = 9 bytes per number |
|---|
| 993 | | - * - terminating NUL character |
|---|
| 994 | | - */ |
|---|
| 995 | | - size = elements * 9; |
|---|
| 996 | | - buf = kmalloc(size + 1, GFP_KERNEL); |
|---|
| 997 | | - if (!buf) |
|---|
| 998 | | - return -ENOMEM; |
|---|
| 999 | | - |
|---|
| 1000 | | - buf[size] = 0; |
|---|
| 1001 | | - |
|---|
| 1002 | | - file->private_data = buf; |
|---|
| 1003 | | - u32_format_array_hex(buf, size, data->array, data->elements); |
|---|
| 977 | + u32_format_array(buf, size, data->array, data->n_elements); |
|---|
| 1004 | 978 | |
|---|
| 1005 | 979 | return nonseekable_open(inode, file); |
|---|
| 1006 | 980 | } |
|---|
| .. | .. |
|---|
| 1029 | 1003 | .llseek = no_llseek, |
|---|
| 1030 | 1004 | }; |
|---|
| 1031 | 1005 | |
|---|
| 1032 | | -static const struct file_operations u32_array_hex_fops = { |
|---|
| 1033 | | - .owner = THIS_MODULE, |
|---|
| 1034 | | - .open = u32_array_open_hex, |
|---|
| 1035 | | - .release = u32_array_release, |
|---|
| 1036 | | - .read = u32_array_read, |
|---|
| 1037 | | - .llseek = no_llseek, |
|---|
| 1038 | | -}; |
|---|
| 1039 | | - |
|---|
| 1040 | 1006 | /** |
|---|
| 1041 | 1007 | * debugfs_create_u32_array - create a debugfs file that is used to read u32 |
|---|
| 1042 | 1008 | * array. |
|---|
| .. | .. |
|---|
| 1045 | 1011 | * @parent: a pointer to the parent dentry for this file. This should be a |
|---|
| 1046 | 1012 | * directory dentry if set. If this parameter is %NULL, then the |
|---|
| 1047 | 1013 | * file will be created in the root of the debugfs filesystem. |
|---|
| 1048 | | - * @array: u32 array that provides data. |
|---|
| 1049 | | - * @elements: total number of elements in the array. |
|---|
| 1014 | + * @array: wrapper struct containing data pointer and size of the array. |
|---|
| 1050 | 1015 | * |
|---|
| 1051 | 1016 | * This function creates a file in debugfs with the given name that exports |
|---|
| 1052 | 1017 | * @array as data. If the @mode variable is so set it can be read from. |
|---|
| 1053 | 1018 | * Writing is not supported. Seek within the file is also not supported. |
|---|
| 1054 | 1019 | * Once array is created its size can not be changed. |
|---|
| 1055 | | - * |
|---|
| 1056 | | - * The function returns a pointer to dentry on success. If debugfs is not |
|---|
| 1057 | | - * enabled in the kernel, the value -%ENODEV will be returned. |
|---|
| 1058 | 1020 | */ |
|---|
| 1059 | | -struct dentry *debugfs_create_u32_array(const char *name, umode_t mode, |
|---|
| 1060 | | - struct dentry *parent, |
|---|
| 1061 | | - u32 *array, u32 elements) |
|---|
| 1021 | +void debugfs_create_u32_array(const char *name, umode_t mode, |
|---|
| 1022 | + struct dentry *parent, |
|---|
| 1023 | + struct debugfs_u32_array *array) |
|---|
| 1062 | 1024 | { |
|---|
| 1063 | | - struct array_data *data = kmalloc(sizeof(*data), GFP_KERNEL); |
|---|
| 1064 | | - |
|---|
| 1065 | | - if (data == NULL) |
|---|
| 1066 | | - return NULL; |
|---|
| 1067 | | - |
|---|
| 1068 | | - data->array = array; |
|---|
| 1069 | | - data->elements = elements; |
|---|
| 1070 | | - |
|---|
| 1071 | | - return debugfs_create_file_unsafe(name, mode, parent, data, |
|---|
| 1072 | | - &u32_array_fops); |
|---|
| 1025 | + debugfs_create_file_unsafe(name, mode, parent, array, &u32_array_fops); |
|---|
| 1073 | 1026 | } |
|---|
| 1074 | 1027 | EXPORT_SYMBOL_GPL(debugfs_create_u32_array); |
|---|
| 1075 | | - |
|---|
| 1076 | | -struct dentry *debugfs_create_u32_array_hex(const char *name, umode_t mode, |
|---|
| 1077 | | - struct dentry *parent, |
|---|
| 1078 | | - u32 *array, u32 elements) |
|---|
| 1079 | | -{ |
|---|
| 1080 | | - struct array_data *data = kmalloc(sizeof(*data), GFP_KERNEL); |
|---|
| 1081 | | - |
|---|
| 1082 | | - if (data == NULL) |
|---|
| 1083 | | - return NULL; |
|---|
| 1084 | | - |
|---|
| 1085 | | - data->array = array; |
|---|
| 1086 | | - data->elements = elements; |
|---|
| 1087 | | - |
|---|
| 1088 | | - return debugfs_create_file_unsafe(name, mode, parent, data, |
|---|
| 1089 | | - &u32_array_hex_fops); |
|---|
| 1090 | | -} |
|---|
| 1091 | | -EXPORT_SYMBOL_GPL(debugfs_create_u32_array_hex); |
|---|
| 1092 | 1028 | |
|---|
| 1093 | 1029 | #ifdef CONFIG_HAS_IOMEM |
|---|
| 1094 | 1030 | |
|---|
| .. | .. |
|---|
| 1133 | 1069 | { |
|---|
| 1134 | 1070 | struct debugfs_regset32 *regset = s->private; |
|---|
| 1135 | 1071 | |
|---|
| 1072 | + if (regset->dev) |
|---|
| 1073 | + pm_runtime_get_sync(regset->dev); |
|---|
| 1074 | + |
|---|
| 1136 | 1075 | debugfs_print_regs32(s, regset->regs, regset->nregs, regset->base, ""); |
|---|
| 1076 | + |
|---|
| 1077 | + if (regset->dev) |
|---|
| 1078 | + pm_runtime_put(regset->dev); |
|---|
| 1079 | + |
|---|
| 1137 | 1080 | return 0; |
|---|
| 1138 | 1081 | } |
|---|
| 1139 | 1082 | |
|---|
| .. | .. |
|---|
| 1163 | 1106 | * This function creates a file in debugfs with the given name that reports |
|---|
| 1164 | 1107 | * the names and values of a set of 32-bit registers. If the @mode variable |
|---|
| 1165 | 1108 | * is so set it can be read from. Writing is not supported. |
|---|
| 1166 | | - * |
|---|
| 1167 | | - * This function will return a pointer to a dentry if it succeeds. This |
|---|
| 1168 | | - * pointer must be passed to the debugfs_remove() function when the file is |
|---|
| 1169 | | - * to be removed (no automatic cleanup happens if your module is unloaded, |
|---|
| 1170 | | - * you are responsible here.) If an error occurs, %NULL will be returned. |
|---|
| 1171 | | - * |
|---|
| 1172 | | - * If debugfs is not enabled in the kernel, the value -%ENODEV will be |
|---|
| 1173 | | - * returned. It is not wise to check for this value, but rather, check for |
|---|
| 1174 | | - * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling |
|---|
| 1175 | | - * code. |
|---|
| 1176 | 1109 | */ |
|---|
| 1177 | | -struct dentry *debugfs_create_regset32(const char *name, umode_t mode, |
|---|
| 1178 | | - struct dentry *parent, |
|---|
| 1179 | | - struct debugfs_regset32 *regset) |
|---|
| 1110 | +void debugfs_create_regset32(const char *name, umode_t mode, |
|---|
| 1111 | + struct dentry *parent, |
|---|
| 1112 | + struct debugfs_regset32 *regset) |
|---|
| 1180 | 1113 | { |
|---|
| 1181 | | - return debugfs_create_file(name, mode, parent, regset, &fops_regset32); |
|---|
| 1114 | + debugfs_create_file(name, mode, parent, regset, &fops_regset32); |
|---|
| 1182 | 1115 | } |
|---|
| 1183 | 1116 | EXPORT_SYMBOL_GPL(debugfs_create_regset32); |
|---|
| 1184 | 1117 | |
|---|
| .. | .. |
|---|
| 1214 | 1147 | * file will be created in the root of the debugfs filesystem. |
|---|
| 1215 | 1148 | * @read_fn: function pointer called to print the seq_file content. |
|---|
| 1216 | 1149 | */ |
|---|
| 1217 | | -struct dentry *debugfs_create_devm_seqfile(struct device *dev, const char *name, |
|---|
| 1218 | | - struct dentry *parent, |
|---|
| 1219 | | - int (*read_fn)(struct seq_file *s, |
|---|
| 1220 | | - void *data)) |
|---|
| 1150 | +void debugfs_create_devm_seqfile(struct device *dev, const char *name, |
|---|
| 1151 | + struct dentry *parent, |
|---|
| 1152 | + int (*read_fn)(struct seq_file *s, void *data)) |
|---|
| 1221 | 1153 | { |
|---|
| 1222 | 1154 | struct debugfs_devm_entry *entry; |
|---|
| 1223 | 1155 | |
|---|
| 1224 | 1156 | if (IS_ERR(parent)) |
|---|
| 1225 | | - return ERR_PTR(-ENOENT); |
|---|
| 1157 | + return; |
|---|
| 1226 | 1158 | |
|---|
| 1227 | 1159 | entry = devm_kzalloc(dev, sizeof(*entry), GFP_KERNEL); |
|---|
| 1228 | 1160 | if (!entry) |
|---|
| 1229 | | - return ERR_PTR(-ENOMEM); |
|---|
| 1161 | + return; |
|---|
| 1230 | 1162 | |
|---|
| 1231 | 1163 | entry->read = read_fn; |
|---|
| 1232 | 1164 | entry->dev = dev; |
|---|
| 1233 | 1165 | |
|---|
| 1234 | | - return debugfs_create_file(name, S_IRUGO, parent, entry, |
|---|
| 1235 | | - &debugfs_devm_entry_ops); |
|---|
| 1166 | + debugfs_create_file(name, S_IRUGO, parent, entry, |
|---|
| 1167 | + &debugfs_devm_entry_ops); |
|---|
| 1236 | 1168 | } |
|---|
| 1237 | 1169 | EXPORT_SYMBOL_GPL(debugfs_create_devm_seqfile); |
|---|
| 1238 | | - |
|---|