linux/fs/sysfs/file.c
<<
>>
Prefs
   1/*
   2 * fs/sysfs/file.c - sysfs regular (text) file implementation
   3 *
   4 * Copyright (c) 2001-3 Patrick Mochel
   5 * Copyright (c) 2007 SUSE Linux Products GmbH
   6 * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
   7 *
   8 * This file is released under the GPLv2.
   9 *
  10 * Please see Documentation/filesystems/sysfs.txt for more information.
  11 */
  12
  13#include <linux/module.h>
  14#include <linux/kobject.h>
  15#include <linux/kallsyms.h>
  16#include <linux/slab.h>
  17#include <linux/list.h>
  18#include <linux/mutex.h>
  19#include <linux/seq_file.h>
  20
  21#include "sysfs.h"
  22#include "../kernfs/kernfs-internal.h"
  23
  24/*
  25 * Determine ktype->sysfs_ops for the given kernfs_node.  This function
  26 * must be called while holding an active reference.
  27 */
  28static const struct sysfs_ops *sysfs_file_ops(struct kernfs_node *kn)
  29{
  30        struct kobject *kobj = kn->parent->priv;
  31
  32        if (kn->flags & KERNFS_LOCKDEP)
  33                lockdep_assert_held(kn);
  34        return kobj->ktype ? kobj->ktype->sysfs_ops : NULL;
  35}
  36
  37/*
  38 * Reads on sysfs are handled through seq_file, which takes care of hairy
  39 * details like buffering and seeking.  The following function pipes
  40 * sysfs_ops->show() result through seq_file.
  41 */
  42static int sysfs_kf_seq_show(struct seq_file *sf, void *v)
  43{
  44        struct kernfs_open_file *of = sf->private;
  45        struct kobject *kobj = of->kn->parent->priv;
  46        const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
  47        ssize_t count;
  48        char *buf;
  49
  50        /* acquire buffer and ensure that it's >= PAGE_SIZE and clear */
  51        count = seq_get_buf(sf, &buf);
  52        if (count < PAGE_SIZE) {
  53                seq_commit(sf, -1);
  54                return 0;
  55        }
  56        memset(buf, 0, PAGE_SIZE);
  57
  58        /*
  59         * Invoke show().  Control may reach here via seq file lseek even
  60         * if @ops->show() isn't implemented.
  61         */
  62        if (ops->show) {
  63                count = ops->show(kobj, of->kn->priv, buf);
  64                if (count < 0)
  65                        return count;
  66        }
  67
  68        /*
  69         * The code works fine with PAGE_SIZE return but it's likely to
  70         * indicate truncated result or overflow in normal use cases.
  71         */
  72        if (count >= (ssize_t)PAGE_SIZE) {
  73                print_symbol("fill_read_buffer: %s returned bad count\n",
  74                        (unsigned long)ops->show);
  75                /* Try to struggle along */
  76                count = PAGE_SIZE - 1;
  77        }
  78        seq_commit(sf, count);
  79        return 0;
  80}
  81
  82static ssize_t sysfs_kf_bin_read(struct kernfs_open_file *of, char *buf,
  83                                 size_t count, loff_t pos)
  84{
  85        struct bin_attribute *battr = of->kn->priv;
  86        struct kobject *kobj = of->kn->parent->priv;
  87        loff_t size = file_inode(of->file)->i_size;
  88
  89        if (!count)
  90                return 0;
  91
  92        if (size) {
  93                if (pos >= size)
  94                        return 0;
  95                if (pos + count > size)
  96                        count = size - pos;
  97        }
  98
  99        if (!battr->read)
 100                return -EIO;
 101
 102        return battr->read(of->file, kobj, battr, buf, pos, count);
 103}
 104
 105/* kernfs read callback for regular sysfs files with pre-alloc */
 106static ssize_t sysfs_kf_read(struct kernfs_open_file *of, char *buf,
 107                             size_t count, loff_t pos)
 108{
 109        const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
 110        struct kobject *kobj = of->kn->parent->priv;
 111        ssize_t len;
 112
 113        /*
 114         * If buf != of->prealloc_buf, we don't know how
 115         * large it is, so cannot safely pass it to ->show
 116         */
 117        if (WARN_ON_ONCE(buf != of->prealloc_buf))
 118                return 0;
 119        len = ops->show(kobj, of->kn->priv, buf);
 120        if (len < 0)
 121                return len;
 122        if (pos) {
 123                if (len <= pos)
 124                        return 0;
 125                len -= pos;
 126                memmove(buf, buf + pos, len);
 127        }
 128        return min_t(ssize_t, count, len);
 129}
 130
 131/* kernfs write callback for regular sysfs files */
 132static ssize_t sysfs_kf_write(struct kernfs_open_file *of, char *buf,
 133                              size_t count, loff_t pos)
 134{
 135        const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
 136        struct kobject *kobj = of->kn->parent->priv;
 137
 138        if (!count)
 139                return 0;
 140
 141        return ops->store(kobj, of->kn->priv, buf, count);
 142}
 143
 144/* kernfs write callback for bin sysfs files */
 145static ssize_t sysfs_kf_bin_write(struct kernfs_open_file *of, char *buf,
 146                                  size_t count, loff_t pos)
 147{
 148        struct bin_attribute *battr = of->kn->priv;
 149        struct kobject *kobj = of->kn->parent->priv;
 150        loff_t size = file_inode(of->file)->i_size;
 151
 152        if (size) {
 153                if (size <= pos)
 154                        return -EFBIG;
 155                count = min_t(ssize_t, count, size - pos);
 156        }
 157        if (!count)
 158                return 0;
 159
 160        if (!battr->write)
 161                return -EIO;
 162
 163        return battr->write(of->file, kobj, battr, buf, pos, count);
 164}
 165
 166static int sysfs_kf_bin_mmap(struct kernfs_open_file *of,
 167                             struct vm_area_struct *vma)
 168{
 169        struct bin_attribute *battr = of->kn->priv;
 170        struct kobject *kobj = of->kn->parent->priv;
 171
 172        return battr->mmap(of->file, kobj, battr, vma);
 173}
 174
 175void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr)
 176{
 177        struct kernfs_node *kn = kobj->sd, *tmp;
 178
 179        if (kn && dir)
 180                kn = kernfs_find_and_get(kn, dir);
 181        else
 182                kernfs_get(kn);
 183
 184        if (kn && attr) {
 185                tmp = kernfs_find_and_get(kn, attr);
 186                kernfs_put(kn);
 187                kn = tmp;
 188        }
 189
 190        if (kn) {
 191                kernfs_notify(kn);
 192                kernfs_put(kn);
 193        }
 194}
 195EXPORT_SYMBOL_GPL(sysfs_notify);
 196
 197static const struct kernfs_ops sysfs_file_kfops_empty = {
 198};
 199
 200static const struct kernfs_ops sysfs_file_kfops_ro = {
 201        .seq_show       = sysfs_kf_seq_show,
 202};
 203
 204static const struct kernfs_ops sysfs_file_kfops_wo = {
 205        .write          = sysfs_kf_write,
 206};
 207
 208static const struct kernfs_ops sysfs_file_kfops_rw = {
 209        .seq_show       = sysfs_kf_seq_show,
 210        .write          = sysfs_kf_write,
 211};
 212
 213static const struct kernfs_ops sysfs_prealloc_kfops_ro = {
 214        .read           = sysfs_kf_read,
 215        .prealloc       = true,
 216};
 217
 218static const struct kernfs_ops sysfs_prealloc_kfops_wo = {
 219        .write          = sysfs_kf_write,
 220        .prealloc       = true,
 221};
 222
 223static const struct kernfs_ops sysfs_prealloc_kfops_rw = {
 224        .read           = sysfs_kf_read,
 225        .write          = sysfs_kf_write,
 226        .prealloc       = true,
 227};
 228
 229static const struct kernfs_ops sysfs_bin_kfops_ro = {
 230        .read           = sysfs_kf_bin_read,
 231};
 232
 233static const struct kernfs_ops sysfs_bin_kfops_wo = {
 234        .write          = sysfs_kf_bin_write,
 235};
 236
 237static const struct kernfs_ops sysfs_bin_kfops_rw = {
 238        .read           = sysfs_kf_bin_read,
 239        .write          = sysfs_kf_bin_write,
 240};
 241
 242static const struct kernfs_ops sysfs_bin_kfops_mmap = {
 243        .read           = sysfs_kf_bin_read,
 244        .write          = sysfs_kf_bin_write,
 245        .mmap           = sysfs_kf_bin_mmap,
 246};
 247
 248int sysfs_add_file_mode_ns(struct kernfs_node *parent,
 249                           const struct attribute *attr, bool is_bin,
 250                           umode_t mode, const void *ns)
 251{
 252        struct lock_class_key *key = NULL;
 253        const struct kernfs_ops *ops;
 254        struct kernfs_node *kn;
 255        loff_t size;
 256
 257        if (!is_bin) {
 258                struct kobject *kobj = parent->priv;
 259                const struct sysfs_ops *sysfs_ops = kobj->ktype->sysfs_ops;
 260
 261                /* every kobject with an attribute needs a ktype assigned */
 262                if (WARN(!sysfs_ops, KERN_ERR
 263                         "missing sysfs attribute operations for kobject: %s\n",
 264                         kobject_name(kobj)))
 265                        return -EINVAL;
 266
 267                if (sysfs_ops->show && sysfs_ops->store) {
 268                        if (mode & SYSFS_PREALLOC)
 269                                ops = &sysfs_prealloc_kfops_rw;
 270                        else
 271                                ops = &sysfs_file_kfops_rw;
 272                } else if (sysfs_ops->show) {
 273                        if (mode & SYSFS_PREALLOC)
 274                                ops = &sysfs_prealloc_kfops_ro;
 275                        else
 276                                ops = &sysfs_file_kfops_ro;
 277                } else if (sysfs_ops->store) {
 278                        if (mode & SYSFS_PREALLOC)
 279                                ops = &sysfs_prealloc_kfops_wo;
 280                        else
 281                                ops = &sysfs_file_kfops_wo;
 282                } else
 283                        ops = &sysfs_file_kfops_empty;
 284
 285                size = PAGE_SIZE;
 286        } else {
 287                struct bin_attribute *battr = (void *)attr;
 288
 289                if (battr->mmap)
 290                        ops = &sysfs_bin_kfops_mmap;
 291                else if (battr->read && battr->write)
 292                        ops = &sysfs_bin_kfops_rw;
 293                else if (battr->read)
 294                        ops = &sysfs_bin_kfops_ro;
 295                else if (battr->write)
 296                        ops = &sysfs_bin_kfops_wo;
 297                else
 298                        ops = &sysfs_file_kfops_empty;
 299
 300                size = battr->size;
 301        }
 302
 303#ifdef CONFIG_DEBUG_LOCK_ALLOC
 304        if (!attr->ignore_lockdep)
 305                key = attr->key ?: (struct lock_class_key *)&attr->skey;
 306#endif
 307        kn = __kernfs_create_file(parent, attr->name, mode & 0777, size, ops,
 308                                  (void *)attr, ns, key);
 309        if (IS_ERR(kn)) {
 310                if (PTR_ERR(kn) == -EEXIST)
 311                        sysfs_warn_dup(parent, attr->name);
 312                return PTR_ERR(kn);
 313        }
 314        return 0;
 315}
 316
 317int sysfs_add_file(struct kernfs_node *parent, const struct attribute *attr,
 318                   bool is_bin)
 319{
 320        return sysfs_add_file_mode_ns(parent, attr, is_bin, attr->mode, NULL);
 321}
 322
 323/**
 324 * sysfs_create_file_ns - create an attribute file for an object with custom ns
 325 * @kobj: object we're creating for
 326 * @attr: attribute descriptor
 327 * @ns: namespace the new file should belong to
 328 */
 329int sysfs_create_file_ns(struct kobject *kobj, const struct attribute *attr,
 330                         const void *ns)
 331{
 332        BUG_ON(!kobj || !kobj->sd || !attr);
 333
 334        return sysfs_add_file_mode_ns(kobj->sd, attr, false, attr->mode, ns);
 335
 336}
 337EXPORT_SYMBOL_GPL(sysfs_create_file_ns);
 338
 339int sysfs_create_files(struct kobject *kobj, const struct attribute **ptr)
 340{
 341        int err = 0;
 342        int i;
 343
 344        for (i = 0; ptr[i] && !err; i++)
 345                err = sysfs_create_file(kobj, ptr[i]);
 346        if (err)
 347                while (--i >= 0)
 348                        sysfs_remove_file(kobj, ptr[i]);
 349        return err;
 350}
 351EXPORT_SYMBOL_GPL(sysfs_create_files);
 352
 353/**
 354 * sysfs_add_file_to_group - add an attribute file to a pre-existing group.
 355 * @kobj: object we're acting for.
 356 * @attr: attribute descriptor.
 357 * @group: group name.
 358 */
 359int sysfs_add_file_to_group(struct kobject *kobj,
 360                const struct attribute *attr, const char *group)
 361{
 362        struct kernfs_node *parent;
 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        error = sysfs_add_file(parent, attr, false);
 376        kernfs_put(parent);
 377
 378        return error;
 379}
 380EXPORT_SYMBOL_GPL(sysfs_add_file_to_group);
 381
 382/**
 383 * sysfs_chmod_file - update the modified mode value on an object attribute.
 384 * @kobj: object we're acting for.
 385 * @attr: attribute descriptor.
 386 * @mode: file permissions.
 387 *
 388 */
 389int sysfs_chmod_file(struct kobject *kobj, const struct attribute *attr,
 390                     umode_t mode)
 391{
 392        struct kernfs_node *kn;
 393        struct iattr newattrs;
 394        int rc;
 395
 396        kn = kernfs_find_and_get(kobj->sd, attr->name);
 397        if (!kn)
 398                return -ENOENT;
 399
 400        newattrs.ia_mode = (mode & S_IALLUGO) | (kn->mode & ~S_IALLUGO);
 401        newattrs.ia_valid = ATTR_MODE;
 402
 403        rc = kernfs_setattr(kn, &newattrs);
 404
 405        kernfs_put(kn);
 406        return rc;
 407}
 408EXPORT_SYMBOL_GPL(sysfs_chmod_file);
 409
 410/**
 411 * sysfs_remove_file_ns - remove an object attribute with a custom ns tag
 412 * @kobj: object we're acting for
 413 * @attr: attribute descriptor
 414 * @ns: namespace tag of the file to remove
 415 *
 416 * Hash the attribute name and namespace tag and kill the victim.
 417 */
 418void sysfs_remove_file_ns(struct kobject *kobj, const struct attribute *attr,
 419                          const void *ns)
 420{
 421        struct kernfs_node *parent = kobj->sd;
 422
 423        kernfs_remove_by_name_ns(parent, attr->name, ns);
 424}
 425EXPORT_SYMBOL_GPL(sysfs_remove_file_ns);
 426
 427/**
 428 * sysfs_remove_file_self - remove an object attribute from its own method
 429 * @kobj: object we're acting for
 430 * @attr: attribute descriptor
 431 *
 432 * See kernfs_remove_self() for details.
 433 */
 434bool sysfs_remove_file_self(struct kobject *kobj, const struct attribute *attr)
 435{
 436        struct kernfs_node *parent = kobj->sd;
 437        struct kernfs_node *kn;
 438        bool ret;
 439
 440        kn = kernfs_find_and_get(parent, attr->name);
 441        if (WARN_ON_ONCE(!kn))
 442                return false;
 443
 444        ret = kernfs_remove_self(kn);
 445
 446        kernfs_put(kn);
 447        return ret;
 448}
 449
 450void sysfs_remove_files(struct kobject *kobj, const struct attribute **ptr)
 451{
 452        int i;
 453        for (i = 0; ptr[i]; i++)
 454                sysfs_remove_file(kobj, ptr[i]);
 455}
 456EXPORT_SYMBOL_GPL(sysfs_remove_files);
 457
 458/**
 459 * sysfs_remove_file_from_group - remove an attribute file from a group.
 460 * @kobj: object we're acting for.
 461 * @attr: attribute descriptor.
 462 * @group: group name.
 463 */
 464void sysfs_remove_file_from_group(struct kobject *kobj,
 465                const struct attribute *attr, const char *group)
 466{
 467        struct kernfs_node *parent;
 468
 469        if (group) {
 470                parent = kernfs_find_and_get(kobj->sd, group);
 471        } else {
 472                parent = kobj->sd;
 473                kernfs_get(parent);
 474        }
 475
 476        if (parent) {
 477                kernfs_remove_by_name(parent, attr->name);
 478                kernfs_put(parent);
 479        }
 480}
 481EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group);
 482
 483/**
 484 *      sysfs_create_bin_file - create binary file for object.
 485 *      @kobj:  object.
 486 *      @attr:  attribute descriptor.
 487 */
 488int sysfs_create_bin_file(struct kobject *kobj,
 489                          const struct bin_attribute *attr)
 490{
 491        BUG_ON(!kobj || !kobj->sd || !attr);
 492
 493        return sysfs_add_file(kobj->sd, &attr->attr, true);
 494}
 495EXPORT_SYMBOL_GPL(sysfs_create_bin_file);
 496
 497/**
 498 *      sysfs_remove_bin_file - remove binary file for object.
 499 *      @kobj:  object.
 500 *      @attr:  attribute descriptor.
 501 */
 502void sysfs_remove_bin_file(struct kobject *kobj,
 503                           const struct bin_attribute *attr)
 504{
 505        kernfs_remove_by_name(kobj->sd, attr->attr.name);
 506}
 507EXPORT_SYMBOL_GPL(sysfs_remove_bin_file);
 508