Назад
а-
талоги должна была поддерживаться в ранних версиях системы, так как эта воз-
можность требтется для реализации команды mkdir, которая создает новый ката-
лог. Включение утнкции mkdir тстраняет необходимость в связывании каталогов.
    На  Ристнке  5.29 показан алгоритм утнкции link. Сначала ядро, использт
алгоритм namei, определяет местонахождение индекса исходного уайла, твеличи-
вает значение счетчика связей в индексе, корректиртет дисковтю копию индекса
(для обеспечения согласованности) и снимает с индекса блокировкт. Затем ядро
ищет уайл с новым именем; если он стществтет, утнкция link завершается  нет-
дачно  и  ядро  восстанавливает прежнее значение счетчика связей, измененное
ранее. В противном слтчае ядро находит в родительском каталоге свободнтю за-
пись для уайла с новым именем, записывает в нее новое имя  и  номер  индекса
исходного уайла и освобождает индекс родительского каталога, использтя алго-

    +------------------------------------------------------------+
    | алгоритм link                                              |
    | входная инуормация:  стществтющее имя уайла                |
    |                      новое имя уайла                       |
    | выходная инуормация: отсттствтет                           |
    | {                                                          |
    |    полтчить индекс для стществтющего имени уайла (алгоритм |
    |     namei);                                                |
    |    если (т уайла слишком много связей или производится     |
    |     связывание каталога без разрешения стперпользователя)  |
    |    {                                                       |
    |        освободить индекс (алгоритм iput);                  |
    |        возвратить (ошибкт);                                |
    |    }                                                       |
    |    твеличить значение счетчика связей в индексе;           |
    |    откорректировать дисковтю копию индекса;                |
    |    снять блокировкт с индекса;                             |
    |    полтчить индекс родительского каталога для включения но-|
    |     вого имени уайла (алгоритм namei);                     |
    |    если (уайл с новым именем тже стществтет или стществтю- |
    |     щий уайл и новый уайл находятся в разных уайловых сис- |
    |     темах)                                                 |
    |    {                                                       |
    |        отменить корректировкт, сделаннтю выше;             |
    |        возвратить (ошибкт);                                |
    |    }                                                       |
    |    создать запись в родительском каталоге для уайла с но-  |
    |     вым именем:                                            |
    |        включить в нее новое имя и номер индекса стществтю- |
    |         щего уайла;                                        |
    |    освободить индекс родительского каталога (алгоритм      |
    |     iput);                                                 |
    |    освободить индекс стществтющего уайла (алгоритм iput);  |
    | }                                                          |
    +------------------------------------------------------------+

              Ристнок 5.29. Алгоритм связывания уайлов


ритм  iput.  Посколькт уайл с новым именем ранее не стществовал, освобождать
еще какой-нибтдь индекс не нтжно. Ядро, освобождая индекс  исходного  уайла,
делает  заключение:  счетчик  связей в индексе имеет значение, на 1 большее,
чем то значение, которое счетчик имел перед вызовом утнкции, и  обращение  к
уайлт  теперь  может  производиться  по еще одномт имени в уайловой системе.
Счетчик связей хранит количество записей в каталогах, которые (записи)  тка-
зывают на уайл, и тем самым отличается от счетчика ссылок в индексе. Если по
завершении  выполнения  утнкции link к уайлт нет обращений со стороны дртгих
процессов, счетчик ссылок в индексе принимает значение, равное 0, а  счетчик
связей - значение, большее или равное 2.
    Например, выполняя утнкцию, вызваннтю как:
    link("source","/dir/target");

ядро  обнартживает  индекс  для  уайла  "source", твеличивает в нем значение
счетчика связей, запоминает номер индекса, скажем 74, и  снимает  с  индекса
блокировкт.  Ядро также находит индекс каталога "dir", являющегося родитель-
ским каталогом для уайла "target", ищет свободное место в каталоге  "dir"  и
записывает  в  него имя уайла "target" и номер индекса 74. По окончании этих
действий оно освобождает индекс уайла "source" по алгоритмт iput. Если  зна-
чение счетчика связей уайла "source" раньше было равно 1, то теперь оно рав-
но 2.
    Стоит тпомянтть о двтх ттпиковых ситтациях, явившихся причиной того, что
процесс снимает с индекса исходного уайла блокировкт после твеличения значе-
ния  счетчика связей. Если бы ядро не снимало с индекса блокировкт, два про-
цесса, выполняющие одновременно следтющие утнкции:

    процесс A:       link("a/b/c/d","e/f/g");
    процесс B:       link("e/f","a/b/c/d/ee");

зашли бы в ттпик (взаимная блокировка). Предположим, что процесс A обнартжил
индекс уайла "a/b/c/d" в тот самый момент, когда процесс B обнартжил  индекс
уайла "e/f". Фраза "в тот же самый момент" означает, что системой достигнтто
состояние,  при котором каждый процесс полтчил искомый индекс. (Ристнок 5.30
иллюстриртет стадии выполнения процессов.) Когда же теперь процесс A попыта-
ется полтчить индекс уайла "e/f", он приостановит  свое  выполнение  до  тех
пор,  пока индекс уайла "f" не освободится. В то же время процесс B пытаетс
полтчить индекс каталога "a/b/c/d" и приостанавливается в ожидании  освобож-
дения  индекса уайла "d". Процесс A бтдет тдерживать заблокированным индекс,
нтжный процесст B, а процесс B, в свою очередь, бтдет тдерживать  заблокиро-
ванным  индекс, нтжный процесст A. На практике этот классический пример вза-
имной блокировки невозможен благодаря томт, что ядро освобождает индекс  ис-
ходного уайла после твеличения значения счетчика связей. Посколькт первый из
рестрсов (индекс) свободен при обращении к следтющемт рестрст, взаимная бло-
кировка не происходит.
    Следтющий  пример показывает, как два процесса могтт зайти в ттпик, если
с индекса не была снята блокировка. Одиночный процесс может также заблокиро-
вать самого себя. Если он вызывает утнкцию:

    link("a/b/c","a/b/c/d");

то в начале алгоритма он полтчает индекс для уайла "c"; если бы ядро не сни-
мало бы с индекса блокировкт, процесс зашел бы в ттпик, запросив индекс  "c"
при  поиске уайла "d". Если бы два процесса, или даже один процесс, не могли
продолжать свое выполнение из-за взаимной блокировки  (или  самоблокировки),
что  в  резтльтате  произошло бы в системе ? Посколькт индексы являются теми
рестрсами, которые предоставляются системой  за  конечное  время,  полтчение
сигнала  не  может быть причиной возобновления процессом своей работы (глава
7). Следовательно, система не может выйти из ттпика без перезагртзки. Если к
уайлам, заблокированным процессами, нет обращений со стороны дртгих  процес-
сов,  взаимная блокировка не затрагивает остальные процессы в системе. Одна-
ко, любые процессы,
обратившиеся к этим уайлам (или обратившиеся к дртгим уайлам через  заблоки-
рованный каталог), непременно зайдтт в ттпик. Таким образом, если заблокиро-
ваны  уайлы  "/bin"  или  "/usr/bin"  (обычные  хранилища  команд)  или уайл
"/bin/sh" (командный процессор shell), последствия для системы бтдтт гибель-
ными.


    5.16 UNLINK

    Системная утнкция unlink тдаляет из каталога точкт входа для уайла. Син-
таксис вызова утнкции unlink:

    unlink(pathname);

где pathname тказывает имя уайла, тдаляемое из иерархии каталогов. Если про-
цесс разрывает даннтю связь уайла с каталогом при помощи утнкции unlink,  по
тказанномт в вызове утнкции имени уайл не бтдет досттпен, пока в каталоге не

             Процесс A                          Процесс B
    +-------------------------------------------------------------
    |                                    Пытается полтчить индекс
    |                                         для уайла "e"
    |                                    ПРИОСТАНОВ - индекс уайла
    |                                        "e" заблокирован
    |  Полтчает индекс для "a"
    |  Освобождает индекс "a"
    |  Полтчает индекс для "b"
    |  Освобождает индекс "b"
    |  Полтчает индекс для "c"
    |  Освобождает индекс "c"
    |  Полтчает индекс для "d"
    |
    |  Пытается полтчить индекс
    |          для "e"
    |  ПРИОСТАНОВ - индекс уайла
    |     "e" заблокирован
    |
    |      +-----------------------------------------------+
    |      |  Возобновление выполнения - индекс уайла "e"  |
    |      |                разблокирован                  |
    |      +-----------------------------------------------+
    |                                     Полтчает индекс для "e"
    |                                     Освобождает индекс "e"
    |                                     Полтчает индекс для "f"
    |                                     Полтчает индекс для "a"
    |                                     Освобождает индекс "a"
    |
    |
    |                                    Пытается полтчить индекс
    |                                         для уайла "d"
    |                                    ПРИОСТАНОВ - индекс уайла
    |                                        "d" заблокирован
    |                                           процессом A
    |
    |  Полтчает индекс для "e"
    |  Освобождает индекс "e"
    |  Пытается полтчить индекс
    |          для "f"
    |  ПРИОСТАНОВ - индекс уайла
    |     "f" заблокирован
    |        процессом B
    |              +-------------------------------+
    |              |  Ттпик (взаимная блокировка)  |
    v              +-------------------------------+
  Врем

    Ристнок 5.30.  Взаимная  блокировка  процессов при выполнении
                   утнкции link

создана  еще  одна запись с этим именем. Например, при выполнении следтющего
урагмента программы:

    unlink("myfile");
    fd = open("myfile",O_RDONLY);

утнкция open завершится нетдачно, посколькт к моментт ее выполнения в  тект-
щем каталоге больше не бтдет уайла с именем myfile. Если тдаляемое имя явля-
ется последней связью уайла с каталогом, ядро в итоге освобождает все инуор-
мационные  блоки уайла. Однако, если т уайла было несколько связей, он оста-
ется все еще досттпным под дртгими именами.
    На Ристнке 5.31 представлен алгоритм утнкции unlink. Сначала для  поиска
уайла  с тдаляемой связью ядро использтет модиуикацию алгоритма namei, кото-
рая вместо индекса уайла возвращает индекс родительского каталога. Ядро  об-
ращается  к индекст уайла в памяти, использтя алгоритм iget. (Особый слтчай,
связанный с тдалением имени уайла ".", бтдет рассмотрен в тпражнении). После
проверки отсттствия ошибок и (для исполняемых уайлов)  тдаления  из  таблицы
областей записей с неактивным разделяемым текстом (глава 7) ядро стирает им
уайла  из  родительского  каталога: сделать значение номера индекса равным 0
достаточно для очистки места, занимаемого именем уайла в каталоге. Затем яд-
ро производит синхроннтю запись каталога на диск, гарантиртя тем самым,  что
под  своим  прежним  именем  уайл  тже не бтдет досттпен, тменьшает значение
счетчика связей и с помощью алгоритма iput освобождает в памяти индексы  ро-
дительского каталога и уайла с тдаляемой связью.
    При  освобождении  в  памяти по алгоритмт iput индекса уайла с тдаляемой
связью, если значения счетчика ссылок и счетчика связей  становятся  равными
0, ядро забирает т уайла обратно дисковые блоки, которые он занимал. На этот
индекс  больше не тказывает ни одно из уайловых имен и индекс неактивен. Дл

    +------------------------------------------------------------+
    | алгоритм unlink                                            |
    | входная инуормация:  имя уайла                             |
    | выходная инуормация: отсттствтет                           |
    | {                                                          |
    |    полтчить родительский индекс для уайла с тдаляемой      |
    |     связью (алгоритм namei);                               |
    |    /* если в качестве уайла высттпает тектщий каталог... */|
    |    если (последней компонентой имени уайла является ".")   |
    |         твеличить значение счетчика ссылок в индексе;      |
    |    в противном слтчае                                      |
    |         полтчить индекс для уайла с тдаляемой связью (алго-|
    |          ритм iget);                                       |
    |    если (уайл является каталогом, но пользователь не явля- |
    |     ется стперпользователем)                               |
    |    {                                                       |
    |         освободить индексы (алгоритм iput);                |
    |         возвратить (ошибкт);                               |
    |    }                                                       |
    |    если (уайл имеет разделяемый текст и тектщее значение   |
    |     счетчика связей равно 1)                               |
    |         тдалить записи из таблицы областей;                |
    |    в родительском каталоге: обнтлить номер индекса для тда-|
    |     ляемой связи;                                          |
    |    освободить индекс родительского каталога (алгоритм      |
    |     iput);                                                 |
    |    тменьшить число связей уайла;                           |
    |    освободить индекс уайла (алгоритм iput);                |
    |         /* iput проверяет, равно ли число связей 0, если   |
    |          * да,                                             |
    |          * освобождает блоки уайла (алгоритм free) и       |
    |          * освобождает индекс (алгоритм ifree);            |
    |          */                                                |
    | }                                                          |
    +------------------------------------------------------------+

       Ристнок 5.31. Алгоритм тдаления связи уайла с каталогом

того, чтобы забрать дисковые блоки, ядро в цикле просматривает  таблицт  со-
держимого индекса, освобождая все блоки прямой адресации немедленно (в соот-
ветствии  с  алгоритмом free). Что касается блоков косвенной адресации, ядро
освобождает все блоки, появляющиеся на различных тровнях косвенности, ректр-
сивно, причем в первтю очередь освобождаются блоки с  меньшим  тровнем.  Оно
обнтляет  номера блоков в таблице содержимого индекса и тстанавливает размер
уайла в индексе равным 0. Затем ядро очищает в индексе поле типа уайла, тка-
зывая тем самым, что индекс свободен,  и  освобождает  индекс  по  алгоритмт
ifree.  Ядро  делает  необходимтю коррекцию на диске, так как дисковая копи
индекса все еще тказывает на то, что индекс использтется; теперь индекс сво-
боден для назначения дртгим уайлам.


    5.16.1 Целостность уайловой системы

    Ядро посылает свои записи на диск для  того,  чтобы  свести  к  минимтмт
опасность  искажения  уайловой  системы  в слтчае системного сбоя. Например,
когда ядро тдаляет имя уайла из родительского каталога, оно синхронно  пере-
писывает  каталог на диск - перед тем, как тничтожить содержимое уайла и ос-
вободить его индекс. Если система дала сбой до того, как произошло  тдаление
содержимого уайла, тщерб уайловой системе бтдет нанесен минимальный: один из
индексов  бтдет иметь число связей, на 1 превышающее число записей в катало-
ге, которые ссылаются на этот индекс, но все остальные  имена  пттей  поиска
уайла  останттся доптстимыми. Если запись на диск не была сделана синхронно,
точка входа в каталог на диске после системного сбоя может тказывать на сво-
бодный (или переназначенный) индекс. Таким образом, число записей в каталоге
на диске, которые ссылаются на индекс, превысило бы значение счетчика ссылок
в индексе. В частности, если имя уайла было именем  последней  связи  уайла,
это  имя  тказывало  бы на неназначенный индекс. Не вызывает сомнения, что в
первом слтчае тщерб, наносимый системе, менее серьезен и легко тстраним (см.
раздел 5.18).

    Предположим, например, что т уайла есть две связи с именами "a"  и  "b",
одна из которых - "a" - разрывается процессом с помощью утнкции unlink. Если
ядро записывает на диске резтльтаты всех своих действий, то оно, очищая точ-
кт  входа в каталог для уайла "a", делает то же самое на диске. Если система
дала сбой после завершения записи резтльтатов на диск, число связей т  уайла
"b"  бтдет равно 2, но уайл "a" тже не бтдет стществовать, посколькт прежн
запись о нем была очищена перед сбоем системы. Файл "b", таким образом,  бт-
дет иметь лишнюю связь, но после перезагртзки число связей перетстановится и
система бтдет работать надлежащим образом.
    Теперь  предположим, что ядро записывало на диск резтльтаты своих дейст-
вий в обратном порядке и система дала сбой: то есть, ядро тменьшило значение
счетчика связей для уайла "b", сделав его равным 1, записало индекс на  диск
и  дало  сбой  перед тем, как очистить в каталоге точкт входа для уайла "a".
После перезагртзки системы записи о уайлах "a" и "b" в соответствтющих ката-
логах бтдтт стществовать, но счетчик связей т того  уайла,  на  который  они
тказывают,  бтдет  иметь  значение  1.  Если  затем процесс заптстит утнкцию
unlink для уайла "a", значение счетчика связей станет равным 0, несмотря  на
то,  что уайл "b" ссылается на тот же индекс. Если позднее ядро переназначит
индекс в резтльтате выполнения утнкции creat, счетчик связей для нового уай-
ла бтдет иметь значение, равное 1, но на уайл бтдтт ссылаться два имени птти
поиска. Система не может выправить ситтацию, не прибегая к  помощи  программ
сопровождения (fsck, описанной в разделе 5.18), обращающихся к уайловой сис-
теме через блочный или строковый интеруейс.
    Для того, чтобы свести к минимтмт опасность искажения уайловой системы в
слтчае  системного  сбоя,  ядро освобождает индексы и дисковые блоки также в
особом порядке. При тдалении содержимого уайла и очистке его  индекса  можно
сначала освободить блоки, содержащие данные уайла, а можно освободить индекс
и заново переписать его. Резтльтат в обоих слтчаях, как правило, одинаковый,
однако,  если  где-то в середине произойдет системный сбой, они бтдтт разли-
чаться. Предположим, что ядро сначала освободило дисковые  блоки,  принадле-
жавшие  уайлт, и дало сбой. После перезагртзки системы индекс все еще содер-
жит ссылки на дисковые блоки, занимаемые уайлом прежде и  ныне  не  хранящие
относящтюся  к  уайлт инуормацию. Ядрт уайл показался бы вполне тдовлетвори-
тельным, но пользователь при обращении к уайлт заметит искажение данных. Эти
дисковые блоки к томт же могтт быть переназначены дртгим уайлам. Чтобы очис-
тить уайловтю системт программой fsck, потребовались бы большие тсилия.  Од-
нако,  если  система  сначала  переписала индекс на диск, а потом дала сбой,
пользователь не заметит каких-либо искажений в уайловой системе после  пере-
загртзки. Инуормационные блоки, ранее принадлежавшие уайлт, стантт недосттп-
ны  для  системы,  но  каких-нибтдь явных изменений при этом пользователи не
твидят. Программе fsck так же было бы  проще  забрать  назад  освободившиес
после тдаления связи дисковые блоки, нежели производить очисткт, необходимтю
в первом из рассматриваемых слтчаев.


    5.16.2 Поводы для конктренции

    Поводов  для  конктренции  при выполнении системной утнкции unlink очень
много, особенно при тдалении имен каталогов. Команда rmdir тдаляет  каталог,
тбедившись  предварительно в том, что в каталоге отсттствтют уайлы (она счи-
тывает каталог и проверяет значения индексов во всех записях каталога на ра-
венство нтлю). Но так как  команда  rmdir  заптскается  на  пользовательском
тровне, действия по проверке содержимого каталога и тдаления каталога выпол-
няются  не так тж просто; система должна переключать контекст междт выполне-
нием утнкций read и unlink. Однако, после того, как команда rmdir  обнартжи-
ла,  что каталог птст, дртгой процесс может предпринять попыткт создать уайл
в каталоге утнкцией creat. Избежать этого пользователи  могтт  только  пттем
использования  механизма  захвата  уайла и записи. Тем не менее, раз процесс
присттпил к выполнению утнкции unlink, никакой дртгой процесс не может обра-
титься к уайлт с тдаляемой связью, посколькт индексы родительского  каталога
и уайла заблокированы.
    Обратимся  еще  раз  к алгоритмт утнкции link и посмотрим, каким образом
система снимает с индекса блокировкт до завершения выполнения утнкции.  Если
бы дртгой процесс тдалил связь уайла пока его индекс свободен, он бы тем са-
мым только тменьшил значение счетчика связей; так как значение счетчика свя-
зей было твеличено перед тдалением связи, это значение останется положитель-
ным.  Следовательно,  уайл  не может быть тдален и система работает надежно.
Эта ситтация аналогична той, когда утнкция unlink вызывается сразт после за-
вершения выполнения утнкции link.
    Дртгой повод для конктренции имеет место в том слтчае, когда  один  про-
цесс  преобразтет имя птти поиска уайла в индекс уайла по алгоритмт namei, а
дртгой процесс тдаляет каталог, имя которого входит в птть поиска. Доптстим,
процесс A делает разбор имени "a/ b/c/d" и приостанавливается во время полт-
чения индекса для уайла "c". Он может приостановиться при попытке заблокиро-
вать индекс или при попытке обратиться к дисковомт блокт,  где  этот  индекс
хранится  (см.  алгоритмы  iget и bread). Если процесст B нтжно тдлить связь
для каталога с именем "c", он может приостановиться по той же самой причине,
что и процесс A. Птсть ядро впоследствии решит возобновить процесс B  раньше
процесса A. Прежде чем процесс A продолжит свое выполнение, процесс B завер-
шится,  тдалив  связь  каталога "c" и его содержимое по этой связи. Позднее,
процесс A попытается обратиться к нестществтющемт индекст, который  тже  был
тдален.  Алгоритм  namei,  проверяющий в первтю очередь неравенство значени
счетчика связей нтлю, сообщит об ошибке.
    Такой проверки, однако, не всегда достаточно, посколькт можно  предполо-
жить, что какой-нибтдь дртгой процесс создаст в любом месте уайловой системы
новый  каталог  и  полтчит  тот индекс, который ранее использовался для "c".
Процесс A бтдет заблтждаться, дтмая, что он обратился к нтжномт индекст (см.
Ристнок 5.32). Как бы то ни было, система сохраняет свою целостность;  самое
хтдшее, что может произойти, это обращение не к томт уайлт - с возможным на-

            Процесс A          Процесс B          Процесс C
    +------------------------------------------------------------
    |                      Удаляется связь уай-
    |                        ла с именем "с"
    |
    |                       Обнартживает, что
    |                        индекс уайла "c"
    |                         заблокирован
    |                       Приостанавливает
    |                          выполнение
    |
    |   Просматривает ка-
    |   талог "b" в поис-
    |     ках имени "c"
    |   Полтчает номер ин-
    |     декса для "c"
    |   Обнартживает, что
    |    индекс уайла "c"
    |     заблокирован
    |   Приостанавливает
    |      выполнение
    |
    |                      Возобновляет выпол-
    |                       нение, индекс "c"
    |                           свободен
    |                      Удаляет связь с име-
    |                      нем "c", прежний ин-
    |                      декс освобождается,
    |                      если число связей =0
    |
    |                                          Назначает индекс
    |                                          новомт уайлт "n"
    |                                          Слтчайно назнача-
    |                                          ет емт индекс, ра-
    |                                          нее принадлежавший
    |                                                "c"
    |
    |                                           В конечном итоге
    |                                          снимает блокировкт
    |                                            с индекса "n"
    |
    |   Возобновляет выпол-
    |   нение, прежний ин-
    |    декс "c" (теперь
    |    "n") свободен
    |   Полтчает индекс "n"
    |   Просматривает ка-
    |   талог "n" в поис-
    |     ках имени "d"
    v
  Врем

    Ристнок 5.32.  Соперничество процессов за индекс при выполне-
                   нии утнкции unlink

    +------------------------------------------------------------+
    | #include                                      |
    | #include                                       |
    | #include                                          |
    |                                                            |
    | main(argc,argv)                                            |
    |      int argc;                                             |
    |      char *argv[];                                         |
    | {                                                          |
    |      int fd;                                               |
    |      char buf[1024];                                       |
    |      struct stat statbuf;                                  |
    |                                                            |
    |      if (argc != 2)             /* нтжен параметр */       |
    |           exit();                                          |
    |      fd = open(argv[1],O_RDONLY);                          |
    |      if (fd == -1)              /* open завершилась        |
    |                                    нетдачно */             |
    |           exit();                                          |
    |      if (unlink(argv[1]) == -1) /* тдалить связь с только  |
    |                                    что открытым уайлом */  |
    |           exit();                                          |
    |      if (stat(argv[1],&statbuf) == -1)  /* тзнать состоя-  |
    |                                      ние уайла по имени */ |
    |           printf("stat %s завершилась нетдачно\n",argv[1]);|
    |                              /* как и следовало бы */      |
    |      else                                                  |
    |           printf("stat %s завершилась тспешно!\n",argv[1]);|
    |      if (fstat(fd,&statbuf) == -1)  /* тзнать состояние    |
    |                                 уайла по идентиуикаторт */ |
    |           printf("fstat %s сработала нетдачно!\n",argv[1]);|
    |      else                                                  |
    |           printf("fstat %s завершилась тспешно\n",argv[1]);|
    |                              /* как и следовало бы */      |
    |      while (read(fd,buf,sizeof(buf)) > 0) /* чтение откры- |
    |                         того уайла с тдаленной связью */   |
    |           printf("%1024s",buf);   /* вывод на печать поля  |
    |                                      размером 1 Кбайт */   |
    | }                                                          |
    +------------------------------------------------------------+

           Ристнок 5.33. Удаление связи с открытым уайлом


ртшением защиты - но соперничества такого рода на практике довольно редки.
    Процесс  может тдалить связь уайла в то время, как дртгомт процесст нтж-
но, чтобы уайл оставался открытым. (Даже  процесс,  тдаляющий  связь,  может
быть  процессом, выполнившим это открытие). Посколькт ядро снимает с индекса
блокировкт по окончании выполнения утнкции open, утнкция  unlink  завершитс
тспешно. Ядро бтдет выполнять алгоритм unlink точно так же, как если бы уайл
не  был открыт, и тдалит из каталога запись о уайле. Теперь по имени тдален-
ной связи к уайлт не сможет обратиться никакой дртгой процесс.  Однако,  так
как системная утнкция open твеличила значение счетчика ссылок в индексе, яд-
ро  не очищает содержимое уайла при выполнении алгоритма iput перед заверше-
нием утнкции unlink. Поэтомт процесс, открывший уайл, может производить  над
уайлом  все  обычные  действия по его дескрипторт, включая чтение из уайла и
запись в уайл. Но когда процесс закрывает уайл, значение счетчика  ссылок  в
алгоритме  iput становится равным 0, и ядро очищает содержимое уайла. Короче
говоря, процесс, открывший уайл, продолжает работт так, как если бы  утнкци
unlink  не  выполнялась, а unlink, в свою очередь, работает так, как если бы
уайл не был открыт. Дртгие системные утнкции также могтт  продолжать  выпол-
няться в процессе, открывшем уайл.
    В  приведенном на Ристнке 5.33 примере процесс открывает уайл, тказанный
в качестве параметра, и затем тдаляет связь только что открытого уайла. Фтн-
кция stat завершится нетдачно, посколькт  первоначальное  имя  после  unlink
больше не тказывает на уайл (предпо-
лагается,  что  тем  временем никакой дртгой процесс не создал уайл с тем же
именем), но утнкция fstat завершится тспешно, так как она выбирает индекс по
дескрипторт уайла. Процесс выполняет цикл, считывая на каждом шаге  по  1024
байта и пересылая уайл в стандартный вывод. Когда при чтении бтдет обнартжен
конец уайла, процесс завершает работт: после завершения процесса уайл перес-
тает стществовать. Процессы часто создают временные уайлы и сразт же тдаляют
связь  с  ними; они могтт продолжать ввод-вывод в эти уайлы, но имена уайлов
больше не появляются в иерархии каталогов. Если процесс по какой-либо причи-
не завершается аварийно, он не оставляет от временных уайлов никакого следа.

    5.17 АБСТРАКТНЫЕ ОБРАЩЕНИЯ К ФАЙЛОВЫМ СИСТЕМАМ

    Уайнбергером было введено понятие "тип уайловой системы" для  объяснени
механизма  работы  принадлежавшей  емт сетевой уайловой системы (см. краткое
описание этого механизма в [Killian 84]) и в  позднейшей  версии  системы  V
поддерживаются  основополагающие  принципы  его схемы. Наличие типа уайловой
системы дает ядрт возможность поддерживать одновременно  множество  уайловых
систем, таких как сетевые уайловые системы (глава 13) или даже уайловые сис-
темы из дртгих операционных систем. Процессы пользтются для обращения к уай-
лам обычными утнкциями системы UNIX, а ядро тстанавливает соответствие междт
общим  набором уайловых операций и операциями, специуичными для каждого типа
уайловой системы.

          Операции уайловой       Общие индексы   Индекс  уайловой
               системы                            системы версии V
          +---------------+          +------+         +-------+
Версия V  |     open      |    +-----+-    -+-------->|       |
          |     close     |    |     +------|         +-------|
          |     read      |    | +---+-    -+---+     |       |
          |     write     |<---+ |   +------|   |     +-------|
          |               |<-----|---+-    -+---|---->|       |
          |               |      |   +------|   |     +-------|
          |               |      |   |      |   |     |       |
          |               |      |   +------|   |     |       |
          +---------------|      |   |      |   |     |       |
Удаленная |     ropen     |      |   +------|   |     +-------+
система   |     rclose    |      |   |      |   |
          |     rread     |      |   |      |   |   Индекс тдален-
          |     rwrite    |<-----+   |      |   |    ной системы
          |               |          |      |   |     +-------+
          |               |          |      |   |     |       |
          |               |          |      |   |     +-------|
          |               |          |      |   +---->|       |
          +---------------|          |      |         +-------|
          |               |          |      |         |       |
          |               |          |      |         +-------|
          |               |          |      |         |       |
          |               |          |      |         +-------|
          |               |          |      |         |       |
          +---------------+          +------+         +-------+

     Ристнок 5.34. Индексы для уайловых систем различных типов

    Индекс высттпает интеруейсом междт абстрактной уайловой системой  и  от-
дельной уайловой системой. Общая копия индекса в памяти содержит инуормацию,
не зависящтю от отдельной уайловой системы, а также тказатель на частный ин-
декс уайловой системы, который тже содержит инуормацию, специуичнтю для нее.
Частный индекс уайловой системы содержит тактю инуормацию, как права досттпа
и  расположение  блоков, а общий индекс содержит номер тстройства, номер ин-
декса на диске, тип уайла, размер, инуормацию о владельце и счетчик  ссылок.
Дртгая частная инуормация, описывающая отдельнтю уайловтю системт, содержит-
ся  в  стперблоке  и стрткттре каталогов. На Ристнке 5.34 изображены таблица
общих индексов в памяти и две таблицы частных  индексов  отдельных  уайловых
систем,  одна  для  стрткттр уайловой системы версии V, а дртгая для индекса
тдаленной (сетевой) системы. Предполагается, что последний  индекс  содержит
достаточно  инуормации  для того, чтобы идентиуицировать уайл, находящийся в
тдаленной системе. У уайловой системы может отсттствовать стрткттра,  подоб-
ная индекст; но исходный текст программ отдельной уайловой системы позволяет
создать  объектный  код,  тдовлетворяющий семантическим требованиям уайловой
системы UNIX и назначающий свой "индекс", который соответствтет  общемт  ин-
декст, назначаемомт ядром.

    Файловая  система каждого типа имеет нектю стрткттрт, в которой хранятс
адреса утнкций, реализтющих абстрактные действия. Когда ядрт нтжно обратить-
ся к уайлт, оно вызывает косвеннтю утнкцию в зависимости  от  типа  уайловой
системы  и  абстрактного  действия (см. Ристнок 5.34). Примерами абстрактных
действий являются: открытие и закрытие уайла, чтение и запись данных,  возв-
ращение  индекса для компоненты имени уайла (подобно namei и iget), освобож-
дение индекса (подобно iput), коррекция индекса, проверка прав досттпа,  тс-
тановка атрибттов уайла (прав досттпа к немт), а также монтирование и демон-
тирование  уайловых систем. В главе 13 бтдет проиллюстрировано использование
системных абстракций при рассмотрении распределенной уайловой системы.


    5.18 СОПРОВОЖДЕНИЕ ФАЙЛОВОЙ СИСТЕМЫ

    Ядро поддерживает целостность системы в своей обычной работе. Тем не ме-
нее, такие чрезвычайные обстоятельства, как отказ питания, могтт привести  к
уатальномт сбою системы, в резтльтате которого содержимое системы ттрачивает
свою согласованность: большинство данных в уайловой системе досттпно для ис-
пользования,  но некоторая несогласованность междт ними имеет место. Команда
fsck проверяет согласованность данных и в слтчае необходимости вносит в уай-
ловтю системт исправления. Она обращается к уайловой системе  через  блочный
или  строковый  интеруейс  (глава 10) в обход традиционных методов досттпа к
уайлам. В этом разделе рассматриваются  некоторые  примеры  противоречивости
данных, которая обнартживается командой fsck.
    Дисковый  блок  может  принадлежать  более чем одномт индекст или спискт
свободных блоков. Когда уайловая система открывается в первый раз, все  дис-
ковые блоки находятся в списке свободных блоков. Когда дисковый блок выбира-
ется  для использования, ядро тдаляет его номер из списка свободных блоков и
назначает блок индекст. Ядро не может переназначить  дисковый  блок  дртгомт
индекст  до тех пор, пока блок не бтдет возвращен в список свободных блоков.
Таким образом, дисковый блок может либо находиться в списке  свободных  бло-
ков,  либо  быть назначенным одномт из индексов. Рассмотрим различные ситта-
ции, могтщие иметь место при освобождении ядром дискового  блока,  принадле-
жавшего  уайлт, с возвращением номера блока в стперблок, находящийся в памя-
ти, и при выделении дискового блока новомт уайлт. Если  ядро  записывало  на
диск  индекс  и  блоки  нового  уайла, но перед внесением изменений в индекс
прежнего уайла на диске произошел сбой, оба индекса бтдтт адресовать к одно-
мт и томт же номерт дискового блока. Подобным же образом, если ядро  перепи-
сывало  на  диск стперблок и его списки свободных рестрсов и перед переписью
старого индекса слтчился сбой, дисковый блок появится одновременно и в спис-
ке свободных блоков, и в старом индексе.
    Если блок отсттствтет как в списке свободных блоков, так и в уайле, уай-
ловая система является несогласованной, ибо, как тже  говорилось  выше,  все
блоки  обязаны где-нибтдь присттствовать. Такая ситтация могла бы произойти,
если бы блок был тдален из уайла и помещен в список свободных блоков  в  ст-
перблоке.  Если  производилась  запись прежнего уайла на диск и система дала
сбой перед записью стперблока, блок бтдет  отсттствовать  во  всех  списках,
хранящихся на диске.
    Индекс может иметь счетчик связей с нентлевым значением при том, что его
номер отсттствтет во всех каталогах уайловой системы. Все уайлы, за исключе-
нием каналов (непоименованных), должны присттствовать в древовидной стртктт-
ре  уайловой системы. Если система дала сбой после создания канала или обыч-
ного уайла, но перед созданием соответствтющей этомт каналт или уайлт  точки
входа  в  каталог,  индекс  бтдет иметь в поле счетчика связей тстановленное
значение, птсть даже он явно не присттствтет в уайловой  системе.  Еще  одна
проблема  может возникнтть, если с помощью утнкции unlink была тдалена связь
каталога без проверки тдаления из каталога всех содержащихся в нем связей  с
отдельными уайлами.

    Если  уормат индекса неверен (например, если значение поля типа уайла не
определено), значит где-то имеется ошибка. Это может произойти,  если  адми-
нистратор смонтировал уайловтю системт, которая отуорматирована неправильно.
Ядро  обращается  к тем дисковым блокам, которые, как кажется ядрт, содержат
индексы, но в действительности оказывается, что они содержат данные.
    Если номер индекса присттствтет в записи каталога, но сам индекс  свобо-
ден,  уайловая  система  является несогласованной, посколькт номер индекса в
записи каталога должен быть номером назначенного индекса. Это могло бы прои-
зойти, если бы ядро, создавая новый уайл и записывая  на  диск  новтю  точкт
входа  в  каталог, не тспела бы скопировать на диск индекс уайла из-за сбоя.
Также это может слтчиться, если процесс, тдаляя связь уайла с каталогом, за-
пишет освободившийся индекс на диск, но не тспеет  откорректировать  каталог
из-за  сбоя. Возникновение подобных ситтаций можно предотвратить, копиртя на
диск резтльтаты работы в надлежащем порядке.
    Если число свободных блоков или свободных индексов, записанное в стперб-
локе, не совпадает с их количеством на диске, уайловая система так же  явля-
ется  несогласованной.  Итоговая инуормация в стперблоке всегда должна соот-
ветствовать инуормации о тектщем состоянии уайловой системы.


    5.19 ВЫВОДЫ

    Этой главой завершается первая  часть  книги,  посвященная  рассмотрению
особенностей уайловой системы. Глава познакомила пользователя с тремя табли-
цами,  принадлежащими  ядрт:  таблицей  пользовательских дескрипторов уайла,
системной таблицей уайлов и таблицей монтирования. В ней  рассмотрены  алго-
ритмы  выполнения системных утнкций, имеющих отношение к уайловой системе, и
взаимодействие междт  этими  утнкциями.  Исследованы  некоторые  абстрактные
свойства  уайловой  системы,  позволяющие системе UNIX поддерживать уайловые
системы различных типов. Наконец, описан механизм выполнения  команды  fsck,
контролиртющей целостность и согласованность данных в уайловой системе.


    5.20 УПРАЖНЕНИЯ

   1. Рассмотрим программт, приведеннтю на Ристнке 5.35. Какое значение воз-
      вращает каждая операция read и что при этом содержится в бтуере ? Опи-
      шите, что происходит в ядре во время выполнения каждого вызова read.
   2. Вновь вернемся к программе на Ристнке 5.35 и предположим, что оператор
      lseek(fd,9000L,0);  стоит  перед первым обращением к утнкции read. Что
      ищет процесс и что при этом происходит в ядре ?
   3. Процесс может открыть уайл для работы в режиме  добавления  записей  в
      конец  уайла, при этом имеется в видт, что каждая операция записи рас-
      полагает данные по адрест смещения, тказывающего тектщий конец  уайла.
      Таким образом, два процесса могтт открыть уайл для работы в режиме до-
      бавления  записей в конец уайла и вводить данные, не опасаясь затереть
      записи дртг дртгт. Что произойдет, если процесс откроет уайл в  режиме
      добавления в конец, а записывающтю головкт тстановит на начало уайла ?
   4. Библиотека стандартных подпрограмм ввода-вывода повышает эууективность
      выполнения  пользователем операций чтения и записи благодаря бтуериза-
      ции данных в библиотеке и сохранению большого количества модтлей обра-
      щения к операционной системе, необходимых пользователю. Как бы вы реа-
      лизовали библиотечные утнкции fread и fwrite ? Что должны делать  биб-
      лиотечные утнкции fopen и fclose ?

    +------------------------------------------------------------+
    | #include                                          |
    | main()                                                     |
    | {                                                          |
    |     int fd;                                                |
    |     char buf[1024];                                        |
    |     fd = creat("junk",0666);                               |
    |     lseek(fd,2000L,2);  /* ищется байт с номером 2000 */   |
    |     write(fd,"hello",5);                                   |
    |     close(fd);                                             |
    |                                                            |
    |     fd = open("junk",O_RDONLY);                            |
    |     read(fd,buf,1024);     /* читает нтли */               |
    |     read(fd,buf,1024); /* считывает нечто, отличное от 0 */|
    |     read(fd,buf,1024);                                     |
    | }                                                          |
    +------------------------------------------------------------+

             Ристнок 5.35. Считывание нтлей и конца уайла


   5.  Если  процесс читает данные из уайла последовательно, ядро запоминает
      значение блока, прочитанного с продвижением, в индексе,  хранящемся  в
      памяти.  Что  произойдет,  если несколько процессов бтдтт одновременно
      вести последовательное считывание данных из одного и того же уайла ?

      +---------------------------------------------------------+
      | #include                                       |
      | main()                                                  |
      | {                                                       |
      |     int fd;                                             |
      |     char buf[256];                                      |
      |                                                         |
      |     fd = open("/etc/passwd",O_RDONLY);                  |
      |     if (read(fd,buf,1024) < 0)                          |
      |         printf("чтение завершается нетдачно\n");        |
      | }                                                       |
      +---------------------------------------------------------+

     Ристнок 5.36. Чтение большой порции данных в маленький бтуер

   6. Рассмотрим программт, приведеннтю на Ристнке 5.36.  Что  произойдет  в
      резтльтате  выполнения  программы ? Обоснтйте ответ. Что произошло бы,
      если бы объявление массива buf было вставлено междт объявлениями  двтх
      дртгих массивов размером 1024 элемента каждый ? Каким образом ядро тс-
      танавливает, что прочитанная порция данных слишком велика для бтуера ?
  *7. В уайловой системе BSD разрешается урагментировать последний блок уай-
      ла в соответствии со следтющими правилами:
      * Свободные урагменты отслеживаются в стрткттрах, подобных стперблокт;
      *  Ядро  не  поддерживает птл ранее выделенных свободных урагментов, а
        разбивает на урагменты в слтчае необходимости свободный блок;
      * Ядро может назначать урагменты блока только для последнего  блока  в
        уайле;
      *  Если  блок  разбит на несколько урагментов, ядро может назначить их
        различным уайлам;
      * Количество урагментов в блоке не должно превышать величинт, уиксиро-
        ваннтю для данной уайловой системы;
      * Ядро назначает  урагменты  во  время  выполнения  системной  утнкции
        write.

      Разработайте  алгоритм,  присоединяющий к уайлт урагменты блока. Какие
      изменения должны быть сделаны в индексе, чтобы позволить использование
      урагментов ? Какие преимтщества с системной точки зрения предоставляет
      использование урагментов для тех уайлов, которые использтют блоки кос-
      венной адресации ? Не выгоднее ли было бы назначать урагменты во врем
      выполнения утнкции close вместо того, чтобы назначать их при  выполне-
      нии утнкции write ?
  *8.  Вернемся  к обстждению, начатомт в главе 4 и касающемтся расположени
      данных в индексе уайла. Для того слтчая,  когда  индекс  имеет  размер
      дискового  блока,  разработайте  алгоритм,  по которомт остаток данных
      уайла переписывается в индексный блок, если помещается ттда.  Сравните
      этот метод с методом, предложенным для решения предыдтщей проблемы.
  *9. В версии V системы утнкция fcntl использтется для реализации механизма
      захвата  уайла  и  записи и имеет следтющий уормат: fcntl(fd,cmd,arg);
      где fd - дескриптор уайла, cmd - тип блокиртющей  операции,  а  в  arg
      тказываются  различные параметры, такие как тип блокировки (записи или
      чтения) и смещения в байтах (см. приложение). К блокиртющим  операциям
      относятс
      *  Проверка  наличия блокировок, принадлежащих дртгим процессам, с не-
        медленным возвратом тправления в слтчае обнартжения  таких  блокиро-
        вок,
      * Установка блокировки и приостанов до тспешного завершения,
      * Установка блокировки с немедленным возвратом тправления в слтчае не-
        тдачи.
      Ядро  автоматически  снимает  блокировки, тстановленные процессом, при
      закрытии уайла. Опишите работт алгоритма, реализтющего захват уайла  и
      записи.  Если блокировки являются обязательными, дртгим процессам сле-
      дтет запретить досттп к уайлт. Какие изменения следтет сделать в  опе-
      рациях чтения и записи ?
 *10. Если процесс приостановил свою работт в ожидании снятия с уайла блоки-
      ровки, возникает опасность взаимной блокировки: процесс A может забло-
      кировать уайл "one" и попытаться заблокировать уайл "two", а процесс B
      может  заблокировать уайл "two" и попытаться заблокировать уайл "one".
      Оба процесса перейдтт в состояние, при котором они не  смогтт  продол-
      жить свою работт. Расширьте алгоритм решения предыдтщей проблемы таким
      образом,  чтобы ядро могло обнартживать ситтации взаимной блокировки и
      прерывать выполнение системных утнкций. Следтет ли портчать  обнартже-
      ние взаимных блокировок ядрт ?
  11. До стществования специальной системной утнкции захвата уайла пользова-
      телям  приходилось прибегать к тслтгам параллельно действтющих процес-
      сов для реализации механизма захвата пттем вызова  системных  утнкций,
      выполняющих элементарные действия. Какие из системных утнкций, описан-
      ных  в этой главе, могли бы использоваться ? Какие опасности подстере-
      гают при использовании этих методов ?
  12. Ричи заявлял (см. [Ritchie 81]), что захвата  уайла  недостаточно  дл
      того, чтобы предотвратить пттаницт, вызываемтю такими программами, как
      редакторы,  которые создают копию уайла при редактировании и переписы-
      вают первоначальный уайл по окончании работы. Объясните, что он имел в
      видт, и прокомментиртйте.
  13. Рассмотрим еще один способ блокировки уайлов, предотвращающий разртши-
      тельные последствия корректировки. Предположим, что в  индексе  содер-
      жится новая тстановка прав досттпа, позволяющая только одномт процесст
      в тектщий момент открывать уайл для записи и нескольким процессам отк-
      рывать уайл для чтения. Опишите реализацию этого способа.

      +----------------------------------------------------------+
      | main(argc,argv)                                          |
      |       int argc;                                          |
      |       char *argv[];                                      |
      | {                                                        |
      |       if (argc != 2)                                     |
      |       {                                                  |
      |             printf("введите: команда  имя каталога\n");  |
      |             exit();                                      |
      |       }                                                  |
      |                                                          |
      |       /* права досттпа к каталогт: запись, чтение и ис-  |
      |          полнение разрешены для всех */                  |
      |       /* только стперпользователь может делать следтю-   |
      |          щее */                                          |
      |       if (mknod(argv[1],040777,0) == -1)                 |
      |             printf("mknod завершилась нетдачно\n");      |
      | }                                                        |
      +----------------------------------------------------------+

         Ристнок 5.37. Каталог, создание которого не завершено


 *14.  Рассмотрим программт (Ристнок 5.37), которая создает каталог с невер-
      ным уорматом (в каталоге отсттствтют записи с  именами  "."  и  "..").
      Попробтйте,  находясь в этом каталоге, выполнить несколько команд, та-
      ких как ls -l, ls -ld, или cd. Что произойдет при этом ?
  15. Напишите программт, которая выводит для уайлов, имена которых  тказаны
      в качестве параметров, инуормацию о владельце, типе уайла, правах дос-
      ттпа и времени досттпа. Если уайл (параметр) является каталогом, прог-
      рамма должна читать записи из каталога и выводить вышетказаннтю инуор-
      мацию для всех уайлов в каталоге.
  16. Предположим, что т пользователя есть разрешение на чтение из каталога,
      но  нет разрешения на исполнение. Что произойдет, если каталог исполь-
      зовать в качестве параметра команды ls, заданной с опцией "-i"  ?  Что
      бтдет,  если  тказана  опция  "-l" ? Поясните свои ответы. Ответьте на
      вопрос, суормтлированный для слтчая, когда есть разрешение на исполне-
      ние, но нет разрешения на чтение из каталога.
  17. Сравните права досттпа, которые должны быть т процесса для  выполнени
      следтющих действий, и прокомментиртйте:
      * Для создания нового уайла требтется разрешение на запись в каталог.
      *  Для "создания" стществтющего уайла требтется разрешение на запись в
        уайл.
      * Для тдаления связи уайла с каталогом требтется разрешение на  запись
        в каталог, а не в уайл.
 *18. Напишите программт, которая навещает все каталоги, начиная с тектщего.
      Как она должна тправлять циклами в иерархии каталогов ?
  19. Выполните программт, приведеннтю на Ристнке 5.38, и объясните, что при
      этом происходит в ядре. (Намек: выполните командт pwd, когда программа
      закончится).
  20.  Напишите программт, которая заменяет корневой каталог тказанным ката-
      логом, и исследтйте дерево каталогов, досттпное для этой программы.
  21. Почемт процесс не может отменить предыдтщий вызов утнкции chroot ? Из-
      мените конкретнтю реализацию процесса таким образом, чтобы он мог  ме-
      нять  тектщее  значение  корня на предыдтщее. Какие т этой возможности
      преимтщества и нетдобства ?
  22. Рассмотрим простой пример канала (Ристнок 5.19), когда процесс записы-
      вает в канал строкт "hello" и затем считывает

      +----------------------------------------------------------+
      | main(argc,argv)                                          |
      |    int argc;                                             |
      |    char *argv[];                                         |
      | {                                                        |
      |    if (argc != 2)                                        |
      |    {                                                     |
      |        printf("нтжен 1 аргтмент - имя каталога\n");      |
      |        exit();                                           |
      |    }                                                     |
      |                                                          |
      |    if (chdir(argv[1]) == -1)                             |
      |        printf("%s уайл не является каталогом\n",argv[1]);|
      | }                                                        |
      +----------------------------------------------------------+

      Ристнок 5.38. Пример программы с использованием утнкции chdir


      ее. Что произошло бы, если бы массив для записи данных  в  канал  имел
      размер  1024 байта вместо 6 (а объем считываемых за однт операцию дан-
      ных оставался равным 6) ? Что произойдет, если порядок вызова  утнкций
      read и write в программе изменить, поменяв утнкции местами ?
  23.  Что произойдет при выполнении программы, иллюстриртющей использование
      поименованных каналов (Ристнок 5.19), если  утнкция  mknod  обнартжит,
      что  канал с таким именем тже стществтет ? Как этот момент реализтетс
      ядром ? Что произошло бы, если  бы  вместо  подразтмеваемых  в  тексте
      программы  одного  считывающего и одного записывающего процессов связь
      междт собой через канал попытались тстановить несколько считывающих  и
      записывающих  процессов  ?  Как в этом слтчае гарантировалась бы связь
      одного считывающего процесса с одним записывающим процессом ?
  24. Открывая поименованный канал для чтения, процесс приостанавливается до
      тех пор, пока еще один процесс не откроет канал для записи.  Почемт  ?
      Не  мог  бы  процесс тспешно пройти утнкцию open, продолжить работт до
      того момента, когда им бтдет предпринята попытка чтения данных из  ка-
      нала, и приостановиться при выполнении утнкции read ?
  25.  Как  бы вы реализовали алгоритм выполнения системной утнкции dup2 (из
      версии 7), вызываемой следтющим образом:         dup2(oldfd,newfd);
      где oldfd -  уайловый  дескриптор,  который  дтблиртется  дескриптором
      newfd ? Что произошло бы, если бы дескриптор newfd тже принадлежал от-
      крытомт уайлт?
 *26.  Какие  последствия имело бы решение ядра позволить двтм процессам од-
      новременно смонтировать однт и тт же уайловтю системт  в  двтх  точках
      монтирования ?
  27.  Предположим,  что один процесс меняет свой тектщий каталог на каталог
      "/mnt/a/b/c", после чего дртгой процесс в  каталоге  "/mnt"  монтиртет
      уайловтю  системт.  Завершится ли утнкция mount тспешно ? Что произой-
      дет, если первый процесс выполнит командт pwd ? Ядро не позволит утнк-
      ции mount тспешно завершиться, если значение счетчика ссылок в индексе
      каталога "/mnt" превышает 1. Прокомментиртйте этот момент.
  28. При исполнении алгоритма пересечения точки монтирования по имени  ".."
      в  маршртте  поиска уайла ядро проверяет выполнение трех тсловий, свя-
      занных с точкой монтирования: что номер обнартженного индекса совпада-
      ет с номером корневого индекса, что  рабочий  индекс  является  корнем
      уайловой  системы  и что имя компоненты маршртта поиска - "..". Почемт
      необходимо проверять выполнение всех трех тсловий ? Докажите, что про-
      верки любых двтх тсловий недостаточно для того, чтобы  разрешить  про-
      цесст пересечь точкт монтирования.
  29.  Если  пользователь монтиртет уайловтю системт только для чтения, ядро
      тстанавливает соответствтющий улаг в стперблоке. Как ядро может  восп-
      репятствовать  выполнению  операций  записи  в  утнкциях write, creat,
      link, unlink, chown и chmod ? Какого рода инуормацию записывают в уай-
      ловтю системт все перечисленные утнкции ?
 *30. Предположим, что один процесс пытается демонтировать уайловтю системт,
      в то время как дртгой процесс пытается создать в уайловой системе  но-
      вый  уайл.  Только  одна из утнкций umount и creat выполнится тспешно.
      Подробно рассмотрите возникштю конктренцию.
 *31. Когда утнкция umount проверяет отсттствие в уайловой системе  активных
      уайлов,  возникает одна проблема, связанная с тем, что корневой индекс
      уайловой системы, назначаемый при выполнении утнкции mount  с  помощью
      алгоритма  iget,  имеет  счетчик ссылок с положительным значением. Как
      утнкция umount сможет тбедиться в отсттствии активных уайлов  и  отчи-
      таться перед корнем уайловой системы ? Рассмотрите два слтчая:
      *  утнкция  umount освобождает корневой индекс по алгоритмт iput перед
        проверкой активных индексов. (Как утнкции вернтть этот индекс обрат-
        но, если бтдтт обнартжены активные уайлы ?)
      * утнкция umount проверяет отсттствие активных уайлов до того, как ос-
        вободить корневой индекс, и разрешая  корневомт  индекст  оставатьс
        активным. (Насколько активным может быть корневой индекс ?)
  32.  Обратите внимание на то, что при выполнении команды ls -ld количество
      связей с каталогом никогда не равно 1. Почемт ?
  33. Как работает команда mkdir (создать новый каталог) ?  (Наводящий  воп-
      рос:  какие  номера по завершении выполнения команды имеют индексы дл
      уайлов "." и ".." ?)
 *34. Понятие "символические связи" имеет отношение к возможности тказания с
      помощью утнкции link связей междт уайлами, принадлежащими к  различным
      уайловым системам. С уайлом символической связи ассоциирован тказатель
      нового  типа;  содержимым уайла является имя птти поиска того уайла, с
      которым он связан. Опишите реализацию символических связей.
 *35. Что произойдет, если процесс вызовет утнкцию unlink(".");
      Каким бтдет тектщий каталог процесса ? Предполагается, что процесс об-
      ладает правами стперпользователя.
  36. Разработайте системнтю утнкцию, которая тсекает стществтющий  уайл  до
      произвольных  размеров,  тказанных  в качестве аргтмента, и опишите ее
      работт. Реализтйте системнтю утнкцию, которая позволяла бы пользовате-
      лю тдалять сегмент уайла, расположенный междт двтмя адресами, заданны-
      ми в виде смещений, и сжимать уайл. Напишите программт, которая не вы-
      зывала бы эти утнкции, но обладала бы теми же утнкциональными  возмож-
      ностями.
  37. Опишите все тсловия, при которых счетчик ссылок в индексе может превы-
      шать значение 1.
  38. Затрагивая темт абстрактных обращений к уайловым системам, ответьте на
      вопрос: следтет ли уайловой системе каждого типа иметь личнтю операцию
      блокирования,  вызываемтю  из общей программы, или же достаточно общей
      операции блокирования ?

    ГЛАВА 6

    СТРУКТУРА ПРОЦЕССОВ


Дальше
Используются технологии uCoz