Что такое Linux: ядро, GNU и system calls
Начнём с простого, но важного вопроса. Когда вы говорите «у меня Linux на сервере», что именно вы имеете в виду? Операционную систему? Ядро? Дистрибутив? Все три варианта встречаются в литературе, и они не означают одно и то же. Понимание разницы — это первый шаг к пониманию, что вообще такое Linux.
В этом уроке разберём: что такое ядро Linux, почему правильнее говорить GNU/Linux (но в реальности все говорят «Linux»), что такое system calls и почему ваш ls физически не может прочитать файл напрямую — он просит ядро это сделать.
Это первый по-настоящему технический урок, и в нём появятся новые слова: ядро (kernel), system call, ring 0 / ring 3, ELF, strace. Если часть из них видите впервые — это нормально, так и должно быть. Здесь мы спускаемся на технический слой, который обычно скрыт от пользователя, и знакомимся с ним постепенно. Каждое незнакомое слово в уроке объясняется по ходу, а под многими терминами в диаграммах есть всплывающая подсказка (наведите курсор). Не пытайтесь запомнить всё сразу: задача урока — построить общую картину «программа -> ядро -> железо», а детали уложатся с практикой.
Что такое ядро (kernel)
Ядро и пространство пользователя: архитектура ОСЯдро — это программа, которая запускается первой при загрузке компьютера и работает до выключения. Её работа — управлять железом и предоставлять интерфейс программам.
Когда вы пишете на Python open('file.txt'), Python не лезет напрямую в SSD. Он не знает, как работает контроллер NVMe, как устроена файловая система ext4, как кодируется DMA-передача. Python вызывает ядро, говорит «дай мне доступ к этому файлу», и ядро делает всю грязную работу.
Ядро Linux написано в основном на C (плюс немного ассемблера для платформенно-зависимых частей). Его размер на 2026 год — около 35 миллионов строк кода. Это один из крупнейших open-source проектов в истории.
Создал ядро Linus Torvalds в 1991 году. Тогда это было хобби, теперь — основа большинства серверов в мире.
Linux — это ядро, а не операционная система
Когда люди говорят «у меня Ubuntu Linux», они имеют в виду: ядро Linux + утилиты GNU + менеджер пакетов apt + графика GNOME + куча других программ. Это всё — операционная система.
Само же слово «Linux» в строгом смысле — это только ядро. Утилиты (ls, cp, bash, grep) — это не Linux. Они написаны проектом GNU (GNU’s Not Unix) задолго до того, как Linux появился.
В сумме это и называется «Ubuntu» или «Debian» — конкретная сборка из конкретных версий этих компонентов. Дистрибутивов десятки, и мы разберём их в следующем уроке.
GNU/Linux holy war
Richard Stallman, основатель проекта GNU, настаивает: правильно говорить «GNU/Linux», потому что без GNU userland ядро Linux бесполезно. Без ls и cp вы не можете даже посмотреть, что лежит на диске.
Linus Torvalds на это отвечает примерно так: «Зови как хочешь, мне всё равно. Большинство людей говорит Linux — пусть будет Linux».
В индустрии все говорят «Linux» — короче и привычнее. В академических текстах и в FSF-кругах пишут «GNU/Linux». Мы в курсе будем говорить «Linux» в широком смысле (ядро + userland), но если речь конкретно про ядро — будем уточнять «ядро Linux».
Есть Linux-системы без GNU. Например, Alpine Linux использует musl libc и busybox вместо GNU coreutils. Android тоже использует ядро Linux, но без GNU userland — там Bionic libc и собственные утилиты. Для DE это важно знать: Alpine — основа большинства Docker-образов, и ls в Alpine ведёт себя слегка иначе, чем ls в Ubuntu.
Монолитное ядро
Архитектурно ядро Linux — монолитное. Это значит: всё (управление процессами, память, файловая система, сеть, драйверы) живёт в одном адресном пространстве и работает как одна большая программа.
Альтернатива — микроядро, где каждая подсистема (FS, network, drivers) — отдельный процесс. Микроядра в теории безопаснее (если один драйвер крашится, ядро живёт), но медленнее (передача данных между процессами стоит дороже).
В мире живых микроядер мало: QNX (промышленные системы), L4 (специализированные применения), seL4 (верификация). Все массовые ОС — монолитные: Linux, Windows NT, macOS XNU (формально гибрид, но с большим монолитным куском).
У монолитного ядра Linux есть полезная фича — kernel modules. Драйверы можно загружать на лету через modprobe, без перезагрузки. Технически это всё ещё одна программа (модули работают в адресном пространстве ядра), но управление гибче.
$ lsmod | head -5
Module Size Used by
nvidia_drm 86016 4
nvidia_modeset 1339392 6 nvidia_drm
nvidia_uvm 1572864 0
nvidia 56885248 44 nvidia_uvm,nvidia_modeset,nvidia_drm
Это вывод на ноутбуке с NVIDIA GPU: вот, например, четыре модуля NVIDIA загружены в ядро. Если бы не было NVIDIA — этих модулей не было бы.
System calls: мост между user и kernel
Что такое системный вызов: механика и таблица syscall strace: трассировка системных вызововПрограмма в user space не имеет доступа к железу напрямую. Если bash хочет открыть файл, он не может сам поговорить с SSD. Он делает system call — специальную инструкцию, которая передаёт управление ядру.
Самые частые system calls на Linux (некоторые из 400+):
Когда вы запускаете ls, под капотом происходит примерно так:
- bash делает
fork()— создаёт копию себя. - Копия делает
execve("/usr/bin/ls", ...)— заменяет код на программу ls. - ls делает
getdents()для текущей директории — получает список имён. - Для каждого файла ls делает
stat()— получает права, размер, дату. - ls делает
write(1, ...)— пишет вывод в stdout (fd 1). - ls завершается через
exit().
Это всё system calls. Вы можете увидеть их в реальном времени через strace:
$ strace -e openat,read,write,close ls / 2>&1 | head -20
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\220>\0\0\0\0\0\0", 832) = 832
close(3) = 0
...
openat(AT_FDCWD, "/", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
getdents64(3, 0x55c1a8e7a3a0 /* 19 entries */, 32768) = 600
close(3) = 0
write(1, "bin etc lib32 media ...\n", 142) = 142
strace — это инструмент для отладки. Когда программа странно себя ведёт (висит, не находит файл, не может писать) — strace -e openat,read,write показывает, что именно она пытается делать. Junior, который умеет читать strace, отлаживает любую программу — даже без исходников.
man 2 open — документация system call open. Цифра 2 — секция man-pages для system calls. Секция 1 — обычные команды (man 1 ls = man ls). Секция 3 — библиотечные функции. Секция 8 — административные команды (man 8 mount). Это пригодится: иногда есть одинаковое имя в разных секциях (man printf неоднозначно — есть printf(1) и printf(3)).
Kernel space vs user space
Введение в системные вызовы: открытый путь к ресурсам ОСКогда программа делает system call, происходит переключение режима CPU: с user mode на kernel mode. В kernel mode CPU может делать всё (читать любую память, обращаться к железу). В user mode ограничен.
Это аппаратная защита (на x86 называется «ring level»: ring 3 = user, ring 0 = kernel). Без неё одна программа могла бы перезаписать память другой — это и было в DOS, и потому DOS падал каждые 30 минут.
Переключение режима — это дорогая операция (несколько сотен наносекунд). Поэтому при работе с большими данными хочется минимизировать syscalls. Например, read() по 1 байту — это будет миллион syscalls на 1MB файл. А read() по 64KB — это всего 16 syscalls. Это в миллион раз быстрее.
Эту разницу видно, когда сравнивают cat file | grep foo (две программы, лишние syscalls на pipe) и grep foo file (одна программа, прямое чтение файла). Второй вариант быстрее. Подробнее в модуле 9 про pipes.
Попробуй сам
Откройте терминал. Установите strace, если ещё нет:
# Ubuntu/Debian
$ sudo apt install -y strace
# macOS — strace нет, но есть dtruss (требует sudo)
# Или: ставится через `brew install strace` (но работает только в Linux VM)
Посмотрите system calls, которые делает pwd:
$ strace -c pwd
/home/user
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
25.00 0.000050 5 10 mmap
15.00 0.000030 15 2 openat
10.00 0.000020 10 2 read
...
Флаг -c собирает статистику. Вы увидите, какие syscalls делает программа. Заметьте: даже простой pwd делает десятки системных вызовов (читает свои библиотеки через openat, mmap, проверяет окружение).
Посмотрите версию вашего ядра:
$ uname -a
Linux dev-server 7.0.0-23-generic #25-Ubuntu SMP PREEMPT_DYNAMIC Wed May 1 12:30:00 UTC 2026 x86_64 GNU/Linux
uname -r покажет только версию (например, 7.0.0-23-generic). В Ubuntu 26.04 LTS идёт ядро 7.0, в Debian 13 — 6.12 LTS.