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