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.

Индексный дескриптор содержит информацию о файле, каждый файл имеет один inode но может иметь несколько имен, то есть жестких ссылок (hardlink).
Индексный дескриптор существует двух форматов в системе: дисковый inode и inode ядра. Очевидно что они описывают один и тот же файл, но инфа в inode ядра актуальна для ядра, для динамического обращения. Дисковый inode кроме информации о файле, о его типе, параметрах прав доступа, должен содержать информацию которая ПОЗВОЛЯЕТ АДРЕСОВАТЬ информацию, которая хранится в данном файле. В качестве примера рассмотрим как хранится информация о блоках в ФС EXT2. Есть указатель на inode operations но фактически это информация не несет информации как происходит адресация данных. Основная задача ФС долговременное хранение, а ГЛАВНОЕ доступ к этим данным.

Иллюстрация того как хранится информация о блоках в ФС EXT2 (классическая иллюстрация адресации очень больших файлов)

Для хранения данных записываемых в файл , или просто, выделено 15 полей по 4 байта, т.е inode содержит 15 блоков указателей, 12 из которых являются блоками прямой адресации. Прямая или как еще говорят непосредственная адресация. То есть в блоке указателе находится адрес блока данных. Прямая часто используется потому что на англ. direct. Direct block pointer.

image image

Собственно 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 - дескриптор файла и он должен содержать указатель на свой суперблок. Это так называемая связь структур, связь таблиц.Проще эту информацию рисовать в виде таблиц.

⚠️ **GitHub.com Fallback** ⚠️