Linux Kernel Total

Table of Contents

General

LinuxChanges

kernel download

docs

docs

ChinaUnix 内核源码版精华帖分类汇总

水木社区 KernelTech版FAQ1.1

1.资源问题
1.1 请推荐一些好的Linux内核参考书?
1.2 请推荐一些好的学习网站
1.3 本版ftp

2. 源代码问题
2.1 如何得到某一版本的Linux内核源代码?
2.2 请问xx命令、xx库的源码是哪个文件?
2.3 linux-2.x.x.tar.gz.sign 文件有什么用途?
2.4 请推荐一些源代码查看工具?
2.5 内核patch如patch-2.6.3怎么用?
2.6 如何统计linux内核有多少行代码?
2.7 xx结构的定义在哪个内核源文件中?
2.8 volatile__volatile__ 是什么意思?
2.9 do{ ... } while(0) 是什么意思?
2.10 list_entry 的定义是怎么回事?
2.11 为什么有些内核变量找不到定义?

3. 模块编程问题
3.1 模块编程需要注意什么?
3.2 为什么insmod一个模块时显示版本不匹配?
3.3 为什么出现Unresolved Symbol错误?
3.4 为什么出现no license错误?
3.5 为什么看不到用printk打印的信息?

4. 内核开发问题
4.1 怎么制作、使用patch文件?
4.2 在内核中可以使用系统调用吗?
4.3 在内核中怎么打开并操作一个文件?
4.4 在内核中读写文件时为什么会出现EFAULT(-14)错误?
4.5 怎么在系统中增加一个自己的系统调用?
4.6 怎么在内核中加入我自己的驱动程序?
4.7 怎么通过程序得到cpu和mem使用率?
4.8 如何获得高精度的系统时间?
4.9 怎么进行系统性能调谐?
4.10 内核中怎么进行互斥?

5. 其它问题
5.1 如何学习Linux内核?
5.2 如何下载精华区?
5.3 init进程是核心进程吗?init与初始进程是不是一回事?
5.4 initrd(.img)有什么用?

6. 关于本FAQ
7. Changelog

1.资源问题
1.1 请推荐一些好的Linux内核参考书?
   a.《Linux Device Drivers, 2nd Edition》,有中文译本
   b.《Understanding the Linux Kernel, 3nd Edition》
   c.《Linux内核源代码情景分析》,分上下两册
   d.《边干边学-Linux内核指导》
   e.《Linux内核2.4版源代码分析大全》
   f.《Linux Kernel Development》
   g.《IA-64 Linux Kernel: Design and Implementation》
   注:a电子版可在http://www.oreilly.com/catalog/linuxdrive2/%E4%B8%8B%E8%BD%BD
       f和g比较新,在国内比较难买到。
   h./Documentation/DocBook & /Documentation/kernel-docs.txt

1.2请推荐一些好的学习网站
         1. 开源/文档/社区/信息资源
         1.01 http://www.kernel.org
                 Linux内核主页

         1.02 http://www.gnu.org or http://www.fsf.org
                 GNU/FSF主页

         1.03 http://www.opensource.org
                 Open Source权威网站

         1.04 http://www.osdl.org
                 OSDL(Open Source Development Labs, Linus Torvalds的家)主页

         1.05 http://www.sourceforge.net
                 大型开放源码软件网站

         1.06 http://freshmeat.net/
                 大型开放源码软件网站

         1.07 http://osdir.com
              开放源码目录,提供许多开放源码软件的索引和链接

         1.08 http://www.rpmfind.net
              提供RPM包的搜索和链接

         1.09 http://oss.sgi.com/projects/
              SGI的开放源码Linux项目

         1.10 http://oss.software.ibm.com/linux/
              IBM的开放源码Linux项目

         1.11 http://www-124.ibm.com/developerworks/oss/
              IBM developerWorks的开放源码Linux项目

         1.12 http://www.kerneltrap.org
              内核开发相关信息和论坛

         1.13 http://kernelnewbies.org
              很好的内核学习网站

         1.14 http://www.kernelhacking.org/
              kernelhacking-HOWTO文档

         1.15 http://www.tldp.org
              Linux文档

         1.16 http://www.nongnu.org/lkdp/
              Linux内核文档

         1.17 http://linux-mm.org/
              Linux内核mm文档

         1.18 http://www.linuxforum.net
              中国Linux论坛

         1.19 http://www.aka.org.cn
              中国信息技术论坛-阿卡(AKA)

         1.20 http://www.lisoleg.net
              利索脚(Linux Source Learning Group)

         1.21 http://www.linuxfans.org/
              中国Linux公社

         1.22 http://www-900.ibm.com/developerWorks/cn/linux
              IBM developerWorks Linux专区

         1.23 http://www.linuxaid.com.cn
              LinuxAid技术支持中心

         1.24 http://lxr.linux.no/source/
              Cross-Referencing Linux,可在线查看Linux内核源代码

         1.25 http://www.linux.org
              Linux信息资源

         1.26 http://www.linuxdevices.com
              嵌入式Linux信息资源

         1.27 http://www.linuxjournal.com/webindex.php
              Linux Journal杂志在线文章

         1.28 http://www.joyfire.net/
              本站joyfire大侠维护的站点

         1.29 http://lwn.net
              Linux Weekly News

         1.30 http://www.ctyme.com/intr/int.htm
              关于BIOS系统调用,很全
         2. 项目资源
         2.01 http://perso.wanadoo.es/xose/linux/linux_ports.html
              Linux移植项目链接资源

         2.02 http://www.uclinux.org
              uClinux主页

         2.03 http://www.fsmlabs.com/ or http://www.rtlinux.org
              RTLinux(Real-Time Linux)主页

         2.04 http://mail.aero.polimi.it/~rtai/
              RTAI(Real Time Application Interface for Linux)主页

         2.05 http://www.ittc.ku.edu/kurt/
              KURT-Linux(Kansas University Real-Time Linux)主页

         2.06 http://www.arm.linux.org.uk/
              ARM Linux主页

         2.07 http://www.linux-mips.org/
              Linux/MIPS主页

         2.08 http://penguinppc.org/
              Linux/PowerPC主页

         2.09 http://www.denx.de
              Denx Software Engineering, PowerPC系列嵌入式Linux资源

         2.10 http://www.netfilter.org/ or http://www.iptables.org/
              netfilter/iptables项目

         2.11 http://www.linuxfromscratch.org
              LFS(Linux From Scratch)项目

         2.12 http://www.uclibc.org
              uClibc(C library for developing embedded Linux systems)主页

         2.13 http://www.LinuxVirtualServer.org
              章文嵩主持的Linux Virtual Server项目

         2.14 http://linux-ha.org
              High-Availability Linux项目

         2.15 http://www.lids.org
              本站vertex大侠主持的LIDS(Linux Intrusion Detection System)项目

         2.16 http://www.minigui.org/
              本站Kongming大侠主持的MiniGUI项目

         2.17 http://user-mode-linux.sourceforge.net/
              User-Mode Linux项目

         2.18 http://lse.sourceforge.net/
              Linux Scalability Effort项目

         2.19 http://linuxperf.nl.linux.org/
              Linux Performance Tuning项目

         2.20 http://euclid.nmu.edu/~benchmark/
              Linux Benchmark项目
1.3本版ftp
         ftp://kernel:kernel@kernel.trueice.net:8021/
                 /incoming/kerneltech.newsmth

         目前我所能找到的内核方面的经典书籍电子版都有
         特别感谢trueice网友提供本版ftp^_^

2. 源代码问题
2.1 如何得到某一版本的Linux内核源代码?
    a. http://www.kernel.org%E6%88%96ftp://ftp.kernel.org%EF%BC%8C%E8%BF%99%E6%98%AFLinux%E5%86%85%E6%A0%B8%E7%89%88%E6%9C%AC%E7%9A%84%E5%8F%91%E5%B8%83
       网站。
    b. 很多镜像或本地网站也提供部分Linux内核版本的下载,多用ftp搜索引擎。
    c. 一般的Linux发行版如Redhat之类会随盘提供相应的内核源代码,不过这个源代
       码往往是改动过的,与标准Linux内核有差异。

2.2 请问xx命令、xx库的源码是哪个文件?
    a. 一个系统除了内核以外,还需要有shell、gcc等一系列工具和命令以及C库等一
       系列库,这些作为应用程序其源代码都不在内核中,需要另外下载相应的源代码。
    b. 对于Redhat系统,可以用rpm -qf命令来查找某一命令所在的软件包,然后再找
       相应的源代码包安装。
    c. gnu.org有很多软件源代码如bash/glibc/binutils/make/gcc的源代码。
    d. 可在http://www.rpmfind.net%E6%88%96http://www.google.com%E5%8E%BB%E6%90%9C%E4%B8%80%E6%90%9C

2.3 linux-2.x.x.tar.gz.sign 文件有什么用途?
     这是一个数字签名文件,用来校验linux-2.x.x.tar.gz这个文件在签名后是没有
     被第三方修改过,更详细的信息参考http://www.kernel.org/signature.html

2.4 请推荐一些源代码查看工具?
    a. Windows系统可以用Source Insight,Linux系统可以用Source Navigator。
    b. vim或emacs编辑器,配合cscope、ctags、etags等交叉索引工具。
    c. vim或emacs编辑器,配合grep、egrep等文本搜索工具,不过最好要对源代码目
       录结构有所熟悉
    d. LXR,以网页的形式通过浏览器浏览,安装复杂,可从http://lxr.linux.no/%E4%B8%8B
       载该工具也可以直接访问http://lxr.linux.no/source/%E5%9C%A8%E7%BA%BF%E9%98%85%E8%AF%BBLinux%E5%86%85%E6%A0%B8%E6%BA%90
       代码。
    e. GNU global,可以在命令行用,也可以生成hypertext,类似lxr,但更省事。

2.5 内核patch如patch-2.6.3怎么用?
    a. 内核patch一般是针对前一个版本,如patch-2.6.3是针对2.6.2的内核。
    b. 内核patch一般是和ChangeLog对应,如patch-2.6.3对应于ChangeLog-2.6.3。
    c. 在内核patch中查找Makefile关键字可得到相关信息,如在patch-2.6.0中有:
         diff -Nru a/Makefile b/Makefile
         — a/Makefile Wed Dec 17 19:00:07 2003
         + b/Makefile Wed Dec 17 19:00:07 2003
         @@ -1,7 +1,7 @@
         VERSION = 2
         PATCHLEVEL = 6
         SUBLEVEL = 0
         -EXTRAVERSION = -test11
         +EXTRAVERSION =
    d. 找到了针对的内核就可以用patch来升级内核了。

2.6 如何统计linux内核有多少行代码?
    尝试以下shell命令:
    find /usr/src/linux-2.x.x -name "*.[chS]" | xargs cat | wc -l

2.7 xx结构的定义在哪个内核源文件中?
    a. 请使用源码查看工具,见问题2.4。
    b. 如果用grep等文本搜索工具,主要在include/linux和include/asm两个目录下
       搜索。

2.8 volatile和_volatile_是什么意思?
    a. volatile是C语言定义的关键字,gcc为了需要又定义了_volatile_,它和
       volatile表达的是同一意思。
    b. volatile的本意是"易变的",由于访问寄存器的速度快于访存,所以编译器一般
       都会作优化以减少访存。如果变量加上volatile修饰,则编译器就不会对此变量
       的读写操作进行优化,即不通过寄存器缓冲而直接访存。
    c. asm _volatile_一起指示编译器不要改动优化后面的汇编语句。
    d.一般说来,volatile用在如下的几个地方:
         i)中断服务程序中修改的供其它程序检测的变量需要加volatile;
         ii)多任务环境下各任务间共享的标志应该加volatile;
         iii)存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义;

2.9 do{ … } while(0)是什么意思?
    a. 主要是为了避免宏在不同情况展开可能会出现的一些错误。
    b. 在http://www.kernelnewbies.org/faq/%E4%B8%8A%E6%9C%89%E8%AF%A6%E7%BB%86%E4%BB%8B%E7%BB%8D

2.10 listentry的定义是怎么回事?
    a. listentry的定义在内核源文件include/linux/list.h中:
       #define listentry(ptr, type, member) \
         ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
    b. 其功能是根据listhead型指针ptr换算成其宿主结构的起始地址,该宿主结构是
       type型的,而ptr在其宿主结构中定义为member成员。如下图:

       req–>|type型对象起始地址
             |
             |… …
       ptr–>|ptr指针所指的member成员地址
             |
             |… …

      ptr指向图中所示的位置,通过 (unsigned long)(&((type*)0)->member) 得到ptr
      和req之间的差值,ptr减去这个差值就得到了type型宿主结构的指针req,返回
      类型为 (type*)

2.11 为什么有些内核变量找不到定义?
    a. 与section的起始地址和结束地址相关的变量(准确地说是常量)一般定义在arch/XXX/kernel/vmlinux.lds.S链接脚本里,
    如 __initramfs_start
    b. 一些变量和函数用宏封装过,原始的定义查找比较困难,如 inb_p() 等等。

3. 模块编程问题
3.1 模块编程需要注意什么?
    a. Documentation/kbuild/目录下提供内核模块编程的核心资料
    b. 如果要用inline功能,需要在gcc编译选项中增加-O2

3.2 为什么insmod一个模块时显示版本不匹配?
    a. 某些时候用insmod -f能够成功加载,但需谨慎使用。

3.3 为什么出现Unresolved Symbol错误?
    a. 首先查看文件/proc/ksyms,看内核有没有输出这个符号,不同的内核版本如
       2.2和2.4输出的符号会有些变化。
    b. 如果内核输出的符号带有版本控制信息如符号printkR12345678,则性质同
       问题3.2。
    c. 注意:现在有很多版本都不输出 sys_call_table 了,另想办法吧!

3.4 为什么出现no license错误?
    在源文件加入下面一行(加在文件头部,尾部均可):
    MODULELICENSE("GPL");或者 MODULELICENSE("Dual BSD/GPL");
    试模块license而定。

3.5 为什么看不到用printk打印的信息?
    a. 打印消息受级别的限制,消息级别可以通过printk设置,如:
         printk("<n>something"); /* 其中0<=n<=7 */
       假设控制台的消息级别为m, 当n<m时消息打印到控制台,否则不打印。
       这样一方面可以提高要打印消息本身的级别(数字越小级别越高),
       另一方面可以改变控制台的消息级别(可从1到8),如改为8可用以下命令:
        # echo "8" > /proc/sys/kernel/printk
    b. 用dmesg命令看。
    c. 当系统运行klogd和syslogd时,内核消息就会由klogd分发到syslogd,
       syslogd会根据配置文件/etc/syslog.conf作相应处理,具体可以查看syslogd
       和syslog.conf的man页。


4. 内核开发问题
4.1 怎么制作、使用patch文件?
    a. patch文件是由diff命令生成的,使用patch文件用patch命令,具体可查看diff
       和patch的man页和info。
    b. diff命令的常用选项组合是urN,如:
         diff -urN linux/ my_linux/ >mypatch.diff

4.2 在内核中可以使用系统调用吗?
    a. 可以。内核源代码中就有使用系统调用的例子,如open()、execve()等。
    b. 在内核中使用系统调用必须要在源文件中包括以下两行:
       #define __KERNEL_SYSCALLS__
       #include <linux/unistd.h>
    c. 内核中使用系统调用的相关定义可查看文件include/asm/unistd.h。
       如果要用的系统调用该文件中没有定义,可以按照其格式自行添加。
    d. 如果要在模块中使用系统调用,必须要自己定义errno如:
       int errno;
       内核在lib/errno.c中定义了errno,但该符号不导出,所以模块编程时需要自己
       定义errno,用以存放系统调用出错号。

4.3 在内核中怎么打开并操作一个文件?
    a. 直接用open()、read()等系统调用,见问题4.2。
    b. 用 filp_open() 函数打开文件,得到 struct file * 的指针fp。
       使用指针fp进行相应操作,如读文件可以用 fp->f_ops->read
       最后用 filp_close() 函数关闭文件。
       filp_open()、filp_close() 函数在 fs/open.c 定义,在 include/linux/fs.h
       声明。
    c. 自己写包装函数,可参照文件fs/exec.c中的 open_exec()kernel_read() 函数。
       在http://www.linuxforum.net/forum/showflat.php?Cat=&Board=linuxK&Number=363455&page=&view=&sb=&o=&vc=1%E4%B8%8A%E6%9C%89%E4%BA%9B%E4%BB%A3%E7%A0%81%E5%8F%AF%E4%BB%A5%E5%8F%82%E7%85%A7

4.4 在内核中读写文件时为什么会出现 EFAULT(-14) 错误?
    a. 内核文件系统提供的read()和write()之类的函数,期望是对用户态程序服务的,
       所以它会验证读写缓冲区不超过用户空间的上限即0xC000 0000。但现在内核中
       要读写文件,缓冲区在内核中即地址会超过0xC000 0000。
    b. 在读写文件前先得到当前fs: mm_segment_t old_fs=get_fs() ;
       并设置当前fs为内核fs: set_fs(KERNEL_DS) ;
       在读写文件后再恢复原先fs: set_fs(old_fs) ;
       set_fs()get_fs() 等相关宏在文件include/asm/uaccess.h中定义。

4.5 怎么在系统中增加一个自己的系统调用?
     去http://www.linuxaid.com.cn/engineer/ideal/kernel/new_syscall.htm
     和http://www.xenotime.net/linux/syscall_ex/%E7%9C%8B%E7%9C%8B

4.6 怎么在内核中加入自己的驱动程序?
    a. 去http://www-900.ibm.com/developerWorks/cn/linux/kernel/l-kerconf/
       index.shtml看看,了解一下整个内核的配置编译系统。
    b. 在相应位置建立自己的源码目录、文件、Makefile等。
    c. 修改上层Makefile,把自己的程序加入到内核编译系统中。
    d. 修改上层Config.in,把自己的程序加入到内核配置系统中。
    e. 确保自己的初始化函数被调用。有两种方法,一是显式调用,即在原来的系统
      初始化函数中直接加入对自己的调用,如字符设备就在drivers/char/mem.c中的
       chr_dev_init() 函数中加入,块设备就在drivers/block/llrwblk.c中的
       blk_dev_init() 函数中加入。另一种方法是用initcall,用宏 module_init 来申
      明你的初始化函数,操作系统在初始化到一定阶段后会自动通过init/main.c中
      的 do_initcalls() 函数来统一调用这些初始化函数。 module_init 宏在文件
      include/linux/init.h 中定义。

4.7 怎么通过程序得到cpu和mem使用率?
    a. 这些信息的最终来源都是/proc目录下的文件,如/proc/stat等。
    b. procps包下的命令如top、vmstat等实现了这些功能,可以参照其源代码。
    c. procps包可从Redhat发行版中得到,也可从http://www.surriel.com/procps/
      处获得。

4.8 如何获得高精度的系统时间?
    a. Linux中jiffy是时钟的基本单位,对于一般的系统来说配置成10ms。大多数时
      钟相关的系统调用都是基于jiffy,所以精度不会太高。
    b. 可以考虑使用TSC(time stamp counter)、rtc(real time clock)等寄存器来获得
      高精度时钟,具体可查看相关的硬件手册。

4.9 怎么进行系统性能调谐?
    a. IBM developworks:
         http://www-900.ibm.com/developerWorks/cn/linux/l-kperf/index.shtml
         http://www-900.ibm.com/developerWorks/cn/linux/management/tune/index.shtml
    b. Linux Performance Tuning项目:http://linuxperf.nl.linux.org/
    c. http://www.fixdown.com/article/article/724.htm

4.10 内核中怎么进行互斥?
     a. Linux内核中有两种机制实现互斥:semaphore和spinlock。semaphore是让进
       程睡眠等待资源,这一般假设无法预测资源什么时候可以获得; spin_lock 一般
       用在SMP中,它假设所等待的资源马上就会被释放,所以循环等待资源。
       semaphore只能用于非中断环境(典型的中断环境过程包括象timer之类的中断
       服务程序,softirq等)的进程间互斥,spinlock可以用于所有的进程间包括不同
       cpu的进程间的互斥,spinlock主要用于保护短小的临界区,使用时必须要特别注
       意死锁问题。
     b. semaphore是通过进程调度来实现互斥的。进程请求获取semaphore时,如果
       semaphore空闲则该进程获得semaphore,设置标志并返回;如果semaphore忙
       (其它用户已经获得semaphore)则系统构建等待队列并通过进程调度机制让本进
       程睡眠。进程释放semaphore时,系统按一定规则通过等待队列唤醒一个睡眠进
       程。对semaphore可执行up()和down()操作,详见include/asm/semaphore.h文件。
     c. spinlock主要是为SMP互斥而引入的。在请求获取spinlock时,如果空闲则获得
       spinlock,设置标志并返回。如果spinlock已经被其它用户获得而处于忙状态,
       系统就会一直占用CPU资源,不停查询spinlock的状态直到获得spinlock。


5. 其它问题
5.1 如何学习Linux内核?
     请先阅读本版精华区内核学习目录的相关文章。

5.2 如何下载精华区?
    a. 下载本站精华区详见BBShelp版置底文章“用户常见问题”。
    b. 在本站精华区ftp上找KernelTech.html.tgz(或类似文件名)文件。
    c. 2004-4月份的精华区下载
   ftp://youngcow.net/Special/smth%C2%BE%C2%AB%C2%BB%C2%AA%C3%87%C3%B8/2004-04-09CHM/KernelTech.chm
5.3 init进程是核心进程吗?init与初始进程是不是一回事?
     Linux操作系统在系统初始化之初就捏造了一个原始进程(原始进程在系统初始化
    完毕后就演化成idle进程),当系统初始化进行到一定阶段,原始进程会创建(通
    过 kernel_thread() 函数)出来init进程,init进程继续进行系统初始化工作并在最
    后执行execve("/sbin/init",…),这样init就从原来的核心进程摇身一变成用户
    进程(用户程序/sbin/init)了。init进程的pid为1,原始进程(idle进程)的
    pid为0。所有其它的进程都由init进程派生,用ps或pstree命令可以看到这一点。

5.4 initrd(.img)有什么用?
    a. initrd(.img)是一个文件系统映像,里面一般包含一些特殊的硬件模块尤其是存
      储设备如scsi/raid/ext3模块,以便在保持内核足够小的同时又支持尽可能多的硬
      件设备,常被安装程序使用。
      initrd(.img)也不是必需的,只要必要的模块编译进内核就可以不用initrd(.img)。
    b. 在使用了initrd(.img)时,系统引导的大致过程如下:
     1)Loader程序(如lilo和grub)加载内核和initrd(.img)
     2)内核解压缩initrd(.img)为正常的RAM盘文件系统并挂接为根分区
     3)执行linuxrc,在此过程中会加载硬件模块
     4)在linuxrc终止后,真正的根文件系统被挂接
     5)在根文件系统上完成正常的引导过程。对于正常的系统而言,执行/sbin/init,
       这时控制就会转到正常的大家所熟知的启动过程。而对于安装程序,只需将控制
       转到安装过程的第一阶段,由它完成后续的安装环境的加载,设备的进一步初始
       化等操作。
    c. 要使用initrd(.img)首先内核必须配置成支持initrd:
         CONFIG_BLK_DEV_RAM=y
         CONFIG_BLK_DEV_INITRD=y
       其次要在Loader脚本中增加相应指示。如在grub.conf中增加一行:
         initrd /boot/initrd-2.4.20.img
    d. 可用mkinitrd命令创建initrd(.img)文件:
         mkinitrd imagefilename kernelversion
       如对于2.4.20的内核可以:
         mkinitrd /boot/initrd-2.4.20.img 2.4.20
    e. 具体可查看Documentation/initrd.txt和man mkiinitrd。mkinitrd命令执行的详
       细过程可以直接查看/sbin/mkinitrd(shell脚本)文件。

Blogs

Linux Cross Reference

kernel blog

The Linux Kernel API

Embedded Linux Wiki

free-electrons

Author: Shi Shougang

Created: 2017-05-17 Wed 22:42

Emacs 24.3.1 (Org mode 8.2.10)

Validate