LCOV - code coverage report
Current view: top level - fs/sysfs - group.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 89 185 48.1 %
Date: 2023-08-24 13:40:31 Functions: 10 18 55.6 %

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

Generated by: LCOV version 1.14