<!doctype linuxdoctr system [
<!entity processor SYSTEM "processor.sgml">
<!entity k-source SYSTEM "k-source.sgml">
<!entity data-structure SYSTEM "data-structure.sgml">
<!entity manifesto SYSTEM "manifesto.sgml">
<!entity gpl SYSTEM "gpl.sgml">
<!entity glossary SYSTEM "glossary.sgml">
]>


<article>
<title>The Linux Kernel</title>
<author>David A Rusling <tt>david.rusling@arm.com</tt></author>
<date>v0.8-3 January 25, 1999</date>
<trans>JF Project
<tdate>v0.8-3 December 2000


<!--Copyright  \0151996-1999        
DavidARusling david.rusling@digital.com
REVIEW,Version0.8-3
January25,1999-->



<abstract>
<!--
This book is for Linux enthusiasts who want to know how the Linux kernel 
works. It is not an internals manual. Rather it describes the principles and 
mechanisms that Linux uses; how and why the Linux kernel works the way that it
does. 
Linux is a moving target; this book is based upon the current, stable,
2.0.33 sources as those are what most individuals and companies are now using.
This book is freely distributable, you may copy and redistribute it under 
certain conditions. Please refer to the copyright and distribution statement.
-->
<htmlurl url="./The-Linux-Kernel-images/frame.html" name="*フレーム表示*">


本書は、Linux カーネルの仕組みを知りたい Linux 愛好家のためのものです。これは
内部構造のマニュアルではありません。むしろ Linux で使用されている原理や
メカニズムを解説したものであり、Linux の動作原理とはどういうもので、なぜそれ
が採用されているのかを説明するものです。

Linux という対象は常に変化しています。本書がベースにしているのは現在の安定
版である 2.0.33 のカーネルソースですが、これは個人や法人の大部分で使用されて
いるのがこのバージョンだからです。

また、本書は自由に配布してもらってかまわないので、一定の条件のもとにではあり
ますが、複製や再配布が可能です。詳細は、<ref id="chapter_cn" 
name="著作権と配布条件">を参照して下さい。

(訳注: ご利用に際して、<ref id="chapter_jp" name="日本語訳について">を
お読みください。)

</abstract>

<toc>


<!--Preface-->
<sect>
はじめに
<p>

<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/penguin2.gif">
</figure>


<!--
Linux is a phenomenon of the Internet. Born out of the hobby project of a 
student it has grown to become more popular than any other freely available 
operating system. To many Linux is an enigma. How can something that is free 
be worthwhile?  In a world dominated by a handful of large software 
corporations, how can something that has been written by a bunch of "hackers" 
(sic)hope to compete?  How can software contributed to by many different 
people in many different countries around the world have a hope of being 
stable and effective?  Yet stable and  effective it is and compete it does.
Many Universities and research establishments use it for their everyday 
computing needs. People are running it on their home PCs and I would wager 
that most companies are using it somewhere even if they do not always realize
that they do. Linux is used to browse the web, host web sites, write theses, 
send electronic mail and, as always with computers, to playg ames. Linux is 
emphatically not a toy; it is a fully developed and professionally written 
operating system used by enthusiasts all over the world.
-->
<p>Linux は、インターネットの産物である。ひとりの学生の趣味のプロジェクトから
出発し、フリーに入手できる他のどんなオペレーティングシステムよりもポピュラー
なものに成長した。
しかし、多くのひとにとって Linux は謎である。フリーなものに価値があるなどという
ことがあり得るのか？ 一握りの巨大ソフトウェア企業に支配された世界において、
いわゆる「ハッカー」連中の書いたもので太刀打ちできるのか？ 世界中の様々な国の
多様な人間が関わって作られたソフトウェアに、安定性と効率を期待できるだろうか？ 
だが、それは安定と効率そのものであり、現に市販製品と競合している。
多くの大学や有名な研究機関において、Linux は日ごとの計算処理の要求を満たす
ために使用されている。個々人が自宅の PC 上で走らせているし、おそらく大部分の
会社でも、かならずしも意識されているわけではないかもしれないが、使用されている
だろう。
Linux の使用目的は、ウェブの閲覧、ウェブサイトのホスティング、そのウェブ
コンテンツの作成、電子メールの送信、そしてコンピュータの常として、ゲームで
遊ぶことなど様々だろう。だが、Linux は、断じておもちゃではない。
本当のプロフェッショナルによって書かれ、全世界に熱心なユーザを持つ、完全に
成熟したオペレーティングシステムである。

<!--
The roots of Linux can be traced back to the origins of Unix. In 1969, Ken
Thompson of the Research Group at Bell Laboratories began experimenting on a
multi-user, multi-tasking operating system using an otherwise idle PDP-7. He 
was soon joined by Dennis Richie and the two of them, along with other 
members of the Research Group produced the early versions of Unix. Richie was 
strongly influenced by an earlier project, MULTICS and the name Unix is 
itself a pun on the name MULTICS. Early versions were written in assembly 
code, but the third version was rewritten in a new programming language, C.
C was designed and written by Richie expressly as a programming language for 
writing operating systems. This rewrite allowed Unix to move on to the more 
powerful PDP-11/45 and 11/70 computers then being produced by DIGITAL. The 
rest, as they say, is history. Unix moved out of the laboratory and into 
main stream computing and soon most major computer manufacturers were 
producing their own versions.
-->
<p>Linux のルーツは、Unix の起源にまで遡る。1969 年、ベル研究所の研究グループ
の一員であった Ken Thompson は、当時誰も使っていなかった PDP-7 上でマルチ
ユーザ、マルチタスクのオペレーティングシステムの実験を始めた。
まもなく Dennis Richie がそれに加わり、ふたりは、研究グループの他のメンバー
からの協力も得て Unix の初期バージョンを生み出した。Richie は、それ以前の 
MULTICS プロジェクトから大きな影響を受けていたので、その Unix という名称
自体も MULTICS という名前をもじったものである。
初期のバージョンはアセンブリコードで記述されていたが、三度目のリリースでは 
C 言語で書き換えらている。C は、オペレーティングシステムを記述するためのプログ
ラミング言語として Richie が特別に作成したものであった。この書き直しによって、
Unix は、よりパワフルな PDP-11/45 や 11/70 といった当時 DIGITAL(DEC) で生産さ
れたばかりのコンピュータに移植することが可能になった。彼ら自身も述べている
ことだが、それは歴史的事件にまで発展する。
Unix は研究所内に留まらず、コンピュータのメインストリームとなり、間もなく
メジャーなコンピュータメーカの大部分が自社バージョンを製造するようになった。

<!--
Linux was the solution to a simple need. The only software that Linus Torvalds,
Linux's author and principle maintainer was able to afford was Minix. Minix is
a simple, Unix like, operating system widely used as a teaching aid. Linus was
less than impressed with its features, his solution was to write his own 
software. He took Unix as his model as that was an operating system that he 
was familiar with in his day to day student life. He started with an Intel 
386 based PC and started to write. Progress was rapid and, excited by this, 
Linus  offered his efforts to other students via the emerging world wide 
computer networks, the nmainly used by the academic community. Others saw the
software and started contributing. Much of this new softwarewa sit self the
solution to a problem that one of the contributors had. Before long, Linux had
become an operating system. It is important to note that Linux contains no 
Unix code, it is a rewrite based on published POSIX standards. Linux is built
with and uses a lot of the GNU ( GNU's Not Unix ) software produced by the 
Free Software Foundation in Cambridge, Massachusetts.
-->
<p>
Linux は、必要の産物であった。Linux の作者であり監修者でもある Linus Torvalds 
にとって、当時入手可能な唯一のソフトウェアは Minix だった。Minix とは、
(当時)教育目的で広く使用されていた、シンプルで Unix ライクなオペレーティング
システムのことである。
Linus は Minix の機能に魅力を感じなかったため、自分自身の
ソフトウェアを書くことで解決しようとした。彼は、学生としての日々の生活で使い
慣れたオペレーティングシステムである Unix をモデルに選んだ。そして、Intel 
386 ベースの PC を使って、コードを書き始める。進歩はめざましく、それに
勢いを得た Linus は、当時動き始めた世界規模のネットワーク、主に研究者の
コミュニティー内で使用されていたネットワーク経由で、その成果を他の学生たちに
提供した。彼らは、そのソフトウェアを見て、自分たちもそのプロジェクトに関わり
始めた。彼らが提供した新しいソフトウェアの多くは、提供者自身が直面した問題
への解決策であった。そしてまもなく、Linux はひとつのオペレーティングシステムと
なるに到る。
注意すべきなのは、Linux は Unix のコードを含んでいないということ
である。Linux は出版された POSIX 規格をもとに書き直されたものだからだ。
また、Linux は、GNU(GNU's Not Unix の略称)の多くのソフトウェアによって
構築されており、それを数多く実装している。GNU ソフトウェアは、
マサチューセッツのボストンにある Free Software Fundation が作成した 
ものである。

<!--
Most people use Linux as a simple tool, often just installing one of the 
many good CDROM-based distributions. A lot of Linux users use it to write 
applications or to run applications written by others. Many Linux users read 
the HOWTOs avidly and feel both the thrill of success when some part of the 
system has been correctly configured and the frustration of failure when it 
has not. A minority are bold enough to write device drivers and  offer kernel 
patches to Linus Torvalds, the creator and maintainer of the Linux kernel. 
Linus accepts additions and modifications to the kernel sources from anyone,
anywhere. This might sound like a recipe for anarchy but Linus exercises 
strict quality control and merges all new code into the kernel himself. At any
one time though, there are only a handful of people contributing sources to 
the Linux kernel.
-->
<p>大部分の人にとって、Linux は単なる道具である。良く出来た CD-ROM ベース
のディストリビューションは多数あるので、そのひとつをインストールするだけで、
たいていすぐに利用できる。多くの Linux ユーザは、それでアプリケーションを書い
たり、他人が書いたアプリケーションを実行する。たくさんのユーザが、HOWTO
<ref id="chapter_intro_fn1" name="(脚注1)"> を熱心に読ん
で、システムの一部を正しく設定できたときにはその成功を喜び、うまくいかない
ときは失敗でがっかりする。小数の人は、大胆にもデバイスドライバを書
いたり、カーネルパッチを作ったりしてカーネル作成者であり管理者でもある Linus に
送ったりする。
Linus は、どこの誰からでもカーネルソースへの追加や変更を受け付けている。この
ような方法は、混乱を生み出すだけのように思えるかもしれない。しかし、Linus は
厳格な品質管理を行っており、カーネルへの新しいコードの追加は彼自身が行って
いる。とはいえ、どんなときも、Linux カーネルソースに貢献する人々は小数だが
存在する。

<!--
The majority of Linux users do not look at how the operating system works, 
how it fits together. This is a shame because looking at Linux is a very good
way to learn more about how an operating system functions. Not only is it well
written, all the sources are freely available for you to look at. This is 
because although the authors retain the copyrights to their software, they 
allow the sources to be freely redistributable under the Free Software 
Foundation's GNU Public License. At first glance though, the sources can be 
confusing; you will see directories called kernel, mm and net but what do they
contain and how does that code work? What is needed is a broader understanding
of the overall structure and aims of Linux. This, in short, is the aim of this
book: to promote a clear understanding of how Linux, the operating system, 
works. To provide a mind model that allows you to picture what is happening 
within the system as you copy a file from one place to another or read 
electronic mail. I well remember the excitement that I felt when I first 
realized just how an operating system actually worked. It is that excitement 
that I want to pass on to the readers of this book.
-->
<p>Linux ユーザの大半は、オペレーティングシステムの仕組みや内部での相互作用を
調べようとはしない。これは残念なことだ。Linux を調べることは、オペレーティング
システムの仕組みについて多くを学ぶ非常によい方法だからである。Linux はよく
書かれたオペレーティングシステムであるだけでなく、そのすべてのソースコードを
自由に入手して調べることが可能になっている。作者はソフトウェアに対する著作
権を保持しているが、Free Software Foundation の <ref id="chapter_gpl" 
name="GNU General Public License"> の
もとでソースの自由な配布を許しているからである。しかし、初めてソースを眺めた
ときには混乱するかもしれない。kernel, mm, net などのディレクトリがあるのは
わかるが、それに何が含まれるのか、どのコードがどういう役割を果たしているのか
見当がつかない。必要なのは、Linux 全体の構造と目的を鳥瞰して、理解すること
である。つまり、これが本書の目的である。すなわち、Linux という
オペレーティングシステムの仕組みについてはっきりとした理解を促進すること
である。ファイルをある場所から別の場所にコピーしたり、電子メールを読んだりする
ときに、何が起こっているのかを思い描けるような心象を提供することである。
オペレーティングシステムの実際の動きについて初めて理解できたときに感じた興奮
をわたしは今も鮮明に覚えている。わたしが本書の読者に伝えたいのは、そのときの
興奮である。

<!--
My involvement with Linux started late in 1994 when I visited Jim Paradis who
was working on a port of Linux to the Alpha AXP processor based systems. I
had worked for Digital Equipment Co. Limited since 1984, mostly in networks
and communications and in 1992 I started working for the newly formed Digital
Semiconductor division. This division's goal was to enter fully into the 
merchant chip vendor market and sell chips, and in particular the Alpha AXP 
range of microprocessors but also Alpha AXP system boards outside of Digital. 
When I first heard about Linux I immediately saw an opportunity to have fun. 
Jim's enthusiasm was catching and I started to help on the port. As I worked 
on this, I began more and more to appreciate not only the operating system but
also the community of engineers that produces it. 
-->
<p>わたしが Linux に関わり始めたのは、1994 年の終わり頃、当時 Alpha AXP ベース
のシステムへの Linux の移植作業をしていた Jim Paradis を訪ねたときだった。その
頃、わたしは 1984 年以来 Digital Equipment Co.Limited でネットワークとコミュ
ニケーションに関する仕事をしていて、1992 年には、新しく設立された電子半導体
部門で働き始めていた。この部門の目的は、商用チップ製造市場に完全に参入して、
Alpha AXP シリーズのマイクロプロセッサを中心に、Alpha AXP システムボードを
他社にも販売するということであった。Linux の話を初めて聞いたとき、
わたしはすぐに面白いことができそうだと思った。Jim の熱心さが伝染して、わたしも
移植の手伝いをしはじめた。その作業をするうちに、わたしはそのオペレーティング
システムだけでなく、それを作り出したエンジニアのコミュニティーをもより深く
敬愛するようになっていった。

<!--
However, Alpha AXP is only one of the many hardware platforms that Linux
runs on. Most Linux kernels are running on Intel processor based systems but a
growing number of non-Intel Linux systems are becoming more commonly
available. Amongst these are Alpha AXP, ARM, MIPS, Sparc and PowerPC. I
could have written this book using any one of those platforms but my
background and technical experiences with Linux are with Linux on the Alpha
AXP and, to a lesser extent on the ARM. This is why this book sometimes uses
non-Intel hardware as an example to illustrate some key point. It must be noted
that around 95% of the Linux kernel sources are common to all of the hardware
platforms that it runs on. Likewise, around 95% of this book is about the
machine independent parts of the Linux kernel. 
-->
<p>しかし、Alpha AXP は、Linux が走る多くのハードウェアプラットフォームのひと
つでしかない。大部分の Linux カーネルは、Intel プロセッサベースのシステムで
動いているが、Intel 以外の Linux システムの数もだんだんと増えていて、入手も
しやすくなってきている。それらの中には、Alpha AXP, ARM, MIPS, Sparc, それに 
PowerPC などがある。それらのひとつを選んでこの文書を書くこともできたのだが、
わたしのバックグラウンドと技術的経験は、Alpha AXP 上の Linux 
のものであり、それより少し程度は低いが ARM 上のものである。本書で、重要な
点について解説するときに Intel 以外のハードウェアを例に挙げるのは、そのため
である。ただ、Linux カーネルのソースの約 95% はどのようなハードウェアプラット
フォームにも当てはまるものとなっている。同様に、本書の約 95 % も、マシンに依存
しない部分の Linux カーネルの解説となっている。

<!--Reader Profile-->
<sect1>想定する読者<label id="chapter_intro_sect1">

<!--
This book does not make any assumptions about the knowledge or experience
of the reader. I believe that interest in the subject matter will encourage a
process of self education where neccessary. That said, a degree of familiarity
with computers, preferably the PC will help the reader derive real benefit from
the material, as will some knowledge of the C programming language. 
-->
<p>この文書は、読者の知識や経験を前提としていない。この主題に興味があるなら、
必要なものは自分から学ぶようになると信じているからである。ただ、コンピュータ、
できれば PC について知っていると、本書から実際に得るものがあるだろうし、C 言語
の知識もあると役立つだろう。

<!--Organisation of this Book-->
<sect1>本書の構成<label id="chapter_intro_sect2">
<!--
This book is not intended to be used as an internals manual for Linux. Instead
it is an introduction to operating systems in general and to Linux in 
particular. The chapters each follow my rule of ``working from the general to 
the particular''. They first give an overview of the kernel subsystem that 
they are describing before launching into its gory details. 
-->
<p>本書では、Linux 内部の作業マニュアルとして使用されることを意図していない。
むしろ、オペレーティングシステム一般の入門書であり、そのなかで特に Linux を
取り上げている。各章は、わたしのルールである「一般から個別へ」という原則に
従って構成されている。つまり、実際にカーネルの内部で動いているコードの詳細
についていきなり説明を始めるのではなく、まずその章で扱うカーネルサブシステム
の概要を確認することから始めている。

<!--
I have deliberately not described the kernel's algorithms, its methods of doing
things, in terms of routine_X() calls routine_Y() which increments the
foo field of the bar data structure. You can read the code to find these things
out. Whenever I need to understand a piece of code or describe it to someone
else I often start with drawing its data structures on the white-board. So, I
have described many of the relevant kernel data structures and their
interrelationships in a fair amount of detail. 
-->
<p>カーネルのアルゴリズムについての叙述は意図的に省いている。
<tt>routine_X()</tt> が <tt>routine_Y()</tt> を呼び出し、それが <tt>foo</tt> 
データ構造内の <tt>bar</tt> フィールドをインクリメントするといった動作方法は
述べていない。そうしたことは、コードを読めばわかるからだ。コードの一部を理解
したり、それを誰かに説明したりする必要があるとき、わたしはよくホワイトボード
にデータ構造を描くことから始める。したがって、わたしは、関係のあるカーネルの
データ構造とそれらの相互関係についてはかなり詳細に述べている。

<!--
Each chapter is fairly independent, like the Linux kernel subsystem that they
each describe. Sometimes, though, there are linkages; for example you cannot
describe a process without understanding how virtual memory works. 
-->
<p>各章は完全に独立している。これは、各章で述べる Linux のカーネルサブシステ
ムが独立しているのと同じである。しかし、ときには関連する事柄もある。たとえば、
仮想メモリの仕組みを理解しないと、プロセスを解説できないといったことである。

<!--
The Hardware Basics chapter (Chapter  hw-basics-chapter) gives a brief
introduction to the modern PC. An operating system has to work closely with
the hardware system that acts as its foundations. The operating system needs
certain services that can only be provided by the hardware. In order to fully
understand the Linux operating system, you need to understand the basics of
the underlying hardware. 
-->
<p><ref id="chapter_hb" name="「ハードウェアの基本」">の章は、現代の PC に関
する簡単な入門となっている。
オペレーティングシステムは、ハードウェアと密接に関連して動作しており、ハード
ウェアはオペレーティングシステムの基礎として働く。オペレーティングシステム
は、ハードウェアでしか提供できないサービスを必要とする。Linux オペレーティン
グシステムを完全に理解するには、その基礎となっているハードウェアの基本を理解
する必要がある。

<!--
The Software Basics chapter (Chapter  sw-basics-chapter) introduces basic
software principles and looks at assembly and C programing languages. It looks
at the tools that are used to build an operating system like Linux and it 
gives an overview of the aims and functions of an operating system. 
-->
<p><ref id="chapter_sb" name="「ソフトウェアの基本」">の章では、ソフトウェア
の基本的な原理を説明し、アセンブリと C 言語を概観する。Linux 等のオペレー
ティングシステムを構築するために使用されるツールについて述べ、オペレーティン
グシステムの目的と機能について概説する。

<!--
The Memory Management chapter (Chapter  mm-chapter) describes the way
that Linux handles the physical and virtual memory in the system. 
-->
<p><ref id="chapter_mm" name="「メモリ管理」">の章では、システム上の物理メモ
リと仮想メモリを Linux がどう扱っているのかについて述べる。

<!--
The Processes chapter (Chapter  processes-chapter) describes what a
process is and how the Linux kernel creates, manages and deletes the
processes in the system. 
-->
<p><ref id="chapter_p" name="「プロセス」">の章では、プロセスとはなにか、
Linux はシステム上でプロセスをどのように生成し、管理し、削除するのかを説明
する。

<!--
Processes communicate with each other and with the kernel to coordinate their
activities. Linux supports a number of Inter-Process Communication (IPC)
mechanisms. Signals and pipes are two of them but Linux also supports the
System V IPC mechanisms named after the Unix TM release in which they first
appeared. These interprocess communications mechanisms are described in
Chapter  IPC-chapter. 
-->
<p>プロセスは、互いに協調して働くため、他のプロセスやカーネルと通信している。
Linux は、いくつかのプロセス間通信(IPC)のメカニズムをサポートしている。シグナル
とパイプはそのうちのふたつだが、Linux は System V IPC もサポートしている。この
名称は、初めてその仕組みが登場したのが Unix の当該リリースの時だったからで
ある。これらプロセス間通信のメカニズムは、<ref id="chapter_ipc" 
name="「プロセス間通信の仕組み」">の章で説明する。

<!--
The Peripheral Component Interconnect (PCI) standard is now firmly
established as the low cost, high performance data bus for PCs. The PCI
chapter (Chapter  PCI-chapter) describes how the Linux kernel initializes and
uses PCI buses and devices in the system. 
-->
<p>PCI(Peripheral Component Interconnect) 規格は、PC 上の低価格・高性能のデータ
バスとして今日ではその立場を確立している。<ref id="chapter_pci" 
name="「 PCI 」">の章では、Linux が、システム上で、PCI バスとそのデバイスを
初期化して使用する方法を説明する。

<!--
The Interrupts and Interrupt Handling chapter (Chapter  interrupt-chapter)
looks at how the Linux kernel handles interrupts. Whilst the kernel has generic
mechanisms and interfaces for handling interrupts, some of the interrupt
handling details are hardware and architecture specific. 
-->
<p><ref id="chapter_i" name="「割り込みと割り込み処理」">の章では、Linux の
割り込み処理の方法について説明する。カーネルは割り込み処理についての汎用
メカニズムとインターフェイスを備えているが、割り込み処理の詳細の中には、
ハードウェアやアーキテクチャに依存するものもある。

<!--
One of Linux's strengths is its support for the many available hardware devices
for the modern PC. The Device Drivers chapter (Chapter  dd-chapter)
describes how the Linux kernel controls the physical devices in the system. 
-->
<p>
Linux の長所のひとつは、現代の PC 向けの多くのハードウェアデバイスをサポート
していることだ。<ref id="chapter_dd" name="「デバイスドライバ」">の章では、
システム上の物理デバイスを Linux がどのように管理しているのか説明する。

<!--
The File system chapter (Chapter  filesystem-chapter) describes how the
Linux kernel maintains the files in the file systems that it supports. It 
describes the Virtual File System (VFS) and how the Linux kernel's real file 
systems are supported. 
-->
<p><ref id="chapter_fs" name="「ファイルシステム」">の章では、Linux 上で
サポートされているファイルシステムをカーネルがどのように維持管理しているのか
を説明している。仮想ファイルシステム(Virtual File System)について述べ、
Linux カーネルの実(real)ファイルシステムがどのようにサポートされているのかを
解説している。

<!--
Networking and Linux are terms that are almost synonymous. In a very real
sense Linux is a product of the Internet or World Wide Web (WWW). Its
developers and users use the web to exchange information ideas, code and
Linux itself is often used to support the networking needs of organizations.
Chapter  networks-chapter describes how Linux supports the network
protocols known collectively as <tt>TCP/IP</tt>. 
-->
<p>ネットワークと Linux とは、ほぼ同義語である。本当の意味で、Linux は
インターネットやウェブ(WWW)の産物なのである。開発者とユーザは、ウェブを使って
情報やアイデアやコードを交換しているし、Linux 自体が、しばしば組織のネット
ワークへの要求を満たすために使用されている。<ref id="chapter_net" 
name="「ネットワーク」">の章では、Linux が、<tt>TCP/IP</tt> と総称されている
ネットワークプロトコルをどのようにサポートしているかについて解説する。

<!--
The Kernel Mechanisms chapter (Chapter  kernel-chapter) looks at some of
the general tasks and mechanisms that the Linux kernel needs to supply so that
other parts of the kernel work effectively together. 
-->
<p><ref id="chapter_km" name="「カーネルメカニズム」">の章では、カーネルの一部
が他の部分と協調して効率よく機能するために、Linux カーネルが提供しなければな
らない一般的なタスクとメカニズムについて解説する。

<!--
The Modules chapter (Chapter  modules-chapter) describes how the Linux
kernel can dynamically load functions, for example file systems, only when they
are needed. 
-->
<p><ref id="chapter_m" name="「モジュール」">の章では、カーネルが、たとえば
ファイルシステムのサポートなどの機能を、必要なときに動的にロードする仕組みに
ついて説明する。

<!--
The Processors chapter (Chapter  processors-chapter) gives a brief
description of some of the processors that Linux has been ported to. 
-->
<p><ref id="chapter_proc" name="「プロセッサ」">の章では、Linux が移植されてい
るいくつかのプロセッサについての概要を説明する。

<!--
The Sources chapter (Chapter  sources-chapter) describes where in the Linux
kernel sources you should start looking for particular kernel functions. 
-->
<p><ref id="chapter_ks" name="「Linux カーネルソース」">の章では、特定の
カーネル関数を探すときソースのどこから探し始めるべきかについて説明する。

<!--Conventions used in this Book-->
<sect1>この文書での表記規則<label id="chapter_intro_sect3">

<!-- The following is a list of the typographical conventions used in this 
book.-->
<p>
この文書では、次のような表記規則を採用している。

<!--
serif font 
           identifies commands or other text that is to be typed 
           literally by the user. 
type font 
           refers to data structures or fields 
           within data structures.
-->

<verb>
 serif font   コマンドや、ユーザが文字どおりにタイプすべきテキストの場合

 type font    データ構造およびそのデータ構造の中のフィールドを示す場合
</verb>
(訳注: 訳文では、どちらも等幅フォントで示しています。)

<!--
Throughout the text there references to pieces of code within the Linux kernel
source tree (for example the boxed margin note adjacent to this text ). These 
are given in case you wish to look at the source code itself and all of the 
file references are relative to /usr/src/linux. Taking foo/bar.c as an example,
the full filename would be /usr/src/linux/foo/bar.c If you are running
Linux (and you should), then looking at the code is a worthwhile experience and
you can use this book as an aid to understanding the code and as a guide to its
many data structures. 
-->
<p>この文書のいたるところに、Linux カーネルのソースツリー内のコードの一部への
参照が付されている。(たとえば、文章のすぐそばにある、四角で囲った記述など。) 
(訳注: 原著では HTML 版以外の PS 版などに付けられています。訳文では、[ ] で
囲って、文中に記述しました。)
それらは、読者が実際にソースそのものを見たい場合を考えて付したものであり、
すべての参照ファイルは、<tt>/usr/src/linux</tt> からの相対位置にある。
たとえば、<tt>/foo/bar.c</tt> を例にとると、ファイルのフルネームは <tt>
/usr/src/linux/foo/bar.c</tt> である。Linux を使っているなら(そうであって欲しい
のだが)、コードを見ることは価値のある経験であり、本書をコードへの理解と
データ構造への手引きとして利用することができる。

<!--Trademarks-->
<sect1>商標について<label id="chapter_intro_sect4">
<p>(訳注: 以下は、原文のままです。)
<!--
ARM is a trademark of ARM Holdings PLC. 

Caldera, OpenLinux and the ``C'' logo are trademarks of Caldera, Inc. 

Caldera OpenDOS 1997 Caldera, Inc. 

DEC is a trademark of Digital Equipment Corporation. 
-->
<p>
ARM は、ARM Holdings PLC の登録商標です。

Caldera, OpenLinux, および C のロゴは、Caldera, Inc の登録商標です。

Caldera OpenDOS 1997 Caldera, Inc.

DEC は、Digital Equipment Corporation の登録商標です。

<!-- 
DIGITAL is a trademark of Digital Equipment Corporation. 

Linux is a trademark of Linus Torvalds. 

Motif is a trademark of The Open System Foundation, Inc. 

MSDOS is a trademark of Microsoft Corporation. 
-->
DIGITAL は、Digital Equipment Corporation の登録商標です。

Linux は、Linus Torvalds の登録商標です。

Motif は、The Open System Fundation, Inc の登録商標です。

MSDOS は、Microsoft Corporation の登録商標です。

<!--
Red Hat, glint and the Red Hat logo are trademarks of Red Hat Software, Inc. 

UNIX is a registered trademark of X/Open. 

XFree86 is a trademark of XFree86 Project, Inc. 

X Window System is a trademark of the X Consortium and the Massachusetts
Institute of Technology. 
-->
Red Hat, glint および Red Hat ロゴは、Red Hat Software, Inc の登録商標です。

UNIX は、X/Open の登録商標です。

XFree86 は、XFree86 Project, Inc の登録商標です。

X Window System は、X Consortium と Massachusetts Institute of Technology の
登録商標です。


<!--The Author-->
<sect1>著者について<label id="chapter_intro_sect5">

<!--
I was born in 1957, a few weeks before Sputnik was launched, in the north of
England. I first met Unix at University, where a lecturer used it as an example
when teaching the notions of kernels, scheduling and other operating systems
goodies. I loved using the newly delivered PDP-11 for my final year project. 
After graduating (in 1982 with a First Class Honours degree in Computer 
Science) Iworked for Prime Computers (Primos) and then after a couple of years
for Digital (VMS, Ultrix). At Digital I worked on many things but for the last
5 years there, Iworked for the semiconductor group on Alpha and StrongARM 
evaluation boards. In 1998 I moved to ARM where I have a small group of 
engineers writing low level firmware and porting operating systems. My 
children (Esther and Stephen) describe me as a geek. 
-->
<p>わたしは、スプートニクが打ち上げられる数週間前の 1957 年に、イギリス北部に
生まれた。Unix と初めて出会ったのは、大学時代だった。講義でカーネルや
スケジューリングその他のオペレーティングシステムの機能についての概念を教わる
ときに、講師が教材として使ったからだ。わたしが卒業する年のプロジェクトとして
 PDP-11 が搬入されたのだが、その新品のマシンを使っていたときのことはとても
印象に残っている。卒業後(1982 年、コンピュータサイエンス学科の First Class 
Honours の学位を得て)、Prime Computer (Primos) に就職し、その数年後に DEC 
(VMS, Ultrix) で働き始めた。DEC では、いろいろなことに従事したが、
最後の 5 年間は、半導体部門の Alpha と Strong ARM の評価委員会で働いた。
1998 年には、ARM に移籍し、ここでは、低レベルファームウェアを書いたり
オペレーティングシステムを移植したりするエンジニアのグループを束ねている。
わたしの子供たち(Esther と Stephen)は、わたしをコンピュータ狂い(geek)と呼ぶ。

<!--
People often ask me about Linux at work and at home and I am only too happy to
oblige. The more that I use Linux in both my professional and personal life the
more that I become a Linux zealot. You may note that I use the term `zealot' 
and not `bigot'; I define a Linux zealot to be an enthusiast that recognizes 
that there are other operating systems but prefers not to use them. As my 
wife, Gill, who uses Windows 95 once remarked ``I never realized that we would
have his and her operating systems''. For me, as an engineer, Linux suits my 
needs perfectly. It is a superb, flexible and adaptable engineering tool that 
I use at work and at home. Most freely available software easily builds on 
Linux and I can often simply download pre-built executable files or install 
them from a CD ROM. What else could I use to learn to program in C++, Perl or 
learn about Java for free? 
-->
<p>職場や家庭で Linux について尋ねられることがしばしばあるが、そんなとき
わたしは楽しさのあまり、つい聞かれてもいないことまで答えてしまう。仕事上でも
個人的にも Linux を使えば使うほど、わたしは Linux の熱心な愛好家になってゆ
く。読者は気付いているかもしれないが、わたしは、狂信家ではなく、愛好家という
言葉を使う。Linux 愛好家とは、他にもオペレーティングシステムがあることを理解
しているが、それらを使うことを好まない情熱的な人間のことだとわたしは考えてい
る。Windows 95 を使っている妻の Gill 
は、こう言ったことがある。「オペレーティングシステムが他にもあるなんて知らな
かったわ。」 エンジニアであるわたしにとって、Linux は自分の要求に完璧に答えて
くれるものである。それは、わたしが職場でも自宅でも使用する、柔軟で応用範囲の
広い非常に出来の良い道具である。フリーで手に入るほとんどのソフトウェアは、
Linux 上で簡単にビルドでき、しばしばあらかじめビルドされた実行ファイルを
ダウンロードすることもでき、それらを CD-ROM からインストールすることもできる。
C++ や Perl でのプログラムを学ぶのに、あるいは Java について知るのに、Linux 
以外にいったい何が自由に使えるというのだろう。


<!--Acknowledgements-->
<sect1>謝辞<label id="chapter_intro_sect6">

<!--
I must thank the many people who have been kind enough to take the time to
e-mail me with comments about this book. I have attempted to incorporated those
comments in each new version that I have produced and I am more than happy to
receive comments, however please note my new e-mail address. 
-->
<p>本書についてのコメントをメールで送ってくれた多くの親切なひとたちに感謝し
たいと思う。それらのコメントは新しいバージョンを出すたびに含めるようにしてき
た。コメントをもらうことは、わたしには本当に嬉しいことなので、是非わたしの
新しいメールアドレスを目に留めてほしい。

<!--
A number of lecturers have written to me asking if they can use some or parts 
of this book in order to teach computing. My answer is an emphatic yes; this 
is one use of the book that I particularly wanted. Who knows, there may be 
another Linus Torvalds sat in the class. 
-->
<p>何名かの講師が、わたしに質問を送り、コンピュータについて教えるためにこの本
の一部を使ってもよいかどうか尋ねてきた。これには当然快諾する。それは
わたしが特に意図していた本書の利用方法だからだ。そのクラスに未来の Linus 
Torvalds が座っていないと誰が断言できるだろうか。

<!--
Special thanks must go to John Rigby and Michael Bauer who gave me full,
detailed review notes of the whole book. Not an easy task. Alan Cox and Stephen
Tweedie have patiently answered my questions - thanks. I used Larry Ewing's
penguins to brighten up the chapters a bit. Finally, thank you to Greg Hankins
for accepting this book into the Linux Documentation Project and onto their 
web site. 
-->
この本全体を非常に詳細に批評してくれた John Rigby と Michael Bauer には特に
感謝している。大変な仕事だったと思う。Alan Cox と Stephen Tweedie はわたしの
質問に辛抱強く答えてくれた。どうもありがとう。各章をすこし明るくするために 
Larry Ewing のペンギンをつかった。最後に、この本を Linux Documentation Project 
に加えることに同意し、ウェブサイトに載せてくれた Greg Hankins に感謝する。

<!--
Footnotes:

1 A HOWTO is just what it sounds like, a document describing how to do
something. Many have been written for Linux and all are very useful. 
-->

<footnote>
<label id="chapter_intro_fn1">
(脚注1)<htmlurl url="http://www.linux.or.jp/JF/" name="HOWTO"> とは、その名の
通り、何かをする方法(how to)を述べた文書である。Linux 向けに多数書かれており、
非常に役に立つ。
</footnote>


<!--第  2 章 ハードウェアの基本-->
<!--Chapter 1 Hardware Basics-->
<sect>ハードウェアの基本<label id="chapter_hb">
<p><figure><ph vspace="75"><img src="./The-Linux-Kernel-images/penguin2.gif">
</figure>

<!--
An operating system has to work closely with the hardware system that acts
as its foundations. The operating system needs certain services that can only
be provided by the hardware. In order to fully understand the Linux operating
system, you need to understand the basics of the underlying hardware. This
chapter gives a brief introduction to that hardware: the modern PC. 
-->
<p>オペレーティングシステムは、その基礎であるハードウェアシステムと密接に協調
しながら動作しなければならない。そして、オペレーティングシステムはハードウェア
でしか提供できない一定のサービスを必要としている。
オペレーティングシステムを完全に理解するには、その基礎となるハードウェアの基本
を理解しなければならない。この章では、そうしたハードウェア、すなわち現代の PC 
について簡単に紹介する。

<!--
When the ``Popular Electronics'' magazine for January 1975 was printed with
an illustration of the Altair 8080 on its front cover, a revolution started. 
The Altair 8080, named after the destination of an early Star Trek episode, 
could be assembled by home electronics enthusiasts for a mere $397. With its 
Intel 8080 processor and 256 bytes of memory but no screen or keyboard it was 
puny by today's standards. Its inventor, Ed Roberts, coined the term ``personal
computer'' to describe his new invention, but the term PC is now used to refer
to almost any computer that you can pick up without needing help. By this
definition, even some of the very powerful Alpha AXP systems are PCs. 
-->
<p>1975 年 1 月、「Popular Electrics」誌がその表紙に Altair 8080 のイラストを
載せたとき、革命が始まった。Altair 8080 は、初期のスタートレックのエピソード
の目的地にちなんで名付けられていたのだが、家庭電子工作の愛好家がわずか 397 ド
ルで組み立てられるというものだった。Intel 8080 プロセッサと 256 バイトのメ
モリ、スクリーンもキーボードもないというそのマシンは、今日の基準からすれば
随分貧弱ではある。その発明者 Ed Roberts は、かれの発明品を呼ぶために
「パーソナルコンピュータ(PC)」という言葉を作り出した。しかし今日ではこの PC 
という言葉は、目の前にあるほとんどあらゆるコンピュータに対して当たり前のよう
に使われていている。この定義からすると、非常にパワフルな Alpha AXP のシステム
のいくつかでさえ PC ということになる。

<!--
Enthusiastic hackers saw the Altair's potential and started to write software
and build hardware for it. To these early pioneers it represented freedom; the
freedom from huge batch processing mainframe systems run and guarded by an
elite priesthood. Overnight fortunes were made by college dropouts fascinated
by this new phenomenon, a computer that you could have at home on your
kitchen table. A lot of hardware appeared, all different to some degree and
software hackers were happy to write software for these new machines.
Paradoxically it was IBM who firmly cast the mould of the modern PC by
announcing the IBM PC in 1981 and shipping it to customers early in 1982. With
its Intel 8088 processor, 64K of memory (expandable to 256K), two floppy
disks and an 80 character by 25 lines Colour Graphics Adapter (CGA) it was
not very powerful by today's standards but it sold well. It was followed, in
1983, by the IBM PC-XT which had the luxury of a 10Mbyte hard drive. It was
not long before IBM PC clones were being produced by a host of companies
such as Compaq and the architecture of the PC became a de-facto standard.
This de-facto standard helped a multitude of hardware companies to compete
together in a growing market which, happily for consumers, kept prices low.
Many of the system architectural features of these early PCs have carried over
into the modern PC. For example, even the most powerful Intel Pentium Pro
based system starts running in the Intel 8086's addressing mode. When Linus
Torvalds started writing what was to become Linux, he picked the most
plentiful and reasonably priced hardware, an Intel 80386 PC. 
-->
熱心なハッカーたちは、Altair の潜在能力を理解し、そのためのソフトウェアを書き、
ハードウェアを作り始めた。そうした初期のパイオニアたちにとって、それは自由の
象徴であった。その自由とは、エリート聖職者階級によって守られて稼働してい
た、巨大なバッチプロセス方式のメインフレームシステムからの自由であった。
一夜にして富豪となる「落ちこぼれ」大学生たちが現れたのも、こうした現象、
すなわち自宅のキッチンテーブルに置くことができるコンピュータという産物に
魅了されてのことだった。多くのハードウェアが
出現し、それらは少しずつ違っていたから、ソフトウェアハッカーたちはそうしたマ
シンのソフトを喜んで書いていた。逆説的なのは、現代の PC の強固な鋳型を作った
のは、IBM であったことだ。彼らは 1981 年に IBM PC を告示して、1982 年はじめに
は顧客に出荷し始めた。Intel 8088 プロセッサ、64k のメモリ(256k まで拡張
可能)、ふたつのフロッピーディスク、25 行 80 文字のカラーグラフィックアダプタ
(CGA)というスペックは、今日の基準からすると決してパワフルとは言えないが、売れ
行きは好調であった。1983 年には IBM PC-XT が登場し、それには贅沢にも 10M バイ
トのハードドライブが付いていた。
まもなく、Compaq などの多くの会社によって IBM PC クローン
が製造されはじめ、PC アーキテクチャは事実上の標準となった。この事実上の標準
が出来たことで、成長する市場で無数の会社が競争し、消費者にとっては幸運なこと
に、価格は低く抑えられた。こうした初期 PC のシステムの構造上の多くの特徴が、
現代の PC にも受け継がれている。たとえば、最も強力な Intel Pentium Pro ベースの
マシンでも、起動時は Intel 8086 のアドレッシングモードで実行されている。
Linus Torvalds が将来 Linux となるはずのコードを書き始めたとき、最も普及して
いて妥当な値段のハードウェアとして彼が選んだのが、Intel 80386 PC であった。

<!--                Figure 1.1: A typical PC motherboard.-->
<#if output="html">
<figure><ph vspace="1">
<img src="./The-Linux-Kernel-images/figure1-1.gif"></figure>
</#if>
<#unless output="html">
<verb>
+--------------------------------------------------------------------+
|   +-------+ +-------+                                              |
|   | power | | power |                                              |
|   +-------+ +-------+   +-------------------+                      |
|  +----------------+     |                   |                      |
|  | パラレルポート |     |-------------------|                      |
|  +----------------+     |                   |                      |
| +-------+  +-------+    |-------------------|                      |
| | COM 1 |  | COM 2 |    |      C P U        |                      |
| +-------+  +-------+    |-------------------|                      |
|                         |                   |                      |
|                         |-------------------|                      |
|                         |                   |                      |
|                         +-------------------+                      |
|                  _______________________   _____________________   |
|                  |                      |  |                    |  |
|                  +----------------------+  +--------------------+  |
|                  _______________________   ______________________  |
|                  |                      |  |                    |  |
|                  +----------------------+  +--------------------+  |
|                                 SIMM メモリースロット              |
|       +-------------------------------+                            |
|       |                               |                            |
|       +-------------------------------+  PCI スロット              |
|       +-------------------------------+                            |
|       |                               |                            |
|       +-------------------------------+                            |
| +----------------------------------------------------+             |
| |                                                    |             |
| +----------------------------------------------------+             |
| +----------------------------------------------------+             |
| |                                                    |ISA スロット |
| +----------------------------------------------------+             |
| +----------------------------------------------------+             |
| |                                                    |             |
| +----------------------------------------------------+             |
+--------------------------------------------------------------------+
</verb>
</#if>
<p>(図表1.1) 典型的な PC マザーボード

<!--
Looking at a PC from the outside, the most obvious components are a system
box, a keyboard, a mouse and a video monitor. On the front of the system box
are some buttons, a little display showing some numbers and a floppy drive.
Most systems these days have a CD ROM and if you feel that you have to
protect your data, then there will also be a tape drive for backups. These
devices are collectively known as the peripherals. 
-->
<p>外観からすると、PC を構成する部品として最も目立つのは、システムの本体であ
り、キーボード、マウス、モニターである。本体の前面には、いくつかのボタン、
数字を表示する小さなランプ、それにフロッピードライブがある。最近のシステム
では CD-ROM があり、データ保護の必要を感じているならバックアップ用のテープ
ドライブもあるだろう。それらのデバイスの総称は、周辺機器である。

<!--
Although the CPU is in overall control of the system, it is not the only
intelligent device. All of the peripheral controllers, for example the IDE
controller, have some level of intelligence. Inside the PC (Figure  1.1) you 
will see a motherboard containing the CPU or microprocessor, the memory and a
number of slots for the ISA or PCI peripheral controllers. Some of the
controllers, for example the IDE disk controller may be built directly onto the
system board. 
-->
CPU がシステム全体をコントロールしているのだが、情報処理機能を持つデバイスは
それだけではない。たとえば、IDE コントローラのような周辺機器のコントローラは
すべてあるレベルの情報処理能力を持っている。PC の内部には(図表(1.1)参照)
マザーボードがあり、
CPU もしくはマイクロプロセッサ、メモリ、ISA や PCI の周辺機器コントローラ
用のいくつかのスロットなどがある。IDE ディスクコントローラのようなコントローラ
の中には、システムボードに直接組み込まれているものもある。

<!--1.1  The CPU-->
<sect1>CPU<label id="chapter_hb_sect1">

<!--
The CPU, or rather microprocessor, is the heart of any computer system. The
microprocessor calculates, performs logical operations and manages data flows
by reading instructions from memory and then executing them. In the early days
of computing the functional components of the microprocessor were separate
(and physically large) units. This is when the term Central Processing Unit was
coined. The modern microprocessor combines these components onto an
integrated circuit etched onto a very small piece of silicon. The terms CPU,
microprocessor and processor are all used interchangeably in this book. 
-->
<p>CPU もしくはマイクロプロセッサは、あらゆるコンピュータシステムの心臓部であ
る。マイクロプロセッサは、計算し、論理演算を行い、メモリから命令を読み出して
それらを実行することでデータフローを管理する。コンピュータの黎明期には、
マイクロプロセッサの演算処理部分は独立した(しかもかなり大きな)ユニットであっ
た。中央演算処理装置(CPU)という言葉が作られた当時はそういうものであった。
現代のマイクロプロセッサは、それらすべての部品を組み合わせて集積回路を作り、
非常に小さなシリコンチップにエッチング処理されている。CPU, マイクロプロセッ
サ、プロセッサといった用語は、本書ではすべて同じ意味で使用される。

<!--
Microprocessors operate on binary data; that is data composed of ones and
zeros. 
These ones and zeros correspond to electrical switches being either on or off.
Just as 42 is a decimal number meaning ``4 10s and 2 units'', a binary number 
is a series of binary digits each one representing a power of 2. In this 
context, a power means the number of times that a number is multiplied by 
itself. 10 to the power 1 ( 101 ) is 10, 10 to the power 2 ( 102 ) is 10x10, 
103 is 10x10x10 and so on. Binary 0001 is decimal 1, binary 0010 is decimal 2,
binary 0011 is 3, binary 0100 is 4 and so on. So, 42 decimal is 101010 binary 
or (2 + 8 + 32 or 21 + 23 + 25 ). Rather than using binary to represent 
numbers in computer programs, another base, hexadecimal is usually used. 
-->
<p>マイクロプロセッサは、バイナリデータを処理する。バイナリデータとは、1 と 
0 から成るデータである。
これらの 1 と 0 とは、電子スイッチのオンかオフかに対応している。単に 42 と
いうと、十進数で " 10 が 4 つと 2 " を意味するが、バイナリナンバー(二進数)
では、一連の二進数値の並びとなり、それぞれが 2 のベキ数を表す。
<#if output="html">
ここでベキ数とは、ある数を自乗する回数のことである。10 の 1乗 
(<dm>10<sup>1</sup></dm>) 
は、10 である。10 の 2 乗 (<dm>10<sup>2</sup></dm>) は、10x10 であり、
(<dm>10<sup>3</sup></dm>) は、10x10x10 になる。二進数の 0001 は、十進数の 1 
であり、二進数の 0010 は、十進数の 2 であり、二進数の 0011 は、3 で、二進数
の 0100 は、4 である。十進数 42 は、二進数 101010 もしくは、
(<dm>2 + 8 + 32</dm> もしくは <dm>2<sup>1</sup> + 2<sup>3</sup> + 2
<sup>5</sup></dm> ) となる。
</#if>
<#unless output="html">
ここでベキ数とは、ある数を自乗する回数のことである。10 の 1乗 は、10 である。
10 の 2 乗は、10x10 であり、10 の 3 乗は、10x10x10 になる。二進数の 0001 は、
十進数の 1 であり、二進数の 0010 は、十進数の 2 であり、二進数の 0011 は、3 
で、二進数の 0100 は、4 である。十進数 42 は、二進数 101010 もしくは、
(2 + 8 + 32 もしくは、2 + 2x2x2 + 2x2x2x2x2 ) となる。
</#if>
しかし、コンピュータプログラムの中で数を表現する場合には、二進数よりもむし
ろ、もう一つの基数である、十六進数のほうを使用するのが通常である。

<!--
In this base, each digital represents a power of 16. As decimal numbers only go
from 0 to 9 the numbers 10 to 15 are represented as a single digit by the 
letters A, B, C, D, E and F. For example, hexadecimal E is decimal 14 and 
hexadecimal 2A is decimal 42 (two 16s) + 10). Using the C programming language
notation (as I do throughout this book) hexadecimal numbers are prefaced 
by ``0x''; hexadecimal 2A is written as 0x2A . 
-->
<p>16 進数では、それぞれの数が 16 のベキ数になっている。10 進数では 0 から 9 
までしかないが、16 進数では 10 から 16 までが A, B, C, D, E, F という数で表現
される。たとえば、16 進数の E は、10 進数では 14 であり、16 進数 2A は、10 進数
では 42 ( 16x2 + 10 ) である。C プログラム言語の表記法では(本書ではこの表記法
に従う)、16 進法は、先頭に " 0x " を付ける。したがって、16 進数 2A は、0x2A と
表記される。

<!--
Microprocessors can perform arithmetic operations such as add, multiply and
divide and logical operations such as ``is X greater than Y?''. 
-->
<p>マイクロプロセッサは、加算、乗算、除算などの算術演算や、「X は Y より大きい
か？」といった論理演算ができる。

<!--
The processor's execution is governed by an external clock. This clock, the
system clock, generates regular clock pulses to the processor and, at each
clock pulse, the processor does some work. For example, a processor could
execute an instruction every clock pulse. A processor's speed is described in
terms of the rate of the system clock ticks. A 100Mhz processor will receive
100,000,000 clock ticks every second. It is misleading to describe the power of
a CPU by its clock rate as different processors perform different amounts of
work per clock tick. However, all things being equal, a faster clock speed
means a more powerful processor. The instructions executed by the processor
are very simple; for example ``read the contents of memory at location X into
register Y''. Registers are the microprocessor's internal storage, used for
storing data and performing operations on it. The operations performed may
cause the processor to stop what it is doing and jump to another instruction
somewhere else in memory. These tiny building blocks give the modern
microprocessor almost limitless power as it can execute millions or even
billions of instructions a second. 
-->
<p>プロセッサの処理は、外部クロックで管理されている。このクロックは、システム
クロックであり、プロセッサに一定間隔でクロックパルスを送り、そのクロックパル
スごとにプロセッサが何らかの処理をする。たとえば、プロセッサはクロックパルス
ごとに命令を実行したりする。プロセッサの速度は、システムクロックの発振速度で
記述される。100MHz のプロセッサは、一秒間に 100,000,000 回のクロックパルスを
受けているわけである。
確かに、プロセッサが違えばクロックごとに実行している処理の量も違うので、CPU の
パワーをクロック速度で考えるのは誤解である。しかし、他のすべての条件が
同じであれば、クロック速度が速いほどプロセッサもパワフルなものになる。
プロセッサで処理される命令は単純である。たとえば、「メモリ上の X という場所に
ある内容を読んでレジスタ Y に書き込め」といったものである。レジスタとは、
マイクロプロセッサ内部の記憶装置で、データを蓄え、そのデータを使って処理を
実行するために利用される。
実行される処理によっては、実行中の処理を停止して、メモリのどこか違う場所
に存在する別の命令処理に移るようプロセッサに命ずるものもある。このように処理
の対象を小さく分割したことによって、現代のマイクロプロセッサは、毎秒数百万や
数十億という命令の処理ができる、無限ともいえる力を手に入れたのである。

<!--
The instructions have to be fetched from memory as they are executed.
Instructions may themselves reference data within memory and that data must
be fetched from memory and saved there when appropriate. 
-->
<p>命令は、実行時にメモリから取り出されなければならない。命令はそれ自体が
メモリ内の参照データであり、それらのデータはメモリから取り出されなければなら
ず、適切な時にメモリに保存されなければならない。

<!--
The size, number and type of register within a microprocessor is entirely
dependent on its type. An Intel 4086 processor has a different register set to
an Alpha AXP processor; for a start, the Intel's are 32 bits wide and the Alpha
AXP's are 64 bits wide. In general, though, any given processor will have a
number of general purpose registers and a smaller number of dedicated
registers. Most processors have the following special purpose, dedicated,
registers: 
-->
<p>マイクロプロセッサ内のレジスタのサイズ、数、タイプは、完全にプロセッサのタ
イプに依存している。Intel 4086 (訳注:80486か？)プロセッサは、Alpha AXP プロ
セッサとは違ったレジスタのセットを持っている。たとえば、Intel のものは 32 ビッ
ト幅だが、Alpha は、64 ビット幅であることからすでに異なっている。しかし、一般
的には、どのようなプロセッサでも、多くの汎用レジスタと、それよりも少ない数の
特別なレジスタを持っている。大部分のプロセッサには、次のような特定の目的に特
化したレジスタがある。

<descrip>
<!--Program Counter (PC)-->
<tag>Program Counter (PC)</tag>
<!--
      This register contains the address of the next instruction to be
      executed. The contents of the PC are automatically incremented each
      time an instruction is fetched, 
-->
このレジスタは、次に実行される命令のアドレスを保持するものである。このカウンタ
 (PC) の内容は、命令がメモリから転送されるたびに、自動的にインクリメントされ
る。

<!--Stack Pointer (SP)-->
<tag>Stack Pointer (SP)</tag>
<!--
      Processors have to have access to large amounts of external read-write
      random access memory (RAM) which facilitates temporary storage of
      data. The stack is a way of easily saving and restoring temporary
      values in external memory. Usually, processors have special
      instructions which allow you to push values onto the stack and to pop
      them off again later. The stack works on a last in first out (LIFO) 
      basis.
      In other words, if you push two values, x and y, onto a stack and then
      pop a value off of the stack then you will get back the value of y. 
-->
プロセッサは、メモリ(Random Access Memory, RAM)にアクセスできなければならな
い。メモリは、(レジスタと比較した場合)大容量の、CPU 外部にある読み書き可能な
記憶装置であり、一時(temporary)データの保存を容易にするものである。スタックは、
外部メモリに一時的に値を保存したり取り出したりするための簡単な方法である。
通常、プロセッサは、特別な命令を使って、スタックに値を積み(push)、あとでそれ
を取り出す(pop)処理をする。スタックは、後入れ先出し(Last In First Out, LIFO)
の原則で動く。言い換えると、x と y のふたつの値を順にスタックに積んでそこから
ひとつの値を取り出すと、値 y が取り出される。

<!--
      Some processor's stacks grow upwards towards the top of memory
      whilst others grow downwards towards the bottom, or base, of memory.
      Some processor's support both types, for example ARM. 
-->
あるプロセッサでは、スタックはメモリの上限に向かって積み上げられ、他の
プロセッサでは、メモリの下限あるいは最初に向かって積み上げられる。あるいは、
ARM のように両方をサポートしているプロセッサもある。

<!--Processor Status (PS)-->
<tag>Processor Status (PS)</tag>
<!--
      Instructions may yield results; for example ``is the content of register
      X greater than the content of register Y?'' will yield true or false as a
      result. The PS register holds this and other information about the
      current state of the processor. For example, most processors have at
      least two modes of operation, kernel (or supervisor) and user. The PS
      register would hold information identifying the current mode. 
-->
命令が実行されると結果が生じる。たとえば、「レジスタ X の内容は、レジスタ Y の
内容より大きいか比較せよ」という命令には、大小という真か偽かの結果が生じる。
PS レジスタは、こうした結果を保持するとともに、プロセッサの現在の状態について
の情報も保持する。たとえば、大部分のプロセッサは、カーネルモード(あるいは、
スーパバイザーモード)とユーザモードという少なくともふたつのモードを持っている。
PS レジスタは、現在のモードを識別する情報も保持する。

</descrip>

<!--1.2  Memory-->
<sect1>メモリ<label id="chapter_hb_sect2">

<!--
All systems have a memory hierarchy with memory at different speeds and
sizes at different points in the hierarchy. The fastest memory is known as
cache memory and is what it sounds like - memory that is used to temporarily
hold, or cache, contents of the main memory. This sort of memory is very fast
but expensive, therefore most processors have a small amount of on-chip
cache memory and more system based (on-board) cache memory. Some
processors have one cache to contain both instructions and data, but others
have two, one for instructions and the other for data. The Alpha AXP processor
has two internal memory caches; one for data (the D-Cache) and one for
instructions (the I-Cache). The external cache (or B-Cache) mixes the two
together. Finally there is the main memory which relative to the external cache
memory is very slow. Relative to the on-CPU cache, main memory is positively
crawling. 
-->
<p>すべてのシステムには、記憶階層(memory hierarchy)がある。そしてその階層の
位置によって、メモリのスピードやサイズが異なる。最速のメモリはキャッシュ
メモリ(cache memory)と呼ばれ、その名前の通りメインメモリの内容を一時的に保持
あるいはキャッシュするために使用される。この種のメモリは非常に高速だが高価
なので、大部分のプロセッサではチップ上に少量しか組み込まれず、マザーボード
上にそれより少し多いキャッシュが置かれるだけである。
プロセッサによっては、命令とデータの両方をひとつのキャッシュに保持するものが
あるが、命令とデータを別々のキャッシュに保存するものもある。Alpha AXP 
プロセッサはふたつの内部キャッシュを持ち、ひとつはデータ用(D-Cache)、もうひと
つは命令用(I-Cache)として使用される。そして、外部キャッシュ(B-Cache)は、両者
を同時に保持する。最後にメインメモリがある。これは外部キャッシュに比べると
非常に速度が遅い。CPU 上のキャッシュと比較すると、メインメモリはイモ虫ほどの
速度でしかない。

<!--
The cache and main memories must be kept in step (coherent). In other words,
if a word of main memory is held in one or more locations in cache, then the
system must make sure that the contents of cache and memory are the same.
The job of cache coherency is done partially by the hardware and partially by
the operating system. This is also true for a number of major system tasks
where the hardware and software must cooperate closely to achieve their aims.
-->
<p>キャッシュとメインメモリとは足並みが揃っていなければならない(一貫性, 
coherent)。言い換えると、メインメモリ上のあるワード(word)がひとつ以上の
キャッシュに保持されている場合、(システムは)キャッシュとメモリの内容を確実に
一致させなければならない。キャッシュの一貫性を保つのは、主にハードウェ
アの仕事であり、オペレーティングシステムも部分的にそれに関与する。このことは
多くの重要なシステムタスクにも当てはまる。ハードウェアとソフトウェアが緊密に
協調することで目的を達成しなければならないタスクは数多くある。

<!--1.3  Buses-->
<sect1>バス<label id="chapter_hb_sect3">

<!--
The individual components of the system board are interconnected by multiple
connection systems known as buses. The system bus is divided into three
logical functions; the address bus, the data bus and the control bus. The
address bus specifies the memory locations (addresses) for the data transfers.
The data bus holds the data transfered. The data bus is bidirectional; it 
allows data to be read into the CPU and written from the CPU. The control bus
contains various lines used to route timing and control signals throughout the
system. Many flavours of bus exist, for example ISA and PCI buses are popular
ways of connecting peripherals to the system. 
-->
<p>システムボード上の個別の部品は、バスと総称される多様な接続方法で互いに結び
つけられている。システムバスは、論理的な機能から次の 3 つに分類される。
アドレスバス、データバス、そしてコントロールバスである。アドレスバスは、データ
転送のためにメモリ上の位置(アドレス)を指定するものであり、データバスはデータ
を保持して転送するするためのものである。データバスは双方向性で、CPU に読み
込まれるデータと、CPU から書き込まれるデータの転送を受け持つ。コントロールバス
は多種の信号線を含んでいて、クロックパルスや制御シグナルなどを(バス上の)シス
テム全体に配線するために使用される。それら以外にも様々な形態のバスが存在する。
たとえば ISA や PCI バスは、システムに周辺機器を接続する際の一般的な方法であ
る。

<!--1.4  Controllers and Peripherals-->
<sect1>コントローラと周辺機器<label id="chapter_hb_sect4">

<!--
Peripherals are real devices, such as graphics cards or disks controlled by
controller chips on the system board or on cards plugged into it. The IDE disks
are controlled by the IDE controller chip and the SCSI disks by the SCSI disk
controller chips and so on. These controllers are connected to the CPU and to
each other by a variety of buses. Most systems built now use PCI and ISA
buses to connect together the main system components. The controllers are
processors like the CPU itself, they can be viewed as intelligent helpers to 
the CPU. The CPU is in overall control of the system. 
-->
<p>周辺機器は、グラフィックカードやディスクといった実(real)デバイスであり、
それらは、システムボード上のチップやボードに差されるカード上のコントローラに
よって制御される。IDE ディスクは、IDE コントローラチップで制御され、SCSI 
ディスクは SCSI ディスクのコントローラチップで制御される。それらのコントローラ
は CPU に接続されていて、多様なバスにより相互にも接続されている。今日製造される
大部分のシステムでは、PCI か ISA バスによってメインシステムの部品に相互接続
されている。コントローラは、CPU 自体と同じプロセッサーであり、CPU を助ける
情報処理装置と考えることもできる。CPU はシステム全体を統括している点でそれらと
役割が異なる。

<!--
All controllers are different, but they usually have registers which control 
them. Software running on the CPU must be able to read and write those 
controlling registers. One register might contain status describing an error. 
Another might be used for control purposes; changing the mode of the 
controller. Each controller on a bus can be individually addressed by the CPU,
this is so that the software device driver can write to its registers and thus
control it. The IDE ribbon is a good example, as it gives you the ability to 
access each drive on the bus separately. Another good example is the PCI bus 
which allows each device (for example a graphics card) to be accessed 
independently. 
-->
<p>コントローラの仕様は相互に異なっているが、通常はレジスタを持ち、それによって
コントローラの制御がなされる。CPU 上で実行されるソフトウェアは、そうしたコン
トローラの制御レジスタを読み書きできなければならない。あるレジスタはエラーを
示すステータス情報を保持しているかもしれず、他のレジスタは、コントローラの
モード変更のための制御目的で使用されているかもしれない。バス上にある個々の
コントローラは、CPU で個別にアドレス管理されているので、それによって、
ソフトウェアであるデバイスドライバは、コントローラのレジスタに書き込みをし
て、それらを制御することができる。IDE ポート(IDE ribbon)がその典型であり、
それを使用することで、バス上のデバイスに対する個別のアクセスが可能になる。
他の典型例は、PCI バスであり、これによっても個別のデバイス(たとえば、グラフィッ
クカード)に独立してアクセスが可能となっている。

<!--1.5  Address Spaces-->
<sect1>アドレス空間<label id="chapter_hb_sect5">

<!--
The system bus connects the CPU with the main memory and is separate from
the buses connecting the CPU with the system's hardware peripherals.
Collectively the memory space that the hardware peripherals exist in is known
as I/O space. I/O space may itself be further subdivided, but we will not worry
too much about that for the moment. The CPU can access both the system
space memory and the I/O space memory, whereas the controllers themselves
can only access system memory indirectly and then only with the help of the
CPU. From the point of view of the device, say the floppy disk controller, it 
will see only the address space that its control registers are in (ISA), and 
not the system memory. Typically a CPU will have separate instructions for 
accessing the memory and I/O space. For example, there might be an instruction
that means ``read a byte from I/O address 0x3f0 into register X''. This is 
exactly how the CPU controls the system's hardware peripherals, by reading and
writing to their registers in I/O space. Where in I/O space the common
peripherals (IDE controller, serial port, floppy disk controller and so on) 
have their registers has been set by convention over the years as the PC 
architecture has developed. The I/O space address 0x3f0 just happens to be the
address of one of the serial port's (COM1) control registers. 
-->
<p>システムバスは、CPU をメインメモリに接続するものであり、CPU をシステムの
周辺機器に接続するバスとは区別されている。周辺機器が占めるメモリ空間は、
 I/O 空間(I/O space)と総称される。I/O 空間はそれ自体さらに細かく分かれるのだ
が、現時点ではあまり気にしないこととする。CPU はシステム空間メモリと I/O 空間
メモリの両方にアクセス可能なのだが、コントローラ自体はシステムメモリに間接的
にアクセスできるだけであり、その際には CPU の助けを借りなければならない。
フロッピーディスクコントローラのようなデバイスの側からこれを見ると、デバイス
はデバイスのコントロールレジスタが占めるアドレス空間しか見ることはできず
(ISA 等の場合)、システムメモリを見ることはできない。
CPU は、システムメモリにアクセスする場合と I/O 空間にアクセスする場合とでは
別々の命令を持っているのが一般的である。たとえば、「I/O 空間のアドレス 0x3f0 
から 1 バイト読み出して、レジスタ X に入れよ」という命令があったとする。
これは CPU がシステムの周辺機器を制御する方法そのものであり、I/O 空間にある
周辺機器コントローラのレジスタの読み書きがまさにそれにあたる。
PC アーキテクチャが今日のように発展しても、I/O 空間のどこに、よく利用される
周辺機器( IDE や シリアルポートやフロッピーのコントローラ)のレジスタがあるか
は、長年の慣習によって決まっている。上記の I/O 空間のアドレス 0x3f0 は、
シリアルポート(COM1)のコントロールレジスタのひとつがあるアドレスとなっている。

<!--
There are times when controllers need to read or write large amounts of data
directly to or from system memory. For example when user data is being written
to the hard disk. In this case, Direct Memory Access (DMA) controllers are
used to allow hardware peripherals to directly access system memory but this
access is under strict control and supervision of the CPU. 
-->
時には、コントローラが、システムメモリに対して直接大量のデータを読み
書きする必要が生じる場合がある。たとえば、ユーザデータがハードディスクに書き込
まれるような時である。その場合、DMA(Direct Memory Aceesss)コントローラが利用さ
れ、周辺機器が直接システムメモリにアクセスできるようになっている。DMA による
システムメモリへのアクセスは、CPU の厳しい管理・監督のもとで行われる。

<!--1.6  Timers-->
<sect1>タイマー<label id="chapter_hb_sect6">

<!--
All operating systems need to know the time and so the modern PC includes a
special peripheral called the Real Time Clock (RTC). This provides two things:
a reliable time of day and an accurate timing interval. The RTC has its own
battery so that it continues to run even when the PC is not powered on, this is
how your PC always ``knows'' the correct date and time. The interval timer
allows the operating system to accurately schedule essential work. 
-->
<p>時間を知ることはすべてのオペレーティングシステムにとって必要なことなので、
現代の PC にはリアルタイムクロック(Real Time Clock, RTC) と呼ばれる特別の
周辺機器が組み込まれている。これが提供するのは、その日の正確な時間と精密な
タイミングインターバル(timing interval)のふたつである。RTC には内蔵バッテリー
があるので、PC に電源が入っていない時でも実行し続けることができる。それゆえ 
PC はいつも正確な日付と時間とを知っているわけである。インターバルタイマーに
よって、オペレーティングシステムは重要な処理を正確にスケジューリングすること
が可能となる。

<!--第  3 章 ソフトウェアの基本-->
<!--Chapter 2 Software Basics-->
<sect>ソフトウェアの基本<label id="chapter_sb">
<p><figure><ph vspace="75"><img src="./The-Linux-Kernel-images/penguin2.gif">
</figure>

<!--
A program is a set of computer instructions that perform a particular task.
That program can be written in assembler, a very low level computer
language, or in a high level, machine independent language such as the C
programming language. An operating system is a special program which
allows the user to run applications such as spreadsheets and word
processors. This chapter introduces basic programming principles and gives
an overview of the aims and functions of an operating system. 
-->
<p>プログラムとは、特定のタスクを実行するコンピュータ命令のセットである。
プログラムは、低水準コンピュータ言語であるアセンブラでも記述でき、C のような
マシンに依存しない高水準のプログラム言語でも記述できる。オペレーティ
ングシステムは、特別なプログラムであり、ユーザによるスプレッドシートやワード
プロセッサといったアプリケーションの実行を可能にするものである。この章
では、基本的なプログラミングの原則を紹介し、オペレーティングシステムの目的や
機能の概観を述べる。

<!--2.1  Computer Languages-->
<sect1>コンピュータ言語<label id="chapter_sb_sect1">
<p>

<!--2.1.1  Assembly Languages-->
<sect2>アセンブリ言語<label id="chapter_sb_sect1-1">

<!--
The instructions that a CPU fetches from memory and executes are not at all
understandable to human beings. They are machine codes which tell the
computer precisely what to do. The hexadecimal number 0x89E5 is an Intel
80486 instruction which copies the contents of the ESP register to the EBP
register. One of the first software tools invented for the earliest computers
was an assembler, a program which takes a human readable source file and
assembles it into machine code. Assembly languages explicitly handle
registers and operations on data and they are specific to a particular
microprocessor. The assembly language for an Intel X86 microprocessor is
very different to the assembly language for an Alpha AXP microprocessor.
The following Alpha AXP assembly code shows the sort of operations that a
program can perform: 
-->
<p>CPU がメモリから取り出して実行する命令は、人間が見ても全く意味不明である。
それらの命令はマシン語であり、コンピュータに何を実行すべきかを正確に伝達する。
例えば、16 進数 0x89E5 は、Intel 80486 の場合、ESP レジスタの内容を EBP レジ
スタにコピーせよという命令に該当する。黎明期のコンピュータのために最初に
発明されたソフトウェアのひとつにアセンブラがある。それは、人間が読んで意味の
わかるソースをマシン語に変換するプログラムである。アセンブリ言語は直接レジスタ
を操作し、そこにあるデータを処理することができるが、その方法はマイクロプロ
セッサに固有のものとなる。Intel X86 プロセッサのアセンブリ言語は、Alpha AXP 
マイクロプロセッサのアセンブリ言語とはかなり異なっている。次の Alpha AXP 
アセンブリコードは、プログラムが実行する処理の一種を示している。

<tscreen><verb>
ldr r16, (r15)    ; Line 1
ldr r17, 4(r15)   ; Line 2
beq r16,r17,100   ; Line 3
str r17, (r15)    ; Line 4
100:              ; Line 5
</verb></tscreen>

<!--
The first statement (on line 1) loads register 16 from the address held in
register 15. The next instruction loads register 17 from the next location in
memory. Line 3 compares the contents of register 16 with that of register 17
and, if they are equal, branches to label 100. If the registers do not contain
the same value then the program continues to line 4 where the contents of r17 
are saved into memory. If the registers do contain the same value then no data
needs to be saved. Assembly level programs are tedious and tricky to write
and prone to errors. Very little of the Linux kernel is written in assembly
language and those parts that are are written only for efficiency and they are
specific to particular microprocessors. 
-->
<p>第一文(Line1)は、レジスタ 16 に対して、レジスタ 15 に保持されたアドレスに
ある(メモリの)内容をロードする。次の命令は、レジスタ 17 に対して、次のアドレス
(レジスタ 15 + 4)のメモリ内容をロードする。Line 3 は、レジスタ 16 
とレジスタ 17 の内容を比較し、同一なら Label 100 に分岐する。両方のレジスタが
同じ内容でない場合、プログラムは 4 行目に移行し、レジスタ 17 の内容がメモリに
保存される。同じ内容の場合は、データを保存する必要はない。アセンブリレベルの
プログラムは、冗長であり、トリッキーな書き方が必要で、エラーが生じやすい。
Linux カーネルはアセンブリ言語で書かれた部分はほとんどなく、その部分も処理効
率を上げる目的のためだけに書かれたものであり、それらは特定のプロセッサに固有
のものとなっている。

<!--2.1.2  The C Programming Language and Compiler-->
<sect2>C 言語とコンパイラ<label id="chapter_sb_sect1-2">

<!--
Writing large programs in assembly language is a difficult and time
consuming task. It is prone to error and the resulting program is not portable,
being tied to one particular processor family. It is far better to use a 
machine independent language like C. C allows you to describe programs in 
terms of their logical algorithms and the data that they operate on. Special 
programs called compilers read the C program and translate it into assembly 
language, generating machine specific code from it. A good compiler can 
generate assembly instructions that are very nearly as efficient as those 
written by a good assembly programmer. Most of the Linux kernel is written in 
the C language. The following C fragment: 
-->
<p>アセンブリ言語でプログラムを書くことは、困難で時間のかかる仕事である。
エラーを生じやすく、出来たプログラムは特定のプロセッサファミリーに束縛される
ので移植性がない。マシンに依存しない C のような言語を使う方がずっとよい。
C を使えば、C で利用可能な論理アルゴリズムとデータ構造を使ってプログラムを
書くことができる。コンパイラと呼ばれる特別なプログラムは、C プログラム
を読み込んで、アセンブリ言語に変換し、それによってマシン語を生成する。よく
出来たコンパイラは、優秀なアセンブリプログラマが書いたのとほとんど同じくらい
効率的なアセンブリ命令を生成することができる。Linux カーネルの大部分は、C 
言語で書かれている。次に C プログラムの一部を示す。

<tscreen><verb>
if (x != y)
        x = y ;
</verb></tscreen>

<!--
performs exactly the same operations as the previous example assembly
code. If the contents of the variable x are not the same as the contents of
variable y then the contents of y will be copied to x. C code is organized into
routines, each of which perform a task. Routines may return any value or data
type supported by C. Large programs like the Linux kernel comprise many
separate C source modules each with its own routines and data structures.
These C source code modules group together logical functions such as
filesystem handling code. 
-->
<p>これは、先ほどのアセンブリコードの例とまったく同じ処理をするものである。
変数 x の内容が変数 y の内容と同一でない場合、y の内容が x にコピーされる。
C コードは、特定のタスクを処理するルーチンとしてまとめることができる。ルーチン
は C でサポートされているすべての値やデータ型を返すことができる。Linux カーネル
のような巨大なプログラムは、多数の独立した C ソースモジュールから構成されてい
て、それぞれが独自のルーチンとデータ構造を持っている。そうした C のソースコード
モジュールは、ファイルシステム処理コードのグループのように、論理的な機能
別にグループ化されている。

<!--
C supports many types of variables, a variable is a location in memory which
can be referenced by a symbolic name. In the above C fragment x and y refer
to locations in memory. The programmer does not care where in memory the
variables are put, it is the linker (see below) that has to worry about that.
Some variables contain different sorts of data, integer and floating point and
others are pointers. 
-->
<p>C では、種々の変数型がサポートされているが、変数とは、シンボル名で参照可能な
メモリ内の位置のことである。上記の C のプログラムでは、x と y は、メモリ内の
位置を参照している。プログラマは、メモリ内に変数が置かれた位置を知る必要はな
く、それに配慮する必要があるのはリンカ(linker)(下記参照)だけである。変数には、
さまざまな種類のデータ、整数、浮動小数点数を格納するためのものとポインタ
(pointer)とがある。

<!--
Pointers are variables that contain the address, the location in memory of
other data. Consider a variable called x, it might live in memory at address
0x80010000. You could have a pointer, called px, which points at x. px might
live at address 0x80010030. The value of px would be 0x80010000: the
address of the variable x. 
-->
<p>ポインタは、アドレスを内容とする変数である。すなわち、他のデータのメモリ内
での位置を表す。x という変数があるとして、それがメモリ内のアドレス 
0x80010000 に存在するとする。その場合、x を差すポインタ、たとえば px を作
ることができる。ここで px は、アドレス 0x80010030 にあるとする。だとすると、
px の値は、変数 x のアドレスである 0x80010000 を内容として持つ。

<!--
C allows you to bundle together related variables into data structures. For
example, 
-->
<p>C を使えば、関連のある変数をデータ構造体としてまとめることができる。たとえ
ば、次のようなデータ構造体があるとする。

<tscreen><verb>
struct {
        int i ;
        char b ;
} my_struct ;
</verb></tscreen>

<!--
is a data structure called my_struct which contains two elements, an
integer (32 bits of data storage) called i and a character (8 bits of data)
called b. 
-->
<p>上記の my_struct というデータ構造は、ふたつの要素を含んでいる。i という整数
(32 ビットのデータ記憶領域)と、b という文字(8 ビットのデータ)という要素である。

<!--2.1.3  Linkers-->
<sect2>リンカ<label id="chapter_sb_sect1-3">

<!--
Linkers are programs that link together several object modules and libraries
to form a single, coherent, program. Object modules are the machine code
output from an assembler or compiler and contain executable machine code
and data together with information that allows the linker to combine the
modules together to form a program. For example one module might contain
all of a program's database functions and another module its command line
argument handling functions. Linkers fix up references between these object
modules, where a routine or data structure referenced in one module actually
exists in another module. The Linux kernel is a single, large program linked
together from its many constituent object modules. 
-->
<p>リンカとは、いくつかのオブジェクトモジュールやライブラリをリンクさせ、ひと
つの整合性のあるプログラムを作成するためのプログラムである。ここでオブジェクト
モジュールとは、アセンブラやコンパイラが出力したマシンコードであり、それに
は、実行可能なマシンコードとデータが含まれると同時に、リンカがモジュールを
結合してひとつのプログラムを作るための情報も含まれている。たとえば、ある
モジュールには、あるプログラムのデータベース関数のすべてが含まれているかもし
れず、ほかのモジュールにはコマンドライン引数を処理するための関数が含まれてい
るかもしれない。リンカはそうしたモジュール間での参照関係を解決するので、それ
によって、あるモジュールで参照されているルーチンやデータ構造が、別のモジュー
ルで実際に存在できるようになる。Linux カーネルという単一の巨大なプログラム
は、多くの構成要素であるオブジェクトモジュールを相互にリンクすることによって
作られている。

<!--2.2  What is an Operating System?-->
<sect1>オペレーティングシステムとは何か？<label id="chapter_sb_sect2">

<!--
Without software a computer is just a pile of electronics that gives off heat.
If the hardware is the heart of a computer then the software is its soul. An
operating system is a collection of system programs which allow the user to
run application software. The operating system abstracts the real hardware of
the system and presents the system's users and its applications with a
virtual machine. In a very real sense the software provides the character of
the system. Most PCs can run one or more operating systems and each one
can have a very different look and feel. Linux is made up of a number of
functionally separate pieces that, together, comprise the operating system.
One obvious part of Linux is the kernel itself; but even that would be useless
without libraries or shells. 
-->
<p>ソフトウェアがなければ、コンピュータは単に熱を放出する電子部品の固まりに
すぎない。ハードウェアがコンピュータの心臓だとすると、ソフトウェアはその
魂である。オペレーティングシステムは、システムプログラムの集合体であり、それ
がユーザによるアプリケーションプログラムの実行を可能にしている。オペレー
ティングシステムは、システム上の実(real)ハードウェアを抽象化して、システムの
ユーザやアプリケーションに仮想マシンを提供する。オペレーティングシステムは、
本当の意味での「システム」を提供しているのである。大部分の PC では、複数の
オペレーティングシステムの走行が可能であり、それらはそれぞれに違った外観と
操作性を持っている。Linux は、機能的には別個の複数の部分から成り立っていて、
それらがひとつになってオペレーティングシステムを構成している。Linux の特徴的
な部分のひとつが、カーネルである。しかし、それさえもライブラリやシェルがなけ
れば役に立たない。

<!--
In order to start understanding what an operating system is, consider what
happens when you type an apparently simple command: 
-->
<p>オペレーティングシステムがどういうものか理解するために、非常に単純なコマンド
を打ったときに何が起こるのかを考えてみよう。

<tscreen><verb>
$ ls
Mail            c               images          perl
docs            tcl
$ 
</verb></tscreen>

<!--
The $ is a prompt put out by a login shell (in this case bash). This means that
it is waiting for you, the user, to type some command. Typing ls causes the
keyboard driver to recognize that characters have been typed. The keyboard
driver passes them to the shell which processes that command by looking for
an executable image of the same name. It finds that image, in /bin/ls.
Kernel services are called to pull the ls executable image into virtual memory
and start executing it. The ls image makes calls to the file subsystem of the
kernel to find out what files are available. The filesystem might make use of
cached filesystem information or use the disk device driver to read this
information from the disk. It might even cause a network driver to exchange
information with a remote machine to find out details of remote files that this
system has access to (filesystems can be remotely mounted via the
Networked File System or NFS). Whichever way the information is located,
ls writes that information out and the video driver displays it on the screen. 
-->
<p><tt>$</tt> は、ログインシェル(ここでは、bash)が出力するプロンプトである。
プロンプトとは、ユーザのコマンド入力をシェルが待っているということを
意味する。<tt>ls</tt> と打ち込むと、キーボードドライバは、文字が打ち込ま
れたことを認識し、そのコマンドをシェルに渡す。シェルは、それを処理するため
に、同じ名前の実行イメージがあるかどうかを探す。シェルが <tt>/bin/ls</tt> に
そのイメージがあることを発見すると、カーネルサービスを呼び出す。呼び出された
カーネルサービスは <tt>ls</tt> の実行イメージを仮想メモリに置いて、その実行を
始める。実行された <tt>ls</tt> のイメージは、カーネルのファイルサブシステムを
呼び出して、どのようなファイルがあるのかを探し出すよう命じる。ファイルシステ
ムは、キャッシュしておいたファイルシステムの情報を利用するか、ディスクデバイ
スドライバを使ってディスクからその情報を読み出させる。あるいは、(Network File 
System(NFS)経由でファイルシステムをリモートマウントしている場合)ネットワーク
ドライバを使用してリモートマシンと情報交換をし、ローカルシステムがアクセスし
ているリモートファイルの詳細について情報を探し出させるかもしれない。その情報
がいずれにある場合でも、<tt>ls</tt> はそうした情報を出力し、ビデオドライバが
それをスクリーンに表示する。

<!--
All of the above seems rather complicated but it shows that even most simple
commands reveal that an operating system is in fact a co-operating set of
functions that together give you, the user, a coherent view of the system. 
-->
<p>上記の説明はやや複雑に思えるかもしれない。しかし、この非常に単純なコマンド
の実行からでも明らかなように、オペレーティングシステムとは、実際、協調して働
く一連の関数のセットであり、それらが一体となることで、ユーザに整合性のあるシ
ステムの概観を提供しているのである。


<!--2.2.1  Memory management-->
<sect2>メモリ管理<label id="chapter_sb_sect2-1">

<!--
With infinite resources, for example memory, many of the things that an
operating system has to do would be redundant. One of the basic tricks of any
operating system is the ability to make a small amount of physical memory
behave like rather more memory. This apparently large memory is known as
virtual memory. The idea is that the software running in the system is fooled
into believing that it is running in a lot of memory. The system divides the
memory into easily handled pages and swaps these pages onto a hard disk as
the system runs. The software does not notice because of another trick,
multi-processing. 
-->
<p>メモリ等のリソースが無限にあるなら、オペレーティングシステムが果たすべき
役割の多くは、余計なものとなるかもしれない。どんなオペレーティングシステム
にもある基本的なトリックのひとつに、少ない物理メモリを実際以上に見せる能力
がある。この一見巨大なメモリは、仮想メモリと呼ばれる。このアイデアは、システム
上で実行されているソフトウェアを騙して、大量のメモリがあるように思いこませる
というものである。すなわち、システムはメモリをページという扱いやすい単位に
分割して、システム実行時に、そうしたページをハードディスク上にスワップ(swap)
する。ソフトウェアがそれに気付かないのは、もうひとつのトリックであるマルチ
プロセス機能のせいである。

<!--2.2.2  Processes-->
<sect2>プロセス<label id="chapter_sb_sect2-2">

<!--
A process could be thought of as a program in action, each process is a
separate entity that is running a particular program. If you look at the
processes on your Linux system, you will see that there are rather a lot. For
example, typing ps shows the following processes on my system: 
-->
<p>プロセスとは、実行中のプログラムであると考えることができる。個々のプロセス
は個別の実体であり、それぞれが特定のプログラムを実行している。Linux 
システム上のプロセスを見た場合、かなり多くのプロセスが存在することに気付くだ
ろう。たとえば、<tt>ps</tt> とタイプすると、筆者のシステム上では次のプロセスが
表示される。

<tscreen><verb>
$ ps
  PID TTY STAT  TIME COMMAND
  158 pRe 1     0:00 -bash
  174 pRe 1     0:00 sh /usr/X11R6/bin/startx
  175 pRe 1     0:00 xinit /usr/X11R6/lib/X11/xinit/xinitrc --
  178 pRe 1 N   0:00 bowman
  182 pRe 1 N   0:01 rxvt -geometry 120x35 -fg white -bg black
  184 pRe 1 <   0:00 xclock -bg grey -geometry -1500-1500 -padding 0
  185 pRe 1 <   0:00 xload -bg grey -geometry -0-0 -label xload
  187 pp6 1     9:26 /bin/bash
  202 pRe 1 N   0:00 rxvt -geometry 120x35 -fg white -bg black
  203 ppc 2     0:00 /bin/bash
 1796 pRe 1 N   0:00 rxvt -geometry 120x35 -fg white -bg black
 1797 v06 1     0:00 /bin/bash
 3056 pp6 3 <   0:02 emacs intro/introduction.tex
 3270 pp6 3     0:00 ps
$     
</verb></tscreen>

<!--
If my system had many CPUs then each process could (theoretically at least)
run on a different CPU. Unfortunately, there is only one so again the operating
system resorts to trickery by running each process in turn for a short period.
This period of time is known as a time-slice. This trick is known as
multi-processing or scheduling and it fools each process into thinking that it
is the only process. Processes are protected from one another so that if one
process crashes or malfunctions then it will not affect any others. The
operating system achieves this by giving each process a separate address
space which only they have access to. 
-->
<p>筆者のシステムに複数の CPU があれば、それぞれのプロセスを、(少なくとも
理論的には)違う CPU 上で実行することが可能である。しかし残念ながらひとつ
しかないため、オペレーティングシステムはここでもトリックを使って、短い時間で
プロセスを順番に実行する。その時間間隔はタイムスライス(time-slice)と呼ばれ、
このトリックは、マルチプロセッシング(multi-processing)もしくはスケジューリン
グ(scheduling)と呼ばれる。すなわちこれは、個々のプロセスを騙して、自分が唯一の
プロセスであると思い込ませるようにするものである。個々のプロセスは他のプロセ
スから保護された状態にあるので、ひとつのプロセスがクラッシュしたりおかしな動き
をしても、他のプロセスに影響を与えることはない。オペレーティングシステムはこの
ことを実現するために、個々のプロセスに自分だけがアクセスできる個別のアドレス
空間を付与している。

<!--2.2.3  Device drivers-->
<sect2>デバイスドライバ<label id="chapter_sb_sect2-3">

<!--
Device drivers make up the major part of the Linux kernel. Like other parts of
the operating system, they operate in a highly privileged environment and can
cause disaster if they get things wrong. Device drivers control the interaction
between the operating system and the hardware device that they are
controlling. For example, the filesystem makes use of a general block device
interface when writing blocks to an IDE disk. The driver takes care of the
details and makes device specific things happen. Device drivers are specific
to the controller chip that they are driving which is why, for example, you
need the NCR810 SCSI driver if your system has an NCR810 SCSI controller.
-->
<p>デバイスドライバは、Linux カーネルの重要な部分を形成している。オペレーティ
ングシステムの他の部分と同様に、デバイスドライバは非常に特権的な環境で
実行されるため、それらが上手く動かない場合は酷い状態になることがある。デバイス
ドライバは、デバイスを制御すると同時に、オペレーティングシステムとハードウェア
間での相互作用も制御する。たとえば、ファイルシステムは、IDE ディスクにブロック
単位の書き込みを行うとき、汎用のブロックデバイスインターフェイスを利用する。
ドライバはその IDE ディスクの詳細に気を配り、そのディスク固有の処理が適切に
実行されるようにする。デバイスドライバは、操作対象であるコントローラチップに
固有のものであるため、たとえば、システムで NCR810 SCSI コントローラを使用してい
る場合、NCR810 SCSI ドライバーが必要になる。

<!--2.2.4  The Filesystems-->
<sect2>ファイルシステム<label id="chapter_sb_sect2-4">

<!--
In Linux, as it is for Unix TM , the separate filesystems that the system may
use are not accessed by device identifiers (such as a drive number or a drive
name) but instead they are combined into a single hierarchical tree structure
that represents the filesystem as a single entity. Linux adds each new
filesystem into this single filesystem tree as they are mounted onto a mount
directory, for example /mnt/cdrom. One of the most important features of
Linux is its support for many different filesystems. This makes it very 
flexible and well able to coexist with other operating systems. The most 
popular filesystem for Linux is the EXT2 filesystem and this is the filesystem
supported by most of the Linux distributions. 
-->
<p>Linux では、Unix と同様に、システム上で個別のファイルシステムを使用する場
合、そのアクセス手段として、(ドライブ番号やドライブ名などの)デバイス識別子は
利用しない。そのかわり、ファイルシステムは、単一の階層的なツリー構造に組み込
まれ、それによって単一の実体として表現される。Linux は、新しい個々のファイル
システムをその単一のファイルシステムに付け加える際、たとえば <tt>/mnt/cdrom
</tt> といったマウントディレクトリ上にマウントするという方法を取る。Linux の
最も重要な特徴のひとつは、多くの異なるファイルシステムのサポートである。
それによって、Linux は、非常に柔軟で、他のオペレーティングシステム
とも上手く共存できるものになっている。Linux の最も一般的なファイルシステムは、
EXT2 ファイルシステムであり、このファイルシステムは、ほとんどの Linux 
ディストリビューションでサポートされている。

<!--
A filesystem gives the user a sensible view of files and directories held on
the hard disks of the system regardless of the filesystem type or the
characteristics of the underlying physical device. Linux transparently
supports many different filesystems (for example MS-DOS and EXT2) and
presents all of the mounted files and filesystems as one integrated virtual
filesystem. So, in general, users and processes do not need to know what sort
of filesystem that any file is part of, they just use them. 
-->
<p>ファイルシステムは、システムのハードディスク上に保存されているファイルや
ディレクトリに関する分かり易い展望をユーザに与える。その際、ファイルシステム
のタイプや、基礎となる物理デバイスの性質の違いは捨象される。Linux は多くの異
なるファイルシステム(たとえば MS-DOS や EXT2)を透過的にサポートし、マウントされ
たファイルやファイルシステムをひとつに統合された仮想ファイルシステムとして
提供する。したがって、一般的に、ユーザやプロセスは、特定のファイルがどのよう
な種類のファイルシステムに属しているのかを知る必要なしに、それを使用できる。

<!--
The block device drivers hide the differences between the physical block
device types (for example, IDE and SCSI) and, so far as each filesystem is
concerned, the physical devices are just linear collections of blocks of data.
The block sizes may vary between devices, for example 512 bytes is common
for floppy devices whereas 1024 bytes is common for IDE devices and, again,
this is hidden from the users of the system. An EXT2 filesystem looks the
same no matter what device holds it. 
-->
<p>ブロックデバイスドライバは、物理的なブロックデバイスのタイプ(たとえば、IDE 
や SCSI)の違いを隠すことが出来る。それゆえ、ファイルシステムに関する限り、物理
デバイスは、データブロックの線形的な集合にすぎない。ブロックサイズは、デバイス
によって異なり、たとえば、フロッピーディスクは 512 バイトが一般的であり、IDE 
ハードディスクでは 1024 バイトが一般的である。しかし、これについても、システム
のユーザからは隠されている。EXT2 ファイルシステムは、そのファイルシステムが置
かれたデバイスがどのようなものであっても、同じ外観を持つ。

<!--2.3  Kernel Data Structures-->
<sect1>カーネルのデータ構造<label id="chapter_sb_sect3">

<!--
The operating system must keep a lot of information about the current state
of the system. As things happen within the system these data structures
must be changed to reflect the current reality. For example, a new process
might be created when a user logs onto the system. The kernel must create a
data structure representing the new process and link it with the data
structures representing all of the other processes in the system. 
-->
<p>オペレーティングシステムは、システムの現在の状態について多くの情報を保持
する必要がある。システム内で何かが起こったら、それに関するデータ構造は
現在の状態を反映するように書き換えられなければならない。たとえば、ユーザがシス
テムにログオンすると、新しいプロセスが生成される。カーネルは、新しいプロセス
を表現するデータ構造体を作成して、それ以外のシステム上の全プロセスを表現し
ているデータ構造体にそれをリンクさせなければならない。

<!--
Mostly these data structures exist in physical memory and are accessible
only by the kernel and its subsystems. Data structures contain data and
pointers; addresses of other data structures or the addresses of routines.
Taken all together, the data structures used by the Linux kernel can look very
confusing. Every data structure has a purpose and although some are used by
several kernel subsystems, they are more simple than they appear at first
sight. 
-->
<p>このようなデータ構造体の大部分は、物理メモリ内に存在し、カーネルとそのサブ
システムからしかアクセスできないようになっている。データ構造体には、データと
ポインタ、すなわち他のデータ構造のアドレスやルーチンのアドレスが含まれている。
それらすべてを一度に見ようとした場合、Linux カーネルによって利用されている
データ構造体は、非常に紛らわしく分かりにくいものに思えるかもしれない。しか
し、すべてのデータ構造体には目的があり、数種のカーネルサブシステムから利用
される(複雑な)構造体もあるが、一般的には、それらは最初に一見した時の印象より
もずっとシンプルである。

<!--
Understanding the Linux kernel hinges on understanding its data structures
and the use that the various functions within the Linux kernel makes of them.
This book bases its description of the Linux kernel on its data structures. It
talks about each kernel subsystem in terms of its algorithms, its methods of
getting things done, and their usage of the kernel's data structures. 
-->
<p>Linux カーネルの理解は、そのデータ構造と、Linux カーネル内の種々の
関数がそれを使用する方法とを理解できるかどうかにかかっている。本書は、
Linux カーネルの説明に際し、そのデータ構造の解説に重点を置く。
個々のカーネルのサブシステムを説明するときは、そのアルゴリズム、処理方法と
同時に、それらが使用しているカーネルのデータ構造という観点を重視する。

<!--2.3.1  Linked Lists-->
<sect2>連結リスト<label id="chapter_sb_sect3-1">

<!--
Linux uses a number of software engineering techniques to link together its
data structures. On a lot of occasions it uses linked or chained data
structures. If each data structure describes a single instance or occurance of
something, for example a process or a network device, the kernel must be
able to find all of the instances. In a linked list a root pointer contains the
address of the first data structure, or element, in the list and each data
structure contains a pointer to the next element in the list. The last 
element's next pointer would be 0 or NULL to show that it is the end of the 
list. In a doubly linked list each element contains both a pointer to the next
element in the list but also a pointer to the previous element in the list. 
Using doubly linked lists makes it easier to add or remove elements from the 
middle of list although you do need more memory accesses. This is a typical 
operating system trade off: memory accesses versus CPU cycles. 
-->
<p>Linux は、多くのソフトウェア工学上のテクニックを使って、データ構造を相互に
リンクしている。多くの場合、Linux では連結あるいは連鎖データ構造体が使用されて
いる。もし、個々のデータ構造体が、単一のプロセスやネットワークデバイスといった
個別の現象や事物を記述するだけなら、カーネルにはそれらの個別データをすべて
探し出す能力が必要になる。連結リストでは、ルートポインタがリスト上の
最初のデータ構造体もしくは要素のアドレスを含んでいて、それぞれのデータ構造体が
リスト上の次の要素へのポインタを含んでいる。最後の要素に含まれる次の要素への
ポインタは(リストの終わりを示す意味がある) 0 か NULL のどちらかである。
二重連結リストでは、個々の要素が、リスト上の次の要素へのポインタとひとつ前の
要素へのポインタの両方を含んでいる。二重連結リストを使えば、リストの真ん中で
要素の追加や削除をすることが容易になるが、ただし、メモリへのアクセス頻度は増加
する。これは、メモリアクセスと CPU サイクルのどちらを優先するかという、オペレー
ティングシステムに典型的な二者択一の問題である。

<!--2.3.2  Hash Tables-->
<sect2>ハッシュテーブル<label id="chapter_sb_sect3-2">

<!--
Linked lists are handy ways of tying data structures together but navigating
linked lists can be inefficient. If you were searching for a particular 
element, you might easily have to look at the whole list before you find the 
one that you need. Linux uses another technique, hashing to get around this 
restriction. A hash table is an array or vector of pointers. An array, or 
vector, is simply a set of things coming one after another in memory. A 
bookshelf could be said to be an array of books. Arrays are accessed by an 
index, the index is an offset into the array. Taking the bookshelf analogy a 
little further, you could describe each book by its position on the shelf; 
you might ask for the 5th book. 
-->
<p>連結リストは、データ構造体を結びつけるには手軽な方法だが、連結リストを辿る
のは非効率な場合がある。特定の要素を検索するなら、リスト全体を簡単に眺めて、
その上で必要な要素を見つけるようにすべきだろう。Linux は、ハッシング(hashing)
という別のテクニックを使って、連結リストの限界を克服している。
ハッシュテーブル(hash table)は、ポインタの配列(array)もしくはベクトル(vector)
である。配列もしくはベクトルとは、単にメモリ内に連続する一連の要素のことであ
る。たとえば、本棚は、本の配列(array)であると言える。配列はインデックスでアクセ
スが可能である。インデックスとは配列へのオフセット(offset)である。再度本棚の
類推で考えると、それぞれの本は、本棚上の位置で表すことができる。5 冊目
(offset)の本という言い方でそれを指定できる。

<!--
A hash table is an array of pointers to data structures and its index is 
derived from information in those data structures. If you had data structures
describing the population of a village then you could use a person's age as an
index. To find a particular person's data you could use their age as an index
into the population hash table and then follow the pointer to the data 
structure containing the person's details. Unfortunately many people in the 
village are likely to have the same age and so the hash table pointer becomes 
a pointer to a chain or list of data structures each describing people of the 
same age. However, searching these shorter chains is still faster than 
searching all of the data structures. 
-->
<p>ハッシュテーブルは、データ構造体に対するポインタの配列であり、そのインデッ
クスは、それらのデータ構造体内の情報から抽出される。ある村の人口を表すデータ
構造体があるとすると、その住人の年齢をインデックスとして使うことができる。
特定の住人のデータを検索する場合、年齢をインデックスとして使用して、その村の
人口についてのハッシュテーブルを検索し、該当するポインタを辿れば、ポイント先
の構造体にその住人の詳細が含まれている。残念ながら、村には、同年齢の住人が
大勢いる場合が多いので、ハッシュテーブルのポインタは、同年齢の住人を記述した
データ構造体の連鎖かリストに対するポインタになるだろう。しかし、こうした短
い連鎖を検索することは、データ構造体すべてを検索するよりもずっと高速である。

<!--
As a hash table speeds up access to commonly used data structures, Linux
often uses hash tables to implement caches. Caches are handy information
that needs to be accessed quickly and are usually a subset of the full set of
information available. Data structures are put into a cache and kept there
because the kernel often accesses them. There is a drawback to caches in
that they are more complex to use and maintain than simple linked lists or
hash tables. If the data structure can be found in the cache (this is known as
a cache hit, then all well and good. If it cannot then all of the relevant data
structures must be searched and, if the data structure exists at all, it must 
be added into the cache. In adding new data structures into the cache an old
cache entry may need discarding. Linux must decide which one to discard, the
danger being that the discarded data structure may be the next one that Linux
needs. 
-->
<p>ハッシュテーブルを使うと、よく利用されるデータ構造体へのアクセスを高速化で
きるので、Linux は、しばしばハッシュテーブルを、キャッシュ(cache)の実装のために
使用している。キャッシュはすばやいアクセスが必要な際の手軽な情報源であり、
通常、手に入る情報のフルセットに対するサブセットとなっている。
カーネルがあるデータ構造体に対し頻繁にアクセスする場合、そのデータ構造体は
キャッシュに入れられて保存される。キャッシュの欠点は、単純な連結リストや
ハッシュテーブルよりも使用と管理が複雑になることである。もしデータ構造体が
キャッシュ内で見つかれば(これは、キャッシュヒット(cache hit)と言われる)、
問題のない良い結果が得られる。しかし、もし見つからない場合、関連するすべて
のデータ構造体が検索され、該当するデータ構造体が存在した際には、それを
キャッシュに追加しなければならない。データ構造体をキャッシュに追加すると、
古いキャッシュエントリを破棄する必要が生じる。Linux はどれを破棄するか決定し
なければならないのだが、問題は、破棄されたデータ構造体は、Linux が次に必要とす
るデータそのものである場合があることである。

<!--2.3.3  Abstract Interfaces-->
<sect2>抽象インターフェイス<label id="chapter_sb_sect3-3">

<!--
The Linux kernel often abstracts its interfaces. An interface is a collection 
of routines and data structures which operate in a particular way. For example
all network device drivers have to provide certain routines in which particular
data structures are operated on. This way there can be generic layers of code
using the services (interfaces) of lower layers of specific code. The network
layer is generic and it is supported by device specific code that conforms to a
standard interface. 
-->
<p>Linux はしばしばそのインターフェイスを抽象化する。インターフェイスとは、
特定の方法で操作されるルーチンとデータ構造体の集合である。たとえば、すべての
ネットワークデバイスドライバは、一定のルーチンを提供しなければならない。
そして、そのドライバのルーチンが、デバイス固有のデータ構造体を処理する。
この方法を使うと、汎用コードから成るレイヤーの存在が可能になる。すなわち、
汎用レイヤーのコードは、下層レイヤーにあるデバイス固有のコードが提供する
サービス(あるいは、インターフェイス)を使用するわけである。ネットワーク
レイヤーは汎用コードから成り、その汎用コードが、標準インターフェイスに準拠
した、デバイス固有のコードによってサポートされている。

<!--
Often these lower layers register themselves with the upper layer at boot
time. This registration usually involves adding a data structure to a linked 
list. For example each filesystem built into the kernel registers itself with 
the kernel at boot time or, if you are using modules, when the filesystem is 
first used. You can see which filesystems have registered themselves by looking
at the file /proc/filesystems. The registration data structure often
includes pointers to functions. These are the addresses of software functions
that perform particular tasks. Again, using filesystem registration as an
example, the data structure that each filesystem passes to the Linux kernel
as it registers includes the address of a filesystem specfic routine which
must be called whenever that filesystem is mounted. 
-->
<p>しばしばそうした下層レイヤーは、起動時に上層レイヤーと伴に登録される。
この登録の際には、通常、データ構造体を連結リストに追加する処理がなされる。
たとえば、あるファイルシステムがカーネルに組み込まれている場合、その個々の
ファイルシステムは起動時にカーネルに登録される。あるいは、もしモジュールに
なっている場合は、ファイルシステムが最初に呼びだされたときに、登録がなされ
る。<tt>/proc/filesystems</tt> というファイルを見れば、どのファイルシステムが
登録されているかが分かる。
カーネルへの登録に使用されるデータ構造体には、しばしば、複数の関数へのポイン
タが含まれている。それらは、特定のタスクを実行する関数のアドレスである。
再度、ファイルシステムの登録を例にとると、個々のファイルシステムが登録の際に
カーネルに渡すデータ構造体には、そのファイルシステムに固有のルーチンのアドレ
スが含まれている。そして、そのルーチンのアドレスを使用して当該ルーチンを呼び
出すことで、当該ファイルシステムがマウントされる仕組みになっている。

<!--第  4 章 メモリ管理-->
<!--Chapter 3 Memory Management-->
<sect>メモリ管理<label id="chapter_mm">
<p><figure><ph vspace="75"><img src="./The-Linux-Kernel-images/penguin2.gif">
</figure>

<!--
The memory management subsystem is one of the most important parts of the
operating system. Since the early days of computing, there has been a need for
more memory than exists physically in a system. Strategies have been
developed to overcome this limitation and the most successful of these is 
virtual memory. Virtual memory makes the system appear to have more memory 
than it actually has by sharing it between competing processes as they need 
it. 
-->
<p>メモリ管理サブシステムは、オペレーティングシステムの最も重要な部分
のひとつである。コンピュータの黎明期以来、システム上にある物理メモリだけでは
足りない状況がずっと続いてきた。この限界を克服するために様々な戦略が立てられ
たが、それらのうちで最も成功したのが、仮想メモリ(virtual memory)である。
仮想メモリとは、システムに実際以上のメモリがあるかのように見せる仕組みであり、
メモリ争奪関係にあるプロセス間で、必要に応じてそれらを協調して使用することに
より実現されている。

<!--
Virtual memory does more than just make your computer's memory go further.
The memory management subsystem provides: 
-->
<p>仮想メモリは、コンピュータのメモリを大きく見せること以外にも様々な機能を
提供している。メモリ管理サブシステムが提供する機能には、次のようなものがあ
る。

<descrip>

<!--Large Address Spaces-->
<tag>巨大なアドレス空間</tag>
<!--
      The operating system makes the system appear as if it has a larger
      amount of memory than it actually has. The virtual memory can be many
      times larger than the physical memory in the system, 
-->
<p>オペレーティングシステムは、システム上に実際以上のメモリがあるかのように
振る舞う。仮想メモリはシステム上の物理メモリより、何倍も大容量にできる。

<!--Protection-->
<tag>データ保護</tag>
<!--
      Each process in the system has its own virtual address space. These
      virtual address spaces are completely separate from each other and so a
      process running one application cannot affect another. Also, the
      hardware virtual memory mechanisms allow areas of memory to be
      protected against writing. This protects code and data from being
      overwritten by rogue applications. 
-->
<p>システム上のプロセスは、各々が独自の仮想アドレス空間を持っている。これらの
仮想アドレス空間は、お互いに完全に独立しているので、あるアプリケーションを実行
しているプロセスは、他のプロセスに影響を与え得ない。
さらに、メモリエリアはハードウェア上の仮想メモリ機構によって、書き込みから保護
されている。
これによって、コードやデータを、出来の悪いアプリケーションによる上書きから
保護している。

<!--Memory Mapping-->
<tag>メモリマッピング</tag>
<!--
      Memory mapping is used to map image and data files into a processes
      address space. In memory mapping, the contents of a file are linked
      directly into the virtual address space of a process. 
-->
<p>メモリマッピング(memory mapping)は、イメージやデータファイルをプロセスの
アドレス空間にマップ(map)するために使用される。メモリマッピングにおいて、
ファイルの内容は、プロセスの仮想アドレス空間に直接リンクされる。

<!--Fair Physical Memory Allocation-->
<tag>公正な物理メモリの割り当て</tag>
<!--
      The memory management subsystem allows each running process in the
      system a fair share of the physical memory of the system, 
-->
<p>メモリ管理サブシステムによって、システム上で実行されている個々のプロセスは、
システムの物理メモリ上に公正な持ち分を所持することができる。

<!--Shared Virtual Memory-->
<tag>共有仮想メモリ</tag>
<!--
      Although virtual memory allows processes to have separate (virtual)
      address spaces, there are times when you need processes to share
      memory. For example there could be several processes in the system
      running the bash command shell. Rather than have several copies of
      bash, one in each processes virtual address space, it is better to have
      only one copy in physical memory and all of the processes running bash
      share it. Dynamic libraries are another common example of executing
      code shared between several processes. 
-->
<p>仮想メモリはプロセスが個別の(仮想)アドレス空間を持つようにしているが、
複数のプロセスでメモリを共有(share)しなければならない場合もある。たとえば、<tt>
bash</tt> のコマンドシェルを実行しているプロセスがシステム上に複数存在するこ
とがある。その場合、物理メモリ内に複数の <tt>bash</tt> のコピーが存在して、
個々のプロセスが個別の仮想アドレス空間を持つよりも、ひとつだけのコピーが存在
し、<tt>bash</tt> を実行するすべてのプロセスでその仮想アドレス空間を共有する
ほうが効率がよい。動的ライブラリ(dynamic library)は、複数のプロセス間で実行
コードを共有するもうひとつの典型例である。

<!--
      Shared memory can also be used as an Inter Process Communication
      (IPC) mechanism, with two or more processes exchanging information
      via memory common to all of them. Linux supports the Unix TM System
      V shared memory IPC. 
-->
<p>共有メモリ(shared memory)は、プロセス間通信(Inter Process Communication, 
IPC)のメカニズムでも使用される。それは、ふたつ以上のプロセスが、それらすべて
に共通のメモリを経由して、情報を交換する仕組みである。Linux は、Unix System 
V の共有メモリ IPC をサポートしている。


</descrip>


<!--3.1  An Abstract Model of Virtual Memory-->
<sect1>仮想メモリの抽象モデル<label id="chapter_mm_sect1">
<p>

<label id="figure3-1">
<!--Figure 3.1: Abstract model of Virtual to Physical address mapping-->
<#if output="html"><figure>
<ph vspace="100"><img src="./The-Linux-Kernel-images/figure3-1.gif">
</figure>
</#if>
<#unless output="html">
<verb>
                                                             プロセス Y
                                             プロセス Y      +--------+
プロセス X                                  ページテーブル +-| VPFN 7 |
+--------+                                    ________     | |--------|
| VPFN 7 |-+   プロセス X                   +-|_______|<-+ | | VPFN 6 |
|--------| |  ページテーブル                | |_______|  | | |--------|
| VPFN 6 | |   ________                   +-+-|_______|<-+-+ | VPFN 5 |
|--------| +->|_______|-+      +-------+  | | |_______|  |   |--------|
| VPFN 5 |    |_______| |   +->| PFN 4 |<-+-+ |_______|  |   | VPFN 4 |
|--------| +->|_______|-+-+ |  |       |  |   |_______|  |   |--------|
| VPFN 4 | |  |_______| | | |  |-------+  |              |   | VPFN 3 |
|--------| |  |_______| | | |  | PFN 3 |  |              |   |--------|
| VPFN 3 |-+->|_______|-+-+-+  |       |  |              |   | VPFN 2 |
|--------| |            | |    |-------|  |              |   |--------|
| VPFN 2 | |            | |    | PFN 2 |<-+              +---| VPFN 1 |
|--------| |            | |    |       |                     |--------|
| VPFN 1 | |            | |    |-------|                     | VPFN 0 |
|--------| |            | +--->| PFN 1 |                     +--------+
| VPFN 0 |-+            |      |       |
+--------+              |      |-------|
                        +----->| PFN 0 |
                               |       |
                               +-------+
仮想メモリ                     物理メモリ                    仮想メモリ
</verb>
</#if>



<p>図表(3.1) 仮想アドレスから物理アドレスへのマッピングに関する抽象モデル


<!--
Before considering the methods that Linux uses to support virtual memory it is
useful to consider an abstract model that is not cluttered by too much detail. 
-->
<p>Linux が仮想メモリをサポートする方法を考える前に、煩瑣な詳細を省いた抽象
モデルを検討することは有益である。

<!--
As the processor executes a program it reads an instruction from memory and
decodes it. In decoding the instruction it may need to fetch or store the 
contents of a location in memory. The processor then executes the instruction 
and moves onto the next instruction in the program. In this way the processor 
is always accessing memory either to fetch instructions or to fetch and store 
data. 
-->
<p>プロセッサがプログラムを実行するとき、プロセッサはメモリから命令を読み出し
て、デコード(decode)する。命令をデコードする際、プロセッサは、ある地点の
メモリの内容を読み出したり(fetch)、書き込んだり(store)することが必要になる場合
もある。そして、プロセッサはその命令を実行し、プログラムの次の命令に移る。
このように、プロセッサはいつもメモリにアクセスしながら、命令を読み出したり、
あるいは、データを読み書きしたりしている。

<!--
In a virtual memory system all of these addresses are virtual addresses and not
physical addresses. These virtual addresses are converted into physical
addresses by the processor based on information held in a set of tables
maintained by the operating system. 
-->
<p>仮想メモリシステムでは、それらに使用されるアドレスはすべて仮想アドレスで
あり、物理アドレスではない。それらの仮想アドレスはプロセッサによって物理
アドレスに変換されるのだが、その変換は、オペレーティングシステムが管理する
変換テーブルに保持された情報を基にして行われる。

<!--
To make this translation easier, virtual and physical memory are divided into
handy sized chunks called pages. These pages are all the same size, they need
not be but if they were not, the system would be very hard to administer. Linux
on Alpha AXP systems uses 8 Kbyte pages and on Intel x86 systems it uses 4
Kbyte pages. Each of these pages is given a unique number; the page frame
number (PFN). 
-->
<p>この変換を容易にするため、仮想メモリと物理メモリは、ページ(page)と呼ばれる
扱い易い単位に分割されている。それらのページはすべて同じサイズである。ページ
のサイズは必ずしも同一である必要はないのだが、同一サイズでない場合、システム
による管理が非常に困難なものになるためにそうされている。Alpha AXP システム上
の Linux では、8 k バイトのページを使用し、Intel x86 システムでは、4 k バイト
のページが使用されている。ページそれぞれには、他と重複しない数値のページ
フレーム番号(Page Frame Number, PFN)が割り振られている。

<!--
In this paged model, a virtual address is composed of two parts; an offset and
a virtual page frame number. If the page size is 4 Kbytes, bits 11:0 of the 
virtual address contain the offset and bits 12 and above are the virtual page 
frame number. Each time the processor encounters a virtual address it must 
extract the offset and the virtual page frame number. The processor must 
translate the virtual page frame number into a physical one and then access 
the location at the correct offset into that physical page. To do this the 
processor uses page tables. 
-->
<p>このようにページ分割されたシステムの場合、仮想アドレスは、オフセット(offset)
と仮想ページフレーム番号(PFN)のふたつの部分から構成される。ページサイズが 
4 k バイトならば、仮想アドレスの bit 11 から 0 にオフセットが含まれていて、
bit 12 以降が仮想ページフレーム番号となっている。
プロセッサは仮想アドレスに出会うたびに、オフセット番号と仮想ページフレーム
番号を抽出する。プロセッサは、仮想ページフレーム番号を物理ページフレーム番号
に変換し、その上で、該当する物理ページの正しいオフセット番号の位置にアクセス
する。その変換のために、プロセッサはページテーブル(page table)を使用する。

<!--
Figure  3.1 shows the virtual address spaces of two processes, process X and
process Y, each with their own page tables. These page tables map each
processes virtual pages into physical pages in memory. This shows that process
X's virtual page frame number 0 is mapped into memory in physical page frame
number 1 and that process Y's virtual page frame number 1 is mapped into
physical page frame number 4. Each entry in the theoretical page table contains
the following information: 
-->
<p><ref id="figure3-1" name="図表(3.1)">は、プロセス X とプロセス Y というふた
つのプロセスの仮想アドレス空間を示すもので、どちらもプロセス自身のページテー
ブルを持っている。それらのページテーブルは、プロセスの仮想ページをメモリの物理
ページにマップするものである。この図表では、プロセス X の仮想ページフレーム番
号 0 が物理ページフレーム番号 1 にマップされ、プロセス Y の仮想ページフレーム
番号 1 が物理ページフレーム番号 4 にマップされている。理論的には、ページテーブ
ル内のそれぞれのエントリーには、次の情報が含まれている。

<!--
      Valid flag. This indicates if this page table entry is valid, 
      The physical page frame number that this entry is describing, 
      Access control information. This describes how the page may be used.
      Can it be written to? Does it contain executable code? 
-->
<descrip>
<tag>有効フラグ(valid flag)</tag>
ページテーブルのエントリが有効かどうかを示す。

<tag>物理ページフレーム番号(physical page frame number)</tag>
そのエントリが記述している物理ページフレーム番号。

<tag>アクセス制御情報(access control information)</tag>
そのページが利用される方法を記述している。書き込み可能か、
実行コードを含むかといったことに関係する情報。
</descrip>

<!--
The page table is accessed using the virtual page frame number as an offset.
Virtual page frame 5 would be the 6th element of the table (0 is the first
element). 
-->
<p>ページテーブルにアクセスする場合、仮想ページフレーム番号が(ページテーブル
への)オフセットとして使用される。仮想ページフレーム番号の 5 は、ページテーブ
ルの 6 番目の要素に該当する。(0 が最初の要素に該当するためである。)

<!--
To translate a virtual address into a physical one, the processor must first 
work out the virtual addresses page frame number and the offset within that 
virtual page. By making the page size a power of 2 this can be easily done by 
masking and shifting. Looking again at Figures  3.1 and assuming a page size 
of 0x2000 bytes (which is decimal 8192) and an address of 0x2194 in process 
Y's virtual address space then the processor would translate that address into
offset 0x194 into virtual page frame number 1. 
-->
<p>仮想アドレスを物理アドレスに変換する場合、プロセッサはまず仮想アドレスページ
フレーム番号とその仮想ページ内のオフセット値を探さなければならない。ページサ
イズを 2 の n 乗とすることで、マスク操作(masking)とシフト操作(shifting)により
それは簡単に実行できる。もう一度<ref id="figure3-1" name="図表(3.1)">を見てほ
しい。ページサイズが 0x2000 バイト(十進数なら 8192)で、プロセス Y の仮想アド
レス空間でのアドレスが 0x2194 だとすると、プロセッサがそのアドレスを変換した
結果は、オフセット値 0x194 を持つ仮想ページ番号 1 となる。

<!--
The processor uses the virtual page frame number as an index into the
processes page table to retrieve its page table entry. If the page table entry
at that offset is valid, the processor takes the physical page frame number 
from this entry. If the entry is invalid, the process has accessed a 
non-existent area of its virtual memory. In this case, the processor cannot 
resolve the address and must pass control to the operating system so that it 
can fix things up. 
-->
<p>プロセッサは、仮想ページフレーム番号をプロセスのページテーブルへの
インデックスとして使用することで、そのページテーブルエントリを知る。もしその
オフセット位置にあるページテーブルエントリが有効(valid)ならば、プロセッサはその
エントリから物理ページフレーム番号を取得する。エントリが無効なら、プロセスは
物理メモリ上に存在しない仮想メモリ領域にアクセスしたことになる。その場合、
プロセッサはアドレスを解決できないので、オペレーティングシステムに制御を渡す
ことで、問題の解決を依頼する。

<!--
Just how the processor notifies the operating system that the correct process
has attempted to access a virtual address for which there is no valid 
translation is specific to the processor. However the processor delivers it, 
this is known as a page fault and the operating system is notified of the 
faulting virtual address and the reason for the page fault. 
-->
<p>現在のプロセスが有効な変換先のない仮想アドレスにアクセスしようとしたことを
プロセッサがオペレーティングシステムに伝える方法は、プロセッサの種類によって
異なる。しかしプロセッサの伝達方法がどのようなものであれ、その現象
はページフォルト(page fault)と呼ばれていて、オペレーティングシステムには、
フォルトとなった仮想アドレスとフォルトが生じた原因とが通知される。

<!--
Assuming that this is a valid page table entry, the processor takes that 
physical page frame number and multiplies it by the page size to get the 
address of the base of the page in physical memory. Finally, the processor 
adds in the offset to the instruction or data that it needs. 
-->
<p>ページテーブルのエントリが有効であった場合、プロセッサは、物理ページフレーム
番号を取得し、それにページサイズを掛け算して、物理メモリ内のページのベース
アドレス(base address)を取得する。最後に、プロセッサは、(そのベースアドレス
を起点に)取得すべき命令やデータまでのオフセットを、そのベースアドレスに加える
(ことで、完全な物理アドレスを得る)。

<!--
Using the above example again, process Y's virtual page frame number 1 is
mapped to physical page frame number 4 which starts at 0x8000 (4 x 0x2000).
Adding in the 0x194 byte offset gives us a final physical address of 0x8194. 
-->
<p>上記の例を再び取り上げると、プロセス Y の仮想ページフレーム番号 1 は、
物理ページフレーム番号 4 にマップされる。その物理ページフレームは、アドレス 
0x8000(4 x 0x2000)を起点(ベースアドレス)としている。そのアドレスに 0x194 
バイトのオフセット値を加えると、最後に 0x8194 という物理アドレスが得られる。

<!--
By mapping virtual to physical addresses this way, the virtual memory can be
mapped into the system's physical pages in any order. For example, in Figure 
3.1 process X's virtual page frame number 0 is mapped to physical page frame
number 1 whereas virtual page frame number 7 is mapped to physical page frame
number 0 even though it is higher in virtual memory than virtual page frame
number 0. This demonstrates an interesting byproduct of virtual memory; the
pages of virtual memory do not have to be present in physical memory in any
particular order. 
-->
<p>仮想アドレスから物理アドレスへのマッピングにこうした方法を使用することで、
仮想メモリからシステムの物理メモリへのマッピングが、その番号と無関係に可能と
なる。たとえば、<ref id="figure3-1" name="図表(3.1)">において、プロセス X の
仮想ページフレーム番号 0 は、
物理ページフレーム番号 1 にマップされるが、仮想ページフレーム番号 7 は、仮想
ページフレーム 0 より大きな番号であるにも関わらず、物理ページフレーム 0 に
マップされる。このことは、仮想メモリ機構が興味深い副産物を持つことを意味す
る。すなわち、仮想メモリのページは、物理メモリ内で特定の順番通りに並んでいる
必要がないということである。

<!--3.1.1  Demand Paging-->
<sect2>デマンドページング<label id="chapter_mm_sect1-1">

<!--
As there is much less physical memory than virtual memory the operating
system must be careful that it does not use the physical memory inefficiently.
One way to save physical memory is to only load virtual pages that are 
currently being used by the executing program. For example, a database program
may be run to query a database. In this case not all of the database needs to 
be loaded into memory, just those data records that are being examined. If the
database query is a search query then it does not make sense to load the code 
from the database program that deals with adding new records. This technique 
of only loading virtual pages into memory as they are accessed is known as 
demand paging. 
-->
<p>仮想メモリに比べて物理メモリは非常に量が少ないので、オペレーティングシステム
は物理メモリを効率的に使うよう気を配らなければならない。物理メモリを節約す
るひとつの方法は、実行中のプログラムが現在使用している仮想ページだけをロード
することである。たとえば、データベースプログラムがデータベースに問い合わせを
実行したとする。その場合、データベース全体がメモリにロードされる
必要はなく、調べる必要のあるデータレコードだけがロードされればよい。データ
ベースへの問い合わせが検索である場合、新規レコード追加の処理をするデータ
ベースプログラムのコードをロードしても意味がない。アクセスされた仮想ページだけ
をメモリにロードするというこのテクニックは、デマンドページング(demand paging)
と呼ばれる。

<!--
When a process attempts to access a virtual address that is not currently in
memory the processor cannot find a page table entry for the virtual page
referenced. For example, in Figure  3.1 there is no entry in process X's page
table for virtual page frame number 2 and so if process X attempts to read from
an address within virtual page frame number 2 the processor cannot translate
the address into a physical one. At this point the processor notifies the 
operating system that a page fault has occurred. 
-->
<p>プロセスが物理メモリ上にない仮想アドレスにアクセスしようとした場合、プロ
セッサは、参照された仮想ページのページテーブルエントリを見つけることができな
い。たとえば、<ref id="figure3-1" name="図表(3.1)"> では、プロセス X の
ページテーブルには、仮想フレーム番号 2 のエントリがないので、プロセス X が
仮想ページフレーム番号 2 の中にあるアドレスを読もうとしても、プロセッサは、
そのアドレスを物理メモリ上のアドレスに変換できない。この時点で、プロセッサは、
ページフォルトが発生したことをオペレーティングシステムに通知する。

<!--
If the faulting virtual address is invalid this means that the process has
attempted to access a virtual address that it should not have. Maybe the
application has gone wrong in some way, for example writing to random
addresses in memory. In this case the operating system will terminate it,
protecting the other processes in the system from this rogue process. 
-->
<p>フォルトとなった仮想アドレスが無効なものである場合、それはプロセスが存在
しない仮想アドレスにアクセスしようとしたことを意味する。おそらく、アプリ
ケーションに不具合が起こって、たとえばメモリ内のランダムなアドレスへ書き込み
をしようとしたのかもしれない。この場合、オペレーティングシステムはその
プロセスを終了させて、暴走したそのプロセスからシステム内の他のプロセスを
保護する。

<!--
If the faulting virtual address was valid but the page that it refers to is not
currently in memory, the operating system must bring the appropriate page into
memory from the image on disk. Disk access takes a long time, relatively
speaking, and so the process must wait quite a while until the page has been
fetched. If there are other processes that could run then the operating system
will select one of them to run. The fetched page is written into a free 
physical page frame and an entry for the virtual page frame number is added to
the processes page table. The process is then restarted at the machine 
instruction where the memory fault occurred. This time the virtual memory 
access is made, the processor can make the virtual to physical address 
translation and so the process continues to run. 
-->
<p>しかし、フォルトとなった仮想アドレスが有効なものであり、参照されたページは
そのときメモリ内になかっただけである場合、オペレーティングシステムは、ディスク
上のイメージから適切なページをメモリ内に持ってこなければならない。ディスク
アクセスは、相対的に時間の掛かる処理なので、プロセスは、ページが来るまでの間
待っている必要がある。その際に実行可能なプロセスがあれば、オペレーティ
ングシステムはそのいくつかを選んで実行する。そして、取ってきたページを空いた
物理ページフレームに書き込んで、仮想ページフレーム番号用のエントリーを
プロセスのページテーブルに追加する。それによって、プロセスはメモリフォルトが
発生した命令があった場所から再び実行される。今度は、仮想メモリへのアクセスに
成功し、プロセッサも仮想アドレスから物理アドレスへの変換ができるので、
プロセスの実行は継続する。

<!--
Linux uses demand paging to load executable images into a processes virtual
memory. Whenever a command is executed, the file containing it is opened and
its contents are mapped into the processes virtual memory. This is done by
modifying the data structures describing this processes memory map and is
known as memory mapping. However, only the first part of the image is actually
brought into physical memory. The rest of the image is left on disk. As the 
image executes, it generates page faults and Linux uses the processes memory 
map in order to determine which parts of the image to bring into memory for 
execution. 
-->
<p>Linux は、デマンドページングを使用して、実行イメージをプロセスの仮想メモリ
にロードする。コマンドが実行される際はいつも、そのコマンドを含むファイルが
オープンされ、ファイルの内容がプロセスの仮想メモリにマップされる。その処理は、
そのプロセスのメモリマップを記述しているデータ構造体を修正することにより
行われるので、メモリマッピング(memory mapping)と呼ばれる。しかし、実際に物理
メモリに置かれるのはイメージの最初の部分だけであり、残りはディスクに保存され
たままとなる。
したがって、イメージが実行されるとページフォルトが起こり、Linux は、プロセスの
メモリマップを利用して、イメージのどの部分をメモリに持ってくれば実行が完遂でき
るのかを判断する。

<!--3.1.2  Swapping-->
<sect2>スワッピング<label id="chapter_mm_sect1-2">

<!--
If a process needs to bring a virtual page into physical memory and there are 
no free physical pages available, the operating system must make room for this
page by discarding another page from physical memory. 
-->
<p>あるプロセスが仮想ページを物理メモリに持ってこなければならないのだが、利用
可能な物理メモリの空きがない場合、オペレーティングシステムは、別のページを物
理メモリから取り除くことでそのページのための空間を確保しなければならない。

<!--
If the page to be discarded from physical memory came from an image or data
file and has not been written to then the page does not need to be saved. 
Instead it can be discarded and if the process needs that page again it can be
brought back into memory from the image or data file. 
-->
<p>物理メモリから取り除くべきページがイメージやデータファイルのコピーであり、
上書きされてはいない場合、そのページは保存する必要はない。破棄しておいて、プロ
セスが再度そのページを必要としたときに、該当するイメージやデータファイルから
メモリ内に戻せばそれでよい。

<!--
However, if the page has been modified, the operating system must preserve the
contents of that page so that it can be accessed at a later time. This type of
page is known as a dirty page and when it is removed from memory it is saved in
a special sort of file called the swap file. Accesses to the swap file are 
very long relative to the speed of the processor and physical memory and the 
operating system must juggle the need to write pages to disk with the need to 
retain them in memory to be used again. 
-->
<p>しかし、ページが変更されている場合には、オペレーティングシステムは、その
ページを維持して、後でそのページにアクセスできるようにしなければならない。
この種のページは、ダーティページ(dirty page)と呼ばれ、メモリから削除されると
きにスワップファイルと呼ばれる特別なファイルに保存される。スワップファイルへ
のアクセスには、プロセッサとメモリとの間のスピードと比べて非常に長い時間が掛
かるので、オペレーティングシステムは、ページをディスクに書き込む必要がある場合
でも、再使用に備えて出来るだけそれをメモリに保持する必要がある。

<!--
If the algorithm used to decide which pages to discard or swap (the swap
algorithm) is not efficient then a condition known as thrashing occurs. In this
case, pages are constantly being written to disk and then being read back and
the operating system is too busy to allow much real work to be performed. If, 
for example, physical page frame number 1 in Figure  3.1 is being regularly 
accessed then it is not a good candidate for swapping to hard disk. The set of
pages that a process is currently using is called the working set. An 
efficient swap scheme would make sure that all processes have their working 
set in physical memory. 
-->
<p>破棄やスワップするページを決めるために使用されるアルゴリズム(スワップ
アルゴリズム)の効率が悪い場合、スラッシング(thrashing)と呼ばれる状態に陥る。
その場合、ページは間断なくディスクに書き込まれたり読み出されたりするので、
オペレーティングシステムはそれに時間を取られて本来の仕事が出来なくなる。
たとえば、もし物理ページフレーム番号 1 (<ref id="figure3-1" name="図表(3.1)">)
が定期的にアクセスされるなら、
そのページはハードディスクにスワップされるべきではない。プロセスが現在使用し
ているページセットは、ワーキングセット(working set)と呼ばれる。効率の良い
スワップスキームとは、すべてのプロセスが自分のワーキングセットを物理メモリに
持つよう手配するスキームである。

<!--
Linux uses a Least Recently Used (LRU) page aging technique to fairly choose
pages which might be removed from the system. This scheme involves every
page in the system having an age which changes as the page is accessed. The
more that a page is accessed, the younger it is; the less that it is accessed 
the older and more stale it becomes. Old pages are good candidates for 
swapping. 
-->
<p>Linux は、最も使用頻度の少ない(最長時間未使用(Least Recently Used, LRU))
ページの寿命を縮める(エイジング(aging))というテクニックを使って、システム
から削除すべきページを公平に選択している。このスキームでは、システム内のすべ
てのページが寿命(age)を持っていて、それがページアクセスされると、変更される
仕組みになっている。
ページへのアクセスが多ければ、そのページの寿命は長くなる。アクセスが少な
ければ寿命が縮み、必要性が薄れる。寿命が尽きたページは、スワッピングの有力な
候補となる。

<!--3.1.3  Shared Virtual Memory-->
<sect2>共有仮想メモリ<label id="chapter_mm_sect1-3">

<!--
Virtual memory makes it easy for several processes to share memory. All
memory access are made via page tables and each process has its own separate
page table. For two processes sharing a physical page of memory, its physical
page frame number must appear in a page table entry in both of their page 
tables.
-->
<p>仮想メモリ機構は、複数のプロセスでのメモリの共有を実現しやすくする。メモリ
へのアクセスはすべてページテーブル経由で行われ、プロセスはそれぞれ自分の独立
したページテーブルを持っている。ふたつのプロセスがメモリ内の物理ページを共有す
るには、その物理ページのフレーム番号が、両者のページテーブル内のエントリに
存在する必要がある。

<!--
Figure  3.1 shows two processes that each share physical page frame number 4.
For process X this is virtual page frame number 4 whereas for process Y this is
virtual page frame number 6. This illustrates an interesting point about 
sharing pages: the shared physical page does not have to exist at the same 
place in virtual memory for any or all of the processes sharing it. 
-->
<p>図表 3.1 では、ふたつのプロセスが物理ページフレーム番号 4 を共有している
様子が示されている。プロセス X にとって、これは仮想ページフレーム番号 4 であ
り、プロセス Y にとって、これは仮想ページ番号 6 である。これはページ共有の
興味深い点を示している。共有された物理ページは、それを共有するプロセスにとって
仮想メモリの同じ位置に存在しなくてもよいということである。

<!--3.1.4  Physical and Virtual Addressing Modes-->
<sect2>物理アドレスモードと仮想アドレスモード<label id="chapter_mm_sect1-4">

<!--
It does not make much sense for the operating system itself to run in virtual
memory. This would be a nightmare situation where the operating system must
maintain page tables for itself. Most multi-purpose processors support the
notion of a physical address mode as well as a virtual address mode. Physical
addressing mode requires no page tables and the processor does not attempt to
perform any address translations in this mode. The Linux kernel is linked to 
run in physical address space. 
-->
<p>オペレーティングシステム自体が仮想メモリ内で実行されるというのはほとんど
ナンセンスである。オペレーティングシステムが自分のページテーブルを管理しなけ
ればならないとしたら、悪夢のような状況になるだろう。大部分の汎用プロセッサ
は、仮想アドレスモードと同時に物理アドレスモードという概念をサポートしてい
る。物理アドレスモードでは、ページテーブルは不要であり、プロセッサはこのモー
ドのときはアドレス変換をしようとしない。Linux カーネルは、この物理アドレス
モードで実行されるようにリンクされている。

<!--
The Alpha AXP processor does not have a special physical addressing mode.
Instead, it divides up the memory space into several areas and designates two 
of them as physically mapped addresses. This kernel address space is known as
KSEG address space and it encompasses all addresses upwards from
0xfffffc0000000000. In order to execute from code linked in KSEG (by 
definition, kernel code) or access data there, the code must be executing in 
kernel mode. The Linux kernel on Alpha is linked to execute from address 
0xfffffc0000310000.
-->
<p>Alpha AXP プロセッサは、特に物理アドレスモードというのは持っていない。
そのかわり、メモリ空間をいくつかのエリアに分割していて、そのうちのふたつを
物理的にマッピングされたアドレス空間として使用する。このカーネルアドレス空間
は、KSEG アドレス空間と呼ばれていて、0xfffffx0000000000 以上のすべてのアドレス
を包含している。KSEG 領域にリンクされているコード(カーネルコードと定義される
コード)を実行したり、その領域のデータにアクセスしたりするためには、そのコード
はカーネルモードで実行される必要がある。Alpha 上の Linux カーネルは、
アドレス 0xfffffc0000310000 から実行されるようにリンクされている。

<!--3.1.5  Access Control-->
<sect2>アクセス制御<label id="chapter_mm_sect1-5">

<!--
The page table entries also contain access control information. As the 
processor is already using the page table entry to map a processes virtual 
address to a physical one, it can easily use the access control information to
check that the process is not accessing memory in a way that it should not. 
-->
<p>ページテーブルのエントリには、アクセス制御情報も含まれている。プロセッサは、
プロセスの仮想アドレスを物理アドレスにマップするためにいつもページテーブルを
使用するので、そこに含まれたアクセス制御情報を利用して、プロセスが許されていな
い方法でメモリにアクセスしていないかどうかを簡単にチェックできる。

<!--
There are many reasons why you would want to restrict access to areas of
memory. Some memory, such as that containing executable code, is naturally
read only memory; the operating system should not allow a process to write data
over its executable code. By contrast, pages containing data can be written to
but attempts to execute that memory as instructions should fail. Most
processors have at least two modes of execution: kernel and user. You would
not want kernel code executing by a user or kernel data structures to be
accessible except when the processor is running in kernel mode. 
-->
<p>メモリの特定のエリアへのアクセスを制限すべき理由は数多くある。実行コードを
含むようなメモリは、通常読み出し専用である。オペレーティングシステムは、プロ
セスがそのような実行コードの位置にデータを上書きするのを許すべきではない。
反対に、データを含むページは上書きされてもよいわけであり、そのメモリの内容を
実行しようとする命令があった場合、失敗させなければならない。
大部分のプロセッサには、実行に関してカーネルモードとユーザモードという少なく
ともふたつのモードがある。カーネルコードをユーザが勝手に実行できないようにする
ためであり、プロセッサがカーネルモードで動いているとき以外は、カーネルのデータ
構造へのアクセスを許さないようにするためである。

<label id="figure3-2">
<!--               Figure 3.2: Alpha AXP Page Table Entry-->
<#if output="html">
<figure><ph vspace="0"><img src="./The-Linux-Kernel-images/figure3-2.gif">
</figure>
</#if>
<#unless output="html">
<verb>
                                   15 13 11
31                                   14 12 10 9 8 7 6 5 4 3 2 1 0
+----------------------------------------------------------------+
|                 | | | |          |  | | |   | | | |  | | | | | |
|                 | | | |          |  |U|K|   |U|K| | G|A|F|F|F|V|
|                 | | | |          |  |W|W|   |R|R| | H|S|O|O|O| |
|                 | | | |          |  |E|E|   |E|E| |  |M|E|W|R| |
|                 | | | |          |  | | |   | | | |  | | | | | |
+----------------------------------------------------------------+
                   ^   ^
                   |   +------- _PAGE_DIRTY
                   |
                   +----------- _PAGE_ACCESSED
63                                                               32
+----------------------------------------------------------------+
|                                                                |
|                                                                |
|                              P F N                             |
|                                                                |
|                                                                |
+----------------------------------------------------------------+
</verb>
</#if>
<p>図表(3.2) Alpha AXP のページテーブルエントリ(PTE)


<!--
The access control information is held in the PTE and is processor specific;
figure  3.2 shows the PTE for Alpha AXP. The bit fields have the following
meanings: 
-->
<p>アクセス制御情報は、PTE に保持されており、それはプロセッサに固有のものであ
る。図表(3.2)は、Alpha AXP の PTE を表している。そのビットフィールドは、次の
ような意味を持つ。

<!--
V     Valid, if set this PTE is valid, 
FOE  ``Fault on Execute'', Whenever an attempt to execute instructions in
      this page occurs, the processor reports a page fault and passes control
      to the operating system, 
FOW ``Fault on Write'', as above but page fault on an attempt to write to this
      page, 
FOR ``Fault on Read'', as above but page fault on an attempt to read from
      this page, 
ASM   Address Space Match. This is used when the operating system wishes
      to clear only some of the entries from the Translation Buffer, 
KRE   Code running in kernel mode can read this page, 
URE   Code running in user mode can read this page, 
GH    Granularity hint used when mapping an entire block with a single
      Translation Buffer entry rather than many, 
KWE   Code running in kernel mode can write to this page, 
UWE   Code running in user mode can write to this page, 
page frame number
      For PTEs with the V bit set, this field contains the physical Page Frame
      Number (page frame number) for this PTE. For invalid PTEs, if this field
      is not zero, it contains information about where the page is in the swap
      file. 
-->
<label id="chapter_mm_pfn">
<verb>
V     「有効(Valid)」。これが設定されると、PTE が有効となる。
FOE   「実行フォールト(Fault On Execute)」。このページ内で命令が実行されようとし
      た際は、プロセッサがページフォルトを報告し、制御をオペレーティングシステム
      に渡す。
FOW   「書き込みフォールト(Fault on Write)」。上記と同様だが、このページへ書き込
      もうとした場合のページフォルトである。
FOR   「読み込みフォールト(Fault On Read)」。上記と同様だが、このページの読み込も
      うとした場合のページフォルトである。
ASM   「アドレス空間合致(Address Space Match)」。これが使用されるのは、オペレー
       ティングシステムが変換テープルから数個のエントリだけを削除したいときである。
KRE    カーネルモードで実行されているコードは、このページを読むことができる。
URE    ユーザモードで実行されているコードは、このページを読むことができる。
GH     Granularity hint(粒度ヒント). ひとつのブロック全体を分割せずに単一の変換
       バッファにマッピングするときに利用される。
KWE    カーネルモードで実行されているコードはこのページに書き込み可能。
UWE    ユーザモードで実行されているコードは、このページに書き込み可能。
PFN(page frame number)
       V ビットが設定された PTE では、このフィールドには、当該 PTE への物理フレー
       ム番号(ページフレーム番号)が書かれている。V ビットが設定されていおらず、こ
       のフィールドがゼロでない場合、スワップファイル内でのページの場所に関する情
       報が書かれている。
</verb>
<!--
The following two bits are defined and used by Linux: 
-->
<p>次のふたつのビットは、Linux で定義され、使用されているものである。

<!--
_PAGE_DIRTY
      if set, the page needs to be written out to the swap file, 
_PAGE_ACCESSED
      Used by Linux to mark a page as having been accessed. 
-->
<verb>
_PAGE_DIRTY
      これが設定された場合、このページはスワップに書き出される必要がある。
_PAGE_ACCESSED
      ページがアクセスされたことを記すために使用される。
</verb>

<!--3.2  Caches-->
<sect1>キャッシュ<label id="chapter_mm_sect2">

<!--
If you were to implement a system using the above theoretical model then it
would work, but not particularly efficiently. Both operating system and 
processor designers try hard to extract more performance from the system. 
Apart from making the processors, memory and so on faster the best approach is
to maintain caches of useful information and data that make some operations
faster. Linux uses a number of memory management related caches: 
-->
<p>上記の理論モデルを使ってシステムを実装した場合、確かに機能はするであろうが、
それほど効率のよいものにはならない。オペレーティングシステムとプロセッサの
設計者はどちらもシステムからよりよいパフォーマンスを引き出そうと懸命に努力
しているからである。より速いプロセッサやメモリを製造するといったことを別に
すると、処理速度を上げる最良の方法は、頻繁に使用する情報やデータのキャッシュ
を維持管理することである。Linux では、キャッシュに関するいくつかのメモリ管理
機構が利用されている。

<descrip>
<!--Buffer Cache-->
<tag>バッファキャッシュ</tag>
<!--
      The buffer cache contains data buffers that are used by the block device
      drivers. 
      These buffers are of fixed sizes (for example 512 bytes) and contain
      blocks of information that have either been read from a block device or
      are being written to it. A block device is one that can only be accessed
      by reading and writing fixed sized blocks of data. All hard disks are
      block devices. 
-->
<p>バッファキャッシュ(buffer cache)には、ブロックデバイスドライバが使用する
データバッファが含まれている。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/fs/buffer.c" 
name="fs/buffer.c">]<newline>
これらのバッファは固定サイズ(たとえば、512 バイト)で、ブロックデバイスから
読み出されたか、そこに書き込まれた情報のブロックが入っている。ブ
ロックデバイスとは、データアクセスの際に、固定サイズのブロック単位でのみ読み
書きできるデバイスを指す。すべてのハードディスクはブロックデバイスである。

<!--
      The buffer cache is indexed via the device identifier and the desired
      block number and is used to quickly find a block of data. Block devices
      are only ever accessed via the buffer cache. If data can be found in the
      buffer cache then it does not need to be read from the physical block
      device, for example a hard disk, and access to it is much faster. 
-->
<p>バッファキャッシュは、デバイス識別子と必要なブロック番号とでインデックス付け
されていて、データブロックをすばやく見つけだすために使用されるものである。
ブロックデバイスは、バッファキャッシュを経由しなければアクセスできない。
データがバッファキャッシュに見つかれば、たとえばハードディスクのような物理
ブロックデバイスから読み出す必要がなくなるので、アクセスがずっと高速になる。

<!--Page Cache-->
<tag>ページキャッシュ</tag>

<!--
      This is used to speed up access to images and data on disk. 
      It is used to cache the logical contents of a file a page at a time and 
      is accessed via the file and offset within the file. As pages are read 
      into memory from disk, they are cached in the page cache. 
-->
<p>ページキャッシュ(page cache)は、ディスク上のイメージやデータへのアクセスを
高速化するために使用される。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/mm/filemap.c" 
name="mm/filemap.c">]<newline>
これは、ページ単位でファイルの論理的な内容をキャッシュし、ファイル名と
そのファイル内のオフセットを使ってアクセスされる。ページがディスクからメモリ
に読み出されると、それらはページキャッシュにキャッシュされる。

<!--Swap Cache-->
<tag>スワップキャッシュ</tag>

<!--
Only modified (or dirty) pages are saved in the swap file. 
So long as these pages are not modified after they have been written to
the swap file then the next time the page is swapped out there is no need
to write it to the swap file as the page is already in the swap file. 
Instead the page can simply be discarded. In a heavily swapping system 
this saves many unnecessary and costly disk operations. 
-->
<p>変更された(あるいは、dirty な)ページだけが、スワップファイルに保存される。
<newline>[see: swap.h, <htmlurl 
url="./The-Linux-Kernel-images/linux/mm/swap_state.c" 
name="mm/swap_state.c">, <htmlurl 
url="./The-Linux-Kernel-images/linux/mm/swapfile.c" 
name="mm/swapfile.c">]<newline>
当該ページがスワップファイルに書き込まれてから変更されていない場合は、再度
スワップアウトされたとしても、同じページがすでにスワップファイル内にあるわけ
だから、スワップファイルに書き込む必要はない。そのページは単に破棄される。
システムがスワップを頻繁に使用する場合、これによって時間の掛かる不必要な
ディスク操作を大幅に省略できる。

<!--Hardware Caches-->
<tag>ハードウェアキャッシュ</tag>

<!--
      One commonly implemented hardware cache is in the processor; a cache
      of Page Table Entries. In this case, the processor does not always read
      the page table directly but instead caches translations for pages as it
      needs them. These are the Translation Look-aside Buffers and contain
      cached copies of the page table entries from one or more processes in
      the system. 
-->
<p>ハードウェアキャッシュ(hardware cache)の実装として一般的なのが、プロセッサ
内のハードウェアキャッシュである、ページテーブルエントリのキャッシュである。
この場合、プロセッサはいつも直接ページテーブルを読み出すのではなく、変換が
必要であったときにそのページ変換をキャッシュしておく。プロセッサ内には、
アドレス変換バッファ(Translation Look-aside Buffer, TLB)があり、そこには、
システム上の複数のプロセスに関するページテーブルエントリのコピーがキャッシュ
されている。

<!--
      When the reference to the virtual address is made, the processor will
      attempt to find a matching TLB entry. If it finds one, it can directly
      translate the virtual address into a physical one and perform the correct
      operation on the data. If the processor cannot find a matching TLB entry
      then it must get the operating system to help. It does this by signalling
      the operating system that a TLB miss has occurred. A system specific
      mechanism is used to deliver that exception to the operating system
      code that can fix things up. The operating system generates a new TLB
      entry for the address mapping. When the exception has been cleared, the
      processor will make another attempt to translate the virtual address.
      This time it will work because there is now a valid entry in the TLB for
      that address. 
-->
<p>仮想アドレスへの参照が行われるとき、プロセッサは合致する TLB エントリを
探そうとする。それが見つかれば、仮想アドレスを直接物理アドレスに変換して、
データに対して適切な処理を実行する。プロセッサが合致する TLB エントリを見つけ
出せない場合は、オペレーティングシステムに助けを求める。すなわち、プロセッサ
は、オペレーティングシステムに対して、TLB 失敗(TLB miss)が起こったことをシグ
ナルで伝える。システム固有のメカニズムを使用して、その例外(exception)をオペ
レーティングシステムの例外処理コードに渡す。オペレーティングシステムは、その
シグナルを受けて、アドレスマッピングのための新しい TLB エントリを生成する。
例外がクリアされると、プロセッサは再度仮想アドレスの変換を試みる。今回は、
TLB 内に必要なアドレスに関する有効なエントリがあるので、問題なく変換される。 

</descrip>

<!--
The drawback of using caches, hardware or otherwise, is that in order to save
effort Linux must use more time and space maintaining these caches and, if the
caches become corrupted, the system will crash. 
-->
<p>ハードウェアキャッシュやその他のキャッシュを使う場合の欠点は、手順を簡略化
するために、これまで以上の時間とメモリ空間を使ってそうしたキャッシュを維持し
なければならないということであり、もしキャッシュが壊れると、システムがクラッ
シュするということである。

<!--3.3  Linux Page Tables-->
<sect1>Linux のページテーブル<label id="chapter_mm_sect3">
<p>

<!--                 Figure 3.3: Three Level Page Tables-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure3-3.gif">
</figure>
</#if>
<#unless output="html">
<verb>
                         仮想アドレス
+-------+--------------+-------------+-----------+----------------+
|       |              |             |           |                |
|       |   Level 1    |  Level 2    |  Level 3  |Byte within page|
|       |      |       |     |       |     |     |         |      |
+-------+------+-------+-----+-------+-----+-----+---------+------+
               |             |             |               |
               |             |             |               |
    Level 1    |  Level 2    |  Level 3    |               |
    Page Table |  Page Table |  Page Table | Physical Page |
    +-------+  |  +-------+  |  +-------+  |  +---------+  |
    |       |  |  |       |  |  |       |  |  |         |  |
    |       |  |  |       |  |  |       |  |  |         |  |
    |---+---|  |  |---+---|  |  |---+---+  |  |---------|  |
    |PFN|   |<-+  |PFN|   |<-+  |PFN|   |<-+  |         |<-+
    |-+-+---|     |-+-+---|     |-+-+---|     |---------|
    | |     |     |  |    |     | |     |     |         |
PGD | |     |     |  |    |     | |     |     |         |
--->+-+-----+  +->+--+----+  +->+-+-----+  +->+---------+
      |        |     |       |    |        |
      +--------+     +-------+    +--------+
</verb>
</#if>
<p>図表(3.3) 3 つのレベルのページテーブル


<!--
Linux assumes that there are three levels of page tables. Each Page Table
accessed contains the page frame number of the next level of Page Table. Figure
  3.3 shows how a virtual address can be broken into a number of fields; each
field providing an offset into a particular Page Table. To translate a virtual
address into a physical one, the processor must take the contents of each level
field, convert it into an offset into the physical page containing the Page 
Table and read the page frame number of the next level of Page Table. This is 
repeated three times until the page frame number of the physical page 
containing the virtual address is found. Now the final field in the virtual 
address, the byte offset, is used to find the data inside the page. 
-->
<p>Linux では、3 つのレベルのページテーブルの存在が前提になっている。アクセス
される個々のページテーブルには、次の段階のページテーブルにおけるページ
フレーム番号が含まれている。図表(3.3)では、仮想アドレスがいくつかのフィールド
に分割されている様子が示されている。図中の仮想アドレスの個々のフィールドが
提供するのは、特定のページテーブルへのオフセットである。プロセッサは、
仮想アドレスを物理アドレスに変換するため、まず個々のレベルのフィールドの
内容を取得して、その内容を当該レベルのページテーブルを含む物理ページ上での
オフセットへと変換し、それによって次のレベルのページテーブルのページフレーム
番号を読み取る。この処理を三度繰り返すと、その仮想アドレスを含んだ物理ページ
のページフレーム番号が分かる。仮想アドレスの最後のフィールドは、バイト
オフセット(byte offset)となっていて、それを使用して当該物理ページ内で必要な
データを見つけ出す。

<!--
Each platform that Linux runs on must provide translation macros that allow the
kernel to traverse the page tables for a particular process. This way, the 
kernel does not need to know the format of the page table entries or how they 
are arranged. 
This is so successful that Linux uses the same page table manipulation code for
the Alpha processor, which has three levels of page tables, and for Intel x86
processors, which have two levels of page tables. 
-->
<p>Linux を実行するプラットフォームが提供しなければならないのが、変換マクロ
である。これは、カーネルが特定のプロセスのためにページテーブルを走査すること
を可能にするものである。そうすることで、カーネルはページテーブルエントリの
フォーマットや、その仕組みを知る必要がなくなる。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/asm-i386/pgtable.h" 
name="include/asm/pgtable.h">]<newline>
この方法は非常に成功しているので、Linux は、ページテーブル操作のコードとして
 Alpha プロセッサにも Intel x86 プロセッサにも同じものを使用している。ただ、
Alpha プロセッサは、3 つのレベルのページテーブルを持つが、Intel x86 は、
2 つのレベルのページテーブルを持つという違いがある。

<!--3.4  Page Allocation and Deallocation-->
<sect1>ページの割り当てとページの解放<label id="chapter_mm_sect4">

<!--
There are many demands on the physical pages in the system. For example,
when an image is loaded into memory the operating system needs to allocate
pages. These will be freed when the image has finished executing and is
unloaded. Another use for physical pages is to hold kernel specific data
structures such as the page tables themselves. The mechanisms and data
structures used for page allocation and deallocation are perhaps the most 
critical in maintaining the efficiency of the virtual memory subsystem. 
-->
<p>システム内の物理メモリに対する需要は大きい。たとえば、イメージがメモリに
ロードされるとき、オペレーティングシステムは、それに物理ページを割り当てる。
イメージが実行を終了し取り除かれたら、そのページは解放される。物理メモリは他
にも、ページテーブル自体のようなカーネル固有のデータ構造を保持する用途に使用
される。ページ割り当てと解放に使用されるメカニズムとデータ構造は、仮想メモリ
サブシステムの効率を維持する上でおそらく最も重要なものである。

<!--
All of the physical pages in the system are described by the mem_map data
structure which is a list of mem_map_t (footnote 1) structures which is 
initialized at boot time. Each mem_map_t describes a single physical page in 
the system. Important fields (so far as memory management is concerned) are: 
-->
<p>システム内のすべての物理ページは <tt><ref id="mem_map_t" 
name="mem_map"></tt> というデータ構造に
よって記述されている。それは、<tt><ref id="mem_map_t" name="mem_map_t"></tt> 
構造体(<ref id="chapter_mm_fn1" name="脚注 1 ">)の
リストであり、それらは起動時に初期化される。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/mm.h" 
name="include/linux/mm.h">]<newline>
個々の <tt>mem_map_t</tt> は、システム内の単一の物理ページを記述する。(メモリ
管理に関する限り)その構造体の重要なフィールドには、次のようなものがある。

<!--
count This is a count of the number of users of this page. The count is greater
      than one when the page is shared between many processes, 
age This field describes the age of the page and is used to decide if the page
      is a good candidate for discarding or swapping, 
map_nr This is the physical page frame number that this mem_map_t describes.
-->
<verb>
count   これは、そのページのユーザ数のカウンターである。ページが複数のプロセ
        スで共有されている時、このカウントは 1 より多くなる。
age     このフィールドは、ページの 寿命(age)を記述するもので、そのページが破棄
        やスワップの候補であるかを判断するのに使われる。
map_nr  これは、mem_map_t が記述する物理ページのフレーム番号である。
</verb>

<!--
The free_area vector is used by the page allocation code to find and free
pages. The whole buffer management scheme is supported by this mechanism
and so far as the code is concerned, the size of the page and physical paging
mechanisms used by the processor are irrelevant. 
-->
<p><tt><ref id="free_area" name="free_area"></tt> という配列も、ページ割り当
てのコードにより、ページの検索と解放のために使用される。すべてのバッファ管理
スキームはこのメカニズムによってサポートされており、そのコードに関する限り、
プロセッサの物理ページングメカニズムとページサイズとの間には、関連性がない。

<!--
Each element of free_area contains information about blocks of pages. The
first element in the array describes single pages, the next blocks of 2 pages,
the next blocks of 4 pages and so on upwards in powers of two. The list element
is used as a queue head and has pointers to the page data structures in the
mem_map array. Free blocks of pages are queued here. map is a pointer to a
bitmap which keeps track of allocated groups of pages of this size. Bit N of 
the bitmap is set if the Nth block of pages is free. 
-->
<p><tt><ref id="free_area" name="free_area"></tt> の個々の要素は、ブロック単位
のページに関する情報を含んでいる。
すなわち、配列の最初の要素はひとつのページ、次が 2 つのページから成るブロック、
さらに次が 4 つのページから成るブロックというふうに 2 の n 乗でブロックのページ
数が増える。
構造体の要素 <tt><ref id="free_area" name="list"></tt> はキューの先頭として
使用され、<tt><ref id="mem_map_t" name="mem_map"></tt> 配列内の <tt><ref 
id="mem_map_t" name="page"></tt> データ構造体へのポインタとなっている。
(訳注: <tt>list</tt> は、v2.0.12 以降は、<tt>next</tt> と <tt>prev</tt> による
二重連結リストになっています。)
空のページブロックはこのキューに並べられる。<tt><ref id="free_area" 
name="map"></tt> は個々のサイズのページグループの割り当て状態を管理してい
るビットマップ(bitmap)に対するポインタである。bitmap の N ビット目は、ページの 
N 番目のブロックが空である場合にセットされる。

<!--
Figure  free-area-figure shows the free_area structure. Element 0 has one
free page (page frame number 0) and element 2 has 2 free blocks of 4 pages, the
first starting at page frame number 4 and the second at page frame number 56. 
-->
<p><ref id="figure3-4" name="図表(3.4)">では、<tt>free_area</tt> 構造体が示
されている。
要素 0 はひとつの空ページ(ページフレーム番号 0 )を持っており、要素 2 は 4 
つのページから成る 2 つの空ブロックを持っている。最初の空ブロックは、ページ
フレーム番号 4 から始まり、次の空ブロックはページフレーム番号 56 から始まって
いる。

<!--3.4.1  Page Allocation-->
<sect2>ページの割り当て<label id="chapter_mm_sect4-1">
<p>
<!--
Linux uses the Buddy algorithm (footnote 2) to effectively allocate and 
deallocate blocks of pages. The page allocation code attempts to allocate a 
block of one or more physical pages. Pages are allocated
in blocks which are powers of 2 in size. That means that it can allocate a 
block 1 page, 2 pages, 4 pages and so on. So long as there are enough free 
pages in the system to grant this request (nr_free_pages > min_free_pages) the
allocation code will search the free_area for a block of pages of the size 
requested. Each element of the free_area has a map of the allocated and free 
blocks of pages for that sized block. For example, element 2 of the array has 
a memory map that describes free and allocated blocks each of 4 pages long. 
-->
<p>Linux は、相棒アルゴリズム
(<ref id="buddy_algorithm" name="Buddy algorithm">)
<ref id="chapter_mm_fn1" name="(脚注 2)"> 
を使用することで、ページブロックを効率的に割り当てたり解放したりしている。
<newline>[see: __get_free_page(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/mm/page_alloc.c" 
name="mm/linux/page_alloc.c">]<newline>
ページ割り当てのコードは、ひとつもしくは複数のページから成るブロックを割り当
てようとする。ページの割り当ては、大きさとして 2 の n 乗のブロック単位となって
いる。すなわち、ひとつのブロックに 1 つのページ、2 つのページ、4 つのページ等が
割り当てられる。システム内に要求(nr_free_pages &gt; 
min_free_pages)に応えられるだけの空き空間があれば、割り当て
コードは、要求されたサイズのページ数でブロックを作成するために <tt>
<ref id="free_area" name="free_area"></tt> を調べる。
<tt>free_area</tt> のそれぞれの要素は、該当するサイズのブロックに関するマップ
を持っていて、割り当て済みもしくは空いているページブロックが参照できるように
なっている。たとえば、配列の要素 2 が持つメモリマップでは、4 つのページから成る
それぞれのブロックのどれが割り当て済みであり、どれが空なのかが記録されている。

<!--
The allocation algorithm first searches for blocks of pages of the size 
requested. It follows the chain of free pages that is queued on the list 
element of the free_area data structure. If no blocks of pages of the 
requested size are free, blocks of the next size (which is twice that of the 
size requested) are looked for. This process continues until all of the 
free_area has been searched or until a block of pages has been found. If the 
block of pages found is larger than that requested it must be broken down 
until there is a block of the right size. Because the blocks are each a power 
of 2 pages big then this breaking down process is easy as you simply break the
blocks in half. The free blocks are queued on the appropriate queue and the 
allocated block of pages is returned to the caller. 
-->
<p>割り当てアルゴリズムは、まず要求されたサイズのページブロックを探す。それは、
<tt><ref id="free_area" name="free_area"></tt> データ構造体のキューにある、
<tt><ref id="free_area" name="list"></tt> 要素上から、空のページの連続を調
べる。もし要求されたサイズのページブロックでは空きがない場合、
次のサイズ(これは要求されたサイズの 2 倍である)のブロックがないか調査する。
この過程は、<tt>free_area</tt> のすべてが調べられるか、ページブロックが見つかる
かするまで続けられる。見つかったページブロックが当初の要求よりも大きい場合、
適切なサイズになるまで分割される。ブロックは 2 の n 乗のページから成り立つの
で、この分割プロセスは半分に割るだけの簡単なものである。空ブロックは適当な
キュー上に並べられ、割り当てられるページブロックが、呼び出しをしたプロセスに
返される。

<label id="figure3-4">
<!--              Figure 3.4: The free_area data structure-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure3-4.gif">
</figure>
</#if>
<#unless output="html">
<verb>

                      free_area                 物理メモリ
                       +-----+                 +-----------+
                       |     |                 |           |
                       |  5  |                 |           |
                       |-----|                 |-----------|
                       |     |                 |           |8
                       |  4  |      map        |           | 
                       |-----|    +------+     |-----------|
                       |     |--->+------+     | / / / /   |7
mem_map_t  mem_map_t   |  3  |      map        |  / / / /  |
 +----+     +----+     |-----|    +------+     |-----------|
 |    |<----|    |<----|     |--->|      |     | / / / /   |6
 |    |---->|    |---->|  2  |    +------+     |  / / / /  |
 | 56 |     |  4 |     |-----|      map        |-----------|
 +----+     +----+     |     |--->+------+     | / / / /   |5
           mem_map_t   |  1  |    |      |     |  / / / /  |
            +----+     |-----|    |      |     |-----------|
            |    |<----|     |    +------+     | / / / /   |4
            |    |---->|  0  |-+    map        |  / / / /  |
            |  0 |     +-----+ |  +------+     |-----------|
            +----+             +->|      |     |           |3
                                  |      |     |           |
                                  |      |     |-----------|
                                  |      |     |           |2
                                  |      |     |           |
                                  +------+     |-----------|   *
                                               |           |1 /| 
                                               |           |   |
                                               |-----------|   |
                            / / / /            | / / / /   |0 PFN
                             / / / / Free PFN  |  / / / /  |
                                               +-----------+
</verb>
</#if>
<p>図表(3.4) free_area のデータ構造

<!--
For example, in Figure  3.4 if a block of 2 pages was requested, the first 
block of 4 pages (starting at page frame number 4) would be broken into two 2 
page blocks. The first, starting at page frame number 4 would be returned to 
the caller as the allocated pages and the second block, starting at page frame
number 6 would be queued as a free block of 2 pages onto element 1 of the 
free_area array. 
-->
<p>たとえば、図表(3.4)では、2 つのページから成るブロックが要求された場合、
(ページフレーム番号 4 から始まっている) 4 つのページから成る最初のブロック
が、2 つのページから成るふたつのブロックに分割される。ページフレーム番号 4 
から始まる最初のブロックは、割り当てられたページとして呼び出したプロセスに
戻され、ページフレーム番号 6 から始まる二番目のブロックは、<tt><ref 
id="free_area" name="free_area"></tt> 配列の要素 1 上にある 2 つのページから
成る空ブロックとしてキュー上に置かれる。

<!--3.4.2  Page Deallocation-->
<sect2>ページの解放<label id="chapter_mm_sect4-2">
<p>
<!--
Allocating blocks of pages tends to fragment memory with larger blocks of free
pages being broken down into smaller ones. The page deallocation code 
recombines pages into larger blocks of free pages whenever it can. In fact the
page block size is important as it allows for easy combination of blocks into
larger blocks. 
-->
<p>ページブロックの割り付けは、大きな空ページを小さく分割するので、
断片化したメモリ(framgment memory)を生じやすい。
<newline>[see: free_pages(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/mm/page_alloc.c" 
name="mm/page_alloc.c">]<newline>
ページを解放するコード(page deallocation code)は、
可能なときはいつでも、空のページをより大きなブロックに連結する。実際、
ブロックをまとめてより大きなブロックを簡単に作れることを考えると、
この(2 の n 乗という)ページブロックサイズには重要な意味がある。

<!--
Whenever a block of pages is freed, the adjacent or buddy block of the same
size is checked to see if it is free. If it is, then it is combined with the 
newly freed block of pages to form a new free block of pages for the next size
block of pages. Each time two blocks of pages are recombined into a bigger 
block of free pages the page deallocation code attempts to recombine that 
block into a yet larger one. In this way the blocks of free pages are as large
as memory usage will allow. 
-->
<p>ページブロックが解放されると、同じサイズの近接ブロックもしくは相棒(buddy)
ブロックが空かどうかチェックされる。もしそうなら、新しく解放されたページ
ブロックと結合して、一段階大きいサイズの新しい空ブロックを作成する。ふたつの
ページブロックが結合されてより大きな空のページブロックが形成されるたびに、
ページ解放コードは、そのブロックをさらに大きなものにしようとする。このように
して、空のページブロックは、メモリの使用方法として許される限り大きなブロックに
なっていく。

<!--
For example, in Figure  3.4, if page frame number 1 were to be freed, then that
would be combined with the already free page frame number 0 and queued onto
element 1 of the free_area as a free block of size 2 pages. 
-->
<p>たとえば、<ref id="figure3-4" name="図表(3.4)">では、ページフレーム番号 1 が
解放されると、すでに解放されていたページフレーム番号 0 と結合される。そして、
2 つのページから成る空ブロックとして <tt><ref id="free_area" name="free_area">
</tt> の要素 1 上のキューに置かれる。


<!--3.5  Memory Mapping-->
<sect1>メモリマッピング<label id="chapter_mm_sect5">

<!--
When an image is executed, the contents of the executable image must be
brought into the processes virtual address space. The same is also true of any
shared libraries that the executable image has been linked to use. The
executable file is not actually brought into physical memory, instead it is 
merely linked into the processes virtual memory. Then, as the parts of the 
program are referenced by the running application, the image is brought into 
memory from the executable image. This linking of an image into a processes 
virtual address space is known as memory mapping. 
-->
<p>イメージが実行されるとき、その実行イメージの内容は、プロセスの仮想アドレス
空間に置かれなければならない。このことは、実行イメージで使用するためにリンク
された共有ライブラリの場合でも同じである。実行ファイルは実際に物理
メモリに置かれるわけではなく、プロセスの仮想メモリにリンクされるだけである。
そして、実行中のアプリケーションからそのプログラムの一部が参照されると、実行
イメージ内のその部分のイメージがメモリの中に置かれる。あるイメージを、プロセ
スの仮想アドレス空間にリンクさせるこの仕組みは、メモリマッピング
(memory mapping)と呼ばれる。

<label id="figure3-5">
<!--                Figure 3.5: Areas of Virtual Memory-->
<#if output="html">
<figure><ph vspace="100"><img src="./The-Linux-Kernel-images/figure3-5.gif">
</figure>
</#if>
<#unless output="html">
<verb>
                                              +--------------+
                                              |              |
                                              |              |
                                              |              |
                                      +------>|--------------|
                                      |       |              |
                                      |       |              |
                                      |       |              |
                                      |       | Virtual Area |
vm_area_struct                        |       |              |
+------------+                        |       |              |
|  vm_end    |------------------------+       |              |
|------------|                                |              |
|  vm_start  |------------------------------->|--------------|
|------------|                                |              |
|  vm_flags  |                                |              |
|----------  |                                |              |
|  vm_inode  |                                |              |
|------------|            仮想メモリ          |              |
|  vm_ops    |----------> 操作ルーチン        |              |
|------------|                                |              |
|            |              open()            |              |
|            |              close()           |              |
|------------|              unmap()           |              |
|  vm_next   |              protect()         |              |
+------------+              advise()          |              |
                            nopage()          |              |
                            wppage()          |              |
                            swapout()         |              |
                            swapin()          |              |
                                              +--------------+
</verb>
</#if>
<p>図表3.5 仮想メモリのエリア


<!--
Every processes virtual memory is represented by an mm_struct data
structure. This contains information about the image that it is currently
executing (for example bash) and also has pointers to a number of
vm_area_struct data structures. Each vm_area_struct data structure
describes the start and end of the area of virtual memory, the processes access
rights to that memory and a set of operations for that memory. These operations
are a set of routines that Linux must use when manipulating this area of 
virtual memory. For example, one of the virtual memory operations performs the
correct actions when the process has attempted to access this virtual memory 
but finds (via a page fault) that the memory is not actually in physical 
memory. This operation is the nopage operation. The nopage operation is used 
when Linux demand pages the pages of an executable image into memory. 
-->
<p>すべてのプロセス仮想メモリは、<tt><ref id="mm_struct" name="mm_struct">
</tt>データ構造体で表現される。これには、現在実行中のイメージ(たとえば、
<tt>bash</tt>)に関する情報が含まれると同時に、
いくつかの <tt><ref id="vm_area_struct" name="vm_area_struct"></tt> データ
構造体へのポインタも含まれる。
<tt>vm_area_struct</tt> データ構造体には、その仮想メモリ領域の始点と終点、
そのメモリへのプロセスのアクセス権、およびそのメモリに対する一連の操作ルーチン
が含まれている。これらの操作ルーチンは、Linux がこの仮想メモリの領域を操作する
際に使わなければならない一連のルーチンである。たとえば、仮想メモリ操作のひと
つに訂正処理があり、それはプロセスが仮想メモリにアクセスしようとしたが、
(ページフォルトによって)その仮想メモリが実際には物理メモリ上にないことが分
かった時になされる。この操作は、<tt><ref id="vm_operations_struct" 
name="nopage"></tt> 操作である。
<tt>nopage</tt> 操作が利用されるのは、Linux のデマンドページングにより実行
イメージのページが物理メモリ内にページを割り当てられるときである。

<!--
When an executable image is mapped into a processes virtual address a set of
vm_area_struct data structures is generated. Each vm_area_struct data
structure represents a part of the executable image; the executable code,
initialized data (variables), unitialized data and so on. Linux supports a 
number of standard virtual memory operations and as the vm_area_struct data
structures are created, the correct set of virtual memory operations are
associated with them. 
-->
<p>実行イメージがプロセス仮想アドレスにマップされるとき、<tt><ref 
id="vm_area_struct" name="vm_area_struct"></tt> データ構造が一組生成される。
<tt>vm_area_struct</tt> データ構造体はそれぞれ実行イメージの一部を表している。
実行コード、初期化されたデータ(変数)、初期化されないデータ等につき、ひとつづつ
の構造体が生成される。Linux はいつくかの標準的な仮想メモリ操作をサポートしてい
るので、<tt>vm_area_struct</tt> データ構造体が生成されると、仮想メモリ操作の
適切なセットがそれらと結びつけられる。

<!--3.6  Demand Paging-->
<sect1>デマンドページング<label id="chapter_mm_sect6">

<!--
Once an executable image has been memory mapped into a processes virtual
memory it can start to execute. As only the very start of the image is 
physically pulled into memory it will soon access an area of virtual memory 
that is not yet in physical memory. When a process accesses a virtual address 
that does not have a valid page table entry, the processor will report a page 
fault to Linux. The page fault describes the virtual address where the page 
fault occurred and the type of memory access that caused. 
-->
<p>実行イメージがいったんメモリにマップされてプロセス仮想メモリに入ると、
イメージの実行開始が可能となる。しかし、そのイメージの最初の部分だけしか物理
メモリに入っていないので、すぐに物理メモリ内にない仮想メモリ領域へとアクセス
がある。プロセスが、有効なページテーブルエントリを持たない仮想アドレスに
アクセスしたとき、プロセッサは Linux にページフォルトの発生を報告する。
<newline>[see: handle_mm_fault, in <htmlurl 
url="./The-Linux-Kernel-images/linux/mm/memory.c" 
name="mm/memory.c">]<newline>
ページフォルトは、そのページフォルトが発生した仮想アドレスと、発生の原因と
なったメモリアクセスのタイプとの情報を含んでいる。

<!--
Linux must find the vm_area_struct that represents the area of memory that
the page fault occurred in. As searching through the vm_area_struct data
structures is critical to the efficient handling of page faults, these are 
linked together in an AVL (Adelson-Velskii and Landis) tree structure. If 
there is no vm_area_struct data structure for this faulting virtual address, 
this process has accessed an illegal virtual address. Linux will signal the 
process, sending a SIGSEGV signal, and if the process does not have a handler 
for that signal it will be terminated. 
-->
<p>Linux は、ページフォルトが起こったメモリ領域を示している <tt><ref 
id="vm_area_struct" name="vm_area_struct"></tt> 構造体を探す。
<tt>vm_area_struct</tt> データ構造での検索はページフォルト
処理の効率を決定する上で非常に重要なので、それらは、AVL(Adelson-Velskii and 
Landis)木構造にリンクされている。もし、フォルトが起こった仮想アドレスに
関する <tt>vm_area_struct</tt> データ構造体が存在しない場合、このプロセスは、
無効な仮想アドレスにアクセスしたことになる。Linux は、そのプロセスに SIGSEGV 
シグナルを送り、もしそのプロセスが当該シグナルを処理しない場合は、そのプロセス
を終了させる。

<!--
Linux next checks the type of page fault that occurred against the types of
accesses allowed for this area of virtual memory. If the process is accessing 
the memory in an illegal way, say writing to an area that it is only allowed 
to read from, it is also signalled with a memory error. 
-->
<p>次に、Linux は、その仮想メモリ領域のアクセス権限に違反して起こったページ
フォルトのタイプをチェックする。プロセスが、たとえば読み出ししか許されない領域
に書き込みをしようとした場合のように、無効な方法でメモリにアクセスしている
場合、そのプロセスにはメモリエラー(memory error)のシグナルも送られる。

<!--
Now that Linux has determined that the page fault is legal, it must deal with 
it. 
Linux must differentiate between pages that are in the swap file and those that
are part of an executable image on a disk somewhere. It does this by using the
page table entry for this faulting virtual address. 
-->
<p>Linux がページフォルトが正当なものと判断した場合、ページフォルトに対処しな
ければならない。
<newline>[see: do_no_page(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/mm/memory.c" 
name="mm/memory.c">]<newline>
Linux は、スワップファイル内のページとディスクの他の場所にある実行イメージの
一部とを区別しなければならない。それをするためには、フォルトが起こった仮想アド
レスのページテーブルエントリが使用される。

<!--
If the page's page table entry is invalid but not empty, the page fault is for
a page currently being held in the swap file. For Alpha AXP page table entries,
these are entries which do not have their valid bit set but which have a 
non-zero value in their PFN field. In this case the PFN field holds 
information about where in the swap (and which swap file) the page is being 
held. How pages in the swap file are handled is described later in this 
chapter. 
-->
<p>フォルトページのページテーブルエントリが無効だが空でない場合、そのページ
フォルトは、現在スワップファイルに保存されているページのものである。Alpha AXP 
のページテーブルエントリの場合、有効ビットは設定されていないが <ref 
id="chapter_mm_pfn" name="PFN"> フィールドに 0 でない値が設定されている
エントリがある。その場合、PFN フィールドには、
スワップのどこに(そしてどのスワップファイルに)当該ページが保存されているのか
に関する情報が記されている。スワップファイル内のページを操作する方法は、
この章の後の部分で紹介される。

<!--
Not all vm_area_struct data structures have a set of virtual memory
operations and even those that do may not have a nopage operation. This is
because by default Linux will fix up the access by allocating a new physical
page and creating a valid page table entry for it. If there is a nopage 
operation for this area of virtual memory, Linux will use it. 
-->
<p><tt><ref id="vm_area_struct" name="vm_area_struct"></tt> データ構造体のすべ
てが、仮想メモリ操作のセットを持っているわけではなく、nopage 操作すらもっていな
い場合もある。これは、デフォルトでは Linux が、アクセスの問題を解決するために、
新しい物理ページを割り付け、そのための有効なページテーブルエントリを作成するよ
うになっているからである。(<tt>vm_area_struct</tt> に)この仮想メモリ領域に
対する nopage 操作が存在する場合、Linux はそのルーチンを使用する。

<!--
The generic Linux nopage operation is used for memory mapped executable
images and it uses the page cache to bring the required image page into 
physical memory. 
-->
<p>汎用的な Linux の nopege 操作ルーチンは、メモリにマップされた実行イメージに
対して使用されるものなので、その nopage 操作ルーチンは、ページキャッシュを
利用して、必要なイメージページを物理メモリに持ってくる。
<newline>[see: filemap_nopage(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/mm/filemap.c" 
name="mm/filemap.c">]<newline>

<!--
However the required page is brought into physical memory, the processes page
tables are updated. It may be necessary for hardware specific actions to update
those entries, particularly if the processor uses translation look aside 
buffers. Now that the page fault has been handled it can be dismissed and the 
process is restarted at the instruction that made the faulting virtual memory 
access. 
-->
<p>方法はどうあれ、必要なページが物理メモリに置かれた場合は、
プロセスページテーブルはアップデートされる。それらのエントリをアップデート
するためにはハードウェア固有の処理が必要になるかもしれない。特に、プロセッサ
がアドレス操作バッファ(Translation Look-aside Buffer, TLB)を利用している場合は
そうである。これでようやくページフォルトは処理されたので、フォルトは解除さ
れ、プロセスは、仮想メモリアクセスでフォルトを起こした命令の時点から再
スタートされる。

<!--3.7  The Linux Page Cache-->
<sect1>Linux のページキャッシュ<label id="chapter_mm_sect7">
<p>

<label id="figure3-6">
<!--                 Figure 3.6: The Linux Page Cache-->
<#if output="html">
<figure><ph vspace="100"><img src="./The-Linux-Kernel-images/figure3-6.gif">
</figure>
</#if>
<#unless output="html">
<verb>
page_hash_table
+--------------+
|              |         mem_map_t                mem_map_t
|--------------|       +-----------+            +-----------+
|              |------>| inode     |12      +-->| inode     |12
|--------------|       |-----------|        |   |-----------|
|              |       | offset    |0x8000  |   | offset    |0x2000
|--------------|       |-----------|        |   |-----------|
|              |       |           |        |   |           |
|--------------|       |           |        |   |           |
|              |       |           |        |   |           |
|--------------|       |-----------|        |   |-----------|
|              |       | next_hash |--------+   | next_hash |
|              |       |-----------|            |-----------|
|              |       | prev_hash |            | prev_hash |
|              |       |-----------|            |-----------|
|              |       |           |            |           |
|              |       +-----------+            +-----------+
|              |
|--------------|
|              |
|--------------|
|              |
+--------------+
</verb>
</#if>
<p>図表3.6 Linux のページキャッシュ


<!--
The role of the Linux page cache is to speed up access to files on disk. Memory
mapped files are read a page at a time and these pages are stored in the page
cache. Figure  3.6 shows that the page cache consists of the
page_hash_table, a vector of pointers to mem_map_t data structures. 
-->
<p>Linux のページキャッシュの役割は、ディスク上のファイルへのアクセス速度を
上げることである。メモリにマップされたファイルはページ単位で読み出され、それら
のページはページキャッシュに保存される。図表(3.6)では、ページキャッシュが 
<tt><ref id="mem_map_t" name="page_hash_table"></tt> から構成されており、それ
が <tt><ref id="mem_map_t" name="mem_map_t"></tt> データ構造へのポインタの配列
となっていることが示されている。
<newline>[see: <htmlurl 
url="The-Linux-Kernel-images/linux/include/linux/pagemap.h" 
name="include/linux/pagemap.h">]<newline>

<!--
Each file in Linux is identified by a VFS inode data structure (described in
Chapter  filesystem-chapter) and each VFS inode is unique and fully describes
one and only one file. The index into the page table is derived from the 
file's VFS inode and the offset into the file. 
-->
<p>Linux 内のファイルはそれぞれ VFS inode データ構造で識別される(詳細は、
<ref id="chapter_fs" name="「ファイルシステム」">の章で述べる)。VFS inode は
システム上ユニークであり、特定の単一のファイルに関する完全な識別子となる。
ページテーブルへのインデックスは、ファイルの VFS inode とそのファイルへの
オフセットから導き出される。

<!--
Whenever a page is read from a memory mapped file, for example when it needs
to be brought back into memory during demand paging, the page is read through
the page cache. If the page is present in the cache, a pointer to the mem_map_t
data structure representing it is returned to the page fault handling code.
Otherwise the page must be brought into memory from the file system that holds
the image. Linux allocates a physical page and reads the page from the file on
disk. 
-->
<p>メモリにマップされたファイルからページが読み出されるとき、たとえばデマンド
ページングでページがメモリに戻されるときなどには、ページはページキャッシュか
ら読み出される。
ページがキャッシュ内にある場合は、そのキャッシュ内のページを表す <tt><ref 
id="mem_map_t" name="mem_map_t"></tt> データ構造体へのポインタが、ページフォ
ルト処理コードに返される。
そうでない場合は、ページは、そのイメージを保存しているファイルシステムから
メモリ内へと取り出さる必要がある。その場合、Linux は物理ページを割り付けて、
ディスク上のファイルからそのページを読み出す。

<!--
If it is possible, Linux will initiate a read of the next page in the file. 
This single page read ahead means that if the process is accessing the pages 
in the file serially, the next page will be waiting in memory for the process. 
-->
<p>要求がなくても、Linux の側でファイル内の次のページを読み出しておくことも
可能である。この単一ページの先読みは、もしプロセスがファイル内のページに連続
してアクセスしている場合は、そのプロセスのために次のページをメモリ内に待機さ
せることを意味する。

<!--
Over time the page cache grows as images are read and executed. Pages will be
removed from the cache as they are no longer needed, say as an image is no
longer being used by any process. As Linux uses memory it can start to run low
on physical pages. In this case Linux will reduce the size of the page cache. 
-->
<p>イメージが読み出されて実行されていくと、ページキャッシュはだんだんと大きく
なる。必要のなくなったページ、たとえばどのプロセスからもアクセスされなくなった
イメージは、キャッシュから削除される。
メモリの使用量が増えると、物理ページが不足してくることがある。その場合、
Linux はページキャッシュのサイズを小さくする。


<!--3.8  Swapping Out and Discarding Pages-->
<sect1>スワップアウトとページの破棄<label id="chapter_mm_sect8">

<!--
When physical memory becomes scarce the Linux memory management
subsystem must attempt to free physical pages. This task falls to the kernel
swap daemon (kswapd). 
The kernel swap daemon is a special type of process, a kernel thread. Kernel
threads are processes have no virtual memory, instead they run in kernel mode 
in the physical address space. The kernel swap daemon is slightly misnamed in
that it does more than merely swap pages out to the system's swap files. Its
role is make sure that there are enough free pages in the system to keep the
memory management system operating efficiently. 
-->
<p>物理メモリが少なくなると、Linux のメモリ管理サブシステムは、物理ページを
解放するよう努力しなければならない。このタスクは、カーネルスワップデーモン
(kernel swap daemon)(<tt>kswapd</tt>)の仕事である。
カーネルスワップデーモンは、カーネルスレッド(kernel thread)という特別な
プロセスである。
カーネルスレッドは仮想メモリを持たず、そのかわり物理アドレス空間内において
カーネルモードで実行される。このカーネルスワップデーモンは、その役割が
単にページをシステムのスワップファイルに書き出すだけでないことからすると、
やや命名に難があるといえる。その役割は、システム内で充分な空ページを
確保して、メモリ管理システムの操作効率を維持することである。

<!--
The Kernel swap daemon (kswapd) is started by the kernel init process at
startup time and sits waiting for the kernel swap timer to periodically 
expire. 
Every time the timer expires, the swap daemon looks to see if the number of 
free pages in the system is getting too low. It uses two variables, 
free_pages_high and free_pages_low to decide if it should free some pages. So 
long as the number of free pages in the system remains above free_pages_high, 
the kernel swap daemon does nothing; it sleeps again until its timer next 
expires. For the purposes of this check the kernel swap daemon takes into 
account the number of pages currently being written out to the swap file. It 
keeps a count of these in nr_async_pages; this is incremented each time a page
is queued waiting to be written out to the swap file and decremented when the 
write to the swap device has completed. free_pages_low and free_pages_high are
set at system startup time and are related to the number of physical pages in 
the system. If the number of free pages in the system has fallen below 
free_pages_high or worse still free_pages_low, the kernel swap daemon will try
three ways to reduce the number of physical pages being used by the system: 
-->
<p>カーネルスワップデーモン(<tt>kswapd</tt>)は、起動時にカーネル初期化プロセ
スにより起動され、カーネルスワップタイマーが定期的に時間切れになるのを待って
いる。
<newline>[see: kswapd(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/mm/vmscan.c" 
name="mm/vmscan.c">]<newline>
タイマーが時間切れになると、スワップデーモンはシステムの空ページの数が減りす
ぎていないかどうかを確認する。<tt>kswapd</tt>は、<tt>
<ref id="swap_info_struct" name="free_pages_high"></tt> と 
<tt>free_pages_low</tt> のふたつの変数を使ってページを解放するかどうかを判断
する。
システム内の空ページの数が <tt>free_pages_high</tt> よりも多い限り、カーネル
スワップデーモンは何もしない。タイマーが切れるまで再び休憩する。このチェックに
際して、カーネルスワップデーモンは、スワップファイルに現在書き出されている
ページ数を考慮に入れる。カーネルスワップデーモンは、その数を、<tt>
nr_async_pages</tt> に保持している。この数は、スワップファイルに書き出される
ためにページがキューに入れられたときに増加し、スワップデバイスへの書き込みが
完了したときに減少する。<tt>free_pages_high</tt> と <tt>free_page_low</tt> と
は、システム起動時にセットされ、システム内の物理ページの数と関連付けられる。
システム内の空ページの数が <tt>free_page_high</tt> 以下になるか、<tt>
free_pages_low</tt> 以下にまで落ち込んでしまった場合には、カーネルスワップ
デーモンは、3 つの方法を使ってシステムで使用されている物理ページの数を減ら
そうとする。

<!--
      Reducing the size of the buffer and page caches, 
      Swapping out System V shared memory pages, 
      Swapping out and discarding pages. 
-->
<itemize>
<item>バッファとページキャッシュのサイズを減らす。
<item>System V 共有メモリページをスワップアウトさせる。
<item>ページをスワップアウトさせて、破棄する。
</itemize>

<!--
If the number of free pages in the system has fallen below free_pages_low, the
kernel swap daemon will try to free 6 pages before it next runs. Otherwise it 
will try to free 3 pages. Each of the above methods are tried in turn until 
enough pages have been freed. The kernel swap daemon remembers which method it
was using the last time that it attempted to free physical pages. Each time it
runs it will start trying to free pages using this last successful method. 
-->
<p>システムの空ページの数が <tt>free_pages_low</tt> 以下になっている場合、
カーネルスワップデーモンは、次の実行時までに 6 つのページを解放する。でなけれ
ば、3 つのページを解放する。上記の方法は、充分なページが解放されるまで順番に
繰り返される。カーネルスワップデーモンは、物理メモリを解放するとき最後に
使った方法を覚えている。実行の際はいつも、前回の最後に成功した方法を使用して
ページを解放しようとし始める。

<!--
After it has free sufficient pages, the swap daemon sleeps again until its 
timer expires. If the reason that the kernel swap daemon freed pages was that 
the number of free pages in the system had fallen below free_pages_low, it only
sleeps for half its usual time. Once the number of free pages is more than
free_pages_low the kernel swap daemon goes back to sleeping longer between
checks. 
-->
<p>充分な空ページが出来たら、スワップデーモンは、タイマーが切れるまで再び休憩
に入る。カーネルスワップデーモンがページを解放した理由が、システム内の空ページ
の数が <tt>free_pages_low</tt> を下回ったからであった場合は、その休憩時間は、
通常の半分に短縮される。空ページの数が <tt>free_pages_low</tt> の数を超えて
しまえば、カーネルスワップデーモンは通常のタイマー間隔での休憩に戻る。

<!--3.8.1  Reducing the Size of the Page and Buffer Caches-->
<sect2>ページキャッシュとバッファキャッシュのサイズの縮小<label 
id="chapter_mm_sect8-1">

<!--
The pages held in the page and buffer caches are good candidates for being 
freed into the free_area vector. The Page Cache, which contains pages of memory
mapped files, may contain unneccessary pages that are filling up the system's
memory. Likewise the Buffer Cache, which contains buffers read from or being
written to physical devices, may also contain unneeded buffers. When the
physical pages in the system start to run out, discarding pages from these
caches is relatively easy as it requires no writing to physical devices (unlike
swapping pages out of memory). Discarding these pages does not have too
many harmful side effects other than making access to physical devices and
memory mapped files slower. However, if the discarding of pages from these
caches is done fairly, all processes will suffer equally. 
-->
<p>ページキャッシュとバッファキャッシュに保存されているページは、解放して <tt>
<ref id="free_area" name="free_area"></tt> 配列に入れるべき有力な候補者である。
ページキャッシュには、メモリにマップされたファイルのページが含まれているので、
メモリを満杯にしている不要なページが含まれている場合がある。同様に、バッファ
キャッシュには、物理デバイスに対する読み書きの結果としてのバッファが含まれてい
るので、ここにも必要のないバッファが含まれている場合がある。
システム内の物理ページが不足し始めると、これらのキャッシュからページを削除する
ことは相対的に容易になる。ページをメモリからスワップアウトさせる場合と異なり、
それらは、物理デバイスへの書き込みを必要としないからである。キャッシュから不要
なページをいくつか破棄したとしても、物理デバイスやメモリにマップされたファイル
へのアクセスが遅くなる以外には、目立った有害な副作用はない。しかし、もしそれら
のキャッシュからページをすべて破棄したとしたら、全プロセスが等しく悪影響を受
ける。

<!--
Every time the Kernel swap daemon tries to shrink these caches 
it examines a block of pages in the mem_map page vector to see if any can be
discarded from physical memory. The size of the block of pages examined is
higher if the kernel swap daemon is intensively swapping; that is if the 
number of free pages in the system has fallen dangerously low. The blocks of 
pages are examined in a cyclical manner; a different block of pages is 
examined each time an attempt is made to shrink the memory map. This is known 
as the clock algorithm as, rather like the minute hand of a clock, the whole 
mem_map page vector is examined a few pages at a time. 
-->
<p>カーネルスワップデーモンは、これらのキャッシュを縮小しようとするたびに、
<tt>page</tt> の配列 <tt><ref id="mem_map_t" name="mem_map"></tt> 内のページ
ブロックを調べて、物理メモリから削除できるものがないかどうかを確認する。
<newline>[see: shrink_mmap(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/mm/filemap.c" 
name="mm/filemap.c">]<newline>
カーネルスワップデーモンが熱心にスワップ処理をしている場合、すなわちシステム
の空ページの数が危険なほど低下している場合には、より大きなサイズのページ
ブロックが調査される。ページブロックの調査は循環的な方法でなされる。すなわち、
メモリマップを縮小しようとするたびごとに違うサイズのページブロックが調査され
る。この方法は、時計の分針に似ていることからクロックアルゴリズム
(clock algorithm)と呼ばれ、<tt>page</tt> の配列 <tt><ref id="mem_map_t" 
name="mem_map"></tt> 全体が、一度に数ページ単位で調査される。

<!--
Each page being examined is checked to see if it is cached in either the page
cache or the buffer cache. You should note that shared pages are not considered
for discarding at this time and that a page cannot be in both caches at the 
same time. If the page is not in either cache then the next page in the 
mem_map page vector is examined. 
-->
<p>個々のページを調査する際は、そのページがページキャッシュかバッファキャッシュ
にキャッシュされているかどうか確認される。
注意すべきなのは、この時点では共有ページは破棄されないこと、および同時に両方の
キャッシュに入っているページは存在しないことである。
当該ページがどちらのキャッシュにも入っていない場合、<tt>page</tt> の配列 <tt>
mem_map</tt> の次のページが調査される。

<!--
Pages are cached in the buffer cache (or rather the buffers within the pages 
are cached) to make buffer allocation and deallocation more efficient. The 
memory map shrinking code tries to free the buffers that are contained within 
the page being examined. 
If all the buffers are freed, then the pages that contain them are also be 
freed. If the examined page is in the Linux page cache, it is removed from the
page cache and freed. 
-->
<p>ページがバッファキャッシュにキャッシュされるのは(あるいは、バッファがページ
キャッシュにキャッシュされるのは)、バッファの割り付けと解放とをより効率的に
行うためである。メモリ縮小コードは調査が終わったページのバッファから、解放しよ
うとする。
<newline>[see: try_to_free_buffer, in <htmlurl 
url="./The-Linux-Kernel-images/linux/fs/buffer.c" 
name="fs/buffer.c">]
それらすべてのバッファが解放されると、それらを含むページも解放される。調査
されたページが Linux のページキャッシュに入っている場合、それはページ
キャッシュから削除され解放される。

<!--
When enough pages have been freed on this attempt then the kernel swap
daemon will wait until the next time it is periodically woken. As none of the 
freed pages were part of any process's virtual memory (they were cached pages),
then no page tables need updating. If there were not enough cached pages
discarded then the swap daemon will try to swap out some shared pages. 
-->
<p>この作業によって充分なページが解放されたら、カーネルスワップデーモンは、
次の定期的呼び出しまで休憩する。解放されたページはどのプロセスの仮想メモリ
の一部にもなっていなかったので(それらはキャッシュされたページであったので)、
どのページテーブルもアップデートされる必要がない。キャッシュされたページが
充分に解放されない場合、スワップデーモンは共有ページのいくつかをスワップアウト
しようとする。

<!--3.8.2  Swapping Out System V Shared Memory Pages-->
<sect2>System V 共有メモリページのスワップアウト<label id="chapter_mm_sect8-2">

<!--
System V shared memory is an inter-process communication mechanism which
allows two or more processes to share virtual memory in order to pass
information amongst themselves. How processes share memory in this way is
described in more detail in Chapter  IPC-chapter. For now it is enough to say
that each area of System V shared memory is described by a shmid_ds data
structure. This contains a pointer to a list of vm_area_struct data structures,
one for each process sharing this area of virtual memory. The
vm_area_struct data structures describe where in each processes virtual
memory this area of System V shared memory goes. Each vm_area_struct
data structure for this System V shared memory is linked together using the
vm_next_shared and vm_prev_shared pointers. Each shmid_ds data
structure also contains a list of page table entries each of which describes 
the physical page that a shared virtual page maps to. 
-->
<p>System V 共有メモリとは、プロセス間通信のメカニズムであり、ふたつ以上の
プロセスがお互いに情報を交換するために仮想メモリを共有することを許す仕組み
である。この方法でどのようにプロセスがメモリを共有するかについては、
<ref id="chapter_ipc_sect3-4" name="「プロセス間通信の仕組み」">の章で詳細に
解説する。今のところ、System V 共有メモリのそれぞれのエリアは、<tt><ref 
id="shmid_ds" name="shmid_ds"></tt> データ構造体により記述されているとだけ
述べておく。
これには、<tt><ref id="vm_area_struct" name="vm_area_struct"></tt> データ構造体
のリストへのポインタが含まれている。その個々の <tt>vm_area_struct</tt> データ
構造体は、仮想メモリの当該領域を共有するプロセスのものであり、それぞれのプロセ
スの仮想メモリのどこに System V 共有メモリの領域があるのかを記述するものであ
る。System V 共有メモリのための <tt>vm_area_struct</tt> データ構造体はそれぞ
れ、<tt><ref id="vm_area_struct" name="vm_next_shared"></tt> と <tt>
vm_prev_shared</tt> ポインタを使ってお互いにリンクされている。
個々の <tt>shmid_ds</tt> データ構造体には、ページテーブルエントリのリストが含ま
れていて、それぞれ共有仮想ページがマップされている物理ページを記述している。

<!--
The kernel swap daemon also uses a clock algorithm when swapping out System
V shared memory pages. . Each time it runs it remembers which page of which 
shared virtual memory area it last swapped out. It does this by keeping two 
indices, the first is an index into the set of shmid_ds data structures, the 
second into the list of page table entries for this area of System V shared 
memory. This makes sure that it fairly victimizes the areas of System V 
shared memory. 
-->
<p>カーネルスワップデーモンは、System V 共有メモリページをスワップアウトする
時にもクロックアルゴリズムを使用する。それが実行される際はいつも、どの共有仮想
メモリエリアのどのページを最後にスワップアウトしたか、カーネルスワップデーモン
は覚えている。それを実現するために、スワップデーモンはふたつのインデックスを
使用する。ひとつは、<tt><ref id="shmid_ds" name="shmid_ds"></tt> データ構造体
のセットへのインデックスであり、もうひとつは、System V 共有メモリの該当エリア
に関するページテーブルエントリのリストへのインデックスである。それによって、
System V 共有メモリに対して公正な負担が課されるようになっている。

<!--
As the physical page frame number for a given virtual page of System V shared
memory is contained in the page tables of all of the processes sharing this 
area of virtual memory, the kernel swap daemon must modify all of these page 
tables to show that the page is no longer in memory but is now held in the 
swap file. For each shared page it is swapping out, the kernel swap daemon 
finds the page table entry in each of the sharing processes page tables (by 
following a pointer from each vm_area_struct data structure). If this 
processes page table entry for this page of System V shared memory is valid, 
it converts it into an invalid but swapped out page table entry and reduces 
this (shared) page's count of users by one. The format of a swapped out System
V shared page table entry contains an index into the set of shmid_ds data 
structures and an index into the page table entries for this area of System V 
shared memory. 
-->
<p>System V共有メモリの仮想ページに対する物理ページフレーム番号は、該当する仮想
メモリエリアを共有するすべてのプロセスのページテーブル内に含まれているので、
カーネルスワップデーモンはこれらすべてのページテーブルを書き換えて、該当ページ
はもはやメモリ内にはなく、スワップファイルに保存されているということを示さな
ければならない。共有ページはひとつずつスワップアウトされるので、カーネル
スワップデーモンは、個々の共有プロセスのページテーブル内のページテーブル
エントリを探す。(これは、個々の <tt><ref id="vm_area_struct" 
name="vm_area_struct"></tt> データ構造体のポインタを追跡することにより実行され
る。)
もし、その System V 共有メモリエリアに対するプロセスのページエントリーテーブル
が有効ならば、スワップデーモンは、それを無効だがスワップアウトされたページ
テーブルエントリである旨に書き換えて、その(共有)ページのユーザ数カウントを
ひとつ減少させる。スワップアウトされた System V 共有ページのテーブルエントリの
フォーマットには、<tt><ref id="shmid_ds" name="shmid_ds"></tt> データ構造体の
セットへのインデックスと その System V 共有メモリエリアに対するページテーブル
エントリへのインデックスとが含まれる。

<!--
If the page's count is zero after the page tables of the sharing processes have
all been modified, the shared page can be written out to the swap file. The 
page table entry in the list pointed at by the shmid_ds data structure for 
this area of System V shared memory is replaced by a swapped out page table 
entry. A swapped out page table entry is invalid but contains an index into 
the set of open swap files and the offset in that file where the swapped out 
page can be found. This information will be used when the page has to be 
brought back into physical memory. 
-->
<p>共有プロセスのページテーブルが完全に書き換えられてページカウントがゼロに
なると、共有ページをスワップファイルに書き出すことが可能になる。その System 
V 共有メモリエリアに対するページテーブルエントリのなかで、<tt>shmid_ds</tt> 
データ構造体によって指示されたリスト内に存在するものは、スワップアウトされた
ページテーブルのエントリ(swapped out page table entry)によって置き換えられ
る。スワップアウトされたページテーブルのエントリは無効だが、スワップファイルを
オープンするためのセットへのインデックスと、そのファイル内でスワップ
アウトされたページを探すためのオフセットとが含まれている。この情報が使用され
るのは、そのページが物理メモリ内に再度戻されるときである。

<!--3.8.3  Swapping Out and Discarding Pages-->
<sect2>スワップアウトされたか破棄されたページ<label id="chapter_mm_sect8-3">

<!--
The swap daemon looks at each process in the system in turn to see if it is a
good candidate for swapping. Good candidates are processes that can be swapped
(some cannot) and that have one or more pages which can be swapped or 
discarded from memory. Pages are swapped out of physical memory into the 
system's swap files only if the data in them cannot be retrieved another way. 
-->
<p>スワップデーモンはシステム内のプロセスを順番に調べて、スワップすべき有力
候補がいないかどうかを探す。
<newline>[see: swap_out(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/mm/vmscan.c" 
name="mm/vmscan.c">]<newline>
候補者とは、スワップ可能で(不可能なプロセスもあ
る)、メモリ内からスワップか破棄することが可能なひとつ以上のページを持っている
プロセスである。ページが物理メモリからスワップアウトされてシステムのスワップ
ファイルに入れられるのは、ページ内のデータがスワップ以外の方法では元に戻せな
い場合だけである。

<!--
A lot of the contents of an executable image come from the image's file and can
easily be re-read from that file. For example, the executable instructions of 
an image will never be modified by the image and so will never be written to 
the swap file. These pages can simply be discarded; when they are again 
referenced by the process, they will be brought back into memory from the 
executable image. 
-->
<p>実行イメージの内容の多くはそのイメージのファイルからメモリ内に置かれている
ので、その内容の再読み出しは簡単に実行できる。たとえば、あるイメージの実行命令
は、そのイメージによって修正されることはないので、それがスワップファイルに書き
込まれることは決してない。それらのページは単に破棄されるだけである。プロセス
から再度参照される時は、実行イメージからメモリ内に戻せばいいからである。

<!--
Once the process to swap has been located, the swap daemon looks through all
of its virtual memory regions looking for areas which are not shared or 
locked. Linux does not swap out all of the swappable pages of the process 
that it has selected; instead it removes only a small number of pages. 
Pages cannot be swapped or discarded if they are locked in memory. 
-->
<p><label id="chapter_mm_lock">
スワップすべきプロセスが見つかったら、スワップデーモンはそのプロセスの仮想
メモリ領域を走査して共有されたりロック(lock)されたりしていないエリアを探す。
Linux 
は、選択したプロセスのスワップ可能なすべてのページをスワップするわけではない。
むしろ、ごく少数のページだけを削除する。メモリ内でロックされている場合、ページ
はスワップも破棄もできない。<newline>
(原注: この操作は、当該プロセスの <tt><ref id="mm_struct" name="mm_struct">
</tt> 上でキューイングされた <tt>vm_area_struct</tt> 構造体のリストにある 
<tt>mv_next</tt> ポインタを順に検査することで実行される。)

<!--
The Linux swap algorithm uses page aging. Each page has a counter (held in the
mem_map_t data structure) that gives the Kernel swap daemon some idea
whether or not a page is worth swapping. Pages age when they are unused and
rejuvinate on access; the swap daemon only swaps out old pages. The default
action when a page is first allocated, is to give it an initial age of 3. 
Each time it is touched, it's age is increased by 3 to a maximum of 20. Every 
time the Kernel swap daemon runs it ages pages, decrementing their age by 1. 
These default actions can be changed and for this reason they (and other swap 
related information) are stored in the swap_control data structure. 
-->
<p>Linux のスワップアルゴリズムは、ページエイジング(page aging)を使っている。
<newline>[see: swap_out_vma(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/mm/vmscan.c" 
name="mm/vmscan.c">]<newline>
ページはそれぞれ(<tt><ref id="mem_map_t" name="mem_map_t"></tt> 構造体の中に)
カウンタを持っていて、それによってカーネルスワップデーモンにページがスワップ
されるべきかどうかを伝えている。
ページが使用されなかったりアクセスによって若返らない場合に、ページは歳を取る。
スワップデーモンは高齢のページだけをスワップアウトさせる。ページを最初に
割り付けるときのデフォルトの操作では、最初に 3 の寿命を与える。
アクセスがあるたびに、年齢は 3 から最大 20 まで上がる。カーネルスワップ
デーモンが実行されると、そのたびにページを加齢し、その年限をひとつずつ引いて
いく。こうしたデフォルトの操作は変更可能であり、それゆえ、設定値(と、その他の
スワップに関係した情報)は、<tt><ref id="swap_control" name="swap_control">
</tt> データ構造体に保存されている。

<!--
If the page is old (age = 0), the swap daemon will process it further. Dirty 
pages are pages which can be swapped out. Linux uses an architecture specific 
bit in the PTE to describe pages this way (see Figure  3.2). However, not all 
dirty pages are necessarily written to the swap file. Every virtual memory 
region of a process may have its own swap operation (pointed at by the vm_ops 
pointer in the vm_area_struct) and that method is used. Otherwise, the swap 
daemon will allocate a page in the swap file and write the page out to that 
device. 
-->
<p>ページの寿命が尽きたら(age=0)、スワップデーモンはさらにその処理を進める。
修正されているページ(dirty page)は、スワップアウトすることができる。Linux は、
PTE 内のアーキテクチャに固有のビットを使ってそれを区別する。
(<ref id="figure3-2" name="図表(3.2)"> 参照)
しかし、dirty page がすべてスワップファイルに書き出される必要はない。
あらゆるプロセスの仮想メモリ領域は、それ自身に必要なスワップ操作が指定されて
いるかもしれず(それは、<tt><ref id="vm_area_struct" name="vm_area_struct">
</tt> 内の <tt>vm_ops</tt> ポインタ
で示される)、そこでの方法が利用されるからである。そうでない場合、スワップ
デーモンは、ページをスワップファイルに割り付け、スワップデバイスに書き出す。

<!--
The page's page table entry is replaced by one which is marked as invalid but
which contains information about where the page is in the swap file. This is an
offset into the swap file where the page is held and an indication of which 
swap file is being used. Whatever the swap method used, the original physical 
page is made free by putting it back into the free_area. Clean (or rather not 
dirty) pages can be discarded and put back into the free_area for re-use. 
-->
<p>スワップアウトされたページのページテーブルエントリは、無効とマークされた
エントリによって置き換えられるが、そのエントリには、ページのスワップファイル
内の位置に関する情報が含まれている。その情報は、スワップファイル内のどこに
ページが保存されているかを表すオフセット値と、どのスワップファイルが使用され
たかを示す指示子から成る。
どのようなスワップメソッドが使用された場合でも、もとの物理ページは解放され、
<tt><ref id="free_area" name="free_area"></tt> の中に入れられる。内容の変更
されていない(あるいは、修正されていない(not dirty))ページは、破棄されて、
再利用のために <tt>free_area</tt> に入れられる。

<!--
If enough of the swappable processes pages have been swapped out or
discarded, the swap daemon will again sleep. The next time it wakes it will
consider the next process in the system. In this way, the swap daemon nibbles
away at each processes physical pages until the system is again in balance.
This is much fairer than swapping out whole processes. 
-->
<p>スワップ可能なプロセスのページが、充分な数だけスワップアウトされるか
破棄された場合、スワップデーモンは再度スリープする。次に起きるときは、システ
ム内の次のプロセスを対象として考慮する。この方法によって、スワップデーモンは
システムがバランスを取り戻すまで、プロセスの物理ページを少しずつ解放してい
く。この方法は、プロセス全体をスワップアウトするよりもずっと公平である。


<!--3.9  The Swap Cache-->
<sect1>スワップキャッシュ<label id="chapter_mm_sect9">

<!--
When swapping pages out to the swap files, Linux avoids writing pages if it
does not have to. There are times when a page is both in a swap file and in
physical memory. This happens when a page that was swapped out of memory
was then brought back into memory when it was again accessed by a process.
So long as the page in memory is not written to, the copy in the swap file
remains valid. 
-->
<p>ページをスワップファイルに移す際、Linux は必要がなければページを書き
込まない。あるページがスワップファイルと物理メモリの両方に存在するときがある。
そのようなことが起こるのは、スワップされてメモリから削除されていたページが
プロセスに再度アクセスされたことでメモリに戻った場合である。メモリにある
ページが書き込みを受けていない限り、スワップファイルにあるページのコピーは
有効なままである。

<!--
Linux uses the swap cache to track these pages. The swap cache is a list of
page table entries, one per physical page in the system. This is a page table
entry for a swapped out page and describes which swap file the page is being
held in together with its location in the swap file. If a swap cache entry is
non-zero, it represents a page which is being held in a swap file that has not
been modified. If the page is subsequently modified (by being written to), its
entry is removed from the swap cache. 
-->
<p>Linux はそのようなページを監視するためにスワップキャッシュを使う。スワップ
キャッシュはページテーブルエントリのリストであり、エントリはシステム上の物理
ページごとに存在する。これは、スワップアウトしたページのページテーブル
エントリであり、そのページがどのスワップファイルに保存されているかということ
と、そのスワップファイル内での位置とが記されているものである。スワップキャッ
シュエントリがゼロでない場合、それは、そのページがスワップファイル内にあり、
しかもそれが変更されていないということを表している。ページの中味がその後で
(書き込みをされて)変更された場合、そのエントリはスワップキャッシュから削除
される。

<!--
When Linux needs to swap a physical page out to a swap file it consults the
swap cache and, if there is a valid entry for this page, it does not need to 
write the page out to the swap file. This is because the page in memory has 
not been modified since it was last read from the swap file. 
-->
<p>Linux が物理ページをスワップファイルにスワップアウトする必要がある場合、
スワップキャッシュをまず調べる。スワップキャッシュにそのページ用の有効な
エントリがあるなら、そのページをスワップファイルに書き出す必要はない。
なぜなら、メモリ内のそのページは、スワップファイルから最後に読み出されて以来
変更されていないからである。

<!--
The entries in the swap cache are page table entries for swapped out pages.
They are marked as invalid but contain information which allow Linux to find 
the right swap file and the right page within that swap file. 
-->
<p>スワップキャッシュのエントリはスワップアウトされたページに関するページテー
ブルのエントリである。それらは無効とマークされているが、どのスワップファイル
のどこでそのページが見つかるかを Linux に知らせる情報を含んでいる。

<!--3.10  Swapping Pages In-->
<sect1>スワップのページイン<label id="chapter_mm_sect10">

<!--
The dirty pages saved in the swap files may be needed again, for example when
an application writes to an area of virtual memory whose contents are held in a
swapped out physical page. Accessing a page of virtual memory that is not held
in physical memory causes a page fault to occur. The page fault is the 
processor signalling the operating system that it cannot translate a virtual 
address into a physical one. In this case this is because the page table entry
describing this page of virtual memory was marked as invalid when the page was
swapped out. The processor cannot handle the virtual to physical address 
translation and so hands control back to the operating system describing as it
does so the virtual address that faulted and the reason for the fault. The 
format of this information and how the processor passes control to the 
operating system is processor specific. 
-->
<p>書き込みをされてスワップファイルに保存されたページが再度必要となることが
ある。たとえば、アプリケーションが仮想メモリのある領域に書き込みをしたいのだ
が、その内容が物理ページからスワップアウトされていた場合などである。物理メモリ
上にない仮想メモリのページにアクセスがあった場合、ページフォルトが起こる。
ページフォルトとは、プロセッサがオペレーティングシステムにシグナルを送って、
仮想アドレスを物理アドレスに変換できないことを伝えることである。この場合、
原因は、仮想メモリの該当ページの情報を記しているページテーブルのエントリが、
ページがスワップアウトされる際に無効とマークされるからである。プロセッサは
その仮想アドレスを物理アドレスに変換できないので、制御をオペレーティングシス
テムに手渡して、仮想アドレスがフォルトを起こしたこととそのフォルトの理由とを
伝える。この情報のフォーマットとプロセッサがオペレーティングシステムに制御を
渡す方法とは、プロセッサ固有のものである。
<newline>[see: do_page_fault(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/arch/i386/mm/fault.c" 
name="arch/i386/mm/fault.c">]<newline>

<!--
The processor specific page fault handling code must locate the
vm_area_struct data structure that describes the area of virtual memory that
contains the faulting virtual address. It does this by searching the
vm_area_struct data structures for this process until it finds the one
containing the faulting virtual address. This is very time critical code and a
processes vm_area_struct data structures are so arranged as to make this
search take as little time as possible. 
-->
<p>プロセッサ固有のページフォルト処理コードは、まず必要な <tt><ref 
id="vm_area_struct" name="vm_area_struct"></tt> データ構造を探さなければなら
ない。
<tt>vm_area_struct</tt>は、仮想メモリのエリアを記述したものであり、そのフォルト
が起きた仮想メモリアドレスを含んでいるからである。
フォルト処理コードは、それらの構造体を検索し、フォルトを起こした仮想アドレスを
含むものを見つけだす。これらは、決して長時間掛かってはいけない(time critical)
コードや処理であるので、<tt>vm_area_struct</tt> 構造体は、検索時間が最短になる
ように並べられている。


<!--
Having carried out the appropriate processor specific actions and found that 
the faulting virtual address is for a valid area of virtual memory, the page 
fault processing becomes generic and applicable to all processors that Linux 
runs on. 
The generic page fault handling code looks for the page table entry for the
faulting virtual address. If the page table entry it finds is for a swapped 
out page, Linux must swap the page back into physical memory. The format of 
the page table entry for a swapped out page is processor specific but all 
processors mark these pages as invalid and put the information neccessary to 
locate the page within the swap file into the page table entry. Linux needs 
this information in order to bring the page back into physical memory. 

-->
<p>プロセッサ固有の動作を適切に処理し、フォルトが起きた仮想アドレスが有効な
仮想メモリ領域にあることが分かった場合、その後のページフォルト処理は、Linux 
が稼働するどのプロセッサにも汎用的で適用可能なものとなる。
<newline>[see: do_no_page(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/mm/memory.c" 
name="mm/memory.c">]<newline>
汎用のページフォルト処理コードは、フォルトを起こした仮想アドレスのページ
テーブルエントリを探す。探し出したページテーブルエントリがスワップアウトされた
ページのものであった場合、Linux はページを物理メモリに戻さなければならない。
スワップアウトされたページに対するページテーブルのエントリはプロセッサ固有の
ものだが、すべてのプロセッサはそれらのページを無効とマークしてあり、そのページ
テーブルエントリにはスワップファイル内で該当ページを見つける際に必要な情報が
書き込まれている。Linux はこの情報を使って、そのページを物理メモリに呼び戻す。
<newline>[see: do_swap_page(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/mm/memory.c"
name="mm/memory.c">]

<!--
At this point, Linux knows the faulting virtual address and has a page table 
entry containing information about where this page has been swapped to. The
vm_area_struct data structure may contain a pointer to a routine which will
swap any page of the area of virtual memory that it describes back into 
physical memory. This is its swapin operation. If there is a swapin operation 
for this area of virtual memory then Linux will use it. This is, in fact, how 
swapped out System V shared memory pages are handled as it requires special 
handling because the format of a swapped out System V shared page is a little 
different from that of an ordinairy swapped out page. There may not be a swapin
operation, in which case Linux will assume that this is an ordinairy page that
does not need to be specially handled. 
It allocates a free physical page and reads the swapped out page back from the
swap file. Information telling it where in the swap file (and which swap file)
is taken from the the invalid page table entry. 
-->
<p>この時点で、Linux は、フォルトが起こった仮想アドレスを知っており、該当
ページがどこにスワップアウトされているかに関する情報を含むページテーブル
エントリを持っている。<tt><ref id="vm_area_struct" name="vm_area_struct"></tt> 
構造体にはある<ref id="vm_operations_struct" name="ルーチン">へのポインタが含ま
れている場合があり、そのルーチンは、その <tt>vm_area_struct</tt> 構造体
で記述している仮想メモリ領域の任意のページを物理メモリへと戻す処理をする。
これは、スワップイン(swapin)操作と呼ばれる。
<newline>[see: shm_swap_in(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/ipc/shm.c" 
name="ipc/shm.c">]<newline>
その仮想メモリエリアにスワップイン処理ルーチンが存在する場合、Linux はその
ルーチンを使用する。これは実際、スワップアウトされた System V 共有メモリ
ページが処理される方法でもある。スワップアウトされた System V 共有ページの
フォーマットは通常のスワップアウトされたページのフォーマットとは少し異なるの
で、それには特別な処理方法が必要とされるからである。しかし、そうした
スワップイン処理ルーチンが存在しない場合もあるので、その際には、Linux は、
そのページが特別な処理を必要としない通常のページであると推定する。
<newline>[see: swap_in(), in <htmlurl 
url="The-Linux-Kernel-images/linux/mm/page_alloc.c" 
name="mm/page_alloc.c">]<newline>
そして、空の物理ページを割り当て、スワップファイルからスワップアウトされた
ページを読み出す。ページがスワップファイルのどこに(およびどのスワップファイル
に)あるかを示す情報は、無効とマークされたそのページテーブルエントリから取得
される。

<!--
If the access that caused the page fault was not a write access then the page 
is left in the swap cache and its page table entry is not marked as writable. 
If the page is subsequently written to, another page fault will occur and, at 
that point, the page is marked as dirty and its entry is removed from the swap
cache. If the page is not written to and it needs to be swapped out again, 
Linux can avoid the write of the page to its swap file because the page is 
already in the swap file. 
-->
<p>ページフォルトを発生させたアクセスが書き込みアクセスでない場合、ページは
スワップキャッシュにそのまま残され、そのページテーブルエントリも書き込み可能
とはマークされない。その後、そのページへの書き込みアクセスが発生すると、その
時点で別なページフォルトが生じ、該当するページ dirty とマークされ、そのエント
リはスワップキャッシュから削除される。
そのページが書き込みされずに、再度スワップアウトされ
る必要が生じた場合、そのページは既にスワップファイルに存在するので、Linux は
ページをあらためてスワップファイルに書き込みせずに済ませることができる。

<!--
If the access that caused the page to be brought in from the swap file was a
write operation, this page is removed from the swap cache and its page table
entry is marked as both dirty and writable. 
-->
<p>ページがスワップファイルから取ってこられるきっかけを作ったアクセスが書き込み
操作であった場合、そのページはスワップキャッシュから削除され、そのページテー
ブルエントリは、dirty かつ書き込み可能であるとマークされる。

<!--
Footnotes:

1 Confusingly the structure is also known as the page structure. 
2 Bibliography reference here 
-->
<footnote>
<label id="chapter_mm_fn1">
(脚注1)紛らわしいことに、この構造体は、ページ構造体とも呼ばれている。<newline>
(脚注2)ここに参考文献を置くこと。
</footnote>

<!--第  5 章 プロセス-->
<!--Chapter 4 Processes-->
<sect>プロセス<label id="chapter_p">
<p>
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/penguin2.gif">
</figure>

<!--
This chapter describes what a process is and how the Linux kernel creates,
manages and deletes the processes in the system. 
-->
<p>この章ではプロセスとは何かを説明し、Linux がシステム上でプロセスをどの
ように生成、管理、削除しているのかについて解説する。

<!--
Processes carry out tasks within the operating system. A program is a set of
machine code instructions and data stored in an executable image on disk and 
is, as such, a passive entity; a process can be thought of as a computer 
program in action. 
It is a dynamic entity, constantly changing as the machine code instructions 
are executed by the processor. As well as the program's instructions and data,
the process also includes the program counter and all of the CPU's registers 
as well as the process stacks containing temporary data such as routine 
parameters, return addresses and saved variables. The current executing 
program, or process, includes all of the current activity in the 
microprocessor. Linux is a multiprocessing operating system. Processes are 
separate tasks each with their own rights and responsibilities. If one process
crashes it will not cause another process in the system to crash. Each 
individual process runs in its own virtual address space and is not capable of
interacting with another process except through secure, kernel managed 
mechanisms. 
-->
<p>プロセスはオペレーティングシステム内でタスクを実行する。プログラムと
は、実行イメージとしてディスクに保存されたマシン語の命令とデータとのセットで
ある。したがって、プログラムとは受動的な実体である。反対に、
プロセスとは実行中のコンピュータプログラムであると考えることができる。
プロセスはダイナミックな実体であり、マシン語の命令がプロセッサにより実行される
につれて常に変化してゆく。プログラムという概念が命令とデータを含むものである
ように、プロセスも、プログラムカウンタ(program counter)など CPU の全レジスタ
情報やプロセススタックを含む概念であり、それらが保持する一時データであるルー
チンパラメータや戻りアドレス、保存された変数などを包含する概念である。
現在実行中のプログラムもしくはカレントプロセス(current process)とは、マイクロプ
ロセッサでの現在の活動すべてを含む概念である。
<p>
Linux はマルチプロセスのオペレーティングシステムである。プロセスとは
個別のタスクであり、それぞれが独自の権限と責任を持つ。ひとつのプロセスが
クラッシュした場合でも、それが他のプロセスをクラッシュさせることはない。
個々の独立したプロセスが独自の仮想アドレス空間で実行されていて、カーネルが
管理する安全な仕組みを使う場合を除いては、他のプロセスと相互に影響を与えあう
ことはない。

<!--
During the lifetime of a process it will use many system resources. It will 
use the CPUs in the system to run its instructions and the system's physical 
memory to hold it and its data. It will open and use files within the 
filesystems and may directly or indirectly use the physical devices in the 
system. Linux must keep track of the process itself and of the system 
resources that it has so that it can manage it and the other processes in the 
system fairly. It would not be fair to the other processes in the system if 
one process monopolized most of the system's physical memory or its CPUs. 
-->
<p>プロセスは、そのライフサイクルの中で、多くのシステムリソース(system 
resources)を使用する。命令を実行するときにはシステムの CPU を使用し、自分自身
とそのデータを保持するにはシステムの物理メモリを使用する。ファイルシステム内
でファイルをオープンして使用し、システムの物理デバイスを直接・間接に利用する
場合もある。Linux は、プロセス自体とそれが持つシステムリソースを常に
監視することで、システム内の当該プロセスとその他のプロセスを公平に管理しなけ
ればならない。ひとつのプロセスがシステムの物理メモリや CPU を独占したとしたら、
それはシステムの他のプロセスに対して公平とは言えない。

<!--
The most precious resource in the system is the CPU, usually there is only one.
Linux is a multiprocessing operating system, its objective is to have a process
running on each CPU in the system at all times, to maximize CPU utilization. If
there are more processes than CPUs (and there usually are), the rest of the
processes must wait before a CPU becomes free until they can be run.
Multiprocessing is a simple idea; a process is executed until it must wait, 
usually for some system resource; when it has this resource, it may run again.
In a uniprocessing system, for example DOS, the CPU would simply sit idle and 
the waiting time would be wasted. In a multiprocessing system many processes 
are kept in memory at the same time. Whenever a process has to wait the 
operating system takes the CPU away from that process and gives it to another,
more deserving process. It is the scheduler which chooses which is the most
appropriate process to run next and Linux uses a number of scheduling 
strategies to ensure fairness. 
-->
<p>システムの最も貴重なリソースは、CPU である。それは通常ひとつしかない。
Linux はマルチプロセス(multiprocessing)のオペレーティングシステムであり、
その目標は、ひとつのプロセスをシステムの個別の CPU 上で常時走らせて、CPU の
使用効率を最大限に上げることである。
もしプロセスの数が CPU の数を上回る場合(通常はそうである)、残りのプロセスは、
プロセスの実行が終わって CPU が空くまで待たなければならない。
マルチプロセッシングのアイデアは単純である。プロセスが実行されると、通常何らか
のシステムリソースのために待ち状態となり、リソースが得られると実行を再開する。
DOS のような単一プロセス(uniprocessing)のシステムでは、CPU はその間、単に待って
いるだけで、待ち時間は無駄になる。マルチプロセッシングシステムでは、多くの
プロセスが同時にメモリに保持されている。プロセスに待ち時間が生じたとき、
オペレーティングシステムはそのプロセスから CPU を取り上げて、より優先すべき
他のプロセスにそれを与える。次に実行するプロセスとしてどれが最も適切かを決定
するのがスケジューラ(scheduler)であり、Linux は、公平を期すためにいくつかの
スケジューリングの戦略を使っている。

<!--
Linux supports a number of different executable file formats, ELF is one, Java
is another and these must be managed transparently as must the processes use of
the system's shared libraries. 
-->
<p>Linux は、多くの実行ファイルフォーマットをサポートしている。ELF はその
ひとつであり、Java もそうである。プロセスがシステムの共有ライブラリを透過的
に扱えるようにしなければならないのと同様に、それらのファイルフォーマットも
透過的に扱われるよう管理されなければならない。

<!--4.1  Linux Processes-->
<sect1>Linux のプロセス<label id="chapter_p_sect1">

<!--
So that Linux can manage the processes in the system, each process is
represented by a task_struct data structure (task and process are terms that
Linux uses interchangeably). The task vector is an array of pointers to every
task_struct data structure in the system. This means that the maximum number 
of processes in the system is limited by the size of the task vector; by 
default it has 512 entries. As processes are created, a new task_struct is 
allocated from system memory and added into the task vector. To make it easy 
to find, the current, running, process is pointed to by the current pointer. 
-->
<p>Linux がシステム上のプロセスを管理できるようにするため、個々のプロセスは、
<tt><ref id="task_struct" name="task_struct"></tt> というデータ構造体で表現さ
れる。(task と process という用語は、Linux では同義として使われている。) 
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/sched.h"
name="include/linux/sched.h">]<newline>
その <tt><ref id="task" name="task"></tt> 配列は、システム上の
すべての <tt>task_struct</tt> データ構造に対するポインタの配列である。このこと
が意味するのは、システム上のプロセスの最大数がその <tt>task</tt> 配列のサイズに
よって制限されるということである。デフォルトでは、それは 512 のエントリを持つ。
プロセスが生成されると、新しい <tt>task_struct</tt> がシステムメモリに
割り当てられ、<tt>task</tt> 配列に追加される。発見を容易にするために、
現在実行中のプロセスは、<tt><ref id="task" name="current"></tt> ポインタ
によってポイントされている。


<!--
As well as the normal type of process, Linux supports real time processes. 
These processes have to react very quickly to external events (hence the 
term ``real time'') and they are treated differently from normal user 
processes by the scheduler. Although the task_struct data structure is quite 
large and complex, but its fields can be divided into a number of functional 
areas: 
-->
<p>通常タイプのプロセスだけでなく、Linux ではリアルタイムプロセス(real time 
process)もサポートしている。そうしたプロセスは外界イベントに即座に反応しなけ
ればならない(したがって、「リアルタイム」という用語が使われる)ので、
スケジューラからは通常のユーザプロセスとは異なる扱いを受ける。
<tt><ref id="task_struct" name="task_struct"></tt> のデータ構造体は極めて巨大
で複雑だが、そのフィールドはいくつかの機能別エリアに分けることができる。

<!--
State As a process executes it changes state according to its circumstances.
      Linux processes have the following states: 1 
      Running
            The process is either running (it is the current process in the
            system) or it is ready to run (it is waiting to be assigned to one
            of the system's CPUs). 
      Waiting
            The process is waiting for an event or for a resource. Linux
            differentiates between two types of waiting process; interruptible
            and uninterruptible. Interruptible waiting processes can be
            interrupted by signals whereas uninterruptible waiting processes
            are waiting directly on hardware conditions and cannot be
            interrupted under any circumstances. 
      Stopped
            The process has been stopped, usually by receiving a signal. A
            process that is being debugged can be in a stopped state. 
      Zombie
            This is a halted process which, for some reason, still has a
            task_struct data structure in the task vector. It is what it
            sounds like, a dead process. 
-->
<descrip>
<tag>状態(State)</tag>
プロセスは、実行中に、環境に応じて状態を変化させる。Linux のプロセスは次のよ
うな状態(state)を取る。(<ref id="chapter_p_fn1" name="脚注1">)
<descrip>

<p><tag>実行中(Running)</tag>
この状態のプロセスは、走行中(システム上で現在走行中のプロセス)か、直ぐに走行
できる(システム上の CPU の割り当てを待っている状態)かのいずれかである。

<p><tag>待機中(Waiting)</tag>
この状態のプロセスは、イベントかリソースを待っている状態である。Linux は、
待機状態のプロセスを割り込み可能(interruptible)か割り込み不可
(uninterruptible)かどうかで区別する。割り込み可能な待機中の
プロセスとはシグナルによって割り込みを掛け得るものであり、割り込み不可な待機
中のプロセスとは、直接ハードウェアの状態に依存するかたちで待機しているので、
どのような状況でも割り込みを掛けられないものをいう。

<p><tag>停止中(Stopped)</tag>
この状態のプロセスは、通常はシグナルを受信したことで停止状態にある。デバッグ
中のプロセスは、停止状態に置くことが可能である。

<p><tag>ゾンビ(Zombie)</tag>
これは終了したプロセスだが、何らかの理由で、<tt><ref id="task" name="task">
</tt> 配列内に <tt><ref id="task_struct" name="task_struct"></tt> 構造体を
まだ持っているものである。これは、その名の通り、既に死んでいるプロセスである。
</descrip>

<!--
Scheduling Information
      The scheduler needs this information in order to fairly decide which
      process in the system most deserves to run, 
-->
<tag>スケジューリング情報(Scheduling Information)</tag>
スケジューラ(scheduler)は、どのプロセスをシステム内で最も優先的に実行すべきか
公平に判断するために、この情報を必要とする。

<!--
Identifiers
      Every process in the system has a process identifier. The process
      identifier is not an index into the task vector, it is simply a number. 
      Each process also has User and group identifiers, these are used to 
      control this processes access to the files and devices in the system, 
-->
<tag>識別子(Identifiers)</tag>
システム内のすべてのプロセスはプロセス識別子を持つ。プロセス識別子は、<tt>task
</tt> 配列へのインデックスではなく、単なる番号である。また個々のプロセスは
ユーザ ID およびグループ ID も持ち、それらの識別子はシステムのファイルやデバイ
スに対するこのプロセスのアクセス制御のために使用される。

<!--
Inter-Process Communication
      Linux supports the classic Unix TM IPC mechanisms of signals, pipes and
      semaphores and also the System V IPC mechanisms of shared memory,
      semaphores and message queues. The IPC mechanisms supported by
      Linux are described in Chapter  IPC-chapter. 
-->
<tag>プロセス間通信(Inter-Process Communication, IPC)</tag>
Linux は、シグナル、パイプ、セマフォという古典的な Unix IPC メカニズムを
サポートすると同時に、共有メモリ、セマフォ、メッセージキューといった System V 
IPC メカニズムもサポートしている。Linux でサポートされている IPC のメカニズム
については、<ref id="chapter_ipc" name="「プロセス間通信の仕組み」">の章で
解説する。

<!--
Links In a Linux system no process is independent of any other process. Every
      process in the system, except the initial process has a parent process.
      New processes are not created, they are copied, or rather cloned from
      previous processes. Every task_struct representing a process keeps
      pointers to its parent process and to its siblings (those processes with
      the same parent process) as well as to its own child processes. You can 
      see the family relationship between the running processes in a Linux 
      system using the pstree command: 
-->
<tag>リンク(Links)</tag>
Linux システムでは、他のプロセスから完全に独立したプロセスは存在しない。シス
テム上のすべてのプロセスは、初期化プロセスを除いて、親プロセス(parent 
process)を持つ。新しいプロセスは創造されるのではなく、コピーされるのであり、
むしろ以前のプロセスのクローンとして生まれるのである。プロセスを表現する <tt>
<ref id="task_struct" name="task_struct"></tt> 構造体はすべて、自分の子プロセス
(child process)へのポインタを保持すると同時に、その親プロセスと兄弟プロセス
(siblings)(同じ親プロセスを持つプロセス)へのポインタを保持している。
<tt>pstree</tt> コマンドを使えば、Linux システム上で実行中のプロセス間の家族
関係を見ることができる。

<verb>
init(1)-+-crond(98)
        |-emacs(387)
        |-gpm(146)
        |-inetd(110)
        |-kerneld(18)
        |-kflushd(2)
        |-klogd(87)
        |-kswapd(3)
        |-login(160)---bash(192)---emacs(225)
        |-lpd(121)
        |-mingetty(161)
        |-mingetty(162)
        |-mingetty(163)
        |-mingetty(164)
        |-login(403)---bash(404)---pstree(594)
        |-sendmail(134)
        |-syslogd(78)
        `-update(166)
</verb>
<!--
      Additionally all of the processes in the system are held in a doubly 
      linked list whose root is the init processes task_struct data structure.
      This list allows the Linux kernel to look at every process in the 
      system. It needs to do this to provide support for commands such as ps 
      or kill. 
-->
さらに、システム内のあらゆるプロセスは、二重連結リストの中に保持されていて、
そのリストのルートは、<tt>init</tt> プロセスの <tt>task_struct</tt> 構造体
となっている。このリストがあることで、Linux カーネルはシステム上のすべての
プロセスを見ることができる。<tt>ps</tt> や <tt>kill</tt> といったコマンドを
サポートするために、カーネルにはこの機能が必要である。

<!--Times and Timers-->
<tag>時間とタイマー</tag>
<!--
      The kernel keeps track of a processes creation time as well as the CPU
      time that it consumes during its lifetime. Each clock tick, the kernel
      updates the amount of time in jiffies that the current process has spent
      in system and in user mode. Linux also supports process specific interval
      timers, processes can use system calls to set up timers to send signals 
      to themselves when the timers expire. These timers can be single-shot or
      periodic timers. 
-->
<p>カーネルは、プロセスが生成された時間と、プロセスの生存時間内での CPU 使用
時間とを監視している。クロックティック(<ref id="clock_tick" name="clock tick">)
ごとに、カーネルは、走行中のプロセスのシステムモードおよびユーザモードでの経過
時間を変数 <tt><ref id="task" name="jiffies"></tt> 
の値を使って更新する。また、Linux は
プロセス固有のインターバルタイマー(interval timer)もサポートしているので、
プロセスはシステムコールを利用してタイマーをセットし、所定時間が経過すると
自分自身にシグナルを送るように設定することもできる。そうしたタイマーは、
一回だけ使うことも定期的に使用することもできる。

<!--File system-->
<tag>ファイルシステム (File system)</tag>
<!--
      Processes can open and close files as they wish and the processes
      task_struct contains pointers to descriptors for each open file as well
      as pointers to two VFS inodes. Each VFS inode uniquely describes a file
      or directory within a file system and also provides a uniform interface 
      to the underlying file systems. How file systems are supported under 
      Linux is described in Chapter  filesystem-chapter. The first is to the 
      root of the process (its home directory) and the second is to its 
      current or pwd directory. pwd is derived from the Unix TM command pwd, 
      print working directory. These two VFS inodes have their count fields 
      incremented to show that one or more processes are referencing them. 
      This is why you cannot delete the directory that a process has as its 
      pwd directory set to, or for that matter one of its sub-directories. 
-->
<p>プロセスは、好きなときにファイルのオープンやクローズができる。プロセスの 
<tt><ref id="task_struct" name="task_struct"></tt> 構造体には、オープンされた
それぞれのファイルのディスクリプタに対するポインタと、ふたつの VFS inode に対
するポインタが含まれている。
個々の VFS inode はファイルシステム内のファイルかディレクトリをユニークに記述
するもので、基盤となるファイルシステムに対する統一的なインターフェイスを提供
するものである。
Linux 上でファイルシステムがどのようにサポートされているかは、
<ref id="chapter_fs" name="「ファイルシステム」">の章で述べられている。
最初の VFS inode はプロセスのルート(そのホームディレクト
リ)に対するものであり、二番目の VFS inode はカレント(もしくは pwd )
ディレクトリに対するもの
である。ここで pwd という呼び方は、Unix のコマンド <tt>pwd</tt> (print working 
directory)に由来するものである。これらふたつの VFS inode は、それぞれの <tt>
<ref id="inode" name="count"></tt>フィールドを増加させて、ひとつ以上のプロセ
スがそのディレクトリを参照中であることを示す。それゆえ、あるプロセスが pwd 
ディレクトリとしてセットしているディレクトリは削除できず、同様にそのサブディ
レクトリも削除できないということが起こる。

<!--Virtual memory-->
<tag>仮想メモリ (Virtual memory)</tag>
<!--
      Most processes have some virtual memory (kernel threads and daemons
      do not) and the Linux kernel must track how that virtual memory is mapped
      onto the system's physical memory. 
-->
<p>大部分のプロセスは、何らかの仮想メモリを持っている。(カーネルスレッド
(kernel threads)とデーモン(daemons)はそうではない。) そして、Linux カーネル
は、そうした仮想メモリがどのようにシステムの物理メモリにマップされているのか
を常に監視しなければならない。

<!--Processor Specific Context--><label id="chapter_p_context">
<tag>プロセッサ固有のコンテキスト (Processor Specific Context)</tag>
<!--
      A process could be thought of as the sum total of the system's current
      state. Whenever a process is running it is using the processor's 
      registers, stacks and so on. This is the processes context and, when a 
      process is suspended, all of that CPU specific context must be saved in 
      the task_struct for the process. When a process is restarted by the
      scheduler its context is restored from here. 
-->
<p>プロセスとは、現在のシステム状態(system state)の総体であると考えることがで
きる。プロセスの走行中には、プロセッサのレジスタやスタック等が使用されている。
これはプロセスのコンテキスト(context)であり、プロセスがサスペンドされたときに
は、その CPU 固有の全コンテキストが、 プロセスの <tt><ref id="task_struct" 
name="task_struct"></tt> 構造体に保存される。プロセスがスケジューラにより再
始動されたときは、そのコンテキストが <tt>task_struct</tt> データ構造体から
回復される。
</descrip>

<!--4.2  Identifiers-->
<sect1>識別子(identifiers)<label id="chapter_p_sect2">

<!--
Linux, like all Unix TM uses user and group identifiers to check for access 
rights to files and images in the system. All of the files in a Linux system 
have ownerships and permissions, these permissions describe what access the 
system's users have to that file or directory. Basic permissions are read, 
write and execute and are assigned to three classes of user; the owner of the 
file, processes belonging to a particular group and all of the processes in 
the system. Each class of user can have different permissions, for example a 
file could have permissions which allow its owner to read and write it, the 
file's group to read it and for all other processes in the system to have no 
access at all. 
-->
<p>Linux は、他のすべての Unix と同様に、ユーザ ID とグループ ID を使用して
システム上のファイルやイメージへのアクセス権をチェックする。Linux システム上の
すべてのファイルは、所有者とパーミッションとを持っていて、そのパーミッション
によってシステム上のユーザが該当するファイルやディレクトリに対してどのような
アクセス権を持つのかを記述している。基本的なパーミッションには、読み出し
(read)、書き込み(write)、実行(execute)があり、それらがユーザの 3 つのクラス、
すなわちファイル所有者、特定のグループの属するプロセス、およびシステム上のす
べてのプロセスというクラスごとに割り当てられている。それぞれのユーザのクラスが
異なるパーミッションを持つということが可能である。たとえば、所有者には書き込み
と読み出しが可能なファイルでも、そのファイルのグループには読み出しのみが可能
であり、システム上の他のすべてのプロセスではまったくアクセスできないという
設定が可能である。

<!--
REVIEW NOTE: Expand and give the bit assignments (777). 
-->
REVIEW NOTE: この部分を詳しくして、ビット割り当てについて説明すること。(777)


<!--
Groups are Linux's way of assigning privileges to files and directories for a 
group of users rather than to a single user or to all processes in the system.
You might, for example, create a group for all of the users in a software 
project and arrange it so that only they could read and write the source code 
for the project. A process can belong to several groups (a maximum of 32 is 
the default) and these are held in the groups vector in the task_struct for 
each process. So long as a file has access rights for one of the groups that 
a process belongs to then that process will have appropriate group access 
rights to that file. 
-->
<p>個人ユーザやシステム上のすべてのプロセスに対して、ファイルやディレクトリへ
のアクセス権権を与えるのではなく、ユーザグループ単位でそれらの権限を割り当て
るのが Linux の流儀である。たとえば、あるソフトウェアプロジェクトに参加した
ユーザ全員のグループを作成し、そのプロジェクトのソースコードに対してその
グループだけが読み書きできるように権限を割り当てることができる。ひとつの
プロセスが複数のグループに属することも可能であり(デフォルトで最大 32 グループ
)、それらの情報は、プロセスごとの <tt><ref id="task_struct" name="task_struct">
</tt> 構造体の <tt>groups</tt> 配列に保持される。あるプロセスが複数のグループ
に属していて、そのうちひとつのグループがファイルへのアクセス権をもっている
場合、そのプロセスは当該ファイルへの適切なグループアクセス権を持つことになる。

<!--
There are four pairs of process and group identifiers held in a processes
task_struct: 
-->
<p>プロセスの <tt><ref id="task_struct" name="task_struct"></tt> 構造体には、
プロセスとグループの識別子に関する 4 組の情報がある。

<descrip>
<!--
uid, gid The user identifier and group identifier of the user that the 
         process is running on behalf of, 
-->
<tag><tt>uid と gid</tt></tag>
実行中のプロセスを代表するユーザ識別子(User ID)とグループ識別子(Group ID)。

<!--
effective uid and gid
      There are some programs which change the uid and gid from that of the
      executing process into their own (held as attributes in the VFS inode
      describing the executable image). These programs are known as setuid
      programs and they are useful because it is a way of restricting accesses
      to services, particularly those that run on behalf of someone else, for
      example a network daemon. The effective uid and gid are those from the
      setuid program and the uid and gid remain as they were. The kernel checks
      the effective uid and gid whenever it checks for privilege rights. 
-->
<tag><tt>実効(effective) uid と gid</tt></tag>
プログラムのなかには、実行プロセスの <tt>uid</tt> と <tt>gid</tt> をプログラム
自体の <tt>uid</tt> と <tt>gid</tt> に変更するものがある。(実行イメージ自体の 
<tt>uid</tt> と <tt>gid</tt> は、VFS inode の属性値として保持されている。)
そうしたプログラムは、<tt>setuid</tt> プログラムと呼ばれていて、アクセス制限、
特に個別のユーザを持たずに実行されるネットワークデーモンのようなサービスへの
アクセスを制限するひとつの方法として有益なものである。
実効 <tt>uid</tt> と <tt>gid</tt> とは、<tt>setuid</tt> プログラムの <tt>
uid</tt> と <tt>gid</tt> が使用され、実(real) <tt>uid</tt> と <tt>gid</tt> も
元のまま残される。カーネルが権限のチェックをする
ときはいつも、実効 <tt>uid</tt> と <tt>gid</tt> をチェックする。

<!--
file system uid and gid
      These are normally the same as the effective uid and gid and are used
      when checking file system access rights. They are needed for NFS
      mounted filesystems where the user mode NFS server needs to access
      files as if it were a particular process. In this case only the file 
      system uid and gid are changed (not the effective uid and gid). This 
      avoids a situation where malicious users could send a kill signal to 
      the NFS server. Kill signals are delivered to processes with a 
      particular effective uid and gid. 
-->
<tag><tt>ファイルシステムの uid と gid</tt></tag>
これらは通常、実効 <tt>uid</tt> や <tt>gid</tt> と同じであり、ファイルシステム
へのアクセス権限をチェックする際に使用される。これらは、NFS でマウントされた
ファイルシステムにとって必要なものである。ユーザモードの NFS サーバは、あたかも
それ自身がある特定のプロセスであるかのようにファイルにアクセスする必要があるか
らである。
その場合、(実効 <tt>uid</tt> と <tt>gid</tt> ではなく)ファイルシステムの 
<tt>uid</tt> と <tt>gid</tt> だけが変更される。これは、悪意のあるユーザが NFS 
サーバに <tt>kill</tt> シグナルを送ることができるという状態を避けるためである。
それゆえ、<tt>kill</tt> シグナルは、特定の実効 <tt>uid</tt> および <tt>gid</tt> 
を持つプロセスに配信される。

<!--
saved uid and gid
      These are mandated by the POSIX standard and are used by programs
      which change the processes uid and gid via system calls. They are used to
      save the real uid and gid during the time that the original uid and gid 
      have been changed. 
-->
<tag><tt>保存された uid と gid</tt></tag>
これらは、POSIX 規格で義務付けられており、システムコール経由でプロセスの <tt>
uid</tt> と <tt>gid</tt> を変更するプログラムによって利用される。それらは、実 
<tt>uid</tt> と <tt>gid</tt> が変更されている間、そのオリジナルな <tt>uid</tt> 
と <tt>gid</tt> を保存するために使用される。
</descrip>

<!--4.3  Scheduling-->
<sect1>スケジューリング<label id="chapter_p_sect3">

<!--
All processes run partially in user mode and partially in system mode. How 
these modes are supported by the underlying hardware differs but generally 
there is a secure mechanism for getting from user mode into system mode and 
back again. User mode has far less privileges than system mode. Each time a 
process makes a system call it swaps from user mode to system mode and 
continues executing. At this point the kernel is executing on behalf of the 
process. In Linux, processes do not preempt the current, running process, they
cannot stop it from running so that they can run. Each process decides to 
relinquish the CPU that it is running on when it has to wait for some system 
event. For example, a process may have to wait for a character to be read from
a file. This waiting happens within the system call, in system mode; the 
process used a library function to open and read the file and it, in turn made
system calls to read bytes from the open file. In this case the waiting 
process will be suspended and another, more deserving process will be chosen 
to run. 
-->
<p>すべてのプロセスは、ある時はユーザモードで、ある時はシステムモードで走行
する。基礎になるハードウェアがそれらのモードをサポートする方法はハードウェア
によって異なるが、一般的には、ユーザモードからシステムモードへの移行および
その逆に移行する場合の安全なメカニズムというものが存在する。ユーザモードは
システムモードよりもずっと限られた特権しか持たない。プロセスはシステムコール
を実行するたびに、ユーザモードからシステムモードに移行して実行を継続する。
このとき、カーネルはそのプロセスを代表して実行を行う。
Linux では、プロセスは、現在走行
中のプロセスを横取り(preempt)しない。自分が実行されるために走行中のプロセスを
止めることはできない。プロセスは、自分が何らかのシステムイベントを待たなけれ
ばならないとき、使用中の CPU を放棄するかどうかを決める。たとえば、あるプロセス
は、ファイルから一文字読み出されるまで待たなければならないかもしれない。
この待機状態は、システムモードにおけるシステムコールによって起こる。
すなわち、プロセスは、ファイルの open や read のためにライブラリ関数を使用し、
次にそのライブラリ関数がシステムコールを発して open されたファイルから
バイト列を read する。この場合、待機中のプロセスはサスペンドされ、その間に
他のより優先度の高いプロセスが選ばれて実行される。

<!--
Processes are always making system calls and so may often need to wait. Even
so, if a process executes until it waits then it still might use a 
disproportionate amount of CPU time and so Linux uses pre-emptive scheduling. 
In this scheme, each process is allowed to run for a small amount of time, 
200ms, and, when this time has expired another process is selected to run and 
the original process is made to wait for a little while until it can run 
again. This small amount of time is known as a time-slice. 
-->
<p>プロセスは終始システムコールを実行するので、しばしば待機する必要が生じる。
その場合でも、もしプロセスが待機状態になるまで実行され続けるとすると、その
プロセスはやはり不公平な CPU 時間を消費していることになり、したがって Linux は
横取り可能(pre-emptive)なスケジューリングを使わざるを得なくなるだろう。
実際の仕組みでは、個々のプロセスは 200ms の短い時間走行を許され、その時間が経過
すると次のプロセスが選ばれて実行され、もとのプロセスは再度実行が可能になるまで
しばらく待たされる。この短い時間間隔は、タイムスライス(time-slice)と呼ばれる。

<!--
It is the scheduler that must select the most deserving process to run out of 
all of the runnable processes in the system. 
A runnable process is one which is waiting only for a CPU to run on. Linux 
uses a reasonably simple priority based scheduling algorithm to choose between
the current processes in the system. When it has chosen a new process to run it
saves the state of the current process, the processor specific registers and 
other context being saved in the processes task_struct data structure. It then
restores the state of the new process (again this is processor specific) to 
run and gives control of the system to that process. For the scheduler to 
fairly allocate CPU time between the runnable processes in the system it keeps
information in the task_struct for each process: 
-->
<p>システム上の実行可能なすべてのプロセスの中から最も優先するプロセスを選んで
実行させる役割を担うのがスケジューラ(scheduler)である。
<newline>[see: shedule(), in 
<htmlurl url="The-Linux-Kernel-images/linux/kernel/sched.c"
name="kernel/sched.c">]<newline>
実行可能なプロセスとは、CPU が空きさえすれば直ぐに走行可能なプロセスである。
Linux は、優先度(priority)ベースの適度にシンプルなスケジューリングアルゴリズ
ムを使ってシステム上の走行プロセスを選択している。新しいプロセスを選んで実行
するとき、Linux は、まず現在実行中のプロセスの状態(state)、すなわちプロセッサ
固有のレジスタ内容、およびプロセスの 
<tt><ref id="task_struct" name="task_struct"></tt> データ構造体に保持さ
れたその他のコンテキストを保存する。そして、新しいプロセスの状態(これもプロ
セッサ固有のものである)を復元して実行し、システムの制御をそのプロセスに渡す。
スケジューラがシステム上の実行可能なプロセスに対して公平に CPU 時間を割り当てる
ために、Linux は個々のプロセスの <tt>task_struct</tt> 構造体内の情報を保持して
いる。その情報とは次のようなものである。

<descrip>
<!--
policy This is the scheduling policy that will be applied to this process. 
      There are two types of Linux process, normal and real time. Real time 
      processes have a higher priority than all of the other processes. If 
      there is a real time process ready to run, it will always run first. 
      Real time processes may have two types of policy, round robin and first 
      in first out. In round robin scheduling, each runnable real time process
      is run in turn and in first in, first out scheduling each runnable 
      process is run in the order that it is in on the run queue and that 
      order is never changed. 
-->
<tag><tt>ポリシー (policy)</tt></tag>
これは、該当プロセスに適用されるスケジューリングポリシーである。Linux のプロ
セスには、ノーマルとリアルタイムのふたつのタイプがある。リアルタイムプロセス
は、他のどのプロセスよりも高い優先度を持つ。実行可能なリアルタイムプロセスが
ある場合、まずそれが常に実行される。リアルタイムプロセスは、ラウンドロビン
(round robin)と先入れ先出し(first in first out)というふたつのタイプのポリシー
を持ち得る。ラウンドロビンスケジューリングでは、個々の実行可能なリアルタイム
プロセスは順番に実行されるが、先入れ先出しスケジューリングでは、個々のプロセ
スは実行キューに置かれた順序で実行され、その順番は絶対に変更されない。

<!--
priority This is the priority that the scheduler will give to this process. It
      is also the amount of time (in jiffies) that this process will run for 
      when it is allowed to run. You can alter the priority of a process by 
      means of system calls and the renice command. 
-->
<tag><tt>優先度 (priority)</tt></tag>
これは、該当するプロセスに対してスケジューラが与える優先度である。これは、
実行を許された時に、そのプロセスが走行可能な
(<tt><ref id="clock_tick" name="jiffies"></tt> 値で表された)時間間隔でもあ
る。システムコールや <tt>renice</tt> コマンドを使用すれば、プロセスの優先度
を変更することができる。

<!--
rt_priority
      Linux supports real time processes and these are scheduled to have a
      higher priority than all of the other non-real time processes in system.
      This field allows the scheduler to give each real time process a relative
      priority. The priority of a real time processes can be altered using 
      system calls. 
-->
<tag><tt>リアルタイムプロセスの優先順位 (rt_priority)</tt></tag>
Linux はリアルタイムプロセスをサポートしており、それらはシステム上の他のどの非
リアルタイムプロセスよりも高い優先順位でスケジューリングされる。このフィールド
は、スケジューラによる個々のリアルタイムプロセスに対する相対的な優先順位の付与
を可能にするものである。リアルタイムプロセスの優先順位は、システムコールを
使用すれば変更できる。

<!--
counter
      This is the amount of time (in jiffies) that this process is allowed to
      run for. It is set to priority when the process is first run and is
      decremented each clock tick. 
-->
<tag><tt>カウンタ (counter)</tt></tag>
これは、当該プロセスが実行を許可される
(<tt><ref id="clock_tick" name="jiffies"></tt> 値で表された)時間間隔である。
これはプロセスが初めて実行される時に <tt>priority</tt> に対して設定され、
クロックティックごとに減少していく。

</descrip>

<!--
The scheduler is run from several places within the kernel. It is run after 
putting the current process onto a wait queue and it may also be run at the 
end of a system call, just before a process is returned to process mode from 
system mode. One reason that it might need to run is because the system timer 
has just set the current processes counter to zero. Each time the scheduler is
run it does the following: 
-->
<p>スケジューラは、カーネル内のいろいろな場所から実行される。それは現在走行中
のプロセスを待ち行列に入れたあとに実行され、またシステムコールが終了してプロ
セスがシステムモードからプロセスモードに戻る直前にも実行されるときがある。
スケジューラの実行が必要とされる理由は、システムタイマーがカレントプロセスの
カウンター(counter)をその時にゼロにセットするからである。<newline>
[see: schedule(), in <htmlurl 
url="The-Linux-Kernel-images/linux/kernel/sched.c" 
name="kernle/sched.c">]<newline>
スケジューラが実行されると、それは次のようなことをする。

<descrip>
<!--
kernel work
      The scheduler runs the bottom half handlers and processes the scheduler
      task queue. These lightweight kernel threads are described in detail in
      chapter  kernel-chapter. 
-->
<tag><tt>カーネルワーク(kernel work)</tt></tag>
スケジューラは、ボトムハーフハンドラ(bottom half handlers)を実行し、
スケジューラのタスクキューを処理する。これらのライトウェイトカーネルスレッド
(lightweight kernel threads)の詳細は、<ref id="chapter_km" 
name="「カーネルメカニズム」">の章で解説する。

<!--
Current process
      The current process must be processed before another process can be
      selected to run. 

      If the scheduling policy of the current processes is round robin then it
      is put onto the back of the run queue. 

      If the task is INTERRUPTIBLE and it has received a signal since the last
      time it was scheduled then its state becomes RUNNING. 

      If the current process has timed out, then its state becomes RUNNING. 

      If the current process is RUNNING then it will remain in that state. 

      Processes that were neither RUNNING nor INTERRUPTIBLE are removed
      from the run queue. This means that they will not be considered for 
      running when the scheduler looks for the most deserving process to run. 
-->
<tag><tt>カレントプロセス (Current process)</tt></tag>
次のプロセスを選んで実行する前に、現在走行中のプロセス(current process)が処理
されなければならない。
<p>走行中のプロセスのスケジューリングポリシーがラウンドロビンなら、そのプロセス
は実行キューの最後に置かれる。
<p>タスクが割り込み可能(INTERRUPTIBLE)で、最後にスケジューリングされてから
プロセスがシグナルを受け取っている場合、そのプロセスの <tt>
<ref id="task_struct" name="task_struct"></tt> の <tt>state</tt>が、走行中
(RUNNING)となる。
<p>現在走行中のプロセスが時間切れになった場合、その <tt>state</tt> は走行中
(RUNNING)となる。
<p>現在走行中のプロセスの <tt>state</tt> が走行中(RUNNING)の場合、その <tt>
state</tt> がそのまま維持される。
<p>走行中(RUNNING)でも割り込み可能(INTERRUPTIBLE)でもないプロセスは実行キュー
から削除される。すなわち、スケジューラが実行すべき最も優先度の高いプロセスを
探しているとき、それらは実行の対象とは見なされないということを意味する。

<!--
Process selection
      The scheduler looks through the processes on the run queue looking for 
      the most deserving process to run. If there are any real time processes 
      (those with a real time scheduling policy) then those will get a higher 
      weighting than ordinary processes. The weight for a normal process is 
      its counter but for a real time process it is counter plus 1000. 
      This means that if there are any runnable real time processes in the 
      system then these will always be run before any normal runnable 
      processes. The current process, which has consumed some of its 
      time-slice (its counter has been decremented) is at a disadvantage if 
      there are other processes with equal priority in the system; that is as 
      it should be. If several processes have the same priority, the one 
      nearest the front of the run queue is chosen. The current process will 
      get put onto the back of the run queue. In a balanced system with many 
      processes of the same priority, each one will run in turn.
      This is known as Round Robin scheduling. However, as processes wait for
      resources, their run order tends to get moved around. 
-->
<tag><tt>プロセス選択 (process selection)</tt></tag>
スケジューラは、実行キュー上のプロセスを見渡して、実行に最も値するプロセスを
探す。もしリアルタイムプロセスがあれば(それらはリアルタイムスケジューリング
ポリシーを持つ)、それらは通常のプロセスよりも重視される。通常のプロセスの
重要性はその <tt>counter</tt> で決まるが、リアルタイムプロセスに関してはその
 <tt>counter</tt> 値に 1000 が付加される。すなわち、システム内に実行可能な
リアルタイムプロセスがある場合、通常の実行可能などんなプロセスよりも必ず先に
実行されるということである。
現在走行中のプロセスは、タイムスライスの一部を消費してしまっている(プロセスの
 <tt>counter</tt> 値が減少している)ので、システム上の同じ優先度を持つプロセス
よりも不利な立場に立つ。それは当然そうなるべきである。多くのプロセスが
同一の優先順位を持つ場合、実行キューの先頭に最も近いものが選択される。現在の
プロセスは実行キューの最後に戻される。同一の優先順位にある多数のプロセス間で
システムのバランスを保つため、個々のプロセスは順番に実行される。これはラウン
ドロビンスケジューリングと呼ばれる。しかし、プロセスはリソースの取得を待つ
場合があるので、実行の順番は前後する傾向がある。

<!--
Swap processes
      If the most deserving process to run is not the current process, then the
      current process must be suspended and the new one made to run. When a
      process is running it is using the registers and physical memory of the
      CPU and of the system. Each time it calls a routine it passes its
      arguments in registers and may stack saved values such as the address to
      return to in the calling routine. So, when the scheduler is running it is
      running in the context of the current process. It will be in a privileged
      mode, kernel mode, but it is still the current process that is running. 
      When that process comes to be suspended, all of its machine state, 
      including the program counter (PC) and all of the processor's registers,
      must be saved in the processes task_struct data structure. Then, all of 
      the machine state for the new process must be loaded. This is a system 
      dependent operation, no CPUs do this in quite the same way but there is 
      usually some hardware assistance for this act. 
-->
<tag><tt>スワッププロセス (swap process)</tt></tag>
最優先で実行されるべきプロセスが現在のプロセスとは異なる場合、現在のプロセスは
停止状態にされ、新しいプロセスが実行される。プロセスは実行中に CPU やシステム
のレジスタや物理メモリを使用している。ルーチンをコールするたびに、プロセスは
レジスタ内の引数をルーチンに渡しているし、呼び出したルーチンから戻されるアドレ
ス等の保存すべき値をスタックに積む場合もある。
それゆえ、スケジューラが実行されている際、スケジューラはカレントプロセスの
コンテキスト(<ref id="chapter_p_context" name="context">)で実行される。
スケジューラは特権モードであるカーネルモードで動作しているのだが、
それでも実行されているのは、カレントプロセスである。
そのプロセスが停止されるべきときは、プログラムカウンタやすべてのプロセッサの
レジスタを含むそのマシンの状態(machine state)全体が、プロセスの <tt><ref 
id="task_struct" name="task_struct"></tt> データ構造体に保存されなければなら
ない。その後で、新しいプロセスのマシンの状態すべてがロードされる。
これはシステムに依存する操作であり、まったく同じ方法で動作する CPU はないのだ
が、この処理に対しては通常なんらかのハードウェアによる援助がなされる。

<!--
      This swapping of process context takes place at the end of the scheduler.
      The saved context for the previous process is, therefore, a snapshot of 
      the hardware context of the system as it was for this process at the end
      of the scheduler. Equally, when the context of the new process is 
      loaded, it too will be a snapshot of the way things were at the end of 
      the scheduler, including this processes program counter and register 
      contents. 
-->
この(新旧両プロセス間での)プロセスコンテキストの入れ替え(swapping)は、スケ
ジューラの処理の一番最後で実行される。直前のプロセスのために保存されたコンテキ
ストは、スケジューラの終わりの時点でのそのプロセスが所持した、システムのハード
ウェアコンテキストに関するスナップショットである。
同様に、新しいプロセスのコンテキストがロードされる時、それもまたスケジューラの
最後の時点におけるそのプロセスのスナップショットであり、それには、プロセスの
プログラムカウンタやレジスタの内容などが含まれている。

<!--
      If the previous process or the new current process uses virtual memory
      then the system's page table entries may need to be updated. Again, this
      action is architecture specific. Processors like the Alpha AXP, which use
      Translation Look-aside Tables or cached Page Table Entries, must flush
      those cached table entries that belonged to the previous process. 
-->
直前のプロセスや新しいプロセスが仮想メモリを使用する場合、システムのページ
テーブルエントリはアップデートされる必要がある。これもまたアーキテクチャ固有の
処理である。Alpha AXP のようなプロセッサの場合、アドレス変換バッファか
キャッシュされたページテーブルエントリを使用するので、直前のプロセスに属する
それらのキャッシュテーブルのエントリを無効にする必要がある。

</descrip>

<!--4.3.1  Scheduling in Multiprocessor Systems-->
<sect2>マルチプロセッサシステムでのスケジューリング

<!--
Systems with multiple CPUs are reasonably rare in the Linux world but a lot of
work has already gone into making Linux an SMP (Symmetric Multi-Processing)
operating system. That is, one that is capable of evenly balancing work between
the CPUs in the system. Nowhere is this balancing of work more apparent than in
the scheduler. 
-->
<p>複数の CPU を持つシステムは Linux の世界ではそれほど多くはないが、Linux を
 SMP(Symmetric Multi-Processing)対応のオペレーティングシステムにするための取
り組みは既に数多くなされている。すなわち、システム内の CPU 間の仕事量を均等に
分担させる仕組みなどである。スケジューラほどこの作業分担処理が顕著に現れると
ころはない。

<!--
In a multiprocessor system, hopefully, all of the processors are busily running
processes. Each will run the scheduler separately as its current process 
exhausts its time-slice or has to wait for a system resource. The first thing 
to notice about an SMP system is that there is not just one idle process in 
the system. In a single processor system the idle process is the first task in
the task vector, in an SMP system there is one idle process per CPU, and you 
could have more than one idle CPU. Additionally there is one current process 
per CPU, so SMP systems must keep track of the current and idle processes for 
each processor. 
-->
<p>マルチプロセッサのシステムでは、すべてのプロセッサが常時プロセスの実行にあ
たっていることが望ましい。個々の CPU 上の現在のプロセスがタイムスライスを使い
切ったり、システムリソースを待たなければならなくなったとき、CPU は独立してスケ
ジューラを実行する。SMP システムに関してまず注意するべきことは、システム内の
アイドル状態のプロセスはひとつではないということである。シングルプロセッサの
システムなら、アイドルプロセスは <tt><ref id="task" name="task"></tt> 配列の
最初のタスクであるが、SMP システムでは CPU ごとにアイドルプロセスが存在する。
加えて、カレントプロセスも CPU ごとに存在するので、SMP システムはカレント
プロセスとアイドルプロセスとを CPU ごとに監視しなければならない。

<!--
In an SMP system each process's task_struct contains the number of the
processor that it is currently running on (processor) and its processor number
of the last processor that it ran on (last_processor). There is no reason why a
process should not run on a different CPU each time it is selected to run but 
Linux can restrict a process to one or more processors in the system using the
processor_mask. If bit N is set, then this process can run on processor N.
When the scheduler is choosing a new process to run it will not consider one 
that does not have the appropriate bit set for the current processor's number 
in its processor_mask. The scheduler also gives a slight advantage to a 
process that last ran on the current processor because there is often a 
performance overhead when moving a process to a different processor. 
-->
<p>SMP システムでは、個々のプロセスの <tt><ref id="task_struct" 
name="task_struct">_</tt> 構造体は、現在プロセスが走行中のプロセッサの番号
(<tt><ref id="task_struct" name="processor"></tt>)、およびそのプロセスが前回実
行されたプロセッサの番号(<tt><ref id="task_struct" name="last_processor"></tt>)
という情報を含む。
プロセスが選ばれるたびに違うプロセッサ上で実行されることがいけないという理由は
ないが、Linux は、<tt><ref id="processor_mask" name="processor_mask"></tt> を
使用して、プロセスがシステム
上の特定のプロセッサしか使わないよう制限することができる。ビット N がセットされ
ると、そのプロセスはプロセッサ N 上で実行が可能になる。スケジューラが、実行すべ
き新しいプロセスを選んでいるとき、割り当てを行おうとするプロセッサ番号に
適した番号が <tt>processor_mask</tt> にセットされていないプロセスは候補から
除外する。また、前回実行されたプロセッサとは異なるプロセッサ上でプロセスを
実行するときは、しばしばパフォーマンス上のオーバーヘッドが生じるので、
あるプロセスが、これから割り付けを行うプロセッサを前回も使っていた
場合は、スケジューラはそのプロセスに対し若干のアドバンテージを与える。


<!--4.4  Files-->
<sect1>ファイル<label id="chapter_p_sect4">
<p>


<!--                    Figure 4.1: A Process's Files-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure4-1.gif">
</figure>
</#if>
<#unless output="html">
<verb>
                   fs_struct                inode
                  +----------+             +------+
              +-->| count    |      +----->|      |
 task_struct  |   |----------|      |      |      |
              |   | unmask   |0x022 |      |      |
|           | |   |----------|      |      |      |
|           | |   | *next    |------+      +------+
|-----------+ |   |----------|
| fs        |-+   | *prev    |------+
|-----------+     +----------+      |       inode
| files     |-+                     |      +------+
|-----------+ |                     +----->|      |
|           | |                            |      |
|           | |    files_struct            |      |
              |   +---------------+        |      |
              +-->| count         |        +------+
                  |---------------|
                  | close_on_exec |
                  |---------------|
                  | open_fs       |
                  |---------------|                          inode
                  | fd[0]         |     file               +------+
                  |---------------|   +--------------+ +-->|      |
                  | fd[1]         |-->| f_mode       | |   |      |
                  |---------------|   |--------------| |   |      |
                  |               |   | f_ps         | |   |      |
                  |               |   |--------------| |   +------+
                  |               |   | f_flags      | |
                  |               |   |--------------| |
                  |               |   | f_count      | |
                  |               |   |--------------| |
                  |---------------|   | f_owner      | |
                  | fd[255]       |   |--------------| |
                  +---------------+   | f_inode      |-+
                                      |--------------|
                                      | f_op         |--->ファイル
                                      |--------------|    操作
                                      | f_version    |    ルーチン
                                      +--------------+
</verb>
</#if>
<p>図表(4.1) プロセスのファイル

<!--
Figure  4.1 shows that there are two data structures that describe file system
specific information for each process in the system. The first, the fs_struct 
contains pointers to this process's VFS inodes and its umask. The umask is the
default mode that new files will be created in, and it can be changed via 
system calls. 
-->
<p>図表 4.1 では、ふたつのデータ構造があり、システム上の個々のプロセスに関する
ファイルシステム固有の情報を記述している仕組みが示されている。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/sched.h" 
name="include/linux/sched.h">]<newline>
ひとつめの、<tt><ref id="fs_struct" name="fs_struct"></tt> は
当該プロセスの VFS <tt><ref id="inode" name="inode"></tt> とその <tt>
umask</tt> に対するポインタを含んでいる。
<tt>umask</tt> とは新しいファイルが作成される際のデフォルトモードであり、
そのモードはシステムコールを介して変更可能である。

<!--
The second data structure, the files_struct, contains information about all of
the files that this process is currently using. Programs read from standard 
input and write to standard output. Any error messages should go to standard 
error. These may be files, terminal input/output or a real device but so far 
as the program is concerned they are all treated as files. Every file has its 
own descriptor and the files_struct contains pointers to up to 256 file data 
structures, each one describing a file being used by this process. The f_mode 
field describes what mode the file has been created in; read only, read and 
write or write only. f_pos holds the position in the file where the next read 
or write operation will occur. f_inode points at the VFS inode describing the 
file and f_ops is a pointer to a vector of routine addresses; one for each 
function that you might wish to perform on a file. There is, for example, a 
write data function. This abstraction of the interface is very powerful and 
allows Linux to support a wide variety of file types. In Linux, pipes are 
implemented using this mechanism as we shall see later. 
-->
<p>ふたつめのデータ構造である <tt><ref id="files_struct" name="files_struct">
</tt> には、そのプロセスが現在使用しているすべてのファイルに関する情報が含まれ
る。プログラムは標準入力(standard input)から読み込みをし、標準出力(standard 
output)に書き出す。すべてのエラーメッセージは標準エラー(standard error)に送ら
れる。
それらはファイルであったり、ターミナルへの入出力であったり、実デバイスであった
りするが、そのプログラムに関する限り、それらはすべてファイルとして扱われる。
すべてのファイルは自分自身の記述子(descriptor)を持っており、<tt>files_struct
</tt> は、256 までの <tt><ref id="file" name="file"></tt> データ構造体に対す
るポインタを含むことができ、それらの各々がそのプロセスで使用されている
ファイルを指し示している。<tt><ref id="file" name="file"></tt> 構造体の 
<tt><ref id="file" name="f_mode"></tt> フィールドはそのファイルがどのモードで
作成されているのかを示す。読み込み専用、読み書き可能、書き込み専用などである。
<tt><ref id="file" name="f_pos"></tt> はファイル内の位置情報を保持していて、
次の読み書き処理がファイル内のどこでなされるかを示している。
<tt><ref id="file" name="f_inode"></tt> は、そのファイルを記述する VFS <tt>
<ref id="inode" name="inode"></tt> をポイントしており、<tt>f_ops</tt>
(訳注: <tt><ref id="file" name="f_op"></tt>？) は、ルーチンのアドレスの配列に
対するポインタであり、個々のルーチンは、たとえば、データ書き込みのための関数な
どの、そのファイルに対する操作の際に呼び出される関数である。
このインターフェイスの抽象化は非常にパワフルであり、それによって Linux は
幅広いファイルタイプをサポートすることができる。Linux では、このメカニズムを
利用したパイプが実装されているが、それについては後ほど述べる。

<!--
Every time a file is opened, one of the free file pointers in the files_struct
is used to point to the new file structure. Linux processes expect three file
descriptors to be open when they start. These are known as standard input,
standard output and standard error and they are usually inherited from the 
creating parent process. All accesses to files are via standard system calls 
which pass or return file descriptors. These descriptors are indices into the 
process's fd vector, so standard input, standard output and standard error 
have file descriptors 0, 1 and 2. Each access to the file uses the file data 
structure's file operation routines to together with the VFS inode to achieve 
its needs. 
-->
<p>ファイルがオープンされるたびに、<tt><ref id="files_struct" 
name="file_struct"></tt> 内にある使用されていない <tt><ref id="file" 
name="file"></tt> へのポインタが新しい <tt>file</tt> 構造体に対するポインタ
として使用される。
Linux のプロセスは、実行される際に 3 つのファイルディスクリプタがあることを
前提にしている。
それらは、標準入力、標準出力、標準エラーと呼ばれ、通常生成に関与し
た親プロセスからそれらを受け継ぐ。ファイルへのアクセスはすべて標準
システムコール経由で行われ、それらのシステムコールとの間でファイルディスクリ
プタのやり取りがある。これらのファイルディスクリプタは、プロセスの <tt>
<ref id="files_struct" name="fd"></tt> 
配列へのインデックスとなっていて、標準入力、標準出力、標準エラーは
それぞれ 0, 1, 2 のファイルディスクリプタを持つ。ファイルへのアクセスのたびに
 <tt>file</tt> データ構造のファイル操作ルーチンと、VFS inode とを使用し、
目的とする必要な処理が行われる。

<!--4.5  Virtual Memory-->
<sect1>仮想メモリ<label id="chapter_p_sect5">

<!--
A process's virtual memory contains executable code and data from many
sources. First there is the program image that is loaded; for example a command
like ls. This command, like all executable images, is composed of both 
executable code and data. The image file contains all of the information 
neccessary to load the executable code and associated program data into the 
virtual memory of the process. Secondly, processses can allocate (virtual) 
memory to use during their processing, say to hold the contents of files that 
it is reading. This newly allocated, virtual, memory needs to be linked into 
the process's existing virtual memory so that it can be used. Thirdly, Linux 
processes use libraries of commonly useful code, for example file handling 
routines. It does not make sense that each process has its own copy of the 
library, Linux uses shared libraries that can be used by several running 
processes at the same time. The code and the data from these shared libraries 
must be linked into this process's virtual address space and also into the 
virtual address space of the other processes sharing the library. 
-->
<p>プロセスの仮想メモリに含まれる実行コードとデータは、様々なソースから成り
立っている。
第一に、ロードされるべきプログラムイメージがある。たとえば、<tt>ls</tt> のよう
なコマンドは、他のすべての実行イメージ同様、実行コードとデータから構成されて
いる。そのイメージファイルには、実行コードとプログラムの関連データとを
プロセスの仮想メモリにロードするのに必要なすべての情報も含まれている。
第二に、プロセス自体が、新たに仮想メモリを割り付ける場合がある。これは、読み出
し中のファイルの内容の保持するときなどに、そのプロセスの処理中に使用されるもの
である。この新しく割り付けられた仮想メモリを使えるようにするには、プロセスの
持つ既存の仮想メモリにリンクしなければならない。
第三に、Linux のプロセスは、たとえばファイルハンドリングのルーチンなど、一般的
によく利用されるコードであるライブラリを使用する。個々のプロセスが自分自身の
ライブラリのコピーを持つのでは意味がないので、Linux はいくつかの実行中の
プロセスから同時に使用することが可能な共有ライブラリを使用している。そうした
共有ライブラリのコードやデータも、そのプロセスの仮想アドレス空間にリンクされ
なければならない。また、それらは、ライブラリを共有している他のプロセスの
仮想アドレス空間にもリンクされなければならない。

<!--
In any given time period a process will not have used all of the code and data
contained within its virtual memory. It could contain code that is only used 
during certain situations, such as during initialization or to process a 
particular event. It may only have used some of the routines from its shared 
libraries. It would be wasteful to load all of this code and data into 
physical memory where it would lie unused. Multiply this wastage by the number
of processes in the system and the system would run very inefficiently. 
Instead, Linux uses a technique called demand paging where the virtual memory 
of a process is brought into physical memory only when a process attempts to 
use it. So, instead of loading the code and data into physical memory straight
away, the Linux kernel alters the process's page table, marking the virtual 
areas as existing but not in memory. When the process attempts to acccess the 
code or data the system hardware will generate a page fault and hand control 
to the Linux kernel to fix things up. Therefore, for every area of virtual 
memory in the process's address space Linux needs to know where that virtual 
memory comes from and how to get it into memory so that it can fix up
these page faults. 
-->
<p>ある限られた時間の単位で眺めれば、プロセスは仮想メモリ内に含まれるコードや
データのすべてを使っているわけではない。特定の状況でしか利用されないコード、
たとえば初期化や特別なイベントを処理するときだけしか使用されないコードも仮想
メモリに含まれている。共有ライブラリのルーチンも僅かしか使用していないかも
しれない。
そうしたコードやデータのすべてを物理メモリにロードして、使わずに放っておく
のは資源の無駄である。システム上のプロセスの数だけこの無駄があるとすると、
システムを実行する上で非常に効率が悪い。これに対処するために、Linux は、
デマンドページングというテクニックを使用し、プロセスがその仮想メモリを使用
するときだけその仮想メモリを物理メモリに戻すようにしている。したがって、
コードやデータを物理メモリに直接ロードするかわりに、Linux カーネルはプロセス
のページテーブルを変更し、仮想エリアを存在はするが(訳注: valid だが)物理メモリ
内には存在しない状態にしている。
プロセスがコードやデータにアクセスしようとすると、システムのハードウェアが
ページフォルトを起こし、制御を Linux カーネルに渡して、カーネルが問題を解決
するようになっている。
それゆえ、そうしたページフォルトに対処するために、プロセスのアドレス空間にある
仮想メモリのすべての領域に関して、Linux は、仮想メモリがどういったソースから
成り立つもので、どうすれば物理メモリ内に取ってこれるのかを知っている必要があ
る。

<label id="figure4-2">
<!--                Figure 4.2: A Process's Virtual Memory-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure4-2.gif">
</figure>
</#if>
<#unless output="html">
<verb>
                                          プロセス仮想メモリ
                                             +----------+
task_struct                                  |          |
|        |                                   |          |
|        |                                   |          |
|        |    mm_struct    vm_area_struct +->|----------|
|--------|  +----------+    +----------+  |  |          |
|  mm    |->| count    | +->| vm_end   |--+  |          |
|--------|  |----------| |  |----------|     |          |
|        |  | pgd      | |  | vm_start |--+  |   Data   |
|        |  |----------| |  |----------|  |  |          |
|        |  |          | |  | vm_flag  |  |  |          |
|        |  |          | |  |----------|  |  |          |
|           |          | |  | vm_inode |  |  |          |
            |----------| |  |----------|  +->|----------|0x8059BB8
            | mmap     |-+  | vm_ops   |     |          |
            |----------|    |----------|     |          |
            | mmap_avi |    |          |     |          |
            |----------|    |          |     |          |
            | mmap_sem |    |----------|  +->|----------|
            +----------+    | vm_next  |-+|  |          |
                            +----------+ ||  |          |
                         +---------------+|  |          |
                         | vm_area_struct |  |          |
                         |  +----------+  |  |          |
                         +->| vm_end   |--+  |          |
                            |----------|     |          |
                            | vm_start |---->|----------|0x8048000
                            |----------|     |          |
                            | vm_flag  |     |          |
                            |----------|     |          |
                            | vm_inode |     |          |
                            |----------|     |          |
                            | vm_ops   |     |          |
                            |----------|     |          |
                            |          |     |          |
                            |          |     |          |
                            |----------|     |          |
                            | vm_next  |     |          |
                            +----------+     |          |
                                             +----------+ 0x0000000
</verb>
</#if>
<p>図表(4.2) プロセスの仮想メモリ

<!--
The Linux kernel needs to manage all of these areas of virtual memory and the
contents of each process's virtual memory is described by a mm_struct data
structure pointed at from its task_struct. The process's mm_struct data 
structure also contains information about the loaded executable image and
a pointer to the process's page tables. It contains pointers to a list of
vm_area_struct data structures, each representing an area of virtual memory 
within this process. 
-->
<p>Linux カーネルはそうした仮想メモリの領域全体を管理する必要があり、個々の
プロセスの仮想メモリの内容は、そのプロセスの<tt><ref id="task_struct" 
name="task_struct"></tt> からポイントされた <tt><ref id="mm_struct" 
name="mm_struct"></tt> データ構造体によって記述されている。
プロセスの <tt>mm_struct</tt> データ構造体は、ロードされた実行イメージに関す
る情報とプロセスのページテーブルへのポインタも含んでいる。また、<tt>mm_struct
</tt> には、<tt><ref id="vm_area_struct" name="vm_area_struct"></tt> 
データ構造体のリストに対するポインタが含まれていて、個々の 
<tt><ref id="vm_area_struct" name="vm_area_struct"></tt> 構造体は、
プロセス内の仮想メモリの領域を表現している。

<!--
This linked list is in ascending virtual memory order, figure  4.2 shows the 
layout in virtual memory of a simple process together with the kernel data 
structures managing it. As those areas of virtual memory are from several 
sources, Linux abstracts the interface by having the vm_area_struct point to 
a set of virtual memory handling routines (via vm_ops). This way all of the 
process's virtual memory can be handled in a consistent way no matter how the 
underlying services managing that memory differ. For example there is a 
routine that will be called when the process attempts to access the memory 
and it does not exist, this is how page faults are handled. 
-->
<p>この <tt><ref id="vm_area_struct" name="vm_area_struct"></tt> の連結リスト
は、仮想メモリアドレスの昇順に並べられている。<ref id="figure4-2" 
name="図表(4.2)">では、単純なプロセスの仮想メモリ内のレイアウトが、それを管理
するカーネルのデータ構造と一緒に示されている。仮想メモリの領域はいく
つものソースから成立しているので、Linux はそのインターフェイスを抽象化
するために、<tt>vm_area_struct</tt> を使って(<tt><ref id="vm_area_struct" 
name="vm_ops"></tt>経由で)、仮想メモリ操作の一連のルーチンをポイントしている。
この方法により、プロセスの仮想メモリはすべて一貫した方法で操作できる
ようになっており、その操作方法は、仮想メモリを管理する基礎的な
サービスがどのように異なっていても変わらない。たとえば、プロセスが仮想メモリに
アクセスしようとしたがそれが物理メモリ上に存在しなかったときに呼び出される
ルーチンがある。ページフォルトを処理する場合に使用されるのが、そのルーチン
である。

<!--
The process's set of vm_area_struct data structures is accessed repeatedly
by the Linux kernel as it creates new areas of virtual memory for the process 
and as it fixes up references to virtual memory not in the system's physical 
memory. This makes the time that it takes to find the correct vm_area_struct 
critical to the performance of the system. To speed up this access, Linux also
arranges the vm_area_struct data structures into an AVL (Adelson-Velskii and 
Landis) tree. This tree is arranged so that each vm_area_struct (or node) has 
a left and a right pointer to its neighbouring vm_area_struct structure. The 
left pointer points to node with a lower starting virtual address and the 
right pointer points to a node with a higher starting virtual address. To 
find the correct node, Linux goes to the root of the tree and follows each 
node's left and right pointers until it finds the right vm_area_struct. Of 
course, nothing is for free and inserting a new vm_area_struct into this tree 
takes additional processing time. 
-->
<p>プロセスが持つ一連の <tt><ref id="vm_area_struct" 
name="vm_area_struct"></tt> データ構造体は、Linux カーネル
から繰り返しアクセスされる。たとえば、Linux が、そのプロセスのために新しい仮想
メモリのエリアを作成するときや、システムの物理メモリ内にない仮想メモリが
参照された場合にそれを解決するときなどである。
それゆえ、正しい <tt>vm_area_struct</tt> を発見するのにかかる時間は、
システムのパフォーマンスに深刻な影響を与える。このアクセス時間を短縮するため
に、Linux は、AVL (Adelson-Velskii and Landis) ツリーのなかに <tt>
vm_area_struct</tt> データ構造体を配置している。このツリーは、個々の <tt>
vm_area_struct</tt> (あるいは、ノード) が左右両隣の <tt>vm_area_struct</tt> 
データ構造体へのポインタを持つように配置されている。左のポインタは、それより
低い仮想アドレスを持つノードをポイントしており、右のポインタはそれより高い
仮想アドレスを持つノードをポイントしている。正しいノードを発見する際、
Linux はツリーの根(root)の部分から入って、個々のノードの左右のポインタを辿り、
正しい <tt>vm_area_struct</tt> を発見する仕組みになっている。
もちろん、この方法もいいことずくめではなく、このツリーに新しい <tt>
vm_area_struct</tt> を追加する場合、(通常より)多くのプロセス時間が消費される。

<!--
When a process allocates virtual memory, Linux does not actually reserve
physical memory for the process. Instead, it describes the virtual memory by
creating a new vm_area_struct data structure. This is linked into the process's
list of virtual memory. When the process attempts to write to a virtual address
within that new virtual memory region then the system will page fault. The
processor will attempt to decode the virtual address, but as there are no Page
Table Entries for any of this memory, it will give up and raise a page fault
exception, leaving the Linux kernel to fix things up. Linux looks to see if 
the virtual address referenced is in the current process's virtual address 
space. If it is, Linux creates the appropriate PTEs and allocates a physical 
page of memory for this process. The code or data may need to be brought into 
that physical page from the filesystem or from the swap disk. The process can 
then be restarted at the instruction that caused the page fault and, this time
as the memory physically exists, it may continue. 
-->
<p>プロセスが仮想メモリの割り付けを行うとき、Linux は実際にそのプロセスのため
の物理メモリを確保するわけではない。そのかわり、Linux は、新しく <tt>
<ref id="vm_area_struct" name="vm_area_struct"></tt> データ構造体を作成すること
でその仮想メモリを記述する。
この構造体はプロセスの仮想メモリのリストにリンクされる。プロセスがその新しい仮
想メモリの領域内にある仮想メモリに書き込みを行おうとするとき、システムはページ
フォルトを起こす。プロセッサは仮想アドレスを(物理アドレスに)デコードしようと
するが、その仮想メモリに関するページテーブルエントリ(PTE)が存在しないので、
諦めてページフォルト例外(page fault exception)を発行し、Linux カーネルに後の
処理を任せる。Linux は、参照された仮想アドレスが現在のプロセスの仮想アドレス
空間にあるかどうかを確認する。もしあるなら、Linux は適切な PTE を作成し、この
プロセスにメモリの物理ページを割り付ける。ファイルシステムやスワップディスク
から、コードやデータをその物理ページへと持って来なければならない場合もある。
それによって、プロセスはページフォルトの原因となった命令の時点から再始動さ
れ、今回は物理メモリが存在するので、実行が継続する。

<!--4.6  Creating a Process-->
<sect1>プロセスの生成<label id="chapter_p_sect6">

<!--
When the system starts up it is running in kernel mode and there is, in a 
sense, only one process, the initial process. Like all processes, the initial 
process has a machine state represented by stacks, registers and so on. These 
will be saved in the initial process's task_struct data structure when other 
processes in the system are created and run. At the end of system 
initialization, the initial process starts up a kernel thread (called init) 
and then sits in an idle loop doing nothing. Whenever there is nothing else to
do the scheduler will run this, idle, process. The idle process's task_struct 
is the only one that is not dynamically allocated, it is statically defined at
kernel build time and is, rather confusingly, called init_task. 
-->
<p>システムは、起動時に、カーネルモードで実行されていて、その際は、ある意味
で、たったひとつのプロセスである初期化プロセスしか存在しない。
初期化プロセスも、他のすべてのプロセスと同様に、スタックやレジスタなどで表現
されるマシン状態(machine state)を持っている。
他のプロセスが生成されて実行される時、それらの情報は、初期化プロセスの 
<tt><ref id="task_struct" name="task_struct"></tt> データ構造体に保存される。
システムの初期化が終了した時点
で、初期化プロセスは、(<tt>init</tt> と呼ばれる)カーネルスレッド(kernel 
thread)を起動し、アイドルループ(idle loop)状態に入って、何もしなくなる。
他に全く何もすることがなければ、スケジューラは、このアイドルプロセスを実行す
る。このアイドルプロセスの <tt>task_struct</tt> は、唯一、動的に割り付けを
されないプロセスであり、それはカーネルがビルドされた時に静的に定義されて
いるプロセスであり、やや紛らわしい名前だが、<tt>init_task</tt> と呼ばれてい
る。

<!--
The init kernel thread or process has a process identifier of 1 as it is the
system's first real process. It does some initial setting up of the system 
(such as opening the system console and mounting the root file system) and 
then executes the system initialization program. This is one of /etc/init, 
/bin/init or /sbin/init depending on your system. The init program uses
/etc/inittab as a script file to create new processes within the system. These
new processes may themselves go on to create new processes. For example the
getty process may create a login process when a user attempts to login. All of
the processes in the system are descended from the init kernel thread. 
-->
<p><tt>init</tt> というカーネルスレッドもしくはプロセスは、システムで最初の
実プロセスなので、プロセス識別子 1 を持っている。それは、システムの初期化
設定のいくつか(システムコンソールのオープンやルートファイルシステムのマウント
など)を実行し、その後でシステムの初期化プログラムを実行する。そのプログラムは、
システムに依存するので、<tt>/etc/init</tt>, <tt>/bin/init</tt>, もしくは
 <tt>/sbin/init</tt> のいずれかとなっている。<tt>init</tt> プログラムは、
スクリプトファイルとして <tt>/etc/inittab</tt> を使用して、システム上で新しい
プロセスを生成する。それらの新しいプロセスはそれ自体でさらに新しいプロセスを
生成する場合もある。たとえば、<tt>getty</tt> プロセスは、ユーザがログインしよう
とする時、<tt>login</tt> プロセスを生成する。システム内のすべてのプロセスは、
その <tt>init</tt> カーネルスレッドの子孫である。

<!--
New processes are created by cloning old processes, or rather by cloning the
current process. A new task is created by a system call (fork or clone) 
and the cloning happens within the kernel in kernel mode. At the end of the 
system call there is a new process waiting to run once the scheduler chooses 
it. A new task_struct data structure is allocated from the system's physical 
memory with one or more physical pages for the cloned process's stacks (user 
and kernel). A new process identifier may be created, one that is unique 
within the set of process identifiers in the system. However, it is perfectly 
reasonable for the cloned process to keep its parents process identifier. The 
new task_struct is entered into the task vector and the contents of the old 
(current) process's task_struct are copied into the cloned task_struct. 
-->
<p>新しいプロセスは、古いプロセスをクローニングするか、もしくは現在のプロセス
をクローニングすることで生成される。
<newline>[see: do_fork(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/kernel/fork.c" 
name="kernel/fork.c">]<newline>
新しいタスクはシステムコール(<tt>fork</tt> もしくは <tt>clone</tt> )によって
生成され、クローニングはカーネル内でカーネルモードにおいて実行される。
そのシステムコールが終了すると、新しいプロセスが誕生し、スケジューラが選択し
たならすぐに実行できる状態で待機している。新しい <tt><ref id="task_struct" 
name="task_struct"></tt> データ
構造体には、クローニングされたプロセスの(ユーザおよびカーネル)スタックのため
に、いくつかの物理ページが、システムの物理メモリから割り付けられる。新しい
プロセスの識別子が作成されるが、その識別子は、システム内にある一連のプロセス
識別子のなかでユニークなものである。しかし、クローニングされたプロセスがその
親プロセスの識別子を保持するという仕組みには、特別な合理的理由がある。
新しい <tt>task_struct</tt> が <tt>task</tt> 配列に追加され、古い方の(現在の)
プロセスの <tt>task_struct</tt> の内容がクローニングされたプロセスの新しい <tt>
task_struct</tt> にコピーされる。

<!--
When cloning processes Linux allows the two processes to share resources rather
than have two separate copies. This applies to the process's files, signal 
handlers and virtual memory. When the resources are to be shared their 
respective count fields are incremented so that Linux will not deallocate 
these resources until both processes have finished using them. So, for 
example, if the cloned process is to share virtual memory, its task_struct 
will contain a pointer to the mm_struct of the original process and that 
mm_struct has its count field incremented to show the number of current 
processes sharing it. 
-->
<p>クローニングの処理の際、Linux は、ふたつのプロセスが個別のリソースを持つ
のでなく、同じリソースを共有することが出来るようにしている。このことは、
プロセスのファイルやシグナルハンドラー、仮想メモリにもついても当てはまる。
リソースが互いに共有されるべき時は、リソースの <tt>count</tt> フィールドが
インクリメントされ、Linux は、両方のプロセスがそれを使うのを止めるまでそれら
のリソース
を解放しないようにする。したがって、たとえば、クローニングされたプロセスが仮想
メモリを共有しようとする場合、そのプロセスの <tt><ref id="task_struct" 
name="task_struct"></tt> には、元の(親)プロセスの <tt><ref id="mm_struct" 
name="mm_struct"></tt> へのポインタが含められ、親プロセスの 
<tt>mm_struct</tt> の <tt><ref id="mm_struct" name="count"></tt> フィールドが
加算されて、それを共有するプロセスの数が示される。

<!--
Cloning a process's virtual memory is rather tricky. A new set of
vm_area_struct data structures must be generated together with their owning
mm_struct data structure and the cloned process's page tables. None of the
process's virtual memory is copied at this point. That would be a rather 
difficult and lengthy task for some of that virtual memory would be in 
physical memory, some in the executable image that the process is currently 
executing and possibly some would be in the swap file. Instead Linux uses a 
technique called ``copy on write'' which means that virtual memory will only 
be copied when one of the two processes tries to write to it. Any virtual 
memory that is not written to, even if it can be, will be shared between the 
two processes without any harm occuring. The read only memory, for example the
executable code, will always be shared. For ``copy on write'' to work, the 
writeable areas have their page table entries marked as read only and the 
vm_area_struct data structures describing them are marked 
as ``copy on write''. When one of the processes attempts to write to this
virtual memory a page fault will occur. It is at this point that Linux will 
make a copy of the memory and fix up the two processes' page tables and 
virtual memory data structures. 
-->
<p>プロセスの仮想メモリのクローニングはややトリッキーである。<tt><ref 
id="vm_area_struct" name="vm_area_struct"></tt> データ構造体の新しいセットが、
それらを所有する <tt><ref id="mm_struct" name="mm_struct"></tt> データ
構造体とクローニングされたプロセスのページテーブルとともに生成される。プロセス
の仮想メモリはこの段階ではまだ複製されていない。それは面倒で時間の掛かるタスク
である。というのも、親プロセスの仮想メモリのうち、ある部分は物理メモリにある
かもしれないが、プロセスが現在実行している実行イメージの中にあるものもあり、
おそらくスワップファイルの中にあるものもあるからである。それゆえ、Linux は、
「コピーオンライト(copy on write)」と呼ばれるテクニックを使用する。その意味は、
ふたつのプロセスのうちのひとつがそれに書き込みをしようとするときだけその仮想
メモリがコピーされるというものである。書き込みが可能な場合でも、(書き込み要求
がないために)書き込まれていないそうした仮想メモリは、何の問題もなくふたつの
プロセス間で共有される。たとえば実行コードのような、読み込み専用のメモリは常に
共有される。
「コピーオンライト」方式を機能させる場合、書き込み可能なエリアは、そのページ
テーブルエントリを読み込み専用とマークし、それらのエリアを記述する 
<tt>vm_area_struct</tt> データ構造体を「コピーオンライト」とマークする。
共有プロセスのひとつがこの仮想メモリに書き込みをしようとすると、ページフォルト
が起こる。この時点で、Linux はメモリのコピーを作成し、ふたつのプロセスのページ
テーブルと仮想メモリのデータ構造を訂正する。

<!--4.7  Times and Timers-->
<sect1>時間とタイマー<label id="chapter_p_sect7">

<!--
The kernel keeps track of a process's creation time as well as the CPU time 
that it consumes during its lifetime. Each clock tick, the kernel updates the 
amount of time in jiffies that the current process has spent in system and in 
user mode. 
-->
<p>カーネルは、プロセスが生成される時間を監視すると同時に、それがライフサイクル
において消費する CPU 時間も監視している。クロックティック(<ref id="clock_tick" 
name="clock tick">)ごとに、
カーネルは、現在のプロセスがシステムモードおよびユーザモードで消費した時間の
総量を <tt>jiffies</tt> 値を使って計測・更新している。

<!--
In addition to these accounting timers, Linux supports process specific 
interval timers. A process can use these timers to send itself various signals
each time that they expire. Three sorts of interval timers are supported: 
-->
<p>そうした時間記録用のタイマーに加えて、Linux はプロセス固有のインターバル
タイマー(interval timer)もサポートしている。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/kernel/itimer.c" 
name="kernel/itimer.c">]<newline>
プロセスはそのタイマーを使用して、タイマーの所定時間が経過するごとに自分自身
に対して様々なシグナルを送っている。サポートされている三種類のインターバル
タイマーには、次のようなものがある。

<descrip>
<!--
Real the timer ticks in real time, and when the timer has expired, the process
     is sent a SIGALRM signal. 
-->
<tag><tt>real</tt></tag>
実時間で計測されるタイマチック(<ref id="clock_tick" name="timer tick">)。その
タイマーの所定時間が経過すると、プロセスに <tt>SIGALRM</tt> シグナルが送られ
る。

<!--
Virtual This timer only ticks when the process is running and when it expires 
        it sends a SIGVTALRM signal. 
-->
<tag><tt>virtual</tt></tag>
プロセスの実行中だけ計測されるタイマチック。所定時間が経過すると、プロセス
に <tt>SIGVTALRM</tt> シグナルを送る。

<!--
Profile This timer ticks both when the process is running and when the system 
        is executing on behalf of the process itself. SIGPROF is signalled 
        when it expires. 
-->
<tag><tt>profile</tt></tag>
プロセスの実行時と、プロセスを代理してシステムが実行されている時の両方で
計測されるタイマチック。所定時間経過により <tt>SIGPROF</tt> シグナルを送
る。

</descrip>

<!--
One or all of the interval timers may be running and Linux keeps all of the
neccessary information in the process's task_struct data structure. System
calls can be made to set up these interval timers and to start them, stop them
and read their current values. The virtual and profile timers are handled the 
same way. Every clock tick the current process's interval timers are 
decremented and, if they have expired, the appropriate signal is sent. 
-->
<p>ひとつもしくはすべてのインターバルタイマーを実行することが可能で、Linux 
はそれらすべての必要な情報をプロセスの <tt><ref id="task_struct" 
name="task_struct"></tt> データ構造体に保存する。これらのインターバルタイマー
の設定、始動、停止および現在の値の読みとりは、システムコールにより実行される。
<newline>[see: do_it_virtual(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/kernel/sched.c" 
name="kernel/sched.c">]
<newline>[see: do_it_prof(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/kernel/sched.c" 
name="kernel/sched.c">]<newline>
virtual および profile タイマーは、同じ方法で操作される。クロックティックごとに
走行中のプロセスのインターバルタイマーの値は減少し、所定時間経過により、適切
なシグナルが送られる。

<!--
Real time interval timers are a little different and for these Linux uses the 
timer mechanism described in Chapter  kernel-chapter. Each process has its own
timer_list data structure and, when the real interval timer is running, this is
queued on the system timer list. When the timer expires the timer bottom half
handler removes it from the queue and calls the interval timer handler. This 
generates the SIGALRM signal and restarts the interval timer, adding it back 
into the system timer queue. 
-->
<p>リアルタイム(real time)インターバルタイマーはそれとは少し異
なり、Linux は、そのために<ref id="chapter_km" name="「カーネルの仕組み」">の
章で解説するタイマーメカニズムを使用する。
<newline>[see: it_real_fn(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/kernel/itimer.c" 
name="kernel/itimer.c">]<newline>
個々のプロセスは、自分の <tt><ref id="timer_list" name="timer_list"></tt> 
データ構造体を持ち、リアル(real)インターバルタイマーが実行されているとき、その
構造体がシステムタイマーリストのキューに入る。所定時間が経過すると、タイマー
のボトムハーフハンドラー(bottom half handler)がそれをキューから削除し、インター
バルタイマーハンドラー(interval timer handler)を呼び出す。そしてそれが 
<tt>SIGALRM</tt> シグナルを生成し、インターバルタイマーを再始動させ、当該
構造体を再度システムタイマーのキューに戻す。

<!--4.8  Executing Programs-->
<sect1>プログラムの実行<label id="chapter_p_sect8">

<!--
In Linux, as in Unix TM, programs and commands are normally executed by a
command interpreter. A command interpreter is a user process like any other
process and is called a shell 2. There are many shells in Linux, some of the 
most popular are sh, bash and tcsh. With the exception of a few built in 
commands, such as cd and pwd, a command is an executable binary file. For 
each command entered, the shell searches the directories in the process's 
search path, held in the PATH environment variable, for an executable image 
with a matching name. If the file is found it is loaded and executed. The 
shell clones itself using the fork mechanism described above and then the new 
child process replaces the binary image that it was executing, the shell, 
with the contents of the executable image file just found. Normally the shell 
waits for the command to complete, or rather for the child process to exit. 
You can cause the shell to run again by pushing the child process to the 
background by typing control-Z, which causes a SIGSTOP signal to be sent to 
the child process, stopping it. You then use the shell command bg to push it 
into a background, the shell sends it a SIGCONT signal to restart it, where 
it will stay until either it ends or it needs to do terminal input or output. 
-->
<p>Linux では、他の Unix と同様に、プログラムやコマンドは、通常コマンドイン
タープリタによって実行される。コマンドインタープリタは、他のプロセス同様
ユーザプロセスであり、シェル(<ref id="chapter_p_fn1" name="脚注 2">)と呼ばれ
る。Linux 上には多くのシェルがあり、
最も有名なものとして、<tt>sh, bash</tt> そして <tt>tcsh</tt> がある。<tt>cd
</tt> や <tt>pwd</tt> といったいくつかの組み込みコマンドを除けば、
コマンドとは実行可能なバイナリファイルのことである。コマンドが入力されると、
シェルは、環境変数 <tt>PATH</tt> に設定されたプロセスの検索パス内のディレクトリ
を探し、同じ名前の実行イメージを見つけようとする。そのファイルが見つかれば、
それはロードされ実行される。シェルは、<tt>fork</tt> という仕組みを使って、
先ほど説明したように自分自身をクローニングする。そして、次に新しい子プロセス
は、親プロセスが実行していたバイナリイメージ、すなわちシェルを、見つかった
ばかりの実行イメージの内容と置き換える。通常、シェルは、そのコマンドの完了、
言い換えると子プロセスの終了を待つ。シェルを再度走らせたいときは、control-Z 
とタイプして、子プロセスをバックグラウンドに押しやればよい。これは、子プロセス
に <tt>SIGSTOP</tt> シグナルを送って、それを停止させる操作である。次に、
シェルコマンド <tt>bg</tt> を使って子プロセスをバックグラウンドに押しやること
もできる。これは、シェルから子プロセスに対して <tt>SIGCONT</tt> シグナルを
送って再始動させるもので、子プロセスは実行が終了するか、ターミナルでの入出力
が必要になるまでそこに留まる。

<!--
An executable file can have many formats or even be a script file. Script 
files have to be recognized and the appropriate interpreter run to handle 
them; for example /bin/sh interprets shell scripts. Executable object files 
contain executable code and data together with enough information to allow the
operating system to load them into memory and execute them. The most commonly 
used object file format used by Linux is ELF but, in theory, Linux is flexible
enough to handle almost any object file format. 
-->
<p>実行ファイルは多種のフォーマットを取ることができる。
それは、スクリプトファイルであってもよい。
スクリプトファイルは解釈可能なものでなければならず、適切なインター
プリタを実行してそれを処理しなければならない。たとえば、<tt>/bin/sh</tt> は、
シェルスクリプトを解釈するインタープリタである。実行可能なオブジェクトファイ
ルには、実行コードとデータ、およびオペレーティングシステムがそれをメモリに
ロードして実行することができるだけの充分な情報が含まれている。Linux 上で最も
一般的に利用されているオブジェクトファイルのフォーマットは、ELF であるが、
理論上は、Linux は、ほとんどすべてのオブジェクトファイルのフォーマットを扱え
るだけの柔軟性をもっている。


<!--                Figure 4.3: Registered Binary Formats-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure4-3.gif">
</figure>
</#if>
<#unless output="html">
<verb>
formats   linux_binfmt          linux_binfmt           linux_binfmt
        +----------------+    +----------------+    +----------------+
------->| next           |--->| next           |--->| next           |
        |----------------|    |----------------|    |----------------|
        | use_count      |    | use_count      |    | use_count      |
        |----------------|    |----------------|    |----------------|
        | *load_binary() |    | *load_binary() |    | *load_binary() |
        |----------------|    |----------------|    |----------------|
        | *load_shlib()  |    | *load_shlib()  |    | *load_shlib()  |
        |----------------|    |----------------|    |----------------|
        | *core_dump()   |    | *core_dump()   |    | *core_dump()   |
        +----------------+    +----------------+    +----------------+
</verb>
</#if>
<p>図表(4.3) 登録されたバイナリフォーマット


<!--
As with file systems, the binary formats supported by Linux are either built 
into the kernel at kernel build time or available to be loaded as modules. The
kernel keeps a list of supported binary formats (see figure  4.3) and when an 
attempt is made to execute a file, each binary format is tried in turn until 
one works. 
Commonly supported Linux binary formats are a.out and ELF. Executable files
do not have to be read completely into memory, a technique known as demand
loading is used. As each part of the executable image is used by a process it 
is brought into memory. Unused parts of the image may be discarded from 
memory. 
-->
<p>ファイルシステムの場合と同様に、Linux でサポートされているバイナリ
フォーマットは、カーネルをビルドする際にカーネルに組み込まれるか、ローダブル
モジュールとして利用可能かのいずれかである。カーネルはサポートするバイナリ
フォーマットのリストを保持しており(図表(4.3)参照)、ファイルが実行されるときは、
その実行に成功するまで、個々のバイナリフォーマットが順番に試される。
<newline>[see: do_execve(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/fs/exec.c" 
name="fs/exec.c">]<newline>
広くサポートされている Linux のバイナリフォーマットは、<tt>a.out</tt> と
 ELF である。実行ファイルは、完全にメモリに読み込まれる必要はなく、デマンド
ローディングと呼ばれるテクニックが使用される。実行イメージの一部がプロセスに
よって使用されるたびに、その部分だけがメモリに取り込まれる。そのイメージの
使用されない部分は、メモリから破棄されてもよい。

<!--4.8.1  ELF-->
<sect2>ELF

<!--
The ELF (Executable and Linkable Format) object file format, designed by the
Unix System Laboratories, is now firmly established as the most commonly used
format in Linux. Whilst there is a slight performance overhead when compared
with other object file formats such as ECOFF and a.out, ELF is felt to be more
flexible. ELF executable files contain executable code, sometimes refered to as
text, and data. Tables within the executable image describe how the program
should be placed into the process's virtual memory. Statically linked images 
are built by the linker (ld), or link editor, into one single image containing
all of the code and data needed to run this image. The image also specifies 
the layout in memory of this image and the address in the image of the first 
code to execute. 
-->
<p>ELF (Executable and Linkable Format) というオブジェクトファイルのフォー
マットは、Unix System 研究所で設計されたもので、今日では Linux 上で最も広く
利用されているフォーマットとしてその地位が確立している。ECOFF や a.out 
のような他のオブジェクトファイルのフォーマットと比較するとパフォーマンス上
ややオーバーヘッドがあるのだが、ELF はむしろそれら以上に柔軟である点が評価され
ている。
ELF の実行ファイルには、時にはテキスト(text)とも呼ばれる実行コード、および
データが含まれる。実行ファイル内のテーブルでは、そのプログラムがプロセッサの
仮想メモリに置かれる際の方法が示されている。静的にリンクされたイメージは、
リンカ(<tt>ld</tt>)、もしくはリンクエディタによって、そのイメージの実行に必要
なすべてのコードとデータを含む単一のイメージにビルドされる。そのイメージは、
自分自身のメモリ内でのレイアウトや、イメージ内の最初の実行コードのアドレスに
ついても指定している。

<!--                Figure 4.4: ELF Executable File Format-->
<#if output="html">
<figure><ph vspace="1" ><img src="./The-Linux-Kernel-images/figure4-4.gif">
</figure>
</#if>
<#unless output="html">
<verb>
             ELF 実行イメージ
            +---------------+                 
            |  e_ident      |'E' 'L' 'F'
            |  e_entry      | 0x8048090
            |  e_phoff      | 52
            |  e_phentsize  | 32
            |  e_phnum      | 2
            |---------------|
            |               |
            |---------------|
            |  p_type       | PT_LOAD
            |  p_offset     | 0
物理ヘッダ  |  p_vaddr      | 0x8048000
            |  p_filesz     | 68532
            |  p_memsz      | 68532
            |  p_flags      | PF_R, PF_X
            |---------------|
            |  p_type       | PT_LOAD
            |  p_offset     | 68536
            |  p_vaddr      | 0x8059BB8
物理ヘッダ  |  p_filesz     | 2200
            |  p_memsz      | 4248
            |  p_flags      | PF_R, PF_W
            |---------------|
            ~               ~
            ~               ~
            |               |
            |    Code       |
            |               |
            |---------------|
            |               |
            |    Data       |
            |               |
            |               |
            +---------------+
</verb>
</#if>
<p>図表(4.4) ELF 実行ファイルフォーマット


<!--
Figure  4.4 shows the layout of a statically linked ELF executable image. 
It is a simple C program that prints ``hello world'' and then exits. The header
describes it as an ELF image with two physical headers (e_phnum is 2) starting
52 bytes (e_phoff) from the start of the image file. The first physical header
describes the executable code in the image. It goes at virtual address 
0x8048000 and there is 65532 bytes of it. This is because it is a statically 
linked image which contains all of the library code for the printf() call to 
output ``hello world''. The entry point for the image, the first instruction 
for the program, is not at the start of the image but at virtual address 
0x8048090 (e_entry). The code starts immediately after the second physical 
header. This physical header describes the data for the program and is to be 
loaded into virtual memory at address 0x8059BB8. This data is both readable 
and writeable. You will notice that the size of the data in the file is 2200 
bytes (p_filesz) whereas its size in memory is 4248 bytes. This because the 
first 2200 bytes contain pre-initialized data and the next 2048 bytes contain 
data that will be initialized by the executing code. 
-->
<p>
図表(4.4) は、静的にリンクされた ELF 実行イメージのレイアウトを示している。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/elf.h" 
name="include/linux/elf.h">]<newline>
これは、簡単な C プログラムであり、"<tt>hello world</tt>" を表示して、終了する
ものである。ヘッダは、ファイルが ELF イメージであること示すのに、2 つの物理
ヘッダを使っていて(<tt>e_phnum</tt> は 2 である)、それらはイメージファイルの
先頭から 52 バイト目(<tt>e_phoff</tt>)から始まっている。
最初の物理ヘッダは、イメージ内の実行コードについて記述している。実行コード
は、仮想アドレスの 0x8048000 に置かれ、その容量が 65532 バイトであることを
示している。この容量は、それが静的にリンクされたイメージだからであり、"<tt>
hello world</tt>" を出力するための <tt>printf()</tt> 呼び出しのライブラリ
コードのすべてを含むからである。イメージのエントリーポイント、すなわちプログ
ラムの最初の命令がある場所は、イメージの先頭ではなく、仮想アドレス 0x8048090 
(<tt>e_entry</tt>) である。
このコードは、二つ目の物理ヘッダのすぐ後ろから始まっている。二つ目の物理ヘッダ
は、プログラムのデータを記述していて、仮想メモリ内のアドレス 0x8059BB8 にロー
ドされるようになっている。このデータは読み書き可能である。ファイルのデータ
サイズが 2200 バイト (<tt>p_filesz</tt>) となっており、メモリ内でのそのサイズ
は 4248 バイトであることに気付いたと思う。これは、最初の 2200 バイトにはあらか
じめ初期化されたデータが含まれていて、次の 2048 バイトには実行コードによって
初期化されるデータが含まれているからである。

<!--
When Linux loads an ELF executable image into the process's virtual address
space, it does not actually load the image. 
It sets up the virtual memory data structures, the process's vm_area_struct
tree and its page tables. When the program is executed page faults will cause 
the program's code and data to be fetched into physical memory. Unused 
portions of the program will never be loaded into memory. Once the ELF binary 
format loader is satisfied that the image is a valid ELF executable image it 
flushes the process's current executable image from its virtual memory. As 
this process is a cloned image (all processes are) this, old, image is the 
program that the parent process was executing, for example the command 
interpreter shell such as bash. This flushing of the old executable image 
discards the old virtual memory data structures and resets the process's page 
tables. It also clears away any signal handlers that were set up and closes 
any files that are open. At the end of the flush the process is ready for the 
new executable image. No matter what format the executable image is, the same 
information gets set up in the process's mm_struct. There are pointers to the 
start and end of the image's code and data. These values are found as the ELF 
executable images physical headers are read and the sections of the program 
that they describe are mapped into the process's virtual address space. That 
is also when the vm_area_struct data structures are set up and the process's 
page tables are modified. The mm_struct data structure also contains pointers 
to the parameters to be passed to the program and to this process's 
environment variables. 
-->
<p>
Linux が ELF 実行イメージをプロセスの仮想アドレス空間にロードするとき、
Linux は実際にそのイメージをロードするわけではない。
<newline>[see: do_load_elf_binary(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/fs/binfmt_elf.c" 
name="fs/binfmt_elf.c">]<newline>
仮想メモリのデータ構造と
プロセスの <tt><ref id="vm_area_struct" name="vm_area_struct"></tt> ツリー、
およびそのページテーブルを設定するだけである。プログラムが実行されると、
ページフォルトによりプログラムのコードとデータが物理メモリに取り出される。
プログラムの使用されていない部分は決してメモリにロードされない。
ELF バイナリフォーマットローダ(loader)は、ロードすべきイメージが有効な ELF 
実行イメージであることを確認すると、そのプロセスの現在の実行イメージをその
仮想メモリから消去する。このプロセスはクローニングされたイメージなので
(すべてのプロセスがそうである)、この古いイメージは、親プロセスが実行している
プログラム、たとえばコマンドインタープリタシェルである <tt>bash</tt> 等のプログ
ラムにすぎないからである。古い実行イメージをこのように消去することで、古い仮想
メモリのデータ構造が破棄され、プロセスのページテーブルがリセットされる。
ローダはまた、設定されたすべてのシグナルハンドラをクリアし、オープンされていた
すべてのファイルを閉じる。それらの消去が終わると、子プロセスは新しい実行
イメージを受け入れ可能になる。
実行イメージのフォーマットが何であれ、同じ情報がプロセスの <tt>
<ref id="mm_struct" name="mm_struct"></tt> に設定される。<tt>mm_struct</tt> 
構造体にはイメージのコードとデータの始点と終点についてのポインタが存在する。
それらの値が見いだされるのは、ELF 実行イメージの物理ヘッダが読み込まれて、
それらのヘッダが記述するプログラムのセクションがプロセスの仮想アドレス空間に
マップされたときである。それは、同時に <tt>vm_area_struct</tt> データ構造体が
設定され、プロセスのページテーブルが変更されるときでもある。<tt>mm_struct
</tt> データ構造体には、そのプログラムに渡されるパラメータとプロセスの環境変
数に対するポインタも含まれている。

<!--ELF Shared Libraries-->
<sect3>ELF 共有ライブラリ

<!--
A dynamically linked image, on the other hand, does not contain all of the 
code and data required to run. Some of it is held in shared libraries that are
linked into the image at run time. The ELF shared library's tables are also 
used by the dynamic linker when the shared library is linked into the image at
run time. Linux uses several dynamic linkers, ld.so.1, libc.so.1 and 
ld-linux.so.1, all to be found in /lib. The libraries contain commonly used 
code such as language subroutines. Without dynamic linking, all programs would
need their own copy of the these libraries and would need far more disk space 
and virtual memory. In dynamic linking, information is included in the ELF 
image's tables for every library routine referenced. The information indicates
to the dynamic linker how to locate the library routine and link it into the 
program's address space. 
-->
<p>反対に、動的にリンクされたイメージは、実行に必要なすべてのコードとデータを
含むわけではない。その幾分かは、共有ライブラリに保持されており、実行時に
イメージにリンクされる。ELF 共有ライブラリのテーブルは、共有ライブラリが実行時
にイメージにリンクされるときに、ダイナミックリンカ(dynamic linker)によっても
使用される。
Linux は、<tt>ld.so.1, libc.so.1, ld-linux.so.1</tt> などいくつかのダイナミック
リンカを使用しており、それらは <tt>/lib</tt> に置かれている。ライブラリには、
言語のサブルーチンなどのよく使用されるコードが含まれている。ダイナミックリンカ
がないと、すべてのプログラムはこれらのライブラリのコピーを自分で所有しなければ
ならず、今よりもかなり多くのディスク容量と仮想メモリを要することになってしま
う。
ダイナミックリンクが使用される場合、参照されるすべてのライブラリルーチンに関
する情報が ELF のイメージテーブルに含まれている。その情報は、ダイナミック
リンカに対して、ライブラリルーチンを探すべき場所とプログラムのアドレス空間に
それをリンクする方法と指示するものである。

<!--
REVIEW NOTE: Do I need more detail here, worked example? 
-->
<p>REVIEW NOTE: 実行時の動作などを、もっと詳しく説明すべきだろうか？

<!--4.8.2  Script Files-->
<sect2>スクリプトファイル

<!--
Script files are executables that need an interpreter to run them. There are a
wide variety of interpreters available for Linux; for example wish, perl and 
command shells such as tcsh. Linux uses the standard Unux TM convention of 
having the first line of a script file contain the name of the interpreter. 
So, a typical script file would start: 
-->
<p>スクリプトファイルは、その実行にインタープリタを必要とする実行ファイル
である。Linux 上で入手可能なインタープリタは非常に多種類ある。たとえば、<tt>
wish, perl</tt>, それに <tt>bash</tt> のようなコマンドシェルである。Linux で
は、標準的な Unix の慣習に従って、スクリプトファイルの最初の一行にインタープリ
タの名前を書くようになっている。典型的なスクリプトファイルは次にように始まる。

<verb>
#!/usr/bin/wish
</verb>

<!--
The script binary loader tries to find the intepreter for the script. 
It does this by attempting to open the executable file that is named in the 
first line of the script. If it can open it, it has a pointer to its VFS inode
and it can go ahead and have it interpret the script file. The name of the 
script file becomes argument zero (the first argument) and all of the other 
arguments move up one place (the  original first argument becomes the new 
second argument and so on). Loading the interpreter is done in the same way as
Linux loads all of its executable files. Linux tries each binary format in 
turn until one works. This means that you could in theory stack several 
interpreters and binary formats making the Linux binary format handler a very 
flexible piece of software. 
-->
<p>スクリプトのバイナリーローダは、そのスクリプトのインタープリタを探そうとす
る。
<newline>[see: do_load_script(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/fs/binfmt_script.c" 
name="fs/binfmt_script.c">]<newline>
そのためにローダは、スクリプトの最初の行で指名されている実行ファイルを
オープンしてみる。オープンできたなら、そのインタープリタは、オープンした
ファイルの VFS inode に対するポインタを所持し、さらに先を読み込んで、
スクリプトファイルを解釈する。スクリプトファイルの名前は、引数 0 (最初の
引数)となり、他のすべての引数の番号がひとつずつ上がる(すなわち、もともと最初に
あった引数は新たに第二引数となり、以下それに続く)。インタープリタのロードは、
Linux が他の実行ファイルをロードする方法と同じである。Linux は、実行に成功する
まで、個々のバイナリフォーマットを順番に試す。つまり、理論的には、いくつかの
インタープリタとバイナリフォーマットを用意しておいて、Linux のバイナリ
フォーマットハンドラを非常に柔軟なソフトウェアにすることが可能なのである。


<!--
Footnotes:

1 REVIEW NOTE: I left out SWAPPING because it does not appear to be used. 

2 Think of a nut the kernel is the edible bit in the middle and the shell goes
around it, providing an interface. 
-->
<p>
<label id="chapter_p_fn1">
<footnote>
(脚注1)REVIEW NOTE: スワッピング(SWAPPING)状態はわざと省いた。使われている
とは思えないからだ。<newline>
(脚注2)木の実に例えると、カーネルは中心の食べられる部分であり、シェルが
その周りを囲んで、インターフェイスを提供している。
</footnote>

<!--第  6 章 プロセス間通信-->
<!--Chapter 5 Interprocess Communication Mechanisms-->
<sect>プロセス間通信の仕組み<label id="chapter_ipc">
<p>
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/penguin2.gif">
</figure>

<!--
Processes communicate with each other and with the kernel to coordinate their
activities. Linux supports a number of Inter-Process Communication (IPC)
mechanisms. Signals and pipes are two of them but Linux also supports the
System V IPC mechanisms named after the Unix TM release in which they first
appeared. 
-->
<p>プロセスは、他のプロセスやカーネルと相互に通信することで、自らの作業の調整
を図っている。Linux では、いくつかのプロセス間通信(Inter-Process 
Communication, IPC)のメカニズムがサポートされている。シグナルとパイプは
その典型であるが、Linux は System V IPC メカニズムもサポートしている。System V
 IPC という名称は、Unix の当該リリースで初めて登場したことからその名が付けられ
ている。

<!--5.1  Signals-->
<sect1>シグナル<label id="chapter_ipc_sect1">

<!--
Signals are one of the oldest inter-process communication methods used by Unix
TM systems. They are used to signal asynchronous events to one or more
processes. A signal could be generated by a keyboard interrupt or an error
condition such as the process attempting to access a non-existent location in 
its virtual memory. Signals are also used by the shells to signal job control
commands to their child processes. 
-->
<p>シグナルは、Unix システムで使用される最も古いプロセス間通信の方法である。
シグナルは、ひとつ以上のプロセスに対して非同期イベント(asynchronous events)を
伝達するために使用される。シグナルが生成されるのは、キーボード割り込みがあっ
たり、プロセスが仮想メモリ内に存在しない場所にアクセスしようとしてエラーが起
きたときなどである。シグナルは、シェルが子プロセスに対してジョブ制御の信号を
伝達するときにも利用される。

<!--
There are a set of defined signals that the kernel can generate or that can be
generated by other processes in the system, provided that they have the correct
privileges. You can list a system's set of signals using the kill command 
(kill -l), on my Intel Linux box this gives: 
-->
<p>一連の定義済みシグナルがあり、それらはカーネルによって生成されるが、正しい
権限を与えられているなら、システム上のカーネル以外のプロセスでも生成が可能で
ある。<tt>kill</tt> コマンド (<tt>kill -l</tt>) を使用すれば、システム上で
利用可能なシグナルのリストを得ることができる。わたしの Intel の Linux ボック
スでは次のような結果が表示された。

<verb>
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL
 5) SIGTRAP      6) SIGIOT       7) SIGBUS       8) SIGFPE
 9) SIGKILL     10) SIGUSR1     11) SIGSEGV     12) SIGUSR2
13) SIGPIPE     14) SIGALRM     15) SIGTERM     17) SIGCHLD
18) SIGCONT     19) SIGSTOP     20) SIGTSTP     21) SIGTTIN
22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO
30) SIGPWR      
</verb>

<!--
The numbers are different for an Alpha AXP Linux box. Processes can choose to
ignore most of the signals that are generated, with two notable exceptions:
neither the SIGSTOP signal which causes a process to halt its execution nor the
SIGKILL signal which causes a process to exit can be ignored. Otherwise
though, a process can choose just how it wants to handle the various signals.
Processes can block the signals and, if they do not block them, they can either
choose to handle them themselves or allow the kernel to handle them. If the
kernel handles the signals, it will do the default actions required for this 
signal. For example, the default action when a process receives the SIGFPE 
(floating point exception) signal is to core dump and then exit. Signals have 
no inherent relative priorities. If two signals are generated for a process at
the same time then they may be presented to the process or handled in any 
order. Also there is no mechanism for handling multiple signals of the same 
kind. There is no way that a process can tell if it received 1 or 42 SIGCONT 
signals. 
-->
<p>シグナルの番号は、Alpha AXP の Linux ボックスでは異なったものになる。プロセ
スは、生成されたシグナルの大部分を無視することもできるが、ふたつだけ有名な
例外がある。プロセスの実行を停止させる SIGSTOP シグナルと、プロセスを終了させ
る SIGKILL シグナルであり、これらは無視できない。それ以外については、プロセス
が様々なシグナルをどう処理するかを自分で選択できる。プロセスはシグナルを
ブロックすることができるが、ブロックしない場合は、自分自身で処理するか、
あるいはカーネルに処理してもらうこともできる。
カーネルがシグナルを処理する場合、そのシグナル
が要求するデフォルトの行為が実行される。たとえば、プロセスが SIGFPE (floatin 
point exception)シグナルを受け取った際のデフォルトの行為は、core dump を行って
終了することである。シグナルには、内在的な相対的優先順位といったものはない。
ひとつのプロセスに対してふたつのシグナルが同時に生成された場合、それらがプロ
セスに渡される順番も、プロセスが処理すべき順番も決まっていない。また、同じ
種類の重複したシグナルを処理するメカニズムというのも存在しない。プロセスは、
SIGCOUNT をひとつだけ受け取ったのか、それともそれを 42 個受け取ったのかと
いうことを伝えるべき方法を持たない。

<!--
Linux implements signals using information stored in the task_struct for the
process. The number of supported signals is limited to the word size of the
processor. Processes with a word size of 32 bits can have 32 signals whereas 64
bit processors like the Alpha AXP may have up to 64 signals. The currently
pending signals are kept in the signal field with a mask of blocked signals 
held in blocked. With the exception of SIGSTOP and SIGKILL, all signals can be
blocked. If a blocked signal is generated, it remains pending until it is 
unblocked. Linux also holds information about how each process handles every 
possible signal and this is held in an array of sigaction data structures 
pointed at by the task_struct for each process. Amongst other things it 
contains either the address of a routine that will handle the signal or a flag
which tells Linux that the process either wishes to ignore this signal or let 
the kernel handle the signal for it. The process modifies the default signal 
handling by making system calls and these calls alter the sigaction for the 
appropriate signal as well as the blocked mask. 
-->
<p>Linux のシグナルの実装では、プロセスの <tt><ref id="task_struct" 
name="task_struct"></tt> 構造体に保存された情報が利用される。
サポートされるシグナルの数は、プロセッサのワード(<ref id="chapter_g_word" 
name="word">)サイズに制限されている。
32 ビットのワードサイズを持つプロセッサは、32 個のシグナルを持つことが出来る
が、Alpha AXP のような 64 ビットプロセッサでは 64 個までである。
まだ処理の済んでいないシグナルは、<tt>task_struct</tt> の <tt><ref 
id="task_struct" name="signal"></tt> フィールドに保存され、<tt><ref 
id="task_struct" name="blockd"></tt> フィールドにブロックされたシグナルの
シグナルマスク(<ref id="signal_mask" name="signal mask">)が保持される。
SIGSTOP と SIGKILL を除いて、すべてのシグナルはブロックすることができる。
ブロックされたシグナルが生成されると、それはブロックを解除されるまで未処理
状態に留まる。また、Linux は、個々のプロセスが受け取るかもしれないあらゆる
シグナルをどう処理するのかに関する情報を保持しているのだが、その情報は <tt>
<ref id="sigaction" name="sigaction"></tt> データ構造体の配列に保存され、個々
のプロセスの <tt>task_struct</tt> データ構造体によってポイントされている。
それ以外にも、<tt>task_struct
</tt> には、シグナルを処理するルーチンのアドレスか、もしくはフラグのいずれか
が含まれている。フラグを使う場合、プロセスは、当該シグナルを無視するか、
そのシグナルの処理をカーネルに代行させるかをそのフラグによって Linux に伝える。
プロセスは、システムコールを使ってシグナルに対するデフォルト処理を変更すること
ができ、そのシステムコールによって適切なシグナルに関する <tt>sigaction</tt> 
構造体を変更したり、<tt>blockd</tt> マスクを変化させたりする。

<!--
Not every process in the system can send signals to every other process, the
kernel can and super users can. Normal processes can only send signals to
processes with the same uid and gid or to processes in the same process group1.
Signals are generated by setting the appropriate bit in the task_struct's
signal field. If the process has not blocked the signal and is waiting but
interruptible (in state Interruptible) then it is woken up by changing its 
state to Running and making sure that it is in the run queue. That way the 
scheduler will consider it a candidate for running when the system next 
schedules. If the default handling is needed, then Linux can optimize the 
handling of the signal. For example if the signal SIGWINCH (the X window 
changed focus) and the default handler is being used then there is nothing to 
be done. 
-->
<p>システム上の全プロセスが他のどのプロセスにもシグナルを送れるというわけでは
ないが、カーネルとスーパーユーザにはそれが可能である。通常のプロセスは、
同じ <tt>uid</tt> や <tt>gid</tt> を持つプロセスか、同じプロセスグループに
属するプロセスにのみシグナルを送れる。<ref id="chapter_ipc_fn" name="(脚注1)">
シグナルの生成は、<tt><ref id="task_struct" 
name="task_struct"></tt> の <tt>signal</tt> フィールドにある適切なビットを
セットすることにより為される。プロセスがシグナルをブロック
しておらず、待機中だが割り込み可能な(INTERRUPTIBLE な)状態にある場合、そのプロ
セスは、目を覚まして実行中(RUNNING)状態に置かれ、実行キューへ登録されて、その
登録を確認される。それによって、スケジューラは、システムの次のスケジュールに
おいて、そのプロセスを実行の候補者と見なす。デフォルトの処理が必要な場合、
Linux はそのシグナルの処理を最適化できる。たとえば、シグナル SIGWINCH 
(X Window のフォーカス変更)が生成され、それに対してデフォルトのハンドラが使用
される場合は、そのハンドラによって適切な処理がなされるので、それ以外の特別な
処理はなされない。

<!--
Signals are not presented to the process immediately they are generated., they
must wait until the process is running again. Every time a process exits from a
system call its signal and blocked fields are checked and, if there are any
unblocked signals, they can now be delivered. This might seem a very unreliable
method but every process in the system is making system calls, for example to
write a character to the terminal, all of the time. Processes can elect to 
wait for signals if they wish, they are suspended in state Interruptible until
a signal is presented. The Linux signal processing code looks at the sigaction
structure for each of the current unblocked signals. 
-->
<p>シグナルは生成されてすぐにプロセスに渡されるわけではない。それらはプロセスが
再び実行されるまで待たなければならない。プロセスがシステムコールによって終了
するときはいつでも、<tt><ref id="task_struct" name="signal"></tt> と <tt>
<ref id="task_struct" name="blocked"></tt> フィールドがチェック
され、もしプロセスが予めブロックしていないシグナルが存在する場合は、その時点で
ようやくプロセスにシグナルを渡すことができる。これは非常に信頼性の低い方法に
思われるかもしれないが、システム内のすべてのプロセスは、始終システムコールを
発して、たとえば、端末に文字を書き込んだりしているので、こうした仕組みはやむを
得ないものである。しかし、プロセスは、自分が望む場合は、自らシグナル待ちの
状態になることもできる。その場合、シグナルが送られるまで、割り込み可能な
サスペンド状態となる。その際、Linux のシグナル処理のコードは、現在ブロック
されていないシグナルを受け取るたびに、<tt><ref id="sigaction" 
name="sigaction"></tt> 構造体を調べる。

<!--
If a signal's handler is set to the default action then the kernel will handle
it. The SIGSTOP signal's default handler will change the current process's 
state to Stopped and then run the scheduler to select a new process to run. 
The default action for the SIGFPE signal will core dump the process and then 
cause it to exit. Alternatively, the process may have specfied its own signal 
handler. This is a routine which will be called whenever the signal is 
generated and the sigaction structure holds the address of this routine. The 
kernel must call the process's signal handling routine and how this happens is
processor specific but all CPUs must cope with the fact that the current 
process is running in kernel mode and is just about to return to the process 
that called the kernel or system routine in user mode. The problem is solved 
by manipulating the stack and registers of the process. The process's program 
counter is set to the address of its signal handling routine and the 
parameters to the routine are added to the call frame or passed in registers. 
When the process resumes operation it appears as if the signal handling 
routine were called normally. 
-->
<p>プロセスのシグナルハンドラがデフォルトにセットされている場合、カーネルが
そのシグナルを処理する。SIGSTOP シグナルのデフォルトのハンドラは、現在のプロ
セスの状態を停止状態(STOPPED)とし、スケジューラを起動して新しいプロセスを実行
する。SIGFPE シグナルのデフォルトの処理は、そのプロセスに core dump させ、
それを終了させる。反対に、プロセスが自分自身のシグナルハンドラを指定すること
もできる。これは、そのシグナルが生成されると必ず呼び出されるルーチンとな
り、<tt><ref id="sigaction" name="sigaction"></tt> 構造体がそのルーチンのアド
レスを保持する。その場合、カーネルはプロセスのシグナル処理ルーチンを呼び出
さなければならず、その呼び出し方法はプロセッサに固有のものであるが、
すべての CPU が対処しなければならない事実として、カーネルモードで実行されて
いるカレントプロセスは、カーネルやシステムルーチンを呼び出した時のユーザモー
ドのプロセスへと戻ろうとしているということである。
この問題を解決するために、プロセスのスタックとレジスタが操作される。プロセスの
プログラムカウンタには、そのシグナル処理ルーチンのアドレスが設定され、
そのルーチンへのパラメータがコールフレームに付加されるか、レジスタに渡される。
プロセスが再び実行を開始するとき、シグナル処理ルーチンは通常通り呼び出された
かのように見える。

<!--
Linux is POSIX compatible and so the process can specify which signals are
blocked when a particular signal handling routine is called. This means 
changing the blocked mask during the call to the processes signal handler. The
blocked mask must be returned to its original value when the signal handling 
routine has finished. Therefore Linux adds a call to a tidy up routine which 
will restore the original blocked mask onto the call stack of the signalled 
process. Linux also optimizes the case where several signal handling routines 
need to be called by stacking them so that each time one handling routine 
exits, the next one is called until the tidy up routine is called. 
-->
<p>Linux は POSIX に準拠しているので、プロセスは、特定のシグナル処理ルーチン
が呼び出されたとき、そのシグナルをブロックするかどうか指定ができる。
これは、プロセスのシグナル処理ルーチンの呼び出しがなされている間にブロック
マスクを変更することを意味する。シグナル処理ルーチンが終了したら、そのブロック
マスクの値は元に戻されなければならない。したがって、Linux は、片づけ用のルー
チン(tidy up routine)へのコールを追加して、そのルーチンがシグナルを受け取った
プロセスのコールスタック上のブロックマスクを元に戻す。
また、Linux は、複数のシグナル処理ルーチンの呼び出しが必要な場合、それらを
スタックに積んでおいて、ひとつの処理ルーチンが終了したら次のルーチンを呼び出す
操作を繰り返して、最後に片づけルーチンを呼び出すという方法でそうした処理を最適
化している。

<!--5.2  Pipes-->
<sect1>パイプ<label id="chapter_ipc_sect2">

<!--
The common Linux shells all allow redirection. For example 
-->
<p>一般的な Linux シェルは、すべてリダイレクション(redirection)をサポートして
いる。たとえば、次のようなリダイレクションがある。

<tscreen><verb>
$ ls | pr | lpr
</verb></tscreen>

<!--
pipes the output from the ls command listing the directory's files into the
standard input of the pr command which paginates them. Finally the standard
output from the pr command is piped into the standard input of the lpr command
which prints the results on the default printer. Pipes then are unidirectional
byte streams which connect the standard output from one process into the 
standard input of another process. Neither process is aware of this 
redirection and behaves just as it would normally. It is the shell which sets 
up these temporary pipes between the processes. 
-->
<p>上記の例では、ディレクトリ内のファイルを表示する <tt>ls</tt> コマンドの
出力をパイプ処理して、<tt>pr</tt> コマンドの標準入力に振り向けて、<tt>pr</tt> 
にページ処理をさせる。そうして、そのコマンド出力をパイプ処理して、<tt>lpr</tt> 
コマンドの標準入力に振り向けて、デフォルトプリンタ上でその結果をプリントさせ
ている。すなわち、パイプとは、あるプロセスの標準出力を別のプロセスの標準入力
へと繋ぐ、片方向性をもったバイトストリームである。その場合、どちらのプロセス
もリダイレクションを意識せず、通常通りに振る舞う。プロセス間にそれらの一時的
なパイプを設定するのはシェルの役目である。

<label id="figure5-1">
<!--                        Figure 5.1: Pipes-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure5-1.gif">
</figure>
</#if>
<#unless output="html">
<verb>
 プロセス 1                             プロセス 2

    file                                  file
+-----------+                         +-----------+
| f_mode    |                         | f_mode    |
|-----------|                         |-----------|
| f_pos     |                         | f_pos     |
|-----------|                         |-----------|
| f_flags   |                         | f_flags   |
|-----------|                         |-----------|
| f_count   |                         | f_count   |
|-----------|                         |-----------|
| f_owner   |      +---------------+  | f_owner   |
|-----------|      |               |  |-----------|
| f_inode   |---+  |    inode      |  | f_inode   |-----+
|-----------|   |  |  +---------+  |  |-----------|     |
| f_op      |-+ |  +->|         |  |  | f_op      |--+  |
|-----------| | +---->|         |  |  |-----------|  |  |
| f_version | |       |         |  |  | f_version |  |  |
+-----------+ |       |         |  |  +-----------+  |  |
              |       |         |  |                 |  |
              |/      +---------+  +-----------------+--+
              *               |                      |
            パイプ            |       データページ   |
            書き込み          |       +-----------+  |
            操作ルーチン      |       |           |  |/
                              +------>|           |  *
                                      |           | パイプ
                                      |           | 読み出し
                                      |           | 操作ルーチン
                                      |           |
                                      |           |
                                      |           |
                                      +-----------+
</verb>
</#if>
<p>図表(5.1) パイプ

<!--
In Linux, a pipe is implemented using two file data structures which both point
at the same temporary VFS inode which itself points at a physical page within
memory. Figure  5.1 shows that each file data structure contains pointers to
different file operation routine vectors; one for writing to the pipe, the 
other for reading from the pipe. 
This hides the underlying differences from the generic system calls which read
and write to ordinary files. As the writing process writes to the pipe, bytes 
are copied into the shared data page and when the reading process reads from 
the pipe, bytes are copied from the shared data page. Linux must synchronize 
access to the pipe. It must make sure that the reader and the writer of the 
pipe are in step and to do this it uses locks, wait queues and signals. 
-->
<p>Linux において、パイプの実装には、ふたつの <tt><ref id="file" name="file">
</tt> データ構造体が使用される。メモリ内のある物理ページをポイントする VFS 
inode を一時的に作成して、それをふたつの構造体で同時にポイントするのである。
図表(5.1)では、それぞれの <tt>file</tt> データ構造体が、ファイル操作ルーチン
の配列の異なる要素をポイントしている様子が示されている。ひとつは、パイプへ
の書き込みであり、もうひとつは、パイプからの読み出しである。
<newline>[see: include/linux/inode_fs_i.h](ママ)
(訳注: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/pipe_fs_i.h" 
name="pipe_fs_i.h"> ？)<newline>
この方法では、通常ファイルへの書き込み処理と読み出し処理をする汎用システム
コール間にある基礎的な違いは隠蔽される。書き込みプロセスがパイプに書き込むと
き、バイト列は共有データページにコピーされ、読み出しプロセスがパイプから読み
出すときは、バイト列がその共有データページからコピーされる。Linux は、その
パイプへのアクセスを同期させなければならない。Linux は、パイプからの読み出し
と、そこへの書き込みとが確実に歩調を合わせるようにしなければならず、そのため
に Linux は、ロック(<ref id="chapter_km_sect5" name="lock">)や待ち行列(<ref 
id="chapter_km_sect4" name="wait queue">)やシグナル(signal)といった仕組
みを利用している。

<!--
When the writer wants to write to the pipe it uses the standard write library
functions. These all pass file descriptors that are indices into the process's
set of file data structures, each one representing an open file or, as in this
case, an open pipe. The Linux system call uses the write routine pointed at by
the file data structure describing this pipe. That write routine uses 
information held in the VFS inode representing the pipe to manage the write 
request. 
If there is enough room to write all of the bytes into the pipe and, so long 
as the pipe is not locked by its reader, Linux locks it for the writer and 
copies the bytes to be written from the process's address space into the 
shared data page. If the pipe is locked by the reader or if there is not 
enough room for the data then the current process is made to sleep on the pipe
inode's wait queue and the scheduler is called so that another process can 
run. It is interruptible, so it can receive signals and it will be woken by 
the reader when there is enough room for the write data or when the pipe is 
unlocked. When the data has been written, the pipe's VFS inode is unlocked and
any waiting readers sleeping on the inode's wait queue will themselves be 
woken up. 
-->
<p>書き込みプロセスがパイプに書き込もうとするときは、標準の書き込みライブラリ
関数を使用する。
それらの間でやり取りされるファイルディスクリプタはすべて、書き込みプロセ
スが持つ一連の <tt><ref id="file" name="file"></tt> データ構造体へのインデッ
クスとなっていて、それら個々の構造体がオープンされたファイル、この場合には
オープンされたパイプを表している。
Linux のシステムコールが使用する書き込みルーチンは、そのパイプを記述する 
<tt>file</tt> データ構造体によってポイントされたルーチンである。書き込み
ルーチンが書き込み要求を処理する際に利用する情報は、そのパイプを表す VFS <tt>
<ref id="inode" name="inode"></tt> に保持された情報である。
<newline>[see: pipe_write(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/fs/pipe.c" 
name="fs/pipe.c">]<newline>
パイプへ書き込もうとする全バイト量を保持するだけの空きが共有ページ上に存在し、
パイプが読み出しプロセスによってロックされていない場合、Linux は書き込み
プロセスのためにそのパイプをロックして、書き込まれるべきバイト列を書き込み
プロセスのアドレス空間から共有データページにコピーする。
パイプが読み出しプロセスによってロックされているか、データを保持する充分な空
きスペースが存在しない場合は、現在のプロセスがパイプの <tt>inode</tt> の待ち
行列上でスリープ状態にされ、スケジューラが呼び出されて、他のプロセスが実行
される。
書き込みプロセスは割り込み可能であるので、シグナルの受信が可能である。
書き込みプロセスは、データ書き込みのための充分なスペースが確保されるか
パイプのロックが解除されたときに、読み込みプロセスによってスリープ状態から
起こされる。
データが書き込まれるとき、パイプの VFS inode のロックは解除され、
その inode の待ち行列上でスリープ状態になっている読み出しプロセスがあれば、
読み出しプロセスもそれによって目を覚ます。

<!--
Reading data from the pipe is a very similar process to writing to it. 
Processes are allowed to do non-blocking reads (it depends on the mode in
which they opened the file or pipe) and, in this case, if there is no data to 
be read or if the pipe is locked, an error will be returned. This means that 
the process can continue to run. The alternative is to wait on the pipe 
inode's wait queue until the write process has finished. When both processes 
have finished with the pipe, the pipe inode is discarded along with the shared
data page. 
-->
<p>パイプからのデータの読み出しは、書き込みプロセスと非常によく似ている。
<newline>[see: pipe_read(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/fs/pipe.c" 
name="fs/pipe.c">]<newline>
プロセスは、ブロッキングしない読み出し(non-blocking read)をすることも
許される。(それは、プロセスがファイルやパイプをオープンするときのモードに
依存する。)そして、その場合、読み出すべきデータがないか、パイプがロックされて
いる場合は、エラーが返される。これは、そのプロセスが実行を継続できることを
意味する。それ以外の方法として、パイプの inode の待ち行列上で休止して、書き込み
プロセスの終了を待つことも可能である。両方のプロセスがパイプ処理を終了する
と、パイプの inode とその共有データページとは破棄される。

<!--
Linux also supports named pipes, also known as FIFOs because pipes operate on
a First In, First Out principle. The first data written into the pipe is the 
first data read from the pipe. Unlike pipes, FIFOs are not temporary objects, 
they are entities in the file system and can be created using the mkfifo 
command. Processes are free to use a FIFO so long as they have appropriate 
access rights to it. The way that FIFOs are opened is a little different from 
pipes. A pipe (its two file data structures, its VFS inode and the shared data
page) is created in one go whereas a FIFO already exists and is opened and 
closed by its users. Linux must handle readers opening the FIFO before writers
open it as well as readers reading before any writers have written to it. That
aside, FIFOs are handled almost exactly the same way as pipes and they use the
same data structures and operations. 
-->
<p>Linux は、名前付きパイプもサポートしている。パイプは先入れ先出し(First In,
 First Out)の原理で処理を行うので、名前付きパイプは FIFO とも呼ばれる。
パイプに書き込まれた最初のデータは、パイプから読み出される最初のデータとな
る。通常のパイプとは異なり、FIFO は一時的なオブジェクトではなく、ファイルシス
テム内の実体であり、<tt>mkfifo</tt> コマンドによって作成が可能である。
プロセスは、それに対する適切なアクセス権限を持つ限り、自由に FIFO を利用する
ことができる。FIFO をオープンする方法は、通常のパイプのそれとは少し異なる。
通常のパイプ(ふたつの <tt>file</tt> データ構造体、VFS inode とその共有データ
ページのセット)は必要に応じて一時的に作成されるだけだが、FIFO はすでに
存在する実体であり、ユーザによってオープンされ、クローズされる。Linux は、
書き込みプロセスが FIFO をオープンする前に読み出しプロセスにそれをオープンさ
せ、書き込みプロセスがそれに書き込んでしまう前に読み出しプロセスがそれを読める
状態にするよう、それらを操作しなければならない。しかし、そうした
ことを除くと、FIFO の処理は、通常のパイプの処理方法とほとんど全く同一であり、
両者は同じデータ構造と処理メカニズムを使っている。


<!--5.3  Sockets-->
<sect1>ソケット<label id="chapter_ipc_sect3">
<p>
REVIEW NOTE: Add when networking chapter written. 


<!--5.3.1  System V IPC Mechanisms-->
<sect2>System V IPC のメカニズム<label id="chapter_ipc_sect3-1">

<!--
Linux supports three types of interprocess communication mechanisms that first
appeared in Unix TM System V (1983). These are message queues, semaphores
and shared memory. These System V IPC mechanisms all share common
authentication methods. Processes may access these resources only by passing
a unique reference identifier to the kernel via system calls. Access to these
System V IPC objects is checked using access permissions, much like accesses
to files are checked. The access rights to the System V IPC object is set by 
the creator of the object via system calls. The object's reference identifier 
is used by each mechanism as an index into a table of resources. It is not a 
straight forward index but requires some manipulation to generate the index. 
-->
<p>Linux は、Unix System V (1983) で初めて登場したプロセス間通信(IPC)の仕組み
を 3 種類サポートしている。それらは、メッセージキュー(message queue)、セマフォ
(semaphore)、そして共有メモリ(shared memory)である。これらの System V IPC の
仕組みはすべて共通の認証方法を利用している。プロセスが共有リソースに
アクセスできるのは、システムコール経由でカーネルに対してユニークな参照識別子
(reference identifier)を渡した場合だけである。
これらの System V IPC オブジェクトへのアクセスをチェックする
場合には、アクセスパーミッションが使用されるが、それはファイルへのアクセス
チェックに類似したものである。System V IPC オブジェクトへのアクセス権限は、
そのオブジェクトの作成者によってシステムコール経由で設定される。個々の IPC 
メカニズムは、オブジェクトの参照識別子を、リソーステーブルへのインデックスと
して利用している。しかし、それは単純なインデックスではなく、そのインデックス
作成には多少の操作を必要とする。

<!--
All Linux data structures representing System V IPC objects in the system
include an ipc_perm structure which contains the owner and creator process's 
user and group identifiers. The access mode for this object (owner, group and 
other) and the 
IPC object's key. The key is used as a way of locating the System V IPC 
object's reference identifier. Two sets of keys are supported: public and 
private. If the key is public then any process in the system, subject to 
rights checking, can find the reference identifier for the System V IPC 
object. System V IPC objects can never be referenced with a key, only by their
reference identifier. 
-->
<p>Linux システム上で System V IPC オブジェクトを表すすべてのデータ構造には、
<tt><ref id="ipc_perm" name="ipc_perm"></tt> 構造体が含まれている。そして、
その構造体には、そのオブジェクトの所有プロセスおよび作成プロセスのユーザ ID 
とグループ ID とが含まれる。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/ipc.h" 
name="include/linux/ipc.h">]<newline>
また、<tt>ipc_perm</tt> には、そのオブジェクトへのアクセスモード(所有者、
グループ、その他)と IPC オブジェクトキー(<tt><ref id="ipc_perm" name="key">
</tt>)も含まれている。
キーは、System V IPC オブジェクトの参照識別子を探す手段として使用される。
サポートされているキーには、プライベート(private)とパブリック(public)の二種類
がある。キーがパブリックの場合、どのようなプロセスでも、アクセス権をチェック
された後、その System V IPC オブジェクトの参照識別子を見つけることができる。
System V IPC オブジェクトは、キーでは参照できないようになっていて、その参照
識別子でのみ参照が可能となっている。

<!--5.3.2  Message Queues-->
<sect2>メッセージキュー<label id="chapter_ipc_sect3-2">

<!--
Message queues allow one or more processes to write messages, which will be
read by one or more reading processes. Linux maintains a list of message
queues, the msgque vector; each element of which points to a msqid_ds data
structure that fully describes the message queue. When message queues are
created a new msqid_ds data structure is allocated from system memory and
inserted into the vector. 
-->
<p>メッセージキュー(message queue)とは、ひとつ以上のプロセスがメッセージを書
き込んで、それをひとつ以上の読み出しプロセスによって読み出すことを可能にする
仕組みである。Linux は、メッセージキューのリストを <tt><ref id="msqid_ds" 
name="msque" ></tt> 配列によって管理している。この配列の個々の要素は、
<tt><ref id="msqid_ds" name="msqid_ds"></tt> データ構造体をポイントしてい
て、その構造体が個々のメッセージキューを完全に記述している。メッセージキューが
作成されるとき、新しい <tt>msqid_ds</tt> データ構造体がシステムメモリから割り
当てられ、配列のなかに挿入される。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/msg.h" 
name="include/linux/msg.h">]<newline>

<!--              Figure 5.2: System V IPC Message Queues-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure5-2.gif">
</figure>
</#if>
<#unless output="html">
<verb>
   msqid_ds
+--------------+
|              |
|  ipc         |
|              |
|--------------|
|              |
|--------------|
|  *msg_last   |                msg                      msg
|--------------|            +------------+            +-----------+
|  *msg_first  |----------->| *msg_next  |----------->| *msg_next |
|--------------|            |------------|            |-----------|
|              |            | msg_type   |            | msg_type  |
|  times       |            |------------|            |-----------|
|              |            | *msg_spot  |            | *msg_spot |
|--------------|            |------------|            |-----------|
|  *wwait      |            | msg_stime  |            | msg_stime |
|--------------|            |------------|            |-----------|
|  *rwait      |            | msg_ts     |            | msg_ts    |
|--------------|       *    |------------|       *    |-----------|
|              |      /|    |            |      /|    |           |
|--------------|       |    |            |       |    |           |
|  msg_qnum    |       |    |            |       |    |           |
|--------------|     msg_ts |  message   |     msg_ts |  message  |
|              |       |    |            |       |    |           |
+--------------+       |    |            |       |    |           |
                       |/   |            |       |/   |           |
                       *    +------------+       *    +-----------+

                            <---------------- msg_qnum ----------->
</verb>
</#if>
<p>図表(5.2)System V IPC メッセージキュー


<!--
Each msqid_ds 
data structure contains an ipc_perm data structure and pointers to the
messages entered onto this queue. In addition, Linux keeps queue modification
times such as the last time that this queue was written to and so on. The
msqid_ds also contains two wait queues; one for the writers to the queue and
one for the readers of the message queue. 
-->
<p>個々の <tt><ref id="msqid_ds" name="msqid_ds"></tt> 構造体には、<tt>
<ref id="ipc_perm" name="ipc_perm"></tt> データ構造体とそのキューに入れられた
メッセージへのポインタが含まれている。さらに、Linux は、キューの変更時間を記録
しており、たとえばそのキューに書き込みがなされた最後の時間といった情報を保持
している。<tt>msqid_ds</tt> には、ふたつの待ち行列が含まれていて、それぞれ
メッセージキューへの書き込みプロセスに対するものと読み出しプロセスに対する
ものとなっている。

<!--
Each time a process attempts to write a message to the write queue its 
effective user and group identifiers are compared with the mode in this 
queue's ipc_perm data structure. If the process can write to the queue then 
the message may be copied from the process's address space into a msg 
data structure and put at the end of this message queue. Each message is tagged
with an application specific type, agreed between the cooperating processes.
However, there may be no room for the message as Linux restricts the number
and length of messages that can be written. In this case the process will be
added to this message queue's write wait queue and the scheduler will be called
to select a new process to run. It will be woken up when one or more messages
have been read from this message queue. 
-->
<p>プロセスが書き込みキューにメッセージを書き込もうとするときはいつも、その
実効ユーザ ID と実効グループ ID とが、そのキューの <tt>ipc_perm</tt> データ
構造体にあるモードと比較される。
プロセスがそのキューに書き込み可能な場合、メッセージは、そのプロセスのアドレ
ス空間から <tt><ref id="msg" name="msg"></tt> データ構造体へとコピーされ、そ
のメッセージキューの最後に置かれる。個々のメッセージには、協調するプロセス間で
合意されたアプリケーション固有のタイプ(type)がタグ付けされる。しかし、Linux 
は、書き込み可能なメッセージの数と長さを制限しているので、メッセージの書き込み
の際に容量が足りない場合が生じ得る。その場合、そのプロセスが当該メッセージ
キューの書き込みキューに加えられ、スケジューラが呼び出されて、新しいプロセス
が実行される。そして、いくつかのメッセージがそのメッセージキューから読み出さ
れたときに、先ほどのプロセスが起こされる。

<!--
Reading from the queue is a similar process. Again, the processes access rights
to the write queue are checked. A reading process may choose to either get the
first message in the queue regardless of its type or select messages with
particular types. If no messages match this criteria the reading process will 
be added to the message queue's read wait queue and the scheduler run. When a
new message is written to the queue this process will be woken up and run 
again.
-->
<p>キューからの読み出しも同様の過程を辿る。再度、書き込みキューに対するプロセ
スのアクセス権がチェックされる。読み出しプロセスは、メッセージのタイプに関係
なくキューの最初のメッセージを取得するか、特定のタイプのメッセージを選択する
かのいずれかを選択することができる。選択基準に合致するメッセージがない場合、
読み出しプロセスはメッセージキューの読み出し待ち行列に加えられて、スケジュー
ラが実行される。新しいメッセージがキューに書き込まれると、そのプロセスは起こ
されて再び実行される。

<!--5.3.3  Semaphores-->
<sect2>セマフォ<label id="chapter_ipc_sect3-3">

<!--
In its simplest form a semaphore is a location in memory whose value can be
tested and set by more than one process. The test and set operation is, so far
as each process is concerned, uninterruptible or atomic; once started nothing 
can stop it. The result of the test and set operation is the addition of the 
current value of the semaphore and the set value, which can be positive or 
negative. Depending on the result of the test and set operation one process 
may have to sleep until the semphore's value is changed by another process. 
Semaphores can be used to implement critical regions, areas of critical code 
that only one process at a time should be executing. 
-->
<p>最も単純な形式で考えると、セマフォとは、複数のプロセスにより、ある値をテスト
(test)したりセット(set)したりすることが可能な、メモリ上の場所である。
テストとセットの操作は、個々のプロセスに関する限り、割り込みができない、もし
くは他のプロセスから干渉を受けない(atomic)操作である。すなわち、いったんプロ
セスが操作を始めると他のプロセスがそれを止めることはできない。テストとセット
の操作の結果は、そのセマフォの現在の値とセットした値との和となる。セットされ
る値は、正の場合も負の場合もある。テストとセットの操作の結果によっては、ある
プロセスが、他のプロセスによってセマフォの値が変更されるまで、休止しなければ
ならない場合が起こる。セマフォは、非常に重要なメモリ領域を作成したいときに
利用することができ、一度に単一のプロセスだけが実行すべき非常に重要なコードの
領域を作り出すことができる。

<!--
Say you had many cooperating processes reading records from and writing
records to a single data file. You would want that file access to be strictly
coordinated. You could use a semaphore with an initial value of 1 and, around 
the file operating code, put two semaphore operations, the first to test and 
decrement the semaphore's value and the second to test and increment it. The 
first process to access the file would try to decrement the semaphore's value 
and it would succeed, the semaphore's value now being 0. This process can now 
go ahead and use the data file but if another process wishing to use it now 
tries to decrement the semaphore's value it would fail as the result would 
be -1. That process will be suspended until the first process has finished 
with the data file. When the first process has finished with the data file it 
will increment the semaphore's value, making it 1 again. Now the waiting 
process can be woken and this time its attempt to increment the semaphore will
succeed. 
-->
<p>たとえば、協調して働く多くのプロセスがあり、それらは単一のファイルを読み込
んだり、それに書き込んだりしているとする。そして、そのファイルへのアクセスを
厳しく調整したいと思っているとする。その場合、セマフォを使い、初期値を 1 に
設定し、ファイル操作コードの中に、ふたつのセマフォ操作コードを加える。ひとつ
は、セマフォの値をテストして、その値から 1 を引くもの、もうひとつは、セマフォ
値をテストして値に 1 を足すものである。
ファイルにアクセスする最初のプロセスは、セマフォの値から 1 を引こうとし、それに
成功すればセマフォの値は 0 になる。このプロセスは処理を続けて、データファイル
を使用するが、もし次のプロセスがそれを使いたいと思ってセマフォの値から 1 を引こ
うとしても、その結果が -1 になってしまうので失敗する。
そのプロセスは、最初のプロセスがデータファイルの使用を終えるまで、停止状態に
なる。最初のプロセスがデータファイルの使用を終えたら、セマフォの値に 1 を足
して、1 に戻す。この時点で、待機していたプロセスが起こされて、今回はセマフォ値
に 1 を足す(訳注: -1 か？)ことに成功する。


<!--                Figure 5.3: System V IPC Semaphores-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure5-3.gif">
</figure>
</#if>
<#unless output="html">
<verb>
                                 +-------+
                        +------->|       |  セマフォ配列
                        |        |-------|
     semid_ds           |        |       |
+------------------+    |        |-------|
|                  |    |        |       |
| ipc              |    |        |-------|
|                  |    |        |       |
|------------------|    |        |-------|
|                  |    |        |       |
| times            |    |        |-------|
|                  |    |        |       |
|------------------|    |        +-------+
| sem_base         |----+                       sem_queue
|------------------|                           +---------+
| sem_pending      |-------------------------->| next    |
|------------------|                           |---------|
| sem_pending_last |     sem_undo              | prev    |
|------------------|  +-----------+            |---------|
| undo             |->| proc_next |            | sleeper |
|------------------|  |-----------|            |---------|
| sem_nsems        |  | id_next   |            | undo    |
+------------------+  |-----------|            |---------|
                      | semid     |            | pid     |
                      |-----------|  +------+  |---------|
                      | semadj    |->|      |  | status  |
                      +-----------+  |      |  |---------|
                                     |      |  | sma     |
                                     |      |  |---------|  +------+
                                     |      |  | sops    |->|      |
                                     |      |  |---------|  |      |
                                     |      |  | nsops   |  |      |
                                     +------+  +---------+  |      |
                                                            |      |
                                                            |      |
                                                            |      |
                                                            +------+
</verb>
</#if>
<p>図表(5.3)System V IPC セマフォ


<!--
System V IPC semaphore objects each describe a semaphore array and Linux
uses the semid_ds data structure to represent this. 
All of the semid_ds data structures in the
system are pointed at by the semary, a vector of pointers. There are
sem_nsems in each semaphore array, each one described by a sem data
structure pointed at by sem_base. All of the processes that are allowed to
manipulate the semaphore array of a System V IPC semaphore object may make
system calls that perform operations on them. The system call can specify many
operations and each operation is described by three inputs; the semaphore 
index, the operation value and a set of flags. The semaphore index is an index
into the semaphore array and the operation value is a numerical value that 
will be added to the current value of the semaphore. First Linux tests whether
or not all of the operations would succeed. An operation will succeed if the 
operation value added to the semaphore's current value would be greater than 
zero or if both the operation value and the semaphore's current value are 
zero. If any of the semaphore operations would fail Linux may suspend the 
process but only if the operation flags have not requested that the system 
call is non-blocking. If the process is to be suspended then Linux must save 
the state of the semaphore operations to be performed and put the current 
process onto a wait queue. It does this by building a sem_queue data structure
on the stack and filling it out. The new sem_queue data structure is put at 
the end of this semaphore object's wait queue (using the sem_pending and 
sem_pending_last pointers). The current process is put on the wait queue in 
the sem_queue data structure (sleeper) and the scheduler called to choose 
another process to run. 
-->
<p>System V IPC セマフォオブジェクトは、それぞれがセマフォ配列を記述しており、
Linux は、<tt><ref id="semid_ds" name="semid_ds"></tt> データ構造体を使用して
これを表現する。
<newline>[see <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/sem.h" 
name="include/linux/sem.h">]<newline>
システム上のすべての <tt>semid_ds</tt> データ構造体は、 <tt><ref id="semid_ds" 
name="semary"></tt> というポインタの配列によってポイントされている。
個々のセマフォ配列には、<tt><ref id="semid_ds" name="sem_nsems"></tt> 個の
要素があり、各々のセマフォ配列の要素は、<tt><ref id="sem" name="sem"></tt> 
データ構造体により記述されていて、<tt>sem</tt> 構造体は <tt><ref id="semid_ds" 
name="sem_base"></tt> によってポイントされている。
System V IPC セマフォオブジェクトから成るセマフォ配列の操作を許されているすべて
のプロセスは、システムコールを生成して、それらを操作する。
システムコールは多くの操作を指定することができるが、個々の操作は、セマフォ
インデックス(semaphore index)、オペレーション値(operation value)、および一連の
フラグ(a set of flag)という 3 つの入力項目によって記述される。
セマフォインデックスとは、セマフォ配列へのインデックスであり、オペレーション
値とは、セマフォの現在の値に加えるべき数値である。
Linux はまず、すべての操作が成功したかどうかをテストする。操作が成功するのは、
セマフォの現在の値にオペレーション値を加えた値がゼロより大きいか、もしくは
オペレーション値とセマフォの現在の値の両方がゼロの場合のいずれかである。
セマフォ操作がひとつでも失敗した場合で、他のプロセスをブロックしない
(non-blocking)システムコールをオペレーションフラグが要求しない場合、Linux は、
プロセスをサスペンドする。
プロセスがサスペンド状態になると、Linux は実行されるべきセマフォ操作の状態
(state)を保存して、現在のプロセスを待ち行列(wait queue)上に置かなければなら
ない。
その処理は、スタックに <tt><ref id="sem_queue" name="sem_queue"></tt> データ
構造体を作成して、必要な情報を書き込むことによってなされる。新しい <tt>
sem_queue</tt> データ構造体は、そのセマフォオブジェクトの待ち行列の最後に置か
れる。(その際は、<tt><ref id="semid_ds" name="sem_pending"</tt> と 
<tt><ref id="semid_ds" name="sem_pending_last"></tt> ポインタが使用される。)
現在のプロセスは、<tt>sem_queue</tt> データ構造体の待ち行列上に(休止状態で)置
かれ、スケジューラが呼び出されて、次のプロセスが実行される。

<!--
If all of the semaphore operations would have succeeded and the current process
does not need to be suspended, Linux goes ahead and applies the operations to
the appropriate members of the semaphore array. Now Linux must check that any
waiting, suspended, processes may now apply their semaphore operations. It
looks at each member of the operations pending queue (sem_pending) in turn,
testing to see if the semphore operations will succeed this time. If they will
then it removes the sem_queue data structure from the operations pending list 
and applies the semaphore operations to the semaphore array. It wakes up the
sleeping process making it available to be restarted the next time the 
scheduler runs. Linux keeps looking through the pending list from the start 
until there is a pass where no semaphore operations can be applied and so no 
more processes can be woken. 
-->
<p>もしセマフォ操作がすべて成功し、現在のプロセスを停止させる必要がなければ、
Linux は処理を継続し、セマフォ配列の適切なメンバーにその操作を適用する。
この時点で、Linux は、待ち状態や停止状態にあるプロセスがそれぞれのセマフォ
操作を適用できるかどうかをチェックする。Linux は、操作ルーチンのペンディング
キュー(pending queue)(<tt><ref id="semid_ds" name="sem_pending"></tt>)のメン
バーそれぞれを順番に見て、今回はそのセマフォ操作が成功するかどうかをテスト
する。
成功した場合、Linux は、ペンディングリストからその <tt>sem_queue</tt> データ
構造体を削除して、セマフォ配列にそのセマフォ操作を適用する。
Linux は、休眠中のプロセスを起こして、次にスケジューラが実行されるときに再始動
されるようにする。Linux は、ペンディングリストを最初から順に調べていって、
適用できるセマフォ操作が無くなり、それ以上プロセスを起こせなくなるまで
それを続ける。

<!--
There is a problem with semaphores, deadlocks. These occur when one process
has altered the semaphores value as it enters a critical region but then fails
to leave the critical region because it crashed or was killed. Linux protects 
against this by maintaining lists of adjustments to the semaphore arrays. The 
idea is that when these adjustments are applied, the semaphores will be put 
back to the state that they were in before the a process's set of semaphore 
operations were applied. These adjustments are kept in sem_undo data 
structures queued both on the semid_ds data structure and on the task_struct 
data structure for the processes using these semaphore arrays. 
-->
<p>セマフォには、デッドロックという問題がある。それが起こるのは、あるプロセス
が、重要なメモリ領域に入ったときのに、クラッシュするか kill されるかしてそこ
から出られなくなり、セマフォ値が変更されたままになる場合である。Linux はこれを
防止するために、セマフォ配列に対する調整(adjustment)リストを管理している。
そのアイデアは、セマフォ配列に調整が適用されると、セマフォが、問題を起こした
プロセスの操作が適用される前の状態(state)に戻されるということである。
これらの調整は、<tt><ref id="sem_undo" name="sem_undo"></tt> データ構造体に
保存されていて、それは <tt><ref id="semid_ds" name="semid_ds"></tt> データ
構造体上のキューとそれらのセマフォ配列を使うプロセスの <tt><ref 
id="task_struct" name="task_struct"></tt> データ構造体上のキューとに置かれる。

<!--
Each individual semaphore operation may request that an adjustment be
maintained. Linux will maintain at most one sem_undo data structure per
process for each semaphore array. If the requesting process does not have one,
then one is created when it is needed. The new sem_undo data structure is
queued both onto this process's task_struct data structure and onto the
semaphore array's semid_ds data structure. As operations are applied to the
semphores in the semaphore array the negation of the operation value is added 
to this semphore's entry in the adjustment array of this process's sem_undo 
data structure. So, if the operation value is 2, then -2 is added to the 
adjustment entry for this semaphore. 
-->
<p>個々のセマフォ操作は、調整のためのデータ管理がなされるされることを個別に要求
する場合がある。Linux は、個々のセマフォ配列について、プロセスあたり最大ひと
つの <tt><ref id="sem_undo" name="sem_undo"></tt> データ構造体しか管理しない。
調整を要求するプロセスがそれをひとつも持っていない場合は、必要なときにひとつの
データ構造体が作成される。新しい <tt><ref id="sem_undo" 
name="sem_undo"></tt> データ構造体は、そのプロセスの <tt><ref id="task_struct"
 name="task_struct"></tt> データ構造体上のキューと、セマフォ配列の <tt>
<ref id="semid_ds" name="semid_ds"></tt> データ構造体上のキューとに入れられる。
セマフォ操作がセマフォ配列のセマフォに対して適用されるとき、オペレーション値
を正負逆にした値が、そのプロセスの <tt>sem_undo</tt> データ構造の調整
(adjustment)配列の中にあるセマフォエントリーに加えられる。
それゆえ、オペレーション値が 2 の場合、-2 がそのセマフォの調整エントリに加え
られる。

<!--
When processes are deleted, as they exit Linux works through their set of
sem_undo data structures applying the adjustments to the semaphore arrays. If
a semaphore set is deleted, the sem_undo data structures are left queued on the
process's task_struct but the semaphore array identifier is made invalid. In
this case the semaphore clean up code simply discards the sem_undo data
structure. 
-->
<p>プロセスが終了して削除されるとき、Linux は、そのプロセスの <tt>
<ref id="sem_undo" name="sem_undo"></tt> データ構造体のセットを調査して、
セマフォ配列に対する調整を適用する。セマフォセットが削除された場合、<tt>
sem_undo</tt> データ構造体は、プロセスの <tt><ref id="task_struct" 
name="task_struct"></tt> のキューに残ったままになるが、セマフォ配列の識別子は
無効になる。その場合、セマフォを片づける(clean up)コードが、単にその <tt>
sem_undo</tt> 構造体を破棄する。


<!--5.3.4  Shared Memory-->
<sect2>共有メモリ<label id="chapter_ipc_sect3-4">

<!--
Shared memory allows one or more processes to communicate via memory that
appears in all of their virtual address spaces. The pages of the virtual 
memory is referenced by page table entries in each of the sharing processes' 
page tables. It does not have to be at the same address in all of the 
processes' virtual memory. As with all System V IPC objects, access to shared 
memory areas is controlled via keys and access rights checking. Once the 
memory is being shared, there are no checks on how the processes are using it.
They must rely on other mechanisms, for example System V semaphores, to 
synchronize access to the memory. 
-->
<p>共有メモリ(shared memory)は、プロセスの仮想アドレス空間の任意の場所を経由
して、複数のプロセスが通信することを可能にする仕組みである。共有される仮想メ
モリのページは、個々の共有プロセスのページテーブル内にあるページテーブルエン
トリによって参照される。
共有されるページは、すべてのプロセスの仮想メモリ内の同一アドレスになくてもよ
い。System V IPC のオブジェクトを使う場合はすべて、共有メモリエリアへのアクセ
スは、キーとアクセス権限のチェックによって制御されている。(正当なアクセスに
より)いったんメモリが共有されたなら、プロセスがそれを使用する方法はチェック
されない。メモリへのアクセスの同期を取るといったことは、他の仕組み、たとえば、
System V のセマフォなどの仕組みに依存しなければならない。


<!--               Figure 5.4: System V IPC Shared Memory-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure5-4.gif">
</figure>
</#if>
<#unless output="html">
<verb>
  shmid_ds
+------------+
|            |
| ipc        |
|            |
|------------|
| shm_segsz  |    +------+
|------------| +->| pte  |
|            | |  |------+
|            | |  | pte  |
| times      | |  |------|
|            | |  |      |
|            | |  |      |
|------------| |  |      |
| shm_npages | |  |------|
|------------| |  | pte  |
| shm_pages  |-+  +------+   vm_area_struct         vm_area_struct
|------------|             +----------------+     +----------------+
| attaches   |------------>|                | +-->|                |
+------------+             |                | |   |                |
                           |                | |   |                |
                           |----------------| |   |----------------|
                           | vm_next_shared |-+   | vm_next_shared |
                           |----------------|     |----------------|
                           |                |     |                |
                           |                |     |                |
                           |                |     |                |
                           +----------------+     +----------------+
</verb>
</#if>
<p>図表(5.4) System V IPC 共有メモリ

<!--
Each newly created shared memory area is represented by a shmid_ds data
structure. These are kept in the shm_segs vector. 
The shmid_ds data structure decribes how big the area of shared memory is,
how many processes are using it and information about how that shared memory
is mapped into their address spaces. It is the creator of the shared memory 
that controls the access permissions to that memory and whether its key is 
public or private. If it has enough access rights it may also lock the shared 
memory into physical memory. 
-->
<p>新しく作成された個々の共有メモリエリアは、<tt><ref id="shmid_ds" 
name="shmid_ds"></tt> データ構造体によって表される。
それらは、<tt><ref id="shmid_ds" name="shm_segs"></tt> 配列に保存される。
<newline>[see: include/linux/sem.h](訳注: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/shm.h" 
name="include/linux/shm.h">？)<newline>
<tt>shmid_ds</tt> データ構造体は、その共有メモリのエリアの大きさ、それを使用
するプロセスの数、およびその共有メモリがプロセスのアドレス空間にマップされて
いる様子に関する情報を記述している。そのメモリへのアクセス権限や、
キーがパブリックキーかプライベートキーかを管理するのは、その共有メモリの作成者
である。プロセスが適切なアクセス権を持っているなら、共有メモリを物理メモリに
<ref id="chapter_mm_lock" name="ロック">することもできる。

<!--
Each process that wishes to share the memory must attach to that virtual
memory via a system call. This creates a new vm_area_struct data structure
describing the shared memory for this process. The process can choose where in
its virtual address space the shared memory goes or it can let Linux choose a
free area large enough. The new vm_area_struct structure is put into the list
of vm_area_struct pointed at by the shmid_ds. The vm_next_shared and
vm_prev_shared pointers are used to link them together. The virtual memory is
not actually created during the attach; it happens when the first process 
attempts to access it. 
-->
<p>メモリを共有しようとする個々のプロセスが、自己の仮想メモリに共有領域を張り
付ける(attach)場合は、システムコールを利用しなければならない。そして、そのシ
ステムコールによって <tt><ref id="vm_area_struct" name="vm_area_struct"></tt> 
データ構造体が作成され、それがプロセスの共有メモリを記述する。
プロセスは、共有メモリが自分の仮想アドレス空間内のどこに置かれるかを選択する
ことができるが、充分な広さの空領域の確保を Linux に任せることもできる。
新しい <tt>vm_area_struct</tt> 構造体は、<tt>vm_area_struct</tt> のリストに
挿入され、<tt><ref id="shmid_ds" name="shmid_ds"></tt> によってポイントされ
る。 <tt><ref id="vm_area_struct" name="vm_next_shared"></tt> と <tt><ref 
id="vm_area_struct" name="vm_prev_shared"></tt> ポインタが、それらをリンクす
るために使用される。共有メモリ領域は、仮想メモリに張り付けられた(attach)だけ
で実際に物理メモリ上に作成されるわけではない。プロセスが最初にそこにアクセス
しようとしたとき、初めて作成される。

<!--
The first time that a process accesses one of the pages of the shared virtual
memory, a page fault will occur. When Linux fixes up that page fault it finds 
the vm_area_struct data structure describing it. This contains pointers to 
handler routines for this type of shared virtual memory. The shared memory 
page fault handling code looks in the list of page table entries for this 
shmid_ds to see if one exists for this page of the shared virtual memory. If 
it does not exist, it will allocate a physical page and create a page table 
entry for it. As well as going into the current process's page tables, this 
entry is saved in the shmid_ds. This means that when the next process that 
attempts to access this memory gets a page fault, the shared memory fault 
handling code will use this newly created physical page for that process too. 
So, the first process that accesses a page of the shared memory causes it to 
be created and thereafter access by the other processes cause that page to be 
added into their virtual address spaces. 
-->
<p>初めてプロセスが共有メモリのページのひとつにアクセスしたときは、ページ
フォルトが発生する。Linux がそのページフォルトを解消したとき、プロセスは、
共有メモリを記述する <tt><ref id="vm_area_struct" name="vm_area_struct"></tt> 
データ構造体を発見する。その構造体には、その共有メモリのタイプに合わせた処理
ルーチンへのポインタが含まれている。共有メモリページフォルト処理コードは、
その <tt><ref id="shmid_ds" name="shmid_ds"></tt> に対するページテーブルエン
トリのリストを探して、共有仮想メモリの該当ページに関するエントリがあるか
どうかを確認する。もし存在しないなら、物理ページを割り当てて、そのための
ページテーブルエントリを作成する。カレントプロセスのページテーブルにそのエン
トリが付け加わると同時に、<tt>shmid_ds</tt> にもそれが保存される。すなわち、
そうしておけば、このメモリにアクセスしようとする次のプロセスがページフォルト
を起こしたとき、共有メモリ処理コードはこの新しく作成された物理ページをそのプ
ロセスのために使用できるわけである。それゆえ、共有メモリにアクセスした最初の
プロセスが物理メモリ上にそれを割り当てたことで、他のプロセスによるそれ以後の
アクセスは、その物理ページをそれらのプロセスの仮想アドレス空間に付加するだけ
で済むようになる。

<!--
When processes no longer wish to share the virtual memory, they detach from it.
So long as other processes are still using the memory the detach only affects 
the current process. Its vm_area_struct is removed from the shmid_ds data
structure and deallocated. The current process's page tables are updated to
invalidate the area of virtual memory that it used to share. When the last 
process sharing the memory detaches from it, the pages of the shared memory 
current in physical memory are freed, as is the shmid_ds data structure for 
this shared memory. 
-->
<p>プロセスがもはや仮想メモリの共有を必要としなくなったとき、プロセスは自己の
仮想メモリからその領域を外す(detach)。他のプロセスがまだそのメモリを使用して
いる限り、外す(detach)操作はカレントプロセスだけにしか影響しない。その <tt>
<ref id="vm_area_struct" name="vm_area_struct"></tt> は、<tt><ref 
id="shmid_ds" name="shmid_ds"></tt> データ構造体から削除され、解放される。
カレントプロセスのページテーブルがアップデートされ、共有されていた仮想メモリ
のエリアは無効にされる。メモリを共有していた最後のプロセスが共有メモリ領域を
外す(detach)とき、物理メモリにある共有メモリのページは解放され、その共有メモ
リに関する <tt>shmid_ds</tt> データ構造体も解放される。

<!--
Further complications arise when shared virtual memory is not locked into
physical memory. In this case the pages of the shared memory may be swapped
out to the system's swap disk during periods of high memory usage. How shared
memory memory is swapped into and out of physical memory is described in
Chapter  mm-chapter. 
-->
<p>共有仮想メモリが物理メモリにロックされないときは、さらに複雑なことが起こる。
その場合、共有メモリのページは、物理メモリの消費が激しい間は、システムのス
ワップディスクにスワップアウトされる。共有メモリが物理メモリからスワップアウ
トやスワップインされる方法は、<ref id="chapter_mm_sect8-2" 
name="「メモリ管理」">の章で解説している。


<!--
Footnotes:

1 REVIEW NOTE: Explain process groups. 
-->
<label id="chapter_ipc_fn">
<footnote>
(脚注1)プロセスグループについて、説明すること。(訳注: 原文のままです。)
</footnote>

<!--第  7 章 PCI-->
<!--Chapter 6 PCI-->
<sect>PCI<label id="chapter_pci">
<p>
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/penguin2.gif">
</figure>

<!--
Peripheral Component Interconnect (PCI), as its name implies is a standard that
describes how to connect the peripheral components of a system together in a
structured and controlled way. The standard describes the way that the system
components are electrically connected and the way that they should behave. This
chapter looks at how the Linux kernel initializes the system's PCI buses and
devices. 
-->
<p>PCI (Peripheral Component Interconnect)とは、その名前から分かるように、
周辺機器(peripheral)とシステムの接続方法について、構造と制御方法を解説した
規格である。この規格(<ref id="bibliography" 
name="[3, PCI Local Bus Specification]">)
では、システム上の機器を電気的に接続する方法と、それらが振る舞うべき方法とが
述べられている。この章では、Linux カーネルがシステムの PCI バスとデバイスを
初期化する方法について説明する。


<label id="figure6-1">
<!--                Figure 6.1: Example PCI Based System-->
<#if>
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure6-1.gif">
</figure>
</#if>
<#unless output="html">
<verb>
                            +-------------+
                            |             |
                            |     CPU     |
                            |             |
                            +------+------+
                                   |                     PCI Bus 0
---------+----------------+--------+--------+-----------------------
         |                |                 |
         |                |                 |          *
   +-----+-----+     +----+----+      +-----+-----+   /| Upstream
   |           |     |         |      |           |    |
   |  PCI-ISA  |     |         |      |  PCI-PCI  |    |
   |  Bridge   |     |         |      |  Bridge   |     
   |           |     +---------+      |           |    | Downstream
   +-----+-----+        Video         +-----+-----+    |
         |                                  |          |/
         |                                  |          *
         | ISA Bus                          |            PCI Bus 1
 ------+-+------------   ----------+--------+---------+-------------
       |                           |                  |
       |                           |                  |
  +----+----+                 +----+----+        +----+----+
  |         |                 |         |        |         |
  |         |                 |         |        |         |
  |         |                 |         |        |         |
  |         |                 |         |        |         |
  +---------+                 +---------+        +---------+
 Super I/O Controller            SCSI              Ethernet
</verb>
</#if>
<p>図表(6.1) PCI バスシステムの例


<!--
Figure  6.1 is a logical diagram of an example PCI based system. The PCI buses
and PCI-PCI bridges are the glue connecting the system components together;
the CPU is connected to PCI bus 0, the primary PCI bus as is the video device.
A special PCI device, a PCI-PCI bridge connects the primary bus to the 
secondary PCI bus, PCI bus 1. In the jargon of the PCI specification, PCI bus 
1 is described as being downstream of the PCI-PCI bridge and PCI bus 0 is 
up-stream of the bridge. Connected to the secondary PCI bus are the SCSI and 
ethernet devices for the system. Physically the bridge, secondary PCI bus and 
two devices would all be contained on the same combination PCI card. The 
PCI-ISA bridge in the system supports older, legacy ISA devices and the 
diagram shows a super I/O controller chip, which controls the keyboard, mouse 
and floppy. 1 
-->
<p>図表(6.1) では、PCI ベースのシステム例を論理的なダイアグラムで示している。
PCI バスと PCI-PCI ブリッジとは、システム機器を相互に接続する仕組み(glue)で
ある。
CPU は、ビデオデバイスと一緒にプライマリ PCI バスである PCI Bus 0 に接続され
ている。特別な PCI デバイスである PCI-PCI ブリッジが、プライマリバスを
セカンダリ PCI バスである PCI Bus 1 に接続している。PCI 規格の専門用語では、
PCI bus 1 は、PCI-PCI ブリッジの下流(downstream)であり、PCI Bus 0 は PCI-PCI 
ブリッジの上流(up-stream)である。
セカンダリ PCI バスには、システムの SCSI とイーサネットデバイスが接続されてい
る。物理的には、ブリッジとセカンダリ PCI バスとふたつのデバイスは、これらが
組み合わされ、同じ PCI カード上にすべて含まれている。
システムの PCI-ISA ブリッジは、旧弊な遺物たる ISA デバイスをサポートするもの
である。またこのダイアグラムでは、Super I/O チップコントローラが示されている
が、これはキーボードやマウス、フロッピーを制御するコントローラである。 
<ref id="chapter_pci_fn" name="(脚注1)">

<!--6.1  PCI Address Spaces-->
<sect1>PCI アドレス空間<label id="chapter_pci_sect1">

<!--
The CPU and the PCI devices need to access memory that is shared between
them. This memory is used by device drivers to control the PCI devices and to
pass information between them. Typically the shared memory contains control
and status registers for the device. These registers are used to control the 
device and to read its status. For example, the PCI SCSI device driver would 
read its status register to find out if the SCSI device was ready to write a 
block of information to the SCSI disk. Or it might write to the control 
register to start the device running after it has been turned on. 
-->
<p>CPU と PCI デバイスとは、両者で共有されたメモリにアクセスする必要がある。
そのメモリは、デバイスドライバが PCI デバイスを制御したり、それらの
間で情報をやり取りするために使用される。通常その共有メモリには、デバイスの
コントロールレジスタやステータスレジスタの情報が含まれる。それらのレジス
タ情報は、デバイスを制御し、その状態を読みとるために利用される。たとえば、PCI 
上の SCSI デバイス (コントローラ) 用のデバイスドライバは、そのステータスレジ
スタを読んで、SCSI デバイスが 
SCSI ディスクに情報ブロックを書き込む準備が出来ているかを調べる。あるいは、
デバイスに電源が入った後、デバイスドライバは、デバイスを起動するために
コントロールレジスタに書き込みをしたりする。

<!--
The CPU's system memory could be used for this shared memory but if it were,
then every time a PCI device accessed memory, the CPU would have to stall,
waiting for the PCI device to finish. Access to memory is generally limited to
one system component at a time. This would slow the system down. It is also 
not a good idea to allow the system's peripheral devices to access main memory
in an uncontrolled way. This would be very dangerous; a rogue device could 
make the system very unstable. 
-->
<p>CPU のシステムメモリをこの共有メモリの代わりに使用することもできるが、
そうしたことがなされると、PCI デバイスがメモリにアクセスするたびに、CPU は
一時停止し、PCI デバイスがメモリの使用を終えるまで待たなければならなくなる。
メモリへのアクセスも、通常、一度にひとつのシステム機器だけに限られる。
したがって、その場合、システムの処理速度が遅くなる。
また、適切な管理方法のないままシステムの周辺機器にメインメモリへのアクセスを
許すことは、よい考えとはいえない。それは非常に危険な場合がある。悪質なデバイス
がシステムを不安定にするからである。

<!--
Peripheral devices have their own memory spaces. The CPU can access these
spaces but access by the devices into the system's memory is very strictly
controlled using DMA (Direct Memory Access) channels. ISA devices have
access to two address spaces, ISA I/O (Input/Output) and ISA memory. PCI has
three; PCI I/O, PCI Memory and PCI Configuration space. All of these address
spaces are also accessible by the CPU with the the PCI I/O and PCI Memory
address spaces being used by the device drivers and the PCI Configuration space
being used by the PCI initialization code within the Linux kernel. 
-->
<p>周辺機器は独自のメモリ空間を持っていて、CPU はそれらの空間へアクセスできる。
しかし、デバイス側からのシステムメモリへのアクセスは、DMA(Direct Memory Access)
チャンネルを使用して厳しく制御される。ISA デバイスは、ISA I/O(Input/Output)空間
と ISA メモリ空間のふたつのアドレス空間へアクセスできる。PCI には三つあり、PCI 
I/O 空間と PCI メモリ空間、PCI コンフィグレーション空間(configuration space)
へアクセスできる。
これらすべてのアドレス空間は CPU からもアクセス可能である。その際、CPU は、
デバイスドライバを使って PCI I/O 空間と PCI メモリ空間へアクセスし、Linux 
カーネル内の PCI 初期化コードを使って PCI コンフィグレーション空間へアクセス
する。

<!--
The Alpha AXP processor does not have natural access to addresses spaces
other than the system address space. It uses support chipsets to access other
address spaces such as PCI Configuration space. It uses a sparse address
mapping scheme which steals part of the large virtual address space and maps it
 to the PCI address spaces. 
-->
<p>Alpha AXP プロセッサは、本来、システムアドレス空間以外のアドレス空間へは
アクセスできない。それゆえ、Alpha AXP プロセッサは、サポートチップを使用して、
PCI コンフィグレーション空間等の他のアドレス空間にアクセスしている。サポート
チップは、スパースアドレスマッピングスキーム(<ref id="sparse" 
name="sparse address mapping scheme">)を使用して、巨大な仮想アドレス空間の一部
を使い、それを PCI アドレス空間にマップしている。

<!--6.2  PCI Configuration Headers-->
<sect1>PCI コンフィグレーションヘッダ<label id="chapter_pci_sect2">
<p>

<label id="figure6-2">
<!--               Figure 6.2: The PCI Configuration Header-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure6-2.gif">
</figure>
</#if>
<#unless output="html">
<verb>
31            16 15            0
+---------------+--------------+
|  デバイス ID  |  ベンダ ID   |00h
|---------------+--------------|
|  ステータス   |   コマンド   |04h
|---------------+------+-------|
|   クラスコード       |       |08h
|-------+-------+------+-------|
|       |       |      |       |10h
|-------+-------+------+-------|
|                              |
|                              |
|                              |
|   ベースアドレスレジスタ     |
|                              |
|                              |
|                              |24h
|------------------------------|
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|---------------+------+-------|
|               | Line |  Pin  |3Ch
+---------------+------+-------+
</verb>
</#if>
<p>図表(6.2) PCI コンフィグレーションヘッダ


<!--
Every PCI device in the system, including the PCI-PCI bridges has a
configuration data structure that is somewhere in the PCI configuration address
space. The PCI Configuration header allows the system to identify and control
the device. Exactly where the header is in the PCI Configuration address space
depends on where in the PCI topology that device is. For example, a PCI video
card plugged into one PCI slot on the PC motherboard will have its 
configuration header at one location and if it is plugged into another PCI 
slot then its header will appear in another location in PCI Configuration 
memory. This does not matter, for wherever the PCI devices and bridges are the
system will find and configure them using the status and configuration 
registers in their configuration headers. 
-->
<p>PCI-PCI ブリッジを含むシステム上のすべての PCI デバイスは、PCI コンフィグ
レーションアドレス空間内に設定用のデータ構造を保持している。
システムは、PCI コンフィグレーションヘッダ(PCI configuration header)を使用する
ことで、デバイスを識別し制御している。
PCI コンフィグレーションアドレス空間内における
ヘッダの正確な位置は、そのデバイスが PCI トポロジーのどこに位置するかに依存す
る。たとえば、PC のマザーボード上のある PCI スロットに差された PCI ビデオ
カードは、そのスロット番号の位置にコンフィグレーションヘッダを持つことになり、
違うスロットに差されていれば、そのヘッダは、PCI コンフィグレーションアドレス
空間の違うメモリ位置にあることになる。
しかし、そうした位置は問題ではない。というのも、PCI デバイスやブリッジが
どこにある場合でも、システムは、それらのコンフィグレーションヘッダ内のステータ
スレジスタとコンフィグレーションレジスタ(configuration register)を使用して、
デバイスを検出し、設定するからである。

<!--
Typically, systems are designed so that every PCI slot has it's PCI 
Configuration Header in an offset that is related to its slot on the board. 
So, for example, the first slot on the board might have its PCI Configuration 
at offset 0 and the second slot at offset 256 (all headers are the same 
length, 256 bytes) and so on. A system specific hardware mechanism is defined 
so that the PCI configuration code can attempt to examine all possible PCI 
Configuration Headers for a given PCI bus and know which devices are present 
and which devices are absent simply by trying to read one of the fields in the
header (usually the Vendor Identification field) and getting some sort of 
error. The (PS 版で規格書が参照されている)describes one possible error message
as returning 0xFFFFFFFF when 
attempting to read the Vendor Identification and Device Identification fields 
for an empty PCI slot. 
-->
<p>一般的に言って、システムは、すべての PCI スロットが、ボード上のスロットの
場所に関連したオフセット位置に PCI コンフィグレーションヘッダを持つように設計
されている。
したがって、たとえば、ボードの最初のスロットは PCI コンフィグレーションアドレス
空間をオフセット 0 の位置に持ち、二つ目のスロットはオフセット 256 の位置に
持つ。(ヘッダは、256 バイトのコンフィグレーション空間のなかで、先頭 64 バイトを
占めている。) そしてこれ以降のスロットについても同様にそれぞれの場所が決められ
ている。
システム固有のハードウェアのメカニズムを設計する場合、PCI 設定コードが、
すべての PCI バス上にあるすべての PCI コンフィグレーションヘッダを調べることが
でき、その際に、ヘッダのフィールド(通常はベンダ識別フィールド)を読み込むことで
エラーが取得されるかどうかによって、デバイスがそのバス上にあるのかどうかを確認
できるように設計されなければならない。
規格書(<ref id="bibliography" name="参考文献 3">)では、空の PCI スロットのベ
ンダ ID とデバイス ID を読み取ろうとしたときは、0xFFFFFFFF というエラー
メッセージだけしか返してはいけないことが記述されている。

<!--
Figure  6.2 shows the layout of the 256 byte PCI configuration header. It 
contains the following fields: 
-->
<p><ref id="figure6-2" name="図表(6.2)">では、256 バイトある PCI コンフィグレー
ションヘッダのレイアウトが示されている。それには、次のようなフィールドが含ま
れる。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/pci.h" 
name="include/linux/pic.h">]<newline>
<descrip>
<!--
Vendor Identification
      A unique number describing the originator of the PCI device. Digital's
      PCI Vendor Identification is 0x1011 and Intel's is 0x8086. 
-->
<tag>ベンダ ID (Vendor Identification)</tag>
その PCI デバイスの製造会社を示す固有の数字である。DEC の PCI ベンダ ID は、
0x1011 であり、Intel は、0x8086 である。

<!--
Device Identification
      A unique number describing the device itself. For example, Digital's
      21141 fast ethernet device has a device identification of 0x0009. 
-->
<tag>デバイス ID (device Identification)</tag>
デバイスそのものを示す固有の数字。たとえば、DEC の 21141 ファストイーサネット
デバイスは、デバイス ID として 0x0009 を持っている。

<!--
Status This field gives the status of the device with the meaning of the bits 
      of this field set by the standard. . 
-->
<tag>ステータス (Status)</tag>
このフィールドは、規格上定められた意味を持つビットによって、デバイスの状態
(status)を表すものである。(<ref id="bibliography" name="参考文献 3">)

<!--
Command
      By writing to this field the system controls the device, for example
      allowing the device to access PCI I/O memory, 
-->
<tag>コマンド (Command)</tag>
このフィールドに書き込むことで、システムはデバイスを制御する。たとえば、デバイ
スに PCI I/O メモリへのアクセスを許すなど。

<!--
Class Code
      This identifies the type of device that this is. There are standard 
      classes for every sort of device; video, SCSI and so on. The class code 
      for SCSI is 0x0100. 
-->
<tag>クラスコード (Class Code)</tag>
これは、そのデバイスのタイプを特定するものである。ビデオ、SCSI など、すべての
種類のデバイスには、規格上のクラスがある。SCSI のクラスコードは 0x0100 である。

<!--
Base Address Registers
      These registers are used to determine and allocate the type, amount and
      location of PCI I/O and PCI memory space that the device can use. 
-->
<tag>ベースアドレスレジスタ (Base Address Register)</tag>
このレジスタは、デバイスが使用できる PC I/O 空間と PCI メモリ空間のタイプと
容量と位置とを決定し割り当てるために使用される。

<!--
Interrupt Pin
      Four of the physical pins on the PCI card carry interrupts from the card
      to the PCI bus. The standard labels these as A, B, C and D. The Interrupt
      Pin field describes which of these pins this PCI device uses. Generally 
      it is hardwired for a pariticular device. That is, every time the system
      boots, the device uses the same interrupt pin. This information allows 
      the interrupt handling subsystem to manage interrupts from this device, 
-->
<tag>割り込みピン (Interrupt Pin)</tag>
PCI カード上の 4 つの物理ピンが、カードから PCI バスへの割り込み信号を
伝えている。規格では、それらを A, B, C, D とラベル付けしている。割り込みピン
フィールドは、PCI デバイスがそれらのうちどのピンを使うかを記述している。
一般的には、それは特定のデバイスごとにハードウェア的に固定されている。
すなわち、システム起動のたびに、デバイスは同じ割り込みピンを使用するわけであ
る。この情報により、割り込み処理サブシステムはそのデバイスからの割り込みを管理
できる。

<!--
Interrupt Line
      The Interrupt Line field of the device's PCI Configuration header is used
      to pass an interrupt handle between the PCI initialisation code, the
      device's driver and Linux's interrupt handling subsystem. The number
      written there is meaningless to the the device driver but it allows the
      interrupt handler to correctly route an interrupt from the PCI device to
      the correct device driver's interrupt handling code within the Linux 
      operating system. See Chapter  interrupt-chapter on page  for details on
      how Linux handles interrupts. 
-->
<tag>割り込みライン (Interrupt Line)</tag>
デバイスの PCI コンフィグレーションヘッダ内の割り込みラインのフィールドは、 
PCI 初期化コードやデバイスドライバ、そして Linux の割り込み処理サブシステムの
間で割り込みハンドルをやり取りするために使用される。
このフィールドに書かれた番号は、デバイスドライバにとっては無意味である。
しかし、Linux オペレーティングシステム上で、割り込み処理ルーチンが、 PCI デバイ
スから発せられた割り込みシグナルを正しいデバイスドライバの割り込み処理コードへ
と手渡すために必要である。
Linux の割り込み処理の方法についての詳細は、<ref id="chapter_i" 
name="「割り込みと割り込み処理」">の章を参考にしてほしい。

</descrip>

<!--6.3  PCI I/O and PCI Memory Addresses-->
<sect1>PCI I/O と PCI メモリアドレス<label id="chapter_pci_sect3">

<!--
These two address spaces are used by the devices to communicate with their
device drivers running in the Linux kernel on the CPU. For example, the DECchip
21141 fast ethernet device maps its internal registers into PCI I/O space. Its
Linux device driver then reads and writes those registers to control the 
device. Video drivers typically use large amounts of PCI memory space to 
contain video information. 
-->
<p>PCI I/O 空間と PCI メモリ空間のふたつのアドレス空間は、デバイスが、
CPU 上で実行されている Linux カーネル内のデバイスドライバと通信をするために
使用される。
たとえば、DEC チップ 21141 ファーストイーサネットデバイスは、内部レジスタ情報
を PCI I/O 空間にマップする。デバイスドライバは、それらのレジスタを読み書きしな
がら、そのデバイスを制御する。ビデオドライバは、一般に巨大な PCI メモリ空間を
使用して、ビデオ情報を保持する。

<!--
Until the PCI system has been set up and the device's access to these address
spaces has been turned on using the Command field in the PCI Configuration
header, nothing can access them. It should be noted that only the PCI
configuration code reads and writes PCI configuration addresses; the Linux
device drivers only read and write PCI I/O and PCI memory addresses. 
-->
<p>PCI システムの設定が行われ、さらに PCI コンフィグレーションヘッダ内のコマン
ドフィールドを使用して、デバイスの PCI I/O と PCI メモリアドレス空間へのアクセ
スが有効と設定されて、初めてそれらのアドレス空間へのアクセスが可能になる。
注意すべきなのは、PCI 設定コードだけが PCI コンフィグレーションアドレス空間に
対する読み書きができるということである。Linux デバイスドライバは、PCI I/O と 
PCI メモリアドレス空間に対してだけしか読み書きできない。

<!--6.4  PCI-ISA Bridges-->
<sect1>PCI-ISA ブリッジ<label id="chapter_pci_sect4">

<!--
These bridges support legacy ISA devices by translating PCI I/O and PCI
Memory space accesses into ISA I/O and ISA Memory accesses. A lot of
systems now sold contain several ISA bus slots and several PCI bus slots. Over
time the need for this backwards compatibility will dwindle and PCI only 
systems will be sold. Where in the ISA address spaces (I/O and Memory) the ISA
devices of the system have their registers was fixed in the dim mists of time 
by the early Intel 8080 based PCs. Even a $5000 Alpha AXP based computer
systems will have its ISA floppy controller at the same place in ISA I/O space
as the first IBM PC. The PCI specification copes with this by reserving the 
lower regions of the PCI I/O and PCI Memory address spaces for use by the ISA
peripherals in the system and using a single PCI-ISA bridge to translate any 
PCI memory accesses to those regions into ISA accesses. 
-->
<p>PCI-ISA ブリッジは、PCI I/O 空間と PCI メモリ空間へのアクセスを ISA I/O 空間
と ISA メモリ空間へのアクセスに変換することで、古い ISA デバイスをサポートして
いる。現在販売されている多くのシステムには ISA スロットと PCI スロットの両方が
いくつか付属している。しばらくすれば、この下位互換性の必要は減少して、PCI のみ
のシステムが販売されるだろう。
システムの ISA デバイスが ISA アドレス空間(I/O 空間とメモリ空間)内でレジスタを
保持している場所は、今では遠い昔となっている初期の Intel 8088 ベースの PC 時代
からずっと固定されたままである。5000 ドルの Alpha AXP ベースのコンピュータ
システムでさえ、ISA フロッピーコントローラが置かれる ISA I/O 空間内の位置は、
初期の IBM PC と同じである。PCI の仕様では、それに対処するために、PCI I/O と 
PCI メモリアドレス空間の下位アドレス領域をシステムの ISA 周辺機器用に予約し、
単一の PCI-ISA ブリッジを使用してそれらの領域にある PCI メモリ空間へのアクセス
を ISA メモリ空間へのアクセスに変換している。

<!--6.5  PCI-PCI Bridges-->
<sect1>PCI-PCI ブリッジ<label id="chapter_pci_sect5">

<!--
PCI-PCI bridges are special PCI devices that glue the PCI buses of the system
together. Simple systems have a single PCI bus but there is an electrical 
limit on the number of PCI devices that a single PCI bus can support. Using 
PCI-PCI bridges to add more PCI buses allows the system to support many more 
PCI devices. This is particularly important for a high performance server. Of 
course, Linux fully supports the use of PCI-PCI bridges. 
-->
<p>PCI-PCI ブリッジは、システム上にある複数の PCI バスを結合するための特別な 
PCI デバイスである。シンプルなシステムは、単一の PCI バスしか持たないが、単一
の PCI バスでサポートできる PCI デバイスの数には電気的な制限がある。PCI-PCI 
ブリッジを使用して多くの PCI バスを加えれば、システムは、より多くの PCI 
デバイスをサポートできる。これは、高いパフォーマンスを要求されるサーバの場合
特に重要である。もちろん、Linux は、PCI-PCI ブリッジを完全にサポートしている。

<!--6.5.1  PCI-PCI Bridges: PCI I/O and PCI Memory Windows-->
<sect2>PCI-PCI ブリッジ: PCI I/O と PCI メモリウィンドウ<label 
id="chapter_pci_sect5-1">

<!--
PCI-PCI bridges only pass a subset of PCI I/O and PCI memory read and write
requests downstream. For example, in Figure  6.1 on page pageref, 
(on page pageref は、PS 版では、on page 62 であり、図表の場所を指示もの)
the PCI-PCI
bridge will only pass read and write addresses from PCI bus 0 to PCI bus 1 if
they are for PCI I/O or PCI memory addresses owned by either the SCSI or
ethernet device; all other PCI I/O and memory addresses are ignored. This
filtering stops addresses propogating needlessly throughout the system. To do
this, the PCI-PCI bridges must be programmed with a base and limit for PCI I/O
and PCI Memory space access that they have to pass from their primary bus
onto their secondary bus. Once the PCI-PCI Bridges in a system have been
configured then so long as the Linux device drivers only access PCI I/O and PCI
Memory space via these windows, the PCI-PCI Bridges are invisible. This is an
important feature that makes life easier for Linux PCI device driver writers.
However, it also makes PCI-PCI bridges somewhat tricky for Linux to configure
as we shall see later on. 
-->
<p>PCI-PCI ブリッジは、PCI I/O 空間と PCI メモリ空間に対する読み書きのリクエス
トのサブセットを下流領域(downstream)のバスに渡すだけである。
たとえば、<ref id="figure6-1"  name="図表(6.1)">では、
PCI-PCI ブリッジは、読み出しと書き込みのアドレスが、SCSI かイーサネットが所有
する PCI I/O アドレス空間か PCI メモリアドレス空間へのものであるならば、その
アドレスを PCI バス 0 から、PCI バス 1 に渡すだけである。それ以外の PCI I/O 
アドレス空間と PCI メモリアドレス空間に関するアドレスはすべて無視される。
このフィルタリングによって、アドレスが不必要にシステム全体に流れるのを防いで
いる。これを実現するためには、PCI-PCI ブリッジは、プライマリバスからセカンダリ
バスに渡す必要のある PCI I/O 空間と PCI メモリ空間のベースアドレスとその上限の
アドレスとをプログラムされていなければならない。
システム上の PCI-PCI ブリッジの設定が完了すると、Linux デバイスドライバが 
PCI I/O 空間と PCI メモリ空間に上記の範囲内でアクセスする限り、デバイスドライ
バからは、PCI-PCI ブリッジが見えなくなる。これは、Linux の PCI デバイスドライバ
の作者にとっては、ドライバの作成が少し楽になるという点で非常に重要な機能で
ある。しかし、これは、Linux からすると、後に述べるように PCI-PCI ブリッジの設
定をややトリッキーにする機能でもある。


<!--6.5.2  PCI-PCI Bridges: PCI Configuration Cycles and PCI Bus Numbering-->
<sect2>PCI-PCI ブリッジ: PCI コンフィグレーションサイクルと PCI バスの番号付け
<label 
id="chapter_pci_sect5-2">
<p>

<label id="figure6-3">
<!--          Figure 6.3: Type 0 PCI Configuration Cycle-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure6-3.gif">
</figure>
</#if>
<#unless output="html">
<verb>
31                                    11 10    8 7        2   1   0
+---------------------------------------+-------+----------+---+---+
|                                       |       |          |   |   |
|     Device Select                     | Func  | Register | 0 | 0 |
|                                       |       |          |   |   |
+---------------------------------------+-------+----------+---+---+
</verb>
</#if>
<p>図表(6.3) Type 0 PCI コンフィグレーションサイクル


<label id="figure6-4">
<!--          Figure 6.4: Type 1 PCI Configuration Cycle-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure6-4.gif">
</figure>
</#if>
<#unless output="html">
<verb>
31           24 23       16 15        11 10    8 7        2   1   0
+--------------+-----------+------------+-------+----------+---+---+
|              |           |            |       |          |   |   |
|   Reserved   |     Bus   |    Device  | Func  | Register | 0 | 1 |
|              |           |            |       |          |   |   |
+--------------+-----------+------------+-------+----------+---+---+
</verb>
</#if>
<p>図表(6.4) Type 1 PCI コンフィグレーションサイクル


<!--
So that the CPU's PCI initialization code can address devices that are not on 
the main PCI bus, there has to be a mechanism that allows bridges to decide 
whether or not to pass Configuration cycles from their primary interface to 
their secondary interface. A cycle is just an address as it appears on the PCI
bus. The PCI specification defines two formats for the PCI Configuration 
addresses; Type 0 and Type 1; these are shown in Figure  6.3 and Figure  6.4 
respectively. Type 0 PCI Configuration cycles do not contain a bus number and 
these are interpretted by all devices as being for PCI configuration addresses
on this PCI bus. Bits 31:11 of the Type 0 configuraration cycles are treated 
as the device select field. One way to design a system is to have each bit 
select a different device. In this case bit 11 would select the PCI device in 
slot 0, bit 12 would select the PCI device in slot 1 and so on. Another way is
to write the device's slot number directly into bits 31:11. Which mechanism is
used in a system depends on the system's PCI memory controller. 
-->
<p>CPU の PCI 初期化コードがメイン PCI バス上にないデバイスを初期化できるように
するには、コンフィグレーションサイクル(Configuration cycle)を PCI のプライマリ
インターフェイスからセカンダリインターフェイスへと渡すか否かをブリッジが決定で
きるような仕組みが存在しなければならない。
コンフィグレーションサイクルは、PCI バス上では単なるアドレスとして表現される。
PCI の規格書では、PCI コンフィグレーションアドレス空間設定のために、Type 0 と 
Type 1 のふたつのフォーマットが定義されていて、それらは図表(6.3)と図表(6.4)と
にそれぞれ示されている。
Type 0 の PCI コンフィグレーションサイクルにはバス番号が含まれない。そして、
Type 0 の PCI コンフィグレーションサイクルは、すべてのデバイスによって、その 
PCI バス上の PCI コンフィグレーションアドレスであると解釈される。
Type 0 のコンフィグレーションサイクルのビット 31 から 11 までは、
デバイス選択フィールドとして扱われる。システムを設計する際のひとつの方法とし
て、個々のビットが違うデバイスを選択するようにする方法がある。その場合、
ビット 11 は、スロット 0 にある PCI デバイスを選択し、ビット 12 は、スロット 1 
にある PCI デバイスを選択する等ということになる。もうひとつの方法は、デバイスの
スロット番号を直接ビット 31 から 11 の領域に書き込むことである。どちらの方法が
利用されるかは、システムの PCI メモリ空間のコントローラに依存する。

<!--
Type 1 PCI Configuration cycles contain a PCI bus number and this type of
configuration cycle is ignored by all PCI devices except the PCI-PCI bridges. 
All of the PCI-PCI Bridges seeing Type 1 configuration cycles may choose to 
pass them to the PCI buses downstream of themselves. Whether the PCI-PCI Bridge
ignores the Type 1 configuration cycle or passes it onto the downstream PCI bus
depends on how the PCI-PCI Bridge has been configured. Every PCI-PCI bridge
has a primary bus interface number and a secondary bus interface number. The
primary bus interface being the one nearest the CPU and the secondary bus
interface being the one furthest away. Each PCI-PCI Bridge also has a
subordinate bus number and this is the maximum bus number of all the PCI buses
that are bridged beyond the secondary bus interface. Or to put it another way,
the subordinate bus number is the highest numbered PCI bus downstream of the
PCI-PCI bridge. When the PCI-PCI bridge sees a Type 1 PCI configuration cycle
it does one of the following things: 
-->
<p>Type 1 の PCI コンフィグレーションサイクルには、PCI バス番号が含まれる。
そして、Type 1 のコンフィグレーションサイクルは、PCI-PCI ブリッジ以外のすべて
の PCI デバイスから無視される。
Type 1 のコンフィグレーションサイクルを見たすべての PCI-PCI ブリッジは、それら
を、自分の下流(downstream)側に渡すかどうかを選択する。PCI-PCI ブリッジが 
Type 1 コンフィグレーションサイクルを無視するか、それとも下流の PCI バスに
渡すかは、PCI-PCI ブリッジの設定次第である。
PCI-PCI ブリッジはすべて、プライマリバスインターフェイス番号とセカンダリバス
インターフェイス番号とを持っている。個々の PCI-PCI ブリッジにとって、プライマリ
バスインターフェイスは、CPU に最も近い側のインターフェイスであり、セカンダリ
バスインターフェイスは CPU に最も遠い側になるインターフェイスである。
また、それぞれの PCI-PCI ブリッジは、サブオーディネイトバス番号(subordinate 
bus number)も
持っている。これは、そのセカンダリバスインターフェイスを越えてブリッジされて
いるすべての PCI バスの中で最大のバス番号に該当する。言い換えるとサブオーディ
ネイトバス番号は、その PCI-PCI ブリッジの下流に位置する PCI バス番号の
なかで最も大きいバス番号である。PCI-PCI ブリッジが Type 1 の PCI コンフィグレー
ションサイクルを見るとき、PCI-PCI ブリッジは次のような処理をする。

<!--
      Ignore it if the bus number specified is not in between the bridge's
      secondary bus number and subordinate bus number (inclusive), 
-->
<itemize>
<item>指定されたバス番号がブリッジのセカンダリバス番号とサブオーディネイトバス
番号の間にない場合(両方の番号を含む)、Type 1 のコンフィグレーションサイクルを
無視する。

<!--
      Convert it to a Type 0 configuration command if the bus number specified
      matches the secondary bus number of the bridge, 
-->
<item>指定されたバス番号がそのブリッジのセカンダリバス番号と一致する場合、
Type 1 コンフィグレーションサイクルを Type 0 の設定コマンドに変換する。
<!--
      Pass it onto the secondary bus interface unchanged if the bus number
      specified is greater than the secondary bus number and less than or equal
      to the subordinate bus number. 
-->
<item>指定されたバス番号がそのブリッジのセカンダリバス番号よりも大きく、かつ
サブオーティネイトバス番号以下である場合、それをそのままセカンダリバスに渡す。
</itemize>

<!--
So, if we want to address Device 1 on bus 3 of the topology Figure 
pci-pci-config-eg-4 on page  we must generate a Type 1 Configuration
command from the CPU. Bridge1 passes this unchanged onto Bus 1. Bridge2
ignores it but Bridge3 converts it into a Type 0 Configuration command and 
sends it out on Bus 3 where Device 1 responds to it. 
-->
<p>したがって、もし<ref id="figure6-9" name="図表(6.9)">のトポロジーの Bus 3 
上のデバイス 1 (D1)と通信したい場合は、Type 1 コンフィグレーションコマンドを 
CPU から送り出さなければならない。ブリッジ 1 は、これを変更せずに Bus 1 に渡
す。ブリッジ 2 は、これを無視するが、ブリッジ 3 は、これを Type 0 コンフィグ
レーションコマンドに変換し、バス 3 上に送信するので、そこにあるデバイス 1 が
これに応答する。

<!--
It is up to each individual operating system to allocate bus numbers during PCI
configuration but whatever the numbering scheme used the following statement
must be true for all of the PCI-PCI bridges in the system: 
-->
<p>PCI の初期化の過程でバス番号を割り当てることは個々のオペレーティングシステム
の責任であるが、どのような番号割り当て方法が取られた場合でも、次の説明は
システムのすべての PCI-PCI ブリッジに当てはまらなければならない。

<!--
``All PCI buses located behind a PCI-PCI bridge must reside between the
seondary bus number and the subordinate bus number (inclusive).'' 
-->
<p><quote>
「PCI-PCI ブリッジの下流にあるすべての PCI バスは、セカンダリバスのバス番号と
サブオーティネイトバス番号との間(その番号を含む)のバス番号を持たなけ
ればならない。」
</quote>

<!--
If this rule is broken then the PCI-PCI Bridges will not pass and translate 
Type 1 PCI configuration cycles correctly and the system will fail to find and
initialise the PCI devices in the system. To achieve this numbering scheme, 
Linux configures these special devices in a particular order. Section 
pci-pci-bus-numbering on page  describes Linux's PCI bridge and bus
numbering scheme in detail together with a worked example. 
-->
<p>このルールが破られた場合、PCI-PCI ブリッジは、Type 1 コンフィグレーション
サイクルを正しく渡したり変換したりできないので、システムはシステム上の PCI 
デバイスを見つけて初期化することに失敗することになる。
この番号割り当て方法を実現するために、
Linux は、それらの特殊なデバイスである PCI-PCI ブリッジをある決まった順番で
設定する。<ref id="chapter_pci_sect6-2-sub" name="「PCI バス番号の割り当て」">
のセクションでは、Linux の PCI ブリッジとバス番号当ての方法について、その実際の
例も交えて詳解している。


<!--6.6  Linux PCI Initialization-->
<sect1>Linux の PCI 初期化方法<label id="chapter_pci_sect6">

<!--
The PCI initialisation code in Linux is broken into three logical parts: 
-->
<p>Linux の PCI 初期化コードは、論理的に 3 つの部分に分かれる。

<!--
PCI Device Driver
      This pseudo-device driver searches the PCI system starting at Bus 0
      and locates all PCI devices and bridges in the system. It builds a linked
      list of data structures describing the topology of the system.
      Additionally, it numbers all of the bridges that it finds. 
-->
<descrip>
<tag>PCI デバイスドライバ</tag>
この仮想デバイスドライバは、Bus 0 から PCI システムの検索を始めて、システム内
のすべての PCI デバイスとブリッジの所在を検出する。そのドライバは、システムの
トポロジーを示すデータ構造体の連結リストを作成する。さらに、発見したブリッジ
すべてに番号付けをする。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/drivers/pci/pci.c" 
name="drivers/pci/pci.c">, <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/pci.h" 
name="include/linux/pci.h">]<newline>

<!--
PCI BIOS
      This software layer provides the services described in
      bib-pci-bios-specification. Even though Alpha AXP does not have
      BIOS services, there is equivalent code in the Linux kernel providing the
      same functions, 
-->
<tag>PCI BIOS</tag>
このソフトウェア層(layer)は、<ref id="chapter_pci_sect6-3" 
name="「PCI BIOS の機能」">で述べる
サービスを提供する。Alpha AXP は BIOS サービスを持たないが、同様の機能を提供
するコードが Linux カーネルの中にある。
<newline>[see: arch/*/kernel/bios32.c](<htmlurl 
url="./The-Linux-Kernel-images/linux/arch/i386/kernel/bios32.c"
name="i386">, <htmlurl 
url="./The-Linux-Kernel-images/linux/arch/alpha/kernel/bios32.c" 
name="alpha">)<newline>

<!--
PCI Fixup
      System specific fixup code tidies up the system specific loose ends of
      PCI initialization. 
-->
<tag>PCI フィックスアップ(fixup)</tag>
システム固有のフィックスアップコード(fixup code)は、PCI の初期化におけるシステ
ム固有の設定の隙間を埋める役割を果たす。
<newline>[see: arch/*/kernel/bios32.c](<htmlurl 
url="./The-Linux-Kernel-images/linux/arch/i386/kernel/bios32.c"
name="i386">, <htmlurl 
url="./The-Linux-Kernel-images/linux/arch/alpha/kernel/bios32.c"
name="alpha">)<newline>

</descrip>

<!--6.6.1  The Linux Kernel PCI Data Structures-->
<sect2>Linux カーネルの PCI データ構造<label id="chapter_pci_sect6-1">
<p>

<label id="figure6-5">
<!--          Figure 6.5: Linux Kernel PCI Data Structures-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure6-5.gif">
</figure>
</#if>
<#unless output="html">
<verb>
                pci_bus
pci_root      +----------+
------------->| parent   |
              | children |--------+
              | next     |        |
              | self     |        |
              | devices  |--+     |
              | bus = 0  |  |     |
              +----------+  |     |
        +-------------------+-----+
        |                   |
        |    +--------------+
        |    |
        |    |     pci_dev          pci_dev           pci_dev
        |    |   +---------+      +---------+       +---------+
        |    +-->| bus     |  +-->| bus     |  +--->| bus     |
        |        | sibling |  |   | sibling |  | +->| sibling |
        |        | next    |--+   | next    |--+ |  | next    |
        |        |         |      |         |    |  |         |
        |        |         |      |         |    |  |         |
        |        +---------+      +---------+    |  +---------+
        |      PCI-ISA Bridge        Video       | PCI-PCI Bridge
        |                                        |
        |      pci_bus                           |
        |     +----------+                       |
        +---->| parent   |                       |
              | children |                       |
              | next     |                       |
              | self     |-----------------------+
              | devices  |--+
              | bus = 1  |  |       pci_dev           pci_dev
              +----------+  |     +---------+       +---------+
                            +---->| bus     |  +--->| bus     |
                                  | sibling |  |    | sibling |
                                  | next    |--+    | next    |
                                  |         |       |         |
                                  |         |       |         |
                                  +---------+       +---------+
                                     SCSI             Ethernet
</verb>
</#if>
<p>図表(6.5) Linux カーネルの PCI データ構造


<!--
As the Linux kernel initialises the PCI system it builds data structures 
mirroring the real PCI topology of the system. Figure  6.5 shows the 
relationships of the data structures that it would build for the example PCI 
system in Figure  6.1 on page pageref. 
-->
<p>Linux カーネルが PCI システムを初期化する際、カーネルは、システムの実際上の
 PCI トポロジーを忠実に反映するため PCI データ構造体を作成する。上記図表(6.5)
は、<ref id="figure6-1" name="図表(6.1)">の PCI システムの例に対して作成される
データ構造体の相互関係を表したものである。

<!--
Each PCI device (including the PCI-PCI Bridges) is described by a pci_dev
data structure. Each PCI bus is described by a pci_bus data structure. The
result is a tree structure of PCI buses each of which has a number of child PCI
devices attached to it. As a PCI bus can only be reached using a PCI-PCI Bridge
(except the primary PCI bus, bus 0), each pci_bus contains a pointer to the PCI
device (the PCI-PCI Bridge) that it is accessed through. That PCI device is a
child of the the PCI Bus's parent PCI bus. 
-->
<p>個々の PCI デバイス(PCI-PCI ブリッジも含む)は、<tt><ref id="pci_dev" 
name="pci_dev"></tt> データ構造体によって記述される。
個々の PCI バスは、<tt><ref id="pci_bus" name="pci_bus"></tt> データ構造体で
記述される。その結果、PCI バスのツリー構造が生成され、個々の PCI バスに
いくつかの子 PCI デバイスが繋がる構造ができる。PCI バスには、
(プライマリ PCI バスである Bus 0 を除いて) PCI-PCI ブリッジを使ってのみ到達が
可能なので、個々の <tt>pci_bus</tt> 構造体には、そのバスへアクセスするための 
PCI デバイス(すなわち PCI-PCI ブリッジ)へのポインタが含まれている。
(<tt>pci_bus</tt> 構造体では)PCI ブリッジは、もとのバスの親に当たる PCI バス
から見て子に該当する。

<!--
Not shown in the Figure  6.5 is a pointer to all of the PCI devices in the 
system, pci_devices. All of the PCI devices in the system have their pci_dev 
data structures queued onto this queue.. This queue is used by the Linux 
kernel to quickly find all of the PCI devices in the system. 
-->
<p><ref id="figure6-5" name="図表(6.5)">では表示されていないが、システム上の
すべての PCI デバイスに対するポインタとして <tt><ref id="pci_dev" 
name="pci_devices"></tt> がある。システム上のすべての PCI デバイスは、
そのキューの上に <tt>pci_dev</tt> データ構造体を登録する。
このキューは、Linux カーネルがシステム上のすべての PCI デバイスをすばやく
探すために使用される。


<!--6.6.2  The PCI Device Driver-->
<sect2>PCI デバイスドライバ<label id="chapter_pci_sect6-2">

<!--
The PCI device driver is not really a device driver at all but a function of 
the operating system called at system initialisation time. The PCI 
initialisation code must scan all of the PCI buses in the system looking for 
all PCI devices in the system (including PCI-PCI bridge devices). 
-->
<p>PCI デバイスドライバは、実際にはデバイスドライバではなく、システムの初期化
の際にコールされるオペレーティングシステムの関数である。PCI 初期化コードは、
システム上のあらゆる PCI バスをスキャンして、すべての PCI 
デバイスを捜す(これには、PCI-PCI ブリッジデバイスも含まれる)。
<newline>[see: Scan_bus(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/drivers/pci/pci.c" 
name="drivers/pci/pci/c">]<newline>
<!--
It uses the PCI BIOS code to find out if every possible slot in the current 
PCI bus that it is scanning is occupied. If the PCI slot is occupied, it 
builds a pci_dev data structure describing the device and links into the list 
of known PCI devices (pointed at by pci_devices). 
-->
<p>PCI 初期化コードは、PCI BIOS のコードを使用して、現在スキャン中の PCI バス
上に存在するスロットが占有されているかどうかをすべて調べる。PCI スロットが占有
されている場合、PCI 初期化コードは、<tt><ref id="pci_dev" name="pci_dev"></tt> 
構造体を作成してそのデバイスを記述し、その構造体を(<tt><ref id="pci_dev" 
name="pci_devices"></tt> によってポイントされた)既知の PCI デバイスのリストに
リンクする。

<!--
The PCI initialisation code starts by scanning PCI Bus 0. It tries to read the
Vendor Identification and Device Identification fields for every possible PCI
device in every possible PCI slot. When it finds an occupied slot it builds a
pci_dev data structure describing the device. All of the pci_dev data
structures built by the PCI initialisation code (including all of the PCI-PCI
Bridges) are linked into a singly linked list; pci_devices. 
-->
<p>PCI 初期化コードは、PCI バスの Bus 0 をスキャンすることから始める。それは、
存在する全 PCI スロットの全 PCI デバイスに対して、そのベンダ ID とデバイス 
ID を読み出そうとする。占有されたスロットを見つけたら、<tt><ref 
id="pci_dev" name="pci_dev"></tt> データ構造体を作成し、デバイス情報を書き込
む。PCI 初期化コードによって作成された <tt>pci_dev</tt> データ構造はすべて(す
べての PCI-PCI ブリッジも含めて)、単純な連結リストである <tt>pci_devices</tt> 
にリンクされる。

<!--
If the PCI device that was found was a PCI-PCI bridge then a pci_bus data
structure is built and linked into the tree of pci_bus and pci_dev data
structures pointed at by pci_root. The PCI initialisation code can tell if the
PCI device is a PCI-PCI Bridge because it has a class code of 0x060400. The 
Linux kernel then configures the PCI bus on the other (downstream) side of the
PCI-PCI Bridge that it has just found. If more PCI-PCI Bridges are found then
these are also configured. This process is known as a depthwise algorithm; the
system's PCI topology is fully mapped depthwise before searching breadthwise.
Looking at Figure  6.1 on page pageref, Linux would configure PCI Bus 1 with 
its Ethernet and SCSI device before it configured the video device on 
PCI Bus 0. 
-->
<p>発見された PCI デバイスが PCI-PCI ブリッジであった場合は、<tt><ref 
id="pci_bus" name="pci_bus"></tt> データ構造体が作成され、<tt>pci_bus</tt> と 
<tt><ref id="pci_dev" name="pci_dev"></tt> データ構造体から成るツリーにリンク
される。そのツリーは、
<tt><ref id="pci_bus" name="pci_root"></tt> によって参照される。PCI-PCI ブリッ
ジは、クラスコード<ref id="chapter_pci_sect2" name="(class code)"> 0x060400 を
持っているので、PCI 初期化コードは、PCI デバイスが PCI-PCI ブリッジであるかど
うかを判別できる。
次に、Linux カーネルは、発見された PCI-PCI ブリッジの反対側(下流側)にある 
PCI バスを設定する。そのバス上でさらに PCI-PCI ブリッジが発見された場合、それら
にも設定がなされる。このプロセスは、デプスワイズアルゴリズム(depthwise 
algorithm)と呼ばれる。システムの PCI トポロジーは、まずひとつの階層が一番奥まで
マップされてから、並列する部分の検出が行われる。<ref id="figure6-1" 
name="図表(6.1)">では、Linux は、まず PCI Bus 1 にあるイーサネットと SCSI 
デバイスを設定してから、PCI Bus 0 にあるビデオデバイスを設定する。

<!--
As Linux searches for downstream PCI buses it must also configure the
intervening PCI-PCI bridges' secondary and subordinate bus numbers. This is
described in detail in Section  pci-pci-bus-numbering below. 
-->
<p>Linux が下流の PCI バスを検出する際は、介在する PCI-PCI ブリッジの
セカンダリバス番号とサブオーディネイトバス番号も設定しなければなら
ない。これについては、以下の<ref id="chapter_pci_sect6-2-sub" 
name="「PCI-PCI ブリッジの設定: PCI バス番号の割り当て」">で詳しく説明する。


<!--Configuring PCI-PCI Bridges - Assigning PCI Bus Numbers-->
<sect3>PCI-PCI ブリッジの設定 - PCI バス番号の割り当て<label 
id="chapter_pci_sect6-2-sub">
<p>

<label id="figure6-6">
<!--              Figure 6.6: Configuring a PCI System: Part 1-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure6-6.gif">
</figure>
</#if>
<#unless output="html">
<verb>
                          +-----------+
                          |           |
                          |           |
         +-------+        |    CPU    |        +-------+
         |       |        |           |        |       |
         |  D 1  |        |           |        |  D 2  |
         |       |        |           |        |       |
         +---+---+        +-----+-----+        +---+---+
  Bus 0      |                  |                  |
  -----------+------------------+------------------+------------------
                                |
                                |
+-------+  +-------+       +----+----+
|       |  |       |       |         |Primary Bus  =  0
|  D 1  |  |  D 2  |       | Bridge  |Secondary Bus = 1
|       |  |       |       |    1    |Subordinate = 0xFF
+---+---+  +---+---+       +----+----+
     |         |                |                              Bus 1
 ----+---------+-+--------------+-------------+---------------------
                 |                            |
                 |                            |
+-------+  +-----+---+                   +----+----+
|       |  |         |                   |         |
|  D 1  |  | Bridge  |                   | Bridge  |
|       |  |    3    |                   |    2    |
+---+---+  +----+----+                   +----+----+
    |           |       Bus ?                 |                 Bus ?
----+-------+---+------------     ------------+----------------------
            |
            |
       +----+----+                   +-------+  +-------+
       |         |                   |       |  |       |
       | Bridge  |                   |  D 1  |  |  D 2  |
       |    4    |                   |       |  |       |
       +----+----+                   +---+---+  +---+---+
            |                            |          |           Bus ?
 -----------+----------------------------+----------+----------------
</verb>
</#if>
<p>図表(6.6) PCI システムの設定: Part 1

<!--
For PCI-PCI bridges to pass PCI I/O, PCI Memory or PCI Configuration address
space reads and writes across them, they need to know the following: 
-->
<p>PCI-PCI ブリッジを介して PCI I/O アドレス空間、PCI メモリアドレス空間、
または PCI コンフィグレーションアドレス空間への読み書きを行うためには、各 
PCI-PCI ブリッジについて以下の情報が必要である。

<!--
Primary Bus Number
      The bus number immediately upstream of the PCI-PCI Bridge, 
Secondary Bus Number
      The bus number immediately downstream of the PCI-PCI Bridge, 
Subordinate Bus Number
      The highest bus number of all of the buses that can be reached
      downstream of the bridge. 
PCI I/O and PCI Memory Windows
      The window base and size for PCI I/O address space and PCI Memory
      address space for all addresses downstream of the PCI-PCI Bridge. 
-->
<descrip>
<tag>プライマリバス番号</tag>
PCI-PCI ブリッジの直上のバス番号

<tag>セカンダリバス番号</tag>
PCI-PCI ブリッジの直下のバス番号

<tag>サブオーディネイトバス番号(subordinate bus number)</tag>
ブリッジの下流に位置する到達可能なバスの中で、最も大きなバス番号

<tag>PCI I/O と PCI メモリウィンドウ</tag>
PCI-PCI ブリッジの下流にある、PCI I/O アドレス空間と PCI メモリアドレス
空間のすべてのアドレスに対するウィンドウのベースアドレスとそのサイズ
</descrip>

<!--
The problem is that at the time when you wish to configure any given PCI-PCI
bridge you do not know the subordinate bus number for that bridge. You do not
know if there are further PCI-PCI bridges downstream and if you did, you do not
know what numbers will be assigned to them. The answer is to use a depthwise
recursive algorithm and scan each bus for any PCI-PCI bridges assigning them
numbers as they are found. As each PCI-PCI bridge is found and its secondary
bus numbered, assign it a temporary subordinate number of 0xFF and scan and
assign numbers to all PCI-PCI bridges downstream of it. This all seems
complicated but the worked example below makes this process clearer. 
-->
<p>問題は、ある PCI-PCI ブリッジを設定しようとするとき、そのブリッジに関する
サブオーディネイトバス番号をその時点では知り得ないということである。
さらに下流の PCI-PCI ブリッジがあるかどうか分からず、分かったとしてもそれらに
割り当てる番号は分からない。
解決策は、デプスワイズ再帰的アルゴリズム(depthwise recursive 
algorithm)を使用して PCI-PCI ブリッジの個々のバスをスキャンして、発見された
時点で番号を当てていくことである。
個々の PCI-PCI ブリッジが発見されて、そのセカンダリバス番号が割り当てられたら、
それに一時的なサブオーディネイトバス番号として 0xFF を割り当てておいて、その
下流にあるすべての PCI-PCI ブリッジをスキャンして番号を割り当てる。
こうした処理全体は複雑に思えるかもしれないが、下記の実際の例を見れば、その
プロセスが分かりやすくなるだろう。

<!--
PCI-PCI Bridge Numbering: Step 1
      Taking the topology in Figure  6.6, the first bridge the scan would find
      is Bridge1. The PCI bus downstream of Bridge1 would be numbered as 1 and
      Bridge1 assigned a secondary bus number of 1 and a temporary
      subordinate bus number of 0xFF. This means that all Type 1 PCI
      Configuration addresses specifying a PCI bus number of 1 or higher
      would be passed across Bridge1 and onto PCI Bus 1. They would be
      translated into Type 0 Configuration cycles if they have a bus number of
      1 but left untranslated for all other bus numbers. This is exactly what 
      the Linux PCI initialisation code needs to do in order to go and scan 
      PCI Bus 1. 
-->
<descrip>
<tag>PCI-PCI ブリッジ番号割り当て: Step 1</tag>
<ref id="figure6-6" name="図表(6.6)">のトポロジーを使うと、スキャンによって、
最初のブリッジとして Bridge 1 が発見される。Bridge 1 の下流に位置する PCI バス
は、バス 1 と番号付けられ、Bridge 1 は、セカンダリバス番号として 1 が、一時的な
サブオーディネイトバス番号として OxFF が割り当てられる。
これは、PCI バス番号として 1 かそれ以上を指定するType 1 の PCI コンフィグレー
ションアドレスが、Bridge 1 を通って PCI バス 1 に渡されることを意味する。
それらは、バス番号 1 を持つ場合は Type 0 のコンフィグレーションサイクルに変換
されるが、それ以外の番号の場合は変換されない。このことは、PCI バス 1 に降りて
スキャンするために、Linux PCI 初期化コードがしなければならないことそのもので
ある。
</descrip>

<label id="figure6-7">
<!--                 Figure 6.7: Configuring a PCI System: Part 2-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure6-7.gif">
</figure>
</#if>
<#unless output="html">
<verb>
                          +-----------+
                          |           |
                          |           |
         +-------+        |    CPU    |        +-------+
         |       |        |           |        |       |
         |  D 1  |        |           |        |  D 2  |
         |       |        |           |        |       |
         +---+---+        +-----+-----+        +---+---+
  Bus 0      |                  |                  |
  -----------+------------------+------------------+------------------
                                |
                                |
+-------+  +-------+       +----+----+
|       |  |       |       |         |Primary Bus  =  0
|  D 1  |  |  D 2  |       | Bridge  |Secondary Bus = 1
|       |  |       |       |    1    |Subordinate = 0xFF
+---+---+  +---+---+       +----+----+
     |         |                |                              Bus 1
 ----+---------+-+--------------+-------------+---------------------
                 |                            |
                 |                            |
+-------+  +-----+---+                   +----+----+
|       |  |         |                   |         |Primary Bus  =  1
|  D 1  |  | Bridge  |                   | Bridge  |Secondary Bus = 2
|       |  |    3    |                   |    2    |Subordinate  =  2
+---+---+  +----+----+                   +----+----+
    |           |       Bus ?                 |                 Bus 2
----+-------+---+------------     ------------+----------------------
            |
            |
       +----+----+                   +-------+  +-------+
       |         |                   |       |  |       |
       | Bridge  |                   |  D 1  |  |  D 2  |
       |    4    |                   |       |  |       |
       +----+----+                   +---+---+  +---+---+
            |                            |          |           Bus ?
 -----------+----------------------------+----------+----------------
</verb>
</#if>
<p>図表(6.7) PCI システムの設定: Part 2



<!--
PCI-PCI Bridge Numbering: Step 2
      Linux uses a depthwise algorithm and so the initialisation code goes on
      to scan PCI Bus 1. Here it finds PCI-PCI Bridge2. There are no further
      PCI-PCI bridges beyond PCI-PCI Bridge2, so it is assigned a
       subordinate bus number of 2 which matches the number assigned to its
      secondary interface. Figure  6.7 shows how the buses and PCI-PCI
      bridges are numbered at this point. 
-->
<descrip>
<tag>PCI-PCI ブリッジの番号割り当て: Part 2</tag>
Linux は、デプスワイズアルゴリズム(depthwise algorithm)を使うので、初期化コード
は PCI バス 1 へと進んでスキャンする。ここで、初期化コードは、PCI-PCI Bridge 2 
を発見する。PCI-PCI ブリッジ 2 以下には PCI-PCI ブリッジは存在しないので、それ
にはサブオーディネイトバス番号 2 が割り当てられ、それはそのセカンダリインター
フェイスに割り当てられた番号と合致する。
<ref id="figure6-7" name="図表(6.7)">では、バスと 
PCI-PCI ブリッジとがこの時点で番号付けされたことを示している。
</descrip>

<label id="figure6-8">
<!--                 Figure 6.8: Configuring a PCI System: Part 3-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure6-8.gif">
</figure>
</#if>
<#unless output="html">
<verb>
                          +-----------+
                          |           |
                          |           |
         +-------+        |    CPU    |        +-------+
         |       |        |           |        |       |
         |  D 1  |        |           |        |  D 2  |
         |       |        |           |        |       |
         +---+---+        +-----+-----+        +---+---+
  Bus 0      |                  |                  |
  -----------+------------------+------------------+------------------
                                |
                                |
+-------+  +-------+       +----+----+
|       |  |       |       |         |Primary Bus  =  0
|  D 1  |  |  D 2  |       | Bridge  |Secondary Bus = 1
|       |  |       |       |    1    |Subordinate = 0xFF
+---+---+  +---+---+       +----+----+
     |         |                |                              Bus 1
 ----+---------+-+--------------+-------------+---------------------
                 |                            |
                 |                            |
+-------+  +-----+---+                   +----+----+
|       |  |         |Primary Bus  =  1  |         |Primary Bus  =  1
|  D 1  |  | Bridge  |Secondary Bus = 3  | Bridge  |Secondary Bus = 2
|       |  |    3    |Subordinate = 0xFF |    2    |Subordinate  =  2
+---+---+  +----+----+                   +----+----+
    |           |       Bus 3                 |                 Bus 2
----+-------+---+------------     ------------+----------------------
            |
            |
       +----+----+                   +-------+  +-------+
       |         |                   |       |  |       |
       | Bridge  |                   |  D 1  |  |  D 2  |
       |    4    |                   |       |  |       |
       +----+----+                   +---+---+  +---+---+
            |                            |          |           Bus ?
 -----------+----------------------------+----------+----------------
</verb>
</#if>
<p>図表(6.8) PCI システム設定: Part 3

<!--
PCI-PCI Bridge Numbering: Step 3
      The PCI initialisation code returns to scanning PCI Bus 1 and finds
      another PCI-PCI bridge, Bridge3. It is assigned 1 as its primary bus
      interface number, 3 as its secondary bus interface number and 0xFF as
      its subordinate bus number. Figure  6.8 on page pageref shows how the
      system is configured now. Type 1 PCI configuration cycles with a bus
      number of 1, 2 or 3 wil be correctly delivered to the appropriate PCI
      buses. 
-->
<descrip>
<tag>PCI-PCI ブリッジの番号割り当て: Step 3</tag>
PCI 初期化コードは、PCI バス 1 のスキャニングに戻り、もうひとつの PCI-PCI 
ブリッジである Bridge 3 を発見する。それは、そのプライマリバスインターフェイス
として 1 を割り当てられ、セカンダリインターフェイスの番号として 3 を、
サブオーディネイトバス番号として 0xFF を割り当てられる。
<ref id="figure6-8" name="図表(6.8)">では、システムが現在どのように設定されたの
かを示している。バス番号 1, 2, 3 についての Type 1 の PCI コンフィグレーション
サイクルは、適切な PCI バスに対して正しく伝達される。
</descrip>

<label id="figure6-9">
<!--                 Figure 6.9: Configuring a PCI System: Part 4-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure6-9.gif">
</figure>
</#if>
<#unless output="html">
<verb>
                          +-----------+
                          |           |
                          |           |
         +-------+        |    CPU    |        +-------+
         |       |        |           |        |       |
         |  D 1  |        |           |        |  D 2  |
         |       |        |           |        |       |
         +---+---+        +-----+-----+        +---+---+
  Bus 0      |                  |                  |
  -----------+------------------+------------------+------------------
                                |
                                |
+-------+  +-------+       +----+----+
|       |  |       |       |         |Primary Bus  =  0
|  D 1  |  |  D 2  |       | Bridge  |Secondary Bus = 1
|       |  |       |       |    1    |Subordinate  =  4
+---+---+  +---+---+       +----+----+
     |         |                |                              Bus 1
 ----+---------+-+--------------+-------------+---------------------
                 |                            |
                 |                            |
+-------+  +-----+---+                   +----+----+
|       |  |         |Primary Bus  =  1  |         |Primary Bus  =  1
|  D 1  |  | Bridge  |Secondary Bus = 3  | Bridge  |Secondary Bus = 2
|       |  |    3    |Subordinate  =  4  |    2    |Subordinate  =  2
+---+---+  +----+----+                   +----+----+
    |           |       Bus 3                 |                 Bus 2
----+-------+---+------------     ------------+----------------------
            |
            |
       +----+----+                   +-------+  +-------+
       |         |Primary Bus  =  3  |       |  |       |
       | Bridge  |Secondary Bus = 4  |  D 1  |  |  D 2  |
       |    4    |Subordinate  =  4  |       |  |       |
       +----+----+                   +---+---+  +---+---+
            |                            |          |           Bus 4
 -----------+----------------------------+----------+----------------
</verb>
</#if>
<p>図表(6.9) PCI システムの設定: Part4


<!--
PCI-PCI Bridge Numbering: Step 4
      Linux starts scanning PCI Bus 3, downstream of PCI-PCI Bridge3. PCI
      Bus 3 has another PCI-PCI bridge (Bridge4) on it, it is assigned 3 as its
      primary bus number and 4 as its secondary bus number. It is the last
      bridge on this branch and so it is assigned a subordinate bus interface
      number of 4. The initialisation code returns to PCI-PCI Bridge3 and
      assigns it a subordinate bus number of 4. Finally, the PCI initialisation
      code can assign 4 as the subordinate bus number for PCI-PCI Bridge1.
      Figure  6.9 on page pageref shows the final bus numbers. 
-->
<descrip>
<tag>PCI-PCI ブリッジの番号当て: Step 4</tag>
Linux は、PCI-PCI ブリッジ Bridge 3 の下流にある PCI バス 3 のスキャニング
を始める。PCI バス 3 は、次の PCI-PCI ブリッジ(Bridge 4)をバス上に持っている
ので、それは、プライマリバス番号として 3 を、セカンダリバス番号として 4 を割り
当てられる。これはそのバス上の最後のブリッジなので、ブリッジにはサブオーディネ
イトバスインターフェイス番号 4 が割り当てられる。
初期化コードは、PCI-PCI Bridge 3 に戻り、それにサブオーディネイトバス番号 4 を
割り当てる。最後に、PCI 初期化コードは、PCI-PCI Bridge 1 にサブオーディネイト
バス番号 4 を割り当てることができる。<ref id="figure6-9" 
name="図表(6.9)">では、最後のバス番号が示されている。
</descrip>

<label id="chapter_pci_sect6-3">
<!--6.6.3  PCI BIOS Functions-->
<sect2>PCI BIOS 関数

<!--
The PCI BIOS functions are a series of standard routines which are common
across all platforms. For example, they are the same for both Intel and Alpha
AXP based systems. They allow the CPU controlled access to all of the PCI
address spaces. 
Only Linux kernel code and device drivers may use them. 
-->
<p>PCI BIOS 関数は、全プラットフォームに共通な、一連の標準ルーチンである。
たとえば、それらは、Intel や Alpah AXP ベースのシステムの両方で同一である。
PCI BIOS 関数は、PCI アドレス空間への CPU で制御されたアクセスを可能にする。
<newline>[see: arch/*/kernel/bios32.c]( <htmlurl 
url="./The-Linux-Kernel-images/linux/arch/i386/kernel/bios32.c" 
name="i386">, <htmlurl 
url="./The-Linux-Kernel-images/linux/arch/i386/kernel/bios32.c" 
name="alpha"> )<newline>
それらを使用できるのは、Linux カーネルコードとデバイスドライバだけである。


<!--6.6.4  PCI Fixup-->
<sect2>PCI フィックスアップ(fixup)

<!--
The PCI fixup code for Alpha AXP does rather more than that for Intel (which
basically does nothing). 
For Intel based systems the system BIOS, which ran at boot time, has already
fully configured the PCI system. This leaves Linux with little to do other than
map that configuration. For non-Intel based systems further configuration needs
to happen to: 
-->
<p>Alpah AXP の PCI フィックスアップ(fixup)コードは、Intel のもの(Intel 版の
コードは基本的に何もしない)以上の役割を果たす。
<newline>[see: arch/*/kernel/bios32.c]( <htmlurl 
url="./The-Linux-Kernel-images/arch/i386/kernel/bios32.c" 
name="i386">, <htmlurl 
url="./The-Linux-Kernel-images/arch/alpha/kernel/bios32.c" 
name="alpha"> )<newline>
Intel ベースのシステムでは、ブート時に実行されるシステム BIOS が、PCI 
システムを完全に設定する。そのために、Linux は、そこでの設定をマップする以外
はほとんどすることがない。Intel ベースでないシステムの場合、次のようなさら
なる設定作業がなされる必要がある。

<!--
      Allocate PCI I/O and PCI Memory space to each device, 
      Configure the PCI I/O and PCI Memory address windows for each
      PCI-PCI bridge in the system, 
      Generate Interrupt Line values for the devices; these control interrupt
      handling for the device. 
-->
<itemize>
<item>個々のデバイスに PCI I/O と PCI メモリ空間を割り当てること。
<item>システムの PCI-PCI ブリッジそれぞれに、PCI I/O アドレスと PCI メモリ
アドレスのウィンドウを設定すること。
<item>デバイスの割り込み処理を制御する、割り込みライン値を生成すること。
</itemize>

<!--
The next subsections describe how that code works. 
-->
<p>次のサブセクションでは、それらのコードの働きを説明する。


<!--Finding Out How Much PCI I/O and PCI Memory Space a Device Needs-->
<sect3>デバイスが必要とする PCI I/O と PCI メモリ空間の容量を調べる

<!--
Each PCI device found is queried to find out how much PCI I/O and PCI Memory
address space it requires. To do this, each Base Address Register has all 1's
written to it and then read. The device will return 0's in the don't-care 
address bits, effectively specifying the address space required. 
-->
<p>検出された PCI デバイスは、その PCI I/O と PCI メモリがアドレス空間をどの
程度必要とするのか調べるために、検査される。その検査のために、個々のベース
アドレスレジスタには、すべて 1 が書き込まれ、その後で読み出される。デバイスは、
使用しないアドレスのビットに関しては 0 を返すので、必要とされるアドレス空間を
効率的に確定することができる。

<label id="figure6-10">
<!--       Figure 6.10: PCI Configuration Header: Base Address Registers-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure6-10.gif">
</figure>
</#if>
<#unless output="html">
<verb>
31                                                4  3  2  1  0
+--------------------------------------------------+--+-----+--+
|                                                  |  |     |  |
|                   Base Address                   |  |     | 0|
|                                                  |  |     |  |
+--------------------------------------------------+--+-----+--+
                                                     |   |
                                    prefetchable-----+  Type

                PCI メモリ空間のベースアドレス


31                                                       2  1  0
+---------------------------------------------------------+--+--+
|                                                         |  |  |
|                   Base Address                          |  |  |
|                                                         |  |  |
+---------------------------------------------------------+--+--+
                                                            |
                                                          Reserved

                PCI I/O 空間のベースアドレス
</verb>
</#if>
<p>図表(6.10) PCI コンフィグレーションヘッダ: ベースアドレスレジスタ


<!--
There are two basic types of Base Address Register, the first indicates within
which address space the devices registers must reside; either PCI I/O or PCI
Memory space. This is indicated by Bit 0 of the register. Figure  6.10 shows 
the two forms of the Base Address Register for PCI Memory and for PCI I/O. 
-->
<p>ベースアドレスレジスタには、基本的にふたつのタイプがある。ひとつは、デバイス
レジスタが、PCI I/O もしくは PCI メモリ空間のどの範囲になければならないかを示
す。これは、レジスタのビット 0 によって示される。
<ref id="figure6-10" name="図表(6.10)">では、PCI メモリと PCI I/O についての
二種類のフォームのベースアドレスレジスタが示されている。

<!--
To find out just how much of each address space a given Base Address Register
is requesting, you write all 1s into the register and then read it back. The 
device will specify zeros in the don't care address bits, effectively 
specifying the address space required. This design implies that all address 
spaces used are a power of two and are naturally aligned. 
-->
<p>そのベースアドレスレジスタがどの程度のアドレス空間を要求しているのかを正確に
知るために、そのレジスタにすべて 1 を書き込んで、そのあとでそれを読み出す。
デバイスは、使用しないアドレス空間ではビット値 0 を返すので、効果的に必要な
アドレス空間を確定できる。こうした設計方法によって、利用されるアドレス空間全体
は 2 の n 乗となり、自然な境界に整合する位置に置かれることになる。

<!--
For example when you initialize the DECChip 21142 PCI Fast Ethernet device, it
tells you that it needs 0x100 bytes of space of either PCI I/O or PCI Memory. 
The initialization code allocates it space. The moment that it allocates 
space, the 21142's control and status registers can be seen at those 
addresses. 
-->
<p>たとえば、DEC チップ 21142 PCI ファーストイーサネットデバイスを初期化すると
き、デバイスは、PCI I/O か PCI メモリのいずれかのスペースとして 0x100 バイトが
必要であると告げるとする。初期化コードは、デバイスにその空間を割り当てる。
空間を割り当てた瞬間、21142 のコントロールレジスタとステータスレジスタが、
それらのアドレス上に存在するのがわかるようになる。

<!--Allocating PCI I/O and PCI Memory to PCI-PCI Bridges and Devices-->
<sect3>PCI-PCI ブリッジとデバイスに対して PCI I/O と PCI メモリを割り当てる

<!--
Like all memory the PCI I/O and PCI memory spaces are finite, and to some
extent scarce. The PCI Fixup code for non-Intel systems (and the BIOS code for
Intel systems) has to allocate each device the amount of memory that it is
requesting in an efficient manner. Both PCI I/O and PCI Memory must be
allocated to a device in a naturally aligned way. For example, if a device 
asks for 0xB0 of PCI I/O space then it must be aligned on an address that is a
multiple of 0xB0. In addition to this, the PCI I/O and PCI Memory bases for 
any given bridge must be aligned on 4K and on 1Mbyte boundaries respectively. 
Given that the address spaces for downstream devices must lie within all of 
the upstream PCI-PCI Bridge's memory ranges for any given device, it is a 
somewhat difficult problem to allocate space efficiently. 
-->
<p>すべてのメモリと同様に、PCI I/O と PCI メモリ空間は有限であり、ときにやや
不足することもある。Intel 以外のシステムにおける PCI フィックスアップコード
(fixup code)(および、Intel システムにおける BIOS コード)は、個々のデバイスに
対して、それが要求する量のメモリを効率的に割り当てなければならない。
一方、PCI I/O と PCI メモリ空間のアドレスは、自然な境界に整合するような方法
で各デバイスに割り当てられなければならない。
たとえば、デバイスが PCI I/O 空間に 0xB0 バイトの容量を要求する場合、それは 
0xB0 の倍数となるアドレス上に割り当てられる必要がある。
これに加えて、各ブリッジに関する PCI I/O と PCI メモリのベースアドレス
は、それぞれ 4 k と 1 M バイトの境界に整合しなければならない。
下流に位置するデバイスのアドレス空間は、上流にあるすべてのブリッジが下流デバイ
ス用として確保するメモリ領域内になければならない。
したがって、空間を効率的に割り当てるのは、やや難しい問題である。

<!--
The algorithm that Linux uses relies on each device described by the bus/device
tree built by the PCI Device Driver being allocated address space in ascending
PCI I/O memory order. Again a recursive algorithm is used to walk the pci_bus
and pci_dev data structures built by the PCI initialisation code. Starting at 
the root PCI bus (pointed at by pci_root) the BIOS fixup code: 
-->
<p>Linux が使っているアルゴリズムでは、PCI デバイスドライバによって作成された
バスとデバイスとのツリー構造によって記述される個々のデバイスに対して、PCI 
I/O 空間および PCI メモリ空間にそれぞれが使うアドレスを昇順に割り当てるという
方法でこの問題に対処している。
この場合も、再帰的アルゴリズムが使用され、PCI 初期化コードによって作成された 
<tt><ref id="pci_bus" name="pci_bus"></tt> と <tt><ref id="pci_dev" 
name="pci_dev"></tt> データ構造体が順番に調べられる。
ルート PCI バス(これは、<tt><ref id="pci_bus" name="pci_root"></tt> によって
ポイントされている)から調査を始めて、BIOS 関数やフィックスアップコードは次の
ようなことをする。

<!--
      Aligns the current global PCI I/O and Memory bases on 4K and 1 Mbyte
      boundaries respectively, 
-->
<itemize>
<item>グローバルな PCI I/O と PCI メモリのカレント(current)ベースアドレ
スを 4 k と 1 M バイトの境界に合わせてそれぞれ設定する。

<!--
      For every device on the current bus (in ascending PCI I/O memory
      needs), 
            allocates it space in PCI I/O and/or PCI Memory, 

            moves on the global PCI I/O and Memory bases by the
            appropriate amounts, 

            enables the device's use of PCI I/O and PCI Memory, 
-->
<item>カレントバス上のすべてのデバイスに対して、(要求された PCI I/O 
および PCI メモリ空間上のアドレスについては昇順で)、次のことをする。
<itemize>
<item>デバイスに、PCI I/O と PCI メモリの両方か一方の空間を割り当てる。
<item>適切な容量分だけ、グローバルな PCI I/O と PCI メモリのベースアドレスを
移動させる。
<item>デバイスが PCI I/O と PCI メモリを使用できるようにする。
</itemize>

<!--
      Allocates space recursively to all of the buses downstream of the current
      bus. Note that this will change the global PCI I/O and Memory bases, 
-->
<item>カレントバスの下流にあるすべてのバスに対して、再帰的に空間を
割り当てる。これには、グローバル　PCI I/O と PCI メモリのベースアドレスの変更が
伴うことに注意。

<!--
      Aligns the current global PCI I/O and Memory bases on 4K and 1 Mbyte
      boundaries respectively and in doing so figure out the size and base of
      PCI I/O and PCI Memory windows required by the current PCI-PCI
      bridge, 
-->
<item>グローバルな PCI I/O と PCI メモリのカレントベースアドレスをそれぞれ 4 k 
と 1 M バイトの境界に合わせて設定し、その際に、現在の PCI-PCI ブリッジが必要と
する PCI I/O と PCI メモリのウィンドウのサイズとベースアドレスとを調べる。

<!--
      Programs the PCI-PCI bridge that links to this bus with its PCI I/O and
      PCI Memory bases and limits, 
-->
<item>そのバスに繋がっている PCI-PCI ブリッジを、その PCI I/O と PCI メモリの
ベースアドレスと上限アドレスとを使って、プログラムする。

<!--
      Turns on bridging of PCI I/O and PCI Memory accesses in the PCI-PCI
      Bridge. This means that if any PCI I/O or PCI Memory addresses seen on
      the Bridge's primary PCI bus that are within its PCI I/O and PCI Memory
      address windows will be bridged onto its secondary PCI bus. 
-->
<item>PCI-PCI ブリッジにプログラムされた PCI I/O と PCI メモリへのアクセスが
ある場合にそれを通過させる機能を、有効にする。このことは、サイズとベース
アドレスによって指定されたそのブリッジのアドレス空間ウィンドウ内にある
 PCI I/O または PCI メモリアドレスがブリッジのプライマリバスに現れた場合、
それをセカンダリ PCI バスに通過させる (bridge する) ことを意味する。
</itemize>

<!--
Taking the PCI system in Figure  6.1 on page pageref as our example the PCI
Fixup code would set up the system in the following way: 
-->
<p><ref id="figure6-1" name="図表(6.1)">にある PCI システムを例に取ると、
PCI フィックスアップコードは、次のような方法でシステムを設定することになる。

<!--
Align the PCI bases
      PCI I/O is 0x4000 and PCI Memory is 0x100000. This allows the
      PCI-ISA bridges to translate all addresses below these into ISA address
      cycles, 
-->
<descrip>
<tag>PCI ベースアドレスの初期設定</tag>
ベースアドレスについて、PCI I/O を 0x4000 とし、PCI メモリを 0x100000 とする。
これによって、PCI-ISA ブリッジは、これより下位のアドレスを ISA アドレスサイクル
に変換できるようになる。

<!--
The Video Device
      This is asking for 0x200000 of PCI Memory and so we allocate it that
      amount starting at the current PCI Memory base of 0x200000 as it has to
      be naturally aligned to the size requested. The PCI Memory base is
      moved to 0x400000 and the PCI I/O base remains at 0x4000. 
-->
<tag>ビデオデバイス</tag>
このデバイスは、PCI メモリの容量として 0x200000 を要求している。したがって、
要求されたサイズのメモリを連続的に割り当てる必要があるので、その容量を
現在の PCI メモリのベースアドレスである 0x200000 から始まる領域に割り当てる。
これによって、PCI メモリのベースアドレスは 0x400000 に移動し、PCI I/O の
ベースアドレスは 0x4000 のままである。

<!--
The PCI-PCI Bridge
      We now cross the PCI-PCI Bridge and allocate PCI memory there, note
      that we do not need to align the bases as they are already correctly
      aligned: 
      The Ethernet Device
            This is asking for 0xB0 bytes of both PCI I/O and PCI Memory
            space. It gets allocated PCI I/O at 0x4000 and PCI Memory at
            0x400000. The PCI Memory base is moved to 0x4000B0 and the
            PCI I/O base to 0x40B0. 
      The SCSI Device
            This is asking for 0x1000 PCI Memory and so it is allocated it at
            0x401000 after it has been naturally aligned. The PCI I/O base is
            still 0x40B0 and the PCI Memory base has been moved to
            0x402000. 
-->
<tag>PCI-PCI ブリッジ</tag>
この時点で、PCI-PCI ブリッジを通過して、その下流にあるデバイスに PCI メモリ
を割り当てる。注意: ベースアドレスは既に正しく設定されており、ここで再設定する
必要はない。

<descrip>
<tag>イーサネットデバイス</tag>
このデバイスは、PCI I/O と PCI メモリ空間両方に 0xB0 バイトを要求している。
したがって、0x4000 に PCI I/O が、0x400000 に PCI メモリが割り当てられる。
PCI メモリのベースアドレスは、0x4000B0 に移動し、PCI I/O ベースアドレスは 
0x40B0 に移動する。

<tag>SCSI デバイス</tag>
このデバイスは、PCI メモリに 0x1000 を要求しているので、それが自然な境界に
沿って配置されるように、0x401000 に必要な空間を割り当てられる。
PCI I/O ベースアドレスは、そのまま 0x40B0 であり、PCI メモリのベースアドレス
は、0x402000 に移動する。
</descrip>

<!--
The PCI-PCI Bridge's PCI I/O and Memory Windows
      We now return to the bridge and set its PCI I/O window at between
      0x4000 and 0x40B0 and it's PCI Memory window at between 0x400000
      and 0x402000. This means that the PCI-PCI Bridge will ignore the PCI
      Memory accesses for the video device and pass them on if they are for
      the ethernet or SCSI devices. 
-->
<tag>PCI-PCI ブリッジの PCI I/O と PCI メモリのウィンドウ</tag>
ここで、ブリッジに戻って、PCI I/O ウィンドウを 0x4000 と 0x40B0 の間に設定し
て、その PCI メモリウィンドウを 0x400000 と 0x402000 との間に設定する。
これは、PCI-PCI ブリッジがビデオデバイスのための PCI メモリアクセスを無視
して、それらがイーサネットか SCSI デバイスのためのものなら通すということを
意味する。

</descrip>

<!--
Footnotes:

1 For example? 
-->
<label id="chapter_pci_fn">
<footnote>
(脚註1)たとえば？
</footnote>

<!--第  8 章 割り込みと割り込み処理-->
<!--Chapter 7 Interrupts and Interrupt Handling-->
<sect>割り込みと割り込み処理<label id="chapter_i">
<p>
<figure><ph vspace="70"><img src="./The-Linux-Kernel-images/penguin2.gif">
</figure>

<!--
This chapter looks at how interrupts are handled by the Linux kernel. Whilst 
the kernel has generic mechanisms and interfaces for handling interrupts, most
of the interrupt handling details are architecture specific. 
-->
<p>この章では、割り込みが Linux によってどのように処理されるかを見る。カーネル
は、割り込み処理のための汎用的な仕組みとインターフェイスを持っているが、
割り込み処理の詳細の大部分はアーキテクチャに固有のものである。

<label id="figure7-1">
<!--            Figure 7.1: A Logical Diagram of Interrupt Routing-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure7-1.gif">
</figure>
</#if>
<#unless output="html">
<verb>
                                                   +---------------+
                                                   |       *  /    |
                                                   |       | /     |
                                                   |       |/      |
                                                   |.      +      .|
+-----------------+                 Real Time Clock|               |
|                 |<-------------------------------|               |
|                 |        +---------+             |       .       |
|                 |<-------|         |0            +---------------+
|     C P U       |        |         |1<-------------キーボード
|                 |    +-->|    P    |2
|                 |    |   |    I    |
|                 |    |   |    C    |4<----------シリアルポート
+-----------------+    |   |         |5<----------サウンド
                       |   |    1    |6<----------フロッピードライブ
                       |   |         |7
                       |   +---------+
                       |
                       |   +---------+
                       |   |         |0
                       +---|         |
                           |    P    |
                           |    I    |3<-------------SCSI
                           |    C    |
                           |         |
                           |    2    |6<-------------ide0
                           |         |7<-------------ide1
                           +---------+
</verb>
</#if>
<p>図表(7.1) 割り込みのルーティングに関する論理的なダイアグラム


<!--
Linux uses a lot of different pieces of hardware to perform many different 
tasks. The video device drives the monitor, the IDE device drives the disks 
and so on. You could drive these devices synchronously, that is you could send
a request for some operation (say writing a block of memory out to disk) and 
then wait for the operation to complete. That method, although it would work, 
is very inefficient and the operating system would spend a lot of time ``busy 
doing nothing'' as it waited for each operation to complete. A better, more 
efficient, way is to make the request and then do other, more useful work and 
later be interrupted by the device when it has finished the request. With this
scheme, there may be many outstanding requests to the devices in the system all
happening at the same time. 
-->
<p>Linux は、多種多様なハードウェアを使用して多くの異なるタスクを実行してい
る。ビデオデバイスはモニタをドライブし、IDE デバイスはディスクをドライブする
等である。それらの複数のデバイスを同期させて使用することも可能であり、その際
は、ある操作についてのリクエストを送り(たとえば、あるメモリブロックをディスクに
書き出す等)、処理の完了を待つことになる。この方法は、たしかに実行はされ
るのだが、非常に効率が悪く、オペレーティングシステムは個々の操作が完了するまで
待ち状態になるため、「何もしないビジー」状態で多くの時間を消費することになる。
もっと効率のよい方法は、リクエストを送った後、より有益な他の仕事をしながら、
リクエストが完了した時点でデバイスから割り込みを受けるという方法である。この
方法ならば、デバイスに対する多くのリクエストを未処理の状態で同時にシステム上に
併存させることが可能になる。

<!--
There has to be some hardware support for the devices to interrupt whatever the
CPU is doing. Most, if not all, general purpose processors such as the Alpha
AXP  use a similar method. Some of the physical pins of the CPU are wired such
that changing the voltage (for example changing it from +5v to -5v) causes the
CPU to stop what it is doing and to start executing special code to handle the
interruption; the interrupt handling code. One of these pins might be 
connected to an interval timer and receive an interrupt every 1000th of a 
second, others may be connected to the other devices in the system, such as 
the SCSI controller. 
-->
<p>CPU がその時にどのような処理を行っていようともデバイスが割り込みをかけること
ができるためには、なんらかのハードウェアによるサポートが必要である。すべてでは
ないとしても、Alpha AXP のような大部分の汎用プロセッサは、そのために類似した
方法を使っている。
CPU の物理ピンのいくつかは、そのピンに電圧の変化(たとえば、+5V から -5V への
変化)が生じると、CPU の現在の処理が中断され、割り込みを処理をする特別なコード
である割り込み処理コード(interrupt handling code)の実行が開始されるように設計
されている。
それらのピンのひとつはインターバルタイマーに接続され、千分の一秒ごとに割り
込みを受けられるようになっていて、それ以外のピンが SCSI コントローラのような
システム上の他のデバイスに接続されている。

<!--
Systems often use an interrupt controller to group the device interrupts 
together before passing on the signal to a single interrupt pin on the CPU. 
This saves interrupt pins on the CPU and also gives flexibility when designing
systems. The interrupt controller has mask and status registers that control 
the interrupts. Setting the bits in the mask register enables and disables 
interrupts and the status register returns the currently active interrupts in 
the system. 
-->
<p>しばしばシステムは、割り込みコントローラ(interrupt controller)を使用して、
デバイスの複数の割り込みをグループ化し、その上で CPU 上の単一の割り込みピンに
シグナルを送っている。
これは CPU の割り込みピンの数を節約し、システムをデザインする際に柔軟性をも
もたらす。割り込みコントローラは、マスクレジスタ(mask register)とステータス
レジスタ(status register)を持つことで割り込みを制御している。
マスクレジスタは、ビットの設定によって割り込みの可不可を決定するものであり、
ステータスレジスタはシステム上の現在アクティブな割り込みを示すものである。

<!--
Some of the interrupts in the system may be hard-wired, for example, the real
time clock's interval timer may be permanently connected to pin 3 on the
interrupt controller. However, what some of the pins are connected to may be
determined by what controller card is plugged into a particular ISA or PCI 
slot. For example, pin 4 on the interrupt controller may be connected to PCI 
slot number 0 which might one day have an ethernet card in it but the next 
have a SCSI controller in it. The bottom line is that each system has its own 
interrupt routing mechanisms and the operating system must be flexible enough 
to cope. 
-->
<p>システム上の割り込みのいくつかは、物理的に配線が固定されている場合がある。
たとえば、リアルタイムクロックのインターバルタイマーは、割り込みコントローラの
ピン 3 に固定的に接続されていることがある。
しかし、ピンが何に接続されているかは、特定の PCI か ISA スロットにどのような
コントローラカードが差されているかによって決まる場合もある。たとえば、割り込み
コントローラのピン 4 は、PCI スロットの 0 番に接続されているかもしれず、その
スロットには、あるときはイーサネットが差されていて、別のときは SCSI コント
ローラが差されているかもしれない。
結局、基本的に、割り込みを伝達する仕組みはシステムごとに異なるので、
オペレーティングシステムにはそれに対処するだけの柔軟性がなければならない。

<!--
Most modern general purpose microprocessors handle the interrupts the same
way. When a hardware interrupt occurs the CPU stops executing the instructions
that it was executing and jumps to a location in memory that either contains 
the interrupt handling code or an instruction branching to the interrupt 
handling code. This code usually operates in a special mode for the CPU, 
interrupt mode, and, normally, no other interrupts can happen in this mode. 
There are exceptions though; some CPUs rank the interrupts in priority and 
higher level interrupts may happen. This means that the first level interrupt 
handling code must be very carefully written and it often has its own stack, 
which it uses to store the CPU's execution state (all of the CPU's normal 
registers and context) before it goes off and handles the interrupt. Some CPUs
have a special set of registers that only exist in interrupt mode, and the 
interrupt code can use these registers to do most of the context saving it 
needs to do. 
-->
<p>現在の汎用マイクロプロセッサの大部分は、同じ方法で割り込みを処理している。
ハードウェア割り込みが発生すると、CPU は、現在実行中の命令の実行を停止し、
割り込み処理コードそのものか、あるいは割り込み処理コードへと分岐する命令の
どちらかを含んだメモリ内のある場所へとジャンプする。
通常このコードは、割り込みモードと言われる CPU の特別なモードで実行されるので、
一般に、このモードにあるときは、他の割り込みは起こらない。
ただし例外があり、ある CPU では割り込みに優先順位を付けているので
優先順位の高い割り込みは起こる場合がある。
すなわち、最高の優先度を持つ割り込み処理コードは非常に入念に書かれていなけれ
ばならず、しばしば独自のスタックを備えているため、その割り込み処理コード
は、起動されて割り込みを処理する前に、そのスタックを使って CPU の実行状態(CPU 
の通常のレジスタとコンテキストのすべて)を保存する。
CPU のなかには、割り込みモード専用の特別なレジスタセットを持っているものが
あるため、割り込み処理コードは、それらのレジスタを使って必要なコンテキスト保存
操作の大部分を実行する。

<!--
When the interrupt has been handled, the CPU's state is restored and the
interrupt is dismissed. The CPU will then continue to doing whatever it was 
doing before being interrupted. It is important that the interrupt processing 
code is as efficient as possible and that the operating system does not block 
interrupts too often or for too long. 
-->
<p>割り込み処理が終了すると、CPU の状態は元に戻され、割り込みは解除される。
CPU は、割り込みが起こる前に実行していた処理を継続する。重要なのは、割り込み処
理コードは出来る限り効率の良いものであることであり、オペレーティングシステムが
頻繁に、あるいは長時間、他の割り込みをブロックすることがないようにすることであ
る。

<!--7.1  Programmable Interrupt Controllers-->
<sect1>プログラム可能な割り込みコントローラ<label id="chapter_i_sect1">

<!--
Systems designers are free to use whatever interrupt architecture they wish but
IBM PCs use the Intel 82C59A-2 CMOS Programmable Interrupt Controller or
its derivatives. This controller has been around since the dawn of the PC and 
it is programmable with its registers being at well known locations in the ISA
address space. Even very modern support logic chip sets keep equivalent 
registers in the same place in ISA memory. Non-Intel based systems such as 
Alpha AXP based PCs are free from these architectural constraints and so often
use different interrupt controllers. 
-->
<p>システム設計者は、自分の好きな割り込みの仕組みを自由に使うことができるが、
IBM PC では、Intel 82C59A-2 という CMOS プログラム可能な割り込みコントローラ
(Programable Interrupt Controller)か、その派生コントローラが使用されている。
このコントローラは、PC の黎明期からあるもので、ISA アドレス空間の決まった場所
(well known location)に存在するレジスタを使ってプログラムすることができる。
最新の補助ロジックチップでさえ、同様のレジスタを ISA メモリの同じ場所に置いて
いる。Alpha AXP のような非 Intel ベースの PC では、そうしたハードウェア上の
制約から解放されており、たいていの場合、それとは異なる割り込みコントローラを
使用している。

<!--
Figure  7.1 shows that there are two 8 bit controllers chained together; each
having a mask and an interrupt status register, PIC1 and PIC2. The mask
registers are at addresses 0x21 and 0xA1 and the status registers are at 0x20
and 0xA0 Writing a one to a particular bit of the mask register enables an
interrupt, writing a zero disables it. So, writing one to bit 3 would enable 
interrupt 3, writing zero would disable it. Unfortunately (and irritatingly), 
the interrupt mask registers are write only, you cannot read back the value 
that you wrote. This means that Linux must keep a local copy of what it has 
set the mask registers to. It modifies these saved masks in the interrupt 
enable and disable routines and writes the full masks to the registers every 
time. 
-->
<p><ref id="figure7-1" name="図表(7.1)">では、ふたつの 8 ビットのプログラム可能
な割り込みコントローラ(Programable Interrupt Controller, PIC)が鎖状に繋がれてい
て、PIC 1 と PIC 2 の個々のコントローラが、それぞれマスクレジスタ(mask 
register)と割り込みステータスレジスタ(interrupt status register)を持ってい
る様子が示されている。
マスクレジスタは、アドレス 0x21 と 0xA1 にあり、ステータスレジスタは、
アドレス 0x20 と 0xA0 にある。
マスクレジスタの特定のビットに 1 を書き込むと割り込みが可能になり、0 を書き込む
と不可になる。そして、ビット 3 に 1 を書き込むと、割り込み 3 が使用可能になり、
0 を書き込むと不可となる。残念なことに(そして、困ったことに)、割り込みマスク
レジスタは書き込み専用であり、書き込んだ値を読み出すことはできない。すなわち、
Linux は、マスクレジスタに設定した値のコピーを自分で保存しなければならない
ことを意味する。Linux はいつも、割り込みの可不可を設定するルーチンに
保存した、それらのマスク値を修正してから、レジスタにマスク値全部を上書きして
いる。

<!--
When an interrupt is signalled, the interrupt handling code reads the two 
interrupt status registers (ISRs). It treats the ISR at 0x20 as the bottom 
eight bits of a sixteen bit interrupt register and the ISR at 0xA0 as the top 
eight bits. So, an interrupt on bit 1 of the ISR at 0xA0 would be treated as 
system interrupt 9. Bit 2 of PIC1 is not available as this is used to chain 
interrupts from PIC2, any interrupt on PIC2 results in bit 2 of PIC1 being 
set. 
-->
<p>割り込みが発生したとき、割り込み処理コードは、ふたつの割り込みステータス
レジスタ(Interrupt status register, ISR)の値を読み出す。
割り込み処理コードは、16 ビットある割り込みステータスレジスタのうち、0x20 に
ある ISR を下位 8 ビットとして扱い、0xA0 にある ISR を上位 8 ビットとして
扱う。
それゆえ、0xA0 にある ISR のビット 1 は、システム割り込み 9 として扱われる。
プログラム可能な割り込みコントローラ PIC 1 のビット 2 は利用できないが、
それは、PIC 2 からの割り込みを繋げるために使用されているからであり、PIC 2 上の
割り込みは、PIC 1 のビット 2 としてセットされる。


<!--7.2  Initializing the Interrupt Handling Data Structures-->
<sect1>割り込み処理のデータ構造の初期化<label id="chapter_i_sect2">

<!--
The kernel's interrupt handling data structures are set up by the device 
drivers as they request control of the system's interrupts. To do this the 
device driver uses a set of Linux kernel services that are used to request an 
interrupt, enable it and to disable it. 
The individual device drivers call these routines to register their interrupt
handling routine addresses. 
-->
<p>カーネルの割り込み処理のためのデータ構造体は、デバイスドライバがシステムの
割り込みの制御を要求する際に、デバイスドライバによって設定される。
その場合、デバイスドライバは、Linux カーネルの一連のサービスを使用して、それに
よって、割り込みを要求したり、あるいは割り込みの可不可を設定したりする。
<newline>
[see: request_irq(), enable_irq(), disable_irq(), in arch/*/kernel/irq.c]
(<htmlurl url="./The-Linux-Kernel-images/linux/arch/i386/kernel/irq.c" 
name="i386">, <htmlurl 
url="./The-Linux-Kernel-images/linux/arch/alpha/kernel/irq.c" 
name="alpha">)<newline>
個別のデバイスドライバは、そうしたルーチンを呼び出して、それぞれの割り込み処理
ルーチンのアドレスを登録する。

<!--
Some interrupts are fixed by convention for the PC architecture and so the 
driver simply requests its interrupt when it is initialized. This is what the 
floppy disk device driver does; it always requests IRQ 6. There may be 
occassions when a device driver does not know which interrupt the device will 
use. This is not a problem for PCI device drivers as they always know what 
their interrupt number is. Unfortunately there is no easy way for ISA device 
drivers to find their interrupt number. Linux solves this problem by allowing 
device drivers to probe for their interrupts. 
-->
<p>割り込みのなかには、PC アーキテクチャの慣習によって固定されているものがある
ので、その場合、ドライバは、初期化される際、単にその割り込みを要求するだけで
よい。
これは、フロッピーディスクドライバの動作そのものであり、フロッピーディスクドラ
イバは、いつも IRQ 6 を要求する。
デバイスドライバは、そのデバイスがどの割り込みを使うかを知らない場合もある。
PCI デバイスドライバの場合は、割り込み番号は常に明らかなので、
そうした問題は起きない。残念ながら、ISA デバイスドライバが割り込み番号を知ろう
とする場合は、簡単な方法というのはない。Linux は、この問題を解決するために、
デバイスドライバに割り込みを検出させる。

<!--
First, the device driver does something to the device that causes it to 
interrupt. Then all of the unassigned interrupts in the system are enabled. 
This means that the device's pending interrupt will now be delivered via the 
programmable interrupt controller. Linux reads the interrupt status register 
and returns its contents to the device driver. A non-zero result means that 
one or more interrupts occured during the probe. The driver now turns probing 
off and the unassigned interrupts are all disabled. 
If the ISA device driver has successfully found its IRQ number then it can now
request control of it as normal. 
-->
<p>まず、デバイスドライバは、何らかの形でデバイスに働きかけて、デバイスに割り
込みを発生させる。次に、システム上でまだ割り当てられていないすべての割り込み
を有効にする。これによって、そのデバイスが伝達できずに保留して
いた割り込みが、プログラム可能な割り込みコントローラ経由で伝達される。
Linux は、割り込みステータスレジスタを読み出し、デバイスドライバにその内容を
返す。0 でない値が返った場合、それは、ひとつ、もしくはそれ以上の割り込みが、
割り込み検出中に発生したことを意味する。この時点で、ドライバは、検出を
終了し、割り当てられていない割り込みは、すべて無効にされる。
<newline>[see: irq_problem_*(), in arch/*/kernel/irq.c](<htmlurl 
url="./The-Linux-Kernel-images/linux/arch/i386/kernel/irq.c" 
name="i386">, <htmlurl 
url="./The-Linux-Kernel-images/linux/arch/alpha/kernel/irq.c" 
name="alpha">)<newline>
ISA デバイスドライバが、IRQ 番号の検出に成功した場合、ドライバは、通常通り
その IRQ 番号の制御を要求する。

<!--
PCI based systems are much more dynamic than ISA based systems. The
interrupt pin that an ISA device uses is often set using jumpers on the 
hardware device and fixed in the device driver. On the other hand, PCI 
devices have their interrupts allocated by the PCI BIOS or the PCI subsystem 
as PCI is initialized when the system boots. Each PCI device may use one of 
four interrupt pins, A, B, C or D. This was fixed when the device was built 
and most devices default to interrupt on pin A. The PCI interrupt lines A, B, 
C and D for each PCI slot are routed to the interrupt controller. So, Pin A 
from PCI slot 4 might be routed to pin 6 of the interrupt controller, pin B 
of PCI slot 4 to pin 7 of the interrupt controller and so on. 
-->
<p>PCI ベースのシステムでは、ISA ベースのシステムよりももっと動的である。
ISA デバイスが使用する割り込みピン(IRQ)は、しばしばハードウェアデバイス上の
ジャンパを使って設定されるので、デバイスドライバ内で固定されている。
反対に、PCI デバイスは、システムのブート時に PCI が初期化される際、
PCI BIOS か PCI サブシステムによって割り込みを割り当てられる。
個々の PCI デバイスは、A, B, C, D の 4 つの割り込みのうち、ひとつを使用する。
(訳注: 規格上は、ひとつから 4 つまで使用できるそうです。)
これはデバイスの作成時に固定されており、大部分のデバイスは標準的なピン A を
割り込みに使用する。個々の PCI スロット上の A, B, C, D の
割り込みライン(interrupt line)は、割り込みコントローラに配線されている。
それゆえ、PCI スロット 4 のピン A は、割り込みコントローラのピン 6 に配線されて
いて、PCI スロット 4 のピン B は、割り込みコントローラのピン 7 に配線されている
等々となっている。

<!--
How the PCI interrupts are routed is entirely system specific and there must be
some set up code which understands this PCI interrupt routing topology. On 
Intel based PCs this is the system BIOS code that runs at boot time but for 
system's without BIOS (for example Alpha AXP based systems) the Linux kernel 
does this setup. 
The PCI set up code writes the pin number of the interrupt controller into the
PCI configuration header for each device. It determines the interrupt pin 
(or IRQ) number using its knowledge of the PCI interrupt routing topology 
together with the devices PCI slot number and which PCI interrupt pin that it 
is using. The interrupt pin that a device uses is fixed and is kept in a 
field in the PCI configuration header for this device. It writes this 
information into the interrupt line field that is reserved for this purpose. 
When the device driver runs, it reads this information and uses it to request 
control of the interrupt from the Linux kernel. 
-->
<p>割り込みがどのように伝達されるかは、完全にシステム固有のものであるので、
そのシステムの PCI 割り込みを伝達するトポロジーを理解しているなんらかの設定
コードが存在する必要がある。
Intel ベースの PC では、これは、起動時に実行されるシステム BIOS であるが、
BIOS のないシステム(たとえば、Alpha AXP ベースのシステム)では、Linux カーネルが
そのセットアップを行う。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/arch/alpha/kernel/bios32.c" 
name="arch/alpha/kernel/bios32.c">]<newline>
PCI 設定コードは、割り込みコントローラのピン番号をデバイスごとの 
<ref id="chapter_pci_sect2" name="PCI コンフィグレーションヘッダ">に書き込む。
PCI 設定コードは、、PCI の割り込み伝達トポロジーやデバイスの PCI スロット番号、
およびそれが現在どの PCI 割り込みピンを使っているかという知識を利用して、割り込
みピン(もしくは IRQ)を決定する。
デバイスが使用する割り込みピンは固定されていて、そのデバイスの PCI 
コンフィグレーションヘッダのフィールド内に保存されている。
PCI 設定コードは、割り込みライン(Interrupt Line)フィールドに、その情報を書き込
む。割り込みラインフィールドはこのために予約されたフィールドである。
デバイスドライバの実行時には、ドライバはこの情報を読み出し、それを使って 
Linux カーネルに割り込み制御を渡すよう要求する。

<!--
There may be many PCI interrupt sources in the system, for example when
PCI-PCI bridges are used. The number of interrupt sources may exceed the
number of pins on the system's programmable interrupt controllers. In this 
case, PCI devices may share interrupts, one pin on the interrupt controller 
taking interrupts from more than one PCI device. Linux supports this by 
allowing the first requestor of an interrupt source declare whether it may be 
shared. Sharing interrupts results in several irqaction data structures being 
pointed at by one entry in the irq_action vector vector. When a shared 
interrupt happens, Linux will call all of the interrupt handlers for that 
source. Any device driver that can share interrupts (which should be all PCI 
device drivers) must be prepared to have its interrupt handler called when 
there is no interrupt to be serviced. 
-->
<p>たとえば、PCI-PCI ブリッジが使用されているシステム上などでは、PCI 割り込みを
必要とするソースがたくさん存在する場合がある。割り込みソースの数が、システムの
プログラム可能な割り込みコントローラ上にあるピンの数を超える場合もある。
その場合、PCI デバイスは割り込みを共有し、割り込みコントローラ上のひとつの
ピンで、複数の PCI デバイスからの割り込みを受けることがある。
Linux がこれをサポートする場合、割り込みソースの中でその割り込みピンを最初に
要求したデバイスが、それを共有するかどうか明示できるようにするという方法
を取っている。割り込みが共有されるときは、いくつかの <tt><ref id="irqaction" 
name="irqaction"></tt> データ構造体が作成され、それらのデータ構造体が、
<tt><ref id="irq_action" name="irq_action"></tt> 配列の配列内にある各エントリ
によってポイントされる。
共有割り込みが起こると、Linux は、そのソースに対するすべての割り込みハンドラを
呼び出す。割り込みの共有が可能なすべてのデバイスドライバ(これらはすべて PCI 
デバイスドライバでなければならない)は、割り込みがサービスされていないときは、
そのドライバの割り込みハンドラーがいつ呼び出されてもいいように準備していなけれ
ばならない。

<!--7.3  Interrupt Handling-->
<sect1>割り込み処理<label id="chapter_i_sect3">
<p>

<label id="figure7-2">
<!--           Figure 7.2: Linux Interrupt Handling Data Structures-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure7-2.gif">
</figure>
</#if>
<#unless output="html">
<verb>
    irq_action
  +----------------+               irqaction
  |                |              +---------+
  |----------------|        +---->| handler |-----> このデバイスの
  |                |        |     | flags   |       割り込み処理
  |----------------|        |     | name    |       ルーチン
  |                |--------+     | next    |
  |----------------|              |         |
  |                |              +---------+
  |----------------|
  |                |
  |----------------|
  |                |
  |----------------|                irqaction       irqaction
3 |                |               +---------+     +---------+
  |----------------|         +---->| handler |---->| handler |
2 |                |         |     | flags   |     | flags   |
  |----------------|         |     | name    |     | name    |
1 |                |---------+     | next    |     | next    |
  |----------------|               |         |     |         |
0 |                |               +---------+     +---------+
  +----------------+
</verb>
</#if>
<p>図表(7.2) Linux 割り込み処理のデータ構造


<!--
One of the principal tasks of Linux's interrupt handling subsystem is to route
the interrupts to the right pieces of interrupt handling code. This code must
understand the interrupt topology of the system. If, for example, the floppy
controller interrupts on pin 6 1 of the interrupt controller then it must 
recognize the interrupt as from the floppy and route it to the floppy device 
driver's interrupt handling code. Linux uses a set of pointers to data 
structures containing the addresses of the routines that handle the system's 
interrupts. These routines belong to the device drivers for the devices in the
system and it is the responsibility of each device driver to request the 
interrupt that it wants when the driver is initialized. Figure  7.2 shows that
irq_action is a vector of pointers to the irqaction data structure. Each 
irqaction data structure contains information about the handler for this 
interrupt, including the address of the interrupt handling routine. As the 
number of interrupts and how they are handled varies between architectures 
and, sometimes, between systems, the Linux interrupt handling code is 
architecture specific. This means that the size of the irq_action vector 
vector varies depending on the number of interrupt sources that there are. 
-->
<p>Linux の割り込み処理サブシステムの主要なタスクのひとつが、割り込み要求を
正しい割り込み処理コードへと伝えることである。このコードは、システムの
割り込みトポロジーを理解していなければならない。たとえば、フロッピーコントロー
ラが割り込みコントローラのピン 6 上で割り込む場合、それは、その割り込みが
フロッピーからのものであることを認識して、フロッピーデバイスの割り込み処理
コードにそれを伝えなければならない。Linux は、一群のポインタを使って、システム
の割り込み処理ルーチンのアドレスを持つ各データ構造体を参照する。これらの
ルーチンは、システム上のデバイス用のデバイスドライバに属しており、ドライバが
初期化されるとき、必要な割り込みを要求するのは個々のデバイスドライバの責任で
ある。図表(7.2)では、<tt><ref id="irq_action" name="irq_action"></tt> は、
<tt><ref id="irqaction" name="irqaction"></tt> データ構造体
へのポインタの配列であることが示されている。個々の <tt>irqaction</tt> 
データ構造体は、割り込み処理ルーチンのアドレスが入っていると同時に、その
割り込みに対する処理ルーチンに関する情報が含まれている。割り込みの数と
その処理方法は、アーキテクチャや、時にはシステムによって異なるので、Linux の
割り込み処理コードは、アーキテクチャ固有のものである。これは、<tt>
irq_action</tt> 配列の配列が、存在する割り込みソースの数によって
異なることを意味している。

<!--
When the interrupt happens, Linux must first determine its source by reading 
the interrupt status register of the system's programmable interrupt 
controllers. It then translates that source into an offset into the irq_action
vector vector. So, for example, an interrupt on pin 6 of the interrupt 
controller from the floppy controller would be translated into the seventh 
pointer in the vector of interrupt handlers. If there is not an interrupt 
handler for the interrupt that occurred then the Linux kernel will log an 
error, otherwise it will call into the interrupt handling routines for all of 
the irqaction data structures for this interrupt source. 
-->
<p>割り込みが起こると、Linux は、まず、システムのプログラム可能な割り込みコント
ローラの割り込みステータスレジスタを読み出して、その割り込みソースを
判断する。そして、そのソースを <tt><ref id="irq_action" 
name="irq_action"></tt> 配列の配列に対するオフセット値に変換する。
それゆえ、たとえば、フロッピーコントローラからの割り込みコントローラのピン 6 
上の割り込みは、割り込み処理ルーチンの配列内での 7 番目のポインタへと変換され
る。発生した割り込みに対する割り込み処理ハンドラがない場合、Linux カーネルは
エラーをログに記録するか、あるいは、その割り込みソースの全 <tt>
<ref id="irqaction" name="irqaction"></tt> データ構造体に対する(デフォルトの)
割り込み処理ルーチンを呼び出す。

<!--
When the device driver's interrupt handling routine is called by the Linux 
kernel it must efficiently work out why it was interrupted and respond. To 
find the cause of the interrupt the device driver would read the status 
register of the device that interrupted. The device may be reporting an error 
or that a requested operation has completed. For example the floppy controller
may be reporting that it has completed the positioning of the floppy's read 
head over the correct sector on the floppy disk. Once the reason for the 
interrupt has been determined, the device driver may need to do more work. If 
it does, the Linux kernel has mechanisms that allow it to postpone that work 
until later. This avoids the CPU spending too much time in interrupt mode. See
the Device Driver chapter (Chapter dd-chapter) for more details. 
-->
<p>デバイスドライバの割り込み処理ルーチンが Linux カーネルによって呼び出された
とき、ルーチンは、割り込みが発生してそれに対処することになった理由を効率的に
調べなければならない。
割り込みの原因を見つけるため、デバイスドライバは、割り込みの発生した
デバイスのステータスレジスタを読み出す。デバイスは、エラーを報告しているかも
しれないし、要求された処理が完了したことを報告しているかもしれない。
たとえば、フロッピーコントローラが、フロッピーディスクの正しいセクタの上
への読みとりヘッドの位置移動を完了したことを報告しているのかもしれない。
割り込みの原因が判明すると、デバイスドライバは、さらに次の仕事をする必要が
生じる場合がある。その場合、Linux カーネルは、その仕事を後回しにすることができ
る仕組みを持っている。すなわち、それによって、CPU が、割り込みモードに長時間
入ったままになるのを防止する。それについての詳細は、<ref id="chapter_dd" 
name="「デバイスドライバ」">の章を見てほしい。

<!--
REVIEW NOTE: Fast and slow interrupts, are these an Intel thing? 
-->
REVIEW NOTE: 高速割り込みと低速割り込みというのは、Intel 系での実装なのか？

<!--
Footnotes:

1 Actually, the floppy controller is one of the fixed interrupts in a PC 
system as, by convention, the floppy controller is always wired to 
interrupt 6. 
-->
<footnote>
(脚注 1): 実際、フロッピーディスクコントローラは、慣習上、PC システムにおいて
決まった割り込みを使うデバイスのひとつである。フロッピーディスクコントローラ
は、いつも割り込み 6 に接続されている。
</footnote>

<!--第  9 章 デバイスドライバ-->
<!--Chapter 8 Device Drivers-->
<sect>デバイスドライバ<label id="chapter_dd">
<p>

<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/penguin2.gif">
</figure>

<!--
One of the purposes of an operating system is to hide the peculiarities of the
system's hardware devices from its users. For example the Virtual File
System presents a uniform view of the mounted filesystems irrespective of
the underlying physical devices. This chapter describes how the Linux kernel
manages the physical devices in the system. 
-->
<p>オペレーティングシステムの目的のひとつは、ユーザからシステムのハードウェア
の特殊性を隠すことである。たとえば仮想ファイルシステムは、土台となる物理
デバイスとは無関係に、マウントされたファイルシステムに統一的な視野を提供する。
この章では、Linux カーネルがシステム上の物理デバイスをどのように管理している
のかを解説する。

<!--
The CPU is not the only intelligent device in the system, every physical device
has its own hardware controller. The keyboard, mouse and serial ports are
controlled by a SuperIO chip, the IDE disks by an IDE controller, SCSI disks
by a SCSI controller and so on. Each hardware controller has its own control
and status registers (CSRs) and these differ between devices. The CSRs for
an Adaptec 2940 SCSI controller are completely different from those of an
NCR 810 SCSI controller. The CSRs are used to start and stop the device, to
initialize it and to diagnose any problems with it. Instead of putting code to
manage the hardware controllers in the system into every application, the
code is kept in the Linux kernel. The software that handles or manages a
hardware controller is known as a device driver. The Linux kernel device
drivers are, essentially, a shared library of privileged, memory resident, low
level hardware handling routines. It is Linux's device drivers that handle the
peculiarities of the devices they are managing. 
-->
<p>CPU だけがシステムで唯一の情報処理デバイスではなく、すべての物理デバイスが
独自のハードウェア制御装置を持っている。キーボード、マウス、シリアルポートは
 Super I/O チップで制御されており、IDE ディスクは IDE コントローラで、SCSI 
ディスクは SCSI コントローラで制御されている。個々のハードウェアコントローラは
独自のコントロールレジスタ(control registers)とステータスレジスタ(status 
registers)(あわせて CSRs)を持っている。それらレジスタの仕様はデバイスごとに異
なっており、Adaptec 2940 SCSI コントローラの CSRs は NCR 810 SCSI コントローラ
のそれとは別物である。CRSs はデバイスの始動と停止、初期化、そして問題診断
(diagnose)のために利用される。システム上のハードウェアコントローラを管理する
コードは、個々のアプリケーションに実装されるのではなく、Linux カーネルの中に
保持されている。
ハードウェアコントローラを操作あるいは管理するソフトウェアはデバイスドライバ
(device driver)と呼ばれている。Linux カーネルのデバイスドライバは、本質的に
特権を与えられ、メモリに常駐する、低レベルハードウェアの処理ルーチンから成る
共有ライブラリである。担当するデバイスの特殊性に対処するのが、Linux のデバイス
ドライバの役割である。

<!--
One of the basic features of Un*x is that it abstracts the handling of 
devices. All
hardware devices look like regular files; they can be opened, closed, read and
written using the same, standard, system calls that are used to manipulate
files. Every device in the system is represented by a device special file, for
example the first IDE disk in the system is represented by /dev/hda. For
block (disk) and character devices, these device special files are created by
the mknod command and they describe the device using major and minor
device numbers. Network devices are also represented by device special files
but they are created by Linux as it finds and initializes the network 
controllers in the system. All devices controlled by the same device driver 
have a common major device number. The minor device numbers are used to
distinguish between different devices and their controllers, for example each
partition on the primary IDE disk has a different minor device number. So,
/dev/hda2, the second partition of the primary IDE disk has a major number
of 3 and a minor number of 2. Linux maps the device special file passed in
system calls (say to mount a file system on a block device) to the device's
device driver using the major device number and a number of system tables,
for example the character device table, chrdevs . 
-->
<p>Un*x の基本的特徴のひとつは、デバイスの操作を抽象化していることである。
すべてのハードウェアデバイスは、通常ファイルのようのように見える。それらは、
ファイル操作で使用されるのと同じ標準的なシステムコールを利用して、オープン、
クローズ、書き込み、読み出しが可能である。システム上のあらゆるデバイスは、
デバイススペシャルファイルによって表現されていて、たとえば、システム上の最初の 
IDE ディスクは <tt>/dev/hda</tt> と表される。
<p>ブロック(ディスク)デバイスとキャラクタデバイスに関しては、それらのデバイス
スペシャルファイルは <tt>mknod</tt> コマンドによって作成され、デバイスを記述
するためにメジャー番号(<ref id="major_number" name="major number">)とマイナー
番号(minor number)とのデバイス番号が使用される。ネットワークデバイスも
デバイススペシャルファイルによって表現されるが、それらは Linux がシステム上の
ネットワークコントローラを見つけて初期化するときに Linux によって作成される。
同一のデバイスドライバによって制御されるすべてのデバイスコントローラは、共通の
メジャー番号を持つ。マイナーデバイス番号が使用されるのは、デバイスドライバが
異なるデバイスやそのデバイスのコントローラを区別するためである。たとえば、プラ
イマリ IDE ディスク上の個々のパーティションは異なるマイナー番号を持つ。それゆ
え、プライマリ IDE ディスクの第二パーティション <tt>/dev/hda2</tt> は、メジャー
番号 3 とマイナー番号 2 を持つ。
Linux は、システムコールで(たとえばブロックデバイス上のファイルシステムをマウン
トするなどして)渡されたデバイススペシャルファイルをそのデバイスのデバイスドライ
バにマップする。その際は、デバイスのメジャー番号といくつかのシステムテーブル、
たとえば <tt><ref id="device_struct" name="chrdevs"></tt> というキャラクタ
デバイステーブルなどを使用する。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/fs/devices.c"
name="fs/devices.c">]<newline>

<!--
Linux supports three types of hardware device: character, block and network.
Character devices are read and written directly without buffering, for example
the system's serial ports /dev/cua0 and /dev/cua1. Block devices can
only be written to and read from in multiples of the block size, typically 512
or 1024 bytes. Block devices are accessed via the buffer cache and may be
randomly accessed, that is to say, any block can be read or written no matter
where it is on the device. Block devices can be accessed via their device
special file but more commonly they are accessed via the file system. Only a
block device can support a mounted file system. Network devices are
accessed via the BSD socket interface and the networking subsytems
described in the Networking chapter (Chapter  network-chapter). 
-->
<p>Linux は 3 種類のハードウェアデバイスをサポートしている。キャラクタデバイス
(character device)、ブロックデバイス(block device)、ネットワークデバイス(
network device)である。キャラクタデバイスは、バッファなしで直接読み書き
するデバイスであり、たとえばシステムのシリアルポート <tt>/dev/cua0</tt> や 
<tt>/dev/cua1</tt> などがそうである。ブロックデバイスとは、ブロックサイズの
倍数、典型的には 512 か 1024 バイトでのみ読み書きするデバイスである。
ブロックデバイスはバッファキャッシュ経由でアクセスされ、ランダムなアクセス、
すなわちデバイス上のどこにあるブロックでも読み書きできるアクセス方法が利用
されることが多い。ブロックデバイスへのアクセスは、それぞれに対応した
デバイススペシャルファイルを経由しても可能であるが、ファイルシステム経由で
アクセスするほうがより一般的である。マウントされるファイルシステムをサポート
できるのはブロックデバイスだけである。ネットワークデバイスへのアクセスは、
<ref id="chapter_net" name="「ネットワーク」">の章で解説する 
BSD ソケットインターフェイスまたはネットワークサブシステム経由で行なう。

<!--
There are many different device drivers in the Linux kernel (that is one of
Linux's strengths) but they all share some common attributes: 
-->
<p>Linux カーネル内には多種多様のデバイスドライバがある(これは、Linux の長所
のひとつである)が、それらすべてが以下の一般的な属性を共有している。

<!--
kernel code
      Device drivers are part of the kernel and, like other code within the
      kernel, if they go wrong they can seriously damage the system. A
      badly written driver may even crash the system, possibly corrupting
      file systems and losing data, 
-->
<descrip>
<tag>カーネルコード (kernel code)</tag>
デバイスドライバはカーネルの一部なので、カーネル内の他のコードと同様に、もし
上手く動かないとシステムに深刻な影響を与える。出来の悪いドライバはシステムを
クラッシュさせる場合すらあり、その結果ファイルシステムが破壊されデータが喪失
することもあり得る。

<!--
Kernel interfaces
      Device drivers must provide a standard interface to the Linux kernel
      or to the subsystem that they are part of. For example, the terminal
      driver provides a file I/O interface to the Linux kernel and a SCSI
      device driver provides a SCSI device interface to the SCSI subsystem
      which, in turn, provides both file I/O and buffer cache interfaces to the
      kernel. 
-->
<tag>カーネルインターフェイス (kernel interfaces)</tag>
デバイスドライバは、Linux カーネルやそれが所属するサブシステムに対して標準イン
ターフェイスを提供しなければならない。たとえば端末ドライバは Linux カーネルに
ファイルへの I/O インターフェイスを提供し、SCSI デバイスドライバは SCSI サブ
システムに対してインターフェイスを提供し、そのサブシステムが次に Linux カーネル
に対してファイル I/O とバッファキャッシュインターフェイスを提供する。

<!--
Kernel mechanisms and services
      Device drivers make use of standard kernel services such as memory
      allocation, interrupt delivery and wait queues to operate, 
-->
<tag>カーネルメカニズムとサービス</tag>
デバイスドライバは、メモリ割り当てや割り込みの伝達、待ち行列などの
標準的なカーネルサービスを利用する。

<!--
Loadable
      Most of the Linux device drivers can be loaded on demand as kernel
      modules when they are needed and unloaded when they are no longer
      being used. This makes the kernel very adaptable and efficient with
      the system's resources, 
-->
<tag>動的ロードが可能(loadable)</tag>
Linux のデバイスドライバの大部分は必要なときにオンデマンドでカーネルモジュール
としてロードが可能であり、必要が無くなればアンロードもできる。これによって、
カーネルの適用能力が高くなり、システムリソースの利用効率も上がる。

<!--
Configurable
      Linux device drivers can be built into the kernel. Which devices are
      built is configurable when the kernel is compiled, 
-->
<tag>設定の柔軟性</tag>
Linux のデバイスドライバはカーネル内に組み込むことも可能である。どのデバイス
を組み込むかは、カーネルのコンパイル時に設定できる。

<!--
Dynamic
      As the system boots and each device driver is initialized it looks for
      the hardware devices that it is controlling. It does not matter if the
      device being controlled by a particular device driver does not exist. In
      this case the device driver is simply redundant and causes no harm
      apart from occupying a little of the system's memory. 
-->
<tag>動的な設定(dynamic)</tag>
システムが起動して個々のデバイスドライバが初期化されると、ドライバは制御すべ
きハードウェアデバイスを捜す。特定のデバイスドライバにより制御されるはずの
デバイスが存在しなかったとしても問題はない。その場合、デバイスドライバは、
単に余分なだけであり、少量のシステムメモリが占有されることを除いて如何なる
悪影響も及ぼさない。
</descrip>


<!--8.1  Polling and Interrupts-->
<sect1>ポーリングと割り込み<label id="chapter_dd_sect1">

<!--
Each time the device is given a command, for example ``move the read head to
sector 42 of the floppy disk'' the device driver has a choice as to how it 
finds out that the command has completed. The device drivers can either poll 
the device or they can use interrupts. 
-->
<p>たとえば「読み取りヘッダをフロッピーディスクのセクタ 42 へ動かせ」といった
コマンドをデバイスが受け取ると、デバイスドライバは次のいずれかの方法、つまり
デバイスをポーリング(polling)するか、あるいは割り込み(interrupt)を使うことに
よって、そのコマンドが完了したかどうかを確認する。

<!--
Polling the device usually means reading its status register every so often
until the device's status changes to indicate that it has completed the 
request. As a device driver is part of the kernel it would be disasterous if a
driver were to poll as nothing else in the kernel would run until the device 
had completed the request. Instead polling device drivers use system timers to
have the kernel call a routine within the device driver at some later time. 
This timer routine would check the status of the command and this is exactly 
how Linux's floppy driver works. Polling by means of timers is at best 
approximate, a much more efficient method is to use interrupts. 
-->
<p>通常、デバイスのポーリングとは、デバイスのステータスレジスタが変化して、
リクエストの実行を完了したことが示されるまで、デバイスのステータスレジスタを
頻繁に読み出す操作を意味している。
デバイスドライバはカーネルの一部であるので、もし、ドライバがポーリングし続ける
とすると、システムに悪影響を与える。というのも、その場合、デバイスがリクエスト
を完了するまで、カーネル内では何も実行されなくなるからである。
しかし、実際にポーリングを行うデバイスドライバは、システムタイマーを使用して、
一定時間経過後に、カーネルにデバイスドライバ内のルーチンを呼び出してもらうよう
にしている。
このシステムタイマーのルーチンは、コマンドのステータスをチェックする。Linux の
フロッピードライバは、まさにこの仕組みを使っている。だが、タイマーを使った
ポーリングでは、精々大ざっぱな制御しかできない。もっと効率の良い方法は、
割り込み(interrupt)を使うことである。

<!--
An interrupt driven device driver is one where the hardware device being
controlled will raise a hardware interrupt whenever it needs to be serviced.
For example, an ethernet device driver would interrupt whenever it receives an
ethernet packet from the network. The Linux kernel needs to be able to deliver
the interrupt from the hardware device to the correct device driver. This is
achieved by the device driver registering its usage of the interrupt with the
kernel. It registers the address of an interrupt handling routine and the
interrupt number that it wishes to own. You can see which interrupts are being
used by the device drivers, as well as how many of each type of interrupts
there have been, by looking at /proc/interrupts: 
-->
<p>割り込みによって駆動されるデバイスドライバとは、ハードウェアデバイスが
サービスを要求するとき、ハードウェアデバイスがハードウェア割り込みをかける
ことで、制御されているものである。
たとえばイーサネットドライバは、イーサネットがネットワークからパケットを
受信したときに割り込みをかける。Linux カーネルは、ハードウェアデバイスから正し
いデバイスドライバへとその割り込みを伝達できなければならない。
これを実現するために、デバイスドライバは、割り込みの処理方法をカーネルに登録す
る。デバイスドライバが登録するのは、割り込み処理ルーチンのアドレスと占有したい
割り込み番号である。どの割り込みがデバイスドライバに使用されているか、
割り込みのタイプ(<ref id="type_of_interrupts" name="type of interrupts">)が
それぞれいくつあるかを確認するには、<tt>/proc/interrupts</tt> を見ればよい。

<verb>
 0:     727432   timer
 1:      20534   keyboard
 2:          0   cascade
 3:      79691 + serial
 4:      28258 + serial
 5:          1   sound blaster
11:      20868 + aic7xxx
13:          1   math error
14:        247 + ide0
15:        170 + ide1
</verb>

<!--
This requesting of interrupt resources is done at driver initialization time.
Some of the interrupts in the system are fixed, this is a legacy of the IBM
PC's architecture. So, for example, the floppy disk controller always uses
interrupt 6. Other interrupts, for example the interrupts from PCI devices are
dynamically allocated at boot time. In this case the device driver must first
discover the interrupt number (IRQ) of the device that it is controlling before
it requests ownership of that interrupt. For PCI interrupts Linux supports
standard PCI BIOS callbacks to determine information about the devices in
the system, including their IRQ numbers. 
-->
<p>割り込みリソースに関する要求は、ドライバの初期化の際に処理される。
システム上の割り込みのいくつかは固定されているが、それは IBM PC アーキテクチャ
の遺産である。したがって、たとえばフロッピーディスクコントローラは常に割り込み
 6 を使用する。それ以外の割り込み、たとえば PCI デバイスからの割り込みは、起動
時に動的に割り当てられる。その場合、デバイスドライバは、まず、制御している
デバイスの割り込み番号(IRQ)を検出した上で、その番号を占有する旨要求
しなければならない。PCI デバイスの割り込みに関して、Linux は、標準的な 
<ref id="chapter_pci_sect6-3" name="PCI BIOS"> のコールバックをサポートする
ことで、システム上のデバイスに関する、IRQ 番号等の情報を判断している。

<!--
How an interrupt is delivered to the CPU itself is architecture dependent but
on most architectures the interrupt is delivered in a special mode that stops
other interrupts from happening in the system. A device driver should do as
little as possible in its interrupt handling routine so that the Linux kernel 
can dismiss the interrupt and return to what it was doing before it was 
interrupted. Device drivers that need to do a lot of work as a result of 
receiving an interrupt can use the kernel's bottom half handlers or task 
queues to queue routines to be called later on. 
-->
<p>割り込みが CPU 自体に伝達される方法はアーキテクチャによって異なるが、大部分
のアーキテクチャでは、割り込みの伝達は、システム上で他の割り込みの発生を停止さ
せる特別なモードで行われる。したがって、デバイスドライバは、割り込み処理ルーチ
ン内でできる限り簡潔な処理をすべきである。そうすれば、Linux カーネルは割り込み
処理をすぐに終了して、割り込みが起こる前に実行していたことに戻ることができる。
割り込みを受信した結果多くの処理をしなければならなくなった場合、デバイスドライ
バは、カーネルのボトムハーフハンドラ(<ref id="chapter_km_sect1" 
name="bottom half handler">)かタスクキュー(<ref id="chapter_km_sect2" 
name="task queue">)
を使用してルーチンをキューイングし、後で呼び出すという方法を取ることができる。

<!--8.2  Direct Memory Access (DMA)-->
<sect1>ダイレクトメモリアクセス(Direct Memory Access, DMA)<label 
id="chapter_dd_sect2">

<!--
Using interrupts driven device drivers to transfer data to or from hardware
devices works well when the amount of data is reasonably low. For example a
9600 baud modem can transfer approximately one character every millisecond
(1/1000 'th second). If the interrupt latency, the amount of time that it takes
between the hardware device raising the interrupt and the device driver's
interrupt handling routine being called, is low (say 2 milliseconds) then the
overall system impact of the data transfer is very low. The 9600 baud modem
data transfer would only take 0.002% of the CPU's processing time. For high
speed devices, such as hard disk controllers or ethernet devices the data
transfer rate is a lot higher. A SCSI device can transfer up to 40 Mbytes of
information per second. 
-->
<p>割り込み駆動型のデバイスドライバを使ってハードウェアデバイスと情報をやり
取りすることが有効なのは、データ量が比較的少ないときである。たとえば 9600 baud 
のモデムはミリ秒(1/1000 秒)あたりおよそ一文字を送信可能である。割り込み遅延
(interrupt latency)、すなわちハードウェアデバイスが割り込みを発信してから
デバイスドライバの割り込み処理ルーチンが呼び出されるまでの時間が短い場合
(たとえば 2 ミリ秒)、データ転送に要するシステム全体へのインパクトは非常に小さ
い。9600 baud のモデムのデータ転送は、0.002&percnt; の CPU 処理時間しかかからな
い。しかし、ハードディスクコントローラやイーサネットのような高速なデバイスの
場合、データ転送レートはずっと高くなる。SCSI デバイスは、最大で毎秒 40 M バイト
の情報を転送できる。

<!--
Direct Memory Access, or DMA, was invented to solve this problem. A DMA
controller allows devices to transfer data to or from the system's memory
without the intervention of the processor. A PC's ISA DMA controller has 8
DMA channels of which 7 are available for use by the device drivers. Each
DMA channel has associated with it a 16 bit address register and a 16 bit
count register. To initiate a data transfer the device driver sets up the DMA
channel's address and count registers together with the direction of the data
transfer, read or write. It then tells the device that it may start the DMA 
when it wishes. When the transfer is complete the device interrupts the PC. 
Whilst the transfer is taking place the CPU is free to do other things. 
-->
<p>ダイレクトメモリアクセス(<ref id="DMA" name="DMA">)はこの問題を解決するため
に発明された。DMA 
コントローラによって、デバイスはプロセッサの介在なしでシステムメモリとの
データのやり取りが可能になる。ISA の DMA コントローラは 8 個の DMA チャンネル
を持っていて、そのうち 7 個はデバイスドライバによって使用することができる。
個々の DMA チャンネルは、16 ビットのアドレスレジスタ(address register)と 16 
ビットのカウントレジスタ(count register)を利用して、デバイスとメモリ間での
転送を行っている。データ転送を始める際、デバイスドライバは DMA チャンネルのアド
レスレジスタとカウントレジスタを設定し、同時に読み出しか書き込みかのデータ転送
の方向を設定する。そしてデバイスドライバは、デバイスに対して、デバイス側の準備
が整い次第 DMA データ転送を始めることを告げる。転送が完了したとき、デバイスは 
PC に割り込みをかける。転送が行われている間、CPU は自由の他のことが出来る。

<!--
Device drivers have to be careful when using DMA. First of all the DMA
controller knows nothing of virtual memory, it only has access to the physical
memory in the system. Therefore the memory that is being DMA'd to or from
must be a contiguous block of physical memory. This means that you cannot
DMA directly into the virtual address space of a process. You can however
lock the process's physical pages into memory, preventing them from being
swapped out to the swap device during a DMA operation. Secondly, the DMA
controller cannot access the whole of physical memory. The DMA channel's
address register represents the first 16 bits of the DMA address, the next 8
bits come from the page register. This means that DMA requests are limited
to the bottom 16 Mbytes of memory. 
-->
<p>デバイスドライバは DMA を使用する際に注意しなければならないことがある。
何よりも先ず、DMA コントローラは仮想メモリについては何も知らず、システムの物理
メモリだけにしかアクセスできないことである。したがって、DMA 転送で書き込まれ
たり読み出されたりするメモリは、物理メモリ上の連続したブロックでなければなら
ない。これは、DMA を使ってプロセスの仮想アドレス空間へ直接アクセスできないこと
を意味する。しかし、メモリ上のプロセスの物理ページをロックして、DMA 処理の間に
それらがスワップデバイスにスワップアウトされないようにすることができる。
次に、DMA コントローラは物理メモリの全域にアクセスできるわけではないということ
である。DMA チャンネルのアドレスレジスタは、DMA アドレスの最初の 16 ビットを
表し、次の 8 ビットは DMA のページレジスタ(page register)から来ている。
これは、DMA リクエストは、メモリの下位 16 M バイトに制限されていることを意味
する。

<!--
DMA channels are scarce resources, there are only 7 of them, and they
cannot be shared between device drivers. Just like interrupts, the device
driver must be able to work out which DMA channel it should use. Like
interrupts, some devices have a fixed DMA channel. The floppy device, for
example, always uses DMA channel 2. Sometimes the DMA channel for a
device can be set by jumpers; a number of ethernet devices use this
technique. The more flexible devices can be told (via their CSRs) which DMA
channels to use and, in this case, the device driver can simply pick a free
DMA channel to use. 
-->
<p>DMA チャンネルは 7 本しかない希少資源であり、デバイスドライバ間で共有が
できない。割り込みの場合のように、デバイスドライバは、どの DMA チャンネルを使う
か決定できなければならない。割り込みの場合と同様、デバイスのなかには固定された 
DMA チャンネルを持つものがある。たとえばフロッピーディスクは常に DMA チャンネ
ル 2 を使用する。デバイスによっては、 DMA チャンネルをジャンパによって設定する
ことができる。多くのイーサネットデバイスはこのテクニックを使用する。より柔軟な
デバイスでは、(CSRs 経由で)どの DMA チャンネルを使うかを伝えられるようになって
いて、その場合、デバイスドライバは単に空の DMA チャンネルを選んで使用することが
できる。

<!--
Linux tracks the usage of the DMA channels using a vector of dma_chan
data structures (one per DMA channel). The dma_chan data structure
contains just two fields, a pointer to a string describing the owner of the DMA
channel and a flag indicating if the DMA channel is allocated or not. It is 
this vector of dma_chan data structures that is printed when you cat
/proc/dma. 
-->
<p>Linux は DMA チャンネルの利用状況を監視するために、DMA チャンネルごとにひと
つある <tt><ref id="dma_chan" name="dma_chan"></tt> データ構造体の、配列を
使用する。 <tt>dma_chan</tt> データ構造体にはフィールドがふたつだけあり、DMA 
チャンネルを使用しているデバイスを記述した文字列へのポインタと、その DMA 
チャンネルがすでに割り当てされているかどうかを表すフラグが含まれている。
<tt>/proc/dma</tt> を <tt>cat</tt> した際にプリントされるのは、この
<tt>dma_chan</tt> データ構造体の配列である。


<!--8.3  Memory-->
<sect1>メモリ<label id="chapter_dd_sect3">

<!--
Device drivers have to be careful when using memory. As they are part of the
Linux kernel they cannot use virtual memory. Each time a device driver runs,
maybe as an interrupt is received or as a bottom half or task queue handler is
scheduled, the current process may change. The device driver cannot rely
on a particular process running even if it is doing work on its behalf. Like 
the rest of the kernel, device drivers use data structures to keep track of the
device that it is controlling. These data structures can be statically 
allocated, part of the device driver's code, but that would be wasteful as it 
makes the kernel larger than it need be. Most device drivers allocate kernel, 
non-paged, memory to hold their data. 
-->
<p>デバイスドライバは注意深くメモリを使用しなければならない。デバイスドライバは
Linux カーネルの一部であるので、仮想メモリは使用できない。割り込みの受信や
ボトムハーフハンドラやタスクキューハンドラの実行によって、デバイスドライバが
起動されるたびに、カレントプロセスが変化する。デバイスドライバは、実行中で
あったプロセスに代わって処理をする場合であっても、特定の実行中のプロセスに
依存できない。カーネルの他の部分と同様に、デバイスドライバはデータ構造体を
使用して、現在制御しているデバイスを監視する。それらのデータ構造体はデバイス
ドライバの一部として静的に割り付けられることも可能だが、それはカーネルを
必要以上に大きくするだけでリソースの無駄使いになる。大部分のデバイスドライバ
は、ページ単位に分割されていないカーネルメモリを割り当てて、データを保持して
いる。

<!--
Linux provides kernel memory allocation and deallocation routines and it is
these that the device drivers use. Kernel memory is allocated in chunks that
are powers of 2. For example 128 or 512 bytes, even if the device driver asks
for less. The number of bytes that the device driver requests is rounded up to
the next block size boundary. This makes kernel memory deallocation easier
as the smaller free blocks can be recombined into bigger blocks. 
-->
<p>Linux はカーネルメモリの割り当てと解放のためのルーチンを提供しているので、
デバイスドライバはそのルーチンを使用する。カーネルメモリは 2 の n 乗ごとの範囲
で割り当てられる。たとえば、デバイスドライバが少量のメモリしか要求しない場
合でも 128 や 512 バイトを割り当てる。デバイスドライバが要求するバイト数は、次
のブロックサイズの値にまで切り上げられる。これによって、小さな空きメモリの
ブロックをより大きなブロックに再結合しやすくなるので、カーネルメモリの解放と
統合が容易になる。

<!--
It may be that Linux needs to do quite a lot of extra work when the kernel
memory is requested. If the amount of free memory is low, physical pages may
need to be discarded or written to the swap device. Normally, Linux would
suspend the requestor, putting the process onto a wait queue until there is
enough physical memory. Not all device drivers (or indeed Linux kernel code)
may want this to happen and so the kernel memory allocation routines can be
requested to fail if they cannot immediately allocate memory. If the device
driver wishes to DMA to or from the allocated memory it can also specify that
the memory is DMA'able. This way it is the Linux kernel that needs to
understand what constitutes DMA'able memory for this system, and not the
device driver. 
-->
<p>カーネルメモリがリクエストされた際、Linux カーネルは非常に多くの余計な仕事
をしなければならない場合がある。空きメモリの量が不足する場合、物理ページは
破棄されるかスワップデバイスに書き込まれる必要がある。通常、Linux は、要求した
プロセスを待ち行列に入れて、充分なメモリが確保されるまでそれをサスペンド状態に
する。しかし、デバイスドライバ(あるいは Linux カーネルコード)のなかにはサスペン
ドできないプロセスもあるので、そうした場合、すぐにメモリを確保できないときは、
カーネルメモリ割り当てルーチンは、リクエストの処理に失敗することもある。
デバイスドライバが DMA を使用して割り当てられたメモリに対して書き込みや読み出し
をしたい場合、ドライバは、そのカーネルメモリを DMA 転送が可能であると指定する
こともできる。この場合、システム上で DMA 転送が可能なメモリの構成がどうなって
いるのか理解しなければならないのは、デバイスドライバではなく、Linux カーネル
である。

<!--8.4  Interfacing Device Drivers with the Kernel-->
<sect1>デバイスドライバとカーネルとのインターフェイス<label 
id="chapter_dd_sect4">

<!--
The Linux kernel must be able to interact with them in standard ways. Each
class of device driver, character, block and network, provides common
interfaces that the kernel uses when requesting services from them. These
common interfaces mean that the kernel can treat often very different devices
and their device drivers absolutely the same. For example, SCSI and IDE
disks behave very differently but the Linux kernel uses the same interface to
both of them. 
-->
<p>Linux カーネルとデバイスドライバーとの相互通信は、標準的な方法で行われなけれ
ばならない。キャラクタデバイス、ブロックデバイス、ネットワークデバイスなど
個々のデバイスドライバのクラス(class)は、クラス共通のインターフェイスを提供して
いて、カーネルがそれらにサービスをリクエストする際は個々のクラスのインターフェ
イスを使用する。
各クラスのデバイスやデバイスドライバはしばしばかなり性質の異なることがあるが、
共通のインターフェイスがあることで、それらを全く同じものとして扱うことができ
る。たとえば、SCSI と IDE ディスクとは非常に異なった動作をするが、Linux カーネ
ルはそれら両方に対して同じインターフェイスを使用することができる。

<!--
Linux is very dynamic, every time a Linux kernel boots it may encounter
different physical devices and thus need different device drivers. Linux allows
you to include device drivers at kernel build time via its configuration 
scripts. When these drivers are initialized at boot time they may not discover
any hardware to control. Other drivers can be loaded as kernel modules when 
they are needed. To cope with this dynamic nature of device drivers, device 
drivers register themselves with the kernel as they are initialized. Linux 
maintains tables of registered device drivers as part of its interfaces with 
them. These tables include pointers to routines and information that support 
the interface with that class of devices. 
-->
<p>Linux は動的な設定にも柔軟に対応する。Linux は、起動のたびに異なった物理デバ
イスを検出するかもしれないので、そのために様々なデバイスドライバを必要とする。
Linux では、カーネルビルドの際の設定によって、デバイスドライバをカーネル
に組み込むことができる。しかし、起動時に初期化される際、組み込まれたデバイス
ドライバは、制御すべきハードウェアを見つけられないことがある。また、カーネルに
組み込まれない場合でも、ドライバが必要なときは、カーネルモジュールとしてそれを
ロードすることもできる。
このような動的なデバイスドライバの性質に対処するために、デバイスドライバは初期
化される際にカーネルに対して自分の情報を登録する。Linux は、それらへのインター
フェイスの一部として、登録されたデバイスドライバのテーブルを管理している。
それらのテーブルには、そのクラスのデバイスへのインターフェイスをサポートする
ルーチンおよび情報へのポインタが含まれている。

<!--8.4.1  Character Devices-->
<sect2>キャラクタデバイス<label id="chapter_dd_sect4-1">
<p>

<!--                  Figure 8.1: Character Devices-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure8-1.gif">
</figure>
</#if>
<#unless output="html">
<verb>
   chrdevs
+---------------+
|  name         |
|  fops         |---------->    file operations
|---------------|
|               |                lseek
|               |                read
|               |                write
|               |                readdir
|               |                select
|               |                ioctl
|               |                mmap
|               |                open
|               |                release
|               |                fsync
|               |                fasync
|               |                check_media_change
+---------------+                revalidate
</verb>
</#if>
<p>図表(8.1) キャラクタデバイス


<!--
Character devices, the simplest of Linux's devices, are accessed as files,
applications use standard system calls to open them, read from them, write to
them and close them exactly as if the device were a file. This is true even if
the device is a modem being used by the PPP daemon to connect a Linux
system onto a network. As a character device is initialized its device driver
registers itself with the Linux kernel by adding an entry into the chrdevs
vector of device_struct data structures. The device's major device
identifier (for example 4 for the tty device) is used as an index into this
vector. The major device identifier for a device is fixed. 

-->
<p>キャラクタデバイス(character device)は、Linux の中で最もシンプルなデバイス
である。それらはファイルとしてアクセスできるので、まるでそのデバイスがファイル
と全く同じであるかのように、アプリケーションは、標準システムコールを使用して
それらをオープンし、読み出しや書き込みをし、クローズする。
これは、デバイスとしてモデムを使い、PPP デーモンで Linux システムをネット
ワークに接続する場合でも同じである。キャラクタデバイスが初期化されるとき、その
デバイスドライバは、自分自身を Linux カーネルに登録するのだが、その際は、<tt>
<ref id="device_struct" name="device_struct"></tt> データ構造体による配列 <tt>
<ref id="device_struct" name="chrdevs"></tt> にエントリを追加する。
デバイスのメジャー番号(たとえば、4 は <tt>tty</tt> デバイス)は、
この配列へのインデックスとして使用される。デバイスの<ref id="major_number" 
name="メジャー番号">は、予め決められている。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/major.h"
name="include/linux/major.h">]<newline>

<!--
Each entry in the chrdevs vector, a device_struct data structure
contains two elements; a pointer to the name of the registered device driver
and a pointer to a block of file operations. This block of file operations is 
itself the addresses of routines within the device character device driver 
each of which handles specific file operations such as open, read, write and 
close. The contents of /proc/devices for character devices is taken from the
chrdevs vector. 
-->
<p><tt><ref id="device_struct" name="chrdevs"></tt> 配列の個々のエントリである
<tt><ref id="device_struct" name="device_struct"></tt> データ構造体には、
ふたつの要素がある。登録されたデバイスドライバの名前へのポインタと、ファイル操
作ルーチン群へのポインタである。
このファイル操作ルーチン群は、それ自体が当該デバイスのキャラクタデバイス
ドライバ内にあるルーチンのアドレスであり、その個々のルーチンが、<tt>open, 
read, write, close</tt> などファイルへの特定の操作を処理する。
キャラクタデバイスに関する <tt>/proc/devices</tt> の内容は、<tt>chrdevs</tt> 
配列から取得される。

<!--
When a character special file representing a character device (for example
/dev/cua0) is opened the kernel must set things up so that the correct
character device driver's file operation routines will be called. Just like an
ordinairy file or directory, each device special file is represented by a VFS
inode . The VFS inode for a character special file, indeed for all device 
special files, contains both the major and minor identifiers for the device. 
This VFS inode was created by the underlying filesystem, for example EXT2, from
information in the real filesystem when the device special file's name was
looked up. 
-->
<p>キャラクタデバイスを表すキャラクタ型スペシャルファイル(たとえば <tt>
/dev/cua0</tt>)がオープンされるとき、カーネルは適切な設定を行い、正しいキャラ
クタデバイスドライバのファイル操作ルーチンが呼び出されるようにしなければなら
ない。通常の
ファイルやディレクトリの場合と同様に、個々のデバイススペシャルファイルは VFS 
<tt><ref id="inode" name="inode"></tt> によって表される。
キャラクタ型スペシャルファイルの VFS inode には、すべてのスペシャルファイルと
同様に、デバイスに関するメジャー番号とマイナー番号が含まれている。
この VFS inode は、デバイススペシャルファイルの名前が問い合わせされる際に、
実ファイルシステム内の情報を元にして、<tt>EXT2</tt> などの基本ファイルシステム
によって作成される。
<newline>[see: ext2_read_inode(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/fs/ext2/inode.c" 
name="fs/ext2/inode.c">]<newline>

<!--
Each VFS inode has associated with it a set of file operations and these are
different depending on the filesystem object that the inode represents.
Whenever a VFS inode representing a character special file is created, its file
operations are set to the default character device operations. 
This has only one file operation, the open file operation. When the character
special file is opened by an application the generic open file operation uses 
the device's major identifier as an index into the chrdevs vector to retrieve 
the file operations block for this particular device. It also sets up the file
data structure describing this character special file, making its file 
operations pointer point to those of the device driver. Thereafter all of the 
applications file operations will be mapped to calls to the character devices 
set of file operations. 
-->
<p>個々の VFS inode は一連のファイル操作ルーチンと関連付けられるので、それら 
VFS inode の性質は、その inode が表現しているファイルシステムオブジェクトの
種類によって異なったものとなる。
キャラクタ型スペシャルファイルを表す VFS inode が作成される際はいつも、デフォル
トのキャラクタデバイス操作ルーチンがそのファイルの操作ルーチンとして設定され
る。
<newline>[see: def_chr_fops, in <htmlurl 
url="./The-Linux-Kernel-images/linux/fs/devices.c" 
name="fs/devices.c">]
<newline>[see: chrdev_open(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/fs/devices.c" 
name="fs/devices.c">]<newline>
このデフォルトのルーチンは、ファイルのオープンというひとつだけのファイル操作を
含むものである。アプリケーションによってキャラクタファイルがオープンされたと
き、その汎用のファイルオープン操作ルーチンは、デバイスのメジャー番号を <tt>
<ref id="device_struct" name="chrdevs"></tt> 配列へのインデックスとして使用し
て、その特定のデバイス用のファイル操作ルーチン群を取ってくる。またそれは、
当該キャラクタスペシャルファイルを記述する <tt><ref id="file" name="file">
</tt> データ構造体を設定し、そのファイル操作ルーチンへのポインタが当該デバイ
スドライバのファイル操作関数群を差すようにする。こうして、アプリケーションの
ファイル操作ルーチンはすべてマップされ、そのキャラクタデバイスに対する一連の
ファイル操作ルーチンの呼び出しに備える。

<!--8.4.2  Block Devices-->
<sect2>ブロックデバイス<label id="chapter_dd_sect4-2">

<!--
Block devices also support being accessed like files. The mechanisms used to
provide the correct set of file operations for the opened block special file 
are very much the same as for character devices. Linux maintains the set of
registered block devices as the blkdevs vector. It, like the chrdevs vector,
is indexed using the device's major device number. Its entries are also
device_struct data structures. Unlike character devices, there are
classes of block devices. SCSI devices are one such class and IDE devices
are another. It is the class that registers itself with the Linux kernel and
provides file operations to the kernel. The device drivers for a class of block
device provide class specific interfaces to the class. So, for example, a SCSI
device driver has to provide interfaces to the SCSI subsystem which the SCSI
subsystem uses to provide file operations for this device to the kernel. 
-->
<p>ブロックデバイスの場合も、ファイルにアクセスするときのようにアクセスできる
仕組みがサポートされている。オープンされたブロック型スペシャルファイルを操作
するために適切な一連のファイル操作ルーチンを提供する際、そのために使用される
メカニズムは、キャラクタデバイスの場合と全く同じである。Linux は、<tt><ref 
id="device_struct" name="blkdevs"></tt> 配列によって、登録された一連のブロック
デバイスを管理している。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/fs/devices.c" 
name="fs/devices.c">]<newline>
それは、<tt><ref id="device_struct" name="chrdevs"></tt> 配列と同様に、デバイス
のメジャー番号を使って索引付けされている。そのエントリも <tt><ref 
id="device_struct" name="device_struct"></tt> データ構造体である。
キャラクタデバイスと違う点は、ブロックデバイスにはクラスがあることである。
SCSI デバイスがそれであり、IDE デバイスもそうである。Linux に自分自身を
登録するのも、カーネルにファイル操作ルーチンを提供するのも、そうしたクラス
である。
ブロックデバイスのクラスに対するデバイスドライバは、そのクラスにクラス固有の
インターフェイスを提供する。それゆえ、たとえば SCSI デバイスドライバは、SCSI 
サブシステムに対してクラス固有のインターフェイスを提供しなければならず、
SCSI サブシステムはそれを使ってそのデバイスに対するファイル操作をカーネルに
提供する。

<!--
Every block device driver must provide an interface to the buffer cache as
well as the normal file operations interface. Each block device driver fills 
in its entry in the blk_dev vector 
of blk_dev_struct data structures . The index into this vector is, again, the
device's major number. The blk_dev_struct data structure consists of the
address of a request routine and a pointer to a list of request data
structures, each one representing a request from the buffer cache for the
driver to read or write a block of data. 
-->
<p>すべてのブロックデバイスドライバは、通常のファイル操作インターフェイスに
加えて、バッファキャッシュへのインターフェイスを提供しなければならない。個々の
ブロックデバイスドライバは、<tt><ref id="blk_dev_struct" 
name="blk_dev_struct"></tt> データ構造体の配列である <tt><ref 
id="blk_dev_struct" name="blk_dev"></tt> 内に自分のエントリを作成する。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/drivers/block/ll_rw_blk.c" 
name="drivers/block/ll_rw_blk.c">]
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/blkdev.h" 
name="include/linux/blkdev.h">]<newline>
この配列へのインデックスもまたデバイスのメジャー番号である。<tt>blk_dev_struct
</tt> データ構造体は、リクエストルーチンのアドレスと <tt><ref id="request" 
name="request"></tt> データ構造体のリストへのポインタによって構成される。
個々の <tt>request</tt> 構造体は、デバイスドライバにデータブロックを読み書き
させようとする、バッファキャッシュからのリクエストを表現している。


<!--           Figure 8.2: Buffer Cache Block Device Requests-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure8-2.gif">
</figure>
</#if>
<#unless output="html">
<verb>
     blk_dev
+---------------+
|               |
|               |     request          request
|---------------|   +---------+    +---------+
|request_fn()   |-->|rq_status| +->|rq_status|
|current_request|   |---------| |  |---------|
|               |   | rq_dev  | |  | rq_dev  |
|---------------|   |---------| |  |---------|
|               |   | mcd     | |  | mcd     |
|  :            |   |---------| |  |---------|
|               |   |         | |  |         |
|  :            |   |         | |  |         |
|               |   |---------| |  |---------|
|               |   | sem     | |  | sem     |   buffer_head
|               |   |---------| |  |---------|   +---------+
|               |   | bh      | |  | bh      |-->| b_dev   |0x0301
|---------------|   |---------| |  |---------|   |---------|
|               |   | tail    | |  | tail    |   |b_blocknr|39
|               |   |---------| |  |---------|   |---------|
|---------------|   | next    |-+  | next    |   | b_state |
|               |   +---------+    +---------+   |---------|
|               |                                | b_count |
+---------------+                                |---------|
                                                 | b_size  |1024
blk_dev_struct 配列                              |---------|
                                                 |         |
                                                 |         |
                                                 |---------|
                                                 | b_next  |
                                                 |---------|
                                                 | b_prev  |
                                                 |---------|
                                                 |         |
                                                 |         |
                                                 |---------|
                                                 | b_data  |
                                                 +---------+
</verb>
</#if>
<p>図表(8.2) バッファキャッシュブロックデバイスリクエスト


<!--
Each time the buffer cache wishes to read or write a block of data to or from a
registered device it adds a request data structure onto its
blk_dev_struct. Figure  8.2 shows that each request has a pointer to one
or more buffer_head data structures, each one a request to read or write a
block of data. The buffer_head structures are locked (by the buffer cache)
and there may be a process waiting on the block operation to this buffer to
complete. Each request structure is allocated from a static list, the
all_requests list. If the request is being added to an empty request list,
the driver's request function is called to start processing the request queue.
Otherwise the driver will simply process every request on the request list. 
-->
<p>バッファキャッシュが登録済みデバイスに対してデータブロックを読み書きしよ
うとする度に、バッファキャッシュはその <tt><ref id="blk_dev_struct" 
name="blk_dev_struct"></tt> に対して <tt><ref id="request" name="request">
</tt> データ構造体を付け加える。図表(8.2)では、個々のリクエストが
ひとつの以上の <tt><ref id="buffer_head" name="buffer_head"></tt> データ構造体
へのポインタを持っていて、それぞれがデータブロックの読み書きのリクエストとなっ
ていることが示されている。
<tt>buffer_head</tt> データ構造体は、(バッファキャッシュによって)ロックされ
るので、そのバッファへのブロック操作の完了を待っているプロセスが存在すること
がある。個々の <tt>request</tt> 構造体は、<tt><ref id="request" 
name="all_requests"></tt> リストというスタティックなリストから割り当てられる。
リクエストが空のリクエストリストに付け加えられた場合、ドライバのリクエスト処理
関数が呼び出され、リクエストキューの処理を始める。そうでない場合、ドライバは単
にリクエストリストにあるすべての <tt>request</tt> を処理する。

<!--
Once the device driver has completed a request it must remove each of the
buffer_head structures from the request structure, mark them as up to
date and unlock them. This unlocking of the buffer_head will wake up any
process that has been sleeping waiting for the block operation to complete. An
example of this would be where a file name is being resolved and the EXT2
filesystem must read the block of data that contains the next EXT2 directory
entry from the block device that holds the filesystem. The process sleeps on
the buffer_head that will contain the directory entry until the device driver
wakes it up. The request data structure is marked as free so that it can be
used in another block request. 
-->
<p>デバイスドライバがあるリクエストの処理を完了すると、ドライバは、<tt><ref 
id="request" name="request"></tt> 構造体から個々の <tt><ref id="buffer_head" 
name="buffer_head"></tt> 構造体を削除し、それらが更新されたことをマークして、
ロックを解除しなければならない。<tt>buffer_head</tt> のロック
解除はブロック操作の完了を待っているすべてのプロセスを目覚めさせる。たとえば、
ファイル名を解決するために、EXT2 ファイルシステムは、そのファイルシステムを
保持するブロックデバイスから次の EXT2 ディレクトリエントリーを含んだデータ
ブロックを読み出さなければならないとする。そのプロセスは、読み出そうとする
ディレクトリエントリを含む <tt>buffer_head</tt> 上でスリープ状態にあるが、
デバイスドライバがそのプロセスを目覚めさせる。(操作が完了すると) <tt>request
</tt> データ構造体は利用可能とマークされるので、次のブロックリクエストの際に
使用される。

<!--8.5  Hard Disks-->
<sect1>ハードディスク<label id="chapter_dd_sect5">

<!--
Disk drives provide a more permanent method for storing data, keeping it on
spinning disk platters. To write data, a tiny head magnetizes minute particles
on the platter's surface. The data is read by a head, which can detect whether
a particular minute particle is magnetized. 
-->
<p>ディスクドライブは、データを回転ディスクプラッタ(platter)上に保持すること
で、メモリよりもデータを長期的に保存する仕組みを提供する。データの書き込みには
小さなヘッドがプラッタの表面にある微細な粒子を磁化する。データはヘッドによって
読み出され、そのヘッドが特定の微細な粒子の磁化の有無を検出している。

<!--
A disk drive consists of one or more platters, each made of finely polished
glass or ceramic composites and coated with a fine layer of iron oxide. The
platters are attached to a central spindle and spin at a constant speed that 
can vary between 3000 and 10,000 RPM depending on the model. Compare this to
a floppy disk which only spins at 360 RPM. The disk's read/write heads are
responsible for reading and writing data and there is a pair for each platter,
one head for each surface. The read/write heads do not physically touch the
surface of the platters, instead they float on a very thin (10 millionths of an
inch) cushion of air. The read/write heads are moved across the surface of the
platters by an actuator. All of the read/write heads are attached together, 
they all move across the surfaces of the platters together. 
-->
<p>ディスクドライブは一枚以上のプラッタから構成される。個々のプラッタは丹念に
磨かれたガラスかセラミック合金から成り、酸化鉄の非常に薄い層でコートされて
いる。プラッタはセンタースピンドル(central spindle)に取り付けられ、モデルによっ
て違いがあるが、3000 から 10,000 の間の一定の速度で回転する。
これと比較した場合、フロッピーは 360 RPM でしか回転しない。
ディスクの読み書きヘッドはデータの読み書きを担当し、プラッタ
一枚に一組、その両面に装着されている。読み書きヘッドはプラッタ表面に物理的に
接触することなく、非常に薄い(1/1千万 インチ)空気の層をクッションに浮いている。
読み書きヘッドはアクチュエータによってプラッタの表面を移動する。すべての
読み書きヘッドは一体となっていて、プラッタ表面上をすべてが同時に動く。
(訳注: RPM, Revolutions Per Minute, 分あたりの回転数)

<!--
Each surface of the platter is divided into narrow, concentric circles called
tracks. Track 0 is the outermost track and the highest numbered track is the
track closest to the central spindle. A cylinder is the set of all tracks with
the same number. So all of the 5th tracks from each side of every platter in 
the disk is known as cylinder 5. As the number of cylinders is the same as the
number of tracks, you often see disk geometries described in terms of
cylinders. Each track is divided into sectors. A sector is the smallest unit of
data that can be written to or read from a hard disk and it is also the disk's
block size. A common sector size is 512 bytes and the sector size was set
when the disk was formatted, usually when the disk is manufactured. 
-->
<p>プラッタの個々の表面は、トラック(track)とよばれる細い同心円に分割されてい
る。トラック 0 が一番外側のトラックであり、最も大きな番号のトラックがセンター
スピンドルに最も近い位置にある。シリンダー(cylinder)とは、同一番号のトラックを
すべて一組にした概念である。それゆえ、ディスク内のすべてのプラッタの両面にある
 5 番トラック全体が、シリンダー 5 と呼ばれる。シリンダ数はトラック数と同じ
なので、ディスクジオメトリは、シリンダの方を使って記述される。個々のトラック
はセクタ(sector)に分割される。セクタはハードディスクで読み書き可能な最も小さな
データ単位であり、ディスクブロックサイズでもある。一般的なセクタサイズは 512 
バイトであり、セクタサイズはディスクのフォーマット時、通常はディスクが製造
された時に設定される。

<!--
A disk is usually described by its geometry, the number of cylinders, heads
and sectors. For example, at boot time Linux describes one of my IDE disks
as: 
-->
<p>ディスクは通常、シリンダ(cylinder)、ヘッド(head)、セクタ(sector)という
ジオメトリによって記述される。たとえば起動時に、Linux は IDE ディスクを次の
ように記述する。

<verb>
hdb: Conner Peripherals 540MB - CFS540A, 516MB w/64kB Cache, CHS=1050/16/63
</verb>

<!--
This means that it has 1050 cylinders (tracks), 16 heads (8 platters) and 63
sectors per track. With a sector, or block, size of 512 bytes this gives the 
disk a storage capacity of 529200 bytes. This does not match the disk's stated
capacity of 516 Mbytes as some of the sectors are used for disk partitioning
information. Some disks automatically find bad sectors and re-index the disk
to work around them. 
-->
<p>上記は、ディスクが 1050 シリンダ(トラック)、16 ヘッド(8 プラッタ)、そして
トラックごとに 63 セクタを持つことを意味する。セクタもしくはブロックサイズが
 512 バイトの場合、ディスクは 529200 キロバイト (1 キロバイト = 1024 バイト
として) の記憶容量を持つことになる。これはディスク情報として表示されるサイズ
である 516 メガバイトと一見異なっているように見えるが、529200 / 1024 は約 
516.8 となり、実は合っている。
(訳注: ちなみに 540MB というのは 1MB = 1000 x 1000 バイトで計算した場合の
数値である。)
ディスクのなかには、自動的に不良セクタを検出して、そのセクタの周辺にあるセクタ
を適切に利用するために、ディスクのインデックスを付け直すものもある。

<!--
Hard disks can be further subdivided into partitions. A partition is a large
group of sectors allocated for a particular purpose. Partitioning a disk allows
the disk to be used by several operating system or for several purposes. A lot
of Linux systems have a single disk with three partitions; one containing a
DOS filesystem, another an EXT2 filesystem and a third for the swap
partition. The partitions of a hard disk are described by a partition table; 
each entry describing where the partition starts and ends in terms of heads, 
sectors and cylinder numbers. For DOS formatted disks, those formatted by 
fdisk, there are four primary disk partitions. Not all four entries in the 
partition table have to be used. There are three types of partition supported 
by fdisk, primary, extended and logical. Extended partitions are not real 
partitions at all, they contain any number of logical parititions. Extended 
and logical partitions were invented as a way around the limit of four primary
partitions. The following is the output from fdisk for a disk containing two 
primary partitions: 
-->
<p>ハードディスクはさらにパーティションに分割できる。パーティションは特別な
目的のために割り当てられたセクタの大規模なグループである。ディスクを
パーティションに分割することで、そのディスクを様々なオペレーティング
システムや様々な目的に利用することが可能になる。多くの Linux システムは、
単一ディスク上に 3 つのパーティションを持つ。ひとつは DOS ファイルシステムを
持ち、ふたつ目が EXT2 ファイルシステム、3 つ目がスワップパーティションを持つ。
ハードディスクのパーティションは、パーティションテーブルによって記述
されている。その個々のエントリは、パーティションの最初と最後の位置をヘッド、
セクタ、シリンダ番号によって記述している。<tt>fdisk</tt> でフォーマットされ
た、DOS フォーマットのディスクの場合、4 つのプライマリディスクパーティション
が存在するが、4 つ全部のエントリがパーティションテーブルで使用される必要はな
い。<tt>fdisk</tt> によってサポートされているパーティションタイプには、
プライマリ、拡張(extended)、論理(logical)の 3 種類がある。拡張パーティション
は実際のパーティションではなく、それらは任意の数の論理パーティションを含む。
拡張パーティションと論理パーティションとは、4 つのプライマリパーティションと
いう限界を回避するために発明された。次に示すのは、ふたつのプライマリ
パーティションを含むディスクに対する <tt>fdisk</tt> の出力である。

<verb>
Disk /dev/sda: 64 heads, 32 sectors, 510 cylinders
Units = cylinders of 2048 * 512 bytes

   Device Boot   Begin    Start      End   Blocks   Id  System
/dev/sda1            1        1      478   489456   83  Linux native
/dev/sda2          479      479      510    32768   82  Linux swap

Expert command (m for help): p

Disk /dev/sda: 64 heads, 32 sectors, 510 cylinders

Nr AF  Hd Sec  Cyl  Hd Sec  Cyl   Start    Size ID
 1 00   1   1    0  63  32  477      32  978912 83
 2 00   0   1  478  63  32  509  978944   65536 82
 3 00   0   0    0   0   0    0       0       0 00
 4 00   0   0    0   0   0    0       0       0 00
</verb>

<!--
This shows that the first partition starts at cylinder or track 0, head 1 and
sector 1 and extends to include cylinder 477, sector 32 and head 63. As there
are 32 sectors in a track and 64 read/write heads, this partition is a whole
number of cylinders in size. fdisk alligns partitions on cylinder boundaries by
default. It starts at the outermost cylinder (0) and extends inwards, towards
the spindle, for 478 cylinders. The second partition, the swap partition, 
starts at the next cylinder (478) and extends to the innermost cylinder of the
disk. 
-->
<p>上記では、第一パーティションは、シリンダもしくはトラック 0 、ヘッド 1 、
そしてセクタ 1 から始まり、シリンダ 477 、セクタ 32 、そしてヘッド 63 まで
の領域になっている。トラックあたり 32 セクタで、 64 ヘッドあるので、この
パーティションは、シリンダ数に合致した容量を持つ。<tt>fdisk</tt> は、
デフォルトでシリンダの境界線上で区切って、パーティションを割り当てる。
<tt>fdisk</tt>は、最外周のシリンダ(0)から出発して、内側方向に広げていき、
回転軸に向かって 478 シリンダから構成される領域を割り当てている。
第二パーティションはスワップパーティションであり、次のシリンダ(478)から
スタートしてディスクの最内周のシリンダに及んでいる。

<label id="figure8-3">
<!--                  Figure 8.3: Linked list of disks-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure8-3.gif">
</figure>
</#if>
<#unless output="html">
<verb>
gendisk_head    gendisk             gendisk
            +-----------+        +-----------+
----------->| major     |8    +->| major     |3
            |-----------|     |  |-----------|
            |major_name |"sd" |  |major_name |"ide0"
            |-----------|     |  |-----------|
            |minor_shift|     |  |minor_shift|
            |-----------|     |  |-----------|
            | max_p     |     |  | max_p     |
            |-----------|     |  |-----------|
            | max_nr    |     |  | max_nr    |
            |-----------|     |  |-----------|
            | init()    |     |  | init()    |   hd_struct[]
            |-----------|     |  |-----------|   +----------+  *
            | part      |     |  | part      |-->|start_sect| /|
            |-----------|     |  |-----------|   | nr_sects |  |
            | sizes     |     |  | sizes     |   |----------|  |
            |-----------|     |  |-----------|   |          |  |
            | nr_real   |     |  | nr_real   |   |  :       |  |
            |-----------|     |  |-----------|   |          |
            |real_device|     |  |real_device|   |  :       | max_p
            |-----------|     |  |-----------|   |          |
            | next      |-----+  | next      |   |  :       |  |
            +-----------+        +-----------+   |          |  |
                                                 |----------|  |
                                                 |start_sect|  |
                                                 | nr_sects |  |/
                                                 +----------+  *
</verb>
</#if>
<p>図表(8.3) ディスクの連結リスト


<!--
During initialization Linux maps the topology of the hard disks in the system.
It finds out how many hard disks there are and of what type. Additionally,
Linux discovers how the individual disks have been partitioned. This is all
represented by a list of gendisk data structures pointed at by the
gendisk_head list pointer. As each disk subsystem, for example IDE, is
initialized it generates gendisk data structures representing the disks that it
finds. It does this at the same time as it registers its file operations and 
adds its entry into the blk_dev data structure. Each gendisk data structure has
a unique major device number and these match the major numbers of the block
special devices. For example, the SCSI disk subsystem creates a single
gendisk entry (``sd'') with a major number of 8, the major number of all
SCSI disk devices. Figure  8.3 shows two gendisk entries, the first one for
the SCSI disk subsystem and the second for an IDE disk controller. This is
ide0, the primary IDE controller. 
-->
<p>初期化の過程で Linux はシステム上のハードディスクのトポロジーをマップする。
まず、ハードディスクの数と、そのタイプを調べる。さらに、Linux は個別のディスク
がどのようにパーティション分割されているかを発見する。これらはすべて、<tt>
<ref id="gendisk" name="gendisk"></tt> データ構造体のリストによって表現され、
それが <tt><ref id="gendisk" name="gendisk_head"></tt> リストポインタによって
ポイントされる。
個々のディスクサブシステム、たとえば IDE ディスクサブシステムは、初期化される
際、<tt>gendisk</tt> データ構造体を生成して、検出したディスクを記述する。それ
と同時に、ディスクサブシステムは、そのファイル操作ルーチンを登録し、そのエント
リを <tt><ref id="blk_dev_struct" name="blk_dev"></tt> データ構造に付け加える。
個々の <tt>gendisk</tt> データ構造体は、ユニークなデバイスメジャー番号を持ち、
その番号は、ブロックスペシャルデバイスのメジャー番号と一致する。
たとえば、SCSI ディスクサブシステムは、単一の <tt>gendisk</tt> エントリ("<tt>sd
</tt>")を作成し、それに SCSI ディスクデバイス全体のメジャー番号である、メジャー
番号 8 を付ける。図表(8.3)では、ふたつの <tt>gendisk</tt> エントリがあり、最初
はすべての SCSI サブシステムのものであり、ふたつめが IDE ディスクコントローラの
ものとなっている。後者は、プライマリ IDE コントローラである <tt>ide0</tt> であ
る。

<!--
Although the disk subsystems build the gendisk entries during their
initialization they are only used by Linux during partition checking. Instead,
each disk subsystem maintains its own data structures which allow it to map
device special major and minor device numbers to partitions within physical
disks. Whenever a block device is read from or written to, either via the 
buffer cache or file operations, the kernel directs the operation to the 
appropriate device using the major device number found in its block special 
device file (for example /dev/sda2). It is the individual device driver or 
subsystem that maps the minor device number to the real physical device. 
-->
<p>ディスクサブシステムは初期化の過程で <tt><ref id="gendisk" name="gendisk">
</tt> エントリを作成するが、それらは Linux によってパーティションチェックの際に
使用されるだけである。
それとは別に、個々のディスクサブシステムは、それぞれ独自のデータ構造体を管理
することで、デバイスのメジャー番号とマイナー番号を物理ディスク内のパーティショ
ンにマップしている。ブロックデバイスがバッファキャッシュやファイル操作ルーチン
経由で読み書きされるときはいつも、カーネルは、ブロックスペシャルデバイスファイ
ル(たとえば <tt>/dev/sda2</tt>)に書かれたメジャー番号を使って、その操作を
適切なデバイスへと導く。そして、デバイスのマイナー番号を実(real)物理デバイスに
マップしているのが、個別のデバイスドライバやデバイスサブシステムである。

<!--8.5.1  IDE Disks-->
<sect2>IDE ディスク<label id="chapter_dd_sect5-1">

<!--
The most common disks used in Linux systems today are Integrated Disk
Electronic or IDE disks. IDE is a disk interface rather than an I/O bus like
SCSI. Each IDE controller can support up to two disks, one the master disk
and the other the slave disk. The master and slave functions are usually set by
jumpers on the disk. The first IDE controller in the system is known as the
primary IDE controller, the next the secondary controller and so on. IDE can
manage about 3.3 Mbytes per second of data transfer to or from the disk and
the maximum IDE disk size is 538Mbytes. Extended IDE, or EIDE, has raised
the disk size to a maximum of 8.6 Gbytes and the data transfer rate up to 16.6
Mbytes per second. IDE and EIDE disks are cheaper than SCSI disks and
most modern PCs contain one or more on board IDE controllers. 
-->
<p>今日 Linux システム上で利用される最も一般的なディスクは、IDE (Integrated 
Disk Electronics)ディスクである。IDE とは、SCSI のような I/O というよりも、
むしろディスクインターフェイスである。
個々の IDE コントローラはふたつまでのディスクをサポートできる。一方がマスターデ
ィスク(master disk)であり、他方がスレイブディスク(slave disk)である。
マスターとスレイブの機能は通常、ディスクのジャンパピンで設定される。システム上
の最初の IDE コントローラはプライマリコントローラと呼ばれ、次のコントローラは
セカンダリコントローラ等と呼ばれる。IDE はディスクとの間で毎秒 3.3 M バイトの
データ転送能力を持っており、IDE の最大ディスクサイズは 528 M バイトである。
拡張 IDE 、もしくは EIDE(Extended IDE) は、最大ディスクサイズを 8.4 G バイトに
拡大し、データ転送能力も毎秒 16.6 M バイトに上げたものである。IDE と EIDE 
ディスクは SCSI ディスクよりも安価であるので、現在の PC にはひとつ以上の
オンボード IDE コントローラが含まれている。

<!--
Linux names IDE disks in the order in which it finds their controllers. The
master disk on the primary controller is /dev/hda and the slave disk is
/dev/hdb. /dev/hdc is the master disk on the secondary IDE controller.
The IDE subsystem registers IDE controllers and not disks with the Linux
kernel. The major identifier for the primary IDE controller is 3 and is 22 for
the secondary IDE controller. This means that if a system has two IDE
controllers there will be entries for the IDE subsystem at indices at 3 and 22
in the blk_dev and blkdevs vectors. The block special files for IDE disks
reflect this numbering, disks /dev/hda and /dev/hdb, both connected to
the primary IDE controller, have a major identifier of 3. Any file or buffer
cache operations for the IDE subsystem operations on these block special
files will be directed to the IDE subsystem as the kernel uses the major
identifier as an index. When the request is made, it is up to the IDE
subsystem to work out which IDE disk the request is for. To do this the IDE
subsystem uses the minor device number from the device special identifier,
this contains information that allows it to direct the request to the correct
partition of the correct disk. The device identifier for /dev/hdb, the slave
IDE drive on the primary IDE controller is (3,64). The device identifier for 
the first partition of that disk (/dev/hdb1) is (3,65). 
-->
<p>Linux はコントローラを見つけた順番に IDE ディスクに名前を付ける。プライマリ
コントローラのマスターディスクは <tt>/dev/hda</tt> であり、スレイブディスクは
 <tt>/dev/hdb</tt> である。<tt>/dev/hdc</tt> はセカンダリ IDE コントローラの
マスターディスクとなる。IDE サブシステムは Linux カーネルに IDE コントローラ
を登録し、ディスクを登録しない。プライマリ IDE コントローラのメジャー番号は、
3 であり、セカンダリ IDE コントローラのメジャー番号は 22 である。これは、システ
ムにふたつの IDE コントローラがある場合、<tt><ref id="blk_dev_struct" 
name="blk_devs"></tt> と <tt><ref id="device_struct" name="blkdevs"></tt> 
配列には 3 と 22 のインデックスがついた IDE サブシステムのエントリが
存在することを意味する。IDE ディスクのブロックスペシャルファイルはこの番号の
割り当てを反映しているので、プライマリ IDE コントローラに接続されたディスクで
ある <tt>/dev/hda</tt> と <tt>/dev/hdb</tt> は、どちらもメジャー番号 3 を持つ。
カーネルはメジャー番号をインデックスとして使用しているため、それらのブロック
スペシャルファイル上の IDE サブシステム操作ルーチンを使ったファイル操作や
バッファキャッシュ操作は、まず、IDE サブシステムへと導かれる。
そうしたリクエストが為されたとき、リクエストがどの IDE ディスクに対するもの
なのかを判別するのは、IDE サブシステムの役目である。
そのために、IDE サブシステムは、デバイスの特別な識別子としてマイナー
番号を使用する。その識別子には、リクエストを正しいディスクの正しい
パーティションに送るための情報が含まれている。プライマリ IDE コントローラ上
のスレイブ IDE ディスクである <tt>/dev/hdb</tt> のデバイス識別子は、<ref 
id="major_number" name="(3,64)">(メジャー番号 3 、マイナー番号 64)である。
そのディスクの最初のパーティション(<tt>/dev/hdb1</tt>)のデバイス識別子は、
(3,65) である。

<!--8.5.2  Initializing the IDE Subsystem-->
<sect2>IDE サブシステムの初期化<label id="chapter_dd_sect5-2">

<!--
IDE disks have been around for much of the IBM PC's history. Throughout
this time the interface to these devices has changed. This makes the
initialization of the IDE subsystem more complex than it might at first 
appear. 
-->
<p>IDE ディスクは、IBM PC の歴史と深く関わっている。それらの時代を通じて
IDE デバイスに対するインターフェイスは何度も変更された。それによって、
IDE サブシステムの初期化は、それが登場した当初よりも複雑なものになっている。

<!--
The maximum number of IDE controllers that Linux can support is 4. Each
controller is represented by an ide_hwif_t data structure in the
ide_hwifs vector. Each ide_hwif_t data structure contains two
ide_drive_t data structures, one per possible supported master and slave
IDE drive. During the initializing of the IDE subsystem, Linux first looks to
see if there is information about the disks present in the system's CMOS
memory. This is battery backed memory that does not lose its contents when
the PC is powered off. This CMOS memory is actually in the system's real
time clock device which always runs no matter if your PC is on or off. The
CMOS memory locations are set up by the system's BIOS and tell Linux what
IDE controllers and drives have been found. Linux retrieves the found disk's
geometry from BIOS and uses the information to set up the ide_hwif_t data
structure for this drive. More modern PCs use PCI chipsets such as Intel's
82430 VX chipset which includes a PCI EIDE controller. The IDE subsystem
uses PCI BIOS callbacks to locate the PCI (E)IDE controllers in the system.
It then calls PCI specific interrogation routines for those chipsets that are
present. 
-->
<p>Linux がサポートできる IDE コントローラの最大数は 4 つである。個々の
コントローラは、<tt><ref id="ide_hwif_t" name="ide_hwifs"></tt> 配列にある 
<tt><ref id="ide_hwif_t" name="ide_hwif_t"></tt> データ構造体によって表される。
個々の <tt>ide_hwif_t</tt> データ構造体はふたつの <tt><ref id="ide_drive_t" 
name="ide_drive_t"></tt> 構造体を含んでおり、各々がマスターとスレイブの IDE 
ドライブのサポートに備えたものとなっている。IDE サブシステムの初期化の過程で、
Linux はまず、システムの CMOS メモリにディスクに関する情報があるかどうかを
確認する。これは、PC の電源が切られたときもバッテリ駆動のバックアップメモリに
よってその内容が失われないようになっている。この CMOS メモリは実際にはシステム
のリアルタイムクロックの中にあり、そのクロックは PC の電源が入っているかどうか
に関わらず、実行されている。その CMOS メモリの場所は BIOS を使って設定が可能
であり、それが Linux に対してどのような IDE コントローラやドライブが検出され
たかを告げる。Linux は検出されたディスクのジオメトリを BIOS から取ってきて、
その情報を利用して当該デバイスの <tt>ide_hwif_t</tt> データ構造体を設定する。
より現代的な PC では、PCI (E)IDE コントローラに含まれる Intel の 82430 VX 
のような PCI チップセットを使用する。そして、システム上にあるそうしたチップ
セット用の PCI 固有の検出ルーチンをコールする。

<!--
Once each IDE interface or controller has been discovered, its ide_hwif_t
is set up to reflect the controllers and attached disks. During operation the
IDE driver writes commands to IDE command registers that exist in the I/O
memory space. The default I/O address for the primary IDE controller's
control and status registers is 0x1F0 - 0x1F7. These addresses were set by
convention in the early days of the IBM PC. The IDE driver registers each
controller with the Linux block buffer cache and VFS, adding it to the
blk_dev and blkdevs vectors respectively. The IDE drive will also request
control of the appropriate interrupt. Again these interrupts are set by
convention to be 14 for the primary IDE controller and 15 for the secondary
IDE controller. However, they like all IDE details, can be overridden by
command line options to the kernel. The IDE driver also adds a gendisk
entry into the list of gendisk's discovered during boot for each IDE
controller found. This list will later be used to discover the partition 
tables of all of the hard disks found at boot time. The partition checking code
understands that IDE controllers may each control two IDE disks. 
-->
<p>個々の IDE インターフェイスやコントローラが発見されたら、その <tt><ref 
id="ide_hwif_t" name="ide_hvif_t"></tt> 構造体が、そのコントローラやそれに接続
されたディスクの状態を反映するために設定される。
設定の過程で、IDE ドライバは、I/O メモリ空間に存在する IDE コマンドレジスタに
コマンドを書き込む。プライマリ IDE コントローラ上のコントロールレジスタと
ステータスレジスタのデフォルトの I/O アドレスは、0x1F0 から 0x1F7 である。
これらのアドレスの設定は、初期の IBM PC の慣習によって決まっている。
IDE ドライバは、個々のコントローラを Linux のブロック
バッファキャッシュと VFS に登録し、それを <tt><ref id="blk_dev_struct" 
name="blk_dev"></tt> と <tt><ref id="device_struct" name="blkdevs"></tt> 
配列にそれぞれ付け加える。IDE ドライブは適切な割り込み制御も要求する。
ここでもまた、その割り込み番号は慣習的に決まっており、プライマリ IDE コント
ローラが 14 で、セカンダリコントローラが 15 である。しかし、それらは、他の
すべての IDE の詳細と同様に、カーネルへのコマンドラインオプションによって
上書き変更が可能である。また IDE ドライバは、起動中に発見された個々の IDE 
コントローラについて、<tt><ref id="gendisk" name="gendisk"></tt> のリストに 
<tt>gendisk</tt> のエントリを付け加える。このリストは後で、起動時に見つかったす
べてのハードディスクのパーティションテーブルを発見するために使用される。

<!--8.5.3  SCSI Disks-->
<sect2>SCSI ディスク<label id="chapter_dd_sect5-3">

<!--
The SCSI (Small Computer System Interface) bus is an efficient peer-to-peer
data bus that supports up to eight devices per bus, including one or more
hosts. Each device has to have a unique identifier and this is usually set by
jumpers on the disks. Data can be transfered synchronously or
asynchronously between any two devices on the bus and with 32 bit wide data
transfers up to 40 Mbytes per second are possible. The SCSI bus transfers
both data and state information between devices, and a single transaction
between an initiator and a target can involve up to eight distinct phases. You
can tell the current phase of a SCSI bus from five signals from the bus. The
eight phases are: 
-->
<p>SCSI (Small Computer System Interface)バスは、効率的な一対一(peer-to-peer)
のデータバスであり、ひとつ以上のホストを含む 8 個のデバイスをひとつのバスで
サポートする。個々のデバイスは固有の識別子を持つ必要があり、通常それはディスク
上のジャンパピンで設定される。バス上にある任意のふたつのデバイス間で
同期あるいは非同期のデータ転送が可能であり、32 ビット幅のデータ転送により最大
毎秒 40 M バイトの転送速度が得られる。SCSI バスは、デバイス間でデータとステート
(状態)の情報の両方を転送する。イニシエータ(initiater)とターゲット(target)間の
一回の転送中に最大 8 つの異なるフェイズ(phase)を取ることがある。現在の SCSI 
バスのフェイズは 5 本の制御線から、確認できる。8 つのフェイズとは次のような
ものである。

<!--
BUS FREE
      No device has control of the bus and there are no transactions
      currently happening, 
-->
<descrip>
<tag>BUS FREE</tag>
バスを制御しているデバイスは存在せず、トランザクションは現在行われていない。

<!--
ARBITRATION
      A SCSI device has attempted to get control of the SCSI bus, it does
      this by asserting its SCSI identifer onto the address pins. The highest
      number SCSI identifier wins. 
-->
<tag>ARBITRATION</tag>
SCSI デバイスが SCSI バスを制御しようとしていて、SCSI 識別子に対応した
ピンを有効にしている。SCSI 識別子の最高値が優先される。

<!--
SELECTION
      When a device has succeeded in getting control of the SCSI bus
      through arbitration it must now signal the target of this SCSI request
      that it wants to send a command to it. It does this by asserting the
      SCSI identifier of the target on the address pins. 
-->
<tag>SELECTION</tag>
ARBITRATION を通じてデバイスが SCSI バスの制御に成功したとき、そのデバイスは 
SCSI のターゲットに対して、コマンドを送る旨のリクエストを SCSI バスの制御線で
伝えなければならない。それをするために、ターゲットの SCSI 識別子に対応した
ピンを有効にする。

<!--
RESELECTION
      SCSI devices may disconnect during the processing of a request. The
      target may then reselect the initiator. Not all SCSI devices support
      this phase. 
-->
<tag>RESELECTION</tag>
SCSI デバイスは、リクエスト処理中に接続を中止するかもしれない。その場合、
ターゲットは、イニシエータに再接続できる。すべての SCSI デバイスがこのフェーズ
をサポートしているわけではない。

<!--
COMMAND
      6,10 or 12 bytes of command can be transfered from the initiator to the
      target, 
-->
<tag>COMMAND</tag>
6,10, もしくは 12 バイトの命令を、イニシエータからターゲットに送ることが
できる。

<!--
DATA IN, DATA OUT
      During these phases data is transfered between the initiator and the
      target, 
-->
<tag>DATA IN, DATA OUT</tag>
これらのフェーズにおいて、データはイニシエータとターゲット間で転送される。

<!--
STATUS
      This phase is entered after completion of all commands and allows the
      target to send a status byte indicating success or failure to the
      initiator, 
-->
<tag>STATUS</tag>
このフェーズに入るのは、コマンドがすべて実行され、ターゲットがイニシエータに
対して成功か失敗を示すステータスバイトを送ることができる場合である。

<!--
MESSAGE IN, MESSAGE OUT
      Additional information is transfered between the initiator and the
      target. 
-->
<tag>MESSAGE IN, MESSAGE OUT</tag>
イニシエータとターゲット間での追加情報の転送。

</descrip>

<!--
The Linux SCSI subsystem is made up of two basic elements, each of which
is represented by data structures: 
-->
<p>Linux SCSI サブシステムは、ふたつの基本要素から成り、それぞれがデータ構造体
によって表される。

<!--
host A SCSI host is a physical piece of hardware, a SCSI controller. The
      NCR810 PCI SCSI controller is an example of a SCSI host. If a Linux
      system has more than one SCSI controller of the same type, each
      instance will be represented by a separate SCSI host. This means that
      a SCSI device driver may control more than one instance of its
      controller. SCSI hosts are almost always the initiator of SCSI
      commands. 
-->
<descrip>
<tag>host</tag>
SCSI ホスト(host)とは物理的なハードウェアである SCSI コントローラを指す。
NCR810 PCI SCSI コントローラは SCSI ホストの典型である。Linux システムが
同種の SCSI コントローラを複数持つ場合、個々のコントローラは、個別の SCSI 
ホストとして表現される。これは、SCSI デバイスドライバは同種のコントローラを
複数制御できることを意味する。SCSI ホストは、ほとんどいつも SCSI コマンドの
イニシエータである。

<!--
Device The most common set of SCSI device is a SCSI disk but the SCSI
      standard supports several more types; tape, CD-ROM and also a
      generic SCSI device. SCSI devices are almost always the targets of
      SCSI commands. These devices must be treated differently, for
      example with removable media such as CD-ROMs or tapes, Linux
      needs to detect if the media was removed. The different disk types
      have different major device numbers, allowing Linux to direct block
      device requests to the appropriate SCSI type. 
-->
<tag>Device</tag>
SCSI デバイスの中で最も一般的なのが SCSI ディスクであるが、SCSI 規格はもっと
多種類のデバイスをサポートしている。テープ、CD-ROM それに汎用 SCSI デバイス
などである。SCSI デバイスはほとんどいつも SCSI コマンドのターゲットである。
それらのデバイスは異なった取り扱いが必要であり、たとえば CD-ROM やテープなどの
リムーバルメディアの場合、Linux はそのメディアが取り出されたかどうか確認できな
ければならない。
異なるディスクタイプには異なるメジャー番号が与えられ、それによって Linux は
ブロックデバイスへのリクエストを適切な SCSI タイプに伝達することができる。
</descrip>

<!--Initializing the SCSI Subsystem-->
<sect2>SCSI サブシステムの初期化<label id="chapter_dd_sect5-4">

<!--
Initializing the SCSI subsystem is quite complex, reflecting the dynamic
nature of SCSI buses and their devices. Linux initializes the SCSI subsystem
at boot time; it finds the SCSI controllers (known as SCSI hosts) in the
system and then probes each of their SCSI buses finding all of their devices. 
It then initializes those devices and makes them available to the rest of the
Linux kernel via the normal file and buffer cache block device operations. This
initialization is done in four phases: 
-->
<p>SCSI サブシステムの初期化は、SCSI バスやデバイスの動的な性質を反映して、
非常に複雑なものになっている。Linux は SCSI サブシステムをブート時に初期化
する。システム上の SCSI コントローラ(SCSI ホストと呼ばれる)を検出し、
コントローラごとの SCSI バスを検査して、バス上のデバイスをすべて検出する。
その上で、それらのデバイスを初期化して、Linux カーネルの残りの部分が、
通常ファイルの操作ルーチンやバッファキャッシュブロックデバイスの操作ルーチンを
経由して、デバイスを利用することが出来るようにする。
この初期化には 4 つのフェイズがある。

<!--
First, Linux finds out which of the SCSI host adapters, or controllers, that
were built into the kernel at kernel build time have hardware to control. Each
built in SCSI host has a Scsi_Host_Template entry in the
builtin_scsi_hosts vector. The Scsi_Host_Template data structure
contains pointers to routines that carry out SCSI host specific actions such as
detecting what SCSI devices are attached to this SCSI host. These routines
are called by the SCSI subsystem as it configures itself and they are part of
the SCSI device driver supporting this host type. Each detected SCSI host,
those for which there are real SCSI devices attached, has its
Scsi_Host_Template data structure added to the scsi_hosts list of
active SCSI hosts. Each instance of a detected host type is represented by a
Scsi_Host data structure held in the scsi_hostlist list. For example a
system with two NCR810 PCI SCSI controllers would have two Scsi_Host
entries in the list, one per controller. Each Scsi_Host points at the
Scsi_Host_Template representing its device driver. 
-->
<p>まず Linux は、カーネル構築時にカーネルに組み込まれた SCSI ホストアダプタ
もしくはコントローラのうち、制御すべきハードウェアを持つのはどれなのかを見
つけだす。
カーネルに組み込まれた個々のホストは、<tt><ref id="Scsi_Host_Template" 
name="builtin_scsi_host"></tt> 配列内に <tt><ref id="Scsi_Host_Template" 
name="Scsi_Host_Template"></tt> エントリを持つ。
<tt>Scsi_Host_Template</tt> データ構造体にはルーチンへのポインタが含まれてい
て、それによって SCSI ホストに接続された SCSI デバイスの検出といったその SCSI 
ホスト固有の処理が実行される。
それらのルーチンは、SCSI サブシステムによっても呼び出されて、その設定を行ったり
もする。それらは、そのホストタイプをサポートする SCSI デバイスドライバの一部で
ある。
検出された個々の SCSI ホストのうち、実際に SCSI デバイスが接続されていたもの
は、自分の <tt>Scsi_Host_Template</tt> データ構造体を、アクティブな SCSI ホスト
のリストである <tt><ref id="Scsi_Host_Template" name="scsi_hosts"></tt> リスト
に付け加える。
検出されたホストタイプの個々の SCSI コントローラは、<tt><ref id="Scsi_Host" 
name="scsi_hostlist"></tt> リスト内にある <tt><ref id="Scsi_Host" 
name="Scsi_Host"></tt> データ構造体によって表現される。たとえば、NCR810 PCI 
SCSI コントローラを持つシステムは、リスト内に、コントローラごとにひとつ、合計
ふたつの <tt>Scsi_Host</tt> エントリを持つ。個々の <tt>Scsi_Host</tt> 構造体
は、そのデバイスドライバを表している <tt>Scsi_Host_Template</tt> をポイントして
いる。


<!--Figure 8.4: SCSI Data Structures-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure8-4.gif">
</figure>
</#if>
<#unless output="html">
<verb>

                                  Scsi_Host_Template
scsi_hosts                         +--------------+
---------------------------------->| next         |
                                   |--------------|
                        +--------->| name         |
                        |          |--------------|
                        |          |              |
                        |          | Device       |
                        |          | Driver       |
                        |          | Routines     |
                        |          |              |
                        |          +--------------+
                        +--------------------------------+
                                                         |
scsi_hostlist                         Scsi_Host          |
----------------------------------->+-------------+      |
                        +---------->| next        |      |
                        |           |-------------|      |
                        |           |             |      |
                        |           |-------------|      |
                        |           | this_id     |      |
                        |           |-------------|      |
                        |           | max_id      |      |
                        |           |-------------|      |
                        |           |             |      |
                        |           |-------------|      |
                        |           | host        |<-----+
                        |           |-------------|
                        |           |             |
                        |           +-------------+
                        +--------------------------------+
                                                         |
                 Scsi_Device            Scsi_Device      |
scsi_device    +-------------+        +-------------+    |
-------------->| next        |------->| next        |    |
               |-------------|        |-------------|    |
               |             |        |             |    |
               |-------------|        |-------------|    |
               | id          |        | id          |    |
               |-------------|        |-------------|    |
               | type        |        | type        |    |
               |-------------|        |-------------|    |
               |             |        |             |    |
               |-------------|        |-------------|    |
               | host        |        | host        |<---+
               |-------------|        |-------------|
               |             |        |             |
               |             |        |             |
               +-------------+        +-------------+
</verb>
</#if>
<p>図表(8.4) SCSI データ構造


<!-- 
Now that every SCSI host has been discovered, the SCSI subsystem must
find out what SCSI devices are attached to each host's bus. SCSI devices are
numbered between 0 and 7 inclusively, each device's number or SCSI
identifier being unique on the SCSI bus to which it is attached. SCSI
identifiers are usually set by jumpers on the device. The SCSI initialization
code finds each SCSI device on a SCSI bus by sending it a
TEST_UNIT_READY command. When a device responds, its identification is
read by sending it an ENQUIRY command. This gives Linux the vendor's
name and the device's model and revision names. SCSI commands are
represented by a Scsi_Cmnd data structure and these are passed to the
device driver for this SCSI host by calling the device driver routines within 
its Scsi_Host_Template data structure. Every SCSI device that is found is
represented by a Scsi_Device data structure, each of which points to its
parent Scsi_Host. All of the Scsi_Device data structures are added to the
scsi_devices list. Figure  8.4 shows how the main data structures relate to
one another. 
-->
<p>SCSI ホストがすべて見つかったら、次に SCSI サブシステムは、個々の SCSI ホス
トにどういった SCSI デバイスが繋がれているのか見つけ出さなければならない。SCSI 
デバイスには 0 から 7 までの番号が振られ、個々のデバイス番号もしくは SCSI 
識別子はそれが繋がれた SCSI バス上においてユニークでなければならない。
通常、SCSI 識別子はデバイス上のジャンパピンで設定される。SCSI 初期化コードは、
SCSI バス上の個々の SCSI デバイスを検出するとき、それらに TEST_UNIT_READY コマ
ンドを送信する。デバイスが応答すると、ENQUIRY コマンドが送信されて、そのデバイ
スの識別子が読み出される。これによって Linux は、そのベンダ名、デバイスモデル、
リビジョン名を取得する。
SCSI コマンドは <tt><ref id="Scsi_Cmnd" name="Scsi_Cmnd"></tt> 
データ構造体によって表現され、それらがこの SCSI ホストに対するデバイスドライバ
に渡されるときは、その <tt><ref id="Scsi_Host_Template" 
name="Scsi_Host_Template"></tt> データ構造体内にあるデバイスドライバルーチンが
呼び出される。発見されたすべての SCSI デバイスは <tt><ref 
id="Scsi_Device" name="Scsi_Device"></tt> データ構造体によって表現され、その
個々の構造体がその親である <tt><ref id="Scsi_Host" name="Scsi_Host"></tt> を
ポイントしている。すべての <tt>Scsi_Device</tt> データ構造体は <tt><ref 
id="Scsi_Device" name="scsi_devices"></tt> リストに付け加えられる。図表(8.4)
では、主要なデータ構造体がどのような相互関係にあるのかが示されている。

<!--
There are four SCSI device types: disk, tape, CD and generic. Each of these
SCSI types are individually registered with the kernel as different major block
device types. However they will only register themselves if one or more of a
given SCSI device type has been found. Each SCSI type, for example SCSI
disk, maintains its own tables of devices. It uses these tables to direct 
kernel block operations (file or buffer cache) to the correct device driver or
SCSI host. Each SCSI type is represented by a Scsi_Device_Template data
structure. This contains information about this type of SCSI device and the
addresses of routines to perform various tasks. The SCSI subsystem uses
these templates to call the SCSI type routines for each type of SCSI device. In
other words, if the SCSI subsystem wishes to attach a SCSI disk device it will
call the SCSI disk type attach routine. The Scsi_Type_Template data
structures are added to the scsi_devicelist list if one or more SCSI
devices of that type have been detected. 
-->
<p>SCSI デバイスには、ディスク、テープ、CD 、汎用の 4 種類のタイプがある。
それらの SCSI タイプの各々が異なるメジャーブロックデバイスタイプとしてカーネル
に独立して登録される。しかし、それらは、その種の SCSI デバイスタイプがひとつ以
上見つかった場合のみ登録がなされる。SCSI ディスクのような個々の SCSI タイプは
独自のデバイステーブルを管理している。そしてそれらのテーブルを利用してカーネル
の(ファイルやバッファキャッシュに対する)ブロック操作ルーチンを正しいデバイス
ドライバや SCSI ホストに導く。
個々の SCSI タイプは <tt><ref id="Scsi_Device_Template" 
name="Scsi_Device_Template"></tt> データ構造体によって表現される。これには、
その SCSI デバイスのタイプと様々なタスクを実行するルーチンのアドレスに関する
情報が含まれる。SCSI サブシステムはそれらのテンプレートを使用して個々の SCSI 
タイプのデバイスに対する SCSI タイプルーチンを呼び出す。言い換えると、もし 
SCSI サブシステムが SCSI ディスクデバイスを追加したい場合、その SCSI ディスク
タイプの追加用ルーチンが呼び出される。ひとつ以上のそのタイプの SCSI デバ
イスが見つかった場合、<tt>Scsi_Type_Template</tt> データ構造体(訳注: <tt><ref 
id="Scsi_Device_Template" name="Scsi_Device_Template"></tt>か？)が <tt>
<ref id="Scsi_Device_Template" name="scsi_devicelist"></tt> リストに付け加え
られる。

<!--
The final phase of the SCSI subsystem initialization is to call the finish
functions for each registered Scsi_Device_Template. For the SCSI disk
type this spins up all of the SCSI disks that were found and then records their
disk geometry. It also adds the gendisk data structure representing all SCSI
disks to the linked list of disks shown in Figure  8.3. 
-->
<p>SCSI サブシステムの初期化における最後のフェーズは、登録された <tt>
<ref id="Scsi_Device_Template" name="Scsi_Device_Template"></tt> の個々に対する
終了用関数を呼び出すことである。SCSI ディスクタイプごとに、その関数が、検出され
た SCSI ディスクすべてをまとめて、それらのディスクジオメトリを記録する。また、
それは、すべての SCSI ディスクを表現している <tt><ref id="gendisk" 
name="gendisk"></tt> データ構造体を<ref id="figure8-3" name="図表(8.3)">で示し
たディスクの連結リストに付け加える。

<!--Delivering Block Device Requests-->
<sect2>ブロックデバイスのリクエストを伝達する<label id="chapter_dd_sect5-5">

<!--
Once Linux has initialized the SCSI subsystem, the SCSI devices may be
used. Each active SCSI device type registers itself with the kernel so that
Linux can direct block device requests to it. There can be buffer cache
requests via blk_dev or file operations via blkdevs. Taking a SCSI disk
driver that has one or more EXT2 filesystem partitions as an example, how do
kernel buffer requests get directed to the right SCSI disk when one of its
EXT2 partitions is mounted? 
-->
<p>Linux が SCSI サブシステムの初期化を完了すると、SCSI デバイスが利用可能に
なる。個々のアクティブな SCSI デバイスのタイプは、Linux がブロックデバイス
リクエストをそれに導けるように、カーネルに登録される。そうしたリクエストには
 <tt><ref id="blk_dev_struct" name="blk_dev"></tt> を経由したバッファキャッシュ
リクエストや <tt><ref id="device_struct" name="blkdevs"></tt> を経由したファイ
ル操作リクエストなどがある。
では、ひとつ以上の数の EXT2 ファイルシステムのパーティションを持つ SCSI ディス
クを例に取ると、その EXT2 パーティションがマウントされているとき、カーネルの
バッファリクエストはどのようにして適切な SCSI ディスクに渡されるのだろうか？

<!--
Each request to read or write a block of data to or from a SCSI disk partition
results in a new request structure being added to the SCSI disks
current_request list in the blk_dev vector. If the request list is being
processed, the buffer cache need not do anything else; otherwise it must
nudge the SCSI disk subsystem to go and process its request queue. Each
SCSI disk in the system is represented by a Scsi_Disk data structure.
These are kept in the rscsi_disks vector that is indexed using part of the
SCSI disk partition's minor device number. For exmaple, /dev/sdb1 has a
major number of 8 and a minor number of 17; this generates an index of 1.
Each Scsi_Disk data structure contains a pointer to the Scsi_Device
data structure representing this device. That in turn points at the Scsi_Host
data structure which ``owns'' it. The request data structures from the buffer
cache are translated into Scsi_Cmd structures describing the SCSI command
that needs to be sent to the SCSI device and this is queued onto the
Scsi_Host structure representing this device. These will be processed by
the individual SCSI device driver once the appropriate data blocks have been
read or written. 
-->
<p>SCSI ディスクパーティションに対するデータブロックの読み書きリクエストが
為されると、<tt><ref id="request" name="request"></tt> 構造体が <tt><ref 
id="blk_dev_struct" name="blk_dev"></tt> 配列内にあるその SCSI ディスクの <tt>
<ref id="request" name="current_request"></tt> リストに付け加えられる。
<tt>request</tt> リストが処理されている場合、バッファキャッシュは何もする必要
がないのだが、そうでない場合は、 SCSI サブシステムを促してそのリクエストキュー
を処理させなければならない。システム上の個々の SCSI ディスクは <tt><ref 
id="Scsi_Disk" name="Scsi_Disk"></tt> データ構造体によって表現されている。
その構造体は <tt><ref id="Scsi_Disk" name="rscsi_disks"></tt> 配列に
保存されていて、その配列は SCSI ディスクパーティションのマイナー番号の
一部を使用してインデックス付けされている。たとえば、<tt>/dev/sdb1</tt> は
メジャー番号 8 とマイナー番号 17 を持っているが、これはインデックス 1 を
生成する。個々の <tt>Scsi_Disk</tt> データ構造体には、このデバイスを表現
する <tt><ref id="Scsi_Device" name="Scsi_Device"></tt> データ構造体へのポイン
タが含まれている。その構造体が次に <tt><ref id="Scsi_Host" name="Scsi_Host">
</tt> 構造体をポイントしており、それがそのデバイスの「オーナー」である。
バッファキャッシュからの <tt>request</tt> データ構造体は、SCSI 
デバイスに送信されるべき SCSI コマンドを記述している <tt><ref id="Scsi_Cmnd" 
name="Scsi_Cmnd"></tt> 構造体に変換され、これがそのデバイスを表す <tt>
Scsi_Host</tt> データ構造体上のキューに置かれる。いったん適切なデータブロックが
書き込まれたり読み出されたりすると、そうしたことが個別の SCSI デバイスドライバ
によって処理される。

<!--8.6  Network Devices-->
<sect1>ネットワークデバイス<label id="chapter_dd_sect6">

<!--
A network device is, so far as Linux's network subsystem is concerned, an
entity that sends and receives packets of data. This is normally a physical
device such as an ethernet card. Some network devices though are software
only such as the loopback device which is used for sending data to yourself.
Each network device is represented by a device data structure. Network
device drivers register the devices that they control with Linux during network
initialization at kernel boot time. The device data structure contains
information about the device and the addresses of functions that allow the
various supported network protocols to use the device's services. These
functions are mostly concerned with transmitting data using the network
device. The device uses standard networking support mechanisms to pass
received data up to the appropriate protocol layer. All network data (packets)
transmitted and received are represented by sk_buff data structures, these
are flexible data structures that allow network protocol headers to be easily
added and removed. How the network protocol layers use the network
devices, how they pass data back and forth using sk_buff data structures is
described in detail in the Networks chapter (Chapter  networks-chapter).
This chapter concentrates on the device data structure and on how network
devices are discovered and initialized. 
-->
<p>Linux のネットワークサブシステムに関する限り、ネットワークデバイスとは、
データパケットを送受信する実体のことである。通常これはイーサネットカードなどの
物理デバイスである。しかし、データを自分に送信するために使用されるループバック
デバイス(loopback device)といったソフトウェアのネットワークデバイスもある。
個々のネットワークデバイスは <tt><ref id="device" name="device"></tt> データ
構造体によって表現される。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/netdevice.h" 
name="include/linux/netdevice.h">]<newline>
ネットワークデバイスコントローラは、カーネル起動時のネットワーク初期化過程で、
Linux に制御しようとするデバイスを登録する。<tt>device</tt> データ構造体には、
デバイスに関する情報と、サポートされる多様なプロトコルがデバイスのサービスを
利用する際に使う関数のアドレスとが含まれる。
これらの関数は大部分がネットワークデバイスを使用したデータ転送に関するものであ
る。デバイスは、受信したデータを適切なプロトコル層に渡すために標準的なネット
ワークサポート機能を使用する。送受信されたすべてのデータ(パケット)は、<tt><ref 
id="sk_buff" name="sk_buff"></tt> データ構造体によって表現されるが、それは柔軟
な構造体なので、ネットワークプロトコルのヘッダの簡単な追加や削除を可能にする。
ネットワークプロトコル層がネットワークデバイスを使用する方法、それらが <tt>
sk_buff</tt> データ構造体を使用してデータを受け渡しする方法については、
<ref id="chapter_net" name="「ネットワーク」">の章で詳しく解説する。本章では、
<tt>device</tt> データ構造体とネットワークデバイスが検出され初期化される方法と
に集中する。

<!--
The device data structure contains information about the network device: 
-->
<p><tt><ref id="device" name="device"></tt> データ構造体にはネットワークデバイ
スに関する次のような情報が含まれている。

<!--
Name Unlike block and character devices which have their device special
      files created using the mknod command, network device special files
      appear spontaniously as the system's network devices are discovered
      and initialized. Their names are standard, each name representing the
      type of device that it is. Multiple devices of the same type are
      numbered upwards from 0. Thus the ethernet devices are known as
      /dev/eth0,/dev/eth1,/dev/eth2 and so on. Some common
      network devices are: 

       /dev/ethN 
               Ethernet devices 
       /dev/slN 
               SLIP devices 
       /dev/pppN 
               PPP devices 
       /dev/lo 
               Loopback devices
-->
<descrip>
<tag>名前 (name)</tag>
<tt>mknod</tt> コマンドを使ってデバイススペシャルファイルを作成するブロック
デバイスやキャラクタデバイスとは異なり、ネットワークデバイスのスペシャル
ファイルは、システムのネットワークデバイスが検出され初期化される際に自動的に
出現する。その名前は標準的なもので、個々の名前はそのデバイスのタイプを表して
いる。同タイプのデバイスが複数ある場合は、0 から順に番号付けされる。したがっ
て、複数のイーサネットデバイスは、<tt>/dev/eht0</tt>, <tt>/dev/eth1</tt>, 
<tt>/dev/eth2</tt> 等となる。一般的なネットワークデバイスをいくつか示す。
<verb>
/dev/ethN  イーサネットデバイス

/dev/slN   SLIP デバイス

/dev/pppN  PPP デバイス

/dev/lo    ループバックデバイス
</verb>

<!--
Bus Information
      This is information that the device driver needs in order to control the
      device. The irq number is the interrupt that this device is using. The
      base address is the address of any of the device's control and status
      registers in I/O memory. The DMA channel is the DMA channel
      number that this network device is using. All of this information is set
      at boot time as the device is initialized. 
-->
<tag>バス情報 (bus information)</tag>
これは、デバイスドライバがデバイスを制御するために必要な情報である。<tt><ref 
id="device" name="irq"></tt> 番号はそのデバイスが使用する割り込み番号である。
<tt><ref id="device" name="base_addr"></tt> は I/O メモリ内にあるコントロールレ
ジスタとステータスレジスタのアドレスである。
<tt><ref id="device" name="dma"></tt> はそのネットワークデバイスが使用する DMA 
チャンネルの番号である。これらすべての情報はブート時のデバイスが初期化される際
に設定される。

<!--
Interface Flags
      These describe the characteristics and abilities of the network device:
-->
<tag>インターフェイスフラグ(interface flag)</tag>
これらは、ネットワークデバイスの特徴と能力とを示している。
<!--
       IFF_UP 
                        Interface is up and running, 
       IFF_BROADCAST 
                        Broadcast address in device is valid 
       IFF_DEBUG 
                        Device debugging turned on 
       IFF_LOOPBACK 
                        This is a loopback device 
       IFF_POINTTOPOINT 
                        This is point to point link (SLIP and PPP) 
       IFF_NOTRAILERS 
                        No network trailers 
       IFF_RUNNING 
                        Resources allocated 
       IFF_NOARP 
                        Does not support ARP protocol 
       IFF_PROMISC 
                        Device in promiscuous receive mode, it will
                        receive 
                        all packets no matter who they are
                        addressed to 
       IFF_ALLMULTI 
                        Receive all IP multicast frames 
       IFF_MULTICAST 
                        Can receive IP multicast frames
-->
<verb>
IFF_UP           インターフェイスが起動され実行中である。

IFF_BROADCAST    デバイスのブロードキャストアドレスが有効である。

IFF_DEBUG        デバイスのデバッギングが有効である。

IFF_LOOPBACK     これは、ループバックデバイスである。

IFF_POINTTOPOINT これは、一対一(point to point)のリンクである。(SLIP と PPP)

IFF_NOTRAILER    ネットワークトレイラー(network trailer)なし。(訳注: 用語集)

IFF_RUNNING      リソースが割り当てられた。

IFF_NOARP        ARP プロトコルをサポートしない。

IFF_PROMISC      プロミスク受信モードのデバイスは、パケットの送信先アドレス
                 とは無関係にすべてのパケットを受信する。

IFF_ALLMULTI     IP マルチキャストフレームを受信する。

IFF_MULTICAST    IP マルチキャストフレームの受信が可能。
</verb>

<!--
Protocol Information
      Each device describes how it may be used by the network protocool
      layers: 
      mtu The size of the largest packet that this network can transmit
            not including any link layer headers that it needs to add. This
            maximum is used by the protocol layers, for example IP, to
            select suitable packet sizes to send. 
      Family The family indicates the protocol family that the device can
            support. The family for all Linux network devices is AF_INET,
            the Internet address family. 
      Type The hardware interface type describes the media that this
            network device is attached to. There are many different types
            of media that Linux network devices support. These include
            Ethernet, X.25, Token Ring, Slip, PPP and Apple Localtalk. 
      Addresses
            The device data structure holds a number of addresses that
            are relevent to this network device, including its IP addresses.
-->
<tag>プロトコル情報</tag>
個々のデバイスは、ネットワークプロトコル層によってどのように利用されるのかを
示している。
<descrip>

<tag>最大転送単位 (mtu)</tag>
そのネットワークで送信可能な最大パケットのサイズ。ただし、それに付加される
リンク層のヘッダ部分は含まれない。この最大値は、IP などのプロトコル層が送信
パケットの適正サイズを選択する際に利用される。

<tag>ファミリー (family)</tag>
ファミリーとは、そのデバイスがサポートできるプロトコルファミリーを指す。すべて
の Linux ネットワークデバイスでサポートされるファミリーは、AF_INET、すなわち
インターネットアドレスファミリーである。

<tag>タイプ (type)</tag>
ハードウェアインターフェイスタイプとは、ネットワークデバイスが取り付けられた
メディアを表している。Linux のネットワークデバイスがサポートするメディアの
タイプは多種に渡る。それには、イーサネット、X.25、トークンリング、SLIP、PPP、
アップルローカルトークなどが含まれる。

<tag>アドレス (Address)</tag>
<tt>device</tt> データ構造体は、IP アドレスを含めて、そのネットワークデバイス
に関係するいくつかのアドレスを保持する。
</descrip>

<!--
Packet Queue
      This is the queue of sk_buff packets queued waiting to be
      transmitted on this network device, 
-->
<tag>パケットキュー (Packet Queue)</tag>
これは、ネットワークデバイス上で転送を待っている <tt><ref id="sk_buff" 
name="sk_buff"></tt> パケットのキューである。

<!--
Support Functions
      Each device provides a standard set of routines that protocol layers
      call as part of their interface to this device's link layer. These 
      include setup and frame transmit routines as well as routines to add 
      standard frame headers and collect statistics. These statistics can be 
      seen using the ifconfig command. 
-->
<tag>サポート関数 (Support Functions)</tag>
個々のデバイスは、そのデバイスのリンク層に対するインターフェイスの一部として、
プロトコル層がコールできるルーチンの標準セットを提供する。それには、設定ルーチ
ンやフレーム送信ルーチン以外にも、標準フレームヘッダ付加や統計情報収集のルーチ
ンも含まれる。それらの統計情報は <tt>ifconfig</tt> コマンドを使って見ることが
できる。
</descrip>

<!--8.6.1  Initializing Network Devices-->
<sect2>ネットワークデバイスの初期化<label id="chpter_dd_sect6-1">

<!--
Network device drivers can, like other Linux device drivers, be built into the
Linux kernel. Each potential network device is represented by a device data
structure within the network device list pointed at by dev_base list pointer.
The network layers call one of a number of network device service routines
whose addresses are held in the device data structure if they need device
specific work performing. Initially though, each device data structure holds
only the address of an initialization or probe routine. 
-->
<p>ネットワークデバイスドライバは、他の Linux デバイスドライバ同様、Linux 
カーネルに組み込むことができる。組み込まれた個々のネットワークデバイスは、
<tt><ref id="device" name="device"></tt> データ構造体によって表され、その構造体
は、ポインタのリストである <tt><ref id="dev_base" name="dev_base"></tt> に
よってポイントされたネットワークデバイスのリスト内に置かれる。
ネットワーク層は、デバイス固有の仕事が必要な場合、ネットワークデバイスに関する
多数のサービスルーチンのひとつを呼び出すが、そうしたルーチンのアドレスは <tt>
device</tt> データ構造体内に保持されている。しかし、適切な初期化が済むまでは、 
<tt>device</tt> データ構造体は、初期化もしくは検出ルーチンのアドレスしか保持し
ていない。

<!--
There are two problems to be solved for network device drivers. Firstly, not 
all of the network device drivers built into the Linux kernel will have 
devices to control. Secondly, the ethernet devices in the system are always 
called /dev/eth0, /dev/eth1 and so on, no matter what their underlying device
drivers are. The problem of ``missing'' network devices is easily solved. As
the initialization routine for each network device is called, it returns a 
status indicating whether or not it located an instance of the controller that
it is driving. If the driver could not find any devices, its entry in the 
device list pointed at by dev_base is removed. If the driver could find a 
device it fills out the rest of the device data structure with information 
about the device and the addresses of the support functions within the network
device driver. 
-->
<p>ネットワークデバイスドライバに関して解決すべき問題はふたつある。まず、
Linux カーネルに組み込まれたネットワークデバイスドライバのすべてが制御すべき
デバイスを持っているわけではないことである。もうひとつは、システム上の
イーサネットデバイスは、それらの基礎になるデバイスドライバとは無関係に、
<tt>/dev/eth0</tt>、<tt>/dev/eth1</tt> 等と呼ばれることである。ネットワーク
デバイスが存在しないという問題は、簡単に解決できる。個々のネットワークデバイス
の初期化ルーチンが呼び出された際に、それらのルーチンは、駆動すべき実際のコン
トローラを特定できたかどうかを報告するステータス情報を返す。ドライバがデバイス
を見つけられなかった場合、<tt><ref id="dev_base" name="dev_base"></tt> によって
ポイントされる <tt><ref id="device" name="device"></tt> 構造体のリスト内の
デバイスのエントリは削除される。ドライバがデバイスを検出できた場合、<tt>
device</tt> データ構造体の未設定部分に、そのデバイス情報とネットワークデバイス
ドライバ内のサポート関数のアドレスとを書き込む。

<!--
The second problem, that of dynamically assigning ethernet devices to the
standard /dev/ethN device special files is solved more elegantly. There are
eight standard entries in the devices list; one for eth0, eth1 and so on to
eth7. The initialization routine is the same for all of them, it tries each
ethernet device driver built into the kernel in turn until one finds a device.
When the driver finds its ethernet device it fills out the ethN device data
structure, which it now owns. It is also at this time that the network device
driver initializes the physical hardware that it is controlling and works out
which IRQ it is using, which DMA channel (if any) and so on. A driver may
find several instances of the network device that it is controlling and, in
this case, it will take over several of the /dev/ethN device data structures.
Once all eight standard /dev/ethN have been allocated, no more ethernet 
devices will be probed for.
-->
<p>もうひとつの問題である、イーサネットデバイスに標準的な <tt>/dev/ethN</tt> 
デバイススペシャルファイルを動的に割り当ててしまうという点については、もう少し
手際よく解決される。デバイスリストには 8 個の標準エントリがあり、順に <tt>
eth0, eth1</tt> 等から <tt>eth7</tt> まで並んでいる。初期化ルーチンは全部に
共通であり、カーネルに組み込まれたイーサネットドライバを、合致するデバイスが
見つかるまで順番に試していく。ドライバが該当するイーサネットデバイスを見つけた
とき、ドライバが所有することになった <tt>ethN</tt> <tt><ref id="device" 
name="device"></tt> データ構造体に情報を書き込む。そして、この時同時に、ネット
ワークデバイスドライバは、制御する物理デバイスを初期化し、使用する IRQ や(もし
必要なら) DMA チャンネル等を決定する。ドライバは、制御すべき複数のネットワーク
デバイスを検出することがあり、その場合は、複数の <tt>/dev/ethN device</tt> 
データ構造体を取得することになる。8 個すべての <tt>/dev/ethN devicd</tt> が割り
当てられると、それ以上のイーサネットデバイスの検出は行われない。

<!--
File translated from TEX by TTH, version 1.0. 
-->

<!--第 10 章 ファイルシステム-->
<!--Chapter 9 The File system-->
<sect>ファイルシステム<label id="chapter_fs">
<p>
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/penguin2.gif">
</figure>

<!--
This chapter describes how the Linux kernel maintains the files in the file
systems that it supports. It describes the Virtual File System (VFS) and
explains how the Linux kernel's real file systems are supported. 
-->
<p>この章では、Linux カーネルがサポートするファイルシステム内でのファイル管理
の方法や、仮想ファイルシステムの仕組みについて解説する。また、Linux カーネルの
実(real)ファイルシステムがどのようにサポートされているのかについても説明する。

<!--
One of the most important features of Linux is its support for many different
file systems. This makes it very flexible and well able to coexist with many
other operating systems. At the time of writing, Linux supports 15 file
systems; ext, ext2, xia, minix, umsdos, msdos, vfat, proc, smb, ncp,
iso9660, sysv, hpfs, affs and ufs, and no doubt, over time more will be
added. 
-->
<p>Linux の最も重要な特徴のひとつに、サポートするファイルシステムの豊富さがあ
る。このことが、Linux を非常に柔軟なものにし、他の多くのオペレーティングシス
テムとの共存を可能にしている。書き込みに関して、Linux は 15 のファイルシステム
をサポートしている。それらは、<tt>ext, ext2, xia, minix, umsdos, msdos, vfat, 
proc, smb, ncp, iso9660, sysv, hpfs, affs,</tt> それに <tt>ufs</tt> であり、
おそらく今後もっと多くのファイルシステムが追加されるだろう。

<!--
In Linux, as it is for Unix TM, the separate file systems the system may use
are not accessed by device identifiers (such as a drive number or a drive
name) but instead they are combined into a single hierarchical tree structure
that represents the file system as one whole single entity. Linux adds each
new file system into this single file system tree as it is mounted. All file
systems, of whatever type, are mounted onto a directory and the files of the
mounted file system cover up the existing contents of that directory. This
directory is known as the mount directory or mount point. When the file
system is unmounted, the mount directory's own files are once again
revealed. 
-->
<p>Linux では、Unix の場合と同様に、システム上で使用される個別のファイルシステ
ムにアクセスする際、(ドライブ番号やドライブ名といった)デバイス識別子は使われな
い。
それらのファイルシステムは、単一の階層的なツリー構造に統合され、それによって
ファイルシステムは全体でひとつの実体として表現される。
新しいファイルシステムをマウントする場合、Linux は個々のファイルシステムをこの
単一のツリー構造に付け加える。すべてのファイルシステムは、そのタイプに関わら
ず、任意のディレクトリにマウントされ、マウントされたファイルシステムのファイル
がそのディレクトリに現存する内容を包み隠す。
そうしたディレクトリは、マウントディレクトリもしくはマウントポイントと呼ばれ
る。ファイルシステムがマウントを解除されると、そのマウントディレクトリに存在
したファイルが再度出現する。

<!--
When disks are initialized (using fdisk, say) they have a partition structure
imposed on them that divides the physical disk into a number of logical
partitions. Each partition may hold a single file system, for example an EXT2
file system. File systems organize files into logical hierarchical structures
with directories, soft links and so on held in blocks on physical devices.
Devices that can contain file systems are known as block devices. The IDE
disk partition /dev/hda1, the first partition of the first IDE disk drive in 
the system, is a block device. The Linux file systems regard these block 
devices as simply linear collections of blocks, they do not know or care about
the underlying physical disk's geometry. It is the task of each block device 
driver to map a request to read a particular block of its device into terms 
meaningful to its device; the particular track, sector and cylinder of its 
hard disk where the block is kept. A file system has to look, feel and operate
in the same way no matter what device is holding it. Moreover, using Linux's 
file systems, it does not matter (at least to the system user) that these 
different file systems are on different physical media controlled by different
hardware controllers. The file system might not even be on the local system, 
it could just as well be a disk remotely mounted over a network link. Consider
the following example where a Linux system has its root file system on a SCSI 
disk: 
-->
<p>ディスクが(たとえば、<tt>fdisk</tt> を使用して)初期化されるとき、ディスク上
にパーティション構造が設定され、物理ディスクがいくつかの論理パーティションに
分割される。個々のパーティションは、EXT2 ファイルシステムといった単一の
ファイルシステムを保持する。ファイルシステムはファイルを組織し、物理デバイス
のブロック上に保持されたディレクトリやソフトリンク(シンボリックリンク)などによ
る論理的な階層構造を形成する。
ファイルシステムを内包し得るデバイスはブロックデバイスと呼ばれる。
IDE ディスクのパーティション <tt>/dev/hda1</tt> は、システム上の最初の IDE 
ディスクの最初のパーティションであるが、これはブロックデバイスである。Linux 
ファイルシステムは、ブロックデバイスをブロックが単に線形に並んだものと見看して
おり、下位にある物理ディスクのジオメトリに関しては知らないか
もしくは関心を持たない。デバイスの特定ブロックの読み出しリクエストを、その
デバイスにとって意味のある言葉に置き換えること、すなわち、ブロックが保存されて
いるそのハードディスク上の特定のトラック、セクタ、シリンダなどに置き換えるの
は、個々のブロックデバイスドライバの仕事である。ファイルシステムは、それを
保持しているのがどのようなデバイスであっても、同じ方法でそれを見て、認識し、
操作をする。さらに、Linux のファイルシステムを使用すれば、そうした異なる
ファイルシステムが異なるハードウェアコントローラに制御された異なる物理メディア
上にあるということは、(少なくともシステムのユーザにとっては)問題ではなくなる。
ファイルシステムはローカルシステム上にないことすら可能であり、ネットワーク
リンク越しに遠隔操作でマウントされたディスクであってもよい。Linux システムが
 SCSI ディスク上にルートファイルシステムを持っている次の例で考えてほしい。

<verb>
A         E         boot      etc       lib       opt       tmp       usr
C         F         cdrom     fd        proc      root      var       sbin
D         bin       dev       home      mnt       lost+found
</verb>

<!--
Neither the users nor the programs that operate on the files themselves need
know that /C is in fact a mounted VFAT file system that is on the first IDE
disk in the system. In the example (which is actually my home Linux system),
/E is the master IDE disk on the second IDE controller. It does not matter
either that the first IDE controller is a PCI controller and that the second is
an ISA controller which also controls the IDE CDROM. I can dial into the
network where I work using a modem and the PPP network protocol using a
modem and in this case I can remotely mount my Alpha AXP Linux system's
file systems on /mnt/remote. 
-->
<p>ユーザはもちろん、ファイル自体に操作を加えるプログラムでさえ、上記 <tt>
/C</tt> が実はマウントされた VFAT ファイルシステムであり、システムの第一の 
IDE ディスク上にあることを知る必要はない。上記の例では(これは実際にわたしが
自宅で使用している Linux システムのものなのだが)、<tt>/E</tt> は第二の IDE 
コントローラ上のマスター IDE ディスクである。プライマリ IDE コントローラが PCI 
コントローラで、第二のコントローラが IDE CD-ROM を制御する ISA コントローラで
あるといったことは(ファイルシステム上では)どちらも問題ではない。また、モデムと
そのモデムによる PPP ネットワークプロトコルを使用して、電話で職場のネットワーク
に接続し、この場合、そこにあるわたしの Alpha AXP Linux システム上のファイルシス
テムを <tt>/mnt/remote</tt> に遠隔操作でマウントすることもできる。

<!--
The files in a file system are collections of data; the file holding the 
sources to this chapter is an ASCII file called filesystems.tex. A file system
not only holds the data that is contained within the files of the file system 
but also the structure of the file system. It holds all of the information 
that Linux users and processes see as files, directories soft links, file 
protection information and so on. Moreover it must hold that information 
safely and securely, the basic integrity of the operating system depends on 
its file systems. Nobody would use an operating system that randomly lost data
and files. 
-->
<p>ファイルシステム上のファイルはデータの集合体である。この章の文章(訳注: 
原文のこと)が入った元のソースファイルは <tt>filesystems.tex</tt> というファイル
名の ASCII ファイルである。ファイルシステムは、そのファイルシステム上のファイル
内に含まれるデータを保持するだけでなく、ファイルシステムの構造をも保持してい
る。Linux のユーザやプロセスが、ファイル、ディレクトリ、ソフトリンク(シンボリッ
クリンク)、ファイル保護情報等々として見ている情報はすべて、ファイルシステムに
よって保持されている。
さらに、ファイルシステムはそうした情報を安全、確実に保持しなけれ
ばならない。オペレーティングシステムの基本的な統一性は、ファイルシステムに
依存しているからである。データやファイルの喪失が突発的に起こるオペレーティング
システムを使おうとする人はいないだろう(<ref id="chapter_fs_fn" 
name="脚注1">)。

<!--
Minix, the first file system that Linux had is rather restrictive and lacking 
in performance. Its filenames cannot be longer than 14 characters (which is 
still better than 8.3 filenames) and the maximum file size is 64MBytes. 
64Mbytes might at first glance seem large enough but large file sizes are 
necessary to hold even modest databases. The first file system designed 
specifically for Linux, the Extended File system, or EXT, was introduced in 
April 1992 and cured a lot of the problems but it was still felt to lack 
performance. So, in 1993, the Second Extended File system, or EXT2, was added. 
It is this file system that is described in detail later on in this chapter. 
-->
<p>Linux が最初に採用していた <tt>minix</tt> ファイルシステムは、やや制限が
多く、パフォーマンスにも欠けていた。ファイル名は 14 文字以上になってはなら
ず(これでも、8 文字 + 3文字 というファイル名よりはましである)、最大ファイル
サイズは 64M バイトであった。64 M バイトというと一見充分なサイズのように
思えるが、ちょっとしたデータベースを作ろうとすると大きなファイルサイズは必要
である。Linux 専用にデザインされた最初のファイルシステムである Extended File 
System (EXT) は、1992 年 4 月に発表され、多くの問題が改善されたが、それでも
まだパフォーマンスの欠如が感じられた。それゆえ、1993 年、Second Extended File 
System (EXT2) が登場した。この章で後ほど詳細に述べるのは、このファイルシステム
についてである。

<!--
An important development took place when the EXT file system was added
into Linux. The real file systems were separated from the operating system
and system services by an interface layer known as the Virtual File system,
or VFS. VFS allows Linux to support many, often very different, file systems, 
each presenting a common software interface to the VFS. All of the details of 
the Linux file systems are translated by software so that all file systems 
appear identical to the rest of the Linux kernel and to programs running in the
system. Linux's Virtual File system layer allows you to transparently mount
the many different file systems at the same time. 
-->
<p>EXT ファイルシステムが加わった際、重要な発展があった。実(real)ファイル
システムがオペレーティングシステムやシステムのサービスから分離され、その
インターフェイス層として仮想ファイルシステム(Virtual File System, VFS) が
付加されたことである。VFS によって、Linux は、多くの、しばしば非常に性質の
異なるファイルシステムのサポートが可能になった。そうした個々のファイルシステム
は VFS に対し共通のソフトウェアインターフェイスを提供する。Linux のファイル
システムの詳細のすべてがソフトウェア上で変換されるので、Linux カーネル
の残りの部分やシステム上で実行されているプログラムにとって、あらゆるファイル
システムは全く同じに見える。Linux の仮想ファイルシステムによって、同時に多く
の異なるファイルシステムを透過的にマウントすることが可能になっている。

<!--
The Linux Virtual File system is implemented so that access to its files is as
fast and efficient as possible. It must also make sure that the files and their
data are kept correctly. These two requirements can be at odds with each
other. The Linux VFS caches information in memory from each file system as
it is mounted and used. A lot of care must be taken to update the file system
correctly as data within these caches is modified as files and directories are
created, written to and deleted. If you could see the file system's data
structures within the running kernel, you would be able to see data blocks
being read and written by the file system. Data structures, describing the
files and directories being accessed would be created and destroyed and all
the time the device drivers would be working away, fetching and saving data.
The most important of these caches is the Buffer Cache, which is integrated
into the way that the individual file systems access their underlying block
devices. As blocks are accessed they are put into the Buffer Cache and kept
on various queues depending on their states. The Buffer Cache not only
caches data buffers, it also helps manage the asynchronous interface with
the block device drivers. 
-->
<p>Linux の仮想ファイルシステムは、ファイルへのアクセスを出来るだけ速く効率的
なものにするために実装されている。それはファイルやデータの正確な保存をも確実に
行わなければならない。これらふたつの要求は両立し難いものである。ファイルシス
テムがマウントされて利用される際、Linux の VFS はそれら個々の情報をメモリに
キャッシュする。ファイルやディレクトリに対する作成や書き込み、削除がなされて
そのキャッシュ内のデータが変更された場合、ファイルシステムを正しく更新する
には細かな配慮が必要になる。実行中のカーネル内にあるファイルシステムのデータ
構造を見ることができるとすれば、ファイルシステムによってデータブロックの読み
書きがなされる様子を観察できるだろう。アクセスされているファイルやディレクトリ
を記述するデータ構造体の作成や破棄がなされ、また終始デバイスドライバが動作
していて、データの取り込みや保存を行っている。これらのキャッシュで最も重要な
のが、バッファキャッシュ(buffer cache)であり、それは、個別のファイルシステム
がその基礎であるブロックデバイスにアクセスする仕組みのなかに組み込まれている。
ブロックがアクセスされると、それはバッファキャッシュに入れられ、それらの
状態に応じて様々なキュー上に保持される。バッファキャッシュは、データバッファを
キャッシュするだけではなく、非同期インターフェイスを管理することで、ブロック
デバイスドライバの手助けもしている。



<!--9.1  The Second Extended File system (EXT2)-->
<sect1>Second Extended File System (EXT2)<label id="chapter_fs_sect1">
<p>

<label id="figure9-1">
<!--          Figure 9.1: Physical Layout of the EXT2 File system-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure9-1.gif">
</figure>
</#if>
<#unless output="html">
<verb>
         +---------------------------------------------+
         |  | Block   |          | Block     | Block   |
         |  | Group 0 |          | Group N-1 | Group N |
         +---------------------------------------------+
                                 |           |
                           +-----+           +-----+
                           |                       |
<--------------------------+                       +-------------->
                           
+------------------------------------------------------------------+
| Super | Group       | Block  | Inode  | Inode |       Data       |
| Block | Descriptors | Bitmap | Bitmap | Table |       Block      |
|       |             |        |        |       |                  |
+------------------------------------------------------------------+
</verb>
</#if>
<p>図表(9.1) EXT2 ファイルシステムの物理的レイアウト

<!--
The Second Extended File system was devised (by Remy Card) as an
extensible and powerful file system for Linux. It is also the most successful
file system so far in the Linux community and is the basis for all of the
currently shipping Linux distributions. 
-->
<p>EXT2 ファイルシステム(Second Extended File System) は、Remy Card によって
考案された Linux 用の拡張性に富むパワフルなファイルシステムである。
それは Linux コミュニティーにおいてこれまでで最も成功したファイルシステムであ
り、現在出荷されているすべての Linux ディストリビューションの基盤でもある。
<newline>[see: fs/ext2/*]
<!--
The EXT2 file system, like a lot of the file systems, is built on the premise
that the data held in files is kept in data blocks. These data blocks are all 
of the same length and, although that length can vary between different EXT2
file systems the block size of a particular EXT2 file system is set when it is
created (using mke2fs). Every file's size is rounded up to an integral number
of blocks. If the block size is 1024 bytes, then a file of 1025 bytes will 
occupy two 1024 byte blocks. Unfortunately this means that on average you waste
half a block per file. Usually in computing you trade off CPU usage for
memory and disk space utilisation. In this case Linux, along with most
operating systems, trades off a relatively inefficient disk usage in order to
reduce the workload on the CPU. 
Not all of the blocks in the file system hold
data, some must be used to contain the information that describes the
structure of the file system. EXT2 defines the file system topology by
describing each file in the system with an inode data structure. An inode
describes which blocks the data within a file occupies as well as the access
rights of the file, the file's modification times and the type of the file. 
Every file in the EXT2 file system is described by a single inode and each 
inode has a single unique number identifying it. The inodes for the file 
system are all kept together in inode tables. EXT2 directories are simply 
special files (themselves described by inodes) which contain pointers to the 
inodes of their directory entries. 
-->
<p>EXT2 ファイルシステムは、多くのファイルシステム同様、ファイルに保持された
データはデータブロックに保存されるという前提のもとに構築されている。これらの
データブロックはすべて同じサイズであり、そのサイズは異なる EXT2 ファイル
システム間で変化することがあるが、特定の EXT2 ファイルシステムにおけるブロック
サイズは(<tt>mke2fs</tt> コマンドを使用した)ファイルシステム作成時に設定さ
れる。ファイルサイズはすべて、ブロックサイズの整数倍に切り上げられる。ブロック
サイズが 1024 バイトの場合、1025 バイトのファイルは 1024 バイトのブロックふたつ
を占有する。残念なことに、これは平均するとファイルごとに半ブロックのディスク
スペースが浪費されることを意味する。( CPU 対記憶装置という二者択一の原理から
すると)コンピュータでは通常、CPU 効率を犠牲にしてメモリとディスクスペース
を有効利用する。しかしこの場合、Linux は、大部分のオペレーティングシステムと
同様、CPU の負荷を減らすために、比較的効率の悪いディスクの使い方をする。
<p>
ファイルシステム上のすべてのブロックがデータを保持しているのではない。ブロック
の一部は、ファイルシステムの構造を記述した情報を保持するために使用されている。
EXT2 はファイルシステムのトポロジーを定義するために、システム上の個々の
ファイルを <tt><ref id="ext2_inode" name="inode"></tt> データ構造体で記述して
いる。
<tt>inode</tt> が記述する事柄には、ファイル内のデータが保持されたブロックの位置
や、ファイルへのアクセス権、ファイルの変更時間、ファイルタイプなどがある。
EXT2 ファイルシステム上のすべてのファイルは、単一の <tt>inode</tt> で記述され、
個々の <tt>inode</tt> は識別のための単一でユニークな番号を持つ。
ファイルシステム上の <tt>inode</tt> は、<tt>inode</tt> テーブル内に保存される。
EXT2 のディレクトリとは(それ自体も <tt>inode</tt> によって記述されている)特殊な
ファイルにすぎず、そのファイルに含まれるのは、そのディレクトリ(が保持する)
エントリの <tt>inode</tt> へのポインタである。

<!--
Figure  9.1 shows the layout of the EXT2 file system as occupying a series of
blocks in a block structured device. So far as each file system is concerned,
block devices are just a series of blocks that can be read and written. A file
system does not need to concern itself with where on the physical media a
block should be put, that is the job of the device's driver. Whenever a file
system needs to read information or data from the block device containing it,
it requests that its supporting device driver reads an integral number of
blocks. The EXT2 file system divides the logical partition that it occupies 
into Block Groups. Each group duplicates information critical to the integrity
of the file system as well as holding real files and directories as blocks of 
information and data. This duplication is neccessary should a disaster occur 
and the file system need recovering. The subsections describe in more detail 
the contents of each Block Group. 
-->
<p><ref id="figure9-1" name="図表(9.1)">は、EXT2 ファイルシステムのレイアウト
を示すものであるが、それらは、ブロック構造を持ったデバイス上で連続したブロック
を占有している。
個々のファイルシステムからすると、ブロックデバイスとは読み書き可能な一連の
ブロックにすぎない。ファイルシステムは物理メディア上のどこにブロックを置くべき
かを気にする必要がない。それはデバイスドライバの仕事である。ファイルシステムが
ブロックデバイスの持つ情報やデータを読み込む必要があるときは、そのデバイスを
サポートするデバイスドライバに対して、ある整数倍の数のブロックを読み込むよう
リクエストをする。
EXT2 ファイルシステムは、ディスク上の論理パーティションを、複数のブロック
グループ(Block Group)に分割する。個々のブロックグループは、実(real)ファイルや
実ディレクトリの情報やデータをブロックとして保持すると同時に、ファイルシステム
の整合性(integrity)を保つために必須の情報を二重化して保持する。二重化が必要なの
は、不具合が生じてファイルシステムを復旧しなければならない場合があるからであ
る。ブロックグループそれぞれの内容については、サブセクションでさらに詳しく説明
する。

<!--9.1.1  The EXT2 Inode-->
<sect2>EXT2 Inode<label id="chapter_fs_sect1-1">
<p>

<label id="figure9-2">
<!--                    Figure 9.2: EXT2 Inode-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure9-2.gif">
</figure>
</#if>
<#unless output="html">
<verb>
  ext2_inode
+-----------------+                                  +-------+
| Mode            |                      +---------->| Data  |
|-----------------|                      |           +-------+
| Owner info      |                      |           
|-----------------|                      |           +-------+
| Size            |                      |   +------>| Data  |
|-----------------|                      |   |       +-------+
| Timestamps      |                      |   |       +-------+
|-----------------|                      |   |       | Data  |
|                 |----------------------+   |       +-------+
| Direct Blocks   |                          |
|                 |--------------------------+       +-------+
|                 |                               +->| Data  |
|                 |                 +---+         |  +-------+
|                 |         +------>|   |---------+  +-------+
|-----------------|         |       |   |----------->| Data  |
| Indirect blocks |---------+       |   |            +-------+
|-----------------|           +---+ +---+  +---+     +-------+
| Double Indirect |---------->|   |------->|   |---->| Data  |
|-----------------|           |   |-+      |   |     +-------+
| Triple Indirect |           |   | |      |   |-+   +-------+
+-----------------+           +---+ |      +---+ +-->| Data  |
                                    |      +---+     +-------+
                                    +----->|   |     +-------+
                                           |   |---->| Data  |
                                           |   |     +-------+
                                           +---+
</verb>
</#if>
<p>図表(9.2) EXT2 Inode


<!--
In the EXT2 file system, the inode is the basic building block; every file and
directory in the file system is described by one and only one inode. The EXT2
inodes for each Block Group are kept in the inode table together with a bitmap
that allows the system to keep track of allocated and unallocated inodes.
Figure  9.2 shows the format of an EXT2 inode, amongst other information, it
contains the following fields: 
-->
<p>EXT2 ファイルシステムでは、<tt><ref id="ext2_inode" name="inode"></tt> が
基本的な建築材料(building block)である。
ファイルシステム上のすべてのファイルとディレクトリは、それらと一対一の関係
に立つ <tt>inode</tt> によって記述される。ブロックグループごとの EXT2  
<tt>inode</tt> は、<tt>inode</tt> テーブルに保存され、同時に、システムが割り当
てや解放を行った <tt>inode</tt> の状態を監視するためのビットマップ(bitmap)も
そのテーブルに保存される。
図表(9.2)では、EXT2 inode のフォーマットを示していて、その種々の情報の中には、
次のようなフィールドが含まれている。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/ext2_fs_i.h" 
name="include/linux/ext2_fs_i.h">]<newline>

<!--
mode This holds two pieces of information; what this inode describes and
      the permissions that users have to it. For EXT2, an inode can
      describe one of file, directory, symbolic link, block device, character
      device or FIFO. 
-->
<label id="chapter_fs_ext2_mode">
<descrip>
<tag>モード (mode)</tag>
このフィールドは 2 種類の情報を保持している。その inode が何を記述しているか
ということと、ユーザがそれに対して持つパーミッションである。
EXT2 の場合、inode が記述できるのは、ファイル、ディレクトリ、シンボリック
リンク、ブロックデバイス、キャラクタデバイス、FIFO のうちのひとつである。

<!--
Owner Information
      The user and group identifiers of the owners of this file or directory.
      This allows the file system to correctly allow the right sort of
      accesses, 
-->
<tag>所有者情報</tag>
そのファイルやディレクトリの所有者(owner)に関するユーザ識別子とグループ識別子。
これによって、ファイルシステムは正しいアクセス権限を適切に判断できる。

<!--
Size The size of the file in bytes, 
-->
<tag>サイズ</tag>
バイト単位で表されるファイルサイズ

<!--
Timestamps
      The time that the inode was created and the last time that it was
      modified, 
-->
<tag>タイムスタンプ(timestamps)</tag>
<tt><ref id="ext2_inode" name="inode"></tt> が作成された時間とそれが最後に修正
された時間

<!--
Datablocks
      Pointers to the blocks that contain the data that this inode is
       describing. The first twelve are pointers to the physical blocks
      containing the data described by this inode and the last three pointers
      contain more and more levels of indirection. For example, the double
      indirect blocks pointer points at a block of pointers to blocks of
      pointers to data blocks. This means that files less than or equal to
      twelve data blocks in length are more quickly accessed than larger
      files. 
-->
<tag>データブロック</tag>
<tt><ref id="ext2_inode" name="inode"></tt> が記述するデータを含んだブロック
に対するポインタ。
最初の 12 個は、その inode が記述するデータを含んだ物理ブロックへのポインタで
あり、最後の 3 つはそれよりも 2 段階間接的なポインタとなっている。たとえば、こ
の二重間接ブロックポインタ(double indirect block pointer)は、物理データブロック
へのポインタ群に対するポインタ群をポイントしている。これは、12 個のデータブロッ
ク以下のサイズしかないファイルは、それより大きいファイルよりも高速にアクセスさ
れることを意味する。
</descrip>

<!--
You should note that EXT2 inodes can describe special device files. These
are not real files but handles that programs can use to access devices. All of
the device files in /dev are there to allow programs to access Linux's
devices. For example the mount program takes as an argument the device file
that it wishes to mount. 
-->
<p>注意すべきなのは、EXT2 inode はスペシャルファイルを表すことができることで
ある。これらは実(real)ファイルではないが、プログラムがそれを使ってデバイスに
アクセスできるようにするためのものである。<tt>/dev</tt> ディレクトリに
すべてのデバイスファイルが存在することによって、プログラムは Linux 上のデバイス
にアクセスできる。たとえば、<tt>mount</tt> プログラムは、マウントしようとする
デバイスファイル名を引数に取る。

<!--9.1.2  The EXT2 Superblock-->
<sect2>EXT2 スーパーブロック(Superblock)<label id="chapter_fs_sect1-2">

<!--
The Superblock contains a description of the basic size and shape of this file
system. The information within it allows the file system manager to use and
maintain the file system. Usually only the Superblock in Block Group 0 is read
when the file system is mounted but each Block Group contains a duplicate
copy in case of file system corruption. Amongst other information it holds the:
-->
<p>スーパーブロック(superblock)には、そのファイルシステムの基本的なサイズと
構造(shape)とを記述した情報が含まれる。そこにある情報によって、ファイルシステム
マネージャは、ファイルシステムの使用と管理が可能となる。通常、ファイルシステム
がマウントされる時、ブロックグループ 0 上のスーパーブロックだけが読み込まれるの
だが、個々のブロックグループにはシステムの破壊に備えた複製が含まれている。
様々な情報のなかには次のようなものがある。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/ext2_fs_sb.h" 
name="include/linux/ext2_fs_sb.h">]<newline>
[訳注:ext2_super_block, in <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/ext2_fs.h" 
name="include/linux/ext2_fs.h">]
<!--
Magic Number
      This allows the mounting software to check that this is indeed the
      Superblock for an EXT2 file system. For the current version of EXT2
      this is 0xEF53. 
-->
<descrip>
<tag>マジックナンバー(<ref id="magic_number" name="magic number">)</tag>
これは、マウント操作を行うソフトウェアが、そのスーパーブロックが本当に EXT2 
ファイルシステムのものであるかチェックすることを可能にするためにある。EXT2 の
現行バージョンでは、この番号は 0xEF53 である。

<!--
Revision Level
      The major and minor revision levels allow the mounting code to
      determine whether or not this file system supports features that are
      only available in particular revisions of the file system. There are also
      feature compatibility fields which help the mounting code to
      determine which new features can safely be used on this file system, 
-->
<tag>リビジョンレベル(revision level)</tag>
メジャーとマイナーのリビジョンレベルによって、マウント操作を行うコードは、
そのファイルシステムの特定のリビジョンでしか利用できない機能(feature)をサポー
トすべきかどうかを判断する。
また、機能互換性フィールド(feature compatibility field)というのが存在し、その
情報は、マウント操作コードが、そのファイルシステム上で新しい機能を安全に使用
することができるかどうかを判断する際の手助けをする。

<!--
Mount Count and Maximum Mount Count
      Together these allow the system to determine if the file system
      should be fully checked. The mount count is incremented each time
      the file system is mounted and when it equals the maximum mount
      count the warning message ``maximal mount count reached, running
      e2fsck is recommended'' is displayed, 
-->
<tag>マウントカウントと最大マウントカウント(mount count and maximum mount 
count)</tag>
これらふたつは、ファイルシステムの整合性を完全にチェックすべきかどうかを
システムが判断できるようにするために存在する。マウントカウントは、ファイル
システムがマウントされるたびに加算され、最大マウントカウントに達すると、
「最大マウントカウントに達したので、<tt>e2fsck</tt> を実行することを薦めます」
という警告メッセージが表示される。

<!--
Block Group Number
      The Block Group number that holds this copy of the Superblock, 
-->
<tag>ブロックグループ番号(block group number)</tag>
このスーパーブロックのコピーを保持するブロックグループ番号。

<!--
Block Size
      The size of the block for this file system in bytes, for example 1024
      bytes, 
-->
<tag>ブロックサイズ(block size)</tag>
バイト数で表されるそのファイルシステムのブロックサイズ。たとえば、1024 バイト等
と表示される。

<!--
Blocks per Group
      The number of blocks in a group. Like the block size this is fixed
      when the file system is created, 
-->
<tag>グループごとのブロック数</tag>
ひとつのグループのブロック数。これは、ブロックサイズ同様、ファイルシステム作成
時に確定される。

<!--
Free Blocks
      The number of free blocks in the file system, 
-->
<tag>フリーブロック</tag>
ファイルシステム上のフリーブロックの数。

<!--
Free Inodes
      The number of free Inodes in the file system, 
-->
<tag>フリー inode</tag>
ファイルシステム上のフリー inode の数。

<!--
First Inode
      This is the inode number of the first inode in the file system. The first
      inode in an EXT2 root file system would be the directory entry for the
      '/' directory. 
-->
<tag>最初の inode (first inode)</tag>
ファイルシステム上の最初の inode の inode 番号。EXT2 ルートファイルシステム
上での最初の inode は、&dquot;<tt>/</tt>&dquot; ディレクトリのディレクトリ
エントリである。
</descrip>


<!--9.1.3  The EXT2 Group Descriptor-->
<sect2>EXT2 グループディスクリプタ<label id="chapter_fs_sect1-3">

<!--
Each Block Group has a data structure describing it. Like the Superblock, all
the group descriptors for all of the Block Groups are duplicated in each Block
Group in case of file system corruption. 
-->
<p>個々のブロックグループは、それを記述するデータ構造体を持っている。スーパー
ブロックと同様に、全ブロックグループに対するグループディスクリプタはすべて、
ファイルシステムの障害に備えて、個々のブロックグループ内で二重化されている。
<newline>[see: ext2_group_desc, in <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/ext2_fs.h"
name="include/linux/ext2_fs.h">]<newline>

<!--
Each Group Descriptor contains the following information: 
-->
<p>個々のグループディスクリプタには、次のような情報が含まれている。

<!--
Blocks Bitmap
      The block number of the block allocation bitmap for this Block Group.
      This is used during block allocation and deallocation, 
-->
<descrip>
<label id="chapter_fs_bitmap">
<tag>ブロックビットマップ(Block Bitmap)</tag>
そのブロックグループに関するブロック割り当てビットマップ(block allocation 
bitmap)のブロック番号。
これは、ブロックの割り当てと解放の際に使用される。

<!--
Inode Bitmap
      The block number of the inode allocation bitmap for this Block Group.
      This is used during inode allocation and deallocation, 
-->
<tag>inode ビットマップ (Inode Bitmap)</tag>
そのブロックグループに対する inode 割り当てビットマップのブロック番号。
これは、inode の割り当てと解放の際に使用される。

<!--
Inode Table
      The block number of the starting block for the inode table for this
      Block Group. Each inode is represented by the EXT2 inode data
      structure described below. 
-->
<tag>inode テーブル(Inode Table)</tag>
そのブロックグループの対する inode テーブルの開始ブロックのブロック番号。
個々の inode は、下記で述べる EXT2 inode データ構造体によって表されている。

<!--
Free blocks count, Free Inodes count, Used directory count
-->
<tag>Free block count, Free Inodes count, Used directory count</tag>
(訳注：これらの項目の説明は原文から省略されています。)
</descrip>

<!--
The group descriptors are placed on after another and together they make the
group descriptor table. Each Blocks Group contains the entire table of group
descriptors after its copy of the Superblock. Only the first copy (in Block
Group 0) is actually used by the EXT2 file system. The other copies are
there, like the copies of the Superblock, in case the main copy is corrupted. 
-->
<p>グループディスクリプタは連続的に配置されているので、全体でグループディスク
リプタテーブルを形成している。個々のブロックグループには、そのスーパーブロッ
クのコピーの後に、グループディスクリプタのテーブル全体が含まれている。
EXT2 ファイルシステムによって実際に使用されるのは、(ブロックグループ 0 にある)
最初のコピーだけである。その他のコピーは、スパーブロックのコピーの場合と同様
に、メインコピーが壊れた場合に備えてのものである。

<!--9.1.4  EXT2 Directories-->
<sect2>EXT2 ディレクトリ<label id="chapter_sect1-4">
<p>

<label id="figure9-3">
<!--                   Figure 9.3: EXT2 Directory-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure9-3.gif">
</figure>
</#if>
<#unless output="html">
<verb>
 0                   15                        55
+---+---+---+------+---+---+---+--------------+--------------------+
| il| 15|  5|  file| i2| 40| 14|very_long_name|                    |
+---+---+---+------+---+---+---+--------------+--------------------+
  |    |           * |    |                   *
  |    |          /| |    |                  /|
  |    |           | |    |                   |
  |    +-----------+ |    +-------------------+
  |                  |          
  |                  |      inode table
  |                  |     +--------------------+
  |                  |     |                    |
  |                  |     |--------------------|
  |                  |     |                    |
  |                  |     |--------------------|
  |                  +---->|                    |
  |                        |--------------------|
  |                        |                    |
  |                        |--------------------|
  +----------------------->|                    |
                           +--------------------+
</verb>
</#if>
<p>図表(9.3) EXT2 ディレクトリ

<!--
In the EXT2 file system, directories are special files that are used to create
and hold access paths to the files in the file system. Figure  9.3 shows the
layout of a directory entry in memory. A directory file is a list of directory
entries, each one containing the following information: 
-->
<p>EXT2 ファイルシステムにおいて、ディレクトリとは、ファイルシステム上のファイ
ルに対するアクセスパス(access path)の作成と保持のために使用されるスペシャル
ファイルである。図表(9.3)では、メモリ上でのディレクトリエントリのレイアウトが
示されている。ディレクトリファイルは、ディレクトリエントリのリストであり、
個々のエントリには次のような情報が含まれている。
<newline>[see: ext2_dir_entry, in <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/ext2_fs.h" 
name="include/linux/ext2_fs.h">]<newline>

<!--
inode The inode for this directory entry. This is an index into the array of
      inodes held in the Inode Table of the Block Group. In figure  9.3, the
      directory entry for the file called file has a reference to inode
      number i1, 
-->
<descrip>
<tag>inode</tag>
そのディレクトリエントリに対する inode 。これは、ブロックグループの inode 
テーブルに保持されている inode 配列へのインデックスになっている。図表(9.3)
では、<tt>file</tt> という名前のファイルに対するディレクトリエントリが inode 
番号 <tt>i1</tt> を参照している。

<!--
name length
      The length of this directory entry in bytes, 
-->
<tag>名前のサイズ (name length)</tag>
バイト数で示されるそのディレクトリエントリのサイズ

<!--
name The name of this directory entry. 
-->
<tag>名前 (name)</tag>
そのディレクトリエントリの名前
</descrip>

<!--
The first two entries for every directory are always the standard ``.'' 
and ``..'' entries meaning ``this directory'' and ``the parent directory'' 
respectively. 
-->
<p>すべてのディレクトリにおける最初のふたつのエントリはいつも、標準となって
いる "<tt>.</tt>" と "<tt>..</tt>" エントリであり、
それらはそれぞれ "現在のディレクトリ" と "親ディレクトリ(parent directory)" 
を意味している。

<!--9.1.5  Finding a File in an EXT2 File System-->
<sect2>EXT2 ファイルシステム上のファイルの検索<label id="chapter_fs_sect1-5">

<!--
A Linux filename has the same format as all Unix TM filenames have. It is a
series of directory names separated by forward slashes (``/'') and ending in
the file's name. One example filename would be /home/rusling/.cshrc
where /home and /rusling are directory names and the file's name is
.cshrc. Like all other Unix TM systems, Linux does not care about the
format of the filename itself; it can be any length and consist of any of the
printable characters. To find the inode representing this file within an EXT2
file system the system must parse the filename a directory at a time until we
get to the file itself. 
-->
<p>Linux のファイル名は、Unix 上のファイル名と同じフォーマットになっている。
それは、スラッシュ("<tt>/</tt>")で区切られた一連のディレクトリ名とその最後
にあるファイルの名前から成る。ファイル名の一例は、<tt>/home/rusling/.cshrc
</tt>であり、ここでの <tt>/home</tt> と <tt>/rusling</tt> はディレクトリ名で
あり、ファイル名は <tt>.cshrc</tt> である。他のすべての Unix システムと同様に、
Linux はファイル名そのもののフォーマットには特別な様式を要求しない。それは任意
の長さで、表示可能な任意の文字であってよい。EXT2 ファイルシステム上の
上記ファイルを表す inode を発見するため、システムは、そのファイル自体の
名前に到達するまでファイル名をディレクトリ単位で分解しなければならない。

<!--
The first inode we need is the inode for the root of the file system and we 
find its number in the file system's superblock. To read an EXT2 inode we must
look for it in the inode table of the appropriate Block Group. If, for example,
the root inode number is 42, then we need the 42nd inode from the inode table
of Block Group 0. The root inode is for an EXT2 directory, in other words the
mode of the root inode describes it as a directory and it's data blocks contain
EXT2 directory entries. 
-->
<p>必要とされる最初の inode は、ファイルシステムのルートディレクトリの inode 
であるので、ファイルシステム上のスーパーブロック内でその番号を見つける。EXT2 
inode を読むためには、適切なブロックグループの inode テーブルでそれを探さなけ
ればならない。たとえば、ルートの inode 番号が 42 である場合、ブロックグループ 
0 の inode テーブルにある 42 番目の inode を必要とする。ルート inode は EXT2 
ディレクトリのものであり、言い換えると、ルート inode のモード(mode)には
ディレクトリと記述されているので、そのデータブロックには EXT2 ディレクトリの
エントリが含まれている。

<!--
home is just one of the many directory entries and this directory entry gives
us the number of the inode describing the /home directory. We have to read
this directory (by first reading its inode and then reading the directory 
entries from the data blocks described by its inode) to find the rusling entry
which gives us the number of the inode describing the /home/rusling directory.
Finally we read the directory entries pointed at by the inode describing the
/home/rusling directory to find the inode number of the .cshrc file and
from this we get the data blocks containing the information in the file. 
-->
<p><tt>home</tt> は多くのディレクトリエントリのひとつにすぎず、このディレクトリ
エントリからは、<tt>/home</tt> ディレクトリが記述する inode の番号が分かる。
<tt>rusling</tt> のエントリを見つけるにはこのディレクトリを読み込まなければ
ならない。(まず、最初にその inode を読み込んで、次にその inode によって記述
されたデータブロックからディレクトリエントリを読み込む。)そして、その中から 
<tt>rusling</tt> エントリが見つかったら、そこから <tt>/home/rusling</tt> 
ディレクトリを記述する inode の番号が分かる。最後に、<tt>/home/rusling</tt> 
ディレクトリを記述する inode によってポイントされたディレクトリエントリを
読んで、<tt>.cshrc</tt> ファイルの inode 番号を発見し、その番号によって
そのファイルの情報を含んでいるデータブロックを取得する。

<!--9.1.6  Changing the Size of a File in an EXT2 File System-->
<sect2>EXT2 ファイルシステム上のファイルサイズの変更<label 
id="chapter_fs_sect1-6">

<!--
One common problem with a file system is its tendency to fragment. The
blocks that hold the file's data get spread all over the file system and this
makes sequentially accessing the data blocks of a file more and more
inefficient the further apart the data blocks are. The EXT2 file system tries 
to overcome this by allocating the new blocks for a file physically close to 
its current data blocks or at least in the same Block Group as its current data
blocks. Only when this fails does it allocate data blocks in another Block
Group. 
-->
<p>ファイルシステムに共通の問題のひとつに、ファイルの断片化(fragment)傾向が
ある。ファイルのデータを保持するブロックはファイルシステム全体に分散して
しまい、そのため、データブロック間の距離が遠くなるにつれて、ファイルのデータ
ブロックに対する連続したアクセスが困難になりアクセス効率が落ちてしまう。
EXT2 ファイルシステムはこの問題を克服するために、ファイルに新しいデータブロック
を割り当てる際、それが現在存在するデータブロックに対し物理的に近接する位置に
割り当てるか、少なくとも元のデータブロックと同じブロックグループ内に割り当て
ようとする。そしてそれが出来ない場合のみ、データブロックを別のブロックグループ
に割り当てる。

<!--
Whenever a process attempts to write data into a file the Linux file system
checks to see if the data has gone off the end of the file's last allocated
block. If it has, then it must allocate a new data block for this file. Until 
the allocation is complete, the process cannot run; it must wait for the file 
system to allocate a new data block and write the rest of the data to it 
before it can continue. The first thing that the EXT2 block allocation 
routines do is to lock the EXT2 Superblock for this file system. Allocating 
and deallocating changes fields within the superblock, and the Linux file 
system cannot allow more than one process to do this at the same time. If 
another process needs to allocate more data blocks, it will have to wait until
this process has finished. Processes waiting for the superblock are suspended,
unable to run, until control of the superblock is relinquished by its current 
user. Access to the superblock is granted on a first come, first served basis 
and once a process has control of the superblock, it keeps control until it 
has finished. Having locked the superblock, the process checks that there are 
enough free blocks left in this file system. If there are not enough free 
blocks, then this attempt to allocate more will fail and the process will 
relinquish control of this file system's superblock. 
-->
<p>プロセスがデータをファイルに書き込もうとするとき、Linux ファイルシステム
は、(データ書き込みの途中で)そのファイルに対して最後に割り当てられたブロック
の終端を越えたかどうかをチェックする。
終端を越えた場合、ファイルシステムはそのファイルに新しいデータブロックを割り
当てる処理をする。割り当てが終わるまで、プロセスは実行を中断する。ファイル
システムが新しいデータブロックを割り当てて、それに残りのデータを書き込むまで
待ってから、プロセスは実行を再開しなければならない。
EXT2 ブロック割り当てルーチンが最初に実行することは、そのファイルシステムに対
する EXT2 スーパーブロックをロック(lock)することである。割り当てと解放は
スーパーブロック内のフィールドの値を変更するので、Linux ファイルシステムは同時
に複数のプロセスがそれをすることを許さない。他のプロセスがさらにデータブロック
を割り当てなければならない場合は、実行中のプロセスが終了するまで待つ必要があ
る。
スーバーブロックのロック解除を待つプロセスはサスペンド状態になり、スーパー
ブロックの制御が現在のユーザによって開放されるまでは実行されない。
スーパーブロックへのアクセスは早い者勝ちの仕組みで許可されるので、プロセスが
いったんスーパーブロックの制御を得た場合、処理の終了までその制御を保持する。
スーパーブロックをロックした後、プロセスはファイルシステム上に充分な空き
ブロックがあるかどうかをチェックする。
充分な空きブロックがない場合、それ以上割り当てようとしても失敗するので、プロ
セスは、そのファイルシステムのスーパーブロックの制御を解放する。

<!--
If there are enough free blocks in the file system, the process tries to 
allocate one. 
If the EXT2 file system has been built to preallocate data blocks then we may
be able to take one of those. The preallocated blocks do not actually exist,
they are just reserved within the allocated block bitmap. The VFS inode
representing the file that we are trying to allocate a new data block for has
two EXT2 specific fields, prealloc_block and prealloc_count, which
are the block number of the first preallocated data block and how many of
them there are, respectively. If there were no preallocated blocks or block
preallocation is not enabled, the EXT2 file system must allocate a new block.
The EXT2 file system first looks to see if the data block after the last data
block in the file is free. Logically, this is the most efficient block to 
allocate as it makes sequential accesses much quicker. If this block is not 
free, then the search widens and it looks for a data block within 64 blocks of
the of the ideal block. This block, although not ideal is at least fairly 
close and within the same Block Group as the other data blocks belonging to 
this file. 
-->
<p>ファイルシステム上に充分な空きブロックがある場合、プロセスはそれを割り当て
ようとする。
<newline>[see:ext2_new_block(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/fs/ext2/balloc.c" 
name="fs/ext2/balloc.c">]<newline>
EXT2 ファイルシステムがデータブロックを先割り当て(preallocate)するようビルド
されている場合、それらの中から割り当てを行うことができる。この先割り当てされた
ブロックは実際には存在せず、割り当てられたブロックビットマップ(<ref 
id="chapter_fs_bitmap" name="block bitmap">)内で予約されているだけである。
ファイルに新しいデータブロックを割り当てようとしている場合、そのファイルを
表す VFS <tt><ref id="inode" name="inode"></tt> には、EXT2 に特有の <tt>
<ref id="ext2_inode_info" name="prealloc_block"></tt> と <tt><ref 
id="ext2_inode_info" name="prealloc_count"></tt> のふたつのフィールドがあり、
それらはそれぞれ、先割り当てされたデータブロックの最初のブロック番号と、
存在するブロック数を表す。
先割り当てされたブロックが存在しないかブロックの先割り当てが無効な場合、EXT2 
ファイルシステムは新しいブロックを割り当てなければならない。まず EXT2 ファイル
システムはファイル内の最後のデータブロックの直後にあるデータブロックが空かどう
かを確認する。理論的には、このブロックは、連続的なアクセスをより高速にできるの
で、割り当てるのに最も効率的なブロックである。このブロックが空でない場合、検索
範囲が広げられ、先ほどの理想的なブロックから 64 ブロック以内にあるブロックを探
す。このブロックは最適ではないにしても、少なくとも非常に近くにあり、そのファイ
ルに属する他のデータブロックと同じブロックグループ内にある。
<newline>[see: ext2_new_block(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/fs/ext2/balloc.c" 
name="fs/ext2/balloc.c">]

<!--
If even that block is not free, the process starts looking in all of the other
Block Groups in turn until it finds some free blocks. The block allocation code
looks for a cluster of eight free data blocks somewhere in one of the Block
Groups. If it cannot find eight together, it will settle for less. If block
preallocation is wanted and enabled it will update prealloc_block and
prealloc_count accordingly. 
-->
<p>そのブロックが空でない場合であっても、プロセスは他のブロックグループを順番
に探して、何らかの空ブロックを見つける。ブロック割り当てコードは、ひとつの
ブロックグループ内のどこかに 8 個の空データブロックのクラスタがあるか調べる。
8 個を一緒に見つけられない場合、それ以下で処理を行う。ブロックの先割り当てが
必要かつ有効とされている場合、当該コードは <tt>prealloc_block</tt> と <tt>
prealloc_count</tt> を適宜更新する。

<!--
Wherever it finds the free block, the block allocation code updates the Block
Group's block bitmap and allocates a data buffer in the buffer cache. That
data buffer is uniquely identified by the file system's supporting device
identifier and the block number of the allocated block. The data in the buffer
is zero'd and the buffer is marked as ``dirty'' to show that it's contents have
not been written to the physical disk. Finally, the superblock itself is marked
as ``dirty'' to show that it has been changed and it is unlocked. If there were
any processes waiting for the superblock, the first one in the queue is allowed
to run again and will gain exclusive control of the superblock for its file
operations. The process's data is written to the new data block and, if that
data block is filled, the entire process is repeated and another data block
allocated. 
-->
<p>空ブロックを見つけた場所に関わりなく、ブロック割り当てコードはブロック
グループのブロックビットマップを更新し、バッファキャッシュにデータバッファを
割り当てる。そのデータバッファは、ファイルシステムがサポートするデバイス識別子
と割り当てられたブロックのブロック番号とによってユニークに識別される。
バッファ内のデータは 0 とされ、バッファの内容が物理ディスクに書き込まれていない
ことを示すためにそのバッファは「ダーティー(dirty)」とマークされる。最後に、
スーパーブロック自身が、変更されてロックを解除されたことを示すために
「ダーティー」とマークされる。スーパーブロックの空きを待つプロセスがある場合、
キューの最初にあるプロセスが再度実行され、ファイル操作のためにスーパーブロック
の排他的な実行制御権を獲得する。プロセスのデータが新しいデータブロックに書き込
まれ、もしそのデータブロックが満杯になると、そのプロセス全体が繰り返されて次の
データブロックが割り当てられる。

<!--9.2  The Virtual File System (VFS)-->
<sect1>仮想ファイルシステム (Virtual File System, VFS)<label 
id="chapter_fs_sect2">
<p>

<label id="figure4-1">
<!--        Figure 9.4: A Logical Diagram of the Virtual File System-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure9-4.gif">
</figure>
</#if>
<#unless output="html">
<verb>
          +---------+                    +------------+
          |         |<------------------>|   inode    |
          |   VFS   |<----------+        | キャッシュ |
          |         |           |        |            |
          +--*---*--+           |        +------------+
            /|  /|              |
     +-------+   +------+       |
     |/                 |/      |
+----*----+        +----*----+  |
|         |        |         |  |
|  MINIX  |        |  EXT2   |  |        +------------+
|         |        |         |  +------->|ディレクトリ|
+----*----+        +----*----+           | キャッシュ |
    /|                 /|                |            |
     *-------+   +------+                +------------+
             |/  |/
          +--*---*---+
          | バッファ |
          |キャッシュ|
          |          |
          +----*-----+
              /|
               |/
          +----*-----+
          | ディスク |
          | ドライブ |
          |          |
          +----------+
</verb>
</#if>
<p>図表(9.4) 仮想ファイルシステムの論理ダイアグラム

<!--
Figure  9.4 shows the relationship between the Linux kernel's Virtual File
System and it's real file systems. The virtual file system must manage all of
the different file systems that are mounted at any given time. To do this it
maintains data structures that describe the whole (virtual) file system and
the real, mounted, file systems. 
Rather confusingly, the VFS describes the system's files in terms of
superblocks and inodes in much the same way as the EXT2 file system uses
superblocks and inodes. Like the EXT2 inodes, the VFS inodes describe files
and directories within the system; the contents and topology of the Virtual
File System. From now on, to avoid confusion, I will write about VFS inodes
and VFS superblocks to distinquish them from EXT2 inodes and superblocks.
-->
<p>図表(9.4)では、Linux の仮想ファイルシステムと実(real)ファイルシステムとの
関係が示されている。仮想ファイルシステムは任意の時間にマウントされた異なる
ファイルシステムすべてを管理しなければならない。そのために、仮想ファイル
システムは、(仮想)ファイルシステム全体、およびマウントされた実(real)ファイル
システムを記述するデータ構造体を管理している。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/fs" name="fs/*">]<newline>
やや混乱するかもしれないが、VFS は、EXT2 ファイルシステムがスーパーブロックや 
inode を利用する方法と非常に似通った方法で、システムのファイルをスーパーブロッ
クと inode を使って記述している。
EXT2 <ref id="ext2_inode" name="inode"> の場合と同様に、VFS <ref id="inode" 
name="inode"> も、システム上のファイルやディレクトリを記述している。すなわち、
仮想ファイルシステムの内容やトポロジーを VFS inode を使って記述しているわけで
ある。
ここからは、混乱を避けるために、(仮想ファイルシステムの inode やスーパー
ブロックに関しては) VFS inode や VFS スーパーブロックと書くことで、EXT2 の 
inode やスーパーブロックと区別する。

<!--
As each file system is initialised, it registers itself with the VFS. This
happens as the operating system initialises itself at system boot time. The
real file systems are either built into the kernel itself or are built as 
loadable modules. File System modules are loaded as the system needs them, so,
for example, if the VFAT file system is implemented as a kernel module, then 
it is only loaded when a VFAT file system is mounted. When a block device based
file system is mounted, and this includes the root file system, the VFS must
read its superblock. Each file system type's superblock read routine must
work out the file system's topology and map that information onto a VFS
superblock data structure. The VFS keeps a list of the mounted file systems
in the system together with their VFS superblocks. Each VFS superblock
contains information and pointers to routines that perform particular
functions. So, for example, the superblock representing a mounted EXT2 file
system contains a pointer to the EXT2 specific inode reading routine. This
EXT2 inode read routine, like all of the file system specific inode read
routines, fills out the fields in a VFS inode. Each VFS superblock contains a
pointer to the first VFS inode on the file system. For the root file system, 
this is the inode that represents the ``/'' directory. This mapping of 
information is very efficient for the EXT2 file system but moderately less so 
for other file systems. 
-->
<p>個々のファイルシステムが初期化されると、それは VFS に登録される。これは、
システムのブート時、オペレーティングシステムが初期化される際に行われる。
実(real)ファイルシステムは、カーネルに組み込まれているか、ローダブルモジュール
としてビルドされているかのいずれかである。ファイルシステムモジュールは、システ
ムがそれを必要とするときにロードされるので、たとえば、VFAT ファイルシステムが
カーネルモジュールとして実装されている場合、それは VFAT ファイルシステムがマウ
ントされたときにのみロードされる。ブロックデバイスベースのファイルシステムが
マウントされ、ルートファイルシステムに組み込まれると、VFS はそのファイルシステ
ムが持つスーパーブロックのデータ構造体を読み込まなければならない。
ファイルシステムタイプごとのスーパーブロック読み込みルーチンは、そのファイル
システムのトポロジーを読み解いて、その情報を VFS スーパーブロックのデータ構造体
にマップする。
VFS は、VFS スーパーブロックを保持すると同時に、システム上のマウントされた
ファイルシステムに関するリストを保持しなければならない。
個々の VFS スーパーブロックには、特定の機能を担当するルーチンの情報と、その
ルーチンへのポインタが含まれている。それゆえ、たとえば、マウントされた EXT2 
ファイルシステムを表すスーパーブロックには、EXT2 固有の inode 読み込みルーチン
へのポインタが含まれている。
この EXT2 inode 読み込みルーチンは、ファイルシステム固有の inode 読み込みルーチ
ンすべてに共通することでもあるが、VFS inode のフィールドに必要な情報を記入
する。個々の VFS スーパーブロックには、そのファイルシステム上の最初の VFS 
inode へのポインタが含まれている。ルートファイルシステムの場合、それは "<tt>/
</tt>" ディレクトリを表す inode である。こうした情報のマッピングは EXT2 ファイ
ルシステムの場合は非常に効率的に行われるが、他のファイルシステムに対してはやや
効率が落ちる。

<!--
As the system's processes access directories and files, system routines are
called that traverse the VFS inodes in the system. 
For example, typing ls for a directory or cat for a file cause the the Virtual
File System to search through the VFS inodes that represent the file system.
As every file and directory on the system is represented by a VFS inode, then
a number of inodes will be being repeatedly accessed. These inodes are kept
in the inode cache which makes access to them quicker. If an inode is not in
the inode cache, then a file system specific routine must be called in order to
read the appropriate inode. The action of reading the inode causes it to be put
into the inode cache and further accesses to the inode keep it in the cache.
The less used VFS inodes get removed from the cache. 
-->
<p>システム上のプロセスがディレクトリやファイルにアクセスする際、システムの
ルーチンはシステム上の VFS <ref id="inode" name="inode"> を経由して呼び出さ
れる。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/fs/inode.c" 
name="fs/inode.c">]<newline>
たとえば、ディレクトリ上で <tt>ls</tt> とタイプするか、ファイルに対して <tt>cat
</tt> とタイプした場合、仮想ファイルシステムは、そのファイルシステムを表す VFS 
inode 群を検索する。
システム上の全ファイルとディレクトリは VFS inode によって表現されているので、
いくつかの inode が繰り返しアクセスされる。それらの inode は inode キャッシュに
保存されて、それらに対するアクセス速度の向上が図られる。inode キャッシュに 
inode がない場合、適切な inode を読み込むためにファイルシステム固有のルーチンが
呼び出される。inode を読み込む処理によって、inode は inode キャッシュに入れら
れ、その inode への更なるアクセスによってキャッシュに保存されたままとなる。
ほとんど使用されない VFS inode はキャッシュから削除される。

<!--
All of the Linux file systems use a common buffer cache to cache data
buffers from the underlying devices to help speed up access by all of the file
systems to the physical devices holding the file systems. 
This buffer cache is independent of the file systems and is integrated into the
mechanisms that the Linux kernel uses to allocate and read and write data
buffers. It has the distinct advantage of making the Linux file systems
independent from the underlying media and from the device drivers that
support them. All block structured devices register themselves with the Linux
kernel and present a uniform, block based, usually asynchronous interface.
Even relatively complex block devices such as SCSI devices do this. As the
real file systems read data from the underlying physical disks, this results in
requests to the block device drivers to read physical blocks from the device
that they control. Integrated into this block device interface is the buffer
cache. As blocks are read by the file systems they are saved in the global
buffer cache shared by all of the file systems and the Linux kernel. Buffers
within it are identified by their block number and a unique identifier for the
device that read it. So, if the same data is needed often, it will be retrieved
from the buffer cache rather than read from the disk, which would take
somewhat longer. Some devices support read ahead where data blocks are
speculatively read just in case they are needed. 
-->
<p>すべての Linux ファイルシステムは、共通のバッファキャッシュを利用して、基礎
となるデバイスのデータバッファをキャッシュする。これは、ファイルシステムが、そ
のファイルシステムを保持する物理デバイスにアクセスする際、アクセス速度の向上に
役立つ。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/fs/buffer.c" 
name="fs/buffer.c">]<newline>
このバッファキャッシュは、ファイルシステムから独立している。そして、それは、
Linux カーネルがデータバッファの割り当て、読み出し、書き込みのために使用する
メカニズムの中に組み込まれている。これによって Linux のファイルシステムは、
基礎となるメディアやそれをサポートするデバイスドライバから独立できるので、
その仕組みは Linux の明らかな長所となっている。
ブロック構造を持つデバイスはすべて、Linux カーネルに登録され、ブロックベース
の、一般に非同期な、統一的インターフェイスを提供する。SCSI のような比較的複雑な
デバイスでも同様である。実(real)ファイルシステムが基礎となる物理デバイスから
データを読み込む場合、実際にはブロックデバイスドライバにリクエストを送り、ドラ
イバが、その制御するデバイスから物理ブロックを読み込む。このブロックデバイスの
インターフェイスに組み込まれているのが、バッファキャッシュである。
ファイルシステムによってブロックが読み込まれると、それらのブロックは、すべての
ファイルシステムと Linux カーネルによって共有される包括的なバッファに保存され
る。バッファ内の個々のブロックは、ブロック番号とそれを読み込んだデバイス固有の
識別子とによって識別される。したがって、同じデータがしばしば必要とされる場合、
それは、時間のかかるディスクからの読み出しを利用するのではなく、バッファキャッ
シュから取り出される。デバイスの中には先読みをサポートするものがあるが、それは
データブロックが必要とされる場合に備えて、予め予測されるデータブロックを読み込
んでおく機能である。

<!--
The VFS also keeps a cache of directory lookups so that the inodes for
frequently used directories can be quickly found. 
As an experiment, try listing a directory that you have not listed recently. 
The first time you list it, you may notice a slight pause but the second time 
you list its contents the result is immediate. The directory cache does not 
store the inodes for the directories itself; these should be in the inode 
cache, the directory cache simply stores the mapping between the full 
directory names and their inode numbers. 
-->
<p>VFS は、頻繁に使用されるディレクトリをすばやく見つけるために、検索された
ディレクトリのキャッシュをも保持している。
<newline>[see : <htmlurl 
url="./The-Linux-Kernel-images/linux/fs/dcache.c" 
name="fs/dcache.c">]<newline>
実験として、最近表示したことがないディレクトリを表示してみるとそれが分かる。
最初に表示した際、やや時間が掛かるのに気付くが、二度目にその内容が表示される時
は、結果が即座に出る。ディレクトリキャッシュはディレクトリの inode そのものを
保存するのではない。それらは inode キャッシュ内になければならず、ディレクトリ
キャッシュは、完全なディレクトリ名とその inode 番号だけを保存している。

<!--9.2.1  The VFS Superblock-->
<sect2>VFS スーパーブロック<label id="chapter_fs_sect2-1">

<!--
Every mounted file system is represented by a VFS superblock; amongst
other information, the VFS superblock contains the: 
-->
<p>マウントされたすべてのファイルシステムは、VFS スーパーブロックによって
表現される。VFS スーパーブロックは様々な情報を含んでいるが、次にその一部を
示す。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/fs.h" 
name="include/linux/fs.h">]<newline>

<!--
Device This is the device identifier for the block device that this file system
      is contained in. For example, /dev/hda1, the first IDE hard disk in
      the system has a device identifier of 0x301, 
-->
<descrip>
<tag>デバイス (device)</tag>
これは、そのファイルシステムが含まれているブロックデバイスのデバイス識別子で
ある。たとえば、システム上の最初の IDE ハードディスクである <tt>/dev/hda1</tt> 
のデバイス識別子は、0x301 である。

<!--
Inode pointers
      The mounted inode pointer points at the first inode in this file
      system. The covered inode pointer points at the inode representing
      the directory that this file system is mounted on. The root file
      system's VFS superblock does not have a covered pointer, 
-->
<tag>inode ポインタ (inode pointer)</tag>
inode ポインタ <tt><ref id="super_block" name="mounted"></tt> は、そのファイ
ルシステムの最初の inode をポイントするポインタである。inode ポインタ <tt><ref 
id="super_block" name="covered"></tt> は、そのファイルシステムがマウントされた
ディレクトリを表す inode をポイントするポインタである。
ルートファイルシステムの VFS スーパーブロックには、<tt>covered</tt> ポインタ
は含まれない。

<!--
Blocksize
      The block size in bytes of this file system, for example 1024 bytes, 
-->
<tag>ブロックサイズ (blocksize)</tag>
バイト単位で表されるそのファイルシステムのブロックサイズ。たとえば、1024 バイ
ト。

<!--
Superblock operations
      A pointer to a set of superblock routines for this file system.
      Amongst other things, these routines are used by the VFS to read and
      write inodes and superblocks. 
-->
<tag>スーパーブロック操作ルーチン (superblock operations)</tag>
そのファイルシステムに対する一連のスーパーブロック操作ルーチンへのポインタ。
それらの中には、VFS が inode とスーパーブロックの読み書きに使用するルーチンが
ある。

<!--
File System type
      A pointer to the mounted file system's file_system_type data
      structure, 
-->
<tag>ファイルシステムタイプ (file system type)</tag>
マウントされたファイルシステムの <tt><ref id="file_system_type" 
name="file_system_type"></tt> データ構造体へのポインタ。

<!--
File System specific
      A pointer to information needed by this file system, 
-->
<tag>ファイルシステム固有の情報 (file system specific)</tag>
そのファイルシステムにとって必要な情報へのポインタ

</descrip>

<!--9.2.2  The VFS Inode-->
<sect2>VFS inode<label id="chapter_fs_sect2-2">

<!--
Like the EXT2 file system, every file, directory and so on in the VFS is
represented by one and only one VFS inode. 
The information in each VFS inode is built from information in the underlying
file system by file system specific routines. VFS inodes exist only in the
kernel's memory and are kept in the VFS inode cache as long as they are
useful to the system. Amongst other information, VFS inodes contain the
following fields: 
-->
<p>EXT2 ファイルシステムと同様に、VFS 上のすべてのファイルやディレクトリ等は
ユニークな VFS <ref id="inode" name="inode"> によって表現される。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/fs.h" 
name="include/linux/fs.h">]<newline>
個々の VFS inode 内の情報は、ファイルシステム固有のルーチンによって、その
基礎となるファイルシステム内の情報から組み立てられる。VFS inode はカーネル
メモリ上にしか存在せず、システムにとって有益である間だけ VFS inode キャッシュ
に保存される。VFS inode に含まれる情報には種種のものがあるが、次にその一部を
示す。

<!--
device This is the device identifer of the device holding the file or whatever
      that this VFS inode represents, 
-->
<descrip>
<tag>デバイス (device)</tag>
これは、ファイルか当該 VFS inode が指すものを保持しているデバイスのデバイス
識別子である。

<!--
inode number
      This is the number of the inode and is unique within this file system.
      The combination of device and inode number is unique within the
      Virtual File System, 
-->
<tag>inode 番号 (inode number)</tag>
これは、その inode の番号であり、それはそのファイルシステム内でユニークな値で
ある。デバイスと inode 番号の組み合わせは、その VFS 上において重複することは
ない。

<!--
mode Like EXT2 this field describes what this VFS inode represents as
      well as access rights to it, 
-->
<tag>モード (mode)</tag>
<ref id="chapter_fs_ext2_mode" name="EXT2"> と同様に、このフィールドが示すの
は、その VFS inode が表す対象とそれに対するアクセス権である。

<!--
user ids
      The owner identifiers, 
-->
<tag>ユーザ ID (user ids)</tag>
所有者の識別子。

<!--
times The creation, modification and write times, 
-->
<tag>時間 (times)</tag>
作成、修正、書き込みが起こった時間。

<!--
block size
      The size of a block for this file in bytes, for example 1024 bytes, 
-->
<tag>ブロックサイズ (block size)</tag>
バイト単位で表されるそのファイルのブロックサイズ。たとえば 1024 バイト。

<!--
inode operations
      A pointer to a block of routine addresses. These routines are specific
      to the file system and they perform operations for this inode, for
      example, truncate the file that is represented by this inode. 
-->
<tag>inode 操作 (inode operations)</tag>
ルーチンのアドレス群へのポインタ。それらのルーチンはファイルシステムに固有で
あり、たとえば、その inode が指すファイルを切り縮めるといった、当該 inode に
対する操作を実行する。

<!--
count The number of system components currently using this VFS inode. A
      count of zero means that the inode is free to be discarded or reused, 
-->
<tag>カウント (count)</tag>
現在その VFS inode を使用しているコンポーネントの数。カウント 0 は、その 
inode が使用されておらず、破棄するか再利用されるべきことを意味する。

<!--
lock This field is used to lock the VFS inode, for example, when it is being
      read from the file system, 
-->
<tag>ロック (lock)</tag>
このフィールドは VFS inode をロックする際に使用される。たとえば、ファイルシステ
ムから読み出されている場合など。

<!--
dirty Indicates whether this VFS inode has been written to, if so the
      underlying file system will need modifying, 
-->
<tag>ダーティー (dirty)</tag>
その VFS inode が書き込みをされたかどうかを示す。もしそうである場合、その
基礎となるファイルシステムは適宜修正される必要がある。

<!--
file system specific information
-->
<tag>ファイル (file)</tag>
ファイルシステム固有の情報。

</descrip>

<!--9.2.3  Registering the File Systems-->
<sect2>ファイルシステムの登録<label id="chapter_fs_sect2-3">
<p>

<label id="figure9-5">
<!--                Figure 9.5: Registered File Systems-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure9-5.gif">
</figure>
</#if>
<#unless output="html">
<verb>
+---file_systems
|
|
|  file_system_type     file_system_type      file_system_type
|  +-------------+      +-------------+      +-------------+
+->|*read_super()|  +-->|*read_super()|  +-->|*read_super()|
   |-------------|  |   |-------------|  |   |-------------|
   | name        |"ext2"| name        |"proc"| name        |"iso9660"
   |-------------|  |   |-------------|  |   |-------------|
   | requires_dev|  |   | requires_dev|  |   | requires_dev|
   |-------------|  |   |-------------|  |   |-------------|
   | next        |--+   | next        |--+   | next        |
   +-------------+      +-------------+      +-------------+
</verb>
</#if>
<p>図表(9.5) ファイルシステムの登録

<!--
When you build the Linux kernel you are asked if you want each of the
supported file systems. When the kernel is built, the file system startup code
contains calls to the initialisation routines of all of the built in file 
systems. 
Linux file systems may also be built as modules and, in this case, they may
be demand loaded as they are needed or loaded by hand using insmod.
Whenever a file system module is loaded it registers itself with the kernel
and unregisters itself when it is unloaded. Each file system's initialisation
routine registers itself with the Virtual File System and is represented by a
file_system_type data structure which contains the name of the file
system and a pointer to its VFS superblock read routine. Figure  9.5 shows
that the file_system_type data structures are put into a list pointed at by
the file_systems pointer. Each file_system_type data structure
contains the following information: 
-->
<p>Linux カーネルをビルドするとき、サポートされている個々のファイルシステム
をカーネルに組み込むかどうか質問がなされる。カーネルがビルドされると、ファイル
システム初期化コードには、組み込まれたファイルシステムすべてに関する初期化
ルーチンへの呼び出しコードが含められる。
<newline>[see: sys_setup(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/fs/filesystems.c" 
name="fs/filesystems.c">]<newline>
Linux のファイルシステムは、モジュールとしてもビルドすることができる。
その場合、それらは必要に応じてオンデマンドでロードされるか、<tt>insmod</tt> 
コマンドを使用して手動でロードされる。
ファイルシステムモジュールがロードされるときはいつも、それがカーネルに登録
され、ロードが解除されると登録が取り消される。
個々のファイルシステムの初期化ルーチンは仮想ファイルシステムに登録され、
<tt><ref id="file_system_type" name="file_system_type"></tt> データ構造体に
よって表現される。その構造体にはファイルシステムの名前と VFS スーパーブロック
読み込みルーチンへのポインタが含まれている。
<ref id="figure9-5" name="図表(9.5)">では、<tt>file_system_type</tt> データ構造
体が、<tt><ref id="file_system_type" name="file_systems"></tt> リストに登録
され、そのポインタによってポイントされる様子が示されている。個々の <tt>
file_system_type</tt> データ構造体には次のような情報が含まれている。
<newline>[see: file_system_type, in <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/fs.h" 
name="include/linux/fs.h">]
<!--
Superblock read routine
      This routine is called by the VFS when an instance of the file system
      is mounted, 
-->
<descrip>
<tag>スーパーブロック読み込みルーチン (superblock read routine)</tag>
このルーチンは、具体的なファイルシステムがマウントされたときに VFS によって
呼び出される。

<!--
File System name
      The name of this file system, for example ext2, 
-->
<tag>ファイルシステム名 (file system name)</tag>
ファイルシステムの名前。たとえば、ext2 など。

<!--
Device needed
      Does this file system need a device to support? Not all file system
      need a device to hold them. The /proc file system, for example, does
      not require a block device, 
-->
<tag>必要なデバイス (device needed)</tag>
そのファイルシステムは、サポートするデバイスが必要か？ すべてのファイルシステム
がそれを保持するデバイスを必要とするわけではない。たとえば、<tt>/proc</tt> 
ファイルシステムはブロックデバイスを必要としない。
</descrip>

<!--
You can see which file systems are registered by looking in at
/proc/filesystems. For example: 
-->
<p>どのファイルシステムが登録されているか知るには、<tt>/proc/filesystems</tt> 
を覗けばよい。たとえば、次のように表示されるだろう。

<verb>
      ext2
nodev proc
      iso9660
</verb>

<!--9.2.4  Mounting a File System-->
<sect2>ファイルシステムのマウント<label id="chapter_fs_sect2-4">

<!--
When the superuser attempts to mount a file system, the Linux kernel must
first validate the arguments passed in the system call. Although mount does
some basic checking, it does not know which file systems this kernel has
been built to support or that the proposed mount point actually exists.
Consider the following mount command: 
-->
<p>スーパーユーザがファイルシステムをマウントするとき、Linux はまず、システム
コールに渡される引数の妥当性検査をしなければならない。<tt>mount</tt> コマンド
も基本的なチェックは行うが、現在のカーネルにどのファイルシステムへのサポート
が組み込まれているかや、ユーザによって指定されたマウントポイントが実際に存在
するかといったことは知らないからである。次の <tt>mount</tt> コマンドについて
考えてほしい。

<verb>
$ mount -t iso9660 -o ro /dev/cdrom /mnt/cdrom
</verb>

<!--
This mount command will pass the kernel three pieces of information; the
name of the file system, the physical block device that contains the file
system and, thirdly, where in the existing file system topology the new file
system is to be mounted. 
-->
<p>この <tt>mount</tt> コマンドはカーネルに 3 つの情報を渡す。ファイルシステム
名、ファイルシステムを含んでいる物理ブロックデバイス、そして 3 つ目に、
現存するファイルシステムのトポロジーにおいて、新しいファイルシステムがどこに
マウントされるべきかということである。
<newline>[see: do_mount(), in <htmlurl
url="./The-Linux-Kernel-images/linux/fs/super.c" 
name="fs/super.c">]
<newline>[see: get_fs_type(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/fs/super.c" 
name="fs/super.c">]<newline>
<!--
The first thing that the Virtual File System must do is to find the file 
system. To do this it searches through the list of known file systems by 
looking at each file_system_type data structure in the list pointed at by
file_systems. If it finds a matching name it now knows that this file system 
type is supported by this kernel and it has the address of the file system 
specific routine for reading this file system's superblock. If it cannot find 
a matching file system name then all is not lost if the kernel is built to 
demand load kernel modules (see Chapter  modules-chapter). In this case the 
kernel will request that the kernel daemon loads the appropriate file system 
module before continuing as before. 
-->
<p>仮想ファイルシステムが最初にすべきことは、そのファイルシステムを見つける
ことである。そのために既知のファイルシステムのリストを走査するのだが、それは
 <tt><ref id="file_system_type" name="file_systems"></tt> によってポイントされ
たリストの中にある <tt><ref id="file_system_type" name="file_system_type">
</tt> データ構造体を個別に探すことによってなされる。
そして、該当する名前が見つかった場合、次にそのファイルシステムが現在のカーネル
でサポートされていること、および現在のカーネルにそのファイルシステムのスーパー
ブロックを読み出すためのファイルシステム固有のルーチンのアドレスが含まれている
ことが分かる。
合致するファイルシステム名を見つけられなかった場合でも、カーネルがオンデマンド
でカーネルモジュールをロードするようビルドされているなら(詳細は<ref 
id="chapter_m" name="「モジュール」">を参照のこと)、処理は継続する。その場合、
カーネルは元の作業を続ける前にカーネルデーモンに対して適切なファイルシステム
をデマンドローディングするようリクエストする。

<!--
Next if the physical device passed by mount is not already mounted, it must
find the VFS inode of the directory that is to be the new file system's mount
point. This VFS inode may be in the inode cache or it might have to be read
from the block device supporting the file system of the mount point. Once the
inode has been found it is checked to see that it is a directory and that there
is not already some other file system mounted there. The same directory
cannot be used as a mount point for more than one file system. 
-->
<p>次に、<tt>mount</tt> によって渡された物理デバイスがまだマウントされていない
場合、新しいファイルシステムのマウントポイントとなるディレクトリの VFS inode 
を見つけなければならない。その VFS inode は、inode キャッシュにあるか、マウント
ポイントがあるファイルシステムをサポートするブロックデバイスから読み出すか
される。inode が分かったら、それがディレクトリかどうか、すでに他のファイル
システムがそこにマウントされていないかどうかを確認するためのチェックがなされ
る。複数のファイルシステムに対するマウントポイントとしては、同一のディレクトリ
は使用できないからである。

<!--
At this point the VFS mount code must allocate a VFS superblock and pass it
the mount information to the superblock read routine for this file system. All
of the system's VFS superblocks are kept in the super_blocks vector of
super_block data structures and one must be allocated for this mount. The
superblock read routine must fill out the VFS superblock fields based on
information that it reads from the physical device. For the EXT2 file system
this mapping or translation of information is quite easy, it simply reads the
EXT2 superblock and fills out the VFS superblock from there. For other file
systems, such as the MS DOS file system, it is not quite such an easy task.
Whatever the file system, filling out the VFS superblock means that the file
system must read whatever describes it from the block device that supports
it. If the block device cannot be read from or if it does not contain this 
type of file system then the mount command will fail. 
-->
<p>この時点で、VFS のマウント処理コードは VFS スーパーブロックを割り当てて、
そのファイルシステムのスーパーブロック読み込みルーチンに対してそのマウント
情報を渡さなければならない。VFS スーパーブロックのすべては <tt><ref 
id="super_block" name="super_block"></tt> データ構造体の <tt><ref 
id="super_block" name="super_blocks"></tt> 配列に保存されているので、その
ひとつが、当該マウントのために割り当てられなければならない。スーパーブロック
読み込みルーチンは、それが物理デバイスから読み出しだ情報を基にして VFS 
スーパーブロックのフィールドを適切な情報で埋めなければならない。
EXT2 ファイルシステムに関しては、この情報のマッピングもしくは変換は非常に簡単で
ある。しかし、MS-DOS ファイルシステムのようなその他のファイルシステムに関して
は、それほど簡単なタスクではない。ファイルシステムが何であれ、VFS スーパー
ブロックのフィールドを埋めることは、それをサポートするブロックデバイスから、
それが示すすべての情報を読み出さなければならないことを意味する。
ブロックデバイスから読み出しができない場合、もしくはデバイスがそのタイプの
ファイルシステムを含まない場合は、<tt>mount</tt> コマンドは失敗に終わる。

<label id="figure9-6">
<!--                Figure 9.6: A Mounted File System-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure9-6.gif">
</figure>
</#if>
<#unless output="html">
<verb>
+---vfsmntlist
|
|
|    vfsmount
|  +-----------+
+->| mnt_dev   | 0x0301
   |-----------|
   |mnt_devname| /dev/hda1
   |-----------|
   |mnt_dirname| /
   |-----------|
   | mnt_flags |
   |-----------|          VFS
   | mnt_sb    |-+    super_block            file_system_type
   |-----------| |  +-------------+          +---------------+
   |           | +->| s_dev       |0x0301 +->| *read_super() |
   |-----------|    |-------------|       |  |---------------|
   | next      |    | s_blocksize |1024   |  | name          |"ext2"
   +-----------+    |-------------|       |  |---------------|
                    | s_type      |-------+  | requires_dev  |
                    |-------------|          |---------------|
                    | s_flags     |          | next          |
                    |-------------|          +---------------+
                    | s_covered   |
                    |-------------|          VFS
                    | s_mounted   |--+      inode
                    |             |  |    +---------+
                    +-------------+  +--->| i_dev   | 0x0301
                                          | i_ino   | 42
                                          |         |
                                          +---------+
</verb>
</#if>
<p>図表(9.6) マウントされたファイルシステム

<!--
Each mounted file system is described by a vfsmount data structure; see
figure  9.6. These are queued on a list pointed at by vfsmntlist. 
Another pointer, vfsmnttail points at the last entry in the list and the
mru_vfsmnt pointer points at the most recently used file system. Each
vfsmount structure contains the device number of the block device holding
the file system, the directory where this file system is mounted and a pointer
to the VFS superblock allocated when this file system was mounted. In turn
the VFS superblock points at the file_system_type data structure for
this sort of file system and to the root inode for this file system. This 
inode is kept resident in the VFS inode cache all of the time that this file 
system is loaded. 
-->
<p>マウントされた個々のファイルシステムは、<tt><ref id="vfsmount" 
name="vfsmount"></tt> データ構造体によって記述される。図表(9.6)を見て欲しい。
それらは <tt><ref id="vfsmount" name="vfsmntlist"></tt> によってポイントされた
リスト上に待ち行列を作っている。
<newline>[see: add_vfsmnt(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/fs/super.c" 
name="fs/super.c">]<newline>
別のポインタである <tt><ref id="vfsmount" name="vfsmnttail"></tt> は、リストの
最後のエントリをポイントしており、<tt><ref id="vfsmount" name="mru_vfsmnt">
</tt> ポインタは最も最近利用されたファイルシステムをポイントしている。
個々の <tt>vfsmount</tt> データ構造体には、そのファイルシステムを保持する
ブロックデバイスのデバイス番号、そのファイルシステムがマウントされている
ディレクトリ、そしてそのファイルシステムがマウントされた時に割り付けられた VFS
 スーパーブロックへのポインタが含まれている。さらに、VFS スーパーブロックは、
該当する種類のファイルシステムに関する <tt><ref id="file_system_type" 
name="file_system_type"></tt> データ構造体とそのファイルシステムのルート inode 
をポイントしている。この inode は、そのファイルシステムがロードされている間は、
 VFS inode キャッシュのなかに保存される。

<!--9.2.5  Finding a File in the Virtual File System-->
<sect2>仮想ファイルシステム内でのファイルの検索<label 
id="chapter_fs_sect2-5">

<!--
To find the VFS inode of a file in the Virtual File System, VFS must resolve
the name a directory at a time, looking up the VFS inode representing each of
the intermediate directories in the name. Each directory lookup involves
calling the file system specific lookup whose address is held in the VFS inode
representing the parent directory. This works because we always have the
VFS inode of the root of each file system available and pointed at by the VFS
superblock for that system. Each time an inode is looked up by the real file
system it checks the directory cache for the directory. If there is no entry in
the directory cache, the real file system gets the VFS inode either from the
underlying file system or from the inode cache. 
-->
<p>仮想ファイルシステム上でファイルの VFS <ref id="inode" name="inode"> を探す
ためには、VFS は、名前に含まれる個々のディレクトリを表す VFS inode を問い合わせ
ながら、ディレクトリごとにその名前解決をしなければならない。
個々のディレクトリ問い合わせの際には、ファイルシステム固有の問い合わせルーチン
が呼び出される。そのルーチンのアドレスはその親ディレクトリを表す VFS inode 内に
保持されている。これが上手くいくのは、個々のファイルシステムのルートディレクト
リの VFS inode は、そのシステムの VFS スーパーブロックによってポイントされてい
るので、必ず知ることができるからである。
実(real)ファイルシステムによって inode が問い合わせされるたびに、ディレクトリ
用のディレクトリキャッシュがチェックされる。ディレクトリキャッシュにエントリが
ない場合、実ファイルシステムは VFS inode を基礎となるファイルシステムからか、
inode キャッシュからのいずれかから取得する。

<!--9.2.6  Creating a File in the Virtual File System-->
<sect2>仮想ファイルシステム上でのファイルの作成<label id="chapter_fs_sect2-6">
<p>(訳注: この部分の原文が存在しません。)

<!--9.2.7  Unmounting a File System-->
<sect2>ファイルシステムのマウント解除<label id="chapter_fs_sect2-7">

<!--
The workshop manual for my MG usually describes assembly as the reverse
of disassembly and the reverse is more or less true for unmounting a file
system. 
A file system cannot be unmounted if something in the system is using one of
its files. So, for example, you cannot umount /mnt/cdrom if a process is
using that directory or any of its children. If anything is using the file 
system to be unmounted there may be VFS inodes from it in the VFS inode cache,
and the code checks for this by looking through the list of inodes looking for
inodes owned by the device that this file system occupies. If the VFS
 superblock for the mounted file system is dirty, that is it has been modified,
then it must be written back to the file system on disk. Once it has been
written to disk, the memory occupied by the VFS superblock is returned to
the kernel's free pool of memory. Finally the vfsmount data structure for
this mount is unlinked from vfsmntlist and freed. 
-->
<p>わたしの愛車である MG の整備マニュアルにはたいていの場合「組み立ては
分解の逆である」としか説明されていないが、これはファイルシステムの
アンマウントに関する説明にも程度の差はあれ言えることだろう。
<newline>[see: do_unmount(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/fs/super.c" 
name="fs/super.c">]<newline>
システム上のファイルシステム内にあるファイルのひとつが何らかのかたちで使用され
ている場合、そのファイルシステムはアンマウントできない。それゆえ
たとえば、プロセスが <tt>/mnt/cdrom</tt> のディレクトリやその子ディレクトリを
使用している場合、そのディレクトリはアンマウントできない。アンマウントすべき
ファイルシステムが何らかのかたちで使用されている場合、そのファイルシステムの 
VFS inode が VFS inode キャッシュにあるかもしれないので、コードはそれをチェック
するために、inode リストを走査し、そのファイルシステムがあるデバイスによって
所有されている inode を探す。マウントされたファイルシステムに関する VFS 
スーパーブロックがダーティー(dirty)な場合、それは修正されているということなの
で、修正されたの内容をディスク上のファイルシステムに書き込まれなければならな
い。ディスクへの書き込みが終了したら、VFS スーパーブロックに占有されていた
メモリは、カーネルの空きメモリのプールに戻される。最後に、そのマウントに関する 
<tt><ref id="vfsmount" name="vfsmount"></tt> データ構造体は、<tt><ref 
id="vfsmount" name="vfsmntlist"></tt> からのリンクを外され、解放される。
<newline>[see: remove_vfsmnt(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/fs/super.c" 
name="fs/super.c">]

<!--9.2.8  The VFS Inode Cache-->
<sect2>VFS inode キャッシュ<label id="chapter_fs_sect2-8">

<!--
As the mounted file systems are navigated, their VFS inodes are being
continually read and, in some cases, written. The Virtual File System
maintains an inode cache to speed up accesses to all of the mounted file
systems. Every time a VFS inode is read from the inode cache the system
saves an access to a physical device. 
-->
<p>マウントされたファイルシステムを操作する際には、そのファイルシステム
の VFS inode が何度も読み出されたり、ある場合には書き込まれたりする。
仮想ファイルシステムは、inode キャッシュを管理して、マウントされたすべての
ファイルシステムへのアクセスを高速化している。
VFS inode が inode キャッシュから読み出されたとき、システムは物理デバイスへの
アクセスを省くことができる。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/fs/inode.c" 
name="fs/inode.c">]

<!--
The VFS inode cache is implmented as a hash table whose entries are
pointers to lists of VFS inodes that have the same hash value. The hash value
of an inode is calculated from its inode number and from the device identifier
for the underlying physical device containing the file system. Whenever the
Virtual File System needs to access an inode, it first looks in the VFS inode
cache. To find an inode in the cache, the system first calculates its hash
value and then uses it as an index into the inode hash table. This gives it a
pointer to a list of inodes with the same hash value. It then reads each inode
in turn until it finds one with both the same inode number and the same device
identifier as the one that it is searching for. 
-->
<p>VFS inode キャッシュは、ハッシュテーブルとして実装されていて、そのエントリ
は、同じハッシュ値を持つ VFS inode のリストへのポインタとなっている。inode の
ハッシュ値は、その inode 番号と、ファイルシステムを保持する下位の物理デバイス
のデバイス識別子によって計算される。仮想ファイルシステムが inode にアクセスする
必要があるときは、システムはまずそのハッシュ値を計算し、それを inode ハッシュ
テーブルへのインデックスとして使用する。それによってシステムは、同じハッシュ値
を持つ inode のリストへのポインタを取得する。そして、個々の inode を順番に
読み出して、探している inode と同一の inode 番号とデバイス識別子の両方を
持つ inode を見つける。

<!--
If it can find the inode in the cache, its count is incremented to show that it
has another user and the file system access continues. Otherwise a free VFS
inode must be found so that the file system can read the inode from memory.
VFS has a number of choices about how to get a free inode. If the system
may allocate more VFS inodes then this is what it does; it allocates kernel
pages and breaks them up into new, free, inodes and puts them into the inode
list. All of the system's VFS inodes are in a list pointed at by first_inode
as well as in the inode hash table. If the system already has all of the inodes
that it is allowed to have, it must find an inode that is a good candidate to 
be reused. Good candidates are inodes with a usage count of zero; this 
indicates that the system is not currently using them. Really important VFS 
inodes, for example the root inodes of file systems always have a usage count 
greater than zero and so are never candidates for reuse. Once a candidate for 
reuse has been located it is cleaned up. The VFS inode might be dirty and in 
this case it needs to be written back to the file system or it might be locked
and in this case the system must wait for it to be unlocked before continuing.
The candidate VFS inode must be cleaned up before it can be reused. 
-->
<p>キャッシュに inode が見つかった場合、その inode のカウント値に 1 が足され、
その inode には他にもユーザがいて、ファイルシステムへのアクセスが継続しているこ
とが示される。
見つからない場合、フリーの VFS inode を見つけて、ファイルシステムがメモリから 
inode を読み込めるようにしなければならない。
VFS がフリーの inode を取得する方法は、複数ある。
システムがより多くの VFS inode を割り当ててもよい場合は、VFS は新規の inode を
割り当てる。VFS はカーネルページを割り当てて、そのページを新規のフリー inode に
分割し、それらを inode リストに入れる。システム上の VFS inode はすべて、inode 
ハッシュテーブルにあると同時に、<tt><ref id="first_inode" name="first_inode">
</tt> によってポイントされるリストにも存在する。
システムがすでに使用できるすべての inode を使い切っている場合、システムは再利用
されるのにふさわしい inode の候補を探さなければならない。
候補は、0 の利用カウントを付けられた inode である。これは、システムが現在その 
inode を使用していないことを示している。たとえば、ファイルシステムのルート 
inode のような本当に重要な VFS inode は常に 0 以上の利用カウントを持っている
ので、再利用候補には決してならない。再利用の候補が特定されたら、それは消去
される。VFS inode はダーティー(dirty)になっているかもしれないので、その場合は
ファイルシステムに書き戻される必要があるが、それ以外にもその inode がロックされ
ている場合があり、その際にシステムは処理を継続する前にロックが解除されるのを待
たなければならない。VFS inode の候補は、再利用される前に消去されなければならな
い。

<!--
However the new VFS inode is found, a file system specific routine must be
called to fill it out from information read from the underlying real file 
system. Whilst it is being filled out, the new VFS inode has a usage count of 
one and is locked so that nothing else accesses it until it contains valid 
information. 
-->
<p>新規の VFS inode を見つけ出す方法に関わらず、ファイルシステム固有のルーチン
が呼び出されて、基礎となる実ファイルシステムから読み出された情報でその inode の
フィールドを埋める必要がある。その情報が書き込まれている間、新しい VFS inode 
は、利用カウント 1 を設定され、有効な情報を所持するようになるまでどこからもアク
セスされないようにロックされる。

<!--
To get the VFS inode that is actually needed, the file system may need to
access several other inodes. This happens when you read a directory; only
the inode for the final directory is needed but the inodes for the intermediate
directories must also be read. As the VFS inode cache is used and filled up,
the less used inodes will be discarded and the more used inodes will remain in
the cache. 
-->
<p>実際に必要な VFS inode を見つけだすために、ファイルシステムは他のいくつかの
 inode にアクセスしなければならない場合がある。これが起こるのはディレクトリの
読み込みのときである。最後のディレクトリの inode だけが必要なのだが、その途中
にあるディレクトリの inode も読み込まなければならない。VFS inode キャッシュが
使用され、それが満杯になると、ほとんど使われない inode は破棄され、より利用頻度
の高い inode がキャッシュに残る。

<!--9.2.9  The Directory Cache-->
<sect2>ディレクトリキャッシュ<label id="chapter_fs_sect2-9">

<!--
To speed up accesses to commonly used directories, the VFS maintains a
cache of directory entries. 
As directories are looked up by the real file systems their details are added
into the directory cache. The next time the same directory is looked up, for
example to list it or open a file within it, then it will be found in the 
directory cache. Only short directory entries (up to 15 characters long) are 
cached but this is reasonable as the shorter directory names are the most 
commonly used ones. For example, /usr/X11R6/bin is very commonly accessed
when the X server is running. 
-->
<p>よく利用されるディレクトリへのアクセスを高速化するために、VFS はディレクトリ
エントリのキャッシュを管理している。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/fs/dcache.c" 
name="fs/dcache.c">]<newline>
実ファイルシステムからディレクトリの
問い合わせがあると、それらの詳細がディレクトリキャッシュに入れられる。
たとえばディレクトリを表示させたり、その中のファイルをオープンするといった
同じディレクトリへの問い合わせが続く場合、そのディレクトリはディレクトリ
キャッシュで発見できる。短い(15 文字までの)ディレクトリエントリのみがキャッシュ
されるのだが、短いディレクトリ名が最も頻繁に使われるため、この方法は合理的であ
る。たとえば、<tt>/usr/X11R6/bin</tt> は、X サーバの実行中に、非常に頻繁にアク
セスされる。

<!--
The directory cache consists of a hash table, each entry of which points at a
list of directory cache entries that have the same hash value. The hash
function uses the device number of the device holding the file system and the
directory's name to calculate the offset, or index, into the hash table. It
allows cached directory entries to be quickly found. It is no use having a
cache when lookups within the cache take too long to find entries, or even not
to find them. 
-->
<p>ディレクトリキャッシュはハッシュテーブルから成り、その個々のエントリは、
同じハッシュ値を持つディレクトリキャッシュエントリのリストをポイントしている。
ハッシュ関数は、そのファイルシステムを保持するデバイスのデバイス番号と
ディレクトリ名とを利用して、そのハッシュテーブルへのオフセットとインデックス
とを計算する。それによって、キャッシュされたディレクトリは高速に発見される
ことが可能になる。キャッシュ内でのエントリ検索の問い合わせに時間がかかりすぎ
たり、エントリを見つけられないようなキャッシュでは意味がない。

<!--
In an effort to keep the caches valid and up to date the VFS keeps lists of
Least Recently Used (LRU) directory cache entries. When a directory entry
is first put into the cache, which is when it is first looked up, it is added 
onto the end of the first level LRU list. In a full cache this will displace 
an existing entry from the front of the LRU list. As the directory entry is 
accessed again it is promoted to the back of the second LRU cache list. Again,
this may displace a cached level two directory entry at the front of the level
two LRU cache list. This displacing of entries at the front of the level one 
and level two LRU lists is fine. The only reason that entries are at the front
of the lists is that they have not been recently accessed. If they had, they 
would be nearer the back of the lists. The entries in the second level LRU 
cache list are safer than entries in the level one LRU cache list. This is the
intention as these entries have not only been looked up but also they have 
been repeatedly referenced. 
-->
<p>キャッシュを有効かつ最新に保つために、VFS は最長時間未使用( Least Recently 
Used, LRU)のディレクトリキャッシュエントリのリストを保持している。ディレクト
リが問い合わせを受けて、そのディレクトリのエントリが初めてキャッシュに入れら
れるとき、それは第一レベルの LRU リストの末尾に付け加えられる。キャッシュが
満杯の場合は、その LRU リストの先頭に存在するエントリを削除することで付け加え
られる。
ディレクトリエントリが再度アクセスされると、それは第二レベルの LRU キャッシュ
の末尾に入れられる。これが満杯の場合も同様に、第二レベルの LRU キャッシュリスト
の先頭にあるディレクトリエントリと入れ替わる形となる。第一レベルと第二レベルの 
LRU リストの先頭にあるエントリを立ち退かせるという方法は妥当である。リストの
先頭にエントリがあることの唯一の理由は、それらが最近アクセスされていないという
ことだからである。アクセスがあれば、リストの後尾近くに移る。第二レベルの LRU 
キャッシュリストにあるエントリは、第一レベルの LRU キャッシュリストにあるエント
リよりも安全である。なぜなら、第二レベルにあるエントリは、問い合わせを受けた
だけでなく、繰り返し参照されているからである。

REVIEW NOTE: Do we need a diagram for this? 

<!--9.3  The Buffer Cache-->
<sect1>バッファキャッシュ<label id="chapter_fs_sect3">
<p>

<label id="figure9-7">
<!--                  Figure 9.7: The Buffer Cache-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure9-7.gif">
</figure>
</#if>
<#unless output="html">
<verb>
                           buffer_head            buffer_head
hash_table +---------+    +-----------+          +-----------+
---------->|         | +->| b_dev     |0x0301 +->| b_dev     |0x0801
           |         | |  |-----------|       |  |-----------|
           |         | |  | b_blocknr |42   +-+  | b_blocknr |17
           |         | |  |-----------|     |    |-----------|
           |         | |  | b_state   |     |    | b_state   |
           |---------| |  |-----------|     |    |-----------|
           |         |-+  | b_count   |     |    | b_count   |
           |---------|    |-----------|     |    |-----------|
           |         |    | b_size    |1024 |    | b_size    |2048
           |         |    |-----------|     |    |-----------|
           |         |    |           |     |    |           |
           |         |    |           |     |    |           |
           |         |    |-----------|     |    |-----------|
           |         |    | b_next    |-----+    | b_next    |
           |         |    |-----------|          |-----------|
           |         |    | b_prev    |          | b_prev    |
           |         |    |-----------|          |-----------|
           |         |    |           |          |           |
           |         |    |-----------|          |-----------|
           |         |    | b_data    |          | b_data    |
           |         |    +-----------+          +-----------+
           |         |
           |         |     buffer_head
           |         |    +-----------+
           |         | +->| b_dev     |0x0301
           |---------| |  |-----------|
           |         |-+  | b_blocknr |39
           |---------|    |-----------|
           |         |    | b_state   |
           |---------|    |-----------|
           ~         ~    ~           ~
           ~         ~    ~           ~
</verb>
</#if>
<p>図表(9.7) バッファキャッシュ

<!--
As the mounted file systems are used they generate a lot of requests to the
block devices to read and write data blocks. All block data read and write
requests are given to the device drivers in the form of buffer_head data
structures via standard kernel routine calls. These give all of the information
that the block device drivers need; the device identifier uniquely identifies 
the device and the block number tells the driver which block to read. All block
devices are viewed as linear collections of blocks of the same size. To speed
up access to the physical block devices, Linux maintains a cache of block
buffers. All of the block buffers in the system are kept somewhere in this
buffer cache, even the new, unused buffers. This cache is shared between all
of the physical block devices; at any one time there are many block buffers in
the cache, belonging to any one of the system's block devices and often in
many different states. If valid data is available from the buffer cache this
saves the system an access to a physical device. Any block buffer that has
been used to read data from a block device or to write data to it goes into the
buffer cache. Over time it may be removed from the cache to make way for a
more deserving buffer or it may remain in the cache as it is frequently
accessed. 
-->
<p>マウントされたファイルシステムが利用される場合、ファイルシステムはデータ
ブロックを読み書きするためにブロックデバイスに対する多くのリクエストを行う。
データブロックの読み書きするためのリクエストはすべて、標準のカーネルルーチン
の呼び出しを経由して、<tt><ref id="buffer_head" name="buffer_head"></tt> データ
構造体で定義されたデバイスドライバに渡される。
この構造体はブロックデバイスドライバに必要なすべての情報を提供する。
デバイス識別子は固有のデバイスを識別し、ブロック番号はドライバにどのブロックを
読み出すべきかを示す。すべてのブロックデバイスは、同一サイズのブロックの
線形的な集合であると見看される。物理ブロックデバイスへのアクセスをスピード
アップするために、Linux はブロックバッファのキャッシュを管理する。
システム上の
すべてのブロックバッファは、使用されていない新しいバッファでさえ、このバッファ
キャッシュのどこかに保存される。このキャッシュはすべての物理ブロックデバイス
間で共有される。どのような時にもそのキャッシュには多くのブロックバッファが
ある。それらはシステムのブロックデバイスのひとつに属していて、しばしば種々の
異なる状態(<tt><ref id="buffer_head" name="state"></tt>)にある。
有効なデータがバッファキャッシュから入手可能な場合、
それによってシステムが物理デバイスにアクセスする手間が省かれる。ブロック
デバイスに対する読み込みや書き出しで使用されたブロックバッファはすべて、
バッファキャッシュに入れられる。時間の経過によって、それらは、より必要性の高い
バッファと交代するためにキャッシュから削除されるか、頻繁にアクセスされるため
キャッシュに残るかする。

<!--
Block buffers within the cache are uniquely identfied by the owning device
identifier and the block number of the buffer. The buffer cache is composed of
two functional parts. The first part is the lists of free block buffers. There
is one list per supported buffer size and the system's free block buffers are
queued onto these lists when they are first created or when they have been
discarded. The currently supported buffer sizes are 512, 1024, 2048, 4096 and
8192 bytes. The second functional part is the cache itself. This is a hash 
table which is a vector of pointers to chains of buffers that have the same 
hash index. The hash index is generated from the owning device identifier and 
the block number of the data block. Figure  9.7 shows the hash table together
with a few entries. Block buffers are either in one of the free lists or they 
are in the buffer cache. When they are in the buffer cache they are also queued
onto Least Recently Used (LRU) lists. There is an LRU list for each buffer
type and these are used by the system to perform work on buffers of a type,
for example, writing buffers with new data in them out to disk. The buffer's
type reflects its state and Linux currently supports the following types: 
-->
<p>キャッシュ内のブロックバッファは、それを保持するデバイスの識別子とバッファ
のブロック番号とによってユニークに識別される。バッファキャッシュはふたつの
機能別部分から構成される。最初の部分は、空のブロックバッファのリストである。
サポートされるバッファサイズごとにひとつのリストがあり、システム上の空のブロッ
クバッファは、初めて作成されたり、削除されたときに、それらのリスト上の待ち行列
に置かれる。現在サポートされているバッファサイズは、512, 1024, 2048, 4096, 
そして 8192 バイトである。第二の部分は、キャッシュそのものである。これは
ハッシュテーブルであり、そのハッシュテーブルは同じハッシュインデックスを持つ
バッファに対するポインタの配列である。ハッシュのインデックスは、該当
ブロックを保持するデバイスの識別子とデータブロックのブロック番号から生成され
る。<ref id="figure9-7" name="図表(9.7)">では、ハッシュテーブルがいくつかの
エントリとともに示されている。
ブロックバッファはフリーリストのいずれかひとつにあるか、バッファキャッシュの
中に存在する。バッファキャッシュにあるときは、それらは最長時間未使用(LRU)
リスト上のキューにも置かれる。LRU リストは個々のタイプのバッファごとに存在し、
システムがそのタイプのバッファ上で処理をする際、たとえば、バッファ内の新しい
データをディスクに書き出す際などに使用される。バッファタイプとはその状態
(state)を反映するものであり、Linux では現在次のようなタイプがサポートされて
いる。

<!--
clean Unused, new buffers, 
locked Buffers that are locked, waiting to be written, 
dirty Dirty buffers. These contain new, valid data, and will be written but
      so far have not been scheduled to write, 
shared Shared buffers, 
unshared
      Buffers that were once shared but which are now not shared, 
-->
<descrip>
<tag>クリーン (clean)</tag>
未使用で新しいバッファ

<tag>ロック済み (locked)</tag>
ロックされ、書き込まれるのを待つバッファ。

<tag>ダーティ (dirty)</tag>
ダーティバッファ。それには新しい有効なデータが含まれ、書き込みがされる予定
だが、今のところ書き込みのスケジュールが回って来ていないもの。

<tag>共有 (shared)</tag>
共有バッファ。

<tag>非共有 (unshared)</tag>
以前は共有であったが、現在は共有されていないバッファ。
</descrip>

<!--
Whenever a file system needs to read a buffer from its underlying physical
device, it trys to get a block from the buffer cache. If it cannot get a buffer
from the buffer cache, then it will get a clean one from the appropriate sized
free list and this new buffer will go into the buffer cache. If the buffer 
that it needed is in the buffer cache, then it may or may not be up to date. 
If it is not up to date or if it is a new block buffer, the file system must 
request that the device driver read the appropriate block of data from the 
disk. 
-->
<p>ファイルシステムは、基礎となる物理デバイスからバッファを読み出す必要が
あるときには、バッファキャッシュからブロックを取得しようとする。
バッファキャッシュから取得できない場合、適切なサイズのフリーリストから
未使用バッファを取得し、その新しいバッファがバッファキャッシュに入る。
ファイルシステムが必要とするバッファがバッファキャッシュにある場合、バッファは
更新(update)されている場合とされていない場合がある。更新されていないか、それが
未使用ブロックバッファである場合は、ファイルシステムは、デバイスドライバによっ
て適切なデータブロックがディスクから読み出されるようリクエストする。

<!--
Like all caches, the buffer cache must be maintained so that it runs 
efficiently and fairly allocates cache entries between the block devices using
the buffer cache. Linux uses the bdflush kernel daemon to perform a lot of 
housekeeping duties on the cache but some happen automatically as a result of 
the cache being used. 
-->
<p>すべてのキャッシュと同様に、バッファキャッシュは、効率よく実行され、バッファ
キャッシュを利用するブロックデバイス間で公平にキャッシュエントリが割り当てられ
るように管理されなければならない。Linux は <tt>bdflush</tt> カーネルデーモン
を使用して、キャッシュに関する多くの細かな作業を実行しているが、それらのいく
つかは、キャッシュが使用された結果として自動的に実行される。

<!--9.3.1  The bdflush Kernel Daemon-->
<sect2>bdflush カーネルデーモン<label id="chapter_fs_sect3-1">

<!--
The bdflush kernel daemon is a simple kernel daemon that provides a
dynamic response to the system having too many dirty buffers; buffers that
contain data that must be written out to disk at some time. It is started as a
kernel thread at system startup time and, rather confusingly, it calls itself
``kflushd'' and that is the name that you will see if you use the ps command
to show the processes in the system. Mostly this daemon sleeps waiting for
the number of dirty buffers in the system to grow too large. As buffers are
allocated and discarded the number of dirty buffers in the system is checked.
If there are too many as a percentage of the total number of buffers in the
system then bdflush is woken up. The default threshold is 60% but, if the
system is desperate for buffers, bdflush will be woken up anyway. This
value can be seen and changed using the update command: 
-->
<p><tt>bdflush</tt> カーネルデーモンは、システムがダーティ(dirty, 更新待ち)
バッファを多く持ちすぎている場合に、システムに対して動的に反応するシンプルな
カーネルデーモンである。
<newline>[see: bdflush(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/fs/buffer.c" 
name="fs/buffer.c">]<newline>
データを保持するバッファは、時々ディスクへと書き戻さなければならない。
そのデーモンは、起動時にはシステム上のカーネルスレッドとして起動される。少し
ややこしいのだが、それは "<tt>kflush</tt>" と呼ばれ、その名前は、システム上の
プロセスを表示する <tt>ps</tt> コマンドを使うと見ることができる。
たいていこのデーモンはスリープ状態で、システム上のダーティバッファの数が多く
なりすぎるのを待っている。バッファが割り当てられたり破棄されたりすると、システ
ム上のダーティバッファの数がチェックされる。システム上のバッファの総数のパーセ
ンテージとしてダーティバッファが多くなりすぎると、<tt>bdflush</tt> は目を覚ま
す。デフォルトの境界線は 60% だが、システムがバッファの不足で困っている場合は、
<tt>bdflush</tt> は強制的に目覚めされられる。この値は、<tt>update</tt> コマンド
を使って確認や変更が可能である。

<verb>
# update -d

bdflush version 1.4
0:    60 Max fraction of LRU list to examine for dirty blocks
1:   500 Max number of dirty blocks to write each time bdflush activated
2:    64 Num of clean buffers to be loaded onto free list by refill_freelist
3:   256 Dirty block threshold for activating bdflush in refill_freelist
4:    15 Percentage of cache to scan for free clusters
5:  3000 Time for data buffers to age before flushing
6:   500 Time for non-data (dir, bitmap, etc) buffers to age before flushing
7:  1884 Time buffer cache load average constant
8:     2 LAV ratio (used to determine threshold for buffer fratricide).
</verb>

<!--
All of the dirty buffers are linked into the BUF_DIRTY LRU list whenever
they are made dirty by having data written to them and bdflush tries to
write a reasonable number of them out to their owning disks. Again this
number can be seen and controlled by the update command and the default is
500 (see above). 
-->
<p>データを書き込まれて更新待ち状態になり、<tt>bdflush</tt> が合理的な数の
ダーティバッファをディスクに書き戻そうとする場合はいつも、ダーティバッファの
すべてが、<tt><ref id="buffer_head" name="BUF_DIRTY"></tt> LRU リストにリンク
される。この数も確認可能であり、<tt>update</tt> コマンドによって制御できる。
デフォルト値は 500 である。(上記を参照)

<!--9.3.2  The update Process-->
<sect2> update プロセス<label id="chapter_fs_sect3-2">

<!--
The update command is more than just a command; it is also a daemon. When
run as superuser (during system initialisation) it will periodically flush all
of the older dirty buffers out to disk. It does this by calling a system 
service routine that does more or less the same thing as bdflush. Whenever a 
dirty buffer is finished with, it is tagged with the system time that it 
should be written out to its owning disk. Every time that update runs it looks
at all of the dirty buffers in the system looking for ones with an expired 
flush time. Every expired buffer is written out to disk. 
-->
<p><tt>update</tt> コマンドは単なるコマンドではなく、デーモンでもある。
(システム初期化の際に)スーパーユーザ権限で起動されると、それは定期的に
古くなったダーティバッファのすべてをディスクに書き戻す(フラッシュする)。
これが実行される際には、<tt>bdflush</tt> と似通ったシステムサービスルーチン
が呼び出される。
<newline>[see: sys_bdflush(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/fs/buffer.c" 
name="fs/buffer.c">]<newline>
ダーティバッファは(システムサービスルーチン)終了時に、元のディスクに書き戻す
ため、システム時間が(バッファの構造体に)付け加えられる。<tt>update</tt> コマン
ドが実行されるときは、いつも、システム上のダーティバッファすべてを検査し、
フラッシュすべき時刻を過ぎているものを探す。フラッシュすべき時刻をすぎた
すべてのバッファは、ディスクに書き戻される。

<!--9.4  The /proc File System-->
<sect1>/proc ファイルシステム<label id="chapter_fs_sect4">

<!--
The /proc file system really shows the power of the Linux Virtual File
System. It does not really exist (yet another of Linux's conjuring tricks),
neither the /proc directory nor its subdirectories and its files actually 
exist. So how can you cat /proc/devices? The /proc file system, like a real 
file system, registers itself with the Virtual File System. However, when the 
VFS makes calls to it requesting inodes as its files and directories are 
opened, the /proc file system creates those files and directories from 
information within the kernel. For example, the kernel's /proc/devices file is
generated from the kernel's data structures describing its devices. 
-->
<p><tt>/proc</tt> ファイルシステムは、Linux の仮想ファイルシステムの能力を
如実に示すものである。そのファイルシステムは実在しない。(これも、Linux の魔術
のひとつである。) <tt>/proc</tt> ディレクトリも、そのサブディレクトリも、
その中のファイルも実在しない。では、どうして <tt>cat /proc/devices</tt> という
コマンドを実行できるのか？ <tt>/proc</tt> ファイルシステムは、実ファイル
システムと同様に、仮想ファイルシステムに登録されている。しかし、VFS が 
<tt>/proc</tt> ファイルシステムを呼び出して、そのファイルやディレクトリを
オープンするために inode をリクエストしたときに、 <tt>/proc</tt> ファイル
システムは、カーネル内の情報からそのファイルやディレクトリを(動的に)作成する。
たとえば、カーネルの <tt>/proc/devices</tt> ファイルはそのデバイスを記述する
カーネルのデータ構造体から生成されている。

<!--
The /proc file system presents a user readable window into the kernel's
inner workings. Several Linux subsystems, such as Linux kernel modules
described in chapter  modules-chapter, create entries in the the /proc file
system. 
-->
<p><tt>/proc</tt> ファイルシステムは、カーネル内部の実行状態への窓を、ユーザ
が読みとれるような形で提供する。Linux カーネルモジュール(<ref 
id="chapter_m" name="「モジュール」">の章を参考)のような Linux サブシステムの
いくつかは、<tt>/proc</tt> ファイルシステム内にエントリを作成している。

<!--9.5  Device Special Files-->
<sect1>デバイススペシャルファイル<label id="chapter_fs_sect5">

<!--
Linux, like all versions of Unix TM presents its hardware devices as special
files. So, for example, /dev/null is the null device. A device file does not 
use any data space in the file system, it is only an access point to the device
driver. The EXT2 file system and the Linux VFS both implement device files
as special types of inode. There are two types of device file; character and
block special files. Within the kernel itself, the device drivers implement 
file semantices: you can open them, close them and so on. Character devices
allow I/O operations in character mode and block devices require that all I/O
is via the buffer cache. When an I/O request is made to a device file, it is
forwarded to the appropriate device driver within the system. Often this is not
a real device driver but a pseudo-device driver for some subsystem such as
the SCSI device driver layer. Device files are referenced by a major number,
which identifies the device type, and a minor type, which identifies the unit,
or instance of that major type. For example, the IDE disks on the first IDE
controller in the system have a major number of 3 and the first partition of an
IDE disk would have a minor number of 1. So, ls -l of /dev/hda1 gives: 
-->
<p>Linux は、Unix のあらゆるバージョンと同様に、ハードウェアデバイスをスペ
シャルファイルで表現している。たとえば、<tt>/dev/null</tt> はヌル(null)デバイス
である。デバイスファイルはシステム上のデータ空間を使用しない。それは、単なる
デバイスドライバへのアクセスポイントである。EXT2 ファイルシステムと Linux VFS 
はどちらもデバイスドライバを特別なタイプの inode として実装している。デバイス
ファイルには、キャラクタスペシャルファイルとブロックスペシャルファイルの
二種類がある。
カーネル自体の内部で、デバイスドライバによるそうしたファイルのオープンや
クローズといった、ファイル操作の意味が定義されている。
キャラクタデバイスでは、キャラクタモードでの I/O 操作が可能であり、ブロック
デバイスではすべての I/O 操作がバッファ経由で行われるよう要求される。
デバイスファイルに対する I/O リクエストがなされると、そのリクエストはシステム
上の適切なデバイスドライバに送られる。これはしばしば実際のドライバでなく、
SCSI デバイスドライバ層といったあるサブシステムの疑似デバイス(pseudo-device)
ドライバである場合がある。デバイスファイルは、デバイスタイプを識別するメジャー
番号と、同じメジャー番号の中での実際のユニット(unit)もしくはインスタンス
(instance)を識別するマイナー番号とで参照される。
たとえば、システム上の最初の IDE ディスクコントローラ上にある IDE ディスクは、
メジャー番号 3 であり、IDE ディスクの最初のパーティションはマイナー番号 1 と
なる。したがって、<tt>/dev/hda1</tt> の <tt>ls -l</tt> の結果は次のようになる。
<newline>[see: Linux の全メジャー番号については、<htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/major.h" 
name="include/linux/major.h">]<newline>

<verb>
$ ls -l /dev/hda1
brw-rw----   1 root    disk       3,    1  Nov 24  15:09 /dev/hda1
</verb>

<!--
Within the kernel, every device is uniquely described by a kdev_t data type,
this is two bytes long, the first byte containing the minor device number and
the second byte holding the major device number. 
The IDE device above is held within the kernel as 0x0301. An EXT2 inode
that represents a block or character device keeps the device's major and
minor numbers in its first direct block pointer. When it is read by the VFS, 
the VFS inode data structure representing it has its i_rdev field set to the
correct device identifier. 
-->
<p>カーネル内部では、すべてのデバイスが <tt><ref id="kdev_t" name="kdev_t">
</tt> データタイプによってユニークに記述される。このデータは 2 バイト長であり、
最初のバイトにはデバイスのマイナー番号が含まれ、二番目のバイトにはメジャー番号
が保持されている。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/kdev_t.h" 
name="include/linux/kdev_t.h">]<newline>
上記の IDE デバイスは、カーネル内の 0x0301 に保持されている。ブロックデバイス
やキャラクタデバイスを表す EXT2 <tt><ref id="ext2_inode" name="inode"></tt> 
は、デバイスのメジャー番号とマイナー番号を、ブロックを直接ポイントする(配列の)
先頭のポインタに保持している。
それが VFS によって読み出されるとき、それを表す VFS <tt><ref id="inode" 
name="inode"></tt> データ構造体は、<tt><ref id="inode" name="i_rdev"></tt> 
フィールドに正しいデバイス識別子を設定する。

<!--
Footnotes:

1 Well, not knowingly, although I have been bitten by operating systems with
more lawyers than Linux has developers 
-->
<label id="chapter_fs_fn">
<footnote>
(脚注 1): Linux には、大勢の開発者がいる。いくつかのオペレーティングシステムに
は、もっと大勢の弁護士がいるらしい。
</footnote>

<!--第 11 章 ネットワーク-->
<!--Chapter 10 Networks-->
<sect>ネットワーク<label id="chapter_net">
<p>
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/penguin2.gif">
</figure>

<!--
Networking and Linux are terms that are almost synonymous. In a very real
sense Linux is a product of the Internet or World Wide Web (WWW). Its
developers and users use the web to exchange information ideas, code, and
Linux itself is often used to support the networking needs of organizations.
This chapter describes how Linux supports the network protocols known
collectively as TCP/IP. 
-->
<p>ネットワーキングと Linux とはほとんど同義語である。本当の意味で、Linux は
インターネットもしくは World Wide Web(WWW) の産物である。開発者やユーザたち
はウェブを使って情報やアイデアやコードを交換しているし、Linux そのものが組織に
おけるネットワークへの要求を満たすために利用されている。この章では、TCP/IP と
総称されるネットワークプロトコルを Linux がどのようにサポートしているかを
解説する。

<!--
The TCP/IP protocols were designed to support communications between
computers connected to the ARPANET, an American research network
funded by the US government. The ARPANET pioneered networking
concepts such as packet switching and protocol layering where one protocol
uses the services of another. ARPANET was retired in 1988 but its
successors (NSF1 NET and the Internet) have grown even larger. What is
now known as the World Wide Web grew from the ARPANET and is itself
supported by the TCP/IP protocols. Unix TM was extensively used on the
ARPANET and the first released networking version of Unix TM was 4.3
BSD. Linux's networking implementation is modeled on 4.3 BSD in that it
supports BSD sockets (with some extensions) and the full range of TCP/IP
networking. This programming interface was chosen because of its
popularity and to help applications be portable between Linux and other Unix
TM platforms. 
-->
<p>TCP/IP プロトコルが設計されたのは、ARPANET に接続されたコンピュータ間
での通信をサポートするためであった。合衆国政府によって設立されたアメリカ
の研究用ネットワークである ARPANET は、ネットワークの基本概念を作り出した
パイオニアであり、その中には、パケットスイッチング(packet switching)や、ある
プロトコルが別のプロトコルのサービスを利用するというプロトコル層(protocol 
layer)といった概念がある。
ARPANET は 1988 年に解散されたが、その後継者(NSF(<ref id="chapter_net_fn" 
name="脚注 1">) NET やインターネット)はそれ以上のものに成長した。
今日 World Wide Web と呼ばれるものは、ARPANET から発展しており、それ自体が 
TCP/IP プロトコルによってサポートされている。Unix は ARPANET 上で広範囲に
使用されが、最初にリリースされたネットワークバージョンの Unix は 4.3 BSD 
であった。Linux におけるネットワークの実装は、(いくつかの拡張機能とともに)BSD 
ソケットと TCP/IP 全般をサポートしている点で、4.3 BSD をモデルとするものであ
る。BSD ソケットというプログラミングインターフェイスが
採用されたのは、その人気ゆえであり、Linux とその他の Unix プラットフォーム間
でのアプリケーションの移植を容易にするためであった。

<!--10.1  An Overview of TCP/IP Networking-->
<sect1>TCP/IP ネットワーキングの概要<label id="chapter_net_sect1">

<!--
This section gives an overview of the main principles of TCP/IP networking.
It is not meant to be an exhaustive description, for that I suggest that you
read . In an IP network every machine is assigned an IP address, this is a 32
bit number that uniquely identifies the machine. The WWW is a very large,
and growing, IP network and every machine that is connected to it has to
have a unique IP address assigned to it. IP addresses are represented by
four numbers separated by dots, for example, 16.42.0.9. This IP address
is actually in two parts, the network address and the host address. The
sizes of these parts may vary (there are several classes of IP addresses)
but using 16.42.0.9 as an example, the network address would be 16.42
and the host address 0.9. The host address is further subdivided into a
subnetwork and a host address. Again, using 16.42.0.9 as an example,
the subnetwork address would be 16.42.0 and the host address 16.42.0.9.
This subdivision of the IP address allows organizations to subdivide their
networks. For example, 16.42 could be the network address of the ACME
Computer Company; 16.42.0 would be subnet 0 and 16.42.1 would be
subnet 1. These subnets might be in separate buildings, perhaps connected
by leased telephone lines or even microwave links. IP addresses are
assigned by the network administrator and having IP subnetworks is a good
way of distributing the administration of the network. IP subnet
administrators are free to allocate IP addresses within their IP subnetworks.
-->
<p>この章では、TCP/IP ネットワーキングにおける基本原則を概説する。
しかし、本書のテーマからして、徹底した記述というわけではない。
IP ネットワークでは、すべてのマシンが IP アドレスを割り当てられる。これはマシン
をユニークに識別する 32 ビットの数である。WWW は広大で今も成長過程にあり、そ
れに接続された IP ネットワークとすべてのマシンはユニークな IP アドレスを割り当
てられなければならない。
IP アドレスは、たとえば 16.42.0.9 のようにドットで区切られた 4 つの
数字で表現される。この IP アドレスは実際には、ネットワークアドレスとホスト
アドレスのふたつの部分に分かれる。( IP アドレスにはいくつかのクラスがあるので)
それらの部分のサイズは定まっていないが、仮に 16.42.0.9 を例に取り、ネットワー
クアドレスを 16.42 とし、ホストアドレスを 0.9 であるとする。ホストアドレスは
さらにサブネットとホストアドレスとに再分割できる。ここでも 16.42.0.9 を例に
取ると、サブネットアドレスは 16.42.0 であり、ホストアドレスは 9 となるだろう。
IP アドレスの細分化により、組織はネットワークを再分割できる。
たとえば、16.42 が ACME コンピュータ会社のネットワークアドレスであるとすると、
16.42.0 はサブネット 0 であり、16.42.1 はサブネット 1 となる。これらのサブ
ネットは、異なる建物の中にあり、おそらく専用線かもしくは無線によっ
て接続されているだろう。IP アドレスはネットワーク管理者によって割り当てられる
ので、IP サブネットを持つことはネットワーク管理を分散するよい方法である。IP 
サブネットの管理者は、その IP サブネットワーク内で自由に IP アドレスを割り当
てることができるからである。

<!--
Generally though, IP addresses are somewhat hard to remember. Names are
much easier. linux.acme.com is much easier to remember than
16.42.0.9 but there must be some mechanism to convert the network
names into an IP address. These names can be statically specified in the
/etc/hosts file or Linux can ask a Distributed Name Server 
(DNS server) to resolve the name for it. In this case the local host must
know the IP address of one or more DNS servers and these are specified in
/etc/resolv.conf. 
-->
<p>しかし、一般的に IP アドレスは覚えるのがやや困難である。名前のほうがより
簡単であり、linux.acme.com のほうが 16.42.0.9 よりもずっと覚えやすい。だが、
ネットワーク名を IP アドレスに変換するには多少の仕組みが必要となる。そうした
名前は、<tt>/etc/hosts</tt> ファイル内で静的に指定できるが、Linux は、
DNS (Domain Name System) サーバに問い合わせて、名前を IP アドレスに
変換することもできる。その場合、ローカルホストはひとつ以上の DNS サーバの IP 
アドレスを知る必要があり、それは <tt>/etc/resolv.conf</tt> で指定される。


<!--
Whenever you connect to another machine, say when reading a web page,
its IP address is used to exchange data with that machine. This data is
contained in IP packets each of which have an IP header containing the IP
addresses of the source and destination machine's IP addresses, a
checksum and other useful information. The checksum is derived from the
data in the IP packet and allows the receiver of IP packets to tell if the IP
packet was corrupted during transmission, perhaps by a noisy telephone
line. The data transmitted by an application may have been broken down into
smaller packets which are easier to handle. The size of the IP data packets
varies depending on the connection media; ethernet packets are generally
bigger than PPP packets. The destination host must reassemble the data
packets before giving the data to the receiving application. You can see this
fragmentation and reassembly of data graphically if you access a web page
containing a lot of graphical images via a moderately slow serial link. 
-->
<p>ウェブページを読む時などに他のマシンに接続する際はいつも、相手のマシンとの
データ交換に IP アドレスが使用される。このデータは IP パケットに含まれていて、
個々のパケットは、送信元の IP アドレスと送信先の IP アドレス、チェックサム
その他の情報を含んだ IP ヘッダを持っている。チェックサムは IP パケットの
データから導き出されるもので、それによって、おそらく電話回線上のノイズなどで、
転送中に IP パケットが壊れなかったかどうかを IP パケットの受信者が判断できる
ようになる。アプリケーションによって送信されるデータは、処理しやすいように、
より小さなパケットへと分割される。IP データパケットのサイズは接続
メディアによって異なり、イーサネットパケットは一般に PPP パケットよりも
サイズが大きい。送信先のホストはそのデータパケットを組み立て直して、それを受信
すべきアプリケーションに渡さなければならない。多くのグラフィックイメージを
含むウェブページに比較的低速なシリアル回線経由でアクセスする場合、このデータ
の分割と統合の過程を視覚的に理解することができる。

<!--
Hosts connected to the same IP subnet can send IP packets directly to each
other, all other IP packets will be sent to a special host, a gateway.
Gateways (or routers) are connected to more than one IP subnet and they
will resend IP packets received on one subnet, but destined for another
onwards. For example, if subnets 16.42.1.0 and 16.42.0.0 are
connected together by a gateway then any packets sent from subnet 0 to
subnet 1 would have to be directed to the gateway so that it could route
them. The local host builds up routing tables which allow it to route IP
packets to the correct machine. For every IP destination there is an entry in
the routing tables which tells Linux which host to send IP packets to in
order that they reach their destination. These routing tables are dynamic and
change over time as applications use the network and as the network
topology changes. 
-->
<p>同一の IP サブネットに接続されたホスト間ではお互いに直接 IP パケットを送信
することができるが、それ以外のすべてのパケットは特別なホストであるゲートウェイ
(gateway)に送信される。ゲートウェイ(あるいはルータ(router))は、複数の IP 
サブネットに接続されていて、あるサブネット上で受信した IP パケットが、別のサブ
ネット宛であった場合に、その IP パケットを送信先に向けて送りなおす。
たとえば、サブネット 16.42.1.0 と 16.42.0.0 がゲートウェイに
よって接続されている場合、サブネット 0 からサブネット 1 へと送信されるパケット
は、ルーティングが可能なゲートウェイに送られなければならない。ローカルホスト
はルーティングテーブルを設定し、それによって正しいマシンに IP パケットを
経路付けすることができる。すべての IP の送信先に関して、ルーティングテーブル
内にひとつのエントリがある。Linux は、それを参照することで、どのホストに送れば
よいかを判断して、IP パケットを宛先に届けている。
これらのルーティングテーブルは、複数のアプリケーションがネットワークを使用した
り、ネットワークトポロジーが変更された場合など、時間の経過によって動的に変化す
る。

<label id="figure10-1">
<!--               Figure 10.1: TCP/IP Protocol Layers-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure10-1.gif">
</figure>
</#if>
<#unless output="html">
<verb>
                     イーサネットフレーム
+----+------------+------------+------+---------//---+----------+
|PRE |送信先      |送信元      |プロ  |              |フレーム  |
|など|イーサネット|イーサネット|トコ  |    データ    |チェック  |
|    |アドレス    |アドレス    |ル    |              |シーケンス|
+----+------------+------------+------+---------//---+----------+
                                      |              |
+-------------------------------------+              +-----------+
|/                                                               |/
*                      IP データグラム                           *
+-+-+--------+-+-+-+------+--------+--------+--------+-------//--+
| | |パケット| | | |プロト|チェック|送信元  |送信先  |           |
| | |長      | | | |コル  |サム    |IP      |IP      |  データ   |
| | |        | | | |      |        |アドレス|アドレス|           |
+-+-+--------+-+-+-+------+--------+--------+--------+-------//--+
                                                     |           |
          +------------------------------------------+           |
          |/                                                     |/
          *                  TCP セグメント                      *
          +--------+--------+----------+----+-+-+---------//-----+
          |送信元  |送信先  |シーケンス|ACK | | |                |
          |TCP     |TCP     |番号      |番号| | |    データ      |
          |アドレス|アドレス|          |    | | |                |
          +--------+--------+----------+----+-+-+---------//-----+
</verb>
</#if>
<p>図表(10.1) TCP/IP プロトコル層

<!--
The IP protocol is a transport layer that is used by other protocols to carry
their data. The Transmission Control Protocol (TCP) is a reliable end to end
protocol that uses IP to transmit and receive its own packets. Just as IP
packets have their own header, TCP has its own header. TCP is a
connection based protocol where two networking applications are connected
by a single, virtual connection even though there may be many subnetworks,
gateways and routers between them. TCP reliably transmits and receives
data between the two applications and guarantees that there will be no lost
or duplicated data. When TCP transmits its packet using IP, the data
contained within the IP packet is the TCP packet itself. The IP layer on each
communicating host is responsible for transmitting and receiving IP packets.
User Datagram Protocol (UDP) also uses the IP layer to transport its
packets, unlike TCP, UDP is not a reliable protocol but offers a datagram
service. 
This use of IP by other protocols means that when IP packets are
received the receiving IP layer must know which upper protocol layer to give
the data contained in this IP packet to. To facilitate this every IP packet
header has a byte containing a protocol identifier. When TCP asks the IP
layer to transmit an IP packet , that IP packet's header states that it
contains a TCP packet. The receiving IP layer uses that protocol identifier to
decide which layer to pass the received data up to, in this case the TCP
layer. When applications communicate via TCP/IP they must specify not
only the target's IP address but also the port address of the application. A
port address uniquely identifies an application and standard network
applications use standard port addresses; for example, web servers use port
80. These registered port addresses can be seen in /etc/services. 
-->
<p>IP(Internet Protocol) プロトコルは、他のプロトコルがデータを運ぶために利用
する、転送のための層(layer)である。TCP (Transmission Control Protocol)は、エン
ドシステム間における信頼性のあるプロトコルで、自己のパケットを送受信するために 
IP を使用する。
IP が独自のヘッダを持つように、TCP も独自のヘッダを持つ。TCP はコネクション
(connection)に基づくプロトコルなので、両端のアプリケーションは、間に多くの
サブネットワークやゲートウェイ、ルータがある場合でも、単一の仮想的コネクション
によって接続される。TCP はふたつのアプリケーション間で信頼性をもってデータ
の受け渡しを行うので、データの喪失や重複が生じないことが保証される。TCP が IP 
を利用してパケットを転送するとき、IP パケット内に含まれるデータは TCP パケット
そのものである。
個々の通信ホスト上で IP 層は、IP パケットの送受信に関して責任を持つ。
UDP (User Datagram Protocol)も IP 層を使用して自分のパケットを転送するが、
TCP と異なり、UDP は信頼性のあるプロトコルではなく、単にデータグラム(datagram)
サービスを提供するだけである。
このように、IP は、他のプロトコルによって利用されている。したがって、IP パケッ
トを受け取った際、受信した IP 層は、どの上位プロトコル層に対してその IP パケッ
トに含まれるデータを渡すべきか認識できなければならない。これを簡単に実現するた
めに、すべての IP ヘッダには、プロトコル識別子が記述された 1 バイトの情報があ
る。TCP が IP 層に IP パケットの送信を依頼するとき、IP パケットのヘッダには、
そのパケットが TCP パケットを含むものであることを伝える情報が記述される。
受信した IP 層は、そのプロトコル識別子を使用して、どの上位層(この場合は、
TCP)に受信したデータを渡すべきかを判断する。
また、アプリケーションが TCP/IP 経由で通信を行うとき、それらは相手方の IP アド
レスだけでなく、アプリケーションのポート番号をも指定しなければならない。
ポート番号はアプリケーションをユニークに特定するものであり、標準的なネット
ワークアプリケーションは標準のポート番号を使用する。たとえば、ウェブサーバは 
80 番ポートを使用している。これら登録済みのポート番号は、<tt>/etc/services
</tt> ファイルで確認できる。

<!--
This layering of protocols does not stop with TCP, UDP and IP. The IP
protocol layer itself uses many different physical media to transport IP
packets to other IP hosts. These media may themselves add their own
protocol headers. One such example is the ethernet layer, but PPP and SLIP
are others. An ethernet network allows many hosts to be simultaneously
connected to a single physical cable. Every transmitted ethernet frame can
be seen by all connected hosts and so every ethernet device has a unique
address. Any ethernet frame transmitted to that address will be received by
the addressed host but ignored by all the other hosts connected to the
network. These unique addresses are built into each ethernet device when
they are manufactured and it is usually kept in an SROM2 on the ethernet
card. Ethernet addresses are 6 bytes long, an example would be
08-00-2b-00-49-A4. Some ethernet addresses are reserved for
multicast purposes and ethernet frames sent with these destination
addresses will be received by all hosts on the network. As ethernet frames
can carry many different protocols (as data) they, like IP packets, contain a
protocol identifier in their headers. This allows the ethernet layer to
correctly receive IP packets and to pass them onto the IP layer. 
-->
<p>このようなプロトコルの多層構造は、TCP, UDP や IP だけに留まらない。すなわ
ち、IP プロトコル自身が様々な異なる物理メディアを使用して IP パケットを他の IP 
ホストに転送している。したがって、それらの物理メディア自体も独自のプロトコル
ヘッダを付け加えている。イーサネット層がその一例であり、他にも PPP 層や SLIP 層
などがある。イーサネットのネットワークでは、多くのホストを同時に単一の物理ケー
ブルに接続することが可能である(訳注: 10BASE5 など。現在、単一の物理ケーブルが
使われることは少なくなりました)。送信されたイーサネットフレーム(frame)は、その
ケーブルに接続されたすべてのホストから見ることが出来るので、個々のイーサネット
デバイスはユニークな(ハードウェア)アドレスを持たなければならない。
特定の(ハードウェア)アドレスに対して送信されたイーサネットフレームはそのアドレ
スのホストに受信され、ネットワークに接続されたそれ以外のすべてのホストからは無
視される。こうしたユニークなアドレスはイーサネットデバイスの製造時にデバイスに
組み込まれていて、通常、イーサネットカードの SROM(<ref id="chapter_net_fn" 
name="脚注2">) に保存されている。
イーサネットのアドレスは 6 バイト長で、たとえば、08-00-2B-00-49-A4 といったもの
になっている。イーサネットのアドレスにはマルチキャスト(<ref id="multicast" 
name="訳注: 用語集(multicast)">)の目的に予約されたものがあり、そうした送信先
アドレスを設定されて送信されたイーサネットフレームは、そのネットワーク上のすべ
てのホストで受信される。
イーサネットフレームは、多種のプロトコルを(データとして)運ぶことができるので、
IP パケットの場合と同様に、イーサネットフレームのヘッダにはプロトコル識別子が
含まれている。これによって、イーサネット層は IP パケットを正確に受信して、それ
を IP 層に渡すことができる。

<!--
In order to send an IP packet via a multi-connection protocol such as
ethernet, the IP layer must find the ethernet address of the IP host. This is
because IP addresses are simply an addressing concept, the ethernet
devices themselves have their own physical addresses. IP addresses on the
other hand can be assigned and reassigned by network administrators at will
but the network hardware responds only to ethernet frames with its own
physical address or to special multicast addresses which all machines must
receive. Linux uses the Address Resolution Protocol (or ARP) to allow
machines to translate IP addresses into real hardware addresses such as
ethernet addresses. A host wishing to know the hardware address
associated with an IP address sends an ARP request packet containing the
IP address that it wishes translating to all nodes on the network by sending
it to a multicast address. The target host that owns the IP address,
responds with an ARP reply that contains its physical hardware address.
ARP is not just restricted to ethernet devices, it can resolve IP addresses
for other physical media, for example FDDI. Those network devices that
cannot ARP are marked so that Linux does not attempt to ARP. There is
also the reverse function, Reverse ARP or RARP, which translates phsyical
network addresses into IP addresses. This is used by gateways, which
respond to ARP requests on behalf of IP addresses that are in the remote
network. 
-->
<p>イーサネットのような(ケーブルに繋がったすべてのホストにフレームが流れる)
マルチコネクションのプロトコル経由で IP パケットを送信するためには、IP 層は、
IP ホストのイーサネットアドレスを知らなければならない。というのも、IP アドレス
は単にアドレス割り当ての概念にすぎず、イーサネットデバイス自体が独自の物理
アドレスを持っているからである。すなわち、IP アドレスはネットワーク管理者の
意志によって割り当てや再割り当てが可能であるのだが、ネットワークハードウェア
は、自分の物理アドレスが付加されたイーサネットフレームか、あるいはすべての
マシンで受信すべき特別なマルチキャストアドレスにしか反応しないからである。
Linux は、ARP (Address Resolution Protocol)を使用して、マシンが、IP アドレスを
イーサネットアドレスのような実際のハードウェアアドレスに変換できるようにしてい
る。
ある IP アドレスに関連付けられたハードウェアアドレスを知ろうとするホストは、
変換したい IP アドレスを含めた ARP リクエストパケットを、マルチキャストアドレス
を付けてネットワーク上のすべてのノード(node)に送信する。その IP アドレスを持つ
ターゲットホスト(target host)は、自分の物理アドレスを含めた ARP リプライによっ
てそれに応答する。ARP はイーサネットデバイスだけでしか利用できないわけではな
く、<ref id="FDDI" name="FDDI"> などのそれ以外の物理メディアに対しても IP アド
レスの解決が可能である。
ARP が利用できないネットワークデバイスはそれが出来ない旨マークされているので、
その場合、Linux がARP を試すことはない。ARP の逆の機能も存在しており、リバース 
ARP もしくは RARP は、ハードウェアアドレスを IP アドレスに変換する。これは
ゲートウェイによって利用されるもので、ゲートウェイは、リモートネットワークにあ
る IP アドレスが書かれた ARP リクエストに応答する際にそれを使用する。

<!--10.2  The Linux TCP/IP Networking Layers-->
<sect1>Linux の TCP/IP ネットワーク層<label id="chapter_net_sect2">
<p>

<label id="figure10-2">
<!--              Figure 10.2: Linux Networking Layers-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure10-2.gif">
</figure>
</#if>
<#unless output="html">
<verb>
                           ネットワーク
                          アプリケーション
                               /|
                                |                       User
--------------------------------+----------------------------
                                |                      Kernel
                                |/
                          +-----*------+
                          |    BSD     |
                          |  ソケット  |
                          +-----*------+
ソケット                       /|
インターフェイス                |/
                          +-----*------+
                          |    INET    |
                          |  ソケット  |
                          +--*--*--*---+
                            /| /| /|
                        +----+  |  +----+
                        |/      |       |/
                    +---*---+   |   +---*---+
                    |       |   |   |       |
                    |  TCP  |   |   |  UDP  |
                    +---*---+   |   +---*---+
プロトコル層           /|       |      /|
                        |       |       |
                        |/      |/      |/
                 +------*-------*-------*-------+
                 |                              |<-+
                 |              IP              |  |
                 +---*----------*----------*----+  |  +-------+
                    /|         /|         /|       +->|       |
                     |          |          |          |  ARP  |
                     |/         |/         |/      +->|       |
                 +---*---+  +---*---+  +---*----+  |  +-------+
ネットワーク     |       |  |       |  |        |<-+
デバイス         |  PPP  |  |  SLIP |  |Ethernet|
                 +-------+  +-------+  +--------+
</verb>
</#if>
<p>図表(10.2) Linux のネットワーク層

<!--
Just like the network protocols themselves, Figure  10.2 shows that Linux
implements the internet protocol address family as a series of connected
layers of software. BSD sockets are supported by a generic socket
management software concerned only with BSD sockets. Supporting this is
the INET socket layer, this manages the communication end points for the
IP based protocols TCP and UDP. UDP (User Datagram Protocol) is a
connectionless protocol whereas TCP (Transmission Control Protocol) is a
reliable end to end protocol. When UDP packets are transmitted, Linux
neither knows nor cares if they arrive safely at their destination. TCP
packets are numbered and both ends of the TCP connection make sure that
transmitted data is received correctly. The IP layer contains code
implementing the Internet Protocol. This code prepends IP headers to
transmitted data and understands how to route incoming IP packets to either
the TCP or UDP layers. Underneath the IP layer, supporting all of Linux's
networking are the network devices, for example PPP and ethernet. Network
devices do not always represent physical devices; some like the loopback
device are purely software devices. Unlike standard Linux devices that are
created via the mknod command, network devices appear only if the
underlying software has found and initialized them. You will only see
/dev/eth0 when you have built a kernel with the appropriate ethernet
device driver in it. The ARP protocol sits between the IP layer and the
protocols that support ARPing for addresses. 
-->
<p>ネットワークプロトコル自体が多層構造を持つのと同様に、図表(10.2)では、Linux 
がインターネットプロトコルアドレスファミリ(address family)をソフトウェアの多層
構造として実装していることが示されている。BSD ソケットは、BSD ソケットだけに関
する汎用のソケット管理ソフトウェアとしてサポートされている。
BSD ソケットをサポートするのが INET ソケット層で、これは、IP ベースの TCP や 
UDP プロトコルのためのエンドポイント通信を管理する。
UDP(User Datagram Protocol)はコネクション管理を行わないプロトコル
であるが、TCP(Transmission Control Protocol)は信頼性のある一対一(end to end)の
プロトコルである。UDP パケットが送信されるとき、Linux はそれが安全に送信先に
届いたかどうか分からないし、気にもしない。TCP パケットは番号付けされている
ので、TCP コネクションの両方のエンド(end, 端)は、送信されたデータが正しく受信さ
れたかどうかを確認できる。
IP 層には、インターネットプロトコル(IP)を処理するためのコードが含まれている。
このコードは、受信したデータの IP ヘッダを取得し、その IP パケットが TCP か 
UDP のどちらかの上位層に宛てたものかを判断して、適切な上位層にルーティングす
る。IP 層の下で Linux のネットワーキングをサポートしているのが、PPP やイーサ
ネットといったネットワークデバイスである。ネットワークデバイスとは必ずしも物理
デバイスを意味するものではない。ループバックデバイス(loopback device)などは純粋
なソフトウェアデバイスだからである。
<tt>mknod</tt> で作成される Linux の標準的なデバイスファイルとは異なり、ネット
ワークデバイスはその基礎となるソフトウェアが物理デバイスを検出し初期化した場合
にだけ現れる。
カーネルに適切なイーサネットデバイスドライバを組み込んだ場合のみ、<tt>
/dev/eth0</tt> を見ることができる。ARP プロトコルは、IP 層と ハードウェア
アドレス解決のために ARP をサポートする下位のプロトコルとの間に位置している。

<!--10.3  The BSD Socket Interface-->
<sect1>BSD ソケットインターフェイス<label id="chapter_net_sect3">

<!--
This is a general interface which not only supports various forms of
networking but is also an inter-process communications mechanism. A
socket describes one end of a communications link, two communicating
processes would each have a socket describing their end of the
communication link between them. Sockets could be thought of as a special
case of pipes but, unlike pipes, sockets have no limit on the amount of data
that they can contain. Linux supports several classes of socket and these
are known as address families. This is because each class has its own
method of addressing its communications. Linux supports the following
socket address families or domains: 
-->
<p>BSD ソケットインターフェイスは、汎用インターフェイスであり、ネットワークの
様々な形態をサポートするだけでなく、プロセス間通信の仕組みでもある。
ソケットは通信リンクの一方のエンド(end, 端)を記述するもので、ふたつの通信プロセ
スが個別にソケットを持ち、両者の間の通信リンクのそれぞれのエンドを記述する。
ソケットはパイプの特殊なケースであると考えることも可能だが、パイプと異なり、
ソケットは保持できるデータ容量に制限がない。Linux は、いくつかのソケットクラス
(socket class)をサポートしており、それらはアドレスファミリ(address family)と
呼ばれている。これは、個々のクラスが独自の通信方式を持っているからである。
Linux は次のようなアドレスファミリもしくはドメイン(domain)をサポートしている。

<!--
 UNIX 
            Unix domain sockets, 
 INET 
            The Internet address family supports communications via 
            TCP/IP protocols 
 AX25 
            Amateur radio X25 
 IPX 
            Novell IPX 
 APPLETALK 
            Appletalk DDP 
 X25 
            X25
-->
<descrip>
<tag>UNIX</tag>Unix ドメインソケット。

<tag>INET</tag>インターネットアドレスファミリ(internet address family)は、
TCP/IP 経由の通信をサポートしている。

<tag>AX25</tag>アマチュア無線 X25。

<tag>IPX</tag>Novell IPX。

<tag>APPLETALK</tag>Appletalk DDP

<tag>X25</tag>X25。
</descrip>

<!--
There are several socket types and these represent the type of service that
supports the connection. Not all address families support all types of
service. Linux BSD sockets support a number of socket types: 
-->
<p>アドレスファミリもしくはドメインには、いくつかのソケットタイプ(socket type)
があり、それらはコネクションをサポートするサービスのタイプを表している。
すべてのサービスタイプをサポートしていないアドレスファミリもある。
Linux BSD ソケットは次のいくつかのソケットタイプをサポートしている。

<!--
Stream These sockets provide reliable two way sequenced data streams
      with a guarantee that data cannot be lost, corrupted or duplicated in
      transit. Stream sockets are supported by the TCP protocol of the
      Internet (INET) address family. 
-->
<descrip>
<tag>Stream</tag>
このソケットは、双方向で順次送達確認の行われる信頼性のあるデータストリーム
(data stream)であり、通信途上でのデータの喪失や破壊、複製が生じないよう保証され
たものである。Stream ソケットは、インターネット(INET)アドレスファミリの TCP 
プロトコルによってサポートされている。

<!--
Datagram
      These sockets also provide two way data transfer but, unlike stream
      sockets, there is no guarantee that the messages will arrive. Even if
      they do arrive there is no guarantee that they will arrive in order or
      even not be duplicated or corrupted. This type of socket is supported
      by the UDP protocol of the Internet address family. 
-->
<tag>Datagram</tag>
このソケットは、双方向でのデータ通信を提供するが、stream ソケットと異なり、
メッセージが到達する保証はない。到達した場合でも、順番通り届いたか、さらに
複製や破壊はないかといったことは保証されない。このタイプのソケットは、インター
ネットアドレスファミリの UDP プロトコルによってサポートされている。

<!--
Raw This allows processes direct (hence ``raw'') access to the
      underlying protocols. It is, for example, possible to open a raw
      socket to an ethernet device and see raw IP data traffic. 
-->
<tag>Raw</tag>
これは、プロセスが、下位層のプロトコルに直接(それゆえ、生(raw))アクセスする
ものである。これを使うと、たとえば、raw ソケットをイーサネットデバイスに対して
オープンし、生(raw)の IP データトラフィックを見ることが可能になる。

<!--
Reliable Delivered Messages
      These are very like datagram sockets but the data is guaranteed to
      arrive. 
-->
<tag>Reliable Delivered Messages</tag>
これは、datagram ソケットと非常に類似しているが、データの到着は保証される。

<!--
Sequenced Packets
      These are like stream sockets except that the data packet sizes are
      fixed. 
-->
<tag>Sequenced Packets</tag>
これは、データパケットサイズが固定されていることを除いて、stream パケットと
同じである。

<!--
Packet This is not a standard BSD socket type, it is a Linux specific
      extension that allows processes to access packets directly at the
      device level. 
-->
<tag>Packet</tag>
これは、標準的な BSD ソケットタイプではない。Linux 固有の拡張であり、
これを使うと、プロセスがデバイスレベルで直接パケットにアクセスできる。
</descrip>

<!--
Processes that communicate using sockets use a client server model. A
server provides a service and clients make use of that service. One example
would be a Web Server, which provides web pages and a web client, or
browser, which reads those pages. A server using sockets, first creates a
socket and then binds a name to it. The format of this name is dependent on
the socket's address family and it is, in effect, the local address of the
server. The socket's name or address is specified using the sockaddr data
structure. An INET socket would have an IP port address bound to it. The
registered port numbers can be seen in /etc/services; for example, the
port number for a web server is 80. Having bound an address to the socket,
the server then listens for incoming connection requests specifying the
bound address. The originator of the request, the client, creates a socket
and makes a connection request on it, specifying the target address of the
server. For an INET socket the address of the server is its IP address and
its port number. These incoming requests must find their way up through the
various protocol layers and then wait on the server's listening socket. Once
the server has received the incoming request it either accepts or rejects it.
If the incoming request is to be accepted, the server must create a new
socket to accept it on. Once a socket has been used for listening for
incoming connection requests it cannot be used to support a connection.
With the connection established both ends are free to send and receive
data. Finally, when the connection is no longer needed it can be shutdown.
Care is taken to ensure that data packets in transit are correctly dealt with. 
-->
<p>ソケットを利用して通信を行うプロセスは、クライアントサーバモデル(client 
server model)を使用する。
サーバはサービスを提供し、クライアントがそのサービスを利用する。その典型が
ウェブサーバであり、サーバがウェブページを提供し、クライアント、もしくは
ブラウザがそのページを読み出す。ソケットを使うサーバは、まずソケットを作成
し、それに名前を結びつける(bind)。その名前のフォーマットはそのソケットの
アドレスファミリに依存し、事実上サーバのローカルアドレスになる。ソケットの
名前もしくはアドレスは、<tt><ref id="sockaddr" name="sockaddr"></tt> データ
構造体を使って指定される。
INET ソケットは、IP ポート番号をそれに結びつける。登録済みポート番号は、
<tt>/etc/services</tt> ファイルで見ることができる。たとえば、ウェブサーバのポー
ト番号は 80 である。アドレスをソケットに結びつけたら、サーバは、そのアドレス
を指定したコネクションリクエストが来るまで待機(listen)している。リクエストの
発信者である
クライアントはソケットを作成し、サーバのターゲットアドレスを指定して、
ソケット上でコネクションリクエストを出す。INET ソケットの場合、サーバの
アドレスは、その IP アドレスとポート番号である。入って来たリクエストは、
様々なプロトコル層を
上昇して、サーバの待機中(listening)のソケット上で(処理されるのを)待つ。サーバ
が入って来たリクエストを受信した場合、サーバは、それを受け入れる(accept)か拒絶
するかのいずれかを行う。リクエストが受け入れられる場合、サーバは
受け入れるための新しいソケットを作成しなければならない。入って来るコネクション
リクエストのために、いったん待機状態(listening)に入ったソケットは、
コネクションをサポートするために使用することはできない。
コネクションが確立されたら、両者は自由にデータの送受信ができる。最後に、それ以
上コネクションが必要なくなったとき、コネクションは遮断(shutdown)できる。
その際、転送中のデータパケットがあっても正しく処理されるよう注意を払う
必要がある。

<!--
The exact meaning of operations on a BSD socket depends on its underlying
address family. Setting up TCP/IP connections is very different from setting
up an amateur radio X.25 connection. Like the virtual filesystem, Linux
abstracts the socket interface with the BSD socket layer being concerned
with the BSD socket interface to the application programs which is in turn
supported by independent address family specific software. At kernel
initialization time, the address families built into the kernel register
themselves with the BSD socket interface. Later on, as applications create
and use BSD sockets, an association is made between the BSD socket and
its supporting address family. This association is made via cross-linking
data structures and tables of address family specific support routines. For
example there is an address family specific socket creation routine which
the BSD socket interface uses when an application creates a new socket. 
-->
<p>BSD ソケット上での操作が厳密に何を意味するかは、その基礎となるアドレス
ファミリによって異なる。TCP/IP コネクションの設定は、アマチュア無線 X.25 
コネクションの設定とは非常に異なる。仮想ファイルシステムの場合のように、Linux 
は、BSD ソケット層(layer)を使ってソケットインターフェイスを抽象化している。
BSD ソケット層側は、アプリケーションプログラムに対する BSD ソケットインター
フェイスと関係付けられ、アプリケーション側は、アドレスファミリごとに独立した
固有のソフトウェアによりサポートされている。
カーネルに組み込まれたアドレスファミリは、カーネルの初期化時に、BSD ソケット
インターフェイスと伴に登録される。その後、アプリケーションが BSD ソケットを
作成して使用する場合、BSD ソケットとそれがサポートするアドレスファミリとの
間で関連付けがなされる。この関連付けは、データ構造体とアドレスファミリ固有の
サポートルーチンとをクロスリンクすることにより実現される。
たとえば、アドレスファミリ固有のソケット作成ルーチンがある場合、アプリケー
ションが新規にソケットを作成しようとする際には、BSD ソケットインターフェイス
は、そのルーチンを使用してソケットを作成する。

<!--
When the kernel is configured, a number of address families and protocols
are built into the protocols vector. Each is represented by its name, for
example ``INET'' and the address of its initialization routine. When the
socket interface is initialized at boot time each protocol's initialization
routine is called. For the socket address families this results in them
registering a set of protocol operations. This is a set of routines, each of
which performs a a particular operation specific to that address family. The
registered protocol operations are kept in the pops vector, a vector of
pointers to proto_ops data structures. 
The proto_ops data structure consists of the address family type and a
set of pointers to socket operation routines specific to a particular address
family. The pops vector is indexed by the address family identifier, for
example the Internet address family identifier (AF_INET is 2). 
-->
<p>一般に、カーネル設定の際には、いくつものアドレスファミリとプロトコルが 
ビルドされ、<tt><htmlurl url="./The-Linux-Kernel-images/linux/net/socket.c" 
name="protocols"></tt> 配列に組み込まれる。それらはそれぞれ、INET といった名前
とその初期化ルーチンのアドレスとによって表現される。ブート時にソケット
インターフェイスが初期化されるとき、個々のプロトコル初期化ルーチンが呼び出さ
れる。ソケットアドレスファミリにとって、これは、一組のプロトコル操作
を登録することを意味する。これは、一組のルーチンであり、それぞれが
アドレスファミリ固有のプロトコル操作を実行する。登録されたプロトコル操作
ルーチンは、<tt><ref id="proto_ops" name="pops"></tt> 配列に保存されるが、
それは <tt><ref id="proto_ops" name="proto_ops"></tt>
 データ構造体へのポインタの配列である。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/net.h" 
name="include/linux/net.h">]<newline>
<tt>proto_ops</tt> データ構造体は、アドレスファミリタイプと、アドレス
ファミリ固有のソケット操作ルーチンに対する一連のポインタから構成されている。
<tt>pops</tt> 配列は、アドレスファミリ識別子によるインデックスが
付けられていて、たとえば、インターネットアドレスファミリの識別子(AF_INET)は
 2 である。


<!--           Figure 10.3: Linux BSD Socket Data Structures-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure10-3.gif">
</figure>
</#if>
<#unless output="html">
<verb>
files_struct
+-------------+
| count       |
|-------------|
|close_on_exec|
|-------------|
| open_fs     |
|-------------|
| fd[0]       |      file
|-------------|   +----------+
| fd[1]       |-->| f_mode   |
|-------------|   |----------|
|             |   | f_pos    |
|             |   |----------|
|             |   | f_flags  |
|-------------|   |----------|
| fd[255]     |   | f_count  |
+-------------+   |----------|
                  | f_owner  |
                  |----------|                    BSD Socket
                  | f_op     |------------------->File Operations
                  |----------|                    
                  | f_inode  |-+     inode        lseek,ioctl
                  |----------| |  +---------+     read, close
                  |f_version | +->|         |     write, fasync
                  +----------+    |         |     select
                              +-->| socket  |
                              |   |---------|SOCK_STREAM
                              |   | type    |------->Address Family
                              |   | ops     |----+   Socket
                              |   | data    |    |   Operations
                              |   +---------+    |
                              |    +-------------+
                              +----+-----------------+
                                   |       sock      |
                                   |   +----------+  |
                                   +-->| type     |SOCK_STREAM
                                       |----------|  |
                                       | protocol |  |
                                       |----------|  |
                                       | socket   |--+
                                       |----------|
                                       |          |
                                       |          |
                                       +----------+
</verb>
</#if>
<p>図表(10.3) Linux BSD ソケットデータ構造体

<!--10.4  The INET Socket Layer-->
<sect1>INET ソケット層<label id="chapter_net_sect4">

<!--
The INET socket layer supports the internet address family which contains
the TCP/IP protocols. As discussed above, these protocols are layered, one
protocol using the services of another. Linux's TCP/IP code and data
structures reflect this layering. Its interface with the BSD socket layer is
through the set of Internet address family socket operations which it
registers with the BSD socket layer during network initialization. These are
kept in the pops vector along with the other registered address families.
The BSD socket layer calls the INET layer socket support routines from the
registered INET proto_ops data structure to perform work for it. For
example a BSD socket create request that gives the address family as
INET will use the underlying INET socket create function. The BSD socket
layer passes the socket data structure representing the BSD socket to the
INET layer in each of these operations. Rather than clutter the BSD
socket wiht TCP/IP specific information, the INET socket layer uses its
own data structure, the sock which it links to the BSD socket data
structure. This linkage can be seen in Figure  10.3. It links the sock data
structure to the BSD socket data structure using the data pointer in the
BSD socket. This means that subsequent INET socket calls can easily
retrieve the sock data structure. The sock data structure's protocol
operations pointer is also set up at creation time and it depends on the
protocol requested. If TCP is requested, then the sock data structure's
protocol operations pointer will point to the set of TCP protocol operations
needed for a TCP connection. 
-->
<p>INET ソケット層は、TCP/IP を含むインターネットアドレスファミリをサポート
するものである。上記で説明したように、これらのプロトコルは多層構造になってい
て、ひとつのプロトコルが別のプロトコルのサービスを利用する。
Linux の TCP/IP のコードとデータ構造はその多層構造を反映している。BSD ソケット
層に対する INET ソケット層のインターフェイスは、一連のインターネットアドレス
ファミリのソケット操作ルーチンを経由するものであり、Linux は、ネットワークの
初期化時にそれらのルーチンを BSD ソケット層と伴に登録する。
それらは、登録された他のアドレスファミリと一緒に <tt><ref id="proto_ops" 
name="pops"></tt> 配列に保存される。BSD ソケット層は、登録済みの INET <tt><ref 
id="proto_ops" name="proto_ops"></tt> データ構造体から、INET 層ソケットを
サポートするルーチンを呼び出して操作を実行する。
たとえば、アドレスファミリを INET と指定した BSD ソケット作成リクエストは、
その基礎にある INET ソケット作成関数を使用する。
BSD ソケット層は、それらの個々の操作をする際に、BSD ソケットを
表す <tt><ref id="socket" name="socket"></tt> データ構造体を INET 層に渡す。
BSD ソケットが TCP/IP 固有の情報でごちゃごちゃにならないように、INET ソケット
層は、独自のデータ構造体である <tt><ref id="sock" name="sock"></tt> を使用し、
この構造体を BSD ソケット層の <tt>socket</tt> データ構造体にリンクする。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/net/sock.h"
name="include/net/sock.h">]<newline>
このリンク関係は、図表(10.3)で示されている。
INET ソケット層は <tt>sock</tt> データ構造体を BSD <tt>socket</tt> データ構造体
にリンクする際、BSD <tt>socket</tt> の <tt>data</tt>ポインタを使用する。
これは、それ以降の INET ソケットの呼び出しで、簡単に <tt>sock</tt> データ構造体
が取り出せることを意味する。
<tt>sock</tt> データ構造体のプロトコル操作ルーチンへのポインタは、その構造体
作成時に設定されるが、設定の内容はリクエストされたプロトコルによって異なる。
TCP/IP がリクエストされた場合、<tt>sock</tt> データ構造体のプロトコル操作ルーチ
ンへのポインタは、TCP コネクションに必要な TCP プロトコル操作ルーチンのセットを
ポイントする。

<!--10.4.1  Creating a BSD Socket-->
<sect2>BSD ソケットの作成

<!--
The system call to create a new socket passes identifiers for its address
family, socket type and protocol. 
Firstly the requested address family is used to search the pops vector for a
matching address family. It may be that a particular address family is
implemented as a kernel module and, in this case, the kerneld daemon
must load the module before we can continue. A new socket data structure
is allocated to represent the BSD socket. Actually the socket data
structure is physically part of the VFS inode data structure and allocating
a socket really means allocating a VFS inode. This may seem strange
unless you consider that sockets can be operated on in just the same way
that ordinairy files can. As all files are represented by a VFS inode data
structure, then in order to support file operations, BSD sockets must also be
represented by a VFS inode data structure. 
-->
<p>システムコールで新規ソケットを作成する際は、アドレスファミリ、ソケットタイ
プ、プロトコルに関する識別子を渡す。
<newline>[see: sys_socket(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/net/socket.c" 
name="net/socket.c">]<newline>
まず、リクエストされたアドレスファミリを使って、<tt><ref id="proto_ops" 
name="pops"</tt> 配列内に合致するアドレスファミリがあるかどうか検索される。
たとえば、特定のアドレスファミリがカーネルモジュールとして実装されている場合
は、処理を継続する前に <tt>kerneld</tt> デーモンによって該当するモジュール
がロードされることになる。
新規の <tt><ref id="socket" name="socket"></tt> データ構造体が割り当てられて、
BSD ソケットが表現される。
実際、<tt>socket</tt> データ構造体は、物理的には VFS <tt><ref id="inode" 
name="inode"></tt> データ構造体の一部なので、<tt>socket</tt> の割り当ては、
VFS <tt>inode</tt> の割り当てを意味する。
これは奇妙に思われるかもしれないが、ソケットは、通常ファイルの操作と同じ方法で
操作され得ることを考えてほしい。すべてのファイルが VFS <tt>inode</tt> データ
構造体によって表現されるので、ファイル操作をサポートするには、BSD ソケットは 
VFS <tt>inode</tt> データ構造体によっても表現されなければならないのである。

<!--
The newly created BSD socket data structure contains a pointer to the
address family specific socket routines and this is set to the proto_ops
data structure retrieved from the pops vector. Its type is set to the sccket
type requested; one of SOCK_STREAM, SOCK_DGRAM and so on. The
address family specific creation routine is called using the address kept in
the proto_ops data structure. 
-->
<p>新規に作成された BSD <tt><ref id="socket" name="socket"></tt> データ構造体に
は、アドレスファミリ固有のソケットルーチンへのポインタが含まれていて、このルー
チンは、<tt><ref id="proto_ops" name="pops"></tt> 配列から取り出された <tt>
<ref id="proto_ops" name="proto_ops"></tt> データ構造体に設定される。そのタイプ
は、リクエストされたソケットタイプ、すなわち SOCK_STREAM, 
SOCK_DGRAM 等に設定される。アドレスファミリ固有の作成ルーチンは、<tt>proto_ops
</tt> データ構造体に保存されたアドレスを使用して呼び出される。

<!--
A free file descriptor is allocated from the current processes fd vector and
the file data structure that it points at is initialized. This includes setting
the file operations pointer to point to the set of BSD socket file operations
supported by the BSD socket interface. Any future operations will be
directed to the socket interface and it will in turn pass them to the
supporting address family by calling its address family operation routines. 
-->
<p>未使用のファイル記述子が、カレントプロセスの <tt><ref id="files_struct" 
name="fd"></tt> 配列から割り当てられて、それがポイントする <tt><ref 
id="file" name="file"></tt> データ構造体が初期化される。
この際に同時に為される処理として、そのファイル操作ポインタのポイント先が、
BSD ソケットインターフェイスによってサポートされる BSD ソケットファイル操作
ルーチン群へと設定される。それ以後の何らかの操作は、ソケットインターフェイス
へと誘導され、ソケットインターフェイスがさらにアドレスファミリ操作ルーチンを
呼び出すことで、それがサポートするアドレスファミリへと誘導される。

<!--10.4.2  Binding an Address to an INET BSD Socket-->
<sect2>アドレスを INET BSD ソケットに bind する

<!--
In order to be able to listen for incoming internet connection requests, each
server must create an INET BSD socket and bind its address to it. The bind
operation is mostly handled within the INET socket layer with some support
from the underlying TCP and UDP protocol layers. The socket having an
address bound to cannot be being used for any other communication. This
means that the socket's state must be TCP_CLOSE. The sockaddr pass
to the bind operation contains the IP address to be bound to and, optionally,
a port number. Normally the IP address bound to would be one that has been
assigned to a network device that supports the INET address family and
whose interface is up and able to be used. You can see which network
interfaces are currently active in the system by using the ifconfig command.
The IP address may also be the IP broadcast address of either all 1's or all
0's. These are special addresses that mean ``send to everybody''3. The IP
address could also be specified as any IP address if the machine is acting
as a transparent proxy or firewall, but only processes with superuser
privileges can bind to any IP address. The IP address bound to is saved in
the sock data structure in the recv_addr and saddr fields. These are
used in hash lookups and as the sending IP address respectively. The port
number is optional and if it is not specified the supporting network is asked
for a free one. By convention, port numbers less than 1024 cannot be used
by processes without superuser privileges. If the underlying network does
allocate a port number it always allocates ones greater than 1024. 
-->
<p>入って来るインターネットコネクションリクエストを待機(listen)するためには、
個々のサーバが INET BSD ソケットを作成して、それにアドレスを結びつけ(bind)
なければ
ならない。bind 操作の大部分は、その基礎にある TCP と UDP プロトコル層の
サポートを受けた INET ソケット層内部で処理される。アドレスを結びつけ(bind)ら
れた
ソケットは、それ以外の通信には使用できない。これは、ソケットの状態(state)が 
TCP_CLOSE でなければならないことを意味する。<tt><ref id="sockaddr" 
name="sockaddr"></tt> 構造体から bind 操作ルーチンに渡される情報の中には、
結びつけ(bind)られるべき IP アドレスと、オプションとしてポート番号がある。
通常、bind された IP アドレスは、ネットワークデバイスに割り当てられたもので
あり、そのデバイスは INET アドレスファミリをサポートするもので、そのデバイス
のインターフェイスは起動されていて使用可能でなければならない。そのインターフェ
イスが現在アクティブであるかを確認するには、<tt>ifconfig</tt> コマンドを使用す
ればよい。
IP アドレスは、アドレス(のビット)をすべて 1 にするか、すべて 0 にするかい
ずれかによって、IP ブロードキャストアドレス(<ref id="broadcast" 
name="訳注:broadcast address">)にすることもできる。
それは特別なアドレスで、「全員に送信」(<ref id="chapter_net_fn" 
name="脚注3">)することを意味する。
マシンが透過的なプロキシかファイアウォールである場合、IP アドレスの指定を任意
の IP アドレスとしても構わないが、スーパーユーザの権限を持ったプロセスだけが任
意の IP アドレスを結びつけ(bind)できる。結びつけ(bind)られた IP アドレスは <tt>
<ref id="sock" 
name="sock"></tt> データ構造体の <tt>recv_addr</tt>(訳注: <tt><ref 
id="sock" name="recv_saddr"></tt>?) と <tt><ref id="sock" name="saddr"></tt> 
に保存される。それらは、ハッシュへの問い合わせの際と、IP アドレスを互いに送信
しあう場合に使用される。ポート番号はオプションであり、指定されない場合、
サポートするネットワークに未使用の番号を割り当てるよう要請がなされる。
慣習では、1024 未満のポート番号は、スーパーユーザの特権がない
プロセスでは使用できない。基礎となるネットワークがポート番号を割り当てる場合、
1024 以上の番号を常に割り当てる。

<!--
As packets are being received by the underlying network devices they must
be routed to the correct INET and BSD sockets so that they can be
processed. For this reason UDP and TCP maintain hash tables which are
used to lookup the addresses within incoming IP messages and direct them
to the correct socket/sock pair. TCP is a connection oriented protocol and
so there is more information involved in processing TCP packets than there
is in processing UDP packets. 
-->
<p>パケットが基礎となるネットワークデバイスで受信されると、パケットは正しい 
INET ソケットと BSD ソケットへと伝達されて、処理されなければならない。
そのために、UDP と TCP は、ハッシュテーブルを管理していて、それを使って、到着
した IP パケット内にあるアドレスを問い合わせて、正しい <tt>
socket/sock</tt> ペアへと IP パケットを伝達する。TCP はコネクション指向の
プロトコルなので、UDP パケットの場合よりも TCP パケットを処理する場合のほうが
関係する情報量が多い。

<!--
UDP maintains a hash table of allocated UDP ports, the udp_hash table.
This consists of pointers to sock data structures indexed by a hash
function based on the port number. As the UDP hash table is much smaller
than the number of permissible port numbers (udp_hash is only 128 or
UDP_HTABLE_SIZE entries long) some entries in the table point to a chain
of sock data structures linked together using each sock's next pointer. 
-->
<p>UDP は、割り当てられた UDP ポートを <tt><ref id="udp_hash" name="udp_hash">
</tt> というハッシュテーブルで管理している。
そのハッシュテーブルは、<tt><ref id="sock" name="sock"></tt> データ構造体への
ポインタから構成されていて、<tt>sock</tt> 構造体はポート番号に基づいてハッシュ
関数によりインデックス付けされている。UDP のハッシュテーブルは、持ち得るポート
番号の数よりも小さい(<tt>udp_hash</tt> は 128 か、UDP_HTABLE_SIZE の数のエント
リしか持たない)ので、テーブル内のエントリのなかには、個々の <tt>sock</tt> が
次へのポインタを持つことでリンクされた <tt>sock</tt> データ構造体の連結リスト
をポイントしているものがある。

<!--
TCP is much more complex as it maintains several hash tables. However,
TCP does not actually add the binding sock data stucture into its hash
tables during the bind operation, it merely checks that the port number
requested is not currently being used. The sock data structure is added to
TCP's hash tables during the listen operation. 
-->
<p>TCP は、複数のハッシュテーブルを管理しているので、UDP よりずっと複雑である。
しかし、TCP は、bind 操作をする間、実際に bind すべき <tt><ref id="sock" 
name="sock"></tt> データ構造体をそのハッシュテーブルに付け加えるわけではなく、
要求されたポート番号が現在使用されていないかどうかチェックするだけである。
<tt>sock</tt> データ構造体は、listen 操作の間に TCP のハッシュテーブルに付け加
えられる。

REVIEW NOTE: What about the route entered? 

<!--10.4.3  Making a Connection on an INET BSD Socket-->
<sect2>INET BSD ソケット上でコネクションを確立する

<!--
Once a socket has been created and, provided it has not been used to listen
for inbound connection requests, it can be used to make outbound
connection requests. For connectionless protocols like UDP this socket
operation does not do a whole lot but for connection orientated protocols like
TCP it involves building a virtual circuit between two applications. 
-->
<p>ソケットが作成されると、そのソケットは、相手側からの(inbound)コネクション
リクエストを待機(listen)するために使用されていない限り、自己側からの(outbound)
コネクションリクエストのために使用できる。
UDP のようなコネクションレスのプロトコルの場合、このソケット操作は限定された
意味しか持たないのだが、TCP のようなコネクション指向のプロトコルの場合だと、
それはふたつのアプリケーション間で仮想サーキットを構築することを意味する。

<!--
An outbound connection can only be made on an INET BSD socket that is in
the right state; that is to say one that does not already have a connection
established and one that is not being used for listening for inbound
connections. This means that the BSD socket data structure must be in
state SS_UNCONNECTED. The UDP protocol does not establish virtual
connections between applications, any messages sent are datagrams, one
off messages that may or may not reach their destinations. It does,
however, support the connect BSD socket operation. A connection operation
on a UDP INET BSD socket simply sets up the addresses of the remote
application; its IP address and its IP port number. Additionally it sets up a
cache of the routing table entry so that UDP packets sent on this BSD
socket do not need to check the routing database again (unless this route
becomes invalid). The cached routing information is pointed at from the
ip_route_cache pointer in the INET sock data structure. If no
addressing information is given, this cached routing and IP addressing
information will be automatically be used for messages sent using this BSD
socket. UDP moves the sock's state to TCP_ESTABLISHED. 
-->
<p>自己側からの(outbound)コネクションリクエストが可能となるのは、INET BSD 
ソケットを使用し、しかも使用する INET BSD ソケットが適切な状態(state)にある
場合だけである。
すなわち、そのソケット上で既にコネクションが確立していないこと、およびそれが
相手側からの(inbound)コネクションリクエストの待機のために使用されていない
場合である。
これは、BSD <tt><ref id="socket" name="socket"></tt> データ構造体が 
SS_UNCONNECTED の状態になければならないことを意味する。
UDP プロトコルはアプリケーション間で仮想コネクションを確立することはなく、送信
されたメッセージはすべてデータグラム(datagram)であるので、送信メッセージが送信
先に届くかどうかは確定しない。しかし、UDP に関しても BSD ソケット操作である 
connect はサポートされている。UDP INET BSD ソケット上での connect 操作は、
単にリモー
トアプリケーションのアドレスとして、その IP アドレスと IP ポート番号を設定
する。さらに、ルーティングテーブルのエントリのキャッシュを設定して、(当該ルート
が無効とならない限り)その BSD ソケットから送信された UDP パケットが再度ルーティ
ング情報をチェックする必要がないようにする。キャッシュされたルーティング情報
は、INET <tt><ref id="sock" name="sock"></tt> データ構造体内の <tt><ref 
id="sock" name="ip_route_cache"></tt> ポインタによってポイントされる。
アドレス情報が指定されない場合、このキャッシュされたルーティング情報と IP アド
レス情報が、その BSD ソケットを使って送信されるメッセージのために
自動的に使用される。そして、UDP は <tt>sock</tt> の状態(state)を 
TCP_ESTABLISHE に変更する。

<!--
For a connect operation on a TCP BSD socket, TCP must build a TCP
message containing the connection information and send it to IP destination
given. The TCP message contains information about the connection, a
unique starting message sequence number, the maximum sized message
that can be managed by the initiating host, the transmit and receive window
size and so on. Within TCP all messages are numbered and the initial
sequence number is used as the first message number. Linux chooses a
reasonably random value to avoid malicious protocol attacks. Every
message transmitted by one end of the TCP connection and successfully
received by the other is acknowledged to say that it arrived successfully
and uncorrupted. Unacknowledges messages will be retransmitted. The
transmit and receive window size is the number of outstanding messages
that there can be without an acknowledgement being sent. The maximum
message size is based on the network device that is being used at the
initiating end of the request. If the receiving end's network device supports
smaller maximum message sizes then the connection will use the minimum
of the two. The application making the outbound TCP connection request
must now wait for a response from the target application to accept or reject
the connection request. As the TCP sock is now expecting incoming
messages, it is added to the tcp_listening_hash so that incoming TCP
messages can be directed to this sock data structure. TCP also starts
timers so that the outbound connection request can be timed out if the target
application does not respond to the request. 
-->
<p>TCP BSD ソケット上での connect 操作の場合、TCP は、コネクション情報を含んだ 
TCP セグメント(segment)を作成して、指定された IP 送信先に送らなければならない。
TCP セグメントには、コネクション情報、開始セグメントのシーケンス番号(sequence 
number)、接続を開始したホスト側が処理できるセグメントの最大サイズ(maximum 
segment size, MSS)、送信および受信の際のウィンドウサイズ(window size)、等が含
まれる。
TCP では、すべてのセグメントに番号が付けられるので、シーケンス番号の初期値に
は、最初のセグメントの番号が利用される。Linux は、悪意のあるアタックを防ぐため
に、妥当な範囲の乱数値を選択している。TCP コネクションの一方から送信され、相手
側で問題なく受信されたセグメントに対してはすべて、データ破損なく成功裡に到達し
た旨の送達確認(acknowledgement)がなされる。送達確認のないセグメントは再送され
る。送信と受信のウィンドウサイズとは、送達確認が送信されないまま存在しうる未解
決セグメントの数である。最大セグメントサイズは、コネクションリクエストを発信し
た側で使用されているネットワークデバイスに依存する。受信側のネットワークデバイ
スがそれよりも小さい最大セグメントサイズしかサポートしていない場合、そのコネク
ションは小さい方を使用する。
自己側からの(outbound) TCP コネクションリクエストを発したアプリケーションは、
相手側アプリケーションがコネクションリクエストを受け入れ(accept)るか拒絶(
reject)するかを返答してくるまで待たなければならない。
その場合、TCP ソケットは相手側からのメッセージを期待しているので、そのソケット
は <tt><ref id="tcp_listening_hash" name="tcp_listening_hash"></tt> に加えられ
て、それによって、相手側からの TCP セグメントはその <tt><ref id="sock" 
name="sock"></tt> データ構造体へと誘導される。また、TCP はタイマーをスタート
させて、送信先のアプリケーションがリクエストに対して応答しない場合、自己側から
の(outbound)コネクションリクエストをタイムアウトさせる。

<!--10.4.4  Listening on an INET BSD Socket-->
<sect2>INET BSD ソケット上での待機(listen)

<!--
Once a socket has had an address bound to it, it may listen for incoming
connection requests specifying the bound addresses. A network application
can listen on a socket without first binding an address to it; in this case the
INET socket layer finds an unused port number (for this protocol) and
automatically binds it to the socket. The listen socket function moves the
socket into state TCP_LISTEN and does any network specific work needed
to allow incoming connections. 
-->
<p>ソケットにアドレスが結びつけ(bind)られると、そのソケットは、結びつけ(bind)
られたアドレスを指定した入ってくるコネクションリクエストを待機する(listen)。
ネットワークアプリケーションは、予めソケットにアドレスを結びつけ(bind)なくて
もそのソケット上で待つことができる。
その場合、INET ソケット層が(そのプロトコルに関して)未使用なポート番号を探して、
自動的にそのソケットに結びつけ(bind)る。ソケット関数 listen は、ソケット状態
(state)を TCP_LISTEN 状態へと変更し、入って来る接続を許可するために必要とされ
るそのネットワーク固有のすべての処理を行う。

<!--
For UDP sockets, changing the socket's state is enough but TCP now adds
the socket's sock data structure into two hash tables as it is now active.
These are the tcp_bound_hash table and the tcp_listening_hash.
Both are indexed via a hash function based on the IP port number. 
-->
<p>UDP ソケットの場合、ソケット状態の変更で充分だが、TCP は、その際、アクティ
ブとなったことで、ソケットの <tt><ref id="sock" name="sock"></tt> データ構造体
をふたつのハッシュテーブルに付け加えなければならない。
それらは、<tt><ref id="tcp_listening_hash" name="tcp_bound_hash"></tt> テーブル
と <tt><ref id="tcp_listening_hash" name="tcp_listening_hash"></tt> である。
どちらも、IP ポート番号に基づくハッシュ関数を経由して、インデックス付けされる。

<!--
Whenever an incoming TCP connection request is received for an active
listening socket, TCP builds a new sock data structure to represent it. This
sock data structure will become the bottom half of the TCP connection
when it is eventually accepted. It also clones the incoming sk_buff
containing the connection request and queues it onto the receive_queue
for the listening sock data structure. The clone sk_buff contains a pointer
to the newly created sock data structure. 
-->
<p>入って来る(incoming) TCP コネクションリクエストがアクティブな待機中
(listening)のソケットで受信されたときはいつも、TCP は、それを表す新規の <tt>
<ref id="sock" name="sock"></tt> データ構造体を作成する。
この <tt>sock</tt> データ構造体は、コネクションリクエストが最終的に受け入れ
(accept)られ
たときに、TCP コネクションのボトムハーフ(bottom half)となる。また TCP は、
入って来たコネクションリクエストを含む <tt><ref id="sk_buff" 
name="sk_buff"></tt> を複製(cloning)して、それを、待機(listen)状態
の <tt>sock</tt>データ構造体の <tt><ref id="sock" name="receive_queue"></tt> 
キューに登録する。
複製された <tt>sk_buff</tt> 構造体には、新規に作成された <tt>sock</tt> 構造体
へのポインタが含まれる。

<!--10.4.5  Accepting Connection Requests-->
<sect2>コネクション要求を受け入れる(accept)

<!--
UDP does not support the concept of connections, accepting INET socket
connection requests only applies to the TCP protocol as an accept operation
on a listening socket causes a new socket data structure to be cloned from
the original listening socket. The accept operation is then passed to the
supporting protocol layer, in this case INET to accept any incoming
connection requests. The INET protocol layer will fail the accept operation
if the underlying protocol, say UDP, does not support connections.
Otherwise the accept operation is passed through to the real protocol, in
this case TCP. The accept operation can be either blocking or non-blocking.
In the non-blocking case if there are no incoming connections to accept, the
accept operation will fail and the newly created socket data structure will
be thrown away. In the blocking case the network application performing the
accept operation will be added to a wait queue and then suspended until a
TCP connection request is received. Once a connection request has been
received the sk_buff containing the request is discarded and the sock
data structure is returned to the INET socket layer where it is linked to the
new socket data structure created earlier. The file descriptor (fd) number
of the new socket is returned to the network application, and the
application can then use that file descriptor in socket operations on the
newly created INET BSD socket. 
-->
<p>UDP はコネクションの概念をサポートしていないので、INET ソケット上でのコネク
ションリクエストの受け入れ(accept)は、TCP プロトコルだけに適用される。先ず、
待機(listen)状態のソケット上の accept 操作ルーチンは、その <tt><ref 
id="socket" name="socket"></tt> データ構造体から、新規の <tt>socket</tt> データ
構造体を複製する。
次に accept 操作ルーチンは、入って来る(incoming)コネクションリクエストを受け入
れる(accept)ために、サポートするプロトコル層(layer)、すなわちこの場合 INET 層に
渡される。
INET プロトコル層は、その下位層のプロトコルがコネクションをサポートしていない
場合、たとえば UDP であった場合は、受け入れ(accept)操作に失敗する。
下位層がコネクションをサポートしている場合、accept 操作ルーチンは、実(real)
プロトコル(この場合、TCP)へと渡される。
accept 操作は、ブロックするかしないかのいずれかで行える。
ブロックしない場合で、受け入れるべきコネクションがない場合、accept 操作ルーチン
は失敗し、新規に作成された <tt>socket</tt> データ構造体は破棄される。
ブロックする場合、accept 操作ルーチンを実行しているネットワークアプリケーション
は、待ち行列に加えられ、TCP コネクションリクエストが受信されるまでサス
ペンドする。
コネクションリクエストが受信されたら、そのリクエストを含む <tt><ref 
id="sk_buff" name="sk_buff"></tt> は破棄され、<tt>sock</tt> データ構造体が 
INET ソケット層へと返されて、それより前に新規作成された <tt>socket</tt> データ
構造体にリンクされる。
新規 <tt>socket</tt> のファイル記述子(<tt>fd</tt>)番号が、ネットワーク
アプリケーションに返されるので、アプリケーションは、新規に作成された INET BSD 
ソケットでのソケット操作を、そのファイル記述子を使用して行うことができるよう
になる。

<!--10.5  The IP Layer-->
<sect1>IP 層<label id="chapter_net_sect5">
<p>

<!--10.5.1  Socket Buffers-->
<sect2>ソケットバッファ(socket buffer)

<!--
One of the problems of having many layers of network protocols, each one
using the services of another, is that each protocol needs to add protocol
headers and tails to data as it is transmitted and to remove them as it
processes received data. This make passing data buffers between the
protocols difficult as each layer needs to find where its particular protocol
headers and tails are. One solution is to copy buffers at each layer but that
would be inefficient. Instead, Linux uses socket buffers or sk_buffs to
pass data between the protocol layers and the network device drivers.
sk_buffs contain pointer and length fields that allow each protocol layer to
manipulate the application data via standard functions or ``methods''. 
-->
<p>個々の層が他層のサービスを利用するという、多層構造のネットワークプロトコル
を持つことの問題点は、個々のプロトコルが、送信の際にはヘッダ(header)とテイル
(tail)をデータに付加し、受信データの処理の際にはそれを削除するといった操作が
必要になることである。
個々の層は自分のプロトコルヘッダとテイルがどこにあるのか探す
必要があるので、このことがプロトコル間でのデータバッファの受け渡しを
むずかしくしている。
個々の層でバッファをコピーすることはひとつの解決策であるが、それでは
非効率である。そこで、Linux は、ソケットバッファもしくは <tt><ref id="sk_buff"
 name="sk_buff"></tt> を使用してプロトコル間やネットワークデバイスとの間で
データを受け渡している。<tt>sk_buff</tt> には、ポインタとデータ長(length)の
フィールドが含まれているので、それによって、個々のプロトコル層は、標準関数
か「メソッド(methods)」経由でアプリケーションデータを操作できる。


<!--             Figure 10.4: The Socket Buffer (sk_buff)-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure10-4.gif">
</figure>
</#if>
<#unless output="html">
<verb>
                   sk_buff
              +-----------------+
              | next            |
              |-----------------|
              | prev            |
              |-----------------|
              | dev             |
              |-----------------|
              |                 |
              |                 |
              |-----------------|
              | head            |---+
              |-----------------|   |
              | data            |---+--+
              |-----------------|   |  |
              | tail            |---+--+--+
              |-----------------|   |  |  |
              | end             |---+--+--+---+
   *          |-----------------|<--+  |  |   |
  /|          |                 |      |  |   |
   |          |                 |      |  |   |
   |      *   |-----------------|<-----+  |   |
   |     /|   |                 |         |   |
truesize  |   | 送信されるべき  |         |   |
   |     len  | パケット        |         |   |
   |      |   |                 |         |   |
   |      |/  |                 |         |   |
   |      *   |-----------------|<--------+   |
   |          |                 |             |
   |/         |                 |             |
   *          +-----------------+<------------+
</verb>
</#if>
<p>図表(10.4) ソケットバッファ (sk_buff)

<!--
Figure  10.4 shows the sk_buff data structure; each sk_buff has a block
of data associated with it. The sk_buff has four data pointers, which are
used to manipulate and manage the socket buffer's data: 
-->
<p>図表(10.4)は、<tt><ref id="sk_buff" name="sk_buff"></tt> データ構造体を
示すものである。
個々の <tt>sk_buff</tt> には、一組のデータが関連付けられている。
<tt>sk_buff</tt> には、4 つのデータポインタがあり、それらを使ってソケット
バッファ内のデータ操作と管理がなされる。それら 4 つのポインタとは、次の
ものである。
<newline>[see <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/skbuff.h" 
name="include/linux/skbuff.h">]<newline>

<!--
head points to the start of the data area in memory. This is fixed when
      the sk_buff and its associated data block is allocated, 
data points at the current start of the protocol data. This pointer varies
      depending on the protocol layer that currently owns the sk_buff, 
tail points at the current end of the protocol data. Again, this pointer
      varies depending on the owning protocol layer, 
end points at the end of the data area in memory. This is fixed when the
      sk_buff is allocated. 
-->
<descrip>
<tag>head</tag>
メモリ内のデータ領域の始点を指す。これは、<tt><ref id="sk_buff" 
name="sk_buff"></tt> と関連するデータブロックが割り当てられたときに確定する。

<tag>data</tag>
プロトコルデータの現在の始点を指す。このポインタは、その時点で <tt>
sk_buff</tt> を所有するプロトコル層に依存するため、値は可変である。

<tag>tail</tag>
プロトコルデータの現在の終点を指す。このポインタも所有者たるプロトコル
層依存なので、値は可変である。

<tag>end</tag>
メモリ内のデータ領域の終点を指す。これは、<tt>sk_buff</tt> が
割り当てられたときに確定する。
</descrip>

<!--
There are two length fields len and truesize, which describe the length
of the current protocol packet and the total size of the data buffer
respectively. The sk_buff handling code provides standard mechanisms
for adding and removing protocol headers and tails to the application data.
These safely manipulate the data, tail and len fields in the sk_buff: 
-->
<p><tt><ref id="sk_buff" name="len"></tt> と <tt><ref id="sk_buff" 
name="truesize"></tt> のふたつのデータ長のフィールド(length field)があり、
それぞれ、現在のプロトコルパケットの長さとデータバッファ全体のサイズを
示している。<tt><ref id="sk_buff" name="sk_buff"></tt> 処理コードは、
アプリケーションデータに対するプロトコルヘッダとプロトコルテイルの付加および
削除に対する標準的な仕組みを提供する。
それらは、<tt>sk_buff</tt> 内のデータ、テイル、<tt>len</tt> フィールドを
安全に操作する。<tt>sk_buff</tt> 処理コードには、次のものがある。

<!--
push This moves the data pointer towards the start of the data area and
      increments the len field. This is used when adding data or protocol
      headers to the start of the data to be transmitted, 
-->
<descrip>
<tag>push</tag>
これは、data ポインタをデータ領域の始点方向に移動させ、<tt>len</tt> フィー
ルドを増加(increment)する。これが使用されるのは、送信されるべきデータの先頭に
データやプロトコルヘッダを付加するときである。
<newline>[see: skb_push(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/skbuff.h" 
name="include/linux/skbuff.h">]

<!--
pull This moves the data pointer away from the start, towards the end
      of the data area and decrements the len field. This is used when
      removing data or protocol headers from the start of the data that has
      been received, 
-->
<tag>pull</tag>
これは、data ポインタを始点とは反対側の、データ領域の終点方向へと移動させ
て、<tt>len</tt> フィールドを減少(decrement)する。これが使用されるのは、受信
したデータの先頭からデータやプロトコルヘッダを削除するときである。
<newline>[see: skb_pull(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/skbuff.h" 
name="include/linux/skbuff.h">]

<!--
put This moves the tail pointer towards the end of the data area and
      increments the len field. This is used when adding data or protocol
      information to the end of the data to be transmitted, 
-->
<tag>put</tag>
これは、tail ポインタをデータ領域の終点方向に移動させ、<tt>len</tt> 
フィールドを増加(increment)する。これが使用されるのは、送信されるべきデータの
終点にデータやプロトコル情報を付加するときである。
<newline>[see: skb_put(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/skbuff.h" 
name="include/linux/skbuff.h">]

<!--
trim This moves the tail pointer towards the start of the data area and
      decrements the len field. This is used when removing data or
      protocol tails from the received packet. 
-->
<tag>trim</tag>
これは、tail ポインタをデータ領域の始点方向に移動させ、<tt>len</tt> 
フィールドを減少(decrement)する。これが使用されるのは、受信したデータから
データやプロトコルテイルを削除するときである。
<newline>[see: skb_trim(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/skbuff.h" 
name="include/linux/skbuff.h">]

</descrip>

<!--
The sk_buff data structure also contains pointers that are used as it is
stored in doubly linked circular lists of sk_buff's during processing. There
are generic sk_buff routines for adding sk_buffs to the front and back of
these lists and for removing them. 
-->
<p><tt>sk_buff</tt> データ構造体には、さらにポインタが含まれている。
<tt>sk_buff</tt> は処理の最中に <tt>sk_buff</tt> の二重連結循環リストに保存
されるが、その際に使用されるポインタである。<tt>sk_buff</tt> をそのリストの
先頭や終端に加える際や、そこから削除する際には、そのための汎用的な <tt>
sk_buff</tt> ルーチンが用意されている。


<!--10.5.2  Receiving IP Packets-->
<sect2>IP パケットの受信

<!--
Chapter  dd-chapter described how Linux's network drivers built are into
the kernel and initialized. This results in a series of device data structures
linked together in the dev_base list. Each device data structure
describes its device and provides a set of callback routines that the network
protocol layers call when they need the network driver to perform work.
These functions are mostly concerned with transmitting data and with the
network device's addresses. When a network device receives packets from
its network it must convert the received data into sk_buff data structures.
These received sk_buff's are added onto the backlog queue by the
network drivers as they are received. 
If the backlog queue grows too large, then the received sk_buff's are
discarded. The network bottom half is flagged as ready to run as there is
work to do. 
-->
<p><ref id="chapter_dd_sect6" name="「デバイスドライバ」">の章では、Linux の
ネットワークドライバがカーネルに組み込まれて、初期化される方法を説明した。
それによって、一連の <tt><ref id="device" name="device"></tt> データ構造体が
<tt><ref id="dev_base" name="dev_base"></tt> リストにリンクされた。個々の 
<tt>device</tt> データ構造体は、そのデバイスを記述するとともに、ネットワーク
層がネットワークドライバに処理を実行させる必要があるときに呼び出すことができる
コールバックルーチンのセットを提供する。
これらの関数の大部分はデータ送信とネットワークデバイスのアドレスに関するもの
である。ネットワークデバイスがそのネットワークからパケットを受信したとき、
受信したデータを <tt><ref id="sk_buff" name="sk_buff"></tt> データ構造体に変換
しなければならない。
ネットワークドライバは、それらを受信すると、受信したパケットから作成された 
<tt>sk_buff</tt> を <tt><ref id="sk_buff_head" name="backlog"></tt> キューに
付け加える。
<newline>[see: netif_rr(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/net/core/dev.c" 
name="net/core/dev.c">]<newline>
もし <tt>backlog</tt> キューが大きくなりすぎた場合、受信した <tt>sk_buff</tt> 
は破棄される。ネットワークのボトムハーフ(bottom half)は、仕事ができたので、実行
準備完了(ready to run)のフラグが立つ。

<!--
When the network bottom half handler is run by the scheduler it processes
any network packets waiting to be transmitted before processing the
backlog queue of sk_buff's determining which protocol layer to pass the
received packets to. 
As the Linux networking layers were initialized, each protocol registered
itself by adding a packet_type data structure onto either the ptype_all
list or into the ptype_base hash table. The packet_type data structure
contains the protocol type, a pointer to a network device, a pointer to the
protocol's receive data processing routine and, finally, a pointer to the next
packet_type data structure in the list or hash chain. The ptype_all
chain is used to snoop all packets being received from any network device
and is not normally used. The ptype_base hash table is hashed by protocol
identifier and is used to decide which protocol should receive the incoming
network packet. The network bottom half matches the protocol types of
incoming sk_buff's against one or more of the packet_type entries in
either table. The protocol may match more than one entry, for example when
snooping all network traffic, and in this case the sk_buff will be cloned.
The sk_buff is passed to the matching protocol's handling routine. 
-->
<p>ネットワークボトムハーフハンドラがスケジューラによって実行されるとき、
そのハンドラは、まず送信待ちになっているネットワークパケットをすべて処理
した後に、どのプロトコル層に受信したパケットを渡すか判断して、<tt><ref 
id="sk_buff" name="sk_buff"></tt> の <tt><ref id="sk_buff_head" 
name="backlog"></tt> キューを処理する。
<newline>[see: net_bh(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/net/core/dev.c" 
name="net/core/dev.c">]<newline>
Linux のネットワーク層が初期化されると、個々のプロトコルが登録され、<tt><ref 
id="packet_type" name="packet_type"></tt> データ構造体を <tt>
<ref id="packet_type" name="ptype_all"></tt> リストか <tt><ref 
id="packet_type" name="ptype_base"></tt> ハッシュテーブルに付け加える。
<tt>packet_type</tt> データ構造体には、プロトコルタイプ、ネットワークデバイス
へのポインタ、プロトコルの受信データ処理ルーチンへのポインタ、最後にそのリスト
かハッシュの連結リスト内の次の <tt>packet_type</tt> データ構造体へのポインタが
含まれる。<tt>ptype_all</tt> 配列の連結リストは、すべてのネットワークデバイス
上で
受信された全パケットを探すために利用されるもので、したがって通常は使用されな
い。<tt>ptype_base</tt> ハッシュテーブルはプロトコル識別子をハッシュインデッ
クスとするもので、どのプロトコルが入って来たネットワークパケットを受信すべき
かを決定するために利用される。ネットワークボトムハーフは、入って来た <tt>
sk_buff</tt> のプロトコルタイプが、上記いずれかのテーブルにあるひとつ以上の
 <tt>packet_type</tt> エントリと合致するかどうか調べる。たとえば、すべてのネッ
トワークトラフィックを調査して、そのプロトコルがひとつ以上のエントリにマッチし
た場合、その際には <tt>sk_buff</tt> は複製される。そして、その <tt>
sk_buff</tt> は、合致したプロトコルの処理ルーチンへと送られる。
<newline>[see: ip_recv(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/net/ipv4/ip_input.c" 
name="net/ipv4/ip_input.c">]<newline>

<!--10.5.3  Sending IP Packets-->
<sect2>IP パケットの送信

<!--
Packets are transmitted by applications exchanging data or else they are
generated by the network protocols as they support established connections
or connections being established. Whichever way the data is generated, an
sk_buff is built to contain the data and various headers are added by the
protocol layers as it passes through them. 
-->
<p>パケットは、データ交換をしようとするアプリケーションによって送信される他に、
確立されたコネクションを維持したりコネクションを確立したりするときに、
ネットワークプロトコルによって生成される。しかし、データの生成方法が
どのようなものであっても、そのデータを保持するために <tt><ref id="sk_buff" 
name="sk_buff"></tt> が作成され、プロトコル層を通過する際に、種々のヘッダが
個々のプロトコル層によって付加される。

<!--
The sk_buff needs to be passed to a network device to be transmitted.
First though the protocol, for example IP, needs to decide which network
device to use. This depends on the best route for the packet. For computers
connected by modem to a single network, say via the PPP protocol, the
routing choice is easy. The packet should either be sent to the local host via
the loopback device or to the gateway at the end of the PPP modem
connection. For computers connected to an ethernet the choices are harder
as there are many computers connected to the network. 
-->
<p><tt><ref id="sk_buff" name="sk_buff"></tt> が送信されるには、ネットワーク
デバイスに渡される必要がある。
しかし、それにはまず、IP 等のプロトコルが、どのネットワークデバイスを使用すべき
か判断する必要がある。この判断は、そのパケットにとって何が最適なルートなのかに
よって決まる。たとえば、PPP プロトコル経由で、モデムによって単一のネットワーク
に接続されているコンピュータの場合、ルートの選択は容易である。パケットは、
ループバックデバイス経由でローカルホストに送られるか、PPP によるモデムの
コネクションの反対側にあるゲートウェイに送られるかのいずれかである。
イーサネットで接続されたコンピュータの場合、そのネットワークには多くのコン
ピュータが接続されているので、選択はそれよりも難しくなる。

<!--
For every IP packet transmitted, IP uses the routing tables to resolve the
route for the destination IP address. Each IP destination successfully
looked up in the routing tables returns a rtable 
data structure describing the route to use. This includes the source IP
address to use, the address of the network device data structure and,
sometimes, a prebuilt hardware header. This hardware header is network
device specific and contains the source and destination physical addresses
and other media specific information. If the network device is an ethernet
device, the hardware header would be as shown in Figure  10.1 and the
source and destination addresses would be physical ethernet addresses.
The hardware header is cached with the route because it must be appended
to each IP packet transmitted on this route and constructing it takes time.
The hardware header may contain physical addresses that have to be
resolved using the ARP protocol. In this case the outgoing packet is stalled
until the address has been resolved. Once it has been resolved and the
hardware header built, the hardware header is cached so that future IP
packets sent using this interface do not have to ARP. 
-->
<p>送信されるすべての IP パケットについては、IP がルーティングテーブルを使用
して送信先の IP アドレスに対するルートの解決をする。ルーティングテーブル内で
の個々の IP 送信先の問い合わせが成功した場合、使用すべきルートを示した 
<tt><ref id="rtable" name="rtable"></tt> データ構造体が返される。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/net/route.h" 
name="include/net/route.h">]<newline>
これには、使用すべき送信元 IP アドレス、そのネットワークの <tt><ref 
id="device" name="device"></tt> データ構造体のアドレス、また時には予め
組み込まれたハードウェアヘッダが含まれる。このハードウェアヘッダはネットワーク
デバイス固有のもので、それには送信元と送信先の物理アドレスと、それ以外の
メディア固有の情報が含まれている。ネットワークデバイスがイーサネットデバイスの
場合、ハードウェアヘッダは<ref id="figure10-1" name="図表(10.1)">で示されるよう
なものとなり、送信元と送信先のアドレスはイーサネットの物理アドレスとなる。
ハードウェアヘッダはそのルートとともにキャッシュされるが、それは、そのルート
上で送信されるべき個々の IP パケットにはそのハードウェアのヘッダが付加されなけ
ればならず、その作成には時間がかかるからである。ハードウェアヘッダに
物理アドレスが含まれる場合、そのアドレスは ARP プロトコルを使用して解決
されなければならない。その場合、出て行く(outgoing)パケットは、
その物理アドレスが解決されるまで送信されない。アドレスが解決されてハードウェア
ヘッダが組み込まれたら、ハードウェアヘッダはキャッシュされ、当該インターフェ
イスを使用して送信されるそれ以降の IP パケットは、ARP を使う必要がなくなる。

<!--10.5.4  Data Fragmentation-->
<sect2>データの細分化(fragmentation)

<!--
Every network device has a maximum packet size and it cannot transmit or
receive a data packet bigger than this. The IP protocol allows for this and
will fragment data into smaller units to fit into the packet size that the
network device can handle. The IP protocol header includes a fragment field
which contains a flag and the fragment offset. 
-->
<p>すべてのネットワークデバイスには最大パケットサイズ(maximum packet size)が
あり、それより大きなデータパケットは送信も受信もできない。IP プロトコルはこれに
対処しており、データを小さな断片(fragment)に分割することで、ネットワーク
デバイスが処理できるパケットサイズに合わせるようになっている。
IP プロトコルヘッダにはフラグメント(fragment)フィールドがあり、そこにはフラグ
(flag)とフラグメントオフセット(fragment offset)が含まれている。

<!--
When an IP packet is ready to be transmited, 
IP finds the network device to send the IP packet out on. This device is
found from the IP routing tables. Each device has a field describing its
maximum transfer unit (in bytes), this is the mtu field. If the device's mtu is
smaller than the packet size of the IP packet that is waiting to be
transmitted, then the IP packet must be broken down into smaller (mtu
sized) fragments. Each fragment is represented by an sk_buff; its IP
header marked to show that it is a fragment and what offset into the data
this IP packet contains. The last packet is marked as being the last IP
fragment. If, during the fragmentation, IP cannot allocate an sk_buff, the
transmit will fail. 
-->
<p>IP パケットの送信準備ができたとき、IP はそのパケットを外に送信するネット
ワークデバイスを探す。そのデバイスは IP ルーティングテーブルで見つかる。
<newline>[see: ip_build_xmit(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/net/ipv4/ip_output.c" 
name="net/ipv4/ip_output.c">]<newline>
個々の <tt><ref id="device" name="device"></tt> データ構造体には、その最大転送
単位 
(単位はバイト) を示すフィールドがあり、これは原語の maximum transfer unit を
略し <tt>mtu</tt> フィールドと呼ばれる。
デバイスの <tt>mtu</tt> が、送信を待つ IP パケットのパケットサイズよりも
小さい場合、IP パケットはより小さな(<tt>mtu</tt> サイズの)フラグメントへと
分割されなければならない。個々のフラグメントは <tt><ref id="sk_buff" 
name="sk_buff"></tt> によって表される。
その IP ヘッダは、そのパケットがフラグメントであること、そして
それに含まれるデータがどのようなオフセット値を持つかを示すためのマーク付けが
なされる。その最後のパケットは、最後の IP フラグメントである旨をマークされる。
細分化(fragmentation)の過程で、IP が <tt>sk_buff</tt> を割り当てられない場合
は、その送信は失敗となる。

<!--
Receiving IP fragments is a little more difficult than sending them because
the IP fragments can be received in any order and they must all be received
before they can be reassembled. Each time an IP packet is received it is
checked to see if it is an IP fragment. The first time that the fragment of a
message is received, IP creates a new ipq data structure, and this is linked
into the ipqueue list of IP fragments awaiting recombination. As more IP
fragments are received, the correct ipq data structure is found and a new
ipfrag data structure is created to describe this fragment. Each ipq data
structure uniquely describes a fragmented IP receive frame with its source
and destination IP addresses, the upper layer protocol identifier and the
identifier for this IP frame. When all of the fragments have been received,
they are combined into a single sk_buff and passed up to the next protocol
level to be processed. Each ipq contains a timer that is restarted each time
a valid fragment is received. If this timer expires, the ipq data structure and
its ipfrag's are dismantled and the message is presumed to have been
lost in transit. It is then up to the higher level protocols to retransmit the
message. 
-->
<p>IP フラグメントの受信は、その送信よりもやや面倒である。IP フラグメントは、
順序ばらばらに受信されるかもしれず、それらすべてが受信されてから組み立て直す
必要があるからである。
<newline>[see: ip_rcv(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/net/ipv4/ip_input.c" 
name="net/ipv4/ip_input.c">]<newline>
IP パケットが受信されるたびに、それが IP フラグメントか
否かのチェックがなされる。最初にメッセージのフラグメントが受信された際、IP 
は、新規に <tt><ref id="ipq" name="ipq"></tt> データ構造体を作成し、その構造体
が IP フラグメントの <tt><ref id="ipq" name="ipqueue"></tt> リストにリンクされ
て、再構成されるのを待つ。
より多くの IP フラグメントが受信されると、適切な <tt>ipq</tt> データ構造が
分かるので、新規に <tt><ref id="ipfrag" name="ipfrag"></tt> データ構造体が
作成されて、そのフラグメントを記述する。
個々の <tt>ipq</tt> データ構造体は、IP 受信フレームのフラグメントを一意的に
記述するが、その際には、送信元と送信先の IP アドレス、上位層プロトコルの
識別子、
その IP フレームの識別子が使用される。フラグメントがすべて受信されたとき、
それらは組み立てられて単一の <tt><ref id="sk_buff" name="sk_buff"></tt> とな
り、次の上位層プロトコルへと渡され、処理される。個々の <tt>ipq</tt> には
タイマー
が含まれていて、それは有効なフラグメントが受信されるたびに再始動される。この
タイマーが時間切れになった場合、<tt>ipq</tt> データ構造体と <tt>ipfrag</tt> と
は破棄され、当該データは転送中に喪失したとの推定がなされる。
そのメッセージの再送は、上位層のプロトコルの役割である。

<!--10.6  The Address Resolution Protocol (ARP)-->
<sect1>Address Resolution Protocol (ARP)<label id="chapter_net_sect6">

<!--
The Address Resolution Protocol's role is to provide translations of IP
addresses into physical hardware addresses such as ethernet addresses. IP
needs this translation just before it passes the data (in the form of an
sk_buff) to the device driver for transmission. 
It performs various checks to see if this device needs a hardware header
and, if it does, if the hardware header for the packet needs to be rebuilt.
Linux caches hardware headers to avoid frequent rebuilding of them. If the
hardware header needs rebuilding, it calls the device specific hardware
header rebuilding routine. All ethernet devices use the same generic header
rebuilding routine which in turn uses the ARP services to translate the 
destination IP address into a physical address. 
-->
<p>ARP(Address Resolution Protocol)の役割は、IP アドレスをイーサネットアドレス
のような物理的なハードウェアのアドレスへと変換することである。IP がこの変換
を必要とするのは、送信のために(<tt><ref id="sk_buff" name="sk_buff"></tt> 形式
の)データをデバイスドライバに渡す直前である。
<newline>[see: ip_build_xmit(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/net/ipv4/ip_output.c" 
name="net/ipv4/ip_output.c">]<newline>
IP が実行する種々チェックの中には、そのデバイスがハードウェアヘッダを必要とする
か、必要とする場合はパケットのハードウェアヘッダを再構成(rebuild)する必要がある
かといった項目が存在する。
Linux は、ハードウェアヘッダをキャッシュすることで、それらを頻繁に再構成しない
で済むようにしている。
ハードウェアヘッダの再構成が必要な場合、Linux は、デバイス固有のハードウェア
ヘッダ再構成ルーチンを呼び出す。
<newline>[see: eth_rebuild_header(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/net/ethernet/eth.c" 
name="net/ethernet/eth.c">]<newline>
すべてのイーサネットデバイスは同一の汎用ヘッダ再構成ルーチンを使用するが、その
ルーチンが ARP サービスを利用して送信先 IP アドレスを物理アドレスに変換する。

<!--
The ARP protocol itself is very simple and consists of two message types,
an ARP request and an ARP reply. The ARP request contains the IP
address that needs translating and the reply (hopefully) contains the
translated IP address, the hardware address. The ARP request is broadcast
to all hosts connected to the network, so, for an ethernet network, all of the
machines connected to the ethernet will see the ARP request. The machine
that owns the IP address in the request will respond to the ARP request
with an ARP reply containing its own physical address. 
-->
<p>ARP プロトコルそのものは非常にシンプルであり、ARP リクエスト(要求、request)
と ARP リプライ(応答、reply)のふたつのタイプのメッセージから成っている。
ARP リクエストには、変換に必要な IP アドレスが含まれ、応答には(上手くいけば)
その IP の変換後のアドレスであるハードウェアアドレスが含まれる。ARP リクエスト
は、ネットワークに接続されたすべてのホストにブロードキャストされるので、ある
イーサネットネットワークにおいては、そのイーサネットに繋がるすべてのマシンが 
ARP リクエストを見ることになる。
要求された IP アドレスを所有するマシンがその ARP リクエストに応答し、
自分の物理アドレスを含めた ARP リプライを返す。

<!--
The ARP protocol layer in Linux is built around a table of arp_table data
structures which each describe an IP to physical address translation. These
entries are created as IP addresses need to be translated and removed as
they become stale over time. Each arp_table data structure has the
following fields: 
-->
<p>Linux 上の ARP プロトコル層は <tt><ref id="arp_table" name="arp_table">
</tt> データ構造体のテーブルを中心に構成されていて、個々の構造体が IP から物理
アドレスへの変換を記述している。
それらのエントリは、IP アドレスの変換が必要になったときに作成され、
それらが時間の経過で役に立たなくなったときに削除される。個々の <tt>arp_table
</tt> データ構造体は次のようなフィールドを持つ。

<!--
 last used 
               the time that this ARP entry was last used, 
 last updated 
               the time that this ARP entry was last updated, 
 flags 
               these describe this entry's state, if it is complete and
               so on, 
-->
<descrip>
<tag>last used</tag>
その ARP エントリが最後に使用された時間。

<tag>last update</tag>
その ARP エントリが最後に更新された時間。

<tag>flags</tag>
これらはそのエントリの状態を表す。それが解決済みでまだ有効なアドレスかどうか、
等である。

<!--
 IP address 
               The IP address that this entry describes 
 hardware address 
               The translated hardware address 
 hardware header 
               This is a pointer to a cached hardware header, 
 timer 
               This is a timer_list entry used to time out ARP
               requests 
               that do not get a response, 
-->
<tag>IP address</tag>
そのエントリが示す IP アドレス。

<tag>hardware address</tag>
変換されたハードウェアアドレス。

<tag>hardware header</tag>
これは、キャッシュされたハードウェアヘッダに対するポインタである。

<tag>timer</tag>
これは <tt><ref id="timer_list" name="timer_list"></tt> のエントリであり、
それは応答の返らない ARP リクエストをタイムアウトするために使用される。

<!--
 retries 
               The number of times that this ARP request has been 
               retried, 
 sk_buff queue 
               List of sk_buff entries waiting for this IP address 
               to be resolved
-->
<tag>retries</tag>
その ARP リクエストがリトライした回数。

<tag>sk_buff queue</tag>
IP アドレスの解決を待つ <tt><ref id="sk_buff" name="sk_buff"></tt> エントリの
リスト。
</descrip>

<!--
The ARP table consists of a table of pointers (the arp_tables vector) to
chains of arp_table entries. The entries are cached to speed up access to
them, each entry is found by taking the last two bytes of its IP address to
generate an index into the table and then following the chain of entries until
the correct one is found. Linux also caches prebuilt hardware headers off
the arp_table entries in the form of hh_cache data structures. 
-->
<p>ARP テーブルは、ポインタテーブル(<tt><ref id="arp_table" name="arp_table">
</tt> の配列)から構成され、そのポインタが <tt>arp_table</tt> エントリの連結
リストを指している。
エントリへのアクセス速度を上げるためにそれらはキャッシュされる。個々のエントリ
を探す場合、エントリは、IP アドレスの末尾 2 バイトを取り出してテーブル内で
インデックス付けされているので、そのインデックスを使ってエントリの連結リストを
辿れば、目的のエントリを見つけることができる。
Linux は、予め作成されたハードウェアヘッダもキャッシュしており、それは <tt>
arp_table</tt> エントリの中に <tt><ref id="hh_cache" name="hh_cache"></tt> 
データ構造体の形で入れられている。

<!--
When an IP address translation is requested and there is no corresponding
arp_table entry, ARP must send an ARP request message. It creates a
new arp_table entry in the table and queues the sk_buff containing the
network packet that needs the address translation on the sk_buff queue of
the new entry. It sends out an ARP request and sets the ARP expiry timer
running. If there is no response then ARP will retry the request a number of
times and if there is still no response ARP will remove the arp_table
entry. Any sk_buff data structures queued waiting for the IP address to be
translated will be notified and it is up to the protocol layer that is
transmitting them to cope with this failure. UDP does not care about lost
packets but TCP will attempt to retransmit on an established TCP link. If the
owner of the IP address responds with its hardware address, the
arp_table entry is marked as complete and any queued sk_buff's will
be removed from the queue and will go on to be transmitted. The hardware
address is written into the hardware header of each sk_buff. 
-->
<p>IP アドレス変換が要求されたが、適合する <tt><ref id="arp_table" 
name="arp_table"></tt> エントリが存在しないとき、ARP は ARP リクエスト
メッセージを送信しなければならない。
ARP は、新規に <tt>arp_table</tt> エントリをテーブル内に作成し、アドレス変換を
要するネットワークパケットを含んだ <tt><ref id="sk_buff" name="sk_buff"></tt> 
を 新規エントリの <tt>sk_buff</tt> キューに登録する。
ARP は ARP リクエストを送信し、ARP 時間切れタイマーを走らせる。
応答がない場合、ARP は何度かリクエストを再送してみるが、それでも応答がない場合
は、その <tt>arp_table</tt> のエントリを削除する。エントリの削除は、その 
IP アドレスの変換を待っているキュー上にあるすべての <tt>sk_buff</tt> に
通知される。そして、失敗を上位プロトコル層に送信するのは ARP プロトコル層の
役割である。
UDP はパケットが喪失しても気にしないが、TCP は確立された TCP リンク上で再送を
試みる。もし、IP アドレスの所有者がハードウェアアドレスを付して応答を返した
場合、その <tt>arp_table</tt> エントリは完成(complete)のマークが付けられ、
キュー上にある該当する <tt>sk_buff</tt> はキューから削除されて、送信処理の
過程にまわされる。ハードウェアアドレスは、個々の <tt>sk_buff</tt> の
ハードウェアヘッダの中に書き込まれる。

<!--
The ARP protocol layer must also respond to ARP requests that specfy its
IP address. It registers its protocol type (ETH_P_ARP), generating a
packet_type data structure. This means that it will be passed all ARP
packets that are received by the network devices. As well as ARP replies,
this includes ARP requests. It generates an ARP reply using the hardware
address kept in the receiving device's device data structure. 
-->
<p>ARP プロトコル層は、自身の IP アドレスを指定した ARP リクエストに対する応答
(respond)もしなければならない。ARP は、物理層の ARP リクエストのプロトコル
タイプ(ETH_P_ARP)を登録し、<tt><ref id="packet_type" name="packet_type"></tt> 
データ構造体を生成する。
これは、ネットワークデバイスが受信したすべての ARP パケットが ARP プロトコル層
に渡されることを意味する。このことは、ARP リプライ(reply)の場合だけでなく、ARP 
リクエスト(request)を発するときも同様である。
ARP が ARP リプライを生成するときは、リクエストを受信したデバイスの <tt><ref 
id="device" name="device"></tt> 構造体に保存されたハードウェアアドレスを使用
する。

<!--
Network topologies can change over time and IP addresses can be
reassigned to different hardware addresses. For example, some dial up
services assign an IP address as each connection is established. In order
that the ARP table contains up to date entries, ARP runs a periodic timer
which looks through all of the arp_table entries to see which have timed
out. It is very careful not to remove entries that contain one or more cached
hardware headers. Removing these entries is dangerous as other data
 structures rely on them. Some arp_table entries are permanent and these
are marked so that they will not be deallocated. The ARP table cannot be
allowed to grow too large; each arp_table entry consumes some kernel
memory. Whenever the a new entry needs to be allocated and the ARP table
has reached its maximum size the table is pruned by searching out the
oldest entries and removing them. 
-->
<p>ネットワークトポロジーは時間の経過によって変化することがあるので、IP アドレ
スが以前と異なるハードウェアアドレスに割り当てられることがある。たとえば、
ダイヤルアップサービスの中には、個々のコネクションが確立した時点で IP アドレス
を割り当てるものがある。ARP テーブルが最新の情報を保持するようにするために、
ARP は定期的に実行されて、<tt><ref id="arp_table" name="arp_table"></tt> の全
エントリを走査してタイムアウトになったものがないか確認がなされる。
その際、キャッシュされたハードウェアヘッダをひとつ以上含むエントリを削除してし
まわないよう注意が払われる。他のデータ構造がそれらのエントリに依存しているの
で、削除してしまうことは危険だからである。
ある種の <tt>arp_table</tt> エントリは永続的で、
それらが解放されないよう、その旨マークされている。ARP テーブルは
大きくなりすぎないよう制限されている。個々の <tt>arp_table</tt> エントリは
カーネルメモリを消費するからである。新規にエントリを割り当てる必要が生じたり、
ARP テーブルが最大サイズに達したときはいつも、一番古いエントリを探してそれらを
削除することでテーブルが適度な大きさに保たれる。

<!--10.7  IP Routing-->
<sect1>IP ルーティング<label id="chapter_net_sect7">

<!--
The IP routing function determines where to send IP packets destined for a
particular IP address. There are many choices to be made when transmitting
IP packets. Can the destination be reached at all? If it can be reached, which
network device should be used to transmit it? If there is more than one
network device that could be used to reach the destination, which is the
better one? The IP routing database maintains information that gives
answers to these questions. There are two databases, the most important
being the Forwarding Information Database. This is an exhaustive list of
known IP destinations and their best routes. A smaller and much faster
database, the route cache is used for quick lookups of routes for IP
destinations. Like all caches, it must contain only the frequently accessed
routes; its contents are derived from the Forwarding Information Database. 
-->
<p>IP ルーティング(経路づけ)機能は、特定の IP アドレス宛の IP パケットをどこに
送信すべき
かを決定する。IP パケットを送信する際は多くの選択肢がある。送信先には到達
可能だろうか？ 到達可能なら、送信のためにどのネットワークデバイスを
使用すべきか？ 送信先に到達し得る利用可能なデバイスが複数ある場合、よりよい
デバイスはどれか？ IP ルーティングデータベースは、それらの疑問に答えるための
情報を管理する。ふたつのデータベースが存在するが、最も重要なのは、フォワーディ
ング 情報データベース(Fowarding Information Database)である。
これは既知の IP 送信先とそこへの最良の経路を
漏れなく収めたリストである。それより小規模だが高速なデータベースとしてルート
キャッシュ(route cache)があり、それは IP 送信先に関するすばやい経路問い合わ
せのために使用される。
すべてのキャッシュと同様に、これには頻繁にアクセスされる経路しか含まれてお
らず、その内容は、フォワーディング情報データベースから取り込まれたものである。

<!--
Routes are added and deleted via IOCTL requests to the BSD socket
interface. These are passed onto the protocol to process. The INET protocol
layer only allows processes with superuser privileges to add and delete IP
routes. These routes can be fixed or they can be dynamic and change over
time. Most systems use fixed routes unless they themselves are routers.
Routers run routing protocols which constantly check on the availability of
routes to all known IP destinations. Systems that are not routers are known
as end systems. The routing protocols are implemented as daemons, for
example GATED, and they also add and delete routes via the IOCTL BSD
socket interface. 
-->
<p>経路(route)は、BSD ソケットインターフェイスへの IOCTL リクエストを経由して
追加と削除がなされる。それらはプロトコルに渡されて、処理される。INET 
プロトコル層の場合、IP の経路の追加と削除ができるのは、スーパーユーザ権限を
持ったプロセスだけである。経路は固定することも可能であり、あるいは、時間の
経過によって動的に変更することも可能である。ルータ(router)(訳注: ルータとは、
ネットワークから他のネットワークに、他のシステムが送信したパケットを送り出す
もの)でない限り、大部分の
システムでは固定されたルートが使用されている。ルータはルーティングプロトコルを
実行して、それが既知の送信先の全 IP に対してルーティングできるよう常時チェック
している。ルータでないシステムは、エンドシステム(end system)と呼ばれる。
ルーティングプロトコルは、たとえば GATED のようにデーモンとして実装されている
が、それらも IOCTL BSD ソケットインターフェイス経由で経路を追加したり削除した
りしている。

<!--10.7.1  The Route Cache-->
<sect2>ルートキャッシュ

<!--
Whenever an IP route is looked up, the route cache is first checked for a
matching route. If there is no matching route in the route cache the
Forwarding Information Database is searched for a route. If no route can be
found there, the IP packet will fail to be sent and the application notified. 
If a route is in the Forwarding Information Database and not in the route 
cache, then a new entry is generated and added into the route cache for this 
route. The route cache is a table (ip_rt_hash_table) that contains pointers to
chains of rtable data structures. The index into the route table is a hash
function based on the least significant two bytes of the IP address. These
are the two bytes most likely to be different between destinations and
provide the best spread of hash values. Each rtable entry contains
information about the route; the destination IP address, the network device
to use to reach that IP address, the maximum size of message that can be
used and so on. It also has a reference count, a usage count and a
timestamp of the last time that they were used (in jiffies). 
The reference
count is incremented each time the route is used to show the number of
network connections using this route. It is decremented as applications stop
using the route. The usage count is incremented each time the route is
looked up and is used to order the rtable entry in its chain of hash entries.
The last used timestamp for all of the entries in the route cache is
periodically checked to see if the rtable is too old . 
If the route has not 
been recently used, it is discarded from the route cache. If routes are kept 
in the route cache they are ordered so that the most used entries are at the 
front of the hash chains. This means that finding them will be quicker when 
routes are looked up. 
-->
<p>IP 経路の問い合わせがあるときはいつも、合致する経路がないか、まず
ルートキャッシュがチェックされる。ルートキャッシュに合致する経路がない場合、
経路についてフォワーディング情報データベースが検索される。そこにも経路が
見つからない場合、IP パケットの送信は失敗し、アプリケーションにその旨通知が
なされる。
フォワーディング情報データベースに該当する経路があり、ルートキャッシュに
はない場合、新規のエントリが生成され、ルートキャッシュにその経路が付け加え
られる。
<p>ルートキャッシュは、<tt><ref id="rtable" name="rtable"></tt> データ構造体の
連結リスト(chain)へのポインタを含んだテーブル(<tt><ref id="rtable" 
name="ip_rt_hash_table"></tt>) である。ルートテーブルに対する
インデックスは、IP アドレスの最下位から 2 バイトを基準としてハッシュ関数
により生成される。これらの 2 バイト情報は、たいていの場合送信先によって異なって
いるので、ハッシュ値を散らすには最良である。個々の <tt>rtable</tt> エントリに
は、経路に関する情報が含まれていて、それには、送信先 IP アドレス、その IP 
アドレスに到達するために使用するネットワークデバイス、使用可能なメッセージ
の最大サイズなどがある。またそれは、リファレンスカウント(reference count)、
ユーサージカウント(usage count)、(<tt>jiffies</tt> を使って表された)最終時間の
タイムスタンプ(timestamp of last time)といった情報も持っている。
リファレンスカウントは、その経路が使用されるたびにインクリメントされ、その経路
を使用したネットワークコネクションの数を示す。そして、この経路を使用した
アプリケーションが終了することによりデクリメントされる。ユーサージカウントは
その経路が問い合わせを受けるごとに加算され、ハッシュエントリの連結リスト内の 
<tt>rtable</tt> を処理するために使用される。ルートキャッシュ内のすべての
エントリは、「最後に使用された時間を示すタイムスタンプ」を持っていて、
それは <tt>rtable</tt> が古くなりすぎていないかの定期的なチェックに使用される。
<newline>[see ip_rt_check_expire(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/net/ipv4/route.c" 
name="net/ipv4/route.c">]<newline>
その経路が最近使用されていない場合、それはルートキャッシュから
破棄される。経路がルートキャッシュに保存されている場合、それらは、最も利用
頻度が多いものがハッシュ連結リストの先頭に来るよう並べ替えられる。これによっ
て、経路問い合わせがあった際に、その発見が高速になる。


<!--10.7.2  The Forwarding Information Database-->
<sect2>フォワーディング情報データベース(Forwarding Information Database)
<p>

<!--          Figure 10.5: The Forwarding Information Database-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure10-5.gif">
</figure>
</#if>
<#unless output="html">
<verb>
fib_zones                                  fib_node
+-------+                                +----------+
|       |                             +->| fib_next |
|-------|                             |  |----------|
|       |                             |  | fib_dst  |
|-------|                             |  |----------|
|       |                             |  | fib_use  |    fib_info
|       |     fib_zone                |  |----------|  +-----------+
|-------|  +-------------+            |  | fib_info |->| fib_next  |
|       |->| fz_next     |            |  |----------|  |-----------|
|-------|  |-------------|  +-------+ |  |fib_metric|  | fib_prev  |
|       |  |fz_hash_table|->|       | |  |----------|  |-----------|
|       |  |-------------|  |-------| |  | fib_tos  |  |fib_gateway|
|       |  | fz_list     |  |       | |  +----------+  |-----------|
|       |  |-------------|  |-------| |                | fib_dev   |
|       |  | fz_nent     |  |       | |                |-----------|
|       |  |-------------|  |       | |                | fib_refcnt|
|       |  | fz_logmask  |  |-------| |                |-----------|
|       |  |-------------|  |       |-+                | fib_window|
|-------|  | fz_mask     |  |-------|                  |-----------|
|       |  +-------------+  |       |                  | fib_flags |
|-------|                   |       |      fib_node    |-----------|
|       |                   |-------|    +----------+  | fib_mtu   |
+-------+                   |       |--->| fib_next |  |-----------|
                            |-------|    |----------|  | fib_irtt  |
                            |       |    | fib_dst  |  +-----------+
                            |       |    |----------|
                            |       |    | fib_use  |    fib_info
                            |-------|    |----------|  +-----------+
                            |       |    | fib_info |->| fib_next  |
                            |-------|    |----------|  |-----------|
                            |       |    |fib_metric|  | fib_prev  |
                            +-------+    |----------|  |-----------|
                                         | fib_tos  |  |fib_gateway|
                                         +----------+  |-----------|
                                                       | fib_dev   |
                                                       |-----------|
                                                       | fib_refcnt|
                                                       |-----------|
                                                       | fib_window|
                                                       |-----------|
                                                       | fib_flags |
                                                       |-----------|
                                                       | fib_mtu   |
                                                       |-----------|
                                                       | fib_irtt  |
                                                       +-----------+
</verb>
</#if>
<p>図表(10.5) フォワーディング情報データベース


<!--
The forwarding information database (shown in Figure  10.5 contains IP's
view of the routes available to this system at this time. It is quite a
complicated data structure and, although it is reasonably efficiently
arranged, it is not a quick database to consult. In particular it would be very
slow to look up destinations in this database for every IP packet
transmitted. This is the reason that the route cache exists: to speed up IP
packet transmission using known good routes. The route cache is derived
from the forwarding database and represents its commonly used entries. 
-->
<p>フォワーディング情報データベース(図表(10.5)参照)には、IP アドレスから見た、
その時点においてシステム上で利用可能な経路の一覧が含まれる。
それは非常に複雑なデータ構造をしていて、妥当な効率を得られるようアレンジされて
はいるが、高速で問い合わせが可能なデータベースではない。
特に、送信されるべきすべての IP パケットについて送信先をこのデータベースに
問い合わせるとしたら、検索は非常に遅いものになるだろう。
ルートキャッシュが存在するのは、そのためである。既存の適切な経路を
使って IP パケットを高速に送信するわけである。ルートキャッシュはこの 
フォワーディング情報データベースから派生したもので、よく利用されるエントリを
表したものである。

<!--
Each IP subnet is represented by a fib_zone data structure. All of these
are pointed at from the fib_zones hash table. The hash index is derived
from the IP subnet mask. All routes to the same subnet are described by
pairs of fib_node and fib_info data structures queued onto the
fz_list of each fib_zone data structure. If the number of routes in this
subnet grows large, a hash table is generated to make finding the
fib_node data structures easier. 
-->
<p>個々の IP サブネットは <tt><ref id="fib_zone" name="fib_zone"></tt> データ
構造体によって表される。
それらのすべては <tt>fib_zones</tt> ハッシュテーブルからポインタ参照されて
いる。ハッシュのインデックスは、その IP サブネットのマスクから生成
されている。同一サブネットに対するすべての経路(route)は、<tt><ref 
id="fib_node" name="fib_node"></tt> と <tt><ref id="fib_info" name="fib_info">
</tt> データ構造体のペアによって記述されていて、それらは、個々の <tt>fib_zone
</tt> データ構造体内の <tt><ref id="fib_zone" name="fz_list"></tt> キューに
登録されている。
そのサブネットの経路の数が増えた場合、ハッシュテーブルが
生成されて、<tt>fib_node</tt> データ構造体の発見を容易にする。

<!--
Several routes may exist to the same IP subnet and these routes can go
through one of several gateways. The IP routing layer does not allow more
than one route to a subnet using the same gateway. In other words, if there
are several routes to a subnet, then each route is guaranteed to use a
different gateway. Associated with each route is its metric. This is a
measure of how advantagious this route is. A route's metric is, essentially,
the number of IP subnets that it must hop across before it reaches the
destination subnet. The higher the metric, the worse the route. 
-->
<p>同一の IP サブネットに対していくつかの経路がある場合があり、それらの
経路は複数のゲートウェイのひとつを通過できる。IP ルーティング層は、
同一サブネットへの複数の経路が同じゲートウェイを使用することは許さない。
言い換えると、あるサブネットへの経路が複数ある場合、個々の経路は
必ず異なるゲートウェイを使用することが保証される。個々の経路に関連付けられ
るのがメトリック(metric)である。これは、その経路がどれだけ最短に近いかを示す
指標である。経路のメトリックは、本質的には、宛先のサブネットに到達するまで
に経由しなければならない IP サブネットの数である。メトリックが大きくなるに
つれて、その経路は最短経路から遠くなる。


<!--
Footnotes:

1 National Science Foundation 

2 Synchronous Read Only Memory 

3 duh? What used for? 
-->
<label id="chapter_net_fn">
<footnote>
(脚注1) National Science Foundation<newline>

(脚注2) Serial Read Only Memory<newline>

(脚注3) で、何のために？<newline>
</footnote>

<!--第 12 章 カーネルメカニズム-->
<!--Chapter 11 Kernel Mechanisms-->
<sect>カーネルメカニズム<label id="chapter_km">
<p>
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/penguin2.gif">
</figure>

<!--
This chapter describes some of the general tasks and mechanisms that the
Linux kernel needs to supply so that other parts of the kernel work
effectively together. 
-->
<p>この章では、Linux カーネルが提供しなければならない汎用的なタスクとメカニズム
のいくつかについて解説する。それらは、カーネルの他の部分(すなわちこの章で述べら
れるいくつかのタスクやメカニズム以外の部分)が効率よく協調動作するために必要なも
のである。

<!--11.1  Bottom Half Handling-->
<sect1>ボトムハーフハンドラ<label id="chapter_km_sect1">
<p>

<!--          Figure 11.1: Bottom Half Handling Data Structures-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure11-1.gif">
</figure>
</#if>
<#unless output="html">
<verb>

          bh_active
31                            0          bh_base
+-----------------------------+     +---------------+
|                             |   0 |               |-->ボトムハーフ
|                             |     |---------------|   ハンドラ
+-----------------------------+     |               |   (timers)
                                    |---------------|
           bh_mask                  |               |
31                            0     |               |
+-----------------------------+     |               |
|                             |     |               |
|                             |     |               |
+-----------------------------+     |               |
                                    |               |
                                    |               |
                                    |---------------|
                                    |               |
                                    |---------------|
                                 31 |               |
                                    +---------------+
</verb>
</#if>
<p>図表(11.1) ボトムハーフハンドラのデータ構造

<!--
There are often times in a kernel when you do not want to do work at this
moment. A good example of this is during interrupt processing. When the
interrupt was asserted, the processor stopped what it was doing and the
operating system delivered the interrupt to the appropriate device driver.
Device drivers should not spend too much time handling interrupts as, during
this time, nothing else in the system can run. There is often some work that
could just as well be done later on. Linux's bottom half handlers were
invented so that device drivers and other parts of the Linux kernel could
queue work to be done later on. Figure  11.1 shows the kernel data
structures associated with bottom half handling. 
-->
<p>カーネルにタスク処理をさせる場合、この時点では処理をさせたくない、という時が
しばしばある。割り込みを処理させる場合は、特にそうである。割り込みが起こると、
プロセッサは実行中の処理を停止し、オペレーティングシステムがその割り込みを適切
なデバイスドライバに伝達する。しかし、デバイスドライバに割り込みを処理させる
場合、割り込み処理中には、システム上で他の処理を実行できない。したがって、デバ
イスドライバは、割り込みの処理にあまり時間を掛けてはいけない。他方、その場で直
ぐに処理せずとも、何の問題もないケースもしばしば存在する。Linux のボトムハーフ
ハンドラが発明されたのは、デバイスドライバやその他のカーネルルーチンがそうした
仕事を一旦キュー上に置いて、あとで処理できるようにするためである。図表(11.1)で
は、ボトムハーフハンドラに関するカーネルのデータ構造体が示されている。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/interrupt.h" 
name="include/linux/interrupt.h">]<newline>

<!--
There can be up to 32 different bottom half handlers; bh_base is a vector of
pointers to each of the kernel's bottom half handling routines. bh_active
and bh_mask have their bits set according to what handlers have been
installed and are active. If bit N of bh_mask is set then the Nth element of
bh_base contains the address of a bottom half routine. If bit N of
bh_active is set then the N'th bottom half handler routine should be
called as soon as the scheduler deems reasonable. These indices are
statically defined; the timer bottom half handler is the highest priority 
(index 0), the console bottom half handler is next in priority (index 1) and 
so on. Typically the bottom half handling routines have lists of tasks 
associated with them. For example, the immediate bottom half handler works 
its way through the immediate tasks queue (tq_immediate) which contains tasks
that need to be performed immediately. 
-->
<p>32 個までの異なるボトムハーフハンドラが存在し得る。
<tt><htmlurl url="./The-Linux-Kernel-images/linux/include/linux/interrupt.h" 
name="bh_base"></tt> は、
カーネルの個々のボトムハーフ処理ルーチンへのポインタのテーブルである。<tt>
bh_active</tt> と <tt>bh_mask</tt> は独自のビットセットを持っていて、その値
はどのようなハンドラがインストールされてアクティブになっているのかによる。
<tt>bh_mask</tt> にビット N がセットされた場合、<tt>bh_base</tt> の N 番目の
要素がそのボトムハーフハンドラのアドレスを含んでいる。<tt>bh_active</tt> に
ビット N がセットされた場合、スケジューラが合理的と考えた直後に N 番目の
ボトムハーフハンドラルーチンが呼び出される。それらのインデックスは静的に
定義されている。タイマー(timer)ボトムハーフハンドラは最優先であり(index 0)、
コンソール(console)ボトムハーフハンドラはそれに次ぐ優先度を持つ(index 1)等
である。
典型的には、ボトムハーフハンドラはそれらと関連したタスクのリストを持っている。
たとえば、イミディエート(immediate)ボトムハーフハンドラはイミディエートタスク
キュー(<tt><htmlurl url="./The-Linux-Kernel-images/linux/kernel/sched.c" 
name="tq_immediate"></tt>)
を通じて処理を行うが、そのキューには即座に(immediately)処理される必要のある
タスクが含まれる。

<!--
Some of the kernel's bottom half handers are device specific, but others are
more generic: 
-->
<p>カーネルのボトムハーフハンドラのいくつかは、デバイス固有のものであるが、
それ以外は汎用的である。

<!--
TIMER
      This handler is marked as active each time the system's periodic
      timer interrupts and is used to drive the kernel's timer queue
      mechanisms, 
CONSOLE
      This handler is used to process console messages, 
TQUEUE
      This handler is used to process tty messages, 
NET This handler handles general network processing, 
IMMEDIATE
      This is a generic handler used by several device drivers to queue
      work to be done later. 
-->
<descrip>
<tag>TIMER</tag>
このハンドラは、システムの定時的なタイマーが割り込むときに、いつもアクティブと
マークされ、カーネルのタイマーキューメカニズムを駆動するために使用される。

<tag>CONSOLE</tag>
このハンドラは、コンソールメッセージを処理するために使用される。

<tag>TQUEUE</tag>
このハンドラは、<tt>tty</tt> メッセージを処理するために使用される。

<tag>NET</tag>
このハンドラは、一般的なネットワーク処理をこなす。

<tag>IMMEDIATE</tag>
これは汎用ハンドラであり、いくつかのデバイスドライバが後で行おうとする仕事を
キューに入れるために使用される。
</descrip>

<!--
Whenever a device driver, or some other part of the kernel, needs to
schedule work to be done later, it adds work to the appropriate system
queue, for example the timer queue, and then signals the kernel that some
bottom half handling needs to be done. It does this by setting the appropriate
bit in bh_active. Bit 8 is set if the driver has queued something on the
immediate queue and wishes the immediate bottom half handler to run and
process it. The bh_active bitmask is checked at the end of each system
call, just before control is returned to the calling process. If it has any 
bits set, the bottom half handler routines that are active are called. Bit 0 is
checked first, then 1 and so on until bit 31. 
The bit in bh_active is cleared as each bottom half handling routine is
called. bh_active is transient; it only has meaning between calls to the
scheduler and is a way of not calling bottom half handling routines when
there is no work for them to do. 
-->
<p>デバイスドライバやカーネルの他の部分が仕事を後回しにする必要があるときは
いつも、その仕事を、たとえばタイマーキューのような、適切なキューに置き、
カーネルにシグナルを送って、ボトムハーフ処理の実行が必要であることを伝える。
それをするには、<tt><htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/interrupt.h" 
name="bh_active"></tt> の適切なビットを設定すればよい。
たとえば、ビット 8 が設定されるのは、ドライバが何かをイミディエートキュー上に
置いて、ボトムハーフハンドラが実行されて処理されるのを望む場合である。
<tt>bh_active</tt> のビットマスクがチェックされるのは、個々のシステムコールの
終了時であり、制御が呼び出しプロセスに戻る直前である。
何らかのビットがセットされていた場合、アクティブなボトムハーフハンドラが
呼び出される。ビット 0 がまず最初にチェックされて、次に 1 へと順次進んで、
31 までチェックされる。
<newline>[see: do_bottom_half(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/kernel/softirq.c" 
name="kernel/softirq.c">]<newline>
<tt>bh_active</tt> のビットは、個々のボトムハーフハンドラが呼び出されるたびに
クリアされる。すなわち、<tt>bh_active</tt> は一時的なもので、スケジューラが
呼び出されたその時点では意味を持つが、次の呼び出しがなされる際には意味を持たな
い。したがって、この方法を使えば、処理すべき仕事がない場合、ボトムハーフ処理
ルーチンは呼び出されない。

<!--11.2  Task Queues-->
<sect1>タスクキュー(task queue)<label id="chapter_km_sect2">
<p>


<!--                  Figure 11.2: A Task Queue-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure11-2.gif">
</figure>
</#if>
<#unless output="html">
<verb>
                tq_struct               tq_struct
task_quequ   +-------------+         +-------------+
------------>| next        |-------->| next        |-------->
             |-------------|         |-------------|
             | sync        |         | sync        |
             |-------------|         |-------------|
             | *routine()  |         | *routine()  |
             |-------------|         |-------------|
             | *data       |         | *data       |
             +-------------+         +-------------+
</verb>
</#if>
<p>図表(11.2) タスクキュー

<!--
Task queues are the kernel's way of deferring work until later. Linux has a
generic mechanism for queuing work on queues and for processing them
later. Task queues are often used in conjunction with bottom half handlers; the
timer task queue is processed when the timer queue bottom half handler
runs. A task queue is a simple data structure, see figure  11.2 which
consists of a singly linked list of tq_struct data structures each of which
contains the address of a routine and a pointer to some data. 
The routine will be called when the element on the task queue is processed
and it will be passed a pointer to the data. 
-->
<p>タスクキューは、カーネルが仕事を後回しにする方法である。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/tqueue.h" 
name="include/linux/tqueue.h">]<newline>
Linux には、仕事をキュー上に置いて、後で処理をする汎用的なメカニズムがある。
タスクキューはしばしばボトムハーフハンドラと一緒に使用される。タイマータスク
キュー(timer task queue)は、タイマーキューボトムハーフハンドラ(timer queue 
bottom half handler)が実行されるときに処理される。
タスクキューはシンプルなデータ構造体であり、図表(11.2)に示されるように、<tt>
<ref id="tq_struct" name="tq_struct"></tt> データ構造体の単純な連結リストであ
る。その個々の構造体には、ルーチンのアドレスとデータへのポインタが含まれてい
る。タスクキュー上の要素が処理されるとき、ルーチンが呼び出され、その際、ルーチ
ンへはデータへのポインタが渡される。

<!--
Anything in the kernel, for example a device driver, can create and use task
queues but there are three task queues created and managed by the kernel: 
-->
<p>カーネル内の何らかのルーチン、たとえばデバイスドライバは、タスクキューを
作成し利用することができるが、次の 3 つのタスクキューは、カーネルによって
作成され管理されている。

<!--
timer This queue is used to queue work that will be done as soon after the
      next system clock tick as is possible. Each clock tick, this queue is
      checked to see if it contains any entries and, if it does, the timer
      queue bottom half handler is made active. The timer queue bottom
      half handler is processed, along with all the other bottom half
      handlers, when the scheduler next runs. This queue should not be
      confused with system timers, which are a much more sophisticated
      mechanism. 
-->
<descrip>
<tag>timer</tag>
このキューは、次のシステムクロックティック(clock tick)の出来るだけ直後に実行さ
れるべき仕事をキューイングするために使用される。
クロックティックごとにこのキューがチェックされ、エントリが含まれているかどうか
確認される。エントリが含まれていた場合、タイマーキューボトムハーフハンドラが
アクティブにされる。
スケジューラが次に実行される時には、タイマーキューボトムハーフハンドラが、
その他すべてのボトムハーフハンドラと伴に処理される。
このキューとシステムタイマーを混同してはいけない。後者は、ずっと洗練された
メカニズムを持っている。

<!--
immediate
      This queue is also processed when the scheduler processes the
      active bottom half handlers. The immediate bottom half handler is
      not as high in priority as the timer queue bottom half handler and so
      these tasks will be run later. 
-->
<tag>immediate</tag>
このキューも、スケジューラがアクティブなボトムハーフハンドラを処理するときに
処理される。イミディエート(immediate)ボトムハーフハンドラは、タイマーキュー
ボトムハーフハンドラほど優先順位は高くないので、これらのタスクは後から実行
される。

<!--
scheduler
      This task queue is processed directly by the scheduler. It is used to
      support other task queues in the system and, in this case, the task
      to be run will be a routine that processes a task queue, say for a
      device driver. 
-->
<tag>scheduler</tag>
このタスクキューは、スケジューラ自身によって処理される。これは、システム上の
他のタスクキューをサポートするために使用されるので、この場合、実行されるべき
タスクは、タスクキューを処理するルーチン、たとえば、デバイスドライバである。
</descrip>

<!--
When task queues are processed, the pointer to the first element in the
queue is removed from the queue and replaced with a null pointer. In fact,
this removal is an atomic operation, one that cannot be interrupted. Then
each element in the queue has its handling routine called in turn. The
elements in the queue are often statically allocated data. However there is
no inherent mechanism for discarding allocated memory. The task queue
processing routine simply moves onto the next element in the list. It is the
job of the task itself to ensure that it properly cleans up any allocated 
kernel memory. 
-->
<p>タスクキューが処理されるとき、キューの最初の要素に対するポインタがキュー
から削除されて、ヌルポインタ(null pointer)と置き換えられる。実際、この削除
処理は、排他的な操作(atomic operation)なので、割り込みできないように
なっている。次に、キュー上の個々の要素が自分の処理ルーチンを順番に呼び出す。
キュー上の要素はしばしば静的に割り当てられたデータである。しかし、割り当て
られたメモリを破棄する固有のメカニズムは存在しない。タスクキュー処理ルーチン
は単にリスト上の次の要素の処理に移るだけである。割り当てられたカーネルメモリ
を確実に適宜再利用可能にするためには、タスク自体がその処理をしなければならな
い。

<!--11.3  Timers-->
<sect1>タイマー(timer)<label id="chapter_km_sect3">
<p>

<label id="figure11-3">
<!--                  Figure 11.3: System Timers-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure11-3.gif">
</figure>
</#if>
<#unless output="html">
<verb>
     timer_table           timer_struct
   +-------------+         +-----------+
 0 |             |-------->| expires   |
   |-------------|         |-----------|
   |             |         | *fn()     |
   |-------------|         +-----------+
   |             |
   |             |         timer_struct
   |-------------|         +-----------+
   |             |-------->| expires   |
   |-------------|         |-----------|
   |             |         | *fn()     |
   |             |         +-----------+
   |-------------|
   |             |     31       timer_active             0
   |-------------|     +----------------------------------+
31 |             |     |                                  |
   +-------------+     +----------------------------------+


     timer_head              timer_head              timer_head
   +--------------+        +--------------+        +--------------+
   | next         |------->| next         |------->| next         |
   |--------------|        |--------------|        |--------------|
   | prev         |<-------| prev         |<-------| prev         |
   |--------------|        |--------------|        |--------------|
   | expires      |        | expires      |        | expires      |
   |--------------|        |--------------|        |--------------|
   | data         |        | data         |        | data         |
   |--------------|        |--------------|        |--------------|
   | *function()  |        | *function()  |        | *function()  |
   +--------------+        +--------------+        +--------------+
</verb>
</#if>
<p>図表(11.3) システムタイマー

<!--
An operating system needs to be able to schedule an activity sometime in
the future. A mechanism is needed whereby activities can be scheduled to
run at some relatively precise time. Any microprocessor that wishes to
support an operating system must have a programmable interval timer that
periodically interrupts the processor. This periodic interrupt is known as a
system clock tick and it acts like a metronome, orchestrating the system's
activities. 
Linux has a very simple view of what time it is; it measures time in clock
ticks since the system booted. All system times are based on this
measurement, which is known as jiffies after the globally available
variable of the same name. 
-->
<p>オペレーティングシステムには、将来の特定の時間にタスクを処理できるような
スケジューリング機能が必要である。そして、スケジューリングにより、タスクを
比較的正確な時間に実行できるようなメカニズムが必要とされる。この点、オペレーテ
ィングシステムをサポートしようとするプロセッサには、必ずプログラム可能なイン
ターバルタイマーがあり、それが定期的にプロセッサに割り込みを掛けている。この
定期的な割り込みは、システムクロックティックと呼ばれる。それは、メトロノームに
似た働きをして、システムの活動を指揮している。
Linux は時刻管理に対して非常にシンプルな見方をしている。
Linux は、時間を起動時からのクロックティック(clock tick)によって計る。すべての
システムタイマーはその計測を基にしており、その計測方法は、広く利用されている
変数名にちなんで <tt>jiffies</tt> と呼ばれている。

<!--
Linux has two types of system timers, both queue routines to be called at
 some system time but they are slightly different in their implementations.
Figure  11.3 shows both mechanisms. 
The first, the old timer mechanism, has a static array of 32 pointers to
timer_struct data structures and a mask of active timers,
timer_active. 
Where the timers go in the timer table is statically defined (rather like the
bottom half handler table bh_base). Entries are added into this table
mostly at system initialization time. The second, newer, mechanism uses a
linked list of timer_list data structures held in ascending expiry time
order. 
-->
<p>Linux には二種類のシステムタイマーがある。どちらのキュールーチンも、ある
システム時間に呼び出されるのだが、それらは実装においてやや異なっている。
<ref id="figure11-3" name="図表(11.3)"> では、両方のメカニズムが示されている。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/timer.h" 
name="include/linux/timer.h">]<newline>
ひとつめは、古いタイマーメカニズムであり、<tt><ref id="timer_struct" 
name="timer_struct"></tt> データ構造体への 32 個のポインタによる静的配列と
アクティブタイマーのマスク <tt><ref id="timer_struct" name="timer_active">
</tt> から構成されている。
タイマーがタイマーテーブル内のどこに置かれるかは、静的に定義されている。
(これは、ボトムハーフハンドラのテーブル <tt>bh_base</tt> にやや似ている。)
エントリがこのテーブルに付け加えられるのは、大抵の場合システム起動時である。
ふたつめは、それより新しいメカニズムであり、<tt><ref id="timer_list" 
name="timer_list"></tt> データ構造体の連結リストを使用する。リストの要素は、
タイマー終了までの残り時間(expire time)の長さの順番で並べられている。

<!--
Both methods use the time in jiffies as an expiry time so that a timer
that wished to run in 5s would have to convert 5s to units of jiffies and
add that to the current system time to get the system time in jiffies
when the timer should expire. Every system clock tick the timer bottom half
handler is marked as active so that the when the scheduler next runs, the
timer queues will be processed. The timer bottom half handler processes
both types of system timer. For the old system timers the timer_active
bit mask is check for bits that are set. 
If the expiry time for an active timer has expired (expiry time is less than
the current system jiffies), its timer routine is called and its active bit is
cleared. For new system timers, the entries in the linked list of
timer_list data structures are checked. 
Every expired timer is removed from the list and its routine is called. The
new timer mechanism has the advantage of being able to pass an argument
to the timer routine. 
-->
<p>どちらの方法の場合でも、タイマーの残り時間を計る際の指標として <tt>jiffies
</tt> を使用する。
それゆえ、5 秒間だけ実行されるタイマーは、まず 5 秒という時間を <tt>jiffies
</tt> の単位に変換して、それを現在のシステム時間に加算することで、タイマーが
終了すべき時刻を <tt>jiffies</tt> 形式のシステム時間として獲得する。
システムクロックティッごとに、タイマーボトムハーフハンドラはアクティブとマーク
され、それによって、スケジューラが次に起動されるときに、タイマーキューが処理
される。タイマーボトムハーフハンドラは、両方のタイプのシステムタイマーを処理す
る。古いほうのシステムタイマーの場合、<tt>timer_active</tt> ビットマスクがチェ
ックされ、設定ビットが確認される。
<newline>[see: timer_bh(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/kernel/sched.c" 
name="kernel/sched.c">]
<newline>[see: run_old_timers(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/kernel/sched.c" 
name="kernel/sched.c">]
<newline>[see: run_timer_list(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/kernel/sched.c" 
name="kernel/sched.c">]<newline>
アクティブタイマーの終了時間が経過した場合
(終了時間の値がシステムの <tt>jiffies</tt> の現在値よりも小さい場合)、
そのタイマールーチンが呼び出され、アクティブビットはクリアされる。新しい
システムタイマーの場合、<tt>timer_list</tt> 構造体の連結リストのエントリが
チェックされる。すべての終了時間タイマーがリストから削除され、そのルーチンが
呼び出される。新しいタイマーのメカニズムには、タイマールーチンに引数を渡せる
という利点がある。

<!--11.4  Wait Queues-->
<sect1>待ち行列(wait queue)<label id="chapter_km_sect4">

<!--
There are many times when a process must wait for a system resource. For
example a process may need the VFS inode describing a directory in the file
system and that inode may not be in the buffer cache. In this case the
process must wait for that inode to be fetched from the physical media
containing the file system before it can carry on. 
-->
<p>プロセスは、何らかのシステムリソースを待たなければならない状態になること
がよくある。たとえば、あるプロセスがファイルシステム上のあるディレクトリを記述
する VFS inode を必要としていのだが、その inode がバッファキャッシュにない時
などである。
その場合、そのプロセスは、そのフィアルシステムを保持する物理メディアから
当該 inode が持ってこられるまで待ってから、処理を継続しなければならない。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/wait.h" 
name="include/linux/wait.h">]

<verb>
                        wait_queue 
                          *task 
                          *next

                    図表(11.4) 待ち行列

</verb>


<!--                   Figure 11.4: Wait Queue-->

<!--
The Linux kernel uses a simple data structure, a wait queue (see figure 
11.4), which consists of a pointer to the processes task_struct and a pointer 
to the next element in the wait queue. 
-->
<p>Linux カーネルはシンプルなデータ構造体である <tt><ref id="wait_queue" 
name="wait_queue"></tt> (図表(11.4)を参照)(訳注: この図表は原文においても GIF 
ファイルではありません。)を使用しているが、これは、<tt><ref id="task_struct" 
name="task_struct"></tt> のプロセスへのポインタと、待ち行列内の次の要素への
ポインタから構成されている。

<!--
When processes are added to the end of a wait queue they can either be
interruptible or uninterruptible. Interruptible processes may be interrupted by
events such as timers expiring or signals being delivered whilst they are
waiting on a wait queue. The waiting processes state will reflect this and
either be INTERRUPTIBLE or UNINTERRUPTIBLE. As this process can not
now continue to run, the scheduler is run and, when it selects a new process
to run, the waiting process will be suspended. 1 
-->
<p>プロセスが待ち行列の終端に付け加えられるとき、そのプロセスは、割り込み可能
か割り込み不可能かのいずれの場合もあり得る。割り込み可能なプロセスは、たとえば
タイマー
の終了といったイベントや、待ち行列上で待っている間に受信したシグナルによって
割り込まれるかもしれない。待ち行列上のプロセスの状態(state)はそれを反映して
いて、その状態は INTERRUPTIBLE(割り込み可能) か UNINTERRUPTIBLE(割り込み不可)
 のいずれかである。待ち行列上に置かれたプロセスは 現時点では動作させつづけられ
ず、スケジューラが次ぎのプロセスを選んだときに、その待ちプロセスはサスペンド状
態となる。(<ref id="chapter_km_fn" name="脚注 1">)

<!--
When the wait queue is processed, the state of every process in the wait
queue is set to RUNNING. If the process has been removed from the run
queue, it is put back onto the run queue. The next time the scheduler runs,
the processes that are on the wait queue are now candidates to be run as
they are now no longer waiting. When a process on the wait queue is
scheduled the first thing that it will do is remove itself from the wait queue.
Wait queues can be used to synchronize access to system resources and
they are used by Linux in its implementation of semaphores (see below). 
-->
<p>待ち行列が処理されるとき、待ち行列上のすべてのプロセスの状態(state)は、
RUNNING(実行中)にセットされる。
プロセスが実行キューから削除されていた場合は、再度実行キュー上に置かれる。
スケジューラが次に実行されるとき、待ち行列上にあるプロセスは、もう今は待ち
状態ではないので、実行されるべき候補者となっている。
待ち行列上のプロセスがスケジューラによって実行されるとき、それが最初に行う
ことは、自分を待ち行列上から削除することである。待ち行列はシステムリソースへの
アクセスを同期させるためにも使用できるので、Linux はそれらを使って、セマフォ
を実装している。

<!--11.5  Buzz Locks-->
<sect1>バズロック (Buzz Locks)<label id="chapter_km_sect5">

<!--
These are better known as spin locks and they are a primitive way of
protecting a data structure or piece of code. They only allow one process at
a time to be within a critical region of code. They are used in Linux to
restrict access to fields in data structures, using a single integer field as a
lock. Each process wishing to enter the region attempts to change the
lock's initial value from 0 to 1. If its current value is 1, the process tries
again, spinning in a tight loop of code. The access to the memory location
holding the lock must be atomic, the action of reading its value, checking
that it is 0 and then changing it to 1 cannot be interrupted by any other
process. Most CPU architectures provide support for this via special
instructions but you can also implement buzz locks using uncached main
memory. 
-->
<p>これは、スピンロック(spin locks)と呼ばれることのほうが多い仕組みであり、
データ構造やコードを保護するプリミティブな方法である。これは、一度にひとつの
プロセスしか重要なコード領域に入れないようにするものである。
Linux においては、データ構造体のフィールドへのアクセスを制限するために利用され
るのだが、その際、一つの単精度整数フィールドを使用したロックの仕組みを提供して
いる。
その領域に入ろうとする個々のプロセスは、ロックの初期値を 0 から 1 へと変更しよ
うとする。現在値が 1 の場合、タイトループ(tight loop)のコード内でスピニング
(spining)しながら、再度それを試みる。
そのロック機構を保持するメモリ領域へのアクセスは排他的(atomic)なものでなけれ
ばならず、その値の読み出し、それが 0 であることの検証、そしてその値の 1 への
変更といった処理は、他のプロセスから割り込まれることがない。大部分の CPU 
アーキテクチャでは、特別な命令によってこの仕組みをサポートしているが、
キャッシュされていないメインメモリを利用してバズロック(buzz lock)を実現する
こともできる。

<!--
When the owning process leaves the critical region of code it decrements
the buzz lock, returning its value to 0. Any processes spinning on the lock
will now read it as 0, the first one to do this will increment it to 1 and 
enter the critical region. 
-->
<p>占有中のプロセスがコードの重要領域から離れるとき、バズロックの値をデクリメン
トして、その値を 0 に戻す。ロック上でスピニングしているプロセスは、この時に
読み出しを行うと、0 を読み出す。それを最初に読み出したプロセスが、その値をイン
クリメントして 1 にし、重要領域へと入る。

<!--11.6  Semaphores-->
<sect1>セマフォ(semaphore)<label id="chapter_km_sect6">

<!--
Semaphores are used to protect critical regions of code or data structures.
Remember that each access of a critical piece of data such as a VFS inode
describing a directory is made by kernel code running on behalf of a process.
It would be very dangerous to allow one process to alter a critical data
structure that is being used by another process. One way to achieve this
would be to use a buzz lock around the critical piece of data is being
accessed but this is a simplistic approach that would not give very good
system performance. Instead Linux uses semaphores to allow just one
process at a time to access critical regions of code and data; all other
processes wishing to access this resource will be made to wait until it
becomes free. The waiting processes are suspended, other processes in the
system can continue to run as normal. 
-->
<p>セマフォは、コードやデータ構造の重要な領域を保護するために利用される。
たとえば、ディレクトリを記述する VFS inode のような重要なデータへの個々のアクセ
スは、そのプロセスに代わってカーネルコードによって実行される。あるプロセスが
使用している重要なデータ構造体に対する、他のプロセスによる変更を許すことは
非常に危険である。これを実現するひとつの方法は、アクセスされる重要なデータの
周囲でバズロックを使用することだが、これは単純なアプローチなので、良好な
システムパフォーマンスは期待できない。それに替えて、Linux はセマフォを使用
して、コードやデータの重要領域へのアクセスを一度にひとつのプロセスにしか
許さないようにしている。リソースへアクセスしようとするそれ以外のプロセス
は、領域がフリーになるまで待たされる。待ちプロセスはサスペンドされ、
システム上の他のプロセスは通常通り実行を続けることが可能である。

<!--
A Linux semaphore data structure contains the following information: 
-->
<p>Linux の <tt><ref id="semaphore" name="semaphore"></tt> データ構造体には、
次のような情報が含まれている。
<newline>[see: include/asm/semaphore.h]
(<htmlurl url="./The-Linux-Kernel-images/linux/include/asm-i386/semaphore.h" 
name="i386">, <htmlurl 
url="./The-Linux-Kernel-images/linux/include/asm-alpha/semaphore.h" 
name="alpha">)

<!--
count This field keeps track of the count of processes wishing to use this
      resource. A positive value means that the resource is available. A
      negative or zero value means that processes are waiting for it. An
      initial value of 1 means that one and only one process at a time can
      use this resource. When processes want this resource they
      decrement the count and when they have finished with this resource
      they increment the count, 
-->
<descrip>
<tag>count</tag>
このフィールドは、そのリソースを利用しようとするプロセスの数を監視するもので
ある。正の値は、リソースが利用可能であることを意味する。負または 0 の値は、
待ち状態のプロセスがあることを意味する。初期値 1 は、そのリソースを利用できる
のは一度にたったひとつのプロセスだけであることを意味する。プロセスがその
リソースを利用したいとき、プロセスはその値(count)をデクリメントし、このリソース
の利用を終了したとき、プロセスはその値をインクリメントする。

<!--
waking This is the count of processes waiting for this resource which is
      also the number of process waiting to be woken up when this
      resource becomes free, 
wait queue
      When processes are waiting for this resource they are put onto this
      wait queue, 
lock A buzz lock used when accessing the waking field. 
-->
<tag>waking</tag>
このフィールドは、そのリソースを待っているプロセス数のうち、そのリソースが
解放されたときに起こされることになっているプロセスの数を示すものである。

<tag>wait queue</tag>
プロセスがそのリソースを待っているとき、それらのプロセスはこの待ち行列上に
置かれる。

<tag>lock</tag>
waking フィールドにアクセスしているときは、バズロックが利用される。
</descrip>

<!--
Suppose the initial count for a semaphore is 1, the first process to come
along will see that the count is positive and decrement it by 1, making it 0.
The process now ``owns'' the critical piece of code or resource that is being
protected by the semaphore. When the process leaves the critical region it
increments the semphore's count. The most optimal case is where there are
no other processes contending for ownership of the critical region. Linux has
implemented semaphores to work efficiently for this, the most common,
case. 
-->
<p>セマフォの初期値が 1 であるとすると、最初にやって来たプロセスは、そのカウ
ントが正であることを確認し、そこから 1 を引いて 0 にする。これでプロセスは、
コードかリソースの重要部分を「占有」したことになり、それがセマフォによって
保護される。プロセスがその重要な領域を離れるとき、セマフォのカウントをインクリ
メントする。最善のケースは、その重要領域を所持しようとする他のプロセスが存在し
ない場合である。Linux は、この最も一般的なケースで効率よく動くようにセマフォを
実装している。

<!--
If another process wishes to enter the critical region whilst it is owned by a
process it too will decrement the count. As the count is now negative (-1)
the process cannot enter the critical region. Instead it must wait until the
owning process exits it. Linux makes the waiting process sleep until the
owning process wakes it on exiting the critical region. The waiting process
adds itself to the semaphore's wait queue and sits in a loop checking the
value of the waking field and calling the scheduler until waking is
non-zero. 
-->
<p>あるプロセスの占有中に他のプロセスが重要領域に入ろうとする場合、そのプロセス
も <tt>count</tt> をデクリメントする。その count は現在 負(-1)となるので、その
プロセスは重要領域に入れず、そのかわり占有中のプロセスが退出するまで待たなけれ
ばならない。Linux は待ちプロセスをスリープさせ、占有プロセスがその重要領域から
退出する際にそのプロセスを目覚めさせる。待ちプロセスは自分自身をセマフォの
待ち行列に登録して、waking フィールドの値をチェックしながらループ状態に
入り、waking が 0 でなくなった時にスケジューラを呼び出す。

<!--
The owner of the critical region increments the semaphore's count and if it
is less than or equal to zero then there are processes sleeping, waiting for
this resource. In the optimal case the semaphore's count would have been
returned to its initial value of 1 and no further work would be neccessary.
The owning process increments the waking counter and wakes up the
process sleeping on the semaphore's wait queue. When the waiting process
wakes up, the waking counter is now 1 and it knows that it it may now enter
the critical region. It decrements the waking counter, returning it to a value
of zero, and continues. All access to the waking field of semaphore are
protected by a buzz lock using the semaphore's lock. 
-->
<p>重要領域の占有者がセマフォの count をインクリメントして、もしその値が 0 以下
ならば、そのリソースを待ちながらスリープしているプロセスが存在する。最良のケー
スでは、セマフォの count は初期値である 1 に戻されているので、それ以上の仕事は
必要がない。
占有プロセスは waking フィールドの値をインクリメントして、セマフォの待ち行列で
スリープ状態にあるプロセスを目覚めさせる。待ちプロセスが起きると、waking 
フィールドの値は 1 なので、重要領域に入ってもよいことがわかる。プロセスは 
waking フィールドの値をデクリメントし、その値を 0 に戻し、実行を続ける。セマフ
ォの waking フィールドへのアクセスはすべて、セマフォのロックを使用したバズロッ
クにより保護されている。

<!--
Footnotes:

1 REVIEW NOTE: What is to stop a task in state INTERRUPTIBLE being
made to run the next time the scheduler runs? Processes in a wait queue
should never run until they are woken up. 
-->
<label id="chapter_km_fn">
<footnote>
(脚注 1)REVIEW NOTE: タスクを割り込み可能な状態で停止させて、次にスケジューラ
が実行される際に、そのタスクが実行されるとはどういうことか？ 待ち行列上でスリー
プ状態にあるプロセスは、目覚めさせられるまで、実行されないはずである。
</footnote>

<!--第 13 章 モジュール-->
<!--Chapter 12 Modules-->
<sect>モジュール<label id="chapter_m">
<p>
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/penguin2.gif">
</figure>

<!--
This chapter describes how the Linux kernel can dynamically load functions,
for example filesystems, only when they are needed. 
-->
<p>この章では、Linux カーネルが、ファイルシステムなどの機能を、必要な時だけ
動的にロードする仕組みについて説明する。

<!--
Linux is a monolithic kernel; that is, it is one, single, large program where 
all the functional components of the kernel have access to all of its internal
data structures and routines. The alternative is to have a micro-kernel
structure where the functional pieces of the kernel are broken out into
separate units with strict communication mechanisms between them. This
makes adding new components into the kernel via the configuration process
rather time consuming. Say you wanted to use a SCSI driver for an NCR 810
SCSI and you had not built it into the kernel. You would have to configure
and then build a new kernel before you could use the NCR 810. There is an
alternative, Linux allows you to dynamically load and unload components of
the operating system as you need them. Linux modules are lumps of code
that can be dynamically linked into the kernel at any point after the system
has booted. They can be unlinked from the kernel and removed when they
are no longer needed. Mostly Linux kernel modules are device drivers,
pseudo-device drivers such as network drivers, or file-systems. 
-->
<p>Linux は、モノリシックなカーネル(monolithic kernel)を使用している。すなわ
ちそれは、単一で巨大なプログラムであり、そこでは、カーネルのあらゆる機能別
コンポーネントが、すべての内部データ構造やルーチンにアクセスできる。
それとは反対の仕組みとして、マイクロカーネル(micro-kernel)構造がある。その
場合、カーネルの機能別部分は、個別のユニットに分割され、ユニット間での厳格な
通信メカニズムが設定される。モノリシックカーネルでは、新規コンポーネントを
カーネルに追加するには、その設定プロセスを経由するので、やや時間がかか
る。たとえば、NCR 810 SCSI の SCSI ドライバを使いたいのだが、まだそれをカーネル
に組み込んでいないとする。その際は、新しいカーネルを設定し、ビルドすることで、
はじめて NCR 810 が使用できるようになる。
しかし、違う選択肢も存在する。Linux では、必要に応じて、オペレーティング
システムのコンポーネントを動的にロードしたり、アンロードしたりできる。
Linux カーネルモジュール(module)とは、システム起動後ならいつでも動的にカーネル
にリンクすることができるコード群である。それらは、必要がなくなればカーネルとの
リンクを解消して削除することができる。大部分の Linux カーネルモジュールは、
デバイスドライバや、ネットワークドライバなどの仮想ドライバ、あるいはファイル
システムなどである。

<!--
You can either load and unload Linux kernel modules explicitly using the
insmod and rmmod commands or the kernel itself can demand that the kernel
daemon (kerneld) loads and unloads the modules as they are needed. 
Dynamically loading code as it is needed is attractive as it keeps the kernel
size to a minimum and makes the kernel very flexible. My current Intel
kernel uses modules extensively and is only 406Kbytes long. I only
occasionally use VFAT file systems and so I build my Linux kernel to
automatically load the VFAT file system module as I mount a VFAT partition.
When I have unmounted the VFAT partition the system detects that I no
longer need the VFAT file system module and removes it from the system.
Modules can also be useful for trying out new kernel code without having to
rebuild and reboot the kernel every time you try it out. Nothing, though, is 
for free and there is a slight performance and memory penalty associated with
kernel modules. There is a little more code that a loadable module must
provide and this and the extra data structures take a little more memory.
There is also a level of indirection introduced that makes accesses of kernel
resources slightly less efficient for modules. 
-->
<p>Linux カーネルモジュールは、<tt>insmod</tt> や <tt>rmmod</tt> コマンドを
使用して、明示的にロードとアンロードが可能である。また、カーネル自身も、
カーネルデーモン(<tt>kerneld</tt>)によって、モジュールのロードとアンロードを
必要に応じて行うことができる。必要なときに動的にロードできるコードというのは、
カーネルのサイズを最小に抑え、それに柔軟性を与えるという意味で非常に魅力的な
機能である。わたしの現在の Intel カーネルはモジュールを広範に使っているので、
406 K バイトで済んでいる。VFAT ファイルシステムはたまにしか使わないため、
VFAT パーティションがマウントされた時に自動的に VFAT ファイルシステムがロード
されるように、わたしのカーネルはビルドされている。VFAT パーティションをアンマウ
ントしたとき、システムはわたしがもはや VFAT ファイルシステムモジュールを必要と
していないことを検出して、システムからそれを削除する。新しいカーネルコードを
試すときでも、試行のたびにカーネルをリビルドして再起動をかける必要がないので、
その点でもモジュールは便利である。しかし、その見返りとして、カーネルモジュール
を使うと若干のパフォーマンスの低下とメモリの消費が起こる。ローダブルモジュール
にするために提供しなければならないコードが少量あり、そのコードと付加的なデータ
構造とが加わるために、メモリの消費量がやや増加する。また、あるレベルで
間接処理が導入されるので、モジュールの場合、カーネルリソースへのアクセスが
やや非効率になる。

<!--
Once a Linux module has been loaded it is as much a part of the kernel as
any normal kernel code. It has the same rights and responsibilities as any
kernel code; in other words, Linux kernel modules can crash the kernel just
like all kernel code or device drivers can. 
-->
<p>Linux モジュールは、いったんロードされると、通常のカーネルコードと同様に
カーネルの一部となる。すなわち、他のカーネルコードと同一の権利と責任を持つ。
言い換えると、Linux カーネルモジュールは、すべてのカーネルコードやデバイス
ドライバと同様に、カーネルをクラッシュさせることもできる。

<!--
So that modules can use the kernel resources that they need, they must be
able to find them. Say a module needs to call kmalloc(), the kernel
memory allocation routine. At the time that it is built, a module does not
know where in memory kmalloc() is, so when the module is loaded, the
kernel must fix up all of the module's references to kmalloc() before the
module can work. The kernel keeps a list of all of the kernel's resources in
the kernel symbol table so that it can resolve references to those resources
from the modules as they are loaded. Linux allows module stacking, this is
where one module requires the services of another module. For example, the
VFAT file system module requires the services of the FAT file system
 module as the VFAT file system is more or less a set of extensions to the
FAT file system. One module requiring services or resources from another
module is very similar to the situation where a module requires services and
resources from the kernel itself. Only here the required services are in
another, previously loaded module. As each module is loaded, the kernel
modifies the kernel symbol table, adding to it all of the resources or symbols
exported by the newly loaded module. This means that, when the next
module is loaded, it has access to the services of the already loaded
modules. 
-->
<p>モジュールが必要なカーネルリソースを使用するためには、まずそれらのリソースを
見つけだす必要がある。たとえば、モジュールが <tt>kmalloc()</tt> やカーネルメモ
リ割り当てルーチンを呼び出す必要がある場合などを考えてほしい。ビルドされた時点
では、モジュールは、メモリ内のどこに <tt>kmalloc()</tt> があるのかを知らない。
したがって、モジュールがロードされたとき、カーネルは、モジュールが動き出す前
に、モジュール内の <tt>kmalloc()</tt> への参照をすべて解決しなければならない。
カーネルは、カーネルのシンボルテーブル内にカーネルリソースのすべてのリストを保
持しているので、モジュールのロード時に、モジュールからのそうしたリソースへの参
照を解決することができる。
Linux では、モジュールをスタック化できる。すなわち、あるモジュールは、他の
モジュールのサービスを前提とし、そのサービスを利用できる。たとえば、VFAT ファイ
ルシステムモジュールは、FAT ファイルシステムのモジュールのサービスを必要とす
る。VFAT ファイルシステムは、多かれ少なかれ FAT ファイルシステムの拡張であるか
らである。他のモジュールのサービスやリソースを必要とするモジュールというのは、
モジュールがカーネルそのもののサービスやリソースを必要とする状況と非常に類似
している。必要とするサービスが、先にロードされた他のモジュールの中だけに
あるからである。個々のモジュールがロードされると、カーネルは、カーネルシンボル
テーブルを変更して、新しくロードされたモジュールがエクスポートしたリソースや
シンボルのすべてをそこに付け加える。これが意味するのは、次のモジュールがロード
されたとき、そのモジュールは既にロードされているモジュールのサービスにアクセス
出来るということである。

<!--
When an attempt is made to unload a module, the kernel needs to know that
the module is unused and it needs some way of notifying the module that it
is about to be unloaded. That way the module will be able to free up any
system resources that it has allocated, for example kernel memory or
interrupts, before it is removed from the kernel. When the module is
unloaded, the kernel removes any symbols that that module exported into
the kernel symbol table. 
-->
<p>モジュールをアンロードしようとするとき、カーネルはそのモジュールが使用されて
いないことを知る必要があり、モジュールにこれからアンロードされることを知らせる
方法をも必要とする。そして、その方法によって、モジュールは、カーネルから削除
される前に、カーネルメモリや割り込みなどの割り当てられたシステムリソースを
解放することが出来る。モジュールがアンロードされるとき、カーネルは、その
モジュールがカーネルシンボルテーブルにエクスポートしたすべてのシンボルを
削除する。

<!--
Apart from the ability of a loaded module to crash the operating system by
being badly written, it presents another danger. What happens if you load a
module built for an earlier or later kernel than the one that you are now
running? This may cause a problem if, say, the module makes a call to a
kernel routine and supplies the wrong arguments. The kernel can optionally
protect against this by making rigorous version checks on the module as it is
loaded. 
-->
<p>適切に書かれなかったために、ロードされたモジュールはオペレーティングシステム
をクラッシュさせることが出来るということの他にも、モジュールの使用は別の危険も
もたらす。現在使用しているカーネルよりも、古いか新しいバージョンのカーネル用に
ビルドされたモジュールをロードした場合、何が起こるだろうか？これが問題を
起こすのは、たとえばモジュールがカーネルルーチンをコールして、誤った引数を渡し
た場合である。カーネルは、オプションとしてではあるが、モジュールのロード時に
そのモジュールを厳格にバージョンチェックすることで、この問題が起こらないように
している。


<!--12.1  Loading a Module-->
<sect1>モジュールのローディング<label id="chapter_m_sect1">
<p>

<label id="figure12-1">
<!--              Figure 12.1: The List of Kernel Modules-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure12-1.gif">
</figure>
</#if>
<#unless output="html">
<verb>
+----module_list
|
|     module                          module
|  +----------+                    +----------+
+->| next     |------------------->| next     |
   |----------|                    |----------|
   | ref      |                 +->| ref      |
   |----------|                 |  |----------|
   | symtab   |------+          |  | symtab   |-------+
   |----------|      |          |  |----------|       |
   | name     |"fat" |          |  | name     |"vfat" |
   |----------|      |          |  |----------|       |
   | size     |      |          |  | size     |       |
   |----------|      |          |  |----------|       |
   | addr     | +----+          |  | addr     | +-----+ 
   |----------| |               |  |----------| |
   | state    | |  symbol_table |  | state    | |  symbol_table
   |----------| |  +----------+ |  |----------| |  +----------+
   |*cleanup()| +->| size     | |  |*cleanup()| +->| size     |
   +----------+    |----------| |  +----------+    |----------|
                   | n_symbols| |                  | n_symbols|
                   |----------| |                  |----------|
                   | n_refs   | |                  | n_refs   |
                   |----------| |                  |----------|
                   |          | |                  |          |
                   | symbols  | |                  | symbols  |
                   |          | |                  |          |
                   |----------| |                  |----------|
                   |references|-+                  |references|
                   |          |                    |          |
                   +----------+                    +----------+
</verb>
</#if>
<p>図表(12.1)カーネルモジュールのリスト

<!--
There are two ways that a kernel module can be loaded. The first way is to
use the insmod command to manually insert the it into the kernel. 
The second, and much more clever way, is to load the module as it is
needed; this is known as demand loading. 
When the kernel discovers the need for a module, for example when the user
mounts a file system that is not in the kernel, the kernel will request that 
the kernel daemon (kerneld) attempts to load the appropriate module. 
-->
<p>カーネルモジュールをロードする方法はふたつある。ひとつは、<tt>insmod</tt> 
コマンドによって手動でカーネルに組み込む方法。もうひとつの、ずっと賢明なやり
方は、必要に応じてモジュールを組み込む方法である。これは、デマンドローディ
ング(demand loading)と呼ばれる。ユーザがカーネル内に存在しないファイルシステム
をロードする時など、モジュールの必要性をカーネルが感知したとき、カーネルは、
カーネルデーモン(kerneld)に適切なモジュールをロードするようリクエストする。

<!--
The kernel daemon is a normal user process albeit with super user
privileges. When it is started up, usually at system boot time, it opens up an
Inter-Process Communication (IPC) channel to the kernel. This link is used
by the kernel to send messages to the kerneld asking for various tasks to
be performed. 
Kerneld's major function is to load and unload kernel modules but it is also
capable of other tasks such as starting up the PPP link over serial line when
it is needed and closing it down when it is not. Kerneld does not perform
these tasks itself, it runs the neccessary programs such as insmod to do the
work. Kerneld is just an agent of the kernel, scheduling work on its behalf. 
-->
<p>カーネルデーモンは、普通のユーザプロセスなのだが、スーパーユーザの権限を
持っている。通常はシステム起動時に実行が開始されるが、それが実行される
と、カーネルデーモンはカーネルに対するプロセス間通信(IPC)のチャンネルを開く。
このリンクはカーネルによって使用され、<tt>kerneld</tt> に対して様々なタスク
の実行を依頼するためのメッセージが送信される。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/kerneld.h" 
name="include/linux/kerneld.h">]<newline>
<tt>kerneld</tt> の主要な機能は、
カーネルモジュールのロードとアンロードだが、他のタスクの処理も可能である。
たとえば、必要なときにシリアル回線上で PPP リンクを開始し、必要がなくなったら
それを切断するといったこともできる。<tt>kerneld</tt> 自身がそうしたタスクを
実行するのではなく、<tt>insmod</tt> などの必要なプログラムを起動してそれに
仕事をさせる。<tt>kerneld</tt> は、カーネルの代理人(agent)のような存在であり、
カーネルを代理して仕事のスケジューリングを行う。

<!--
The insmod utility must find the requested kernel module that it is to load.
Demand loaded kernel modules are normally kept in
/lib/modules/kernel-version. The kernel modules are linked object
files just like other programs in the system except that they are linked as a
relocatable images. That is, images that are not linked to run from a
particular address. They can be either a.out or elf format object files.
insmod makes a privileged system call to find the kernel's exported
symbols. 
These are kept in pairs containing the symbol's name and its value, for
example its address. The kernel's exported symbol table is held in the first
module data structure in the list of modules maintained by the kernel and
pointed at by the module_list pointer. 
Only specifically entered symbols are added into the table, which is built
when the kernel is compiled and linked, not every symbol in the kernel is
exported to its modules. An example symbol is ``request_irq'' which
is the kernel routine that must be called when a driver wishes to take control
of a particular system interrupt. In my current kernel, this has a value of
0x0010cd30. You can easily see the exported kernel symbols and their
values by looking at /proc/ksyms or by using the ksyms utility. The
ksyms utility can either show you all of the exported kernel symbols or only
those symbols exported by loaded modules. insmod reads the module into its
virtual memory and fixes up its unresolved references to kernel routines and
resources using the exported symbols from the kernel. This fixing up takes
the form of patching the module image in memory. insmod physically writes
the address of the symbol into the appropriate place in the module. 
-->
<p><tt>insmod</tt> ユーティリティは、リクエストされたカーネルモジュールを
発見して、それをロードしなければならない。デマンドローディングでロードされた
カーネルモジュールは通常 <tt>/lib/modules/kernel-version</tt> に保存される。
カーネルモジュールは他のプログラムと同じくリンクされたオブジェクトファイル
なのだが、リロケータブル(relocatable)イメージとしてリンクされている点で異なる。
すなわち、特定の固定的なアドレスから実行されるようにリンクされたのではない
イメージであるということである。それらは <tt>a.out</tt> か <tt>ELF</tt> か
のいずれかのフォーマットを取る。<tt>insmod</tt> は、特権的なシステムコールを
発行して、カーネルによってエクスポートされたシンボルを見つけだす。
<newline>[see: sys_get_kernel_syms(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/kernel/module.c" 
name="kernel/module.c">]<newline>
それらは、シンボル名と、そのアドレスなどの値とを含んだペアとして保存される。
カーネルがエクスポートしたシンボルテーブルは、カーネルが管理するモジュール
のリストの最初の <tt><ref id="module" name="module"></tt> データ構造体に保持
され、その構造体は、<tt><ref id="module" name="module_list"></tt> ポインタに
よってポイントされる。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/module.h" 
name="include/linux/module.h">]<newline>
カーネルのシンボルテーブルに追加されるのは、明示的に追加が指示されたシンボル
だけである。シンボルテーブルは、カーネルのコンパイルとリンクがなされる時に
作成されるのだが、すべてのシンボルがモジュールにエクスポートされるわけでは
ない。
たとえば、<tt>request_irq</tt> というシンボルがあるが、これは、ドライバが特定の
システム割り込みを制御しようとする場合に呼び出されるカーネルルーチンである。
わたしの現在のカーネルでは、このシンボルは 0x0010cd30 という値を持っている。
エクスポートされたカーネルシンボルとその値を簡単に見るには、<tt>/proc/ksyms
</tt> を見るか、<tt>ksyms</tt> ユーティリティを使えばよい。
<tt>ksyms</tt> ユーティリティを使えば、エクスポートされたすべてのカーネル
シンボルを見ることも、ローダブルモジュールによってエクスポートされたシンボル
だけを見ることもできる。<tt>insmod</tt> コマンドは、
モジュールを仮想メモリから読み出して、カーネルがエクスポートしているシンボル
を使うことで、カーネルルーチンへの参照のなかでまだ解決されていない参照を
適宜解決(fixup)する。この解決は、メモリ内のモジュールイメージにパッチを当てる
という形式を取っている。<tt>insmod</tt> は、シンボルのアドレスをモジュール内の
適切な場所に書き込む。

<!--
When insmod has fixed up the module's references to exported kernel
symbols, it asks the kernel for enough space to hold the new kernel, again
using a privileged system call. The kernel allocates a new module data
structure and enough kernel memory to hold the new module and puts it at
the end of the kernel modules list. The new module is marked as
UNINITIALIZED. 
Figure  12.1 shows the list of kernel modules after two modules, VFAT and
VFAT have been loaded into the kernel. Not shown in the diagram is the first
module on the list, which is a pseudo-module that is only there to hold the
kernel's exported symbol table. You can use the command lsmod to list all
of the loaded kernel modules and their interdependencies. lsmod simply
reformats /proc/modules which is built from the list of kernel module
data structures. The memory that the kernel allocates for it is mapped into
the insmod process's address space so that it can access it. insmod copies
the module into the allocated space and relocates it so that it will run from
the kernel address that it has been allocated. This must happen as the
module cannot expect to be loaded at the same address twice let alone into
the same address in two different Linux systems. Again, this relocation
involves patching the module image with the appropriate addresses. 
-->
<p><tt>insmod</tt> によって、エクスポートされたカーネルシンボルに対するモジュー
ルの参照が解決されると、<tt>insmod</tt> は、再度特権的なシステムコールを使っ
て、新しいカーネルを保持するのに充分なスペースをくれるようカーネルに依頼する。
カーネルは、新規の <tt><ref id="module" name="module"></tt> データ構造体と、
新しいモジュールを保持するのに充分なメモリ容量を割り当てて、それをカーネル
モジュールリストの最後尾に置く。
その新しいモジュールは UNINITIALIZED とマークされる。
<newline>[see: sys_create_module(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/kernel/module.c" 
name="kernel/module.c">]<newline>
<ref id="figure12-1" name="図表(12.1)">では、VFAT と FAT のふたつのモジュール
がカーネルにロードされた後のカーネルモジュールのリストが示されている。
図表では示されていないが、リストの
先頭のモジュールは <tt>pseudo-module</tt> となっていて、これはカーネルの
エクスポートされたシンボルのテーブルを保持するためだけにそこに置かれているもの
である。<tt>lsmod</tt> コマンドを使えば、ロードされているすべてのモジュールと
その依存関係を表示することができる。<tt>lsmod</tt> は単に <tt>/proc/modules
</tt> を再構成しただけのもので、<tt>/proc/modules</tt> の方は、カーネルの 
<tt>module</tt> データ構造体のリストから作成されたものである。
モジュール用に割り当てられたメモリは、 <tt>insmod</tt> がモジュールにアクセス
できるよう、<tt>insmod</tt> プロセスのアドレス空間にマップされる。
<tt>insmod</tt> は、モジュールを割り当てられたアドレス空間にコピーして
モジュールの置き場所を変更することで、割り当てを受けたカーネルアドレス空間から
モジュールが実行されるようにする。
こうした処理が必要なのは、異なる Linux システム上ではモジュールを同じアドレス
にロードするよう要求できないだけでなく、同一システム上でも同じアドレスに
二度ロードするよう要求することはできないからである。このアドレスの変更の際
には、モジュールイメージが適切なアドレスを持つように修正がなされる。

<!--
The new module also exports symbols to the kernel and insmod builds a
table of these exported images. Every kernel module must contain module
initialization and module cleanup routines and these symbols are
deliberately not exported but insmod must know the addresses of them so
that it can pass them to the kernel. All being well, insmod is now ready to
initialize the module and it makes a privileged system call passing the kernel
the addresses of the module's initialization and cleanup routines. 
When a new module is added into the kernel, it must update the kernel's set
of symbols and modify the modules that are being used by the new module.
Modules that have other modules dependent on them must maintain a list of
references at the end of their symbol table and pointed at by their module
data structure. Figure  12.1 shows that the VFAT file system module is
dependent on the FAT file system module. So, the FAT module contains a
reference to the VFAT module; the reference was added when the VFAT
module was loaded. The kernel calls the modules initialization routine and, if
it is successful it carries on installing the module. The module's cleanup
routine address is stored in it's module data structure and it will be called
by the kernel when that module is unloaded. Finally, the module's state is
set to RUNNING. 
-->
<p>新しいモジュールもカーネルにシンボルをエクスポートするので、<tt>insmod</tt>
 はエクスポートされるイメージのテーブルを作成しなければならない。すべての
カーネルモジュールには、モジュール初期化と削除のルーチンが含まれていなければ
ならず、それらのシンボルはわざとエクスポートされないのだが、<tt>insmod</tt> 
は、カーネルにそのルーチンのアドレスを渡さなければならないので、それらのアド
レスを知っていなければならない。
これらすべてが上手くいった場合、<tt>insmod</tt> はモジュールを初期化する準備が
整ったため、特権的なシステムコールを発行して、カーネルに対して、モジュールの
初期化ルーチンと削除ルーチンのアドレスを渡す。
<newline>[see: sys_init_module(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/kernel/module.c" 
name="kernel/module.c">]<newline>
新しいモジュールがカーネルに組み込まれるとき、カーネルの一連のシンボルが
更新されなければならず、新規モジュールによって利用されることになるモジュールに
対しても修正が加えられなければならない。
他のモジュールから依存されているモジュールは、そのシンボルテーブルの末尾にある
参照リストを管理しなければならず、その参照リストは自己の <tt><ref 
id="module" name="module"></tt> データ構造体によってポイントされなければなら
ない。
<ref id="figure12-1" name="図表(12.1)">では、VFAT ファイルシステムモジュール
は、FAT ファイルシステムモジュールに依存している。したがって、FAT モジュール
には、VFAT モジュールへの参照が含まれていなければならない。その参照は、VFAT 
モジュールがロードされたときに付け加えられる。
カーネルはモジュール初期化ルーチンを呼び出し、それが成功した場合、モジュールの
インストールを行う。モジュールの削除ルーチンのアドレスは、そのモジュールの 
<tt>module</tt> データ構造体に保存され、モジュールがアンロードされるときに、
カーネルによって呼び出される。最後に、モジュールの状態が RUNNING にセットされ
る。

<!--12.2  Unloading a Module-->
<sect1>モジュールのアンロード<label id="chapter_m_sect2">

<!--
Modules can be removed using the rmmod command but demand loaded
modules are automatically removed from the system by kerneld when they
are no longer being used. Every time its idle timer expires, kerneld makes
a system call requesting that all unused demand loaded modules are
removed from the system. The timer's value is set when you start
kerneld; my kerneld checks every 180 seconds. So, for example, if you
mount an iso9660 CD ROM and your iso9660 filesystem is a loadable
module, then shortly after the CD ROM is unmounted, the iso9660 module
will be removed from the kernel. 
-->
<p>モジュールは <tt>rmmod</tt> コマンドを使って削除することが可能であるが、
オンデマンドでロードされたモジュールは使用されなくなったとき <tt>kerneld
</tt> によって自動的にシステムから削除される。アイドルタイマー(idle timer)が
時間切れになった際はいつも、<tt>kerneld</tt> はシステムコールを発行し、
オンデマンドでロードされたモジュールのなかで使用されなくなったものすべてを
システムから削除するようリクエストする。
タイマーの値は、<tt>kerneld</tt> を始動した時にセットされる。わたしの 
<tt>kerneld</tt> のタイマー設定は 180 秒にしてある。
たとえば、iso9660 CD-ROM をマウントして、その iso9660 ファイルシステムが
ローダブルモジュールであった場合、CD-ROM がアンマウントされてからしばらく
すると、iso9660 モジュールはカーネルから削除される。

<!--
A module cannot be unloaded so long as other components of the kernel are
depending on it. For example, you cannot unload the VFAT module if you
have one or more VFAT file systems mounted. If you look at the output of
lsmod, you will see that each module has a count associated with it. For
example: 
-->
<p>他のカーネルの一部が、あるモジュールに依存している間は、そのモジュールは
アンロードできない。たとえば、ひとつ以上の VFAT ファイルシステムをマウントして
いる場合、VFAT モジュールはアンマウントできない。<tt>lsmod</tt> の出力
を見れば、個々のモジュールが依存関係についてもカウントを持っていることが分か
る。

<verb>
Module:        #pages:  Used by:
msdos              5                  1
vfat               4                  1 (autoclean)
fat                6    &lsqb;vfat msdos&rsqb;  2 (autoclean)
</verb>

<!--
The count is the number of kernel entities that are dependent on this module.
In the above example, the vfat and msdos modules are both dependent on
the fat module and so it has a count of 2. Both the vfat and msdos
modules have 1 dependent, which is a mounted file system. If I were to load
another VFAT file system then the vfat module's count would become 2. A
module's count is held in the first longword of its image. 
-->
<p>カウントは、そのモジュールに依存しているカーネル実体(entity)の数を表してい
る。上記の例では、<tt>vfat</tt> と <tt>msdos</tt> モジュールはどちらも <tt>
fat</tt> モジュールに依存しているので、<tt>fat</tt> のカウントは 2 となって
いる。<tt>vfat</tt> と <tt>msdos</tt> モジュールは両方ともそれに依存する 1 つの
実体を持っているが、その実体とはマウントされたファイルシステムである。
もし、わたしがもうひとつ VFAT ファイルシステムをマウントしたとすると、
<tt>vfat</tt> モジュールのカウントは 2 になるだろう。モジュールのカウントは、
イメージの最初のロングワード(longword)の中に保持されている。

<!--
This field is slightly overloaded as it also holds the AUTOCLEAN and
VISITED flags. Both of these flags are used for demand loaded modules.
These modules are marked as AUTOCLEAN so that the system can
recognize which ones it may automatically unload. The VISITED flag marks
the module as in use by one or more other system components; it is set
whenever another component makes use of the module. Each time the
system is asked by kerneld to remove unused demand loaded modules it
looks through all of the modules in the system for likely candidates. It only
looks at modules marked as AUTOCLEAN and in the state RUNNING. If the
candidate has its VISITED flag cleared then it will remove the module,
otherwise it will clear the VISITED flag and go on to look at the next
module in the system. 
-->
<p>そのフィールドには、AUTOCLEAN と VISITED フラグも保持されるので、やや
情報過多ともいえるフィールドになっている。これらふたつのフラグは、デマンド
ローディングでロードされたモジュールに対して使用される。
そうしたモジュールが AUTOCLEAN とマークされるのは、システムが
そのモジュールを自動的にアンロードする対象と認識できるようにするためである。
VISITED フラグは、ひとつ以上のシステムコンポーネントがそのモジュールを
使っていることを示している。VISITED フラグは、他のコンポーネントがその
モジュールと使うときは必ずセットされる。オンデマンドでロードされたが使用され
なくなったモジュールを削除するかどうかを <tt>kerneld</tt> がシステムに尋ねた
ときは、システムはシステム上のすべてのモジュールを見回して、使用されなくなった
という条件に該当するものを捜す。システムは AUTOCLEAN とマークされていて 
RUNNING 状態にあるモジュールだけを見る。該当するモジュールが VISITED フラグを
クリアした場合、システムはそのモジュールを削除するが、モジュールがフラグをクリ
アしない場合は、システムがその VISITED フラグをクリアして、システム上の次の
モジュールの調査に移る。

<!--
Assuming that a module can be unloaded, its cleanup routine is called to
allow it to free up the kernel resources that it has allocated. 
The module data structure is marked as DELETED and it is unlinked from
the list of kernel modules. Any other modules that it is dependent on have
their reference lists modified so that they no longer have it as a dependent.
All of the kernel memory that the module needed is deallocated. 
-->
<p>モジュールがアンロード可能な場合、そのモジュールの削除ルーチンが呼び出され、
そのルーチンが、モジュールに割り当てられたカーネルリソースを解放する。
<newline>&lsqb;see: sys_delete_module(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/kernel/module.c" 
name="kernel/module.c">&rsqb;<newline>
その <tt><ref id="module" name="module"></tt> データ構造体は DELETED とマーク
され、カーネルモジュールのリストから削除される。(削除されたモジュールが依存
していた)他のモジュールは、削除モジュールがもはや依存するものではなくなった
ので、参照リストを修正しないといけない。
削除モジュールが必要としていたカーネルメモリはすべて割り当てを解放される。

<!--第 14 章 プロセッサ-->
&processor;

<!--第 15 章 カーネルソース-->
&k-source;

<!--第 16 章  Linux データ構造-->
&data-structure;





<!--Chapter 16 Useful Web and FTP Sites-->
<sect>有益なウェブと FTP サイト<label id="chapter_ww">
<p>
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/penguin2.gif">
</figure>

<!--
The following World Wide Web and ftp sites are useful: 
-->
<p>以下では、便利なウェブサイトや FTP サイトについて述べる。

<!--
http://www.azstarnet.com/ [\tilde]axplinux
      This is David Mosberger-Tang's Alpha AXP Linux web site and it
      is the place to go for all of the Alpha AXP HOWTOs. It also has a
      large number of pointers to Linux and Alpha AXP specific
      information such as CPU data sheets. 
-->
<descrip>
<tag><tt><htmlurl url="http://www.azstarnet.com/&tilde;axplinux/" 
name="http://www.azstarnet.com/&tilde;axplinux/"></tt></tag>
これは、David Mosberger-Tag の Alpha AXP Linux のウェブサイトで、Alpha AXP 
HOWTO のすべてが集まった場所である。また、ここには、CPU のデータシートと
いった Linux と Alpha AXP に固有の情報に関する膨大なリンク集がある。
(訳注: 現在は、<htmlurl url="http://www.alphalinux.org/" 
name="http://www.alphalinux.org/"> にリダイレクトされます。)
<!--
http://www.redhat.com/
      Red Hat's web site. This has a lot of useful pointers. 
-->
<tag><tt><htmlurl url="http://www.redhat.com/" 
name="http://www.redhat.com/"></tt></tag>
Red Hat のウェブサイト。多くの有益なリンクがある。

<!--
ftp://sunsite.unc.edu
      This is the major site for a lot of free software. The Linux specific
      software is held in pub/Linux. 
-->
<tag><tt><htmlurl url="ftp://sunsite.unc.edu/" 
name="ftp://sunsite.unc.edu/"></tt></tag>
多くのフリーソフトを集めたメジャーサイト。Linux 固有のソフトウェアは、
<tt>pub/Linux</tt> にある。

<!--
http://www.intel.com
      Intel's web site and a good place to look for Intel chip information. 
-->
<tag><tt><htmlurl url="http://www.intel.com/"
name="http://www.intel.com/"></tt></tag>
Intel のウェブサイト。Intel チップの情報を探すときに便利である。

<!--
http://www.ssc.com/lj/index.html
      The Linux Journal is a very good Linux magazine and well worth the
      yearly subscription for its excellent articles. 
-->
<tag><tt><htmlurl url="http://www.ssc.com/lj/index.html"
name="http://www.ssc.com/lj/index.html"></tt></tag>
Linux Journal は、非常にすばらしい Linux 雑誌である。その優れた記事は、
年間購読して読むに値する。<newline>
(訳注: 現在は、<htmlurl url="http://www2.linuxjournal.com/" 
name="http://www2.linuxjournal.com/"> となっています。)

<!--
http://www.blackdown.org/java-linux.html
      This is the primary site for information on Java on Linux. 
-->
<tag><tt><htmlurl url="http://www.blackdown.org/java-linux.html"
name="http://www.blackdown.org/java-linux.html"></tt></tag>
Linux 上での Java 情報に関するプライマリサイト。

<!--
ftp://tsx-11.mit.edu/ [\tilde]ftp/pub/linux
      MIT's Linux ftp site. 
-->
<tag><tt><htmlurl url="ftp://tsx-11.mit.edu/ftp/pub/linux/"
name="ftp://tsx-11.mit.edu/ftp/pub/linux/"></tt></tag>
MIT の Linux FTP サイト。

<!--
ftp://ftp.cs.helsinki.fi/pub/Software/Linux/Kernel
      Linus's kernel sources. 
-->
<tag><tt><htmlurl url="ftp://ftp.cs.helsinki.fi/pub/Software/Linux/Kernel/"
name="ftp://ftp.cs.helsinki.fi/pub/Software/Linux/Kernel/"></tt></tag>
Linux のカーネルソース。<newline>
(訳注: 現在は、<htmlurl 
url="http://www.kernel.org/" name="http://www.kernel.org/"> となっています。)

<!--
http://www.linux.org.uk
      The UK Linux User Group. 
-->
<tag><tt><htmlurl url="http://www.linux.org.uk/"
name="http://www.linux.org.uk/"></tt></tag>
UK Linux ユーザグループ。

<!--
http://sunsite.unc.edu/mdw/linux.html
      Home page for the Linux Documentation Project, 
-->
<tag>(http://sunsite.unc.edu/mdw/linux.html)<newline>
<tt><htmlurl url="http://www.linuxdoc.org/" 
name="http://www.linuxdoc.org/"></tt> (訳注: 現在のページです。)</tag>
Linux Documentation Project のホームページ。

<!--
http://www.digital.com
      Digital Equipment Corporation's main web page. 
-->
<tag><htmlurl url="http://www.digital.com/"
name="http://www.digital.com/"></tag>
Digital Equipment Corporation のメインサイト。
(DEC は Compaq に買収されたため、Compaq のサイトにリダイレクトされます。)

<!--
http://altavista.digital.com
      DIGITAL's Altavista search engine. A very good place to search
      for information within the web and news groups. 
-->
<tag><tt><htmlurl url="http://altavista.digital.com/"
name="http://altavista.digital.com/"></tt></tag>
DEC の Altavista サーチエンジン。ウェブとニュースグループに関する情報を
検索するには、よい場所である。

<!--
http://www.linuxhq.com
      The Linux HQ web site holds up to date official and unoffical
      patches as well as advice and web pointers that help you get the
      best set of kernel sources possible for your system. 
-->
<tag><tt><htmlurl url="http://www.linuxhq.com/"
name="http://www.linuxhq.com/"></tt></tag>
Linux HQ ウェブサイトには、公式および非公式の最新パッチが置かれている。
それ以外にも、アドバイスやリンクがあるので、手持ちのシステムに最も適した
カーネルソースを入手したい場合に役に立つだろう。(訳注: 同様に、
<htmlurl url="http://www.kernelnotes.org/" 
name="http://www.kernelnotes.org/"> もご覧ください。)

<!--
http://www.amd.com
      The AMD web site. 
-->
<tag><tt><htmlurl url="http://www.amd.com/"
name="http://www.amd.com/"></tt></tag>
AMD のウェブサイト

<!--
http://www.cyrix.com
      Cyrix's web site. 
-->
<tag><tt><htmlurl url="http://www.cyrix.com/"
name="http://www.cyrix.com/"></tt></tag>
Cyrix のウェブサイト。

<!--
http://www.arm.com
      ARM's web site. 
-->
<tag><tt><htmlurl url="http://www.arm.com/"
name="http://www.arm.com/"></tt></tag>
ARM のウェブサイト。

<tag>以下は、訳注です。</tag>

<tag><tt><htmlurl url="http://www.linux.or.jp/link/kernel.html" 
name="http://www.linux.or.jp/link/kernel.html"></tt></tag>
「日本の Linux 情報」にあるカーネル関係のリンク集

<tag><tt><htmlurl 
url="http://jungla.dit.upm.es/&tilde;jmseyas/linux/kernel/hackers-docs.html" 
name="http://jungla.dit.upm.es/&tilde;jmseyas/linux/kernel/hackers-docs.html">
</tt></tag>
カーネル関連文書のリンク集

<tag><tt><htmlurl url="http://www.linux.or.jp/JF/" 
name="http://www.linux.or.jp/JF/"></tt></tag>
JF ホームページ

<label id="chapter_ww2">

<tag><tt><htmlurl url="http://www.gnu.org/home.ja.html"
name="http://www.gnu.org/home.ja.html"></tt></tag>
日本語 GNU ホームページ


<tag><tt><htmlurl url="http://arashi.debian.or.jp/&tilde;mhatta/fdl.ja.txt"
name="http://arashi.debian.or.jp/&tilde;mhatta/fdl.ja.txt"></tt></tag>
GNU Free Documentation License(GNU FDL)の日本語訳

</descrip>



<!--第 18 章 LDP 宣言-->
&manifesto;


<!--Chapter 18 The GNU General Public License-->
<sect>The GNU General Public License<label id="chapter_gpl">
<p>
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/penguin2.gif">
</figure>

<!--
Printed below is the GNU General Public License (the GPL or copyleft),
under which Linux is licensed. It is reproduced here to clear up some of the
confusion about Linux's copyright status-Linux is not shareware, and it is
not in the public domain. The bulk of the Linux kernel is copyright 1993 by
Linus Torvalds, and other software and parts of the kernel are copyrighted
by their authors. Thus, Linux is copyrighted, however, you may redistribute
it under the terms of the GPL printed below. 
-->
<p>以下の文書は、GNU General Public License (GPL もしくは copyleft) であり、
Linux はこのライセンスに従っている。それをここに記載したのは、Linux の著作権
の内容に関するいくつかの誤解を解くためである。Linux は、シェアウェア
でも、パブリックドメインソフトウェアでもない。Linux カーネルの大半は、1993 年
に Linus Torvalds が著作権を取得しており、それ以外のソフトウェアやカーネルの
部分についても、それぞれの作成者が著作権を持っている。したがって、Linux は、
著作権の設定されたソフトウェアであり、その上で、以下に示す GPL の条項のもとに
再配布が可能なのである。
<p>
(訳注: 以下は、<url 
url="ftp://ftp.sra.co.jp/pub/gnu/local-fix/GPL2-j/gpl.text.gz"
name="こちら">にある引地信之さん、引地美恵子さんの日本語訳として
公開されているものをお借りしました。
GNU の他の文書に関しては、<ref id="chapter_ww2" name="「ウェブと FTP サイト」">
をご覧ください。＊これまで GPL を翻訳してくださった方の氏名を間違えていました。
お詫びするとともに、上記のように訂正します(2001/07/22)＊)


<!--GPL 本文。-->
&gpl;


<!--第 20 章 用語集-->
&glossary;



<!--別文書として付属する LDP の旧版ライセンス-->
<sect>著作権と配布条件<label id="chapter_cn">

<p>
<tt>Legal Notice</tt><newline>
(訳注: 本章は、原文に付属する著作権と配布条件です。)

<!--
UNIX is a trademark of Univel.<br>
Linux is a trademark of Linus Torvalds, and has no connection to
UNIX<sup><font size=-4><tt>T</tt>M</font></sup>&nbsp; or Univel.<br>
-->
<p>
UNIX は、Univel の登録商標です。
Linux は、Linus Torvalds の登録商標であり、Unix とは無関係です。

<p>
Copyright (c) 1996,1997,1998,1999 David A Rusling<newline>
3 Foxglove Close, Wokingham, Berkshire RG41 3NF, UK <newline>
<tt>david.rusling@arm.com</tt>

<p>
<!--
This book (``The Linux Kernel'') may be reproduced and distributed 
in whole or in part, without fee, subject to the following conditions:
-->
本書(The Linux Kernel)は、次の条件に従うかぎり、無料で、全体もしくは一部を
複製および配布することが可能です。

<itemize>
<!--
The copyright notice above and this permission notice must be
preserved complete on all complete or partial copies.
-->
<item>
上記著作権表示とこの配布条件とが、全体もしくは一部の複製上のすべてに
完全なかたちで保持されなければなりません。

<p>
<!--
Any translation or derived work must be approved by the
author in writing before distribution.<newline>
-->
<item>
翻訳もしくは派生文書を作成した場合、配布に先だって著者に連絡し、その承認
を得なければなりません。

<p>
<!--
If you distribute this work in part, instructions for obtaining the 
complete version of this manual must be included, and a means for obtaining 
a complete version provided.<newline>
-->
<item>
この文書の一部のみを配布する場合、この文書全体が入手可能であることを
告知し、全体を入手する方法を示されなければなりません。

<p>
<!--
Small portions may be reproduced as illustrations for reviews or 
quotes in other works without this permission notice if proper citation is 
given.<newline>
-->
<item>
書評での抜粋及び他の文書での引用としてこの文書の僅かな部分を抜き書きする
場合は、引用元を適切に明示する限り、この許可条項を表記する必要はありません。
</itemize>

<p>
<!--
Exceptions to these rules may be granted for academic purposes: Write
to the author and ask. These restrictions are here to protect us as 
authors, not to restrict you as learners and educators.<newline>
-->
学術目的での利用については、これらの規定の適用例外となる場合があるので、
著者に連絡を取り、尋ねてください。こうした制限は著者としての我々を守るため
のものであり、学習者や教育者への制限を課すことを意図するものではありません。


<!--
All source code in this document is placed under the GNU General Public 
License, available via anonymous FTP from 
<tt>prep.ai.mit.edu:/pub/gnu/COPYING</tt>.  
It is also reproduced in appendix 
(訳注: HTML リファレンス表示)../appendices/gpl.html" gpl.
-->
<p>この文書内のすべてのソースコード(文書自体を含む)には、GNU General Public 
License が適用されます。左記ライセンスは、匿名 FTP サイトである、
<tt>prep.ai.mit.edu:/pub/gnu/COPYING</tt> で入手が可能です。
本書の
<ref id="chapter_gpl" name="The GNU General Public Lincense">
は、そのライセンスのコピーとなっています。





<!--PS 版に付属する参考文献集-->
<sect>Bibliography<label id="bibliography">
<p>
<enum>
<item>Richard L. Sites, <it>Alpha Architecture Reference Manual</it>, Digital 
Press
<newline>(訳注: alpha 関連文書は、<htmlurl 
url="http://ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html" 
name="http://ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html"> から入手が可能です。)

<p><item>Matt Welsh and Lar Kaufman, <it>Running Linux</it>, O'Reilly & 
Associates, Inc, ISBN 1-56592-100-3
<newline>(訳注:「Running Linux, 導入からネットワーク構築まで」,
山崎康宏 技術監修、小嶋隆一 訳、1996年4月発行, O'Reilly ジャパン, 
ISBN 4-900900-00-1)

<p><item>PCI Special Interest Group, <it>PCI Local Bus Specification</it>
<newline>(訳注: 関連リンク <htmlurl url="http://www.pcisig.com/" 
name="http://www.pcisig.com">)

<p><item>PCI Special Interest Group, <it>PCI BIOS ROM Specification</it>

<p><item>PCI Special Interest Group, <it>PCI to PCI Bridge Architecture 
Specification</it>

<p><item>Intel, <it>Peripheral Components</it>, Intel 296467, ISBN 
1-55512-207-8

<p><item>Brian W. Kernighan and Dennis Richie, 
<it>The C Programming Language</it> Prentice Hall, ISBN 0-13-11-362-8
<newline>(訳注: 「プログラミング言語 C 」,石田晴久 訳, 1989, 共立出版, ISBN 
4-320-02692-6)

<p><item>Steven Levy, <it>Hackers</it>, Penguin, ISBN 0-14-023269-9

<label id="bibliography_intel">
<p><item>Intel, <it>Intel 486 Prosessor Family: Programmer's Reference Manual
</it>, Intel
<newline>(訳注: おそらく同種の内容の文書として、
Intel Architecture Software Developer's Manual, Volume 1,2,3 があります。
インテルのサイト <htmlurl 
url="http://www.intel.co.jp/jp/developer/vtune/cbts/refman.htm" 
name="http://www.intel.co.jp/jp/developer/vtune/cbts/refman.htm"> 
でご確認ください。)

<p><item>Comer D. E, <it>Interworking with TCP/IP, Volume 1 - Principle, 
Protocols and Architecture</it>, Prentice Hall International Inc
<newline>(訳注: 「TCP/IP によるネットワーク構築 Vol.1 (第 2 版)」,村井純/
楠本博之訳, 共立出版, 1993, ISBN 4-320-02667-5)

<p><item>David Jagger, <it>ARM Architecture Reference Manual</it>, 
Prentice Hall, ISBN 0-13-736299-4
</enum>

以下は、訳注です。
<itemize>
<item>
「Linux カーネルインターナル」, M.Beck, H.Bohme,他, 株式会社クイック 訳, 
ASCII, 1999, ISBN4-7561-3135

<item>
「Linux デバイスドライバ], Alessandro Rubini, 山崎康宏 山崎邦子共訳, 
O'Reilly Japan, 1998, ISBN4-900900-73-7

<item>
「Unix カーネルの魔法」, B.Goodheart, J.Cox, 櫻川貴司 監訳, プレンティスホール,
 1997, ISBN4-931356-04-4
<item>
「Linux 2.0 カーネルブック」, R.Card, E.Dumas, 他, 臼田昭司 伊藤敏 他共訳, 
Ohmsha, 1999, ISBN4-274-07879-5 

<item>「Linux Core Kernel Commentary」, Scott Maxwell, 小嶋隆一 訳, 
小学館, 2000, ISBN4-7978-2006-3
...
</itemize>


<!--訳者のあとがき-->
<sect>日本語訳について<label id="chapter_jp">
<p>
この文書は、David A. Rusling 著 <htmlurl 
url="http://www.linuxdoc.org/LDP/tlk/tlk.html" name="The Linux Kernel"> 
の翻訳です。HTML 版とテキスト版があります。

訳文の HTML 版には、原文の PostScript 版にあるソースコードへのリファレンスを
リンクとして埋め込みました。ただ、JF サイトには、本文で直接参照される最低限の
ソースファイルしか上げていません。ソース全体をご覧になるには、<url 
url="ftp://ftp.linet.gr.jp/pub/JF/html/The-Linux-Kernel.tar.gz" 
name="この文書の HTML ソース">と、カーネル 2.0.33 のソースを
ダウンロードし、任意の場所に展開して、この文書のサブディレクトリ 
<tt>The-Linux-Kernel-images</tt> 下に <tt>linux</tt> という名前でソースへの
シンボリックリンクを張ってください。全ソースファイルが簡単に参照できるように
なります。

カーネルソースは、リングサーバー <htmlurl 
url="ftp://ftp.ring.gr.jp/archives/linux/kernel.org/kernel/v2.0" 
name="ftp://ftp.ring.gr.jp/archives/linux/kernel.org/kernel/v2.0"> 
や、お近くのミラーサイトからダウンロードできます。

<sect1>参考文献
<p>
この文書は、カーネル 2.0.33 に基づいています。2.2.x での変更については、
<htmlurl url="http://www.tux.org/lkml/#s10" 
name="The linux-kernel mailing list FAQ"> に簡単な説明があります。
2.4.x については、<htmlurl 
url="http://www.changelog.net/" name="ChangeLog"> に <htmlurl 
url="http://www.changelog.net/log/1999/special/wwol2.4" 
name="「素晴らしき Linux 2.4 の世界」"> という記事があり、LDP に、<htmlurl 
url="http://www.linuxdoc.org/LDP/lki/index.html" 
name="Linux Kernel Internal"> という文書があります。

この文書以外のカーネル関連文書については、<tt>/usr/src/linux/Documentation</tt>
 内の <tt>kernel-docs.txt</tt> や、<url 
url="http://jungla.dit.upm.es/&tilde;jmseyas/linux/kernel/hackers-docs.html" 
name="Kernel links"> に参考文献があります。また、本書では触れられていない 
Linux の起動についての文書として、JF に <url 
url="http://www.linux.or.jp/JF/JFdocs/readkernel.html" 
name="「コメントから読む Linux カーネル」"> があります。

市販されている日本語の Linux カーネル関連書籍については、<ref 
id="bibliography" name="bibliography"> をご覧下さい。


<sect1>謝辞
<p>
翻訳に際しては、JF Project のメンバー、特に次の皆さんにお世話になりました。

<verb>
川嶋  勤 さん
武井 伸光 さん
山森 浩幸 さん
瀬戸口 崇 さん
瀬藤  誠 さん
加藤 大典 さん
野本 浩一 さん
四亭  さん
水原  さん
佐野 武俊 さん
toshi さん
福田 さん
引地 信之さん
</verb>

武井さんと川嶋さんには、全編にわたり査読していただきました。特に川嶋さんには、
不明な点について繰り返し教えていただきました。山森さん、瀬戸口さん、瀬藤さん
には、何度も校正をお手伝いしていただきました。佐野さん、野本さん、丁寧な査読
ありがとうございました。ご協力いただいたすべての方に謹んで感謝いたします。


尚、誤訳や、誤字脱字等がありましたら、JF メーリングリスト
<tt>&lt;JF@linux.or.jp&gt;</tt> か、訳者までお知らせください。


千旦裕司 <tt>&lt;ysenda@pop01.odn.ne.jp&gt;</tt>

</article>
