diff options
Diffstat (limited to 'fs/sysfs/file.c')
-rw-r--r-- | fs/sysfs/file.c | 84 |
1 files changed, 25 insertions, 59 deletions
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 27d1785b7644..a271c87c4472 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
@@ -20,43 +20,6 @@ | |||
20 | 20 | ||
21 | #include "sysfs.h" | 21 | #include "sysfs.h" |
22 | 22 | ||
23 | #define to_sattr(a) container_of(a,struct subsys_attribute, attr) | ||
24 | |||
25 | /* | ||
26 | * Subsystem file operations. | ||
27 | * These operations allow subsystems to have files that can be | ||
28 | * read/written. | ||
29 | */ | ||
30 | static ssize_t | ||
31 | subsys_attr_show(struct kobject * kobj, struct attribute * attr, char * page) | ||
32 | { | ||
33 | struct kset *kset = to_kset(kobj); | ||
34 | struct subsys_attribute * sattr = to_sattr(attr); | ||
35 | ssize_t ret = -EIO; | ||
36 | |||
37 | if (sattr->show) | ||
38 | ret = sattr->show(kset, page); | ||
39 | return ret; | ||
40 | } | ||
41 | |||
42 | static ssize_t | ||
43 | subsys_attr_store(struct kobject * kobj, struct attribute * attr, | ||
44 | const char * page, size_t count) | ||
45 | { | ||
46 | struct kset *kset = to_kset(kobj); | ||
47 | struct subsys_attribute * sattr = to_sattr(attr); | ||
48 | ssize_t ret = -EIO; | ||
49 | |||
50 | if (sattr->store) | ||
51 | ret = sattr->store(kset, page, count); | ||
52 | return ret; | ||
53 | } | ||
54 | |||
55 | static struct sysfs_ops subsys_sysfs_ops = { | ||
56 | .show = subsys_attr_show, | ||
57 | .store = subsys_attr_store, | ||
58 | }; | ||
59 | |||
60 | /* | 23 | /* |
61 | * There's one sysfs_buffer for each open file and one | 24 | * There's one sysfs_buffer for each open file and one |
62 | * sysfs_open_dirent for each sysfs_dirent with one or more open | 25 | * sysfs_open_dirent for each sysfs_dirent with one or more open |
@@ -66,7 +29,7 @@ static struct sysfs_ops subsys_sysfs_ops = { | |||
66 | * sysfs_dirent->s_attr.open points to sysfs_open_dirent. s_attr.open | 29 | * sysfs_dirent->s_attr.open points to sysfs_open_dirent. s_attr.open |
67 | * is protected by sysfs_open_dirent_lock. | 30 | * is protected by sysfs_open_dirent_lock. |
68 | */ | 31 | */ |
69 | static spinlock_t sysfs_open_dirent_lock = SPIN_LOCK_UNLOCKED; | 32 | static DEFINE_SPINLOCK(sysfs_open_dirent_lock); |
70 | 33 | ||
71 | struct sysfs_open_dirent { | 34 | struct sysfs_open_dirent { |
72 | atomic_t refcnt; | 35 | atomic_t refcnt; |
@@ -119,7 +82,11 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer | |||
119 | 82 | ||
120 | sysfs_put_active_two(attr_sd); | 83 | sysfs_put_active_two(attr_sd); |
121 | 84 | ||
122 | BUG_ON(count > (ssize_t)PAGE_SIZE); | 85 | /* |
86 | * The code works fine with PAGE_SIZE return but it's likely to | ||
87 | * indicate truncated result or overflow in normal use cases. | ||
88 | */ | ||
89 | BUG_ON(count >= (ssize_t)PAGE_SIZE); | ||
123 | if (count >= 0) { | 90 | if (count >= 0) { |
124 | buffer->needs_read_fill = 0; | 91 | buffer->needs_read_fill = 0; |
125 | buffer->count = count; | 92 | buffer->count = count; |
@@ -350,31 +317,23 @@ static int sysfs_open_file(struct inode *inode, struct file *file) | |||
350 | { | 317 | { |
351 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; | 318 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; |
352 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; | 319 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; |
353 | struct sysfs_buffer * buffer; | 320 | struct sysfs_buffer *buffer; |
354 | struct sysfs_ops * ops = NULL; | 321 | struct sysfs_ops *ops; |
355 | int error; | 322 | int error = -EACCES; |
356 | 323 | ||
357 | /* need attr_sd for attr and ops, its parent for kobj */ | 324 | /* need attr_sd for attr and ops, its parent for kobj */ |
358 | if (!sysfs_get_active_two(attr_sd)) | 325 | if (!sysfs_get_active_two(attr_sd)) |
359 | return -ENODEV; | 326 | return -ENODEV; |
360 | 327 | ||
361 | /* if the kobject has no ktype, then we assume that it is a subsystem | 328 | /* every kobject with an attribute needs a ktype assigned */ |
362 | * itself, and use ops for it. | 329 | if (kobj->ktype && kobj->ktype->sysfs_ops) |
363 | */ | ||
364 | if (kobj->kset && kobj->kset->ktype) | ||
365 | ops = kobj->kset->ktype->sysfs_ops; | ||
366 | else if (kobj->ktype) | ||
367 | ops = kobj->ktype->sysfs_ops; | 330 | ops = kobj->ktype->sysfs_ops; |
368 | else | 331 | else { |
369 | ops = &subsys_sysfs_ops; | 332 | printk(KERN_ERR "missing sysfs attribute operations for " |
370 | 333 | "kobject: %s\n", kobject_name(kobj)); | |
371 | error = -EACCES; | 334 | WARN_ON(1); |
372 | |||
373 | /* No sysfs operations, either from having no subsystem, | ||
374 | * or the subsystem have no operations. | ||
375 | */ | ||
376 | if (!ops) | ||
377 | goto err_out; | 335 | goto err_out; |
336 | } | ||
378 | 337 | ||
379 | /* File needs write support. | 338 | /* File needs write support. |
380 | * The inode's perms must say it's ok, | 339 | * The inode's perms must say it's ok, |
@@ -564,7 +523,11 @@ int sysfs_add_file_to_group(struct kobject *kobj, | |||
564 | struct sysfs_dirent *dir_sd; | 523 | struct sysfs_dirent *dir_sd; |
565 | int error; | 524 | int error; |
566 | 525 | ||
567 | dir_sd = sysfs_get_dirent(kobj->sd, group); | 526 | if (group) |
527 | dir_sd = sysfs_get_dirent(kobj->sd, group); | ||
528 | else | ||
529 | dir_sd = sysfs_get(kobj->sd); | ||
530 | |||
568 | if (!dir_sd) | 531 | if (!dir_sd) |
569 | return -ENOENT; | 532 | return -ENOENT; |
570 | 533 | ||
@@ -652,7 +615,10 @@ void sysfs_remove_file_from_group(struct kobject *kobj, | |||
652 | { | 615 | { |
653 | struct sysfs_dirent *dir_sd; | 616 | struct sysfs_dirent *dir_sd; |
654 | 617 | ||
655 | dir_sd = sysfs_get_dirent(kobj->sd, group); | 618 | if (group) |
619 | dir_sd = sysfs_get_dirent(kobj->sd, group); | ||
620 | else | ||
621 | dir_sd = sysfs_get(kobj->sd); | ||
656 | if (dir_sd) { | 622 | if (dir_sd) { |
657 | sysfs_hash_and_remove(dir_sd, attr->name); | 623 | sysfs_hash_and_remove(dir_sd, attr->name); |
658 | sysfs_put(dir_sd); | 624 | sysfs_put(dir_sd); |