diff options
Diffstat (limited to 'fs/sysfs')
-rw-r--r-- | fs/sysfs/bin.c | 56 | ||||
-rw-r--r-- | fs/sysfs/dir.c | 532 | ||||
-rw-r--r-- | fs/sysfs/file.c | 88 | ||||
-rw-r--r-- | fs/sysfs/inode.c | 205 | ||||
-rw-r--r-- | fs/sysfs/mount.c | 5 | ||||
-rw-r--r-- | fs/sysfs/symlink.c | 50 | ||||
-rw-r--r-- | fs/sysfs/sysfs.h | 37 |
7 files changed, 473 insertions, 500 deletions
diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c index 60c702bc10ae..e9d293593e52 100644 --- a/fs/sysfs/bin.c +++ b/fs/sysfs/bin.c | |||
@@ -54,14 +54,14 @@ fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count) | |||
54 | int rc; | 54 | int rc; |
55 | 55 | ||
56 | /* need attr_sd for attr, its parent for kobj */ | 56 | /* need attr_sd for attr, its parent for kobj */ |
57 | if (!sysfs_get_active_two(attr_sd)) | 57 | if (!sysfs_get_active(attr_sd)) |
58 | return -ENODEV; | 58 | return -ENODEV; |
59 | 59 | ||
60 | rc = -EIO; | 60 | rc = -EIO; |
61 | if (attr->read) | 61 | if (attr->read) |
62 | rc = attr->read(kobj, attr, buffer, off, count); | 62 | rc = attr->read(kobj, attr, buffer, off, count); |
63 | 63 | ||
64 | sysfs_put_active_two(attr_sd); | 64 | sysfs_put_active(attr_sd); |
65 | 65 | ||
66 | return rc; | 66 | return rc; |
67 | } | 67 | } |
@@ -125,14 +125,14 @@ flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count) | |||
125 | int rc; | 125 | int rc; |
126 | 126 | ||
127 | /* need attr_sd for attr, its parent for kobj */ | 127 | /* need attr_sd for attr, its parent for kobj */ |
128 | if (!sysfs_get_active_two(attr_sd)) | 128 | if (!sysfs_get_active(attr_sd)) |
129 | return -ENODEV; | 129 | return -ENODEV; |
130 | 130 | ||
131 | rc = -EIO; | 131 | rc = -EIO; |
132 | if (attr->write) | 132 | if (attr->write) |
133 | rc = attr->write(kobj, attr, buffer, offset, count); | 133 | rc = attr->write(kobj, attr, buffer, offset, count); |
134 | 134 | ||
135 | sysfs_put_active_two(attr_sd); | 135 | sysfs_put_active(attr_sd); |
136 | 136 | ||
137 | return rc; | 137 | return rc; |
138 | } | 138 | } |
@@ -184,12 +184,12 @@ static void bin_vma_open(struct vm_area_struct *vma) | |||
184 | if (!bb->vm_ops || !bb->vm_ops->open) | 184 | if (!bb->vm_ops || !bb->vm_ops->open) |
185 | return; | 185 | return; |
186 | 186 | ||
187 | if (!sysfs_get_active_two(attr_sd)) | 187 | if (!sysfs_get_active(attr_sd)) |
188 | return; | 188 | return; |
189 | 189 | ||
190 | bb->vm_ops->open(vma); | 190 | bb->vm_ops->open(vma); |
191 | 191 | ||
192 | sysfs_put_active_two(attr_sd); | 192 | sysfs_put_active(attr_sd); |
193 | } | 193 | } |
194 | 194 | ||
195 | static void bin_vma_close(struct vm_area_struct *vma) | 195 | static void bin_vma_close(struct vm_area_struct *vma) |
@@ -201,12 +201,12 @@ static void bin_vma_close(struct vm_area_struct *vma) | |||
201 | if (!bb->vm_ops || !bb->vm_ops->close) | 201 | if (!bb->vm_ops || !bb->vm_ops->close) |
202 | return; | 202 | return; |
203 | 203 | ||
204 | if (!sysfs_get_active_two(attr_sd)) | 204 | if (!sysfs_get_active(attr_sd)) |
205 | return; | 205 | return; |
206 | 206 | ||
207 | bb->vm_ops->close(vma); | 207 | bb->vm_ops->close(vma); |
208 | 208 | ||
209 | sysfs_put_active_two(attr_sd); | 209 | sysfs_put_active(attr_sd); |
210 | } | 210 | } |
211 | 211 | ||
212 | static int bin_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | 212 | static int bin_fault(struct vm_area_struct *vma, struct vm_fault *vmf) |
@@ -219,12 +219,12 @@ static int bin_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
219 | if (!bb->vm_ops || !bb->vm_ops->fault) | 219 | if (!bb->vm_ops || !bb->vm_ops->fault) |
220 | return VM_FAULT_SIGBUS; | 220 | return VM_FAULT_SIGBUS; |
221 | 221 | ||
222 | if (!sysfs_get_active_two(attr_sd)) | 222 | if (!sysfs_get_active(attr_sd)) |
223 | return VM_FAULT_SIGBUS; | 223 | return VM_FAULT_SIGBUS; |
224 | 224 | ||
225 | ret = bb->vm_ops->fault(vma, vmf); | 225 | ret = bb->vm_ops->fault(vma, vmf); |
226 | 226 | ||
227 | sysfs_put_active_two(attr_sd); | 227 | sysfs_put_active(attr_sd); |
228 | return ret; | 228 | return ret; |
229 | } | 229 | } |
230 | 230 | ||
@@ -241,12 +241,12 @@ static int bin_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
241 | if (!bb->vm_ops->page_mkwrite) | 241 | if (!bb->vm_ops->page_mkwrite) |
242 | return 0; | 242 | return 0; |
243 | 243 | ||
244 | if (!sysfs_get_active_two(attr_sd)) | 244 | if (!sysfs_get_active(attr_sd)) |
245 | return VM_FAULT_SIGBUS; | 245 | return VM_FAULT_SIGBUS; |
246 | 246 | ||
247 | ret = bb->vm_ops->page_mkwrite(vma, vmf); | 247 | ret = bb->vm_ops->page_mkwrite(vma, vmf); |
248 | 248 | ||
249 | sysfs_put_active_two(attr_sd); | 249 | sysfs_put_active(attr_sd); |
250 | return ret; | 250 | return ret; |
251 | } | 251 | } |
252 | 252 | ||
@@ -261,12 +261,12 @@ static int bin_access(struct vm_area_struct *vma, unsigned long addr, | |||
261 | if (!bb->vm_ops || !bb->vm_ops->access) | 261 | if (!bb->vm_ops || !bb->vm_ops->access) |
262 | return -EINVAL; | 262 | return -EINVAL; |
263 | 263 | ||
264 | if (!sysfs_get_active_two(attr_sd)) | 264 | if (!sysfs_get_active(attr_sd)) |
265 | return -EINVAL; | 265 | return -EINVAL; |
266 | 266 | ||
267 | ret = bb->vm_ops->access(vma, addr, buf, len, write); | 267 | ret = bb->vm_ops->access(vma, addr, buf, len, write); |
268 | 268 | ||
269 | sysfs_put_active_two(attr_sd); | 269 | sysfs_put_active(attr_sd); |
270 | return ret; | 270 | return ret; |
271 | } | 271 | } |
272 | 272 | ||
@@ -281,12 +281,12 @@ static int bin_set_policy(struct vm_area_struct *vma, struct mempolicy *new) | |||
281 | if (!bb->vm_ops || !bb->vm_ops->set_policy) | 281 | if (!bb->vm_ops || !bb->vm_ops->set_policy) |
282 | return 0; | 282 | return 0; |
283 | 283 | ||
284 | if (!sysfs_get_active_two(attr_sd)) | 284 | if (!sysfs_get_active(attr_sd)) |
285 | return -EINVAL; | 285 | return -EINVAL; |
286 | 286 | ||
287 | ret = bb->vm_ops->set_policy(vma, new); | 287 | ret = bb->vm_ops->set_policy(vma, new); |
288 | 288 | ||
289 | sysfs_put_active_two(attr_sd); | 289 | sysfs_put_active(attr_sd); |
290 | return ret; | 290 | return ret; |
291 | } | 291 | } |
292 | 292 | ||
@@ -301,12 +301,12 @@ static struct mempolicy *bin_get_policy(struct vm_area_struct *vma, | |||
301 | if (!bb->vm_ops || !bb->vm_ops->get_policy) | 301 | if (!bb->vm_ops || !bb->vm_ops->get_policy) |
302 | return vma->vm_policy; | 302 | return vma->vm_policy; |
303 | 303 | ||
304 | if (!sysfs_get_active_two(attr_sd)) | 304 | if (!sysfs_get_active(attr_sd)) |
305 | return vma->vm_policy; | 305 | return vma->vm_policy; |
306 | 306 | ||
307 | pol = bb->vm_ops->get_policy(vma, addr); | 307 | pol = bb->vm_ops->get_policy(vma, addr); |
308 | 308 | ||
309 | sysfs_put_active_two(attr_sd); | 309 | sysfs_put_active(attr_sd); |
310 | return pol; | 310 | return pol; |
311 | } | 311 | } |
312 | 312 | ||
@@ -321,12 +321,12 @@ static int bin_migrate(struct vm_area_struct *vma, const nodemask_t *from, | |||
321 | if (!bb->vm_ops || !bb->vm_ops->migrate) | 321 | if (!bb->vm_ops || !bb->vm_ops->migrate) |
322 | return 0; | 322 | return 0; |
323 | 323 | ||
324 | if (!sysfs_get_active_two(attr_sd)) | 324 | if (!sysfs_get_active(attr_sd)) |
325 | return 0; | 325 | return 0; |
326 | 326 | ||
327 | ret = bb->vm_ops->migrate(vma, from, to, flags); | 327 | ret = bb->vm_ops->migrate(vma, from, to, flags); |
328 | 328 | ||
329 | sysfs_put_active_two(attr_sd); | 329 | sysfs_put_active(attr_sd); |
330 | return ret; | 330 | return ret; |
331 | } | 331 | } |
332 | #endif | 332 | #endif |
@@ -356,7 +356,7 @@ static int mmap(struct file *file, struct vm_area_struct *vma) | |||
356 | 356 | ||
357 | /* need attr_sd for attr, its parent for kobj */ | 357 | /* need attr_sd for attr, its parent for kobj */ |
358 | rc = -ENODEV; | 358 | rc = -ENODEV; |
359 | if (!sysfs_get_active_two(attr_sd)) | 359 | if (!sysfs_get_active(attr_sd)) |
360 | goto out_unlock; | 360 | goto out_unlock; |
361 | 361 | ||
362 | rc = -EINVAL; | 362 | rc = -EINVAL; |
@@ -384,7 +384,7 @@ static int mmap(struct file *file, struct vm_area_struct *vma) | |||
384 | bb->vm_ops = vma->vm_ops; | 384 | bb->vm_ops = vma->vm_ops; |
385 | vma->vm_ops = &bin_vm_ops; | 385 | vma->vm_ops = &bin_vm_ops; |
386 | out_put: | 386 | out_put: |
387 | sysfs_put_active_two(attr_sd); | 387 | sysfs_put_active(attr_sd); |
388 | out_unlock: | 388 | out_unlock: |
389 | mutex_unlock(&bb->mutex); | 389 | mutex_unlock(&bb->mutex); |
390 | 390 | ||
@@ -399,7 +399,7 @@ static int open(struct inode * inode, struct file * file) | |||
399 | int error; | 399 | int error; |
400 | 400 | ||
401 | /* binary file operations requires both @sd and its parent */ | 401 | /* binary file operations requires both @sd and its parent */ |
402 | if (!sysfs_get_active_two(attr_sd)) | 402 | if (!sysfs_get_active(attr_sd)) |
403 | return -ENODEV; | 403 | return -ENODEV; |
404 | 404 | ||
405 | error = -EACCES; | 405 | error = -EACCES; |
@@ -426,11 +426,11 @@ static int open(struct inode * inode, struct file * file) | |||
426 | mutex_unlock(&sysfs_bin_lock); | 426 | mutex_unlock(&sysfs_bin_lock); |
427 | 427 | ||
428 | /* open succeeded, put active references */ | 428 | /* open succeeded, put active references */ |
429 | sysfs_put_active_two(attr_sd); | 429 | sysfs_put_active(attr_sd); |
430 | return 0; | 430 | return 0; |
431 | 431 | ||
432 | err_out: | 432 | err_out: |
433 | sysfs_put_active_two(attr_sd); | 433 | sysfs_put_active(attr_sd); |
434 | kfree(bb); | 434 | kfree(bb); |
435 | return error; | 435 | return error; |
436 | } | 436 | } |
@@ -483,7 +483,8 @@ void unmap_bin_file(struct sysfs_dirent *attr_sd) | |||
483 | * @attr: attribute descriptor. | 483 | * @attr: attribute descriptor. |
484 | */ | 484 | */ |
485 | 485 | ||
486 | int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr) | 486 | int sysfs_create_bin_file(struct kobject *kobj, |
487 | const struct bin_attribute *attr) | ||
487 | { | 488 | { |
488 | BUG_ON(!kobj || !kobj->sd || !attr); | 489 | BUG_ON(!kobj || !kobj->sd || !attr); |
489 | 490 | ||
@@ -497,7 +498,8 @@ int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr) | |||
497 | * @attr: attribute descriptor. | 498 | * @attr: attribute descriptor. |
498 | */ | 499 | */ |
499 | 500 | ||
500 | void sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr) | 501 | void sysfs_remove_bin_file(struct kobject *kobj, |
502 | const struct bin_attribute *attr) | ||
501 | { | 503 | { |
502 | sysfs_hash_and_remove(kobj->sd, attr->attr.name); | 504 | sysfs_hash_and_remove(kobj->sd, attr->attr.name); |
503 | } | 505 | } |
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index e0201837d244..590717861c7a 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include "sysfs.h" | 25 | #include "sysfs.h" |
26 | 26 | ||
27 | DEFINE_MUTEX(sysfs_mutex); | 27 | DEFINE_MUTEX(sysfs_mutex); |
28 | DEFINE_MUTEX(sysfs_rename_mutex); | ||
29 | DEFINE_SPINLOCK(sysfs_assoc_lock); | 28 | DEFINE_SPINLOCK(sysfs_assoc_lock); |
30 | 29 | ||
31 | static DEFINE_SPINLOCK(sysfs_ino_lock); | 30 | static DEFINE_SPINLOCK(sysfs_ino_lock); |
@@ -85,46 +84,6 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd) | |||
85 | } | 84 | } |
86 | 85 | ||
87 | /** | 86 | /** |
88 | * sysfs_get_dentry - get dentry for the given sysfs_dirent | ||
89 | * @sd: sysfs_dirent of interest | ||
90 | * | ||
91 | * Get dentry for @sd. Dentry is looked up if currently not | ||
92 | * present. This function descends from the root looking up | ||
93 | * dentry for each step. | ||
94 | * | ||
95 | * LOCKING: | ||
96 | * mutex_lock(sysfs_rename_mutex) | ||
97 | * | ||
98 | * RETURNS: | ||
99 | * Pointer to found dentry on success, ERR_PTR() value on error. | ||
100 | */ | ||
101 | struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd) | ||
102 | { | ||
103 | struct dentry *dentry = dget(sysfs_sb->s_root); | ||
104 | |||
105 | while (dentry->d_fsdata != sd) { | ||
106 | struct sysfs_dirent *cur; | ||
107 | struct dentry *parent; | ||
108 | |||
109 | /* find the first ancestor which hasn't been looked up */ | ||
110 | cur = sd; | ||
111 | while (cur->s_parent != dentry->d_fsdata) | ||
112 | cur = cur->s_parent; | ||
113 | |||
114 | /* look it up */ | ||
115 | parent = dentry; | ||
116 | mutex_lock(&parent->d_inode->i_mutex); | ||
117 | dentry = lookup_one_noperm(cur->s_name, parent); | ||
118 | mutex_unlock(&parent->d_inode->i_mutex); | ||
119 | dput(parent); | ||
120 | |||
121 | if (IS_ERR(dentry)) | ||
122 | break; | ||
123 | } | ||
124 | return dentry; | ||
125 | } | ||
126 | |||
127 | /** | ||
128 | * sysfs_get_active - get an active reference to sysfs_dirent | 87 | * sysfs_get_active - get an active reference to sysfs_dirent |
129 | * @sd: sysfs_dirent to get an active reference to | 88 | * @sd: sysfs_dirent to get an active reference to |
130 | * | 89 | * |
@@ -134,7 +93,7 @@ struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd) | |||
134 | * RETURNS: | 93 | * RETURNS: |
135 | * Pointer to @sd on success, NULL on failure. | 94 | * Pointer to @sd on success, NULL on failure. |
136 | */ | 95 | */ |
137 | static struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd) | 96 | struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd) |
138 | { | 97 | { |
139 | if (unlikely(!sd)) | 98 | if (unlikely(!sd)) |
140 | return NULL; | 99 | return NULL; |
@@ -147,8 +106,10 @@ static struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd) | |||
147 | return NULL; | 106 | return NULL; |
148 | 107 | ||
149 | t = atomic_cmpxchg(&sd->s_active, v, v + 1); | 108 | t = atomic_cmpxchg(&sd->s_active, v, v + 1); |
150 | if (likely(t == v)) | 109 | if (likely(t == v)) { |
110 | rwsem_acquire_read(&sd->dep_map, 0, 1, _RET_IP_); | ||
151 | return sd; | 111 | return sd; |
112 | } | ||
152 | if (t < 0) | 113 | if (t < 0) |
153 | return NULL; | 114 | return NULL; |
154 | 115 | ||
@@ -163,7 +124,7 @@ static struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd) | |||
163 | * Put an active reference to @sd. This function is noop if @sd | 124 | * Put an active reference to @sd. This function is noop if @sd |
164 | * is NULL. | 125 | * is NULL. |
165 | */ | 126 | */ |
166 | static void sysfs_put_active(struct sysfs_dirent *sd) | 127 | void sysfs_put_active(struct sysfs_dirent *sd) |
167 | { | 128 | { |
168 | struct completion *cmpl; | 129 | struct completion *cmpl; |
169 | int v; | 130 | int v; |
@@ -171,6 +132,7 @@ static void sysfs_put_active(struct sysfs_dirent *sd) | |||
171 | if (unlikely(!sd)) | 132 | if (unlikely(!sd)) |
172 | return; | 133 | return; |
173 | 134 | ||
135 | rwsem_release(&sd->dep_map, 1, _RET_IP_); | ||
174 | v = atomic_dec_return(&sd->s_active); | 136 | v = atomic_dec_return(&sd->s_active); |
175 | if (likely(v != SD_DEACTIVATED_BIAS)) | 137 | if (likely(v != SD_DEACTIVATED_BIAS)) |
176 | return; | 138 | return; |
@@ -183,45 +145,6 @@ static void sysfs_put_active(struct sysfs_dirent *sd) | |||
183 | } | 145 | } |
184 | 146 | ||
185 | /** | 147 | /** |
186 | * sysfs_get_active_two - get active references to sysfs_dirent and parent | ||
187 | * @sd: sysfs_dirent of interest | ||
188 | * | ||
189 | * Get active reference to @sd and its parent. Parent's active | ||
190 | * reference is grabbed first. This function is noop if @sd is | ||
191 | * NULL. | ||
192 | * | ||
193 | * RETURNS: | ||
194 | * Pointer to @sd on success, NULL on failure. | ||
195 | */ | ||
196 | struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd) | ||
197 | { | ||
198 | if (sd) { | ||
199 | if (sd->s_parent && unlikely(!sysfs_get_active(sd->s_parent))) | ||
200 | return NULL; | ||
201 | if (unlikely(!sysfs_get_active(sd))) { | ||
202 | sysfs_put_active(sd->s_parent); | ||
203 | return NULL; | ||
204 | } | ||
205 | } | ||
206 | return sd; | ||
207 | } | ||
208 | |||
209 | /** | ||
210 | * sysfs_put_active_two - put active references to sysfs_dirent and parent | ||
211 | * @sd: sysfs_dirent of interest | ||
212 | * | ||
213 | * Put active references to @sd and its parent. This function is | ||
214 | * noop if @sd is NULL. | ||
215 | */ | ||
216 | void sysfs_put_active_two(struct sysfs_dirent *sd) | ||
217 | { | ||
218 | if (sd) { | ||
219 | sysfs_put_active(sd); | ||
220 | sysfs_put_active(sd->s_parent); | ||
221 | } | ||
222 | } | ||
223 | |||
224 | /** | ||
225 | * sysfs_deactivate - deactivate sysfs_dirent | 148 | * sysfs_deactivate - deactivate sysfs_dirent |
226 | * @sd: sysfs_dirent to deactivate | 149 | * @sd: sysfs_dirent to deactivate |
227 | * | 150 | * |
@@ -233,17 +156,27 @@ static void sysfs_deactivate(struct sysfs_dirent *sd) | |||
233 | int v; | 156 | int v; |
234 | 157 | ||
235 | BUG_ON(sd->s_sibling || !(sd->s_flags & SYSFS_FLAG_REMOVED)); | 158 | BUG_ON(sd->s_sibling || !(sd->s_flags & SYSFS_FLAG_REMOVED)); |
159 | |||
160 | if (!(sysfs_type(sd) & SYSFS_ACTIVE_REF)) | ||
161 | return; | ||
162 | |||
236 | sd->s_sibling = (void *)&wait; | 163 | sd->s_sibling = (void *)&wait; |
237 | 164 | ||
165 | rwsem_acquire(&sd->dep_map, 0, 0, _RET_IP_); | ||
238 | /* atomic_add_return() is a mb(), put_active() will always see | 166 | /* atomic_add_return() is a mb(), put_active() will always see |
239 | * the updated sd->s_sibling. | 167 | * the updated sd->s_sibling. |
240 | */ | 168 | */ |
241 | v = atomic_add_return(SD_DEACTIVATED_BIAS, &sd->s_active); | 169 | v = atomic_add_return(SD_DEACTIVATED_BIAS, &sd->s_active); |
242 | 170 | ||
243 | if (v != SD_DEACTIVATED_BIAS) | 171 | if (v != SD_DEACTIVATED_BIAS) { |
172 | lock_contended(&sd->dep_map, _RET_IP_); | ||
244 | wait_for_completion(&wait); | 173 | wait_for_completion(&wait); |
174 | } | ||
245 | 175 | ||
246 | sd->s_sibling = NULL; | 176 | sd->s_sibling = NULL; |
177 | |||
178 | lock_acquired(&sd->dep_map, _RET_IP_); | ||
179 | rwsem_release(&sd->dep_map, 1, _RET_IP_); | ||
247 | } | 180 | } |
248 | 181 | ||
249 | static int sysfs_alloc_ino(ino_t *pino) | 182 | static int sysfs_alloc_ino(ino_t *pino) |
@@ -298,7 +231,61 @@ void release_sysfs_dirent(struct sysfs_dirent * sd) | |||
298 | goto repeat; | 231 | goto repeat; |
299 | } | 232 | } |
300 | 233 | ||
301 | static void sysfs_d_iput(struct dentry * dentry, struct inode * inode) | 234 | static int sysfs_dentry_delete(struct dentry *dentry) |
235 | { | ||
236 | struct sysfs_dirent *sd = dentry->d_fsdata; | ||
237 | return !!(sd->s_flags & SYSFS_FLAG_REMOVED); | ||
238 | } | ||
239 | |||
240 | static int sysfs_dentry_revalidate(struct dentry *dentry, struct nameidata *nd) | ||
241 | { | ||
242 | struct sysfs_dirent *sd = dentry->d_fsdata; | ||
243 | int is_dir; | ||
244 | |||
245 | mutex_lock(&sysfs_mutex); | ||
246 | |||
247 | /* The sysfs dirent has been deleted */ | ||
248 | if (sd->s_flags & SYSFS_FLAG_REMOVED) | ||
249 | goto out_bad; | ||
250 | |||
251 | /* The sysfs dirent has been moved? */ | ||
252 | if (dentry->d_parent->d_fsdata != sd->s_parent) | ||
253 | goto out_bad; | ||
254 | |||
255 | /* The sysfs dirent has been renamed */ | ||
256 | if (strcmp(dentry->d_name.name, sd->s_name) != 0) | ||
257 | goto out_bad; | ||
258 | |||
259 | mutex_unlock(&sysfs_mutex); | ||
260 | out_valid: | ||
261 | return 1; | ||
262 | out_bad: | ||
263 | /* Remove the dentry from the dcache hashes. | ||
264 | * If this is a deleted dentry we use d_drop instead of d_delete | ||
265 | * so sysfs doesn't need to cope with negative dentries. | ||
266 | * | ||
267 | * If this is a dentry that has simply been renamed we | ||
268 | * use d_drop to remove it from the dcache lookup on its | ||
269 | * old parent. If this dentry persists later when a lookup | ||
270 | * is performed at its new name the dentry will be readded | ||
271 | * to the dcache hashes. | ||
272 | */ | ||
273 | is_dir = (sysfs_type(sd) == SYSFS_DIR); | ||
274 | mutex_unlock(&sysfs_mutex); | ||
275 | if (is_dir) { | ||
276 | /* If we have submounts we must allow the vfs caches | ||
277 | * to lie about the state of the filesystem to prevent | ||
278 | * leaks and other nasty things. | ||
279 | */ | ||
280 | if (have_submounts(dentry)) | ||
281 | goto out_valid; | ||
282 | shrink_dcache_parent(dentry); | ||
283 | } | ||
284 | d_drop(dentry); | ||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | static void sysfs_dentry_iput(struct dentry *dentry, struct inode *inode) | ||
302 | { | 289 | { |
303 | struct sysfs_dirent * sd = dentry->d_fsdata; | 290 | struct sysfs_dirent * sd = dentry->d_fsdata; |
304 | 291 | ||
@@ -307,7 +294,9 @@ static void sysfs_d_iput(struct dentry * dentry, struct inode * inode) | |||
307 | } | 294 | } |
308 | 295 | ||
309 | static const struct dentry_operations sysfs_dentry_ops = { | 296 | static const struct dentry_operations sysfs_dentry_ops = { |
310 | .d_iput = sysfs_d_iput, | 297 | .d_revalidate = sysfs_dentry_revalidate, |
298 | .d_delete = sysfs_dentry_delete, | ||
299 | .d_iput = sysfs_dentry_iput, | ||
311 | }; | 300 | }; |
312 | 301 | ||
313 | struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) | 302 | struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) |
@@ -344,12 +333,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) | |||
344 | return NULL; | 333 | return NULL; |
345 | } | 334 | } |
346 | 335 | ||
347 | static int sysfs_ilookup_test(struct inode *inode, void *arg) | ||
348 | { | ||
349 | struct sysfs_dirent *sd = arg; | ||
350 | return inode->i_ino == sd->s_ino; | ||
351 | } | ||
352 | |||
353 | /** | 336 | /** |
354 | * sysfs_addrm_start - prepare for sysfs_dirent add/remove | 337 | * sysfs_addrm_start - prepare for sysfs_dirent add/remove |
355 | * @acxt: pointer to sysfs_addrm_cxt to be used | 338 | * @acxt: pointer to sysfs_addrm_cxt to be used |
@@ -357,47 +340,20 @@ static int sysfs_ilookup_test(struct inode *inode, void *arg) | |||
357 | * | 340 | * |
358 | * This function is called when the caller is about to add or | 341 | * This function is called when the caller is about to add or |
359 | * remove sysfs_dirent under @parent_sd. This function acquires | 342 | * remove sysfs_dirent under @parent_sd. This function acquires |
360 | * sysfs_mutex, grabs inode for @parent_sd if available and lock | 343 | * sysfs_mutex. @acxt is used to keep and pass context to |
361 | * i_mutex of it. @acxt is used to keep and pass context to | ||
362 | * other addrm functions. | 344 | * other addrm functions. |
363 | * | 345 | * |
364 | * LOCKING: | 346 | * LOCKING: |
365 | * Kernel thread context (may sleep). sysfs_mutex is locked on | 347 | * Kernel thread context (may sleep). sysfs_mutex is locked on |
366 | * return. i_mutex of parent inode is locked on return if | 348 | * return. |
367 | * available. | ||
368 | */ | 349 | */ |
369 | void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, | 350 | void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, |
370 | struct sysfs_dirent *parent_sd) | 351 | struct sysfs_dirent *parent_sd) |
371 | { | 352 | { |
372 | struct inode *inode; | ||
373 | |||
374 | memset(acxt, 0, sizeof(*acxt)); | 353 | memset(acxt, 0, sizeof(*acxt)); |
375 | acxt->parent_sd = parent_sd; | 354 | acxt->parent_sd = parent_sd; |
376 | 355 | ||
377 | /* Lookup parent inode. inode initialization is protected by | ||
378 | * sysfs_mutex, so inode existence can be determined by | ||
379 | * looking up inode while holding sysfs_mutex. | ||
380 | */ | ||
381 | mutex_lock(&sysfs_mutex); | 356 | mutex_lock(&sysfs_mutex); |
382 | |||
383 | inode = ilookup5(sysfs_sb, parent_sd->s_ino, sysfs_ilookup_test, | ||
384 | parent_sd); | ||
385 | if (inode) { | ||
386 | WARN_ON(inode->i_state & I_NEW); | ||
387 | |||
388 | /* parent inode available */ | ||
389 | acxt->parent_inode = inode; | ||
390 | |||
391 | /* sysfs_mutex is below i_mutex in lock hierarchy. | ||
392 | * First, trylock i_mutex. If fails, unlock | ||
393 | * sysfs_mutex and lock them in order. | ||
394 | */ | ||
395 | if (!mutex_trylock(&inode->i_mutex)) { | ||
396 | mutex_unlock(&sysfs_mutex); | ||
397 | mutex_lock(&inode->i_mutex); | ||
398 | mutex_lock(&sysfs_mutex); | ||
399 | } | ||
400 | } | ||
401 | } | 357 | } |
402 | 358 | ||
403 | /** | 359 | /** |
@@ -422,18 +378,22 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, | |||
422 | */ | 378 | */ |
423 | int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | 379 | int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) |
424 | { | 380 | { |
381 | struct sysfs_inode_attrs *ps_iattr; | ||
382 | |||
425 | if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)) | 383 | if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)) |
426 | return -EEXIST; | 384 | return -EEXIST; |
427 | 385 | ||
428 | sd->s_parent = sysfs_get(acxt->parent_sd); | 386 | sd->s_parent = sysfs_get(acxt->parent_sd); |
429 | 387 | ||
430 | if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode) | ||
431 | inc_nlink(acxt->parent_inode); | ||
432 | |||
433 | acxt->cnt++; | ||
434 | |||
435 | sysfs_link_sibling(sd); | 388 | sysfs_link_sibling(sd); |
436 | 389 | ||
390 | /* Update timestamps on the parent */ | ||
391 | ps_iattr = acxt->parent_sd->s_iattr; | ||
392 | if (ps_iattr) { | ||
393 | struct iattr *ps_iattrs = &ps_iattr->ia_iattr; | ||
394 | ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME; | ||
395 | } | ||
396 | |||
437 | return 0; | 397 | return 0; |
438 | } | 398 | } |
439 | 399 | ||
@@ -512,70 +472,22 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | |||
512 | */ | 472 | */ |
513 | void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | 473 | void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) |
514 | { | 474 | { |
475 | struct sysfs_inode_attrs *ps_iattr; | ||
476 | |||
515 | BUG_ON(sd->s_flags & SYSFS_FLAG_REMOVED); | 477 | BUG_ON(sd->s_flags & SYSFS_FLAG_REMOVED); |
516 | 478 | ||
517 | sysfs_unlink_sibling(sd); | 479 | sysfs_unlink_sibling(sd); |
518 | 480 | ||
481 | /* Update timestamps on the parent */ | ||
482 | ps_iattr = acxt->parent_sd->s_iattr; | ||
483 | if (ps_iattr) { | ||
484 | struct iattr *ps_iattrs = &ps_iattr->ia_iattr; | ||
485 | ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME; | ||
486 | } | ||
487 | |||
519 | sd->s_flags |= SYSFS_FLAG_REMOVED; | 488 | sd->s_flags |= SYSFS_FLAG_REMOVED; |
520 | sd->s_sibling = acxt->removed; | 489 | sd->s_sibling = acxt->removed; |
521 | acxt->removed = sd; | 490 | acxt->removed = sd; |
522 | |||
523 | if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode) | ||
524 | drop_nlink(acxt->parent_inode); | ||
525 | |||
526 | acxt->cnt++; | ||
527 | } | ||
528 | |||
529 | /** | ||
530 | * sysfs_drop_dentry - drop dentry for the specified sysfs_dirent | ||
531 | * @sd: target sysfs_dirent | ||
532 | * | ||
533 | * Drop dentry for @sd. @sd must have been unlinked from its | ||
534 | * parent on entry to this function such that it can't be looked | ||
535 | * up anymore. | ||
536 | */ | ||
537 | static void sysfs_drop_dentry(struct sysfs_dirent *sd) | ||
538 | { | ||
539 | struct inode *inode; | ||
540 | struct dentry *dentry; | ||
541 | |||
542 | inode = ilookup(sysfs_sb, sd->s_ino); | ||
543 | if (!inode) | ||
544 | return; | ||
545 | |||
546 | /* Drop any existing dentries associated with sd. | ||
547 | * | ||
548 | * For the dentry to be properly freed we need to grab a | ||
549 | * reference to the dentry under the dcache lock, unhash it, | ||
550 | * and then put it. The playing with the dentry count allows | ||
551 | * dput to immediately free the dentry if it is not in use. | ||
552 | */ | ||
553 | repeat: | ||
554 | spin_lock(&dcache_lock); | ||
555 | list_for_each_entry(dentry, &inode->i_dentry, d_alias) { | ||
556 | if (d_unhashed(dentry)) | ||
557 | continue; | ||
558 | dget_locked(dentry); | ||
559 | spin_lock(&dentry->d_lock); | ||
560 | __d_drop(dentry); | ||
561 | spin_unlock(&dentry->d_lock); | ||
562 | spin_unlock(&dcache_lock); | ||
563 | dput(dentry); | ||
564 | goto repeat; | ||
565 | } | ||
566 | spin_unlock(&dcache_lock); | ||
567 | |||
568 | /* adjust nlink and update timestamp */ | ||
569 | mutex_lock(&inode->i_mutex); | ||
570 | |||
571 | inode->i_ctime = CURRENT_TIME; | ||
572 | drop_nlink(inode); | ||
573 | if (sysfs_type(sd) == SYSFS_DIR) | ||
574 | drop_nlink(inode); | ||
575 | |||
576 | mutex_unlock(&inode->i_mutex); | ||
577 | |||
578 | iput(inode); | ||
579 | } | 491 | } |
580 | 492 | ||
581 | /** | 493 | /** |
@@ -584,25 +496,15 @@ repeat: | |||
584 | * | 496 | * |
585 | * Finish up sysfs_dirent add/remove. Resources acquired by | 497 | * Finish up sysfs_dirent add/remove. Resources acquired by |
586 | * sysfs_addrm_start() are released and removed sysfs_dirents are | 498 | * sysfs_addrm_start() are released and removed sysfs_dirents are |
587 | * cleaned up. Timestamps on the parent inode are updated. | 499 | * cleaned up. |
588 | * | 500 | * |
589 | * LOCKING: | 501 | * LOCKING: |
590 | * All mutexes acquired by sysfs_addrm_start() are released. | 502 | * sysfs_mutex is released. |
591 | */ | 503 | */ |
592 | void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) | 504 | void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) |
593 | { | 505 | { |
594 | /* release resources acquired by sysfs_addrm_start() */ | 506 | /* release resources acquired by sysfs_addrm_start() */ |
595 | mutex_unlock(&sysfs_mutex); | 507 | mutex_unlock(&sysfs_mutex); |
596 | if (acxt->parent_inode) { | ||
597 | struct inode *inode = acxt->parent_inode; | ||
598 | |||
599 | /* if added/removed, update timestamps on the parent */ | ||
600 | if (acxt->cnt) | ||
601 | inode->i_ctime = inode->i_mtime = CURRENT_TIME; | ||
602 | |||
603 | mutex_unlock(&inode->i_mutex); | ||
604 | iput(inode); | ||
605 | } | ||
606 | 508 | ||
607 | /* kill removed sysfs_dirents */ | 509 | /* kill removed sysfs_dirents */ |
608 | while (acxt->removed) { | 510 | while (acxt->removed) { |
@@ -611,7 +513,6 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) | |||
611 | acxt->removed = sd->s_sibling; | 513 | acxt->removed = sd->s_sibling; |
612 | sd->s_sibling = NULL; | 514 | sd->s_sibling = NULL; |
613 | 515 | ||
614 | sysfs_drop_dentry(sd); | ||
615 | sysfs_deactivate(sd); | 516 | sysfs_deactivate(sd); |
616 | unmap_bin_file(sd); | 517 | unmap_bin_file(sd); |
617 | sysfs_put(sd); | 518 | sysfs_put(sd); |
@@ -744,17 +645,22 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, | |||
744 | } | 645 | } |
745 | 646 | ||
746 | /* attach dentry and inode */ | 647 | /* attach dentry and inode */ |
747 | inode = sysfs_get_inode(sd); | 648 | inode = sysfs_get_inode(dir->i_sb, sd); |
748 | if (!inode) { | 649 | if (!inode) { |
749 | ret = ERR_PTR(-ENOMEM); | 650 | ret = ERR_PTR(-ENOMEM); |
750 | goto out_unlock; | 651 | goto out_unlock; |
751 | } | 652 | } |
752 | 653 | ||
753 | /* instantiate and hash dentry */ | 654 | /* instantiate and hash dentry */ |
754 | dentry->d_op = &sysfs_dentry_ops; | 655 | ret = d_find_alias(inode); |
755 | dentry->d_fsdata = sysfs_get(sd); | 656 | if (!ret) { |
756 | d_instantiate(dentry, inode); | 657 | dentry->d_op = &sysfs_dentry_ops; |
757 | d_rehash(dentry); | 658 | dentry->d_fsdata = sysfs_get(sd); |
659 | d_add(dentry, inode); | ||
660 | } else { | ||
661 | d_move(ret, dentry); | ||
662 | iput(inode); | ||
663 | } | ||
758 | 664 | ||
759 | out_unlock: | 665 | out_unlock: |
760 | mutex_unlock(&sysfs_mutex); | 666 | mutex_unlock(&sysfs_mutex); |
@@ -763,7 +669,9 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, | |||
763 | 669 | ||
764 | const struct inode_operations sysfs_dir_inode_operations = { | 670 | const struct inode_operations sysfs_dir_inode_operations = { |
765 | .lookup = sysfs_lookup, | 671 | .lookup = sysfs_lookup, |
672 | .permission = sysfs_permission, | ||
766 | .setattr = sysfs_setattr, | 673 | .setattr = sysfs_setattr, |
674 | .getattr = sysfs_getattr, | ||
767 | .setxattr = sysfs_setxattr, | 675 | .setxattr = sysfs_setxattr, |
768 | }; | 676 | }; |
769 | 677 | ||
@@ -826,141 +734,65 @@ void sysfs_remove_dir(struct kobject * kobj) | |||
826 | __sysfs_remove_dir(sd); | 734 | __sysfs_remove_dir(sd); |
827 | } | 735 | } |
828 | 736 | ||
829 | int sysfs_rename_dir(struct kobject * kobj, const char *new_name) | 737 | int sysfs_rename(struct sysfs_dirent *sd, |
738 | struct sysfs_dirent *new_parent_sd, const char *new_name) | ||
830 | { | 739 | { |
831 | struct sysfs_dirent *sd = kobj->sd; | ||
832 | struct dentry *parent = NULL; | ||
833 | struct dentry *old_dentry = NULL, *new_dentry = NULL; | ||
834 | const char *dup_name = NULL; | 740 | const char *dup_name = NULL; |
835 | int error; | 741 | int error; |
836 | 742 | ||
837 | mutex_lock(&sysfs_rename_mutex); | 743 | mutex_lock(&sysfs_mutex); |
838 | 744 | ||
839 | error = 0; | 745 | error = 0; |
840 | if (strcmp(sd->s_name, new_name) == 0) | 746 | if ((sd->s_parent == new_parent_sd) && |
747 | (strcmp(sd->s_name, new_name) == 0)) | ||
841 | goto out; /* nothing to rename */ | 748 | goto out; /* nothing to rename */ |
842 | 749 | ||
843 | /* get the original dentry */ | ||
844 | old_dentry = sysfs_get_dentry(sd); | ||
845 | if (IS_ERR(old_dentry)) { | ||
846 | error = PTR_ERR(old_dentry); | ||
847 | old_dentry = NULL; | ||
848 | goto out; | ||
849 | } | ||
850 | |||
851 | parent = old_dentry->d_parent; | ||
852 | |||
853 | /* lock parent and get dentry for new name */ | ||
854 | mutex_lock(&parent->d_inode->i_mutex); | ||
855 | mutex_lock(&sysfs_mutex); | ||
856 | |||
857 | error = -EEXIST; | 750 | error = -EEXIST; |
858 | if (sysfs_find_dirent(sd->s_parent, new_name)) | 751 | if (sysfs_find_dirent(new_parent_sd, new_name)) |
859 | goto out_unlock; | 752 | goto out; |
860 | |||
861 | error = -ENOMEM; | ||
862 | new_dentry = d_alloc_name(parent, new_name); | ||
863 | if (!new_dentry) | ||
864 | goto out_unlock; | ||
865 | 753 | ||
866 | /* rename sysfs_dirent */ | 754 | /* rename sysfs_dirent */ |
867 | error = -ENOMEM; | 755 | if (strcmp(sd->s_name, new_name) != 0) { |
868 | new_name = dup_name = kstrdup(new_name, GFP_KERNEL); | 756 | error = -ENOMEM; |
869 | if (!new_name) | 757 | new_name = dup_name = kstrdup(new_name, GFP_KERNEL); |
870 | goto out_unlock; | 758 | if (!new_name) |
871 | 759 | goto out; | |
872 | dup_name = sd->s_name; | 760 | |
873 | sd->s_name = new_name; | 761 | dup_name = sd->s_name; |
762 | sd->s_name = new_name; | ||
763 | } | ||
874 | 764 | ||
875 | /* rename */ | 765 | /* Remove from old parent's list and insert into new parent's list. */ |
876 | d_add(new_dentry, NULL); | 766 | if (sd->s_parent != new_parent_sd) { |
877 | d_move(old_dentry, new_dentry); | 767 | sysfs_unlink_sibling(sd); |
768 | sysfs_get(new_parent_sd); | ||
769 | sysfs_put(sd->s_parent); | ||
770 | sd->s_parent = new_parent_sd; | ||
771 | sysfs_link_sibling(sd); | ||
772 | } | ||
878 | 773 | ||
879 | error = 0; | 774 | error = 0; |
880 | out_unlock: | 775 | out: |
881 | mutex_unlock(&sysfs_mutex); | 776 | mutex_unlock(&sysfs_mutex); |
882 | mutex_unlock(&parent->d_inode->i_mutex); | ||
883 | kfree(dup_name); | 777 | kfree(dup_name); |
884 | dput(old_dentry); | ||
885 | dput(new_dentry); | ||
886 | out: | ||
887 | mutex_unlock(&sysfs_rename_mutex); | ||
888 | return error; | 778 | return error; |
889 | } | 779 | } |
890 | 780 | ||
781 | int sysfs_rename_dir(struct kobject *kobj, const char *new_name) | ||
782 | { | ||
783 | return sysfs_rename(kobj->sd, kobj->sd->s_parent, new_name); | ||
784 | } | ||
785 | |||
891 | int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) | 786 | int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) |
892 | { | 787 | { |
893 | struct sysfs_dirent *sd = kobj->sd; | 788 | struct sysfs_dirent *sd = kobj->sd; |
894 | struct sysfs_dirent *new_parent_sd; | 789 | struct sysfs_dirent *new_parent_sd; |
895 | struct dentry *old_parent, *new_parent = NULL; | ||
896 | struct dentry *old_dentry = NULL, *new_dentry = NULL; | ||
897 | int error; | ||
898 | 790 | ||
899 | mutex_lock(&sysfs_rename_mutex); | ||
900 | BUG_ON(!sd->s_parent); | 791 | BUG_ON(!sd->s_parent); |
901 | new_parent_sd = (new_parent_kobj && new_parent_kobj->sd) ? | 792 | new_parent_sd = new_parent_kobj && new_parent_kobj->sd ? |
902 | new_parent_kobj->sd : &sysfs_root; | 793 | new_parent_kobj->sd : &sysfs_root; |
903 | 794 | ||
904 | error = 0; | 795 | return sysfs_rename(sd, new_parent_sd, sd->s_name); |
905 | if (sd->s_parent == new_parent_sd) | ||
906 | goto out; /* nothing to move */ | ||
907 | |||
908 | /* get dentries */ | ||
909 | old_dentry = sysfs_get_dentry(sd); | ||
910 | if (IS_ERR(old_dentry)) { | ||
911 | error = PTR_ERR(old_dentry); | ||
912 | old_dentry = NULL; | ||
913 | goto out; | ||
914 | } | ||
915 | old_parent = old_dentry->d_parent; | ||
916 | |||
917 | new_parent = sysfs_get_dentry(new_parent_sd); | ||
918 | if (IS_ERR(new_parent)) { | ||
919 | error = PTR_ERR(new_parent); | ||
920 | new_parent = NULL; | ||
921 | goto out; | ||
922 | } | ||
923 | |||
924 | again: | ||
925 | mutex_lock(&old_parent->d_inode->i_mutex); | ||
926 | if (!mutex_trylock(&new_parent->d_inode->i_mutex)) { | ||
927 | mutex_unlock(&old_parent->d_inode->i_mutex); | ||
928 | goto again; | ||
929 | } | ||
930 | mutex_lock(&sysfs_mutex); | ||
931 | |||
932 | error = -EEXIST; | ||
933 | if (sysfs_find_dirent(new_parent_sd, sd->s_name)) | ||
934 | goto out_unlock; | ||
935 | |||
936 | error = -ENOMEM; | ||
937 | new_dentry = d_alloc_name(new_parent, sd->s_name); | ||
938 | if (!new_dentry) | ||
939 | goto out_unlock; | ||
940 | |||
941 | error = 0; | ||
942 | d_add(new_dentry, NULL); | ||
943 | d_move(old_dentry, new_dentry); | ||
944 | |||
945 | /* Remove from old parent's list and insert into new parent's list. */ | ||
946 | sysfs_unlink_sibling(sd); | ||
947 | sysfs_get(new_parent_sd); | ||
948 | drop_nlink(old_parent->d_inode); | ||
949 | sysfs_put(sd->s_parent); | ||
950 | sd->s_parent = new_parent_sd; | ||
951 | inc_nlink(new_parent->d_inode); | ||
952 | sysfs_link_sibling(sd); | ||
953 | |||
954 | out_unlock: | ||
955 | mutex_unlock(&sysfs_mutex); | ||
956 | mutex_unlock(&new_parent->d_inode->i_mutex); | ||
957 | mutex_unlock(&old_parent->d_inode->i_mutex); | ||
958 | out: | ||
959 | dput(new_parent); | ||
960 | dput(old_dentry); | ||
961 | dput(new_dentry); | ||
962 | mutex_unlock(&sysfs_rename_mutex); | ||
963 | return error; | ||
964 | } | 796 | } |
965 | 797 | ||
966 | /* Relationship between s_mode and the DT_xxx types */ | 798 | /* Relationship between s_mode and the DT_xxx types */ |
@@ -969,11 +801,46 @@ static inline unsigned char dt_type(struct sysfs_dirent *sd) | |||
969 | return (sd->s_mode >> 12) & 15; | 801 | return (sd->s_mode >> 12) & 15; |
970 | } | 802 | } |
971 | 803 | ||
804 | static int sysfs_dir_release(struct inode *inode, struct file *filp) | ||
805 | { | ||
806 | sysfs_put(filp->private_data); | ||
807 | return 0; | ||
808 | } | ||
809 | |||
810 | static struct sysfs_dirent *sysfs_dir_pos(struct sysfs_dirent *parent_sd, | ||
811 | ino_t ino, struct sysfs_dirent *pos) | ||
812 | { | ||
813 | if (pos) { | ||
814 | int valid = !(pos->s_flags & SYSFS_FLAG_REMOVED) && | ||
815 | pos->s_parent == parent_sd && | ||
816 | ino == pos->s_ino; | ||
817 | sysfs_put(pos); | ||
818 | if (valid) | ||
819 | return pos; | ||
820 | } | ||
821 | pos = NULL; | ||
822 | if ((ino > 1) && (ino < INT_MAX)) { | ||
823 | pos = parent_sd->s_dir.children; | ||
824 | while (pos && (ino > pos->s_ino)) | ||
825 | pos = pos->s_sibling; | ||
826 | } | ||
827 | return pos; | ||
828 | } | ||
829 | |||
830 | static struct sysfs_dirent *sysfs_dir_next_pos(struct sysfs_dirent *parent_sd, | ||
831 | ino_t ino, struct sysfs_dirent *pos) | ||
832 | { | ||
833 | pos = sysfs_dir_pos(parent_sd, ino, pos); | ||
834 | if (pos) | ||
835 | pos = pos->s_sibling; | ||
836 | return pos; | ||
837 | } | ||
838 | |||
972 | static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) | 839 | static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) |
973 | { | 840 | { |
974 | struct dentry *dentry = filp->f_path.dentry; | 841 | struct dentry *dentry = filp->f_path.dentry; |
975 | struct sysfs_dirent * parent_sd = dentry->d_fsdata; | 842 | struct sysfs_dirent * parent_sd = dentry->d_fsdata; |
976 | struct sysfs_dirent *pos; | 843 | struct sysfs_dirent *pos = filp->private_data; |
977 | ino_t ino; | 844 | ino_t ino; |
978 | 845 | ||
979 | if (filp->f_pos == 0) { | 846 | if (filp->f_pos == 0) { |
@@ -989,29 +856,31 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
989 | if (filldir(dirent, "..", 2, filp->f_pos, ino, DT_DIR) == 0) | 856 | if (filldir(dirent, "..", 2, filp->f_pos, ino, DT_DIR) == 0) |
990 | filp->f_pos++; | 857 | filp->f_pos++; |
991 | } | 858 | } |
992 | if ((filp->f_pos > 1) && (filp->f_pos < INT_MAX)) { | 859 | mutex_lock(&sysfs_mutex); |
993 | mutex_lock(&sysfs_mutex); | 860 | for (pos = sysfs_dir_pos(parent_sd, filp->f_pos, pos); |
994 | 861 | pos; | |
995 | /* Skip the dentries we have already reported */ | 862 | pos = sysfs_dir_next_pos(parent_sd, filp->f_pos, pos)) { |
996 | pos = parent_sd->s_dir.children; | 863 | const char * name; |
997 | while (pos && (filp->f_pos > pos->s_ino)) | 864 | unsigned int type; |
998 | pos = pos->s_sibling; | 865 | int len, ret; |
999 | 866 | ||
1000 | for ( ; pos; pos = pos->s_sibling) { | 867 | name = pos->s_name; |
1001 | const char * name; | 868 | len = strlen(name); |
1002 | int len; | 869 | ino = pos->s_ino; |
1003 | 870 | type = dt_type(pos); | |
1004 | name = pos->s_name; | 871 | filp->f_pos = ino; |
1005 | len = strlen(name); | 872 | filp->private_data = sysfs_get(pos); |
1006 | filp->f_pos = ino = pos->s_ino; | ||
1007 | 873 | ||
1008 | if (filldir(dirent, name, len, filp->f_pos, ino, | ||
1009 | dt_type(pos)) < 0) | ||
1010 | break; | ||
1011 | } | ||
1012 | if (!pos) | ||
1013 | filp->f_pos = INT_MAX; | ||
1014 | mutex_unlock(&sysfs_mutex); | 874 | mutex_unlock(&sysfs_mutex); |
875 | ret = filldir(dirent, name, len, filp->f_pos, ino, type); | ||
876 | mutex_lock(&sysfs_mutex); | ||
877 | if (ret < 0) | ||
878 | break; | ||
879 | } | ||
880 | mutex_unlock(&sysfs_mutex); | ||
881 | if ((filp->f_pos > 1) && !pos) { /* EOF */ | ||
882 | filp->f_pos = INT_MAX; | ||
883 | filp->private_data = NULL; | ||
1015 | } | 884 | } |
1016 | return 0; | 885 | return 0; |
1017 | } | 886 | } |
@@ -1020,5 +889,6 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
1020 | const struct file_operations sysfs_dir_operations = { | 889 | const struct file_operations sysfs_dir_operations = { |
1021 | .read = generic_read_dir, | 890 | .read = generic_read_dir, |
1022 | .readdir = sysfs_readdir, | 891 | .readdir = sysfs_readdir, |
892 | .release = sysfs_dir_release, | ||
1023 | .llseek = generic_file_llseek, | 893 | .llseek = generic_file_llseek, |
1024 | }; | 894 | }; |
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index f5ea4680f15f..e222b2582746 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
@@ -53,7 +53,7 @@ struct sysfs_buffer { | |||
53 | size_t count; | 53 | size_t count; |
54 | loff_t pos; | 54 | loff_t pos; |
55 | char * page; | 55 | char * page; |
56 | struct sysfs_ops * ops; | 56 | const struct sysfs_ops * ops; |
57 | struct mutex mutex; | 57 | struct mutex mutex; |
58 | int needs_read_fill; | 58 | int needs_read_fill; |
59 | int event; | 59 | int event; |
@@ -75,7 +75,7 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer | |||
75 | { | 75 | { |
76 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; | 76 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; |
77 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; | 77 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; |
78 | struct sysfs_ops * ops = buffer->ops; | 78 | const struct sysfs_ops * ops = buffer->ops; |
79 | int ret = 0; | 79 | int ret = 0; |
80 | ssize_t count; | 80 | ssize_t count; |
81 | 81 | ||
@@ -85,13 +85,13 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer | |||
85 | return -ENOMEM; | 85 | return -ENOMEM; |
86 | 86 | ||
87 | /* need attr_sd for attr and ops, its parent for kobj */ | 87 | /* need attr_sd for attr and ops, its parent for kobj */ |
88 | if (!sysfs_get_active_two(attr_sd)) | 88 | if (!sysfs_get_active(attr_sd)) |
89 | return -ENODEV; | 89 | return -ENODEV; |
90 | 90 | ||
91 | buffer->event = atomic_read(&attr_sd->s_attr.open->event); | 91 | buffer->event = atomic_read(&attr_sd->s_attr.open->event); |
92 | count = ops->show(kobj, attr_sd->s_attr.attr, buffer->page); | 92 | count = ops->show(kobj, attr_sd->s_attr.attr, buffer->page); |
93 | 93 | ||
94 | sysfs_put_active_two(attr_sd); | 94 | sysfs_put_active(attr_sd); |
95 | 95 | ||
96 | /* | 96 | /* |
97 | * The code works fine with PAGE_SIZE return but it's likely to | 97 | * The code works fine with PAGE_SIZE return but it's likely to |
@@ -199,16 +199,16 @@ flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t | |||
199 | { | 199 | { |
200 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; | 200 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; |
201 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; | 201 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; |
202 | struct sysfs_ops * ops = buffer->ops; | 202 | const struct sysfs_ops * ops = buffer->ops; |
203 | int rc; | 203 | int rc; |
204 | 204 | ||
205 | /* need attr_sd for attr and ops, its parent for kobj */ | 205 | /* need attr_sd for attr and ops, its parent for kobj */ |
206 | if (!sysfs_get_active_two(attr_sd)) | 206 | if (!sysfs_get_active(attr_sd)) |
207 | return -ENODEV; | 207 | return -ENODEV; |
208 | 208 | ||
209 | rc = ops->store(kobj, attr_sd->s_attr.attr, buffer->page, count); | 209 | rc = ops->store(kobj, attr_sd->s_attr.attr, buffer->page, count); |
210 | 210 | ||
211 | sysfs_put_active_two(attr_sd); | 211 | sysfs_put_active(attr_sd); |
212 | 212 | ||
213 | return rc; | 213 | return rc; |
214 | } | 214 | } |
@@ -335,7 +335,7 @@ static int sysfs_open_file(struct inode *inode, struct file *file) | |||
335 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; | 335 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; |
336 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; | 336 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; |
337 | struct sysfs_buffer *buffer; | 337 | struct sysfs_buffer *buffer; |
338 | struct sysfs_ops *ops; | 338 | const struct sysfs_ops *ops; |
339 | int error = -EACCES; | 339 | int error = -EACCES; |
340 | char *p; | 340 | char *p; |
341 | 341 | ||
@@ -344,7 +344,7 @@ static int sysfs_open_file(struct inode *inode, struct file *file) | |||
344 | memmove(last_sysfs_file, p, strlen(p) + 1); | 344 | memmove(last_sysfs_file, p, strlen(p) + 1); |
345 | 345 | ||
346 | /* need attr_sd for attr and ops, its parent for kobj */ | 346 | /* need attr_sd for attr and ops, its parent for kobj */ |
347 | if (!sysfs_get_active_two(attr_sd)) | 347 | if (!sysfs_get_active(attr_sd)) |
348 | return -ENODEV; | 348 | return -ENODEV; |
349 | 349 | ||
350 | /* every kobject with an attribute needs a ktype assigned */ | 350 | /* every kobject with an attribute needs a ktype assigned */ |
@@ -393,13 +393,13 @@ static int sysfs_open_file(struct inode *inode, struct file *file) | |||
393 | goto err_free; | 393 | goto err_free; |
394 | 394 | ||
395 | /* open succeeded, put active references */ | 395 | /* open succeeded, put active references */ |
396 | sysfs_put_active_two(attr_sd); | 396 | sysfs_put_active(attr_sd); |
397 | return 0; | 397 | return 0; |
398 | 398 | ||
399 | err_free: | 399 | err_free: |
400 | kfree(buffer); | 400 | kfree(buffer); |
401 | err_out: | 401 | err_out: |
402 | sysfs_put_active_two(attr_sd); | 402 | sysfs_put_active(attr_sd); |
403 | return error; | 403 | return error; |
404 | } | 404 | } |
405 | 405 | ||
@@ -437,12 +437,12 @@ static unsigned int sysfs_poll(struct file *filp, poll_table *wait) | |||
437 | struct sysfs_open_dirent *od = attr_sd->s_attr.open; | 437 | struct sysfs_open_dirent *od = attr_sd->s_attr.open; |
438 | 438 | ||
439 | /* need parent for the kobj, grab both */ | 439 | /* need parent for the kobj, grab both */ |
440 | if (!sysfs_get_active_two(attr_sd)) | 440 | if (!sysfs_get_active(attr_sd)) |
441 | goto trigger; | 441 | goto trigger; |
442 | 442 | ||
443 | poll_wait(filp, &od->poll, wait); | 443 | poll_wait(filp, &od->poll, wait); |
444 | 444 | ||
445 | sysfs_put_active_two(attr_sd); | 445 | sysfs_put_active(attr_sd); |
446 | 446 | ||
447 | if (buffer->event != atomic_read(&od->event)) | 447 | if (buffer->event != atomic_read(&od->event)) |
448 | goto trigger; | 448 | goto trigger; |
@@ -509,6 +509,7 @@ int sysfs_add_file_mode(struct sysfs_dirent *dir_sd, | |||
509 | if (!sd) | 509 | if (!sd) |
510 | return -ENOMEM; | 510 | return -ENOMEM; |
511 | sd->s_attr.attr = (void *)attr; | 511 | sd->s_attr.attr = (void *)attr; |
512 | sysfs_dirent_init_lockdep(sd); | ||
512 | 513 | ||
513 | sysfs_addrm_start(&acxt, dir_sd); | 514 | sysfs_addrm_start(&acxt, dir_sd); |
514 | rc = sysfs_add_one(&acxt, sd); | 515 | rc = sysfs_add_one(&acxt, sd); |
@@ -542,6 +543,18 @@ int sysfs_create_file(struct kobject * kobj, const struct attribute * attr) | |||
542 | 543 | ||
543 | } | 544 | } |
544 | 545 | ||
546 | int sysfs_create_files(struct kobject *kobj, const struct attribute **ptr) | ||
547 | { | ||
548 | int err = 0; | ||
549 | int i; | ||
550 | |||
551 | for (i = 0; ptr[i] && !err; i++) | ||
552 | err = sysfs_create_file(kobj, ptr[i]); | ||
553 | if (err) | ||
554 | while (--i >= 0) | ||
555 | sysfs_remove_file(kobj, ptr[i]); | ||
556 | return err; | ||
557 | } | ||
545 | 558 | ||
546 | /** | 559 | /** |
547 | * sysfs_add_file_to_group - add an attribute file to a pre-existing group. | 560 | * sysfs_add_file_to_group - add an attribute file to a pre-existing group. |
@@ -579,46 +592,23 @@ EXPORT_SYMBOL_GPL(sysfs_add_file_to_group); | |||
579 | */ | 592 | */ |
580 | int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) | 593 | int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) |
581 | { | 594 | { |
582 | struct sysfs_dirent *victim_sd = NULL; | 595 | struct sysfs_dirent *sd; |
583 | struct dentry *victim = NULL; | ||
584 | struct inode * inode; | ||
585 | struct iattr newattrs; | 596 | struct iattr newattrs; |
586 | int rc; | 597 | int rc; |
587 | 598 | ||
588 | rc = -ENOENT; | 599 | mutex_lock(&sysfs_mutex); |
589 | victim_sd = sysfs_get_dirent(kobj->sd, attr->name); | ||
590 | if (!victim_sd) | ||
591 | goto out; | ||
592 | 600 | ||
593 | mutex_lock(&sysfs_rename_mutex); | 601 | rc = -ENOENT; |
594 | victim = sysfs_get_dentry(victim_sd); | 602 | sd = sysfs_find_dirent(kobj->sd, attr->name); |
595 | mutex_unlock(&sysfs_rename_mutex); | 603 | if (!sd) |
596 | if (IS_ERR(victim)) { | ||
597 | rc = PTR_ERR(victim); | ||
598 | victim = NULL; | ||
599 | goto out; | 604 | goto out; |
600 | } | ||
601 | |||
602 | inode = victim->d_inode; | ||
603 | |||
604 | mutex_lock(&inode->i_mutex); | ||
605 | |||
606 | newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); | ||
607 | newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; | ||
608 | newattrs.ia_ctime = current_fs_time(inode->i_sb); | ||
609 | rc = sysfs_setattr(victim, &newattrs); | ||
610 | 605 | ||
611 | if (rc == 0) { | 606 | newattrs.ia_mode = (mode & S_IALLUGO) | (sd->s_mode & ~S_IALLUGO); |
612 | fsnotify_change(victim, newattrs.ia_valid); | 607 | newattrs.ia_valid = ATTR_MODE; |
613 | mutex_lock(&sysfs_mutex); | 608 | rc = sysfs_sd_setattr(sd, &newattrs); |
614 | victim_sd->s_mode = newattrs.ia_mode; | ||
615 | mutex_unlock(&sysfs_mutex); | ||
616 | } | ||
617 | 609 | ||
618 | mutex_unlock(&inode->i_mutex); | ||
619 | out: | 610 | out: |
620 | dput(victim); | 611 | mutex_unlock(&sysfs_mutex); |
621 | sysfs_put(victim_sd); | ||
622 | return rc; | 612 | return rc; |
623 | } | 613 | } |
624 | EXPORT_SYMBOL_GPL(sysfs_chmod_file); | 614 | EXPORT_SYMBOL_GPL(sysfs_chmod_file); |
@@ -637,6 +627,12 @@ void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr) | |||
637 | sysfs_hash_and_remove(kobj->sd, attr->name); | 627 | sysfs_hash_and_remove(kobj->sd, attr->name); |
638 | } | 628 | } |
639 | 629 | ||
630 | void sysfs_remove_files(struct kobject * kobj, const struct attribute **ptr) | ||
631 | { | ||
632 | int i; | ||
633 | for (i = 0; ptr[i]; i++) | ||
634 | sysfs_remove_file(kobj, ptr[i]); | ||
635 | } | ||
640 | 636 | ||
641 | /** | 637 | /** |
642 | * sysfs_remove_file_from_group - remove an attribute file from a group. | 638 | * sysfs_remove_file_from_group - remove an attribute file from a group. |
@@ -755,3 +751,5 @@ EXPORT_SYMBOL_GPL(sysfs_schedule_callback); | |||
755 | 751 | ||
756 | EXPORT_SYMBOL_GPL(sysfs_create_file); | 752 | EXPORT_SYMBOL_GPL(sysfs_create_file); |
757 | EXPORT_SYMBOL_GPL(sysfs_remove_file); | 753 | EXPORT_SYMBOL_GPL(sysfs_remove_file); |
754 | EXPORT_SYMBOL_GPL(sysfs_remove_files); | ||
755 | EXPORT_SYMBOL_GPL(sysfs_create_files); | ||
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index e28cecf179f5..a4a0a9419711 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/capability.h> | 18 | #include <linux/capability.h> |
19 | #include <linux/errno.h> | 19 | #include <linux/errno.h> |
20 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
21 | #include <linux/slab.h> | ||
21 | #include <linux/xattr.h> | 22 | #include <linux/xattr.h> |
22 | #include <linux/security.h> | 23 | #include <linux/security.h> |
23 | #include "sysfs.h" | 24 | #include "sysfs.h" |
@@ -37,7 +38,9 @@ static struct backing_dev_info sysfs_backing_dev_info = { | |||
37 | }; | 38 | }; |
38 | 39 | ||
39 | static const struct inode_operations sysfs_inode_operations ={ | 40 | static const struct inode_operations sysfs_inode_operations ={ |
41 | .permission = sysfs_permission, | ||
40 | .setattr = sysfs_setattr, | 42 | .setattr = sysfs_setattr, |
43 | .getattr = sysfs_getattr, | ||
41 | .setxattr = sysfs_setxattr, | 44 | .setxattr = sysfs_setxattr, |
42 | }; | 45 | }; |
43 | 46 | ||
@@ -46,7 +49,7 @@ int __init sysfs_inode_init(void) | |||
46 | return bdi_init(&sysfs_backing_dev_info); | 49 | return bdi_init(&sysfs_backing_dev_info); |
47 | } | 50 | } |
48 | 51 | ||
49 | struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd) | 52 | static struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd) |
50 | { | 53 | { |
51 | struct sysfs_inode_attrs *attrs; | 54 | struct sysfs_inode_attrs *attrs; |
52 | struct iattr *iattrs; | 55 | struct iattr *iattrs; |
@@ -64,81 +67,101 @@ struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd) | |||
64 | 67 | ||
65 | return attrs; | 68 | return attrs; |
66 | } | 69 | } |
67 | int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) | 70 | |
71 | int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr * iattr) | ||
68 | { | 72 | { |
69 | struct inode * inode = dentry->d_inode; | ||
70 | struct sysfs_dirent * sd = dentry->d_fsdata; | ||
71 | struct sysfs_inode_attrs *sd_attrs; | 73 | struct sysfs_inode_attrs *sd_attrs; |
72 | struct iattr *iattrs; | 74 | struct iattr *iattrs; |
73 | unsigned int ia_valid = iattr->ia_valid; | 75 | unsigned int ia_valid = iattr->ia_valid; |
76 | |||
77 | sd_attrs = sd->s_iattr; | ||
78 | |||
79 | if (!sd_attrs) { | ||
80 | /* setting attributes for the first time, allocate now */ | ||
81 | sd_attrs = sysfs_init_inode_attrs(sd); | ||
82 | if (!sd_attrs) | ||
83 | return -ENOMEM; | ||
84 | sd->s_iattr = sd_attrs; | ||
85 | } | ||
86 | /* attributes were changed at least once in past */ | ||
87 | iattrs = &sd_attrs->ia_iattr; | ||
88 | |||
89 | if (ia_valid & ATTR_UID) | ||
90 | iattrs->ia_uid = iattr->ia_uid; | ||
91 | if (ia_valid & ATTR_GID) | ||
92 | iattrs->ia_gid = iattr->ia_gid; | ||
93 | if (ia_valid & ATTR_ATIME) | ||
94 | iattrs->ia_atime = iattr->ia_atime; | ||
95 | if (ia_valid & ATTR_MTIME) | ||
96 | iattrs->ia_mtime = iattr->ia_mtime; | ||
97 | if (ia_valid & ATTR_CTIME) | ||
98 | iattrs->ia_ctime = iattr->ia_ctime; | ||
99 | if (ia_valid & ATTR_MODE) { | ||
100 | umode_t mode = iattr->ia_mode; | ||
101 | iattrs->ia_mode = sd->s_mode = mode; | ||
102 | } | ||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | int sysfs_setattr(struct dentry *dentry, struct iattr *iattr) | ||
107 | { | ||
108 | struct inode *inode = dentry->d_inode; | ||
109 | struct sysfs_dirent *sd = dentry->d_fsdata; | ||
74 | int error; | 110 | int error; |
75 | 111 | ||
76 | if (!sd) | 112 | if (!sd) |
77 | return -EINVAL; | 113 | return -EINVAL; |
78 | 114 | ||
79 | sd_attrs = sd->s_iattr; | 115 | mutex_lock(&sysfs_mutex); |
80 | |||
81 | error = inode_change_ok(inode, iattr); | 116 | error = inode_change_ok(inode, iattr); |
82 | if (error) | 117 | if (error) |
83 | return error; | 118 | goto out; |
84 | 119 | ||
85 | iattr->ia_valid &= ~ATTR_SIZE; /* ignore size changes */ | 120 | iattr->ia_valid &= ~ATTR_SIZE; /* ignore size changes */ |
86 | 121 | ||
87 | error = inode_setattr(inode, iattr); | 122 | error = inode_setattr(inode, iattr); |
88 | if (error) | 123 | if (error) |
89 | return error; | 124 | goto out; |
90 | 125 | ||
91 | if (!sd_attrs) { | 126 | error = sysfs_sd_setattr(sd, iattr); |
92 | /* setting attributes for the first time, allocate now */ | 127 | out: |
93 | sd_attrs = sysfs_init_inode_attrs(sd); | 128 | mutex_unlock(&sysfs_mutex); |
94 | if (!sd_attrs) | ||
95 | return -ENOMEM; | ||
96 | sd->s_iattr = sd_attrs; | ||
97 | } else { | ||
98 | /* attributes were changed at least once in past */ | ||
99 | iattrs = &sd_attrs->ia_iattr; | ||
100 | |||
101 | if (ia_valid & ATTR_UID) | ||
102 | iattrs->ia_uid = iattr->ia_uid; | ||
103 | if (ia_valid & ATTR_GID) | ||
104 | iattrs->ia_gid = iattr->ia_gid; | ||
105 | if (ia_valid & ATTR_ATIME) | ||
106 | iattrs->ia_atime = timespec_trunc(iattr->ia_atime, | ||
107 | inode->i_sb->s_time_gran); | ||
108 | if (ia_valid & ATTR_MTIME) | ||
109 | iattrs->ia_mtime = timespec_trunc(iattr->ia_mtime, | ||
110 | inode->i_sb->s_time_gran); | ||
111 | if (ia_valid & ATTR_CTIME) | ||
112 | iattrs->ia_ctime = timespec_trunc(iattr->ia_ctime, | ||
113 | inode->i_sb->s_time_gran); | ||
114 | if (ia_valid & ATTR_MODE) { | ||
115 | umode_t mode = iattr->ia_mode; | ||
116 | |||
117 | if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) | ||
118 | mode &= ~S_ISGID; | ||
119 | iattrs->ia_mode = sd->s_mode = mode; | ||
120 | } | ||
121 | } | ||
122 | return error; | 129 | return error; |
123 | } | 130 | } |
124 | 131 | ||
132 | static int sysfs_sd_setsecdata(struct sysfs_dirent *sd, void **secdata, u32 *secdata_len) | ||
133 | { | ||
134 | struct sysfs_inode_attrs *iattrs; | ||
135 | void *old_secdata; | ||
136 | size_t old_secdata_len; | ||
137 | |||
138 | iattrs = sd->s_iattr; | ||
139 | if (!iattrs) | ||
140 | iattrs = sysfs_init_inode_attrs(sd); | ||
141 | if (!iattrs) | ||
142 | return -ENOMEM; | ||
143 | |||
144 | old_secdata = iattrs->ia_secdata; | ||
145 | old_secdata_len = iattrs->ia_secdata_len; | ||
146 | |||
147 | iattrs->ia_secdata = *secdata; | ||
148 | iattrs->ia_secdata_len = *secdata_len; | ||
149 | |||
150 | *secdata = old_secdata; | ||
151 | *secdata_len = old_secdata_len; | ||
152 | return 0; | ||
153 | } | ||
154 | |||
125 | int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, | 155 | int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, |
126 | size_t size, int flags) | 156 | size_t size, int flags) |
127 | { | 157 | { |
128 | struct sysfs_dirent *sd = dentry->d_fsdata; | 158 | struct sysfs_dirent *sd = dentry->d_fsdata; |
129 | struct sysfs_inode_attrs *iattrs; | ||
130 | void *secdata; | 159 | void *secdata; |
131 | int error; | 160 | int error; |
132 | u32 secdata_len = 0; | 161 | u32 secdata_len = 0; |
133 | 162 | ||
134 | if (!sd) | 163 | if (!sd) |
135 | return -EINVAL; | 164 | return -EINVAL; |
136 | if (!sd->s_iattr) | ||
137 | sd->s_iattr = sysfs_init_inode_attrs(sd); | ||
138 | if (!sd->s_iattr) | ||
139 | return -ENOMEM; | ||
140 | |||
141 | iattrs = sd->s_iattr; | ||
142 | 165 | ||
143 | if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN)) { | 166 | if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN)) { |
144 | const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; | 167 | const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; |
@@ -150,12 +173,13 @@ int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, | |||
150 | &secdata, &secdata_len); | 173 | &secdata, &secdata_len); |
151 | if (error) | 174 | if (error) |
152 | goto out; | 175 | goto out; |
153 | if (iattrs->ia_secdata) | ||
154 | security_release_secctx(iattrs->ia_secdata, | ||
155 | iattrs->ia_secdata_len); | ||
156 | iattrs->ia_secdata = secdata; | ||
157 | iattrs->ia_secdata_len = secdata_len; | ||
158 | 176 | ||
177 | mutex_lock(&sysfs_mutex); | ||
178 | error = sysfs_sd_setsecdata(sd, &secdata, &secdata_len); | ||
179 | mutex_unlock(&sysfs_mutex); | ||
180 | |||
181 | if (secdata) | ||
182 | security_release_secctx(secdata, secdata_len); | ||
159 | } else | 183 | } else |
160 | return -EINVAL; | 184 | return -EINVAL; |
161 | out: | 185 | out: |
@@ -170,7 +194,6 @@ static inline void set_default_inode_attr(struct inode * inode, mode_t mode) | |||
170 | 194 | ||
171 | static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) | 195 | static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) |
172 | { | 196 | { |
173 | inode->i_mode = iattr->ia_mode; | ||
174 | inode->i_uid = iattr->ia_uid; | 197 | inode->i_uid = iattr->ia_uid; |
175 | inode->i_gid = iattr->ia_gid; | 198 | inode->i_gid = iattr->ia_gid; |
176 | inode->i_atime = iattr->ia_atime; | 199 | inode->i_atime = iattr->ia_atime; |
@@ -178,17 +201,6 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) | |||
178 | inode->i_ctime = iattr->ia_ctime; | 201 | inode->i_ctime = iattr->ia_ctime; |
179 | } | 202 | } |
180 | 203 | ||
181 | |||
182 | /* | ||
183 | * sysfs has a different i_mutex lock order behavior for i_mutex than other | ||
184 | * filesystems; sysfs i_mutex is called in many places with subsystem locks | ||
185 | * held. At the same time, many of the VFS locking rules do not apply to | ||
186 | * sysfs at all (cross directory rename for example). To untangle this mess | ||
187 | * (which gives false positives in lockdep), we're giving sysfs inodes their | ||
188 | * own class for i_mutex. | ||
189 | */ | ||
190 | static struct lock_class_key sysfs_inode_imutex_key; | ||
191 | |||
192 | static int sysfs_count_nlink(struct sysfs_dirent *sd) | 204 | static int sysfs_count_nlink(struct sysfs_dirent *sd) |
193 | { | 205 | { |
194 | struct sysfs_dirent *child; | 206 | struct sysfs_dirent *child; |
@@ -201,38 +213,55 @@ static int sysfs_count_nlink(struct sysfs_dirent *sd) | |||
201 | return nr + 2; | 213 | return nr + 2; |
202 | } | 214 | } |
203 | 215 | ||
216 | static void sysfs_refresh_inode(struct sysfs_dirent *sd, struct inode *inode) | ||
217 | { | ||
218 | struct sysfs_inode_attrs *iattrs = sd->s_iattr; | ||
219 | |||
220 | inode->i_mode = sd->s_mode; | ||
221 | if (iattrs) { | ||
222 | /* sysfs_dirent has non-default attributes | ||
223 | * get them from persistent copy in sysfs_dirent | ||
224 | */ | ||
225 | set_inode_attr(inode, &iattrs->ia_iattr); | ||
226 | security_inode_notifysecctx(inode, | ||
227 | iattrs->ia_secdata, | ||
228 | iattrs->ia_secdata_len); | ||
229 | } | ||
230 | |||
231 | if (sysfs_type(sd) == SYSFS_DIR) | ||
232 | inode->i_nlink = sysfs_count_nlink(sd); | ||
233 | } | ||
234 | |||
235 | int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | ||
236 | { | ||
237 | struct sysfs_dirent *sd = dentry->d_fsdata; | ||
238 | struct inode *inode = dentry->d_inode; | ||
239 | |||
240 | mutex_lock(&sysfs_mutex); | ||
241 | sysfs_refresh_inode(sd, inode); | ||
242 | mutex_unlock(&sysfs_mutex); | ||
243 | |||
244 | generic_fillattr(inode, stat); | ||
245 | return 0; | ||
246 | } | ||
247 | |||
204 | static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) | 248 | static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) |
205 | { | 249 | { |
206 | struct bin_attribute *bin_attr; | 250 | struct bin_attribute *bin_attr; |
207 | struct sysfs_inode_attrs *iattrs; | ||
208 | 251 | ||
209 | inode->i_private = sysfs_get(sd); | 252 | inode->i_private = sysfs_get(sd); |
210 | inode->i_mapping->a_ops = &sysfs_aops; | 253 | inode->i_mapping->a_ops = &sysfs_aops; |
211 | inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; | 254 | inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; |
212 | inode->i_op = &sysfs_inode_operations; | 255 | inode->i_op = &sysfs_inode_operations; |
213 | inode->i_ino = sd->s_ino; | ||
214 | lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key); | ||
215 | 256 | ||
216 | iattrs = sd->s_iattr; | 257 | set_default_inode_attr(inode, sd->s_mode); |
217 | if (iattrs) { | 258 | sysfs_refresh_inode(sd, inode); |
218 | /* sysfs_dirent has non-default attributes | ||
219 | * get them for the new inode from persistent copy | ||
220 | * in sysfs_dirent | ||
221 | */ | ||
222 | set_inode_attr(inode, &iattrs->ia_iattr); | ||
223 | if (iattrs->ia_secdata) | ||
224 | security_inode_notifysecctx(inode, | ||
225 | iattrs->ia_secdata, | ||
226 | iattrs->ia_secdata_len); | ||
227 | } else | ||
228 | set_default_inode_attr(inode, sd->s_mode); | ||
229 | 259 | ||
230 | /* initialize inode according to type */ | 260 | /* initialize inode according to type */ |
231 | switch (sysfs_type(sd)) { | 261 | switch (sysfs_type(sd)) { |
232 | case SYSFS_DIR: | 262 | case SYSFS_DIR: |
233 | inode->i_op = &sysfs_dir_inode_operations; | 263 | inode->i_op = &sysfs_dir_inode_operations; |
234 | inode->i_fop = &sysfs_dir_operations; | 264 | inode->i_fop = &sysfs_dir_operations; |
235 | inode->i_nlink = sysfs_count_nlink(sd); | ||
236 | break; | 265 | break; |
237 | case SYSFS_KOBJ_ATTR: | 266 | case SYSFS_KOBJ_ATTR: |
238 | inode->i_size = PAGE_SIZE; | 267 | inode->i_size = PAGE_SIZE; |
@@ -255,6 +284,7 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) | |||
255 | 284 | ||
256 | /** | 285 | /** |
257 | * sysfs_get_inode - get inode for sysfs_dirent | 286 | * sysfs_get_inode - get inode for sysfs_dirent |
287 | * @sb: super block | ||
258 | * @sd: sysfs_dirent to allocate inode for | 288 | * @sd: sysfs_dirent to allocate inode for |
259 | * | 289 | * |
260 | * Get inode for @sd. If such inode doesn't exist, a new inode | 290 | * Get inode for @sd. If such inode doesn't exist, a new inode |
@@ -267,11 +297,11 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) | |||
267 | * RETURNS: | 297 | * RETURNS: |
268 | * Pointer to allocated inode on success, NULL on failure. | 298 | * Pointer to allocated inode on success, NULL on failure. |
269 | */ | 299 | */ |
270 | struct inode * sysfs_get_inode(struct sysfs_dirent *sd) | 300 | struct inode * sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd) |
271 | { | 301 | { |
272 | struct inode *inode; | 302 | struct inode *inode; |
273 | 303 | ||
274 | inode = iget_locked(sysfs_sb, sd->s_ino); | 304 | inode = iget_locked(sb, sd->s_ino); |
275 | if (inode && (inode->i_state & I_NEW)) | 305 | if (inode && (inode->i_state & I_NEW)) |
276 | sysfs_init_inode(sd, inode); | 306 | sysfs_init_inode(sd, inode); |
277 | 307 | ||
@@ -315,3 +345,14 @@ int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) | |||
315 | else | 345 | else |
316 | return -ENOENT; | 346 | return -ENOENT; |
317 | } | 347 | } |
348 | |||
349 | int sysfs_permission(struct inode *inode, int mask) | ||
350 | { | ||
351 | struct sysfs_dirent *sd = inode->i_private; | ||
352 | |||
353 | mutex_lock(&sysfs_mutex); | ||
354 | sysfs_refresh_inode(sd, inode); | ||
355 | mutex_unlock(&sysfs_mutex); | ||
356 | |||
357 | return generic_permission(inode, mask, NULL); | ||
358 | } | ||
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 49749955ccaf..776137828dca 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c | |||
@@ -18,12 +18,12 @@ | |||
18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/magic.h> | 20 | #include <linux/magic.h> |
21 | #include <linux/slab.h> | ||
21 | 22 | ||
22 | #include "sysfs.h" | 23 | #include "sysfs.h" |
23 | 24 | ||
24 | 25 | ||
25 | static struct vfsmount *sysfs_mount; | 26 | static struct vfsmount *sysfs_mount; |
26 | struct super_block * sysfs_sb = NULL; | ||
27 | struct kmem_cache *sysfs_dir_cachep; | 27 | struct kmem_cache *sysfs_dir_cachep; |
28 | 28 | ||
29 | static const struct super_operations sysfs_ops = { | 29 | static const struct super_operations sysfs_ops = { |
@@ -50,11 +50,10 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) | |||
50 | sb->s_magic = SYSFS_MAGIC; | 50 | sb->s_magic = SYSFS_MAGIC; |
51 | sb->s_op = &sysfs_ops; | 51 | sb->s_op = &sysfs_ops; |
52 | sb->s_time_gran = 1; | 52 | sb->s_time_gran = 1; |
53 | sysfs_sb = sb; | ||
54 | 53 | ||
55 | /* get root inode, initialize and unlock it */ | 54 | /* get root inode, initialize and unlock it */ |
56 | mutex_lock(&sysfs_mutex); | 55 | mutex_lock(&sysfs_mutex); |
57 | inode = sysfs_get_inode(&sysfs_root); | 56 | inode = sysfs_get_inode(sb, &sysfs_root); |
58 | mutex_unlock(&sysfs_mutex); | 57 | mutex_unlock(&sysfs_mutex); |
59 | if (!inode) { | 58 | if (!inode) { |
60 | pr_debug("sysfs: could not get root inode\n"); | 59 | pr_debug("sysfs: could not get root inode\n"); |
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index c5081ad77026..b93ec51fa7ac 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c | |||
@@ -11,6 +11,7 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/fs.h> | 13 | #include <linux/fs.h> |
14 | #include <linux/gfp.h> | ||
14 | #include <linux/mount.h> | 15 | #include <linux/mount.h> |
15 | #include <linux/module.h> | 16 | #include <linux/module.h> |
16 | #include <linux/kobject.h> | 17 | #include <linux/kobject.h> |
@@ -123,6 +124,44 @@ void sysfs_remove_link(struct kobject * kobj, const char * name) | |||
123 | sysfs_hash_and_remove(parent_sd, name); | 124 | sysfs_hash_and_remove(parent_sd, name); |
124 | } | 125 | } |
125 | 126 | ||
127 | /** | ||
128 | * sysfs_rename_link - rename symlink in object's directory. | ||
129 | * @kobj: object we're acting for. | ||
130 | * @targ: object we're pointing to. | ||
131 | * @old: previous name of the symlink. | ||
132 | * @new: new name of the symlink. | ||
133 | * | ||
134 | * A helper function for the common rename symlink idiom. | ||
135 | */ | ||
136 | int sysfs_rename_link(struct kobject *kobj, struct kobject *targ, | ||
137 | const char *old, const char *new) | ||
138 | { | ||
139 | struct sysfs_dirent *parent_sd, *sd = NULL; | ||
140 | int result; | ||
141 | |||
142 | if (!kobj) | ||
143 | parent_sd = &sysfs_root; | ||
144 | else | ||
145 | parent_sd = kobj->sd; | ||
146 | |||
147 | result = -ENOENT; | ||
148 | sd = sysfs_get_dirent(parent_sd, old); | ||
149 | if (!sd) | ||
150 | goto out; | ||
151 | |||
152 | result = -EINVAL; | ||
153 | if (sysfs_type(sd) != SYSFS_KOBJ_LINK) | ||
154 | goto out; | ||
155 | if (sd->s_symlink.target_sd->s_dir.kobj != targ) | ||
156 | goto out; | ||
157 | |||
158 | result = sysfs_rename(sd, parent_sd, new); | ||
159 | |||
160 | out: | ||
161 | sysfs_put(sd); | ||
162 | return result; | ||
163 | } | ||
164 | |||
126 | static int sysfs_get_target_path(struct sysfs_dirent *parent_sd, | 165 | static int sysfs_get_target_path(struct sysfs_dirent *parent_sd, |
127 | struct sysfs_dirent *target_sd, char *path) | 166 | struct sysfs_dirent *target_sd, char *path) |
128 | { | 167 | { |
@@ -210,10 +249,13 @@ static void sysfs_put_link(struct dentry *dentry, struct nameidata *nd, void *co | |||
210 | } | 249 | } |
211 | 250 | ||
212 | const struct inode_operations sysfs_symlink_inode_operations = { | 251 | const struct inode_operations sysfs_symlink_inode_operations = { |
213 | .setxattr = sysfs_setxattr, | 252 | .setxattr = sysfs_setxattr, |
214 | .readlink = generic_readlink, | 253 | .readlink = generic_readlink, |
215 | .follow_link = sysfs_follow_link, | 254 | .follow_link = sysfs_follow_link, |
216 | .put_link = sysfs_put_link, | 255 | .put_link = sysfs_put_link, |
256 | .setattr = sysfs_setattr, | ||
257 | .getattr = sysfs_getattr, | ||
258 | .permission = sysfs_permission, | ||
217 | }; | 259 | }; |
218 | 260 | ||
219 | 261 | ||
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index af4c4e7482ac..30f5a44fb5d3 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h | |||
@@ -8,6 +8,7 @@ | |||
8 | * This file is released under the GPLv2. | 8 | * This file is released under the GPLv2. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/lockdep.h> | ||
11 | #include <linux/fs.h> | 12 | #include <linux/fs.h> |
12 | 13 | ||
13 | struct sysfs_open_dirent; | 14 | struct sysfs_open_dirent; |
@@ -50,6 +51,9 @@ struct sysfs_inode_attrs { | |||
50 | struct sysfs_dirent { | 51 | struct sysfs_dirent { |
51 | atomic_t s_count; | 52 | atomic_t s_count; |
52 | atomic_t s_active; | 53 | atomic_t s_active; |
54 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
55 | struct lockdep_map dep_map; | ||
56 | #endif | ||
53 | struct sysfs_dirent *s_parent; | 57 | struct sysfs_dirent *s_parent; |
54 | struct sysfs_dirent *s_sibling; | 58 | struct sysfs_dirent *s_sibling; |
55 | const char *s_name; | 59 | const char *s_name; |
@@ -62,8 +66,8 @@ struct sysfs_dirent { | |||
62 | }; | 66 | }; |
63 | 67 | ||
64 | unsigned int s_flags; | 68 | unsigned int s_flags; |
69 | unsigned short s_mode; | ||
65 | ino_t s_ino; | 70 | ino_t s_ino; |
66 | umode_t s_mode; | ||
67 | struct sysfs_inode_attrs *s_iattr; | 71 | struct sysfs_inode_attrs *s_iattr; |
68 | }; | 72 | }; |
69 | 73 | ||
@@ -75,6 +79,7 @@ struct sysfs_dirent { | |||
75 | #define SYSFS_KOBJ_BIN_ATTR 0x0004 | 79 | #define SYSFS_KOBJ_BIN_ATTR 0x0004 |
76 | #define SYSFS_KOBJ_LINK 0x0008 | 80 | #define SYSFS_KOBJ_LINK 0x0008 |
77 | #define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) | 81 | #define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) |
82 | #define SYSFS_ACTIVE_REF (SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR) | ||
78 | 83 | ||
79 | #define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK | 84 | #define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK |
80 | #define SYSFS_FLAG_REMOVED 0x0200 | 85 | #define SYSFS_FLAG_REMOVED 0x0200 |
@@ -84,36 +89,46 @@ static inline unsigned int sysfs_type(struct sysfs_dirent *sd) | |||
84 | return sd->s_flags & SYSFS_TYPE_MASK; | 89 | return sd->s_flags & SYSFS_TYPE_MASK; |
85 | } | 90 | } |
86 | 91 | ||
92 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
93 | #define sysfs_dirent_init_lockdep(sd) \ | ||
94 | do { \ | ||
95 | struct attribute *attr = sd->s_attr.attr; \ | ||
96 | struct lock_class_key *key = attr->key; \ | ||
97 | if (!key) \ | ||
98 | key = &attr->skey; \ | ||
99 | \ | ||
100 | lockdep_init_map(&sd->dep_map, "s_active", key, 0); \ | ||
101 | } while(0) | ||
102 | #else | ||
103 | #define sysfs_dirent_init_lockdep(sd) do {} while(0) | ||
104 | #endif | ||
105 | |||
87 | /* | 106 | /* |
88 | * Context structure to be used while adding/removing nodes. | 107 | * Context structure to be used while adding/removing nodes. |
89 | */ | 108 | */ |
90 | struct sysfs_addrm_cxt { | 109 | struct sysfs_addrm_cxt { |
91 | struct sysfs_dirent *parent_sd; | 110 | struct sysfs_dirent *parent_sd; |
92 | struct inode *parent_inode; | ||
93 | struct sysfs_dirent *removed; | 111 | struct sysfs_dirent *removed; |
94 | int cnt; | ||
95 | }; | 112 | }; |
96 | 113 | ||
97 | /* | 114 | /* |
98 | * mount.c | 115 | * mount.c |
99 | */ | 116 | */ |
100 | extern struct sysfs_dirent sysfs_root; | 117 | extern struct sysfs_dirent sysfs_root; |
101 | extern struct super_block *sysfs_sb; | ||
102 | extern struct kmem_cache *sysfs_dir_cachep; | 118 | extern struct kmem_cache *sysfs_dir_cachep; |
103 | 119 | ||
104 | /* | 120 | /* |
105 | * dir.c | 121 | * dir.c |
106 | */ | 122 | */ |
107 | extern struct mutex sysfs_mutex; | 123 | extern struct mutex sysfs_mutex; |
108 | extern struct mutex sysfs_rename_mutex; | ||
109 | extern spinlock_t sysfs_assoc_lock; | 124 | extern spinlock_t sysfs_assoc_lock; |
110 | 125 | ||
111 | extern const struct file_operations sysfs_dir_operations; | 126 | extern const struct file_operations sysfs_dir_operations; |
112 | extern const struct inode_operations sysfs_dir_inode_operations; | 127 | extern const struct inode_operations sysfs_dir_inode_operations; |
113 | 128 | ||
114 | struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd); | 129 | struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd); |
115 | struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd); | 130 | struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd); |
116 | void sysfs_put_active_two(struct sysfs_dirent *sd); | 131 | void sysfs_put_active(struct sysfs_dirent *sd); |
117 | void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, | 132 | void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, |
118 | struct sysfs_dirent *parent_sd); | 133 | struct sysfs_dirent *parent_sd); |
119 | int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd); | 134 | int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd); |
@@ -133,6 +148,9 @@ int sysfs_create_subdir(struct kobject *kobj, const char *name, | |||
133 | struct sysfs_dirent **p_sd); | 148 | struct sysfs_dirent **p_sd); |
134 | void sysfs_remove_subdir(struct sysfs_dirent *sd); | 149 | void sysfs_remove_subdir(struct sysfs_dirent *sd); |
135 | 150 | ||
151 | int sysfs_rename(struct sysfs_dirent *sd, | ||
152 | struct sysfs_dirent *new_parent_sd, const char *new_name); | ||
153 | |||
136 | static inline struct sysfs_dirent *__sysfs_get(struct sysfs_dirent *sd) | 154 | static inline struct sysfs_dirent *__sysfs_get(struct sysfs_dirent *sd) |
137 | { | 155 | { |
138 | if (sd) { | 156 | if (sd) { |
@@ -153,9 +171,12 @@ static inline void __sysfs_put(struct sysfs_dirent *sd) | |||
153 | /* | 171 | /* |
154 | * inode.c | 172 | * inode.c |
155 | */ | 173 | */ |
156 | struct inode *sysfs_get_inode(struct sysfs_dirent *sd); | 174 | struct inode *sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd); |
157 | void sysfs_delete_inode(struct inode *inode); | 175 | void sysfs_delete_inode(struct inode *inode); |
176 | int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr *iattr); | ||
177 | int sysfs_permission(struct inode *inode, int mask); | ||
158 | int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); | 178 | int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); |
179 | int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); | ||
159 | int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, | 180 | int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, |
160 | size_t size, int flags); | 181 | size_t size, int flags); |
161 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name); | 182 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name); |