diff options
| author | Nicolai Stange <nicstange@gmail.com> | 2016-03-22 09:11:18 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-04-12 17:14:21 -0400 |
| commit | 4d45f7974ccf0aa783034fef2661573b3a28609e (patch) | |
| tree | 302b046fc51e7215d5eca256385dfc2d7e98852f /fs/debugfs | |
| parent | 4909f168104b24f592fb8d502e2a6520346a3927 (diff) | |
debugfs: unproxify files created through debugfs_create_bool()
Currently, the struct file_operations fops_bool associated with files
created through the debugfs_create_bool() helpers are not file
lifetime aware.
Thus, a lifetime managing proxy is created around fops_bool each time such
a file is opened which is an unnecessary waste of resources.
Implement file lifetime management for the fops_bool file_operations.
Namely, make debugfs_read_file_bool() and debugfs_write_file_bool() safe
against file removals by means of debugfs_use_file_start() and
debugfs_use_file_finish().
Make debugfs_create_bool() create its files in non-proxying operation mode
through debugfs_create_mode_unsafe().
Finally, purge debugfs_create_mode() as debugfs_create_bool() had been its
last user.
Signed-off-by: Nicolai Stange <nicstange@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/debugfs')
| -rw-r--r-- | fs/debugfs/file.c | 41 |
1 files changed, 20 insertions, 21 deletions
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 4b3967e86e97..8a548bee1b3d 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c | |||
| @@ -312,22 +312,6 @@ ssize_t debugfs_attr_write(struct file *file, const char __user *buf, | |||
| 312 | } | 312 | } |
| 313 | EXPORT_SYMBOL_GPL(debugfs_attr_write); | 313 | EXPORT_SYMBOL_GPL(debugfs_attr_write); |
| 314 | 314 | ||
| 315 | static struct dentry *debugfs_create_mode(const char *name, umode_t mode, | ||
| 316 | struct dentry *parent, void *value, | ||
| 317 | const struct file_operations *fops, | ||
| 318 | const struct file_operations *fops_ro, | ||
| 319 | const struct file_operations *fops_wo) | ||
| 320 | { | ||
| 321 | /* if there are no write bits set, make read only */ | ||
| 322 | if (!(mode & S_IWUGO)) | ||
| 323 | return debugfs_create_file(name, mode, parent, value, fops_ro); | ||
| 324 | /* if there are no read bits set, make write only */ | ||
| 325 | if (!(mode & S_IRUGO)) | ||
| 326 | return debugfs_create_file(name, mode, parent, value, fops_wo); | ||
| 327 | |||
| 328 | return debugfs_create_file(name, mode, parent, value, fops); | ||
| 329 | } | ||
| 330 | |||
| 331 | static struct dentry *debugfs_create_mode_unsafe(const char *name, umode_t mode, | 315 | static struct dentry *debugfs_create_mode_unsafe(const char *name, umode_t mode, |
| 332 | struct dentry *parent, void *value, | 316 | struct dentry *parent, void *value, |
| 333 | const struct file_operations *fops, | 317 | const struct file_operations *fops, |
| @@ -756,9 +740,17 @@ ssize_t debugfs_read_file_bool(struct file *file, char __user *user_buf, | |||
| 756 | size_t count, loff_t *ppos) | 740 | size_t count, loff_t *ppos) |
| 757 | { | 741 | { |
| 758 | char buf[3]; | 742 | char buf[3]; |
| 759 | bool *val = file->private_data; | 743 | bool val; |
| 744 | int r, srcu_idx; | ||
| 745 | |||
| 746 | r = debugfs_use_file_start(F_DENTRY(file), &srcu_idx); | ||
| 747 | if (likely(!r)) | ||
| 748 | val = *(bool *)file->private_data; | ||
| 749 | debugfs_use_file_finish(srcu_idx); | ||
| 750 | if (r) | ||
| 751 | return r; | ||
| 760 | 752 | ||
| 761 | if (*val) | 753 | if (val) |
| 762 | buf[0] = 'Y'; | 754 | buf[0] = 'Y'; |
| 763 | else | 755 | else |
| 764 | buf[0] = 'N'; | 756 | buf[0] = 'N'; |
| @@ -774,6 +766,7 @@ ssize_t debugfs_write_file_bool(struct file *file, const char __user *user_buf, | |||
| 774 | char buf[32]; | 766 | char buf[32]; |
| 775 | size_t buf_size; | 767 | size_t buf_size; |
| 776 | bool bv; | 768 | bool bv; |
| 769 | int r, srcu_idx; | ||
| 777 | bool *val = file->private_data; | 770 | bool *val = file->private_data; |
| 778 | 771 | ||
| 779 | buf_size = min(count, (sizeof(buf)-1)); | 772 | buf_size = min(count, (sizeof(buf)-1)); |
| @@ -781,8 +774,14 @@ ssize_t debugfs_write_file_bool(struct file *file, const char __user *user_buf, | |||
| 781 | return -EFAULT; | 774 | return -EFAULT; |
| 782 | 775 | ||
| 783 | buf[buf_size] = '\0'; | 776 | buf[buf_size] = '\0'; |
| 784 | if (strtobool(buf, &bv) == 0) | 777 | if (strtobool(buf, &bv) == 0) { |
| 785 | *val = bv; | 778 | r = debugfs_use_file_start(F_DENTRY(file), &srcu_idx); |
| 779 | if (likely(!r)) | ||
| 780 | *val = bv; | ||
| 781 | debugfs_use_file_finish(srcu_idx); | ||
| 782 | if (r) | ||
| 783 | return r; | ||
| 784 | } | ||
| 786 | 785 | ||
| 787 | return count; | 786 | return count; |
| 788 | } | 787 | } |
| @@ -834,7 +833,7 @@ static const struct file_operations fops_bool_wo = { | |||
| 834 | struct dentry *debugfs_create_bool(const char *name, umode_t mode, | 833 | struct dentry *debugfs_create_bool(const char *name, umode_t mode, |
| 835 | struct dentry *parent, bool *value) | 834 | struct dentry *parent, bool *value) |
| 836 | { | 835 | { |
| 837 | return debugfs_create_mode(name, mode, parent, value, &fops_bool, | 836 | return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_bool, |
| 838 | &fops_bool_ro, &fops_bool_wo); | 837 | &fops_bool_ro, &fops_bool_wo); |
| 839 | } | 838 | } |
| 840 | EXPORT_SYMBOL_GPL(debugfs_create_bool); | 839 | EXPORT_SYMBOL_GPL(debugfs_create_bool); |
