Курсовая работа: Мониторинг виртуальной памяти в ОС Linux
Каждый фрагмент исполняемого кода, который может быть добавлен в ядро во время его работы, называется модулем ядра. Каждый модуль создается из объектного кода, не связанного в полноценный исполняемый файл. Модуль может быть загружен в ядро с помощью программы insmod (вызывающей функции create _ module () / init _ module () ), и выгружен с помощью rmmod (вызывающего delete _ module () ). В данной работе реализует именно такой динамически загружаемый модуль.
1.1.7 Типы устройств
В Linux различают три основных типа устройств. Каждый драйвер обычно соответствует одному из этих типов. Выделяют:
· Символьные драйверы
· Блочные драйверы
· Сетевые драйверы
Символьное устройство может рассматриваться как поток байт (так же как и файл); символьный драйвер должен реализовывать такое поведение. Такой драйвер имеет, как правило, функции открытия, закрытия, чтения и записи. Текстовая консоль и последовательный порт – примеры символьных устройств. Они могут легко быть представлены абстракцией потоков. Работа с символьными устройствами осуществляется через специальные файлы устройств, находящиеся в директории /dev. Единственное значимое отличие обычного файла от такого устройства – это произвольный доступ, тогда как к большинству символьных устройств можно обращаться лишь последовательно.
Как и к символьным, доступ к блочным устройствам можно получить через файлы в директории /dev. Блочное устройство – это устройство (например, диск), способное содержать в себе файловую систему. В системе Unix блочное устройство может лишь передавать один или более целых блоков данных, обычно по 512 байт. Интерфейс взаимодействия блочных драйверов с ядром значительно отличается от интерфейса символьных драйверов.
Любая сетевая транзакция выполняется через интерфейс сокетов. Сетевой интерфейс отвечает за передачу и прием пакетов под управлением сетевой подсистемы ядра вне зависимости от того, к каким именно транзакциям они относятся. Многие сетевые соединения (особенно использующие протокол TCP) ориентированы на потоки данных. Но сетевые устройства обычно работают с пакетами, а не с потоками. Таким образом, сетевые устройства содержат в себе черты как символьных, так и блочных.
2. Конструкторский раздел
2.1 Модульная структура драйвера
Драйвер memmon состоит из следующих модулей:
mmon.c – основной модуль, отвечающий за инициализацию и выгрузку драйвера
mm-fault.c – обработчик страничных ошибок
syscalls.c – высокоуровневая часть перехвата системных вызовов
syscalls-entry.S – низкоуровневая часть перехвата системных вызовов
watch-pids.c – список процессов, за которыми осуществляется мониторинг, добавление и удаление из него
events.c – кольцевой буфер событий
2.2 Инициализация и выгрузка драйвера
Инициализацию драйвера выполняет функция int __init init(void). Она вызывается при загрузке драйвера в контексте процесса, вызвашего init_module() (системный вызов загрузки драйвера) и выполняет следующие действия:
1. Инициализирует битовую карту отслеживаемых процессов и кольцевой буфер событий
2. Устанавливает обработчики системных вызовов и страничной ошибки
3. Создает директорию /proc/memmon и файлы в ней
Создание файлов происходит в последнюю очередь для того, чтобы пользовательские приложения не могли обратиться к драйверу до завершения инициализации.
Выгрузку выполняет функция void __exit exit(void) , вызываемая в контексте процесса, сделавшего delete_module() . Она выполняет действия, обратные к init():
1. Удаляет директорию /proc/memmon
2. Снимает перехват системных вызовов и страничного отказа
3. Освобождает память
2.3 Взаимодействие с пользовательскими приложениями
Для взаимодействия с пользовательскими приложениями драйвер использует файловую систему procfs – псевдо-файловую систему, предоставляющую различную информацию о системе. Любой драйвер может добавлять в ее иерархию свои файлы и папки для передачи пользовательским программам различной информации. Ядро предоставляет ряд функций для работы с procfs, из который данный драйвер использует следующие:
proc_mkdir() – создает папку в /proc
create_proc_entry() – создает файл в указанной папке /proc или самой /proc
remove_proc_entry() – удаляет папку или файл в /proc