diff options
Diffstat (limited to 'fs/sysfs')
-rw-r--r-- | fs/sysfs/dir.c | 10 | ||||
-rw-r--r-- | fs/sysfs/file.c | 67 | ||||
-rw-r--r-- | fs/sysfs/symlink.c | 88 |
3 files changed, 60 insertions, 105 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 337162935d21..4948d9bc405d 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
@@ -440,7 +440,7 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | |||
440 | /** | 440 | /** |
441 | * sysfs_remove_one - remove sysfs_dirent from parent | 441 | * sysfs_remove_one - remove sysfs_dirent from parent |
442 | * @acxt: addrm context to use | 442 | * @acxt: addrm context to use |
443 | * @sd: sysfs_dirent to be added | 443 | * @sd: sysfs_dirent to be removed |
444 | * | 444 | * |
445 | * Mark @sd removed and drop nlink of parent inode if @sd is a | 445 | * Mark @sd removed and drop nlink of parent inode if @sd is a |
446 | * directory. @sd is unlinked from the children list. | 446 | * directory. @sd is unlinked from the children list. |
@@ -678,8 +678,10 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, | |||
678 | sd = sysfs_find_dirent(parent_sd, dentry->d_name.name); | 678 | sd = sysfs_find_dirent(parent_sd, dentry->d_name.name); |
679 | 679 | ||
680 | /* no such entry */ | 680 | /* no such entry */ |
681 | if (!sd) | 681 | if (!sd) { |
682 | ret = ERR_PTR(-ENOENT); | ||
682 | goto out_unlock; | 683 | goto out_unlock; |
684 | } | ||
683 | 685 | ||
684 | /* attach dentry and inode */ | 686 | /* attach dentry and inode */ |
685 | inode = sysfs_get_inode(sd); | 687 | inode = sysfs_get_inode(sd); |
@@ -781,6 +783,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) | |||
781 | old_dentry = sysfs_get_dentry(sd); | 783 | old_dentry = sysfs_get_dentry(sd); |
782 | if (IS_ERR(old_dentry)) { | 784 | if (IS_ERR(old_dentry)) { |
783 | error = PTR_ERR(old_dentry); | 785 | error = PTR_ERR(old_dentry); |
786 | old_dentry = NULL; | ||
784 | goto out; | 787 | goto out; |
785 | } | 788 | } |
786 | 789 | ||
@@ -848,6 +851,7 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) | |||
848 | old_dentry = sysfs_get_dentry(sd); | 851 | old_dentry = sysfs_get_dentry(sd); |
849 | if (IS_ERR(old_dentry)) { | 852 | if (IS_ERR(old_dentry)) { |
850 | error = PTR_ERR(old_dentry); | 853 | error = PTR_ERR(old_dentry); |
854 | old_dentry = NULL; | ||
851 | goto out; | 855 | goto out; |
852 | } | 856 | } |
853 | old_parent = old_dentry->d_parent; | 857 | old_parent = old_dentry->d_parent; |
@@ -855,6 +859,7 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) | |||
855 | new_parent = sysfs_get_dentry(new_parent_sd); | 859 | new_parent = sysfs_get_dentry(new_parent_sd); |
856 | if (IS_ERR(new_parent)) { | 860 | if (IS_ERR(new_parent)) { |
857 | error = PTR_ERR(new_parent); | 861 | error = PTR_ERR(new_parent); |
862 | new_parent = NULL; | ||
858 | goto out; | 863 | goto out; |
859 | } | 864 | } |
860 | 865 | ||
@@ -878,7 +883,6 @@ again: | |||
878 | error = 0; | 883 | error = 0; |
879 | d_add(new_dentry, NULL); | 884 | d_add(new_dentry, NULL); |
880 | d_move(old_dentry, new_dentry); | 885 | d_move(old_dentry, new_dentry); |
881 | dput(new_dentry); | ||
882 | 886 | ||
883 | /* Remove from old parent's list and insert into new parent's list. */ | 887 | /* Remove from old parent's list and insert into new parent's list. */ |
884 | sysfs_unlink_sibling(sd); | 888 | sysfs_unlink_sibling(sd); |
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index b834f1709f9f..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; |
@@ -354,31 +317,23 @@ static int sysfs_open_file(struct inode *inode, struct file *file) | |||
354 | { | 317 | { |
355 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; | 318 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; |
356 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; | 319 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; |
357 | struct sysfs_buffer * buffer; | 320 | struct sysfs_buffer *buffer; |
358 | struct sysfs_ops * ops = NULL; | 321 | struct sysfs_ops *ops; |
359 | int error; | 322 | int error = -EACCES; |
360 | 323 | ||
361 | /* need attr_sd for attr and ops, its parent for kobj */ | 324 | /* need attr_sd for attr and ops, its parent for kobj */ |
362 | if (!sysfs_get_active_two(attr_sd)) | 325 | if (!sysfs_get_active_two(attr_sd)) |
363 | return -ENODEV; | 326 | return -ENODEV; |
364 | 327 | ||
365 | /* if the kobject has no ktype, then we assume that it is a subsystem | 328 | /* every kobject with an attribute needs a ktype assigned */ |
366 | * itself, and use ops for it. | 329 | if (kobj->ktype && kobj->ktype->sysfs_ops) |
367 | */ | ||
368 | if (kobj->kset && kobj->kset->ktype) | ||
369 | ops = kobj->kset->ktype->sysfs_ops; | ||
370 | else if (kobj->ktype) | ||
371 | ops = kobj->ktype->sysfs_ops; | 330 | ops = kobj->ktype->sysfs_ops; |
372 | else | 331 | else { |
373 | ops = &subsys_sysfs_ops; | 332 | printk(KERN_ERR "missing sysfs attribute operations for " |
374 | 333 | "kobject: %s\n", kobject_name(kobj)); | |
375 | error = -EACCES; | 334 | WARN_ON(1); |
376 | |||
377 | /* No sysfs operations, either from having no subsystem, | ||
378 | * or the subsystem have no operations. | ||
379 | */ | ||
380 | if (!ops) | ||
381 | goto err_out; | 335 | goto err_out; |
336 | } | ||
382 | 337 | ||
383 | /* File needs write support. | 338 | /* File needs write support. |
384 | * The inode's perms must say it's ok, | 339 | * The inode's perms must say it's ok, |
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 3eac20c63c41..5f66c4466151 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c | |||
@@ -19,39 +19,6 @@ | |||
19 | 19 | ||
20 | #include "sysfs.h" | 20 | #include "sysfs.h" |
21 | 21 | ||
22 | static int object_depth(struct sysfs_dirent *sd) | ||
23 | { | ||
24 | int depth = 0; | ||
25 | |||
26 | for (; sd->s_parent; sd = sd->s_parent) | ||
27 | depth++; | ||
28 | |||
29 | return depth; | ||
30 | } | ||
31 | |||
32 | static int object_path_length(struct sysfs_dirent * sd) | ||
33 | { | ||
34 | int length = 1; | ||
35 | |||
36 | for (; sd->s_parent; sd = sd->s_parent) | ||
37 | length += strlen(sd->s_name) + 1; | ||
38 | |||
39 | return length; | ||
40 | } | ||
41 | |||
42 | static void fill_object_path(struct sysfs_dirent *sd, char *buffer, int length) | ||
43 | { | ||
44 | --length; | ||
45 | for (; sd->s_parent; sd = sd->s_parent) { | ||
46 | int cur = strlen(sd->s_name); | ||
47 | |||
48 | /* back up enough to print this bus id with '/' */ | ||
49 | length -= cur; | ||
50 | strncpy(buffer + length, sd->s_name, cur); | ||
51 | *(buffer + --length) = '/'; | ||
52 | } | ||
53 | } | ||
54 | |||
55 | /** | 22 | /** |
56 | * sysfs_create_link - create symlink between two objects. | 23 | * sysfs_create_link - create symlink between two objects. |
57 | * @kobj: object whose directory we're creating the link in. | 24 | * @kobj: object whose directory we're creating the link in. |
@@ -112,7 +79,6 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char | |||
112 | return error; | 79 | return error; |
113 | } | 80 | } |
114 | 81 | ||
115 | |||
116 | /** | 82 | /** |
117 | * sysfs_remove_link - remove symlink in object's directory. | 83 | * sysfs_remove_link - remove symlink in object's directory. |
118 | * @kobj: object we're acting for. | 84 | * @kobj: object we're acting for. |
@@ -124,24 +90,54 @@ void sysfs_remove_link(struct kobject * kobj, const char * name) | |||
124 | sysfs_hash_and_remove(kobj->sd, name); | 90 | sysfs_hash_and_remove(kobj->sd, name); |
125 | } | 91 | } |
126 | 92 | ||
127 | static int sysfs_get_target_path(struct sysfs_dirent * parent_sd, | 93 | static int sysfs_get_target_path(struct sysfs_dirent *parent_sd, |
128 | struct sysfs_dirent * target_sd, char *path) | 94 | struct sysfs_dirent *target_sd, char *path) |
129 | { | 95 | { |
130 | char * s; | 96 | struct sysfs_dirent *base, *sd; |
131 | int depth, size; | 97 | char *s = path; |
98 | int len = 0; | ||
99 | |||
100 | /* go up to the root, stop at the base */ | ||
101 | base = parent_sd; | ||
102 | while (base->s_parent) { | ||
103 | sd = target_sd->s_parent; | ||
104 | while (sd->s_parent && base != sd) | ||
105 | sd = sd->s_parent; | ||
106 | |||
107 | if (base == sd) | ||
108 | break; | ||
109 | |||
110 | strcpy(s, "../"); | ||
111 | s += 3; | ||
112 | base = base->s_parent; | ||
113 | } | ||
114 | |||
115 | /* determine end of target string for reverse fillup */ | ||
116 | sd = target_sd; | ||
117 | while (sd->s_parent && sd != base) { | ||
118 | len += strlen(sd->s_name) + 1; | ||
119 | sd = sd->s_parent; | ||
120 | } | ||
132 | 121 | ||
133 | depth = object_depth(parent_sd); | 122 | /* check limits */ |
134 | size = object_path_length(target_sd) + depth * 3 - 1; | 123 | if (len < 2) |
135 | if (size > PATH_MAX) | 124 | return -EINVAL; |
125 | len--; | ||
126 | if ((s - path) + len > PATH_MAX) | ||
136 | return -ENAMETOOLONG; | 127 | return -ENAMETOOLONG; |
137 | 128 | ||
138 | pr_debug("%s: depth = %d, size = %d\n", __FUNCTION__, depth, size); | 129 | /* reverse fillup of target string from target to base */ |
130 | sd = target_sd; | ||
131 | while (sd->s_parent && sd != base) { | ||
132 | int slen = strlen(sd->s_name); | ||
139 | 133 | ||
140 | for (s = path; depth--; s += 3) | 134 | len -= slen; |
141 | strcpy(s,"../"); | 135 | strncpy(s + len, sd->s_name, slen); |
136 | if (len) | ||
137 | s[--len] = '/'; | ||
142 | 138 | ||
143 | fill_object_path(target_sd, path, size); | 139 | sd = sd->s_parent; |
144 | pr_debug("%s: path = '%s'\n", __FUNCTION__, path); | 140 | } |
145 | 141 | ||
146 | return 0; | 142 | return 0; |
147 | } | 143 | } |