LCOV - code coverage report
Current view: top level - fs/sysfs - file.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 79 271 29.2 %
Date: 2021-04-22 12:43:58 Functions: 9 28 32.1 %

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

Generated by: LCOV version 1.14