06 сем Лекция 3 - chrislvt/OS GitHub Wiki
Линукс предоставляет интерфейс VFS, в Unix VFS Vnode.
Основными структурами является struct suberblock, struct dentry.
В struct superblock увидели важнейшие поля:
struct file_system_types система предоставляет возможность создать собственный тип файловой системы и зарегистрировать его но тип может быть один, в то время как смонтированных фс может быть много. Кроме это имеется указатель на struct super_operations, struct dentry_operations, нет указателя struct inode_operations. Кроме перечисленных полей которые нам перечисляли, хочет добавить поле void *s_fs_info; это закрытая приватная информация ФС. Обратить внимание Это может быть полезно при разработке собственной Фс. Код для создания управления и ликвидация объектов суперблок находится в файле fs/super.c. Объект суперблок создается и инициализируется в функции alloc_super() вызывается при монтировании ФС. alloc_super() создает новый superblock, т.е выделяет инициализирует новую структуру суперблок.
Заголовок функции выглядит следующим образом :
Опустит важные интересные строки, все можно посмотреть в мануале
static struct super_block *alloc_super(struct file_system_type * type, int flags, struct user_namespace *user_ns)
{
...
INIT_LIST_HEAD(&s->s_mounts);
...
return NULL;
}
Структура struct super_operations описывает таблицу операции определенную на супер блоке, если например в ФС необходимо выполнить запись в суперблок, то будет вызываться функция write_superblock следующим образом:
sb->s_op->write_super(sb);
где указатель на сб указатель на супер блок, write_super передается указатель на суперблок в качестве параметра. Данная запись вытекает из того факта что ядро линукс написано на языке си и по правилам языка си обращение к полям указателя выполняется таким образом. Данный пример полезен для обращения к соотв. полям структур
Struct super_operations.
<linux/fs.h>
struct super_operations
{
struct inode *(*alloc_inode)(struct super_block *sb);
void (*destroy_inode)(struct inode *);
void (*dirty_inode)(struct inode *, int flags);
int (* write_inode)(struct inode *, struct writeback_control * wbc);
int (* drop_inode)(struct inode *);
void (* put_super)(struct super_block *);
int(* sync_fs)(struct super_block *sb, int wait);
...
int (* statfs)(struct dentry, struct kstatfs *);
int (*remount_fs)(struct super_block, int *, char *);
int (*umount_begin)(struct super_block *);
}
Про первую. Это функция создает и инциализирует новый объект inode. К ооп не имеет никакого отношение, но подчеркивает что это не тип, а экземпляр соответствующего типа. Создан чтобы представлять В ФС какой то файл. Если создаем файл в Фс, то он будет сопоставлен с опр. суперблоком. ФС Может быть не смонтированной, то есть может быть виртуальной, но все равно у нее будет суперблок, суперблок может существовать как структура в памяти.
Очевидно что есть функция что удаляет объект.
dirty обозначает измененный inode. Были внесены какие то изменения в struct inode. Вызывается подсистемой VFS для того чтобы обновить информацию в журналируемых файловых системах например EXT3.
Из write следует что записывает указанный inode на диск. В старых версиях в качестве второго параметр int wait, сейчас указывает как должно выполняться операция например синхронно.
drop_inode Эта функция вызывается подсистемой VFS когда исчезает последняя ссылка на inode. Подчеркивается что обычная фс unix никогда не определяет эту функцию и в этом случае подсистема VFS удаляет этот inode.
put_super эта функция вызывается при размонтировании VFS для освобождения указанного суперблока.
sync_fs Синхронизирует метаданные фс с данным на диске. Параметр wiat указывает синхронно или асинхронно.
ЕЩЕ РАЗ ПОВТОРЯЕТ. Структуры меняются. Надо внимательно смотреть на версию ядра, с который вы собираетесь писать ФС
statfs Вызывается для статистики ФС. При этом статистика записывается в структуру statfs.
statfs возвращает информацию о запущенной файловой системе
*remount_fs Вызывается когда ФС монтируется с другими параметрами монтирования.
umount_begin речь идет о прерывании монтирования, ей передается struct superblock.
Все эти функции связанны с inode. Важнейшей информации является inode, структуры описывающие файлы. Смонтированной ФС!! Здесь видим операции определенные на inode и super_block, мы можем получить статистику, мы видим dentry( информацию о каталогах).
НЮ хочет подчеркнуть, в отношение другие структур разработчик может определить собственный функции для работы с inod`ами. В ядре имеется бол-е кол--во функции.
Рассмотрит коротко struct file_system_type. Важная. Назначение она определяет тип ФС.
struct file_system_type
{
const char *name;
int fs_flags;
#define FS_REQUIRES_DEV 1
#define FS_BINARY_MOUNTDATA 2
...
struct dentry *(*mount)(struct file_system_type *, int, const char *, void *);
void (*kill_sb)(struct super_block*);
struct module *owner;
struct file_system_type * next;
struct hlist_head fs_super;
...
}
Для каждой Фс только одна структура file_system_type и линукс, так и unix, предоставляет возможность динамически добавлять и удалять ФС, для этого используется две функции:
extern int register_filesystem(struct file_system_type *);
extern int unregister_filesystem(struct file_system_type *);
ВАЖНО! Что передаем структуру созданную разработчиком.
Функция mount вызывается при монтировании ФС и если на нее посмотреть то видим, что монтируем ФС определенного типа, т.е конкретную ФС.
Функция kill_sb предназначена для того чтобы уничтожить созданный суперблок, освободить место, фактически отмонтировать ФС.
КОгда ФС монтируется создается структура struct_vfsmount. Которая представляет конкретный экземпляр ФС.
struct_vfsmount
{
struct dentry *mnt_root; // указатель на корневой каталог ФС
struct superblock *mnt_sb; // указатель на суперблок данной монтируемой ФС
int mnt_flags; // флаги монтирования.
} _ _randomize_logout;
Индексный дескриптор содержит информацию о файле, каждый файл имеет один inode но может иметь несколько имен, то есть жестких ссылок (hardlink).
Индексный дескриптор существует двух форматов в системе: дисковый inode и inode ядра. Очевидно что они описывают один и тот же файл, но инфа в inode ядра актуальна для ядра, для динамического обращения. Дисковый inode кроме информации о файле, о его типе, параметрах прав доступа, должен содержать информацию которая ПОЗВОЛЯЕТ АДРЕСОВАТЬ информацию, которая хранится в данном файле. В качестве примера рассмотрим как хранится информация о блоках в ФС EXT2. Есть указатель на inode operations но фактически это информация не несет информации как происходит адресация данных. Основная задача ФС долговременное хранение, а ГЛАВНОЕ доступ к этим данным.
Иллюстрация того как хранится информация о блоках в ФС EXT2 (классическая иллюстрация адресации очень больших файлов)
Для хранения данных записываемых в файл , или просто, выделено 15 полей по 4 байта, т.е inode содержит 15 блоков указателей, 12 из которых являются блоками прямой адресации. Прямая или как еще говорят непосредственная адресация. То есть в блоке указателе находится адрес блока данных. Прямая часто используется потому что на англ. direct. Direct block pointer.
Собственно 4к откуда берется это 1024 x 4 байта = 4096 байт = 4K. Соответственно 13 блок двойная косвенная адресация, 14 блок тройная косвенная адресация. Ну и можно посчитать размер соответствующего файла, а главное получить доступ. Когда мы сохраняем очень большие файлы, то доступ к информации в этих файлах увеличивается за счет косвенной адресации, это связанно с перемещением диска. Для того чтобы переместить диск и могла начаться операция чтения нужно чтобы этот диск стал определеным образом(как всегда предолжение не закончено). Существует в старых монографиях таких как Дейтел описание алгоритмов перемещения головок. Они перемещаются поступательным движением, диск вращается, а головки имеют поступательное движение. Ну как всё в технике, в конечном итоге находится наиболее оптимальный алгоритм и об этом перестают говорить.
Давайте посмотрим на структуру inode.
struct inode
{
umode_t i_mode; //права доступа
unsigned short i_opflags;
kuid_t i_uid;
kgid_t i_gid;
unsigned int i_flags;
...
const struct inode_operations *i_op; /* указатель на ту таблицу операций с индексом которые определены в конкретной системе для работы с этим индексом. Такая структура создаётся для конкретной файловой системы */
struct super_block *i_sb; /*указатель на связаный суперблок, так как именно он хранит информацию об inode данной файловой системы. */
struct address_space *i_mapping;
...
unsigned long i_ino;
union
{
const unsigned int i_nlink;
unsigned int _i_nlink;
};
dev_t i_rdev;
loff_t i_size;
struct timespec i_atime;
struct timespec i_mtime;
struct timespec i_ctime;
...
unsigned int i_blkbits;
...
blkcnt_t i_blocks;
...
struct hlist_node i_hash;
struct list_head i_io_list;
...
struct list_head i_lru; /*inode LRU list. LRU используется для inode. Если открыли файл, то очень вероятно что вы будете работать с этим файлом.*/
...
union{
struct hlist_head i_dentry;
struct rcu_head i_rcu;
};
...
atomic_t i_count; /* счётчик ссылок */
...
atomic_t i_writecount; /*счётчик исп-я для записи */
...
count struct file_operations *i_top;
struct address_space i_data;
struct list_head i_devices; /* список блочных устройств */
union
{
struct pipe_inode_info *i_pipe;
struct block_device *i_bdev;
struct cdev *i_cdev;
char *i_link;
unsigned i_dir_seq;
};
...
}
Прежде чем перейти к обсуждению полей, обратите внимание struct list_head. Это тенденция современная Linux объявлять типы для обозначения соответствующих полей.
struct list_head
{
struct list_head *next;
struct list_head *prev;
}
Часто используется и говорит что все ядро построено на двусвязных списков. Найдите структуру в man и распечатать.
Лекция 4
В ядре линукс существует ряд функций предназначеных для работы со связаными списками. Структура list_head описывает двухсвязный список. Эту структуру можно использовать в своём коде.
Цирюлик приводит такой пример.
struct todo_struct
{
struct list_head list;
int priority;
/* другие поля */
};
Структура list_head везде встречается в объявлении в ядре.
struct inode - очень большая структура, при этом не стоит забывать что существует inode дисковый и inode ядра. Мы исследуем ядренный inode и по названию приведенных полей видим их назначение.
Очень показательным полем является union который перечисляет фактически типы устройств: буфер, pipe, драйвер блочного устройства, драйвер символьного устройства, символьная ссылка link (массив ссылок так как указатель).
Обратить внимание на umode_t i_mode -права доступа, struct inode operations - указатель на ту таблицу операций с индексом которые определены в конкретной системе для работы с этим индексом. Такая структура создаётся для конкретной файловой системы.
struct super_block *i_sb - указатель на связаный суперблок, так как именно он хранит информацию об inode данной файловой системы. Суперблок создаётся когда файловая система монтируется и суперблок содержит информацию о смонтированной фс. Понятно, что файлы могут находиться в конкретной файловой системе. Файлв описываются struct inode. Struct inode - дескриптор файла и он должен содержать указатель на свой суперблок. Это так называемая связь структур, связь таблиц.Проще эту информацию рисовать в виде таблиц.