Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Торым операционная система хранит часть информации с жесткого диска в памяти для быстрого доступа. Теперь мы рассмотрим, как он работает и реализуется.



Когда вы выполняете запись в файл на жестком диске, файл разбивается на порции, называемые страницами, которые отображаются в оперативную память. Операционная система обновляет страницы в памяти, и немного позднее страницы записываются на диск.

Если страница копируется с жесткого диска в память (это называется подкачкой или свопингом), она становится чистой или неочищенной. Неочищенная страница изменяется в памяти, но изменения на диск не записываются. Чистая страница существует в памяти в том же состоянии, что и на диске.

В 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 */
33 5 struct list_head i_mmap_nonlinear; /*список отображения

VM_NONLINEAR */ 33 6 spinlock_t i_mmap_lock; /* защищенное дерево, счетчик, список */

337 atomic__t truncate_count; /* исключает появление

соревновательных состояний */

338 unsigned long flags; /* биты ошибки/маска gfp */
33 9 struct backing__dev_info *backing_dev_info; /* предварительное

чтение с устройства и т. д. */

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);
307

3 08 int (*readpages)(struct file *filp,

struct address__space *mapping,

309 struct list_head *pages, unsigned nr_pages);
310

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, адресные пространства и страницы связа­ны друг с другом; этот рисунок полезен для анализа кода кеша страниц.


Кеш страниц



 


 
 

 

 

 

 

 

 

  struct file    
*mapping  
   
   

 

 

 

 

 

  struct address.space  
  *host  
 
     
  *page_tree  
 
     
  *a_ops  
L.   J

 

  struct address_space_operations  
  writepage()  
     
  readpage()  
     
  set_page_dirty()  
    j

 

  struct radixjree  
  struct page  
     
  struct page  
     
  struct page  
    j

Рис. 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 • Файловые системы


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

         
    struct bufferjiead      
  *b_bdev   struct block.device  
   
         
  *b_page   struct page  
   
         
  b_size    
     
  b_data  
  L          

Рис. 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.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  struct bio            
*bi_next   ...................... struct bio  
   
       
*bi_bdev   struct block_device  
   
       
*biJo_vec     struct bio_vec  
               
    ------------------------- ■ -..................... — ■ ■ ■ -—■ *bv__page   ------ > struct page
           
             
  1—►   bvjen    
       
    bv_offset  
  ^    

Рис. 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; Просмотров: 705; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.06 с.)
Главная | Случайная страница | Обратная связь