Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sysfs: copy bin mmap support from fs/sysfs/bin.c to fs/sysfs/file.c

sysfs bin file handling will be merged into the regular file support.
This patch copies mmap support from bin so that fs/sysfs/file.c can
handle mmapping bin files.

The code is copied mostly verbatim with the following updates.

* ->mmapped and ->vm_ops are added to sysfs_open_file and bin_buffer
references are replaced with sysfs_open_file ones.

* Symbols are prefixed with sysfs_.

* sysfs_unmap_bin_file() grabs sysfs_open_dirent and traverses
->files. Invocation of this function is added to
sysfs_addrm_finish().

* sysfs_bin_mmap() is added to sysfs_bin_operations.

This is a preparation and the new mmap path isn't used yet.

Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Tejun Heo and committed by
Greg Kroah-Hartman
73d97146 2f0c6b75

+249 -1
+1
fs/sysfs/dir.c
··· 595 595 acxt->removed = sd->u.removed_list; 596 596 597 597 sysfs_deactivate(sd); 598 + sysfs_unmap_bin_file(sd); 598 599 unmap_bin_file(sd); 599 600 sysfs_put(sd); 600 601 }
+246 -1
fs/sysfs/file.c
··· 22 22 #include <linux/limits.h> 23 23 #include <linux/uaccess.h> 24 24 #include <linux/seq_file.h> 25 + #include <linux/mm.h> 25 26 26 27 #include "sysfs.h" 27 28 ··· 53 52 struct mutex mutex; 54 53 int event; 55 54 struct list_head list; 55 + 56 + bool mmapped; 57 + const struct vm_operations_struct *vm_ops; 56 58 }; 57 59 58 60 static bool sysfs_is_bin(struct sysfs_dirent *sd) ··· 305 301 return len; 306 302 } 307 303 304 + static void sysfs_bin_vma_open(struct vm_area_struct *vma) 305 + { 306 + struct file *file = vma->vm_file; 307 + struct sysfs_open_file *of = sysfs_of(file); 308 + 309 + if (!of->vm_ops) 310 + return; 311 + 312 + if (!sysfs_get_active(of->sd)) 313 + return; 314 + 315 + if (of->vm_ops->open) 316 + of->vm_ops->open(vma); 317 + 318 + sysfs_put_active(of->sd); 319 + } 320 + 321 + static int sysfs_bin_fault(struct vm_area_struct *vma, struct vm_fault *vmf) 322 + { 323 + struct file *file = vma->vm_file; 324 + struct sysfs_open_file *of = sysfs_of(file); 325 + int ret; 326 + 327 + if (!of->vm_ops) 328 + return VM_FAULT_SIGBUS; 329 + 330 + if (!sysfs_get_active(of->sd)) 331 + return VM_FAULT_SIGBUS; 332 + 333 + ret = VM_FAULT_SIGBUS; 334 + if (of->vm_ops->fault) 335 + ret = of->vm_ops->fault(vma, vmf); 336 + 337 + sysfs_put_active(of->sd); 338 + return ret; 339 + } 340 + 341 + static int sysfs_bin_page_mkwrite(struct vm_area_struct *vma, 342 + struct vm_fault *vmf) 343 + { 344 + struct file *file = vma->vm_file; 345 + struct sysfs_open_file *of = sysfs_of(file); 346 + int ret; 347 + 348 + if (!of->vm_ops) 349 + return VM_FAULT_SIGBUS; 350 + 351 + if (!sysfs_get_active(of->sd)) 352 + return VM_FAULT_SIGBUS; 353 + 354 + ret = 0; 355 + if (of->vm_ops->page_mkwrite) 356 + ret = of->vm_ops->page_mkwrite(vma, vmf); 357 + else 358 + file_update_time(file); 359 + 360 + sysfs_put_active(of->sd); 361 + return ret; 362 + } 363 + 364 + static int sysfs_bin_access(struct vm_area_struct *vma, unsigned long addr, 365 + void *buf, int len, int write) 366 + { 367 + struct file *file = vma->vm_file; 368 + struct sysfs_open_file *of = sysfs_of(file); 369 + int ret; 370 + 371 + if (!of->vm_ops) 372 + return -EINVAL; 373 + 374 + if (!sysfs_get_active(of->sd)) 375 + return -EINVAL; 376 + 377 + ret = -EINVAL; 378 + if (of->vm_ops->access) 379 + ret = of->vm_ops->access(vma, addr, buf, len, write); 380 + 381 + sysfs_put_active(of->sd); 382 + return ret; 383 + } 384 + 385 + #ifdef CONFIG_NUMA 386 + static int sysfs_bin_set_policy(struct vm_area_struct *vma, 387 + struct mempolicy *new) 388 + { 389 + struct file *file = vma->vm_file; 390 + struct sysfs_open_file *of = sysfs_of(file); 391 + int ret; 392 + 393 + if (!of->vm_ops) 394 + return 0; 395 + 396 + if (!sysfs_get_active(of->sd)) 397 + return -EINVAL; 398 + 399 + ret = 0; 400 + if (of->vm_ops->set_policy) 401 + ret = of->vm_ops->set_policy(vma, new); 402 + 403 + sysfs_put_active(of->sd); 404 + return ret; 405 + } 406 + 407 + static struct mempolicy *sysfs_bin_get_policy(struct vm_area_struct *vma, 408 + unsigned long addr) 409 + { 410 + struct file *file = vma->vm_file; 411 + struct sysfs_open_file *of = sysfs_of(file); 412 + struct mempolicy *pol; 413 + 414 + if (!of->vm_ops) 415 + return vma->vm_policy; 416 + 417 + if (!sysfs_get_active(of->sd)) 418 + return vma->vm_policy; 419 + 420 + pol = vma->vm_policy; 421 + if (of->vm_ops->get_policy) 422 + pol = of->vm_ops->get_policy(vma, addr); 423 + 424 + sysfs_put_active(of->sd); 425 + return pol; 426 + } 427 + 428 + static int sysfs_bin_migrate(struct vm_area_struct *vma, const nodemask_t *from, 429 + const nodemask_t *to, unsigned long flags) 430 + { 431 + struct file *file = vma->vm_file; 432 + struct sysfs_open_file *of = sysfs_of(file); 433 + int ret; 434 + 435 + if (!of->vm_ops) 436 + return 0; 437 + 438 + if (!sysfs_get_active(of->sd)) 439 + return 0; 440 + 441 + ret = 0; 442 + if (of->vm_ops->migrate) 443 + ret = of->vm_ops->migrate(vma, from, to, flags); 444 + 445 + sysfs_put_active(of->sd); 446 + return ret; 447 + } 448 + #endif 449 + 450 + static const struct vm_operations_struct sysfs_bin_vm_ops = { 451 + .open = sysfs_bin_vma_open, 452 + .fault = sysfs_bin_fault, 453 + .page_mkwrite = sysfs_bin_page_mkwrite, 454 + .access = sysfs_bin_access, 455 + #ifdef CONFIG_NUMA 456 + .set_policy = sysfs_bin_set_policy, 457 + .get_policy = sysfs_bin_get_policy, 458 + .migrate = sysfs_bin_migrate, 459 + #endif 460 + }; 461 + 462 + static int sysfs_bin_mmap(struct file *file, struct vm_area_struct *vma) 463 + { 464 + struct sysfs_open_file *of = sysfs_of(file); 465 + struct bin_attribute *battr = of->sd->s_bin_attr.bin_attr; 466 + struct kobject *kobj = of->sd->s_parent->s_dir.kobj; 467 + int rc; 468 + 469 + mutex_lock(&of->mutex); 470 + 471 + /* need of->sd for battr, its parent for kobj */ 472 + rc = -ENODEV; 473 + if (!sysfs_get_active(of->sd)) 474 + goto out_unlock; 475 + 476 + rc = -EINVAL; 477 + if (!battr->mmap) 478 + goto out_put; 479 + 480 + rc = battr->mmap(file, kobj, battr, vma); 481 + if (rc) 482 + goto out_put; 483 + 484 + /* 485 + * PowerPC's pci_mmap of legacy_mem uses shmem_zero_setup() 486 + * to satisfy versions of X which crash if the mmap fails: that 487 + * substitutes a new vm_file, and we don't then want bin_vm_ops. 488 + */ 489 + if (vma->vm_file != file) 490 + goto out_put; 491 + 492 + rc = -EINVAL; 493 + if (of->mmapped && of->vm_ops != vma->vm_ops) 494 + goto out_put; 495 + 496 + /* 497 + * It is not possible to successfully wrap close. 498 + * So error if someone is trying to use close. 499 + */ 500 + rc = -EINVAL; 501 + if (vma->vm_ops && vma->vm_ops->close) 502 + goto out_put; 503 + 504 + rc = 0; 505 + of->mmapped = 1; 506 + of->vm_ops = vma->vm_ops; 507 + vma->vm_ops = &sysfs_bin_vm_ops; 508 + out_put: 509 + sysfs_put_active(of->sd); 510 + out_unlock: 511 + mutex_unlock(&of->mutex); 512 + 513 + return rc; 514 + } 515 + 308 516 /** 309 517 * sysfs_get_open_dirent - get or create sysfs_open_dirent 310 518 * @sd: target sysfs_dirent ··· 591 375 mutex_lock(&sysfs_open_file_mutex); 592 376 spin_lock_irqsave(&sysfs_open_dirent_lock, flags); 593 377 594 - list_del(&of->list); 378 + if (of) 379 + list_del(&of->list); 380 + 595 381 if (atomic_dec_and_test(&od->refcnt)) 596 382 sd->s_attr.open = NULL; 597 383 else ··· 695 477 return 0; 696 478 } 697 479 480 + void sysfs_unmap_bin_file(struct sysfs_dirent *sd) 481 + { 482 + struct sysfs_open_dirent *od; 483 + struct sysfs_open_file *of; 484 + 485 + if (!sysfs_is_bin(sd)) 486 + return; 487 + 488 + spin_lock_irq(&sysfs_open_dirent_lock); 489 + od = sd->s_attr.open; 490 + if (od) 491 + atomic_inc(&od->refcnt); 492 + spin_unlock_irq(&sysfs_open_dirent_lock); 493 + if (!od) 494 + return; 495 + 496 + mutex_lock(&sysfs_open_file_mutex); 497 + list_for_each_entry(of, &od->files, list) { 498 + struct inode *inode = file_inode(of->file); 499 + unmap_mapping_range(inode->i_mapping, 0, 0, 1); 500 + } 501 + mutex_unlock(&sysfs_open_file_mutex); 502 + 503 + sysfs_put_open_dirent(sd, NULL); 504 + } 505 + 698 506 /* Sysfs attribute files are pollable. The idea is that you read 699 507 * the content and then you use 'poll' or 'select' to wait for 700 508 * the content to change. When the content changes (assuming the ··· 806 562 .read = sysfs_bin_read, 807 563 .write = sysfs_write_file, 808 564 .llseek = generic_file_llseek, 565 + .mmap = sysfs_bin_mmap, 809 566 }; 810 567 811 568 int sysfs_add_file_mode_ns(struct sysfs_dirent *dir_sd,
+2
fs/sysfs/sysfs.h
··· 220 220 int sysfs_add_file_mode_ns(struct sysfs_dirent *dir_sd, 221 221 const struct attribute *attr, int type, 222 222 umode_t amode, const void *ns); 223 + void sysfs_unmap_bin_file(struct sysfs_dirent *sd); 224 + 223 225 /* 224 226 * bin.c 225 227 */