Билет 04 - honeycarbs/bmstu-os-6sem GitHub Wiki
Файловая подсистема /proc — назначение, особенности, файлы, поддиректории, ссылка self, информация об окружении, состоянии процесса, прерываниях. Структура proc_dir_entry: функции для работы с элементами /proc. Использование структуры file_operations для регистрации функций работы с файлами. Передача данных из адресного пространства пользователя в адресное пространство ядра и обратно (лаб. раб.). Обоснование необходимости использования специальных функций для передачи данных из пространства пользователя в ядро и из ядра в пространство пользователя.
Назначение.
/proc (process information pseudo-file-system) - интерфейс, предоставляющий доступ к структурам ядра. Реализован в виде файловой системы. Информацию мы получаем аналогично обращениям к файлам с помощью стандартных обращений к функциям работыс файлами. Она была создана для того, чтобы разработчики в режиме пользователя могли получать ифнормацию о процессах и ресурсах, которые используют эти процессы. Эта информация доступна из структур ядра, в ЛР3 был написан код для получения информации о процессах из структур ядра, мы обращались к struct task_struct. А proc предоставляет информацию в usermode. Соотвественно, для получения этой информации не надо писать LKM.
Особенности В более старых источниках написано, что файловая система proc является немонтируемой. Под этим подразумевается, что она не связана ни с каким внешним носителем (она видна в файловых системах, подключенных к корневому каталогу, но не связана ни с каким внешним устройством. Поэтому она и называется псевдо-файловой системой).

Однако для того чтобы ФС была доступна, она должна быть подмонтирована, в результате должна быть доступна информация из суперблока, который является основной структурой, описывающей файловую систему. Когда происходит обращение к ФС proc, информация к которой идет обращение создается на лету, то есть файловая система виртуальная.
Файловая система монтируется при загрузке системы. Но ее также можно смонтировать вручную:
mount -t proc proc/porcЭто сделано для общности - система работает единообразно со всеми файловыми системами.
В виртуальной файловой системе proc для каждого процесса существует директория идентификатора процесса /proc/[pid]. Для данной поддиректории также для каждого процесса существует /proc/self, для того, чтобы не вызывать getpid(). В директории /proc/self находятся директории и файлы, несущие информацию об окружении процесса, открытых файлах процессов и т.д.
| элемент | тип | содержание |
|---|---|---|
| cmdline | файл | readonly, содержит полную командную строку для создания |
| вызовов open, mkdir, symlink, mknode. | ||
| cwd | символическая ссылка | Указывает на директорию процесса |
| environ | файл | Информация об окружении процесса |
| exe | символическая ссылка | Указывает на образ процесса (на его файл) |
| fd | директория | Ссылки на файлы, которые «открыл» процесс |
| root | символическая ссылка | Указывает на корень файловой системы процесса |
| stat | файл | Информация о процессе |
/proc/[pid]/environ — информация об окружении процесса.
Данный файл содержит исходное окружение, которое было установлено при запуске текущего процесса (вызове execve()). Переменные окружения разделены символами конца строки ('\0'). Если после вызова execve() окружение процесса будет модифицировано (например, вызовом функции putenv() или модификацией переменной окружения напрямую), этот файл не отразит внесенных изменений.
/proc/[pid]/stat — информация о состоянии процесса.
Данный файл содержит информацию о состоянии процесса (pid, comm, state, ppid, pgrp, session, tty_nr, tpgid, flags и др.)
/proc/interrupts — информация о об источниках прерываний и о частоте возникновения этих прерываний.
Файл /proc/interrupts предоставляет таблицу о количестве прерываний на каждом из процессоров в следующем виде:
- Первая колонка: номер прерывания
- Колонки CPUx: счётчики прерываний на каждом из процессоров
- Следующая колонка: вид прерывания:
- IO-APIC-edge — прерывание по фронту на контроллер I/O APIC
- IO-APIC-fasteoi — прерывание по уровню на контроллер I/O APIC
- PCI-MSI-edge — MSI прерывание
- XT-PIC-XT-PIC — прерывание на PIC контроллер
- Последняя колонка: устройство, ассоциированное с данным прерыванием
Файлы и поддиректории файловой системы /proc используют структуру proc_dir_entry:
struct proc_dir_entry {
const char *name; // имя виртуального файла
mode_t mode; // режим доступа
uid_t uid; // уникальный номер пользователя — владельца файла
uid_t id; // уникальный номер группы, которой принадлежит файл
struct inode_operations *proc_iops; // функции-обработчики операций с inode
struct file_operations *proc_fops; // функции-обработчики операций с файлом
struct proc_dir_entry *next, *parent, *subdir;
...
read_proc_t *read_proc; // функция чтения из /proc
write_proc_t *write_proc; // функция записи в /proc
void *data; // Указатель на локальные данные
atomic_t count; // счетчик ссылок на файл
...
};Начиная с ядра 3.10 больше не поддерживается функция create_proc_entry(). Вместо нее используются функции:
#include <linux/types.h>
#include <linux/fs.h>
extern struct proc_dir_entry *proc_create_data(const char *, umode_t, struct proc_dir_entry *, const struct file_operations *, void *);
struct proc_dir_entry *proc_create(const char *name, umode_t mode, struct proc_dir_entry *parent, const struct file_operations *proc_fops);Создавать каталоги в файловой системе /proc можно используя proc_mkdir(), а также символические ссылки с proc_symlink(). Для простых элементов /proc, для которых требуется только функция чтения, используется create_proc_read_entry(), которая создает запись /proc и инициализирует функцию read_proc в одном вызове.
extern struct proc_dir_entry *proc_symlink(const char *, struct proc_dir_entry *, const char *);
extern struct proc_dir_entry *proc_mkdir(const char *, struct proc_dir_entry *);
struct proc_dir_entry *create_proc_read_entry( const char *name, mode_t mode, struct proc_dir_entry *base, read_proc_t *read_proc, void *data );
### Использование структуры file_operations для регистрации функций работы с файлами
С некоторой версии ядра file_operations не поддерживается. Пример из лаб. раб. регистрации функций работы с файлами:
```C
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0)
#define HAVE_PROC_OPS
#endif
#ifdef HAVE_PROC_OPS
static struct proc_ops fileops = {
.proc_read = fortune_read,
.proc_write = fortune_write,
.proc_open = fortune_open,
.proc_release = fortune_release,
};
#else
static struct file_operations fileops = {
.owner = THIS_MODULE,
.read = fortune_read,
.write = fortune_write,
.open = fortune_open,
.release = fortune_release,
};
#endifПередача данных из адресного пространства пользователя в адресное пространство ядра и обратно (лаб. раб.)
// const char __user *buf - адрес источника в пространстве пользователя
ssize_t fortune_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) {
int space_left = (_BUF_SIZE - write_inx) + 1;
printk(KERN_INFO "== fortine write is called");
if (space_left < count) {
printk(KERN_INFO "== ERROR: buffer is full. Terminating...");
return -ENOSPC;
}
if (copy_from_user(&_cookie_pot[write_inx], buf, count)) {
return -EFAULT; // no space left on device
}
write_inx += count;
_cookie_pot[write_inx - 1] = '\0';
printk(KERN_INFO "== writing successful");
return count;
}
static ssize_t fortune_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) {
int len;
if (*ppos > 0) {
return 0;
}
if (read_inx >= write_inx) {
read_inx = 0;
}
len = 0;
if (write_inx > 0) {
len = sprintf(tmp, "%s\n", &_cookie_pot[read_inx]);
copy_to_user(buf, tmp, len);
buf += len;
read_inx += len;
}
*ppos += len;
printk(KERN_INFO "== reading successful");
return len;
}БУФЕР КОЛЬЦЕВОЙ, НЕ ЦИКЛИЧЕСКИЙ
Обоснование необходимости использования специальных функций для передачи данных из пространства пользователя в ядро и из ядра в пространство пользователя.
Из U в K:
напрямую приложение обратиться к буферу ядра не может. Т.е. та последовательность действий по read/write, которая реализована при обращении к внешним устройствам (файлам, клавиатуре, мыши) здесь не работает, поскольку идет обращение к ядру. Ядро защищено.
Из K в U:
Когда ядро обращается к приложениям, там обратная ситуация, поскольку выполняется код ядра, может возникнуть ситуация, когда буфер, к которому обращается код ядра, находится на странице, которая выгружена по каким-то причинам.