LCOV - code coverage report
Current view: top level - fs/sysfs - group.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 87 220 39.5 %
Date: 2021-04-22 12:43:58 Functions: 9 18 50.0 %

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

Generated by: LCOV version 1.14