diff options
-rw-r--r-- | fs/sysfs/dir.c | 56 | ||||
-rw-r--r-- | fs/sysfs/inode.c | 56 | ||||
-rw-r--r-- | fs/sysfs/sysfs.h | 1 |
3 files changed, 56 insertions, 57 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index edb30621b82f..c6f3b697064c 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
@@ -435,6 +435,62 @@ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | |||
435 | } | 435 | } |
436 | 436 | ||
437 | /** | 437 | /** |
438 | * sysfs_drop_dentry - drop dentry for the specified sysfs_dirent | ||
439 | * @sd: target sysfs_dirent | ||
440 | * | ||
441 | * Drop dentry for @sd. @sd must have been unlinked from its | ||
442 | * parent on entry to this function such that it can't be looked | ||
443 | * up anymore. | ||
444 | * | ||
445 | * @sd->s_dentry which is protected with sysfs_assoc_lock points | ||
446 | * to the currently associated dentry but we're not holding a | ||
447 | * reference to it and racing with dput(). Grab dcache_lock and | ||
448 | * verify dentry before dropping it. If @sd->s_dentry is NULL or | ||
449 | * dput() beats us, no need to bother. | ||
450 | */ | ||
451 | static void sysfs_drop_dentry(struct sysfs_dirent *sd) | ||
452 | { | ||
453 | struct dentry *dentry = NULL; | ||
454 | struct inode *inode; | ||
455 | |||
456 | /* We're not holding a reference to ->s_dentry dentry but the | ||
457 | * field will stay valid as long as sysfs_assoc_lock is held. | ||
458 | */ | ||
459 | spin_lock(&sysfs_assoc_lock); | ||
460 | spin_lock(&dcache_lock); | ||
461 | |||
462 | /* drop dentry if it's there and dput() didn't kill it yet */ | ||
463 | if (sd->s_dentry && sd->s_dentry->d_inode) { | ||
464 | dentry = dget_locked(sd->s_dentry); | ||
465 | spin_lock(&dentry->d_lock); | ||
466 | __d_drop(dentry); | ||
467 | spin_unlock(&dentry->d_lock); | ||
468 | } | ||
469 | |||
470 | spin_unlock(&dcache_lock); | ||
471 | spin_unlock(&sysfs_assoc_lock); | ||
472 | |||
473 | dput(dentry); | ||
474 | /* XXX: unpin if directory, this will go away soon */ | ||
475 | if (sysfs_type(sd) == SYSFS_DIR) | ||
476 | dput(dentry); | ||
477 | |||
478 | /* adjust nlink and update timestamp */ | ||
479 | inode = ilookup(sysfs_sb, sd->s_ino); | ||
480 | if (inode) { | ||
481 | mutex_lock(&inode->i_mutex); | ||
482 | |||
483 | inode->i_ctime = CURRENT_TIME; | ||
484 | drop_nlink(inode); | ||
485 | if (sysfs_type(sd) == SYSFS_DIR) | ||
486 | drop_nlink(inode); | ||
487 | |||
488 | mutex_unlock(&inode->i_mutex); | ||
489 | iput(inode); | ||
490 | } | ||
491 | } | ||
492 | |||
493 | /** | ||
438 | * sysfs_addrm_finish - finish up sysfs_dirent add/remove | 494 | * sysfs_addrm_finish - finish up sysfs_dirent add/remove |
439 | * @acxt: addrm context to finish up | 495 | * @acxt: addrm context to finish up |
440 | * | 496 | * |
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index f95966847a81..3756e152285a 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c | |||
@@ -197,62 +197,6 @@ void sysfs_instantiate(struct dentry *dentry, struct inode *inode) | |||
197 | d_instantiate(dentry, inode); | 197 | d_instantiate(dentry, inode); |
198 | } | 198 | } |
199 | 199 | ||
200 | /** | ||
201 | * sysfs_drop_dentry - drop dentry for the specified sysfs_dirent | ||
202 | * @sd: target sysfs_dirent | ||
203 | * | ||
204 | * Drop dentry for @sd. @sd must have been unlinked from its | ||
205 | * parent on entry to this function such that it can't be looked | ||
206 | * up anymore. | ||
207 | * | ||
208 | * @sd->s_dentry which is protected with sysfs_assoc_lock points | ||
209 | * to the currently associated dentry but we're not holding a | ||
210 | * reference to it and racing with dput(). Grab dcache_lock and | ||
211 | * verify dentry before dropping it. If @sd->s_dentry is NULL or | ||
212 | * dput() beats us, no need to bother. | ||
213 | */ | ||
214 | void sysfs_drop_dentry(struct sysfs_dirent *sd) | ||
215 | { | ||
216 | struct dentry *dentry = NULL; | ||
217 | struct inode *inode; | ||
218 | |||
219 | /* We're not holding a reference to ->s_dentry dentry but the | ||
220 | * field will stay valid as long as sysfs_assoc_lock is held. | ||
221 | */ | ||
222 | spin_lock(&sysfs_assoc_lock); | ||
223 | spin_lock(&dcache_lock); | ||
224 | |||
225 | /* drop dentry if it's there and dput() didn't kill it yet */ | ||
226 | if (sd->s_dentry && sd->s_dentry->d_inode) { | ||
227 | dentry = dget_locked(sd->s_dentry); | ||
228 | spin_lock(&dentry->d_lock); | ||
229 | __d_drop(dentry); | ||
230 | spin_unlock(&dentry->d_lock); | ||
231 | } | ||
232 | |||
233 | spin_unlock(&dcache_lock); | ||
234 | spin_unlock(&sysfs_assoc_lock); | ||
235 | |||
236 | dput(dentry); | ||
237 | /* XXX: unpin if directory, this will go away soon */ | ||
238 | if (sysfs_type(sd) == SYSFS_DIR) | ||
239 | dput(dentry); | ||
240 | |||
241 | /* adjust nlink and update timestamp */ | ||
242 | inode = ilookup(sysfs_sb, sd->s_ino); | ||
243 | if (inode) { | ||
244 | mutex_lock(&inode->i_mutex); | ||
245 | |||
246 | inode->i_ctime = CURRENT_TIME; | ||
247 | drop_nlink(inode); | ||
248 | if (sysfs_type(sd) == SYSFS_DIR) | ||
249 | drop_nlink(inode); | ||
250 | |||
251 | mutex_unlock(&inode->i_mutex); | ||
252 | iput(inode); | ||
253 | } | ||
254 | } | ||
255 | |||
256 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) | 200 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) |
257 | { | 201 | { |
258 | struct sysfs_addrm_cxt acxt; | 202 | struct sysfs_addrm_cxt acxt; |
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 3e9a5ee38233..92fe1e51a29b 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h | |||
@@ -90,7 +90,6 @@ extern int sysfs_create_subdir(struct kobject *kobj, const char *name, | |||
90 | struct sysfs_dirent **p_sd); | 90 | struct sysfs_dirent **p_sd); |
91 | extern void sysfs_remove_subdir(struct sysfs_dirent *sd); | 91 | extern void sysfs_remove_subdir(struct sysfs_dirent *sd); |
92 | 92 | ||
93 | extern void sysfs_drop_dentry(struct sysfs_dirent *sd); | ||
94 | extern int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); | 93 | extern int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); |
95 | 94 | ||
96 | extern spinlock_t sysfs_assoc_lock; | 95 | extern spinlock_t sysfs_assoc_lock; |