W jaki sposób Linux rozróżnia rzeczywiste i nieistniejące pliki (np. Urządzenia)?

28

To pytanie na niskim poziomie i rozumiem, że może nie być to najlepsze miejsce do zadawania pytań. Ale to wydawało się bardziej odpowiednie niż jakakolwiek inna strona SE, więc proszę.

Wiem, że w systemie plików Linux niektóre pliki faktycznie istnieją , na przykład: /usr/bin/bashjest taki, który istnieje. Jednak (o ile dobrze rozumiem), niektóre także w rzeczywistości nie istnieją jako takie i są bardziej wirtualnych plików, np: /dev/sda, /proc/cpuinfo, itd. Moje pytania są (są dwa, ale zbyt ściśle związane odrębne pytania):

  • W jaki sposób jądro Linuksa sprawdza, czy te pliki są prawdziwe (i dlatego odczytują je z dysku), czy nie po wydaniu polecenia odczytu (lub takiego)?
  • Jeśli plik nie jest prawdziwy: na przykład odczyt z /dev/randomzwróci losowe dane, a odczyt z /dev/nullzwróci EOF. Jak to działa, jakie dane należy odczytać z tego pliku wirtualnego (a zatem co zrobić, gdy / jeśli dane zapisane również do pliku wirtualnego) - czy istnieje jakaś mapa ze wskaźnikami do oddzielania poleceń odczytu / zapisu odpowiednich dla każdego pliku, a nawet sam katalog wirtualny? Więc wpis dla /dev/nullmoże po prostu zwrócić EOF.
Joe
źródło
1
Po utworzeniu pliku jądro rejestruje jego typ. Zwykłe pliki dyskowe są wtedy traktowane inaczej niż dowiązania symboliczne, urządzenia blokowe, urządzenia znakowe, katalogi, gniazda, FIFO itp. Zadaniem jądra jest wiedzieć.
Jonathan Leffler,
zobacz człowieka pge for mknod
Jasen
To trochę jak pytanie „skąd włącznik światła wie, czy światło jest włączone?” Przełącznik światła decyduje, czy światło jest włączone.
Wyścigi lekkości z Monicą

Odpowiedzi:

25

Istnieją więc w zasadzie dwa różne rodzaje rzeczy:

  1. Normalne systemy plików, które przechowują pliki w katalogach z danymi i metadanymi w znany sposób (w tym miękkie linki, twarde łącza itp.). Są one często, ale nie zawsze, wspierane przez urządzenie blokujące dla trwałego przechowywania (tmpfs żyje tylko w pamięci RAM, ale poza tym jest identyczny z normalnym systemem plików). Ich semantyka jest znana; czytaj, pisz, zmieniaj nazwy i tak dalej, wszystko działa tak, jak tego oczekujesz.
  2. Wirtualne systemy plików różnego rodzaju. /proci /syssą tutaj przykładami, podobnie jak niestandardowe systemy plików FUSE, takie jak sshfslub ifuse. Jest w nich znacznie więcej różnorodności, ponieważ tak naprawdę odnoszą się one do systemu plików z semantyką, który jest w pewnym sensie „niestandardowy”. Tak więc, kiedy czytasz z pliku pod /proc, tak naprawdę nie uzyskujesz dostępu do określonego fragmentu danych, który został zapisany przez coś innego, co zapisuje go wcześniej, jak w normalnym systemie plików. Zasadniczo wykonujesz wywołanie jądra, żądając informacji generowanych w locie. I ten kod może robić, co tylko zechce, ponieważ jest to tylko jakaś funkcja gdzieś implementująca readsemantykę. Tak więc masz dziwne zachowanie plików /proc, na przykład udając, że są dowiązaniami symbolicznymi, gdy nie są

Kluczem jest to, że w /devrzeczywistości jest to zwykle jeden z pierwszych rodzajów. Współczesne dystrybucje /devsą czymś w rodzaju tmpfs, ale w starszych systemach zwykłym katalogiem na dysku jest brak specjalnych atrybutów. Kluczem jest to, że pliki poniżej/dev to węzły urządzeń, rodzaj specjalnych plików podobnych do FIFO lub gniazd Unix; węzeł urządzenia ma główny i podrzędny numer, a ich odczytywanie lub zapisywanie wywołuje sterownik jądra, podobnie jak odczytywanie lub zapisywanie FIFO wywołuje jądro w celu buforowania danych wyjściowych w potoku. Ten sterownik może robić, co chce, ale zwykle w jakiś sposób dotyka sprzętu, np. Aby uzyskać dostęp do dysku twardego lub odtwarzać dźwięk w głośnikach.

Aby odpowiedzieć na oryginalne pytania:

  1. Istnieją dwa pytania dotyczące tego, czy „plik istnieje”, czy nie; chodzi o to, czy plik węzła urządzenia istnieje dosłownie i czy ma znaczenie sens kopii zapasowej jądra. Ten pierwszy rozwiązano tak jak wszystko w normalnym systemie plików. Nowoczesne systemy używają udevlub coś w tym rodzaju do wyszukiwania zdarzeń sprzętowych i automatycznego tworzenia i niszczenia odpowiednio węzłów urządzeń /dev. Ale starsze systemy lub lekkie niestandardowe wersje mogą po prostu mieć wszystkie swoje węzły urządzeń dosłownie na dysku, utworzone wcześniej. Tymczasem, kiedy czytasz te pliki, wykonujesz wywołanie do kodu jądra, który jest określony przez główne i podrzędne numery urządzeń; jeśli to nie jest rozsądne (na przykład próbujesz odczytać urządzenie blokowe, które nie istnieje), po prostu pojawi się jakiś błąd we / wy.

  2. Sposób, w jaki działa, jaki kod jądra ma być wywoływany, dla którego pliku urządzenia się zmienia. W przypadku wirtualnych systemów plików /proc, implementują własne readi writefunkcje; jądro po prostu wywołuje ten kod w zależności od tego, w którym punkcie montowania jest, a reszta zajmuje się implementacją systemu plików. W przypadku plików urządzeń wysyłany jest na podstawie głównych i podrzędnych numerów urządzeń.

Tom Hunt
źródło
Więc jeśli, powiedzmy, stary system /devzostałby odłączony, pliki nadal byłyby dostępne, ale myślę, że zostałyby usunięte po uruchomieniu systemu?
Joe
2
Jeśli stary system (ten bez dynamicznego tworzenia urządzeń) zostanie zamknięty, normalnie lub nienormalnie, węzły urządzeń pozostaną na dysku, tak jak każdy plik. Następnie, gdy miało miejsce kolejne uruchomienie, pozostały one również na dysku i można ich używać jak zwykle. Tylko w nowoczesnych systemach dzieje się coś wyjątkowego, nie tworząc i niszcząc węzłów urządzeń.
Tom Hunt,
Czyli bardziej nowoczesny system nieużywający tmpfsdynamicznie tworzyłby je i usuwał w razie potrzeby, np .: uruchamianie i zamykanie?
Joe
3
devtmpfs, /devsystem plików we współczesnym systemie Linux jest podobny do tmpfs, ale ma pewne różnice w obsłudze udev. (Jądro wykonuje pewne automatyczne tworzenie węzłów przed przekazaniem do udev, aby uprościć rozruch). We wszystkich tych przypadkach węzły urządzeń żyją tylko w pamięci RAM i są tworzone i niszczone dynamicznie, gdy wymaga tego sprzęt. Prawdopodobnie możesz także użyć udevna zwykłym dysku /dev, ale nigdy tego nie widziałem i nie ma żadnych dobrych powodów.
Tom Hunt,
17

Oto lista plików /dev/sda1mojego prawie aktualnego serwera Arch Linux:

% ls -li /dev/sda1
1294 brw-rw---- 1 root disk 8, 1 Nov  9 13:26 /dev/sda1

Więc wpis w katalogu /dev/dlasda ma numer i-węzła, 1294. To prawdziwy plik na dysku.

Zobacz, gdzie zwykle pojawia się rozmiar pliku. Zamiast tego pojawia się „8, 1”. Jest to główny i mniejszy numer urządzenia. Zwróć także uwagę na „b” w uprawnieniach do plików.

Plik /usr/include/ext2fs/ext2_fs.hzawiera tę (fragment) strukturę C:

/*
 * Structure of an inode on the disk
 */
struct ext2_inode {
    __u16   i_mode;     /* File mode */

Ta struktura pokazuje nam strukturę dyskową i-węzła pliku. W tej strukturze jest wiele interesujących rzeczy; spójrz na to długo.

i_modeElementemstruct ext2_inode ma 16 bitów i używa tylko 9 dla użytkownika / grupy / pozostałych, odczyt / zapis / wykonanie uprawnień, a kolejne 3 do setuid, setgid i lepkie. Ma 4 bity, aby rozróżnić typy, takie jak „zwykły plik”, „link”, „katalog”, „nazwany potok”, „gniazdo rodziny Unix” i „urządzenie blokujące”.

Jądro Linux może postępować zgodnie ze zwykłym algorytmem wyszukiwania katalogów, a następnie podejmować decyzje na podstawie uprawnień i flag w i_modeelemencie. W przypadku „b”, blokuj pliki urządzeń, może znaleźć główne i podrzędne numery urządzeń, i tradycyjnie, użyj głównego numeru urządzenia, aby wyszukać wskaźnik do funkcji jądra (sterownika urządzenia), która zajmuje się dyskami. Podrzędny numer urządzenia zwykle jest używany, jak powiedzmy, numer urządzenia magistrali SCSI, numer urządzenia EIDE lub coś w tym rodzaju.

Niektóre inne decyzje dotyczące sposobu postępowania z plikiem typu /proc/cpuinfosą podejmowane na podstawie typu systemu plików. Jeśli wykonasz:

% mount | grep proc 
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)

widać, że /procma system plików typu „proc”. Czytanie z pliku /procpowoduje, że jądro robi coś innego w zależności od typu systemu plików, podobnie jak otwarcie pliku w systemie plików ReiserFS lub DOS spowodowałoby, że jądro użyłoby różnych funkcji do zlokalizowania plików i zlokalizowania danych pliki.

Bruce Ediger
źródło
Czy jesteś pewien, że tylko „prawdziwe pliki na dysku” mają wyświetlany numer i-węzła? Rozumiem, 4026531975 -r--r--r-- 1 root root 0 Nov 14 18:41 /proc/mdstatco wyraźnie nie jest „prawdziwym plikiem”.
guntbert
7

Na koniec wszystkie są plikami dla Uniksa, to jest piękno abstrakcji.

Sposób, w jaki pliki są obsługiwane przez jądro, teraz jest inna historia.

/ proc, a obecnie / dev i / run (aka / var / run) to wirtualne systemy plików w pamięci RAM. / proc to interfejs / windows do zmiennych i struktur jądra.

Polecam przeczytać jądro Linux http://tldp.org/LDP/tlk/tlk.html i sterowniki urządzeń Linux, wydanie trzecie https://lwn.net/Kernel/LDD3/ .

Podobał mi się także projekt i wdrożenie systemu operacyjnego FreeBSD http://www.amazon.com/Design-Implementation-FreeBSD-Operating-System/dp/0321968972/ref=sr_1_1

Zajrzyj na odpowiednią stronę dotyczącą twojego pytania.

http://www.tldp.org/LDP/tlk/dd/drivers.html

Rui F. Ribeiro
źródło
dzięki, nieznacznie zmieniłem pierwsze pytanie po tym, jak to skomentowałeś.
Joe
Proszę przeczytać ostatni komentarz.
Rui F Ribeiro
5

Oprócz odpowiedzi @ RuiFRibeiro i @ BruceEdiger, twoje rozróżnienie nie jest dokładnie tym, co robi jądro. W rzeczywistości masz różne rodzaje plików: zwykłe pliki, katalogi, dowiązania symboliczne, urządzenia, gniazda (i zawsze zapominam o kilku, więc nie będę próbował stworzyć pełnej listy). Możesz uzyskać informacje o typie pliku za pomocą ls: jest to pierwszy znak w linii. Na przykład:

$ls -la /dev/sda
brw-rw---- 1 root disk 8, 0 17 nov.  08:29 /dev/sda

„B” na samym początku sygnalizuje, że ten plik jest urządzeniem blokowym. Myślnik oznacza zwykły plik, „l” symboliczny link i tak dalej. Informacje te są przechowywane w metadanych pliku i są dostępne statna przykład poprzez wywołanie systemowe , dzięki czemu jądro może na przykład inaczej odczytać plik i dowiązanie symboliczne.

Następnie dokonujesz kolejnego rozróżnienia między „plikami rzeczywistymi” /bin/bashi „plikami wirtualnymi”, /proc/cpuinfoale lszgłaszasz oba jako zwykłe pliki, więc różnica jest inna:

ls -la /proc/cpuinfo /bin/bash
-rwxr-xr-x 1 root root  829792 24 août  10:58 /bin/bash
-r--r--r-- 1 root wheel      0 20 nov.  16:50 /proc/cpuinfo

Dzieje się tak, ponieważ należą one do różnych systemów plików. /procjest punktem montażowym pseudo-systemu plików, procfspodczas gdy /bin/bashznajduje się na zwykłym systemie plików dysku. Kiedy Linux otwiera plik (robi to inaczej w zależności od systemu plików), zapełnia strukturę danych, filektóra ma, między innymi, strukturę kilku wskaźników funkcji, które opisują sposób korzystania z tego pliku. Dlatego może implementować różne zachowania dla różnego rodzaju plików.

Na przykład są to operacje reklamowane przez /proc/meminfo:

static int meminfo_proc_open(struct inode *inode, struct file *file)
{
    return single_open(file, meminfo_proc_show, NULL);
}

static const struct file_operations meminfo_proc_fops = {
    .open       = meminfo_proc_open,
    .read       = seq_read,
    .llseek     = seq_lseek,
    .release    = single_release,
};

Patrząc na definicję meminfo_proc_open, można zauważyć, że ta funkcja zapełnia bufor w pamięci informacjami zwracanymi przez funkcję meminfo_proc_show, której zadaniem jest zbieranie danych o zużyciu pamięci. Informacje te można następnie odczytać normalnie. Przy każdym otwarciu pliku funkcjameminfo_proc_open jest wywoływana, a informacje o pamięci są odświeżane.

lgeorget
źródło
3

Wszystkie pliki w systemie plików są „rzeczywiste” w tym sensie, że pozwalają na operacje wejścia / wyjścia plików. Po otwarciu pliku jądro tworzy deskryptor pliku, który jest obiektem (w sensie programowania obiektowego), który działa jak plik. Jeśli czytasz plik, deskryptor pliku wykonuje metodę odczytu, która z kolei poprosi system plików (sysfs, ext4, nfs itp.) O dane z pliku. Systemy plików stanowią jednolity interfejs do przestrzeni użytkownika i wiedzą, co zrobić, aby obsłużyć odczyty i zapisy. Z kolei systemy plików proszą inne warstwy o obsługę swoich żądań. W przypadku zwykłego pliku, powiedzmy systemu plików ext4, będzie to wymagało wyszukiwania w strukturach danych systemu plików (co może obejmować odczyt dysku), a ostatecznie odczytu z dysku (lub pamięci podręcznej) w celu skopiowania danych do bufora odczytu. W przypadku pliku powiedzmy sysfs, generalnie po prostu sprintf () s coś do bufora. W przypadku węzła tworzenia bloków poprosi sterownik dysku o odczytanie niektórych bloków i skopiowanie ich do bufora (numery główne i podrzędne informują system plików, do którego sterownika należy kierować żądania).

jpkotta
źródło