<!doctype linuxdoctr system><!-- -*-mode: sgml-*- -->

<article>
<title>Linux Kernel 2.4 Internals</title>
<author>Tigran Aivazian <tt>tigran@veritas.com</tt></author>
<date>7 August 2002 (29 av 6001)</date>
<trans>訳: Hiroshi Miura <tt>miura@da-cha.org</tt></trans>
<tdate>22 May 2003</tdate>
<!-- 訳:三浦広志 miura@da-cha.org -->
<abstract>
<!--
Introduction to the Linux 2.4 kernel. The latest copy of this document
can be always downloaded from:
-->
この文書はLinux 2.4カーネルの手引きです。原文の最新版は、以下のURLからダウンロードできます。
<url url="http://www.moses.uklinux.net/patches/lki.sgml">

また、訳文の最新版は、
<url url="http://www.da-cha.org/">
にて配布されます。

<!--
This guide is now part of the Linux Documentation 
<url url="http://www.linuxdoc.org/guides.html">

or can be read online (latest version) at:

<url url="http://www.moses.uklinux.net/patches/lki.html">
-->
このガイドは、現在では、LDP (Linux Documentation Project)の一部となっており、
<url url="http://www.linuxdoc.org/guides.html">
から様々なフォーマットでダウンロードできます。
また、最新版は<url url="http://www.moses.uklinux.net/patches/lki.html">からオンラインで読むことができます。

<bf>This documentation is free software; you can redistribute
it and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.</bf>

<!--
The author is working as senior Linux kernel engineer at VERITAS Software
Ltd and wrote this book for the purpose of supporting the short training
course/lectures he gave on this subject, internally at VERITAS.
-->
著者は、VERITASソフトウエア社で、シニアLinuxカーネルエンジニアとして働いています。
そしてこの本は、VERITAS内部で、このタイトルで行っている短期間のトレーニングコース/講義の補助のために書き下したものです。
<!--
Thanks to 
Juan J. Quintela <tt>(quintela@fi.udc.es)</tt>,
Francis Galiegue <tt>(fg@mandrakesoft.com)</tt>,
Hakjun Mun <tt>(juniorm@orgio.net)</tt>,
Matt Kraai <tt>(kraai@alumni.carnegiemellon.edu)</tt>,
Nicholas Dronen <tt>(ndronen@frii.com)</tt>,
Samuel S Chessman <tt>(chessman@tux.org)</tt>,
Nadeem Hasan <tt>(nhasan@nadmm.com)</tt>
for various corrections and suggestions.

The Linux Page Cache chapter was written by:
Christoph Hellwig <tt>(hch@caldera.de)</tt>.

The IPC Mechanisms chapter was written by: 
Russell Weight <tt>(weightr@us.ibm.com)</tt> and Mingming Cao <tt>(mcao@us.ibm.com)</tt>

-->
謝辞:
Juan J. Quintela <tt>(quintela@fi.udc.es)</tt>,
Francis Galiegue <tt>(fg@mandrakesoft.com)</tt>,
Hakjun Mun <tt>(juniorm@orgio.net)</tt>,
Matt Kraai <tt>(kraai@alumni.carnegiemellon.edu)</tt>,
Nicholas Dronen <tt>(ndronen@frii.com)</tt>,
Samuel S Chessman <tt>(chessman@tux.org)</tt>,
Nadeem Hasan <tt>(nhasan@nadmm.com)</tt>,
Michael Svetlik <tt>(m.svetlik@ssi-schaefer-peem.com)</tt>
のみなさまには、多くの訂正と、ご意見をいただきました。

Linux ページキャッシュの章は、Christoph Hellwig <tt>(hch@caldera.de)</tt> によって書かれたものです。

IPC機構の章は、Russell Weight <tt>(weightr@us.ibm.com)</tt> と Mingming Cao <tt>(mcao@us.ibm.com)</tt> により書かれたものです。

IPC機構の章は、
Russell Weight <tt>(weightr@us.ibm.com)</tt> and Mingming Cao <tt>(mcao@us.ibm.com)</tt>
より書かれたものです。

本訳は、三浦広志<tt>(miura@da-cha.org)</tt>が著者の許可を得て訳出したものです。訳出についての指摘は、三浦までお願いします。
訳出にあたっては、小林＠四日市さん<tt>(zap03216@nifty.ne.jp)</tt>、小幡昇さん<tt>(noboru@ylug.org)</tt>から貴重なご指摘と訂正をいただきました。ありがとうございます。
</abstract>

<toc>

<sect><!-- Booting --> ブート<p>
<sect1><!-- Building the Linux Kernel Image --> Linuxカーネルイメージの作成<p>
<!--
This section explains the steps taken during compilation of the Linux kernel
and the output produced at each stage.
The build process depends on the architecture so I would like to emphasize
that we only consider building a Linux/x86 kernel.
-->
この章では、Linuxカーネルをコンパイルをする時に取られるステップと各ステージの生成物について解説します。
ビルド工程はアーキテクチャにより異なりますが、ここではLinux/x86カーネルのビルドについてだけ考えることにします。

<!--
When the user types 'make zImage' or 'make bzImage' the resulting bootable
kernel image is stored as
-->
ユーザが、'make zImage'あるいは'make bzimage'とタイプすると、その結果の起動イメージは、それぞれ<tt>arch/i386/boot/zImage</tt> と <tt>arch/i386/boot/bzImage</tt> になります。
<!-- 
Here is how the image is built:
-->
ここでは、どのようにイメージが作られるかを見ていきましょう。
<enum>
<!--
<item> C and assembly source files are compiled into ELF relocatable object format (.o) and
       some of them are grouped logically into archives (.a) using
	   <bf>ar(1)</bf>.
-->
<item> C とアセンブリのソースファイルは、ELF 再配置可能オブジェクト形式 (.o) へとコンパイルされる。中には論理的なグループとして <bf>ar(1)</bf> を使ってアーカイブ形式 (.a) にされるものもある。
<!--
<item> Using <bf>ld(1)</bf>, the above .o and .a are linked into <tt>vmlinux</tt> which is a
       statically linked, non-stripped ELF 32-bit LSB 80386 executable file.
-->
<item> <bf>ld(1)</bf> を使って、上記の .o と .a は 'vmlinux' ファイルへとリンクされる。'vmlinux'ファイルは、静的にリンクされたストリップ前の ELF 32-bit LSB 80386 実行形式ファイルである。

<!-- 
<item> <tt>System.map</tt> is produced by <bf>nm vmlinux</bf>, irrelevant or uninteresting
       symbols are grepped out.
 -->
<item> <tt>System.map</tt> は、'nm vmlinux' から作成される。関連がないシンボルや些細なシンボルは、fマップファイルから除外される。

<!-- 
<item> Enter directory <tt>arch/i386/boot</tt>.
 -->
<item> <tt>arch/i386/boot</tt> ディレクトリに移る。

<!-- 
<item> Bootsector asm code <tt>bootsect.S</tt> is preprocessed either with or without
       <bf>-D__BIG_KERNEL__</bf>, depending on whether the target is
       bzImage or zImage, into <tt>bbootsect.s</tt> or <tt>bootsect.s</tt> respectively.
 -->
<item> ブートセクタのアセンブラコード <tt>bootsect.S</tt> は、ターゲットが bzImage か zImage かによって <bf>-D__BIG_KERNEL__ </bf> をつけるか、あるいはつけないかされて、プリプロセッサが
処理する。そして、各々の場合で <tt>bbootsect.s</tt> かあるいは <tt>bootsect.s</tt> が生成される。

<!-- 
<item> <tt>bbootsect.s</tt> is assembled and then converted into 'raw binary' form
       called <tt>bbootsect</tt> (or <tt>bootsect.s</tt> assembled and raw-converted into
       <tt>bootsect</tt> for zImage).
 -->
<item> <tt>bbootsect.s</tt> はアセンブルされ、その後、<tt>bbootsect</tt> という名前の'rawバイナリ'形式へと変換される。(あるいは、<tt>bootsect.s</tt> がアセンブルされ zImage 向けの <tt>bootsect</tt> へrawバイナリ変換される)

<!-- 
<item> Setup code <tt>setup.S</tt> (<tt>setup.S</tt> includes <tt>video.S</tt>) is preprocessed into
       <tt>bsetup.s</tt> for bzImage or <tt>setup.s</tt> for zImage. In the same way as the
       bootsector code, the difference is marked by <bf>-D__BIG_KERNEL__</bf> present
       for bzImage.  The result is then converted into 'raw binary' form
       called <tt>bsetup</tt>.
 -->
<item> セットアップ用のコード setup.S (setup.Sは、video.Sを含む)は、 bzImageのときはbsetup.sへ、zImageの時はsetup.sへプリプロセッサの処理結果が出力される。ブートセクタのコードと同じ方法で処理されるが、bzImageの場合に、-D__BIG_KERNEL__タグが付与されるところに違いがある。生成物は、bsetupという名前の'rawバイナリ'形式へと変換される。

<!-- 
<item> Enter directory <tt>arch/i386/boot/compressed</tt> and convert 
       <tt>/usr/src/linux/vmlinux</tt> to $tmppiggy (tmp filename) in raw binary
       format, removing <tt>.note</tt> and <tt>.comment</tt> ELF sections.

<item> <bf>gzip -9 < $tmppiggy > $tmppiggy.gz</bf></item>
 -->
<item> arch/i386/boot/compressed というディレクトリへとうつり、 /usr/src/linux/vmlinux をrawバイナリ形式の、$tmppiggy (テンポラリファイル名)へと変換する。またこの際に、ELF フォーマットでの .note セクションと .comment セクションが削除される。

<item> gzip -9 < $tmppiggy > $tmppiggy.gz</item>

<!-- 
<item> Link $tmppiggy.gz into ELF relocatable (<bf>ld -r</bf>) <tt>piggy.o</tt>.
 -->
<item> $tmppiggy.gz を ELF 再配置可能形式の (ld -r) piggy.o へリンクする。
<!--
<item> Compile compression routines <tt>head.S</tt> and <tt>misc.c</tt> (still in 
       <tt>arch/i386/boot/compressed</tt> directory) into ELF objects <tt>head.o</tt> and
       <tt>misc.o</tt>.
 -->
<item> head.S と misc.c からなる圧縮ルーチンをコンパイルする(まだ arch/i386/boot/compressed ディレクトリ)。そして ELF オブジェクト形式の head.o と、misc.o を生成する。

<!--
<item> Link together <tt>head.o</tt>, <tt>misc.o</tt> and <tt>piggy.o</tt> into <tt>bvmlinux</tt> (or <tt>vmlinux</tt> for
       zImage, don't mistake this for <tt>/usr/src/linux/vmlinux</tt>!). Note the
       difference between <bf>-Ttext 0x1000</bf> used for <tt>vmlinux</tt> and <bf>-Ttext 0x100000</bf>
       for <tt>bvmlinux</tt>, i.e. for bzImage compression loader is high-loaded.
 -->
<item> head.o と misc.o、そして piggy.o をリンクし、bvmlinuxとする(あるいは zImageの場合は、vmlinux にする。 /usr/src/linux/vmlinux と間違わないこと)。ここで、vmlinux では-Ttext 0x1000 だが、bvmlinux の場合 -Ttext 0x100000 というところに違いがある。bzImage の圧縮ローダは high エリアにロードされる。

<!--
<item> Convert <tt>bvmlinux</tt> to 'raw binary' <tt>bvmlinux.out</tt> removing <tt>.note</tt> and 
       <tt>.comment</tt> ELF sections.
 -->
<item>.note と .comment の2つの ELF セクションを削除して bvmlinux は 'raw バイナリ'形式の bvmlinux.outへと変換される。

<!--
<item> Go back to <tt>arch/i386/boot</tt> directory and, using the program <bf>tools/build</bf>,
       cat together <tt>bbootsect</tt>, <tt>bsetup</tt> and <tt>compressed/bvmlinux.out</tt> into <tt>bzImage</tt>
	   (delete extra 'b' above for <tt>zImage</tt>). This writes important variables
       like <tt>setup_sects</tt> and <tt>root_dev</tt> at the end of the bootsector.
 -->
<item> ディレクトリ arch/i386/boot へ戻り、tools/build にあるプログラムを使って、 bbootsect + bsetup + 圧縮された/bvmlinux.out を bzImage へとつなぎ合わせる(zImage の場合は、各々の b を取ったものをつなぎ合わせる)。これは、さらに setup_sects や、root_dev のような重要な変数を、ブートセクタの最後のところへと書き込む。
</enum>

<!-- 
The size of the bootsector is always 512 bytes. The size of the setup must
be greater than 4 sectors but is limited above by about 12K - the rule
is:
-->
ブートセクタの大きさは、常に512バイトです。setupのサイズは、4セクタより大きくなければなりませんが、最大でも約12Kに制限されています。これは次のようなルールで計算されます。

<!-- 
0x4000 bytes >= 512 + setup_sects * 512 + room for stack while running 
bootsector/setup
 -->
0x4000 bytes >= 512 + setup のセクタ数 * 512 + ブートセクタ／setupを実行するときのスタックの領域

<!-- 
We will see later where this limitation comes from.
 -->
後で、この制限がどこからきているのか学ぶことにしましょう。

<!-- 
The upper limit on the bzImage size produced at this step is about 2.5M for
booting with LILO and 0xFFFF paragraphs (0xFFFF0 = 1048560 bytes) for
booting raw image, e.g. from floppy disk or CD-ROM (El-Torito emulation mode).
 -->
bzImage のサイズの上限は、現時点では LILO からのブートで約2.5M となっています。そして、たとえば、フロッピーディスクや、CD-ROM (El-Torito エミュレーションモードにおいて)といった、raw イメージのブートでは 0xFFFF パラグラフ分(0xFFFF0 = 1048560 バイト)になります。

<!-- 
Note that while <bf>tools/build</bf> does validate the size of boot sector, kernel image
and lower bound of setup size, it does not check the *upper* bound of said
setup size. Therefore it is easy to build a broken kernel by just adding some
large ".space" at the end of <tt>setup.S</tt>.
 -->
ここで <bf>tools/build</bf> は、カーネルイメージのブートセクタやカーネルイメージ、setup の下限サイズを検証します。しかし、setup の上限については、チェックしません。したがって、<tt>setup.S</tt> の最後に余分な大きな".space"を付加するだけで、簡単に壊れたカーネルが作成できてしまいます。


<!-- 
<sect1>Booting: Overview<p>
 -->
<sect1>ブート: 概論<p>

<!-- 
The boot process details are architecture-specific, so we shall
focus our attention on the IBM PC/IA32 architecture.
Due to old design and backward compatibility, the PC firmware boots the
operating system in an old-fashioned manner.
This process can be separated into the following six logical stages:
 -->
ブートプロセスの詳細部分はアーキテクチャに依存しています。そこで IBM PC/IA32 のアーキテクチャへ注目することにします。古いデザインですし、また過去への互換性への問題から、PC のファームウエアは、オペレーティングシステムをブートするときには、古い方式で起動してきます。このプロセスは、つぎの 6 つの論理的なステップへと分割できます。

<!-- 
<enum>
<item> BIOS selects the boot device.
<item> BIOS loads the bootsector from the boot device.
<item> Bootsector loads setup, decompression routines and compressed kernel
       image.
<item> The kernel is uncompressed in protected mode.
<item> Low-level initialisation is performed by asm code.
<item> High-level C initialisation.
</enum>
-->
<enum>
<item> BIOS はブートデバイスを選ぶ。
<item> BIOS はブートデバイスのブートセクタをメモリーへと読み込む。
<item> ブートセクタは、setup と解凍ルーチンそして、圧縮されたカーネルを読み込む。
<item> カーネルは、プロテクトモードで解凍される。
<item> ローレベルの初期化が asm コードで行われる。
<item> ハイレベルの C での初期化が行われる。
</enum>

<!-- 
<sect1>Booting: BIOS POST<p>
 -->
<sect1>ブート: BIOS POST<p>
<!-- 
<enum>
<item> The power supply starts the clock generator and asserts #POWERGOOD
       signal on the bus.
<item> CPU #RESET line is asserted (CPU now in real 8086 mode).
<item> %ds=%es=%fs=%gs=%ss=0, %cs=0xFFFF0000,%eip = 0x0000FFF0 (ROM BIOS POST code).
<item> All POST checks are performed with interrupts disabled.
<item> IVT (Interrupt Vector Table) initialised at address 0.
<item> The BIOS Bootstrap Loader function is invoked via <bf>int 0x19</bf>,
       with %dl containing the boot device 'drive number'. This loads 
       track 0, sector 1 at physical address 0x7C00 (0x07C0:0000).
</enum>
 -->
<enum>
<item> 電源が入り、クロックジェネレータが開始する。また、バス上の #POWERGOOD 信号がアサートされる。
<item> CPU #RESET 信号がアサートされる (この時 CPU は、8086 互換のリアルモードである)。
<item> %ds=%es=%fs=%gs=%ss=0, %cs=0xFFFF0000, %eip = 0x0000FFF0 (ROM BIOS POST コード)。
<item> 割り込みが禁止された状態で、すべての POST チェックが行われる。
<item> IVT (割り込みベクトルテーブル) がアドレス 0 へ初期化される。 
<item> BIOS の ブートストラップローダ関数が、<bf>int 0x19</bf> により呼び出される。このとき、%dl は、ブートデバイスの「ドライブ番号」である。この関数は、 トラック 0 セクタ 1 番を物理アドレスの 0x7C00 (0x07C0:0000) へと読み込む。
</enum>

<!-- 
<sect1>Booting: bootsector and setup<p>
 -->
<sect1>ブート: ブートセクタと setup<p>

<!-- 
The bootsector used to boot Linux kernel could be either:
-->
Linuxカーネルをブートするために使われるブートセクタは、
<!-- 
<itemize>
<item> Linux bootsector (<tt>arch/i386/boot/bootsect.S</tt>),
<item> LILO (or other bootloader's) bootsector, or
<item> no bootsector (loadlin etc)
</itemize>
 -->
<itemize>
<item> Linux ブートセクタ (<tt>arch/i386/boot/bootsect.S</tt>),
<item> LILO (あるいは他のブートローダ) ブートセクタ、あるいは
<item> ブートセクタはない(loadlinなど)
</itemize>
のいずれかになります。
<!-- 
We consider here the Linux bootsector in detail.
The first few lines initialise the convenience macros to be used for segment
values:
 -->
ここで、Linuxブートセクタの詳細を見てみます。最初の数行では、セグメント値に使う便宜上のマクロが初期化されています。
<tscreen><code>
29 SETUPSECS = 4		/* default nr of setup-sectors */
30 BOOTSEG   = 0x07C0		/* original address of boot-sector */
31 INITSEG   = DEF_INITSEG	/* we move boot here - out of the way */
32 SETUPSEG  = DEF_SETUPSEG	/* setup starts here */
33 SYSSEG    = DEF_SYSSEG	/* system loaded at 0x10000 (65536) */
34 SYSSIZE   = DEF_SYSSIZE	/* system size: # of 16-byte clicks */
</code></tscreen>
<!-- 
(the numbers on the left are the line numbers of bootsect.S file)
The values of <tt>DEF_INITSEG</tt>, <tt>DEF_SETUPSEG</tt>, <tt>DEF_SYSSEG</tt> and <tt>DEF_SYSSIZE</tt> are taken
from <tt>include/asm/boot.h</tt>:
 -->
(左の数字は bootsect.S ファイルの行番号である) <tt>DEF_INITSEG</tt>, <tt>DEF_SETUPSEG</tt>, <tt>DEF_SYSSEG</tt> および <tt>DEF_SYSSIZE</tt> の値は、 <tt>include/asm/boot.h</tt> で定義されており、
<tscreen><code>
/* Don't touch these, unless you really know what you're doing. */
#define DEF_INITSEG     0x9000
#define DEF_SYSSEG      0x1000
#define DEF_SETUPSEG    0x9020
#define DEF_SYSSIZE     0x7F00
</code></tscreen>
となっています。
<!-- 
Now, let us consider the actual code of <tt>bootsect.S</tt>:
 -->
さて、実際の<tt>bootsect.S</tt>のコードを見ていきましょう。

<tscreen><code>
    54		movw	$BOOTSEG, %ax
    55		movw	%ax, %ds
    56		movw	$INITSEG, %ax
    57		movw	%ax, %es
    58		movw	$256, %cx
    59		subw	%si, %si
    60		subw	%di, %di
    61		cld
    62		rep
    63		movsw
    64		ljmp	$INITSEG, $go
       
    65	# bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde).  We
    66	# wouldn't have to worry about this if we checked the top of memory.  Also
    67	# my BIOS can be configured to put the wini drive tables in high memory
    68	# instead of in the vector table.  The old stack might have clobbered the
    69	# drive table.
       
    70	go:	movw	$0x4000-12, %di		# 0x4000 is an arbitrary value >=
    71						# length of bootsect + length of
    72						# setup + room for stack;
    73						# 12 is disk parm size.
    74		movw	%ax, %ds		# ax and es already contain INITSEG
    75		movw	%ax, %ss
    76		movw	%di, %sp		# put stack at INITSEG:0x4000-12.
</code></tscreen>

<!-- 
Lines 54-63 move the bootsector code from address 0x7C00 to 0x90000.
This is achieved by:
 -->
54-63行は、アドレス 0x7C00 から 0x90000 へブートセクタコードを移動しています。これは、次のような手順で実行されています。
<!-- 
<enum>
<item> set %ds:%si to $BOOTSEG:0 (0x7C0:0 = 0x7C00)

<item> set %es:%di to $INITSEG:0 (0x9000:0 = 0x90000)

<item> set the number of 16bit words in %cx (256 words = 512 bytes = 1 sector)

<item> clear DF (direction) flag in EFLAGS to auto-increment addresses (cld)

<item> go ahead and copy 512 bytes (rep movsw)
</enum>
 -->
<enum>
<item>  %ds:%si へ $BOOTSEG:0 (0x7C0:0 = 0x7C00) を設定する。

<item>  %es:%di へ $INITSEG:0 (0x9000:0 = 0x90000)を設定する。

<item> %cx へ16ビットのワード値を代入する (256 ワード = 512 バイト = 1 セクタ)。

<item> 自動的にアドレスを加算するよう(cld)に、EFLAGS の DF (direction) フラグをクリアする。

<item> 先に進み、 512 bytes (rep movsw)コピーする。
</enum>

<!-- 
The reason this code does not use <tt>rep movsd</tt> is intentional (hint - .code16).
 -->
このコードが<tt>rep movsd</tt>を使わないのは、特別な理由があります。(ヒント .code16)
<!-- 
Line 64 jumps to label <tt>go:</tt> in the newly made copy of the
bootsector, i.e. in segment 0x9000. This and the following three
instructions (lines 64-76) prepare the stack at $INITSEG:0x4000-0xC, i.e. 
%ss = $INITSEG (0x9000) and %sp = 0x3FF4 (0x4000-0xC). This is where the
limit on setup size comes from that we mentioned earlier (see Building the
Linux Kernel Image).
 -->
64行目では、新しく作られたブートセクタのコピーのラベル<tt>go:</tt>へジャンプする。つまり、セグメント 0x9000です。これと続く3つの命令(64-76行)では、$INITSEG:0x4000-0xCへスタックを設定しています。つまり、%ss = $INITSEG (0x9000) と %sp = 0x3FF4 (0x4000-0xC) です。ここに前出のsetupのサイズ制限がどこからきているかの理由があります (Linux カーネルイメージの作成 参照)。

<!-- 
Lines 77-103 patch the disk parameter table for the first disk to
allow multi-sector reads:
 -->
77-103行では、一つめのディスクパラメータテーブルを上書きして、マルチセクタ読み込みができるようにします。
<tscreen><code>
    77	# Many BIOS's default disk parameter tables will not recognise
    78	# multi-sector reads beyond the maximum sector number specified
    79	# in the default diskette parameter tables - this may mean 7
    80	# sectors in some cases.
    81	#
    82	# Since single sector reads are slow and out of the question,
    83	# we must take care of this by creating new parameter tables
    84	# (for the first disk) in RAM.  We will set the maximum sector
    85	# count to 36 - the most we will encounter on an ED 2.88.  
    86	#
    87	# High doesn't hurt.  Low does.
    88	#
    89	# Segments are as follows: ds = es = ss = cs - INITSEG, fs = 0,
    90	# and gs is unused.
       
    91		movw	%cx, %fs		# set fs to 0
    92		movw	$0x78, %bx		# fs:bx is parameter table address
    93		pushw	%ds
    94		ldsw	%fs:(%bx), %si		# ds:si is source
    95		movb	$6, %cl			# copy 12 bytes
    96		pushw	%di			# di = 0x4000-12.
    97		rep				# don't need cld -> done on line 66
    98		movsw
    99		popw	%di
   100		popw	%ds
   101		movb	$36, 0x4(%di)		# patch sector count
   102		movw	%di, %fs:(%bx)
   103		movw	%es, %fs:2(%bx)
</code></tscreen>

<!-- 
The floppy disk controller is reset using BIOS service int 0x13 function 0 
(reset FDC) and setup sectors are loaded immediately after the 
bootsector, i.e. at physical address 0x90200 ($INITSEG:0x200), again using
BIOS service int 0x13, function 2 (read sector(s)).
This happens during lines 107-124:
 -->
BIOS のサービスの int 0x13 ファンクション0 (reset FDC) を使って、フロッピーディスクコントローラをリセットします。そして、setup セクタが bootsector のすぐ後へ読み込まれます。つまり 物理アドレスの0x90200 ($INITSEG:0x200) です。そして、再度BIOSサービスのint 0x13 ファンクション 2(read sector(s)) を呼び出します。この辺りは、107-124行に記述されています。

<tscreen><code>
   107	load_setup:
   108		xorb	%ah, %ah		# reset FDC 
   109		xorb	%dl, %dl
   110		int 	$0x13	
   111		xorw	%dx, %dx		# drive 0, head 0
   112		movb	$0x02, %cl		# sector 2, track 0
   113		movw	$0x0200, %bx		# address = 512, in INITSEG
   114		movb	$0x02, %ah		# service 2, "read sector(s)"
   115		movb	setup_sects, %al	# (assume all on head 0, track 0)
   116		int	$0x13			# read it
   117		jnc	ok_load_setup		# ok - continue
       
   118		pushw	%ax			# dump error code
   119		call	print_nl
   120		movw	%sp, %bp
   121		call	print_hex
   122		popw	%ax	
   123		jmp	load_setup
       
   124	ok_load_setup:
</code></tscreen>
<!-- 
If loading failed for some reason (bad floppy or someone pulled the diskette
out during the operation), we dump error code and retry in an endless
loop. 
The only way to get out of it is to reboot the machine, unless retry succeeds
but usually it doesn't (if something is wrong it will only get worse).
 -->
もし、なにかの原因(フロッピーが劣化しているとか、使用中にディスケットを抜き去ったとか)で読み込みが失敗したら、エラーコードを表示しながら、無限に再試行されます。再試行が成功していない状態から抜け出すには、パソコンを再起動するほかありません。しかし、通常このようなことは起りません (もしなにかが間違えているとしたら、単におかしくなったのです)。
<!-- 
If loading setup_sects sectors of setup code succeeded we jump to label
<tt>ok_load_setup:</tt>.
 -->
もし、setupのコードのsetup_sectセクタの読み込みがうまく行くと、ラベル <tt>ok_load_setup:</tt> へジャンプします。
<!-- 
Then we proceed to load the compressed kernel image at physical
address 0x10000. This
is done to preserve the firmware data areas in low memory (0-64K).
After the kernel is loaded, we jump to $SETUPSEG:0 (<tt>arch/i386/boot/setup.S</tt>).
Once the data is no longer needed (e.g. no more calls to BIOS) it is
overwritten by moving the entire (compressed) kernel image from 0x10000 to
0x1000 (physical addresses, of course).
This is done by <tt>setup.S</tt> which sets things up for protected mode and jumps
to 0x1000 which is the head of the compressed kernel, i.e.
<tt>arch/386/boot/compressed/{head.S,misc.c}</tt>.
This sets up stack and calls <tt>decompress_kernel()</tt> which uncompresses the
kernel to address 0x100000 and jumps to it.
 -->
その後、圧縮されたカーネルイメージを物理アドレス 0x10000 へと読み込みます。これは、低位のメモリ領域 (0-64K) にあるファームウエアのデータ領域を保護するために行われています。カーネルが読み込まれると、$SETUPSEG:0 (<tt>arch/i386/boot/setup.S</tt>)にジャンプします。ファームのデータがもう要らなくなれば (例えば、もうBIOSをコールしないなど)、（圧縮された）すべてのカーネルのイメージを 0x10000 から 0x1000 (当然、物理アドレス)へ移します。その結果、この領域は上書きされます。
これは、<tt>setup.S</tt>で実行されます。このコードでは、プロテクトモードへの移行に必要なことを行い、圧縮カーネルの先頭である 0x1000 へとジャンプするようになっています。つまり、<tt>arch/i386/boot/compressed/{head.S,misc.c}</tt> です。
さらに、スタックを設定し、<tt>decompress_kernel()</tt> を呼び出します。このルーチンではカーネルをアドレス 0x100000 へ展開します。そして、その展開されたカーネルへジャンプします。

<!-- 
Note that old bootloaders (old versions of LILO) could only load the
first 4 sectors of setup, which is why there is code in setup to load the rest of
itself if needed. Also, the code in setup has to take care of various
combinations of loader type/version vs zImage/bzImage and is therefore
highly complex.
 -->
ここで古いブートローダ(古いLILO)では、setupの最初の4セクタしか読み込むことが
できません。そのため、もし必要であれば自分自身の残りを読み込むようなsetupの
コードが存在しています。もちろん、setup のコードは様々なタイプ/バージョンのローダとzImage/bzImageの組合わせを取り扱わなければなりません。そのため、非常に複雑です。

<!-- 
Let us examine the kludge in the bootsector code that allows to load a big
kernel, known also as "bzImage".
 -->
ここで、"bzImage" として知られている大きなカーネルのロードを行うブートセクタコードでの対処方法を見てみましょう。
<!-- 
The setup sectors are loaded as usual at 0x90200, but the kernel is loaded
64K chunk at a time using a special helper routine that calls BIOS to move
data from low to high memory. This helper routine is referred to by
<tt>bootsect_kludge</tt> in <tt>bootsect.S</tt> and is defined as <tt>bootsect_helper</tt> in <tt>setup.S</tt>.
 -->
setupのセクタは、通常0x90200にロードされますが、この時のカーネルは、一度に64Kの固まりで読み込まれるような特別な補助ルーチンを使います。このルーチンは、データを低位アドレスから、高位アドレスへ移動するBIOSコールを呼び出します。この補助ルーチンは、<tt>setup.S</tt>の<tt>bootsect_kludge</tt>ラベルから参照されます。そして<tt>bootsect_helper</tt>として<tt>setup.S</tt>で定義されています。
<!-- 
The <tt>bootsect_kludge</tt> label in <tt>setup.S</tt> contains the value of setup segment
and the offset of <tt>bootsect_helper</tt> code in it so that bootsector can use the <tt>lcall</tt>
instruction to jump to it (inter-segment jump).
 -->
<tt>setup.S</tt>の<tt>bootsect_klugh</tt>ラベルは、setupセグメント値と、その中の<tt>bootsect_helper</tt>コードのオフセットからなっています。そのため、ブートセクタでは、ジャンプするのに<tt>lcall</tt>命令を使うことができます。(つまりセグメント内ジャンプです)
<!-- 
The reason why it is in <tt>setup.S</tt> is simply because there is no more space left
in bootsect.S (which is strictly not true - there are approximately 4 spare bytes
and at least 1 spare byte in <tt>bootsect.S</tt> but that is not enough, obviously).
This routine uses BIOS service int 0x15 (ax=0x8700) to move to high memory
and resets %es to always point to 0x10000. This ensures that the code in <tt>bootsect.S</tt>
doesn't run out of low memory when copying data from disk.
 -->
<tt>setup.S</tt>にこれがあるのは、単にbootsect.Sには、もう余分なスペースが無いからなのです。（これは厳密には正しくはありません -- <tt>bootsect.S</tt>には、約4バイトと少なくとも1バイトの余裕があります。しかし、明らかに十分とはいえません)。このルーチンは高位のメモリへ移動するのに、int 0x15(ax=0x8700)のBIOSサービスを使い、%esを常に0x10000を示すようリセットします。これは、<tt>bootsect.S</tt>のコード内で、ディスクからデータをコピーするときに低位メモリが足らなくならないことを保証します。
<!--
<sect1> Using LILO as a bootloader <p>
-->
<sect1> LILOをブートローダとして使う <p>
<!--
There are several advantages in using a specialised bootloader (LILO) over
a bare bones Linux bootsector:
-->
Linuxブートセクタを裸で使わず、特別なブートローダ(LILO)を使うことで、利点が生まれます。
<!--
<enum>
<item> Ability to choose between multiple Linux kernels or even multiple OSes.
<item> Ability to pass kernel command line parameters (there is a patch
       called BCP that adds this ability to bare-bones bootsector+setup).
<item> Ability to load much larger bzImage kernels - up to 2.5M vs 1M.
</enum>
-->
<enum>
<item> 複数の Linux カーネルから選択したり、さらには複数の OS も選択できるようになります。
<item> カーネルにコマンドラインパラメタを渡すことができるようになります (裸の bootsector+setup にこの機能を付加できる BCP というパッチがあります)。
<item> よりサイズの大きな bzImage カーネルをロードすることができます。1M までのところが 2.5M まで可能になります。
</enum>

<!--
Old versions of LILO (v17 and earlier) could not load bzImage kernels. The
newer versions (as of a couple of years ago or earlier) use the same
technique as bootsect+setup of moving data from low into high memory by
means of BIOS services. Some people (Peter Anvin notably) argue that zImage
support should be removed. The main reason (according to Alan Cox) it stays
is that there are apparently some broken BIOSes that make it impossible to
boot bzImage kernels while loading zImage ones fine.
-->
LILO の古いバージョン(v17以前)では、bzImage カーネルをロードすることができません。新しいバージョンでは(ここ数年前より最近では)、bootsect+setup と同じように、BIOS サービスにある低位メモリから高位メモリへデータを移動するテクニックを使っています。人によっては(特に Peter Anvinは)、zImage サポートは削除すべきだと主張しています。それでも残されている主な理由は、(Alan Cox によると) zImage のロードは可能だが、bzImage カーネルのブートができないような壊れた BIOS が明らかに存在しているためだということです。

<!--
The last thing LILO does is to jump to <tt>setup.S</tt> and things proceed as normal.
-->
LILO は最後に、<tt>setup.S</tt>へジャンプし、通常どおりの処理を続けます。

<!--
<sect1> High level initialisation <p>
-->
<sect1> 高いレベルの初期化 <p>

<!--
By "high-level initialisation" we consider anything which is not directly
related to bootstrap, even though parts of the code to perform this are
written in asm, namely <tt>arch/i386/kernel/head.S</tt> which is the head of the
uncompressed kernel. The following steps are performed:
-->
「高いレベルの初期化」では、ブートに直接関連しないものについて考えます。しかし、これを行うコードの一部は、
展開されたカーネルの先頭にある<tt>arch/i386/kernel/head.S</tt>と呼ばれるアセンブラで書かれています。そこでは、以下のような処理が行われます。

<!--
<enum>
<item> Initialise segment values (%ds = %es = %fs = %gs = __KERNEL_DS = 0x18).
<item> Initialise page tables.
<item> Enable paging by setting PG bit in %cr0.
<item> Zero-clean BSS (on SMP, only first CPU does this).
<item> Copy the first 2k of bootup parameters (kernel commandline).
<item> Check CPU type using EFLAGS and, if possible, cpuid, able to detect
       386 and higher.
<item> The first CPU calls <tt>start_kernel()</tt>, all others call
       <tt>arch/i386/kernel/smpboot.c:initialize_secondary()</tt> if ready=1,
       which just reloads esp/eip and doesn't return.
</enum>
-->
<enum>
<item> セグメント値を初期化する (%ds = %es = %fs = %gs = __KERNEL_DS = 0x18)。
<item> ページテーブルを初期化する。
<item> %cr0のPGビットをセットし、ページングを有効にする。
<item> BSSをゼロで埋める (SMPでは、１つめのCPUだけがこの処理を行う)。
<item> ブートパラメータの最初の2kをコピーする (カーネルコマンドライン)。
<item> CPUタイプをEFLAGSと、可能であれば386以上を確認できるcpuidでチェックする。
<item> １つめのCPUは<tt>start_kernel()</tt>を呼び出し、他のCPUは、ready=1であれば単に esp/eip をリロードするのみで戻ってこない関数の <tt>arch/i386/kernel/smpboot.c:initialize_secondary()</tt> を呼び出す。
</enum>

<!--
The <tt>init/main.c:start_kernel()</tt> is written in C and does the following:
-->
<tt>init/main.c:start_kernel()</tt>はCで書かれており、以下のような処理を行います。

<!--
<enum>
<item> Take a global kernel lock (it is needed so that only one CPU
       goes through initialisation).
<item> Perform arch-specific setup (memory layout analysis, copying
       boot command line again, etc.).
-->
<enum>
<item> (初期化の間には１つのCPUだけが動作することが必要なため)グローバルのカーネルロックを取得する。
<item> アーキテクチャ独自のセットアップを実行する(メモリレイアウトの解析、ブートコマンドラインの再度のコピーなど)。
<!--
<item> Print Linux kernel "banner" containing the version, compiler used to
       build it etc. to the kernel ring buffer for messages. This is taken
       from the variable linux_banner defined in init/version.c and is the
       same string as displayed by <bf>cat /proc/version</bf>.
-->
<item> Linux カーネルのバージョン、ビルドに使用したコンパイラなどからなる「バナー」をメッセージ用のカーネルリングバッファへ書き込む。このメッセージは、init/version.c で定義されている linux_bannar 変数から取得する。このメッセージは、<bf>cat /proc/version</bf> コマンドを実行したときと同じメッセージになっている。

<!--
<item> Initialise traps.
<item> Initialise irqs.
<item> Initialise data required for scheduler.
-->
<item> trap を初期化する。
<item> irq を初期化する。
<item> スケジューラの使うデータを初期化する。
<!--
<item> Initialise time keeping data.
<item> Initialise softirq subsystem.
<item> Parse boot commandline options.
<item> Initialise console.
-->
<item> 時刻を保持するデータを初期化する。
<item> ソフト割り込みサブシステムを初期化する。
<item> ブートコマンドラインオプションを解析する。
<item> コンソールを初期化する。
<!--
<item> If module support was compiled into the kernel, initialise dynamical
       module loading facility.
<item> If "profile=" command line was supplied, initialise profiling buffers.
<item> <tt>kmem_cache_init()</tt>, initialise most of slab allocator.
-->
<item> もしモジュールサポートがカーネルに組み込まれていたら、動的モジュール読み込み機構を初期化する。
<item> もし、"profile=" コマンドラインがあれば、プロファイルバッファを初期化する。
<item> <tt>kmem_cache_init()</tt> を実行し、ほとんどのスラブアロケータを初期化する。
<!--
<item> Enable interrupts.
<item> Calculate BogoMips value for this CPU.
<item> Call <tt>mem_init()</tt> which calculates <tt>max_mapnr</tt>, <tt>totalram_pages</tt> and
       <tt>high_memory</tt> and prints out the "Memory: ..." line.
<item> <tt>kmem_cache_sizes_init()</tt>, finish slab allocator initialisation.
-->
<item> 割り込みを有効にする。
<item> 使用している CPU の BogoMips を計算する。
<item> <tt>max_mapnr</tt>、<tt>totalram_pages</tt> と <tt>high_memory</tt>を計算する<tt>mem_init()</tt>を呼び出し、"Memory: ..." の行を表示する。
<item> <tt>kmem_cache_sizes_init()</tt> を実行し、スラブアロケータの初期化が完了する。
<!--
<item> Initialise data structures used by procfs.
<item> <tt>fork_init()</tt>, create <tt>uid_cache</tt>, initialise <tt>max_threads</tt> based on
       the amount of memory available and configure <tt>RLIMIT_NPROC</tt> for
       <tt>init_task</tt> to be <tt>max_threads/2</tt>.
-->
<item> procfs が使うデータ構造体を初期化する。
<item> <tt>fork_init()</tt>を呼び出し、<tt>uid_cache</tt> を作成して、利用可能なメモリ量に基づき<tt>max_threads</tt>を初期化し、  <tt>init_task</tt> が <tt>max_threads/2</tt> になるよう <tt>RLIMIT_NPROC</tt> を設定する。
<!--
<item> Create various slab caches needed for VFS, VM, buffer cache, etc.
-->
<item> VFS、VM、バッファキャッシュなどで必要な種々のスラブキャッシュを作成する。
<!--
<item> If System V IPC support is compiled in, initialise the IPC subsystem.
       Note that for System V shm, this includes mounting an internal
       (in-kernel) instance of shmfs filesystem.
-->
<item> System V IPC サポートがカーネルに含まれていたら、IPC サブシステムを初期化する。System V shm の場合は、shmfsファイルシステムの(カーネルの)内部インスタンスをマウントすることに注意すること。
<!--
<item> If quota support is compiled into the kernel, create and initialise
       a special slab cache for it.
-->
<item> quota サポートがカーネルに含まれていたら、quota 用のスラブキャッシュを作成し初期化する。
<!--
<item> Perform arch-specific "check for bugs" and, whenever possible,
       activate workaround for processor/bus/etc bugs. Comparing various
       architectures reveals that "ia64 has no bugs" and "ia32 has quite a
       few bugs", good example is "f00f bug" which is only checked if kernel
       is compiled for less than 686 and worked around accordingly.
-->
<item> アーキテクチャ特有の「バグのチェック」を行う。そして現時点で可能な限り、プロセッサやバス、その他の対処を有効にする。各種のアーキテクチャを比較すると、「IA64 にはバグはなく」、「IA32 はかなりバグがある」。この良い例として「f00fバグ」がある。このバグは、カーネルが 686 より前の CPU 向けにコンパイルされたときだけチェックされ、チェック結果に従い対処を行なう。
<!--
<item> Set a flag to indicate that a schedule should be invoked at "next
       opportunity" and create a kernel thread <tt>init()</tt> which execs
       execute_command if supplied via "init=" boot parameter, or tries to
       exec <bf>/sbin/init</bf>, <bf>/etc/init</bf>, <bf>/bin/init</bf>, <bf>/bin/sh</bf> in this order; if
       all these fail, panic with "suggestion" to use "init=" parameter.
<item> Go into the idle loop, this is an idle thread with pid=0.
</enum>
-->
<item> スケジューラが「次の機会」に起動される事を示すフラグをセットする。そして、<tt>init</tt> カーネルスレッドを作成する。このカーネルスレッドは、もし、"init=" ブートパラメータが与えられていた場合は、 execute_command を実行する。もし指定がなければ、<bf>/sbin/init</bf>、<bf>/etc/init</bf>、<bf>/bin/init</bf>、<bf>/bin/sh</bf>の順にファイルを探し、実行しようとする。もし全て失敗したら、"init="パラメータを使うよう「忠告」してパニック状態になる。
<item> アイドルループに入る。これは pid=0 のアイドルスレッドとなる。
</enum>

<!--
Important thing to note here that the <tt>init()</tt> kernel thread calls
<tt>do_basic_setup()</tt> which in turn calls <tt>do_initcalls()</tt> which goes through the
list of functions registered by means of <tt>__initcall</tt> or <tt>module_init()</tt> macros
and invokes them. These functions either do not depend on each other
or their dependencies have been manually fixed by the link order in the
Makefiles. This means that, depending on
the position of directories in the trees and the structure of the Makefiles,
the order in which initialisation functions are invoked can change. Sometimes, this
is important because you can imagine two subsystems A and B with B depending
on some initialisation done by A. If A is compiled statically and B is a
module then B's entry point is guaranteed to be invoked after A prepared
all the necessary environment. If A is a module, then B is also necessarily
a module so there are no problems. But what if both A and B are statically
linked into the kernel? The order in which they are invoked depends on the relative 
entry point offsets in the <tt>.initcall.init</tt> ELF section of the kernel image.
-->
ここで重要なことは、<tt>init()</tt> カーネルスレッドが <tt>do_basic_setup()</tt> を呼び出していることです。この関数はさらに、<tt>__initcall</tt> や <tt>module_init()</tt> マクロによって登録された関数のリストを読み出して実行する <tt>do_initcalls()</tt> を呼び出します。
これらの関数は、各々が相互に依存していないか、Makefileでリンクの順序を入れ替えることで、依存関係を手動で修正してあります。
これはすなわち、ツリーの中のディレクトリの位置とMakefileの構成によって、初期化関数の実行順序が入れ替えられるということを意味しています。
ときには、二つのサブディレクトリAとBがあった場合、BがAの中の初期化関数に依存しているような場合に、この順序が重要になります。もし、Aが静的にカーネルにリンクされ、Bはモジュールであった場合は、Bの実行タイミングは、Aが必要な環境を整えた後であることが保証されます。もし、Aがモジュールであり、Bも当然モジュールである場合にも問題はありません。しかし、AとBが両方静的にカーネルにリンクされる場合はどうでしょう? 2つの実行順序は、カーネルイメージの<tt>.initcall.init</tt> ELF セクションにおける位置の差に依存しているのです。
<!--
Rogier Wolff proposed to introduce a hierarchical "priority" infrastructure
whereby modules could let the linker know in what (relative) order they
should be linked, but so far there are no patches available that implement
this in a sufficiently elegant manner to be acceptable into the kernel.
Therefore, make sure your link order is correct. If, in the example above,
A and B work fine when compiled statically once, they will always work,
provided they are listed sequentially in the same Makefile. If they don't
work, change the order in which their object files are listed.
-->
Rogier Wolffは階層的な「優先度」構造を提案し、それによって
リンカがどの(相互的な)順序でモジュールをリンクするかが分かるようにしました。しかし、いまのところ、これをカーネルへ受け入れられるような効果的にエレガントな方法で実装したパッチは存在していません。
したがって、リンクの順序を正しくしないといけないのです。もし、上記の例で、AとBがともに静的にコンパイルされたとき良好に動作したなら、常に動作しますが、そのためにはおなじMakefileに順序よくリストしなければなりません。
もしうまく働かないようなら、オブジェクトファイルのリスト順を変えることになります。
<!--
Another thing worth noting is Linux's ability to execute an "alternative
init program" by means of passing "init=" boot commandline. This is useful
for recovering from accidentally overwritten <bf>/sbin/init</bf> or debugging the
initialisation (rc) scripts and <tt>/etc/inittab</tt> by hand, executing them
one at a time.
-->
注意する価値のあるもう一つの事柄として、"init="ブートコマンドラインを渡すことにより、「別のinitプログラム」を実行するLinuxの機能があります。これは、<bf>/sbin/init</bf> を誤って上書きしたときの回復や、初期化(rc)スクリプトや <tt>/etc/initttab</tt> を、一回に一つずつ手で実行することでデバッグするのに有益です。
<!--
<sect1>SMP Bootup on x86<p>
-->
<sect1>x86でのSMPブート <p>

<!--
On SMP, the BP goes through the normal sequence of bootsector, setup etc
until it reaches the <tt>start_kernel()</tt>, and then on to <tt>smp_init()</tt> and
especially <tt>src/i386/kernel/smpboot.c:smp_boot_cpus()</tt>. The <tt>smp_boot_cpus()</tt>
goes in a loop for each apicid (until <tt>NR_CPUS</tt>) and calls <tt>do_boot_cpu()</tt> on
it. What <tt>do_boot_cpu()</tt> does is create (i.e. <tt>fork_by_hand</tt>) an idle task for
the target cpu and write in well-known locations defined by the Intel MP
spec (0x467/0x469) the EIP of trampoline code found in <tt>trampoline.S</tt>. Then
it generates STARTUP IPI to the target cpu which makes this AP execute the
code in <tt>trampoline.S</tt>.
-->
SMPにおいて、BP は <tt>start_kernel()</tt>へ進み、そして<tt>smp_init()</tt>と特に<tt>src/i386/kernel/smpboot.c:smp_boot_cpus()</tt>に進むまで、通常のブートセクタ、setupなどのブートシーケンスを進んでいきます。
<tt>smp_boot_cpus()</tt>は、(<tt>NR_CPUS</tt>まで)ループで各apicidごとに実行され、その中で<tt>do_boot_cpu()</tt>が呼ばれます。
<tt>do_boot_cpu()</tt>はターゲットのCPU用のアイドルタスクを生成(i.e. <tt>fork_by_hand</tt>)します。そして、Intel MP仕様で定義されている既定の位置 (0x467/0x469) へと、<tt>trampoline.S</tt>にあるトランポリンコードのEIPを書き込みます。そして、このAPが <tt>trampoline.S</tt>のコードを実行するように、ターゲット CPU の STARTUP IPI を生成します。

<!--
The boot CPU  creates a copy of trampoline code for each CPU in
low memory. The AP code writes a magic number in its own code which is
verified by the BP to make sure that AP is executing the trampoline code.
The requirement that trampoline code must be in low memory is enforced by
the Intel MP specification.
-->
ブートした CPU は、低位メモリにある各 CPU のトランポリンコードのコピーを作成します。APコードはマジックナンバーを自身のコードに埋め込むことで、BPによりそのAPがトランポリンコードを実行してよいかの判断を行わせます。Intel MP仕様によって規定されているため、トランポリンコードは低位メモリに置かれる必要があります。

<!--
The trampoline code simply sets %bx register to 1, enters protected mode
and jumps to startup_32 which is the main entry to <tt>arch/i386/kernel/head.S</tt>.
-->
トランポリンコードは単純に %bx レジスタを 1 にします。そして、プロテクトモードに移り、<tt>arch/i386/kernel/head.S</tt>のメインエントリーポイントであるstartup_32 へとジャンプします。

<!--
Now, the AP starts executing <tt>head.S</tt> and discovering that it is not a BP,
it skips the code that clears BSS and then enters <tt>initialize_secondary()</tt>
which just enters the idle task for this CPU - recall that <tt>init_tasks[cpu]</tt>
was already initialised by BP executing <tt>do_boot_cpu(cpu)</tt>.
-->
さて、APは<tt>head.S</tt>の実行を開始し、自身がBPではないことに気が付きます。
すると、BSSをクリアするコードの実行をスキップして、<tt>initalize_secondary()</tt>へと進みます。そして、この CPU はアイドルタスクへと単に進みます。
-- <tt>init_tasks[cpu]</tt>は、BPが<tt>do_boot_cpu(cpu)</tt> を実行したときにすでに初期化されていたことを思い起こしましょう。

<!--
Note that init_task can be shared but each idle thread must have its own
TSS. This is why <tt>init_tss[NR_CPUS]</tt> is an array.
-->
ここで、init_taskは共有できますが、各アイドルスレッドで各々 TSS を持たなければならないことに注意しましょう。これは、<tt>init_tss[NR_CPUS]</tt>が配列になっている理由になっています。

<!--
<sect1>Freeing initialisation data and code<p>
-->
<sect1>初期化データおよびコードの解放<p>

<!--
When the operating system initialises itself, most of the code and data
structures are never needed again.
Most operating systems (BSD, FreeBSD etc.) cannot dispose of this unneeded
information, thus wasting precious physical kernel memory.
The excuse they use (see McKusick's 4.4BSD book) is that "the relevant code
is spread around various subsystems and so it is not feasible to free it".
Linux, of course, cannot use such excuses because under Linux "if something
is possible in principle, then it is already implemented or somebody is
working on it".
-->
オペレーティングシステムが自身を初期化するとき、そのためのほとんどのコードとデータ構造体は二度と使われることはありません。ほとんどのオペレーティングシステム(BSD, FreeBSD etc...)では、この不必要な情報を破棄することができません。すなわち、貴重な物理カーネルメモリを浪費していることになるのです。
彼らの使う言い訳(McKusickの4.4BSD本を参照)は、「関連のコードが各種のサブシステムに広がっており、これらを解放するのは現実的ではない。」ということです。Linux はもちろん、このような言い訳をしません。なぜなら、Linux では、「もしなにかが原理的に可能であれば、それはすでに実装されているか、誰かが作業している」からです。

<!--
So, as I said earlier, Linux kernel can only be compiled as an ELF binary, and
now we find out the reason (or one of the reasons) for that. The reason
related to throwing away initialisation code/data is that Linux provides two
macros to be used:
-->
そして、前の章で述べたように、Linux カーネルはELF バイナリとしてのみコンパイルできることから、私たちにもそれが可能なことが(あるいは、その根拠の一つ)が分かっています。以下のように使われる2つのマクロを Linux が提供しており、初期化コード/データを廃棄することができるようになっています。

<!--
<itemize>
<item> <tt>__init</tt> - for initialisation code
<item> <tt>__initdata</tt> - for data
</itemize>
-->
<itemize>
<item> <tt>__init</tt> - 初期化コード用
<item> <tt>__initdata</tt> - 初期化データ用
</itemize>

<!--
These evaluate to gcc attribute specificators (also known as "gcc magic")
as defined in <tt>include/linux/init.h</tt>:
-->
これらは<tt>include/linux/init.h</tt>に定義されるgccの属性指示子("gcc magic"としても知られる)を評価します。

<tscreen><code>
#ifndef MODULE
#define __init        __attribute__ ((__section__ (".text.init")))
#define __initdata    __attribute__ ((__section__ (".data.init")))
#else
#define __init
#define __initdata
#endif
</code></tscreen>

<!--
What this means is that if the code is compiled statically into the kernel
(i.e. MODULE is not defined) then it is placed in the special ELF section
<tt>.text.init</tt>, which is declared in the linker map in <tt>arch/i386/vmlinux.lds</tt>.
Otherwise (i.e. if it is a module) the macros evaluate to nothing.
-->
これが意味することは、もしコードがカーネルに静的にコンパイルされているなら(つまり MODULEが定義されていなければ）、特殊な ELF セクションの<tt>text.init</tt>にこれらのコードが配置されるということです。そしてその配置は、<tt>arch/i386/vmlinux.lds</tt>のリンカマップに定義されるのです。
逆に(つまりモジュールであれば)マクロはなにもしないということです。

<!--
What happens during boot is that the "init" kernel thread (function
<tt>init/main.c:init()</tt>) calls the arch-specific function <tt>free_initmem()</tt> which
frees all the pages between addresses <tt>__init_begin</tt> and <tt>__init_end</tt>.
-->
ブート時に、アドレス<tt>__init_begin</tt>から<tt>__init_end</tt>の間の全てのページを解放する、アーキテクチャ特有の関数<tt>free_initmem()</tt>を、"init"カーネルスレッド(関数<tt>init/main.c:init()</tt>)が呼び出すのです。

<!--
On a typical system (my workstation), this results in freeing about 260K of
memory.
-->
(私のワークステーションのような)一般的なシステムでは、この結果、約260Kのメモリの解放になります。

<!--
The functions registered via <tt>module_init()</tt> are placed in <tt>.initcall.init</tt>
which is also freed in the static case. The current trend in Linux, when
designing a subsystem (not necessarily a module), is to provide
init/exit entry points from the early stages of design so that in the
future, the subsystem in question can be modularised if needed. 
Example of this is pipefs, see <tt>fs/pipe.c</tt>. Even if a given subsystem will never become a module, e.g. bdflush (see <tt>fs/buffer.c</tt>), it is still nice and tidy to use the <tt>module_init()</tt> macro against its initialisation function, provided it does not matter when exactly is the function called.

Example of this is pipefs, see it. Even if a given subsystem will never become a module, it is still nice and tidy to use the  macro against its initialisation function, provided it does not matter when exactly is the function called.

-->
<tt>module_init()</tt>によって登録された関数は、<tt>.initcall.init</tt>に配置され、静的にリンクされていたときには同様に解放されます。Linux 開発の現在の方向性では、将来問題のサブシステムが必要に応じてモジュール化できるように、(当初モジュールの必要性のない)サブシステムの場合にも、デザインの初期段階から、init/exit エントリーポイントが提供されるようにしています。<tt>fs/pipe.c</tt>のpipefsが、このよい例です。たとえ、bdflush (<tt>fs/buffer.c</tt>参照)のように、あるサブシステムが決してモジュールになることがなく、その時点でその関数を呼ぶことが重要でないとしても、それでも初期化関数として<tt>module_init()</tt>マクロを使うことはよいことです。

<!--
There are two more macros which work in a similar manner, called <tt>__exit</tt> and
<tt>__exitdata</tt>, but they are more directly connected to the module support and
therefore will be explained in a later section.
-->
さらに同じような使い方をする<tt>__exit</tt>と<tt>__exitdata</tt>という名前の2つのマクロがあります。しかしこれらは、モジュールサポートにより直接的につながるため、後のセクションにて説明します。

<!--
<sect1>Processing kernel command line<p>
-->
<sect1>カーネルコマンドラインを処理する<p>

<!--
Let us recall what happens to the commandline passed to kernel during boot:
-->
ここで、ブート時にカーネルに渡されたコマンドラインに何が起こるかを考えてみましょう。

<enum>
<!--
<item> LILO (or BCP) accepts the commandline using BIOS keyboard services
       and stores it at a well-known location in physical memory, as well
       as a signature saying that there is a valid commandline there.
-->
<item> LILO(ないしはBCP) は BIOS のキーボードサービスを使って、コマンドラインを受け取る。そして、物理メモリの既定の位置に、そこに有効なコマンドラインがあることを示す印といっしょに格納する。
<!-- 
<item> <tt>arch/i386/kernel/head.S</tt> copies the first 2k of it out to the zeropage.

2001-Oct 削除

       Note that the current version (21) of LILO chops the commandline to
       79 bytes. This is a nontrivial bug in LILO (when large EBDA support
       is enabled) and Werner promised to fix it sometime soon. If you really
       need to pass commandlines longer than 79 bytes then you can either
       use BCP or hardcode your commandline in
       <tt>arch/i386/kernel/setup.c:parse_mem_cmdline()</tt> function.
 -->
<item> <tt>arch/i386/kernel/head.S</tt> は自身の最初の 2k をゼロページの外へとコピーする。
<!--
ここで現在のバージョン (21) の LILO はコマンドラインを79バイトで切ってしまうことに注意すること。これは(ラージEBDAサポートを有効にしたときの)自明ではないバグでWernerはできるだけ早くにこれを修正すると言っている。もし
本当に 79 バイト以上のコマンドラインを渡す必要がある場合には、BCPを使うか、コマンドラインを <tt>arch/i386/kernel/setup.s:parse_mem_cmdline()</tt>関数にハードコードするかすること。
-->

<!--
<item> <tt>arch/i386/kernel/setup.c:parse_mem_cmdline()</tt> (called by
       <tt>setup_arch()</tt>, itself called by <tt>start_kernel()</tt>) copies 256 bytes from zeropage
       into <tt>saved_command_line</tt> which is displayed by <tt>/proc/cmdline</tt>. This
       same routine processes the "mem=" option if present and makes appropriate
       adjustments to VM parameters.
-->
<item> (<tt>start_kernel()</tt> から呼ばれた <tt>setup_arch()</tt>から呼び出される) <tt>arch/i386/kernel/setup.c:parse_mem_cmdline()</tt>は、ゼロページから 256 バイトを <tt>/proc/cmdline</tt> で表示されるのと同じ  <tt>saved_command_line</tt> へとコピーする。これと同じルーチンは、"mem=" オプションがもしあれば処理し、VM パラメータを適切に調整する。

<!--
<item> We return to commandline in <tt>parse_options()</tt> (called by <tt>start_kernel()</tt>)
       which processes some "in-kernel" parameters (currently "init=" and
       environment/arguments for init) and passes each word to <tt>checksetup()</tt>.
-->
<item> 話を(<tt>start_kernel()</tt>から呼ばれる) <tt>parse_options()</tt> のコマンドラインに戻すと、この関数は「カーネル内部」パラメータ(現時点では、"init="と init の環境変数、引数)も処理し、各ワードを<tt>checksetup()</tt>へと渡す。

<!--
<item> <tt>checksetup()</tt> goes through the code in ELF section <tt>.setup.init</tt> and
       invokes each function, passing it the word if it matches. Note that
       using the return value of 0 from the function registered via <tt>__setup()</tt>,
       it is possible to pass the same "variable=value" to more than one
       function with "value" invalid to one and valid to another.
       Jeff Garzik commented: "hackers who do that get spanked :)"
       Why? Because this is clearly ld-order specific, i.e. kernel linked
       in one order will have functionA invoked before functionB and another
       will have it in reversed order, with the result depending on the order.
-->
<item> <tt>checksetup()</tt> は ELF セクション<tt>.setup.init</tt>のコードについて、そこの各関数を起動し、コマンドラインがマッチしていた時は、コマンドラインのワードを渡していく。ここで、<tt>__setup()</tt>で登録された関数からの返り値が 0 のときは、同じ"variable=value" を一つ以上の関数へ渡せ、その"value"が一方の関数では無効で、他方では有効であるということを表している。
Jeff Garzikは、「こういうことをするハッカーはおしりペンペンだ :) 」とコメントしている。なぜか?
これは明らかに ID の順序に特有で、つまりある順序でリンクされたカーネルは関数Aを関数Bの前に起動するが、そうでない場合は、逆の順序になり結果が順序に依存してしまうからだ。

</enum>

<!--
So, how do we write code that processes boot commandline? We use the <tt>__setup()</tt>
macro defined in <tt>include/linux/init.h</tt>:
-->
さて、ブートコマンドラインを処理するコードはどのようになっているのでしょうか。<tt>include/linux/init.h</tt>で定義される <tt>__setup()</tt> マクロを使います。

<tscreen><code>

/*
 * Used for kernel command line parameter setup
 */
struct kernel_param {
	const char *str;
	int (*setup_func)(char *);
};

extern struct kernel_param __setup_start, __setup_end;

#ifndef MODULE
#define __setup(str, fn) \
   static char __setup_str_##fn[] __initdata = str; \
   static struct kernel_param __setup_##fn __initsetup = \
   { __setup_str_##fn, fn }

#else
#define __setup(str,func) /* nothing */
endif
</code></tscreen>

<!--
So, you would typically use it in your code like this
(taken from code of real driver, BusLogic HBA <tt>drivers/scsi/BusLogic.c</tt>):
-->
次に、実際のコードでの典型的な使い方は以下のようになります (実際のドライバの BusLogic HBA <tt>drivers/scsi/BusLogic.c</tt>から引用)。

<tscreen><code>
static int __init
BusLogic_Setup(char *str)
{
        int ints[3];

        (void)get_options(str, ARRAY_SIZE(ints), ints);

        if (ints[0] != 0) {
                BusLogic_Error("BusLogic: Obsolete Command Line Entry "
                                "Format Ignored\n", NULL);
                return 0;
        }
        if (str == NULL || *str == '\0')
                return 0;
        return BusLogic_ParseDriverOptions(str);
}

__setup("BusLogic=", BusLogic_Setup);
</code></tscreen>

<!--
Note that <tt>__setup()</tt> does nothing for modules, so the code that wishes to
process boot commandline and can be either a module or statically linked
must invoke its parsing function manually in the module initialisation
routine. This also means that it is possible to write code that
processes parameters when compiled as a module but not when it is static or
vice versa.
-->
ここで <tt>__setup()</tt>はモジュールに対しては何もしません。そしてモジュールであれ静的にリンクされているのであれ、ブートコマンドラインを処理したいコードでは、モジュールの初期化ルーチンにおいて、自身の解析関数を持っていてそれを起動しなければならないからです。これは、静的にコンパイルされる時などだけでなく、モジュールとしてコンパイルされる時にも、パラメータを処理するコードを書くことができるという事でもあります。

<!--
<sect>Process and Interrupt Management<p>
-->
<sect> プロセスと割り込み管理 <p>

<!--
<sect1>Task Structure and Process Table<p>
-->
<sect1>タスク構造体とプロセステーブル<p>

<!--
Every process under Linux is dynamically allocated a <tt>struct task_struct</tt>
structure. The maximum number of processes which can be created on Linux
is limited only by the amount of physical memory present, and is
equal to (see <tt>kernel/fork.c:fork_init()</tt>):
-->
Linuxでは、全てのプロセスは <tt>struct tack_struct</tt> 構造体が動的に割り当てられます。Linux 上で動かせる最大のプロセス数の制限は、存在する物理メモリ容量で決まります (<tt>kernel/fork.c:fork_init()</tt>参照)。その値は以下のとおりです。つまり、

<tscreen><code>
        /*
         * The default maximum number of threads is set to a safe
         * value: the thread structures can take up at most half
         * of memory.
         */
        max_threads = mempages / (THREAD_SIZE/PAGE_SIZE) / 2;
</code></tscreen>
になります。

<!--
which, on IA32 architecture, basically means <tt>num_physpages/4</tt>. As an example,
on a 512M machine, you can create 32k threads. This is a considerable
improvement over the 4k-epsilon limit for older (2.2 and earlier) kernels.
Moreover, this can be changed at runtime using the KERN_MAX_THREADS <bf>sysctl(2)</bf>,
or simply using procfs interface to kernel tunables:
-->
IA32 アーキテクチャでは、基本的に <tt>num_physpages/4</tt> を意味しています。例えば、512M のマシンがあれば、32k 個のスレッドを生成できるという訳です。これは古い (2.2 やそれ以前の) カーネルの 4k 弱の制限に比べ相当な改善になっています。
そのうえ、実行時にカーネルを調整できる KERN_MAX_THREADS <bf>sysctl(2)</bf> や、単純に procfs インターフェースを使って変更することもできます。

<tscreen><code>
# cat /proc/sys/kernel/threads-max 
32764
# echo 100000 > /proc/sys/kernel/threads-max 
# cat /proc/sys/kernel/threads-max 
100000
# gdb -q vmlinux /proc/kcore
Core was generated by `BOOT_IMAGE=240ac18 ro root=306 video=matrox:vesa:0x118'.
#0  0x0 in ?? ()
(gdb) p max_threads
$1 = 100000
</code></tscreen>

<!--
The set of processes on the Linux system is represented as a collection of
<tt>struct task_struct</tt> structures which are linked in two ways:
-->
Linux システムでは、プロセス群は２種類の異なる方法でリンクされた <tt>struct task_struct</tt> 構造体の集合として表すことができます。

<!--
<enum>
<item> as a hashtable, hashed by pid, and
<item> as a circular, doubly-linked list using <tt>p->next_task</tt> and <tt>p->prev_task</tt>
       pointers.
</enum>
-->
<enum>
<item>  pid によりハッシュされたハッシュテーブルと、
<item>  <tt>p->next_task</tt> と <tt>p->prev_task</tt> ポインタを用いた円環状のダブルリンクリスト。
</enum>

<!--
The hashtable is called <tt>pidhash[]</tt> and is defined in
<tt>include/linux/sched.h</tt>:
-->
ハッシュテーブルは、<tt>pidhash[]</tt> と呼ばれ、<tt>include/linux/sched.h</tt> で定義されています。

<tscreen><code>
/* PID hashing. (shouldnt this be dynamic?) */
#define PIDHASH_SZ (4096 >> 2)
extern struct task_struct *pidhash[PIDHASH_SZ];

#define pid_hashfn(x)   ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
</code></tscreen>

<!--
The tasks are hashed by their pid value and the above hashing function is
supposed to distribute the elements uniformly in their domain
(<tt>0</tt> to <tt>PID_MAX-1</tt>). The hashtable is used to quickly find a task by given pid,
using <tt>find_task_pid()</tt> inline from <tt>include/linux/sched.h</tt>:
-->
タスクはpid値のハッシュにされ、上記のハッシュ関数はその(<tt>0</tt>から<tt>PID_MAX-1</tt>の)領域に要素が均一に分散されるようになっています。ハッシュテーブルは、<tt>include/linux/sched.h</tt> の中にある <tt>find_task_pid()</tt> を使って、与えられた pid のタスクをすぐに見つけられるよう使われています。 

<tscreen><code>
static inline struct task_struct *find_task_by_pid(int pid)
{
        struct task_struct *p, **htable = &amp;pidhash[pid_hashfn(pid)];

        for(p = *htable; p && p->pid != pid; p = p->pidhash_next)
                ;

        return p;
}
</code></tscreen>

<!--
The tasks on each hashlist (i.e. hashed to the same value) are linked
by <tt>p->pidhash_next/pidhash_pprev</tt> which are used by <tt>hash_pid()</tt> and
 <tt>unhash_pid()</tt> to insert and remove a given process into the hashtable.
These are done under protection of the read-write spinlock called <tt>tasklist_lock</tt>
taken for WRITE.
-->
各ハッシュリストの(つまり同じ値にハッシュされた)タスクは、<tt>p->pidhash_next/pidhash_pprev</tt>によって
リンクされ、<tt>hash_pid()</tt>と<tt>unhash_pid()</tt>がハッシュテーブルにあるプロセスを挿入したり削除したりするのに使われます。
これらの操作は、WRITEのために取得する<tt>tasklist_lock</tt>という読み書きスピンロックの保護のもと行われます。

<!--
The circular doubly-linked list that uses <tt>p->next_task/prev_task</tt> is
maintained so that one could go through all tasks on the system easily.
This is achieved by the <tt>for_each_task()</tt> macro from <tt>include/linux/sched.h</tt>:
-->
<tt>p->next_task/prev_task</tt>が使うリング状の双方向リンクリストは、システムのすべてのタスクに容易に到達できるように管理されます。これは、<tt>include/linux/sched.h</tt>で定義される<tt>for_each_task()</tt>マクロによって実現されています。

<tscreen><code>
#define for_each_task(p) \
        for (p = &amp;init_task ; (p = p->next_task) != &amp;init_task ; )
</code></tscreen>

<!--
Users of <tt>for_each_task()</tt> should take tasklist_lock for READ.
Note that <tt>for_each_task()</tt> is using <tt>init_task</tt> to mark the beginning (and end)
of the list - this is safe because the idle task (pid 0) never exits.
-->
<tt>for_each_task()</tt>のユーザはREAD の tasklist_lock を取得する必要があります。
ここで、<tt>for_each_task()</tt>がリストの始点(と終点)を表すのに<tt>init_task</tt>を使用しています。これは、アイドルタスク(pid 0)が終了することがないことから、安全な方法です。

<!--
The modifiers of the process hashtable or/and the process table links,
notably <tt>fork()</tt>, <tt>exit()</tt> and <tt>ptrace()</tt>, must take <tt>tasklist_lock</tt> for WRITE. What is
more interesting is that the writers must also disable interrupts on the 
local CPU. The reason for this is not trivial: the <tt>send_sigio()</tt> function walks the
task list and thus takes <tt>tasklist_lock</tt> for READ, and it is called from
<tt>kill_fasync()</tt> in interrupt context. This is why writers must disable
interrupts while readers don't need to.
-->
プロセスハッシュテーブルまたはプロセステーブルリンクの変更時には、特に <tt>fork()</tt>と<tt>exit</tt>、<tt>ptrace()</tt> ですが、WRITEのために<tt>tasklist_lock</tt>を取得しなければなりません。
もっと興味深いことには、書き込みを行う時は、ローカルCPUの割り込みも無効にしなければならないのです。これには明白な理由があります。<tt>send_sigio()</tt>関数はタスクリストをたどって、READのために<tt>tasklist_lock</tt>を取得し、割り込みコンテキストで <tt>kill_fasync()</tt>から呼び出されるからです。
これが、読み込みを行うときには不要でも、書き込みを行うときには必ず割り込みを無効にしなければならない理由です。

<!--
Now that we understand how the <tt>task_struct</tt> structures are linked together,
let us examine the members of <tt>task_struct</tt>. They loosely correspond to the
members of UNIX 'struct proc' and 'struct user' combined together.
-->
さて、<tt>task_struct</tt>構造体がどのようにして相互にリンクしているか見ていきましょう。
<tt>task_struct</tt>のメンバーを子細にみてみます。これらは相互に結合している UNIX の'struct proc'と 'struct user' と弱い関連があります。

<!--
The other versions of UNIX separated the task state information into
one part which should be kept memory-resident at all times (called 'proc
structure' which includes process state, scheduling information etc.) and
another part which is only needed when the process is running (called 'u area' which
includes file descriptor table, disk quota information etc.). The only reason
for such ugly design was that memory was a very scarce resource. Modern
operating systems (well, only Linux at the moment but others, e.g. FreeBSD
seem to improve in this direction towards Linux) do not need such separation
and therefore maintain process state in a kernel memory-resident data
structure at all times.
-->
UNIX の他のバージョンでは、タスク状態の情報は2つに分けて格納されます。一つは常にメモリ内に
無ければならない('proc structure'とよばれ、プロセス状態、スケジューリング情報などを含んでいる)ものです。
もう一方は、プロセスが走行するときにだけ必要になる('u area'と呼ばれ、ファイルディスクリプタテーブル、ディスククオタ情報などの)情報です。このような醜い実装がなされたのは、単にメモリが非常に貴重な資源であったという事情がありました。現代のOSでは、(もちろん今学んでいる Linux だけでなく、他の例えば FreeBSD では、Linuxのこの方向性をさらに進歩させたものになっている) このように分離する必要はなく、それゆえ常にメモリ上にあるデータ構造体によりプロセス状態の管理を行うようになっています。

<!--
The task_struct structure is declared in <tt>include/linux/sched.h</tt> and is
currently 1680 bytes in size.

The state field is declared as:
-->
task_struct構造体は、 <tt>include/linux/sched.h</tt>で宣言され、そのサイズは現在 1680 byte です。

状態フィールドは次のように宣言されています。

<tscreen><code>
volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */

#define TASK_RUNNING            0
#define TASK_INTERRUPTIBLE      1
#define TASK_UNINTERRUPTIBLE    2
#define TASK_ZOMBIE             4
#define TASK_STOPPED            8
#define TASK_EXCLUSIVE          32
</code></tscreen>

<!--
Why is <tt>TASK_EXCLUSIVE</tt> defined as 32 and not 16? Because 16 was used up by
<tt>TASK_SWAPPING</tt> and I forgot to shift <tt>TASK_EXCLUSIVE</tt> up when I removed
all references to <tt>TASK_SWAPPING</tt> (sometime in 2.3.x).

The <tt>volatile</tt> in <tt>p->state</tt> declaration means it can be modified
asynchronously (from interrupt handler):
-->
なぜ <tt>TASK_EXCLUSIVE</tt> が 16ではなく32と定義されているのでしょうか。実は16は
<tt>TASK_SWAPPING</tt> により使われており、(2.3.xのどこかで)<tt>TASK_SWAPPING</tt>のリファレンスを削除するときに <tt>TASK_EXCLUSIVE</tt>をシフトするのを忘れてしまったからなのです。
<tt>p->state</tt>の<tt>volatile</tt>修飾子は、(割り込みハンドラから)非同期で変更され得ることを意味しています。
<enum>
<!-- 
<item><bf>TASK_RUNNING</bf>: means the task is "supposed to be" on the run
queue.  The reason it may not yet be on the runqueue is that marking a task as
<tt>TASK_RUNNING</tt> and placing it on the runqueue is not atomic.  You need to hold
the <tt>runqueue_lock</tt> read-write spinlock for read in order to look at the
runqueue. If you do so, you will then see that every task on the runqueue is in
<tt>TASK_RUNNING</tt> state. However, the converse is not true for the reason explained
above. Similarly, drivers can mark themselves (or rather the process context they
run in) as <tt>TASK_INTERRUPTIBLE</tt> (or <tt>TASK_UNINTERRUPTIBLE</tt>) and then call <tt>schedule()</tt>,
which will then remove it from the runqueue (unless there is a pending signal, in which
case it is left on the runqueue).  </item>
 -->
<item><bf>TASK_RUNNING</bf>:タスクが runキューにある「であろう」ことを意味する。runキューにないかもしれないタスクへ<tt>TASK_RUNNING</tt>印をつけておく理由は、runqueueに置く操作がアトミックでないからである。
runキューを調べるには読み込みのために <tt>runqueue_lock</tt> 読み書きスピンロックを取得する必要がある。もしそうすると、その後に runqueue 上の各タスクが <tt>TASK_RUNNING</tt> 状態にあるかどうか見るだろう。しかし、上記の理由からは、逆は真にならない。
同様に, ドライバが自身を(走行しているプロセスのコンテキストに関わらず)<tt>TASK_INTERRUPTIBLE</tt> (もしくは <tt>TASK_UNINTERRUPTIBLE</tt>) にマークできる。 そしてその後、 <tt>schedule()</tt> を呼び出す。これは (runqueue に残されるケースである保留されたシグナルがなければ) runqueueからそれを削除する。

<!--
<item><bf>TASK_INTERRUPTIBLE</bf>: means the task is sleeping but can be woken up
by a signal or by expiry of a timer.</item>
-->
<item><bf>TASK_INTERRUPTIBLE</bf>: タスクは休止しているが、シグナルやタイマの終了で起こされることがある。

<!--
<item><bf>TASK_UNINTERRUPTIBLE</bf>: same as <tt>TASK_INTERRUPTIBLE</tt>, except it cannot
be woken up.</item>
-->
<item><bf>TASK_UNINTERRUPTIBLE</bf>: <tt>TASK_INTERRUPTIBLE</tt>と同じだが、起こされない点が異なっている。

<!--
<item><bf>TASK_ZOMBIE</bf>: task has terminated but has not had its status collected
(<tt>wait()</tt>-ed for) by the parent (natural or by adoption).</item>
-->
<item><bf>TASK_ZONBIE</bF>: タスクは終了しているが、その状態が(通常かアダプションによる)親プロセスによって(<tt>wait()</tt>により)回収されていない。

<!-- 
<item><bf>TASK_STOPPED</bf>: task was stopped, either due to job control signals or
due to <bf>ptrace(2)</bf>.</item>
-->
<item><bf>TASK_STOPPED</bf>: ジョブ制御シグナルか<bf>ptrace(2)</bf>により、タスクが停止している。

<!--
<item><bf>TASK_EXCLUSIVE</bf>: this is not a separate state but can be OR-ed to
either one of <tt>TASK_INTERRUPTIBLE</tt> or <tt>TASK_UNINTERRUPTIBLE</tt>.
This means that when
this task is sleeping on a wait queue with many other tasks, it will be
woken up alone instead of causing "thundering herd" problem by waking up all
the waiters.</item>
-->
<item><bf>TASK_EXCLUSIVE</bf>: これは独立した状態ではなく、<tt>TASK_INTERRUPTIBLE</tt> や <tt>TASK_UNINTERRUPTIBLE</tt> と OR される。他の多くのタスクといっしょにウエイトキューで休止しているとき、全ての待機タスクを起こすことで"thundering herd"問題を起こす代りに、自分だけ起きることを意味している。
</enum>

<!--
Task flags contain information about the process states which are not
mutually exclusive:
-->
タスクフラグは相互排他的ではないプロセス状態についての情報からなっています。

<tscreen><code>
unsigned long flags;	/* per process flags, defined below */
/*
 * Per process flags
 */
#define PF_ALIGNWARN    0x00000001      /* Print alignment warning msgs */
                                        /* Not implemented yet, only for 486*/
#define PF_STARTING     0x00000002      /* being created */
#define PF_EXITING      0x00000004      /* getting shut down */
#define PF_FORKNOEXEC   0x00000040      /* forked but didn't exec */
#define PF_SUPERPRIV    0x00000100      /* used super-user privileges */
#define PF_DUMPCORE     0x00000200      /* dumped core */
#define PF_SIGNALED     0x00000400      /* killed by a signal */
#define PF_MEMALLOC     0x00000800      /* Allocating memory */
#define PF_VFORK        0x00001000      /* Wake up parent in mm_release */
#define PF_USEDFPU      0x00100000      /* task used FPU this quantum (SMP) */
</code></tscreen>

<!--
The fields <tt>p->has_cpu</tt>, <tt>p->processor</tt>, <tt>p->counter</tt>, <tt>p->priority</tt>, <tt>p->policy</tt> and
 <tt>p->rt_priority</tt> are related to the scheduler and will be looked at later.
-->
<tt>p->has_cpu</tt>や <tt>p->processor</tt>, <tt>p->counter</tt>, <tt>p->priority</tt>, <tt>p->policy</tt> そして <tt>p->rt_priority</tt>フィールドはスケジューラと関連があるため、後ほど見ていきます。

<!--
The fields <tt>p->mm</tt> and <tt>p->active_mm</tt> point respectively to the process' address space
described by <tt>mm_struct</tt> structure and to the active address space if the
process doesn't have a real one (e.g. kernel threads). This helps minimise
TLB flushes on switching address spaces when the task is scheduled out.
So, if we are scheduling-in the kernel thread (which has no <tt>p->mm</tt>) then its
<tt>next->active_mm</tt> will be set to the <tt>prev->active_mm</tt> of the task that was
scheduled-out, which will be the same as <tt>prev->mm</tt> if <tt>prev->mm != NULL</tt>.
The address space can be shared between threads if <tt>CLONE_VM</tt> flag is passed
to the <bf>clone(2)</bf> system call or by means of <bf>vfork(2)</bf> system call.
-->
<tt>p->mm</tt> と <tt>p->active_mm</tt> フィールドはそれぞれ、プロセスの <tt>mm_struct</tt> 構造体で表されるアドレス空間と、プロセスがリアルなアドレス空間を持たない(e.g. カーネルスレッド)時の、アクティブなアドレス空間を示しています。
これはタスクがスケジューラにより中止するときのアドレス空間スイッチにおけるTLBフラッシュを最小限にしてくれます。そして、もし(<tt>p->mm</tt>をもたない)カーネルスレッドがスケジュールインするときは、この<tt>next->active_mm</tt>はスケジュールアウトされたタスクの<tt>prev->active_mm</tt>に設定されます。このタスクは、もし<tt>prev->mm != NULL </tt>であったときの<tt>prev->mm</tt>に等しくなります。
<tt>CLONE_VM</tt>フラグが<bf>clone(2)</bf>システムコールに渡されたときや、<bf>vfork(2)</bf>システムコールによるときは、アドレス空間はスレッドで共有されます。

<!--
The fields <tt>p->exec_domain</tt> and <tt>p->personality</tt> relate to the personality of
the task, i.e. to the way certain system calls behave in order to emulate the
"personality" of foreign flavours of UNIX.
-->
<tt>p->exec_domain</tt> と <tt>p->personality</tt> フィールドはタスクのパーソナリティに関連しています。
つまり、あるシステムコールが他のUNIXの"personality"をエミュレートするために振る舞う方法になっています。

<!--
The field <tt>p->fs</tt> contains filesystem information, which under Linux means
three pieces of information:
-->
<tt>p->fs</tt>フィールドはファイルシステム情報からなり、Linuxにおいては、三つの情報要素を意味します。

<!--
<enum>
<item>root directory's dentry and mountpoint,
<item>alternate root directory's dentry and mountpoint,
<item>current working directory's dentry and mountpoint.
</enum>
-->
<enum>
<item>ルートディレクトリのdentryとマウントポイント
<item>代替ルートディレクトリのdentryとマウントポイント
<item>現在のワーキングディレクトリのdentryとマウントポイント
</enum>

<!--
This structure also includes a reference count because it can be shared
between cloned tasks when <tt>CLONE_FS</tt> flag is passed to the <bf>clone(2)</bf> system
call.
-->
この構造体はリファレンスカウントも保持します。これは、<tt>CLONE_FS</tt>フラグが<bf>clone(2)</bf>システムコールに渡されたときに、クローンのタスク間で共有できるようにするためです。

<!--
The field <tt>p->files</tt> contains the file descriptor table. This too can be
shared between tasks, provided <tt>CLONE_FILES</tt> is specified with <bf>clone(2)</bf> system
call.
-->
<tt>p->files</tt>フィールドは、ファイルディスクリプタテーブルからなっています。これも<tt>CLONE_FILES</tt>が<bf>clone(2)</bf>システムコールで指定されたときにタスク間で共有されます。

<!--
The field <tt>p->sig</tt> contains signal handlers and can be shared between cloned
tasks by means of <tt>CLONE_SIGHAND</tt>.
-->
<tt>p->sig</tt>フィールドは、シグナルハンドラからなっています。そして<tt>CLONE_SIGHAND</tt>によりクローンのタスク間で共有されます。

<!--
<sect1>Creation and termination of tasks and kernel threads<p>
-->
<sect1>タスクとカーネルスレッドの生成と終端<p>

<!--
Different books on operating systems define a "process" in different ways,
starting from "instance of a program in execution" and ending with "that 
which is produced by clone(2) or fork(2) system calls".
Under Linux, there are three kinds of processes:
-->
オペレーティングシステムの他の書籍では、「プロセス」をそれぞれ違うように定義しています。「実行時のプログラムのインスタンス」に始まり、「clone(2)やfork(2)システムコールにより生成されるもの」
まで様々です。Linuxにおいては、三つのプロセスの種類があります。

<!--
<itemize>
<item> the idle thread(s),
<item> kernel threads,
<item> user tasks.
</itemize>
-->
<itemize>
<item>アイドルスレッド
<item>カーネルスレッド
<item>ユーザタスク
</itemize>

<!--
The idle thread is created at compile time for the first CPU; it is then
"manually" created for each CPU by means of arch-specific
<tt>fork_by_hand()</tt> in <tt>arch/i386/kernel/smpboot.c</tt>, which unrolls the <bf>fork(2)</bf> system
call by hand (on some archs). Idle tasks share one init_task structure but
have a private TSS structure, in the per-CPU array <tt>init_tss</tt>. Idle tasks all have
pid = 0 and no other task can share pid, i.e. use <tt>CLONE_PID</tt> flag to <bf>clone(2)</bf>.
-->
アイドルスレッドはコンパイル時に一つめのCPUのために作られます。そして「手動」でアーキテクチャ特有の<tt>arch/i386/kernel/smpboot.c</tt>の<tt>fork_by_hand()</tt>により各CPUごとに作られます。この関数では、<bf>fork(2)</bf>システムコールが(アーキテクチャによっては)手で展開されています。アイドルタスクは一つのinit_task構造体を共有しますが、TSS構造体は個別にCPUごとの配列<tt>init_tss</tt>として持っています。アイドルタスクはすべて pid=0 となりますが、他のタスクは pidを共有できません。これはつまり <tt>CLONE_PID</tt>フラグを<bf>clone(2)</bf>へと渡すということです。

<!--
Kernel threads are created using <tt>kernel_thread()</tt> function which invokes
the <bf>clone(2)</bf> system call in kernel mode. Kernel threads usually have no user
address space, i.e. <tt>p->mm = NULL</tt>, because they explicitly do <tt>exit_mm()</tt>, e.g.
via <tt>daemonize()</tt> function. Kernel threads can always access kernel address
space directly. They are allocated pid numbers in the low range. Running at
processor's ring 0 (on x86, that is) implies that the kernel threads enjoy all I/O privileges
and cannot be pre-empted by the scheduler.
-->
カーネルスレッドは、カーネルモードで <bf>clone(2)</bf> システムコールを呼び出す <tt>kernel_thread()</tt>関数を使って生成されます。カーネルスレッドは通常ユーザアドレス空間を持ちません(つまり<tt>p->mm = NULL</tt>)。これは、これらのスレッドが、(たとえば<tt>daemonize()</tt>関数を通して)明白に<tt>exit_mm()</tt>を行うからです。
カーネルスレッドは、いつでもカーネルアドレス空間へ直接アクセスできます。そして、小さな値のpid番号を割り当てられます。(x86のとき) プロセッサリング0 で走行しているときは、カーネルスレッドがすべてのI/Oの権利をもち、スケジューラに対してプリエンプティブではないということを意味しています。

<!--
User tasks are created by means of <bf>clone(2)</bf> or <bf>fork(2)</bf> system calls, both of
which internally invoke <bf>kernel/fork.c:do_fork()</bf>.
-->
ユーザタスクは、<bf>clone(2)</bf>ないしは、<bf>fork(2)</bf>システムコールにより作られます。これらのシステムコールは、内部的に<bf>kernel/fork.c:do_fork()</bf>を呼び出しています。

<!--
Let us understand what happens when a user process makes a <bf>fork(2)</bf> system
call. Although <bf>fork(2)</bf> is architecture-dependent due to the
different ways of passing user stack and registers, the actual underlying
function <tt>do_fork()</tt> that does the job is portable and is located at
<tt>kernel/fork.c</tt>.
-->
ここで、ユーザプロセスが<bf>fork(2)</bf>システムコールを呼び出したときに、何が起こっているかを解説しましょう。<bf>fork(2)</bf>がユーザスタックやレジスタを渡す方法が異なるという意味でアーキテクチャ依存だとしても、根底にある実際の仕事を行う関数の <tt>do_fork()</tt> は可搬性があり、ソースコードの<tt>kernel/fork.c</tt>に納められています。

<!--
The following steps are done:
-->
以下のステップで実行されます。


<enum>
<!--
<item> Local variable <tt>retval</tt> is set to <tt>-ENOMEM</tt>, as this is the value which <tt>errno</tt>
       should be set to if <bf>fork(2)</bf> fails to allocate a new task structure.
-->
<item> ローカル変数の<tt>retval</tt>が<tt>-ENOMEM</tt>にセットされる。これは<bf>fork(2)</bf>が新しいタスク構造体の割り当てに失敗したときにセットされる<tt>errno</tt>の値になっている。

<!--
<item> If <tt>CLONE_PID</tt> is set in <tt>clone_flags</tt> then return an error (<tt>-EPERM</tt>), unless
       the caller is the idle thread (during boot only). So, normal user
       threads cannot pass <tt>CLONE_PID</tt> to <bf>clone(2)</bf> and expect it to succeed.
       For <bf>fork(2)</bf>, this is irrelevant as <tt>clone_flags</tt> is set to <tt>SIFCHLD</tt> - this
       is only relevant when <tt>do_fork()</tt> is invoked from <tt>sys_clone()</tt> which
       passes the <tt>clone_flags</tt> from the value requested from userspace.
-->
<item> もし <tt>CLONE_PID</tt> が <tt>clone_flags</tt> にセットされていた場合、呼び出し元がアイドルスレッド(ブート時のみ)でない限り、エラー(<tt>-EPERM</tt>)を返す。通常のユーザスレッドが<tt>CLONE_PID</tt>を<bf>clone(2)</bf>に渡すことはできないし、成功を期待することもできない。
<!-- 
<item> <tt>current->vfork_sem</tt> is initialised (it is later cleared in the child).
       This is used by <tt>sys_vfork()</tt> (<bf>vfork(2)</bf> system call, corresponds to 
       <tt>clone_flags = CLONE_VFORK|CLONE_VM|SIGCHLD</tt>) to make the parent sleep
       until the child does <tt>mm_release()</tt>, for example as a result of <tt>exec()</tt>ing
       another program or <bf>exit(2)</bf>-ing.
-->
<item><tt>current->vfork_sem</tt> が初期化される(これは子によって後にクリアされる)。例えば、他のプログラムを <tt>exec()</tt> したり、<bf>exit(2)</bf> したときのように、これは <tt>sys_vfork()</tt> (<tt>clone_flags = CLONE_VFORK|CLONE_VM|SIGCHLD</tt>に関連する <bf>vfork(2)</bf> システムコール) により、子プロセスが<tt>mm_release()</tt>を実行するまで、親を休止させるために使われる。
</item>
<!-- 
<item> A new task structure is allocated using arch-dependent
       <tt>alloc_task_struct()</tt> macro. On x86 it is just a gfp at <tt>GFP_KERNEL</tt>
       priority. This is the first reason why <bf>fork(2)</bf> system call may sleep.
       If this allocation fails, we return <tt>-ENOMEM</tt>.
 -->
<item>新しいタスク構造体がアーキテクチャ依存の<tt>alloc_task_struct()</tt>マクロを使って割り当てられる。x86 上では、<tt>GFP_KERNEL</tt> 優先度の gfp になっている。これが <bf>fork(2)</bf> システムコールが休止する最大の理由になっている。もし割り当てが失敗すれば、<tt>-ENOMEM</tt>を返す。
<!-- 
<item> All the values from current process' task structure are copied into
       the new one, using structure assignment <tt>*p = *current</tt>. Perhaps this
       should be replaced by a <!-&#045; fix:memset to memcpy -&#045;>  memcpy? Later on, the fields that should not
       be inherited by the child are set to the correct values.
 -->
<item>現在のプロセスのタスク構造体の全ての値は、構造体の代入 <tt>*p = *current</tt> によって、新しいものへコピーされる。おそらくこれは、memcpyに置き換えられるべきものだ。その後で、子に引き継がれないフィールドは、正しい値に設定される。

<!-- 
<item> Big kernel lock is taken as the rest of the code would otherwise be
       non-reentrant.
 -->
<item>残りのコードがリエントラント可能ではないことから、大きなカーネルロックが取得される。

<!-- 
<item> If the parent has user resources (a concept of UID, Linux is flexible
       enough to make it a question rather than a fact), then verify if the
       user exceeded <tt>RLIMIT_NPROC</tt> soft limit - if so, fail with <tt>-EAGAIN</tt>, if
       not, increment the count of processes by given uid <tt>p->user->count</tt>.
 -->
<item> もし、親がユーザ資源をもっていた場合 (UIDの考え方において、Linuxは、事実としてではなく、その質問をするだけの十分な柔軟性をもっている) 、ユーザが<tt>RLIMIT_NPROC</tt>ソフトリミットを越えているかどうかを確認する。もし越えているなら失敗し<tt>-EAGAIN</tt>を返す。もし越えていなければ、与えられたuidのプロセスのカウンタ<tt>p->user->count</tt>を1増加させる。


<!-- <item> If the system-wide number of tasks exceeds the value of the tunable
       max_threads, fail with <tt>-EAGAIN</tt>. -->
<item>もし、実行されるシステム全体のタスク数が、調整可能な値である max_threads を越えていた場合、失敗して<tt>-EAGAIN</tt>を返す。

<!-- <item> If the binary being executed belongs to a modularised execution
       domain, increment the corresponding module's reference count. -->
<item>もしバイナリがモジュール実行領域に関連していた場合、関連モジュールのリファレンスカウンタを増やす。

<!-- <item> If the binary being executed belongs to a modularised binary format,
       increment the corresponding module's reference count. -->
<item>もし、実行されるバイナリがモジュール化されたバイナリフォーマットに関連していた場合、関連モジュールのリファレンスカウンタを1増加させる。

<!-- <item> The child is marked as 'has not execed' (<tt>p->did_exec = 0</tt>) -->
<item>子が「実行されていない」(<tt>p->pid_exec = 0</tt>)とマークされる。

<!-- <item> The child is marked as 'not-swappable' (<tt>p->swappable = 0</tt>) -->
<item>子が「スワップ不可」(<tt>p->swappable = 0</tt>)とマークされる。

<!-- <item> The child is put into 'uninterruptible sleep' state, i.e.
       <tt>p->state = TASK_UNINTERRUPTIBLE</tt> (TODO: why is this done?
       I think it's not needed - get rid of it, Linus confirms it is not
       needed)
 -->
<item>子が、「割り込み不可休止」状態、つまり<tt>p->state = TASK_UNINTERRUPTIBLE</tt>に入る(TODO: なぜこれが行われるのか？わたしには不要に思われる─これを削除するには、Linus が必要ないと認める必要がある)。

<!-- <item> The child's <tt>p->flags</tt> are set according to the value of clone_flags;
       for plain <bf>fork(2)</bf>, this will be <tt>p->flags = PF_FORKNOEXEC</tt>.
 -->
<item>子の<tt>p->flags</tt>が clone_flags の値にしたがって設定される。通常の<bf>fork(2)</bf>の時は、これは<tt>p->flags = PF_FORKNOEXEC</tt>になる。

<!-- 
<item> The child's pid <tt>p->pid</tt> is set using the fast algorithm in
       <tt>kernel/fork.c:get_pid()</tt> (TODO: <tt>lastpid_lock</tt> spinlock can be made
       redundant since <tt>get_pid()</tt> is always called under big kernel lock
       from <tt>do_fork()</tt>, also remove flags argument of <tt>get_pid()</tt>, patch sent
       to Alan on 20/06/2000 - followup later).
 -->
<item>子のpid <tt>p->pid</tt> は<tt>kernel/fork.c:get_pid()</tt>にある fast アルゴリズムを使用して、設定される。(TODO: <tt>lastpid_lock</tt>スピンロックはリダンダントにできる。<tt>do_fork()</tt>から大きなカーネルロックのもと常に<tt>get_pid()</tt>が呼ばれ<tt>get_pid()</tt>のフラグ引数を削除すればリダンダントにできる。パッチは Alan に2000年6月20日に送った。その後をフォローすること)

<!-- 
<item> The rest of the code in <tt>do_fork()</tt> initialises the rest of child's
       task structure. At the very end, the child's task structure is
       hashed into the <tt>pidhash</tt> hashtable and the child is woken up (TODO:
       <tt>wake_up_process(p)</tt> sets <tt>p->state = TASK_RUNNING</tt> and adds the process
       to the runq, therefore we probably didn't need to set <tt>p->state</tt> to
       <tt>TASK_RUNNING</tt> earlier on in <tt>do_fork()</tt>). The interesting part is
       setting <tt>p->exit_signal</tt> to <tt>clone_flags & CSIGNAL</tt>, which for <bf>fork(2)</bf>
       means just <tt>SIGCHLD</tt> and setting <tt>p->pdeath_signal</tt> to 0. The
       <tt>pdeath_signal</tt> is used when a process 'forgets' the original parent 
       (by dying) and can be set/get by means of <tt>PR_GET/SET_PDEATHSIG</tt>
       commands of <bf>prctl(2)</bf> system call (You might argue that the way the
       value of <tt>pdeath_signal</tt> is returned via userspace pointer argument
       in <bf>prctl(2)</bf> is a bit silly - mea culpa, after Andries Brouwer 
       updated the manpage it was too late to fix ;)
 -->
<item> <tt>do_fork()</tt>の残りのコードは、子のタスク構造体の残りを初期化する。一番最後に、子のタスク構造体は<tt>pidhash</tt>ハッシュ表にハッシュされ、子は起こされる(TODO: <tt>wake_up_process(p)</tt>は<tt>p->state = TASK_RUNNING</tt>を設定し、プロセスを runq に加える。したがって、<tt>do_fork()</tt>の最初のほうで<tt>p->state</tt>を<tt>TASK_RUNNING</tt>に設定する必要はおそらくない)。
興味深いのは、<bf>fork(2)</bf>にとって<tt>SIGCHLD</tt>を意味する、<tt>p->exit_signal</tt>が<tt>clone_flags & CSIGNAL</tt>に設定することと、<tt>p->pdeath_signal</tt>を0に設定することである。
<tt>pdeath_signal</tt>は、(親が死ぬなどして)プロセスがオリジナルの親を「忘れた」ときに使われ、<bf>prctl(2)</bf>システムコールの<tt>PR_GET/SET_PDEATHSIG</tt>によって設定/取得することができる。(<tt>pdeath_signal</tt>の値は、<bf>prctl(2)</bf>がユーザ空間のポインタアーギュメントを経由して戻されるということが少し不思議だと主張されるかもしれない―ごめんなさい。Andries Brouwer がマニュアルページを更新したあとだったので、修正が間に合わなかった ;)
</enum>
<!-- termination: mea culpa はラテン語で「私の罪」らしいです。by Kobayashi -->
<!-- 
Thus tasks are created. There are several ways for tasks to terminate:
 -->
このようにタスクが生成されます。そして、タスクが終端するには、いくつか方法があります。

<enum>
<!-- 
<item> by making <bf>exit(2)</bf> system call;

<item> by being delivered a signal with default disposition to die;

<item> by being forced to die under certain exceptions;

<item> by calling <bf>bdflush(2)</bf> with <tt>func == 1</tt> (this is Linux-specific, for
       compatibility with old distributions that still had the 'update'
       line in <tt>/etc/inittab</tt> - nowadays the work of update is done by
       kernel thread <tt>kupdate</tt>).
 -->
<item><bf>exit(2)</bf>システムコールを発行する。

<item>デフォルトで死ぬ性質のシグナルが届く。

<item>特定の例外によって、強制的に死ぬ。

<item><tt>func == 1</tt>の<bf>bdflush(2)</bf>を呼ぶ (これは Linux 独特であり、'update'行が<tt>/etc/inittab</tt>に残っているような古いディストリビューションとの互換性のためである。現在ではupdateの仕事は、カーネルスレッドの<tt>kupdate</tt>が行っている)。

</enum>

<!-- 
Functions implementing system calls under Linux are prefixed with <tt>sys_</tt>, 
but they are usually concerned only with argument checking or arch-specific
ways to pass some information and the actual work is done by <tt>do_</tt> functions.
So it is with <tt>sys_exit()</tt> which calls <tt>do_exit()</tt> to do the work. Although, 
other parts of the kernel sometimes invoke <tt>sys_exit()</tt> while they should really
call <tt>do_exit()</tt>.
 -->
Linux でシステムコールを実装している関数は、<tt>sys_</tt>のプレフィックスを持っています。しかし、これらの関数は、たいてい引数のチェックやアーキテクチャ独特の情報の渡し方についてのみ関心をもっており、実際の仕事は、<tt>do_</tt>のついた関数が行います。そのため、<tt>sys_exit()</tt>においては、<tt>do_exit()</tt>を実際の仕事を行うために呼び出します。しかしながら、カーネルの他の部分で時折、実処理をしている<tt>do_exit()</tt>を呼び出さなければならない場面で、<tt>sys_exit()</tt>を呼び出しているところが見受けられます。

<!-- 
The function <tt>do_exit()</tt> is found in <tt>kernel/exit.c</tt>. The points to note about
<tt>do_exit()</tt>:
 -->
<tt>do_exit()</tt>関数は、<tt>kernel/exit.c</tt>にあります。<tt>do_exit()</tt>についてのポイントとしては、

<!-- 
<itemize>
<item> Uses global kernel lock (locks but doesn't unlock).

<item> Calls <tt>schedule()</tt> at the end, which never returns.

<item> Sets the task state to <tt>TASK_ZOMBIE</tt>.

<item> Notifies any child with <tt>current->pdeath_signal</tt>, if not 0.

<item> Notifies the parent with a <tt>current->exit_signal</tt>, which is usually
       equal to <tt>SIGCHLD</tt>.

<item> Releases resources allocated by fork, closes open files etc.

<item> On architectures that use lazy FPU switching (ia64, mips, mips64)
       (TODO: remove 'flags' argument of 
       sparc, sparc64), do whatever the hardware requires to pass the FPU
       ownership (if owned by current) to "none".
</itemize>
 -->
<itemize>
<item>グローバルカーネルロックを使用する(ロックするがロック解除しない)。

<item><tt>schedule()</tt>を最後に呼び出すが、戻ることはない。

<item>タスク状態を<tt>TASK_ZOMBIE</tt>に設定する。

<item>もし0でなければ、<tt>current->pdeath_signal</tt>により、すべての子に通知する。

<item>親に<tt>current->exit_signal</tt>によって通知する。これは通常<tt>SIGCHLD</tt>になる。

<item>forkによって割り当てられた資源を解放する。オープンしたファイルなど。</item>

<item>lazy FPUスイッチングを使うアーキテクチャの場合(ia64, mips, mips64) (TODO: sparc, sparc64の'flags'引数を削除する) FPUオーナーシップ(もしカレントが所有していたら）「なし」を渡すためにハードウエアが要求することを行う。</item>

</itemize>

<!-- 
<sect1>Linux Scheduler<p>
 -->

<sect1>Linuxスケジューラ<p>

<!-- 
The job of a scheduler is to arbitrate access to the current CPU between
multiple processes. The scheduler is implemented in the 'main kernel file'
<tt>kernel/sched.c</tt>. The corresponding header file <tt>include/linux/sched.h</tt> is
included (either explicitly or indirectly) by virtually every kernel source
file.
 -->
スケジューラの仕事は、カレントの CPU へのアクセスを複数のプロセス間で仲裁することにあります。スケジューラは、「メインのカーネルファイル」<tt>kernel/sched.c</tt>に実装されています。関連のへッダファイルである<tt>include/linux/sched.h</tt>は、(明示的にせよ間接的にせよ)事実上全てのカーネルソースファイルから読み込まれます。

<!-- 
The fields of task structure relevant to scheduler include:
 -->
スケジューラに関連するタスク構造体のフィールドには、次のものがあります。

<itemize>
<!-- 
<item> <tt>p->need_resched</tt>: this field is set if <tt>schedule()</tt> should be invoked at
       the 'next opportunity'.
 -->
<item><tt>p->need_resched</tt>: このフィールドは、<tt>schedule()</tt>が「次の機会」に起動されるべき時にセットされます。</item>

<!-- 
<item> <tt>p->counter</tt>: number of clock ticks left to run in this scheduling
       slice, decremented by a timer. When this field becomes lower than or equal to zero, it is reset
       to 0 and <tt>p->need_resched</tt> is set. This is also sometimes called 'dynamic
       priority' of a process because it can change by itself.
 -->
<item><tt>p->counter</tt>: このスケジューリングスライスでの実行の残りのクロックチック数でタイマによって減少される。この値が0以下になったときは、<TT>p->need_resched</tt> が設定される。これは自身が変更できるため、プロセスの「動的優先度」と呼ばれることもある。

<!-- 
<item> <tt>p->priority</tt>: the process' static priority, only changed through well-known
       system calls like <bf>nice(2)</bf>, POSIX.1b <bf>sched_setparam(2)</bf> or 4.4BSD/SVR4
       <bf>setpriority(2)</bf>.
 -->
<item> <tt>p->priority</tt>: プロセスの静的な優先度であり、よく使われるシステムコールの<bf>nice(2)</bf>や、POSIX.1bの<bf>sched_setparam(2)</bf>、4.4BSD/SVR4の<bf>setpriority(2)</bf>によって変更される。</item>

<!-- 
<item> <tt>p->rt_priority</tt>: realtime priority
 -->
<item><tt>p->rt_priority</tt>: リアルタイム優先度。

<!-- 
<item> <tt>p->policy</tt>: the scheduling policy, specifies which scheduling class the
       task belongs to. Tasks can change their scheduling class using the
       <bf>sched_setscheduler(2)</bf> system call. The valid values are <tt>SCHED_OTHER</tt>
       (traditional UNIX process), <tt>SCHED_FIFO</tt> (POSIX.1b FIFO realtime
       process) and <tt>SCHED_RR</tt> (POSIX round-robin realtime process). One can 
       also OR <tt>SCHED_YIELD</tt> to any of these values to signify that the process
       decided to yield the CPU, for example by calling <bf>sched_yield(2)</bf> system
       call. A FIFO realtime process will run until either a) it blocks on I/O,
       b) it explicitly yields the CPU or c) it is preempted by another realtime
       process with a higher <tt>p->rt_priority</tt> value. <tt>SCHED_RR</tt> is the same as
       <tt>SCHED_FIFO</tt>, except that when its timeslice expires it goes back to
       the end of the runqueue.
 -->
<item><tt>p->policy</tt>: スケジューリングポリシーであり、タスクが所属するスケジューリングのクラスを表す。<bf>sched_setscheduler(2)</bf>システムコールを使うことで、タスクのスケジューリングのクラスを変更することができる。取りうる値には、<tt>SCHED_OTHER</tt>(伝統的なUNIXのプロセス)、<tt>SCHED_FIFO</tt>(POSIX.1b FIFO リアルタイムプロセス)と<tt>SCHED_RR</tt>(POSIX ラウンドロビンリアルタイムプロセス)がある。これらは、<tt>SCHED_YIELD</tt>とORを取ることができ、たとえば<bf>sched_yield(2)</bf>システムコールを呼び出すことによって、プロセスが CPU を譲ることにしたことを示すことができる。FIFOリアルタイムプロセスは a) I/Oがブロックされるか、b) 明示的に CPU を解放するか、c) 他の高い<tt>p->rt_priority</tt>値を持つリアルタイムプロセスから割り込まれるか、いずれかがあるまで実行される。</item>
</itemize>

<!-- 
The scheduler's algorithm is simple, despite the great apparent complexity
of the <tt>schedule()</tt> function. The function is complex because it implements
three scheduling algorithms in one and also because of the subtle 
SMP-specifics.
 -->
<tt>schedule()</tt>関数は、見掛け上、非常に複雑ですが、スケジューラのアルゴリズムは単純です。関数が複雑なのは、3つのスケジューリングアルゴリズムを一つに実装しているのと同時に、SMP のデリケートな仕様を実装しているからです。

<!-- 
The apparently 'useless' gotos in <tt>schedule()</tt> are there for a purpose - to
generate the best optimised (for i386) code. Also, note that scheduler
(like most of the kernel) was completely rewritten for 2.4, therefore the
discussion below does not apply to 2.2 or earlier kernels.

Let us look at the function in detail:
 -->
明らかに「無駄な」gotoが<tt>schedule()</tt>にありますが、これはi386で一番最適化されたコードを生成するためです。もちろん、スケジューラは2.4で完全に(カーネルの他の部分同様)書き直されました。そのため、以下の議論は2.2やそれ以前のカーネルには当てはまりません。

では詳細に関数を見ていきましょう。

<enum>
<!-- 
<item> If <tt>current->active_mm == NULL</tt> then something is wrong. Current
       process, even a kernel thread (<tt>current->mm == NULL</tt>) must have a valid
       <tt>p->active_mm</tt> at all times.
 -->
<item> もし<tt>current->active_mm == NULL</tt>なら、なにかがおかしい。カレントのプロセスは、カーネルスレッド(<tt>current->mm == NULL </tt>)であったとしても、正しい<tt>p->active_mm</tt>を常に持っていなければならない。</item>

<!-- 
<item> If there is something to do on the <tt>tq_scheduler</tt> task queue, process it
       now. Task queues provide a kernel mechanism to schedule execution of
       functions at a later time. We shall look at it in details elsewhere.
 -->
<item>もし<tt>tq_scheduler</tt>タスクキューに実行するものがあれば、いまそれを処理する。タスクキューは関数の実行を遅らせてスケジュールを行うカーネルの仕組みを提供するものである。その詳細は他の章で説明する。

<!-- 
<item> Initialise local variables <tt>prev</tt> and <tt>this_cpu</tt> to current task and
       current CPU respectively.
 -->
<item>ローカル変数の<tt>prev</tt>と<tt>this_cpu</tt>を、それぞれ現在のタスクと現在の CPU に初期化する。</item>

<!-- 
<item> Check if <tt>schedule()</tt> was invoked from interrupt handler (due to a bug)
       and panic if so.
 -->
<item><tt>schedule()</tt>が(バグにより)割り込みハンドラから起動されていないかチェックする。もしそうならカーネルパニックになる。

<!-- 
<item> Release the global kernel lock.
 -->
<item>グローバルカーネルロックを解放する。

<!-- 
<item> If there is some work to do via softirq mechanism, do it now.
 -->
<item>もしソフト割り込み機構経由で行うことがあれば、ここで実行する。

<!-- 
<item> Initialise local pointer <tt>struct schedule_data *sched_data</tt> to point
       to per-CPU (cacheline-aligned to prevent cacheline ping-pong)
       scheduling data area, which contains the TSC value of <tt>last_schedule</tt> and the
       pointer to last scheduled task structure (TODO: <tt>sched_data</tt> is used on
       SMP only but why does <tt>init_idle()</tt> initialises it on UP as well?).
 -->
<item>ローカルポインタ<tt>struct  schedule_data *sched_data</tt>を初期化し、CPU毎の(キャッシュラインピンポンを避けるためキャッシュラインにアラインされる)スケジューリングデータ領域を指すようにする。これは、<tt>last_schedule</tt>のTSC値や最後にスケジュールされたタスク構造体へのポインタからなっている。(TODO: <tt>sched_data</tt>は SMP の時のみ使われるが、なぜ<tt>init_idle()</tt>は UPであっても同様に初期化を行うのか?)</item>

<!-- 
<item> <tt>runqueue_lock</tt> spinlock is taken. Note that we use <tt>spin_lock_irq()</tt>
       because in <tt>schedule()</tt> we guarantee that interrupts are enabled. Therefore,
       when we unlock <tt>runqueue_lock</tt>, we can just re-enable them instead of
       saving/restoring eflags (<tt>spin_lock_irqsave/restore</tt> variant).
 -->
<item><tt>runqueue_lock</tt>スピンロックを取得する。私たちが<tt>spin_lock_irq()</tt>を使うのは、<tt>schedule()</tt>の中で、割り込み可になっていることを保証するためである。したがって、<tt>runqueue_lock</tt>を解除するときには、(<tt>spin_lock_irqsave/restore</tt>の一種の) saving/restoring eflagsを使うのではなく、単に再度有効にするだけでよい。

<!-- 
<item> task state machine: if the task is in <tt>TASK_RUNNING</tt> state, it is left
       alone; if it is in <tt>TASK_INTERRUPTIBLE</tt> state and a signal is pending,
       it is moved into <tt>TASK_RUNNING</tt> state. In all other cases, it is deleted
       from the runqueue.
 -->
<item>タスク状態機械: もしタスクが<tt>TASK_RUNNING</tt>状態にあれば、そのままにされる。もし<tt>TASK_INTERRUPTIBLE</tt>状態であり、シグナルが保留されていれば、<tt>TASK_RUNNING</tt>状態へ移行させる。それ以外の場合は、runqueueから削除する。

<!-- 
<item> <tt>next</tt> (best candidate to be scheduled) is set to the idle task of
       this cpu. However, the goodness of this candidate is set to a very
       low value (-1000), in hope that there is someone better than that.
 -->
<item>(もっともスケジュールされやすい候補の)<tt>next</tt>がこの CPU でのアイドルタスクにされる。しかし、この候補のグッドネスは、他のものがこれより良くなるように、とても低い値(-1000)となる。

<!-- 
<item> If the <tt>prev</tt> (current) task is in <tt>TASK_RUNNING</tt> state, then the
       current goodness is set to its goodness and it is marked as a better
       candidate to be scheduled than the idle task.
 -->
<item>もし<tt>prev</tt>(カレント)のタスクが<tt>TASK_RUNNING</tt>状態であれば、カレントのグッドネスをそのグッドネスと同じに設定する。アイドルタスクよりスケジュールされやすくなるよう印をつける。</item>

<!-- 
<item> Now the runqueue is examined and a goodness of each process that can
       be scheduled on this cpu is compared with current value; the
       process with highest goodness wins. Now the concept of "can be
       scheduled on this cpu" must be clarified: on UP, every process on
       the runqueue is eligible to be scheduled; on SMP, only process not
       already running on another cpu is eligible to be scheduled on this
       cpu. The goodness is calculated by a function called <tt>goodness()</tt>, which
       treats realtime processes by making their goodness very high
       (<tt>1000 + p->rt_priority</tt>), this being greater than 1000 guarantees that
       no <tt>SCHED_OTHER</tt> process can win; so they only contend with other
       realtime processes that may have a greater <tt>p->rt_priority</tt>. 
 -->
<item> さて、runqueueを調べ、このCPUでスケジュールされることが可能な各プロセスのグッドネスをカレントの値と比較する。そして、もっとも高いグッドネスを持つプロセスが勝つ。ここで、この「この CPU でスケジュールされることが可能な」という考え方を明確にすると、UP では、runqueue の各プロセスをスケジュール可能である。SMP においては、すでに他の CPU で走行可能になっていないプロセスだけがスケジュールできる。グッドネスは<tt>goodness()</tt>という関数により計算される。リアルタイムプロセスのグッドネスでは非常に高く(<tt>1000 + p->rt_priority</tt>)することで処理する。 1000 より大きいことで、<tt>SCHED_OTHER</tt>ではないプロセスが勝つことを保証している。そして他のより大きな<tt>p->rt_priority</tt>を持つリアルタイムプロセスだけが争うことができる。

<!-- 
The
       goodness function returns 0 if the process' time slice (<tt>p->counter</tt>) 
       is over. For non-realtime processes, the initial value of goodness is
       set to <tt>p->counter</tt> - this way, the process is less likely to get CPU if
       it already had it for a while, i.e. interactive processes are favoured
       more than CPU bound number crunchers. The arch-specific constant
       <tt>PROC_CHANGE_PENALTY</tt> attempts to implement "cpu affinity" (i.e. give 
       advantage to a process on the same CPU). It also gives a slight
       advantage to processes with mm pointing to current <tt>active_mm</tt> or to
       processes with no (user) address space, i.e. kernel threads.
 -->
プロセスのタイムスライス(<tt>p->counter</tt>)が終了したときは、goodness 関数は 0 を返す。リアルタイムではないプロセスでは、グッドネスの初期値は <tt>p->counter</tt> に設定されるため、すでにしばらくの間 CPU を占有したプロセスは、 CPU を得ることが少なくなる。つまり対話的プロセスは、CPUの割り当てをたくさんとってしまうプロセスより優先される。
アーキテクチャ固有の定数<tt>PROC_CHANGE_PENALTY</tt>は「CPU との密接度」を実装しようとしたもの(つまり、同じ CPU のプロセスが優先される)で、これはカレントの<tt>active_mm</tt>をさしているプロセスや、(ユーザ）アドレス空間を持たない(カーネルスレッドのような)プロセスに若干の優先度を与える。

<!-- 
<item> if the current value of goodness is 0 then the entire list of
       processes (not just the ones on the runqueue!) is examined and their dynamic
       priorities are recalculated using simple algorithm:
 -->
<item>もし、グッドネスの現在の値が 0 のときは、プロセスのリストの全て(runqueueにあるものだけではなく)が検査され、その動的な優先度が単純なアルゴリズムにより再計算される。

<tscreen><code>

recalculate:
        {
                struct task_struct *p;
                spin_unlock_irq(&amp;runqueue_lock);
                read_lock(&amp;tasklist_lock);
                for_each_task(p)
                        p->counter = (p->counter >> 1) + p->priority;
                read_unlock(&amp;tasklist_lock);
                spin_lock_irq(&amp;runqueue_lock);
        }
</code></tscreen>
<!-- 
	   Note that the we drop the <tt>runqueue_lock</tt> before we recalculate. The
	   reason is that we go through entire set of processes;  this can take
	   a long time, during which the <tt>schedule()</tt> could be called on another CPU and
	   select a process with goodness good enough for that CPU, whilst we on
	   this CPU were forced to recalculate. Ok, admittedly this is somewhat
	   inconsistent because while we (on this CPU) are selecting a process with
	   the best goodness, <tt>schedule()</tt> running on another CPU could be
	   recalculating dynamic priorities.
 -->
再計算を行う前に<tt>runqueue_lock</tt>を解除することに注目しよう。全てのプロセスの配列を処理するため、時間を必要とするからだ。CPU が再計算をさせられているその間に、<tt>schedule()</tt>が他の CPU において呼ばれ、その CPU にとって十分にグッドネスが良いプロセスを選ぶことができる。そう、これは明らかにちょっと矛盾している。私たちが(この CPU 上で)もっとも良いグッドネスを持つプロセスを選んでいる間に、他の CPU で実行されている <tt>schedudle()</tt> が、動的優先度を再計算することができているからだ。

<!-- 
<item> From this point on it is certain that <tt>next</tt> points to the task to
       be scheduled, so we initialise <tt>next->has_cpu</tt> to 1 and <tt>next->processor</tt>
       to <tt>this_cpu</tt>. The <tt>runqueue_lock</tt> can now be unlocked.
 -->
<item>この時点で、<tt>next</tt>がスケジュールされるタスクを指しており、そのため<tt>next->has_cpu</tt>を 1 に<tt>next->processor</tt>を<tt>this_cpu</tt>に初期化していることが確実である。<tt>runqueue_lock</tt>はそうしたうえで解除できる。

<!-- 
<item> If we are switching back to the same task (<tt>next == prev</tt>) then we can
       simply reacquire the global kernel lock and return, i.e. skip all the
       hardware-level (registers, stack etc.) and VM-related (switch page
       directory, recalculate <tt>active_mm</tt> etc.) stuff.
 -->
<item>もし同じタスクに戻ってきたなら(<tt>next == prev</tt>)、単純にグローバルカーネルロックを再取得し返る。つまり、全てのハードウエアレベル(レジスタ、スタックなど)と VM 関連(スイッチページディレクトリ、<tt>active_mm</tt>の再計算など)のものはスキップされる。

<!-- 
<item> The macro <tt>switch_to()</tt> is architecture specific. On i386, it is
       concerned with a) FPU handling, b) LDT handling, c) reloading segment
       registers, d) TSS handling and e) reloading debug registers.
 -->
<item>マクロ<tt>switch_to()</tt>はアーキテクチャ特有である。i386では、これは a)FPU ハンドリング、b) LDT ハンドリング、c) セグメントレジスタのリロード、d)TSSのハンドリング、e) デバッグレジスタのリロードに関係がある。
</enum>

<!-- 
<sect1>Linux linked list implementation<p>
 -->
<sect1>Linuxでのリンクリストの実装<p>

<!-- 
Before we go on to examine implementation of wait queues, we must
acquaint ourselves with the Linux standard doubly-linked list implementation.
Wait queues (as well as everything else in Linux) make heavy use
of them and they are called in jargon "list.h implementation" because the
most relevant file is <tt>include/linux/list.h</tt>.
 -->
ウエイトキューの実装に行く前に、Linux標準のダブルリンクリストの実装に熟知しなければなりません。
ウエイトキュー(Linuxの他のものと同様）は、この実装を良く使いますし、<tt>include/linux/list.h</tt> がもっとも関連していることから、ジャーゴンで「list.h の実装」とも呼ばれます。

<!-- 
The fundamental data structure here is <tt>struct list_head</tt>:
 -->
ここでの基礎的なデータ構造体は、<tt>struct list_head</tt>です。

<tscreen><code>
struct list_head {
        struct list_head *next, *prev;
};

#define LIST_HEAD_INIT(name) { &amp;(name), &amp;(name) }

#define LIST_HEAD(name) \
        struct list_head name = LIST_HEAD_INIT(name)

#define INIT_LIST_HEAD(ptr) do { \
        (ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)

#define list_entry(ptr, type, member) \
        ((type *)((char *)(ptr)-(unsigned long)(&amp;((type *)0)->member)))

#define list_for_each(pos, head) \
        for (pos = (head)->next; pos != (head); pos = pos->next)
</code></tscreen>

<!-- 
The first three macros are for initialising an empty list by pointing both
<tt>next</tt> and <tt>prev</tt> pointers to itself. It is obvious from C syntactical
restrictions which ones should be used where - for example, <tt>LIST_HEAD_INIT()</tt>
can be used for structure's element initialisation in declaration, the second
can be used for static variable initialising declarations and the third can
be used inside a function.
 -->
最初の 3 つのマクロは<tt>next</tt>と<tt>prev</tt>ポインタを自身を指すようにして、空リストを初期化するものです。例えば、<tt>LIST_HEAD_INIT()</tt> は、宣言時に構造体の要素を初期化するために使われ、2つ目はスタティック変数の初期化を行う宣言で、3つ目は関数の中で使われると言ったように、どれがどこで使われるかは、 C の構文の制約からも明らかです。

<!-- 
The macro <tt>list_entry()</tt> gives access to individual list element, for example
(from <tt>fs/file_table.c:fs_may_remount_ro()</tt>):
 -->
マクロ<tt>list_entry()</tt>はそれぞれのリスト要素へのアクセスを提供します。たとえば、
(<tt>fs/file_table.c:fs_may_remount_ro()</tt>からの例で):

<tscreen><code>
struct super_block {
   ...
   struct list_head s_files;
   ...
} *sb = &amp;some_super_block;

struct file {
   ...
   struct list_head f_list;
   ...
} *file;

struct list_head *p;

for (p = sb->s_files.next; p != &amp;sb->s_files; p = p->next) {
     struct file *file = list_entry(p, struct file, f_list);
     do something to 'file'
}
</code></tscreen>

<!-- 
A good example of the use of <tt>list_for_each()</tt> macro is in the scheduler where
we walk the runqueue looking for the process with highest goodness:
 -->
<tt>list_for_each()</tt>マクロの使い方の良い例が、ちょうど注目しているスケジューラのなかの、もっとも高いグッドネスを持つプロセスを探してrunqueueを見る部分にあります。

<tscreen><code>
static LIST_HEAD(runqueue_head);
struct list_head *tmp;
struct task_struct *p;

list_for_each(tmp, &amp;runqueue_head) {
    p = list_entry(tmp, struct task_struct, run_list);
    if (can_schedule(p)) {
        int weight = goodness(p, this_cpu, prev->active_mm);
        if (weight > c)
            c = weight, next = p;
    }
}
</code></tscreen>

<!-- 
Here, <tt>p->run_list</tt> is declared as <tt>struct list_head run_list</tt> inside
<tt>task_struct</tt> structure and serves as anchor to the list. Removing an element
from the list and adding (to head or tail of the list) is done by
 <tt>list_del()/list_add()/list_add_tail()</tt> macros. The examples below are adding
and removing a task from runqueue:
 -->
ここで、<tt>p->run_list</tt>は、<tt>task_struct</tt>構造体の中の<tt>struct list_head run_list</tt>として宣言されています。そして、リストのアンカーを提供します。要素をリストから削除し、あるいは追加(リストの先頭にせよ、末尾にせよ)する場合には、<tt>list_del()/list_add()/list_add_tail()</tt>マクロによって実行します。以下の例は、runqueueへタスクを追加および削除する例です。

<tscreen><code>
static inline void del_from_runqueue(struct task_struct * p)
{
        nr_running--;
        list_del(&amp;p->run_list);
        p->run_list.next = NULL;
}

static inline void add_to_runqueue(struct task_struct * p)
{
        list_add(&amp;p->run_list, &amp;runqueue_head);
        nr_running++;
}

static inline void move_last_runqueue(struct task_struct * p)
{
        list_del(&amp;p->run_list);
        list_add_tail(&amp;p->run_list, &amp;runqueue_head);
}

static inline void move_first_runqueue(struct task_struct * p)
{
        list_del(&amp;p->run_list);
        list_add(&amp;p->run_list, &amp;runqueue_head);
}
</code></tscreen>

<!-- 
<sect1>Wait Queues<p>
 -->
<sect1>ウエイトキュー<p>

<!-- 
When a process requests the kernel to do something which is currently
impossible but that may become possible later, the process is put to sleep
and is woken up when the request is more likely to be satisfied. One of the
kernel mechanisms used for this is called a 'wait queue'. 
 -->
プロセスがカーネルに依頼したことが現在不可能であるが、後に可能となる事であったなら、プロセスは休止状態へと入り、要求が満たされる条件が整いそうなときに起こされます。この時使われるカーネルのメカニズムの一つが「ウエイトキュー」です。

<!-- 
Linux implementation allows wake-on semantics using <tt>TASK_EXCLUSIVE</tt> flag.
With waitqueues, you can either use a well-known queue and then simply
<tt>sleep_on/sleep_on_timeout/interruptible_sleep_on/interruptible_sleep_on_timeout</tt>,
or you can define your own waitqueue and use <tt>add/remove_wait_queue</tt> to add and
remove yourself from it and <tt>wake_up/wake_up_interruptible</tt> to wake up
when needed.
 -->
Linux の実装では、<tt>TASK_EXCLUSIVE</tt>フラグを使う起動セマンティクスを許しています。ウエイトキューによって、well-knownキューを使って単純に <tt>sleep_on/sleep_on_timeout/interruptible_sleep_on/interruptible_sleep_on_timeout</tt> を使うこともできますし、自身のウエイトキューを定義し、それに自身を追加/削除するために <tt>add/remove_wait_queue</tt> を使用して、必要時に起きるため<tt>wake_up/wake_up_interruptible</tt> を使用することもできます。

<!-- 
An example of the first usage of waitqueues is interaction between the page
allocator (in <tt>mm/page_alloc.c:__alloc_pages()</tt>) and the <tt>kswapd</tt> kernel daemon (in
<tt>mm/vmscan.c:kswap()</tt>), by means of wait queue <tt>kswapd_wait,</tt> declared in
<tt>mm/vmscan.c</tt>; the <tt>kswapd</tt> daemon sleeps on this queue, and it is woken up
whenever the page allocator needs to free up some pages.
 -->
最初のウエイトキューの使い方の例としては、(<tt>mm/page_alloc.c:__alloc_pages()</tt>の) ページアロケータ と (<tt>mm/vmscan.c:kswap()</tt>の) <tt>kswapd</tt> カーネルデーモンの間における、<tt>mm/vmscan.c</tt> で定義されるウエイトキュー<tt>kswapd_wait</tt>による相互作用があります。<tt>kswapd</tt>デーモンはこのキュー上で休止し、ページアロケータがページを解放してやる必要がでるまで起きることはありません。

<!-- 
An example of autonomous waitqueue usage is interaction between
user process requesting data via <bf>read(2)</bf> system call and kernel running in
the interrupt context to supply the data. An interrupt handler might look
like (simplified <tt>drivers/char/rtc_interrupt()</tt>):
 -->
自発的なウエイトキューの用例には、 <bf>read(2)</bf>システムコールでデータを要求するユーザプロセスと、データを提供するため、割り込みコンテキストで走行するカーネルの間の相互作用があります。割り込みハンドラは以下のようになっています (<tt>drivers/char/rtc_interrupt()</tt>を簡略化)。

<tscreen><code>
static DECLARE_WAIT_QUEUE_HEAD(rtc_wait);

void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
	spin_lock(&amp;rtc_lock);	
	rtc_irq_data = CMOS_READ(RTC_INTR_FLAGS);
	spin_unlock(&amp;rtc_lock);	
	wake_up_interruptible(&amp;rtc_wait);
}
</code></tscreen>
<!-- 
So, the interrupt handler obtains the data by reading from some
device-specific I/O port (<tt>CMOS_READ()</tt> macro turns into a couple <tt>outb/inb</tt>) and
then wakes up whoever is sleeping on the <tt>rtc_wait</tt> wait queue.

Now, the <bf>read(2)</bf> system call could be implemented as:
 -->
ここで割り込みハンドラは、デバイスに特有のI/O ポートを読み取る(<tt>CMOS_READ()</tt> マクロは複数の <tt>outb/inb</tt>になります)ことでデータを取得し、<tt>rtc_wait</tt> ウエイトキューで休止中のものを起動します。

<tscreen><code>
ssize_t rtc_read(struct file file, char *buf, size_t count, loff_t *ppos)
{
	DECLARE_WAITQUEUE(wait, current);
	unsigned long data;
	ssize_t retval;

	add_wait_queue(&amp;rtc_wait, &amp;wait);
	current->state = TASK_INTERRUPTIBLE;
	do {
		spin_lock_irq(&amp;rtc_lock);
		data = rtc_irq_data;
		rtc_irq_data = 0;
		spin_unlock_irq(&amp;rtc_lock);

		if (data != 0)
			break;

		if (file->f_flags & O_NONBLOCK) {
			retval = -EAGAIN;
			goto out;
		}
		if (signal_pending(current)) {
			retval = -ERESTARTSYS;
			goto out;
		}
		schedule();
	} while(1);
	retval = put_user(data, (unsigned long *)buf);	
	if (!retval)
		retval = sizeof(unsigned long);

out:
	current->state = TASK_RUNNING;
	remove_wait_queue(&amp;rtc_wait, &amp;wait);
	return retval;
}
</code></tscreen>
<!-- 
What happens in <tt>rtc_read()</tt> is this:
 -->
<tt>rtc_read()</tt> で起っている事というのは、

<enum>
<!-- 
<item> We declare a wait queue element pointing to current process context.

<item> We add this element to the <tt>rtc_wait</tt> waitqueue.

<item> We mark current context as <tt>TASK_INTERRUPTIBLE</tt> which means it will not
       be rescheduled after the next time it sleeps.
 -->
<item>ウエイトキューの要素をカレントプロセスのコンテキストを指すよう宣言する。</item>

<item>この要素を <tt>rtc_wait</tt> ウエイトキューに追加する。</item>

<item>現在のコンテキストに、次回休止したあとに再スケジュールされないことを意味する <tt>TASK_INTERRUPTIBLE</tt>のマークづけをする。</item>

<!-- 
<item> We check if there is no data available; if there is we break out,
       copy data to user buffer, mark ourselves as <tt>TASK_RUNNING</tt>, remove
	   ourselves from the wait queue and return
 -->
<item>データが存在しないかどうかチェックする。もし存在するなら、処理を中断してデータをユーザバッファにコピーし、自身を<tt>TASK_RUNNING</tt>とマークして、自身をウエイトキューから削除して、返る。</item>

<!-- 
<item> If there is no data yet, we check whether the user specified non-blocking I/O
       and if so we fail with <tt>EAGAIN</tt> (which is the same as <tt>EWOULDBLOCK</tt>)
 -->
<item>データがなければ、ユーザがノンブロッキング I/O を指定したかどうかチェックし、もしそうなら、<tt>EAGAIN</tt>(これは、<tt>EWOULDBLOCK</tt>と同じ)エラーで終了する。</item>

<!-- 
<item> We also check if a signal is pending and if so inform the "higher
       layers" to restart the system call if necessary. By "if necessary"
       I meant the details of signal disposition as specified in <bf>sigaction(2)</bf>
       system call.
 -->
<item>ここでまた、シグナルが保留されていないかをチェックする。もし保留されていれば、「より上のレイヤー」に、必要があればシステムコールを再スタートさせるよう知らせる。「必要があれば」とは、<bf>sigaction(2)</bf>システムコールで指定されるシグナルの性質の詳細を意図している。

<!-- 
<item> Then we "switch out", i.e. fall asleep, until woken up by the
       interrupt handler. If we didn't mark ourselves as <tt>TASK_INTERRUPTIBLE</tt>
       then the scheduler could schedule us sooner than when the data is
       available, thus causing unneeded processing.
 -->
<item>そして、「switch out」つまり、割り込みハンドラに起こされるまで休止状態になる。もし自身を<tt>TASK_INTERRUPTIBLE</tt>にマークしないと、スケジューラはデータが有効になるより早くスケジュールするため、不必要な処理の原因になる。
</enum>

<!-- 
It is also worth pointing out that, using wait queues, it is rather easy to
implement the <bf>poll(2)</bf> system call:
 -->
また、ウエイトキューを用いることで、<bf>poll(2)</bf>システムコールの実装がむしろ容易になっていることも指摘しておきましょう。

<tscreen><code>
static unsigned int rtc_poll(struct file *file, poll_table *wait)
{
        unsigned long l;

        poll_wait(file, &amp;rtc_wait, wait);

        spin_lock_irq(&amp;rtc_lock);
        l = rtc_irq_data;
        spin_unlock_irq(&amp;rtc_lock);

        if (l != 0)
                return POLLIN | POLLRDNORM;
        return 0;
}
</code></tscreen>

<!-- 
All the work is done by the device-independent function <tt>poll_wait()</tt> which does
the necessary waitqueue manipulations; all we need to do is point it to the
waitqueue which is woken up by our device-specific interrupt handler.
 -->
全ての仕事は、デバイス非依存関数の<tt>poll_wait()</tt>によって行われます。これは、必要なウエイトキューの操作を行います。我々がしなければならないことは、デバイス特有の割り込みハンドラによって起こすべきウエイトキューを指示することだけです。

<!-- 
<sect1>Kernel Timers<p>
 -->
<sect1>カーネルタイマ<p>

<!-- 
Now let us turn our attention to kernel timers. Kernel timers are used to
dispatch execution of a particular function (called 'timer handler') at a 
specified time in the future. The main data structure is <tt>struct timer_list</tt>
declared in <tt>include/linux/timer.h</tt>:
 -->
さて、次はカーネルタイマに注目しましょう。カーネルタイマとは、将来の特定の時刻に、特定の関数(「タイマーハンドラ」と呼ばれる)の実行を行わせるためにあるものです。
主なデータ構造体は、<tt>struct timer_list</tt>であり、<tt>include/linux/timer.h</tt>で定義されています。

<tscreen><code>
struct timer_list {
        struct list_head list;
        unsigned long expires;
        unsigned long data;
        void (*function)(unsigned long);
        volatile int running;
};
</code></tscreen>

<!-- 
The <tt>list</tt> field is for linking into the internal list, protected by the
<tt>timerlist_lock</tt> spinlock. The <tt>expires</tt> field is the value of <tt>jiffies</tt> when
the <tt>function</tt> handler should be invoked with <tt>data</tt> passed as a parameter.
The <tt>running</tt> field is used on SMP to test if the timer handler is currently
 running on another CPU.
 -->
<tt>list</tt>フィールドは内部のリストへとリンクするためのもので、<tt>timerlist_lock</tt>スピンロックにより保護されています。<tt>expires</tt>フィールドは、<tt>function</tt>ハンドラが<tt>data</tt>をパラメータとして渡され起動されるときの<tt>jiffies</tt>の値です。<tt>running</tt>フィールドは、タイマハンドラが現在他の CPU で動作しているかテストするために SMP において用いられます。

<!-- 
The functions <tt>add_timer()</tt> and <tt>del_timer()</tt> add and remove a given timer to the
list. When a timer expires, it is removed automatically. Before a timer is
used, it MUST be initialised by means of <tt>init_timer()</tt> function. And before it
is added, the fields <tt>function</tt> and <tt>expires</tt> must be set.
 -->
関数<tt>add_timer()</tt>と、<tt>del_timer()</tt>は、与えられたタイマのリストへの追加ならびに削除を行います。タイマの時間が終了すると、自動的に削除されます。タイマが使われる前に、必ず<tt>init_timer()</tt>関数によって初期化しなければなりません。そして、追加前に<tt>function</tt>と<tt>expires</tt>フィールドを必ず設定しなければなりません。

<!-- 
<sect1>Bottom Halves<p>
 -->
<sect1>ボトムハーフ<p>

<!-- 
Sometimes it is reasonable to split the amount of work to be performed inside
an interrupt handler into immediate work (e.g. acknowledging the interrupt,
updating the stats etc.) and work which can be postponed until later, when
interrupts are enabled (e.g. to do some postprocessing on data, wake up
processes waiting for this data, etc).
 -->
割り込みハンドラが実行する仕事を、すぐに行う(例えば、割り込みへの反応、状態の更新などの)仕事と、割り込みが有効(データの後処理)になってから、後で処理すれば良いもの(データの後処理の実施や、データを待っているプロセスを起こすなど)との2つに分けるのが理にかなっていることが、時々あります。

<!-- 
Bottom halves are the oldest mechanism for deferred execution of kernel
tasks and have been available since Linux 1.x. In Linux 2.0, a new mechanism
was added, called 'task queues', which will be the subject of next section.
 -->
ボトムハーフは、カーネルタスクの実行を延期する最も古い機構で、Linux 1.xのときからあります。Linux 2.0になって、次の章で取り扱う「タスクキュー」という新しい機構が導入されました。

<!-- 
Bottom halves are serialised by the <tt>global_bh_lock</tt> spinlock, i.e.
there can only be one bottom half running on any CPU at a time. However,
when attempting to execute the handler, if <tt>global_bh_lock</tt> is not available,
the bottom half is marked (i.e. scheduled) for execution - so processing can
continue, as opposed to a busy loop on <tt>global_bh_lock</tt>.
 -->
ボトムハーフは<tt>global_bh_lock</tt>スピンロックによってシリアライズされます。つまり一度にいずれかのCPUで実行できるのは、ただ一つのボトムハーフのみであるということです。ハンドラを実行しようとするとき、<tt>global_bh_lock</tt>が有効でなければ、ボトムハーフは実行の印をつけられ(つまりスケジュールされ)ます。そして、<tt>global_bh_lock</tt>でビジーループすることを避けるため処理は継続されます。

<!-- 
There can only be 32 bottom halves registered in total. 
The functions required to manipulate bottom halves are as follows (all
exported to modules):
 -->
現在、全部で32のボトムハーフだけが登録されています。ボトムハーフを操作するために必要となる関数は、以下のようになります(すべてモジュール化されています)。

<itemize>
<!-- 
<item> <tt>void init_bh(int nr, void (*routine)(void))</tt>: installs a bottom half
       handler pointed to by <tt>routine</tt> argument into slot <tt>nr</tt>. The slot
       ought to be enumerated in <tt>include/linux/interrupt.h</tt> in the form
       <tt>XXXX_BH</tt>, e.g. <tt>TIMER_BH</tt> or <tt>TQUEUE_BH</tt>. Typically, a subsystem's
       initialisation routine (<tt>init_module()</tt> for modules) installs the
       required bottom half using this function.
 -->
<item><tt>void init_bh(int nr, void (*routine)(void))</tt>: <tt>routine</tt>で指示されるボトムハーフハンドラをスロット<tt>nr</tt>へ導入する。スロットは<tt>include/linux/interrupt.h</tt>に、<tt>XXXX_BH</tt>の形で(例えば、<tt>TIMER_BH</tt>や<tt>TQUEUE_BH</tt>のように)列挙されていなければならない。通常、サブシステムの初期化ルーチン(モジュールの場合には<tt>init_module()</tt>)は、この関数を使って必要なボトムハーフを導入する。

<!-- 
<item> <tt>void remove_bh(int nr)</tt>: does the opposite of <tt>init_bh()</tt>, i.e.
       de-installs bottom half installed at slot <tt>nr</tt>. There is no error
       checking performed there, so, for example <tt>remove_bh(32)</tt> will
       panic/oops the system. Typically, a subsystem's cleanup routine
       (<tt>cleanup_module()</tt> for modules) uses this function to free up the slot
       that can later be reused by some other subsystem. (TODO: wouldn't it
       be nice to have <tt>/proc/bottom_halves</tt> list all registered bottom
       halves on the system? That means <tt>global_bh_lock</tt> must be made
       read/write, obviously)
 -->
<item><tt>void remove_bh(int nr)</tt>: <tt>init_bf()</tt>の逆を実行する。つまり、スロット<tt>nr</tt>に導入されたボトムハーフを削除する。ここではエラーチェックは行われない。そのため、例えば、<tt>remove_bh(32)</tt>はシステムがpanicまたはoopsになる。通常、サブシステムのクリーンアップルーチンは(モジュールの場合、<tt>cleanup_module()</tt>)、他のサブシステムが後で再利用できるよう、この関数をスロットを解放するために使用する。(TODO: システムの全ての登録されたボトムハーフが、<tt>/proc/bottom_halves</tt>にリストアップされたらどうだろう? これは、<tt>blobal_bh_lock</tt>が明示的に読み書きされなければならないということを意味する)</item>

<!-- 
<item> <tt>void mark_bh(int nr)</tt>: marks bottom half in slot <tt>nr</tt> for execution. Typically,
       an interrupt handler will mark its bottom half (hence the name!) for
       execution at a "safer time".
 -->
<item><tt>void mark_bh(int nr)</tt>: スロット<tt>nr</tt>のボトムハーフに実行の印をつける。通常、割り込みハンドラはそのボトムハーフ(この名前がついた由来!)に「安全な時刻」に実行するよう印をつける。
</itemize>

<!-- 
Bottom halves are globally locked tasklets, so the question "when are bottom
half handlers executed?" is really "when are tasklets executed?". And the
answer is, in two places: a) on each <tt>schedule()</tt> and b) on each
interrupt/syscall return path in <tt>entry.S</tt> (TODO: therefore, the <tt>schedule()</tt>
case is really boring - it like adding yet another very very slow interrupt,
why not get rid of <tt>handle_softirq</tt> label from <tt>schedule()</tt> altogether?).
 -->
ボトムハーフは、グローバルロックされたタスクレットです。そこで「ボトムハンドラはいつ実行されるのか？」という質問は、本当は「タスクレットはいつ実行されるのか?」というのが本当なのです。答えは、a) 各<tt>schedule()</tt>と b)<tt>entry.S</tt>の各割り込み/システムコールのリターンパスの二カ所です。(TODO: そのため、<tt>schedule()</tt>の場合は本当に遅いのです。もう一つの非常に遅い遅い割り込みを追加したようなものです。なぜ、<tt>schedule()</tt>から<tt>handle_softirq</tt>ラベルを完全に取り除かなかったのか?)

<!-- 
<sect1>Task Queues<p>
 -->
<sect1>タスクキュー<p>

<!-- 
Task queues can be though of as a dynamic extension to old bottom halves. In
fact, in the source code they are sometimes referred to as "new" bottom
halves. More specifically, the old bottom halves discussed in previous
section have these limitations:
 -->
タスクキューは古いボトムハーフのダイナミックな拡張として考えられます。実際のところ、ソースコードでは、「新しい」ボトムハーフとして参照されているところもあります。より具体的には、前章で取り上げた古いボトムハーフには、次に示すような制限があります。

<enum>
<!-- 
<item> There are only a fixed number (32) of them.
 -->
<item>決められた数(32)しか存在できません。</item>
<!-- 
<item> Each bottom half can only be associated with one handler function.
 -->
<item>各ボトムハーフは一つのハンドラ関数としか関連づけられません。</item>

<!-- 
<item> Bottom halves are consumed with a spinlock held so they cannot block.
 -->
<item>ボトムハーフは、ブロック出来ないように、持っているスピンロックが消費されます。
</enum>

<!-- 
So, with task queues, arbitrary number of functions can be chained and
processed one after another at a later time. One creates a new task queue
using the <tt>DECLARE_TASK_QUEUE()</tt> macro and queues a task onto it using
the <tt>queue_task()</tt> function. The task queue then can be processed using
<tt>run_task_queue()</tt>. Instead of creating your own task queue (and
having to consume it manually) you can use one of Linux' predefined
task queues which are consumed at well-known points:
 -->
そこで、タスクキューにより任意の数の関数をつなぎ、後で次々と処理ができるようにします。 <tt>DECLARE_TASK_QUEUE</tt> マクロを使って新しいタスクキューを作成すると、<tt>queue_task()</tt>関数を使って、そのキューへとタスクをためることができます。そして、タスクキューは<tt>run_task_queue</tt>によって処理されます。自身のタスクキューを作成する代りに(そして、手動で消費する代りに）、Linux にあらかじめ準備された、良く知られた個所で消費されるタスクキューを使うことができます。

<enum>
<!-- 
<item> <bf>tq_timer</bf>: the timer task queue, run on each timer interrupt
    and when releasing a tty device (closing or releasing a half-opened
    terminal device). Since the timer handler runs in interrupt context,
    the <tt>tq_timer</tt> tasks also run in interrupt context and thus cannot block.
 -->
<item><bf>tq_timer</bf>: タイマのタスクキュー。各タイマ割り込み毎と tty デバイスを解放するとき(半オープン状態のターミナルデバイスをクローズないしは解放する時)に実行する。タイマハンドラが割り込みコンテキストで実行されたときは、<tt>tq_timer</tt>タスクも割り込みコンテキスト内で実行されるため、ブロックできない。
</item>
<!-- 
<item> <bf>tq_scheduler</bf>: the scheduler task queue, consumed by the scheduler (and also
    when closing tty devices, like <tt>tq_timer</tt>). Since the scheduler executed
    in the context of the process being re-scheduled, the <tt>tq_scheduler</tt>
    tasks can do anything they like, i.e. block, use process context data
    (but why would they want to), etc.
 -->
<item><bf>tq_scheduler</bf>: スケジューラによって(<tt>tq_timer</tt> 同様 tty を閉じるときも)消費されるスケジューラタスクキュー。スケジューラが再スケジュールされるプロセスのコンテキストで実行されるため、<tt>tq_scheduler</tt> タスクはやりたいことが何でもできる。つまり、ブロックしてプロセスのコンテキストのデータを使用する(やりたいかどうかは別として)などである。

<!-- 
<item> <bf>tq_immediate</bf>: this is really a bottom half <tt>IMMEDIATE_BH</tt>, so
    drivers can <tt>queue_task(task, &amp;tq_immediate)</tt> and then
    <tt>mark_bh(IMMEDIATE_BH)</tt> to be consumed in interrupt context.
 -->
<item><bf>tq_immediate</bf>: これは本当はボトムハーフ<tt>IMMEDIATE_BH</tt>であり、そのためドライバは<tt>queue_task(task, &amp;tq_immediate)</tt> と、そして割り込みコンテキストで消費される<tt>mark_bh(IMMEDIATE_BH)</tt>を行う。</item>

<!-- 
<item> <bf>tq_disk</bf>: used by low level block device access (and RAID) to start
    the actual requests. This task queue is exported to modules but shouldn't
    be used except for the special purposes which it was designed for.
 -->
<item><bf>tq_disk</bf>: 実際の要求を開始するため、低レベルブロックデバイスのアクセス(とRAID)により使われる。このタスクキューはモジュールにエキスポートされるが、設計上の特定の目的を除いて使われない。</item>
</enum>

<!-- 
Unless a driver uses its own task queues, it does not need to call
<tt>run_tasks_queues()</tt> to process the queue, except under circumstances explained
below.
 -->
ドライバが自身のタスクキューを使わないかぎり、以下の場合を除いて、キューを処理するために<tt>run_tasks_queue()</tt>を呼ぶ必要はありません。

<!-- 
The reason <tt>tq_timer/tq_scheduler</tt> task queues are consumed not only in the
usual places but elsewhere (closing tty device is but one example) becomes
clear if one remembers that the driver can schedule tasks on the queue, and these tasks 
only make sense while a particular instance of the device is still valid
- which usually means until the application closes it. So, the driver may
need to call <tt>run_task_queue()</tt> to flush the tasks it (and anyone else) has
put on the queue, because allowing them to run at a later time may make no
sense - i.e. the relevant data structures may have been freed/reused by a
different instance. This is the reason you see <tt>run_task_queue()</tt> on <tt>tq_timer</tt>
and <tt>tq_scheduler</tt> in places other than timer interrupt and <tt>schedule()</tt>
respectively.
 -->

タスクキュー<tt>tq_timer/tq_scheduler</tt> を消費するのが通常の場所だけでなく外の場所(一例としては、ttyデバイスのクローズ)でも行われる理由は、ドライバがキューにタスクをスケジュールしたとき、そのタスクが意味を持つのはデバイスの特定のインスタンスが有効であるとき(通常はアプリケーションがクローズするまで)なのを考えると自ずと明らかでしょう。
そのため、ドライバは<tt>run_task_queue</tt>を呼んで、自身や(他のドライバが)キューにいれたタスクをフラッシュする必要があります。これは、後で実行することができるようにすることが無意味だからです。つまり、関連するデータ構造は他のインスタンスにより解放されたり再利用されるということです。
これが、それぞれタイマ割り込みや<tt>schedule()</tt>の代りに<tt>tq_timer</tt>と<tt>tq_scheduler</tt>に<tt>run_task_queue()</tt>がある理由になっています。

<!-- 
<sect1>Tasklets<p>
 -->
<sect1>タスクレット<p>

<!-- 
Not yet, will be in future revision.
 -->
作成中。将来のリビジョンで記述。

<!-- 
<sect1>Softirqs<p>

Not yet, will be in future revision.
 -->
<sect1>ソフト割り込み<p>

作成中。将来のリビジョンで記述。

<!-- 
<sect1>How System Calls Are Implemented on i386 Architecture?<p>

There are two mechanisms under Linux for implementing system calls:
 -->
<sect1>システムコールがi386ではどのように実装されているか?<P>

<!-- 
<itemize>
<item> lcall7/lcall27 call gates;
<item> int 0x80 software interrupt.
</itemize>
 -->
<itemize>
<item> lcall7/lcall27 コールゲート
<item> int 0x80 ソフトウエア割り込み
</itemize>

<!-- 
Native Linux programs use int 0x80 whilst binaries from foreign flavours
of UNIX (Solaris, UnixWare 7 etc.) use the lcall7 mechanism. The name 'lcall7' is
historically misleading because it also covers lcall27 (e.g. Solaris/x86), but
the handler function is called lcall7_func. 
 -->
他のUNIX系OS(Solaris, Unixware 7 など)のバイナリではlcall7メカニズムを使っていますが、ネイティブな Linux プログラムは int 0x80 を使っています。'lcall7'の名前は、歴史的な過ちです。これは、lcall27(例えば Solaris/x86)も使用しているが、ハンドラ関数はlcall7_funcと呼ばれているからです。

<!-- 
When the system boots, the function <tt>arch/i386/kernel/traps.c:trap_init()</tt> is
called which sets up the IDT so that vector 0x80 (of type 15, dpl 3) points to
the address of system_call entry from <tt>arch/i386/kernel/entry.S</tt>.
 -->
システムがブートするとき、IDTを設定する関数 <tt>arch/i386/kernel/traps.c:trap_init()</tt> が呼ばれ、(type 15, dpl 3 の)ベクタ 0x80 を、<tt>arch/i386/kernel/entry.S</tt>のシステムコールエントリアドレスを示すように設定します。

<!-- 
When a userspace application makes a system call, the arguments are passed via registers
and the application executes 'int 0x80' instruction. This causes a trap into
kernel mode and processor jumps to system_call entry point in <tt>entry.S</tt>.
What this does is:
 -->
ユーザ空間のアプリケーションがシステムコールを行う時は、引数をレジスタに入れて、'int 0x80' 命令を実行します。これは、カーネルモードにトラップされ、プロセッサは<tt>entry.S</tt>のシステムコールエントリポイントへとジャンプします。これは、次のようなことを行います。

<enum>
<!-- 
<item> Save registers.
 -->
<item>レジスタを保存する。

<!-- 
<item> Set %ds and %es to KERNEL_DS, so that all data (and extra segment)
       references are made in kernel address space.
 -->
<item>%ds と %es を KERNEL_DS に設定する。そのため、参照する全てのデータ(と外部のセグメント)はカーネルアドレス空間になる。

<!-- 
<item> If the value of %eax is greater than <tt>NR_syscalls</tt> (currently 256),
       fail with <tt>ENOSYS</tt> error.
 -->
<item>もし %eax の値が<tt>NR_syscalls</tt>(現在 256) より大きかった場合には、<tt>ENOSYS</tt> エラーで失敗する。

<!-- 
<item> If the task is being ptraced (<tt>tsk->ptrace & PF_TRACESYS</tt>), do special
       processing. This is to support programs like strace (analogue of
       SVR4 <bf>truss(1)</bf>) or debuggers.
 -->
<item> もしタスクがptraced されていた(<tt>tsk->ptrace & PF_TRADESYS </tt>)時は、特別な処理を行う。これは strace (SVR4でいう<bf>truss(1)</bf>)のようなプログラムやデバッガをサポートするためである。

<!-- 
<item> Call <tt>sys_call_table+4*(syscall_number from %eax)</tt>. This table is
       initialised in the same file (<tt>arch/i386/kernel/entry.S</tt>) to point to
       individual system call handlers which under Linux are (usually)
       prefixed with <tt>sys_</tt>, e.g. <tt>sys_open</tt>, <tt>sys_exit</tt>, etc. These C system
       call handlers will find their arguments on the stack where <tt>SAVE_ALL</tt>
       stored them.
 -->
<item><tt>sys_call_table+4*(%eax の syscall_number)</tt>を呼ぶ。このテーブルは同じファイル(<tt>arch/i386/kernel/entry.S</tt>)で初期化されており、各々のシステムコールハンドラを指している。Linux においては、ハンドラには通常、例えば <tt>sys_open</tt>や<tt>sys_exit</tt>のように <tt>sys_</tt>というプレフィックスがついている。これらの C システムコールハンドラは<tt>SAVE_ALL</tt>が格納したスタックから引数を見つけ出す。

<!-- 
<item> Enter 'system call return path'. This is a separate label because it
       is used not only by int 0x80 but also by lcall7, lcall27. This is
       concerned with handling tasklets (including bottom halves), checking
       if a <tt>schedule()</tt> is needed (<tt>tsk->need_resched != 0</tt>), checking if there
       are signals pending and if so handling them.
 -->
<item>``system call return path''に入る。int 0x80 だけでなく、lcall7, lcall27でも使うため、別のラベルになっている。これは、(ボトムハーフの)タスクレットの取り扱いや、<tt>schedule()</tt>が必要かどうか(<tt>tsk->need_resched != 0</tt>) を確認したり、シグナルが保留されていないか確認したり、そしてそれらのシグナルを処理したりすることに関連している。
</enum>

<!-- 
Linux supports up to 6 arguments for system calls. They are passed in
%ebx, %ecx, %edx, %esi, %edi (and %ebp used temporarily, see <tt>_syscall6()</tt> in
<tt>asm-i386/unistd.h</tt>). The system call number is passed via %eax.
 -->
Linux は システムコールに 6 つまでの引数をサポートしています。これらは %ebx, %ecx, %edx, %esi, %edi (および一時的に使われる %edp。<tt>asm-i386/unistd.h</tt>の<tt>_syscall6()</tt>を参照)に入れて渡されます。システムコール番号は %eax で渡されます。

<!-- 
<sect1>Atomic Operations<p>
 -->
<sect1>アトミックな操作<p>

<!-- 
There are two types of atomic operations: bitmaps and <tt>atomic_t</tt>. Bitmaps are
very convenient for maintaining a concept of "allocated" or "free" units
from some large collection where each unit is identified by some number, for
example free inodes or free blocks. They are also widely used for simple
locking, for example to provide exclusive access to open a device. An example
of this can be found in <tt>arch/i386/kernel/microcode.c</tt>:
  -->
2つのタイプのアトミックな操作があります。ビットマップと<tt>atomic_t</tt> です。ビットマップは、ある大きな集合から「割り当て」や「解放」の単位で、各単位がある番号で指定される、例えばフリー inodeやフリーブロックのようなコンセプトを維持するのにとても便利です。これらは単純なロックに広く使われています。例えばデバイスのオープンを排他的に行えるようにするために使われます。この例は、<tt>arch/i386/kernel/microcode.c</tt>に見ることができます。

<tscreen><code>
/*
 *  Bits in microcode_status. (31 bits of room for future expansion)
 */
#define MICROCODE_IS_OPEN       0       /* set if device is in use */

static unsigned long microcode_status;
</code></tscreen>

<!-- 
There is no need to initialise <tt>microcode_status</tt> to 0 as BSS is zero-cleared
under Linux explicitly. 
 -->
BSSを Linux で明示的にゼロクリーンするように <tt>microcode_status</tt> を0に初期化する必要はありません。

<tscreen><code>
/*
 * We enforce only one user at a time here with open/close.
 */
static int microcode_open(struct inode *inode, struct file *file)
{
        if (!capable(CAP_SYS_RAWIO))
                return -EPERM;

        /* one at a time, please */
        if (test_and_set_bit(MICROCODE_IS_OPEN, &amp;microcode_status))
                return -EBUSY;

        MOD_INC_USE_COUNT;
        return 0;
}
</code></tscreen>

<!-- 
The operations on bitmaps are:
 -->
ビットマップの操作は、

<itemize>
<!-- 
<item> <bf>void set_bit(int nr, volatile void *addr)</bf>: set bit <tt>nr</tt>
       in the bitmap pointed to by <tt>addr</tt>.
 -->
<item><bf>void set_bit(int nr, volatile void *addr)</bf>: <tt>addr</tt>で示されるビットマップの<tt>nr</tt>のビットをセットする。

</item>
<!-- 
<item> <bf>void clear_bit(int nr, volatile void *addr)</bf>: clear bit
       <tt>nr</tt> in the bitmap pointed to by <tt>addr</tt>.
 -->
<item><bf>void clear_bit(int nr, volatile void *addr)</bf>: <tt>addr</tt>で示されるビットマップの<tt>nr</tt>ビットをクリアする。

</item>
<!-- 
<item> <bf>void change_bit(int nr, volatile void *addr)</bf>: toggle bit
       <tt>nr</tt> (if set clear, if clear set) in the bitmap pointed to by <tt>addr</tt>.
 -->
<item><bf>void change_bit(int nr, volati.e void *addr)</bf>: <tt>addr</tt>で示されるビットマップの<tt>nr</tt>ビットを反転(クリアされていればセット、セットされていればクリア)する。

</item>
<!-- 
<item> <bf>int test_and_set_bit(int nr, volatile void *addr)</bf>:
       atomically set bit <tt>nr</tt> and return the old bit value.
 -->
<item><bf>int test_and_set_bit(int nr, volatile void *addr)</bf>: アトミックに<tt>nr</tt>ビットをセットし、古いビットの値を返す。

</item>
<!-- 
<item> <bf>int test_and_clear_bit(int nr, volatile void *addr)</bf>:
       atomically clear bit <tt>nr</tt> and return the old bit value.
 -->
<item><bf>int test_and_clear_bit(int nr, volatile void *addr)</bf>: アトミックに<tt>nr</tt>ビットをクリアし、古いビットの値を返す。


<!-- 
<item> <bf>int test_and_change_bit(int nr, volatile void *addr)</bf>:
       atomically toggle bit <tt>nr</tt> and return the old bit value.
 -->
<item><bf>int test_and_change_bit(int nr, volatile void *addr)</bf>: アトミックに<tt>nr</tt>ビットを反転し、古いビットの値を返す。


</itemize>

<!-- 
These operations use the <tt>LOCK_PREFIX</tt> macro, which on SMP kernels evaluates to
bus lock instruction prefix and to nothing on UP. This guarantees atomicity
of access in SMP environment.
 -->
これらの操作は、<tt>LOCK_PREFIX</tt> マクロを使っています。このマクロは SMP カーネルにおいてバスのロック操作を行う接頭辞として評価されますが、UP カーネルでは何もしません。これによって、SMP 環境でのアトミックなアクセスを保証しています。

<!-- 
Sometimes bit manipulations are not convenient, but instead we need to perform
arithmetic operations - add, subtract, increment decrement. The typical cases
are reference counts (e.g. for inodes). This facility is provided by the
<tt>atomic_t</tt> data type and the following operations:
 -->
ときにはビット操作が不便な場面もありますが、その場合は算術演算を使う必要があります。加算、減算、インクリメント、デクリメントなどです。(inode のような)参照カウンタが典型的な例です。この機能は<tt>atmic_t</tt>データタイプと以下の操作で実現されています

<itemize>
<!-- 
<item> <bf>atomic_read(&amp;v)</bf>: read the value of <tt>atomic_t</tt> variable <tt>v</tt>.
 -->
<item> <bf>atomic_read(&amp;v)</bf>: <tt>atomic_t</tt>変数<tt>t</tt>の値を読み込む。

<!-- 
<item> <bf>atomic_set(&amp;v, i)</bf>: set the value of <tt>atomic_t</tt> variable
        <tt>v</tt> to integer <tt>i</tt>.
 -->
<item> <bf>atomic_set(&amp;v, i)</bf>: <tt>atomic_t</tt> 変数 <tt>v</tt> を整数値 <tt>i</tt> に設定する。

<!-- 
<item> <bf>void atomic_add(int i, volatile atomic_t *v)</bf>: add integer
       <tt>i</tt> to the value of atomic variable pointed to by <tt>v</tt>.
 -->
<item> <bf>void atomic_add(int i, volatile atomic_t *v)</bf>: 整数値<tt>i</tt> を<tt>v</tt> で示されるアトミック変数の値に加算する。

<!-- 
<item> <bf>void atomic_sub(int i, volatile atomic_t *v)</bf>: subtract
       integer <tt>i</tt> from the value of atomic variable pointed to by <tt>v</tt>.
 -->
<item> <bf>void atomic_sub(int i, volatile atomic_t *v)</bf>: 整数値<tt>i</tt> を<tt>v</tt> で示されるアトミック変数の値から減算する。

<!-- 
<item> <bf>int atomic_sub_and_test(int i, volatile atomic_t *v)</bf>:
       subtract integer <tt>i</tt> from the value of atomic variable pointed to by
       <tt>v</tt>; return 1 if the new value is 0, return 0 otherwise.
 -->
<item> <bf>int atomic_sub_and_test(int i, volatile atomic_t *v)</bf>: 整数値<tt>i</tt> を<tt>v</tt> で示されるアトミック変数の値から減算し、その結果が0のときは 1 を返し、それ以外では 0 を返す。

<!-- 
<item> <bf>void atomic_inc(volatile atomic_t *v)</bf>: increment the value
       by 1.
 -->
<item> <bf>void atomic_inc(volatile atomic_t *v)</bf>: 値を 1 インクリメントする。

<!-- 
<item> <bf>void atomic_dec(volatile atomic_t *v)</bf>: decrement the value
       by 1.
 -->
<item> <bf>void atomic_dec(volatile atomic_t *v)</bf>: 値を 1 デクリメントする。 

<!-- 
<item> <bf>int atomic_dec_and_test(volatile atomic_t *v)</bf>: decrement
       the value; return 1 if the new value is 0, return 0 otherwise.
 -->
<item> <bf>int atomic_dec_and_test(volatile atomic_t *v)</bf>: 値をデクリメントする。そして、結果が0なら1を返し、それ以外なら0を返す。

<!-- 
<item> <bf>int atomic_inc_and_test(volatile atomic_t *v)</bf>: increment
       the value; return 1 if the new value is 0, return 0 otherwise.
 -->
<item> <bf>int atomic_inc_and_test(volatile atomic_t *v)</bf>: 値をインクリメントする。そして、結果が0なら1を返し、それ以外なら0を返す。

<!-- 
<item> <bf>int atomic_add_negative(int i, volatile atomic_t *v)</bf>: add
       the value of <tt>i</tt> to <tt>v</tt> and return 1 if the result is negative. Return
       0 if the result is greater than or equal to 0. This operation is used
       for implementing semaphores.
 -->
<item> <bf>int atomic_add_negative(int i, volatile atomic_t *v)</bf>: <tt>i</tt> を<tt>v</tt>の値に加算する。そして、結果が負数ならば1を返し、結果が0以上であれば0を返す。この操作はセマフォの実装に用いられている。
</itemize>

<!-- 
<sect1>Spinlocks, Read-write Spinlocks and Big-Reader Spinlocks<p>
 -->
<sect1>スピンロック、読み書きスピンロック、ビッグリーダースピンロック<p>

<!-- 
Since the early days of Linux support (early 90s, this century),
developers were faced with the classical problem of accessing shared data
between different types of context (user process vs
interrupt) and different instances of the same context from multiple cpus.
 -->
初期の Linux (前世紀 90 年代の初頭)から、開発者は、異なる型のコンテキストの間や、複数の CPU における同じ型のコンテキストであるが違ったインスタンス間での共有データのアクセスに関する古典的問題に直面していました。

 <!-- 
 SMP support was added to Linux 1.3.42 on 15 Nov 1995 (the original patch
 was made to 1.3.37 in October the same year).
  -->
 1995 年 11 月 15 日に、SMP サポート(オリジナルのパッチは 同年 10 月の 1.3.37 に対するものでした)が Linux 1.3.42 で追加されました。

 <!-- 
 If the critical region of code may be executed by either process context
 and interrupt context, then the way to protect it using <tt>cli/sti</tt> instructions
 on UP is:
   -->
コードのクリティカル領域がプロセスコンテキストと割り込みコンテキストの両方で実行されることも考えられるので、UPで<tt>cli/sti</tt>命令を使って保護する方法は、

<tscreen><code>
unsigned long flags;

save_flags(flags);
cli();
/* critical code */
restore_flags(flags);
</code></tscreen>

のようになります。

<!-- 
While this is ok on UP, it obviously is of no use on SMP because the same
code sequence may be executed simultaneously on another cpu, and while <tt>cli()</tt>
provides protection against races with interrupt context on each CPU individually, it
provides no protection at all against races between contexts running on different
CPUs. This is where spinlocks are useful for.
 -->
これが UP でOKだとしても、 SMP では明らかに意味がありません。同じコードシーケンスが他の CPU で同時に実行されるかも知れないからです。そして、<tt>cli()</tt>は個々の CPU 上での割り込みコンテキストの競合からの保護しか提供しないため、異なった CPU で実行されるコンテキスト間の競合からの保護には全くならないのです。これでスピンロックが有用になります。

<!-- 
There are three types of spinlocks: vanilla (basic), read-write and
big-reader spinlocks. Read-write spinlocks should be used when there is a
natural tendency of 'many readers and few writers'. Example of this is
access to the list of registered filesystems (see <tt>fs/super.c</tt>). The list is
guarded by the <tt>file_systems_lock</tt> read-write spinlock because one needs exclusive
access only when registering/unregistering a filesystem, but any process can
read the file <tt>/proc/filesystems</tt> or use the <bf>sysfs(2)</bf> system call to force a
read-only scan of the file_systems list. This makes it sensible to use
read-write spinlocks. With read-write spinlocks, one can have multiple
readers at a time but only one writer and there can be no readers while
there is
a writer. Btw, it would be nice if new readers would not get a lock while
there
is a writer trying to get a lock, i.e. if Linux could correctly deal with
the issue of potential writer starvation by multiple readers. 
This would mean that readers must be blocked while there is a writer
attempting to get the lock. This is not
currently the case and it is not obvious whether this should be fixed - the
argument to the contrary is - readers usually take the lock for a very short
time so should they really be starved while the writer takes the lock for
potentially longer periods?
 -->
3 つのタイプのスピンロックがあります。バニラ(基本)、読み書き、ビッグリーダー スピンロックです。読み書きスピンロックは「読む者が多くて書く者が少ない」よくある傾向の場合に用いられます。この例としては、登録されたファイルシステムのリスト(<tt>fs/super.c</tt>参照)へのアクセスがあります。
リストは、<tt>file_systems_lock</tt>読み書きスピンロックにより保護され、ファイルシステムの登録/解除の際にだけ排他的なアクセスを行います。しかし、全てのプロセスは<tt>/proc/filesystems</tt>を読めますし、<bf>sysfs(2)</bf>システムコールを使って、ファイルシステムの読み取り専用アクセスを行うことができるのです。このことが、読み書きスピンロックを使う際に気をつかう点になっています。読み書きスピンロックによって、同時に複数の読み取りができるか、単一の書き込みがあって、他の読み取りができない状況かになります。とはいうものの、書き込み者がロックを取得しようとしている間、新しい読み取り者がロックを取得できないなら、つまり複数の読み取り者による書き込み者の飢餓問題について、Linux が正しく処理しているなら、これは良いことだといえます。書き取り者がロックを取得しようとしている間は、読み取り者がブロックされなければならないという事を意味しています。

これは現在のところ問題ではなく、修正しなければならないことかどうかも明らかではありません。
逆にいうと、読み取り者は常に非常に短い時間だけのロックを取得していれば、
書き込み者が比較的長い時間間隔でロックを取得している間に本当に枯渇してしまう
ことがあるのか? ということです。

<!-- 
Big-reader spinlocks are a form of read-write spinlocks
heavily optimised for very light read access, with a penalty for writes.
There is a limited number of big-reader spinlocks - currently only two exist,
of which one is used only on sparc64 (global irq) and the other is used for
networking. In all other cases where the access pattern does not fit into
any of these two scenarios, one should use basic spinlocks. You cannot block
while holding any kind of spinlock.
 -->
ビッグリーダスピンロックは、読み書きスピンロックに、非常に軽い読込みアクセスへ強く最適化をかけたもので、書き込みアクセスにはペナルティを課しています。ビッグリーダスピンロックは限られた範囲、現在は2個所だけで使われています。一つは sparc64 (global irq) でのみ使われ、もう一つはネットワークスタックです。アクセスパターンがこの2つの型のどちらにも当てはまらない場合では、基本スピンロックを使っています。どの種類のスピンロックを保持している場合でもブロックすることはできません。

<!-- 
Spinlocks come in three flavours: plain, <tt>_irq()</tt> and <tt>_bh()</tt>.
 -->
プレーン、<tt>_irq()</tt>、<tt>_bh()</tt>と、スピンロックには3種類あります。

<enum>
<!-- 
<item> Plain <tt>spin_lock()/spin_unlock()</tt>: if you know the interrupts are always
       disabled or if you do not race with interrupt context (e.g. from
       within interrupt handler), then you can use this one. It does not
       touch interrupt state on the current CPU.
 -->
<item> プレーン<tt>spin_lock()/spin_unlock()</tt>: 割り込みが常に不可にされるか、割り込みコンテキストと競合しないことが分かっている(例えば割り込みハンドラ内部で)なら、これを使うことができる。現在の CPU の割り込み状態には触れることがない。

<!-- 
<item> <tt>spin_lock_irq()/spin_unlock_irq()</tt>: if you know that interrupts are
       always enabled then you can use this version, which simply disables 
       (on lock) and re-enables (on unlock) interrupts on the current CPU.
       For example, <tt>rtc_read()</tt> uses
       <tt>spin_lock_irq(&amp;rtc_lock)</tt> (interrupts are always enabled inside
       <tt>read()</tt>) whilst <tt>rtc_interrupt()</tt> uses
       <tt>spin_lock(&amp;rtc_lock)</tt> (interrupts are always disabled inside 
       interrupt handler). Note that <tt>rtc_read()</tt> uses <tt>spin_lock_irq()</tt> and not
       the more generic <tt>spin_lock_irqsave()</tt> because on entry to any system
       call interrupts are always enabled.
 -->
<item> <tt>spin_lock_irq()/spin_unlock_irq()</tt>: もし割り込みが常に有効ならこのバージョンのスピンロックを使うことができる。これは単純に現在の CPU の割り込みを(ロック時に)無効にし、(アンロック時に）再度有効にする。
たとえば、<tt>rtc_interrupt()</tt>が<tt>spin_lock(&amp;rtc_lock)</tt>(割り込みは割り込みハンドラの中では常に無効)を使うため、<tt>rtc_read()</tt>は<tt>spin_lock_irq(&amp;rtc_lock)</tt>(read中割り込みは常に有効）を使っている。<tt>rtc_read()</tt>が<tt>spin_lock_irq()</tt>を使い、より汎用的な<tt>spin_lock_irqsave()</tt>を使わないのは、全てのシステムコール割り込みが常に有効になっているからである。

<!-- 
<item> <tt>spin_lock_irqsave()/spin_unlock_irqrestore()</tt>: the strongest form,
       to be used when the interrupt state is not known, but only if
       interrupts matter at all, i.e. there is no point in using it if
       our interrupt handlers don't execute any critical code.
 -->
<item> <tt>spin_lock_irqsave()/spin_unlock_irqrestore()</tt>: 割り込み状況が分からないときに使う、最強の形式。割り込みが問題になる場合だけでなく、割り込みが全く不明な場合にも使われる。
つまり、割り込みハンドラがクリティカルコードを実行しない場合には、これを使うポイントはないということだ。
</enum>

<!-- 
The reason you cannot use plain <tt>spin_lock()</tt> if you race against interrupt handlers is because if you take it and then
an interrupt comes in on the same CPU, it will busy wait for the lock forever:
the lock holder, having been interrupted, will not continue until the
interrupt handler returns.
 -->
もし割り込みハンドラが競合するならば、素の<tt>spin_lock()</tt>を使えません。
これを使ったときに、割り込みが同じCPU上で発生すると、永遠にロックを待ちつづけるためです。
割り込まれているロックを取得したハンドラは、割り込みハンドラから処理が返ってくるまで、
処理を継続できないためです。

<!-- 
The most common usage of a spinlock is to access a data structure shared
between user process context and interrupt handlers:
 -->
ユーザプロセスのコンテキストと割り込みハンドラとで共有するデータ構造体にアクセスするときには、スピンロックがもっとも良く使われています。

<tscreen><code>
spinlock_t my_lock = SPIN_LOCK_UNLOCKED;

my_ioctl()
{
	spin_lock_irq(&amp;my_lock);
	/* critical section */
	spin_unlock_irq(&amp;my_lock);
}

my_irq_handler()
{
	spin_lock(&amp;lock);
	/* critical section */
	spin_unlock(&amp;lock);
}
</code></tscreen>

<!-- 
There are a couple of things to note about this example:
 -->
この例については、いくつか注記があります。

<!-- 
<enum>
<item> The process context, represented here as a typical driver method -
       <tt>ioctl()</tt> (arguments and return values omitted for clarity), must
       use <tt>spin_lock_irq()</tt> because it knows that interrupts are always
       enabled while executing the device <tt>ioctl()</tt> method.

<item> Interrupt context, represented here by <tt>my_irq_handler()</tt> (again
       arguments omitted for clarity) can use plain <tt>spin_lock()</tt> form because
       interrupts are disabled inside an interrupt handler.
</enum>
 -->
<enum>
<item> 典型的なドライバがとる方法の(属性値と返り値が明確に省略されている)<tt>ioctl()</tt>
によるプロセスのコンテキストでは、必ず<tt>spin_lock_irq()</tt>を使わなければならない。
これは、デバイスの<tt>ioctl()</tt>呼び出しを実行している間は、割り込みが常に有効になっているためである。


<item> (属性値は明確に省略されている)<tt>my_irq_handler()</tt>によって表される割り込みコンテキスト
では、plain <tt>spin_lock()</tt> form を使うことができる。これは、割り込みハンドラ内部では、割り込みは無効にされているためである。

</enum>

<!-- 
<sect1>Semaphores and read/write Semaphores<p>
 -->
<sect1>セマフォと読み書きセマフォ<p>

<!-- 
Sometimes, while accessing a shared data structure, one must perform operations
that can block, for example copy data to userspace. The locking primitive
available for such scenarios under Linux is called a semaphore. There are two
types of semaphores: basic and read-write semaphores. Depending on the
initial value of the semaphore, they can be used for either mutual exclusion
(initial value of 1) or to provide more sophisticated type of access.
 -->
時折、共有データ構造体にアクセスするときに、操作の実行をブロックしなければならないことが
あります。たとえばデータをユーザ空間へコピーする場合などです。Linux におけるこのような場合に
使用できるロックの基本機構としてセマフォと呼ばれるものがあります。
セマフォには2つのタイプがあり、基本セマフォと読み書きセマフォと呼んでいます。
セマフォの初期値により、交互実行(初期値1)にも、より複雑なアクセスのタイプを提供するためにも
使うことができます。

<!-- 
Read-write semaphores differ from basic semaphores in the same way as
read-write spinlocks differ from basic spinlocks: one can have multiple
readers at a time but only one writer and there can be no readers while there are
writers - i.e. the writer blocks all readers and new readers block while a
writer is waiting.
 -->
読み書きセマフォと基本のセマフォとの違いは、読み書きスピンロックと基本のスピンロックの相違と
同様のものになっています。一方が同時に複数の読み手と一つの書き手を許すのに対して、もう一方は
書き込みのある間は読み出しがロックされるものになります。つまり、書き手が全ての読み手をブロックし、書き手が待ち状態にある間、新しい読み手はブロックします。

<!-- 
Also, basic semaphores can be interruptible - just use the operations
<tt>down/up_interruptible()</tt> instead of the plain <tt>down()/up()</tt> and check the
value returned from <tt>down_interruptible()</tt>: it will be non zero if the operation was
interrupted.
 -->
同様に、素の<tt>down()/up()</tt>の代りに<tt>down/up_interruptible()</tt>を使うことと、<tt>down_interruptible()</tt>からの返り値をチェックすることで、基本セマフォは割り込みが可能になります。
もし操作が割り込まれたならば、返り値が0以外になります。

<!-- 
Using semaphores for mutual exclusion is ideal in situations where a critical
code section may call by reference unknown functions registered by other
subsystems/modules, i.e. the caller cannot know apriori whether the function
blocks or not.
 -->
クリティカルコードが他のサブシステムやモジュールから登録される未知の関数から呼び出される状況では、典型的には交互実行にセマフォを使うことになります。
つまり、呼び出し側が先験的に関数がブロックされるかどうか知ることができない場合です。

<!-- 
A simple example of semaphore usage is in <tt>kernel/sys.c</tt>, implementation of
<bf>gethostname(2)/sethostname(2)</bf> system calls.
 -->
セマフォの簡単な例は、<bf>gethostname(2)/sethostname(2)</bf>システムコールを実装した<tt>kernel/sys.c</tt>にあります。

<tscreen><code>
asmlinkage long sys_sethostname(char *name, int len)
{
        int errno;

        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
        if (len < 0 || len > __NEW_UTS_LEN)
                return -EINVAL;
        down_write(&amp;uts_sem);
        errno = -EFAULT;
        if (!copy_from_user(system_utsname.nodename, name, len)) {
                system_utsname.nodename[len] = 0;
                errno = 0;
        }
        up_write(&amp;uts_sem);
        return errno;
}

asmlinkage long sys_gethostname(char *name, int len)
{
        int i, errno;

        if (len < 0)
                return -EINVAL;
        down_read(&amp;uts_sem);
        i = 1 + strlen(system_utsname.nodename);
        if (i > len)
                i = len;
        errno = 0;
        if (copy_to_user(name, system_utsname.nodename, i))
                errno = -EFAULT;
        up_read(&amp;uts_sem);
        return errno;
}
</code></tscreen>

<!-- 
The points to note about this example are:
 -->
この例のポイントは以下の通りです。


<enum>
<!-- 
<item> The functions may block while copying data from/to userspace in
       <tt>copy_from_user()/copy_to_user()</tt>. Therefore they could not use any form
       of spinlock here.

<item> The semaphore type chosen is read-write as opposed to basic because
       there may be lots of concurrent <bf>gethostname(2)</bf> requests which need not
       be mutually exclusive.
 -->
<item> 関数は、<tt>copy_from_user()/copy_to_user()</tt>で、データをユーザスペースから、もしくはユーザスペースへコピーするときにブロックされることがある。
すなわち、ここではいかなるタイプのスピンロックもつかうことはできない。

<item> ベーシックではなく読み書きのセマフォが選ばれているのは
<bf>gethostname(2)</bf>要求が同時にたくさん発生し得るが、それらは交互に実行する必要はない
ためである。

</enum>

<!-- 
Although Linux implementation of semaphores and read-write semaphores is
very sophisticated, there are possible scenarios one can think of which are
not yet implemented, for example there is no concept of interruptible
read-write semaphores. This is obviously because there are no real-world
situations which require these exotic flavours of the primitives.
 -->
Linux のセマフォならびに読み書きセマフォの実装は非常に精巧にできていますが、
まだ実装されていない考え得る可能なシナリオも存在しています。例えば、割り込み可能な
読み書きセマフォのコンセプトなどです。このようなエキゾチックな種類のプリミティブ
が必要になる状況は、実世界でない状況なので、このようなコンセプトは明らかにありえません。

<!-- 
<sect1>Kernel Support for Loading Modules<p>
 -->
<sect1>モジュール読み込みのカーネルサポート<p>

<!-- 
Linux is a monolithic operating system and despite all the modern hype about
some "advantages" offered by operating systems based on micro-kernel design,
the truth remains (quoting Linus Torvalds himself):
 -->
マイクロカーネルデザインに基づくオペレーティングシステムの提供する"アドバンテージ"といった最近の宣伝にも関わらず、Linux はモノリシックなオペレーティングシステムです。
実際、(Linus Torvalds 彼自身の言葉によると)

<tscreen>
... message passing as the fundamental operation of the OS is just an
exercise in computer science masturbation. It may feel good, but you
don't actually get anything DONE.
</tscreen>

<!-- 
Therefore, Linux is and will always be based on a monolithic design, which
means that all subsystems run in the same privileged mode and share the same
address space; communication between them is achieved by the usual C function
call means.
 -->
だから、Linux は ずっとモノリシックデザインをベースとしており、すべてのサブシステムは
同じ特権モードで動き、同じアドレス空間を共有しているのです。カーネル内の通信は
通常の C 関数呼び出しで行われます。

<!-- 
However, although separating kernel functionality into separate "processes"
as is done in micro-kernels is definitely a bad idea, separating it into
dynamically loadable on demand kernel modules is desirable in some
circumstances (e.g. on machines with low memory or for installation kernels
which could otherwise contain ISA auto-probing device drivers that are
mutually exclusive). The decision whether to include support for loadable
modules is made at compile time and is determined by the <tt>CONFIG_MODULES</tt>
option. Support for module autoloading via <tt>request_module()</tt> mechanism is
a separate compilation option (<tt>CONFIG_KMOD</tt>).
 -->
しかし、たとえマイクロカーネルが行うようにカーネルの機能をそれぞれの「プロセス」へと分けることは
明らかに悪い考えですが、オンデマンドで動的に読み込めるカーネルモジュールに分けることは、ある
条件下(例えば、マシンのメモリが少ない場合や、互いに排他的な複数の ISA 自動判別デバイスドライバを持つカーネルをインストールした場合)では、いい考えです。ローダブルモジュールのサポートを組み込むかどうかの判断は、コンパイル時に行われ、<tt>CONFIG_MODULES</tt> オプションによって指定されます。
<tt>request_module()</tt> 機構によるモジュールの自動組み込みのサポートは、別のコンパイルオプション (<tt>CONFIG_KMOD</tt>) になっています。
<!-- 
The following functionality can be implemented as loadable modules under
Linux:
 -->
以下の機能は Linux のロード可能モジュールとして実装されています。

<!-- 

<enum>
<item> Character and block device drivers, including misc device drivers.

<item> Terminal line disciplines.

<item> Virtual (regular) files in <tt>/proc</tt> and in devfs (e.g. <tt>/dev/cpu/microcode</tt>
       vs <tt>/dev/misc/microcode</tt>).

<item> Binary file formats (e.g. ELF, aout, etc).

<item> Execution domains (e.g. Linux, UnixWare7, Solaris, etc).

<item> Filesystems.

<item> System V IPC.
</enum>
 -->
<enum>
<item> キャラクタならびにブロックデバイスドライバ。misc デバイスドライバを含む。

<item> ターミナルライン関係。

<item> <tt>/proc</tt>と devfs における仮想(一般の)ファイル (例えば<tt>/dev/cpu/microcode</tt>や<tt>dev/misc/micrococe</tt>)。

<item> バイナリファイルフォーマット (例えば ELF, aoutなど)。

<item> 実行ドメイン (例えば, Linux, UnixWare7, Solarisなど)。

<item> ファイルシステム。

<item> System V IPC。

</enum>

<!-- 
There a few things that cannot be implemented as modules under Linux
(probably because it makes no sense for them to be modularised):
 -->
一部には Linux におけるモジュールとして実装できていないものもあります。(おそらくそれらは
モジュールについて考慮されていないためと思われます）

<!-- 
<enum>
<item> Scheduling algorithms.

<item> VM policies.

<item> Buffer cache, page cache and other caches.
</enum>
 -->
<enum>
<item> スケジューリングアルゴリズム

<item> VMポリシー

<item> バッファキャッシュ、ページキャッシュやその他のキャッシュ
</enum>

<!-- 
Linux provides several system calls to assist in loading modules:
 -->
Linux にはロード可能モジュールを援助するいろいろなシステムコールがあります。

<!-- 
<enum>
<item><tt>caddr_t create_module(const char *name, size_t size)</tt>: allocates 
      <tt>size</tt> bytes using <tt>vmalloc()</tt> and maps a module structure at the 
      beginning thereof. This new module is then linked into the list headed
      by module_list. Only a process with <tt>CAP_SYS_MODULE</tt> can invoke this
      system call, others will get <tt>EPERM</tt> returned.

<item><tt>long init_module(const char *name, struct module *image)</tt>: loads the
      relocated module image and causes the module's initialisation routine
      to be invoked. Only a process with <tt>CAP_SYS_MODULE</tt> can invoke this
      system call, others will get <tt>EPERM</tt> returned.

<item><tt>long delete_module(const char *name)</tt>: attempts to unload the module.
      If <tt>name == NULL</tt>, attempt is made to unload all unused modules.

<item><tt>long query_module(const char *name, int which, void *buf, 
      size_t bufsize, size_t *ret)</tt>: returns information about a module
      (or about all modules).
</enum>
 -->
<enum>
<item><tt>caddr_t create_module(cost char *name, size_t size)</tt>: <tt>vmalloc()</tt>を用いて<tt>size</tt>バイトを割り当て、モジュールの構造体をその先頭に割り付ける。
新しいモジュールは module_list が先頭にあるリストへとリンクされる。<tt>CAP_SYS_MODULE</tt>のプロセスのみが、このシステムコールを呼び出すことができ、他のプロセスは<tt>EPERM</tt>エラーが返る。

<item> <tt>long init_module(const char *name, struct module *image)</tt>: 再配置されたモジュールイメージを読み込み、モジュールの初期化ルーチンが起動される。<tt>CAP_SYS_MODULE</tt>が設定されたプロセスのみがこのシステムコールを呼び出すことができ、それ以外の場合は<tt>EPERM</tt>エラーが返る。

<item><tt>long delete_module(const char *name)</tt>: モジュールをアンロードしようとする。<tt>name == NULL</tt>ならば、全ての使用されていないモジュールを取り外そうとする。

<item> <tt>long query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret)</tt>: モジュールの(ないしは全てのモジュールの)情報を返す。

</enum>

<!-- 
The command interface available to users consists of:
 -->
ユーザが使えるコマンドインターフェースは次の通りです。

<!-- 
<itemize>
<item><bf>insmod</bf>: insert a single module.

<item><bf>modprobe</bf>: insert a module including all other modules it depends
      on.
	  
<item><bf>rmmod</bf>: remove a module.

<item><bf>modinfo</bf>: print some information about a module, e.g. author, 
      description, parameters the module accepts, etc.
</itemize>
 -->
<itemize>
<item> <bf>insmod</bf>: 一つのモジュールを挿入する。

<item><bf>modprobe</bf>: モジュールをその依存する全てのモジュールとともに挿入する。
 
<item><bf>rmmod</bf>: モジュールを取り外します。

<item><bf>modinfo</bf> : モジュールについての情報を表示する。例えば、作者、内容、モジュールの受け取れるパラメータ など。

</itemize>

<!-- 
Apart from being able to load a module manually using either <bf>insmod</bf> or <bf>modprobe</bf>,
it is also possible to have the module inserted automatically by the kernel
when a particular functionality is required. The kernel interface for this
is the function called <tt>request_module(name)</tt> which is exported to modules,
so that modules can load other modules as well. The <tt>request_module(name)</tt>
internally creates a kernel thread which execs the userspace command
<bf>modprobe -s -k module_name</bf>, using the standard <tt>exec_usermodehelper()</tt> kernel
interface (which is also exported to modules). The function returns 0 on
success, however it is usually not worth checking the return code from
<tt>request_module()</tt>. Instead, the programming idiom is:
 -->
<bf>insmod</bf>や<bf>modprobe</bf>を使ってモジュールを手動で読み込むことができるのは当然ですが、
特定の機能が必要になったときに、カーネルが自動的にモジュールを読む機能もあります。
この機能のカーネルインターフェースは <tt>request_module(name)</tt>という関数で、モジュールへエキスポートされています。そして、モジュールは他のモジュールを同様に読み込むことができるのです。 
<tt>request_module(name)</tt>は内部的にカーネルスレッドを作成し、標準の<tt>exec_usermodehelper()</tt>カーネルインターフェース(これもまたモジュールにエキスポートされています)を使って、ユーザ空間のコマンドの<bf>modprobe -s -k module_name</bf>を実行させます。
関数は成功すれば0を返しますが、<tt>request_module()</tt>の返り値をチェックすることに通常は意味はありません。そのかわり、プログラミングでは、

<tscreen><code>
if (check_some_feature() == NULL)
    request_module(module);
if (check_some_feature() == NULL)
    return -ENODEV;
</code></tscreen>

のようにするのが通例です。

<!-- 
For example, this is done by <tt>fs/block_dev.c:get_blkfops()</tt> to load a module
<tt>block-major-N</tt> when attempt is made to open a block device with major <tt>N</tt>.
Obviously, there is no such module called <tt>block-major-N</tt> (Linux developers
only chose sensible names for their modules) but it is mapped to a proper
module name using the file <tt>/etc/modules.conf</tt>. However, for most well-known
major numbers (and other kinds of modules) the <bf>modprobe/insmod</bf> commands
know which real module to load without needing an explicit alias statement
in <tt>/etc/modules.conf</tt>.
 -->
例えばこれは、<tt>fs/block_dev.c:get_blkfops()</tt>により、メジャー番号が<tt>N</tt>であるようなブロックデバイスをオープンしようとしたときに、モジュール<tt>block-major-N</tt>を読み込むために実行されます。明らかに、<tt>block-major-N</tt>といったモジュールは存在していません(Linux 開発者は、モジュールにはそれなりの名前を選ぶものです)。でも、<tt>/etc/modules.conf</tt>ファイルにより、あるモジュール名に割り当ててあるのです。しかし、たいていの良く知られたメジャー番号(とそのモジュール)については、<bf>modprobe/insmod</bf>コマンドは、<tt>/etc/modules.conf</tt>に明示的なalias 文がなくとも、実際のモジュールがなにかを分かっています。

<!-- 
A good example of loading a module is inside the <bf>mount(2)</bf> system call. The
 <bf>mount(2)</bf> system call accepts the filesystem type as a string which
 <tt>fs/super.c:do_mount()</tt> then passes on to <tt>fs/super.c:get_fs_type()</tt>:
 -->
モジュールの読み込の良い例が、<bf>mount(2)</bf>システムコールの内部にあります。
<bf>mount(2)</bf>システムコールはファイルシステムタイプを文字列として受け取り、<tt>fs/super.c:do_mount()</tt>は<tt>fs/super.c:get_fs_type()</tt>へそれを渡します。

<tscreen><code>
static struct file_system_type *get_fs_type(const char *name)
{
        struct file_system_type *fs;

        read_lock(&amp;file_systems_lock);
        fs = *(find_filesystem(name));
        if (fs && !try_inc_mod_count(fs->owner))
                fs = NULL;
        read_unlock(&amp;file_systems_lock);
        if (!fs && (request_module(name) == 0)) {
                read_lock(&amp;file_systems_lock);
                fs = *(find_filesystem(name));
                if (fs && !try_inc_mod_count(fs->owner))
                        fs = NULL;
                read_unlock(&amp;file_systems_lock);
        }
        return fs;
}
</code></tscreen>

<!-- 
A few things to note in this function:
 -->
この関数では、いくつか注意する点があります。


<enum>
<!-- 
<item> First we attempt to find the filesystem with the given name amongst
       those already registered. This is done under protection of
       <tt>file_systems_lock</tt> taken for read (as we are not modifying the list
       of registered filesystems).
 -->
<item> 最初に、与えられた名前のファイルシステムをすでに登録されているうちから見つけようとする。(登録されているファイルシステムのリストを更新しないため)読み込みのために取得する <tt>file_system_lock</tt> の保護のもと、これは実行される。

<!-- 
<item> If such a filesystem is found then we attempt to get a new reference
       to it by trying to increment its module's hold count. This always
       returns 1 for statically linked filesystems or for modules not
       presently being deleted. If <tt>try_inc_mod_count()</tt> returned 0 then
       we consider it a failure - i.e. if the module is there but is being
       deleted, it is as good as if it were not there at all.
  -->
<item> もしファイルシステムが見つかったら、新しいリファレンスを取得しようとする。そして、モジュールのホールドカウントを 1 増やそうとする。これは静的にリンクされたファイルシステムでは常に 1 を返す。モジュールとしてロードしたファイルシステムでも、現在削除されているところでない限り 1 を返す。もし <tt>try_inc_mod_count()</tt> が 0 を返す場合は失敗したと考える。つまり、モジュールはあるが削除されているところで、それは元々なかったのと同じことである。

<!-- 
<item> We drop the <tt>file_systems_lock</tt> because what we are about to do next
       (<tt>request_module()</tt>) is a blocking operation, and therefore we can't
       hold a spinlock over it. Actually, in this specific case, we would
       have to drop <tt>file_systems_lock</tt> anyway, even if <tt>request_module()</tt> were
       guaranteed to be non-blocking and the module loading were executed
       in the same context atomically. The reason for this is that the module's
       initialisation function will try to call <tt>register_filesystem()</tt>, which will 
       take the same <tt>file_systems_lock</tt> read-write spinlock for write.
 -->
<item> (<tt>request_module()</tt>)次は、ブロックする操作を行いたいため、<tt>file_system_lock</tt>を落とす。したがってこの時にはスピンロックを保持できない。実際のところ、この特別な場合には、たとえ<tt>request_module()</tt>がノンブロックであることが保証されていて、モジュール読み込みが同じコンテキストでアトミックに実行されたとしても、<tt>file_system_lock</tt>を落とさなければならない。これは、モジュールの初期化ルーチンでは、書き込みのために同じ<tt>file_systems_lock</tt>を呼び出す<tt>register_filesystem()</tt>を呼び出すことがあるからである。

<!-- 
<item> If the attempt to load was successful, then we take the
       <tt>file_systems_lock</tt> spinlock and try to locate the newly registered
       filesystem in the list. Note that this is slightly wrong because
       it is in principle possible for a bug in modprobe command to cause
       it to coredump after it successfully loaded the requested module, in
       which case <tt>request_module()</tt> will fail even though the new filesystem will be
       registered, and yet <tt>get_fs_type()</tt> won't find it.
 -->
<item> もしロードが成功したら、<tt>file_systems_lock</tt>スピンロックを取得し、新しく登録されたファイルシステムをリストへ加えようとする。これは少し悪い考えである。というのは、原理的にはmodprobe コマンドのバグになり得るからだ。
<tt>request_module()</tt>が失敗したが、新しいファイルシステムが登録されてしまって、しかも<tt>get_fs_type()</tt>が見つからない場合に、要求されたモジュールのロードが成功した後にコアダンプしてしまうことがあるためだ。

<!-- 
<item> If the filesystem is found and we are able to get a reference to it,
       we return it. Otherwise we return NULL.
 -->
<item> もしファイルシステムが見つかり、そのリファレンスを取得できたら復帰する。そうでなければ、NULL を返す。

</enum>


<!-- 
When a module is loaded into the kernel, it can refer to any symbols that
are exported as public by the kernel using <tt>EXPORT_SYMBOL()</tt> macro or by
other currently loaded modules. If the module uses symbols from another
module, it is marked as depending on that module during dependency
recalculation, achieved by running <bf>depmod -a</bf> command on boot (e.g. after
installing a new kernel).
 -->
モジュールがカーネルにロードされているとき、カーネルの <tt>EXPORT_SYMBOL()</tt>マクロを使っている部分や現在ロードされている他のモジュールから、パブリックにエキスポートされたシンボルを参照することができます。
。もしモジュールが他のモジュールからのシンボルを使うときは、ブート時の<bf>depmod -a</bf>コマンドの実行により行われる依存関係の再計算の間は(例えば新しいカーネルをインストールした後など)、そのモジュールは保留されることになります。

<!-- 
Usually, one must match the set of modules with the version of the kernel
interfaces they use, which under Linux simply means the "kernel version" as
there is no special kernel interface versioning mechanism in general.
However, there is a limited functionality called "module versioning" or
<tt>CONFIG_MODVERSIONS</tt> which allows to avoid recompiling modules when switching
to a new kernel. 
 -->
通常、使用するカーネルインターフェースのバージョンと、モジュール一式のバージョンは一致しなければなりません。これは Linux では、特別なカーネルインターフェースのバージョン機構を一般には持っていないため、単純な「カーネルバージョン」を意味しています。しかし、「モジュールバージョン」ないしは<tt>CONFIG_MODVERSIONS</tt> と呼ばれる限定された機能をもっています。これによって、新しいカーネルに移行したときにモジュールの再コンパイルを避けることができます。
<!-- 
What happens here is that the kernel symbol table is treated
differently for internal access and for access from modules. The elements of
public (i.e. exported) part of the symbol table are built by 32bit
checksumming the C declaration. So, in order to resolve a symbol used by a
module during loading, the loader must match the full representation of the
symbol that includes the checksum; it will refuse to load the module if these
symbols differ. 
 -->
カーネルのシンボルテーブルを、内部のアクセスとモジュールのアクセスを別々に扱うことで、これを実現しています。シンボルテーブルのパブリック(つまりエキスポートされた）要素は、Cの修飾子により32ビットチェックサムがつけられます。そして、ロード中にモジュールが使うシンボルを解決するために、ローダはチェックサムを含めてシンボルの表記名を比較します。もし一致しなければロードを拒否するようになっています。
<!-- 
This
only happens when both the kernel and the module are compiled with module
versioning enabled. If either one of them uses the original symbol names,
the loader simply tries to match the kernel version declared by the module
and the one exported by the kernel and refuses to load if they differ.
-->
これは、カーネルとモジュールを、モジュールバージョンを有効にしてコンパイルしたときのみ起ります。もし、どちらかがオリジナルのシンボル名を使っていた場合、ローダは単にモジュールによってカーネルバージョンの修飾のついたものと、カーネルによりエキスポートされているものを比較して、違っていればロードを拒否します。

<!-- 
<sect>Virtual Filesystem (VFS)<p>
 -->
<sect>仮想ファイルシステム (VFS) <p>

<!-- 
<sect1>Inode Caches and Interaction with Dcache<p>
 -->
<sect1>Inode キャッシュとDcache との相互作用<p>

<!-- 
In order to support multiple filesystems, Linux contains a special kernel
interface level called VFS (Virtual Filesystem Switch). This is similar
to the vnode/vfs interface found in SVR4 derivatives (originally it came from
BSD and Sun original implementations).
 -->
複数のファイルシステムをサポートするため、 Linux は VFS (Virtual Filesystem Switch)
という特別なカーネルインターフェースレベルを持っています。
これは SVR4 から派生した OS に見られる vnode/vfs インターフェースに良く似ています
(もともとは、BSD と Sun に由来の実装からきています)。

<!-- 
Linux inode cache is implemented in a single file, <tt>fs/inode.c</tt>, which consists
of 977 lines of code. It is interesting to note that not many changes have been
made to it for the last 5-7 years: one can still recognise some of the code
comparing the latest version with, say, 1.3.42.
 -->
Linux の inode キャッシュは、一つの 977 行からなるファイル <tt>fs/inode.c</tt> に実装されています。
特筆すべき事に、このファイルは、この 5-7 年の間ほとんど変更がありませんでした。
一番最後に更新されたのは、そう 1.3.42 の時なのです。

<!-- 
The structure of Linux inode cache is as follows:
 -->
Linux の inode キャッシュの構造は以下の通りです。

<enum>
<!-- 
item> A global hashtable, <tt>inode_hashtable</tt>, where each inode is hashed by the
       value of the superblock pointer and 32bit inode number. Inodes without a
       superblock (<tt>inode->i_sb == NULL</tt>) are added to a doubly linked list
       headed by <tt>anon_hash_chain</tt> instead. Examples of anonymous inodes
       are sockets created by <tt>net/socket.c:sock_alloc()</tt>, by calling
       <tt>fs/inode.c:get_empty_inode()</tt>.
 -->
<item> 
各 inode がスーパーブロックポインタと 32bit の inode 番号の値によってハッシュされるグローバルハッシュテーブル <tt>inode_hashtable</tt>。 スーパーブロックの無い inode (<tt>inode->i_sb == NULL</tt>) は、代りに<tt>anon_hash_chain</tt>で始まるダブルリンクリストへとつながれる。匿名 inodeの例として、<tt>fs/inode.c:get_empty_inode()</tt>を呼ぶことで、<tt>net/socket.c:sock_alloc()</tt>によって作られるソケットがある。

<!-- 
<item> A global type in_use list (<tt>inode_in_use</tt>), which contains valid inodes
       with <tt>i_count>0</tt> and <tt>i_nlink>0</tt>. Inodes newly allocated by
       <tt>get_empty_inode()</tt> and <tt>get_new_inode()</tt> are added to the <tt>inode_in_use</tt> list.
 -->
<item> <tt>i_count>0</tt> かつ <tt>i_nlink>0</tt> となる inode からなるグローバルタイプの in_use_list(<tt>inode_in_use</tt>)。inode は、<tt>get_empty_inode()</tt> と <tt>get_new_inode()</tt> により新たに割り当てられ、<tt>inode_in_use</tt> リストへつながれる。

<!-- 
<item> A global type unused list (<tt>inode_unused</tt>), which contains valid inodes
       with <tt>i_count = 0</tt>.
 -->
<item> <tt>i_count = 0</tt>であるような グローバルタイプの未使用リスト (<tt>inode_unused</tt>)。

<!-- 
<item> A per-superblock type dirty list (<tt>sb->s_dirty</tt>) which contains valid
       inodes with <tt>i_count>0</tt>, <tt>i_nlink>0</tt> and <tt>i_state & I_DIRTY</tt>.
       When inode is marked
       dirty, it is added to the <tt>sb->s_dirty</tt> list if it is also hashed.
       Maintaining a per-superblock dirty list of inodes allows to quickly
       sync inodes.
 -->
<item> <tt>i_count>0</tt>、<tt>i_nlink>0</tt>そして<tt>i_state & I_DIRTY </tt>であるような inode によるスーパーブロック毎の汚れたリスト(<tt>sb->s_dirty</tt>)。inodeが dirtyの印がつけられたら、それはやはりハッシュになっている<tt>sb->s_dirty</tt>リストに追加される。スーパーブロック毎に inode の dirty リストを管理することで、inode の同期をすばやく行うことができるようになる。

<!-- 
<item> Inode cache proper - a SLAB cache called <tt>inode_cachep</tt>. As inode
       objects are allocated and freed, they are taken from and returned to
       this SLAB cache.
 -->
<item> 厳密な意味の inode キャッシュ -- <tt>inode_cachep</tt>を呼び出す SLAB キャッシュ。inode オブジェクトが割り当てられたり、解放されたりするときは、この SLAB キャッシュから取得されたり、返されたりする。
</enum>

<!-- 
The type lists are anchored from <tt>inode->i_list</tt>, the hashtable from
<tt>inode->i_hash</tt>. Each inode can be on a hashtable and one and only one type
(in_use, unused or dirty) list.
 -->
それぞれのタイプリストは、<tt>inode->i_list</tt>から指し示され、ハッシュテーブルは、<tt>inode->i_hash</tt>から結び付けられています。各 inode は それぞれハッシュテーブルと１種類のみのタイプリスト(in_use, unused, または dirty)に入ります。

<!-- 
All these lists are protected by a single spinlock: <tt>inode_lock</tt>.
 -->
このすべてのリストは一つのスピンロック<tt>inode_lock</tt>により保護されています。

<!-- 
The inode cache subsystem is initialised when <tt>inode_init()</tt> function is called from
<tt>init/main.c:start_kernel()</tt>. The function is marked as <tt>__init</tt>, which means
its code is thrown away later on. It is passed a single argument - the
number of physical pages on the system. This is so that the inode cache can
configure itself depending on how much memory is available, i.e. create
a larger hashtable if there is enough memory.
-->
inode キャッシュサブシステムは、<tt>inode_init()</tt>関数が、<tt>init/main.c:start_kernel()</tt>から呼び出された時に初期化されます。この関数は、<tt>__init</tt>とマークされており、これはその後、このコードが解放されてしまうことを意味しています。この関数は一つの引数 -- システムの物理ページ数を渡します。このことから、inode キャッシュは利用可能なメモリ量に依存して決められていることがわかります。つまり、もし十分な量のメモリがあれば、より大きなハッシュテーブルを作成するということです。

<!-- 
The only stats information about inode cache is the number of unused inodes,
stored in <tt>inodes_stat.nr_unused</tt> and accessible to user programs via files
<tt>/proc/sys/fs/inode-nr</tt> and <tt>/proc/sys/fs/inode-state</tt>.
 -->
inode キャッシュに関するの唯一の統計的情報は、利用されていないinode数です。これは、<tt>inodes_stat.nr_unused</tt>に格納され、ファイル<tt>/proc/sys/fs/inode-nr</tt>や<tt>proc/sys/fs/inode-state</tt>を通してユーザプログラムから見ることができます。

<!-- 
We can examine one of the lists from <bf>gdb</bf> running on a live kernel thus:
 -->
そのため、生きたカーネルで実行する <bf>gdb</bf> からリストを取出すことができます。

<tscreen><code>
(gdb) printf "%d\n", (unsigned long)(&amp;((struct inode *)0)->i_list)
8
(gdb) p inode_unused
$34 = 0xdfa992a8
(gdb) p (struct list_head)inode_unused
$35 = {next = 0xdfa992a8, prev = 0xdfcdd5a8}
(gdb) p ((struct list_head)inode_unused).prev
$36 = (struct list_head *) 0xdfcdd5a8
(gdb) p (((struct list_head)inode_unused).prev)->prev
$37 = (struct list_head *) 0xdfb5a2e8
(gdb) set $i = (struct inode *)0xdfb5a2e0
(gdb) p $i->i_ino
$38 = 0x3bec7
(gdb) p $i->i_count
$39 = {counter = 0x0}
</code></tscreen>

<!-- 
Note that we deducted 8 from the address 0xdfb5a2e8 to obtain the address of
the <tt>struct inode</tt> (0xdfb5a2e0) according to the definition of <tt>list_entry()</tt>
macro from <tt>include/linux/list.h</tt>.
 -->
ここで、<tt>include/linux/list.h</tt> の <tt>list_entry()</tt>マクロの定義にしたがって<tt>struct inode</tt>のアドレス (0xdfb5a3e0) を得るために、アドレス 0xdfb5a2e8 から8を引いていることに注意しましょう。

<!-- 
To understand how inode cache works, let us trace a lifetime of an inode
of a regular file on ext2 filesystem as it is opened and closed:
 -->
inode キャッシュがどのように働くか理解するために、ext2 ファイルシステムの通常のファイルで、
オープン、クローズされるときの inode の一生を見ていきましょう。

<tscreen><code>
fd = open("file", O_RDONLY);
close(fd);
</code></tscreen>

<!-- 
The <bf>open(2)</bf> system call is implemented in <tt>fs/open.c:sys_open</tt> function and
the real work is done by <tt>fs/open.c:filp_open()</tt> function, which is split into
two parts:

ここで、関数の()がぬけている。(三浦）
 -->
<bf>open(2)</bf> システムコールは <tt>fs/open.c:sys_open()</tt> 関数に定義されていて、実体は <tt>fs/open.c:file_open()</tt> 関数が行っています。この関数は2つの部分に分けられ、

<enum>
<!-- 
<item> <tt>open_namei()</tt>: fills in the nameidata structure containing the dentry
       and vfsmount structures.
 -->
<item> <tt>open_namei()</tt>:  dentryとvfsmount構造体からなるnameiデータ構造体を埋める。

<!-- 
<item> <tt>dentry_open()</tt>: given a dentry and vfsmount, this function allocates a new
       <tt>struct file</tt> and links them together; it also invokes the filesystem
       specific <tt>f_op->open()</tt> method which was set in <tt>inode->i_fop</tt> when inode
       was read in <tt>open_namei()</tt> (which provided inode via <tt>dentry->d_inode</tt>).
 -->
<item> <tt>dentry_open()</tt>: dentryやvfsmountを与える。この関数は、新しい<tt>struct file</tt>を割り当て、相互にリンクする。また、inode が(<tt>dentry->d_inode</tt>から inode を与える) <tt>open_namei()</tt> で読み込まれる時 <tt>inode->i_fop</tt> にセットされているファイルシステムに特有の <tt>f_op->open()</tt> メソッドを呼び出す。
</enum>

<!-- 
The <tt>open_namei()</tt> function interacts with dentry cache via <tt>path_walk()</tt>, which
in turn calls <tt>real_lookup()</tt>, which invokes the filesystem specific <tt>inode_operations->lookup()</tt> method.
The role of this method is to find the entry in the parent
directory with the matching name and then do <tt>iget(sb, ino)</tt> to get the
corresponding inode - which brings us to the inode cache. When the inode is
read in, the dentry is instantiated by means of <tt>d_add(dentry, inode)</tt>. While
we are at it, note that for UNIX-style filesystems which have the concept of
on-disk inode number, it is the lookup method's job to map its endianness
to current CPU format, e.g. if the inode number in raw (fs-specific) dir
entry is in little-endian 32 bit format one could do:
 -->
<tt>open_namei()</tt> 関数は、ファイルシステム毎の<tt>inode_operations->lookup()</tt> メソッドを起動する <tt>real_lookup()</tt>をさらに呼び出す <tt>path_walk()</tt> によって、 dentry キャッシュと相互作用を起こします。
このメソッドの役割は、親ディレクトリで名前の一致するエントリを探すことで、その inode を取得するため <tt>iget(sb, ino)</tt> を呼び出しています。この関数は inode キャッシュへアクセスします。
inode が読み込まれたら、 <tt>d_add(dentry, inode)</tt> により dentry のインスタンスが作成されます。
ここで注意するのは、上記の間で、オンディスク inode 番号というコンセプトを持つUNIX スタイルのファイルシステムのために、そのエンディアンを現在の CPU フォーマットにマップするのがルックアップメソッドの仕事だということです。
たとえば、ファイルシステムに特有な raw ディレクトリエントリの inode 番号がリトルエンディアンの32ビットフォーマットであれば、

<tscreen><code>
unsigned long ino = le32_to_cpu(de->inode);
inode = iget(sb, ino);
d_add(dentry, inode);
</code></tscreen>
というコードを実行します。

<!--
So, when we open a file we hit <tt>iget(sb, ino)</tt> which is really
<tt>iget4(sb, ino, NULL, NULL)</tt>, which does:
-->
このように、ファイルを開くときには、実体が<tt>iget4(sb, ino, NULL, NULL)</tt> である <tt>iget(sb, ino)</tt> をたたきます。これは、

<enum>
<!--
<item> Attempt to find an inode with matching superblock and inode number
       in the hashtable under protection of <tt>inode_lock</tt>. If inode is found,
       its reference count (<tt>i_count</tt>) is incremented; if it
       was 0 prior to incrementation and the inode is not dirty, it is removed from whatever
       type list (<tt>inode->i_list</tt>) it is currently on (it has to be
       <tt>inode_unused</tt> list, of course) and inserted into
       <tt>inode_in_use</tt> type list; finally, <tt>inodes_stat.nr_unused</tt> is decremented.
-->
<item> <tt>inode_lock</tt>の保護のもと、ハッシュテーブルの中から、スーパブロックと inode 番号が一致する inode を見つけようとする。もし、inode が見つかれば、その参照カウンタ (<tt>i_count</tt>) を増分する。
もし、増加の前の値が 0 であったらば、inode は dirty ではないので、どのタイプのリスト(<tt>iode->i_list</tt>)からであれ削除する。これは、現在 on (それはもちろん<tt>inode_unused</tt>リストでなければならない)であり、<tt>inode_in_use</tt>タイプのリストに挿入される。最後に、<tt>inodes_stat.nr_unused</tt> が減少される。

<!--
<item> If inode is currently locked, we wait until it is unlocked so that
       <tt>iget4()</tt> is guaranteed to return an unlocked inode.
-->
<item> もしinodeが現在ロックされていたら、ロックが解除されるまで待つ。つまり、<tt>iget4()</tt>はロックされていない inode を返すことが保証される。

<!--
<item> If inode was not found in the hashtable then it is the first time we
       encounter this inode, so we call <tt>get_new_inode()</tt>, passing it the pointer
       to the place in the hashtable where it should be inserted to.
-->
<item> もし inode がハッシュテーブルに見つからなければ、この inode に初めて出会ったということになる。よって、<tt>get_new_inode()</tt>を呼び出し、ハッシュテーブルの挿入すべき位置をポインタで渡す。

<!--
<item> <tt>get_new_inode()</tt> allocates a new inode from the <tt>inode_cachep</tt> SLAB
       cache but this operation can block (<tt>GFP_KERNEL</tt> allocation), so it
       must drop the <tt>inode_lock</tt> spinlock which guards the hashtable. Since it
       has dropped the spinlock, it must retry searching the inode in the
       hashtable afterwards; if it is found this time, it returns (after incrementing
       the reference by <tt>__iget</tt>) the one found in the hashtable and destroys
       the newly allocated one. If it is still not found in the hashtable,
       then the new inode we have just allocated is the one to be used;
       therefore it is initialised to the required values and the fs-specific
       <tt>sb->s_op->read_inode()</tt> method is invoked to populate the rest of the
       inode. This brings us from inode cache back to the filesystem code -
       remember that we came to the inode cache when filesystem-specific
       <tt>lookup()</tt> method invoked <tt>iget()</tt>. While the <tt>s_op->read_inode()</tt> method
       is reading the inode from disk, the inode is locked (<tt>i_state = I_LOCK</tt>);
       it is unlocked after the <tt>read_inode()</tt> method returns and all the waiters for it are
       woken up.
-->
<item> <tt>get_new_inode()</tt> は新しい inode を<tt>inode_cachep</tt> SLAB キャッシュから割り当てる。しかし、この操作は(<tt> GFP_KERNEL</tt>割り当てで)ブロックできるため、ハッシュテーブルを守る <tt>inode_lock</tt> spinlock をドロップしないといけない。spinlock をドロップしてしまったため、後で再びハッシュテーブルで inode を検索してみなくてはならない。再度それが見つかれば、ハッシュテーブルで見つけたものを復帰し、(<tt>__iget</tt> によって参照数を増やした後に)、新しく割り当てられた inode を破棄する。ハッシュテーブルでまだ見つからなければ、今さっき割り当てた新しい inode が、使われるべきものとなる。したがって、それは要求された値に初期化される。そして、ファイルシステムに特有の <tt>sb->s_op->read_inode()</tt> メソッドは、残りの inode を使うために起動される。
ということで、inode キャッシュバックのコードから、ファイルシステムコードへ見に行かなければならない。
ここで、ファイルシステムに特有の <tt>lookup()</tt> メソッドが <tt>iget()</tt>を起動したために、 inode キャッシュのコードを読んでいることを思い出してほしい。 <tt>s_op->read_inode()</tt> メソッドがディスクよりinodeを読み込む間、inode はロックされる。(<tt>i_state = I_LOCK()</tt>) <tt>read_inode()</tt> メソッドが復帰した後にロック解除される。そして、inode ロックを待っている全てが起こされる。

</enum>
<!-- 
Now, let's see what happens when we close this file descriptor. The <bf>close(2)</bf>
system call is implemented in <tt>fs/open.c:sys_close()</tt> function, which calls
<tt>do_close(fd, 1)</tt> which rips (replaces with NULL) the descriptor of the
process' file descriptor table and invokes the <tt>filp_close()</tt> function which does
most of the work. The interesting things happen in <tt>fput()</tt>, which checks if
this was the last reference to the file, and if so calls
<tt>fs/file_table.c:_fput()</tt> which calls <tt>__fput()</tt> which is where interaction with
dcache (and therefore with inode cache - remember dcache is a Master of inode
cache!) happens. The <tt>fs/dcache.c:dput()</tt> does <tt>dentry_iput()</tt> which brings us
back to inode cache via <tt>iput(inode)</tt> so let us understand
<tt>fs/inode.c:iput(inode)</tt>:
-->
さて、このファイルディスクリプタをcloseしたときに、なにが起こるかをみていきます。<bf>close(2)</bf> システムコールは、<tt>do_close(fd, 1)</tt> を呼び出す <tt>fs/open.c:sys_close()</tt> 関数として実装されています。<tt>do_close(fd, 1)</tt> は、プロセスのファイルディスクリプタテーブルの記述子を剥ぎ取り(NULL で置き換える)、ほとんどの作業を行う <tt>filp_close()</tt> 関数を呼び出します。
<tt>fput()</tt>ではおもしろいことが起こります。これがファイルの最後のリファレンスであるならば、<tt>__fput()</tt>を呼びだす <tt>fs/file_table.c:_fput()</tt> が呼び出され、dcache と相互作用を起こします。(しかも inode cache とも作用します -- dcache は inode キャッシュのマスターであった!)
<tt>fs/dcache.c:dput()</tt> は、 我々を <tt>iput(inode)</tt>を経由してinode キャッシュへ引き戻してくれる<tt>dentry_iput()</tt>を実行します。
したがって、<tt>fs/inode.c:iput(inode)</tt>は次のように理解することができます。

<enum>
<!--
<item> If parameter passed to us is NULL, we do absolutely nothing and return.
-->
<item> もし渡されたパラメータが NULL ならば、本当に何もせず戻る。
<!--
<item> if there is a fs-specific <tt>sb->s_op->put_inode()</tt> method, it is invoked
       immediately with no spinlocks held (so it can block).
-->
<item> もし、fs特有の <tt>sb->s_op->put_inode()</tt> メソッドがあれば、(ブロックできるため)スピンロックを取得することなくすぐに起動される。
<!--
<item> <tt>inode_lock</tt> spinlock is taken and <tt>i_count</tt> is decremented. If this was
       NOT the last reference to this inode then we simply check if
       there are too many references to it and so <tt>i_count</tt> can wrap around
       the 32 bits allocated to it and if so we print a warning and return.
       Note that we call <tt>printk()</tt> while holding the <tt>inode_lock</tt> spinlock -
       this is fine because <tt>printk()</tt> can never block, therefore it may be called in
       absolutely any context (even from interrupt handlers!).
-->
<item> <tt>inode_lock</tt>スピンロックが取得され <tt>i_count</tt> が１つ減少される。
もしこれがこの inode への最後のリファレンスで＊なけれ＊ば、単純にリファレンスが多すぎないかどうかを確認する。
これは、<tt>i_count</tt> が割り当てられた 32bit 以内に納めるためである。もし、リファレンスが多すぎる場合は警告を表示して返る。
ここで、<tt>inode_lock</tt> スピンロックを取得しているときに <tt>printk()</tt> を呼び出すが、これは大丈夫である。というのは、<tt>printk()</tt>はブロックされることはなく、したがっていついかなるコンテキスト(割り込みハンドラでさえ)からでも呼び出すことができるためだ。

<!--
<item> If this was the last active reference then some work needs to be done.
-->
<item> もし最後のアクティブなリファレンスであった場合には、必要な処理がある。
</enum>

<!--
The work performed by <tt>iput()</tt> on the last inode reference is rather complex
so we separate it into a list of its own:
-->
最後の inode リファレンスでの <tt>iput()</tt> が行う処理は、やや複雑なものです。そのため、リストでもその最後に分けてあります。

<enum>
<!--
<item> If <tt>i_nlink == 0</tt> (e.g. the file was unlinked while we held it open)
       then the inode is removed from hashtable and from its type list; if
       there are any data pages held in page cache for this inode, they are
       removed by means of <tt>truncate_all_inode_pages(&amp;inode->i_data)</tt>. Then
       the filesystem-specific <tt>s_op->delete_inode()</tt> method is invoked,
       which typically deletes the on-disk copy of the inode. If there is no
       <tt>s_op->delete_inode()</tt> method registered by the filesystem (e.g. ramfs)
       then we call <tt>clear_inode(inode)</tt>, which invokes <tt>s_op->clear_inode()</tt> if
       registered and if inode corresponds to a block device, this device's
       reference count is dropped by <tt>bdput(inode->i_bdev)</tt>.
-->
<item> もし <tt>i_nlink == 0</tt> (例: ファイルがオープンしているときに unlink された)場合は、
inode はハッシュテーブルとtype list から削除される。もし、この inode のページキャッシュになにかデータページが保持されていたら、<tt>truncate_all_inode_pages(&amp;inode->i_data)</tt> により削除される。
そして、ファイルシステム特有の <tt>s_op->delete_inode()</tt>メソッドが呼び出される。
これは通常は、ディスク上の inode を削除する。もし、<tt>s_op->delete_inode()</tt>メソッドがファイルシステムにより登録されていない(例: ramfs)場合には、<tt>clear_inode(inode)</tt>を呼び出し、これはもし登録されていれば<tt>s_op->clear_inode()</tt>を呼び出す。また、inode が特定のブロックデバイスに関連していれば、デバイスのリファレンスカウントを<tt>bdput(inode->i_bdev)</tt>で落とす。

<!--
<item> if <tt>i_nlink != 0</tt> then we check if there are other inodes in the same
       hash bucket and if there is none, then if inode is not dirty we delete
       it from its type list and add it to <tt>inode_unused</tt> list, incrementing
       <tt>inodes_stat.nr_unused</tt>. If there are inodes in the same hashbucket
       then we delete it from the type list and add to <tt>inode_unused</tt> list.
       If this was an anonymous inode (NetApp .snapshot) then we delete it
       from the type list and clear/destroy it completely.
-->
<item> もし <tt>i_nlink != 0</tt> なら、同じハッシュバケットの他の inode があるかチェックする。そして、なければ inode は dirty ではないため、その type list から削除できる。 そして、<tt>inode_unused</tt>リストへ追加し、<tt>inodes_stat.nr_unused</tt>を増分する。
もし、これが匿名 inode であった(NetApp .snapshot)なら、タイプリストから削除し、完全にクリア/破壊する。
</enum>


<!--
<sect1>Filesystem Registration/Unregistration<p>
-->
<sect1>ファイルシステム登録/登録解除<p>

<!--
The Linux kernel provides a mechanism for new filesystems to be written with
minimum effort. The historical reasons for this are:
-->
Linuxカーネルは、新しいファイルシステムを最小限の努力で書くことができる機構を提供しています。その歴史的な理由とは次のようなものです。

<enum>
<!--
<item> In the world where people still use non-Linux operating systems
       to protect their investment in legacy software, Linux had to provide
       interoperability by supporting a great multitude of different
       filesystems - most of which would not deserve to exist on their own
       but only for compatibility with existing non-Linux operating systems.
-->
<item> 人々がLinux以外のオペレーティングシステムを使っている世界で、古いソフトウエアへの投資を保護するために、Linuxは大変多くの異なったファイルファイルシステムのサポートにより相互運用性を提供しなければならなかった。そのため、多くのファイルシステムはそれ自身の存在はそれほど重要ではないが、現存するLinux以外のオペレーティングシステムがとの互換性をとるためだけの目的で存在する。

<!--
<item> The interface for filesystem writers had to be very simple so that
       people could try to reverse engineer existing proprietary filesystems
       by writing read-only versions of them. Therefore Linux VFS makes it
       very easy to implement read-only filesystems; 95% of the work is
       to finish them by adding full write-support. As a concrete example,
       I wrote read-only BFS filesystem for Linux in about 10 hours, but it
       took several weeks to complete it to have full write support (and
       even today some purists claim that it is not complete because "it
       doesn't have compactification support").
-->
<item> ファイルシステムを記述するインターフェースはとてもシンプルなものでなければならなかった。
現存するプロプラエタリなファイルシステムを、読込みのみ可能なファイルシステムを書くことによってリバースエンジニアリングできるようにするために、ファイルシステムを記述するインターフェースはとてもシンプルなものでなければならなかった。
したがって、LinuxのVFSは読込み専用ファイルシステムの実装が非常に容易になっている。ファイルシステムのサポートを書く仕事のの95%は、書き込みのフルサポートを追加して完成させることに費やされるのである。具体的な例としては、私がLinux用に読込み専用のBFSファイルシステムを書くのに約１０時間でできたのに対して、完全な書き込みサポートを追加して完成させるのに数週間を要したことを挙げられる(しかも、現在でも
完璧主義者から、"これはcompactificationサポートを持たないため"完成していないと主張されるのだ)。

<!--
<item> The VFS interface is exported, and therefore all Linux filesystems can
       be implemented as modules.
-->
<item> VFS インターフェースはエキスポートされており、したがってすべてのLinuxファイルシステムはモジュールとして実装できる。

</enum>

<!--
Let us consider the steps required to implement a filesystem under Linux.
The code to implement a filesystem can be either a dynamically loadable
module or statically linked into the kernel, and the way it is done under
Linux is very transparent. All that is needed is to fill in a
<tt>struct file_system_type</tt> structure and register it with the VFS using
the <tt>register_filesystem()</tt> function as in the following example from
<tt>fs/bfs/inode.c</tt>:
-->
ここで、Linuxでファイルシステムの実装に必要なステップを考えてみましょう。ファイルシステムを実装するコードは、動的にロードされるモジュールでも、静的にカーネルにリンクされるようにも構成することができます。
そして、 Linuxの元で行われる方法は非常に明白です。必要なことは、<tt>struct file_system_type</tt>構造体に情報を埋めて、これをVFSへ<tt>register_filesystem()</tt>関数によって登録することだけなのです。<tt>fs/bfs/inode.c</tt>の例だと、以下のようになります。

<tscreen><code>
#include <linux/module.h>
#include <linux/init.h>

static struct super_block *bfs_read_super(struct super_block *, void *, int);

static DECLARE_FSTYPE_DEV(bfs_fs_type, "bfs", bfs_read_super);

static int __init init_bfs_fs(void)
{
        return register_filesystem(&amp;bfs_fs_type);
}

static void __exit exit_bfs_fs(void)
{
        unregister_filesystem(&amp;bfs_fs_type);
}

module_init(init_bfs_fs)
module_exit(exit_bfs_fs)
</code></tscreen>

<!--
The <tt>module_init()/module_exit()</tt> macros ensure that, when BFS is compiled as a
module, the functions <tt>init_bfs_fs()</tt> and <tt>exit_bfs_fs()</tt> turn into <tt>init_module()</tt>
and <tt>cleanup_module()</tt> respectively; if BFS is statically linked into the kernel,
the <tt>exit_bfs_fs()</tt> code vanishes as it is unnecessary.
-->
<tt>module_init()/module_exit()</tt>マクロは、BFSがモジュールとしてコンパイルされたときに、関数<tt>init_bfs_fs()</tt>と<tt>exit_bfs_fs()</tt>がそれぞれ、<tt>init_module()</tt>と<tt>cleanup_module()</tt>になるようにします。

<!--
The <tt>struct file_system_type</tt> is declared in <tt>include/linux/fs.h</tt>:
 -->
<tt>struct file_system_type</tt>は、<tt>include/linux/fs.h</tt>で定義されます。

<tscreen><code>
struct file_system_type {
        const char *name;
        int fs_flags;
        struct super_block *(*read_super) (struct super_block *, void *, int);
        struct module *owner;
        struct vfsmount *kern_mnt; /* For kernel mount, if it's FS_SINGLE fs */
        struct file_system_type * next;
};
</code></tscreen>

<!-- 
The fields thereof are explained thus:
 -->
それぞれのメンバは、次のように説明されます。

<itemize>

<!-- <item><bf>name</bf>: human readable name, appears in <tt>/proc/filesystems</tt> file
	  and is used as a key to find a filesystem by its name; this same name is
	  used for the filesystem type in <bf>mount(2)</bf>, and it should be unique:  there
	  can (obviously) be only one filesystem with a given name. For modules,
	  name points to module's address spaces and not copied: this means <bf>cat
	  /proc/filesystems</bf> can oops if the module was unloaded but filesystem is
	  still registered.
 -->
<item> <bf>name</bf>: 人が読める名前で、<tt>filesystemsproc</tt>ファイルへ現われます。そして、ファイルシステムを名前から見つけるときのキーとして使われます。これと同じ名前は、<bf>mount(2)</bf>へ指定するファイルシステムのタイプとしても使われ、ファイルシステムごとに一意でなければなりません。

<!-- 
<item><bf>fs_flags</bf>: one or more (ORed) of the flags: <tt>FS_REQUIRES_DEV</tt>
      for filesystems that can only be mounted on a block device, <tt>FS_SINGLE</tt>
      for filesystems that can have only one superblock, <tt>FS_NOMOUNT</tt> for
      filesystems that cannot be mounted from userspace by means of <bf>mount(2)</bf>
      system call: they can however be mounted internally using <tt>kern_mount()</tt>
      interface, e.g. pipefs.
 -->
<item> <bf>fs_flags</bf>: １つないしは(ORされた)複数のフラグ: <tt>FS_REQUIRES_DEV</tt>は、ブロックデバイス上にだけマウント可能なファイルシステムという意味。<tt>FS_SINGLE</tt>は、唯１つのスーパーブロックをもつファイルシステム、<tt>FS_NOMOUNT</tt>はユーザスペースからマウントできない、つまり<bf>mount(2)</bf>システムコールでマウントできないファイルシステム。しかしこれは、内部的には<tt>kern_mount()</tt>インターフェースを使えばマウントできる (例 pipefs)。

<!-- 
<item><bf>read_super</bf>: a pointer to the function that reads the super
      block during mount operation. This function is required: if it is not
      provided, mount operation (whether from userspace or inkernel) will
      always fail except in <tt>FS_SINGLE</tt> case where it will Oops in
      <tt>get_sb_single()</tt>, trying to dereference a NULL pointer in
      <tt>fs_type->kern_mnt->mnt_sb</tt> with (<tt>fs_type->kern_mnt = NULL</tt>).
 -->
<item><bf>read_super</bf>: マウント操作中にスーパブロックを読込む関数へのポインタ。この関数は必須である。このポインタが渡されなかったなら、マウント操作(ユーザ空間にせよカーネルからにせよ)が<tt>FS_SINGLE</tt>の場合を除いて常に失敗し、
<tt>fs_type->kern_mnt->mnt_sb</tt>を(<tt>fs_type->kern_mnt = NULL</tt>)のように参照しようとして、<tt>get_sb_sinle()</tt>でOops エラーが発生する。

<!-- 
<item><bf>owner</bf>: pointer to the module that implements this filesystem.
      If the filesystem is statically linked into the kernel then this is
      NULL. You don't need to set this manually as the macro <tt>THIS_MODULE</tt>
      does the right thing automatically.
 -->
<item><bf>owner</bf>: このファイルシステムを実装しているモジュールへのポインタ。もしファイルシステムがカーネルに静的にリンクされていれば、この値はNULLとなる。これを手動で設定する必要はなく、マクロ <tt>THIS_MODULE</tt> によって自動で適切に設定される。

<!-- 
<item><bf>kern_mnt</bf>: for <tt>FS_SINGLE</tt> filesystems only. This is set by
      <tt>kern_mount()</tt> (TODO: <tt>kern_mount()</tt> should refuse to mount filesystems
      if <tt>FS_SINGLE</tt> is not set).
 -->
<item><bf>kern_mnt</bf>: <tt>FS_SINGLE</tt>ファイルシステムのみ利用。これは<tt>kern_mount()</tt>が設定する。(TODO: <tt>kern_mount()</tt>は<tt>FS_SINGLE</tt>が設定されていないファイルシステムのマウントを拒否すべきである)。

<!-- 
<item><bf>next</bf>: linkage into singly-linked list headed by <tt>file_systems</tt>
      (see <tt>fs/super.c</tt>). The list is protected by the <tt>file_systems_lock</tt>
      read-write spinlock and functions <tt>register/unregister_filesystem()</tt>
	  modify it by linking and unlinking the entry from the list.
 -->
<item> <bf>next</bf>: <tt>file_systemsによる</tt>片方向リストの先頭へのリンク (<tt>fs/super.c</tt>を参照)。リストは、<tt>file_systems_lock</tt>読み書きスピンロックにより保護されており、<tt>register/unregister_filesystem()</tt>関数は、リストからエントリを取り外したり、入れたりすることで変更を行う。
</itemize>

<!-- 
The job of the <tt>read_super()</tt> function is to fill in the fields of the superblock,
allocate root inode and initialise any fs-private information associated with
this mounted instance of the filesystem. So, typically the <tt>read_super()</tt> would
do:
 -->
<tt>read_super()</tt>関数の仕事は、スーパーブロックのフィールドを埋めることです。
inodeの場所を割り当て、マウントされたファイルシステムのインスタンスに関連づけられたfs固有の情報を初期化します。

<enum>
<!-- 
<item> Read the superblock from the device specified via <tt>sb->s_dev</tt> argument,
       using buffer cache <tt>bread()</tt> function. If it anticipates to read a few
       more subsequent metadata blocks immediately then it makes sense to
       use <tt>breada()</tt> to schedule reading extra blocks asynchronously.
 -->
<item> バッファキャッシュ<tt>bread()</tt>関数を使って、スーパーブロックを<tt>sb->s_dev</tt>項で指示されるデバイスから読み取る。
<!-- 
<item> Verify that superblock contains the valid magic number and overall
       "looks" sane.
 -->
<item> スーパブロックが正しいマジックナンバーからなっているか確認し、全体的に正常であるかを「見」る。

<!-- 
<item> Initialise <tt>sb->s_op</tt> to point to <tt>struct super_block_operations</tt>
       structure. This structure contains filesystem-specific functions
       implementing operations like "read inode", "delete inode", etc.
 -->
<item> <tt>sb->s_op</tt>を<tt>struct super_block_operations</tt>構造体を指すように初期化する。この構造体は、「inodeを読み取る」とか、「inodeを削除する」などのような操作を実装しているファイルシステム特有の関数からなる。

<!-- 
<item> Allocate root inode and root dentry using <tt>d_alloc_root()</tt>.
 -->
<item> <tt>d_alloc_root()</tt>を用いてルートinodeとルートdentryを割り当てる。

<!-- 
<item> If the filesystem is not mounted read-only then set <tt>sb->s_dirt</tt> to 1
       and mark the buffer containing superblock dirty (TODO: why do we
       do this? I did it in BFS because MINIX did it...)
 -->
<item> もしファイルシステムが読み取り専用でマウントされていなければ、<tt>sb->s_dirt</tt>を1に設定し、スーパーブロックからなるバッファをdirtyとマークする(TODO: なぜこれが必要?BFSでは、MINIXがそうしていたのでやっているが...)
</enum>

<!-- 
<sect1>File Descriptor Management<p>
 -->
<sect1>ファイルデスクリプタ管理<p>

<!-- 
Under Linux there are several levels of indirection between user file
descriptor and the kernel inode structure. When a process makes <bf>open(2)</bf>
system call, the kernel returns a small non-negative integer which can be
used for subsequent I/O operations on this file. This integer is an index
into an array of pointers to <tt>struct file</tt>. Each file structure points to
a dentry via <tt>file->f_dentry</tt>. And each dentry points to an inode via
<tt>dentry->d_inode</tt>. 
 -->
Linuxにおいては、ユーザファイルデスクリプタとカーネルのinode構造体の間に間接的なレベルが存在しています。プロセスが<tt>open(2)</tt>システムコール呼び出すとき、カーネルは、このファイルを次のI/O操作で使用する小さい正の整数を返します。この整数は、<tt>struct file</tt>へのポインタの配列のインデックスになっています。各ファイル構造体は、<tt>file->f_dentry</tt>を通して、dentryを指しています。そして各dentryは<tt>dentry->d_inode</tt>を通じてinodeを指しています。

<!-- 
Each task contains a field <tt>tsk->files</tt> which is a pointer to
<tt>struct files_struct</tt> defined in <tt>include/linux/sched.h</tt>:
 -->
各タスクは、<tt>include/linux/sched.h</tt>で定義されている<tt>struct files_struct</tt>を指している<tt>tsk->files</tt>フィールドを持っています。

<tscreen><code>
/*
 * Open file table structure
 */
struct files_struct {
        atomic_t count;
        rwlock_t file_lock;
        int max_fds;
        int max_fdset;
        int next_fd;
        struct file ** fd;      /* current fd array */
        fd_set *close_on_exec;
        fd_set *open_fds;
        fd_set close_on_exec_init;
        fd_set open_fds_init;
        struct file * fd_array[NR_OPEN_DEFAULT];
};
</code></tscreen>

<!-- 
The <tt>file->count</tt> is a reference count, incremented by <tt>get_file()</tt> (usually
called by <tt>fget()</tt>) and decremented by <tt>fput()</tt> and by <tt>put_filp()</tt>. The difference
between <tt>fput()</tt> and <tt>put_filp()</tt> is that <tt>fput()</tt> does more work usually needed
for regular files, such as releasing flock locks, releasing dentry, etc, while
<tt>put_filp()</tt> is only manipulating file table structures, i.e. decrements the
count, removes the file from the <tt>anon_list</tt> and adds it to the <tt>free_list</tt>,
under protection of <tt>files_lock</tt> spinlock.
 -->
<tt>file->count</tt>は参照カウンタであり、(通常、<tt>fget()</tt>から呼び出される)<tt>get_file()</tt>で増分され、<tt>fput()</tt>と<tt>put_filp()</tt>で減少されます。<tt>fput()</tt>と<tt>put_filp()</tt>の違いは、<tt>fput()</tt>が一般のファイルに通常必要な、ファイルロックの開放やdentryの開放などの追加の処理を行うのに対し、<tt>put_filp()</tt>は単にファイルテーブル構造体を操作するに過ぎないところにあります。つまり、カウンタの減少は<tt>file_lock</tt>スピンロックの保護のもと、<tt>anon_list</tt>からファイルを削除し、それを<tt>free_list</tt>へ追加するということです。

<!-- 
The <tt>tsk->files</tt> can be shared between parent and child if the child thread
was created using <tt>clone()</tt> system call with <tt>CLONE_FILES</tt> set in the clone flags
argument. This can be seen in <tt>kernel/fork.c:copy_files()</tt> (called by
<tt>do_fork()</tt>) which only increments the <tt>file->count</tt> if <tt>CLONE_FILES</tt> is set
instead of the usual copying file descriptor table in time-honoured
tradition of classical UNIX <bf>fork(2)</bf>.
 -->

もし子のスレッドがクローンフラグ引数に<tt>CLONE_FILES</tt>を設定して<tt>clone()</tt>システムコールを呼んで作られたものであれば、<tt>tsk->files</tt>は親と子の間で共有することができます。これは、(<tt>do_fork()</tt>によって呼ばれる)<tt>kernel/fork.c:copy_files()</tt>において見ることができ、これは、もし<tt>CLONE_FILES</tt>が、伝統的な従来の古典的UNIXの<bf>fork(2)</bf>における通常のファイルデスクリプタテーブルのコピーのかわりに設定されていれば、単に<tt>file->count</tt>を増分させるだけです。

<!-- 
When a file is opened, the file structure allocated for it is installed into
<tt>current->files->fd[fd]</tt> slot and a <tt>fd</tt> bit is set in the bitmap
<tt>current->files->open_fds</tt> . All this is done under the write protection of 
<tt>current->files->file_lock</tt> read-write spinlock. When the descriptor is
closed a <tt>fd</tt> bit is cleared in <tt>current->files->open_fds</tt> and
<tt>current->files->next_fd</tt> is set equal to <tt>fd</tt> as a hint for finding the
first unused descriptor next time this process wants to open a file.
 -->
ファイルが開かれるとき、それに割り当てられるファイル構造体は、<tt>current->files->fd[fd]</tt>スロットへ組み込まれます。そしてビットマップ<tt>current->files->open_fds</tt>の<tt>fd</tt>ビットがセットされます。これらのことは全て、<tt>current->files->file_lock</tt>読み書きスピンロックの書き込み保護のもとで行われます。もし、デスクリプタがcloseされれば、 <tt>current->files->open_fds</tt>の<tt>fd</tt>ビットはクリアされ、このプロセスがファイルをつぎにオープン使用としたときに、最初の未使用のデスクリプタを見つけるためのヒントとして、<tt>current->files->next_fd</tt>は<tt>fd</tt>と同じになるよう設定されます。

<!-- 
<sect1>File Structure Management<p>
 -->
<sect1> ファイル構造体管理<p>

<!-- 
The file structure is declared in <tt>include/linux/fs.h</tt>:
 -->
ファイル構造体は <tt>include/linux/fs.h</tt>で定義されています。

<tscreen><code>
struct fown_struct {
        int pid;                /* pid or -pgrp where SIGIO should be sent */
        uid_t uid, euid;        /* uid/euid of process setting the owner */
        int signum;             /* posix.1b rt signal to be delivered on IO */
};

struct file {
        struct list_head        f_list;
        struct dentry           *f_dentry;
        struct vfsmount         *f_vfsmnt;
        struct file_operations  *f_op;
        atomic_t                f_count;
        unsigned int            f_flags;
        mode_t                  f_mode;
        loff_t                  f_pos;
        unsigned long           f_reada, f_ramax, f_raend, f_ralen, f_rawin;
        struct fown_struct      f_owner;
        unsigned int            f_uid, f_gid;
        int                     f_error;

        unsigned long           f_version;
  
        /* needed for tty driver, and maybe others */
        void                    *private_data; 
};
</code></tscreen>

<!-- 
Let us look at the various fields of <tt>struct file</tt>:
 -->
では <tt>struct file</tt> のメンバを見ていきましょう。

<enum>
<!-- <item><bf>f_list</bf>: this field links file structure on one (and only one)
      of the lists: a) <tt>sb->s_files</tt> list of all open files on this filesystem,
      if the corresponding inode is not anonymous, then <tt>dentry_open()</tt> (called
      by <tt>filp_open()</tt>) links the file into this list; 
      b) <tt>fs/file_table.c:free_list</tt>, containing unused file structures;
      c) <tt>fs/file_table.c:anon_list</tt>, when a new file structure is created by
      <tt>get_empty_filp()</tt> it is placed on this list. All these lists are
      protected by the <tt>files_lock</tt> spinlock.
 -->
<item> <bf>f_list</bf>: このメンバは次のリストのうち一つ(そしてただひとつ)のファイル構造体をリンクする。a) このファイルシステムの全てのオープンしているファイルの<tt>sb->s_files</tt>リスト、もし関連するinodeが匿名でなければ、(<tt>filp_open()</tt>からよばれる)<tt>dentry_open()</tt>は、このリストにファイルをリンクする。b) <tt>fs/file_table.c:free_list</tt>, 未使用のファイル構造体からなる。c) <tt>fs/file_table.c:anon_list</tt>, <tt>get_empty_filp()</tt>によって新しいファイル構造体が作られたときにこのリストにおかれる。すべてのリストは<tt>files_lock</tt>スピンロックによって保護される。

<!-- 
<item><bf>f_dentry</bf>: the dentry corresponding to this file. The dentry
      is created at nameidata lookup time by <tt>open_namei()</tt> (or
      rather <tt>path_walk()</tt>
	  which it calls) but the actual <tt>file->f_dentry</tt> field is set by
      <tt>dentry_open()</tt> to contain the dentry thus found.
 -->
<item> <bf>f_dentry</bf>: このファイルに関連づけられるdentry。dentryは、<tt>open_namei()</tt>がnameidataを探すとき(あるいは、これを呼び出す<tt>path_walk()</tt>が実行されたとき)に作られる。しかし、実際の<tt>file->f_dentry</tt>メンバは<tt>dentry_open()</tt>によって、このようにして見つかったdentryにセットされる。

<!-- 
<item><bf>f_vfsmnt</bf>: the pointer to <tt>vfsmount</tt> structure of the filesystem
      containing the file. This is set by <tt>dentry_open()</tt> but is found as part
      of nameidata lookup by <tt>open_namei()</tt> (or rather <tt>path_init()</tt> which it
      calls).
 -->
<item> <bf>f_vfsmnt</bf>: そのファイルの<tt>vfsmount</tt>ファイルシステム構造体を指す。これは、<tt>dentry_open()</tt>によって設定されるが、<tt>open_namei()</tt>(ないしは、これを呼び出す <tt>path_init()</tt>) により nameidata の一部として見ることができる。

<!-- 
<item><bf>f_op</bf>: the pointer to <tt>file_operations</tt> which contains various
      methods that can be invoked on the file. This is copied from
      <tt>inode->i_fop</tt> which is placed there by filesystem-specific
      <tt>s_op->read_inode()</tt> method during nameidata lookup. We will look at
      <tt>file_operations</tt> methods in detail later on in this section.
 -->
<item> <bf>f_op</bf>: このファイルで起動されるさまざまなメソッドからなる<tt>file_operations</tt>を指す。これは、nameidataの検索中にファイルシステム特有の<tt>s_op->read_inode()</tt>メソッドによって作られた、<tt>inode->i_fop</tt>からコピーされる。このセクションの後の方で、<tt>file_operations</tt>メソッドは詳細に見ていくことにしよう。

<!-- 
<item><bf>f_count</bf>: reference count manipulated by
      <tt>get_file/put_filp/fput</tt>.
 -->
<item><bf>f_count</bf>: <tt>get_file/put_filp/fput</tt>により操作されるリファレンスカウンタ。

<!-- 
<item><bf>f_flags</bf>: <tt>O_XXX</tt> flags from <bf>open(2)</bf> system call copied there
      (with slight modifications by <tt>filp_open()</tt>) by <tt>dentry_open()</tt> and after
      clearing <tt>O_CREAT</tt>, <tt>O_EXCL</tt>, <tt>O_NOCTTY</tt>, <tt>O_TRUNC</tt> - there is no point in
      storing these flags permanently since they cannot be modified by 
      <tt>F_SETFL</tt> (or queried by <tt>F_GETFL</tt>) <bf>fcntl(2)</bf> calls.
 -->
<item><bf>f_flags</bf>: <tt>dentry_open()</tt>によって(<tt>filp_open()</tt>が若干の変更を加えて)コピーされる<bf>open(2)</bf>システムコールからの<tt>O_XXX</tt>フラグ。<tt>O_CREAT</tt>、<tt>O_EXCL</tt>、<tt>O_NOCTTY</tt>、<tt>O_TRUNC</tt>をクリアした後はこれらのフラグを長い間保存しておく意味はない。なぜなら、<tt>F_SETFL</tt> や <tt>F_GETFL</tt> <bf>fcntl(2)</bf> システムコールで変更されることも、問い合わせられることもないからである。

<!-- 
<item><bf>f_mode</bf>: a combination of userspace flags and mode, set
      by <tt>dentry_open()</tt>. The point of the conversion is to store read and
      write access in separate bits so one could do easy checks like
      <tt>(f_mode & FMODE_WRITE)</tt> and <tt>(f_mode & FMODE_READ)</tt>.
 -->
<item><bf>f_mode</bf>: ユーザ空間のフラグとモードの組み合わせ。<tt>dentry_open()</tt>によって設定される。変換のポイントは、読み書きのアクセスを別のビットへ格納することで、<tt>(f_mode & FMODE_WRITE)</tt>や<tt>(f_mode & FMODE_READ)</tt>のようなチェックを容易にすることができる。

<!-- 
<item><bf>f_pos</bf>: a current file position for next read or write to
      the file. Under i386 it is of type <tt>long long</tt>, i.e. a 64bit value.
 -->
<item><bf>f_pos</bf>: 次回のファイルの読み書きにおける現在のファイル位置。i386では、<tt>long long</tt>型、つまり64ビット値になる。

<!-- <item><bf>f_reada, f_ramax, f_raend, f_ralen, f_rawin</bf>: to support
      readahead - too complex to be discussed by mortals ;)
 -->
<item><bf>f_reada, f_ramax, f_raend, f_ralen, frawin</bf>: readaheadをサポートする。 -- 複雑すぎて人間には議論できない ;)

<!-- <item><bf>f_owner</bf>: owner of file I/O to receive asynchronous I/O 
      notifications via <tt>SIGIO</tt> mechanism (see <tt>fs/fcntl.c:kill_fasync()</tt>).
 -->
<item><bf>f_owner</bf>: 非同期I/O通知を<tt>SIGIO</tt>機構を通じて受け取るファイルI/Oの所有者。(<tt>fs/fcntl.c:kill_fasync()</tt>参照)

<!-- <item><bf>f_uid, f_gid</bf> - set to user id and group id of the process that
      opened the file, when the file structure is created in
      <tt>get_empty_filp()</tt>. If the file is a socket, used by ipv4 netfilter.
 -->
<item><bf>f_uid, f_gid</bf>: ファイル構造体が<tt>get_empty_filp()</tt>によって作られたときにファイルを開いたプロセスのユーザIDとグループIDに設定される。ファイルがソケットのときは、ipv4ネットフィルタが使う。

<!-- <item><bf>f_error</bf>: used by NFS client to return write errors. It is
      set in <tt>fs/nfs/file.c</tt> and checked in <tt>mm/filemap.c:generic_file_write()</tt>.
 -->
<item><bf>f_error</bf>: 書き込みエラーを返すためにNFSクライアントが利用する。これは<tt>fs/nfs/file.c</tt>で設定され、<tt>mm/filemap.c:generic_file_write()</tt>でチェックされる。

<!-- <item><bf>f_version</bf> - versioning mechanism for invalidating caches,
      incremented (using global <tt>event</tt>) whenever <tt>f_pos</tt> changes.
 -->
<item><bf>f_version</bf>: キャッシュを取り消すためのバージョン管理メカニズム。(グローバル変数の<tt>event</tt>を使って)<tt>f_pos</tt>が変ったときにいつも増分される。

<!-- <item><bf>private_data</bf>: private per-file data which can be used by
      filesystems (e.g. coda stores credentials here) or by device drivers.
      Device drivers (in the presence of devfs) could use this field to
      differentiate between multiple instances instead of the classical
      minor number encoded in <tt>file->f_dentry->d_inode->i_rdev</tt>.
	 -->
<item><bf>private_data</bf>: ファイルシステムが使うことができる(例えば、coda はここに 証明書を格納する) 非公開のファイル毎のデータ。ないしは、デバイスドライバが使う。(devfsにある)デバイスドライバは、このメンバを、<tt>file->f_dentry->d_inode->i_rdev</tt>に符号化される、古典的なマイナー番号のかわりに、複数のインスタンス間を区別するのに使える。
  
</enum>

<!-- 
Now let us look at <tt>file_operations</tt> structure which contains the methods that
can be invoked on files. Let us recall that it is copied from <tt>inode->i_fop</tt>
where it is set by <tt>s_op->read_inode()</tt> method. It is declared in
<tt>include/linux/fs.h</tt>:
 -->
さて、ファイルについて起動できるメソッドからできている <tt>file_operations</tt>構造体を見てみましょう。<tt>inode->i_fop</tt>からコピーされることや、それが<tt>s_op->read_inode()</tt>メソッドによって設定されることなどを覚えているでしょうか。これは、<tt>include/linux/fs.h</tt>で定義されています。

<tscreen><code>
struct file_operations {
        struct module *owner;
        loff_t (*llseek) (struct file *, loff_t, int);
        ssize_t (*read) (struct file *, char *, size_t, loff_t *);
        ssize_t (*write) (struct file *, const char *, size_t, loff_t *);
        int (*readdir) (struct file *, void *, filldir_t);
        unsigned int (*poll) (struct file *, struct poll_table_struct *);
        int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
        int (*mmap) (struct file *, struct vm_area_struct *);
        int (*open) (struct inode *, struct file *);
        int (*flush) (struct file *);
        int (*release) (struct inode *, struct file *);
        int (*fsync) (struct file *, struct dentry *, int datasync);
        int (*fasync) (int, struct file *, int);
        int (*lock) (struct file *, int, struct file_lock *);
        ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
        ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
};
</code></tscreen>

<enum>
<!-- 
<item><bf>owner</bf>: a pointer to the module that owns the subsystem in
      question. Only drivers need to set it to <tt>THIS_MODULE</tt>, filesystems can
      happily ignore it because their module counts are controlled at
      mount/umount time whilst the drivers need to control it at open/release
      time.
 -->
<item><bf>owner</bf>: 論点となっているサブシステムを所有しているモジュールを指す。ドライバのみがこれを<tt>THIS_MODULE</tt>に設定する必要があり、モジュールのカウントは、ドライバがopen/release時に制御する必要があるのに対して、mount/umountのときに制御されるため、ファイルシステムは幸運なことに無視できる。

<!-- 
<item><bf>llseek</bf>: implements the <bf>lseek(2)</bf> system call. Usually it is
      omitted and <tt>fs/read_write.c:default_llseek()</tt> is used, which does the
      right thing (TODO: force all those who set it to NULL currently to use
      default_llseek - that way we save an <tt>if()</tt> in <tt>llseek()</tt>)
 -->
<item><bf>llseek</bf>: <bf>lseek(2)</bf>システムコールを実装している。通常、これは省略され、<tt>fs/read_wirte.c:default_llseek()</tt>が使われる。これは正しい方法である。(TODO: default_llseekを使うために現在これにNULLを設定しなければならなくなっている。このときは、<tt>llseek()</tt>で<tt>if()</tt>を保存している)。

<!-- 
<item><bf>read</bf>: implements <tt>read(2)</tt> system call. Filesystems can use
      <tt>mm/filemap.c:generic_file_read()</tt> for regular files and
      <tt>fs/read_write.c:generic_read_dir()</tt> (which simply returns <tt>-EISDIR</tt>)
      for directories here.
 -->
<item><bf>read</bf>: <tt>read(2)</tt>システムコールの実装。ここでは、ファイルシステムは、<tt>mm/flemap.c:generic_file_read()</tt>を通常のファイルに、<tt>fs/read_write.c:generic_read_dir()</tt>(単純に<tt>-EISDIR</tt>を返す)をディレクトリに使用できる。

<!-- 
<item><bf>write</bf>: implements <bf>write(2)</bf> system call. Filesystems can use
      <tt>mm/filemap.c:generic_file_write()</tt> for regular files and ignore it for
      directories here.
 -->
<item><bf>write</bf>: <bf>write(2)</bf>システムコールの実装。ここでは、ファイルシステムは、<tt>mm/filemap.c:generic_file_write()</tt>を通常のファイルに使用でき、ディレクトリは無視できる。

<!-- <item><bf>readdir</bf>: used by filesystems. Ignored for regular files
      and implements <bf>readdir(2)</bf> and <bf>getdents(2)</bf> system calls for directories.
 -->
<item><bf>readdir</bf>: ファイルシステムが使う。通常のファイルは無視され、ディレクトリには<bf>readdir(2)</bf> と <bf>getdents(2)</bf> システムコールが実装される。

<!-- <item><bf>poll</bf>: implements <bf>poll(2)</bf> and <bf>select(2)</bf> system calls.
 -->
<item><bf>poll</bf>: <bf>poll(2)</bf> と <bf>select(2)</bf> システムコールが実装される。

<!-- 
<item><bf>ioctl</bf>: implements driver or filesystem-specific
      ioctls. Note that generic file ioctls like <tt>FIBMAP</tt>, <tt>FIGETBSZ</tt>, <tt>FIONREAD</tt>
	  are implemented by higher levels so they never read <tt>f_op->ioctl()</tt>
	  method.
 -->
<item><bf>ioctl</bf>: ドライバやファイルシステム特有の ioctl を実装している。一般のファイルに対する <tt>FIBMAP</tt>や <tt>FIGETBSZ</tt>、 <tt>FIONREAD</tt> のようなioctl は、高レベルで実装されており<tt>f_op->ioctl()</tt> メソッドを読むことがない。

<!-- <item><bf>mmap</bf>: implements the <bf>mmap(2)</bf> system call. Filesystems can use
      <bf>generic_file_mmap</bf> here for regular files and ignore it on directories.
 -->
<item><bf>mmap</bf>: <bf>mmap(2)</bf> システムコールを実装している。ファイルシステムは <bf>generic_file_mmap</bf>を一般のファイルに対してここで使うことができ、ディレクトリに対しては無視される。

<!-- <item><bf>open</bf>: called at <bf>open(2)</bf> time by <tt>dentry_open()</tt>. Filesystems
      rarely use this, e.g. coda tries to cache the file locally at open
      time.
 -->
<item><bf>open</bf>: <bf>open(2)</bf> したときに<tt>dentry_open()</tt> が呼ぶ。ファイルシステムは滅多に使わない。例えば、coda はオープンしたときにファイルをローカルにキャッシュしようとする。
<!-- 
<item><bf>flush</bf>: called at each <bf>close(2)</bf> of this file, not necessarily
      the last one (see <tt>release()</tt> method below). The only filesystem that
      uses this is NFS client to flush all dirty pages. Note that this can
      return an error which will be passed back to userspace which made the
      <bf>close(2)</bf> system call.
 -->
<item><bf>flush</bf>: ファイルの各<bf>close(2)</bf>ごとに呼ばれる。必ずしも最後に呼ばれる必要はない。(以下の<tt>release()</tt>メソッド参照) これを使うファイルシステムというのは、唯一NFSのクライアントで、全てのdirtyページを書き出す。ここで、<bf>close(2)</bf>システムコールから、ユーザ空間に送り返されるエラーを返すことがある。

<!-- 
<item><bf>release</bf>: called at the last <bf>close(2)</bf> of this file, i.e. when
      <tt>file->f_count</tt> reaches 0. Although defined as returning int, the return
      value is ignored by VFS (see <tt>fs/file_table.c:__fput()</tt>).
 -->
<item><bf>release</bf>: ファイルの最後の<bf>close(2)</bf>で呼ばれる。つまり、<tt>file->f_count</tt>が0であるときだ。整数を返すと定義されているにも関わらず、VFSでは返り値は無視される。(<tt>fs/file_table.c:__fput()</tt>を参照)

<!-- 
<item><bf>fsync</bf>: maps directly to <bf>fsync(2)/fdatasync(2)</bf> system calls,
      with the last argument specifying whether it is fsync or fdatasync.
      Almost no work is done by VFS around this, except to map file
      descriptor to a file structure (<tt>file = fget(fd)</tt>) and down/up
      <tt>inode->i_sem</tt> semaphore. Ext2 filesystem currently ignores the last
      argument and does exactly the same for <bf>fsync(2)</bf> and <bf>fdatasync(2)</bf>.
 -->
<item><bf>fsync</bf>: <bf>fsync(2)/fdatasync(2)</bf>システムコールに直接対応する。最後の引数でfsyncになるかfdatasyncになるかを指定する。VFS はその際ほとんど何も仕事をしないが、ファイルディスクリプタを file 構造体に対応させること (<tt>file = fget(fd)</tt>)、および <tt>inode->i_sem</tt> セマフォを操作することは行う。Ext2 ファイルシステムは最後の引数を無視するので、<bf>fsync(2)</bf> と <bf>fdatasync(2)</bf> のシステムコールは全く同じ働きをする。

<!-- <item><bf>fasync</bf>: this method is called when <tt>file->f_flags & FASYNC</tt>
      changes.
 -->
<item><bf>fasync</bf>: このメソッドは、<tt>file->f_flags & FASYNC</tt> が真であるときに使われる。

<!-- <item><bf>lock</bf>: the filesystem-specific portion of the POSIX <bf>fcntl(2)</bf>
      file region locking mechanism. The only bug here is that because it is
      called before fs-independent portion (<tt>posix_lock_file()</tt>), if it
      succeeds but the standard POSIX lock code fails then it will never be
      unlocked on fs-dependent level..
      -->
<item><bf>lock</bf> : ファイルシステムに固有なPOSIXの<bf>fcntl(2)</bf>のファイル領域ロック機構。ここでの唯一のバグは、fs 非依存(<tt>posix_lock_file()</tt>)なものが呼ばれる前に呼ばれたとき、もし成功したが通常のPOSIXロックコードが失敗したら fs 依存レベルでは、ロック解除できなくなるということである。

<!-- 
<item><bf>readv</bf>: implements <bf>readv(2)</bf> system call.
 -->
<item><bf>readv</bf>: <bf>readv(2)</bf>システムコールの実装。

<!-- 
<item><bf>writev</bf>: implements <bf>writev(2)</bf> system call.
 -->
<item><bf>writev</bf>: <bf>writev(2)</bf>システムコールの実装。
</enum>

<!-- 
<sect1>Superblock and Mountpoint Management<p>
 -->
<sect1>スーパーブロックとマウントポイント管理<p>

<!-- 
Under Linux, information about mounted filesystems is kept in two separate
structures - <tt>super_block</tt> and <tt>vfsmount</tt>. The reason for this is that Linux
allows to mount the same filesystem (block device) under multiple mount
points, which means that the same <tt>super_block</tt> can correspond to multiple
<tt>vfsmount</tt> structures.
 -->
Linux においては、マウントされたファイルシステムについての情報は2つに分かれた構造体 <tt>super_block</tt>と<tt>vfsmount</tt> で保持されています。これは Linux は同じファイルシステム(ブロックデバイス)を複数のマウントポイントへマウントする、つまり同じ<tt>super_block</tt> が複数の<tt>vfsmount</tt>構造体へ関連づけられるという意味ですが、これが許されていることが、2つに分かれて管理される理由になっています。

<!--
Let us look at <tt>struct super_block</tt> first, declared in <tt>include/linux/fs.h</tt>:
 -->
<tt>include/linux/fs.h</tt> で定義される <tt>struct super_block</tt> を最初にみていきます。

<tscreen><code>
struct super_block {
        struct list_head        s_list;         /* Keep this first */
        kdev_t                  s_dev;
        unsigned long           s_blocksize;
        unsigned char           s_blocksize_bits;
        unsigned char           s_lock;
        unsigned char           s_dirt;
        struct file_system_type *s_type;
        struct super_operations *s_op;
        struct dquot_operations *dq_op;
        unsigned long           s_flags;
        unsigned long           s_magic;
        struct dentry           *s_root;
        wait_queue_head_t       s_wait;

        struct list_head        s_dirty;        /* dirty inodes */
        struct list_head        s_files;

        struct block_device     *s_bdev;
        struct list_head        s_mounts;       /* vfsmount(s) of this one */
        struct quota_mount_options s_dquot;     /* Diskquota specific options */

       union {
                struct minix_sb_info    minix_sb;
                struct ext2_sb_info     ext2_sb;
		..... all filesystems that need sb-private info ...
                void                    *generic_sbp;
        } u;
       /*
         * The next field is for VFS *only*. No filesystems have any business
         * even looking at it. You had been warned.
         */
        struct semaphore s_vfs_rename_sem;      /* Kludge */

        /* The next field is used by knfsd when converting a (inode number based)
         * file handle into a dentry. As it builds a path in the dcache tree from
         * the bottom up, there may for a time be a subpath of dentrys which is not
         * connected to the main tree.  This semaphore ensure that there is only ever
         * one such free path per filesystem.  Note that unconnected files (or other
         * non-directories) are allowed, but not unconnected diretories.
         */
        struct semaphore s_nfsd_free_path_sem;
};
</code></tscreen>

<!-- 
The various fields in the <tt>super_block</tt> structure are:
 -->
<tt>super_block</tt> 構造体には様々なメンバがあります。

<enum>
<!-- 
<item><bf>s_list</bf>: a doubly-linked list of all active superblocks; note
      I don't say "of all mounted filesystems" because under Linux one can
      have multiple instances of a mounted filesystem corresponding to a
      single superblock.
 -->
<item><bf>s_list</bf>: 全てのアクティブなスーパーブロックのダブルリンクリスト。ここで、「全てのマウントされたファイルシステム」と言わないのは、Linux では、一つのスーパブロックに関連づけられたマウントされたファイルシステムの複数のインスタンスを持てるためである。

<!-- 
<item><bf>s_dev</bf>: for filesystems which require a block to be mounted
      on, i.e. for <tt>FS_REQUIRES_DEV</tt> filesystems, this is the <tt>i_dev</tt> of the
      block device. For others (called anonymous filesystems) this is an
      integer <tt>MKDEV(UNNAMED_MAJOR, i)</tt> where <tt>i</tt> is the first unset bit in
      <tt>unnamed_dev_in_use</tt> array, between 1 and 255 inclusive. See 
      <tt>fs/super.c:get_unnamed_dev()/put_unnamed_dev()</tt>. It has been suggested
      many times that anonymous filesystems should not use <tt>s_dev</tt> field.
 -->
<item><bf>s_dev</bf>: マウントされるのにブロックを必要とするファイルシステム、つまり <tt>FS_REQUIRES_DEV</tt> なファイルシステムにとっては、このメンバはそのブロックデバイスの <tt>i_dev</tt> である。その他の (匿名ファイルシステムと呼ばれる) ファイルシステムに対しては、これは <tt>MKDEV(UNNAMED_MAJOR, i)</tt> で表される整数である。ただし <tt>i</tt> は、<tt>unnamed_dev_in_use</tt> ビット配列の中で最初の OFF ビットを指す、1 から 255 の範囲の値である。<tt>fs/super.c:get_unnamed_dev()/put_unnamed_dev()</tt> を参照のこと。匿名ファイルシステムが <tt>s_dev</tt> メンバを利用すべきでないということは、これまで何度も提案されてきた。

<!-- 
<item><bf>s_blocksize, s_blocksize_bits</bf>: blocksize and log2(blocksize).
 -->
<item><bf>s_blocksize, s_blocksize_bits</bf>: ブロックサイズとlog2(ブロックサイズ)。

<!-- 
<item><bf>s_lock</bf>: indicates whether superblock is currently locked by
      <tt>lock_super()/unlock_super()</tt>.
 -->
<item><bf>s_lock</bf>: スーパーブロックが、<tt>lock_super()/unlock_super()</tt> によって現在ロックされているかどうかを示す。

<!-- 
<item><bf>s_dirt</bf>: set when superblock is changed, and cleared whenever
      it is written back to disk.
 -->
<item><bf>s_dirt</bf>: スーパーブロックが変更されたときに設定され、ディスクへ書き戻されたときはいつもクリアされる。

<!-- 
<item><bf>s_type</bf>: pointer to <tt>struct file_system_type</tt> of the
      corresponding filesystem. Filesystem's <tt>read_super()</tt> method doesn't need
      to set it as VFS <tt>fs/super.c:read_super()</tt> sets it for you if
      fs-specific <tt>read_super()</tt> succeeds and resets to NULL if it fails.
 -->
<item><bf>s_type</bf>: 関連するファイルシステムの <tt>struct file_system_type</tt> を指す。fs 特有の<tt>read_super()</tt>が成功したときに VFS <tt>fs/super.c:read_super()</tt> が設定し、失敗したとき NULL にリセットするため、ファイルシステムの <tt>read_super()</tt> メソッドは設定する必要がない。

<!-- 
<item><bf>s_op</bf>: pointer to <tt>super_operations</tt> structure which contains
      fs-specific methods to read/write inodes etc. It is the job of
      filesystem's <tt>read_super()</tt> method to initialise <tt>s_op</tt> correctly.
 -->
<item><bf>s_op</bf>: fs 特有のread/write inodeなどのメソッドからなる <tt>super_operations</tt> 構造体へのポインタ。<tt>s_op</tt> を正しく初期化するのは、ファイルシステムの <tt>read_super()</tt> メソッドの仕事である。

<!-- 
<item><bf>dq_op</bf>: disk quota operations.
 -->
<item><bf>dq_op</bf>: ディスククオタ操作。

<!-- 
<item><bf>s_flags</bf>: superblock flags.
 -->
<item><bf>s_flags</bf>: スーパーブロックフラグ。

<!-- 
<item><bf>s_magic</bf>: filesystem's magic number. Used by minix filesystem
      to differentiate between multiple flavours of itself.
 -->
<item><bf>s_magic</bf>: ファイルシステムのマジック番号。minixファイルシステムでは、それ自身の複数バージョンを区別するために使われる。

<!-- 
<item><bf>s_root</bf>: dentry of the filesystem's root. It is the job of
      <tt>read_super()</tt> to read the root inode from the disk and pass it to
      <tt>d_alloc_root()</tt> to allocate the dentry and instantiate it. Some
      filesystems spell "root" other than "/" and so use more generic
      <tt>d_alloc()</tt> function to bind the dentry to a name, e.g. pipefs mounts
      itself on "pipe:" as its own root instead of "/".
 -->
<item><bf>s_root</bf>: ファイルシステムのルートのdentry。ルートの inode をディスクから読み、<tt>d_alloc_root()</tt>を呼んでdentryを割り当てて実体化するために渡すのは、<tt>read_super()</tt> の仕事である。

<!-- 
<item><bf>s_wait</bf>: waitqueue of processes waiting for superblock to be
      unlocked.
 -->
<item><bf>s_wait</bf>: スーパーブロックがロック解除されるのを待つプロセスの待ちキュー。

<!-- 
<item><bf>s_dirty</bf>: a list of all dirty inodes. Recall that if inode
      is dirty (<tt>inode->i_state & I_DIRTY</tt>) then it is on superblock-specific
      dirty list linked via <tt>inode->i_list</tt>.
 -->
<item><bf>s_dirty</bf>: 全てのdirty な inode のリスト。もし inode が汚れて(<tt>inode->i_state & I_DIRTY</tt>)いれば、スーパーブロック特有の<tt>inode->i_list</tt>経由でリンクされた dirty リストにおかれる。

<!-- 
<item><bf>s_files</bf>: a list of all open files on this superblock. Useful
      for deciding whether filesystem can be remounted read-only, see
      <tt>fs/file_table.c:fs_may_remount_ro()</tt> which goes through <tt>sb->s_files</tt> list
      and denies remounting if there are files opened for write
      (<tt>file->f_mode & FMODE_WRITE</tt>) or files with pending 
      unlink (<tt>inode->i_nlink == 0</tt>).
 -->
<item><bf>s_files</bf>: このスーパーブロックでオープンしているファイル全てのリスト。ファイルシステムを read-only で再マウントできるかを判断するときに有用。<tt>sb->s_files</tt> リストをみて、もしファイルが書き込みオープンされている(<tt>file->f_mode & FMODE_WRITE</tt>)か、unlinkが保留されている(<tt>inode->i_nlink == 0</tt>)ファイルがあれば、再マウントを拒否する<tt>fs/file_table.c:fs_may_remount_ro()</tt>を参照すること。 

<!-- 
<item><bf>s_bdev</bf>: for <tt>FS_REQUIRES_DEV</tt>, this points to the block_device
      structure describing the device the filesystem is mounted on.
 -->
<item><bf>s_bdev</bf>: <tt>FS_REQUIRES_DEV</tt> のために、これは ファイルシステムがマウントされているデバイスを表す block_device 構造体を指している。

<!-- 
<item><bf>s_mounts</bf>: a list of all <tt>vfsmount</tt> structures, one for each
      mounted instance of this superblock.
 -->
<item><bf>s_mounts</bf>: 全ての <tt>vfsmount</tt> 構造体のリスト。マウントされたこのスーパーブロックの各インスタンスの??? <!-- 不明: sourceにあたること -->

<!-- 
<item><bf>s_dquot</bf>: more diskquota stuff.
 -->
<item><bf>s_dquot</bf>: ディスククオタ用。
</enum>

<!-- The superblock operations are described in the <tt>super_operations</tt> structure
declared in <tt>include/linux/fs.h</tt>:
 -->
スーパーブロックの操作は、<tt>include/linux/fs.h</tt> で定義されている <tt>super_operations</tt> 構造体に記述されている。

<tscreen><code>
struct super_operations {
        void (*read_inode) (struct inode *);
        void (*write_inode) (struct inode *, int);
        void (*put_inode) (struct inode *);
        void (*delete_inode) (struct inode *);
        void (*put_super) (struct super_block *);
        void (*write_super) (struct super_block *);
        int (*statfs) (struct super_block *, struct statfs *);
        int (*remount_fs) (struct super_block *, int *, char *);
        void (*clear_inode) (struct inode *);
        void (*umount_begin) (struct super_block *);
};
</code></tscreen>

<enum>
<!-- 
<item><bf>read_inode</bf>: reads the inode from the filesystem. It is only
      called from <tt>fs/inode.c:get_new_inode()</tt> from <tt>iget4()</tt> (and therefore
      <tt>iget()</tt>). If a filesystem wants to use <tt>iget()</tt> then <tt>read_inode()</tt> must be
      implemented - otherwise <tt>get_new_inode()</tt> will panic.
      While inode is being read it is locked (<tt>inode->i_state = I_LOCK</tt>). When
      the function returns, all waiters on <tt>inode->i_wait</tt> are woken up. The job
      of the filesystem's <tt>read_inode()</tt> method is to locate the disk block which
      contains the inode to be read and use buffer cache <tt>bread()</tt> function to
      read it in and initialise the various fields of inode structure, for
      example the <tt>inode->i_op</tt> and <tt>inode->i_fop</tt> so that VFS level knows what
      operations can be performed on the inode or corresponding file. 
      Filesystems that don't implement <tt>read_inode()</tt> are ramfs and
      pipefs. For example, ramfs has its own inode-generating function
      <tt>ramfs_get_inode()</tt> with all the inode operations calling it as needed.
 -->
<item><bf>read_inode</bf>: inodeをファイルシステムから読み込む。<tt>iget4()</tt>(したがって、<tt>iget()</tt>)を通して、<tt>fs/inode.c:get_new_inode()</tt> からのみ呼ばれる。もしファイルシステムが<tt>iget()</tt>を使いたいならば、<tt>read_inode()</tt>は実装されないといけない。そうでなければ、<tt>get_new_inode()</tt>はパニックになる。
inodeが読まれている間はロックされる(<tt>inode->i_state = I_LOCK</tt>)。関数から復帰するとき、全ての<tt>inode->i_wait</tt>の待ちは起こされる。ファイルシステムの<tt>read_inode()</tt>メソッドの仕事は、読み込まれる inode からなるディスクブロックを割り当て、バッファーキャッシュ <tt>bread()</tt>関数を使って読み込み，inode 構造体の様々なフィールドが初期化される．
例えば<tt>inode->i_op</tt> と<tt>inode->i_fop</tt> では、VFSレベルが、inode や関連するファイルでなんの操作が行われるかを知っている 
<tt>read_inode()</tt>を実装しないファイルシステムは、ramfsとpipefsである。たとえば、ramfsは、必要になったときに全てのinode の操作が呼ぶ、自身のinode生成関数<tt>ramfs_get_inode()</tt>を持っている。

<!-- <item><bf>write_inode</bf>: write inode back to disk. Similar to
      <tt>read_inode()</tt> in that it needs to locate the relevant block on
      disk and interact with buffer cache by calling
      <tt>mark_buffer_dirty(bh)</tt>. This method is called on dirty inodes
      (those marked dirty with <tt>mark_inode_dirty()</tt>) when the inode needs
      to be sync'd either individually or as part of syncing the
      entire filesystem.
 -->
<item><bf>write_inode</bf>: inode をディスクに書き戻す。<tt>read_inode()</tt>と似て、ディスクに同様なブロックを割り当て、<tt>mark_buffer_dirty(bh)</tt>を呼ぶことで、バッファキャッシュと作用する。このメソッドは、inodeが、それぞれやファイルシステム全体の同期の一部なりで同期される必要があるとき、dirty な inode (<tt>mark_inode_dirty()</tt>によって dirty と印をつけられている)に対して呼ばれる。

<!-- 
<item><bf>put_inode</bf>: called whenever the reference count is decreased.
 -->
<item><bf>put_inode</bf>: リファレンスカウンタが減少させられるときにいつも呼ばれる。

<!-- 
<item><bf>delete_inode</bf>: called whenever both <tt>inode->i_count</tt> and
      <tt>inode->i_nlink</tt> reach 0. Filesystem deletes the on-disk copy of the
      inode and calls <tt>clear_inode()</tt> on VFS inode to "terminate it with
      extreme prejudice".
 -->
<item><bf>delete_inode</bf>: <tt>inode->i_count</tt>と<tt>inode->i_nlink</tt>が0になるときは常に呼ばれる。ファイルシステムは、オンディスクのinodeのコピーを削除し、VFSで<tt>clear_inode()</tt>を呼び出して、「完全に根絶する」。

<!-- ★terminate ... with extreme prejudice：映画 『地獄の黙示録』
（APOCALYPSE NOW, 1979） で大国的傲慢さや民族的偏見を象徴する台詞 
"Terminate with extreme prejudice."。直訳すると「極端な偏見をもってケリ
をつけろ」。http://www.din.or.jp/~tsu2/starcraft/episode/eps6d3.html -->
 -->

<!-- 
<item><bf>put_super</bf>: called at the last stages of <bf>umount(2)</bf> system
      call to notify the filesystem that any private information held by
      the filesystem about this instance should be freed. Typically this
      would <tt>brelse()</tt> the block containing the superblock and <tt>kfree()</tt> any
      bitmaps allocated for free blocks, inodes, etc.
 -->
<item><bf>put_super</bf>: <bf>umount(2)</bf>システムコールの最終段階で呼ばれ、ファイルシステムに対して、このインスタンスについてファイルシステムが保持しているいかなる内部の情報を解放しなければならないことを通知する。典型的にはこれは、スーパーブロックがあるブロックを<tt>brelse()</tt>し、フリーブロックやinodeなどのために割り当てられたビットマップを全て<tt>kfree()</tt>する。
 
<!-- 
<item><bf>write_super</bf>: called when superblock needs to be
      written back to disk. It should find the block containing the
      superblock (usually kept in <tt>sb-private</tt> area) and
      <tt>mark_buffer_dirty(bh)</tt> . It should also clear <tt>sb->s_dirt</tt> flag.
 -->
<item><bf>write_super</bf>: スーパーブロックをディスクに書き戻す必要があるときに呼ばれる。これは、スーパブロック(通常<tt>sb-private</tt>領域にある)と<tt>mark_buffer_dirty(bh)</tt>があるブロックを見つけなければならない。これはまた、<tt>sb->s_dirt</tt>フラグをクリアする。

<!-- 
<item><bf>statfs</bf>: implements <bf>fstatfs(2)/statfs(2)</bf> system calls. Note
      that the pointer to <tt>struct statfs</tt> passed as argument is a kernel
      pointer, not a user pointer so we don't need to do any I/O to
      userspace. If not implemented then <tt>statfs(2)</tt> will fail with <tt>ENOSYS</tt>.
 -->
<item><bf>statfs</bf>: <bf>fstatfs(2)/statfs(2)</bf>システムコールの実装。引数として渡される<tt>struct stats</tt>へのポインタは、ユーザポインタではなくカーネルポインタであるため、ユーザ空間へのI/Oが不必要であることに注意すること。もし実装されていなければ、<tt>statfs(2)</tt>は<tt>ENOSYS</tt>で失敗する。

<!-- 
<item><bf>remount_fs</bf>: called whenever filesystem is being remounted.
 -->
<item><bf>remount_fs</bf>: ファイルシステムを再マウントするときには必ず呼ばれる。

<!-- 
<item><bf>clear_inode</bf>: called from VFS level <tt>clear_inode()</tt>. Filesystems
      that attach private data to inode structure (via <tt>generic_ip</tt> field) must
      free it here.
 -->
<item><bf>clear_inode</bf>: VFSレベル<tt>clear_inode()</tt>から呼ばれる。プライベートデータをinode構造体へ(<tt>generic_ip</tt>メンバを経由して)割り当てるファイルシステムは、ここで解放されなければならない。

<!-- 
<item><bf>umount_begin</bf>: called during forced umount to notify the
      filesystem beforehand, so that it can do its best to make sure that
      nothing keeps the filesystem busy. Currently used only by NFS. This
      has nothing to do with the idea of generic VFS level forced umount
      support.
 -->
<item><bf>umount_begin</bf>: なにもファイルシステムをビジーにしないことを確かめるのに全力を尽くすことができるように、あらかじめファイルシステムへ通知するため、umountを強制する間に呼ばれる。現在、NFSでのみ使われる。これは、一般的なVFSレベルの強制umountサポートとの関係はない。
</enum>

<!-- 
So, let us look at what happens when we mount a on-disk (<tt>FS_REQUIRES_DEV</tt>)
filesystem. The implementation of the <bf>mount(2)</bf> system call is in
<tt>fs/super.c:sys_mount()</tt> which is the just a wrapper that copies the options,
filesystem type and device name for the <tt>do_mount()</tt> function which does the
real work:
 -->
それでは、on-disk (<tt>FS_REQUIRES_DEV</tt>)ファイルシステムをマウントするときに起ることを見ていきましょう。
<bf>mount(2)</bf>システムコールの実装は、<tt>fs/super.c:sys_mount()</tt> にあり、これは実際の処理を行う <tt>do_mount()</tt> 関数にオプションとファイルシステムタイプやデバイス名をコピーする単なるラッパーになっています。

<enum>
<!-- 
<item>Filesystem driver is loaded if needed and its module's reference count
      is incremented. Note that during mount operation, the filesystem
      module's reference count is incremented twice - once by <tt>do_mount()</tt>
	  calling <tt>get_fs_type()</tt> and once by <tt>get_sb_dev()</tt> calling <tt>get_filesystem()</tt>
	  if <tt>read_super()</tt> was successful. The first increment is to prevent
      module unloading while we are inside <tt>read_super()</tt> method and the second
      increment is to indicate that the module is in use by this mounted
      instance. Obviously, <tt>do_mount()</tt> decrements the count before returning, so
      overall the count only grows by 1 after each mount.
 -->
<item>ファイルシステムのドライバは必要になったときにロードされ、モジュールの参照カウントが増分される。ここで、マウントの最中にファイルシステムのモジュールについての参照カウントについては、2つ増分されることに注意が必要である。<tt>do_mount()</tt>が<tt>get_fs_type()</tt>を呼ぶときに1回、<tt>read_super()</tt>が成功したならば、<tt>get_sb_dev()</tt>が<tt>get_filesystem()</tt>を呼ぶときに1回である。1つめの増分は、<tt>read_super()</tt>の内部において、モジュールがアンロードされるのを避けるためであり、2つめの増分は、マウントされたインスタンスによってモジュールが使用中であることを示すためのものである。明らかに、各マウント後の全体でのカウントは1つだけ増えることから、<tt>do_mount()</tt>は戻る前にカウンタを減少させるのである。

<!-- 
<item>Since, in our case, <tt>fs_type->fs_flags & FS_REQUIRES_DEV</tt> is true, the
      superblock is initialised by a call to <tt>get_sb_bdev()</tt> which obtains
      the reference to the block device and interacts with the filesystem's
      <tt>read_super()</tt> method to fill in the superblock. If all goes well, the
      <tt>super_block</tt> structure is initialised and we have an extra reference 
      to the filesystem's module and a reference to the underlying block
      device.
 -->
<item>我々の場合、<tt>fs_type->fs_flags & FS_REQUIRES_DEV</tt>が真であるなら、ブロックデバイスへのリファレンスを取得し、ファイルシステムの<tt>read_super()</tt>メソッドと連携してスーパーブロックを埋める<tt>get_sb_bdev()</tt>を呼ぶことで、スーパーブロックが初期化される。全てがうまく行けば、<tt>super_block</tt>構造体は初期化され、ファイルシステムモジュールへのextra参照と、下にあるブロックデバイスへの参照を得ることになる。

<!-- 
<item>A new <tt>vfsmount</tt> structure is allocated and linked to <tt>sb->s_mounts</tt> list
      and to the global <tt>vfsmntlist</tt> list. The <tt>vfsmount</tt> field <tt>mnt_instances</tt>
	  allows to find all instances mounted on the same superblock as this
      one. The <tt>mnt_list</tt> field allows to find all instances for all
      superblocks system-wide.  The <tt>mnt_sb</tt> field
      points to this superblock and <tt>mnt_root</tt> has a new reference to the
      <tt>sb->s_root</tt> dentry.
 -->
<item> 新しい<tt>vfsmount</tt>構造体が割り当てられ、<tt>sb->s_mounts</tt>リストとグローバルな<tt>vfsmntlist</tt>リストへリンクされる。<tt>vfsmount</tt>のメンバの<tt>mnt_instances</tt>は全ての同じスーパーブロックにマウントされているインスタンスを見つけられるようにする。
<tt>mnt_list</tt>メンバは、システム全体の全てのスーパーブロックに対して、全てのインスタンスを見つけることができるようにする。<tt>mnt_sb</tt>メンバはこのスーパーブロックを指し、<tt>mnt_root</tt>は<tt>sb->s_root</tt> dentry への新しい参照を持つ。
</enum>

<!-- 
<sect1>Example Virtual Filesystem: pipefs<p>
 -->
<sect1>仮想ファイルシステムの例: pipefs<p>

<!-- 
As a simple example of Linux filesystem that does not require a block device
for mounting, let us consider pipefs from <tt>fs/pipe.c</tt>. The filesystem's preamble
is rather straightforward and requires little explanation:
 -->
マウントにブロックデバイスが必要ない簡単な Linux ファイルシステムの例として、<tt>fs/pipe.c</tt>からpipefsを取り上げましょう。ファイルシステムの前提部分はかなり簡単で、ちょっとした説明で十分です。

<tscreen><code>
static DECLARE_FSTYPE(pipe_fs_type, "pipefs", pipefs_read_super,
        FS_NOMOUNT|FS_SINGLE);

static int __init init_pipe_fs(void)
{
        int err = register_filesystem(&amp;pipe_fs_type);
        if (!err) {
                pipe_mnt = kern_mount(&amp;pipe_fs_type);
                err = PTR_ERR(pipe_mnt);
                if (!IS_ERR(pipe_mnt))
                        err = 0;
        }
        return err;
}

static void __exit exit_pipe_fs(void)
{
        unregister_filesystem(&amp;pipe_fs_type);
        kern_umount(pipe_mnt);
}

module_init(init_pipe_fs)
module_exit(exit_pipe_fs)
</code></tscreen>

<!-- 
The filesystem is of type <tt>FS_NOMOUNT|FS_SINGLE</tt>, which means it cannot be
mounted from userspace and can only have one superblock system-wide. The
<tt>FS_SINGLE</tt> file also means that it must be mounted via <tt>kern_mount()</tt> after
it is successfully registered via <tt>register_filesystem()</tt>, which is exactly
what happens in <tt>init_pipe_fs()</tt>. The only bug in this function is that if
<tt>kern_mount()</tt> fails (e.g. because <tt>kmalloc()</tt> failed in <tt>add_vfsmnt()</tt>) then the
filesystem is left as registered but module initialisation fails. This will
cause <bf>cat /proc/filesystems</bf> to Oops. (have just sent a patch to Linus
mentioning that although this is not a real bug today as pipefs can't be
compiled as a module, it should be written with the view that in the future
it may become modularised).
 -->
このファイルシステムは、ユーザ空間からマウントできず、システム全体で一つのスーパーブロックのみ持てることを意味する<tt>FS_NOMOUNT|FS_SINGLE</tt>型になっています。
<tt>FS_SINGLE</tt>であるファイルは同様に、<tt>register_filesystem()</tt>を使って登録成功したあとに、<tt>kern_mount()</tt>を使ってマウントされなければならないことを意味しています。これは、まさに、<tt>init_pipe_fs()</tt>で行われることです。この関数の唯一のバグは、もし<tt>kern_mount()</tt>が失敗した場合(例えば、<tt>kmalloc()</tt>が<tt>add_vfsmnt()</tt>中で失敗したときなど)に、ファイルシステムは登録された状態で残りますが、モジュールの初期化は失敗になることです。
これは、<bf>cat /proc/filesystems</bf>の Oops エラーの原因になります。(丁度 Linus に、これを知らせるパッチを送った。pipefs はモジュールとしてコンパイルできないためこれは真のバグではないが、将来モジュールになるときを考えて書かれるべきだと思う)。

<!-- 
The result of <tt>register_filesystem()</tt> is that <tt>pipe_fs_type</tt> is linked into
the <tt>file_systems</tt> list so one can read <tt>/proc/filesystems</tt> and find "pipefs"
entry in there with "nodev" flag indicating that <tt>FS_REQUIRES_DEV</tt> was not set.
The <tt>/proc/filesystems</tt> file should really be enhanced to support all the new
<tt>FS_</tt> flags (and I made a patch to do so) but it cannot be done because it will
break all the user applications that use it. Despite Linux kernel interfaces
changing every minute (only for the better) when it comes to the userspace
compatibility, Linux is a very conservative operating system which allows
many applications to be used for a long time without being recompiled.
 -->
<tt>register_filesystem()</tt>の結果として、<tt>pipe_fs_type</tt>が<tt>fle_systems</tt>リストにリンクされることになります。つまり<tt>/proc/filesystems</tt>を読み出して、<tt>FS_REQUIRES_DEV</tt>が設定されていないことを示す「nodev」フラグつきで「pipefs」が登録されているのを見つけられることになります。<tt>/proc/filesystems</tt>ファイルは、新しい<tt>FS_</tt>フラグを全てサポートするよう、まさに機能強化されるべきです(そして、私はそのパッチを作りました)。しかし、これを使う全てのユーザのアプリケーションが動かなくなるため、今だ実行することができません。 
Linux カーネルインターフェースが随時変更されている(単に良くするために)にも関わらず、ユーザ空間での互換性に及ぶとなると、Linux はとても保守的なオペレーティングシステムとなり、長い期間再コンパイルをしないで多くのアプリケーションが使えるようにするのです。

<!-- 
The result of <tt>kern_mount()</tt> is that:
 -->
<tt>kern_mount()</tt>の結果は次のようになります。

<enum>
<!-- <item>A new unnamed (anonymous) device number is allocated by setting a bit in
      <tt>unnamed_dev_in_use</tt> bitmap; if there are no more bits then <tt>kern_mount()</tt>
	  fails with <tt>EMFILE</tt>.
 -->
<item>新たな無名の(anonymous)デバイス番号が割り当てられ、<tt>unnamed_dev_in_use</tt>ビットマップのビットが設定される。もし割り当てるビットがなければ、<tt>kern_mount()</tt>は<tt>EMFILE</tt>で失敗する。

<!-- 
<item>A new superblock structure is allocated by means of <tt>get_empty_super()</tt>.
      The <tt>get_empty_super()</tt> function walks the list of superblocks headed
      by <tt>super_block</tt> and looks for empty entry, i.e. <tt>s->s_dev == 0</tt>. If no
      such empty superblock is found then a new one is allocated using
      <tt>kmalloc()</tt> at <tt>GFP_USER</tt> priority. The maximum system-wide number of
      superblocks is checked in <tt>get_empty_super()</tt> so if it starts failing,
      one can adjust the tunable <tt>/proc/sys/fs/super-max</tt>.
 -->
<item><tt>get_empty_super()</tt>によって、新たなスーパーブロック構造体が割り当てられる。<tt>get_empty_super()</tt>関数は、<tt>super_block</tt>によって先頭を示されるスーパーブロックのリストを見て、<tt>s->s_dev == 0</tt>となる空のエントリーを探す。

<!-- 
<item>A filesystem-specific <tt>pipe_fs_type->read_super()</tt> method, i.e.
      <tt>pipefs_read_super()</tt>, is invoked which allocates root inode and root
      dentry <tt>sb->s_root</tt>, and sets <tt>sb->s_op</tt> to be <tt>&amp;pipefs_ops</tt>.
 -->
<item> ファイルシステム特有の<tt>pipe_fs_type->read_super()</tt>メソッド(つまり<tt>pipefs_read_super()</tt>だが)が起動され、ルートのinodeとルートのdentryとなる <tt>sb->s_root</tt>を割り当て、<tt>sb->s_op</tt>を<tt>&amp;pipefs_ops</tt>になるよう設定する。

<!-- 
<item>Then <tt>kern_mount()</tt> calls <tt>add_vfsmnt(NULL, sb->s_root, "none")</tt> which
      allocates a new <tt>vfsmount</tt> structure and links it into <tt>vfsmntlist</tt> and
      <tt>sb->s_mounts</tt>.
 -->
<item>そして <tt>kern_mount()</tt> が 新しい<tt>vfsmount</tt>構造体を割り当て、<tt>vfsmntlist</tt>と<tt>sb->s_mounts</tt> へリンクする<tt>add_vfsmnt(NULL, sb->s_root, "none")</tt> を呼ぶ。

<!-- 
<item>The <tt>pipe_fs_type->kern_mnt</tt> is set to this new <tt>vfsmount</tt> structure and
      it is returned. The reason why the return value of <tt>kern_mount()</tt> is a
      <tt>vfsmount</tt> structure is because even <tt>FS_SINGLE</tt> filesystems can be mounted
      multiple times and so their <tt>mnt->mnt_sb</tt> will point to the same thing
      which would be silly to return from multiple calls to <tt>kern_mount()</tt>.
 -->
<item><tt>pipe_fs_type->kern_mnt</tt>は新しい<tt>vfsmount</tt>構造体に設定されて戻る。<tt>kern_mount()</tt>返り値が<tt>vfsmount</tt>構造体になっているのは、<tt>FS_SINGLE</tt>のファイルシステムでさえ複数回マウントできることから、<tt>mnt->mnt_sb</tt>は<tt>kern_mount()</tt>の複数回の呼び出しからの戻りであったとしても同じものを指して戻るためである。
</enum>

<!-- 
Now that the filesystem is registered and inkernel-mounted we can use it.
The entry point into the pipefs filesystem is the <bf>pipe(2)</bf> system call,
implemented in arch-dependent function <tt>sys_pipe()</tt> but the real work is done
by a portable <tt>fs/pipe.c:do_pipe()</tt> function. Let us look at <tt>do_pipe()</tt> then.
The interaction with pipefs happens when <tt>do_pipe()</tt> calls <tt>get_pipe_inode()</tt>
to allocate a new pipefs inode. For this inode, <tt>inode->i_sb</tt> is set to
pipefs' superblock <tt>pipe_mnt->mnt_sb</tt>, the file operations <tt>i_fop</tt> is set to
<tt>rdwr_pipe_fops</tt> and the number of readers and writers (held in <tt>inode->i_pipe</tt>)
is set to 1. The reason why there is a separate inode field <tt>i_pipe</tt> instead
of keeping it in the <tt>fs-private</tt> union is that pipes and FIFOs share the same
code and FIFOs can exist on other filesystems which use the other access
paths within the same union which is very bad C and can work only by pure
luck. So, yes, 2.2.x kernels work only by pure luck and will stop working
as soon as you slightly rearrange the fields in the inode.
 -->
これでファイルシステムは登録され、私たちが使えるようにカーネル内にマウントされました。pipefsファイルシステムのエントリポイントは、<bf>pipe(2)</bf>システムコールとなり、これはアーキテクチャ依存の<tt>sys_pipe()</tt>へ実装されていますが、実際にはアーキテクチャ非依存の<tt>fs/pipe.c:do_pipe()</tt>関数で処理されます。これから<tt>do_pipe()</tt>を見ていこうと思います。pipefs との相互作用は、<tt>do_pipe()</tt>が<tt>get_pipe_inode()</tt>を新しい pipefs の inode を割り当てるために呼び出したときに起こります。この inode のために、<tt>inode->i_sb</tt>は、pipefs のスーパーブロック<tt>pipe_mnt->mnt_sb</tt>へ設定されます。そしてファイルの操作<tt>i_fop</tt>は<tt>rdwr_pipe_fops</tt>に設定されて、(<tt>inode->i_pipe</tt>に保持される)読み書きする者の数は 1 に設定されます。<tt>fs-private</tt> 共用体へ保存する代りに、別の inode メンバ <tt>i_pipe</tt> がある理由は、pipe と FIFO が同じコードを共有しているためと、同じ共用体の中の他のアクセスパスを使う複数の FIFO が他のファイルシステム上に存在できるようにあうるためです。これはとても悪い C の使い方であり、純粋に運だけで動きます。そのため、そう、2.2.x カーネルは、運だけで動いているのです。inode のフィールドをすこし調整すればすぐに処理を停止してしまうことになるでしょう。

<!-- 
Each <bf>pipe(2)</bf> system call increments a reference count on the <tt>pipe_mnt</tt>
mount instance.
 -->
<bf>pipe(2)</bf>システムコール毎に、<tt>pipe_mnt</tt>マウントインスタンスの参照カウンタは増分されます。

<!-- 
Under Linux, pipes are not symmetric (bidirection or STREAM pipes), i.e.
two sides of the file have different <tt>file->f_op</tt> operations - the
<tt>read_pipe_fops</tt> and <tt>write_pipe_fops</tt> respectively. The write on read side
returns <tt>EBADF</tt> and so does read on write side.
 -->
Linux においては パイプは対称（双方向あるいはSTREAM pipe)ではなく、つまりファイルの両側で、<tt>read_pipe_fops</tt>と<tt>write_pipe_fops</tt>それぞれの <tt>file->f_op</tt> 操作は持てません。

<!-- 
<sect1>Example Disk Filesystem: BFS<p>
 -->
<sect1>ディスクファイルシステムの例:BFS<p>

<!-- 
As a simple example of ondisk Linux filesystem, let us consider BFS. The
preamble of the BFS module is in <tt>fs/bfs/inode.c</tt>:
 -->
簡単なディスク上の Linux ファイルシステムの例としてBFSを考えてみましょう。BFSモジュールのプリアンブルは<tt>fs/bfs/inode.c</tt>にあり、

<tscreen><code>
static DECLARE_FSTYPE_DEV(bfs_fs_type, "bfs", bfs_read_super);

static int __init init_bfs_fs(void)
{
        return register_filesystem(&amp;bfs_fs_type);
}

static void __exit exit_bfs_fs(void)
{
        unregister_filesystem(&amp;bfs_fs_type);
}

module_init(init_bfs_fs)
module_exit(exit_bfs_fs)
</code></tscreen>
となっています。

<!-- 
A special fstype declaration macro <tt>DECLARE_FSTYPE_DEV()</tt> is used which
sets the <tt>fs_type->flags</tt> to <tt>FS_REQUIRES_DEV</tt> to signify that BFS requires a
real block device to be mounted on.
 -->
特別なfstype 定義マクロ<tt>DECLARE_FSTYPE_DEV()</tt>が使われて、<tt>fs_type->flags</tt>を <tt>FS_REQUIRES_DEV</tt>に設定され、BFS がマウントする実際のブロックデバイスが必要であることを示しています。

<!-- 
The module's initialisation function registers the filesystem with VFS and
the cleanup function (only present when BFS is configured to be a module)
unregisters it.
 -->
モジュールの初期化関数はファイルシステムと(BFSがモジュールとして設定されたときのみ存在する)登録解除を行う解除関数をVFSに登録します。

<!-- 
With the filesystem registered, we can proceed to mount it, which would
invoke out <tt>fs_type->read_super()</tt> method which is implemented in
<tt>fs/bfs/inode.c:bfs_read_super().</tt> It does the following:
 -->
ファイルシステムの登録を行うことで、マウントを進めることができます。マウントでは<tt>fs/bfs/inode.c:bfs_read_super()</tt> に実装されている <tt>fs_type->read_super()</tt>メソッドが起動されます。この関数は次のような処理を行います。

<enum>
<!-- 
<item><tt>set_blocksize(s->s_dev, BFS_BSIZE)</tt>: since we are about to interact
      with the block device layer via the buffer cache, we must initialise a few
      things, namely set the block size and also inform VFS via fields
      <tt>s->s_blocksize</tt> and <tt>s->s_blocksize_bits</tt>.
 -->
<item><tt>set_blocksize(s->s_dev, BFS_BSIZE)</tt>: ブロック型デバイス層とバッファキャッシュを通して相互作用しようとしていることから、二つ三つの初期化を行う必要がある。すなわち、ブロックサイズを設定して、さらに <tt>s->s_blocksize</tt> と <tt>s->s_blocksize_bits</tt> メンバを通じて VFS へ通知するのだ。

<!-- 
<item><tt>bh = bread(dev, 0, BFS_BSIZE)</tt>: we read block 0 of the device
      passed via <tt>s->s_dev</tt>. This block is the filesystem's superblock.
 -->
<item><tt>bh = bread(dev, 0, BFS_BSIZE)</tt>: デバイスのブロック０を読み、<tt>s->s_dev</tt> を通じて渡す。このブロックはファイルシステムのスーパーブロックである。

<!-- 
<item>Superblock is validated against <tt>BFS_MAGIC</tt> number and, if valid, stored
      in the sb-private field <tt>s->su_sbh</tt> (which is really <tt>s->u.bfs_sb.si_sbh</tt>).
 -->
<item>スーパーブロックは<tt>BFS_MAGIC</tt>番号に対して正当性を確認し、sbプライベートメンバ<tt>s->su_sbh</tt>へ格納する(実際は<tt>s->u.bfs_sb.si_sbh</tt>である)。

<!-- 
<item>Then we allocate inode bitmap using <tt>kmalloc(GFP_KERNEL)</tt> and clear all
      bits to 0 except the first two which we set to 1 to indicate that we
      should never allocate inodes 0 and 1. Inode 2 is root and the
      corresponding bit will be set to 1 a few lines later anyway - the
      filesystem should have a valid root inode at mounting time!
 -->
<item>そして、 inode ビットマップを<tt>kmalloc(GFP_KERNEL)</tt> を使って割り当て、1に設定される最初の2つを除く全てのビットを0に設定する。これは、inode 0と1をずっと割り当てないことを示すためである。inode 1はルートであり、関連するビットはいずれ数行後に1に設定される。というのは、ファイルシステムはマウントされるときには必ず妥当なルート inode を持ってるべきものだからだ。

<!-- 
<item>Then we initialise <tt>s->s_op</tt>, which means that we can from this point
      invoke inode cache via <tt>iget()</tt> which results in <tt>s_op->read_inode()</tt> to
      be invoked. This finds the block that contains the specified (by
      <tt>inode->i_ino</tt> and <tt>inode->i_dev</tt>) inode and reads it in. If we fail to
      get root inode then we free the inode bitmap and release superblock
      buffer back to buffer cache and return NULL. If root inode was read OK,
      then we allocate a dentry with name <tt>/</tt> (as becometh root) and
      instantiate it with this inode.
 -->
<item> そして<tt>s->s_op</tt>を初期化する。これは<tt>s_op->read_inode()</tt>が起動される結果として<tt>iget()</tt>を通じて、この時点から inode キャッシュを呼び出すことができる。これは、(<tt>inode->i_ino</tt>と<tt>inode->i_dev</tt>による)特定のinode からなるブロックを見つけて読み込む。
もしルート inode の取得が失敗したら、inode ビットマップを解放し、バッファーキャッシュの背後にあるスーパーブロックバッファーを解放して、NULL を返す。もしルート inode の読み込みがOKであれば、(ルートとなる)<tt>/</tt>という名前のdentryを割り当て、この inode を実体化する。

<!-- 
<item>Now we go through all inodes on the filesystem and read them all in
      order to set the corresponding bits in our internal inode bitmap and
      also to calculate some other internal parameters like the offset of
      last inode and the start/end blocks of last file. Each inode we read
      is returned back to inode cache via <tt>iput()</tt> - we don't hold a reference
      to it longer than needed.
 -->
<item>さて、ファイルシステムの全ての inode を見て、内部の inode ビットマップの関連するビットを設定するために、それを全て読み込む。そして、最後の inode のオフセットや最後のファイルの開始/終了ブロックのようなその他の内部パラメータを計算する。読み込む各 inode は inode キャッシュへ <tt>iput()</tt>を通じて戻される。そう、必要以上に長く参照を保持できないのだ。

<!-- 
<item>If the filesystem was not mounted read-only, we mark the superblock
      buffer dirty and set <tt>s->s_dirt</tt> flag (TODO: why do I do this?
      Originally, I did it because <tt>minix_read_super()</tt> did but neither minix
      nor BFS seem to modify superblock in the <tt>read_super()</tt>).
 -->
<item>もしファイルシステムが読み込み専用でマウントされなければ、スーパーブロックバッファをdirtyと印をつけ、<tt>s->s_dirt</tt>フラグを設定する(TODO: なぜこれをやるのか? 普通は、これは<tt>minix_read_super()</tt>がやるからなのだが、minixもBFS も<tt>read_super()</tt>でスーパーブロックを書き換えていないようなのだ)。

<!-- 
<item>All is well so we return this initialised superblock back to the caller
      at VFS level, i.e. <tt>fs/super.c:read_super()</tt>.
 -->
<item>全てがうまく行けば、VFS層の呼び出し、つまり<tt>fs/super.c:read_super()</tt>へ、この初期化されたスーパーブロックを返す。
</enum>

<!-- 
After the <tt>read_super()</tt> function returns successfully, VFS obtains the
reference to the filesystem module via call to <tt>get_filesystem(fs_type)</tt> in
<tt>fs/super.c:get_sb_bdev()</tt> and a reference to the block device.
 -->
<tt>read_super()</tt>関数が成功して戻った後、<tt>fs/super.c:get_sb_bdev()</tt>の<tt>get_filesystem(fs_type)</tt>呼び出しを通じて VFS はファイルシステムモジュールへの参照とブロックデバイスへの参照を得ます。

<!-- 
Now, let us examine what happens when we do I/O on the filesystem. We already
examined how inodes are read when <tt>iget()</tt> is called and how they are released
on <tt>iput().</tt> Reading inodes sets up, among other things, <tt>inode->i_op</tt> and
<tt>inode->i_fop</tt>; opening a file will propagate <tt>inode->i_fop</tt> into <tt>file->f_op</tt>.
 -->
ここで、ファイルシステムへ I/O を行うときになにが起るかを考えてみましょう。すでに <tt>iget()</tt>が呼ばれるときにinodeがどのように読まれるか、また<tt>iput()</tt>でどのように解放されるかは見てきました。<!-- 20020801みうら途中 -->
 inode の読み込みは、他のことに混じって<tt>inode->i_op</tt>と<tt>inode->i_fop</tt>の事前設定を行うことになります。ファイルのオープンは、<tt>inode->i_fop</tt>から<tt>file->f_op</tt>へ伝搬します。

<!-- 
Let us examine the code path of the <bf>link(2)</bf> system call. The implementation
of the system call is in <tt>fs/namei.c:sys_link()</tt>:
 -->
さて、<bf>link(2)</bf>システムコールのコードの通り道をみていきましょう。システムコールの実装は<tt>fs/namei.c:sys_link()</tt>にあります。

<enum>
<!-- 
<item>The userspace names are copied into kernel space by means of <tt>getname()</tt>
      function which does the error checking.
 -->
<item> ユーザ空間の名前はカーネル空間へエラーチェックを行う<tt>getname()</tt>関数を使ってコピーされる。

<!-- 
<item>These names are nameidata converted using <tt>path_init()/path_walk()</tt>
      interaction with dcache. The result is stored in <tt>old_nd</tt> and <tt>nd</tt>
	  structures.
 -->
<item> これらの名前は<tt>path_init()/path_walk()</tt>を使って nameidata に変換され、dcache と相互作用する。結果は <tt>old_nd</tt> と<tt>nd</tt>構造体へ格納される。

<!-- 
<item>If <tt>old_nd.mnt != nd.mnt</tt> then "cross-device link" <tt>EXDEV</tt> is returned - 
      one cannot link between filesystems, in Linux this translates into -
      one cannot link between mounted instances of a filesystem (or, in
      particular between filesystems).
 -->
<item> <tt>old_nd.mnt != nd.mnt</tt>であったら、「クロスデバイスリンク」<tt>EXDEV</tt>が返される。ファイルシステムを超えたリンクはできないが、Linux ではそれをファイルシステムのマウントされたインスタンス(あるいは特定のファイルシステム間)を超えたリンクができないと解釈している。

<!-- 
<item>A new dentry is created corresponding to <tt>nd</tt> by <tt>lookup_create()</tt> .
 -->
<item> 新しい dentry が作られ<tt>nd</tt>へ<tt>lookup_create()</tt>によって関連づけられる。

<!-- 
<item>A generic <tt>vfs_link()</tt> function is called which checks if we can
      create a new entry in the directory and invokes the <tt>dir->i_op->link()</tt>
	  method which brings us back to filesystem-specific
      <tt>fs/bfs/dir.c:bfs_link()</tt> function.
 -->
<item> 一般的な<tt>vfs_link()</tt>関数が呼ばれ、ディレクトリに新しいエントリーを作ることができるかどうかチェックする。そして、<tt>dir->i_op->link()</tt>メソッドを呼び出す。これはファイルシステムに特有の<tt>fs/bfs/dir.c:bfs_link()</tt>関数を呼び出すことになる。

<!-- 
<item>Inside <tt>bfs_link()</tt>, we check if we are trying to link a directory and
      if so, refuse with <tt>EPERM</tt> error. This is the same behaviour as standard (ext2).
 -->
<item><tt>bfs_link()</tt>の内部では、ディレクトリをリンクしようとしていないかチェックし、もしそうであれば<tt>EPERM</tt>エラーで拒否する。これは標準ファイルシステム(ext2)を同じ挙動である。

<!-- 
<item>We attempt to add a new directory entry to the specified directory
      by calling the helper function <tt>bfs_add_entry()</tt> which goes through all
      entries looking for unused slot (<tt>de->ino == 0</tt>) and, when found, writes
      out the name/inode pair into the corresponding block and marks it
      dirty (at non-superblock priority).
 -->
<item>へルパー関数<tt>bfs_add_entry()</tt>を呼び出して新しいディレクトリエントリを特定のディレクトリに追加しようとする。この関数は、使用していないスロット(<tt>de->ino == 0</tt>)を探して全てのエントリーを見ていき、見つかったならば、 name/inode の対を関連するブロックへ書き出して、 dirtyの印を(スーパブロック以外の優先度で)つける。

<!-- 
<item>If we successfully added the directory entry then there is no way
      to fail the operation so we increment <tt>inode->i_nlink</tt>, update
      <tt>inode->i_ctime</tt> and mark this inode dirty as well as instantiating the
      new dentry with the inode.
 -->
<item> もし、ディレクトリエントリの追加が成功したら、操作が失敗することはないため、<tt>inode->i_nlink</tt>を増分し、<tt>inode->i_ctime</tt>を更新して、inode と一緒にインスタンス化した新しいdentryと同様に、この inode を dirty とマークする。
</enum>

<!-- 
Other related inode operations like <tt>unlink()/rename()</tt> etc work in a similar
way, so not much is gained by examining them all in details.
 -->
<tt>unlink()/rename()</tt>のような他の関連 inode 操作も、同じようなやり方で働きます。したがって、あまりメリットがないため、ここで全ての詳細を扱うことはしません。

<!-- 
<sect1>Execution Domains and Binary Formats<p>
 -->
<sect1>実行ドメインとバイナリフォーマット<p>

<!-- 
Linux supports loading user application binaries from disk. More
interestingly, the binaries can be stored in different formats and the
operating system's response to programs via system calls can deviate from
norm (norm being the Linux behaviour) as required, in order to emulate
formats found in other flavours of UNIX (COFF, etc) and also to emulate
system calls behaviour of other flavours (Solaris, UnixWare, etc). This is
what execution domains and binary formats are for.
 -->
Linux は、ディスクからのユーザアプリケーションバイナリの読み込みをサポートしています。もっと面白いことには、そのバイナリは、他のフォーマットで保存されていても構いません。プログラムに対するシステムコールを通じたオペレーティングシステムの反応は、
他の UNIX に見られるフォーマット(COFFなど)をエミュレートし、さらに他のタイプ(Solaris, Unixwareなど)のシステムコールの振る舞いをエミュレートするために、必要ならば、標準(Linux の振る舞いをする標準)から外れることができます。これが、実行ドメインとバイナリフォーマットが必要になる理由になっています。

<!-- 
Each Linux task has a personality stored in its <tt>task_struct</tt> (<tt>p->personality</tt>).
The currently existing (either in the official kernel or as addon patch)
personalities include support for FreeBSD, Solaris, UnixWare, OpenServer and
many other popular operating systems. 
The value of <tt>current->personality</tt> is split into two parts:
 -->
各 Linux のタスクは、<tt>task_struct</tt>(<tt>p->personality</tt>)のなかにそれぞれのパーソナリティを持っています。現在(正式なカーネルも追加パッチでも含め)存在するパーソナリティには、FreeBSD、Solaris、UnixWare、OpenServerのサポートを含み、さらに他のメジャーなオペレーティングシステムもあります。
その <tt>current->personality</tt> の値は2つの部分に分かれます。

<enum>
<!-- 
<item>high three bytes - bug emulation: <tt>STICKY_TIMEOUTS</tt>, <tt>WHOLE_SECONDS</tt>, etc.
<item>low byte - personality proper, a unique number.
 -->
<item>高位の3バイト - バグエミュレーション: <tt>STICKY_TIMEOUTS</tt>, <tt>WHOLE_SECONDS</tt>など
<item>低位の1バイト - パーソナリティに固有な番号
</enum>

<!-- 
By changing the personality, we can change
the way the operating system treats certain system calls, for example
adding a <tt>STICKY_TIMEOUT</tt> to <tt>current->personality</tt> makes <bf>select(2)</bf> system call
preserve the value of last argument (timeout) instead of storing the
unslept time. Some buggy programs rely on buggy operating systems (non-Linux)
and so Linux provides a way to emulate bugs in cases where the source code
is not available and so bugs cannot be fixed.
 -->
パーソナリティの変更により、私たちはオペレーティングシステムがシステムコールを取り扱う方法を変えることができます。たとえば、<tt>STICKY_TIMEOUT</tt>を<tt>current->personality</tt>へ与えることで、<tt>select(2)</tt>システムコールは、残り時間を保存するかわりに、最後の引数(タイムアウト)の値を維持します。プログラムの中には(Linuxにはない)バグのあるオペレーティングシステムに依存したバグのあるものが存在するため、ソースコードが入手できずバグを改修できない場合のために、Linux はバグをエミュレートする方法を提供しているのです。

<!-- 
Execution domain is a contiguous range of personalities implemented by a
single module. Usually a single execution domain implements a single
personality but sometimes it is possible to implement "close" personalities
in a single module without too many conditionals.
 -->
実行ドメインは、パーソナリティの延長線上にあり、一つのモジュールとして実装されています。通常一つの実行ドメインは一つのパーソナリティを実装していますが、なかには、それほど多くない条件を満たすことで一つのモジュールの中に「閉じた」複数のパーソナリティを実装することもできます。

<!-- 
Execution domains are implemented in <tt>kernel/exec_domain.c</tt> and were completely
rewritten for 2.4 kernel, compared with 2.2.x. The list of execution domains
currently supported by the kernel, along with the range of personalities
they support, is available by reading the <tt>/proc/execdomains</tt> file. Execution
domains, except the <tt>PER_LINUX</tt> one, can be implemented as dynamically
loadable modules.
 -->
実行ドメインは<tt>kernel/exec_domain.c</tt>に実装され、2.4 カーネルで 2.2.x から完全に書き直されました。サポートしているパーソナリティの種類に加え、カーネルが現在サポートしている実行ドメインのリストは、<tt>/proc/execdomains</tt>ファイルを読み出すことで得ることができます。<tt>PER_LINUX</tt> を除く実行ドメインは、動的に読み込まれるモジュールとして実装できます。

<!-- 
The user interface is via <bf>personality(2)</bf> system call, which sets the current
process' personality or returns the value of <tt>current->personality</tt> if the
argument is set to impossible personality 0xffffffff. Obviously, the
behaviour of this system call itself does not depend on personality..
 -->
ユーザインターフェースは、<bf>personality(2)</bf>システムコールを通じて、現在のプロセスのパーソナリティを設定できるようになっています。あるいは、もし引数が存在しないパーソナリティ 0xffffffff であったら<tt>current->personality</tt>をただ返します。明らかにこのシステムコールの振る舞いは、パーソナリティとは独立です。

<!-- 
The kernel interface to execution domains registration consists of two
functions:
 -->
実行ドメイン登録のカーネルインターフェースは2つの関数になっています。

<itemize>
<!-- 
<item><tt>int register_exec_domain(struct exec_domain *)</tt>: registers the
      execution domain by linking it into single-linked list <tt>exec_domains</tt>
	  under the write protection of the read-write spinlock <tt>exec_domains_lock</tt>.
      Returns 0 on success, non-zero on failure.
 -->
<item><tt>int register_exec_domain(struct exec_domain *)</tt>: 読み書きスピンロック<tt>exec_domain_lock</tt>による書き込み保護のもと、単リンクリストの<tt>exec_domains</tt>へ実行ドメインをリンクすることで、登録する。成功すれば0を返し、失敗なら非0となる。

<!-- 
<item><tt>int unregister_exec_domain(struct exec_domain *)</tt>: unregisters the
      execution domain by unlinking it from the <tt>exec_domains</tt> list, again using
      <tt>exec_domains_lock</tt> spinlock in write mode. Returns 0 on success.
 -->
<item><tt>int unregister_exec_domain(struct exec_domain *)</tt>: <tt>exec_domians</tt>リストからはずすことにより実行ドメインを登録解除する。登録と同様、<tt>exec_domian_lock</tt>スピンロックを書き込みモードで利用する。成功すれば0を返す。
</itemize>

<!-- 
The reason why <tt>exec_domains_lock</tt> is a read-write is that only registration
and unregistration requests modify the list, whilst doing
<bf>cat /proc/filesystems</bf> calls <tt>fs/exec_domain.c:get_exec_domain_list()</tt>, which
needs only read access to the list. Registering a new execution domain
defines a "lcall7 handler" and a signal number conversion map. Actually,
ABI patch extends this concept of exec domain to include extra information
(like socket options, socket types, address family and errno maps).
 -->
<tt>exec_domains_lock</tt>が読み書きロックである理由は、登録と登録解除要求のみがリストを書き換え、<bf>cat /proc/filesystems</bf>が<tt>fs/exec_domain.c:get_exec_domain_list()</tt>を呼ぶことだけが、リストの読み出しを行うためです。新しい実行ドメインの登録により、「lcall7 ハンドラ」とシグナル番号の変換マップを定義されます。実際、ABIパッチは、この実行ドメインの考え方を拡張して、(ソケットオプションやソケットタイプ、アドレスファミリィやエラー番号マップといった)追加の情報を持つようにしています。

<!-- 
The binary formats are implemented in a similar manner, i.e. a single-linked
list formats is defined in <tt>fs/exec.c</tt> and is protected by a read-write lock
<tt>binfmt_lock</tt>. As with <tt>exec_domains_lock</tt>, the <tt>binfmt_lock</tt> is taken read on
most occasions except for registration/unregistration of binary formats.
Registering a new binary format enhances the <bf>execve(2)</bf> system call with new
<tt>load_binary()/load_shlib()</tt> functions as well as ability to <tt>core_dump()</tt> . The
<tt>load_shlib()</tt> method is used only by the old <bf>uselib(2)</bf> system call while
the <tt>load_binary()</tt> method is called by the <tt>search_binary_handler()</tt> from
<tt>do_execve()</tt> which implements <bf>execve(2)</bf> system call.
 -->
バイナリフォーマットは同じように実装されています。つまり、単リンクリストフォーマットを<tt>fs/exec.c</tt>で定義し、読み書きロックの<tt>binfmt_lock</tt>で保護します。<tt>exec_domains_lock</tt>のように、<tt>binfmt_lock</tt>は、バイナリフォーマットの登録や登録解除のときを除くほとんどの場合に読み込みのみになっています。
新しいバイナリフォーマットを登録することで、<tt>core_dump()</tt>ができるのと同様に、新しい<tt>load_binary/load_shlib()</tt>関数によって、<bf>execve(2)</bf>システムコールは機能拡張されます。<tt>load_binary()</tt>メソッドが、<bf>execve(2)</bf>システムコールを実装している<tt>do_execve()</tt>から<tt>search_binary_handler()</tt>によって呼ばれているときに、<tt>load_shlib()</tt>メソッドは古い<bf>uselib(2)</bf>システムコールによってのみ使わます。

<!-- 
The personality of the process is determined at binary format loading by
the corresponding format's <tt>load_binary()</tt> method using some heuristics.
For example to determine UnixWare7 binaries one first marks the binary
using the <bf>elfmark(1)</bf> utility, which sets the ELF header's <tt>e_flags</tt> to the magic
value 0x314B4455 which is detected at ELF loading time and
<tt>current->personality</tt> is set to PER_UW7. If this heuristic fails, then a more
generic one, such as treat ELF interpreter paths like <tt>/usr/lib/ld.so.1</tt> or
<tt>/usr/lib/libc.so.1</tt> to
indicate a SVR4 binary, is used and personality is set to PER_SVR4. One
could write a little utility program that uses Linux's <bf>ptrace(2)</bf> capabilities
to single-step the code and force a running program into any personality.
 -->
プロセスのパーソナリティは、若干の発見的手法をつかって対応するフォーマットの<tt>load_binary()</tt>メソッドから読み込まれたバイナリーフォーマットによって決定されます。
UnixWare7バイナリを決定する例としては、まず<bf>elfmark(1)</bf>ユーティリティを使って、ELFのへッダーの<tt>e_flags</tt>に、マジック値 0x314B4455に設定し、印をつけます。
このマジック値は、ELFのロード時に検出され、<tt>current->personality</tt>にPER_UW7を設定します。

<!-- 
Once personality (and therefore <tt>current->exec_domain</tt>) is known, the system
calls are handled as follows. Let us assume that a process makes a system
call by means of lcall7 gate instruction. This transfers control to
<tt>ENTRY(lcall7)</tt> of <tt>arch/i386/kernel/entry.S</tt> because it was prepared in
<tt>arch/i386/kernel/traps.c:trap_init()</tt>. After appropriate stack layout
conversion, <tt>entry.S:lcall7</tt> obtains the pointer to <tt>exec_domain</tt> from <tt>current</tt>
and then an offset of lcall7 handler within the <tt>exec_domain</tt> (which is 
hardcoded as 4 in asm code so you can't shift the <tt>handler</tt> field around in
C declaration of <tt>struct exec_domain</tt>) and jumps to it. So, in C, it would
look like this:
 -->
一度パーソナリティ(と、従って<tt>current->exzec_domain</tt>)が分かれば、システムコールは次のように取り扱います。プロセスが lcall7 ゲート命令を使ってシステムコールを発行したとしましょう。
これは制御を <tt>arch/i386/kernel/entry.S</tt>の<tt>ENTRY(lcall7)</tt>に移します。なぜならこれは、<tt>arch/i386/kernel/traps.c:trap_init()</tt>に準備されているためです。
適切なスタック割り当ての変換のあと、<tt>entry.S:lcall7</tt>は<tt>current</tt> から <tt>exec_domain</tt> へのポインタと、そして(アセンブラで4にハードコードされており、<tt>struct exec_domain</tt>のCの定義で、<tt>handler</tt>メンバを移動できないのであるが)<tt>exec_domain</tt>中の lcall7 ハンドラのオフセットを得て、そこへジャンプします。そうです、Cでは、次のようになります。

<tscreen><code>
static void UW7_lcall7(int segment, struct pt_regs * regs)
{
       abi_dispatch(regs, &amp;uw7_funcs[regs->eax &amp; 0xff], 1);
}
</code></tscreen>

<!-- 
where <tt>abi_dispatch()</tt> is a wrapper around the table of function pointers that
implement this personality's system calls <tt>uw7_funcs</tt>.
 -->
<tt>abi_dispatch()</tt>は、関数ポインタの表へのラッパーであり、それはこのパーソナリティのシステムコールの<tt>uw7_funcs</tt>を実装したものになっています。

<!-- 
<sect>Linux Page Cache<p>
 -->
<sect>Linux ページキャッシュ<p>

<!-- 
In this chapter we describe the Linux 2.4 pagecache.  The pagecache
is - as the name suggests - a cache of physical pages. In the UNIX world the
concept of a pagecache became popular with the introduction of SVR4 UNIX,
where it replaced the buffercache for data IO operations.
 -->
この章では、Linux 2.4のページキャッシュについて説明します。ページキャッシュは、
名前が示しているように、物理ページのキャッシュです。UNIX の世界ではページキャッシュの考え方は SVR4 UNIX の登場により、データI/O操作でのバッファーキャッシュを置き換えるようにして良く使われるようになりました。
<!-- 
While the SVR4 pagecache is only used for filesystem data cache and thus uses
the struct vnode and an offset into the file as hash parameters, the Linux page
cache is designed to be more generic, and therefore uses a struct address_space
(explained below) as first parameter.  Because the Linux pagecache is tightly
coupled to the notation of address spaces, you will need at least a basic
understanding of adress_spaces to understand the way the pagecache works.
An address_space is some kind of software MMU that maps all pages of one object
(e.g. inode) to an other concurrency (typically physical disk blocks).
The struct address_space is defined in <tt>include/linux/fs.h</tt> as:
 -->
SVR4 ページキャッシュでは、ファイルシステムのデータキャッシュとしてのみ使われており、
したがって vnode 構造体とファイルのオフセットをハッシュパラメータとして使っていますが、
Linux のページキャッシュはより一般的に設計されているため、(以下で説明する)構造体 address_space を一つ目のパラメタとして使います。
Linux ページキャッシュは、アドレス空間の表記法に強く結び付けられているため、
ページキャッシュの働きを理解するには、少なくとも address_space の基本的な理解が必要です。
address_space はソフトウエア MMU の一種で、あるオブジェクト (例えば inode) のすべてのページを他の対応する値(典型的には物理ディスクブロック)へと対応づけています。構造体 address_spece は <tt>include/linux/fs.h</tt> で以下のように定義されています。

<!--  Dec-2000
<tscreen><code>
	struct address_space {
		struct list_head			pages;
	        unsigned long           		nrpages;
		struct address_space_operations *	a_ops;
		void *					host;
		struct vm_area_struct *			i_mmap;
		struct vm_area_struct *			i_mmap_shared;
		spinlock_t				i_shared_lock;
	};
</code></tscreen>
-->
<!-- 2001-Oct -->
<tscreen><code>
	struct address_space {
		struct list_head        clean_pages;
		struct list_head        dirty_pages;
		struct list_head        locked_pages;
		unsigned long           nrpages;
		struct address_space_operations *a_ops;
		struct inode            *host;
		struct vm_area_struct	*i_mmap;
		struct vm_area_struct	*i_mmap_shared;
		spinlock_t		i_shared_lock;
	};
</code></tscreen>

<!-- 
===Old=== Dec, 2000 
To understand the way address_spaces works, we only need to look at a few of
these fields:  pages is a double linked list of all pages that belong to this
address_space, <tt>nrpages</tt> is the number of pages in <tt>pages</tt>,  
<tt>a_ops</tt> defines the
methods of this address_space and <tt>host</tt> is a opaque pointer to the object this
address_space belongs to.  The usage of <tt>pages</tt> and <tt>nrpages</tt> is obvious, so we
will take a tighter look at the <tt>address_space_operations</tt> structure, defined in
the same header:

address_spaces の働く方法を理解するには、これらのメンバの一部を見るだけでよいのです。
<tt>pages</tt> は、この address_space に属している全てのページの双方向リンクリストです。<tt>nrpages</tt>は<tt>pages</tt>のページ数で、<tt>a_ops</tt>はこの address_space のmethodを定義しています。そして、<tt>host</tt> は、このaddress_spaceが属するオブジェクトへの opaque ポインタとなっています。

===New=== Oct, 2001
To understand the way address_spaces works, we only need to look at a few of this fields:
<tt>clean_pages</tt>, <tt>dirty_pages</tt> and <tt>locked_pages</tt> are double linked lists
of all clean, dirty and locked pages that belong to this address_space, <tt>nrpages</tt>
is the total number of pages in this address_space.  <tt>a_ops</tt> defines the methods of
this object and <tt>host</tt> is an pointer to the inode this address_space belongs to -
it may also be NULL, e.g. in the case of the swapper address_space
(<tt>mm/swap_state.c,</tt>).

The usage of <tt>clean_pages</tt>, <tt>dirty_pages</tt>, <tt>locked_pages</tt> and
<tt>nrpages</tt> is obvious, so we will take a tighter look at the
<tt>address_space_operations</tt> structure, defined in the same header:

 -->
address_spaces の働く方法を理解するには、これらのメンバの一部を見るだけでいいでしょう。
<tt>clean_pages</tt>、<tt>dirty_pages</tt>、<tt>locked_pages</tt> は、この address_space に属している clean、dirty、locked のそれぞれのページについての双方向リンクリストです。
また、 <tt>nrpages</tt> はこの address_space の総ページ数になっています。
<tt>a_ops</tt> は、このオブジェクトのメソッドを定義しており、
<tt>host</tt> は、この address_space が属する inode へのポインタとなっています。これは NULL にもなります。例えば、swapper の address_space の場合 (<tt>mm/swap_state.c</tt>) がそれにあたります。

<tt>clean_pages</tt> や <tt>dirty_pages</tt>、それに <tt>locked_pages</tt>、 <tt>nrpages</tt> の用法は自明だと思いますので、 <tt>address_space_operations</tt> 構造体をしっかりみていきます。これは同じへッダファイルに定義されており、

<!-- 2000-Dec
<tscreen><code>
	struct address_space_operations {
		int (*writepage)(struct page *);
		int (*readpage)(struct file *, struct page *);
		int (*sync_page)(struct page *);
		int (*prepare_write)(struct file *,
				struct page *, unsigned, unsigned);
		int (*commit_write)(struct file *,
				struct page *, unsigned, unsigned);
		int (*bmap)(struct address_space *, long);
	};
</code></tscreen>
-->
<!-- 2001-Oct -->
<tscreen><code>
	struct address_space_operations {
		int (*writepage)(struct page *);
		int (*readpage)(struct file *, struct page *);
		int (*sync_page)(struct page *);
		int (*prepare_write)(struct file *, struct page *, unsigned, unsigned);
		int (*commit_write)(struct file *, struct page *, unsigned, unsigned);
		int (*bmap)(struct address_space *, long);
	};
</code></tscreen>
となっています。

<!-- 
For a basic view at the principle of address_spaces (and the pagecache) we need
to take a look at -><tt>writepage</tt> and -><tt>readpage</tt>, but in practice we need
to take a look at -><tt>prepare_write</tt> and -><tt>commit_write</tt>, too.
 -->
address_space と ページキャッシュの基本的な考え方からは、-><tt>writepage</tt> と -><tt>readpage</tt>に注目する必要があります。しかし、実際には -><tt>prepare_write</tt>と -><tt>commit_write</tt>にも注目する必要があります。

<!-- 
You can probably guess what the address_space_operations methods do
by virtue of their names alone; nevertheless, they do require some
explanation.  Their use in the course of filesystem data I/O, by
far the most common path through the pagecache, provides a good
way of understanding them.
Unlike most other UNIX-like operating systems, Linux has generic file
operations (a subset of the SYSVish vnode operations) for data IO through the
pagecache.  This means that the data will not directly interact with the file-
system on read/write/mmap, but will be read/written from/to the pagecache
whenever possible.  The pagecache has to get data from the actual low-level
filesystem in case the user wants to read from a page not yet in memory,
or write data to disk in case memory gets low.
 -->
おそらくその名前からの連想だけで address_space_operations メソッドが何を実行するか、当てることができるでしょう。それでも、若干の追加説明は必要です。ファイルシステムデータ I/O での使われかたは、ページキャッシュへ通じる王道であり、理解するのにうってつけです。
多くの他のUNIX系のオペレーティングシステムと違い、Linux では、ページキャッシュによるデータ I/O に対して一般的なファイル操作( SYSV の vnode 操作のサブセット)が可能です。これは、read/write/mmap においてはデータが直接ファイルシステムと作用せず、可能な限りページキャッシュへの書き込みや読み込みによって行われることを意味しています。ページキャッシュは、ユーザがメモリにないページから読み込みたい場合やメモリが少ない場合にディスクへデータを書き込みたい場合に、データを実際の低レベルファイルシステムから取得しなければなりません。

<!-- 
In the read path the generic methods will first try to find a page that
matches the wanted inode/index tuple.
 -->
読み込みパスでは、一般的なメソッドでは、最初に必要とするinode/インデックスタプルに対応するページを見つけようとします。

<tscreen>
	hash = page_hash(inode->i_mapping, index);
</tscreen>
<!-- 
Then we test whether the page actually exists.
 -->
そしてどのページが実際に存在しているかテストします。

<tscreen>
	hash = page_hash(inode->i_mapping, index);
	page = __find_page_nolock(inode->i_mapping, index, *hash);
</tscreen>
<!-- 
When it does not exist, we allocate a new free page, and add it to the page-
cache hash.
 -->
もし存在しないときは新しいフリーページを割り当てページキャッシュへ追加します。
<tscreen>
	page = page_cache_alloc();
	__add_to_page_cache(page, mapping, index, hash);
</tscreen>
<!-- 
After the page is hashed we use the -><tt>readpage</tt> address_space operation to
actually fill the page with data. (file is an open instance of inode).
 -->
ページがハッシュされたら、-><tt>readpage</tt> アドレス空間操作を使って、ページを実際にデータで埋め(ファイルはinodeのオープンインスタンス)ます。
<tscreen>
	error = mapping->a_ops->readpage(file, page);
</tscreen>
<!-- 
Finally we can copy the data to userspace.

For writing to the filesystem two pathes exist: one for writable mappings
(mmap) and one for the write(2) family of syscalls. The mmap case is very
simple, so it will be discussed first.
When a user modifies mappings, the VM subsystem marks the page dirty.
 -->
最後にデータをユーザスペースにコピーします。

ファイルシステムに書くには2つのパスがあります。1つはマップ(mmap)に書き込むこと、もう一つは write(2) のようなシステムコールを用いることです。mmap の場合がとてもシンプルなことから、まず最初に取り上げることにします。
ユーザがマップを変更するとき、VMサブシステムはページを dirty とマークします。


<tscreen>
	SetPageDirty(page);
</tscreen>
<!-- 
The bdflush kernel thread that is trying to free pages, either as background
activity or because memory gets low will try to call -><tt>writepage</tt> on the pages
that are explicitly marked dirty.  The -><tt>writepage</tt> method does now have to
write the pages content back to disk and free the page.
 -->
バックグランドでの活動として、あるいはメモリが少なくなったのを理由として、ページを解放しようとする bdflush カーネルスレッドは、dirty とマークされたページの -><tt>writepage</tt> を呼ぼうとします。-><tt>writepage</tt> メソッドは、ページの内容をディスクに書出し、ページを解放しなければなりません。

<!-- 
The second write path is _much_ more complicated.  For each page the user
writes to, we are basically doing the following:
(for the full code see <tt>mm/filemap.c:generic_file_write()</tt>).
 -->
2つめの書き込みパスは、 ＊とても＊たいへん複雑です。ユーザが書き込む各ページに対して、基本的に以下のことを行います(コードの全体は <tt>mm/filemap.c:generic_file_write()</tt> を参照)。

<tscreen>
	page = __grab_cache_page(mapping, index, &amp;cached_page);
	mapping->a_ops->prepare_write(file, page, offset, offset+bytes);
	copy_from_user(kaddr+offset, buf, bytes);
	mapping->a_ops->commit_write(file, page, offset, offset+bytes);
</tscreen>

<!-- 
So first we try to find the hashed page or allocate a new one, then we call the
-><tt>prepare_write</tt> address_space method, copy the user buffer to kernel memory and
finally call the -><tt>commit_write</tt> method.  As you probably have seen
->prepare_write and -><tt>commit_write</tt> are fundamentally different from -><tt>readpage</tt>
and -><tt>writepage</tt>, because they are not only called when physical IO is actually
wanted but everytime the user modifies the file.
There are two (or more?) ways to handle this, the first one uses the Linux
buffercache to delay the physical IO, by filling a <tt>page->buffers</tt> pointer with
buffer_heads, that will be used in try_to_free_buffers (<tt>fs/buffers.c</tt>) to
request IO once memory gets low, and is used very widespread in the current
kernel.  The other way just sets the page dirty andAfter appropriate stack layout
conversion, <tt>entry.S:lcall7</tt> obtains the pointer to <tt>exec_domain</tt> from <tt>current</tt>
and then an offset of lcall7 handler within the <tt>exec_domain</tt> (which is 
hardcoded as 4 in asm code so you can't shift the <tt>handler</tt> field around in
C declaration of <tt>struct exec_domain</tt>) and jumps to it. So, in C, it would
look like this:
 relies on -><tt>writepage</tt> to do
all the work.  Due to the lack of a validitity bitmap in struct page this does
not work with filesystem that have a smaller granuality then <tt>PAGE_SIZE</tt>.
 -->
最初に、ハッシュされたページを見つけようとするか新しいページを割り当てようとします。そして、-><tt>prepare_write</tt> アドレス空間メソッドを呼び出し、ユーザバッファをカーネルメモリにコピーし、そして最後に -><tt>commit_write</tt> メソッドを呼び出します。おそらく -><tt>prepare_write</tt> と -><tt>commit_write</tt> は、-><tt>readpage</tt> と -><tt>writepage</tt> からは基本的に異なるものに見えるでしょう。これは物理 I/O を実際に求められた時だけではなく、ユーザがファイルを変更したときにはいつも呼び出されるからです。
これを扱う方法は2つ(あるいはそれ以上?)あります。一つめは <tt>page->buffers</tt> ポインタを try_to_free_buffers(<tt>fs/buffers.c</tt>) で使われている buffer_heads で埋めることで、物理 IO の遅延に Linux バッファーキャッシュを使います。
もう一つの方法は、ページを dirty に単に設定し、後の全てを -><tt>writepage</tt>にまかせることです。
ページ構造体に有効なビットマップが欠けているため、<tt>PAGE_SIZE</tt>より小さいgranualityをもっているファイルシステムでは働きません。

<sect>IPC機構<p>
<!-- 
<sect>IPC Mechanisms<p>
This chapter describes the semaphore, shared memory, and
message queue IPC mechanisms as implemented in the Linux 2.4
kernel. It is organized into four sections. The
first three sections cover the interfaces and support functions
for <ref id="semaphores" name="semaphores">,
<ref id="message" name="message queues">,
and <ref id="sharedmem" name="shared memory"> respectively.
The <ref id="ipc_primitives" name="last"> section describes
a set of common functions and data structures that are shared by
all three mechanisms.
 -->
本章ではLinux 2.4 カーネルで実装されている IPC 機構のセマフォ、共有メモリおよびメッセージキューについて記述します。
四つの節で構成され、最初の三つの節では<ref id="semaphores" name="セマフォ">と
<ref id="message" name="メッセージキュー">、<ref id="sharedmem" name="共有メモリ">を順に取り上げて、インターフェースとサポート関数を説明します。また、
<ref id="ipc_primitives" name="最後">の節では、三つの機構で共有される共通関数群とデータ構造を説明します。

<!-- 
<sect1>Semaphores<label id="semaphores"><p>
 -->
<sect1>セマフォ<label id="semaphores"><p>
<!-- 
The functions described in this section implement the user level
semaphore mechanisms. Note that this implementation relies on the
use of kernel splinlocks and kernel semaphores. To avoid confusion,
the term "kernel semaphore" will be used in reference to kernel
semaphores. All other uses of the word "sempahore" will be in
reference to the user level semaphores.
 -->
この節で説明している関数はユーザレベルのセマフォ機構の実装になっています。この実装部分はカーネルスピンロックとカーネルセマフォの利用に頼っていることに注意しましょう。
混乱を避けるため、カーネルのセマフォを参照するときは「カーネルセマフォ」と呼ぶことにします。その他の単に「セマフォ」というときは、ユーザレベルのセマフォを指すことにします。

<!-- 
<sect2>Semaphore System Call Interfaces<label id="sem_apis"><p>
 -->
<sect2>セマフォシステムコールのインターフェース<label id="sem_apis"><p>

<sect3>sys_semget()<label id="sys_semget"><p>
<!-- 
The entire call to sys_semget() is protected by the
global <ref id="struct_ipc_ids" name="sem_ids.sem">
kernel semaphore.
 -->
全てのsys_semget()への呼出しは、カーネルグローバルな<ref id="struct_ipc_ids" name="sem_ids.sem">カーネルセマフォで保護されます。
<!-- 
In the case where a new set of semaphores must be
created, the <ref id="newary" name="newary()"> function is
called to create and initialize a new semaphore set. The ID of
the new set is returned to the caller.
 -->
新しいセマフォのセットを作らなければならない場合は、<ref id="newary" name="newary()"> 関数が呼ばれて、新しいセマフォセットの作成と初期化をします。そして新しいセットID が呼出し元に戻されます。

<!-- 
In the case where a key value is provided for an existing
semaphore set, <ref id="ipc_findkey" name="ipc_findkey()">
is invoked to look up the corresponding semaphore descriptor
array index.  The parameters and permissions of the caller are
verified before returning the semaphore set ID.
 -->
キーの値が既存のセマフォセットに対して発行されたものだった場合は、<ref id="ipc_findkey" name="ipc_findkey()"> が呼び出され、相当するセマフォディスクリプタ配列インデックスを見つけます。パラメータと呼出し元の
パーミッションは、セマフォのセットIDを返却する前に確認されます。
</sect3>

<sect3>sys_semctl()<label id="sys_semctl"><p>
<!-- 
For the <ref id="IPC_INFO_and_SEM_INFO" name="IPC_INFO">,
<ref id="IPC_INFO_and_SEM_INFO" name="SEM_INFO">, and
<ref id="SEM_STAT" name="SEM_STAT"> commands,
<ref id="semctl_nolock" name="semctl_nolock()">
is called to perform the necessary functions.
 -->
<ref id="IPC_INFO_and_SEM_INFO" name="IPC_INFO">と <ref id="IPC_INFO_and_SEM_INFO" name="SEM_INFO"> そして
<ref id="SEM_STAT" name="SEM_STAT"> コマンドについては、必要な関数処理を行う
<ref id="semctl_nolock" name="semctl_nolock()"> を呼び出します。

<!-- 
For the <ref id="GETALL" name="GETALL">, <ref id="GETVAL" name="GETVAL">,
<ref id="GETPID" name="GETPID">, <ref id="GETNCNT" name="GETNCNT">,
<ref id="GETZCNT" name="GETZCNT">, <ref id="IPC_STAT" name="IPC_STAT">,
<ref id="SETVAL" name="SETVAL">,and <ref id="SETALL" name="SETALL"> commands,
<ref id="semctl_main" name="semctl_main()"> is called to perform the
necessary functions.
 -->
<ref id="GETALL" name="GETALL">、 <ref id="GETVAL" name="GETVAL">、
<ref id="GETPID" name="GETPID">、<ref id="GETNCNT" name="GETNCNT">、
<ref id="GETZCNT" name="GETZCNT">、 <ref id="IPC_STAT" name="IPC_STAT">、
<ref id="SETVAL" name="SETVAL">、<ref id="SETALL" name="SETALL"> コマンドについては、
必要な関数処理を行う <ref id="semctl_main" name="semctl_main()"> を呼び出します。

<!-- 
For the <ref id="semctl_ipc_rmid" name="IPC_RMID">
and <ref id="semctl_ipc_set" name="IPC_SET"> command,
<ref id="semctl_down" name="semctl_down()"> is called
to perform the necessary functions. Throughout both of these
operations, the global <ref id="struct_ipc_ids" name="sem_ids.sem">
kernel semaphore is held.
 -->
<ref id="semctl_ipc_rmid" name="IPC_RMID">や<ref id="semctl_ipc_set" name="IPC_SET"> コマンドについては、必要な関数処理を行う <ref id="semctl_down" name="semctl_down()"> を呼び出します。
両方の演算の間は、グローバルな <ref id="struct_ipc_ids" name="sem_ids.sem"> カーネルセマフォを保持します。
</sect3>

<sect3>sys_semop()<label id="sys_semop"><p>
<!-- 
After validating the call parameters, the semaphore
operations data is copied from user space to a temporary buffer.
If a small temporary buffer is sufficient, then a stack buffer is
used. Otherwise, a larger buffer is allocated. After copying in the
semaphore operations data, the global semaphores spinlock is
locked, and the user-specified semaphore set ID is validated.
Access permissions for the semaphore set are also validated.
 -->
呼出し引数の有効性を確認した後、セマフォの操作データをユーザ空間から一時バッファへコピーします。
小さい一時バッファで大きさが十分であればスタックバッファが使われます。不十分なら、大きいバッファが割り当てられます。セマフォの操作データのコピーが終わった後に、グローバルなセマフォスピンロックをロックします。そしてユーザが指定したセマフォセットIDが確認されます。セマフォセットへのパーミッションも有効か確認されます。

<!-- 
All of the user-specified semaphore operations are parsed.
During this process, a count is maintained of all the operations that
have the SEM_UNDO flag set. A <tt>decrease</tt> flag is set if any of the
operations subtract from a semaphore value, and an <tt>alter</tt> flag is set
if any of the semaphore values are modified (i.e. increased or
decreased). The number of each
semaphore to be modified is validated.
 -->
ユーザが指定したセマフォ操作が全て解析されます。この処理の間、カウント<!-- a count? -->は SEM_UNDO フラグセットをもつ全ての操作を保持します。
セマフォ値を減算する操作のときには、 <tt>decrease</tt>フラグが設定されます。そして、セマフォの値を変更する(つまり増加もしくは減少する)もの全てについて、<tt>alter</tt> フラグが設定されます。そして変更される各セマフォの値が有効か確認されます。

<!-- 
If SEM_UNDO was asserted for any of the semaphore operations,
then the undo list for the current task is searched for an undo
structure associated with this semaphore set. During this search,
if the semaphore set ID of any of the undo structures is found
to be -1, then <ref id="freeundos" name="freeundos()">
is called to free the undo structure
and remove it from the list. If no undo structure is found for
this semaphore set then <ref id="alloc_undo" name="alloc_undo()">
is called to allocate and initialize one.
 -->
もし、これらの操作のいずれかがセマフォの状態を変化させるのであれば、このセマフォセットに関連する undo 構造体が 現在のタスクの undo リストから探されます。この検索の間、もし undo 構造体の任意のセマフォセットIDが -1 であると分かったならば、<ref id="freeundos" name="freeundos()"> が呼ばれ、 undo 構造体が解放されてリストから削除されます。もし、undo 構造体がこのセマフォセットについて見つからなければ、
<ref id="alloc_undo" name="alloc_undo()"> が呼ばれて割り当ておよび初期化が行われます。

<!-- 
The <ref id="try_atomic_semop" name="try_atomic_semop()">
function is called with the <tt>do_undo</tt>
parameter equal to 0 in order to execute the sequence of
operations. The return value indicates that either the
operations passed, failed, or were not executed because
they need to block. Each of these cases are further described below:
 -->
一連の操作を実行するために  <ref id="try_atomic_semop" name="try_atomic_semop()"> 関数を <tt>do_undo</tt> パラメータを 0 にして呼び出します。返り値は、操作が処理されたか失敗したか、あるいはブロックの必要があったため実行されなかったかを示しています。各々の場合を以下に示します。

<!-- 
<sect4>Non-blocking Semaphore Operations<label id="Non-blocking_Semaphore_Operations"><p>
The <ref id="try_atomic_semop" name="try_atomic_semop()">
function returns zero to indicate that all operations in the
sequence succeeded. In this case, <ref id="update_queue" name="update_queue()"> is called to traverse the queue of pending semaphore operations for the semaphore set and awaken any sleeping tasks that no longer need to block. This completes the execution of the sys_semop() system call for this case.
</sect4>
 -->
<sect4>非ブロックセマフォ操作<label id="Non-blocking_Semaphore_Operations"><p>
<ref id="try_atomic_semop" name="try_atomic_semop()"> 関数は、一連の全ての操作が成功したときに、ゼロを返します。この場合には、<ref id="update_queue" name="update_queue()"> が呼び出され、セマフォセットのうち保留されているセマフォの操作のキューを走査して、もうブロックの必要がない休止タスクを起こします。この処理によって、この場合の sys_semop() システムコールの実行が完了します。
</sect4>

<!--
<sect4>Failing Semaphore Operations<label id="Failing_Semaphore_Operations"><p>
If <ref id="try_atomic_semop" name="try_atomic_semop()">
returns a negative value, then a failure condition was encountered.
In this case, none of the operations have been executed.
This occurs when either a semaphore operation would cause an
invalid semaphore value, or an operation marked IPC_NOWAIT is
unable to complete.  The error condition is then returned to the
caller of sys_semop().

Before sys_semop() returns, a call is made to
<ref id="update_queue" name="update_queue()"> to traverse
the queue of pending semaphore operations for the semaphore set
and awaken any sleeping tasks that no longer need to block.
</sect4>
-->
<sect4>セマフォ操作の失敗<label id="Failing_Semaphore_Operations"><p>
もし、<ref id="try_atomic_semop" name="try_atomic_semop()">が負の値を返した場合、
障害状態に遭遇したことになります。この場合、操作は全て実行されません。
これは、セマフォ操作が、無効なセマフォ値になったり、IPC_NOWAITにマークづけられた操作が実行完了できなかった場合に起ります。エラー状態はその後、sys_semop()の呼出し元に返されます。

sys_memop()から戻る前に、セマフォセットの保留されたセマフォ操作のキューを走査するため update_queue() を呼出し、もうブロックの必要のない休止タスクを起こします。

</sect4>

<sect4><!--
Blocking Semaphore Operations<label id="Blocking_Semaphore_Operations"><p>
The <ref id="try_atomic_semop" name="try_atomic_semop()">
function returns 1 to indicate that the
sequence of semaphore operations was not executed because
one of the semaphores would block. For this case, a new
<ref id="struct_sem_queue" name="sem_queue"> element is
initialized containing these semaphore operations. If any of
these operations would alter the state of the semaphore, then
the new queue element is added at the tail of the queue.
Otherwise, the new queue element is added at the head of the queue.
-->ブロッキングセマフォ操作<label id="Blocking_Semaphore_Operations"><p>
<ref id="try_atomic_semop" name="try_atomic_semop()">関数は、セマフォ操作の一つがブロックされ、
一連のセマフォ操作が実行されなかった場合には 1 を返します。この場合、新しい<ref id="struct_sem_queue" name="sem_queue">の要素がこれらのセマフォ操作を含めて初期化されます。もし、これらの操作のいずれかがセマフォの状態を変化させそうであれば、新しいキューの要素はキューの末尾に追加されます。
そうでなければ新しいキューの要素がキューの先頭に挿入されます。

<!--
The <tt>semsleeping</tt> element of the current
task is set to indicate that the task is sleeping on this
<ref id="struct_sem_queue" name="sem_queue"> element.
The current task is marked as TASK_INTERRUPTIBLE, and the
<tt>sleeper</tt> element of the
<ref id="struct_sem_queue" name="sem_queue">
is set to identify this task as the sleeper. The
global semaphore spinlock is then unlocked, and schedule() is called
to put the current task to sleep.
-->
現在のタスクの<tt>semsleeping</tt>要素は、タスクがこの<ref id="struct_sem_queue" name="sem_queue"> 要素
で休止されているかどうかを示しています。現在のタスクが TASK_INTERRUPTIBLE とマークされ、<ref id="struct_sem_queue" name="sem_queue">の<tt>sleeper</tt>要素がこのタスクが休止していることを示すため設定されます。
そしてグローバルセマフォスピンロックを解除し、現在のタスクを休止するためschedule()を呼び出します。

<!--
When awakened, the task re-locks the global semaphore spinlock,
determines why it was awakened, and how it should
respond.  The following cases are handled:
-->
起こされたとき、なぜ起こされたか、どのように反応すべきかを判断するため、タスクはグローバルセマフォロックを再ロックします。以下のような場合が処理されます。

 <!-- 
<itemize>
     <item>If the the semaphore set has been removed, then
        the system call fails with EIDRM.
     <item> If the <tt>status</tt> element of the
	<ref id="struct_sem_queue" name="sem_queue"> structure
	is set to 1, then the task was awakened in order to retry the
	semaphore operations. Another call to
	<ref id="try_atomic_semop" name="try_atomic_semop()"> is
	made to execute the sequence of semaphore operations.  If
	try_atomic_sweep() returns 1, then the task must block again
	as described above. Otherwise, 0 is returned for success,
	or an appropriate error code is returned in case of failure.
-->
<!--

	Before sys_semop() returns, current->semsleeping is cleared,
	and the <ref id="struct_sem_queue" name="sem_queue">
	is removed from the queue.  If any of the specified semaphore
	operations were altering operations (increase or decrease),
	then <ref id="update_queue" name="update_queue()"> is
	called to traverse the queue of pending semaphore operations
	for the semaphore set and awaken any sleeping tasks that no
	longer need to block.

<item>  If the <tt>status</tt> element of the
	<ref id="struct_sem_queue" name="sem_queue"> structure is
	NOT set to 1, and the
	<ref id="struct_sem_queue" name="sem_queue"> element has
	not been dequeued, then the task was awakened by an interrupt.
	In this case, the system call fails with EINTR.  Before
	returning, current->semsleeping is cleared, and the
	<ref id="struct_sem_queue" name="sem_queue"> is removed
	from the queue.  Also,
	<ref id="update_queue" name="update_queue()"> is called
	if any of the operations were altering operations.
<item>  If the <tt>status</tt> element of the
	<ref id="struct_sem_queue" name="sem_queue"> structure is
	NOT set to 1, and the
	<ref id="struct_sem_queue" name="sem_queue"> element
	has been dequeued,
	then the semaphore operations have already been executed by
	<ref id="update_queue" name="update_queue()">.  The
	queue <tt>status</tt>, which could be 0 for success
	or a negated error code for failure, becomes the return value of
	the system call.
</itemize>
-->

<itemize>
<item> もし、セマフォセットが削除されたなら、システムコールは、EIDRMで失敗する。
<item> もし、 <ref id="struct_sem_queue" name="sem_queue"> 構造体の <tt>status</tt> 要素が 1 に設定されていたら、タスクはセマフォ操作を再び試みるために起こされた。もう1度<ref id="try_atomic_semop" name="try_atomic_semop()"> 呼出しが一連のセマフォ操作の実行を行う。もし try_atomic_sweep() が 1 を返すなら、タスクは上記のように再度ブロックされなければならない。そうでなければ成功して 0 が戻ってくるか、失敗した場合は適切なエラーコードが返される。

sys_semop() が戻る前に、current-&gt;semsleeping がクリアされる。そして、 <ref id="struct_sem_queue" name="sem_queue">は、キューから削除される。もし指定されたセマフォ操作がいずれも変更の操作(増分、減分)なら、<ref id="update_queue" name="update_queue()"> が、セマフォセットの保留されたセマフォ操作のキューを走査するために呼び出され、もうブロックの必要のない休止タスクを起こす。

<item>もし、<ref id="struct_sem_queue" name="sem_queue"> 構造体の <tt>status</tt> 要素が 1 で 「ない」うえに
<ref id="struct_sem_queue" name="sem_queue"> 要素がキューからはずされなければ、タスクは割り込みにより起こされたことになる。この場合システムコールは失敗し EINTR を返す。戻る前に current-&gt;semsleeping はクリアされ、<ref id="struct_sem_queue" name="sem_queue">はキューから削除される。さらに、もし変更を加える操作があったら <ref id="update_queue" name="update_queue()"> も呼び出される。

<item>もし、<ref id="struct_sem_queue" name="sem_queue"> 構造体の <tt>status</tt> 要素が1に設定されて『なく』、<ref id="struct_sem_queue" name="sem_queue"> 要素がキューから削除されてなければ、セマフォ操作は既に
<ref id="update_queue" name="update_queue()"> により実行されている。キュー<tt>status</tt>は、成功すれば0に、失敗時に負のエラーコードになり、システムコールの返り値になる。
</itemize>
</sect4>
</sect3>
</sect2>

<!--
<sect2>Semaphore Specific Support Structures<label id="sem_structures"><p>
The following structures are used specifically for semaphore support:
-->
<sect2>セマフォ独自にサポートする構造体<label id="sem_structures"><p>
以下の構造体は、セマフォのサポートに特に使われます。

<sect3>struct sem_array<label id="struct_sem_array"><p>
<tscreen><code>
/* One sem_array data structure for each set of semaphores in the system. */
struct sem_array {
    struct kern_ipc_perm sem_perm; /* permissions .. see ipc.h */
    time_t sem_otime; /* last semop time */
    time_t sem_ctime; /* last change time */
    struct sem *sem_base; /* ptr to first semaphore in array */
    struct sem_queue *sem_pending; /* pending operations to be processed */
    struct sem_queue **sem_pending_last; /* last pending operation */
    struct sem_undo *undo; /* undo requests on this array * /
    unsigned long sem_nsems; /* no. of semaphores in array */
};
</code></tscreen>
</sect3>

<sect3>struct sem<label id="struct_sem"><p>
<tscreen><code>
/* One semaphore structure for each semaphore in the system. */
struct sem {
        int     semval;         /* current value */
        int     sempid;         /* pid of last operation */
};
</code></tscreen>
</sect3>

<sect3>struct seminfo<label id="struct_seminfo"><p>
<tscreen><code>
struct  seminfo {
        int semmap;
        int semmni;
        int semmns;
        int semmnu;
        int semmsl;
        int semopm;
        int semume;
        int semusz;
        int semvmx;
        int semaem;
};
</code></tscreen>
</sect3>

<sect3>struct semid64_ds<label id="struct_semid64_ds"><p>
<tscreen><code>
struct semid64_ds {
        struct ipc64_perm sem_perm;             /* permissions .. see
ipc.h */
        __kernel_time_t sem_otime;              /* last semop time */
        unsigned long   __unused1;
        __kernel_time_t sem_ctime;              /* last change time */
        unsigned long   __unused2;
        unsigned long   sem_nsems;              /* no. of semaphores in
array */
        unsigned long   __unused3;
        unsigned long   __unused4;
};
</code></tscreen>
</sect3>

<sect3>struct sem_queue<label id="struct_sem_queue"><p>
<tscreen><code>
/* One queue for each sleeping process in the system. */
struct sem_queue {
        struct sem_queue *      next;    /* next entry in the queue */
        struct sem_queue **     prev;    /* previous entry in the queue, *(q->pr
ev) == q */
        struct task_struct*     sleeper; /* this process */
        struct sem_undo *       undo;    /* undo structure */
        int                     pid;     /* process id of requesting process */
        int                     status;  /* completion status of operation */
        struct sem_array *      sma;     /* semaphore array for operations */
        int                     id;      /* internal sem id */
        struct sembuf *         sops;    /* array of pending operations */
        int                     nsops;   /* number of operations */
        int                     alter;   /* operation will alter semaphore */
};
</code></tscreen>
</sect3>

<sect3>struct sembuf<label id="struct_sembuf"><p>
<tscreen><code>
/* semop system calls takes an array of these. */
struct sembuf {
        unsigned short  sem_num;        /* semaphore index in array */
        short           sem_op;         /* semaphore operation */
        short           sem_flg;        /* operation flags */
};
</code></tscreen>
</sect3>

<sect3>struct sem_undo<label id="struct_sem_undo"><p>
<tscreen><code>
/* Each task has a list of undo requests. They are executed automatically
 * when the process exits.
 */
struct sem_undo {
        struct sem_undo *       proc_next;      /* next entry on this process */
        struct sem_undo *       id_next;        /* next entry on this semaphore set */
        int                     semid;          /* semaphore set identifier */
        short *                 semadj;         /* array of adjustments, one per
 semaphore */
};
</code></tscreen>
</sect3>
</sect2>

<!--
<sect2>Semaphore Support Functions<label id="sem_primitives"><p>
The following functions are used specifically in support of
semaphores:
-->
<sect2>セマフォサポート関数<label id="sem_primitives"><p>
以下の関数は特にセマフォのサポートのために使われます。

<!--
<sect3>newary()<label id="newary"><p>
newary() relies on the <ref id="ipc_alloc" name="ipc_alloc()">
function to allocate the memory
required for the new semaphore set. It allocates enough memory
for the semaphore set descriptor and for each of the semaphores
in the set.  The allocated memory is cleared, and the address of the
first element of the semaphore set descriptor is passed to
<ref id="ipc_addid" name="ipc_addid()">.
<ref id="ipc_addid" name="ipc_addid()"> reserves an array entry
for the new semaphore set descriptor and initializes the
(<ref id="struct_kern_ipc_perm" name="struct kern_ipc_perm">) data for the set.
The global <tt>used_sems</tt> variable is updated by the number of
semaphores in the new set and the initialization of the
(<ref id="struct_kern_ipc_perm" name="struct kern_ipc_perm">)
data for the new set is completed. Other
initialization for this set performed are listed below:
-->
<sect3>newary()<label id="newary"><p>
newary() は、新しいセマフォセットに必要となるメモリを割り当てるために、 <ref id="ipc_alloc" name="ipc_alloc()">を利用しています。そして、セマフォセット記述子とセット中の各セマフォの全てに十分なメモリを割り当てます。
割り当てられたメモリはクリアされ、セマフォセットディスクリプタの最初の要素のアドレスが、<ref id="ipc_addid" name="ipc_addid()"> へと渡されます。<ref id="ipc_addid" name="ipc_addid()"> は、新しいセマフォセット記述子のエントリ配列を予約し、データ(<ref id="struct_kern_ipc_perm" name="struct kern_ipc_perm">)を初期化します。
グローバルな<tt>used_sems</tt> 変数は、新しいセットのセマフォ数で更新されて、新しいセットのためのデータ(<ref id="struct_kern_ipc_perm" name="struct kern_ipc_perm">)の初期化が完了します。このセットに関わる他の初期化は以下の通りです。


<itemize>
<!-- <item> The <tt>sem_base</tt> element for the set is initialized
	to the address immediately following the
	(<ref id="struct_sem_array" name="struct sem_array">)
	portion of the newly allocated data. This corresponds to
	the location of the first semaphore in the set.

--> 
<item>セットの<tt>sem_base</tt> 要素が、新たに割り当てられたデータの(<ref id="struct_sem_array" name="struct sem_array">)のすぐあとのアドレスに初期化される。これは、セット中の最初のセマフォの場所に対応する。

<!-- <item>  The <tt>sem_pending</tt> queue is initialized as empty.-->
<item> <tt>sem_pending</tt>キューは、空に初期化される。
</itemize>

<!--
All of the operations following the call to <ref id="ipc_addid" name="ipc_addid()">
are performed while holding the global semaphores spinlock. After
unlocking the global semaphores spinlock, newary() calls
<ref id="ipc_buildid" name="ipc_buildid()">
(via sem_buildid()). This function uses the index
of the semaphore set descriptor to create a unique ID, that is then
returned to the caller of newary().
-->
<ref id="ipc_addid" name="ipc_addid()">の呼出しに続く全ての操作は、グローバルセマフォスピンロックを保持した状態で実行します。グローバルセマフォスピンロックをアンロックした後に、newary() は、(sem_buildid()経由で)<ref id="ipc_buildid" name="ipc_buildid()"> を呼出します。この関数は、セマフォセットディスクリプタのインデックスを使用し、ユニークな ID を生成します。そして、newary() の呼出し元に戻ります。
</sect3>

<!--
<sect3>freeary()<label id="freeary"><p>
freeary() is called by <ref id="semctl_down" name="semctl_down()"> to perform the
functions listed below. It is called with the global semaphores
spinlock locked and it returns with the spinlock unlocked
-->
<sect3>freeary()<label id="freeary"><p>
freeary() は <ref id="semctl_down" name="semctl_down()">によって呼び出され、以下に列挙する機能を実行します。グローバルなセマフォスピンロックがロックされた状態で呼び出され、スピンロックが解除された状態で戻されます。

<itemize>
<!--
<item>  The <ref id="func_ipc_rmid" name="ipc_rmid()"> function
	is called (via the
	sem_rmid() wrapper) to delete the ID for the semaphore
	set and to retrieve a pointer to the semaphore set.
-->
<item> セマフォセットの ID を削除しセマフォセットへのポインタを回収するため、 <ref id="func_ipc_rmid" name="ipc_rmid()">  関数が、(sem_rmid()ラッパー経由で)呼び出される。

<!--
<item>  The undo list for the semaphore set is invalidated.
<item>  All pending processes are awakened and caused to fail
	with EIDRM.
-->
<item> セマフォセット undo リストの有効性が確認される。
<item> 全ての保留プロセスが起こされ、EIDRM の失敗を引き起こす。
<!--
<item>  The number of used semaphores is reduced by the number
	of semaphores in the removed set.

<item>  The memory associated with the semaphore set is freed.
-->
<item> 使用しているセマフォ数のカウンタは、削除したセットのセマフォ数分減らされる。
<item> セマフォセットに割り当てられたメモリを解放する。
</itemize>
</sect3>


<!--
<sect3>semctl_down()<label id="semctl_down"><p>
semctl_down() provides the <ref id="semctl_ipc_rmid" name="IPC_RMID"> and
<ref id="semctl_ipc_set" name="IPC_SET"> operations of the
semctl() system call.  The semaphore set ID and the access permissions
are verified prior to either of these operations, and in either
case, the global semaphore spinlock is held throughout the
operation.
-->

<sect3>semctl_down() <label id="semctl_down"><p>
semctl_down() は、 semctl()システムコールの <ref id="semctl_ipc_rmid" name="IPC_RMID"> と <ref id="semctl_ipc_set" name="IPC_SET"> 操作を提供します。セマフォセットIDとパーミッションは、これらの操作に先立って確認され、どちらの場合も、操作の間はグローバルセマフォスピンロックを保持します。

<!--
<sect4>IPC_RMID<label id="semctl_ipc_rmid"><p>
The IPC_RMID operation calls <ref id="freeary" name="freeary()"> to remove the semaphore set.
</sect4>
-->
<sect4>
IPC_RMID<label id="semctl_ipc_rmid"><p>
IPC_RMID 操作では、セマフォセットの削除を行うため、 <ref id="freeary" name="freeary()">を呼び出します。
</sect4>
<!--
<sect4>IPC_SET<label id="semctl_ipc_set"><p>
The IPC_SET operation updates the <tt>uid</tt>, <tt>gid</tt>,
<tt>mode</tt>, and <tt>ctime</tt> elements of the semaphore set.
</sect4>
-->
<sect4>
IPC_SET<label id="semctl_ipc_set"><p>
IPC_SET 操作では、セマフォセットの<tt>uid</tt>、<tt>gid</tt>、<tt>mode</tt>および<tt>ctime</tt> 要素を更新します。
</sect4>
</sect3>

<!--
<sect3>semctl_nolock()<label id="semctl_nolock"><p>
semctl_nolock() is called by <ref id="sys_semctl" name="sys_semctl()">
to perform the IPC_INFO, SEM_INFO and SEM_STAT functions.
-->
<sect3>semctl_nolock()<label id="semctl_nolock"><p>
semctl_nolock() は <ref id="sys_semctl" name="sys_semctl()"> から呼び出され、IPC_INFO、SEM_INFO および SEM_STAT 機能を実行します。

<!--
<sect4>IPC_INFO and SEM_INFO<label id="IPC_INFO_and_SEM_INFO"><p>
IPC_INFO and SEM_INFO cause a temporary <ref id="struct_seminfo" name="seminfo">
buffer to be initialized and loaded with unchanging semaphore
statistical data. Then, while holding the global <tt>sem_ids.sem</tt>
kernel semaphore, the <tt>semusz</tt> and <tt>semaem</tt> elements of
the <ref id="struct_seminfo" name="seminfo"> structure are
updated according to the given command (IPC_INFO or SEM_INFO).
The return value of the system call is set to the maximum
semaphore set ID.
-->

<sect4>IPC_INFO と SEM_INFO<label id="IPC_INFO_and_SEM_INFO"><p>
IPC_INFO と SEM_INFO は、臨時に <ref id="struct_seminfo" name="seminfo"> バッファを初期化し、変更されなかったセマフォの統計データを読み込ませます。そして、グローバルの<tt>sem_ids.sem</tt> カーネルセマフォを確保し、 <ref id="struct_seminfo" name="seminfo"> 構造体の <tt>semusz</tt> と <tt>semaem</tt> 要素を与えられた(IPC_INFO または SEM_INFO)コマンドに従い更新します。システムコールの返り値は、セマフォセットIDの最大値になります。
</sect4>

<!--
<sect4>SEM_STAT<label id="SEM_STAT"><p>
SEM_STAT causes a temporary <ref id="struct_semid64_ds" name="semid64_ds">
buffer to be initialized.  The global
semaphore spinlock is then held while copying the <tt>sem_otime</tt>,
<tt>sem_ctime</tt>, and <tt>sem_nsems</tt> values into the buffer. This data is
then copied to user space.
-->

<sect4>SEM_STAT<label id="SEM_STAT"><p>
SEM_STAT は、臨時に<ref id="struct_semid64_ds" name="semid64_ds">バッファを初期化します。その後、グローバルセマフォスピンロックを保持し、<tt>sem_otime</tt>、<tt>sem_ctime</tt>と<tt>sem_nsems</tt> の値をバッファにコピーします。このデータはその後ユーザ空間にコピーされます。
</sect4>
</sect3>

<!--
<sect3>semctl_main()<label id="semctl_main"><p>
semctl_main() is called by <ref id="sys_semctl" name="sys_semctl()"> to perform many
of the supported functions, as described in the subsections below.
Prior to performing any of the following operations, semctl_main()
locks the global semaphore spinlock and validates the
semaphore set ID and the permissions. The spinlock is released
before returning.
-->

<sect3>semctl_main()<label id="semctl_main"><p>
semctl_main() は、 <ref id="sys_semctl" name="sys_semctl()"> により呼び出され、以下の節で示している多くのサポートする機能を実行します。全ての操作に先だって、semctl_main() は、グローバルセマフォロックをロックし、セマフォセットIDとパーミッションの有効性を確認します。スピンロックは戻る前に解除されます。


<!--
<sect4>GETALL<label id="GETALL"><p>
The GETALL operation loads the current semaphore values into
a temporary kernel buffer and copies
them out to user space. The small stack buffer is used if the
semaphore set is small. Otherwise, the spinlock is temporarily
dropped in order to allocate a larger buffer. The spinlock is
held while copying the semaphore values in to the temporary buffer.
-->

<sect4>GETALL<label id="GETALL"><p>
GETALL 操作は、現在のセマフォ値を一時的なカーネルバッファへ読み込み、ユーザ空間へコピーします。もしセマフォバッファが小さければ、小さなスタックバッファが使われます。そうでなければ、スピンロックが一時的に落とされ、大きなバッファを確保します。セマフォ値を一時バッファへコピーする間、スピンロックを保持します。
</sect4>

<!--
<sect4>SETALL<label id="SETALL"><p>
The SETALL operation copies semaphore values from user space into a temporary buffer,
and then into the semaphore set. The spinlock is dropped while
copying the values from user space into the temporary buffer,
and while verifying reasonable values. If the semaphore set
is small, then a stack buffer is used, otherwise a larger buffer
is allocated. The spinlock is regained and held while the
following operations are performed on the semaphore set:
-->

<sect4>SETALL<label id="SETALL"><p>
SETALL 操作は、セマフォ値をユーザ空間からカーネルの一時バッファへコピーし、その後セマフォセットへコピーします。一時バッファへユーザ空間から値をコピーする間、および正しい値か確認する間、スピンロックを落とします。もしセマフォセットが小さければ、スタックバッファが使われ、そうでなければ大きなバッファが確保されます。以下の操作をセマフォセットへ行う間、スピンロックを再取得し、保持します。

<itemize>
<!--
<item>  The semaphore values are copied into the semaphore set.
-->
<item> セマフォ値がセマフォセットへコピーされる。
<!--
<item>  The semaphore adjustments of the undo queue for
	the semaphore set are cleared.
-->
<item> セマフォセットのためのアンドゥキューにあるセマフォ修正はクリアされる。

<!--
<item>  The <tt>sem_ctime</tt> value for the semaphore set is set.
-->
<item> セマフォセットの<tt>sem_ctime</tt> 値が設定される。

<!--
<item>  The <ref id="update_queue" name="update_queue()">
        function is called to traverse
	the queue of pending semops and look for any tasks that
	can be completed as a result of the SETALL operation. Any
	pending tasks that are no longer blocked are awakened.
-->
<item> <ref id="update_queue" name="update_queue()"> 関数が呼び出され、保留している semops のキューを走査し、SETALL 操作の結果として完了できるタスクを探す。もうブロックされていない全ての保留中タスクが起こされる。
</itemize>
</sect4>

<!--
<sect4>IPC_STAT<label id="IPC_STAT"><p>
In the IPC_STAT operation, the <tt>sem_otime</tt>,
<tt>sem_ctime</tt>, and <tt>sem_nsems</tt> value are copied into
a stack buffer. The data is then copied to user space after
dropping the spinlock.
</sect4>
-->

<sect4>IPC_STAT<label id="IPC_STAT"><p>
IPC_STAT 操作では、<tt>sem_otime</tt>、<tt>sem_ctime</tt>と<tt>sem_nsems</tt> 値をスタックバッファへコピーする。そのデータは、その後スピンロックを落としてからユーザ空間へコピーする。
</sect4>

<!--
<sect4>GETVAL<label id="GETVAL"><p>
For GETVAL in the non-error case, the return value for the system call is
set to the value of the specified semaphore.
</sect4>
-->

<sect4>GETVAL<label id="GETVAL"><p>
エラーのない場合、GETVALでは、システムコールの返り値に指定したセマフォの値が設定される。
</sect4>

<!--
<sect4>GETPID<label id="GETPID"><p>
For GETPID in the non-error case, the return value for the system call is
set to the <tt>pid</tt> associated with the last operation on the
semaphore.
</sect4>
-->
<sect4>GETPID<label id="GETPID"><p>
エラーのない場合、GETPIDでは、システムコールの返り値にセマフォでの最後の操作に対応する pid を設定します。
</sect4>


<!--
<sect4>GETNCNT<label id="GETNCNT"><p>
For GETNCNT in the non-error case, the return value for the system call
is set to the number of processes waiting on the semaphore
being less than zero. This number is calculated by the
<ref id="count_semncnt" name="count_semncnt()"> function.
</sect4>
-->

<sect4>GETNCNT<label id="GETNCNT"><p>
エラーのない場合、GETNCNT ではシステムコールの返り値に、セマフォが 0 未満になるのを待っているプロセスの数を設定します。この数値は<ref id="count_semncnt" name="count_semncnt()"> 関数が計算します。
</sect4>


<!--
<sect4>GETZCNT<label id="GETZCNT"><p>
For GETZCNT in the non-error case, the return value for the system call
is set to the number of processes waiting on the semaphore
being set to zero. This number is calculated by the
<ref id="count_semzcnt" name="count_semzcnt()"> function.
</sect4>
-->

<sect4>GETZCNT<label id="GETZCNT"><p>
エラーのない場合、GETZCNT ではシステムコールの返り値に、セマフォが0に設定されるのを待っているプロセスの数を設定します。この数値は<ref id="count_semzcnt" name="count_semzcnt()"> 関数が計算します。
</sect4>


<!--
<sect4>SETVAL<label id="SETVAL"><p>
After validating the new semaphore value, the following
functions are performed:
-->

<sect4>SETVAL<label id="SETVAL"><p>
新しいセマフォ値の有効性を確認したあと、以下の機能が実行されます。

<itemize>
<!--
<item>  The undo queue is searched for any adjustments to
	this semaphore. Any adjustments that are found are reset to
	zero.
-->
<item> このセマフォの修正がないかどうか、undo キューを検索する。

<!--
<item>  The semaphore value is set to the value provided.
-->
<item> セマフォ値に、与えられた値をセットする。
<!--
<item>  The <tt>sem_ctime</tt> value for the semaphore set is updated.
-->
<item> セマフォセットの <tt>sem_ctime</tt> 値を更新する。
<!--
<item>  The <ref id="update_queue" name="update_queue()">
        function is called to traverse
	the queue of pending semops and look for any tasks that
	can be completed as a result of the
	<ref id="SETALL" name="SETALL"> operation. Any
	pending tasks that are no longer blocked are awakened.
オリジナル誤りか? SETALL/SETVAL
-->
<item><ref id="update_queue" name="update_queue()">関数が呼ばれ、保留 semops キューを走査して、
<ref id="SETVAL" name="SETVAL"> 操作の結果として完了できるタスクを検索する。
</itemize>
</sect4>
</sect3>

<!--
<sect3>count_semncnt()<label id="count_semncnt"><p>
count_semncnt() counts the number of tasks waiting on the value of a semaphore
to be less than zero.
</sect3>
-->

<sect3>count_semncnt()<label id="count_semncnt"><p>
count_semncnt() は、セマフォ値が 0 より小さくなるのを待っているタスク数を数えます。
</sect3>


<!--
<sect3>count_semzcnt()<label id="count_semzcnt"><p>
count_semzcnt() counts the number of tasks waiting on the value of a semaphore
to be zero.
-->

<sect3>count_semzcnt()<label id="count_semzcnt"><p>
count_semzcnt() は、セマフォ値が 0 になるのを待っているタスク数を数えます。
</sect3>

<!--
<sect3>update_queue()<label id="update_queue"><p>
update_queue() traverses the queue of pending semops for
a semaphore set and calls
<ref id="try_atomic_semop" name="try_atomic_semop()">
to determine which sequences of semaphore operations
would succeed. If the status of the queue element
indicates that blocked tasks have already
been awakened, then the queue element is skipped over. For other
elements of the queue, the <tt>q-alter</tt> flag
is passed as the undo parameter to
<ref id="try_atomic_semop" name="try_atomic_semop()">,
indicating that any
altering operations should be undone before returning.
-->

<sect3>update_queue()<label id="update_queue"><p>
update_queue() は、セマフォセットの保留中 semops キューを走査して、
<ref id="try_atomic_semop" name="try_atomic_semop()"> を呼び出し、
どのセマフォ操作のシーケンスが成功しそうかを判断します。
もしキュー要素の状態により、ブロックされたタスクがすでに起こされていることが示されていたら、
そのときはそのキュー要素はスキップされます。
キューのその他の要素では、<tt>q-alter</tt> フラグが <ref id="try_atomic_semop" name="try_atomic_semop()"> の undo パラメータとして渡され、変更の操作から戻る前に実行される操作を表します。

<!--
If the sequence of operations would block, then
update_queue() returns without making any changes.
-->

もし一連の操作がブロックされるなら、update_queue() は一切変更されることなく戻ります。

<!--
A sequence of operations can fail if one of the semaphore
operations would cause an invalid semaphore value, or an
operation marked IPC_NOWAIT is unable to complete. In such a
case, the task that is blocked on the sequence of semaphore
operations is awakened, and the queue status is set with an
appropriate error code. The queue element is also dequeued.
-->
もしセマフォ操作の一つが無効なセマフォ値を引き起こしたり、IPC_NOWAIT とマークされている操作が完了できなかったならば、一連の操作は失敗します。そのような場合は、セマフォ操作によりブロックされていたタスクは起こされ、キューの状態として適切なエラーコードが設定されます。キュー要素はもちろんキューから削除されます。

<!--
If the sequence of operations is non-altering, then
they would have passed a zero value as the undo parameter to
<ref id="try_atomic_semop" name="try_atomic_semop()">.
If these operations succeeded, then they
are considered complete and are removed from the queue.
The blocked task is awakened, and the queue element
<tt>status</tt> is set to indicate success.
-->
もし一連の操作が変更を生じないならば、<ref id="try_atomic_semop" name="try_atomic_semop()"> 
の undo パラメータとして 0 を渡します。
もしそれらの操作が成功すれば、処理は完了したと見なして、キューから削除します。ブロックされたタスクが起こされ、キュー要素の<tt>status</tt>が成功を示すよう設定されます。

<!--
If the sequence of operations would alter the semaphore
values, but can succeed, then sleeping tasks that no longer
need to be blocked are awakened. The queue status is set to
1 to indicate that the blocked task has been awakened. The
operations have not been performed, so the queue element is not
removed from the queue. The semaphore operations would be
executed by the awakened task.
-->

もしセットの操作がセマフォの値を変更する場合で、処理が成功できるなら、もうブロックされる必要のない休止タスクが起こされます。操作が実行されなくても、キュー要素がキューから削除されることはありません。セマフォ操作は、起こされたタスクによって実行されます。


</sect3>


<!--
<sect3>try_atomic_semop()<label id="try_atomic_semop"><p>
try_atomic_semop() is called by <ref id="sys_semop" name="sys_semop()">
and <ref id="update_queue" name="update_queue()">
to determine if a sequence of semaphore operations will all
succeed. It determines this by attempting to perform each of the
operations.
-->

<sect3>try_atomic_semop()<label id="try_atomic_semop"><p>
try_atomic_semop() は、<ref id="sys_semop" name="sys_semop()"> と<ref id="update_queue" name="update_queue()"> により呼び出され、一連のセマフォ操作が全て成功するかどうか判断します。これは、各操作の実行を試みることによって判断が行われます。

<!--
If a blocking operation is encountered, then the process
is aborted and all operations are reversed. -EAGAIN is returned
if IPC_NOWAIT is set. Otherwise 1 is returned to indicate that
the sequence of semaphore operations is blocked.
-->
もしブロックされた操作に遭遇したなら、プロセスはアボートし、全ての操作は差し戻されます。
もしIPC_NOWAIT が設定されていたなら -EAGAIN が返されます。そうでなければ 1 が返され、一連のセマフォ操作がブロックされたことを示します。

<!--
If a semaphore value is adjusted beyond system limits, then
then all operations are reversed, and -ERANGE is returned.
-->
もしセマフォ値がシステムの制限を越えて変更されるならば、全ての操作は差し戻され、
-ERANGE が返されます。

<!--
If all operations in the sequence succeed, and the <tt>do_undo</tt>
parameter is non-zero, then all operations are reversed, and 0
is returned. If the <tt>do_undo</tt> parameter is zero, then all operations
succeeded and remain in force, and the <tt>sem_otime</tt>, field of the
semaphore set is updated.
-->
もしシーケンス中の全ての操作が成功しても、<tt>do_undo</tt>パラメータが0でなければ、
全ての操作が差し戻されて、0 が返されます。もし <tt>do_undo</tt> パラメータが 0 なら、
全ての操作が成功し、強制的に残され、セマフォセットの<tt>sem_otime</tt> メンバが更新されます。
</sect3>

<!--
<sect3>sem_revalidate()<label id="sem_revalidate"><p>
sem_revalidate() is called when the global semaphores spinlock
has been temporarily dropped and needs to be locked again. It is
called by <ref id="semctl_main" name="semctl_main()">
and <ref id="alloc_undo" name="alloc_undo()">.  It validates the
semaphore ID and permissions and on success, returns with the
global semaphores spinlock locked.-->

<sect3>sem_revalidate()<label id="sem_revalidate"><p>
sem_revalidate() は、グローバルセマフォスピンロックが一時的に落とされ、再度ロックしなければならないときに呼び出されます。 つまり、<ref id="semctl_main" name="semctl_main()"> と <ref id="alloc_undo" name="alloc_undo()"> によって呼び出されます。セマフォIDとパーミッションの有効性を確認し、良ければグローバルセマフォスピンロックをロックして戻ります。
</sect3>

<!--
<sect3>freeundos()<label id="freeundos"><p>
freeundos() traverses the process undo list in search of
the desired undo structure. If found, the undo structure is removed from the
list and freed. A pointer to the next undo structure on the
process list is returned.-->

<sect3>freeundos()<label id="freeundos"><p>
freeundos() は、プロセスの undo リストを走査し、要求された undo 構造体を探します。
もし見つかれば、undo 構造体はリストから削除され、解放されます。
そして、プロセスリストの次の undo 構造体へのポインタが返されます。
</sect3>


<!--
<sect3>alloc_undo()<label id="alloc_undo"><p>
alloc_undo() expects to be called with the global semaphores
spinlock locked. In the case of an error, it returns with it
unlocked.
-->

<sect3>alloc_undo()<label id="alloc_undo"><p>
alloc_undo() は、グローバルセマフォスピンロックを獲得して呼ばれることを期待しています。エラーがあった場合は、スピンロックを解除して戻ります。

<!--The global semaphores spinlock is unlocked, and kmalloc() is
called to allocate sufficient memory for both the
<ref id="struct_sem_undo" name="sem_undo">
structure, and also an array of one adjustment value for each
semaphore in the set. On success, the global spinlock is regained
with a call to <ref id="sem_revalidate" name="sem_revalidate()">.
-->
グローバルセマフォスピンロックが解除され、 <ref id="struct_sem_undo" name="sem_undo">構造体と、セット中の各セマフォの修正値の配列の両方に十分なメモリを確保するため、kmalloc()を呼び出します。
成功すれば、グローバルスピンロックが<ref id="sem_revalidate" name="sem_revalidate()">を呼び出すことで再確保されます。

<!--
The new semundo structure is then initialized, and the address
of this structure is placed at the address provided by the
caller. The new undo structure is then placed at the head of undo
list for the current task.
-->
新しい semundo 構造体が初期化され、この構造体のアドレスが呼出し元によって与えられたアドレスへ格納されます。新しい undo 構造体は、現在のタスクの undo リストの先頭へ位置させられます。
</sect3>


<!--
<sect3>sem_exit()<label id="sem_exit"><p>sem_exit() is called by do_exit(), and is responsible for
executing all of the undo adjustments for the exiting task.
-->

<sect3>sem_exit()<label id="sem_exit"><p>
sem_exit() は、do_exit() により呼び出され、存在するタスクの全ての undo 修正を実行する責任があります。

<!--
If the current process was blocked on a semaphore, then it is
removed from the <ref id="struct_sem_queue" name="sem_queue">
list while holding the global semaphores spinlock.
-->

もし現在のプロセスがセマフォでブロックされているなら、 グローバルセマフォスピンロックを保持して
<ref id="struct_sem_queue" name="sem_queue">リストから削除します。

<!--
The undo list for the current task is then traversed, and the
following operations are performed while holding and releasing the
the global semaphores spinlock around the processing of each
element of the list. The following operations are performed for
each of the undo elements:
-->
そして現在のタスクのための undo リストが走査され、リストの各要素の処理毎にグローバルセマフォスピンロックの取得と解除が行われつつ、以下の操作が実行されます。以下の操作は、各 undo 要素ごとに実行されます。

<itemize>
<!--
<item>  The undo structure and the semaphore set ID are validated.
<item>  The undo list of the corresponding semaphore set is
	searched to find a reference to the same undo structure and to
	remove it from that list.
<item>  The adjustments indicated in the undo structure are
	applied to the semaphore set.
<item>  The <tt>sem_otime</tt> parameter of the semaphore set is updated.
<item>  <ref id="update_queue" name="update_queue()"> is called
        to traverse the queue of
	pending semops and awaken any sleeping tasks that no longer
	need to be blocked as a result of executing the undo
	operations.
<item>  The undo structure is freed.
-->
<item> undo 構造体とセマフォセット ID について有効性を確認する。
<item> 関連するセマフォセットの undo リストから、同じ undo 構造体への参照が検索され、リストからそれを削除する。
<item> undo 構造体に示されている修正をセマフォセットへ適用する。
<item> セマフォセットの<tt>sem_otime</tt> パラメータが更新される。
<item>  <ref id="update_queue" name="update_queue()"> が呼び出され、保留中の semops のキューを走査して、もうアンドゥ操作の実行の結果としてブロックする必要のない休止タスクを起こす。
<item> undo 構造体を解放する。
</itemize>

<!--
When the processing of the list is complete, the
current->semundo value is cleared.
-->
リストの処理が完了したならば、current-&gt;semundo の値をクリアします。
</sect3>
</sect2>
</sect1>


<!--
<sect1>Message queues<label id= "message"><p>
<sect2>Message System Call Interfaces<label id="Message_System_Call_Interfaces"><p>
<sect3>sys_msgget()<label id="sys_msgget"><p>-->

<sect1>メッセージキュー<label id= "message"><p>
<sect2>メッセージシステムコールインターフェース<label id="Message_System_Call_Interfaces"><p>
<sect3>sys_msgget()<label id="sys_msgget"><p>

<!--
The entire call to sys_msgget() is protected by
the global message queue semaphore
(<ref id="struct_ipc_ids" name="msg_ids.sem">).
-->
sys_msgget()へのコール全体は、グローバルメッセージキューセマフォ(<ref id="struct_ipc_ids" name="msg_ids.sem">)により保護されています。

<!--
In the case where a new message queue must be created,
the <ref id="newque" name="newque()"> function is
called to create and initialize
a new message queue, and the new queue ID is returned to
the caller.
-->
新しいメッセージキューを作らなければならない場合、<ref id="newque" name="newque()">関数が
呼び出され、新しいメッセージキューの作成と初期化を行い、新しいキューIDを呼出し元に返します。

<!--
If a key value is provided for an existing message queue,
then <ref id="ipc_findkey" name="ipc_findkey()"> is called
to look up the corresponding index in the global message queue
descriptor array (msg_ids.entries). The
parameters and permissions of the caller are verified before
returning the message queue ID. The look up operation and
verification are performed while the global message queue
spinlock(msg_ids.ary) is held.
-->
もし与えられたキーの値が既存のメッセージキューへなら、 <ref id="ipc_findkey" name="ipc_findkey()">が呼び出され、グローバルメッセージキューデスクリプタ配列(msg_ids.entries)の対応するインデックスを探します。呼出し元のパラメータとパーミッションは、メッセージキューIDを戻す前に確認されます。検索操作と確認は、グローバルメッセージキュースピンロック(msg_ids.ary)が保持された状態で行われます。
</sect3>


<!--
<sect3>sys_msgctl()<label id="sys_msgctl"><p>
The parameters passed to sys_msgctl() are: a message
queue ID (<tt>msqid</tt>), the operation
(<tt>cmd</tt>), and a pointer to a user space buffer of type
<ref id="struct_msqid_ds" name="msgid_ds">
(<tt>buf</tt>).  Six operations are
provided in this function: IPC_INFO, MSG_INFO,IPC_STAT,
MSG_STAT, IPC_SET and IPC_RMID.  The message queue
ID and the operation parameters are validated; then, the operation(cmd)
is performed as follows:
-->

<sect3>sys_msgctl()<label id="sys_msgctl"><p>
sys_msgctl()へ渡されるパラメータは、メッセージキューID(<tt>msqid</tt>)、操作(<tt>cmd</tt>)、タイプ<ref id="struct_msqid_ds" name="msgid_ds">のユーザ空間バッファへのポインタ(<tt>buf</tt>)です。
6 つの操作がこの関数で提供されています。IPC_INFO, MSG_INFO, IPC_STAT, MSG_STAT, IPC_SET, IPC_RMIDです。メッセージキューIDと操作パラメータが確認され、操作(cmd)が以下のように実行されます。

<!--
<sect4>IPC_INFO ( or MSG_INFO)<label id="msgctl_IPCINFO"><p>
The global message queue information is copied to user space.
</sect4>
-->
<sect4>IPC_INFO (または MSG_INFO)<label id="msgctl_IPCINFO"><p>
グローバルメッセージキューの情報がユーザ空間にコピーされます。
</sect4>


<!--
<sect4>IPC_STAT ( or MSG_STAT)<label id="msgctl_IPCSTAT"><p>
A temporary buffer of type <ref id="struct_msqid64_ds" name="struct msqid64_ds">
is initialized and the global message queue spinlock is locked.
After verifying the access permissions of the calling process,
the message queue information associated with the message
queue ID is loaded into the temporary buffer, the global
message queue spinlock is unlocked, and the contents of
the temporary buffer are copied out to user space by
<ref id="copy_msqid_to_user" name="copy_msqid_to_user()">.
-->

<sect4>IPC_STAT (または MSG_STAT)<label id="msgctl_IPCSTAT"><p>
タイプ <ref id="struct_msqid64_ds" name="struct msqid64_ds"> の一時バッファが初期化され、グローバルメッセージキュースピンロックを取得します。
呼び出したプロセスのアクセス権を確認したら、メッセージキューIDに対応しているメッセージキューの情報を、一時バッファへ読み込みます。そしてメッセージキュースピンロックを解除します。一時バッファの内容は、ユーザ空間へ<ref id="copy_msqid_to_user" name="copy_msqid_to_user()"> により書き出します。
</sect4>

<!--
<sect4>IPC_SET<label id="msgctl_IPCSET"><p>
The user data is copied in via
<ref id="copy_msqid_to_user" name="copy_msqid_to_user()">.  The global
message queue semaphore and spinlock are obtained and released
at the end.  After the the message queue ID and the current
process access permissions are validated, the message queue
information is updated with the user provided data.  Later,
<ref id="expunge_all" name="expunge_all()"> and
<ref id="ss_wakeup" name="ss_wakeup()">
are called to wake up all
processes sleeping on the receiver and sender waiting queues
of the message queue. This is because some receivers may now
be excluded by stricter access permissions and some senders
may now be able to send the message due to an increased
queue size.
-->

<sect4>IPC_SET<label id="msgctl_IPCSET"><p>
ユーザデータは、<ref id="copy_msqid_to_user" name="copy_msqid_to_user()">によりコピーされます。グローバルメッセージキューセマフォとスピンロックはこのとき取得され、最後に解除されます。メッセージキューID と現在のプロセスのアクセス権の有効性が確認された後、メッセージキューの情報がユーザから与えられたデータで更新されます。その後、
<ref id="expunge_all" name="expunge_all()"> と <ref id="ss_wakeup" name="ss_wakeup()">
が呼び出され、全てのメッセージキューの受け手と送り手のウエイトキューで休止しているプロセスを起こします。これは、そのときには受け手が厳密なアクセス権により排除されていたり、送り手がキューサイズが増したことによりメッセージの送信が可能になる場合があるためです。
</sect4>


<!--
<sect4>IPC_RMID<label id="msgctl_IPCRMID"><p>
The global message queue semaphore
is obtained and the global message queue spinlock is locked.
After validating the message queue ID and the current task
access permissions, <ref id="freeque" name="freeque()">
is called to free the resources related to the message queue ID.
The global message queue semaphore and spinlock are released.
-->

<sect4>IPC_RMID<label id="msgctl_IPCRMID"><p>
グローバルメッセージキューセマフォが取得され、グローバルメッセージキュースピンロックがロックされます。メッセージキューIDと現在のタスクのアクセス権の有効性が確認されたあと、<ref id="freeque" name="freeque()">が呼び出されてメッセージキューIDに対応づけられているリソースを解放します。
そして、グローバルメッセージキューセマフォとスピンロックが解除されます。
</sect4>
</sect3>


<!--
<sect3>sys_msgsnd()<label id="sys_msgsnd"><p>
sys_msgsnd() receives as parameters a message queue ID
(<tt>msqid</tt>), a pointer to a buffer of type
<ref id="struct_msg_msg" name="struct msg_msg">
(<tt>msgp</tt>), the size of the message to be sent
(<tt>msgsz</tt>), and a flag indicating wait vs.
not wait (<tt>msgflg</tt>). There are two task waiting
queues and one message waiting queue associated with the message
queue ID. If there is a task in the receiver waiting queue
that is waiting for this message, then the message is
delivered directly to the receiver, and the receiver is
awakened. Otherwise, if there is enough space available in
the message waiting queue, the message is saved in this
queue. As a last resort, the sending task enqueues itself
on the sender waiting queue. A more in-depth discussion of the
operations performed by sys_msgsnd() follows:
-->

<sect3>sys_msgsnd()<label id="sys_msgsnd"><p>
sys_msgsng() は、パラメータとしてメッセージキューID(<tt>msqid</tt>)、<ref id="struct_msg_msg" name="struct msg_msg"> タイプのバッファへのポインタ(<tt>msgp</tt>)、送るメッセージのサイズ(<tt>msgsz</tt>)と、待ちか否かを示すフラグ(<tt>msgflg</tt>)を受け取ります。メッセージキューIDに対応するのは、2つのタスクウエイトキューと、1つのメッセージウエイトキューがあります。受け手ウエイトキューにこのメッセージを待っているタスクがあれば、メッセージは直接受け手へ届けられ、受け手は起こされます。
そうでなければ、メッセージウエイトキューに十分な余裕があれば、メッセージはこのキューへ格納されます。結局は、送り手のタスクは自身を送り手ウエイトキューへいれます。sys_msgsnd()が処理する操作のより詳細な内容は次のようになります。

<enum>
<!--
<item>  Validates the user buffer address and the message
	type, then invokes
	<ref id="load_msg" name="load_msg()"> to load the	contents of the user message into a temporary object
	<tt<label id="msg">msg</tt> of type
	<ref id="struct_msg_msg" name="struct msg_msg">.
	The message type and message size fields
	of <tt>msg</tt> are also initialized.
-->
<item> ユーザバッファアドレスとメッセージタイプの有効性を確認し、その後	<ref id="load_msg" name="load_msg()"> を呼び出して、ユーザメッセージの内容を、<ref id="struct_msg_msg" name="struct msg_msg">タイプの一時オブジェクト<tt><label id="msg">msg</tt>へ読み込みます。
<tt>msg</tt>のメッセージタイプとメッセージサイズ領域も初期化されます。

<!--
<item>  Locks the global message queue spinlock and gets
	the message queue descriptor associated with the
	message queue ID. If no such message queue exists,
	returns EINVAL.
-->
<item> グローバルメッセージキュースピンロックをロックして、メッセージキューIDに対応づけられるメッセージキュー記述子を取得します。そのようなメッセージキューが存在しなければ、EINVAL を返します。

<!--
<item><label id="sndretry">
        Invokes <ref id="ipc_checkid" name="ipc_checkid()">
	(via msg_checkid())to verify that the message
	queue ID is valid and calls
	<ref id="ipcperms" name="ipcperms()"> to check the
	calling process' access permissions.
-->
<item><label id="sndretry"> メッセージキューIDが有効であるか確認するため、(msg_checkid()経由で)<ref id="ipc_checkid" name="ipc_checkid()">を呼び出します。そして、<ref id="ipcperms" name="ipcperms()"> を呼び出して、呼出し元のプロセスのアクセス権をチェックします。

<!--
<item>  Checks the message size and the space left in
	the message waiting queue to see if there is enough
	room to store the message. If not, the following
	substeps are performed:
-->
<item>
メッセージのサイズとメッセージウエイトキューの残りサイズをチェックして、メッセージを格納するのに十分余裕があるかどうか調べます。もし不十分であれば、以下の副項目を実施します。

        <enum>
<!--
        <item>  If IPC_NOWAIT is specified in
		<tt>msgflg</tt> the global message
		queue spinlock is unlocked, the memory
		resources for the message are freed, and EAGAIN
		is returned.
-->
        <item>  もし IPC_NOWAIT が<tt>msgflg</tt> に指定されていれば、グローバルメッセージキュースピンロックが解除され、メッセージ用のメモリ領域が解放されて、EAGAIN を返します。
<!--
        <item>  Invokes
		<ref id="ss_add" name="ss_add()"> to
		enqueue the current
		task in the sender waiting queue. It also unlocks
		the global message queue spinlock and invokes
		schedule() to put the current task to sleep.
-->
       <item> <ref id="ss_add" name="ss_add()"> を起動し、現在のタスクを送り元ウエイトキューへといれます。これはまた、グローバルキュースピンロックを解除し、schedule() を呼び出して、現在のタスクを休止します。
<!--
        <item>  When awakened, obtains the global spinlock
		again and verifies that the message queue ID
		is still valid. If the message queue ID is not valid,
		ERMID is returned.
-->
        <item> 起こされたら、再度グローバルスピンロックを取得し、メッセージキューIDがまだ有効か確認します。もしメッセージキューIDが有効でなければ、ERMID を返します。
<!--
        <item>  Invokes <ref id="ss_del" name="ss_del()">
		to remove the sending task from the sender
		waiting queue. If there is any signal pending
		for the task, sys_msgsnd() unlocks the
		global spinlock,
		invokes <ref id="free_msg" name="free_msg()">
		to free the message buffer,
		and returns EINTR. Otherwise, the function goes
		<ref id="sndretry" name="back">
		to check again whether there is enough space
		in the message waiting queue.
-->
        <item>  <ref id="ss_del" name="ss_del()"> を起動し、送り元ウエイトキューから送り手のタスクを削除します。もしタスクに保留されたシグナルがあれば、 sys_msgsnd() はグローバルスピンロックを解除し、 <ref id="free_msg" name="free_msg()"> を起動して、メッセージバッファを解放してEINTR を返します。そうでなければ、関数は <ref id="sndretry" name="戻り">、メッセージウエイトキューに十分な余裕があるか再度チェックします。 
        </enum>
</item>
<!--
<item>  Invokes
	<ref id="pipelined_send" name="pipelined_send()">
	to try to send the message to the waiting receiver directly.
-->
<item> <ref id="pipelined_send" name="pipelined_send()"> を起動して、メッセージを待っている受け手に直接送ります。
<!--
<item>  If there is no receiver waiting for this message,
	enqueues <tt>msg</tt> into the message waiting
	queue(msq->q_messages). Updates the
	<tt>q_cbytes</tt> and
	the <tt>q_qnum</tt> fields of the message
	queue descriptor, as well as the global variables
	<tt>msg_bytes</tt> and
	<tt>msg_hdrs</tt>, which indicate the total
	number of bytes used for messages and the total number
	of messages system wide.
-->
<item> もしこのメッセージを待つ受け手がなければ、<tt>msg</tt> をメッセージウエイトキュー(msg->q_messages) へ格納します。

大域変数の<tt>msg_bytes</tt> や <tt>msg_hdrs</tt> はメッセージに使われる総バイト数やシステム全体のメッセージ数を意味していますが、 これらと同様、メッセージキュー記述子の <tt>q_cbytes</tt> と <tt>q_qnum</tt> 領域も更新します。
<!--
<item>  If the message has been successfully sent or
	enqueued, updates the <tt>q_lspid</tt>
	and the <tt>q_stime</tt> fields
	of the message queue descriptor and releases the global
	message queue spinlock.
-->
メッセージの送信が成功したり、キューにいれられた場合は、メッセージキュー記述子の<tt>q_lspid</tt>と<tt>q_stime</tt> 領域を更新し、グローバルメッセージスピンロックを解除します。
</enum>
</sect3>

<sect3>sys_msgrcv()<label id="sys_msgrcv"><p>
<!--
The sys_msgrcv() function receives as parameters
a message queue ID
(<tt>msqid</tt>), a pointer to a buffer of type
<ref id="struct_msg_msg" name="msg_msg">
(<tt>msgp</tt>), the desired
message size(<tt>msgsz</tt>), the message type
(<tt>msgtyp</tt>), and the flags
(<tt>msgflg</tt>). It searches the message waiting queue
associated with the message queue ID, finds the first
message in the queue which matches the request type, and
copies it into the given user buffer. If no such message
is found in the message waiting queue, the requesting task
is enqueued into the receiver waiting queue until the
desired message is available. A more in-depth discussion of the
operations performed by sys_msgrcv() follows:
-->
sys_msgrcv() 関数は、パラメータとしてメッセージキューID(<tt>msqid</tt>)、<ref id="struct_msg_msg" name="msg_msg"> 型のバッファへのポインタ(<tt>msgp</tt>)、希望するメッセージのサイズ(<tt>msgsz</tt>)とフラグ(<tt>msgflg</tt>)を受け取ります。メッセージキューIDに関連するメッセージウエイトキューを検索し、要求する型にマッチするキューの最初のメッセージを見つけ、与えられたユーザバッファへコピーします。もし、そのようなメッセージが、メッセージウエイトキューに見つからなかったら、要求元のタスクは希望するメッセージがくるまで受け手ウエイトキューへ入れられます。ss_msgrcv() による操作の、より詳細な説明は以下の通りです。

<enum>
<!--
<item>  First, invokes
	<ref id="convert_mode" name="convert_mode()">
	to derive the search mode from
	<tt>msgtyp</tt>.  sys_msgrcv() then locks
	the global message
	queue spinlock and obtains the message queue descriptor
	associated with the message queue ID. If no such
	message queue exists, it returns EINVAL.
-->
<!-- XXX: miura 2003.3.27  -->
<item> まず、<tt>msgtyp</tt>から検索モードから派生して<ref id="convert_mode" name="convert_mode()">を起動する。そして sys_msgrcv() はグローバルメッセージキュースピンロックをロックする。そしてメッセージキューID に対応するメッセージキュー記述子を得る。もしメッセージキューがなければ EINVAL を返す。

<!--
<item>  Checks whether the current task has the correct
	permissions to access the message queue.
-->
<item> 現在のタスクがメッセージキューをアクセスするパーミッションを持っているかどうかチェックします。
<!--
<item><label id="rcvretry">
        Starting from the first message in the message
	waiting queue, invokes
	<ref id="testmsg" name="testmsg()"> to check whether
	the message type matches the required type.  sys_msgrcv()
	continues searching until a matched message is found or the whole
	waiting queue is exhausted. If the search mode is
	SEARCH_LESSEQUAL, then the first message on the queue
	with the lowest type less than or equal to
	<tt>msgtyp</tt> is searched.
-->
<item> <label id="rcvretry">
メッセージウエイトキューの最初のメッセージから順に <ref id="testmsg" name="testmsg()"> を呼び出し、そのメッセージタイプが要求されたタイプと一致するか確認する。 sys_msgrcv() は、適合するメッセージが見つかるか、全てのウエイトキューを探し尽くすまで検索を継続する。もし検索モードが SEARCH_LESSEQUAL であれば、<tt>msgtyp</tt> 以下で最も小さいタイプのキューの最初のメッセージを探す。
<!--
<item>  If a message is found, sys_msgrcv() performs
	the following substeps:
-->
<item> もしメッセージが見つかったら、 sys_msgrcv() は以下のサブステップを実行する。

        <enum>
<!--
        <item>  If the message size is larger than
		the desired size and <tt>msgflg</tt>
		indicates no error allowed, unlocks the global
		message queue spinlock and returns E2BIG.
-->
        <item> もしメッセージサイズが想定されたサイズより大きく、<tt>msgflg</tt> がエラー許容なしを示していたら、グローバルメッセージキュースピンロックを解除し、E2BIG を返す。
<!--
        <item>  Removes the message from the message
		waiting queue and updates the message queue
		statistics.
-->
   <item>メッセージウエイトキューからメッセージを削除し、メッセージキューの統計情報を更新する。
<!--
        <item>  Wakes up all tasks sleeping on the senders
		waiting queue. The removal of a message from
		the queue in the previous step makes it possible
		for one of the senders to progress. Goes to
		the <ref id="laststep" name="last step">
-->
<item> 送り手ウエイトキューで休止している全てのタスクを起こす。前のステップでキューからメッセージを削除したことで、送り手の中には処理を継続できるものがあるからだ。
そして、<ref id="laststep" name="最後のステップ">へと進む。
        </enum>
<!--
<item>  If no message matching the receivers criteria is found
	in the message waiting queue, then <tt>msgflg</tt>
	is checked. If IPC_NOWAIT is set, then the global message
	queue spinlock is unlocked and ENOMSG is returned. Otherwise,
	the receiver is enqueued on the receiver waiting queue as
	follows:
-->
<item> もしメッセージウエイトキューに受け手の基準に合致するメッセージが見つからなかったら、<tt>msgflg</tt>が確認される。もし IPC_NOWAIT が設定されていたら、グローバルメッセージキュースピンロックを解除し、ENOMSG を返す。そうでなければ、受け手は以下のように受け手ウエイトキューへ入れられる。

	<enum>
<!--
	<item>  A <ref id="struct_msg_receiver" name="msg_receiver"> data structure
		<tt>msr</tt> is allocated and is
		added to the head of waiting queue.
-->
<item> <ref id="struct_msg_receiver" name="msg_receiver"> データ構造体の <tt>msr</tt> を割り当て、ウエイトキューの先頭に追加する。
<!--
        <item>  The <tt>r_tsk</tt> field of <tt>msr</tt>
		is set to current task.
-->
<item> <tt>msr</tt> の <tt>r_tsk</tt> メンバに現在のタスクを設定する。
<!--
        <item>  The <tt>r_msgtype</tt> and
		<tt>r_mode</tt> fields are
		initialized with the desired message type and
		mode respectively.
-->
<item> <tt>r_msgtype</tt> と <tt>r_mode</tt> メンバは初期化され、メッセージのタイプとモードをそれぞれ要求された値にする。
 
<!--        <item>  If <tt>msgflg</tt> indicates
		MSG_NOERROR, then the r_maxsize field of
		<tt>msr</tt> is set to be the
		value of <tt>msgsz</tt> otherwise
		it is set to be INT_MAX.
-->
<item>もし <tt>msgflg</tt> が MSG_NOERROR となっていたら、 <tt>msr</tt> の r_maxsize メンバは <tt>msgsz</tt> の値が設定される。そうでなければ INT_MAX が設定される。

<!--
     <item>  The <tt>r_msg</tt> field
		is initialized to indicate that
		no message has been received yet.
 -->
<item> メンバ <tt>r_msg</tt> はメッセージをまだ受け取っていない状態を表すように初期化される。

<!--
        <item>  After the initialization is complete,
		the status of the receiving task is set to
		TASK_INTERRUPTIBLE, the global message queue
		spinlock is unlocked, and schedule() is invoked.
 -->
<item> 初期化の完了後、受け手のタスクの状態は TASK_INTERRUPTIBLE に設定される。そしてグローバルメッセージキュースピンロックは解除され、 schedule() が呼び出される。

        </enum>
<!--
<item>  After the receiver is awakened,
	the <tt>r_msg</tt> field of
	<tt>msr</tt> is checked.  This field is used to
	store the pipelined message or in the case of an error,
	to store the error status.
	If the <tt>r_msg</tt> field is filled
	with the desired message, then go to the
	<ref id="laststep" name="last step">  Otherwise,
	the global message queue spinlock is locked again.
 -->
<item> 受け手が起きたあと、<tt>msr</tt> の <tt>r_msg</tt> メンバ がチェックされる。
このメンバはパイプラインのメッセージの格納に使われ、エラーの場合にはエラー状態が格納される。
もし、<tt>r_msg</tt> メンバが要求されたメッセージでいっぱいになったら、<ref id="laststep" name="最後のステップ"> へ進む。それ以外の場合は、グローバルメッセージキュースピンロックが再度ロックされる。
<!--
<item>  After obtaining the spinlock,
	the <tt>r_msg</tt> field is
	re-checked to see if the message was received while
	waiting for the spinlock. If the message has been
	received, the <ref id="laststep" name="last step">
	occurs.
 -->
<item>スピンロックの取得後、<tt>r_msg</tt> メンバは、スピンロックを待っている間にメッセージが受け取られていないか、再度確認される。もしメッセージが受け取られているなら、<ref id="laststep" name="最後のステップ"> へ進む。
<!--
<item>  If the <tt>r_msg</tt> field remains
	unchanged, then the task was
	awakened in order to retry.  In this case,
	<tt>msr</tt> is dequeued. If there is a
	signal pending for the task, then the global message
	queue spinlock is unlocked and EINTR is returned.
	Otherwise, the function needs to go
	<ref id="rcvretry" name="back"> and retry.
 -->
<item> もし、<tt>r_msg</tt> メンバが変更されていないなら、再試行のためタスクが起こされる。この場合、<tt>msr</tt> はキューから削除される。もしタスクに保留されたシグナルがあれば、グローバルメッセージキュースピンロックは解除され、 EINTR が返される。
それ以外では、関数は<ref id="rcvretry" name="戻って"> 、再試行される。

<!--
<item>  If the <tt>r_msg</tt> field shows
	that an error occurred
	while sleeping, the global message queue spinlock
	is unlocked and the error is returned. -->
<item> もし<tt>r_msg</tt>メンバにより、休止中にエラーが発生したことが分かれば、グローバルメッセージキュースピンロックは解除され、エラーが返される。
<!--
<item><label id="laststep">
        After validating that the address of the user buffer
	<tt>msp</tt> is valid, message type is loaded
	into the <tt>mtype</tt> field of
	<tt>msp</tt>,and
	<ref id="store_msg" name="store_msg()">
	is invoked to copy the message contents to
	the <tt>mtext</tt> field of
	<tt>msp</tt>. Finally the memory for the message is
	freed by function <ref id="free_msg" name="free_msg()">.
 -->
<item><label id="laststep">
   ユーザバッファのアドレス<tt>msp</tt>の有効性を確認したあと、メッセージタイプが<tt>msp</tt> の <tt>mtype</tt>メンバに書き込まれ、 <ref id="store_msg" name="store_msg()"> が呼び出されて、メッセージの内容が<tt>msr</tt>の<tt>mtext</tt>メンバへコピーされます。最後にメッセージ用のメモリが関数 <ref id="free_msg" name="free_msg()">により解放されます。

</enum>
</sect3>
</sect2>

<!--
<sect2>Message Specific Structures<label id="datastructs"><p>
Data structures for message queues are defined in msg.c.
<sect3>struct msg_queue<label id="struct_msg_queue"><p>
 -->
<sect2>メッセージ独自の構造体<label id="datastructs"><p>
メッセージキューのデータ構造体は msg.c で定義されています。
<sect3>struct msg_queue<label id="struct_msg_queue"><p>
<tscreen><code>
/* one msq_queue structure for each present queue on the system */
struct msg_queue {
        struct kern_ipc_perm q_perm;
        time_t q_stime;                 /* last msgsnd time */
        time_t q_rtime;                 /* last msgrcv time */
        time_t q_ctime;                 /* last change time */
        unsigned long q_cbytes;         /* current number of bytes on queue */
        unsigned long q_qnum;           /* number of messages in queue */
        unsigned long q_qbytes;         /* max number of bytes on queue */
        pid_t q_lspid;                  /* pid of last msgsnd */
        pid_t q_lrpid;                  /* last receive pid */

        struct list_head q_messages;
        struct list_head q_receivers;
        struct list_head q_senders;
};
</code></tscreen>
</sect3>

<sect3>struct msg_msg<label id="struct_msg_msg"><p>
<tscreen><code>
/* one msg_msg structure for each message */
struct msg_msg {
        struct list_head m_list;
        long  m_type;
        int m_ts;           /* message text size */
        struct msg_msgseg* next;
        /* the actual message follows immediately */
};
</code></tscreen>
</sect3>

<sect3>struct msg_msgseg<label id="struct_msg_msgseg"><p>
<tscreen><code>
/* message segment for each message */
struct msg_msgseg {
        struct msg_msgseg* next;
        /* the next part of the message follows immediately */
};
</code></tscreen>
</sect3>

<sect3>struct msg_sender<label id="struct_msg_sender"><p>
<tscreen><code>
/* one msg_sender for each sleeping sender */
struct msg_sender {
        struct list_head list;
        struct task_struct* tsk;
};
</code></tscreen>
</sect3>

<sect3>struct msg_receiver<label id="struct_msg_receiver"><p>
<tscreen><code>
/* one msg_receiver structure for each sleeping receiver */
struct msg_receiver {
        struct list_head r_list;
        struct task_struct* r_tsk;

        int r_mode;
        long r_msgtype;
        long r_maxsize;

        struct msg_msg* volatile r_msg;
};
</code></tscreen>
</sect3>

<sect3>struct msqid64_ds<label id="struct_msqid64_ds"><p>
<tscreen><code>
struct msqid64_ds {
        struct ipc64_perm msg_perm;
        __kernel_time_t msg_stime;      /* last msgsnd time */
        unsigned long   __unused1;
        __kernel_time_t msg_rtime;      /* last msgrcv time */
        unsigned long   __unused2;
        __kernel_time_t msg_ctime;      /* last change time */
        unsigned long   __unused3;
        unsigned long  msg_cbytes;      /* current number of bytes on queue */
        unsigned long  msg_qnum;        /* number of messages in queue */
        unsigned long  msg_qbytes;      /* max number of bytes on queue */
        __kernel_pid_t msg_lspid;       /* pid of last msgsnd */
        __kernel_pid_t msg_lrpid;       /* last receive pid */
        unsigned long  __unused4;
        unsigned long  __unused5;
};
</code></tscreen>
</sect3>

<sect3>struct msqid_ds<label id="struct_msqid_ds"><p>
<tscreen><code>
 struct msqid_ds {
        struct ipc_perm msg_perm;
        struct msg *msg_first;          /* first message on queue,unused  */
        struct msg *msg_last;           /* last message in queue,unused */
        __kernel_time_t msg_stime;      /* last msgsnd time */
        __kernel_time_t msg_rtime;      /* last msgrcv time */
        __kernel_time_t msg_ctime;      /* last change time */
        unsigned long  msg_lcbytes;     /* Reuse junk fields for 32 bit */
        unsigned long  msg_lqbytes;     /* ditto */
        unsigned short msg_cbytes;      /* current number of bytes on queue */
        unsigned short msg_qnum;        /* number of messages in queue */
        unsigned short msg_qbytes;      /* max number of bytes on queue */
        __kernel_ipc_pid_t msg_lspid;   /* pid of last msgsnd */
        __kernel_ipc_pid_t msg_lrpid;   /* last receive pid */
};
</code></tscreen>
</sect3>

<sect3>msg_setbuf<label id="msg_setbuf"><p>
<tscreen><code>
struct msq_setbuf {
        unsigned long   qbytes;
        uid_t           uid;
        gid_t           gid;
        mode_t          mode;
};
</code></tscreen>
</sect3>
</sect2>
<!--
<sect2>Message Support Functions<label id="msgfuncs"><p>
<sect3>newque()<label id="newque"><p>
newque() allocates the memory for a new message queue
descriptor (<ref id="struct_msg_queue" name="struct msg_queue">)
and then calls <ref id="ipc_addid" name="ipc_addid()">, which
reserves a message queue array entry for the new message queue
descriptor.  The message queue descriptor is initialized as
follows:
 -->
<sect2>メッセージサポート関数<label id="msgfuncs"><p>
<sect3>newque()<label id="newque"><p>
newque() は、新しいメッセージキュー記述子(<ref id="struct_msg_queue" name="struct msg_queue">)のためのメモリを割り当て、<ref id="ipc_addid" name="ipc_addid()"> を呼び出して、新しいメッセージキュー記述子用にメッセージキュー配列のエントリを予約させます。
メッセージキュー記述子は以下のように初期化されます。

<itemize>
<!--
<item>  The <ref id="struct_kern_ipc_perm" name="kern_ipc_perm">
        structure is initialized.
 -->
<item>  <ref id="struct_kern_ipc_perm" name="kern_ipc_perm">構造体が初期化される。
<!--
<item>  The <tt>q_stime</tt> and <tt>q_rtime</tt> fields of the message
	queue descriptor are initialized as 0. The <tt>q_ctime</tt>
	field is set to be CURRENT_TIME.
 -->
<item> メッセージキュー記述子の<tt>q_stime</tt>と<tt>q_rtime</tt>メンバは 0 に初期化される。<tt>q_ctime</tt>メンバは CURRENT_TIME に設定される。
<!--
<item>  The maximum number of bytes allowed in this
	queue message (<tt>q_qbytes</tt>) is set to be MSGMNB,
	and the number of bytes currently used by the queue
	(<tt>q_cbytes</tt>) is initialized as 0.
 -->
<item> このキューメッセージで許される最大バイト数(<tt>q_qbytes</tt>)が MSGMNB に設定され、キューにより現在使われているバイト数(<tt>q_cbytes</tt>)が0に初期化される。
<!--
<item>  The message waiting queue (<tt>q_messages</tt>),
	the receiver waiting queue (<tt>q_receivers</tt>),
	and the sender waiting queue (<tt>q_senders</tt>)
	are each initialized as empty.
 -->
<item>メッセージウエイトキュー(<tt>q_messages</tt>)、待ち手ウエイトキュー(<tt>q_receivers</tt>)、送り手ウエイトキュー(<tt>q_senders</tt>)がそれぞれ空に初期化される。
</itemize>
<!--
All the operations following the call to
<ref id="ipc_addid" name="ipc_addid()"> are
performed while holding the global message queue spinlock.
After unlocking the spinlock, newque() calls msg_buildid(),
which maps directly to <ref id="ipc_buildid" name="ipc_buildid()">.
<ref id="ipc_buildid" name="ipc_buildid()">
uses the index of the message queue descriptor to create a unique
message queue ID that is then returned to the caller of newque().
 -->
<ref id="ipc_addid" name="ipc_addid()"> の呼出しにつづく全ての操作は、グローバルメッセージキュースピンロックを保持して実行されます。スピンロックを解除後、newque() は、  <ref id="ipc_buildid" name="ipc_buildid()"> に直接マップされている msg_buildid() を呼び出します。<ref id="ipc_buildid" name="ipc_buildid()"> は、メッセージキュー記述子のインデックスを用いてユニークなメッセージキュー ID を作りだします。そしてこれは、 newque() により呼出し元に戻されます。
</sect3>

<!--
<sect3>freeque()<label id="freeque"><p>
When a message queue is going to be removed, the freeque() function is
called.  This function assumes that the global message queue spinlock
is already locked by the calling function.  It frees all kernel
resources associated with that message queue. First, it calls
<ref id="func_ipc_rmid" name="ipc_rmid()"> (via msg_rmid())
to remove the message queue descriptor from the array of global
message queue descriptors. Then it calls
<ref id="expunge_all" name="expunge_all"> to wake up
all receivers and <ref id="ss_wakeup" name="ss_wakeup()">
to wake up all senders sleeping on this message queue. Later
the global message queue spinlock is released.
All messages stored in this message queue are freed and the
memory for the message queue descriptor is freed.
</sect3>
 -->
<sect3>freeque()<label id="freeque"><p>
メッセージキューが削除されるときは、 freeque() 関数が呼ばれます。この関数は、グローバルメッセージキュースピンロックが、呼出し元関数によって既にロックされているものと仮定します。指定されるメッセージキューに関連している全てのカーネルリソースを解放します。まず、(msg_rmid経由で)<ref id="func_ipc_rmid" name="ipc_rmid()"> を呼び出し、グローバルメッセージキュー記述子の配列からメッセージキュー記述子を削除します。そして、<ref id="expunge_all" name="expunge_all"> を呼び出して、全ての受け手を起こし、<ref id="ss_wakeup" name="ss_wakeup()">を呼び出して、このメッセージキューで休止している全ての送り手を起こします。
最後に、グローバルメッセージキュースピンロックを解除します。このメッセージキューに格納されている全てのメッセージは解放され、メッセージキュー記述子のメモリも解放されます。
</sect3>

<!--
<sect3>ss_wakeup()<label id="ss_wakeup"><p>
ss_wakeup() wakes up all the tasks waiting in the given
message sender waiting queue. If this function is called by
<ref id="freeque" name="freeque()">, then all senders
in the queue are dequeued.
</sect3>
 -->
<sect3>ss_wakeup()<label id="ss_wakeup"><p>
ss_wakeup() は与えられたメッセージ送り手ウエイトキューで待ちになっている全てのタスクを起こします。
この関数が<ref id="freeque" name="freeque()">から呼ばれたなら、キューにある全ての送り手はキューから削除されます。
</sect3>
<!--
<sect3>ss_add()<label id="ss_add"><p>
ss_add() receives as parameters a message queue descriptor
and a message sender data structure.  It fills the
<tt>tsk</tt> field of the message sender data
structure with the current process, changes the status of
current process to TASK_INTERRUPTIBLE,
then inserts the message sender data structure at the head of
the sender waiting queue of the given message queue.
</sect3>
 -->
<sect3>ss_add()<label id="ss_add"><p>
ss_add() はパラメータとしてメッセージキュー記述子とメッセージ送り手データ構造体を受け取ります。現在のプロセスをもとにメッセージ送り手データ構造体の<tt>tsk</tt> メンバを埋め、現在のプロセスの状態を TASK_INTERRUPTIBLE に変更し、そして与えられたメッセージキューの送り手ウエイトキューの先頭へメッセージ送り手データ構造体を挿入します。
</sect3>

<!--
<sect3>ss_del()<label id="ss_del"><p>
If the given message sender data structure
(<tt>mss</tt>) is still in the associated sender
waiting queue, then ss_del() removes
<tt>mss</tt> from the queue.
</sect3>
 -->
<sect3>ss_del()<label id="ss_del"><p>
与えられたメッセージ送り手データ構造体(<tt>mss</tt>) はまだ対応するウエイトキューに保管されたままです。そして、ss_del() は、<tt>mss</tt>をキューから削除します。
</sect3>

<!--
<sect3>expunge_all()<label id="expunge_all"><p>
expunge_all() receives as parameters a message queue
descriptor(<tt>msq</tt>) and an integer value
(<tt>res</tt>) indicating the reason for waking up the
receivers. For each sleeping receiver associated with
<tt>msq</tt>, the <tt>r_msg</tt>
field is set to the indicated
wakeup reason (<tt>res</tt>), and the associated receiving
task is awakened. This function is called when a message queue is
removed or a message control operation has been performed.
</sect3>
 -->
<sect3>expunge_all()<label id="expunge_all"><p>
expunge_all() は、パラメータとしてメッセージキュー記述子(<tt>msq</tt>)と受け手が起こされた理由を示す整数値(<tt>res</tt>)を受け取ります。それぞれの<tt>msq</tt>に対応して休止中の受け手に対して、<tt>r_msg</tt> メンバが起こされた理由(<tt>res</tt>)を設定し、その対応する受け手のタスクが起こされます。
この関数はメッセージキューが削除されるときと、メッセージ制御操作が行われるときに呼び出されます。
</sect3>

<!--
<sect3>load_msg()<label id="load_msg"><p>
When a process sends a message, the
<ref id="sys_msgsnd" name="sys_msgsnd()"> function
first invokes the load_msg() function to load the message
from user space to kernel space.  The message is represented in
kernel memory as a linked list of data blocks. Associated with
the first data block is a <ref id="struct_msg_msg" name="msg_msg">
structure that describes the overall message. The datablock
associated with the msg_msg structure is limited to a size of
DATA_MSG_LEN. The data block and the structure are allocated in one
contiguous memory block that can be as large as one page in memory.
If the full message will not fit into this first data block, then
additional data blocks are allocated and are organized into a
linked list.  These additional data blocks are limited to a size
of DATA_SEG_LEN, and each include an associated
<ref id="struct_msg_msgseg" name="msg_msgseg)"> structure. The
msg_msgseg structure and the associated data block are allocated in
one contiguous memory block that can be as large as one page in
memory.  This function returns the address of the new
<ref id="struct_msg_msg" name="msg_msg"> structure on success.
</sect3>
 -->
<sect3>load_msg()<label id="load_msg"><p>
プロセスがメッセージを送るとき、<ref id="sys_msgsnd" name="sys_msgsnd()"> 関数は、最初に
load_msg() 関数を呼び出し、メッセージをユーザ空間からカーネル空間へと読み込みます。
メッセージはカーネルメモリ内ではデータブロックのリンクリストとして表現されています。
最初のデータブロックに関連しているのは、全てのメッセージを表す<ref id="struct_msg_msg" name="msg_msg"> 構造体です。msg_msg 構造体に関連づけられているデータブロックは、DATA_MSG_LEN のサイズに制限されています。
データブロックと構造体はメモリで一ページで取りうる最大の一つの連続したメモリブロックに割り当てられています。もし全てのメッセージが最初のデータブロックに入りきらなければ、追加のデータブロックが割り当てられ、リンクリストに登録されます。これら追加のデータブロックは、DATA_SEG_LEN にサイズが制限されており、各々は関連する<ref id="struct_msg_msgseg" name="msg_msgseg)"> 構造体を読み込みます。msg_msgseg 構造体と対応するデータブロックはメモリで一ページで取りうる最大の一つの連続したメモリブロックに割り当てられています。この関数は、成功時には新しい<ref id="struct_msg_msg" name="msg_msg"> 構造体のアドレスを返り値にもって戻ります。
</sect3>

<!--
<sect3>store_msg()<label id="store_msg"><p>
The store_msg() function is called by
<ref id="sys_msgrcv" name="sys_msgrcv()"> to reassemble a received
message into the user space buffer provided by the caller. The data
described by the <ref id="struct_msg_msg" name="msg_msg">
structure and any <ref id="struct_msg_msgseg" name="msg_msgseg">
structures are sequentially copied to the user space buffer.
</sect3>
 -->
<sect3>store_msg()<label id="store_msg"><p>
store_msg() 関数は、<ref id="sys_msgrcv" name="sys_msgrcv()"> により呼び出され、受けたメッセージを呼出し元の提供するユーザ空間バッファへ再度組み立てます。 <ref id="struct_msg_msg" name="msg_msg"> 構造体と<ref id="struct_msg_msgseg" name="msg_msgseg">構造体により示されるデータは、ユーザ空間バッファへ順次コピーされます。
</sect3>

<!--
<sect3>free_msg()<label id="free_msg"><p>
The free_msg() function releases the memory for a message
data structure <ref id="struct_msg_msg" name="msg_msg">,
and the message segments.
</sect3>
 -->
<sect3>free_msg()<label id="free_msg"><p>
free_msg() 関数はメッセージデータ構造体 <ref id="struct_msg_msg" name="msg_msg"> とメッセージセグメントのメモリを解放します。
</sect3>

<!--
<sect3>convert_mode()<label id="convert_mode"><p>
convert_mode() is called by <ref id="sys_msgrcv" name="sys_msgrcv()">.
It receives as parameters the address of the specified message
type (<tt>msgtyp</tt>) and a flag (<tt>msgflg</tt>).
It returns the search mode to the caller based on the value of
<tt>msgtyp</tt> and <tt>msgflg</tt>.  If
<tt>msgtyp</tt> is null, then SEARCH_ANY is returned.
If <tt>msgtyp</tt> is less than 0, then <tt>msgtyp</tt> is
set to it's absolute value and SEARCH_LESSEQUAL is returned.
If MSG_EXCEPT is specified in <tt>msgflg</tt>, then SEARCH_NOTEQUAL is returned.
Otherwise SEARCH_EQUAL is returned.
</sect3>
 -->
<sect3>convert_mode()<label id="convert_mode"><p>
convert_mode() は <ref id="sys_msgrcv" name="sys_msgrcv()"> から呼び出されます。パラメータとして、指定するメッセージタイプの<!-- 原文のaddress は実際の関数ではポインタのこと -->ポインタ(<tt>msgtyp</tt>)とフラグ(<tt>msgflg</tt>)を受け取ります。
この関数は、<tt>msgtyp</tt>と<tt>msgflg</tt>の値に基づいて、呼出し元へ検索モードを返します。もし、<tt>msgtyp</tt>が0<!-- long *msgtyp と定義されていて条件判断で if (*msgtype == 0) とされているので、原文のNULLは誤り。 -->ならば、 SEARCH_ANYを返します。
もし、<tt>msgtyp</tt>の値が0より小さければ、<tt>msgtype</tt>はその絶対値に設定され、SEARCH_LESSEQUAL を返します。もし MSG_EXCEPT が<tt>msgflg</tt> に指定されていれば、SEARCH_NOTEQUAL が返されます。そうでなければ、SEARCH_EQUAL が返されます。

</sect3>
<!--
<sect3>testmsg()<label id="testmsg"><p>
The testmsg() function checks whether a message meets the
criteria specified by the receiver.  It returns 1 if one of the
following conditions is true:
 -->
<sect3>testmsg()<label id="testmsg"><p>
testmsg() 関数は、メッセージが受け手の指定する条件に合致するか調べます。もし、以下の条件の一つが真となれば、1を返します。

<!--
<itemize>
<item>  The search mode indicates searching any message (SEARCH_ANY).
<item>  The search mode is SEARCH_LESSEQUAL and the message type
	is less than or equal to desired type.
<item>  The search mode is SEARCH_EQUAL and the message type is
	the same as desired type.
<item>  Search mode is SEARCH_NOTEQUAL and the message type is
	not equal to the specified type.
</itemize>
 -->
<itemize>
<item> 検索モードが全メッセージ検索(SEARCH_ANY)の場合
<item> 検索モードが SEARCH_LESSEQUAL に指定されており、メッセージタイプが指定されたタイプ以下である場合
<item> 検索モードが SEARCH_EQUAL でメッセージタイプが指定されたタイプと同じである場合
<item> 検索モードが SEARCH_NOTEQUAL で、メッセージタイプが指定されたタイプと異なる場合 
</itemize>
</sect3>

<!--
<sect3>pipelined_send()<label id="pipelined_send"><p>
pipelined_send() allows a process to directly send a message
to a waiting receiver rather than deposit the message in the
associated message waiting queue. The
<ref id="testmsg" name="testmsg()"> function is
invoked to find the first receiver which is waiting for the
given message. If found, the waiting receiver is removed from
the receiver waiting queue, and the associated receiving task is
awakened. The message is stored in the <tt>r_msg</tt>
field of the receiver, and 1 is returned. In the case where no
receiver is waiting for the message, 0 is returned.
 -->
<sect3>pipelined_send()<label id="pipelined_send"><p>
プロセスは pipelined_send() を使うことで、対応づけられているメッセージキューへ入れるのではなく、直接待機中の受け手へメッセージを送ることができます。
与えられたメッセージを待つ最初の受け手を見つけるため、 <ref id="testmsg" name="testmsg()"> 関数を呼び出します。もし見つかれば、待っている受け手は受け手ウエイトキューから削除され、関連する受け手のタスクは起こされます。メッセージは受け手の<tt>r_msg</tt>メンバへ格納されて、1を返します。メッセージを待っている受け手がいない場合、0を返します。

<!--
In the process of searching for a receiver, potential
receivers may be found which have requested a size that is too small
for the given message. Such receivers are removed from the queue,
and are awakened with an error status of E2BIG, which is stored in the
<tt>r_msg</tt> field. The search then continues until
either a valid receiver is found, or the queue is exhausted.
 -->
受け手を探すプロセスでは、与えられたメッセージに対して小さすぎるサイズを要求していることで、潜在的受け手が分かるでしょう。そのような受け手はキューから削除され、起こされてエラー状態 E2BIG を渡されます。このエラーは、<tt>r_msg</tt>メンバに格納されます。この検索は、有効な受け手が見つかるか、キューを見尽くすまで継続します。
</sect3>

<!--
<sect3>copy_msqid_to_user()<label id="copy_msqid_to_user"><p>
copy_msqid_to_user() copies the contents of a kernel buffer to
the user buffer.  It receives as parameters a user buffer, a
kernel buffer of type
<ref id="struct_msqid64_ds" name="msqid64_ds">, and a
version flag indicating
the new IPC version vs. the old IPC version.  If the version
flag equals IPC_64, then copy_to_user() is invoked to copy from
the kernel buffer to the user buffer directly.  Otherwise a
temporary buffer of type struct msqid_ds is initialized, and the
kernel data is translated to this temporary buffer.  Later
copy_to_user() is called to copy the contents of the the temporary
buffer to the user buffer.
</sect3>
 -->
<sect3>copy_msqid_to_user()<label id="copy_msqid_to_user"><p>
copy_msqid_to_user() はカーネルバッファの内容をユーザバッファにコピーします。パラメータとしてユーザバッファと <ref id="struct_msqid64_ds" name="msqid64_ds"> 型のカーネルバッファと、新しいIPC バージョンか古い IPC バージョンかを示すバージョンフラグを受け取ります。
もしバージョンフラグが IPC_64 ならば、 copy_to_user() が起動され、カーネルバッファからユーザバッファへ直接コピーします。そうでなければ、struct msqid_ds 型の一時バッファが初期化され、カーネルデータはこの一時バッファへ変換されます。そして、copy_to_user() が呼び出され、一時バッファの内容がユーザバッファへコピーされます。
</sect3>

<!--
<sect3>copy_msqid_from_user()<label id="copy_msqid_from_user"><p>
The function copy_msqid_from_user() receives as parameters
a kernel message buffer of type struct msq_setbuf, a user buffer
and a version flag indicating the new IPC version vs. the old IPC
version.  In the case of the new IPC version, copy_from_user()
is called to copy the contents of the user buffer
to a temporary buffer of type <ref id="struct_msqid64_ds" name="msqid64_ds">.
Then, the <tt>qbytes</tt>,<tt>uid</tt>, <tt>gid</tt>,
and <tt>mode</tt> fields of the kernel buffer are
filled with the values of the
corresponding fields from the temporary buffer.  In the case of the
old IPC version, a temporary buffer of type struct
<ref id="struct_msqid_ds" name="msqid_ds"> is used instead.
</sect3>
 -->
<sect3>copy_msqid_from_user()<label id="copy_msqid_from_user"><p>
copy_msqid_from_user() 関数は、パラメータとしてstruct msq_setbuf型のカーネルメッセージバッファとユーザバッファと、新しいIPC バージョンか古い IPC バージョンかを示すバージョンフラグを受け取ります。IPCバージョンが新しい場合、copy_from_user()が呼び出されて、ユーザバッファの内容を <ref id="struct_msqid64_ds" name="msqid64_ds"> 型の一時バッファへコピーします。
そしてカーネルバッファの<tt>qbytes</tt>, <tt>uid</tt>, <tt>gid</tt>と<tt>mode</tt>領域を一時バッファの対応する領域の値にします。古い IPC のバージョンならば、<ref id="struct_msqid_ds" name="msqid_ds"> 型の一時バッファを代りに用います。
</sect3>
</sect2>
</sect1>


<!--
<sect1>Shared Memory<label id="sharedmem"><p>
<sect2>Shared Memory System Call Interfaces<label id="Shared_Memory_System_Call_Interfaces">
<p>
-->
<sect1>共有メモリ<label id="sharedmem"><p>
<sect2>共有メモリシステムコールインターフェース<label id="Shared_Memory_System_Call_Interfaces">
<p>
<!--
<sect3>sys_shmget()<label id="sys_shmget"><p>
The entire call to sys_shmget() is protected by the
global shared memory semaphore.

In the case where a new shared memory segment must
be created, the <ref id="newseg" name="newseg()"> function is called to create
and initialize a new shared memory segment.  The ID of
the new segment is returned to the caller.

In the case where a key value is provided for an
existing shared memory segment, the corresponding index
in the shared memory descriptors array is looked up, and
the parameters and permissions of the caller are verified
before returning the shared memory segment ID. The look up
operation and verification are performed while the global
shared memory spinlock is held.
</sect3>
 -->
<sect3>sys_shmget()<label id="sys_shmget"><p>
sys_shmget() は、呼出し全体をグローバル共有メモリセマフォにより保護します。

新しい共有メモリセグメントを作る必要のある場合、 関数<ref id="newseg" name="newseg()"> が呼び出され、新しい共有メモリセグメントを作成し初期化します。新しいセグメントのIDが呼出し元へ返されます。

既存の共有メモリセグメントの キー値が与えられている場合、共有メモリ記述子配列の対応するインデックスを見つけ出し、パラメータと呼出し元のパーミッションを確認後、共有メモリセグメントIDを返します。
検索操作と有効性の確認はグローバル共有メモリスピンロックを保持した状態で行われます。
</sect3>

<!--
<sect3>sys_shmctl()<label id="sys_shmctl"><p>
<sect4>IPC_INFO<label id="IPC_INFO"><p>
A temporary <ref id="struct_shminfo64" name="shminfo64">
buffer is loaded with system-wide
shared memory parameters and is copied out to user space for
access by the calling application.
</sect4>
 -->
<sect3>sys_shmctl()<label id="sys_shmctl"><p>
<sect4>IPC_INFO<label id="IPC_INFO"><p>
一時バッファ <ref id="struct_shminfo64" name="shminfo64"> が
システムワイドの共有メモリパラメータとともに読み込まれ、呼出し元のアプリケーションからアクセスするユーザ空間へコピーします。
</sect4>

<!--
<sect4>SHM_INFO<label id="SHM_INFO"><p>
The global shared memory semaphore and the global shared
memory spinlock are held while gathering system-wide statistical
information for shared memory.  The
<ref id="shm_get_stat" name="shm_get_stat()"> function is called
to calculate both the number of shared memory pages that are
resident in memory and the number of shared memory pages that are
swapped out. Other statistics include the total number of shared
memory pages and the number of shared memory segments in use.
The counts of <tt>swap_attempts</tt> and <tt>swap_successes</tt>
are hard-coded to zero. These statistics are stored in a temporary
<ref id="struct_shm_info" name="shm_info"> buffer and copied out
to user space for the calling application.
</sect4>
 -->
<sect4>SHM_INFO<label id="SHM_INFO"><p>
共有メモリのシステムワイドの統計情報を集める間は、グローバル共有メモリセマフォとグローバル共有メモリスピンロックを取得します。
関数<ref id="shm_get_stat" name="shm_get_stat()"> を呼び出し、メモリ中に存在する共有メモリページ数とスワップアウトした共有メモリページ数を計算します。
<tt>swap_attempts</tt>と<tt>swap_successes</tt>の計数は、常に0 とされています。これらの統計値は一時バッファ <ref id="struct_shm_info" name="shm_info"> へ格納され、呼び出したアプリケーションのユーザ空間へとコピーされます。
</sect4>

<!--
<sect4>SHM_STAT, IPC_STAT<label id="SHM_STAT_IPC_STAT"><p>
For SHM_STAT and IPC_STATA, a temporary buffer of type
<ref id="struct_shmid64_ds" name="struct shmid64_ds"> is
initialized, and the global shared memory spinlock is locked.

XXX 'IPC_STATA' may typo of 'IPC_STAT' by miura XXX

 -->
<sect4>SHM_STAT, IPC_STAT<label id="SHM_STAT_IPC_STAT"><p>
SHM_STAT と IPC_STAT のため、<ref id="struct_shmid64_ds" name="struct shmid64_ds"> 型の一時バッファが初期化され、グローバル共有メモリスピンロックをロックします。

<!--
For the SHM_STAT case, the shared memory segment ID parameter is
expected to be a straight index (i.e. 0 to n where n is the
number of shared memory IDs in the system). After validating
the index, <ref id="ipc_buildid" name="ipc_buildid()">
is called (via shm_buildid()) to
convert the index into a shared memory ID. In the passing case
of SHM_STAT, the shared memory ID will be the return value.
Note that this is an undocumented feature, but is maintained
for the ipcs(8) program.
 -->
SHM_STAT の場合は、共有メモリセグメント ID パラメータは、１次元のインデックス(つまり、0 から n で、n はシステムの共有メモリ ID の番号) を期待しています。<!--  straight index の訳語は検討必要  -->
インデックスの有効性を確認後、<ref id="ipc_buildid" name="ipc_buildid()"> が(shm_buildid()経由で)呼び出され、インデックスを共有メモリ ID へ変換します。SHM_STAT を渡した場合、共有メモリ ID が返り値になります。この機能は文献にないけれども、ipcs(8) プログラムのために準備されていることに注意しましょう。

<!--
For the IPC_STAT case, the shared memory segment ID parameter is
expected to be an ID that was generated by a call to
<ref id="sys_shmget" name="shmget()">.
The ID is validated before proceeding. In the passing case of
IPC_STAT, 0 will be the return value.
 -->
IPC_STAT の場合、共有メモリセグメント ID パラメータについて、IDが<ref id="sys_shmget" name="shmget()"> を呼出して生成されていることを期待します。
この ID は処理を行う前に有効性が確認されます。IPC_STAT を渡した場合、0 が返り値となります。

<!--
For both SHM_STAT and IPC_STAT, the access permissions of
the caller are verified. The desired statistics are loaded into
the temporary buffer and then copied out to the calling
application.
 -->
SHM_STATと IPC_STAT の双方について、呼出し元のアクセス権の有効性を確認します。要求された統計情報は一時バッファへ読み込まれ、その後呼出し元へコピーされます。
</sect4>

<!--
<sect4>SHM_LOCK, SHM_UNLOCK<label id="SHM_LOCK_SHM_UNLOCK"><p>
After validating access permissions, the global shared
memory spinlock is locked, and the shared memory segment ID
is validated.  For both SHM_LOCK and SHM_UNLOCK,
<ref id="shmem_lock" name="shmem_lock()">
is called to perform the function. The parameters for
<ref id="shmem_lock" name="shmem_lock()">
identify the function to be performed.
</sect4>
 -->
<sect4>SHM_LOCK, SHM_UNLOCK<label id="SHM_LOCK_SHM_UNLOCK"><p>
アクセス権の有効性を確認後、グローバル共有メモリスピンロックをロックし、共有メモリセグメントIDの有効性を確認します。SHM_LOCK と SHM_UNLOCK 双方で、その処理を行うため、<ref id="shmem_lock" name="shmem_lock()"> を呼び出します。<ref id="shmem_lock" name="shmem_lock()">のパラメータには、処理すべき関数の識別子を渡します。
</sect4>

<!--
<sect4>IPC_RMID<label id="IPC_RMID"><p>
During IPC_RMID the global shared memory semaphore and
the global shared memory spinlock are held throughout this
function. The Shared Memory ID is validated, and then if
there are no current attachments, <ref id="shm_destroy" name="shm_destroy()">
is called to destroy the shared memory segment.
Otherwise, the SHM_DEST flag is set to mark it for destruction,
and the IPC_PRIVATE flag is set to prevent other processes from
being able to reference the shared memory ID.
</sect4>
 -->
<sect4>IPC_RMID<label id="IPC_RMID"><p>
IPC_RMID の処理の間は、グローバル共有メモリセマフォとグローバル共有メモリスピンロックが取得されます。共有メモリID の有効性を確認したあと、もし current attachment がなければ、<ref id="shm_destroy" name="shm_destroy()"> を呼出し、共有メモリセグメントを破壊します。そうでなければ、SHM_DEST フラグをセットし、これが破壊するという印になります。そして、他のプロセスを共有メモリIDの参照から守るために、IPC_PRIVATE フラグをセットします。

</sect4>

<!--
<sect4>IPC_SET<label id="IPC_SET"><p>
After validating the shared memory segment ID and the user
access permissions, the <tt>uid</tt>, <tt>gid</tt>, and <tt>mode</tt> flags of the
shared memory segment are updated with the user data. The
<tt>shm_ctime</tt> field is also updated.  These changes are made
while holding the global shared memory semaphore and the
global share memory spinlock.
</sect4> -->
<sect4>IPC_SET<label id="IPC_SET"><p>
共有メモリセグメントIDとユーザのアクセス権の有効性を確認後、共有メモリセグメントの<tt>uid</tt>や<tt>gid</tt>、そして<tt>mode</tt> フラグをユーザデータで更新します。<tt>shm_ctime</tt>領域も更新します。これらの変更は、グローバル共有メモリセマフォとグローバル共有メモリスピンロックを保持した状態で処理されます。
</sect4>
</sect3>

<!--
<sect3>sys_shmat()<label id="sys_shmat"><p>
sys_shmat() takes as parameters, a shared memory segment ID,
an address at which the shared memory segment should be
attached(<tt>shmaddr</tt>), and flags which will be described below.
 -->
<sect3>sys_shmat()<label id="sys_shmat"><p>
sys_shmat() は、共有メモリセグメントIDと共有メモリセグメントを配置するアドレス(<tt>shmaddr</tt>)、そして以下に示すフラグをパラメータに取ります。

<!--
If <tt>shmaddr</tt> is non-zero, and the SHM_RND flag is
specified, then <tt>shmaddr</tt> is rounded down to a multiple of
SHMLBA. If <tt>shmaddr</tt> is not a multiple of SHMLBA and SHM_RND
is not specified, then EINVAL is returned.
 -->
もし<tt>shmaddr</tt>が0でなく、SHM_RND フラグが指定されていたなら、<tt>shmaddr</tt>は SHMLBA の倍数へと丸められます。もし、<tt>shmaddr</tt> がSHMLBAの倍数でなく、SHM_RND も指定されていなければ、EINVAL が返されます。

<!--
The access permissions of the caller are validated and
the <tt>shm_nattch</tt> field for the shared memory segment is
incremented. Note that this increment guarantees that the
attachment count is non-zero and prevents the shared memory
segment from being destroyed during the process of attaching
to the segment.  These operations are performed while holding the
global shared memory spinlock.
 -->
呼出し元のアクセス権の有効性が確認され、共有メモリセグメントの<tt>shm_nattch</tt>領域が1つ増分され
ます。ここで、この増分は 割り当てカウントが0ではないことを保証し、共有メモリセグメントをセグメントの割り当て処理中の破壊から守るために行われます。これらの操作は、グローバル共有メモリスピンロックを保持した状態で行われます。

<!--
The do_mmap() function is called to create a virtual memory
mapping to the shared memory segment pages. This is done while
holding the <tt>mmap_sem</tt> semaphore of the current task. The
MAP_SHARED flag is passed to do_mmap(). If an address was
provided by the caller, then the MAP_FIXED flag is also passed
to do_mmap(). Otherwise, do_mmap() will select the virtual
address at which to map the shared memory segment.
 -->

共有メモリセグメントページへの仮想メモリマップを作るため、 do_mmap() 関数を呼び出します。これはカレントタスクの <tt>mmap_sem</tt> セマフォを保持した状態で行われます。MAP_SHARED フラグが do_mmap() へ渡されます。もしアドレスが呼出し元から渡されたなら、 MAP_FIXED フラグも do_mmap() へ渡されます。そうでなければ、 共有メモリセグメントへ割り当てる仮想アドレスは do_mmap() が選びます。

<!--
NOTE <ref id="shm_inc" name="shm_inc()"> will be invoked within the do_mmap()
function call via the <tt>shm_file_operations</tt> structure. This
function is called to set the PID, to set the current time, and
to increment the number of attachments to this shared memory
segment.
 -->
注: <ref id="shm_inc" name="shm_inc()">が do_mmap() 関数コールの中で <tt>shm_file_operations</tt> 構造体を経て起動されます。この関数は、 PID を設定し、現在の時刻を設定し、この共有メモリセグメントへの割り当て数を増分するため呼び出されます。


<!--
After the call to do_mmap(), the global shared memory
semaphore and the global shared memory spinlock are both
obtained.  The attachment count is then decremented.  The the net
change to the attachment count is 1 for a call
to shmat() because of the call to <ref id="shm_inc" name="shm_inc()">. If, after
decrementing the attachment count, the resulting count is found
to be zero, and if the segment is marked for destruction
(SHM_DEST), then <ref id="shm_destroy" name="shm_destroy()"> is
called to release the shared memory segment resources.
 -->
do_mmap() を呼び出したあとは、グローバル共有メモリセマフォとグローバル共有メモリスピンロックの両方が取得されます。割り当てカウントは減少されます。

<ref id="shm_inc" name="shm_inc()"> を呼び出すため、shmat()への呼び出しに対して割り当て数の正味の変更が 1 になります。もし割り当て数の減少した後で、セグメントが破壊にマーク(SHM_DEST)されたら、<ref id="shm_destroy" name="shm_destroy()"> が呼び出され、共有メモリセグメントの資源が解放されます。`

<!--
Finally, the virtual address at which the shared memory is
mapped is returned to the caller at the user specified address.
If an error code had been returned by do_mmap(), then this
failure code is passed on as the return value for the system call.
 -->
最後に、共有メモリのマップされる仮想メモリが、呼出し元のユーザの指定したアドレスへ返されます。
 do_mmap() よりエラーコードが返されたときには、このエラーコードがシステムコールの返り値として戻されます。
</sect3>

<sect3>sys_shmdt()<label id="sys_shmdt"><p>
<!--
The global shared memory semaphore is held while performing
sys_shmdt(). The <tt>mm_struct</tt> of the current
process is searched for the <tt>vm_area_struct</tt> associated with
the shared memory address. When it is found, do_munmap() is
called to undo the virtual address mapping for the shared memory segment.
 -->
sys_shmdt() の処理中はグローバル共有メモリセマフォが保持されます。現在のプロセスの<tt>mm_struct</tt> について、共有メモリアドレスに対応する <tt>vm_area_struct</tt> を検索します。
もし見つかれば、 do_munmap() が呼び出されて、共有メモリセグメントの仮想アドレスへのマッピングが解除されます。

<!--
Note also that do_munmap() performs a call-back to
<ref id="shm_close" name="shm_close()">,
which performs the shared-memory book keeping functions, and
releases the shared memory segment resources if there are no other
attachments.

sys_shmdt() unconditionally returns 0.
 -->
ここで、 do_munmap() は共有メモリの予約を維持する関数の<ref id="shm_close" name="shm_close()">をコールバックし、他の割り当てがない共有メモリセグメントの資源を解放することに注意してください。

sys_shmdt() は無条件に0を返します。
</sect3>
</sect2>
<!--
<sect2>Shared Memory Support Structures<label id="shm_structures"><p>
 -->
<sect2>共有メモリサポート構造体<label id="shm_structures"><p>
<sect3>struct shminfo64<label id="struct_shminfo64"><p>
<tscreen><code>
struct shminfo64 {
        unsigned long   shmmax;
        unsigned long   shmmin;
        unsigned long   shmmni;
        unsigned long   shmseg;
        unsigned long   shmall;
        unsigned long   __unused1;
        unsigned long   __unused2;
        unsigned long   __unused3;
        unsigned long   __unused4;
};
</code></tscreen>
</sect3>
<sect3>struct shm_info<label id="struct_shm_info"><p>
<tscreen><code>
struct shm_info {
        int used_ids;
        unsigned long shm_tot;  /* total allocated shm */
        unsigned long shm_rss;  /* total resident shm */
        unsigned long shm_swp;  /* total swapped shm */
        unsigned long swap_attempts;
        unsigned long swap_successes;
};
</code></tscreen>
</sect3>

<sect3>struct shmid_kernel<label id="struct_shmid_kernel"><p>
<tscreen><code>
struct shmid_kernel /* private to the kernel */
{
        struct kern_ipc_perm    shm_perm;
        struct file *           shm_file;
        int                     id;
        unsigned long           shm_nattch;
        unsigned long           shm_segsz;
        time_t                  shm_atim;
        time_t                  shm_dtim;
        time_t                  shm_ctim;
        pid_t                   shm_cprid;
        pid_t                   shm_lprid;
};
</code></tscreen>
</sect3>

<sect3>struct shmid64_ds<label id="struct_shmid64_ds"><p>
<tscreen><code>
struct shmid64_ds {
        struct ipc64_perm       shm_perm;       /* operation perms */
        size_t                  shm_segsz;      /* size of segment (bytes) */
        __kernel_time_t         shm_atime;      /* last attach time */
        unsigned long           __unused1;
        __kernel_time_t         shm_dtime;      /* last detach time */
        unsigned long           __unused2;
        __kernel_time_t         shm_ctime;      /* last change time */
        unsigned long           __unused3;
        __kernel_pid_t          shm_cpid;       /* pid of creator */
        __kernel_pid_t          shm_lpid;       /* pid of last operator */
        unsigned long           shm_nattch;     /* no. of current attaches */
        unsigned long           __unused4;
        unsigned long           __unused5;
};
</code></tscreen>
</sect3>

<sect3>struct shmem_inode_info<label id="struct_shmem_inode_info"><p>
<tscreen><code>
struct shmem_inode_info {
        spinlock_t      lock;
        unsigned long   max_index;
        swp_entry_t     i_direct[SHMEM_NR_DIRECT]; /* for the first blocks */
        swp_entry_t   **i_indirect; /* doubly indirect blocks */
        unsigned long   swapped;
        int             locked;     /* into memory */
        struct list_head        list;
};
</code></tscreen>
</sect3>
</sect2>

<!--
<sect2>Shared Memory Support Functions<label id="shm_primitives"><p>
<sect3>newseg()<label id="newseg"><p>
The newseg() function is called when a new shared memory
segment needs to be created.  It acts on three parameters for
the new segment the key, the flag, and the size.  After
validating that the size of the shared memory segment to be
created is between SHMMIN and SHMMAX and that the total number
of shared memory segments does not exceed SHMALL, it allocates
a new shared memory segment descriptor.
The <ref id="shmem_file_setup" name="shmem_file_setup()">
function is invoked later to create an unlinked file of type
tmpfs.  The returned file pointer is saved in the <tt>shm_file</tt> field
of the associated shared memory segment descriptor. The files
size is set to be the same as the size of the segment.  The
new shared memory segment descriptor is initialized and inserted
into the global IPC shared memory descriptors array.  The shared
memory segment ID is created by shm_buildid()
(via <ref id="ipc_buildid" name="ipc_buildid()">).
This segment ID is saved in the <tt>id</tt> field of the shared memory
segment descriptor, as well as in the <tt>i_ino</tt> field of the associated
inode.  In addition, the address of the shared memory operations
defined in structure <tt>shm_file_operation</tt> is stored in the associated
file.  The value of the global variable <tt>shm_tot</tt>, which indicates
the total number of shared memory segments system wide, is also
increased to reflect this change.  On success, the segment ID is
returned to the caller application.
</sect3>
 -->
<sect2>共有メモリサポート関数<label id="shm_primitives"><p>
<sect3>newseg()<label id="newseg"><p>
newseg() 関数は、新しい共有メモリセグメントを作る必要が出たときに呼ばれます。
これは、新しいセグメントのキー、フラグ、サイズの三つのパラメータを受け取ります。作成する共有メモリセグメントのサイズが SHMMIN と SHMMAX の間にあり、共有メモリセグメントの総数が SHMALL を越えないといった有効性を確認した後に、新しい共有メモリセグメント記述子を割り当てます。
<ref id="shmem_file_setup" name="shmem_file_setup()"> 関数は、tmpfs 型のアンリンクされたファイルを作成するために、その後に呼び出されます。返されるファイルポインタは、共有メモリセグメント記述子の対応する<tt>shm_file</tt>領域へ保存されます。ファイルサイズはセグメントサイズと同じに設定されます。新しい共有メモリセグメント記述子は初期化され、グローバル IPC 共有メモリ記述子配列へ挿入されます。共有メモリセグメント ID は (<ref id="ipc_buildid" name="ipc_buildid()">経由で) shm_buildid() により作成されます。このセグメントIDは、inode に対応する <tt>i_ino</tt> 領域と同様に共有メモリセグメント記述子の <tt>id</tt> 領域へ保存されます。
これに加えて、<tt>shm_file_operation</tt>構造体で定義される共有メモリ操作のアドレスは、対応するファイルへと保存されます。
システム全体での共有メモリセグメントの総数を示すグローバル変数 <tt>shm_tot</tt> の値も、この変更を反映して増分されます。
成功した場合、セグメント ID が呼出し元アプリケーションへ返されます。

<!--
<sect3>shm_get_stat()<label id="shm_get_stat"><p>
shm_get_stat() cycles through all of the shared memory
structures, and calculates the total number of memory pages in
use by shared memory and the total number of shared memory pages
that are swapped out. There is a file structure and an inode
structure for each shared memory segment.  Since the required
data is obtained via the inode, the spinlock for each inode
structure that is accessed is locked and unlocked in sequence.
</sect3>
 -->
<sect3>shm_get_stat()<label id="shm_get_stat"><p>
shm_get_stat() は、全ての共有メモリ構造体を順に辿っていき、共有メモリに使われているメモリの全ページ数と、スワップアウトされている全メモリページ数を計算します。各共有メモリセグメントにはファイル構造体とiノード構造体があります。求めるデータをiノード経由で取得するため、アクセスされる各iノード構造体のスピンロックのロックとロック解除が、それぞれに行われます。
</sect3>

<!--
<sect3>shmem_lock()<label id="shmem_lock"><p>
shmem_lock() receives as parameters a pointer to the
shared memory segment descriptor and a flag indicating
lock vs. unlock.The locking state of the shared memory
segment is stored in an	associated inode. This state is compared
with the desired locking state; shmem_lock() simply returns if they match.
 -->
<sect3>shmem_lock()<label id="shmem_lock"><p>
shmem_lock() はパラメータに共有メモリ記述子へのポインタとロックかアンロックを示すフラグを受け取ります。共有メモリセグメントのロック状態は対応するiノードへ格納されます。
この状態は、要求されたロック状態と比較されます。shmem_lock() は、一致した場合に単に返ります。

<!--
While holding the semaphore of the associated inode, the
locking state of the inode is set. The following list of items
occur for each page in the shared memory segment:
 -->
対応するiノードのセマフォを保持している間に、iノードのロック状態が設定されます。各共有メモリセグメントの各ページにおいて、以下のリストの項目が実行されます。
<itemize>
<!--
<item>  find_lock_page() is called to lock the page (setting
	PG_locked) and to increment the reference count of the page.
	Incrementing the reference count assures that the shared
	memory segment remains locked in memory throughout this
	operation.
 -->
<item> find_lock_page() は、ページをロック(PG_lockedを設定)し、ページの参照カウンタを1増加させます。参照カウンタの加算は共有メモリセグメントがこの操作中を通してメモリのロックされた状態にあることを保証するために実施されます。
<!--
<item>  If the desired state is locked, then PG_locked is cleared,
	but the reference count remains incremented.
 -->
<item> もし要求された状態がロック状態なら PG_locked はクリアされますが、参照カウンタは増加されたままにされます。
<!--
<item>  If the desired state is unlocked, then the reference count
	is decremented twice once for the current reference, and once
	for the existing reference which caused the page to remain
	locked in memory. Then PG_locked is cleared.
 -->
<item> もし要求された状態がアンロック状態なら、参照カウンタは2度減算されます。一つは現在の参照、もう一つはメモリの中でロックされたままのページになる原因の既存の参照のためです。それから PG_locked はクリアされます。
</itemize>
</sect3>

<!--
<sect3>shm_destroy()<label id="shm_destroy"><p>
During shm_destroy() the total number of shared memory pages
is adjusted to account for the removal of the shared memory segment.
<ref id="func_ipc_rmid" name="ipc_rmid()"> is called
(via shm_rmid()) to remove the Shared Memory ID. <ref id="shmem_lock" name="shmem_lock"> is
called to unlock the shared memory pages, effectively decrementing
the reference counts to zero for each page. fput() is called to
decrement the usage counter <tt>f_count</tt> for the associated file object,
and if necessary, to release the file object resources.  kfree() is
called to free the shared memory segment descriptor.
</sect3>
 -->
<sect3>shm_destroy()<label id="shm_destroy"><p>
shm_destroy() の間、共有メモリページ総数は、共有メモリセグメントの削除の責任をとって調整されます。
<ref id="func_ipc_rmid" name="ipc_rmid()"> は、(shm_rmid() 経由で)呼び出され、共有メモリID を削除します。
<ref id="shmem_lock" name="shmem_lock"> が呼び出され、共有メモリページをアンロックし、各ページの参照カウントを効率的に 0 に減算します。 fput() が呼び出され、対応するファイルオブジェクトの利用カウンタ<tt>f_count</tt>を1減算します。そして、必要であれば、ファイルオブジェクトの資源を解放します。kfree() が呼び出され、共有メモリセグメント記述子を解放します。
</sect3>

<!--
<sect3>shm_inc()<label id="shm_inc"><p>
shm_inc() sets the PID, sets the current time, and increments
the number of attachments for the given shared memory segment.
These operations are performed while holding the global shared
memory spinlock.
</sect3>
 -->
<sect3>shm_inc()<label id="shm_inc"><p>
shm_inc() は PID を設定し、現在の時間を設定し、そして与えられた共有メモリセグメントの付属数を1増加させます。これらの操作は、グローバル共有メモリスピンロックを保持して行われます。
</sect3>

<!--
<sect3>shm_close()<label id="shm_close"><p>
shm_close() updates the <tt>shm_lprid</tt> and the <tt>shm_dtim</tt> fields
and decrements the number of attached shared memory segments. If
there are no other attachments to the shared memory segment,
then <ref id="shm_destroy" name="shm_destroy()"> is called to
release the shared memory segment resources. These operations are
all performed while holding both the global shared memory semaphore
and the global	shared memory spinlock.
</sect3>
 -->
<sect3>shm_close()<label id="shm_close"><p>
shm_close() は、<tt>shm_lprid</tt> と <tt>shm_dtim</tt> メンバを更新し、割り当て共有メモリセグメント数を 1 減算します。共有メモリセグメントが他に割り当てられていなければ、<ref id="shm_destroy" name="shm_destroy()"> を呼び出し、共有メモリセグメントの資源を解放します。これらの操作は全てグローバル共有メモリセマフォとグローバル共有メモリスピンロックの両方を保持して行われます。
</sect3>

<!--
<sect3>shmem_file_setup()<label id="shmem_file_setup"><p>
The function shmem_file_setup() sets up an unlinked file living
in the tmpfs file system with the given name and size.  If there
are enough systen memory resource for this file, it creates a new
dentry under the mount root of tmpfs, and allocates a new file
descriptor and a new inode object of tmpfs type.  Then it associates
the new dentry object with the new inode object by calling
d_instantiate() and saves the address of the dentry object in the
file descriptor. The <tt>i_size</tt> field of the inode object is set to
be the file size and the <tt>i_nlink</tt> field is set to be 0 in order to
mark the inode unlinked.  Also, shmem_file_setup() stores the
address of the <tt>shmem_file_operations</tt> structure in the <tt>f_op</tt> field,

and initializes <tt>f_mode</tt> and <tt>f_vfsmnt</tt> fields of the file descriptor
properly.  The function shmem_truncate() is called to complete the
initialization of the inode object. On success, shmem_file_setup()
returns the new file descriptor.
</sect3>
 -->
<sect3>shmem_file_setup()<label id="shmem_file_setup"><p>
関数 shmem_file_setup() は、 tmpfs ファイルシステムに存在するアンリンクされたファイルを、与えられた名前とサイズに設定します。もしこのファイルに対して十分なシステムメモリリソースがあれば、新しい dエントリを tmpfs のマウントルートに作成します。そして新しいファイルディスクリプタと tmpfs 型の新しい iノードオブジェクトを割り当てます。そして、d_instantiate() を呼出し、新しい d エントリオブジェクトに新しい i ノードオブジェクトを対応づけます。dエントリオブジェクトのアドレスをファイルディスクリプタへ保存します。iノードオブジェクトの<tt>i_size</tt> メンバはファイルサイズに設定され、iノードがアンリンクされた印をつけるため <tt>i_nlink</tt> を 0 に設定します。そして、 shmem_file_setup() は、<tt>shmem_file_operations</tt> 構造体のアドレスも <tt>f_op</tt> メンバへ保存します。
そして、ファイルディスクリプタの <tt>f_mode</tt> と <tt>f_vfsmnt</tt> メンバが適切に初期化されます。関数 shmem_truncate() が呼び出され、iノード オブジェクトの初期化を完了させます。成功したなら、 shmem_file_setup() は新しいファイルディスクリプタを返します。
</sect3>
</sect2>
</sect1>

<!--
<sect1>Linux IPC Primitives<label id="ipc_primitives"><p>
 -->
<sect1>Linux IPC プリミティブ<label id="ipc_primitives"><p>
<!--
<sect2>Generic Linux IPC Primitives used with Semaphores, Messages,and Shared Memory
<label id="Generic_Linux_IPC_Primitives_used_with_Semaphores_Messages_and_Shared_Memory">
<p>
The semaphores, messages, and shared memory mechanisms of Linux
are built on a set of common primitives. These primitives are described in the sections below.
 -->
<sect2>セマフォ、メッセージおよび共有メモリで使用する汎用 Linux IPCプリミティブ
<label id="Generic_Linux_IPC_Primitives_used_with_Semaphores_Messages_and_Shared_Memory">
<p>
Linux のセマフォ、メッセージおよび共有メモリ機構は一連の共通プリミティブで構成されています。これらのプリミティブを以下で説明します。

<!--
<sect3>ipc_alloc()<label id="ipc_alloc"><p>
If the memory allocation is greater than PAGE_SIZE, then
vmalloc() is used to allocate memory. Otherwise, kmalloc() is
called with GFP_KERNEL to allocate the memory.
</sect3>
 -->
<sect3>ipc_alloc()<label id="ipc_alloc"><p>
メモリ割り当てが PAGE_SIZE より大きければ、vmalloc() がメモリ割り当てに使われます。そうでなければ、 kmalloc() が GFP_KERNEL 付きで呼び出されメモリを割り当てます。
</sect3>

<!--
<sect3>ipc_addid()<label id="ipc_addid"><p>
When a new semaphore set, message queue, or shared memory
segment is added,  ipc_addid() first calls <ref id="grow_ary" name="grow_ary()"> to
insure that the size of the corresponding descriptor array is
sufficiently large for the system maximum.  The array of descriptors
is searched for the first unused element. If an unused element
is found, the count of descriptors which are in use is incremented.
The <ref id="struct_kern_ipc_perm" name="kern_ipc_perm"> structure for the new resource descriptor
is then initialized, and the array index for the new descriptor
is returned. When ipc_addid() succeeds, it returns with the global
spinlock for the given IPC type locked.
</sect3>
 -->
<sect3>ipc_addid()<label id="ipc_addid"><p>
新しいセマフォセット、メッセージキュー、ないしはメモリセグメントが追加されると、 ipc_addid() は、
関連するディスクリプタの配列のサイズがシステムの最大値に対して十分に大きいことを保証するため、最初に <ref id="grow_ary" name="grow_ary()"> を呼び出します。そしてディスクリプタの配列の最初の未使用要素を検索します。もし未使用の要素が見つかったら、使用中のディスクリプタのカウンタを1増加します。
新しい資源のディスクリプタのために <ref id="struct_kern_ipc_perm" name="kern_ipc_perm"> 構造体を初期化し、新しいディスクリプタの配列のインデックスを返します。 ipc_addid() が成功したら、与えられたIPC のタイプのグローバルスピンロックを取得して戻ります。
</sect3>

<!--
<sect3>ipc_rmid()<label id="func_ipc_rmid"><p>
ipc_rmid() removes the IPC descriptor from the the global
descriptor array of the IPC type, updates the count of IDs which
are in use, and adjusts the maximum ID in the corresponding
descriptor array if necessary. A pointer to  the IPC
descriptor associated with given IPC ID is returned.
</sect3>
 -->
<sect3>ipc_rmid()<label id="func_ipc_rmid"><p>
ipc_rmid() は、IPCディスクリプタをIPCタイプのグローバルディスクリプタ配列から削除し、 使用されている ID のカウントを更新します。そして必要なら対応するディスクリプタ配列の最大 ID を調整します。
与えられた IPC ID に対応する IPC ディスクリプタへのポインタを返します。
</sect3>

<!--
<sect3>ipc_buildid()<label id="ipc_buildid"><p>
ipc_buildid() creates a unique ID to be associated with
each descriptor within a given IPC type. This ID is created at
the time a new IPC element is added (e.g. a new shared memory
segment or a new semaphore set).  The IPC ID converts
easily into the corresponding descriptor array index. Each
IPC type maintains a sequence number which is incremented
each time a descriptor is added.  An ID is created by
multiplying the sequence number with SEQ_MULTIPLIER and adding
the product to the descriptor array index. The sequence number
used in creating a particular IPC ID is then stored in the
corresponding descriptor. The existence of the sequence number
makes it possible to detect the use of a stale IPC ID.
</sect3>
 -->
<sect3>ipc_buildid()<label id="ipc_buildid"><p>
ipc_buildid() は与えられたIPCタイプの各ディスクリプタに対応するユニークなIDを作成します。この ID は新しいIPC要素が追加されるときに作成されます(例: 新しい共有メモリセグメントや新しいセマフォセット)。 IPC ID は対応するディスクリプタ配列のインデックスへ容易に変換できます。各IPCタイプは、ディスクリプタが追加される毎に増加させるシーケンス番号を管理しています。 ID はシーケンス番号をSEQ_MULTIPLIER 倍し、この積にディスクリプタ配列のインデックスを加算することで生成します。シーケンス番号が存在することにより、古い IPC ID の利用を検出することができます。
</sect3>

<!--
<sect3>ipc_checkid()<label id="ipc_checkid"><p>
ipc_checkid() divides the given IPC ID by the SEQ_MULTIPLIER
and compares the quotient with the seq value saved corresponding
descriptor.  If they are equal, then the IPC ID is considered to
be valid and 1 is returned.  Otherwise, 0 is returned.
</sect3>
 -->
<sect3>ipc_checkid()<label id="ipc_checkid"><p>
ipc_checkid() は、与えられた IPC IDを SEQ_MULTIPLIER で除算し、その商を対応するディスクリプタに保存されているシーケンス値と比較します。もし値が等しいなら、IPC ID は有効であると考えられ、1を返します。そうでなければ、0 を返します。
</sect3>

<!--
<sect3>grow_ary()<label id="grow_ary"><p>
grow_ary() handles the possibility that the maximum
(tunable) number of IDs for a given IPC type can be dynamically
changed. It enforces the current maximum limit so that it is no
greater than the permanent system limit (IPCMNI) and adjusts it down
if necessary. It also insures that the existing descriptor array
is large enough.  If the existing array size is sufficiently large,
then the current maximum limit is returned.  Otherwise, a new larger
array is allocated, the old array is copied into the new array,
and the old array is freed.  The corresponding global
spinlock is held when updating the descriptor array for the
given IPC type.
</sect3>
 -->
<sect3>grow_ary()<label id="grow_ary"><p>
grow_ary() は、与えられた IPC タイプの 最大の(設定可能な) ID 数を動的に変更できる機能を取り扱います。これは現在の最大限度が恒久的なシステムの限度(IPCMNI)を越えないように強制し、必要なら引き下げます。これはまた既存のディスクリプタ配列が十分に大きくなるよう保証します。
もし既存の配列サイズが十分に大きかったら、現在の最大限度を返します。そうでなければ、新しい大きな配列を割り当てます。そして古い配列を新しい配列へコピーし、古い配列を解放します。与えられた IPC タイプのディスクリプタ配列を更新するときは、対応するグローバルスピンロックを保持します。
</sect3> 

<!--
<sect3>ipc_findkey()<label id="ipc_findkey"><p>
ipc_findkey() searches through the descriptor array of
the specified <ref id="struct_ipc_ids" name="ipc_ids"> object,
and searches for the specified key. Once found, the index of
the corresponding descriptor is returned. If the key is not found,
then -1 is returned.
</sect3>
 -->
<sect3>ipc_findkey()<label id="ipc_findkey"><p>
ipc_findkey() は、特定の <ref id="struct_ipc_ids" name="ipc_ids"> オブジェクトのディスクリプタの配列を検索して特定のキーを探します。見つかったら、対応するディスクリプタのインデックスを返します。もしキーが見つからなかったら、-1 を返します。
</sect3>

<!--
<sect3>ipcperms()<label id="ipcperms"><p>
ipcperms() checks the user, group, and other permissions
for access to the IPC resources. It returns 0 if permission
is granted and -1 otherwise.
</sect3>
 -->
<sect3>ipcperms()<label id="ipcperms"><p>
ipcperms() は、IPC 資源にアクセスするユーザ、グループと他のパーミッションをチェックします。もしパーミッションが有効なら0を返し、そうでなければ-1を返します。
</sect3>

<!--
<sect3>ipc_lock()<label id="ipc_lock"><p>
ipc_lock() takes an IPC ID as one of its parameters.
It locks the global spinlock for the given IPC type, and
returns a pointer to the descriptor corresponding to the
specified IPC ID.
</sect3>
 -->
<sect3>ipc_lock()<label id="ipc_lock"><p>
ipc_lock() は、 IPC IDをパラメータの一つとして受け取ります。与えられた IPC タイプのグローバルスピンロックをロックし、特定のIPC IDに対応するディスクリプタへのポインタを返します。
</sect3>

<!--
<sect3>ipc_unlock()<label id="ipc_unlock"><p>
ipc_unlock() releases the global spinlock for the indicated IPC
type.
</sect3>
 -->
<sect3>ipc_unlock()<label id="ipc_unlock"><p>
ipc_unlock() は、示された IPC タイプのグローバルスピンロックを解除します。
</sect3>

<!--
<sect3>ipc_lockall()<label id="ipc_lockall"><p>
ipc_lockall() locks the global spinlock for the given
IPC mechanism (i.e. shared memory, semaphores, and messaging).
</sect3>
 -->
<sect3>ipc_lockall()<label id="ipc_lockall"><p>
ipc_lockall() は、与えられたIPC機構(つまり共有メモリとセマフォとメッセージング)用のグローバルスピンロックをロックします。
</sect3>

<!--
<sect3>ipc_unlockall()<label id="ipc_unlockall"><p>
ipc_unlockall() unlocks the global spinlock for the given
IPC mechanism (i.e. shared memory, semaphores, and messaging).
</sect3>
 -->
<sect3>ipc_unlockall()<label id="ipc_unlockall"><p>
ipc_unlockall() は、与えられたIPC機構(つまり共有メモリとセマフォとメッセージング)用のグローバルスピンロックを解除します。
</sect3>

<!--
<sect3>ipc_get()<label id="ipc_get"><p>
ipc_get() takes a pointer to a particular IPC type
(i.e. shared memory, semaphores, or message queues) and a
descriptor ID, and returns a pointer to the corresponding
IPC descriptor.  Note that although the descriptors for each
IPC type are of different data types, the common
<ref id="struct_kern_ipc_perm" name="kern_ipc_perm">
structure type is embedded as the first entity in every case.
The ipc_get() function returns this common data type. The expected
model is that ipc_get() is called through a wrapper function
(e.g. shm_get()) which casts the data type to the correct
descriptor data type.
</sect3>
 -->
<sect3>ipc_get()<label id="ipc_get"><p>
ipc_get() は、特定の IPC タイプ(つまり共有メモリとセマフォとメッセージング)へのポインタとディスクリプタIDを取り、対応する IPC ディスクリプタへのポインタを返します。ここで、各 IPC タイプのディスクリプタが違うデータタイプであっても、それぞれの場合で、共通の<ref id="struct_kern_ipc_perm" name="kern_ipc_perm"> 構造体タイプが最初のエンティティとして埋め込まれます。 ipc_get() 関数は、この共有のデータタイプを返します。データ型を正しいディスクリプタのデータ型へキャストするラッパー関数(たとえば shm_get())を通して、ipc_get() が呼び出されることを期待するモデルになっています。
</sect3>

<!--
<sect3>ipc_parse_version()<label id="ipc_parse_version"><p>
ipc_parse_version() removes the IPC_64 flag from the command
if it is present and returns either IPC_64 or IPC_OLD.
</sect3>
 -->
<sect3>ipc_parse_version()<label id="ipc_parse_version"><p>
ipc_parse_version() は、 もしあればIPC_64 フラグをコマンドから削除します。そして、 IPC_64か IPC_OLDを返します。
</sect3>
</sect2>

<!--
<sect2>Generic IPC Structures used with Semaphores,
Messages, and Shared Memory<label id="ipc_structures"><p>
The semaphores, messages, and shared memory mechanisms all make
use of the following common structures:
 -->
<sect2>セマフォ、メッセージおよび共有メモリで使われる汎用 IPC 構造体<label id="ipc_structures"><p>
セマフォ、メッセージおよび共有メモリ機構は全て以下の共有の構造体を使うようになっています。

<!--
<sect3>struct kern_ipc_perm<label id="struct_kern_ipc_perm"><p>
Each of the IPC descriptors has a data object of this type
as the first element. This makes it possible to access any
descriptor from any of the generic IPC functions using a pointer
of this data type.
 -->
<sect3>struct kern_ipc_perm<label id="struct_kern_ipc_perm"><p>
各 IPC ディスクリプタは、最初の要素にこの型のデータオブジェクトを持っています。これは、全ての汎用 IPC 関数からこのデータ型のポインタを用いて、全てのディスクリプタへアクセスできるようにするためです。

<tscreen><code>
/* used by in-kernel data structures */
struct kern_ipc_perm {
    key_t key;
    uid_t uid;
    gid_t gid;
    uid_t cuid;
    gid_t cgid;
    mode_t mode;
    unsigned long seq;
};
</code></tscreen>
</sect3>

<!--
<sect3>struct ipc_ids<label id="struct_ipc_ids"><p>
The ipc_ids structure describes the common data for semaphores,
message queues, and shared memory. There are three global instances of
this data structure- - <tt>semid_ds</tt>,
<tt>msgid_ds</tt> and <tt>shmid_ds</tt>- - for
semaphores, messages and shared memory respectively. In each
instance, the <tt>sem</tt> semaphore is used to
protect access to the structure.
The <tt>entries</tt> field points to an IPC
descriptor array, and the
<tt>ary</tt> spinlock protects access to this array.  The
<tt>seq</tt> field is a global sequence number which will
be incremented when a new IPC resource is created.
-->
<sect3>struct ipc_ids<label id="struct_ipc_ids"><p>
ipc_ids 構造体は、セマフォとメッセージキューと共有メモリの共通データを表しています。このデータ構造体には三つのグローバルインスタンスがあります。それぞれセマフォ、メッセージ、共有メモリ用に、<tt>semid_ds</tt>、<tt>msgid_ds</tt>と<tt>shmid_ds</tt>です。
各インスタンスでは、<tt>sem </tt>セマフォが使われ、構造体へのアクセスを保護しています。
<tt>entries</tt> メンバは、IPC ディスクリプタ配列を指しており、<tt>ary</tt> スピンロックがこの配列へのアクセスを保護しています。<tt>seq</tt> メンバは、新しい IPC 資源を作ったときに1増加されるグローバルシーケンス番号になっています。

<tscreen><code>
struct ipc_ids {
    int size;
    int in_use;
    int max_id;
    unsigned short seq;
    unsigned short seq_max;
    struct semaphore sem;
    spinlock_t ary;
    struct ipc_id* entries;
};
</code></tscreen>
</sect3>

<!--
<sect3>struct ipc_id<label id="struct_ipc_id"><p>
An array of struct ipc_id exists in each instance of
the <ref id="struct_ipc_ids" name="ipc_ids"> structure.
The array is dynamically allocated and may be replaced with
larger array by <ref id="grow_ary" name="grow_ary()">
as required. The array is
sometimes referred to as the descriptor array, since the
<ref id="struct_kern_ipc_perm" name="kern_ipc_perm"> data
type is used as the common descriptor data type by the IPC generic
functions.
 -->
<sect3>struct ipc_id<label id="struct_ipc_id"><p>
構造体 ipc_id の配列は、<ref id="struct_ipc_ids" name="ipc_ids"> 構造体の各インスタンスに存在します。この配列は動的に割り当てられ、必要に応じて<ref id="grow_ary" name="grow_ary()">によってより大きな配列に置き換えられることになります。<ref id="struct_kern_ipc_perm" name="kern_ipc_perm"> データタイプが IPC 汎用関数によって共通ディスクリプタデータタイプとして使われるため、この配列は時々ディスクリプタ配列として参照されます。

<tscreen><code>
struct ipc_id {
    struct kern_ipc_perm* p;
};
</code></tscreen>
</sect3>
</sect2>
</sect1>
</sect>
</article>
