aboutsummaryrefslogtreecommitdiffstats
path: root/fs/sysfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/sysfs')
-rw-r--r--fs/sysfs/dir.c68
-rw-r--r--fs/sysfs/file.c10
-rw-r--r--fs/sysfs/group.c70
-rw-r--r--fs/sysfs/inode.c2
4 files changed, 73 insertions, 77 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index e8e0e71b29d5..e068e744dbdd 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -74,7 +74,7 @@ static int sysfs_sd_compare(const struct sysfs_dirent *left,
74} 74}
75 75
76/** 76/**
77 * sysfs_link_subling - link sysfs_dirent into sibling rbtree 77 * sysfs_link_sibling - link sysfs_dirent into sibling rbtree
78 * @sd: sysfs_dirent of interest 78 * @sd: sysfs_dirent of interest
79 * 79 *
80 * Link @sd into its sibling rbtree which starts from 80 * Link @sd into its sibling rbtree which starts from
@@ -998,68 +998,38 @@ static struct sysfs_dirent *sysfs_dir_next_pos(const void *ns,
998 return pos; 998 return pos;
999} 999}
1000 1000
1001static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) 1001static int sysfs_readdir(struct file *file, struct dir_context *ctx)
1002{ 1002{
1003 struct dentry *dentry = filp->f_path.dentry; 1003 struct dentry *dentry = file->f_path.dentry;
1004 struct sysfs_dirent * parent_sd = dentry->d_fsdata; 1004 struct sysfs_dirent * parent_sd = dentry->d_fsdata;
1005 struct sysfs_dirent *pos = filp->private_data; 1005 struct sysfs_dirent *pos = file->private_data;
1006 enum kobj_ns_type type; 1006 enum kobj_ns_type type;
1007 const void *ns; 1007 const void *ns;
1008 ino_t ino;
1009 loff_t off;
1010 1008
1011 type = sysfs_ns_type(parent_sd); 1009 type = sysfs_ns_type(parent_sd);
1012 ns = sysfs_info(dentry->d_sb)->ns[type]; 1010 ns = sysfs_info(dentry->d_sb)->ns[type];
1013 1011
1014 if (filp->f_pos == 0) { 1012 if (!dir_emit_dots(file, ctx))
1015 ino = parent_sd->s_ino; 1013 return 0;
1016 if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) == 0)
1017 filp->f_pos++;
1018 else
1019 return 0;
1020 }
1021 if (filp->f_pos == 1) {
1022 if (parent_sd->s_parent)
1023 ino = parent_sd->s_parent->s_ino;
1024 else
1025 ino = parent_sd->s_ino;
1026 if (filldir(dirent, "..", 2, filp->f_pos, ino, DT_DIR) == 0)
1027 filp->f_pos++;
1028 else
1029 return 0;
1030 }
1031 mutex_lock(&sysfs_mutex); 1014 mutex_lock(&sysfs_mutex);
1032 off = filp->f_pos; 1015 for (pos = sysfs_dir_pos(ns, parent_sd, ctx->pos, pos);
1033 for (pos = sysfs_dir_pos(ns, parent_sd, filp->f_pos, pos);
1034 pos; 1016 pos;
1035 pos = sysfs_dir_next_pos(ns, parent_sd, filp->f_pos, pos)) { 1017 pos = sysfs_dir_next_pos(ns, parent_sd, ctx->pos, pos)) {
1036 const char * name; 1018 const char *name = pos->s_name;
1037 unsigned int type; 1019 unsigned int type = dt_type(pos);
1038 int len, ret; 1020 int len = strlen(name);
1039 1021 ino_t ino = pos->s_ino;
1040 name = pos->s_name; 1022 ctx->pos = pos->s_hash;
1041 len = strlen(name); 1023 file->private_data = sysfs_get(pos);
1042 ino = pos->s_ino;
1043 type = dt_type(pos);
1044 off = filp->f_pos = pos->s_hash;
1045 filp->private_data = sysfs_get(pos);
1046 1024
1047 mutex_unlock(&sysfs_mutex); 1025 mutex_unlock(&sysfs_mutex);
1048 ret = filldir(dirent, name, len, off, ino, type); 1026 if (!dir_emit(ctx, name, len, ino, type))
1027 return 0;
1049 mutex_lock(&sysfs_mutex); 1028 mutex_lock(&sysfs_mutex);
1050 if (ret < 0)
1051 break;
1052 } 1029 }
1053 mutex_unlock(&sysfs_mutex); 1030 mutex_unlock(&sysfs_mutex);
1054 1031 file->private_data = NULL;
1055 /* don't reference last entry if its refcount is dropped */ 1032 ctx->pos = INT_MAX;
1056 if (!pos) {
1057 filp->private_data = NULL;
1058
1059 /* EOF and not changed as 0 or 1 in read/write path */
1060 if (off == filp->f_pos && off > 1)
1061 filp->f_pos = INT_MAX;
1062 }
1063 return 0; 1033 return 0;
1064} 1034}
1065 1035
@@ -1077,7 +1047,7 @@ static loff_t sysfs_dir_llseek(struct file *file, loff_t offset, int whence)
1077 1047
1078const struct file_operations sysfs_dir_operations = { 1048const struct file_operations sysfs_dir_operations = {
1079 .read = generic_read_dir, 1049 .read = generic_read_dir,
1080 .readdir = sysfs_readdir, 1050 .iterate = sysfs_readdir,
1081 .release = sysfs_dir_release, 1051 .release = sysfs_dir_release,
1082 .llseek = sysfs_dir_llseek, 1052 .llseek = sysfs_dir_llseek,
1083}; 1053};
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 602f56db0442..d2bb7ed8fa74 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -449,10 +449,12 @@ void sysfs_notify_dirent(struct sysfs_dirent *sd)
449 449
450 spin_lock_irqsave(&sysfs_open_dirent_lock, flags); 450 spin_lock_irqsave(&sysfs_open_dirent_lock, flags);
451 451
452 od = sd->s_attr.open; 452 if (!WARN_ON(sysfs_type(sd) != SYSFS_KOBJ_ATTR)) {
453 if (od) { 453 od = sd->s_attr.open;
454 atomic_inc(&od->event); 454 if (od) {
455 wake_up_interruptible(&od->poll); 455 atomic_inc(&od->event);
456 wake_up_interruptible(&od->poll);
457 }
456 } 458 }
457 459
458 spin_unlock_irqrestore(&sysfs_open_dirent_lock, flags); 460 spin_unlock_irqrestore(&sysfs_open_dirent_lock, flags);
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index aec3d5c98c94..09a1a25cd145 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -20,38 +20,64 @@ static void remove_files(struct sysfs_dirent *dir_sd, struct kobject *kobj,
20 const struct attribute_group *grp) 20 const struct attribute_group *grp)
21{ 21{
22 struct attribute *const* attr; 22 struct attribute *const* attr;
23 int i; 23 struct bin_attribute *const* bin_attr;
24 24
25 for (i = 0, attr = grp->attrs; *attr; i++, attr++) 25 if (grp->attrs)
26 sysfs_hash_and_remove(dir_sd, NULL, (*attr)->name); 26 for (attr = grp->attrs; *attr; attr++)
27 sysfs_hash_and_remove(dir_sd, NULL, (*attr)->name);
28 if (grp->bin_attrs)
29 for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++)
30 sysfs_remove_bin_file(kobj, *bin_attr);
27} 31}
28 32
29static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, 33static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj,
30 const struct attribute_group *grp, int update) 34 const struct attribute_group *grp, int update)
31{ 35{
32 struct attribute *const* attr; 36 struct attribute *const* attr;
37 struct bin_attribute *const* bin_attr;
33 int error = 0, i; 38 int error = 0, i;
34 39
35 for (i = 0, attr = grp->attrs; *attr && !error; i++, attr++) { 40 if (grp->attrs) {
36 umode_t mode = 0; 41 for (i = 0, attr = grp->attrs; *attr && !error; i++, attr++) {
42 umode_t mode = 0;
43
44 /*
45 * In update mode, we're changing the permissions or
46 * visibility. Do this by first removing then
47 * re-adding (if required) the file.
48 */
49 if (update)
50 sysfs_hash_and_remove(dir_sd, NULL,
51 (*attr)->name);
52 if (grp->is_visible) {
53 mode = grp->is_visible(kobj, *attr, i);
54 if (!mode)
55 continue;
56 }
57 error = sysfs_add_file_mode(dir_sd, *attr,
58 SYSFS_KOBJ_ATTR,
59 (*attr)->mode | mode);
60 if (unlikely(error))
61 break;
62 }
63 if (error) {
64 remove_files(dir_sd, kobj, grp);
65 goto exit;
66 }
67 }
37 68
38 /* in update mode, we're changing the permissions or 69 if (grp->bin_attrs) {
39 * visibility. Do this by first removing then 70 for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++) {
40 * re-adding (if required) the file */ 71 if (update)
41 if (update) 72 sysfs_remove_bin_file(kobj, *bin_attr);
42 sysfs_hash_and_remove(dir_sd, NULL, (*attr)->name); 73 error = sysfs_create_bin_file(kobj, *bin_attr);
43 if (grp->is_visible) { 74 if (error)
44 mode = grp->is_visible(kobj, *attr, i); 75 break;
45 if (!mode)
46 continue;
47 } 76 }
48 error = sysfs_add_file_mode(dir_sd, *attr, SYSFS_KOBJ_ATTR, 77 if (error)
49 (*attr)->mode | mode); 78 remove_files(dir_sd, kobj, grp);
50 if (unlikely(error))
51 break;
52 } 79 }
53 if (error) 80exit:
54 remove_files(dir_sd, kobj, grp);
55 return error; 81 return error;
56} 82}
57 83
@@ -67,8 +93,8 @@ static int internal_create_group(struct kobject *kobj, int update,
67 /* Updates may happen before the object has been instantiated */ 93 /* Updates may happen before the object has been instantiated */
68 if (unlikely(update && !kobj->sd)) 94 if (unlikely(update && !kobj->sd))
69 return -EINVAL; 95 return -EINVAL;
70 if (!grp->attrs) { 96 if (!grp->attrs && !grp->bin_attrs) {
71 WARN(1, "sysfs: attrs not set by subsystem for group: %s/%s\n", 97 WARN(1, "sysfs: (bin_)attrs not set by subsystem for group: %s/%s\n",
72 kobj->name, grp->name ? "" : grp->name); 98 kobj->name, grp->name ? "" : grp->name);
73 return -EINVAL; 99 return -EINVAL;
74 } 100 }
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index 0ce3ccf7f401..3e2837a633ed 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -24,8 +24,6 @@
24#include <linux/security.h> 24#include <linux/security.h>
25#include "sysfs.h" 25#include "sysfs.h"
26 26
27extern struct super_block * sysfs_sb;
28
29static const struct address_space_operations sysfs_aops = { 27static const struct address_space_operations sysfs_aops = {
30 .readpage = simple_readpage, 28 .readpage = simple_readpage,
31 .write_begin = simple_write_begin, 29 .write_begin = simple_write_begin,