diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-12 16:40:20 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-12 16:40:20 -0400 |
commit | dc690d8ef842b464f1c429a376ca16cb8dbee6ae (patch) | |
tree | 77955849af5a15755f5e55e24ae4b9c520583a72 /fs | |
parent | 57399ec9077a4b962b81037aaa279fab52f5e989 (diff) | |
parent | 91a6902958f052358899f58683d44e36228d85c2 (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/driver-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/driver-2.6: (61 commits)
sysfs: add parameter "struct bin_attribute *" in .read/.write methods for sysfs binary attributes
sysfs: make directory dentries and inodes reclaimable
sysfs: implement sysfs_get_dentry()
sysfs: move sysfs_drop_dentry() to dir.c and make it static
sysfs: restructure add/remove paths and fix inode update
sysfs: use sysfs_mutex to protect the sysfs_dirent tree
sysfs: consolidate sysfs spinlocks
sysfs: make kobj point to sysfs_dirent instead of dentry
sysfs: implement sysfs_find_dirent() and sysfs_get_dirent()
sysfs: implement SYSFS_FLAG_REMOVED flag
sysfs: rename sysfs_dirent->s_type to s_flags and make room for flags
sysfs: make sysfs_drop_dentry() access inodes using ilookup()
sysfs: Fix oops in sysfs_drop_dentry on x86_64
sysfs: use singly-linked list for sysfs_dirent tree
sysfs: slim down sysfs_dirent->s_active
sysfs: move s_active functions to fs/sysfs/dir.c
sysfs: fix root sysfs_dirent -> root dentry association
sysfs: use iget_locked() instead of new_inode()
sysfs: reorganize sysfs_new_indoe() and sysfs_create()
sysfs: fix parent refcounting during rename and move
...
Diffstat (limited to 'fs')
-rw-r--r-- | fs/debugfs/inode.c | 63 | ||||
-rw-r--r-- | fs/ecryptfs/main.c | 2 | ||||
-rw-r--r-- | fs/ocfs2/cluster/masklog.c | 1 | ||||
-rw-r--r-- | fs/partitions/check.c | 1 | ||||
-rw-r--r-- | fs/sysfs/bin.c | 195 | ||||
-rw-r--r-- | fs/sysfs/dir.c | 1297 | ||||
-rw-r--r-- | fs/sysfs/file.c | 379 | ||||
-rw-r--r-- | fs/sysfs/group.c | 55 | ||||
-rw-r--r-- | fs/sysfs/inode.c | 221 | ||||
-rw-r--r-- | fs/sysfs/mount.c | 36 | ||||
-rw-r--r-- | fs/sysfs/symlink.c | 150 | ||||
-rw-r--r-- | fs/sysfs/sysfs.h | 169 |
12 files changed, 1563 insertions, 1006 deletions
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index ec8896b264de..1d533a2ec3a6 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c | |||
@@ -368,6 +368,69 @@ void debugfs_remove(struct dentry *dentry) | |||
368 | } | 368 | } |
369 | EXPORT_SYMBOL_GPL(debugfs_remove); | 369 | EXPORT_SYMBOL_GPL(debugfs_remove); |
370 | 370 | ||
371 | /** | ||
372 | * debugfs_rename - rename a file/directory in the debugfs filesystem | ||
373 | * @old_dir: a pointer to the parent dentry for the renamed object. This | ||
374 | * should be a directory dentry. | ||
375 | * @old_dentry: dentry of an object to be renamed. | ||
376 | * @new_dir: a pointer to the parent dentry where the object should be | ||
377 | * moved. This should be a directory dentry. | ||
378 | * @new_name: a pointer to a string containing the target name. | ||
379 | * | ||
380 | * This function renames a file/directory in debugfs. The target must not | ||
381 | * exist for rename to succeed. | ||
382 | * | ||
383 | * This function will return a pointer to old_dentry (which is updated to | ||
384 | * reflect renaming) if it succeeds. If an error occurs, %NULL will be | ||
385 | * returned. | ||
386 | * | ||
387 | * If debugfs is not enabled in the kernel, the value -%ENODEV will be | ||
388 | * returned. | ||
389 | */ | ||
390 | struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry, | ||
391 | struct dentry *new_dir, const char *new_name) | ||
392 | { | ||
393 | int error; | ||
394 | struct dentry *dentry = NULL, *trap; | ||
395 | const char *old_name; | ||
396 | |||
397 | trap = lock_rename(new_dir, old_dir); | ||
398 | /* Source or destination directories don't exist? */ | ||
399 | if (!old_dir->d_inode || !new_dir->d_inode) | ||
400 | goto exit; | ||
401 | /* Source does not exist, cyclic rename, or mountpoint? */ | ||
402 | if (!old_dentry->d_inode || old_dentry == trap || | ||
403 | d_mountpoint(old_dentry)) | ||
404 | goto exit; | ||
405 | dentry = lookup_one_len(new_name, new_dir, strlen(new_name)); | ||
406 | /* Lookup failed, cyclic rename or target exists? */ | ||
407 | if (IS_ERR(dentry) || dentry == trap || dentry->d_inode) | ||
408 | goto exit; | ||
409 | |||
410 | old_name = fsnotify_oldname_init(old_dentry->d_name.name); | ||
411 | |||
412 | error = simple_rename(old_dir->d_inode, old_dentry, new_dir->d_inode, | ||
413 | dentry); | ||
414 | if (error) { | ||
415 | fsnotify_oldname_free(old_name); | ||
416 | goto exit; | ||
417 | } | ||
418 | d_move(old_dentry, dentry); | ||
419 | fsnotify_move(old_dir->d_inode, new_dir->d_inode, old_name, | ||
420 | old_dentry->d_name.name, S_ISDIR(old_dentry->d_inode->i_mode), | ||
421 | NULL, old_dentry->d_inode); | ||
422 | fsnotify_oldname_free(old_name); | ||
423 | unlock_rename(new_dir, old_dir); | ||
424 | dput(dentry); | ||
425 | return old_dentry; | ||
426 | exit: | ||
427 | if (dentry && !IS_ERR(dentry)) | ||
428 | dput(dentry); | ||
429 | unlock_rename(new_dir, old_dir); | ||
430 | return NULL; | ||
431 | } | ||
432 | EXPORT_SYMBOL_GPL(debugfs_rename); | ||
433 | |||
371 | static decl_subsys(debug, NULL, NULL); | 434 | static decl_subsys(debug, NULL, NULL); |
372 | 435 | ||
373 | static int __init debugfs_init(void) | 436 | static int __init debugfs_init(void) |
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index 606128f5c927..02ca6f1e55d7 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c | |||
@@ -840,8 +840,6 @@ static int __init ecryptfs_init(void) | |||
840 | goto out; | 840 | goto out; |
841 | } | 841 | } |
842 | kobj_set_kset_s(&ecryptfs_subsys, fs_subsys); | 842 | kobj_set_kset_s(&ecryptfs_subsys, fs_subsys); |
843 | sysfs_attr_version.attr.owner = THIS_MODULE; | ||
844 | sysfs_attr_version_str.attr.owner = THIS_MODULE; | ||
845 | rc = do_sysfs_registration(); | 843 | rc = do_sysfs_registration(); |
846 | if (rc) { | 844 | if (rc) { |
847 | printk(KERN_ERR "sysfs registration failed\n"); | 845 | printk(KERN_ERR "sysfs registration failed\n"); |
diff --git a/fs/ocfs2/cluster/masklog.c b/fs/ocfs2/cluster/masklog.c index 2b205f5d5790..e9e042b93dbf 100644 --- a/fs/ocfs2/cluster/masklog.c +++ b/fs/ocfs2/cluster/masklog.c | |||
@@ -74,7 +74,6 @@ struct mlog_attribute { | |||
74 | #define define_mask(_name) { \ | 74 | #define define_mask(_name) { \ |
75 | .attr = { \ | 75 | .attr = { \ |
76 | .name = #_name, \ | 76 | .name = #_name, \ |
77 | .owner = THIS_MODULE, \ | ||
78 | .mode = S_IRUGO | S_IWUSR, \ | 77 | .mode = S_IRUGO | S_IWUSR, \ |
79 | }, \ | 78 | }, \ |
80 | .mask = ML_##_name, \ | 79 | .mask = ML_##_name, \ |
diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 9a3a058f3553..98e0b85a9bb2 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c | |||
@@ -397,7 +397,6 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len, | |||
397 | static struct attribute addpartattr = { | 397 | static struct attribute addpartattr = { |
398 | .name = "whole_disk", | 398 | .name = "whole_disk", |
399 | .mode = S_IRUSR | S_IRGRP | S_IROTH, | 399 | .mode = S_IRUSR | S_IRGRP | S_IROTH, |
400 | .owner = THIS_MODULE, | ||
401 | }; | 400 | }; |
402 | 401 | ||
403 | sysfs_create_file(&p->kobj, &addpartattr); | 402 | sysfs_create_file(&p->kobj, &addpartattr); |
diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c index d3b9f5f07db1..135353f8a296 100644 --- a/fs/sysfs/bin.c +++ b/fs/sysfs/bin.c | |||
@@ -20,29 +20,41 @@ | |||
20 | 20 | ||
21 | #include "sysfs.h" | 21 | #include "sysfs.h" |
22 | 22 | ||
23 | struct bin_buffer { | ||
24 | struct mutex mutex; | ||
25 | void *buffer; | ||
26 | int mmapped; | ||
27 | }; | ||
28 | |||
23 | static int | 29 | static int |
24 | fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count) | 30 | fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count) |
25 | { | 31 | { |
26 | struct bin_attribute * attr = to_bin_attr(dentry); | 32 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; |
27 | struct kobject * kobj = to_kobj(dentry->d_parent); | 33 | struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; |
34 | struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; | ||
35 | int rc; | ||
36 | |||
37 | /* need attr_sd for attr, its parent for kobj */ | ||
38 | if (!sysfs_get_active_two(attr_sd)) | ||
39 | return -ENODEV; | ||
28 | 40 | ||
29 | if (!attr->read) | 41 | rc = -EIO; |
30 | return -EIO; | 42 | if (attr->read) |
43 | rc = attr->read(kobj, attr, buffer, off, count); | ||
31 | 44 | ||
32 | return attr->read(kobj, buffer, off, count); | 45 | sysfs_put_active_two(attr_sd); |
46 | |||
47 | return rc; | ||
33 | } | 48 | } |
34 | 49 | ||
35 | static ssize_t | 50 | static ssize_t |
36 | read(struct file * file, char __user * userbuf, size_t count, loff_t * off) | 51 | read(struct file *file, char __user *userbuf, size_t bytes, loff_t *off) |
37 | { | 52 | { |
38 | char *buffer = file->private_data; | 53 | struct bin_buffer *bb = file->private_data; |
39 | struct dentry *dentry = file->f_path.dentry; | 54 | struct dentry *dentry = file->f_path.dentry; |
40 | int size = dentry->d_inode->i_size; | 55 | int size = dentry->d_inode->i_size; |
41 | loff_t offs = *off; | 56 | loff_t offs = *off; |
42 | int ret; | 57 | int count = min_t(size_t, bytes, PAGE_SIZE); |
43 | |||
44 | if (count > PAGE_SIZE) | ||
45 | count = PAGE_SIZE; | ||
46 | 58 | ||
47 | if (size) { | 59 | if (size) { |
48 | if (offs > size) | 60 | if (offs > size) |
@@ -51,43 +63,56 @@ read(struct file * file, char __user * userbuf, size_t count, loff_t * off) | |||
51 | count = size - offs; | 63 | count = size - offs; |
52 | } | 64 | } |
53 | 65 | ||
54 | ret = fill_read(dentry, buffer, offs, count); | 66 | mutex_lock(&bb->mutex); |
55 | if (ret < 0) | 67 | |
56 | return ret; | 68 | count = fill_read(dentry, bb->buffer, offs, count); |
57 | count = ret; | 69 | if (count < 0) |
70 | goto out_unlock; | ||
58 | 71 | ||
59 | if (copy_to_user(userbuf, buffer, count)) | 72 | if (copy_to_user(userbuf, bb->buffer, count)) { |
60 | return -EFAULT; | 73 | count = -EFAULT; |
74 | goto out_unlock; | ||
75 | } | ||
61 | 76 | ||
62 | pr_debug("offs = %lld, *off = %lld, count = %zd\n", offs, *off, count); | 77 | pr_debug("offs = %lld, *off = %lld, count = %d\n", offs, *off, count); |
63 | 78 | ||
64 | *off = offs + count; | 79 | *off = offs + count; |
65 | 80 | ||
81 | out_unlock: | ||
82 | mutex_unlock(&bb->mutex); | ||
66 | return count; | 83 | return count; |
67 | } | 84 | } |
68 | 85 | ||
69 | static int | 86 | static int |
70 | flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count) | 87 | flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count) |
71 | { | 88 | { |
72 | struct bin_attribute *attr = to_bin_attr(dentry); | 89 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; |
73 | struct kobject *kobj = to_kobj(dentry->d_parent); | 90 | struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; |
91 | struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; | ||
92 | int rc; | ||
93 | |||
94 | /* need attr_sd for attr, its parent for kobj */ | ||
95 | if (!sysfs_get_active_two(attr_sd)) | ||
96 | return -ENODEV; | ||
97 | |||
98 | rc = -EIO; | ||
99 | if (attr->write) | ||
100 | rc = attr->write(kobj, attr, buffer, offset, count); | ||
74 | 101 | ||
75 | if (!attr->write) | 102 | sysfs_put_active_two(attr_sd); |
76 | return -EIO; | ||
77 | 103 | ||
78 | return attr->write(kobj, buffer, offset, count); | 104 | return rc; |
79 | } | 105 | } |
80 | 106 | ||
81 | static ssize_t write(struct file * file, const char __user * userbuf, | 107 | static ssize_t write(struct file *file, const char __user *userbuf, |
82 | size_t count, loff_t * off) | 108 | size_t bytes, loff_t *off) |
83 | { | 109 | { |
84 | char *buffer = file->private_data; | 110 | struct bin_buffer *bb = file->private_data; |
85 | struct dentry *dentry = file->f_path.dentry; | 111 | struct dentry *dentry = file->f_path.dentry; |
86 | int size = dentry->d_inode->i_size; | 112 | int size = dentry->d_inode->i_size; |
87 | loff_t offs = *off; | 113 | loff_t offs = *off; |
114 | int count = min_t(size_t, bytes, PAGE_SIZE); | ||
88 | 115 | ||
89 | if (count > PAGE_SIZE) | ||
90 | count = PAGE_SIZE; | ||
91 | if (size) { | 116 | if (size) { |
92 | if (offs > size) | 117 | if (offs > size) |
93 | return 0; | 118 | return 0; |
@@ -95,72 +120,100 @@ static ssize_t write(struct file * file, const char __user * userbuf, | |||
95 | count = size - offs; | 120 | count = size - offs; |
96 | } | 121 | } |
97 | 122 | ||
98 | if (copy_from_user(buffer, userbuf, count)) | 123 | mutex_lock(&bb->mutex); |
99 | return -EFAULT; | ||
100 | 124 | ||
101 | count = flush_write(dentry, buffer, offs, count); | 125 | if (copy_from_user(bb->buffer, userbuf, count)) { |
126 | count = -EFAULT; | ||
127 | goto out_unlock; | ||
128 | } | ||
129 | |||
130 | count = flush_write(dentry, bb->buffer, offs, count); | ||
102 | if (count > 0) | 131 | if (count > 0) |
103 | *off = offs + count; | 132 | *off = offs + count; |
133 | |||
134 | out_unlock: | ||
135 | mutex_unlock(&bb->mutex); | ||
104 | return count; | 136 | return count; |
105 | } | 137 | } |
106 | 138 | ||
107 | static int mmap(struct file *file, struct vm_area_struct *vma) | 139 | static int mmap(struct file *file, struct vm_area_struct *vma) |
108 | { | 140 | { |
109 | struct dentry *dentry = file->f_path.dentry; | 141 | struct bin_buffer *bb = file->private_data; |
110 | struct bin_attribute *attr = to_bin_attr(dentry); | 142 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; |
111 | struct kobject *kobj = to_kobj(dentry->d_parent); | 143 | struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; |
144 | struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; | ||
145 | int rc; | ||
146 | |||
147 | mutex_lock(&bb->mutex); | ||
148 | |||
149 | /* need attr_sd for attr, its parent for kobj */ | ||
150 | if (!sysfs_get_active_two(attr_sd)) | ||
151 | return -ENODEV; | ||
112 | 152 | ||
113 | if (!attr->mmap) | 153 | rc = -EINVAL; |
114 | return -EINVAL; | 154 | if (attr->mmap) |
155 | rc = attr->mmap(kobj, attr, vma); | ||
115 | 156 | ||
116 | return attr->mmap(kobj, attr, vma); | 157 | if (rc == 0 && !bb->mmapped) |
158 | bb->mmapped = 1; | ||
159 | else | ||
160 | sysfs_put_active_two(attr_sd); | ||
161 | |||
162 | mutex_unlock(&bb->mutex); | ||
163 | |||
164 | return rc; | ||
117 | } | 165 | } |
118 | 166 | ||
119 | static int open(struct inode * inode, struct file * file) | 167 | static int open(struct inode * inode, struct file * file) |
120 | { | 168 | { |
121 | struct kobject *kobj = sysfs_get_kobject(file->f_path.dentry->d_parent); | 169 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; |
122 | struct bin_attribute * attr = to_bin_attr(file->f_path.dentry); | 170 | struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; |
123 | int error = -EINVAL; | 171 | struct bin_buffer *bb = NULL; |
124 | 172 | int error; | |
125 | if (!kobj || !attr) | ||
126 | goto Done; | ||
127 | 173 | ||
128 | /* Grab the module reference for this attribute if we have one */ | 174 | /* need attr_sd for attr */ |
129 | error = -ENODEV; | 175 | if (!sysfs_get_active(attr_sd)) |
130 | if (!try_module_get(attr->attr.owner)) | 176 | return -ENODEV; |
131 | goto Done; | ||
132 | 177 | ||
133 | error = -EACCES; | 178 | error = -EACCES; |
134 | if ((file->f_mode & FMODE_WRITE) && !(attr->write || attr->mmap)) | 179 | if ((file->f_mode & FMODE_WRITE) && !(attr->write || attr->mmap)) |
135 | goto Error; | 180 | goto err_out; |
136 | if ((file->f_mode & FMODE_READ) && !(attr->read || attr->mmap)) | 181 | if ((file->f_mode & FMODE_READ) && !(attr->read || attr->mmap)) |
137 | goto Error; | 182 | goto err_out; |
138 | 183 | ||
139 | error = -ENOMEM; | 184 | error = -ENOMEM; |
140 | file->private_data = kmalloc(PAGE_SIZE, GFP_KERNEL); | 185 | bb = kzalloc(sizeof(*bb), GFP_KERNEL); |
141 | if (!file->private_data) | 186 | if (!bb) |
142 | goto Error; | 187 | goto err_out; |
143 | 188 | ||
144 | error = 0; | 189 | bb->buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); |
145 | goto Done; | 190 | if (!bb->buffer) |
146 | 191 | goto err_out; | |
147 | Error: | 192 | |
148 | module_put(attr->attr.owner); | 193 | mutex_init(&bb->mutex); |
149 | Done: | 194 | file->private_data = bb; |
150 | if (error) | 195 | |
151 | kobject_put(kobj); | 196 | /* open succeeded, put active reference and pin attr_sd */ |
197 | sysfs_put_active(attr_sd); | ||
198 | sysfs_get(attr_sd); | ||
199 | return 0; | ||
200 | |||
201 | err_out: | ||
202 | sysfs_put_active(attr_sd); | ||
203 | kfree(bb); | ||
152 | return error; | 204 | return error; |
153 | } | 205 | } |
154 | 206 | ||
155 | static int release(struct inode * inode, struct file * file) | 207 | static int release(struct inode * inode, struct file * file) |
156 | { | 208 | { |
157 | struct kobject * kobj = to_kobj(file->f_path.dentry->d_parent); | 209 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; |
158 | struct bin_attribute * attr = to_bin_attr(file->f_path.dentry); | 210 | struct bin_buffer *bb = file->private_data; |
159 | u8 * buffer = file->private_data; | 211 | |
160 | 212 | if (bb->mmapped) | |
161 | kobject_put(kobj); | 213 | sysfs_put_active_two(attr_sd); |
162 | module_put(attr->attr.owner); | 214 | sysfs_put(attr_sd); |
163 | kfree(buffer); | 215 | kfree(bb->buffer); |
216 | kfree(bb); | ||
164 | return 0; | 217 | return 0; |
165 | } | 218 | } |
166 | 219 | ||
@@ -181,9 +234,9 @@ const struct file_operations bin_fops = { | |||
181 | 234 | ||
182 | int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr) | 235 | int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr) |
183 | { | 236 | { |
184 | BUG_ON(!kobj || !kobj->dentry || !attr); | 237 | BUG_ON(!kobj || !kobj->sd || !attr); |
185 | 238 | ||
186 | return sysfs_add_file(kobj->dentry, &attr->attr, SYSFS_KOBJ_BIN_ATTR); | 239 | return sysfs_add_file(kobj->sd, &attr->attr, SYSFS_KOBJ_BIN_ATTR); |
187 | } | 240 | } |
188 | 241 | ||
189 | 242 | ||
@@ -195,7 +248,7 @@ int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr) | |||
195 | 248 | ||
196 | void sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr) | 249 | void sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr) |
197 | { | 250 | { |
198 | if (sysfs_hash_and_remove(kobj->dentry, attr->attr.name) < 0) { | 251 | if (sysfs_hash_and_remove(kobj->sd, attr->attr.name) < 0) { |
199 | printk(KERN_ERR "%s: " | 252 | printk(KERN_ERR "%s: " |
200 | "bad dentry or inode or no such file: \"%s\"\n", | 253 | "bad dentry or inode or no such file: \"%s\"\n", |
201 | __FUNCTION__, attr->attr.name); | 254 | __FUNCTION__, attr->attr.name); |
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index c4342a019972..aee966c44aac 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
@@ -9,21 +9,337 @@ | |||
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 <linux/idr.h> | ||
13 | #include <linux/completion.h> | ||
12 | #include <asm/semaphore.h> | 14 | #include <asm/semaphore.h> |
13 | #include "sysfs.h" | 15 | #include "sysfs.h" |
14 | 16 | ||
15 | DECLARE_RWSEM(sysfs_rename_sem); | 17 | DEFINE_MUTEX(sysfs_mutex); |
16 | spinlock_t sysfs_lock = SPIN_LOCK_UNLOCKED; | 18 | spinlock_t sysfs_assoc_lock = SPIN_LOCK_UNLOCKED; |
19 | |||
20 | static spinlock_t sysfs_ino_lock = SPIN_LOCK_UNLOCKED; | ||
21 | static DEFINE_IDA(sysfs_ino_ida); | ||
22 | |||
23 | /** | ||
24 | * sysfs_link_sibling - link sysfs_dirent into sibling list | ||
25 | * @sd: sysfs_dirent of interest | ||
26 | * | ||
27 | * Link @sd into its sibling list which starts from | ||
28 | * sd->s_parent->s_children. | ||
29 | * | ||
30 | * Locking: | ||
31 | * mutex_lock(sysfs_mutex) | ||
32 | */ | ||
33 | void sysfs_link_sibling(struct sysfs_dirent *sd) | ||
34 | { | ||
35 | struct sysfs_dirent *parent_sd = sd->s_parent; | ||
36 | |||
37 | BUG_ON(sd->s_sibling); | ||
38 | sd->s_sibling = parent_sd->s_children; | ||
39 | parent_sd->s_children = sd; | ||
40 | } | ||
41 | |||
42 | /** | ||
43 | * sysfs_unlink_sibling - unlink sysfs_dirent from sibling list | ||
44 | * @sd: sysfs_dirent of interest | ||
45 | * | ||
46 | * Unlink @sd from its sibling list which starts from | ||
47 | * sd->s_parent->s_children. | ||
48 | * | ||
49 | * Locking: | ||
50 | * mutex_lock(sysfs_mutex) | ||
51 | */ | ||
52 | void sysfs_unlink_sibling(struct sysfs_dirent *sd) | ||
53 | { | ||
54 | struct sysfs_dirent **pos; | ||
55 | |||
56 | for (pos = &sd->s_parent->s_children; *pos; pos = &(*pos)->s_sibling) { | ||
57 | if (*pos == sd) { | ||
58 | *pos = sd->s_sibling; | ||
59 | sd->s_sibling = NULL; | ||
60 | break; | ||
61 | } | ||
62 | } | ||
63 | } | ||
64 | |||
65 | /** | ||
66 | * sysfs_get_dentry - get dentry for the given sysfs_dirent | ||
67 | * @sd: sysfs_dirent of interest | ||
68 | * | ||
69 | * Get dentry for @sd. Dentry is looked up if currently not | ||
70 | * present. This function climbs sysfs_dirent tree till it | ||
71 | * reaches a sysfs_dirent with valid dentry attached and descends | ||
72 | * down from there looking up dentry for each step. | ||
73 | * | ||
74 | * LOCKING: | ||
75 | * Kernel thread context (may sleep) | ||
76 | * | ||
77 | * RETURNS: | ||
78 | * Pointer to found dentry on success, ERR_PTR() value on error. | ||
79 | */ | ||
80 | struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd) | ||
81 | { | ||
82 | struct sysfs_dirent *cur; | ||
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 | |||
95 | dentry = NULL; | ||
96 | depth = 0; | ||
97 | cur = sd; | ||
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 | |||
110 | spin_unlock(&dcache_lock); | ||
111 | spin_unlock(&sysfs_assoc_lock); | ||
112 | |||
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; | ||
118 | |||
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 */ | ||
132 | parent_dentry = dentry; | ||
133 | dentry = lookup_one_len_kern(cur->s_name, parent_dentry, | ||
134 | strlen(cur->s_name)); | ||
135 | dput(parent_dentry); | ||
136 | |||
137 | if (IS_ERR(dentry)) { | ||
138 | sysfs_put(cur); | ||
139 | return dentry; | ||
140 | } | ||
141 | |||
142 | mutex_lock(&sysfs_mutex); | ||
143 | spin_lock(&sysfs_assoc_lock); | ||
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 | } | ||
158 | |||
159 | mutex_unlock(&sysfs_mutex); | ||
160 | return dentry; | ||
161 | } | ||
162 | |||
163 | /** | ||
164 | * sysfs_get_active - get an active reference to sysfs_dirent | ||
165 | * @sd: sysfs_dirent to get an active reference to | ||
166 | * | ||
167 | * Get an active reference of @sd. This function is noop if @sd | ||
168 | * is NULL. | ||
169 | * | ||
170 | * RETURNS: | ||
171 | * Pointer to @sd on success, NULL on failure. | ||
172 | */ | ||
173 | struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd) | ||
174 | { | ||
175 | if (unlikely(!sd)) | ||
176 | return NULL; | ||
177 | |||
178 | while (1) { | ||
179 | int v, t; | ||
180 | |||
181 | v = atomic_read(&sd->s_active); | ||
182 | if (unlikely(v < 0)) | ||
183 | return NULL; | ||
184 | |||
185 | t = atomic_cmpxchg(&sd->s_active, v, v + 1); | ||
186 | if (likely(t == v)) | ||
187 | return sd; | ||
188 | if (t < 0) | ||
189 | return NULL; | ||
190 | |||
191 | cpu_relax(); | ||
192 | } | ||
193 | } | ||
194 | |||
195 | /** | ||
196 | * sysfs_put_active - put an active reference to sysfs_dirent | ||
197 | * @sd: sysfs_dirent to put an active reference to | ||
198 | * | ||
199 | * Put an active reference to @sd. This function is noop if @sd | ||
200 | * is NULL. | ||
201 | */ | ||
202 | void sysfs_put_active(struct sysfs_dirent *sd) | ||
203 | { | ||
204 | struct completion *cmpl; | ||
205 | int v; | ||
206 | |||
207 | if (unlikely(!sd)) | ||
208 | return; | ||
209 | |||
210 | v = atomic_dec_return(&sd->s_active); | ||
211 | if (likely(v != SD_DEACTIVATED_BIAS)) | ||
212 | return; | ||
213 | |||
214 | /* atomic_dec_return() is a mb(), we'll always see the updated | ||
215 | * sd->s_sibling. | ||
216 | */ | ||
217 | cmpl = (void *)sd->s_sibling; | ||
218 | complete(cmpl); | ||
219 | } | ||
220 | |||
221 | /** | ||
222 | * sysfs_get_active_two - get active references to sysfs_dirent and parent | ||
223 | * @sd: sysfs_dirent of interest | ||
224 | * | ||
225 | * Get active reference to @sd and its parent. Parent's active | ||
226 | * reference is grabbed first. This function is noop if @sd is | ||
227 | * NULL. | ||
228 | * | ||
229 | * RETURNS: | ||
230 | * Pointer to @sd on success, NULL on failure. | ||
231 | */ | ||
232 | struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd) | ||
233 | { | ||
234 | if (sd) { | ||
235 | if (sd->s_parent && unlikely(!sysfs_get_active(sd->s_parent))) | ||
236 | return NULL; | ||
237 | if (unlikely(!sysfs_get_active(sd))) { | ||
238 | sysfs_put_active(sd->s_parent); | ||
239 | return NULL; | ||
240 | } | ||
241 | } | ||
242 | return sd; | ||
243 | } | ||
244 | |||
245 | /** | ||
246 | * sysfs_put_active_two - put active references to sysfs_dirent and parent | ||
247 | * @sd: sysfs_dirent of interest | ||
248 | * | ||
249 | * Put active references to @sd and its parent. This function is | ||
250 | * noop if @sd is NULL. | ||
251 | */ | ||
252 | void sysfs_put_active_two(struct sysfs_dirent *sd) | ||
253 | { | ||
254 | if (sd) { | ||
255 | sysfs_put_active(sd); | ||
256 | sysfs_put_active(sd->s_parent); | ||
257 | } | ||
258 | } | ||
259 | |||
260 | /** | ||
261 | * sysfs_deactivate - deactivate sysfs_dirent | ||
262 | * @sd: sysfs_dirent to deactivate | ||
263 | * | ||
264 | * Deny new active references and drain existing ones. | ||
265 | */ | ||
266 | static void sysfs_deactivate(struct sysfs_dirent *sd) | ||
267 | { | ||
268 | DECLARE_COMPLETION_ONSTACK(wait); | ||
269 | int v; | ||
270 | |||
271 | BUG_ON(sd->s_sibling || !(sd->s_flags & SYSFS_FLAG_REMOVED)); | ||
272 | sd->s_sibling = (void *)&wait; | ||
273 | |||
274 | /* atomic_add_return() is a mb(), put_active() will always see | ||
275 | * the updated sd->s_sibling. | ||
276 | */ | ||
277 | v = atomic_add_return(SD_DEACTIVATED_BIAS, &sd->s_active); | ||
278 | |||
279 | if (v != SD_DEACTIVATED_BIAS) | ||
280 | wait_for_completion(&wait); | ||
281 | |||
282 | sd->s_sibling = NULL; | ||
283 | } | ||
284 | |||
285 | static int sysfs_alloc_ino(ino_t *pino) | ||
286 | { | ||
287 | int ino, rc; | ||
288 | |||
289 | retry: | ||
290 | spin_lock(&sysfs_ino_lock); | ||
291 | rc = ida_get_new_above(&sysfs_ino_ida, 2, &ino); | ||
292 | spin_unlock(&sysfs_ino_lock); | ||
293 | |||
294 | if (rc == -EAGAIN) { | ||
295 | if (ida_pre_get(&sysfs_ino_ida, GFP_KERNEL)) | ||
296 | goto retry; | ||
297 | rc = -ENOMEM; | ||
298 | } | ||
299 | |||
300 | *pino = ino; | ||
301 | return rc; | ||
302 | } | ||
303 | |||
304 | static void sysfs_free_ino(ino_t ino) | ||
305 | { | ||
306 | spin_lock(&sysfs_ino_lock); | ||
307 | ida_remove(&sysfs_ino_ida, ino); | ||
308 | spin_unlock(&sysfs_ino_lock); | ||
309 | } | ||
310 | |||
311 | void release_sysfs_dirent(struct sysfs_dirent * sd) | ||
312 | { | ||
313 | struct sysfs_dirent *parent_sd; | ||
314 | |||
315 | repeat: | ||
316 | /* Moving/renaming is always done while holding reference. | ||
317 | * sd->s_parent won't change beneath us. | ||
318 | */ | ||
319 | parent_sd = sd->s_parent; | ||
320 | |||
321 | if (sysfs_type(sd) == SYSFS_KOBJ_LINK) | ||
322 | sysfs_put(sd->s_elem.symlink.target_sd); | ||
323 | if (sysfs_type(sd) & SYSFS_COPY_NAME) | ||
324 | kfree(sd->s_name); | ||
325 | kfree(sd->s_iattr); | ||
326 | sysfs_free_ino(sd->s_ino); | ||
327 | kmem_cache_free(sysfs_dir_cachep, sd); | ||
328 | |||
329 | sd = parent_sd; | ||
330 | if (sd && atomic_dec_and_test(&sd->s_count)) | ||
331 | goto repeat; | ||
332 | } | ||
17 | 333 | ||
18 | static void sysfs_d_iput(struct dentry * dentry, struct inode * inode) | 334 | static void sysfs_d_iput(struct dentry * dentry, struct inode * inode) |
19 | { | 335 | { |
20 | struct sysfs_dirent * sd = dentry->d_fsdata; | 336 | struct sysfs_dirent * sd = dentry->d_fsdata; |
21 | 337 | ||
22 | if (sd) { | 338 | if (sd) { |
23 | /* sd->s_dentry is protected with sysfs_lock. This | 339 | /* sd->s_dentry is protected with sysfs_assoc_lock. |
24 | * allows sysfs_drop_dentry() to dereference it. | 340 | * This allows sysfs_drop_dentry() to dereference it. |
25 | */ | 341 | */ |
26 | spin_lock(&sysfs_lock); | 342 | spin_lock(&sysfs_assoc_lock); |
27 | 343 | ||
28 | /* The dentry might have been deleted or another | 344 | /* The dentry might have been deleted or another |
29 | * lookup could have happened updating sd->s_dentry to | 345 | * lookup could have happened updating sd->s_dentry to |
@@ -32,7 +348,7 @@ static void sysfs_d_iput(struct dentry * dentry, struct inode * inode) | |||
32 | */ | 348 | */ |
33 | if (sd->s_dentry == dentry) | 349 | if (sd->s_dentry == dentry) |
34 | sd->s_dentry = NULL; | 350 | sd->s_dentry = NULL; |
35 | spin_unlock(&sysfs_lock); | 351 | spin_unlock(&sysfs_assoc_lock); |
36 | sysfs_put(sd); | 352 | sysfs_put(sd); |
37 | } | 353 | } |
38 | iput(inode); | 354 | iput(inode); |
@@ -42,260 +358,402 @@ static struct dentry_operations sysfs_dentry_ops = { | |||
42 | .d_iput = sysfs_d_iput, | 358 | .d_iput = sysfs_d_iput, |
43 | }; | 359 | }; |
44 | 360 | ||
45 | static unsigned int sysfs_inode_counter; | 361 | struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) |
46 | ino_t sysfs_get_inum(void) | ||
47 | { | 362 | { |
48 | if (unlikely(sysfs_inode_counter < 3)) | 363 | char *dup_name = NULL; |
49 | sysfs_inode_counter = 3; | 364 | struct sysfs_dirent *sd = NULL; |
50 | return sysfs_inode_counter++; | ||
51 | } | ||
52 | 365 | ||
53 | /* | 366 | if (type & SYSFS_COPY_NAME) { |
54 | * Allocates a new sysfs_dirent and links it to the parent sysfs_dirent | 367 | name = dup_name = kstrdup(name, GFP_KERNEL); |
55 | */ | 368 | if (!name) |
56 | static struct sysfs_dirent * __sysfs_new_dirent(void * element) | 369 | goto err_out; |
57 | { | 370 | } |
58 | struct sysfs_dirent * sd; | ||
59 | 371 | ||
60 | sd = kmem_cache_zalloc(sysfs_dir_cachep, GFP_KERNEL); | 372 | sd = kmem_cache_zalloc(sysfs_dir_cachep, GFP_KERNEL); |
61 | if (!sd) | 373 | if (!sd) |
62 | return NULL; | 374 | goto err_out; |
375 | |||
376 | if (sysfs_alloc_ino(&sd->s_ino)) | ||
377 | goto err_out; | ||
63 | 378 | ||
64 | sd->s_ino = sysfs_get_inum(); | ||
65 | atomic_set(&sd->s_count, 1); | 379 | atomic_set(&sd->s_count, 1); |
380 | atomic_set(&sd->s_active, 0); | ||
66 | atomic_set(&sd->s_event, 1); | 381 | atomic_set(&sd->s_event, 1); |
67 | INIT_LIST_HEAD(&sd->s_children); | 382 | |
68 | INIT_LIST_HEAD(&sd->s_sibling); | 383 | sd->s_name = name; |
69 | sd->s_element = element; | 384 | sd->s_mode = mode; |
385 | sd->s_flags = type; | ||
70 | 386 | ||
71 | return sd; | 387 | return sd; |
388 | |||
389 | err_out: | ||
390 | kfree(dup_name); | ||
391 | kmem_cache_free(sysfs_dir_cachep, sd); | ||
392 | return NULL; | ||
72 | } | 393 | } |
73 | 394 | ||
74 | static void __sysfs_list_dirent(struct sysfs_dirent *parent_sd, | 395 | /** |
75 | struct sysfs_dirent *sd) | 396 | * sysfs_attach_dentry - associate sysfs_dirent with dentry |
397 | * @sd: target sysfs_dirent | ||
398 | * @dentry: dentry to associate | ||
399 | * | ||
400 | * Associate @sd with @dentry. This is protected by | ||
401 | * sysfs_assoc_lock to avoid race with sysfs_d_iput(). | ||
402 | * | ||
403 | * LOCKING: | ||
404 | * mutex_lock(sysfs_mutex) | ||
405 | */ | ||
406 | static void sysfs_attach_dentry(struct sysfs_dirent *sd, struct dentry *dentry) | ||
76 | { | 407 | { |
77 | if (sd) | 408 | dentry->d_op = &sysfs_dentry_ops; |
78 | list_add(&sd->s_sibling, &parent_sd->s_children); | 409 | dentry->d_fsdata = sysfs_get(sd); |
410 | |||
411 | /* protect sd->s_dentry against sysfs_d_iput */ | ||
412 | spin_lock(&sysfs_assoc_lock); | ||
413 | sd->s_dentry = dentry; | ||
414 | spin_unlock(&sysfs_assoc_lock); | ||
415 | |||
416 | d_rehash(dentry); | ||
79 | } | 417 | } |
80 | 418 | ||
81 | static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent *parent_sd, | 419 | static int sysfs_ilookup_test(struct inode *inode, void *arg) |
82 | void * element) | ||
83 | { | 420 | { |
84 | struct sysfs_dirent *sd; | 421 | struct sysfs_dirent *sd = arg; |
85 | sd = __sysfs_new_dirent(element); | 422 | return inode->i_ino == sd->s_ino; |
86 | __sysfs_list_dirent(parent_sd, sd); | ||
87 | return sd; | ||
88 | } | 423 | } |
89 | 424 | ||
90 | /* | 425 | /** |
426 | * sysfs_addrm_start - prepare for sysfs_dirent add/remove | ||
427 | * @acxt: pointer to sysfs_addrm_cxt to be used | ||
428 | * @parent_sd: parent sysfs_dirent | ||
91 | * | 429 | * |
92 | * Return -EEXIST if there is already a sysfs element with the same name for | 430 | * This function is called when the caller is about to add or |
93 | * the same parent. | 431 | * remove sysfs_dirent under @parent_sd. This function acquires |
432 | * sysfs_mutex, grabs inode for @parent_sd if available and lock | ||
433 | * i_mutex of it. @acxt is used to keep and pass context to | ||
434 | * other addrm functions. | ||
94 | * | 435 | * |
95 | * called with parent inode's i_mutex held | 436 | * LOCKING: |
437 | * Kernel thread context (may sleep). sysfs_mutex is locked on | ||
438 | * return. i_mutex of parent inode is locked on return if | ||
439 | * available. | ||
96 | */ | 440 | */ |
97 | int sysfs_dirent_exist(struct sysfs_dirent *parent_sd, | 441 | void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, |
98 | const unsigned char *new) | 442 | struct sysfs_dirent *parent_sd) |
99 | { | 443 | { |
100 | struct sysfs_dirent * sd; | 444 | struct inode *inode; |
101 | 445 | ||
102 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { | 446 | memset(acxt, 0, sizeof(*acxt)); |
103 | if (sd->s_element) { | 447 | acxt->parent_sd = parent_sd; |
104 | const unsigned char *existing = sysfs_get_name(sd); | ||
105 | if (strcmp(existing, new)) | ||
106 | continue; | ||
107 | else | ||
108 | return -EEXIST; | ||
109 | } | ||
110 | } | ||
111 | 448 | ||
112 | return 0; | 449 | /* Lookup parent inode. inode initialization and I_NEW |
450 | * clearing are protected by sysfs_mutex. By grabbing it and | ||
451 | * looking up with _nowait variant, inode state can be | ||
452 | * determined reliably. | ||
453 | */ | ||
454 | mutex_lock(&sysfs_mutex); | ||
455 | |||
456 | inode = ilookup5_nowait(sysfs_sb, parent_sd->s_ino, sysfs_ilookup_test, | ||
457 | parent_sd); | ||
458 | |||
459 | if (inode && !(inode->i_state & I_NEW)) { | ||
460 | /* parent inode available */ | ||
461 | acxt->parent_inode = inode; | ||
462 | |||
463 | /* sysfs_mutex is below i_mutex in lock hierarchy. | ||
464 | * First, trylock i_mutex. If fails, unlock | ||
465 | * sysfs_mutex and lock them in order. | ||
466 | */ | ||
467 | if (!mutex_trylock(&inode->i_mutex)) { | ||
468 | mutex_unlock(&sysfs_mutex); | ||
469 | mutex_lock(&inode->i_mutex); | ||
470 | mutex_lock(&sysfs_mutex); | ||
471 | } | ||
472 | } else | ||
473 | iput(inode); | ||
113 | } | 474 | } |
114 | 475 | ||
476 | /** | ||
477 | * sysfs_add_one - add sysfs_dirent to parent | ||
478 | * @acxt: addrm context to use | ||
479 | * @sd: sysfs_dirent to be added | ||
480 | * | ||
481 | * Get @acxt->parent_sd and set sd->s_parent to it and increment | ||
482 | * nlink of parent inode if @sd is a directory. @sd is NOT | ||
483 | * linked into the children list of the parent. The caller | ||
484 | * should invoke sysfs_link_sibling() after this function | ||
485 | * completes if @sd needs to be on the children list. | ||
486 | * | ||
487 | * This function should be called between calls to | ||
488 | * sysfs_addrm_start() and sysfs_addrm_finish() and should be | ||
489 | * passed the same @acxt as passed to sysfs_addrm_start(). | ||
490 | * | ||
491 | * LOCKING: | ||
492 | * Determined by sysfs_addrm_start(). | ||
493 | */ | ||
494 | void sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | ||
495 | { | ||
496 | sd->s_parent = sysfs_get(acxt->parent_sd); | ||
497 | |||
498 | if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode) | ||
499 | inc_nlink(acxt->parent_inode); | ||
500 | |||
501 | acxt->cnt++; | ||
502 | } | ||
115 | 503 | ||
116 | static struct sysfs_dirent * | 504 | /** |
117 | __sysfs_make_dirent(struct dentry *dentry, void *element, mode_t mode, int type) | 505 | * sysfs_remove_one - remove sysfs_dirent from parent |
506 | * @acxt: addrm context to use | ||
507 | * @sd: sysfs_dirent to be added | ||
508 | * | ||
509 | * Mark @sd removed and drop nlink of parent inode if @sd is a | ||
510 | * directory. @sd is NOT unlinked from the children list of the | ||
511 | * parent. The caller is repsonsible for removing @sd from the | ||
512 | * children list before calling this function. | ||
513 | * | ||
514 | * This function should be called between calls to | ||
515 | * sysfs_addrm_start() and sysfs_addrm_finish() and should be | ||
516 | * passed the same @acxt as passed to sysfs_addrm_start(). | ||
517 | * | ||
518 | * LOCKING: | ||
519 | * Determined by sysfs_addrm_start(). | ||
520 | */ | ||
521 | void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | ||
118 | { | 522 | { |
119 | struct sysfs_dirent * sd; | 523 | BUG_ON(sd->s_sibling || (sd->s_flags & SYSFS_FLAG_REMOVED)); |
120 | 524 | ||
121 | sd = __sysfs_new_dirent(element); | 525 | sd->s_flags |= SYSFS_FLAG_REMOVED; |
122 | if (!sd) | 526 | sd->s_sibling = acxt->removed; |
123 | goto out; | 527 | acxt->removed = sd; |
124 | 528 | ||
125 | sd->s_mode = mode; | 529 | if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode) |
126 | sd->s_type = type; | 530 | drop_nlink(acxt->parent_inode); |
127 | sd->s_dentry = dentry; | ||
128 | if (dentry) { | ||
129 | dentry->d_fsdata = sysfs_get(sd); | ||
130 | dentry->d_op = &sysfs_dentry_ops; | ||
131 | } | ||
132 | 531 | ||
133 | out: | 532 | acxt->cnt++; |
134 | return sd; | ||
135 | } | 533 | } |
136 | 534 | ||
137 | int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry, | 535 | /** |
138 | void * element, umode_t mode, int type) | 536 | * sysfs_drop_dentry - drop dentry for the specified sysfs_dirent |
537 | * @sd: target sysfs_dirent | ||
538 | * | ||
539 | * Drop dentry for @sd. @sd must have been unlinked from its | ||
540 | * parent on entry to this function such that it can't be looked | ||
541 | * up anymore. | ||
542 | * | ||
543 | * @sd->s_dentry which is protected with sysfs_assoc_lock points | ||
544 | * to the currently associated dentry but we're not holding a | ||
545 | * reference to it and racing with dput(). Grab dcache_lock and | ||
546 | * verify dentry before dropping it. If @sd->s_dentry is NULL or | ||
547 | * dput() beats us, no need to bother. | ||
548 | */ | ||
549 | static void sysfs_drop_dentry(struct sysfs_dirent *sd) | ||
139 | { | 550 | { |
140 | struct sysfs_dirent *sd; | 551 | struct dentry *dentry = NULL; |
552 | struct inode *inode; | ||
553 | |||
554 | /* We're not holding a reference to ->s_dentry dentry but the | ||
555 | * field will stay valid as long as sysfs_assoc_lock is held. | ||
556 | */ | ||
557 | spin_lock(&sysfs_assoc_lock); | ||
558 | spin_lock(&dcache_lock); | ||
559 | |||
560 | /* drop dentry if it's there and dput() didn't kill it yet */ | ||
561 | if (sd->s_dentry && sd->s_dentry->d_inode) { | ||
562 | dentry = dget_locked(sd->s_dentry); | ||
563 | spin_lock(&dentry->d_lock); | ||
564 | __d_drop(dentry); | ||
565 | spin_unlock(&dentry->d_lock); | ||
566 | } | ||
141 | 567 | ||
142 | sd = __sysfs_make_dirent(dentry, element, mode, type); | 568 | spin_unlock(&dcache_lock); |
143 | __sysfs_list_dirent(parent_sd, sd); | 569 | spin_unlock(&sysfs_assoc_lock); |
144 | 570 | ||
145 | return sd ? 0 : -ENOMEM; | 571 | /* dentries for shadowed inodes are pinned, unpin */ |
572 | if (dentry && sysfs_is_shadowed_inode(dentry->d_inode)) | ||
573 | dput(dentry); | ||
574 | dput(dentry); | ||
575 | |||
576 | /* adjust nlink and update timestamp */ | ||
577 | inode = ilookup(sysfs_sb, sd->s_ino); | ||
578 | if (inode) { | ||
579 | mutex_lock(&inode->i_mutex); | ||
580 | |||
581 | inode->i_ctime = CURRENT_TIME; | ||
582 | drop_nlink(inode); | ||
583 | if (sysfs_type(sd) == SYSFS_DIR) | ||
584 | drop_nlink(inode); | ||
585 | |||
586 | mutex_unlock(&inode->i_mutex); | ||
587 | iput(inode); | ||
588 | } | ||
146 | } | 589 | } |
147 | 590 | ||
148 | static int init_dir(struct inode * inode) | 591 | /** |
592 | * sysfs_addrm_finish - finish up sysfs_dirent add/remove | ||
593 | * @acxt: addrm context to finish up | ||
594 | * | ||
595 | * Finish up sysfs_dirent add/remove. Resources acquired by | ||
596 | * sysfs_addrm_start() are released and removed sysfs_dirents are | ||
597 | * cleaned up. Timestamps on the parent inode are updated. | ||
598 | * | ||
599 | * LOCKING: | ||
600 | * All mutexes acquired by sysfs_addrm_start() are released. | ||
601 | * | ||
602 | * RETURNS: | ||
603 | * Number of added/removed sysfs_dirents since sysfs_addrm_start(). | ||
604 | */ | ||
605 | int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) | ||
149 | { | 606 | { |
150 | inode->i_op = &sysfs_dir_inode_operations; | 607 | /* release resources acquired by sysfs_addrm_start() */ |
151 | inode->i_fop = &sysfs_dir_operations; | 608 | mutex_unlock(&sysfs_mutex); |
609 | if (acxt->parent_inode) { | ||
610 | struct inode *inode = acxt->parent_inode; | ||
152 | 611 | ||
153 | /* directory inodes start off with i_nlink == 2 (for "." entry) */ | 612 | /* if added/removed, update timestamps on the parent */ |
154 | inc_nlink(inode); | 613 | if (acxt->cnt) |
155 | return 0; | 614 | inode->i_ctime = inode->i_mtime = CURRENT_TIME; |
615 | |||
616 | mutex_unlock(&inode->i_mutex); | ||
617 | iput(inode); | ||
618 | } | ||
619 | |||
620 | /* kill removed sysfs_dirents */ | ||
621 | while (acxt->removed) { | ||
622 | struct sysfs_dirent *sd = acxt->removed; | ||
623 | |||
624 | acxt->removed = sd->s_sibling; | ||
625 | sd->s_sibling = NULL; | ||
626 | |||
627 | sysfs_drop_dentry(sd); | ||
628 | sysfs_deactivate(sd); | ||
629 | sysfs_put(sd); | ||
630 | } | ||
631 | |||
632 | return acxt->cnt; | ||
156 | } | 633 | } |
157 | 634 | ||
158 | static int init_file(struct inode * inode) | 635 | /** |
636 | * sysfs_find_dirent - find sysfs_dirent with the given name | ||
637 | * @parent_sd: sysfs_dirent to search under | ||
638 | * @name: name to look for | ||
639 | * | ||
640 | * Look for sysfs_dirent with name @name under @parent_sd. | ||
641 | * | ||
642 | * LOCKING: | ||
643 | * mutex_lock(sysfs_mutex) | ||
644 | * | ||
645 | * RETURNS: | ||
646 | * Pointer to sysfs_dirent if found, NULL if not. | ||
647 | */ | ||
648 | struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, | ||
649 | const unsigned char *name) | ||
159 | { | 650 | { |
160 | inode->i_size = PAGE_SIZE; | 651 | struct sysfs_dirent *sd; |
161 | inode->i_fop = &sysfs_file_operations; | 652 | |
162 | return 0; | 653 | for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) |
654 | if (sysfs_type(sd) && !strcmp(sd->s_name, name)) | ||
655 | return sd; | ||
656 | return NULL; | ||
163 | } | 657 | } |
164 | 658 | ||
165 | static int init_symlink(struct inode * inode) | 659 | /** |
660 | * sysfs_get_dirent - find and get sysfs_dirent with the given name | ||
661 | * @parent_sd: sysfs_dirent to search under | ||
662 | * @name: name to look for | ||
663 | * | ||
664 | * Look for sysfs_dirent with name @name under @parent_sd and get | ||
665 | * it if found. | ||
666 | * | ||
667 | * LOCKING: | ||
668 | * Kernel thread context (may sleep). Grabs sysfs_mutex. | ||
669 | * | ||
670 | * RETURNS: | ||
671 | * Pointer to sysfs_dirent if found, NULL if not. | ||
672 | */ | ||
673 | struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, | ||
674 | const unsigned char *name) | ||
166 | { | 675 | { |
167 | inode->i_op = &sysfs_symlink_inode_operations; | 676 | struct sysfs_dirent *sd; |
168 | return 0; | 677 | |
678 | mutex_lock(&sysfs_mutex); | ||
679 | sd = sysfs_find_dirent(parent_sd, name); | ||
680 | sysfs_get(sd); | ||
681 | mutex_unlock(&sysfs_mutex); | ||
682 | |||
683 | return sd; | ||
169 | } | 684 | } |
170 | 685 | ||
171 | static int create_dir(struct kobject * k, struct dentry * p, | 686 | static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, |
172 | const char * n, struct dentry ** d) | 687 | const char *name, struct sysfs_dirent **p_sd) |
173 | { | 688 | { |
174 | int error; | ||
175 | umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; | 689 | umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; |
690 | struct sysfs_addrm_cxt acxt; | ||
691 | struct sysfs_dirent *sd; | ||
176 | 692 | ||
177 | mutex_lock(&p->d_inode->i_mutex); | 693 | /* allocate */ |
178 | *d = lookup_one_len(n, p, strlen(n)); | 694 | sd = sysfs_new_dirent(name, mode, SYSFS_DIR); |
179 | if (!IS_ERR(*d)) { | 695 | if (!sd) |
180 | if (sysfs_dirent_exist(p->d_fsdata, n)) | 696 | return -ENOMEM; |
181 | error = -EEXIST; | 697 | sd->s_elem.dir.kobj = kobj; |
182 | else | ||
183 | error = sysfs_make_dirent(p->d_fsdata, *d, k, mode, | ||
184 | SYSFS_DIR); | ||
185 | if (!error) { | ||
186 | error = sysfs_create(*d, mode, init_dir); | ||
187 | if (!error) { | ||
188 | inc_nlink(p->d_inode); | ||
189 | (*d)->d_op = &sysfs_dentry_ops; | ||
190 | d_rehash(*d); | ||
191 | } | ||
192 | } | ||
193 | if (error && (error != -EEXIST)) { | ||
194 | struct sysfs_dirent *sd = (*d)->d_fsdata; | ||
195 | if (sd) { | ||
196 | list_del_init(&sd->s_sibling); | ||
197 | sysfs_put(sd); | ||
198 | } | ||
199 | d_drop(*d); | ||
200 | } | ||
201 | dput(*d); | ||
202 | } else | ||
203 | error = PTR_ERR(*d); | ||
204 | mutex_unlock(&p->d_inode->i_mutex); | ||
205 | return error; | ||
206 | } | ||
207 | 698 | ||
699 | /* link in */ | ||
700 | sysfs_addrm_start(&acxt, parent_sd); | ||
701 | if (!sysfs_find_dirent(parent_sd, name)) { | ||
702 | sysfs_add_one(&acxt, sd); | ||
703 | sysfs_link_sibling(sd); | ||
704 | } | ||
705 | if (sysfs_addrm_finish(&acxt)) { | ||
706 | *p_sd = sd; | ||
707 | return 0; | ||
708 | } | ||
208 | 709 | ||
209 | int sysfs_create_subdir(struct kobject * k, const char * n, struct dentry ** d) | 710 | sysfs_put(sd); |
711 | return -EEXIST; | ||
712 | } | ||
713 | |||
714 | int sysfs_create_subdir(struct kobject *kobj, const char *name, | ||
715 | struct sysfs_dirent **p_sd) | ||
210 | { | 716 | { |
211 | return create_dir(k,k->dentry,n,d); | 717 | return create_dir(kobj, kobj->sd, name, p_sd); |
212 | } | 718 | } |
213 | 719 | ||
214 | /** | 720 | /** |
215 | * sysfs_create_dir - create a directory for an object. | 721 | * sysfs_create_dir - create a directory for an object. |
216 | * @kobj: object we're creating directory for. | 722 | * @kobj: object we're creating directory for. |
217 | * @shadow_parent: parent parent object. | 723 | * @shadow_parent: parent object. |
218 | */ | 724 | */ |
219 | 725 | int sysfs_create_dir(struct kobject *kobj, | |
220 | int sysfs_create_dir(struct kobject * kobj, struct dentry *shadow_parent) | 726 | struct sysfs_dirent *shadow_parent_sd) |
221 | { | 727 | { |
222 | struct dentry * dentry = NULL; | 728 | struct sysfs_dirent *parent_sd, *sd; |
223 | struct dentry * parent; | ||
224 | int error = 0; | 729 | int error = 0; |
225 | 730 | ||
226 | BUG_ON(!kobj); | 731 | BUG_ON(!kobj); |
227 | 732 | ||
228 | if (shadow_parent) | 733 | if (shadow_parent_sd) |
229 | parent = shadow_parent; | 734 | parent_sd = shadow_parent_sd; |
230 | else if (kobj->parent) | 735 | else if (kobj->parent) |
231 | parent = kobj->parent->dentry; | 736 | parent_sd = kobj->parent->sd; |
232 | else if (sysfs_mount && sysfs_mount->mnt_sb) | 737 | else if (sysfs_mount && sysfs_mount->mnt_sb) |
233 | parent = sysfs_mount->mnt_sb->s_root; | 738 | parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata; |
234 | else | 739 | else |
235 | return -EFAULT; | 740 | return -EFAULT; |
236 | 741 | ||
237 | error = create_dir(kobj,parent,kobject_name(kobj),&dentry); | 742 | error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd); |
238 | if (!error) | 743 | if (!error) |
239 | kobj->dentry = dentry; | 744 | kobj->sd = sd; |
240 | return error; | 745 | return error; |
241 | } | 746 | } |
242 | 747 | ||
243 | /* attaches attribute's sysfs_dirent to the dentry corresponding to the | 748 | static int sysfs_count_nlink(struct sysfs_dirent *sd) |
244 | * attribute file | ||
245 | */ | ||
246 | static int sysfs_attach_attr(struct sysfs_dirent * sd, struct dentry * dentry) | ||
247 | { | 749 | { |
248 | struct attribute * attr = NULL; | 750 | struct sysfs_dirent *child; |
249 | struct bin_attribute * bin_attr = NULL; | 751 | int nr = 0; |
250 | int (* init) (struct inode *) = NULL; | ||
251 | int error = 0; | ||
252 | |||
253 | if (sd->s_type & SYSFS_KOBJ_BIN_ATTR) { | ||
254 | bin_attr = sd->s_element; | ||
255 | attr = &bin_attr->attr; | ||
256 | } else { | ||
257 | attr = sd->s_element; | ||
258 | init = init_file; | ||
259 | } | ||
260 | 752 | ||
261 | dentry->d_fsdata = sysfs_get(sd); | 753 | for (child = sd->s_children; child; child = child->s_sibling) |
262 | /* protect sd->s_dentry against sysfs_d_iput */ | 754 | if (sysfs_type(child) == SYSFS_DIR) |
263 | spin_lock(&sysfs_lock); | 755 | nr++; |
264 | sd->s_dentry = dentry; | 756 | return nr + 2; |
265 | spin_unlock(&sysfs_lock); | ||
266 | error = sysfs_create(dentry, (attr->mode & S_IALLUGO) | S_IFREG, init); | ||
267 | if (error) { | ||
268 | sysfs_put(sd); | ||
269 | return error; | ||
270 | } | ||
271 | |||
272 | if (bin_attr) { | ||
273 | dentry->d_inode->i_size = bin_attr->size; | ||
274 | dentry->d_inode->i_fop = &bin_fops; | ||
275 | } | ||
276 | dentry->d_op = &sysfs_dentry_ops; | ||
277 | d_rehash(dentry); | ||
278 | |||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | static int sysfs_attach_link(struct sysfs_dirent * sd, struct dentry * dentry) | ||
283 | { | ||
284 | int err = 0; | ||
285 | |||
286 | dentry->d_fsdata = sysfs_get(sd); | ||
287 | /* protect sd->s_dentry against sysfs_d_iput */ | ||
288 | spin_lock(&sysfs_lock); | ||
289 | sd->s_dentry = dentry; | ||
290 | spin_unlock(&sysfs_lock); | ||
291 | err = sysfs_create(dentry, S_IFLNK|S_IRWXUGO, init_symlink); | ||
292 | if (!err) { | ||
293 | dentry->d_op = &sysfs_dentry_ops; | ||
294 | d_rehash(dentry); | ||
295 | } else | ||
296 | sysfs_put(sd); | ||
297 | |||
298 | return err; | ||
299 | } | 757 | } |
300 | 758 | ||
301 | static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, | 759 | static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, |
@@ -303,24 +761,60 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, | |||
303 | { | 761 | { |
304 | struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata; | 762 | struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata; |
305 | struct sysfs_dirent * sd; | 763 | struct sysfs_dirent * sd; |
306 | int err = 0; | 764 | struct bin_attribute *bin_attr; |
765 | struct inode *inode; | ||
766 | int found = 0; | ||
307 | 767 | ||
308 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { | 768 | for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) { |
309 | if (sd->s_type & SYSFS_NOT_PINNED) { | 769 | if (sysfs_type(sd) && |
310 | const unsigned char * name = sysfs_get_name(sd); | 770 | !strcmp(sd->s_name, dentry->d_name.name)) { |
771 | found = 1; | ||
772 | break; | ||
773 | } | ||
774 | } | ||
311 | 775 | ||
312 | if (strcmp(name, dentry->d_name.name)) | 776 | /* no such entry */ |
313 | continue; | 777 | if (!found) |
778 | return NULL; | ||
314 | 779 | ||
315 | if (sd->s_type & SYSFS_KOBJ_LINK) | 780 | /* attach dentry and inode */ |
316 | err = sysfs_attach_link(sd, dentry); | 781 | inode = sysfs_get_inode(sd); |
317 | else | 782 | if (!inode) |
318 | err = sysfs_attach_attr(sd, dentry); | 783 | return ERR_PTR(-ENOMEM); |
784 | |||
785 | mutex_lock(&sysfs_mutex); | ||
786 | |||
787 | if (inode->i_state & I_NEW) { | ||
788 | /* initialize inode according to type */ | ||
789 | switch (sysfs_type(sd)) { | ||
790 | case SYSFS_DIR: | ||
791 | inode->i_op = &sysfs_dir_inode_operations; | ||
792 | inode->i_fop = &sysfs_dir_operations; | ||
793 | inode->i_nlink = sysfs_count_nlink(sd); | ||
794 | break; | ||
795 | case SYSFS_KOBJ_ATTR: | ||
796 | inode->i_size = PAGE_SIZE; | ||
797 | inode->i_fop = &sysfs_file_operations; | ||
798 | break; | ||
799 | case SYSFS_KOBJ_BIN_ATTR: | ||
800 | bin_attr = sd->s_elem.bin_attr.bin_attr; | ||
801 | inode->i_size = bin_attr->size; | ||
802 | inode->i_fop = &bin_fops; | ||
319 | break; | 803 | break; |
804 | case SYSFS_KOBJ_LINK: | ||
805 | inode->i_op = &sysfs_symlink_inode_operations; | ||
806 | break; | ||
807 | default: | ||
808 | BUG(); | ||
320 | } | 809 | } |
321 | } | 810 | } |
322 | 811 | ||
323 | return ERR_PTR(err); | 812 | sysfs_instantiate(dentry, inode); |
813 | sysfs_attach_dentry(sd, dentry); | ||
814 | |||
815 | mutex_unlock(&sysfs_mutex); | ||
816 | |||
817 | return NULL; | ||
324 | } | 818 | } |
325 | 819 | ||
326 | const struct inode_operations sysfs_dir_inode_operations = { | 820 | const struct inode_operations sysfs_dir_inode_operations = { |
@@ -328,58 +822,46 @@ const struct inode_operations sysfs_dir_inode_operations = { | |||
328 | .setattr = sysfs_setattr, | 822 | .setattr = sysfs_setattr, |
329 | }; | 823 | }; |
330 | 824 | ||
331 | static void remove_dir(struct dentry * d) | 825 | static void remove_dir(struct sysfs_dirent *sd) |
332 | { | 826 | { |
333 | struct dentry * parent = dget(d->d_parent); | 827 | struct sysfs_addrm_cxt acxt; |
334 | struct sysfs_dirent * sd; | ||
335 | |||
336 | mutex_lock(&parent->d_inode->i_mutex); | ||
337 | d_delete(d); | ||
338 | sd = d->d_fsdata; | ||
339 | list_del_init(&sd->s_sibling); | ||
340 | sysfs_put(sd); | ||
341 | if (d->d_inode) | ||
342 | simple_rmdir(parent->d_inode,d); | ||
343 | |||
344 | pr_debug(" o %s removing done (%d)\n",d->d_name.name, | ||
345 | atomic_read(&d->d_count)); | ||
346 | 828 | ||
347 | mutex_unlock(&parent->d_inode->i_mutex); | 829 | sysfs_addrm_start(&acxt, sd->s_parent); |
348 | dput(parent); | 830 | sysfs_unlink_sibling(sd); |
831 | sysfs_remove_one(&acxt, sd); | ||
832 | sysfs_addrm_finish(&acxt); | ||
349 | } | 833 | } |
350 | 834 | ||
351 | void sysfs_remove_subdir(struct dentry * d) | 835 | void sysfs_remove_subdir(struct sysfs_dirent *sd) |
352 | { | 836 | { |
353 | remove_dir(d); | 837 | remove_dir(sd); |
354 | } | 838 | } |
355 | 839 | ||
356 | 840 | ||
357 | static void __sysfs_remove_dir(struct dentry *dentry) | 841 | static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd) |
358 | { | 842 | { |
359 | struct sysfs_dirent * parent_sd; | 843 | struct sysfs_addrm_cxt acxt; |
360 | struct sysfs_dirent * sd, * tmp; | 844 | struct sysfs_dirent **pos; |
361 | 845 | ||
362 | dget(dentry); | 846 | if (!dir_sd) |
363 | if (!dentry) | ||
364 | return; | 847 | return; |
365 | 848 | ||
366 | pr_debug("sysfs %s: removing dir\n",dentry->d_name.name); | 849 | pr_debug("sysfs %s: removing dir\n", dir_sd->s_name); |
367 | mutex_lock(&dentry->d_inode->i_mutex); | 850 | sysfs_addrm_start(&acxt, dir_sd); |
368 | parent_sd = dentry->d_fsdata; | 851 | pos = &dir_sd->s_children; |
369 | list_for_each_entry_safe(sd, tmp, &parent_sd->s_children, s_sibling) { | 852 | while (*pos) { |
370 | if (!sd->s_element || !(sd->s_type & SYSFS_NOT_PINNED)) | 853 | struct sysfs_dirent *sd = *pos; |
371 | continue; | 854 | |
372 | list_del_init(&sd->s_sibling); | 855 | if (sysfs_type(sd) && sysfs_type(sd) != SYSFS_DIR) { |
373 | sysfs_drop_dentry(sd, dentry); | 856 | *pos = sd->s_sibling; |
374 | sysfs_put(sd); | 857 | sd->s_sibling = NULL; |
858 | sysfs_remove_one(&acxt, sd); | ||
859 | } else | ||
860 | pos = &(*pos)->s_sibling; | ||
375 | } | 861 | } |
376 | mutex_unlock(&dentry->d_inode->i_mutex); | 862 | sysfs_addrm_finish(&acxt); |
377 | 863 | ||
378 | remove_dir(dentry); | 864 | remove_dir(dir_sd); |
379 | /** | ||
380 | * Drop reference from dget() on entrance. | ||
381 | */ | ||
382 | dput(dentry); | ||
383 | } | 865 | } |
384 | 866 | ||
385 | /** | 867 | /** |
@@ -393,102 +875,166 @@ static void __sysfs_remove_dir(struct dentry *dentry) | |||
393 | 875 | ||
394 | void sysfs_remove_dir(struct kobject * kobj) | 876 | void sysfs_remove_dir(struct kobject * kobj) |
395 | { | 877 | { |
396 | __sysfs_remove_dir(kobj->dentry); | 878 | struct sysfs_dirent *sd = kobj->sd; |
397 | kobj->dentry = NULL; | 879 | |
880 | spin_lock(&sysfs_assoc_lock); | ||
881 | kobj->sd = NULL; | ||
882 | spin_unlock(&sysfs_assoc_lock); | ||
883 | |||
884 | __sysfs_remove_dir(sd); | ||
398 | } | 885 | } |
399 | 886 | ||
400 | int sysfs_rename_dir(struct kobject * kobj, struct dentry *new_parent, | 887 | int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd, |
401 | const char *new_name) | 888 | const char *new_name) |
402 | { | 889 | { |
403 | int error = 0; | 890 | struct sysfs_dirent *sd = kobj->sd; |
404 | struct dentry * new_dentry; | 891 | struct dentry *new_parent = NULL; |
892 | struct dentry *old_dentry = NULL, *new_dentry = NULL; | ||
893 | const char *dup_name = NULL; | ||
894 | int error; | ||
405 | 895 | ||
406 | if (!new_parent) | 896 | /* get dentries */ |
407 | return -EFAULT; | 897 | old_dentry = sysfs_get_dentry(sd); |
898 | if (IS_ERR(old_dentry)) { | ||
899 | error = PTR_ERR(old_dentry); | ||
900 | goto out_dput; | ||
901 | } | ||
408 | 902 | ||
409 | down_write(&sysfs_rename_sem); | 903 | new_parent = sysfs_get_dentry(new_parent_sd); |
904 | if (IS_ERR(new_parent)) { | ||
905 | error = PTR_ERR(new_parent); | ||
906 | goto out_dput; | ||
907 | } | ||
908 | |||
909 | /* lock new_parent and get dentry for new name */ | ||
410 | mutex_lock(&new_parent->d_inode->i_mutex); | 910 | mutex_lock(&new_parent->d_inode->i_mutex); |
411 | 911 | ||
412 | new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name)); | 912 | new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name)); |
413 | if (!IS_ERR(new_dentry)) { | 913 | if (IS_ERR(new_dentry)) { |
414 | /* By allowing two different directories with the | 914 | error = PTR_ERR(new_dentry); |
415 | * same d_parent we allow this routine to move | 915 | goto out_unlock; |
416 | * between different shadows of the same directory | ||
417 | */ | ||
418 | if (kobj->dentry->d_parent->d_inode != new_parent->d_inode) | ||
419 | return -EINVAL; | ||
420 | else if (new_dentry->d_parent->d_inode != new_parent->d_inode) | ||
421 | error = -EINVAL; | ||
422 | else if (new_dentry == kobj->dentry) | ||
423 | error = -EINVAL; | ||
424 | else if (!new_dentry->d_inode) { | ||
425 | error = kobject_set_name(kobj, "%s", new_name); | ||
426 | if (!error) { | ||
427 | struct sysfs_dirent *sd, *parent_sd; | ||
428 | |||
429 | d_add(new_dentry, NULL); | ||
430 | d_move(kobj->dentry, new_dentry); | ||
431 | |||
432 | sd = kobj->dentry->d_fsdata; | ||
433 | parent_sd = new_parent->d_fsdata; | ||
434 | |||
435 | list_del_init(&sd->s_sibling); | ||
436 | list_add(&sd->s_sibling, &parent_sd->s_children); | ||
437 | } | ||
438 | else | ||
439 | d_drop(new_dentry); | ||
440 | } else | ||
441 | error = -EEXIST; | ||
442 | dput(new_dentry); | ||
443 | } | 916 | } |
444 | mutex_unlock(&new_parent->d_inode->i_mutex); | ||
445 | up_write(&sysfs_rename_sem); | ||
446 | 917 | ||
918 | /* By allowing two different directories with the same | ||
919 | * d_parent we allow this routine to move between different | ||
920 | * shadows of the same directory | ||
921 | */ | ||
922 | error = -EINVAL; | ||
923 | if (old_dentry->d_parent->d_inode != new_parent->d_inode || | ||
924 | new_dentry->d_parent->d_inode != new_parent->d_inode || | ||
925 | old_dentry == new_dentry) | ||
926 | goto out_unlock; | ||
927 | |||
928 | error = -EEXIST; | ||
929 | if (new_dentry->d_inode) | ||
930 | goto out_unlock; | ||
931 | |||
932 | /* rename kobject and sysfs_dirent */ | ||
933 | error = -ENOMEM; | ||
934 | new_name = dup_name = kstrdup(new_name, GFP_KERNEL); | ||
935 | if (!new_name) | ||
936 | goto out_drop; | ||
937 | |||
938 | error = kobject_set_name(kobj, "%s", new_name); | ||
939 | if (error) | ||
940 | goto out_drop; | ||
941 | |||
942 | dup_name = sd->s_name; | ||
943 | sd->s_name = new_name; | ||
944 | |||
945 | /* move under the new parent */ | ||
946 | d_add(new_dentry, NULL); | ||
947 | d_move(sd->s_dentry, new_dentry); | ||
948 | |||
949 | mutex_lock(&sysfs_mutex); | ||
950 | |||
951 | sysfs_unlink_sibling(sd); | ||
952 | sysfs_get(new_parent_sd); | ||
953 | sysfs_put(sd->s_parent); | ||
954 | sd->s_parent = new_parent_sd; | ||
955 | sysfs_link_sibling(sd); | ||
956 | |||
957 | mutex_unlock(&sysfs_mutex); | ||
958 | |||
959 | error = 0; | ||
960 | goto out_unlock; | ||
961 | |||
962 | out_drop: | ||
963 | d_drop(new_dentry); | ||
964 | out_unlock: | ||
965 | mutex_unlock(&new_parent->d_inode->i_mutex); | ||
966 | out_dput: | ||
967 | kfree(dup_name); | ||
968 | dput(new_parent); | ||
969 | dput(old_dentry); | ||
970 | dput(new_dentry); | ||
447 | return error; | 971 | return error; |
448 | } | 972 | } |
449 | 973 | ||
450 | int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent) | 974 | int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) |
451 | { | 975 | { |
452 | struct dentry *old_parent_dentry, *new_parent_dentry, *new_dentry; | 976 | struct sysfs_dirent *sd = kobj->sd; |
453 | struct sysfs_dirent *new_parent_sd, *sd; | 977 | struct sysfs_dirent *new_parent_sd; |
978 | struct dentry *old_parent, *new_parent = NULL; | ||
979 | struct dentry *old_dentry = NULL, *new_dentry = NULL; | ||
454 | int error; | 980 | int error; |
455 | 981 | ||
456 | old_parent_dentry = kobj->parent ? | 982 | BUG_ON(!sd->s_parent); |
457 | kobj->parent->dentry : sysfs_mount->mnt_sb->s_root; | 983 | new_parent_sd = new_parent_kobj->sd ? new_parent_kobj->sd : &sysfs_root; |
458 | new_parent_dentry = new_parent ? | 984 | |
459 | new_parent->dentry : sysfs_mount->mnt_sb->s_root; | 985 | /* get dentries */ |
986 | old_dentry = sysfs_get_dentry(sd); | ||
987 | if (IS_ERR(old_dentry)) { | ||
988 | error = PTR_ERR(old_dentry); | ||
989 | goto out_dput; | ||
990 | } | ||
991 | old_parent = sd->s_parent->s_dentry; | ||
992 | |||
993 | new_parent = sysfs_get_dentry(new_parent_sd); | ||
994 | if (IS_ERR(new_parent)) { | ||
995 | error = PTR_ERR(new_parent); | ||
996 | goto out_dput; | ||
997 | } | ||
460 | 998 | ||
461 | if (old_parent_dentry->d_inode == new_parent_dentry->d_inode) | 999 | if (old_parent->d_inode == new_parent->d_inode) { |
462 | return 0; /* nothing to move */ | 1000 | error = 0; |
1001 | goto out_dput; /* nothing to move */ | ||
1002 | } | ||
463 | again: | 1003 | again: |
464 | mutex_lock(&old_parent_dentry->d_inode->i_mutex); | 1004 | mutex_lock(&old_parent->d_inode->i_mutex); |
465 | if (!mutex_trylock(&new_parent_dentry->d_inode->i_mutex)) { | 1005 | if (!mutex_trylock(&new_parent->d_inode->i_mutex)) { |
466 | mutex_unlock(&old_parent_dentry->d_inode->i_mutex); | 1006 | mutex_unlock(&old_parent->d_inode->i_mutex); |
467 | goto again; | 1007 | goto again; |
468 | } | 1008 | } |
469 | 1009 | ||
470 | new_parent_sd = new_parent_dentry->d_fsdata; | 1010 | new_dentry = lookup_one_len(kobj->name, new_parent, strlen(kobj->name)); |
471 | sd = kobj->dentry->d_fsdata; | ||
472 | |||
473 | new_dentry = lookup_one_len(kobj->name, new_parent_dentry, | ||
474 | strlen(kobj->name)); | ||
475 | if (IS_ERR(new_dentry)) { | 1011 | if (IS_ERR(new_dentry)) { |
476 | error = PTR_ERR(new_dentry); | 1012 | error = PTR_ERR(new_dentry); |
477 | goto out; | 1013 | goto out_unlock; |
478 | } else | 1014 | } else |
479 | error = 0; | 1015 | error = 0; |
480 | d_add(new_dentry, NULL); | 1016 | d_add(new_dentry, NULL); |
481 | d_move(kobj->dentry, new_dentry); | 1017 | d_move(sd->s_dentry, new_dentry); |
482 | dput(new_dentry); | 1018 | dput(new_dentry); |
483 | 1019 | ||
484 | /* Remove from old parent's list and insert into new parent's list. */ | 1020 | /* Remove from old parent's list and insert into new parent's list. */ |
485 | list_del_init(&sd->s_sibling); | 1021 | mutex_lock(&sysfs_mutex); |
486 | list_add(&sd->s_sibling, &new_parent_sd->s_children); | 1022 | |
1023 | sysfs_unlink_sibling(sd); | ||
1024 | sysfs_get(new_parent_sd); | ||
1025 | sysfs_put(sd->s_parent); | ||
1026 | sd->s_parent = new_parent_sd; | ||
1027 | sysfs_link_sibling(sd); | ||
487 | 1028 | ||
488 | out: | 1029 | mutex_unlock(&sysfs_mutex); |
489 | mutex_unlock(&new_parent_dentry->d_inode->i_mutex); | ||
490 | mutex_unlock(&old_parent_dentry->d_inode->i_mutex); | ||
491 | 1030 | ||
1031 | out_unlock: | ||
1032 | mutex_unlock(&new_parent->d_inode->i_mutex); | ||
1033 | mutex_unlock(&old_parent->d_inode->i_mutex); | ||
1034 | out_dput: | ||
1035 | dput(new_parent); | ||
1036 | dput(old_dentry); | ||
1037 | dput(new_dentry); | ||
492 | return error; | 1038 | return error; |
493 | } | 1039 | } |
494 | 1040 | ||
@@ -496,23 +1042,27 @@ static int sysfs_dir_open(struct inode *inode, struct file *file) | |||
496 | { | 1042 | { |
497 | struct dentry * dentry = file->f_path.dentry; | 1043 | struct dentry * dentry = file->f_path.dentry; |
498 | struct sysfs_dirent * parent_sd = dentry->d_fsdata; | 1044 | struct sysfs_dirent * parent_sd = dentry->d_fsdata; |
1045 | struct sysfs_dirent * sd; | ||
499 | 1046 | ||
500 | mutex_lock(&dentry->d_inode->i_mutex); | 1047 | sd = sysfs_new_dirent("_DIR_", 0, 0); |
501 | file->private_data = sysfs_new_dirent(parent_sd, NULL); | 1048 | if (sd) { |
502 | mutex_unlock(&dentry->d_inode->i_mutex); | 1049 | mutex_lock(&sysfs_mutex); |
503 | 1050 | sd->s_parent = sysfs_get(parent_sd); | |
504 | return file->private_data ? 0 : -ENOMEM; | 1051 | sysfs_link_sibling(sd); |
1052 | mutex_unlock(&sysfs_mutex); | ||
1053 | } | ||
505 | 1054 | ||
1055 | file->private_data = sd; | ||
1056 | return sd ? 0 : -ENOMEM; | ||
506 | } | 1057 | } |
507 | 1058 | ||
508 | static int sysfs_dir_close(struct inode *inode, struct file *file) | 1059 | static int sysfs_dir_close(struct inode *inode, struct file *file) |
509 | { | 1060 | { |
510 | struct dentry * dentry = file->f_path.dentry; | ||
511 | struct sysfs_dirent * cursor = file->private_data; | 1061 | struct sysfs_dirent * cursor = file->private_data; |
512 | 1062 | ||
513 | mutex_lock(&dentry->d_inode->i_mutex); | 1063 | mutex_lock(&sysfs_mutex); |
514 | list_del_init(&cursor->s_sibling); | 1064 | sysfs_unlink_sibling(cursor); |
515 | mutex_unlock(&dentry->d_inode->i_mutex); | 1065 | mutex_unlock(&sysfs_mutex); |
516 | 1066 | ||
517 | release_sysfs_dirent(cursor); | 1067 | release_sysfs_dirent(cursor); |
518 | 1068 | ||
@@ -530,7 +1080,7 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
530 | struct dentry *dentry = filp->f_path.dentry; | 1080 | struct dentry *dentry = filp->f_path.dentry; |
531 | struct sysfs_dirent * parent_sd = dentry->d_fsdata; | 1081 | struct sysfs_dirent * parent_sd = dentry->d_fsdata; |
532 | struct sysfs_dirent *cursor = filp->private_data; | 1082 | struct sysfs_dirent *cursor = filp->private_data; |
533 | struct list_head *p, *q = &cursor->s_sibling; | 1083 | struct sysfs_dirent **pos; |
534 | ino_t ino; | 1084 | ino_t ino; |
535 | int i = filp->f_pos; | 1085 | int i = filp->f_pos; |
536 | 1086 | ||
@@ -543,38 +1093,52 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
543 | i++; | 1093 | i++; |
544 | /* fallthrough */ | 1094 | /* fallthrough */ |
545 | case 1: | 1095 | case 1: |
546 | ino = parent_ino(dentry); | 1096 | if (parent_sd->s_parent) |
1097 | ino = parent_sd->s_parent->s_ino; | ||
1098 | else | ||
1099 | ino = parent_sd->s_ino; | ||
547 | if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0) | 1100 | if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0) |
548 | break; | 1101 | break; |
549 | filp->f_pos++; | 1102 | filp->f_pos++; |
550 | i++; | 1103 | i++; |
551 | /* fallthrough */ | 1104 | /* fallthrough */ |
552 | default: | 1105 | default: |
1106 | mutex_lock(&sysfs_mutex); | ||
1107 | |||
1108 | pos = &parent_sd->s_children; | ||
1109 | while (*pos != cursor) | ||
1110 | pos = &(*pos)->s_sibling; | ||
1111 | |||
1112 | /* unlink cursor */ | ||
1113 | *pos = cursor->s_sibling; | ||
1114 | |||
553 | if (filp->f_pos == 2) | 1115 | if (filp->f_pos == 2) |
554 | list_move(q, &parent_sd->s_children); | 1116 | pos = &parent_sd->s_children; |
555 | 1117 | ||
556 | for (p=q->next; p!= &parent_sd->s_children; p=p->next) { | 1118 | for ( ; *pos; pos = &(*pos)->s_sibling) { |
557 | struct sysfs_dirent *next; | 1119 | struct sysfs_dirent *next = *pos; |
558 | const char * name; | 1120 | const char * name; |
559 | int len; | 1121 | int len; |
560 | 1122 | ||
561 | next = list_entry(p, struct sysfs_dirent, | 1123 | if (!sysfs_type(next)) |
562 | s_sibling); | ||
563 | if (!next->s_element) | ||
564 | continue; | 1124 | continue; |
565 | 1125 | ||
566 | name = sysfs_get_name(next); | 1126 | name = next->s_name; |
567 | len = strlen(name); | 1127 | len = strlen(name); |
568 | ino = next->s_ino; | 1128 | ino = next->s_ino; |
569 | 1129 | ||
570 | if (filldir(dirent, name, len, filp->f_pos, ino, | 1130 | if (filldir(dirent, name, len, filp->f_pos, ino, |
571 | dt_type(next)) < 0) | 1131 | dt_type(next)) < 0) |
572 | return 0; | 1132 | break; |
573 | 1133 | ||
574 | list_move(q, p); | ||
575 | p = q; | ||
576 | filp->f_pos++; | 1134 | filp->f_pos++; |
577 | } | 1135 | } |
1136 | |||
1137 | /* put cursor back in */ | ||
1138 | cursor->s_sibling = *pos; | ||
1139 | *pos = cursor; | ||
1140 | |||
1141 | mutex_unlock(&sysfs_mutex); | ||
578 | } | 1142 | } |
579 | return 0; | 1143 | return 0; |
580 | } | 1144 | } |
@@ -583,7 +1147,6 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin) | |||
583 | { | 1147 | { |
584 | struct dentry * dentry = file->f_path.dentry; | 1148 | struct dentry * dentry = file->f_path.dentry; |
585 | 1149 | ||
586 | mutex_lock(&dentry->d_inode->i_mutex); | ||
587 | switch (origin) { | 1150 | switch (origin) { |
588 | case 1: | 1151 | case 1: |
589 | offset += file->f_pos; | 1152 | offset += file->f_pos; |
@@ -591,31 +1154,35 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin) | |||
591 | if (offset >= 0) | 1154 | if (offset >= 0) |
592 | break; | 1155 | break; |
593 | default: | 1156 | default: |
594 | mutex_unlock(&file->f_path.dentry->d_inode->i_mutex); | ||
595 | return -EINVAL; | 1157 | return -EINVAL; |
596 | } | 1158 | } |
597 | if (offset != file->f_pos) { | 1159 | if (offset != file->f_pos) { |
1160 | mutex_lock(&sysfs_mutex); | ||
1161 | |||
598 | file->f_pos = offset; | 1162 | file->f_pos = offset; |
599 | if (file->f_pos >= 2) { | 1163 | if (file->f_pos >= 2) { |
600 | struct sysfs_dirent *sd = dentry->d_fsdata; | 1164 | struct sysfs_dirent *sd = dentry->d_fsdata; |
601 | struct sysfs_dirent *cursor = file->private_data; | 1165 | struct sysfs_dirent *cursor = file->private_data; |
602 | struct list_head *p; | 1166 | struct sysfs_dirent **pos; |
603 | loff_t n = file->f_pos - 2; | 1167 | loff_t n = file->f_pos - 2; |
604 | 1168 | ||
605 | list_del(&cursor->s_sibling); | 1169 | sysfs_unlink_sibling(cursor); |
606 | p = sd->s_children.next; | 1170 | |
607 | while (n && p != &sd->s_children) { | 1171 | pos = &sd->s_children; |
608 | struct sysfs_dirent *next; | 1172 | while (n && *pos) { |
609 | next = list_entry(p, struct sysfs_dirent, | 1173 | struct sysfs_dirent *next = *pos; |
610 | s_sibling); | 1174 | if (sysfs_type(next)) |
611 | if (next->s_element) | ||
612 | n--; | 1175 | n--; |
613 | p = p->next; | 1176 | pos = &(*pos)->s_sibling; |
614 | } | 1177 | } |
615 | list_add_tail(&cursor->s_sibling, p); | 1178 | |
1179 | cursor->s_sibling = *pos; | ||
1180 | *pos = cursor; | ||
616 | } | 1181 | } |
1182 | |||
1183 | mutex_unlock(&sysfs_mutex); | ||
617 | } | 1184 | } |
618 | mutex_unlock(&dentry->d_inode->i_mutex); | 1185 | |
619 | return offset; | 1186 | return offset; |
620 | } | 1187 | } |
621 | 1188 | ||
@@ -628,12 +1195,20 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin) | |||
628 | int sysfs_make_shadowed_dir(struct kobject *kobj, | 1195 | int sysfs_make_shadowed_dir(struct kobject *kobj, |
629 | void * (*follow_link)(struct dentry *, struct nameidata *)) | 1196 | void * (*follow_link)(struct dentry *, struct nameidata *)) |
630 | { | 1197 | { |
1198 | struct dentry *dentry; | ||
631 | struct inode *inode; | 1199 | struct inode *inode; |
632 | struct inode_operations *i_op; | 1200 | struct inode_operations *i_op; |
633 | 1201 | ||
634 | inode = kobj->dentry->d_inode; | 1202 | /* get dentry for @kobj->sd, dentry of a shadowed dir is pinned */ |
635 | if (inode->i_op != &sysfs_dir_inode_operations) | 1203 | dentry = sysfs_get_dentry(kobj->sd); |
1204 | if (IS_ERR(dentry)) | ||
1205 | return PTR_ERR(dentry); | ||
1206 | |||
1207 | inode = dentry->d_inode; | ||
1208 | if (inode->i_op != &sysfs_dir_inode_operations) { | ||
1209 | dput(dentry); | ||
636 | return -EINVAL; | 1210 | return -EINVAL; |
1211 | } | ||
637 | 1212 | ||
638 | i_op = kmalloc(sizeof(*i_op), GFP_KERNEL); | 1213 | i_op = kmalloc(sizeof(*i_op), GFP_KERNEL); |
639 | if (!i_op) | 1214 | if (!i_op) |
@@ -658,54 +1233,72 @@ int sysfs_make_shadowed_dir(struct kobject *kobj, | |||
658 | * directory. | 1233 | * directory. |
659 | */ | 1234 | */ |
660 | 1235 | ||
661 | struct dentry *sysfs_create_shadow_dir(struct kobject *kobj) | 1236 | struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj) |
662 | { | 1237 | { |
663 | struct sysfs_dirent *sd; | 1238 | struct sysfs_dirent *parent_sd = kobj->sd->s_parent; |
664 | struct dentry *parent, *dir, *shadow; | 1239 | struct dentry *dir, *parent, *shadow; |
665 | struct inode *inode; | 1240 | struct inode *inode; |
1241 | struct sysfs_dirent *sd; | ||
1242 | struct sysfs_addrm_cxt acxt; | ||
666 | 1243 | ||
667 | dir = kobj->dentry; | 1244 | dir = sysfs_get_dentry(kobj->sd); |
668 | inode = dir->d_inode; | 1245 | if (IS_ERR(dir)) { |
1246 | sd = (void *)dir; | ||
1247 | goto out; | ||
1248 | } | ||
669 | parent = dir->d_parent; | 1249 | parent = dir->d_parent; |
670 | shadow = ERR_PTR(-EINVAL); | 1250 | |
1251 | inode = dir->d_inode; | ||
1252 | sd = ERR_PTR(-EINVAL); | ||
671 | if (!sysfs_is_shadowed_inode(inode)) | 1253 | if (!sysfs_is_shadowed_inode(inode)) |
672 | goto out; | 1254 | goto out_dput; |
673 | 1255 | ||
674 | shadow = d_alloc(parent, &dir->d_name); | 1256 | shadow = d_alloc(parent, &dir->d_name); |
675 | if (!shadow) | 1257 | if (!shadow) |
676 | goto nomem; | 1258 | goto nomem; |
677 | 1259 | ||
678 | sd = __sysfs_make_dirent(shadow, kobj, inode->i_mode, SYSFS_DIR); | 1260 | sd = sysfs_new_dirent("_SHADOW_", inode->i_mode, SYSFS_DIR); |
679 | if (!sd) | 1261 | if (!sd) |
680 | goto nomem; | 1262 | goto nomem; |
1263 | sd->s_elem.dir.kobj = kobj; | ||
681 | 1264 | ||
1265 | sysfs_addrm_start(&acxt, parent_sd); | ||
1266 | |||
1267 | /* add but don't link into children list */ | ||
1268 | sysfs_add_one(&acxt, sd); | ||
1269 | |||
1270 | /* attach and instantiate dentry */ | ||
1271 | sysfs_attach_dentry(sd, shadow); | ||
682 | d_instantiate(shadow, igrab(inode)); | 1272 | d_instantiate(shadow, igrab(inode)); |
683 | inc_nlink(inode); | 1273 | inc_nlink(inode); /* tj: synchronization? */ |
684 | inc_nlink(parent->d_inode); | 1274 | |
685 | shadow->d_op = &sysfs_dentry_ops; | 1275 | sysfs_addrm_finish(&acxt); |
686 | 1276 | ||
687 | dget(shadow); /* Extra count - pin the dentry in core */ | 1277 | dget(shadow); /* Extra count - pin the dentry in core */ |
688 | 1278 | ||
689 | out: | 1279 | goto out_dput; |
690 | return shadow; | 1280 | |
691 | nomem: | 1281 | nomem: |
692 | dput(shadow); | 1282 | dput(shadow); |
693 | shadow = ERR_PTR(-ENOMEM); | 1283 | sd = ERR_PTR(-ENOMEM); |
694 | goto out; | 1284 | out_dput: |
1285 | dput(dir); | ||
1286 | out: | ||
1287 | return sd; | ||
695 | } | 1288 | } |
696 | 1289 | ||
697 | /** | 1290 | /** |
698 | * sysfs_remove_shadow_dir - remove an object's directory. | 1291 | * sysfs_remove_shadow_dir - remove an object's directory. |
699 | * @shadow: dentry of shadow directory | 1292 | * @shadow_sd: sysfs_dirent of shadow directory |
700 | * | 1293 | * |
701 | * The only thing special about this is that we remove any files in | 1294 | * The only thing special about this is that we remove any files in |
702 | * the directory before we remove the directory, and we've inlined | 1295 | * the directory before we remove the directory, and we've inlined |
703 | * what used to be sysfs_rmdir() below, instead of calling separately. | 1296 | * what used to be sysfs_rmdir() below, instead of calling separately. |
704 | */ | 1297 | */ |
705 | 1298 | ||
706 | void sysfs_remove_shadow_dir(struct dentry *shadow) | 1299 | void sysfs_remove_shadow_dir(struct sysfs_dirent *shadow_sd) |
707 | { | 1300 | { |
708 | __sysfs_remove_dir(shadow); | 1301 | __sysfs_remove_dir(shadow_sd); |
709 | } | 1302 | } |
710 | 1303 | ||
711 | const struct file_operations sysfs_dir_operations = { | 1304 | const struct file_operations sysfs_dir_operations = { |
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index b502c7197ec0..cc497994b2a8 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
@@ -50,29 +50,15 @@ static struct sysfs_ops subsys_sysfs_ops = { | |||
50 | .store = subsys_attr_store, | 50 | .store = subsys_attr_store, |
51 | }; | 51 | }; |
52 | 52 | ||
53 | /** | 53 | struct sysfs_buffer { |
54 | * add_to_collection - add buffer to a collection | 54 | size_t count; |
55 | * @buffer: buffer to be added | 55 | loff_t pos; |
56 | * @node: inode of set to add to | 56 | char * page; |
57 | */ | 57 | struct sysfs_ops * ops; |
58 | 58 | struct semaphore sem; | |
59 | static inline void | 59 | int needs_read_fill; |
60 | add_to_collection(struct sysfs_buffer *buffer, struct inode *node) | 60 | int event; |
61 | { | 61 | }; |
62 | struct sysfs_buffer_collection *set = node->i_private; | ||
63 | |||
64 | mutex_lock(&node->i_mutex); | ||
65 | list_add(&buffer->associates, &set->associates); | ||
66 | mutex_unlock(&node->i_mutex); | ||
67 | } | ||
68 | |||
69 | static inline void | ||
70 | remove_from_collection(struct sysfs_buffer *buffer, struct inode *node) | ||
71 | { | ||
72 | mutex_lock(&node->i_mutex); | ||
73 | list_del(&buffer->associates); | ||
74 | mutex_unlock(&node->i_mutex); | ||
75 | } | ||
76 | 62 | ||
77 | /** | 63 | /** |
78 | * fill_read_buffer - allocate and fill buffer from object. | 64 | * fill_read_buffer - allocate and fill buffer from object. |
@@ -87,9 +73,8 @@ remove_from_collection(struct sysfs_buffer *buffer, struct inode *node) | |||
87 | */ | 73 | */ |
88 | static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer) | 74 | static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer) |
89 | { | 75 | { |
90 | struct sysfs_dirent * sd = dentry->d_fsdata; | 76 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; |
91 | struct attribute * attr = to_attr(dentry); | 77 | struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; |
92 | struct kobject * kobj = to_kobj(dentry->d_parent); | ||
93 | struct sysfs_ops * ops = buffer->ops; | 78 | struct sysfs_ops * ops = buffer->ops; |
94 | int ret = 0; | 79 | int ret = 0; |
95 | ssize_t count; | 80 | ssize_t count; |
@@ -99,8 +84,15 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer | |||
99 | if (!buffer->page) | 84 | if (!buffer->page) |
100 | return -ENOMEM; | 85 | return -ENOMEM; |
101 | 86 | ||
102 | buffer->event = atomic_read(&sd->s_event); | 87 | /* need attr_sd for attr and ops, its parent for kobj */ |
103 | count = ops->show(kobj,attr,buffer->page); | 88 | if (!sysfs_get_active_two(attr_sd)) |
89 | return -ENODEV; | ||
90 | |||
91 | buffer->event = atomic_read(&attr_sd->s_event); | ||
92 | count = ops->show(kobj, attr_sd->s_elem.attr.attr, buffer->page); | ||
93 | |||
94 | sysfs_put_active_two(attr_sd); | ||
95 | |||
104 | BUG_ON(count > (ssize_t)PAGE_SIZE); | 96 | BUG_ON(count > (ssize_t)PAGE_SIZE); |
105 | if (count >= 0) { | 97 | if (count >= 0) { |
106 | buffer->needs_read_fill = 0; | 98 | buffer->needs_read_fill = 0; |
@@ -138,10 +130,7 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos) | |||
138 | 130 | ||
139 | down(&buffer->sem); | 131 | down(&buffer->sem); |
140 | if (buffer->needs_read_fill) { | 132 | if (buffer->needs_read_fill) { |
141 | if (buffer->orphaned) | 133 | retval = fill_read_buffer(file->f_path.dentry,buffer); |
142 | retval = -ENODEV; | ||
143 | else | ||
144 | retval = fill_read_buffer(file->f_path.dentry,buffer); | ||
145 | if (retval) | 134 | if (retval) |
146 | goto out; | 135 | goto out; |
147 | } | 136 | } |
@@ -196,14 +185,23 @@ fill_write_buffer(struct sysfs_buffer * buffer, const char __user * buf, size_t | |||
196 | * passing the buffer that we acquired in fill_write_buffer(). | 185 | * passing the buffer that we acquired in fill_write_buffer(). |
197 | */ | 186 | */ |
198 | 187 | ||
199 | static int | 188 | static int |
200 | flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t count) | 189 | flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t count) |
201 | { | 190 | { |
202 | struct attribute * attr = to_attr(dentry); | 191 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; |
203 | struct kobject * kobj = to_kobj(dentry->d_parent); | 192 | struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; |
204 | struct sysfs_ops * ops = buffer->ops; | 193 | struct sysfs_ops * ops = buffer->ops; |
194 | int rc; | ||
195 | |||
196 | /* need attr_sd for attr and ops, its parent for kobj */ | ||
197 | if (!sysfs_get_active_two(attr_sd)) | ||
198 | return -ENODEV; | ||
199 | |||
200 | rc = ops->store(kobj, attr_sd->s_elem.attr.attr, buffer->page, count); | ||
205 | 201 | ||
206 | return ops->store(kobj,attr,buffer->page,count); | 202 | sysfs_put_active_two(attr_sd); |
203 | |||
204 | return rc; | ||
207 | } | 205 | } |
208 | 206 | ||
209 | 207 | ||
@@ -231,37 +229,26 @@ sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t | |||
231 | ssize_t len; | 229 | ssize_t len; |
232 | 230 | ||
233 | down(&buffer->sem); | 231 | down(&buffer->sem); |
234 | if (buffer->orphaned) { | ||
235 | len = -ENODEV; | ||
236 | goto out; | ||
237 | } | ||
238 | len = fill_write_buffer(buffer, buf, count); | 232 | len = fill_write_buffer(buffer, buf, count); |
239 | if (len > 0) | 233 | if (len > 0) |
240 | len = flush_write_buffer(file->f_path.dentry, buffer, len); | 234 | len = flush_write_buffer(file->f_path.dentry, buffer, len); |
241 | if (len > 0) | 235 | if (len > 0) |
242 | *ppos += len; | 236 | *ppos += len; |
243 | out: | ||
244 | up(&buffer->sem); | 237 | up(&buffer->sem); |
245 | return len; | 238 | return len; |
246 | } | 239 | } |
247 | 240 | ||
248 | static int sysfs_open_file(struct inode *inode, struct file *file) | 241 | static int sysfs_open_file(struct inode *inode, struct file *file) |
249 | { | 242 | { |
250 | struct kobject *kobj = sysfs_get_kobject(file->f_path.dentry->d_parent); | 243 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; |
251 | struct attribute * attr = to_attr(file->f_path.dentry); | 244 | struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; |
252 | struct sysfs_buffer_collection *set; | ||
253 | struct sysfs_buffer * buffer; | 245 | struct sysfs_buffer * buffer; |
254 | struct sysfs_ops * ops = NULL; | 246 | struct sysfs_ops * ops = NULL; |
255 | int error = 0; | 247 | int error; |
256 | |||
257 | if (!kobj || !attr) | ||
258 | goto Einval; | ||
259 | 248 | ||
260 | /* Grab the module reference for this attribute if we have one */ | 249 | /* need attr_sd for attr and ops, its parent for kobj */ |
261 | if (!try_module_get(attr->owner)) { | 250 | if (!sysfs_get_active_two(attr_sd)) |
262 | error = -ENODEV; | 251 | return -ENODEV; |
263 | goto Done; | ||
264 | } | ||
265 | 252 | ||
266 | /* if the kobject has no ktype, then we assume that it is a subsystem | 253 | /* if the kobject has no ktype, then we assume that it is a subsystem |
267 | * itself, and use ops for it. | 254 | * itself, and use ops for it. |
@@ -273,33 +260,21 @@ static int sysfs_open_file(struct inode *inode, struct file *file) | |||
273 | else | 260 | else |
274 | ops = &subsys_sysfs_ops; | 261 | ops = &subsys_sysfs_ops; |
275 | 262 | ||
263 | error = -EACCES; | ||
264 | |||
276 | /* No sysfs operations, either from having no subsystem, | 265 | /* No sysfs operations, either from having no subsystem, |
277 | * or the subsystem have no operations. | 266 | * or the subsystem have no operations. |
278 | */ | 267 | */ |
279 | if (!ops) | 268 | if (!ops) |
280 | goto Eaccess; | 269 | goto err_out; |
281 | |||
282 | /* make sure we have a collection to add our buffers to */ | ||
283 | mutex_lock(&inode->i_mutex); | ||
284 | if (!(set = inode->i_private)) { | ||
285 | if (!(set = inode->i_private = kmalloc(sizeof(struct sysfs_buffer_collection), GFP_KERNEL))) { | ||
286 | error = -ENOMEM; | ||
287 | goto Done; | ||
288 | } else { | ||
289 | INIT_LIST_HEAD(&set->associates); | ||
290 | } | ||
291 | } | ||
292 | mutex_unlock(&inode->i_mutex); | ||
293 | 270 | ||
294 | /* File needs write support. | 271 | /* File needs write support. |
295 | * The inode's perms must say it's ok, | 272 | * The inode's perms must say it's ok, |
296 | * and we must have a store method. | 273 | * and we must have a store method. |
297 | */ | 274 | */ |
298 | if (file->f_mode & FMODE_WRITE) { | 275 | if (file->f_mode & FMODE_WRITE) { |
299 | |||
300 | if (!(inode->i_mode & S_IWUGO) || !ops->store) | 276 | if (!(inode->i_mode & S_IWUGO) || !ops->store) |
301 | goto Eaccess; | 277 | goto err_out; |
302 | |||
303 | } | 278 | } |
304 | 279 | ||
305 | /* File needs read support. | 280 | /* File needs read support. |
@@ -308,48 +283,38 @@ static int sysfs_open_file(struct inode *inode, struct file *file) | |||
308 | */ | 283 | */ |
309 | if (file->f_mode & FMODE_READ) { | 284 | if (file->f_mode & FMODE_READ) { |
310 | if (!(inode->i_mode & S_IRUGO) || !ops->show) | 285 | if (!(inode->i_mode & S_IRUGO) || !ops->show) |
311 | goto Eaccess; | 286 | goto err_out; |
312 | } | 287 | } |
313 | 288 | ||
314 | /* No error? Great, allocate a buffer for the file, and store it | 289 | /* No error? Great, allocate a buffer for the file, and store it |
315 | * it in file->private_data for easy access. | 290 | * it in file->private_data for easy access. |
316 | */ | 291 | */ |
292 | error = -ENOMEM; | ||
317 | buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL); | 293 | buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL); |
318 | if (buffer) { | 294 | if (!buffer) |
319 | INIT_LIST_HEAD(&buffer->associates); | 295 | goto err_out; |
320 | init_MUTEX(&buffer->sem); | 296 | |
321 | buffer->needs_read_fill = 1; | 297 | init_MUTEX(&buffer->sem); |
322 | buffer->ops = ops; | 298 | buffer->needs_read_fill = 1; |
323 | add_to_collection(buffer, inode); | 299 | buffer->ops = ops; |
324 | file->private_data = buffer; | 300 | file->private_data = buffer; |
325 | } else | 301 | |
326 | error = -ENOMEM; | 302 | /* open succeeded, put active references and pin attr_sd */ |
327 | goto Done; | 303 | sysfs_put_active_two(attr_sd); |
328 | 304 | sysfs_get(attr_sd); | |
329 | Einval: | 305 | return 0; |
330 | error = -EINVAL; | 306 | |
331 | goto Done; | 307 | err_out: |
332 | Eaccess: | 308 | sysfs_put_active_two(attr_sd); |
333 | error = -EACCES; | ||
334 | module_put(attr->owner); | ||
335 | Done: | ||
336 | if (error) | ||
337 | kobject_put(kobj); | ||
338 | return error; | 309 | return error; |
339 | } | 310 | } |
340 | 311 | ||
341 | static int sysfs_release(struct inode * inode, struct file * filp) | 312 | static int sysfs_release(struct inode * inode, struct file * filp) |
342 | { | 313 | { |
343 | struct kobject * kobj = to_kobj(filp->f_path.dentry->d_parent); | 314 | struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; |
344 | struct attribute * attr = to_attr(filp->f_path.dentry); | 315 | struct sysfs_buffer *buffer = filp->private_data; |
345 | struct module * owner = attr->owner; | ||
346 | struct sysfs_buffer * buffer = filp->private_data; | ||
347 | 316 | ||
348 | if (buffer) | 317 | sysfs_put(attr_sd); |
349 | remove_from_collection(buffer, inode); | ||
350 | kobject_put(kobj); | ||
351 | /* After this point, attr should not be accessed. */ | ||
352 | module_put(owner); | ||
353 | 318 | ||
354 | if (buffer) { | 319 | if (buffer) { |
355 | if (buffer->page) | 320 | if (buffer->page) |
@@ -376,57 +341,43 @@ static int sysfs_release(struct inode * inode, struct file * filp) | |||
376 | static unsigned int sysfs_poll(struct file *filp, poll_table *wait) | 341 | static unsigned int sysfs_poll(struct file *filp, poll_table *wait) |
377 | { | 342 | { |
378 | struct sysfs_buffer * buffer = filp->private_data; | 343 | struct sysfs_buffer * buffer = filp->private_data; |
379 | struct kobject * kobj = to_kobj(filp->f_path.dentry->d_parent); | 344 | struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; |
380 | struct sysfs_dirent * sd = filp->f_path.dentry->d_fsdata; | 345 | struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; |
381 | int res = 0; | 346 | |
347 | /* need parent for the kobj, grab both */ | ||
348 | if (!sysfs_get_active_two(attr_sd)) | ||
349 | goto trigger; | ||
382 | 350 | ||
383 | poll_wait(filp, &kobj->poll, wait); | 351 | poll_wait(filp, &kobj->poll, wait); |
384 | 352 | ||
385 | if (buffer->event != atomic_read(&sd->s_event)) { | 353 | sysfs_put_active_two(attr_sd); |
386 | res = POLLERR|POLLPRI; | ||
387 | buffer->needs_read_fill = 1; | ||
388 | } | ||
389 | 354 | ||
390 | return res; | 355 | if (buffer->event != atomic_read(&attr_sd->s_event)) |
391 | } | 356 | goto trigger; |
392 | 357 | ||
358 | return 0; | ||
393 | 359 | ||
394 | static struct dentry *step_down(struct dentry *dir, const char * name) | 360 | trigger: |
395 | { | 361 | buffer->needs_read_fill = 1; |
396 | struct dentry * de; | 362 | return POLLERR|POLLPRI; |
397 | |||
398 | if (dir == NULL || dir->d_inode == NULL) | ||
399 | return NULL; | ||
400 | |||
401 | mutex_lock(&dir->d_inode->i_mutex); | ||
402 | de = lookup_one_len(name, dir, strlen(name)); | ||
403 | mutex_unlock(&dir->d_inode->i_mutex); | ||
404 | dput(dir); | ||
405 | if (IS_ERR(de)) | ||
406 | return NULL; | ||
407 | if (de->d_inode == NULL) { | ||
408 | dput(de); | ||
409 | return NULL; | ||
410 | } | ||
411 | return de; | ||
412 | } | 363 | } |
413 | 364 | ||
414 | void sysfs_notify(struct kobject * k, char *dir, char *attr) | 365 | void sysfs_notify(struct kobject *k, char *dir, char *attr) |
415 | { | 366 | { |
416 | struct dentry *de = k->dentry; | 367 | struct sysfs_dirent *sd = k->sd; |
417 | if (de) | 368 | |
418 | dget(de); | 369 | mutex_lock(&sysfs_mutex); |
419 | if (de && dir) | 370 | |
420 | de = step_down(de, dir); | 371 | if (sd && dir) |
421 | if (de && attr) | 372 | sd = sysfs_find_dirent(sd, dir); |
422 | de = step_down(de, attr); | 373 | if (sd && attr) |
423 | if (de) { | 374 | sd = sysfs_find_dirent(sd, attr); |
424 | struct sysfs_dirent * sd = de->d_fsdata; | 375 | if (sd) { |
425 | if (sd) | 376 | atomic_inc(&sd->s_event); |
426 | atomic_inc(&sd->s_event); | ||
427 | wake_up_interruptible(&k->poll); | 377 | wake_up_interruptible(&k->poll); |
428 | dput(de); | ||
429 | } | 378 | } |
379 | |||
380 | mutex_unlock(&sysfs_mutex); | ||
430 | } | 381 | } |
431 | EXPORT_SYMBOL_GPL(sysfs_notify); | 382 | EXPORT_SYMBOL_GPL(sysfs_notify); |
432 | 383 | ||
@@ -440,19 +391,30 @@ const struct file_operations sysfs_file_operations = { | |||
440 | }; | 391 | }; |
441 | 392 | ||
442 | 393 | ||
443 | int sysfs_add_file(struct dentry * dir, const struct attribute * attr, int type) | 394 | int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, |
395 | int type) | ||
444 | { | 396 | { |
445 | struct sysfs_dirent * parent_sd = dir->d_fsdata; | ||
446 | umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG; | 397 | umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG; |
447 | int error = -EEXIST; | 398 | struct sysfs_addrm_cxt acxt; |
399 | struct sysfs_dirent *sd; | ||
448 | 400 | ||
449 | mutex_lock(&dir->d_inode->i_mutex); | 401 | sd = sysfs_new_dirent(attr->name, mode, type); |
450 | if (!sysfs_dirent_exist(parent_sd, attr->name)) | 402 | if (!sd) |
451 | error = sysfs_make_dirent(parent_sd, NULL, (void *)attr, | 403 | return -ENOMEM; |
452 | mode, type); | 404 | sd->s_elem.attr.attr = (void *)attr; |
453 | mutex_unlock(&dir->d_inode->i_mutex); | ||
454 | 405 | ||
455 | return error; | 406 | sysfs_addrm_start(&acxt, dir_sd); |
407 | |||
408 | if (!sysfs_find_dirent(dir_sd, attr->name)) { | ||
409 | sysfs_add_one(&acxt, sd); | ||
410 | sysfs_link_sibling(sd); | ||
411 | } | ||
412 | |||
413 | if (sysfs_addrm_finish(&acxt)) | ||
414 | return 0; | ||
415 | |||
416 | sysfs_put(sd); | ||
417 | return -EEXIST; | ||
456 | } | 418 | } |
457 | 419 | ||
458 | 420 | ||
@@ -464,9 +426,9 @@ int sysfs_add_file(struct dentry * dir, const struct attribute * attr, int type) | |||
464 | 426 | ||
465 | int sysfs_create_file(struct kobject * kobj, const struct attribute * attr) | 427 | int sysfs_create_file(struct kobject * kobj, const struct attribute * attr) |
466 | { | 428 | { |
467 | BUG_ON(!kobj || !kobj->dentry || !attr); | 429 | BUG_ON(!kobj || !kobj->sd || !attr); |
468 | 430 | ||
469 | return sysfs_add_file(kobj->dentry, attr, SYSFS_KOBJ_ATTR); | 431 | return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR); |
470 | 432 | ||
471 | } | 433 | } |
472 | 434 | ||
@@ -480,16 +442,16 @@ int sysfs_create_file(struct kobject * kobj, const struct attribute * attr) | |||
480 | int sysfs_add_file_to_group(struct kobject *kobj, | 442 | int sysfs_add_file_to_group(struct kobject *kobj, |
481 | const struct attribute *attr, const char *group) | 443 | const struct attribute *attr, const char *group) |
482 | { | 444 | { |
483 | struct dentry *dir; | 445 | struct sysfs_dirent *dir_sd; |
484 | int error; | 446 | int error; |
485 | 447 | ||
486 | dir = lookup_one_len(group, kobj->dentry, strlen(group)); | 448 | dir_sd = sysfs_get_dirent(kobj->sd, group); |
487 | if (IS_ERR(dir)) | 449 | if (!dir_sd) |
488 | error = PTR_ERR(dir); | 450 | return -ENOENT; |
489 | else { | 451 | |
490 | error = sysfs_add_file(dir, attr, SYSFS_KOBJ_ATTR); | 452 | error = sysfs_add_file(dir_sd, attr, SYSFS_KOBJ_ATTR); |
491 | dput(dir); | 453 | sysfs_put(dir_sd); |
492 | } | 454 | |
493 | return error; | 455 | return error; |
494 | } | 456 | } |
495 | EXPORT_SYMBOL_GPL(sysfs_add_file_to_group); | 457 | EXPORT_SYMBOL_GPL(sysfs_add_file_to_group); |
@@ -502,30 +464,31 @@ EXPORT_SYMBOL_GPL(sysfs_add_file_to_group); | |||
502 | */ | 464 | */ |
503 | int sysfs_update_file(struct kobject * kobj, const struct attribute * attr) | 465 | int sysfs_update_file(struct kobject * kobj, const struct attribute * attr) |
504 | { | 466 | { |
505 | struct dentry * dir = kobj->dentry; | 467 | struct sysfs_dirent *victim_sd = NULL; |
506 | struct dentry * victim; | 468 | struct dentry *victim = NULL; |
507 | int res = -ENOENT; | 469 | int rc; |
508 | 470 | ||
509 | mutex_lock(&dir->d_inode->i_mutex); | 471 | rc = -ENOENT; |
510 | victim = lookup_one_len(attr->name, dir, strlen(attr->name)); | 472 | victim_sd = sysfs_get_dirent(kobj->sd, attr->name); |
511 | if (!IS_ERR(victim)) { | 473 | if (!victim_sd) |
512 | /* make sure dentry is really there */ | 474 | goto out; |
513 | if (victim->d_inode && | 475 | |
514 | (victim->d_parent->d_inode == dir->d_inode)) { | 476 | victim = sysfs_get_dentry(victim_sd); |
515 | victim->d_inode->i_mtime = CURRENT_TIME; | 477 | if (IS_ERR(victim)) { |
516 | fsnotify_modify(victim); | 478 | rc = PTR_ERR(victim); |
517 | res = 0; | 479 | victim = NULL; |
518 | } else | 480 | goto out; |
519 | d_drop(victim); | ||
520 | |||
521 | /** | ||
522 | * Drop the reference acquired from lookup_one_len() above. | ||
523 | */ | ||
524 | dput(victim); | ||
525 | } | 481 | } |
526 | mutex_unlock(&dir->d_inode->i_mutex); | ||
527 | 482 | ||
528 | return res; | 483 | mutex_lock(&victim->d_inode->i_mutex); |
484 | victim->d_inode->i_mtime = CURRENT_TIME; | ||
485 | fsnotify_modify(victim); | ||
486 | mutex_unlock(&victim->d_inode->i_mutex); | ||
487 | rc = 0; | ||
488 | out: | ||
489 | dput(victim); | ||
490 | sysfs_put(victim_sd); | ||
491 | return rc; | ||
529 | } | 492 | } |
530 | 493 | ||
531 | 494 | ||
@@ -538,30 +501,34 @@ int sysfs_update_file(struct kobject * kobj, const struct attribute * attr) | |||
538 | */ | 501 | */ |
539 | int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) | 502 | int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) |
540 | { | 503 | { |
541 | struct dentry *dir = kobj->dentry; | 504 | struct sysfs_dirent *victim_sd = NULL; |
542 | struct dentry *victim; | 505 | struct dentry *victim = NULL; |
543 | struct inode * inode; | 506 | struct inode * inode; |
544 | struct iattr newattrs; | 507 | struct iattr newattrs; |
545 | int res = -ENOENT; | 508 | int rc; |
546 | 509 | ||
547 | mutex_lock(&dir->d_inode->i_mutex); | 510 | rc = -ENOENT; |
548 | victim = lookup_one_len(attr->name, dir, strlen(attr->name)); | 511 | victim_sd = sysfs_get_dirent(kobj->sd, attr->name); |
549 | if (!IS_ERR(victim)) { | 512 | if (!victim_sd) |
550 | if (victim->d_inode && | 513 | goto out; |
551 | (victim->d_parent->d_inode == dir->d_inode)) { | 514 | |
552 | inode = victim->d_inode; | 515 | victim = sysfs_get_dentry(victim_sd); |
553 | mutex_lock(&inode->i_mutex); | 516 | if (IS_ERR(victim)) { |
554 | newattrs.ia_mode = (mode & S_IALLUGO) | | 517 | rc = PTR_ERR(victim); |
555 | (inode->i_mode & ~S_IALLUGO); | 518 | victim = NULL; |
556 | newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; | 519 | goto out; |
557 | res = notify_change(victim, &newattrs); | ||
558 | mutex_unlock(&inode->i_mutex); | ||
559 | } | ||
560 | dput(victim); | ||
561 | } | 520 | } |
562 | mutex_unlock(&dir->d_inode->i_mutex); | ||
563 | 521 | ||
564 | return res; | 522 | inode = victim->d_inode; |
523 | mutex_lock(&inode->i_mutex); | ||
524 | newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); | ||
525 | newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; | ||
526 | rc = notify_change(victim, &newattrs); | ||
527 | mutex_unlock(&inode->i_mutex); | ||
528 | out: | ||
529 | dput(victim); | ||
530 | sysfs_put(victim_sd); | ||
531 | return rc; | ||
565 | } | 532 | } |
566 | EXPORT_SYMBOL_GPL(sysfs_chmod_file); | 533 | EXPORT_SYMBOL_GPL(sysfs_chmod_file); |
567 | 534 | ||
@@ -576,7 +543,7 @@ EXPORT_SYMBOL_GPL(sysfs_chmod_file); | |||
576 | 543 | ||
577 | void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr) | 544 | void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr) |
578 | { | 545 | { |
579 | sysfs_hash_and_remove(kobj->dentry, attr->name); | 546 | sysfs_hash_and_remove(kobj->sd, attr->name); |
580 | } | 547 | } |
581 | 548 | ||
582 | 549 | ||
@@ -589,12 +556,12 @@ void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr) | |||
589 | void sysfs_remove_file_from_group(struct kobject *kobj, | 556 | void sysfs_remove_file_from_group(struct kobject *kobj, |
590 | const struct attribute *attr, const char *group) | 557 | const struct attribute *attr, const char *group) |
591 | { | 558 | { |
592 | struct dentry *dir; | 559 | struct sysfs_dirent *dir_sd; |
593 | 560 | ||
594 | dir = lookup_one_len(group, kobj->dentry, strlen(group)); | 561 | dir_sd = sysfs_get_dirent(kobj->sd, group); |
595 | if (!IS_ERR(dir)) { | 562 | if (dir_sd) { |
596 | sysfs_hash_and_remove(dir, attr->name); | 563 | sysfs_hash_and_remove(dir_sd, attr->name); |
597 | dput(dir); | 564 | sysfs_put(dir_sd); |
598 | } | 565 | } |
599 | } | 566 | } |
600 | EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group); | 567 | EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group); |
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index 52eed2a7a5ef..f318b73c790c 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c | |||
@@ -18,26 +18,25 @@ | |||
18 | #include "sysfs.h" | 18 | #include "sysfs.h" |
19 | 19 | ||
20 | 20 | ||
21 | static void remove_files(struct dentry * dir, | 21 | static void remove_files(struct sysfs_dirent *dir_sd, |
22 | const struct attribute_group * grp) | 22 | const struct attribute_group *grp) |
23 | { | 23 | { |
24 | struct attribute *const* attr; | 24 | struct attribute *const* attr; |
25 | 25 | ||
26 | for (attr = grp->attrs; *attr; attr++) | 26 | for (attr = grp->attrs; *attr; attr++) |
27 | sysfs_hash_and_remove(dir,(*attr)->name); | 27 | sysfs_hash_and_remove(dir_sd, (*attr)->name); |
28 | } | 28 | } |
29 | 29 | ||
30 | static int create_files(struct dentry * dir, | 30 | static int create_files(struct sysfs_dirent *dir_sd, |
31 | const struct attribute_group * grp) | 31 | const struct attribute_group *grp) |
32 | { | 32 | { |
33 | struct attribute *const* attr; | 33 | struct attribute *const* attr; |
34 | int error = 0; | 34 | int error = 0; |
35 | 35 | ||
36 | for (attr = grp->attrs; *attr && !error; attr++) { | 36 | for (attr = grp->attrs; *attr && !error; attr++) |
37 | error = sysfs_add_file(dir, *attr, SYSFS_KOBJ_ATTR); | 37 | error = sysfs_add_file(dir_sd, *attr, SYSFS_KOBJ_ATTR); |
38 | } | ||
39 | if (error) | 38 | if (error) |
40 | remove_files(dir,grp); | 39 | remove_files(dir_sd, grp); |
41 | return error; | 40 | return error; |
42 | } | 41 | } |
43 | 42 | ||
@@ -45,44 +44,44 @@ static int create_files(struct dentry * dir, | |||
45 | int sysfs_create_group(struct kobject * kobj, | 44 | int sysfs_create_group(struct kobject * kobj, |
46 | const struct attribute_group * grp) | 45 | const struct attribute_group * grp) |
47 | { | 46 | { |
48 | struct dentry * dir; | 47 | struct sysfs_dirent *sd; |
49 | int error; | 48 | int error; |
50 | 49 | ||
51 | BUG_ON(!kobj || !kobj->dentry); | 50 | BUG_ON(!kobj || !kobj->sd); |
52 | 51 | ||
53 | if (grp->name) { | 52 | if (grp->name) { |
54 | error = sysfs_create_subdir(kobj,grp->name,&dir); | 53 | error = sysfs_create_subdir(kobj, grp->name, &sd); |
55 | if (error) | 54 | if (error) |
56 | return error; | 55 | return error; |
57 | } else | 56 | } else |
58 | dir = kobj->dentry; | 57 | sd = kobj->sd; |
59 | dir = dget(dir); | 58 | sysfs_get(sd); |
60 | if ((error = create_files(dir,grp))) { | 59 | error = create_files(sd, grp); |
60 | if (error) { | ||
61 | if (grp->name) | 61 | if (grp->name) |
62 | sysfs_remove_subdir(dir); | 62 | sysfs_remove_subdir(sd); |
63 | } | 63 | } |
64 | dput(dir); | 64 | sysfs_put(sd); |
65 | return error; | 65 | return error; |
66 | } | 66 | } |
67 | 67 | ||
68 | void sysfs_remove_group(struct kobject * kobj, | 68 | void sysfs_remove_group(struct kobject * kobj, |
69 | const struct attribute_group * grp) | 69 | const struct attribute_group * grp) |
70 | { | 70 | { |
71 | struct dentry * dir; | 71 | struct sysfs_dirent *dir_sd = kobj->sd; |
72 | struct sysfs_dirent *sd; | ||
72 | 73 | ||
73 | if (grp->name) { | 74 | if (grp->name) { |
74 | dir = lookup_one_len_kern(grp->name, kobj->dentry, | 75 | sd = sysfs_get_dirent(dir_sd, grp->name); |
75 | strlen(grp->name)); | 76 | BUG_ON(!sd); |
76 | BUG_ON(IS_ERR(dir)); | 77 | } else |
77 | } | 78 | sd = sysfs_get(dir_sd); |
78 | else | ||
79 | dir = dget(kobj->dentry); | ||
80 | 79 | ||
81 | remove_files(dir,grp); | 80 | remove_files(sd, grp); |
82 | if (grp->name) | 81 | if (grp->name) |
83 | sysfs_remove_subdir(dir); | 82 | sysfs_remove_subdir(sd); |
84 | /* release the ref. taken in this routine */ | 83 | |
85 | dput(dir); | 84 | sysfs_put(sd); |
86 | } | 85 | } |
87 | 86 | ||
88 | 87 | ||
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 5266eec15f6e..3756e152285a 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c | |||
@@ -133,187 +133,94 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) | |||
133 | */ | 133 | */ |
134 | static struct lock_class_key sysfs_inode_imutex_key; | 134 | static struct lock_class_key sysfs_inode_imutex_key; |
135 | 135 | ||
136 | struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent * sd) | 136 | void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) |
137 | { | 137 | { |
138 | struct inode * inode = new_inode(sysfs_sb); | 138 | inode->i_blocks = 0; |
139 | if (inode) { | 139 | inode->i_mapping->a_ops = &sysfs_aops; |
140 | inode->i_blocks = 0; | 140 | inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; |
141 | inode->i_mapping->a_ops = &sysfs_aops; | 141 | inode->i_op = &sysfs_inode_operations; |
142 | inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; | 142 | inode->i_ino = sd->s_ino; |
143 | inode->i_op = &sysfs_inode_operations; | 143 | lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key); |
144 | inode->i_ino = sd->s_ino; | 144 | |
145 | lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key); | 145 | if (sd->s_iattr) { |
146 | 146 | /* sysfs_dirent has non-default attributes | |
147 | if (sd->s_iattr) { | 147 | * get them for the new inode from persistent copy |
148 | /* sysfs_dirent has non-default attributes | 148 | * in sysfs_dirent |
149 | * get them for the new inode from persistent copy | 149 | */ |
150 | * in sysfs_dirent | 150 | set_inode_attr(inode, sd->s_iattr); |
151 | */ | ||
152 | set_inode_attr(inode, sd->s_iattr); | ||
153 | } else | ||
154 | set_default_inode_attr(inode, mode); | ||
155 | } | ||
156 | return inode; | ||
157 | } | ||
158 | |||
159 | int sysfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *)) | ||
160 | { | ||
161 | int error = 0; | ||
162 | struct inode * inode = NULL; | ||
163 | if (dentry) { | ||
164 | if (!dentry->d_inode) { | ||
165 | struct sysfs_dirent * sd = dentry->d_fsdata; | ||
166 | if ((inode = sysfs_new_inode(mode, sd))) { | ||
167 | if (dentry->d_parent && dentry->d_parent->d_inode) { | ||
168 | struct inode *p_inode = dentry->d_parent->d_inode; | ||
169 | p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME; | ||
170 | } | ||
171 | goto Proceed; | ||
172 | } | ||
173 | else | ||
174 | error = -ENOMEM; | ||
175 | } else | ||
176 | error = -EEXIST; | ||
177 | } else | ||
178 | error = -ENOENT; | ||
179 | goto Done; | ||
180 | |||
181 | Proceed: | ||
182 | if (init) | ||
183 | error = init(inode); | ||
184 | if (!error) { | ||
185 | d_instantiate(dentry, inode); | ||
186 | if (S_ISDIR(mode)) | ||
187 | dget(dentry); /* pin only directory dentry in core */ | ||
188 | } else | 151 | } else |
189 | iput(inode); | 152 | set_default_inode_attr(inode, sd->s_mode); |
190 | Done: | ||
191 | return error; | ||
192 | } | 153 | } |
193 | 154 | ||
194 | /* | 155 | /** |
195 | * Get the name for corresponding element represented by the given sysfs_dirent | 156 | * sysfs_get_inode - get inode for sysfs_dirent |
157 | * @sd: sysfs_dirent to allocate inode for | ||
158 | * | ||
159 | * Get inode for @sd. If such inode doesn't exist, a new inode | ||
160 | * is allocated and basics are initialized. New inode is | ||
161 | * returned locked. | ||
162 | * | ||
163 | * LOCKING: | ||
164 | * Kernel thread context (may sleep). | ||
165 | * | ||
166 | * RETURNS: | ||
167 | * Pointer to allocated inode on success, NULL on failure. | ||
196 | */ | 168 | */ |
197 | const unsigned char * sysfs_get_name(struct sysfs_dirent *sd) | 169 | struct inode * sysfs_get_inode(struct sysfs_dirent *sd) |
198 | { | 170 | { |
199 | struct attribute * attr; | 171 | struct inode *inode; |
200 | struct bin_attribute * bin_attr; | ||
201 | struct sysfs_symlink * sl; | ||
202 | |||
203 | BUG_ON(!sd || !sd->s_element); | ||
204 | |||
205 | switch (sd->s_type) { | ||
206 | case SYSFS_DIR: | ||
207 | /* Always have a dentry so use that */ | ||
208 | return sd->s_dentry->d_name.name; | ||
209 | |||
210 | case SYSFS_KOBJ_ATTR: | ||
211 | attr = sd->s_element; | ||
212 | return attr->name; | ||
213 | |||
214 | case SYSFS_KOBJ_BIN_ATTR: | ||
215 | bin_attr = sd->s_element; | ||
216 | return bin_attr->attr.name; | ||
217 | 172 | ||
218 | case SYSFS_KOBJ_LINK: | 173 | inode = iget_locked(sysfs_sb, sd->s_ino); |
219 | sl = sd->s_element; | 174 | if (inode && (inode->i_state & I_NEW)) |
220 | return sl->link_name; | 175 | sysfs_init_inode(sd, inode); |
221 | } | ||
222 | return NULL; | ||
223 | } | ||
224 | 176 | ||
225 | static inline void orphan_all_buffers(struct inode *node) | 177 | return inode; |
226 | { | ||
227 | struct sysfs_buffer_collection *set; | ||
228 | struct sysfs_buffer *buf; | ||
229 | |||
230 | mutex_lock_nested(&node->i_mutex, I_MUTEX_CHILD); | ||
231 | set = node->i_private; | ||
232 | if (set) { | ||
233 | list_for_each_entry(buf, &set->associates, associates) { | ||
234 | down(&buf->sem); | ||
235 | buf->orphaned = 1; | ||
236 | up(&buf->sem); | ||
237 | } | ||
238 | } | ||
239 | mutex_unlock(&node->i_mutex); | ||
240 | } | 178 | } |
241 | 179 | ||
242 | 180 | /** | |
243 | /* | 181 | * sysfs_instantiate - instantiate dentry |
244 | * Unhashes the dentry corresponding to given sysfs_dirent | 182 | * @dentry: dentry to be instantiated |
245 | * Called with parent inode's i_mutex held. | 183 | * @inode: inode associated with @sd |
184 | * | ||
185 | * Unlock @inode if locked and instantiate @dentry with @inode. | ||
186 | * | ||
187 | * LOCKING: | ||
188 | * None. | ||
246 | */ | 189 | */ |
247 | void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent) | 190 | void sysfs_instantiate(struct dentry *dentry, struct inode *inode) |
248 | { | 191 | { |
249 | struct dentry *dentry = NULL; | 192 | BUG_ON(!dentry || dentry->d_inode); |
250 | struct inode *inode; | ||
251 | 193 | ||
252 | /* We're not holding a reference to ->s_dentry dentry but the | 194 | if (inode->i_state & I_NEW) |
253 | * field will stay valid as long as sysfs_lock is held. | 195 | unlock_new_inode(inode); |
254 | */ | ||
255 | spin_lock(&sysfs_lock); | ||
256 | spin_lock(&dcache_lock); | ||
257 | |||
258 | /* dget dentry if it's still alive */ | ||
259 | if (sd->s_dentry && sd->s_dentry->d_inode) | ||
260 | dentry = dget_locked(sd->s_dentry); | ||
261 | |||
262 | spin_unlock(&dcache_lock); | ||
263 | spin_unlock(&sysfs_lock); | ||
264 | |||
265 | /* drop dentry */ | ||
266 | if (dentry) { | ||
267 | spin_lock(&dcache_lock); | ||
268 | spin_lock(&dentry->d_lock); | ||
269 | if (!d_unhashed(dentry) && dentry->d_inode) { | ||
270 | inode = dentry->d_inode; | ||
271 | spin_lock(&inode->i_lock); | ||
272 | __iget(inode); | ||
273 | spin_unlock(&inode->i_lock); | ||
274 | dget_locked(dentry); | ||
275 | __d_drop(dentry); | ||
276 | spin_unlock(&dentry->d_lock); | ||
277 | spin_unlock(&dcache_lock); | ||
278 | simple_unlink(parent->d_inode, dentry); | ||
279 | orphan_all_buffers(inode); | ||
280 | iput(inode); | ||
281 | } else { | ||
282 | spin_unlock(&dentry->d_lock); | ||
283 | spin_unlock(&dcache_lock); | ||
284 | } | ||
285 | 196 | ||
286 | dput(dentry); | 197 | d_instantiate(dentry, inode); |
287 | } | ||
288 | } | 198 | } |
289 | 199 | ||
290 | int sysfs_hash_and_remove(struct dentry * dir, const char * name) | 200 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) |
291 | { | 201 | { |
292 | struct sysfs_dirent * sd; | 202 | struct sysfs_addrm_cxt acxt; |
293 | struct sysfs_dirent * parent_sd; | 203 | struct sysfs_dirent **pos, *sd; |
294 | int found = 0; | ||
295 | 204 | ||
296 | if (!dir) | 205 | if (!dir_sd) |
297 | return -ENOENT; | 206 | return -ENOENT; |
298 | 207 | ||
299 | if (dir->d_inode == NULL) | 208 | sysfs_addrm_start(&acxt, dir_sd); |
300 | /* no inode means this hasn't been made visible yet */ | 209 | |
301 | return -ENOENT; | 210 | for (pos = &dir_sd->s_children; *pos; pos = &(*pos)->s_sibling) { |
211 | sd = *pos; | ||
302 | 212 | ||
303 | parent_sd = dir->d_fsdata; | 213 | if (!sysfs_type(sd)) |
304 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); | ||
305 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { | ||
306 | if (!sd->s_element) | ||
307 | continue; | 214 | continue; |
308 | if (!strcmp(sysfs_get_name(sd), name)) { | 215 | if (!strcmp(sd->s_name, name)) { |
309 | list_del_init(&sd->s_sibling); | 216 | *pos = sd->s_sibling; |
310 | sysfs_drop_dentry(sd, dir); | 217 | sd->s_sibling = NULL; |
311 | sysfs_put(sd); | 218 | sysfs_remove_one(&acxt, sd); |
312 | found = 1; | ||
313 | break; | 219 | break; |
314 | } | 220 | } |
315 | } | 221 | } |
316 | mutex_unlock(&dir->d_inode->i_mutex); | ||
317 | 222 | ||
318 | return found ? 0 : -ENOENT; | 223 | if (sysfs_addrm_finish(&acxt)) |
224 | return 0; | ||
225 | return -ENOENT; | ||
319 | } | 226 | } |
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 00ab9125d398..402cc356203c 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c | |||
@@ -19,28 +19,18 @@ struct vfsmount *sysfs_mount; | |||
19 | struct super_block * sysfs_sb = NULL; | 19 | struct super_block * sysfs_sb = NULL; |
20 | struct kmem_cache *sysfs_dir_cachep; | 20 | struct kmem_cache *sysfs_dir_cachep; |
21 | 21 | ||
22 | static void sysfs_clear_inode(struct inode *inode); | ||
23 | |||
24 | static const struct super_operations sysfs_ops = { | 22 | static const struct super_operations sysfs_ops = { |
25 | .statfs = simple_statfs, | 23 | .statfs = simple_statfs, |
26 | .drop_inode = sysfs_delete_inode, | 24 | .drop_inode = sysfs_delete_inode, |
27 | .clear_inode = sysfs_clear_inode, | ||
28 | }; | 25 | }; |
29 | 26 | ||
30 | static struct sysfs_dirent sysfs_root = { | 27 | struct sysfs_dirent sysfs_root = { |
31 | .s_sibling = LIST_HEAD_INIT(sysfs_root.s_sibling), | 28 | .s_count = ATOMIC_INIT(1), |
32 | .s_children = LIST_HEAD_INIT(sysfs_root.s_children), | 29 | .s_flags = SYSFS_ROOT, |
33 | .s_element = NULL, | 30 | .s_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, |
34 | .s_type = SYSFS_ROOT, | ||
35 | .s_iattr = NULL, | ||
36 | .s_ino = 1, | 31 | .s_ino = 1, |
37 | }; | 32 | }; |
38 | 33 | ||
39 | static void sysfs_clear_inode(struct inode *inode) | ||
40 | { | ||
41 | kfree(inode->i_private); | ||
42 | } | ||
43 | |||
44 | static int sysfs_fill_super(struct super_block *sb, void *data, int silent) | 34 | static int sysfs_fill_super(struct super_block *sb, void *data, int silent) |
45 | { | 35 | { |
46 | struct inode *inode; | 36 | struct inode *inode; |
@@ -53,24 +43,26 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) | |||
53 | sb->s_time_gran = 1; | 43 | sb->s_time_gran = 1; |
54 | sysfs_sb = sb; | 44 | sysfs_sb = sb; |
55 | 45 | ||
56 | inode = sysfs_new_inode(S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, | 46 | inode = new_inode(sysfs_sb); |
57 | &sysfs_root); | 47 | if (!inode) { |
58 | if (inode) { | ||
59 | inode->i_op = &sysfs_dir_inode_operations; | ||
60 | inode->i_fop = &sysfs_dir_operations; | ||
61 | /* directory inodes start off with i_nlink == 2 (for "." entry) */ | ||
62 | inc_nlink(inode); | ||
63 | } else { | ||
64 | pr_debug("sysfs: could not get root inode\n"); | 48 | pr_debug("sysfs: could not get root inode\n"); |
65 | return -ENOMEM; | 49 | return -ENOMEM; |
66 | } | 50 | } |
67 | 51 | ||
52 | sysfs_init_inode(&sysfs_root, inode); | ||
53 | |||
54 | inode->i_op = &sysfs_dir_inode_operations; | ||
55 | inode->i_fop = &sysfs_dir_operations; | ||
56 | /* directory inodes start off with i_nlink == 2 (for "." entry) */ | ||
57 | inc_nlink(inode); | ||
58 | |||
68 | root = d_alloc_root(inode); | 59 | root = d_alloc_root(inode); |
69 | if (!root) { | 60 | if (!root) { |
70 | pr_debug("%s: could not get root dentry!\n",__FUNCTION__); | 61 | pr_debug("%s: could not get root dentry!\n",__FUNCTION__); |
71 | iput(inode); | 62 | iput(inode); |
72 | return -ENOMEM; | 63 | return -ENOMEM; |
73 | } | 64 | } |
65 | sysfs_root.s_dentry = root; | ||
74 | root->d_fsdata = &sysfs_root; | 66 | root->d_fsdata = &sysfs_root; |
75 | sb->s_root = root; | 67 | sb->s_root = root; |
76 | return 0; | 68 | return 0; |
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 7b9c5bfde920..2f86e0422290 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c | |||
@@ -11,71 +11,39 @@ | |||
11 | 11 | ||
12 | #include "sysfs.h" | 12 | #include "sysfs.h" |
13 | 13 | ||
14 | static int object_depth(struct kobject * kobj) | 14 | static int object_depth(struct sysfs_dirent *sd) |
15 | { | 15 | { |
16 | struct kobject * p = kobj; | ||
17 | int depth = 0; | 16 | int depth = 0; |
18 | do { depth++; } while ((p = p->parent)); | 17 | |
18 | for (; sd->s_parent; sd = sd->s_parent) | ||
19 | depth++; | ||
20 | |||
19 | return depth; | 21 | return depth; |
20 | } | 22 | } |
21 | 23 | ||
22 | static int object_path_length(struct kobject * kobj) | 24 | static int object_path_length(struct sysfs_dirent * sd) |
23 | { | 25 | { |
24 | struct kobject * p = kobj; | ||
25 | int length = 1; | 26 | int length = 1; |
26 | do { | 27 | |
27 | length += strlen(kobject_name(p)) + 1; | 28 | for (; sd->s_parent; sd = sd->s_parent) |
28 | p = p->parent; | 29 | length += strlen(sd->s_name) + 1; |
29 | } while (p); | 30 | |
30 | return length; | 31 | return length; |
31 | } | 32 | } |
32 | 33 | ||
33 | static void fill_object_path(struct kobject * kobj, char * buffer, int length) | 34 | static void fill_object_path(struct sysfs_dirent *sd, char *buffer, int length) |
34 | { | 35 | { |
35 | struct kobject * p; | ||
36 | |||
37 | --length; | 36 | --length; |
38 | for (p = kobj; p; p = p->parent) { | 37 | for (; sd->s_parent; sd = sd->s_parent) { |
39 | int cur = strlen(kobject_name(p)); | 38 | int cur = strlen(sd->s_name); |
40 | 39 | ||
41 | /* back up enough to print this bus id with '/' */ | 40 | /* back up enough to print this bus id with '/' */ |
42 | length -= cur; | 41 | length -= cur; |
43 | strncpy(buffer + length,kobject_name(p),cur); | 42 | strncpy(buffer + length, sd->s_name, cur); |
44 | *(buffer + --length) = '/'; | 43 | *(buffer + --length) = '/'; |
45 | } | 44 | } |
46 | } | 45 | } |
47 | 46 | ||
48 | static int sysfs_add_link(struct dentry * parent, const char * name, struct kobject * target) | ||
49 | { | ||
50 | struct sysfs_dirent * parent_sd = parent->d_fsdata; | ||
51 | struct sysfs_symlink * sl; | ||
52 | int error = 0; | ||
53 | |||
54 | error = -ENOMEM; | ||
55 | sl = kmalloc(sizeof(*sl), GFP_KERNEL); | ||
56 | if (!sl) | ||
57 | goto exit1; | ||
58 | |||
59 | sl->link_name = kmalloc(strlen(name) + 1, GFP_KERNEL); | ||
60 | if (!sl->link_name) | ||
61 | goto exit2; | ||
62 | |||
63 | strcpy(sl->link_name, name); | ||
64 | sl->target_kobj = kobject_get(target); | ||
65 | |||
66 | error = sysfs_make_dirent(parent_sd, NULL, sl, S_IFLNK|S_IRWXUGO, | ||
67 | SYSFS_KOBJ_LINK); | ||
68 | if (!error) | ||
69 | return 0; | ||
70 | |||
71 | kobject_put(target); | ||
72 | kfree(sl->link_name); | ||
73 | exit2: | ||
74 | kfree(sl); | ||
75 | exit1: | ||
76 | return error; | ||
77 | } | ||
78 | |||
79 | /** | 47 | /** |
80 | * sysfs_create_link - create symlink between two objects. | 48 | * sysfs_create_link - create symlink between two objects. |
81 | * @kobj: object whose directory we're creating the link in. | 49 | * @kobj: object whose directory we're creating the link in. |
@@ -84,24 +52,57 @@ exit1: | |||
84 | */ | 52 | */ |
85 | int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * name) | 53 | int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * name) |
86 | { | 54 | { |
87 | struct dentry *dentry = NULL; | 55 | struct sysfs_dirent *parent_sd = NULL; |
88 | int error = -EEXIST; | 56 | struct sysfs_dirent *target_sd = NULL; |
57 | struct sysfs_dirent *sd = NULL; | ||
58 | struct sysfs_addrm_cxt acxt; | ||
59 | int error; | ||
89 | 60 | ||
90 | BUG_ON(!name); | 61 | BUG_ON(!name); |
91 | 62 | ||
92 | if (!kobj) { | 63 | if (!kobj) { |
93 | if (sysfs_mount && sysfs_mount->mnt_sb) | 64 | if (sysfs_mount && sysfs_mount->mnt_sb) |
94 | dentry = sysfs_mount->mnt_sb->s_root; | 65 | parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata; |
95 | } else | 66 | } else |
96 | dentry = kobj->dentry; | 67 | parent_sd = kobj->sd; |
68 | |||
69 | error = -EFAULT; | ||
70 | if (!parent_sd) | ||
71 | goto out_put; | ||
72 | |||
73 | /* target->sd can go away beneath us but is protected with | ||
74 | * sysfs_assoc_lock. Fetch target_sd from it. | ||
75 | */ | ||
76 | spin_lock(&sysfs_assoc_lock); | ||
77 | if (target->sd) | ||
78 | target_sd = sysfs_get(target->sd); | ||
79 | spin_unlock(&sysfs_assoc_lock); | ||
80 | |||
81 | error = -ENOENT; | ||
82 | if (!target_sd) | ||
83 | goto out_put; | ||
84 | |||
85 | error = -ENOMEM; | ||
86 | sd = sysfs_new_dirent(name, S_IFLNK|S_IRWXUGO, SYSFS_KOBJ_LINK); | ||
87 | if (!sd) | ||
88 | goto out_put; | ||
89 | sd->s_elem.symlink.target_sd = target_sd; | ||
97 | 90 | ||
98 | if (!dentry) | 91 | sysfs_addrm_start(&acxt, parent_sd); |
99 | return -EFAULT; | ||
100 | 92 | ||
101 | mutex_lock(&dentry->d_inode->i_mutex); | 93 | if (!sysfs_find_dirent(parent_sd, name)) { |
102 | if (!sysfs_dirent_exist(dentry->d_fsdata, name)) | 94 | sysfs_add_one(&acxt, sd); |
103 | error = sysfs_add_link(dentry, name, target); | 95 | sysfs_link_sibling(sd); |
104 | mutex_unlock(&dentry->d_inode->i_mutex); | 96 | } |
97 | |||
98 | if (sysfs_addrm_finish(&acxt)) | ||
99 | return 0; | ||
100 | |||
101 | error = -EEXIST; | ||
102 | /* fall through */ | ||
103 | out_put: | ||
104 | sysfs_put(target_sd); | ||
105 | sysfs_put(sd); | ||
105 | return error; | 106 | return error; |
106 | } | 107 | } |
107 | 108 | ||
@@ -114,17 +115,17 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char | |||
114 | 115 | ||
115 | void sysfs_remove_link(struct kobject * kobj, const char * name) | 116 | void sysfs_remove_link(struct kobject * kobj, const char * name) |
116 | { | 117 | { |
117 | sysfs_hash_and_remove(kobj->dentry,name); | 118 | sysfs_hash_and_remove(kobj->sd, name); |
118 | } | 119 | } |
119 | 120 | ||
120 | static int sysfs_get_target_path(struct kobject * kobj, struct kobject * target, | 121 | static int sysfs_get_target_path(struct sysfs_dirent * parent_sd, |
121 | char *path) | 122 | struct sysfs_dirent * target_sd, char *path) |
122 | { | 123 | { |
123 | char * s; | 124 | char * s; |
124 | int depth, size; | 125 | int depth, size; |
125 | 126 | ||
126 | depth = object_depth(kobj); | 127 | depth = object_depth(parent_sd); |
127 | size = object_path_length(target) + depth * 3 - 1; | 128 | size = object_path_length(target_sd) + depth * 3 - 1; |
128 | if (size > PATH_MAX) | 129 | if (size > PATH_MAX) |
129 | return -ENAMETOOLONG; | 130 | return -ENAMETOOLONG; |
130 | 131 | ||
@@ -133,7 +134,7 @@ static int sysfs_get_target_path(struct kobject * kobj, struct kobject * target, | |||
133 | for (s = path; depth--; s += 3) | 134 | for (s = path; depth--; s += 3) |
134 | strcpy(s,"../"); | 135 | strcpy(s,"../"); |
135 | 136 | ||
136 | fill_object_path(target, path, size); | 137 | fill_object_path(target_sd, path, size); |
137 | pr_debug("%s: path = '%s'\n", __FUNCTION__, path); | 138 | pr_debug("%s: path = '%s'\n", __FUNCTION__, path); |
138 | 139 | ||
139 | return 0; | 140 | return 0; |
@@ -141,27 +142,16 @@ static int sysfs_get_target_path(struct kobject * kobj, struct kobject * target, | |||
141 | 142 | ||
142 | static int sysfs_getlink(struct dentry *dentry, char * path) | 143 | static int sysfs_getlink(struct dentry *dentry, char * path) |
143 | { | 144 | { |
144 | struct kobject *kobj, *target_kobj; | 145 | struct sysfs_dirent *sd = dentry->d_fsdata; |
145 | int error = 0; | 146 | struct sysfs_dirent *parent_sd = sd->s_parent; |
147 | struct sysfs_dirent *target_sd = sd->s_elem.symlink.target_sd; | ||
148 | int error; | ||
146 | 149 | ||
147 | kobj = sysfs_get_kobject(dentry->d_parent); | 150 | mutex_lock(&sysfs_mutex); |
148 | if (!kobj) | 151 | error = sysfs_get_target_path(parent_sd, target_sd, path); |
149 | return -EINVAL; | 152 | mutex_unlock(&sysfs_mutex); |
150 | 153 | ||
151 | target_kobj = sysfs_get_kobject(dentry); | ||
152 | if (!target_kobj) { | ||
153 | kobject_put(kobj); | ||
154 | return -EINVAL; | ||
155 | } | ||
156 | |||
157 | down_read(&sysfs_rename_sem); | ||
158 | error = sysfs_get_target_path(kobj, target_kobj, path); | ||
159 | up_read(&sysfs_rename_sem); | ||
160 | |||
161 | kobject_put(kobj); | ||
162 | kobject_put(target_kobj); | ||
163 | return error; | 154 | return error; |
164 | |||
165 | } | 155 | } |
166 | 156 | ||
167 | static void *sysfs_follow_link(struct dentry *dentry, struct nameidata *nd) | 157 | static void *sysfs_follow_link(struct dentry *dentry, struct nameidata *nd) |
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 502c949c402d..6a37f2386a8d 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h | |||
@@ -1,9 +1,40 @@ | |||
1 | struct sysfs_elem_dir { | ||
2 | struct kobject * kobj; | ||
3 | }; | ||
4 | |||
5 | struct sysfs_elem_symlink { | ||
6 | struct sysfs_dirent * target_sd; | ||
7 | }; | ||
8 | |||
9 | struct sysfs_elem_attr { | ||
10 | struct attribute * attr; | ||
11 | }; | ||
12 | |||
13 | struct sysfs_elem_bin_attr { | ||
14 | struct bin_attribute * bin_attr; | ||
15 | }; | ||
16 | |||
17 | /* | ||
18 | * As long as s_count reference is held, the sysfs_dirent itself is | ||
19 | * accessible. Dereferencing s_elem or any other outer entity | ||
20 | * requires s_active reference. | ||
21 | */ | ||
1 | struct sysfs_dirent { | 22 | struct sysfs_dirent { |
2 | atomic_t s_count; | 23 | atomic_t s_count; |
3 | struct list_head s_sibling; | 24 | atomic_t s_active; |
4 | struct list_head s_children; | 25 | struct sysfs_dirent * s_parent; |
5 | void * s_element; | 26 | struct sysfs_dirent * s_sibling; |
6 | int s_type; | 27 | struct sysfs_dirent * s_children; |
28 | const char * s_name; | ||
29 | |||
30 | union { | ||
31 | struct sysfs_elem_dir dir; | ||
32 | struct sysfs_elem_symlink symlink; | ||
33 | struct sysfs_elem_attr attr; | ||
34 | struct sysfs_elem_bin_attr bin_attr; | ||
35 | } s_elem; | ||
36 | |||
37 | unsigned int s_flags; | ||
7 | umode_t s_mode; | 38 | umode_t s_mode; |
8 | ino_t s_ino; | 39 | ino_t s_ino; |
9 | struct dentry * s_dentry; | 40 | struct dentry * s_dentry; |
@@ -11,30 +42,60 @@ struct sysfs_dirent { | |||
11 | atomic_t s_event; | 42 | atomic_t s_event; |
12 | }; | 43 | }; |
13 | 44 | ||
45 | #define SD_DEACTIVATED_BIAS INT_MIN | ||
46 | |||
47 | struct sysfs_addrm_cxt { | ||
48 | struct sysfs_dirent *parent_sd; | ||
49 | struct inode *parent_inode; | ||
50 | struct sysfs_dirent *removed; | ||
51 | int cnt; | ||
52 | }; | ||
53 | |||
14 | extern struct vfsmount * sysfs_mount; | 54 | extern struct vfsmount * sysfs_mount; |
55 | extern struct sysfs_dirent sysfs_root; | ||
15 | extern struct kmem_cache *sysfs_dir_cachep; | 56 | extern struct kmem_cache *sysfs_dir_cachep; |
16 | 57 | ||
17 | extern void sysfs_delete_inode(struct inode *inode); | 58 | extern struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd); |
18 | extern struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *); | 59 | extern void sysfs_link_sibling(struct sysfs_dirent *sd); |
19 | extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *)); | 60 | extern void sysfs_unlink_sibling(struct sysfs_dirent *sd); |
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); | ||
20 | 72 | ||
21 | extern int sysfs_dirent_exist(struct sysfs_dirent *, const unsigned char *); | 73 | extern void sysfs_delete_inode(struct inode *inode); |
22 | extern int sysfs_make_dirent(struct sysfs_dirent *, struct dentry *, void *, | 74 | extern void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode); |
23 | umode_t, int); | 75 | extern struct inode * sysfs_get_inode(struct sysfs_dirent *sd); |
24 | 76 | extern void sysfs_instantiate(struct dentry *dentry, struct inode *inode); | |
25 | extern int sysfs_add_file(struct dentry *, const struct attribute *, int); | 77 | |
26 | extern int sysfs_hash_and_remove(struct dentry * dir, const char * name); | 78 | extern void release_sysfs_dirent(struct sysfs_dirent * sd); |
79 | extern struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, | ||
80 | const unsigned char *name); | ||
81 | extern struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, | ||
82 | const unsigned char *name); | ||
83 | extern struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, | ||
84 | int type); | ||
85 | |||
86 | extern int sysfs_add_file(struct sysfs_dirent *dir_sd, | ||
87 | const struct attribute *attr, int type); | ||
88 | extern int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name); | ||
27 | extern struct sysfs_dirent *sysfs_find(struct sysfs_dirent *dir, const char * name); | 89 | extern struct sysfs_dirent *sysfs_find(struct sysfs_dirent *dir, const char * name); |
28 | 90 | ||
29 | extern int sysfs_create_subdir(struct kobject *, const char *, struct dentry **); | 91 | extern int sysfs_create_subdir(struct kobject *kobj, const char *name, |
30 | extern void sysfs_remove_subdir(struct dentry *); | 92 | struct sysfs_dirent **p_sd); |
93 | extern void sysfs_remove_subdir(struct sysfs_dirent *sd); | ||
31 | 94 | ||
32 | extern const unsigned char * sysfs_get_name(struct sysfs_dirent *sd); | ||
33 | extern void sysfs_drop_dentry(struct sysfs_dirent *sd, struct dentry *parent); | ||
34 | extern int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); | 95 | extern int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); |
35 | 96 | ||
36 | extern spinlock_t sysfs_lock; | 97 | extern spinlock_t sysfs_assoc_lock; |
37 | extern struct rw_semaphore sysfs_rename_sem; | 98 | extern struct mutex sysfs_mutex; |
38 | extern struct super_block * sysfs_sb; | 99 | extern struct super_block * sysfs_sb; |
39 | extern const struct file_operations sysfs_dir_operations; | 100 | extern const struct file_operations sysfs_dir_operations; |
40 | extern const struct file_operations sysfs_file_operations; | 101 | extern const struct file_operations sysfs_file_operations; |
@@ -42,73 +103,9 @@ extern const struct file_operations bin_fops; | |||
42 | extern const struct inode_operations sysfs_dir_inode_operations; | 103 | extern const struct inode_operations sysfs_dir_inode_operations; |
43 | extern const struct inode_operations sysfs_symlink_inode_operations; | 104 | extern const struct inode_operations sysfs_symlink_inode_operations; |
44 | 105 | ||
45 | struct sysfs_symlink { | 106 | static inline unsigned int sysfs_type(struct sysfs_dirent *sd) |
46 | char * link_name; | ||
47 | struct kobject * target_kobj; | ||
48 | }; | ||
49 | |||
50 | struct sysfs_buffer { | ||
51 | struct list_head associates; | ||
52 | size_t count; | ||
53 | loff_t pos; | ||
54 | char * page; | ||
55 | struct sysfs_ops * ops; | ||
56 | struct semaphore sem; | ||
57 | int orphaned; | ||
58 | int needs_read_fill; | ||
59 | int event; | ||
60 | }; | ||
61 | |||
62 | struct sysfs_buffer_collection { | ||
63 | struct list_head associates; | ||
64 | }; | ||
65 | |||
66 | static inline struct kobject * to_kobj(struct dentry * dentry) | ||
67 | { | ||
68 | struct sysfs_dirent * sd = dentry->d_fsdata; | ||
69 | return ((struct kobject *) sd->s_element); | ||
70 | } | ||
71 | |||
72 | static inline struct attribute * to_attr(struct dentry * dentry) | ||
73 | { | 107 | { |
74 | struct sysfs_dirent * sd = dentry->d_fsdata; | 108 | return sd->s_flags & SYSFS_TYPE_MASK; |
75 | return ((struct attribute *) sd->s_element); | ||
76 | } | ||
77 | |||
78 | static inline struct bin_attribute * to_bin_attr(struct dentry * dentry) | ||
79 | { | ||
80 | struct sysfs_dirent * sd = dentry->d_fsdata; | ||
81 | return ((struct bin_attribute *) sd->s_element); | ||
82 | } | ||
83 | |||
84 | static inline struct kobject *sysfs_get_kobject(struct dentry *dentry) | ||
85 | { | ||
86 | struct kobject * kobj = NULL; | ||
87 | |||
88 | spin_lock(&dcache_lock); | ||
89 | if (!d_unhashed(dentry)) { | ||
90 | struct sysfs_dirent * sd = dentry->d_fsdata; | ||
91 | if (sd->s_type & SYSFS_KOBJ_LINK) { | ||
92 | struct sysfs_symlink * sl = sd->s_element; | ||
93 | kobj = kobject_get(sl->target_kobj); | ||
94 | } else | ||
95 | kobj = kobject_get(sd->s_element); | ||
96 | } | ||
97 | spin_unlock(&dcache_lock); | ||
98 | |||
99 | return kobj; | ||
100 | } | ||
101 | |||
102 | static inline void release_sysfs_dirent(struct sysfs_dirent * sd) | ||
103 | { | ||
104 | if (sd->s_type & SYSFS_KOBJ_LINK) { | ||
105 | struct sysfs_symlink * sl = sd->s_element; | ||
106 | kfree(sl->link_name); | ||
107 | kobject_put(sl->target_kobj); | ||
108 | kfree(sl); | ||
109 | } | ||
110 | kfree(sd->s_iattr); | ||
111 | kmem_cache_free(sysfs_dir_cachep, sd); | ||
112 | } | 109 | } |
113 | 110 | ||
114 | static inline struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd) | 111 | static inline struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd) |
@@ -122,7 +119,7 @@ static inline struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd) | |||
122 | 119 | ||
123 | static inline void sysfs_put(struct sysfs_dirent * sd) | 120 | static inline void sysfs_put(struct sysfs_dirent * sd) |
124 | { | 121 | { |
125 | if (atomic_dec_and_test(&sd->s_count)) | 122 | if (sd && atomic_dec_and_test(&sd->s_count)) |
126 | release_sysfs_dirent(sd); | 123 | release_sysfs_dirent(sd); |
127 | } | 124 | } |
128 | 125 | ||