歷史記錄-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]