aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/sysfs/dir.c56
-rw-r--r--fs/sysfs/inode.c56
-rw-r--r--fs/sysfs/sysfs.h1
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 */
451static 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 */
214void 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
256int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) 200int 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);
91extern void sysfs_remove_subdir(struct sysfs_dirent *sd); 91extern void sysfs_remove_subdir(struct sysfs_dirent *sd);
92 92
93extern void sysfs_drop_dentry(struct sysfs_dirent *sd);
94extern int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); 93extern int sysfs_setattr(struct dentry *dentry, struct iattr *iattr);
95 94
96extern spinlock_t sysfs_assoc_lock; 95extern spinlock_t sysfs_assoc_lock;