diff options
| -rw-r--r-- | fs/proc/proc_sysctl.c | 31 |
1 files changed, 18 insertions, 13 deletions
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 8efb1e10b025..3e64c6502dc8 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c | |||
| @@ -266,21 +266,19 @@ static void proc_sys_prune_dcache(struct ctl_table_header *head) | |||
| 266 | struct inode *inode, *prev = NULL; | 266 | struct inode *inode, *prev = NULL; |
| 267 | struct proc_inode *ei; | 267 | struct proc_inode *ei; |
| 268 | 268 | ||
| 269 | list_for_each_entry(ei, &head->inodes, sysctl_inodes) { | 269 | rcu_read_lock(); |
| 270 | list_for_each_entry_rcu(ei, &head->inodes, sysctl_inodes) { | ||
| 270 | inode = igrab(&ei->vfs_inode); | 271 | inode = igrab(&ei->vfs_inode); |
| 271 | if (inode) { | 272 | if (inode) { |
| 272 | spin_unlock(&sysctl_lock); | 273 | rcu_read_unlock(); |
| 273 | iput(prev); | 274 | iput(prev); |
| 274 | prev = inode; | 275 | prev = inode; |
| 275 | d_prune_aliases(inode); | 276 | d_prune_aliases(inode); |
| 276 | spin_lock(&sysctl_lock); | 277 | rcu_read_lock(); |
| 277 | } | 278 | } |
| 278 | } | 279 | } |
| 279 | if (prev) { | 280 | rcu_read_unlock(); |
| 280 | spin_unlock(&sysctl_lock); | 281 | iput(prev); |
| 281 | iput(prev); | ||
| 282 | spin_lock(&sysctl_lock); | ||
| 283 | } | ||
| 284 | } | 282 | } |
| 285 | 283 | ||
| 286 | /* called under sysctl_lock, will reacquire if has to wait */ | 284 | /* called under sysctl_lock, will reacquire if has to wait */ |
| @@ -296,10 +294,10 @@ static void start_unregistering(struct ctl_table_header *p) | |||
| 296 | p->unregistering = &wait; | 294 | p->unregistering = &wait; |
| 297 | spin_unlock(&sysctl_lock); | 295 | spin_unlock(&sysctl_lock); |
| 298 | wait_for_completion(&wait); | 296 | wait_for_completion(&wait); |
| 299 | spin_lock(&sysctl_lock); | ||
| 300 | } else { | 297 | } else { |
| 301 | /* anything non-NULL; we'll never dereference it */ | 298 | /* anything non-NULL; we'll never dereference it */ |
| 302 | p->unregistering = ERR_PTR(-EINVAL); | 299 | p->unregistering = ERR_PTR(-EINVAL); |
| 300 | spin_unlock(&sysctl_lock); | ||
| 303 | } | 301 | } |
| 304 | /* | 302 | /* |
| 305 | * Prune dentries for unregistered sysctls: namespaced sysctls | 303 | * Prune dentries for unregistered sysctls: namespaced sysctls |
| @@ -310,6 +308,7 @@ static void start_unregistering(struct ctl_table_header *p) | |||
| 310 | * do not remove from the list until nobody holds it; walking the | 308 | * do not remove from the list until nobody holds it; walking the |
| 311 | * list in do_sysctl() relies on that. | 309 | * list in do_sysctl() relies on that. |
| 312 | */ | 310 | */ |
| 311 | spin_lock(&sysctl_lock); | ||
| 313 | erase_header(p); | 312 | erase_header(p); |
| 314 | } | 313 | } |
| 315 | 314 | ||
| @@ -455,11 +454,17 @@ static struct inode *proc_sys_make_inode(struct super_block *sb, | |||
| 455 | inode->i_ino = get_next_ino(); | 454 | inode->i_ino = get_next_ino(); |
| 456 | 455 | ||
| 457 | ei = PROC_I(inode); | 456 | ei = PROC_I(inode); |
| 458 | ei->sysctl = head; | ||
| 459 | ei->sysctl_entry = table; | ||
| 460 | 457 | ||
| 461 | spin_lock(&sysctl_lock); | 458 | spin_lock(&sysctl_lock); |
| 462 | list_add(&ei->sysctl_inodes, &head->inodes); | 459 | if (unlikely(head->unregistering)) { |
| 460 | spin_unlock(&sysctl_lock); | ||
| 461 | iput(inode); | ||
| 462 | inode = NULL; | ||
| 463 | goto out; | ||
| 464 | } | ||
| 465 | ei->sysctl = head; | ||
| 466 | ei->sysctl_entry = table; | ||
| 467 | list_add_rcu(&ei->sysctl_inodes, &head->inodes); | ||
| 463 | head->count++; | 468 | head->count++; |
| 464 | spin_unlock(&sysctl_lock); | 469 | spin_unlock(&sysctl_lock); |
| 465 | 470 | ||
| @@ -487,7 +492,7 @@ out: | |||
| 487 | void proc_sys_evict_inode(struct inode *inode, struct ctl_table_header *head) | 492 | void proc_sys_evict_inode(struct inode *inode, struct ctl_table_header *head) |
| 488 | { | 493 | { |
| 489 | spin_lock(&sysctl_lock); | 494 | spin_lock(&sysctl_lock); |
| 490 | list_del(&PROC_I(inode)->sysctl_inodes); | 495 | list_del_rcu(&PROC_I(inode)->sysctl_inodes); |
| 491 | if (!--head->count) | 496 | if (!--head->count) |
| 492 | kfree_rcu(head, rcu); | 497 | kfree_rcu(head, rcu); |
| 493 | spin_unlock(&sysctl_lock); | 498 | spin_unlock(&sysctl_lock); |
