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