Linux FUSE: “failed to close” file

0

Piszę serwer FUSE w Linuksie nie korzystający z biblioteki libfuse. I natrafiłem na następujący problem.
W katalogu zamontowanego systemu plików wydaję polecenie

touch a

i otrzymuję komunikat

touch: failed to close 'a': No such file or directory

To samo dzieje się dla poleceń np. cp czy install. A jeśli w edytorze tekstowym mam otwarty plik z tego katalogu i próbuję zapisać, to wypisuje komunikat “I/O Error”.
Natomiast pliki są tworzone i zapisywane, co można sprawdzić zarówno poleceniem ls jak i w logach programu serwera FUSE.

Szukałem błędu w obsłudze opcode FUSE_WRITE oraz FUSE_RELEASE, ale wszystko wydaje się poprawne.
Sprawdzałem też w kodzie źródłowym libfuse, jakie struktury zwraca FUSE_WRITE oraz FUSE_RELEASE, i u mnie są te same. Może powstało coś nowego w ostatnich kernelach Linuksa...

Link do pliku serwera FUSE: https://github.com/overcq/oux/blob/master/program/filesystem/mount/0.cx#L2604

0

O tym, co to jest FUSE, przeczytałem dopiero wczoraj na Wikipedii, więc nie wypowiem się.

Spróbujmy inaczej. W man touch napisane jest, że touch albo zmienia "czasy pliku", albo tworzy plik. Jak to się odnosi do zwrotu close a z tego komunikatu błędu?

0
Silv napisał(a):

Spróbujmy inaczej. W man touch napisane jest, że touch albo zmienia "czasy pliku", albo tworzy plik. Jak to się odnosi do zwrotu close a z tego komunikatu błędu?

Pewnie tak że otwarcie lub utworzenie pliku i zapis do niego udają się, a błąd występuje dopiero w momencie zamykania pliku - mimo to zawartość pliku pozostaje prawidłowa.

0

@Azarien: OK, ma to sens patrząc na cały proces, bez wyróżniania poszczególnych bibliotek / programów. Ale apparently działanie touch kończy się przed rozpoczęciem jakiegokolwiek zapisu do pliku, więc jak ten program może otrzymywać komunikaty o zamknięciu pliku?

2

Na FUSE się nie znam za bardzo ale
a. czy coś ciekawego leci na dmesgu?
b. jesteś w stanie w Twoim kodzie postawić pułapkę na linijkach zwracających -ENOENT? Bo stawiam, że tam trafiasz.

EDIT: po dyskusji z @Silv mocno obstawiam, że to z flusha błąd leci ;)

@overcq jesteś w stanie dać "książkę kucharską" jak ten Twój projekt odpalić i wypreparować odpowiedni dysk dla niego i to zamontować?

Na moją intuicję błąd przychodzi Ci gdzieś z tych okolic https://elixir.bootlin.com/linux/latest/source/fs/fuse/file.c#L508
czyli u Ciebie chyba ta linijka: https://github.com/overcq/oux/blob/master/program/filesystem/mount/0.cx#L804
Ale dopóki się debuggerem w to nie wepniesz/nie złapiesz jakiegoś loga to możemy wróżyć z fusów co najwyżej.

1

@overcq: Znalazłem to pytanie na SO, dotyczące tworzenia systemu plików z użyciem FUSE, a bez libfuse. Autor co prawda pisze, że nie chce korzystać z C, tylko z języka Monte (https://github.com/monte-language/monte ?); ale ponieważ niewiele zrozumiałem z odpowiedzi do tego pytania, sam oceń, czy przyda Ci się.

1

Dziękuję wszystkim za odpowiedzi – problem rozwiązany. Błąd był w linii 803 czyli tam, gdzie wskazywał @alagner . Błędem było użycie funkcji konwersji numeru inode z przestrzeni kernela do przestrzeni tego systemu plików (E_main_Q_filesystem_P_inode), ponieważ jako argument nie był podany inode znajdujący się w strukturze struct E_main_Z_file_handle, lecz tylko numer kolejny w tablicy file handles (in_buf_2->fh) wskazujący na tę strukturę.
W tamtym miejscu (w obsłudze FUSE_FLUSH) w ogóle nie szukałem.

Dla formalności:

  • dmesg nic nie wypisywał, co jest teraz logiczne, skoro to mój kod zwracał wprost ten numer błędu.
  • Tak, ustawiłem raport linii w linii 804 i w linii 806 i rzeczywiście w logu się pojawiła ta pierwsza.
    (Niestety nie mogę uruchomić debugera na tym programie mount, ponieważ nie potrafi go obsłużyć i się blokuje.)

Jak zainstalować mount.oux-fuse? Nie tworzyłem dotychczas opisu, ponieważ są tylko dwie opcje: albo zainstalować w systemie (potrzebny root), albo uruchamiać z katalogów kompilacji. Nie ma obecnie opcji instalacji w katalogu użytkownika.

W skrócie: całe repozytorium https://github.com/overcq/oux buduje biblioteki będące w katalogu module, a programy są budowane lokalnie w podkatalogach katalogu program.

Jeśli wykona się make w katalogu oux, to zbuduje biblioteki. Natomiast jeśli wykona się make w podkatalogu konkretnego programu, to zbuduje najpierw biblioteki, a później ten program, czyli wszystko, co potrzebne zbuduje jednym poleceniem make. (Tylko za pierwszym razem chwilę potrwa, zanim zbuduje listę plików nagłówkowych dla wszystkich funkcji w systemie. No i potrzebna jest zainstalowana dokumentacja dla man w systemie.)
Tylko że do uruchomienia programu biblioteki (pliki *.so) muszą być tam, gdzie szuka ich dynamiczny linker, czyli na przykład zainstalowane w systemie. A do tego trzeba wykonać jako root make install w katalogu oux albo make install w podkatalogu konkretnego programu, by zainstalować w systemie również ten program. (Od razu ostrzegam, by nie wykonywać jako root make, albo make install bez wcześniejszego make jako user, ponieważ to jest niezdefiniowane.) Istnieje możliwość wkompilowania bibliotek w program: trzeba zakomentować H_make_C_to_libs w pliku oux/compile/1.mak, a następnie wykonać make w podkatalogu programu.

Do opisywanego w tym wątku programu potrzebne są dwa będące w podkatalogach katalogu oux/program/filesystem: mkfs (tworzy system plików) i mount (montuje system plików).
Do utworzenia dysku w pliku i jego zamontowania potrzeba wykonać następujące polecenia (po zastąpieniu tekstów właściwymi argumentami) jako root:

dd if=/dev/zero of='ścieżka do katalogu tymczasowego/fs' count='liczba sektorów 512 B'
losetup -Pf --show 'ścieżka do katalogu tymczasowego/fs'
# W konsoli wypisze utworzone urządzenie /dev/loop, np. /dev/loop0.
fdisk /dev/loop0 # W tym programie trzeba utworzyć nową partycję z domyślnymi parametrami.
# Po zapisaniu partycji (zakończeniu programu) pojawi się nowe urządzenie: /dev/loop0p1.
mkfs.oux /dev/loop0p1
mount -t oux /dev/loop0p1 'ścieżka do mountpoint'

Jeśli programy mkfs i mount nie były we wcześniejszym kroku instalowane (make install), to można je wywołać z katalogów kompilacji jako:

oux/program/filesystem/mkfs/a.out /dev/loop0p1
oux/program/filesystem/mount/a.out /dev/loop0p1 'ścieżka do mountpoint'

Teraz można wykonywać w innym terminalu operacje w 'ścieżka do mountpoint', podczas gdy w bieżącym terminalu program mount wypisuje, co robi.
By zakończyć należy w drugim terminalu opuścić katalog 'ścieżka do mountpoint' i wykonać jako root:

umount 'ścieżka do mountpoint'
losetup -d /dev/loop0

W pierwszym terminalu program mount zakończy działanie.

To jest eksperymentalny system plików, w którym zawartości plików są przechowywane bez dzielenia na fragmenty, a tablica plików znajduje się na końcu partycji.

1 użytkowników online, w tym zalogowanych: 0, gości: 1