Строка 475
Подсистема VFS зависит от кешей памяти, называемых SLAB-кешами, хранящими структуры, которыми эта подсистема управляет. Гл. 4 подробно описывает SLAB-кеши. Функция vf s_caches_init () инициализирует используемые системой кеши SLAB. На рис. 8.17 показан обзор иерархии вызовов из vf s_cache_init■(). Мы подробно рассмотрим каждую функцию из этой иерархии вызовов. Вы можете сверяться с этой иерархией по мере того, как мы будем рассматривать входящие в нее функции.
В табл. 8.4 подводится итог представляемых vf s_caches_in.it () или вызываемыми из нее функциями новых функций.
fs/dcache.c
1624 1625 1626 1627 1628 1629 1630 1631
2632
2433
1623 void init vfs_caches_init(unsigned long mempages)
{
names_cachep = kmem_cache_create("names_cache", PATH_MAX, 0,
SLAB_HWCACHE_ALIGN, NULL, NULL); if (Jnames_cachep)
panic("Cannot create names SLAB cache");
filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0,
SLAB_HWCACHE_ALIGN, filp_ctor, filp_dtor);
1634 if(!filp_cachep)
1635 panic("Cannot create filp SLAB cache"
1636
1637 dcache_init(mempages) ;
1638 inode_init(merapages);
1639 files_init(mempages);
1640 mnt_init(mempages);
1641 bdev_cache_init();
1642 chrdev_init();
1643 }
Строка 1623
Функция получает глобальную переменную num_physpages [значение которой вычисляется во время mem_init () ] в качестве параметра, хранящего число доступных физических страниц, в системной памяти. Это число влияет на создание кеша SLAB, как будет описано позже.
Строки 1625-1629
Следующим шагом является создание области памяти names_cachep. В гл. 4 подробно описана функция kmem_cache_create (). Эта область памяти хранит объекты размера РАТН_МАХ, т. е. максимально доступной длины пути в символах. (Значение устанавливается в linux/limits . h в значение 4096.) В этой точке кеш создан как пустой объект или область памяти размера РАТН_МАХ. Настоящая область памяти выделяется во время первой потенциальной последовательности вызовов к getname ().
Как сказано в гл. 6, функция getname () вызывается в начале того же связанного с файлом системного вызова [в нашем примере sys_open () ] для чтения имени файла из адресного пространства процесса. Объекты освобождаются из кеша с помощью функции putname ().
Если names_cache не может быть создан, ядро переходит к функции паники и забирает управление у потока функции.
Строки 1631-1635
Далее создается f ilp_cache с объектами размером со структуру файла. Объект, хранящий структуру файла, выделяется с помощью функции get_empty_f ilp () (f s/f ile_table. с), вызываемой, например, при создании канала или открытии файла. Объект описателя файла освобождается с помощью вызова file_free() (fs/file_table.c).
Строка 1637
Функция dcache_init()(fs/dcache.c) создает кеш SLAB, хранящий пустой описатель1. Сам кеш называется dentry_cache. Сам описатель dentry создается
для каждого иерархического компонента в пути файла, запрошенном процессом при доступе к файлу или директории. Структура связывает компонент директории с представляющей ее inode для дальнейшего ускорения доступа к компоненту через соответствующий inode.
Строка 1638
Функция inode_init () (f s/inode. с) инициализирует хеш-таблицу inode и голову массива очереди ожидания, используемую для хранения хешированных inode, которые хочет заблокировать ядро. Голова очереди ожидания (wait_queue_head_t) для хешируемых inode хранится в массиве, называемом i_wait_queue_head. Этот массив инициализируется в данной точке процесса запуска системы.
В данной точке создается inode_hashtable. Эта таблица ускоряет поиск inode. Последним происходит кеширование SLAB, используемое для хранения созданных объектов inode. Она называется inode_cache. Область памяти для этого кеша выделяется при вызове alloc_inode (f s/inode. с) и освобождается при вызове destroy_inode () (f s/inode. с).
Строка 1639
Функция files_init() вызывается для определения максимального количества памяти, разрешенной для файлов на один процесс. Устанавливается поле max_f iles структуры f iles_stat. Далее она используется при создании файла для определения того, достаточно ли памяти для открытия файла. Давайте рассмотрим эту функцию.
fs/file_table.с
292 void init files_init(unsigned long mempages)
293 {
294 int n;
299 n = (mempages * (PAGE_SIZE / 1024)) / 10;
3 00 files_stat.max_files = n;
3 01 if (files_stat.max_files < NR_FILE)
302 files_stat.max_files = NR_FILE;
303 }
Строка 299
Размер страницы делится на количество пространства (вместе со связанными inode и кешем), которое займет файл (в данном случае 1 Кб). Это значение умножается на количество страниц для получения общего количества «блоков», которые можно использовать для файлов. Деление на 10 дает значение предела использования памяти для файлов, при котором они будут занимать не более 10 % доступной памяти.
Строки 301-302
NR_FILE (include/linux/f s. h) устанавливается в 8192.
Строка 1640
Следующая функция, mnt_init (), создает кеш, хранящий объекты vf smount, используемые VFS для монтирования файловых систем. Кеш называется mnt_cache. Также функция создает массив mount__hachtable, хранящий ссылки на объекты в mnt_cache для быстрого доступа. Далее выполняются вызовы для инициализации файловой системы sysf s и монтирования файловой системы root. Давайте рассмотрим подробнее создание таблицы хеширования.
1139 struct list_head *d;
1140 unsigned long order;
1141 unsigned int nr_hash;
1142 int i;
1149 order = 0;
1150 mount_hashtable = (struct list_head *)
1151 get_free_pages(GFP_ATOMIC, order);
1152
1153 if (!mount_hashtable)
1154 panic("Failed to allocate mount hash table\n");
1161 nr_hash = (1UL « order) * PAGE_SIZE / sizeof(struct list_head);
1162 hash_bits = 0;
1163 do {
1164 hash_bits++;
1165 } while ((nr_hash » hash_bits) != 0);
1166 hash_bits—;
1172 nr_hash = 1UL << hash_bits;
1173 hash_mask = nr_hash-l; 1174
1175 printk("Mount-cache hash table entries: %d (order: %ld,
%ld bytes)\n", nr_hash, order, (PAGE_SIZE « order));
1179 d = mount_hashtable;
Строки 1139-1144
Массив хеш-таблицы состоит из полной страницы памяти. Гл. 4 подробно описыва-
ет работу этой функции де^£гее_радез (). Самое главное в том, что эта
функция возвращает указатель на область памяти в размере страниц второго порядка. В этом случае мы выделяем одну страницу для хранения таблицы хеша.
Строки 1161-1173
Следующим шагом является определение количества вхождений в таблице; пг_пазп настраивается для хранения номера порядка (степень двойки) головы списка, который помещается в таблицу, пазп_Ьл^Б вычисляется как количество необходимых для представления наибольшей степени двойки пг_пазп битов. Строка 1172 переопределяется пг_пазп, чтобы она состояла из одного левого бита. Далее битовая маска пересчитывается на основе нового значения пг_пазп.
Строки 1179-1185
Наконец, мы инициализируем хеш-таблицу с помощью вызова макроса Ш1Т_1ЯЗТ_НЕАП, получающего указатель на область памяти, в которой инициализируется новая голова списка. Мы проделываем это пг_пазп раз (по количеству элементов, которые может хранить таблица).
Давайте рассмотрим пример. Мы предполагаем, что РАСЕ_31гЕ равна 4 Кб и Нзг^пеас! равна 8 байтам. Из-за того что порядок равен 0, значение пг_пазп становится равным 500; поэтому в таблицу 4 Кб может входить до 500 элементов; (1иь«огбег) становится количество выделенных страниц. Например, если порядок равен 1 (что значит, что мы запрашиваем 21 страницу в хеш-таблице), сдвинутый влево бит 00000001 становится равным 00000010 (или 2 в двоичной системе счисления). Далее мы рассчитываем количество битов, необходимых хеш-коду. Проследив каждую итерацию цикла, мы получим следующее.
Начальные значения пазп_Ь:1^з = 0 и пг_Ь.аэЬ = 500.
• Итерация 1: пазп_ЫЬз = 1, и (500 » 1)! = 0 (000111110100» 1) = 000011111010
• Итерация 2: пазп_Ыts = 2, и (500 » 2)! = 0
237 int init init_rootfs(void)
238 {
239 return register_filesystem(&rootfs_fs_type);
240 }
Файловая система rootf s - это первая монтируемая ядром файловая система. Это простая пустая директория, которая перемонтируется реальной файловой системой на более поздних этапах загрузки ядра.
Строки 218-222
Этот блок кода объявляет структуру rootf s_fs_type f ile_system_type. Для получения и удаления связанных суперблоков определяются только два метода.
Строки 237-240
Функция init rootf s () просто регистрирует rootf s в ядре. Таким образом,
вся связанная с типом файловой системы информация становится доступной (ин-формациия хранится в структуре f ile_system_type) внутри ядра.
Итерация 9: hash_bits = 9, и (500 » 9)! = 0 (000111111010 » 3) = 000000000000
После остановки цикла while функция hash_bits декрементируется до 8, nr_hash устанавливается в 000100000000 и hash_mask устанавливается в 000011111111.
После того как функция mnt_init () инициализирует mount_hashtable и создает mnt_cache, она выполняет три вызова:
fs/namespace.с
1189 sysfs_init();
1190 init_rootfs();
1191 init_mount_tree();
1192 }
вуз1 s_in.it () отвечает за создании файловой системы зуз:Ев; 1п±Ь_±ооЬйз () и 1п1ь_тоипЪ_1;гее () вместе отвечают за монтирование корневой файловой системы. Мы подробно рассмотрим каждый шаг этих функций.
fs/ramfs/inode.с
218 static struct file_system_type rootfs_fs_type = С
219 .name = "rootfs",
220 .get_sb = rootfs_get_sb,
221 .kill_sb = kill_litter_super,
Итерация 9: hash_bits = 9, и (500 » 9)! = 0 (000111111010 » 3) = 000000000000
После остановки цикла while функция hash_bits декрементируется до 8, nr_hash устанавливается в 000100000000 и hash_mask устанавливается в 000011111111.
После того как функция mnt_init () инициализирует mount_hashtable и создает mnt_cache, она выполняет три вызова:
fs/namespace.с
1189 sysfs_init();
1190 init_rootfs();
1191 init_mount_tree();
1192 }
вуз1 s_in.it () отвечает за создании файловой системы зуз:Ев; 1п±Ь_±ооЬйз () и 1п1ь_тоипЪ_1;гее () вместе отвечают за монтирование корневой файловой системы. Мы подробно рассмотрим каждый шаг этих функций.
fs/ramfs/inode.с
218 static struct file_system_type rootfs_fs_type = С
219 .name = "rootfs",
220 .get_sb = rootfs_get_sb,
221 .kill_sb = kill_litter_super,
namespace), GFP_KERNEL) if (!namespace)
panic("Can't allocate initial namespace"); atomic_set(&namespace->count, 1); INIT_LIST_HEAD(&namespace->list); init_rwsem(&namespace->sem); list_add(&mnt->mnt_list, &namespace->list); namespace->root = mnt;
init_task.namespace = namespace; read_lock(&tasklist_lock); do_each_thread(g, p) { get_namespace(namespace);
Строки 1116-1123
Инициализация пространства имен процесса. Эта структура хранит указатели на смонтированные древовидные структуры и соответствующие dentry. Выделяется объект namespace, счетчик устанавливается в 1, инициализируется список полей типа list_head, инициализируются семафоры, блокирующие пространство имен (и дерево монтирования), а поле root, соответствующее структуре vf smount, устанавливается таким образом, чтобы указывать на новые выделенные vf smount.
Строка 1125
Поле namespace описателя процесса текущей задачи (задача init) устанавливается так, чтобы указывать на только что выделенный и инициализированный объект пространства имен. (Текущим процессом является процесс 0.)
Строки 1134-1135
Следующие две функции устанавливают значения четырех полей в f s_struct, связанной с нашим процессом; f s_struct, хранящая поле для корня, и элементы текущей рабочей директории устанавливаются следующими двумя функциями.
Мы только что закончили рассмотрение того, что происходит в функции mnt_init. Давайте продолжим рассмотрение vfs_mnt_init.
1641 bdev_cache_init() fs/block_dev.с
290 void init bdev_cache_init(void)
291 {
292 int err;
293 bdev_cachep = kmem_cache_create("bdev_cache",
294 sizeof(struct bdev_inode) ,
295 0,
296 SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
297 init_once,
298 NULL);
299 if (!bdev_cachep)
300 panic("Cannot create bdev_cache SLAB cache");
301 err = register_filesystem(&bd_type) ;
302 if (err)
303 panic("Cannot register bdev pseudo-fs");
304 bd_mnt = kern_mount (&bd_type) ,-
305 err = PTR_ERR(bd_mnt);
306 if (IS_ERR(bd_mnt))
307 panic("Cannot create bdev pseudo-fs");
294 static struct file_system_type bd_type = {
295 .name = "bdev",
296 .get_sb = bd_get_sb,
297 .kill_sb = kill_anon_super,
298 };
Как вы можете видеть, структура file_system специальной файловой системы bdev имеет только две определенные функции: одну для выборки суперблоков файловой системы и другую для удаления-освобождения суперблока. В этой точке может удивить, почему блочное устройство регистрируется как файловая система. В гл. 6 мы видели, что системы, не являющиеся технически файловыми системами, могут использовать структуры файловой системы ядра; поэтому они не имеют точек монтирования, но могут использовать структуры VFS ядра для поддержки файловых систем. Блочные устройства являются одним из видов псевдофайловых систем, которые используют структуры файловой системы VFS ядра. В случае bdev эти структуры представляют собой ограниченный набор полей, так как не все из них имеют смысл для отдельных приложений.
Строки 304-308
Вызов kern_mount () устанавливает все связанные с монтированием VFS-структуры и возвращает структуру vf smount. (См. подробное описание глобальной переменной bd_mnt, указывающей на структуру vfsmount, и blockdev_superblock, указывающей на суперблок vfsmount, в гл. 6.)
Эта функция инициализирует объекты символьного устройства, которые описывают модель драйвера:
f s /char_dev.с
void init chrdev_init(void)
{
433 subsystem_init(&cdev_subsys);
434 cdev_map = kobj_map_init(base_probe, &cdev_subsys);
435 }