aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2012-11-24 11:29:40 -0500
committerOleg Nesterov <oleg@redhat.com>2013-02-08 11:47:03 -0500
commite591c8d78e49e6206935cf31c4d2b603bbb29166 (patch)
treefd454634604829933828e06849550dfbcfc37542 /kernel
parent9a98e03cc145c994da824dac7602334f50feb670 (diff)
uprobes: Introduce uprobe->register_rwsem
Introduce uprobe->register_rwsem. It is taken for writing around __uprobe_register/unregister. Change handler_chain() to use this sem rather than consumer_rwsem. The main reason for this change is that we have the nasty problem with mmap_sem/consumer_rwsem dependency. filter_chain() needs to protect uprobe->consumers like handler_chain(), but they can not use the same lock. filter_chain() can be called under ->mmap_sem (currently this is always true), but we want to allow ->handler() to play with the probed task's memory, and this needs ->mmap_sem. Alternatively we could use srcu, but synchronize_srcu() is very slow and ->register_rwsem allows us to do more. In particular, we can teach handler_chain() to do remove_breakpoint() if this bp is "nacked" by all consumers, we know that we can't race with the new consumer which does uprobe_register(). See also the next patches. uprobes_mutex[] is almost ready to die. Signed-off-by: Oleg Nesterov <oleg@redhat.com> Acked-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/events/uprobes.c10
1 files changed, 8 insertions, 2 deletions
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index d1d1394bca8b..61d0fa6b5012 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -91,6 +91,7 @@ static atomic_t uprobe_events = ATOMIC_INIT(0);
91struct uprobe { 91struct uprobe {
92 struct rb_node rb_node; /* node in the rb tree */ 92 struct rb_node rb_node; /* node in the rb tree */
93 atomic_t ref; 93 atomic_t ref;
94 struct rw_semaphore register_rwsem;
94 struct rw_semaphore consumer_rwsem; 95 struct rw_semaphore consumer_rwsem;
95 struct mutex copy_mutex; /* TODO: kill me and UPROBE_COPY_INSN */ 96 struct mutex copy_mutex; /* TODO: kill me and UPROBE_COPY_INSN */
96 struct list_head pending_list; 97 struct list_head pending_list;
@@ -449,6 +450,7 @@ static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset)
449 450
450 uprobe->inode = igrab(inode); 451 uprobe->inode = igrab(inode);
451 uprobe->offset = offset; 452 uprobe->offset = offset;
453 init_rwsem(&uprobe->register_rwsem);
452 init_rwsem(&uprobe->consumer_rwsem); 454 init_rwsem(&uprobe->consumer_rwsem);
453 mutex_init(&uprobe->copy_mutex); 455 mutex_init(&uprobe->copy_mutex);
454 /* For now assume that the instruction need not be single-stepped */ 456 /* For now assume that the instruction need not be single-stepped */
@@ -476,10 +478,10 @@ static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
476 if (!test_bit(UPROBE_RUN_HANDLER, &uprobe->flags)) 478 if (!test_bit(UPROBE_RUN_HANDLER, &uprobe->flags))
477 return; 479 return;
478 480
479 down_read(&uprobe->consumer_rwsem); 481 down_read(&uprobe->register_rwsem);
480 for (uc = uprobe->consumers; uc; uc = uc->next) 482 for (uc = uprobe->consumers; uc; uc = uc->next)
481 uc->handler(uc, regs); 483 uc->handler(uc, regs);
482 up_read(&uprobe->consumer_rwsem); 484 up_read(&uprobe->register_rwsem);
483} 485}
484 486
485static void consumer_add(struct uprobe *uprobe, struct uprobe_consumer *uc) 487static void consumer_add(struct uprobe *uprobe, struct uprobe_consumer *uc)
@@ -873,9 +875,11 @@ int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *
873 mutex_lock(uprobes_hash(inode)); 875 mutex_lock(uprobes_hash(inode));
874 uprobe = alloc_uprobe(inode, offset); 876 uprobe = alloc_uprobe(inode, offset);
875 if (uprobe) { 877 if (uprobe) {
878 down_write(&uprobe->register_rwsem);
876 ret = __uprobe_register(uprobe, uc); 879 ret = __uprobe_register(uprobe, uc);
877 if (ret) 880 if (ret)
878 __uprobe_unregister(uprobe, uc); 881 __uprobe_unregister(uprobe, uc);
882 up_write(&uprobe->register_rwsem);
879 } 883 }
880 mutex_unlock(uprobes_hash(inode)); 884 mutex_unlock(uprobes_hash(inode));
881 if (uprobe) 885 if (uprobe)
@@ -899,7 +903,9 @@ void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consume
899 return; 903 return;
900 904
901 mutex_lock(uprobes_hash(inode)); 905 mutex_lock(uprobes_hash(inode));
906 down_write(&uprobe->register_rwsem);
902 __uprobe_unregister(uprobe, uc); 907 __uprobe_unregister(uprobe, uc);
908 up_write(&uprobe->register_rwsem);
903 mutex_unlock(uprobes_hash(inode)); 909 mutex_unlock(uprobes_hash(inode));
904 put_uprobe(uprobe); 910 put_uprobe(uprobe);
905} 911}