[RFC] Maintaining persistent kernel data across module unload/reload

From: Keith Owens (kaos@ocs.com.au)
Date: Tue Jan 11 2000 - 22:50:35 EST


Some modules claim to have a need to maintain persistent data in the
kernel even when the module is unloaded and reloaded. I can see four
approaches to fixing this problem, there may be others. Note: this
only applies to kernel data, it says nothing about maintaining external
data across reboots.

Comments please.

Options.

(1) Forbid persistent data. "Sorry, the kernel does not support module
    data that retains its value across unload/reload".

(2) For every module that needs persistent data and is configured in,
    compile some module specific variables into the static kernel and
    export them.

(3) Designate persistent variables in the module source, modutils
    handles these variable differently when unloading and reloading a
    module.

(4) Add a kernel service where a module can register arbitrary data and
    find it again during reload.

(5) Any other ideas?

Pros and cons.

(1) Forbid persistent data.

    Pro: No change, this is the current position. If this is the
         required policy, it must be documented as a restriction on
         modules.

    Con: Some developers believe that they need persistent kernel data.

(2) Add kernel static variables.

    Pro: Easy to code. Just add a small object that only contains the
         persistent data for a module. When the module is configured,
         compile and the link the persistent data into the kernel.

         ifeq ($(CONFIG_FOO),y)
           O_OBJS := FOO.o
         else
           ifeq ($(CONFIG_FOO),m)
             OX_OBJS += FOO_persistent.o
             M_OBJS += FOO.o
           endif
         endif

    Con: The persistent data is compiled into the static kernel when
         the module is configured, even if the module is never loaded.
         The persistent variables now have to be exported, even though
         only one module uses them.
         Source that used to be in a single file is now split.
         Changes to Makefiles as well as source.

(3) Designate persistent variables in the module source with modutils
    support. Example

    static __persistent struct foo *foo_p;
    if (!foo_p)
      initialize(&foo_p);

    Pro: A cleaner solution than splitting the source.
         The code source looks the same with or without -DMODULES.
         It is similar to the existing methods such as __init code.
         No Makefile changes.
         Minimal source changes, add one string to each persistent
         variable definition.
         Persistent data is only allocated when a module is used at
         least once instead of always compiled into the kernel.
         No unnecessary exports.

    Con: Changes to modutils and the module related syscalls with the
         backward compatibility problems that introduces (my problem).
         ksymoops has to understand __persistent data (my problem).
         Some extra overhead in the kernel to maintain the list of
         persistent data, each set of persistent data has a header
         which defines where the persistent data is, how big it is and
         which module it belongs to.
         Users have to upgrade to the latest modutils and ksymoops.

(4) Kernel service to register arbitrary data by name.

    This idea was pinched from MVS which has exactly the same problem.
    The kernel provides a service which takes an arbitrary name and an
    associated token and stores that data. The module or any other
    module can ask "give me the token for this name" or "update the
    token for this name". The name is limited to 16 bytes, an
    arbitrary length. The token is fixed at 4*(min(sizeof(void *),
    sizeof(long))) bytes which gives enough room for a couple of
    pointers and lengths.

    The module can store whatever it likes in the token. Small amounts
    of data can be stored in the token itself. For larger amounts of
    persistent data, the module must kmalloc the larger data and store
    its address and length in the token.

    Example code to use name tokens.

    /* name_token_create() returns 0 if the name does not already exist
     * or it exists and the token is zeroes. It returns -EEXIST if the
     * token exists and is non-zero. The name_token_xxx routines can
     * be called from anywhere, they do not rely on any external locks.
     * They could be restricted to non-IRQ contexts, I see no reason
     * for an IRQ to call name_token_xxx().
     */

    /* Can race with other copies of the code that creates the same
     * name, loop until we get a defined result.
     */
    while (1) {
      memset(&token, 0, sizeof(token));
      if ((i = name_token_create(&name, &token)) == 0) {
        /* New token, first time in */
        old_token = token;
        alloc_my_persistent_data();
        token.p = my_persistent_data_p;
        token.l = sizeof(*my_persistent_data_p);
        if (name_token_update(&name, &token, &old_token) == 0)
          break; /* Token created and set */
        else
          dealloc_my_persistent_data(); /* Race, other code updated the token */
      }
      else if (i != -EEXISTS) {
        printk(KERN_ERROR "name_token_create failed %d\n", i);
        return(-EBUSY);
      }
      break; /* token exists and is non-zero */
    }
    /* token now contains the persistent data for this module */

    Pro: No changes to Makefiles, modutils, ksymoops.
         Persistent data is only allocated when a module is used at
         least once instead of always compiled into the kernel.
         No unnecessary exports.

    Con: Every module that needs persistent data has to be modified to
         call name_token_xxx() and kmalloc its persistent data.
         ksymoops can not find kmalloc data so it will not be able to
         decode persistent data created using this technique.

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Sat Jan 15 2000 - 21:00:19 EST