Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Lections_v2.docx
Скачиваний:
1
Добавлен:
01.07.2025
Размер:
11 Мб
Скачать
☆

Лекция 5. 3.03.2014 Файлы.

Для того, чтобы система могла работать с файлами, вводится абстракция «открытый файл».

В системе для работы с файлами создаются дополнительные структуры.

Только процессы могут выполнять функции read/write. Процесс, заинтересованный в работе с файлом, открывает файл. При каждом открытии файла каким-либо процессом ядро создает в системной области памяти экземпляр структуры файл (struct file).

Каждый файл имеет единственный vnode, inode и все процессы, открывшие данный файл получат указатель на одни и те же vnode inode. Struct file представляет из себя двусвязный список.

struct file

{

mode_t f_mode;

loff_t f_pos;

unsigned short f_flags;

unsigned short f_count;

unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin;

struct file *f_next, *f_prev;

int f_oner;

struct inode *f_inode;

struct file_operations *f_op;

unsigned long f_version;

void *orivate_data;

};

Функции, которые система предоставляет для работы с файлом на самом деле являются методами этой структуры.

В зависимости от конкретной файловой системы struct operation может иметь уникальную реализацию или использовать некоторый универсальный метод, если такой имеется. Если вместо метода/ссылки на метод указывается null, значит данная операция в конкретной файловой системе не определена. С процессом ассоциированы три структуры. Три структуры данных связывают вместе файловую систему (ВФС) и процессы. Это

Struct:

  1. files_struct

  2. fs_struct

  3. namespace

Files_struct определена в linux/file.h

<linux/file.h>

struct files_struct

{

atomic_t count; //счетчик ссылок. изменение – неделимая операция

spinlock_t file_lock; // защита структуры

int max_fds; // максимальное количество файловых объектов

int max_fdset; // максимальное количество файловых дескрипторов

int next_fd; // номер следующего файлового дескриптора

struct file **fd; // массив всех файловых объектов

fd_set *close_on_exec; // файловые дескрипторы для закрытия или исполнения

fd_set *open_fds;

fd_set close_on_exec_init;

fd_set open_fds_init; // инициализированный набор файловых дескрипторов

struct file *fd_array[NR_OPEN_DEFAULT]; //список открытых файловых объектов. Константа // определена в системе и по умолчанию равна 32 (можно открыть не более 32 файловых //объектов). При превышении система создаст новый массив.

};

<linux/fs_struct.h>

struct fs_struct

{

atomic_t count; // количество использованных юзером структур

rwlock_t lock; // read-write lock

int umask;

struct dentry *root; // корневая директория

struct dentry *pwd; // dentry of current working directory. Избавляет от необходимости указывать полное имя файла

struct dentry *altroot; // dentry of alternative root

struct vfsmount *rootmnt;

struct vfsmount *pwdmnt;

struct vfsmount *altrootmnt;

};

Spinlock – блокировка, которая осуществляется путем активного ожидания на процессе. read_writelock – блокировка более высокого уровня в ядре.

Перечисленные структуры относятся к процессу. Fs_struct содержит информацию о файловой системе, которая связана с процессом. Процесс в Линукс может быть связан с разными файловыми системами.

Третья структура – namespace. Была добавлена в ядро линукс начиная с версии 2.4. Она позволяет каждому процессу иметь уникальный взгляд на подмонтированные файловые системы. Структура имеет следующий вид.

<linux/namespace.h>

struct namespace

{

atomic_t count;

struct vfsmount *root;

struct list_head list; // list of mount points. Точно определяет двусвязный список //подмонтированных файловых систем, которые составляют namespace

struct rw_semaphore sem; // sem protecting the namespace

};

Данная структура линкуется дескриптору каждого процесса. Для большинства процессов имеются уникальные структуры files_struct и fs_struct (каждый процесс ссылается на свои собственные files_struct и fs_struct). Но могут быть установлены флаги CLONE_FILES и CLONE_FS, тогда указанные структуры будут разделяемыми, то есть несколько процессов будут ссылаться на одни и те же структуры. Соответственно count в каждой структуре будет равен количеству ссылок. Потоки (threads) обычно определяют эти две константы и таким образом разделяют единственную files_struct и fs_struct процессам. Как правило, обычный процесс указанные флаги не устанавливает и, таким образом, имеет собственную системную информацию об открытых файлах. Структура namespace работает по-другому. Все процессы разделяют одно и то же пространство имен (namespace), то есть они все видят одну и ту же иерархию файлов, используя одну и ту же таблицу монтирования. Однако, если установлен флаг CLONE_NEWNS, с использованием системного вызова clone() процессу выделяется уникальная структура namespace. В силу того, что большинство процессов не устанавливают этот флаг, все процессы наследуют пространство имен своих предков.

Read-write.

ssize_t read(struct file *filp, char *buff, size_t count, loff_t *offp);

ssize_t write(struct file *filp, char *buff, size_t count, loff_t *offp);

Параметры одинаковы, потому что, с точки зрения системы, read и write фактически выполняют одинаковые действия.

Read-write являются методами структуры struct operations.

Первый параметр – указатель на файл, count – размер требуемых для передачи данных, *buff – указатель на user buffer. В этот буфер данные или записываются или это пустой буфер при чтении,

*offp – указатель (loff_t – long offset type), указывает смещение в файле.

Адреса пространства пользователя не могут напрямую быть использованы для выполнения копирования (memory copy). Адреса пространства пользователя не могут быть напрямую использованы в пространстве ядра. На это есть несколько причин. Первое и важнейшее отличие адресного пространства ядра от адресного пространства процесса (юзера) заключается в том, что адресное пространство юзера выгружаемо (swapped). Когда ядро обращается, используя указатель на юзерспейс, связанный с какой-то страницей, эта страница может отсутствовать в памяти и возникнет исключение. Важно отметить, что в линукс 2.0 для архитектуры х86 используются совершенно разные карты памяти для userspace и kernelspace. Отсюда указатели на адресное пространство юзера не могут быть выделены в пространстве ядра. Для того, чтобы избежать этих проблем, необходимо копировать фактический сегмент данных процесса в пространство ядра – так называемое кросспространственное (cross-space) копирование. Для этого в линукс имеются специальные функции, которые определены в файле <asm/uaccess.h>. Эти функции оптимизируют процесс копирования.

<asm/uaccess.h>

unsigned long copy_to_user(void *to, const void *from, unsigned long count);

unsigned long copy_from_user(void *to, const void *from, unsigned long count);

Системные вызовы read-write переводят систему в режим ядра и уже в режиме ядра выполняются действия с драйверами устройства. Но в это время супервизор не может работать с адресным пространство процесса, так как пространство может быть выгружено (и будет, если процесс спит более 20 секунд).

Read-write вызывают другие функции, в том числе copy_to_user, copy_from_user.

ssize_t dev_read(struct file *file, char *leaf, size_t count, loff_t *ppos);

Схема 2.

Ошибки специфицированы в <linux.errno.h>

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]