Witam

Utworzyłem serwer wirtualnego systemu plików FUSE w Linuksie. Nie używam biblioteki libfuse, lecz w programie obsługuję przysyłane żądania klienta (kernela) do systemu plików, czyli zastępuję to, co robi libfuse, dla mojego systemu plików i komunikuję się bezpośrednio z kernelem. Nie ma prawie żadnej dokumentacji, tylko jakaś szczątkowa, więc często zaglądałem też do źródeł libfuse, która nie jest łatwa do zrozumienia ze względu na obecne w tej bibliotece warstwy abstrakcji.

Jednak teraz napotkałem na problem, którego przyczyny nie potrafię zlokalizować. Mianowicie w żądaniu FUSE_MKDIR (utwórz katalog) cały kod w moim serwerze systemu plików się wykonuje, następnie przechodzi do oczekiwania na kolejne żądanie (w funkcji read), ale klient tego żądania się blokuje w sposób niemożliwy do przerwania bez restartu systemu operacyjnego.

Przykładowo:

  1. Montuję mój system plików FUSE na jakimś katalogu, więc w terminalu uruchamia się serwer systemu plików i wypisuje komunikaty, co robi.
  2. Wydaję z drugiego terminala polecenie mkdir a z podaną odpowienią ścieżką do tego katalogu, w którym zamontowałem serwer, np mkdir /mnt/oth/a.
  3. Serwer wypisuje, że obsłużył żądanie FUSE_MKDIR i czeka na kolejne.
  4. Terminal, w którym wydałem polecenie mkdir blokuje się na tym poleceniu.
  5. umount -f z podaną ścieżką do katalogu zakańcza program serwera w sposób normalny (tak jak dla polecenia umount).

Debugowanie metodą logowania wykonywania się linii programu mojego serwera systemu plików FUSE wykazało, że mkdir blokuje się tylko wtedy, gdy odsyłam do klienta odpowiedź, jak w liniach następujących od: https://github.com/overcq/oux/blob/bb43e07448df89ded21adbd3b9d9a708ac3340bf/program/filesystem/mount/0.cx#L1934 . Natomiast, jeśli zamiast odsyłania tej odpowiedzi do klienta odeślę komunikat błędu (tylko strukturę out_buf), to katalog zostanie utworzony poprawnie, mkdir zwróci komunikat błędu, ale się nie zablokuje.

Testowałem również, czy nie wysyłam zbyt mało danych i klient nie blokuje się na oczekiwaniu na dane, ale jeśli zwracam za dużo danych, to writev wraca z błędem wskazującym, że nieprawidłowy argument.

Czekam na każdą pomoc, jednak jeśli zamierzasz pobrać https://github.com/overcq/oux , skompilować i uruchomić polecenia mkfs i mount tego serwera plików FUSE, to nie rób tego na maszynie, której nie będziesz mógł zrestartować.

Do uruchomienia tego serwera plików FUSE potrzeba:

  1. Pobrać środowisko z https://github.com/overcq/oux .
  2. Przejść do katalogu program/filesystem/mkfs i wykonać polecenie make. (Pierwsza kompilacja musi zbudować bazę danych plików nagłówkowych z dokumentacji dostępnej w systemie, więc potrwa kilka minut.)
  3. Przejść do katalogu program/filesystem/mount i wykonać polecenie make.
  4. Przejść do katalogu program/filesystem i utworzyć plik dysku poleceniem dd if=/dev/zero of=dysk bs=4096 count=500.
  5. Utworzyć urządzenie blokowe z tego pliku dysku poleceniem losetup -f disk i sprawdzić wynik poleceniem losetup.
  6. Wykonać polecenie mkfs/a.out /dev/loop z odczytanym wyżej numerem loop, by utworzyć system plików na tym dysku.
  7. Wykonać polecenie mkdir mnt, by utworzyć punkt montowania, a następnie mount/a.out /dev/loop mnt z odczytanym wyżej numerem loop, by zamontować system plików.
  8. W drugim terminalu przejść do katalogu program/filesystem/mnt i można wylistować zawartość dysku poleceniem ls -al.
  9. Wydać polecenie mkdir a, by spróbować utworzyć katalog w systemie plików.
    Wtedy ten drugi terminal się zablokuje, jak również zablokowane do restartu systemu będzie użyte urządzenie /dev/loop z określonym numerem oraz katalog mnt.
  10. W trzecim terminalu przejść do katalogu program/filesystem i wydać polecenie umount -f mnt, które powinno zakończyć program serwera plików FUSE w pierwszym terminalu.

Po aktualizacji kernela Linuksa z wersji 5.11.2 na 5.11.9 problem zniknął.