at v2.6.26-rc7 259 lines 5.7 kB view raw
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 25#include <asm/uaccess.h> 26 27#include "sysfs.h" 28 29struct bin_buffer { 30 struct mutex mutex; 31 void *buffer; 32 int mmapped; 33}; 34 35static int 36fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count) 37{ 38 struct sysfs_dirent *attr_sd = dentry->d_fsdata; 39 struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; 40 struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; 41 int rc; 42 43 /* need attr_sd for attr, its parent for kobj */ 44 if (!sysfs_get_active_two(attr_sd)) 45 return -ENODEV; 46 47 rc = -EIO; 48 if (attr->read) 49 rc = attr->read(kobj, attr, buffer, off, count); 50 51 sysfs_put_active_two(attr_sd); 52 53 return rc; 54} 55 56static ssize_t 57read(struct file *file, char __user *userbuf, size_t bytes, loff_t *off) 58{ 59 struct bin_buffer *bb = file->private_data; 60 struct dentry *dentry = file->f_path.dentry; 61 int size = dentry->d_inode->i_size; 62 loff_t offs = *off; 63 int count = min_t(size_t, bytes, PAGE_SIZE); 64 65 if (size) { 66 if (offs > size) 67 return 0; 68 if (offs + count > size) 69 count = size - offs; 70 } 71 72 mutex_lock(&bb->mutex); 73 74 count = fill_read(dentry, bb->buffer, offs, count); 75 if (count < 0) 76 goto out_unlock; 77 78 if (copy_to_user(userbuf, bb->buffer, count)) { 79 count = -EFAULT; 80 goto out_unlock; 81 } 82 83 pr_debug("offs = %lld, *off = %lld, count = %d\n", offs, *off, count); 84 85 *off = offs + count; 86 87 out_unlock: 88 mutex_unlock(&bb->mutex); 89 return count; 90} 91 92static int 93flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count) 94{ 95 struct sysfs_dirent *attr_sd = dentry->d_fsdata; 96 struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; 97 struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; 98 int rc; 99 100 /* need attr_sd for attr, its parent for kobj */ 101 if (!sysfs_get_active_two(attr_sd)) 102 return -ENODEV; 103 104 rc = -EIO; 105 if (attr->write) 106 rc = attr->write(kobj, attr, buffer, offset, count); 107 108 sysfs_put_active_two(attr_sd); 109 110 return rc; 111} 112 113static ssize_t write(struct file *file, const char __user *userbuf, 114 size_t bytes, loff_t *off) 115{ 116 struct bin_buffer *bb = file->private_data; 117 struct dentry *dentry = file->f_path.dentry; 118 int size = dentry->d_inode->i_size; 119 loff_t offs = *off; 120 int count = min_t(size_t, bytes, PAGE_SIZE); 121 122 if (size) { 123 if (offs > size) 124 return 0; 125 if (offs + count > size) 126 count = size - offs; 127 } 128 129 mutex_lock(&bb->mutex); 130 131 if (copy_from_user(bb->buffer, userbuf, count)) { 132 count = -EFAULT; 133 goto out_unlock; 134 } 135 136 count = flush_write(dentry, bb->buffer, offs, count); 137 if (count > 0) 138 *off = offs + count; 139 140 out_unlock: 141 mutex_unlock(&bb->mutex); 142 return count; 143} 144 145static int mmap(struct file *file, struct vm_area_struct *vma) 146{ 147 struct bin_buffer *bb = file->private_data; 148 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; 149 struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; 150 struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; 151 int rc; 152 153 mutex_lock(&bb->mutex); 154 155 /* need attr_sd for attr, its parent for kobj */ 156 if (!sysfs_get_active_two(attr_sd)) 157 return -ENODEV; 158 159 rc = -EINVAL; 160 if (attr->mmap) 161 rc = attr->mmap(kobj, attr, vma); 162 163 if (rc == 0 && !bb->mmapped) 164 bb->mmapped = 1; 165 else 166 sysfs_put_active_two(attr_sd); 167 168 mutex_unlock(&bb->mutex); 169 170 return rc; 171} 172 173static int open(struct inode * inode, struct file * file) 174{ 175 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; 176 struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; 177 struct bin_buffer *bb = NULL; 178 int error; 179 180 /* binary file operations requires both @sd and its parent */ 181 if (!sysfs_get_active_two(attr_sd)) 182 return -ENODEV; 183 184 error = -EACCES; 185 if ((file->f_mode & FMODE_WRITE) && !(attr->write || attr->mmap)) 186 goto err_out; 187 if ((file->f_mode & FMODE_READ) && !(attr->read || attr->mmap)) 188 goto err_out; 189 190 error = -ENOMEM; 191 bb = kzalloc(sizeof(*bb), GFP_KERNEL); 192 if (!bb) 193 goto err_out; 194 195 bb->buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); 196 if (!bb->buffer) 197 goto err_out; 198 199 mutex_init(&bb->mutex); 200 file->private_data = bb; 201 202 /* open succeeded, put active references */ 203 sysfs_put_active_two(attr_sd); 204 return 0; 205 206 err_out: 207 sysfs_put_active_two(attr_sd); 208 kfree(bb); 209 return error; 210} 211 212static int release(struct inode * inode, struct file * file) 213{ 214 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; 215 struct bin_buffer *bb = file->private_data; 216 217 if (bb->mmapped) 218 sysfs_put_active_two(attr_sd); 219 kfree(bb->buffer); 220 kfree(bb); 221 return 0; 222} 223 224const struct file_operations bin_fops = { 225 .read = read, 226 .write = write, 227 .mmap = mmap, 228 .llseek = generic_file_llseek, 229 .open = open, 230 .release = release, 231}; 232 233/** 234 * sysfs_create_bin_file - create binary file for object. 235 * @kobj: object. 236 * @attr: attribute descriptor. 237 */ 238 239int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr) 240{ 241 BUG_ON(!kobj || !kobj->sd || !attr); 242 243 return sysfs_add_file(kobj->sd, &attr->attr, SYSFS_KOBJ_BIN_ATTR); 244} 245 246 247/** 248 * sysfs_remove_bin_file - remove binary file for object. 249 * @kobj: object. 250 * @attr: attribute descriptor. 251 */ 252 253void sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr) 254{ 255 sysfs_hash_and_remove(kobj->sd, attr->attr.name); 256} 257 258EXPORT_SYMBOL_GPL(sysfs_create_bin_file); 259EXPORT_SYMBOL_GPL(sysfs_remove_bin_file);