[RFC] Design + prototype: Multiple kprobes at an address - take 2

Ananth N Mavinakayanahalli amavin@redhat.com
Thu Apr 7 12:30:00 GMT 2005


Jim Keniston wrote:
> On Wed, 2005-04-06 at 07:48, Ananth N Mavinakayanahalli wrote:

Hi Jim,

Thanks for the review comments!

> I missed take 1.  Sorry if these comments have already been addressed,
> but here goes...
> 
> ...
> 
>>+
>>+static void copy_kprobe(struct kprobe *src, struct kprobe *dst)
>>+{
>>+	dst->opcode = src->opcode;
>>+	memcpy(&dst->ainsn, &src->ainsn, sizeof(struct arch_specific_insn));
>>+}
> 
> 
> x86_64 stores the copy of the instruction on a different (executable)
> page.  (See arch_prepare_kprobe().)  It's not clear to me that you take
> this into account.

struct arch_specific_insn on x86_64 is just kprobe_opcode_t *insn. So I
think we should be ok here.

>>+
>>+struct aggr_probe *register_aggr_probe(struct kprobe *old_p)
>>+{
>>+	struct aggr_probe *ap;
>>+
>>+	ap = kcalloc(1, sizeof(struct aggr_probe), GFP_ATOMIC);
> 
> 
> I understand why you have to use GFP_ATOMIC here (lock held), but
> consider that there may be many probepoints where there are multiple
> kprobes.  (E.g., Hien is thinking of re-implementing retprobes using
> your multiple-kprobes feature, to allow register/unregister of a
> retprobe to be independent of the entry probe.  Think about those two
> probes at the entry for every system call.)  Anyway, it's probably best
> to avoid eating up GFP_ATOMIC memory.
> 
> Instead, why not pre-allocate this memory early in register_kprobe(),
> before you acquire the lock?  If you don't need it (the usual case), you
> can just free it.

Hmm, some cases to think of if kmalloc/kcalloc fails in this case:

- if this is the only probe at the address, the registration should
still go on.
- if this is one of many, the registration should fail.

I think this is doable.

> ...
> 
>> int register_kprobe(struct kprobe *p)
>> {
>> 	int ret = 0;
>> 	unsigned long flags = 0;
>>+	struct aggr_probe *ap;
>>+	struct kprobe *old_p;
>> 
>> 	if ((ret = arch_prepare_kprobe(p)) != 0) {
>> 		goto rm_kprobe;
>> 	}
>>+	
>> 	spin_lock_irqsave(&kprobe_lock, flags);
>> 	INIT_HLIST_NODE(&p->hlist);
>>-	if (get_kprobe(p->addr)) {
>>-		ret = -EEXIST;
>>+	old_p = get_kprobe(p->addr);
>>+	if (old_p) {
>>+		if (old_p->break_handler) {
> 
> 
> Seems like you could change this to
> 		if (old_p->break_handler || p->break_handler)
> and remove the two checks below.

Yes, you are right. Guess I can't get dumber :-)

....

>> 
>> void unregister_kprobe(struct kprobe *p)
>> {
>> 	unsigned long flags;
>>-	arch_remove_kprobe(p);
>>+	struct kprobe *kp;
>>+	struct aggr_probe *ap;
>>+	
>> 	spin_lock_irqsave(&kprobe_lock, flags);
>>+	kp = get_kprobe(p->addr);
>>+	if (kp && (kp->pre_handler == aggr_pre_handler)) {
>>+
>>+		/* this is one of the possibly many kprobes at the address */
>>+		ap = container_of(kp, struct aggr_probe, kp);
>>+		list_del(&p->list);
>>+
>>+		/* 
>>+		 * if we just unregistered the last probe at the address,
>>+		 * its time to cleanup
>>+		 */ 
>>+		if (list_empty(&ap->kprobes)) {
>>+			arch_remove_kprobe(p);
> 
> 
> Unfortunately, on x86_64, arch_remove_kprobe() can sleep, so you can't
> call it holding a lock.
> 
> ...

Hmm OK. Will have to rearrange the code a bit.

Thanks,
Ananth



More information about the Systemtap mailing list