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