linux/fs/sysfs/file.c
<<
>>
Prefs
   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.txt 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
  19#include "sysfs.h"
  20#include "../kernfs/kernfs-internal.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 */
  26static const struct sysfs_ops *sysfs_file_ops(struct kernfs_node *kn)
  27{
  28        struct kobject *kobj = kn->parent->priv;
  29
  30        if (kn->flags & KERNFS_LOCKDEP)
  31                lockdep_assert_held(kn);
  32        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 */
  40static int sysfs_kf_seq_show(struct seq_file *sf, void *v)
  41{
  42        struct kernfs_open_file *of = sf->private;
  43        struct kobject *kobj = of->kn->parent->priv;
  44        const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
  45        ssize_t count;
  46        char *buf;
  47
  48        /* acquire buffer and ensure that it's >= PAGE_SIZE and clear */
  49        count = seq_get_buf(sf, &buf);
  50        if (count < PAGE_SIZE) {
  51                seq_commit(sf, -1);
  52                return 0;
  53        }
  54        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        if (ops->show) {
  61                count = ops->show(kobj, of->kn->priv, buf);
  62                if (count < 0)
  63                        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        if (count >= (ssize_t)PAGE_SIZE) {
  71                printk("fill_read_buffer: %pS returned bad count\n",
  72                                ops->show);
  73                /* Try to struggle along */
  74                count = PAGE_SIZE - 1;
  75        }
  76        seq_commit(sf, count);
  77        return 0;
  78}
  79
  80static ssize_t sysfs_kf_bin_read(struct kernfs_open_file *of, char *buf,
  81                                 size_t count, loff_t pos)
  82{
  83        struct bin_attribute *battr = of->kn->priv;
  84        struct kobject *kobj = of->kn->parent->priv;
  85        loff_t size = file_inode(of->file)->i_size;
  86
  87        if (!count)
  88                return 0;
  89
  90        if (size) {
  91                if (pos >= size)
  92                        return 0;
  93                if (pos + count > size)
  94                        count = size - pos;
  95        }
  96
  97        if (!battr->read)
  98                return -EIO;
  99
 100        return battr->read(of->file, kobj, battr, buf, pos, count);
 101}
 102
 103/* kernfs read callback for regular sysfs files with pre-alloc */
 104static ssize_t sysfs_kf_read(struct kernfs_open_file *of, char *buf,
 105                             size_t count, loff_t pos)
 106{
 107        const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
 108        struct kobject *kobj = of->kn->parent->priv;
 109        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        if (WARN_ON_ONCE(buf != of->prealloc_buf))
 116                return 0;
 117        len = ops->show(kobj, of->kn->priv, buf);
 118        if (len < 0)
 119                return len;
 120        if (pos) {
 121                if (len <= pos)
 122                        return 0;
 123                len -= pos;
 124                memmove(buf, buf + pos, len);
 125        }
 126        return min_t(ssize_t, count, len);
 127}
 128
 129/* kernfs write callback for regular sysfs files */
 130static ssize_t sysfs_kf_write(struct kernfs_open_file *of, char *buf,
 131                              size_t count, loff_t pos)
 132{
 133        const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
 134        struct kobject *kobj = of->kn->parent->priv;
 135
 136        if (!count)
 137                return 0;
 138
 139        return ops->store(kobj, of->kn->priv, buf, count);
 140}
 141
 142/* kernfs write callback for bin sysfs files */
 143static ssize_t sysfs_kf_bin_write(struct kernfs_open_file *of, char *buf,
 144                                  size_t count, loff_t pos)
 145{
 146        struct bin_attribute *battr = of->kn->priv;
 147        struct kobject *kobj = of->kn->parent->priv;
 148        loff_t size = file_inode(of->file)->i_size;
 149
 150        if (size) {
 151                if (size <= pos)
 152                        return -EFBIG;
 153                count = min_t(ssize_t, count, size - pos);
 154        }
 155        if (!count)
 156                return 0;
 157
 158        if (!battr->write)
 159                return -EIO;
 160
 161        return battr->write(of->file, kobj, battr, buf, pos, count);
 162}
 163
 164static int sysfs_kf_bin_mmap(struct kernfs_open_file *of,
 165                             struct vm_area_struct *vma)
 166{
 167        struct bin_attribute *battr = of->kn->priv;
 168        struct kobject *kobj = of->kn->parent->priv;
 169
 170        return battr->mmap(of->file, kobj, battr, vma);
 171}
 172
 173void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr)
 174{
 175        struct kernfs_node *kn = kobj->sd, *tmp;
 176
 177        if (kn && dir)
 178                kn = kernfs_find_and_get(kn, dir);
 179        else
 180                kernfs_get(kn);
 181
 182        if (kn && attr) {
 183                tmp = kernfs_find_and_get(kn, attr);
 184                kernfs_put(kn);
 185                kn = tmp;
 186        }
 187
 188        if (kn) {
 189                kernfs_notify(kn);
 190                kernfs_put(kn);
 191        }
 192}
 193EXPORT_SYMBOL_GPL(sysfs_notify);
 194
 195static const struct kernfs_ops sysfs_file_kfops_empty = {
 196};
 197
 198static const struct kernfs_ops sysfs_file_kfops_ro = {
 199        .seq_show       = sysfs_kf_seq_show,
 200};
 201
 202static const struct kernfs_ops sysfs_file_kfops_wo = {
 203        .write          = sysfs_kf_write,
 204};
 205
 206static const struct kernfs_ops sysfs_file_kfops_rw = {
 207        .seq_show       = sysfs_kf_seq_show,
 208        .write          = sysfs_kf_write,
 209};
 210
 211static const struct kernfs_ops sysfs_prealloc_kfops_ro = {
 212        .read           = sysfs_kf_read,
 213        .prealloc       = true,
 214};
 215
 216static const struct kernfs_ops sysfs_prealloc_kfops_wo = {
 217        .write          = sysfs_kf_write,
 218        .prealloc       = true,
 219};
 220
 221static const struct kernfs_ops sysfs_prealloc_kfops_rw = {
 222        .read           = sysfs_kf_read,
 223        .write          = sysfs_kf_write,
 224        .prealloc       = true,
 225};
 226
 227static const struct kernfs_ops sysfs_bin_kfops_ro = {
 228        .read           = sysfs_kf_bin_read,
 229};
 230
 231static const struct kernfs_ops sysfs_bin_kfops_wo = {
 232        .write          = sysfs_kf_bin_write,
 233};
 234
 235static const struct kernfs_ops sysfs_bin_kfops_rw = {
 236        .read           = sysfs_kf_bin_read,
 237        .write          = sysfs_kf_bin_write,
 238};
 239
 240static const struct kernfs_ops sysfs_bin_kfops_mmap = {
 241        .read           = sysfs_kf_bin_read,
 242        .write          = sysfs_kf_bin_write,
 243        .mmap           = sysfs_kf_bin_mmap,
 244};
 245
 246int sysfs_add_file_mode_ns(struct kernfs_node *parent,
 247                           const struct attribute *attr, bool is_bin,
 248                           umode_t mode, kuid_t uid, kgid_t gid, const void *ns)
 249{
 250        struct lock_class_key *key = NULL;
 251        const struct kernfs_ops *ops;
 252        struct kernfs_node *kn;
 253        loff_t size;
 254
 255        if (!is_bin) {
 256                struct kobject *kobj = parent->priv;
 257                const struct sysfs_ops *sysfs_ops = kobj->ktype->sysfs_ops;
 258
 259                /* every kobject with an attribute needs a ktype assigned */
 260                if (WARN(!sysfs_ops, KERN_ERR
 261                         "missing sysfs attribute operations for kobject: %s\n",
 262                         kobject_name(kobj)))
 263                        return -EINVAL;
 264
 265                if (sysfs_ops->show && sysfs_ops->store) {
 266                        if (mode & SYSFS_PREALLOC)
 267                                ops = &sysfs_prealloc_kfops_rw;
 268                        else
 269                                ops = &sysfs_file_kfops_rw;
 270                } else if (sysfs_ops->show) {
 271                        if (mode & SYSFS_PREALLOC)
 272                                ops = &sysfs_prealloc_kfops_ro;
 273                        else
 274                                ops = &sysfs_file_kfops_ro;
 275                } else if (sysfs_ops->store) {
 276                        if (mode & SYSFS_PREALLOC)
 277                                ops = &sysfs_prealloc_kfops_wo;
 278                        else
 279                                ops = &sysfs_file_kfops_wo;
 280                } else
 281                        ops = &sysfs_file_kfops_empty;
 282
 283                size = PAGE_SIZE;
 284        } else {
 285                struct bin_attribute *battr = (void *)attr;
 286
 287                if (battr->mmap)
 288                        ops = &sysfs_bin_kfops_mmap;
 289                else if (battr->read && battr->write)
 290                        ops = &sysfs_bin_kfops_rw;
 291                else if (battr->read)
 292                        ops = &sysfs_bin_kfops_ro;
 293                else if (battr->write)
 294                        ops = &sysfs_bin_kfops_wo;
 295                else
 296                        ops = &sysfs_file_kfops_empty;
 297
 298                size = battr->size;
 299        }
 300
 301#ifdef CONFIG_DEBUG_LOCK_ALLOC
 302        if (!attr->ignore_lockdep)
 303                key = attr->key ?: (struct lock_class_key *)&attr->skey;
 304#endif
 305
 306        kn = __kernfs_create_file(parent, attr->name, mode & 0777, uid, gid,
 307                                  size, ops, (void *)attr, ns, key);
 308        if (IS_ERR(kn)) {
 309                if (PTR_ERR(kn) == -EEXIST)
 310                        sysfs_warn_dup(parent, attr->name);
 311                return PTR_ERR(kn);
 312        }
 313        return 0;
 314}
 315
 316/**
 317 * sysfs_create_file_ns - create an attribute file for an object with custom ns
 318 * @kobj: object we're creating for
 319 * @attr: attribute descriptor
 320 * @ns: namespace the new file should belong to
 321 */
 322int sysfs_create_file_ns(struct kobject *kobj, const struct attribute *attr,
 323                         const void *ns)
 324{
 325        kuid_t uid;
 326        kgid_t gid;
 327
 328        BUG_ON(!kobj || !kobj->sd || !attr);
 329
 330        kobject_get_ownership(kobj, &uid, &gid);
 331        return sysfs_add_file_mode_ns(kobj->sd, attr, false, attr->mode,
 332                                      uid, gid, ns);
 333
 334}
 335EXPORT_SYMBOL_GPL(sysfs_create_file_ns);
 336
 337int sysfs_create_files(struct kobject *kobj, const struct attribute **ptr)
 338{
 339        int err = 0;
 340        int i;
 341
 342        for (i = 0; ptr[i] && !err; i++)
 343                err = sysfs_create_file(kobj, ptr[i]);
 344        if (err)
 345                while (--i >= 0)
 346                        sysfs_remove_file(kobj, ptr[i]);
 347        return err;
 348}
 349EXPORT_SYMBOL_GPL(sysfs_create_files);
 350
 351/**
 352 * sysfs_add_file_to_group - add an attribute file to a pre-existing group.
 353 * @kobj: object we're acting for.
 354 * @attr: attribute descriptor.
 355 * @group: group name.
 356 */
 357int sysfs_add_file_to_group(struct kobject *kobj,
 358                const struct attribute *attr, const char *group)
 359{
 360        struct kernfs_node *parent;
 361        kuid_t uid;
 362        kgid_t gid;
 363        int error;
 364
 365        if (group) {
 366                parent = kernfs_find_and_get(kobj->sd, group);
 367        } else {
 368                parent = kobj->sd;
 369                kernfs_get(parent);
 370        }
 371
 372        if (!parent)
 373                return -ENOENT;
 374
 375        kobject_get_ownership(kobj, &uid, &gid);
 376        error = sysfs_add_file_mode_ns(parent, attr, false,
 377                                       attr->mode, uid, gid, NULL);
 378        kernfs_put(parent);
 379
 380        return error;
 381}
 382EXPORT_SYMBOL_GPL(sysfs_add_file_to_group);
 383
 384/**
 385 * sysfs_chmod_file - update the modified mode value on an object attribute.
 386 * @kobj: object we're acting for.
 387 * @attr: attribute descriptor.
 388 * @mode: file permissions.
 389 *
 390 */
 391int sysfs_chmod_file(struct kobject *kobj, const struct attribute *attr,
 392                     umode_t mode)
 393{
 394        struct kernfs_node *kn;
 395        struct iattr newattrs;
 396        int rc;
 397
 398        kn = kernfs_find_and_get(kobj->sd, attr->name);
 399        if (!kn)
 400                return -ENOENT;
 401
 402        newattrs.ia_mode = (mode & S_IALLUGO) | (kn->mode & ~S_IALLUGO);
 403        newattrs.ia_valid = ATTR_MODE;
 404
 405        rc = kernfs_setattr(kn, &newattrs);
 406
 407        kernfs_put(kn);
 408        return rc;
 409}
 410EXPORT_SYMBOL_GPL(sysfs_chmod_file);
 411
 412/**
 413 * sysfs_break_active_protection - break "active" protection
 414 * @kobj: The kernel object @attr is associated with.
 415 * @attr: The attribute to break the "active" protection for.
 416 *
 417 * With sysfs, just like kernfs, deletion of an attribute is postponed until
 418 * all active .show() and .store() callbacks have finished unless this function
 419 * is called. Hence this function is useful in methods that implement self
 420 * deletion.
 421 */
 422struct kernfs_node *sysfs_break_active_protection(struct kobject *kobj,
 423                                                  const struct attribute *attr)
 424{
 425        struct kernfs_node *kn;
 426
 427        kobject_get(kobj);
 428        kn = kernfs_find_and_get(kobj->sd, attr->name);
 429        if (kn)
 430                kernfs_break_active_protection(kn);
 431        return kn;
 432}
 433EXPORT_SYMBOL_GPL(sysfs_break_active_protection);
 434
 435/**
 436 * sysfs_unbreak_active_protection - restore "active" protection
 437 * @kn: Pointer returned by sysfs_break_active_protection().
 438 *
 439 * Undo the effects of sysfs_break_active_protection(). Since this function
 440 * calls kernfs_put() on the kernfs node that corresponds to the 'attr'
 441 * argument passed to sysfs_break_active_protection() that attribute may have
 442 * been removed between the sysfs_break_active_protection() and
 443 * sysfs_unbreak_active_protection() calls, it is not safe to access @kn after
 444 * this function has returned.
 445 */
 446void sysfs_unbreak_active_protection(struct kernfs_node *kn)
 447{
 448        struct kobject *kobj = kn->parent->priv;
 449
 450        kernfs_unbreak_active_protection(kn);
 451        kernfs_put(kn);
 452        kobject_put(kobj);
 453}
 454EXPORT_SYMBOL_GPL(sysfs_unbreak_active_protection);
 455
 456/**
 457 * sysfs_remove_file_ns - remove an object attribute with a custom ns tag
 458 * @kobj: object we're acting for
 459 * @attr: attribute descriptor
 460 * @ns: namespace tag of the file to remove
 461 *
 462 * Hash the attribute name and namespace tag and kill the victim.
 463 */
 464void sysfs_remove_file_ns(struct kobject *kobj, const struct attribute *attr,
 465                          const void *ns)
 466{
 467        struct kernfs_node *parent = kobj->sd;
 468
 469        kernfs_remove_by_name_ns(parent, attr->name, ns);
 470}
 471EXPORT_SYMBOL_GPL(sysfs_remove_file_ns);
 472
 473/**
 474 * sysfs_remove_file_self - remove an object attribute from its own method
 475 * @kobj: object we're acting for
 476 * @attr: attribute descriptor
 477 *
 478 * See kernfs_remove_self() for details.
 479 */
 480bool sysfs_remove_file_self(struct kobject *kobj, const struct attribute *attr)
 481{
 482        struct kernfs_node *parent = kobj->sd;
 483        struct kernfs_node *kn;
 484        bool ret;
 485
 486        kn = kernfs_find_and_get(parent, attr->name);
 487        if (WARN_ON_ONCE(!kn))
 488                return false;
 489
 490        ret = kernfs_remove_self(kn);
 491
 492        kernfs_put(kn);
 493        return ret;
 494}
 495
 496void sysfs_remove_files(struct kobject *kobj, const struct attribute **ptr)
 497{
 498        int i;
 499        for (i = 0; ptr[i]; i++)
 500                sysfs_remove_file(kobj, ptr[i]);
 501}
 502EXPORT_SYMBOL_GPL(sysfs_remove_files);
 503
 504/**
 505 * sysfs_remove_file_from_group - remove an attribute file from a group.
 506 * @kobj: object we're acting for.
 507 * @attr: attribute descriptor.
 508 * @group: group name.
 509 */
 510void sysfs_remove_file_from_group(struct kobject *kobj,
 511                const struct attribute *attr, const char *group)
 512{
 513        struct kernfs_node *parent;
 514
 515        if (group) {
 516                parent = kernfs_find_and_get(kobj->sd, group);
 517        } else {
 518                parent = kobj->sd;
 519                kernfs_get(parent);
 520        }
 521
 522        if (parent) {
 523                kernfs_remove_by_name(parent, attr->name);
 524                kernfs_put(parent);
 525        }
 526}
 527EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group);
 528
 529/**
 530 *      sysfs_create_bin_file - create binary file for object.
 531 *      @kobj:  object.
 532 *      @attr:  attribute descriptor.
 533 */
 534int sysfs_create_bin_file(struct kobject *kobj,
 535                          const struct bin_attribute *attr)
 536{
 537        kuid_t uid;
 538        kgid_t gid;
 539
 540        BUG_ON(!kobj || !kobj->sd || !attr);
 541
 542        kobject_get_ownership(kobj, &uid, &gid);
 543        return sysfs_add_file_mode_ns(kobj->sd, &attr->attr, true,
 544                                      attr->attr.mode, uid, gid, NULL);
 545}
 546EXPORT_SYMBOL_GPL(sysfs_create_bin_file);
 547
 548/**
 549 *      sysfs_remove_bin_file - remove binary file for object.
 550 *      @kobj:  object.
 551 *      @attr:  attribute descriptor.
 552 */
 553void sysfs_remove_bin_file(struct kobject *kobj,
 554                           const struct bin_attribute *attr)
 555{
 556        kernfs_remove_by_name(kobj->sd, attr->attr.name);
 557}
 558EXPORT_SYMBOL_GPL(sysfs_remove_bin_file);
 559