LCOV - code coverage report
Current view: top level - fs/sysfs - file.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 53 231 22.9 %
Date: 2023-08-24 13:40:31 Functions: 7 28 25.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  * fs/sysfs/file.c - sysfs regular (text) file implementation
       4             :  *
       5             :  * Copyright (c) 2001-3 Patrick Mochel
       6             :  * Copyright (c) 2007 SUSE Linux Products GmbH
       7             :  * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
       8             :  *
       9             :  * Please see Documentation/filesystems/sysfs.rst for more information.
      10             :  */
      11             : 
      12             : #include <linux/module.h>
      13             : #include <linux/kobject.h>
      14             : #include <linux/slab.h>
      15             : #include <linux/list.h>
      16             : #include <linux/mutex.h>
      17             : #include <linux/seq_file.h>
      18             : #include <linux/mm.h>
      19             : 
      20             : #include "sysfs.h"
      21             : 
      22             : /*
      23             :  * Determine ktype->sysfs_ops for the given kernfs_node.  This function
      24             :  * must be called while holding an active reference.
      25             :  */
      26             : static const struct sysfs_ops *sysfs_file_ops(struct kernfs_node *kn)
      27             : {
      28           0 :         struct kobject *kobj = kn->parent->priv;
      29             : 
      30             :         if (kn->flags & KERNFS_LOCKDEP)
      31             :                 lockdep_assert_held(kn);
      32           0 :         return kobj->ktype ? kobj->ktype->sysfs_ops : NULL;
      33             : }
      34             : 
      35             : /*
      36             :  * Reads on sysfs are handled through seq_file, which takes care of hairy
      37             :  * details like buffering and seeking.  The following function pipes
      38             :  * sysfs_ops->show() result through seq_file.
      39             :  */
      40           0 : static int sysfs_kf_seq_show(struct seq_file *sf, void *v)
      41             : {
      42           0 :         struct kernfs_open_file *of = sf->private;
      43           0 :         struct kobject *kobj = of->kn->parent->priv;
      44           0 :         const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
      45             :         ssize_t count;
      46             :         char *buf;
      47             : 
      48           0 :         if (WARN_ON_ONCE(!ops->show))
      49             :                 return -EINVAL;
      50             : 
      51             :         /* acquire buffer and ensure that it's >= PAGE_SIZE and clear */
      52           0 :         count = seq_get_buf(sf, &buf);
      53           0 :         if (count < PAGE_SIZE) {
      54           0 :                 seq_commit(sf, -1);
      55           0 :                 return 0;
      56             :         }
      57           0 :         memset(buf, 0, PAGE_SIZE);
      58             : 
      59           0 :         count = ops->show(kobj, of->kn->priv, buf);
      60           0 :         if (count < 0)
      61           0 :                 return count;
      62             : 
      63             :         /*
      64             :          * The code works fine with PAGE_SIZE return but it's likely to
      65             :          * indicate truncated result or overflow in normal use cases.
      66             :          */
      67           0 :         if (count >= (ssize_t)PAGE_SIZE) {
      68           0 :                 printk("fill_read_buffer: %pS returned bad count\n",
      69             :                                 ops->show);
      70             :                 /* Try to struggle along */
      71           0 :                 count = PAGE_SIZE - 1;
      72             :         }
      73           0 :         seq_commit(sf, count);
      74           0 :         return 0;
      75             : }
      76             : 
      77           0 : static ssize_t sysfs_kf_bin_read(struct kernfs_open_file *of, char *buf,
      78             :                                  size_t count, loff_t pos)
      79             : {
      80           0 :         struct bin_attribute *battr = of->kn->priv;
      81           0 :         struct kobject *kobj = of->kn->parent->priv;
      82           0 :         loff_t size = file_inode(of->file)->i_size;
      83             : 
      84           0 :         if (!count)
      85             :                 return 0;
      86             : 
      87           0 :         if (size) {
      88           0 :                 if (pos >= size)
      89             :                         return 0;
      90           0 :                 if (pos + count > size)
      91           0 :                         count = size - pos;
      92             :         }
      93             : 
      94           0 :         if (!battr->read)
      95             :                 return -EIO;
      96             : 
      97           0 :         return battr->read(of->file, kobj, battr, buf, pos, count);
      98             : }
      99             : 
     100             : /* kernfs read callback for regular sysfs files with pre-alloc */
     101           0 : static ssize_t sysfs_kf_read(struct kernfs_open_file *of, char *buf,
     102             :                              size_t count, loff_t pos)
     103             : {
     104           0 :         const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
     105           0 :         struct kobject *kobj = of->kn->parent->priv;
     106             :         ssize_t len;
     107             : 
     108             :         /*
     109             :          * If buf != of->prealloc_buf, we don't know how
     110             :          * large it is, so cannot safely pass it to ->show
     111             :          */
     112           0 :         if (WARN_ON_ONCE(buf != of->prealloc_buf))
     113             :                 return 0;
     114           0 :         len = ops->show(kobj, of->kn->priv, buf);
     115           0 :         if (len < 0)
     116             :                 return len;
     117           0 :         if (pos) {
     118           0 :                 if (len <= pos)
     119             :                         return 0;
     120           0 :                 len -= pos;
     121           0 :                 memmove(buf, buf + pos, len);
     122             :         }
     123           0 :         return min_t(ssize_t, count, len);
     124             : }
     125             : 
     126             : /* kernfs write callback for regular sysfs files */
     127           0 : static ssize_t sysfs_kf_write(struct kernfs_open_file *of, char *buf,
     128             :                               size_t count, loff_t pos)
     129             : {
     130           0 :         const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
     131           0 :         struct kobject *kobj = of->kn->parent->priv;
     132             : 
     133           0 :         if (!count)
     134             :                 return 0;
     135             : 
     136           0 :         return ops->store(kobj, of->kn->priv, buf, count);
     137             : }
     138             : 
     139             : /* kernfs write callback for bin sysfs files */
     140           0 : static ssize_t sysfs_kf_bin_write(struct kernfs_open_file *of, char *buf,
     141             :                                   size_t count, loff_t pos)
     142             : {
     143           0 :         struct bin_attribute *battr = of->kn->priv;
     144           0 :         struct kobject *kobj = of->kn->parent->priv;
     145           0 :         loff_t size = file_inode(of->file)->i_size;
     146             : 
     147           0 :         if (size) {
     148           0 :                 if (size <= pos)
     149             :                         return -EFBIG;
     150           0 :                 count = min_t(ssize_t, count, size - pos);
     151             :         }
     152           0 :         if (!count)
     153             :                 return 0;
     154             : 
     155           0 :         if (!battr->write)
     156             :                 return -EIO;
     157             : 
     158           0 :         return battr->write(of->file, kobj, battr, buf, pos, count);
     159             : }
     160             : 
     161           0 : static int sysfs_kf_bin_mmap(struct kernfs_open_file *of,
     162             :                              struct vm_area_struct *vma)
     163             : {
     164           0 :         struct bin_attribute *battr = of->kn->priv;
     165           0 :         struct kobject *kobj = of->kn->parent->priv;
     166             : 
     167           0 :         return battr->mmap(of->file, kobj, battr, vma);
     168             : }
     169             : 
     170           0 : static int sysfs_kf_bin_open(struct kernfs_open_file *of)
     171             : {
     172           0 :         struct bin_attribute *battr = of->kn->priv;
     173             : 
     174           0 :         if (battr->f_mapping)
     175           0 :                 of->file->f_mapping = battr->f_mapping();
     176             : 
     177           0 :         return 0;
     178             : }
     179             : 
     180           2 : void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr)
     181             : {
     182           2 :         struct kernfs_node *kn = kobj->sd, *tmp;
     183             : 
     184           2 :         if (kn && dir)
     185           0 :                 kn = kernfs_find_and_get(kn, dir);
     186             :         else
     187           2 :                 kernfs_get(kn);
     188             : 
     189           2 :         if (kn && attr) {
     190           2 :                 tmp = kernfs_find_and_get(kn, attr);
     191           2 :                 kernfs_put(kn);
     192           2 :                 kn = tmp;
     193             :         }
     194             : 
     195           2 :         if (kn) {
     196           2 :                 kernfs_notify(kn);
     197           2 :                 kernfs_put(kn);
     198             :         }
     199           2 : }
     200             : EXPORT_SYMBOL_GPL(sysfs_notify);
     201             : 
     202             : static const struct kernfs_ops sysfs_file_kfops_empty = {
     203             : };
     204             : 
     205             : static const struct kernfs_ops sysfs_file_kfops_ro = {
     206             :         .seq_show       = sysfs_kf_seq_show,
     207             : };
     208             : 
     209             : static const struct kernfs_ops sysfs_file_kfops_wo = {
     210             :         .write          = sysfs_kf_write,
     211             : };
     212             : 
     213             : static const struct kernfs_ops sysfs_file_kfops_rw = {
     214             :         .seq_show       = sysfs_kf_seq_show,
     215             :         .write          = sysfs_kf_write,
     216             : };
     217             : 
     218             : static const struct kernfs_ops sysfs_prealloc_kfops_ro = {
     219             :         .read           = sysfs_kf_read,
     220             :         .prealloc       = true,
     221             : };
     222             : 
     223             : static const struct kernfs_ops sysfs_prealloc_kfops_wo = {
     224             :         .write          = sysfs_kf_write,
     225             :         .prealloc       = true,
     226             : };
     227             : 
     228             : static const struct kernfs_ops sysfs_prealloc_kfops_rw = {
     229             :         .read           = sysfs_kf_read,
     230             :         .write          = sysfs_kf_write,
     231             :         .prealloc       = true,
     232             : };
     233             : 
     234             : static const struct kernfs_ops sysfs_bin_kfops_ro = {
     235             :         .read           = sysfs_kf_bin_read,
     236             : };
     237             : 
     238             : static const struct kernfs_ops sysfs_bin_kfops_wo = {
     239             :         .write          = sysfs_kf_bin_write,
     240             : };
     241             : 
     242             : static const struct kernfs_ops sysfs_bin_kfops_rw = {
     243             :         .read           = sysfs_kf_bin_read,
     244             :         .write          = sysfs_kf_bin_write,
     245             : };
     246             : 
     247             : static const struct kernfs_ops sysfs_bin_kfops_mmap = {
     248             :         .read           = sysfs_kf_bin_read,
     249             :         .write          = sysfs_kf_bin_write,
     250             :         .mmap           = sysfs_kf_bin_mmap,
     251             :         .open           = sysfs_kf_bin_open,
     252             : };
     253             : 
     254        5458 : int sysfs_add_file_mode_ns(struct kernfs_node *parent,
     255             :                 const struct attribute *attr, umode_t mode, kuid_t uid,
     256             :                 kgid_t gid, const void *ns)
     257             : {
     258        5458 :         struct kobject *kobj = parent->priv;
     259        5458 :         const struct sysfs_ops *sysfs_ops = kobj->ktype->sysfs_ops;
     260        5458 :         struct lock_class_key *key = NULL;
     261        5458 :         const struct kernfs_ops *ops = NULL;
     262             :         struct kernfs_node *kn;
     263             : 
     264             :         /* every kobject with an attribute needs a ktype assigned */
     265        5458 :         if (WARN(!sysfs_ops, KERN_ERR
     266             :                         "missing sysfs attribute operations for kobject: %s\n",
     267             :                         kobject_name(kobj)))
     268             :                 return -EINVAL;
     269             : 
     270        5458 :         if (mode & SYSFS_PREALLOC) {
     271           0 :                 if (sysfs_ops->show && sysfs_ops->store)
     272             :                         ops = &sysfs_prealloc_kfops_rw;
     273           0 :                 else if (sysfs_ops->show)
     274             :                         ops = &sysfs_prealloc_kfops_ro;
     275           0 :                 else if (sysfs_ops->store)
     276           0 :                         ops = &sysfs_prealloc_kfops_wo;
     277             :         } else {
     278        5458 :                 if (sysfs_ops->show && sysfs_ops->store)
     279             :                         ops = &sysfs_file_kfops_rw;
     280           0 :                 else if (sysfs_ops->show)
     281             :                         ops = &sysfs_file_kfops_ro;
     282           0 :                 else if (sysfs_ops->store)
     283           0 :                         ops = &sysfs_file_kfops_wo;
     284             :         }
     285             : 
     286        5458 :         if (!ops)
     287           0 :                 ops = &sysfs_file_kfops_empty;
     288             : 
     289             : #ifdef CONFIG_DEBUG_LOCK_ALLOC
     290             :         if (!attr->ignore_lockdep)
     291             :                 key = attr->key ?: (struct lock_class_key *)&attr->skey;
     292             : #endif
     293             : 
     294        5458 :         kn = __kernfs_create_file(parent, attr->name, mode & 0777, uid, gid,
     295             :                                   PAGE_SIZE, ops, (void *)attr, ns, key);
     296        5458 :         if (IS_ERR(kn)) {
     297           0 :                 if (PTR_ERR(kn) == -EEXIST)
     298           0 :                         sysfs_warn_dup(parent, attr->name);
     299           0 :                 return PTR_ERR(kn);
     300             :         }
     301             :         return 0;
     302             : }
     303             : 
     304           9 : int sysfs_add_bin_file_mode_ns(struct kernfs_node *parent,
     305             :                 const struct bin_attribute *battr, umode_t mode,
     306             :                 kuid_t uid, kgid_t gid, const void *ns)
     307             : {
     308           9 :         const struct attribute *attr = &battr->attr;
     309           9 :         struct lock_class_key *key = NULL;
     310             :         const struct kernfs_ops *ops;
     311             :         struct kernfs_node *kn;
     312             : 
     313           9 :         if (battr->mmap)
     314             :                 ops = &sysfs_bin_kfops_mmap;
     315           9 :         else if (battr->read && battr->write)
     316             :                 ops = &sysfs_bin_kfops_rw;
     317           9 :         else if (battr->read)
     318             :                 ops = &sysfs_bin_kfops_ro;
     319           0 :         else if (battr->write)
     320             :                 ops = &sysfs_bin_kfops_wo;
     321             :         else
     322           0 :                 ops = &sysfs_file_kfops_empty;
     323             : 
     324             : #ifdef CONFIG_DEBUG_LOCK_ALLOC
     325             :         if (!attr->ignore_lockdep)
     326             :                 key = attr->key ?: (struct lock_class_key *)&attr->skey;
     327             : #endif
     328             : 
     329           9 :         kn = __kernfs_create_file(parent, attr->name, mode & 0777, uid, gid,
     330           9 :                                   battr->size, ops, (void *)attr, ns, key);
     331           9 :         if (IS_ERR(kn)) {
     332           0 :                 if (PTR_ERR(kn) == -EEXIST)
     333           0 :                         sysfs_warn_dup(parent, attr->name);
     334           0 :                 return PTR_ERR(kn);
     335             :         }
     336             :         return 0;
     337             : }
     338             : 
     339             : /**
     340             :  * sysfs_create_file_ns - create an attribute file for an object with custom ns
     341             :  * @kobj: object we're creating for
     342             :  * @attr: attribute descriptor
     343             :  * @ns: namespace the new file should belong to
     344             :  */
     345        1170 : int sysfs_create_file_ns(struct kobject *kobj, const struct attribute *attr,
     346             :                          const void *ns)
     347             : {
     348             :         kuid_t uid;
     349             :         kgid_t gid;
     350             : 
     351        1170 :         if (WARN_ON(!kobj || !kobj->sd || !attr))
     352             :                 return -EINVAL;
     353             : 
     354        1170 :         kobject_get_ownership(kobj, &uid, &gid);
     355        1170 :         return sysfs_add_file_mode_ns(kobj->sd, attr, attr->mode, uid, gid, ns);
     356             : }
     357             : EXPORT_SYMBOL_GPL(sysfs_create_file_ns);
     358             : 
     359           0 : int sysfs_create_files(struct kobject *kobj, const struct attribute * const *ptr)
     360             : {
     361           0 :         int err = 0;
     362             :         int i;
     363             : 
     364           0 :         for (i = 0; ptr[i] && !err; i++)
     365           0 :                 err = sysfs_create_file(kobj, ptr[i]);
     366           0 :         if (err)
     367           0 :                 while (--i >= 0)
     368           0 :                         sysfs_remove_file(kobj, ptr[i]);
     369           0 :         return err;
     370             : }
     371             : EXPORT_SYMBOL_GPL(sysfs_create_files);
     372             : 
     373             : /**
     374             :  * sysfs_add_file_to_group - add an attribute file to a pre-existing group.
     375             :  * @kobj: object we're acting for.
     376             :  * @attr: attribute descriptor.
     377             :  * @group: group name.
     378             :  */
     379           2 : int sysfs_add_file_to_group(struct kobject *kobj,
     380             :                 const struct attribute *attr, const char *group)
     381             : {
     382             :         struct kernfs_node *parent;
     383             :         kuid_t uid;
     384             :         kgid_t gid;
     385             :         int error;
     386             : 
     387           2 :         if (group) {
     388           0 :                 parent = kernfs_find_and_get(kobj->sd, group);
     389             :         } else {
     390           2 :                 parent = kobj->sd;
     391           2 :                 kernfs_get(parent);
     392             :         }
     393             : 
     394           2 :         if (!parent)
     395             :                 return -ENOENT;
     396             : 
     397           2 :         kobject_get_ownership(kobj, &uid, &gid);
     398           2 :         error = sysfs_add_file_mode_ns(parent, attr, attr->mode, uid, gid,
     399             :                                        NULL);
     400           2 :         kernfs_put(parent);
     401             : 
     402           2 :         return error;
     403             : }
     404             : EXPORT_SYMBOL_GPL(sysfs_add_file_to_group);
     405             : 
     406             : /**
     407             :  * sysfs_chmod_file - update the modified mode value on an object attribute.
     408             :  * @kobj: object we're acting for.
     409             :  * @attr: attribute descriptor.
     410             :  * @mode: file permissions.
     411             :  *
     412             :  */
     413           0 : int sysfs_chmod_file(struct kobject *kobj, const struct attribute *attr,
     414             :                      umode_t mode)
     415             : {
     416             :         struct kernfs_node *kn;
     417             :         struct iattr newattrs;
     418             :         int rc;
     419             : 
     420           0 :         kn = kernfs_find_and_get(kobj->sd, attr->name);
     421           0 :         if (!kn)
     422             :                 return -ENOENT;
     423             : 
     424           0 :         newattrs.ia_mode = (mode & S_IALLUGO) | (kn->mode & ~S_IALLUGO);
     425           0 :         newattrs.ia_valid = ATTR_MODE;
     426             : 
     427           0 :         rc = kernfs_setattr(kn, &newattrs);
     428             : 
     429           0 :         kernfs_put(kn);
     430           0 :         return rc;
     431             : }
     432             : EXPORT_SYMBOL_GPL(sysfs_chmod_file);
     433             : 
     434             : /**
     435             :  * sysfs_break_active_protection - break "active" protection
     436             :  * @kobj: The kernel object @attr is associated with.
     437             :  * @attr: The attribute to break the "active" protection for.
     438             :  *
     439             :  * With sysfs, just like kernfs, deletion of an attribute is postponed until
     440             :  * all active .show() and .store() callbacks have finished unless this function
     441             :  * is called. Hence this function is useful in methods that implement self
     442             :  * deletion.
     443             :  */
     444           0 : struct kernfs_node *sysfs_break_active_protection(struct kobject *kobj,
     445             :                                                   const struct attribute *attr)
     446             : {
     447             :         struct kernfs_node *kn;
     448             : 
     449           0 :         kobject_get(kobj);
     450           0 :         kn = kernfs_find_and_get(kobj->sd, attr->name);
     451           0 :         if (kn)
     452           0 :                 kernfs_break_active_protection(kn);
     453           0 :         return kn;
     454             : }
     455             : EXPORT_SYMBOL_GPL(sysfs_break_active_protection);
     456             : 
     457             : /**
     458             :  * sysfs_unbreak_active_protection - restore "active" protection
     459             :  * @kn: Pointer returned by sysfs_break_active_protection().
     460             :  *
     461             :  * Undo the effects of sysfs_break_active_protection(). Since this function
     462             :  * calls kernfs_put() on the kernfs node that corresponds to the 'attr'
     463             :  * argument passed to sysfs_break_active_protection() that attribute may have
     464             :  * been removed between the sysfs_break_active_protection() and
     465             :  * sysfs_unbreak_active_protection() calls, it is not safe to access @kn after
     466             :  * this function has returned.
     467             :  */
     468           0 : void sysfs_unbreak_active_protection(struct kernfs_node *kn)
     469             : {
     470           0 :         struct kobject *kobj = kn->parent->priv;
     471             : 
     472           0 :         kernfs_unbreak_active_protection(kn);
     473           0 :         kernfs_put(kn);
     474           0 :         kobject_put(kobj);
     475           0 : }
     476             : EXPORT_SYMBOL_GPL(sysfs_unbreak_active_protection);
     477             : 
     478             : /**
     479             :  * sysfs_remove_file_ns - remove an object attribute with a custom ns tag
     480             :  * @kobj: object we're acting for
     481             :  * @attr: attribute descriptor
     482             :  * @ns: namespace tag of the file to remove
     483             :  *
     484             :  * Hash the attribute name and namespace tag and kill the victim.
     485             :  */
     486          48 : void sysfs_remove_file_ns(struct kobject *kobj, const struct attribute *attr,
     487             :                           const void *ns)
     488             : {
     489          48 :         struct kernfs_node *parent = kobj->sd;
     490             : 
     491          48 :         kernfs_remove_by_name_ns(parent, attr->name, ns);
     492          48 : }
     493             : EXPORT_SYMBOL_GPL(sysfs_remove_file_ns);
     494             : 
     495             : /**
     496             :  * sysfs_remove_file_self - remove an object attribute from its own method
     497             :  * @kobj: object we're acting for
     498             :  * @attr: attribute descriptor
     499             :  *
     500             :  * See kernfs_remove_self() for details.
     501             :  */
     502           0 : bool sysfs_remove_file_self(struct kobject *kobj, const struct attribute *attr)
     503             : {
     504           0 :         struct kernfs_node *parent = kobj->sd;
     505             :         struct kernfs_node *kn;
     506             :         bool ret;
     507             : 
     508           0 :         kn = kernfs_find_and_get(parent, attr->name);
     509           0 :         if (WARN_ON_ONCE(!kn))
     510             :                 return false;
     511             : 
     512           0 :         ret = kernfs_remove_self(kn);
     513             : 
     514           0 :         kernfs_put(kn);
     515           0 :         return ret;
     516             : }
     517             : EXPORT_SYMBOL_GPL(sysfs_remove_file_self);
     518             : 
     519           0 : void sysfs_remove_files(struct kobject *kobj, const struct attribute * const *ptr)
     520             : {
     521             :         int i;
     522             : 
     523           0 :         for (i = 0; ptr[i]; i++)
     524           0 :                 sysfs_remove_file(kobj, ptr[i]);
     525           0 : }
     526             : EXPORT_SYMBOL_GPL(sysfs_remove_files);
     527             : 
     528             : /**
     529             :  * sysfs_remove_file_from_group - remove an attribute file from a group.
     530             :  * @kobj: object we're acting for.
     531             :  * @attr: attribute descriptor.
     532             :  * @group: group name.
     533             :  */
     534           0 : void sysfs_remove_file_from_group(struct kobject *kobj,
     535             :                 const struct attribute *attr, const char *group)
     536             : {
     537             :         struct kernfs_node *parent;
     538             : 
     539           0 :         if (group) {
     540           0 :                 parent = kernfs_find_and_get(kobj->sd, group);
     541             :         } else {
     542           0 :                 parent = kobj->sd;
     543           0 :                 kernfs_get(parent);
     544             :         }
     545             : 
     546           0 :         if (parent) {
     547           0 :                 kernfs_remove_by_name(parent, attr->name);
     548           0 :                 kernfs_put(parent);
     549             :         }
     550           0 : }
     551             : EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group);
     552             : 
     553             : /**
     554             :  *      sysfs_create_bin_file - create binary file for object.
     555             :  *      @kobj:  object.
     556             :  *      @attr:  attribute descriptor.
     557             :  */
     558           1 : int sysfs_create_bin_file(struct kobject *kobj,
     559             :                           const struct bin_attribute *attr)
     560             : {
     561             :         kuid_t uid;
     562             :         kgid_t gid;
     563             : 
     564           1 :         if (WARN_ON(!kobj || !kobj->sd || !attr))
     565             :                 return -EINVAL;
     566             : 
     567           1 :         kobject_get_ownership(kobj, &uid, &gid);
     568           1 :         return sysfs_add_bin_file_mode_ns(kobj->sd, attr, attr->attr.mode, uid,
     569             :                                            gid, NULL);
     570             : }
     571             : EXPORT_SYMBOL_GPL(sysfs_create_bin_file);
     572             : 
     573             : /**
     574             :  *      sysfs_remove_bin_file - remove binary file for object.
     575             :  *      @kobj:  object.
     576             :  *      @attr:  attribute descriptor.
     577             :  */
     578           0 : void sysfs_remove_bin_file(struct kobject *kobj,
     579             :                            const struct bin_attribute *attr)
     580             : {
     581           0 :         kernfs_remove_by_name(kobj->sd, attr->attr.name);
     582           0 : }
     583             : EXPORT_SYMBOL_GPL(sysfs_remove_bin_file);
     584             : 
     585           0 : static int internal_change_owner(struct kernfs_node *kn, kuid_t kuid,
     586             :                                  kgid_t kgid)
     587             : {
     588           0 :         struct iattr newattrs = {
     589             :                 .ia_valid = ATTR_UID | ATTR_GID,
     590             :                 .ia_uid = kuid,
     591             :                 .ia_gid = kgid,
     592             :         };
     593           0 :         return kernfs_setattr(kn, &newattrs);
     594             : }
     595             : 
     596             : /**
     597             :  *      sysfs_link_change_owner - change owner of a sysfs file.
     598             :  *      @kobj:  object of the kernfs_node the symlink is located in.
     599             :  *      @targ:  object of the kernfs_node the symlink points to.
     600             :  *      @name:  name of the link.
     601             :  *      @kuid:  new owner's kuid
     602             :  *      @kgid:  new owner's kgid
     603             :  *
     604             :  * This function looks up the sysfs symlink entry @name under @kobj and changes
     605             :  * the ownership to @kuid/@kgid. The symlink is looked up in the namespace of
     606             :  * @targ.
     607             :  *
     608             :  * Returns 0 on success or error code on failure.
     609             :  */
     610           0 : int sysfs_link_change_owner(struct kobject *kobj, struct kobject *targ,
     611             :                             const char *name, kuid_t kuid, kgid_t kgid)
     612             : {
     613           0 :         struct kernfs_node *kn = NULL;
     614             :         int error;
     615             : 
     616           0 :         if (!name || !kobj->state_in_sysfs || !targ->state_in_sysfs)
     617             :                 return -EINVAL;
     618             : 
     619           0 :         error = -ENOENT;
     620           0 :         kn = kernfs_find_and_get_ns(kobj->sd, name, targ->sd->ns);
     621           0 :         if (!kn)
     622             :                 goto out;
     623             : 
     624           0 :         error = -EINVAL;
     625           0 :         if (kernfs_type(kn) != KERNFS_LINK)
     626             :                 goto out;
     627           0 :         if (kn->symlink.target_kn->priv != targ)
     628             :                 goto out;
     629             : 
     630           0 :         error = internal_change_owner(kn, kuid, kgid);
     631             : 
     632             : out:
     633           0 :         kernfs_put(kn);
     634           0 :         return error;
     635             : }
     636             : 
     637             : /**
     638             :  *      sysfs_file_change_owner - change owner of a sysfs file.
     639             :  *      @kobj:  object.
     640             :  *      @name:  name of the file to change.
     641             :  *      @kuid:  new owner's kuid
     642             :  *      @kgid:  new owner's kgid
     643             :  *
     644             :  * This function looks up the sysfs entry @name under @kobj and changes the
     645             :  * ownership to @kuid/@kgid.
     646             :  *
     647             :  * Returns 0 on success or error code on failure.
     648             :  */
     649           0 : int sysfs_file_change_owner(struct kobject *kobj, const char *name, kuid_t kuid,
     650             :                             kgid_t kgid)
     651             : {
     652             :         struct kernfs_node *kn;
     653             :         int error;
     654             : 
     655           0 :         if (!name)
     656             :                 return -EINVAL;
     657             : 
     658           0 :         if (!kobj->state_in_sysfs)
     659             :                 return -EINVAL;
     660             : 
     661           0 :         kn = kernfs_find_and_get(kobj->sd, name);
     662           0 :         if (!kn)
     663             :                 return -ENOENT;
     664             : 
     665           0 :         error = internal_change_owner(kn, kuid, kgid);
     666             : 
     667           0 :         kernfs_put(kn);
     668             : 
     669           0 :         return error;
     670             : }
     671             : EXPORT_SYMBOL_GPL(sysfs_file_change_owner);
     672             : 
     673             : /**
     674             :  *      sysfs_change_owner - change owner of the given object.
     675             :  *      @kobj:  object.
     676             :  *      @kuid:  new owner's kuid
     677             :  *      @kgid:  new owner's kgid
     678             :  *
     679             :  * Change the owner of the default directory, files, groups, and attributes of
     680             :  * @kobj to @kuid/@kgid. Note that sysfs_change_owner mirrors how the sysfs
     681             :  * entries for a kobject are added by driver core. In summary,
     682             :  * sysfs_change_owner() takes care of the default directory entry for @kobj,
     683             :  * the default attributes associated with the ktype of @kobj and the default
     684             :  * attributes associated with the ktype of @kobj.
     685             :  * Additional properties not added by driver core have to be changed by the
     686             :  * driver or subsystem which created them. This is similar to how
     687             :  * driver/subsystem specific entries are removed.
     688             :  *
     689             :  * Returns 0 on success or error code on failure.
     690             :  */
     691           0 : int sysfs_change_owner(struct kobject *kobj, kuid_t kuid, kgid_t kgid)
     692             : {
     693             :         int error;
     694             :         const struct kobj_type *ktype;
     695             : 
     696           0 :         if (!kobj->state_in_sysfs)
     697             :                 return -EINVAL;
     698             : 
     699             :         /* Change the owner of the kobject itself. */
     700           0 :         error = internal_change_owner(kobj->sd, kuid, kgid);
     701           0 :         if (error)
     702             :                 return error;
     703             : 
     704           0 :         ktype = get_ktype(kobj);
     705           0 :         if (ktype) {
     706             :                 /*
     707             :                  * Change owner of the default groups associated with the
     708             :                  * ktype of @kobj.
     709             :                  */
     710           0 :                 error = sysfs_groups_change_owner(kobj, ktype->default_groups,
     711             :                                                   kuid, kgid);
     712           0 :                 if (error)
     713             :                         return error;
     714             :         }
     715             : 
     716             :         return 0;
     717             : }
     718             : EXPORT_SYMBOL_GPL(sysfs_change_owner);
     719             : 
     720             : /**
     721             :  *      sysfs_emit - scnprintf equivalent, aware of PAGE_SIZE buffer.
     722             :  *      @buf:   start of PAGE_SIZE buffer.
     723             :  *      @fmt:   format
     724             :  *      @...:   optional arguments to @format
     725             :  *
     726             :  *
     727             :  * Returns number of characters written to @buf.
     728             :  */
     729           0 : int sysfs_emit(char *buf, const char *fmt, ...)
     730             : {
     731             :         va_list args;
     732             :         int len;
     733             : 
     734           0 :         if (WARN(!buf || offset_in_page(buf),
     735             :                  "invalid sysfs_emit: buf:%p\n", buf))
     736             :                 return 0;
     737             : 
     738           0 :         va_start(args, fmt);
     739           0 :         len = vscnprintf(buf, PAGE_SIZE, fmt, args);
     740           0 :         va_end(args);
     741             : 
     742           0 :         return len;
     743             : }
     744             : EXPORT_SYMBOL_GPL(sysfs_emit);
     745             : 
     746             : /**
     747             :  *      sysfs_emit_at - scnprintf equivalent, aware of PAGE_SIZE buffer.
     748             :  *      @buf:   start of PAGE_SIZE buffer.
     749             :  *      @at:    offset in @buf to start write in bytes
     750             :  *              @at must be >= 0 && < PAGE_SIZE
     751             :  *      @fmt:   format
     752             :  *      @...:   optional arguments to @fmt
     753             :  *
     754             :  *
     755             :  * Returns number of characters written starting at &@buf[@at].
     756             :  */
     757           0 : int sysfs_emit_at(char *buf, int at, const char *fmt, ...)
     758             : {
     759             :         va_list args;
     760             :         int len;
     761             : 
     762           0 :         if (WARN(!buf || offset_in_page(buf) || at < 0 || at >= PAGE_SIZE,
     763             :                  "invalid sysfs_emit_at: buf:%p at:%d\n", buf, at))
     764             :                 return 0;
     765             : 
     766           0 :         va_start(args, fmt);
     767           0 :         len = vscnprintf(buf + at, PAGE_SIZE - at, fmt, args);
     768           0 :         va_end(args);
     769             : 
     770           0 :         return len;
     771             : }
     772             : EXPORT_SYMBOL_GPL(sysfs_emit_at);

Generated by: LCOV version 1.14