Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Описатель кеша общего назначения
Как было сказано ранее, кеши всегда хранят объекты предопределенного размера общего назначения в виде пар. Один кеш - для выделения объектов из зоны DMA, другой - для стандартного выделения из обычной памяти. Если вы вспомните, что такое зоны памяти, вы поймете, что DMA-кеши размещаются в ZONE_DMA, а стандартные - в ZONE_ NORMAL. Структура cache_sizes является удобным средством для хранения всей связанной с размерами кешей информации. include/linux/slab.h 69 struct cache_sizes { 70 size_t cs_size; 71 kmem_cache_t *cs_cachep; 72 kmem_cache_t *cs_dmacachep; 73 }; 4.4.2.1 cs_size Поле cs_size хранит размер объекта памяти, находящегося в кеше. Глава 4 • Управление памятью 4.4.2.2 cs_cachep Поле cs__cachep хранит указатель на описатель кеша обычной памяти, выделяемых из ZONE_NORMAL. 4.4.2.3 cs_dmacachep Поле cs_dmacachep хранит указатель на описатель кеша обычной памяти, выделяемых ИЗ ZONE_NORMAL. На ум приходит вопрос: «Где хранятся описатели кешей? » Выделитель секций обладает специально зарезервированным для этого кешем. Кеш cache_cache хранит объекты типа описателя кеша. Кеш секции инициализируется статически при загрузке системы, для того чтобы можно было быть уверенным, что место для описателей кеша есть. Описатель секции Каждая секция в кеше имеет описатель, хранящий связанную с этой секцией информацию. Необходимо заметить, что описатель кеша хранится в специальном кеше, называемом cache__cache. Описатель секции, в свою очередь, хранится в двух местах: внутри самой секции (точнее говоря, фрейм первой страницы) или снаружи, в первом кеше общего назначения, в объекте достаточного размера для хранения описателя секции. Он заполняется при создании кеша на основе оставшегося после объекта размещения. Это пространство определяется при создании кеша. Давайте рассмотрим несколько полей описателя секции. mm/slab.с 173 struct slab { 174 struct list_head list; 175 unsigned long coloroff; 176 void *s__mem; /* включает цветовой отступ */ 177 unsigned int inuse; /* количество активных объектов в секции */ 178 kmem_bufctl_t free; 179 }; List Как вы помните из обсуждения описателя кеша, секция может находиться в одном из трех состояний: free, partial или full. Описатель кеша хранит описатель секции в трех списках - по одному для каждого состояния. Все секции в определенном состоянии хранятся в двусвязном списке в зависимости от значения поля list. Sjnem Поле s_mem хранит указатель на первый объект в секции. Выделение секций Inuse Значение inuse отслеживает количество занятых в секции объектов. Для полностью или частично заполненных секций это число положительное, а для свободных секций равно 0. Free Поле free хранит значение индекса для массива, элементы которого представляют объекты секции. В частности, поле free хранит значение индекса элемента массива, представляющего первый доступный объект в секции. Тип данных kmem_buf ctl_t связывает все объекты внутри секции. Этот тип является просто беззнаковым целым и определен в include /asm/ types.h. Этот тип данных определяет массив, всегда хранящийся сразу после описателя секции, в зависимости от того, хранится ли описатель секции внутри ее или снаружи. Все станет значительно понятней, если мы взглянем на функцию slab_buf ctl_t, возвращающую массив: mm/slab.с 1614 static inline kmem_bufctl_t *slab_bufctl(struct slab *slabp) 1615 { 1616 return (kmem_bufctl_t *)(slabp+1); 1617 } Функция slab_buf с tl__t () получает указатель на описатель секции и возвращает указатель на область памяти, следующую сразу за описателем секции. При инициализации кеша поле slab_f гее устанавливается в 0 (так как все объекты свободны, будет возвращен первый) и каждое вхождение в массив kniem__buf ctl_t устанавливается в значение индекса следующего члена массива. Это означает, что нулевой элемент хранит значение 1, первый элемент хранит значение 2 и т. д. Последний элемент в массиве хранит значение BUFCTL_END, что означает, что он является последним элементом в массиве. Рис. 4.8 демонстрирует описатель секции, массив buf с tl и размещение объекта секции, когда описатель секции хранится внутри самой секции. В табл. 4.5 показаны возможные значения некоторых полей описателя секции в каждом из трех возможных состояний. Глава 4 • Управление памятью
Рис. 4.8. Описатель секции и bufctl Таблица 4.5. Состояние секции и значения полей описателя Free Partial Full
slab_inuse slab-> free X X N N ПРИМЕЧАНИЕ. N = количество объектов в секции; X = некоторое положительное число. Жизненный цикл выделителя секции Жизненный цикл выделителя секции Теперь мы рассмотрим взаимодействие кеша и выделителя секции на протяжении жизненного цикла ядра. Ядру нужно быть уверенным, что некоторые структуры находятся на своих местах для поддержки запрошенной процессом области памяти и при создании специализированного кеша в динамически загружаемом модуле. Для выделителя секции важную роль играют несколько глобальных структур. Некоторые из них упоминались в этой главе. Давайте рассмотрим эти глобальные переменные. Глобальные переменные выделителя секции С выделителем секции связаны несколько глобальных переменных. Они включают: • cache_cache. Описатель кеша, содержащий все остальные описатели кешей. Читабельное для человека имя этого кеша - kmem__cache. Это единственный статически выделяемый описатель кеша. • cache__chain. Элемент списка, служащий в качестве указателя на список описателей кешей. • cache__chain_sem. Семафор, контролирующий доступ к cache_chain1. Каждый раз, когда в последовательность добавляется новый элемент (новый описатель кеша), этот семафор получается с помощью down () и освобождается с помощью up (). • malloc_sizes [ ]. Массив, хранящий описатели кеша для DMA- и неБМА-кешей, которые связаны с общим кешем. Перед инициализацией выделителя секций эти структуры уже должны находиться на своих местах. Давайте посмотрим, как они создаются. mm/slab.с 486 static kmem_cache_t cache_cache = { 487.lists = LIST3_INIT(cache_cache.lists), 488.batchcount = 1, 489.limit = BOOT_CPUCACHE_ENTRIES/ 490.objsize = sizeof(kmem_cache_t), 491.flags = SLAB_NO_REAP, 492.spinlock = SPIN_LOCK_UNLOCKED, 493.color_off = Ll_CACHE_BYTES, 494.name = иктет_саспеи, 495 }; 497 /* Защищенный доступ к последовательности кеша. */ 498 static struct semaphore cache_chain_sem; 1 Семафоры подробно описываются в гл. 9, «Построение ядра Linux». Глава 4 • Управление памятью 500 struct list_head cache_chain; Описатель кеша cache_cache обладает флагом SLAB_NO_REAP. Даже если памяти мало, этот кеш сохраняется на протяжении всей жизни ядра. Обратите внимание, что семафор cache_chain только определяется, но не инициализируется. Инициализация происходит во время инициализации системы в вызове kmem_cache_init (). Здесь мы рассмотрим эту функцию подробнее. mm/slab.с 462 struct cache_sizes malloc_sizes[] = { 463 #define CACHE(x) {.cs_size = (x) }, 464 #include < linux/kmalloc__sizes.h> 465 { 0, } 466 #undef CACHE 467 }; Этот фрагмент кода инициализирует массив malloc_sizes [ ] и устанавливает поле cs_size в соответствии со значением, определенным в include/linux/ kernel_sizes. h. Как было сказано ранее, размер кеша может варьироваться от 32 байт до 131072 байт в зависимости от специальных настроек ядра1. Когда глобальные переменные заняли свои места, ядро начинает инициализацию выделителя секций с помощью вызова kmem_cache_init () из init/main.c2. Эта функция берет на себя заботу об инициализации последовательности кешей, его семафора, общего кеша, кеша kmem_cache - короче говоря, всех глобальных переменных, используемых выделителем секций для управления секциями. В этом месте создаются специализированные кеши. Для создания кешей используется функция kmem_cache_create (). Создание кеша Создание кеша включает три шага: 1. Выделение и инициализация описателя. 2. Расчет раскраски секции и размера объекта. 3. Добавление кеша в список cache_chain. 1 Существует несколько настроек, при которых размер общего кеша становится большим, чем 131072. Более 2 Гл. 9 описывает процесс инициализации начиная с загрузки. Мы увидим, как kmem_cache_init () встраи Популярное:
|
Последнее изменение этой страницы: 2016-03-25; Просмотров: 683; Нарушение авторского права страницы