summaryrefslogtreecommitdiffstats
path: root/fs/sysfs/file.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2013-11-28 14:54:21 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-11-29 20:35:05 -0500
commitf6acf8bb6a40ba3bfcf542e4c4c9e8968c8cb57a (patch)
tree63a9a946dd065f636a20a9435e2e502313bef178 /fs/sysfs/file.c
parentdd8a5b036b6e8d50854e130555f90f062c5eacec (diff)
sysfs, kernfs: introduce kernfs_ops
We're in the process of separating out core sysfs functionality into kernfs which will deal with sysfs_dirents directly. This patch introduces kernfs_ops which hosts methods kernfs users implement and updates fs/sysfs/file.c such that sysfs_kf_*() functions populate kernfs_ops and kernfs_file_*() functions call the matching entries from kernfs_ops. kernfs_ops contains the following groups of methods. * seq_show() - for kernfs files which use seq_file for reads. * read() - for direct read implementations. Used iff seq_show() is not implemented. * write() - for writes. * mmap() - for mmaps. Notes: * sysfs_elem_attr->ops is added so that kernfs_ops can be accessed from sysfs_dirent. kernfs_ops() helper is added to verify locking and access the field. * SYSFS_FLAG_HAS_(SEQ_SHOW|MMAP) added. sd->s_attr->ops is accessible only while holding active_ref and there are cases where we want to take different actions depending on which ops are implemented. These two flags cache whether the two ops are implemented for those. * kernfs_file_*() no longer test sysfs type but chooses different behaviors depending on which methods in kernfs_ops are implemented. The conversions are trivial except for the open path. As kernfs_file_open() now decides whether to allow read/write accesses depending on the kernfs_ops implemented, the presence of methods in kobjs and attribute_bin should be propagated to kernfs_ops. sysfs_add_file_mode_ns() is updated so that it propagates presence / absence of the callbacks through _empty, _ro, _wo, _rw kernfs_ops. Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/sysfs/file.c')
-rw-r--r--fs/sysfs/file.c146
1 files changed, 112 insertions, 34 deletions
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index acba5835577e..cbebc335af8c 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -58,6 +58,17 @@ static struct sysfs_open_file *sysfs_of(struct file *file)
58} 58}
59 59
60/* 60/*
61 * Determine the kernfs_ops for the given sysfs_dirent. This function must
62 * be called while holding an active reference.
63 */
64static const struct kernfs_ops *kernfs_ops(struct sysfs_dirent *sd)
65{
66 if (!sysfs_ignore_lockdep(sd))
67 lockdep_assert_held(sd);
68 return sd->s_attr.ops;
69}
70
71/*
61 * Determine ktype->sysfs_ops for the given sysfs_dirent. This function 72 * Determine ktype->sysfs_ops for the given sysfs_dirent. This function
62 * must be called while holding an active reference. 73 * must be called while holding an active reference.
63 */ 74 */
@@ -180,7 +191,7 @@ static int kernfs_seq_show(struct seq_file *sf, void *v)
180 191
181 of->event = atomic_read(&of->sd->s_attr.open->event); 192 of->event = atomic_read(&of->sd->s_attr.open->event);
182 193
183 return sysfs_kf_seq_show(sf, v); 194 return of->sd->s_attr.ops->seq_show(sf, v);
184} 195}
185 196
186static const struct seq_operations kernfs_seq_ops = { 197static const struct seq_operations kernfs_seq_ops = {
@@ -201,6 +212,7 @@ static ssize_t kernfs_file_direct_read(struct sysfs_open_file *of,
201 loff_t *ppos) 212 loff_t *ppos)
202{ 213{
203 ssize_t len = min_t(size_t, count, PAGE_SIZE); 214 ssize_t len = min_t(size_t, count, PAGE_SIZE);
215 const struct kernfs_ops *ops;
204 char *buf; 216 char *buf;
205 217
206 buf = kmalloc(len, GFP_KERNEL); 218 buf = kmalloc(len, GFP_KERNEL);
@@ -218,7 +230,11 @@ static ssize_t kernfs_file_direct_read(struct sysfs_open_file *of,
218 goto out_free; 230 goto out_free;
219 } 231 }
220 232
221 len = sysfs_kf_bin_read(of, buf, len, *ppos); 233 ops = kernfs_ops(of->sd);
234 if (ops->read)
235 len = ops->read(of, buf, len, *ppos);
236 else
237 len = -EINVAL;
222 238
223 sysfs_put_active(of->sd); 239 sysfs_put_active(of->sd);
224 mutex_unlock(&of->mutex); 240 mutex_unlock(&of->mutex);
@@ -250,10 +266,10 @@ static ssize_t kernfs_file_read(struct file *file, char __user *user_buf,
250{ 266{
251 struct sysfs_open_file *of = sysfs_of(file); 267 struct sysfs_open_file *of = sysfs_of(file);
252 268
253 if (sysfs_is_bin(of->sd)) 269 if (of->sd->s_flags & SYSFS_FLAG_HAS_SEQ_SHOW)
254 return kernfs_file_direct_read(of, user_buf, count, ppos);
255 else
256 return seq_read(file, user_buf, count, ppos); 270 return seq_read(file, user_buf, count, ppos);
271 else
272 return kernfs_file_direct_read(of, user_buf, count, ppos);
257} 273}
258 274
259/* kernfs write callback for regular sysfs files */ 275/* kernfs write callback for regular sysfs files */
@@ -312,6 +328,7 @@ static ssize_t kernfs_file_write(struct file *file, const char __user *user_buf,
312{ 328{
313 struct sysfs_open_file *of = sysfs_of(file); 329 struct sysfs_open_file *of = sysfs_of(file);
314 ssize_t len = min_t(size_t, count, PAGE_SIZE); 330 ssize_t len = min_t(size_t, count, PAGE_SIZE);
331 const struct kernfs_ops *ops;
315 char *buf; 332 char *buf;
316 333
317 buf = kmalloc(len + 1, GFP_KERNEL); 334 buf = kmalloc(len + 1, GFP_KERNEL);
@@ -335,10 +352,11 @@ static ssize_t kernfs_file_write(struct file *file, const char __user *user_buf,
335 goto out_free; 352 goto out_free;
336 } 353 }
337 354
338 if (sysfs_is_bin(of->sd)) 355 ops = kernfs_ops(of->sd);
339 len = sysfs_kf_bin_write(of, buf, len, *ppos); 356 if (ops->write)
357 len = ops->write(of, buf, len, *ppos);
340 else 358 else
341 len = sysfs_kf_write(of, buf, len, *ppos); 359 len = -EINVAL;
342 360
343 sysfs_put_active(of->sd); 361 sysfs_put_active(of->sd);
344 mutex_unlock(&of->mutex); 362 mutex_unlock(&of->mutex);
@@ -524,6 +542,7 @@ static const struct vm_operations_struct kernfs_vm_ops = {
524static int kernfs_file_mmap(struct file *file, struct vm_area_struct *vma) 542static int kernfs_file_mmap(struct file *file, struct vm_area_struct *vma)
525{ 543{
526 struct sysfs_open_file *of = sysfs_of(file); 544 struct sysfs_open_file *of = sysfs_of(file);
545 const struct kernfs_ops *ops;
527 int rc; 546 int rc;
528 547
529 mutex_lock(&of->mutex); 548 mutex_lock(&of->mutex);
@@ -532,8 +551,9 @@ static int kernfs_file_mmap(struct file *file, struct vm_area_struct *vma)
532 if (!sysfs_get_active(of->sd)) 551 if (!sysfs_get_active(of->sd))
533 goto out_unlock; 552 goto out_unlock;
534 553
535 if (sysfs_is_bin(of->sd)) 554 ops = kernfs_ops(of->sd);
536 rc = sysfs_kf_bin_mmap(of, vma); 555 if (ops->mmap)
556 rc = ops->mmap(of, vma);
537 if (rc) 557 if (rc)
538 goto out_put; 558 goto out_put;
539 559
@@ -660,34 +680,19 @@ static void sysfs_put_open_dirent(struct sysfs_dirent *sd,
660static int kernfs_file_open(struct inode *inode, struct file *file) 680static int kernfs_file_open(struct inode *inode, struct file *file)
661{ 681{
662 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; 682 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
663 struct kobject *kobj = attr_sd->s_parent->priv; 683 const struct kernfs_ops *ops;
664 struct sysfs_open_file *of; 684 struct sysfs_open_file *of;
665 bool has_read, has_write, has_mmap; 685 bool has_read, has_write, has_mmap;
666 int error = -EACCES; 686 int error = -EACCES;
667 687
668 /* need attr_sd for attr and ops, its parent for kobj */
669 if (!sysfs_get_active(attr_sd)) 688 if (!sysfs_get_active(attr_sd))
670 return -ENODEV; 689 return -ENODEV;
671 690
672 if (sysfs_is_bin(attr_sd)) { 691 ops = kernfs_ops(attr_sd);
673 struct bin_attribute *battr = attr_sd->priv;
674 692
675 has_read = battr->read || battr->mmap; 693 has_read = ops->seq_show || ops->read || ops->mmap;
676 has_write = battr->write || battr->mmap; 694 has_write = ops->write || ops->mmap;
677 has_mmap = battr->mmap; 695 has_mmap = ops->mmap;
678 } else {
679 const struct sysfs_ops *ops = sysfs_file_ops(attr_sd);
680
681 /* every kobject with an attribute needs a ktype assigned */
682 if (WARN(!ops, KERN_ERR
683 "missing sysfs attribute operations for kobject: %s\n",
684 kobject_name(kobj)))
685 goto err_out;
686
687 has_read = ops->show;
688 has_write = ops->store;
689 has_mmap = false;
690 }
691 696
692 /* check perms and supported operations */ 697 /* check perms and supported operations */
693 if ((file->f_mode & FMODE_WRITE) && 698 if ((file->f_mode & FMODE_WRITE) &&
@@ -729,10 +734,10 @@ static int kernfs_file_open(struct inode *inode, struct file *file)
729 * seq_file or is not requested. This unifies private data access 734 * seq_file or is not requested. This unifies private data access
730 * and readable regular files are the vast majority anyway. 735 * and readable regular files are the vast majority anyway.
731 */ 736 */
732 if (sysfs_is_bin(attr_sd)) 737 if (ops->seq_show)
733 error = seq_open(file, NULL);
734 else
735 error = seq_open(file, &kernfs_seq_ops); 738 error = seq_open(file, &kernfs_seq_ops);
739 else
740 error = seq_open(file, NULL);
736 if (error) 741 if (error)
737 goto err_free; 742 goto err_free;
738 743
@@ -777,7 +782,7 @@ void sysfs_unmap_bin_file(struct sysfs_dirent *sd)
777 struct sysfs_open_dirent *od; 782 struct sysfs_open_dirent *od;
778 struct sysfs_open_file *of; 783 struct sysfs_open_file *of;
779 784
780 if (!sysfs_is_bin(sd)) 785 if (!(sd->s_flags & SYSFS_FLAG_HAS_MMAP))
781 return; 786 return;
782 787
783 spin_lock_irq(&sysfs_open_dirent_lock); 788 spin_lock_irq(&sysfs_open_dirent_lock);
@@ -880,23 +885,96 @@ const struct file_operations kernfs_file_operations = {
880 .poll = kernfs_file_poll, 885 .poll = kernfs_file_poll,
881}; 886};
882 887
888static const struct kernfs_ops sysfs_file_kfops_empty = {
889};
890
891static const struct kernfs_ops sysfs_file_kfops_ro = {
892 .seq_show = sysfs_kf_seq_show,
893};
894
895static const struct kernfs_ops sysfs_file_kfops_wo = {
896 .write = sysfs_kf_write,
897};
898
899static const struct kernfs_ops sysfs_file_kfops_rw = {
900 .seq_show = sysfs_kf_seq_show,
901 .write = sysfs_kf_write,
902};
903
904static const struct kernfs_ops sysfs_bin_kfops_ro = {
905 .read = sysfs_kf_bin_read,
906};
907
908static const struct kernfs_ops sysfs_bin_kfops_wo = {
909 .write = sysfs_kf_bin_write,
910};
911
912static const struct kernfs_ops sysfs_bin_kfops_rw = {
913 .read = sysfs_kf_bin_read,
914 .write = sysfs_kf_bin_write,
915 .mmap = sysfs_kf_bin_mmap,
916};
917
883int sysfs_add_file_mode_ns(struct sysfs_dirent *dir_sd, 918int sysfs_add_file_mode_ns(struct sysfs_dirent *dir_sd,
884 const struct attribute *attr, int type, 919 const struct attribute *attr, int type,
885 umode_t amode, const void *ns) 920 umode_t amode, const void *ns)
886{ 921{
887 umode_t mode = (amode & S_IALLUGO) | S_IFREG; 922 umode_t mode = (amode & S_IALLUGO) | S_IFREG;
923 const struct kernfs_ops *ops;
888 struct sysfs_addrm_cxt acxt; 924 struct sysfs_addrm_cxt acxt;
889 struct sysfs_dirent *sd; 925 struct sysfs_dirent *sd;
890 int rc; 926 int rc;
891 927
928 if (type == SYSFS_KOBJ_ATTR) {
929 struct kobject *kobj = dir_sd->priv;
930 const struct sysfs_ops *sysfs_ops = kobj->ktype->sysfs_ops;
931
932 /* every kobject with an attribute needs a ktype assigned */
933 if (WARN(!sysfs_ops, KERN_ERR
934 "missing sysfs attribute operations for kobject: %s\n",
935 kobject_name(kobj)))
936 return -EINVAL;
937
938 if (sysfs_ops->show && sysfs_ops->store)
939 ops = &sysfs_file_kfops_rw;
940 else if (sysfs_ops->show)
941 ops = &sysfs_file_kfops_ro;
942 else if (sysfs_ops->store)
943 ops = &sysfs_file_kfops_wo;
944 else
945 ops = &sysfs_file_kfops_empty;
946 } else {
947 struct bin_attribute *battr = (void *)attr;
948
949 if ((battr->read && battr->write) || battr->mmap)
950 ops = &sysfs_bin_kfops_rw;
951 else if (battr->read)
952 ops = &sysfs_bin_kfops_ro;
953 else if (battr->write)
954 ops = &sysfs_bin_kfops_wo;
955 else
956 ops = &sysfs_file_kfops_empty;
957 }
958
892 sd = sysfs_new_dirent(attr->name, mode, type); 959 sd = sysfs_new_dirent(attr->name, mode, type);
893 if (!sd) 960 if (!sd)
894 return -ENOMEM; 961 return -ENOMEM;
895 962
963 sd->s_attr.ops = ops;
896 sd->s_ns = ns; 964 sd->s_ns = ns;
897 sd->priv = (void *)attr; 965 sd->priv = (void *)attr;
898 sysfs_dirent_init_lockdep(sd); 966 sysfs_dirent_init_lockdep(sd);
899 967
968 /*
969 * sd->s_attr.ops is accesible only while holding active ref. We
970 * need to know whether some ops are implemented outside active
971 * ref. Cache their existence in flags.
972 */
973 if (ops->seq_show)
974 sd->s_flags |= SYSFS_FLAG_HAS_SEQ_SHOW;
975 if (ops->mmap)
976 sd->s_flags |= SYSFS_FLAG_HAS_MMAP;
977
900 sysfs_addrm_start(&acxt); 978 sysfs_addrm_start(&acxt);
901 rc = sysfs_add_one(&acxt, sd, dir_sd); 979 rc = sysfs_add_one(&acxt, sd, dir_sd);
902 sysfs_addrm_finish(&acxt); 980 sysfs_addrm_finish(&acxt);