diff options
Diffstat (limited to 'fs/debugfs')
-rw-r--r-- | fs/debugfs/file.c | 43 | ||||
-rw-r--r-- | fs/debugfs/inode.c | 69 |
2 files changed, 65 insertions, 47 deletions
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index c5ca6ae5a30c..63146295153b 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/debugfs.h> | 21 | #include <linux/debugfs.h> |
22 | #include <linux/io.h> | 22 | #include <linux/io.h> |
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/atomic.h> | ||
24 | 25 | ||
25 | static ssize_t default_read_file(struct file *file, char __user *buf, | 26 | static ssize_t default_read_file(struct file *file, char __user *buf, |
26 | size_t count, loff_t *ppos) | 27 | size_t count, loff_t *ppos) |
@@ -403,6 +404,47 @@ struct dentry *debugfs_create_size_t(const char *name, umode_t mode, | |||
403 | } | 404 | } |
404 | EXPORT_SYMBOL_GPL(debugfs_create_size_t); | 405 | EXPORT_SYMBOL_GPL(debugfs_create_size_t); |
405 | 406 | ||
407 | static int debugfs_atomic_t_set(void *data, u64 val) | ||
408 | { | ||
409 | atomic_set((atomic_t *)data, val); | ||
410 | return 0; | ||
411 | } | ||
412 | static int debugfs_atomic_t_get(void *data, u64 *val) | ||
413 | { | ||
414 | *val = atomic_read((atomic_t *)data); | ||
415 | return 0; | ||
416 | } | ||
417 | DEFINE_SIMPLE_ATTRIBUTE(fops_atomic_t, debugfs_atomic_t_get, | ||
418 | debugfs_atomic_t_set, "%lld\n"); | ||
419 | DEFINE_SIMPLE_ATTRIBUTE(fops_atomic_t_ro, debugfs_atomic_t_get, NULL, "%lld\n"); | ||
420 | DEFINE_SIMPLE_ATTRIBUTE(fops_atomic_t_wo, NULL, debugfs_atomic_t_set, "%lld\n"); | ||
421 | |||
422 | /** | ||
423 | * debugfs_create_atomic_t - create a debugfs file that is used to read and | ||
424 | * write an atomic_t value | ||
425 | * @name: a pointer to a string containing the name of the file to create. | ||
426 | * @mode: the permission that the file should have | ||
427 | * @parent: a pointer to the parent dentry for this file. This should be a | ||
428 | * directory dentry if set. If this parameter is %NULL, then the | ||
429 | * file will be created in the root of the debugfs filesystem. | ||
430 | * @value: a pointer to the variable that the file should read to and write | ||
431 | * from. | ||
432 | */ | ||
433 | struct dentry *debugfs_create_atomic_t(const char *name, umode_t mode, | ||
434 | struct dentry *parent, atomic_t *value) | ||
435 | { | ||
436 | /* if there are no write bits set, make read only */ | ||
437 | if (!(mode & S_IWUGO)) | ||
438 | return debugfs_create_file(name, mode, parent, value, | ||
439 | &fops_atomic_t_ro); | ||
440 | /* if there are no read bits set, make write only */ | ||
441 | if (!(mode & S_IRUGO)) | ||
442 | return debugfs_create_file(name, mode, parent, value, | ||
443 | &fops_atomic_t_wo); | ||
444 | |||
445 | return debugfs_create_file(name, mode, parent, value, &fops_atomic_t); | ||
446 | } | ||
447 | EXPORT_SYMBOL_GPL(debugfs_create_atomic_t); | ||
406 | 448 | ||
407 | static ssize_t read_file_bool(struct file *file, char __user *user_buf, | 449 | static ssize_t read_file_bool(struct file *file, char __user *user_buf, |
408 | size_t count, loff_t *ppos) | 450 | size_t count, loff_t *ppos) |
@@ -431,6 +473,7 @@ static ssize_t write_file_bool(struct file *file, const char __user *user_buf, | |||
431 | if (copy_from_user(buf, user_buf, buf_size)) | 473 | if (copy_from_user(buf, user_buf, buf_size)) |
432 | return -EFAULT; | 474 | return -EFAULT; |
433 | 475 | ||
476 | buf[buf_size] = '\0'; | ||
434 | if (strtobool(buf, &bv) == 0) | 477 | if (strtobool(buf, &bv) == 0) |
435 | *val = bv; | 478 | *val = bv; |
436 | 479 | ||
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 4888cb3fdef7..c7c83ff0f752 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c | |||
@@ -533,8 +533,7 @@ EXPORT_SYMBOL_GPL(debugfs_remove); | |||
533 | */ | 533 | */ |
534 | void debugfs_remove_recursive(struct dentry *dentry) | 534 | void debugfs_remove_recursive(struct dentry *dentry) |
535 | { | 535 | { |
536 | struct dentry *child; | 536 | struct dentry *child, *next, *parent; |
537 | struct dentry *parent; | ||
538 | 537 | ||
539 | if (IS_ERR_OR_NULL(dentry)) | 538 | if (IS_ERR_OR_NULL(dentry)) |
540 | return; | 539 | return; |
@@ -544,61 +543,37 @@ void debugfs_remove_recursive(struct dentry *dentry) | |||
544 | return; | 543 | return; |
545 | 544 | ||
546 | parent = dentry; | 545 | parent = dentry; |
546 | down: | ||
547 | mutex_lock(&parent->d_inode->i_mutex); | 547 | mutex_lock(&parent->d_inode->i_mutex); |
548 | list_for_each_entry_safe(child, next, &parent->d_subdirs, d_u.d_child) { | ||
549 | if (!debugfs_positive(child)) | ||
550 | continue; | ||
548 | 551 | ||
549 | while (1) { | 552 | /* perhaps simple_empty(child) makes more sense */ |
550 | /* | ||
551 | * When all dentries under "parent" has been removed, | ||
552 | * walk up the tree until we reach our starting point. | ||
553 | */ | ||
554 | if (list_empty(&parent->d_subdirs)) { | ||
555 | mutex_unlock(&parent->d_inode->i_mutex); | ||
556 | if (parent == dentry) | ||
557 | break; | ||
558 | parent = parent->d_parent; | ||
559 | mutex_lock(&parent->d_inode->i_mutex); | ||
560 | } | ||
561 | child = list_entry(parent->d_subdirs.next, struct dentry, | ||
562 | d_u.d_child); | ||
563 | next_sibling: | ||
564 | |||
565 | /* | ||
566 | * If "child" isn't empty, walk down the tree and | ||
567 | * remove all its descendants first. | ||
568 | */ | ||
569 | if (!list_empty(&child->d_subdirs)) { | 553 | if (!list_empty(&child->d_subdirs)) { |
570 | mutex_unlock(&parent->d_inode->i_mutex); | 554 | mutex_unlock(&parent->d_inode->i_mutex); |
571 | parent = child; | 555 | parent = child; |
572 | mutex_lock(&parent->d_inode->i_mutex); | 556 | goto down; |
573 | continue; | ||
574 | } | 557 | } |
575 | __debugfs_remove(child, parent); | 558 | up: |
576 | if (parent->d_subdirs.next == &child->d_u.d_child) { | 559 | if (!__debugfs_remove(child, parent)) |
577 | /* | 560 | simple_release_fs(&debugfs_mount, &debugfs_mount_count); |
578 | * Try the next sibling. | ||
579 | */ | ||
580 | if (child->d_u.d_child.next != &parent->d_subdirs) { | ||
581 | child = list_entry(child->d_u.d_child.next, | ||
582 | struct dentry, | ||
583 | d_u.d_child); | ||
584 | goto next_sibling; | ||
585 | } | ||
586 | |||
587 | /* | ||
588 | * Avoid infinite loop if we fail to remove | ||
589 | * one dentry. | ||
590 | */ | ||
591 | mutex_unlock(&parent->d_inode->i_mutex); | ||
592 | break; | ||
593 | } | ||
594 | simple_release_fs(&debugfs_mount, &debugfs_mount_count); | ||
595 | } | 561 | } |
596 | 562 | ||
597 | parent = dentry->d_parent; | 563 | mutex_unlock(&parent->d_inode->i_mutex); |
564 | child = parent; | ||
565 | parent = parent->d_parent; | ||
598 | mutex_lock(&parent->d_inode->i_mutex); | 566 | mutex_lock(&parent->d_inode->i_mutex); |
599 | __debugfs_remove(dentry, parent); | 567 | |
568 | if (child != dentry) { | ||
569 | next = list_entry(child->d_u.d_child.next, struct dentry, | ||
570 | d_u.d_child); | ||
571 | goto up; | ||
572 | } | ||
573 | |||
574 | if (!__debugfs_remove(child, parent)) | ||
575 | simple_release_fs(&debugfs_mount, &debugfs_mount_count); | ||
600 | mutex_unlock(&parent->d_inode->i_mutex); | 576 | mutex_unlock(&parent->d_inode->i_mutex); |
601 | simple_release_fs(&debugfs_mount, &debugfs_mount_count); | ||
602 | } | 577 | } |
603 | EXPORT_SYMBOL_GPL(debugfs_remove_recursive); | 578 | EXPORT_SYMBOL_GPL(debugfs_remove_recursive); |
604 | 579 | ||