Наши партнеры

UnixForum






Книги по Linux (с отзывами читателей)

Библиотека сайта rus-linux.net

Разделы диска и средства для работы с ними в Линукс

(C) В.А.Костромин, 2004.

Оглавление Вперед

1. Необходимые сведения о дисках и дисковых разделах

1.1. Зачем нужны разделы?

Современные жесткие диски объемом в десятки и сотни гигабайт принято разбивать на “логическе диски” или разделы (по-английски - partition). Раздел - это множество последовательно расположенных секторов на диске, которое воспринимается операционной системой как отдельный независимый диск. Есть несколько причин для разбиения диска на разделы.

  • DOS, например, не поддерживает файловые системы объемом более 2 ГБайт, так что разбиение на разделы необходимо для преодоления этого “2-гигабайтного барьера”.
  • Разделы диска могут служить для создания на одном диске файловых систем различных типов (FAT, HPFS, NTFS, ext2, ...), которые могут использоваться различными операционными системам.
  • Иногда разделы малого объема используются для специальных целей: например, загрузчик Boot Manager в OS/2 создает для себя небольшой раздел, на лэптопах иногда создаются специальные разделы для сохранения состояния системы, когда она переходит в режим “сна”.
  • В некоторых “особо надежных” системах выделяется специальный раздел для хранения резервных копий файлов.
  • В ОС Линукс считается “хорошим тоном” хранить на отдельном разделе (обычно /home) все личные файлы пользователей, а также выделять отдельный раздел (/usr/local) для программного обеспечения, устанавливаемого из пакетов, не входящих в дистрибутив. В таком случае при переустановке системы или переходу к другому дистрибутиву вы не теряете ни ваши личные файлы, ни дополнительно установленное ПО.
  • Использование разделов уменьшает риск и возможные потери вследствие сбоев в системе, а также время, необходимое для процедур резервного копирования данных и восстановления данных после сбоев. Поскольку сбой в файловой системе приводит к потере данных только в одном разделе, вы в случае такого сбоя теряете только часть своих данных (и времени на их восстановление требуется значительно меньше).
  • Разбиение на разделы может служить и для повышения безопасности. В хорошо сконструированных системах часто все системное программное обеспечение устанавливается в отдельный раздел, к которому разрешен доступ только по чтению. Например, в Unix-системах можно смонтировать все файловые системы, кроме корневой, с опциями “nosuid,nodev”, и разместить каталоги /tmp, /home, /var вне корневой файловой системы, минимизируя тем самым риск того, что какая-то программа с установленным битом suid сможет изменить важные системные файлы путем создания жесткой ссылки на них.
  • Разбиение диска на разделы повышает эффективность использования дискового пространства на дисках большого объема. Каждый раздел можно отформатировать с индивидуальным значением размера блока, в зависимости от того, какие данные будут храниться на этом разделе. Если у вас предполагается наличие большого количества маленьких файлов, то размер блока целесообразно задать примерно равным среднему размеру ваших файлов. А иначе 10 файлов по 1 байту могут занять 40 килобайт (при размере блока в 4 КБ) и больше.
  • В разных разделах могут быть созданы файловые системы разного типа, что позволяет в некоторых случаях повысить эффективность работы системы. Например, в файловой системе ReiserFS дисковое пространство, занимаемое файлом, точно соответствует его размеру, в то время как в Ext3 для хранения файла размером в несколько байтов отводится целый блок файловой системы -- 1, 2 или 4 KB. Поэтому для хранения кэша proxy-сервера или для каталога /tmp лучше отвести отдельные ReiserFS-разделы, так как большинство временных файлов имеют небольшие размеры.
  • С помощью разделов можно контролировать использование дискового пространства и установить пределы для некоторых процессов или пользователей.
  • Для целей тестирования нового или нестабильно работающего программного обеспечения целесообразно выделить особый раздел.
  • Наконец, все еще существует старая проблема с BIOS, которая делает невозможной загрузку системы, которая размещается в цилиндрах, номера которых превышают 1024. Поэтому для обеспечения возможности загрузки ОС возникает необходимость создания разделов, расположенных “ниже” 1024-ого цилиндра, в которых размещаются данные, необходимые для обеспечения процесса загрузки.

Разбиение диска не означает, конечно, что диск физически разрезается на несколько разделов - все осуществляется на логическом уровне. Просто создается так называемая таблица разбиения диска - набор индексов или ссылок (адресов), определяющих размещение разделов на диске. Чтобы понимать, как это устроено и работает, необходимо рассмотреть способы адресации дискового пространства.

1.2. О трех режимах адресации дискового пространства

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

Между отдельными пластинами имеются небольшие промежутки, в которых размещены головки считывания/записи, имеющие возможность по-шагово перемещаться от одной дорожки к другой. Каждой магнитной поверхности соответствует своя головка считывания/записи. Головки перемещаются синхронно, то есть в каждый момент времени все они установлены на дорожки с одинаковыми номерами, только на разных пластинах: если головка с номером 1 находится на 15-ой дорожке, то головка с любым другим номером тоже находится на 15-ой дорожке, (только, соответственно, "смотрит" на одну из сторон другой пластины). Таким образом, совокупность дорожек, расположенных одна под другой, как-бы образует цилиндрическую поверхность. Так ее и принято именовать - цилиндром. И если все головки установлены на 15-ю дорожку, можно говорить, что считывание (или запись) в этот момент производится с цилиндра 15.

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

Первоначально число секторов на всех дорожках жесткого диска было одинаковым, поэтому емкость диска можно было легко вычислить, перемножив три числа: число цилиндров, число дорожек в цилиндре, число секторов на дорожке. И диски в те времена однозначно характеризовались совокупностью этих трех цифр. Эта тройка даже получила специальное название - "геометрия диска" и сокращенное обозначение "C/H/S" - от первых букв соответствующих английских терминов: Cylinder/Head/Sector, т.е. цилиндр/головка/сектор. Диск с геометрией C/H/S имел объем C*H*S*512 байт.

Для старых моделей дисков для указания места, в которое нужно записать данные, достаточно было указать номер цилиндра, номер головки и номер сектора. Получив эти три цифры контроллер диска успешно справлялся с задачей чтения или записи информации. Сектор и до сих пор является адресуемой единицей информации на жестком диске. Запись и считывание данных производится целыми секторами, то есть порциями по 512 байт.

Теперь давайте вспомним, что обращение к диску происходит не только тогда, когда мы сохраняем на диске какой-то файл. Чтобы само создание файла стало возможным, необходимо вначале загрузить операционную систему, которая тоже "лежит" на диске в виде файлов. Загрузка ОС осуществляется базовой системой ввода-вывода (BIOS) - специальной программой, прошитой в постоянной памяти компьютера. В первых моделях компьютеров на основе микропроцессоров от Intel для операций с диском на этапе загрузки ОС выполнялась подпрограмма BIOS, которая называется процедурой обработки прерывания с номером 13h (это шестнадцатиричное число, соответствующее десятичному номеру 19). Перед вызовом этого прерывания в регистры микропроцессора Intel 80x86 заносились тип операции (например, чтение или запись данных на диск), а также номера цилиндра, головки и сектора на дорожке (C/H/S). Данные эти заносились в регистры микропроцессора следующим образом:

  • AH — выбор операции (или функции прерывания 13, например, чтение или запись);
  • CH — младшие 8 бит номера цилиндра;
  • CL — 7-6 биты соответствуют старшим битам номера цилиндра, 5-0 биты соответствуют номеру сектора;
  • DH — номер считывающей головки;
  • DL — номер диска (80h или 81h).
Таким образом, имелась возможность задать один из 210 = 1024 номеров цилиндра, один из 26=64 номеров сектора и один из 28=256 номеров головки. Поскольку число считывающих головок никогда не было больше 16, а нулевой сектор каждой дорожки используется для обозначения начала дорожки, то есть число практически используемых секторов на дорожке равно 63, то, хотя для указания цилиндра использовалось 10 бит, все равно BIOS не мог работать с дисками объемом более 1024*63*16*512 = 504 Мбайт.
    Примечания: 1. Здесь и далее для указания объемов диска используются двоичные величины: 1 КБайт = 1024 байта, 1 МБайт = 1024 КБайта = 1048576 байт.
    2. В отличие от нумерации физических цилиндров и дорожек, которые нумеруются начиная с 0, сектора на дорожке нумеруют, начиная с 1. По-видимому, это объясняется тем, что нулевой сектор каждой дорожки используется для обозначения начала дорожки.

Операционная система MS-DOS и первые версии Windows тоже использовали для обращения к диску прерывание 13h BIOS, поэтому тоже не могли работать с дисками объемом более 504 МБайт. А производители дисков все увеличивали их объемы, причем чаще всего в первую очередь увеличивалось число цилиндров (то есть дорожек на пластине).

Для того, чтобы можно было использовать такие диски, разработчики BIOS стали применять разные хитрые приемы (подробнее об этом вы можете узнать из [2] и [3]). Например, Extended CHS (ECHS) или "Large disk support" (иногда обозначается просто как "Large") использует еще четыре незанятых бита номера головки для увеличения числа адресуемых цилиндров (но по каким-то причинам оказалось невозможно использовать все 256 значений номера головки, используются только 255). Это позволило использовать "фальшивую геометрию" диска в 1024 цилиндра, 255 считывающих головок и 63 сектора на дорожку. Трансляцию Extended CHS в реальный CHS-адрес осуществляет BIOS. Это позволяет работать с дисками, объемом до 1024*255*63*512 байт =8 422 686 720 байт или 8,0325 Гбайт.

Но разработчики все увеличивали плотность записи на диск, число пластин и дорожек, изобретали другие способы увеличения объема дисков. В частности, число секторов на дорожках стало разным (на более длинных дорожках, расположенных ближе к краю пластин, число секторов стали увеличивать). В результате три числа C/H/S уже перестали правильно отражать "геометрию диска", а старые версии BIOS перестали обеспечивать доступ ко всему дисковому пространству.

Тогда придумали другой прием для работы с большими дисками через Int 13h — линейную адресацию блоков ("Linear Block Addressing" или LBA). Если не вдаваться в подробности, то можно сказать, что все сектора на диске нумеруются последовательно, начиная с первого сектора на нулевой дорожке нулевого цилиндра. Нумерация логических секторов при этом начинается с нуля, причем нулевой сектор содержит главную загрузочную запись (MBR). Вместо CHS-адреса каждый сектор получает 64-битный логический адрес, который является просто порядковым номером сектора в общем массиве секторов. Таким образом, граница адресуемого объема диска отодвигается до значения 264*512 байт = 243 Терабайт (даже современные диски объемом в сотни Гигабайт не используют для адресации секторов и половины из 64 разрядов).

В отличие от двух первых способов обращения к диску (CHS и ECHS) линейная адресация не требует, чтобы BIOS знал истинную геометрию диска (число секторов, головок, цилиндров). Однако это означает, что старое прерывание 13h не может использоваться для обращения к диску. Поэтому современные версии BIOS имеют "расширенное" прерывание 13h, вызов которого осуществляется занесением других значений в регистр AH. Предварительно в регистрах DS:SI формируется указатель на 16-байтовый "пакет адреса", восемь последних байт которого (8*8=64 бита) представляют собой адрес нужного сектора, после чего вызывается "расширенное" прерывание 13h BIOS, которое передает контроллеру диска линейный адрес сектора.

В Setup BIOS поддержка преобразования линейного номера в CHS-адрес обозначается как "поддержка LBA". В новых версиях BIOS обычно имеется выбор из трех вариантов: "Large", "LBA" и "Normal" (последнее означает, что трансляция адресов не производится).

Надо заметить, что все сказанное относится только к дискам с интерфейсом IDE. В контроллерах SCSI-дисков с самого начала использовалась линейная адресация секторов.

Отметим, что для того, чтобы работать с дисками объемом более 8 Гигабайт, все три участника этого процесса (контроллер диска, BIOS и операционная система) должны уметь работать в режиме LBA. Последние версии всех операционных систем (например, Windows 2000 и Linux) при работе с дисками уже не используют прерывание 13h BIOS, а используют собственные драйвера для работы с дисками. Но, прежде чем система сможет использовать собственный драйвер, она должна как минимум его загрузить. Поэтому на этапе начальной загрузки любая система вынуждена пользоваться BIOS. И если версия BIOS не поддерживает режим LBA, появляется ограничение на размещение операционной системы за пределами 8 Гбайт (точнее - в цилиндрах с номером больше 1024): они не могут оттуда загружаться, хотя после успешной загрузки могут работать с дисками гораздо большего объема.

Таким образом, истинная геометрия современных дисков известна только контроллеру диска. И разные способы определения геометрии могут дать совершенно не согласующиеся между собой результаты. Например, на корпусе моего 40-гигабайтного диска Seagate ST340810A я увидел следующую надпись:
16383 Cyl 16 HDS 63 Sec 
LBA 78165360 

Для того же диска процедура автоматического определения диска в BIOS сообщила, что его геометрия имеет вид 19158/16/255. А в выводе команды dmesg в Linux я увидел следующие строки:

Листинг 1.

hda: C/H/S=1277/240/255 from BIOS ignored
hda: ST340810A, ATA DISK drive
hda: 78165360 sectors (40021 MB) w/2048KiB Cache, CHS=77545/16/63
 hda: hda1 hda2 hda3 hda4 < hda5 hda6 hda7 hda8 hda9 >

Программа fdisk дала следующий результат:

Disk /dev/hda: 16 heads, 63 sectors, 77545 cylinders

Единственное число, которое здесь не вызывает сомнений, - это общее число секторов на диске, равное 78165360.

Я привел этот пример для того, чтобы наглядно показать, что "геометрия диска" для современных устройств потеряла практическое значение. Однако многие программы разбиения диска в той или иной мере используют это понятие, поэтому пришлось уделить ему столько внимания. А теперь вернемся к основной теме - таблице разделов диска.

1.3. Где хранится информация о разделах диска

Очевидно, что информация о том, каким образом диск разбит на разделы, должна быть записана где-то на том же диске. Для этой информации выделяется по 64 байта в самом первом секторе диска (первый сектор нулевой дорожки на нулевом цилиндре) и в первом секторе каждого "расширенного" раздела (что такое "расширенный" раздел, будет объяснено дальше). В этой цепочке секторов и содержится информация о разбиении диска на разделы.

Начало этой структуры (или вход в нее) находится в первом секторе жесткого диска (нулевом секторе в смысле LBA), который называется главным загрузочным сектором (или MBR – Master Boot Record). Его структура представлена в табл. 1

Таблица 1. Структура главного загрузочного сектора.

Смещение

Размер

Содержание

0x000

446 байт

Код первичного загрузчика

0x1BE

64 байта

Таблица разбиения диска

0x1FE

2 байта

"Магическое число" (0x55AA)

Последние два байта MBR называются сигнатурой. Значение этих байтов должно быть 55h AAh. В случае, если это не так, запись считается некорректной. Код первичного загрузчика различен в загрузчиках, используемых разными операционными системами. Да и для одной и той же операционной системы могут использоваться разные загрузчики. Например, в Линукс - это могут быть LILO, GRUB, ASPLoader или еще какой-то другой загрузчик, вплоть до NTLoader от Windows. Но, поскольку рассмотрение процедур загрузки не входит в наши задачи, эта часть загрузочных секторов в рамках данной статьи не рассматривается, нас интересует только таблица разбиения диска (в английской терминологии - partition table).

Таблица разбиения диска на разделы в MBR содержит 4 записи по 16 байт для 4 разделов (эти разделы называют первичными). Каждая такая запись имеет следующую структуру:

Листинг 2.

struct partition {
  char active;      /* 0x80: раздел активный (загрузочный), 0: не активный */
  char begin[3];    /* CHS первого сектора, 24 бита*/
  char type;        /* тип раздела (например, 83— LINUX_NATIVE, 82— LINUX_SWAP, 85— EXTENDED) */
  char end[3];      /* CHS последнего сектора, 24 бита */
  int start;        /* номер начального сектора (32-бита, счет начинается с 0) */
  int length;       /* число секторов в разделе (32 бита) */
};

Поскольку в таблице разбиения отведено только 4 строки для задания разделов, число первичных разделов на диске с самого начала ограничено: их может быть не более 4. Если нужно создать более 4-х разделов, один из первичных разделов объявляется "расширенным", и в нем создаются "логические разделы". Для расширенного раздела в поле type указывается одно из следующих шестнадцатеричных значений: 0x05 - расширенный DOS-раздел, 0x0F - расширенный Windows-раздел, 0x85 - расширенный Linux-раздел. Расширенные разделы сами по себе не используются, они могут лишь хранить логические разделы. Первый сектор расширенного раздела тоже содержит таблицу разделов, подобную таблице из MBR. Однако из четырех возможных указателей на разделы используется только два: один используется для задания логического раздела, другой - для определения еще одного расширенного раздела. Два оставшихся указателя не используются. Каждый следующий расширенный раздел имеет свою таблицу разбиения, в которой, как и в первичном расширенном разделе, используются только две строки, задающие один логический и один расширенный раздел.

Таким образом, получается цепочка из таблиц разделов, где первая описывает три основных раздела, а каждая следующая — один логический раздел и положение следующей таблицы. Эта цепочка и определяет разбиение диска на разделы. Еще раз подчеркнем, что расширенный раздел как на физическом диске, так и в расширенном разделе вложенного расширенного раздела (предыдущего уровня) может быть только один: ни одна из существующих программ разбиения дисков (fdisk и ее усовершенствованные аналоги) не умеет создавать более одного расширенного раздела. Программа sfdisk в Linux может очень наглядно показать всю цепочку разделов диска:

Листинг 3.

[root]# /sbin/sfdisk -l -x /dev/hda
Disk /dev/hda: 77545 cylinders, 16 heads, 63 sectors/track
Warning: extended partition does not start at a cylinder boundary.
DOS and Linux will interpret the contents differently.
Units = cylinders of 516096 bytes, blocks of 1024 bytes, counting from 0

   Device Boot Start    End     #cyls    #blocks  Id System
/dev/hda1         0+   1051-   1052-    530113+  82 Linux swap
/dev/hda2  *   1051+   5115-   4065-   2048287+   b W95 FAT32
/dev/hda3      5115+   5323-    208-    104422+  83 Linux
/dev/hda4      5323+  77544   72222-  36399825    f W95 Ext'd (LBA)

/dev/hda5      5323+   8367-   3044    1534176   83 Linux
   -           8367+  12431-   4065-   2048287+   5 Extended
   -           5323+   5323-      0          0    0 Empty
   -           5323+   5323-      0          0    0 Empty

/dev/hda6      8367+  12431-   4064    2048256   83 Linux
   -          12431+  36815-  24385-  12289725    5 Extended
   -           8367+   8367-      0          0    0 Empty
   -           8367+   8367-      0          0    0 Empty

/dev/hda7     12431+  36815-  24385-  12289693+  83 Linux
   -          36815+  77535-  40721-  20523037+   5 Extended
   -          12431+  12431-      0          0    0 Empty
   -          12431+  12431-      0          0    0 Empty

/dev/hda8     36815+  77535-  40721-  20523006    c W95 FAT32 (LBA)
   -          77535+  77544      10-      4567+   5 Extended
   -          36815+  36815-      0          0    0 Empty
   -	      36815+  36815-      0          0    0 Empty

Число логических разделов теоретически не ограничено, потому что каждый логический раздел может содержать таблицу разделов и вложенные логические разделы. Однако реально ограничения все же существуют, например, Linux может работать не более чем с 15 разделами на SCSI-дисках и не более чем с 63-мя разделами на IDE-дисках. Это обусловлено уже особенностями самой операционной системы, а именно тем, что ограничено число возможных значений младшего номера устройства. Для IDE-устройств в Линукс зарезервировано 64 значения младшего номера устройства. Например, /dev/hda имеет старший номер 3, а младший - 0, для /dev/hda1 старший номер - 3, младший - 1, и так далее до /dev/hda63. Для SCSI-устройств в Линукс выделено только 16 значений для младшего номер каждого диска, так что возможны только 15 разделов.

DOS использует поля begin и end таблицы разбиения диска и функции прерывания 13 BIOS (Int 13h) для доступа к диску, и поэтому не может использовать диски объемом более 8,4 Гбайт, а разделы не могут быть более 2,1 Гбайт (но это уже из-за ограничений файловой системы FAT16). Linux использует только поля start и length таблицы разбиения диска и поддерживает разделы, содержащие до 232 секторов, т. е. размер раздела может достигать 2 Тбайт.

Но все это имеет значение только после того, как операционная система уже загружена. На этапе загрузки же происходит следующее. Программа загрузки BIOS (Basic Input/Output System –базовой системы ввода/вывода, записанной в ПЗУ вашего ПК), поочередно опрашивает все диски в поисках "загрузочного" (помните "магическое сисло" 0xAA55). Этот опрос осуществляется вызовом прерывания 13h BIOS.

Когда будет обнаружено загрузочное устройство, данные из сектора 1 дорожки 0 цилиндра 0 (это так называемый первичный загрузчик) первого откликнувшегося диска (дискеты, твердого диска или другого загрузочного устройства) загружаются по абсолютному адресу 0000:7c00 и управление передается по этому адресу. Программа первичного загрузчика (вы помните, ее объем не превышает 446 байт) определяет активный раздел диска (очевидно, что она тоже использует прерывание 13), а затем загружает и выполняет код из корневого сектора этого раздела. Только потом управление передается активной операционной системе диска. Если опрос всех дисков, выполняемый программой BIOS, неудачен, управление передается на прерывание INT 18H.

Но мы немного отклонились от основной линии повествования в сторону процедуры загрузки ОС. Давайте вернемся к структуре указателя раздела, приведеннной в листинге 2.

Поле type в описании раздела задает тип файловой системы, созданной в этом разделе. Однако в процессе разметки диска (создания таблицы разделов) форматирование разделов не производится, создается только сама таблица. И, наоборот, программы форматирования не обращают внимания на указание типа раздела в этой таблице, создают в разделе файловую систему того типа, который указан им при запуске команды форматирования, например:

[root]# mkfs.ext3 /dev/hda3

Поэтому возможны довольно курьезные случаи, когда раздел, для которого в таблице разделов указан тип, скажем, FAT32 (0x0C) отформатирован под Ext2 (код 0x83) и используется именно в таком качестве. Естественно, это может поставить некоторые программные средства в затруднительное положение. Кстати, размер поля, отведенного для типа (один байт), не позволяет присвоить уникальные идентификаторы всем вновь разрабатываемым типам ФС. Например, под кодом 0x83 (Linux Native) вынуждено скрываться сразу несколько типов файловых систем: Ext2, Ext3, ReiserFS, XFS, JFS, -- всех их объединяет то, что они разработаны (или портированы) именно для работы в среде Linux.

В заключение отмечу, что в Линукс вы можете увидеть список возможных типов, если запустите программу fdisk и дадите команду l – вывести список известных типов разделов. Более подробный список вы можете найти в “Partition types” А.Брауэра (см. [5] в списке ссылок).

Оглавление Вперед