[CFT][RFC] Module auto-unloading solution.

From: Steve Youngs (sryoungs_at_bigpond.net.au)
Date: 12/17/03

  • Next message: RunNHide: "Re: Initio SCSI Drivers"
    To: Linux Kernel List <linux-kernel@vger.kernel.org>
    Date:	Wed, 17 Dec 2003 16:19:15 +1000
    
    

    Hi Folks!

    Modules don't auto-unload, they haven't since the introduction of
    kmod. Whether that's right or wrong is _not_ what this post is
    about.

    I do know that there are a lot of people out there using Linux who
    like to have their unused modules silently and cleanly automatically
    unload. For that reason, I put together the script at the end of this
    post. So people have the option if they want it.

    Before I offer it to the general public, it'd be fantastic if some of
    you could look it over, kick the tyres and take it for a spin around
    the block. All comments etc would be very welcome and greatly
    appreciated.

    Thanks.

    ---------------------------------------------------
    #!/bin/bash

    ## Copyright (C) 2003 Steve Youngs

    ## RCS: $Id: auto-rmmod.sh,v 1.7 2003-12-17 15:34:51+10 steve Exp $
    ## Author: Steve Youngs <sryoungs@bigpond.net.au>
    ## Maintainer: Steve Youngs <sryoungs@bigpond.net.au>
    ## Created: <2003-11-25>
    ## Last-Modified: <2003-12-17 15:34:33 (steve)>
    ## Homepage: None yet. For now, email the Maintainer for the latest
    ## version

    ## Redistribution and use in source and binary forms, with or without
    ## modification, are permitted provided that the following conditions
    ## are met:
    ##
    ## 1. Redistributions of source code must retain the above copyright
    ## notice, this list of conditions and the following disclaimer.
    ##
    ## 2. Redistributions in binary form must reproduce the above copyright
    ## notice, this list of conditions and the following disclaimer in the
    ## documentation and/or other materials provided with the distribution.
    ##
    ## 3. Neither the name of the author nor the names of any contributors
    ## may be used to endorse or promote products derived from this
    ## software without specific prior written permission.
    ##
    ## THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
    ## IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    ## WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    ## DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
    ## FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    ## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    ## SUBSTITUTE GOODS OR SERVICES LOSS OF USE, DATA, OR PROFITS OR
    ## BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    ## WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
    ## OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
    ## IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

    ### Commentary:
    ##
    ## This script is for people who want their kernel modules auto-unloaded
    ## when they are not in use. It won't try to unload ethernet drivers
    ## because these modules don't set the "in-use" property. If you want
    ## to unload your ethernet drivers just do so manually with
    ## `modprobe -r module'.
    ##
    ## If you have any modules that you don't want this script to unload
    ## you can specify a regular expression of modules on the command
    ## line. See `auto-rmmod.sh --help' for details.
    ##
    ## *************************** W A R N I N G ***************************
    ## * *
    ## * Even though I have taken considerable care to ensure that ONLY *
    ## * unused modules are ever unloaded you should thoroughly test this *
    ## * script BEFORE putting it to use. *
    ## * *
    ## * For testing purposes you can use: `auto-rmmod.sh [REGEXP] --test' *
    ## * *
    ## *********************************************************************

    ## Setup and Usage:
    ##
    ## Check the paths in the variables listed after "### Code:", ensure
    ## that they are correct.
    ##
    ## Test with `auto-rmmod.sh [REGEXP] --test' until you're happy with
    ## what is going on.
    ##
    ## Next add a cron entry similar to this one to root's crontab:
    ##
    ## 0-59/10 * * * * exec /path/to/auto-rmmod.sh [REGEXP]
    ##
    ## That will run the script once every ten minutes. Now you can sit
    ## back and enjoy the wonders of automatic loading and unloading of
    ## your kernel modules.

    ## Note: Modules that don't want to auto-load:
    ##
    ## The loading mechanism for character device modules changed in
    ## 2.6.0-test10. In pre -test10 kernels these modules were called
    ## with `char-major-<major>', in -test10 and later kernels they are
    ## now called with `char-major-<major>-<minor>'. The modules,
    ## themselves, are supposed to export these chardev aliases, but as
    ## yet, not many of them do. To work around this until your module
    ## has been fixed put `alias char-major-<major>-<minor> module' or
    ## `alias char-major-<major>-* module' into your
    ## `/etc/modprobe.conf'. This will also be true of block devices,
    ## but as at -test11 it still hasn't been implemented.

    ## Feedback, bug reports and patches etc:
    ##
    ## All are welcome. Send them to the address listed at "Maintainer"
    ## at the top of this file.

    ### Todo:
    ##
    ##

    ### Code:

    ## Ensure that all of these are correct for your system.
    BASENAME=/usr/bin/basename
    CAT=/usr/bin/cat
    CUT=/usr/bin/cut
    FIND=/usr/bin/find
    GREP=/usr/bin/grep
    ID=/usr/bin/id
    MODPROBE=/sbin/modprobe
    SED=/usr/bin/sed
    TR=/usr/bin/tr
    XARGS=/usr/bin/xargs

    ############################################################
    # Nothing Configurable Beyond this point #
    ############################################################

    currentkernel=`uname -r`
    ethernetdir=/lib/modules/$currentkernel/kernel/drivers/net
    opts=$1

    # Check to see if this is a test run.
    if [ "$opts" == "--test" -o "$2" == "--test" ]; then
        if [ "$opts" == "--test" ]; then
            unset opts
        fi
        MODPROBE="$MODPROBE --dry-run --verbose"
    fi

    # There's no point in running this unless we're root.
    function chkuser() {
        if [ `$ID --user` -ne 0 ]; then
            echo "Error: You must be root to run this."
            exit 1
        fi
    }

    function buildregexp() {
        # Create a regexp of ethernet modules.
        $FIND $ethernetdir -type f -name \*.ko > /dev/null 2>&1
        if [ $? -eq 0 ]; then
            for file in `ls /lib/modules/$currentkernel/kernel/drivers/net/`; do
                convertedname=`$BASENAME $file .ko|$SED s/-/_/`
                if [ $internalpersist ]; then
                    internalpersist="$convertedname\|$internalpersist"
                else
                    internalpersist="$convertedname"
                fi
            done
            # Need to truncate a trailing '\|'.
            internalpersist=`expr match "$internalpersist" '\(.*[^\\\\|]\)'`
        fi

        # Set the list of persistant modules to any ethernet modules.
        if [ $internalpersist ]; then
            persistantmods="$internalpersist"
        fi

        # Add any user supplied regexp to the list of modules to NOT unload.
        if [[ $opts && $persistantmods ]]; then
            persistantmods="$persistantmods\|$opts"
        elif [ $opts ]; then
            persistantmods="$opts"
        fi
    }

    # The actual guts of this has to run 2 or 3 times to clean up all the
    # modules. The reason behind this is that removing one module can
    # free up another, so we take a couple of extra passes at it.
    function doit() {
        i=1
        while [ $i -le 3 ]; do
            if [ $persistantmods ]; then
                $CAT /proc/modules | $GREP -v $persistantmods | \
                    $CUT -d ' ' -f 1,3 | $GREP ' 0$' | $CUT -d ' ' -f 1 | \
                    $TR '\n' ' ' | $XARGS $MODPROBE --remove
                i=$[ i + 1 ]
            else
                $CAT /proc/modules | $CUT -d ' ' -f 1,3 | $GREP ' 0$' | \
                    $CUT -d ' ' -f 1 | $TR '\n' ' ' | $XARGS $MODPROBE --remove
                i=$[ i + 1 ]
            fi
        done
    }

    function usage() {
        cat<<EOF
    `$BASENAME $0`
    `$BASENAME $0` [REGEXP]
    `$BASENAME $0` [OPTION]

    REGEXP

      Is a regular expression of module names that you DO NOT want this
      script to unload. Be aware that the kernel converts dashes ('-') to
      underscores ('_') in module names. Also note that you should NOT
      include the suffix '.ko'.

      Example: If you never want this script to unload 'foo-bar.ko',
      'foo-baz.ko', and 'widgets.ko', the REGEXP would be
      'foo_ba[rz]\|widgets'. Be sure to surround your REGEXP in single
      quotes to avoid unexpected results.

      See grep(1) for the format of REGEXP.

    OPTION

      -h|--help|--usage ..... Display this usage text.

      --test ................ Run in "test mode". Display the modules to
                              be removed, but do not actually remove them.
    EOF
    }

    case $opts in
        \?|-\?|h|-h|--help|--usage)
            usage
            exit 0
            ;;
        *)
            chkuser
            buildregexp
            doit
            exit 0
            ;;
    esac

    ### auto-rmmod.sh ends here

    ## $Log: auto-rmmod.sh,v $
    ## Revision 1.7 2003-12-17 15:34:51+10 steve
    ## Doc fix.
    ##
    ## Revision 1.6 2003-12-17 14:59:05+10 steve
    ## Major rewrite, getting ready for general consumption.
    ## Added a "usage" function, command line options, and the option to run
    ## in "test" mode.
    ##
    ## Revision 1.5 2003-12-15 16:08:20+10 steve
    ## Even more doc fixes.
    ##
    ## Revision 1.4 2003-12-15 15:35:40+10 steve
    ## Rename to `auto-rmmod.sh'
    ##
    ## Revision 1.3 2003-12-15 15:33:06+10 steve
    ## Doc fixes.
    ##
    ## Revision 1.2 2003-11-25 09:54:46+10 steve
    ## Don't use an external file with the `-f' switch, just use a regexp
    ## directly from the script.
    ##

    #Local Variables:
    #time-stamp-start: "Last-Modified:[ ]+\\\\?[\"<]+"
    #time-stamp-end: "\\\\?[\">]"
    #time-stamp-line-limit: 10
    #time-stamp-format: "%4y-%02m-%02d %02H:%02M:%02S (%u)"
    #End:

    -- 
    |---<Steve Youngs>---------------<GnuPG KeyID: A94B3003>---|
    |              Ashes to ashes, dust to dust.               |
    |      The proof of the pudding, is under the crust.       |
    |------------------------------<sryoungs@bigpond.net.au>---|
    
    

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


    • application/pgp-signature attachment: stored

  • Next message: RunNHide: "Re: Initio SCSI Drivers"

    Relevant Pages

    • Re: [PATCH 2/4] libata: Implement disk shock protection support
      ... To be honest I also don't like the change to issue UNLOAD to ... kernel get into regarding suspend? ... if the daemon happens to request head parking right at ... signalling to the kernel. ...
      (Linux-Kernel)
    • Re: Filter and manipulate sections of file
      ... regexp A that opens a section, ... The second objective is to create a script that instead of printing ... I know bash and perl can easily handle this and in-fact I plan to ... >>> I have two objectives in mind. ...
      (comp.unix.shell)
    • Re: Filter and manipulate sections of file
      ... I have two objectives in mind. ... regexp A that opens a section, ... The second objective is to create a script that instead of printing ... I know bash and perl can easily handle this and in-fact I plan to ...
      (comp.unix.shell)
    • Re: PATCH: (as177) Add class_device_unregister_wait() and platform_device_unregister_wait() to the
      ... >> but why do refcounting at all? ... not with the kernel. ... Not being able to unload them _totally_ defeats the purpose of ... > concluded it's extremely hard to solve and generally not worth the ...
      (Linux-Kernel)
    • netgraph modules wont unload after use
      ... so I turned to netgraph as the solution.However it seems that netgraph will not permit a module ... This going into the kernel because my bpf based userland stuff is probably not going to hold up to the packet rate. ... ifconfig ath0 ssid ')(allmightytallest' ... But the module will never unload: ...
      (freebsd-net)