Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Торым операционная система хранит часть информации с жесткого диска в памяти для быстрого доступа. Теперь мы рассмотрим, как он работает и реализуется.
Когда вы выполняете запись в файл на жестком диске, файл разбивается на порции, называемые страницами, которые отображаются в оперативную память. Операционная система обновляет страницы в памяти, и немного позднее страницы записываются на диск. Если страница копируется с жесткого диска в память (это называется подкачкой или свопингом), она становится чистой или неочищенной. Неочищенная страница изменяется в памяти, но изменения на диск не записываются. Чистая страница существует в памяти в том же состоянии, что и на диске. В Linux память разделяется на зоны1. Каждая зона имеет список активных и неактивных страниц. Когда страница является неактивной на протяжении некоторого времени, она свопируется (записывается обратно на диск) в свободную память. Каждая страница в списке зон имеет указатель на address__space. Каждая address_space имеет указатель на структуру address_space__operations. Страницы помечаются как неочищенные с помощью вызова функции set_dirty__page () структуры address_ space_operation. Рис. 6.12 иллюстрирует эту зависимость. Зона ( Активные страницы V (неактивныв страницы V- Страница ( addr j Страница ( addr )
Адресное пространство addr_space_ops Операции адресного пространства seLdirty_page() Рис. 6.12. Кеш страниц и зоны 1 См. подробности в гл. 4. 6.4 Кеш страниц 6.4.1 Структура address_space Ядром кеша страниц является объект address_space. Рассмотрим его поближе. include/linux/fs.h 32 6 struct address_space { 327 struct inode *host; ./* владелец: inode, block_device */ 328 struct radix_tree_root page_tree; /* корневое дерево для всех страниц*/ 329 spinlock_t tree_lock; /* и защищающие его циклические блокировки */ 33 0 unsigned long nrpages; /* общее количество страниц */ 331 pgoff_t writeback__index; /* отсюда начинается обратная запись */ 332 struct address_space_operations *a_ops; /* методы */ 333 struct prio_tree_root i_mmap; /* дерево частного отображения в память */ 334 unsigned int i_mmap_writable; /* счетчик отображения VM_SHARED */ VM_NONLINEAR */ 33 6 spinlock_t i_mmap_lock; /* защищенное дерево, счетчик, список */ 337 atomic__t truncate_count; /* исключает появление соревновательных состояний */ 338 unsigned long flags; /* биты ошибки/маска gfp */ чтение с устройства и т. д. */ 340 spinlock_t private_lock; /* для нужд address_space */ 341 struct list_head private_list; /* то же */ 342 struct address__space *assoc_mapping; /* то же */ 343 }; Комментарии к коду структуры достаточно информативны. Некоторые дополнительные пояснения позволят понять работу операций кеша страниц. Обычно address_space связан с inode и поле host указывает на этот inode. Тем не менее для выполнения основного назначения кеша страниц и структуры адресного пространства это поле необязательно. Оно может быть NULL, если address_space связан с объектом ядра, не являющимся inode. Структура address__space имеет поле, которое уже должно быть вам знакомо: address_space_operations. Как и структура файла f ile_operations, address_space_operations содержит информацию об операциях, корректных для address_space. include/linux/fs.h 297 struct address_space_operations { Глава 6 • Файловые системы 298 int (*writepage)(struct page *page, struct writeback_control *wbc); 299 int (*readpage)(struct file *, struct page *); 300 int (*sync_page)(struct page *); 301 3 02 /* Запись обратно некоторых грязных страниц, отображенных в память */ 3 03 int (*writepages) (struct address__space *, struct writeback_control *); 304 3 05 /* Установка страницы в грязное состояние */ 3 06 int (*set_page_dirty)(struct page *page); 3 08 int (*readpages)(struct file *filp, struct address__space *mapping, 309 struct list_head *pages, unsigned nr_pages); 311 /* 312 * ext3 требует, чтобы за удачным вызовом prepare_write() следовал 313 * вызов commit_write()- он должен быть сбалансирован 314 */ 315 int (*prepare_write)(struct file *, struct page *, unsigned, unsigned); 316 int (*commit__write)(struct file *, struct page *, unsigned, unsigned); 317 /* Этот ляп нужен только для FIBMAP. Не используйте его */ 318 sector_t (*bmap)(struct address_space *, sector_t); 319 int (*invalidatepage) (struct page *, unsigned long); 320 int (*releasepage) (struct page *, int); 321 ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov, 322 loff_t offset, unsigned long nr_segs); 323 }; Эти функции достаточно понятны: readpage () и wri tepage () читают и записывают страницы, связанные с адресным пространством соответственно. Несколько страниц можно прочитать и записать с помощью readpages () и writepages (). Журналируе-мые файловые системы, такие, как ext3, могут предоставлять функции для prepare., write () и commit_write (). Когда ядро проверяет кеш страниц для некоторой страницы, проверка должна выполняться быстро. Поэтому каждое адресное пространство имеет radix_tree, выполняющий быстрый поиск для определения того, находится ли страница в кеше страниц или нет. Рис. 6.13 иллюстрирует, как файлы, inode, адресные пространства и страницы связаны друг с другом; этот рисунок полезен для анализа кода кеша страниц. Кеш страниц
Рис. 6. 13. Файлы, inode, адресные пространства и страницы Структура bufferjiead Каждый сектор блочного устройства представляется в ядре Linux с помощью структуры buf fer_head, которая хранит всю информацию, необходимую для отображения физического сектора в памяти в физическую оперативную память. Структура buf f er_head изображена на рис. 6.14. include/linux/buffer_head.h 47 struct buffer_head { 48 /* Первая строка кеша: */ 49 unsigned long b__state; /* битовая карта состояния буфера (см. ниже) */ 50 atomic_t b_count; /* пользователи употребляют этот блок */ 51 struct buffer_head *b_this_page; /* циклический список буферов страниц */ 52 struct page *b_page; /* страница, куда отображается данный заголовок буфера */ 53 54 sector_t b_blocknr; /* номер блока */ 55 u32 b_size; /* размер блока */ Глава 6 • Файловые системы
Рис. 6.14. Структура bufferjiead 56 char *b_data; /* указатель на блок данных */ 57 58 struct block_device *b_bdev; 59 bh_end_io_t *b_end_io; /* завершение ввода-вывода */ 60 void *b_private; /* зарезервировано для b_end_io */ 61 struct list_head b_assoc_buffers; /* связь с другим отображением в память */ 62 }; Физический сектор, к которому относится структура buf f er_head, - это логический блок b_blocknr устройства b_dev. Физическая память, к которой обращается структура buf f er_head, - это блок памяти, начинающийся в b_data длиной b_size байт. Блок памяти находится в физической странице b_page. Другое определение структуры buf f er_head применяется для использования задачи управления тем, какие физические секторы отображаются в физическую память. (Так как это отступление касается структуры bio, а не buf fer_head, обратитесь к mpage. с для получения более подробной информации о структуре buf f er_head.) Как упоминалось в гл. 4, каждая страница физической памяти в ядре Linux представляется структурой страницы. Страница состоит из нескольких блоков ввода-вывода. Так как каждый блок ввода-вывода не может быть больше страницы (хотя и может быть меньше), страница состоит из одного или более блоков ввода-вывода. В старых версиях Linux блоки ввода-вывода выполнялись только с помощью буферов, но в версии 2.6 разработан новый способ, использующий структуру bio. Новый способ позволяет ядру Linux группировать блоки ввода-вывода вместе более управляемым способом. Представьте, что мы записываем порцию данных в начало текстового файла и в его конец. Это обновление требует двух структур buf fer_head для передачи данных: Кеш страниц одной, указывающей на начало, и одной, указывающей на конец. Структура bio позволяет файловой операции группировать отдельные порции вместе в единую структуру. Это альтернативный способ рассмотрения буферов и страниц в виде последовательности сегментов буфера. Структура bio_vec представляет последовательность сегментов в буфере. Структура bio_vec изображена на рис. 6.15.
Рис. 6.15. Структура bio include/linux/biо.h 47 struct bio_vec { 48 struct page *bv__page; 49 unsigned int bv_len; 50 unsigned int bv_offset; 51 }; Структура bio__vec хранит указатель на страницу, длину сегмента и отступ сегмента в страницу. Структура bio состоит из массива структур bio_vec (вместе с другими полями). Поэтому структура bio представляет собой количество последовательных сегментов памяти из одного или нескольких буферов на одной или нескольких страницах1. 1 См. более подробную информацию о структуре bio в файле include/linux/bio.h. Глава 6 • Файловые системы 6.5 Системные вызовы VFS и слой файловой системы До этой точки мы рассмотрели все структуры, связанные с VFS и кешем страниц. Теперь мы сфокусируемся на двух системных вызовах, используемых для работы с файлами, и отследим их выполнение до уровня ядра. Мы увидим, что системные вызовы open (), close(), read () и write () используют ранее описанные структуры. Мы упоминали, что в VFS файлы трактуются абстрактно. Вы можете открывать, читать, записывать и закрывать файлы, а то, что происходит на физическом уровне, слой VFS не волнует. Эта специфика отражена в гл. 5. В VFS интегрирован специфичный для файловой системы слой, преобразующий файловый ввод-вывод VFS в страницы и блоки. Так как на компьютере может присутствовать несколько типов файловых систем, таких, как отформатированный в ext2 жесткий диск niso9660 cdroni, слой файловой системы делится на два основных раздела: обобщенные и специфические операции файловой системы (см. рис. 6.3). Следуя методу рассмотрения сверху вниз, этот раздел отслеживает запросы на чтение и запись начиная с вызовов VFS read () или write () через слой файловой системы до специфических блочных запросов ввода-вывода, обрабатываемых драйвером блочного устройства. В нашем путешествии мы перейдем от обобщенной файловой системы к специфическому слою файловой системы. В качестве примера специфического слоя файловой системы мы будем использовать драйвер файловой системы ext2. При этом имейте в виду, что в зависимости от файла, к которому происходит обращение, могут быть использованы драйверы различных файловых систем. Далее мы встретимся с кешем страниц, встроенным в Linux и располагающемся в слое обобщенной файловой системы. В старых версиях Linux буфер кеша и кеш страниц присутствовали, тогда как в версии 2.6 кеш страниц взял на себя всю функциональность буфера кеша. 6.5.1 ореп() Когда процесс желает работать с содержимым файла, он использует системный вызов open(): Синтаксис #include < sys/types.h> #include < sys/stat.h> #include < fcntl.h> int open(const char *pathname/ int flags); int open(const char *pathname/ int flags, mode__t mode); int creat(const char *pathname/ xnode_t mode); Системный вызов open получает в качестве аргументов путь к файлу, флаги для обозначения режима доступа к открываемому файлу и битовую маска разрешений (если файл Популярное:
|
Последнее изменение этой страницы: 2016-03-25; Просмотров: 758; Нарушение авторского права страницы