Блочные и символьные устройства¶
Отличие блочных и символьных устройств¶
Устройства в Linux представлены специальными файлами в /dev. Первый символ в выводе ls -l указывает на тип:
ls -l /dev/sda /dev/tty
# brw-rw---- ... /dev/sda (b — блочное)
# crw-rw-rw- ... /dev/tty (c — символьное)
Символьное устройство (character device, c):
- работает как последовательный поток байт;
- обычно не поддерживает произвольное позиционирование (
lseek); - примеры:
/dev/tty,/dev/null,/dev/random,/dev/urandom,/dev/input/mouse0.
Блочное устройство (block device, b):
- предоставляет доступ к данным фиксированными блоками (обычно 512 байт или 4 КБ);
- поддерживает случайный доступ по смещению (
lseek); - используется файловыми системами для хранения данных;
- примеры:
/dev/sda,/dev/sda1,/dev/nvme0n1.
Иерархия ввода-вывода: от userspace до железа¶
Userspace
┌────────────────────────────────────────────────────────────┐
│ open("/dev/sda", ...) open("/dev/tty", ...) │
│ read(fd, buf, n) write(fd, buf, n) │
└──────────────────┬─────────────────────┬───────────────────┘
│ syscall │ syscall
▼ ▼
┌────────────────────────────────────────────────────────────┐
│ VFS (Virtual File System) │
│ единый интерфейс: struct file_operations │
│ (.read, .write, .ioctl, .mmap, ...) │
└──────────────────┬─────────────────────┬───────────────────┘
│ │
блочное устр. символьное устр.
│ │
▼ ▼
┌──────────────────────────┐ ┌──────────────────────────┐
│ Block I/O layer │ │ Char device driver │
│ │ │ │
│ ┌────────────────────┐ │ │ поток байт без буфера │
│ │ Page cache │ │ │ нет произвольного │
│ │ (буферизация: │ │ │ позиционирования │
│ │ блоки кешируются │ │ │ │
│ │ в RAM) │ │ │ /dev/tty — терминал │
│ └────────┬───────────┘ │ │ /dev/null — пустота │
│ │ │ │ /dev/random — энтропия │
│ ┌────────▼───────────┐ │ └──────────────┬───────────┘
│ │ I/O scheduler │ │ │
│ │ (CFQ, deadline, │ │ │
│ │ noop, ...) │ │ │
│ └────────┬───────────┘ │ │
└───────────┼──────────────┘ │
│ │
▼ ▼
┌──────────────────────────────────────────────────────────┐
│ Device driver │
│ (модуль ядра, регистрирует major/minor) │
└──────────────────────────────┬───────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────┐
│ Hardware │
│ SSD/HDD (SCSI/NVMe) UART / USB / GPU / ... │
└──────────────────────────────────────────────────────────┘
Ключевое различие:
- Блочное устройство: запросы накапливаются в очереди, page cache позволяет переиспользовать данные без повторного
чтения с диска, поддерживается
lseek. - Символьное устройство: каждый
read/writeуходит напрямую в драйвер, кеш не задействован, последовательный поток без позиционирования.
Чтение и запись с устройств¶
С точки зрения программы устройства — это обычные файлы, доступные через open, read, write:
#include <fcntl.h>
#include <unistd.h>
// Чтение случайных байт
int fd = open("/dev/random", O_RDONLY);
unsigned char buf[32];
ssize_t n = read(fd, buf, sizeof(buf));
close(fd);
// Запись в терминал
int tty = open("/dev/tty", O_WRONLY);
write(tty, "Hello\n", 6);
close(tty);
Виртуальные устройства: /dev/null, /dev/zero, /dev/random¶
Виртуальные устройства не связаны с реальным физическим оборудованием — они реализованы прямо в ядре:
| Устройство | Чтение | Запись |
|---|---|---|
/dev/null |
Всегда возвращает EOF (0 байт) | Молча поглощает всё |
/dev/zero |
Бесконечный поток нулевых байт | Молча поглощает всё |
/dev/random |
Случайные байты (с Linux 5.6 блокирует только до инициализации CRNG, далее как /dev/urandom) |
Пополняет пул энтропии |
/dev/urandom |
Случайные байты (не блокирует) | Пополняет пул энтропии |
/dev/full |
Бесконечный поток нулей | Всегда возвращает ENOSPC |
Пример: создать файл из 10 МБ нулей:
Перенаправление stdout/stderr в терминал¶
Каждый активный терминал (псевдотерминал) виден как /dev/pts/N. Перенаправить вывод программы в конкретный терминал
можно через dup2:
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main(void) {
int fd = open("/dev/pts/3", O_WRONLY);
if (fd == -1) {
perror("open");
return 1;
}
dup2(fd, 1); // перенаправить stdout
dup2(fd, 2); // перенаправить stderr
close(fd);
printf("Hello from process!\n");
return 0;
}
То же самое из оболочки:
Узнать номер своего терминала: команда tty выводит путь к устройству (/dev/pts/1 и т.п.).
Информация об оборудовании в файловой системе¶
Linux экспортирует информацию о железе через виртуальные файловые системы — данные генерируются ядром динамически и не хранятся на диске:
| Путь | Содержимое |
|---|---|
/proc/cpuinfo |
Модель, тактовая частота и флаги каждого процессора |
/proc/meminfo |
Объём и состояние оперативной памяти |
/proc/<pid>/maps |
Карта виртуальной памяти конкретного процесса |
/sys/block/* |
Информация о блочных устройствах (дисках, SSD) |
/sys/class/net/* |
Сетевые интерфейсы |
/sys/class/hwmon/* |
Датчики температуры, напряжения, скорости вентилятора |
Старший и младший номера устройства (major/minor)¶
Каждый файл устройства идентифицируется парой чисел:
- major — номер драйвера (ядро использует его для поиска нужного драйвера);
- minor — номер конкретного экземпляра устройства внутри драйвера.
ls -l /dev/sda /dev/sda1 /dev/null
# brw-rw---- 1 root disk 8, 0 /dev/sda (major=8, minor=0)
# brw-rw---- 1 root disk 8, 1 /dev/sda1 (major=8, minor=1)
# crw-rw-rw- 1 root root 1, 3 /dev/null (major=1, minor=3)
Программно получить major/minor из struct stat:
#include <sys/stat.h>
#include <sys/sysmacros.h>
struct stat st;
stat("/dev/sda", &st);
unsigned int maj = major(st.st_rdev);
unsigned int min = minor(st.st_rdev);
Создать файл устройства вручную (требует root):
#include <sys/stat.h>
#include <sys/sysmacros.h>
dev_t dev = makedev(8, 0);
mknod("/dev/mysda", S_IFBLK | 0660, dev);
Или через команду:
Связанные темы¶
- Основы файловых систем — типы файлов в VFS,
/dev/shm, tmpfs - Перенаправление ввода/вывода —
/dev/null, перенаправление stderr - mmap и отображение файлов — отображение блочных устройств и файлов в память
- Файловые дескрипторы —
open,read,writeдля устройств
Источники¶
man 4 null— устройства /dev/null и /dev/zeroman 4 random— генераторы случайных чиселman 4 tty— терминальные устройстваman 2 mknod— создание файла устройстваman 3 major— макросы major/minor/makedevman 5 proc— виртуальная файловая система /procman 5 sysfs— виртуальная файловая система /sys