aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/proc/proc_sysctl.c31
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:
487void proc_sys_evict_inode(struct inode *inode, struct ctl_table_header *head) 492void 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);