aboutsummaryrefslogtreecommitdiff
path: root/documentation/content/ru/articles/geom-class/_index.adoc
diff options
context:
space:
mode:
Diffstat (limited to 'documentation/content/ru/articles/geom-class/_index.adoc')
-rw-r--r--documentation/content/ru/articles/geom-class/_index.adoc43
1 files changed, 23 insertions, 20 deletions
diff --git a/documentation/content/ru/articles/geom-class/_index.adoc b/documentation/content/ru/articles/geom-class/_index.adoc
index 9ec0e0c6e2..a7940ade06 100644
--- a/documentation/content/ru/articles/geom-class/_index.adoc
+++ b/documentation/content/ru/articles/geom-class/_index.adoc
@@ -1,8 +1,11 @@
---
-title: Создание класса GEOM
authors:
- - author: Ivan Voras
+ -
+ author: 'Ivan Voras'
email: ivoras@FreeBSD.org
+description: 'Руководство по внутреннему устройству GEOM и созданию собственного класса GEOM'
+tags: ["GEOM", "kernel", "modules", "FreeBSD"]
+title: 'Создание класса GEOM'
trademarks: ["freebsd", "intel", "general"]
---
@@ -47,10 +50,10 @@ endif::[]
toc::[]
[[intro]]
-== Вступление
+== Введение
[[intro-docs]]
-=== Документация
+=== Documentation
Документация по программированию для ядра скудная, это одна из немногих областей программирования, где почти нет хороших учебных пособий, и совет "читай исходники!" - сохраняет свою справедливость. Однако, существует несколько статей и книг разной актуальности, которые рекомендуются к изучению перед тем, как начать программировать:
@@ -88,7 +91,7 @@ options WITNESS_SUPPORT
options WITNESS
....
-Также включите отладочные символы, если планируете выполнять отладку по дампам аварийных отказов
+Также включите отладочные символы, если планируете выполнять отладку по дампам аварийных отказов:
[.programlisting]
....
@@ -129,7 +132,7 @@ kern.metadelay=3
[.programlisting]
....
dumpdev="/dev/ad0s4b"
-dumpdir="/usr/core"
+dumpdir="/usr/core
....
Переменная `dumpdev` указывает на раздел подкачки, а `dumpdir` сообщает системе куда перемещать дамп ядра при следующей загрузке.
@@ -170,7 +173,7 @@ KMOD=geom_journal
.include <bsd.kmod.mk>
....
-Этот [.filename]#Makefile# (с измененными именами файлов) подойдет к любому модулю ядра. Класс GEOM может размещаться в одном единственном модуле ядра. Если для сборки вашего модуля требуется больше, чем один файл, то перечислите их имена, разделенные пробельными символами, в переменной `SRCS`.
+Этот [.filename]#Makefile# (с измененными именами файлов) подойдет к любому модулю ядра. Класс GEOM может размещаться в одном единственном модуле ядра. Если для сборки вашего модуля требуется больше, чем один файл, то перечислите их имена, разделенные пробельными символами, в переменной `SRCS`.
[[kernelprog]]
== Программирование в ядре FreeBSD
@@ -187,7 +190,7 @@ KMOD=geom_journal
static MALLOC_DEFINE(M_GJOURNAL, "gjournal data", "GEOM_JOURNAL Data");
....
-Для того, чтобы можно было использовать этот макрос, необходимо включить следующие заголовочные файлы: [.filename]#sys/param.h#, [.filename]#sys/kernel.h# и [.filename]#sys/malloc.h#
+Для того, чтобы можно было использовать этот макрос, необходимо включить следующие заголовочные файлы: [.filename]#sys/param.h#, [.filename]#sys/kernel.h# и [.filename]#sys/malloc.h#.
Существует еще один механизм выделения памяти - UMA (Universal Memory Allocator), описанный в man:uma[9]. Это специфический метод, преимущественно предназначенный для быстрого выделения памяти под списки, состоящие из элементов одинакового размера (например, динамические массивы структур).
@@ -201,7 +204,7 @@ KMOD=geom_journal
[[kernelprog-bios]]
=== BIOs
-Структура `bio` используется для всех операций ввода/вывода, касающихся GEOM. Она содержит информацию о том, какое устройство ('поставщик geom') должно ответить на запрос, тип запроса, смещение, длину и указатель на буфер, а также набор "определенных пользователем" флагов и полей .
+Структура `bio` используется для всех операций ввода/вывода, касающихся GEOM. Она содержит информацию о том, какое устройство ('поставщик geom') должно ответить на запрос, тип запроса, смещение, длину и указатель на буфер, а также набор "определенных пользователем" флагов и полей .
Важным моментом является то, что `bio` обрабатываются асинхронно. Это значит, что во многих частях кода нет аналога к man:read[2] и man:write[2] функциям из пространства пользовательских процессов, которые не возвращают управление пока не выполнится системный вызов. Скорее, по завершении обработки запроса (или в случае ошибки при обработке) как извещение вызывается определенная пользователем функция.
@@ -220,12 +223,12 @@ KMOD=geom_journal
Класс GEOM выполняет преобразования данных. Эти преобразования могут быть скомпонованы друг с другом в виде дерева. Экземпляр класса GEOM называют __geom__.
-В каждом классе GEOM есть несколько "методов класса", которые вызываются когда экземпляра класса нет в наличии (или же они не привязаны к конкретному экземпляру класса).
+В каждом классе GEOM есть несколько "методов класса", которые вызываются когда экземпляра класса нет в наличии (или же они не привязаны к конкретному экземпляру класса):
* `.init` вызывается тогда, когда системе GEOM становится известно о классе GEOM (например, когда загружается модуль ядра).
-* `.fini` будет вызван в случае отказа GEOM системы от класса (например, при выгрузке модуля).
+* `.fini` будет вызван в случае отказа GEOM системы от класса (например, при выгрузке модуля)
* `.taste` вызывается, когда в системе появляется новый класс или поставщик geom ("provider"). Если соответствие найдено, то эта функция обычно создает и запускает экземпляр geom.
-* `.destroy_geom` вызывается при необходимости разрушить экземпляр geom.
+* `.destroy_geom` вызывается при необходимости разрушить экземпляр geom
* `.ctlconf` будет вызван, когда пользователь запросит изменение конфигурации существующего экземпляра geom
Также определены функции событий GEOM, которые копируются в экземпляр geom.
@@ -241,7 +244,7 @@ KMOD=geom_journal
* `struct g_provider *provider` : "поставщик geom" предоставляемый данным экземпляром geom
* `uint16_t n_disks` : Количество потребителей geom ("consumer"), обслуживаемых данным экземпляром geom
-* `struct g_consumer \**disks` : Массив `struct g_consumer*`. (Невозможно обойтись одинарным указателем, потому что система GEOM создает для нас структуры struct g_consumer)
+* `struct g_consumer \**disks` : Массив `struct g_consumer*`. (Невозможно обойтись одинарным указателем, потому что система GEOM создает для нас структуры struct g_consumer).
Структура `softc` содержит состояние экземпляра geom. У каждого экземпляра есть свой softc.
@@ -283,7 +286,7 @@ KMOD=geom_journal
[.programlisting]
....
- команда [-опции] имя_geom [другие]
+ verb [-options] geomname [other]
....
Общими командами являются:
@@ -329,18 +332,18 @@ KMOD=geom_journal
* Файловая система преобразует запрос в экземпляр структуры bio и передает его системе GEOM. Файловая система "знает", что экземпляр geom должен обработать запрос, так как файловые системы размещаются непосредственно над экземпляром geom.
* Запрос завершается вызовом функции `.start`() в потоке g_down и достигает верхнего экземпляра geom.
* Верхний экземпляр geom (например, это секционировщик разделов (partition slicer)) определяет, что запрос должен быть переадресован нижестоящему экземпляру geom (к примеру, драйверу диска). Вышестоящий экземпляр geom создает копию запроса bio (запросы bio _ВСЕГДА_ копируются при передаче между экземплярами geom при помощи `g_clone_bio`()!), изменяет поля смещения и целевого поставщика geom и запускает на обработку копию при помощи функции `g_io_request`()
-* Драйвер диска также получает запрос bio, как вызов функции `.start`() в потоке `g_down`. Драйвер обращается к контроллеру диска, получает блок данных и вызывает функцию `g_io_deliver`() используя копию запроса bio
-* Теперь, извещение о завершении bio "всплывает" в потоке `g_up`. Сначала в потоке `g_up` вызывается функция `.done`() секционировщика разделов, последний использует полученную информацию, разрушает клонированный экземпляр структуры bio посредством `g_destroy_bio`() и вызывает `g_io_deliver`() используя первоначальный запрос
-* Файловая система получает данные и передает их пользовательскому процессу
+* Драйвер диска также получает запрос bio, как вызов функции `.start`() в потоке `g_down`. Драйвер обращается к контроллеру диска, получает блок данных и вызывает функцию `g_io_deliver`() используя копию запроса bio.
+* Теперь, извещение о завершении bio "всплывает" в потоке `g_up`. Сначала в потоке `g_up` вызывается функция `.done`() секционировщика разделов, последний использует полученную информацию, разрушает клонированный экземпляр структуры bio посредством `g_destroy_bio`() и вызывает `g_io_deliver`() используя первоначальный запрос.
+* Файловая система получает данные и передает их пользовательскому процессу.
-За информацией о том, как данные передаются в структуре `bio` между экземплярами geom, смотрите man:g_bio[9] (обратите внимание на использование полей `bio_parent` и `bio_children`).
+За информацией о том, как данные передаются в структуре `bio` между экземплярами geom, смотрите man:g_bio[9] (обратите внимание на использование полей `bio_parent` и `bio_children`).
Важный момент в том, что __НЕЛЬЗЯ ДОПУСКАТЬ БЛОКИРОВОК В ПОТОКАХ G_UP И G_DOWN__. Вот неполный перечень того, что нельзя делать в этих потоках:
* Вызывать функции `msleep`() или `tsleep`().
* Использовать функции `g_write_data`() и `g_read_data`(), так как они блокируются в момент обмена данными с потребителями geom.
* Ожидать ввод/вывод.
-* Вызывать man:malloc[9] и `uma_zalloc`() с установленным флагом `M_WAITOK`.
+* Вызывать man:malloc[9] и `uma_zalloc`() с установленным флагом `M_WAITOK`
* Использовать man:sx[9]
Это ограничение на код GEOM призвано избежать от "засорения" пути запроса ввода/вывода, так как блокировки обычно не имеют четких временных границ, и нет гарантий на занимаемое время (также на то есть и другие технические причины). Это также значит, что в вышеупомянутых потоках сколь-нибудь сложные операции выполнить нельзя, например: любое сложное преобразование требует выделения памяти. К счастью решение есть: создание дополнительных ядерных потоков.
@@ -348,7 +351,7 @@ KMOD=geom_journal
[[geom-kernelthreads]]
=== Ядерные потоки выполнения, предназначенные для использования в коде geom
-Ядерные потоки выполнения создаются функцией man:kthread_create[9], в своем поведении они схожи с потоками, созданными в пространстве пользовательских процессов, но есть одно отличие: они не могут известить вызвавший их поток о своем завершении; по завершению - необходимо вызывать man:kthread_exit[9]
+Ядерные потоки выполнения создаются функцией man:kthread_create[9], в своем поведении они схожи с потоками, созданными в пространстве пользовательских процессов, но есть одно отличие: они не могут известить вызвавший их поток о своем завершении; по завершению - необходимо вызывать man:kthread_exit[9].
В коде GEOM обычное назначение этих потоков - разгрузить поток `g_down` (функцию `.start`() ) от обработки запросов. Эти потоки подобны "обработчикам событий" ("event handlers"): у них есть очередь событий (которая наполняется событиями от разных функций из разных потоков; очередь необходимо защищать мьютексом), события из очереди выбираются одно за другим и обрабатываются в большом блоке `switch`().