Configuring linux kernel

From LQWiki
Jump to: navigation, search

Configuring the Linux kernel is the first step when Compiling a Linux kernel. In this step you can specify what kind of computer components your kernel will support. Options of the Linux kernel cover architecture, device drivers, filesystems, networking, security and other settings.

Requirements

This document assumes you are running the latest 2.6 kernel, provided - as package - by your distribution. You can determine the kernel version with:

uname -r

If you do not have them, install the kernel sources; here assumed to be in /usr/src/linux.

Summary

This document will describe how to recognize config options for currently running- and not running modules. That information will be used to to (de)select those options for a configuration tailored for your computer. First will be described how options can be recognized and changed manually, below also is a script that parses the configuration of your distribution and deselects not loaded modules.

Manually

Rather than spoiling the kernel source directory we can build the kernel in a subdirectory of your home directory:

mkdir -p /home/$USER/build/kernel
zcat /proc/config.gz > /home/$USER/build/kernel/.config

In the last command you extracted the .config file used to build the currently running kernel. This (hidden) .config file contains the kernel config options your distribution selected for this kernel, to support a wide range of hardware these options are mostly modules. This .config file will be loaded automatically by menuconfig.

cd /usr/src/linux
make O=/home/$USER/build/kernel menuconfig

Instead of menuconfig, xconfig or gconfig will also work in a graphical environment.

The advantages of using the .config file of the distribution are:

  • You know that the initial kernel configuration supports most hardware
  • You can play safe by only deselecting the options you know you don't need
  • Going through the options, you'll learn about the linux kernel, the computer and your hardware

The disadvantages:

  • There are a LOT of options to be deselected
  • You may not be certain about a lot of options
  • Building the kernel with too many modules takes longer

While it is true that the build time of a kernel without unnecessary modules will be reduced, going through all config options will take much longer than the buildtime gained. On the other hand, you'll have to do this only once thoroughly, subsequent builds can use the same .config file.

When you exit and choose to save the options, the hidden .config file will be overwritten with the new choice of config options, and will be used when Compiling a Linux kernel. But before that, how to determine right options.

find config options in menu

You can search for a config option in menuconfig. Press '/' and enter a config option (but strip CONFIG_). for instance 'USB_PRINTER', and it will list the current state (y/n/m), where to find this option in the menu and more.

Searching is is nice, however, only if you know the name of the config option and the state you'll need. So now is the question, how to get these. first the state:

Determine the wanted modules

To list all modules, type /sbin/modprobe -l. To list loaded modules use /sbin/lsmod. Note that the last list is much shorter.

In lsmod the first column lists the modules for hardware that was loaded during boot. It is very probable that you'll want these in your configuration too. If modules aren't loaded, it's an indication that you may not need them.

We'll need to have the same format like listed by modprobe to be able to determine the config option name later. Therefore we can cut the lsmod output and pipe it through modinfo:

#!/bin/bash
/sbin/lsmod|cut -d" " -f1|xargs /sbin/modinfo -n;

Save as loaded_mods.sh and make it excecutable after editing by typing chmod u+x loaded_mods.sh. You can then run it by typing ./loaded_mods.sh

Determine not wanted modules

Sometimes you want to know what modules you don't need. To list those enter as root in the console:

#!/bin/bash
modprobe -l | grep -v -E "^($(lsmod | cut -d" " -f1 | tail +2 | xargs modinfo -n | tr "\n" "|"))$"

save as not_loaded_mods.sh and type chmod u+x not_loaded_mods.sh

Module names to config options

Now we know how to determine the wanted state for modules, it's time to learn how to translate the module name into a config option. We can do this by parsing makefiles in kernel source (sub)directories. In the makefiles the config options and module names are listed.

#!/bin/bash
mod="${1%.ko}";
dir="${1%/*}";
sed -e :a -e '/\\$/N; s/\\\n//; ta' "${dir#*/kernel/}/Makefile" | \
sed -n "s/^obj-\$(CONFIG_\([A-Z0-9_]*\))\W*+=\W*"${mod##*/}"\.o$/\1/p";

Save as mod2config.sh and make it excecutable. This script will need an module (as listed in modprobe -l) and will translate it into a config option. So to list all not loaded modules:

for f in `./not_loaded_mods.sh`; do 
  ./mod2config.sh $f; 
done | less

and for the loaded:

for f in `./loaded_mods.sh`; do
  ./mod2config.sh $f;
done | less

Conclusion

Using this information, you can search for config options in menuconfig and activate or deactivate them. Please use some common sense, however. Only deactivate a module if you cannot think of a use for the module. Also there are options that were not modules in the original .config. You'll have to figure the required settings for these for yourself.

As a script

You don't have to be root to run the script below, but you should be running a 2.6 kernel. It parses that kernels' .config and removes modules when not currently loaded. You may want to add some modules you'll need occasionally after running this script.

mkdir -p /home/$USER/build/kernel/
cd /home/$USER/build/kernel/

save this script debloatconfig in this directory

#!/bin/bash
# Copyright (c) 2007 Roel Kluin GNU GPL v.2

appvers="0.2"

usage() {
cat << ENDUSAGE
suggest a kernel .config based on running modules in a highly modular kernel

usage: kcnfsuggest [options]
  -c|--config FILE
                 specify the kernel config file
  -l|--list FILE
                 use kernel config-module list, created with make_kcfg-modlist
  -k|--kernel-source DIRECTORY
                 specify the kernel source directory
  -y|--yes       If a module is loaded suggest to compile it in
                 (this may not always be possible)
  -m|--modules   If a module is loaded suggest to compile it
                 as a module (default)
  -K|--keep-modules
                 If not loaded now, suggest to keep it as a module
  -n|--no        If not loaded now, suggest to not compile it (default)
  -C|--comment TEXT
                 Display \"text\" after each line modified. In comment,
                 where needed \"# \" is placed before the text
  -h|--help      Prints this message
  -v|--version   print version and exit"

ENDUSAGE
}

get_mod2conf_makefile() {
        sed -n "s/^\W*obj-\$(CONFIG_\([A-Z0-9_]*\))\W*+=.*$1\.o.*$/\1/p" "$2/Makefile";
}

set_config_for() {
        if [ "$2" = "y" ]; then
                echo "$1=y${ym_comment}";
        elif [ "$2" = "m" ]; then
                echo "$1=m${ym_comment}";
        else
                echo "# $1 is not set${n_comment}";
        fi
}

OPTS=`getopt -o hvl:k:ymnKc:C: --long help,version,list,kernel-source:yes,modules,keep-modules,no,keep-modules,config:,comment: -n kcnfsuggest -- "$@"` || exit 1;
eval set -- "$OPTS";

# default values
loaded_module="m";
not_loaded_module="n";
ksrcdir="/usr/src/linux-`uname -r`/";

while true ; do
        case "$1" in
        -h|--help)
                usage; exit 0 ;;
        -c|--config)
                cfgfile="$2"; shift 2;;
        -l|--list)
                list="$2"; shift 2;;
        -k|--kernel-source)
                ksrcdir="$2"; shift 2;;
        -y|--yes)
                loaded_module="y"; shift ;;
        -m|--modules)
                loaded_module="m"; shift ;;
        -n|--no)
                not_loaded_module="n"; shift ;;
        -C|--comment)
                ym_comment=" # $2";
                n_comment=" $2";
                shift 2;;
        -K|--keep-modules)
                not_loaded_module="m"; shift ;;
        -v|--version)
                echo "version $appvers"; exit 0 ;;
        --) shift ; break ;;
        *) usage ; exit 1 ;;
        esac
done

if [ -z "$list" ]; then
        if [ ! -d "$ksrcdir" ]; then
                echo "Specify a kernel source directory or a config-module list" 1>&2;
                usage; exit 1;
        fi

        # try to guess the .config location
        if [ -z "$cfgfile" ]; then
                if [ -r "${ksrcdir}config.generic" ]; then
                        cfgfile="${ksrcdir}config.generic";
                elif [ -r "${ksrcdir}.config" ]; then
                        cfgfile="${ksrcdir}.config";
                fi
        fi
elif [ ! -r "$list" ]; then
        echo "ERROR: List could not read: $list" 1>&2;
        exit 1;
fi

if [ -z "$cfgfile" ]; then
        echo "Please specify a config file to parse" 1>&2;
        usage; exit 1
elif [ ! -r "$cfgfile" ]; then
        echo "ERROR: The config file cannot be read: $cfgfile" 1>&2;
        exit 1
fi

mi="`whereis modinfo | cut -d" " -f 2`";
if [ "$mi" == "modinfo:" ]; then
        echo "modinfo not found" 1>&2;
fi

for module in `cat /proc/modules|cut -d" " -f1`; do
        license="`$mi -l "$module"`";
        if [ -n "${license##*GPL*}" ]; then
                echo "WARNING: $module has licence \"$license\", when built this \
kernel will not include proprietary modules" 1>&2;
        else
                module="`$mi -n $module`";
                dir="${module%/*}";
                if [ -n "${dir##*/kernel/*}" ]; then
                        echo "WARNING: module not in kernel directory: $module" 1>&2;
                        continue;
                fi
                mod="${module%.ko}";
                mod="${mod##*/}"
                if [ -z "$list" ]; then
                        dir="${ksrcdir}${dir#*/kernel/}";
                        option="`get_mod2conf_makefile $mod $dir`";
                else
                        option="`grep ":$mod$" $list`";
                        option="${option%:*}";
                fi
                if [ -z "$option" ]; then
                        echo "WARNING: no kernel config option found for $mod" 1>&2;
                else
                        # loop because grep/sed may have returned more options
                        for op in $option; do
                                char_count=${#enable_option};
                                enable_option="${enable_option/ $op /}";
                                if [ $char_count -ne ${#enable_option} ]; then
                                        # echo "WARNING: duplicate option ignored: $op, for $mod" 1>&2;
                                        continue;
                                fi
                                enable_option="$enable_option $op";
                        done
                fi
        fi
done

for line in `cat "$cfgfile"|tr " " "^"`; do
        option=${line##\#*}; # delete comment
        option=${option%=m*};
        option=${option%%*=*}; # delete non-module options
        if [ "${option#CONFIG_}" ]; then
                char_count=${#enable_option};
                enable_option="${enable_option/$option/}";
                if [ $char_count -eq ${#enable_option} ]; then
                        set_config_for "$option" "$not_loaded_module";
                else
                        set_config_for "$option" "$loaded_module";
                fi
        else
                # other options (non-module or not recognized) are left unchanged
                echo "${line//^/ }";
        fi
done

now run:

chmod u+x debloatconfig
zcat /proc/config.gz > std.config

If the latter command didn't work, then the kernel you run lacks the CONFIG_IKCONFIG option. You may be able to find the .config from some other source.

debloatconfig -c std.config -k /usr/src/linux/ -m -C "changed by $USER" > .config

you may see some warnings if you have proprietary modules, or if a module wasn't found. In the latter case the generic configuration won't be changed.

cd /usr/src/linux
make O=/home/$USER/build/kernel/ oldconfig

if you want to upgrade to a newer kernel, go to the path of that kernel's sources and do again:

make O=/home/$USER/build/kernel/ oldconfig

If source code was changed, between kernel versions, the state for the corresponding config options will be asked again.

finally, I still suggest you use this to review the settings:

make O=/home/$USER/build/kernel/ menuconfig

There are a few reasons why I'd suggest you to review the settings after usage, however:

  • Compiled in options won't be changed, although changing them may benefit your hardware.
  • This script removes modules that are not loaded. This may include some modules you'll want to use occasionally.
  • resolve warnings

The advantage is, that now you'll have to make much less changes.

Other helpful tools

  • Documentation of your hardware (sometimes available online)
  • Documentation directory in your kernel sources
  • cat /proc/cpuinfo
  • lspci
  • Help options in menuconfig