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
  21/*
  22 * Determine ktype->sysfs_ops for the given kernfs_node.  This function
  23 * must be called while holding an active reference.
  24 */
  25static const struct sysfs_ops *sysfs_file_ops(struct kernfs_node *kn)
  26{
  27        struct kobject *kobj = kn->parent->priv;
  28
  29        if (kn->flags & KERNFS_LOCKDEP)
  30                lockdep_assert_held(kn);
  31        return kobj->ktype ? kobj->ktype->sysfs_ops : NULL;
  32}
  33
  34/*
  35 * Reads on sysfs are handled through seq_file, which takes care of hairy
  36 * details like buffering and seeking.  The following function pipes
  37 * sysfs_ops->show() result through seq_file.
  38 */
  39static int sysfs_kf_seq_show(struct seq_file *sf, void *v)
  40{
  41        struct kernfs_open_file *of = sf->private;
  42        struct kobject *kobj = of->kn->parent->priv;
  43        const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
  44        ssize_t count;
  45        char *buf;
  46
  47        /* acquire buffer and ensure that it's >= PAGE_SIZE and clear */
  48        count = seq_get_buf(sf, &buf);
  49        if (count < PAGE_SIZE) {
  50                seq_commit(sf, -1);
  51                return 0;
  52        }
  53        memset(buf, 0, PAGE_SIZE);
  54
  55        /*
  56         * Invoke show().  Control may reach here via seq file lseek even
  57         * if @ops->show() isn't implemented.
  58         */
  59        if (ops->show) {
  60                count = ops->show(kobj, of->kn->priv, buf);
  61                if (count < 0)
  62                        return count;
  63        }
  64
  65        /*
  66         * The code works fine with PAGE_SIZE return but it's likely to
  67         * indicate truncated result or overflow in normal use cases.
  68         */
  69        if (count >= (ssize_t)PAGE_SIZE) {
  70                printk("fill_read_buffer: %pS returned bad count\n",
  71                                ops->show);
  72                /* Try to struggle along */
  73                count = PAGE_SIZE - 1;
  74        }
  75        seq_commit(sf, count);
  76        return 0;
  77}
  78
  79static ssize_t sysfs_kf_bin_read(struct kernfs_open_file *of, char *buf,
  80                                 size_t count, loff_t pos)
  81{
  82        struct bin_attribute *battr = of->kn->priv;
  83        struct kobject *kobj = of->kn->parent->priv;
  84        loff_t size = file_inode(of->file)->i_size;
  85
  86        if (!count)
  87                return 0;
  88
  89        if (size) {
  90                if (pos >= size)
  91                        return 0;
  92                if (pos + count > size)
  93                        count = size - pos;
  94        }
  95
  96        if (!battr->read)
  97                return -EIO;
  98
  99        return battr->read(of->file, kobj, battr, buf, pos, count);
 100}
 101
 102/* kernfs read callback for regular sysfs files with pre-alloc */
 103static ssize_t sysfs_kf_read(struct kernfs_open_file *of, char *buf,
 104                             size_t count, loff_t pos)
 105{
 106        const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
 107        struct kobject *kobj = of->kn->parent->priv;
 108        ssize_t len;
 109
 110        /*
 111         * If buf != of->prealloc_buf, we don't know how
 112         * large it is, so cannot safely pass it to ->show
 113         */
 114        if (WARN_ON_ONCE(buf != of->prealloc_buf))
 115                return 0;
 116        len = ops->show(kobj, of->kn->priv, buf);
 117        if (len < 0)
 118                return len;
 119        if (pos) {
 120                if (len <= pos)
 121                        return 0;
 122                len -= pos;
 123                memmove(buf, buf + pos, len);
 124        }
 125        return min_t(ssize_t, count, len);
 126}
 127
 128/* kernfs write callback for regular sysfs files */
 129static ssize_t sysfs_kf_write(struct kernfs_open_file *of, char *buf,
 130                              size_t count, loff_t pos)
 131{
 132        const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
 133        struct kobject *kobj = of->kn->parent->priv;
 134
 135        if (!count)
 136                return 0;
 137
 138        return ops->store(kobj, of->kn->priv, buf, count);
 139}
 140
 141/* kernfs write callback for bin sysfs files */
 142static ssize_t sysfs_kf_bin_write(struct kernfs_open_file *of, char *buf,
 143                                  size_t count, loff_t pos)
 144{
 145        struct bin_attribute *battr = of->kn->priv;
 146        struct kobject *kobj = of->kn->parent->priv;
 147        loff_t size = file_inode(of->file)->i_size;
 148
 149        if (size) {
 150                if (size <= pos)
 151                        return -EFBIG;
 152                count = min_t(ssize_t, count, size - pos);
 153        }
 154        if (!count)
 155                return 0;
 156
 157        if (!battr->write)
 158                return -EIO;
 159
 160        return battr->write(of->file, kobj, battr, buf, pos, count);
 161}
 162
 163static int sysfs_kf_bin_mmap(struct kernfs_open_file *of,
 164                             struct vm_area_struct *vma)
 165{
 166        struct bin_attribute *battr = of->kn->priv;
 167        struct kobject *kobj = of->kn->parent->priv;
 168
 169        return battr->mmap(of->file, kobj, battr, vma);
 170}
 171
 172void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr)
 173{
 174        struct kernfs_node *kn = kobj->sd, *tmp;
 175
 176        if (kn && dir)
 177                kn = kernfs_find_and_get(kn, dir);
 178        else
 179                kernfs_get(kn);
 180
 181        if (kn && attr) {
 182                tmp = kernfs_find_and_get(kn, attr);
 183                kernfs_put(kn);
 184                kn = tmp;
 185        }
 186
 187        if (kn) {
 188                kernfs_notify(kn);
 189                kernfs_put(kn);
 190        }
 191}
 192EXPORT_SYMBOL_GPL(sysfs_notify);
 193
 194static const struct kernfs_ops sysfs_file_kfops_empty = {
 195};
 196
 197static const struct kernfs_ops sysfs_file_kfops_ro = {
 198        .seq_show       = sysfs_kf_seq_show,
 199};
 200
 201static const struct kernfs_ops sysfs_file_kfops_wo = {
 202        .write          = sysfs_kf_write,
 203};
 204
 205static const struct kernfs_ops sysfs_file_kfops_rw = {
 206        .seq_show       = sysfs_kf_seq_show,
 207        .write          = sysfs_kf_write,
 208};
 209
 210static const struct kernfs_ops sysfs_prealloc_kfops_ro = {
 211        .read           = sysfs_kf_read,
 212        .prealloc       = true,
 213};
 214
 215static const struct kernfs_ops sysfs_prealloc_kfops_wo = {
 216        .write          = sysfs_kf_write,
 217        .prealloc       = true,
 218};
 219
 220static const struct kernfs_ops sysfs_prealloc_kfops_rw = {
 221        .read           = sysfs_kf_read,
 222        .write          = sysfs_kf_write,
 223        .prealloc       = true,
 224};
 225
 226static const struct kernfs_ops sysfs_bin_kfops_ro = {
 227        .read           = sysfs_kf_bin_read,
 228};
 229
 230static const struct kernfs_ops sysfs_bin_kfops_wo = {
 231        .write          = sysfs_kf_bin_write,
 232};
 233
 234static const struct kernfs_ops sysfs_bin_kfops_rw = {
 235        .read           = sysfs_kf_bin_read,
 236        .write          = sysfs_kf_bin_write,
 237};
 238
 239static const struct kernfs_ops sysfs_bin_kfops_mmap = {
 240        .read           = sysfs_kf_bin_read,
 241        .write          = sysfs_kf_bin_write,
 242        .mmap           = sysfs_kf_bin_mmap,
 243};
 244
 245int sysfs_add_file_mode_ns(struct kernfs_node *parent,
 246                           const struct attribute *attr, bool is_bin,
 247                           umode_t mode, kuid_t uid, kgid_t gid, const void *ns)
 248{
 249        struct lock_class_key *key = NULL;
 250        const struct kernfs_ops *ops;
 251        struct kernfs_node *kn;
 252        loff_t size;
 253
 254        if (!is_bin) {
 255                struct kobject *kobj = parent->priv;
 256                const struct sysfs_ops *sysfs_ops = kobj->ktype->sysfs_ops;
 257
 258                /* every kobject with an attribute needs a ktype assigned */
 259                if (WARN(!sysfs_ops, KERN_ERR
 260                         "missing sysfs attribute operations for kobject: %s\n",
 261                         kobject_name(kobj)))
 262                        return -EINVAL;
 263
 264                if (sysfs_ops->show && sysfs_ops->store) {
 265                        if (mode & SYSFS_PREALLOC)
 266                                ops = &sysfs_prealloc_kfops_rw;
 267                        else
 268                                ops = &sysfs_file_kfops_rw;
 269                } else if (sysfs_ops->show) {
 270                        if (mode & SYSFS_PREALLOC)
 271                                ops = &sysfs_prealloc_kfops_ro;
 272                        else
 273                                ops = &sysfs_file_kfops_ro;
 274                } else if (sysfs_ops->store) {
 275                        if (mode & SYSFS_PREALLOC)
 276                                ops = &sysfs_prealloc_kfops_wo;
 277                        else
 278                                ops = &sysfs_file_kfops_wo;
 279                } else
 280                        ops = &sysfs_file_kfops_empty;
 281
 282                size = PAGE_SIZE;
 283        } else {
 284                struct bin_attribute *battr = (void *)attr;
 285
 286                if (battr->mmap)
 287                        ops = &sysfs_bin_kfops_mmap;
 288                else if (battr->read && battr->write)
 289                        ops = &sysfs_bin_kfops_rw;
 290                else if (battr->read)
 291                        ops = &sysfs_bin_kfops_ro;
 292                else if (battr->write)
 293                        ops = &sysfs_bin_kfops_wo;
 294                else
 295                        ops = &sysfs_file_kfops_empty;
 296
 297                size = battr->size;
 298        }
 299
 300#ifdef CONFIG_DEBUG_LOCK_ALLOC
 301        if (!attr->ignore_lockdep)
 302                key = attr->key ?: (struct lock_class_key *)&attr->skey;
 303#endif
 304
 305        kn = __kernfs_create_file(parent, attr->name, mode & 0777, uid, gid,
 306                                  size, ops, (void *)attr, ns, key);
 307        if (IS_ERR(kn)) {
 308                if (PTR_ERR(kn) == -EEXIST)
 309                        sysfs_warn_dup(parent, attr->name);
 310                return PTR_ERR(kn);
 311        }
 312        return 0;
 313}
 314
 315/**
 316 * sysfs_create_file_ns - create an attribute file for an object with custom ns
 317 * @kobj: object we're creating for
 318 * @attr: attribute descriptor
 319 * @ns: namespace the new file should belong to
 320 */
 321int sysfs_create_file_ns(struct kobject *kobj, const struct attribute *attr,
 322                         const void *ns)
 323{
 324        kuid_t uid;
 325        kgid_t gid;
 326
 327        if (WARN_ON(!kobj || !kobj->sd || !attr))
 328                return -EINVAL;
 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 * const *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 * const *ptr)
 497{
 498        int i;
 499
 500        for (i = 0; ptr[i]; i++)
 501                sysfs_remove_file(kobj, ptr[i]);
 502}
 503EXPORT_SYMBOL_GPL(sysfs_remove_files);
 504
 505/**
 506 * sysfs_remove_file_from_group - remove an attribute file from a group.
 507 * @kobj: object we're acting for.
 508 * @attr: attribute descriptor.
 509 * @group: group name.
 510 */
 511void sysfs_remove_file_from_group(struct kobject *kobj,
 512                const struct attribute *attr, const char *group)
 513{
 514        struct kernfs_node *parent;
 515
 516        if (group) {
 517                parent = kernfs_find_and_get(kobj->sd, group);
 518        } else {
 519                parent = kobj->sd;
 520                kernfs_get(parent);
 521        }
 522
 523        if (parent) {
 524                kernfs_remove_by_name(parent, attr->name);
 525                kernfs_put(parent);
 526        }
 527}
 528EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group);
 529
 530/**
 531 *      sysfs_create_bin_file - create binary file for object.
 532 *      @kobj:  object.
 533 *      @attr:  attribute descriptor.
 534 */
 535int sysfs_create_bin_file(struct kobject *kobj,
 536                          const struct bin_attribute *attr)
 537{
 538        kuid_t uid;
 539        kgid_t gid;
 540
 541        if (WARN_ON(!kobj || !kobj->sd || !attr))
 542                return -EINVAL;
 543
 544        kobject_get_ownership(kobj, &uid, &gid);
 545        return sysfs_add_file_mode_ns(kobj->sd, &attr->attr, true,
 546                                      attr->attr.mode, uid, gid, NULL);
 547}
 548EXPORT_SYMBOL_GPL(sysfs_create_bin_file);
 549
 550/**
 551 *      sysfs_remove_bin_file - remove binary file for object.
 552 *      @kobj:  object.
 553 *      @attr:  attribute descriptor.
 554 */
 555void sysfs_remove_bin_file(struct kobject *kobj,
 556                           const struct bin_attribute *attr)
 557{
 558        kernfs_remove_by_name(kobj->sd, attr->attr.name);
 559}
 560EXPORT_SYMBOL_GPL(sysfs_remove_bin_file);
 561