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

Generated by: LCOV version 1.14