Главная страница

Второе издание


Скачать 3.09 Mb.
НазваниеВторое издание
Дата08.09.2019
Размер3.09 Mb.
Формат файлаpdf
Имя файлаLav_Robert_Razrabotka_yadra_Linux_Litmir.net_264560_original_254.pdf
ТипДокументы
#86226
страница44 из 53
1   ...   40   41   42   43   44   45   46   47   ...   53
Экспортируемые символы
При загрузке модули динамически компонуются с ядром. Так же как и в случае динамически загружаемых бинарных файлов пространства пользователя, в коде мо- дулей могут вызываться только те функции ядра (основного образа или других мо- дулей), которые явно экспортируются для использования. В ядре экспортирование осуществляется с помощью специальных директив EXPORT_SYMBOL () и EXPORT_
SYMBOL_GPL().
Функции, которые экспортируются, доступны для использования модулями.
Функции, которые не экспортируются, не могут быть вызваны из модулей. Правила компоновки и вызова функций для модулей значительно более строгие, чем для основного образа ядра. Код ядра может использовать любые интерфейсы ядра (кро- ме тех, которые определены с ключевым словом s t a t i c ) , потому что код ядра ком- понуется в один выполняемый образ. Экспортируемые символы, конечно, тоже не должны определяться как s t a t i c .
Набор символов ядра, которые экспортируются, называется экспортируемым ин- терфейсом ядра или даже (здесь не нужно удивляться) API ядра.
Модули 353

Экспортировать символы просто. После того как функция определена, необходи- мо вызвать директиву EXPORT_SYMBOL ().
/*
* get_pirate_beard_color — возвратить значение цвета бороды текущего
* пирата pirate — это глобальная переменная, доступная из данной
* функции цвета определены в файле
*/
int get_pirate_beard_color(void)
{
return pirate->beard->color;
}
EXPORT_SYMBOL(get_pirate_beard_color);
Допустим, что функция g e t _ p i r a t e _ b e a r d _ c o l o r ( ) объявлена в заголовочном файле и ее может использовать любой модуль.
Некоторые разработчики хотят, чтобы их интерфейсы были доступны только для модулей с лицензией GPL. Такая возможность обеспечивается компоновщиком ядра с помощью макроса MODULE_LICENSE (). Если есть желание, чтобы рассматриваемая функция была доступна только для модулей, которые помеченные как соответствую- щие лицензии GPL, то экспортировать функцию можно следующим образом.
EXPORT_SYMBOL_GPL(get_pirate_beard_color);
Если код ядра конфигурируется для компиляции в виде модуля, то необходимо гарантировать, что все используемые интерфейсы экспортируются. В противном случае будут возникать ошибки компоновщика и загружаемый модуль не будет рабо- тать.
Вокруг модулей
В этой главе были рассмотрены особенности написания, сборки, загрузки и вы- грузки модулей ядра. Мы обсудили, что такое модули и каким образом ядро опе- рационной системы Linux, несмотря на то что оно является монолитным, может загружать код динамически. Были также рассмотрены параметры модулей и экспор- тируемые символы. На примере воображаемого модуля ядра (драйвера устройства)
управления удочкой был показан процесс написания модуля и процесс добавления к нему различных возможностей, таких как внешние параметры.
В следующей главе будут рассмотрены объекты k o b j e c t и файловая система sysf's,
которые являются основным интерфейсом к драйверам устройств и, следовательно,
к модулям ядра.
354 Глава 16

17
Объекты kobject
и файловая
система sysfs
У
нифицированная модель представления устройств — это существенно новая осо- бенность, которая появилась в ядрах серии 2.6. Модель устройств— это еди- ный механизм для представления устройств и описания их топологии в системе.
Использование единого представления устройств позволяет получить следующие преимущества.
• Уменьшается дублирование кода.
• Используется механизм для выполнения общих, часто встречающихся функ- ций, таких как счетчики использования.
• Появляется возможность систематизации всех устройств в системе, возмож- ность просмотра состояний устройств и определения, к какой шине то или другое устройство подключено.
• Появляется возможность генерации полной и корректной информации о древо- видной структуре всех устройств в системе, включая все шины и соединения.
• Обеспечивается возможность связывания устройств с их драйверами и наоборот.
• Появляется возможность разделения устройств ва категории в соответствии с различными классификациями, таких как устройства ввода, без знания физиче- ской топологии устройств.
• Обеспечивается возможность просмотра иерархии устройств от листьев к кор- ню и выключения питания устройств в правильном порядке.
Последний пункт был самой первой мотивацией необходимости создания общей модели представления устройств. Для того чтобы реализовать интеллектуальное управление электропитанием в ядре, необходимо построить дерево, которое пред- ставляет топологию устройств в системе. Для выключения питания устройств, ко- торые организованы в виде древовидной топологии, ориентированной сверху вниз,
ядро должно выключить питание нижних узлов (листьев) перед выключением пита- ния верхних узлов. Например, ядро должно выключить питание USB-мыши перед
тем, как выключать питание контроллера шины USB, а питание контроллера шины
USB должно быть выключено перед выключением питания шины PCI. Чтобы делать это эффективно и правильно для всей системы, ядру необходимо отслеживать топо- логию дерева всех устройств в системе.
Объекты kobject
Сердцем модели представления устройств являются объекты kobject, которые представляются с помощью структуры s t r u c t k o b j e c t , определенной в файле
< l i n u x / k o b j e c t . h > . Тип kobject аналогичен классу Object таких объектно-ори- ентированных языков программирования, как С# и Java. Этот тип определяет общую функциональность, такую как счетчик ссылок, имя, указатель на родительский объ- ект, что позволяет создавать объектную иерархию.
Структура, с помощью которой реализованы объекты kobject, имеет следующий вид.
struct kobject {
char *k_name;
char name[KOBJ_NAME_LEN];
struct kref kref;
struct list_head entry;
struct kobject *parent;
struct kset *kset;
struct kobj_type *ktype;
struct dentry *dentry;
};
Поле k_name содержит указатель на имя объекта. Если длина имени меньше
KOBJ_NAME_LEN, что сейчас составляет 20 байт, то имя хранится в массиве name, a ноле kname указывает на первый элемент этого массива. Если длина имени больше
KOBJ_NAME_LEN байт, то динамически выделяется буфер, размер которого достато- чен для хранения строки символов имени, имя записывается в этот буфер, а поле k_name указывает на него.
Указатель p a r e n t указывает на родительский объект данного объекта kobject.
Таким образом, с помощью структур k o b j e c t может быть создана иерархия объ- ектов в ядре, которая позволяет устанавливать соотношения родства между раз- личными объектами. Как будет видно дальше, с помощью файловой системы sysfs осуществляется представление в пространстве пользователя той иерархии объектов kobject, которая существует в ядре.
Указатель d e n t r y содержит адрес структуры s t r u c t dentry, которая представ- ляет этот объект в файловой системе sysfs.
Поля kref, ktype и k s e t указывают на экземпляры структур, которые использу- ются для поддержки объектов kobject. Поле e n t r y используется совместно с полем kset. Сами эти структуры и их использование будут обсуждаться ниже.
Обычно структуры kobject встраиваются в другие структуры данных и сами по себе не используются. Например, такая важная структура, как s t r u c t cdev, имеет поле kobj.
356 Глава 17

/* структура cdev - объект для представления символьных устройств */
struct cdev {
struct kobject kobj;
struct module *owner;
struct file_operations *ops;
struct list_head list;
dev_t dev;
unsigned int count;
};
Когда структуры kobject встраиваются в другие структуры данных, то последние получают те стандартизированные возможности, которые обеспечиваются структу- рами kobject. Еще более важно, что структуры, которые содержат в себе объекты kobject, становятся частью объектной иерархии. Например, структура cdev пред- ставляется в объектной иерархии с помощью указателя на родительский объект cdev->kobj->parent и списка cdev->kobj->entry.
Типы ktype
Объекты kobject могут быть связаны с определенным типом, который называ- ется ktype. Типы ktype представляются с помощью структуры s t r u c t kobj_type,
определенной в файле следующим образом.
struct kobj_type {
void (*release)(struct kobject * ) ;
struct sysfs_ops *sysfs_ops;
struct attribute **default_attrs;
};
Тип ktype имеет простое назначение— представлять общее поведение для не- которого семейства объектов kobject. Вместо того чтобы для каждого отдельного объекта задавать особенности поведения, эти особенности связываются с их полем ktype, и объекты одного "типа" характеризуются одинаковым поведением.
Поле r e l e a s e содержит указатель на деструктор, который вызывается, когда ко- личество ссылок на объект становится равным нулю. Эта функция отвечает за осво- бождение памяти, связанной с объектом, и за другие операции очистки.
Поле sysfs_ops указывает на структуру sysfs_ops. Эта структура определяет поведение файлов на файловой системе sysfs при выполнении операций записи и чтения. Более детально она рассматривается в разделе "Добавлепие файлов на фай- ловой системе sysfs".
Наконец, поле d e f a u l t _ a t t r s указывает на массив структур a t t r i b u t e . Эти структуры определяют атрибуты, которые связаны с объектом kobject и использу- ются но умолчанию. Атрибуты соответствуют свойствам данного объекта. Если не- который объект kobject экспортируется через файловую систему sysfs, то атрибуты экспортируются как отдельные файлы. Последний элемент этого массива должен со- держать значению NULL.
Объекты kobject и файловая система sysfs 357

Множества объектов k s e t
Множества kset представляют собой коллекции объектов kobject. Множество kset работает как базовый контейнерный класс для объектов, например, "все блоч- ные устройства". Множества kset очень похожи на типы ktype, и возникает вопрос:
"Для чего нужны два разных обобщения?" Множество kset объединяет несколько объектов kobject, а типы ktype определяют общие свойства, которые связаны с объектами k o b j e c t одного типа. Существует возможность объединить объекты одного типа ktype в различные множества kset.
Поле kset объекта kobject указывает на связанное с данным объектом множе- ство kset. Множество объектов k s e t представляется с помощью структуры kset,
которая определена в файле следующим образом.
struct kset {
struct subsystem *subsys;
struct kobj_type *ktype;
struct list_head list;
struct kobject kobj;
struct kset_hotplug_ops *hotplug_ops;
};
Указатель ktype указывает на структуру ktype, которая определяет тип всех объ- ектов данного множества, поле l i s t - список всех объектов kobject данного мно- жества, поле kobj — объект kobject, который представляет базовый класс для всех объектов данного множества, а поле hotplug_ops указывает на структуру, которая определяет поведение объектов kobject при горячем подключении устройств, свя- занных с данным множеством.
Наконец, поле sybsys указывает на структуру s t r u c t subsystem, которая связа- на с данным множеством kset.
Подсистемы
Подсистемы используются для представления высокоуровневых концепций ядра и являются коллекцией одного или нескольких множеств kset. Множества kset со- держат объекты kobject, подсистемы — множества kset, но связь между множества- ми в подсистеме значительно более слабая, чем связь между объектами kobject в множестве. Множества kset одной подсистемы могут иметь только наиболее общие объединяющие факторы.
Несмотря на их важную роль, подсистемы представляются с помощью очень про- стой структуры данных — s t r u c t subsystem.
struct subsystem {
struct kset ksot;
struct rw_semaphore rwsem;
};
Структура subsystem содержит только одно множество kset, тем не менее не- сколько множеств kset могут указывать на общую структуру subsystem с помощью
358 Глава 17
поля subsys. Такие однонаправленные взаимоотношения означают, что нет возмож- ности определить все множестпа подсистемы, только имея ее структуру subsystem.
Поле k s e t , которое содержится в структуре subsystem, — это множество k s e t подсистемы, которое используется по умолчанию, чтобы зафиксировать положение этой подсистемы в иерархии объектов.
Поле rwsem структуры s u b s y s t e m — это семафор чтения-записи (см. главу 9,
"Средства синхронизации в ядре"), который используется для защиты подсистемы и ее множеств k s e t от конкурентного доступа. Все множества k s e t должны принадле- жать какой-нибудь подсистеме, поскольку они используют семафор подсистемы для защиты своих данных от конкурентного доступа.
Путаница со структурами
Те несколько структур, которые только что были описаны, приводят к путани- це не потому, что их много (только четыре) или они сложные (все они достаточно просты), а потому что они сильно друг с другом переплетаются. При использовании объектов k o b j e c t достаточно сложно рассказать об одной структуре, не упоминая другие. Тем не менее, на основании рассмотренных особенностей этих структур можно построить прочное понимание их взаимоотношений.
Самым важным является объект k o b j e c t , который представляется с помощью структуры s t r u c t k o b j e c t . Структура k o b j e c t используется для представления наиболее общих объектных свойств структур данных ядра, таких как счетчик ссы- лок, взаимоотношения родитель-порожденный и имя объекта. С помощью структуры k o b j e c t эти свойства можно обеспечить одинаковым для всех стандартным спосо- бом. Сами по себе структуры k o b j e c t не очень полезны, они обычно встраиваются в другие структуры данных.
С каждым объектом k o b j e c t связан один определенный тип данных— k t y p e ,
который представляется с помощью структуры s t r u c t k o b j _ t y p e . На экземпляр такой структуры указывает поле ktype каждого объекта kobject. С помощью типов ktype определяются некоторые общие свойства объектов: поведение при удалении объекта, поведение, связанное с файловой системой sysfs, а также атрибуты объекта.
Объекты k o b j e c t группируются в множества, которые называются k s e t .
Множества k s e t представляются с помощью структур данных s t r u c t k s e t . Эти множества предназначены для двух целей. Во-первых, они позволяют использовать встроенный в них объект k o b j e c t в качестве базового класса для группы других объектов k o b j e c t . Во-вторых, они позволяют объединять вместе несколько связан- ных между собой объектов k o b j e c t . На файловой системе sysfs объекты k o b j e c t представляются отдельными каталогами файловой системы. Связанные между собой каталоги, например все подкаталоги одного каталога, могут быть включены в одно множество k s e t .
Подсистемы соответствуют большим участкам ядра и являются набором мно- жеств k s e t . Подсистемы представляются с помощью структур s t r u c t subsystem.
Все каталоги, которые находятся в корне файловой системы sysfs, соответствуют подсистемам ядра.
На рис. 17.1 показаны взаимоотношения между этими структурами данных.
Объекты kobject и файловая система sysfs 359

Подсистема
Подсистема
Рис. 17.1. Взаимоотношения между объектами kobject, множествами
kset и подсистемами
Управление и манипуляции с объектами k o b j e c t
Теперь, когда у нас уже есть представление о внутреннем устройстве объектов kobject и связанных с ними структурах данных, самое время рассмотреть экспор- тируемые интерфейсы, которые дают возможность управлять объектами kobject и выполнять с ними другие манипуляции. В основном, разработчикам драйверов не- посредственно не приходится иметь дело с объектами kobject. Структуры kobject встраиваются в некоторые специальные структуры данных (как это было в приме- ре структуры устройства посимвольного ввода-вывода) и управляются "за кадром" с помощью соответствующей подсистемы драйверов. Тем не менее, объекты kobject не всегда могут оставаться невидимыми, иногда с ними приходится иметь дело, как при разработке кода драйверов, так и при разработке кода управления подсистема- ми ядра.
Первый шаг при работе с объектами kobject - это их декларация и инициали- зация. Инициализируются объекты kobject с помощью функции k o b j e c t _ i n i t () ,
которая определена в файле следующим образом.
void kobject_init(struct kobject *kobj);
Единственным параметром этой функции является объект kobject, который не- обходимо проинициализировать. Перед вызовом этой функции область памяти, в ко- торой хранится объект, должна быть заполнена нулевыми значениями. Обычно это делается при инициализации большой структуры данных, в которую встраивается объект kobject. В других случаях просто необходимо вызвать функцию memset ().
memset(kobj, 0, sizeof (*kobj));
После заполнения нулями безопасным будет инициализация полей p a r e n t и kset, как показано в следующем примере.
360
Глава 17
kset kobj kobj kobj kobj kobj kset kobj kobj kobj
kobj = kmalloc(sizeof (*kobj), GFP_KERNEL);
if (!kobj)
return -ENOMEM;
memset(kobj, 0, sizeof (*kobj));
kobj->ksct - kset;
kobj->parent = parent_kobj;
kobject_init (kobj);
После инициализации необходимо установить имя объекта с помощью функции k o b j e c t _ s e t _ n a m e ( ) , которая имеет следующий прототип.
int kobject_set_name(struct kobject * kobj, const char * fmt, , . . . ) ;
Эта функция принимает переменное количество параметров, по аналогии с функ- циями p r i n t f () и p r i n t k (). Как уже было сказано, на имя объекта указывает поле k_name структуры k o b j e c t . Если это имя достаточно короткое, то оно хранится в статически выделенном массиве name, поэтому есть смысл без необходимости не указывать длинные имена.
После того как для объекта выделена память и объекту присвоено имя, нужно установить значение его поля k s e t , а также опционально поле k t y p e . Последнее необходимо делать только в том случае, если множество k s e t не предоставляет типа ktype для данного объекта, в противном случае значение поля ktype, которое указано в структуре k s e t , имеет преимущество. Если интересно, почему объекты k o b j e c t имеют свое поле ktype, то добро пожаловать в клуб!
Счетчики ссылок
Одно из главных свойств, которое реализуется с помощью объектов k o b j e c t , —
это унифицированная система поддержки счетчиков ссылок. После инициализации количество ссылок на объект устанавливается равным единице. Пока значение счет- чика ссылок на объект не равно нулю, объект существует в памяти, и говорят, что он
захвачен (pinned, буквально, пришпилен). Любой код, который работает с объектом,
вначале должен увеличить значение счетчика ссылок. После того как код закончил работу с объектом, он должен уменьшить значение счетчика ссылок. Увеличение значения счетчика называют захватом (getting), уменьшение — освобождением (putting)
ссылки на объект. Когда значение счетчика становится равным нулю, объект может быть уничтожен, а занимаемая им память освобождена.
Увеличение значения счетчика ссылок выполняется с помощью функции kobject_get().
struct kobject * kobject_get(struct kobject *kobj);
Эта функция возвращает указатель на объект kobject в случае успеха и значение
NULL в случае ошибки.
Уменьшение значения счетчика ссылок выполняется с помощью функции kobject_put().
void kobject put(struct kobject *kobj);
Объекты kobject и файловая система sysfs 361

Если значение счетчика ссылок объекта, который передается в качестве параме- тра, становится равным нулю, то вызывается функция, на которую указывает указа- тель r e l e a s e поля ktype этого объекта.
Структуры k r e f
Внутреннее представление счетчика ссылок выполнено с помощью структуры kref, которая определена в файле следующим образом.
struct kref{
atomic_t refcount;
};
Единственное поле этой структуры — атомарная переменная, в которой хранится значение счетчика ссылок. Структура используется просто для того, чтобы выпол- нять проверку типов. Чтобы воспользоваться структурой kref, необходимо ее ини- циализировать с помощью функции k r e f _ i n i t () .
void kref_init(struct kref *krcf)
{
atomic_set(&kref->refcount, 1 ) ;
}
Как видно из определения, эта функция просто инициализирует атомарную пере- менную тина a t o m i c _ t в значение, равное единице.
Следовательно, структура kref является захваченной сразу же после инициализа- ции, так же ведут себя и объекты kobject.
Для того чтобы захватить ссылку на структуру kref, необходимо использовать функцию kref_get ().
void kref_get(struct kref *kref)
{
WARN_ON(!atomic_read(&kref->refcount));
atomic_inc(&kref->refcount);
}
Эта функция увеличивает значение счетчика ссылок на единицу. Она не возвра- щает никаких значений. Чтобы освободить ссылку на структуру kref, необходимо использовать функцию kref_put ().
void kref_put(struct kref *kref, void (*release) (struct kref *kref))
{
WARN_ON(release == NULL);
WARN_ON(release == (void (*)(struct kref *))kfree);
if (atomic dec_and_test (&kref->refcount))
release (kref);
}
Эта функция уменьшает значение счетчика ссылок на единицу и вызывает функ- цию r e l e a s e (), которая передастся ей в качестве параметра, когда значение счет- чика ссылок становится равным нулю. Как видно из использованного выражения
WARM_ON (), функция r e l e a s e () не может просто совпадать с функцией k f r е е (),
362 Глава 17
а должна быть специальной функцией, которая принимает указатель на структуру s t r u c t kref в качестве своего единственного параметра и не возвращает никаких значений.
Вместо того чтобы разрабатывать свои функции управления счетчиками ссылок на основании типа данных atomic_t, настоятельно рекомендуется использовать тип данных kref и соответствующие функции, которые обеспечивают общий и правиль- но работающий механизм поддержки счетчиков ссылок в ядре.
Все эти функции определены в файле l i b / k r e f . c и объявлены в файле
< l i n u x / k r e f . h > .
Файловая система sysfs
Файловая система sysfs — это виртуальная файловая система, которая существу- ет только в оперативной памяти и позволяет просматривать иерархию объектов kobject. Она позволяет пользопателям просматривать топологию устройств опера- ционной системы в виде простой файловой системы. Атрибуты объектов k o b j e c t могут экспортироваться в виде файлов, которые позволяют считывать значения пе- ременных ядра, а также опционально записывать их.
Хотя изначально целью создания модели представления устройств было описа- ние топологии устройств системы для управления электропитанием, файловая си- стема sysfs стала удачным продолжением этой идеи. Для того чтобы упростить отлад- ку, разработчик унифицированной модели устройств решил экспортировать дерево устройств в виде файловой системы. Такое решение показало свою полезность вна- чале в качестве замены файлов, связанных с устройствами, которые раньше экспор- тировались через файловую систему /ргос, а позже в качестве мощного инструмен- та просмотра информации о системной иерархии объектов. Вначале, до появления объектов kobject, файловая система sysfs называлась driverfs. Позже стало ясно —
новая объектная модель была бы очень кстати, и в результате этого появилась кон- цепция объектов kobject. Сегодня каждая система, на которой работает ядро 2.6,
имеет поддержку файловой системы sysfs, и практически во всех случаях эта файло- вая система монтируется.
Основная идея работы файловой системы sysfs — это привязка объектов kobject к структуре каталогов с помощью поля dentry, которое есть в структуре kobject.
Вспомните из материала главы 12, "Виртуальная файловая система", что структура dentry используется для представления элементов каталогов. Связывание объектов с элементами каталогов проявляется в том, что каждый объект просто видится как каталог файловой системы. Экспортирование объектов k o b j e c t в виде файловой системы выполняется путем построения дерева элементов каталогов в оперативной памяти. Но обратите внимание, объекты kobject уже образуют древовидную струк- туру — нашу модель устройств! Поэтому простое назначение каждому объекту иерар- хии, которые уже образуют дерево в памяти, соответствующего элемента каталога позволяет легко построить файловую систему sysfs.
На рис. 17.2 показан частичный вид файловой системы sysfs, которая смонтиро- вана на каталог /sys.
Корневой каталог файлопой системы sysfs содержит семь подкаталогов: block, bus,
c l a s s , devices, firmware, module и power. В каталоге block содержатся каталоги для каждого зарегистрированного в системе устройства блочного ввода-вывода.
Объекты kobject и файловая система sysfs 363

/sys block/
fd0
hda dev device-> . ./. ./devices/psi0000:00/0000:00:1f.1/ide/0.0
hda1
dev size start star hda2
hda3
hda4
hda5
hda6
queue lidc hdd loop0
loop1
Ioop2
Ioop3
Ioop4
Ioop5
Ioop6
Ioop7
md0
bus/
class/
devices/
firmware/
power
1   ...   40   41   42   43   44   45   46   47   ...   53


написать администратору сайта