Билет 09 - honeycarbs/bmstu-os-6sem GitHub Wiki

Файловая система: процесс и файловые структуры связанные с процессом. Файлы и открытые файлы, связь структур, представляющих открытые файлы на разных уровнях. Системный вызов open() и библиотечная функция fopen(): параметры и флаги, определенные на функции open(). Реализация системного вызова open() в ядре Linux. Пример: файл открывается два раза системным вызовом open() для записи и в него последовательно записывается строка «аааааааааааа» по первому дескриптору и затем строка «вввв» по второму дескриптору, затем файл закрывается два раза. Показать, что будет записано в файл и пояснить результат.

Процесс и файловые структуры связанные с процессом

Процесс - это программа в стадии выполнения.

Процесс является единицей декомпозиции системы, именно ему выделяются ресурсы системы.

struct file - структура, которая позволяет организовывать работу с файлом, определяет системные таблицы всех открытых файлов.

struct file
{
    ...
    struct path f_path;
    struct inode *f_inode;
    const struct file_operations *f_op;
    spinlock_t f_lock;
    ...
    atomic_long_t f_count;
    unsigned int f_flags;
    fmode_t f_mode; // режим доступа к файлу
    long offset type;
    struct mutex f_pos_lock;
    loff_t f_pos; // смещение в файле
    struct fown_struct  f_owner;
    ...
};

Каждый процесс также связан со структурами:

task_struct описывает запущенный в системе процесс, создаётся динамически, кроме процесса init. Для процесса init создаётся структура init_task.

struct task_struct { volatile long state; void *state; unsigned int flags; int prio, static_prio; struct list_head tasks; ... struct thread_struct thread; struct files_struct *files; ... };

struct files_struct *files формирует таблицу открытых файлов процесса. Каждый процесс имеет собственную такую таблицу. struct files_struct { atomic_t count; // счётчик пользователей структуры spinlock_t file_lock; // средство взаимоисключения int max_fds; // максимальное количество файловых дескрипторов ... struct file **fd; // массив всех файловых дескрипторов ... struct file *fd_array[32]; // массив открытых файловых дескрипторов };

struct fs_struct *fs описывает файловую систему, к которой относится процесс. До запуска программы является исполняемым файлом.

struct fs_struct
{
    atomic_t count; // количество пользователей
    rwlock_t lock;
    int umask; // права доступа
    struct dentry *root; // корневая директория
    struct dentry *pwd; // текущая директория
    struct dentry *altroot; // альтернативная корневая директория
    struct vfsmount *rootmnt; // объект монтирования корневой директории
    struct vfsmount *pwdmnt; // объект монтирования текущей директории
    struct vfsmount *altrootmnt; // объект монтирования альтернативной корневой директории 
};

namespace позволяет каждому процессу иметь своё видение смонтированной файловой системы

struct namespace
{
    atomic_t count;
    struct vfsmount *root;
    struct list_head list;
    struct rw_semaphore sem;
};

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

structs drawio

Системный вызов open() и библиотечная функция fopen()

Для процесса открытия файла в различных структурах, даже в структурах ядра, имеется функция open. Системный вызов open возвращает файловый дескриптор.

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

Используемые флаги:

O_RDONLY - только чтение
O_WRONLY - только запись
O_RDWR - доступ на чтение и на запись

Некоторые флаги создания файлов и флаги состояния файлов:

O_APPEND - файл открывается в режиме добавления
O_CLOEXEC - устанавливает флаг close-on-exec на новом файловом дескрипторе
O_CREAT - файл будет создан, если он ещё не существует
O_PATH - создаётся файловый дескриптор для указания положения в дереве файловой системы и для выполенния операций, работающих исключительно на уровне файловых дескрипторов
O_TMPFILE - создаётся безымянный временный файл

fopen() - это функция стандартной библиотеки. Стоит отметить, что стандартный ввод-вывод буферизуется. Также работает с форматированными данными.

FILE *fopen(const char *fname, const char *mode);
``
Системный вызов open:
```C
int open(const char *filename, int access, unsigned mode)

Системный вызов open() создаёт новый файловый дескриптор для открытого файла, запись в общесистемной таблице открытых файлов. Эта запись регистрирует смещение в файле и флаги состояния файла.

Системный вызов open() является обёрткой функции ядра ksys_open(), которая вызывает функцию do_sys_open(): в теле функции do_sys_open() вызывается функция build_open_how() и функция do_sys_openat2(). Функция do_sys_openat2() вызывается функции build_open_flags(), getname(filename), get_unused_fd_flags() и, если функция get_unused_fd_flags() возвращает fd > 0, то вызывается функция do_filp_open(). Функция do_sys_openat2() выполняет все задачи системного вызова open. Сначала выполняется проверка правильности флагов и их преобразование во внутреннее представление функцией build_open_flags(). В случае неуспешного преобразования и проверки будет возвращена ошибка.

Панический пример с ааа

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void)
{
    int fd1 = open("file.txt", O_RDWR);
    int fd2 = open("file.txt", O_RDWR);

    char buf1[] = "aaaaaaaaaaaa";
    char buf2[] = "bbbb";
    write(fd1, buf1, sizeof(buf1) - 1);
    write(fd2, buf2, sizeof(buf2) - 1);

    close(fd1);
    close(fd2);

    return 0;
}

Результатом работы программы будет: "bbbbaaaaaaaa"

Файл дважды открывается для записи с помощью open(), при этом создается два экземпляра структуры struct file, которые описываются один статический файл. Файловые дескрипторы независимы между собой, поэтому положение указателей f_pos будут изменяться независимо друг от друга.

⚠️ **GitHub.com Fallback** ⚠️