~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/sysfs/group.c

Version: ~ [ linux-5.4-rc3 ] ~ [ linux-5.3.6 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.79 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.149 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.196 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.196 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.75 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * fs/sysfs/group.c - Operations for adding/removing multiple files at once.
  3  *
  4  * Copyright (c) 2003 Patrick Mochel
  5  * Copyright (c) 2003 Open Source Development Lab
  6  * Copyright (c) 2013 Greg Kroah-Hartman
  7  * Copyright (c) 2013 The Linux Foundation
  8  *
  9  * This file is released undert the GPL v2.
 10  *
 11  */
 12 
 13 #include <linux/kobject.h>
 14 #include <linux/module.h>
 15 #include <linux/dcache.h>
 16 #include <linux/namei.h>
 17 #include <linux/err.h>
 18 #include "sysfs.h"
 19 
 20 
 21 static void remove_files(struct kernfs_node *parent,
 22                          const struct attribute_group *grp)
 23 {
 24         struct attribute *const *attr;
 25         struct bin_attribute *const *bin_attr;
 26 
 27         if (grp->attrs)
 28                 for (attr = grp->attrs; *attr; attr++)
 29                         kernfs_remove_by_name(parent, (*attr)->name);
 30         if (grp->bin_attrs)
 31                 for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++)
 32                         kernfs_remove_by_name(parent, (*bin_attr)->attr.name);
 33 }
 34 
 35 static int create_files(struct kernfs_node *parent, struct kobject *kobj,
 36                         const struct attribute_group *grp, int update)
 37 {
 38         struct attribute *const *attr;
 39         struct bin_attribute *const *bin_attr;
 40         int error = 0, i;
 41 
 42         if (grp->attrs) {
 43                 for (i = 0, attr = grp->attrs; *attr && !error; i++, attr++) {
 44                         umode_t mode = (*attr)->mode;
 45 
 46                         /*
 47                          * In update mode, we're changing the permissions or
 48                          * visibility.  Do this by first removing then
 49                          * re-adding (if required) the file.
 50                          */
 51                         if (update)
 52                                 kernfs_remove_by_name(parent, (*attr)->name);
 53                         if (grp->is_visible) {
 54                                 mode = grp->is_visible(kobj, *attr, i);
 55                                 if (!mode)
 56                                         continue;
 57                         }
 58 
 59                         WARN(mode & ~(SYSFS_PREALLOC | 0664),
 60                              "Attribute %s: Invalid permissions 0%o\n",
 61                              (*attr)->name, mode);
 62 
 63                         mode &= SYSFS_PREALLOC | 0664;
 64                         error = sysfs_add_file_mode_ns(parent, *attr, false,
 65                                                        mode, NULL);
 66                         if (unlikely(error))
 67                                 break;
 68                 }
 69                 if (error) {
 70                         remove_files(parent, grp);
 71                         goto exit;
 72                 }
 73         }
 74 
 75         if (grp->bin_attrs) {
 76                 for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++) {
 77                         if (update)
 78                                 kernfs_remove_by_name(parent,
 79                                                 (*bin_attr)->attr.name);
 80                         error = sysfs_add_file_mode_ns(parent,
 81                                         &(*bin_attr)->attr, true,
 82                                         (*bin_attr)->attr.mode, NULL);
 83                         if (error)
 84                                 break;
 85                 }
 86                 if (error)
 87                         remove_files(parent, grp);
 88         }
 89 exit:
 90         return error;
 91 }
 92 
 93 
 94 static int internal_create_group(struct kobject *kobj, int update,
 95                                  const struct attribute_group *grp)
 96 {
 97         struct kernfs_node *kn;
 98         int error;
 99 
100         BUG_ON(!kobj || (!update && !kobj->sd));
101 
102         /* Updates may happen before the object has been instantiated */
103         if (unlikely(update && !kobj->sd))
104                 return -EINVAL;
105         if (!grp->attrs && !grp->bin_attrs) {
106                 WARN(1, "sysfs: (bin_)attrs not set by subsystem for group: %s/%s\n",
107                         kobj->name, grp->name ?: "");
108                 return -EINVAL;
109         }
110         if (grp->name) {
111                 kn = kernfs_create_dir(kobj->sd, grp->name,
112                                        S_IRWXU | S_IRUGO | S_IXUGO, kobj);
113                 if (IS_ERR(kn)) {
114                         if (PTR_ERR(kn) == -EEXIST)
115                                 sysfs_warn_dup(kobj->sd, grp->name);
116                         return PTR_ERR(kn);
117                 }
118         } else
119                 kn = kobj->sd;
120         kernfs_get(kn);
121         error = create_files(kn, kobj, grp, update);
122         if (error) {
123                 if (grp->name)
124                         kernfs_remove(kn);
125         }
126         kernfs_put(kn);
127         return error;
128 }
129 
130 /**
131  * sysfs_create_group - given a directory kobject, create an attribute group
132  * @kobj:       The kobject to create the group on
133  * @grp:        The attribute group to create
134  *
135  * This function creates a group for the first time.  It will explicitly
136  * warn and error if any of the attribute files being created already exist.
137  *
138  * Returns 0 on success or error code on failure.
139  */
140 int sysfs_create_group(struct kobject *kobj,
141                        const struct attribute_group *grp)
142 {
143         return internal_create_group(kobj, 0, grp);
144 }
145 EXPORT_SYMBOL_GPL(sysfs_create_group);
146 
147 /**
148  * sysfs_create_groups - given a directory kobject, create a bunch of attribute groups
149  * @kobj:       The kobject to create the group on
150  * @groups:     The attribute groups to create, NULL terminated
151  *
152  * This function creates a bunch of attribute groups.  If an error occurs when
153  * creating a group, all previously created groups will be removed, unwinding
154  * everything back to the original state when this function was called.
155  * It will explicitly warn and error if any of the attribute files being
156  * created already exist.
157  *
158  * Returns 0 on success or error code from sysfs_create_group on failure.
159  */
160 int sysfs_create_groups(struct kobject *kobj,
161                         const struct attribute_group **groups)
162 {
163         int error = 0;
164         int i;
165 
166         if (!groups)
167                 return 0;
168 
169         for (i = 0; groups[i]; i++) {
170                 error = sysfs_create_group(kobj, groups[i]);
171                 if (error) {
172                         while (--i >= 0)
173                                 sysfs_remove_group(kobj, groups[i]);
174                         break;
175                 }
176         }
177         return error;
178 }
179 EXPORT_SYMBOL_GPL(sysfs_create_groups);
180 
181 /**
182  * sysfs_update_group - given a directory kobject, update an attribute group
183  * @kobj:       The kobject to update the group on
184  * @grp:        The attribute group to update
185  *
186  * This function updates an attribute group.  Unlike
187  * sysfs_create_group(), it will explicitly not warn or error if any
188  * of the attribute files being created already exist.  Furthermore,
189  * if the visibility of the files has changed through the is_visible()
190  * callback, it will update the permissions and add or remove the
191  * relevant files.
192  *
193  * The primary use for this function is to call it after making a change
194  * that affects group visibility.
195  *
196  * Returns 0 on success or error code on failure.
197  */
198 int sysfs_update_group(struct kobject *kobj,
199                        const struct attribute_group *grp)
200 {
201         return internal_create_group(kobj, 1, grp);
202 }
203 EXPORT_SYMBOL_GPL(sysfs_update_group);
204 
205 /**
206  * sysfs_remove_group: remove a group from a kobject
207  * @kobj:       kobject to remove the group from
208  * @grp:        group to remove
209  *
210  * This function removes a group of attributes from a kobject.  The attributes
211  * previously have to have been created for this group, otherwise it will fail.
212  */
213 void sysfs_remove_group(struct kobject *kobj,
214                         const struct attribute_group *grp)
215 {
216         struct kernfs_node *parent = kobj->sd;
217         struct kernfs_node *kn;
218 
219         if (grp->name) {
220                 kn = kernfs_find_and_get(parent, grp->name);
221                 if (!kn) {
222                         WARN(!kn, KERN_WARNING
223                              "sysfs group %p not found for kobject '%s'\n",
224                              grp, kobject_name(kobj));
225                         return;
226                 }
227         } else {
228                 kn = parent;
229                 kernfs_get(kn);
230         }
231 
232         remove_files(kn, grp);
233         if (grp->name)
234                 kernfs_remove(kn);
235 
236         kernfs_put(kn);
237 }
238 EXPORT_SYMBOL_GPL(sysfs_remove_group);
239 
240 /**
241  * sysfs_remove_groups - remove a list of groups
242  *
243  * @kobj:       The kobject for the groups to be removed from
244  * @groups:     NULL terminated list of groups to be removed
245  *
246  * If groups is not NULL, remove the specified groups from the kobject.
247  */
248 void sysfs_remove_groups(struct kobject *kobj,
249                          const struct attribute_group **groups)
250 {
251         int i;
252 
253         if (!groups)
254                 return;
255         for (i = 0; groups[i]; i++)
256                 sysfs_remove_group(kobj, groups[i]);
257 }
258 EXPORT_SYMBOL_GPL(sysfs_remove_groups);
259 
260 /**
261  * sysfs_merge_group - merge files into a pre-existing attribute group.
262  * @kobj:       The kobject containing the group.
263  * @grp:        The files to create and the attribute group they belong to.
264  *
265  * This function returns an error if the group doesn't exist or any of the
266  * files already exist in that group, in which case none of the new files
267  * are created.
268  */
269 int sysfs_merge_group(struct kobject *kobj,
270                        const struct attribute_group *grp)
271 {
272         struct kernfs_node *parent;
273         int error = 0;
274         struct attribute *const *attr;
275         int i;
276 
277         parent = kernfs_find_and_get(kobj->sd, grp->name);
278         if (!parent)
279                 return -ENOENT;
280 
281         for ((i = 0, attr = grp->attrs); *attr && !error; (++i, ++attr))
282                 error = sysfs_add_file(parent, *attr, false);
283         if (error) {
284                 while (--i >= 0)
285                         kernfs_remove_by_name(parent, (*--attr)->name);
286         }
287         kernfs_put(parent);
288 
289         return error;
290 }
291 EXPORT_SYMBOL_GPL(sysfs_merge_group);
292 
293 /**
294  * sysfs_unmerge_group - remove files from a pre-existing attribute group.
295  * @kobj:       The kobject containing the group.
296  * @grp:        The files to remove and the attribute group they belong to.
297  */
298 void sysfs_unmerge_group(struct kobject *kobj,
299                        const struct attribute_group *grp)
300 {
301         struct kernfs_node *parent;
302         struct attribute *const *attr;
303 
304         parent = kernfs_find_and_get(kobj->sd, grp->name);
305         if (parent) {
306                 for (attr = grp->attrs; *attr; ++attr)
307                         kernfs_remove_by_name(parent, (*attr)->name);
308                 kernfs_put(parent);
309         }
310 }
311 EXPORT_SYMBOL_GPL(sysfs_unmerge_group);
312 
313 /**
314  * sysfs_add_link_to_group - add a symlink to an attribute group.
315  * @kobj:       The kobject containing the group.
316  * @group_name: The name of the group.
317  * @target:     The target kobject of the symlink to create.
318  * @link_name:  The name of the symlink to create.
319  */
320 int sysfs_add_link_to_group(struct kobject *kobj, const char *group_name,
321                             struct kobject *target, const char *link_name)
322 {
323         struct kernfs_node *parent;
324         int error = 0;
325 
326         parent = kernfs_find_and_get(kobj->sd, group_name);
327         if (!parent)
328                 return -ENOENT;
329 
330         error = sysfs_create_link_sd(parent, target, link_name);
331         kernfs_put(parent);
332 
333         return error;
334 }
335 EXPORT_SYMBOL_GPL(sysfs_add_link_to_group);
336 
337 /**
338  * sysfs_remove_link_from_group - remove a symlink from an attribute group.
339  * @kobj:       The kobject containing the group.
340  * @group_name: The name of the group.
341  * @link_name:  The name of the symlink to remove.
342  */
343 void sysfs_remove_link_from_group(struct kobject *kobj, const char *group_name,
344                                   const char *link_name)
345 {
346         struct kernfs_node *parent;
347 
348         parent = kernfs_find_and_get(kobj->sd, group_name);
349         if (parent) {
350                 kernfs_remove_by_name(parent, link_name);
351                 kernfs_put(parent);
352         }
353 }
354 EXPORT_SYMBOL_GPL(sysfs_remove_link_from_group);
355 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp