| .. | .. | 
|---|
| 2 | 2 |  /* | 
|---|
| 3 | 3 |   *  inode.c - part of debugfs, a tiny little debug file system | 
|---|
| 4 | 4 |   * | 
|---|
| 5 |  | - *  Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com>  | 
|---|
 | 5 | + *  Copyright (C) 2004,2019 Greg Kroah-Hartman <greg@kroah.com>  | 
|---|
| 6 | 6 |   *  Copyright (C) 2004 IBM Inc. | 
|---|
 | 7 | + *  Copyright (C) 2019 Linux Foundation <gregkh@linuxfoundation.org>  | 
|---|
| 7 | 8 |   * | 
|---|
| 8 | 9 |   *  debugfs is for people to use instead of /proc or /sys. | 
|---|
| 9 | 10 |   *  See ./Documentation/core-api/kernel-api.rst for more details. | 
|---|
| 10 | 11 |   */ | 
|---|
 | 12 | +  | 
|---|
 | 13 | +#define pr_fmt(fmt)	"debugfs: " fmt  | 
|---|
| 11 | 14 |   | 
|---|
| 12 | 15 |  #include <linux/module.h> | 
|---|
| 13 | 16 |  #include <linux/fs.h> | 
|---|
| .. | .. | 
|---|
| 23 | 26 |  #include <linux/parser.h> | 
|---|
| 24 | 27 |  #include <linux/magic.h> | 
|---|
| 25 | 28 |  #include <linux/slab.h> | 
|---|
 | 29 | +#include <linux/security.h>  | 
|---|
| 26 | 30 |   | 
|---|
| 27 | 31 |  #include "internal.h" | 
|---|
| 28 | 32 |   | 
|---|
| .. | .. | 
|---|
| 31 | 35 |  static struct vfsmount *debugfs_mount; | 
|---|
| 32 | 36 |  static int debugfs_mount_count; | 
|---|
| 33 | 37 |  static bool debugfs_registered; | 
|---|
 | 38 | +static unsigned int debugfs_allow __ro_after_init = DEFAULT_DEBUGFS_ALLOW_BITS;  | 
|---|
 | 39 | +  | 
|---|
 | 40 | +/*  | 
|---|
 | 41 | + * Don't allow access attributes to be changed whilst the kernel is locked down  | 
|---|
 | 42 | + * so that we can use the file mode as part of a heuristic to determine whether  | 
|---|
 | 43 | + * to lock down individual files.  | 
|---|
 | 44 | + */  | 
|---|
 | 45 | +static int debugfs_setattr(struct dentry *dentry, struct iattr *ia)  | 
|---|
 | 46 | +{  | 
|---|
 | 47 | +	int ret = security_locked_down(LOCKDOWN_DEBUGFS);  | 
|---|
 | 48 | +  | 
|---|
 | 49 | +	if (ret && (ia->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)))  | 
|---|
 | 50 | +		return ret;  | 
|---|
 | 51 | +	return simple_setattr(dentry, ia);  | 
|---|
 | 52 | +}  | 
|---|
 | 53 | +  | 
|---|
 | 54 | +static const struct inode_operations debugfs_file_inode_operations = {  | 
|---|
 | 55 | +	.setattr	= debugfs_setattr,  | 
|---|
 | 56 | +};  | 
|---|
 | 57 | +static const struct inode_operations debugfs_dir_inode_operations = {  | 
|---|
 | 58 | +	.lookup		= simple_lookup,  | 
|---|
 | 59 | +	.setattr	= debugfs_setattr,  | 
|---|
 | 60 | +};  | 
|---|
 | 61 | +static const struct inode_operations debugfs_symlink_inode_operations = {  | 
|---|
 | 62 | +	.get_link	= simple_get_link,  | 
|---|
 | 63 | +	.setattr	= debugfs_setattr,  | 
|---|
 | 64 | +};  | 
|---|
| 34 | 65 |   | 
|---|
| 35 | 66 |  static struct inode *debugfs_get_inode(struct super_block *sb) | 
|---|
| 36 | 67 |  { | 
|---|
| .. | .. | 
|---|
| 163 | 194 |  	return 0; | 
|---|
| 164 | 195 |  } | 
|---|
| 165 | 196 |   | 
|---|
| 166 |  | -static void debugfs_i_callback(struct rcu_head *head)  | 
|---|
 | 197 | +static void debugfs_free_inode(struct inode *inode)  | 
|---|
| 167 | 198 |  { | 
|---|
| 168 |  | -	struct inode *inode = container_of(head, struct inode, i_rcu);  | 
|---|
| 169 | 199 |  	if (S_ISLNK(inode->i_mode)) | 
|---|
| 170 | 200 |  		kfree(inode->i_link); | 
|---|
| 171 | 201 |  	free_inode_nonrcu(inode); | 
|---|
| 172 |  | -}  | 
|---|
| 173 |  | -  | 
|---|
| 174 |  | -static void debugfs_destroy_inode(struct inode *inode)  | 
|---|
| 175 |  | -{  | 
|---|
| 176 |  | -	call_rcu(&inode->i_rcu, debugfs_i_callback);  | 
|---|
| 177 | 202 |  } | 
|---|
| 178 | 203 |   | 
|---|
| 179 | 204 |  static const struct super_operations debugfs_super_operations = { | 
|---|
| 180 | 205 |  	.statfs		= simple_statfs, | 
|---|
| 181 | 206 |  	.remount_fs	= debugfs_remount, | 
|---|
| 182 | 207 |  	.show_options	= debugfs_show_options, | 
|---|
| 183 |  | -	.destroy_inode	= debugfs_destroy_inode,  | 
|---|
 | 208 | +	.free_inode	= debugfs_free_inode,  | 
|---|
| 184 | 209 |  }; | 
|---|
| 185 | 210 |   | 
|---|
| 186 | 211 |  static void debugfs_release_dentry(struct dentry *dentry) | 
|---|
| .. | .. | 
|---|
| 242 | 267 |  			int flags, const char *dev_name, | 
|---|
| 243 | 268 |  			void *data) | 
|---|
| 244 | 269 |  { | 
|---|
 | 270 | +	if (!(debugfs_allow & DEBUGFS_ALLOW_API))  | 
|---|
 | 271 | +		return ERR_PTR(-EPERM);  | 
|---|
 | 272 | +  | 
|---|
| 245 | 273 |  	return mount_single(fs_type, flags, data, debug_fill_super); | 
|---|
| 246 | 274 |  } | 
|---|
| 247 | 275 |   | 
|---|
| .. | .. | 
|---|
| 269 | 297 |  { | 
|---|
| 270 | 298 |  	struct dentry *dentry; | 
|---|
| 271 | 299 |   | 
|---|
| 272 |  | -	if (IS_ERR(parent))  | 
|---|
 | 300 | +	if (!debugfs_initialized() || IS_ERR_OR_NULL(name) || IS_ERR(parent))  | 
|---|
| 273 | 301 |  		return NULL; | 
|---|
| 274 | 302 |   | 
|---|
| 275 | 303 |  	if (!parent) | 
|---|
| 276 | 304 |  		parent = debugfs_mount->mnt_root; | 
|---|
| 277 | 305 |   | 
|---|
| 278 |  | -	dentry = lookup_one_len_unlocked(name, parent, strlen(name));  | 
|---|
 | 306 | +	dentry = lookup_positive_unlocked(name, parent, strlen(name));  | 
|---|
| 279 | 307 |  	if (IS_ERR(dentry)) | 
|---|
| 280 | 308 |  		return NULL; | 
|---|
| 281 |  | -	if (!d_really_is_positive(dentry)) {  | 
|---|
| 282 |  | -		dput(dentry);  | 
|---|
| 283 |  | -		return NULL;  | 
|---|
| 284 |  | -	}  | 
|---|
| 285 | 309 |  	return dentry; | 
|---|
| 286 | 310 |  } | 
|---|
| 287 | 311 |  EXPORT_SYMBOL_GPL(debugfs_lookup); | 
|---|
| .. | .. | 
|---|
| 291 | 315 |  	struct dentry *dentry; | 
|---|
| 292 | 316 |  	int error; | 
|---|
| 293 | 317 |   | 
|---|
| 294 |  | -	pr_debug("debugfs: creating file '%s'\n",name);  | 
|---|
 | 318 | +	if (!(debugfs_allow & DEBUGFS_ALLOW_API))  | 
|---|
 | 319 | +		return ERR_PTR(-EPERM);  | 
|---|
 | 320 | +  | 
|---|
 | 321 | +	if (!debugfs_initialized())  | 
|---|
 | 322 | +		return ERR_PTR(-ENOENT);  | 
|---|
 | 323 | +  | 
|---|
 | 324 | +	pr_debug("creating file '%s'\n", name);  | 
|---|
| 295 | 325 |   | 
|---|
| 296 | 326 |  	if (IS_ERR(parent)) | 
|---|
| 297 | 327 |  		return parent; | 
|---|
| 298 | 328 |   | 
|---|
| 299 | 329 |  	error = simple_pin_fs(&debug_fs_type, &debugfs_mount, | 
|---|
| 300 | 330 |  			      &debugfs_mount_count); | 
|---|
| 301 |  | -	if (error)  | 
|---|
 | 331 | +	if (error) {  | 
|---|
 | 332 | +		pr_err("Unable to pin filesystem for file '%s'\n", name);  | 
|---|
| 302 | 333 |  		return ERR_PTR(error); | 
|---|
 | 334 | +	}  | 
|---|
| 303 | 335 |   | 
|---|
| 304 | 336 |  	/* If the parent is not specified, we create it in the root. | 
|---|
| 305 | 337 |  	 * We need the root dentry to do this, which is in the super | 
|---|
| .. | .. | 
|---|
| 310 | 342 |  		parent = debugfs_mount->mnt_root; | 
|---|
| 311 | 343 |   | 
|---|
| 312 | 344 |  	inode_lock(d_inode(parent)); | 
|---|
| 313 |  | -	dentry = lookup_one_len(name, parent, strlen(name));  | 
|---|
 | 345 | +	if (unlikely(IS_DEADDIR(d_inode(parent))))  | 
|---|
 | 346 | +		dentry = ERR_PTR(-ENOENT);  | 
|---|
 | 347 | +	else  | 
|---|
 | 348 | +		dentry = lookup_one_len(name, parent, strlen(name));  | 
|---|
| 314 | 349 |  	if (!IS_ERR(dentry) && d_really_is_positive(dentry)) { | 
|---|
 | 350 | +		if (d_is_dir(dentry))  | 
|---|
 | 351 | +			pr_err("Directory '%s' with parent '%s' already present!\n",  | 
|---|
 | 352 | +			       name, parent->d_name.name);  | 
|---|
 | 353 | +		else  | 
|---|
 | 354 | +			pr_err("File '%s' in directory '%s' already present!\n",  | 
|---|
 | 355 | +			       name, parent->d_name.name);  | 
|---|
| 315 | 356 |  		dput(dentry); | 
|---|
| 316 | 357 |  		dentry = ERR_PTR(-EEXIST); | 
|---|
| 317 | 358 |  	} | 
|---|
| .. | .. | 
|---|
| 329 | 370 |  	inode_unlock(d_inode(dentry->d_parent)); | 
|---|
| 330 | 371 |  	dput(dentry); | 
|---|
| 331 | 372 |  	simple_release_fs(&debugfs_mount, &debugfs_mount_count); | 
|---|
| 332 |  | -	return NULL;  | 
|---|
 | 373 | +	return ERR_PTR(-ENOMEM);  | 
|---|
| 333 | 374 |  } | 
|---|
| 334 | 375 |   | 
|---|
| 335 | 376 |  static struct dentry *end_creating(struct dentry *dentry) | 
|---|
| .. | .. | 
|---|
| 352 | 393 |  	dentry = start_creating(name, parent); | 
|---|
| 353 | 394 |   | 
|---|
| 354 | 395 |  	if (IS_ERR(dentry)) | 
|---|
| 355 |  | -		return NULL;  | 
|---|
 | 396 | +		return dentry;  | 
|---|
 | 397 | +  | 
|---|
 | 398 | +	if (!(debugfs_allow & DEBUGFS_ALLOW_API)) {  | 
|---|
 | 399 | +		failed_creating(dentry);  | 
|---|
 | 400 | +		return ERR_PTR(-EPERM);  | 
|---|
 | 401 | +	}  | 
|---|
| 356 | 402 |   | 
|---|
| 357 | 403 |  	inode = debugfs_get_inode(dentry->d_sb); | 
|---|
| 358 |  | -	if (unlikely(!inode))  | 
|---|
 | 404 | +	if (unlikely(!inode)) {  | 
|---|
 | 405 | +		pr_err("out of free dentries, can not create file '%s'\n",  | 
|---|
 | 406 | +		       name);  | 
|---|
| 359 | 407 |  		return failed_creating(dentry); | 
|---|
 | 408 | +	}  | 
|---|
| 360 | 409 |   | 
|---|
| 361 | 410 |  	inode->i_mode = mode; | 
|---|
| 362 | 411 |  	inode->i_private = data; | 
|---|
| 363 | 412 |   | 
|---|
 | 413 | +	inode->i_op = &debugfs_file_inode_operations;  | 
|---|
| 364 | 414 |  	inode->i_fop = proxy_fops; | 
|---|
| 365 | 415 |  	dentry->d_fsdata = (void *)((unsigned long)real_fops | | 
|---|
| 366 | 416 |  				DEBUGFS_FSDATA_IS_REAL_FOPS_BIT); | 
|---|
| .. | .. | 
|---|
| 391 | 441 |   * This function will return a pointer to a dentry if it succeeds.  This | 
|---|
| 392 | 442 |   * pointer must be passed to the debugfs_remove() function when the file is | 
|---|
| 393 | 443 |   * to be removed (no automatic cleanup happens if your module is unloaded, | 
|---|
| 394 |  | - * you are responsible here.)  If an error occurs, %NULL will be returned.  | 
|---|
 | 444 | + * you are responsible here.)  If an error occurs, ERR_PTR(-ERROR) will be  | 
|---|
 | 445 | + * returned.  | 
|---|
| 395 | 446 |   * | 
|---|
| 396 | 447 |   * If debugfs is not enabled in the kernel, the value -%ENODEV will be | 
|---|
| 397 | 448 |   * returned. | 
|---|
| .. | .. | 
|---|
| 427 | 478 |   * debugfs core. | 
|---|
| 428 | 479 |   * | 
|---|
| 429 | 480 |   * It is your responsibility to protect your struct file_operation | 
|---|
| 430 |  | - * methods against file removals by means of debugfs_use_file_start()  | 
|---|
| 431 |  | - * and debugfs_use_file_finish(). ->open() is still protected by  | 
|---|
 | 481 | + * methods against file removals by means of debugfs_file_get()  | 
|---|
 | 482 | + * and debugfs_file_put(). ->open() is still protected by  | 
|---|
| 432 | 483 |   * debugfs though. | 
|---|
| 433 | 484 |   * | 
|---|
| 434 | 485 |   * Any struct file_operations defined by means of | 
|---|
| .. | .. | 
|---|
| 465 | 516 |   * wide range of flexibility in creating a file, or a directory (if you want | 
|---|
| 466 | 517 |   * to create a directory, the debugfs_create_dir() function is | 
|---|
| 467 | 518 |   * recommended to be used instead.) | 
|---|
| 468 |  | - *  | 
|---|
| 469 |  | - * This function will return a pointer to a dentry if it succeeds.  This  | 
|---|
| 470 |  | - * pointer must be passed to the debugfs_remove() function when the file is  | 
|---|
| 471 |  | - * to be removed (no automatic cleanup happens if your module is unloaded,  | 
|---|
| 472 |  | - * you are responsible here.)  If an error occurs, %NULL will be returned.  | 
|---|
| 473 |  | - *  | 
|---|
| 474 |  | - * If debugfs is not enabled in the kernel, the value -%ENODEV will be  | 
|---|
| 475 |  | - * returned.  | 
|---|
| 476 | 519 |   */ | 
|---|
| 477 |  | -struct dentry *debugfs_create_file_size(const char *name, umode_t mode,  | 
|---|
| 478 |  | -					struct dentry *parent, void *data,  | 
|---|
| 479 |  | -					const struct file_operations *fops,  | 
|---|
| 480 |  | -					loff_t file_size)  | 
|---|
 | 520 | +void debugfs_create_file_size(const char *name, umode_t mode,  | 
|---|
 | 521 | +			      struct dentry *parent, void *data,  | 
|---|
 | 522 | +			      const struct file_operations *fops,  | 
|---|
 | 523 | +			      loff_t file_size)  | 
|---|
| 481 | 524 |  { | 
|---|
| 482 | 525 |  	struct dentry *de = debugfs_create_file(name, mode, parent, data, fops); | 
|---|
| 483 | 526 |   | 
|---|
| 484 |  | -	if (de)  | 
|---|
 | 527 | +	if (!IS_ERR(de))  | 
|---|
| 485 | 528 |  		d_inode(de)->i_size = file_size; | 
|---|
| 486 |  | -	return de;  | 
|---|
| 487 | 529 |  } | 
|---|
| 488 | 530 |  EXPORT_SYMBOL_GPL(debugfs_create_file_size); | 
|---|
| 489 | 531 |   | 
|---|
| .. | .. | 
|---|
| 500 | 542 |   * This function will return a pointer to a dentry if it succeeds.  This | 
|---|
| 501 | 543 |   * pointer must be passed to the debugfs_remove() function when the file is | 
|---|
| 502 | 544 |   * to be removed (no automatic cleanup happens if your module is unloaded, | 
|---|
| 503 |  | - * you are responsible here.)  If an error occurs, %NULL will be returned.  | 
|---|
 | 545 | + * you are responsible here.)  If an error occurs, ERR_PTR(-ERROR) will be  | 
|---|
 | 546 | + * returned.  | 
|---|
| 504 | 547 |   * | 
|---|
| 505 | 548 |   * If debugfs is not enabled in the kernel, the value -%ENODEV will be | 
|---|
| 506 | 549 |   * returned. | 
|---|
| .. | .. | 
|---|
| 511 | 554 |  	struct inode *inode; | 
|---|
| 512 | 555 |   | 
|---|
| 513 | 556 |  	if (IS_ERR(dentry)) | 
|---|
| 514 |  | -		return NULL;  | 
|---|
 | 557 | +		return dentry;  | 
|---|
 | 558 | +  | 
|---|
 | 559 | +	if (!(debugfs_allow & DEBUGFS_ALLOW_API)) {  | 
|---|
 | 560 | +		failed_creating(dentry);  | 
|---|
 | 561 | +		return ERR_PTR(-EPERM);  | 
|---|
 | 562 | +	}  | 
|---|
| 515 | 563 |   | 
|---|
| 516 | 564 |  	inode = debugfs_get_inode(dentry->d_sb); | 
|---|
| 517 |  | -	if (unlikely(!inode))  | 
|---|
 | 565 | +	if (unlikely(!inode)) {  | 
|---|
 | 566 | +		pr_err("out of free dentries, can not create directory '%s'\n",  | 
|---|
 | 567 | +		       name);  | 
|---|
| 518 | 568 |  		return failed_creating(dentry); | 
|---|
 | 569 | +	}  | 
|---|
| 519 | 570 |   | 
|---|
| 520 | 571 |  	inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; | 
|---|
| 521 |  | -	inode->i_op = &simple_dir_inode_operations;  | 
|---|
 | 572 | +	inode->i_op = &debugfs_dir_inode_operations;  | 
|---|
| 522 | 573 |  	inode->i_fop = &simple_dir_operations; | 
|---|
| 523 | 574 |   | 
|---|
| 524 | 575 |  	/* directory inodes start off with i_nlink == 2 (for "." entry) */ | 
|---|
| .. | .. | 
|---|
| 550 | 601 |  	struct inode *inode; | 
|---|
| 551 | 602 |   | 
|---|
| 552 | 603 |  	if (IS_ERR(dentry)) | 
|---|
| 553 |  | -		return NULL;  | 
|---|
 | 604 | +		return dentry;  | 
|---|
 | 605 | +  | 
|---|
 | 606 | +	if (!(debugfs_allow & DEBUGFS_ALLOW_API)) {  | 
|---|
 | 607 | +		failed_creating(dentry);  | 
|---|
 | 608 | +		return ERR_PTR(-EPERM);  | 
|---|
 | 609 | +	}  | 
|---|
| 554 | 610 |   | 
|---|
| 555 | 611 |  	inode = debugfs_get_inode(dentry->d_sb); | 
|---|
| 556 |  | -	if (unlikely(!inode))  | 
|---|
 | 612 | +	if (unlikely(!inode)) {  | 
|---|
 | 613 | +		pr_err("out of free dentries, can not create automount '%s'\n",  | 
|---|
 | 614 | +		       name);  | 
|---|
| 557 | 615 |  		return failed_creating(dentry); | 
|---|
 | 616 | +	}  | 
|---|
| 558 | 617 |   | 
|---|
| 559 | 618 |  	make_empty_dir_inode(inode); | 
|---|
| 560 | 619 |  	inode->i_flags |= S_AUTOMOUNT; | 
|---|
| .. | .. | 
|---|
| 586 | 645 |   * This function will return a pointer to a dentry if it succeeds.  This | 
|---|
| 587 | 646 |   * pointer must be passed to the debugfs_remove() function when the symbolic | 
|---|
| 588 | 647 |   * link is to be removed (no automatic cleanup happens if your module is | 
|---|
| 589 |  | - * unloaded, you are responsible here.)  If an error occurs, %NULL will be  | 
|---|
| 590 |  | - * returned.  | 
|---|
 | 648 | + * unloaded, you are responsible here.)  If an error occurs, ERR_PTR(-ERROR)  | 
|---|
 | 649 | + * will be returned.  | 
|---|
| 591 | 650 |   * | 
|---|
| 592 | 651 |   * If debugfs is not enabled in the kernel, the value -%ENODEV will be | 
|---|
| 593 | 652 |   * returned. | 
|---|
| .. | .. | 
|---|
| 599 | 658 |  	struct inode *inode; | 
|---|
| 600 | 659 |  	char *link = kstrdup(target, GFP_KERNEL); | 
|---|
| 601 | 660 |  	if (!link) | 
|---|
| 602 |  | -		return NULL;  | 
|---|
 | 661 | +		return ERR_PTR(-ENOMEM);  | 
|---|
| 603 | 662 |   | 
|---|
| 604 | 663 |  	dentry = start_creating(name, parent); | 
|---|
| 605 | 664 |  	if (IS_ERR(dentry)) { | 
|---|
| 606 | 665 |  		kfree(link); | 
|---|
| 607 |  | -		return NULL;  | 
|---|
 | 666 | +		return dentry;  | 
|---|
| 608 | 667 |  	} | 
|---|
| 609 | 668 |   | 
|---|
| 610 | 669 |  	inode = debugfs_get_inode(dentry->d_sb); | 
|---|
| 611 | 670 |  	if (unlikely(!inode)) { | 
|---|
 | 671 | +		pr_err("out of free dentries, can not create symlink '%s'\n",  | 
|---|
 | 672 | +		       name);  | 
|---|
| 612 | 673 |  		kfree(link); | 
|---|
| 613 | 674 |  		return failed_creating(dentry); | 
|---|
| 614 | 675 |  	} | 
|---|
| 615 | 676 |  	inode->i_mode = S_IFLNK | S_IRWXUGO; | 
|---|
| 616 |  | -	inode->i_op = &simple_symlink_inode_operations;  | 
|---|
 | 677 | +	inode->i_op = &debugfs_symlink_inode_operations;  | 
|---|
| 617 | 678 |  	inode->i_link = link; | 
|---|
| 618 | 679 |  	d_instantiate(dentry, inode); | 
|---|
| 619 | 680 |  	return end_creating(dentry); | 
|---|
| 620 | 681 |  } | 
|---|
| 621 | 682 |  EXPORT_SYMBOL_GPL(debugfs_create_symlink); | 
|---|
| 622 | 683 |   | 
|---|
| 623 |  | -static void __debugfs_remove_file(struct dentry *dentry, struct dentry *parent)  | 
|---|
 | 684 | +static void __debugfs_file_removed(struct dentry *dentry)  | 
|---|
| 624 | 685 |  { | 
|---|
| 625 | 686 |  	struct debugfs_fsdata *fsd; | 
|---|
| 626 |  | -  | 
|---|
| 627 |  | -	simple_unlink(d_inode(parent), dentry);  | 
|---|
| 628 |  | -	d_delete(dentry);  | 
|---|
| 629 | 687 |   | 
|---|
| 630 | 688 |  	/* | 
|---|
| 631 | 689 |  	 * Paired with the closing smp_mb() implied by a successful | 
|---|
| .. | .. | 
|---|
| 641 | 699 |  		wait_for_completion(&fsd->active_users_drained); | 
|---|
| 642 | 700 |  } | 
|---|
| 643 | 701 |   | 
|---|
| 644 |  | -static int __debugfs_remove(struct dentry *dentry, struct dentry *parent)  | 
|---|
 | 702 | +static void remove_one(struct dentry *victim)  | 
|---|
| 645 | 703 |  { | 
|---|
| 646 |  | -	int ret = 0;  | 
|---|
| 647 |  | -  | 
|---|
| 648 |  | -	if (simple_positive(dentry)) {  | 
|---|
| 649 |  | -		dget(dentry);  | 
|---|
| 650 |  | -		if (!d_is_reg(dentry)) {  | 
|---|
| 651 |  | -			if (d_is_dir(dentry))  | 
|---|
| 652 |  | -				ret = simple_rmdir(d_inode(parent), dentry);  | 
|---|
| 653 |  | -			else  | 
|---|
| 654 |  | -				simple_unlink(d_inode(parent), dentry);  | 
|---|
| 655 |  | -			if (!ret)  | 
|---|
| 656 |  | -				d_delete(dentry);  | 
|---|
| 657 |  | -		} else {  | 
|---|
| 658 |  | -			__debugfs_remove_file(dentry, parent);  | 
|---|
| 659 |  | -		}  | 
|---|
| 660 |  | -		dput(dentry);  | 
|---|
| 661 |  | -	}  | 
|---|
| 662 |  | -	return ret;  | 
|---|
 | 704 | +        if (d_is_reg(victim))  | 
|---|
 | 705 | +		__debugfs_file_removed(victim);  | 
|---|
 | 706 | +	simple_release_fs(&debugfs_mount, &debugfs_mount_count);  | 
|---|
| 663 | 707 |  } | 
|---|
| 664 | 708 |   | 
|---|
| 665 | 709 |  /** | 
|---|
| 666 |  | - * debugfs_remove - removes a file or directory from the debugfs filesystem  | 
|---|
| 667 |  | - * @dentry: a pointer to a the dentry of the file or directory to be  | 
|---|
| 668 |  | - *          removed.  If this parameter is NULL or an error value, nothing  | 
|---|
| 669 |  | - *          will be done.  | 
|---|
| 670 |  | - *  | 
|---|
| 671 |  | - * This function removes a file or directory in debugfs that was previously  | 
|---|
| 672 |  | - * created with a call to another debugfs function (like  | 
|---|
| 673 |  | - * debugfs_create_file() or variants thereof.)  | 
|---|
| 674 |  | - *  | 
|---|
| 675 |  | - * This function is required to be called in order for the file to be  | 
|---|
| 676 |  | - * removed, no automatic cleanup of files will happen when a module is  | 
|---|
| 677 |  | - * removed, you are responsible here.  | 
|---|
| 678 |  | - */  | 
|---|
| 679 |  | -void debugfs_remove(struct dentry *dentry)  | 
|---|
| 680 |  | -{  | 
|---|
| 681 |  | -	struct dentry *parent;  | 
|---|
| 682 |  | -	int ret;  | 
|---|
| 683 |  | -  | 
|---|
| 684 |  | -	if (IS_ERR_OR_NULL(dentry))  | 
|---|
| 685 |  | -		return;  | 
|---|
| 686 |  | -  | 
|---|
| 687 |  | -	parent = dentry->d_parent;  | 
|---|
| 688 |  | -	inode_lock(d_inode(parent));  | 
|---|
| 689 |  | -	ret = __debugfs_remove(dentry, parent);  | 
|---|
| 690 |  | -	inode_unlock(d_inode(parent));  | 
|---|
| 691 |  | -	if (!ret)  | 
|---|
| 692 |  | -		simple_release_fs(&debugfs_mount, &debugfs_mount_count);  | 
|---|
| 693 |  | -}  | 
|---|
| 694 |  | -EXPORT_SYMBOL_GPL(debugfs_remove);  | 
|---|
| 695 |  | -  | 
|---|
| 696 |  | -/**  | 
|---|
| 697 |  | - * debugfs_remove_recursive - recursively removes a directory  | 
|---|
 | 710 | + * debugfs_remove - recursively removes a directory  | 
|---|
| 698 | 711 |   * @dentry: a pointer to a the dentry of the directory to be removed.  If this | 
|---|
| 699 | 712 |   *          parameter is NULL or an error value, nothing will be done. | 
|---|
| 700 | 713 |   * | 
|---|
| .. | .. | 
|---|
| 706 | 719 |   * removed, no automatic cleanup of files will happen when a module is | 
|---|
| 707 | 720 |   * removed, you are responsible here. | 
|---|
| 708 | 721 |   */ | 
|---|
| 709 |  | -void debugfs_remove_recursive(struct dentry *dentry)  | 
|---|
 | 722 | +void debugfs_remove(struct dentry *dentry)  | 
|---|
| 710 | 723 |  { | 
|---|
| 711 |  | -	struct dentry *child, *parent;  | 
|---|
| 712 |  | -  | 
|---|
| 713 | 724 |  	if (IS_ERR_OR_NULL(dentry)) | 
|---|
| 714 | 725 |  		return; | 
|---|
| 715 | 726 |   | 
|---|
| 716 |  | -	parent = dentry;  | 
|---|
| 717 |  | - down:  | 
|---|
| 718 |  | -	inode_lock(d_inode(parent));  | 
|---|
| 719 |  | - loop:  | 
|---|
| 720 |  | -	/*  | 
|---|
| 721 |  | -	 * The parent->d_subdirs is protected by the d_lock. Outside that  | 
|---|
| 722 |  | -	 * lock, the child can be unlinked and set to be freed which can  | 
|---|
| 723 |  | -	 * use the d_u.d_child as the rcu head and corrupt this list.  | 
|---|
| 724 |  | -	 */  | 
|---|
| 725 |  | -	spin_lock(&parent->d_lock);  | 
|---|
| 726 |  | -	list_for_each_entry(child, &parent->d_subdirs, d_child) {  | 
|---|
| 727 |  | -		if (!simple_positive(child))  | 
|---|
| 728 |  | -			continue;  | 
|---|
| 729 |  | -  | 
|---|
| 730 |  | -		/* perhaps simple_empty(child) makes more sense */  | 
|---|
| 731 |  | -		if (!list_empty(&child->d_subdirs)) {  | 
|---|
| 732 |  | -			spin_unlock(&parent->d_lock);  | 
|---|
| 733 |  | -			inode_unlock(d_inode(parent));  | 
|---|
| 734 |  | -			parent = child;  | 
|---|
| 735 |  | -			goto down;  | 
|---|
| 736 |  | -		}  | 
|---|
| 737 |  | -  | 
|---|
| 738 |  | -		spin_unlock(&parent->d_lock);  | 
|---|
| 739 |  | -  | 
|---|
| 740 |  | -		if (!__debugfs_remove(child, parent))  | 
|---|
| 741 |  | -			simple_release_fs(&debugfs_mount, &debugfs_mount_count);  | 
|---|
| 742 |  | -  | 
|---|
| 743 |  | -		/*  | 
|---|
| 744 |  | -		 * The parent->d_lock protects agaist child from unlinking  | 
|---|
| 745 |  | -		 * from d_subdirs. When releasing the parent->d_lock we can  | 
|---|
| 746 |  | -		 * no longer trust that the next pointer is valid.  | 
|---|
| 747 |  | -		 * Restart the loop. We'll skip this one with the  | 
|---|
| 748 |  | -		 * simple_positive() check.  | 
|---|
| 749 |  | -		 */  | 
|---|
| 750 |  | -		goto loop;  | 
|---|
| 751 |  | -	}  | 
|---|
| 752 |  | -	spin_unlock(&parent->d_lock);  | 
|---|
| 753 |  | -  | 
|---|
| 754 |  | -	inode_unlock(d_inode(parent));  | 
|---|
| 755 |  | -	child = parent;  | 
|---|
| 756 |  | -	parent = parent->d_parent;  | 
|---|
| 757 |  | -	inode_lock(d_inode(parent));  | 
|---|
| 758 |  | -  | 
|---|
| 759 |  | -	if (child != dentry)  | 
|---|
| 760 |  | -		/* go up */  | 
|---|
| 761 |  | -		goto loop;  | 
|---|
| 762 |  | -  | 
|---|
| 763 |  | -	if (!__debugfs_remove(child, parent))  | 
|---|
| 764 |  | -		simple_release_fs(&debugfs_mount, &debugfs_mount_count);  | 
|---|
| 765 |  | -	inode_unlock(d_inode(parent));  | 
|---|
 | 727 | +	simple_pin_fs(&debug_fs_type, &debugfs_mount, &debugfs_mount_count);  | 
|---|
 | 728 | +	simple_recursive_removal(dentry, remove_one);  | 
|---|
 | 729 | +	simple_release_fs(&debugfs_mount, &debugfs_mount_count);  | 
|---|
| 766 | 730 |  } | 
|---|
| 767 |  | -EXPORT_SYMBOL_GPL(debugfs_remove_recursive);  | 
|---|
 | 731 | +EXPORT_SYMBOL_GPL(debugfs_remove);  | 
|---|
 | 732 | +  | 
|---|
 | 733 | +/**  | 
|---|
 | 734 | + * debugfs_lookup_and_remove - lookup a directory or file and recursively remove it  | 
|---|
 | 735 | + * @name: a pointer to a string containing the name of the item to look up.  | 
|---|
 | 736 | + * @parent: a pointer to the parent dentry of the item.  | 
|---|
 | 737 | + *  | 
|---|
 | 738 | + * This is the equlivant of doing something like  | 
|---|
 | 739 | + * debugfs_remove(debugfs_lookup(..)) but with the proper reference counting  | 
|---|
 | 740 | + * handled for the directory being looked up.  | 
|---|
 | 741 | + */  | 
|---|
 | 742 | +void debugfs_lookup_and_remove(const char *name, struct dentry *parent)  | 
|---|
 | 743 | +{  | 
|---|
 | 744 | +	struct dentry *dentry;  | 
|---|
 | 745 | +  | 
|---|
 | 746 | +	dentry = debugfs_lookup(name, parent);  | 
|---|
 | 747 | +	if (!dentry)  | 
|---|
 | 748 | +		return;  | 
|---|
 | 749 | +  | 
|---|
 | 750 | +	debugfs_remove(dentry);  | 
|---|
 | 751 | +	dput(dentry);  | 
|---|
 | 752 | +}  | 
|---|
 | 753 | +EXPORT_SYMBOL_GPL(debugfs_lookup_and_remove);  | 
|---|
| 768 | 754 |   | 
|---|
| 769 | 755 |  /** | 
|---|
| 770 | 756 |   * debugfs_rename - rename a file/directory in the debugfs filesystem | 
|---|
| .. | .. | 
|---|
| 821 | 807 |  		goto exit; | 
|---|
| 822 | 808 |  	} | 
|---|
| 823 | 809 |  	d_move(old_dentry, dentry); | 
|---|
| 824 |  | -	fsnotify_move(d_inode(old_dir), d_inode(new_dir), old_name.name,  | 
|---|
 | 810 | +	fsnotify_move(d_inode(old_dir), d_inode(new_dir), &old_name.name,  | 
|---|
| 825 | 811 |  		d_is_dir(old_dentry), | 
|---|
| 826 | 812 |  		NULL, old_dentry); | 
|---|
| 827 | 813 |  	release_dentry_name_snapshot(&old_name); | 
|---|
| .. | .. | 
|---|
| 832 | 818 |  	if (dentry && !IS_ERR(dentry)) | 
|---|
| 833 | 819 |  		dput(dentry); | 
|---|
| 834 | 820 |  	unlock_rename(new_dir, old_dir); | 
|---|
| 835 |  | -	return NULL;  | 
|---|
 | 821 | +	if (IS_ERR(dentry))  | 
|---|
 | 822 | +		return dentry;  | 
|---|
 | 823 | +	return ERR_PTR(-EINVAL);  | 
|---|
| 836 | 824 |  } | 
|---|
| 837 | 825 |  EXPORT_SYMBOL_GPL(debugfs_rename); | 
|---|
| 838 | 826 |   | 
|---|
| .. | .. | 
|---|
| 845 | 833 |  } | 
|---|
| 846 | 834 |  EXPORT_SYMBOL_GPL(debugfs_initialized); | 
|---|
| 847 | 835 |   | 
|---|
 | 836 | +static int __init debugfs_kernel(char *str)  | 
|---|
 | 837 | +{  | 
|---|
 | 838 | +	if (str) {  | 
|---|
 | 839 | +		if (!strcmp(str, "on"))  | 
|---|
 | 840 | +			debugfs_allow = DEBUGFS_ALLOW_API | DEBUGFS_ALLOW_MOUNT;  | 
|---|
 | 841 | +		else if (!strcmp(str, "no-mount"))  | 
|---|
 | 842 | +			debugfs_allow = DEBUGFS_ALLOW_API;  | 
|---|
 | 843 | +		else if (!strcmp(str, "off"))  | 
|---|
 | 844 | +			debugfs_allow = 0;  | 
|---|
 | 845 | +	}  | 
|---|
 | 846 | +  | 
|---|
 | 847 | +	return 0;  | 
|---|
 | 848 | +}  | 
|---|
 | 849 | +early_param("debugfs", debugfs_kernel);  | 
|---|
| 848 | 850 |  static int __init debugfs_init(void) | 
|---|
| 849 | 851 |  { | 
|---|
| 850 | 852 |  	int retval; | 
|---|
 | 853 | +  | 
|---|
 | 854 | +	if (!(debugfs_allow & DEBUGFS_ALLOW_MOUNT))  | 
|---|
 | 855 | +		return -EPERM;  | 
|---|
| 851 | 856 |   | 
|---|
| 852 | 857 |  	retval = sysfs_create_mount_point(kernel_kobj, "debug"); | 
|---|
| 853 | 858 |  	if (retval) | 
|---|
| .. | .. | 
|---|
| 862 | 867 |  	return retval; | 
|---|
| 863 | 868 |  } | 
|---|
| 864 | 869 |  core_initcall(debugfs_init); | 
|---|
| 865 |  | -  | 
|---|