diff options
Diffstat (limited to 'fs/sysfs/group.c')
-rw-r--r-- | fs/sysfs/group.c | 83 |
1 files changed, 70 insertions, 13 deletions
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index 477904915032..eeba38417b1d 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c | |||
@@ -23,35 +23,50 @@ static void remove_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, | |||
23 | int i; | 23 | int i; |
24 | 24 | ||
25 | for (i = 0, attr = grp->attrs; *attr; i++, attr++) | 25 | for (i = 0, attr = grp->attrs; *attr; i++, attr++) |
26 | if (!grp->is_visible || | 26 | sysfs_hash_and_remove(dir_sd, (*attr)->name); |
27 | grp->is_visible(kobj, *attr, i)) | ||
28 | sysfs_hash_and_remove(dir_sd, (*attr)->name); | ||
29 | } | 27 | } |
30 | 28 | ||
31 | static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, | 29 | static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, |
32 | const struct attribute_group *grp) | 30 | const struct attribute_group *grp, int update) |
33 | { | 31 | { |
34 | struct attribute *const* attr; | 32 | struct attribute *const* attr; |
35 | int error = 0, i; | 33 | int error = 0, i; |
36 | 34 | ||
37 | for (i = 0, attr = grp->attrs; *attr && !error; i++, attr++) | 35 | for (i = 0, attr = grp->attrs; *attr && !error; i++, attr++) { |
38 | if (!grp->is_visible || | 36 | mode_t mode = 0; |
39 | grp->is_visible(kobj, *attr, i)) | 37 | |
40 | error |= | 38 | /* in update mode, we're changing the permissions or |
41 | sysfs_add_file(dir_sd, *attr, SYSFS_KOBJ_ATTR); | 39 | * visibility. Do this by first removing then |
40 | * re-adding (if required) the file */ | ||
41 | if (update) | ||
42 | sysfs_hash_and_remove(dir_sd, (*attr)->name); | ||
43 | if (grp->is_visible) { | ||
44 | mode = grp->is_visible(kobj, *attr, i); | ||
45 | if (!mode) | ||
46 | continue; | ||
47 | } | ||
48 | error = sysfs_add_file_mode(dir_sd, *attr, SYSFS_KOBJ_ATTR, | ||
49 | (*attr)->mode | mode); | ||
50 | if (unlikely(error)) | ||
51 | break; | ||
52 | } | ||
42 | if (error) | 53 | if (error) |
43 | remove_files(dir_sd, kobj, grp); | 54 | remove_files(dir_sd, kobj, grp); |
44 | return error; | 55 | return error; |
45 | } | 56 | } |
46 | 57 | ||
47 | 58 | ||
48 | int sysfs_create_group(struct kobject * kobj, | 59 | static int internal_create_group(struct kobject *kobj, int update, |
49 | const struct attribute_group * grp) | 60 | const struct attribute_group *grp) |
50 | { | 61 | { |
51 | struct sysfs_dirent *sd; | 62 | struct sysfs_dirent *sd; |
52 | int error; | 63 | int error; |
53 | 64 | ||
54 | BUG_ON(!kobj || !kobj->sd); | 65 | BUG_ON(!kobj || (!update && !kobj->sd)); |
66 | |||
67 | /* Updates may happen before the object has been instantiated */ | ||
68 | if (unlikely(update && !kobj->sd)) | ||
69 | return -EINVAL; | ||
55 | 70 | ||
56 | if (grp->name) { | 71 | if (grp->name) { |
57 | error = sysfs_create_subdir(kobj, grp->name, &sd); | 72 | error = sysfs_create_subdir(kobj, grp->name, &sd); |
@@ -60,7 +75,7 @@ int sysfs_create_group(struct kobject * kobj, | |||
60 | } else | 75 | } else |
61 | sd = kobj->sd; | 76 | sd = kobj->sd; |
62 | sysfs_get(sd); | 77 | sysfs_get(sd); |
63 | error = create_files(sd, kobj, grp); | 78 | error = create_files(sd, kobj, grp, update); |
64 | if (error) { | 79 | if (error) { |
65 | if (grp->name) | 80 | if (grp->name) |
66 | sysfs_remove_subdir(sd); | 81 | sysfs_remove_subdir(sd); |
@@ -69,6 +84,47 @@ int sysfs_create_group(struct kobject * kobj, | |||
69 | return error; | 84 | return error; |
70 | } | 85 | } |
71 | 86 | ||
87 | /** | ||
88 | * sysfs_create_group - given a directory kobject, create an attribute group | ||
89 | * @kobj: The kobject to create the group on | ||
90 | * @grp: The attribute group to create | ||
91 | * | ||
92 | * This function creates a group for the first time. It will explicitly | ||
93 | * warn and error if any of the attribute files being created already exist. | ||
94 | * | ||
95 | * Returns 0 on success or error. | ||
96 | */ | ||
97 | int sysfs_create_group(struct kobject *kobj, | ||
98 | const struct attribute_group *grp) | ||
99 | { | ||
100 | return internal_create_group(kobj, 0, grp); | ||
101 | } | ||
102 | |||
103 | /** | ||
104 | * sysfs_update_group - given a directory kobject, create an attribute group | ||
105 | * @kobj: The kobject to create the group on | ||
106 | * @grp: The attribute group to create | ||
107 | * | ||
108 | * This function updates an attribute group. Unlike | ||
109 | * sysfs_create_group(), it will explicitly not warn or error if any | ||
110 | * of the attribute files being created already exist. Furthermore, | ||
111 | * if the visibility of the files has changed through the is_visible() | ||
112 | * callback, it will update the permissions and add or remove the | ||
113 | * relevant files. | ||
114 | * | ||
115 | * The primary use for this function is to call it after making a change | ||
116 | * that affects group visibility. | ||
117 | * | ||
118 | * Returns 0 on success or error. | ||
119 | */ | ||
120 | int sysfs_update_group(struct kobject *kobj, | ||
121 | const struct attribute_group *grp) | ||
122 | { | ||
123 | return internal_create_group(kobj, 1, grp); | ||
124 | } | ||
125 | |||
126 | |||
127 | |||
72 | void sysfs_remove_group(struct kobject * kobj, | 128 | void sysfs_remove_group(struct kobject * kobj, |
73 | const struct attribute_group * grp) | 129 | const struct attribute_group * grp) |
74 | { | 130 | { |
@@ -95,4 +151,5 @@ void sysfs_remove_group(struct kobject * kobj, | |||
95 | 151 | ||
96 | 152 | ||
97 | EXPORT_SYMBOL_GPL(sysfs_create_group); | 153 | EXPORT_SYMBOL_GPL(sysfs_create_group); |
154 | EXPORT_SYMBOL_GPL(sysfs_update_group); | ||
98 | EXPORT_SYMBOL_GPL(sysfs_remove_group); | 155 | EXPORT_SYMBOL_GPL(sysfs_remove_group); |