За последние годы Linux приобрела немало новых возможностей и применяется во многих гетерогенных средах. Linux работает на микроконтроллерах, применяется в маршрутизаторах, служит для поддержки аппаратных ускорителей трехмерной графики, поддерживает многоэкранную среду Xfree. Все это важные функции для конечных пользователей. Но немало сделано и для удовлетворения требований, предъявляемых к серверам, в особенности, с момента перехода на ядро Linux 2.2.x.

Благодаря широкой поддержке отрасли и усилиям, предпринимаемым сторонниками свободно распространяемых программ, Linux приобрела важные черты, присущие коммерческим версиям Unix и других ОС для крупных серверов. Одна из таких черт — поддержка файловых систем, способных работать с большими разделами жестких дисков, легко масштабироваться на многие тысячи файлов, быстро восстанавливаться после сбоя, поддерживать более высокую производительность ввода/вывода, эффективно работать с файлами самого разного размера, противостоять внутренней и внешней фрагментации и даже предоставлять новые функции, которые не поддерживаются ни в одной из более традиционных файловых систем.

Эта статья — первая из двух, в которой читатели смогут познакомиться с так называемыми журнальными файловыми системами (journal file system): JFS (http://oss.software.ibm.com/developerworks/ opensource/jfs/), XFS (http://oss.sgi.com/projects/xfs/), Ext3 и ReiserFS (http://www.devlinux.com). Вторая статья, как предполагается, будет посвящена детальному описанию функционирования журнальных файловых систем и их производительности, демонстрируемой на различных тестах. (Автор пока не осуществил свое намерение в отношении второй части статьи; однако, в его переписке с редакцией «Открытых систем» недавно прозвучало подтверждение этих планов. — Прим. ред. перев.)

Глоссарий

Внутренняя фрагментация

Логический блок — минимальная единица дискового пространства, которую резервирует файловая система посредством системных вызовов. Если размер файла меньше числа байт в логическом блоке, то на диске он все равно будет занимать один блок. Таким образом, если длина конкретного файла не делится нацело на число байт в логическом блоке (размер файла MOD размер блока ?0), то файловая система будет вынуждена резервировать новый блок, который останется незаполненным до конца, что приводит к нерациональному использованию дискового пространства. Такая излишняя трата пространства на диске называется внутренней фрагментацией. Чем больше размер логического блока, тем больше будет и внутренняя фрагментация.

Внешняя фрагментация

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

Экстент

Экстент (непрерывная область на диске) представляет собой последовательность логических блоков. Механизм экстентов используется несколькими файловыми системами и ядрами баз данных. Описатель экстента обычно состоит из трех полей: beginning, extent size, offset, где beginning («начало») — это адрес блока, с которого начинается экстент, extent size («размер экстента») — это количество блоков, а offset («сдвиг») — это смещение первого байта экстента относительно начала файла.

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

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

B+деревья

B+деревья широко используются в индексных структурах баз данных, обеспечивая быстрый и масштабируемый доступ к записям. Название «B+дерево» — сокращение от Balanced Tree («сбалансированное дерево»). Знак «+» указывает на то, что это модифицированная версия «исходного» B-дерева; она содержит указатели, которые провязывают между собой листья дерева, что помогает последовательному доступу.

B+деревья состоят из узлов двух различных типов: промежуточные узлы и концевые узлы (листья). Все узлы содержат в себе множества пар (ключ, указатель), упорядоченные по значению ключа в порядке возрастания. Указатели промежуточных узлов служат для ссылки на другие указатели промежуточных или концевых узлов, указатели концевых узлов — непосредственно на информацию. Ключ применяется для организации информации внутри B+дерева. В базах данных каждая запись имеет поле ключа, по значению которого различают записи одного и того же типа. B-деревья используют ключ для построения индекса записей баз данных, который позволяет сократить время доступа к ним. Сравнивая текущий ключ с ключом искомого узла, программа находит требуемую информацию.

Чтобы найти определенную запись, необходимо сделать следующее. Предположим, что мы ищем запись с определенным ключом — «K». Поиск следует начинать с корневого узла, а затем последовательно сканировать ключи, хранящиеся внутри. Узел сканируется до тех пор, пока не найден ключ со значением больше «K». Затем переходим к узлу (промежуточному или конечному, пока не известно точно, к какому), на который ссылается соответствующий указатель. После этого, если этот узел является промежуточным, операция повторяется. Наконец, найден конечный узел, который последовательно сканируется до тех пор, пока не найден требуемый ключ «K». Поскольку, для того чтобы найти нужный ключ, требуется извлечь меньшее число блоков, этот метод поиска имеет меньший уровень сложности, чем последовательное сканирование, при котором, в самом худшем случае, пришлось бы просмотреть все элементы.

UNIX File System

UFS — название файловой системы, использовавшейся в SCO Unix, System V и некоторых других ранних вариантах Unix. Ядро Linux включает факультативную поддержку UFS. Большинство диалектов Unix по-прежнему использует UFS, хотя и с небольшими специфическими модификациями.

Virtual File System

VFS — специальный уровень в ядре, который предоставляет унифицированный API-интерфейс файловых служб, не зависящий от того, в какой именно файловой системе размещается файл. Все реализации файловой системы (vfat, ext2fs, jfs и т.д.) должны предоставлять определенные функции VFS, чтобы их можно было использовать в Linux. Этот уровень абстракции дает пользовательским приложениям возможность работать с множеством различных файловых систем, в том числе, и с коммерчески распространяемыми продуктами.

Журнал

Что такое журнальная файловая система

Общеизвестно, что представляет собой кэш-память — буфер, зарезервированный в быстрой памяти и предназначенный для ускорения операций ввода/вывода. Такого рода буфер часто используется в файловых системах (его называют дисковым кэшем) и в базах данных для увеличения общей производительности. Проблема возникает в том случае, если в системе произошел сбой прежде, чем буферы были записаны на диск; в таком случае после перезагрузки системы она будет находиться в противоречивом состоянии. Представьте себе, что файл был удален из кэша, но остался на жестком диске. Вот почему базы данных и файловые системы должны иметь возможность возвращать систему в непротиворечивое состояние. За долгие годы совершенствования баз данных были созданы способы, позволяющие быстро восстанавливать их, однако, время восстановления файловых систем и, более конкретно, UFS-подобных систем увеличивается по мере роста размеров файловой системы. Утилита восстановления fsck для ext2fs должна просканировать раздел диска целиком, чтобы вернуть файловую систему обратно в непротиворечивое состояние. Из-за того, что эта задача требует очень больших затрат времени в случае крупных серверов с сотнями гигабайт, а иногда и терабайт данных, говорить о высоком уровне готовности подобных систем не приходится. Именно это стало основной причиной создания для файловых систем технологии, подобной технологии восстановления баз данных, в силу чего и появились журнальные файловые системы.

Механизм работы

Транзакция представляет собой набор простейших операций, удовлетворяющий определенным свойствам; речь идет о так называемых свойствах ACID (Atomicity, Consistency, Isolation, Durability — «атомарность, целостность, изолированность, долговечность»). Самое важное свойство в контексте данной статьи — атомарность. Данная характеристика означает, что все относящиеся к одной транзакции операции выполняются полностью, либо отменяются, не порождая никаких изменений. Эти свойства транзакций создают основу функционирования баз данных, беря на себя решение проблем, связанных с необходимостью сохранения целостности при параллельной работе с ними. Чтобы добиться этого, базы данных записывают в файл регистрации (log file) каждую отдельную операцию транзакции. При этом перед выполнением операции записывается не только ее название, но и значения аргументов. Каждую транзакцию должна завершать операция ее принятия, или подтверждения (commit), в частности, свидетельствующая о том, что буферы записаны на диск. Если в системе произошел сбой, можно просмотреть назад записи в файле регистрации до тех пор, пока не встретится последняя операция принятия транзакции, и постараться восстановить состояние диска на этот момент.

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

Важное различие между базами данных и журналированием файловых систем состоит в том, что базы данных регистрируют пользователей и управляющие данные, в то время как в файловых системах регистрация, как правило, ограничивается только метаданными, т.е. ее внутренними управляющими структурами (описатели inode, таблицы резервирования свободных блоков, таблицы inode и т.д.).

Решение проблемы масштабируемости

UFS и ext2fs создавались во времена, когда жесткие диски и другие носители не отличались большой емкостью. Рост емкости привел к появлению файлов, каталогов и разделов большего размера, что, в свою очередь, породило ряд серьезных проблем, связанных с файловой системой. Эти проблемы — следствие ограничений внутренних структур, которые используются при построении файловых систем. Такие структуры были вполне адекватны для среднего размера старых файлов и каталогов, однако, в новых условиях они стали неэффективны. Старые структуры порождают две серьезные проблемы.

  • Они не в состоянии поддерживать возросшие объемы хранения. Старые файловые системы были рассчитаны на определенные размеры файлов, каталогов и разделов. Структуры файловой системы выделяли определенное число разрядов под данные о размере файла, фиксированное число разрядов для хранения номера логического блока и т.д. Как следствие жестких ограничений на число разрядов для поля размера налагались определенные ограничения и на размер файлов и разделов, а также на количество элементов в каталоге.
  • Они не пригодны для управления новыми объемами хранения. Хотя старые структуры иногда способны поддерживать новые размеры объектов, на практике зачастую это невозможно из соображений производительности. Некоторые структуры прекрасно работают со старыми размерами, но в новой ситуации часто становятся причиной резкого падения производительности.

Файловые системы последнего поколения создавались с учетом необходимости решить проблемы масштабируемости. В них реализованы некоторые новые структуры и методы.

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

В настоящее время максимальный размер блочного устройства ограничивает размер файловой системы 2 Тбайт. Кроме того, в VFS существует ограничение на размер файла в 2 Гбайт. Однако важно отметить, что теперь файловые системы могут масштабироваться, и с выпуском ядра Linux 2.4 эти ограничения преодолены. JFS и XFS — коммерческие версии файловых систем, предназначенные для тех ОС, в которых подобных ограничений нет.

Усовершенствования

Структура свободных блоков

Большинство файловых систем поддерживают структуры, в которых отслеживаются свободные блоки и которые, как правило, содержат список всех номеров свободных блоков. Благодаря таким структурам файловая система в состоянии удовлетворить запросы, выдаваемые приложениями. Для контроля свободных блоков в UFS и ext2fs применяются так называемые битовые карты. Битовая карта состоит из массива бит, каждый бит которого соответствует логическому блоку в разделе файловой системы. Состояние резервирования каждого блока будет отражаться соответствующим битом. Логическое значение «1» может означать, что блок занят, а «0» — свободен. Основная проблема, возникающая при использовании такой структуры, состоит в том, что битовая карта увеличивается в размерах параллельно с ростом размеров файловой системы, поскольку каждому отдельному блоку в файловой системе должен соответствовать собственный бит в битовой карте. До тех пор, пока применяется алгоритм последовательного поиска свободных блоков, производительность будет падать, поскольку время, необходимое для поиска свободного блока, также будет расти (в худшем случае сложность составит O(n), где n — размер битовой карты). Подход, предусматривающий применение битовой карты, себя вполне оправдывает при файловой системе среднего размера, но по мере ее роста ситуация ухудшается.

Решение, предлагаемое в файловых системах нового поколения, предусматривает использование экстентов с одновременным построением B+дерева. Этот подход оправдан, поскольку может одновременно применяться для определения местонахождения свободных блоков. Кроме того, работа с экстентами дает возможность сократить размер структуры: не нужно ставить бит в соответствие каждому отдельному блоку. Более того, при использовании экстентов размер структуры свободных блоков зависит не от размера файловой системы, а от допустимого числа экстентов. Производительность также должна возрасти, поскольку при поиске будет обрабатываться меньшее число элементов. Кроме того, при работе с экстентами, даже в том случае, если применяются список и алгоритмы последовательного поиска, производительность все равно возрастет, поскольку структура будет объединять несколько блоков в одну непрерывную область, и, тем самым, будет сокращаться время поиска запрашиваемого числа свободных блоков.

Второй подход к решению проблемы управления свободными блоками состоит в использовании дополнительных структур, которые позволяют применять алгоритмы поиска с меньшей скоростью роста сложности. B+деревья используются именно потому, что они помогают быстрее определять местонахождение требуемых объектов. Свободные блоки организуются в B+деревья, а не в списки. Кроме того, применяется и подход, при котором B+деревья описывают не блоки, а экстенты. Это дает возможность применять различные методы индексации. Индексация по размеру или по позиции экстента позволяет файловой системе быстро находить порцию из нескольких свободных блоков, либо по размеру, либо по их местоположению.

Большое число элементов каталога

Все файловые системы используют специальные объекты, называемые каталогами. Элементы каталога суть пары (номер inode, имя файла), где inode — описатель (внутренняя структура файловой системы), используемый для хранения служебной информации, связанной с файлом. Когда приложению требуется определенный файл в каталоге, заданный именем, необходимо просмотреть структуру элементов каталога. Старые файловые системы организовывали элементы в каталоге в виде списка, к которому затем применялись последовательные алгоритмы поиска. Как следствие, при работе с большими каталогами, содержащими тысячи файлов и другие каталоги, производительность оказывалась чрезвычайно низкой. Эта проблема, как и в случае со свободными блоками, связана с использованием соответствующей структуры. Новое поколение файловых систем обладает более эффективными структурами и алгоритмами для определения местонахождения файлов внутри каталога, которые работают намного быстрее.

Файловые системы, о которых говорится в данной статье, для организации элементов внутри каталога используют B+деревья, что позволяет значительно сократить время поиска. Индексация в B+дереве ведется по имени элемента каталога. Таким образом, когда необходим определенный файл в данном каталоге, поиск ведется по B+дереву данного каталога, что позволяет быстро найти inode требуемого файла. Детали использования B+деревьев зависят от конкретной файловой системы. Одни файловые системы поддерживают B+дерево для каждого отдельного каталога, в других существует единое B+дерево для всей иерархии каталогов файловой системы.

Файлы большого размера

Прежде файловые системы создавались в расчете на совершенно определенные методы работы с файлами. ext2fs и UFS были спроектированы с учетом того, что файловая система содержит, главным образом, файлы небольшого размера. Именно этим объясняется структура индексных описателей файлов inode в ext2fs и UFS.

Коротко говоря, описатель inode представляет собой структуру, применяемую в UFS и ext2fs для хранения информации о файле. В inode содержатся данные о правах доступа к файлу, тип файла, число ссылок и указатели на блоки файловой системы, занятые файлом. Описатель включает в себя несколько прямых указателей, которые представляют собой указатели (адреса блоков) на логические блоки файловой системы, используемые файлом, которому они принадлежат; кроме того, он также содержит косвенные указатели, дважды и даже трижды косвенные указатели. Косвенные указатели — это указатели (адреса) на блоки, где хранятся другие указатели на логические блоки. Дважды косвенные указатели — это указатели на блоки, которые содержат косвенные указатели, а трижды косвенные указатели — на блоки с дважды косвенными указателями. Основная проблема, связанная с такой методикой адресации, состоит в том, что по мере увеличения размера файла все более интенсивно используются косвенные указатели всех видов. Следует подчеркнуть, что применение косвенных указателей приводит к увеличению числа обращений к диску: для того чтобы получить требуемый блок, необходимо извлечь больше промежуточных блоков. Таким образом, при росте размера файла увеличивается и длительность операций над ним. Резонен вопрос: почему разработчики ext2fs не ограничились только прямыми указателями, если с ними система работает заведомо быстрее? Основная причина состоит в том, что описатели inode имеют фиксированный размер, и при использовании только прямых указателей этот размер был бы очень велик; в силу этого при работе с небольшими файлами пространство тратилось бы впустую.

Новые файловые системы эффективно используют дисковое пространство, но при этом предлагают лучшую технологию адресации для файлов большего размера. И опять-таки, их основное отличие состоит в использовании B+дерева для организации блоков файлов. Блоки индексируются по смещению в файле; затем, когда требуется определенное смещение, процедуры файловой системы просматривают B+дерево в поисках затребованного блока.

Для того чтобы минимизировать использование косвенных указателей, можно использовать логические блоки большего размера. Однако логические блоки большего размера увеличивают уровень внутренней фрагментации, поэтому применяются другие методы. Один из таких методов — использование экстентов для объединения нескольких логических блоков. Применение экстентов имеет тот же эффект, что и блоки большего размера, поскольку увеличивается соотношение «информация на адресуемый элемент». Некоторые из описываемых файловых систем используют экстенты для решения задачи адресации файлов большого размера. Более того, экстенты можно организовать в B+дерево, индексируя их по смещению в файле, что сокращает время сканирования. Новые описатели inode, как правило, поддерживают определенные прямые указатели на непрерывные области, а в том случае, если файлу требуются дополнительные непрерывные области, они могут быть организованы в B+дереве. Чтобы обеспечить высокую производительность при доступе к небольшим файлам, файловые системы нового поколения хранят данные о файлах внутри самого описателя. Таким образом, когда пользователь получает описатель inode, он также получает и данные о нем. Особенно полезна эта технология для символьных ссылок, когда данных в файле действительно очень немного.

Другие усовершенствования

Для UFS-подобных файловых систем характерно несколько ограничений. Среди них — невозможность управлять неплотными файлами как особым случаем и проблема фиксированного числа описателей inode.

Поддержка разреженных файлов

Предположим, создан новый файл, и в его начало записано пара байт. Что произойдет, если в этот файл записать данные со смещением «10000»? Теперь файловая система должна проанализировать, сколько блоков необходимо, чтобы покрыть разрыв между смещением 2 и смещением 10000. Это может потребовать некоторого времени. Теперь вопрос состоит в следующем: почему файловая система должна резервировать блоки, находящиеся в середине, если нам они не нужны? Ответ на этот вопрос — поддержка разреженных файлов, предлагаемая файловыми системами нового поколения.

Поддержка разреженных файлов тесно связана с методом адресации экстентов областей для блоков файла. Соответствующий механизм использует поле «смещение внутри файла» описателя экстента. Таким образом, когда файловая система вынуждена искать свободные блоки, чтобы заполнить разрыв в такой ситуации, она просто определяет новый экстент с соответствующим значением поля «смещение внутри файла». Впоследствии, когда приложение пытается прочитать байт внутри разрыва, возвращается значение null, поскольку в этом «промежутке» нет никакой информации.

Решение проблемы внутренней фрагментации

При обсуждении внутренней фрагментации и производительности указывалось, что системным администраторам часто приходится выбирать между производительностью и неэффективными затратами пространства. Если вернутся к первой таблице, то становится ясно, что новые файловые системы могут управлять блоками размером до 64 Кбайт. Такой (и даже меньший) размер блока может породить значительные неэффективные затраты пространства из-за внутренней фрагментации. Чтобы использование блоков больших размеров было оправдано, в ReiserFS реализован метод, позволяющий решить данную задачу.

Как отмечалось, ReiserFS использует B*дерево для организации объектов файловой системы. Эти объекты представляют собой структуры, в которых хранится информация о файле — время доступа, права доступа и т.д. Другими словами, информация, содержащаяся в описателях inode, в данных каталогов и файлов. В терминах ReiserFS эти объекты называются «статистическими элементами» (stat_data), «элементами каталогов» и «прямыми/косвенными элементами» соответственно. Косвенные элементы состоят из указателей на неотформатированные узлы (логические блоки без заданного формата, применяемые для хранения данных файла), а прямые элементы содержат сами данные файла. Кроме того, эти элементы имеют разный размер и хранятся в концевых узлах дерева, иногда с другими элементами, в том случае, когда внутри узла достаточно места. Информация о файле хранится по возможности близко к данным файла: файловая система всегда пытается объединить статические элементы с прямыми/косвенными элементами того же файла. Следует подчеркнуть, что, в отличие от прямых элементов, данные файла, на которые указывают косвенные элементы, не хранятся внутри дерева. Для поддержки файлов небольшого размера разработан специальный механизм управления прямыми элементами.

Прямые элементы призваны хранить данные небольших файлов и даже «хвосты» файлов. В силу этого, некоторые хвосты могут храниться внутри одного и того же концевого узла, позволяя значительно сократить уровень неэффективного использования пространства. Однако использование этого метода хранения вместе хвостов файлов увеличивает внешнюю фрагментацию; кроме того, формирование дополнительных структур требует значительных затрат времени и снижает производительность. Поэтому совместное хранение хвостов файлов может быть отключено, если того явным образом потребует системный администратор.

Динамическое выделение inode

Еще одна важная проблема, связанная с UFS-подобными файловыми системами, состоит в том, что они поддерживают фиксированное число описателей inode —максимум описателей определяет максимальное число объектов, которые могут поддерживаться в файловой системе. В том случае, если все inode в файловой системе задействованы, приходится делать резервную копию раздела, а затем переформатировать ее с большим числом inode. Фиксированное число inode определяется потому, что для управления состоянием описателей файлов в UFS используются структуры фиксированного размера — точно так же, как и в случае свободных блоков. Кроме того, UFS резервирует описатели inode для файловой системы в известном месте на диске, поэтому нет необходимости указывать соответствие описателей и логических блоков. Проблема возникает в том случае, когда системному администратору приходится заранее определять максимальное число объектов, которым предстоит управлять файловой системе. Далеко не всегда целесообразно указывать в качестве верхней границы слишком большое число, поскольку для размещения inode резервируется значительное дисковое пространство, которое нельзя использовать для других целей и которое в таком случае будет тратиться впустую.

Возможным решением является динамическое выделение inode. Этот подход позволяет отказаться от назначения максимально возможного числа объектов в момент форматирования файловой системы. Однако использование этого метода выделения описателей порождает другие проблемы: необходимость определять соответствие описателей и логических блоков, поддерживать сложные структуры управления inode и т.д. В описываемых в статье файловых системах для организации динамического выделения inode также используются B+деревья. Более того, в JFS применяются «непрерывные inode», которые формируют концевые узлы в B+дереве, и могут хранить вместе до 32 inode. Использование динамического выделения inode — процедура сложная и требующая больших временных затрат, но она помогает преодолеть ограничения, накладываемые старыми файловыми системами.

Литература

[1] Обзор JFS и технические комментарии Стива Беста и Дейва Клейкампа

[2] Mike Holton, Raj Das, «XFS: A Next Generation Journalled 64-Bit Filesystem With Guaranteed Rate I/O», SGI

[3] Adam Sweeney, Doug Doucette, Wei Hu, Curtis Anderson, Mike Nishimoto, Geoff Peck, «Scalability in the XFS File System», SGI

[4] Philip Trautman, Jim Mostek, «Scalability and Performance in Modern File Systems», см. Web-сайт ReiserFS

[5] Remy Card, Theodore Ts?o, Stephen Tweedie, «Design and Implementation of the Second Extended Filesystem»

[6] Список рассылки разработчиков ReiserFS. Чтобы подписаться, пошлите письмо по адресу reiserfs-subscribe@devlinux.com

[7] Список рассылки JFS. Чтобы подписаться, пошлите письмо по адресу majordomo@oss.software.ibm.com, указав в теме сообщения subscribe, а в его тексте — subscribe jfs-discussion

[8] Henry F. Korth, Abraham Silberschatz, «Fundamentos de Bases de Datos». McGraw-Hill, 1993

Автор благодарит Стефена Твиди, Дейва Клейкампа, Стива Беста, Ханса Райзера, а также всех тех, кто поддерживает списки рассылки по JFS и ReiserFS за плодотворные беседы и консультации.


Copyright (с) 2001, Хуан Сантос Флоридо. Данный материал может распространяться только в соответствии с правилами и условиями, определяемыми «Лицензией на Открытые Публикации» (см. ее текст по адресу http://www.opencontent.org/openpub/). Juan I. Santos Florido, Journal File Systems. Linux Gazette, Issue 55, July 2000 (www.linuxgazette.com). Перевод на русский язык: Галина Никитина, июль 2001.

Поделитесь материалом с коллегами и друзьями