JF Linux Kernel 3.x/2.6 Documentation: /usr/src/linux/Documentation/filesystems/files.txt

filesystems/files.txt

file ロックとファイル構造体の解説 [プレインテキスト版]


=========================================================
これは、
Linux-3.5/Documentation/filesystems/files.txt の和訳です。
翻訳団体: JF プロジェクト < http://linuxjf.sourceforge.jp/ >
更新日 : 2012/09/04
翻訳者 : Seiji Kaneko < skaneko at mbn dot or dot jp >
査読者 : Masanori Kobayashi <zap03216 at nifty dot ne dot jp >
=========================================================
#File management in the Linux kernel
#-----------------------------------
Linux カーネルでのファイル管理
------------------------------

#This document describes how locking for files (struct file)
#and file descriptor table (struct files) works.
この文書は、ファイル (file 構造体) のロックとファイルディスクリプタテーブ
ル (ファイル構造体) がどのように動作するかを記載したものです。

#Up until 2.6.12, the file descriptor table has been protected
#with a lock (files->file_lock) and reference count (files->count).
#->file_lock protected accesses to all the file related fields
#of the table. ->count was used for sharing the file descriptor
#table between tasks cloned with CLONE_FILES flag. Typically
#this would be the case for posix threads. As with the common
#refcounting model in the kernel, the last task doing
#a put_files_struct() frees the file descriptor (fd) table.
#The files (struct file) themselves are protected using
#reference count (->f_count).
2.6.12 まではファイルディスクリプタテーブルはロック (files->file_lock) と
リファレンスカウント (files->count) で保護され、テーブルのファイルに関す
るすべてのフィールドへのアクセスは ->file_lock で保護されていました。
また、->count が CLONE_FILES フラグつきで複製されたタスク間での、ファイル
ディスクリプタテーブルの共有に用いられていました。通常、posix スレッドが
この場合に当たります。カーネル内のリファレンスカウント共通モデルに沿って、
put_files_struct() を最後に行ったタスクが、ファイルディスクリプタ (fd)
テーブルを解放します。ファイル (struct file) 自体は、リファレンスカウント
(->f_count) を使って保護されています。

#In the new lock-free model of file descriptor management,
#the reference counting is similar, but the locking is
#based on RCU. The file descriptor table contains multiple
#elements - the fd sets (open_fds and close_on_exec, the
#array of file pointers, the sizes of the sets and the array
#etc.). In order for the updates to appear atomic to
#a lock-free reader, all the elements of the file descriptor
#table are in a separate structure - struct fdtable.
#files_struct contains a pointer to struct fdtable through
#which the actual fd table is accessed. Initially the
#fdtable is embedded in files_struct itself. On a subsequent
#expansion of fdtable, a new fdtable structure is allocated
#and files->fdtab points to the new structure. The fdtable
#structure is freed with RCU and lock-free readers either
#see the old fdtable or the new fdtable making the update
#appear atomic. Here are the locking rules for
#the fdtable structure -
新しいファイルディスクリプタ管理のロックフリーモデルでは、リファレンスカ
ウントによる管理は従来と同様ですが、ロック処理は RCU に基づくものになりま
す。ファイルディスクリプタテーブルには複数の要素 - fd 一式 (open_fd 群や
close_on_exec, file ポインタの配列, 組や配列の数やサイズなど) - が格納さ
れています。ロックを持たない読み出し側から更新がアトミックであるように見
せるために、ファイルディスクリプタテーブルの各要素はすべて独立した一つの
構造体 - fdtable 構造体 - 内にあります。files_struct には fdtable 構造体
へのポインタが格納され、そのポインタ経由で実際の fd テーブルへのアクセス
が行われます。もともとは fdtable は files_struct 自体に埋め込まれていま
した。それ以降の fdtable の拡張時に、新しい fdtable 構造体が導入され、
files->fdtab がこの新しい構造体を指すようになりました。fdtable 構造体は、
ロックを持たない読み出し処理から古い fdtable と新しい fdtable の両方がア
トミックに更新されているように見せることができるよう、RCU により解放され
ます。以下が fdtable 構造体へのロック取得規則です。

#1. All references to the fdtable must be done through
#   the files_fdtable() macro :
1. fdtable への参照は、必ず files_fdtable() マクロ経由で行なわなければ
  いけません。

	struct fdtable *fdt;

	rcu_read_lock();

	fdt = files_fdtable(files);
	....
	if (n <= fdt->max_fds)
		....
	...
	rcu_read_unlock();

#   files_fdtable() uses rcu_dereference() macro which takes care of
#   the memory barrier requirements for lock-free dereference.
#   The fdtable pointer must be read within the read-side
#   critical section.
   files_fdtable() は rcu_dereference() マクロを使います。
   rcu_dereference() マクロが、ロックなしの参照を行なうのに必要なメモリ
   バリア要求の面倒を見ます。fdtable ポインタは読み出し側のクリティカル
   セクション中で読み出さなければいけません。

#2. Reading of the fdtable as described above must be protected
#   by rcu_read_lock()/rcu_read_unlock().
2. 上記の fdtable の読み出しは、rcu_read_lock()/rcu_read_unlock() で
  保護しなければいけません。

#3. For any update to the fd table, files->file_lock must
#   be held.
3. fd テーブルを更新する場合には、どのような更新でも files->file_lock
  を持っていなければいけません。

#4. To look up the file structure given an fd, a reader
#   must use either fcheck() or fcheck_files() APIs. These
#   take care of barrier requirements due to lock-free lookup.
#   An example :
4. ある fd に対してファイル構造体を参照するには、読み側では fcheck() ま
  たは fcheck_files() API を使わなければいけません。これらの API はロ
  ック不要の参照に伴うバリアの要求の面倒を見てくれます。
  以下に例を示します。

	struct file *file;

	rcu_read_lock();
	file = fcheck(fd);
	if (file) {
		...
	}
	....
	rcu_read_unlock();

#5. Handling of the file structures is special. Since the look-up
#   of the fd (fget()/fget_light()) are lock-free, it is possible
#   that look-up may race with the last put() operation on the
#   file structure. This is avoided using atomic_long_inc_not_zero()
#   on ->f_count :
5. ファイル構造体の操作には特別の注意が必要です。fd の検索
  (fget()/fget_light()) はロックをとりませんから、検索時にファイル構
  造体への最後の put() 操作と競合を起こす可能性があります。これは
  ->f_count に対して atomic_long_inc_not_zero() を用いることによっ
  て回避します。

	rcu_read_lock();
	file = fcheck_files(files, fd);
	if (file) {
		if (atomic_long_inc_not_zero(&file->f_count))
			*fput_needed = 1;
		else
		/* Didn't get the reference, someone's freed */
			file = NULL;
	}
	rcu_read_unlock();
	....
	return file;

#   atomic_long_inc_not_zero() detects if refcounts is already zero or
#   goes to zero during increment. If it does, we fail
#   fget()/fget_light().
   atomic_long_inc_not_zero() は refcount が既に 0 となっていること、ま
   たは増加時に 0 となることを検出します。このような場合、
   fget()/fget_light() は失敗します。

#6. Since both fdtable and file structures can be looked up
#   lock-free, they must be installed using rcu_assign_pointer()
#   API. If they are looked up lock-free, rcu_dereference()
#   must be used. However it is advisable to use files_fdtable()
#   and fcheck()/fcheck_files() which take care of these issues.
6. fdtable と file 構造体のいずれもがロックをとらないで参照可能ですから、
  これらについては rcu_assign_pointer() API を用いてインストールする必
  要があります。ロックをとらないで参照する場合、rcu_dereference() を使
  う必要があります。ただし、files_fdtable() と fcheck()/fcheck_files()
  はこれらの面倒を見てくれますので、これを使うのがおすすめです。

#7. While updating, the fdtable pointer must be looked up while
#   holding files->file_lock. If ->file_lock is dropped, then
#   another thread expand the files thereby creating a new
#   fdtable and making the earlier fdtable pointer stale.
#   For example :
7. 更新時には、fdtable ポインタは files->file_lock を持った状態で参照
  する必要があります。->file_lock を持っていない場合、他のスレッドがそ
  のファイルを拡張して新しい fdtable を作成し、以前の fdtable ポインタ
  を無効状態にしてしまう可能性があります。
  例を以下に示します。

	spin_lock(&files->file_lock);
	fd = locate_fd(files, file, start);
	if (fd >= 0) {
		/* locate_fd() may have expanded fdtable, load the ptr */
		fdt = files_fdtable(files);
		__set_open_fd(fd, fdt);
		__clear_close_on_exec(fd, fdt);
		spin_unlock(&files->file_lock);
	.....

#   Since locate_fd() can drop ->file_lock (and reacquire ->file_lock),
#   the fdtable pointer (fdt) must be loaded after locate_fd().
   locate_fd() が ->file_lock を解放して (その後 ->file_lock を再取
   得する) 可能性があるため、fdtable ポインタ (fdt) は locate_fd()
   実行後にロードする必要があります。

Linux カーネル 3.x/2.6 付属文書一覧へ戻る