Шрифт:
Интервал:
Закладка:
Операции блочного ввода-вывода работают в каждый отдельный момент времени с одним дисковым блоком. Часто встречающаяся операция блочного ввода-вывода — это чтение и запись файловых индексов. Ядро предоставляет функцию bread(), которая выполняет низкоуровневое чтение одного блока с диска. С помощью буферов дисковые блоки отображаются на связанные с ними страницы памяти и благодаря этому сохраняются в страничном кэше.
Например, при первом открытии в текстовом редакторе дискового файла с исходным кодом, данные считываются с диска и записываются в память. При редактировании файла считывается вес больше данных в страницы памяти. Когда этот файл позже начинают компилировать, то ядро может считывать соответствующие страницы памяти из дискового кэша. Нет необходимости снова считывать данные с диска. Поскольку пользователи склонны к тому, чтобы периодически работать с одними и теми же файлами, страничный кэш уменьшает необходимость выполнения большого количества дисковых операций.
Страничный кэш
Как следует из названия, страничный кэш (page cache) — это кэш страниц; памяти. Соответствующие страницы памяти получаются в результате чтения и записи обычных файлов на файловых системах, специальных файлов блочных устройств и файлов, отображаемых в память. Таким образом, в страничном кэше содержатся страницы памяти, полностью заполненные данными из файлов, к которым только что производился доступ. Перед выполнением операции страничного ввода-вывода, как, например, read()[84], ядро проверяет, есть ли те данные, которые нужно считать, в страничном кэше. Если данные находятся в кэше, то ядро может быстро возвратить требуемую страницу памяти.
Объект address_space
Физическая страница памяти может содержать данные из нескольких несмежных физических дисковых блоков[85].
Проверка наличия определенных данных в страничном кэше может быть затруднена, если смежные блоки принадлежат совершенно разным страницам памяти. Невозможно проиндексировать данные в страничном кэше, используя только имя устройства и номер блока, что было бы наиболее простым решением.
Более того, страничный кэш ядра Linux является хранилищем данных достаточно общего характера в отношении того, какие страницы памяти в нем могут кэшироваться. Первоначально страничный кэш был предложен в операционной системе System V (SVR 4) для кэширования только данных из файловых систем. Следовательно, для управления страничным кэшем операционной системы SVR 4 использовался эквивалент файлового объекта, который назывался struct vnode. Кэш операционной системы Linux разрабатывался с целью кэширования любых объектов, основанных на страницах памяти, что включает множество типов файлов и отображений в память.
Для получения необходимой общности в страничном кэше операционной системы Linux используется структура address_space (адресное пространство), которая позволяет идентифицировать страницы памяти, находящиеся в кэше. Эта структура определена в файле <linux/fs.h> следующим образом.
struct address_space {
struct inode *host; /* файловый индекс, которому
принадлежит объект */
struct radix_tree_root page_tree; /* базисное дерево
всех страниц */
spinlock_t tree_lock; /* блокировка для защиты
поля page_tree */
unsigned int i_mmap_wrltable; /* количество областей
памяти с флагом VM_SHARED */
struct prio_tree_root i_mmap; /* список всех отображений */
struct list_head i_mmap_nonlinear; /* список областей
памяти с флагом VM_NONLINEAR */
spinlock_t i_mmap_lock; /* блокировка поля i_mmap */
atomic_t truncate_count; /* счетчик запросов
truncate */
unsigned long nrpages; /* общее количество страниц */
pgoff_t writeback_index; /* смещения начала
обратной записи */
struct address_space_operations *a_ops; /* таблица операций */
unsigned long flags; /* маска gfp_mask
и флаги ошибок */
struct backing_dev_info *backing_dev_info; /* информация
упреждающего чтения */
spinlock_t private_lock; /* блокировка
для частных отображений */
struct list_head private_list; /* список
частных отображений */
struct address_spacs *assoc_mapping; /* соответствующие
буферы */
};
Поле i_mmap — это дерево поиска по приоритетам для всех совместно используемых и частных отображений. Дерево поиска по приоритетам— это хитрая смесь базисных и частично упорядоченных бинарных деревьев[86].
Всего в адресном пространстве nrpages страниц памяти.
Объект address_space связан с некоторым другим объектом ядра, обычно с файловым индексом. Если это так, то поле host указывает на соответствующий файловый индекс. Если значение поля host равно NULL, то соответствующий объект не является файловым индексом; например, объект address_space может быть связан с процессом подкачки страниц (swapper).
Поле a_ops указывает на таблицу операций с адресным пространством так же, как и в случае объектов подсистемы VFS. Таблица операций представлена с помощью структуры struct address_space_operations, которая определена в файле <linux/fs.h> следующим образом.
struct address_space_operations {
int (*writepage)(struct page*, struct writeback_control*);
int (*readpage)(struct file*, struct page*);
int (*sync_page)(struct page*);
int (*writepages)(struct address_space*,
struct writeback_control*);
int (*set_page_dirty)(struct page*);
int (*readpages)(struct file*, struct address_space*,
struct list_head*, unsigned);
int (*prepare_write)(struct file*, struct page*,
unsigned, unsigned);
int (*commit_write)(struct file*, struct page*,
unsigned, unsigned);
sector_t (*bmap)(struct address_space*, sector_t);
int (*invalidatepage)(struct page*, unsigned long);
int (*releasepage)(struct page*, int);
int (*direct_IO)(int, struct kiocb*, const struct iovec*,
loff_t, unsigned long);
};
Методы read_page и write_page являются наиболее важными. Рассмотрим шаги, которые выполняются при страничной операции чтения.
Методу чтения в качестве параметров передается пара значений: объект address_space и смещение. Эти значения используются следующим образом для поиска необходимых данных в страничном кэше.
page = find_get_page(mapping, index);
где параметр mapping — это заданное адресное пространство, a index — заданная позиция в файле.
Если в кэше нет необходимой страницы памяти, то новая страница памяти выделяется и добавляется в кэш следующим образом.
struct page *cached_page;
int error;
cached_page = page_cache_alloc_cold(mapping);
if (!cached_page)
/* ошибка выделения памяти */
error =
add_to_page_cache_lru(cached_page, mapping, index, GFP_KERNEL);
if (error)
/* ошибка добавления страницы памяти в страничный кэш */
Наконец, необходимые данные могут быть считаны с диска, добавлены в страничный кэш и возвращены пользователю. Это делается следующим образом.
error = mapping->a_ops->readpage(file, page);
Операции записи несколько отличаются. Для отображаемых в память файлов при изменении страницы памяти система управления виртуальной памятью просто вызывает следующую функцию.
SetPageDirty(page);
Ядро выполняет запись этой страницы памяти позже с помощью вызова метода writepage(). Операции записи для файлов, открытых обычным образом (без отображения в память), выполняются более сложным путем. В основном, общая операция записи, которая реализована в файле mm/filemap.с, включает следующие шаги.
page =
__grab_cache_page(mapping, index, &cached_page, &lru_pvec);
status =
a_ops->prepare_write(file, page, offset, offset+bytes);
page_fault =
filemap_copy_from_user(page, offset, buf, bytes);
status =
a_ops->commit_write(file, page, offset, offset+bytes);
- QT 4: программирование GUI на С++ - Жасмин Бланшет - Программирование
- C# для профессионалов. Том II - Симон Робинсон - Программирование
- Как спроектировать современный сайт - Чои Вин - Программирование
- Каждому проекту своя методология - Алистэр Коуберн - Программирование
- Программируем Arduino. Основы работы со скетчами - Монк Саймон - Программирование
- Творческий отбор. Как создавались лучшие продукты Apple во времена Стива Джобса - Кен Косиенда - Прочая околокомпьтерная литература / Интернет / Программирование
- Гибкое управление проектами и продуктами - Борис Вольфсон - Программирование
- Сделай видеоигру один и не свихнись - Слава Грис - Программирование / Руководства
- Программирование игр и головоломок - Жак Арсак - Программирование
- Как почистить сканы книг и сделать книгу - IvanStorogev? KpNemo - Программирование