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

UnixForum






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

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

“И узнаешь ты много такого, о чем совсем не хотел знать”
Автор неизвестен

Заметки пользователя Linux

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

Восстанавливаем таблицу разбиения диска

Назад: 1.4. Как устроен главный загрузочный сектор диска (MBR) .

1.5. Как устроена и используется таблица разделов диска

Таблица разбиения диска на разделы (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 бита) */
};

Поясню кратко, что такое CHS и тип раздела.

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

Поскольку в таблице разбиения отведено только 4 строки для задания разделов, число первичных разделов на диске с самого начала ограничено: их может быть не более 4. Если нужно создать более 4-х разделов, один из первичных разделов объявляется "расширенным" (тип раздела — 5, или F, или 85 в шестнадцатеричной системе), и в нем создаются "логические разделы". Расширенные разделы сами по себе не используются, они могут лишь хранить логические разделы. Первый сектор расширенного раздела хранит таблицу разделов с четырьмя входами: один используется для логического раздела, другой для еще одного расширенного раздела, а два не используются. Каждый расширенный раздел имеет свою таблицу разбиения, в которой, как и в первичном расширенном разделе, используются только две строки, задающие один логический и один расширенный раздел. Еще раз подчеркнем, что расширенный раздел как на физическом диске, так и в расширенном разделе вложенного расширенного раздела (предыдущего уровня) может быть только один: ни одна из существующих программ разбиения дисков (fdisk и ее усовершенствованные аналоги) не умеет создавать более одного расширенного раздела.

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

Листинг 3.

[root]# sfdisk -l -x /dev/hda

Disk /dev/hda: 784 cylinders, 255 heads, 63 sectors/track
Units = cylinders of 8225280 bytes, blocks of 1024 bytes, counting from 0

Device     Boot    Start    End    #cyls     #blocks      Id    System
/dev/hda1   *       0+      189      190-    1526143+    6    FAT16
/dev/hda2        190        783      594      4771305     5    Extended
/dev/hda3           0         —         0             0          0    Empty
/dev/hda4           0         —         0             0          0    Empty

/dev/hda5        190+      380      191-    1534176     6    FAT16381        783      403      3237097+   5    Extended190        189        0                0       0    Empty190        189        0                0       0    Empty

/dev/hda6        381+      783      403-    3237066     7    HPFS/NTFS381        380          0             0        0    Empty381        380          0             0        0    Empty381        380          0             0        0    Empty

Число логических разделов в принципе не ограничено, потому что каждый логический раздел может содержать таблицу разделов и вложенные логические разделы. Однако реально ограничения все же существуют, например, Linux может работать не более чем с 15 разделами на SCSI-дисках и не более чем с 63-мя разделами на IDE-дисках.

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

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

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

Если опрос всех дисков, выполняемый программой BIOS, неудачен, управление передается на прерывание INT 18H (но эту ветку мы здесь не рассматриваем).

Как видите, загрузка ОС основана на прерывании 13 BIOS. А прерывание 13 использует адресацию секторов на диске на основе геометрии диска, то есть указанием номеров цилиндра, головки и сектора на дорожке (C/H/S). Первоначально эти данные заносились в регистры микропроцессора Intel 80x86 следующим образом:

  • AH — выбор операции;
  • CH — младшие 8 бит номера цилиндра;
  • CL — 7-6 биты соответствуют старшим битам номера цилиндра, 5-0 биты соответствуют номеру сектора;
  • DH — номер считывающей головки;
  • DL — номер диска (80h или 81h).

Таким образом, имелась возможность задать один из 210 = 1024 номеров цилиндра, один из 26=64 номеров сектора и 28= 64 номеров головки. (Заметим в скобках, что нумерацию физических цилиндров и дорожек принято начинать с 0, а сектора на дорожке нумеруют, начиная с 1, поэтому возможны 63 номера сектора). Однако практически головок было не более 16-ти, а число секторов на дорожке — не более 63, и хотя для указания цилиндра использовалось 10 бит, все равно BIOS не мог работать с дисками объемом более 1024*63*16*512 = 528 Мбайт.

Для преодоления этого ограничения стали применять разные хитрые приемы (подробнее об этом вы можете узнать из [2]). Например, Extended CHS (ECHS) или "Large disk support" (иногда обозначается просто как "Large") использует еще три незанятых бита номера головки для увеличения числа адресуемых цилиндров. Это позволило использовать "фальшивую геометрию диска" в 8192 цилиндра, 16 считывающих головок и 63 сектора/дорожку. Трансляцию Extended CHS в реальный CHS-адрес (который может иметь до 8192 цилиндров) осуществляет BIOS. Это позволяет работать с дисками, объемом до 8192*16*63*512 = 4 227 858 432 байт или 4,2 Гбайт.

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

Тогда придумали другой прием для работы с большими дисками через Int 13h — линейную адресацию блоков ("Linear Block Addressing" или LBA). Если не вдаваться в подробности, то можно сказать, что все сектора на диске нумеруются последовательно, начиная с первого сектора на нулевой дорожке нулевого цилиндра. Вместо CHS-адреса каждый сектор получает логический адрес — просто его порядковый номер в общем массиве секторов. Нумерация логических секторов начинается с нуля, причем нулевой сектор содержит главную загрузочную запись (MBR). В Setup BIOS поддержка преобразования линейного номера в CHS-адрес обозначается как "поддержка LBA". Таким образом, в новых версиях BIOS обычно имеется выбор из трех вариантов: "Large", "LBA" и "Normal" (последнее означает, что трансляция адресов не производится).

Но и в режиме LBA обращение к физическому диску все равно осуществляется через функции Int 13h, которые используют 3D нотацию (C,H,S). В силу этого возникает ограничение на возможный объем диска: BIOS, и, следовательно, MS-DOS и ранние версии Windows, не могли адресовать диски объемом более 8,4 Гбайт.

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

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

Когда я прочитал все, что только что пересказал, мне показалось, что причина того, почему система у меня не грузится, а Knoppix получает доступ к диску, понятна. Ведь как сообщает fdisk у меня как раз неправильно указано разбиение разделов в формате C/H/S (см. листинг 1). Поля же start и length таблицы разделов (см. листинг 2), очевидно, заданы корректно, поэтому после загрузки системы мы получаем доступ к информации в этих разделах. Так что вроде остается только найти способы восстановления первоначальной таблицы разделов диска. Но о своих дальнейших действиях я расскажу в следующей части настоящих заметок, а пока хочу еще рассказать о том, какую роль играет поле type в таблице разделов.

По идее тип раздела определяет тип файловой системы, созданной в этом разделе.

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

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

[root]# mkfs.ext3 /dev/hda3

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

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

Продолжение: 1.6. Создаем резервную копию данных.