Overview of the Linux Virtual File System
異なるファイルシステム実装に依存させるために抽象化をカーネル内に提供する
Directory Entry Chache
open(2), stat(2), chmod(2)などのシステムコールを実装している
これらのシステムコールに渡されるパス名引数はVFSによってDirectory Entry Chacheを検索するために使用される これによりパス名を特定のdentryに変換する非常に高速な検索メカニズムが提供される
Inode Object
個々のdentryは通常inodeへのポインタを持っている.Inodeは通常ファイル, direcory, FIFOなどのファイルシステムオブジェクトである
inodeはディスク上, メモリ上に存在しており, 1つのinodeは複数のdentryによって指し示すことができる
inodeを探索するには, 親ディレクトリのinodeのlookup()を呼び出す必要がある.
File Object
File strcutreの割り当てが必要
dentryへのポインタとファイル操作のメンバ関数のセットで初期化される
FIleのread, write, closeはユーザースペースのfile descriptorを使用して適切なファイル構造を取得し, 必要なファイル構造メソッドを呼び出して必要な処理を行うことで実行される
RegisteringとMounting
登録と登録解除には以下のAPI関数を使用する
code: register.c
extern int register_filesystem(struct file_system_type *);
extern int unregister_filesystem(struct file_system_type *);
(これ多分cよね??書き方的にYudai.icon)
渡されたstruct file_system_typeはファイルシステムを記述する
ファイルシステムをネームスペース内のディレクトリにマウントするリクエストが行われると, VFSは特定のファイルシステムに対して適切なmount() メソッドを呼び出す.
karnelに登録されているファイルシステムは/proc/filesystemファイルで確認できる.
struct File_system_type
name:
ファイルシステムの名前を表す
ext2, iso9660
fs_flags
ファイルシステムに関するフラグ。マウントやファイルシステムの動作を制御する。
FS_REQUIRES_DEV: useが必要
FS_NO_DCHCHE: ディレクトリキャッシュを使用しない
init_fs_context
fx_contextを初期化するコールバック関数
parameters:
ファイルシステムのマウント時に使用される記述する構造体へのポインタ
mount
ファイルシステムを新しくマウントする際に呼び出されるメソッド
引数:
struct file_system_type *fs_type:マウント対象のファイルシステム
int flags: マウントフラグ(ex:読み取り専用マウント)
const char *dev_name: マウント対象のデバイス名
void *data: マウントオプション
kill_sb
ファイルシステムインスタンスを修了する際に呼び出されるメソッド。マウント解除時のリソース解放など
owner
内部のVFSで使用される
next
内部的なVFSリンクリストで使用される
fs_supers
このファイルのスーパーブロック(ファイルシステムインスタンス)を管理するためのハッシュリスト
Lockdep-specific keys
ロックでバックツールで使用されるロックキー
主な鍵:
s_lock_key, s_umount_key: スーパーブロックのロック。
i_lock_key, i_mutex_key: inode レベルのロック。
invalidate_lock_key, i_mutex_dir_key: ディレクトリ操作用ロック。
struct super_operations
VFSを通じて, superblockおよび関連リソースの操作を定義
使用される場面:
inodの割り当て、解放
ファイルシステムの同期
マウントやアンマウント
ファイルシステムの統計取得
inode関連メソッド
alloc_inode(struct super_block *sb)
inodeオブジェクトのメモリ割り当て、初期化
destroy_inode(struct inode *inode)
alloc_inodeで割り当てたリソースを解放
free_inode(struct inode *inode)
RCUコールバックとしてinodeを解放
inodeのステータスやデータ更新
dirty_inode(struct inode *inode, int flats)
inodeがdirtyとマークされたときに呼ばれる
write_inode(struct inode *inode, struct writeback_control *wbc)
inodeをディスクに書き込む
永続化が必要とされたときに呼ばれる
drop_inode((struct inode *inode)
inodeの最終参照が削除されたときに呼ばれる
superblock関連のメソッド
put_super(struct super_block *sb)
ファイルシステムのアンマウント時にsuperblockを解放する
sync_fs(struct super_block *sb, int wait)
superblockに関連する全てのデータをディスクに同期
ファイルシステム全体を永続化する際に呼ばれる
freeze_super(struct super_block *sb, enum freeze_holder who)
ファイルシステムを一貫した状態でロックする
thaw_super(struct super_block *sb, enum freeze_holder who)
ロック状態のファイルシステムを解除
code:super_operations.c
struct super_operations myfs_super_ops = {
.alloc_inode = myfs_alloc_inode,
.destoy_inode = myfs_destroy_inode,
.put_super = myfs_put_super,
.statfs = myfs_statfs,
.sync_fs = myfs_sync_fs
struct xattr_handler
拡張属性を扱うためのハンドラを定義する. 拡張属性は「名前: 値」のペアで構成され、ファイルやディレクトリに追加のメタデータを提供する仕組み
メンバー:
name:
特定の名前に一致する属性を処理する場合に使用する
prefix
特定のプレオフィックスに一致する属性を処理する
nameと同時に使用しない
list
対象のdentryに対して, リスト化可能かどうかを判断する
get
特定の拡張属性の値を取得するために呼ばれる
set
特定の拡張属性の値を設定するために呼ばれる
code:handler.c
static struct xattr_handler myfs_xattr_handler = {
.prefix = "user",
.list = myfs_listxattr,
.get = myfs_getxattr,
.set = myfs_setxattr,
};
struct inode_operations
inodeに対する操作を定義する
メンバー:
ファイル操作
create
新しい通常ファイルを作成する
unlink
ファイルを削除する
symlink
シンボリックリンクを作成する
mknod
特殊ファイルを作成する
ディレクトリ操作
lookup
ディレクトリ内で名前からinodeを検索する
名前はdentryで指定する
mkdir
新しいサブディレクトリを作成する
rename
ファイルやディレクトリの名前を変更する
属性操作
setattr
ファイルの属性を設定する
getattr
ファイルの属性を取得する
listxattr
inodeの拡張属性を列挙する
ACL
get_acl/set_acl
inodeに関連付けられたACLを所得または設定する
code:inode_operations.c
struct inode_operations myfs_inode_ops = {
.create = myfs_create,
.lookup = myfs_lookup,
.unlink = myfs_unlink,
.mkdir = myfs_mkdir,
.rmdir = myfs_rmdir,
.rename = myfs_rename,
.setattr = myfs_setattr,
.getattr = myfs_getattr,
};
アドレス空間オブジェクト
ページキャッシュ内のページをグループ化し管理するデータ構造
ページキャッシュの追跡
プロセスのアドレス空間との連携
ストレージとのやり取り
struct address_space_operations
アドレス空間操作を定義する構造体
ページの読み書き
writepage
ダーティーページをストレージに書き戻す
動作:
PG_Dirtyフラグをクリア
書き戻し中はPG_Writebackフラグを設定
書き戻し完了後にページをアンロック
read_folio
バッキングストア(ディスクなど)からページを読み込み、フォリオ(複数ページ単位)をキャッシュに格納
writepages
アドレス空間に関連づけられた複数ページをまとめて書き戻す
mpage_writepagesがデフォルト実装として提供される
フォリオの管理
dirty_folio
フォリオをダーティ状態にマークする
動作:
フォリオのダーティフラグ(PAGECACHE_TAG_DIRTY)を設定
readahead
複数ページを一括で非同期に読み込む
書き込みの準備と完了
write_bigin
書き込みの準備を行う
write_end
書き込みの完了処理を行う
フォリオの解放と無効化
release_folio
フォリオの開放時にプライベートデータを削除
free_folio
フォリオがページキャッシュから完全に削除された際のクリーンアップ
invalidate_folio
フォリオが無効化される際にプライベートデータを更新または削除
Direct I/O
direct_io
ページキャッシュを介さず、ストレージからプロセスのアドレス空間へ直接データを転送
フォーリオのマイグレージョンとクリーニング
migrate_folio
フォリオを物理メモリ上で別の場所に移動
launder_folio
フォリオが解放される前にデーティ状態を解消
File object
開かれたファイルを表すデータ構造
プロセスがファイルやデバイスとやり取りを行う際の橋渡しとして機能する。オープンファイルに対応するstruct fileオブジェクトが作成され、ファイルの操作や状態を管理する
struct file_operations
ファイルのオープン、読み書き、クローズなどの操作を定義する
ファイルの位置とアクセス
IIseek
ファイル位置を変更する
オフセットの調整方法にしたあいファイル位置インデックスを更新
特定のファイルやデバイスでアライメントを考慮する場合にカスタマイズ可能
読み書き操作
read
ユーザー空間にデータを読み込む
write
ユーザー空間からデータを書き込む
read_iter
非同期またはベクタ化された読み込み操作
write_iter
非同期またはベクタ化された書き込み操作
ディレクトリ操作
iterate_shared
ディレクトリの内容を読み取る
ディレクトリエントリを呼び出しプロセスに渡す
ポーリングと通知
poll
ファイルの序つ愛を確認する
ファイルの制御をチェック
制御操作
unlocked_ioctl
デバイス固有やファイル固有のコマンドを処理する
ユーザー空間の操作を直接カーネル空間に渡すインターフェース
compat_iotl
32ビットシステムコールが64ビットカーネルで使用する場合に対応する処理
メモリマッピング
mmap
ファイルをメモリ空間にマッピングする
ユーザー空間からファイルの内容を直接操作可能に
オープンとクローズ
open
フィルがオープンされた時に呼び出される
flush
closeシステムコールで呼び出されファイルをフラッシュ
見書き込みデータをストレージに反映
release
最後のファイル参照がクローズされた際に呼び出される
同期とロック
fsync
ファイルデータを同期する
ページキャッシュからストレージデータを確実に書き戻す
lock
ファイルのロック操作
ファイル領域の操作
fallocate
ストレージブロックを事前割り当て、または領域を削除する
copy_file_range
ファイル間でデータをコピー
remap_file_range
ファイル間でデータ領域を再マッピング
code:file_operations.c
struct file_operations myfs_file_ops = {
.llseak = default_llseek,
.read = myfs_read,
.write = myfs_write,
.open = myfs_open,
.release = myfs_release,
.mmp = myfs_mmp,
.fsync = myfs_fsync,
};
あー、linuxではカーネル空間とユーザー空間で分けることで、ユーザーを複数作成できるようになっている。1つのOSを1人だけとは限らないに近い?
デフォルトでこの形にする理由ってなんだろね。