Задание является факультативным. Его исполнение не является обязательным для успешной сдачи экзамена.
Успешная сдача задания освобождает студента от сдачи экзамена.
Реализовать модуль ядра, который регистрирует символьное устройство с именем “math”.
Устройство должно предоставлять возможность взаимодействия с ним с помощью системного вызова ioctl(int fd, unsigned int cmd, unsigned long arg).
Первый аргумент — файловый дескриптор, второй — номер команды, третий — адрес области памяти в пространстве пользователя (для иных устройств это произвольный аргумент).
Область памяти должна содержать массив элементов типа int.
Обработчик каждой команды должен считывать из адресного пространства пользователя аргумент(-ы), вычислять результат и записывать его в область памяти, следующую за последним аргументом.
К примеру, MATH_IOCTL_SUM считывает аргументы по адресам arg и arg+sizeof(int), а записывает результат по адресу arg+2*sizeof(int).
Это устройство должно отвечать на несколько команд системного вызова ioctl(2):
MATH_IOCTL_SQR — возводит в квадрат единственный аргумент
MATH_IOCTL_NEG — меняет знак единственного аргумента
MATH_IOCTL_ADD — складывает два аргумента
MATH_IOCTL_SUB — вычитает второй аргумент из первого
MATH_IOCTL_MUL — умножает два аргумента
MATH_IOCTL_DIV — делит первый аргумент на второй
Модуль должен быть выгружаемым.
Модуль должен использовать определения команд MATH_IOCTL_XXX из файла math.h.
Модуль должен предоставлять возможность одновременной работы с символьным устройством 4 пользователям. Пятому пользователю (и последующим) на попытку открыть файл должен возвращаться код ошибки EBUSY.
Одновременное использование символьного устройства не должно приводить к гонкам (race condition).
Обработчик ioctl должен проверять входные данные и предотвращать целочисленные переполнения, деление на ноль и другие ошибки. Если аргументы пользователя некорректны, ему необходимо вернуть код ошибки EINVAL.
Для взаимодействия с памятью пользователя необходимо использовать функции из набора get_user, put_user, copy_to_user, copy_from_user.
Исходный код утилиты math_ctl, с помощью которой можно проверить работоспособность символьного устройства.
Makefile для сборки модуля и утилиты math_ctl. Для сборки выполните команду “make” без аргументов, для загрузки модуля выполните “make insert_module”.
Заготовка исходного файла модуля с указанием стандартных заголовочных файлов.
Заголовочный файл с определением констант MATH_IOCTL_XXX.
Ссылка на архив: ftp://dione.intelib.org/pub/segoon/math.tar.gz
Для упрощения отладки используйте pr_info(), печатающую отладочную информацию в системный лог (либо другие функции из семейства printk). Лог можно прочитать с помощью консольной команды dmesg.
Для работы с символьным устройством используйте функции
register_chrdev() и
unregister_chrdev(). Из файловых операций структуры
file_operations необходимо реализовать лишь методы open (вызывается при попытке открытия файла), release (вызывается при закрытии файлового дескриптора), unlocked_ioctl (вызывается при соответствующем системном вызове ioctl(2)). Остальные поля структуры file_operations для задания не важны.
Для ограничения числа пользователей рекомендуется использовать атомарные переменные.
Для сборки модуля требуются заголовочные файлы ядра. В дистрибутивах линукс семейства Debian (Debian, Ubuntu, Mint, …) для их установки требуется пакет linux-headers-generic. В дистрибутивах семейства Fedora требуется пакет kernel-devel.
Помните, что код ядра должен возвращать код ошибки в виде отрицательного значения для отличия от успешного (неотрицательного) результата. Пользовательский код преобразует это отрицательное значение в первоначальный код ошибки. Например, если ядро хочет вернуть код ошибки EBUSY, то соответствующая команда должна быть “return -EBUSY”, а не “return EBUSY”.
Если не понятно, как реализовать ту или иную команду, посмотрите в код утилиты math_ctl. Возможно, по коду пользователя этой команды вы поймёте, как нужно действовать.
Учтите, что адрес переменной типа int в адресном пространстве процесса имеет тип “int __user *”, а не “int *”. Макрос ”__user” используется для нахождения небезопасного разыменования пользовательского указателя.
Решённое задание отправляйте на почту segooon AT gmail.com.
При возникновении проблем компиляции, отладки или других проблем пишите на тот же адрес.
Задание является факультативным. Его сдача не влияет ни на сдачу экзамена, ни на получение автомата.
Реализовать модуль ядра, который регистрирует символьное устройство с именем “prime”.
Устройство должно предоставлять возможность взаимодействия с помощью системного вызова read.
При чтении с помощью системного вызова read устройство выдаёт последовательность простых чисел типа uint64_t.
Устройство сохраняет информацию о том, сколько чисел было считано и при последовательных вызовах read выдаёт продолжение прерванной последовательности.
Вызов read с размером буфера, не кратным 8 (sizeof(uint64_t)), обрабатывается как ошибочный.
Возможно использование устройства более чем одним пользователем.
При этом каждый пользователь считывает свою последовательность простых чисел независимо от других пользователей.
Работа с очень большими числами не должна значительно задерживать обработку сигналов.
При получении сигнала процесс не должен блокироваться на длительное время.