This patch indroduces mod_symname_hash, and its install/remove operations.
Since symbol_search() has to return the lowest address symbol and
symbol_search_next() returns the next lowest symbol, thus the installation
should be sorted ascendingly.
In mod_symname_hash_install_range scenario, spn are already arranged
ascendingly, so for mod_symname_hash_install:
Install spn previous to sp:
If sp is the start of bucket, and
1) spn->value is smaller than sp->value.
Install spn next to sp:
1) sp->name_hash_next is NULL or
2) sp->name_hash_next->value larger than spn->value
spn->value is the kernel address of the symbol and will not change.
So we use it mainly to determine the sequence. When spn->value equals
sp->value, they must be symbols within a kernel module.
Signed-off-by: Tao Liu <ltao(a)redhat.com>
---
defs.h | 1 +
symbols.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 74 insertions(+)
diff --git a/defs.h b/defs.h
index cbd45e5..bbdca79 100644
--- a/defs.h
+++ b/defs.h
@@ -2755,6 +2755,7 @@ struct symbol_table_data {
double val_hash_searches;
double val_hash_iterations;
struct syment *symname_hash[SYMNAME_HASH];
+ struct syment *mod_symname_hash[SYMNAME_HASH];
struct symbol_namespace kernel_namespace;
struct syment *ext_module_symtable;
struct syment *ext_module_symend;
diff --git a/symbols.c b/symbols.c
index 69dccdb..ad12d1c 100644
--- a/symbols.c
+++ b/symbols.c
@@ -1157,6 +1157,79 @@ symname_hash_install(struct syment *spn)
}
}
+/*
+ * Install a single kernel module symbol into the mod_symname_hash.
+ */
+static void
+mod_symname_hash_install(struct syment *spn)
+{
+ struct syment *sp;
+ int index;
+
+ if (!spn)
+ return;
+
+ index = SYMNAME_HASH_INDEX(spn->name);
+
+ sp = st->mod_symname_hash[index];
+
+ if (!sp || (spn->value < sp->value)) {
+ st->mod_symname_hash[index] = spn;
+ spn->name_hash_next = sp;
+ return;
+ }
+ for (; sp; sp = sp->name_hash_next) {
+ if (!sp->name_hash_next ||
+ spn->value < sp->name_hash_next->value) {
+ spn->name_hash_next = sp->name_hash_next;
+ sp->name_hash_next = spn;
+ return;
+ }
+ }
+}
+
+static void
+mod_symname_hash_remove(struct syment *spn)
+{
+ struct syment *sp;
+ int index;
+
+ if (!spn)
+ return;
+
+ index = SYMNAME_HASH_INDEX(spn->name);
+
+ if (st->mod_symname_hash[index] == spn) {
+ st->mod_symname_hash[index] = spn->name_hash_next;
+ return;
+ }
+
+ for (sp = st->mod_symname_hash[index]; sp; sp = sp->name_hash_next) {
+ if (sp->name_hash_next == spn) {
+ sp->name_hash_next = spn->name_hash_next;
+ return;
+ }
+ }
+}
+
+static void
+mod_symtable_hash_install_range(struct syment *from, struct syment *to)
+{
+ struct syment *sp;
+
+ for (sp = from; sp <= to; sp++)
+ mod_symname_hash_install(sp);
+}
+
+static void
+mod_symtable_hash_remove_range(struct syment *from, struct syment *to)
+{
+ struct syment *sp;
+
+ for (sp = from; sp <= to; sp++)
+ mod_symname_hash_remove(sp);
+}
+
/*
* Static kernel symbol value search
*/
--
2.29.2