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