diff options
Diffstat (limited to 'fs/sysfs')
-rw-r--r-- | fs/sysfs/bin.c | 36 | ||||
-rw-r--r-- | fs/sysfs/dir.c | 754 | ||||
-rw-r--r-- | fs/sysfs/file.c | 248 | ||||
-rw-r--r-- | fs/sysfs/group.c | 2 | ||||
-rw-r--r-- | fs/sysfs/inode.c | 103 | ||||
-rw-r--r-- | fs/sysfs/mount.c | 26 | ||||
-rw-r--r-- | fs/sysfs/symlink.c | 34 | ||||
-rw-r--r-- | fs/sysfs/sysfs.h | 184 |
8 files changed, 587 insertions, 800 deletions
diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c index 5afe2a26f5d8..006fc64227dd 100644 --- a/fs/sysfs/bin.c +++ b/fs/sysfs/bin.c | |||
@@ -1,9 +1,15 @@ | |||
1 | /* | 1 | /* |
2 | * bin.c - binary file operations for sysfs. | 2 | * fs/sysfs/bin.c - sysfs binary file implementation |
3 | * | 3 | * |
4 | * Copyright (c) 2003 Patrick Mochel | 4 | * Copyright (c) 2003 Patrick Mochel |
5 | * Copyright (c) 2003 Matthew Wilcox | 5 | * Copyright (c) 2003 Matthew Wilcox |
6 | * Copyright (c) 2004 Silicon Graphics, Inc. | 6 | * Copyright (c) 2004 Silicon Graphics, Inc. |
7 | * Copyright (c) 2007 SUSE Linux Products GmbH | ||
8 | * Copyright (c) 2007 Tejun Heo <teheo@suse.de> | ||
9 | * | ||
10 | * This file is released under the GPLv2. | ||
11 | * | ||
12 | * Please see Documentation/filesystems/sysfs.txt for more information. | ||
7 | */ | 13 | */ |
8 | 14 | ||
9 | #undef DEBUG | 15 | #undef DEBUG |
@@ -14,9 +20,9 @@ | |||
14 | #include <linux/kobject.h> | 20 | #include <linux/kobject.h> |
15 | #include <linux/module.h> | 21 | #include <linux/module.h> |
16 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/mutex.h> | ||
17 | 24 | ||
18 | #include <asm/uaccess.h> | 25 | #include <asm/uaccess.h> |
19 | #include <asm/semaphore.h> | ||
20 | 26 | ||
21 | #include "sysfs.h" | 27 | #include "sysfs.h" |
22 | 28 | ||
@@ -30,8 +36,8 @@ static int | |||
30 | fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count) | 36 | fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count) |
31 | { | 37 | { |
32 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; | 38 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; |
33 | struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; | 39 | struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; |
34 | struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; | 40 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; |
35 | int rc; | 41 | int rc; |
36 | 42 | ||
37 | /* need attr_sd for attr, its parent for kobj */ | 43 | /* need attr_sd for attr, its parent for kobj */ |
@@ -87,8 +93,8 @@ static int | |||
87 | flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count) | 93 | flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count) |
88 | { | 94 | { |
89 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; | 95 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; |
90 | struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; | 96 | struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; |
91 | struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; | 97 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; |
92 | int rc; | 98 | int rc; |
93 | 99 | ||
94 | /* need attr_sd for attr, its parent for kobj */ | 100 | /* need attr_sd for attr, its parent for kobj */ |
@@ -140,8 +146,8 @@ static int mmap(struct file *file, struct vm_area_struct *vma) | |||
140 | { | 146 | { |
141 | struct bin_buffer *bb = file->private_data; | 147 | struct bin_buffer *bb = file->private_data; |
142 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; | 148 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; |
143 | struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; | 149 | struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; |
144 | struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; | 150 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; |
145 | int rc; | 151 | int rc; |
146 | 152 | ||
147 | mutex_lock(&bb->mutex); | 153 | mutex_lock(&bb->mutex); |
@@ -167,12 +173,12 @@ static int mmap(struct file *file, struct vm_area_struct *vma) | |||
167 | static int open(struct inode * inode, struct file * file) | 173 | static int open(struct inode * inode, struct file * file) |
168 | { | 174 | { |
169 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; | 175 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; |
170 | struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; | 176 | struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; |
171 | struct bin_buffer *bb = NULL; | 177 | struct bin_buffer *bb = NULL; |
172 | int error; | 178 | int error; |
173 | 179 | ||
174 | /* need attr_sd for attr */ | 180 | /* binary file operations requires both @sd and its parent */ |
175 | if (!sysfs_get_active(attr_sd)) | 181 | if (!sysfs_get_active_two(attr_sd)) |
176 | return -ENODEV; | 182 | return -ENODEV; |
177 | 183 | ||
178 | error = -EACCES; | 184 | error = -EACCES; |
@@ -193,13 +199,12 @@ static int open(struct inode * inode, struct file * file) | |||
193 | mutex_init(&bb->mutex); | 199 | mutex_init(&bb->mutex); |
194 | file->private_data = bb; | 200 | file->private_data = bb; |
195 | 201 | ||
196 | /* open succeeded, put active reference and pin attr_sd */ | 202 | /* open succeeded, put active references */ |
197 | sysfs_put_active(attr_sd); | 203 | sysfs_put_active_two(attr_sd); |
198 | sysfs_get(attr_sd); | ||
199 | return 0; | 204 | return 0; |
200 | 205 | ||
201 | err_out: | 206 | err_out: |
202 | sysfs_put_active(attr_sd); | 207 | sysfs_put_active_two(attr_sd); |
203 | kfree(bb); | 208 | kfree(bb); |
204 | return error; | 209 | return error; |
205 | } | 210 | } |
@@ -211,7 +216,6 @@ static int release(struct inode * inode, struct file * file) | |||
211 | 216 | ||
212 | if (bb->mmapped) | 217 | if (bb->mmapped) |
213 | sysfs_put_active_two(attr_sd); | 218 | sysfs_put_active_two(attr_sd); |
214 | sysfs_put(attr_sd); | ||
215 | kfree(bb->buffer); | 219 | kfree(bb->buffer); |
216 | kfree(bb); | 220 | kfree(bb); |
217 | return 0; | 221 | return 0; |
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 83e76b3813c9..9161db4d6b5c 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
@@ -1,5 +1,13 @@ | |||
1 | /* | 1 | /* |
2 | * dir.c - Operations for sysfs directories. | 2 | * fs/sysfs/dir.c - sysfs core and dir operation implementation |
3 | * | ||
4 | * Copyright (c) 2001-3 Patrick Mochel | ||
5 | * Copyright (c) 2007 SUSE Linux Products GmbH | ||
6 | * Copyright (c) 2007 Tejun Heo <teheo@suse.de> | ||
7 | * | ||
8 | * This file is released under the GPLv2. | ||
9 | * | ||
10 | * Please see Documentation/filesystems/sysfs.txt for more information. | ||
3 | */ | 11 | */ |
4 | 12 | ||
5 | #undef DEBUG | 13 | #undef DEBUG |
@@ -11,10 +19,11 @@ | |||
11 | #include <linux/namei.h> | 19 | #include <linux/namei.h> |
12 | #include <linux/idr.h> | 20 | #include <linux/idr.h> |
13 | #include <linux/completion.h> | 21 | #include <linux/completion.h> |
14 | #include <asm/semaphore.h> | 22 | #include <linux/mutex.h> |
15 | #include "sysfs.h" | 23 | #include "sysfs.h" |
16 | 24 | ||
17 | DEFINE_MUTEX(sysfs_mutex); | 25 | DEFINE_MUTEX(sysfs_mutex); |
26 | DEFINE_MUTEX(sysfs_rename_mutex); | ||
18 | spinlock_t sysfs_assoc_lock = SPIN_LOCK_UNLOCKED; | 27 | spinlock_t sysfs_assoc_lock = SPIN_LOCK_UNLOCKED; |
19 | 28 | ||
20 | static spinlock_t sysfs_ino_lock = SPIN_LOCK_UNLOCKED; | 29 | static spinlock_t sysfs_ino_lock = SPIN_LOCK_UNLOCKED; |
@@ -25,18 +34,28 @@ static DEFINE_IDA(sysfs_ino_ida); | |||
25 | * @sd: sysfs_dirent of interest | 34 | * @sd: sysfs_dirent of interest |
26 | * | 35 | * |
27 | * Link @sd into its sibling list which starts from | 36 | * Link @sd into its sibling list which starts from |
28 | * sd->s_parent->s_children. | 37 | * sd->s_parent->s_dir.children. |
29 | * | 38 | * |
30 | * Locking: | 39 | * Locking: |
31 | * mutex_lock(sysfs_mutex) | 40 | * mutex_lock(sysfs_mutex) |
32 | */ | 41 | */ |
33 | void sysfs_link_sibling(struct sysfs_dirent *sd) | 42 | static void sysfs_link_sibling(struct sysfs_dirent *sd) |
34 | { | 43 | { |
35 | struct sysfs_dirent *parent_sd = sd->s_parent; | 44 | struct sysfs_dirent *parent_sd = sd->s_parent; |
45 | struct sysfs_dirent **pos; | ||
36 | 46 | ||
37 | BUG_ON(sd->s_sibling); | 47 | BUG_ON(sd->s_sibling); |
38 | sd->s_sibling = parent_sd->s_children; | 48 | |
39 | parent_sd->s_children = sd; | 49 | /* Store directory entries in order by ino. This allows |
50 | * readdir to properly restart without having to add a | ||
51 | * cursor into the s_dir.children list. | ||
52 | */ | ||
53 | for (pos = &parent_sd->s_dir.children; *pos; pos = &(*pos)->s_sibling) { | ||
54 | if (sd->s_ino < (*pos)->s_ino) | ||
55 | break; | ||
56 | } | ||
57 | sd->s_sibling = *pos; | ||
58 | *pos = sd; | ||
40 | } | 59 | } |
41 | 60 | ||
42 | /** | 61 | /** |
@@ -44,16 +63,17 @@ void sysfs_link_sibling(struct sysfs_dirent *sd) | |||
44 | * @sd: sysfs_dirent of interest | 63 | * @sd: sysfs_dirent of interest |
45 | * | 64 | * |
46 | * Unlink @sd from its sibling list which starts from | 65 | * Unlink @sd from its sibling list which starts from |
47 | * sd->s_parent->s_children. | 66 | * sd->s_parent->s_dir.children. |
48 | * | 67 | * |
49 | * Locking: | 68 | * Locking: |
50 | * mutex_lock(sysfs_mutex) | 69 | * mutex_lock(sysfs_mutex) |
51 | */ | 70 | */ |
52 | void sysfs_unlink_sibling(struct sysfs_dirent *sd) | 71 | static void sysfs_unlink_sibling(struct sysfs_dirent *sd) |
53 | { | 72 | { |
54 | struct sysfs_dirent **pos; | 73 | struct sysfs_dirent **pos; |
55 | 74 | ||
56 | for (pos = &sd->s_parent->s_children; *pos; pos = &(*pos)->s_sibling) { | 75 | for (pos = &sd->s_parent->s_dir.children; *pos; |
76 | pos = &(*pos)->s_sibling) { | ||
57 | if (*pos == sd) { | 77 | if (*pos == sd) { |
58 | *pos = sd->s_sibling; | 78 | *pos = sd->s_sibling; |
59 | sd->s_sibling = NULL; | 79 | sd->s_sibling = NULL; |
@@ -67,96 +87,39 @@ void sysfs_unlink_sibling(struct sysfs_dirent *sd) | |||
67 | * @sd: sysfs_dirent of interest | 87 | * @sd: sysfs_dirent of interest |
68 | * | 88 | * |
69 | * Get dentry for @sd. Dentry is looked up if currently not | 89 | * Get dentry for @sd. Dentry is looked up if currently not |
70 | * present. This function climbs sysfs_dirent tree till it | 90 | * present. This function descends from the root looking up |
71 | * reaches a sysfs_dirent with valid dentry attached and descends | 91 | * dentry for each step. |
72 | * down from there looking up dentry for each step. | ||
73 | * | 92 | * |
74 | * LOCKING: | 93 | * LOCKING: |
75 | * Kernel thread context (may sleep) | 94 | * mutex_lock(sysfs_rename_mutex) |
76 | * | 95 | * |
77 | * RETURNS: | 96 | * RETURNS: |
78 | * Pointer to found dentry on success, ERR_PTR() value on error. | 97 | * Pointer to found dentry on success, ERR_PTR() value on error. |
79 | */ | 98 | */ |
80 | struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd) | 99 | struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd) |
81 | { | 100 | { |
82 | struct sysfs_dirent *cur; | 101 | struct dentry *dentry = dget(sysfs_sb->s_root); |
83 | struct dentry *parent_dentry, *dentry; | ||
84 | int i, depth; | ||
85 | |||
86 | /* Find the first parent which has valid s_dentry and get the | ||
87 | * dentry. | ||
88 | */ | ||
89 | mutex_lock(&sysfs_mutex); | ||
90 | restart0: | ||
91 | spin_lock(&sysfs_assoc_lock); | ||
92 | restart1: | ||
93 | spin_lock(&dcache_lock); | ||
94 | 102 | ||
95 | dentry = NULL; | 103 | while (dentry->d_fsdata != sd) { |
96 | depth = 0; | 104 | struct sysfs_dirent *cur; |
97 | cur = sd; | 105 | struct dentry *parent; |
98 | while (!cur->s_dentry || !cur->s_dentry->d_inode) { | ||
99 | if (cur->s_flags & SYSFS_FLAG_REMOVED) { | ||
100 | dentry = ERR_PTR(-ENOENT); | ||
101 | depth = 0; | ||
102 | break; | ||
103 | } | ||
104 | cur = cur->s_parent; | ||
105 | depth++; | ||
106 | } | ||
107 | if (!IS_ERR(dentry)) | ||
108 | dentry = dget_locked(cur->s_dentry); | ||
109 | 106 | ||
110 | spin_unlock(&dcache_lock); | 107 | /* find the first ancestor which hasn't been looked up */ |
111 | spin_unlock(&sysfs_assoc_lock); | 108 | cur = sd; |
112 | 109 | while (cur->s_parent != dentry->d_fsdata) | |
113 | /* from the found dentry, look up depth times */ | ||
114 | while (depth--) { | ||
115 | /* find and get depth'th ancestor */ | ||
116 | for (cur = sd, i = 0; cur && i < depth; i++) | ||
117 | cur = cur->s_parent; | 110 | cur = cur->s_parent; |
118 | 111 | ||
119 | /* This can happen if tree structure was modified due | ||
120 | * to move/rename. Restart. | ||
121 | */ | ||
122 | if (i != depth) { | ||
123 | dput(dentry); | ||
124 | goto restart0; | ||
125 | } | ||
126 | |||
127 | sysfs_get(cur); | ||
128 | |||
129 | mutex_unlock(&sysfs_mutex); | ||
130 | |||
131 | /* look it up */ | 112 | /* look it up */ |
132 | parent_dentry = dentry; | 113 | parent = dentry; |
133 | dentry = lookup_one_len_kern(cur->s_name, parent_dentry, | 114 | mutex_lock(&parent->d_inode->i_mutex); |
115 | dentry = lookup_one_len_kern(cur->s_name, parent, | ||
134 | strlen(cur->s_name)); | 116 | strlen(cur->s_name)); |
135 | dput(parent_dentry); | 117 | mutex_unlock(&parent->d_inode->i_mutex); |
136 | 118 | dput(parent); | |
137 | if (IS_ERR(dentry)) { | ||
138 | sysfs_put(cur); | ||
139 | return dentry; | ||
140 | } | ||
141 | 119 | ||
142 | mutex_lock(&sysfs_mutex); | 120 | if (IS_ERR(dentry)) |
143 | spin_lock(&sysfs_assoc_lock); | 121 | break; |
144 | |||
145 | /* This, again, can happen if tree structure has | ||
146 | * changed and we looked up the wrong thing. Restart. | ||
147 | */ | ||
148 | if (cur->s_dentry != dentry) { | ||
149 | dput(dentry); | ||
150 | sysfs_put(cur); | ||
151 | goto restart1; | ||
152 | } | ||
153 | |||
154 | spin_unlock(&sysfs_assoc_lock); | ||
155 | |||
156 | sysfs_put(cur); | ||
157 | } | 122 | } |
158 | |||
159 | mutex_unlock(&sysfs_mutex); | ||
160 | return dentry; | 123 | return dentry; |
161 | } | 124 | } |
162 | 125 | ||
@@ -319,7 +282,7 @@ void release_sysfs_dirent(struct sysfs_dirent * sd) | |||
319 | parent_sd = sd->s_parent; | 282 | parent_sd = sd->s_parent; |
320 | 283 | ||
321 | if (sysfs_type(sd) == SYSFS_KOBJ_LINK) | 284 | if (sysfs_type(sd) == SYSFS_KOBJ_LINK) |
322 | sysfs_put(sd->s_elem.symlink.target_sd); | 285 | sysfs_put(sd->s_symlink.target_sd); |
323 | if (sysfs_type(sd) & SYSFS_COPY_NAME) | 286 | if (sysfs_type(sd) & SYSFS_COPY_NAME) |
324 | kfree(sd->s_name); | 287 | kfree(sd->s_name); |
325 | kfree(sd->s_iattr); | 288 | kfree(sd->s_iattr); |
@@ -335,22 +298,7 @@ static void sysfs_d_iput(struct dentry * dentry, struct inode * inode) | |||
335 | { | 298 | { |
336 | struct sysfs_dirent * sd = dentry->d_fsdata; | 299 | struct sysfs_dirent * sd = dentry->d_fsdata; |
337 | 300 | ||
338 | if (sd) { | 301 | sysfs_put(sd); |
339 | /* sd->s_dentry is protected with sysfs_assoc_lock. | ||
340 | * This allows sysfs_drop_dentry() to dereference it. | ||
341 | */ | ||
342 | spin_lock(&sysfs_assoc_lock); | ||
343 | |||
344 | /* The dentry might have been deleted or another | ||
345 | * lookup could have happened updating sd->s_dentry to | ||
346 | * point the new dentry. Ignore if it isn't pointing | ||
347 | * to this dentry. | ||
348 | */ | ||
349 | if (sd->s_dentry == dentry) | ||
350 | sd->s_dentry = NULL; | ||
351 | spin_unlock(&sysfs_assoc_lock); | ||
352 | sysfs_put(sd); | ||
353 | } | ||
354 | iput(inode); | 302 | iput(inode); |
355 | } | 303 | } |
356 | 304 | ||
@@ -378,7 +326,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) | |||
378 | 326 | ||
379 | atomic_set(&sd->s_count, 1); | 327 | atomic_set(&sd->s_count, 1); |
380 | atomic_set(&sd->s_active, 0); | 328 | atomic_set(&sd->s_active, 0); |
381 | atomic_set(&sd->s_event, 1); | ||
382 | 329 | ||
383 | sd->s_name = name; | 330 | sd->s_name = name; |
384 | sd->s_mode = mode; | 331 | sd->s_mode = mode; |
@@ -393,30 +340,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) | |||
393 | return NULL; | 340 | return NULL; |
394 | } | 341 | } |
395 | 342 | ||
396 | /** | ||
397 | * sysfs_attach_dentry - associate sysfs_dirent with dentry | ||
398 | * @sd: target sysfs_dirent | ||
399 | * @dentry: dentry to associate | ||
400 | * | ||
401 | * Associate @sd with @dentry. This is protected by | ||
402 | * sysfs_assoc_lock to avoid race with sysfs_d_iput(). | ||
403 | * | ||
404 | * LOCKING: | ||
405 | * mutex_lock(sysfs_mutex) | ||
406 | */ | ||
407 | static void sysfs_attach_dentry(struct sysfs_dirent *sd, struct dentry *dentry) | ||
408 | { | ||
409 | dentry->d_op = &sysfs_dentry_ops; | ||
410 | dentry->d_fsdata = sysfs_get(sd); | ||
411 | |||
412 | /* protect sd->s_dentry against sysfs_d_iput */ | ||
413 | spin_lock(&sysfs_assoc_lock); | ||
414 | sd->s_dentry = dentry; | ||
415 | spin_unlock(&sysfs_assoc_lock); | ||
416 | |||
417 | d_rehash(dentry); | ||
418 | } | ||
419 | |||
420 | static int sysfs_ilookup_test(struct inode *inode, void *arg) | 343 | static int sysfs_ilookup_test(struct inode *inode, void *arg) |
421 | { | 344 | { |
422 | struct sysfs_dirent *sd = arg; | 345 | struct sysfs_dirent *sd = arg; |
@@ -480,10 +403,8 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, | |||
480 | * @sd: sysfs_dirent to be added | 403 | * @sd: sysfs_dirent to be added |
481 | * | 404 | * |
482 | * Get @acxt->parent_sd and set sd->s_parent to it and increment | 405 | * Get @acxt->parent_sd and set sd->s_parent to it and increment |
483 | * nlink of parent inode if @sd is a directory. @sd is NOT | 406 | * nlink of parent inode if @sd is a directory and link into the |
484 | * linked into the children list of the parent. The caller | 407 | * children list of the parent. |
485 | * should invoke sysfs_link_sibling() after this function | ||
486 | * completes if @sd needs to be on the children list. | ||
487 | * | 408 | * |
488 | * This function should be called between calls to | 409 | * This function should be called between calls to |
489 | * sysfs_addrm_start() and sysfs_addrm_finish() and should be | 410 | * sysfs_addrm_start() and sysfs_addrm_finish() and should be |
@@ -491,15 +412,30 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, | |||
491 | * | 412 | * |
492 | * LOCKING: | 413 | * LOCKING: |
493 | * Determined by sysfs_addrm_start(). | 414 | * Determined by sysfs_addrm_start(). |
415 | * | ||
416 | * RETURNS: | ||
417 | * 0 on success, -EEXIST if entry with the given name already | ||
418 | * exists. | ||
494 | */ | 419 | */ |
495 | void sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | 420 | int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) |
496 | { | 421 | { |
422 | if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)) { | ||
423 | printk(KERN_WARNING "sysfs: duplicate filename '%s' " | ||
424 | "can not be created\n", sd->s_name); | ||
425 | WARN_ON(1); | ||
426 | return -EEXIST; | ||
427 | } | ||
428 | |||
497 | sd->s_parent = sysfs_get(acxt->parent_sd); | 429 | sd->s_parent = sysfs_get(acxt->parent_sd); |
498 | 430 | ||
499 | if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode) | 431 | if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode) |
500 | inc_nlink(acxt->parent_inode); | 432 | inc_nlink(acxt->parent_inode); |
501 | 433 | ||
502 | acxt->cnt++; | 434 | acxt->cnt++; |
435 | |||
436 | sysfs_link_sibling(sd); | ||
437 | |||
438 | return 0; | ||
503 | } | 439 | } |
504 | 440 | ||
505 | /** | 441 | /** |
@@ -508,9 +444,7 @@ void sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | |||
508 | * @sd: sysfs_dirent to be added | 444 | * @sd: sysfs_dirent to be added |
509 | * | 445 | * |
510 | * Mark @sd removed and drop nlink of parent inode if @sd is a | 446 | * Mark @sd removed and drop nlink of parent inode if @sd is a |
511 | * directory. @sd is NOT unlinked from the children list of the | 447 | * directory. @sd is unlinked from the children list. |
512 | * parent. The caller is repsonsible for removing @sd from the | ||
513 | * children list before calling this function. | ||
514 | * | 448 | * |
515 | * This function should be called between calls to | 449 | * This function should be called between calls to |
516 | * sysfs_addrm_start() and sysfs_addrm_finish() and should be | 450 | * sysfs_addrm_start() and sysfs_addrm_finish() and should be |
@@ -521,7 +455,9 @@ void sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | |||
521 | */ | 455 | */ |
522 | void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | 456 | void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) |
523 | { | 457 | { |
524 | BUG_ON(sd->s_sibling || (sd->s_flags & SYSFS_FLAG_REMOVED)); | 458 | BUG_ON(sd->s_flags & SYSFS_FLAG_REMOVED); |
459 | |||
460 | sysfs_unlink_sibling(sd); | ||
525 | 461 | ||
526 | sd->s_flags |= SYSFS_FLAG_REMOVED; | 462 | sd->s_flags |= SYSFS_FLAG_REMOVED; |
527 | sd->s_sibling = acxt->removed; | 463 | sd->s_sibling = acxt->removed; |
@@ -540,53 +476,49 @@ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | |||
540 | * Drop dentry for @sd. @sd must have been unlinked from its | 476 | * Drop dentry for @sd. @sd must have been unlinked from its |
541 | * parent on entry to this function such that it can't be looked | 477 | * parent on entry to this function such that it can't be looked |
542 | * up anymore. | 478 | * up anymore. |
543 | * | ||
544 | * @sd->s_dentry which is protected with sysfs_assoc_lock points | ||
545 | * to the currently associated dentry but we're not holding a | ||
546 | * reference to it and racing with dput(). Grab dcache_lock and | ||
547 | * verify dentry before dropping it. If @sd->s_dentry is NULL or | ||
548 | * dput() beats us, no need to bother. | ||
549 | */ | 479 | */ |
550 | static void sysfs_drop_dentry(struct sysfs_dirent *sd) | 480 | static void sysfs_drop_dentry(struct sysfs_dirent *sd) |
551 | { | 481 | { |
552 | struct dentry *dentry = NULL; | ||
553 | struct inode *inode; | 482 | struct inode *inode; |
483 | struct dentry *dentry; | ||
554 | 484 | ||
555 | /* We're not holding a reference to ->s_dentry dentry but the | 485 | inode = ilookup(sysfs_sb, sd->s_ino); |
556 | * field will stay valid as long as sysfs_assoc_lock is held. | 486 | if (!inode) |
487 | return; | ||
488 | |||
489 | /* Drop any existing dentries associated with sd. | ||
490 | * | ||
491 | * For the dentry to be properly freed we need to grab a | ||
492 | * reference to the dentry under the dcache lock, unhash it, | ||
493 | * and then put it. The playing with the dentry count allows | ||
494 | * dput to immediately free the dentry if it is not in use. | ||
557 | */ | 495 | */ |
558 | spin_lock(&sysfs_assoc_lock); | 496 | repeat: |
559 | spin_lock(&dcache_lock); | 497 | spin_lock(&dcache_lock); |
560 | 498 | list_for_each_entry(dentry, &inode->i_dentry, d_alias) { | |
561 | /* drop dentry if it's there and dput() didn't kill it yet */ | 499 | if (d_unhashed(dentry)) |
562 | if (sd->s_dentry && sd->s_dentry->d_inode) { | 500 | continue; |
563 | dentry = dget_locked(sd->s_dentry); | 501 | dget_locked(dentry); |
564 | spin_lock(&dentry->d_lock); | 502 | spin_lock(&dentry->d_lock); |
565 | __d_drop(dentry); | 503 | __d_drop(dentry); |
566 | spin_unlock(&dentry->d_lock); | 504 | spin_unlock(&dentry->d_lock); |
505 | spin_unlock(&dcache_lock); | ||
506 | dput(dentry); | ||
507 | goto repeat; | ||
567 | } | 508 | } |
568 | |||
569 | spin_unlock(&dcache_lock); | 509 | spin_unlock(&dcache_lock); |
570 | spin_unlock(&sysfs_assoc_lock); | ||
571 | |||
572 | /* dentries for shadowed inodes are pinned, unpin */ | ||
573 | if (dentry && sysfs_is_shadowed_inode(dentry->d_inode)) | ||
574 | dput(dentry); | ||
575 | dput(dentry); | ||
576 | 510 | ||
577 | /* adjust nlink and update timestamp */ | 511 | /* adjust nlink and update timestamp */ |
578 | inode = ilookup(sysfs_sb, sd->s_ino); | 512 | mutex_lock(&inode->i_mutex); |
579 | if (inode) { | ||
580 | mutex_lock(&inode->i_mutex); | ||
581 | 513 | ||
582 | inode->i_ctime = CURRENT_TIME; | 514 | inode->i_ctime = CURRENT_TIME; |
515 | drop_nlink(inode); | ||
516 | if (sysfs_type(sd) == SYSFS_DIR) | ||
583 | drop_nlink(inode); | 517 | drop_nlink(inode); |
584 | if (sysfs_type(sd) == SYSFS_DIR) | ||
585 | drop_nlink(inode); | ||
586 | 518 | ||
587 | mutex_unlock(&inode->i_mutex); | 519 | mutex_unlock(&inode->i_mutex); |
588 | iput(inode); | 520 | |
589 | } | 521 | iput(inode); |
590 | } | 522 | } |
591 | 523 | ||
592 | /** | 524 | /** |
@@ -599,11 +531,8 @@ static void sysfs_drop_dentry(struct sysfs_dirent *sd) | |||
599 | * | 531 | * |
600 | * LOCKING: | 532 | * LOCKING: |
601 | * All mutexes acquired by sysfs_addrm_start() are released. | 533 | * All mutexes acquired by sysfs_addrm_start() are released. |
602 | * | ||
603 | * RETURNS: | ||
604 | * Number of added/removed sysfs_dirents since sysfs_addrm_start(). | ||
605 | */ | 534 | */ |
606 | int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) | 535 | void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) |
607 | { | 536 | { |
608 | /* release resources acquired by sysfs_addrm_start() */ | 537 | /* release resources acquired by sysfs_addrm_start() */ |
609 | mutex_unlock(&sysfs_mutex); | 538 | mutex_unlock(&sysfs_mutex); |
@@ -629,8 +558,6 @@ int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) | |||
629 | sysfs_deactivate(sd); | 558 | sysfs_deactivate(sd); |
630 | sysfs_put(sd); | 559 | sysfs_put(sd); |
631 | } | 560 | } |
632 | |||
633 | return acxt->cnt; | ||
634 | } | 561 | } |
635 | 562 | ||
636 | /** | 563 | /** |
@@ -651,8 +578,8 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, | |||
651 | { | 578 | { |
652 | struct sysfs_dirent *sd; | 579 | struct sysfs_dirent *sd; |
653 | 580 | ||
654 | for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) | 581 | for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling) |
655 | if (sysfs_type(sd) && !strcmp(sd->s_name, name)) | 582 | if (!strcmp(sd->s_name, name)) |
656 | return sd; | 583 | return sd; |
657 | return NULL; | 584 | return NULL; |
658 | } | 585 | } |
@@ -690,28 +617,25 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, | |||
690 | umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; | 617 | umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; |
691 | struct sysfs_addrm_cxt acxt; | 618 | struct sysfs_addrm_cxt acxt; |
692 | struct sysfs_dirent *sd; | 619 | struct sysfs_dirent *sd; |
620 | int rc; | ||
693 | 621 | ||
694 | /* allocate */ | 622 | /* allocate */ |
695 | sd = sysfs_new_dirent(name, mode, SYSFS_DIR); | 623 | sd = sysfs_new_dirent(name, mode, SYSFS_DIR); |
696 | if (!sd) | 624 | if (!sd) |
697 | return -ENOMEM; | 625 | return -ENOMEM; |
698 | sd->s_elem.dir.kobj = kobj; | 626 | sd->s_dir.kobj = kobj; |
699 | 627 | ||
700 | /* link in */ | 628 | /* link in */ |
701 | sysfs_addrm_start(&acxt, parent_sd); | 629 | sysfs_addrm_start(&acxt, parent_sd); |
630 | rc = sysfs_add_one(&acxt, sd); | ||
631 | sysfs_addrm_finish(&acxt); | ||
702 | 632 | ||
703 | if (!sysfs_find_dirent(parent_sd, name)) { | 633 | if (rc == 0) |
704 | sysfs_add_one(&acxt, sd); | 634 | *p_sd = sd; |
705 | sysfs_link_sibling(sd); | 635 | else |
706 | } | ||
707 | |||
708 | if (!sysfs_addrm_finish(&acxt)) { | ||
709 | sysfs_put(sd); | 636 | sysfs_put(sd); |
710 | return -EEXIST; | ||
711 | } | ||
712 | 637 | ||
713 | *p_sd = sd; | 638 | return rc; |
714 | return 0; | ||
715 | } | 639 | } |
716 | 640 | ||
717 | int sysfs_create_subdir(struct kobject *kobj, const char *name, | 641 | int sysfs_create_subdir(struct kobject *kobj, const char *name, |
@@ -723,24 +647,18 @@ int sysfs_create_subdir(struct kobject *kobj, const char *name, | |||
723 | /** | 647 | /** |
724 | * sysfs_create_dir - create a directory for an object. | 648 | * sysfs_create_dir - create a directory for an object. |
725 | * @kobj: object we're creating directory for. | 649 | * @kobj: object we're creating directory for. |
726 | * @shadow_parent: parent object. | ||
727 | */ | 650 | */ |
728 | int sysfs_create_dir(struct kobject *kobj, | 651 | int sysfs_create_dir(struct kobject * kobj) |
729 | struct sysfs_dirent *shadow_parent_sd) | ||
730 | { | 652 | { |
731 | struct sysfs_dirent *parent_sd, *sd; | 653 | struct sysfs_dirent *parent_sd, *sd; |
732 | int error = 0; | 654 | int error = 0; |
733 | 655 | ||
734 | BUG_ON(!kobj); | 656 | BUG_ON(!kobj); |
735 | 657 | ||
736 | if (shadow_parent_sd) | 658 | if (kobj->parent) |
737 | parent_sd = shadow_parent_sd; | ||
738 | else if (kobj->parent) | ||
739 | parent_sd = kobj->parent->sd; | 659 | parent_sd = kobj->parent->sd; |
740 | else if (sysfs_mount && sysfs_mount->mnt_sb) | ||
741 | parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata; | ||
742 | else | 660 | else |
743 | return -EFAULT; | 661 | parent_sd = &sysfs_root; |
744 | 662 | ||
745 | error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd); | 663 | error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd); |
746 | if (!error) | 664 | if (!error) |
@@ -748,39 +666,20 @@ int sysfs_create_dir(struct kobject *kobj, | |||
748 | return error; | 666 | return error; |
749 | } | 667 | } |
750 | 668 | ||
751 | static int sysfs_count_nlink(struct sysfs_dirent *sd) | ||
752 | { | ||
753 | struct sysfs_dirent *child; | ||
754 | int nr = 0; | ||
755 | |||
756 | for (child = sd->s_children; child; child = child->s_sibling) | ||
757 | if (sysfs_type(child) == SYSFS_DIR) | ||
758 | nr++; | ||
759 | return nr + 2; | ||
760 | } | ||
761 | |||
762 | static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, | 669 | static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, |
763 | struct nameidata *nd) | 670 | struct nameidata *nd) |
764 | { | 671 | { |
765 | struct dentry *ret = NULL; | 672 | struct dentry *ret = NULL; |
766 | struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata; | 673 | struct sysfs_dirent *parent_sd = dentry->d_parent->d_fsdata; |
767 | struct sysfs_dirent * sd; | 674 | struct sysfs_dirent *sd; |
768 | struct bin_attribute *bin_attr; | ||
769 | struct inode *inode; | 675 | struct inode *inode; |
770 | int found = 0; | ||
771 | 676 | ||
772 | mutex_lock(&sysfs_mutex); | 677 | mutex_lock(&sysfs_mutex); |
773 | 678 | ||
774 | for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) { | 679 | sd = sysfs_find_dirent(parent_sd, dentry->d_name.name); |
775 | if (sysfs_type(sd) && | ||
776 | !strcmp(sd->s_name, dentry->d_name.name)) { | ||
777 | found = 1; | ||
778 | break; | ||
779 | } | ||
780 | } | ||
781 | 680 | ||
782 | /* no such entry */ | 681 | /* no such entry */ |
783 | if (!found) | 682 | if (!sd) |
784 | goto out_unlock; | 683 | goto out_unlock; |
785 | 684 | ||
786 | /* attach dentry and inode */ | 685 | /* attach dentry and inode */ |
@@ -790,33 +689,11 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, | |||
790 | goto out_unlock; | 689 | goto out_unlock; |
791 | } | 690 | } |
792 | 691 | ||
793 | if (inode->i_state & I_NEW) { | 692 | /* instantiate and hash dentry */ |
794 | /* initialize inode according to type */ | 693 | dentry->d_op = &sysfs_dentry_ops; |
795 | switch (sysfs_type(sd)) { | 694 | dentry->d_fsdata = sysfs_get(sd); |
796 | case SYSFS_DIR: | 695 | d_instantiate(dentry, inode); |
797 | inode->i_op = &sysfs_dir_inode_operations; | 696 | d_rehash(dentry); |
798 | inode->i_fop = &sysfs_dir_operations; | ||
799 | inode->i_nlink = sysfs_count_nlink(sd); | ||
800 | break; | ||
801 | case SYSFS_KOBJ_ATTR: | ||
802 | inode->i_size = PAGE_SIZE; | ||
803 | inode->i_fop = &sysfs_file_operations; | ||
804 | break; | ||
805 | case SYSFS_KOBJ_BIN_ATTR: | ||
806 | bin_attr = sd->s_elem.bin_attr.bin_attr; | ||
807 | inode->i_size = bin_attr->size; | ||
808 | inode->i_fop = &bin_fops; | ||
809 | break; | ||
810 | case SYSFS_KOBJ_LINK: | ||
811 | inode->i_op = &sysfs_symlink_inode_operations; | ||
812 | break; | ||
813 | default: | ||
814 | BUG(); | ||
815 | } | ||
816 | } | ||
817 | |||
818 | sysfs_instantiate(dentry, inode); | ||
819 | sysfs_attach_dentry(sd, dentry); | ||
820 | 697 | ||
821 | out_unlock: | 698 | out_unlock: |
822 | mutex_unlock(&sysfs_mutex); | 699 | mutex_unlock(&sysfs_mutex); |
@@ -833,7 +710,6 @@ static void remove_dir(struct sysfs_dirent *sd) | |||
833 | struct sysfs_addrm_cxt acxt; | 710 | struct sysfs_addrm_cxt acxt; |
834 | 711 | ||
835 | sysfs_addrm_start(&acxt, sd->s_parent); | 712 | sysfs_addrm_start(&acxt, sd->s_parent); |
836 | sysfs_unlink_sibling(sd); | ||
837 | sysfs_remove_one(&acxt, sd); | 713 | sysfs_remove_one(&acxt, sd); |
838 | sysfs_addrm_finish(&acxt); | 714 | sysfs_addrm_finish(&acxt); |
839 | } | 715 | } |
@@ -854,15 +730,13 @@ static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd) | |||
854 | 730 | ||
855 | pr_debug("sysfs %s: removing dir\n", dir_sd->s_name); | 731 | pr_debug("sysfs %s: removing dir\n", dir_sd->s_name); |
856 | sysfs_addrm_start(&acxt, dir_sd); | 732 | sysfs_addrm_start(&acxt, dir_sd); |
857 | pos = &dir_sd->s_children; | 733 | pos = &dir_sd->s_dir.children; |
858 | while (*pos) { | 734 | while (*pos) { |
859 | struct sysfs_dirent *sd = *pos; | 735 | struct sysfs_dirent *sd = *pos; |
860 | 736 | ||
861 | if (sysfs_type(sd) && sysfs_type(sd) != SYSFS_DIR) { | 737 | if (sysfs_type(sd) != SYSFS_DIR) |
862 | *pos = sd->s_sibling; | ||
863 | sd->s_sibling = NULL; | ||
864 | sysfs_remove_one(&acxt, sd); | 738 | sysfs_remove_one(&acxt, sd); |
865 | } else | 739 | else |
866 | pos = &(*pos)->s_sibling; | 740 | pos = &(*pos)->s_sibling; |
867 | } | 741 | } |
868 | sysfs_addrm_finish(&acxt); | 742 | sysfs_addrm_finish(&acxt); |
@@ -890,90 +764,68 @@ void sysfs_remove_dir(struct kobject * kobj) | |||
890 | __sysfs_remove_dir(sd); | 764 | __sysfs_remove_dir(sd); |
891 | } | 765 | } |
892 | 766 | ||
893 | int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd, | 767 | int sysfs_rename_dir(struct kobject * kobj, const char *new_name) |
894 | const char *new_name) | ||
895 | { | 768 | { |
896 | struct sysfs_dirent *sd = kobj->sd; | 769 | struct sysfs_dirent *sd = kobj->sd; |
897 | struct dentry *new_parent = NULL; | 770 | struct dentry *parent = NULL; |
898 | struct dentry *old_dentry = NULL, *new_dentry = NULL; | 771 | struct dentry *old_dentry = NULL, *new_dentry = NULL; |
899 | const char *dup_name = NULL; | 772 | const char *dup_name = NULL; |
900 | int error; | 773 | int error; |
901 | 774 | ||
902 | /* get dentries */ | 775 | mutex_lock(&sysfs_rename_mutex); |
776 | |||
777 | error = 0; | ||
778 | if (strcmp(sd->s_name, new_name) == 0) | ||
779 | goto out; /* nothing to rename */ | ||
780 | |||
781 | /* get the original dentry */ | ||
903 | old_dentry = sysfs_get_dentry(sd); | 782 | old_dentry = sysfs_get_dentry(sd); |
904 | if (IS_ERR(old_dentry)) { | 783 | if (IS_ERR(old_dentry)) { |
905 | error = PTR_ERR(old_dentry); | 784 | error = PTR_ERR(old_dentry); |
906 | goto out_dput; | 785 | goto out; |
907 | } | ||
908 | |||
909 | new_parent = sysfs_get_dentry(new_parent_sd); | ||
910 | if (IS_ERR(new_parent)) { | ||
911 | error = PTR_ERR(new_parent); | ||
912 | goto out_dput; | ||
913 | } | 786 | } |
914 | 787 | ||
915 | /* lock new_parent and get dentry for new name */ | 788 | parent = old_dentry->d_parent; |
916 | mutex_lock(&new_parent->d_inode->i_mutex); | ||
917 | 789 | ||
918 | new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name)); | 790 | /* lock parent and get dentry for new name */ |
919 | if (IS_ERR(new_dentry)) { | 791 | mutex_lock(&parent->d_inode->i_mutex); |
920 | error = PTR_ERR(new_dentry); | 792 | mutex_lock(&sysfs_mutex); |
921 | goto out_unlock; | ||
922 | } | ||
923 | 793 | ||
924 | /* By allowing two different directories with the same | 794 | error = -EEXIST; |
925 | * d_parent we allow this routine to move between different | 795 | if (sysfs_find_dirent(sd->s_parent, new_name)) |
926 | * shadows of the same directory | ||
927 | */ | ||
928 | error = -EINVAL; | ||
929 | if (old_dentry->d_parent->d_inode != new_parent->d_inode || | ||
930 | new_dentry->d_parent->d_inode != new_parent->d_inode || | ||
931 | old_dentry == new_dentry) | ||
932 | goto out_unlock; | 796 | goto out_unlock; |
933 | 797 | ||
934 | error = -EEXIST; | 798 | error = -ENOMEM; |
935 | if (new_dentry->d_inode) | 799 | new_dentry = d_alloc_name(parent, new_name); |
800 | if (!new_dentry) | ||
936 | goto out_unlock; | 801 | goto out_unlock; |
937 | 802 | ||
938 | /* rename kobject and sysfs_dirent */ | 803 | /* rename kobject and sysfs_dirent */ |
939 | error = -ENOMEM; | 804 | error = -ENOMEM; |
940 | new_name = dup_name = kstrdup(new_name, GFP_KERNEL); | 805 | new_name = dup_name = kstrdup(new_name, GFP_KERNEL); |
941 | if (!new_name) | 806 | if (!new_name) |
942 | goto out_drop; | 807 | goto out_unlock; |
943 | 808 | ||
944 | error = kobject_set_name(kobj, "%s", new_name); | 809 | error = kobject_set_name(kobj, "%s", new_name); |
945 | if (error) | 810 | if (error) |
946 | goto out_drop; | 811 | goto out_unlock; |
947 | |||
948 | mutex_lock(&sysfs_mutex); | ||
949 | 812 | ||
950 | dup_name = sd->s_name; | 813 | dup_name = sd->s_name; |
951 | sd->s_name = new_name; | 814 | sd->s_name = new_name; |
952 | 815 | ||
953 | /* move under the new parent */ | 816 | /* rename */ |
954 | d_add(new_dentry, NULL); | 817 | d_add(new_dentry, NULL); |
955 | d_move(sd->s_dentry, new_dentry); | 818 | d_move(old_dentry, new_dentry); |
956 | |||
957 | sysfs_unlink_sibling(sd); | ||
958 | sysfs_get(new_parent_sd); | ||
959 | sysfs_put(sd->s_parent); | ||
960 | sd->s_parent = new_parent_sd; | ||
961 | sysfs_link_sibling(sd); | ||
962 | |||
963 | mutex_unlock(&sysfs_mutex); | ||
964 | 819 | ||
965 | error = 0; | 820 | error = 0; |
966 | goto out_unlock; | ||
967 | |||
968 | out_drop: | ||
969 | d_drop(new_dentry); | ||
970 | out_unlock: | 821 | out_unlock: |
971 | mutex_unlock(&new_parent->d_inode->i_mutex); | 822 | mutex_unlock(&sysfs_mutex); |
972 | out_dput: | 823 | mutex_unlock(&parent->d_inode->i_mutex); |
973 | kfree(dup_name); | 824 | kfree(dup_name); |
974 | dput(new_parent); | ||
975 | dput(old_dentry); | 825 | dput(old_dentry); |
976 | dput(new_dentry); | 826 | dput(new_dentry); |
827 | out: | ||
828 | mutex_unlock(&sysfs_rename_mutex); | ||
977 | return error; | 829 | return error; |
978 | } | 830 | } |
979 | 831 | ||
@@ -985,96 +837,69 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) | |||
985 | struct dentry *old_dentry = NULL, *new_dentry = NULL; | 837 | struct dentry *old_dentry = NULL, *new_dentry = NULL; |
986 | int error; | 838 | int error; |
987 | 839 | ||
840 | mutex_lock(&sysfs_rename_mutex); | ||
988 | BUG_ON(!sd->s_parent); | 841 | BUG_ON(!sd->s_parent); |
989 | new_parent_sd = new_parent_kobj->sd ? new_parent_kobj->sd : &sysfs_root; | 842 | new_parent_sd = new_parent_kobj->sd ? new_parent_kobj->sd : &sysfs_root; |
990 | 843 | ||
844 | error = 0; | ||
845 | if (sd->s_parent == new_parent_sd) | ||
846 | goto out; /* nothing to move */ | ||
847 | |||
991 | /* get dentries */ | 848 | /* get dentries */ |
992 | old_dentry = sysfs_get_dentry(sd); | 849 | old_dentry = sysfs_get_dentry(sd); |
993 | if (IS_ERR(old_dentry)) { | 850 | if (IS_ERR(old_dentry)) { |
994 | error = PTR_ERR(old_dentry); | 851 | error = PTR_ERR(old_dentry); |
995 | goto out_dput; | 852 | goto out; |
996 | } | 853 | } |
997 | old_parent = sd->s_parent->s_dentry; | 854 | old_parent = old_dentry->d_parent; |
998 | 855 | ||
999 | new_parent = sysfs_get_dentry(new_parent_sd); | 856 | new_parent = sysfs_get_dentry(new_parent_sd); |
1000 | if (IS_ERR(new_parent)) { | 857 | if (IS_ERR(new_parent)) { |
1001 | error = PTR_ERR(new_parent); | 858 | error = PTR_ERR(new_parent); |
1002 | goto out_dput; | 859 | goto out; |
1003 | } | 860 | } |
1004 | 861 | ||
1005 | if (old_parent->d_inode == new_parent->d_inode) { | ||
1006 | error = 0; | ||
1007 | goto out_dput; /* nothing to move */ | ||
1008 | } | ||
1009 | again: | 862 | again: |
1010 | mutex_lock(&old_parent->d_inode->i_mutex); | 863 | mutex_lock(&old_parent->d_inode->i_mutex); |
1011 | if (!mutex_trylock(&new_parent->d_inode->i_mutex)) { | 864 | if (!mutex_trylock(&new_parent->d_inode->i_mutex)) { |
1012 | mutex_unlock(&old_parent->d_inode->i_mutex); | 865 | mutex_unlock(&old_parent->d_inode->i_mutex); |
1013 | goto again; | 866 | goto again; |
1014 | } | 867 | } |
868 | mutex_lock(&sysfs_mutex); | ||
1015 | 869 | ||
1016 | new_dentry = lookup_one_len(kobj->name, new_parent, strlen(kobj->name)); | 870 | error = -EEXIST; |
1017 | if (IS_ERR(new_dentry)) { | 871 | if (sysfs_find_dirent(new_parent_sd, sd->s_name)) |
1018 | error = PTR_ERR(new_dentry); | ||
1019 | goto out_unlock; | 872 | goto out_unlock; |
1020 | } else | 873 | |
1021 | error = 0; | 874 | error = -ENOMEM; |
875 | new_dentry = d_alloc_name(new_parent, sd->s_name); | ||
876 | if (!new_dentry) | ||
877 | goto out_unlock; | ||
878 | |||
879 | error = 0; | ||
1022 | d_add(new_dentry, NULL); | 880 | d_add(new_dentry, NULL); |
1023 | d_move(sd->s_dentry, new_dentry); | 881 | d_move(old_dentry, new_dentry); |
1024 | dput(new_dentry); | 882 | dput(new_dentry); |
1025 | 883 | ||
1026 | /* Remove from old parent's list and insert into new parent's list. */ | 884 | /* Remove from old parent's list and insert into new parent's list. */ |
1027 | mutex_lock(&sysfs_mutex); | ||
1028 | |||
1029 | sysfs_unlink_sibling(sd); | 885 | sysfs_unlink_sibling(sd); |
1030 | sysfs_get(new_parent_sd); | 886 | sysfs_get(new_parent_sd); |
1031 | sysfs_put(sd->s_parent); | 887 | sysfs_put(sd->s_parent); |
1032 | sd->s_parent = new_parent_sd; | 888 | sd->s_parent = new_parent_sd; |
1033 | sysfs_link_sibling(sd); | 889 | sysfs_link_sibling(sd); |
1034 | 890 | ||
1035 | mutex_unlock(&sysfs_mutex); | ||
1036 | |||
1037 | out_unlock: | 891 | out_unlock: |
892 | mutex_unlock(&sysfs_mutex); | ||
1038 | mutex_unlock(&new_parent->d_inode->i_mutex); | 893 | mutex_unlock(&new_parent->d_inode->i_mutex); |
1039 | mutex_unlock(&old_parent->d_inode->i_mutex); | 894 | mutex_unlock(&old_parent->d_inode->i_mutex); |
1040 | out_dput: | 895 | out: |
1041 | dput(new_parent); | 896 | dput(new_parent); |
1042 | dput(old_dentry); | 897 | dput(old_dentry); |
1043 | dput(new_dentry); | 898 | dput(new_dentry); |
899 | mutex_unlock(&sysfs_rename_mutex); | ||
1044 | return error; | 900 | return error; |
1045 | } | 901 | } |
1046 | 902 | ||
1047 | static int sysfs_dir_open(struct inode *inode, struct file *file) | ||
1048 | { | ||
1049 | struct dentry * dentry = file->f_path.dentry; | ||
1050 | struct sysfs_dirent * parent_sd = dentry->d_fsdata; | ||
1051 | struct sysfs_dirent * sd; | ||
1052 | |||
1053 | sd = sysfs_new_dirent("_DIR_", 0, 0); | ||
1054 | if (sd) { | ||
1055 | mutex_lock(&sysfs_mutex); | ||
1056 | sd->s_parent = sysfs_get(parent_sd); | ||
1057 | sysfs_link_sibling(sd); | ||
1058 | mutex_unlock(&sysfs_mutex); | ||
1059 | } | ||
1060 | |||
1061 | file->private_data = sd; | ||
1062 | return sd ? 0 : -ENOMEM; | ||
1063 | } | ||
1064 | |||
1065 | static int sysfs_dir_close(struct inode *inode, struct file *file) | ||
1066 | { | ||
1067 | struct sysfs_dirent * cursor = file->private_data; | ||
1068 | |||
1069 | mutex_lock(&sysfs_mutex); | ||
1070 | sysfs_unlink_sibling(cursor); | ||
1071 | mutex_unlock(&sysfs_mutex); | ||
1072 | |||
1073 | release_sysfs_dirent(cursor); | ||
1074 | |||
1075 | return 0; | ||
1076 | } | ||
1077 | |||
1078 | /* Relationship between s_mode and the DT_xxx types */ | 903 | /* Relationship between s_mode and the DT_xxx types */ |
1079 | static inline unsigned char dt_type(struct sysfs_dirent *sd) | 904 | static inline unsigned char dt_type(struct sysfs_dirent *sd) |
1080 | { | 905 | { |
@@ -1085,232 +910,51 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
1085 | { | 910 | { |
1086 | struct dentry *dentry = filp->f_path.dentry; | 911 | struct dentry *dentry = filp->f_path.dentry; |
1087 | struct sysfs_dirent * parent_sd = dentry->d_fsdata; | 912 | struct sysfs_dirent * parent_sd = dentry->d_fsdata; |
1088 | struct sysfs_dirent *cursor = filp->private_data; | 913 | struct sysfs_dirent *pos; |
1089 | struct sysfs_dirent **pos; | ||
1090 | ino_t ino; | 914 | ino_t ino; |
1091 | int i = filp->f_pos; | ||
1092 | 915 | ||
1093 | switch (i) { | 916 | if (filp->f_pos == 0) { |
1094 | case 0: | 917 | ino = parent_sd->s_ino; |
1095 | ino = parent_sd->s_ino; | 918 | if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) == 0) |
1096 | if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0) | ||
1097 | break; | ||
1098 | filp->f_pos++; | 919 | filp->f_pos++; |
1099 | i++; | 920 | } |
1100 | /* fallthrough */ | 921 | if (filp->f_pos == 1) { |
1101 | case 1: | 922 | if (parent_sd->s_parent) |
1102 | if (parent_sd->s_parent) | 923 | ino = parent_sd->s_parent->s_ino; |
1103 | ino = parent_sd->s_parent->s_ino; | 924 | else |
1104 | else | 925 | ino = parent_sd->s_ino; |
1105 | ino = parent_sd->s_ino; | 926 | if (filldir(dirent, "..", 2, filp->f_pos, ino, DT_DIR) == 0) |
1106 | if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0) | ||
1107 | break; | ||
1108 | filp->f_pos++; | 927 | filp->f_pos++; |
1109 | i++; | 928 | } |
1110 | /* fallthrough */ | 929 | if ((filp->f_pos > 1) && (filp->f_pos < INT_MAX)) { |
1111 | default: | 930 | mutex_lock(&sysfs_mutex); |
1112 | mutex_lock(&sysfs_mutex); | ||
1113 | |||
1114 | pos = &parent_sd->s_children; | ||
1115 | while (*pos != cursor) | ||
1116 | pos = &(*pos)->s_sibling; | ||
1117 | |||
1118 | /* unlink cursor */ | ||
1119 | *pos = cursor->s_sibling; | ||
1120 | |||
1121 | if (filp->f_pos == 2) | ||
1122 | pos = &parent_sd->s_children; | ||
1123 | |||
1124 | for ( ; *pos; pos = &(*pos)->s_sibling) { | ||
1125 | struct sysfs_dirent *next = *pos; | ||
1126 | const char * name; | ||
1127 | int len; | ||
1128 | |||
1129 | if (!sysfs_type(next)) | ||
1130 | continue; | ||
1131 | |||
1132 | name = next->s_name; | ||
1133 | len = strlen(name); | ||
1134 | ino = next->s_ino; | ||
1135 | |||
1136 | if (filldir(dirent, name, len, filp->f_pos, ino, | ||
1137 | dt_type(next)) < 0) | ||
1138 | break; | ||
1139 | 931 | ||
1140 | filp->f_pos++; | 932 | /* Skip the dentries we have already reported */ |
1141 | } | 933 | pos = parent_sd->s_dir.children; |
934 | while (pos && (filp->f_pos > pos->s_ino)) | ||
935 | pos = pos->s_sibling; | ||
1142 | 936 | ||
1143 | /* put cursor back in */ | 937 | for ( ; pos; pos = pos->s_sibling) { |
1144 | cursor->s_sibling = *pos; | 938 | const char * name; |
1145 | *pos = cursor; | 939 | int len; |
1146 | 940 | ||
1147 | mutex_unlock(&sysfs_mutex); | 941 | name = pos->s_name; |
1148 | } | 942 | len = strlen(name); |
1149 | return 0; | 943 | filp->f_pos = ino = pos->s_ino; |
1150 | } | ||
1151 | |||
1152 | static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin) | ||
1153 | { | ||
1154 | struct dentry * dentry = file->f_path.dentry; | ||
1155 | 944 | ||
1156 | switch (origin) { | 945 | if (filldir(dirent, name, len, filp->f_pos, ino, |
1157 | case 1: | 946 | dt_type(pos)) < 0) |
1158 | offset += file->f_pos; | ||
1159 | case 0: | ||
1160 | if (offset >= 0) | ||
1161 | break; | 947 | break; |
1162 | default: | ||
1163 | return -EINVAL; | ||
1164 | } | ||
1165 | if (offset != file->f_pos) { | ||
1166 | mutex_lock(&sysfs_mutex); | ||
1167 | |||
1168 | file->f_pos = offset; | ||
1169 | if (file->f_pos >= 2) { | ||
1170 | struct sysfs_dirent *sd = dentry->d_fsdata; | ||
1171 | struct sysfs_dirent *cursor = file->private_data; | ||
1172 | struct sysfs_dirent **pos; | ||
1173 | loff_t n = file->f_pos - 2; | ||
1174 | |||
1175 | sysfs_unlink_sibling(cursor); | ||
1176 | |||
1177 | pos = &sd->s_children; | ||
1178 | while (n && *pos) { | ||
1179 | struct sysfs_dirent *next = *pos; | ||
1180 | if (sysfs_type(next)) | ||
1181 | n--; | ||
1182 | pos = &(*pos)->s_sibling; | ||
1183 | } | ||
1184 | |||
1185 | cursor->s_sibling = *pos; | ||
1186 | *pos = cursor; | ||
1187 | } | 948 | } |
1188 | 949 | if (!pos) | |
950 | filp->f_pos = INT_MAX; | ||
1189 | mutex_unlock(&sysfs_mutex); | 951 | mutex_unlock(&sysfs_mutex); |
1190 | } | 952 | } |
1191 | |||
1192 | return offset; | ||
1193 | } | ||
1194 | |||
1195 | |||
1196 | /** | ||
1197 | * sysfs_make_shadowed_dir - Setup so a directory can be shadowed | ||
1198 | * @kobj: object we're creating shadow of. | ||
1199 | */ | ||
1200 | |||
1201 | int sysfs_make_shadowed_dir(struct kobject *kobj, | ||
1202 | void * (*follow_link)(struct dentry *, struct nameidata *)) | ||
1203 | { | ||
1204 | struct dentry *dentry; | ||
1205 | struct inode *inode; | ||
1206 | struct inode_operations *i_op; | ||
1207 | |||
1208 | /* get dentry for @kobj->sd, dentry of a shadowed dir is pinned */ | ||
1209 | dentry = sysfs_get_dentry(kobj->sd); | ||
1210 | if (IS_ERR(dentry)) | ||
1211 | return PTR_ERR(dentry); | ||
1212 | |||
1213 | inode = dentry->d_inode; | ||
1214 | if (inode->i_op != &sysfs_dir_inode_operations) { | ||
1215 | dput(dentry); | ||
1216 | return -EINVAL; | ||
1217 | } | ||
1218 | |||
1219 | i_op = kmalloc(sizeof(*i_op), GFP_KERNEL); | ||
1220 | if (!i_op) | ||
1221 | return -ENOMEM; | ||
1222 | |||
1223 | memcpy(i_op, &sysfs_dir_inode_operations, sizeof(*i_op)); | ||
1224 | i_op->follow_link = follow_link; | ||
1225 | |||
1226 | /* Locking of inode->i_op? | ||
1227 | * Since setting i_op is a single word write and they | ||
1228 | * are atomic we should be ok here. | ||
1229 | */ | ||
1230 | inode->i_op = i_op; | ||
1231 | return 0; | 953 | return 0; |
1232 | } | 954 | } |
1233 | 955 | ||
1234 | /** | ||
1235 | * sysfs_create_shadow_dir - create a shadow directory for an object. | ||
1236 | * @kobj: object we're creating directory for. | ||
1237 | * | ||
1238 | * sysfs_make_shadowed_dir must already have been called on this | ||
1239 | * directory. | ||
1240 | */ | ||
1241 | |||
1242 | struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj) | ||
1243 | { | ||
1244 | struct sysfs_dirent *parent_sd = kobj->sd->s_parent; | ||
1245 | struct dentry *dir, *parent, *shadow; | ||
1246 | struct inode *inode; | ||
1247 | struct sysfs_dirent *sd; | ||
1248 | struct sysfs_addrm_cxt acxt; | ||
1249 | |||
1250 | dir = sysfs_get_dentry(kobj->sd); | ||
1251 | if (IS_ERR(dir)) { | ||
1252 | sd = (void *)dir; | ||
1253 | goto out; | ||
1254 | } | ||
1255 | parent = dir->d_parent; | ||
1256 | |||
1257 | inode = dir->d_inode; | ||
1258 | sd = ERR_PTR(-EINVAL); | ||
1259 | if (!sysfs_is_shadowed_inode(inode)) | ||
1260 | goto out_dput; | ||
1261 | |||
1262 | shadow = d_alloc(parent, &dir->d_name); | ||
1263 | if (!shadow) | ||
1264 | goto nomem; | ||
1265 | |||
1266 | sd = sysfs_new_dirent("_SHADOW_", inode->i_mode, SYSFS_DIR); | ||
1267 | if (!sd) | ||
1268 | goto nomem; | ||
1269 | sd->s_elem.dir.kobj = kobj; | ||
1270 | |||
1271 | sysfs_addrm_start(&acxt, parent_sd); | ||
1272 | |||
1273 | /* add but don't link into children list */ | ||
1274 | sysfs_add_one(&acxt, sd); | ||
1275 | |||
1276 | /* attach and instantiate dentry */ | ||
1277 | sysfs_attach_dentry(sd, shadow); | ||
1278 | d_instantiate(shadow, igrab(inode)); | ||
1279 | inc_nlink(inode); /* tj: synchronization? */ | ||
1280 | |||
1281 | sysfs_addrm_finish(&acxt); | ||
1282 | |||
1283 | dget(shadow); /* Extra count - pin the dentry in core */ | ||
1284 | |||
1285 | goto out_dput; | ||
1286 | |||
1287 | nomem: | ||
1288 | dput(shadow); | ||
1289 | sd = ERR_PTR(-ENOMEM); | ||
1290 | out_dput: | ||
1291 | dput(dir); | ||
1292 | out: | ||
1293 | return sd; | ||
1294 | } | ||
1295 | |||
1296 | /** | ||
1297 | * sysfs_remove_shadow_dir - remove an object's directory. | ||
1298 | * @shadow_sd: sysfs_dirent of shadow directory | ||
1299 | * | ||
1300 | * The only thing special about this is that we remove any files in | ||
1301 | * the directory before we remove the directory, and we've inlined | ||
1302 | * what used to be sysfs_rmdir() below, instead of calling separately. | ||
1303 | */ | ||
1304 | |||
1305 | void sysfs_remove_shadow_dir(struct sysfs_dirent *shadow_sd) | ||
1306 | { | ||
1307 | __sysfs_remove_dir(shadow_sd); | ||
1308 | } | ||
1309 | 956 | ||
1310 | const struct file_operations sysfs_dir_operations = { | 957 | const struct file_operations sysfs_dir_operations = { |
1311 | .open = sysfs_dir_open, | ||
1312 | .release = sysfs_dir_close, | ||
1313 | .llseek = sysfs_dir_lseek, | ||
1314 | .read = generic_read_dir, | 958 | .read = generic_read_dir, |
1315 | .readdir = sysfs_readdir, | 959 | .readdir = sysfs_readdir, |
1316 | }; | 960 | }; |
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 3e1cc062a740..d3be1e7fb48b 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
@@ -1,15 +1,22 @@ | |||
1 | /* | 1 | /* |
2 | * file.c - operations for regular (text) files. | 2 | * fs/sysfs/file.c - sysfs regular (text) file implementation |
3 | * | ||
4 | * Copyright (c) 2001-3 Patrick Mochel | ||
5 | * Copyright (c) 2007 SUSE Linux Products GmbH | ||
6 | * Copyright (c) 2007 Tejun Heo <teheo@suse.de> | ||
7 | * | ||
8 | * This file is released under the GPLv2. | ||
9 | * | ||
10 | * Please see Documentation/filesystems/sysfs.txt for more information. | ||
3 | */ | 11 | */ |
4 | 12 | ||
5 | #include <linux/module.h> | 13 | #include <linux/module.h> |
6 | #include <linux/fsnotify.h> | ||
7 | #include <linux/kobject.h> | 14 | #include <linux/kobject.h> |
8 | #include <linux/namei.h> | 15 | #include <linux/namei.h> |
9 | #include <linux/poll.h> | 16 | #include <linux/poll.h> |
10 | #include <linux/list.h> | 17 | #include <linux/list.h> |
18 | #include <linux/mutex.h> | ||
11 | #include <asm/uaccess.h> | 19 | #include <asm/uaccess.h> |
12 | #include <asm/semaphore.h> | ||
13 | 20 | ||
14 | #include "sysfs.h" | 21 | #include "sysfs.h" |
15 | 22 | ||
@@ -50,14 +57,33 @@ static struct sysfs_ops subsys_sysfs_ops = { | |||
50 | .store = subsys_attr_store, | 57 | .store = subsys_attr_store, |
51 | }; | 58 | }; |
52 | 59 | ||
60 | /* | ||
61 | * There's one sysfs_buffer for each open file and one | ||
62 | * sysfs_open_dirent for each sysfs_dirent with one or more open | ||
63 | * files. | ||
64 | * | ||
65 | * filp->private_data points to sysfs_buffer and | ||
66 | * sysfs_dirent->s_attr.open points to sysfs_open_dirent. s_attr.open | ||
67 | * is protected by sysfs_open_dirent_lock. | ||
68 | */ | ||
69 | static spinlock_t sysfs_open_dirent_lock = SPIN_LOCK_UNLOCKED; | ||
70 | |||
71 | struct sysfs_open_dirent { | ||
72 | atomic_t refcnt; | ||
73 | atomic_t event; | ||
74 | wait_queue_head_t poll; | ||
75 | struct list_head buffers; /* goes through sysfs_buffer.list */ | ||
76 | }; | ||
77 | |||
53 | struct sysfs_buffer { | 78 | struct sysfs_buffer { |
54 | size_t count; | 79 | size_t count; |
55 | loff_t pos; | 80 | loff_t pos; |
56 | char * page; | 81 | char * page; |
57 | struct sysfs_ops * ops; | 82 | struct sysfs_ops * ops; |
58 | struct semaphore sem; | 83 | struct mutex mutex; |
59 | int needs_read_fill; | 84 | int needs_read_fill; |
60 | int event; | 85 | int event; |
86 | struct list_head list; | ||
61 | }; | 87 | }; |
62 | 88 | ||
63 | /** | 89 | /** |
@@ -74,7 +100,7 @@ struct sysfs_buffer { | |||
74 | static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer) | 100 | static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer) |
75 | { | 101 | { |
76 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; | 102 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; |
77 | struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; | 103 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; |
78 | struct sysfs_ops * ops = buffer->ops; | 104 | struct sysfs_ops * ops = buffer->ops; |
79 | int ret = 0; | 105 | int ret = 0; |
80 | ssize_t count; | 106 | ssize_t count; |
@@ -88,8 +114,8 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer | |||
88 | if (!sysfs_get_active_two(attr_sd)) | 114 | if (!sysfs_get_active_two(attr_sd)) |
89 | return -ENODEV; | 115 | return -ENODEV; |
90 | 116 | ||
91 | buffer->event = atomic_read(&attr_sd->s_event); | 117 | buffer->event = atomic_read(&attr_sd->s_attr.open->event); |
92 | count = ops->show(kobj, attr_sd->s_elem.attr.attr, buffer->page); | 118 | count = ops->show(kobj, attr_sd->s_attr.attr, buffer->page); |
93 | 119 | ||
94 | sysfs_put_active_two(attr_sd); | 120 | sysfs_put_active_two(attr_sd); |
95 | 121 | ||
@@ -128,7 +154,7 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos) | |||
128 | struct sysfs_buffer * buffer = file->private_data; | 154 | struct sysfs_buffer * buffer = file->private_data; |
129 | ssize_t retval = 0; | 155 | ssize_t retval = 0; |
130 | 156 | ||
131 | down(&buffer->sem); | 157 | mutex_lock(&buffer->mutex); |
132 | if (buffer->needs_read_fill) { | 158 | if (buffer->needs_read_fill) { |
133 | retval = fill_read_buffer(file->f_path.dentry,buffer); | 159 | retval = fill_read_buffer(file->f_path.dentry,buffer); |
134 | if (retval) | 160 | if (retval) |
@@ -139,7 +165,7 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos) | |||
139 | retval = simple_read_from_buffer(buf, count, ppos, buffer->page, | 165 | retval = simple_read_from_buffer(buf, count, ppos, buffer->page, |
140 | buffer->count); | 166 | buffer->count); |
141 | out: | 167 | out: |
142 | up(&buffer->sem); | 168 | mutex_unlock(&buffer->mutex); |
143 | return retval; | 169 | return retval; |
144 | } | 170 | } |
145 | 171 | ||
@@ -189,7 +215,7 @@ static int | |||
189 | flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t count) | 215 | flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t count) |
190 | { | 216 | { |
191 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; | 217 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; |
192 | struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; | 218 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; |
193 | struct sysfs_ops * ops = buffer->ops; | 219 | struct sysfs_ops * ops = buffer->ops; |
194 | int rc; | 220 | int rc; |
195 | 221 | ||
@@ -197,7 +223,7 @@ flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t | |||
197 | if (!sysfs_get_active_two(attr_sd)) | 223 | if (!sysfs_get_active_two(attr_sd)) |
198 | return -ENODEV; | 224 | return -ENODEV; |
199 | 225 | ||
200 | rc = ops->store(kobj, attr_sd->s_elem.attr.attr, buffer->page, count); | 226 | rc = ops->store(kobj, attr_sd->s_attr.attr, buffer->page, count); |
201 | 227 | ||
202 | sysfs_put_active_two(attr_sd); | 228 | sysfs_put_active_two(attr_sd); |
203 | 229 | ||
@@ -228,20 +254,102 @@ sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t | |||
228 | struct sysfs_buffer * buffer = file->private_data; | 254 | struct sysfs_buffer * buffer = file->private_data; |
229 | ssize_t len; | 255 | ssize_t len; |
230 | 256 | ||
231 | down(&buffer->sem); | 257 | mutex_lock(&buffer->mutex); |
232 | len = fill_write_buffer(buffer, buf, count); | 258 | len = fill_write_buffer(buffer, buf, count); |
233 | if (len > 0) | 259 | if (len > 0) |
234 | len = flush_write_buffer(file->f_path.dentry, buffer, len); | 260 | len = flush_write_buffer(file->f_path.dentry, buffer, len); |
235 | if (len > 0) | 261 | if (len > 0) |
236 | *ppos += len; | 262 | *ppos += len; |
237 | up(&buffer->sem); | 263 | mutex_unlock(&buffer->mutex); |
238 | return len; | 264 | return len; |
239 | } | 265 | } |
240 | 266 | ||
267 | /** | ||
268 | * sysfs_get_open_dirent - get or create sysfs_open_dirent | ||
269 | * @sd: target sysfs_dirent | ||
270 | * @buffer: sysfs_buffer for this instance of open | ||
271 | * | ||
272 | * If @sd->s_attr.open exists, increment its reference count; | ||
273 | * otherwise, create one. @buffer is chained to the buffers | ||
274 | * list. | ||
275 | * | ||
276 | * LOCKING: | ||
277 | * Kernel thread context (may sleep). | ||
278 | * | ||
279 | * RETURNS: | ||
280 | * 0 on success, -errno on failure. | ||
281 | */ | ||
282 | static int sysfs_get_open_dirent(struct sysfs_dirent *sd, | ||
283 | struct sysfs_buffer *buffer) | ||
284 | { | ||
285 | struct sysfs_open_dirent *od, *new_od = NULL; | ||
286 | |||
287 | retry: | ||
288 | spin_lock(&sysfs_open_dirent_lock); | ||
289 | |||
290 | if (!sd->s_attr.open && new_od) { | ||
291 | sd->s_attr.open = new_od; | ||
292 | new_od = NULL; | ||
293 | } | ||
294 | |||
295 | od = sd->s_attr.open; | ||
296 | if (od) { | ||
297 | atomic_inc(&od->refcnt); | ||
298 | list_add_tail(&buffer->list, &od->buffers); | ||
299 | } | ||
300 | |||
301 | spin_unlock(&sysfs_open_dirent_lock); | ||
302 | |||
303 | if (od) { | ||
304 | kfree(new_od); | ||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | /* not there, initialize a new one and retry */ | ||
309 | new_od = kmalloc(sizeof(*new_od), GFP_KERNEL); | ||
310 | if (!new_od) | ||
311 | return -ENOMEM; | ||
312 | |||
313 | atomic_set(&new_od->refcnt, 0); | ||
314 | atomic_set(&new_od->event, 1); | ||
315 | init_waitqueue_head(&new_od->poll); | ||
316 | INIT_LIST_HEAD(&new_od->buffers); | ||
317 | goto retry; | ||
318 | } | ||
319 | |||
320 | /** | ||
321 | * sysfs_put_open_dirent - put sysfs_open_dirent | ||
322 | * @sd: target sysfs_dirent | ||
323 | * @buffer: associated sysfs_buffer | ||
324 | * | ||
325 | * Put @sd->s_attr.open and unlink @buffer from the buffers list. | ||
326 | * If reference count reaches zero, disassociate and free it. | ||
327 | * | ||
328 | * LOCKING: | ||
329 | * None. | ||
330 | */ | ||
331 | static void sysfs_put_open_dirent(struct sysfs_dirent *sd, | ||
332 | struct sysfs_buffer *buffer) | ||
333 | { | ||
334 | struct sysfs_open_dirent *od = sd->s_attr.open; | ||
335 | |||
336 | spin_lock(&sysfs_open_dirent_lock); | ||
337 | |||
338 | list_del(&buffer->list); | ||
339 | if (atomic_dec_and_test(&od->refcnt)) | ||
340 | sd->s_attr.open = NULL; | ||
341 | else | ||
342 | od = NULL; | ||
343 | |||
344 | spin_unlock(&sysfs_open_dirent_lock); | ||
345 | |||
346 | kfree(od); | ||
347 | } | ||
348 | |||
241 | static int sysfs_open_file(struct inode *inode, struct file *file) | 349 | static int sysfs_open_file(struct inode *inode, struct file *file) |
242 | { | 350 | { |
243 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; | 351 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; |
244 | struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; | 352 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; |
245 | struct sysfs_buffer * buffer; | 353 | struct sysfs_buffer * buffer; |
246 | struct sysfs_ops * ops = NULL; | 354 | struct sysfs_ops * ops = NULL; |
247 | int error; | 355 | int error; |
@@ -294,33 +402,38 @@ static int sysfs_open_file(struct inode *inode, struct file *file) | |||
294 | if (!buffer) | 402 | if (!buffer) |
295 | goto err_out; | 403 | goto err_out; |
296 | 404 | ||
297 | init_MUTEX(&buffer->sem); | 405 | mutex_init(&buffer->mutex); |
298 | buffer->needs_read_fill = 1; | 406 | buffer->needs_read_fill = 1; |
299 | buffer->ops = ops; | 407 | buffer->ops = ops; |
300 | file->private_data = buffer; | 408 | file->private_data = buffer; |
301 | 409 | ||
302 | /* open succeeded, put active references and pin attr_sd */ | 410 | /* make sure we have open dirent struct */ |
411 | error = sysfs_get_open_dirent(attr_sd, buffer); | ||
412 | if (error) | ||
413 | goto err_free; | ||
414 | |||
415 | /* open succeeded, put active references */ | ||
303 | sysfs_put_active_two(attr_sd); | 416 | sysfs_put_active_two(attr_sd); |
304 | sysfs_get(attr_sd); | ||
305 | return 0; | 417 | return 0; |
306 | 418 | ||
419 | err_free: | ||
420 | kfree(buffer); | ||
307 | err_out: | 421 | err_out: |
308 | sysfs_put_active_two(attr_sd); | 422 | sysfs_put_active_two(attr_sd); |
309 | return error; | 423 | return error; |
310 | } | 424 | } |
311 | 425 | ||
312 | static int sysfs_release(struct inode * inode, struct file * filp) | 426 | static int sysfs_release(struct inode *inode, struct file *filp) |
313 | { | 427 | { |
314 | struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; | 428 | struct sysfs_dirent *sd = filp->f_path.dentry->d_fsdata; |
315 | struct sysfs_buffer *buffer = filp->private_data; | 429 | struct sysfs_buffer *buffer = filp->private_data; |
316 | 430 | ||
317 | sysfs_put(attr_sd); | 431 | sysfs_put_open_dirent(sd, buffer); |
432 | |||
433 | if (buffer->page) | ||
434 | free_page((unsigned long)buffer->page); | ||
435 | kfree(buffer); | ||
318 | 436 | ||
319 | if (buffer) { | ||
320 | if (buffer->page) | ||
321 | free_page((unsigned long)buffer->page); | ||
322 | kfree(buffer); | ||
323 | } | ||
324 | return 0; | 437 | return 0; |
325 | } | 438 | } |
326 | 439 | ||
@@ -335,24 +448,24 @@ static int sysfs_release(struct inode * inode, struct file * filp) | |||
335 | * again will not get new data, or reset the state of 'poll'. | 448 | * again will not get new data, or reset the state of 'poll'. |
336 | * Reminder: this only works for attributes which actively support | 449 | * Reminder: this only works for attributes which actively support |
337 | * it, and it is not possible to test an attribute from userspace | 450 | * it, and it is not possible to test an attribute from userspace |
338 | * to see if it supports poll (Nether 'poll' or 'select' return | 451 | * to see if it supports poll (Neither 'poll' nor 'select' return |
339 | * an appropriate error code). When in doubt, set a suitable timeout value. | 452 | * an appropriate error code). When in doubt, set a suitable timeout value. |
340 | */ | 453 | */ |
341 | static unsigned int sysfs_poll(struct file *filp, poll_table *wait) | 454 | static unsigned int sysfs_poll(struct file *filp, poll_table *wait) |
342 | { | 455 | { |
343 | struct sysfs_buffer * buffer = filp->private_data; | 456 | struct sysfs_buffer * buffer = filp->private_data; |
344 | struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; | 457 | struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; |
345 | struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; | 458 | struct sysfs_open_dirent *od = attr_sd->s_attr.open; |
346 | 459 | ||
347 | /* need parent for the kobj, grab both */ | 460 | /* need parent for the kobj, grab both */ |
348 | if (!sysfs_get_active_two(attr_sd)) | 461 | if (!sysfs_get_active_two(attr_sd)) |
349 | goto trigger; | 462 | goto trigger; |
350 | 463 | ||
351 | poll_wait(filp, &kobj->poll, wait); | 464 | poll_wait(filp, &od->poll, wait); |
352 | 465 | ||
353 | sysfs_put_active_two(attr_sd); | 466 | sysfs_put_active_two(attr_sd); |
354 | 467 | ||
355 | if (buffer->event != atomic_read(&attr_sd->s_event)) | 468 | if (buffer->event != atomic_read(&od->event)) |
356 | goto trigger; | 469 | goto trigger; |
357 | 470 | ||
358 | return 0; | 471 | return 0; |
@@ -373,8 +486,17 @@ void sysfs_notify(struct kobject *k, char *dir, char *attr) | |||
373 | if (sd && attr) | 486 | if (sd && attr) |
374 | sd = sysfs_find_dirent(sd, attr); | 487 | sd = sysfs_find_dirent(sd, attr); |
375 | if (sd) { | 488 | if (sd) { |
376 | atomic_inc(&sd->s_event); | 489 | struct sysfs_open_dirent *od; |
377 | wake_up_interruptible(&k->poll); | 490 | |
491 | spin_lock(&sysfs_open_dirent_lock); | ||
492 | |||
493 | od = sd->s_attr.open; | ||
494 | if (od) { | ||
495 | atomic_inc(&od->event); | ||
496 | wake_up_interruptible(&od->poll); | ||
497 | } | ||
498 | |||
499 | spin_unlock(&sysfs_open_dirent_lock); | ||
378 | } | 500 | } |
379 | 501 | ||
380 | mutex_unlock(&sysfs_mutex); | 502 | mutex_unlock(&sysfs_mutex); |
@@ -397,25 +519,21 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, | |||
397 | umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG; | 519 | umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG; |
398 | struct sysfs_addrm_cxt acxt; | 520 | struct sysfs_addrm_cxt acxt; |
399 | struct sysfs_dirent *sd; | 521 | struct sysfs_dirent *sd; |
522 | int rc; | ||
400 | 523 | ||
401 | sd = sysfs_new_dirent(attr->name, mode, type); | 524 | sd = sysfs_new_dirent(attr->name, mode, type); |
402 | if (!sd) | 525 | if (!sd) |
403 | return -ENOMEM; | 526 | return -ENOMEM; |
404 | sd->s_elem.attr.attr = (void *)attr; | 527 | sd->s_attr.attr = (void *)attr; |
405 | 528 | ||
406 | sysfs_addrm_start(&acxt, dir_sd); | 529 | sysfs_addrm_start(&acxt, dir_sd); |
530 | rc = sysfs_add_one(&acxt, sd); | ||
531 | sysfs_addrm_finish(&acxt); | ||
407 | 532 | ||
408 | if (!sysfs_find_dirent(dir_sd, attr->name)) { | 533 | if (rc) |
409 | sysfs_add_one(&acxt, sd); | ||
410 | sysfs_link_sibling(sd); | ||
411 | } | ||
412 | |||
413 | if (!sysfs_addrm_finish(&acxt)) { | ||
414 | sysfs_put(sd); | 534 | sysfs_put(sd); |
415 | return -EEXIST; | ||
416 | } | ||
417 | 535 | ||
418 | return 0; | 536 | return rc; |
419 | } | 537 | } |
420 | 538 | ||
421 | 539 | ||
@@ -457,42 +575,6 @@ int sysfs_add_file_to_group(struct kobject *kobj, | |||
457 | } | 575 | } |
458 | EXPORT_SYMBOL_GPL(sysfs_add_file_to_group); | 576 | EXPORT_SYMBOL_GPL(sysfs_add_file_to_group); |
459 | 577 | ||
460 | |||
461 | /** | ||
462 | * sysfs_update_file - update the modified timestamp on an object attribute. | ||
463 | * @kobj: object we're acting for. | ||
464 | * @attr: attribute descriptor. | ||
465 | */ | ||
466 | int sysfs_update_file(struct kobject * kobj, const struct attribute * attr) | ||
467 | { | ||
468 | struct sysfs_dirent *victim_sd = NULL; | ||
469 | struct dentry *victim = NULL; | ||
470 | int rc; | ||
471 | |||
472 | rc = -ENOENT; | ||
473 | victim_sd = sysfs_get_dirent(kobj->sd, attr->name); | ||
474 | if (!victim_sd) | ||
475 | goto out; | ||
476 | |||
477 | victim = sysfs_get_dentry(victim_sd); | ||
478 | if (IS_ERR(victim)) { | ||
479 | rc = PTR_ERR(victim); | ||
480 | victim = NULL; | ||
481 | goto out; | ||
482 | } | ||
483 | |||
484 | mutex_lock(&victim->d_inode->i_mutex); | ||
485 | victim->d_inode->i_mtime = CURRENT_TIME; | ||
486 | fsnotify_modify(victim); | ||
487 | mutex_unlock(&victim->d_inode->i_mutex); | ||
488 | rc = 0; | ||
489 | out: | ||
490 | dput(victim); | ||
491 | sysfs_put(victim_sd); | ||
492 | return rc; | ||
493 | } | ||
494 | |||
495 | |||
496 | /** | 578 | /** |
497 | * sysfs_chmod_file - update the modified mode value on an object attribute. | 579 | * sysfs_chmod_file - update the modified mode value on an object attribute. |
498 | * @kobj: object we're acting for. | 580 | * @kobj: object we're acting for. |
@@ -513,7 +595,9 @@ int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) | |||
513 | if (!victim_sd) | 595 | if (!victim_sd) |
514 | goto out; | 596 | goto out; |
515 | 597 | ||
598 | mutex_lock(&sysfs_rename_mutex); | ||
516 | victim = sysfs_get_dentry(victim_sd); | 599 | victim = sysfs_get_dentry(victim_sd); |
600 | mutex_unlock(&sysfs_rename_mutex); | ||
517 | if (IS_ERR(victim)) { | 601 | if (IS_ERR(victim)) { |
518 | rc = PTR_ERR(victim); | 602 | rc = PTR_ERR(victim); |
519 | victim = NULL; | 603 | victim = NULL; |
@@ -521,10 +605,19 @@ int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) | |||
521 | } | 605 | } |
522 | 606 | ||
523 | inode = victim->d_inode; | 607 | inode = victim->d_inode; |
608 | |||
524 | mutex_lock(&inode->i_mutex); | 609 | mutex_lock(&inode->i_mutex); |
610 | |||
525 | newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); | 611 | newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); |
526 | newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; | 612 | newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; |
527 | rc = notify_change(victim, &newattrs); | 613 | rc = notify_change(victim, &newattrs); |
614 | |||
615 | if (rc == 0) { | ||
616 | mutex_lock(&sysfs_mutex); | ||
617 | victim_sd->s_mode = newattrs.ia_mode; | ||
618 | mutex_unlock(&sysfs_mutex); | ||
619 | } | ||
620 | |||
528 | mutex_unlock(&inode->i_mutex); | 621 | mutex_unlock(&inode->i_mutex); |
529 | out: | 622 | out: |
530 | dput(victim); | 623 | dput(victim); |
@@ -632,4 +725,3 @@ EXPORT_SYMBOL_GPL(sysfs_schedule_callback); | |||
632 | 725 | ||
633 | EXPORT_SYMBOL_GPL(sysfs_create_file); | 726 | EXPORT_SYMBOL_GPL(sysfs_create_file); |
634 | EXPORT_SYMBOL_GPL(sysfs_remove_file); | 727 | EXPORT_SYMBOL_GPL(sysfs_remove_file); |
635 | EXPORT_SYMBOL_GPL(sysfs_update_file); | ||
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index f318b73c790c..d1972374655a 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c | |||
@@ -13,8 +13,6 @@ | |||
13 | #include <linux/dcache.h> | 13 | #include <linux/dcache.h> |
14 | #include <linux/namei.h> | 14 | #include <linux/namei.h> |
15 | #include <linux/err.h> | 15 | #include <linux/err.h> |
16 | #include <linux/fs.h> | ||
17 | #include <asm/semaphore.h> | ||
18 | #include "sysfs.h" | 16 | #include "sysfs.h" |
19 | 17 | ||
20 | 18 | ||
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 10d1b52899f1..9236635111f4 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c | |||
@@ -1,7 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * inode.c - basic inode and dentry operations. | 2 | * fs/sysfs/inode.c - basic sysfs inode and dentry operations |
3 | * | 3 | * |
4 | * sysfs is Copyright (c) 2001-3 Patrick Mochel | 4 | * Copyright (c) 2001-3 Patrick Mochel |
5 | * Copyright (c) 2007 SUSE Linux Products GmbH | ||
6 | * Copyright (c) 2007 Tejun Heo <teheo@suse.de> | ||
7 | * | ||
8 | * This file is released under the GPLv2. | ||
5 | * | 9 | * |
6 | * Please see Documentation/filesystems/sysfs.txt for more information. | 10 | * Please see Documentation/filesystems/sysfs.txt for more information. |
7 | */ | 11 | */ |
@@ -14,7 +18,6 @@ | |||
14 | #include <linux/capability.h> | 18 | #include <linux/capability.h> |
15 | #include <linux/errno.h> | 19 | #include <linux/errno.h> |
16 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
17 | #include <asm/semaphore.h> | ||
18 | #include "sysfs.h" | 21 | #include "sysfs.h" |
19 | 22 | ||
20 | extern struct super_block * sysfs_sb; | 23 | extern struct super_block * sysfs_sb; |
@@ -34,16 +37,6 @@ static const struct inode_operations sysfs_inode_operations ={ | |||
34 | .setattr = sysfs_setattr, | 37 | .setattr = sysfs_setattr, |
35 | }; | 38 | }; |
36 | 39 | ||
37 | void sysfs_delete_inode(struct inode *inode) | ||
38 | { | ||
39 | /* Free the shadowed directory inode operations */ | ||
40 | if (sysfs_is_shadowed_inode(inode)) { | ||
41 | kfree(inode->i_op); | ||
42 | inode->i_op = NULL; | ||
43 | } | ||
44 | return generic_delete_inode(inode); | ||
45 | } | ||
46 | |||
47 | int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) | 40 | int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) |
48 | { | 41 | { |
49 | struct inode * inode = dentry->d_inode; | 42 | struct inode * inode = dentry->d_inode; |
@@ -133,8 +126,22 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) | |||
133 | */ | 126 | */ |
134 | static struct lock_class_key sysfs_inode_imutex_key; | 127 | static struct lock_class_key sysfs_inode_imutex_key; |
135 | 128 | ||
129 | static int sysfs_count_nlink(struct sysfs_dirent *sd) | ||
130 | { | ||
131 | struct sysfs_dirent *child; | ||
132 | int nr = 0; | ||
133 | |||
134 | for (child = sd->s_dir.children; child; child = child->s_sibling) | ||
135 | if (sysfs_type(child) == SYSFS_DIR) | ||
136 | nr++; | ||
137 | |||
138 | return nr + 2; | ||
139 | } | ||
140 | |||
136 | static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) | 141 | static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) |
137 | { | 142 | { |
143 | struct bin_attribute *bin_attr; | ||
144 | |||
138 | inode->i_blocks = 0; | 145 | inode->i_blocks = 0; |
139 | inode->i_mapping->a_ops = &sysfs_aops; | 146 | inode->i_mapping->a_ops = &sysfs_aops; |
140 | inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; | 147 | inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; |
@@ -150,6 +157,32 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) | |||
150 | set_inode_attr(inode, sd->s_iattr); | 157 | set_inode_attr(inode, sd->s_iattr); |
151 | } else | 158 | } else |
152 | set_default_inode_attr(inode, sd->s_mode); | 159 | set_default_inode_attr(inode, sd->s_mode); |
160 | |||
161 | |||
162 | /* initialize inode according to type */ | ||
163 | switch (sysfs_type(sd)) { | ||
164 | case SYSFS_DIR: | ||
165 | inode->i_op = &sysfs_dir_inode_operations; | ||
166 | inode->i_fop = &sysfs_dir_operations; | ||
167 | inode->i_nlink = sysfs_count_nlink(sd); | ||
168 | break; | ||
169 | case SYSFS_KOBJ_ATTR: | ||
170 | inode->i_size = PAGE_SIZE; | ||
171 | inode->i_fop = &sysfs_file_operations; | ||
172 | break; | ||
173 | case SYSFS_KOBJ_BIN_ATTR: | ||
174 | bin_attr = sd->s_bin_attr.bin_attr; | ||
175 | inode->i_size = bin_attr->size; | ||
176 | inode->i_fop = &bin_fops; | ||
177 | break; | ||
178 | case SYSFS_KOBJ_LINK: | ||
179 | inode->i_op = &sysfs_symlink_inode_operations; | ||
180 | break; | ||
181 | default: | ||
182 | BUG(); | ||
183 | } | ||
184 | |||
185 | unlock_new_inode(inode); | ||
153 | } | 186 | } |
154 | 187 | ||
155 | /** | 188 | /** |
@@ -177,50 +210,24 @@ struct inode * sysfs_get_inode(struct sysfs_dirent *sd) | |||
177 | return inode; | 210 | return inode; |
178 | } | 211 | } |
179 | 212 | ||
180 | /** | ||
181 | * sysfs_instantiate - instantiate dentry | ||
182 | * @dentry: dentry to be instantiated | ||
183 | * @inode: inode associated with @sd | ||
184 | * | ||
185 | * Unlock @inode if locked and instantiate @dentry with @inode. | ||
186 | * | ||
187 | * LOCKING: | ||
188 | * None. | ||
189 | */ | ||
190 | void sysfs_instantiate(struct dentry *dentry, struct inode *inode) | ||
191 | { | ||
192 | BUG_ON(!dentry || dentry->d_inode); | ||
193 | |||
194 | if (inode->i_state & I_NEW) | ||
195 | unlock_new_inode(inode); | ||
196 | |||
197 | d_instantiate(dentry, inode); | ||
198 | } | ||
199 | |||
200 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) | 213 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) |
201 | { | 214 | { |
202 | struct sysfs_addrm_cxt acxt; | 215 | struct sysfs_addrm_cxt acxt; |
203 | struct sysfs_dirent **pos, *sd; | 216 | struct sysfs_dirent *sd; |
204 | 217 | ||
205 | if (!dir_sd) | 218 | if (!dir_sd) |
206 | return -ENOENT; | 219 | return -ENOENT; |
207 | 220 | ||
208 | sysfs_addrm_start(&acxt, dir_sd); | 221 | sysfs_addrm_start(&acxt, dir_sd); |
209 | 222 | ||
210 | for (pos = &dir_sd->s_children; *pos; pos = &(*pos)->s_sibling) { | 223 | sd = sysfs_find_dirent(dir_sd, name); |
211 | sd = *pos; | 224 | if (sd) |
212 | 225 | sysfs_remove_one(&acxt, sd); | |
213 | if (!sysfs_type(sd)) | 226 | |
214 | continue; | 227 | sysfs_addrm_finish(&acxt); |
215 | if (!strcmp(sd->s_name, name)) { | ||
216 | *pos = sd->s_sibling; | ||
217 | sd->s_sibling = NULL; | ||
218 | sysfs_remove_one(&acxt, sd); | ||
219 | break; | ||
220 | } | ||
221 | } | ||
222 | 228 | ||
223 | if (sysfs_addrm_finish(&acxt)) | 229 | if (sd) |
224 | return 0; | 230 | return 0; |
225 | return -ENOENT; | 231 | else |
232 | return -ENOENT; | ||
226 | } | 233 | } |
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index fbc7b65fe262..c76c540be3c8 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c | |||
@@ -1,5 +1,13 @@ | |||
1 | /* | 1 | /* |
2 | * mount.c - operations for initializing and mounting sysfs. | 2 | * fs/sysfs/symlink.c - operations for initializing and mounting sysfs |
3 | * | ||
4 | * Copyright (c) 2001-3 Patrick Mochel | ||
5 | * Copyright (c) 2007 SUSE Linux Products GmbH | ||
6 | * Copyright (c) 2007 Tejun Heo <teheo@suse.de> | ||
7 | * | ||
8 | * This file is released under the GPLv2. | ||
9 | * | ||
10 | * Please see Documentation/filesystems/sysfs.txt for more information. | ||
3 | */ | 11 | */ |
4 | 12 | ||
5 | #define DEBUG | 13 | #define DEBUG |
@@ -8,25 +16,25 @@ | |||
8 | #include <linux/mount.h> | 16 | #include <linux/mount.h> |
9 | #include <linux/pagemap.h> | 17 | #include <linux/pagemap.h> |
10 | #include <linux/init.h> | 18 | #include <linux/init.h> |
11 | #include <asm/semaphore.h> | ||
12 | 19 | ||
13 | #include "sysfs.h" | 20 | #include "sysfs.h" |
14 | 21 | ||
15 | /* Random magic number */ | 22 | /* Random magic number */ |
16 | #define SYSFS_MAGIC 0x62656572 | 23 | #define SYSFS_MAGIC 0x62656572 |
17 | 24 | ||
18 | struct vfsmount *sysfs_mount; | 25 | static struct vfsmount *sysfs_mount; |
19 | struct super_block * sysfs_sb = NULL; | 26 | struct super_block * sysfs_sb = NULL; |
20 | struct kmem_cache *sysfs_dir_cachep; | 27 | struct kmem_cache *sysfs_dir_cachep; |
21 | 28 | ||
22 | static const struct super_operations sysfs_ops = { | 29 | static const struct super_operations sysfs_ops = { |
23 | .statfs = simple_statfs, | 30 | .statfs = simple_statfs, |
24 | .drop_inode = sysfs_delete_inode, | 31 | .drop_inode = generic_delete_inode, |
25 | }; | 32 | }; |
26 | 33 | ||
27 | struct sysfs_dirent sysfs_root = { | 34 | struct sysfs_dirent sysfs_root = { |
35 | .s_name = "", | ||
28 | .s_count = ATOMIC_INIT(1), | 36 | .s_count = ATOMIC_INIT(1), |
29 | .s_flags = SYSFS_ROOT, | 37 | .s_flags = SYSFS_DIR, |
30 | .s_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, | 38 | .s_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, |
31 | .s_ino = 1, | 39 | .s_ino = 1, |
32 | }; | 40 | }; |
@@ -50,11 +58,6 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) | |||
50 | return -ENOMEM; | 58 | return -ENOMEM; |
51 | } | 59 | } |
52 | 60 | ||
53 | inode->i_op = &sysfs_dir_inode_operations; | ||
54 | inode->i_fop = &sysfs_dir_operations; | ||
55 | inc_nlink(inode); /* directory, account for "." */ | ||
56 | unlock_new_inode(inode); | ||
57 | |||
58 | /* instantiate and link root dentry */ | 61 | /* instantiate and link root dentry */ |
59 | root = d_alloc_root(inode); | 62 | root = d_alloc_root(inode); |
60 | if (!root) { | 63 | if (!root) { |
@@ -62,7 +65,6 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) | |||
62 | iput(inode); | 65 | iput(inode); |
63 | return -ENOMEM; | 66 | return -ENOMEM; |
64 | } | 67 | } |
65 | sysfs_root.s_dentry = root; | ||
66 | root->d_fsdata = &sysfs_root; | 68 | root->d_fsdata = &sysfs_root; |
67 | sb->s_root = root; | 69 | sb->s_root = root; |
68 | return 0; | 70 | return 0; |
@@ -77,7 +79,7 @@ static int sysfs_get_sb(struct file_system_type *fs_type, | |||
77 | static struct file_system_type sysfs_fs_type = { | 79 | static struct file_system_type sysfs_fs_type = { |
78 | .name = "sysfs", | 80 | .name = "sysfs", |
79 | .get_sb = sysfs_get_sb, | 81 | .get_sb = sysfs_get_sb, |
80 | .kill_sb = kill_litter_super, | 82 | .kill_sb = kill_anon_super, |
81 | }; | 83 | }; |
82 | 84 | ||
83 | int __init sysfs_init(void) | 85 | int __init sysfs_init(void) |
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 4ce687f0b5d0..3eac20c63c41 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c | |||
@@ -1,5 +1,13 @@ | |||
1 | /* | 1 | /* |
2 | * symlink.c - operations for sysfs symlinks. | 2 | * fs/sysfs/symlink.c - sysfs symlink implementation |
3 | * | ||
4 | * Copyright (c) 2001-3 Patrick Mochel | ||
5 | * Copyright (c) 2007 SUSE Linux Products GmbH | ||
6 | * Copyright (c) 2007 Tejun Heo <teheo@suse.de> | ||
7 | * | ||
8 | * This file is released under the GPLv2. | ||
9 | * | ||
10 | * Please see Documentation/filesystems/sysfs.txt for more information. | ||
3 | */ | 11 | */ |
4 | 12 | ||
5 | #include <linux/fs.h> | 13 | #include <linux/fs.h> |
@@ -7,7 +15,7 @@ | |||
7 | #include <linux/module.h> | 15 | #include <linux/module.h> |
8 | #include <linux/kobject.h> | 16 | #include <linux/kobject.h> |
9 | #include <linux/namei.h> | 17 | #include <linux/namei.h> |
10 | #include <asm/semaphore.h> | 18 | #include <linux/mutex.h> |
11 | 19 | ||
12 | #include "sysfs.h" | 20 | #include "sysfs.h" |
13 | 21 | ||
@@ -60,10 +68,9 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char | |||
60 | 68 | ||
61 | BUG_ON(!name); | 69 | BUG_ON(!name); |
62 | 70 | ||
63 | if (!kobj) { | 71 | if (!kobj) |
64 | if (sysfs_mount && sysfs_mount->mnt_sb) | 72 | parent_sd = &sysfs_root; |
65 | parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata; | 73 | else |
66 | } else | ||
67 | parent_sd = kobj->sd; | 74 | parent_sd = kobj->sd; |
68 | 75 | ||
69 | error = -EFAULT; | 76 | error = -EFAULT; |
@@ -87,20 +94,15 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char | |||
87 | if (!sd) | 94 | if (!sd) |
88 | goto out_put; | 95 | goto out_put; |
89 | 96 | ||
90 | sd->s_elem.symlink.target_sd = target_sd; | 97 | sd->s_symlink.target_sd = target_sd; |
91 | target_sd = NULL; /* reference is now owned by the symlink */ | 98 | target_sd = NULL; /* reference is now owned by the symlink */ |
92 | 99 | ||
93 | sysfs_addrm_start(&acxt, parent_sd); | 100 | sysfs_addrm_start(&acxt, parent_sd); |
101 | error = sysfs_add_one(&acxt, sd); | ||
102 | sysfs_addrm_finish(&acxt); | ||
94 | 103 | ||
95 | if (!sysfs_find_dirent(parent_sd, name)) { | 104 | if (error) |
96 | sysfs_add_one(&acxt, sd); | ||
97 | sysfs_link_sibling(sd); | ||
98 | } | ||
99 | |||
100 | if (!sysfs_addrm_finish(&acxt)) { | ||
101 | error = -EEXIST; | ||
102 | goto out_put; | 105 | goto out_put; |
103 | } | ||
104 | 106 | ||
105 | return 0; | 107 | return 0; |
106 | 108 | ||
@@ -148,7 +150,7 @@ static int sysfs_getlink(struct dentry *dentry, char * path) | |||
148 | { | 150 | { |
149 | struct sysfs_dirent *sd = dentry->d_fsdata; | 151 | struct sysfs_dirent *sd = dentry->d_fsdata; |
150 | struct sysfs_dirent *parent_sd = sd->s_parent; | 152 | struct sysfs_dirent *parent_sd = sd->s_parent; |
151 | struct sysfs_dirent *target_sd = sd->s_elem.symlink.target_sd; | 153 | struct sysfs_dirent *target_sd = sd->s_symlink.target_sd; |
152 | int error; | 154 | int error; |
153 | 155 | ||
154 | mutex_lock(&sysfs_mutex); | 156 | mutex_lock(&sysfs_mutex); |
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 6b8c8d76d308..f0326f281d1c 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h | |||
@@ -1,20 +1,39 @@ | |||
1 | /* | ||
2 | * fs/sysfs/sysfs.h - sysfs internal header file | ||
3 | * | ||
4 | * Copyright (c) 2001-3 Patrick Mochel | ||
5 | * Copyright (c) 2007 SUSE Linux Products GmbH | ||
6 | * Copyright (c) 2007 Tejun Heo <teheo@suse.de> | ||
7 | * | ||
8 | * This file is released under the GPLv2. | ||
9 | */ | ||
10 | |||
11 | struct sysfs_open_dirent; | ||
12 | |||
13 | /* type-specific structures for sysfs_dirent->s_* union members */ | ||
1 | struct sysfs_elem_dir { | 14 | struct sysfs_elem_dir { |
2 | struct kobject * kobj; | 15 | struct kobject *kobj; |
16 | /* children list starts here and goes through sd->s_sibling */ | ||
17 | struct sysfs_dirent *children; | ||
3 | }; | 18 | }; |
4 | 19 | ||
5 | struct sysfs_elem_symlink { | 20 | struct sysfs_elem_symlink { |
6 | struct sysfs_dirent * target_sd; | 21 | struct sysfs_dirent *target_sd; |
7 | }; | 22 | }; |
8 | 23 | ||
9 | struct sysfs_elem_attr { | 24 | struct sysfs_elem_attr { |
10 | struct attribute * attr; | 25 | struct attribute *attr; |
26 | struct sysfs_open_dirent *open; | ||
11 | }; | 27 | }; |
12 | 28 | ||
13 | struct sysfs_elem_bin_attr { | 29 | struct sysfs_elem_bin_attr { |
14 | struct bin_attribute * bin_attr; | 30 | struct bin_attribute *bin_attr; |
15 | }; | 31 | }; |
16 | 32 | ||
17 | /* | 33 | /* |
34 | * sysfs_dirent - the building block of sysfs hierarchy. Each and | ||
35 | * every sysfs node is represented by single sysfs_dirent. | ||
36 | * | ||
18 | * As long as s_count reference is held, the sysfs_dirent itself is | 37 | * As long as s_count reference is held, the sysfs_dirent itself is |
19 | * accessible. Dereferencing s_elem or any other outer entity | 38 | * accessible. Dereferencing s_elem or any other outer entity |
20 | * requires s_active reference. | 39 | * requires s_active reference. |
@@ -22,28 +41,43 @@ struct sysfs_elem_bin_attr { | |||
22 | struct sysfs_dirent { | 41 | struct sysfs_dirent { |
23 | atomic_t s_count; | 42 | atomic_t s_count; |
24 | atomic_t s_active; | 43 | atomic_t s_active; |
25 | struct sysfs_dirent * s_parent; | 44 | struct sysfs_dirent *s_parent; |
26 | struct sysfs_dirent * s_sibling; | 45 | struct sysfs_dirent *s_sibling; |
27 | struct sysfs_dirent * s_children; | 46 | const char *s_name; |
28 | const char * s_name; | ||
29 | 47 | ||
30 | union { | 48 | union { |
31 | struct sysfs_elem_dir dir; | 49 | struct sysfs_elem_dir s_dir; |
32 | struct sysfs_elem_symlink symlink; | 50 | struct sysfs_elem_symlink s_symlink; |
33 | struct sysfs_elem_attr attr; | 51 | struct sysfs_elem_attr s_attr; |
34 | struct sysfs_elem_bin_attr bin_attr; | 52 | struct sysfs_elem_bin_attr s_bin_attr; |
35 | } s_elem; | 53 | }; |
36 | 54 | ||
37 | unsigned int s_flags; | 55 | unsigned int s_flags; |
38 | umode_t s_mode; | ||
39 | ino_t s_ino; | 56 | ino_t s_ino; |
40 | struct dentry * s_dentry; | 57 | umode_t s_mode; |
41 | struct iattr * s_iattr; | 58 | struct iattr *s_iattr; |
42 | atomic_t s_event; | ||
43 | }; | 59 | }; |
44 | 60 | ||
45 | #define SD_DEACTIVATED_BIAS INT_MIN | 61 | #define SD_DEACTIVATED_BIAS INT_MIN |
62 | |||
63 | #define SYSFS_TYPE_MASK 0x00ff | ||
64 | #define SYSFS_DIR 0x0001 | ||
65 | #define SYSFS_KOBJ_ATTR 0x0002 | ||
66 | #define SYSFS_KOBJ_BIN_ATTR 0x0004 | ||
67 | #define SYSFS_KOBJ_LINK 0x0008 | ||
68 | #define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) | ||
69 | |||
70 | #define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK | ||
71 | #define SYSFS_FLAG_REMOVED 0x0200 | ||
72 | |||
73 | static inline unsigned int sysfs_type(struct sysfs_dirent *sd) | ||
74 | { | ||
75 | return sd->s_flags & SYSFS_TYPE_MASK; | ||
76 | } | ||
46 | 77 | ||
78 | /* | ||
79 | * Context structure to be used while adding/removing nodes. | ||
80 | */ | ||
47 | struct sysfs_addrm_cxt { | 81 | struct sysfs_addrm_cxt { |
48 | struct sysfs_dirent *parent_sd; | 82 | struct sysfs_dirent *parent_sd; |
49 | struct inode *parent_inode; | 83 | struct inode *parent_inode; |
@@ -51,63 +85,47 @@ struct sysfs_addrm_cxt { | |||
51 | int cnt; | 85 | int cnt; |
52 | }; | 86 | }; |
53 | 87 | ||
54 | extern struct vfsmount * sysfs_mount; | 88 | /* |
89 | * mount.c | ||
90 | */ | ||
55 | extern struct sysfs_dirent sysfs_root; | 91 | extern struct sysfs_dirent sysfs_root; |
92 | extern struct super_block *sysfs_sb; | ||
56 | extern struct kmem_cache *sysfs_dir_cachep; | 93 | extern struct kmem_cache *sysfs_dir_cachep; |
57 | 94 | ||
58 | extern struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd); | 95 | /* |
59 | extern void sysfs_link_sibling(struct sysfs_dirent *sd); | 96 | * dir.c |
60 | extern void sysfs_unlink_sibling(struct sysfs_dirent *sd); | 97 | */ |
61 | extern struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd); | ||
62 | extern void sysfs_put_active(struct sysfs_dirent *sd); | ||
63 | extern struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd); | ||
64 | extern void sysfs_put_active_two(struct sysfs_dirent *sd); | ||
65 | extern void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, | ||
66 | struct sysfs_dirent *parent_sd); | ||
67 | extern void sysfs_add_one(struct sysfs_addrm_cxt *acxt, | ||
68 | struct sysfs_dirent *sd); | ||
69 | extern void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, | ||
70 | struct sysfs_dirent *sd); | ||
71 | extern int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt); | ||
72 | |||
73 | extern void sysfs_delete_inode(struct inode *inode); | ||
74 | extern struct inode * sysfs_get_inode(struct sysfs_dirent *sd); | ||
75 | extern void sysfs_instantiate(struct dentry *dentry, struct inode *inode); | ||
76 | |||
77 | extern void release_sysfs_dirent(struct sysfs_dirent * sd); | ||
78 | extern struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, | ||
79 | const unsigned char *name); | ||
80 | extern struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, | ||
81 | const unsigned char *name); | ||
82 | extern struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, | ||
83 | int type); | ||
84 | |||
85 | extern int sysfs_add_file(struct sysfs_dirent *dir_sd, | ||
86 | const struct attribute *attr, int type); | ||
87 | extern int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name); | ||
88 | extern struct sysfs_dirent *sysfs_find(struct sysfs_dirent *dir, const char * name); | ||
89 | |||
90 | extern int sysfs_create_subdir(struct kobject *kobj, const char *name, | ||
91 | struct sysfs_dirent **p_sd); | ||
92 | extern void sysfs_remove_subdir(struct sysfs_dirent *sd); | ||
93 | |||
94 | extern int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); | ||
95 | |||
96 | extern spinlock_t sysfs_assoc_lock; | ||
97 | extern struct mutex sysfs_mutex; | 98 | extern struct mutex sysfs_mutex; |
98 | extern struct super_block * sysfs_sb; | 99 | extern struct mutex sysfs_rename_mutex; |
100 | extern spinlock_t sysfs_assoc_lock; | ||
101 | |||
99 | extern const struct file_operations sysfs_dir_operations; | 102 | extern const struct file_operations sysfs_dir_operations; |
100 | extern const struct file_operations sysfs_file_operations; | ||
101 | extern const struct file_operations bin_fops; | ||
102 | extern const struct inode_operations sysfs_dir_inode_operations; | 103 | extern const struct inode_operations sysfs_dir_inode_operations; |
103 | extern const struct inode_operations sysfs_symlink_inode_operations; | ||
104 | |||
105 | static inline unsigned int sysfs_type(struct sysfs_dirent *sd) | ||
106 | { | ||
107 | return sd->s_flags & SYSFS_TYPE_MASK; | ||
108 | } | ||
109 | 104 | ||
110 | static inline struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd) | 105 | struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd); |
106 | struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd); | ||
107 | void sysfs_put_active(struct sysfs_dirent *sd); | ||
108 | struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd); | ||
109 | void sysfs_put_active_two(struct sysfs_dirent *sd); | ||
110 | void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, | ||
111 | struct sysfs_dirent *parent_sd); | ||
112 | int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd); | ||
113 | void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd); | ||
114 | void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt); | ||
115 | |||
116 | struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, | ||
117 | const unsigned char *name); | ||
118 | struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, | ||
119 | const unsigned char *name); | ||
120 | struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type); | ||
121 | |||
122 | void release_sysfs_dirent(struct sysfs_dirent *sd); | ||
123 | |||
124 | int sysfs_create_subdir(struct kobject *kobj, const char *name, | ||
125 | struct sysfs_dirent **p_sd); | ||
126 | void sysfs_remove_subdir(struct sysfs_dirent *sd); | ||
127 | |||
128 | static inline struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd) | ||
111 | { | 129 | { |
112 | if (sd) { | 130 | if (sd) { |
113 | WARN_ON(!atomic_read(&sd->s_count)); | 131 | WARN_ON(!atomic_read(&sd->s_count)); |
@@ -116,13 +134,33 @@ static inline struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd) | |||
116 | return sd; | 134 | return sd; |
117 | } | 135 | } |
118 | 136 | ||
119 | static inline void sysfs_put(struct sysfs_dirent * sd) | 137 | static inline void sysfs_put(struct sysfs_dirent *sd) |
120 | { | 138 | { |
121 | if (sd && atomic_dec_and_test(&sd->s_count)) | 139 | if (sd && atomic_dec_and_test(&sd->s_count)) |
122 | release_sysfs_dirent(sd); | 140 | release_sysfs_dirent(sd); |
123 | } | 141 | } |
124 | 142 | ||
125 | static inline int sysfs_is_shadowed_inode(struct inode *inode) | 143 | /* |
126 | { | 144 | * inode.c |
127 | return S_ISDIR(inode->i_mode) && inode->i_op->follow_link; | 145 | */ |
128 | } | 146 | struct inode *sysfs_get_inode(struct sysfs_dirent *sd); |
147 | int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); | ||
148 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name); | ||
149 | |||
150 | /* | ||
151 | * file.c | ||
152 | */ | ||
153 | extern const struct file_operations sysfs_file_operations; | ||
154 | |||
155 | int sysfs_add_file(struct sysfs_dirent *dir_sd, | ||
156 | const struct attribute *attr, int type); | ||
157 | |||
158 | /* | ||
159 | * bin.c | ||
160 | */ | ||
161 | extern const struct file_operations bin_fops; | ||
162 | |||
163 | /* | ||
164 | * symlink.c | ||
165 | */ | ||
166 | extern const struct inode_operations sysfs_symlink_inode_operations; | ||