📄 marker.c
字号:
{ struct hlist_head *head; struct hlist_node *node; struct marker_entry *e; int found = 0; size_t len = strlen(name) + 1; u32 hash = jhash(name, len-1, 0); head = &marker_table[hash & ((1 << MARKER_HASH_BITS)-1)]; hlist_for_each_entry(e, node, head, hlist) { if (!strcmp(name, e->name)) { found = 1; break; } } if (!found) return -ENOENT; if (e->single.func != __mark_empty_function) return -EBUSY; hlist_del(&e->hlist); /* Make sure the call_rcu has been executed */ if (e->rcu_pending) rcu_barrier_sched(); kfree(e); return 0;}/* * Set the mark_entry format to the format found in the element. */static int marker_set_format(struct marker_entry **entry, const char *format){ struct marker_entry *e; size_t name_len = strlen((*entry)->name) + 1; size_t format_len = strlen(format) + 1; e = kmalloc(sizeof(struct marker_entry) + name_len + format_len, GFP_KERNEL); if (!e) return -ENOMEM; memcpy(&e->name[0], (*entry)->name, name_len); e->format = &e->name[name_len]; memcpy(e->format, format, format_len); if (strcmp(e->format, MARK_NOARGS) == 0) e->call = marker_probe_cb_noarg; else e->call = marker_probe_cb; e->single = (*entry)->single; e->multi = (*entry)->multi; e->ptype = (*entry)->ptype; e->refcount = (*entry)->refcount; e->rcu_pending = 0; hlist_add_before(&e->hlist, &(*entry)->hlist); hlist_del(&(*entry)->hlist); /* Make sure the call_rcu has been executed */ if ((*entry)->rcu_pending) rcu_barrier_sched(); kfree(*entry); *entry = e; trace_mark(core_marker_format, "name %s format %s", e->name, e->format); return 0;}/* * Sets the probe callback corresponding to one marker. */static int set_marker(struct marker_entry **entry, struct marker *elem, int active){ int ret; WARN_ON(strcmp((*entry)->name, elem->name) != 0); if ((*entry)->format) { if (strcmp((*entry)->format, elem->format) != 0) { printk(KERN_NOTICE "Format mismatch for probe %s " "(%s), marker (%s)\n", (*entry)->name, (*entry)->format, elem->format); return -EPERM; } } else { ret = marker_set_format(entry, elem->format); if (ret) return ret; } /* * probe_cb setup (statically known) is done here. It is * asynchronous with the rest of execution, therefore we only * pass from a "safe" callback (with argument) to an "unsafe" * callback (does not set arguments). */ elem->call = (*entry)->call; /* * Sanity check : * We only update the single probe private data when the ptr is * set to a _non_ single probe! (0 -> 1 and N -> 1, N != 1) */ WARN_ON(elem->single.func != __mark_empty_function && elem->single.probe_private != (*entry)->single.probe_private && !elem->ptype); elem->single.probe_private = (*entry)->single.probe_private; /* * Make sure the private data is valid when we update the * single probe ptr. */ smp_wmb(); elem->single.func = (*entry)->single.func; /* * We also make sure that the new probe callbacks array is consistent * before setting a pointer to it. */ rcu_assign_pointer(elem->multi, (*entry)->multi); /* * Update the function or multi probe array pointer before setting the * ptype. */ smp_wmb(); elem->ptype = (*entry)->ptype; elem->state = active; return 0;}/* * Disable a marker and its probe callback. * Note: only waiting an RCU period after setting elem->call to the empty * function insures that the original callback is not used anymore. This insured * by preempt_disable around the call site. */static void disable_marker(struct marker *elem){ /* leave "call" as is. It is known statically. */ elem->state = 0; elem->single.func = __mark_empty_function; /* Update the function before setting the ptype */ smp_wmb(); elem->ptype = 0; /* single probe */ /* * Leave the private data and id there, because removal is racy and * should be done only after an RCU period. These are never used until * the next initialization anyway. */}/** * marker_update_probe_range - Update a probe range * @begin: beginning of the range * @end: end of the range * * Updates the probe callback corresponding to a range of markers. */void marker_update_probe_range(struct marker *begin, struct marker *end){ struct marker *iter; struct marker_entry *mark_entry; mutex_lock(&markers_mutex); for (iter = begin; iter < end; iter++) { mark_entry = get_marker(iter->name); if (mark_entry) { set_marker(&mark_entry, iter, !!mark_entry->refcount); /* * ignore error, continue */ } else { disable_marker(iter); } } mutex_unlock(&markers_mutex);}/* * Update probes, removing the faulty probes. * * Internal callback only changed before the first probe is connected to it. * Single probe private data can only be changed on 0 -> 1 and 2 -> 1 * transitions. All other transitions will leave the old private data valid. * This makes the non-atomicity of the callback/private data updates valid. * * "special case" updates : * 0 -> 1 callback * 1 -> 0 callback * 1 -> 2 callbacks * 2 -> 1 callbacks * Other updates all behave the same, just like the 2 -> 3 or 3 -> 2 updates. * Site effect : marker_set_format may delete the marker entry (creating a * replacement). */static void marker_update_probes(void){ /* Core kernel markers */ marker_update_probe_range(__start___markers, __stop___markers); /* Markers in modules. */ module_update_markers();}/** * marker_probe_register - Connect a probe to a marker * @name: marker name * @format: format string * @probe: probe handler * @probe_private: probe private data * * private data must be a valid allocated memory address, or NULL. * Returns 0 if ok, error value on error. * The probe address must at least be aligned on the architecture pointer size. */int marker_probe_register(const char *name, const char *format, marker_probe_func *probe, void *probe_private){ struct marker_entry *entry; int ret = 0; struct marker_probe_closure *old; mutex_lock(&markers_mutex); entry = get_marker(name); if (!entry) { entry = add_marker(name, format); if (IS_ERR(entry)) { ret = PTR_ERR(entry); goto end; } } /* * If we detect that a call_rcu is pending for this marker, * make sure it's executed now. */ if (entry->rcu_pending) rcu_barrier_sched(); old = marker_entry_add_probe(entry, probe, probe_private); if (IS_ERR(old)) { ret = PTR_ERR(old); goto end; } mutex_unlock(&markers_mutex); marker_update_probes(); /* may update entry */ mutex_lock(&markers_mutex); entry = get_marker(name); WARN_ON(!entry); entry->oldptr = old; entry->rcu_pending = 1; /* write rcu_pending before calling the RCU callback */ smp_wmb(); call_rcu_sched(&entry->rcu, free_old_closure);end: mutex_unlock(&markers_mutex); return ret;}EXPORT_SYMBOL_GPL(marker_probe_register);/** * marker_probe_unregister - Disconnect a probe from a marker * @name: marker name * @probe: probe function pointer * @probe_private: probe private data * * Returns the private data given to marker_probe_register, or an ERR_PTR(). * We do not need to call a synchronize_sched to make sure the probes have * finished running before doing a module unload, because the module unload * itself uses stop_machine(), which insures that every preempt disabled section * have finished. */int marker_probe_unregister(const char *name, marker_probe_func *probe, void *probe_private){ struct marker_entry *entry; struct marker_probe_closure *old; int ret = -ENOENT; mutex_lock(&markers_mutex); entry = get_marker(name); if (!entry) goto end; if (entry->rcu_pending) rcu_barrier_sched(); old = marker_entry_remove_probe(entry, probe, probe_private); mutex_unlock(&markers_mutex); marker_update_probes(); /* may update entry */ mutex_lock(&markers_mutex); entry = get_marker(name); if (!entry) goto end; entry->oldptr = old; entry->rcu_pending = 1; /* write rcu_pending before calling the RCU callback */ smp_wmb(); call_rcu_sched(&entry->rcu, free_old_closure); remove_marker(name); /* Ignore busy error message */ ret = 0;end: mutex_unlock(&markers_mutex); return ret;}EXPORT_SYMBOL_GPL(marker_probe_unregister);static struct marker_entry *get_marker_from_private_data(marker_probe_func *probe, void *probe_private){ struct marker_entry *entry; unsigned int i; struct hlist_head *head; struct hlist_node *node; for (i = 0; i < MARKER_TABLE_SIZE; i++) { head = &marker_table[i]; hlist_for_each_entry(entry, node, head, hlist) { if (!entry->ptype) { if (entry->single.func == probe && entry->single.probe_private == probe_private) return entry; } else { struct marker_probe_closure *closure; closure = entry->multi; for (i = 0; closure[i].func; i++) { if (closure[i].func == probe && closure[i].probe_private == probe_private) return entry; } } } } return NULL;}/** * marker_probe_unregister_private_data - Disconnect a probe from a marker * @probe: probe function * @probe_private: probe private data * * Unregister a probe by providing the registered private data. * Only removes the first marker found in hash table. * Return 0 on success or error value. * We do not need to call a synchronize_sched to make sure the probes have * finished running before doing a module unload, because the module unload * itself uses stop_machine(), which insures that every preempt disabled section * have finished. */int marker_probe_unregister_private_data(marker_probe_func *probe, void *probe_private){ struct marker_entry *entry; int ret = 0; struct marker_probe_closure *old; mutex_lock(&markers_mutex); entry = get_marker_from_private_data(probe, probe_private); if (!entry) { ret = -ENOENT; goto end; } if (entry->rcu_pending) rcu_barrier_sched(); old = marker_entry_remove_probe(entry, NULL, probe_private); mutex_unlock(&markers_mutex); marker_update_probes(); /* may update entry */ mutex_lock(&markers_mutex); entry = get_marker_from_private_data(probe, probe_private); WARN_ON(!entry); entry->oldptr = old; entry->rcu_pending = 1; /* write rcu_pending before calling the RCU callback */ smp_wmb(); call_rcu_sched(&entry->rcu, free_old_closure); remove_marker(entry->name); /* Ignore busy error message */end: mutex_unlock(&markers_mutex); return ret;}EXPORT_SYMBOL_GPL(marker_probe_unregister_private_data);/** * marker_get_private_data - Get a marker's probe private data * @name: marker name * @probe: probe to match * @num: get the nth matching probe's private data * * Returns the nth private data pointer (starting from 0) matching, or an * ERR_PTR. * Returns the private data pointer, or an ERR_PTR. * The private data pointer should _only_ be dereferenced if the caller is the * owner of the data, or its content could vanish. This is mostly used to * confirm that a caller is the owner of a registered probe. */void *marker_get_private_data(const char *name, marker_probe_func *probe, int num){ struct hlist_head *head; struct hlist_node *node; struct marker_entry *e; size_t name_len = strlen(name) + 1; u32 hash = jhash(name, name_len-1, 0); int i; head = &marker_table[hash & ((1 << MARKER_HASH_BITS)-1)]; hlist_for_each_entry(e, node, head, hlist) { if (!strcmp(name, e->name)) { if (!e->ptype) { if (num == 0 && e->single.func == probe) return e->single.probe_private; else break; } else { struct marker_probe_closure *closure; int match = 0; closure = e->multi; for (i = 0; closure[i].func; i++) { if (closure[i].func != probe) continue; if (match++ == num) return closure[i].probe_private; } } } } return ERR_PTR(-ENOENT);}EXPORT_SYMBOL_GPL(marker_get_private_data);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -