Open2

FUSE周りの情報整理

Yusuke SasakiYusuke Sasaki

polyfuseの開発にあたってかき集めた情報をちまちままとめておきたい

情報源

Yusuke SasakiYusuke Sasaki

多重化・マルチスレッド化に関する覚え書き

リクエストを多重化して処理したい場合、FUSEカーネルドライバとの接続であるファイルディスクリプタを共有したり複製したりして持ち回す必要がある。大雑把に考えられる選択肢は以下の通り:

1. 同じ fd を共有する場合

dup(2) によるファイルディスクリプタの複製は実行せず、ひとつのFDを使いまわす

fuser ではこの方針を採用している: https://github.com/cberner/fuser/blob/v0.15.1/src/channel.rs#L53 ほかの FUSE も多分同じ方針を採用してると思われる

イメージ

let fd = Arc::new(unsafe { OwnedFd::from_raw_fd(fd) });

let req = read_request(&fd)?;

///
let fd2 = fd.clone();
std::thread::spawn(move || {
    req.reply_to(&fd2, ...);
});

利点

  • 考えるべきことが少なくなり、実装がシンプルになる

欠点

  • 大量のデータを扱う場合(例えばページキャッシュまるごと read(2) で呼び出したり、数GBもするデータを writev(2) で書き出すなど)、排他制御のせいで他スレッドがブロックされる
    • splice(2) による回避策などを取るべき

2. dup(2) による複製

やってることは実質的に 1. と同じになる(はず)。ここでは説明を省略

3. FUSE_DEV_IOC_CLONE

/dev/fuse をオープンした後、ioctl(newfd, FUSE_DEV_IOC_CLONE, &origfd) によってコンテキストを共有する方式。

dup(2) の場合とは異なり、複製後の newfd は元の origfd とは別の fd として扱われる

利点

  • 排他制御によりブロッキングされない

欠点

  • リプライを書き込む fd をデーモン側で気にする必要がある
    • read(2)/readv(2) などでリクエストを読み込むと、FUSEデバイスは対応するリクエストを 自身の processing queue へと移動させ、応答を待機する
    • ここで他の fd にリプライをしてしまうと、上で移動した processing queue に対する処理が元 fd 側で実行されなくなる