diff options
Diffstat (limited to 'fs/sysfs/file.c')
-rw-r--r-- | fs/sysfs/file.c | 82 |
1 files changed, 58 insertions, 24 deletions
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 9cfe53e1e00d..c0e117649a4d 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <linux/kobject.h> | 7 | #include <linux/kobject.h> |
8 | #include <linux/namei.h> | 8 | #include <linux/namei.h> |
9 | #include <linux/poll.h> | 9 | #include <linux/poll.h> |
10 | #include <linux/list.h> | ||
10 | #include <asm/uaccess.h> | 11 | #include <asm/uaccess.h> |
11 | #include <asm/semaphore.h> | 12 | #include <asm/semaphore.h> |
12 | 13 | ||
@@ -50,17 +51,29 @@ static struct sysfs_ops subsys_sysfs_ops = { | |||
50 | .store = subsys_attr_store, | 51 | .store = subsys_attr_store, |
51 | }; | 52 | }; |
52 | 53 | ||
54 | /** | ||
55 | * add_to_collection - add buffer to a collection | ||
56 | * @buffer: buffer to be added | ||
57 | * @node inode of set to add to | ||
58 | */ | ||
53 | 59 | ||
54 | struct sysfs_buffer { | 60 | static inline void |
55 | size_t count; | 61 | add_to_collection(struct sysfs_buffer *buffer, struct inode *node) |
56 | loff_t pos; | 62 | { |
57 | char * page; | 63 | struct sysfs_buffer_collection *set = node->i_private; |
58 | struct sysfs_ops * ops; | ||
59 | struct semaphore sem; | ||
60 | int needs_read_fill; | ||
61 | int event; | ||
62 | }; | ||
63 | 64 | ||
65 | mutex_lock(&node->i_mutex); | ||
66 | list_add(&buffer->associates, &set->associates); | ||
67 | mutex_unlock(&node->i_mutex); | ||
68 | } | ||
69 | |||
70 | static inline void | ||
71 | remove_from_collection(struct sysfs_buffer *buffer, struct inode *node) | ||
72 | { | ||
73 | mutex_lock(&node->i_mutex); | ||
74 | list_del(&buffer->associates); | ||
75 | mutex_unlock(&node->i_mutex); | ||
76 | } | ||
64 | 77 | ||
65 | /** | 78 | /** |
66 | * fill_read_buffer - allocate and fill buffer from object. | 79 | * fill_read_buffer - allocate and fill buffer from object. |
@@ -70,7 +83,8 @@ struct sysfs_buffer { | |||
70 | * Allocate @buffer->page, if it hasn't been already, then call the | 83 | * Allocate @buffer->page, if it hasn't been already, then call the |
71 | * kobject's show() method to fill the buffer with this attribute's | 84 | * kobject's show() method to fill the buffer with this attribute's |
72 | * data. | 85 | * data. |
73 | * This is called only once, on the file's first read. | 86 | * This is called only once, on the file's first read unless an error |
87 | * is returned. | ||
74 | */ | 88 | */ |
75 | static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer) | 89 | static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer) |
76 | { | 90 | { |
@@ -88,12 +102,13 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer | |||
88 | 102 | ||
89 | buffer->event = atomic_read(&sd->s_event); | 103 | buffer->event = atomic_read(&sd->s_event); |
90 | count = ops->show(kobj,attr,buffer->page); | 104 | count = ops->show(kobj,attr,buffer->page); |
91 | buffer->needs_read_fill = 0; | ||
92 | BUG_ON(count > (ssize_t)PAGE_SIZE); | 105 | BUG_ON(count > (ssize_t)PAGE_SIZE); |
93 | if (count >= 0) | 106 | if (count >= 0) { |
107 | buffer->needs_read_fill = 0; | ||
94 | buffer->count = count; | 108 | buffer->count = count; |
95 | else | 109 | } else { |
96 | ret = count; | 110 | ret = count; |
111 | } | ||
97 | return ret; | 112 | return ret; |
98 | } | 113 | } |
99 | 114 | ||
@@ -153,6 +168,10 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos) | |||
153 | ssize_t retval = 0; | 168 | ssize_t retval = 0; |
154 | 169 | ||
155 | down(&buffer->sem); | 170 | down(&buffer->sem); |
171 | if (buffer->orphaned) { | ||
172 | retval = -ENODEV; | ||
173 | goto out; | ||
174 | } | ||
156 | if (buffer->needs_read_fill) { | 175 | if (buffer->needs_read_fill) { |
157 | if ((retval = fill_read_buffer(file->f_path.dentry,buffer))) | 176 | if ((retval = fill_read_buffer(file->f_path.dentry,buffer))) |
158 | goto out; | 177 | goto out; |
@@ -165,7 +184,6 @@ out: | |||
165 | return retval; | 184 | return retval; |
166 | } | 185 | } |
167 | 186 | ||
168 | |||
169 | /** | 187 | /** |
170 | * fill_write_buffer - copy buffer from userspace. | 188 | * fill_write_buffer - copy buffer from userspace. |
171 | * @buffer: data buffer for file. | 189 | * @buffer: data buffer for file. |
@@ -243,19 +261,25 @@ sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t | |||
243 | ssize_t len; | 261 | ssize_t len; |
244 | 262 | ||
245 | down(&buffer->sem); | 263 | down(&buffer->sem); |
264 | if (buffer->orphaned) { | ||
265 | len = -ENODEV; | ||
266 | goto out; | ||
267 | } | ||
246 | len = fill_write_buffer(buffer, buf, count); | 268 | len = fill_write_buffer(buffer, buf, count); |
247 | if (len > 0) | 269 | if (len > 0) |
248 | len = flush_write_buffer(file->f_path.dentry, buffer, len); | 270 | len = flush_write_buffer(file->f_path.dentry, buffer, len); |
249 | if (len > 0) | 271 | if (len > 0) |
250 | *ppos += len; | 272 | *ppos += len; |
273 | out: | ||
251 | up(&buffer->sem); | 274 | up(&buffer->sem); |
252 | return len; | 275 | return len; |
253 | } | 276 | } |
254 | 277 | ||
255 | static int check_perm(struct inode * inode, struct file * file) | 278 | static int sysfs_open_file(struct inode *inode, struct file *file) |
256 | { | 279 | { |
257 | struct kobject *kobj = sysfs_get_kobject(file->f_path.dentry->d_parent); | 280 | struct kobject *kobj = sysfs_get_kobject(file->f_path.dentry->d_parent); |
258 | struct attribute * attr = to_attr(file->f_path.dentry); | 281 | struct attribute * attr = to_attr(file->f_path.dentry); |
282 | struct sysfs_buffer_collection *set; | ||
259 | struct sysfs_buffer * buffer; | 283 | struct sysfs_buffer * buffer; |
260 | struct sysfs_ops * ops = NULL; | 284 | struct sysfs_ops * ops = NULL; |
261 | int error = 0; | 285 | int error = 0; |
@@ -285,6 +309,18 @@ static int check_perm(struct inode * inode, struct file * file) | |||
285 | if (!ops) | 309 | if (!ops) |
286 | goto Eaccess; | 310 | goto Eaccess; |
287 | 311 | ||
312 | /* make sure we have a collection to add our buffers to */ | ||
313 | mutex_lock(&inode->i_mutex); | ||
314 | if (!(set = inode->i_private)) { | ||
315 | if (!(set = inode->i_private = kmalloc(sizeof(struct sysfs_buffer_collection), GFP_KERNEL))) { | ||
316 | error = -ENOMEM; | ||
317 | goto Done; | ||
318 | } else { | ||
319 | INIT_LIST_HEAD(&set->associates); | ||
320 | } | ||
321 | } | ||
322 | mutex_unlock(&inode->i_mutex); | ||
323 | |||
288 | /* File needs write support. | 324 | /* File needs write support. |
289 | * The inode's perms must say it's ok, | 325 | * The inode's perms must say it's ok, |
290 | * and we must have a store method. | 326 | * and we must have a store method. |
@@ -310,9 +346,11 @@ static int check_perm(struct inode * inode, struct file * file) | |||
310 | */ | 346 | */ |
311 | buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL); | 347 | buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL); |
312 | if (buffer) { | 348 | if (buffer) { |
349 | INIT_LIST_HEAD(&buffer->associates); | ||
313 | init_MUTEX(&buffer->sem); | 350 | init_MUTEX(&buffer->sem); |
314 | buffer->needs_read_fill = 1; | 351 | buffer->needs_read_fill = 1; |
315 | buffer->ops = ops; | 352 | buffer->ops = ops; |
353 | add_to_collection(buffer, inode); | ||
316 | file->private_data = buffer; | 354 | file->private_data = buffer; |
317 | } else | 355 | } else |
318 | error = -ENOMEM; | 356 | error = -ENOMEM; |
@@ -325,16 +363,11 @@ static int check_perm(struct inode * inode, struct file * file) | |||
325 | error = -EACCES; | 363 | error = -EACCES; |
326 | module_put(attr->owner); | 364 | module_put(attr->owner); |
327 | Done: | 365 | Done: |
328 | if (error && kobj) | 366 | if (error) |
329 | kobject_put(kobj); | 367 | kobject_put(kobj); |
330 | return error; | 368 | return error; |
331 | } | 369 | } |
332 | 370 | ||
333 | static int sysfs_open_file(struct inode * inode, struct file * filp) | ||
334 | { | ||
335 | return check_perm(inode,filp); | ||
336 | } | ||
337 | |||
338 | static int sysfs_release(struct inode * inode, struct file * filp) | 371 | static int sysfs_release(struct inode * inode, struct file * filp) |
339 | { | 372 | { |
340 | struct kobject * kobj = to_kobj(filp->f_path.dentry->d_parent); | 373 | struct kobject * kobj = to_kobj(filp->f_path.dentry->d_parent); |
@@ -342,8 +375,9 @@ static int sysfs_release(struct inode * inode, struct file * filp) | |||
342 | struct module * owner = attr->owner; | 375 | struct module * owner = attr->owner; |
343 | struct sysfs_buffer * buffer = filp->private_data; | 376 | struct sysfs_buffer * buffer = filp->private_data; |
344 | 377 | ||
345 | if (kobj) | 378 | if (buffer) |
346 | kobject_put(kobj); | 379 | remove_from_collection(buffer, inode); |
380 | kobject_put(kobj); | ||
347 | /* After this point, attr should not be accessed. */ | 381 | /* After this point, attr should not be accessed. */ |
348 | module_put(owner); | 382 | module_put(owner); |
349 | 383 | ||
@@ -548,7 +582,7 @@ EXPORT_SYMBOL_GPL(sysfs_chmod_file); | |||
548 | 582 | ||
549 | void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr) | 583 | void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr) |
550 | { | 584 | { |
551 | sysfs_hash_and_remove(kobj->dentry,attr->name); | 585 | sysfs_hash_and_remove(kobj->dentry, attr->name); |
552 | } | 586 | } |
553 | 587 | ||
554 | 588 | ||