Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.30-rc2 512 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 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 = kmalloc(count, GFP_KERNEL); 161 if (!temp) 162 return -ENOMEM; 163 164 if (copy_from_user(temp, userbuf, count)) { 165 count = -EFAULT; 166 goto out_free; 167 } 168 169 mutex_lock(&bb->mutex); 170 171 memcpy(bb->buffer, temp, count); 172 173 count = flush_write(dentry, bb->buffer, offs, count); 174 mutex_unlock(&bb->mutex); 175 176 if (count > 0) 177 *off = offs + count; 178 179out_free: 180 kfree(temp); 181 return count; 182} 183 184static void bin_vma_open(struct vm_area_struct *vma) 185{ 186 struct file *file = vma->vm_file; 187 struct bin_buffer *bb = file->private_data; 188 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; 189 190 if (!bb->vm_ops || !bb->vm_ops->open) 191 return; 192 193 if (!sysfs_get_active_two(attr_sd)) 194 return; 195 196 bb->vm_ops->open(vma); 197 198 sysfs_put_active_two(attr_sd); 199} 200 201static void bin_vma_close(struct vm_area_struct *vma) 202{ 203 struct file *file = vma->vm_file; 204 struct bin_buffer *bb = file->private_data; 205 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; 206 207 if (!bb->vm_ops || !bb->vm_ops->close) 208 return; 209 210 if (!sysfs_get_active_two(attr_sd)) 211 return; 212 213 bb->vm_ops->close(vma); 214 215 sysfs_put_active_two(attr_sd); 216} 217 218static int bin_fault(struct vm_area_struct *vma, struct vm_fault *vmf) 219{ 220 struct file *file = vma->vm_file; 221 struct bin_buffer *bb = file->private_data; 222 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; 223 int ret; 224 225 if (!bb->vm_ops || !bb->vm_ops->fault) 226 return VM_FAULT_SIGBUS; 227 228 if (!sysfs_get_active_two(attr_sd)) 229 return VM_FAULT_SIGBUS; 230 231 ret = bb->vm_ops->fault(vma, vmf); 232 233 sysfs_put_active_two(attr_sd); 234 return ret; 235} 236 237static int bin_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) 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 VM_FAULT_SIGBUS; 246 247 if (!bb->vm_ops->page_mkwrite) 248 return 0; 249 250 if (!sysfs_get_active_two(attr_sd)) 251 return VM_FAULT_SIGBUS; 252 253 ret = bb->vm_ops->page_mkwrite(vma, vmf); 254 255 sysfs_put_active_two(attr_sd); 256 return ret; 257} 258 259static int bin_access(struct vm_area_struct *vma, unsigned long addr, 260 void *buf, int len, int write) 261{ 262 struct file *file = vma->vm_file; 263 struct bin_buffer *bb = file->private_data; 264 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; 265 int ret; 266 267 if (!bb->vm_ops || !bb->vm_ops->access) 268 return -EINVAL; 269 270 if (!sysfs_get_active_two(attr_sd)) 271 return -EINVAL; 272 273 ret = bb->vm_ops->access(vma, addr, buf, len, write); 274 275 sysfs_put_active_two(attr_sd); 276 return ret; 277} 278 279#ifdef CONFIG_NUMA 280static int bin_set_policy(struct vm_area_struct *vma, struct mempolicy *new) 281{ 282 struct file *file = vma->vm_file; 283 struct bin_buffer *bb = file->private_data; 284 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; 285 int ret; 286 287 if (!bb->vm_ops || !bb->vm_ops->set_policy) 288 return 0; 289 290 if (!sysfs_get_active_two(attr_sd)) 291 return -EINVAL; 292 293 ret = bb->vm_ops->set_policy(vma, new); 294 295 sysfs_put_active_two(attr_sd); 296 return ret; 297} 298 299static struct mempolicy *bin_get_policy(struct vm_area_struct *vma, 300 unsigned long addr) 301{ 302 struct file *file = vma->vm_file; 303 struct bin_buffer *bb = file->private_data; 304 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; 305 struct mempolicy *pol; 306 307 if (!bb->vm_ops || !bb->vm_ops->get_policy) 308 return vma->vm_policy; 309 310 if (!sysfs_get_active_two(attr_sd)) 311 return vma->vm_policy; 312 313 pol = bb->vm_ops->get_policy(vma, addr); 314 315 sysfs_put_active_two(attr_sd); 316 return pol; 317} 318 319static int bin_migrate(struct vm_area_struct *vma, const nodemask_t *from, 320 const nodemask_t *to, unsigned long flags) 321{ 322 struct file *file = vma->vm_file; 323 struct bin_buffer *bb = file->private_data; 324 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; 325 int ret; 326 327 if (!bb->vm_ops || !bb->vm_ops->migrate) 328 return 0; 329 330 if (!sysfs_get_active_two(attr_sd)) 331 return 0; 332 333 ret = bb->vm_ops->migrate(vma, from, to, flags); 334 335 sysfs_put_active_two(attr_sd); 336 return ret; 337} 338#endif 339 340static struct vm_operations_struct bin_vm_ops = { 341 .open = bin_vma_open, 342 .close = bin_vma_close, 343 .fault = bin_fault, 344 .page_mkwrite = bin_page_mkwrite, 345 .access = bin_access, 346#ifdef CONFIG_NUMA 347 .set_policy = bin_set_policy, 348 .get_policy = bin_get_policy, 349 .migrate = bin_migrate, 350#endif 351}; 352 353static int mmap(struct file *file, struct vm_area_struct *vma) 354{ 355 struct bin_buffer *bb = file->private_data; 356 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; 357 struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; 358 struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; 359 int rc; 360 361 mutex_lock(&bb->mutex); 362 363 /* need attr_sd for attr, its parent for kobj */ 364 rc = -ENODEV; 365 if (!sysfs_get_active_two(attr_sd)) 366 goto out_unlock; 367 368 rc = -EINVAL; 369 if (!attr->mmap) 370 goto out_put; 371 372 rc = attr->mmap(kobj, attr, vma); 373 if (rc) 374 goto out_put; 375 376 /* 377 * PowerPC's pci_mmap of legacy_mem uses shmem_zero_setup() 378 * to satisfy versions of X which crash if the mmap fails: that 379 * substitutes a new vm_file, and we don't then want bin_vm_ops. 380 */ 381 if (vma->vm_file != file) 382 goto out_put; 383 384 rc = -EINVAL; 385 if (bb->mmapped && bb->vm_ops != vma->vm_ops) 386 goto out_put; 387 388 rc = 0; 389 bb->mmapped = 1; 390 bb->vm_ops = vma->vm_ops; 391 vma->vm_ops = &bin_vm_ops; 392out_put: 393 sysfs_put_active_two(attr_sd); 394out_unlock: 395 mutex_unlock(&bb->mutex); 396 397 return rc; 398} 399 400static int open(struct inode * inode, struct file * file) 401{ 402 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; 403 struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; 404 struct bin_buffer *bb = NULL; 405 int error; 406 407 /* binary file operations requires both @sd and its parent */ 408 if (!sysfs_get_active_two(attr_sd)) 409 return -ENODEV; 410 411 error = -EACCES; 412 if ((file->f_mode & FMODE_WRITE) && !(attr->write || attr->mmap)) 413 goto err_out; 414 if ((file->f_mode & FMODE_READ) && !(attr->read || attr->mmap)) 415 goto err_out; 416 417 error = -ENOMEM; 418 bb = kzalloc(sizeof(*bb), GFP_KERNEL); 419 if (!bb) 420 goto err_out; 421 422 bb->buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); 423 if (!bb->buffer) 424 goto err_out; 425 426 mutex_init(&bb->mutex); 427 bb->file = file; 428 file->private_data = bb; 429 430 mutex_lock(&sysfs_bin_lock); 431 hlist_add_head(&bb->list, &attr_sd->s_bin_attr.buffers); 432 mutex_unlock(&sysfs_bin_lock); 433 434 /* open succeeded, put active references */ 435 sysfs_put_active_two(attr_sd); 436 return 0; 437 438 err_out: 439 sysfs_put_active_two(attr_sd); 440 kfree(bb); 441 return error; 442} 443 444static int release(struct inode * inode, struct file * file) 445{ 446 struct bin_buffer *bb = file->private_data; 447 448 mutex_lock(&sysfs_bin_lock); 449 hlist_del(&bb->list); 450 mutex_unlock(&sysfs_bin_lock); 451 452 kfree(bb->buffer); 453 kfree(bb); 454 return 0; 455} 456 457const struct file_operations bin_fops = { 458 .read = read, 459 .write = write, 460 .mmap = mmap, 461 .llseek = generic_file_llseek, 462 .open = open, 463 .release = release, 464}; 465 466 467void unmap_bin_file(struct sysfs_dirent *attr_sd) 468{ 469 struct bin_buffer *bb; 470 struct hlist_node *tmp; 471 472 if (sysfs_type(attr_sd) != SYSFS_KOBJ_BIN_ATTR) 473 return; 474 475 mutex_lock(&sysfs_bin_lock); 476 477 hlist_for_each_entry(bb, tmp, &attr_sd->s_bin_attr.buffers, list) { 478 struct inode *inode = bb->file->f_path.dentry->d_inode; 479 480 unmap_mapping_range(inode->i_mapping, 0, 0, 1); 481 } 482 483 mutex_unlock(&sysfs_bin_lock); 484} 485 486/** 487 * sysfs_create_bin_file - create binary file for object. 488 * @kobj: object. 489 * @attr: attribute descriptor. 490 */ 491 492int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr) 493{ 494 BUG_ON(!kobj || !kobj->sd || !attr); 495 496 return sysfs_add_file(kobj->sd, &attr->attr, SYSFS_KOBJ_BIN_ATTR); 497} 498 499 500/** 501 * sysfs_remove_bin_file - remove binary file for object. 502 * @kobj: object. 503 * @attr: attribute descriptor. 504 */ 505 506void sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr) 507{ 508 sysfs_hash_and_remove(kobj->sd, attr->attr.name); 509} 510 511EXPORT_SYMBOL_GPL(sysfs_create_bin_file); 512EXPORT_SYMBOL_GPL(sysfs_remove_bin_file);