历史记录-A 目前FAQ维护一览: bx_bird----------------->中断管理 updated freshground----------------->内存FAQ; sirx----------------->进程管理与线程相关+内核同步 garycao----------------->内核介绍与基本配置+内核调试+内核编程; xshell----------------->内核模块编程+启动初始化; 目录: 一 Linux内核FAQ说明 二 索引 三 论坛问题 四 基本Linux文档 五 成员说明 六 Linux Kernel 1. 内核介绍和基本配置 2. 启动初始化 3. 内存管理 4. 内核同步 5. 进程管理及线程相关 6. 中断 7. 内核模块编程 8. PCI 9. 网络 10. 文件系统 11. 硬件相关 12. 内核调试 七 Linux 设备驱动程序 八 Linux 内核编程 九 Linux 资源 十 faq整理相关的声明 一 Linux内核FAQ说明 LINUX内核FAQ收集整理了中国linux论坛内核技术版讨论过的与LINUX内核相关的常见问题 .当你在接触内核的过程中碰到问题,可以先在这儿查阅是否已经有过类似的讨论,如果阅 读之后仍有疑问或者FAQ中没有涉及到你所关心的问题,请到KernelTech_CN留言. 二 索引 三 论坛问题 四 基本Linux文档 Linux驱动程序第二版 深入理解Linux内核英文版 Daniel P. Bovet & Marco Cesati O'Reilly出版 Intel关于x86体系手册 官方Linux文档网站 Linux汇编相关资源 tux.org上面的相关连接 The Linux Kernel Hackers' Guide The Linux Kernel The Linux FAQ The Linux Kernel HOWTO Kernelhacking-HOWTO Various Linux HOWTOs on specific questions BogoMips mini-HOWTO by Wim van Dorst the network drivers by Donald Becker the Linux Alpha HOWTO by Neal Crook www.kernelnewbies.org 如何提问以帮助你更快地得到答案 如何有效地提供BUG报告 五 成员说明 这里目前列出的是加入FAQ整理工作的成员名单和他们的介绍(待补) freshgound,sirx,bx_bird,garycao,xshell 六 Linux内核 I 内核介绍和基本配置 (lkml指Linux kernel Mailing List) 1. Q: 什么是试验版内核? ```A: (lkml)Linux内核版本分为两个开发树:试验树(版本号为奇数,如:1.3.xx 或 2.1.x )和稳定树(版本号为偶数,如1.2.xx,2.0.xx)。 试验树更新得很快,通常用于测试新的特 性,算法,设备驱动程序,等等。试验树的内核也许会产生奇怪的操作,这样就有可能导致数 据丢失,或者机器死锁等等。 2. Q: 什么是稳定版内核? ```A: (lkml)稳定树具有定义良好的特性,更少的bug,可靠的驱动程序。虽然稳定树的更 新比实验树慢很多,通常有一些比别的版本好的"最佳版本"。Linux的发行版通常是基于这 些"最佳版本",而不一定是最新的版本。 3. Q: 内核版本号为f.g.hhprei表示什么? ```A: (lkml)这是Linux版本f.g.hh的中间版。通常i < 5,但是也有例外,如2.0.34prei 就具有i = 1 to 16个版本。有时候"pre"会被的Linux版本维护者的名字的简写所取代。如 2.1.105ac4表示Alan Cox发布的内核版本2.1.105的第四个中间版。 4. Q: 我在哪里能下载Linux的最新内核源码? ```A: (lkml)Linux内核源码(试验树和稳定树)的主要站点是由Transmeta公司(Linus Tor valds工作的公司)维护的http://www.kernel.org/。这个站点在全球很多国家都有镜像站 点。你可以通过链接http://www.CODE.kernel.org/来访问本国的镜像站点。这里,CODE "是指国家代码。如"cn"是中国的国家代码,这样,中国的Linux内核主要镜像站点就是ht tp://www.cn.kernel.org/。 ```你也可以通过FTP访问ftp://ftp.CODE.kernel.org/pub/linux/kernel/来得到Linux内 核的patch,这是Linus发布他的Linux内核的地方。其他的著名的Linux内核hacker在"peo ple"目录下有自己的目录,他们可以在那里存放自己的内核patch。"testing"是linus存放 自己的pre-release patches的地方。pre-release patches主要是其他的开发者使用的, 以便他们可以与Linus的源码树保持同步。加上这些patch的内核可能比试验树的内核更加 危险,它可能会crash,甚至破坏你的文件系统。使用这些patch时,你需要特别地注意到 这种风险性。 5. Q: 我在哪里能下载额外的Linux的内核的patch? ```A: (lkml)有很多地方提供不同的额外的patch,这些patch可以为Linux内核增加新的功 能。这里是一个不错的站点。 6. Q: 什么是patch? ```A: patch文件(这里指Linux内核patch)是ASCII文本文件,它包含在原始代码和新代码 之间的不同部分,以及一些附加的信息,如文件名,行号。通过patch程序(man patch)可 以把这个patch加到一个现有的内核源码树上。 7. Q: 怎样制作Linux内核的patch? ```A: (lkml)你可以用diff程序(info diff)来制作patch。最简单的方式是在/usr/src目 录下建立两个源码树,建立一个链接"/usr/src/linux",链接到修改后的源码树。然后再 运行diff程序比较这两个源码树。文件/usr/src/Documentation/CodingStyle包含了更多 的详细的信息,读一读这个文件。要记住: 总是使用unified (-u) diff格式。 不要改变源码的格式,以免使diff文件不必要的变大。察看你的编辑器设置,不要把tabs 转换为空格或者相反。如果你没有特殊的原因,尽量针对最新的官方源码树做你的patch。 否则,你的patch很有可能被忽略。或者,你在你的帖子中注明你的patch所针对的Linux版 本号。 确认你的patch只包括你这个patch所需要做的改动,而不是你对源码树的所有的改动。通 常,patch限制在几个文件或目录里。最好只diff相关的文件。例如,如果我只修改了dri vers/net目录下的文件driver_xyz.c,我会用以下的指令(假定你的原始源码树目录名字为 "linux-2.4.18","linux"链接指向修改后的源码树): cd /usr/src diff -u linux-2.4.18/drivers/net/driver_xyz.c linux/drivers/net/driver_xyz.c > my_patch 8. Q: 怎样安装一个patch? ```A: (lkml)(From /usr/src/linux/README)你可以通过安装patch来升级你的Linux源码 版本。patch一般都是使用传统的gzip或比较新的bzip2压缩后的压缩文件。如果你想要通 过安装patch升级你的Linux源码版本,你需要得到所有的新的patch文件,进入到你想要升 级的内核源码目录,执行: gzip -cd patchXX.gz patch -p0 或: bzip2 -dc patchXX.bz2 patch -p0 (按顺序,为所有的版本号大于你当前的源码树的版本号的patch,重复xx),就完成了你的 升级。你也许需要移走backup文件(xxx~或xxx.orig),确认没有安装失败的patch(xxx# 或 xxx.rej)。如果这些文件存在,要么你,要么我犯了一个错误。 你也可以使用patch-kernel来自动完成这些步骤。它会根据当前的内核版本来自动安装所 有找到的patch。这样,运行命令: linux/scripts/patch-kernel linux 指令的第一个参数是内核源码的目录。patch需要存放在当前目录,或者存放在第二个参数 所指定的目录。 ```你可以察看内核的README文件(/usr/src/linux/README)的"Installing the kernel"了 解更多信息。这里是一个Linux HQ Project网站关于patch的比较好的说明。 9. Q: 每个人都在谈论"CVS tree at vger",vger是什么?这个CVS树做什么? ```A: (lkml)vger.kernel.org是一个服务于Linux社团的邮件列表和网站。一个Linux内核 开发树的CVS服务器是http://vger.samba.org/译注:现在好像不能访问?),它是最新的 vger.kernel.org的主源码树的镜像。需要注意CVS源码树不是官方的源码树,它主要是为 了方便一些资深的Linux内核hacker的使用而建立的。由Linus Torvalds所维护的网站htt p://www.kernel.org/才是官方Linux源码树存放的地方,它在全球都有镜像站点。David Miller (vger CVS tree 维护者)定期地把CVS树生成的patch提交给Linus。另外,vger C VS源码树还存放Sparc, Sparc64 和一些网络方面的试验和测试的patch。 10. Q: 我在哪里能找到更多的CVS相关的信息? A: (lkml)很多GNU/Linux的发行版都包括了CVS,你也可以访问CVS Bubbles page 11. Q: 哪里有CVS指南? A: (lkml)这是一个你可以访问的CVS指南: An interactive CVS tutorial 访问这个站点,你花15分钟就可以得到一个关于CVS工作流程的大概的概念(推荐)。由于目 前已经开发了很多的CVS图形前端工具,你可以不用学习一般的神秘的CVS指令。 12. Q: 怎样才能把我的patch加到官方Linux内核呢? A: (lkml)根据你的patch的内容的不同,有几种不同的方式把它加入官方Linux内核。首先 ,确定你所修改的代码是由谁来维护(察看MAINTANERS文件)。如果你的patch只是一个很小 的bug修复,而且你确信它"显然正确",那么,你可以把它发给适当的维护者,以及张贴到 lkml中。如果这是一个紧急的buf修复(如:一个大的安全漏洞),你也可以把它直接发给L inus,但是要记住他有可能会不理睬随意的patch,除非他认为它们"显然正确"。如果你的 patch很大,例如,大片重写的代码或一个新的设备驱动程序,为了节省网络带宽和磁盘空 间,你可以给lkml发送一个帖子来说明你的patch,并在你的帖子中加上你的patch的链接 。最后,如果你不大确信你的patch是否正确,需要一些维护者的反馈,你可以使用私信。 如果你的patch所涉及的内核部分,没有明确的维护者,那么你有三个选择: 把它发送给[email protected],希望有人能看到它来提交给Linus,或者Lin us本人会看到它(基本不要指望) 把它发给linux-kernel,并Cc:Linus Torvalds <[email protected]>。希望Linus 能够采用它。要注意没人知道Linus怎么工作,他不一定给你直接的回复。你需要检查Lin us发布的patch来看他有没有采用你的patch。如果他没有采用,你也许需要重新发送一次 你的patch(通常很多次)。如果等了几个礼拜或者几个月以后,经过了很多的patch的发布 后,他仍然没有采用你的patch,也许你应该放弃。他也许不喜欢它。 把它发给linux-kernel,并Cc:Alan Cox 。Alan在回复邮件方面做的 好一些,他会把你的patch排队,定期的把它转发给Linux,这样,你就可以不用再担心没 有人理睬它了。他总是显得品位很好,如果Alan接受了你的patch,很可能Linus也会接受 。如果他不喜欢你的patch,你也许会收到一封emain给你解释。 13. Q: 为什么Linux内核tarball包含的目录是linux而不是linux-x.y.z? A: (lkml)这是因为Linus想要这样做。这样可以使安装连续的patch更容易一些,因为不用 每次都改变目录名称,这样也让Linus的生活更加轻松一些。 14. Q: 官方Linux内核和Alan Cox的内核(ac系列的patch)有什么区别? A: (lkml)Alan的内核可以被看作Linus的内核的测试版。虽然Linus很保守,只接受明显的 和经过很好测试的2.4的内核patch,Alan维护着一系列内核patch,它们包含着新的概念, 更多(与/或)更新的驱动程序,更多的插入的patch。如果这些patch能够证明自己是稳定的 ,Alan就会把它们提交给Linus,一般把它们加入到官方Linux内核中去。 15. Q: Linux内核是由谁维护的? A: (lkml)最初,由Linus Torvalds来维护所有内核。当Linux内核成熟后,他把一些老的 稳定的版本的维护工作委派给了其他人,而他继续维护最新的开发版。在2002年5月27号, 以下的内核版本是由以下人员来维护的。 2.0 David Weinehall <[email protected]> 2.2 Alan Cox 2.4 Marcelo Tosatti <[email protected]> 2.5 Linus Torvalds <[email protected]> 16. Q: 我怎么建立我自己的内核? A: (linux天字一号) Let's step by step: **********step 1做一个新kernel出来******************** 1.从http://www.kernel.org/pub/linux/kernel/v2.4/linux-2.4.12.tar.gz将最新的稳定 版kernel down下来。 2.用mv /usr/src/linux /usr/src/linux.old将原来的目录移走,用tar xfzv linux-2.4 .12.tar.gz -C /usr/src/linux将代码解开. 3.切换到/usr/src/linux目录,执行make menUConfig 4. 可以什么都不用改,直接保存。当然也可以试着去配置内核的选项,大部分都可以直接 看出是干什么的,看不出的可以查其帮助信息。 5. 执行make dep 6. 执行make bzImage做一个压缩的内核。 7. 编译完成后,可以从/usr/src/linux/arch/i386/中找到新内核bzImage. 8. 执行make modules,编译完成后将/usr/src/linux/modules拷到/lib/modules/2.4.12目 录让系统自动加载这些驱动及模块,如果无法实现自动化,以后需要你用insmod去加载这 些东西。 ************step 2 使用这个新内核********************* 1. 用cp /usr/src/linux/arch/i386/bzImage /boot将内核复制到/boot目录。 2. 用vi /etc/lilo.conf命令来修改lilo配置文件大概如下: boot=/dev/hda map=/boot/map install=/boot/boot.b lba32 (支持大硬盘) timeout=50 (启动等待时间) default=linux (默认的启动项) other=/dev/hda1 (DOS操作系统) label=win (label) table=/dev/hda image=/boot/vmlinuz label=linux root=/dev/hda2 (hda2为旧系统的根文件系统) read-only ---------上面原系统本身会有,你需要加入下面的代码----------------- image=/boot/bzImage label=new (新系统的名字) root=/dev/hda2 (根文件系统,不一定是hda2,可根据与旧系统的根文件系统来决定) read-only 3. 执行lilo II 启动初始化 1 Q:内核启动相关的代码有哪些? A:以X86为例, arch/i386/boot/bootsect.S 引导部分; arch/i386/boot/setup.S,video.S 根据BIOS初始化硬件数据,进入保护模式,并加载内核 映象; arch/i386/kernel/head.S 页表初始化; 2 Q:内核引导时可以加参数麽?有哪些参数可以加载? A:可以.一般而言,就是在lilo引导指定内核时加参数,如root=/dev/hda??,参见 BootPrompt-Howto. 3 Q:内核引导过程中为什么不能使用0-64K直接的地址区域? A:保留给BIOS数据区,在启动过程中,启动代码使用BIOS数据区和相关的BIOS调用获取初 始化必 需的硬件信息.但是在启动后期该区域可以被覆盖使用,这也就意味着内核启动之后不能 够进行BIOS 调用. 4 Q:大内核与普通内核的分界线是多少K? A:大小在508K之内的属于普通内核,可以直接加载到0x10000,然后解压缩到0x100000,否则 加载到 0x100000后再原地解压. 5 Q:508K数值是如何得到的? A: 内核引导代码将自己从当前所在的位置0x7c00:0000跳到0x9000:0000处(即576K地址处) 继续运行.所以如果是xx普通内核则必然要求大小满足 576K - 64K(BIOS自动保留区) - 参数区4K(到底存放了什么有待商榷) = 508K 之 内. 参数区存放系统引导时接收的命令行参数和BIOS传给内核的必要的硬件信息 6 Q:如何编译链接不同类型的内核映象? A:make bzimage与make zimage分别对应了大内核与普通内核的生成方式. 7 Q:内核启动时传入的命令行参数存放在甚么位置? A: ????? 8 Q:内核启动初始时的内存如何布局? A: 0A0000 +------------------------------+ Reserved for BIOS Do not use. Reserved for BIOS EBDA. 09A000 +------------------------------+ Stack/heap/cmdline For use by the kernel real-mode code. 098000 +------------------------------+ Kernel setup The kernel real-mode code. 090200 +------------------------------+ Kernel boot sector The kernel legacy boot sector. 090000 +------------------------------+ Protected-mode kernel The bulk of the kernel image. 010000 +------------------------------+ Boot loader <- Boot sector entry point 0000:7C00 001000 +------------------------------+ Reserved for MBR/BIOS 000800 +------------------------------+ Typically used by MBR 000600 +------------------------------+ BIOS use only 000000 +------------------------------+ III 内存管理 Freshground整理结果 IV 内核同步 1 Q: 对于单cpu的系统,是不是不应该用spin_lock。如果用了,会不会降低系统的性能呢 ? A: (minihorse) > I have a question related to spin locking on UP systems.Before that I would > like to point out my understanding of the background stuff > 1. spinlocks shud be used in intr handlers It should be used in the interrupt handler, if you need to prevent any race conditions with other interrupt/non-interrupt context code that may be executing on some other CPU on an SMP system. Thus spinlocks need to be held for as short a duration as possible. You would need to use the spin_lock_irqsave/spin_unlock_irqrestore variant pair to prevent your interrupt handler from running on the same processor while holding the lock. This may be needed if the interrupt handler may try to acquire the same lock thus causing a deadlock. > 2. interrupts can preempt kernel code > 3. spinlocks are turned to empty when kernel is compiled without SMP > support. > > If a particular driver is running( not the intr handler part) and at this > time an interrupt occurs. The handler has to be invoked now. Won't the > preemption cause race conditions/inconsistencies? Is any other mechanism > used? Pl correct me if I have not understood any part of this correctly On a UP kernel the spin_lock_irqsave/spin_unlock_irqrestore pair eXPand to save_flags(flag); cli()/restore_flags(flag). The maSKINg of interrupts on the processor between spin_lock_irqsave and spin_unlock_irqrestore pair prevent the user context code from being preempted by the interrupt handler. 2 Q. 我希望在核心代码中实现对某个数据结构的保护,也就是在同一时刻只能有一个进程 对他操作,在用户进程中可以采用信号量来实现,在核心中呢? A.(BNN)Criticl Regsion is a far more famous issue which is applied to many are as including system software. Below are my 2 cents and wish helpful. ------------------------------------------------------------------ * Why need protection in kernel mode? In a Word, all data structures are shard by all processes including interrupt handlers. * How to protect critical data structures? Make sure the operations on those data structures are ATOMIC. For traditional operating systems(compared to real-time os), the kernel is non -preemptive. (We will consider SMP model later). In other words, within the ke rnel, you do NOT have to worry about the consistency of your critical data str uctures. The only thing we have to take care is all about the interrupt handle rs including ther timer. In other words, within the kernel mode, the interrupt still can branch your execution flow. In the case that an interrupt will have to work on some data structures which is shared by some kernel threads or fun ctions. We then still have to use either * cli/sti (disable/enable interrupt), * raise the corresponding IPL level, * or use some lock mechanisms to make sure the data structures consistent. Basically, for different CPU architecture, soem different **one clock cycle** instructures are provided in order to achieve the ATOMIC feature and thus impl ement the mutex or semaphore mechanisms. In other words, those instructions wi ll promise something like: atomic_add, atomic_dec, test_and_set primtives. I personally am more familiar with powerpc arch. Within powerpc, an instructio n pair called "reserve the memory bus" and "release the memory bus" are provid ed. With those two instructures, linux can provide any ATOMIC operations. For x86, conceptually, the thing should be the same. Atomic issue is very imprtant for kernel data structures. However, the size of atomic granularity is very important. For real-time opearating system which r equires that the kernel should be also preemtpive, we need make sure the criti cal area should be protected in case another either high priority process/thre ad take the cpu control away. 3 Q. 有3个进程P1,P2,P3,P1首先P(mutex)后,P2,P3阻塞,当P1释放互斥信号量V(mutex) 以后,P2,P3哪个进程先进入?根据什么原则? A. (xshell)first wait first get , FWFG. 4 Q.原子操作疑问 #define atomic_set(v,i) (((v)->counter) = (i)) static __inline__ void atomic_add(int i, volatile atomic_t *v) { __asm__ __volatile__( LOCK "addl %1,%0" :"=m" (__atomic_fool_gcc(v)) :"ir" (i), "m" (__atomic_fool_gcc(v))); } 请问为什么atomic_set(v,i)不需要用LOCK(并用汇编来写)? 而atomic_add()为什么不写成这样: #define atomic_add(i,v) (((v)->counter) += (i)) A.(nxin)在现在的体系中,一个加操作至少需要三步,从内存取数据,执行加法运算,将 结果存回内存,不可能在一个时钟周期完成,在多处理器的环境下,需要用特殊的汇编指 令保证操作的原子性。而set操作只是把数据存到内存,这个操作总是原子性的,当然如果 数据长度超过机器字的长度或不是按字边界对齐,操作可能不是原子的。 5 Q: 对于单cpu的系统,是不是不应该用spin_lock。如果用了,会不会降低系统的性能呢 ? A: (minihorse) > I have a question related to spin locking on UP systems.Before that I would > like to point out my understanding of the background stuff > 1. spinlocks shud be used in intr handlers It should be used in the interrupt handler, if you need to prevent any race conditions with other interrupt/non-interrupt context code that may be executing on some other CPU on an SMP system. Thus spinlocks need to be held for as short a duration as possible. You would need to use the spin_lock_irqsave/spin_unlock_irqrestore variant pair to prevent your interrupt handler from running on the same processor while holding the lock. This may be needed if the interrupt handler may try to acquire the same lock thus causing a deadlock. > 2. interrupts can preempt kernel code > 3. spinlocks are turned to empty when kernel is compiled without SMP > support. > > If a particular driver is running( not the intr handler part) and at this > time an interrupt occurs. The handler has to be invoked now. Won't the > preemption cause race conditions/inconsistencies? Is any other mechanism > used? Pl correct me if I have not understood any part of this correctly On a UP kernel the spin_lock_irqsave/spin_unlock_irqrestore pair expand to save_flags(flag); cli()/restore_flags(flag). The masking of interrupts on the processor between spin_lock_irqsave and spin_unlock_irqrestore pair prevent the user context code from being preempted by the interrupt handler V 进程管理及线程相关 1. Q: 如何在内核中唤醒和睡眠用户进程? A: (xshell)你可以参考interruptible_sleep_on和wake_up_interruptible的代码实现对 指定进程的睡眠与唤醒, 其中,使用interruptible_sleep_on将当前进程置入睡眠态和一睡眠进程管理队列中,该 队列中的进程可被中断唤醒,wake_up_interruptible则唤醒睡眠进程管理队列中的进程。 详细信息 2. Q: 如read, 用户没输入时候,系统调用阻塞。此时候进程(进程1)是否退出了核心执行 态,进入suspend,由内核重新调度其他进程(进程2)运行;那先前的进程1在用户输入时如 何又再次获得cpu呢??是等进程2 的时间片用完,重新调度吗 ? A: (linux_tao)进程在核心态执行系统调用,系统调用阻塞时进程转入内存睡眠状态,内 核调度其他进程运行。当睡眠进程等待的事件发生时,该进程被唤醒,转为内存就绪。之 后它被调度,进入“核心态运行”状态。在此状态下,继续完成read调用。read调用完成 后,返回用户态运行。 (sirx)不需要等到进程2的时间片用完。如果进程1等待的中断发生的时候进程2正在执行系 统调用,那么需要__等到进程2的系统调用执行完__再重新调度。如果中断发生的时候进程 2正在用户态运行,马上重新调度。 详见Linux 内核笔记2 – 进程调度 3. Q: linux中线程是不是属于内核实现的?或者是创建线程在用户级,管理在内核? A: (sirx)linux下的线程有用户态和内核态两种,但内核只创建和管理内核线程,用它们 来完成一些需要经常重复执行的工作。用户线程,就是应用程序内部的线程啦,由用户态 的线程库来生成和调度,内核从来就不知道用户线程的存在。 4. Q: 在linux下当一个进程创建了若干个线程的时候 a、这时在主进程(非线程中)内调用fork,那么子进程是如何继承父进程的线程的?是全 部还是不继承? b、若在主进程的某个线程内fork,这时这个子进程是继承父进程的全部线程还是只继承f ork它的线程或是不继承? A: (待答) 5. Q.在当前系统下,调度时间片的长度是多少? A: (sirx) 与2.2.x版的内核相比,kernel2.4.x的时间片长度缩短了,对于最高优先级的 进程来说,时间片的长度为100ms,默认优先级进程的时间片长度为60ms,而最低优先级进 程的时间片长度为10ms。 6. Q. Linux如何保证对I/O事件相对比较快的响应速度,这个响应速度是否与调度时间片 的长短有关? A: (sirx)当I/O事件发生的是时候,对应的中断处理程序被激活,当它发现有进程在等待 这个I/O事件的时候,它会激活等待进程,并且设置当前正在执行进程的need_resched标志 ,这样在中断处理程序返回的时候,调度程序被激活,原来在等待I/O事件的进程(很可能 )获得执行权,从而保证了对I/O事件的相对快速响应(毫秒级)。 从上面的说明可以看出,在I/O事件发生的时候,I/O事件的处理进程会抢占当前进程,响 应速度与调度时间片的长度无关。 7. Q.高优先级(nice)进程和低优先级进程在执行上有何区别?例如一个优先级为-19(最 高优先级)的进程和优先级为20(最低)的进程有何区别 A: (sirx)进程获得的CPU时间的绝对数目取决于它的初始counter值,初始的counter的计 算公式(sched.c in kernel 2.4.14)如下: p->counter = (p->counter >> 1) + ((20 - p->nice) >> 2) +1) 由公式可以计算出,对于标准进程(p->nice 为0), 得到的初始counter为6,即进程获 得的时间片为60ms。 最高优先级进程(nice为-19)的初始counter值为10,进程的时间片为100ms。 最低优先级进程(nice为20)的初始counter值为1,进程时间片为10ms。 结论是最高优先级进程会获得最低优先级进程10倍的执行时间,普通优先级进程接近两倍 的执行时间。当然,这是在进程不进行任何IO操作的时候的数据,在有IO操作的时候,进 程会经常被迫睡眠来等待IO操作的完成,真正所占用的CPU时间是很难比较的。 我们可以看到每次重新计算counter的时候,新的counter值都要加上它本身剩余值的一半 ,这种奖励只适用于通过SCHED_YIELD主动放弃CPU的进程,只有它在重新计算的时候coun ter值没有用完,所以在计算后counter值会增大,但永远不可能超过20。 8. Q: Linux提供的同步机制有那些? A: (garycao)(see /usr/include/目录下semaphore.h,pthread.h) 一般linux信号量分为以下几类 1. semaphore: int sem_init (sem_t *sem, int pshared, unsigned int value); int sem_wait (sem_t * sem); int sem_post (sem_t * sem); int sem_destroy (sem_t * sem); 2. mutex pthread_mutex_init pthread_mutex_lock pthread_mutex_unlock pthread_mutex_destroy 3.Condition Variables pthread_cond_init pthread_cond_wait pthread_cond_signal pthread_cond_broadcast pthread_cond_destroy VI 中断管理 bx_bird的整理 VII 模块编程 1 Q:模块编程有甚么好的起步教程? A:去Google上搜寻lkmpg(可加载内核模块编程), 也可以"Complete Linux Loadable Kern el Modules"为关键字查询.内核源码中有很多驱动都是模块编程很好的范例. 2 Q:将驱动程序以模块形式加载与作为内核的一部分使用有甚么不同? A:模块的方式减小了整个内核的大小,增加了使用的灵活性. 3 Q:内核编译后make moduels_install安装的模块存放在何处? A:对于2.4.X是/lib/modules/`uname -r`/kernel/;而2.2.X则是/lib/modules/`uname -r `/; 4 Q:模块调试有哪些工具和方法? A:最简单的是printk+dmesg,另外kgdb也是不错的选择. 5 Q:如何加载自己已经编译的模块? A:insmod ./your.o;modprobe ./your.o也可以. 6 Q:为什么我用insmod加载模块时它说找不到模块文件? A:你可以insmod后跟所要加载模块的完整路径.或者修改/etc/modules.conf增加一个新的 alias. ps,如果在rh6.2上编译2.4.X,模块安装后需要cd /lib/modules/`uname -r`/; mv kernel /* .;然后depmod -a建立modules.dep即可实现相关模块的自动加载. 7 Q:模块编程中常见的几个宏怎么使用? A:MODULE_PARM(var,type) 定义类型type的参数var,在insmod时可以通过var=???指定var 的值; 以下询息可以用/sbin/modinfo a_module 查看: MODULE_PARM_DESC(var,desc) 模块可选参数的描述; MODULE_AUTHOR(name) 模块作者; MODULE_DESCRIPTION(desc) 模块功能的描述; 8 Q:模块编程时常用的编译选项是哪些? A: CFLAGS=-DMODULE -D__KERNEL__ -I/lib/modules/`uname -r`/build/include -O2(为 你当前使用的内核编译模块) 9 Q:内核模块加载时出现版本错误该怎么办? A:说明你当前运行的内核在内核加载时检查版本询息,可以在内核配置菜单中去掉这一选项 ,另外你也可以 在编译内核时添加版本询息,即#include <linux/modversion.h>,然后重新编译再次加载. 10 Q:内核模块中如何使用系统调用? A:在模块程序中加上这几句: #define __KERNEL_SYSCALLS__ #include <linux/unistd.h> int errno; 11 Q:在内核模块编程中如何进行文件操作? A:加入open,read,close等系统调用,在使用这些文件操作的系统调用之前需要set_fs(KER NEL_DS); 12 Q:如何使当前模块的函数符号对内核其他部分是不可见的? A:在模块程序的最后一行加上EXPORT_NO_SYMBOLS即可. VIII PCI 1. Q: pci_read_config_byte, pci_read_config_word等等函数的原形在哪里? A: (hyl)/arch/i386/kernel/pci-pc.c 中有几个 pci_ops 型的变量.详细信息 IX 网络 1. Q: 怎样才能快速找到connect,socket函数实现的代码? A: (nxin)下载并解开glibc的源码,socket的实现在sysdeps/unix/sysv/linux/i386/soc ket.S中,linux的大部分系统调用都在sysdeps/unix/sysv/linux/ 或sysdeps/unix/sysv /linux/i386/ 中。系统调用最后都调用了int $0x80,有些共用同一个入口,比如socket ,connect都调sys_socketcall,但select调sys_select。 2. Q: 请教高手:Lan网卡收到包后,应该比较mac地址? ```A: (nxin)网卡可以工作在几种模式之下,比如是否接收广播,是否接收指定MAC地址, 是否接收指定多播地址,是否全部接收,一般情况不设为全部接收状态,因为这样会加重 系统负担,如果你需要可以设为混杂模式就可以全部接收了。 X 文件系统 1 Q: Linux可以打开文件数是多少 ? A: (jkl)每个进程可打开的文件数量受rlimit制约,缺省为1024,上限为1024*1024。但系 统中总的打开文件的数量受file-max和inode-max这两个参数制约,它们可以在/proc/sys /fs/中读取和调整。 XI 硬件相关 1. Q: 磁盘扇区与磁盘块如何定义以及如何区分使用? A: (m.ouyang)Basically I think, hard sector is a physical parameter got from d evice, block size is just block size, when fs layer transfers requests to ide drivers , all info are in sector expression, anyway, block size setting will a ffect io requests. For example, if you doubled block size, you may cut io requ est times(ide interrupts) to nearly a half. So in your own ide/atapi driver, y ou can define the block size as you want, but not sector size, only keep it as multiples of sector size. XII 内核调试 1. Q: 有人熟悉linux内核调试技术吗? A: (garycao)有以下几种方法: 使用kgdb通过串口来调试 bdi2000 gdb可以通过以太(bdi2000的以太,bdi2000通过bdm或jtag来调)来调.(注:x86没有 bdm和jtag调试接口) windriver vision probe(click)来调试内核,最大的不方便是看不到源码,不过如果你熟悉 汇编的话,也能调. 2. Q:为什么需要两台机器用于kgdb调试内核? A:kgdb需要gdb来处理源码并分析gcc产生的调试信息.当内核在被调试时 GDB不能运行在测试机器上.因此gdb必需在一台拥有正常运转的内核的机器 上被执行. 3. Q:用户可以在中断句柄中设置断点麽? A:当然可以.断点可以设置在内核中任何一个地方.但是kgdb不能在正被kgdb 使用的内核部分设置断点,如kgdb串行线中断句柄和"interprocessor"中断句柄. 4. Q:为什么内核和模块需要在开发机器上编译而不是测试机器上? A:gdb需要参考源代码文件和vmlinux或者模块的目标文件.因为gdb是运行在开 发机器上所以这些文件必需被提供.测试机器上仅仅需要vmlinux和模块的目标文件 即可,如果一个内核或者模块在开发机器上编译完成后,只需要把这些文件拷 贝到测试机器上.另一方面,如果在测试机器上编译的话,就需要将源文件和目标文件都 拷贝到开发机器上.所以在开发机器上直接编译比较简单. 七 Linux 设备驱动程序 1 Q: 怎样添加我的驱动程序到内核? A: (garycao)在linux 2.4中,你需要修改两个文件 config.in(也可能为Config.in)和Makefile 如:你把你的程序mydriver.c放在drivers/char目录下 1. 你可以修改drivers/char/Config.in,在合适的位置加上一行: tristate 'XXXXXXXX' CONFIG_XXXX 2. 然后你需要修改drivers/char/Makefile,在合适的位置,加上 obj-$(CONFIG_XXXX) += mydriver.o 这样,你就可以在make menuconfig时选择配置你的驱动程序了 八 Linux 内核编程 1. Q: linux 内核原代码汇编中 .align 伪指令的意思是什么? A: (rush)gas文档 For example `.align 3' advances the location counter until it a multiple of 8. If the location counter is already a multiple of 8, no change is needed. 比如.align 3,2的三次方就是8,也就是要对齐在8边界,比如你现在所在的byte是5,那 .align 3之后那个变量就会在8,中间自动插了2个内容为null的byte。如果是在程序代码 段中则会插入nop操作码,如果我没理解错的话。 2. Q: start_kernel里面的prof_shift干什么用的 ? if (prof_shift) { prof_buffer = (unsigned int *) memory_start; /* only text is profiled */ prof_len = (unsigned long) &_etext - (unsigned long) &_stext; prof_len >>= prof_shift; memory_start += prof_len * sizeof(unsigned int); memset(prof_buffer, 0, prof_len * sizeof(unsigned int)); } prof_buffer分配做什么用的,prof在原代码里什么意思 A: (xshell)prof means profile,也许译成"概要"比较合适,这里是内核对自身代码使用情 况的一个统计 这段代码的意思是你是否想通过在启动命令行中设置profile="整型参数n"将内核分成pro f_shift=n个部分以便检查内核各部分代码使用的频繁程度 prof_buffer当然是内核存放那些统计记录的地址区域 init/main.c中该函数用于从命令行接受启动参数profile,赋值给prof_shift 135 static int __init profile_setup(char *str) 136 { 137 int par; 138 if (get_option(&str,&par)) prof_shift = par; 139 return 1; 140 } 与之相关的有/proc/profile and /usr/sbin/readprofile,当然必需在启动时加profile= integer,否则没有的啊 3. Q: System.map中的几个标志T,t,B,b,..的问题 ? A: (ytang)refer from binutils documents: The symbol type. At least the following types are used; others are, as well, d epending on the object file format. If lowercase, the symbol is local; if uppe rcase, the symbol is global (external). A The symbol's value is absolute, and will not be changed by further linking. B The symbol is in the uninitialized data section (known as BSS). C The symbol is common. Common symbols are uninitialized data. When linking, mul tiple common symbols may appear with the same name. If the symbol is defined a nywhere, the common symbols are treated as undefined references. For more deta ils on common symbols, see the discussion of -warn-common in Linker options. D The symbol is in the initialized data section. G The symbol is in an initialized data section for small objects. Some object fi le formats permit more efficient Access to small data objects, such as a globa l int variable as opposed to a large global array. I The symbol is an indirect reference to another symbol. This is a GNU extension to the a.out object file format which is rarely used. N The symbol is a debugging symbol. R The symbol is in a read only data section. S The symbol is in an uninitialized data section for small objects. T The symbol is in the text (code) section. U The symbol is undefined. V The symbol is a weak object. When a weak defined symbol is linked with a norma l defined symbol, the normal defined symbol is used with no error. When a weak undefined symbol is linked and the symbol is not defined, the value of the we ak symbol becomes zero with no error. W The symbol is a weak symbol that has not been specifically tagged as a weak ob ject symbol. When a weak defined symbol is linked with a normal defined symbol , the normal defined symbol is used with no error. When a weak undefined symbo l is linked and the symbol is not defined, the value of the weak symbol become s zero with no error. 4. Q: 为什么需要copy_from_user ? A: (xshell) 1. copy_from_user中的fixup的作用是为了修补当缺页异常在中断上下文中发生时保证co py_from_user的正常返回,其返回值为尚未成功copy的字节数,如果在非中断上下文的情况 下,发生用户空间或内核空间地址缺页异常仍然按照一般的缺页异常的处理方式调页.所以 copy_from_user在使用上具有通用性 2. 内核地址空间中可以发生缺页异常,但是并不真正地调页,这仅仅是为了遵循MMU的缺 页机制而已,同时也做一些缺页检查,这一点可以在fault.c中的do_page_fault()的vmall oc_fault:中找到答案 5. Q: wmb是干吗的函数 ? A: (xshell)在指令序列中放一个wmb的效果是使得指令执行到该处时,把所有缓存的数据 写到该写的地方,同时使得wmb前面的写指令一定会在wmb的写指令之前执行 6. Q: 宏#与##有什么区别 ? A: (jkl)宏定义中的"#"前缀将参数替换成字符串,例如 #define test(x) #x test(123) 被替换成字符串"123"; "##"用于连接参数,例如 #define test(x,y) ##x##y test(123,456) 替换成123456; 因此BI(0x0,0)替换成BUILD_IRQ(0x00),"pushl $"#nr"-256nt"替换成"pushl $""0x00 ""-256nt" cpp.info手册对此有详细说明。 7. Q: __attribute__是什么意思? A: (jkl)__attribute__是gcc的关键字,用以描述变量属性,如: __attribute__((regparm(0))) int printk(const char * fmt, ...) __attribute__ (( format (printf, 1, 2)));禁止printk使用寄存器传递调用参数,并将printk的参数1作为 printf格式串,从参数2开始检查其类型;详细信息 8. Q: 请问_end在那儿定义的 ? (2.0.34里的archi386kernelsetup.c中的_end变量line number 162) A: (jkl)_end是连接器ld定义的,每个ELF格式的应用程序都可以使用此符号。参见vmlin ux.lds文件. ld的脚本里面可以定义许多东西。info ld可以了解ld脚本的编写。 9. Q: .prvious是什么意思 ? A: (jkl).previous伪指令恢复当前段的前一个段作为当前段,由于ELF中允许用.section自定义段,这里的.previous作用就是恢复.text作为当前段。 或许应该说恢复到当前.section定义之前的段作为当前段。 10. Q: volatile是什么意思 ? A: (onfirelinux)volatile指一个变量可能随时由于外界地变化而变化。详细信息 11. Q: 什么是信号 ? A: (sirx)信号是UNIX进程间通信的一种标准方式,在最早期的UNIX系统中已经存在。信号的出现允许内核和其它进程通知进程特定事件的发生。现代UNIX中也存在其它的进程间通信方式,但由于信号相对简单和有效,它们仍然被广泛使用。 详细信息 九 Linux 资源 十 faq整理相关的声明 1.关于faq faq应该是一些基础性的资料,应该是简明扼要,需要展开的话就应该属于精华文档应该收录的内容. 2.关于作者署名. 为了表示对作者的尊重,尽量注明作者名称.不过如果答案是由3人以上讨论得出的,或者没法确定作者的,则不进行署名. 3.faq使用"早发布,多发布原则" 4.faq风格尽量参考别人成熟的格式.http://www.tux.org/lkml/ -- 我是谁? ※ 来源:.农大BBS http://bbs.cau.edu.cn[FROM: 61.149.2.231]
[1] [2] 下一页
(出处:http://www.sheup.com)