実験の結果、特定の device fd から読み込んだリクエストは必ず同じfdにリプライを書き込む必要があることが分かった。
例えば、これまでのサンプルコードで用いていたように Session::next_request と Session::reply で異なるfdを用いるとファイルシステム全体がブロックしてしまう:
let conn = MountOptions::default().mount("/path/to/mountpoint")?;
while let Some(req) = session.next_request(&conn)? {
let cloned_conn = conn.try_ioc_clone()?;
std::thread::spawn(move || {
...
session.reply(&cloned_conn, &req, data)?; // conn とは別の fd に書き込む
});
}
このような挙動になる原因として、FUSE_DEV_IOC_CLONE によって複製された fd はそれぞれ独自の processing queue を持ち、保留中のリクエストをfd毎に管理してることが考えられる。
上の例の場合、req を conn から読み出したあと、それに対するリプライを cloned_conn に書き込んでいる。この場合 conn 側の processing queue は更新されないので、req に対応するカーネル側の処理が続行しないことになる。
上の考察を検証するため、カーネル側の実装を精査する必要がある。
実験の結果、特定の device fd から読み込んだリクエストは必ず同じfdにリプライを書き込む必要があることが分かった。
例えば、これまでのサンプルコードで用いていたように
Session::next_requestとSession::replyで異なるfdを用いるとファイルシステム全体がブロックしてしまう:このような挙動になる原因として、
FUSE_DEV_IOC_CLONEによって複製された fd はそれぞれ独自の processing queue を持ち、保留中のリクエストをfd毎に管理してることが考えられる。上の例の場合、
reqをconnから読み出したあと、それに対するリプライをcloned_connに書き込んでいる。この場合conn側の processing queue は更新されないので、reqに対応するカーネル側の処理が続行しないことになる。上の考察を検証するため、カーネル側の実装を精査する必要がある。