diff options
Diffstat (limited to 'fs/sysfs/dir.c')
-rw-r--r-- | fs/sysfs/dir.c | 28 |
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 | ||
385 | void sysfs_remove_subdir(struct dentry * d) | 401 | void sysfs_remove_subdir(struct dentry * d) |
@@ -390,6 +406,7 @@ void sysfs_remove_subdir(struct dentry * d) | |||
390 | 406 | ||
391 | static void __sysfs_remove_dir(struct dentry *dentry) | 407 | static 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. |