FreeBSD, 08 лекция (от 20 октября)
Материал из eSyr's wiki.
Сегодня про инпут-оутпут.
Возьмем приложение, которое что-то пишет на диск и посмотрим на его колл стек.
dtrace -l -- все дтрейс провайдеры в ядре, то есть все функции, в которые дтрейс поставил хуки и которые мы можем перехватить.
Будем перехватывать vtblk_startegy.
Делаем скрипт,который вешает хук на эту функцию, указывая ограничение, что нас интересует только процессор dd. Распечатываем стек командой stack(20)
Что происходит первым делом вс сисколе? Все сисколы, как рид, так и райт, работают с структурой uio, она доходит до самого vop слоя. Эта структура аллоцируется и заполняется. Дальше нам надо разрешить этот дескриптр в стракт файл. А дальше у файла есть методы, которые и вызываются. fo_read и fo_write. Дальше рассмотрим случай, когда попадаем в ио ноду. Vnode отправляет uio в VFS.
Если у нас была настоящая система, у которой есть драйвер, то дальше попадем в GEOM.
Структуру uio создает хэндлер на стеке. Если операция была векторная, то будет вектор. Потом смещение в файле, потом resid -- сколько надо считать или записать, модифицируемая. Потом указывается в каком адресном пространстве все будет, пишем или читаем, тред владелец.
Далее идет fget_read fget_write
Далее fo_write -- это простейший инлайн, который использует структуру, описывющую операции стракт файла.
структура fileops с полями, названия которых говорят сами за себя. Своя для каждого типа файло -- сокетов, файлов, итд. Специальная структура bad_fieops для случаев вроде forced unmount.
Нас инересуют только файлы с Vnode.
Если файловый дескриптор имеет типа DTYPE_VNODE у него будет указатель на реальную вноду.
Это может быть именованный сокет, симлинк, локальный файл, директория. Для любого файла на машине может существовать не более одной вноды. Почему в? От слова виртуал. Появилась в раннем юниксе, когда возникла необходимост в абстракции над разными файловыми системами.
В структуре есть
* тип * вектор операций(зависит от типа фс) * структура для данных для фс * ссылка на маунт пойнт -- на тот экземпляр фс, которой эта внода принадлежит. * два реф каунтера различной степени жесткости. Когда они обнуляются внода может быть удалена, но необязательно -- некоторое время она будет болтаться в кэше. * структура buf_obj, которая собирает в себе множество буферов, которые представляют содержимое файло. ПОнятно что весь файл в память за раз не поднимается. Описывается по каким офсетам какая информация до куда поднята и грязные ли буфера.
Теперь воп_вектор.
Это тоже структура с указателями на функции и еще указателем на другой воп_вектор. Таким образом они могут друг друга наследовать. Это появилось в середине 70, когда стало понятно что одна ос и одна фс это неудобно. Все было до с++. Сначала сделали в солярис. Сделали объектный слой. Сам код для этого генерируется автоматически из файла с описаниями.
Делается для того, чтобы можно было сделать стек из векторов.
Корнем иерархии является вектор, который на все операции говорит not_supported.
ffs умеет только создавать, переименовывать, но когда доходит до дискового ио, она передает все ufs.
Код генерируется с помощью awk.
генерируется структура аргументов vop_read_args и две декларации VOP_READ_APV и VOP_READ
Теперь про структуру buf_obj Давным давно, когда в юниксе не было ммап. Буф ссылался на номер иноды, смещение и длину. Когда появился ммап стало понятно, что надо объединять эти две вещи.
Каждый буф стал коллекцией vm_pages. В некотором смысле это compatibililty layer.
Сам буф это заголовок, а сами данные в vm_page. Количество страниц в буфере -- сколько можем за один раз вытащить с диска делить на размер страницы.
Страницы не обязательно должны быть последвательны в памяти.
Получается вм_обж, который ссылается на вноде, внод ссылается на буф_обж, а буф_обж обратно на внод и вм_обж. И еще буф_обж в некотором смысле дублирует вм_обж. Есть какбы прямое отображение файла в страницы, которые делает вм, и есть менее прямое, которое делает буф_обж.
ммап плохо увязывается в общую концепцию юникса, где к файлам был доступ через рид и райт, и если винчестер умирал, мы получали синхронную ошибку.
Представим ситуацию, когда процесс делает ммап какого-то файла. потом открывает файл два. потом делает рид и читае в память, но не в простую, а которая мэтчится в файл. Предположим рид небольшой, меньше страницы. Если два процесса один читает из одного файла в ммап другого файла, а второй наоборот, то получаем дедлок.
При этом решение должно не замедлять нормальную работу.
Дизайн и реализация ОС FreeBSD
01 02 03 04 05 06 07 08 09 10 11 12
Календарь
Октябрь
| 02 | 09 | 16 | 23 | 30 |
Ноябрь
| 06 | 13 | 20 | 27 | |
Декабрь
| 04 | 11 | 18 |