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