On Wed, Oct 20, 2021 at 6:44 PM lijiang <lijiang(a)redhat.com> wrote:
 On Wed, Oct 20, 2021 at 6:22 PM Tao Liu <ltao(a)redhat.com> wrote:
 >
 > Hello lijiang,
 >
 > Thanks for reviewing the patch!
 >
 > On Wed, Oct 20, 2021 at 4:46 PM lijiang <lijiang(a)redhat.com> wrote:
 > >
 > > Hi, Tao
 > > Thank you for the update.
 > >
 > > On Sat, Oct 16, 2021 at 1:21 PM Tao Liu <ltao(a)redhat.com> wrote:
 > > >
 > > > 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;
 > >                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 > > This could overwrite the existing syment if (sp && (spn->value <
 > > sp->value)), right?
 > >
 > I think it won't overwrite existing syment. if (sp && (spn->value
<
 > > sp->value)), then what we want to do is inserting spn as the start of the
bucket, and making sp to be the 2nd one. So st->mod_symname_hash[index] = spn, making
spn to be the start of the bucket, then spn->name_hash_next = sp, making sp right after
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;
 > > > +               }
 > > > +       }
 > > > +}
 > >
 > > Can the above mod_symname_hash_remove() be simplified into the
 > > following implementation? The code may become more readable, and I
 > > didn't see any obvious performance issues as below.
 > >
 > > +static void
 > > +mod_symname_hash_remove(struct syment *spn)
 > > +{
 > > +       int index;
 > > +       struct syment *sp;
 > > +
 > > +       if (!spn)
 > > +               return;
 > > +
 > > +       index = SYMNAME_HASH_INDEX(spn->name);
 > > +       sp = st->mod_symname_hash[index];
 > > +
 > > +       while (sp) {
 > > +               if (sp == spn) {
 > > +                       sp = spn->name_hash_next;
 > > +                       spn->name_hash_next = NULL;
 > > +                       return;
 > > +               }
 > > +               sp = sp->name_hash_next;
 > > +       }
 > > +}
 > >
 >
 > I don't think it can work. if (sp == spn), then sp should be removed
 > from the hash table. Since it is a singly linked list, the
 > name_hash_next field of the one which is prior to sp should be
 > updated. But in the code it is not.
 >
 I haven't debugged it, just an idea.  I will debug it later. Thanks.
 
You are right, the first node needs to be treated specially in a
single linked list without a specific head node. I have no other
issues.
Thanks.
Lianbo
 > Thanks,
 > Tao Liu
 > >
 > > > +
 > > > +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
 > > >
 > >
 >