• Панорамный снимок

    панорамный снимок

    www.dental-plus.ru





Linux Kernel (Ядро линукса) (часть 2)


Реализация системных вызовов VFS

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

Вернемся к примеру, рассмотренному в начале главы. Пользователь выдает команду оболочки, копирующую MS-DOS-файл /floppy/TEST в Ех12-файл /tmp/test. Оболочка вызывает внешнюю программу, например, ср, которая, предположим, выполнит следующий фрагмент кода:
inf = open("/floppy/TEST", O-RDONLY, 0);
outf = open("/tmp/test", 0_WRONLY | 0_CREAT | 0_TRUNC, 0600); do {
len = read(inf, buf, 4096); write(outf, buf, len);
}while (len); close(outf); close(inf);
На самом деле, код реальной программы ср сложнее, поскольку она должна еще проверять коды ошибок, возможно, возвращенных системным вызовом. В нашем примере мы сосредоточим внимание на "нормальном" поведении операции копирования.

Системный вызов ореп

Системный вызов open о обслуживается функцией sys_open, которая принимает в качестве параметров filename (путь к файлу, который нужно открыть), flags (флаги режима доступа) и mode (битовую маску прав доступа), если требуется создать файл. В случае успеха системный вызов возвращает дескриптор файла, т. е. индекс, присвоенный новому файлу в массиве указателей на файловые объекты current->fiies->fd; иначе возвращается -1.

В рассматриваемом примере open вызывается дважды. Первый раз, чтобы открыть /floppy/TEST для чтения (флаг o rdonly), а второй — чтобы открыть /tmp/test для записи (флаг o wronly). Если файл /tmp/test еще не существует, он создается (флаг o creat) с исключительными правами владельца на чтение и запись (восьмеричное число 0600 в качестве третьего параметра).

В противном случае, если файл существует, он перезаписывается (флаг
o trunc). Все флаги системного вызова open перечислены в табл. 12.18.
Опишем работу функции sys open . Она выполняет следующие шаги:
1. Вызывает getname , чтобы прочитать из адресного пространства процесса путь к файлу.
2. Вызывает get_unused_fd, Чтобы наЙТИ незанятый СЛОТ В current-> fiies->fd. Соответствующий индекс (дескриптор нового файла) хранится в локальной переменной fd.
3. Вызывает функцию fiip openo, передавая ей в качестве параметров путь, флаги режима доступа и битовую маску прав доступа. В свою очередь, эта функция выполняет следующие шаги:
• копирует флаги режима доступа в namei fiags, но кодирует флаги режима доступа o rdonly, o wronly и o rdwr специальным образом: нулевой (самый младший) бит namei fiags устанавливается, только если доступ к файлу требует прав на чтение, а бит с номером 1 устанавливается, только если доступ к файлу требует прав на запись. Обратите внимание, что в системном вызове open невозможно указать, что доступ к файлу не требует привилегий на чтение или запись. Однако это имеет смысл при анализе пути, содержащем символьные ссылки;
• вызывает функцию open namei , передавая ей в качестве параметров путь, модифицированные флаги режима доступа и адрес локальной структуры nameidata. Эта функция анализирует путь следующим образом:
п если флаг o creat не установлен среди флагов режима доступа, функция запускает операцию анализа пути со сброшенным флагом lookup_parent и установленным флагом LOOKUP_OPEN. Кроме того, флаг lookup follow устанавливается, только если флаг o nofollow сброшен, а флаг lookup directory устанавливается, только если флаг o_directory установлен;
п если среди флагов режима доступа флаг o creat установлен, функция запускает операцию анализа с установленными флагами
LOOKUP_PARENT, LOOKUP_OPEN И LOOKU P_CREATE. ЕСЛИ фуНКЦИЯ
path iookup завершит свое выполнение успешно, обсуждаемая функция проверит, существует ли запрошенный файл. В противном случае она выделит новый дисковый индексный дескриптор, вызвав метод create родительского индексного дескриптора;
Функция open namei , помимо прочего, выполняет несколько проверок на безопасность в отношении файла, который определила операция анализа пути. В частности, проверяется, существует ли индексный дескриптор, связанный с найденным объектом "элемент каталога", является ли он обычным файлом, и разрешен ли текущему процессу доступ к этому файлу в соответствии с флагами режима доступа. Кроме того, если файл открывается для записи, функция убеждается, что он не заблокирован другими процессами.
• вызывает функцию dentry open , передавая ей адреса объекта "элемент каталога” и объекта, представляющего смонтированную систему,
которые были получены в результате анализа пути. Вызванная функция
выполняет следующее:
- выделяет новый файловый объект;
-инициализирует поля f fiags и f mode файлового объекта в соответствии с флагами режима доступа, переданными системному вызову open;
- инициализирует поля f dent г у и fvfsmnt файлового объекта в соответствии с адресами объекта элемент каталога” и объекта, представляющего смонтированную файловую систему, переданными в качестве параметров;
- записывает в поле f op содержимое поля i_op соответствующего объекта индексный дескриптор”. Это действие устанавливает все методы, необходимые для последующих файловых операций;
- заносит файловый объект в список открытых файлов, на который указывает поле s_f iies суперблока файловой системы;
- если метод open определен среди файловых операций, функция вызывает его;
- вызывает fiie ra state init () для инициализации структур данных опережающего чтения
- если флаг o direct установлен, функция проверяет, можно ли выполнить операции прямого ввода/вывода на этом файле - возвращает адрес файлового объекта;
• возвращает адрес файлового объекта.
4. Записывает в current->fiies->fd[fd] адрес файлового объекта, возвращенный функцией dentry open .
5. Возвращает fd.
Системные вызовы readQ и writeQ
Вернемся к коду программы ср. Системный вызов open возвращает два дескриптора файла, которые сохраняются в переменных inf и outf. Далее программа входит в цикл, на каждом шаге которого очередная порция файла /floppy/TEST копируется в локальный буфер (системный вызов read ()), а затем данные из локального буфера записываются в файл /tmp/test (системный
ВЫЗОВ write о).
Системные ВЫЗОВЫ read И write во многом схожи. Оба принимают три параметра: дескриптор файла fd, адрес buf некоторой области памяти (буфера, содержащего пересылаемые данные) и число count, указывающее, сколько байтов должно быть передано. Естественно, read о пересылает данные из файла в буфер, a write о — в обратном направлении. Оба системных вызова возвращают либо количество успешно переданных байтов, либо -1, что является индикатором ошибки.

Если возвращено значение, меньшее, чем count, это не означает, что произошла ошибка. Ядро имеет право в любой момент прервать системный вызов, даже если не все запрошенные байты были получены. Пользовательское приложение должно проверять возвращаемое значение и повторять системный вызов, если это необходимо. Как правило, небольшое значение возвращается, когда выполняется чтение из канала или терминального устройства, когда достигнут конец файла или когда системный вызов прерван сигналом. Состояние конец файла” (EOF) легко распознается по нулевому значению, возвращенному системным вызовом read . Это состояние не следует путать с аварийным завершением по сигналу. Если read прерывается сигналом до чтения данных, возникнет ошибка.

Операция чтения или записи всегда выполняется с точки, определяемой файловым указателем (полем f pos файлового объекта). Оба системных вызова обновляют файловый указатель, увеличивая его на количество переданных байтов.

Опуская подробности, можно сказать, что sys reado (служебная процедура системного вызова read о) и syswriteo (служебная процедура системного вызова write о) выполняют практически одни и те же действия. Каждая из них:
1. Вызывает функцию fget light о, чтобы по дескриптору fd вычислить адрес file соответствующего файлового объекта
2. Если флаги в fiie->f_mode запрещают доступ запрошенного типа (операцию записи или чтения), служебная процедура возвращает код ошибки
-EBADF.
3. Если у объекта file нет файловой операции read о или aio readO (соответственно, write ИЛИ aio write ), ВОЗВращаеТСЯ КОД Ошибки -EINVAL.
4. Вызывает функцию access oko для грубой проверки параметров buf иcount
5. Вызывает функцию rw_verify_area, чтобы проверить, нет ли конфликтующих обязательных блокировок для соответствующей порции файла. Если это так, служебная процедура возвращает код ошибки или приоста
навливает текущий процесс, если блокировка была установлена с помощью команды f setlkw (см. разд. "Блокировка файлов” далее в этой главе).
6. Вызывает метод file->f_op->read (соответственно, file->f_op->write) для передачи данных, если он определен; в противном случае вызывает метод file->f_op->aio_read (file->f_op->aio_write). Все ЭТИ методы, обсуждае- мые в главе 16, возвращают фактически переданное количество байтов. В качестве побочного эффекта обновляется файловый указатель.
7. Вызывает fput light , чтобы освободить файловый объект.
8. Возвращает фактически переданное количество байтов.

Предыдущая страница | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | Следующая страница




Возможно, Вас также заинтересует:

ОС Knoppix - это Linux без проблем

ВведениеЕсли вы цените свое время, умеете считать деньги и знаете стоимость информации, то эта книга для вас. А так как к книге прилагается компакт- диск с готовой к работе операционной системой Knoppix Live CD, то лишь достаточно вставить его в привод и перегрузить компьютер,...

Linux Kernel (Ядро линукса) (часть 1)

Спин-блокировкаСпин-блокировка необходима в многопроцессорной системе, потому что могут возникнуть другие прерывания того же типа, и другие процессоры могут приступить к их обработке. Без спин-блокировки к главному дескриптору прерывания могли бы обратиться сразу несколько процессоров. Как мы...

Linux Kernel (Ядро линукса) (часть 2)

Копирование при записи В системах Unix первых поколений создание процесса было реализовано довольно неуклюже: получив системный вызов fork о, ядро в буквальном смысле дублировало все адресное пространство родителя и присваивало копию процессу-потомку. Такая операция...

Linux Kernel (Ядро линукса) (часть 3)

Буферы блоков и головы буферовУ каждого буфера есть дескриптор голова буфера, имеющий тип buffer head. Этот дескриптор содержит всю информацию, необходимую ядру для работы с блоком, так что перед обработкой блока ядро обязательно проверяет голову...