[RFC] Design + prototype: Multiple kprobes at an address - take 2
Ananth N Mavinakayanahalli
amavin@redhat.com
Fri Apr 8 12:34:00 GMT 2005
Prasanna S Panchamukhi wrote:
>>>register_multiprobe(struct mult_handler *mh):
>>> User has to allocate mult_handler (defined in kprobes.h) and pass
>>>the pointer to register_multiprobe();
>>>This routine does some housekeeping by storing reference to individual
>>>handlers and registering kprobes with common handler if the user requests
>>>for
>>>the first time at a given address. On subsequenct calls to insert probes on
>>>the same address, this routines just adds the individual handlers to the
>>>list
>>>without registering the kprobes.
>>>unregister_multiprobe(struct mult_handler *mh);
>>> User has to pass the mult_handler pointer to unregister.
>>>This routine just check if the he is the only active user and calls
>>>unregister
>>>kprobes. If there are more active users, it just removes the individual
>>>hanlders
>>>inserted by this user from the list.
>>
>>This design currently does not handle a case of a mult_probe at an
>>address where a kprobe is already present. I see a segfault during
>>module unload.
>>
>>Are we going to allow the registration of a probe (using existing api)
>>and then another one using the multiprobe interface and vice versa?
>>
>
>
> Well, let wrapper routine over these interfaces handle this issue.
> Maneesh has some thoughts about the wrapper routine.(...see maneesh's email
> for details)
Good idea
> The segfault you are seeing is not because of my patch, it is the known
> bug in the existing kprobes. To recreate just call unregister_kprobe() without
> even registering it and it segfaults. I will send out a patch to fix this
> kprobes problem.
>
Just verify if the probe exists in the list at all during unregister.
>>
>>>unsigned int kprobe_cpu = NR_CPUS;
>>>static DEFINE_SPINLOCK(kprobe_lock);
>>>+static DEFINE_SPINLOCK(multprobe_lock);
>>
>>As Frank suggested, this can be a rwlock.
>>
>>
>>>+/* New interface to support multiple handlers feature without even
>>>changing a
>>>+ * single line of exiting kprobes interface and data structures. This
>>>routines
>>>+ * accepts pointer to mult_handler structure, user has to allocate
>>>+ * multi_handler structure and pass the pointer. This routine basically
>>>checks
>>>+ * and registers the kprobes common handlers if the user is inserting a
>>>probe
>>>+ * for the first time and saves the references to individual kprobes
>>>handlers.
>>>+ * On subsequent call to this routine to insert multiple handler at the
>>>same
>>>+ * address, it just adds the mult_handler structure to the list.
>>>+ */
>>>+int register_multiprobe(struct mult_handler *multh)
>>>+{
>>>+ struct mult_probe *multp = NULL;
>>>+ struct kprobe *temp = NULL;
>>>+ unsigned long flags = 0, flags1 = 0;
>>>+ int ret = 0;
>>>+
>>>+ spin_lock_irqsave(&multprobe_lock, flags);
>>>+
>>>+ spin_lock_irqsave(&kprobe_lock, flags1);
>>>+ temp = get_kprobe(multh->kp.addr);
>>>+ spin_unlock_irqrestore(&kprobe_lock, flags1);
>>>+ if (temp == NULL) {
>>>+ multp = kmalloc(sizeof(struct mult_probe), GFP_ATOMIC);
>>>+ if (!multp) {
>>>+ ret = -ENOMEM;
>>>+ goto out;
>>>+ }
>>>+ multp->comm_probe.addr = multh->kp.addr;
>>>+ multp->comm_probe.pre_handler = comm_pre_handler;
>>>+ multp->comm_probe.post_handler = comm_post_handler;
>>>+ multp->comm_probe.fault_handler = comm_fault_handler;
>>>+ INIT_HLIST_HEAD(&multp->head);
>>>+ register_kprobe(&multp->comm_probe);
>>>+ } else {
>>>+ multp = container_of(temp, struct mult_probe, comm_probe);
>>>+ if (!multp) {
>>>+ ret = -EEXIST;
>>>+ goto out;
>>>+ }
>>
>>This is wrong - container_of is a macro and does not verify if you are
>>passing a valid pointer imbedded in the higher structure. It always
>>returns an address (correct/incorrect depends on the usage). Please
>>see my patch of yesterday (take2) for a simpler usage. Same goes for
>>other such usages in the patch.
>>
>
>
> no harm in checking the ptr, but right thing would be to remove the checks.
> Will be taken care in my next release.
It is a question of correct and incorrect and not harm :-). Also means
less code.
>
>>And it isn't a bad idea to double-check if temp->pre_handler ==
>>comm_pre_handler before making continuing with the registration.
>>
>
>
> Can you think of a situation where this check is really essential?
Consider this chunk form the patch:
+ spin_lock_irqsave(&kprobe_lock, flags1);
+ temp = get_kprobe(multh->kp.addr);
This will return a valid kprobe if one is present. But this does not
tell us whether the kprobe was registered using the multi interface or
the normal one.
+ spin_unlock_irqrestore(&kprobe_lock, flags1);
+ if (temp == NULL) {
+ multp = kmalloc(sizeof(struct mult_probe), GFP_ATOMIC);
+ if (!multp) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ multp->comm_probe.addr = multh->kp.addr;
+ multp->comm_probe.pre_handler = comm_pre_handler;
+ multp->comm_probe.post_handler = comm_post_handler;
+ multp->comm_probe.fault_handler = comm_fault_handler;
+ INIT_HLIST_HEAD(&multp->head);
+ register_kprobe(&multp->comm_probe);
+ } else {
+ multp = container_of(temp, struct mult_probe, comm_probe);
+ if (!multp) {
+ ret = -EEXIST;
+ goto out;
+ }
+ }
Now in the else case, you may end up adding the new kprobe to a
non-existing list since you don't have a check if the kprobe handlers
at the address are the aggregate handlers. AFAICS, this can have serious
consequences.
>
>>>+ INIT_HLIST_NODE(&multh->hlist);
>>>+ hlist_add_head(&multh->hlist, &multp->head);
>>
>>Also, why do we need a hlist for the mult_probe and mult_handler
>>structs? Can we not do with just lists?
>>
>
>
> hlist can save some space for us.
>
We don't need any hashing for the kprobes list at the same address - I
don't see why we should use hlists.
Thanks,
Ananth
More information about the Systemtap
mailing list