Linux kernel:

  内核设计流派:

    单内核设计,但是充分借鉴了微内核体系设计的优点,为内核引入了模块化机制,内核高度模块化;

    内核被模块化之后,一些最为基本最为重要的内容,被编译到内核核心;而其他更多的功能则以模块的方式来提供;而且支持动态装载和卸载各内核模块;


  内核的组成部分:

    kernel:内核核心文件,一般为bzp_w_picpath,经过压缩处理的镜像文件;通常内核核心文件保存在/boot/目录下,名称为vmlinuz-version-release


    kernel object(ko):内核对象,内核额外功能模块,一般该类文件放置于/lib/modules/version-release


      注意:内核模块与内核核心,版本号必须严格匹配;


      内核模块其实就是内核源代码的一部分,只是在编译内核的过程中,由于其功能可能并非内核核心所必须,所以以模块的方式被编译;


      在编译内核时,内核的功能通常有如下几种选择方式;

        [ ] kernel function:no,不选择编译此功能;

        [M] kernel function:modules,将此功能编译为内核模块使用;此功能不占据内和空间,只占用磁盘空间;

        [*] kernel function:yes,将此功能直接编译进内核核心;


    ramdisk:内和补充文件,辅助文件,对于内核核心来说,此文件非必须,是否使用此文件取决于内核能否直接驱动rootfs所在的存储设备;

      设备的驱动程序,SCSI设备的驱动

      逻辑设备驱程序,lvm的驱动程序,软raid驱动程序等;

      文件系统;


      cpio -i -F initramfs-2.6.32-573.el6.x86_64.img


      简化的rootfs


    注意:一般来讲,kernel核心文件和ramdisk文件必须具有完全相同的版本号;


内核管理的相关命令:

  uname:打印当前系统相关信息(内核版本号、硬件架构、主机名称和操作系统类型等)。

    常用选项:

      -n:显示节点名称

      -r:显示内核版本号,包括version和release

      -a:显示所有信息

    例子:

      uname -a


  lsmod:显示已经加载到内核中的模块的状态信息。

    显示有Linux内核核心已经装载的内核模块;

    lsmod显示的内容,分为三个字段:

      模块名称    模块大小    被引用次数及被谁所引用;

    例子:

      lsmod


  modinfo:显示kernel模块的信息。

    常用选项:

      -F field:仅显示指定字段的信息;通常只能指定一个字段;

      -n:只显示模块文件的绝对路径;(最常用)

      -a:只显示模块的作者信息;

      -d:只显示模块的描述信息;

      -l:只显示许可证信息;

      -p:只显示模块参数信息;

    例子:

      modinfo


  depmod:可产生模块依赖的映射文件,在构建嵌入式系统时,需要由这个命令来生成相应的文件,由modprobe使用。

    选项:

      -a或--all:分析所有可用的模块; 

      -d或debug:执行排错模式; 

      -e:输出无法参照的符号; 

      -i:不检查符号表的版本; 

      -m<文件>或system-map<文件>:使用指定的符号表文件; 

      -s或--system-log:在系统记录中记录错误; 

      -v或--verbose:执行时显示详细的信息; 

      -V或--version:显示版本信息; 

      --help:显示帮助。


实现内核模块的动态装载和卸载的命令:

  insmod:装载指定的内核模块,但无法自动解决模块间的依赖关系;

    例子:

      insmod modinfo -n btrfs 

    注意:filename:模块文件的绝对路径;


  rmmod:用于从当前运行的内核中移除指定的内核模块。

    例子:

      rmmod raid1


  modprobe:从内核中移除模块或者向内核中插入模块;

    默认的配置文件:/etc/modprobe.conf , /etc/modprobe.d/*

    例子:

      modprobe module_name:装载模块,自动识别和解决依赖关系;

      modprobe -r module_name:卸载模块 


  ramdisk管理:

    ramdisk文件是在操作系统安装完成之后,由特定的应用程序根据当前硬件设备信息,文件系统信息等量身定制而成;


    ramdisk文件的制作工具:

      centos 5:

        mkinitrd:建立要载入ramdisk的映像文件,以供Linux开机时载入ramdisk。

          选项:

            -f:若指定的映像问家名称与现有文件重复,则覆盖现有的文件; 

            -v:执行时显示详细的信息; 

            --omit-scsi-modules:不要载入SCSI模块; 

            --preload=<模块名称>:指定要载入的模块; 

            --with=<模块名称>:指定要载入的模块; 

            --version:显示版本信息。

          例子:

            mkinitrd -v -f myinitrd.img $(uname -r)


      centos 6/7:

        dracut:建立要载入ramdisk的映像文件,以供Linux开机时载入ramdisk。

          例子:

            dracut /boot/initramfs-$(uname -r).img $(uname -r)


        mkinitrd脚本:      


内和信息输出的两个重要的伪文件系统:  

  /proc:内核状态及统计信息的主要的输出接口;同时还提供了一个能够输入配置信息,完成内核参数实时配置的接口——/proc/sys;

    /proc/*(除了sys目录):信息输出,只读;

    /proc/sys:可读写,可以接受用户指定的“新值”,来实现对内核相应功能或特性的实时配置;


    查看内核输出的状态信息或统计信息,直接使用cat命令即可;


    修改或设置内核功能或特性:

      使用echo命令,借助于覆盖输出重定向进行修改或设置即可;


      echo "value" > /proc/sys/path/to/parameter


    查看内核参数以及配置/proc/sys中的诸多功能,还可以使用:

      sysctl命令:

        sysctl - configure kernel parameters at runtime


  sysctl:用于在内核运行时动态地修改内核的运行参数,可用的内核参数在目录/proc/sys中。

    查看内核参数:

      sysctl -a:查看所有可以被修改的内核参数;

      sysctl variable:查看指定内核参数的设定值;

    配置某个内核参数(功能或特性)的值:

      sysctl -w variable=value

    注意:此方法中,"="两端不能写空格字符;

      sysctl -p:根据配置文件设置内存参数;重新读取并加载配置文件中所有的设置参数并且使其生效;


        常用的几个内核参数:

          net.ipv4.ip_forward:Linux的核心转发功能,路由功能;取值0,1

          net.ipv4.icmp_echo_ignore_all:忽略所有来源于外部主机的ping操作请求,取值0,1

          vm.drcp_caches:清理buffer和cache,释放物理内存,取值:0,1,2

          kernel.hostname:当前生效的主机名:


          DDOS:dynamic deny of service,动态拒绝服务攻击


            DCHP:IP地址耗尽策略,发送大量随机Mac地址DHCP discover消息


            DNS:ARP攻击,ARP欺骗,

            网关欺骗

            源IP地址欺骗

            dead ping: 


  /sys:sysfs

    专门为用户提供使用的伪文件系统,输出内核识别出来的各硬件设备的相关属性信息,也包括内核对硬件特性的可设定的信息;对于某些参数进行特定格式的修改,以调整或设定硬件的工作特性;


    echo '- - -' > /sys/class/scsi_host/host2/scan


    udev:

      通过读取/sys目录下的硬件设备的信息,按需为各硬件设备创建设备文件;


      udev是运行在用户空间的进程;


      专用工具:udevadmin,hotplug...


      当内核已经被加载至内存中,假如操作系统被安装到sda磁盘上,则内核需先标识出sda磁盘并而将其标记为设备(创建设备文件),而后才能挂载此设备;


      为了能够让这样的设备以后也能正常使用,内核通过内置的devtmpfs为每个内核所要使用的设备创建设备文件;而这样的文件可以被当作文件系统挂载之后,从内核直接转移到真正的rootfs中的dev目录内的;对于操作系统启动之后被新插入的设备,就必须要依靠udev来识别并创建设备文件了;


      udev之所以能够为设备创建设备文件,主要依赖于其事先定义好的规则;而这样的规则一般保存在udev的规则配置文件中:

        /etc/udev/runles.d

        /usr/lib/udev/rules.d


如何定制内核——编译内核源代码:

  http://kernel.org 内核维护的官方站点,可以获取内核源代码包;


  编译源代码的前提条件:

    1.开发环境

      开发工具:gcc,make,automake,qt,GTK,ncurese

        程序包组:

          “Development Tool”,“Server Platform Development”                  

          “开发工具”,“服务器平台开发”


          ncurses-devel


        头文件:/usr/include/*.h


    2.获取目标主机上各硬件设备的相关信息;

      CPU:

        # cat /proc/cpuinfo

        # lscpu

        # x86info -a


      PCI设备:       

        # lspic[-v|-vv]


      USB设备:

        #lsubs[-v|-vv]


      块设备:

        #lsblk


      了解更多的硬件设备信息:

        # hal-device(centos6可用包名:hal-0.5.14-14.e16.x86_64)


    3.获取目标主机系统功能的相关选项:

      比如:目标主机需要使用哪种文件系统;

            目标主机是否需要启动安全防护机制;

            ...


编译安装应用程序的一般步骤:

  1. #./.configure arg1 [arg2...]

  2. # make

  3. # make install


编译安装内核的一般步骤:

  1.需要准备或生成一个.config的文件,该文件记录了内核的编译细节:

    哪些功能直接编译进内核;

    哪些功能编译成内核模块;

    哪些功能在此次编译中不启用;


    make menuconfig|xconfig|config


  2.开始编译内核

    make [-j #]

      多线程编译,可以将编译进程在多个CPU核心上并行进行;


  3.安装模块文件:

    make module-install


  4.安装内核核心文件,并生成grub的启动菜单;

    make install

      安装的是bziage文件,安装到/boot/vmlinuz-version-release

      生成与内核版本完全匹配的initramfs文件

      编辑grub的配置文件,生成启动菜单项;


  Screen:一款由GNU计划开发的用于命令行终端切换的自由软件。

    例子:

      screen(开启screen)  

      Ctrl +a;d(拆除screen)

      screen -ls(列表显示screen)

      screen -r screen_ID(恢复连接至指定的screen)

      exit(关闭screen)


内核的配置选项:

  64-bit kernel

    是否支持64位内核


  general setup --->

    通用配置项:

    () local version - append to kernel release

      自定义本地版本号,附加到内核版本号后面的信息,由变异者定义;

    ((none)) default hostname

      定义当没有设置主机名时的默认主机名;


  enable loadable module support

    是否支持内核模块的动态装卸载;


  enable the block layer

    是否支持启用块层,通常是选择支持;


  processor type and features:

    处理器类型和特性

    processor family (generic-x86-64) --> (core 2/newer Xeon)

      选择处理器类型


    power management and acpi options:

      电源管理及高级电源管理接口选项


    executable file formats / emulations

      指定可执行文件的格式,默认为ELF,以#!开头的文件也具备可执行特性;


    networking support

      内核中的网络协议栈

      networking options

        [ ] ipv6 support


    device drivers:

      设备驱动程序


    file system:

      dos/fat/nt file systems

        [M] NTFS support


    kernel hacking:

      内核调试的相关内容


    security options:

      NAS selinux support

      安全选项


    cryptographic API:

      加密解密的应用程序变口;


    virtualization:

      虚拟化相关


配置内核的方式:

  1.make config:基于单行命令以遍历内核所有功能的方式进行内核配置,因此每个内核选项的配置都是交互式的;


  2.make menuconfig:基于curses的文本模式的配置窗口;


  3.make gconfig:基于gtk开发环境的窗口配置界面;一般情况下,只要安装了“桌面平台开发”程序包组就可以了;


  4.make xconfig:基于QT开发环境的窗口配置界面;一般情况下,只要安装了“桌面平台开发”程序包组就可以了;


  5.make defconfig:基于内核为目标平台提供默认配置模板进行配置;


  6.make allnoconfig:所有的功能全部不编译(全部选no)的配置方式;


  7.make allyesconfig:所有的功能全部编译进核心(全部选yes)的配置方式;


内核的编译方式:

  1.全编译:make [-j #]

  2.部分编译:

    a.只编译某个子目录中的相关源代码;

      # cd /user/src/linux

      # make [-j #] dir_name/

    b.只编译特定的模块

      # cd /usr/src/linux

      # make [dir/]file.ko


      示例:

        # cd /usr/src/linux

        # make drivers/net/ethernet/intel/e1000/e1000.ko

  3.交叉编译:编译的目标平台与当前编译的平台不相同;

    make arch=arch_name


      示例:

        # make arch=arm


内核重新编译:

  1.将所有/usr/src/inux-version目录的内容直接删除,重新从源代码包释放;随后可以重复之前的步骤重新编译即可;


  2.先清理之前的编译接口:

    make clean:

      清理大多数的编译生成的文件,但是会保留.config文件;


    make mrproper:

      清理所有编译生成的文件,包括.config以及其他的备份文件;


    make distclean:

      相当于make mrproper,但是还会额外清理各种patches以及编译器自身的备份文件;


编译安装内核实例

~]# tar xf linux-3.10.99.tar.xz -C /usr/src

~]# cd /usr/src

src]# ln -sv linux-3.10.99 linux

src]# cd /usr/src/linux

linux]# cp /boot/config-$(uname -r) ./.config

linux]# make menuconfig

linux]# make -j 4

linux]# make modules_install

linux]# make install

linux]# reboot


重启之后在grub菜单中选择新编译的内核来启动,如果可以看到登录提示符,则说明内核编译升级成功!

然后可以尝试编译其他与当前操作系统版本不同的其他更高级版本的内核,多试几个版本,了解一下各个不同版本的内核的特性;