linux/fs/sysfs/bin.c
<<
>>
Prefs
   1/*
   2 * fs/sysfs/bin.c - sysfs binary file implementation
   3 *
   4 * Copyright (c) 2003 Patrick Mochel
   5 * Copyright (c) 2003 Matthew Wilcox
   6 * Copyright (c) 2004 Silicon Graphics, Inc.
   7 * Copyright (c) 2007 SUSE Linux Products GmbH
   8 * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
   9 *
  10 * This file is released under the GPLv2.
  11 *
  12 * Please see Documentation/filesystems/sysfs.txt for more information.
  13 */
  14
  15#undef DEBUG
  16
  17#include <linux/errno.h>
  18#include <linux/fs.h>
  19#include <linux/kernel.h>
  20#include <linux/kobject.h>
  21#include <linux/module.h>
  22#include <linux/slab.h>
  23#include <linux/mutex.h>
  24#include <linux/mm.h>
  25
  26#include <asm/uaccess.h>
  27
  28#include "sysfs.h"
  29
  30/*
  31 * There's one bin_buffer for each open file.
  32 *
  33 * filp->private_data points to bin_buffer and
  34 * sysfs_dirent->s_bin_attr.buffers points to a the bin_buffer s
  35 * sysfs_dirent->s_bin_attr.buffers is protected by sysfs_bin_lock
  36 */
  37static DEFINE_MUTEX(sysfs_bin_lock);
  38
  39struct bin_buffer {
  40        struct mutex                    mutex;
  41        void                            *buffer;
  42        int                             mmapped;
  43        const struct vm_operations_struct *vm_ops;
  44        struct file                     *file;
  45        struct hlist_node               list;
  46};
  47
  48static int
  49fill_read(struct file *file, char *buffer, loff_t off, size_t count)
  50{
  51        struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
  52        struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
  53        struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
  54        int rc;
  55
  56        /* need attr_sd for attr, its parent for kobj */
  57        if (!sysfs_get_active(attr_sd))
  58                return -ENODEV;
  59
  60        rc = -EIO;
  61        if (attr->read)
  62                rc = attr->read(file, kobj, attr, buffer, off, count);
  63
  64        sysfs_put_active(attr_sd);
  65
  66        return rc;
  67}
  68
  69static ssize_t
  70read(struct file *file, char __user *userbuf, size_t bytes, loff_t *off)
  71{
  72        struct bin_buffer *bb = file->private_data;
  73        int size = file->f_path.dentry->d_inode->i_size;
  74        loff_t offs = *off;
  75        int count = min_t(size_t, bytes, PAGE_SIZE);
  76        char *temp;
  77
  78        if (!bytes)
  79                return 0;
  80
  81        if (size) {
  82                if (offs > size)
  83                        return 0;
  84                if (offs + count > size)
  85                        count = size - offs;
  86        }
  87
  88        temp = kmalloc(count, GFP_KERNEL);
  89        if (!temp)
  90                return -ENOMEM;
  91
  92        mutex_lock(&bb->mutex);
  93
  94        count = fill_read(file, bb->buffer, offs, count);
  95        if (count < 0) {
  96                mutex_unlock(&bb->mutex);
  97                goto out_free;
  98        }
  99
 100        memcpy(temp, bb->buffer, count);
 101
 102        mutex_unlock(&bb->mutex);
 103
 104        if (copy_to_user(userbuf, temp, count)) {
 105                count = -EFAULT;
 106                goto out_free;
 107        }
 108
 109        pr_debug("offs = %lld, *off = %lld, count = %d\n", offs, *off, count);
 110
 111        *off = offs + count;
 112
 113 out_free:
 114        kfree(temp);
 115        return count;
 116}
 117
 118static int
 119flush_write(struct file *file, char *buffer, loff_t offset, size_t count)
 120{
 121        struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
 122        struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
 123        struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
 124        int rc;
 125
 126        /* need attr_sd for attr, its parent for kobj */
 127        if (!sysfs_get_active(attr_sd))
 128                return -ENODEV;
 129
 130        rc = -EIO;
 131        if (attr->write)
 132                rc = attr->write(file, kobj, attr, buffer, offset, count);
 133
 134        sysfs_put_active(attr_sd);
 135
 136        return rc;
 137}
 138
 139static ssize_t write(struct file *file, const char __user *userbuf,
 140                     size_t bytes, loff_t *off)
 141{
 142        struct bin_buffer *bb = file->private_data;
 143        int size = file->f_path.dentry->d_inode->i_size;
 144        loff_t offs = *off;
 145        int count = min_t(size_t, bytes, PAGE_SIZE);
 146        char *temp;
 147
 148        if (!bytes)
 149                return 0;
 150
 151        if (size) {
 152                if (offs > size)
 153                        return 0;
 154                if (offs + count > size)
 155                        count = size - offs;
 156        }
 157
 158        temp = memdup_user(userbuf, count);
 159        if (IS_ERR(temp))
 160                return PTR_ERR(temp);
 161
 162        mutex_lock(&bb->mutex);
 163
 164        memcpy(bb->buffer, temp, count);
 165
 166        count = flush_write(file, bb->buffer, offs, count);
 167        mutex_unlock(&bb->mutex);
 168
 169        if (count > 0)
 170                *off = offs + count;
 171
 172        kfree(temp);
 173        return count;
 174}
 175
 176static void bin_vma_open(struct vm_area_struct *vma)
 177{
 178        struct file *file = vma->vm_file;
 179        struct bin_buffer *bb = file->private_data;
 180        struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
 181
 182        if (!bb->vm_ops)
 183                return;
 184
 185        if (!sysfs_get_active(attr_sd))
 186                return;
 187
 188        if (bb->vm_ops->open)
 189                bb->vm_ops->open(vma);
 190
 191        sysfs_put_active(attr_sd);
 192}
 193
 194static int bin_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 195{
 196        struct file *file = vma->vm_file;
 197        struct bin_buffer *bb = file->private_data;
 198        struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
 199        int ret;
 200
 201        if (!bb->vm_ops)
 202                return VM_FAULT_SIGBUS;
 203
 204        if (!sysfs_get_active(attr_sd))
 205                return VM_FAULT_SIGBUS;
 206
 207        ret = VM_FAULT_SIGBUS;
 208        if (bb->vm_ops->fault)
 209                ret = bb->vm_ops->fault(vma, vmf);
 210
 211        sysfs_put_active(attr_sd);
 212        return ret;
 213}
 214
 215static int bin_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 216{
 217        struct file *file = vma->vm_file;
 218        struct bin_buffer *bb = file->private_data;
 219        struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
 220        int ret;
 221
 222        if (!bb->vm_ops)
 223                return VM_FAULT_SIGBUS;
 224
 225        if (!sysfs_get_active(attr_sd))
 226                return VM_FAULT_SIGBUS;
 227
 228        ret = 0;
 229        if (bb->vm_ops->page_mkwrite)
 230                ret = bb->vm_ops->page_mkwrite(vma, vmf);
 231
 232        sysfs_put_active(attr_sd);
 233        return ret;
 234}
 235
 236static int bin_access(struct vm_area_struct *vma, unsigned long addr,
 237                  void *buf, int len, int write)
 238{
 239        struct file *file = vma->vm_file;
 240        struct bin_buffer *bb = file->private_data;
 241        struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
 242        int ret;
 243
 244        if (!bb->vm_ops)
 245                return -EINVAL;
 246
 247        if (!sysfs_get_active(attr_sd))
 248                return -EINVAL;
 249
 250        ret = -EINVAL;
 251        if (bb->vm_ops->access)
 252                ret = bb->vm_ops->access(vma, addr, buf, len, write);
 253
 254        sysfs_put_active(attr_sd);
 255        return ret;
 256}
 257
 258#ifdef CONFIG_NUMA
 259static int bin_set_policy(struct vm_area_struct *vma, struct mempolicy *new)
 260{
 261        struct file *file = vma->vm_file;
 262        struct bin_buffer *bb = file->private_data;
 263        struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
 264        int ret;
 265
 266        if (!bb->vm_ops)
 267                return 0;
 268
 269        if (!sysfs_get_active(attr_sd))
 270                return -EINVAL;
 271
 272        ret = 0;
 273        if (bb->vm_ops->set_policy)
 274                ret = bb->vm_ops->set_policy(vma, new);
 275
 276        sysfs_put_active(attr_sd);
 277        return ret;
 278}
 279
 280static struct mempolicy *bin_get_policy(struct vm_area_struct *vma,
 281                                        unsigned long addr)
 282{
 283        struct file *file = vma->vm_file;
 284        struct bin_buffer *bb = file->private_data;
 285        struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
 286        struct mempolicy *pol;
 287
 288        if (!bb->vm_ops)
 289                return vma->vm_policy;
 290
 291        if (!sysfs_get_active(attr_sd))
 292                return vma->vm_policy;
 293
 294        pol = vma->vm_policy;
 295        if (bb->vm_ops->get_policy)
 296                pol = bb->vm_ops->get_policy(vma, addr);
 297
 298        sysfs_put_active(attr_sd);
 299        return pol;
 300}
 301
 302static int bin_migrate(struct vm_area_struct *vma, const nodemask_t *from,
 303                        const nodemask_t *to, unsigned long flags)
 304{
 305        struct file *file = vma->vm_file;
 306        struct bin_buffer *bb = file->private_data;
 307        struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
 308        int ret;
 309
 310        if (!bb->vm_ops)
 311                return 0;
 312
 313        if (!sysfs_get_active(attr_sd))
 314                return 0;
 315
 316        ret = 0;
 317        if (bb->vm_ops->migrate)
 318                ret = bb->vm_ops->migrate(vma, from, to, flags);
 319
 320        sysfs_put_active(attr_sd);
 321        return ret;
 322}
 323#endif
 324
 325static const struct vm_operations_struct bin_vm_ops = {
 326        .open           = bin_vma_open,
 327        .fault          = bin_fault,
 328        .page_mkwrite   = bin_page_mkwrite,
 329        .access         = bin_access,
 330#ifdef CONFIG_NUMA
 331        .set_policy     = bin_set_policy,
 332        .get_policy     = bin_get_policy,
 333        .migrate        = bin_migrate,
 334#endif
 335};
 336
 337static int mmap(struct file *file, struct vm_area_struct *vma)
 338{
 339        struct bin_buffer *bb = file->private_data;
 340        struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
 341        struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
 342        struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
 343        int rc;
 344
 345        mutex_lock(&bb->mutex);
 346
 347        /* need attr_sd for attr, its parent for kobj */
 348        rc = -ENODEV;
 349        if (!sysfs_get_active(attr_sd))
 350                goto out_unlock;
 351
 352        rc = -EINVAL;
 353        if (!attr->mmap)
 354                goto out_put;
 355
 356        rc = attr->mmap(file, kobj, attr, vma);
 357        if (rc)
 358                goto out_put;
 359
 360        /*
 361         * PowerPC's pci_mmap of legacy_mem uses shmem_zero_setup()
 362         * to satisfy versions of X which crash if the mmap fails: that
 363         * substitutes a new vm_file, and we don't then want bin_vm_ops.
 364         */
 365        if (vma->vm_file != file)
 366                goto out_put;
 367
 368        rc = -EINVAL;
 369        if (bb->mmapped && bb->vm_ops != vma->vm_ops)
 370                goto out_put;
 371
 372        /*
 373         * It is not possible to successfully wrap close.
 374         * So error if someone is trying to use close.
 375         */
 376        rc = -EINVAL;
 377        if (vma->vm_ops && vma->vm_ops->close)
 378                goto out_put;
 379
 380        rc = 0;
 381        bb->mmapped = 1;
 382        bb->vm_ops = vma->vm_ops;
 383        vma->vm_ops = &bin_vm_ops;
 384out_put:
 385        sysfs_put_active(attr_sd);
 386out_unlock:
 387        mutex_unlock(&bb->mutex);
 388
 389        return rc;
 390}
 391
 392static int open(struct inode * inode, struct file * file)
 393{
 394        struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
 395        struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
 396        struct bin_buffer *bb = NULL;
 397        int error;
 398
 399        /* binary file operations requires both @sd and its parent */
 400        if (!sysfs_get_active(attr_sd))
 401                return -ENODEV;
 402
 403        error = -EACCES;
 404        if ((file->f_mode & FMODE_WRITE) && !(attr->write || attr->mmap))
 405                goto err_out;
 406        if ((file->f_mode & FMODE_READ) && !(attr->read || attr->mmap))
 407                goto err_out;
 408
 409        error = -ENOMEM;
 410        bb = kzalloc(sizeof(*bb), GFP_KERNEL);
 411        if (!bb)
 412                goto err_out;
 413
 414        bb->buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
 415        if (!bb->buffer)
 416                goto err_out;
 417
 418        mutex_init(&bb->mutex);
 419        bb->file = file;
 420        file->private_data = bb;
 421
 422        mutex_lock(&sysfs_bin_lock);
 423        hlist_add_head(&bb->list, &attr_sd->s_bin_attr.buffers);
 424        mutex_unlock(&sysfs_bin_lock);
 425
 426        /* open succeeded, put active references */
 427        sysfs_put_active(attr_sd);
 428        return 0;
 429
 430 err_out:
 431        sysfs_put_active(attr_sd);
 432        kfree(bb);
 433        return error;
 434}
 435
 436static int release(struct inode * inode, struct file * file)
 437{
 438        struct bin_buffer *bb = file->private_data;
 439
 440        mutex_lock(&sysfs_bin_lock);
 441        hlist_del(&bb->list);
 442        mutex_unlock(&sysfs_bin_lock);
 443
 444        kfree(bb->buffer);
 445        kfree(bb);
 446        return 0;
 447}
 448
 449const struct file_operations bin_fops = {
 450        .read           = read,
 451        .write          = write,
 452        .mmap           = mmap,
 453        .llseek         = generic_file_llseek,
 454        .open           = open,
 455        .release        = release,
 456};
 457
 458
 459void unmap_bin_file(struct sysfs_dirent *attr_sd)
 460{
 461        struct bin_buffer *bb;
 462        struct hlist_node *tmp;
 463
 464        if (sysfs_type(attr_sd) != SYSFS_KOBJ_BIN_ATTR)
 465                return;
 466
 467        mutex_lock(&sysfs_bin_lock);
 468
 469        hlist_for_each_entry(bb, tmp, &attr_sd->s_bin_attr.buffers, list) {
 470                struct inode *inode = bb->file->f_path.dentry->d_inode;
 471
 472                unmap_mapping_range(inode->i_mapping, 0, 0, 1);
 473        }
 474
 475        mutex_unlock(&sysfs_bin_lock);
 476}
 477
 478/**
 479 *      sysfs_create_bin_file - create binary file for object.
 480 *      @kobj:  object.
 481 *      @attr:  attribute descriptor.
 482 */
 483
 484int sysfs_create_bin_file(struct kobject *kobj,
 485                          const struct bin_attribute *attr)
 486{
 487        BUG_ON(!kobj || !kobj->sd || !attr);
 488
 489        return sysfs_add_file(kobj->sd, &attr->attr, SYSFS_KOBJ_BIN_ATTR);
 490}
 491
 492
 493/**
 494 *      sysfs_remove_bin_file - remove binary file for object.
 495 *      @kobj:  object.
 496 *      @attr:  attribute descriptor.
 497 */
 498
 499void sysfs_remove_bin_file(struct kobject *kobj,
 500                           const struct bin_attribute *attr)
 501{
 502        sysfs_hash_and_remove(kobj->sd, NULL, attr->attr.name);
 503}
 504
 505EXPORT_SYMBOL_GPL(sysfs_create_bin_file);
 506EXPORT_SYMBOL_GPL(sysfs_remove_bin_file);
 507