diff options
Diffstat (limited to 'fs/sysfs/file.c')
-rw-r--r-- | fs/sysfs/file.c | 82 |
1 files changed, 38 insertions, 44 deletions
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index d2bb7ed8fa74..15ef5eb13663 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
@@ -20,7 +20,7 @@ | |||
20 | #include <linux/list.h> | 20 | #include <linux/list.h> |
21 | #include <linux/mutex.h> | 21 | #include <linux/mutex.h> |
22 | #include <linux/limits.h> | 22 | #include <linux/limits.h> |
23 | #include <asm/uaccess.h> | 23 | #include <linux/uaccess.h> |
24 | 24 | ||
25 | #include "sysfs.h" | 25 | #include "sysfs.h" |
26 | 26 | ||
@@ -45,8 +45,8 @@ struct sysfs_open_dirent { | |||
45 | struct sysfs_buffer { | 45 | struct sysfs_buffer { |
46 | size_t count; | 46 | size_t count; |
47 | loff_t pos; | 47 | loff_t pos; |
48 | char * page; | 48 | char *page; |
49 | const struct sysfs_ops * ops; | 49 | const struct sysfs_ops *ops; |
50 | struct mutex mutex; | 50 | struct mutex mutex; |
51 | int needs_read_fill; | 51 | int needs_read_fill; |
52 | int event; | 52 | int event; |
@@ -59,16 +59,16 @@ struct sysfs_buffer { | |||
59 | * @buffer: data buffer for file. | 59 | * @buffer: data buffer for file. |
60 | * | 60 | * |
61 | * Allocate @buffer->page, if it hasn't been already, then call the | 61 | * Allocate @buffer->page, if it hasn't been already, then call the |
62 | * kobject's show() method to fill the buffer with this attribute's | 62 | * kobject's show() method to fill the buffer with this attribute's |
63 | * data. | 63 | * data. |
64 | * This is called only once, on the file's first read unless an error | 64 | * This is called only once, on the file's first read unless an error |
65 | * is returned. | 65 | * is returned. |
66 | */ | 66 | */ |
67 | static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer) | 67 | static int fill_read_buffer(struct dentry *dentry, struct sysfs_buffer *buffer) |
68 | { | 68 | { |
69 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; | 69 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; |
70 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; | 70 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; |
71 | const struct sysfs_ops * ops = buffer->ops; | 71 | const struct sysfs_ops *ops = buffer->ops; |
72 | int ret = 0; | 72 | int ret = 0; |
73 | ssize_t count; | 73 | ssize_t count; |
74 | 74 | ||
@@ -106,7 +106,7 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer | |||
106 | } | 106 | } |
107 | 107 | ||
108 | /** | 108 | /** |
109 | * sysfs_read_file - read an attribute. | 109 | * sysfs_read_file - read an attribute. |
110 | * @file: file pointer. | 110 | * @file: file pointer. |
111 | * @buf: buffer to fill. | 111 | * @buf: buffer to fill. |
112 | * @count: number of bytes to read. | 112 | * @count: number of bytes to read. |
@@ -127,12 +127,12 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer | |||
127 | static ssize_t | 127 | static ssize_t |
128 | sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos) | 128 | sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos) |
129 | { | 129 | { |
130 | struct sysfs_buffer * buffer = file->private_data; | 130 | struct sysfs_buffer *buffer = file->private_data; |
131 | ssize_t retval = 0; | 131 | ssize_t retval = 0; |
132 | 132 | ||
133 | mutex_lock(&buffer->mutex); | 133 | mutex_lock(&buffer->mutex); |
134 | if (buffer->needs_read_fill || *ppos == 0) { | 134 | if (buffer->needs_read_fill || *ppos == 0) { |
135 | retval = fill_read_buffer(file->f_path.dentry,buffer); | 135 | retval = fill_read_buffer(file->f_path.dentry, buffer); |
136 | if (retval) | 136 | if (retval) |
137 | goto out; | 137 | goto out; |
138 | } | 138 | } |
@@ -154,9 +154,8 @@ out: | |||
154 | * Allocate @buffer->page if it hasn't been already, then | 154 | * Allocate @buffer->page if it hasn't been already, then |
155 | * copy the user-supplied buffer into it. | 155 | * copy the user-supplied buffer into it. |
156 | */ | 156 | */ |
157 | 157 | static int fill_write_buffer(struct sysfs_buffer *buffer, | |
158 | static int | 158 | const char __user *buf, size_t count) |
159 | fill_write_buffer(struct sysfs_buffer * buffer, const char __user * buf, size_t count) | ||
160 | { | 159 | { |
161 | int error; | 160 | int error; |
162 | 161 | ||
@@ -167,7 +166,7 @@ fill_write_buffer(struct sysfs_buffer * buffer, const char __user * buf, size_t | |||
167 | 166 | ||
168 | if (count >= PAGE_SIZE) | 167 | if (count >= PAGE_SIZE) |
169 | count = PAGE_SIZE - 1; | 168 | count = PAGE_SIZE - 1; |
170 | error = copy_from_user(buffer->page,buf,count); | 169 | error = copy_from_user(buffer->page, buf, count); |
171 | buffer->needs_read_fill = 1; | 170 | buffer->needs_read_fill = 1; |
172 | /* if buf is assumed to contain a string, terminate it by \0, | 171 | /* if buf is assumed to contain a string, terminate it by \0, |
173 | so e.g. sscanf() can scan the string easily */ | 172 | so e.g. sscanf() can scan the string easily */ |
@@ -183,16 +182,15 @@ fill_write_buffer(struct sysfs_buffer * buffer, const char __user * buf, size_t | |||
183 | * @count: number of bytes | 182 | * @count: number of bytes |
184 | * | 183 | * |
185 | * Get the correct pointers for the kobject and the attribute we're | 184 | * Get the correct pointers for the kobject and the attribute we're |
186 | * dealing with, then call the store() method for the attribute, | 185 | * dealing with, then call the store() method for the attribute, |
187 | * passing the buffer that we acquired in fill_write_buffer(). | 186 | * passing the buffer that we acquired in fill_write_buffer(). |
188 | */ | 187 | */ |
189 | 188 | static int flush_write_buffer(struct dentry *dentry, | |
190 | static int | 189 | struct sysfs_buffer *buffer, size_t count) |
191 | flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t count) | ||
192 | { | 190 | { |
193 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; | 191 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; |
194 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; | 192 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; |
195 | const struct sysfs_ops * ops = buffer->ops; | 193 | const struct sysfs_ops *ops = buffer->ops; |
196 | int rc; | 194 | int rc; |
197 | 195 | ||
198 | /* need attr_sd for attr and ops, its parent for kobj */ | 196 | /* need attr_sd for attr and ops, its parent for kobj */ |
@@ -219,15 +217,14 @@ flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t | |||
219 | * then push it to the kobject in flush_write_buffer(). | 217 | * then push it to the kobject in flush_write_buffer(). |
220 | * There is no easy way for us to know if userspace is only doing a partial | 218 | * There is no easy way for us to know if userspace is only doing a partial |
221 | * write, so we don't support them. We expect the entire buffer to come | 219 | * write, so we don't support them. We expect the entire buffer to come |
222 | * on the first write. | 220 | * on the first write. |
223 | * Hint: if you're writing a value, first read the file, modify only the | 221 | * Hint: if you're writing a value, first read the file, modify only the |
224 | * the value you're changing, then write entire buffer back. | 222 | * the value you're changing, then write entire buffer back. |
225 | */ | 223 | */ |
226 | 224 | static ssize_t sysfs_write_file(struct file *file, const char __user *buf, | |
227 | static ssize_t | 225 | size_t count, loff_t *ppos) |
228 | sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | ||
229 | { | 226 | { |
230 | struct sysfs_buffer * buffer = file->private_data; | 227 | struct sysfs_buffer *buffer = file->private_data; |
231 | ssize_t len; | 228 | ssize_t len; |
232 | 229 | ||
233 | mutex_lock(&buffer->mutex); | 230 | mutex_lock(&buffer->mutex); |
@@ -339,13 +336,14 @@ static int sysfs_open_file(struct inode *inode, struct file *file) | |||
339 | if (kobj->ktype && kobj->ktype->sysfs_ops) | 336 | if (kobj->ktype && kobj->ktype->sysfs_ops) |
340 | ops = kobj->ktype->sysfs_ops; | 337 | ops = kobj->ktype->sysfs_ops; |
341 | else { | 338 | else { |
342 | WARN(1, KERN_ERR "missing sysfs attribute operations for " | 339 | WARN(1, KERN_ERR |
343 | "kobject: %s\n", kobject_name(kobj)); | 340 | "missing sysfs attribute operations for kobject: %s\n", |
341 | kobject_name(kobj)); | ||
344 | goto err_out; | 342 | goto err_out; |
345 | } | 343 | } |
346 | 344 | ||
347 | /* File needs write support. | 345 | /* File needs write support. |
348 | * The inode's perms must say it's ok, | 346 | * The inode's perms must say it's ok, |
349 | * and we must have a store method. | 347 | * and we must have a store method. |
350 | */ | 348 | */ |
351 | if (file->f_mode & FMODE_WRITE) { | 349 | if (file->f_mode & FMODE_WRITE) { |
@@ -420,7 +418,7 @@ static int sysfs_release(struct inode *inode, struct file *filp) | |||
420 | */ | 418 | */ |
421 | static unsigned int sysfs_poll(struct file *filp, poll_table *wait) | 419 | static unsigned int sysfs_poll(struct file *filp, poll_table *wait) |
422 | { | 420 | { |
423 | struct sysfs_buffer * buffer = filp->private_data; | 421 | struct sysfs_buffer *buffer = filp->private_data; |
424 | struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; | 422 | struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; |
425 | struct sysfs_open_dirent *od = attr_sd->s_attr.open; | 423 | struct sysfs_open_dirent *od = attr_sd->s_attr.open; |
426 | 424 | ||
@@ -518,8 +516,9 @@ static int sysfs_attr_ns(struct kobject *kobj, const struct attribute *attr, | |||
518 | ns = ops->namespace(kobj, attr); | 516 | ns = ops->namespace(kobj, attr); |
519 | out: | 517 | out: |
520 | if (err) { | 518 | if (err) { |
521 | WARN(1, KERN_ERR "missing sysfs namespace attribute operation for " | 519 | WARN(1, KERN_ERR |
522 | "kobject: %s\n", kobject_name(kobj)); | 520 | "missing sysfs namespace attribute operation for kobject: %s\n", |
521 | kobject_name(kobj)); | ||
523 | } | 522 | } |
524 | *pns = ns; | 523 | *pns = ns; |
525 | return err; | 524 | return err; |
@@ -566,17 +565,17 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, | |||
566 | 565 | ||
567 | /** | 566 | /** |
568 | * sysfs_create_file - create an attribute file for an object. | 567 | * sysfs_create_file - create an attribute file for an object. |
569 | * @kobj: object we're creating for. | 568 | * @kobj: object we're creating for. |
570 | * @attr: attribute descriptor. | 569 | * @attr: attribute descriptor. |
571 | */ | 570 | */ |
572 | 571 | int sysfs_create_file(struct kobject *kobj, const struct attribute *attr) | |
573 | int sysfs_create_file(struct kobject * kobj, const struct attribute * attr) | ||
574 | { | 572 | { |
575 | BUG_ON(!kobj || !kobj->sd || !attr); | 573 | BUG_ON(!kobj || !kobj->sd || !attr); |
576 | 574 | ||
577 | return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR); | 575 | return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR); |
578 | 576 | ||
579 | } | 577 | } |
578 | EXPORT_SYMBOL_GPL(sysfs_create_file); | ||
580 | 579 | ||
581 | int sysfs_create_files(struct kobject *kobj, const struct attribute **ptr) | 580 | int sysfs_create_files(struct kobject *kobj, const struct attribute **ptr) |
582 | { | 581 | { |
@@ -590,6 +589,7 @@ int sysfs_create_files(struct kobject *kobj, const struct attribute **ptr) | |||
590 | sysfs_remove_file(kobj, ptr[i]); | 589 | sysfs_remove_file(kobj, ptr[i]); |
591 | return err; | 590 | return err; |
592 | } | 591 | } |
592 | EXPORT_SYMBOL_GPL(sysfs_create_files); | ||
593 | 593 | ||
594 | /** | 594 | /** |
595 | * sysfs_add_file_to_group - add an attribute file to a pre-existing group. | 595 | * sysfs_add_file_to_group - add an attribute file to a pre-existing group. |
@@ -654,7 +654,6 @@ int sysfs_chmod_file(struct kobject *kobj, const struct attribute *attr, | |||
654 | } | 654 | } |
655 | EXPORT_SYMBOL_GPL(sysfs_chmod_file); | 655 | EXPORT_SYMBOL_GPL(sysfs_chmod_file); |
656 | 656 | ||
657 | |||
658 | /** | 657 | /** |
659 | * sysfs_remove_file - remove an object attribute. | 658 | * sysfs_remove_file - remove an object attribute. |
660 | * @kobj: object we're acting for. | 659 | * @kobj: object we're acting for. |
@@ -662,8 +661,7 @@ EXPORT_SYMBOL_GPL(sysfs_chmod_file); | |||
662 | * | 661 | * |
663 | * Hash the attribute name and kill the victim. | 662 | * Hash the attribute name and kill the victim. |
664 | */ | 663 | */ |
665 | 664 | void sysfs_remove_file(struct kobject *kobj, const struct attribute *attr) | |
666 | void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr) | ||
667 | { | 665 | { |
668 | const void *ns; | 666 | const void *ns; |
669 | 667 | ||
@@ -672,13 +670,15 @@ void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr) | |||
672 | 670 | ||
673 | sysfs_hash_and_remove(kobj->sd, ns, attr->name); | 671 | sysfs_hash_and_remove(kobj->sd, ns, attr->name); |
674 | } | 672 | } |
673 | EXPORT_SYMBOL_GPL(sysfs_remove_file); | ||
675 | 674 | ||
676 | void sysfs_remove_files(struct kobject * kobj, const struct attribute **ptr) | 675 | void sysfs_remove_files(struct kobject *kobj, const struct attribute **ptr) |
677 | { | 676 | { |
678 | int i; | 677 | int i; |
679 | for (i = 0; ptr[i]; i++) | 678 | for (i = 0; ptr[i]; i++) |
680 | sysfs_remove_file(kobj, ptr[i]); | 679 | sysfs_remove_file(kobj, ptr[i]); |
681 | } | 680 | } |
681 | EXPORT_SYMBOL_GPL(sysfs_remove_files); | ||
682 | 682 | ||
683 | /** | 683 | /** |
684 | * sysfs_remove_file_from_group - remove an attribute file from a group. | 684 | * sysfs_remove_file_from_group - remove an attribute file from a group. |
@@ -793,9 +793,3 @@ int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), | |||
793 | return 0; | 793 | return 0; |
794 | } | 794 | } |
795 | EXPORT_SYMBOL_GPL(sysfs_schedule_callback); | 795 | EXPORT_SYMBOL_GPL(sysfs_schedule_callback); |
796 | |||
797 | |||
798 | EXPORT_SYMBOL_GPL(sysfs_create_file); | ||
799 | EXPORT_SYMBOL_GPL(sysfs_remove_file); | ||
800 | EXPORT_SYMBOL_GPL(sysfs_remove_files); | ||
801 | EXPORT_SYMBOL_GPL(sysfs_create_files); | ||