diff options
author | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-03-20 21:47:52 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-04-22 16:16:31 -0400 |
commit | 0f4238958d28044b335644b69df6071cdb04b5ce (patch) | |
tree | 159b82f8eb9479cdc10f861d682309b4c0c8c411 | |
parent | bbd1ae412c9eb09ae7bb11cfaf7018a2367d493f (diff) |
[SCSI] sysfs: make group is_valid return a mode_t
We have a problem in scsi_transport_spi in that we need to customise
not only the visibility of the attributes, but also their mode. Fix
this by making the is_visible() callback return a mode, with 0
indicating is not visible.
Also add a sysfs_update_group() API to allow us to change either the
visibility or mode of the files at any time on the fly.
Acked-by: Kay Sievers <kay.sievers@vrfy.org>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r-- | fs/sysfs/file.c | 14 | ||||
-rw-r--r-- | fs/sysfs/group.c | 83 | ||||
-rw-r--r-- | fs/sysfs/sysfs.h | 2 | ||||
-rw-r--r-- | include/linux/sysfs.h | 4 |
4 files changed, 85 insertions, 18 deletions
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index ade9a7e6a757..dbdfabbfd609 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
@@ -477,11 +477,10 @@ const struct file_operations sysfs_file_operations = { | |||
477 | .poll = sysfs_poll, | 477 | .poll = sysfs_poll, |
478 | }; | 478 | }; |
479 | 479 | ||
480 | 480 | int sysfs_add_file_mode(struct sysfs_dirent *dir_sd, | |
481 | int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, | 481 | const struct attribute *attr, int type, mode_t amode) |
482 | int type) | ||
483 | { | 482 | { |
484 | umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG; | 483 | umode_t mode = (amode & S_IALLUGO) | S_IFREG; |
485 | struct sysfs_addrm_cxt acxt; | 484 | struct sysfs_addrm_cxt acxt; |
486 | struct sysfs_dirent *sd; | 485 | struct sysfs_dirent *sd; |
487 | int rc; | 486 | int rc; |
@@ -502,6 +501,13 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, | |||
502 | } | 501 | } |
503 | 502 | ||
504 | 503 | ||
504 | int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, | ||
505 | int type) | ||
506 | { | ||
507 | return sysfs_add_file_mode(dir_sd, attr, type, attr->mode); | ||
508 | } | ||
509 | |||
510 | |||
505 | /** | 511 | /** |
506 | * sysfs_create_file - create an attribute file for an object. | 512 | * sysfs_create_file - create an attribute file for an object. |
507 | * @kobj: object we're creating for. | 513 | * @kobj: object we're creating for. |
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); |
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index ff17f8da9b43..ce4e15f8aaeb 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h | |||
@@ -154,6 +154,8 @@ extern const struct file_operations sysfs_file_operations; | |||
154 | int sysfs_add_file(struct sysfs_dirent *dir_sd, | 154 | int sysfs_add_file(struct sysfs_dirent *dir_sd, |
155 | const struct attribute *attr, int type); | 155 | const struct attribute *attr, int type); |
156 | 156 | ||
157 | int sysfs_add_file_mode(struct sysfs_dirent *dir_sd, | ||
158 | const struct attribute *attr, int type, mode_t amode); | ||
157 | /* | 159 | /* |
158 | * bin.c | 160 | * bin.c |
159 | */ | 161 | */ |
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 03378e3515b3..add3c5a40827 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h | |||
@@ -32,7 +32,7 @@ struct attribute { | |||
32 | 32 | ||
33 | struct attribute_group { | 33 | struct attribute_group { |
34 | const char *name; | 34 | const char *name; |
35 | int (*is_visible)(struct kobject *, | 35 | mode_t (*is_visible)(struct kobject *, |
36 | struct attribute *, int); | 36 | struct attribute *, int); |
37 | struct attribute **attrs; | 37 | struct attribute **attrs; |
38 | }; | 38 | }; |
@@ -105,6 +105,8 @@ void sysfs_remove_link(struct kobject *kobj, const char *name); | |||
105 | 105 | ||
106 | int __must_check sysfs_create_group(struct kobject *kobj, | 106 | int __must_check sysfs_create_group(struct kobject *kobj, |
107 | const struct attribute_group *grp); | 107 | const struct attribute_group *grp); |
108 | int sysfs_update_group(struct kobject *kobj, | ||
109 | const struct attribute_group *grp); | ||
108 | void sysfs_remove_group(struct kobject *kobj, | 110 | void sysfs_remove_group(struct kobject *kobj, |
109 | const struct attribute_group *grp); | 111 | const struct attribute_group *grp); |
110 | int sysfs_add_file_to_group(struct kobject *kobj, | 112 | int sysfs_add_file_to_group(struct kobject *kobj, |