Як Linux відрізняє реальні та неіснуючі (наприклад: пристрої) файли?


28

Це питання на низькому рівні, і я розумію, що це може бути не найкраще місце для запитання. Але це здавалося більш доцільним, ніж будь-який інший веб-сайт SE, і ось далі.

Я знаю, що у файловій системі Linux деякі файли фактично існують , наприклад: /usr/bin/bashтакий, який існує. Тим НЕ менше, (наскільки я розумію), деякі з них також фактично не існує як такої і більш віртуальних файлів, наприклад: /dev/sda, /proc/cpuinfoі т.д. Мої питання (вони два, але занадто тісно пов'язані , щоб бути окремі питання):

  • Як ядро ​​Linux працює, чи є ці файли справжніми (і тому читати їх з диска) чи ні, коли видається команда читання (або така)?
  • Якщо файл не є реальним: як приклад, читання з /dev/randomповерне випадкові дані, а читання з /dev/nullповернеться EOF. Як працює, які дані читати з цього віртуального файлу (а отже, що робити, коли / якщо дані також записуються у віртуальний файл) - чи існує якась карта з покажчиками, щоб розділити команди читання / запису, відповідні кожному файлу, чи навіть для самого віртуального каталогу? Отже, запис у програмі /dev/nullможе просто повернути EOF.

1
Коли файл створюється, ядро ​​записує його тип. Зазвичай файли диска обробляються по-різному від символьних посилань, блокуючих пристроїв, символьних пристроїв, каталогів, сокетів, FIFO тощо. Це завдання знати ядро.
Джонатан Леффлер

дивіться чоловік pge для mknod
Ясен

Це на зразок запитання "як перемикач світла знає, чи увімкнено світло?" Вимикач світла відповідає за те, щоб вирішити, чи включено світло.
Легкі перегони з Монікою

Відповіді:


25

Таким чином, тут є два різні речі:

  1. Звичайні файлові системи, які містять файли в каталогах з даними та метаданими, звичним способом (включаючи м'які посилання, жорсткі посилання тощо). Вони часто, але не завжди, підтримуються блоковим пристроєм для постійного зберігання (tmpfs живе лише в оперативній пам'яті, але в іншому випадку ідентичний звичайній файловій системі). Семантика їх знайома; читати, писати, перейменувати тощо, все працює так, як ви їх очікуєте.
  2. Віртуальні файлові системи різних видів. /procі /sysє прикладами тут, як і FUSE власні файлові системи типу sshfsабо ifuse. У них набагато більше різноманітності, оскільки насправді вони просто посилаються на файлову систему з семантикою, яка в певному сенсі є "звичайною". Таким чином, коли ви читаєте з файлу внизу /proc, ви фактично не отримуєте доступу до певного фрагменту даних, який зберігається чимось іншим, записуючи його раніше, як у звичайній файловій системі. Ви по суті здійснюєте виклик ядра, запитуючи деяку інформацію, що генерується на ходу. І цей код може робити все що завгодно, оскільки це лише якась функція, де реалізується readсемантика. Таким чином, у вас є дивна поведінка файлів під /proc, як, наприклад, прикидаючись символічними посиланнями, коли вони відсутні '

Ключовим є те, що /devнасправді, як правило, є одним із перших видів. У сучасних дистрибутивах нормально мати /devщось на зразок tmpfs, але в старих системах було нормально мати звичайний каталог на диску, без особливих атрибутів. Ключовим є те, що файли під/dev є вузли пристрою, це тип спеціального файлу, подібного до FIFO або Unix-сокетів; вузол пристрою має основне та другорядне число, і їх читання або запис здійснює дзвінок до драйвера ядра, подібно до читання або запису FIFO викликає ядро ​​для буферування результатів у трубі. Цей драйвер може робити все, що завгодно, але зазвичай він якось торкається обладнання, наприклад, для доступу до жорсткого диска або відтворення звуку в колонках.

Щоб відповісти на початкові запитання:

  1. Є два питання, що стосуються того, існує "файл" чи ні; це те, чи буквально існує файл вузла пристрою та чи має значення підтримка коду ядра. Перший вирішується так само, як і все, у звичайній файловій системі. Сучасні системи використовують udevабо щось подібне для спостереження за подіями обладнання та автоматично створюють і знищують вузли пристрою /devвідповідно. Але старіші системи або легкі побудови на замовлення можуть просто мати усі свої вузли пристроїв буквально на диску, створені достроково. Тим часом, читаючи ці файли, ви здійснюєте виклик коду ядра, який визначається основним та незначним номером пристрою; якщо вони не є розумними (наприклад, ви намагаєтеся прочитати блоковий пристрій, який не існує), ви просто отримаєте якусь помилку вводу / виводу.

  2. Як це працює, який код ядра потрібно викликати, для якого файлу пристрою залежить. Для таких віртуальних файлових систем /procвони реалізують свої власні readта writeфункції; ядро просто викликає цей код залежно від того, в якій точці монтажу він знаходиться, а реалізація файлової системи піклується про інше. Для файлів пристрою він надсилається на основі основних та незначних номерів пристроїв.


Так, якщо, скажімо, у старої системи була потужність, файли в /devних все-таки були б, але я думаю, що вони будуть очищені при запуску системи?
Джо

2
Якщо стара система (та без створення будь-якого динамічного пристрою) була вимкнена, нормально або ненормально, вузли пристрою залишалися б на диску, як і будь-який файл. Потім, коли відбудеться наступний завантаження, вони також залишаться на диску, і ви можете використовувати їх як звичайні. Лише в сучасних системах відбувається щось особливе, що створюється і знищує вузли пристроїв.
Том Хант

Отже, більш сучасна система, яка не використовує tmpfs, динамічно створюватиме та видалятиме їх за потребою, наприклад: завантаження та завершення роботи?
Джо

3
devtmpfs, /devфайлова система в сучасному Linux схожа на a tmpfs, але має деякі відмінності в підтримці udev. (Ядро виконує деякі автоматизовані створення вузлів самостійно перед передачею udev, щоб зробити завантаження менш складним.) У всіх цих випадках вузли пристроїв живуть лише в оперативній пам'яті та створюються та знищуються динамічно, як цього вимагає обладнання. Імовірно, ви також можете користуватися udevна звичайному диску /dev, але я ніколи не бачив цього, і це, здається, не має жодних вагомих причин.
Том Хант

17

Ось список файлів /dev/sda1на моєму майже сучасному сервері Arch Linux:

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

Таким чином, запис у каталозі /dev/для sdaмає номер inode 1294. Це реальний файл на диску.

Подивіться, де зазвичай відображається розмір файлу. Натомість з'являється "8, 1". Це основний та незначний номер пристрою. Також зверніть увагу на "b" у дозволах на файл.

Файл /usr/include/ext2fs/ext2_fs.hмістить цю структуру (фрагмент) C:

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

Ця структура показує нам структуру диска inode файлу. У цій структурі є багато цікавого; довго погляньте на це.

i_modeЕлемент struct ext2_inodeмає 16 бітів, і він використовує тільки 9 для користувача / групи / інший, читання / запис / виконання дозволів, а інший 3 для Setuid, setgid і липким. У ньому є 4 біти для розмежування таких типів, як "звичайний файл", "посилання", "каталог", "названа труба", "сокет сімейства Unix" та "блок пристроїв".

Ядро Linux може слідувати звичайному алгоритму пошуку каталогів, а потім приймати рішення на основі дозволів та прапорів у i_modeелементі. Для "b" блокуйте файли пристроїв, вони можуть знаходити основні та незначні номери пристроїв, а традиційно за допомогою основного номера пристрою шукайте вказівник на деяку функцію ядра (драйвер пристрою), що займається дисками. Незначний номер пристрою зазвичай використовується як, скажімо, номер пристрою шини SCSI або номер пристрою EIDE або щось подібне.

Деякі інші рішення про те, як поводитися з файлом як /proc/cpuinfo, приймаються на основі типу файлової системи. Якщо ви робите:

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

ви бачите, що /procмає тип файлової системи "proc". Читання з файлу у /procзмушує ядро ​​робити щось інше залежно від типу файлової системи, подібно до того, як відкриття файлу у файловій системі ReiserFS або DOS призведе до того, що ядро ​​використовує різні функції для пошуку файлів та пошуку даних файли.


Ви впевнені, що лише "реальні файли на диску" мають номер inode? Я розумію, 4026531975 -r--r--r-- 1 root root 0 Nov 14 18:41 /proc/mdstatщо явно не є "реальним файлом".
guntbert

7

Зрештою, вони всі файли для Unix, ось краса абстракції.

Те, як ядро ​​обробляє файли, тепер це вже інша історія.

/ proc і нині / dev та / run (aka / var / run) - це віртуальні файлові системи в оперативній пам'яті. / proc - це інтерфейс / windows для змінних та структур ядра.

Рекомендую прочитати ядро ​​Linux http://tldp.org/LDP/tlk/tlk.html та драйвери пристроїв Linux, третє видання https://lwn.net/Kernel/LDD3/ .

Мені також сподобалося проектування та впровадження операційної системи FreeBSD http://www.amazon.com/Design-Implementation-FreeBSD-Operating-System/dp/0321968972/ref=sr_1_1

Подивіться на відповідну сторінку, що стосується вашого питання.

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


дякую, я трохи змінив перше питання після того, як ви прокоментували це.
Джо

Прочитайте, будь ласка, останній коментар.
Rui F Ribeiro

5

Окрім відповідей @ RuiFRibeiro та @ BruceEdiger, відмінність, яку ви робите, - це не саме відмінність ядра. Насправді у вас є різні види файлів: звичайні файли, каталоги, символічні посилання, пристрої, сокети (і я завжди забуваю їх декілька, тому я не намагаюся скласти повний список). Ви можете мати інформацію про тип файлу за допомогою ls: це перший символ у рядку. Наприклад:

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

Значення "b" на самому початку сигналізує про те, що цей файл є блоковим пристроєм. Тире, означає звичайний файл, "я" символічне посилання тощо. Ця інформація зберігається у метаданих файлу і є доступною, наприклад, через системний виклик stat, тому ядро ​​може читати файл по-різному, наприклад, символічне посилання.

Потім ви робите інше розмежування між такими як "реальні файли", як /bin/bash"віртуальні файли", /proc/cpuinfoале lsповідомляєте як про звичайні файли, так що різниця має інший вид:

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

Що відбувається, це те, що вони належать до різних файлових систем. /procє точкою монтажу псевдофайлової системи, procfsтоді як /bin/bashзнаходиться у звичайній файловій системі диска. Коли Linux відкриває файл (він робить це по-різному залежно від файлової системи), він заповнює структуру даних, fileяка, серед інших атрибутів, має структуру з декількох функціональних покажчиків, які описують, як користуватися цим файлом. Отже, він може реалізувати різну поведінку для файлів різного типу.

Наприклад, такі операції рекламуються /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,
};

Якщо ви подивитесь на визначення meminfo_proc_open, ви можете побачити, що ця функція заповнює буфер в пам'яті з інформацією, поверненою функцією meminfo_proc_show, завданням якої є збір даних про використання пам'яті. Потім цю інформацію можна прочитати нормально. Кожен раз, коли ви відкриваєте файл, meminfo_proc_openвикликається функція , і інформація про пам'ять оновлюється.


3

Усі файли у файловій системі є "справжніми" в тому сенсі, що вони дозволяють введення / виводу файлів. Коли ви відкриваєте файл, ядро ​​створює дескриптор файлу, який є об'єктом (у сенсі об'єктно-орієнтованого програмування), який діє як файл. Якщо ви читаєте файл, дескриптор файлу виконує метод читання, який, у свою чергу, запитає у файловій системі (sysfs, ext4, nfs тощо) дані з файлу. Файлові системи представляють єдиний інтерфейс до простору користувачів і знають, що робити для обробки читання та запису. Файлові системи, у свою чергу, просять інші шари обробляти їх запити. У звичайному файлі, скажімо, у файловій системі ext4, це вимагатиме пошуку в структурі даних файлової системи (яка може включати в себе зчитування диска), а в кінцевому підсумку читання з диска (або кеша) для копіювання даних у буфер читання. Для файлу в say sysfs, це загалом просто sprintf () s щось до буфера. Для вузла блочного розробника він попросить драйвер диска прочитати деякі блоки та скопіювати їх у буфер (основні та незначні номери повідомляють файловій системі, до якого драйвера надсилати запити).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.