| .. | .. | 
|---|
| 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 |  | -  | 
|---|