home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1996 May / PCOnline_05_1996.bin / linux / source / a / bin / modules-.2 / modules- / modules-1.2.8 / insmod / HOWTO-modularize < prev    next >
Encoding:
Text File  |  1995-05-27  |  9.0 KB  |  316 lines

  1. Written by Bjorn Ekwall <bj0rn@blox.se> in the spring of 1995
  2.  
  3. How to modularize
  4. =================
  5.  
  6. There are some guidelines for modularizing; some of them are
  7. easy to implement but there are a couple of tricky parts as well.
  8.  
  9. The things to watch out for is that the module-to-be should
  10. really *be* a module. i.e. an entity that supplies a well
  11. defined *separate* functionality.
  12.  
  13. It should also have a "clean" interface to the rest of the
  14. kernel, i.e. it should not demand that a whole bunch of
  15. new symbols should be added to "linux/kernel/ksyms.c".
  16.  
  17.  
  18. The "easy" parts:
  19.  
  20.     1. Make sure that the first includes in these lines:
  21.         #ifdef MODULE
  22.         #include <linux/module.h>
  23.         #include <linux/version.h>
  24.         #endif
  25.        Only <linux/config.h> or <linux/autoconf.h> should
  26.        be included before these lines.
  27.        This will ensure that the "symbol versions" will
  28.        work correctly, as well as supplying the necessary
  29.        module definitions that you will need later on.
  30.  
  31.        Actually, you should use the "extended" format:
  32.         #ifdef MODULE
  33.         #include <linux/module.h>
  34.         #include <linux/version.h>
  35.         #else
  36.         #define MOD_INC_USE_COUNT
  37.         #define MOD_DEC_USE_COUNT
  38.         #endif
  39.        This will make your code less "#ifdef"-infested...
  40.  
  41.     
  42.     2. Identify the spots where the module functionality
  43.        is requested and released.  Usually you will find
  44.        these spots in "open_*()" and "close_*()".
  45.        Every time the module supplies a "resource", add:
  46.  
  47.            MOD_INC_USE_COUNT;
  48.  
  49.        and every time it releases the resource, add:
  50.  
  51.            MOD_DEC_USE_COUNT;
  52.  
  53.        Without these safeguards you will risk the sanity
  54.        of the module as well as of the kernel.
  55.        Check the logic so that the INC's and DEC's are
  56.        balanced, since the "hidden" count must be zero
  57.        for the module to be unloaded.
  58.  
  59.  
  60.     3. Lastly, add the "standard module definitions",
  61.        using this skeleton:
  62.  
  63.         #ifdef MODULE
  64.         char kernel_version[] = UTS_RELEASE;
  65.  
  66.     ...
  67.     /* driver specific module definitions */
  68.     ...
  69.  
  70.         int
  71.         init_module(void)
  72.         {
  73.     ...
  74.     /* driver specific inititialization, usually "register_*()" */
  75.     ...
  76.             if (fail)
  77.                 return -EIO;
  78.     ...
  79.  
  80.             return 0;
  81.         }
  82.  
  83.         void
  84.         cleanup_module(void)
  85.         {
  86.     ...
  87.     /* driver specific cleanups, ususally "unregister_*()" */
  88.     ...
  89.         }
  90.         #endif /* MODULE */
  91.  
  92.     
  93.        Note that due to historical reasons, many (most?) modules,
  94.        in their "cleanup_module", still include something like:
  95.  
  96.         if (MOD_IN_USE)
  97.             printk("xxx: device busy, remove delayed\n");
  98.         else
  99.         /* driver specific cleanups, ususally "unregister_*()" */
  100.     
  101.        With recent kernels this is taken care of automatically,
  102.        so you won't need it.
  103.        If you feel adventurous, you can clean up your old modules
  104.        by removing this historic check, but then of course you
  105.        have also said goodbye to Linux 1.0.* ...
  106.  
  107.  
  108.     4. Update the Makefile so that the module will be compiled
  109.        with the correct flags and so that it will be automatically
  110.        linked to the correct place in the directory tree.
  111.        You can take a look at "linux/drivers/net/Makefile" for
  112.        an example.  If you are lucky, you just add a line or two,
  113.        where the magic line is:
  114.  
  115.            MODULES := $(MODULES) my_module.o
  116.  
  117.        If your Makefile is not already prepared for modules,
  118.        you will have to modify (or add) the "modules:" target,
  119.        and also update the "depend:" or "dep:" target.
  120.        As before: "the previous source is your friend" :-)
  121.  
  122.  
  123. The "hard" parts:
  124.  
  125.     Now you have a potential module that you can try out
  126.     by doing "make modules" in the kernel root directory.
  127.  
  128.     The compilation will usually go without problems,
  129.     but just wait...
  130.  
  131.     The command "insmod my_module.o" will more often than
  132.     not protest and give you a list of undefined symbols.
  133.  
  134.     Whatever you do, *do not* start to add symbols to
  135.     "linux/kernel/ksyms.c" !!!
  136.  
  137.     Often these "errors" come from the fact that the module
  138.     doesn't have a "clean" interface to the kernel.
  139.     Kernel resident drivers will get their symbols resolved
  140.     from the complete set of kernel symbols, but the module
  141.     only has the exported symbols available.
  142.     Hidden interdependencies between parts of the kernel
  143.     will now be seen as these missing symbols.
  144.  
  145.     The solution is to clean up the interface, instead
  146.     of just making the dependencies permanent by adding
  147.     a symbol to "linux/kernel/ksyms.c".
  148.  
  149.     Two examples:
  150.  
  151.     - In kernels before 1.1.85 there was a function in
  152.       slhc.o, "ip_csum", that prevented that module to
  153.       be cleanly loaded. Instead of just adding this
  154.       symbol to ksyms.c, I noticed that "ip_csum" was
  155.       *only* used by slhc.o, and that is was defined as
  156.       an inline function in "linux/net/inet/ip.c".
  157.       The "correct" solution was to move this "function"
  158.       from ip.c to ip.h, since this header was included
  159.       anyway by slhc.o!
  160.       Problem solved!
  161.     
  162.     - In the 1.1.88 kernel, the nfs.o module complained
  163.       about "socki_lookup" being undefined.
  164.       Would you believe that this function was used
  165.       externally *only* by nfs.o, and that it has later
  166.       been cleaned up in "linux/net/socket.c" so that the
  167.       function call can be replaced by a simple assignment!?!
  168.  
  169. --- linux-1.1.88/fs/nfs/sock.c    Mon Jan 23 09:38:29 1995
  170. +++ linux/fs/nfs/sock.c    Sun Feb  5 01:27:48 1995
  171. @@ -37,9 +37,6 @@
  172.   * ***FIXME*** should probably put this in nfs_fs.h */
  173.  #define NFS_SLACK_SPACE 1024
  174.  
  175. -
  176. -extern struct socket *socki_lookup(struct inode *inode);
  177. -
  178.  #define _S(nr) (1<<((nr)-1))
  179.  
  180.  /*
  181. @@ -81,7 +78,7 @@
  182.      file = server->file;
  183.      inode = file->f_inode;
  184.      select = file->f_op->select;
  185. -    sock = socki_lookup(inode);
  186. +    sock = &inode->u.socket_i;
  187.      if (!sock) {
  188.          printk("nfs_rpc_call: socki_lookup failed\n");
  189.          return -EBADF;
  190.  
  191.  
  192.       Problem solved!
  193.  
  194.       This should be your *first* step before you even *start*
  195.       thinking of adding symbols to "linux/kernel/ksyms.c"...
  196.  
  197.       My own "snooper/sniffer" for these cases is just to do
  198.       "nm -gu my_module.o" and compare with "ksyms -a".
  199.       After having removed the "module interface":
  200.           _Using_Versions
  201.         _init_module
  202.         _cleanup_module
  203.         _kernel_version
  204.         _mod_use_count
  205.       the remaining undefined symbols can be searched for
  206.       in all sources in the kernel tree.
  207.       I'm lazy, so I have prepared two files, like this:
  208.           find . -name '*.c' -print > Sources-c
  209.         find . -name '*.h' -print > Sorces-h
  210.       For every undefined symbol, do:
  211.           grep symbol_name `cat Sources-c`
  212.           grep symbol_name `cat Sources-h`
  213.      With this information it is time to look through the
  214.      sources and to check if there *really* is a need to
  215.      export the symbol, or if a small rewrite will fix it...
  216.  
  217.      This is tedious work, but you only have to do it once :-)
  218.      For every symbol :-(
  219.      I promise you that you will learn a lot more of the
  220.      kernel internals than you ever thought you needed!
  221.  
  222.      Anyway, the goal is to create clean interfaces.
  223.      This will reduce the "bloat" in ksyms.c, but it will
  224.      also, as a side-effect, clean up the kernel!
  225.  
  226.  
  227.      There is yet another cleanup method that you should
  228.      contemplate.
  229.      Since 1.1.23 there has been support for stacked modules,
  230.      where a module can supply symbols for use by later
  231.      loaded modules.
  232.      This is accomplished by allowing insmod to extract the
  233.      global symbols in a module and to add an extra symbol
  234.      table to the kernel.
  235.  
  236.      For modules that consist of only one source file, it
  237.      is possible to selectively export symbols by using
  238.      the "static" keyword on all *local* symbols.
  239.  
  240.      For other modules, that are pre-built by "ld -r",
  241.      this is not possible, which means that the set of
  242.      exported symbols might become *huge* :-(
  243.  
  244.      If the module isn't intended to be a "base" module
  245.      in a module stack, you can always tell insmod not
  246.      to export the symbols by doing "insmod -x module.o".
  247.  
  248.      But there is another way!
  249.  
  250.      You can use the "unknown" function: "register_symtab()"
  251.      and select the symbols in your source instead!
  252.  
  253.      Actually, one can also explicitly *delete* all symbols
  254.      from a module by including "register_symtab(0)" in the
  255.      function "init_module".
  256.  
  257.      I'm ending this looooong note by showing you an example
  258.      of the use of "register_symtab()", where I'm using the
  259.      slhc module as a model.
  260.      IMHO this is the right way to do it...
  261.      The msdos/umsdos interface will be next...
  262.  
  263.      Bjorn
  264.  
  265. --- linux-1.1.88/drivers/net/Makefile    Tue Jan 31 13:36:24 1995
  266. +++ linux/drivers/net/Makefile    Sun Feb  5 09:27:05 1995
  267. @@ -242,6 +242,7 @@
  268.  NETDRV_OBJS := $(NETDRV_OBJS) slhc.o
  269.  else
  270.  MODULES := slhc.o $(MODULES)
  271. +SYMTAB_OBJS := slhc.o $(SYMTAB_OBJS)
  272.  endif
  273.  
  274.  ifdef CONFIG_8390
  275. @@ -249,6 +250,8 @@
  276.  else
  277.  MODULES := 8390.o $(MODULES)
  278.  endif
  279. +
  280. +include ../../versions.mk
  281.  
  282.  net.a: $(NETDRV_OBJS)
  283.      rm -f net.a
  284. --- linux-1.1.88/drivers/net/slhc.c    Mon Jan 23 09:38:31 1995
  285. +++ linux/drivers/net/slhc.c    Sun Feb  5 09:25:36 1995
  286. @@ -730,17 +730,26 @@
  287.  #ifdef MODULE
  288.  char kernel_version[] = UTS_RELEASE;
  289.  
  290. +static struct symbol_table slhc_syms = {
  291. +#include <linux/symtab_begin.h>
  292. +    X(slhc_compress),
  293. +    X(slhc_free),
  294. +    X(slhc_init),
  295. +    X(slhc_remember),
  296. +    X(slhc_toss),
  297. +    X(slhc_uncompress),
  298. +#include <linux/symtab_end.h>
  299. +};
  300. +
  301.  int init_module(void)
  302.  {
  303.      printk("CSLIP: code copyright 1989 Regents of the University of California\n");
  304. +    register_symtab(&slhc_syms);
  305.      return 0;
  306.  }
  307.  
  308.  void cleanup_module(void)
  309.  {
  310. -    if (MOD_IN_USE)  {
  311. -        printk("CSLIP: module in use, remove delayed");
  312. -    }
  313.      return;
  314.  }
  315.  #endif /* MODULE */
  316.