990309132c93ca5f386077333c480500c7191ea2
[platform/kernel/linux-starfive.git] / fs / sysfs / group.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * fs/sysfs/group.c - Operations for adding/removing multiple files at once.
4  *
5  * Copyright (c) 2003 Patrick Mochel
6  * Copyright (c) 2003 Open Source Development Lab
7  * Copyright (c) 2013 Greg Kroah-Hartman
8  * Copyright (c) 2013 The Linux Foundation
9  */
10
11 #include <linux/kobject.h>
12 #include <linux/module.h>
13 #include <linux/dcache.h>
14 #include <linux/namei.h>
15 #include <linux/err.h>
16 #include <linux/fs.h>
17 #include "sysfs.h"
18
19
20 static void remove_files(struct kernfs_node *parent,
21                          const struct attribute_group *grp)
22 {
23         struct attribute *const *attr;
24         struct bin_attribute *const *bin_attr;
25
26         if (grp->attrs)
27                 for (attr = grp->attrs; *attr; attr++)
28                         kernfs_remove_by_name(parent, (*attr)->name);
29         if (grp->bin_attrs)
30                 for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++)
31                         kernfs_remove_by_name(parent, (*bin_attr)->attr.name);
32 }
33
34 static int create_files(struct kernfs_node *parent, struct kobject *kobj,
35                         kuid_t uid, kgid_t gid,
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, mode, uid,
65                                                        gid, 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 (i = 0, bin_attr = grp->bin_attrs; *bin_attr; i++, bin_attr++) {
77                         umode_t mode = (*bin_attr)->attr.mode;
78
79                         if (update)
80                                 kernfs_remove_by_name(parent,
81                                                 (*bin_attr)->attr.name);
82                         if (grp->is_bin_visible) {
83                                 mode = grp->is_bin_visible(kobj, *bin_attr, i);
84                                 if (!mode)
85                                         continue;
86                         }
87
88                         WARN(mode & ~(SYSFS_PREALLOC | 0664),
89                              "Attribute %s: Invalid permissions 0%o\n",
90                              (*bin_attr)->attr.name, mode);
91
92                         mode &= SYSFS_PREALLOC | 0664;
93                         error = sysfs_add_bin_file_mode_ns(parent, *bin_attr,
94                                                            mode, uid, gid,
95                                                            NULL);
96                         if (error)
97                                 break;
98                 }
99                 if (error)
100                         remove_files(parent, grp);
101         }
102 exit:
103         return error;
104 }
105
106
107 static int internal_create_group(struct kobject *kobj, int update,
108                                  const struct attribute_group *grp)
109 {
110         struct kernfs_node *kn;
111         kuid_t uid;
112         kgid_t gid;
113         int error;
114
115         if (WARN_ON(!kobj || (!update && !kobj->sd)))
116                 return -EINVAL;
117
118         /* Updates may happen before the object has been instantiated */
119         if (unlikely(update && !kobj->sd))
120                 return -EINVAL;
121         if (!grp->attrs && !grp->bin_attrs) {
122                 WARN(1, "sysfs: (bin_)attrs not set by subsystem for group: %s/%s\n",
123                         kobj->name, grp->name ?: "");
124                 return -EINVAL;
125         }
126         kobject_get_ownership(kobj, &uid, &gid);
127         if (grp->name) {
128                 if (update) {
129                         kn = kernfs_find_and_get(kobj->sd, grp->name);
130                         if (!kn) {
131                                 pr_warn("Can't update unknown attr grp name: %s/%s\n",
132                                         kobj->name, grp->name);
133                                 return -EINVAL;
134                         }
135                 } else {
136                         kn = kernfs_create_dir_ns(kobj->sd, grp->name,
137                                                   S_IRWXU | S_IRUGO | S_IXUGO,
138                                                   uid, gid, kobj, NULL);
139                         if (IS_ERR(kn)) {
140                                 if (PTR_ERR(kn) == -EEXIST)
141                                         sysfs_warn_dup(kobj->sd, grp->name);
142                                 return PTR_ERR(kn);
143                         }
144                 }
145         } else {
146                 kn = kobj->sd;
147         }
148
149         kernfs_get(kn);
150         error = create_files(kn, kobj, uid, gid, grp, update);
151         if (error) {
152                 if (grp->name)
153                         kernfs_remove(kn);
154         }
155         kernfs_put(kn);
156
157         if (grp->name && update)
158                 kernfs_put(kn);
159
160         return error;
161 }
162
163 /**
164  * sysfs_create_group - given a directory kobject, create an attribute group
165  * @kobj:       The kobject to create the group on
166  * @grp:        The attribute group to create
167  *
168  * This function creates a group for the first time.  It will explicitly
169  * warn and error if any of the attribute files being created already exist.
170  *
171  * Returns 0 on success or error code on failure.
172  */
173 int sysfs_create_group(struct kobject *kobj,
174                        const struct attribute_group *grp)
175 {
176         return internal_create_group(kobj, 0, grp);
177 }
178 EXPORT_SYMBOL_GPL(sysfs_create_group);
179
180 static int internal_create_groups(struct kobject *kobj, int update,
181                                   const struct attribute_group **groups)
182 {
183         int error = 0;
184         int i;
185
186         if (!groups)
187                 return 0;
188
189         for (i = 0; groups[i]; i++) {
190                 error = internal_create_group(kobj, update, groups[i]);
191                 if (error) {
192                         while (--i >= 0)
193                                 sysfs_remove_group(kobj, groups[i]);
194                         break;
195                 }
196         }
197         return error;
198 }
199
200 /**
201  * sysfs_create_groups - given a directory kobject, create a bunch of attribute groups
202  * @kobj:       The kobject to create the group on
203  * @groups:     The attribute groups to create, NULL terminated
204  *
205  * This function creates a bunch of attribute groups.  If an error occurs when
206  * creating a group, all previously created groups will be removed, unwinding
207  * everything back to the original state when this function was called.
208  * It will explicitly warn and error if any of the attribute files being
209  * created already exist.
210  *
211  * Returns 0 on success or error code from sysfs_create_group on failure.
212  */
213 int sysfs_create_groups(struct kobject *kobj,
214                         const struct attribute_group **groups)
215 {
216         return internal_create_groups(kobj, 0, groups);
217 }
218 EXPORT_SYMBOL_GPL(sysfs_create_groups);
219
220 /**
221  * sysfs_update_groups - given a directory kobject, create a bunch of attribute groups
222  * @kobj:       The kobject to update the group on
223  * @groups:     The attribute groups to update, NULL terminated
224  *
225  * This function update a bunch of attribute groups.  If an error occurs when
226  * updating a group, all previously updated groups will be removed together
227  * with already existing (not updated) attributes.
228  *
229  * Returns 0 on success or error code from sysfs_update_group on failure.
230  */
231 int sysfs_update_groups(struct kobject *kobj,
232                         const struct attribute_group **groups)
233 {
234         return internal_create_groups(kobj, 1, groups);
235 }
236 EXPORT_SYMBOL_GPL(sysfs_update_groups);
237
238 /**
239  * sysfs_update_group - given a directory kobject, update an attribute group
240  * @kobj:       The kobject to update the group on
241  * @grp:        The attribute group to update
242  *
243  * This function updates an attribute group.  Unlike
244  * sysfs_create_group(), it will explicitly not warn or error if any
245  * of the attribute files being created already exist.  Furthermore,
246  * if the visibility of the files has changed through the is_visible()
247  * callback, it will update the permissions and add or remove the
248  * relevant files. Changing a group's name (subdirectory name under
249  * kobj's directory in sysfs) is not allowed.
250  *
251  * The primary use for this function is to call it after making a change
252  * that affects group visibility.
253  *
254  * Returns 0 on success or error code on failure.
255  */
256 int sysfs_update_group(struct kobject *kobj,
257                        const struct attribute_group *grp)
258 {
259         return internal_create_group(kobj, 1, grp);
260 }
261 EXPORT_SYMBOL_GPL(sysfs_update_group);
262
263 /**
264  * sysfs_remove_group: remove a group from a kobject
265  * @kobj:       kobject to remove the group from
266  * @grp:        group to remove
267  *
268  * This function removes a group of attributes from a kobject.  The attributes
269  * previously have to have been created for this group, otherwise it will fail.
270  */
271 void sysfs_remove_group(struct kobject *kobj,
272                         const struct attribute_group *grp)
273 {
274         struct kernfs_node *parent = kobj->sd;
275         struct kernfs_node *kn;
276
277         if (grp->name) {
278                 kn = kernfs_find_and_get(parent, grp->name);
279                 if (!kn) {
280                         WARN(!kn, KERN_WARNING
281                              "sysfs group '%s' not found for kobject '%s'\n",
282                              grp->name, kobject_name(kobj));
283                         return;
284                 }
285         } else {
286                 kn = parent;
287                 kernfs_get(kn);
288         }
289
290         remove_files(kn, grp);
291         if (grp->name)
292                 kernfs_remove(kn);
293
294         kernfs_put(kn);
295 }
296 EXPORT_SYMBOL_GPL(sysfs_remove_group);
297
298 /**
299  * sysfs_remove_groups - remove a list of groups
300  *
301  * @kobj:       The kobject for the groups to be removed from
302  * @groups:     NULL terminated list of groups to be removed
303  *
304  * If groups is not NULL, remove the specified groups from the kobject.
305  */
306 void sysfs_remove_groups(struct kobject *kobj,
307                          const struct attribute_group **groups)
308 {
309         int i;
310
311         if (!groups)
312                 return;
313         for (i = 0; groups[i]; i++)
314                 sysfs_remove_group(kobj, groups[i]);
315 }
316 EXPORT_SYMBOL_GPL(sysfs_remove_groups);
317
318 /**
319  * sysfs_merge_group - merge files into a pre-existing attribute group.
320  * @kobj:       The kobject containing the group.
321  * @grp:        The files to create and the attribute group they belong to.
322  *
323  * This function returns an error if the group doesn't exist or any of the
324  * files already exist in that group, in which case none of the new files
325  * are created.
326  */
327 int sysfs_merge_group(struct kobject *kobj,
328                        const struct attribute_group *grp)
329 {
330         struct kernfs_node *parent;
331         kuid_t uid;
332         kgid_t gid;
333         int error = 0;
334         struct attribute *const *attr;
335         int i;
336
337         parent = kernfs_find_and_get(kobj->sd, grp->name);
338         if (!parent)
339                 return -ENOENT;
340
341         kobject_get_ownership(kobj, &uid, &gid);
342
343         for ((i = 0, attr = grp->attrs); *attr && !error; (++i, ++attr))
344                 error = sysfs_add_file_mode_ns(parent, *attr, (*attr)->mode,
345                                                uid, gid, NULL);
346         if (error) {
347                 while (--i >= 0)
348                         kernfs_remove_by_name(parent, (*--attr)->name);
349         }
350         kernfs_put(parent);
351
352         return error;
353 }
354 EXPORT_SYMBOL_GPL(sysfs_merge_group);
355
356 /**
357  * sysfs_unmerge_group - remove files from a pre-existing attribute group.
358  * @kobj:       The kobject containing the group.
359  * @grp:        The files to remove and the attribute group they belong to.
360  */
361 void sysfs_unmerge_group(struct kobject *kobj,
362                        const struct attribute_group *grp)
363 {
364         struct kernfs_node *parent;
365         struct attribute *const *attr;
366
367         parent = kernfs_find_and_get(kobj->sd, grp->name);
368         if (parent) {
369                 for (attr = grp->attrs; *attr; ++attr)
370                         kernfs_remove_by_name(parent, (*attr)->name);
371                 kernfs_put(parent);
372         }
373 }
374 EXPORT_SYMBOL_GPL(sysfs_unmerge_group);
375
376 /**
377  * sysfs_add_link_to_group - add a symlink to an attribute group.
378  * @kobj:       The kobject containing the group.
379  * @group_name: The name of the group.
380  * @target:     The target kobject of the symlink to create.
381  * @link_name:  The name of the symlink to create.
382  */
383 int sysfs_add_link_to_group(struct kobject *kobj, const char *group_name,
384                             struct kobject *target, const char *link_name)
385 {
386         struct kernfs_node *parent;
387         int error = 0;
388
389         parent = kernfs_find_and_get(kobj->sd, group_name);
390         if (!parent)
391                 return -ENOENT;
392
393         error = sysfs_create_link_sd(parent, target, link_name);
394         kernfs_put(parent);
395
396         return error;
397 }
398 EXPORT_SYMBOL_GPL(sysfs_add_link_to_group);
399
400 /**
401  * sysfs_remove_link_from_group - remove a symlink from an attribute group.
402  * @kobj:       The kobject containing the group.
403  * @group_name: The name of the group.
404  * @link_name:  The name of the symlink to remove.
405  */
406 void sysfs_remove_link_from_group(struct kobject *kobj, const char *group_name,
407                                   const char *link_name)
408 {
409         struct kernfs_node *parent;
410
411         parent = kernfs_find_and_get(kobj->sd, group_name);
412         if (parent) {
413                 kernfs_remove_by_name(parent, link_name);
414                 kernfs_put(parent);
415         }
416 }
417 EXPORT_SYMBOL_GPL(sysfs_remove_link_from_group);
418
419 /**
420  * compat_only_sysfs_link_entry_to_kobj - add a symlink to a kobject pointing
421  * to a group or an attribute
422  * @kobj:               The kobject containing the group.
423  * @target_kobj:        The target kobject.
424  * @target_name:        The name of the target group or attribute.
425  * @symlink_name:       The name of the symlink file (target_name will be
426  *                      considered if symlink_name is NULL).
427  */
428 int compat_only_sysfs_link_entry_to_kobj(struct kobject *kobj,
429                                          struct kobject *target_kobj,
430                                          const char *target_name,
431                                          const char *symlink_name)
432 {
433         struct kernfs_node *target;
434         struct kernfs_node *entry;
435         struct kernfs_node *link;
436
437         /*
438          * We don't own @target_kobj and it may be removed at any time.
439          * Synchronize using sysfs_symlink_target_lock. See sysfs_remove_dir()
440          * for details.
441          */
442         spin_lock(&sysfs_symlink_target_lock);
443         target = target_kobj->sd;
444         if (target)
445                 kernfs_get(target);
446         spin_unlock(&sysfs_symlink_target_lock);
447         if (!target)
448                 return -ENOENT;
449
450         entry = kernfs_find_and_get(target, target_name);
451         if (!entry) {
452                 kernfs_put(target);
453                 return -ENOENT;
454         }
455
456         if (!symlink_name)
457                 symlink_name = target_name;
458
459         link = kernfs_create_link(kobj->sd, symlink_name, entry);
460         if (PTR_ERR(link) == -EEXIST)
461                 sysfs_warn_dup(kobj->sd, symlink_name);
462
463         kernfs_put(entry);
464         kernfs_put(target);
465         return PTR_ERR_OR_ZERO(link);
466 }
467 EXPORT_SYMBOL_GPL(compat_only_sysfs_link_entry_to_kobj);
468
469 static int sysfs_group_attrs_change_owner(struct kernfs_node *grp_kn,
470                                           const struct attribute_group *grp,
471                                           struct iattr *newattrs)
472 {
473         struct kernfs_node *kn;
474         int error;
475
476         if (grp->attrs) {
477                 struct attribute *const *attr;
478
479                 for (attr = grp->attrs; *attr; attr++) {
480                         kn = kernfs_find_and_get(grp_kn, (*attr)->name);
481                         if (!kn)
482                                 return -ENOENT;
483
484                         error = kernfs_setattr(kn, newattrs);
485                         kernfs_put(kn);
486                         if (error)
487                                 return error;
488                 }
489         }
490
491         if (grp->bin_attrs) {
492                 struct bin_attribute *const *bin_attr;
493
494                 for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++) {
495                         kn = kernfs_find_and_get(grp_kn, (*bin_attr)->attr.name);
496                         if (!kn)
497                                 return -ENOENT;
498
499                         error = kernfs_setattr(kn, newattrs);
500                         kernfs_put(kn);
501                         if (error)
502                                 return error;
503                 }
504         }
505
506         return 0;
507 }
508
509 /**
510  * sysfs_group_change_owner - change owner of an attribute group.
511  * @kobj:       The kobject containing the group.
512  * @grp:        The attribute group.
513  * @kuid:       new owner's kuid
514  * @kgid:       new owner's kgid
515  *
516  * Returns 0 on success or error code on failure.
517  */
518 int sysfs_group_change_owner(struct kobject *kobj,
519                              const struct attribute_group *grp, kuid_t kuid,
520                              kgid_t kgid)
521 {
522         struct kernfs_node *grp_kn;
523         int error;
524         struct iattr newattrs = {
525                 .ia_valid = ATTR_UID | ATTR_GID,
526                 .ia_uid = kuid,
527                 .ia_gid = kgid,
528         };
529
530         if (!kobj->state_in_sysfs)
531                 return -EINVAL;
532
533         if (grp->name) {
534                 grp_kn = kernfs_find_and_get(kobj->sd, grp->name);
535         } else {
536                 kernfs_get(kobj->sd);
537                 grp_kn = kobj->sd;
538         }
539         if (!grp_kn)
540                 return -ENOENT;
541
542         error = kernfs_setattr(grp_kn, &newattrs);
543         if (!error)
544                 error = sysfs_group_attrs_change_owner(grp_kn, grp, &newattrs);
545
546         kernfs_put(grp_kn);
547
548         return error;
549 }
550 EXPORT_SYMBOL_GPL(sysfs_group_change_owner);
551
552 /**
553  * sysfs_groups_change_owner - change owner of a set of attribute groups.
554  * @kobj:       The kobject containing the groups.
555  * @groups:     The attribute groups.
556  * @kuid:       new owner's kuid
557  * @kgid:       new owner's kgid
558  *
559  * Returns 0 on success or error code on failure.
560  */
561 int sysfs_groups_change_owner(struct kobject *kobj,
562                               const struct attribute_group **groups,
563                               kuid_t kuid, kgid_t kgid)
564 {
565         int error = 0, i;
566
567         if (!kobj->state_in_sysfs)
568                 return -EINVAL;
569
570         if (!groups)
571                 return 0;
572
573         for (i = 0; groups[i]; i++) {
574                 error = sysfs_group_change_owner(kobj, groups[i], kuid, kgid);
575                 if (error)
576                         break;
577         }
578
579         return error;
580 }
581 EXPORT_SYMBOL_GPL(sysfs_groups_change_owner);