aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/sysfs/bin.c6
-rw-r--r--fs/sysfs/dir.c214
-rw-r--r--fs/sysfs/file.c82
-rw-r--r--fs/sysfs/group.c2
-rw-r--r--fs/sysfs/inode.c36
-rw-r--r--fs/sysfs/mount.c11
-rw-r--r--fs/sysfs/symlink.c1
-rw-r--r--fs/sysfs/sysfs.h21
8 files changed, 305 insertions, 68 deletions
diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c
index e8f540d38d48..d3b9f5f07db1 100644
--- a/fs/sysfs/bin.c
+++ b/fs/sysfs/bin.c
@@ -16,6 +16,7 @@
16#include <linux/slab.h> 16#include <linux/slab.h>
17 17
18#include <asm/uaccess.h> 18#include <asm/uaccess.h>
19#include <asm/semaphore.h>
19 20
20#include "sysfs.h" 21#include "sysfs.h"
21 22
@@ -146,7 +147,7 @@ static int open(struct inode * inode, struct file * file)
146 Error: 147 Error:
147 module_put(attr->attr.owner); 148 module_put(attr->attr.owner);
148 Done: 149 Done:
149 if (error && kobj) 150 if (error)
150 kobject_put(kobj); 151 kobject_put(kobj);
151 return error; 152 return error;
152} 153}
@@ -157,8 +158,7 @@ static int release(struct inode * inode, struct file * file)
157 struct bin_attribute * attr = to_bin_attr(file->f_path.dentry); 158 struct bin_attribute * attr = to_bin_attr(file->f_path.dentry);
158 u8 * buffer = file->private_data; 159 u8 * buffer = file->private_data;
159 160
160 if (kobj) 161 kobject_put(kobj);
161 kobject_put(kobj);
162 module_put(attr->attr.owner); 162 module_put(attr->attr.owner);
163 kfree(buffer); 163 kfree(buffer);
164 return 0; 164 return 0;
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 511edef8b321..9dcdf556c99c 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -9,6 +9,7 @@
9#include <linux/module.h> 9#include <linux/module.h>
10#include <linux/kobject.h> 10#include <linux/kobject.h>
11#include <linux/namei.h> 11#include <linux/namei.h>
12#include <asm/semaphore.h>
12#include "sysfs.h" 13#include "sysfs.h"
13 14
14DECLARE_RWSEM(sysfs_rename_sem); 15DECLARE_RWSEM(sysfs_rename_sem);
@@ -32,8 +33,7 @@ static struct dentry_operations sysfs_dentry_ops = {
32/* 33/*
33 * Allocates a new sysfs_dirent and links it to the parent sysfs_dirent 34 * Allocates a new sysfs_dirent and links it to the parent sysfs_dirent
34 */ 35 */
35static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd, 36static struct sysfs_dirent * __sysfs_new_dirent(void * element)
36 void * element)
37{ 37{
38 struct sysfs_dirent * sd; 38 struct sysfs_dirent * sd;
39 39
@@ -45,12 +45,28 @@ static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd,
45 atomic_set(&sd->s_count, 1); 45 atomic_set(&sd->s_count, 1);
46 atomic_set(&sd->s_event, 1); 46 atomic_set(&sd->s_event, 1);
47 INIT_LIST_HEAD(&sd->s_children); 47 INIT_LIST_HEAD(&sd->s_children);
48 list_add(&sd->s_sibling, &parent_sd->s_children); 48 INIT_LIST_HEAD(&sd->s_sibling);
49 sd->s_element = element; 49 sd->s_element = element;
50 50
51 return sd; 51 return sd;
52} 52}
53 53
54static void __sysfs_list_dirent(struct sysfs_dirent *parent_sd,
55 struct sysfs_dirent *sd)
56{
57 if (sd)
58 list_add(&sd->s_sibling, &parent_sd->s_children);
59}
60
61static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent *parent_sd,
62 void * element)
63{
64 struct sysfs_dirent *sd;
65 sd = __sysfs_new_dirent(element);
66 __sysfs_list_dirent(parent_sd, sd);
67 return sd;
68}
69
54/* 70/*
55 * 71 *
56 * Return -EEXIST if there is already a sysfs element with the same name for 72 * Return -EEXIST if there is already a sysfs element with the same name for
@@ -77,14 +93,14 @@ int sysfs_dirent_exist(struct sysfs_dirent *parent_sd,
77} 93}
78 94
79 95
80int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry, 96static struct sysfs_dirent *
81 void * element, umode_t mode, int type) 97__sysfs_make_dirent(struct dentry *dentry, void *element, mode_t mode, int type)
82{ 98{
83 struct sysfs_dirent * sd; 99 struct sysfs_dirent * sd;
84 100
85 sd = sysfs_new_dirent(parent_sd, element); 101 sd = __sysfs_new_dirent(element);
86 if (!sd) 102 if (!sd)
87 return -ENOMEM; 103 goto out;
88 104
89 sd->s_mode = mode; 105 sd->s_mode = mode;
90 sd->s_type = type; 106 sd->s_type = type;
@@ -94,7 +110,19 @@ int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry,
94 dentry->d_op = &sysfs_dentry_ops; 110 dentry->d_op = &sysfs_dentry_ops;
95 } 111 }
96 112
97 return 0; 113out:
114 return sd;
115}
116
117int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry,
118 void * element, umode_t mode, int type)
119{
120 struct sysfs_dirent *sd;
121
122 sd = __sysfs_make_dirent(dentry, element, mode, type);
123 __sysfs_list_dirent(parent_sd, sd);
124
125 return sd ? 0 : -ENOMEM;
98} 126}
99 127
100static int init_dir(struct inode * inode) 128static int init_dir(struct inode * inode)
@@ -165,11 +193,11 @@ int sysfs_create_subdir(struct kobject * k, const char * n, struct dentry ** d)
165 193
166/** 194/**
167 * sysfs_create_dir - create a directory for an object. 195 * sysfs_create_dir - create a directory for an object.
168 * @parent: parent parent object.
169 * @kobj: object we're creating directory for. 196 * @kobj: object we're creating directory for.
197 * @shadow_parent: parent parent object.
170 */ 198 */
171 199
172int sysfs_create_dir(struct kobject * kobj) 200int sysfs_create_dir(struct kobject * kobj, struct dentry *shadow_parent)
173{ 201{
174 struct dentry * dentry = NULL; 202 struct dentry * dentry = NULL;
175 struct dentry * parent; 203 struct dentry * parent;
@@ -177,7 +205,9 @@ int sysfs_create_dir(struct kobject * kobj)
177 205
178 BUG_ON(!kobj); 206 BUG_ON(!kobj);
179 207
180 if (kobj->parent) 208 if (shadow_parent)
209 parent = shadow_parent;
210 else if (kobj->parent)
181 parent = kobj->parent->dentry; 211 parent = kobj->parent->dentry;
182 else if (sysfs_mount && sysfs_mount->mnt_sb) 212 else if (sysfs_mount && sysfs_mount->mnt_sb)
183 parent = sysfs_mount->mnt_sb->s_root; 213 parent = sysfs_mount->mnt_sb->s_root;
@@ -298,21 +328,12 @@ void sysfs_remove_subdir(struct dentry * d)
298} 328}
299 329
300 330
301/** 331static void __sysfs_remove_dir(struct dentry *dentry)
302 * sysfs_remove_dir - remove an object's directory.
303 * @kobj: object.
304 *
305 * The only thing special about this is that we remove any files in
306 * the directory before we remove the directory, and we've inlined
307 * what used to be sysfs_rmdir() below, instead of calling separately.
308 */
309
310void sysfs_remove_dir(struct kobject * kobj)
311{ 332{
312 struct dentry * dentry = dget(kobj->dentry);
313 struct sysfs_dirent * parent_sd; 333 struct sysfs_dirent * parent_sd;
314 struct sysfs_dirent * sd, * tmp; 334 struct sysfs_dirent * sd, * tmp;
315 335
336 dget(dentry);
316 if (!dentry) 337 if (!dentry)
317 return; 338 return;
318 339
@@ -333,32 +354,60 @@ void sysfs_remove_dir(struct kobject * kobj)
333 * Drop reference from dget() on entrance. 354 * Drop reference from dget() on entrance.
334 */ 355 */
335 dput(dentry); 356 dput(dentry);
357}
358
359/**
360 * sysfs_remove_dir - remove an object's directory.
361 * @kobj: object.
362 *
363 * The only thing special about this is that we remove any files in
364 * the directory before we remove the directory, and we've inlined
365 * what used to be sysfs_rmdir() below, instead of calling separately.
366 */
367
368void sysfs_remove_dir(struct kobject * kobj)
369{
370 __sysfs_remove_dir(kobj->dentry);
336 kobj->dentry = NULL; 371 kobj->dentry = NULL;
337} 372}
338 373
339int sysfs_rename_dir(struct kobject * kobj, const char *new_name) 374int sysfs_rename_dir(struct kobject * kobj, struct dentry *new_parent,
375 const char *new_name)
340{ 376{
341 int error = 0; 377 int error = 0;
342 struct dentry * new_dentry, * parent; 378 struct dentry * new_dentry;
343
344 if (!strcmp(kobject_name(kobj), new_name))
345 return -EINVAL;
346 379
347 if (!kobj->parent) 380 if (!new_parent)
348 return -EINVAL; 381 return -EFAULT;
349 382
350 down_write(&sysfs_rename_sem); 383 down_write(&sysfs_rename_sem);
351 parent = kobj->parent->dentry; 384 mutex_lock(&new_parent->d_inode->i_mutex);
352
353 mutex_lock(&parent->d_inode->i_mutex);
354 385
355 new_dentry = lookup_one_len(new_name, parent, strlen(new_name)); 386 new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name));
356 if (!IS_ERR(new_dentry)) { 387 if (!IS_ERR(new_dentry)) {
357 if (!new_dentry->d_inode) { 388 /* By allowing two different directories with the
389 * same d_parent we allow this routine to move
390 * between different shadows of the same directory
391 */
392 if (kobj->dentry->d_parent->d_inode != new_parent->d_inode)
393 return -EINVAL;
394 else if (new_dentry->d_parent->d_inode != new_parent->d_inode)
395 error = -EINVAL;
396 else if (new_dentry == kobj->dentry)
397 error = -EINVAL;
398 else if (!new_dentry->d_inode) {
358 error = kobject_set_name(kobj, "%s", new_name); 399 error = kobject_set_name(kobj, "%s", new_name);
359 if (!error) { 400 if (!error) {
401 struct sysfs_dirent *sd, *parent_sd;
402
360 d_add(new_dentry, NULL); 403 d_add(new_dentry, NULL);
361 d_move(kobj->dentry, new_dentry); 404 d_move(kobj->dentry, new_dentry);
405
406 sd = kobj->dentry->d_fsdata;
407 parent_sd = new_parent->d_fsdata;
408
409 list_del_init(&sd->s_sibling);
410 list_add(&sd->s_sibling, &parent_sd->s_children);
362 } 411 }
363 else 412 else
364 d_drop(new_dentry); 413 d_drop(new_dentry);
@@ -366,7 +415,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
366 error = -EEXIST; 415 error = -EEXIST;
367 dput(new_dentry); 416 dput(new_dentry);
368 } 417 }
369 mutex_unlock(&parent->d_inode->i_mutex); 418 mutex_unlock(&new_parent->d_inode->i_mutex);
370 up_write(&sysfs_rename_sem); 419 up_write(&sysfs_rename_sem);
371 420
372 return error; 421 return error;
@@ -378,12 +427,10 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent)
378 struct sysfs_dirent *new_parent_sd, *sd; 427 struct sysfs_dirent *new_parent_sd, *sd;
379 int error; 428 int error;
380 429
381 if (!new_parent)
382 return -EINVAL;
383
384 old_parent_dentry = kobj->parent ? 430 old_parent_dentry = kobj->parent ?
385 kobj->parent->dentry : sysfs_mount->mnt_sb->s_root; 431 kobj->parent->dentry : sysfs_mount->mnt_sb->s_root;
386 new_parent_dentry = new_parent->dentry; 432 new_parent_dentry = new_parent ?
433 new_parent->dentry : sysfs_mount->mnt_sb->s_root;
387 434
388again: 435again:
389 mutex_lock(&old_parent_dentry->d_inode->i_mutex); 436 mutex_lock(&old_parent_dentry->d_inode->i_mutex);
@@ -547,6 +594,95 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)
547 return offset; 594 return offset;
548} 595}
549 596
597
598/**
599 * sysfs_make_shadowed_dir - Setup so a directory can be shadowed
600 * @kobj: object we're creating shadow of.
601 */
602
603int sysfs_make_shadowed_dir(struct kobject *kobj,
604 void * (*follow_link)(struct dentry *, struct nameidata *))
605{
606 struct inode *inode;
607 struct inode_operations *i_op;
608
609 inode = kobj->dentry->d_inode;
610 if (inode->i_op != &sysfs_dir_inode_operations)
611 return -EINVAL;
612
613 i_op = kmalloc(sizeof(*i_op), GFP_KERNEL);
614 if (!i_op)
615 return -ENOMEM;
616
617 memcpy(i_op, &sysfs_dir_inode_operations, sizeof(*i_op));
618 i_op->follow_link = follow_link;
619
620 /* Locking of inode->i_op?
621 * Since setting i_op is a single word write and they
622 * are atomic we should be ok here.
623 */
624 inode->i_op = i_op;
625 return 0;
626}
627
628/**
629 * sysfs_create_shadow_dir - create a shadow directory for an object.
630 * @kobj: object we're creating directory for.
631 *
632 * sysfs_make_shadowed_dir must already have been called on this
633 * directory.
634 */
635
636struct dentry *sysfs_create_shadow_dir(struct kobject *kobj)
637{
638 struct sysfs_dirent *sd;
639 struct dentry *parent, *dir, *shadow;
640 struct inode *inode;
641
642 dir = kobj->dentry;
643 inode = dir->d_inode;
644 parent = dir->d_parent;
645 shadow = ERR_PTR(-EINVAL);
646 if (!sysfs_is_shadowed_inode(inode))
647 goto out;
648
649 shadow = d_alloc(parent, &dir->d_name);
650 if (!shadow)
651 goto nomem;
652
653 sd = __sysfs_make_dirent(shadow, kobj, inode->i_mode, SYSFS_DIR);
654 if (!sd)
655 goto nomem;
656
657 d_instantiate(shadow, igrab(inode));
658 inc_nlink(inode);
659 inc_nlink(parent->d_inode);
660 shadow->d_op = &sysfs_dentry_ops;
661
662 dget(shadow); /* Extra count - pin the dentry in core */
663
664out:
665 return shadow;
666nomem:
667 dput(shadow);
668 shadow = ERR_PTR(-ENOMEM);
669 goto out;
670}
671
672/**
673 * sysfs_remove_shadow_dir - remove an object's directory.
674 * @shadow: dentry of shadow directory
675 *
676 * The only thing special about this is that we remove any files in
677 * the directory before we remove the directory, and we've inlined
678 * what used to be sysfs_rmdir() below, instead of calling separately.
679 */
680
681void sysfs_remove_shadow_dir(struct dentry *shadow)
682{
683 __sysfs_remove_dir(shadow);
684}
685
550const struct file_operations sysfs_dir_operations = { 686const struct file_operations sysfs_dir_operations = {
551 .open = sysfs_dir_open, 687 .open = sysfs_dir_open,
552 .release = sysfs_dir_close, 688 .release = sysfs_dir_close,
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
54struct sysfs_buffer { 60static inline void
55 size_t count; 61add_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
70static inline void
71remove_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 */
75static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer) 89static 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;
273out:
251 up(&buffer->sem); 274 up(&buffer->sem);
252 return len; 275 return len;
253} 276}
254 277
255static int check_perm(struct inode * inode, struct file * file) 278static 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
333static int sysfs_open_file(struct inode * inode, struct file * filp)
334{
335 return check_perm(inode,filp);
336}
337
338static int sysfs_release(struct inode * inode, struct file * filp) 371static 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
549void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr) 583void 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
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index 122145b0895c..b20951c93761 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -13,6 +13,8 @@
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>
16#include "sysfs.h" 18#include "sysfs.h"
17 19
18 20
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index e79e38d52c00..542d2bcc73df 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -13,6 +13,7 @@
13#include <linux/backing-dev.h> 13#include <linux/backing-dev.h>
14#include <linux/capability.h> 14#include <linux/capability.h>
15#include <linux/errno.h> 15#include <linux/errno.h>
16#include <asm/semaphore.h>
16#include "sysfs.h" 17#include "sysfs.h"
17 18
18extern struct super_block * sysfs_sb; 19extern struct super_block * sysfs_sb;
@@ -32,6 +33,16 @@ static struct inode_operations sysfs_inode_operations ={
32 .setattr = sysfs_setattr, 33 .setattr = sysfs_setattr,
33}; 34};
34 35
36void sysfs_delete_inode(struct inode *inode)
37{
38 /* Free the shadowed directory inode operations */
39 if (sysfs_is_shadowed_inode(inode)) {
40 kfree(inode->i_op);
41 inode->i_op = NULL;
42 }
43 return generic_delete_inode(inode);
44}
45
35int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) 46int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)
36{ 47{
37 struct inode * inode = dentry->d_inode; 48 struct inode * inode = dentry->d_inode;
@@ -209,6 +220,22 @@ const unsigned char * sysfs_get_name(struct sysfs_dirent *sd)
209 return NULL; 220 return NULL;
210} 221}
211 222
223static inline void orphan_all_buffers(struct inode *node)
224{
225 struct sysfs_buffer_collection *set = node->i_private;
226 struct sysfs_buffer *buf;
227
228 mutex_lock_nested(&node->i_mutex, I_MUTEX_CHILD);
229 if (node->i_private) {
230 list_for_each_entry(buf, &set->associates, associates) {
231 down(&buf->sem);
232 buf->orphaned = 1;
233 up(&buf->sem);
234 }
235 }
236 mutex_unlock(&node->i_mutex);
237}
238
212 239
213/* 240/*
214 * Unhashes the dentry corresponding to given sysfs_dirent 241 * Unhashes the dentry corresponding to given sysfs_dirent
@@ -217,16 +244,23 @@ const unsigned char * sysfs_get_name(struct sysfs_dirent *sd)
217void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent) 244void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent)
218{ 245{
219 struct dentry * dentry = sd->s_dentry; 246 struct dentry * dentry = sd->s_dentry;
247 struct inode *inode;
220 248
221 if (dentry) { 249 if (dentry) {
222 spin_lock(&dcache_lock); 250 spin_lock(&dcache_lock);
223 spin_lock(&dentry->d_lock); 251 spin_lock(&dentry->d_lock);
224 if (!(d_unhashed(dentry) && dentry->d_inode)) { 252 if (!(d_unhashed(dentry) && dentry->d_inode)) {
253 inode = dentry->d_inode;
254 spin_lock(&inode->i_lock);
255 __iget(inode);
256 spin_unlock(&inode->i_lock);
225 dget_locked(dentry); 257 dget_locked(dentry);
226 __d_drop(dentry); 258 __d_drop(dentry);
227 spin_unlock(&dentry->d_lock); 259 spin_unlock(&dentry->d_lock);
228 spin_unlock(&dcache_lock); 260 spin_unlock(&dcache_lock);
229 simple_unlink(parent->d_inode, dentry); 261 simple_unlink(parent->d_inode, dentry);
262 orphan_all_buffers(inode);
263 iput(inode);
230 } else { 264 } else {
231 spin_unlock(&dentry->d_lock); 265 spin_unlock(&dentry->d_lock);
232 spin_unlock(&dcache_lock); 266 spin_unlock(&dcache_lock);
@@ -248,7 +282,7 @@ int sysfs_hash_and_remove(struct dentry * dir, const char * name)
248 return -ENOENT; 282 return -ENOENT;
249 283
250 parent_sd = dir->d_fsdata; 284 parent_sd = dir->d_fsdata;
251 mutex_lock(&dir->d_inode->i_mutex); 285 mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
252 list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { 286 list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
253 if (!sd->s_element) 287 if (!sd->s_element)
254 continue; 288 continue;
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index e503f858fba8..f6a87a824883 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -8,6 +8,7 @@
8#include <linux/mount.h> 8#include <linux/mount.h>
9#include <linux/pagemap.h> 9#include <linux/pagemap.h>
10#include <linux/init.h> 10#include <linux/init.h>
11#include <asm/semaphore.h>
11 12
12#include "sysfs.h" 13#include "sysfs.h"
13 14
@@ -18,9 +19,12 @@ struct vfsmount *sysfs_mount;
18struct super_block * sysfs_sb = NULL; 19struct super_block * sysfs_sb = NULL;
19struct kmem_cache *sysfs_dir_cachep; 20struct kmem_cache *sysfs_dir_cachep;
20 21
22static void sysfs_clear_inode(struct inode *inode);
23
21static struct super_operations sysfs_ops = { 24static struct super_operations sysfs_ops = {
22 .statfs = simple_statfs, 25 .statfs = simple_statfs,
23 .drop_inode = generic_delete_inode, 26 .drop_inode = sysfs_delete_inode,
27 .clear_inode = sysfs_clear_inode,
24}; 28};
25 29
26static struct sysfs_dirent sysfs_root = { 30static struct sysfs_dirent sysfs_root = {
@@ -31,6 +35,11 @@ static struct sysfs_dirent sysfs_root = {
31 .s_iattr = NULL, 35 .s_iattr = NULL,
32}; 36};
33 37
38static void sysfs_clear_inode(struct inode *inode)
39{
40 kfree(inode->i_private);
41}
42
34static int sysfs_fill_super(struct super_block *sb, void *data, int silent) 43static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
35{ 44{
36 struct inode *inode; 45 struct inode *inode;
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c
index f50e3cc2ded8..4869f611192f 100644
--- a/fs/sysfs/symlink.c
+++ b/fs/sysfs/symlink.c
@@ -7,6 +7,7 @@
7#include <linux/module.h> 7#include <linux/module.h>
8#include <linux/kobject.h> 8#include <linux/kobject.h>
9#include <linux/namei.h> 9#include <linux/namei.h>
10#include <asm/semaphore.h>
10 11
11#include "sysfs.h" 12#include "sysfs.h"
12 13
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index bd7cec295dab..fe1cbfd208ed 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -2,6 +2,7 @@
2extern struct vfsmount * sysfs_mount; 2extern struct vfsmount * sysfs_mount;
3extern struct kmem_cache *sysfs_dir_cachep; 3extern struct kmem_cache *sysfs_dir_cachep;
4 4
5extern void sysfs_delete_inode(struct inode *inode);
5extern struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *); 6extern struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *);
6extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *)); 7extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *));
7 8
@@ -33,6 +34,22 @@ struct sysfs_symlink {
33 struct kobject * target_kobj; 34 struct kobject * target_kobj;
34}; 35};
35 36
37struct sysfs_buffer {
38 struct list_head associates;
39 size_t count;
40 loff_t pos;
41 char * page;
42 struct sysfs_ops * ops;
43 struct semaphore sem;
44 int orphaned;
45 int needs_read_fill;
46 int event;
47};
48
49struct sysfs_buffer_collection {
50 struct list_head associates;
51};
52
36static inline struct kobject * to_kobj(struct dentry * dentry) 53static inline struct kobject * to_kobj(struct dentry * dentry)
37{ 54{
38 struct sysfs_dirent * sd = dentry->d_fsdata; 55 struct sysfs_dirent * sd = dentry->d_fsdata;
@@ -96,3 +113,7 @@ static inline void sysfs_put(struct sysfs_dirent * sd)
96 release_sysfs_dirent(sd); 113 release_sysfs_dirent(sd);
97} 114}
98 115
116static inline int sysfs_is_shadowed_inode(struct inode *inode)
117{
118 return S_ISDIR(inode->i_mode) && inode->i_op->follow_link;
119}