aboutsummaryrefslogtreecommitdiffstats
path: root/fs/sysfs/dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/sysfs/dir.c')
-rw-r--r--fs/sysfs/dir.c28
1 files changed, 25 insertions, 3 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 2a94dc36d166..e0d377aaf2cc 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -53,6 +53,19 @@ void release_sysfs_dirent(struct sysfs_dirent * sd)
53 repeat: 53 repeat:
54 parent_sd = sd->s_parent; 54 parent_sd = sd->s_parent;
55 55
56 /* If @sd is being released after deletion, s_active is write
57 * locked. If @sd is cursor for directory walk or being
58 * released prematurely, s_active has no reader or writer.
59 *
60 * sysfs_deactivate() lies to lockdep that s_active is
61 * unlocked immediately. Lie one more time to cover the
62 * previous lie.
63 */
64 if (!down_write_trylock(&sd->s_active))
65 rwsem_acquire(&sd->s_active.dep_map,
66 SYSFS_S_ACTIVE_DEACTIVATE, 0, _RET_IP_);
67 up_write(&sd->s_active);
68
56 if (sd->s_type & SYSFS_KOBJ_LINK) 69 if (sd->s_type & SYSFS_KOBJ_LINK)
57 sysfs_put(sd->s_elem.symlink.target_sd); 70 sysfs_put(sd->s_elem.symlink.target_sd);
58 if (sd->s_type & SYSFS_COPY_NAME) 71 if (sd->s_type & SYSFS_COPY_NAME)
@@ -113,6 +126,7 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
113 126
114 atomic_set(&sd->s_count, 1); 127 atomic_set(&sd->s_count, 1);
115 atomic_set(&sd->s_event, 1); 128 atomic_set(&sd->s_event, 1);
129 init_rwsem(&sd->s_active);
116 INIT_LIST_HEAD(&sd->s_children); 130 INIT_LIST_HEAD(&sd->s_children);
117 INIT_LIST_HEAD(&sd->s_sibling); 131 INIT_LIST_HEAD(&sd->s_sibling);
118 132
@@ -371,7 +385,6 @@ static void remove_dir(struct dentry * d)
371 d_delete(d); 385 d_delete(d);
372 sd = d->d_fsdata; 386 sd = d->d_fsdata;
373 list_del_init(&sd->s_sibling); 387 list_del_init(&sd->s_sibling);
374 sysfs_put(sd);
375 if (d->d_inode) 388 if (d->d_inode)
376 simple_rmdir(parent->d_inode,d); 389 simple_rmdir(parent->d_inode,d);
377 390
@@ -380,6 +393,9 @@ static void remove_dir(struct dentry * d)
380 393
381 mutex_unlock(&parent->d_inode->i_mutex); 394 mutex_unlock(&parent->d_inode->i_mutex);
382 dput(parent); 395 dput(parent);
396
397 sysfs_deactivate(sd);
398 sysfs_put(sd);
383} 399}
384 400
385void sysfs_remove_subdir(struct dentry * d) 401void sysfs_remove_subdir(struct dentry * d)
@@ -390,6 +406,7 @@ void sysfs_remove_subdir(struct dentry * d)
390 406
391static void __sysfs_remove_dir(struct dentry *dentry) 407static void __sysfs_remove_dir(struct dentry *dentry)
392{ 408{
409 LIST_HEAD(removed);
393 struct sysfs_dirent * parent_sd; 410 struct sysfs_dirent * parent_sd;
394 struct sysfs_dirent * sd, * tmp; 411 struct sysfs_dirent * sd, * tmp;
395 412
@@ -403,12 +420,17 @@ static void __sysfs_remove_dir(struct dentry *dentry)
403 list_for_each_entry_safe(sd, tmp, &parent_sd->s_children, s_sibling) { 420 list_for_each_entry_safe(sd, tmp, &parent_sd->s_children, s_sibling) {
404 if (!sd->s_type || !(sd->s_type & SYSFS_NOT_PINNED)) 421 if (!sd->s_type || !(sd->s_type & SYSFS_NOT_PINNED))
405 continue; 422 continue;
406 list_del_init(&sd->s_sibling); 423 list_move(&sd->s_sibling, &removed);
407 sysfs_drop_dentry(sd, dentry); 424 sysfs_drop_dentry(sd, dentry);
408 sysfs_put(sd);
409 } 425 }
410 mutex_unlock(&dentry->d_inode->i_mutex); 426 mutex_unlock(&dentry->d_inode->i_mutex);
411 427
428 list_for_each_entry_safe(sd, tmp, &removed, s_sibling) {
429 list_del_init(&sd->s_sibling);
430 sysfs_deactivate(sd);
431 sysfs_put(sd);
432 }
433
412 remove_dir(dentry); 434 remove_dir(dentry);
413 /** 435 /**
414 * Drop reference from dget() on entrance. 436 * Drop reference from dget() on entrance.